From df48d271e26a06d76c2ac881e90157d85fb7431f Mon Sep 17 00:00:00 2001 From: Iwan Snel Date: Mon, 20 Oct 2025 20:22:01 +0200 Subject: [PATCH] added grammar files --- src/ast/comparison.rs | 1 + src/ast/evaluable.rs | 4 +++ src/ast/expression.rs | 23 ++++++++++++++++ src/ast/literal.rs | 5 ++++ src/ast/mod.rs | 6 ++++ src/ast/operators.rs | 30 ++++++++++++++++++++ src/expressions.lalrpop | 9 ++++++ src/grammar.ebnf | 10 +++++++ src/literals.lalrpop | 11 ++++---- src/main.rs | 6 ++++ src/optimising/mod.rs | 1 + src/tests/expressions.rs | 16 +++++++++++ src/tests/literals.rs | 49 +++++++++++++++++++++++++++++++++ src/tests/mod.rs | 59 ++-------------------------------------- 14 files changed, 168 insertions(+), 62 deletions(-) diff --git a/src/ast/comparison.rs b/src/ast/comparison.rs index e69de29..ba176f3 100644 --- a/src/ast/comparison.rs +++ b/src/ast/comparison.rs @@ -0,0 +1 @@ +use crate::ast::expression::Expression; diff --git a/src/ast/evaluable.rs b/src/ast/evaluable.rs index e69de29..31eb3e3 100644 --- a/src/ast/evaluable.rs +++ b/src/ast/evaluable.rs @@ -0,0 +1,4 @@ +/// A node that is evaluable to type `T` +pub trait Evaluable { + fn evaluate(&self) -> T; +} \ No newline at end of file diff --git a/src/ast/expression.rs b/src/ast/expression.rs index e69de29..87cf609 100644 --- a/src/ast/expression.rs +++ b/src/ast/expression.rs @@ -0,0 +1,23 @@ +use crate::ast::literal::Literal; + +pub enum Expression { + Identifier(String), + Literal(Literal), + + Addition(Box, Box), + Subtraction(Box, Box), + Multiplication(Box, Box), + Division(Box, Box), + Remainder(Box, Box), + Negation(Box), + + And(Box, Box), + Or(Box, Box), + + Equal(Box, Box), + NotEqual(Box, Box), + Less(Box, Box), + LessEqual(Box, Box), + Greater(Box, Box), + GreaterEqual(Box, Box), +} diff --git a/src/ast/literal.rs b/src/ast/literal.rs index e69de29..1c40790 100644 --- a/src/ast/literal.rs +++ b/src/ast/literal.rs @@ -0,0 +1,5 @@ +pub enum Literal { + Int(i64), + Float(f64), + Bool(bool), +} diff --git a/src/ast/mod.rs b/src/ast/mod.rs index e69de29..088b33b 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -0,0 +1,6 @@ +mod evaluable; +pub mod literal; +pub mod expression; +pub mod logical; +mod comparison; +mod operators; \ No newline at end of file diff --git a/src/ast/operators.rs b/src/ast/operators.rs index e69de29..65e9a5c 100644 --- a/src/ast/operators.rs +++ b/src/ast/operators.rs @@ -0,0 +1,30 @@ +use crate::ast::expression::Expression; + +pub enum Operator { + Unary(UnaryOperator), + Binary(BinaryOperator), +} + +pub enum UnaryOperator { + Minus, + Not, + Reference, + Dereference, +} + +pub enum BinaryOperator { + Plus, + Minus, + Multiply, + Divide, + Modulo, + And, + Or, + Xor, + Equal, + NotEqual, + Greater, + GreaterEqual, + Less, + LessEqual, +} diff --git a/src/expressions.lalrpop b/src/expressions.lalrpop index e69de29..5129355 100644 --- a/src/expressions.lalrpop +++ b/src/expressions.lalrpop @@ -0,0 +1,9 @@ +use crate::ast::expression::Expression; + +grammar; + +pub ASTExpression: Expression = { + => Expression::Identifier(String::from(s)), +}; + +pub Identifier: &'input str = => s; \ No newline at end of file diff --git a/src/grammar.ebnf b/src/grammar.ebnf index e69de29..a1113c7 100644 --- a/src/grammar.ebnf +++ b/src/grammar.ebnf @@ -0,0 +1,10 @@ +Expr := Identifier +| Expr Expr +| "&" Identifier "." Expr +| "(" Expr ")" + +Declaration := Identifier ":=" Expr ";" + +Abstraction := "&" Identifier "." Expr ";" + +Application := Identifier "<|" Expr \ No newline at end of file diff --git a/src/literals.lalrpop b/src/literals.lalrpop index 0c256c9..7254c1e 100644 --- a/src/literals.lalrpop +++ b/src/literals.lalrpop @@ -1,13 +1,14 @@ use std::str::FromStr; +use crate::ast::literal::Literal; grammar; -pub Atom: f64 = { - => n as f64, - Float, - "(" ")", +pub Atom: Literal = { + => Literal::Int(n), + => Literal::Float(f), + "(" ")" => f, }; pub Int: i64 = => i64::from_str(s).unwrap(); pub Float: f64 = => f64::from_str(s).unwrap(); -pub StringLiteral: &'input str = => s; \ No newline at end of file +//pub StringLiteral: &'input str = => s; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index cdcec57..65d0080 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,11 @@ +use lalrpop_util::lalrpop_mod; + mod ast; mod optimising; +mod tests; + +lalrpop_mod!(pub literals); +lalrpop_mod!(pub expressions); fn main() { println!("Hello, world!"); diff --git a/src/optimising/mod.rs b/src/optimising/mod.rs index e69de29..edcaf04 100644 --- a/src/optimising/mod.rs +++ b/src/optimising/mod.rs @@ -0,0 +1 @@ +mod constfolding; \ No newline at end of file diff --git a/src/tests/expressions.rs b/src/tests/expressions.rs index e69de29..d319aa2 100644 --- a/src/tests/expressions.rs +++ b/src/tests/expressions.rs @@ -0,0 +1,16 @@ + + +#[test] +fn identifiers() { + use crate::expressions::IdentifierParser as IdentParser; + assert!(IdentParser::new().parse("a").is_ok()); + assert!(IdentParser::new().parse("_").is_ok()); + assert!(IdentParser::new().parse("a_a_a_").is_ok()); + assert!(IdentParser::new().parse("_0").is_ok()); + assert!(IdentParser::new().parse("_a").is_ok()); + assert!(IdentParser::new().parse("__").is_ok()); + + assert!(IdentParser::new().parse("0").is_err()); + assert!(IdentParser::new().parse("0123456").is_err()); + assert!(IdentParser::new().parse("0aaaa").is_err()); +} \ No newline at end of file diff --git a/src/tests/literals.rs b/src/tests/literals.rs index e69de29..a076262 100644 --- a/src/tests/literals.rs +++ b/src/tests/literals.rs @@ -0,0 +1,49 @@ +use crate::literals::AtomParser as Parser; +use std::any::type_name_of_val; +use std::convert::identity; + +#[test] +fn int_literals() { + let parser = Parser::new(); + let valid_ints = vec!["1234567890", "(1234567890)", "((((1))))"]; + let invalid_ints = vec!["01", "(1", "6543)", "((987652345)"]; + + assert!(valid_ints.into_iter().all(|s| parser.parse(s).is_ok())); + assert!(invalid_ints.into_iter().all(|s| parser.parse(s).is_err())); +} + +#[test] +fn test_float_dots() { + let valid_floats = vec![ + "0.0", + "-0.0", + "3.141592653589793", + "-1.123456765432123456789", + ]; + assert!(Parser::new().parse("1.1").is_ok()); + assert!(Parser::new().parse("-1.1").is_ok()); + assert!(Parser::new().parse(".1").is_ok()); + assert!(Parser::new().parse("-.1").is_ok()); +} + +#[test] +fn test_float_exps() { + let parser = crate::literals::FloatParser::new(); + + let valid_float_exps: Vec<&str> = vec![ + "1e1", "-1e1", "1e-1", "-1e-1", "1.1e1", "1.1e-1", "-1.1e1", "-1.1e-1", ".1e1", "-.1e1", + "-.1e-1", "1E1", "-1E1", "1E-1", "-1E-1", "1.1E1", "1.1E-1", "-1.1E1", "-1.1E-1", ".1E1", + "-.1E1", "-.1E-1", + ]; + + let invalid_float_exps: Vec<&str> = vec!["AAAAAAAAAAAAAAA", "1.e1", "1e1.1", "1.1e1.1", "-1e1.1", "1e-1.1"]; + + assert!( + valid_float_exps + .into_iter() + .all(|s| parser.parse(s).is_ok()) + ); + assert!(invalid_float_exps + .into_iter() + .all(|s| parser.parse(s).is_err())); +} diff --git a/src/tests/mod.rs b/src/tests/mod.rs index be8226d..d2fa69d 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,57 +1,2 @@ -#[cfg(test)] -mod test { - use crate::grammar; - use grammar::AtomParser as Parser; - #[test] - fn int_literals() { - assert!(Parser::new().parse("22").is_ok()); - assert!(Parser::new().parse("(22)").is_ok()); - assert!(Parser::new().parse("((22))").is_ok()); - } - - #[test] - fn test_float_dots() { - assert!(Parser::new().parse("1.1").is_ok()); - assert!(Parser::new().parse("-1.1").is_ok()); - assert!(Parser::new().parse(".1").is_ok()); - assert!(Parser::new().parse("-.1").is_ok()); - } - - #[test] - fn test_float_exps() { - assert!(Parser::new().parse("(1e1)").is_ok()); - assert!(Parser::new().parse("(-1e1)").is_ok()); - assert!(Parser::new().parse("(1e-1)").is_ok()); - assert!(Parser::new().parse("(-1e-1)").is_ok()); - assert!(Parser::new().parse("(1E1)").is_ok()); - assert!(Parser::new().parse("(-1E1)").is_ok()); - assert!(Parser::new().parse("(1E-1)").is_ok()); - assert!(Parser::new().parse("(-1E-1)").is_ok()); - assert!(Parser::new().parse("(1.1e1)").is_ok()); - assert!(Parser::new().parse("(-1.1e1)").is_ok()); - assert!(Parser::new().parse("(1.1e-1)").is_ok()); - assert!(Parser::new().parse("(-1.1e-1)").is_ok()); - assert!(Parser::new().parse("(1.1E1)").is_ok()); - assert!(Parser::new().parse("(-1.1E1)").is_ok()); - assert!(Parser::new().parse("(1.1E-1)").is_ok()); - assert!(Parser::new().parse("(-1.1E-1)").is_ok()); - - assert!(Parser::new().parse("(1.0e1)").is_ok()); - assert!(Parser::new().parse("(-0.1e1)").is_ok()); - assert!(Parser::new().parse("(1.0e-1)").is_ok()); - assert!(Parser::new().parse("(-1.0e-1)").is_ok()); - assert!(Parser::new().parse("(1.E1)").is_err()); - assert!(Parser::new().parse("(-1E1)").is_ok()); - assert!(Parser::new().parse("(1E-10)").is_ok()); - assert!(Parser::new().parse("(-1E-1)").is_ok()); - assert!(Parser::new().parse("(1.1e1)").is_ok()); - assert!(Parser::new().parse("(-1.1e1)").is_ok()); - assert!(Parser::new().parse("(1.1e-1)").is_ok()); - assert!(Parser::new().parse("(-1.1e-1)").is_ok()); - assert!(Parser::new().parse("(1.1E1)").is_ok()); - assert!(Parser::new().parse("(-1.1E1)").is_ok()); - assert!(Parser::new().parse("(1.1E-1)").is_ok()); - assert!(Parser::new().parse("(-1.1E-1)").is_ok()); - assert!(Parser::new().parse("FOOBAR").is_err()); - } -} +mod literals; +mod expressions;