Refactor Tuple and Record to share ValueList
Introduce `ValueList` type alias for `Rc<Vec<Value>>` 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.
This commit is contained in:
+19
-3
@@ -55,12 +55,16 @@ pub trait Object: fmt::Debug {
|
|||||||
fn as_any(&self) -> &dyn Any;
|
fn as_any(&self) -> &dyn Any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A shared sequence of values, used by both Tuples and Records.
|
||||||
|
pub type ValueList = Rc<Vec<Value>>;
|
||||||
|
|
||||||
/// Internal storage for Records to allow sharing schema (keys) between instances.
|
/// Internal storage for Records to allow sharing schema (keys) between instances.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct RecordData {
|
pub struct RecordData {
|
||||||
/// Names for slots.
|
/// Names for slots.
|
||||||
pub keys: Rc<Vec<Keyword>>,
|
pub keys: Rc<Vec<Keyword>>,
|
||||||
pub values: Vec<Value>,
|
/// The actual values, potentially shared with a Tuple.
|
||||||
|
pub values: ValueList,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Core data value in Myc Script (similar to TDataValue)
|
/// Core data value in Myc Script (similar to TDataValue)
|
||||||
@@ -73,7 +77,7 @@ pub enum Value {
|
|||||||
DateTime(i64),
|
DateTime(i64),
|
||||||
Text(Rc<str>),
|
Text(Rc<str>),
|
||||||
Keyword(Keyword),
|
Keyword(Keyword),
|
||||||
Tuple(Rc<Vec<Value>>),
|
Tuple(ValueList),
|
||||||
Record(Rc<RecordData>),
|
Record(Rc<RecordData>),
|
||||||
Function(Rc<dyn Fn(Vec<Value>) -> Value>),
|
Function(Rc<dyn Fn(Vec<Value>) -> Value>),
|
||||||
Object(Rc<dyn Object>), // For compiled Closures and other opaque types
|
Object(Rc<dyn Object>), // 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<Value>) -> Self {
|
pub fn make_tuple(values: Vec<Value>) -> Self {
|
||||||
Value::Tuple(Rc::new(values))
|
Value::Tuple(Rc::new(values))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn make_record(keys: Vec<Keyword>, values: Vec<Value>) -> Self {
|
pub fn make_record(keys: Vec<Keyword>, values: Vec<Value>) -> 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 {
|
pub fn static_type(&self) -> StaticType {
|
||||||
|
|||||||
+9
-24
@@ -601,18 +601,12 @@ impl VM {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn flatten_value(val: Value, into: &mut Vec<Value>) {
|
fn flatten_value(val: Value, into: &mut Vec<Value>) {
|
||||||
match val {
|
if let Some(values) = val.as_slice() {
|
||||||
Value::Tuple(values) => {
|
for item in values.iter() {
|
||||||
for item in values.iter() {
|
Self::flatten_value(item.clone(), into);
|
||||||
Self::flatten_value(item.clone(), into);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Value::Record(r) => {
|
} else {
|
||||||
for item in r.values.iter() {
|
into.push(val);
|
||||||
Self::flatten_value(item.clone(), into);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => into.push(val),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -685,26 +679,17 @@ impl VM {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
BoundKind::Tuple { elements } => {
|
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).
|
// Otherwise, we assume the sequence was already flattened (e.g. by Specializer).
|
||||||
match values.get(*offset) {
|
if let Some(val) = values.get(*offset) {
|
||||||
Some(Value::Tuple(t)) => {
|
if let Some(sub_values) = val.as_slice() {
|
||||||
*offset += 1;
|
*offset += 1;
|
||||||
let mut sub_offset = 0;
|
let mut sub_offset = 0;
|
||||||
for el in elements {
|
for el in elements {
|
||||||
self.unpack(el, t, &mut sub_offset)?;
|
self.unpack(el, sub_values, &mut sub_offset)?;
|
||||||
}
|
}
|
||||||
return Ok(());
|
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 {
|
for el in elements {
|
||||||
|
|||||||
Reference in New Issue
Block a user