parse math expressions

This commit is contained in:
mehbark 2026-01-02 21:07:26 -05:00
parent fcac4db1dc
commit e2213a627b
3 changed files with 75 additions and 5 deletions

View file

@ -8,6 +8,19 @@ pub enum Ident {
Return(Symbol),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum BinOp {
Add,
Sub,
Mul,
Div,
Mod,
Pow,
Eq,
Lt,
Le,
}
// TODO: great display repr for this for testing (yes it's allowed)
#[derive(Debug, Clone)]
pub enum Ast {
@ -26,7 +39,7 @@ pub enum Ast {
/// `f x`
App(Box<Ast>, Box<Ast>),
/// `x + y` (only builtins, sorry)
BinOp(Box<Ast>, fn(Val, Val) -> Val, Box<Ast>),
BinOp(Box<Ast>, BinOp, Box<Ast>),
/// `3`
Num(f64),
/// `(println bla; 3) #=> 3`

View file

@ -3,10 +3,11 @@ use std::{fmt, process};
use ariadne::{Color, Label, Report, ReportKind, Source};
use chumsky::{
input::{Stream, ValueInput},
pratt::{infix, left, none, right},
prelude::*,
};
use crate::ast::{Ast, Ident};
use crate::ast::{Ast, BinOp, Ident};
use logos::Logos;
@ -47,7 +48,7 @@ enum Token<'a> {
#[token("fn")]
Fn,
#[regex(r"[+*/%=-]")]
#[regex(r"([+*/%=<>-]|\*\*|<=|>=)")]
BinOp(&'a str),
#[regex(r"[a-zA-Z_][a-zA-Z_0-9']*")]
@ -210,7 +211,45 @@ where
})
.labelled("function application");
app.or(non_app)
let atom = app.or(non_app);
// %
atom.pratt((
infix(none(10), just(Token::BinOp("=")), |l, _, r, _| {
Ast::BinOp(Box::new(l), BinOp::Eq, Box::new(r))
}),
infix(none(10), just(Token::BinOp("<")), |l, _, r, _| {
Ast::BinOp(Box::new(l), BinOp::Lt, Box::new(r))
}),
infix(none(10), just(Token::BinOp("<=")), |l, _, r, _| {
Ast::BinOp(Box::new(l), BinOp::Le, Box::new(r))
}),
// note that these two are flipped
infix(none(10), just(Token::BinOp(">")), |l, _, r, _| {
Ast::BinOp(Box::new(r), BinOp::Lt, Box::new(l))
}),
infix(none(10), just(Token::BinOp(">=")), |l, _, r, _| {
Ast::BinOp(Box::new(r), BinOp::Le, Box::new(l))
}),
infix(right(3), just(Token::BinOp("%")), |l, _, r, _| {
Ast::BinOp(Box::new(l), BinOp::Mod, Box::new(r))
}),
infix(right(3), just(Token::BinOp("**")), |l, _, r, _| {
Ast::BinOp(Box::new(l), BinOp::Pow, Box::new(r))
}),
infix(left(2), just(Token::BinOp("*")), |l, _, r, _| {
Ast::BinOp(Box::new(l), BinOp::Mul, Box::new(r))
}),
infix(right(2), just(Token::BinOp("/")), |l, _, r, _| {
Ast::BinOp(Box::new(l), BinOp::Div, Box::new(r))
}),
infix(left(1), just(Token::BinOp("+")), |l, _, r, _| {
Ast::BinOp(Box::new(l), BinOp::Add, Box::new(r))
}),
infix(left(1), just(Token::BinOp("-")), |l, _, r, _| {
Ast::BinOp(Box::new(l), BinOp::Sub, Box::new(r))
}),
))
})
.labelled("expression")
.separated_by(semicolon)

View file

@ -1,4 +1,4 @@
use std::fmt;
use std::{fmt, ops};
use crate::{map::Map, symbol::Symbol};
@ -23,3 +23,21 @@ impl fmt::Debug for Val {
}
}
}
impl ops::Add for Val {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
match (self, rhs) {
(Val::Number(a), Val::Number(b)) => Val::Number(a + b),
(f @ Val::Function { .. }, g @ Val::Function { .. }) => todo!(),
(Val::Map(mut m1), Val::Map(m2)) => {
for (k, v) in m2 {
m1.insert(k, v);
}
Val::Map(m1)
}
(lhs, rhs) => panic!("how do i add these {lhs:?} {rhs:?}"),
}
}
}