diff --git a/builtins/src/lib.rs b/builtins/src/lib.rs index d84e4e36..22aa1280 100644 --- a/builtins/src/lib.rs +++ b/builtins/src/lib.rs @@ -55,6 +55,14 @@ impl BuiltinType { } } +trait BuiltinOperator: Sized { + fn as_str(&self) -> &'static str; + + fn ty(&self) -> BuiltinType; + + fn iter() -> slice::Iter<'static, Self>; +} + pub enum Arithmetic { Add, Sub, @@ -62,8 +70,28 @@ pub enum Arithmetic { Div, } -impl Arithmetic { - pub fn as_str(&self) -> &'static str { +pub enum Mode { + OrEqual, + Strict, +} + +pub enum Equality { + Equals, + Differs, +} + +pub enum Comparison { + LessThan(Mode), + GreaterThan(Mode), +} + +pub enum Unary { + Not, + Minus, +} + +impl BuiltinOperator for Arithmetic { + fn as_str(&self) -> &'static str { match self { Arithmetic::Add => name::ADD, Arithmetic::Sub => name::SUB, @@ -72,7 +100,11 @@ impl Arithmetic { } } - pub fn iter() -> slice::Iter<'static, Arithmetic> { + fn ty(&self) -> BuiltinType { + BuiltinType::Number + } + + fn iter() -> slice::Iter<'static, Arithmetic> { static VALUES: &[Arithmetic] = &[ Arithmetic::Add, Arithmetic::Sub, @@ -84,23 +116,9 @@ impl Arithmetic { } } -pub enum Mode { - OrEqual, - Strict, -} - -pub enum Comparison { - Equals, - Differs, - LessThan(Mode), - GreaterThan(Mode), -} - -impl Comparison { - pub fn as_str(&self) -> &'static str { +impl BuiltinOperator for Comparison { + fn as_str(&self) -> &'static str { match self { - Comparison::Equals => name::EQ, - Comparison::Differs => name::NE, Comparison::LessThan(Mode::Strict) => name::LT, Comparison::LessThan(Mode::OrEqual) => name::LTE, Comparison::GreaterThan(Mode::Strict) => name::GT, @@ -108,10 +126,12 @@ impl Comparison { } } - pub fn iter() -> slice::Iter<'static, Comparison> { + fn ty(&self) -> BuiltinType { + BuiltinType::Comparable + } + + fn iter() -> slice::Iter<'static, Comparison> { static VALUES: &[Comparison] = &[ - Comparison::Equals, - Comparison::Differs, Comparison::LessThan(Mode::Strict), Comparison::LessThan(Mode::OrEqual), Comparison::GreaterThan(Mode::Strict), @@ -122,27 +142,41 @@ impl Comparison { } } -pub enum Unary { - Not, - Minus, +impl BuiltinOperator for Equality { + fn as_str(&self) -> &'static str { + match self { + Equality::Equals => name::EQ, + Equality::Differs => name::NE, + } + } + + fn ty(&self) -> BuiltinType { + BuiltinType::Equalable + } + + fn iter() -> slice::Iter<'static, Equality> { + static VALUES: &[Equality] = &[Equality::Equals, Equality::Differs]; + + VALUES.iter() + } } -impl Unary { - pub fn as_str(&self) -> &'static str { +impl BuiltinOperator for Unary { + fn as_str(&self) -> &'static str { match self { Unary::Not => name::NOT, Unary::Minus => name::MIN, } } - pub fn ty(&self) -> BuiltinType { + fn ty(&self) -> BuiltinType { match self { Unary::Not => BuiltinType::Bool, Unary::Minus => BuiltinType::Number, } } - pub fn iter() -> slice::Iter<'static, Unary> { + fn iter() -> slice::Iter<'static, Unary> { static VALUES: &[Unary] = &[Unary::Not, Unary::Minus]; VALUES.iter() @@ -151,6 +185,7 @@ impl Unary { pub enum Operator { Arithmetic(Arithmetic), + Equality(Equality), Comparison(Comparison), Unary(Unary), } @@ -160,24 +195,24 @@ impl Operator { match self { Operator::Arithmetic(inner) => inner.as_str(), Operator::Comparison(inner) => inner.as_str(), + Operator::Equality(inner) => inner.as_str(), Operator::Unary(inner) => inner.as_str(), } } pub fn ty(&self) -> BuiltinType { match self { - Operator::Arithmetic(_) => BuiltinType::Number, - Operator::Comparison(Comparison::Equals) - | Operator::Comparison(Comparison::Differs) => BuiltinType::Equalable, - Operator::Comparison(_) => BuiltinType::Comparable, - Operator::Unary(Unary::Not) => BuiltinType::Bool, - Operator::Unary(Unary::Minus) => BuiltinType::Number, + Operator::Arithmetic(inner) => inner.ty(), + Operator::Equality(inner) => inner.ty(), + Operator::Comparison(inner) => inner.ty(), + Operator::Unary(inner) => inner.ty(), } } pub fn try_from_str(s: &str) -> Option { use Arithmetic::*; use Comparison::*; + use Equality::*; use Unary::*; use Operator as Op; @@ -188,8 +223,8 @@ impl Operator { name::MUL => Some(Op::Arithmetic(Mul)), name::DIV => Some(Op::Arithmetic(Div)), - name::EQ => Some(Op::Comparison(Equals)), - name::NE => Some(Op::Comparison(Differs)), + name::EQ => Some(Op::Equality(Equals)), + name::NE => Some(Op::Equality(Differs)), name::LT => Some(Op::Comparison(LessThan(Mode::Strict))), name::LTE => Some(Op::Comparison(LessThan(Mode::OrEqual))), name::GT => Some(Op::Comparison(GreaterThan(Mode::Strict))), @@ -226,11 +261,15 @@ impl AppendAstBuiltins for Ast { ), ( BuiltinType::Comparable, + vec![builder::type_symbol("int"), builder::type_symbol("char")], + ), + ( + BuiltinType::Equalable, vec![ builder::type_symbol("int"), - builder::type_symbol("float"), builder::type_symbol("char"), builder::type_symbol("bool"), + builder::type_symbol("string"), ], ), ] diff --git a/fire/src/outside.rs b/fire/src/outside.rs index e493e9b9..e5e06958 100644 --- a/fire/src/outside.rs +++ b/fire/src/outside.rs @@ -9,6 +9,7 @@ use builtins::Operator; use builtins::Arithmetic::*; use builtins::Comparison::*; +use builtins::Equality::*; use builtins::Mode::*; use builtins::Unary::*; @@ -54,8 +55,8 @@ pub fn perform_call( fn bool_ops(lhs: &bool, rhs: &bool, op: builtins::Operator) -> Instance { match op { Operator::Unary(Not) => Instance::from(!lhs), - Operator::Comparison(Equals) => Instance::from(lhs == rhs), - Operator::Comparison(Differs) => Instance::from(lhs != rhs), + Operator::Equality(Equals) => Instance::from(lhs == rhs), + Operator::Equality(Differs) => Instance::from(lhs != rhs), _ => unreachable!( "invalid operation on booleans: `{}`. this is an intepreter error", op.as_str() @@ -72,8 +73,8 @@ fn int_ops(lhs: &i64, rhs: &i64, op: builtins::Operator) -> Instance { Operator::Arithmetic(Div) => Instance::from(lhs / rhs), Operator::Unary(Minus) => Instance::from(-lhs), // operations returning booleans - Operator::Comparison(Equals) => Instance::from(lhs == rhs), - Operator::Comparison(Differs) => Instance::from(lhs != rhs), + Operator::Equality(Equals) => Instance::from(lhs == rhs), + Operator::Equality(Differs) => Instance::from(lhs != rhs), Operator::Comparison(LessThan(Strict)) => Instance::from(lhs < rhs), Operator::Comparison(LessThan(OrEqual)) => Instance::from(lhs <= rhs), Operator::Comparison(GreaterThan(Strict)) => Instance::from(lhs > rhs), @@ -87,8 +88,8 @@ fn int_ops(lhs: &i64, rhs: &i64, op: builtins::Operator) -> Instance { fn char_ops(lhs: &char, rhs: &char, op: builtins::Operator) -> Instance { match op { - Operator::Comparison(Equals) => Instance::from(lhs == rhs), - Operator::Comparison(Differs) => Instance::from(lhs != rhs), + Operator::Equality(Equals) => Instance::from(lhs == rhs), + Operator::Equality(Differs) => Instance::from(lhs != rhs), Operator::Comparison(LessThan(Strict)) => Instance::from(lhs < rhs), Operator::Comparison(LessThan(OrEqual)) => Instance::from(lhs <= rhs), Operator::Comparison(GreaterThan(Strict)) => Instance::from(lhs > rhs), @@ -109,8 +110,8 @@ fn float_ops(lhs: &f64, rhs: &f64, op: builtins::Operator) -> Instance { Operator::Arithmetic(Div) => Instance::from(lhs / rhs), Operator::Unary(Minus) => Instance::from(-lhs), // operationrs returning booleans - Operator::Comparison(Equals) => Instance::from(lhs == rhs), - Operator::Comparison(Differs) => Instance::from(lhs != rhs), + Operator::Equality(Equals) => Instance::from(lhs == rhs), + Operator::Equality(Differs) => Instance::from(lhs != rhs), Operator::Comparison(LessThan(Strict)) => Instance::from(lhs < rhs), Operator::Comparison(LessThan(OrEqual)) => Instance::from(lhs <= rhs), Operator::Comparison(GreaterThan(Strict)) => Instance::from(lhs > rhs), @@ -124,8 +125,8 @@ fn float_ops(lhs: &f64, rhs: &f64, op: builtins::Operator) -> Instance { fn string_ops(lhs: &str, rhs: &str, op: builtins::Operator) -> Instance { match op { - Operator::Comparison(Equals) => Instance::from(lhs == rhs), - Operator::Comparison(Differs) => Instance::from(lhs != rhs), + Operator::Equality(Equals) => Instance::from(lhs == rhs), + Operator::Equality(Differs) => Instance::from(lhs != rhs), _ => unreachable!( "invalid operation on strings: `{}`. this is an intepreter error", op.as_str() diff --git a/typecheck/src/checker.rs b/typecheck/src/checker.rs index 29fb7d67..c0a33f6f 100644 --- a/typecheck/src/checker.rs +++ b/typecheck/src/checker.rs @@ -11,7 +11,6 @@ use location::SpanTuple; use std::iter::Iterator; -use builtins::Comparison::*; use builtins::Unary::*; use crate::typemap::TypeMap; @@ -46,6 +45,9 @@ impl<'ctx> Checker<'ctx> { ) -> Result, Error> { use builtins::*; + // TODO: Can we do something else here? + // the `union_type` function used to create builtins now actually creates proper unions, so we could maybe reuse that? + // so check out builtins::builder::union_type let numbers = [ RefIdx::Resolved(self.0.primitives.int_type), RefIdx::Resolved(self.0.primitives.float_type), @@ -82,7 +84,7 @@ impl<'ctx> Checker<'ctx> { .find(|set| set.is_superset_of(lhs_type)); let arity = match op { - Operator::Arithmetic(_) | Operator::Comparison(_) => 2, + Operator::Arithmetic(_) | Operator::Comparison(_) | Operator::Equality(_) => 2, Operator::Unary(_) => 1, }; @@ -90,9 +92,7 @@ impl<'ctx> Checker<'ctx> { // FIXME: We should probably move it to `unexpected_arith_type` since it's only used there let valid_union_type = match op { Operator::Arithmetic(_) => Type::builtin(numbers.into_iter().collect()), - Operator::Comparison(Equals) | Operator::Comparison(Differs) => { - Type::builtin(equalable.into_iter().collect()) - } + Operator::Equality(_) => Type::builtin(equalable.into_iter().collect()), Operator::Unary(Minus) => Type::builtin(numbers.into_iter().collect()), Operator::Comparison(_) => Type::builtin(comparable.into_iter().collect()), Operator::Unary(Not) => Type::builtin(comparable.into_iter().collect()), diff --git a/typecheck/src/typer.rs b/typecheck/src/typer.rs index 73a11a63..0760b23c 100644 --- a/typecheck/src/typer.rs +++ b/typecheck/src/typer.rs @@ -51,7 +51,7 @@ impl<'ctx> Typer<'ctx> { match op { Operator::Arithmetic(_) | Operator::Unary(Unary::Minus) => args[0], - Operator::Comparison(_) | Operator::Unary(Unary::Not) => { + Operator::Comparison(_) | Operator::Unary(Unary::Not) | Operator::Equality(_) => { RefIdx::Resolved(self.0.primitives.bool_type) } }