handball/src/main.rs

147 lines
3.2 KiB
Rust

use logos::Logos;
mod grammar;
#[derive(Logos, Debug, PartialEq)]
enum LogosToken {
#[regex(r"[0-9]+", priority = 2)]
Int,
#[regex(r"[0-9]+(\\.[0-9]+)?")]
Float,
#[regex(r"[A-Za-z0-9!$%&*+\-./:<=>?@^_~]+")]
Ident,
#[error]
#[regex(r"[ \t\n\f]+", logos::skip)]
Error,
#[token(r"(")]
Lparen,
#[token(r")")]
Rparen,
}
#[derive(Debug)]
pub struct LexError;
type Spanned<Tok, Loc, Error> = Result<(Loc, Tok, Loc), Error>;
struct Lexer<'a>(logos::Lexer<'a, LogosToken>);
impl<'a> Lexer<'a> {
fn new(src: &'a str) -> Self {
Self(LogosToken::lexer(src))
}
}
#[derive(Clone, Debug)]
pub enum Token<'s> {
Int(i64),
Float(f64),
Ident(&'s str),
Lparen,
Rparen,
}
impl<'a> Iterator for Lexer<'a> {
type Item = Spanned<Token<'a>, usize, LexError>;
fn next(&mut self) -> Option<Self::Item> {
let kind = self.0.next()?;
let span = self.0.span();
let text = self.0.slice();
let t = match kind {
LogosToken::Int => Token::Int(text.parse().unwrap()),
LogosToken::Float => Token::Float(text.parse().unwrap()),
LogosToken::Ident => Token::Ident(text),
LogosToken::Lparen => Token::Lparen,
LogosToken::Rparen => Token::Rparen,
LogosToken::Error => return Some(Err(LexError)),
};
Some(Ok((span.start, t, span.end)))
}
}
#[derive(Clone, Debug)]
pub enum Tree<'s> {
Leaf(Val<'s>),
Branch(Vec<Tree<'s>>),
}
#[derive(Clone, Debug)]
pub enum Val<'s> {
Int(i64),
Float(f64),
Ident(&'s str),
}
enum Func {}
enum RVal {
Func(Func),
Num(f64),
}
enum Op {
Push(RVal),
Call(u8),
Print,
}
fn comp_to(t: &Tree)
fn eval(t: &Tree<'_>) -> f64 {
match t {
Tree::Leaf(Val::Ident(_)) => panic!("Need number got {:?}", t),
Tree::Leaf(Val::Float(f)) => *f,
Tree::Leaf(Val::Int(i)) => *i as f64,
Tree::Branch(v) => {
if let Tree::Leaf(Val::Ident(f)) = v[0] {
match f {
"min" => v[1..].iter().map(eval).reduce(f64::min).unwrap(),
"max" => v[1..].iter().map(eval).reduce(f64::max).unwrap(),
"+" => v[1..].iter().map(eval).sum(),
"*" => v[1..].iter().map(eval).product(),
"/" => eval(&v[1]) / v[2..].iter().map(eval).product::<f64>(),
"-" => eval(&v[1]) - v[2..].iter().map(eval).sum::<f64>(),
_ => panic!("Unknown func {:?}", f),
}
} else {
panic!("Not a function")
}
}
}
}
fn main() {
let src = std::fs::read_to_string(std::env::args().nth(1).unwrap()).unwrap();
let tree = grammar::TreesParser::new().parse(Lexer::new(&src));
let t = dbg!(tree).unwrap();
dbg!(eval(&t[0]));
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn math_exprs() {
fn test(s: &str, v: f64) {
let tree = grammar::TreesParser::new().parse(Lexer::new(s)).unwrap();
assert_eq!(tree.len(), 1);
assert_eq!(eval(&tree[0]), v);
}
test("1", 1.0);
test("(+ 1 2)", 3.0);
test("(+ 1 2 (/ 2 3 4 5))", 3.033333333333333);
}
}