From be36987625884e170263b1f06cb029aff3f28414 Mon Sep 17 00:00:00 2001
From: Per Lindgren <per.lindgren@ltu.se>
Date: Fri, 20 Sep 2019 20:25:50 +0200
Subject: [PATCH] wip
---
examples/tmp.rs | 22 ++-
src/ast.rs | 7 +-
src/interpreter.rs | 332 +++++++++++++++++++++++++++++++++++++++++++++
src/lib.rs | 1 +
src/parse.rs | 133 +++++++-----------
5 files changed, 408 insertions(+), 87 deletions(-)
create mode 100644 src/interpreter.rs
diff --git a/examples/tmp.rs b/examples/tmp.rs
index bde570e..3a1280c 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 f296112..f445e1c 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 0000000..3531dcd
--- /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 b5afeca..56c2ccd 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 95e2105..66e9823 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,
--
GitLab