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:
2024-10-15 19:01:21 -07:00
parent 07a59c8930
commit 2ec122016c
6 changed files with 115 additions and 5 deletions

View File

@@ -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)]