Skip to content
Snippets Groups Projects
Commit be369876 authored by Per Lindgren's avatar Per Lindgren
Browse files

wip

parent fee50aa2
No related branches found
No related tags found
No related merge requests found
use crust::{ use crust::{
ast::Span, ast::Span,
parse::{parse_assign, test}, parse::{parse_assign, parse_expr},
interpreter::{eval_expr}
}; };
fn test(s: &str, v: i32) {
match parse_expr(Span::new(s)) {
Ok((Span { fragment: "", .. }, e)) => {
println!("{:?}", &e);
println!("eval {} {}", eval_expr(&e), v);
assert_eq!(eval_expr(&e), v);
}
Ok((s, t)) => println!(
"parse incomplete, \n parsed tokens \t{:?}, \n remaining \t{:?}",
t, s
),
Err(err) => println!("{:?}", err),
}
}
fn main() { fn main() {
// test("- -1 + + 1", - -1 + 1); // rust does not allow + as a unary op (I do ;) // test("- -1 + + 1", - -1 + 1); // rust does not allow + as a unary op (I do ;)
// test("(-1-1)+(-1+3)", (-1 - 1) + (-1) + 3); // test("(-1-1)+(-1+3)", (-1 - 1) + (-1) + 3);
...@@ -12,6 +28,6 @@ fn main() { ...@@ -12,6 +28,6 @@ fn main() {
// test("1*2+3", 1 * 2 + 3); // test("1*2+3", 1 * 2 + 3);
// // just to check that we get a parse error // // just to check that we get a parse error
// test("1*2+3+3*21-a12+2", 1 * 2 + 3 + 3 * 21 - 12 + 2); // test("1*2+3+3*21-a12+2", 1 * 2 + 3 + 3 * 21 - 12 + 2);
test("1 + a(1, 2)", 1 + 2); test("1 + (1 - 2)", 1 + (1 - 2) );
println!("{:?}", parse_assign(Span::new("3 = 4"))); println!("{:?}", parse_assign(Span::new("3 = a(1, 2+3)")));
} }
...@@ -26,7 +26,7 @@ pub enum Expr<'a> { ...@@ -26,7 +26,7 @@ pub enum Expr<'a> {
Bool(bool), Bool(bool),
Par(Box<SpanExpr<'a>>), Par(Box<SpanExpr<'a>>),
Id(String), Id(String),
Fn(String, Vec<SpanExpr<'a>>), Call(String, Vec<SpanExpr<'a>>),
BinOp(Op, Box<SpanExpr<'a>>, Box<SpanExpr<'a>>), BinOp(Op, Box<SpanExpr<'a>>, Box<SpanExpr<'a>>),
UnaryOp(Op, Box<SpanExpr<'a>>), UnaryOp(Op, Box<SpanExpr<'a>>),
} }
...@@ -39,8 +39,8 @@ pub enum Cmd<'a> { ...@@ -39,8 +39,8 @@ pub enum Cmd<'a> {
Let(SpanMut<'a>, String, SpanType<'a>, SpanExpr<'a>), Let(SpanMut<'a>, String, SpanType<'a>, SpanExpr<'a>),
// id = expr // id = expr
Assign(SpanExpr<'a>, SpanExpr<'a>), Assign(SpanExpr<'a>, SpanExpr<'a>),
// /// if predicate do-this, and optionally do-that) // if predicate do-this, and optionally do-that)
// If(Expr, Block, Option<Block>), If(SpanExpr<'a>, SpanBlock<'a>, Option<SpanBlock<'a>>),
// /// while predicate do-this // /// while predicate do-this
// While(Expr, Block), // While(Expr, Block),
// Return(Expr), // Return(Expr),
...@@ -70,6 +70,7 @@ pub type SpanMut<'a> = (Span<'a>, Mutability); ...@@ -70,6 +70,7 @@ pub type SpanMut<'a> = (Span<'a>, Mutability);
// } // }
pub type SpanBlock<'a> = (Span<'a>, Vec<SpanCmd<'a>>); pub type SpanBlock<'a> = (Span<'a>, Vec<SpanCmd<'a>>);
pub type Block<'a> = Vec<Cmd<'a>>;
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub enum Type<'a> { pub enum Type<'a> {
......
// Interpreter
use crate::ast::{Expr, Op, SpanExpr};
pub fn eval_expr(e: &SpanExpr) -> i32 {
match e.clone().1 {
Expr::Num(i) => i,
Expr::BinOp(op, l, r) => {
let lv = eval_expr(&l);
let rv = eval_expr(&r);
match op {
Op::Add => lv + rv,
Op::Sub => lv - rv,
Op::Mul => lv * rv,
Op::Div => lv / rv,
Op::Pow => lv.pow(rv as u32),
_ => unimplemented!(),
}
}
Expr::UnaryOp(op, e) => {
let e = eval_expr(&e);
match op {
Op::Add => e,
Op::Sub => -e,
_ => unimplemented!(),
}
}
_ => unimplemented!(),
}
}
// use crate::ast::{Binop, Cmd, Constant, Expr, Item, Prog, TypeDecl};
// use crate::check::{check_prog, Fenv, Tenv};
// use crate::parse::parse_prog;
//use std::collections::HashMap;
// pub type Addr = u32;
// #[derive(Debug, PartialEq, Clone)]
// pub enum Data {
// Value(Constant),
// Pointer(Addr),
// }
// pub type Venv = HashMap<String, Addr>;
// pub type Menv = HashMap<Addr, Data>;
// #[derive(Debug, PartialEq, Clone)]
// pub struct Mem {
// pub Addr: u32,
// pub Menv: Menv,
// }
// impl Mem {
// fn new() -> Mem {
// Mem {
// Addr: 0,
// Menv: Menv::new(),
// }
// }
// fn alloc(&mut self) -> Addr {
// // allocate a new address
// self.Addr += 1;
// self.Addr
// }
// }
// pub fn get_bool(d: Data) -> bool {
// if let Data::Value(Constant::Boolean(b)) = d {
// b
// } else {
// panic!("cannot evaluate into Boolean");
// }
// }
// pub fn get_i32(d: Data) -> i32 {
// if let Data::Value(Constant::Num(i)) = d {
// i
// } else {
// panic!("cannot evaluate into i32");
// }
// }
// pub fn eval_expr(exp: &Expr, mem: &mut Mem, venv: &Venv, fenv: &Fenv) -> Data {
// println!("\neval_expr {:?}, mem {:?}, venv {:?}", exp, mem, venv);
// match exp {
// Expr::Constant(c) => Data::Value(c.clone()),
// Expr::Binop(e1, op, e2) => {
// let ev1 = eval_expr(e1, mem, venv, fenv);
// let ev2 = eval_expr(e2, mem, venv, fenv);
// Data::Value(match op {
// Binop::And => Constant::Boolean(get_bool(ev1) && get_bool(ev2)),
// Binop::Or => Constant::Boolean(get_bool(ev1) && get_bool(ev2)),
// Binop::Equal => Constant::Boolean(ev1 == ev2),
// Binop::Less => Constant::Boolean(get_i32(ev1) < get_i32(ev2)),
// Binop::LessEqual => Constant::Boolean(get_i32(ev1) <= get_i32(ev2)),
// Binop::Greater => Constant::Boolean(get_i32(ev1) > get_i32(ev2)),
// Binop::GreaterEqual => Constant::Boolean(get_i32(ev1) >= get_i32(ev2)),
// Binop::Divide => Constant::Num(get_i32(ev1) / get_i32(ev2)),
// Binop::Reminder => Constant::Num(get_i32(ev1) % get_i32(ev2)),
// Binop::Minus => Constant::Num(get_i32(ev1) - get_i32(ev2)),
// Binop::Plus => Constant::Num(get_i32(ev1) + get_i32(ev2)),
// Binop::Times => Constant::Num(get_i32(ev1) * get_i32(ev2)),
// })
// }
// Expr::Id(id) => {
// let e = mem.Menv.get(venv.get(id).unwrap()).unwrap();
// println!("{:?} -> {:?}", id, e);
// e.to_owned()
// }
// Expr::Not(e) => {
// let ev = eval_expr(e, mem, venv, fenv);
// Data::Value(Constant::Boolean(!get_bool(ev)))
// }
// Expr::Application(id, exprs) => {
// // evaluate arguments
// println!("application {:?}", id);
// let args: Vec<Data> = exprs
// .into_iter()
// .map(|e| eval_expr(e, mem, venv, fenv))
// .collect();
// println!("args {:?}", args);
// // lookup callee
// let f = fenv.get(id).unwrap();
// println!("f {:?}", &f);
// let parameter_names: Vec<String> =
// f.sig.1.clone().into_iter().map(|idt| idt.0).collect();
// println!("f par_names {:?}", &parameter_names);
// let mut lenv = Venv::new(); // local environment for function application
// let arg_assign: Vec<(String, Data)> =
// parameter_names.into_iter().zip(args.into_iter()).collect();
// println!("arg assignments {:?}", &arg_assign);
// for (id, val) in arg_assign {
// let addr = mem.alloc(); // get new allocation slot
// mem.Menv.insert(addr, val); // write the new value
// lenv.insert(id, addr);
// }
// println!("local enviroment {:?}", &lenv);
// println!("memory {:?}", &mem);
// // execute function, unwrap the result as we need a Constant
// eval_body(f.body.clone(), mem, &mut lenv, fenv).unwrap()
// }
// Expr::Ref(exp) => {
// println!("here");
// match *exp.to_owned() {
// Expr::Id(id) => {
// println!("id {:?}", &id);
// let addr = venv.get(&id).unwrap();
// Data::Pointer(*addr)
// }
// _ => {
// let val = eval_expr(exp, mem, venv, fenv);
// println!("-- value {:?}", &val);
// let addr = mem.alloc(); // get new allocation slot
// mem.Menv.insert(addr, val.to_owned()); // write the new value
// let ref_val = Data::Pointer(addr);
// println!(
// "Ref exp {:?} e {:?} mem {:?} venv {:?}",
// exp, val, mem, venv
// );
// ref_val
// }
// }
// }
// Expr::RefMut(exp) => {
// println!("here");
// match *exp.to_owned() {
// Expr::Id(id) => {
// println!("id {:?}", &id);
// let addr = venv.get(&id).unwrap();
// Data::Pointer(*addr)
// }
// _ => {
// let val = eval_expr(exp, mem, venv, fenv);
// println!("-- value {:?}", &val);
// let addr = mem.alloc(); // get new allocation slot
// mem.Menv.insert(addr, val.to_owned()); // write the new value
// let ref_val = Data::Pointer(addr);
// println!(
// "Ref exp {:?} e {:?} mem {:?} venv {:?}",
// exp, val, mem, venv
// );
// ref_val
// }
// }
// }
// Expr::Deref(exp) => {
// println!("-- Deref");
// let e = eval_expr(exp, mem, venv, fenv);
// println!("-- DereRef {:?} {:?}", exp, e);
// if let Data::Pointer(addr) = e {
// mem.Menv.get(&addr).unwrap().to_owned()
// } else {
// panic!("cannot deref {:?}", e);
// }
// }
// _ => unimplemented!(),
// }
// }
// pub fn eval_lvalue(exp: &Expr, mem: &mut Mem, venv: &Venv, fenv: &Fenv) -> Addr {
// println!("eval_lvalue {:?},{:?},{:?},{:?} ", exp, mem, venv, fenv);
// match exp {
// Expr::Id(id) => {
// let addr = venv.get(id).unwrap();
// println!("addr {:?}", addr);
// addr.to_owned()
// }
// Expr::Deref(exp) => {
// let lv = eval_expr(exp, mem, venv, fenv);
// println!("lv {:?}", lv);
// match eval_expr(exp, mem, venv, fenv) {
// Data::Pointer(addr) => addr,
// _ => panic!("cannot deref {:?}", exp),
// }
// }
// _ => unimplemented!(),
// }
// }
// // commands may return with a value
// // either directly (return) or
// // if inside an inner block (then/else, or while)
// pub fn menv_update(data: Data, menv: &mut Menv) {
// // match data {
// // Pointer::
// // }
// }
// pub fn dump(msg: &str, mem: &Mem, venv: &Venv) {
// println!("{:?} {:?} {:?}", msg, mem, venv);
// }
// // A return genaretes Some(Data) else None
// pub fn eval_cmd(cmd: &Cmd, mem: &mut Mem, venv: &mut Venv, fenv: &Fenv) -> Option<Data> {
// println!("{:?}", cmd);
// match cmd {
// Cmd::Assign(lexp, rexp) => {
// let rval = eval_expr(rexp, mem, venv, fenv);
// println!("val {:?}", rval);
// let addr = eval_lvalue(lexp, mem, venv, fenv);
// // println!("lval {:?}", lval);
// // let addr = venv.get(&lval).unwrap();
// mem.Menv.insert(addr, rval);
// None
// }
// Cmd::If(exp, then_block, opt_else) => {
// if get_bool(eval_expr(exp, mem, venv, fenv)) {
// eval_body(then_block.to_vec(), mem, venv, fenv)
// } else {
// if let Some(else_block) = opt_else {
// eval_body(else_block.to_vec(), mem, venv, fenv)
// } else {
// None
// }
// }
// }
// Cmd::Let(_, id, _, exp) => {
// let val = eval_expr(exp, mem, venv, fenv);
// println!("val {:?}", val);
// let addr = mem.alloc(); // get new allocation slot
// mem.Menv.insert(addr, val); // write the new value
// venv.insert(id.to_owned(), addr);
// dump("after Let", mem, venv);
// None
// }
// Cmd::Return(exp) => {
// let v = Some(eval_expr(exp, mem, venv, fenv));
// println!("return value {:?}", v);
// v
// }
// Cmd::While(exp, body) => {
// while get_bool(eval_expr(exp, mem, venv, fenv)) {
// if let Some(retv) = eval_body(body.to_vec(), mem, venv, fenv) {
// return Some(retv);
// }
// }
// None
// }
// }
// }
// pub fn eval_body(cmds: Vec<Cmd>, mem: &mut Mem, venv: &mut Venv, fenv: &Fenv) -> Option<Data> {
// for c in &cmds {
// if let Some(ret) = eval_cmd(c, mem, venv, fenv) {
// return Some(ret);
// }
// }
// None
// }
// pub fn build_env(prog: Prog) -> (Tenv, Fenv) {
// let mut tenv = Tenv::new();
// let mut fenv = Fenv::new();
// for i in prog {
// match i {
// Item::TypeDecl(TypeDecl::Struct(id, layout)) => {
// tenv.insert(id.clone(), TypeDecl::Struct(id, layout));
// }
// Item::Function(f) => {
// fenv.insert(f.sig.0.to_owned(), f);
// }
// }
// }
// (tenv, fenv)
// }
// pub fn eval_prog(prog: &str) {
// let (unparsed, prog) = parse_prog(prog).unwrap();
// println!("prog: {:?}", prog);
// println!("unparsed: {:?}", unparsed);
// let (tenv, fenv) = check_prog(&prog);
// println!("envs {:?}", (tenv, &fenv));
// // assume main does not take any parameters
// let call_main = Expr::Application("main".to_owned(), Vec::<Expr>::new());
// let mut mem = Mem::new();
// let mut venv = Venv::new();
// let ret = eval_expr(&call_main, &mut mem, &mut venv, &fenv);
// println!("return from main = {:?}", ret);
// println!("venv = {:?}", venv);
// println!("mem = {:?}", mem);
// }
...@@ -2,3 +2,4 @@ ...@@ -2,3 +2,4 @@
pub mod ast; pub mod ast;
pub mod parse; pub mod parse;
pub mod interpreter;
...@@ -6,15 +6,15 @@ use std::slice::Iter; ...@@ -6,15 +6,15 @@ use std::slice::Iter;
use nom::{ use nom::{
branch::alt, branch::alt,
bytes::complete::tag, bytes::complete::tag,
character::complete::{alpha1, char, digit1, multispace0}, character::complete::{alpha1, char, digit1, multispace0, multispace1},
combinator::{cut, map}, combinator::{cut, map, opt},
error::ParseError, error::ParseError,
multi::{many1, separated_list}, multi::{many1, separated_list},
sequence::{delimited, preceded, tuple}, sequence::{delimited, preceded, terminated, tuple},
IResult, IResult,
}; };
use crate::ast::{Cmd, Expr, Op, Span, SpanCmd, SpanExpr}; use crate::ast::{Cmd, Expr, Op, Span, SpanCmd, SpanExpr, Block};
pub fn parse_i32(i: Span) -> IResult<Span, (Span, i32)> { pub fn parse_i32(i: Span) -> IResult<Span, (Span, i32)> {
map(digit1, |digit_str: Span| { map(digit1, |digit_str: Span| {
...@@ -42,7 +42,7 @@ pub enum Token<'a> { ...@@ -42,7 +42,7 @@ pub enum Token<'a> {
Num(i32), Num(i32),
Bool(bool), Bool(bool),
Id(String), Id(String),
Fn(String, Vec<(Span<'a>, Vec<SpanToken<'a>>)>), Call(String, Vec<(Span<'a>, Vec<SpanToken<'a>>)>),
Par(Vec<SpanToken<'a>>), Par(Vec<SpanToken<'a>>),
Op(Op), Op(Op),
} }
...@@ -54,9 +54,10 @@ fn parse_terminal(i: Span) -> IResult<Span, SpanToken> { ...@@ -54,9 +54,10 @@ fn parse_terminal(i: Span) -> IResult<Span, SpanToken> {
map(parse_i32, |(s, v)| (s, Token::Num(v))), map(parse_i32, |(s, v)| (s, Token::Num(v))),
map(tag("true"), |s| (s, Token::Bool(true))), map(tag("true"), |s| (s, Token::Bool(true))),
map(tag("false"), |s| (s, Token::Bool(false))), map(tag("false"), |s| (s, Token::Bool(false))),
map(tuple((alpha1, parse_par(separated_list(char(','), parse_tokens)))), |(s, t)| { map(
(s, Token::Fn(s.to_string(), t)) tuple((alpha1, parse_par(separated_list(char(','), parse_tokens)))),
}), |(s, t)| (s, Token::Call(s.to_string(), t)),
),
map(alpha1, |s: Span| (s, Token::Id(s.to_string()))), map(alpha1, |s: Span| (s, Token::Id(s.to_string()))),
map(parse_par(parse_tokens), |(s, tokens)| { map(parse_par(parse_tokens), |(s, tokens)| {
(s, Token::Par(tokens)) (s, Token::Par(tokens))
...@@ -82,17 +83,20 @@ fn compute_atom<'a>(t: &mut Peekable<Iter<SpanToken<'a>>>) -> SpanExpr<'a> { ...@@ -82,17 +83,20 @@ fn compute_atom<'a>(t: &mut Peekable<Iter<SpanToken<'a>>>) -> SpanExpr<'a> {
Some((s, Token::Bool(b))) => (*s, Expr::Bool(*b)), Some((s, Token::Bool(b))) => (*s, Expr::Bool(*b)),
Some((s, Token::Id(id))) => (*s, Expr::Id(id.to_string())), Some((s, Token::Id(id))) => (*s, Expr::Id(id.to_string())),
Some((_, Token::Par(v))) => climb(&mut v.iter().peekable(), 0), Some((_, Token::Par(v))) => climb(&mut v.iter().peekable(), 0),
Some((s, Token::Op(op))) => { Some((s, Token::Call(id, vv))) => {
(*s, Expr::UnaryOp(*op, Box::new(climb(t, 4)))) //
} // assume highest precedence let v: Vec<SpanExpr> = vv
.iter()
.map(|(span, t)| climb(&mut (*t).iter().peekable(), 0))
.collect();
(*s, Expr::Call(id.to_string(), v))
}
Some((s, Token::Op(op))) => (*s, Expr::UnaryOp(*op, Box::new(climb(t, 4)))), // assume highest precedence
_ => panic!("error in compute atom"), _ => panic!("error in compute atom"),
} }
} }
fn climb<'a>( fn climb<'a>(t: &mut Peekable<Iter<SpanToken<'a>>>, min_prec: u8) -> SpanExpr<'a> {
t: &mut Peekable<Iter<SpanToken<'a>>>,
min_prec: u8,
) -> SpanExpr<'a> {
let mut result: SpanExpr = compute_atom(t); let mut result: SpanExpr = compute_atom(t);
loop { loop {
...@@ -125,35 +129,7 @@ pub fn parse_expr(i: Span) -> IResult<Span, SpanExpr> { ...@@ -125,35 +129,7 @@ pub fn parse_expr(i: Span) -> IResult<Span, SpanExpr> {
})(i) })(i)
} }
pub fn test(s: &str, v: i32) { // fn parse_if(i: Span) -> IResult<Span, SpanCmd> {
match parse_expr(Span::new(s)) {
Ok((Span { fragment: "", .. }, e)) => {
println!("{:?}", &e);
println!("eval {} {}", math_eval(&e), v);
assert_eq!(math_eval(&e), v);
}
Ok((s, t)) => println!(
"parse incomplete, \n parsed tokens \t{:?}, \n remaining \t{:?}",
t, s
),
Err(err) => println!("{:?}", err),
}
}
// helpers
fn parse_par<'a, O, F, E>(
inner: F,
) -> impl Fn(Span<'a>) -> IResult<Span<'a>, O, E>
where
F: Fn(Span<'a>) -> IResult<Span<'a>, O, E>,
E: ParseError<Span<'a>>,
{
// delimited allows us to split up the input
// cut allwos us to consume the input (and prevent backtracking)
delimited(char('('), preceded(multispace0, inner), cut(char(')')))
}
// fn parse_if<'a>(i: Span) -> IResult<Span, SpanCmd> {
// map( // map(
// preceded( // preceded(
// // here to avoid ambiguity with other names starting with `if`, if we added // // here to avoid ambiguity with other names starting with `if`, if we added
...@@ -172,6 +148,27 @@ where ...@@ -172,6 +148,27 @@ where
// )(i) // )(i)
// } // }
// helpers
fn parse_par<'a, O, F, E>(inner: F) -> impl Fn(Span<'a>) -> IResult<Span<'a>, O, E>
where
F: Fn(Span<'a>) -> IResult<Span<'a>, O, E>,
E: ParseError<Span<'a>>,
{
// delimited allows us to split up the input
// cut allwos us to consume the input (and prevent backtracking)
delimited(char('('), preceded(multispace0, inner), cut(char(')')))
}
fn parse_sem<'a, O, F, E>(inner: F) -> impl Fn(Span<'a>) -> IResult<Span<'a>, O, E>
where
F: Fn(Span<'a>) -> IResult<Span<'a>, O, E>,
E: ParseError<Span<'a>>,
{
// delimited allows us to split up the input
// cut allwos us to consume the input (and prevent backtracking)
delimited(char('{'), preceded(multispace0, inner), cut(char('}')))
}
// pub fn parse_let(i: &str) -> IResult<&str, Cmd, VerboseError<&str>> { // pub fn parse_let(i: &str) -> IResult<&str, Cmd, VerboseError<&str>> {
// context( // context(
// "let expression", // "let expression",
...@@ -243,16 +240,18 @@ pub fn parse_assign<'a>(i: Span<'a>) -> IResult<Span<'a>, Cmd<'a>> { ...@@ -243,16 +240,18 @@ pub fn parse_assign<'a>(i: Span<'a>) -> IResult<Span<'a>, Cmd<'a>> {
// )(i) // )(i)
// } // }
// pub fn parse_cmd(i: &str) -> IResult<&str, Cmd, VerboseError<&str>> { // pub fn parse_cmd<'a>(i: Span<'a>) -> IResult<Span<'a>, Cmd<'a>> {
// preceded( pub fn parse_cmd(i: Span) -> IResult<Span, Cmd> {
// multispace0, preceded(
multispace0,
parse_assign,
// alt((parse_while, parse_let, parse_if, parse_assign, parse_return)), // alt((parse_while, parse_let, parse_if, parse_assign, parse_return)),
// )(i) )(i)
// } }
// pub fn parse_block(i: &str) -> IResult<&str, Block, VerboseError<&str>> { pub fn parse_block(i: Span) -> IResult<Span, Block> {
// preceded(multispace0, s_cmd(separated_list(tag(";"), parse_cmd)))(i) preceded(multispace0, parse_sem(separated_list(tag(";"), parse_cmd)))(i)
// } }
// fn s_cmd<'a, O, F>(inner: F) -> impl Fn(&'a str) -> IResult<&'a str, O, VerboseError<&'a str>> // fn s_cmd<'a, O, F>(inner: F) -> impl Fn(&'a str) -> IResult<&'a str, O, VerboseError<&'a str>>
// where // where
...@@ -355,34 +354,6 @@ pub fn parse_assign<'a>(i: Span<'a>) -> IResult<Span<'a>, Cmd<'a>> { ...@@ -355,34 +354,6 @@ pub fn parse_assign<'a>(i: Span<'a>) -> IResult<Span<'a>, Cmd<'a>> {
// )(i) // )(i)
// } // }
// tests
fn math_eval(e: &SpanExpr) -> i32 {
match e.clone().1 {
Expr::Num(i) => i,
Expr::BinOp(op, l, r) => {
let lv = math_eval(&l);
let rv = math_eval(&r);
match op {
Op::Add => lv + rv,
Op::Sub => lv - rv,
Op::Mul => lv * rv,
Op::Div => lv / rv,
Op::Pow => lv.pow(rv as u32),
_ => unimplemented!(),
}
}
Expr::UnaryOp(op, e) => {
let e = math_eval(&e);
match op {
Op::Add => e,
Op::Sub => -e,
_ => unimplemented!(),
}
}
_ => unimplemented!(),
}
}
#[derive(Debug, Copy, Clone, PartialEq)] #[derive(Debug, Copy, Clone, PartialEq)]
enum Ass { enum Ass {
Left, Left,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment