From 6bd439f35c1184f04488ee4f0db21632e1301b51 Mon Sep 17 00:00:00 2001
From: A404M <ahmadmahmoudiprogrammer@gmail.com>
Date: Fri, 7 Feb 2025 21:14:11 +0330
Subject: add plus trying to add return

---
 src/compiler/ast-tree.c       | 337 ++++++++++++++++++++++--------------------
 src/compiler/ast-tree.h       |  19 ++-
 src/compiler/code-generator.c |  30 +++-
 src/compiler/code-generator.h |   1 +
 src/compiler/lexer.c          |   7 +-
 src/compiler/lexer.h          |   2 +
 src/compiler/parser.c         |  44 +++++-
 src/compiler/parser.h         |   3 +
 src/main.c                    |  54 +++----
 src/runner/runner.c           | 143 ++++++++++++++++++
 src/runner/runner.h           |  11 ++
 src/utils/log.h               |   2 +
 12 files changed, 453 insertions(+), 200 deletions(-)
 create mode 100644 src/runner/runner.c
 create mode 100644 src/runner/runner.h

(limited to 'src')

diff --git a/src/compiler/ast-tree.c b/src/compiler/ast-tree.c
index 7bb9f8f..7f955ff 100644
--- a/src/compiler/ast-tree.c
+++ b/src/compiler/ast-tree.c
@@ -6,9 +6,28 @@
 #include <stdlib.h>
 #include <string.h>
 
