Add tuple and map literals
This commit introduces support for tuple and map literals in the AST. Tuples are now represented by `UntypedKind::Tuple` and maps by `UntypedKind::Map`. The `Binder` has been updated to correctly handle these new node types and infer their types. The `VM` now also supports evaluating tuple and map literals.
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, BTreeMap};
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
use crate::ast::nodes::{Node, UntypedKind};
|
||||
use crate::ast::compiler::bound_nodes::{BoundKind, Address};
|
||||
use crate::ast::types::{Identity, StaticType};
|
||||
use crate::ast::types::{Identity, StaticType, Value};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct LocalInfo {
|
||||
@@ -229,6 +229,44 @@ impl Binder {
|
||||
}
|
||||
Ok(self.make_node(node.identity.clone(), BoundKind::Block { exprs: bound_exprs }, last_ty))
|
||||
},
|
||||
|
||||
UntypedKind::Tuple { elements } => {
|
||||
let mut bound_elems = Vec::new();
|
||||
for e in elements {
|
||||
bound_elems.push(self.bind(e)?);
|
||||
}
|
||||
// For now, tuple type is List(Any)
|
||||
let ty = StaticType::List(Box::new(StaticType::Any));
|
||||
Ok(self.make_node(node.identity.clone(), BoundKind::Tuple { elements: bound_elems }, ty))
|
||||
},
|
||||
|
||||
UntypedKind::Map { entries } => {
|
||||
let mut bound_entries = Vec::new();
|
||||
let mut key_types = BTreeMap::new(); // For Record type inference if keys are constant keywords
|
||||
|
||||
for (k, v) in entries {
|
||||
// Keys must be compile-time constants for now (for Record type),
|
||||
// or at least we enforce keywords.
|
||||
// But `bind` processes runtime expressions too.
|
||||
// Let's bind both.
|
||||
let bound_k = self.bind(k)?;
|
||||
let bound_v = self.bind(v)?;
|
||||
|
||||
// If key is a constant keyword, we can build a static record type.
|
||||
if let BoundKind::Constant(Value::Keyword(kw)) = &bound_k.kind {
|
||||
key_types.insert(*kw, bound_v.ty.clone());
|
||||
}
|
||||
|
||||
bound_entries.push((bound_k, bound_v));
|
||||
}
|
||||
|
||||
// If all keys are known, we produce a Record type. Else Map(Any, Any) which we don't have yet.
|
||||
// We default to Record(Any) if keys are dynamic (not supported well yet) or known.
|
||||
// Since our parser enforced keywords, we assume we have a Record.
|
||||
let ty = StaticType::Record(Rc::new(key_types));
|
||||
|
||||
Ok(self.make_node(node.identity.clone(), BoundKind::Map { entries: bound_entries }, ty))
|
||||
},
|
||||
|
||||
UntypedKind::Extension(_) => {
|
||||
Err("Custom extensions not supported in Binder yet".to_string())
|
||||
|
||||
@@ -51,6 +51,14 @@ pub enum BoundKind {
|
||||
exprs: Vec<Node<BoundKind, StaticType>>,
|
||||
},
|
||||
|
||||
// NEW
|
||||
Tuple {
|
||||
elements: Vec<Node<BoundKind, StaticType>>,
|
||||
},
|
||||
Map {
|
||||
entries: Vec<(Node<BoundKind, StaticType>, Node<BoundKind, StaticType>)>,
|
||||
},
|
||||
|
||||
// Extension points (need to be adapted for bound nodes if they use variables)
|
||||
// For now, we assume extensions are self-contained or handled dynamically.
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user