From 307730a44be438971f86e30404abcc35c3944d7b Mon Sep 17 00:00:00 2001 From: Kubat <maelle.martin@proton.me> Date: Thu, 1 May 2025 15:48:38 +0200 Subject: [PATCH] [AST] Move the Const & ConstOrVar definitions to their own file for readability --- grimoire/src/ast/constant.rs | 109 +++++++++++++++++++++++++++++++++ grimoire/src/ast/expr.rs | 113 +---------------------------------- grimoire/src/ast/mod.rs | 8 ++- grimoire/src/error.rs | 11 +++- grimoire/src/parser/expr.rs | 2 +- grimoire/src/state.rs | 5 +- 6 files changed, 127 insertions(+), 121 deletions(-) create mode 100644 grimoire/src/ast/constant.rs diff --git a/grimoire/src/ast/constant.rs b/grimoire/src/ast/constant.rs new file mode 100644 index 0000000..f4f81e9 --- /dev/null +++ b/grimoire/src/ast/constant.rs @@ -0,0 +1,109 @@ +use crate::{error::Error, types::Type}; +use derive_more::Display; + +#[derive(Debug, Clone, PartialEq, Display)] +pub enum Const { + /// Integer, like 1, 42, -1, etc + Int(i32), + + /// A floating point number, like 3.14, .01, 3, etc + Flt(f32), + + /// A string, can be multiline or not: "something", '''Some other things''' + /// + /// TODO: Esapce in display! + #[display("'''{_0}'''")] + Str(String), + + /// A boolean value, `true` or `false` + Bool(bool), + + /// An identifier, follows the same rules as rust identifiers. + 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)), + }, + } + } +} diff --git a/grimoire/src/ast/expr.rs b/grimoire/src/ast/expr.rs index 7a6f74c..8875400 100644 --- a/grimoire/src/ast/expr.rs +++ b/grimoire/src/ast/expr.rs @@ -1,117 +1,6 @@ -use crate::{ - ast::{AstSpan, operator}, - error::Error, - types::Type, -}; +use crate::ast::{AstSpan, Const, operator}; use derive_more::Display; -#[derive(Debug, Clone, PartialEq, Display)] -pub enum Const { - /// Integer, like 1, 42, -1, etc - Int(i32), - - /// A floating point number, like 3.14, .01, 3, etc - Flt(f32), - - /// A string, can be multiline or not: "something", '''Some other things''' - /// - /// TODO: Esapce in display! - #[display("'''{_0}'''")] - Str(String), - - /// A boolean value, `true` or `false` - Bool(bool), - - /// An identifier, follows the same rules as rust identifiers. - 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]. diff --git a/grimoire/src/ast/mod.rs b/grimoire/src/ast/mod.rs index 2fa8585..6a5d6db 100644 --- a/grimoire/src/ast/mod.rs +++ b/grimoire/src/ast/mod.rs @@ -1,5 +1,7 @@ -pub mod expr; -pub mod operator; +mod constant; +mod expr; mod span; -pub use span::Span as AstSpan; +pub mod operator; + +pub use self::{constant::*, expr::*, span::Span as AstSpan}; diff --git a/grimoire/src/error.rs b/grimoire/src/error.rs index a9dbb09..915f91b 100644 --- a/grimoire/src/error.rs +++ b/grimoire/src/error.rs @@ -8,11 +8,14 @@ pub enum Error { #[error("already defined spell '{0}': {1}")] Redefined(&'static str, &'static str), + #[error("unexpect: {0}")] + Unexpected(&'static str), + #[error("undefined spell '{0}'")] Undefined(String), #[error("can't cast '{0}' into {1:?}")] - CantCast(crate::ast::expr::Const, crate::types::Type), + CantCast(crate::ast::Const, crate::types::Type), #[error("{0}")] ParseFloat(#[from] ParseFloatError), @@ -22,4 +25,10 @@ pub enum Error { #[error("{0}")] ParseBool(#[from] ParseBoolError), + + #[error("empty {0}")] + Empty(&'static str), + + #[error("error in spell '{0}' instantiation: {1}")] + BuildSpell(&'static str, Box<Error>), } diff --git a/grimoire/src/parser/expr.rs b/grimoire/src/parser/expr.rs index d4849ad..5b1fab5 100644 --- a/grimoire/src/parser/expr.rs +++ b/grimoire/src/parser/expr.rs @@ -1,5 +1,5 @@ use crate::{ - ast::{AstSpan, expr::*, operator}, + ast::{AstSpan, Expression, VarOrConst, operator}, parser::*, }; use nom::{ diff --git a/grimoire/src/state.rs b/grimoire/src/state.rs index 1dec380..73dd415 100644 --- a/grimoire/src/state.rs +++ b/grimoire/src/state.rs @@ -1,8 +1,5 @@ use crate::{ - ast::{ - expr::{Const, Expression, VarOrConst}, - operator, - }, + ast::{Const, Expression, VarOrConst, operator}, error::Error, types::Type, }; -- GitLab