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:
+14
-17
@@ -1,7 +1,7 @@
|
||||
use std::rc::Rc;
|
||||
use crate::ast::lexer::{Lexer, Token, TokenKind};
|
||||
use crate::ast::types::{Identity, NodeIdentity, Value, Keyword};
|
||||
use crate::ast::nodes::{Node, UntypedKind, Context};
|
||||
use crate::ast::nodes::{Node, UntypedKind};
|
||||
|
||||
pub struct Parser<'a> {
|
||||
lexer: Lexer<'a>,
|
||||
@@ -202,29 +202,24 @@ impl<'a> Parser<'a> {
|
||||
fn parse_vector_literal(&mut self) -> Result<Node<UntypedKind>, String> {
|
||||
let token = self.advance()?;
|
||||
let mut elements = Vec::new();
|
||||
let mut temp_ctx = Context::new();
|
||||
|
||||
while *self.peek() != TokenKind::RightBracket && *self.peek() != TokenKind::EOF {
|
||||
let expr = self.parse_expression()?;
|
||||
match expr.eval(&mut temp_ctx) {
|
||||
Ok(val) => elements.push(val),
|
||||
Err(e) => return Err(format!("Vector literal error: {}", e)),
|
||||
}
|
||||
elements.push(expr);
|
||||
}
|
||||
|
||||
self.expect(TokenKind::RightBracket)?;
|
||||
|
||||
Ok(Node {
|
||||
identity: Rc::new(NodeIdentity { location: token.location }),
|
||||
kind: UntypedKind::Constant(Value::List(Rc::new(elements))),
|
||||
kind: UntypedKind::Tuple { elements },
|
||||
ty: (),
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_map_literal(&mut self) -> Result<Node<UntypedKind>, String> {
|
||||
let token = self.advance()?;
|
||||
let mut map = std::collections::HashMap::new();
|
||||
let mut temp_ctx = Context::new();
|
||||
let mut entries = Vec::new();
|
||||
|
||||
while *self.peek() != TokenKind::RightBrace {
|
||||
if *self.peek() == TokenKind::EOF {
|
||||
@@ -232,24 +227,26 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
let key_node = self.parse_expression()?;
|
||||
let key = match key_node.eval(&mut temp_ctx)? {
|
||||
Value::Keyword(k) => k,
|
||||
_ => return Err("Map keys must be keywords".to_string()),
|
||||
};
|
||||
// We check for keyword kind here (syntactically) to avoid ambiguity, but
|
||||
// strictly we could allow any expression and check at runtime.
|
||||
// Delphi enforces keywords. We can do minimal check here.
|
||||
match &key_node.kind {
|
||||
UntypedKind::Constant(Value::Keyword(_)) => {},
|
||||
_ => return Err("Map keys must be keywords (syntactically)".to_string()),
|
||||
}
|
||||
|
||||
if *self.peek() == TokenKind::RightBrace {
|
||||
return Err("Map literal must have even number of forms".to_string());
|
||||
}
|
||||
let val_node = self.parse_expression()?;
|
||||
let val = val_node.eval(&mut temp_ctx)?;
|
||||
|
||||
map.insert(key, val);
|
||||
|
||||
entries.push((key_node, val_node));
|
||||
}
|
||||
self.expect(TokenKind::RightBrace)?;
|
||||
|
||||
Ok(Node {
|
||||
identity: Rc::new(NodeIdentity { location: token.location }),
|
||||
kind: UntypedKind::Constant(Value::Record(Rc::new(map))),
|
||||
kind: UntypedKind::Map { entries },
|
||||
ty: (),
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user