Skip to content

Commit d7f019a

Browse files
committed
Add comments and finalize newer version of HIR
1 parent a209a6d commit d7f019a

File tree

9 files changed

+456
-88
lines changed

9 files changed

+456
-88
lines changed

optd-dsl/src/analyzer/hir.rs

Lines changed: 120 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,128 @@
1-
/*pub type Identifier = String;
1+
use super::r#type::{TypeRegistry, Typed};
2+
use ordered_float::OrderedFloat;
3+
use std::collections::HashMap;
24

5+
/// Unique identifier for variables, functions, types, etc.
6+
pub type Identifier = String;
7+
8+
/// Represents literal values in the language
9+
#[derive(Debug, Clone, PartialEq)]
10+
pub enum Literal {
11+
Int64(i64),
12+
String(String),
13+
Bool(bool),
14+
Float64(OrderedFloat<f64>),
15+
Unit,
16+
}
17+
18+
/// Represents expressions in the High-level Intermediate Representation
19+
#[derive(Debug, Clone)]
320
pub enum Expr {
4-
IfThenElse {
5-
cond: Typed<Expr>,
6-
then: Typed<Expr>,
7-
otherwise: Typed<Expr>,
8-
},
9-
Ref(Identifier),
10-
Value(i64),
21+
// Control flow
22+
PatternMatch(Typed<Expr>, Vec<MatchArm>),
23+
IfThenElse(Typed<Expr>, Typed<Expr>, Typed<Expr>),
24+
25+
// Bindings and constructors
26+
Let(Identifier, Typed<Expr>, Typed<Expr>),
27+
Constructor(String, Vec<Typed<Expr>>),
28+
29+
// Operations
30+
Binary(Typed<Expr>, BinOp, Typed<Expr>),
31+
Unary(UnaryOp, Typed<Expr>),
32+
33+
// Function-related
34+
Member(Typed<Expr>, Identifier),
35+
Call(Typed<Expr>, Vec<Typed<Expr>>),
36+
37+
// Basic expressions
38+
Ref(String),
39+
Literal(Literal),
40+
Fail(Typed<Expr>),
41+
42+
// Collections
43+
Array(Vec<Typed<Expr>>),
44+
Tuple(Vec<Typed<Expr>>),
45+
Map(Vec<(Typed<Expr>, Typed<Expr>)>),
1146
}
1247

13-
#[derive(Clone, PartialEq, Eq, Debug)]
14-
pub struct Typed<T> {
15-
pub value: Box<T>,
16-
pub ty: Type,
48+
/// Represents patterns for pattern matching
49+
#[derive(Debug, Clone)]
50+
pub enum Pattern {
51+
Bind(Typed<Identifier>, Typed<Pattern>),
52+
Constructor(Typed<Identifier>, Vec<Typed<Pattern>>),
53+
Literal(Literal),
54+
Wildcard,
1755
}
1856

19-
impl<T> Typed<T> {
20-
pub fn new(value: T, ty: Type) -> Self {
21-
Self {
22-
value: Box::new(value),
23-
ty,
24-
}
25-
}
57+
/// Represents a single arm in a pattern match expression
58+
#[derive(Debug, Clone)]
59+
pub struct MatchArm {
60+
pub pattern: Typed<Pattern>,
61+
pub expr: Typed<Expr>,
2662
}
2763

28-
pub struct HIR {}
29-
*/
64+
/// Binary operators supported by the language
65+
#[derive(Debug, Clone, PartialEq)]
66+
pub enum BinOp {
67+
// Arithmetic
68+
Add,
69+
Sub,
70+
Mul,
71+
Div,
72+
73+
// String, list, map
74+
Concat,
75+
76+
// Comparison
77+
Eq,
78+
Neq,
79+
Gt,
80+
Lt,
81+
Ge,
82+
Le,
83+
84+
// Logical
85+
And,
86+
Or,
87+
88+
// Other
89+
Range,
90+
}
91+
92+
/// Unary operators supported by the language
93+
#[derive(Debug, Clone, PartialEq)]
94+
pub enum UnaryOp {
95+
Neg,
96+
Not,
97+
}
98+
99+
/// Stores annotation information for a function or expression
100+
#[derive(Debug, Clone)]
101+
pub struct AnnotatedExpr {
102+
/// The expression itself
103+
pub expr: Typed<Expr>,
104+
105+
/// List of annotations associated with this expression
106+
pub annotations: Vec<Identifier>,
107+
}
108+
109+
/// The High-level Intermediate Representation (HIR) for a program.
110+
///
111+
/// The HIR is an intermediary representation that exists after type checking and
112+
/// before code generation or optimization. Unlike the AST, the HIR:
113+
///
114+
/// 1. Contains fully resolved type information for all expressions
115+
/// 2. Has undergone semantic analysis and type checking
116+
/// 3. Has simpler, more regular structure with less syntactic sugar
117+
/// 4. Contains only valid, well-typed expressions (error nodes are removed)
118+
/// 5. Preserves information about annotations for later compilation phases
119+
/// 6. Serves as a bridge between the frontend (parsing, type checking) and
120+
/// the backend (optimization, code generation)
121+
#[derive(Debug, Clone)]
122+
pub struct HIR {
123+
/// Map from function name to its annotated expression
124+
pub expressions: HashMap<Identifier, AnnotatedExpr>,
125+
126+
/// Registry of all types used in the program
127+
pub types: TypeRegistry,
128+
}

