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 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)]
|
#![allow(dead_code)]
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
@@ -17,6 +17,7 @@ pub trait ExprVisitor {
|
|||||||
fn visit_primary_expr(&mut self, expr: &PrimaryExpr) -> Result<(), Error>;
|
fn visit_primary_expr(&mut self, expr: &PrimaryExpr) -> Result<(), Error>;
|
||||||
fn visit_function_expr(&mut self, expr: &FunctionExpr) -> Result<(), Error>;
|
fn visit_function_expr(&mut self, expr: &FunctionExpr) -> Result<(), Error>;
|
||||||
fn visit_list_expr(&mut self, expr: &ListExpr) -> 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 {
|
pub trait Expr: Debug + Any {
|
||||||
@@ -153,6 +154,22 @@ impl Expr for ListExpr {
|
|||||||
fn as_any_ref(&self) -> &dyn Any { self }
|
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 {
|
pub trait StmtVisitor {
|
||||||
fn visit_import_stmt(&mut self, stmt: &ImportStmt) -> Result<(), Error>;
|
fn visit_import_stmt(&mut self, stmt: &ImportStmt) -> Result<(), Error>;
|
||||||
fn visit_expr_stmt(&mut self, stmt: &ExprStmt) -> Result<(), Error>;
|
fn visit_expr_stmt(&mut self, stmt: &ExprStmt) -> Result<(), Error>;
|
||||||
|
|||||||
@@ -958,4 +958,26 @@ impl ExprVisitor for Compiler<'_> {
|
|||||||
|
|
||||||
Ok(())
|
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);
|
self.update_end(expr.rbracket.line);
|
||||||
Ok(())
|
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 {
|
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
|
// there shouldn't be any local assignments inside of a list expression
|
||||||
Ok(())
|
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)]
|
#[derive(Default)]
|
||||||
@@ -405,4 +416,12 @@ impl ExprVisitor for LocalNameCollector {
|
|||||||
}
|
}
|
||||||
Ok(())
|
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)
|
Ok(expr)
|
||||||
} else if self.mat(TokenKind::LBracket)? {
|
} else if self.mat(TokenKind::LBracket)? {
|
||||||
self.list()
|
self.list_or_map()
|
||||||
} else {
|
} else {
|
||||||
Err(self.error(format!("unexpected token {:?}", self.current.kind)))
|
Err(self.error(format!("unexpected token {:?}", self.current.kind)))
|
||||||
}
|
}
|
||||||
@@ -986,12 +986,34 @@ impl Parser {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list(&mut self) -> Result<ExprP> {
|
fn list_or_map(&mut self) -> Result<ExprP> {
|
||||||
let lbracket = self.prev.clone().unwrap();
|
let lbracket = self.prev.clone().unwrap();
|
||||||
let mut exprs = Vec::new();
|
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) {
|
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)? {
|
while self.mat(TokenKind::Comma)? {
|
||||||
// allow trailing comma
|
// allow trailing comma
|
||||||
if self.check(TokenKind::RBracket) {
|
if self.check(TokenKind::RBracket) {
|
||||||
@@ -1011,6 +1033,29 @@ impl Parser {
|
|||||||
rbracket,
|
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)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -229,7 +229,10 @@ GENERATE = [
|
|||||||
"rbrace: Token",
|
"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
|
# Stmt
|
||||||
GenerateGroup("Stmt")
|
GenerateGroup("Stmt")
|
||||||
.add_struct("Import", ["import_kw: Token", "what: Vec<Token>", "module: Token"])
|
.add_struct("Import", ["import_kw: Token", "what: Vec<Token>", "module: Token"])
|
||||||
|
|||||||
Reference in New Issue
Block a user