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
+3
-1
@@ -3,13 +3,14 @@ use std::str::FromStr;
|
|||||||
use crate::math::types::Operator;
|
use crate::math::types::Operator;
|
||||||
use rust_decimal::Decimal;
|
use rust_decimal::Decimal;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
Number(Decimal),
|
Number(Decimal),
|
||||||
Identifier(String),
|
Identifier(String),
|
||||||
Operator(Operator),
|
Operator(Operator),
|
||||||
OpenParen,
|
OpenParen,
|
||||||
CloseParen,
|
CloseParen,
|
||||||
|
Comma,
|
||||||
Eof,
|
Eof,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,6 +74,7 @@ impl<'a> Lexer<'a> {
|
|||||||
match self.chars.next() {
|
match self.chars.next() {
|
||||||
Some('(') => Token::OpenParen,
|
Some('(') => Token::OpenParen,
|
||||||
Some(')') => Token::CloseParen,
|
Some(')') => Token::CloseParen,
|
||||||
|
Some(',') => Token::Comma,
|
||||||
Some('+') => Token::Operator(Operator::Add),
|
Some('+') => Token::Operator(Operator::Add),
|
||||||
Some('-') => Token::Operator(Operator::Subtract),
|
Some('-') => Token::Operator(Operator::Subtract),
|
||||||
Some('*') => Token::Operator(Operator::Multiply),
|
Some('*') => Token::Operator(Operator::Multiply),
|
||||||
|
|||||||
+6
-2
@@ -1,8 +1,12 @@
|
|||||||
|
use crate::math::types::Expression;
|
||||||
|
|
||||||
mod lexer;
|
mod lexer;
|
||||||
|
mod parser;
|
||||||
|
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
pub fn parse(source: &str) -> Vec<lexer::Token> {
|
pub fn parse(source: &str) -> Expression {
|
||||||
let lexer = lexer::from(source);
|
let lexer = lexer::from(source);
|
||||||
lexer.collect()
|
let mut parser = parser::from(lexer.collect());
|
||||||
|
parser.parse()
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -10,7 +10,7 @@ pub enum Expression {
|
|||||||
Function(String, Vec<Expression>),
|
Function(String, Vec<Expression>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Operator {
|
pub enum Operator {
|
||||||
Add,
|
Add,
|
||||||
Subtract,
|
Subtract,
|
||||||
|
|||||||
Reference in new issue
Block a user