From 4c7d3c1d1e71823efc47a78ef8a608ee1656b035 Mon Sep 17 00:00:00 2001
From: A404M <ahmadmahmoudiprogrammer@gmail.com>
Date: Thu, 27 Mar 2025 07:11:18 +0330
Subject: add dereferencing

---
 src/compiler/ast-tree.c | 69 ++++++++++++++++++++++++++++++++++++++++++++-----
 src/compiler/ast-tree.h |  2 ++
 src/compiler/lexer.c    | 35 +++++++++++++------------
 src/compiler/lexer.h    |  3 ++-
 src/compiler/parser.c   | 38 +++++++++++++++++++++++++++
 src/compiler/parser.h   |  3 +++
 src/runner/runner.c     | 37 +++++++++++++++++++++-----
 7 files changed, 156 insertions(+), 31 deletions(-)

(limited to 'src')

diff --git a/src/compiler/ast-tree.c b/src/compiler/ast-tree.c
index 4190679..71429f1 100644
--- a/src/compiler/ast-tree.c
+++ b/src/compiler/ast-tree.c
@@ -155,6 +155,7 @@ const char *AST_TREE_TOKEN_STRINGS[] = {
     "AST_TREE_TOKEN_OPERATOR_SMALLER_OR_EQUAL",
     "AST_TREE_TOKEN_OPERATOR_POINTER",
     "AST_TREE_TOKEN_OPERATOR_ADDRESS",
+    "AST_TREE_TOKEN_OPERATOR_DEREFERENCE",
 
     "AST_TREE_TOKEN_SCOPE",
 
@@ -224,6 +225,7 @@ void astTreePrint(const AstTree *tree, int indent) {
     goto RETURN_SUCCESS;
   case AST_TREE_TOKEN_OPERATOR_POINTER:
   case AST_TREE_TOKEN_OPERATOR_ADDRESS:
+  case AST_TREE_TOKEN_OPERATOR_DEREFERENCE:
   case AST_TREE_TOKEN_OPERATOR_PLUS:
   case AST_TREE_TOKEN_OPERATOR_MINUS:
   case AST_TREE_TOKEN_KEYWORD_PRINT_U64:
@@ -466,6 +468,7 @@ void astTreeDestroy(AstTree tree) {
   }
   case AST_TREE_TOKEN_OPERATOR_POINTER:
   case AST_TREE_TOKEN_OPERATOR_ADDRESS:
+  case AST_TREE_TOKEN_OPERATOR_DEREFERENCE:
   case AST_TREE_TOKEN_OPERATOR_PLUS:
   case AST_TREE_TOKEN_OPERATOR_MINUS:
   case AST_TREE_TOKEN_KEYWORD_PRINT_U64:
@@ -753,6 +756,7 @@ AstTree *copyAstTreeBack(AstTree *tree, AstTreeVariables oldVariables[],
   }
   case AST_TREE_TOKEN_OPERATOR_POINTER:
   case AST_TREE_TOKEN_OPERATOR_ADDRESS:
+  case AST_TREE_TOKEN_OPERATOR_DEREFERENCE:
   case AST_TREE_TOKEN_OPERATOR_PLUS:
   case AST_TREE_TOKEN_OPERATOR_MINUS:
   case AST_TREE_TOKEN_KEYWORD_PRINT_U64:
@@ -867,7 +871,7 @@ AstTree *copyAstTreeBack(AstTree *tree, AstTreeVariables oldVariables[],
   }
   case AST_TREE_TOKEN_NONE:
   }
-  printLog("Bad token %ld", tree->token);
+  printLog("Bad token %d", tree->token);
   UNREACHABLE;
 }
 
@@ -880,16 +884,28 @@ AstTreeVariables copyAstTreeVariables(AstTreeVariables variables,
       .size = variables.size,
   };
 
