From f4921294e6c25561b2e7c56ab8e84d6645c1e7ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vili=20Sinerv=C3=A4?= Date: Wed, 29 Jan 2025 15:14:27 +0200 Subject: [PATCH] Tweaks and macros to make code more compact --- src/compiler/ast.rs | 2 +- src/compiler/parser.rs | 433 +++++++++++++++++------------------------ 2 files changed, 184 insertions(+), 251 deletions(-) diff --git a/src/compiler/ast.rs b/src/compiler/ast.rs index 13dd9b1..4919a28 100644 --- a/src/compiler/ast.rs +++ b/src/compiler/ast.rs @@ -13,5 +13,5 @@ pub enum Expression<'source> { Box>, Option>>, ), - FunCall(&'source str, Vec>>), + FunCall(&'source str, Vec>), } diff --git a/src/compiler/parser.rs b/src/compiler/parser.rs index 15f2909..895bb61 100644 --- a/src/compiler/parser.rs +++ b/src/compiler/parser.rs @@ -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 peek(pos, tokens).text != ")" { loop { - arguments.push(Box::new(parse_expression(pos, tokens))); + arguments.push(parse_expression(pos, tokens)); match peek(pos, tokens).text { "," => next_expect_string(pos, tokens, ","), @@ -211,7 +211,7 @@ mod tests { use super::*; use crate::compiler::token::CodeLocation; - fn new_int(text: &str) -> Token { + fn int_tok(text: &str) -> Token { Token::new( text, 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( text, 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( text, 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] fn test_binary_op_basic() { - let result = parse(&vec![new_int("1"), new_id("+"), new_int("23")]); - assert_eq!( - result, - BinaryOp(Box::new(IntLiteral(1)), "+", Box::new(IntLiteral(23))) - ); + let result = parse(&vec![int_tok("1"), id_tok("+"), int_tok("23")]); + assert_eq!(result, BinaryOp(int_ast!(1), "+", int_ast!(23))); - let result = parse(&vec![new_int("4"), new_id("-"), new_int("56")]); - assert_eq!( - result, - BinaryOp(Box::new(IntLiteral(4)), "-", Box::new(IntLiteral(56))) - ); + let result = parse(&vec![int_tok("4"), id_tok("-"), int_tok("56")]); + assert_eq!(result, BinaryOp(int_ast!(4), "-", int_ast!(56))); - let result = parse(&vec![new_int("1"), new_id("*"), new_int("2")]); - assert_eq!( - result, - BinaryOp(Box::new(IntLiteral(1)), "*", Box::new(IntLiteral(2))) - ); + let result = parse(&vec![int_tok("1"), id_tok("*"), int_tok("2")]); + assert_eq!(result, BinaryOp(int_ast!(1), "*", int_ast!(2))); - let result = parse(&vec![new_int("1"), new_id("/"), new_int("2")]); - assert_eq!( - result, - BinaryOp(Box::new(IntLiteral(1)), "/", Box::new(IntLiteral(2))) - ); + let result = parse(&vec![int_tok("1"), id_tok("/"), int_tok("2")]); + assert_eq!(result, BinaryOp(int_ast!(1), "/", int_ast!(2))); } #[test] fn test_binary_op_identifier() { - let result = parse(&vec![new_id("a"), new_id("+"), new_int("1")]); - assert_eq!( - result, - BinaryOp(Box::new(Identifier("a")), "+", Box::new(IntLiteral(1))) - ); + let result = parse(&vec![id_tok("a"), id_tok("+"), int_tok("1")]); + assert_eq!(result, BinaryOp(id_ast!("a"), "+", int_ast!(1))); - let result = parse(&vec![new_int("1"), new_id("-"), new_id("a")]); - assert_eq!( - result, - BinaryOp(Box::new(IntLiteral(1)), "-", Box::new(Identifier("a"))) - ); + let result = parse(&vec![int_tok("1"), id_tok("-"), id_tok("a")]); + assert_eq!(result, BinaryOp(int_ast!(1), "-", id_ast!("a"))); } #[test] fn test_binary_op_multiple() { let result = parse(&vec![ - new_int("1"), - new_id("+"), - new_int("2"), - new_id("-"), - new_int("3"), + int_tok("1"), + id_tok("+"), + int_tok("2"), + id_tok("-"), + int_tok("3"), ]); assert_eq!( result, - BinaryOp( - Box::new(BinaryOp( - Box::new(IntLiteral(1)), - "+", - Box::new(IntLiteral(2)) - )), - "-", - Box::new(IntLiteral(3)) - ) + BinaryOp(bin_ast!(int_ast!(1), "+", int_ast!(2)), "-", int_ast!(3)) ); } #[test] fn test_binary_op_precedence() { let result = parse(&vec![ - new_int("1"), - new_id("+"), - new_int("2"), - new_id("*"), - new_int("3"), + int_tok("1"), + id_tok("+"), + int_tok("2"), + id_tok("*"), + int_tok("3"), ]); assert_eq!( result, - BinaryOp( - Box::new(IntLiteral(1)), - "+", - Box::new(BinaryOp( - Box::new(IntLiteral(2)), - "*", - Box::new(IntLiteral(3)) - )), - ) + BinaryOp(int_ast!(1), "+", bin_ast!(int_ast!(2), "*", int_ast!(3)),) ); let result = parse(&vec![ - new_int("1"), - new_id("-"), - new_int("2"), - new_id("/"), - new_int("3"), + int_tok("1"), + id_tok("-"), + int_tok("2"), + id_tok("/"), + int_tok("3"), ]); assert_eq!( result, - BinaryOp( - Box::new(IntLiteral(1)), - "-", - Box::new(BinaryOp( - Box::new(IntLiteral(2)), - "/", - Box::new(IntLiteral(3)) - )), - ) + BinaryOp(int_ast!(1), "-", bin_ast!(int_ast!(2), "/", int_ast!(3)),) ); } #[test] fn test_parenthesized() { let result = parse(&vec![ - new_id("("), - new_int("1"), - new_id("+"), - new_int("2"), - new_id(")"), - new_id("*"), - new_int("3"), + id_tok("("), + int_tok("1"), + id_tok("+"), + int_tok("2"), + id_tok(")"), + id_tok("*"), + int_tok("3"), ]); assert_eq!( result, - BinaryOp( - Box::new(BinaryOp( - Box::new(IntLiteral(1)), - "+", - Box::new(IntLiteral(2)) - )), - "*", - Box::new(IntLiteral(3)), - ) + BinaryOp(bin_ast!(int_ast!(1), "+", int_ast!(2)), "*", int_ast!(3),) ); let result = parse(&vec![ - new_id("("), - new_id("("), - new_int("1"), - new_id("-"), - new_int("2"), - new_id(")"), - new_id(")"), - new_id("/"), - new_int("3"), + id_tok("("), + id_tok("("), + int_tok("1"), + id_tok("-"), + int_tok("2"), + id_tok(")"), + id_tok(")"), + id_tok("/"), + int_tok("3"), ]); assert_eq!( result, - BinaryOp( - Box::new(BinaryOp( - Box::new(IntLiteral(1)), - "-", - Box::new(IntLiteral(2)) - )), - "/", - Box::new(IntLiteral(3)), - ) + BinaryOp(bin_ast!(int_ast!(1), "-", int_ast!(2)), "/", int_ast!(3),) ); } #[test] fn test_if_then() { let result = parse(&vec![ - new_id("if"), - new_int("1"), - new_id("+"), - new_int("2"), - new_id("then"), - new_int("3"), + id_tok("if"), + int_tok("1"), + id_tok("+"), + int_tok("2"), + id_tok("then"), + int_tok("3"), ]); assert_eq!( result, - Conditional( - Box::new(BinaryOp( - Box::new(IntLiteral(1)), - "+", - Box::new(IntLiteral(2)) - )), - Box::new(IntLiteral(3)), - None, - ) + Conditional(bin_ast!(int_ast!(1), "+", int_ast!(2)), int_ast!(3), None,) ); } #[test] fn test_if_then_else() { let result = parse(&vec![ - new_id("if"), - new_id("a"), - new_id("then"), - new_id("b"), - new_id("+"), - new_id("c"), - new_id("else"), - new_int("1"), - new_id("*"), - new_int("2"), + id_tok("if"), + id_tok("a"), + id_tok("then"), + id_tok("b"), + id_tok("+"), + id_tok("c"), + id_tok("else"), + int_tok("1"), + id_tok("*"), + int_tok("2"), ]); assert_eq!( result, Conditional( - Box::new(Identifier("a")), - Box::new(BinaryOp( - Box::new(Identifier("b")), - "+", - Box::new(Identifier("c")), - )), - Some(Box::new(BinaryOp( - Box::new(IntLiteral(1)), - "*", - Box::new(IntLiteral(2)), - ))) + id_ast!("a"), + bin_ast!(id_ast!("b"), "+", id_ast!("c")), + Some(bin_ast!(int_ast!(1), "*", int_ast!(2))) ) ); } @@ -451,25 +401,21 @@ mod tests { #[test] fn test_embedded_if_then_else() { let result = parse(&vec![ - new_int("1"), - new_id("+"), - new_id("if"), - new_id("true"), - new_id("then"), - new_int("2"), - new_id("else"), - new_int("3"), + int_tok("1"), + id_tok("+"), + id_tok("if"), + id_tok("true"), + id_tok("then"), + int_tok("2"), + id_tok("else"), + int_tok("3"), ]); assert_eq!( result, BinaryOp( - Box::new(IntLiteral(1)), + int_ast!(1), "+", - Box::new(Conditional( - Box::new(BoolLiteral(true)), - Box::new(IntLiteral(2)), - Some(Box::new(IntLiteral(3))) - )) + Box::new(Conditional(bool_ast!(true), int_ast!(2), Some(int_ast!(3)))) ) ); } @@ -477,28 +423,28 @@ mod tests { #[test] fn test_nested_if_then_else() { let result = parse(&vec![ - new_id("if"), - new_id("true"), - new_id("then"), - new_id("if"), - new_id("false"), - new_id("then"), - new_int("1"), - new_id("else"), - new_int("2"), - new_id("else"), - new_int("3"), + id_tok("if"), + id_tok("true"), + id_tok("then"), + id_tok("if"), + id_tok("false"), + id_tok("then"), + int_tok("1"), + id_tok("else"), + int_tok("2"), + id_tok("else"), + int_tok("3"), ]); assert_eq!( result, Conditional( - Box::new(BoolLiteral(true)), + bool_ast!(true), Box::new(Conditional( - Box::new(BoolLiteral(false)), - Box::new(IntLiteral(1)), - Some(Box::new(IntLiteral(2))) + bool_ast!(false), + int_ast!(1), + Some(int_ast!(2)) )), - Some(Box::new(IntLiteral(3))) + Some(int_ast!(3)) ) ); } @@ -506,71 +452,58 @@ mod tests { #[test] fn test_func_basic() { let result = parse(&vec![ - new_id("f"), - new_punc("("), - new_id("a"), - new_punc(","), - new_id("b"), - new_punc(")"), + id_tok("f"), + punc_tok("("), + id_tok("a"), + punc_tok(","), + id_tok("b"), + punc_tok(")"), ]); assert_eq!( result, - FunCall( - "f", - vec![Box::new(Identifier("a")), Box::new(Identifier("b")),] - ) + FunCall("f", vec![Identifier("a"), Identifier("b"),]) ); let result = parse(&vec![ - new_id("f"), - new_punc("("), - new_id("a"), - new_punc(","), - new_int("1"), - new_id("+"), - new_int("2"), - new_punc(")"), + id_tok("f"), + punc_tok("("), + id_tok("a"), + punc_tok(","), + int_tok("1"), + id_tok("+"), + int_tok("2"), + punc_tok(")"), ]); assert_eq!( result, FunCall( "f", - vec![ - Box::new(Identifier("a")), - Box::new(BinaryOp( - Box::new(IntLiteral(1)), - "+", - Box::new(IntLiteral(2)), - )), - ] + vec![Identifier("a"), BinaryOp(int_ast!(1), "+", int_ast!(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![])); } #[test] fn test_func_nested() { let result = parse(&vec![ - new_id("f"), - new_punc("("), - new_id("a"), - new_punc(","), - new_id("g"), - new_punc("("), - new_id("b"), - new_punc(")"), - new_punc(")"), + id_tok("f"), + punc_tok("("), + id_tok("a"), + punc_tok(","), + id_tok("g"), + punc_tok("("), + id_tok("b"), + punc_tok(")"), + punc_tok(")"), ]); assert_eq!( result, FunCall( "f", - vec![ - Box::new(Identifier("a")), - Box::new(FunCall("g", vec![Box::new(Identifier("b"))])), - ] + vec![Identifier("a"), FunCall("g", vec![Identifier("b")]),] ) ); } @@ -578,19 +511,19 @@ mod tests { #[test] fn test_func_embedded() { let result = parse(&vec![ - new_int("1"), - new_id("+"), - new_id("f"), - new_punc("("), - new_id("a"), - new_punc(")"), + int_tok("1"), + id_tok("+"), + id_tok("f"), + punc_tok("("), + id_tok("a"), + punc_tok(")"), ]); assert_eq!( result, 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] fn test_parenthesized_mismatched() { parse(&vec![ - new_id("("), - new_int("1"), - new_id("+"), - new_int("2"), - new_id("*"), - new_int("3"), + id_tok("("), + int_tok("1"), + id_tok("+"), + int_tok("2"), + id_tok("*"), + int_tok("3"), ]); } @@ -612,24 +545,24 @@ mod tests { #[should_panic] fn test_func_missing_comma() { parse(&vec![ - new_id("f"), - new_punc("("), - new_id("a"), - new_id("b"), - new_punc(")"), + id_tok("f"), + punc_tok("("), + id_tok("a"), + id_tok("b"), + punc_tok(")"), ]); } #[test] #[should_panic] 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] #[should_panic] fn test_if_no_then() { - parse(&vec![new_id("if"), new_id("true")]); + parse(&vec![id_tok("if"), id_tok("true")]); } #[test] @@ -641,19 +574,19 @@ mod tests { #[test] #[should_panic] 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] #[should_panic] fn test_invalid_middle() { parse(&vec![ - new_int("1"), - new_id("+"), - new_int("2"), - new_int("2"), - new_id("+"), - new_int("3"), + int_tok("1"), + id_tok("+"), + int_tok("2"), + int_tok("2"), + id_tok("+"), + int_tok("3"), ]); } @@ -661,12 +594,12 @@ mod tests { #[should_panic] fn test_invalid_end() { parse(&vec![ - new_int("1"), - new_id("+"), - new_int("2"), - new_int("2"), - new_id("+"), - new_int("3"), + int_tok("1"), + id_tok("+"), + int_tok("2"), + int_tok("2"), + id_tok("+"), + int_tok("3"), ]); } }