1
0
Fork 0

Tweaks and macros to make code more compact

This commit is contained in:
Vili Sinervä 2025-01-29 15:14:27 +02:00
parent bdb59aaee0
commit f4921294e6
No known key found for this signature in database
GPG key ID: DF8FEAF54EFAC996
2 changed files with 184 additions and 251 deletions

View file

@ -13,5 +13,5 @@ pub enum Expression<'source> {
Box<Expression<'source>>, Box<Expression<'source>>,
Option<Box<Expression<'source>>>, Option<Box<Expression<'source>>>,
), ),
FunCall(&'source str, Vec<Box<Expression<'source>>>), FunCall(&'source str, Vec<Expression<'source>>),
} }

View file

@ -115,7 +115,7 @@ fn parse_function<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> Expres
// If/loop used instead of while to show that we will always use break to exit the loop // If/loop used instead of while to show that we will always use break to exit the loop
if peek(pos, tokens).text != ")" { if peek(pos, tokens).text != ")" {
loop { loop {
arguments.push(Box::new(parse_expression(pos, tokens))); arguments.push(parse_expression(pos, tokens));
match peek(pos, tokens).text { match peek(pos, tokens).text {
"," => next_expect_string(pos, tokens, ","), "," => next_expect_string(pos, tokens, ","),
@ -211,7 +211,7 @@ mod tests {
use super::*; use super::*;
use crate::compiler::token::CodeLocation; use crate::compiler::token::CodeLocation;
fn new_int(text: &str) -> Token { fn int_tok(text: &str) -> Token {
Token::new( Token::new(
text, text,
TokenType::Integer, TokenType::Integer,
@ -219,7 +219,13 @@ mod tests {
) )
} }
fn new_id(text: &str) -> Token { macro_rules! int_ast {
($x:expr) => {
Box::new(IntLiteral($x))
};
}
fn id_tok(text: &str) -> Token {
Token::new( Token::new(
text, text,
TokenType::Identifier, TokenType::Identifier,
@ -227,7 +233,13 @@ mod tests {
) )
} }
fn new_punc(text: &str) -> Token { macro_rules! id_ast {
($x:expr) => {
Box::new(Identifier($x))
};
}
fn punc_tok(text: &str) -> Token {
Token::new( Token::new(
text, text,
TokenType::Punctuation, TokenType::Punctuation,
@ -235,215 +247,153 @@ mod tests {
) )
} }
macro_rules! bin_ast {
($x:expr, $y:expr, $z:expr) => {
Box::new(BinaryOp($x, $y, $z))
};
}
macro_rules! bool_ast {
($x:expr) => {
Box::new(BoolLiteral($x))
};
}
#[test] #[test]
fn test_binary_op_basic() { fn test_binary_op_basic() {
let result = parse(&vec![new_int("1"), new_id("+"), new_int("23")]); let result = parse(&vec![int_tok("1"), id_tok("+"), int_tok("23")]);
assert_eq!( assert_eq!(result, BinaryOp(int_ast!(1), "+", int_ast!(23)));
result,
BinaryOp(Box::new(IntLiteral(1)), "+", Box::new(IntLiteral(23)))
);
let result = parse(&vec![new_int("4"), new_id("-"), new_int("56")]); let result = parse(&vec![int_tok("4"), id_tok("-"), int_tok("56")]);
assert_eq!( assert_eq!(result, BinaryOp(int_ast!(4), "-", int_ast!(56)));
result,
BinaryOp(Box::new(IntLiteral(4)), "-", Box::new(IntLiteral(56)))
);
let result = parse(&vec![new_int("1"), new_id("*"), new_int("2")]); let result = parse(&vec![int_tok("1"), id_tok("*"), int_tok("2")]);
assert_eq!( assert_eq!(result, BinaryOp(int_ast!(1), "*", int_ast!(2)));
result,
BinaryOp(Box::new(IntLiteral(1)), "*", Box::new(IntLiteral(2)))
);
let result = parse(&vec![new_int("1"), new_id("/"), new_int("2")]); let result = parse(&vec![int_tok("1"), id_tok("/"), int_tok("2")]);
assert_eq!( assert_eq!(result, BinaryOp(int_ast!(1), "/", int_ast!(2)));
result,
BinaryOp(Box::new(IntLiteral(1)), "/", Box::new(IntLiteral(2)))
);
} }
#[test] #[test]
fn test_binary_op_identifier() { fn test_binary_op_identifier() {
let result = parse(&vec![new_id("a"), new_id("+"), new_int("1")]); let result = parse(&vec![id_tok("a"), id_tok("+"), int_tok("1")]);
assert_eq!( assert_eq!(result, BinaryOp(id_ast!("a"), "+", int_ast!(1)));
result,
BinaryOp(Box::new(Identifier("a")), "+", Box::new(IntLiteral(1)))
);
let result = parse(&vec![new_int("1"), new_id("-"), new_id("a")]); let result = parse(&vec![int_tok("1"), id_tok("-"), id_tok("a")]);
assert_eq!( assert_eq!(result, BinaryOp(int_ast!(1), "-", id_ast!("a")));
result,
BinaryOp(Box::new(IntLiteral(1)), "-", Box::new(Identifier("a")))
);
} }
#[test] #[test]
fn test_binary_op_multiple() { fn test_binary_op_multiple() {
let result = parse(&vec![ let result = parse(&vec![
new_int("1"), int_tok("1"),
new_id("+"), id_tok("+"),
new_int("2"), int_tok("2"),
new_id("-"), id_tok("-"),
new_int("3"), int_tok("3"),
]); ]);
assert_eq!( assert_eq!(
result, result,
BinaryOp( BinaryOp(bin_ast!(int_ast!(1), "+", int_ast!(2)), "-", int_ast!(3))
Box::new(BinaryOp(
Box::new(IntLiteral(1)),
"+",
Box::new(IntLiteral(2))
)),
"-",
Box::new(IntLiteral(3))
)
); );
} }
#[test] #[test]
fn test_binary_op_precedence() { fn test_binary_op_precedence() {
let result = parse(&vec![ let result = parse(&vec![
new_int("1"), int_tok("1"),
new_id("+"), id_tok("+"),
new_int("2"), int_tok("2"),
new_id("*"), id_tok("*"),
new_int("3"), int_tok("3"),
]); ]);
assert_eq!( assert_eq!(
result, result,
BinaryOp( BinaryOp(int_ast!(1), "+", bin_ast!(int_ast!(2), "*", int_ast!(3)),)
Box::new(IntLiteral(1)),
"+",
Box::new(BinaryOp(
Box::new(IntLiteral(2)),
"*",
Box::new(IntLiteral(3))
)),
)
); );
let result = parse(&vec![ let result = parse(&vec![
new_int("1"), int_tok("1"),
new_id("-"), id_tok("-"),
new_int("2"), int_tok("2"),
new_id("/"), id_tok("/"),
new_int("3"), int_tok("3"),
]); ]);
assert_eq!( assert_eq!(
result, result,
BinaryOp( BinaryOp(int_ast!(1), "-", bin_ast!(int_ast!(2), "/", int_ast!(3)),)
Box::new(IntLiteral(1)),
"-",
Box::new(BinaryOp(
Box::new(IntLiteral(2)),
"/",
Box::new(IntLiteral(3))
)),
)
); );
} }
#[test] #[test]
fn test_parenthesized() { fn test_parenthesized() {
let result = parse(&vec![ let result = parse(&vec![
new_id("("), id_tok("("),
new_int("1"), int_tok("1"),
new_id("+"), id_tok("+"),
new_int("2"), int_tok("2"),
new_id(")"), id_tok(")"),
new_id("*"), id_tok("*"),
new_int("3"), int_tok("3"),
]); ]);
assert_eq!( assert_eq!(
result, result,
BinaryOp( BinaryOp(bin_ast!(int_ast!(1), "+", int_ast!(2)), "*", int_ast!(3),)
Box::new(BinaryOp(
Box::new(IntLiteral(1)),
"+",
Box::new(IntLiteral(2))
)),
"*",
Box::new(IntLiteral(3)),
)
); );
let result = parse(&vec![ let result = parse(&vec![
new_id("("), id_tok("("),
new_id("("), id_tok("("),
new_int("1"), int_tok("1"),
new_id("-"), id_tok("-"),
new_int("2"), int_tok("2"),
new_id(")"), id_tok(")"),
new_id(")"), id_tok(")"),
new_id("/"), id_tok("/"),
new_int("3"), int_tok("3"),
]); ]);
assert_eq!( assert_eq!(
result, result,
BinaryOp( BinaryOp(bin_ast!(int_ast!(1), "-", int_ast!(2)), "/", int_ast!(3),)
Box::new(BinaryOp(
Box::new(IntLiteral(1)),
"-",
Box::new(IntLiteral(2))
)),
"/",
Box::new(IntLiteral(3)),
)
); );
} }
#[test] #[test]
fn test_if_then() { fn test_if_then() {
let result = parse(&vec![ let result = parse(&vec![
new_id("if"), id_tok("if"),
new_int("1"), int_tok("1"),
new_id("+"), id_tok("+"),
new_int("2"), int_tok("2"),
new_id("then"), id_tok("then"),
new_int("3"), int_tok("3"),
]); ]);
assert_eq!( assert_eq!(
result, result,
Conditional( Conditional(bin_ast!(int_ast!(1), "+", int_ast!(2)), int_ast!(3), None,)
Box::new(BinaryOp(
Box::new(IntLiteral(1)),
"+",
Box::new(IntLiteral(2))
)),
Box::new(IntLiteral(3)),
None,
)
); );
} }
#[test] #[test]
fn test_if_then_else() { fn test_if_then_else() {
let result = parse(&vec![ let result = parse(&vec![
new_id("if"), id_tok("if"),
new_id("a"), id_tok("a"),
new_id("then"), id_tok("then"),
new_id("b"), id_tok("b"),
new_id("+"), id_tok("+"),
new_id("c"), id_tok("c"),
new_id("else"), id_tok("else"),
new_int("1"), int_tok("1"),
new_id("*"), id_tok("*"),
new_int("2"), int_tok("2"),
]); ]);
assert_eq!( assert_eq!(
result, result,
Conditional( Conditional(
Box::new(Identifier("a")), id_ast!("a"),
Box::new(BinaryOp( bin_ast!(id_ast!("b"), "+", id_ast!("c")),
Box::new(Identifier("b")), Some(bin_ast!(int_ast!(1), "*", int_ast!(2)))
"+",
Box::new(Identifier("c")),
)),
Some(Box::new(BinaryOp(
Box::new(IntLiteral(1)),
"*",
Box::new(IntLiteral(2)),
)))
) )
); );
} }
@ -451,25 +401,21 @@ mod tests {
#[test] #[test]
fn test_embedded_if_then_else() { fn test_embedded_if_then_else() {
let result = parse(&vec![ let result = parse(&vec![
new_int("1"), int_tok("1"),
new_id("+"), id_tok("+"),
new_id("if"), id_tok("if"),
new_id("true"), id_tok("true"),
new_id("then"), id_tok("then"),
new_int("2"), int_tok("2"),
new_id("else"), id_tok("else"),
new_int("3"), int_tok("3"),
]); ]);
assert_eq!( assert_eq!(
result, result,
BinaryOp( BinaryOp(
Box::new(IntLiteral(1)), int_ast!(1),
"+", "+",
Box::new(Conditional( Box::new(Conditional(bool_ast!(true), int_ast!(2), Some(int_ast!(3))))
Box::new(BoolLiteral(true)),
Box::new(IntLiteral(2)),
Some(Box::new(IntLiteral(3)))
))
) )
); );
} }
@ -477,28 +423,28 @@ mod tests {
#[test] #[test]
fn test_nested_if_then_else() { fn test_nested_if_then_else() {
let result = parse(&vec![ let result = parse(&vec![
new_id("if"), id_tok("if"),
new_id("true"), id_tok("true"),
new_id("then"), id_tok("then"),
new_id("if"), id_tok("if"),
new_id("false"), id_tok("false"),
new_id("then"), id_tok("then"),
new_int("1"), int_tok("1"),
new_id("else"), id_tok("else"),
new_int("2"), int_tok("2"),
new_id("else"), id_tok("else"),
new_int("3"), int_tok("3"),
]); ]);
assert_eq!( assert_eq!(
result, result,
Conditional( Conditional(
Box::new(BoolLiteral(true)), bool_ast!(true),
Box::new(Conditional( Box::new(Conditional(
Box::new(BoolLiteral(false)), bool_ast!(false),
Box::new(IntLiteral(1)), int_ast!(1),
Some(Box::new(IntLiteral(2))) Some(int_ast!(2))
)), )),
Some(Box::new(IntLiteral(3))) Some(int_ast!(3))
) )
); );
} }
@ -506,71 +452,58 @@ mod tests {
#[test] #[test]
fn test_func_basic() { fn test_func_basic() {
let result = parse(&vec![ let result = parse(&vec![
new_id("f"), id_tok("f"),
new_punc("("), punc_tok("("),
new_id("a"), id_tok("a"),
new_punc(","), punc_tok(","),
new_id("b"), id_tok("b"),
new_punc(")"), punc_tok(")"),
]); ]);
assert_eq!( assert_eq!(
result, result,
FunCall( FunCall("f", vec![Identifier("a"), Identifier("b"),])
"f",
vec![Box::new(Identifier("a")), Box::new(Identifier("b")),]
)
); );
let result = parse(&vec![ let result = parse(&vec![
new_id("f"), id_tok("f"),
new_punc("("), punc_tok("("),
new_id("a"), id_tok("a"),
new_punc(","), punc_tok(","),
new_int("1"), int_tok("1"),
new_id("+"), id_tok("+"),
new_int("2"), int_tok("2"),
new_punc(")"), punc_tok(")"),
]); ]);
assert_eq!( assert_eq!(
result, result,
FunCall( FunCall(
"f", "f",
vec![ vec![Identifier("a"), BinaryOp(int_ast!(1), "+", int_ast!(2),),]
Box::new(Identifier("a")),
Box::new(BinaryOp(
Box::new(IntLiteral(1)),
"+",
Box::new(IntLiteral(2)),
)),
]
) )
); );
let result = parse(&vec![new_id("f"), new_punc("("), new_punc(")")]); let result = parse(&vec![id_tok("f"), punc_tok("("), punc_tok(")")]);
assert_eq!(result, FunCall("f", vec![])); assert_eq!(result, FunCall("f", vec![]));
} }
#[test] #[test]
fn test_func_nested() { fn test_func_nested() {
let result = parse(&vec![ let result = parse(&vec![
new_id("f"), id_tok("f"),
new_punc("("), punc_tok("("),
new_id("a"), id_tok("a"),
new_punc(","), punc_tok(","),
new_id("g"), id_tok("g"),
new_punc("("), punc_tok("("),
new_id("b"), id_tok("b"),
new_punc(")"), punc_tok(")"),
new_punc(")"), punc_tok(")"),
]); ]);
assert_eq!( assert_eq!(
result, result,
FunCall( FunCall(
"f", "f",
vec![ vec![Identifier("a"), FunCall("g", vec![Identifier("b")]),]
Box::new(Identifier("a")),
Box::new(FunCall("g", vec![Box::new(Identifier("b"))])),
]
) )
); );
} }
@ -578,19 +511,19 @@ mod tests {
#[test] #[test]
fn test_func_embedded() { fn test_func_embedded() {
let result = parse(&vec![ let result = parse(&vec![
new_int("1"), int_tok("1"),
new_id("+"), id_tok("+"),
new_id("f"), id_tok("f"),
new_punc("("), punc_tok("("),
new_id("a"), id_tok("a"),
new_punc(")"), punc_tok(")"),
]); ]);
assert_eq!( assert_eq!(
result, result,
BinaryOp( BinaryOp(
Box::new(IntLiteral(1)), int_ast!(1),
"+", "+",
Box::new(FunCall("f", vec![Box::new(Identifier("a"))])) Box::new(FunCall("f", vec![Identifier("a")]))
) )
); );
} }
@ -599,12 +532,12 @@ mod tests {
#[should_panic] #[should_panic]
fn test_parenthesized_mismatched() { fn test_parenthesized_mismatched() {
parse(&vec![ parse(&vec![
new_id("("), id_tok("("),
new_int("1"), int_tok("1"),
new_id("+"), id_tok("+"),
new_int("2"), int_tok("2"),
new_id("*"), id_tok("*"),
new_int("3"), int_tok("3"),
]); ]);
} }
@ -612,24 +545,24 @@ mod tests {
#[should_panic] #[should_panic]
fn test_func_missing_comma() { fn test_func_missing_comma() {
parse(&vec![ parse(&vec![
new_id("f"), id_tok("f"),
new_punc("("), punc_tok("("),
new_id("a"), id_tok("a"),
new_id("b"), id_tok("b"),
new_punc(")"), punc_tok(")"),
]); ]);
} }
#[test] #[test]
#[should_panic] #[should_panic]
fn test_func_missing_close() { fn test_func_missing_close() {
parse(&vec![new_id("f"), new_punc("("), new_id("a")]); parse(&vec![id_tok("f"), punc_tok("("), id_tok("a")]);
} }
#[test] #[test]
#[should_panic] #[should_panic]
fn test_if_no_then() { fn test_if_no_then() {
parse(&vec![new_id("if"), new_id("true")]); parse(&vec![id_tok("if"), id_tok("true")]);
} }
#[test] #[test]
@ -641,19 +574,19 @@ mod tests {
#[test] #[test]
#[should_panic] #[should_panic]
fn test_invalid_start() { fn test_invalid_start() {
parse(&vec![new_int("1"), new_int("2"), new_id("+"), new_int("3")]); parse(&vec![int_tok("1"), int_tok("2"), id_tok("+"), int_tok("3")]);
} }
#[test] #[test]
#[should_panic] #[should_panic]
fn test_invalid_middle() { fn test_invalid_middle() {
parse(&vec![ parse(&vec![
new_int("1"), int_tok("1"),
new_id("+"), id_tok("+"),
new_int("2"), int_tok("2"),
new_int("2"), int_tok("2"),
new_id("+"), id_tok("+"),
new_int("3"), int_tok("3"),
]); ]);
} }
@ -661,12 +594,12 @@ mod tests {
#[should_panic] #[should_panic]
fn test_invalid_end() { fn test_invalid_end() {
parse(&vec![ parse(&vec![
new_int("1"), int_tok("1"),
new_id("+"), id_tok("+"),
new_int("2"), int_tok("2"),
new_int("2"), int_tok("2"),
new_id("+"), id_tok("+"),
new_int("3"), int_tok("3"),
]); ]);
} }
} }