From d76c19e0bea07806c49175c91d19eb38cfb230dd Mon Sep 17 00:00:00 2001
From: A404M <ahmadmahmoudiprogrammer@gmail.com>
Date: Tue, 8 Apr 2025 19:17:04 +0330
Subject: add characters

---
 src/compiler/ast-tree.c | 18 ++++++++++++------
 src/compiler/ast-tree.h |  2 +-
 src/compiler/lexer.c    | 33 +++++++++++++++++++++++++++++++++
 src/compiler/lexer.h    |  2 ++
 src/compiler/parser.c   | 37 +++++++++++++++++++++++++++++++++++--
 src/compiler/parser.h   |  8 ++++++--
 6 files changed, 89 insertions(+), 11 deletions(-)

(limited to 'src/compiler')

diff --git a/src/compiler/ast-tree.c b/src/compiler/ast-tree.c
index 239f9b4..678c533 100644
--- a/src/compiler/ast-tree.c
+++ b/src/compiler/ast-tree.c
@@ -1237,6 +1237,7 @@ AstTreeRoot *makeAstTree(ParserNode *parsedRoot) {
       case PARSER_TOKEN_VALUE_BOOL:
       case PARSER_TOKEN_VALUE_INT:
       case PARSER_TOKEN_VALUE_FLOAT:
+      case PARSER_TOKEN_VALUE_CHAR:
       case PARSER_TOKEN_FUNCTION_DEFINITION:
       case PARSER_TOKEN_FUNCTION_CALL:
       case PARSER_TOKEN_IDENTIFIER:
@@ -1462,13 +1463,16 @@ AstTree *astTreeParse(ParserNode *parserNode, AstTreeHelper *helper) {
     return astTreeParseIdentifier(parserNode, helper);
   case PARSER_TOKEN_VALUE_INT:
     return astTreeParseValue(parserNode, AST_TREE_TOKEN_VALUE_INT,
-                             sizeof(AstTreeInt));
+                             sizeof(AstTreeInt), NULL);
   case PARSER_TOKEN_VALUE_FLOAT:
     return astTreeParseValue(parserNode, AST_TREE_TOKEN_VALUE_FLOAT,
-                             sizeof(AstTreeFloat));
+                             sizeof(AstTreeFloat), NULL);
   case PARSER_TOKEN_VALUE_BOOL:
     return astTreeParseValue(parserNode, AST_TREE_TOKEN_VALUE_BOOL,
-                             sizeof(AstTreeBool));
+                             sizeof(AstTreeBool), NULL);
+  case PARSER_TOKEN_VALUE_CHAR:
+    return astTreeParseValue(parserNode, AST_TREE_TOKEN_VALUE_INT,
+                             sizeof(AstTreeInt), &AST_TREE_U8_TYPE);
   case PARSER_TOKEN_KEYWORD_NULL:
     return astTreeParseKeyword(parserNode, AST_TREE_TOKEN_VALUE_NULL);
   case PARSER_TOKEN_KEYWORD_UNDEFINED:
