Add map literals
Map literals share the brackets with lists, but they use colons to delimit keys and values. Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
19
src/ast.rs
19
src/ast.rs
@@ -1,5 +1,5 @@
|
||||
// This is an auto-generated file. Any changes made to this file may be overwritten.
|
||||
// This file was created at: 2024-10-07 10:41:44
|
||||
// This file was created at: 2024-10-14 20:16:29
|
||||
#![allow(dead_code)]
|
||||
use std::fmt::Debug;
|
||||
use std::any::Any;
|
||||
@@ -17,6 +17,7 @@ pub trait ExprVisitor {
|
||||
fn visit_primary_expr(&mut self, expr: &PrimaryExpr) -> Result<(), Error>;
|
||||
fn visit_function_expr(&mut self, expr: &FunctionExpr) -> Result<(), Error>;
|
||||
fn visit_list_expr(&mut self, expr: &ListExpr) -> Result<(), Error>;
|
||||
fn visit_map_expr(&mut self, expr: &MapExpr) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
pub trait Expr: Debug + Any {
|
||||
@@ -153,6 +154,22 @@ impl Expr for ListExpr {
|
||||
fn as_any_ref(&self) -> &dyn Any { self }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MapExpr {
|
||||
pub lbracket: Token,
|
||||
pub pairs: Vec<(ExprP, ExprP)>,
|
||||
pub rbracket: Token,
|
||||
}
|
||||
|
||||
impl Expr for MapExpr {
|
||||
fn accept(&self, visitor: &mut dyn ExprVisitor) -> Result<(), Error> {
|
||||
visitor.visit_map_expr(self)
|
||||
}
|
||||
|
||||
fn as_any(self: Box<Self>) -> Box<dyn Any> { self }
|
||||
fn as_any_ref(&self) -> &dyn Any { self }
|
||||
}
|
||||
|
||||
pub trait StmtVisitor {
|
||||
fn visit_import_stmt(&mut self, stmt: &ImportStmt) -> Result<(), Error>;
|
||||
fn visit_expr_stmt(&mut self, stmt: &ExprStmt) -> Result<(), Error>;
|
||||
|
||||
@@ -958,4 +958,26 @@ impl ExprVisitor for Compiler<'_> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn visit_map_expr(&mut self, expr: &MapExpr) -> Result<()> {
|
||||
let line = expr_line_number(expr);
|
||||
let map_global = self.get_global("Map").unwrap();
|
||||
let insert_constant = self.insert_constant(Str::create("insert"))?;
|
||||
|
||||
self.emit(line, Op::GetGlobal(map_global));
|
||||
self.emit(line, Op::Call(0));
|
||||
|
||||
for (key, value) in &expr.pairs {
|
||||
self.emit(line, Op::Dup);
|
||||
self.emit(line, Op::GetAttr(insert_constant));
|
||||
|
||||
self.compile_expr(key)?;
|
||||
self.compile_expr(value)?;
|
||||
|
||||
self.emit(line, Op::Call(2));
|
||||
self.emit(line, Op::Pop);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,6 +125,12 @@ impl ExprVisitor for LineNumber {
|
||||
self.update_end(expr.rbracket.line);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn visit_map_expr(&mut self, expr: &MapExpr) -> Result<()> {
|
||||
self.update_start(expr.lbracket.line);
|
||||
self.update_end(expr.rbracket.line);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn expr_line_number(expr: &dyn Expr) -> LineRange {
|
||||
@@ -282,6 +288,11 @@ impl ExprVisitor for LocalAssignCollector {
|
||||
// there shouldn't be any local assignments inside of a list expression
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn visit_map_expr(&mut self, _expr: &MapExpr) -> Result<()> {
|
||||
// there shouldn't be any local assignments inside of a map expression
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -405,4 +416,12 @@ impl ExprVisitor for LocalNameCollector {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn visit_map_expr(&mut self, expr: &MapExpr) -> Result<()> {
|
||||
for (key, value) in &expr.pairs {
|
||||
key.accept(self)?;
|
||||
value.accept(self)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,6 +144,10 @@ pub fn init_types() {
|
||||
});
|
||||
)*
|
||||
})*
|
||||
|
||||
$({
|
||||
$name.borrow_mut().set_attr("name", Str::create(stringify!($name)));
|
||||
})*
|
||||
}};
|
||||
}
|
||||
|
||||
|
||||
@@ -931,7 +931,7 @@ impl Parser {
|
||||
}
|
||||
Ok(expr)
|
||||
} else if self.mat(TokenKind::LBracket)? {
|
||||
self.list()
|
||||
self.list_or_map()
|
||||
} else {
|
||||
Err(self.error(format!("unexpected token {:?}", self.current.kind)))
|
||||
}
|
||||
@@ -986,12 +986,34 @@ impl Parser {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn list(&mut self) -> Result<ExprP> {
|
||||
fn list_or_map(&mut self) -> Result<ExprP> {
|
||||
let lbracket = self.prev.clone().unwrap();
|
||||
let mut exprs = Vec::new();
|
||||
|
||||
// check if it's a map
|
||||
if self.mat(TokenKind::Colon)? {
|
||||
let rbracket = self
|
||||
.expect("expected ']' after empty map body", TokenKind::RBracket)?
|
||||
.clone();
|
||||
return Ok(Box::new(MapExpr {
|
||||
lbracket,
|
||||
pairs: vec![],
|
||||
rbracket,
|
||||
}));
|
||||
}
|
||||
|
||||
if !self.check(TokenKind::RBracket) {
|
||||
exprs.push(self.expr()?);
|
||||
let expr = self.expr()?;
|
||||
|
||||
// check if it's a map
|
||||
if self.mat(TokenKind::Colon)? {
|
||||
let value = self.expr()?;
|
||||
let pairs = vec![(expr, value)];
|
||||
return self.finish_map(lbracket, pairs);
|
||||
}
|
||||
|
||||
exprs.push(expr);
|
||||
|
||||
while self.mat(TokenKind::Comma)? {
|
||||
// allow trailing comma
|
||||
if self.check(TokenKind::RBracket) {
|
||||
@@ -1011,6 +1033,29 @@ impl Parser {
|
||||
rbracket,
|
||||
}))
|
||||
}
|
||||
|
||||
fn finish_map(&mut self, lbracket: Token, mut pairs: Vec<(ExprP, ExprP)>) -> Result<ExprP> {
|
||||
while self.mat(TokenKind::Comma)? {
|
||||
// trailing comma
|
||||
if self.check(TokenKind::RBracket) {
|
||||
break;
|
||||
}
|
||||
let key = self.expr()?;
|
||||
self.expect("expected ':' after map key", TokenKind::Colon)?;
|
||||
let value = self.expr()?;
|
||||
pairs.push((key, value));
|
||||
}
|
||||
|
||||
let rbracket = self
|
||||
.expect("expect ']' after map pairs", TokenKind::RBracket)?
|
||||
.clone();
|
||||
|
||||
Ok(Box::new(MapExpr {
|
||||
lbracket,
|
||||
pairs,
|
||||
rbracket,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -229,7 +229,10 @@ GENERATE = [
|
||||
"rbrace: Token",
|
||||
],
|
||||
)
|
||||
.add_struct("List", ["lbracket: Token", "exprs: Vec<ExprP>", "rbracket: Token"]),
|
||||
.add_struct("List", ["lbracket: Token", "exprs: Vec<ExprP>", "rbracket: Token"])
|
||||
.add_struct(
|
||||
"Map", ["lbracket: Token", "pairs: Vec<(ExprP, ExprP)>", "rbracket: Token"]
|
||||
),
|
||||
# Stmt
|
||||
GenerateGroup("Stmt")
|
||||
.add_struct("Import", ["import_kw: Token", "what: Vec<Token>", "module: Token"])
|
||||
|
||||
Reference in New Issue
Block a user