+  size_t new_variables_size = variables_size + 1;
+  AstTreeVariables new_oldVariables[new_variables_size];
+  AstTreeVariables new_newVariables[new_variables_size];
+  for (size_t i = 0; i < variables_size; ++i) {
+    new_oldVariables[i] = oldVariables[i];
+    new_newVariables[i] = newVariables[i];
+  }
+  new_oldVariables[new_variables_size - 1] = variables;
+  new_newVariables[new_variables_size - 1] = result;
+
   for (size_t i = 0; i < result.size; ++i) {
     result.data[i] = a404m_malloc(sizeof(*result.data[i]));
     if (variables.data[i]->value != NULL) {
-      result.data[i]->value = copyAstTreeBack(
-          variables.data[i]->value, oldVariables, newVariables, variables_size);
+      result.data[i]->value =
+          copyAstTreeBack(variables.data[i]->value, new_oldVariables,
+                          new_newVariables, new_variables_size);
     } else {
       result.data[i]->value = NULL;
     }
-    result.data[i]->type = copyAstTreeBack(
-        variables.data[i]->type, oldVariables, newVariables, variables_size);
+    result.data[i]->type =
+        copyAstTreeBack(variables.data[i]->type, new_oldVariables,
+                        new_newVariables, new_variables_size);
     result.data[i]->isConst = variables.data[i]->isConst;
     result.data[i]->name_begin = variables.data[i]->name_begin;
     result.data[i]->name_end = variables.data[i]->name_end;
@@ -1022,6 +1038,7 @@ AstTreeRoot *makeAstTree(ParserNode *parsedRoot) {
     case PARSER_TOKEN_TYPE_BOOL:
     case PARSER_TOKEN_OPERATOR_POINTER:
     case PARSER_TOKEN_OPERATOR_ADDRESS:
+    case PARSER_TOKEN_OPERATOR_DEREFERENCE:
       goto AFTER_SWITCH;
     case PARSER_TOKEN_ROOT:
     case PARSER_TOKEN_KEYWORD_PRINT_U64:
@@ -1266,6 +1283,9 @@ AstTree *astTreeParse(ParserNode *parserNode, AstTreeHelper *helper) {
   case PARSER_TOKEN_OPERATOR_ADDRESS:
     return astTreeParseUnaryOperator(parserNode, helper,
                                      AST_TREE_TOKEN_OPERATOR_ADDRESS);
+  case PARSER_TOKEN_OPERATOR_DEREFERENCE:
+    return astTreeParseUnaryOperator(parserNode, helper,
+                                     AST_TREE_TOKEN_OPERATOR_DEREFERENCE);
   case PARSER_TOKEN_VARIABLE:
     return astTreeParseVariable(parserNode, helper);
   case PARSER_TOKEN_KEYWORD_IF:
@@ -1423,6 +1443,7 @@ AstTree *astTreeParseFunction(ParserNode *parserNode, AstTreeHelper *p_helper) {
     case PARSER_TOKEN_KEYWORD_NULL:
     case PARSER_TOKEN_OPERATOR_POINTER:
     case PARSER_TOKEN_OPERATOR_ADDRESS:
+    case PARSER_TOKEN_OPERATOR_DEREFERENCE:
       printError(node->str_begin, node->str_end, "Unexpected %s",
                  PARSER_TOKEN_STRINGS[node->token]);
       goto RETURN_ERROR;
@@ -1947,6 +1968,7 @@ AstTree *astTreeParseCurlyBracket(ParserNode *parserNode,
     case PARSER_TOKEN_KEYWORD_NULL:
     case PARSER_TOKEN_OPERATOR_POINTER:
     case PARSER_TOKEN_OPERATOR_ADDRESS:
+    case PARSER_TOKEN_OPERATOR_DEREFERENCE:
       printError(node->str_begin, node->str_end, "Unexpected %s",
                  PARSER_TOKEN_STRINGS[node->token]);
       goto RETURN_ERROR;
@@ -2044,6 +2066,7 @@ AstTreeFunction *getFunction(AstTree *value) {
   case AST_TREE_TOKEN_OPERATOR_ASSIGN:
   case AST_TREE_TOKEN_OPERATOR_POINTER:
   case AST_TREE_TOKEN_OPERATOR_ADDRESS:
+  case AST_TREE_TOKEN_OPERATOR_DEREFERENCE:
   case AST_TREE_TOKEN_OPERATOR_PLUS:
   case AST_TREE_TOKEN_OPERATOR_MINUS:
   case AST_TREE_TOKEN_OPERATOR_SUM:
@@ -2134,6 +2157,7 @@ bool isConst(AstTree *tree, AstTreeHelper *helper) {
     AstTreeVariable *metadata = tree->metadata;
     return metadata->isConst;
   }
+  case AST_TREE_TOKEN_OPERATOR_DEREFERENCE:
   case AST_TREE_TOKEN_OPERATOR_ADDRESS:
   case AST_TREE_TOKEN_OPERATOR_POINTER: {
     AstTreeSingleChild *metadata = tree->metadata;
@@ -2169,6 +2193,17 @@ AstTree *makeTypeOf(AstTree *value) {
     return newAstTree(AST_TREE_TOKEN_OPERATOR_POINTER, makeTypeOf(metadata),
                       &AST_TREE_TYPE_TYPE, value->str_begin, value->str_end);
   }
+  case AST_TREE_TOKEN_OPERATOR_DEREFERENCE: {
+    AstTreeSingleChild *metadata = value->metadata;
+    AstTree *type = makeTypeOf(metadata);
+    if (type->token != AST_TREE_TOKEN_OPERATOR_POINTER) {
+      UNREACHABLE;
+    }
+    AstTree *ret = type->metadata;
+    astTreeDelete(type->type);
+    astTreeDelete(type->metadata);
+    return ret;
+  }
   case AST_TREE_TOKEN_FUNCTION_CALL: {
     AstTreeFunctionCall *metadata = value->metadata;
     AstTreeFunction *function = metadata->function->metadata;
@@ -2267,6 +2302,7 @@ bool typeIsEqual(const AstTree *type0, const AstTree *type1) {
   case AST_TREE_TOKEN_OPERATOR_PLUS:
   case AST_TREE_TOKEN_OPERATOR_MINUS:
   case AST_TREE_TOKEN_SCOPE:
+  case AST_TREE_TOKEN_OPERATOR_DEREFERENCE:
   case AST_TREE_TOKEN_OPERATOR_ADDRESS:
     return false;
   case AST_TREE_TOKEN_TYPE_TYPE:
@@ -2369,12 +2405,13 @@ AstTree *getValue(AstTree *tree, AstTreeSetTypesHelper helper) {
   case AST_TREE_TOKEN_OPERATOR_SMALLER_OR_EQUAL:
   case AST_TREE_TOKEN_OPERATOR_POINTER:
   case AST_TREE_TOKEN_OPERATOR_ADDRESS:
+  case AST_TREE_TOKEN_OPERATOR_DEREFERENCE:
   case AST_TREE_TOKEN_KEYWORD_IF:
   case AST_TREE_TOKEN_KEYWORD_WHILE:
   case AST_TREE_TOKEN_KEYWORD_COMPTIME:
   case AST_TREE_TOKEN_SCOPE: {
     bool shouldRet = false;
-    AstTree *value = runExpression(tree,  &shouldRet);
+    AstTree *value = runExpression(tree, &shouldRet);
     if (value == NULL) {
       printError(tree->str_begin, tree->str_end, "Unknown error");
     }
@@ -2431,6 +2468,7 @@ bool isCircularDependenciesBack(AstTreeHelper *helper,
     return false;
   case AST_TREE_TOKEN_OPERATOR_POINTER:
   case AST_TREE_TOKEN_OPERATOR_ADDRESS:
+  case AST_TREE_TOKEN_OPERATOR_DEREFERENCE:
   case AST_TREE_TOKEN_KEYWORD_COMPTIME:
   case AST_TREE_TOKEN_OPERATOR_PLUS:
   case AST_TREE_TOKEN_OPERATOR_MINUS: {
@@ -2623,6 +2661,8 @@ bool setAllTypes(AstTree *tree, AstTreeSetTypesHelper helper,
     return setTypesOperatorPointer(tree, helper);
   case AST_TREE_TOKEN_OPERATOR_ADDRESS:
     return setTypesOperatorAddress(tree, helper);
+  case AST_TREE_TOKEN_OPERATOR_DEREFERENCE:
+    return setTypesOperatorDereference(tree, helper);
   case AST_TREE_TOKEN_VARIABLE_DEFINE:
     return setTypesVariableDefine(tree, helper);
   case AST_TREE_TOKEN_KEYWORD_IF:
@@ -2988,6 +3028,7 @@ bool setTypesVariable(AstTree *tree, AstTreeSetTypesHelper helper) {
 
 bool setTypesOperatorAssign(AstTree *tree, AstTreeSetTypesHelper helper) {
   AstTreeInfix *infix = tree->metadata;
+  // TODO: check left one for being left value
   if (!setTypesAstInfix(infix, helper)) {
     return false;
   } else if (!typeIsEqual(infix->left.type, infix->right.type)) {
@@ -3070,6 +3111,22 @@ bool setTypesOperatorAddress(AstTree *tree, AstTreeSetTypesHelper helper) {
   return true;
 }
 
+bool setTypesOperatorDereference(AstTree *tree, AstTreeSetTypesHelper helper) {
+  AstTreeSingleChild *metadata = tree->metadata;
+  if (!setAllTypes(metadata, helper, NULL)) {
+    return false;
+  }
+
+  if (metadata->type->token != AST_TREE_TOKEN_OPERATOR_POINTER) {
+    printError(tree->str_begin, tree->str_end,
+               "Can only dereferenece pointers");
+    return false;
+  }
+
+  tree->type = copyAstTree(metadata->type->metadata);
+  return true;
+}
+
 bool setTypesVariableDefine(AstTree *tree, AstTreeSetTypesHelper helper) {
   AstTreeVariable *metadata = tree->metadata;
   tree->type = &AST_TREE_VOID_TYPE;
diff --git a/src/compiler/ast-tree.h b/src/compiler/ast-tree.h
index 87d5c93..6ce8c64 100644
--- a/src/compiler/ast-tree.h
+++ b/src/compiler/ast-tree.h
@@ -57,6 +57,7 @@ typedef enum AstTreeToken {
   AST_TREE_TOKEN_OPERATOR_SMALLER_OR_EQUAL,
   AST_TREE_TOKEN_OPERATOR_POINTER,
   AST_TREE_TOKEN_OPERATOR_ADDRESS,
+  AST_TREE_TOKEN_OPERATOR_DEREFERENCE,
 
   AST_TREE_TOKEN_SCOPE,
 
@@ -267,6 +268,7 @@ bool setTypesOperatorInfixWithRet(AstTree *tree, AstTree *retType,
 bool setTypesOperatorUnary(AstTree *tree, AstTreeSetTypesHelper helper);
 bool setTypesOperatorPointer(AstTree *tree, AstTreeSetTypesHelper helper);
 bool setTypesOperatorAddress(AstTree *tree, AstTreeSetTypesHelper helper);
+bool setTypesOperatorDereference(AstTree *tree, AstTreeSetTypesHelper helper);
 bool setTypesVariableDefine(AstTree *tree, AstTreeSetTypesHelper helper);
 bool setTypesIf(AstTree *tree, AstTreeSetTypesHelper helper,
                 AstTreeFunction *function);
diff --git a/src/compiler/lexer.c b/src/compiler/lexer.c
index 905186a..75fb04b 100644
--- a/src/compiler/lexer.c
+++ b/src/compiler/lexer.c
@@ -69,13 +69,14 @@ const char *LEXER_TOKEN_STRINGS[] = {
     "LEXER_TOKEN_SYMBOL_SMALLER_OR_EQUAL",
     "LEXER_TOKEN_SYMBOL_POINTER",
     "LEXER_TOKEN_SYMBOL_ADDRESS",
+    "LEXER_TOKEN_SYMBOL_DEREFERENCE",
 
     "LEXER_TOKEN_NONE",
 };
 
 const char *LEXER_SYMBOL_STRINGS[] = {
-    ";", "(", ")", "{", "}", "->", ":",  "=",  "+=", "-=", "*=", "/=", "%=",
-    ",", "+", "-", "*", "/", "%",  "==", "!=", ">",  ">=", "<",  "<=", "&",
+    ";", "(", ")", "{", "}", "->", ":",  "=", "+=", "-=", "*=", "/=", "%=", ",",
+    "+", "-", "*", "/", "%", "==", "!=", ">", ">=", "<",  "<=", "&",  ".*",
 };
 const LexerToken LEXER_SYMBOL_TOKENS[] = {
     LEXER_TOKEN_SYMBOL_EOL,
@@ -104,6 +105,7 @@ const LexerToken LEXER_SYMBOL_TOKENS[] = {
     LEXER_TOKEN_SYMBOL_SMALLER,
     LEXER_TOKEN_SYMBOL_SMALLER_OR_EQUAL,
     LEXER_TOKEN_SYMBOL_ADDRESS,
+    LEXER_TOKEN_SYMBOL_DEREFERENCE,
 };
 const size_t LEXER_SYMBOL_SIZE =
     sizeof(LEXER_SYMBOL_TOKENS) / sizeof(*LEXER_SYMBOL_TOKENS);
@@ -195,20 +197,21 @@ LexerNodeArray lexer(char *str) {
     if (isSpace(c)) {
       lexerPushClear(&result, &result_size, iter, &node_str_begin, &node_token,
                      LEXER_TOKEN_NONE);
-    } else if (isIdentifier(c)) {
+    } else if (isIdentifier(c) ||
+               (node_token == LEXER_TOKEN_IDENTIFIER && isNumber(c))) {
       if (node_token != LEXER_TOKEN_IDENTIFIER &&
           node_token != LEXER_TOKEN_NUMBER) {
         lexerPushClear(&result, &result_size, iter, &node_str_begin,
                        &node_token, LEXER_TOKEN_IDENTIFIER);
       }
-    } else if (isNumber(c)) {
-      if (node_token != LEXER_TOKEN_IDENTIFIER &&
-          node_token != LEXER_TOKEN_NUMBER) {
+    } else if (isNumber(c) || (node_token == LEXER_TOKEN_NUMBER && c == '.')) {
+      if (node_token != LEXER_TOKEN_NUMBER) {
         lexerPushClear(&result, &result_size, iter, &node_str_begin,
                        &node_token, LEXER_TOKEN_NUMBER);
       }
-    } else if (isSymbol(c) || isSingleSymbol(c)) {
-      if (node_token != LEXER_TOKEN_SYMBOL || isSingleSymbol(*node_str_begin)) {
+    } else if (isSymbol(c)) {
+      if (node_token != LEXER_TOKEN_SYMBOL ||
+          !isCompleteSymbol(node_str_begin, iter - node_str_begin + 1)) {
         lexerPushClear(&result, &result_size, iter, &node_str_begin,
                        &node_token, LEXER_TOKEN_SYMBOL);
       }
@@ -308,6 +311,7 @@ void lexerPushClear(LexerNodeArray *array, size_t *array_size, char *iter,
   case LEXER_TOKEN_SYMBOL_SMALLER_OR_EQUAL:
   case LEXER_TOKEN_SYMBOL_POINTER:
   case LEXER_TOKEN_SYMBOL_ADDRESS:
+  case LEXER_TOKEN_SYMBOL_DEREFERENCE:
     if (*array_size == array->size) {
       *array_size += 1 + *array_size / 2;
       array->data =
@@ -336,7 +340,7 @@ bool isIdentifier(char c) {
   return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || c == '_';
 }
 
-bool isNumber(char c) { return ('0' <= c && c <= '9') || c == '.'; }
+bool isNumber(char c) { return '0' <= c && c <= '9'; }
 
 bool isSymbol(char c) {
   switch (c) {
@@ -351,14 +355,6 @@ bool isSymbol(char c) {
   case '=':
   case '!':
   case '&':
-    return true;
-  default:
-    return false;
-  }
-}
-
-bool isSingleSymbol(char c) {
-  switch (c) {
   case ';':
   case ':':
   case ',':
@@ -372,4 +368,9 @@ bool isSingleSymbol(char c) {
   }
 }
 
+bool isCompleteSymbol(char *str, size_t str_size) {
+  return searchInStringArray(LEXER_SYMBOL_STRINGS, LEXER_SYMBOL_SIZE, str,
+                             str_size) != LEXER_SYMBOL_SIZE;
+}
+
 bool isSpace(char c) { return isspace(c); }
diff --git a/src/compiler/lexer.h b/src/compiler/lexer.h
index 1ebe405..5e2496b 100644
--- a/src/compiler/lexer.h
+++ b/src/compiler/lexer.h
@@ -62,6 +62,7 @@ typedef enum LexerToken {
   LEXER_TOKEN_SYMBOL_SMALLER_OR_EQUAL,
   LEXER_TOKEN_SYMBOL_POINTER,
   LEXER_TOKEN_SYMBOL_ADDRESS,
+  LEXER_TOKEN_SYMBOL_DEREFERENCE,
 
   LEXER_TOKEN_NONE,
 } LexerToken;
@@ -105,5 +106,5 @@ extern void lexerPushClear(LexerNodeArray *array, size_t *array_size,
 extern bool isIdentifier(char c);
 extern bool isNumber(char c);
 extern bool isSymbol(char c);
-extern bool isSingleSymbol(char c);
+extern bool isCompleteSymbol(char *str, size_t str_size);
 extern bool isSpace(char c);
diff --git a/src/compiler/parser.c b/src/compiler/parser.c
index fa6e17c..17d596b 100644
--- a/src/compiler/parser.c
+++ b/src/compiler/parser.c
@@ -71,6 +71,7 @@ const char *PARSER_TOKEN_STRINGS[] = {
     "PARSER_TOKEN_OPERATOR_SMALLER_OR_EQUAL",
     "PARSER_TOKEN_OPERATOR_POINTER",
     "PARSER_TOKEN_OPERATOR_ADDRESS",
+    "PARSER_TOKEN_OPERATOR_DEREFERENCE",
 
     "PARSER_TOKEN_FUNCTION_DEFINITION",
 
@@ -106,6 +107,10 @@ static constexpr ParserOrder PARSER_ORDER[] = {
         .ltr = false,
         ORDER_ARRAY(LEXER_TOKEN_SYMBOL_FUNCTION_ARROW, ),
     },
+    {
+        .ltr = true,
+        ORDER_ARRAY(LEXER_TOKEN_SYMBOL_DEREFERENCE, ),
+    },
     {
         .ltr = true,
         ORDER_ARRAY(LEXER_TOKEN_SYMBOL_PLUS, LEXER_TOKEN_SYMBOL_MINUS,
@@ -241,6 +246,7 @@ void parserNodePrint(const ParserNode *node, int indent) {
     goto RETURN_SUCCESS;
   case PARSER_TOKEN_OPERATOR_POINTER:
   case PARSER_TOKEN_OPERATOR_ADDRESS:
+  case PARSER_TOKEN_OPERATOR_DEREFERENCE:
   case PARSER_TOKEN_OPERATOR_PLUS:
   case PARSER_TOKEN_OPERATOR_MINUS:
   case PARSER_TOKEN_KEYWORD_PRINT_U64:
@@ -468,6 +474,7 @@ void parserNodeDelete(ParserNode *node) {
     goto RETURN_SUCCESS;
   case PARSER_TOKEN_OPERATOR_POINTER:
   case PARSER_TOKEN_OPERATOR_ADDRESS:
+  case PARSER_TOKEN_OPERATOR_DEREFERENCE:
   case PARSER_TOKEN_OPERATOR_PLUS:
   case PARSER_TOKEN_OPERATOR_MINUS:
   case PARSER_TOKEN_KEYWORD_PRINT_U64:
@@ -787,6 +794,12 @@ ParserNode *parseNode(LexerNode *node, LexerNode *begin, LexerNode *end,
     *conti = result == NULL;
     return result;
   }
+  case LEXER_TOKEN_SYMBOL_DEREFERENCE: {
+    ParserNode *result = parserRightOperator(node, begin, parent,
+                                             PARSER_TOKEN_OPERATOR_DEREFERENCE);
+    *conti = result == NULL;
+    return result;
+  }
   case LEXER_TOKEN_KEYWORD_IF:
     return parserIf(node, end, parent);
   case LEXER_TOKEN_KEYWORD_WHILE:
@@ -1198,6 +1211,7 @@ ParserNode *parserFunction(LexerNode *node, LexerNode *begin, LexerNode *end,
       case PARSER_TOKEN_OPERATOR_MODULO_ASSIGN:
       case PARSER_TOKEN_OPERATOR_POINTER:
       case PARSER_TOKEN_OPERATOR_ADDRESS:
+      case PARSER_TOKEN_OPERATOR_DEREFERENCE:
       case PARSER_TOKEN_OPERATOR_PLUS:
       case PARSER_TOKEN_OPERATOR_MINUS:
       case PARSER_TOKEN_OPERATOR_SUM:
@@ -1436,6 +1450,27 @@ ParserNode *parserLeftOperator(LexerNode *node, LexerNode *end,
                            (ParserNodeSingleChildMetadata *)right, parent);
 }
 
+ParserNode *parserRightOperator(LexerNode *node, LexerNode *begin,
+                                ParserNode *parent, ParserToken token) {
+  LexerNode *leftNode = node - 1;
+
+  if (leftNode < begin || leftNode->parserNode == NULL) {
+    printError(node->str_begin, node->str_end, "No operand found");
+    return NULL;
+  }
+
+  ParserNode *left = getUntilCommonParent(leftNode->parserNode, parent);
+
+  if (left == NULL) {
+    printError(node->str_begin, node->str_end, "No operand found");
+    return NULL;
+  }
+
+  return left->parent = node->parserNode =
+             newParserNode(token, node->str_begin, left->str_end,
+                           (ParserNodeSingleChildMetadata *)left, parent);
+}
+
 ParserNode *parserIf(LexerNode *node, LexerNode *end, ParserNode *parent) {
   LexerNode *conditionNode = node + 1;
   if (conditionNode >= end) {
@@ -1578,6 +1613,7 @@ bool isExpression(ParserNode *node) {
   case PARSER_TOKEN_OPERATOR_MODULO_ASSIGN:
   case PARSER_TOKEN_OPERATOR_POINTER:
   case PARSER_TOKEN_OPERATOR_ADDRESS:
+  case PARSER_TOKEN_OPERATOR_DEREFERENCE:
   case PARSER_TOKEN_OPERATOR_PLUS:
   case PARSER_TOKEN_OPERATOR_MINUS:
   case PARSER_TOKEN_OPERATOR_SUM:
@@ -1670,6 +1706,7 @@ bool isType(ParserNode *node) {
   case PARSER_TOKEN_OPERATOR_MULTIPLY_ASSIGN:
   case PARSER_TOKEN_OPERATOR_DIVIDE_ASSIGN:
   case PARSER_TOKEN_OPERATOR_MODULO_ASSIGN:
+  case PARSER_TOKEN_OPERATOR_DEREFERENCE:
   case PARSER_TOKEN_OPERATOR_PLUS:
   case PARSER_TOKEN_OPERATOR_MINUS:
   case PARSER_TOKEN_OPERATOR_SUM:
@@ -1706,6 +1743,7 @@ bool isValue(ParserNode *node) {
   case PARSER_TOKEN_OPERATOR_MODULO_ASSIGN:
   case PARSER_TOKEN_OPERATOR_POINTER:
   case PARSER_TOKEN_OPERATOR_ADDRESS:
+  case PARSER_TOKEN_OPERATOR_DEREFERENCE:
   case PARSER_TOKEN_OPERATOR_PLUS:
   case PARSER_TOKEN_OPERATOR_MINUS:
   case PARSER_TOKEN_OPERATOR_SUM:
diff --git a/src/compiler/parser.h b/src/compiler/parser.h
index b888dae..e566696 100644
--- a/src/compiler/parser.h
+++ b/src/compiler/parser.h
@@ -67,6 +67,7 @@ typedef enum ParserToken {
   PARSER_TOKEN_OPERATOR_SMALLER_OR_EQUAL,
   PARSER_TOKEN_OPERATOR_POINTER,
   PARSER_TOKEN_OPERATOR_ADDRESS,
+  PARSER_TOKEN_OPERATOR_DEREFERENCE,
 
   PARSER_TOKEN_FUNCTION_DEFINITION,
 
@@ -191,6 +192,8 @@ ParserNode *parserBinaryOrLeftOperator(LexerNode *node, LexerNode *begin,
                                        LexerToken laterToken);
 ParserNode *parserLeftOperator(LexerNode *node, LexerNode *end,
                                ParserNode *parent, ParserToken token);
+ParserNode *parserRightOperator(LexerNode *node, LexerNode *begin,
+                                ParserNode *parent, ParserToken token);
 ParserNode *parserIf(LexerNode *node, LexerNode *end, ParserNode *parent);
 ParserNode *parserWhile(LexerNode *node, LexerNode *end, ParserNode *parent);
 ParserNode *parserComptime(LexerNode *node, LexerNode *end, ParserNode *parent);
diff --git a/src/runner/runner.c b/src/runner/runner.c
index 1c9ef07..efb91ee 100644
--- a/src/runner/runner.c
+++ b/src/runner/runner.c
@@ -44,6 +44,9 @@
       (type) * (originalType *)(op0)->metadata)
 
 void runnerVariableSetValue(AstTreeVariable *variable, AstTree *value) {
+  if (variable->isConst) {
+    UNREACHABLE;
+  }
   if (variable->value != NULL) {
     astTreeDelete(variable->value);
   }
@@ -179,13 +182,21 @@ AstTree *runExpression(AstTree *expr, bool *shouldRet) {
   }
   case AST_TREE_TOKEN_OPERATOR_ASSIGN: {
     AstTreeInfix *metadata = expr->metadata;
+    AstTreeVariable *left;
     if (metadata->left.token == AST_TREE_TOKEN_VARIABLE) {
-      AstTreeVariable *left = metadata->left.metadata;
-      runnerVariableSetValue(left, runExpression(&metadata->right, shouldRet));
-      return copyAstTree(left->value);
+      left = metadata->left.metadata;
+    } else if (metadata->left.token == AST_TREE_TOKEN_OPERATOR_DEREFERENCE) {
+      AstTree *left_metadata = metadata->left.metadata;
+      if (left_metadata->token != AST_TREE_TOKEN_VARIABLE) {
+        UNREACHABLE;
+      }
+      left = left_metadata->metadata;
+      left = left->value->metadata;
     } else {
       UNREACHABLE;
     }
+    runnerVariableSetValue(left, runExpression(&metadata->right, shouldRet));
+    return copyAstTree(left->value);
   }
   case AST_TREE_TOKEN_KEYWORD_RETURN: {
     AstTreeReturn *metadata = expr->metadata;
@@ -849,13 +860,25 @@ AstTree *runExpression(AstTree *expr, bool *shouldRet) {
     return copyAstTree(expr);
   case AST_TREE_TOKEN_OPERATOR_ADDRESS: {
     AstTreeSingleChild *metadata = expr->metadata;
-    return newAstTree(AST_TREE_TOKEN_VARIABLE, metadata->metadata,
-                      copyAstTree(expr->type), expr->str_begin, expr->str_end);
+    if (metadata->token != AST_TREE_TOKEN_VARIABLE) {
+      UNREACHABLE;
+    }
+    return copyAstTree(metadata);
+  }
+  case AST_TREE_TOKEN_OPERATOR_DEREFERENCE: {
+    AstTreeSingleChild *metadata = expr->metadata;
+    AstTree *operand = runExpression(metadata, shouldRet);
+    if (metadata->token != AST_TREE_TOKEN_VARIABLE) {
+      UNREACHABLE;
+    }
+    AstTreeVariable *variable = operand->metadata;
+    AstTree *ret = copyAstTree(variable->value);
+    astTreeDelete(operand);
+    return ret;
   }
   case AST_TREE_TOKEN_VARIABLE: {
     AstTreeVariable *variable = expr->metadata;
-    AstTree *value = variable->value;
-    return runExpression(value, shouldRet);
+    return copyAstTree(variable->value);
   }
   case AST_TREE_TOKEN_FUNCTION:
   case AST_TREE_TOKEN_NONE:
-- 
cgit v1.2.3