Refactor Record and List to use TupleData
The `Value::List` and `Value::Record` variants have been consolidated into a single `Value::Tuple` variant. This new variant uses a `TupleData` struct to store values and an optional `Rc<Vec<Keyword>>` for keys, allowing it to represent both ordered lists/tuples and key-value records. This change simplifies the internal representation and improves performance by allowing schema sharing for records. It also includes updates to the compiler, runtime, and tests to reflect the new structure.
This commit is contained in:
+67
-47
@@ -55,6 +55,14 @@ pub trait Object: fmt::Debug {
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
}
|
||||
|
||||
/// Internal storage for Tuples (and Records) to allow sharing schema (keys) between instances.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TupleData {
|
||||
pub values: Vec<Value>,
|
||||
/// Optional names for slots. If present, this is semantically a Record.
|
||||
pub keys: Option<Rc<Vec<Keyword>>>,
|
||||
}
|
||||
|
||||
/// Core data value in Myc Script (similar to TDataValue)
|
||||
#[derive(Clone)]
|
||||
pub enum Value {
|
||||
@@ -65,8 +73,7 @@ pub enum Value {
|
||||
DateTime(i64),
|
||||
Text(Rc<str>),
|
||||
Keyword(Keyword),
|
||||
List(Rc<Vec<Value>>),
|
||||
Record(Rc<Vec<(Keyword, Value)>>),
|
||||
Tuple(Rc<TupleData>), // Replaces List and Record
|
||||
Function(Rc<dyn Fn(Vec<Value>) -> Value>),
|
||||
Object(Rc<dyn Object>), // For compiled Closures and other opaque types
|
||||
Cell(Rc<RefCell<Value>>), // Boxed value for captures
|
||||
@@ -217,6 +224,14 @@ impl Value {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_list(values: Vec<Value>) -> Self {
|
||||
Value::Tuple(Rc::new(TupleData { values, keys: None }))
|
||||
}
|
||||
|
||||
pub fn make_record(keys: Vec<Keyword>, values: Vec<Value>) -> Self {
|
||||
Value::Tuple(Rc::new(TupleData { values, keys: Some(Rc::new(keys)) }))
|
||||
}
|
||||
|
||||
pub fn static_type(&self) -> StaticType {
|
||||
match self {
|
||||
Value::Void => StaticType::Void,
|
||||
@@ -226,41 +241,45 @@ impl Value {
|
||||
Value::DateTime(_) => StaticType::DateTime,
|
||||
Value::Text(_) => StaticType::Text,
|
||||
Value::Keyword(_) => StaticType::Keyword,
|
||||
Value::List(l) => {
|
||||
if l.is_empty() {
|
||||
return StaticType::Vector(Box::new(StaticType::Any), 0);
|
||||
}
|
||||
|
||||
let element_types: Vec<_> = l.iter().map(|v| v.static_type()).collect();
|
||||
|
||||
// Check for Homogeneity (Vector)
|
||||
let first_ty = &element_types[0];
|
||||
let all_same = element_types.iter().all(|t| t == first_ty);
|
||||
|
||||
if all_same {
|
||||
match first_ty {
|
||||
StaticType::Vector(inner, len) => {
|
||||
// Possible Matrix
|
||||
StaticType::Matrix(inner.clone(), vec![l.len(), *len])
|
||||
},
|
||||
StaticType::Matrix(inner, shape) => {
|
||||
let mut new_shape = vec![l.len()];
|
||||
new_shape.extend(shape);
|
||||
StaticType::Matrix(inner.clone(), new_shape)
|
||||
},
|
||||
_ => StaticType::Vector(Box::new(first_ty.clone()), l.len())
|
||||
Value::Tuple(t) => {
|
||||
if let Some(keys) = &t.keys {
|
||||
// It's a Record
|
||||
let mut fields = Vec::with_capacity(t.values.len());
|
||||
for (i, v) in t.values.iter().enumerate() {
|
||||
fields.push((keys[i], v.static_type()));
|
||||
}
|
||||
StaticType::Record(Rc::new(fields))
|
||||
} else {
|
||||
StaticType::Tuple(element_types)
|
||||
// It's a List/Tuple
|
||||
let l = &t.values;
|
||||
if l.is_empty() {
|
||||
return StaticType::Vector(Box::new(StaticType::Any), 0);
|
||||
}
|
||||
|
||||
let element_types: Vec<_> = l.iter().map(|v| v.static_type()).collect();
|
||||
|
||||
// Check for Homogeneity (Vector)
|
||||
let first_ty = &element_types[0];
|
||||
let all_same = element_types.iter().all(|t| t == first_ty);
|
||||
|
||||
if all_same {
|
||||
match first_ty {
|
||||
StaticType::Vector(inner, len) => {
|
||||
// Possible Matrix
|
||||
StaticType::Matrix(inner.clone(), vec![l.len(), *len])
|
||||
},
|
||||
StaticType::Matrix(inner, shape) => {
|
||||
let mut new_shape = vec![l.len()];
|
||||
new_shape.extend(shape);
|
||||
StaticType::Matrix(inner.clone(), new_shape)
|
||||
},
|
||||
_ => StaticType::Vector(Box::new(first_ty.clone()), l.len())
|
||||
}
|
||||
} else {
|
||||
StaticType::Tuple(element_types)
|
||||
}
|
||||
}
|
||||
},
|
||||
Value::Record(r) => {
|
||||
let mut fields = Vec::with_capacity(r.len());
|
||||
for (k, v) in r.iter() {
|
||||
fields.push((*k, v.static_type()));
|
||||
}
|
||||
StaticType::Record(Rc::new(fields))
|
||||
},
|
||||
Value::Function(_) => StaticType::Any, // Dynamic function
|
||||
Value::Object(o) => StaticType::Object(o.type_name()),
|
||||
Value::Cell(c) => c.borrow().static_type(),
|
||||
@@ -284,21 +303,22 @@ impl fmt::Display for Value {
|
||||
},
|
||||
Value::Text(t) => write!(f, "\"{}\"", t),
|
||||
Value::Keyword(k) => write!(f, ":{}", k.name()),
|
||||
Value::List(l) => {
|
||||
write!(f, "[")?;
|
||||
for (i, val) in l.iter().enumerate() {
|
||||
if i > 0 { write!(f, " ")?; }
|
||||
write!(f, "{}", val)?;
|
||||
Value::Tuple(t) => {
|
||||
if let Some(keys) = &t.keys {
|
||||
write!(f, "{{")?;
|
||||
for i in 0..t.values.len() {
|
||||
if i > 0 { write!(f, ", ")?; }
|
||||
write!(f, ":{} {}", keys[i].name(), t.values[i])?;
|
||||
}
|
||||
write!(f, "}}")
|
||||
} else {
|
||||
write!(f, "[")?;
|
||||
for (i, val) in t.values.iter().enumerate() {
|
||||
if i > 0 { write!(f, " ")?; }
|
||||
write!(f, "{}", val)?;
|
||||
}
|
||||
write!(f, "]")
|
||||
}
|
||||
write!(f, "]")
|
||||
},
|
||||
Value::Record(r) => {
|
||||
write!(f, "{{")?;
|
||||
for (i, (k, v)) in r.iter().enumerate() {
|
||||
if i > 0 { write!(f, ", ")?; }
|
||||
write!(f, ":{} {}", k.name(), v)?;
|
||||
}
|
||||
write!(f, "}}")
|
||||
},
|
||||
Value::Function(_) => write!(f, "<native fn>"),
|
||||
Value::Object(o) => write!(f, "<{}>", o.type_name()),
|
||||
|
||||
Reference in New Issue
Block a user