optd-dsl/src/analyzer/type.rs

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ pub enum Type {
1313
String,
1414
Bool,
1515
Float64,
16+
// Special types
1617
Unit,
18+
Universe,
1719
// Complex types
1820
Array(Box<Type>),
1921
Closure(Box<Type>, Box<Type>),
@@ -82,7 +84,7 @@ impl<T> Typed<T> {
8284
/// The TypeRegistry keeps track of the inheritance relationships between
8385
/// types, particularly for user-defined ADTs. It provides methods to register
8486
/// types and check subtyping relationships.
85-
#[derive(Debug)]
87+
#[derive(Debug, Clone)]
8688
pub struct TypeRegistry {
8789
subtypes: HashMap<Identifier, HashSet<Identifier>>,
8890
}
@@ -148,6 +150,8 @@ impl TypeRegistry {
148150
}
149151

150152
match (child, parent) {
153+
// Universe is the top type - everything is a subtype of Universe
154+
(_, Type::Universe) => true,
151155
// Check transitive inheritance
152156
(Type::Adt(child_name), Type::Adt(parent_name)) => {
153157
if child_name == parent_name {
@@ -247,12 +251,20 @@ mod type_registry_tests {
247251
assert!(registry.is_subtype(&Type::String, &Type::String));
248252
assert!(registry.is_subtype(&Type::Float64, &Type::Float64));
249253
assert!(registry.is_subtype(&Type::Unit, &Type::Unit));
254+
assert!(registry.is_subtype(&Type::Universe, &Type::Universe));
250255

251256
// Different primitive types should not be subtypes
252257
assert!(!registry.is_subtype(&Type::Int64, &Type::Bool));
253258
assert!(!registry.is_subtype(&Type::String, &Type::Int64));
254259
assert!(!registry.is_subtype(&Type::Float64, &Type::Int64));
255260
assert!(!registry.is_subtype(&Type::Unit, &Type::Bool));
261+
262+
// All types should be subtypes of Universe
263+
assert!(registry.is_subtype(&Type::Int64, &Type::Universe));
264+
assert!(registry.is_subtype(&Type::Bool, &Type::Universe));
265+
assert!(registry.is_subtype(&Type::String, &Type::Universe));
266+
assert!(registry.is_subtype(&Type::Float64, &Type::Universe));
267+
assert!(registry.is_subtype(&Type::Unit, &Type::Universe));
256268
}
257269

258270
#[test]
@@ -277,6 +289,9 @@ mod type_registry_tests {
277289
&Type::Array(Box::new(Type::Array(Box::new(Type::Int64))))
278290
));
279291

292+
// Array of any type is subtype of Universe
293+
assert!(registry.is_subtype(&Type::Array(Box::new(Type::Int64)), &Type::Universe));
294+
280295
// Array with inheritance (will be tested more with ADTs)
281296
let mut adts_registry = TypeRegistry::new();
282297
let vehicle = create_product_adt("Vehicle", vec![]);
@@ -315,6 +330,9 @@ mod type_registry_tests {
315330
// Empty tuples
316331
assert!(registry.is_subtype(&Type::Tuple(vec![]), &Type::Tuple(vec![])));
317332

333+
// All tuples are subtypes of Universe
334+
assert!(registry.is_subtype(&Type::Tuple(vec![Type::Int64, Type::Bool]), &Type::Universe));
335+
318336
// Nested tuples
319337
assert!(registry.is_subtype(
320338
&Type::Tuple(vec![
@@ -349,6 +367,12 @@ mod type_registry_tests {
349367
&Type::Map(Box::new(Type::String), Box::new(Type::Int64)),
350368
&Type::Map(Box::new(Type::String), Box::new(Type::Bool))
351369
));
370+
371+
// All maps are subtypes of Universe
372+
assert!(registry.is_subtype(
373+
&Type::Map(Box::new(Type::String), Box::new(Type::Int64)),
374+
&Type::Universe
375+
));
352376
}
353377

354378
#[test]
@@ -367,6 +391,12 @@ mod type_registry_tests {
367391
&Type::Closure(Box::new(Type::Float64), Box::new(Type::Bool))
368392
));
369393

394+
// All closures are subtypes of Universe
395+
assert!(registry.is_subtype(
396+
&Type::Closure(Box::new(Type::Int64), Box::new(Type::Bool)),
397+
&Type::Universe
398+
));
399+
370400
// Contravariant parameter types - broader param type is a subtype
371401
let mut adts_registry = TypeRegistry::new();
372402
let animal = create_product_adt("Animal", vec![]);
@@ -444,6 +474,9 @@ mod type_registry_tests {
444474
&Type::Adt("Shapes".to_string())
445475
));
446476

477+
// All ADTs are subtypes of Universe
478+
assert!(registry.is_subtype(&Type::Adt("Shapes".to_string()), &Type::Universe));
479+
447480
// Non-subtypes should return false
448481
assert!(!registry.is_subtype(
449482
&Type::Adt("Shapes".to_string()),
@@ -456,6 +489,35 @@ mod type_registry_tests {
456489
));
457490
}
458491

492+
#[test]
493+
fn test_universe_as_top_type() {
494+
let registry = TypeRegistry::new();
495+
496+
// Check that Universe is a supertype of all primitive types
497+
assert!(registry.is_subtype(&Type::Int64, &Type::Universe));
498+
assert!(registry.is_subtype(&Type::String, &Type::Universe));
499+
assert!(registry.is_subtype(&Type::Bool, &Type::Universe));
500+
assert!(registry.is_subtype(&Type::Float64, &Type::Universe));
501+
assert!(registry.is_subtype(&Type::Unit, &Type::Universe));
502+
503+
// Check that Universe is a supertype of all complex types
504+
assert!(registry.is_subtype(&Type::Array(Box::new(Type::Int64)), &Type::Universe));
505+
assert!(registry.is_subtype(&Type::Tuple(vec![Type::Int64, Type::Bool]), &Type::Universe));
506+
assert!(registry.is_subtype(
507+
&Type::Map(Box::new(Type::String), Box::new(Type::Int64)),
508+
&Type::Universe
509+
));
510+
assert!(registry.is_subtype(
511+
&Type::Closure(Box::new(Type::Int64), Box::new(Type::Bool)),
512+
&Type::Universe
513+
));
514+
515+
// But Universe is not a subtype of any other type
516+
assert!(!registry.is_subtype(&Type::Universe, &Type::Int64));
517+
assert!(!registry.is_subtype(&Type::Universe, &Type::String));
518+
assert!(!registry.is_subtype(&Type::Universe, &Type::Array(Box::new(Type::Int64))));
519+
}
520+
459521
#[test]
460522
fn test_complex_nested_type_hierarchy() {
461523
let mut registry = TypeRegistry::new();
@@ -521,6 +583,11 @@ mod type_registry_tests {
521583
&Type::Adt("Vehicles".to_string())
522584
));
523585

586+
// All vehicle types are subtypes of Universe
587+
assert!(registry.is_subtype(&Type::Adt("Vehicles".to_string()), &Type::Universe));
588+
assert!(registry.is_subtype(&Type::Adt("Cars".to_string()), &Type::Universe));
589+
assert!(registry.is_subtype(&Type::Adt("SportsCar".to_string()), &Type::Universe));
590+
524591
// Test negative cases
525592
assert!(!registry.is_subtype(
526593
&Type::Adt("Vehicles".to_string()),
@@ -614,5 +681,20 @@ mod type_registry_tests {
614681
]))))
615682
)
616683
));
684+
685+
// Any complex nested type is a subtype of Universe
686+
assert!(registry.is_subtype(
687+
&Type::Map(
688+
Box::new(Type::String),
689+
Box::new(Type::Array(Box::new(Type::Tuple(vec![
690+
Type::Adt("Dog".to_string()),
691+
Type::Closure(
692+
Box::new(Type::Adt("Animals".to_string())),
693+
Box::new(Type::Adt("Cat".to_string()))
694+
)
695+
]))))
696+
),
697+
&Type::Universe
698+
));
617699
}
618700
}

