use std::rc::Rc; use std::collections::HashMap; use std::fmt; use crate::tokenizing::TokenKind; use crate::typechecking::{TypeConst, Type}; use crate::typechecking::TypeConst::*; #[derive(Debug, PartialEq, Clone)] pub struct BinOp { sigil: Rc } impl BinOp { pub fn from_sigil(sigil: &str) -> BinOp { BinOp { sigil: Rc::new(sigil.to_string()) } } pub fn sigil(&self) -> &Rc { &self.sigil } pub fn from_sigil_token(tok: &TokenKind) -> Option { use self::TokenKind::*; let s = match tok { Operator(op) => op, Period => ".", Pipe => "|", Slash => "/", LAngleBracket => "<", RAngleBracket => ">", _ => return None }; Some(BinOp::from_sigil(s)) } /* pub fn get_type(&self) -> Result { let s = self.sigil.as_str(); BINOPS.get(s).map(|x| x.0.clone()).ok_or(format!("Binop {} not found", s)) } */ pub fn min_precedence() -> i32 { i32::min_value() } pub fn get_precedence_from_token(op: &TokenKind) -> Option { use self::TokenKind::*; let s = match op { Operator(op) => op, Period => ".", Pipe => "|", Slash => "/", LAngleBracket => "<", RAngleBracket => ">", _ => return None }; let default = 10_000_000; Some(BINOPS.get(s).map(|x| x.2.clone()).unwrap_or_else(|| { default })) } pub fn get_precedence(&self) -> i32 { let s: &str = &self.sigil; let default = 10_000_000; BINOPS.get(s).map(|x| x.2.clone()).unwrap_or_else(|| { default }) } } #[derive(Debug, PartialEq, Clone)] pub struct PrefixOp { sigil: Rc } impl PrefixOp { pub fn from_sigil(sigil: &str) -> PrefixOp { PrefixOp { sigil: Rc::new(sigil.to_string()) } } pub fn sigil(&self) -> &Rc { &self.sigil } pub fn is_prefix(op: &str) -> bool { PREFIX_OPS.get(op).is_some() } /* pub fn get_type(&self) -> Result { let s = self.sigil.as_str(); PREFIX_OPS.get(s).map(|x| x.0.clone()).ok_or(format!("Prefix op {} not found", s)) } */ } //TODO make this macro exportable? macro_rules! mk_type { ($type_name:ident) => { Type::Const(TypeConst::$type_name) }; ($t1:ident -> $t2:ident) => { Type::Arrow(Box::new(mk_type!($t1)), Box::new(mk_type!($t2))) }; ($t1:ident -> $t2:ident -> $t3:ident) => { Type::Arrow(Box::new(mk_type!($t1)), Box::new(mk_type!($t2 -> $t3))) }; } lazy_static! { static ref PREFIX_OPS: HashMap<&'static str, (Type, ())> = hashmap! { "+" => (mk_type!(Int -> Int), ()), "-" => (mk_type!(Int -> Int), ()), "!" => (mk_type!(Bool -> Bool), ()), }; } /* the second tuple member is a placeholder for when I want to make evaluation rules tied to the * binop definition */ //TODO some of these types are going to have to be adjusted lazy_static! { static ref BINOPS: HashMap<&'static str, (Type, (), i32)> = hashmap! { "+" => (mk_type!(Nat -> Nat -> Nat), (), 10), "-" => (mk_type!(Nat -> Nat -> Nat), (), 10), "*" => (mk_type!(Nat -> Nat -> Nat), (), 20), "/" => (mk_type!(Nat -> Nat -> Float), (), 20), "quot" => (mk_type!(Nat -> Nat -> Nat), (), 20), "%" => (mk_type!(Nat -> Nat -> Nat), (), 20), "++" => (mk_type!(StringT -> StringT -> StringT), (), 30), "^" => (mk_type!(Nat -> Nat -> Nat), (), 20), "&" => (mk_type!(Nat -> Nat -> Nat), (), 20), "|" => (mk_type!(Nat -> Nat -> Nat), (), 20), ">" => (mk_type!(Nat -> Nat -> Bool), (), 20), ">=" => (mk_type!(Nat -> Nat -> Bool), (), 20), "<" => (mk_type!(Nat -> Nat -> Bool), (), 20), "<=" => (mk_type!(Nat -> Nat -> Bool), (), 20), "==" => (mk_type!(Nat -> Nat -> Bool), (), 20), "=" => (mk_type!(Unit), (), 20), //TODO not sure what the type of this should be b/c special fmr "<=>" => (mk_type!(Nat -> Nat -> Ordering), (), 20), //TODO figure out how to treat Order }; }