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::LParen,
|
||||||
TokenKind::LBracket,
|
TokenKind::LBracket,
|
||||||
TokenKind::LBrace,
|
TokenKind::LBrace,
|
||||||
|
TokenKind::ObjBrace,
|
||||||
];
|
];
|
||||||
|
|
||||||
const UN_EXPR_START: &[TokenKind] = &[TokenKind::Plus, TokenKind::Minus, TokenKind::Bang];
|
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
|
// Expression parsing
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -165,7 +175,17 @@ impl<'t> Parser<'t> {
|
|||||||
}
|
}
|
||||||
.into()
|
.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 => {
|
TokenKind::LParen => {
|
||||||
let prev_skip = self.set_skip_newlines(true)?;
|
let prev_skip = self.set_skip_newlines(true)?;
|
||||||
let first = self.next_expr()?;
|
let first = self.next_expr()?;
|
||||||
@@ -175,7 +195,7 @@ impl<'t> Parser<'t> {
|
|||||||
self.set_skip_newlines(prev_skip)?;
|
self.set_skip_newlines(prev_skip)?;
|
||||||
let end_token = self.expect_token_kind(TokenKind::RParen, "end of tuple")?;
|
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);
|
list.insert(0, first);
|
||||||
Expr::Base(
|
Expr::Base(
|
||||||
BaseExpr {
|
BaseExpr {
|
||||||
@@ -212,6 +232,28 @@ impl<'t> Parser<'t> {
|
|||||||
Ok(list_items)
|
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
|
// Token matching functions
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -220,13 +262,19 @@ impl<'t> Parser<'t> {
|
|||||||
let mut next_token = self.lexer.next_token()?;
|
let mut next_token = self.lexer.next_token()?;
|
||||||
|
|
||||||
if self.is_skip_newlines() {
|
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()?;
|
next_token = self.lexer.next_token()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.is_token_kind(TokenKind::Newline) {
|
if self.is_token_kind(TokenKind::Newline) {
|
||||||
self.curr_token = next_token;
|
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()?;
|
next_token = self.lexer.next_token()?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -485,9 +533,7 @@ mod test {
|
|||||||
test_parser!(
|
test_parser!(
|
||||||
Parser::try_from("(:sym,)").unwrap(),
|
Parser::try_from("(:sym,)").unwrap(),
|
||||||
next_expr,
|
next_expr,
|
||||||
base_expr(BaseExprKind::Tuple(vec![
|
base_expr(BaseExprKind::Tuple(vec![base_expr(BaseExprKind::Sym),]))
|
||||||
base_expr(BaseExprKind::Sym),
|
|
||||||
]))
|
|
||||||
);
|
);
|
||||||
|
|
||||||
test_parser!(
|
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]
|
#[test]
|
||||||
fn test_bin_expr() {
|
fn test_bin_expr() {
|
||||||
test_parser!(
|
test_parser!(
|
||||||
@@ -613,26 +679,30 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_multiline_exprs() {
|
fn test_multiline_exprs() {
|
||||||
test_parser!(
|
test_parser!(
|
||||||
Parser::try_from(r"[
|
Parser::try_from(
|
||||||
|
r"[
|
||||||
1,
|
1,
|
||||||
x,
|
x,
|
||||||
['value', :value],
|
['value', :value],
|
||||||
:sym
|
:sym
|
||||||
]").unwrap(),
|
]"
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
next_expr,
|
next_expr,
|
||||||
base_expr(BaseExprKind::List(vec![
|
base_expr(BaseExprKind::List(vec![
|
||||||
base_expr(BaseExprKind::Num),
|
base_expr(BaseExprKind::Num),
|
||||||
base_expr(BaseExprKind::Ident),
|
base_expr(BaseExprKind::Ident),
|
||||||
base_expr(BaseExprKind::List(vec![
|
base_expr(BaseExprKind::List(vec![
|
||||||
base_expr(BaseExprKind::Str),
|
base_expr(BaseExprKind::Str),
|
||||||
base_expr(BaseExprKind::Sym),
|
base_expr(BaseExprKind::Sym),
|
||||||
])),
|
])),
|
||||||
base_expr(BaseExprKind::Sym),
|
base_expr(BaseExprKind::Sym),
|
||||||
]))
|
]))
|
||||||
);
|
);
|
||||||
|
|
||||||
test_parser!(
|
test_parser!(
|
||||||
Parser::try_from(r"(
|
Parser::try_from(
|
||||||
|
r"(
|
||||||
1,
|
1,
|
||||||
x,
|
x,
|
||||||
[
|
[
|
||||||
@@ -640,26 +710,31 @@ mod test {
|
|||||||
'value',
|
'value',
|
||||||
],
|
],
|
||||||
:sym
|
:sym
|
||||||
)").unwrap(),
|
)"
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
next_expr,
|
next_expr,
|
||||||
base_expr(BaseExprKind::Tuple(vec![
|
base_expr(BaseExprKind::Tuple(vec![
|
||||||
base_expr(BaseExprKind::Num),
|
base_expr(BaseExprKind::Num),
|
||||||
base_expr(BaseExprKind::Ident),
|
base_expr(BaseExprKind::Ident),
|
||||||
base_expr(BaseExprKind::List(vec![
|
base_expr(BaseExprKind::List(vec![
|
||||||
base_expr(BaseExprKind::Sym),
|
base_expr(BaseExprKind::Sym),
|
||||||
base_expr(BaseExprKind::Str),
|
base_expr(BaseExprKind::Str),
|
||||||
])),
|
])),
|
||||||
base_expr(BaseExprKind::Sym),
|
base_expr(BaseExprKind::Sym),
|
||||||
]))
|
]))
|
||||||
);
|
);
|
||||||
|
|
||||||
test_parser!(
|
test_parser!(
|
||||||
Parser::try_from(r"(
|
Parser::try_from(
|
||||||
|
r"(
|
||||||
+ 1
|
+ 1
|
||||||
+ 2
|
+ 2
|
||||||
+ 3
|
+ 3
|
||||||
+ 4
|
+ 4
|
||||||
)").unwrap(),
|
)"
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
next_expr,
|
next_expr,
|
||||||
bin_expr(
|
bin_expr(
|
||||||
un_expr(UnOp::Plus, base_expr(BaseExprKind::Num)),
|
un_expr(UnOp::Plus, base_expr(BaseExprKind::Num)),
|
||||||
@@ -677,29 +752,30 @@ mod test {
|
|||||||
);
|
);
|
||||||
|
|
||||||
test_parser!(
|
test_parser!(
|
||||||
Parser::try_from(r"(
|
Parser::try_from(
|
||||||
|
r"(
|
||||||
+ 1
|
+ 1
|
||||||
+ 2
|
+ 2
|
||||||
+ 3
|
+ 3
|
||||||
+ 4
|
+ 4
|
||||||
,
|
,
|
||||||
)").unwrap(),
|
)"
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
next_expr,
|
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(
|
bin_expr(
|
||||||
un_expr(UnOp::Plus, base_expr(BaseExprKind::Num)),
|
base_expr(BaseExprKind::Num),
|
||||||
BinOp::Plus,
|
BinOp::Plus,
|
||||||
bin_expr(
|
bin_expr(
|
||||||
base_expr(BaseExprKind::Num),
|
base_expr(BaseExprKind::Num),
|
||||||
BinOp::Plus,
|
BinOp::Plus,
|
||||||
bin_expr(
|
base_expr(BaseExprKind::Num)
|
||||||
base_expr(BaseExprKind::Num),
|
|
||||||
BinOp::Plus,
|
|
||||||
base_expr(BaseExprKind::Num)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
]))
|
)]))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user