Skip to content

Commit f7f9b9f

Browse files
authored
(feat) Analyzer HIR Metadata Setup (#52)
## Problem Setup code for the analyzer. The `HIR` gets wrapped with a metadata field. Illustration: ```rust /// Metadata that can be attached to expression nodes /// /// This trait allows for different types of metadata to be attached to /// expression nodes while maintaining a common interface for access. pub trait ExprMetadata: Debug + Clone {} /// Empty metadata implementation for cases where no additional data is needed pub struct NoMetadata; /// Combined span and type information for an expression pub struct TypedSpan { /// Source code location. pub span: Span, /// Inferred type. pub ty: Type, } /// Expression nodes in the HIR with optional metadata /// /// The M type parameter allows attaching different kinds of metadata to expressions, /// such as type information, source spans, or both. pub struct Expr<M: ExprMetadata = NoMetadata> { /// The actual expression node pub kind: ExprKind<M>, /// Optional metadata for the expression pub metadata: M, } ``` ## Summary of changes Adapted the engine to take EmptyMetadata (no functional changes), all relevant code to review is in HIR. The critical pass is that the metadata is all we should need to perform type checking and inference. This PR is dependent on #51
1 parent 040ad57 commit f7f9b9f

File tree

10 files changed

+330
-239
lines changed

10 files changed

+330
-239
lines changed

optd-dsl/src/analyzer/hir.rs

+63-14
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
//! unified representation that can be transformed into optimizer-specific
1616
//! intermediate representations through the bridge modules.
1717
18-
use std::{collections::HashMap, sync::Arc};
19-
2018
use super::context::Context;
19+
use super::r#type::Type;
20+
use crate::utils::span::Span;
21+
use std::fmt::Debug;
22+
use std::{collections::HashMap, sync::Arc};
2123

2224
/// Unique identifier for variables, functions, types, etc.
2325
pub type Identifier = String;
@@ -190,25 +192,68 @@ pub enum CoreData<T> {
190192
None,
191193
}
192194

193-
/// Expression nodes in the HIR
195+
/// Metadata that can be attached to expression nodes
196+
///
197+
/// This trait allows for different types of metadata to be attached to
198+
/// expression nodes while maintaining a common interface for access.
199+
pub trait ExprMetadata: Debug + Clone {}
200+
201+
/// Empty metadata implementation for cases where no additional data is needed
202+
#[derive(Debug, Clone, Default)]
203+
pub struct NoMetadata;
204+
impl ExprMetadata for NoMetadata {}
205+
206+
/// Combined span and type information for an expression
207+
#[derive(Debug, Clone)]
208+
pub struct TypedSpan {
209+
/// Source code location.
210+
pub span: Span,
211+
/// Inferred type.
212+
pub ty: Type,
213+
}
214+
impl ExprMetadata for TypedSpan {}
215+
216+
/// Expression nodes in the HIR with optional metadata
217+
///
218+
/// The M type parameter allows attaching different kinds of metadata to expressions,
219+
/// such as type information, source spans, or both.
194220
#[derive(Debug, Clone)]
195-
pub enum Expr {
221+
pub struct Expr<M: ExprMetadata = NoMetadata> {
222+
/// The actual expression node
223+
pub kind: ExprKind<M>,
224+
/// Optional metadata for the expression
225+
pub metadata: M,
226+
}
227+
228+
impl Expr<NoMetadata> {
229+
/// Creates a new expression without metadata
230+
pub fn new(kind: ExprKind<NoMetadata>) -> Self {
231+
Self {
232+
kind,
233+
metadata: NoMetadata,
234+
}
235+
}
236+
}
237+
238+
/// Expression node kinds without metadata
239+
#[derive(Debug, Clone)]
240+
pub enum ExprKind<M: ExprMetadata = NoMetadata> {
196241
/// Pattern matching expression
197-
PatternMatch(Arc<Expr>, Vec<MatchArm>),
242+
PatternMatch(Arc<Expr<M>>, Vec<MatchArm<M>>),
198243
/// Conditional expression
199-
IfThenElse(Arc<Expr>, Arc<Expr>, Arc<Expr>),
244+
IfThenElse(Arc<Expr<M>>, Arc<Expr<M>>, Arc<Expr<M>>),
200245
/// Variable binding
201-
Let(Identifier, Arc<Expr>, Arc<Expr>),
246+
Let(Identifier, Arc<Expr<M>>, Arc<Expr<M>>),
202247
/// Binary operation
203-
Binary(Arc<Expr>, BinOp, Arc<Expr>),
248+
Binary(Arc<Expr<M>>, BinOp, Arc<Expr<M>>),
204249
/// Unary operation
205-
Unary(UnaryOp, Arc<Expr>),
250+
Unary(UnaryOp, Arc<Expr<M>>),
206251
/// Function call
207-
Call(Arc<Expr>, Vec<Arc<Expr>>),
252+
Call(Arc<Expr<M>>, Vec<Arc<Expr<M>>>),
208253
/// Variable reference
209254
Ref(Identifier),
210255
/// Core expression
211-
CoreExpr(CoreData<Arc<Expr>>),
256+
CoreExpr(CoreData<Arc<Expr<M>>>),
212257
/// Core value
213258
CoreVal(Value),
214259
}
@@ -238,11 +283,11 @@ pub enum Pattern {
238283

239284
/// Match arm combining pattern and expression
240285
#[derive(Debug, Clone)]
241-
pub struct MatchArm {
286+
pub struct MatchArm<M: ExprMetadata = NoMetadata> {
242287
/// Pattern to match against
243288
pub pattern: Pattern,
244289
/// Expression to evaluate if pattern matches
245-
pub expr: Arc<Expr>,
290+
pub expr: Arc<Expr<M>>,
246291
}
247292

248293
/// Standard binary operators
@@ -269,7 +314,11 @@ pub enum UnaryOp {
269314

270315
/// Program representation after the analysis phase
271316
#[derive(Debug)]
272-
pub struct HIR {
317+
pub struct HIR<M: ExprMetadata = NoMetadata> {
273318
pub context: Context,
274319
pub annotations: HashMap<Identifier, Vec<Annotation>>,
320+
pub expressions: Vec<Expr<M>>,
275321
}
322+
323+
/// Type alias for HIR with both type and source location information
324+
pub type TypedSpannedHIR = HIR<TypedSpan>;

optd-dsl/src/analyzer/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pub mod context;
22
pub mod hir;
33
pub mod semantic_checker;
4+
pub mod r#type;
45
pub mod type_checker;

optd-dsl/src/analyzer/type_checker/type.rs renamed to optd-dsl/src/analyzer/type.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::{
33
collections::{HashMap, HashSet},
44
ops::{Deref, DerefMut},
55
};
6+
67
pub type Identifier = String;
78

89
/// Represents types in the language.
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
pub mod error;
2-
pub mod r#type;

optd-dsl/src/engine/eval/core.rs

+17-16
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,11 @@ mod tests {
161161
use crate::{
162162
analyzer::{
163163
context::Context,
164-
hir::{CoreData, Expr, FunKind, Literal, Value},
164+
hir::{CoreData, Expr, ExprKind, FunKind, Literal, Value},
165165
},
166166
engine::Engine,
167167
};
168+
use ExprKind::*;
168169
use std::sync::Arc;
169170

170171
/// Test evaluation of literal values
@@ -175,7 +176,7 @@ mod tests {
175176
let harness = TestHarness::new();
176177

177178
// Create a literal expression
178-
let literal_expr = Arc::new(Expr::CoreExpr(CoreData::Literal(int(42))));
179+
let literal_expr = Arc::new(Expr::new(CoreExpr(CoreData::Literal(int(42)))));
179180
let results = evaluate_and_collect(literal_expr, engine, harness).await;
180181

181182
// Check result
@@ -196,11 +197,11 @@ mod tests {
196197
let engine = Engine::new(ctx);
197198

198199
// Create an array expression with values to evaluate
199-
let array_expr = Arc::new(Expr::CoreExpr(CoreData::Array(vec![
200+
let array_expr = Arc::new(Expr::new(CoreExpr(CoreData::Array(vec![
200201
lit_expr(int(1)),
201202
lit_expr(int(2)),
202203
lit_expr(int(3)),
203-
])));
204+
]))));
204205

205206
let results = evaluate_and_collect(array_expr, engine, harness).await;
206207

@@ -234,11 +235,11 @@ mod tests {
234235
let engine = Engine::new(ctx);
235236

236237
// Create a tuple expression with mixed types
237-
let tuple_expr = Arc::new(Expr::CoreExpr(CoreData::Tuple(vec![
238+
let tuple_expr = Arc::new(Expr::new(CoreExpr(CoreData::Tuple(vec![
238239
lit_expr(int(42)),
239240
lit_expr(string("hello")),
240241
lit_expr(Literal::Bool(true)),
241-
])));
242+
]))));
242243

243244
let results = evaluate_and_collect(tuple_expr, engine, harness).await;
244245

@@ -272,10 +273,10 @@ mod tests {
272273
let engine = Engine::new(ctx);
273274

274275
// Create a struct expression
275-
let struct_expr = Arc::new(Expr::CoreExpr(CoreData::Struct(
276+
let struct_expr = Arc::new(Expr::new(CoreExpr(CoreData::Struct(
276277
"Point".to_string(),
277278
vec![lit_expr(int(10)), lit_expr(int(20))],
278-
)));
279+
))));
279280

280281
let results = evaluate_and_collect(struct_expr, engine, harness).await;
281282

@@ -306,11 +307,11 @@ mod tests {
306307
let engine = Engine::new(ctx);
307308

308309
// Create a map expression
309-
let map_expr = Arc::new(Expr::CoreExpr(CoreData::Map(vec![
310+
let map_expr = Arc::new(Expr::new(CoreExpr(CoreData::Map(vec![
310311
(lit_expr(string("a")), lit_expr(int(1))),
311312
(lit_expr(string("b")), lit_expr(int(2))),
312313
(lit_expr(string("c")), lit_expr(int(3))),
313-
])));
314+
]))));
314315

315316
let results = evaluate_and_collect(map_expr, engine, harness).await;
316317

@@ -371,10 +372,10 @@ mod tests {
371372
let engine = Engine::new(ctx);
372373

373374
// Create a function expression (just a simple closure)
374-
let fn_expr = Arc::new(Expr::CoreExpr(CoreData::Function(FunKind::Closure(
375+
let fn_expr = Arc::new(Expr::new(CoreExpr(CoreData::Function(FunKind::Closure(
375376
vec!["x".to_string()],
376377
lit_expr(int(42)), // Just returns 42 regardless of argument
377-
))));
378+
)))));
378379

379380
let results = evaluate_and_collect(fn_expr, engine, harness).await;
380381

@@ -396,7 +397,7 @@ mod tests {
396397
let engine = Engine::new(ctx);
397398

398399
// Create a null expression
399-
let null_expr = Arc::new(Expr::CoreExpr(CoreData::None));
400+
let null_expr = Arc::new(Expr::new(CoreExpr(CoreData::None)));
400401

401402
let results = evaluate_and_collect(null_expr, engine, harness).await;
402403

@@ -430,9 +431,9 @@ mod tests {
430431
let engine = Engine::new(ctx);
431432

432433
// Create a fail expression with a message
433-
let fail_expr = Arc::new(Expr::CoreExpr(CoreData::Fail(Box::new(Arc::new(
434-
Expr::CoreVal(Value(CoreData::Literal(string("error message")))),
435-
)))));
434+
let fail_expr = Arc::new(Expr::new(CoreExpr(CoreData::Fail(Box::new(Arc::new(
435+
Expr::new(CoreVal(Value(CoreData::Literal(string("error message"))))),
436+
))))));
436437

437438
let results =
438439
evaluate_and_collect_with_custom_k(fail_expr, engine, harness, return_k).await;

0 commit comments

Comments
 (0)