1
0
Fork 0

Add locations to AST Expressions

This commit is contained in:
Vili Sinervä 2025-01-31 19:49:46 +02:00
parent a2f96cc8df
commit 56281008e4
No known key found for this signature in database
GPG key ID: DF8FEAF54EFAC996
3 changed files with 320 additions and 144 deletions

View file

@ -1,21 +1,85 @@
use crate::compiler::token::CodeLocation;
use std::fmt;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum Expression<'source> { pub enum Expression<'source> {
EmptyLiteral(), EmptyLiteral(CodeLocation),
IntLiteral(u32), IntLiteral(CodeLocation, u32),
BoolLiteral(bool), BoolLiteral(CodeLocation, bool),
Identifier(&'source str), Identifier(CodeLocation, &'source str),
UnaryOp(&'source str, Box<Expression<'source>>), UnaryOp(CodeLocation, &'source str, Box<Expression<'source>>),
VarDeclaration(&'source str, Box<Expression<'source>>), VarDeclaration(CodeLocation, &'source str, Box<Expression<'source>>),
BinaryOp( BinaryOp(
CodeLocation,
Box<Expression<'source>>, Box<Expression<'source>>,
&'source str, &'source str,
Box<Expression<'source>>, Box<Expression<'source>>,
), ),
Conditional( Conditional(
CodeLocation,
Box<Expression<'source>>, Box<Expression<'source>>,
Box<Expression<'source>>, Box<Expression<'source>>,
Option<Box<Expression<'source>>>, Option<Box<Expression<'source>>>,
), ),
FunCall(&'source str, Vec<Expression<'source>>), FunCall(CodeLocation, &'source str, Vec<Expression<'source>>),
Block(Vec<Expression<'source>>), Block(CodeLocation, Vec<Expression<'source>>),
}
impl<'source> Expression<'source> {
pub fn loc(&self) -> CodeLocation {
match self {
Expression::EmptyLiteral(loc) => *loc,
Expression::IntLiteral(loc, _) => *loc,
Expression::BoolLiteral(loc, _) => *loc,
Expression::Identifier(loc, _) => *loc,
Expression::UnaryOp(loc, _, _) => *loc,
Expression::VarDeclaration(loc, _, _) => *loc,
Expression::BinaryOp(loc, _, _, _) => *loc,
Expression::Conditional(loc, _, _, _) => *loc,
Expression::FunCall(loc, _, _) => *loc,
Expression::Block(loc, _) => *loc,
}
}
fn expr_type_str(&self) -> &str {
match self {
Expression::EmptyLiteral(..) => "Empty literal",
Expression::IntLiteral(..) => "Integer literal",
Expression::BoolLiteral(..) => "Boolen literal",
Expression::Identifier(..) => "Identifier",
Expression::UnaryOp(..) => "Unary operation",
Expression::VarDeclaration(..) => "Variable declaration",
Expression::BinaryOp(..) => "Binary operation",
Expression::Conditional(..) => "Conditional",
Expression::FunCall(..) => "Function call",
Expression::Block(..) => "Block",
}
}
fn val_string(&self) -> String {
match self {
Expression::EmptyLiteral(..) => "".to_string(),
Expression::IntLiteral(_, val) => val.to_string(),
Expression::BoolLiteral(_, val) => val.to_string(),
Expression::Identifier(_, name) => name.to_string(),
Expression::UnaryOp(_, op, _) => op.to_string(),
Expression::VarDeclaration(_, name, _) => name.to_string(),
Expression::BinaryOp(_, _, op, _) => op.to_string(),
Expression::Conditional(_, condition, _, _) => format!("if {}", condition),
Expression::FunCall(_, name, args) => format!("{} with {} args", name, args.len()),
Expression::Block(_, expressions) => format!("with {} expressions", expressions.len()),
}
}
}
impl<'source> fmt::Display for Expression<'source> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{} {} at {}",
self.expr_type_str(),
self.val_string(),
self.loc()
)
}
} }

View file

