diff --git a/src/schala_lang/builtin.rs b/src/schala_lang/builtin.rs index c2d5df0..f4076ba 100644 --- a/src/schala_lang/builtin.rs +++ b/src/schala_lang/builtin.rs @@ -1,15 +1,14 @@ use std::rc::Rc; +use std::collections::HashMap; + +use schala_lang::typechecking::{Type, TypeResult, TConst}; +use self::Type::*; use self::TConst::*; #[derive(Debug, PartialEq, Clone)] pub struct BinOp { sigil: Rc } -#[derive(Debug, PartialEq, Clone)] -pub struct PrefixOp { - sigil: Rc -} - impl BinOp { pub fn from_sigil(sigil: Rc) -> BinOp { BinOp { sigil } @@ -17,10 +16,16 @@ impl BinOp { pub fn sigil(&self) -> &Rc { &self.sigil } + pub fn get_type(&self) -> TypeResult { + let s = self.sigil.as_str(); + BINOPS.get(s).map(|x| x.0.clone()).ok_or(format!("Binop {} not found", s)) + } +} + +impl BinOp { pub fn min_precedence() -> i32 { i32::min_value() } - pub fn get_precedence(op: &str) -> i32 { match op { "+" | "-" => 10, @@ -30,6 +35,11 @@ impl BinOp { } } +#[derive(Debug, PartialEq, Clone)] +pub struct PrefixOp { + sigil: Rc +} + impl PrefixOp { pub fn from_sigil(sigil: Rc) -> PrefixOp { PrefixOp { sigil } @@ -44,3 +54,18 @@ impl PrefixOp { } } } + + +/* the second tuple member is a placeholder for when I want to make evaluation rules tied to the + * binop definition */ +lazy_static! { + static ref BINOPS: HashMap<&'static str, (Type, (), i32)> = + hashmap! { + "+" => (Func(bx!(Const(Int)), bx!(Func(bx!(Const(Int)), bx!(Const(Int))))), (), 10), + "-" => (Func(bx!(Const(Int)), bx!(Func(bx!(Const(Int)), bx!(Const(Int))))), (), 10), + "*" => (Func(bx!(Const(Int)), bx!(Func(bx!(Const(Int)), bx!(Const(Int))))), (), 20), + "/" => (Func(bx!(Const(Int)), bx!(Func(bx!(Const(Int)), bx!(Const(Int))))), (), 20), + "%" => (Func(bx!(Const(Int)), bx!(Func(bx!(Const(Int)), bx!(Const(Int))))), (), 20), + "++" => (Func(bx!(Const(StringT)), bx!(Func(bx!(Const(StringT)), bx!(Const(StringT))))), (), 30), + }; +} diff --git a/src/schala_lang/typechecking.rs b/src/schala_lang/typechecking.rs index a160052..50e641e 100644 --- a/src/schala_lang/typechecking.rs +++ b/src/schala_lang/typechecking.rs @@ -2,7 +2,6 @@ use std::rc::Rc; use std::collections::HashMap; use schala_lang::parsing; -use schala_lang::builtin; pub struct TypeContext { bindings: HashMap, Type> @@ -45,7 +44,7 @@ impl parsing::TypeName { } } -type TypeResult = Result; +pub type TypeResult = Result; impl TypeContext { pub fn new() -> TypeContext { @@ -100,7 +99,7 @@ impl TypeContext { &StringLiteral(_) => Ok(Const(StringT)), &BoolLiteral(_) => Ok(Const(Bool)), &BinExp(ref op, ref lhs, ref rhs) => { /* remember there are both the haskell convention talk and the write you a haskell ways to do this! */ - match self.infer_optype(op)? { + match op.get_type()? { Func(box t1, box Func(box t2, box t3)) => { let lhs_ty = self.infer(lhs)?; let rhs_ty = self.infer(rhs)?; @@ -130,11 +129,6 @@ impl TypeContext { _ => Err(format!("Type not yet implemented")) } } - fn infer_optype(&mut self, _op: &builtin::BinOp) -> TypeResult { - use self::Type::*; use self::TConst::*; - //this is a shim; not all ops are binops from int -> int -> int - Ok(Func(bx!(Const(Int)), bx!(Func(bx!(Const(Int)), bx!(Const(Int)))))) - } fn unify(&mut self, t1: Type, t2: Type) -> TypeResult { use self::Type::*;// use self::TConst::*; match (t1, t2) {