@@ -1657,6 +1661,7 @@ AstTree *astTreeParseFunction(ParserNode *parserNode, AstTreeHelper *p_helper) {
     case PARSER_TOKEN_VALUE_INT:
     case PARSER_TOKEN_VALUE_FLOAT:
     case PARSER_TOKEN_VALUE_BOOL:
+      case PARSER_TOKEN_VALUE_CHAR:
     case PARSER_TOKEN_TYPE_TYPE:
     case PARSER_TOKEN_TYPE_FUNCTION:
     case PARSER_TOKEN_TYPE_VOID:
@@ -1893,11 +1898,11 @@ AstTree *astTreeParseIdentifier(ParserNode *parserNode, AstTreeHelper *helper) {
 }
 
 AstTree *astTreeParseValue(ParserNode *parserNode, AstTreeToken token,
-                           size_t metadata_size) {
+                           size_t metadata_size, AstTree *type) {
   void *metadata = a404m_malloc(metadata_size);
   memcpy(metadata, parserNode->metadata, metadata_size);
 
-  return newAstTree(token, metadata, NULL, parserNode->str_begin,
+  return newAstTree(token, metadata, type, parserNode->str_begin,
                     parserNode->str_end);
 }
 
@@ -2203,6 +2208,7 @@ AstTree *astTreeParseCurlyBracket(ParserNode *parserNode,
     case PARSER_TOKEN_VALUE_INT:
     case PARSER_TOKEN_VALUE_FLOAT:
     case PARSER_TOKEN_VALUE_BOOL:
+      case PARSER_TOKEN_VALUE_CHAR:
     case PARSER_TOKEN_TYPE_TYPE:
     case PARSER_TOKEN_TYPE_FUNCTION:
     case PARSER_TOKEN_TYPE_VOID:
@@ -3344,7 +3350,7 @@ bool setTypesValueFloat(AstTree *tree, AstTreeSetTypesHelper helper) {
       printWarning(tree->str_begin, tree->str_end, "Value is overflowing");
     }
     tree->type = &AST_TREE_F16_TYPE;
-    #endif
+#endif
   } else if (typeIsEqual(helper.lookingType, &AST_TREE_F32_TYPE)) {
     tree->token = AST_TREE_TOKEN_VALUE_FLOAT;
     AstTreeFloat value = *(AstTreeFloat *)tree->metadata;
diff --git a/src/compiler/ast-tree.h b/src/compiler/ast-tree.h
index 4617ce4..fb708af 100644
--- a/src/compiler/ast-tree.h
+++ b/src/compiler/ast-tree.h
@@ -260,7 +260,7 @@ AstTree *astTreeParseFunctionCall(ParserNode *parserNode,
                                   AstTreeHelper *helper);
 AstTree *astTreeParseIdentifier(ParserNode *parserNode, AstTreeHelper *helper);
 AstTree *astTreeParseValue(ParserNode *parserNode, AstTreeToken token,
-                           size_t metadata_size);
+                           size_t metadata_size,AstTree *type);
 AstTree *astTreeParseKeyword(ParserNode *parserNode, AstTreeToken token);
 AstTree *astTreeParsePrintU64(ParserNode *parserNode, AstTreeHelper *helper);
 AstTree *astTreeParseReturn(ParserNode *parserNode, AstTreeHelper *helper);
diff --git a/src/compiler/lexer.c b/src/compiler/lexer.c
index 0f971d7..43ea4c1 100644
--- a/src/compiler/lexer.c
+++ b/src/compiler/lexer.c
@@ -41,6 +41,7 @@ const char *LEXER_TOKEN_STRINGS[] = {
     "LEXER_TOKEN_KEYWORD_UNDEFINED",
 
     "LEXER_TOKEN_NUMBER",
+    "LEXER_TOKEN_CHAR",
 
     "LEXER_TOKEN_SYMBOL",
     "LEXER_TOKEN_SYMBOL_EOL",
@@ -193,12 +194,15 @@ LexerNodeArray lexer(char *str) {
                        &node_token, LEXER_TOKEN_NONE);
         ++iter;
         int in = 1;
+        char *openingIter = iter - 2;
+
         for (; in != 0; ++iter) {
           if (*iter == '*' && *(iter + 1) == '/') {
             --in;
           } else if (*iter == '/' && *(iter + 1) == '*') {
             ++in;
           } else if (*iter == '\0') {
+            printError(openingIter, openingIter + 2, "No closing */ found");
             goto RETURN_ERROR;
           }
         }
@@ -211,6 +215,23 @@ LexerNodeArray lexer(char *str) {
     if (isSpace(c)) {
       lexerPushClear(&result, &result_size, iter, &node_str_begin, &node_token,
                      LEXER_TOKEN_NONE);
+    } else if (isString(c)) {
+      lexerPushClear(&result, &result_size, iter, &node_str_begin, &node_token,
+                     LEXER_TOKEN_CHAR);
+      const char opening = c;
+      char *openingIter = iter;
+      ++iter;
+      for (;; ++iter) {
+        if (*iter == '\0') {
+          printError(openingIter, openingIter + 1, "No closing `%c` found",
+                     opening);
+          goto RETURN_ERROR;
+        } else if (*iter == '\\') {
+          ++iter;
+        } else if (*iter == '\'') {
+          break;
+        }
+      }
     } else if (isIdentifier(c) ||
                (node_token == LEXER_TOKEN_IDENTIFIER && isNumber(c))) {
       if (node_token != LEXER_TOKEN_IDENTIFIER &&
@@ -300,6 +321,7 @@ void lexerPushClear(LexerNodeArray *array, size_t *array_size, char *iter,
   case LEXER_TOKEN_KEYWORD_STRUCT:
   case LEXER_TOKEN_KEYWORD_UNDEFINED:
   case LEXER_TOKEN_NUMBER:
+  case LEXER_TOKEN_CHAR:
   case LEXER_TOKEN_SYMBOL_EOL:
   case LEXER_TOKEN_SYMBOL_OPEN_PARENTHESIS:
   case LEXER_TOKEN_SYMBOL_CLOSE_PARENTHESIS:
@@ -397,6 +419,17 @@ bool isSpace(char c) {
   case ' ':
   case '\n':
   case '\t':
+  case '\v':
+    return true;
+  default:
+    return false;
+  }
+}
+
+extern bool isString(char c) {
+  switch (c) {
+  case '\'':
+  case '\"':
     return true;
   default:
     return false;
diff --git a/src/compiler/lexer.h b/src/compiler/lexer.h
index 8759e10..42f7aa8 100644
--- a/src/compiler/lexer.h
+++ b/src/compiler/lexer.h
@@ -36,6 +36,7 @@ typedef enum LexerToken {
   LEXER_TOKEN_KEYWORD_UNDEFINED,
 
   LEXER_TOKEN_NUMBER,
+  LEXER_TOKEN_CHAR,
 
   LEXER_TOKEN_SYMBOL,
   LEXER_TOKEN_SYMBOL_EOL,
@@ -114,3 +115,4 @@ extern bool isNumber(char c);
 extern bool isSymbol(char c);
 extern bool isCompleteSymbol(char *str, size_t str_size);
 extern bool isSpace(char c);
+extern bool isString(char c);
diff --git a/src/compiler/parser.c b/src/compiler/parser.c
index 951d3b4..8df9b2d 100644
--- a/src/compiler/parser.c
+++ b/src/compiler/parser.c
@@ -17,6 +17,7 @@ const char *PARSER_TOKEN_STRINGS[] = {
     "PARSER_TOKEN_VALUE_INT",
     "PARSER_TOKEN_VALUE_FLOAT",
     "PARSER_TOKEN_VALUE_BOOL",
+    "PARSER_TOKEN_VALUE_CHAR",
 
     "PARSER_TOKEN_TYPE_TYPE",
     "PARSER_TOKEN_TYPE_FUNCTION",
@@ -109,7 +110,8 @@ static const ParserOrder PARSER_ORDER[] = {
                     LEXER_TOKEN_KEYWORD_F128, LEXER_TOKEN_KEYWORD_U64,
                     LEXER_TOKEN_KEYWORD_BOOL, LEXER_TOKEN_KEYWORD_TRUE,
                     LEXER_TOKEN_KEYWORD_FALSE, LEXER_TOKEN_KEYWORD_NULL,
-                    LEXER_TOKEN_NUMBER, LEXER_TOKEN_KEYWORD_UNDEFINED, ),
+                    LEXER_TOKEN_NUMBER, LEXER_TOKEN_CHAR,
+                    LEXER_TOKEN_KEYWORD_UNDEFINED, ),
     },
     {
         .ltr = false,
@@ -234,6 +236,11 @@ void parserNodePrint(const ParserNode *node, int indent) {
     printf(",value=%b", *metadata);
   }
     goto RETURN_SUCCESS;
+  case PARSER_TOKEN_VALUE_CHAR: {
+    ParserNodeCharMetadata *metadata = node->metadata;
+    printf(",value=%c", (char)*metadata);
+  }
+    goto RETURN_SUCCESS;
   case PARSER_TOKEN_CONSTANT:
   case PARSER_TOKEN_VARIABLE: {
     const ParserNodeVariableMetadata *metadata = node->metadata;
@@ -479,7 +486,6 @@ void parserNodeDelete(ParserNode *node) {
     free(metadata);
   }
     goto RETURN_SUCCESS;
-
   case PARSER_TOKEN_VALUE_INT: {
     ParserNodeIntMetadata *metadata = node->metadata;
     free(metadata);
@@ -490,6 +496,11 @@ void parserNodeDelete(ParserNode *node) {
     free(metadata);
   }
     goto RETURN_SUCCESS;
+  case PARSER_TOKEN_VALUE_CHAR: {
+    ParserNodeCharMetadata *metadata = node->metadata;
+    free(metadata);
+  }
+    goto RETURN_SUCCESS;
   case PARSER_TOKEN_CONSTANT:
   case PARSER_TOKEN_VARIABLE: {
     ParserNodeVariableMetadata *metadata = node->metadata;
@@ -749,6 +760,8 @@ ParserNode *parseNode(LexerNode *node, LexerNode *begin, LexerNode *end,
     return parserComma(node, begin, parent);
   case LEXER_TOKEN_NUMBER:
     return parserNumber(node, parent);
+  case LEXER_TOKEN_CHAR:
+    return parserChar(node, parent);
   case LEXER_TOKEN_SYMBOL_ASSIGN:
     return parserBinaryOperator(node, begin, end, parent,
                                 PARSER_TOKEN_OPERATOR_ASSIGN);
@@ -1011,6 +1024,22 @@ ParserNode *parserNumber(LexerNode *node, ParserNode *parent) {
   return node->parserNode = parserNode;
 }
 
+ParserNode *parserChar(LexerNode *node, ParserNode *parent) {
+  const size_t size = node->str_end - 1 - node->str_begin - 1;
+  ParserNodeCharMetadata *metadata = a404m_malloc(sizeof(*metadata));
+  if (size == 1) {
+    *metadata = *(node->str_begin + 1);
+  } else if (size > 1) {
+    NOT_IMPLEMENTED;
+  } else {
+    printError(node->str_begin, node->str_end,
+               "Bad character: Character can't be empty");
+  }
+  return node->parserNode =
+             newParserNode(PARSER_TOKEN_VALUE_CHAR, node->str_begin,
+                           node->str_end, metadata, parent);
+}
+
 ParserNode *parserBoolValue(LexerNode *node, ParserNode *parent) {
   ParserNodeBoolMetadata *metadata = a404m_malloc(sizeof(*metadata));
   *metadata = node->token == LEXER_TOKEN_KEYWORD_TRUE;
@@ -1218,6 +1247,7 @@ ParserNode *parserFunction(LexerNode *node, LexerNode *begin, LexerNode *end,
       case PARSER_TOKEN_VALUE_INT:
       case PARSER_TOKEN_VALUE_FLOAT:
       case PARSER_TOKEN_VALUE_BOOL:
+      case PARSER_TOKEN_VALUE_CHAR:
       case PARSER_TOKEN_TYPE_TYPE:
       case PARSER_TOKEN_TYPE_FUNCTION:
       case PARSER_TOKEN_TYPE_VOID:
@@ -1700,6 +1730,7 @@ bool isExpression(ParserNode *node) {
   case PARSER_TOKEN_VALUE_INT:
   case PARSER_TOKEN_VALUE_FLOAT:
   case PARSER_TOKEN_VALUE_BOOL:
+  case PARSER_TOKEN_VALUE_CHAR:
   case PARSER_TOKEN_KEYWORD_IF:
   case PARSER_TOKEN_KEYWORD_WHILE:
   case PARSER_TOKEN_KEYWORD_COMPTIME:
@@ -1777,6 +1808,7 @@ bool isType(ParserNode *node) {
   case PARSER_TOKEN_VALUE_INT:
   case PARSER_TOKEN_VALUE_FLOAT:
   case PARSER_TOKEN_VALUE_BOOL:
+  case PARSER_TOKEN_VALUE_CHAR:
   case PARSER_TOKEN_KEYWORD_PRINT_U64:
   case PARSER_TOKEN_KEYWORD_RETURN:
   case PARSER_TOKEN_OPERATOR_ASSIGN:
@@ -1813,6 +1845,7 @@ bool isValue(ParserNode *node) {
   case PARSER_TOKEN_VALUE_INT:
   case PARSER_TOKEN_VALUE_FLOAT:
   case PARSER_TOKEN_VALUE_BOOL:
+  case PARSER_TOKEN_VALUE_CHAR:
   case PARSER_TOKEN_IDENTIFIER:
   case PARSER_TOKEN_OPERATOR_ACCESS:
   case PARSER_TOKEN_OPERATOR_ASSIGN:
diff --git a/src/compiler/parser.h b/src/compiler/parser.h
index 8eaea77..cb7af45 100644
--- a/src/compiler/parser.h
+++ b/src/compiler/parser.h
@@ -13,6 +13,7 @@ typedef enum ParserToken {
   PARSER_TOKEN_VALUE_INT,
   PARSER_TOKEN_VALUE_FLOAT,
   PARSER_TOKEN_VALUE_BOOL,
+  PARSER_TOKEN_VALUE_CHAR,
 
   PARSER_TOKEN_TYPE_TYPE,
   PARSER_TOKEN_TYPE_FUNCTION,
@@ -28,7 +29,7 @@ typedef enum ParserToken {
   PARSER_TOKEN_TYPE_U64,
 #ifdef FLOAT_16_SUPPORT
   PARSER_TOKEN_TYPE_F16,
-  #endif
+#endif
   PARSER_TOKEN_TYPE_F32,
   PARSER_TOKEN_TYPE_F64,
   PARSER_TOKEN_TYPE_F128,
@@ -86,7 +87,7 @@ extern const char *PARSER_TOKEN_STRINGS[];
 typedef struct ParserOrder {
   bool ltr;
   size_t size;
-  LexerToken data[22];
+  LexerToken data[23];
 } ParserOrder;
 
 typedef struct ParserNode {
@@ -130,6 +131,8 @@ typedef u64 ParserNodeIntMetadata;
 
 typedef f128 ParserNodeFloatMetadata;
 
+typedef ParserNodeIntMetadata ParserNodeCharMetadata;
+
 typedef struct ParserNodeInfixMetadata {
   ParserNode *left;
   ParserNode *right;
@@ -177,6 +180,7 @@ ParserNode *parserNoMetadata(LexerNode *node, ParserNode *parent,
 ParserNode *parserPrintU64(LexerNode *node, LexerNode *end, ParserNode *parent);
 ParserNode *parserReturn(LexerNode *node, LexerNode *end, ParserNode *parent);
 ParserNode *parserNumber(LexerNode *node, ParserNode *parent);
+ParserNode *parserChar(LexerNode *node, ParserNode *parent);
 ParserNode *parserBoolValue(LexerNode *node, ParserNode *parent);
 ParserNode *parserEol(LexerNode *node, LexerNode *begin, ParserNode *parent);
 ParserNode *parserComma(LexerNode *node, LexerNode *begin, ParserNode *parent);
-- 
cgit v1.2.3