@ -59,7 +59,12 @@ fn parse_expression<'source>(
if OPS[level].contains(&peek(pos, tokens).text) { if OPS[level].contains(&peek(pos, tokens).text) {
let operator_token = consume_strings(pos, tokens, OPS[level]); let operator_token = consume_strings(pos, tokens, OPS[level]);
let right = parse_expression(level, pos, tokens); let right = parse_expression(level, pos, tokens);
BinaryOp(Box::new(left), operator_token.text, Box::new(right)) BinaryOp(
operator_token.loc,
Box::new(left),
operator_token.text,
Box::new(right),
)
} else { } else {
left left
} }
@ -70,7 +75,12 @@ fn parse_expression<'source>(
let operator_token = consume_strings(pos, tokens, OPS[level]); let operator_token = consume_strings(pos, tokens, OPS[level]);
let right = parse_expression(level + 1, pos, tokens); let right = parse_expression(level + 1, pos, tokens);
left = BinaryOp(Box::new(left), operator_token.text, Box::new(right)); left = BinaryOp(
operator_token.loc,
Box::new(left),
operator_token.text,
Box::new(right),
);
} }
left left
} }
@ -78,7 +88,7 @@ fn parse_expression<'source>(
if OPS[level].contains(&peek(pos, tokens).text) { if OPS[level].contains(&peek(pos, tokens).text) {
let operator_token = consume_strings(pos, tokens, OPS[level]); let operator_token = consume_strings(pos, tokens, OPS[level]);
let right = parse_expression(level, pos, tokens); let right = parse_expression(level, pos, tokens);
UnaryOp(operator_token.text, Box::new(right)) UnaryOp(operator_token.loc, operator_token.text, Box::new(right))
} else { } else {
parse_expression(level + 1, pos, tokens) parse_expression(level + 1, pos, tokens)
} }
@ -119,14 +129,14 @@ fn parse_var_declaration<'source>(
tokens: &[Token<'source>], tokens: &[Token<'source>],
) -> Expression<'source> { ) -> Expression<'source> {
consume_string(pos, tokens, "var"); consume_string(pos, tokens, "var");
let name = consume_type(pos, tokens, TokenType::Identifier).text; let name_token = consume_type(pos, tokens, TokenType::Identifier);
consume_string(pos, tokens, "="); consume_string(pos, tokens, "=");
let value = parse_expression(0, pos, tokens); let value = parse_expression(0, pos, tokens);
VarDeclaration(name, Box::new(value)) VarDeclaration(name_token.loc, name_token.text, Box::new(value))
} }
fn parse_conditional<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> Expression<'source> { fn parse_conditional<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> Expression<'source> {
consume_string(pos, tokens, "if"); let start = consume_string(pos, tokens, "if");
let condition = Box::new(parse_expression(0, pos, tokens)); let condition = Box::new(parse_expression(0, pos, tokens));
consume_string(pos, tokens, "then"); consume_string(pos, tokens, "then");
let then_expr = Box::new(parse_expression(0, pos, tokens)); let then_expr = Box::new(parse_expression(0, pos, tokens));
@ -139,7 +149,7 @@ fn parse_conditional<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> Exp
_ => None, _ => None,
}; };
Conditional(condition, then_expr, else_expr) Conditional(start.loc, condition, then_expr, else_expr)
} }
fn parse_parenthesized<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> Expression<'source> { fn parse_parenthesized<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> Expression<'source> {
@ -150,7 +160,7 @@ fn parse_parenthesized<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> E
} }
fn parse_block<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> Expression<'source> { fn parse_block<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> Expression<'source> {
consume_string(pos, tokens, "{"); let start = consume_string(pos, tokens, "{");
let mut expressions = Vec::new(); let mut expressions = Vec::new();
loop { loop {
@ -171,14 +181,15 @@ fn parse_block<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> Expressio
} }
// If the last expression of the block ended in a semicolon, empty return // If the last expression of the block ended in a semicolon, empty return
if peek(pos, tokens).text == "}" { let next_token = peek(pos, tokens);
expressions.push(EmptyLiteral()); if next_token.text == "}" {
expressions.push(EmptyLiteral(next_token.loc));
break; break;
} }
} }
consume_string(pos, tokens, "}"); consume_string(pos, tokens, "}");
Block(expressions) Block(start.loc, expressions)
} }
fn parse_function<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> Expression<'source> { fn parse_function<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> Expression<'source> {
@ -198,13 +209,14 @@ fn parse_function<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> Expres
} }
} }
consume_string(pos, tokens, ")"); consume_string(pos, tokens, ")");
FunCall(identifier.text, arguments) FunCall(identifier.loc, identifier.text, arguments)
} }
fn parse_int_literal<'source>(pos: &mut usize, tokens: &[Token]) -> Expression<'source> { fn parse_int_literal<'source>(pos: &mut usize, tokens: &[Token]) -> Expression<'source> {
let token = consume_type(pos, tokens, TokenType::Integer); let token = consume_type(pos, tokens, TokenType::Integer);
IntLiteral( IntLiteral(
token.loc,
token token
.text .text
.parse::<u32>() .parse::<u32>()
@ -216,13 +228,13 @@ fn parse_bool_literal<'source>(pos: &mut usize, tokens: &[Token]) -> Expression<
let token = consume_type(pos, tokens, TokenType::Identifier); let token = consume_type(pos, tokens, TokenType::Identifier);
match token.text { match token.text {
"true" => BoolLiteral(true), "true" => BoolLiteral(token.loc, true),
"false" => BoolLiteral(false), "false" => BoolLiteral(token.loc, false),
_ => panic!("Fatal parser error! Expected bool literal but found {token}"), _ => panic!("Fatal parser error! Expected bool literal but found {token}"),
} }
} }
fn parse_identifier<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> Expression<'source> { fn parse_identifier<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> Expression<'source> {
let token = consume_type(pos, tokens, TokenType::Identifier); let token = consume_type(pos, tokens, TokenType::Identifier);
Identifier(token.text) Identifier(token.loc, token.text)
} }

View file

@ -1,33 +1,111 @@
use super::*; use super::*;
use crate::compiler::tokenizer::tokenize; use crate::compiler::{token::CodeLocation, tokenizer::tokenize};
macro_rules! bool_ast {
($x:expr) => {
BoolLiteral(CodeLocation::new(usize::MAX, usize::MAX), $x)
};
}
macro_rules! bool_ast_b {
($x:expr) => {
Box::new(bool_ast!($x))
};
}
macro_rules! int_ast { macro_rules! int_ast {
($x:expr) => { ($x:expr) => {
Box::new(IntLiteral($x)) IntLiteral(CodeLocation::new(usize::MAX, usize::MAX), $x)
};
}
macro_rules! int_ast_b {
($x:expr) => {
Box::new(int_ast!($x))
}; };
} }
macro_rules! id_ast { macro_rules! id_ast {
($x:expr) => { ($x:expr) => {
Box::new(Identifier($x)) Identifier(CodeLocation::new(usize::MAX, usize::MAX), $x)
};
}
macro_rules! id_ast_b {
($x:expr) => {
Box::new(id_ast!($x))
}; };
} }
macro_rules! un_ast { macro_rules! un_ast {
($x:expr, $y:expr) => { ($x:expr, $y:expr) => {
Box::new(UnaryOp($x, $y)) UnaryOp(CodeLocation::new(usize::MAX, usize::MAX), $x, $y)
};
}
macro_rules! un_ast_b {
($x:expr, $y:expr) => {
Box::new(un_ast!($x, $y))
}; };
} }
macro_rules! bin_ast { macro_rules! bin_ast {
($x:expr, $y:expr, $z:expr) => { ($x:expr, $y:expr, $z:expr) => {
Box::new(BinaryOp($x, $y, $z)) BinaryOp(CodeLocation::new(usize::MAX, usize::MAX), $x, $y, $z)
}; };
} }
macro_rules! bool_ast { macro_rules! bin_ast_b {
($x:expr, $y:expr, $z:expr) => {
Box::new(bin_ast!($x, $y, $z))
};
}
macro_rules! con_ast {
($x:expr, $y:expr, $z:expr) => {
Conditional(CodeLocation::new(usize::MAX, usize::MAX), $x, $y, $z)
};
}
macro_rules! con_ast_b {
($x:expr, $y:expr, $z:expr) => {
Box::new(con_ast!($x, $y, $z))
};
}
macro_rules! fun_ast {
($x:expr, $y:expr) => {
FunCall(CodeLocation::new(usize::MAX, usize::MAX), $x, $y)
};
}
macro_rules! fun_ast_b {
($x:expr, $y:expr) => {
Box::new(fun_ast!($x, $y))
};
}
macro_rules! block_ast {
($x:expr) => { ($x:expr) => {
Box::new(BoolLiteral($x)) Block(CodeLocation::new(usize::MAX, usize::MAX), $x)
};
}
macro_rules! block_ast_b {
($x:expr) => {
Box::new(block_ast!($x))
};
}
macro_rules! empty_ast {
() => {
EmptyLiteral(CodeLocation::new(usize::MAX, usize::MAX))
};
}
macro_rules! var_ast {
($x:expr, $y:expr) => {
VarDeclaration(CodeLocation::new(usize::MAX, usize::MAX), $x, $y)
}; };
} }
@ -58,16 +136,16 @@ fn test_invalid_end() {
#[test] #[test]
fn test_binary_op_basic() { fn test_binary_op_basic() {
let result = parse(&tokenize("1 + 23")); let result = parse(&tokenize("1 + 23"));
assert_eq!(result, BinaryOp(int_ast!(1), "+", int_ast!(23))); assert_eq!(result, bin_ast!(int_ast_b!(1), "+", int_ast_b!(23)));
let result = parse(&tokenize("4 - 56")); let result = parse(&tokenize("4 - 56"));
assert_eq!(result, BinaryOp(int_ast!(4), "-", int_ast!(56))); assert_eq!(result, bin_ast!(int_ast_b!(4), "-", int_ast_b!(56)));
let result = parse(&tokenize("1 * 2")); let result = parse(&tokenize("1 * 2"));
assert_eq!(result, BinaryOp(int_ast!(1), "*", int_ast!(2))); assert_eq!(result, bin_ast!(int_ast_b!(1), "*", int_ast_b!(2)));
let result = parse(&tokenize("1 / 2")); let result = parse(&tokenize("1 / 2"));
assert_eq!(result, BinaryOp(int_ast!(1), "/", int_ast!(2))); assert_eq!(result, bin_ast!(int_ast_b!(1), "/", int_ast_b!(2)));
} }
#[test] #[test]
@ -75,22 +153,26 @@ fn test_binary_op_all_levels() {
let result = parse(&tokenize("1 * 2 + 3 < 4 == 5 and 6 or 7")); let result = parse(&tokenize("1 * 2 + 3 < 4 == 5 and 6 or 7"));
assert_eq!( assert_eq!(
result, result,
BinaryOp(
bin_ast!( bin_ast!(
bin_ast!( bin_ast_b!(
bin_ast!( bin_ast_b!(
bin_ast!(bin_ast!(int_ast!(1), "*", int_ast!(2)), "+", int_ast!(3)), bin_ast_b!(
bin_ast_b!(
bin_ast_b!(int_ast_b!(1), "*", int_ast_b!(2)),
"+",
int_ast_b!(3)
),
"<", "<",
int_ast!(4) int_ast_b!(4)
), ),
"==", "==",
int_ast!(5) int_ast_b!(5)
), ),
"and", "and",
int_ast!(6) int_ast_b!(6)
), ),
"or", "or",
int_ast!(7) int_ast_b!(7)
) )
); );
} }
@ -98,10 +180,10 @@ fn test_binary_op_all_levels() {
#[test] #[test]
fn test_binary_op_identifier() { fn test_binary_op_identifier() {
let result = parse(&tokenize("a + 1")); let result = parse(&tokenize("a + 1"));
assert_eq!(result, BinaryOp(id_ast!("a"), "+", int_ast!(1))); assert_eq!(result, bin_ast!(id_ast_b!("a"), "+", int_ast_b!(1)));
let result = parse(&tokenize("1 - a")); let result = parse(&tokenize("1 - a"));
assert_eq!(result, BinaryOp(int_ast!(1), "-", id_ast!("a"))); assert_eq!(result, bin_ast!(int_ast_b!(1), "-", id_ast_b!("a")));
} }
#[test] #[test]
@ -109,7 +191,11 @@ fn test_binary_op_multiple() {
let result = parse(&tokenize("1 + 2 - 3")); let result = parse(&tokenize("1 + 2 - 3"));
assert_eq!( assert_eq!(
result, result,
BinaryOp(bin_ast!(int_ast!(1), "+", int_ast!(2)), "-", int_ast!(3)) bin_ast!(
bin_ast_b!(int_ast_b!(1), "+", int_ast_b!(2)),
"-",
int_ast_b!(3)
)
); );
} }
@ -118,13 +204,21 @@ fn test_binary_op_precedence() {
let result = parse(&tokenize("1 + 2 * 3")); let result = parse(&tokenize("1 + 2 * 3"));
assert_eq!( assert_eq!(
result, result,
BinaryOp(int_ast!(1), "+", bin_ast!(int_ast!(2), "*", int_ast!(3)),) bin_ast!(
int_ast_b!(1),
"+",
bin_ast_b!(int_ast_b!(2), "*", int_ast_b!(3))
)
); );
let result = parse(&tokenize("1 - 2 / 3")); let result = parse(&tokenize("1 - 2 / 3"));
assert_eq!( assert_eq!(
result, result,
BinaryOp(int_ast!(1), "-", bin_ast!(int_ast!(2), "/", int_ast!(3)),) bin_ast!(
int_ast_b!(1),
"-",
bin_ast_b!(int_ast_b!(2), "/", int_ast_b!(3))
)
); );
} }
@ -133,7 +227,11 @@ fn test_assignment_basic() {
let result = parse(&tokenize("a = 1 + 2")); let result = parse(&tokenize("a = 1 + 2"));
assert_eq!( assert_eq!(
result, result,
BinaryOp(id_ast!("a"), "=", bin_ast!(int_ast!(1), "+", int_ast!(2))) bin_ast!(
id_ast_b!("a"),
"=",
bin_ast_b!(int_ast_b!(1), "+", int_ast_b!(2))
)
); );
} }
@ -142,10 +240,14 @@ fn test_assignment_chain() {
let result = parse(&tokenize("a = b = 1 + 2")); let result = parse(&tokenize("a = b = 1 + 2"));
assert_eq!( assert_eq!(
result, result,
BinaryOp( bin_ast!(
id_ast!("a"), id_ast_b!("a"),
"=", "=",
bin_ast!(id_ast!("b"), "=", bin_ast!(int_ast!(1), "+", int_ast!(2))) bin_ast_b!(
id_ast_b!("b"),
"=",
bin_ast_b!(int_ast_b!(1), "+", int_ast_b!(2))
)
) )
); );
} }
@ -159,36 +261,40 @@ fn test_assignment_invalid() {
#[test] #[test]
fn test_unary_basic() { fn test_unary_basic() {
let result = parse(&tokenize("not x")); let result = parse(&tokenize("not x"));
assert_eq!(result, UnaryOp("not", id_ast!("x"))); assert_eq!(result, un_ast!("not", id_ast_b!("x")));
let result = parse(&tokenize("-x")); let result = parse(&tokenize("-x"));
assert_eq!(result, UnaryOp("-", id_ast!("x"))); assert_eq!(result, un_ast!("-", id_ast_b!("x")));
let result = parse(&tokenize("-1")); let result = parse(&tokenize("-1"));
assert_eq!(result, UnaryOp("-", int_ast!(1))); assert_eq!(result, un_ast!("-", int_ast_b!(1)));
let result = parse(&tokenize("-1 + 2")); let result = parse(&tokenize("-1 + 2"));
assert_eq!( assert_eq!(
result, result,
BinaryOp(un_ast!("-", int_ast!(1)), "+", int_ast!(2)) bin_ast!(un_ast_b!("-", int_ast_b!(1)), "+", int_ast_b!(2))
); );
} }
#[test] #[test]
fn test_unary_chain() { fn test_unary_chain() {
let result = parse(&tokenize("not not x")); let result = parse(&tokenize("not not x"));
assert_eq!(result, UnaryOp("not", un_ast!("not", id_ast!("x")))); assert_eq!(result, un_ast!("not", un_ast_b!("not", id_ast_b!("x"))));
let result = parse(&tokenize("--x")); let result = parse(&tokenize("--x"));
assert_eq!(result, UnaryOp("-", un_ast!("-", id_ast!("x")))); assert_eq!(result, un_ast!("-", un_ast_b!("-", id_ast_b!("x"))));
let result = parse(&tokenize("--1")); let result = parse(&tokenize("--1"));
assert_eq!(result, UnaryOp("-", un_ast!("-", int_ast!(1)))); assert_eq!(result, un_ast!("-", un_ast_b!("-", int_ast_b!(1))));
let result = parse(&tokenize("--1 + 2")); let result = parse(&tokenize("--1 + 2"));
assert_eq!( assert_eq!(
result, result,
BinaryOp(un_ast!("-", un_ast!("-", int_ast!(1))), "+", int_ast!(2)) bin_ast!(
un_ast_b!("-", un_ast_b!("-", int_ast_b!(1))),
"+",
int_ast_b!(2)
)
); );
} }
@ -197,7 +303,11 @@ fn test_parenthesized() {
let result = parse(&tokenize("(1+2)*3")); let result = parse(&tokenize("(1+2)*3"));
assert_eq!( assert_eq!(
result, result,
BinaryOp(bin_ast!(int_ast!(1), "+", int_ast!(2)), "*", int_ast!(3),) bin_ast!(
bin_ast_b!(int_ast_b!(1), "+", int_ast_b!(2)),
"*",
int_ast_b!(3)
)
); );
} }
@ -206,16 +316,24 @@ fn test_parenthesized_nested() {
let result = parse(&tokenize("((1 - 2))/3")); let result = parse(&tokenize("((1 - 2))/3"));
assert_eq!( assert_eq!(
result, result,
BinaryOp(bin_ast!(int_ast!(1), "-", int_ast!(2)), "/", int_ast!(3),) bin_ast!(
bin_ast_b!(int_ast_b!(1), "-", int_ast_b!(2)),
"/",
int_ast_b!(3)
)
); );
let result = parse(&tokenize("((1 + 2)*3) / 4")); let result = parse(&tokenize("((1 + 2)*3) / 4"));
assert_eq!( assert_eq!(
result, result,
BinaryOp( bin_ast!(
bin_ast!(bin_ast!(int_ast!(1), "+", int_ast!(2)), "*", int_ast!(3)), bin_ast_b!(
bin_ast_b!(int_ast_b!(1), "+", int_ast_b!(2)),
"*",
int_ast_b!(3)
),
"/", "/",
int_ast!(4) int_ast_b!(4)
) )
); );
} }
@ -231,7 +349,11 @@ fn test_if_then() {
let result = parse(&tokenize("if 1 + 2 then 3")); let result = parse(&tokenize("if 1 + 2 then 3"));
assert_eq!( assert_eq!(
result, result,
Conditional(bin_ast!(int_ast!(1), "+", int_ast!(2)), int_ast!(3), None,) con_ast!(
bin_ast_b!(int_ast_b!(1), "+", int_ast_b!(2)),
int_ast_b!(3),
None
)
); );
} }
@ -240,10 +362,10 @@ fn test_if_then_else() {
let result = parse(&tokenize("if a then b + c else 1 * 2")); let result = parse(&tokenize("if a then b + c else 1 * 2"));
assert_eq!( assert_eq!(
result, result,
Conditional( con_ast!(
id_ast!("a"), id_ast_b!("a"),
bin_ast!(id_ast!("b"), "+", id_ast!("c")), bin_ast_b!(id_ast_b!("b"), "+", id_ast_b!("c")),
Some(bin_ast!(int_ast!(1), "*", int_ast!(2))) Some(bin_ast_b!(int_ast_b!(1), "*", int_ast_b!(2)))
) )
); );
} }
@ -253,10 +375,10 @@ fn test_if_then_else_embedded() {
let result = parse(&tokenize("1 + if true then 2 else 3")); let result = parse(&tokenize("1 + if true then 2 else 3"));
assert_eq!( assert_eq!(
result, result,
BinaryOp( bin_ast!(
int_ast!(1), int_ast_b!(1),
"+", "+",
Box::new(Conditional(bool_ast!(true), int_ast!(2), Some(int_ast!(3)))) con_ast_b!(bool_ast_b!(true), int_ast_b!(2), Some(int_ast_b!(3)))
) )
); );
} }
@ -266,14 +388,10 @@ fn test_if_then_else_nested() {
let result = parse(&tokenize("if true then if false then 1 else 2 else 3")); let result = parse(&tokenize("if true then if false then 1 else 2 else 3"));
assert_eq!( assert_eq!(
result, result,
Conditional( con_ast!(
bool_ast!(true), bool_ast_b!(true),
Box::new(Conditional( con_ast_b!(bool_ast_b!(false), int_ast_b!(1), Some(int_ast_b!(2))),
bool_ast!(false), Some(int_ast_b!(3))
int_ast!(1),
Some(int_ast!(2))
)),
Some(int_ast!(3))
) )
); );
} }
@ -287,22 +405,19 @@ fn test_if_no_then() {
#[test] #[test]
fn test_func_basic() { fn test_func_basic() {
let result = parse(&tokenize("f(a, b)")); let result = parse(&tokenize("f(a, b)"));
assert_eq!( assert_eq!(result, fun_ast!("f", vec![id_ast!("a"), id_ast!("b"),]));
result,
FunCall("f", vec![Identifier("a"), Identifier("b"),])
);
let result = parse(&tokenize("f(a, 1 + 2)")); let result = parse(&tokenize("f(a, 1 + 2)"));
assert_eq!( assert_eq!(
result, result,
FunCall( fun_ast!(
"f", "f",
vec![Identifier("a"), BinaryOp(int_ast!(1), "+", int_ast!(2),),] vec![id_ast!("a"), bin_ast!(int_ast_b!(1), "+", int_ast_b!(2)),]
) )
); );
let result = parse(&tokenize("f()")); let result = parse(&tokenize("f()"));
assert_eq!(result, FunCall("f", vec![])); assert_eq!(result, fun_ast!("f", vec![]));
} }
#[test] #[test]
@ -310,11 +425,7 @@ fn test_func_embedded() {
let result = parse(&tokenize("1 + f(a)")); let result = parse(&tokenize("1 + f(a)"));
assert_eq!( assert_eq!(
result, result,
BinaryOp( bin_ast!(int_ast_b!(1), "+", fun_ast_b!("f", vec![id_ast!("a")]))
int_ast!(1),
"+",
Box::new(FunCall("f", vec![Identifier("a")]))
)
); );
} }
@ -323,10 +434,7 @@ fn test_func_nested() {
let result = parse(&tokenize("f(a, g(b))")); let result = parse(&tokenize("f(a, g(b))"));
assert_eq!( assert_eq!(
result, result,
FunCall( fun_ast!("f", vec![id_ast!("a"), fun_ast!("g", vec![id_ast!("b")]),])
"f",
vec![Identifier("a"), FunCall("g", vec![Identifier("b")]),]
)
); );
} }
@ -347,19 +455,19 @@ fn test_block_basic() {
let result = parse(&tokenize("{ a = 1; b; }")); let result = parse(&tokenize("{ a = 1; b; }"));
assert_eq!( assert_eq!(
result, result,
Block(vec![ block_ast!(vec![
BinaryOp(id_ast!("a"), "=", int_ast!(1)), bin_ast!(id_ast_b!("a"), "=", int_ast_b!(1)),
Identifier("b"), id_ast!("b"),
EmptyLiteral() empty_ast!()
]) ])
); );
let result = parse(&tokenize("{ a = 1; b }")); let result = parse(&tokenize("{ a = 1; b }"));
assert_eq!( assert_eq!(
result, result,
Block(vec![ block_ast!(vec![
BinaryOp(id_ast!("a"), "=", int_ast!(1)), bin_ast!(id_ast_b!("a"), "=", int_ast_b!(1)),
Identifier("b"), id_ast!("b"),
]) ])
); );
} }
@ -369,10 +477,10 @@ fn test_block_embedded() {
let result = parse(&tokenize("{ 1 + 2 } * 3")); let result = parse(&tokenize("{ 1 + 2 } * 3"));
assert_eq!( assert_eq!(
result, result,
BinaryOp( bin_ast!(
Box::new(Block(vec![BinaryOp(int_ast!(1), "+", int_ast!(2))])), block_ast_b!(vec![bin_ast!(int_ast_b!(1), "+", int_ast_b!(2))]),
"*", "*",
int_ast!(3) int_ast_b!(3)
) )
); );
} }
@ -382,10 +490,10 @@ fn test_block_nested() {
let result = parse(&tokenize("{ a = { 1 + 2}}")); let result = parse(&tokenize("{ a = { 1 + 2}}"));
assert_eq!( assert_eq!(
result, result,
Block(vec![BinaryOp( block_ast!(vec![bin_ast!(
id_ast!("a"), id_ast_b!("a"),
"=", "=",
Box::new(Block(vec![BinaryOp(int_ast!(1), "+", int_ast!(2))])), block_ast_b!(vec![bin_ast!(int_ast_b!(1), "+", int_ast_b!(2))])
)]) )])
); );
} }
@ -405,15 +513,15 @@ fn test_block_missing_semicolon() {
#[test] #[test]
fn test_var_basic() { fn test_var_basic() {
let result = parse(&tokenize("var x = 1")); let result = parse(&tokenize("var x = 1"));
assert_eq!(result, VarDeclaration("x", int_ast!(1))); assert_eq!(result, var_ast!("x", int_ast_b!(1)));
let result = parse(&tokenize("{ var x = 1; x = 2; }")); let result = parse(&tokenize("{ var x = 1; x = 2; }"));
assert_eq!( assert_eq!(
result, result,
Block(vec![ block_ast!(vec![
VarDeclaration("x", int_ast!(1)), var_ast!("x", int_ast_b!(1)),
BinaryOp(id_ast!("x"), "=", int_ast!(2)), bin_ast!(id_ast_b!("x"), "=", int_ast_b!(2)),
EmptyLiteral() empty_ast!()
]) ])
); );
} }
@ -435,61 +543,53 @@ fn test_omitting_semicolons() {
let result = parse(&tokenize("{ { a } { b } }")); let result = parse(&tokenize("{ { a } { b } }"));
assert_eq!( assert_eq!(
result, result,
Block(vec![ block_ast!(vec![
Block(vec![Identifier("a")]), block_ast!(vec![id_ast!("a")]),
Block(vec![Identifier("b")]) block_ast!(vec![id_ast!("b")])
]) ])
); );
let result = parse(&tokenize("{ if true then { a } b }")); let result = parse(&tokenize("{ if true then { a } b }"));
assert_eq!( assert_eq!(
result, result,
Block(vec![ block_ast!(vec![
Conditional( con_ast!(bool_ast_b!(true), block_ast_b!(vec![id_ast!("a")]), None),
bool_ast!(true), id_ast!("b"),
Box::new(Block(vec![Identifier("a")])),
None
),
Identifier("b"),
]) ])
); );
let result = parse(&tokenize("{ if true then { a }; b }")); let result = parse(&tokenize("{ if true then { a }; b }"));
assert_eq!( assert_eq!(
result, result,
Block(vec![ block_ast!(vec![
Conditional( con_ast!(bool_ast_b!(true), block_ast_b!(vec![id_ast!("a")]), None),
bool_ast!(true), id_ast!("b"),
Box::new(Block(vec![Identifier("a")])),
None
),
Identifier("b"),
]) ])
); );
let result = parse(&tokenize("{ if true then { a } else { b } c }")); let result = parse(&tokenize("{ if true then { a } else { b } c }"));
assert_eq!( assert_eq!(
result, result,
Block(vec![ block_ast!(vec![
Conditional( con_ast!(
bool_ast!(true), bool_ast_b!(true),
Box::new(Block(vec![Identifier("a")])), block_ast_b!(vec![id_ast!("a")]),
Some(Box::new(Block(vec![Identifier("b")]))) Some(block_ast_b!(vec![id_ast!("b")]))
), ),
Identifier("c"), id_ast!("c"),
]) ])
); );
let result = parse(&tokenize("x = { { f(a) } { b } }")); let result = parse(&tokenize("x = { { f(a) } { b } }"));
assert_eq!( assert_eq!(
result, result,
BinaryOp( bin_ast!(
id_ast!("x"), id_ast_b!("x"),
"=", "=",
Box::new(Block(vec![ block_ast_b!(vec![
Block(vec![FunCall("f", vec![Identifier("a")])]), block_ast!(vec![fun_ast!("f", vec![id_ast!("a")])]),
Block(vec![Identifier("b")]), block_ast!(vec![id_ast!("b")]),
])) ])
) )
); );
} }