Refactor map and record representation

Replaces the use of `BTreeMap` and `HashMap` for maps and records with
`Vec<(Keyword, Value)>` and `Vec<(Keyword, StaticType)>`. This
simplifies the data structure and allows for ordered iteration, which is
important for serialization and comparison.

Also updates the `unpack` function in `vm.rs` to handle records as well
as lists when destructuring.
This commit is contained in:
Michael Schimmel
2026-02-20 15:10:07 +01:00
parent 6ddc1c0a11
commit ca2c85a8a4
6 changed files with 60 additions and 37 deletions
+29 -14
View File
@@ -1,6 +1,5 @@
use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;
use std::any::Any;
use crate::ast::compiler::bound_nodes::{Address, BoundKind, TypedNode};
use crate::ast::types::{Value, Object};
@@ -318,13 +317,13 @@ macro_rules! dispatch_eval {
},
BoundKind::Map { entries } => {
let mut map = HashMap::new();
let mut map = Vec::with_capacity(entries.len());
for (k, v) in entries {
let key = $self.$eval_method($($observer,)? k)?;
let val = $self.$eval_method($($observer,)? v)?;
if let Value::Keyword(kw) = key {
map.insert(kw, val);
map.push((kw, val));
} else {
return Err(format!("Map key must be keyword, got {}", key));
}
@@ -678,19 +677,35 @@ impl VM {
Ok(())
}
BoundKind::Tuple { elements } => {
// If the current value at offset is a List, we dive into it.
// Otherwise, we assume the list was already flattened (e.g. by Specializer).
if let Some(Value::List(l)) = values.get(*offset) {
*offset += 1;
let mut sub_offset = 0;
for el in elements {
self.unpack(el, l, &mut sub_offset)?;
}
} else {
for el in elements {
self.unpack(el, values, offset)?;
// If the current value at offset is a List or Record, we dive into it.
// Otherwise, we assume the sequence was already flattened (e.g. by Specializer).
if let Some(val) = values.get(*offset) {
match val {
Value::List(l) => {
*offset += 1;
let mut sub_offset = 0;
for el in elements {
self.unpack(el, l, &mut sub_offset)?;
}
return Ok(());
}
Value::Record(r) => {
*offset += 1;
let mut sub_offset = 0;
// Treat record values as a tuple sequence in definition order
let record_values: Vec<_> = r.iter().map(|(_, v)| v.clone()).collect();
for el in elements {
self.unpack(el, &record_values, &mut sub_offset)?;
}
return Ok(());
}
_ => {}
}
}
for el in elements {
self.unpack(el, values, offset)?;
}
Ok(())
}
_ => Err("Invalid node in parameter pattern".to_string()),