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:
@@ -366,6 +366,9 @@ fn register_comparison(env: &Environment) {
|
||||
(Value::Bool(a), Value::Bool(b)) => Value::Bool(a == b),
|
||||
(Value::Keyword(a), Value::Keyword(b)) => Value::Bool(a == b),
|
||||
(Value::DateTime(a), Value::DateTime(b)) => Value::Bool(a == b),
|
||||
(Value::Record(la, va), Value::Record(lb, vb)) => {
|
||||
Value::Bool(std::sync::Arc::ptr_eq(la, lb) && va == vb)
|
||||
}
|
||||
(Value::Void, Value::Void) => Value::Bool(true),
|
||||
_ => Value::Bool(false),
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use crate::ast::types::{Keyword, Purity, Signature, StaticType, Value};
|
||||
use std::any::TypeId;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// Represents a Rust type that can be exposed to the script environment.
|
||||
pub trait Scriptable: 'static + Sized {
|
||||
@@ -149,7 +148,7 @@ impl TypeBuilder {
|
||||
}
|
||||
|
||||
pub fn build(self) -> StaticType {
|
||||
StaticType::Record(Rc::new(self.fields))
|
||||
StaticType::Record(crate::ast::types::RecordLayout::get_or_create(self.fields))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,20 +201,16 @@ mod tests {
|
||||
|
||||
// Check static type
|
||||
let st = TypeRegistry::resolve_type::<Person>(®istry);
|
||||
if let StaticType::Record(fields) = st {
|
||||
assert!(fields.iter().any(|(k, _)| *k == Keyword::intern("greet")));
|
||||
if let StaticType::Record(layout) = st {
|
||||
assert!(layout.fields.iter().any(|(k, _)| *k == Keyword::intern("greet")));
|
||||
} else {
|
||||
panic!("Expected Record type");
|
||||
}
|
||||
|
||||
// Check runtime behavior
|
||||
if let Value::Record(r) = wrapped {
|
||||
let idx = r
|
||||
.keys
|
||||
.iter()
|
||||
.position(|k| *k == Keyword::intern("greet"))
|
||||
.unwrap();
|
||||
let greet_fn = &r.values[idx];
|
||||
if let Value::Record(layout, values) = wrapped {
|
||||
let idx = layout.index_of(Keyword::intern("greet")).unwrap();
|
||||
let greet_fn = &values[idx];
|
||||
|
||||
if let Value::Function(f) = greet_fn {
|
||||
let res = (f.func)(vec![]);
|
||||
@@ -251,13 +246,9 @@ mod tests {
|
||||
|
||||
if let Value::Function(f) = factory_val {
|
||||
let instance = (f.func)(vec![Value::Text("Bob".into()), Value::Int(40)]);
|
||||
if let Value::Record(r) = instance {
|
||||
let idx = r
|
||||
.keys
|
||||
.iter()
|
||||
.position(|k| *k == Keyword::intern("greet"))
|
||||
.unwrap();
|
||||
let greet_fn = &r.values[idx];
|
||||
if let Value::Record(layout, values) = instance {
|
||||
let idx = layout.index_of(Keyword::intern("greet")).unwrap();
|
||||
let greet_fn = &values[idx];
|
||||
|
||||
if let Value::Function(gf) = greet_fn {
|
||||
let res = (gf.func)(vec![]);
|
||||
|
||||
Reference in New Issue
Block a user