mirror of
https://github.com/Noratrieb/dilaria.git
synced 2026-01-17 02:45:02 +01:00
fix lists
This commit is contained in:
parent
7d45811913
commit
1c1cf390e6
4 changed files with 130 additions and 56 deletions
|
|
@ -1,6 +1,3 @@
|
||||||
# todo: calls (property access and function calls)
|
|
||||||
|
|
||||||
|
|
||||||
<program> ::= <statement-list>
|
<program> ::= <statement-list>
|
||||||
|
|
||||||
<statement-list> ::= { <statement> }
|
<statement-list> ::= { <statement> }
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
mod alloc;
|
|
||||||
mod ast;
|
mod ast;
|
||||||
mod errors;
|
mod errors;
|
||||||
mod lex;
|
mod lex;
|
||||||
|
|
|
||||||
|
|
@ -118,14 +118,7 @@ impl<'code> Parser<'code> {
|
||||||
|
|
||||||
fn fn_args(&mut self) -> ParseResult<'code, Vec<Ident>> {
|
fn fn_args(&mut self) -> ParseResult<'code, Vec<Ident>> {
|
||||||
self.expect(TokenType::ParenO)?;
|
self.expect(TokenType::ParenO)?;
|
||||||
let mut params = Vec::new();
|
let params = self.parse_list(TokenType::ParenC, Self::ident)?;
|
||||||
while self.peek_kind().ok_or(ParseErr::EOF("function argument"))? != &TokenType::ParenC {
|
|
||||||
let ident = self.ident()?;
|
|
||||||
params.push(ident);
|
|
||||||
|
|
||||||
// todo (ident ident) would be allowed here, but should not
|
|
||||||
self.maybe_consume(TokenType::Comma);
|
|
||||||
}
|
|
||||||
self.expect(TokenType::ParenC)?;
|
self.expect(TokenType::ParenC)?;
|
||||||
Ok(params)
|
Ok(params)
|
||||||
}
|
}
|
||||||
|
|
@ -367,17 +360,7 @@ impl<'code> Parser<'code> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn array_literal(&mut self, open_span: Span) -> ParseResult<'code, Expr> {
|
fn array_literal(&mut self, open_span: Span) -> ParseResult<'code, Expr> {
|
||||||
let mut elements = Vec::new();
|
let elements = self.parse_list(TokenType::BracketC, Self::expression)?;
|
||||||
while self
|
|
||||||
.peek_kind()
|
|
||||||
.ok_or(ParseErr::EOFExpecting(TokenType::BracketC))?
|
|
||||||
!= &TokenType::BracketC
|
|
||||||
{
|
|
||||||
let expr = self.expression()?;
|
|
||||||
elements.push(expr);
|
|
||||||
// todo [expr expr] would be allowed here, but should not
|
|
||||||
self.maybe_consume(TokenType::Comma);
|
|
||||||
}
|
|
||||||
let closing_bracket = self.expect(TokenType::BracketC)?;
|
let closing_bracket = self.expect(TokenType::BracketC)?;
|
||||||
Ok(Expr::Literal(Literal::Array(
|
Ok(Expr::Literal(Literal::Array(
|
||||||
elements,
|
elements,
|
||||||
|
|
@ -385,6 +368,41 @@ impl<'code> Parser<'code> {
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_list<T, F>(
|
||||||
|
&mut self,
|
||||||
|
close: TokenType<'code>,
|
||||||
|
mut parser: F,
|
||||||
|
) -> ParseResult<'code, Vec<T>>
|
||||||
|
where
|
||||||
|
F: FnMut(&mut Self) -> ParseResult<'code, T>,
|
||||||
|
{
|
||||||
|
let mut elements = Vec::new();
|
||||||
|
|
||||||
|
if self.peek_kind() == Some(&close) {
|
||||||
|
return Ok(elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
let expr = parser(self)?;
|
||||||
|
elements.push(expr);
|
||||||
|
|
||||||
|
while self
|
||||||
|
.peek_kind()
|
||||||
|
.ok_or_else(|| ParseErr::EOFExpecting(close.clone()))?
|
||||||
|
!= &close
|
||||||
|
{
|
||||||
|
self.expect(TokenType::Comma)?;
|
||||||
|
|
||||||
|
// trailing comma support
|
||||||
|
if self.peek_kind() == Some(&close) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let expr = parser(self)?;
|
||||||
|
elements.push(expr);
|
||||||
|
}
|
||||||
|
Ok(elements)
|
||||||
|
}
|
||||||
|
|
||||||
// token helpers
|
// token helpers
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|
|
||||||
|
|
@ -408,7 +408,7 @@ mod logical_or {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn and() {
|
fn and() {
|
||||||
test_literal_bin_op(TokenType::Or, BinaryOpKind::Or, parse_logical_or);
|
test_literal_bin_op(Or, BinaryOpKind::Or, parse_logical_or);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -427,7 +427,7 @@ mod logical_and {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn and() {
|
fn and() {
|
||||||
test_literal_bin_op(TokenType::And, BinaryOpKind::And, parse_logical_and);
|
test_literal_bin_op(And, BinaryOpKind::And, parse_logical_and);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -446,12 +446,12 @@ mod equality {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn not_equal() {
|
fn not_equal() {
|
||||||
test_literal_bin_op(TokenType::BangEqual, BinaryOpKind::NotEqual, parse_equality);
|
test_literal_bin_op(BangEqual, BinaryOpKind::NotEqual, parse_equality);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn equal() {
|
fn equal() {
|
||||||
test_literal_bin_op(TokenType::EqualEqual, BinaryOpKind::Equal, parse_equality);
|
test_literal_bin_op(EqualEqual, BinaryOpKind::Equal, parse_equality);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -470,30 +470,22 @@ mod comparison {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn greater() {
|
fn greater() {
|
||||||
test_literal_bin_op(TokenType::Greater, BinaryOpKind::Greater, parse_comparison);
|
test_literal_bin_op(Greater, BinaryOpKind::Greater, parse_comparison);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn greater_equal() {
|
fn greater_equal() {
|
||||||
test_literal_bin_op(
|
test_literal_bin_op(GreaterEqual, BinaryOpKind::GreaterEqual, parse_comparison);
|
||||||
TokenType::GreaterEqual,
|
|
||||||
BinaryOpKind::GreaterEqual,
|
|
||||||
parse_comparison,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn less() {
|
fn less() {
|
||||||
test_literal_bin_op(TokenType::Less, BinaryOpKind::Less, parse_comparison);
|
test_literal_bin_op(Less, BinaryOpKind::Less, parse_comparison);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn less_equal() {
|
fn less_equal() {
|
||||||
test_literal_bin_op(
|
test_literal_bin_op(LessEqual, BinaryOpKind::LessEqual, parse_comparison);
|
||||||
TokenType::LessEqual,
|
|
||||||
BinaryOpKind::LessEqual,
|
|
||||||
parse_comparison,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -512,12 +504,12 @@ mod term {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn add() {
|
fn add() {
|
||||||
test_literal_bin_op(TokenType::Plus, BinaryOpKind::Add, parse_term);
|
test_literal_bin_op(Plus, BinaryOpKind::Add, parse_term);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sub() {
|
fn sub() {
|
||||||
test_literal_bin_op(TokenType::Minus, BinaryOpKind::Sub, parse_term);
|
test_literal_bin_op(Minus, BinaryOpKind::Sub, parse_term);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -536,17 +528,17 @@ mod factor {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn multiply() {
|
fn multiply() {
|
||||||
test_literal_bin_op(TokenType::Asterisk, BinaryOpKind::Mul, parse_factor);
|
test_literal_bin_op(Asterisk, BinaryOpKind::Mul, parse_factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn divide() {
|
fn divide() {
|
||||||
test_literal_bin_op(TokenType::Slash, BinaryOpKind::Div, parse_factor);
|
test_literal_bin_op(Slash, BinaryOpKind::Div, parse_factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn modulo() {
|
fn modulo() {
|
||||||
test_literal_bin_op(TokenType::Percent, BinaryOpKind::Mod, parse_factor);
|
test_literal_bin_op(Percent, BinaryOpKind::Mod, parse_factor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -568,7 +560,7 @@ mod unary {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn not() {
|
fn not() {
|
||||||
let tokens = [TokenType::Not, TokenType::True].map(token).into();
|
let tokens = [Not, True].map(token).into();
|
||||||
let unary = parse_unary(tokens);
|
let unary = parse_unary(tokens);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Expr::UnaryOp(Box::new(UnaryOp {
|
Expr::UnaryOp(Box::new(UnaryOp {
|
||||||
|
|
@ -582,9 +574,7 @@ mod unary {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn neg() {
|
fn neg() {
|
||||||
let tokens = [TokenType::Minus, TokenType::Number(10.0)]
|
let tokens = [Minus, Number(10.0)].map(token).into();
|
||||||
.map(token)
|
|
||||||
.into();
|
|
||||||
let unary = parse_unary(tokens);
|
let unary = parse_unary(tokens);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Expr::UnaryOp(Box::new(UnaryOp {
|
Expr::UnaryOp(Box::new(UnaryOp {
|
||||||
|
|
@ -607,7 +597,7 @@ mod primary {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ident() {
|
fn ident() {
|
||||||
let tokens = [TokenType::Ident("tokens")].map(token).into();
|
let tokens = [Ident("tokens")].map(token).into();
|
||||||
let literal = parse_primary(tokens);
|
let literal = parse_primary(tokens);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Expr::Ident(Ident {
|
Expr::Ident(Ident {
|
||||||
|
|
@ -620,14 +610,14 @@ mod primary {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn string() {
|
fn string() {
|
||||||
let tokens = [TokenType::Number(10.0)].map(token).into();
|
let tokens = [Number(10.0)].map(token).into();
|
||||||
let literal = parse_primary(tokens);
|
let literal = parse_primary(tokens);
|
||||||
assert_eq!(num_lit(10.0), literal);
|
assert_eq!(num_lit(10.0), literal);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn number() {
|
fn number() {
|
||||||
let tokens = [TokenType::String("uwu".to_string())].map(token).into();
|
let tokens = [String("uwu".to_string())].map(token).into();
|
||||||
let literal = parse_primary(tokens);
|
let literal = parse_primary(tokens);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Expr::Literal(Literal::String("uwu".to_string(), Span::dummy())),
|
Expr::Literal(Literal::String("uwu".to_string(), Span::dummy())),
|
||||||
|
|
@ -637,14 +627,14 @@ mod primary {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_object() {
|
fn empty_object() {
|
||||||
let tokens = [TokenType::BraceO, TokenType::BraceC].map(token).into();
|
let tokens = [BraceO, BraceC].map(token).into();
|
||||||
let literal = parse_primary(tokens);
|
let literal = parse_primary(tokens);
|
||||||
assert_eq!(Expr::Literal(Literal::Object(Span::dummy())), literal);
|
assert_eq!(Expr::Literal(Literal::Object(Span::dummy())), literal);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_array() {
|
fn empty_array() {
|
||||||
let tokens = [TokenType::BracketO, TokenType::BracketC].map(token).into();
|
let tokens = [BracketO, BracketC].map(token).into();
|
||||||
let literal = parse_primary(tokens);
|
let literal = parse_primary(tokens);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Expr::Literal(Literal::Array(Vec::new(), Span::dummy())),
|
Expr::Literal(Literal::Array(Vec::new(), Span::dummy())),
|
||||||
|
|
@ -654,7 +644,7 @@ mod primary {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn r#false() {
|
fn r#false() {
|
||||||
let tokens = [TokenType::False].map(token).into();
|
let tokens = [False].map(token).into();
|
||||||
let literal = parse_primary(tokens);
|
let literal = parse_primary(tokens);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Expr::Literal(Literal::Boolean(false, Span::dummy())),
|
Expr::Literal(Literal::Boolean(false, Span::dummy())),
|
||||||
|
|
@ -664,7 +654,7 @@ mod primary {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn r#true() {
|
fn r#true() {
|
||||||
let tokens = [TokenType::True].map(token).into();
|
let tokens = [True].map(token).into();
|
||||||
let literal = parse_primary(tokens);
|
let literal = parse_primary(tokens);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Expr::Literal(Literal::Boolean(true, Span::dummy())),
|
Expr::Literal(Literal::Boolean(true, Span::dummy())),
|
||||||
|
|
@ -674,8 +664,78 @@ mod primary {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn null() {
|
fn null() {
|
||||||
let tokens = [TokenType::Null].map(token).into();
|
let tokens = [Null].map(token).into();
|
||||||
let literal = parse_primary(tokens);
|
let literal = parse_primary(tokens);
|
||||||
assert_eq!(Expr::Literal(Literal::Null(Span::dummy())), literal);
|
assert_eq!(Expr::Literal(Literal::Null(Span::dummy())), literal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn empty_array_literal() {
|
||||||
|
let tokens = [BracketO, BracketC].map(token).into();
|
||||||
|
let literal = parse_primary(tokens);
|
||||||
|
assert_eq!(
|
||||||
|
Expr::Literal(Literal::Array(Vec::new(), Span::dummy())),
|
||||||
|
literal
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn single_array_literal() {
|
||||||
|
let tokens = [BracketO, Number(10.0), BracketC].map(token).into();
|
||||||
|
let literal = parse_primary(tokens);
|
||||||
|
assert_eq!(
|
||||||
|
Expr::Literal(Literal::Array(vec![num_lit(10.0)], Span::dummy())),
|
||||||
|
literal
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn single_array_literal_trailing_comma() {
|
||||||
|
let tokens = [BracketO, Number(10.0), Comma, BracketC].map(token).into();
|
||||||
|
let literal = parse_primary(tokens);
|
||||||
|
assert_eq!(
|
||||||
|
Expr::Literal(Literal::Array(vec![num_lit(10.0)], Span::dummy())),
|
||||||
|
literal
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn two_array_literal() {
|
||||||
|
let tokens = [BracketO, Number(10.0), Comma, Number(10.0), BracketC]
|
||||||
|
.map(token)
|
||||||
|
.into();
|
||||||
|
let literal = parse_primary(tokens);
|
||||||
|
assert_eq!(
|
||||||
|
Expr::Literal(Literal::Array(
|
||||||
|
vec![num_lit(10.0), num_lit(10.0)],
|
||||||
|
Span::dummy()
|
||||||
|
)),
|
||||||
|
literal
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn two_array_literal_trailing_comma() {
|
||||||
|
let tokens = [BracketO, Number(10.0), Comma, Number(10.0), Comma, BracketC]
|
||||||
|
.map(token)
|
||||||
|
.into();
|
||||||
|
let literal = parse_primary(tokens);
|
||||||
|
assert_eq!(
|
||||||
|
Expr::Literal(Literal::Array(
|
||||||
|
vec![num_lit(10.0), num_lit(10.0)],
|
||||||
|
Span::dummy()
|
||||||
|
)),
|
||||||
|
literal
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn two_array_literal_no_comma() {
|
||||||
|
let tokens = [BracketO, Number(10.0), Number(10.0), BracketC]
|
||||||
|
.map(token)
|
||||||
|
.into();
|
||||||
|
let mut parser = parser(tokens);
|
||||||
|
let expr = parser.primary();
|
||||||
|
assert!(expr.is_err());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue