From dc81b7d61634cf8b994e31b10115487614060caa Mon Sep 17 00:00:00 2001 From: Michael Schimmel Date: Sat, 21 Feb 2026 15:16:04 +0100 Subject: [PATCH] Refactor Tuple and Record to share ValueList Introduce `ValueList` type alias for `Rc>` to reduce boilerplate and improve readability. Add `as_slice()` method to `Value` to provide a unified way to access the underlying values of Tuples and Records. Update `flatten_value` and `unpack` in `VM` to utilize the new `as_slice()` method, simplifying logic and improving consistency. --- src/ast/types.rs | 22 +++++++++++++++++++--- src/ast/vm.rs | 33 +++++++++------------------------ 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/ast/types.rs b/src/ast/types.rs index c898cff..65b760f 100644 --- a/src/ast/types.rs +++ b/src/ast/types.rs @@ -55,12 +55,16 @@ pub trait Object: fmt::Debug { fn as_any(&self) -> &dyn Any; } +/// A shared sequence of values, used by both Tuples and Records. +pub type ValueList = Rc>; + /// Internal storage for Records to allow sharing schema (keys) between instances. #[derive(Debug, Clone)] pub struct RecordData { /// Names for slots. pub keys: Rc>, - pub values: Vec, + /// The actual values, potentially shared with a Tuple. + pub values: ValueList, } /// Core data value in Myc Script (similar to TDataValue) @@ -73,7 +77,7 @@ pub enum Value { DateTime(i64), Text(Rc), Keyword(Keyword), - Tuple(Rc>), + Tuple(ValueList), Record(Rc), Function(Rc) -> Value>), Object(Rc), // For compiled Closures and other opaque types @@ -225,12 +229,24 @@ impl Value { } } + /// Returns the underlying values as a slice if this is a Tuple or Record. + pub fn as_slice(&self) -> Option<&[Value]> { + match self { + Value::Tuple(v) => Some(v), + Value::Record(r) => Some(&r.values), + _ => None, + } + } + pub fn make_tuple(values: Vec) -> Self { Value::Tuple(Rc::new(values)) } pub fn make_record(keys: Vec, values: Vec) -> Self { - Value::Record(Rc::new(RecordData { keys: Rc::new(keys), values })) + Value::Record(Rc::new(RecordData { + keys: Rc::new(keys), + values: Rc::new(values) + })) } pub fn static_type(&self) -> StaticType { diff --git a/src/ast/vm.rs b/src/ast/vm.rs index 378d08e..d8d9478 100644 --- a/src/ast/vm.rs +++ b/src/ast/vm.rs @@ -601,18 +601,12 @@ impl VM { } fn flatten_value(val: Value, into: &mut Vec) { - match val { - Value::Tuple(values) => { - for item in values.iter() { - Self::flatten_value(item.clone(), into); - } + if let Some(values) = val.as_slice() { + for item in values.iter() { + Self::flatten_value(item.clone(), into); } - Value::Record(r) => { - for item in r.values.iter() { - Self::flatten_value(item.clone(), into); - } - } - _ => into.push(val), + } else { + into.push(val); } } @@ -685,26 +679,17 @@ impl VM { Ok(()) } BoundKind::Tuple { elements } => { - // If the current value at offset is a Tuple (List or Record), we dive into it. + // If the current value at offset is a Tuple or Record, we dive into it. // Otherwise, we assume the sequence was already flattened (e.g. by Specializer). - match values.get(*offset) { - Some(Value::Tuple(t)) => { + if let Some(val) = values.get(*offset) { + if let Some(sub_values) = val.as_slice() { *offset += 1; let mut sub_offset = 0; for el in elements { - self.unpack(el, t, &mut sub_offset)?; + self.unpack(el, sub_values, &mut sub_offset)?; } return Ok(()); } - Some(Value::Record(r)) => { - *offset += 1; - let mut sub_offset = 0; - for el in elements { - self.unpack(el, &r.values, &mut sub_offset)?; - } - return Ok(()); - } - _ => {} } for el in elements {