feat(parser): add parser
added a basic ast parser that is likely riddled with bugs
This commit is contained in:
4 files changed
+179
-4
No files matched your search
@@ -0,0 +1,169 @@
|
||||
use crate::math::{
|
||||
lexer::Token,
|
||||
types::{Expression, Operator},
|
||||
};
|
||||
|
||||
pub fn from(tokens: Vec<Token>) -> Parser {
|
||||
Parser::new(tokens)
|
||||
}
|
||||
|
||||
pub struct Parser {
|
||||
tokens: Vec<Token>,
|
||||
position: usize,
|
||||
}
|
||||
|
||||
impl Parser {
|
||||
pub fn new(tokens: Vec<Token>) -> 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<Expression> {
|
||||
let mut params: Vec<Expression> = 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
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user