hey it can calculate 4 again xP

This commit is contained in:
LunarAkai 2025-08-07 00:29:16 +02:00
commit d253497b3e
11 changed files with 137 additions and 95 deletions

View file

@ -6,7 +6,7 @@ Akai Lang (yeah I'm not creative and the name is still unused on github, sooo) i
## Planned Features ## Planned Features
- Object-Oriented - Object-Oriented
- dynamic typing - dynamic typing / Type inference
- LLVM Backend - LLVM Backend
## Hello World ## Hello World
@ -14,4 +14,7 @@ Akai Lang (yeah I'm not creative and the name is still unused on github, sooo) i
fun helloWorld() { fun helloWorld() {
print("Hello World!") print("Hello World!")
} }
``` ```
## Shoutout to these amazing ressources that help(ed) me understand language design:
- [https://mukulrathi.com/create-your-own-programming-language/intro-to-compiler/](https://mukulrathi.com/create-your-own-programming-language/intro-to-compiler/)

View file

@ -0,0 +1,71 @@
/// Abstract Syntax Tree
#[derive(Debug)]
pub enum Expression<'src> {
Ident(&'src str),
Integer(i64),
Float(f64),
String(String),
Bool(bool),
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>>),
Var {
name: &'src str,
rhs: Box<Expression<'src>>,
then: Box<Expression<'src>>,
},
Function {
name: &'src str,
args: Vec<&'src str>,
body: Box<Expression<'src>>,
then: Box<Expression<'src>>,
},
Unit,
}
pub fn eval<'src>(
expr: &'src Expression<'src>,
vars: &mut Vec<(&'src str, f64)>,
funcs: &mut Vec<(&'src str, &'src [&'src str], &'src Expression<'src>)>,
) -> Result<f64, String> {
match expr {
Expression::Ident(_) => todo!(),
Expression::Integer(x) => Ok((*x) as f64),
Expression::Float(_) => todo!(),
Expression::String(_) => todo!(),
Expression::Bool(_) => todo!(),
Expression::Negatation(lhs) => todo!(),
Expression::Add(lhs, rhs) => Ok(eval(lhs, vars, funcs)? + eval(rhs, vars, funcs)?),
Expression::Substract(lhs, rhs) => Ok(eval(lhs, vars, funcs)? - eval(rhs, vars, funcs)?),
Expression::Multiply(lhs, rhs) => Ok(eval(lhs, vars, funcs)? * eval(rhs, vars, funcs)?),
Expression::Divide(lhs, rhs) => Ok(eval(lhs, vars, funcs)? / eval(rhs, vars, funcs)?),
Expression::Var { name, rhs, then } => todo!(),
Expression::Function {
name,
args,
body,
then,
} => todo!(),
Expression::Unit => todo!(),
}
}

View file

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

View file

@ -9,11 +9,11 @@ pub enum Op {
impl Op { impl Op {
pub fn eval(&self) -> String { pub fn eval(&self) -> String {
let text: &str = match self { let text: &str = match self {
Op::Add => "+", Op::Add => "+",
Op::Subtract => "-", Op::Subtract => "-",
Op::Multiply => "*", Op::Multiply => "*",
Op::Divide => "/", Op::Divide => "/",
}; };
text.to_string() text.to_string()
} }
} }

View file

@ -1,62 +0,0 @@
/// Abstract Syntax Tree
#[derive(Debug)]
pub enum Expression<'src> {
VariableName(&'src str),
Integer(i64),
Float(f64),
String(String),
Bool(bool),
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>>),
Var {
name: &'src str,
rhs: Box<Expression<'src>>,
then: Box<Expression<'src>>,
},
Function {
name: &'src str,
args: Vec<&'src str>,
body: Box<Expression<'src>>,
then: Box<Expression<'src>>,
},
Unit
}
impl<'src> Expression<'src> {
pub fn evaluate(&self) -> String {
match self {
Expression::VariableName(_) => todo!(),
Expression::Integer(_) => todo!(),
Expression::Float(_) => todo!(),
Expression::String(_) => todo!(),
Expression::Bool(_) => todo!(),
Expression::Negatation(expression) => todo!(),
Expression::Add(expression, expression1) => todo!(),
Expression::Substract(expression, expression1) => todo!(),
Expression::Multiply(expression, expression1) => todo!(),
Expression::Divide(expression, expression1) => todo!(),
Expression::Var { name, rhs, then } => todo!(),
Expression::Function { name, args, body, then } => todo!(),
Expression::Unit => todo!(),
}
}
}

View file

@ -0,0 +1 @@
pub mod tokens;

View file

@ -39,7 +39,7 @@ pub enum Token<'src> {
#[regex("[0-9]+", |lex| lex.slice().parse::<i64>().unwrap())] #[regex("[0-9]+", |lex| lex.slice().parse::<i64>().unwrap())]
Integer(i64), Integer(i64),
#[regex(r"[_a-zA-Z][_0-9a-zA-Z]*")] #[regex(r"[_a-zA-Z][_0-9a-zA-Z]*")]
Ident(&'src str), Ident(&'src str),
@ -53,5 +53,3 @@ pub enum Token<'src> {
#[token("else")] #[token("else")]
Keyword(&'src str), Keyword(&'src str),
} }

View file

@ -1,3 +1,3 @@
pub mod ast; pub mod abstract_syntax_tree;
pub mod lexer;
pub mod parser; pub mod parser;
pub mod tokens;

View file

@ -1,7 +1,14 @@
use chumsky::{combinator::Or, prelude::{choice, just, recursive}, recursive, select, text::{self, ascii::ident}, IterParser, Parser}; use chumsky::{
IterParser, Parser,
combinator::Or,
prelude::{choice, just, recursive},
recursive, select,
text::{self, ascii::ident},
};
use crate::{language_frontend::ast::ast::Expression, language_frontend::tokens::Token}; 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)] #[allow(clippy::let_and_return)]
pub fn parser<'src>() -> impl Parser<'src, &'src [Token<'src>], Expression<'src>> { pub fn parser<'src>() -> impl Parser<'src, &'src [Token<'src>], Expression<'src>> {
@ -9,16 +16,16 @@ pub fn parser<'src>() -> impl Parser<'src, &'src [Token<'src>], Expression<'src>
Token::Ident(ident) => ident Token::Ident(ident) => ident
}; };
let keyword = |kw: &'static str| select! { let keyword = |kw: &'static str| {
Token::Keyword(k) if k == kw => () select! {
Token::Keyword(k) if k == kw => ()
}
}; };
let eq = just(Token::Equals); let eq = just(Token::Equals);
let expr = recursive( let expr = recursive(|expr| {
|expr| let atom = {
{
let atom = {
let parenthesized = expr let parenthesized = expr
.clone() .clone()
.delimited_by(just(Token::ParenBegin), just(Token::ParenEnd)); .delimited_by(just(Token::ParenBegin), just(Token::ParenEnd));
@ -63,7 +70,7 @@ pub fn parser<'src>() -> impl Parser<'src, &'src [Token<'src>], Expression<'src>
let decl = recursive(|decl| { let decl = recursive(|decl| {
let r#var = keyword("var") let r#var = keyword("var")
.ignore_then(ident.clone()) .ignore_then(ident.clone())
.then_ignore(eq.clone()) .then_ignore(eq.clone())
.then(decl.clone()) .then(decl.clone())
.then(decl.clone()) .then(decl.clone())
@ -84,10 +91,10 @@ pub fn parser<'src>() -> impl Parser<'src, &'src [Token<'src>], Expression<'src>
args, args,
body: Box::new(body), body: Box::new(body),
then: Box::new(then), then: Box::new(then),
}); });
var.or(r#fun).or(expr) var.or(r#fun).or(expr)
}); });
decl decl
} }

