diff --git a/.gitignore b/.gitignore index 68f7583..c7e89de 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target -*.sh \ No newline at end of file +*.sh +sample.akai \ No newline at end of file diff --git a/src/language_frontend/abstract_syntax_tree/ast.rs b/src/language_frontend/abstract_syntax_tree/ast.rs index 8e2394a..53603de 100644 --- a/src/language_frontend/abstract_syntax_tree/ast.rs +++ b/src/language_frontend/abstract_syntax_tree/ast.rs @@ -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>), Add(Box>, Box>), Substract(Box>, Box>), Multiply(Box>, Box>), Divide(Box>, Box>), + // Keywords Var { name: &'src str, rhs: Box>, @@ -37,16 +41,24 @@ pub fn eval<'src>( funcs: &mut Vec<(&'src str, &'src [&'src str], &'src Expression<'src>)>, ) -> Result { 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!(), } diff --git a/src/language_frontend/abstract_syntax_tree/mod.rs b/src/language_frontend/abstract_syntax_tree/mod.rs index a2d9679..3c19eab 100644 --- a/src/language_frontend/abstract_syntax_tree/mod.rs +++ b/src/language_frontend/abstract_syntax_tree/mod.rs @@ -1,2 +1,3 @@ pub mod ast; pub mod op; +pub mod parser; diff --git a/src/language_frontend/parser.rs b/src/language_frontend/abstract_syntax_tree/parser.rs similarity index 85% rename from src/language_frontend/parser.rs rename to src/language_frontend/abstract_syntax_tree/parser.rs index e4bed75..5e0203e 100644 --- a/src/language_frontend/parser.rs +++ b/src/language_frontend/abstract_syntax_tree/parser.rs @@ -1,9 +1,5 @@ use chumsky::{ - IterParser, Parser, - combinator::Or, - prelude::{choice, just, recursive}, - recursive, select, - text::{self, ascii::ident}, + 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}; @@ -12,8 +8,8 @@ use crate::{language_frontend::abstract_syntax_tree::ast::Expression, language_f #[allow(clippy::let_and_return)] pub fn parser<'src>() -> impl Parser<'src, &'src [Token<'src>], Expression<'src>> { - let ident = select! { - Token::Ident(ident) => ident + let ident = select_ref! { + Token::Ident(ident) => *ident }; let keyword = |kw: &'static str| { @@ -41,6 +37,8 @@ pub fn parser<'src>() -> impl Parser<'src, &'src [Token<'src>], Expression<'src> .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)) @@ -70,9 +68,9 @@ pub fn parser<'src>() -> impl Parser<'src, &'src [Token<'src>], Expression<'src> let decl = recursive(|decl| { let r#var = keyword("var") - .ignore_then(ident.clone()) + .ignore_then(ident) .then_ignore(eq.clone()) - .then(decl.clone()) + .then(expr.clone()) .then(decl.clone()) .map(|((name, rhs), then)| Expression::Var { name, @@ -82,10 +80,10 @@ pub fn parser<'src>() -> impl Parser<'src, &'src [Token<'src>], Expression<'src> let r#fun = keyword("fun") .ignore_then(ident.clone()) - .then(ident.clone().repeated().collect()) + .then(ident.repeated().collect::>()) .then_ignore(eq.clone()) - .then(decl.clone()) - .then(decl.clone()) + .then(expr.clone()) + .then(decl) .map(|(((name, args), body), then)| Expression::Function { name, args, diff --git a/src/language_frontend/lexer/tokens.rs b/src/language_frontend/lexer/tokens.rs index 3d8ff21..7a5cace 100644 --- a/src/language_frontend/lexer/tokens.rs +++ b/src/language_frontend/lexer/tokens.rs @@ -37,9 +37,12 @@ pub enum Token<'src> { #[token("}")] BraceEnd, - #[regex("[0-9]+", |lex| lex.slice().parse::().unwrap())] + #[regex(r"[+-]?[0-9]+", |lex| lex.slice().parse::().unwrap(), priority = 3)] Integer(i64), + #[regex(r"[+-]?([0-9]*[.])?[0-9]+", |lex| lex.slice().parse::().unwrap())] + Float(f64), + #[regex(r"[_a-zA-Z][_0-9a-zA-Z]*")] Ident(&'src str), diff --git a/src/language_frontend/mod.rs b/src/language_frontend/mod.rs index 8c28b19..0d2d3fd 100644 --- a/src/language_frontend/mod.rs +++ b/src/language_frontend/mod.rs @@ -1,3 +1,2 @@ pub mod abstract_syntax_tree; pub mod lexer; -pub mod parser; diff --git a/src/main.rs b/src/main.rs index 9c2d4c8..d8f741c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,11 @@ use chumsky::Parser; use logos::Logos; -use crate::language_frontend::abstract_syntax_tree; use crate::{ - language_frontend::lexer::tokens::Token, language_frontend::parser::parser}; + language_frontend::lexer::tokens::Token, language_frontend::abstract_syntax_tree::parser::parser}; use crate::language_frontend::abstract_syntax_tree::ast::{eval, Expression}; + mod language_frontend; /* @@ -17,7 +17,8 @@ Simple Compiler -> 4 Stages: */ fn main() { - let lexer = Token::lexer("1 + 1 * 3"); + let sourcecode = std::fs::read_to_string("sample.akai").unwrap(); + let lexer = Token::lexer(&sourcecode); let mut tokens = vec![]; for (token, span) in lexer.spanned() { @@ -30,19 +31,6 @@ fn main() { } } - /* - match parser().parse(&tokens).into_result() { - Ok(expr) => match eval(&ast, &mut Vec::new(), &mut Vec::new()) { - Ok(output) => println!("{output}"), - Err(eval_err) => println!("Evaluation error: {eval_err}"), - } - Err(e) => { - println!("parse error: {:#?}", e); - return; - } - }; */ - - match parser().parse(&tokens).into_result() { Ok(ast) => match eval(&ast, &mut Vec::new(), &mut Vec::new()) { Ok(output) => println!("{output}"),