diff --git a/Cargo.lock b/Cargo.lock index 04a459946e737bf6b02e4d92d8aaeb08e62cc608..b11e624f90930462f943132891cb93b6fd7154b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -387,9 +387,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "proc-macro2" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c" +checksum = "e4b93dba1818d32e781f9d008edd577bab215e83ef50e8a1ddf1ad301b19a09f" dependencies = [ "unicode-xid", ] diff --git a/examples/borrow.rs b/examples/borrow.rs index 7e40ef0b4b7602100030e39753b6e14c2f36b25a..fe386e9b3542824299748f9b7a75ec2b6f81df62 100644 --- a/examples/borrow.rs +++ b/examples/borrow.rs @@ -1,6 +1,11 @@ -fn f(a: &i32, b: &mut bool) {} +fn f(x: &i32, y: &mut bool) { + *y = true; + let c = *x; + // println!("{}", c); +} fn main() { let mut a = 1; let mut b = false; - f(&a, &mut b) + f(&a, &mut b); + // println!("{}", b); } diff --git a/examples/borrow2.rs b/examples/borrow2.rs index f84101eb46b865ce539d4791beae9ec10f265342..f99b6d5d921895510c27eb954e2386a448e89a95 100644 --- a/examples/borrow2.rs +++ b/examples/borrow2.rs @@ -1,5 +1,22 @@ -fn f(a: &i32, b: &mut i32) {} +// parameter a is of type &i32 +fn f(a: &i32, b: &mut bool) { + *b = true; + let c = *a; + //println!("{}", c); +} fn main() { let mut a = 1; - f(&mut a, &mut a) + let mut b = false; + // argument &a, is bound to parameter a in function + f(&a, &mut b); + // println!("{}", b); } + +// here we don't want to shadow a in main by the +// local a in f. + +// this is can be solved by "alpha renaming" +// in a function f(x, ...) = x ... +// x can be "renamed" to a new name y +// by changing all appearances of x to y +// (as long as y don't appear in f) \ No newline at end of file diff --git a/examples/borrow_err.rs b/examples/borrow_err.rs index 63157b53b2008d714818be0fa0c16f510968c76c..b540df16dcc3eb97b250678e64095a29088d3b6b 100644 --- a/examples/borrow_err.rs +++ b/examples/borrow_err.rs @@ -1,7 +1,10 @@ +#[derive(Debug, Copy, Clone)] +struct A {} fn main() { - let mut a = 5; + let mut a = A {}; let b = &mut a; //let q = *b; - let c = a; + let c = *b; println!("b {:?}", *b); + let d = a; } diff --git a/examples/borrow_err2.rs b/examples/borrow_err2.rs new file mode 100644 index 0000000000000000000000000000000000000000..a732ba2bb48fc69ee4472c548caa068db1e6e03f --- /dev/null +++ b/examples/borrow_err2.rs @@ -0,0 +1,6 @@ +fn main() { + let mut a = 5; + let b = &a; + a = 4; + let d = *b; +} diff --git a/examples/deref.rs b/examples/deref.rs new file mode 100644 index 0000000000000000000000000000000000000000..08e49d742defbe0e546ab2560bfe26a36d2bb5d3 --- /dev/null +++ b/examples/deref.rs @@ -0,0 +1,4 @@ +fn main() { + let a = 1; + let b = *&a; +} diff --git a/examples/deref2.rs b/examples/deref2.rs new file mode 100644 index 0000000000000000000000000000000000000000..5a038e84f6afae86fd3bc875597092a1f83d1bc9 --- /dev/null +++ b/examples/deref2.rs @@ -0,0 +1,5 @@ +fn main() { + let a = 1; + let b = &a; + let c = *b; +} diff --git a/examples/deref3.rs b/examples/deref3.rs new file mode 100644 index 0000000000000000000000000000000000000000..727fe27379039309678514e80d8c5bd31f7c55b4 --- /dev/null +++ b/examples/deref3.rs @@ -0,0 +1,8 @@ +fn main() { + let mut a = 1; + let mut b = &a; + let c = &mut b; + + let d = *c; + let e = *d; +} diff --git a/examples/deref_assign3.rs b/examples/deref_assign3.rs index db7311ea1875d4ddad5e6bef83ded2949e084d1a..a7ee5030565eca454c359a334eef0ed546f73b7e 100644 --- a/examples/deref_assign3.rs +++ b/examples/deref_assign3.rs @@ -1,10 +1,9 @@ -fn main() -> i32 { +fn main() { let mut a = 7; let mut aa = 8; - let mut b = &a; - let c = &b; + let mut b = &mut a; + let c = &mut b; - *c = &aa; + *c = &mut aa; *b = 99; - aa } diff --git a/src/borrow.rs b/src/borrow.rs index 5b4781cb06186ff498e15eeaffaac4c9198771c6..d0e990af6b854921198d365ca8265e53084c8a73 100644 --- a/src/borrow.rs +++ b/src/borrow.rs @@ -1,568 +1,370 @@ -use std::io::Write; +// boorrow -use env_logger::Builder; -use log::{trace, LevelFilter}; -use std::convert::From; +use std::collections::{HashMap, VecDeque}; use crate::ast::*; -use crate::bc_env::{Bc, BcEnv, Error, IdBc}; -use crate::env::{new_fn_env, new_type_env, FnEnv, TypeEnv}; +use crate::env::*; + +type Id = String; + +#[derive(Debug, Clone)] +enum Val { + Num(i32), + Bool(bool), + Uninitialized, + Unit, + Ref(Id), + RefMut(Id), +} -// type check +type IdVal = HashMap<Id, (bool, Val)>; -fn bc_expr( - e: &Expr, - fn_env: &FnEnv, - type_env: &TypeEnv, - bc_env: &mut BcEnv, -) -> Result<Type, Error> { - use Expr::*; - println!("expr_type {}", e); - println!("var_env {:?}", bc_env); +#[derive(Debug)] +struct Mem(VecDeque<IdVal>); - match e { - // Num(_) => Ok(Type::I32), - // Bool(_) => Ok(Type::Bool), - // Infix(l, op, r) => { - // let lt = expr_type(l, fn_env, type_env, var_env)?; - // let rt = expr_type(r, fn_env, type_env, var_env)?; - - // let lt = strip_mut(lt); - // let rt = strip_mut(rt); - - // use Op::*; - // match op { - // // Arithmetic and Boolen - // Add | Mul | Div | Sub | And | Or => { - // // check if op and args are compliant - // let opt = op.get_type(); - // if lt == opt && rt == opt { - // Ok(opt) - // } else { - // Err(format!( - // "Expected type {}, found, left {}: {}, {:?} right {}: {}, {:?}", - // opt, l, lt, lt, r, rt, rt - // )) - // } - // } - // // Equality - // Eq | Neq => { - // // check if args are of same type - // if lt == rt { - // Ok(Type::Bool) - // } else { - // Err(format!( - // "Comparison requires operands of same type, left {}, right {}", - // lt, rt - // )) - // } - // } - // // Comparison - // Less | Greater | LessEq | GreaterEq => { - // if lt == Type::I32 && rt == Type::I32 { - // // check if args are of i32 - // Ok(Type::Bool) - // } else { - // Err(format!( - // "Comparison requires operands of same type, left {}, right {}", - // lt, rt - // )) - // } - // } - // _ => panic!("ICE on {}", e), - // } - // } - - // Prefix(op, r) => { - // let rt = expr_type(r, fn_env, type_env, var_env)?; - // let opt = op.get_type(); - - // // check if both of same type - // if rt == opt { - // Ok(opt) - // } else { - // Err(format!("op {} rt {}", opt, rt)) - // } - // } - - // Call(s, args) => { - // trace!("call {} with {}", s, args); - - // let arg_t: Vec<Type> = args - // .clone() - // .0 - // .into_iter() - // .map(|e| expr_type(&*e, fn_env, type_env, var_env)) - // .collect::<Result<_, _>>()?; - - // trace!("arg types {:?}", arg_t); - // let f = match fn_env.get(s.as_str()) { - // Some(f) => f, - // None => Err(format!("{} not found", s))?, - // }; - - // let par_t: Vec<Type> = (f.params.0.clone()) - // .into_iter() - // .map(|p| From::from(&p)) - // .collect(); - - // trace!( - // "fn to call {} with params {} and types {:?}", - // f, - // f.params, - // par_t - // ); - - // if arg_t == par_t { - // Ok(f.result.clone()) - // } else { - // Err(format!( - // "arguments types {:?} does not match parameter types {:?}", - // arg_t, par_t - // )) - // } - // } - - // Id(id) => match var_env.get(id.to_string()) { - // Some(t) => Ok(t.clone()), - // None => Err(format!("variable not found {}", id)), - // }, - - // As(_e, _t) => unimplemented!("here we implement explicit type cast"), - - // // Convert Expr::Ref to Type::Ref - // Ref(ref_e) => { - // let t = expr_type(ref_e, fn_env, type_env, var_env)?; - // trace!("ref_e {}, t {}", ref_e, t); - // let t = match t { - // Type::Mut(t) => t.clone(), - // t => Box::new(t), - // }; - // Ok(Type::Ref(t)) - // } - - // // Convert Expr::Mut to Type::Mut - // RefMut(ref_mut_e) => { - // let t = expr_type(ref_mut_e, fn_env, type_env, var_env)?; - // match t { - // Type::Mut(_) => Ok(Type::Ref(Box::new(t))), - // _ => Err(format!("{} is not mutable in {}", t, ref_mut_e)), - // } - // } - - // DeRef(deref_e) => { - // let t = expr_type(deref_e, fn_env, type_env, var_env)?; - // trace!("deref_t {}", &t); - // let t = strip_mut(t); - // trace!("strip deref_t {}", &t); - // match t { - // Type::Ref(dt) => Ok(*dt), - // _ => Err(format!("cannot deref {} of type {}", e, t)), - // } - // } - - // Block(b) => check_stmts(b, fn_env, type_env, var_env), - - // Stmt(s) => check_stmt(s, fn_env, type_env, var_env), - _ => unimplemented!(), +impl Mem { + fn new() -> Self { + Mem(VecDeque::new()) } -} -// fn lexpr_type<'a>( -// e: &Expr, -// fn_env: &FnEnv, -// type_env: &TypeEnv, -// var_env: &'a mut VarEnv, -// ) -> Result<&'a mut Type, Error> { -// use Expr::*; -// trace!("expr_type {}", e); -// trace!("var_env {:?}", var_env); - -// match e { -// Id(id) => match var_env.get_mut(id.to_string()) { -// Some(t) => Ok(t), -// None => Err(format!("variable not found {}", id)), -// }, - -// DeRef(deref_e) => { -// let t = lexpr_type(deref_e, fn_env, type_env, var_env)?; -// trace!("deref_t {}", &t); - -// // strip mut -// let t = match t { -// Type::Mut(t) => t, -// _ => t, -// }; -// trace!("strip deref_t {}", t); -// match t { -// Type::Ref(dt) => Ok(dt), -// _ => Err(format!("cannot deref {} of type {}", e, t)), -// } -// } -// _ => Err(format!("Illegal left hand expression {}", e)), -// } -// } - -// strip a "mut T" to a T -fn strip_mut(t: Type) -> Type { - match t { - Type::Mut(t) => *t, - _ => t, + fn get(&self, id: String) -> Option<&Val> { + self.0.iter().find_map(|hm| match hm.get(id.as_str()) { + Some((_, v)) => Some(v), // always ok to go from mut to non mut + _ => None, + }) } -} -// determine if a type is declared recursively -fn is_known(t: &Type) -> bool { - use Type::*; - match t { - Type::Unknown => false, - Unit | Bool | I32 => true, - Mut(t) | Ref(t) => is_known(t), - _ => panic!("ICE is_known"), + fn get_mut(&mut self, id: String) -> Option<&mut Val> { + self.0 + .iter_mut() + .find_map(|hm| match hm.get_mut(id.as_str()) { + Some((true, v)) => Some(v), // a mut reference + Some((_, v)) => { + match v { + Val::Uninitialized => Some(v), // an uninitialized + Val::RefMut(_) => { + // a ref mut + println!("get &mut {:?}", v); + Some(v) + } + _ => panic!("cannot access as mutable"), + } + } + _ => None, + }) } -} -pub fn bc_stmt( - s: &Stmt, - fn_env: &FnEnv, - type_env: &TypeEnv, - bc_env: &mut BcEnv, -) -> Result<(), Error> { - use Stmt::*; - // trace!("stmt: {}", s); - // match s { - // Stmt::Block(b) => check_stmts(b, fn_env, type_env, var_env), - - // Expr(e) => expr_type(&*e, fn_env, type_env, var_env), - - // Let(var_id, is_mut, ot, oe) => { - // let t: Type = match (ot, oe) { - // (Some(t), Some(e)) => { - // let e_type = expr_type(&*e, fn_env, type_env, var_env)?; - // let e_type = strip_mut(e_type); - // match strip_mut(t.clone()) == e_type { - // true => t.clone(), - // false => { - // trace!("e {}", e); - // Err(format!("incompatible types, {} <> {}", t, e_type))? - // } - // } - // } - // (None, Some(e)) => { - // let e_type = strip_mut(expr_type(&*e, fn_env, type_env, var_env)?); - // match is_known(&e_type) { - // true => e_type, - // _ => Err("reference to unknown type".to_string())?, - // } - // } - // (Some(t), None) => t.clone(), - // _ => Type::Unknown, - // }; - // let t = match is_mut { - // true => Type::Mut(Box::new(t)), - // false => t, - // }; - // var_env.new_id(var_id.clone(), t); - // trace!("var_env {:?}", var_env); - // Ok(Type::Unit) - // } - - // Assign(lh, e) => { - // trace!("assign"); - - // let e_type = expr_type(&*e, fn_env, type_env, var_env)?; - // trace!("e_type = {}", &e_type); - // let e_type = strip_mut(e_type); - // trace!("e_type stripped = {}", &e_type); - - // trace!("lh expr = {:?}", lh); - - // let lh_type = lexpr_type(lh, fn_env, type_env, var_env)?; - // trace!("lh_type {}", lh_type); - - // if match lh_type { - // Type::Unknown => { - // trace!("assign to unknown"); - // *lh_type = e_type.clone(); - // true - // } - // Type::Mut(t) => match **t { - // Type::Unknown => { - // trace!("assign to `mut Unknown`"); - // *t = Box::new(e_type.clone()); - // true - // } - // _ => **t == e_type, - // }, - - // _ => Err(format!("assignment to immutable"))?, - // } { - // Ok(Type::Unit) - // } else { - // Err(format!("cannot assign {} = {}", &lh_type, e_type)) - // } - // } - - // While(e, block) => match expr_type(&*e, fn_env, type_env, var_env) { - // Ok(Type::Bool) => { - // let _ = check_stmts(&block, fn_env, type_env, var_env)?; - // Ok(Type::Unit) // a while statement is of unit type; - // } - // _ => Err("Condition not Boolean".to_string()), - // }, - - // If(e, then, o_else) => match expr_type(&*e, fn_env, type_env, var_env)? { - // Type::Bool => { - // // The condition is of Bool type - // let then_type = check_stmts(&then, fn_env, type_env, var_env)?; - // trace!("then type {}", then_type); - // match o_else { - // None => Ok(then_type), // type of the arm - // Some(else_stmts) => { - // let else_type = check_stmts(&else_stmts, fn_env, type_env, var_env)?; - // trace!("else type {}", else_type); - - // match then_type == else_type { - // true => Ok(then_type), // same type of both arms - // false => { - // trace!("error-----"); - // Err(format!( - // "'then' arm :{} does not match 'else' arm :{}", - // then_type, else_type - // )) - // } - // } - // } - // } - // } - // _ => Err("Condition not Boolean".to_string()), - // }, - // Semi => Ok(Type::Unit), - // } - Ok(()) -} + fn new_id(&mut self, id: String, is_mut: bool) { + let hm = self.0.front_mut().unwrap(); + println!("insert id {:?}, in scope {:?}", id, hm); -pub fn bc_stmts( - stmts: &Stmts, - fn_env: &FnEnv, - type_env: &TypeEnv, - bc_env: &mut BcEnv, -) -> Result<(), Error> { - bc_env.push_empty_scope(); - - let t = stmts - .stmts - .iter() - .try_fold((), |_, s| bc_stmt(s, fn_env, type_env, bc_env))?; - - bc_env.pop_scope(); - // if stmts.trailing_semi { - // Ok(()) - // } else { - // Ok(t.clone()) - // } - - Ok(()) -} + hm.insert(id, (is_mut, Val::Uninitialized)); + } -pub fn build_env(p: &Program) -> (FnEnv, TypeEnv) { - let fn_env = new_fn_env(&p.fn_decls); - let type_env = new_type_env(&p.type_decls); + fn update(&mut self, id: String, val: Val) { + // println!("before mem {:?}", self); + match self.get_mut(id.clone()) { + Some(v_ref) => { + println!("found"); + *v_ref = val; + } + None => { + panic!("variable not found"); + } + }; + // println!("after mem {:?}", self); + } - (fn_env, type_env) -} + fn push_empty_scope(&mut self) { + self.0.push_front(HashMap::new()); + } -// pub fn dump_env(fn_env: &FnEnv, type_env: &TypeEnv) { -// trace!("fn_env {:?}", fn_env); -// trace!("type_env {:?}", type_env); -// } + fn push_param_scope(&mut self, args: IdVal) { + self.0.push_front(args) + } + + fn pop_scope(&mut self) { + self.0.pop_front(); + } +} -// check a whole Program -pub fn bc_prog(p: &Program) -> Result<(), Error> { - let (fn_env, type_env) = build_env(&p); +fn eval_infix(l: Val, op: &Op, r: Val) -> Val { + match (l, op, r) { + // Operations on Num + (Val::Num(l), op, Val::Num(r)) => match op { + // arithmetic operations on Num + Op::Add => Val::Num(l + r), + Op::Sub => Val::Num(l - r), + Op::Mul => Val::Num(l * r), + Op::Div => Val::Num(l / r), + // comparisons + Op::Eq => Val::Bool(l == r), + Op::Neq => Val::Bool(l != r), + Op::Less => Val::Bool(l < r), + Op::LessEq => Val::Bool(l <= r), + Op::Greater => Val::Bool(l > r), + Op::GreaterEq => Val::Bool(l >= r), + _ => panic!("expression evaluation error"), + }, + // boolean + (Val::Bool(l), op, Val::Bool(r)) => Val::Bool(match op { + Op::And => l && r, + Op::Or => l || r, + Op::Eq => l == r, + _ => panic!("expression evaluation error"), + }), + _ => panic!("expression evaluation error"), + } +} - println!("Input program \n{}", &p); +fn eval_prefix(op: &Op, r: Val) -> Val { + match (op, r) { + // Operations on Num + (op, Val::Num(r)) => match op { + // arithmetic operations on Num + Op::Sub => Val::Num(-r), + Op::Add => Val::Num(r), + _ => panic!("expression evaluation error"), + }, + // boolean + (op, Val::Bool(r)) => match op { + Op::Not => Val::Bool(!r), + _ => panic!("expression evaluation error"), + }, + // Unint + _ => panic!("expression evaluation error"), + } +} - for fd in p.fn_decls.iter() { - println!("check function\n{}", fd); - println!("ast\n{:?}", fd); +fn eval_expr(e: &Expr, m: &mut Mem, fn_env: &FnEnv) -> Val { + println!("eval_expr {}", e); + match e { + Expr::Num(i) => Val::Num(*i), + Expr::Bool(b) => Val::Bool(*b), + // Expr::As(_, _) => {} + Expr::Infix(l, op, r) => { + let l = eval_expr(l, m, fn_env); + let r = eval_expr(r, m, fn_env); + eval_infix(l, op, r) + } + Expr::Prefix(op, r) => { + let r = eval_expr(r, m, fn_env); + eval_prefix(op, r) + } + Expr::Id(id) => match m.get(id.to_owned()) { + Some(v) => v.clone(), + None => panic!("identifier not found {:?}", id), + }, + Expr::Ref(e) => match &**e { + Expr::Id(id) => match m.get(id.to_owned()) { + Some(_) => Val::Ref(id.to_owned()), + None => panic!("identifier not found {:?}", id), + }, + _ => panic!("ref of non identifier"), + }, + Expr::RefMut(e) => match &**e { + Expr::Id(id) => match m.get(id.to_owned()) { + Some(_) => Val::RefMut(id.to_owned()), + None => panic!("identifier not found {:?}", id), + }, + _ => panic!("ref on non identifier"), + }, + Expr::DeRef(e) => { + println!("deref e {:?}", e); + + let ev = eval_expr(e, m, fn_env); + println!("ev {:?}", ev); + + match ev { + Val::Ref(id) => eval_expr(&Expr::Id(id), m, fn_env), + Val::RefMut(id) => eval_expr(&Expr::Id(id), m, fn_env), + _ => panic!("cannot deref"), + } + } + Expr::Call(id, ee) => { + println!("call {}", id); + let args: Vec<Val> = ee.0.iter().map(|e| eval_expr(e, m, fn_env)).collect(); - let mut bc_env = BcEnv::new(); + eval_fn(id, &args, m, fn_env) + } + _ => { + unimplemented!(); + } + } +} - // build a scope for the arguments - let mut arg_ty = IdBc::new(); +fn eval_left_expr(e: &Expr, m: &Mem, fn_env: &FnEnv) -> Id { + println!("eval_left_expr {}", e); + match e { + Expr::Id(id) => id.to_owned(), + + Expr::DeRef(e) => { + println!("eval_left deref e {:?}", e); + + let ev = eval_left_expr(e, m, fn_env); + println!("eval_left {:?}", ev); + + match m.get(ev) { + Some(Val::Ref(id)) => { + println!("Ref id {}", id); + id.clone() + } + Some(Val::RefMut(id)) => { + println!("RefMut id {}", id); + id.clone() + } + _ => panic!("deref failed"), + } + } + _ => panic!("illegal left hand expression"), + } +} - for Param { is_mut, id, ty } in fd.params.0.iter() { - let ty = match *is_mut { - true => Bc::Unique, - _ => Bc::Shared, - }; - arg_ty.insert(id.to_owned(), ty); +fn eval_stmts(stmts: &Stmts, m: &mut Mem, fn_env: &FnEnv) -> Val { + let ss = &stmts.stmts; + + m.push_empty_scope(); + + let mut stmt_val = Val::Unit; + + for s in ss { + println!("s {}", s); + println!("m {:?}", m); + stmt_val = match s { + // Id, is_mut, Option<Type>, Option<Box<Expr> + Stmt::Let(id, is_mut, _, o_expr) => { + println!("let"); + m.new_id(id.to_owned(), *is_mut); + match o_expr { + Some(e) => { + let r = eval_expr(e, m, fn_env); + println!("r {:?}", r); + m.update(id.to_owned(), r); + Val::Unit + } + _ => Val::Unit, + } + } + Stmt::Assign(ev, e) => { + println!("assign"); + match &**ev { + Expr::Id(id) => { + let v = eval_expr(e, m, fn_env); + m.update(id.to_owned(), v) + } + _ => { + let lv = eval_left_expr(ev, m, fn_env); + println!("lv {:?}", lv); + let v = eval_expr(e, m, fn_env); + m.update(lv, v) + } + }; + Val::Unit + } + Stmt::While(e, while_block) => { + println!("while"); + while match eval_expr(e, m, fn_env) { + Val::Bool(b) => b, + _ => panic!("non boolean condition"), + } { + eval_stmts(while_block, m, fn_env); + } + Val::Unit + } + Stmt::If(e, then_block, op_else_block) => { + println!("if"); + // println!("scope before {}", m); + match (eval_expr(e, m, fn_env), op_else_block) { + (Val::Bool(true), _) => eval_stmts(then_block, m, fn_env), + (Val::Bool(false), Some(else_block)) => eval_stmts(else_block, m, fn_env), + (Val::Bool(_), _) => Val::Uninitialized, // this should never happen if value used + _ => panic!("non boolean condition"), + } + } + Stmt::Expr(e) => { + println!("expr"); + eval_expr(e, m, fn_env) + } + Stmt::Block(block) => { + println!("block"); + eval_stmts(block, m, fn_env) + } + Stmt::Semi => Val::Unit, } + } + m.pop_scope(); + if stmts.trailing_semi { + Val::Unit + } else { + println!("statements with return value {:?}", stmt_val); + stmt_val + } +} - // var_env.push_param_scope(arg_ty); +fn eval_fn(id: &str, args: &Vec<Val>, m: &mut Mem, fn_env: &FnEnv) -> Val { + if let Some(fn_decl) = fn_env.get(id) { + println!("f id {:?}, {:?}", id, fn_decl.params); + + let p_id: &Vec<(bool, String)> = &fn_decl + .params + .0 + .iter() + .map(|param| (param.is_mut, param.id.to_owned())) + .collect(); + + let p_id_arg: Vec<(&(bool, String), &Val)> = p_id.iter().zip(args).collect(); + let p_id_arg: IdVal = p_id_arg + .into_iter() + .map(|(s, v)| (s.1.clone(), (s.0, v.clone()))) + .collect(); + + println!("args {:?}", args); + println!("p_id_arg {:?}", &p_id_arg); + + m.push_param_scope(p_id_arg); + let ret = eval_stmts(&fn_decl.body, m, fn_env); + println!("mem {:?}, ret {:?}", m, ret); + m.pop_scope(); + ret + } else { + panic!("function not found"); + } +} - // let stmt_type = check_stmts(&fd.body, &fn_env, &type_env, &mut var_env); - // trace!("result {}: {} {:?}", &fd.id, &fd.result, &stmt_type); +pub fn eval_prog(file_name: &str) { + let p = crate::read_file::parse(file_name); + println!("prog \n{}", p); - // let stmt_type = strip_mut(stmt_type?); + let fn_env = new_fn_env(&p.fn_decls); + let args: Vec<Val> = Vec::new(); + let mut m = Mem::new(); - // if stmt_type != fd.result { - // Err(format!( - // "return type {} does not match statements type {}", - // fd.result, stmt_type - // ))?; - // } - } - Ok(()) + eval_fn("main", &args, &mut m, &fn_env); } -// unit test - -// #[test] -// fn test_stmts() { -// use crate::grammar::*; -// use crate::*; -// // use Type::*; - -// // setup environment -// let p = ProgramParser::new().parse(prog1!()).unwrap(); -// let fn_env = new_fn_env(&p.fn_decls); -// let type_env = new_type_env(&p.type_decls); -// let mut var_env = VarEnv::new(); - -// trace!("{}", &p); - -// let b = fn_env.get(&"b").unwrap(); - -// let body = &b.body; -// trace!("{}", &body); - -// trace!("{:?}", check_stmts(body, &fn_env, &type_env, &mut var_env)); -// } - -// #[test] -// fn test_expr_type() { -// use crate::grammar::*; -// use crate::*; -// use Type::*; - -// // setup environment -// let i = prog1!(); -// println!("{}", i); -// let p = ProgramParser::new().parse(prog1!()).unwrap(); -// let fn_env = new_fn_env(&p.fn_decls); -// let type_env = new_type_env(&p.type_decls); -// let mut var_env = VarEnv::new(); -// var_env.push_empty_scope(); - -// // // some test variables in scope -// var_env.new_id("i".to_string(), I32); // let i : i32 ... -// var_env.new_id("j".to_string(), Unknown); // let i ... - -// println!("p {}", p); - -// // type of number -// assert_eq!( -// expr_type(&Expr::Num(1), &fn_env, &type_env, &mut var_env), -// Ok(I32) -// ); - -// // type of variables - -// // not found -// assert!(expr_type(&Expr::Id("a".to_string()), &fn_env, &type_env, &mut var_env).is_err()); - -// // let i: i32 ... -// assert_eq!( -// expr_type(&Expr::Id("i".to_string()), &fn_env, &type_env, &mut var_env), -// Ok(I32) -// ); - -// // let j ... (has no type yet) -// assert_eq!( -// expr_type(&Expr::Id("j".to_string()), &fn_env, &type_env, &mut var_env), -// Ok(Unknown) -// ); - -// // // let n: A ... -// // assert_eq!( -// // expr_type(&Expr::Id("n".to_string()), &fn_env, &type_env, &var_env), -// // Ok(Named("A".to_string())) -// // ); - -// // type of arithmetic operation (for now just i32) -// assert_eq!( -// expr_type( -// &*ExprParser::new().parse("1 + 2 - 5").unwrap(), -// &fn_env, -// &type_env, -// &mut var_env -// ), -// Ok(I32) -// ); - -// // type of arithmetic unary operation (for now just i32) -// assert_eq!( -// expr_type( -// &*ExprParser::new().parse("- 5").unwrap(), -// &fn_env, -// &type_env, -// &mut var_env -// ), -// Ok(I32) -// ); - -// // call, with check, ok -// assert_eq!( -// expr_type( -// &*ExprParser::new().parse("b(1)").unwrap(), -// &fn_env, -// &type_env, -// &mut var_env -// ), -// Ok(I32) -// ); - -// // call, with check, ok (i: i32) -// assert_eq!( -// expr_type( -// &*ExprParser::new().parse("b(i)").unwrap(), -// &fn_env, -// &type_env, -// &mut var_env -// ), -// Ok(I32) -// ); - -// // call, with check, error wrong number args -// assert!(expr_type( -// &*ExprParser::new().parse("b(1, 2)").unwrap(), -// &fn_env, -// &type_env, -// &mut var_env -// ) -// .is_err()); - -// // call, with check, error type of arg -// assert!(expr_type( -// &*ExprParser::new().parse("b(true)").unwrap(), -// &fn_env, -// &type_env, -// &mut var_env -// ) -// .is_err()); - -// // call, with check, ok (i: i32) -// assert_eq!( -// expr_type( -// &*ExprParser::new().parse("c(n)").unwrap(), -// &fn_env, -// &type_env, -// &var_env -// ), -// Ok(Unit) -// ); - -// TODO, ref/ref mut/deref -// } +#[test] +fn test_deref() { + let mut m: Mem = Mem::new(); + let mut hm = IdVal::new(); + + hm.insert("a".to_string(), (false, Val::Num(7))); + hm.insert("b".to_string(), (false, Val::Ref("a".to_string()))); + hm.insert("c".to_string(), (false, Val::Ref("b".to_string()))); + m.push_param_scope(hm); + println!("mem {:?}", m); + let e: Expr = Expr::Id("a".to_string()); + let v = eval_expr(&e, &mut m, &FnEnv::new()); + println!("v {:?}", v); + + let e: Expr = Expr::DeRef(Box::new(Expr::Id("b".to_string()))); + let v = eval_expr(&e, &mut m, &FnEnv::new()); + println!("v {:?}", v); + + let e: Expr = Expr::DeRef(Box::new(Expr::Id("c".to_string()))); + let v = eval_expr(&e, &mut m, &FnEnv::new()); + println!("v {:?}", v); + + let e: Expr = Expr::DeRef(Box::new(Expr::DeRef(Box::new(Expr::Id("c".to_string()))))); + let v = eval_expr(&e, &mut m, &FnEnv::new()); + println!("v {:?}", v); +} diff --git a/src/check.rs b/src/check.rs index f8532f716b007ce601a6d32bb183020f36bc2ab3..8dfed9f52fe1f27b88be24b18fa7113435d3ddb6 100644 --- a/src/check.rs +++ b/src/check.rs @@ -5,7 +5,7 @@ use log::{trace, LevelFilter}; use std::convert::From; use crate::ast::*; -use crate::env::{new_fn_env, new_type_env, Borrow, Error, FnEnv, IdType, TypeEnv, VarEnv}; +use crate::env::{new_fn_env, new_type_env, Bc, Error, FnEnv, IdType, TypeEnv, VarEnv}; // type check @@ -447,7 +447,7 @@ pub fn check(p: &Program) -> Result<(), Error> { true => Type::Mut(Box::new(ty.clone())), _ => ty.clone(), }; - arg_ty.insert(id.to_owned(), (Borrow::Free, ty)); + arg_ty.insert(id.to_owned(), (Bc::Free, ty)); } var_env.push_param_scope(arg_ty); diff --git a/src/env.rs b/src/env.rs index 2539edd67ad95524870c3484b0494085d2d3c7ef..6d154c7f9b86d533e824ed57085b707b2cd9d2a1 100644 --- a/src/env.rs +++ b/src/env.rs @@ -23,7 +23,7 @@ pub fn new_fn_env(v: &Vec<FnDecl>) -> FnEnv { } #[derive(Debug, PartialEq)] -pub enum Borrow { +pub enum Bc { Free, // or maybe owned Unique, Shared(Vec<String>), @@ -32,7 +32,7 @@ pub enum Borrow { pub type Address = i32; type Scope = i32; -pub type IdType = HashMap<Id, (Borrow, Type)>; +pub type IdType = HashMap<Id, (Bc, Type)>; #[derive(Debug)] pub struct VarEnv { env: VecDeque<IdType>, @@ -45,7 +45,7 @@ impl VarEnv { } } - pub fn get(&self, id: String) -> Option<(Scope, &(Borrow, Type))> { + pub fn get(&self, id: String) -> Option<(Scope, &(Bc, Type))> { self.env.iter().enumerate().find_map(|(scope, hm)| { hm.get(id.as_str()) .map(|t| ((self.env.len() - scope) as Scope, t)) @@ -56,7 +56,7 @@ impl VarEnv { self.get(id).map(|(s, t)| (s, &t.1)) } - pub fn get_mut(&mut self, id: String) -> Option<&mut (Borrow, Type)> { + pub fn get_mut(&mut self, id: String) -> Option<&mut (Bc, Type)> { self.env.iter_mut().find_map(|hm| hm.get_mut(id.as_str())) } @@ -68,7 +68,7 @@ impl VarEnv { let hm = self.env.front_mut().unwrap(); println!("insert id {:?}, in scope {:?}", &id, hm); - hm.insert(id, (Borrow::Free, ty)); + hm.insert(id, (Bc::Free, ty)); } pub fn update(&mut self, id: String, ty: Type) -> Result<(), Error> { diff --git a/src/grammar.lalrpop b/src/grammar.lalrpop index 9ec3c9f4617c4099b6f8ab30d6d2b8a386fcf547..f5f0e8357da3dd802d92de1670221577624d28de 100644 --- a/src/grammar.lalrpop +++ b/src/grammar.lalrpop @@ -124,7 +124,7 @@ Param : Param = { Type : Type = { "bool" => Type::Bool, "()" => Type::Unit, - "i32" => Type::I32, // this should likely be a paratrized Num type later + "i32" => Type::I32, // this should likely be a parametrized Num type later Id => Type::Named(<>), "&" <Type> => Type::Ref(Box::new(<>)), "&" "mut" <Type> => Type::Ref(Box::new(Type::Mut(Box::new(<>)))), @@ -159,7 +159,7 @@ StmtBlock: Stmt = { } Stmt: Stmt = { - "let" <m: "mut"?> <id: Id> <t: (":" <Type>)?> <e: ("=" <Expr>)?> => Stmt::Let(id, m.is_some(), t, e), + "let" <m: "mut"?> <id: Id> <t: (":" <Type>)?> <e: ("=" <Expr>)?> => Stmt::Let(id, m.is_some(), t, e), <Expr> "=" <Expr> => Stmt::Assign(<>), <ExprNoBlock> => Stmt::Expr(<>), } diff --git a/src/vm.rs b/src/vm.rs index bfe900508a628864a6e2c71a07247aaeb0b10c00..e89bdd3b2de2bc8fc725bee1142e16ddceb21349 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -1,12 +1,9 @@ -// vm +// boorrow use std::collections::{HashMap, VecDeque}; -// use std::convert::From; -//use std::iter::{FromIterator, Map}; use crate::ast::*; use crate::env::*; -//use crate::grammar::*; type Id = String; @@ -44,7 +41,12 @@ impl Mem { Some((true, v)) => Some(v), // a mut reference Some((_, v)) => { match v { - Val::Uninitialized => Some(v), // an unitialized + Val::Uninitialized => Some(v), // an uninitialized + Val::RefMut(_) => { + // a ref mut + println!("get &mut {:?}", v); + Some(v) + } _ => panic!("cannot access as mutable"), } } @@ -175,6 +177,7 @@ fn eval_expr(e: &Expr, m: &mut Mem, fn_env: &FnEnv) -> Val { match ev { Val::Ref(id) => eval_expr(&Expr::Id(id), m, fn_env), + Val::RefMut(id) => eval_expr(&Expr::Id(id), m, fn_env), _ => panic!("cannot deref"), } } @@ -364,4 +367,4 @@ fn test_deref() { let e: Expr = Expr::DeRef(Box::new(Expr::DeRef(Box::new(Expr::Id("c".to_string()))))); let v = eval_expr(&e, &mut m, &FnEnv::new()); println!("v {:?}", v); -} +} \ No newline at end of file diff --git a/tests/test_borrow.rs b/tests/test_borrow.rs new file mode 100644 index 0000000000000000000000000000000000000000..16dba2cf7e5fadc27a22ebbdf371711f0add0f5f --- /dev/null +++ b/tests/test_borrow.rs @@ -0,0 +1,120 @@ +use erode::borrow::*; + +#[test] +fn minmal_test() { + eval_prog("examples/minimal.rs"); +} + +#[test] +fn ref_test() { + eval_prog("examples/ref.rs"); +} + +#[test] +fn assign_test() { + eval_prog("examples/assign.rs"); +} + +#[test] +fn ref_mut_test() { + eval_prog("examples/ref_mut.rs"); +} + +#[test] +fn deref_test() { + eval_prog("examples/deref.rs"); +} + +#[test] +fn deref2_test() { + eval_prog("examples/deref2.rs"); +} + +#[test] +fn deref3_test() { + eval_prog("examples/deref3.rs"); +} + +#[test] +fn deref_assign_test() { + eval_prog("examples/deref_assign.rs"); +} + +#[test] +fn deref_assign2_test() { + eval_prog("examples/deref_assign2.rs"); +} + +#[test] +fn deref_assign3_test() { + eval_prog("examples/deref_assign3.rs"); +} + +#[test] +fn scopes_test() { + eval_prog("examples/scopes.rs"); +} + +#[test] +fn scopes_err_test() { + eval_prog("examples/scopes_err.rs"); +} +#[test] +fn vm_test() { + eval_prog("examples/vm.rs"); +} + +#[test] +fn if_test() { + eval_prog("examples/if.rs"); +} + +#[test] +fn while_test() { + eval_prog("examples/while.rs"); +} + +#[test] +fn let_test() { + eval_prog("examples/let.rs"); +} + +#[test] +fn let2_test() { + eval_prog("examples/let2.rs"); +} + +#[test] +fn call_test() { + eval_prog("examples/call.rs"); +} + +#[test] +fn call2_test() { + eval_prog("examples/call2.rs"); +} + +#[test] +fn call3_test() { + eval_prog("examples/call3.rs"); +} + +#[test] +fn call_ref_test() { + eval_prog("examples/call_ref.rs"); +} + +#[test] +fn call_mut_ref_test() { + eval_prog("examples/call_mut_ref.rs"); +} + +#[test] +fn borrow() { + eval_prog("examples/borrow.rs"); +} + +#[test] +fn borrow2() { + eval_prog("examples/borrow2.rs"); +} diff --git a/tests/test_vm.rs b/tests/test_vm.rs index 471e908cdaf16db4174bb0588fee83938f154659..61c8d03968c83d4f0784ffe8a59880b86e08d473 100644 --- a/tests/test_vm.rs +++ b/tests/test_vm.rs @@ -20,6 +20,21 @@ fn ref_mut_test() { eval_prog("examples/ref_mut.rs"); } +#[test] +fn deref_test() { + eval_prog("examples/deref.rs"); +} + +#[test] +fn deref2_test() { + eval_prog("examples/deref2.rs"); +} + +#[test] +fn deref3_test() { + eval_prog("examples/deref3.rs"); +} + #[test] fn deref_assign_test() { eval_prog("examples/deref_assign.rs"); @@ -93,3 +108,13 @@ fn call_ref_test() { fn call_mut_ref_test() { eval_prog("examples/call_mut_ref.rs"); } + +#[test] +fn borrow() { + eval_prog("examples/borrow.rs"); +} + +#[test] +fn borrow2() { + eval_prog("examples/borrow2.rs"); +}