optd-dsl/src/lexer/lex.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = Simple<char, Span>>
115115
just("!=").to(Token::NotEq),
116116
just(">=").to(Token::GreaterEq),
117117
just("<=").to(Token::LessEq),
118-
just("->").to(Token::Arrow),
118+
just("=>").to(Token::BigArrow),
119+
just("->").to(Token::SmallArrow),
119120
just("&&").to(Token::And),
120121
just("||").to(Token::Or),
121122
just("++").to(Token::Concat),

optd-dsl/src/lexer/tokens.rs

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -32,23 +32,24 @@ pub enum Token {
3232
Unit, // ()
3333

3434
// Operators
35-
Plus, // +
36-
Minus, // -
37-
Mul, // *
38-
Div, // /
39-
Eq, // =
40-
Arrow, // ->
41-
EqEq, // ==
42-
NotEq, // !=
43-
Greater, // >
44-
Less, // <
45-
GreaterEq, // >=
46-
LessEq, // <=
47-
Not, // !
48-
And, // &&
49-
Or, // ||
50-
Range, // ..
51-
Concat, // ++
35+
Plus, // +
36+
Minus, // -
37+
Mul, // *
38+
Div, // /
39+
Eq, // =
40+
BigArrow, // =>
41+
SmallArrow, // ->
42+
EqEq, // ==
43+
NotEq, // !=
44+
Greater, // >
45+
Less, // <
46+
GreaterEq, // >=
47+
LessEq, // <=
48+
Not, // !
49+
And, // &&
50+
Or, // ||
51+
Range, // ..
52+
Concat, // ++
5253

5354
// Delimiters
5455
LParen, // (
@@ -109,7 +110,8 @@ impl std::fmt::Display for Token {
109110
Token::Mul => write!(f, "*"),
110111
Token::Div => write!(f, "/"),
111112
Token::Eq => write!(f, "="),
112-
Token::Arrow => write!(f, "->"),
113+
Token::BigArrow => write!(f, "=>"),
114+
Token::SmallArrow => write!(f, "->"),
113115
Token::EqEq => write!(f, "=="),
114116
Token::NotEq => write!(f, "!="),
115117
Token::Greater => write!(f, ">"),

0 commit comments

Comments
 (0)