From 82818670e664c86a763cf89128ab10558ce27cd4 Mon Sep 17 00:00:00 2001
From: Kubat <maelle.martin@proton.me>
Date: Thu, 1 May 2025 11:49:13 +0200
Subject: [PATCH] [PARSER] Add the reserved keyword check + assign tags to each
 operator

---
 grimoire/src/ast/expr.rs        | 32 ++++++++++++++++----------------
 grimoire/src/parser/error.rs    |  9 ++++++---
 grimoire/src/parser/expr.rs     | 18 ++++++++++++------
 grimoire/src/parser/keywords.rs | 26 ++++++++++++++++++++++++++
 grimoire/src/parser/mod.rs      |  1 +
 grimoire/src/parser/utils.rs    |  8 ++++++--
 6 files changed, 67 insertions(+), 27 deletions(-)
 create mode 100644 grimoire/src/parser/keywords.rs

diff --git a/grimoire/src/ast/expr.rs b/grimoire/src/ast/expr.rs
index 89ad2fd..bfd3b87 100644
--- a/grimoire/src/ast/expr.rs
+++ b/grimoire/src/ast/expr.rs
@@ -37,8 +37,8 @@ pub enum UnOp {
 impl UnOp {
     pub fn as_str(&self) -> &'static str {
         match self {
-            UnOp::Not => todo!(),
-            UnOp::Neg => todo!(),
+            UnOp::Not => "!",
+            UnOp::Neg => "-",
         }
     }
 }
@@ -70,20 +70,20 @@ pub enum BinOp {
 impl BinOp {
     pub fn as_str(&self) -> &'static str {
         match self {
-            BinOp::Add => todo!(),
-            BinOp::Sub => todo!(),
-            BinOp::Mul => todo!(),
-            BinOp::Div => todo!(),
-            BinOp::Mod => todo!(),
-            BinOp::CompGE => todo!(),
-            BinOp::CompGT => todo!(),
-            BinOp::CompLT => todo!(),
-            BinOp::CompLE => todo!(),
-            BinOp::Or => todo!(),
-            BinOp::And => todo!(),
-            BinOp::Xor => todo!(),
-            BinOp::CompEQ => todo!(),
-            BinOp::CompNEQ => todo!(),
+            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 => "!=",
         }
     }
 }
diff --git a/grimoire/src/parser/error.rs b/grimoire/src/parser/error.rs
index 2185b01..331ef71 100644
--- a/grimoire/src/parser/error.rs
+++ b/grimoire/src/parser/error.rs
@@ -4,13 +4,16 @@ use std::num::{ParseFloatError, ParseIntError};
 
 #[derive(Debug, thiserror::Error)]
 pub enum ParserError {
-    #[error("{0:?}, {1}")]
+    #[error("{0:?}: {1}")]
     ParseFloat(Location, ParseFloatError),
 
-    #[error("{0:?}, {1}")]
+    #[error("{0:?}: {1}")]
     ParseInt(Location, ParseIntError),
 
-    #[error("{0:?}, {1:?}")]
+    #[error("{0:?} use of a reserved keyword: '{1}'")]
+    UseOfReservedKeyword(Location, &'static str),
+
+    #[error("{0:?}: nom error {1:?}")]
     Nom(Location, ErrorKind),
 }
 
diff --git a/grimoire/src/parser/expr.rs b/grimoire/src/parser/expr.rs
index cb91241..4fde857 100644
--- a/grimoire/src/parser/expr.rs
+++ b/grimoire/src/parser/expr.rs
@@ -2,21 +2,27 @@ use crate::{
     ast::{AstSpan, expr::*},
     parser::*,
 };
-
 use nom::{
-    Parser, branch::alt, bytes::complete::tag, character::complete::multispace0, combinator::map,
-    multi::many0, sequence::preceded,
+    Parser,
+    branch::alt,
+    bytes::complete::tag,
+    character::complete::{char, multispace0},
+    combinator::{map, value},
+    multi::many0,
+    sequence::preceded,
 };
 
 fn var_or_constant(s: Span) -> ParserResult<Expression> {
+    // Note: the order is important!
     utils::map_with_locaiton(
         alt((
             map(utils::number, VarOrConstant::Int),
             map(utils::float, VarOrConstant::Flt),
             map(utils::string, VarOrConstant::Str),
-            map(utils::keyword("true"), |_| VarOrConstant::Bool(true)),
-            map(utils::keyword("false"), |_| VarOrConstant::Bool(false)),
-            map(utils::identifier, VarOrConstant::Var),
+            value(VarOrConstant::Bool(true), utils::keyword(keywords::TRUE)),
+            value(VarOrConstant::Bool(false), utils::keyword(keywords::FALSE)),
+            map(preceded(char('$'), utils::identifier), VarOrConstant::Var),
+            map(utils::identifier, VarOrConstant::Ident),
         )),
         Expression::Leaf,
     )
diff --git a/grimoire/src/parser/keywords.rs b/grimoire/src/parser/keywords.rs
new file mode 100644
index 0000000..4ba2f7d
--- /dev/null
+++ b/grimoire/src/parser/keywords.rs
@@ -0,0 +1,26 @@
+pub const TRUE: &str = "true";
+pub const FALSE: &str = "false";
+
+pub fn check(keyword: &str) -> Result<&str, &'static str> {
+    const RESERVED: &[&str] = &[TRUE, FALSE];
+    const _: () = {
+        let mut i = 0usize;
+        while i < RESERVED.len() {
+            let mut j = 0usize;
+            let reserved = RESERVED[i].as_bytes();
+            while j < reserved.len() {
+                assert!(
+                    u8::is_ascii_lowercase(&reserved[j]),
+                    "reserved keyword must be ascii-lowercase composed..."
+                );
+                j += 1;
+            }
+            i += 1;
+        }
+    };
+
+    match RESERVED.iter().find(|&&r| r == keyword.trim()) {
+        Some(&reserved) => Err(reserved),
+        None => Ok(keyword),
+    }
+}
diff --git a/grimoire/src/parser/mod.rs b/grimoire/src/parser/mod.rs
index 245e522..ea673b9 100644
--- a/grimoire/src/parser/mod.rs
+++ b/grimoire/src/parser/mod.rs
@@ -1,5 +1,6 @@
 mod error;
 mod expr;
+pub mod keywords;
 mod location;
 mod span;
 pub mod utils;
diff --git a/grimoire/src/parser/utils.rs b/grimoire/src/parser/utils.rs
index dcdbb44..5b870a8 100644
--- a/grimoire/src/parser/utils.rs
+++ b/grimoire/src/parser/utils.rs
@@ -1,6 +1,6 @@
 use crate::{
     ast::AstSpan,
-    parser::{error::*, span::*},
+    parser::{error::*, keywords, span::*},
 };
 use nom::{
     Parser,
@@ -68,7 +68,11 @@ pub fn identifier(s: Span) -> ParserResult<String> {
         alt((alpha1, tag("_"))),
         many0(alt((alphanumeric1, tag("_")))),
     ))
-    .map(String::from)
+    .map_res(|ident: Span| {
+        keywords::check(ident.into_fragment())
+            .map_err(|reserved| ParserError::UseOfReservedKeyword(ident.into(), reserved))
+            .map(String::from)
+    })
     .parse(s)
 }
 
-- 
GitLab