From 188fc08d3b3095a843c24207fe3a73999b2894fb Mon Sep 17 00:00:00 2001
From: A404M <ahmadmahmoudiprogrammer@gmail.com>
Date: Wed, 12 Feb 2025 16:58:21 +0330
Subject: enhanced if with else fix if scope bug

---
 src/compiler/ast-tree.c | 191 ++++++++++++++++++++++++++++++++++++++++++++++--
 src/compiler/ast-tree.h |  17 ++---
 src/compiler/lexer.c    |   7 +-
 src/compiler/lexer.h    |   1 +
 src/compiler/parser.c   | 107 +++++++++++++++++++++++----
 src/compiler/parser.h   |   5 +-
 src/main.c              |   2 +-
 src/runner/runner.c     | 181 +++++++++++++++++++++++++++------------------
 src/runner/runner.h     |   2 +
 9 files changed, 404 insertions(+), 109 deletions(-)

(limited to 'src')

diff --git a/src/compiler/ast-tree.c b/src/compiler/ast-tree.c
index f92b95c..aeb1391 100644
--- a/src/compiler/ast-tree.c
+++ b/src/compiler/ast-tree.c
@@ -222,12 +222,27 @@ void astTreePrint(const AstTree *tree, int indent) {
     for (int i = 0; i < indent; ++i)
       printf(" ");
     printf("body=\n");
-    astTreePrint(metadata->body, indent + 1);
+    astTreePrint(metadata->ifBody, indent + 1);
     printf("\n");
     for (int i = 0; i < indent; ++i)
       printf(" ");
   }
     goto RETURN_SUCCESS;
+  case AST_TREE_TOKEN_SCOPE: {
+    AstTreeScope *metadata = tree->metadata;
+    printf(",\n");
+    for (int i = 0; i < indent; ++i)
+      printf(" ");
+    printf("expressions=[\n");
+    for (size_t i = 0; i < metadata->expressions_size; ++i) {
+      astTreePrint(metadata->expressions[i], indent + 1);
+      printf(",\n");
+    }
+    for (int i = 0; i < indent; ++i)
+      printf(" ");
+    printf("]");
+  }
+    goto RETURN_SUCCESS;
   case AST_TREE_TOKEN_NONE:
   }
 
@@ -332,10 +347,24 @@ void astTreeDestroy(AstTree tree) {
   case AST_TREE_TOKEN_KEYWORD_IF: {
     AstTreeIf *metadata = tree.metadata;
     astTreeDelete(metadata->condition);
-    astTreeDelete(metadata->body);
+    astTreeDelete(metadata->ifBody);
+    free(metadata);
+  }
+    return;
+  case AST_TREE_TOKEN_SCOPE: {
+    AstTreeScope *metadata = tree.metadata;
+    for (size_t i = 0; i < metadata->expressions_size; ++i) {
+      astTreeDelete(metadata->expressions[i]);
+    }
+    for (size_t i = 0; i < metadata->variables.size; ++i) {
+      astTreeVariableDelete(metadata->variables.data[i]);
+    }
+    free(metadata->expressions);
+    free(metadata->variables.data);
     free(metadata);
   }
     return;
+
   case AST_TREE_TOKEN_NONE:
   }
   UNREACHABLE;
