From 66da876e2aa5137d1bfec9e43f0f850eb2cc5dc7 Mon Sep 17 00:00:00 2001 From: ozzy <2+ozzy@noreply.localhost> Date: Fri, 25 Sep 2026 20:29:43 -0500 Subject: [PATCH] feat(parser): add parser added a basic ast parser that is likely riddled with bugs --- src/math/lexer.rs | 4 +- src/math/mod.rs | 8 ++- src/math/parser.rs | 169 +++++++++++++++++++++++++++++++++++++++++++++ src/math/types.rs | 2 +- 4 files changed, 179 insertions(+), 4 deletions(-) create mode 100644 src/math/parser.rs diff --git a/src/math/lexer.rs b/src/math/lexer.rs index 2d0a005..7d02fe2 100644 --- a/src/math/lexer.rs +++ b/src/math/lexer.rs @@ -3,13 +3,14 @@ use std::str::FromStr; use crate::math::types::Operator; use rust_decimal::Decimal; -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum Token { Number(Decimal), Identifier(String), Operator(Operator), OpenParen, CloseParen, + Comma, Eof, } @@ -73,6 +74,7 @@ impl<'a> Lexer<'a> { match self.chars.next() { Some('(') => Token::OpenParen, Some(')') => Token::CloseParen, + Some(',') => Token::Comma, Some('+') => Token::Operator(Operator::Add), Some('-') => Token::Operator(Operator::Subtract), Some('*') => Token::Operator(Operator::Multiply), diff --git a/src/math/mod.rs b/src/math/mod.rs index 0ce4f14..6a5ad7d 100644 --- a/src/math/mod.rs +++ b/src/math/mod.rs @@ -1,8 +1,12 @@ +use crate::math::types::Expression; + mod lexer; +mod parser; pub mod types; -pub fn parse(source: &str) -> Vec { +pub fn parse(source: &str) -> Expression { let lexer = lexer::from(source); - lexer.collect() + let mut parser = parser::from(lexer.collect()); + parser.parse() } diff --git a/src/math/parser.rs b/src/math/parser.rs new file mode 100644 index 0000000..e08948f --- /dev/null +++ b/src/math/parser.rs @@ -0,0 +1,169 @@ +use crate::math::{ + lexer::Token, + types::{Expression, Operator}, +}; + +pub fn from(tokens: Vec) -> Parser { + Parser::new(tokens) +} + +pub struct Parser { + tokens: Vec, + position: usize, +} + +impl Parser { + pub fn new(tokens: Vec) -> Self { + Self { + tokens, + position: 0, + } + } + + pub fn parse(&mut self) -> Expression { + self.parse_additive() + } + + fn parse_additive(&mut self) -> Expression { + let mut left = self.parse_multiplicative(); + + while let Some(token) = self.tokens.get(self.position) { + match token { + Token::Operator(Operator::Add) => { + self.position += 1; + let right = self.parse_multiplicative(); + left = Expression::Operation(Operator::Add, Box::new(left), Box::new(right)); + } + Token::Operator(Operator::Subtract) => { + self.position += 1; + let right = self.parse_multiplicative(); + left = + Expression::Operation(Operator::Subtract, Box::new(left), Box::new(right)); + } + _ => break, + } + } + + left + } + + fn parse_multiplicative(&mut self) -> Expression { + let mut left = self.parse_primary(); + + while let Some(token) = self.tokens.get(self.position) { + match token { + Token::Operator(Operator::Multiply) => { + self.position += 1; + let right = self.parse_exponential(); + left = + Expression::Operation(Operator::Multiply, Box::new(left), Box::new(right)); + } + Token::Operator(Operator::Divide) => { + self.position += 1; + let right = self.parse_exponential(); + left = Expression::Fraction(Box::new(left), Box::new(right)); + } + Token::Operator(Operator::Modulo) => { + self.position += 1; + let right = self.parse_exponential(); + left = Expression::Operation(Operator::Modulo, Box::new(left), Box::new(right)); + } + Token::OpenParen => { + self.position += 1; + let right = self.parse_group(); + left = + Expression::Operation(Operator::Multiply, Box::new(left), Box::new(right)); + self.position += 1; + } + Token::Identifier(_) => { + let right = self.parse_primary(); + left = + Expression::Operation(Operator::Multiply, Box::new(left), Box::new(right)); + } + _ => break, + } + } + + left + } + + fn parse_exponential(&mut self) -> Expression { + let mut left = self.parse_primary(); + + while let Some(token) = self.tokens.get(self.position) { + match token { + Token::Operator(Operator::Power) => { + self.position += 1; + let right = self.parse_group(); + left = + Expression::Operation(Operator::Multiply, Box::new(left), Box::new(right)); + } + _ => break, + } + } + + left + } + + fn parse_group(&mut self) -> Expression { + match self.tokens.get(self.position).expect("expected token!") { + Token::OpenParen => { + self.position += 1; + self.parse_additive() + } + _ => self.parse_primary(), + } + } + + fn parse_primary(&mut self) -> Expression { + let token = self + .tokens + .get(self.position) + .cloned() + .expect("expected token!"); + + match token { + Token::Number(num) => { + self.position += 1; + Expression::Number(num) + } + Token::Identifier(identifier) => { + let is_function = + matches!(self.tokens.get(self.position + 1), Some(Token::OpenParen)); + if is_function { + self.position += 2; + let params = self.parse_function_params(); + Expression::Function(identifier, params) + } else { + self.position += 1; + Expression::Variable(identifier) + } + } + _ => { + panic!("unexpected token! {:?}", token); + } + } + } + + fn parse_function_params(&mut self) -> Vec { + let mut params: Vec = Vec::new(); + + while let Some(token) = self.tokens.get(self.position) { + match token { + Token::Comma => { + self.position += 1; + } + Token::CloseParen => { + self.position += 1; + break; + } + _ => { + let expression = self.parse_additive(); + params.push(expression); + } + } + } + + params + } +} diff --git a/src/math/types.rs b/src/math/types.rs index 885f26f..3be98ed 100644 --- a/src/math/types.rs +++ b/src/math/types.rs @@ -10,7 +10,7 @@ pub enum Expression { Function(String, Vec), } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum Operator { Add, Subtract,