hey it can calculate 4 again xP

This commit is contained in:
LunarAkai 2025-08-07 01:37:01 +02:00
commit 8a44d045ae
7 changed files with 50 additions and 36 deletions

View file

@ -2,19 +2,23 @@
#[derive(Debug)]
pub enum Expression<'src> {
// Identifier
Ident(&'src str),
// Types
Integer(i64),
Float(f64),
String(String),
Bool(bool),
// Operations
Negatation(Box<Expression<'src>>),
Add(Box<Expression<'src>>, Box<Expression<'src>>),
Substract(Box<Expression<'src>>, Box<Expression<'src>>),
Multiply(Box<Expression<'src>>, Box<Expression<'src>>),
Divide(Box<Expression<'src>>, Box<Expression<'src>>),
// Keywords
Var {
name: &'src str,
rhs: Box<Expression<'src>>,
@ -37,16 +41,24 @@ pub fn eval<'src>(
funcs: &mut Vec<(&'src str, &'src [&'src str], &'src Expression<'src>)>,
) -> Result<f64, String> {
match expr {
Expression::Ident(_) => todo!(),
Expression::Ident(name) => {
if let Some((_, val)) = vars.iter().rev().find(|(var, _)| var == name) {
Ok(*val)
} else {
Err(format!("Cannot find variable `{name}` in scope"))
}
},
Expression::Integer(x) => Ok((*x) as f64),
// Types
Expression::Integer(x) => Ok((*x) as f64), // todo
Expression::Float(_) => todo!(),
Expression::Float(x) => Ok(*x),
Expression::String(_) => todo!(),
Expression::Bool(_) => todo!(),
// Operations
Expression::Negatation(lhs) => todo!(),
Expression::Add(lhs, rhs) => Ok(eval(lhs, vars, funcs)? + eval(rhs, vars, funcs)?),
@ -57,14 +69,26 @@ pub fn eval<'src>(
Expression::Divide(lhs, rhs) => Ok(eval(lhs, vars, funcs)? / eval(rhs, vars, funcs)?),
Expression::Var { name, rhs, then } => todo!(),
// Keywords
Expression::Var { name, rhs, then } => {
let rhs = eval(rhs, vars, funcs)?;
vars.push((*name, rhs));
let output = eval(then, vars, funcs);
vars.pop();
output
},
Expression::Function {
name,
args,
body,
then,
} => todo!(),
} => {
funcs.push((name, args, body));
let output = eval(then, vars, funcs);
funcs.pop();
output
},
Expression::Unit => todo!(),
}

View file

@ -1,2 +1,3 @@
pub mod ast;
pub mod op;
pub mod parser;

View file

@ -0,0 +1,98 @@
use chumsky::{
combinator::Or, prelude::{choice, just, recursive}, recursive, select, select_ref, text::{self, ascii::ident, whitespace}, IterParser, Parser
};
use crate::{language_frontend::abstract_syntax_tree::ast::Expression, language_frontend::lexer::tokens::Token};
// goal of parsing is to construct an abstract syntax tree
#[allow(clippy::let_and_return)]
pub fn parser<'src>() -> impl Parser<'src, &'src [Token<'src>], Expression<'src>> {
let ident = select_ref! {
Token::Ident(ident) => *ident
};
let keyword = |kw: &'static str| {
select! {
Token::Keyword(k) if k == kw => ()
}
};
let eq = just(Token::Equals);
let expr = recursive(|expr| {
let atom = {
let parenthesized = expr
.clone()
.delimited_by(just(Token::ParenBegin), just(Token::ParenEnd));
let integer = select! {
Token::Integer(n) => Expression::Integer(n),
};
parenthesized.or(integer)
};
let unary = just(Token::Substract)
.repeated()
.foldr(atom, |_op, rhs| Expression::Negatation(Box::new(rhs)));
// "Punktrechnung vor Strichrechnung :nerd:"
let binary_1 = unary.clone().foldl(
just(Token::Multiply)
.or(just(Token::Divide))
.then(unary)
.repeated(),
|lhs, (op, rhs)| match op {
Token::Multiply => Expression::Multiply(Box::new(lhs), Box::new(rhs)),
Token::Divide => Expression::Divide(Box::new(lhs), Box::new(rhs)),
_ => unreachable!(),
},
);
let binary_2 = binary_1.clone().foldl(
just(Token::Add)
.or(just(Token::Substract))
.then(binary_1)
.repeated(),
|lhs, (op, rhs)| match op {
Token::Add => Expression::Add(Box::new(lhs), Box::new(rhs)),
Token::Substract => Expression::Substract(Box::new(lhs), Box::new(rhs)),
_ => unreachable!(),
},
);
binary_2
});
let decl = recursive(|decl| {
let r#var = keyword("var")
.ignore_then(ident)
.then_ignore(eq.clone())
.then(expr.clone())
.then(decl.clone())
.map(|((name, rhs), then)| Expression::Var {
name,
rhs: Box::new(rhs),
then: Box::new(then),
});
let r#fun = keyword("fun")
.ignore_then(ident.clone())
.then(ident.repeated().collect::<Vec<_>>())
.then_ignore(eq.clone())
.then(expr.clone())
.then(decl)
.map(|(((name, args), body), then)| Expression::Function {
name,
args,
body: Box::new(body),
then: Box::new(then),
});
var.or(r#fun).or(expr)
});
decl
}