Skip to content

Commit

Permalink
builtins: Cleanup operators and add Equality kind
Browse files Browse the repository at this point in the history
  • Loading branch information
CohenArthur committed Sep 25, 2024
1 parent e3ddd4b commit 3804872
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 55 deletions.
129 changes: 90 additions & 39 deletions builtins/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::slice;
mod builder;

pub const TYPE_COMPARABLE: &str = "builtin.comparable";
pub const TYPE_EQUALABLE: &str = "builtin.comparable";
pub const TYPE_EQUALABLE: &str = "builtin.equalable";
pub const TYPE_NUMBER: &str = "builtin.number";

macro_rules! name {
Expand Down Expand Up @@ -55,15 +55,43 @@ 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,
Mul,
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,
Expand All @@ -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,
Expand All @@ -84,34 +116,22 @@ 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,
Comparison::GreaterThan(Mode::OrEqual) => name::GTE,
}
}

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),
Expand All @@ -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()
Expand All @@ -151,6 +185,7 @@ impl Unary {

pub enum Operator {
Arithmetic(Arithmetic),
Equality(Equality),
Comparison(Comparison),
Unary(Unary),
}
Expand All @@ -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<Operator> {
use Arithmetic::*;
use Comparison::*;
use Equality::*;
use Unary::*;

use Operator as Op;
Expand All @@ -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))),
Expand Down Expand Up @@ -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"),
],
),
]
Expand All @@ -249,6 +288,17 @@ impl AppendAstBuiltins for Ast {
)
});

let eq_builtins = Equality::iter().map(|op| {
builder::function(
op.as_str(),
vec![
builder::argument("lhs", builder::builtin_type_symbol(BuiltinType::Comparable)),
builder::argument("rhs", builder::builtin_type_symbol(BuiltinType::Comparable)),
],
Some(builder::builtin_type_symbol(BuiltinType::Bool)),
)
});

let cmp_builtins = Comparison::iter().map(|op| {
builder::function(
op.as_str(),
Expand Down Expand Up @@ -276,6 +326,7 @@ impl AppendAstBuiltins for Ast {
// potential last expression of the `stmts` to not be the last expression anymore
new_stmts.extend(builtin_types);
new_stmts.extend(arithmetic_builtins);
new_stmts.extend(eq_builtins);
new_stmts.extend(cmp_builtins);
new_stmts.extend(unary_builtins);

Expand Down
21 changes: 11 additions & 10 deletions fire/src/outside.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use builtins::Operator;

use builtins::Arithmetic::*;
use builtins::Comparison::*;
use builtins::Equality::*;
use builtins::Mode::*;
use builtins::Unary::*;

Expand Down Expand Up @@ -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()
Expand All @@ -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),
Expand All @@ -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),
Expand All @@ -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),
Expand All @@ -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()
Expand Down
10 changes: 5 additions & 5 deletions typecheck/src/checker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use location::SpanTuple;

use std::iter::Iterator;

use builtins::Comparison::*;
use builtins::Unary::*;

use crate::typemap::TypeMap;
Expand Down Expand Up @@ -46,6 +45,9 @@ impl<'ctx> Checker<'ctx> {
) -> Result<Vec<Type>, 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),
Expand Down Expand Up @@ -82,17 +84,15 @@ 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,
};

// FIXME: Clean that up
// 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()),
Expand Down
2 changes: 1 addition & 1 deletion typecheck/src/typer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand Down

0 comments on commit 3804872

Please sign in to comment.