View file

@ -1,12 +1,23 @@
use chumsky::Parser; use chumsky::Parser;
use logos::Logos; use logos::Logos;
use crate::{language_frontend::parser::parser, language_frontend::tokens::Token}; use crate::language_frontend::abstract_syntax_tree;
use crate::{
language_frontend::lexer::tokens::Token, language_frontend::parser::parser};
use crate::language_frontend::abstract_syntax_tree::ast::{eval, Expression};
mod language_frontend; mod language_frontend;
/*
Simple Compiler -> 4 Stages:
- lex
- parse
- type-check
- translate to machine instructions
*/
fn main() { fn main() {
let lexer = Token::lexer("(1 + 1) * 3"); let lexer = Token::lexer("1 + 1 * 3");
let mut tokens = vec![]; let mut tokens = vec![];
for (token, span) in lexer.spanned() { for (token, span) in lexer.spanned() {
@ -19,16 +30,28 @@ fn main() {
} }
} }
let ast = match parser().parse(&tokens).into_result() { /*
Ok(expr) => { match parser().parse(&tokens).into_result() {
println!("[AST]\n{:#?}", expr); Ok(expr) => match eval(&ast, &mut Vec::new(), &mut Vec::new()) {
expr Ok(output) => println!("{output}"),
Err(eval_err) => println!("Evaluation error: {eval_err}"),
} }
Err(e) => { Err(e) => {
println!("parse error: {:#?}", e); println!("parse error: {:#?}", e);
return; return;
} }
}; }; */
println!("\n[result]\n{}", ast.evaluate());
match parser().parse(&tokens).into_result() {
Ok(ast) => match eval(&ast, &mut Vec::new(), &mut Vec::new()) {
Ok(output) => println!("{output}"),
Err(eval_err) => println!("Evaluation error: {eval_err}"),
},
Err(parse_errs) => parse_errs
.into_iter()
.for_each(|err| println!("Parse error: {err}")),
};
//println!("\n[result]\n{}", abstract_syntax_tree::ast::eval(absyntr, vars, funcs));
} }

View file

@ -17,6 +17,7 @@ class Cat derive Animal:
fun helloWorld() { fun helloWorld() {
// Variables either dynamically or statically typed // Variables either dynamically or statically typed
// -> Type inference
var String: test = "I'm a string" var String: test = "I'm a string"
var foo = 12 // reads as int var foo = 12 // reads as int