Add object parsing and tests
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -9,6 +9,7 @@ const BASE_EXPR_START: &[TokenKind] = &[
|
||||
TokenKind::LParen,
|
||||
TokenKind::LBracket,
|
||||
TokenKind::LBrace,
|
||||
TokenKind::ObjBrace,
|
||||
];
|
||||
|
||||
const UN_EXPR_START: &[TokenKind] = &[TokenKind::Plus, TokenKind::Minus, TokenKind::Bang];
|
||||
@@ -61,6 +62,15 @@ impl<'t> Parser<'t> {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Statement parsing
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
impl<'t> Parser<'t> {
|
||||
pub fn next_stmt(&mut self) -> Result<Stmt> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Expression parsing
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -165,7 +175,17 @@ impl<'t> Parser<'t> {
|
||||
}
|
||||
.into()
|
||||
}
|
||||
TokenKind::LBrace => todo!(),
|
||||
TokenKind::LBrace => todo!("TODO body expressions"),
|
||||
TokenKind::ObjBrace => {
|
||||
let prev_skip = self.set_skip_newlines(true)?;
|
||||
let object = self.next_obj_list()?;
|
||||
let end_token = self.expect_token_kind(TokenKind::RBrace, "end of object (right curly brace)")?;
|
||||
let span = token.span().union(end_token.span());
|
||||
Expr::Base(BaseExpr {
|
||||
kind: BaseExprKind::Object(object),
|
||||
span,
|
||||
})
|
||||
}
|
||||
TokenKind::LParen => {
|
||||
let prev_skip = self.set_skip_newlines(true)?;
|
||||
let first = self.next_expr()?;
|
||||
@@ -175,7 +195,7 @@ impl<'t> Parser<'t> {
|
||||
self.set_skip_newlines(prev_skip)?;
|
||||
let end_token = self.expect_token_kind(TokenKind::RParen, "end of tuple")?;
|
||||
|
||||
let span = first.span().union(end_token.span());
|
||||
let span = token.span().union(end_token.span());
|
||||
list.insert(0, first);
|
||||
Expr::Base(
|
||||
BaseExpr {
|
||||
@@ -212,6 +232,28 @@ impl<'t> Parser<'t> {
|
||||
Ok(list_items)
|
||||
}
|
||||
|
||||
/// Parses the tail of a `BaseExprKind::Object` expression.
|
||||
///
|
||||
/// This function expects that the initial object brace `%{` has already been eaten.
|
||||
fn next_obj_list(&mut self) -> Result<Vec<(Expr, Expr)>> {
|
||||
let mut object = Vec::new();
|
||||
|
||||
// Parses this pattern:
|
||||
// ( key EQ value ( COMMA key = value )* COMMA? )?
|
||||
while !self.is_token_kind(TokenKind::RBrace) {
|
||||
let key = self.next_expr()?;
|
||||
self.expect_token_kind(TokenKind::Eq, "equals sign for object item")?;
|
||||
let value = self.next_expr()?;
|
||||
object.push((key, value));
|
||||
|
||||
// match a comma, otherwise exit the loop
|
||||
if self.match_token_kind(TokenKind::Comma)?.is_none() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(object)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Token matching functions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -220,13 +262,19 @@ impl<'t> Parser<'t> {
|
||||
let mut next_token = self.lexer.next_token()?;
|
||||
|
||||
if self.is_skip_newlines() {
|
||||
while next_token.map(|t| t.kind() == TokenKind::Newline).unwrap_or(false) {
|
||||
while next_token
|
||||
.map(|t| t.kind() == TokenKind::Newline)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
next_token = self.lexer.next_token()?;
|
||||
}
|
||||
|
||||
if self.is_token_kind(TokenKind::Newline) {
|
||||
self.curr_token = next_token;
|
||||
while next_token.map(|t| t.kind() == TokenKind::Newline).unwrap_or(false) {
|
||||
while next_token
|
||||
.map(|t| t.kind() == TokenKind::Newline)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
next_token = self.lexer.next_token()?;
|
||||
}
|
||||
}
|
||||
@@ -485,9 +533,7 @@ mod test {
|
||||
test_parser!(
|
||||
Parser::try_from("(:sym,)").unwrap(),
|
||||
next_expr,
|
||||
base_expr(BaseExprKind::Tuple(vec![
|
||||
base_expr(BaseExprKind::Sym),
|
||||
]))
|
||||
base_expr(BaseExprKind::Tuple(vec![base_expr(BaseExprKind::Sym),]))
|
||||
);
|
||||
|
||||
test_parser!(
|
||||
@@ -497,6 +543,26 @@ mod test {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_object_expr() {
|
||||
test_parser!(
|
||||
Parser::try_from(
|
||||
r#"%{
|
||||
:sym = value,
|
||||
key = "value",
|
||||
"lit" = 1,
|
||||
}"#
|
||||
)
|
||||
.unwrap(),
|
||||
next_expr,
|
||||
base_expr(BaseExprKind::Object(vec![
|
||||
(base_expr(BaseExprKind::Sym), base_expr(BaseExprKind::Ident)),
|
||||
(base_expr(BaseExprKind::Ident), base_expr(BaseExprKind::Str)),
|
||||
(base_expr(BaseExprKind::Str), base_expr(BaseExprKind::Num)),
|
||||
]))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bin_expr() {
|
||||
test_parser!(
|
||||
@@ -613,26 +679,30 @@ mod test {
|
||||
#[test]
|
||||
fn test_multiline_exprs() {
|
||||
test_parser!(
|
||||
Parser::try_from(r"[
|
||||
Parser::try_from(
|
||||
r"[
|
||||
1,
|
||||
x,
|
||||
['value', :value],
|
||||
:sym
|
||||
]").unwrap(),
|
||||
]"
|
||||
)
|
||||
.unwrap(),
|
||||
next_expr,
|
||||
base_expr(BaseExprKind::List(vec![
|
||||
base_expr(BaseExprKind::Num),
|
||||
base_expr(BaseExprKind::Ident),
|
||||
base_expr(BaseExprKind::List(vec![
|
||||
base_expr(BaseExprKind::Str),
|
||||
base_expr(BaseExprKind::Sym),
|
||||
base_expr(BaseExprKind::Str),
|
||||
base_expr(BaseExprKind::Sym),
|
||||
])),
|
||||
base_expr(BaseExprKind::Sym),
|
||||
]))
|
||||
);
|
||||
|
||||
test_parser!(
|
||||
Parser::try_from(r"(
|
||||
Parser::try_from(
|
||||
r"(
|
||||
1,
|
||||
x,
|
||||
[
|
||||
@@ -640,26 +710,31 @@ mod test {
|
||||
'value',
|
||||
],
|
||||
:sym
|
||||
)").unwrap(),
|
||||
)"
|
||||
)
|
||||
.unwrap(),
|
||||
next_expr,
|
||||
base_expr(BaseExprKind::Tuple(vec![
|
||||
base_expr(BaseExprKind::Num),
|
||||
base_expr(BaseExprKind::Ident),
|
||||
base_expr(BaseExprKind::List(vec![
|
||||
base_expr(BaseExprKind::Sym),
|
||||
base_expr(BaseExprKind::Str),
|
||||
base_expr(BaseExprKind::Sym),
|
||||
base_expr(BaseExprKind::Str),
|
||||
])),
|
||||
base_expr(BaseExprKind::Sym),
|
||||
]))
|
||||
);
|
||||
|
||||
test_parser!(
|
||||
Parser::try_from(r"(
|
||||
Parser::try_from(
|
||||
r"(
|
||||
+ 1
|
||||
+ 2
|
||||
+ 3
|
||||
+ 4
|
||||
)").unwrap(),
|
||||
)"
|
||||
)
|
||||
.unwrap(),
|
||||
next_expr,
|
||||
bin_expr(
|
||||
un_expr(UnOp::Plus, base_expr(BaseExprKind::Num)),
|
||||
@@ -677,29 +752,30 @@ mod test {
|
||||
);
|
||||
|
||||
test_parser!(
|
||||
Parser::try_from(r"(
|
||||
Parser::try_from(
|
||||
r"(
|
||||
+ 1
|
||||
+ 2
|
||||
+ 3
|
||||
+ 4
|
||||
,
|
||||
)").unwrap(),
|
||||
)"
|
||||
)
|
||||
.unwrap(),
|
||||
next_expr,
|
||||
base_expr(BaseExprKind::Tuple(vec![
|
||||
base_expr(BaseExprKind::Tuple(vec![bin_expr(
|
||||
un_expr(UnOp::Plus, base_expr(BaseExprKind::Num)),
|
||||
BinOp::Plus,
|
||||
bin_expr(
|
||||
un_expr(UnOp::Plus, base_expr(BaseExprKind::Num)),
|
||||
base_expr(BaseExprKind::Num),
|
||||
BinOp::Plus,
|
||||
bin_expr(
|
||||
base_expr(BaseExprKind::Num),
|
||||
BinOp::Plus,
|
||||
bin_expr(
|
||||
base_expr(BaseExprKind::Num),
|
||||
BinOp::Plus,
|
||||
base_expr(BaseExprKind::Num)
|
||||
)
|
||||
base_expr(BaseExprKind::Num)
|
||||
)
|
||||
)
|
||||
]))
|
||||
)]))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user