diff --git a/test_files/assign.rs b/examples/assign.rs similarity index 100% rename from test_files/assign.rs rename to examples/assign.rs diff --git a/test_files/assign2.rs b/examples/assign2.rs similarity index 100% rename from test_files/assign2.rs rename to examples/assign2.rs diff --git a/test_files/assign_err.rs b/examples/assign_err.rs similarity index 100% rename from test_files/assign_err.rs rename to examples/assign_err.rs diff --git a/test_files/assign_err2.rs b/examples/assign_err2.rs similarity index 100% rename from test_files/assign_err2.rs rename to examples/assign_err2.rs diff --git a/test_files/assign_err3.rs b/examples/assign_err3.rs similarity index 100% rename from test_files/assign_err3.rs rename to examples/assign_err3.rs diff --git a/test_files/call.rs b/examples/call.rs similarity index 100% rename from test_files/call.rs rename to examples/call.rs diff --git a/test_files/call2.rs b/examples/call2.rs similarity index 100% rename from test_files/call2.rs rename to examples/call2.rs diff --git a/test_files/call3.rs b/examples/call3.rs similarity index 100% rename from test_files/call3.rs rename to examples/call3.rs diff --git a/test_files/call_err.rs b/examples/call_err.rs similarity index 100% rename from test_files/call_err.rs rename to examples/call_err.rs diff --git a/test_files/call_err2.rs b/examples/call_err2.rs similarity index 100% rename from test_files/call_err2.rs rename to examples/call_err2.rs diff --git a/test_files/call_mut_ref.rs b/examples/call_mut_ref.rs similarity index 100% rename from test_files/call_mut_ref.rs rename to examples/call_mut_ref.rs diff --git a/test_files/call_ref.rs b/examples/call_ref.rs similarity index 100% rename from test_files/call_ref.rs rename to examples/call_ref.rs diff --git a/test_files/comment.rs b/examples/comment.rs similarity index 100% rename from test_files/comment.rs rename to examples/comment.rs diff --git a/test_files/deref_assign.rs b/examples/deref_assign.rs similarity index 100% rename from test_files/deref_assign.rs rename to examples/deref_assign.rs diff --git a/examples/deref_assign2.rs b/examples/deref_assign2.rs index 20860b29085d39e255a0d35f9b1a8a5e6cd9bf47..2d6189d2c98e2837a3790d441d3119ba3e70743d 100644 --- a/examples/deref_assign2.rs +++ b/examples/deref_assign2.rs @@ -1,11 +1,7 @@ -fn f() -> i32 { +fn main() -> i32 { let mut a = 7; - let mut b = &mut a; - let c = &mut b; + let b = &a; + let c = &b; **c = 9; a } - -fn main() { - println!("a {}", f()); -} diff --git a/test_files/deref_assign3.rs b/examples/deref_assign3.rs similarity index 100% rename from test_files/deref_assign3.rs rename to examples/deref_assign3.rs diff --git a/test_files/if.rs b/examples/if.rs similarity index 100% rename from test_files/if.rs rename to examples/if.rs diff --git a/test_files/let.rs b/examples/let.rs similarity index 100% rename from test_files/let.rs rename to examples/let.rs diff --git a/test_files/let2.rs b/examples/let2.rs similarity index 100% rename from test_files/let2.rs rename to examples/let2.rs diff --git a/test_files/minimal.rs b/examples/minimal.rs similarity index 100% rename from test_files/minimal.rs rename to examples/minimal.rs diff --git a/test_files/mut.rs b/examples/mut.rs similarity index 100% rename from test_files/mut.rs rename to examples/mut.rs diff --git a/test_files/mut2.rs b/examples/mut2.rs similarity index 100% rename from test_files/mut2.rs rename to examples/mut2.rs diff --git a/examples/ref.rs b/examples/ref.rs new file mode 100644 index 0000000000000000000000000000000000000000..8a80b3b54bb920002ee7aa5321195083a898c325 --- /dev/null +++ b/examples/ref.rs @@ -0,0 +1,7 @@ +fn main() { + let a = 1; + let b: &i32 = &a; + let c = &a; + let d = b; + let e = &d; +} diff --git a/examples/ref2.rs b/examples/ref2.rs new file mode 100644 index 0000000000000000000000000000000000000000..36b9fdebe6dc03f64d59a62ae13c9b496cde99c7 --- /dev/null +++ b/examples/ref2.rs @@ -0,0 +1,5 @@ +fn main() { + let mut a = 1; + let b = &mut a; + let c = b; +} diff --git a/examples/ref3.rs b/examples/ref3.rs new file mode 100644 index 0000000000000000000000000000000000000000..a56f9802bed86e4ab4a2e6535d276358d6545c30 --- /dev/null +++ b/examples/ref3.rs @@ -0,0 +1,5 @@ +fn main() { + let mut a = 1; + let mut b = &mut a; + let c = &mut b; +} diff --git a/examples/ref4.rs b/examples/ref4.rs new file mode 100644 index 0000000000000000000000000000000000000000..d8813a140488805ff91a529a96373c03552da4a3 --- /dev/null +++ b/examples/ref4.rs @@ -0,0 +1,5 @@ +fn main() { + let mut a = 1; + let mut b = &mut a; + let c = *b; +} diff --git a/examples/ref5.rs b/examples/ref5.rs new file mode 100644 index 0000000000000000000000000000000000000000..d8813a140488805ff91a529a96373c03552da4a3 --- /dev/null +++ b/examples/ref5.rs @@ -0,0 +1,5 @@ +fn main() { + let mut a = 1; + let mut b = &mut a; + let c = *b; +} diff --git a/examples/ref_err.rs b/examples/ref_err.rs new file mode 100644 index 0000000000000000000000000000000000000000..f0ddb3e745bdabe1badb29f283b736d1fc4a2bf2 --- /dev/null +++ b/examples/ref_err.rs @@ -0,0 +1,4 @@ +fn main() { + let mut a = 1; + let b: &mut i32 = &a; +} diff --git a/examples/ref_err2.rs b/examples/ref_err2.rs new file mode 100644 index 0000000000000000000000000000000000000000..f941cd7cfaf49aaf3d5145c3b9c681af4359add5 --- /dev/null +++ b/examples/ref_err2.rs @@ -0,0 +1,4 @@ +fn main() { + let a = 1; + let b: &i32 = &mut a; +} diff --git a/examples/ref_err3.rs b/examples/ref_err3.rs new file mode 100644 index 0000000000000000000000000000000000000000..11de065f9055401355859bdc0f6311033163bd01 --- /dev/null +++ b/examples/ref_err3.rs @@ -0,0 +1,4 @@ +fn main() { + let mut a = 1; + let mut b: &i32 = &mut a; +} diff --git a/test_files/ref_mut.rs b/examples/ref_mut.rs similarity index 100% rename from test_files/ref_mut.rs rename to examples/ref_mut.rs diff --git a/test_files/type_err.rs b/examples/type_err.rs similarity index 100% rename from test_files/type_err.rs rename to examples/type_err.rs diff --git a/test_files/type_err2.rs b/examples/type_err2.rs similarity index 100% rename from test_files/type_err2.rs rename to examples/type_err2.rs diff --git a/test_files/vm.rs b/examples/vm.rs similarity index 100% rename from test_files/vm.rs rename to examples/vm.rs diff --git a/test_files/while.rs b/examples/while.rs similarity index 100% rename from test_files/while.rs rename to examples/while.rs diff --git a/src/check.rs b/src/check.rs index b6dfac2392d18505095c0eaa3ed7228c02fae8ff..18c42be5f4caca3f1749045cf1bb52fd551807a4 100644 --- a/src/check.rs +++ b/src/check.rs @@ -136,12 +136,7 @@ fn expr_type( // } // } Id(id) => match var_env.get(id.to_string()) { - Some(t) => match t { - // variable bound to type - Some(t) => Ok(t.clone()), - // not yet bound - None => Err(format!("variable {:?} has no type yet", id)), - }, + Some(t) => Ok(t.clone()), None => Err(format!("variable not found {}", id)), }, @@ -150,18 +145,28 @@ fn expr_type( // Convert Expr::Ref to Type::Ref Ref(ref_e) => { let t = expr_type(ref_e, fn_env, type_env, var_env)?; - Ok(Type::Ref(Box::new(t))) + 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)?; - Ok(Type::Mut(Box::new(t))) + 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)), @@ -171,6 +176,13 @@ fn expr_type( } } +fn strip_mut(t: Type) -> Type { + match t { + Type::Mut(t) => *t, + _ => t, + } +} + // // walk the left hand expression in an assignment. // // Ok(Type), the type of the left hand // // Err(), illegal left hand @@ -332,22 +344,26 @@ pub fn check_stmts( Expr(e) => expr_type(&*e, fn_env, type_env, var_env), Let(var_id, is_mut, ot, oe) => { - let ot: Option<Type> = match (ot, oe) { + let t: Type = match (ot, oe) { (Some(t), Some(e)) => { let e_type = expr_type(&*e, fn_env, type_env, var_env)?; match *t == e_type { - true => Some(t.clone()), - false => Err("incompatible types")?, + true => t.clone(), + false => { + trace!("e {}", e); + Err(format!("incompatible types, {} <> {}", t, e_type))? + } } } - (None, Some(e)) => Some(expr_type(&*e, fn_env, type_env, var_env)?), - (ot, None) => ot.clone(), + (None, Some(e)) => expr_type(&*e, fn_env, type_env, var_env)?, + (Some(t), None) => t.clone(), + _ => Type::Unknown, }; - let ot = match is_mut { - true => Type::Mut(Box::new(ot)), - false => ot, + let t = match is_mut { + true => Type::Mut(Box::new(t)), + false => t, }; - var_env.new_id(var_id.clone(), ot); + var_env.new_id(var_id.clone(), t); trace!("var_env {:?}", var_env); Ok(Type::Unit) } @@ -460,8 +476,8 @@ pub fn check(p: &Program) -> Result<(), Error> { // build a scope for the arguments let mut arg_ty = IdType::new(); for Param { is_mut, id, ty } in fd.params.0.iter() { - // TODO move is_mut to Type - arg_ty.insert(id.to_owned(), Some(ty.clone())); + // TODO move is_mut to Type in parser + arg_ty.insert(id.to_owned(), ty.clone()); } var_env.push_param_scope(arg_ty); @@ -492,9 +508,8 @@ fn test_expr_type() { var_env.push_empty_scope(); // // some test variables in scope - var_env.new_id("i".to_string(), Some(I32)); // let i : i32 ... - var_env.new_id("j".to_string(), None); // let i ... - var_env.new_id("n".to_string(), Some(Type::Named("A".to_string()))); // let n : A ... + var_env.new_id("i".to_string(), I32); // let i : i32 ... + var_env.new_id("j".to_string(), Unknown); // let i ... println!("p {}", p); diff --git a/src/env.rs b/src/env.rs index e3d1fc1c8fe26e23625926a23b667212529c8474..c2f4abaa7ac69deaa9143c238c378d94c585e2c2 100644 --- a/src/env.rs +++ b/src/env.rs @@ -23,11 +23,11 @@ pub fn new_fn_env(v: &Vec<FnDecl>) -> FnEnv { } // Option<Type> -// +// // Some<Type>, variable has a declared type // None, variable has been introduced, but type not yet determined -pub type IdType = HashMap<Id, Option<Type>>; +pub type IdType = HashMap<Id, Type>; #[derive(Debug)] pub struct VarEnv(VecDeque<IdType>); @@ -37,31 +37,31 @@ impl VarEnv { VarEnv(VecDeque::new()) } - pub fn get(&self, id: String) -> Option<&(Option<Type>)> { + pub fn get(&self, id: String) -> Option<&Type> { self.0.iter().find_map(|hm| hm.get(id.as_str())) } - pub fn get_mut(&mut self, id: String) -> Option<&mut (Option<Type>)> { + pub fn get_mut(&mut self, id: String) -> Option<&mut Type> { self.0.iter_mut().find_map(|hm| hm.get_mut(id.as_str())) } - pub fn new_id(&mut self, id: String, oty: Option<Type>) { + pub fn new_id(&mut self, id: String, ty: Type) { let hm = self.0.front_mut().unwrap(); println!("insert id {:?}, in scope {:?}", id, hm); - hm.insert(id, (oty)); + hm.insert(id, ty); } pub fn update(&mut self, id: String, ty: Type) -> Result<(), Error> { use Type::*; match self.get_mut(id.clone()) { Some(ot) => match ot { - None => { + Type::Unknown => { // no type assigned - *ot = Some(ty); + *ot = ty; Ok(()) } - Some(t) => match *t == ty { + t => match *t == ty { true => Ok(()), false => Err(format!("types differ {} <> {}", t, ty)), }, @@ -89,12 +89,12 @@ fn type_env_test() { use Type::*; let mut var_env = VarEnv::new(); var_env.push_empty_scope(); - var_env.new_id("a".to_owned(), None); + var_env.new_id("a".to_owned(), Type::Unknown); println!("{:?}", var_env); println!("update a {:?}", var_env.update("a".to_owned(), I32)); println!("get a {:?}", var_env.get("a".to_owned())); - assert_eq!(var_env.get("a".to_owned()), Some(&Some(I32))); + assert_eq!(var_env.get("a".to_owned()), Some(&I32)); println!("update a {:?}", var_env.update("a".to_owned(), I32)); assert!(var_env.update("a".to_owned(), I32).is_ok()); @@ -114,12 +114,12 @@ fn type_env_test() { println!("update a {:?}", var_env.update("a".to_owned(), I32)); assert!(var_env.update("a".to_owned(), I32).is_ok()); - var_env.new_id("a".to_owned(), None); + var_env.new_id("a".to_owned(), Unknown); println!("get a {:?}", var_env.get("a".to_owned())); - assert_eq!(var_env.get("a".to_owned()), Some(&None)); + assert_eq!(var_env.get("a".to_owned()), Some(&Unknown)); println!("update a {:?}", var_env.update("a".to_owned(), Bool)); println!("get a {:?}", var_env.get("a".to_owned())); - assert_eq!(var_env.get("a".to_owned()), Some(&Some(Bool))); + assert_eq!(var_env.get("a".to_owned()), Some(&Bool)); println!("update a {:?}", var_env.update("a".to_owned(), Bool)); assert!(var_env.update("a".to_owned(), Bool).is_ok()); @@ -129,7 +129,7 @@ fn type_env_test() { println!("pop_scope"); var_env.pop_scope(); println!("get a {:?}", var_env.get("a".to_owned())); - assert_eq!(var_env.get("a".to_owned()), Some(&Some(I32))); + assert_eq!(var_env.get("a".to_owned()), Some(&I32)); println!("update a {:?}", var_env.update("a".to_owned(), Bool)); assert!(var_env.update("a".to_owned(), Bool).is_err()); diff --git a/test_files/deref_assign2.rs b/test_files/deref_assign2.rs deleted file mode 100644 index 2d6189d2c98e2837a3790d441d3119ba3e70743d..0000000000000000000000000000000000000000 --- a/test_files/deref_assign2.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn main() -> i32 { - let mut a = 7; - let b = &a; - let c = &b; - **c = 9; - a -} diff --git a/test_files/ref.rs b/test_files/ref.rs deleted file mode 100644 index ae2d37e8ac6bd464b154c34acd9689df9c520373..0000000000000000000000000000000000000000 --- a/test_files/ref.rs +++ /dev/null @@ -1,9 +0,0 @@ -fn main() -> i32 { - let mut a = 1; - let b: &mut i32 = &a; - let c = &b; - let d = **c; - let e = *c; - let f = *e; - d + f -} diff --git a/test_files/ref2.rs b/test_files/ref2.rs deleted file mode 100644 index 2b751d15af5ab609f578df6c958e00d3186b5365..0000000000000000000000000000000000000000 --- a/test_files/ref2.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() -> i32 { - let mut a = 1; - let b: &mut i32 = &mut a; - let c = *b; -} diff --git a/tests/test_check.rs b/tests/test_check.rs index ded31df19ea9e5c8ef38ce9cee366956627e6e72..659152a951d52b193d05de1937e63c86c242e7b6 100644 --- a/tests/test_check.rs +++ b/tests/test_check.rs @@ -3,109 +3,144 @@ use erode::read_file; #[test] fn check_prog() { - check(&read_file::parse("test_files/minimal.rs")).unwrap(); + check(&read_file::parse("examples/minimal.rs")).unwrap(); } #[test] fn check_assign() { - assert!(check(&read_file::parse("test_files/assign.rs")).is_ok()); + assert!(check(&read_file::parse("examples/assign.rs")).is_ok()); } #[test] fn check_assign2() { - assert!(check(&read_file::parse("test_files/assign2.rs")).is_ok()); + assert!(check(&read_file::parse("examples/assign2.rs")).is_ok()); } #[test] fn check_assign_err() { - assert!(check(&read_file::parse("test_files/assign_err.rs")).is_err()); + assert!(check(&read_file::parse("examples/assign_err.rs")).is_err()); } #[test] fn check_assign_err2() { - assert!(check(&read_file::parse("test_files/assign_err2.rs")).is_err()); + assert!(check(&read_file::parse("examples/assign_err2.rs")).is_err()); } #[test] fn check_assign_err3() { - assert!(check(&read_file::parse("test_files/assign_err3.rs")).is_err()); + assert!(check(&read_file::parse("examples/assign_err3.rs")).is_err()); } #[test] fn check_let() { - check(&read_file::parse("test_files/let.rs")).unwrap(); + check(&read_file::parse("examples/let.rs")).unwrap(); } #[test] fn check_let2() { - assert!(check(&read_file::parse("test_files/let2.rs")).is_ok()); + assert!(check(&read_file::parse("examples/let2.rs")).is_ok()); } #[test] fn check_call() { - assert!(check(&read_file::parse("test_files/call.rs")).is_ok()); + assert!(check(&read_file::parse("examples/call.rs")).is_ok()); } #[test] fn check_call2() { - assert!(check(&read_file::parse("test_files/call2.rs")).is_ok()); + assert!(check(&read_file::parse("examples/call2.rs")).is_ok()); } #[test] fn check_call3() { - assert!(check(&read_file::parse("test_files/call3.rs")).is_ok()); + assert!(check(&read_file::parse("examples/call3.rs")).is_ok()); } #[test] fn check_call_err() { - assert!(check(&read_file::parse("test_files/call_err.rs")).is_err()); + assert!(check(&read_file::parse("examples/call_err.rs")).is_err()); } #[test] fn check_call_err2() { - assert!(check(&read_file::parse("test_files/call_err2.rs")).is_err()); + assert!(check(&read_file::parse("examples/call_err2.rs")).is_err()); } #[test] fn check_mut() { - assert!(check(&read_file::parse("test_files/mut.rs")).is_ok()); + assert!(check(&read_file::parse("examples/mut.rs")).is_ok()); } #[test] fn check_mut2() { - assert!(check(&read_file::parse("test_files/mut2.rs")).is_ok()); + assert!(check(&read_file::parse("examples/mut2.rs")).is_ok()); } #[test] fn check_type_err() { - assert!(check(&read_file::parse("test_files/type_err.rs")).is_err()); + assert!(check(&read_file::parse("examples/type_err.rs")).is_err()); } #[test] fn check_type_err2() { - assert!(check(&read_file::parse("test_files/type_err2.rs")).is_err()); + assert!(check(&read_file::parse("examples/type_err2.rs")).is_err()); } #[test] fn check_if() { - assert!(check(&read_file::parse("test_files/if.rs")).is_ok()); + assert!(check(&read_file::parse("examples/if.rs")).is_ok()); } #[test] fn check_while() { - assert!(check(&read_file::parse("test_files/while.rs")).is_ok()); + assert!(check(&read_file::parse("examples/while.rs")).is_ok()); } #[test] fn check_deref_assign() { - assert!(check(&read_file::parse("test_files/deref_assign.rs")).is_ok()); + assert!(check(&read_file::parse("examples/deref_assign.rs")).is_ok()); } #[test] fn check_deref_assign2() { - assert!(check(&read_file::parse("test_files/deref_assign2.rs")).is_ok()); + assert!(check(&read_file::parse("examples/deref_assign2.rs")).is_ok()); +} + +#[test] +fn check_ref() { + assert!(check(&read_file::parse("examples/ref.rs")).is_ok()); } #[test] fn check_ref2() { - assert!(check(&read_file::parse("test_files/ref2.rs")).is_ok()); + assert!(check(&read_file::parse("examples/ref2.rs")).is_ok()); +} + +#[test] +fn check_ref3() { + assert!(check(&read_file::parse("examples/ref3.rs")).is_ok()); +} + +#[test] +fn check_ref4() { + assert!(check(&read_file::parse("examples/ref4.rs")).is_ok()); +} + +#[test] +fn check_ref5() { + assert!(check(&read_file::parse("examples/ref5.rs")).is_ok()); +} + +#[test] +fn check_ref_err() { + assert!(check(&read_file::parse("examples/ref_err.rs")).is_err()); +} + +#[test] +fn check_ref_err2() { + assert!(check(&read_file::parse("examples/ref_err2.rs")).is_err()); +} + +#[test] +fn check_ref_err3() { + assert!(check(&read_file::parse("examples/ref_err3.rs")).is_err()); } diff --git a/tests/test_vm.rs b/tests/test_vm.rs index 47ab53a19e86c35a565fdc7f9f2fb0980c2ab217..27086b6f8606e08a5be220f8124c5deb43406fb5 100644 --- a/tests/test_vm.rs +++ b/tests/test_vm.rs @@ -2,85 +2,85 @@ use erode::vm::*; #[test] fn ref_test() { - eval_prog("test_files/ref.rs"); + eval_prog("examples/ref.rs"); } #[test] fn assign_test() { - eval_prog("test_files/assign.rs"); + eval_prog("examples/assign.rs"); } #[test] fn ref_mut_test() { - eval_prog("test_files/ref_mut.rs"); + eval_prog("examples/ref_mut.rs"); } #[test] fn deref_assign_test() { - eval_prog("test_files/deref_assign.rs"); + eval_prog("examples/deref_assign.rs"); } #[test] fn deref_assign2_test() { - eval_prog("test_files/deref_assign2.rs"); + eval_prog("examples/deref_assign2.rs"); } #[test] fn deref_assign3_test() { - eval_prog("test_files/deref_assign3.rs"); + eval_prog("examples/deref_assign3.rs"); } #[test] fn scopes_test() { - eval_prog("test_files/scopes.rs"); + eval_prog("examples/scopes.rs"); } #[test] fn vm_test() { - eval_prog("test_files/vm.rs"); + eval_prog("examples/vm.rs"); } #[test] fn if_test() { - eval_prog("test_files/if.rs"); + eval_prog("examples/if.rs"); } #[test] fn while_test() { - eval_prog("test_files/while.rs"); + eval_prog("examples/while.rs"); } #[test] fn mut_test() { - eval_prog("test_files/mut.rs"); + eval_prog("examples/mut.rs"); } #[test] fn mut2_test() { - eval_prog("test_files/mut2.rs"); + eval_prog("examples/mut2.rs"); } #[test] fn call_test() { - eval_prog("test_files/call.rs"); + eval_prog("examples/call.rs"); } #[test] fn call2_test() { - eval_prog("test_files/call2.rs"); + eval_prog("examples/call2.rs"); } #[test] fn call3_test() { - eval_prog("test_files/call3.rs"); + eval_prog("examples/call3.rs"); } #[test] fn call_ref_test() { - eval_prog("test_files/call_ref.rs"); + eval_prog("examples/call_ref.rs"); } #[test] fn call_mut_ref_test() { - eval_prog("test_files/call_mut_ref.rs"); + eval_prog("examples/call_mut_ref.rs"); }