Math :D
This commit is contained in:
parent
9aa09537a9
commit
29b4f225b2
6 changed files with 155 additions and 1 deletions
10
src/ast.rs
Normal file
10
src/ast.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
#[derive(Debug)]
|
||||
pub enum Expresion {
|
||||
Integer(isize),
|
||||
Negate(Box<Expresion>),
|
||||
Add(Box<Expresion>, Box<Expresion>),
|
||||
Subtract(Box<Expresion>, Box<Expresion>),
|
||||
Multiply(Box<Expresion>, Box<Expresion>),
|
||||
Divide(Box<Expresion>, Box<Expresion>),
|
||||
Modulo(Box<Expresion>, Box<Expresion>),
|
||||
}
|
42
src/executor.rs
Normal file
42
src/executor.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
use chumsky::{error::Simple, Parser};
|
||||
use core::ops::Range;
|
||||
use logos::Logos;
|
||||
|
||||
use crate::{ast::Expresion, parser::parser, tokens::Token};
|
||||
|
||||
pub enum Error {
|
||||
Lexing(Range<usize>, String),
|
||||
Ast(Vec<Simple<Token>>),
|
||||
}
|
||||
|
||||
pub fn execute(code: &str) -> Result<isize, Error> {
|
||||
let lexer = Token::lexer(code);
|
||||
let mut tokens = vec![];
|
||||
for (token, span) in lexer.spanned() {
|
||||
match token {
|
||||
Ok(token) => tokens.push(token),
|
||||
Err(error) => return Err(Error::Lexing(span, error)),
|
||||
}
|
||||
}
|
||||
|
||||
let ast_result = parser().parse(tokens);
|
||||
let Ok(ast) = ast_result else {
|
||||
return Err(Error::Ast(ast_result.unwrap_err()));
|
||||
};
|
||||
|
||||
Ok(ast.evaluate())
|
||||
}
|
||||
|
||||
impl Expresion {
|
||||
fn evaluate(&self) -> isize {
|
||||
match self {
|
||||
Expresion::Integer(value) => *value,
|
||||
Expresion::Negate(value) => -value.evaluate(),
|
||||
Expresion::Add(left, right) => left.evaluate() + right.evaluate(),
|
||||
Expresion::Subtract(left, right) => left.evaluate() - right.evaluate(),
|
||||
Expresion::Multiply(left, right) => left.evaluate() * right.evaluate(),
|
||||
Expresion::Divide(left, right) => left.evaluate() / right.evaluate(),
|
||||
Expresion::Modulo(left, right) => left.evaluate() % right.evaluate(),
|
||||
}
|
||||
}
|
||||
}
|
17
src/main.rs
17
src/main.rs
|
@ -1,3 +1,18 @@
|
|||
mod ast;
|
||||
mod executor;
|
||||
mod parser;
|
||||
mod tokens;
|
||||
use std::{env, fs};
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
let src = fs::read_to_string(env::args().nth(1).expect("Expected a file"))
|
||||
.expect("Failed to read file");
|
||||
match executor::execute(&src) {
|
||||
Ok(result) => println!("{}", result),
|
||||
Err(err) => match err {
|
||||
executor::Error::Lexing(range, msg) => {
|
||||
println!("Invalid Syntax at: {:?} | {}", range, msg)
|
||||
}
|
||||
executor::Error::Ast(ast) => println!("AST Error: {:?}", ast),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
55
src/parser.rs
Normal file
55
src/parser.rs
Normal file
|
@ -0,0 +1,55 @@
|
|||
use crate::ast::Expresion;
|
||||
use crate::tokens::Token;
|
||||
use chumsky::prelude::*;
|
||||
|
||||
pub fn parser() -> impl Parser<Token, Expresion, Error = Simple<Token>> {
|
||||
recursive(|parser| {
|
||||
let atom = {
|
||||
let parenthesized = parser
|
||||
.clone()
|
||||
.delimited_by(just(Token::ParanthesisOpen), just(Token::ParenthesisClose));
|
||||
|
||||
let integer = select! {
|
||||
Token::Integer(n) => Expresion::Integer(n),
|
||||
};
|
||||
|
||||
parenthesized.or(integer)
|
||||
};
|
||||
|
||||
let unary = just(Token::Minus)
|
||||
.repeated()
|
||||
.then(atom)
|
||||
.foldr(|_operator, value| Expresion::Negate(Box::new(value)));
|
||||
|
||||
let multiply_and_divide_and_modulo = unary
|
||||
.clone()
|
||||
.then(
|
||||
just(Token::Multiply)
|
||||
.or(just(Token::Divide))
|
||||
.or(just(Token::Modulo))
|
||||
.then(unary)
|
||||
.repeated(),
|
||||
)
|
||||
.foldl(|left, (operator, right)| match operator {
|
||||
Token::Multiply => Expresion::Multiply(Box::new(left), Box::new(right)),
|
||||
Token::Divide => Expresion::Divide(Box::new(left), Box::new(right)),
|
||||
Token::Modulo => Expresion::Modulo(Box::new(left), Box::new(right)),
|
||||
_ => unreachable!(),
|
||||
});
|
||||
|
||||
multiply_and_divide_and_modulo
|
||||
.clone()
|
||||
.then(
|
||||
just(Token::Plus)
|
||||
.or(just(Token::Minus))
|
||||
.then(multiply_and_divide_and_modulo)
|
||||
.repeated(),
|
||||
)
|
||||
.foldl(|left, (operator, right)| match operator {
|
||||
Token::Plus => Expresion::Add(Box::new(left), Box::new(right)),
|
||||
Token::Minus => Expresion::Subtract(Box::new(left), Box::new(right)),
|
||||
_ => unreachable!(),
|
||||
})
|
||||
})
|
||||
.then_ignore(end())
|
||||
}
|
30
src/tokens.rs
Normal file
30
src/tokens.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
use logos::Logos;
|
||||
|
||||
#[derive(Logos, Debug, PartialEq, Eq, Hash, Clone)]
|
||||
#[logos(skip r"[ \t\n]+")]
|
||||
#[logos(error = String)]
|
||||
pub enum Token {
|
||||
#[token("+")]
|
||||
Plus,
|
||||
|
||||
#[token("-")]
|
||||
Minus,
|
||||
|
||||
#[token("*")]
|
||||
Multiply,
|
||||
|
||||
#[token("/")]
|
||||
Divide,
|
||||
|
||||
#[token("%")]
|
||||
Modulo,
|
||||
|
||||
#[token("(")]
|
||||
ParanthesisOpen,
|
||||
|
||||
#[token(")")]
|
||||
ParenthesisClose,
|
||||
|
||||
#[regex("[0-9]+", |lex| lex.slice().parse::<isize>().unwrap())]
|
||||
Integer(isize),
|
||||
}
|
2
test.math
Normal file
2
test.math
Normal file
|
@ -0,0 +1,2 @@
|
|||
-128 + 5 * ( 37 + 8 - 19) * 39 / 27 * (-17) + 55 % 45 + -59
|
||||
|
Loading…
Add table
Reference in a new issue