From 68294f44faa3d52674122623d8b52596c3e1fea1 Mon Sep 17 00:00:00 2001 From: Kubat <maelle.martin@proton.me> Date: Thu, 1 May 2025 14:46:03 +0200 Subject: [PATCH] [AST] Separate the BinOp into three categories to ease the implementation of binop evaluation --- grimoire/src/ast/expr.rs | 162 ++++++++++++++------------ grimoire/src/ast/mod.rs | 1 + grimoire/src/ast/operator.rs | 159 ++++++++++++++++++++++++++ grimoire/src/parser/expr.rs | 67 ++++++----- grimoire/src/state.rs | 213 +++++++++++++++++++++++++++-------- grimoire/src/types.rs | 4 + 6 files changed, 466 insertions(+), 140 deletions(-) create mode 100644 grimoire/src/ast/operator.rs diff --git a/grimoire/src/ast/expr.rs b/grimoire/src/ast/expr.rs index ff04c04..7a6f74c 100644 --- a/grimoire/src/ast/expr.rs +++ b/grimoire/src/ast/expr.rs @@ -1,5 +1,9 @@ +use crate::{ + ast::{AstSpan, operator}, + error::Error, + types::Type, +}; use derive_more::Display; -use crate::ast::AstSpan; #[derive(Debug, Clone, PartialEq, Display)] pub enum Const { @@ -22,6 +26,92 @@ pub enum Const { Ident(String), } +impl Const { + pub fn is_null(&self) -> bool { + match self { + Const::Int(x) => *x == 0, + Const::Flt(x) => x.abs() <= f32::EPSILON, + Const::Str(x) => x.is_empty() || *x == "false" || *x == "null", + Const::Bool(x) => *x, + Const::Ident(x) => *x == "Null", + } + } + + pub fn unwrap_identifier(self) -> String { + match self { + Const::Ident(x) => x, + x => panic!("can't unwrap {x} as i32"), + } + } + + pub fn unwrap_boolean(self) -> bool { + !self.is_null() + } + + pub fn unwrap_integer(self) -> i32 { + match self { + Const::Int(x) => x, + Const::Flt(x) => x as i32, + Const::Bool(x) => x as i32, + x => panic!("can't unwrap {x} as i32"), + } + } + + pub fn unwrap_float(self) -> f32 { + match self { + Const::Int(x) => x as f32, + Const::Flt(x) => x, + Const::Bool(true) => 1., + Const::Bool(false) => 0., + x => panic!("can't unwrap {x} as i32"), + } + } + + pub fn cast_into(self, ty: Type) -> Result<Self, Error> { + if ty == Type::Boolean { + return Ok(Self::Bool(self.unwrap_boolean())); + } + match self { + Self::Int(x) => match ty { + Type::Float => Ok(Self::Flt(x as f32)), + Type::String => Ok(Self::Str(x.to_string())), + Type::Number | Type::Integer => Ok(Self::Int(x)), + ty => Err(Error::CantCast(Self::Int(x), ty)), + }, + + Self::Flt(x) => match ty { + Type::Number | Type::Float => Ok(Self::Flt(x)), + Type::String => Ok(Self::Str(x.to_string())), + Type::Integer => Ok(Self::Int(x as i32)), + ty => Err(Error::CantCast(Self::Flt(x), ty)), + }, + + Self::Bool(x) => match ty { + Type::Float => Ok(Self::Flt(if x { 0. } else { 1. })), + Type::String => Ok(Self::Str(x.to_string())), + Type::Number | Type::Integer => Ok(Self::Int(x as i32)), + ty => Err(Error::CantCast(Self::Bool(x), ty)), + }, + + Self::Str(x) => match ty { + Type::String => Ok(Self::Str(x)), + Type::Number => str::parse::<f32>(&x) + .map(Self::Flt) + .or_else(|_| str::parse::<i32>(&x).map(Self::Int)) + .map_err(|_| Error::CantCast(Self::Str(x), Type::Number)), + Type::Float => str::parse::<f32>(&x).map(Self::Flt).map_err(Into::into), + Type::Integer => str::parse::<i32>(&x).map(Self::Int).map_err(Into::into), + _ => unreachable!(), + }, + + Self::Ident(x) => match ty { + Type::Identifier | Type::Actor | Type::Printer => Ok(Self::Ident(x)), + ty => Err(Error::CantCast(Self::Ident(x), ty)), + }, + } + } +} + #[derive(Debug, Clone, PartialEq, Display)] pub enum VarOrConst { /// A [Const]. @@ -56,73 +146,7 @@ impl VarOrConst { #[derive(Debug)] pub enum Expression { - Binary(AstSpan, Box<Expression>, BinOp, Box<Expression>), - Unary(AstSpan, UnOp, Box<Expression>), + Binary(AstSpan, Box<Expression>, operator::Binary, Box<Expression>), + Unary(AstSpan, operator::Unary, Box<Expression>), Leaf(AstSpan, VarOrConst), } - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum UnOp { - Not, - Neg, -} - -impl UnOp { - pub fn as_str(&self) -> &'static str { - match self { - UnOp::Not => "!", - UnOp::Neg => "-", - } - } -} - -impl AsRef<str> for UnOp { - fn as_ref(&self) -> &str { - self.as_str() - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum BinOp { - Add, - Sub, - Mul, - Div, - Mod, - CompGE, - CompGT, - CompLT, - CompLE, - Or, - And, - Xor, - CompEQ, - CompNEQ, -} - -impl BinOp { - pub fn as_str(&self) -> &'static str { - match self { - BinOp::Add => "+", - BinOp::Sub => "-", - BinOp::Mul => "*", - BinOp::Div => "/", - BinOp::Mod => "%", - BinOp::CompGE => ">=", - BinOp::CompGT => ">", - BinOp::CompLT => "<=", - BinOp::CompLE => "<", - BinOp::Or => "|", - BinOp::And => "&", - BinOp::Xor => "^", - BinOp::CompEQ => "=", - BinOp::CompNEQ => "!=", - } - } -} - -impl AsRef<str> for BinOp { - fn as_ref(&self) -> &str { - self.as_str() - } -} diff --git a/grimoire/src/ast/mod.rs b/grimoire/src/ast/mod.rs index 19b1f1b..2fa8585 100644 --- a/grimoire/src/ast/mod.rs +++ b/grimoire/src/ast/mod.rs @@ -1,4 +1,5 @@ pub mod expr; +pub mod operator; mod span; pub use span::Span as AstSpan; diff --git a/grimoire/src/ast/operator.rs b/grimoire/src/ast/operator.rs new file mode 100644 index 0000000..5537fff --- /dev/null +++ b/grimoire/src/ast/operator.rs @@ -0,0 +1,159 @@ +use derive_more::Display; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Display)] +#[display("{op}", op = self.as_str())] +pub enum Unary { + Not, + Neg, +} + +impl Unary { + pub fn as_str(&self) -> &'static str { + match self { + Unary::Not => "!", + Unary::Neg => "-", + } + } +} + +impl AsRef<str> for Unary { + fn as_ref(&self) -> &str { + self.as_str() + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Display)] +#[display("{op}", op = self.as_str())] +pub enum Numeric { + Add, + Sub, + Mul, + Div, + Mod, + CompGE, + CompGT, + CompLT, + CompLE, +} + +impl Numeric { + pub fn as_str(&self) -> &'static str { + match self { + Numeric::Add => "+", + Numeric::Sub => "-", + Numeric::Mul => "*", + Numeric::Div => "/", + Numeric::Mod => "%", + Numeric::CompGE => ">=", + Numeric::CompGT => ">", + Numeric::CompLT => "<=", + Numeric::CompLE => "<", + } + } +} + +impl AsRef<str> for Numeric { + fn as_ref(&self) -> &str { + self.as_str() + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Display)] +#[display("{op}", op = self.as_str())] +pub enum Logic { + Or, + And, + Xor, +} + +impl Logic { + pub fn as_str(&self) -> &'static str { + match self { + Logic::Or => "|", + Logic::And => "&", + Logic::Xor => "^", + } + } +} + +impl AsRef<str> for Logic { + fn as_ref(&self) -> &str { + self.as_str() + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Display)] +#[display("{op}", op = self.as_str())] +pub enum Equal { + CompEQ, + CompNEQ, +} + +impl Equal { + pub fn as_str(&self) -> &'static str { + match self { + Equal::CompEQ => "=", + Equal::CompNEQ => "!=", + } + } + + pub fn apply(self, eq_res: bool) -> bool { + (self.check_equals() && eq_res) || (self.check_not_equals() && !eq_res) + } + + pub fn check_equals(self) -> bool { + !self.check_not_equals() + } + + pub fn check_not_equals(self) -> bool { + matches!(self, Equal::CompNEQ) + } +} + +impl AsRef<str> for Equal { + fn as_ref(&self) -> &str { + self.as_str() + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Display)] +#[display("{op}", op = self.as_str())] +pub enum Binary { + Numeric(Numeric), + Logic(Logic), + Equal(Equal), +} + +impl Binary { + pub fn as_str(&self) -> &'static str { + match self { + Binary::Numeric(op) => op.as_str(), + Binary::Logic(op) => op.as_str(), + Binary::Equal(op) => op.as_str(), + } + } +} + +impl AsRef<str> for Binary { + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl From<Numeric> for Binary { + fn from(value: Numeric) -> Self { + Binary::Numeric(value) + } +} + +impl From<Logic> for Binary { + fn from(value: Logic) -> Self { + Binary::Logic(value) + } +} + +impl From<Equal> for Binary { + fn from(value: Equal) -> Self { + Binary::Equal(value) + } +} diff --git a/grimoire/src/parser/expr.rs b/grimoire/src/parser/expr.rs index 340f2be..d4849ad 100644 --- a/grimoire/src/parser/expr.rs +++ b/grimoire/src/parser/expr.rs @@ -1,5 +1,5 @@ use crate::{ - ast::{AstSpan, expr::*}, + ast::{AstSpan, expr::*, operator}, parser::*, }; use nom::{ @@ -32,8 +32,8 @@ fn var_or_constant(s: Span) -> ParserResult<Expression> { fn leaf(s: Span) -> ParserResult<Expression> { // Note: the order is important! alt(( - unop(UnOp::Not, expression), - unop(UnOp::Neg, expression), + unop(operator::Unary::Not, expression), + unop(operator::Unary::Neg, expression), utils::parse_paren(expression), var_or_constant, )) @@ -41,7 +41,7 @@ fn leaf(s: Span) -> ParserResult<Expression> { } fn unop<'a>( - op: UnOp, + op: operator::Unary, next: impl Parser<Span<'a>, Output = Expression, Error = ParserError>, ) -> impl Parser<Span<'a>, Output = Expression, Error = ParserError> { utils::map_with_locaiton( @@ -51,17 +51,29 @@ fn unop<'a>( } fn binop<'a>( - op: BinOp, + op: impl Into<operator::Binary>, next: impl Parser<Span<'a>, Output = Expression, Error = ParserError>, -) -> impl Parser<Span<'a>, Output = (AstSpan, BinOp, Expression), Error = ParserError> { - preceded( - multispace0, - utils::with_location((map(tag(op.as_str()), move |_| op), next)) - .map(|(ast_span, (op, expr))| (ast_span, op, expr)), - ) +) -> impl Parser<Span<'a>, Output = (AstSpan, operator::Binary, Expression), Error = ParserError> { + // Used to mitigate the impact of monomorphisation. + fn aux<'a>( + op: operator::Binary, + next: impl Parser<Span<'a>, Output = Expression, Error = ParserError>, + ) -> impl Parser<Span<'a>, Output = (AstSpan, operator::Binary, Expression), Error = ParserError> + { + preceded( + multispace0, + utils::with_location((map(tag(op.as_str()), move |_| op), next)) + .map(|(ast_span, (op, expr))| (ast_span, op, expr)), + ) + } + + aux(op.into(), next) } -fn fold_exprs(initial: Expression, remainder: Vec<(AstSpan, BinOp, Expression)>) -> Expression { +fn fold_exprs( + initial: Expression, + remainder: Vec<(AstSpan, operator::Binary, Expression)>, +) -> Expression { remainder .into_iter() .fold(initial, |acc, (ast_span, op, expr)| { @@ -72,9 +84,9 @@ fn fold_exprs(initial: Expression, remainder: Vec<(AstSpan, BinOp, Expression)>) fn terms(s: Span) -> ParserResult<Expression> { let (s, initial) = leaf(s)?; let (s, remainder): (Span, Vec<_>) = many0(alt(( - binop(BinOp::Mul, leaf), - binop(BinOp::Div, leaf), - binop(BinOp::Mod, leaf), + binop(operator::Numeric::Mul, leaf), + binop(operator::Numeric::Div, leaf), + binop(operator::Numeric::Mod, leaf), ))) .parse(s)?; Ok((s, fold_exprs(initial, remainder))) @@ -82,22 +94,25 @@ fn terms(s: Span) -> ParserResult<Expression> { fn sums(s: Span) -> ParserResult<Expression> { let (s, initial) = terms(s)?; - let (s, remainder) = - many0(alt((binop(BinOp::Add, terms), binop(BinOp::Sub, terms)))).parse(s)?; + let (s, remainder) = many0(alt(( + binop(operator::Numeric::Add, terms), + binop(operator::Numeric::Sub, terms), + ))) + .parse(s)?; Ok((s, fold_exprs(initial, remainder))) } fn logic_terms(s: Span) -> ParserResult<Expression> { let (s, initial) = sums(s)?; - let (s, remainder) = many0(binop(BinOp::And, sums)).parse(s)?; + let (s, remainder) = many0(binop(operator::Logic::And, sums)).parse(s)?; Ok((s, fold_exprs(initial, remainder))) } fn logic_sums(s: Span) -> ParserResult<Expression> { let (s, initial) = logic_terms(s)?; let (s, remainder) = many0(alt(( - binop(BinOp::Xor, logic_terms), - binop(BinOp::Or, logic_terms), + binop(operator::Logic::Xor, logic_terms), + binop(operator::Logic::Or, logic_terms), ))) .parse(s)?; Ok((s, fold_exprs(initial, remainder))) @@ -106,10 +121,10 @@ fn logic_sums(s: Span) -> ParserResult<Expression> { fn logic_comp(s: Span) -> ParserResult<Expression> { let (s, initial) = logic_sums(s)?; let (s, remainder) = many0(alt(( - binop(BinOp::CompLE, logic_sums), - binop(BinOp::CompGE, logic_sums), - binop(BinOp::CompLT, logic_sums), - binop(BinOp::CompGT, logic_sums), + binop(operator::Numeric::CompLE, logic_sums), + binop(operator::Numeric::CompGE, logic_sums), + binop(operator::Numeric::CompLT, logic_sums), + binop(operator::Numeric::CompGT, logic_sums), ))) .parse(s)?; Ok((s, fold_exprs(initial, remainder))) @@ -118,8 +133,8 @@ fn logic_comp(s: Span) -> ParserResult<Expression> { pub fn expression(s: Span) -> ParserResult<Expression> { let (s, initial) = logic_comp(s)?; let (s, remainder) = many0(alt(( - binop(BinOp::CompEQ, logic_comp), - binop(BinOp::CompNEQ, logic_comp), + binop(operator::Equal::CompEQ, logic_comp), + binop(operator::Equal::CompNEQ, logic_comp), ))) .parse(s)?; Ok((s, fold_exprs(initial, remainder))) diff --git a/grimoire/src/state.rs b/grimoire/src/state.rs index 3fa2f57..1dec380 100644 --- a/grimoire/src/state.rs +++ b/grimoire/src/state.rs @@ -1,5 +1,8 @@ use crate::{ - ast::expr::{Const, Expression}, + ast::{ + expr::{Const, Expression, VarOrConst}, + operator, + }, error::Error, types::Type, }; @@ -22,55 +25,175 @@ impl State { .ok_or_else(|| Error::Undefined(var.as_ref().to_string())) } - pub fn evaluate(&self, expr: Expression) -> Result<Const, Error> { - todo!() + fn evaluate_numeric_binop( + &self, + left: Expression, + op: operator::Numeric, + right: Expression, + ) -> Result<Const, Error> { + let left = self.evaluate_as(left, Type::Number)?; + let right = self.evaluate_as(right, Type::Number)?; + + match matches!(left, Const::Flt(_)) || matches!(right, Const::Flt(_)) { + // Use float operations + true => { + let left = left.unwrap_float(); + let right = right.unwrap_float(); + match op { + operator::Numeric::Add => Ok(Const::Flt(left + right)), + operator::Numeric::Sub => Ok(Const::Flt(left - right)), + operator::Numeric::Mul => Ok(Const::Flt(left * right)), + operator::Numeric::CompGE => Ok(Const::Bool(left >= right)), + operator::Numeric::CompGT => Ok(Const::Bool(left > right)), + operator::Numeric::CompLT => Ok(Const::Bool(left < right)), + operator::Numeric::CompLE => Ok(Const::Bool(left <= right)), + + operator::Numeric::Div if right.abs() >= f32::EPSILON => { + Ok(Const::Flt(left / right)) + } + operator::Numeric::Mod if right.abs() >= f32::EPSILON => { + Ok(Const::Flt(left % right)) + } + + operator::Numeric::Div => Ok(Const::Flt(f32::NAN)), + operator::Numeric::Mod => Ok(Const::Flt(f32::NAN)), + } + } + + // Use integer operations + false => { + let left = left.unwrap_integer(); + let right = right.unwrap_integer(); + match op { + operator::Numeric::Add => Ok(Const::Int(left + right)), + operator::Numeric::Sub => Ok(Const::Int(left - right)), + operator::Numeric::Mul => Ok(Const::Int(left * right)), + operator::Numeric::CompGE => Ok(Const::Bool(left >= right)), + operator::Numeric::CompGT => Ok(Const::Bool(left > right)), + operator::Numeric::CompLT => Ok(Const::Bool(left < right)), + operator::Numeric::CompLE => Ok(Const::Bool(left <= right)), + + operator::Numeric::Div if right != 0 => Ok(Const::Int(left / right)), + operator::Numeric::Mod if right != 0 => Ok(Const::Int(left % right)), + + operator::Numeric::Div => Ok(Const::Flt(f32::NAN)), + operator::Numeric::Mod => Ok(Const::Flt(f32::NAN)), + } + } + } } - pub fn evaluate_as(&self, expr: Expression, ty: Type) -> Result<Const, Error> { - match self.evaluate(expr)? { - Const::Int(x) => match ty { - Type::Float => Ok(Const::Flt(x as f32)), - Type::String => Ok(Const::Str(x.to_string())), - Type::Boolean => Ok(Const::Bool(x != 0)), - Type::Integer => Ok(Const::Int(x)), - ty => Err(Error::CantCast(Const::Int(x), ty)), - }, - Const::Flt(x) => match ty { - Type::Float => Ok(Const::Flt(x)), - Type::String => Ok(Const::Str(x.to_string())), - Type::Boolean => Ok(Const::Bool(x.abs() <= f32::EPSILON)), - Type::Integer => Ok(Const::Int(x as i32)), - ty => Err(Error::CantCast(Const::Flt(x), ty)), - }, - Const::Bool(x) => match ty { - Type::Float => Ok(Const::Flt(if x { 0. } else { 1. })), - Type::String => Ok(Const::Str(x.to_string())), - Type::Boolean => Ok(Const::Bool(x)), - Type::Integer => Ok(Const::Int(x as i32)), - ty => Err(Error::CantCast(Const::Bool(x), ty)), - }, - Const::Str(x) => match ty { - Type::String => Ok(Const::Str(x)), - Type::Float => str::parse::<f32>(&x).map(Const::Flt).map_err(Into::into), - Type::Integer => str::parse::<i32>(&x).map(Const::Int).map_err(Into::into), - Type::Boolean => str::parse::<bool>(&x).map(Const::Bool).map_err(Into::into), - Type::Identifier | Type::Actor | Type::Printer => unreachable!(), + fn evaluate_logic_binop( + &self, + left: Expression, + op: operator::Logic, + right: Expression, + ) -> Result<Const, Error> { + // Here we evaluate eagerly to catch errors! + let left = self.evaluate_as(left, Type::Boolean)?.unwrap_boolean(); + let right = self.evaluate_as(right, Type::Boolean)?.unwrap_boolean(); + Ok(Const::Bool(match op { + operator::Logic::Or => left || right, + operator::Logic::And => left && right, + operator::Logic::Xor => left ^ right, + })) + } + + fn evaluate_equal_binop( + &self, + left: Expression, + op: operator::Equal, + right: Expression, + ) -> Result<Const, Error> { + Ok(Const::Bool( + match (self.evaluate(left)?, self.evaluate(right)?) { + // Easy! + (Const::Int(x), Const::Int(y)) => op.apply(x == y), + (Const::Flt(x), Const::Flt(y)) => op.apply(x == y), + (Const::Bool(x), Const::Bool(y)) => op.apply(x == y), + + (Const::Str(x), Const::Ident(y)) + | (Const::Ident(x), Const::Str(y)) + | (Const::Ident(x), Const::Ident(y)) + | (Const::Str(x), Const::Str(y)) => op.apply(x == y), + + // Cast, handle permutations and cast priority. + (Const::Int(x), Const::Flt(y)) => op.apply(x == y as i32), + (Const::Flt(x), Const::Int(y)) => op.apply(x == y as f32), + + // Cast with permutation. Here we cast all into a boolean first! + (x @ Const::Int(_), Const::Bool(y)) | (Const::Bool(y), x @ Const::Int(_)) => { + op.apply(x.unwrap_boolean() == y) + } + + (x @ Const::Flt(_), Const::Bool(y)) | (Const::Bool(y), x @ Const::Flt(_)) => { + op.apply(x.unwrap_boolean() == y) + } + + // Can be inter-casted, they are not equal! + _ => op.check_not_equals(), }, - Const::Ident(x) => match ty { - Type::Identifier => match self.identifiers.contains(&x) { - true => Ok(Const::Ident(x)), - false => Err(Error::Undefined(x)), - }, - Type::Actor => match self.actors.contains(&x) { - true => Ok(Const::Ident(x)), // TODO: Return the Actor object? - false => Err(Error::Undefined(x)), - }, - Type::Printer => match self.printers.contains(&x) { - true => Ok(Const::Ident(x)), // TODO: Return the Printer object? - false => Err(Error::Undefined(x)), + )) + } + + pub fn evaluate(&self, expr: Expression) -> Result<Const, Error> { + match expr { + // Leaf, simple. + Expression::Leaf(_, VarOrConst::Const(constant)) => Ok(constant), + Expression::Leaf(_, VarOrConst::Var(var)) => self.resolve(var).cloned(), + + // Unary, not complicated. + Expression::Unary(_, op, inner) => match op { + operator::Unary::Not => Ok(Const::Bool( + !self.evaluate_as(*inner, Type::Boolean)?.unwrap_boolean(), + )), + operator::Unary::Neg => match self.evaluate_as(*inner, Type::Number)? { + Const::Int(x) => Ok(Const::Int(-x)), + Const::Flt(x) => Ok(Const::Flt(-x)), + _ => unreachable!(), }, - ty => Err(Error::CantCast(Const::Ident(x), ty)), }, + + // Binary, just long to write... + Expression::Binary(_, left, op, right) => match op { + operator::Binary::Numeric(op) => self.evaluate_numeric_binop(*left, op, *right), + operator::Binary::Logic(op) => self.evaluate_logic_binop(*left, op, *right), + operator::Binary::Equal(op) => self.evaluate_equal_binop(*left, op, *right), + }, + } + } + + fn check_identifier(&self, ident: impl Into<String>) -> Result<Const, Error> { + let x = ident.into(); + match self.identifiers.contains(&x) { + true => Ok(Const::Ident(x)), + false => Err(Error::Undefined(x)), + } + } + + fn find_actor(&self, actor: impl Into<String>) -> Result<Const, Error> { + let x = actor.into(); + match self.actors.contains(&x) { + true => Ok(Const::Ident(x)), + false => Err(Error::Undefined(x)), + } + } + + fn find_printer(&self, printer: impl Into<String>) -> Result<Const, Error> { + let x = printer.into(); + match self.printers.contains(&x) { + true => Ok(Const::Ident(x)), + false => Err(Error::Undefined(x)), + } + } + + pub fn evaluate_as(&self, expr: Expression, ty: Type) -> Result<Const, Error> { + let constant = self.evaluate(expr)?; + match ty { + Type::Identifier => self.check_identifier(constant.unwrap_identifier()), + Type::Actor => self.find_actor(constant.unwrap_identifier()), + Type::Printer => self.find_printer(constant.unwrap_identifier()), + ty => constant.cast_into(ty), } } } diff --git a/grimoire/src/types.rs b/grimoire/src/types.rs index da91ab8..6f3b138 100644 --- a/grimoire/src/types.rs +++ b/grimoire/src/types.rs @@ -6,6 +6,10 @@ pub enum Type { Integer, Boolean, + /// Can be [Type::Integer] or [Type::Float]. [Type::Boolean] will be converted into a + /// [Type::Integer] constant. + Number, + Identifier, Actor, Printer, -- GitLab