This commit is contained in:
Snoweuph 2025-02-14 19:07:32 +01:00
parent 9aa09537a9
commit 29b4f225b2
Signed by: snoweuph
GPG key ID: BEFC41DA223CEC55
6 changed files with 155 additions and 1 deletions

10
src/ast.rs Normal file
View 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
View 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(),
}
}
}

View file

@ -1,3 +1,18 @@
mod ast;
mod executor;
mod parser;
mod tokens;
use std::{env, fs};
fn main() { 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
View 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
View 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
View file

@ -0,0 +1,2 @@
-128 + 5 * ( 37 + 8 - 19) * 39 / 27 * (-17) + 55 % 45 + -59