-const AstTree AST_TREE_U64_TYPE = {
+AstTree AST_TREE_TYPE_TYPE = {
+    .token = AST_TREE_TOKEN_TYPE_TYPE,
+    .metadata = NULL,
+    .type = &AST_TREE_TYPE_TYPE,
+};
+
+AstTree AST_TREE_VOID_TYPE = {
+    .token = AST_TREE_TOKEN_TYPE_VOID,
+    .metadata = NULL,
+    .type = &AST_TREE_TYPE_TYPE,
+};
+
+AstTree AST_TREE_U64_TYPE = {
     .token = AST_TREE_TOKEN_TYPE_U64,
     .metadata = NULL,
+    .type = &AST_TREE_TYPE_TYPE,
+};
+
+AstTree AST_TREE_VOID_VALUE = {
+    .token = AST_TREE_TOKEN_NONE,
+    .metadata = NULL,
+    .type = &AST_TREE_VOID_TYPE,
 };
 
 const char *AST_TREE_TOKEN_STRINGS[] = {
@@ -27,6 +46,7 @@ const char *AST_TREE_TOKEN_STRINGS[] = {
     "AST_TREE_TOKEN_VALUE_U64",
 
     "AST_TREE_TOKEN_OPERATOR_ASSIGN",
+    "AST_TREE_TOKEN_OPERATOR_SUM",
 
     "AST_TREE_TOKEN_NONE",
 };
@@ -134,6 +154,7 @@ void astTreePrint(const AstTree *tree, int indent) {
            metadata->name_begin);
   }
     goto RETURN_SUCCESS;
+  case AST_TREE_TOKEN_OPERATOR_SUM:
   case AST_TREE_TOKEN_OPERATOR_ASSIGN: {
     AstTreeInfix *metadata = tree->metadata;
     printf(",\n");
@@ -146,16 +167,6 @@ void astTreePrint(const AstTree *tree, int indent) {
       printf(" ");
     printf("right=\n");
     astTreePrint(&metadata->right, indent + 1);
-    printf(",\n");
-    for (int i = 0; i < indent; ++i)
-      printf(" ");
-    printf("leftType=\n");
-    astTreePrint(&metadata->leftType, indent + 1);
-    printf(",\n");
-    for (int i = 0; i < indent; ++i)
-      printf(" ");
-    printf("rightType=\n");
-    astTreePrint(&metadata->rightType, indent + 1);
     printf("\n");
     for (int i = 0; i < indent; ++i)
       printf(" ");
@@ -184,6 +195,15 @@ void astTreeRootPrint(const AstTreeRoot *root) {
 }
 
 void astTreeDestroy(AstTree tree) {
+  if (tree.type != &AST_TREE_TYPE_TYPE && tree.type != &AST_TREE_VOID_TYPE &&
+      tree.type != &AST_TREE_U64_TYPE) {
+    if (tree.type == NULL) {
+      printLog("token = %s %p %p", AST_TREE_TOKEN_STRINGS[tree.token],
+               tree.metadata, tree.type);
+      return;
+    }
+    astTreeDelete(tree.type);
+  }
   switch (tree.token) {
   case AST_TREE_TOKEN_FUNCTION: {
     AstTreeFunction *metadata = tree.metadata;
@@ -238,12 +258,11 @@ void astTreeDestroy(AstTree tree) {
     // AstTreeIdentifier *metadata = tree.metadata; // not needed
   }
     return;
+  case AST_TREE_TOKEN_OPERATOR_SUM:
   case AST_TREE_TOKEN_OPERATOR_ASSIGN: {
     AstTreeInfix *metadata = tree.metadata;
     astTreeDestroy(metadata->left);
     astTreeDestroy(metadata->right);
-    astTreeDestroy(metadata->leftType);
-    astTreeDestroy(metadata->rightType);
     free(metadata);
   }
     return;
@@ -281,28 +300,40 @@ void astTreeRootDelete(AstTreeRoot *root) {
   free(root);
 }
 
-AstTree *newAstTree(AstTreeToken token, void *metadata) {
+AstTree *newAstTree(AstTreeToken token, void *metadata, AstTree *type) {
   AstTree *result = a404m_malloc(sizeof(*result));
   result->token = token;
   result->metadata = metadata;
-  result->typeChecked = false;
+  result->type = type;
   return result;
 }
 
 AstTree *copyAstTree(AstTree *tree) {
   switch (tree->token) {
   case AST_TREE_TOKEN_TYPE_TYPE:
+    return &AST_TREE_TYPE_TYPE;
   case AST_TREE_TOKEN_TYPE_VOID:
+    return &AST_TREE_VOID_TYPE;
   case AST_TREE_TOKEN_TYPE_U64:
-    return newAstTree(tree->token, NULL);
+    return &AST_TREE_U64_TYPE;
   case AST_TREE_TOKEN_VALUE_U64:
-    return newAstTree(tree->token, (void *)(AstTreeU64)tree->metadata);
+    return newAstTree(tree->token, (void *)(AstTreeU64)tree->metadata,
+                      &AST_TREE_U64_TYPE);
   case AST_TREE_TOKEN_VARIABLE:
-    return newAstTree(tree->token, tree->metadata);
+    return newAstTree(tree->token, tree->metadata, copyAstTree(tree->type));
+  case AST_TREE_TOKEN_TYPE_FUNCTION: {
+    AstTreeTypeFunction *metadata = tree->metadata;
+    AstTreeTypeFunction *new_metadata = a404m_malloc(sizeof(*new_metadata));
+    new_metadata->returnType = copyAstTree(metadata->returnType);
+    if (metadata->arguments_size != 0) {
+      UNREACHABLE;
+    }
+    return newAstTree(tree->token, new_metadata, copyAstTree(tree->type));
+  }
   case AST_TREE_TOKEN_OPERATOR_ASSIGN:
+  case AST_TREE_TOKEN_OPERATOR_SUM:
   case AST_TREE_TOKEN_FUNCTION:
   case AST_TREE_TOKEN_KEYWORD_PRINT_U64:
-  case AST_TREE_TOKEN_TYPE_FUNCTION:
   case AST_TREE_TOKEN_FUNCTION_CALL:
   case AST_TREE_TOKEN_VARIABLE_DEFINE:
   case AST_TREE_TOKEN_NONE:
@@ -387,6 +418,7 @@ AstTreeRoot *makeAstTree(ParserNode *parsedRoot) {
     case PARSER_TOKEN_SYMBOL_COMMA:
     case PARSER_TOKEN_FUNCTION_CALL:
     case PARSER_TOKEN_OPERATOR_ASSIGN:
+    case PARSER_TOKEN_OPERATOR_SUM:
     case PARSER_TOKEN_NONE:
       printLog("Should not be here");
       goto RETURN_ERROR;
@@ -408,11 +440,6 @@ AstTreeRoot *makeAstTree(ParserNode *parsedRoot) {
       if (type == NULL) {
         goto RETURN_ERROR;
       }
-
-      if (!hasTypeOf(value, type)) {
-        printLog("Type mismatch");
-        goto RETURN_ERROR;
-      }
     } else {
       type = NULL;
     }
@@ -483,13 +510,13 @@ AstTree *astTreeParse(ParserNode *parserNode, AstTreeVariables **variables,
   case PARSER_TOKEN_FUNCTION_DEFINITION:
     return astTreeParseFunction(parserNode, variables, variables_size);
   case PARSER_TOKEN_TYPE_TYPE:
-    return newAstTree(AST_TREE_TOKEN_TYPE_TYPE, NULL);
+    return &AST_TREE_TYPE_TYPE;
   case PARSER_TOKEN_TYPE_FUNCTION:
     return astTreeParseTypeFunction(parserNode, variables, variables_size);
   case PARSER_TOKEN_TYPE_VOID:
-    return newAstTree(AST_TREE_TOKEN_TYPE_VOID, NULL);
+    return &AST_TREE_VOID_TYPE;
   case PARSER_TOKEN_TYPE_U64:
-    return newAstTree(AST_TREE_TOKEN_TYPE_U64, NULL);
+    return &AST_TREE_U64_TYPE;
   case PARSER_TOKEN_FUNCTION_CALL:
     return astTreeParseFunctionCall(parserNode, variables, variables_size);
   case PARSER_TOKEN_IDENTIFIER:
@@ -497,11 +524,14 @@ AstTree *astTreeParse(ParserNode *parserNode, AstTreeVariables **variables,
   case PARSER_TOKEN_VALUE_U64:
     return newAstTree(
         AST_TREE_TOKEN_VALUE_U64,
-        (void *)(AstTreeU64)(ParserNodeU64Metadata)parserNode->metadata);
+        (void *)(AstTreeU64)(ParserNodeU64Metadata)parserNode->metadata,
+        &AST_TREE_U64_TYPE);
   case PARSER_TOKEN_KEYWORD_PRINT_U64:
     return astTreeParsePrintU64(parserNode, variables, variables_size);
   case PARSER_TOKEN_OPERATOR_ASSIGN:
     return astTreeParseAssign(parserNode, variables, variables_size);
+  case PARSER_TOKEN_OPERATOR_SUM:
+    return astTreeParseSum(parserNode, variables, variables_size);
   case PARSER_TOKEN_VARIABLE:
   case PARSER_TOKEN_CONSTANT:
   case PARSER_TOKEN_SYMBOL_EOL:
@@ -611,7 +641,7 @@ AstTree *astTreeParseFunction(ParserNode *parserNode,
 
   function->scope = scope;
 
-  AstTree *result = newAstTree(AST_TREE_TOKEN_FUNCTION, function);
+  AstTree *result = newAstTree(AST_TREE_TOKEN_FUNCTION, function, NULL);
 
   return result;
 
@@ -663,7 +693,8 @@ AstTree *astTreeParseTypeFunction(ParserNode *parserNode,
     goto RETURN_ERROR;
   }
 
-  return newAstTree(AST_TREE_TOKEN_TYPE_FUNCTION, typeFunction);
+  return newAstTree(AST_TREE_TOKEN_TYPE_FUNCTION, typeFunction,
+                    &AST_TREE_TYPE_TYPE);
 
 RETURN_ERROR:
   return NULL;
@@ -693,15 +724,9 @@ AstTree *astTreeParseFunctionCall(ParserNode *parserNode,
   for (size_t i = 0; i < metadata->parameters_size; ++i) {
     printLog("Not impelemented yet");
     exit(1);
-    if ((metadata->parameters[i] = astTreeParse(node_metadata->params->data[i],
-                                                variables, variables_size)) ==
-            NULL ||
-        hasTypeOf(metadata->parameters[i], function->metadata)) {
-      goto RETURN_ERROR;
-    }
   }
 
-  return newAstTree(AST_TREE_TOKEN_FUNCTION_CALL, metadata);
+  return newAstTree(AST_TREE_TOKEN_FUNCTION_CALL, metadata, NULL);
 RETURN_ERROR:
   for (size_t i = 0; i < metadata->parameters_size; ++i) {
     astTreeDelete(metadata->parameters[i]);
@@ -719,7 +744,7 @@ AstTree *astTreeParseIdentifier(ParserNode *parserNode,
     printLog("Variable not found");
     return NULL;
   }
-  return newAstTree(AST_TREE_TOKEN_VARIABLE, var);
+  return newAstTree(AST_TREE_TOKEN_VARIABLE, var, NULL);
 }
 
 AstTree *astTreeParsePrintU64(ParserNode *parserNode,
@@ -733,7 +758,7 @@ AstTree *astTreeParsePrintU64(ParserNode *parserNode,
   }
 
   return newAstTree(AST_TREE_TOKEN_KEYWORD_PRINT_U64,
-                    (AstTreeSingleChild *)operand);
+                    (AstTreeSingleChild *)operand, NULL);
 }
 
 AstTree *astTreeParseAssign(ParserNode *parserNode,
@@ -759,7 +784,32 @@ AstTree *astTreeParseAssign(ParserNode *parserNode,
   free(left);
   free(right);
 
-  return newAstTree(AST_TREE_TOKEN_OPERATOR_ASSIGN, metadata);
+  return newAstTree(AST_TREE_TOKEN_OPERATOR_ASSIGN, metadata, NULL);
+}
+
+AstTree *astTreeParseSum(ParserNode *parserNode, AstTreeVariables **variables,
+                         size_t variables_size) {
+  ParserNodeInfixMetadata *node_metadata = parserNode->metadata;
+
+  AstTree *left = astTreeParse(node_metadata->left, variables, variables_size);
+  if (left == NULL) {
+    return NULL;
+  }
+  AstTree *right =
+      astTreeParse(node_metadata->right, variables, variables_size);
+  if (right == NULL) {
+    return NULL;
+  }
+
+  AstTreeInfix *metadata = a404m_malloc(sizeof(*metadata));
+
+  metadata->left = *left;
+  metadata->right = *right;
+
+  free(left);
+  free(right);
+
+  return newAstTree(AST_TREE_TOKEN_OPERATOR_SUM, metadata, NULL);
 }
 
 bool astTreeParseConstant(ParserNode *parserNode, AstTreeVariables **variables,
@@ -844,84 +894,11 @@ AstTree *astTreeParseVariable(ParserNode *parserNode,
     goto RETURN_ERROR;
   }
 
-  return newAstTree(AST_TREE_TOKEN_VARIABLE_DEFINE, variable);
+  return newAstTree(AST_TREE_TOKEN_VARIABLE_DEFINE, variable, NULL);
 RETURN_ERROR:
   return NULL;
 }
 
-bool hasTypeOf(AstTree *value, const AstTree *type) {
-  if (value->token == AST_TREE_TOKEN_VARIABLE) {
-    AstTreeVariable *variable = value->metadata;
-    return typeIsEqual(variable->type, type);
-  }
-
-  switch (type->token) {
-  case AST_TREE_TOKEN_TYPE_TYPE:
-    switch (value->token) {
-    case AST_TREE_TOKEN_TYPE_TYPE:
-    case AST_TREE_TOKEN_TYPE_FUNCTION:
-    case AST_TREE_TOKEN_TYPE_VOID:
-    case AST_TREE_TOKEN_TYPE_U64:
-      return true;
-    case AST_TREE_TOKEN_FUNCTION:
-    case AST_TREE_TOKEN_KEYWORD_PRINT_U64:
-    case AST_TREE_TOKEN_FUNCTION_CALL:
-    case AST_TREE_TOKEN_VARIABLE:
-    case AST_TREE_TOKEN_VALUE_U64:
-    case AST_TREE_TOKEN_VARIABLE_DEFINE:
-    case AST_TREE_TOKEN_OPERATOR_ASSIGN:
-      return false;
-    case AST_TREE_TOKEN_NONE:
-    }
-    goto ERROR;
-  case AST_TREE_TOKEN_TYPE_FUNCTION:
-    AstTreeTypeFunction *typeMetadata = type->metadata;
-    switch (value->token) {
-    case AST_TREE_TOKEN_FUNCTION: {
-      AstTreeFunction *valueMetadata = value->metadata;
-      if (typeMetadata->arguments_size != valueMetadata->arguments.size) {
-        return false;
-      }
-      for (size_t i = 0; i < typeMetadata->arguments_size; ++i) {
-        if (!typeIsEqual(typeMetadata->arguments[i],
-                         valueMetadata->arguments.data[i]->type)) {
-          return false;
-        }
-      }
-      return typeIsEqual(typeMetadata->returnType, valueMetadata->returnType);
-    }
-    case AST_TREE_TOKEN_KEYWORD_PRINT_U64:
-    case AST_TREE_TOKEN_VALUE_U64:
-    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_FUNCTION_CALL:
-    case AST_TREE_TOKEN_VARIABLE:
-    case AST_TREE_TOKEN_VARIABLE_DEFINE:
-    case AST_TREE_TOKEN_OPERATOR_ASSIGN:
-      return false;
-    case AST_TREE_TOKEN_NONE:
-    }
-    goto ERROR;
-  case AST_TREE_TOKEN_TYPE_U64:
-    return value->token == AST_TREE_TOKEN_VALUE_U64;
-  case AST_TREE_TOKEN_FUNCTION:
-  case AST_TREE_TOKEN_TYPE_VOID:
-  case AST_TREE_TOKEN_FUNCTION_CALL:
-  case AST_TREE_TOKEN_VARIABLE:
-  case AST_TREE_TOKEN_KEYWORD_PRINT_U64:
-  case AST_TREE_TOKEN_VALUE_U64:
-  case AST_TREE_TOKEN_VARIABLE_DEFINE:
-  case AST_TREE_TOKEN_OPERATOR_ASSIGN:
-    return false;
-  case AST_TREE_TOKEN_NONE:
-  }
-ERROR:
-  printLog("Bad token '%d'", type->token);
-  exit(1);
-}
-
 AstTreeFunction *getFunction(AstTree *value) {
   switch (value->token) {
   case AST_TREE_TOKEN_FUNCTION:
@@ -933,7 +910,7 @@ AstTreeFunction *getFunction(AstTree *value) {
   }
   case AST_TREE_TOKEN_VARIABLE: {
     AstTreeVariable *metadata = value->metadata;
-    if (metadata->type->token == AST_TREE_TOKEN_TYPE_FUNCTION) {
+    if (metadata->value->token == AST_TREE_TOKEN_FUNCTION) {
       return metadata->value->metadata;
     } else {
       return NULL;
@@ -947,6 +924,7 @@ AstTreeFunction *getFunction(AstTree *value) {
   case AST_TREE_TOKEN_VALUE_U64:
   case AST_TREE_TOKEN_VARIABLE_DEFINE:
   case AST_TREE_TOKEN_OPERATOR_ASSIGN:
+  case AST_TREE_TOKEN_OPERATOR_SUM:
     return NULL;
   case AST_TREE_TOKEN_NONE:
   }
@@ -967,6 +945,7 @@ bool isConst(AstTree *value) {
   case AST_TREE_TOKEN_FUNCTION_CALL:
   case AST_TREE_TOKEN_VARIABLE_DEFINE:
   case AST_TREE_TOKEN_OPERATOR_ASSIGN:
+  case AST_TREE_TOKEN_OPERATOR_SUM:
     return false;
   case AST_TREE_TOKEN_VARIABLE: {
     AstTreeVariable *metadata = value->metadata;
@@ -984,7 +963,7 @@ AstTree *makeTypeOf(AstTree *value) {
   case AST_TREE_TOKEN_TYPE_FUNCTION:
   case AST_TREE_TOKEN_TYPE_VOID:
   case AST_TREE_TOKEN_TYPE_U64:
-    return newAstTree(AST_TREE_TOKEN_TYPE_TYPE, NULL);
+    return &AST_TREE_TYPE_TYPE;
   case AST_TREE_TOKEN_FUNCTION_CALL: {
     AstTreeFunctionCall *metadata = value->metadata;
     AstTreeFunction *function = metadata->function->metadata;
@@ -1004,17 +983,28 @@ AstTree *makeTypeOf(AstTree *value) {
           copyAstTree(function->arguments.data[i]->type);
     }
 
-    return newAstTree(AST_TREE_TOKEN_TYPE_FUNCTION, type_metadata);
+    return newAstTree(AST_TREE_TOKEN_TYPE_FUNCTION, type_metadata,
+                      &AST_TREE_TYPE_TYPE);
   }
   case AST_TREE_TOKEN_VALUE_U64:
-    return newAstTree(AST_TREE_TOKEN_TYPE_U64, NULL);
+    return &AST_TREE_U64_TYPE;
   case AST_TREE_TOKEN_VARIABLE: {
     AstTreeVariable *variable = value->metadata;
     return copyAstTree(variable->type);
   }
+  case AST_TREE_TOKEN_OPERATOR_ASSIGN: {
+    AstTreeInfix *metadata = value->metadata;
+    return makeTypeOf(&metadata->left);
+  }
+  case AST_TREE_TOKEN_OPERATOR_SUM: {
+    AstTreeInfix *metadata = value->metadata;
+
+    // TODO: find a better way
+
+    return makeTypeOf(&metadata->left);
+  }
   case AST_TREE_TOKEN_VARIABLE_DEFINE:
   case AST_TREE_TOKEN_KEYWORD_PRINT_U64:
-  case AST_TREE_TOKEN_OPERATOR_ASSIGN:
   case AST_TREE_TOKEN_NONE:
   }
   printLog("Bad token '%d'", value->token);
@@ -1028,6 +1018,7 @@ bool typeIsEqual(const AstTree *type0, const AstTree *type1) {
   case AST_TREE_TOKEN_VALUE_U64:
   case AST_TREE_TOKEN_VARIABLE_DEFINE:
   case AST_TREE_TOKEN_OPERATOR_ASSIGN:
+  case AST_TREE_TOKEN_OPERATOR_SUM:
     return false;
   case AST_TREE_TOKEN_TYPE_TYPE:
   case AST_TREE_TOKEN_TYPE_VOID:
@@ -1037,8 +1028,20 @@ bool typeIsEqual(const AstTree *type0, const AstTree *type1) {
     if (type1->token != AST_TREE_TOKEN_TYPE_FUNCTION) {
       return false;
     }
-    printLog("Not implemented yet");
-    exit(1);
+    AstTreeTypeFunction *type0_metadata = type0->metadata;
+    AstTreeTypeFunction *type1_metadata = type1->metadata;
+    if (!typeIsEqual(type0_metadata->returnType->type,
+                     type1_metadata->returnType->type)) {
+      return false;
+    }
+    if (type0_metadata->arguments_size != type1_metadata->arguments_size) {
+      return false;
+    }
+    for (size_t i = 0; i < type0_metadata->arguments_size; ++i) {
+      printLog("Not implemented yet");
+      exit(1);
+    }
+    return true;
   case AST_TREE_TOKEN_FUNCTION_CALL:
     printLog("Not implemented yet");
     exit(1);
@@ -1064,10 +1067,9 @@ bool setAllTypesRoot(AstTreeRoot *root) {
 }
 
 bool setAllTypes(AstTree *tree) {
-  if (tree->typeChecked == true) {
+  if (tree->type != NULL) {
     return true;
   }
-  tree->typeChecked = true;
   switch (tree->token) {
   case AST_TREE_TOKEN_TYPE_TYPE:
   case AST_TREE_TOKEN_TYPE_VOID:
@@ -1087,6 +1089,8 @@ bool setAllTypes(AstTree *tree) {
     return setTypesVariable(tree);
   case AST_TREE_TOKEN_OPERATOR_ASSIGN:
     return setTypesOperatorAssign(tree);
+  case AST_TREE_TOKEN_OPERATOR_SUM:
+    return setTypesOperatorSum(tree);
   case AST_TREE_TOKEN_NONE:
   }
   printLog("Bad token '%d'", tree->token);
@@ -1106,8 +1110,8 @@ bool setTypesFunction(AstTree *tree) {
   }
 
   for (size_t i = 0; i < metadata->scope.expressions_size; ++i) {
-    AstTree expression = metadata->scope.expressions[i];
-    if (!setAllTypes(&expression)) {
+    AstTree *expression = &metadata->scope.expressions[i];
+    if (!setAllTypes(expression)) {
       return false;
     }
   }
@@ -1118,18 +1122,19 @@ bool setTypesFunction(AstTree *tree) {
     }
   }
 
-  return true;
+  tree->type = makeTypeOf(tree);
+  return tree->type != NULL;
 }
 
 bool setTypesPrintU64(AstTree *tree) {
   AstTreeSingleChild *metadata = tree->metadata;
   if (!setAllTypes(metadata)) {
     return false;
-  }
-  if (!hasTypeOf(metadata, &AST_TREE_U64_TYPE)) {
+  } else if (!typeIsEqual(metadata->type, &AST_TREE_U64_TYPE)) {
     printLog("Type mismatch");
     return false;
   } else {
+    tree->type = &AST_TREE_VOID_TYPE;
     return true;
   }
 }
@@ -1142,7 +1147,15 @@ bool setTypesTypeFunction(AstTree *tree) {
     return false;
   }
 
-  return setAllTypes(metadata->returnType);
+  if (!setAllTypes(metadata->returnType)) {
+    return false;
+  } else if (!typeIsEqual(metadata->returnType->type, &AST_TREE_TYPE_TYPE)) {
+    printLog("Type mismatch");
+    return false;
+  }
+
+  tree->type = &AST_TREE_TYPE_TYPE;
+  return true;
 }
 
 bool setTypesFunctionCall(AstTree *tree) {
@@ -1156,10 +1169,7 @@ bool setTypesFunctionCall(AstTree *tree) {
   if (metadata->function->token != AST_TREE_TOKEN_VARIABLE) {
     printLog("Not yet supported");
     return false;
-  }
-
-  if (!setAllTypes(metadata->function)) {
-    printLog("Type mismatch");
+  } else if (!setAllTypes(metadata->function)) {
     return false;
   }
 
@@ -1168,64 +1178,65 @@ bool setTypesFunctionCall(AstTree *tree) {
       function->arguments.size != metadata->parameters_size) {
     printLog("Arguments doesn't match %ld != %ld", function->arguments.size,
              metadata->parameters_size);
-    return false;
+    return NULL;
   }
 
+  tree->type = copyAstTree(function->returnType);
   return true;
 }
 
 bool setTypesVariable(AstTree *tree) {
   AstTreeVariable *metadata = tree->metadata;
-  return setTypesAstVariable(metadata);
+  if (setTypesAstVariable(metadata)) {
+    tree->type = copyAstTree(metadata->type);
+    return true;
+  } else {
+    return false;
+  }
 }
 
 bool setTypesOperatorAssign(AstTree *tree) {
   AstTreeInfix *infix = tree->metadata;
   if (!setTypesAstInfix(infix)) {
-    return true;
-  } else if (!typeIsEqual(&infix->leftType, &infix->rightType)) {
+    return false;
+  } else if (!typeIsEqual(infix->left.type, infix->right.type)) {
     printLog("Type mismatch");
     return false;
   } else {
+    tree->type = copyAstTree(infix->left.type);
     return true;
   }
 }
 
-bool setTypesAstVariable(AstTreeVariable *variable) {
-  if (!setAllTypes(variable->value)) {
+bool setTypesOperatorSum(AstTree *tree) {
+  AstTreeInfix *infix = tree->metadata;
+  if (!setTypesAstInfix(infix)) {
     return false;
-  }
-
-  if (variable->type == NULL) {
-    if ((variable->type = makeTypeOf(variable->value)) == NULL) {
-      return false;
-    }
-  }
-
-  if (!hasTypeOf(variable->value, variable->type)) {
+  } else if (!typeIsEqual(infix->left.type, infix->right.type)) {
     printLog("Type mismatch");
     return false;
   } else {
+    tree->type = copyAstTree(infix->left.type);
     return true;
   }
 }
 
-bool setTypesAstInfix(AstTreeInfix *infix) {
-  if (!setAllTypes(&infix->left) || !setAllTypes(&infix->right)) {
+bool setTypesAstVariable(AstTreeVariable *variable) {
+  if (!setAllTypes(variable->value)) {
+    return false;
+  } else if (variable->type == NULL &&
+             (variable->type = makeTypeOf(variable->value)) == NULL) {
+    return false;
+  } else if (!typeIsEqual(variable->value->type, variable->type)) {
     printLog("Type mismatch");
     return false;
+  } else {
+    return true;
   }
+}
 
-  AstTree *lType = makeTypeOf(&infix->left);
-  AstTree *rType = makeTypeOf(&infix->right);
-
-  infix->leftType = *lType;
-  infix->rightType = *rType;
-
-  free(lType);
-  free(rType);
-
-  return true;
+bool setTypesAstInfix(AstTreeInfix *infix) {
+  return setAllTypes(&infix->left) && setAllTypes(&infix->right);
 }
 
 bool astTreeCleanRoot(AstTreeRoot *root) {
@@ -1251,6 +1262,7 @@ bool astTreeClean(AstTree *tree) {
   case AST_TREE_TOKEN_VALUE_U64:
   case AST_TREE_TOKEN_VARIABLE_DEFINE:
   case AST_TREE_TOKEN_OPERATOR_ASSIGN:
+  case AST_TREE_TOKEN_OPERATOR_SUM:
     return true;
   case AST_TREE_TOKEN_NONE:
   }
@@ -1271,8 +1283,8 @@ bool astTreeCleanFunction(AstTree *tree) {
   }
 
   for (size_t i = 0; i < metadata->scope.expressions_size; ++i) {
-    AstTree expression = metadata->scope.expressions[i];
-    if (!astTreeClean(&expression)) {
+    AstTree *expression = &metadata->scope.expressions[i];
+    if (!astTreeClean(expression)) {
       return false;
     }
   }
@@ -1331,6 +1343,7 @@ size_t astTreeTypeSize(AstTree tree) {
   case AST_TREE_TOKEN_VARIABLE_DEFINE:
   case AST_TREE_TOKEN_VALUE_U64:
   case AST_TREE_TOKEN_OPERATOR_ASSIGN:
+  case AST_TREE_TOKEN_OPERATOR_SUM:
   case AST_TREE_TOKEN_NONE:
   }
   UNREACHABLE;
diff --git a/src/compiler/ast-tree.h b/src/compiler/ast-tree.h
index 1aada03..28e74af 100644
--- a/src/compiler/ast-tree.h
+++ b/src/compiler/ast-tree.h
@@ -20,6 +20,7 @@ typedef enum AstTreeToken {
   AST_TREE_TOKEN_VALUE_U64,
 
   AST_TREE_TOKEN_OPERATOR_ASSIGN,
+  AST_TREE_TOKEN_OPERATOR_SUM,
 
   AST_TREE_TOKEN_NONE,
 } AstTreeToken;
@@ -28,11 +29,14 @@ extern const char *AST_TREE_TOKEN_STRINGS[];
 
 typedef struct AstTree {
   AstTreeToken token;
-  bool typeChecked;
   void *metadata;
+  struct AstTree *type;
 } AstTree;
 
-extern const AstTree AST_TREE_U64_TYPE;
+extern AstTree AST_TREE_TYPE_TYPE;
+extern AstTree AST_TREE_VOID_TYPE;
+extern AstTree AST_TREE_U64_TYPE;
+extern AstTree AST_TREE_VOID_VALUE;
 
 typedef struct AstTreeVariable {
   char *name_begin;
@@ -82,8 +86,6 @@ typedef AstTree AstTreeSingleChild;
 typedef struct AstTreeInfix {
   AstTree left;
   AstTree right;
-  AstTree leftType;
-  AstTree rightType;
 } AstTreeInfix;
 
 void astTreePrint(const AstTree *tree, int indent);
@@ -95,7 +97,7 @@ void astTreeVariableDelete(AstTreeVariable *variable);
 void astTreeDelete(AstTree *tree);
 void astTreeRootDelete(AstTreeRoot *root);
 
-AstTree *newAstTree(AstTreeToken token, void *metadata);
+AstTree *newAstTree(AstTreeToken token, void *metadata, AstTree *type);
 AstTree *copyAstTree(AstTree *tree);
 
 AstTreeRoot *makeAstTree(ParserNode *parsedRoot);
@@ -132,6 +134,9 @@ AstTree *astTreeParseAssign(ParserNode *parserNode,
                             AstTreeVariables **variables,
                             size_t variables_size);
 
+AstTree *astTreeParseSum(ParserNode *parserNode, AstTreeVariables **variables,
+                         size_t variables_size);
+
 bool astTreeParseConstant(ParserNode *parserNode, AstTreeVariables **variables,
                           size_t variables_size);
 
@@ -139,8 +144,7 @@ AstTree *astTreeParseVariable(ParserNode *parserNode,
                               AstTreeVariables **variables,
                               size_t variables_size);
 
-bool hasTypeOf(AstTree *value, const AstTree *type);
-AstTreeFunction* getFunction(AstTree *value);
+AstTreeFunction *getFunction(AstTree *value);
 bool isConst(AstTree *value);
 AstTree *makeTypeOf(AstTree *value);
 bool typeIsEqual(const AstTree *type0, const AstTree *type1);
@@ -153,6 +157,7 @@ bool setTypesTypeFunction(AstTree *tree);
 bool setTypesFunctionCall(AstTree *tree);
 bool setTypesVariable(AstTree *tree);
 bool setTypesOperatorAssign(AstTree *tree);
+bool setTypesOperatorSum(AstTree *tree);
 
 bool setTypesAstVariable(AstTreeVariable *variable);
 bool setTypesAstInfix(AstTreeInfix *infix);
diff --git a/src/compiler/code-generator.c b/src/compiler/code-generator.c
index 6ef6807..ab7583e 100644
--- a/src/compiler/code-generator.c
+++ b/src/compiler/code-generator.c
@@ -132,6 +132,7 @@ CodeGeneratorOperand *newCodeGeneratorOperandFromAstTree(AstTree tree) {
   case AST_TREE_TOKEN_FUNCTION_CALL:
   case AST_TREE_TOKEN_VARIABLE_DEFINE:
   case AST_TREE_TOKEN_OPERATOR_ASSIGN:
+  case AST_TREE_TOKEN_OPERATOR_SUM:
   case AST_TREE_TOKEN_NONE:
   }
   UNREACHABLE;
@@ -232,6 +233,7 @@ CodeGeneratorCodes *codeGenerator(AstTreeRoot *astTreeRoot) {
     case AST_TREE_TOKEN_TYPE_U64:
     case AST_TREE_TOKEN_VARIABLE_DEFINE:
     case AST_TREE_TOKEN_OPERATOR_ASSIGN:
+    case AST_TREE_TOKEN_OPERATOR_SUM:
     case AST_TREE_TOKEN_NONE:
       break;
     }
@@ -325,7 +327,7 @@ bool codeGeneratorAstTreeFunction(char *name_begin, char *name_end,
           newCodeGeneratorOperandFromAstTree(infix->right);
       operands->op0 = *op0;
       operands->op1 = *op1;
-      operands->bytes = astTreeTypeSize(infix->leftType);
+      operands->bytes = astTreeTypeSize(*infix->left.type);
       free(op0);
       free(op1);
 
@@ -334,6 +336,30 @@ bool codeGeneratorAstTreeFunction(char *name_begin, char *name_end,
                                     operands));
     }
       goto OK;
+    case AST_TREE_TOKEN_OPERATOR_SUM: {
+      AstTreeInfix *infix = tree.metadata;
+
+      if (infix->left.token != AST_TREE_TOKEN_VARIABLE) {
+        printLog("Not implemented yet");
+        exit(1);
+      }
+
+      CodeGeneratorMov *operands = a404m_malloc(sizeof(*operands));
+      CodeGeneratorOperand *op0 =
+          newCodeGeneratorOperandFromAstTree(infix->left);
+      CodeGeneratorOperand *op1 =
+          newCodeGeneratorOperandFromAstTree(infix->right);
+      operands->op0 = *op0;
+      operands->op1 = *op1;
+      operands->bytes = astTreeTypeSize(*infix->left.type);
+      free(op0);
+      free(op1);
+
+      generateCodePushCode(
+          codes, createGenerateCode(NULL, NULL, CODE_GENERATOR_INSTRUCTION_ADD,
+                                    operands));
+    }
+      goto OK;
     case AST_TREE_TOKEN_VARIABLE_DEFINE:
     case AST_TREE_TOKEN_VALUE_U64:
     case AST_TREE_TOKEN_VARIABLE:
@@ -488,6 +514,8 @@ char *codeGeneratorToFlatASM(const CodeGeneratorCodes *codes) {
       free(inst);
     }
       continue;
+    case CODE_GENERATOR_INSTRUCTION_ADD: {
+    }
     }
     UNREACHABLE;
   }
diff --git a/src/compiler/code-generator.h b/src/compiler/code-generator.h
index e4d9cac..3c3222a 100644
--- a/src/compiler/code-generator.h
+++ b/src/compiler/code-generator.h
@@ -9,6 +9,7 @@ typedef enum CodeGeneratorInstruction : uint8_t {
   CODE_GENERATOR_INSTRUCTION_CALL,
   CODE_GENERATOR_INSTRUCTION_RET,
   CODE_GENERATOR_INSTRUCTION_MOV,
+  CODE_GENERATOR_INSTRUCTION_ADD,
   CODE_GENERATOR_INSTRUCTION_FUNCTION_BEGIN,
   CODE_GENERATOR_INSTRUCTION_FUNCTION_END,
 } CodeGeneratorInstruction;
diff --git a/src/compiler/lexer.c b/src/compiler/lexer.c
index 071a2f8..fc7307f 100644
--- a/src/compiler/lexer.c
+++ b/src/compiler/lexer.c
@@ -15,6 +15,7 @@ const char *LEXER_TOKEN_STRINGS[] = {
     "LEXER_TOKEN_KEYWORD_VOID",
     "LEXER_TOKEN_KEYWORD_U64",
     "LEXER_TOKEN_KEYWORD_PRINT_U64",
+    "LEXER_TOKEN_KEYWORD_RETURN",
 
     "LEXER_TOKEN_NUMBER",
 
@@ -28,12 +29,13 @@ const char *LEXER_TOKEN_STRINGS[] = {
     "LEXER_TOKEN_SYMBOL_COLON",
     "LEXER_TOKEN_SYMBOL_ASSIGN",
     "LEXER_TOKEN_SYMBOL_COMMA",
+    "LEXER_TOKEN_SYMBOL_PLUS",
 
     "LEXER_TOKEN_NONE",
 };
 
 const char *LEXER_SYMBOL_STRINGS[] = {
-    ";", "(", ")", "{", "}", "->", ":", "=", ",",
+    ";", "(", ")", "{", "}", "->", ":", "=", ",", "+",
 };
 const LexerToken LEXER_SYMBOL_TOKENS[] = {
     LEXER_TOKEN_SYMBOL_EOL,
@@ -45,6 +47,7 @@ const LexerToken LEXER_SYMBOL_TOKENS[] = {
     LEXER_TOKEN_SYMBOL_COLON,
     LEXER_TOKEN_SYMBOL_ASSIGN,
     LEXER_TOKEN_SYMBOL_COMMA,
+    LEXER_TOKEN_SYMBOL_PLUS,
 };
 const size_t LEXER_SYMBOL_SIZE =
     sizeof(LEXER_SYMBOL_TOKENS) / sizeof(*LEXER_SYMBOL_TOKENS);
@@ -54,12 +57,14 @@ const char *LEXER_KEYWORD_STRINGS[] = {
     "void",
     "u64",
     "print_u64",
+    "return",
 };
 const LexerToken LEXER_KEYWORD_TOKENS[] = {
     LEXER_TOKEN_KEYWORD_TYPE,
     LEXER_TOKEN_KEYWORD_VOID,
     LEXER_TOKEN_KEYWORD_U64,
     LEXER_TOKEN_KEYWORD_PRINT_U64,
+    LEXER_TOKEN_KEYWORD_RETURN,
 };
 const size_t LEXER_KEYWORD_SIZE =
     sizeof(LEXER_KEYWORD_TOKENS) / sizeof(*LEXER_KEYWORD_TOKENS);
diff --git a/src/compiler/lexer.h b/src/compiler/lexer.h
index 41c1ab7..81d6fd5 100644
--- a/src/compiler/lexer.h
+++ b/src/compiler/lexer.h
@@ -9,6 +9,7 @@ typedef enum LexerToken {
   LEXER_TOKEN_KEYWORD_VOID,
   LEXER_TOKEN_KEYWORD_U64,
   LEXER_TOKEN_KEYWORD_PRINT_U64,
+  LEXER_TOKEN_KEYWORD_RETURN,
 
   LEXER_TOKEN_NUMBER,
 
@@ -22,6 +23,7 @@ typedef enum LexerToken {
   LEXER_TOKEN_SYMBOL_COLON,
   LEXER_TOKEN_SYMBOL_ASSIGN,
   LEXER_TOKEN_SYMBOL_COMMA,
+  LEXER_TOKEN_SYMBOL_PLUS,
 
   LEXER_TOKEN_NONE,
 } LexerToken;
diff --git a/src/compiler/parser.c b/src/compiler/parser.c
index 7a9e0e3..c8ad924 100644
--- a/src/compiler/parser.c
+++ b/src/compiler/parser.c
@@ -31,6 +31,7 @@ const char *PARSER_TOKEN_STRINGS[] = {
     "PARSER_TOKEN_SYMBOL_COMMA",
 
     "PARSER_TOKEN_OPERATOR_ASSIGN",
+    "PARSER_TOKEN_OPERATOR_SUM",
 
     "PARSER_TOKEN_FUNCTION_DEFINITION",
 
@@ -59,6 +60,10 @@ static constexpr ParserOrder PARSER_ORDER[] = {
         .ltr = false,
         ORDER_ARRAY(LEXER_TOKEN_SYMBOL_FUNCTION_ARROW, ),
     },
+    {
+        .ltr = true,
+        ORDER_ARRAY(LEXER_TOKEN_SYMBOL_PLUS, ),
+    },
     {
         .ltr = true,
         ORDER_ARRAY(LEXER_TOKEN_SYMBOL_COLON, LEXER_TOKEN_KEYWORD_PRINT_U64, ),
@@ -208,7 +213,8 @@ void parserNodePrint(const ParserNode *node, int indent) {
       printf(" ");
   }
     goto RETURN_SUCCESS;
-  case PARSER_TOKEN_OPERATOR_ASSIGN: {
+  case PARSER_TOKEN_OPERATOR_ASSIGN:
+  case PARSER_TOKEN_OPERATOR_SUM: {
     const ParserNodeInfixMetadata *metadata = node->metadata;
     printf(",\n");
     for (int i = 0; i < indent; ++i)
@@ -298,7 +304,8 @@ void parserNodeDelete(ParserNode *node) {
     free(metadata);
   }
     goto RETURN_SUCCESS;
-  case PARSER_TOKEN_OPERATOR_ASSIGN: {
+  case PARSER_TOKEN_OPERATOR_ASSIGN:
+  case PARSER_TOKEN_OPERATOR_SUM: {
     ParserNodeInfixMetadata *metadata = node->metadata;
     parserNodeDelete(metadata->left);
     parserNodeDelete(metadata->right);
@@ -434,6 +441,8 @@ ParserNode *parseNode(LexerNode *node, LexerNode *begin, LexerNode *end,
     return parserNumber(node, parent);
   case LEXER_TOKEN_SYMBOL_ASSIGN:
     return parserAssign(node, begin, end, parent);
+  case LEXER_TOKEN_SYMBOL_PLUS:
+    return parserPlus(node, begin, end, parent);
   case LEXER_TOKEN_SYMBOL:
   case LEXER_TOKEN_SYMBOL_OPEN_PARENTHESIS:
   case LEXER_TOKEN_SYMBOL_OPEN_CURLY_BRACKET:
@@ -845,9 +854,33 @@ ParserNode *parserAssign(LexerNode *node, LexerNode *begin, LexerNode *end,
   return left->parent = right->parent = node->parserNode =
              newParserNode(PARSER_TOKEN_OPERATOR_ASSIGN, left->str_begin,
                            right->str_end, metadata, parent);
+}
 
-  printLog("Not implemented");
-  return NULL;
+ParserNode *parserPlus(LexerNode *node, LexerNode *begin, LexerNode *end,
+                       ParserNode *parent) {
+  LexerNode *leftNode = node - 1;
+  LexerNode *rightNode = node + 1;
+
+  if (leftNode < begin || rightNode >= end) {
+    printLog("Bad plus");
+    return NULL;
+  }
+
+  ParserNode *left = getUntilCommonParent(leftNode->parserNode, parent);
+  ParserNode *right = getUntilCommonParent(rightNode->parserNode, parent);
+
+  if (left == NULL || right == NULL) {
+    printLog("Bad plus");
+    return NULL;
+  }
+
+  ParserNodeInfixMetadata *metadata = a404m_malloc(sizeof(*metadata));
+  metadata->left = left;
+  metadata->right = right;
+
+  return left->parent = right->parent = node->parserNode =
+             newParserNode(PARSER_TOKEN_OPERATOR_SUM, left->str_begin,
+                           right->str_end, metadata, parent);
 }
 
 bool isAllArguments(const ParserNodeArray *nodes) {
@@ -870,6 +903,7 @@ bool isExpression(ParserNode *node) {
   case PARSER_TOKEN_FUNCTION_CALL:
   case PARSER_TOKEN_KEYWORD_PRINT_U64:
   case PARSER_TOKEN_OPERATOR_ASSIGN:
+  case PARSER_TOKEN_OPERATOR_SUM:
     return true;
   case PARSER_TOKEN_ROOT:
   case PARSER_TOKEN_TYPE_TYPE:
@@ -907,6 +941,7 @@ bool isType(ParserNode *node) {
   case PARSER_TOKEN_VALUE_U64:
   case PARSER_TOKEN_KEYWORD_PRINT_U64:
   case PARSER_TOKEN_OPERATOR_ASSIGN:
+  case PARSER_TOKEN_OPERATOR_SUM:
     return false;
   case PARSER_TOKEN_NONE:
   }
@@ -921,6 +956,7 @@ bool isValue(ParserNode *node) {
   case PARSER_TOKEN_VALUE_U64:
   case PARSER_TOKEN_IDENTIFIER:
   case PARSER_TOKEN_OPERATOR_ASSIGN:
+  case PARSER_TOKEN_OPERATOR_SUM:
     return true;
   case PARSER_TOKEN_TYPE_FUNCTION:
   case PARSER_TOKEN_TYPE_TYPE:
diff --git a/src/compiler/parser.h b/src/compiler/parser.h
index ea53042..abce8db 100644
--- a/src/compiler/parser.h
+++ b/src/compiler/parser.h
@@ -27,6 +27,7 @@ typedef enum ParserToken {
   PARSER_TOKEN_SYMBOL_COMMA,
 
   PARSER_TOKEN_OPERATOR_ASSIGN,
+  PARSER_TOKEN_OPERATOR_SUM,
 
   PARSER_TOKEN_FUNCTION_DEFINITION,
 
@@ -119,6 +120,8 @@ ParserNode *parserVariable(LexerNode *node, LexerNode *begin, LexerNode *end,
                            ParserNode *parent);
 ParserNode *parserAssign(LexerNode *node, LexerNode *begin, LexerNode *end,
                          ParserNode *parent);
+ParserNode *parserPlus(LexerNode *node, LexerNode *begin, LexerNode *end,
+                       ParserNode *parent);
 
 bool isAllArguments(const ParserNodeArray *nodes);
 
diff --git a/src/main.c b/src/main.c
index cd63515..999b41a 100644
--- a/src/main.c
+++ b/src/main.c
@@ -2,12 +2,14 @@
 #include "compiler/code-generator.h"
 #include "compiler/lexer.h"
 #include "compiler/parser.h"
+#include "runner/runner.h"
 #include "utils/file.h"
 #include "utils/log.h"
 #include <stdio.h>
 #include <stdlib.h>
 
-static int runWithPrint(const char *filePath, const char *outFilePath) {
+static int compileRun(const char *filePath, const char *outFilePath,
+                      bool print) {
   char *code = readWholeFile(filePath);
 
   if (code == NULL) {
@@ -18,21 +20,24 @@ static int runWithPrint(const char *filePath, const char *outFilePath) {
   if (lexerNodeArrayIsError(lexed)) {
     goto RETURN_ERROR;
   }
-  lexerNodeArrayPrint(lexed);
+  if (print)
+    lexerNodeArrayPrint(lexed);
 
   ParserNode *parsedRoot = parser(lexed);
   lexerNodeArrayDestroy(lexed);
   if (parsedRoot == NULL) {
     goto RETURN_ERROR;
   }
-  parserNodePrint(parsedRoot, 0);
+  if (print)
+    parserNodePrint(parsedRoot, 0);
 
   AstTreeRoot *astTree = makeAstTree(parsedRoot);
   parserNodeDelete(parsedRoot);
   if (astTree == NULL) {
     goto RETURN_ERROR;
   }
-  astTreeRootPrint(astTree);
+  if (print)
+    astTreeRootPrint(astTree);
 
   CodeGeneratorCodes *codes = codeGenerator(astTree);
   astTreeRootDelete(astTree);
@@ -44,7 +49,8 @@ static int runWithPrint(const char *filePath, const char *outFilePath) {
   codeGeneratorDelete(codes);
   free(code);
 
-  puts(fasm);
+  if (print)
+    puts(fasm);
 
   if (codeGeneratorFlatASMExec(outFilePath, fasm)) {
     free(fasm);
@@ -58,7 +64,7 @@ RETURN_ERROR:
   return 1;
 }
 
-static int run(const char *filePath, const char *outFilePath) {
+static int run(const char *filePath, bool print) {
   char *code = readWholeFile(filePath);
 
   if (code == NULL) {
@@ -69,47 +75,45 @@ static int run(const char *filePath, const char *outFilePath) {
   if (lexerNodeArrayIsError(lexed)) {
     goto RETURN_ERROR;
   }
+  if (print)
+    lexerNodeArrayPrint(lexed);
 
   ParserNode *parsedRoot = parser(lexed);
   lexerNodeArrayDestroy(lexed);
   if (parsedRoot == NULL) {
     goto RETURN_ERROR;
   }
+  if (print)
+    parserNodePrint(parsedRoot, 0);
 
   AstTreeRoot *astTree = makeAstTree(parsedRoot);
   parserNodeDelete(parsedRoot);
   if (astTree == NULL) {
     goto RETURN_ERROR;
   }
-
-  CodeGeneratorCodes *codes = codeGenerator(astTree);
-  astTreeRootDelete(astTree);
-  if (codes == NULL) {
-    goto RETURN_ERROR;
-  }
-
-  char *fasm = codeGeneratorToFlatASM(codes);
-  codeGeneratorDelete(codes);
-  free(code);
-
-  if (codeGeneratorFlatASMExec(outFilePath, fasm)) {
-    free(fasm);
-    return system(outFilePath);
+  if (print)
+    astTreeRootPrint(astTree);
+
+  if (runAstTree(astTree)) {
+    astTreeRootDelete(astTree);
+    return 0;
+  } else {
+    astTreeRootDelete(astTree);
+    return 1;
   }
 
-  return 1;
-
 RETURN_ERROR:
   free(code);
   return 1;
 }
 
 int main(int argc, char *argv[]) {
-  if (argc < 3) {
-    run("test/main.felan", "build/out");
+  if (argc < 2) {
+    // compileRun("test/main.felan", "build/out", false);
+    run("test/main.felan", false);
     printLog("Too few args");
     return 1;
   }
 
-  return runWithPrint(argv[1], argv[2]);
+  return run(argv[1], true);
 }
diff --git a/src/runner/runner.c b/src/runner/runner.c
new file mode 100644
index 0000000..790e6c5
--- /dev/null
+++ b/src/runner/runner.c
@@ -0,0 +1,143 @@
+#include "runner.h"
+#include "compiler/ast-tree.h"
+#include "utils/log.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+bool runAstTree(AstTreeRoot *root) {
+  constexpr char MAIN_STR[] = "main";
+  constexpr size_t MAIN_STR_SIZE =
+      (sizeof(MAIN_STR) / sizeof(*MAIN_STR)) - sizeof(*MAIN_STR);
+  for (size_t i = 0; i < root->variables.size; ++i) {
+    AstTreeVariable *variable = root->variables.data[i];
+    size_t name_size = variable->name_end - variable->name_begin;
+    if (name_size == MAIN_STR_SIZE &&
+        strncmp(variable->name_begin, MAIN_STR, MAIN_STR_SIZE) == 0 &&
+        variable->value->token == AST_TREE_TOKEN_FUNCTION) {
+
+      AstTree *main = variable->value;
+      AstTreeFunction *mainFunction = main->metadata;
+      return runAstTreeFunction(mainFunction) == &AST_TREE_VOID_VALUE;
+    }
+  }
+  printLog("main function is not found");
+  return false;
+}
+
+AstTree *runAstTreeFunction(AstTreeFunction *function) {
+  for (size_t i = 0; i < function->scope.expressions_size; ++i) {
+    AstTree expr = function->scope.expressions[i];
+    switch (expr.token) {
+    case AST_TREE_TOKEN_KEYWORD_PRINT_U64: {
+      AstTreeSingleChild *metadata = expr.metadata;
+      AstTree *tree = calcAstTreeValue(metadata);
+      printf("%ld", (AstTreeU64)tree->metadata);
+      astTreeDelete(tree);
+    }
+      continue;
+    case AST_TREE_TOKEN_FUNCTION_CALL: {
+      AstTree *ret = calcAstTreeValue(&expr);
+      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;
+        astTreeDelete(left->value);
+        left->value = calcAstTreeValue(&metadata->right);
+      } else {
+        UNREACHABLE;
+      }
+    }
+      continue;
+    case AST_TREE_TOKEN_OPERATOR_SUM:
+    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_VARIABLE:
+    case AST_TREE_TOKEN_VARIABLE_DEFINE:
+    case AST_TREE_TOKEN_VALUE_U64:
+    case AST_TREE_TOKEN_NONE:
+    }
+    printLog("%d", expr.token);
+    UNREACHABLE;
+  }
+
+  return &AST_TREE_VOID_VALUE;
+}
+
+AstTree *calcAstTreeValue(AstTree *tree) {
+  switch (tree->token) {
+  case AST_TREE_TOKEN_VALUE_U64: {
+    return deepCopyAstTree(tree);
+  }
+  case AST_TREE_TOKEN_VARIABLE: {
+    AstTreeVariable *variable = tree->metadata;
+    return calcAstTreeValue(variable->value);
+  }
+  case AST_TREE_TOKEN_FUNCTION_CALL: {
+    AstTreeFunctionCall *metadata = tree->metadata;
+    if (metadata->parameters_size != 0) {
+      UNREACHABLE;
+    } else if (metadata->function->token == AST_TREE_TOKEN_VARIABLE) {
+      AstTreeVariable *variable = metadata->function->metadata;
+      return runAstTreeFunction(variable->value->metadata);
+    } else {
+      UNREACHABLE;
+    }
+  }
+  case AST_TREE_TOKEN_OPERATOR_SUM: {
+    AstTreeInfix *metadata = tree->metadata;
+    AstTree *left = calcAstTreeValue(&metadata->left);
+    AstTree *right = calcAstTreeValue(&metadata->right);
+
+    if (left->type == &AST_TREE_U64_TYPE && right->type == &AST_TREE_U64_TYPE) {
+      if (left->token == AST_TREE_TOKEN_VALUE_U64 &&
+          right->token == AST_TREE_TOKEN_VALUE_U64) {
+        left->metadata =
+            (void *)((AstTreeU64)left->metadata + (AstTreeU64)right->metadata);
+        astTreeDelete(right);
+        return left;
+      } else {
+        UNREACHABLE;
+      }
+    }
+  }
+  case AST_TREE_TOKEN_FUNCTION:
+  case AST_TREE_TOKEN_KEYWORD_PRINT_U64:
+  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_VARIABLE_DEFINE:
+  case AST_TREE_TOKEN_OPERATOR_ASSIGN:
+  case AST_TREE_TOKEN_NONE:
+  }
+  UNREACHABLE;
+}
+
+AstTree *deepCopyAstTree(AstTree *tree) {
+  switch (tree->token) {
+  case AST_TREE_TOKEN_VALUE_U64:
+    return newAstTree(tree->token, tree->metadata, copyAstTree(tree->type));
+  case AST_TREE_TOKEN_VARIABLE:
+  case AST_TREE_TOKEN_FUNCTION:
+  case AST_TREE_TOKEN_KEYWORD_PRINT_U64:
+  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_FUNCTION_CALL:
+  case AST_TREE_TOKEN_VARIABLE_DEFINE:
+  case AST_TREE_TOKEN_OPERATOR_ASSIGN:
+  case AST_TREE_TOKEN_OPERATOR_SUM:
+  case AST_TREE_TOKEN_NONE:
+  }
+  UNREACHABLE;
+}
diff --git a/src/runner/runner.h b/src/runner/runner.h
new file mode 100644
index 0000000..f143cbc
--- /dev/null
+++ b/src/runner/runner.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "compiler/ast-tree.h"
+#include <stdint.h>
+
+bool runAstTree(AstTreeRoot *root);
+
+AstTree *runAstTreeFunction(AstTreeFunction *function);
+
+AstTree *calcAstTreeValue(AstTree *tree);
+AstTree *deepCopyAstTree(AstTree *tree);
diff --git a/src/utils/log.h b/src/utils/log.h
index 620b2a3..6e6bea9 100644
--- a/src/utils/log.h
+++ b/src/utils/log.h
@@ -1,5 +1,7 @@
 #pragma once
 
+#include <stdlib.h>
+
 #define printLog(format,...) _printLogBack(format, __FILE_NAME__, __LINE__, ## __VA_ARGS__)
 
 #define UNREACHABLE printLog("Unreachable");exit(1)
-- 
cgit v1.2.3