diff --git a/examples/tmp.rs b/examples/tmp.rs index bde570e67889947cf38bbd8fb21e6c4feda3c652..3a1280cf6f9b7357cc6dbf7fe88ee1db325075a6 100644 --- a/examples/tmp.rs +++ b/examples/tmp.rs @@ -1,8 +1,24 @@ use crust::{ 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() { // test("- -1 + + 1", - -1 + 1); // rust does not allow + as a unary op (I do ;) // test("(-1-1)+(-1+3)", (-1 - 1) + (-1) + 3); @@ -12,6 +28,6 @@ fn main() { // test("1*2+3", 1 * 2 + 3); // // 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 + a(1, 2)", 1 + 2); - println!("{:?}", parse_assign(Span::new("3 = 4"))); + test("1 + (1 - 2)", 1 + (1 - 2) ); + println!("{:?}", parse_assign(Span::new("3 = a(1, 2+3)"))); } diff --git a/src/ast.rs b/src/ast.rs index f29611295a093d976ebed08940ce46e175920432..f445e1ceeb0a4b44abe3811201afc429adb00cfa 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -26,7 +26,7 @@ pub enum Expr<'a> { Bool(bool), Par(Box<SpanExpr<'a>>), Id(String), - Fn(String, Vec<SpanExpr<'a>>), + Call(String, Vec<SpanExpr<'a>>), BinOp(Op, Box<SpanExpr<'a>>, Box<SpanExpr<'a>>), UnaryOp(Op, Box<SpanExpr<'a>>), } @@ -39,8 +39,8 @@ pub enum Cmd<'a> { Let(SpanMut<'a>, String, SpanType<'a>, SpanExpr<'a>), // id = expr Assign(SpanExpr<'a>, SpanExpr<'a>), - // /// if predicate do-this, and optionally do-that) - // If(Expr, Block, Option<Block>), + // if predicate do-this, and optionally do-that) + If(SpanExpr<'a>, SpanBlock<'a>, Option<SpanBlock<'a>>), // /// while predicate do-this // While(Expr, Block), // Return(Expr), @@ -70,6 +70,7 @@ pub type SpanMut<'a> = (Span<'a>, Mutability); // } pub type SpanBlock<'a> = (Span<'a>, Vec<SpanCmd<'a>>); +pub type Block<'a> = Vec<Cmd<'a>>; #[derive(Debug, PartialEq, Clone)] pub enum Type<'a> { diff --git a/src/interpreter.rs b/src/interpreter.rs new file mode 100644 index 0000000000000000000000000000000000000000..3531dcd241e93e0319d71bc655e062e02c73c61a --- /dev/null +++ b/src/interpreter.rs @@ -0,0 +1,332 @@ +// 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 {:?}", ¶meter_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); +// } diff --git a/src/lib.rs b/src/lib.rs index b5afecafe3d0a66ea3b66ae31359b41646bb88aa..56c2ccd7d9cf7c59a13e95a1ffe8f49897afc74e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,3 +2,4 @@ pub mod ast; pub mod parse; +pub mod interpreter; diff --git a/src/parse.rs b/src/parse.rs index 95e21051bbf1d11dac5cc4da68476d24ace92ffd..66e982388379fdecd89370df9e0c0ef96c4da8c3 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -6,15 +6,15 @@ use std::slice::Iter; use nom::{ branch::alt, bytes::complete::tag, - character::complete::{alpha1, char, digit1, multispace0}, - combinator::{cut, map}, + character::complete::{alpha1, char, digit1, multispace0, multispace1}, + combinator::{cut, map, opt}, error::ParseError, multi::{many1, separated_list}, - sequence::{delimited, preceded, tuple}, + sequence::{delimited, preceded, terminated, tuple}, 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)> { map(digit1, |digit_str: Span| { @@ -42,7 +42,7 @@ pub enum Token<'a> { Num(i32), Bool(bool), Id(String), - Fn(String, Vec<(Span<'a>, Vec<SpanToken<'a>>)>), + Call(String, Vec<(Span<'a>, Vec<SpanToken<'a>>)>), Par(Vec<SpanToken<'a>>), Op(Op), } @@ -54,9 +54,10 @@ fn parse_terminal(i: Span) -> IResult<Span, SpanToken> { map(parse_i32, |(s, v)| (s, Token::Num(v))), map(tag("true"), |s| (s, Token::Bool(true))), map(tag("false"), |s| (s, Token::Bool(false))), - map(tuple((alpha1, parse_par(separated_list(char(','), parse_tokens)))), |(s, t)| { - (s, Token::Fn(s.to_string(), t)) - }), + map( + 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(parse_par(parse_tokens), |(s, tokens)| { (s, Token::Par(tokens)) @@ -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::Id(id))) => (*s, Expr::Id(id.to_string())), Some((_, Token::Par(v))) => climb(&mut v.iter().peekable(), 0), - Some((s, Token::Op(op))) => { - (*s, Expr::UnaryOp(*op, Box::new(climb(t, 4)))) - } // assume highest precedence + Some((s, Token::Call(id, vv))) => { + // + 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"), } } -fn climb<'a>( - t: &mut Peekable<Iter<SpanToken<'a>>>, - min_prec: u8, -) -> SpanExpr<'a> { +fn climb<'a>(t: &mut Peekable<Iter<SpanToken<'a>>>, min_prec: u8) -> SpanExpr<'a> { let mut result: SpanExpr = compute_atom(t); loop { @@ -125,35 +129,7 @@ pub fn parse_expr(i: Span) -> IResult<Span, SpanExpr> { })(i) } -pub fn test(s: &str, v: i32) { - 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> { +// fn parse_if(i: Span) -> IResult<Span, SpanCmd> { // map( // preceded( // // here to avoid ambiguity with other names starting with `if`, if we added @@ -172,6 +148,27 @@ where // )(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>> { // context( // "let expression", @@ -243,16 +240,18 @@ pub fn parse_assign<'a>(i: Span<'a>) -> IResult<Span<'a>, Cmd<'a>> { // )(i) // } -// pub fn parse_cmd(i: &str) -> IResult<&str, Cmd, VerboseError<&str>> { -// preceded( -// multispace0, -// alt((parse_while, parse_let, parse_if, parse_assign, parse_return)), -// )(i) -// } +// pub fn parse_cmd<'a>(i: Span<'a>) -> IResult<Span<'a>, Cmd<'a>> { +pub fn parse_cmd(i: Span) -> IResult<Span, Cmd> { + preceded( + multispace0, + parse_assign, + // alt((parse_while, parse_let, parse_if, parse_assign, parse_return)), + )(i) +} -// pub fn parse_block(i: &str) -> IResult<&str, Block, VerboseError<&str>> { -// preceded(multispace0, s_cmd(separated_list(tag(";"), parse_cmd)))(i) -// } +pub fn parse_block(i: Span) -> IResult<Span, Block> { + 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>> // where @@ -355,34 +354,6 @@ pub fn parse_assign<'a>(i: Span<'a>) -> IResult<Span<'a>, Cmd<'a>> { // )(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)] enum Ass { Left,