Refactor: Implement Record Layouts and Optimized Field Access

Introduces a new `RecordLayout` system for efficient and type-safe
record handling.

Key changes:
- `RecordLayout` struct with `O(1)` field lookup using FMap
  optimization.
- Field accessors (`.name`) are now first-class callable values.
- Parser recognizes dot-prefixed identifiers as field accessors.
- Binder and TypeChecker handle field accessors.
- Optimizer transforms field accessor calls into specialized `GetField`
  nodes.
- VM executes `GetField` efficiently by directly accessing record
  values.
- Adds a new `records.myc` example showcasing record features.
- Improves comparison logic for records to use pointer equality for
  layout.
This commit is contained in:
Michael Schimmel
2026-02-26 21:38:20 +01:00
parent 2ad2eb5d43
commit bf74795e01
20 changed files with 548 additions and 63 deletions
+38 -5
View File
@@ -112,6 +112,27 @@ impl Optimizer {
)
}
BoundKind::FieldAccessor(k) => (BoundKind::FieldAccessor(k), node.ty.clone()),
BoundKind::GetField { ref rec, field } => {
let rec_opt = self.visit_node((**rec).clone(), sub, path);
// Constant folding for Field Access
if let BoundKind::Constant(Value::Record(layout, values)) = &rec_opt.kind
&& let Some(idx) = layout.index_of(field)
{
return folder.make_constant_node(values[idx].clone(), &node);
}
(
BoundKind::GetField {
rec: Box::new(rec_opt),
field,
},
node.ty.clone(),
)
}
BoundKind::Set { addr, value } => {
let value = Box::new(self.visit_node(*value, sub, path));
if let BoundKind::Constant(val) = &value.kind {
@@ -175,6 +196,23 @@ impl Optimizer {
let args = self.visit_node(*args, sub, path);
if self.enabled {
// Optimized Field Access Transformation
if let BoundKind::FieldAccessor(k) = &callee.kind
&& let BoundKind::Tuple { elements } = &args.kind
&& elements.len() == 1
{
let rec = elements[0].clone();
let metrics = node.ty.clone();
return Node {
identity: node.identity,
kind: BoundKind::GetField {
rec: Box::new(rec),
field: *k,
},
ty: metrics,
};
}
let mut arg_nodes = Vec::new();
self.flatten_tuple(args.clone(), &mut arg_nodes);
@@ -542,11 +580,6 @@ impl Optimizer {
self.flatten_tuple(el, into);
}
}
BoundKind::Record { fields } => {
for (_, v) in fields {
self.flatten_tuple(v, into);
}
}
BoundKind::Nop => {}
_ => into.push(node),
}
+7 -1
View File
@@ -68,6 +68,9 @@ impl UsageInfo {
self.assigned.insert(*addr);
self.collect(value);
}
BoundKind::GetField { rec, .. } => {
self.collect(rec);
}
BoundKind::Lambda {
params,
body,
@@ -147,7 +150,10 @@ impl UsageInfo {
BoundKind::Expansion { bound_expanded, .. } => {
self.collect(bound_expanded);
}
_ => {}
BoundKind::Again { args } => {
self.collect(args);
}
BoundKind::Nop | BoundKind::FieldAccessor(_) | BoundKind::Extension(_) => {}
}
}