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:
@@ -294,6 +294,22 @@ impl VM {
|
||||
Ok(val)
|
||||
}
|
||||
BoundKind::Get { addr, .. } => self.get_value(*addr),
|
||||
|
||||
BoundKind::FieldAccessor(k) => Ok(Value::FieldAccessor(*k)),
|
||||
|
||||
BoundKind::GetField { rec, field } => {
|
||||
let rec_val = self.eval_internal(obs, rec)?;
|
||||
if let Value::Record(layout, values) = rec_val {
|
||||
if let Some(idx) = layout.index_of(*field) {
|
||||
Ok(values[idx].clone())
|
||||
} else {
|
||||
Err(format!("Record does not have field :{}", field.name()))
|
||||
}
|
||||
} else {
|
||||
Err(format!("Attempt to access field on non-record: {}", rec_val))
|
||||
}
|
||||
}
|
||||
|
||||
BoundKind::Set { addr, value } => {
|
||||
let val = self.eval_internal(obs, value)?;
|
||||
self.set_value(*addr, val.clone())?;
|
||||
@@ -368,6 +384,29 @@ impl VM {
|
||||
return Ok(Value::TailCallRequest(Box::new((obj, arg_vals))));
|
||||
}
|
||||
Value::Function(f) => return Ok((f.func)(arg_vals)),
|
||||
Value::FieldAccessor(k) => {
|
||||
if arg_vals.len() != 1 {
|
||||
return Err(format!(
|
||||
"Field accessor .{} expects exactly 1 argument, got {}",
|
||||
k.name(),
|
||||
arg_vals.len()
|
||||
));
|
||||
}
|
||||
let rec = &arg_vals[0];
|
||||
if let Value::Record(layout, values) = rec {
|
||||
if let Some(idx) = layout.index_of(k) {
|
||||
return Ok(values[idx].clone());
|
||||
} else {
|
||||
return Err(format!("Record does not have field :{}", k.name()));
|
||||
}
|
||||
} else {
|
||||
return Err(format!(
|
||||
"Field accessor .{} expects a record, got {}",
|
||||
k.name(),
|
||||
rec
|
||||
));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(format!(
|
||||
"Tail call target is not a function: {}",
|
||||
@@ -380,6 +419,29 @@ impl VM {
|
||||
loop {
|
||||
match func_val {
|
||||
Value::Function(f) => break Ok((f.func)(arg_vals)),
|
||||
Value::FieldAccessor(k) => {
|
||||
if arg_vals.len() != 1 {
|
||||
break Err(format!(
|
||||
"Field accessor .{} expects exactly 1 argument, got {}",
|
||||
k.name(),
|
||||
arg_vals.len()
|
||||
));
|
||||
}
|
||||
let rec = &arg_vals[0];
|
||||
if let Value::Record(layout, values) = rec {
|
||||
if let Some(idx) = layout.index_of(k) {
|
||||
break Ok(values[idx].clone());
|
||||
} else {
|
||||
break Err(format!("Record does not have field :{}", k.name()));
|
||||
}
|
||||
} else {
|
||||
break Err(format!(
|
||||
"Field accessor .{} expects a record, got {}",
|
||||
k.name(),
|
||||
rec
|
||||
));
|
||||
}
|
||||
}
|
||||
Value::Object(obj) => {
|
||||
if let Some(closure) = obj.as_any().downcast_ref::<Closure>() {
|
||||
let old_stack_top = self.stack.len();
|
||||
|
||||
Reference in New Issue
Block a user