Added type information to binop definitions

Also started centralizing precedence there too
This commit is contained in:
greg 2018-02-24 17:37:23 -08:00
parent df86e0c16e
commit d3ef980dc5
2 changed files with 33 additions and 14 deletions

View File

@ -1,15 +1,14 @@
use std::rc::Rc; 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)] #[derive(Debug, PartialEq, Clone)]
pub struct BinOp { pub struct BinOp {
sigil: Rc<String> sigil: Rc<String>
} }
#[derive(Debug, PartialEq, Clone)]
pub struct PrefixOp {
sigil: Rc<String>
}
impl BinOp { impl BinOp {
pub fn from_sigil(sigil: Rc<String>) -> BinOp { pub fn from_sigil(sigil: Rc<String>) -> BinOp {
BinOp { sigil } BinOp { sigil }
@ -17,10 +16,16 @@ impl BinOp {
pub fn sigil(&self) -> &Rc<String> { pub fn sigil(&self) -> &Rc<String> {
&self.sigil &self.sigil
} }
pub fn get_type(&self) -> TypeResult<Type> {
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 { pub fn min_precedence() -> i32 {
i32::min_value() i32::min_value()
} }
pub fn get_precedence(op: &str) -> i32 { pub fn get_precedence(op: &str) -> i32 {
match op { match op {
"+" | "-" => 10, "+" | "-" => 10,
@ -30,6 +35,11 @@ impl BinOp {
} }
} }
#[derive(Debug, PartialEq, Clone)]
pub struct PrefixOp {
sigil: Rc<String>
}
impl PrefixOp { impl PrefixOp {
pub fn from_sigil(sigil: Rc<String>) -> PrefixOp { pub fn from_sigil(sigil: Rc<String>) -> PrefixOp {
PrefixOp { sigil } 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),
};
}

View File

@ -2,7 +2,6 @@ use std::rc::Rc;
use std::collections::HashMap; use std::collections::HashMap;
use schala_lang::parsing; use schala_lang::parsing;
use schala_lang::builtin;
pub struct TypeContext { pub struct TypeContext {
bindings: HashMap<Rc<String>, Type> bindings: HashMap<Rc<String>, Type>
@ -45,7 +44,7 @@ impl parsing::TypeName {
} }
} }
type TypeResult<T> = Result<T, String>; pub type TypeResult<T> = Result<T, String>;
impl TypeContext { impl TypeContext {
pub fn new() -> TypeContext { pub fn new() -> TypeContext {
@ -100,7 +99,7 @@ impl TypeContext {
&StringLiteral(_) => Ok(Const(StringT)), &StringLiteral(_) => Ok(Const(StringT)),
&BoolLiteral(_) => Ok(Const(Bool)), &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! */ &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)) => { Func(box t1, box Func(box t2, box t3)) => {
let lhs_ty = self.infer(lhs)?; let lhs_ty = self.infer(lhs)?;
let rhs_ty = self.infer(rhs)?; let rhs_ty = self.infer(rhs)?;
@ -130,11 +129,6 @@ impl TypeContext {
_ => Err(format!("Type not yet implemented")) _ => Err(format!("Type not yet implemented"))
} }
} }
fn infer_optype(&mut self, _op: &builtin::BinOp) -> TypeResult<Type> {
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<Type> { fn unify(&mut self, t1: Type, t2: Type) -> TypeResult<Type> {
use self::Type::*;// use self::TConst::*; use self::Type::*;// use self::TConst::*;
match (t1, t2) { match (t1, t2) {