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