diff --git a/.gitignore b/.gitignore index d9f8653..ac78f8d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ target/ **/*.rs.bk Cargo.lock -.vscode/ \ No newline at end of file +.vscode/ +.idea/ \ No newline at end of file diff --git a/src/codegen/emit.rs b/src/codegen/emit.rs new file mode 100644 index 0000000..78714e0 --- /dev/null +++ b/src/codegen/emit.rs @@ -0,0 +1,7 @@ + +use syntax::*; + +pub trait ModuleProvider { + fn gen_module(&mut self, modu: T) + where T: IntoIterator; +} diff --git a/src/codegen/llvm.rs b/src/codegen/llvm.rs new file mode 100644 index 0000000..bc713c6 --- /dev/null +++ b/src/codegen/llvm.rs @@ -0,0 +1,320 @@ +use std::char; +use std::ffi::{CString, NulError}; +use std::io::{self, Read, Write, BufReader}; +use std::ptr; +use std::collections::HashMap; +use std::iter::*; + +use std::ops::Deref; +use libc::{c_uint, c_ulonglong, c_char}; + + +use llvm_sys::prelude::{LLVMBuilderRef, LLVMContextRef, LLVMModuleRef, LLVMPassManagerRef, LLVMTypeRef, LLVMValueRef}; +use llvm_sys::execution_engine::{LLVMExecutionEngineRef, LLVMGenericValueToFloat, LLVMRunFunction, LLVMGenericValueRef}; +use llvm_sys::analysis::{LLVMVerifyFunction, LLVMVerifierFailureAction}; +use llvm_sys::LLVMRealPredicate; +use llvm_sys::core::*; + +// use codegen::llvm::*; +use syntax::*; +use types::*; +use utils::*; + +#[derive(Debug, Clone)] +pub struct LLVMCodegen { + module: LLVMModuleRef, + builder: LLVMBuilderRef, + context: LLVMContextRef, + unique: usize, +} + +pub type VarEnv<'a> = SymTable<'a, &'a str, LLVMValueRef>; + +fn get_llvm_op(op: BinOp, p_type: &Type) + -> unsafe extern "C" + fn(LLVMBuilderRef, LLVMValueRef, LLVMValueRef, *const ::libc::c_char) -> LLVMValueRef +{ + use self::BinOp::*; + use self::Type::*; + if let &Con(ref ty_name) = p_type { + let name_ref = ty_name.as_str(); + match op { + Add => match name_ref { + "Int" => LLVMBuildAdd, + "Float" => LLVMBuildFAdd, + _ => unreachable!() + }, + Sub => match name_ref { + "Int" => LLVMBuildSub, + "Float" => LLVMBuildFSub, + _ => unreachable!() + }, + Mul => match name_ref { + "Int" => LLVMBuildMul, + "Float" => LLVMBuildFMul, + _ => unreachable!() + }, + Div => LLVMBuildFDiv, + Rem => LLVMBuildURem, // TODO: WTF LLVM builder ??? + _ => unreachable!() + } + } else { + unreachable!() + } +} + +unsafe fn raw_string(s: &str) -> *mut c_char { + CString::new(s).unwrap().into_raw() +} + +impl LLVMCodegen { + pub fn new(name: &str) -> LLVMCodegen { + unsafe { + let ctx = LLVMContextCreate(); + let modu = LLVMModuleCreateWithNameInContext(CString::new(name).unwrap().into_raw(), ctx); + let builder = LLVMCreateBuilderInContext(ctx); + LLVMCodegen { + module: modu, + context: ctx, + builder: builder, + unique: 0 + } + } + } + + pub fn dump(&mut self) { + unsafe { + LLVMDumpModule(self.module); + } + } + + fn gensym(&mut self) -> Result { + let mut f = String::new(); + f.push_str(self.unique.to_string().as_str()); + self.unique = self.unique + 1; + CString::new(f) + } + + unsafe fn get_fun_type(&mut self, scm: &Scheme) -> LLVMTypeRef { + match scm { + &Scheme::Mono(ref ty) => self.get_llvm_type(ty.deref()), + _ => unreachable!() + } + } + + unsafe fn get_llvm_type(&mut self, ty: &Type) -> LLVMTypeRef { + use self::Type::*; + match ty { + &Con(ref n) => match n.as_str() { + // Primary types + "Int" => LLVMInt32TypeInContext(self.context), + "Float" => LLVMDoubleTypeInContext(self.context), + "Char" => LLVMInt8TypeInContext(self.context), + + // User defined types + t => self.gen_user_type(t) + }, + &Arr(ref p, ref ret) => { + let mut psty: Vec = vec![]; + let mut r: &Type = p.deref(); + loop { + if let &Prod(ref t, ref rest) = r { + psty.push(self.get_llvm_type(t.deref())); + r = rest; + } else { + psty.push(self.get_llvm_type(r.deref())); + break; + } + } + let argc = psty.len(); + LLVMFunctionType(self.get_llvm_type(ret.deref()), psty.as_mut_ptr(), argc as c_uint, 0) + } + &Prod(ref l, ref r) => unimplemented!(), // TODO: make a struct represent tuple + &Comp(ref c, ref p) => unimplemented!(), // TODO: determine the type + + _ => unimplemented!(), + } + } + + unsafe fn gen_lit(&mut self, lit: &Lit) -> LLVMValueRef { + use self::Lit::*; + match lit { + &Float(f) => LLVMConstReal(LLVMDoubleTypeInContext(self.context), f), + &Int(i) => LLVMConstInt(LLVMInt32TypeInContext(self.context), i as c_ulonglong, 1), + &Bool(true) => LLVMConstInt(LLVMInt1TypeInContext(self.context), 1 as c_ulonglong, 0), + &Bool(false) => LLVMConstInt(LLVMInt1TypeInContext(self.context), 0 as c_ulonglong, 0), + // TODO: String represent + &Str(ref s) => unimplemented!(), + } + } + + unsafe fn get_or_add_function(&mut self, fname: &str, fty: &Type) -> LLVMValueRef { + let n = CString::new(fname).unwrap().into_raw(); + let f = LLVMGetNamedFunction(self.module, n); + if f.is_null() { + let llvm_ty = self.get_llvm_type(fty); + LLVMAddFunction( + self.module, + CString::new(fname).unwrap().into_raw(), + llvm_ty) + } else { + f + } + } + + unsafe fn gen_user_type(&mut self, tyname: &str) -> LLVMTypeRef { + // TODO: make a user defined type definition + unimplemented!() + } + + unsafe fn create_entry_block_alloca(&mut self, fun: LLVMValueRef, var_name: &str, ty: &Type) -> LLVMValueRef { + let builder = LLVMCreateBuilderInContext(self.context); + let bb = LLVMGetEntryBasicBlock(fun); + let fi = LLVMGetFirstInstruction(bb); + let llvm_ty = self.get_llvm_type(ty); + LLVMPositionBuilder(builder, bb, fi); + LLVMBuildAlloca(builder, llvm_ty, raw_string(var_name)) + } + + pub fn gen_top_level(&mut self, def: &Def, prelude: &VarEnv) { + unsafe { + if let Item::Form(ref form) = def.node { + /// If is a global function definition + match (*form).node { + Expr::Abs(ref lambda) => { + let fun_type = (*form).tag.ref_type(); + let fun = self.get_or_add_function(def.ident.as_str(), fun_type); + + // Check redefinition + if LLVMCountBasicBlocks(fun) != 0 { + panic!("Redefinition of function"); // TODO: Error return + } + let paramc = LLVMCountParams(fun) as usize; + if paramc != lambda.param.len() { + // TODO: Error return + panic!("Redefinition of function with different argument count"); + } + + let mut symtbl = prelude.sub_env(); + + + let bb = LLVMAppendBasicBlockInContext( + self.context, + fun, + CString::new("entry").unwrap().into_raw()); + + LLVMPositionBuilderAtEnd(self.builder, bb); + + /// For each parameter, set argument name, + /// create store instruction, add to + /// symbol table. + for (i, &VarDecl(ref pname, ref ptype)) in lambda.param.iter().enumerate() { + let llarg = LLVMGetParam(fun, i as c_uint); + // let lltype = self.get_llvm_type(ptype.body()); + LLVMSetValueName(llarg, raw_string(pname.as_str())); + + let alloca = self.create_entry_block_alloca(fun, pname.as_str(), ptype.body()); + + LLVMBuildStore(self.builder, llarg, alloca); + symtbl.insert(pname.as_str(), alloca); + } + + let fun_body = self.gen_expr(lambda.body.deref(), &mut symtbl); + LLVMBuildRet(self.builder, fun_body); + + if LLVMVerifyFunction(fun, LLVMVerifierFailureAction::LLVMPrintMessageAction) != 0 { + println!("Function verify failed"); + } + } + _ => unimplemented!() + } + } else { + unimplemented!() + } + } + } + + unsafe fn gen_expr<'a: 'b, 'b>( + &mut self, + form: &'a Form, + symtbl: &mut VarEnv<'b>) + -> LLVMValueRef + { + use self::Expr::*; + // println!("{:?}", form); + match form.node { + Lit(ref lit) => self.gen_lit(lit), + Var(ref vn) => { + let var_name = vn.as_str(); + match symtbl.lookup(&var_name) { + Some(v) => { + LLVMBuildLoad(self.builder, *v, raw_string(var_name)) + // *v + }, + // Impossible because of type check + None => self.get_or_add_function(var_name, form.tag.ref_type()) + } + } + Binary(op, ref lhs, ref rhs) => { + let lval = self.gen_expr(lhs, symtbl); + let rval = self.gen_expr(rhs, symtbl); + let instr = get_llvm_op(op, lhs.tag.ref_type()); + + instr(self.builder, lval, rval, self.gensym().unwrap().into_raw()) + } + Let(ref var_decl, ref val, ref exp) => { + let &VarDecl(ref var, ref tyvar) = var_decl; + let var_name = var.as_str(); + + let blk = LLVMGetInsertBlock(self.builder); + let fun = LLVMGetBasicBlockParent(blk); + + let init = self.gen_expr(val, symtbl); + let alloca = self.create_entry_block_alloca(fun, var_name, tyvar.body()); + LLVMBuildStore(self.builder, init, alloca); + + let old = symtbl.insert(var_name, alloca); + + let res = self.gen_expr(exp.deref(), symtbl); + + if let Some(o) = old { + symtbl.insert(var_name, o); + } else { + symtbl.remove(&var_name); + } + res + } + Apply(ref callee, ref args) => { + // let funty = self.get_fun_type(callee.deref().tag.ref_scheme()); + let callee_ref = self.gen_expr(callee, symtbl); + + let mut argsv = vec![]; + for arg in args.iter() { + // TODO: unpack tuple + argsv.push(self.gen_expr(arg, symtbl)); + } + + LLVMBuildCall( + self.builder, + callee_ref, + argsv.as_mut_ptr(), + argsv.len() as c_uint, + self.gensym().unwrap().into_raw()) + } + Block(ref fs) => { + let mut it = fs.iter(); + if let Some(v) = it.next() { + let mut ret = self.gen_expr(v, symtbl); + for n in it { + ret = self.gen_expr(n, symtbl); + } + ret + } else { + panic!("Empty block") + } + } + _ => unimplemented!() + } + } +} + diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs new file mode 100644 index 0000000..78f3b2d --- /dev/null +++ b/src/codegen/mod.rs @@ -0,0 +1,2 @@ +pub mod emit; +pub mod llvm; \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 3d08505..6bc1670 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,4 +19,4 @@ pub mod parser; pub mod typeinfer; pub mod codegen; pub mod types; -pub mod core; +// pub mod core; diff --git a/src/main.rs b/src/main.rs index d7beab7..8e378c8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,67 @@ extern crate rl; -// use rl::syntax; -// use rl::parser::*; +use rl::utils::*; +use rl::syntax::*; +use rl::parser::*; +use rl::types::*; +use rl::typeinfer::*; +use rl::codegen::llvm::*; + +use std::io; +use std::io::Write; +use std::ops::Deref; +use std::collections::HashMap; +fn repl() { + let stdin = io::stdin(); + let mut stdout = io::stdout(); + let mut input = String::new(); + + let mut generator = LLVMCodegen::new("repl"); + + 'main: loop { + print!("> "); + stdout.flush().unwrap(); + input.clear(); + stdin.read_line(&mut input).ok().expect("Failed to read line"); + if input.as_str() == ".quit\n" { + break; + } + let mut res: Vec<_> = parse(input.as_str()).into_iter().collect(); + println!("Parsed syntax tree:"); + println!("{:?}", res); + + let ty_op = Scheme::Poly(vec!["a".to_string()], + P(Type::Arr(P(Type::Prod(P(Type::Var("a".to_string())), + P(Type::Var("a".to_string())))), + P(Type::Var("a".to_string()))))); + + + let mut ty_infer = infer::Infer::new(); + let mut ty_env = infer::Infer::new_env(); + + ty_env.insert(String::from("+"), ty_op); + + let inf = ty_infer.infer_defs(&ty_env, &mut res); + match inf { + Ok(_) => { + println!("Typed AST:"); + println!("{:?}", res); + println!("LLVM IR:"); + for def in res { + generator.gen_top_level(def.deref(), &VarEnv::new()); + } + generator.dump(); + }, + Err(e) => println!("{:?}", e) + } + + + } +} fn main() { // println!("{:?}", type_term(Span::new("(a) * ASDBCa * Fuck * Shit * c"))); // println!("{:?}", type_factor(Span::new("shit"))); // println!("{:?}", type_factor(Span::new("Fuck"))); // println!("{:?}", type_expr(Span::new("a"))); - + repl(); } \ No newline at end of file diff --git a/src/parser.rs b/src/parser.rs index 826c8bf..ba89139 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -13,6 +13,7 @@ fn form(e: Expr) -> P
{ impl_rdp! { grammar! { + top = { bind* } type_anno = { (["forall"] ~ type_bounds ~ ["."])? ~ type_expr } type_expr = { { type_factor } @@ -107,6 +108,9 @@ impl_rdp! { } process! { + program(&self) -> LinkedList< P > { + (_: top, bs: _binds()) => bs + } // Just for test _type_expr(&self) -> P { @@ -140,11 +144,22 @@ impl_rdp! { _bind(&self) -> P { (_: assign, ass: _assign()) => { let (VarDecl(name, ty), mut val) = ass; - val.tag.annotate = Some(ty); + val.tag.annotate = match ty { + Scheme::Slot => None, + _ => Some(ty) + }; // f.settype(ty); Def::value(Pos::new(0,0), name, val) } } + _binds(&self) -> LinkedList< P > { + (_: bind, head: _bind(), mut tail: _binds()) => { + tail.push_front(head); + tail + }, + () => LinkedList::new() + } + _lit(&self) -> Lit { @@ -280,6 +295,12 @@ impl_rdp! { } } +pub fn parse(src: &str) -> LinkedList> { + let mut parser = Rdp::new(StringInput::new(src)); + parser.top(); + parser.program() +} + #[cfg(test)] mod tests { diff --git a/src/syntax.rs b/src/syntax.rs index fdc33e2..ee9c821 100644 --- a/src/syntax.rs +++ b/src/syntax.rs @@ -21,6 +21,11 @@ pub struct Def { } impl Def { + /// Get ident as `&str` + pub fn name(&self) -> &str { + self.ident.as_str() + } + /// Create a definition node define a form (value). pub fn value(pos: Pos, name: S, body: E) -> P { P(Def { @@ -38,6 +43,18 @@ impl Def { } } + pub fn form_annot(&self) -> Option<&Scheme> { + match self.node { + Item::Form(ref f) => { + match f.deref().tag.annotate { + Some(ref scm) => Some(scm), + _ => None + } + }, + _ => None + } + } + /// Set the type of form /// only called if this is a value definition pub fn set_form_scheme(&mut self, scm: Scheme) { @@ -74,27 +91,6 @@ pub enum Item { Alg(Vec), } -/// Represents a variant of `data` type -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub struct Variant { - pub name: Name, - pub body: VariantBody, -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub enum VariantBody { - Struct(Vec), - Tuple(Vec), - Unit, -} - -/// A field definition of struct in `data` -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub struct Field { - pub pos: Pos, - pub name: Option, - pub ty: P, -} /// Represents a form diff --git a/src/typeinfer/infer.rs b/src/typeinfer/infer.rs index 39fd03b..fab0c0a 100644 --- a/src/typeinfer/infer.rs +++ b/src/typeinfer/infer.rs @@ -16,12 +16,14 @@ use std::ops::Deref; use std::ops::DerefMut; use std::ops::Placer; +use std::mem; + #[derive(Clone, PartialEq, Debug)] -pub enum TypeError<'a> { - NotInScope(&'a Form), +pub enum TypeError { + NotInScope(Form), MisMatch(Type, Type), - HighRank(&'a Form), - UnknownOperator(&'a BinOp, &'a Pos), + HighRank(Form), + UnknownOperator(BinOp, Pos), } #[derive(Clone, PartialEq, Debug)] @@ -31,14 +33,14 @@ pub struct Infer { } #[derive(Clone, PartialEq, Debug)] -pub struct Constraint(Type, Type); +struct Constraint(Type, Type); impl Constraint { pub fn apply_mut(&mut self, sub: &Subst) { self.0 = self.0.clone().apply(sub); self.1 = self.1.clone().apply(sub); } - pub fn unify<'a>(self) -> Result> { + pub fn unify<'a>(self) -> Result { use self::Type::*; match self { Constraint(Var(n), t) | @@ -82,7 +84,7 @@ impl Substituable for Constraint { fn generalize(e: &TypeEnv, ty: Type) -> Scheme { let fvs: Vec<_> = ty.ftv() .into_iter() - .filter(|fv| !e.exist(fv.as_str())) + .filter(|fv| !e.exist(fv)) .collect(); if fvs.is_empty() { Scheme::Mono(P(ty)) @@ -147,7 +149,7 @@ impl Infer { fn infer<'a>(&mut self, e: &TypeEnv, form: &'a mut Form) - -> Result<&'a Scheme, TypeError<'a>> { + -> Result<&'a Scheme, TypeError> { use self::Expr::*; use self::Scheme::*; use self::TypeError::*; @@ -170,7 +172,7 @@ impl Infer { form.tag.ty = (*ty).clone(); // form.set_scheme(); } else { - return Err(NotInScope(form)); + return Err(NotInScope(form.to_owned())); } } @@ -180,7 +182,7 @@ impl Infer { // Exntend the environment with parameters type, // then infer function body. Abs(ref mut fun) => { - let mut extends: Vec<(&str, &Scheme)> = vec![]; + let mut extends = vec![]; let mut types: Vec = vec![]; for p in fun.param.iter_mut() { @@ -188,7 +190,7 @@ impl Infer { Slot => p.1 = Scheme::Mono(P(self.fresh())), _ => {} } - extends.push((p.0.as_str(), &p.1)); + extends.push((p.0.to_owned(), p.1.clone())); types.push(p.1.body().clone()); } let typaram = Type::product_n(types); @@ -222,7 +224,7 @@ impl Infer { Binary(ref op, ref mut left, ref mut right) => { let ty_left = self.infer(e, left)?.body(); let ty_right = self.infer(e, right)?.body(); - if let Some(ty_op) = e.lookup(op.as_str()) { + if let Some(ty_op) = e.lookup(&op.as_str().to_string()) { let ty_lr = Type::product(ty_left.clone(), ty_right.clone()); form.tag.ty = to_mono(self.fresh()); @@ -230,7 +232,7 @@ impl Infer { let ty_fun = Scheme::arrow(ty_lr, form.tag.clone_type()); self.uni(ty_op.body(), ty_fun.body()); } else { - return Err(TypeError::UnknownOperator(op, &form.tag.pos)); + return Err(TypeError::UnknownOperator(op.clone(), form.tag.pos.clone())); } } @@ -242,7 +244,7 @@ impl Infer { } self.uni(ty.body(), tyval.body()); - let tyexp = self.infer(&e.extend(name.as_str(), &tyval), body)?; + let tyexp = self.infer(&e.extend(name.to_owned(), tyval.to_owned()), body)?; form.tag.ty = tyexp.clone(); } @@ -298,38 +300,48 @@ impl Infer { /// Do type inference over top level definitions pub fn infer_defs<'a>(&mut self, _env: &'a TypeEnv<'a>, - program: &'a mut Vec) - -> Result<(), TypeError<'a>> { - - // Only need form definitions - let defs: Vec<&mut Def> = program - .iter_mut() - .filter(|ref v| v.is_form()) - .collect(); - - // Give each definitions a temporary type - let name_scms: Vec<(String, Scheme)> = defs - .iter() - .map(|ref d| (d.ident.clone(), to_mono(self.fresh()))) - .collect(); - // Add them into environment - let extends: Vec<_> = name_scms - .iter() - .map(|&(ref n, ref s)| (n.as_str(), s)) - .collect(); - let env = _env.extend_n(extends); - - for d in defs { - self.infer(&env, d.form_body_mut())?; + program: &'a mut Vec>) + -> Result<(), TypeError> { + + // Give each definitions a temporary type if no annotattion + let mut env = { + let name_scms = program + .iter() + .filter(|ref v| v.is_form()) + .map(|ref d| (d.name().to_string(), match d.form_annot() { + Some(s) => s.clone(), + _ => to_mono(self.fresh()) + })); + + // Add them into environment + _env.extend_n(name_scms) + }; + + for d in program.iter_mut() { + if d.is_form() { + let sub = { + self.infer(&env, d.form_body_mut())?; + self.solve()? + }; + d.form_body_mut().apply_mut(&sub); + + let general = generalize(&env, d.form_type().body().to_owned()); + + d.form_body_mut().tag.set_scheme(general); + + env.insert(d.name().to_owned(), d.form_type().clone()); + } } + Ok(()) } /// Solve constraints. This will move out the `Infer` struct. - pub fn solve<'a>(self) -> Result> { + fn solve<'a>(&mut self) -> Result { let mut sub = HashMap::::new(); - let mut constraints = self.constraints; + // let mut constraints = self.constraints; + let mut constraints = mem::replace(&mut self.constraints, LinkedList::new()); while let Some(cons) = constraints.pop_front() { let new_sub = cons.unify()?; for ref mut c in constraints.iter_mut() { @@ -396,7 +408,7 @@ mod tests { let PRIMITIVES: Vec<(&str, &Scheme)> = vec![("+", &ty_op)]; let mut syn: Form = parse_expr("(a: Fuck, b) -> let c = a in { c + b }"); - let mut env = TypeEnv::from_iter(PRIMITIVES.clone()); + let mut env = TypeEnv::from_iter(PRIMITIVES.iter().map(|&(n, s)| (n.to_string(), s.clone()))); let sub = { let mut inf = Infer::new(); inf.infer(&mut env, &mut syn); diff --git a/src/typeinfer/mod.rs b/src/typeinfer/mod.rs index 225fd04..c7853f1 100644 --- a/src/typeinfer/mod.rs +++ b/src/typeinfer/mod.rs @@ -2,19 +2,3 @@ pub mod subst; pub mod typeenv; pub mod infer; -// use syntax::*; -// use self::subst::*; -// use self::infer::*; -// use self::typeenv::*; - -// pub fn type_check<'b, 'a: 'b, T>(_env: &'a TypeEnv<'a>, program: &'a mut Vec) -> TypeEnv<'b> { -// // Add top level definition names into environment. -// // Types are set to temporaries. -// let name_types: Vec<_> = program.iter() -// .filter(|ref v| v.is_value()) -// .map(|ref v| (v.ident.as_str(), v.value_type().unwrap())) -// .collect(); - -// let mut env = _env.extend_n(name_types); - -// } diff --git a/src/typeinfer/typeenv.rs b/src/typeinfer/typeenv.rs index f874e38..5275a9d 100644 --- a/src/typeinfer/typeenv.rs +++ b/src/typeinfer/typeenv.rs @@ -6,5 +6,5 @@ use types::*; -pub type TypeEnv<'a> = SymTable<'a, &'a Scheme>; +pub type TypeEnv<'a> = SymTable<'a, String, Scheme>; diff --git a/src/types.rs b/src/types.rs index 018e8ed..580eef8 100644 --- a/src/types.rs +++ b/src/types.rs @@ -7,6 +7,30 @@ use std::ops::DerefMut; use std::iter::IntoIterator; use std::iter::DoubleEndedIterator; + +/// Represents a variant of `data` type +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct Variant { + pub name: Name, + pub body: VariantBody, +} + +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub enum VariantBody { + Struct(Vec), + Tuple(Vec), + Unit, +} + +/// A field definition of struct in `data` +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct Field { +// pub pos: Pos, + pub name: Option, + pub ty: P, +} + + /// Type scheme #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub enum Scheme { diff --git a/src/utils.rs b/src/utils.rs index b717a35..f7d3278 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -8,53 +8,61 @@ pub fn P(t: T) -> Box { } #[derive(Clone, PartialEq, Debug)] -pub struct SymTable<'a, T: 'a> { - vars: HashMap<&'a str, T>, - parent: Option<&'a SymTable<'a, T>>, +pub struct SymTable<'a, K, T: 'a> + where K: 'a + ::std::cmp::Eq + ::std::hash::Hash { + vars: HashMap, + parent: Option<&'a SymTable<'a, K, T>>, } -impl<'a: 'b, 'b, T: 'a> SymTable<'a, T> { - pub fn new() -> SymTable<'a, T> { +impl<'a: 'b, 'b, K:'a, T: 'a> SymTable<'a, K, T> + where K: 'a + ::std::cmp::Eq + ::std::hash::Hash { + pub fn new() -> SymTable<'a, K, T> { SymTable { vars: HashMap::new(), parent: None, } } - pub fn from_iter(it: I) -> SymTable<'a, T> - where I: IntoIterator + pub fn from_iter(it: I) -> SymTable<'a, K, T> + where I: IntoIterator { let mut env = SymTable::new(); env.vars.extend(it); env } - fn sub_env(&'a self) -> SymTable<'b, T> { + pub fn sub_env(&'a self) -> SymTable<'b, K, T> { let mut it = SymTable::new(); it.parent = Some(self); it } - pub fn exist(&self, k: &str) -> bool { + pub fn exist(&self, k: &K) -> bool { self.vars.contains_key(k) } - pub fn extend(&'a self, name: &'b str, ty: T) -> SymTable<'b, T> { + pub fn extend(&'a self, name: K, ty: T) -> SymTable<'b, K, T> { let mut it = self.sub_env(); it.vars.insert(name, ty); return it; } - pub fn extend_n(&'a self, terms: I) -> SymTable<'b, T> - where I: IntoIterator + pub fn extend_n(&'a self, terms: I) -> SymTable<'b, K, T> + where I: IntoIterator { let mut it = self.sub_env(); it.vars.extend(terms); return it; } + pub fn remove(&mut self, k: &K) -> Option { + self.vars.remove(k) + } + pub fn insert(&mut self, k: K, v: T) -> Option { + self.vars.insert(k, v) + } - pub fn lookup(&self, name: &'a str) -> Option<&T> { + pub fn lookup(&self, name: &K) -> Option<&T> { match self.vars.get(name) { None => { if let Some(p) = self.parent {