@@ -793,9 +822,10 @@ AstTree *astTreeParse(ParserNode *parserNode, AstTreeHelper *helper) {
   case PARSER_TOKEN_SYMBOL_EOL:
     return astTreeParse((ParserNodeSingleChildMetadata *)parserNode->metadata,
                         helper);
+  case PARSER_TOKEN_SYMBOL_CURLY_BRACKET:
+    return astTreeParseCurlyBracket(parserNode, helper);
   case PARSER_TOKEN_CONSTANT:
   case PARSER_TOKEN_SYMBOL_PARENTHESIS:
-  case PARSER_TOKEN_SYMBOL_CURLY_BRACKET:
   case PARSER_TOKEN_SYMBOL_COMMA:
   case PARSER_TOKEN_NONE:
   case PARSER_TOKEN_ROOT:
@@ -1216,19 +1246,135 @@ AstTree *astTreeParseIf(ParserNode *parserNode, AstTreeHelper *helper) {
     return NULL;
   }
 
-  AstTree *body = astTreeParse(node_metadata->body, helper);
-  if (body == NULL) {
+  AstTree *ifBody = astTreeParse(node_metadata->ifBody, helper);
+  if (ifBody == NULL) {
     return NULL;
   }
 
+  AstTree *elseBody;
+  if(node_metadata->elseBody != NULL){
+    elseBody = astTreeParse(node_metadata->elseBody, helper);
+    if(elseBody == NULL){
+      return NULL;
+    }
+  }else{
+    elseBody = NULL;
+  }
+
   AstTreeIf *metadata = a404m_malloc(sizeof(*metadata));
   metadata->condition = condition;
-  metadata->body = body;
+  metadata->ifBody = ifBody;
+  metadata->elseBody = elseBody;
 
   return newAstTree(AST_TREE_TOKEN_KEYWORD_IF, metadata, NULL,
                     parserNode->str_begin, parserNode->str_end);
 }
 
+AstTree *astTreeParseCurlyBracket(ParserNode *parserNode,
+                                  AstTreeHelper *p_helper) {
+  ParserNodeArray *body = parserNode->metadata;
+
+  size_t expressions_size = 0;
+
+  AstTreeScope *scope = a404m_malloc(sizeof(*scope));
+  scope->variables.data = a404m_malloc(0);
+  scope->variables.size = 0;
+  scope->expressions = a404m_malloc(0);
+  scope->expressions_size = 0;
+
+  size_t variables_size = p_helper->variables_size + 1;
+  AstTreeVariables *variables[variables_size];
+  for (size_t i = 0; i < p_helper->variables_size; ++i) {
+    variables[i] = p_helper->variables[i];
+  }
+  variables[variables_size - 1] = &scope->variables;
+
+  AstTreeHelper helper = {
+      .variables = variables,
+      .variables_size = variables_size,
+      .variable = p_helper->variable,
+      .globalDeps = p_helper->globalDeps,
+  };
+
+  for (size_t i = 0; i < body->size; ++i) {
+    ParserNode *node = body->data[i];
+    switch (node->token) {
+    case PARSER_TOKEN_SYMBOL_EOL:
+      node = (ParserNodeSingleChildMetadata *)node->metadata;
+      goto OK_NODE;
+    case PARSER_TOKEN_KEYWORD_IF:
+      goto OK_NODE;
+    case PARSER_TOKEN_ROOT:
+    case PARSER_TOKEN_IDENTIFIER:
+    case PARSER_TOKEN_VALUE_U64:
+    case PARSER_TOKEN_VALUE_BOOL:
+    case PARSER_TOKEN_TYPE_TYPE:
+    case PARSER_TOKEN_TYPE_FUNCTION:
+    case PARSER_TOKEN_TYPE_VOID:
+    case PARSER_TOKEN_TYPE_U64:
+    case PARSER_TOKEN_TYPE_BOOL:
+    case PARSER_TOKEN_KEYWORD_PRINT_U64:
+    case PARSER_TOKEN_KEYWORD_RETURN:
+    case PARSER_TOKEN_CONSTANT:
+    case PARSER_TOKEN_VARIABLE:
+    case PARSER_TOKEN_SYMBOL_CURLY_BRACKET:
+    case PARSER_TOKEN_SYMBOL_PARENTHESIS:
+    case PARSER_TOKEN_SYMBOL_COMMA:
+    case PARSER_TOKEN_OPERATOR_ASSIGN:
+    case PARSER_TOKEN_OPERATOR_PLUS:
+    case PARSER_TOKEN_OPERATOR_MINUS:
+    case PARSER_TOKEN_OPERATOR_SUM:
+    case PARSER_TOKEN_OPERATOR_SUB:
+    case PARSER_TOKEN_OPERATOR_MULTIPLY:
+    case PARSER_TOKEN_OPERATOR_DIVIDE:
+    case PARSER_TOKEN_OPERATOR_MODULO:
+    case PARSER_TOKEN_FUNCTION_DEFINITION:
+    case PARSER_TOKEN_FUNCTION_CALL:
+      printError(node->str_begin, node->str_end, "Unexpected %s",
+                 PARSER_TOKEN_STRINGS[node->token]);
+      goto RETURN_ERROR;
+    case PARSER_TOKEN_NONE:
+    }
+    UNREACHABLE;
+  OK_NODE:
+
+    if (node->token == PARSER_TOKEN_CONSTANT) {
+      if (!astTreeParseConstant(node, &helper)) {
+        goto RETURN_ERROR;
+      }
+    } else {
+      AstTree *tree = astTreeParse(node, &helper);
+
+      if (tree == NULL) {
+        goto RETURN_ERROR;
+      }
+
+      if (expressions_size == scope->expressions_size) {
+        expressions_size += expressions_size / 2 + 1;
+        scope->expressions = a404m_realloc(
+            scope->expressions, expressions_size * sizeof(*scope->expressions));
+      }
+      scope->expressions[scope->expressions_size] = tree;
+      scope->expressions_size += 1;
+    }
+  }
+
+  scope->expressions =
+      a404m_realloc(scope->expressions,
+                    scope->expressions_size * sizeof(*scope->expressions));
+
+  return newAstTree(AST_TREE_TOKEN_SCOPE, scope, NULL, parserNode->str_begin,
+                    parserNode->str_end);
+
+RETURN_ERROR:
+  for (size_t i = 0; i < scope->expressions_size; ++i) {
+    // astTreeDelete(scope->expressions[i]);
+  }
+  free(scope->variables.data);
+  free(scope->expressions);
+  return NULL;
+}
+
 AstTreeFunction *getFunction(AstTree *value) {
   switch (value->token) {
   case AST_TREE_TOKEN_FUNCTION:
@@ -1262,6 +1408,7 @@ AstTreeFunction *getFunction(AstTree *value) {
   case AST_TREE_TOKEN_OPERATOR_MULTIPLY:
   case AST_TREE_TOKEN_OPERATOR_DIVIDE:
   case AST_TREE_TOKEN_OPERATOR_MODULO:
+  case AST_TREE_TOKEN_SCOPE:
     return NULL;
   case AST_TREE_TOKEN_NONE:
   }
@@ -1293,6 +1440,7 @@ bool isConst(AstTree *value) {
   case AST_TREE_TOKEN_OPERATOR_MULTIPLY:
   case AST_TREE_TOKEN_OPERATOR_DIVIDE:
   case AST_TREE_TOKEN_OPERATOR_MODULO:
+  case AST_TREE_TOKEN_SCOPE:
     return false;
   case AST_TREE_TOKEN_VARIABLE: {
     AstTreeVariable *metadata = value->metadata;
@@ -1361,6 +1509,7 @@ AstTree *makeTypeOf(AstTree *value) {
   case AST_TREE_TOKEN_KEYWORD_PRINT_U64:
   case AST_TREE_TOKEN_KEYWORD_RETURN:
   case AST_TREE_TOKEN_KEYWORD_IF:
+  case AST_TREE_TOKEN_SCOPE:
   case AST_TREE_TOKEN_NONE:
   }
   UNREACHABLE;
@@ -1384,6 +1533,7 @@ bool typeIsEqual(const AstTree *type0, const AstTree *type1) {
   case AST_TREE_TOKEN_OPERATOR_MODULO:
   case AST_TREE_TOKEN_OPERATOR_PLUS:
   case AST_TREE_TOKEN_OPERATOR_MINUS:
+  case AST_TREE_TOKEN_SCOPE:
     return false;
   case AST_TREE_TOKEN_TYPE_TYPE:
   case AST_TREE_TOKEN_TYPE_VOID:
@@ -1424,6 +1574,7 @@ bool typeIsEqual(const AstTree *type0, const AstTree *type1) {
 bool isCircularDependencies(AstTreeHelper *helper, AstTreeVariable *variable,
                             AstTree *tree) {
   switch (tree->token) {
+  case AST_TREE_TOKEN_SCOPE:
   case AST_TREE_TOKEN_TYPE_TYPE:
   case AST_TREE_TOKEN_TYPE_FUNCTION:
   case AST_TREE_TOKEN_TYPE_VOID:
@@ -1543,7 +1694,10 @@ bool setAllTypes(AstTree *tree, AstTreeFunction *function) {
     return setTypesVariableDefine(tree);
   case AST_TREE_TOKEN_KEYWORD_IF:
     return setTypesIf(tree, function);
+  case AST_TREE_TOKEN_SCOPE:
+    return setTypesScope(tree, function);
   case AST_TREE_TOKEN_NONE:
+    break;
   }
   UNREACHABLE;
 }
@@ -1733,7 +1887,7 @@ bool setTypesIf(AstTree *tree, AstTreeFunction *function) {
   AstTreeIf *metadata = tree->metadata;
 
   if (!setAllTypes(metadata->condition, function) ||
-      !setAllTypes(metadata->body, function)) {
+      !setAllTypes(metadata->ifBody, function)) {
     return false;
   }
 
@@ -1748,6 +1902,26 @@ bool setTypesIf(AstTree *tree, AstTreeFunction *function) {
   return true;
 }
 
+bool setTypesScope(AstTree *tree, AstTreeFunction *function) {
+  AstTreeScope *metadata = tree->metadata;
+
+  tree->type = &AST_TREE_VOID_TYPE;
+
+  for (size_t i = 0; i < metadata->expressions_size; ++i) {
+    if (!setAllTypes(metadata->expressions[i], function)) {
+      return false;
+    }
+  }
+
+  for (size_t i = 0; i < metadata->variables.size; ++i) {
+    if (!setTypesAstVariable(metadata->variables.data[i])) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
 bool setTypesAstInfix(AstTreeInfix *infix) {
   return setAllTypes(&infix->left, NULL) && setAllTypes(&infix->right, NULL);
 }
@@ -1787,8 +1961,10 @@ bool astTreeClean(AstTree *tree) {
   case AST_TREE_TOKEN_OPERATOR_MULTIPLY:
   case AST_TREE_TOKEN_OPERATOR_DIVIDE:
   case AST_TREE_TOKEN_OPERATOR_MODULO:
+  case AST_TREE_TOKEN_SCOPE:
     return true;
   case AST_TREE_TOKEN_NONE:
+    break;
   }
   UNREACHABLE;
 }
@@ -1879,6 +2055,7 @@ size_t astTreeTypeSize(AstTree tree) {
   case AST_TREE_TOKEN_OPERATOR_MULTIPLY:
   case AST_TREE_TOKEN_OPERATOR_DIVIDE:
   case AST_TREE_TOKEN_OPERATOR_MODULO:
+  case AST_TREE_TOKEN_SCOPE:
   case AST_TREE_TOKEN_NONE:
   }
   UNREACHABLE;
diff --git a/src/compiler/ast-tree.h b/src/compiler/ast-tree.h
index 38a6f66..594b213 100644
--- a/src/compiler/ast-tree.h
+++ b/src/compiler/ast-tree.h
@@ -33,6 +33,8 @@ typedef enum AstTreeToken {
   AST_TREE_TOKEN_OPERATOR_DIVIDE,
   AST_TREE_TOKEN_OPERATOR_MODULO,
 
+  AST_TREE_TOKEN_SCOPE,
+
   AST_TREE_TOKEN_NONE,
 } AstTreeToken;
 
@@ -109,7 +111,8 @@ typedef struct AstTreeReturn {
 
 typedef struct AstTreeIf {
   AstTree *condition;
-  AstTree *body;
+  AstTree *ifBody;
+  AstTree *elseBody;
 } AstTreeIf;
 
 typedef struct AstTreeHelper {
@@ -141,31 +144,22 @@ AstTreeVariable *getVariable(AstTreeHelper *helper, char *name_begin,
                              char *name_end);
 
 AstTree *astTreeParse(ParserNode *parserNode, AstTreeHelper *helper);
-
 AstTree *astTreeParseFunction(ParserNode *parserNode, AstTreeHelper *helper);
-
 AstTree *astTreeParseTypeFunction(ParserNode *parserNode,
                                   AstTreeHelper *helper);
-
 AstTree *astTreeParseFunctionCall(ParserNode *parserNode,
                                   AstTreeHelper *helper);
-
 AstTree *astTreeParseIdentifier(ParserNode *parserNode, AstTreeHelper *helper);
-
 AstTree *astTreeParsePrintU64(ParserNode *parserNode, AstTreeHelper *helper);
 AstTree *astTreeParseReturn(ParserNode *parserNode, AstTreeHelper *helper);
-
 AstTree *astTreeParseBinaryOperator(ParserNode *parserNode,
                                     AstTreeHelper *helper, AstTreeToken token);
-
 AstTree *astTreeParseUnaryOperator(ParserNode *parserNode,
                                    AstTreeHelper *helper, AstTreeToken token);
-
 bool astTreeParseConstant(ParserNode *parserNode, AstTreeHelper *helper);
-
 AstTree *astTreeParseVariable(ParserNode *parserNode, AstTreeHelper *helper);
-
 AstTree *astTreeParseIf(ParserNode *parserNode, AstTreeHelper *helper);
+AstTree *astTreeParseCurlyBracket(ParserNode *parserNode, AstTreeHelper *helper);
 
 AstTreeFunction *getFunction(AstTree *value);
 bool isConst(AstTree *value);
@@ -188,6 +182,7 @@ bool setTypesOperatorInfix(AstTree *tree);
 bool setTypesOperatorUnary(AstTree *tree);
 bool setTypesVariableDefine(AstTree *tree);
 bool setTypesIf(AstTree *tree,AstTreeFunction *function);
+bool setTypesScope(AstTree *tree,AstTreeFunction *function);
 
 bool setTypesAstVariable(AstTreeVariable *variable);
 bool setTypesAstInfix(AstTreeInfix *infix);
diff --git a/src/compiler/lexer.c b/src/compiler/lexer.c
index a61c3af..1f45be0 100644
--- a/src/compiler/lexer.c
+++ b/src/compiler/lexer.c
@@ -21,6 +21,7 @@ const char *LEXER_TOKEN_STRINGS[] = {
     "LEXER_TOKEN_KEYWORD_TRUE",
     "LEXER_TOKEN_KEYWORD_FALSE",
     "LEXER_TOKEN_KEYWORD_IF",
+    "LEXER_TOKEN_KEYWORD_ELSE",
 
     "LEXER_TOKEN_NUMBER",
 
@@ -68,14 +69,15 @@ const size_t LEXER_SYMBOL_SIZE =
     sizeof(LEXER_SYMBOL_TOKENS) / sizeof(*LEXER_SYMBOL_TOKENS);
 
 const char *LEXER_KEYWORD_STRINGS[] = {
-    "type", "void", "u64", "bool", "print_u64", "return", "true", "false", "if",
+    "type",   "void", "u64",   "bool", "print_u64",
+    "return", "true", "false", "if",   "else",
 };
 const LexerToken LEXER_KEYWORD_TOKENS[] = {
     LEXER_TOKEN_KEYWORD_TYPE,      LEXER_TOKEN_KEYWORD_VOID,
     LEXER_TOKEN_KEYWORD_U64,       LEXER_TOKEN_KEYWORD_BOOL,
     LEXER_TOKEN_KEYWORD_PRINT_U64, LEXER_TOKEN_KEYWORD_RETURN,
     LEXER_TOKEN_KEYWORD_TRUE,      LEXER_TOKEN_KEYWORD_FALSE,
-    LEXER_TOKEN_KEYWORD_IF,
+    LEXER_TOKEN_KEYWORD_IF,        LEXER_TOKEN_KEYWORD_ELSE,
 };
 const size_t LEXER_KEYWORD_SIZE =
     sizeof(LEXER_KEYWORD_TOKENS) / sizeof(*LEXER_KEYWORD_TOKENS);
@@ -208,6 +210,7 @@ void lexerPushClear(LexerNodeArray *array, size_t *array_size, char *iter,
   case LEXER_TOKEN_KEYWORD_TRUE:
   case LEXER_TOKEN_KEYWORD_FALSE:
   case LEXER_TOKEN_KEYWORD_IF:
+  case LEXER_TOKEN_KEYWORD_ELSE:
   case LEXER_TOKEN_NUMBER:
   case LEXER_TOKEN_SYMBOL_EOL:
   case LEXER_TOKEN_SYMBOL_OPEN_PARENTHESIS:
diff --git a/src/compiler/lexer.h b/src/compiler/lexer.h
index 4e74d1d..e7afd62 100644
--- a/src/compiler/lexer.h
+++ b/src/compiler/lexer.h
@@ -14,6 +14,7 @@ typedef enum LexerToken {
   LEXER_TOKEN_KEYWORD_TRUE,
   LEXER_TOKEN_KEYWORD_FALSE,
   LEXER_TOKEN_KEYWORD_IF,
+  LEXER_TOKEN_KEYWORD_ELSE,
 
   LEXER_TOKEN_NUMBER,
 
diff --git a/src/compiler/parser.c b/src/compiler/parser.c
index d4364af..b952dc1 100644
--- a/src/compiler/parser.c
+++ b/src/compiler/parser.c
@@ -297,8 +297,13 @@ void parserNodePrint(const ParserNode *node, int indent) {
     printf(",\n");
     for (int i = 0; i < indent; ++i)
       printf(" ");
-    printf("body=\n");
-    parserNodePrint(metadata->body, indent + 1);
+    printf("ifBody=\n");
+    parserNodePrint(metadata->ifBody, indent + 1);
+    printf("\n,");
+    for (int i = 0; i < indent; ++i)
+      printf(" ");
+    printf("elseBody=\n");
+    parserNodePrint(metadata->elseBody, indent + 1);
     printf("\n");
     for (int i = 0; i < indent; ++i)
       printf(" ");
@@ -404,7 +409,8 @@ void parserNodeDelete(ParserNode *node) {
   case PARSER_TOKEN_KEYWORD_IF: {
     ParserNodeIfMetadata *metadata = node->metadata;
     parserNodeDelete(metadata->condition);
-    parserNodeDelete(metadata->body);
+    parserNodeDelete(metadata->ifBody);
+    parserNodeDelete(metadata->elseBody);
     free(metadata);
   }
     goto RETURN_SUCCESS;
@@ -577,6 +583,7 @@ ParserNode *parseNode(LexerNode *node, LexerNode *begin, LexerNode *end,
   }
   case LEXER_TOKEN_KEYWORD_IF:
     return parserIf(node, end, parent);
+  case LEXER_TOKEN_KEYWORD_ELSE:
   case LEXER_TOKEN_SYMBOL:
   case LEXER_TOKEN_SYMBOL_OPEN_PARENTHESIS:
   case LEXER_TOKEN_SYMBOL_OPEN_CURLY_BRACKET:
@@ -588,6 +595,23 @@ ParserNode *parseNode(LexerNode *node, LexerNode *begin, LexerNode *end,
 
 ParserNode *getUntilCommonParent(ParserNode *node, ParserNode *parent) {
   while (node != NULL && node != parent && node->parent != parent) {
+    if (node == node->parent) {
+      return NULL;
+    }
+
+    node = node->parent;
+  }
+  return node;
+}
+
+ParserNode *getUntilCommonParents(ParserNode *node, ParserNode *parent,
+                                  ParserNode *parent2) {
+  while (node != NULL && node != parent && node->parent != parent &&
+         node->parent != parent2) {
+    if (node == node->parent) {
+      return NULL;
+    }
+
     node = node->parent;
   }
   return node;
@@ -616,6 +640,29 @@ ParserNode *getNextUsingCommonParent(LexerNode *node, LexerNode *end,
   return NULL;
 }
 
+LexerNode *getNextLexerNodeUsingCommonParent(LexerNode *node, LexerNode *end,
+                                             ParserNode *parent) {
+  ParserNode *parsed = getUntilCommonParent(node->parserNode, parent);
+  if (parsed == NULL) {
+    return NULL;
+  }
+
+  while (true) {
+    node += 1;
+    if (node >= end) {
+      return NULL;
+    }
+
+    ParserNode *newParsed = getUntilCommonParent(node->parserNode, parsed);
+
+    if (newParsed == NULL) {
+      return node;
+    }
+  }
+
+  return NULL;
+}
+
 ParserNode *parserIdentifier(LexerNode *node, ParserNode *parent) {
   return node->parserNode =
              newParserNode(PARSER_TOKEN_IDENTIFIER, node->str_begin,
@@ -781,9 +828,11 @@ ParserNode *parserParenthesis(LexerNode *closing, LexerNode *begin,
   for (LexerNode *iter = closing - 1; iter >= begin; --iter) {
 
     if (iter->parserNode != NULL) {
-      ParserNode *pNode = getUntilCommonParent(iter->parserNode, parent);
+      ParserNode *pNode =
+          getUntilCommonParents(iter->parserNode, parent, parserNode);
       if (pNode == NULL) {
         printLog("Bad node", pNode->str_begin, pNode->str_end);
+        return NULL;
       } else {
         pNode->parent = parserNode;
       }
@@ -850,9 +899,11 @@ ParserNode *parserCurlyBrackets(LexerNode *closing, LexerNode *begin,
 
   for (LexerNode *iter = closing - 1; iter >= begin; --iter) {
     if (iter->parserNode != NULL) {
-      ParserNode *pNode = getUntilCommonParent(iter->parserNode, parent);
+      ParserNode *pNode =
+          getUntilCommonParents(iter->parserNode, parent, parserNode);
       if (pNode == NULL) {
-        printLog("Bad node", pNode->str_begin, pNode->str_end);
+        printLog(iter->str_begin, iter->str_end, "Bad node");
+        return NULL;
       } else {
         pNode->parent = parserNode;
       }
@@ -868,11 +919,11 @@ ParserNode *parserCurlyBrackets(LexerNode *closing, LexerNode *begin,
     return NULL;
   }
 
-  parserNode->str_begin = opening->str_begin,
+  parserNode->str_begin = opening->str_begin;
   parserNode->str_end = closing->str_end;
 
-  opening->parserNode = parserNode;
-  closing->parserNode = parserNode;
+  opening->parserNode = closing->parserNode = parserNode;
+
   if (parserNodeArray(opening + 1, closing, parserNode)) {
     return parserNode;
   } else {
@@ -1156,7 +1207,9 @@ ParserNode *parserIf(LexerNode *node, LexerNode *end, ParserNode *parent) {
     return NULL;
   }
 
-  ParserNode *body = getNextUsingCommonParent(conditionNode, end, parent);
+  LexerNode *bodyNode =
+      getNextLexerNodeUsingCommonParent(conditionNode, end, parent);
+  ParserNode *body = getUntilCommonParent(bodyNode->parserNode, parent);
 
   if (body == NULL) {
     printError(node->str_begin, node->str_end, "If has bad body");
@@ -1165,11 +1218,37 @@ ParserNode *parserIf(LexerNode *node, LexerNode *end, ParserNode *parent) {
 
   ParserNodeIfMetadata *metadata = a404m_malloc(sizeof(*metadata));
   metadata->condition = condition;
-  metadata->body = body;
+  metadata->ifBody = body;
+
+  LexerNode *elseNode =
+      getNextLexerNodeUsingCommonParent(bodyNode, end, parent);
+  if (elseNode == NULL || elseNode->token != LEXER_TOKEN_KEYWORD_ELSE) {
+    metadata->elseBody = NULL;
+    return condition->parent = body->parent = node->parserNode =
+               newParserNode(PARSER_TOKEN_KEYWORD_IF, node->str_begin,
+                             body->str_end, metadata, parent);
+  }
+
+  LexerNode *elseBodyNode = elseNode + 1;
+
+  if (elseBodyNode >= end || elseBodyNode->parserNode == NULL) {
+    printError(elseNode->str_begin, elseNode->str_end, "Else has bad body");
+    return NULL;
+  }
+
+  ParserNode *elseBody = getUntilCommonParent(elseBodyNode->parserNode, parent);
+
+  if (elseBody == NULL) {
+    printError(elseNode->str_begin, elseNode->str_end, "Else has bad body");
+    return NULL;
+  }
+
+  metadata->elseBody = elseBody;
 
-  return condition->parent = body->parent = node->parserNode =
-             newParserNode(PARSER_TOKEN_KEYWORD_IF, node->str_begin,
-                           node->str_end, metadata, parent);
+  return elseBody->parent = elseNode->parserNode = condition->parent =
+             body->parent = node->parserNode =
+                 newParserNode(PARSER_TOKEN_KEYWORD_IF, node->str_begin,
+                               elseBody->str_end, metadata, parent);
 }
 
 bool isAllArguments(const ParserNodeArray *nodes) {
diff --git a/src/compiler/parser.h b/src/compiler/parser.h
index cb90b71..60825a9 100644
--- a/src/compiler/parser.h
+++ b/src/compiler/parser.h
@@ -106,7 +106,8 @@ typedef bool ParserNodeBoolMetadata;
 
 typedef struct ParserNodeIfMetadata {
   ParserNode *condition;
-  ParserNode *body;
+  ParserNode *ifBody;
+  ParserNode *elseBody;
 }ParserNodeIfMetadata;
 
 void parserNodePrint(const ParserNode *node, int indent);
@@ -122,7 +123,9 @@ ParserNode *parseNode(LexerNode *node, LexerNode *begin, LexerNode *end,
                       ParserNode *parent, bool *conti);
 
 ParserNode *getUntilCommonParent(ParserNode *node, ParserNode *parent);
+ParserNode *getUntilCommonParents(ParserNode *node, ParserNode *parent,ParserNode *parent2);
 ParserNode *getNextUsingCommonParent(LexerNode *node,LexerNode *end, ParserNode *parent);
+LexerNode *getNextLexerNodeUsingCommonParent(LexerNode *node,LexerNode *end, ParserNode *parent);
 
 ParserNode *parserIdentifier(LexerNode *node, ParserNode *parent);
 ParserNode *parserType(LexerNode *node, ParserNode *parent);
diff --git a/src/main.c b/src/main.c
index 8a61324..4b7747b 100644
--- a/src/main.c
+++ b/src/main.c
@@ -111,7 +111,7 @@ int main(int argc, char *argv[]) {
     return 1;
   }
 
-  const int ret = run(argv[1], false);
+  const int ret = run(argv[1], true);
   fileDelete();
   return ret;
 }
diff --git a/src/runner/runner.c b/src/runner/runner.c
index 958658a..431305c 100644
--- a/src/runner/runner.c
+++ b/src/runner/runner.c
@@ -162,87 +162,122 @@ AstTree *runAstTreeFunction(AstTree *tree, AstTree **arguments,
   AstTree *ret = &AST_TREE_VOID_VALUE;
 
   for (size_t i = 0; i < function->scope.expressions_size; ++i) {
-    AstTree *expr = function->scope.expressions[i];
-  RUN:
-    switch (expr->token) {
-    case AST_TREE_TOKEN_KEYWORD_PRINT_U64: {
-      AstTreeSingleChild *metadata = expr->metadata;
-      AstTree *tree = calcAstTreeValue(metadata, &pages);
-      printf("%lu", (AstTreeU64)tree->metadata);
-      astTreeDelete(tree);
+    AstTree *r = runExpression(function->scope.expressions[i], &pages);
+    if (r) {
+      ret = r;
+      break;
     }
-      continue;
-    case AST_TREE_TOKEN_FUNCTION_CALL: {
-      AstTree *ret = calcAstTreeValue(expr, &pages);
-      if (ret != &AST_TREE_VOID_VALUE) {
-        astTreeDelete(ret);
-      }
-    }
-      continue;
-    case AST_TREE_TOKEN_OPERATOR_ASSIGN: {
-      AstTreeInfix *metadata = expr->metadata;
-      if (metadata->left.token == AST_TREE_TOKEN_VARIABLE) {
-        AstTreeVariable *left = metadata->left.metadata;
-        runnerVariableSetValue(&pages, left,
-                               calcAstTreeValue(&metadata->right, &pages));
-      } else {
-        UNREACHABLE;
-      }
-    }
-      continue;
-    case AST_TREE_TOKEN_KEYWORD_RETURN: {
-      AstTreeReturn *metadata = expr->metadata;
-      if (metadata->value != NULL) {
-        ret = calcAstTreeValue(metadata->value, &pages);
-      } else {
-        ret = &AST_TREE_VOID_VALUE;
-      }
-      goto RETURN;
+  }
+
+  runnerVariablesDelete(pages.data[pages.size - 1]);
+  free(pages.data);
+
+  return ret;
+}
+
+AstTree *runExpression(AstTree *expr, RunnerVariablePages *pages) {
+  switch (expr->token) {
+  case AST_TREE_TOKEN_KEYWORD_PRINT_U64: {
+    AstTreeSingleChild *metadata = expr->metadata;
+    AstTree *tree = calcAstTreeValue(metadata, pages);
+    printf("%lu", (AstTreeU64)tree->metadata);
+    astTreeDelete(tree);
+  }
+    return NULL;
+  case AST_TREE_TOKEN_FUNCTION_CALL: {
+    AstTree *ret = calcAstTreeValue(expr, pages);
+    if (ret != &AST_TREE_VOID_VALUE) {
+      astTreeDelete(ret);
     }
-      continue;
-    case AST_TREE_TOKEN_VARIABLE_DEFINE: {
-      AstTreeVariable *variable = expr->metadata;
-      runnerVariableSetValue(&pages, variable, copyAstTree(variable->value));
+  }
+    return NULL;
+  case AST_TREE_TOKEN_OPERATOR_ASSIGN: {
+    AstTreeInfix *metadata = expr->metadata;
+    if (metadata->left.token == AST_TREE_TOKEN_VARIABLE) {
+      AstTreeVariable *left = metadata->left.metadata;
+      runnerVariableSetValue(pages, left,
+                             calcAstTreeValue(&metadata->right, pages));
+    } else {
+      UNREACHABLE;
     }
-      continue;
-    case AST_TREE_TOKEN_KEYWORD_IF: {
-      AstTreeIf *metadata = expr->metadata;
-      AstTree *tree = calcAstTreeValue(metadata->condition, &pages);
-      if ((AstTreeBool)tree->metadata) {
-        expr = metadata->body;
-        goto RUN;
-      }
-      astTreeDelete(tree);
+  }
+    return NULL;
+  case AST_TREE_TOKEN_KEYWORD_RETURN: {
+    AstTreeReturn *metadata = expr->metadata;
+    if (metadata->value != NULL) {
+      return calcAstTreeValue(metadata->value, pages);
+    } else {
+      return &AST_TREE_VOID_VALUE;
     }
-      continue;
-    case AST_TREE_TOKEN_OPERATOR_PLUS:
-    case AST_TREE_TOKEN_OPERATOR_MINUS:
-    case AST_TREE_TOKEN_OPERATOR_SUM:
-    case AST_TREE_TOKEN_OPERATOR_SUB:
-    case AST_TREE_TOKEN_OPERATOR_MULTIPLY:
-    case AST_TREE_TOKEN_OPERATOR_DIVIDE:
-    case AST_TREE_TOKEN_OPERATOR_MODULO:
-    case AST_TREE_TOKEN_FUNCTION:
-    case AST_TREE_TOKEN_TYPE_TYPE:
-    case AST_TREE_TOKEN_TYPE_FUNCTION:
-    case AST_TREE_TOKEN_TYPE_VOID:
-    case AST_TREE_TOKEN_TYPE_U64:
-    case AST_TREE_TOKEN_TYPE_BOOL:
-    case AST_TREE_TOKEN_VARIABLE:
-    case AST_TREE_TOKEN_VALUE_VOID:
-    case AST_TREE_TOKEN_VALUE_U64:
-    case AST_TREE_TOKEN_VALUE_BOOL:
-    case AST_TREE_TOKEN_NONE:
+  }
+  case AST_TREE_TOKEN_VARIABLE_DEFINE: {
+    AstTreeVariable *variable = expr->metadata;
+    runnerVariableSetValue(pages, variable, copyAstTree(variable->value));
+  }
+    return NULL;
+  case AST_TREE_TOKEN_KEYWORD_IF: {
+    AstTreeIf *metadata = expr->metadata;
+    AstTree *tree = calcAstTreeValue(metadata->condition, pages);
+    if ((AstTreeBool)tree->metadata) {
+      return runExpression(metadata->ifBody, pages);
+    } else {
+      return runExpression(metadata->elseBody, pages);
     }
-    printLog("Bad token %d", expr->token);
-    UNREACHABLE;
+    astTreeDelete(tree);
   }
+    return NULL;
+  case AST_TREE_TOKEN_SCOPE: {
+    AstTreeScope *metadata = expr->metadata;
 
-RETURN:
-  runnerVariablesDelete(pages.data[pages.size - 1]);
-  free(pages.data);
+    RunnerVariablePages newPages = {
+        .data = a404m_malloc((pages->size + 1) * sizeof(*newPages.data)),
+        .size = pages->size + 1,
+    };
 
-  return ret;
+    for (size_t i = 0; i < pages->size; ++i) {
+      newPages.data[i] = pages->data[i];
+    }
+
+    newPages.data[pages->size] =
+        a404m_malloc(sizeof(*newPages.data[pages->size]));
+    newPages.data[pages->size]->size = 0;
+    newPages.data[pages->size]->data =
+        a404m_malloc(newPages.data[pages->size]->size *
+                     sizeof(*newPages.data[pages->size]->data));
+
+    for (size_t i = 0; i < metadata->variables.size; ++i) {
+      AstTreeVariable *variable = metadata->variables.data[i];
+      runnerVariablePush(newPages.data[newPages.size - 1], variable);
+    }
+
+    for (size_t i = 0; i < metadata->expressions_size; ++i) {
+      AstTree *r = runExpression(metadata->expressions[i], &newPages);
+      if (r) {
+        return r;
+      }
+    }
+  }
+    return NULL;
+  case AST_TREE_TOKEN_OPERATOR_PLUS:
+  case AST_TREE_TOKEN_OPERATOR_MINUS:
+  case AST_TREE_TOKEN_OPERATOR_SUM:
+  case AST_TREE_TOKEN_OPERATOR_SUB:
+  case AST_TREE_TOKEN_OPERATOR_MULTIPLY:
+  case AST_TREE_TOKEN_OPERATOR_DIVIDE:
+  case AST_TREE_TOKEN_OPERATOR_MODULO:
+  case AST_TREE_TOKEN_FUNCTION:
+  case AST_TREE_TOKEN_TYPE_TYPE:
+  case AST_TREE_TOKEN_TYPE_FUNCTION:
+  case AST_TREE_TOKEN_TYPE_VOID:
+  case AST_TREE_TOKEN_TYPE_U64:
+  case AST_TREE_TOKEN_TYPE_BOOL:
+  case AST_TREE_TOKEN_VARIABLE:
+  case AST_TREE_TOKEN_VALUE_VOID:
+  case AST_TREE_TOKEN_VALUE_U64:
+  case AST_TREE_TOKEN_VALUE_BOOL:
+  case AST_TREE_TOKEN_NONE:
+  }
+  UNREACHABLE;
 }
 
 AstTree *calcAstTreeValue(AstTree *tree, RunnerVariablePages *pages) {
diff --git a/src/runner/runner.h b/src/runner/runner.h
index 758ed28..c1a2382 100644
--- a/src/runner/runner.h
+++ b/src/runner/runner.h
@@ -29,5 +29,7 @@ bool runAstTree(AstTreeRoot *root);
 AstTree *runAstTreeFunction(AstTree *tree, AstTree **arguments,
                             size_t arguments_size,RunnerVariablePages *pages);
 
+AstTree* runExpression(AstTree *expr,RunnerVariablePages *pages);
+
 AstTree *calcAstTreeValue(AstTree *tree,RunnerVariablePages *pages);
 AstTree *deepCopyAstTree(AstTree *tree);
-- 
cgit v1.2.3