#include "parser.h"

#include "compiler/lexer.h"
#include "utils/log.h"
#include "utils/memory.h"
#include "utils/string.h"
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

const char *PARSER_TOKEN_STRINGS[] = {
    "PARSER_TOKEN_ROOT",

    "PARSER_TOKEN_IDENTIFIER",

    "PARSER_TOKEN_VALUE_INT",
    "PARSER_TOKEN_VALUE_FLOAT",
    "PARSER_TOKEN_VALUE_BOOL",

    "PARSER_TOKEN_TYPE_TYPE",
    "PARSER_TOKEN_TYPE_FUNCTION",
    "PARSER_TOKEN_TYPE_VOID",
    "PARSER_TOKEN_TYPE_BOOL",
    "PARSER_TOKEN_TYPE_I8",
    "PARSER_TOKEN_TYPE_U8",
    "PARSER_TOKEN_TYPE_I16",
    "PARSER_TOKEN_TYPE_U16",
    "PARSER_TOKEN_TYPE_I32",
    "PARSER_TOKEN_TYPE_U32",
    "PARSER_TOKEN_TYPE_I64",
    "PARSER_TOKEN_TYPE_U64",
    "PARSER_TOKEN_TYPE_F16",
    "PARSER_TOKEN_TYPE_F32",
    "PARSER_TOKEN_TYPE_F64",
    "PARSER_TOKEN_TYPE_F128",

    "PARSER_TOKEN_KEYWORD_PRINT_U64",
    "PARSER_TOKEN_KEYWORD_RETURN",
    "PARSER_TOKEN_KEYWORD_IF",

    "PARSER_TOKEN_CONSTANT",
    "PARSER_TOKEN_VARIABLE",

    "PARSER_TOKEN_SYMBOL_EOL",
    "PARSER_TOKEN_SYMBOL_CURLY_BRACKET",
    "PARSER_TOKEN_SYMBOL_PARENTHESIS",
    "PARSER_TOKEN_SYMBOL_COMMA",

    "PARSER_TOKEN_OPERATOR_ASSIGN",
    "PARSER_TOKEN_OPERATOR_PLUS",
    "PARSER_TOKEN_OPERATOR_MINUS",
    "PARSER_TOKEN_OPERATOR_SUM",
    "PARSER_TOKEN_OPERATOR_SUB",
    "PARSER_TOKEN_OPERATOR_MULTIPLY",
    "PARSER_TOKEN_OPERATOR_DIVIDE",
    "PARSER_TOKEN_OPERATOR_MODULO",

    "PARSER_TOKEN_FUNCTION_DEFINITION",

    "PARSER_TOKEN_FUNCTION_CALL",

    "PARSER_TOKEN_NONE",
};

#define ORDER_ARRAY(...)                                                       \
  .size = sizeof((LexerToken[]){__VA_ARGS__}) / sizeof(LexerToken),            \
  .data = {__VA_ARGS__}

static constexpr ParserOrder PARSER_ORDER[] = {
    {
        .ltr = true,
        ORDER_ARRAY(LEXER_TOKEN_SYMBOL_CLOSE_CURLY_BRACKET, ),
    },
    {
        .ltr = true,
        ORDER_ARRAY(LEXER_TOKEN_SYMBOL_CLOSE_PARENTHESIS,
                    LEXER_TOKEN_IDENTIFIER, LEXER_TOKEN_KEYWORD_TYPE,
                    LEXER_TOKEN_KEYWORD_VOID, LEXER_TOKEN_KEYWORD_I8,
                    LEXER_TOKEN_KEYWORD_U8, LEXER_TOKEN_KEYWORD_I16,
                    LEXER_TOKEN_KEYWORD_U16, LEXER_TOKEN_KEYWORD_I32,
                    LEXER_TOKEN_KEYWORD_U32, LEXER_TOKEN_KEYWORD_I64,
                    LEXER_TOKEN_KEYWORD_F16, LEXER_TOKEN_KEYWORD_F32,
                    LEXER_TOKEN_KEYWORD_F64, LEXER_TOKEN_KEYWORD_F128,
                    LEXER_TOKEN_KEYWORD_U64, LEXER_TOKEN_KEYWORD_BOOL,
                    LEXER_TOKEN_KEYWORD_TRUE, LEXER_TOKEN_KEYWORD_FALSE,
                    LEXER_TOKEN_NUMBER, ),
    },
    {
        .ltr = false,
        ORDER_ARRAY(LEXER_TOKEN_SYMBOL_FUNCTION_ARROW, ),
    },
    {
        .ltr = true,
        ORDER_ARRAY(LEXER_TOKEN_SYMBOL_PLUS, LEXER_TOKEN_SYMBOL_MINUS, ),
    },
    {
        .ltr = true,
        ORDER_ARRAY(LEXER_TOKEN_SYMBOL_MULTIPLY, LEXER_TOKEN_SYMBOL_DIVIDE,
                    LEXER_TOKEN_SYMBOL_MODULO, ),
    },
    {
        .ltr = true,
        ORDER_ARRAY(LEXER_TOKEN_SYMBOL_SUM, LEXER_TOKEN_SYMBOL_SUB, ),
    },
    {
        .ltr = true,
        ORDER_ARRAY(LEXER_TOKEN_SYMBOL_EQUAL, LEXER_TOKEN_SYMBOL_NOT_EQUAL,
                    LEXER_TOKEN_SYMBOL_GREATER, LEXER_TOKEN_SYMBOL_SMALLER,
                    LEXER_TOKEN_SYMBOL_GREATER_OR_EQUAL,
                    LEXER_TOKEN_SYMBOL_SMALLER_OR_EQUAL, ),
    },
    {
        .ltr = true,
        ORDER_ARRAY(LEXER_TOKEN_SYMBOL_COLON, ),
    },
    {
        .ltr = false,
        ORDER_ARRAY(LEXER_TOKEN_SYMBOL_ASSIGN, ),
    },
    {
        .ltr = true,
        ORDER_ARRAY(LEXER_TOKEN_KEYWORD_RETURN,
                    LEXER_TOKEN_KEYWORD_PRINT_U64, ),
    },
    {
        .ltr = true,
        ORDER_ARRAY(LEXER_TOKEN_SYMBOL_EOL, LEXER_TOKEN_SYMBOL_COMMA, ),
    },
    {
        .ltr = true,
        ORDER_ARRAY(LEXER_TOKEN_KEYWORD_IF, ),
    },
};

static constexpr size_t PARSER_ORDER_SIZE =
    sizeof(PARSER_ORDER) / sizeof(*PARSER_ORDER);

void parserNodePrint(const ParserNode *node, int indent) {
  for (int i = 0; i < indent; ++i)
    printf(" ");

  if (node == NULL) {
    printf("null");
    return;
  }

  printf("{token=\"%s\"", PARSER_TOKEN_STRINGS[node->token]);

  switch (node->token) {
  case PARSER_TOKEN_ROOT:
  case PARSER_TOKEN_SYMBOL_CURLY_BRACKET:
  case PARSER_TOKEN_SYMBOL_PARENTHESIS: {
    const ParserNodeArray *metadata = node->metadata;
    printf(",children=[\n");
    for (size_t i = 0; i < metadata->size; ++i) {
      parserNodePrint(metadata->data[i], indent + 1);
      printf(",\n");
    }
    for (int i = 0; i < indent; ++i)
      printf(" ");
    printf("]");
  }
    goto RETURN_SUCCESS;
  case PARSER_TOKEN_IDENTIFIER:
  case PARSER_TOKEN_TYPE_TYPE:
  case PARSER_TOKEN_TYPE_VOID:
  case PARSER_TOKEN_TYPE_BOOL:
  case PARSER_TOKEN_TYPE_I8:
  case PARSER_TOKEN_TYPE_U8:
  case PARSER_TOKEN_TYPE_I16:
  case PARSER_TOKEN_TYPE_U16:
  case PARSER_TOKEN_TYPE_I32:
  case PARSER_TOKEN_TYPE_U32:
  case PARSER_TOKEN_TYPE_I64:
  case PARSER_TOKEN_TYPE_U64:
  case PARSER_TOKEN_TYPE_F16:
  case PARSER_TOKEN_TYPE_F32:
  case PARSER_TOKEN_TYPE_F64:
  case PARSER_TOKEN_TYPE_F128:
    goto RETURN_SUCCESS;
  case PARSER_TOKEN_VALUE_INT: {
    ParserNodeIntMetadata metadata = (ParserNodeIntMetadata)node->metadata;
    printf(",operand=%ld", metadata);
  }
    goto RETURN_SUCCESS;
  case PARSER_TOKEN_VALUE_FLOAT: {
    ParserNodeFloatMetadata *metadata = node->metadata;
    printf(",operand=%Lf", *metadata);
  }
    goto RETURN_SUCCESS;
  case PARSER_TOKEN_VALUE_BOOL: {
    ParserNodeIntMetadata metadata = (ParserNodeIntMetadata)node->metadata;
    printf(",value=%b", (ParserNodeBoolMetadata)metadata);
  }
    goto RETURN_SUCCESS;
  case PARSER_TOKEN_CONSTANT:
  case PARSER_TOKEN_VARIABLE: {
    const ParserNodeVariableMetadata *metadata = node->metadata;
    printf(",\n");
    for (int i = 0; i < indent; ++i)
      printf(" ");
    printf("name=\n");
    parserNodePrint(metadata->name, indent + 1);
    printf(",\n");
    for (int i = 0; i < indent; ++i)
      printf(" ");
    printf("type=\n");
    parserNodePrint(metadata->type, indent + 1);
    printf(",\n");
    for (int i = 0; i < indent; ++i)
      printf(" ");
    printf("value=\n");
    parserNodePrint(metadata->value, indent + 1);
    printf("\n");
    for (int i = 0; i < indent; ++i)
      printf(" ");
  }
    goto RETURN_SUCCESS;
  case PARSER_TOKEN_OPERATOR_PLUS:
  case PARSER_TOKEN_OPERATOR_MINUS:
  case PARSER_TOKEN_KEYWORD_PRINT_U64:
  case PARSER_TOKEN_SYMBOL_COMMA:
  case PARSER_TOKEN_SYMBOL_EOL: {
    const ParserNodeSingleChildMetadata *metadata = node->metadata;
    printf(",\n");
    for (int i = 0; i < indent; ++i)
      printf(" ");
    printf("child=\n");
    parserNodePrint(metadata, indent + 1);
    printf("\n");
    for (int i = 0; i < indent; ++i)
      printf(" ");
  }
    goto RETURN_SUCCESS;
  case PARSER_TOKEN_KEYWORD_RETURN: {
    const ParserNodeReturnMetadata *metadata = node->metadata;
    printf(",\n");
    for (int i = 0; i < indent; ++i)
      printf(" ");
    printf("value=\n");
    parserNodePrint(metadata->value, indent + 1);
    printf("\n");
    for (int i = 0; i < indent; ++i)
      printf(" ");
  }
    goto RETURN_SUCCESS;
  case PARSER_TOKEN_FUNCTION_DEFINITION: {
    const ParserNodeFunctionDefnitionMetadata *metadata = node->metadata;
    printf(",\n");
    for (int i = 0; i < indent; ++i)
      printf(" ");
    printf("arguments=\n");
    parserNodePrint(metadata->arguments, indent + 1);
    printf(",\n");
    for (int i = 0; i < indent; ++i)
      printf(" ");
    printf("returnType=\n");
    parserNodePrint(metadata->returnType, indent + 1);
    printf(",\n");
    for (int i = 0; i < indent; ++i)
      printf(" ");
    printf("body=\n");
    parserNodePrint(metadata->body, indent + 1);
    printf("\n");
    for (int i = 0; i < indent; ++i)
      printf(" ");
  }
    goto RETURN_SUCCESS;
  case PARSER_TOKEN_TYPE_FUNCTION: {
    const ParserNodeTypeFunctionMetadata *metadata = node->metadata;
    printf(",\n");
    for (int i = 0; i < indent; ++i)
      printf(" ");
    printf("arguments=\n");
    parserNodePrint(metadata->arguments, indent + 1);
    printf(",\n");
    for (int i = 0; i < indent; ++i)
      printf(" ");
    printf("returnType=\n");
    parserNodePrint(metadata->returnType, indent + 1);
    printf("\n");
    for (int i = 0; i < indent; ++i)
      printf(" ");
  }
    goto RETURN_SUCCESS;
  case PARSER_TOKEN_FUNCTION_CALL: {
    const ParserNodeFunctionCall *metadata = node->metadata;
    printf(",\n");
    for (int i = 0; i < indent; ++i)
      printf(" ");
    printf("function=\n");
    parserNodePrint(metadata->function, indent + 1);
    printf(",\n");
    for (int i = 0; i < indent; ++i)
      printf(" ");
    printf("params=[\n");
    for (size_t i = 0; i < metadata->params->size; ++i) {
      parserNodePrint(metadata->params->data[i], indent + 1);
      printf(",\n");
    }
    for (int i = 0; i < indent; ++i)
      printf(" ");
    printf("]\n");
    for (int i = 0; i < indent; ++i)
      printf(" ");
  }
    goto RETURN_SUCCESS;
  case PARSER_TOKEN_OPERATOR_ASSIGN:
  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_OPERATOR_EQUAL:
  case PARSER_TOKEN_OPERATOR_NOT_EQUAL:
  case PARSER_TOKEN_OPERATOR_GREATER:
  case PARSER_TOKEN_OPERATOR_SMALLER:
  case PARSER_TOKEN_OPERATOR_GREATER_OR_EQUAL:
  case PARSER_TOKEN_OPERATOR_SMALLER_OR_EQUAL: {
    const ParserNodeInfixMetadata *metadata = node->metadata;
    printf(",\n");
    for (int i = 0; i < indent; ++i)
      printf(" ");
    printf("left=\n");
    parserNodePrint(metadata->left, indent + 1);
    printf(",\n");
    for (int i = 0; i < indent; ++i)
      printf(" ");
    printf("right=\n");
    parserNodePrint(metadata->right, indent + 1);
    printf("\n");
    for (int i = 0; i < indent; ++i)
      printf(" ");
  }
    goto RETURN_SUCCESS;
  case PARSER_TOKEN_KEYWORD_IF: {
    ParserNodeIfMetadata *metadata = node->metadata;
    printf(",\n");
    for (int i = 0; i < indent; ++i)
      printf(" ");
    printf("condition=\n");
    parserNodePrint(metadata->condition, indent + 1);
    printf(",\n");
    for (int i = 0; i < indent; ++i)
      printf(" ");
    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(" ");
    free(metadata);
  }
    goto RETURN_SUCCESS;
  case PARSER_TOKEN_NONE:
  }
  UNREACHABLE;

RETURN_SUCCESS:
  printf("}");
}

void parserNodeDelete(ParserNode *node) {
  if (node == NULL) {
    return;
  }
  switch (node->token) {
  case PARSER_TOKEN_ROOT:
  case PARSER_TOKEN_SYMBOL_CURLY_BRACKET:
  case PARSER_TOKEN_SYMBOL_PARENTHESIS: {
    ParserNodeArray *metadata = node->metadata;
    for (size_t i = 0; i < metadata->size; ++i) {
      parserNodeDelete(metadata->data[i]);
    }
    free(metadata->data);
    free(metadata);
  }
    goto RETURN_SUCCESS;
  case PARSER_TOKEN_IDENTIFIER:
  case PARSER_TOKEN_TYPE_TYPE:
  case PARSER_TOKEN_TYPE_VOID:
  case PARSER_TOKEN_TYPE_BOOL:
  case PARSER_TOKEN_TYPE_I8:
  case PARSER_TOKEN_TYPE_U8:
  case PARSER_TOKEN_TYPE_I16:
  case PARSER_TOKEN_TYPE_U16:
  case PARSER_TOKEN_TYPE_I32:
  case PARSER_TOKEN_TYPE_U32:
  case PARSER_TOKEN_TYPE_I64:
  case PARSER_TOKEN_TYPE_U64:
  case PARSER_TOKEN_TYPE_F16:
  case PARSER_TOKEN_TYPE_F32:
  case PARSER_TOKEN_TYPE_F64:
  case PARSER_TOKEN_TYPE_F128:
  case PARSER_TOKEN_VALUE_INT:
  case PARSER_TOKEN_VALUE_BOOL:
    goto RETURN_SUCCESS;
  case PARSER_TOKEN_VALUE_FLOAT: {
    ParserNodeFloatMetadata *metadata = node->metadata;
    free(metadata);
  }
    goto RETURN_SUCCESS;
  case PARSER_TOKEN_CONSTANT:
  case PARSER_TOKEN_VARIABLE: {
    ParserNodeVariableMetadata *metadata = node->metadata;
    parserNodeDelete(metadata->name);
    parserNodeDelete(metadata->type);
    parserNodeDelete(metadata->value);
    free(metadata);
  }
    goto RETURN_SUCCESS;
  case PARSER_TOKEN_OPERATOR_PLUS:
  case PARSER_TOKEN_OPERATOR_MINUS:
  case PARSER_TOKEN_KEYWORD_PRINT_U64:
  case PARSER_TOKEN_SYMBOL_COMMA:
  case PARSER_TOKEN_SYMBOL_EOL: {
    ParserNodeSingleChildMetadata *metadata = node->metadata;
    parserNodeDelete(metadata);
  }
    goto RETURN_SUCCESS;
  case PARSER_TOKEN_KEYWORD_RETURN: {
    ParserNodeReturnMetadata *metadata = node->metadata;
    if (metadata->value != NULL) {
      parserNodeDelete(metadata->value);
    }
    free(metadata);
  }
    goto RETURN_SUCCESS;
  case PARSER_TOKEN_FUNCTION_DEFINITION: {
    ParserNodeFunctionDefnitionMetadata *metadata = node->metadata;
    parserNodeDelete(metadata->arguments);
    parserNodeDelete(metadata->returnType);
    parserNodeDelete(metadata->body);
    free(metadata);
  }
    goto RETURN_SUCCESS;
  case PARSER_TOKEN_TYPE_FUNCTION: {
    ParserNodeTypeFunctionMetadata *metadata = node->metadata;
    parserNodeDelete(metadata->arguments);
    parserNodeDelete(metadata->returnType);
    free(metadata);
  }
    goto RETURN_SUCCESS;
  case PARSER_TOKEN_FUNCTION_CALL: {
    ParserNodeFunctionCall *metadata = node->metadata;
    parserNodeDelete(metadata->function);
    for (size_t i = 0; i < metadata->params->size; ++i) {
      parserNodeDelete(metadata->params->data[i]);
    }
    free(metadata->params->data);
    free(metadata->params);
    free(metadata);
  }
    goto RETURN_SUCCESS;
  case PARSER_TOKEN_OPERATOR_ASSIGN:
  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_OPERATOR_EQUAL:
  case PARSER_TOKEN_OPERATOR_NOT_EQUAL:
  case PARSER_TOKEN_OPERATOR_GREATER:
  case PARSER_TOKEN_OPERATOR_SMALLER:
  case PARSER_TOKEN_OPERATOR_GREATER_OR_EQUAL:
  case PARSER_TOKEN_OPERATOR_SMALLER_OR_EQUAL: {
    ParserNodeInfixMetadata *metadata = node->metadata;
    parserNodeDelete(metadata->left);
    parserNodeDelete(metadata->right);
    free(metadata);
  }
    goto RETURN_SUCCESS;
  case PARSER_TOKEN_KEYWORD_IF: {
    ParserNodeIfMetadata *metadata = node->metadata;
    parserNodeDelete(metadata->condition);
    parserNodeDelete(metadata->ifBody);
    parserNodeDelete(metadata->elseBody);
    free(metadata);
  }
    goto RETURN_SUCCESS;
  case PARSER_TOKEN_NONE:
  }
  UNREACHABLE;

RETURN_SUCCESS:
  free(node);
}

ParserNode *newParserNode(ParserToken token, char *str_begin, char *str_end,
                          void *metadata, ParserNode *parent) {
  ParserNode *parserNode = a404m_malloc(sizeof(*parserNode));
  parserNode->token = token;
  parserNode->str_begin = str_begin;
  parserNode->str_end = str_end;
  parserNode->metadata = metadata;
  parserNode->parent = parent;
  return parserNode;
}

ParserNode *parser(LexerNodeArray lexed) {
  ParserNode *root = newParserNode(PARSER_TOKEN_ROOT, NULL, NULL, NULL, NULL);
  if (parserNodeArray(lexed.data, lexed.data + lexed.size, root)) {
    return root;
  } else {
    free(root);
    return NULL;
  }
}

bool parserNodeArray(LexerNode *begin, LexerNode *end, ParserNode *parent) {
  size_t parsedNodes_size = 0;

  ParserNodeArray *parsedNodes = a404m_malloc(sizeof(*parsedNodes));
  parsedNodes->data =
      a404m_malloc(parsedNodes_size * sizeof(*parsedNodes->data));
  parsedNodes->size = 0;

  for (size_t orders_index = 0; orders_index < PARSER_ORDER_SIZE;
       ++orders_index) {
    const ParserOrder orders = PARSER_ORDER[orders_index];

    for (LexerNode *iter = orders.ltr ? begin : end - 1;
         iter < end && iter >= begin; orders.ltr ? ++iter : --iter) {

      if (iter->parserNode != NULL) {
        continue;
      }

      for (size_t order_index = 0; order_index < orders.size; ++order_index) {
        const LexerToken order = orders.data[order_index];
        if (iter->token == order) {
          bool conti = false;
          ParserNode *parserNode = parseNode(iter, begin, end, parent, &conti);
          if (parserNode == NULL && !conti) {
            goto RETURN_ERROR;
          }
        }
      }
    }
  }

  for (LexerNode *iter = begin; iter < end; ++iter) {
    ParserNode *pNode = iter->parserNode;
    if (pNode == NULL) {
      printError(iter->str_begin, iter->str_end, "Bad child");
      goto RETURN_ERROR;
    } else if (pNode->parent != parent) {
      continue;
    }

    for (size_t i = 0; i < parsedNodes->size; ++i) {
      if (parsedNodes->data[i] == pNode) {
        goto CONTINUE;
      }
    }
    if (parsedNodes->size == parsedNodes_size) {
      parsedNodes_size += parsedNodes_size / 2 + 1;
      parsedNodes->data = a404m_realloc(
          parsedNodes->data, sizeof(*parsedNodes->data) * parsedNodes_size);
    }
    parsedNodes->data[parsedNodes->size] = pNode;
    parsedNodes->size += 1;
  CONTINUE:
  }

  parsedNodes->data = a404m_realloc(
      parsedNodes->data, parsedNodes->size * sizeof(*parsedNodes->data));

  parent->metadata = parsedNodes;

  return true;

RETURN_ERROR:
  for (size_t i = 0; i < parsedNodes->size; ++i) {
    free(parsedNodes->data[i]);
  }
  free(parsedNodes->data);
  free(parsedNodes);
  return false;
}

ParserNode *parseNode(LexerNode *node, LexerNode *begin, LexerNode *end,
                      ParserNode *parent, bool *conti) {
  switch (node->token) {
  case LEXER_TOKEN_IDENTIFIER:
    return parserNoMetadata(node, parent, PARSER_TOKEN_IDENTIFIER);
  case LEXER_TOKEN_KEYWORD_TYPE:
    return parserNoMetadata(node, parent, PARSER_TOKEN_TYPE_TYPE);
  case LEXER_TOKEN_KEYWORD_VOID:
    return parserNoMetadata(node, parent, PARSER_TOKEN_TYPE_VOID);
  case LEXER_TOKEN_KEYWORD_I8:
    return parserNoMetadata(node, parent, PARSER_TOKEN_TYPE_I8);
  case LEXER_TOKEN_KEYWORD_U8:
    return parserNoMetadata(node, parent, PARSER_TOKEN_TYPE_U8);
  case LEXER_TOKEN_KEYWORD_I16:
    return parserNoMetadata(node, parent, PARSER_TOKEN_TYPE_I16);
  case LEXER_TOKEN_KEYWORD_U16:
    return parserNoMetadata(node, parent, PARSER_TOKEN_TYPE_U16);
  case LEXER_TOKEN_KEYWORD_I32:
    return parserNoMetadata(node, parent, PARSER_TOKEN_TYPE_I32);
  case LEXER_TOKEN_KEYWORD_U32:
    return parserNoMetadata(node, parent, PARSER_TOKEN_TYPE_U32);
  case LEXER_TOKEN_KEYWORD_I64:
    return parserNoMetadata(node, parent, PARSER_TOKEN_TYPE_I64);
  case LEXER_TOKEN_KEYWORD_U64:
    return parserNoMetadata(node, parent, PARSER_TOKEN_TYPE_U64);
  case LEXER_TOKEN_KEYWORD_BOOL:
    return parserNoMetadata(node, parent, PARSER_TOKEN_TYPE_BOOL);
  case LEXER_TOKEN_KEYWORD_F16:
    return parserNoMetadata(node, parent, PARSER_TOKEN_TYPE_F16);
  case LEXER_TOKEN_KEYWORD_F32:
    return parserNoMetadata(node, parent, PARSER_TOKEN_TYPE_F32);
  case LEXER_TOKEN_KEYWORD_F64:
    return parserNoMetadata(node, parent, PARSER_TOKEN_TYPE_F64);
  case LEXER_TOKEN_KEYWORD_F128:
    return parserNoMetadata(node, parent, PARSER_TOKEN_TYPE_F128);
  case LEXER_TOKEN_KEYWORD_PRINT_U64:
    return parserPrintU64(node, end, parent);
  case LEXER_TOKEN_KEYWORD_RETURN:
    return parserReturn(node, end, parent);
  case LEXER_TOKEN_KEYWORD_TRUE:
  case LEXER_TOKEN_KEYWORD_FALSE:
    return parserBoolValue(node, parent);
  case LEXER_TOKEN_SYMBOL_EOL:
    return parserEol(node, begin, parent);
  case LEXER_TOKEN_SYMBOL_CLOSE_PARENTHESIS:
    return parserParenthesis(node, begin, parent);
  case LEXER_TOKEN_SYMBOL_CLOSE_CURLY_BRACKET:
    return parserCurlyBrackets(node, begin, parent);
  case LEXER_TOKEN_SYMBOL_FUNCTION_ARROW:
    return parserFunction(node, begin, end, parent);
  case LEXER_TOKEN_SYMBOL_COLON:
    return parserVariable(node, begin, end, parent);
  case LEXER_TOKEN_SYMBOL_COMMA:
    return parserComma(node, begin, parent);
  case LEXER_TOKEN_NUMBER:
    return parserNumber(node, parent);
  case LEXER_TOKEN_SYMBOL_ASSIGN:
    return parserBinaryOperator(node, begin, end, parent,
                                PARSER_TOKEN_OPERATOR_ASSIGN);
  case LEXER_TOKEN_SYMBOL_SUM:
    return parserBinaryOperator(node, begin, end, parent,
                                PARSER_TOKEN_OPERATOR_SUM);
  case LEXER_TOKEN_SYMBOL_SUB:
    return parserBinaryOperator(node, begin, end, parent,
                                PARSER_TOKEN_OPERATOR_SUB);
  case LEXER_TOKEN_SYMBOL_MULTIPLY:
    return parserBinaryOperator(node, begin, end, parent,
                                PARSER_TOKEN_OPERATOR_MULTIPLY);
  case LEXER_TOKEN_SYMBOL_DIVIDE:
    return parserBinaryOperator(node, begin, end, parent,
                                PARSER_TOKEN_OPERATOR_DIVIDE);
  case LEXER_TOKEN_SYMBOL_MODULO:
    return parserBinaryOperator(node, begin, end, parent,
                                PARSER_TOKEN_OPERATOR_MODULO);
  case LEXER_TOKEN_SYMBOL_EQUAL:
    return parserBinaryOperator(node, begin, end, parent,
                                PARSER_TOKEN_OPERATOR_EQUAL);
  case LEXER_TOKEN_SYMBOL_NOT_EQUAL:
    return parserBinaryOperator(node, begin, end, parent,
                                PARSER_TOKEN_OPERATOR_NOT_EQUAL);
  case LEXER_TOKEN_SYMBOL_GREATER:
    return parserBinaryOperator(node, begin, end, parent,
                                PARSER_TOKEN_OPERATOR_GREATER);
  case LEXER_TOKEN_SYMBOL_SMALLER:
    return parserBinaryOperator(node, begin, end, parent,
                                PARSER_TOKEN_OPERATOR_SMALLER);
  case LEXER_TOKEN_SYMBOL_GREATER_OR_EQUAL:
    return parserBinaryOperator(node, begin, end, parent,
                                PARSER_TOKEN_OPERATOR_GREATER_OR_EQUAL);
  case LEXER_TOKEN_SYMBOL_SMALLER_OR_EQUAL:
    return parserBinaryOperator(node, begin, end, parent,
                                PARSER_TOKEN_OPERATOR_SMALLER_OR_EQUAL);
  case LEXER_TOKEN_SYMBOL_PLUS: {
    ParserNode *result = parserBinaryOrLeftOperator(node, begin, end, parent,
                                                    PARSER_TOKEN_OPERATOR_PLUS,
                                                    LEXER_TOKEN_SYMBOL_SUM);
    *conti = result == NULL;
    return result;
  }
  case LEXER_TOKEN_SYMBOL_MINUS: {
    ParserNode *result = parserBinaryOrLeftOperator(node, begin, end, parent,
                                                    PARSER_TOKEN_OPERATOR_MINUS,
                                                    LEXER_TOKEN_SYMBOL_SUB);
    *conti = result == NULL;
    return result;
  }
  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:
  case LEXER_TOKEN_NONE:
    break;
  }
  UNREACHABLE;
}

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;
}

ParserNode *getNextUsingCommonParent(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 getUntilCommonParent(node->parserNode, parent);
    }
  }

  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 *parserNoMetadata(LexerNode *node, ParserNode *parent,
                             ParserToken token) {
  return node->parserNode =
             newParserNode(token, node->str_begin, node->str_end, NULL, parent);
}

ParserNode *parserPrintU64(LexerNode *node, LexerNode *end,
                           ParserNode *parent) {
  LexerNode *afterNode = node + 1;
  if (afterNode >= end) {
    printError(node->str_begin, node->str_end, "No param");
    return NULL;
  } else if (afterNode->parserNode == NULL) {
    printError(node->str_begin, node->str_end, "Bad param");
    return NULL;
  }

  ParserNode *operand = getUntilCommonParent(afterNode->parserNode, parent);
  if (operand == NULL) {
    printError(node->str_begin, node->str_end, "Bad param");
    return NULL;
  }

  return operand->parent = node->parserNode = newParserNode(
             PARSER_TOKEN_KEYWORD_PRINT_U64, node->str_begin, node->str_end,
             (ParserNodeSingleChildMetadata *)operand, parent);
}

ParserNode *parserReturn(LexerNode *node, LexerNode *end, ParserNode *parent) {
  LexerNode *afterNode = node + 1;
  ParserNode *operand;
  if (afterNode >= end || afterNode->parserNode == NULL) {
    operand = NULL;
  } else {
    operand = getUntilCommonParent(afterNode->parserNode, parent);
    if (operand == NULL) {
      printError(node->str_begin, node->str_end, "No param");
      return NULL;
    }
  }

  ParserNodeReturnMetadata *metadata = a404m_malloc(sizeof(*metadata));
  metadata->value = operand;

  node->parserNode = newParserNode(PARSER_TOKEN_KEYWORD_RETURN, node->str_begin,
                                   node->str_end, metadata, parent);
  if (operand != NULL) {
    operand->parent = node->parserNode;
  }

  return node->parserNode;
}

ParserNode *parserNumber(LexerNode *node, ParserNode *parent) {
  ParserNode *parserNode;
  switch (*node->str_begin) {
  case '0':
    if (node->str_end - node->str_begin > 1) {
      printError(node->str_begin, node->str_end, "Not implemented");
      return NULL;
    }
    // fall through
  default: {
    bool success;
    uint64_t value = decimalToU64(node->str_begin, node->str_end, &success);
    if (success) {
      parserNode =
          newParserNode(PARSER_TOKEN_VALUE_INT, node->str_begin, node->str_end,
                        (void *)(ParserNodeIntMetadata)value, parent);
    } else {
      ParserNodeFloatMetadata *metadata = a404m_malloc(sizeof(*metadata));
      *metadata = numberToFloat(node->str_begin, node->str_end, &success);

      if (success) {
        parserNode = newParserNode(PARSER_TOKEN_VALUE_FLOAT, node->str_begin,
                                   node->str_end, metadata, parent);
      } else {
        printError(node->str_begin, node->str_end, "Error in parsing number");
        return NULL;
      }
    }
  }
  }
  return node->parserNode = parserNode;
}

ParserNode *parserBoolValue(LexerNode *node, ParserNode *parent) {
  return node->parserNode = newParserNode(
             PARSER_TOKEN_VALUE_BOOL, node->str_begin, node->str_end,
             (void *)(ParserNodeBoolMetadata)(node->token ==
                                              LEXER_TOKEN_KEYWORD_TRUE),
             parent);
}

ParserNode *parserEol(LexerNode *node, LexerNode *begin, ParserNode *parent) {
  LexerNode *nodeBefore = node - 1;
  ParserNode *parserNodeBefore;
  if (nodeBefore < begin) {
    parserNodeBefore = NULL;
  } else if (nodeBefore->parserNode == NULL) {
    printError(node->str_begin, node->str_end, "Bad EOL after %s",
               LEXER_TOKEN_STRINGS[nodeBefore->token]);
    return NULL;
  } else {
    parserNodeBefore = getUntilCommonParent(nodeBefore->parserNode, parent);
    if (parserNodeBefore == NULL || !isExpression(parserNodeBefore)) {
      printError(node->str_begin, node->str_end, "Bad EOL after %s",
                 LEXER_TOKEN_STRINGS[nodeBefore->token]);
      return NULL;
    }
  }
  ParserNode *parserNode =
      newParserNode(PARSER_TOKEN_SYMBOL_EOL, node->str_begin, node->str_end,
                    (ParserNodeSingleChildMetadata *)parserNodeBefore, parent);
  node->parserNode = parserNode;
  if (parserNodeBefore != NULL) {
    parserNodeBefore->parent = parserNode;
  }
  return parserNode;
}

ParserNode *parserComma(LexerNode *node, LexerNode *begin, ParserNode *parent) {
  LexerNode *nodeBefore = node - 1;
  ParserNode *parserNodeBefore;
  if (nodeBefore < begin || nodeBefore->parserNode == NULL) {
    printError(node->str_begin, node->str_end, "Bad Comma after %s",
               LEXER_TOKEN_STRINGS[nodeBefore->token]);
    return NULL;
  } else {
    parserNodeBefore = getUntilCommonParent(nodeBefore->parserNode, parent);
    if (parserNodeBefore == NULL || !isExpression(parserNodeBefore)) {
      printError(node->str_begin, node->str_end, "Bad Comma after %s",
                 LEXER_TOKEN_STRINGS[nodeBefore->token]);
      return NULL;
    }
  }
  return node->parserNode = parserNodeBefore->parent = newParserNode(
             PARSER_TOKEN_SYMBOL_COMMA, node->str_begin, node->str_end,
             (ParserNodeSingleChildMetadata *)parserNodeBefore, parent);
}

ParserNode *parserParenthesis(LexerNode *closing, LexerNode *begin,
                              ParserNode *parent) {
  ParserNode *parserNode = a404m_malloc(sizeof(*parserNode));
  parserNode->parent = parent;

  LexerNode *opening = NULL;

  for (LexerNode *iter = closing - 1; iter >= begin; --iter) {

    if (iter->parserNode != NULL) {
      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;
      }
    } else if (iter->token == LEXER_TOKEN_SYMBOL_OPEN_PARENTHESIS) {
      opening = iter;
      break;
    }
  }

  if (opening == NULL) {
    printError(closing->str_begin, closing->str_end,
               "No opening for parenthesis");
    return NULL;
  }
  opening->parserNode = parserNode;
  closing->parserNode = parserNode;

  LexerNode *beforeNode = opening - 1;
  ParserNode *before;
  if (beforeNode < begin || beforeNode->parserNode == NULL ||
      (before = getUntilCommonParent(beforeNode->parserNode, parent)) == NULL ||
      !isExpression(before)) {
    before = NULL;
  } else {
    before->parent = parserNode;
  }

  if (before == NULL) {
    parserNode->token = PARSER_TOKEN_SYMBOL_PARENTHESIS;
    parserNode->str_begin = opening->str_begin;
    parserNode->str_end = closing->str_end;

    if (parserNodeArray(opening + 1, closing, parserNode)) {
      return parserNode;
    } else {
      free(parserNode);
      return NULL;
    }
  } else {
    parserNode->token = PARSER_TOKEN_FUNCTION_CALL;
    parserNode->str_begin = before->str_begin;
    parserNode->str_end = closing->str_end;

    if (parserNodeArray(opening + 1, closing, parserNode)) {
      ParserNodeFunctionCall *metadata = malloc(sizeof(*metadata));
      metadata->function = before;
      metadata->params = parserNode->metadata;
      parserNode->metadata = metadata;
      return parserNode;
    } else {
      free(parserNode);
      return NULL;
    }
  }
}

ParserNode *parserCurlyBrackets(LexerNode *closing, LexerNode *begin,
                                ParserNode *parent) {
  ParserNode *parserNode = a404m_malloc(sizeof(*parserNode));
  parserNode->parent = parent;
  parserNode->token = PARSER_TOKEN_SYMBOL_CURLY_BRACKET;

  LexerNode *opening = NULL;

  for (LexerNode *iter = closing - 1; iter >= begin; --iter) {
    if (iter->parserNode != NULL) {
      ParserNode *pNode =
          getUntilCommonParents(iter->parserNode, parent, parserNode);
      if (pNode == NULL) {
        printLog(iter->str_begin, iter->str_end, "Bad node");
        return NULL;
      } else {
        pNode->parent = parserNode;
      }
    } else if (iter->token == LEXER_TOKEN_SYMBOL_OPEN_CURLY_BRACKET) {
      opening = iter;
      break;
    }
  }

  if (opening == NULL) {
    printError(closing->str_begin, closing->str_end,
               "No opening for curly brackets");
    return NULL;
  }

  parserNode->str_begin = opening->str_begin;
  parserNode->str_end = closing->str_end;

  opening->parserNode = closing->parserNode = parserNode;

  if (parserNodeArray(opening + 1, closing, parserNode)) {
    return parserNode;
  } else {
    free(parserNode);
    return NULL;
  }
}

ParserNode *parserFunction(LexerNode *node, LexerNode *begin, LexerNode *end,
                           ParserNode *parent) {
  LexerNode *paramsNode = node - 1;
  LexerNode *retTypeNode = node + 1;
  LexerNode *bodyNode = node + 2;
  if (paramsNode < begin || paramsNode->parserNode == NULL) {
  NO_PARAMS:
    printError(node->str_begin, node->str_end, "No params");
    return NULL;
  } else if (retTypeNode >= end || retTypeNode->parserNode == NULL) {
  NO_RETURN_TYPE:
    printError(node->str_begin, node->str_end, "No return type");
    return NULL;
  }
  ParserNode *params = getUntilCommonParent(paramsNode->parserNode, parent);
  ParserNode *retType = getUntilCommonParent(retTypeNode->parserNode, parent);
  ParserNode *body;

  if (bodyNode >= end || bodyNode->parserNode == NULL) {
    body = NULL;
  } else {
    body = getUntilCommonParent(bodyNode->parserNode, parent);
    if (body == NULL || body->token != PARSER_TOKEN_SYMBOL_CURLY_BRACKET) {
      printError(node->str_begin, node->str_end, "Bad body");
      return NULL;
    }
    ParserNodeArray *bodyArray = body->metadata;
    for (size_t i = 0; i < bodyArray->size; ++i) {
      switch (bodyArray->data[i]->token) {
      case PARSER_TOKEN_SYMBOL_EOL:
      case PARSER_TOKEN_KEYWORD_IF:
        continue;
      case PARSER_TOKEN_ROOT:
      case PARSER_TOKEN_IDENTIFIER:
      case PARSER_TOKEN_VALUE_INT:
      case PARSER_TOKEN_VALUE_FLOAT:
      case PARSER_TOKEN_VALUE_BOOL:
      case PARSER_TOKEN_TYPE_TYPE:
      case PARSER_TOKEN_TYPE_FUNCTION:
      case PARSER_TOKEN_TYPE_VOID:
      case PARSER_TOKEN_TYPE_BOOL:
      case PARSER_TOKEN_TYPE_I8:
      case PARSER_TOKEN_TYPE_U8:
      case PARSER_TOKEN_TYPE_I16:
      case PARSER_TOKEN_TYPE_U16:
      case PARSER_TOKEN_TYPE_I32:
      case PARSER_TOKEN_TYPE_U32:
      case PARSER_TOKEN_TYPE_I64:
      case PARSER_TOKEN_TYPE_U64:
      case PARSER_TOKEN_TYPE_F16:
      case PARSER_TOKEN_TYPE_F32:
      case PARSER_TOKEN_TYPE_F64:
      case PARSER_TOKEN_TYPE_F128:
      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_OPERATOR_EQUAL:
      case PARSER_TOKEN_OPERATOR_NOT_EQUAL:
      case PARSER_TOKEN_OPERATOR_GREATER:
      case PARSER_TOKEN_OPERATOR_SMALLER:
      case PARSER_TOKEN_OPERATOR_GREATER_OR_EQUAL:
      case PARSER_TOKEN_OPERATOR_SMALLER_OR_EQUAL:
      case PARSER_TOKEN_FUNCTION_DEFINITION:
      case PARSER_TOKEN_FUNCTION_CALL:
        printError(bodyArray->data[i]->str_begin, bodyArray->data[i]->str_end,
                   "Maybe forgot a ; with %s",
                   PARSER_TOKEN_STRINGS[bodyArray->data[i]->token]);
        return NULL;
      case PARSER_TOKEN_NONE:
      }
      UNREACHABLE;
    }
  }

  if (params->token != PARSER_TOKEN_SYMBOL_PARENTHESIS) {
    goto NO_PARAMS;
  } else if (!isType(retType)) {
    goto NO_RETURN_TYPE;
  } else if (!isAllArguments(params->metadata)) {
    printError(params->str_begin, params->str_end, "Bad arguments");
    return NULL;
  }

  if (body != NULL) {
    ParserNodeFunctionDefnitionMetadata *metadata =
        a404m_malloc(sizeof(*metadata));

    metadata->body = body;
    metadata->arguments = params;
    metadata->returnType = retType;

    return params->parent = retType->parent = body->parent = node->parserNode =
               newParserNode(PARSER_TOKEN_FUNCTION_DEFINITION,
                             params->str_begin, body->str_end, metadata,
                             parent);
  } else {
    ParserNodeTypeFunctionMetadata *metadata = a404m_malloc(sizeof(*metadata));

    metadata->arguments = params;
    metadata->returnType = retType;

    return params->parent = retType->parent = node->parserNode =
               newParserNode(PARSER_TOKEN_TYPE_FUNCTION, params->str_begin,
                             retType->str_end, metadata, parent);
  }
}

ParserNode *parserVariable(LexerNode *node, LexerNode *begin, LexerNode *end,
                           ParserNode *parent) {
  ParserNode *variableNode = a404m_malloc(sizeof(*variableNode));
  variableNode->parent = parent;

  LexerNode *nameNode = node - 1;
  if (nameNode < begin || nameNode->parserNode == NULL) {
    printError(node->str_begin, node->str_end, "No name");
    goto RETURN_ERROR;
  }

  ParserNode *name = getUntilCommonParent(nameNode->parserNode, parent);

  if (name == NULL) {
    printError(node->str_begin, node->str_end,
               "Name should be identifier but got nothing");
    return NULL;
  } else if (name->token != PARSER_TOKEN_IDENTIFIER) {
    printError(name->str_begin, name->str_end,
               "Name should be identifier but got '%s'",
               PARSER_TOKEN_STRINGS[name->token]);
    return NULL;
  } else {
    name->parent = variableNode;
    variableNode->str_begin = name->str_begin;
  }

  LexerNode *node1 = node + 1;
  ParserNode *type;
  ParserNode *value;

  ParserToken token = PARSER_TOKEN_VARIABLE;

  if (node1 >= end) {
    printError(node->str_begin, node->str_end, "Bad variable definition");
    return NULL;
  } else if (node1->token == LEXER_TOKEN_SYMBOL_COLON) {
    type = NULL;
    node1->parserNode = variableNode;
    token = PARSER_TOKEN_CONSTANT;
  } else if (node1->token == LEXER_TOKEN_SYMBOL_ASSIGN) {
    type = NULL;
    node1->parserNode = variableNode;
  } else if (node1->parserNode == NULL) {
    printError(node1->str_begin, node1->str_end,
               "Bad variable type with token '%s' %d",
               LEXER_TOKEN_STRINGS[node1->token], node1->token);
    return NULL;
  } else {
    type = getUntilCommonParent(node1->parserNode, parent);
    if (type == NULL || !isType(type)) {
      printError(node1->str_begin, node1->str_end, "Bad variable type");
      return NULL;
    }
    type->parent = variableNode;
    for (++node1; node1 < end && getUntilCommonParent(node1->parserNode,
                                                      parent) == variableNode;
         ++node1) {
    }
    if (node1 < end && node1->token == LEXER_TOKEN_SYMBOL_COLON) {
      node1->parserNode = variableNode;
      token = PARSER_TOKEN_CONSTANT;
    } else if (node1 < end && node1->token == LEXER_TOKEN_SYMBOL_ASSIGN) {
      node1->parserNode = variableNode;
    } else {
      node1 = NULL;
      value = NULL;
    }
  }

  if (node1 != NULL) {
    LexerNode *valueNode = node1 + 1;
    if (valueNode >= end || valueNode->parserNode == NULL) {
      printError(name->str_begin, name->str_end, "No value");
      return NULL;
    } else {
      value = getUntilCommonParent(valueNode->parserNode, parent);
      if (!isValue(value)) {
        printError(name->str_begin, name->str_end, "Bad value");
        return NULL;
      }
      value->parent = variableNode;
    }
  }

  ParserNodeVariableMetadata *metadata = a404m_malloc(sizeof(*metadata));
  metadata->value = value;
  metadata->name = name;
  metadata->type = type;

  variableNode->metadata = metadata;

  if (value != NULL) {
    variableNode->str_end = value->str_end;
  } else {
    variableNode->str_end = type->str_end;
  }

  variableNode->token = token;
  return node->parserNode = variableNode;

RETURN_ERROR:
  free(variableNode);
  return NULL;
}

ParserNode *parserBinaryOperator(LexerNode *node, LexerNode *begin,
                                 LexerNode *end, ParserNode *parent,
                                 ParserToken token) {
  LexerNode *leftNode = node - 1;
  LexerNode *rightNode = node + 1;

  if (leftNode < begin || rightNode >= end) {
    printError(node->str_begin, node->str_end, "Bad binary operator");
    return NULL;
  }

  ParserNode *left = getUntilCommonParent(leftNode->parserNode, parent);
  ParserNode *right = getUntilCommonParent(rightNode->parserNode, parent);

  if (left == NULL || right == NULL) {
    printError(node->str_begin, node->str_end, "Bad binary operator");
    return NULL;
  }

  ParserNodeInfixMetadata *metadata = a404m_malloc(sizeof(*metadata));
  metadata->left = left;
  metadata->right = right;

  return left->parent = right->parent = node->parserNode = newParserNode(
             token, left->str_begin, right->str_end, metadata, parent);
}

ParserNode *parserBinaryOrLeftOperator(LexerNode *node, LexerNode *begin,
                                       LexerNode *end, ParserNode *parent,
                                       ParserToken token,
                                       LexerToken laterToken) {
  LexerNode *leftNode = node - 1;
  LexerNode *rightNode = node + 1;

  if ((leftNode >= begin && leftNode->parserNode != NULL) || rightNode >= end ||
      rightNode->parserNode == NULL) {
    node->token = laterToken;
    return NULL;
  }

  ParserNode *right = getUntilCommonParent(rightNode->parserNode, parent);

  if (right == NULL) {
    node->token = laterToken;
    return NULL;
  }

  return right->parent = node->parserNode =
             newParserNode(token, node->str_begin, right->str_end,
                           (ParserNodeSingleChildMetadata *)right, parent);
}

ParserNode *parserIf(LexerNode *node, LexerNode *end, ParserNode *parent) {
  LexerNode *conditionNode = node + 1;
  if (conditionNode >= end) {
    printError(node->str_begin, node->str_end, "If has no condition");
    return NULL;
  }

  ParserNode *condition =
      getUntilCommonParent(conditionNode->parserNode, parent);

  if (condition == NULL) {
    printError(conditionNode->str_begin, conditionNode->str_end,
               "If has bad condition");
    return NULL;
  }

  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");
    return NULL;
  }

  ParserNodeIfMetadata *metadata = a404m_malloc(sizeof(*metadata));
  metadata->condition = condition;
  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 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) {
  for (size_t i = 0; i < nodes->size; ++i) {
    const ParserNode *node = nodes->data[i];
    if (node->token != PARSER_TOKEN_SYMBOL_COMMA && i + 1 != nodes->size) {
      return false;
    }
  }
  return true;
}

bool isExpression(ParserNode *node) {
  switch (node->token) {
  case PARSER_TOKEN_IDENTIFIER:
  case PARSER_TOKEN_CONSTANT:
  case PARSER_TOKEN_VARIABLE:
  case PARSER_TOKEN_SYMBOL_PARENTHESIS:
  case PARSER_TOKEN_FUNCTION_DEFINITION:
  case PARSER_TOKEN_FUNCTION_CALL:
  case PARSER_TOKEN_KEYWORD_PRINT_U64:
  case PARSER_TOKEN_KEYWORD_RETURN:
  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_OPERATOR_EQUAL:
  case PARSER_TOKEN_OPERATOR_NOT_EQUAL:
  case PARSER_TOKEN_OPERATOR_GREATER:
  case PARSER_TOKEN_OPERATOR_SMALLER:
  case PARSER_TOKEN_OPERATOR_GREATER_OR_EQUAL:
  case PARSER_TOKEN_OPERATOR_SMALLER_OR_EQUAL:
  case PARSER_TOKEN_VALUE_INT:
  case PARSER_TOKEN_VALUE_FLOAT:
  case PARSER_TOKEN_VALUE_BOOL:
  case PARSER_TOKEN_KEYWORD_IF:
    return true;
  case PARSER_TOKEN_ROOT:
  case PARSER_TOKEN_TYPE_TYPE:
  case PARSER_TOKEN_TYPE_FUNCTION:
  case PARSER_TOKEN_TYPE_VOID:
  case PARSER_TOKEN_TYPE_BOOL:
  case PARSER_TOKEN_TYPE_I8:
  case PARSER_TOKEN_TYPE_U8:
  case PARSER_TOKEN_TYPE_I16:
  case PARSER_TOKEN_TYPE_U16:
  case PARSER_TOKEN_TYPE_I32:
  case PARSER_TOKEN_TYPE_U32:
  case PARSER_TOKEN_TYPE_I64:
  case PARSER_TOKEN_TYPE_U64:
  case PARSER_TOKEN_TYPE_F16:
  case PARSER_TOKEN_TYPE_F32:
  case PARSER_TOKEN_TYPE_F64:
  case PARSER_TOKEN_TYPE_F128:
  case PARSER_TOKEN_SYMBOL_EOL:
  case PARSER_TOKEN_SYMBOL_CURLY_BRACKET:
  case PARSER_TOKEN_SYMBOL_COMMA:
    return false;
  case PARSER_TOKEN_NONE:
  }
  UNREACHABLE;
}

bool isType(ParserNode *node) {
  switch (node->token) {
  case PARSER_TOKEN_TYPE_TYPE:
  case PARSER_TOKEN_TYPE_FUNCTION:
  case PARSER_TOKEN_TYPE_VOID:
  case PARSER_TOKEN_TYPE_I8:
  case PARSER_TOKEN_TYPE_U8:
  case PARSER_TOKEN_TYPE_I16:
  case PARSER_TOKEN_TYPE_U16:
  case PARSER_TOKEN_TYPE_I32:
  case PARSER_TOKEN_TYPE_U32:
  case PARSER_TOKEN_TYPE_I64:
  case PARSER_TOKEN_TYPE_U64:
  case PARSER_TOKEN_TYPE_F16:
  case PARSER_TOKEN_TYPE_F32:
  case PARSER_TOKEN_TYPE_F64:
  case PARSER_TOKEN_TYPE_F128:
  case PARSER_TOKEN_TYPE_BOOL:
    return true;
  case PARSER_TOKEN_IDENTIFIER:
  case PARSER_TOKEN_CONSTANT:
  case PARSER_TOKEN_VARIABLE:
  case PARSER_TOKEN_SYMBOL_PARENTHESIS:
  case PARSER_TOKEN_FUNCTION_DEFINITION:
  case PARSER_TOKEN_ROOT:
  case PARSER_TOKEN_SYMBOL_EOL:
  case PARSER_TOKEN_SYMBOL_CURLY_BRACKET:
  case PARSER_TOKEN_SYMBOL_COMMA:
  case PARSER_TOKEN_FUNCTION_CALL:
  case PARSER_TOKEN_VALUE_INT:
  case PARSER_TOKEN_VALUE_FLOAT:
  case PARSER_TOKEN_VALUE_BOOL:
  case PARSER_TOKEN_KEYWORD_PRINT_U64:
  case PARSER_TOKEN_KEYWORD_RETURN:
  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_OPERATOR_EQUAL:
  case PARSER_TOKEN_OPERATOR_NOT_EQUAL:
  case PARSER_TOKEN_OPERATOR_GREATER:
  case PARSER_TOKEN_OPERATOR_SMALLER:
  case PARSER_TOKEN_OPERATOR_GREATER_OR_EQUAL:
  case PARSER_TOKEN_OPERATOR_SMALLER_OR_EQUAL:
  case PARSER_TOKEN_KEYWORD_IF:
    return false;
  case PARSER_TOKEN_NONE:
  }
  UNREACHABLE;
}

bool isValue(ParserNode *node) {
  switch (node->token) {
  case PARSER_TOKEN_FUNCTION_DEFINITION:
  case PARSER_TOKEN_FUNCTION_CALL:
  case PARSER_TOKEN_VALUE_INT:
  case PARSER_TOKEN_VALUE_FLOAT:
  case PARSER_TOKEN_VALUE_BOOL:
  case PARSER_TOKEN_IDENTIFIER:
  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_OPERATOR_EQUAL:
  case PARSER_TOKEN_OPERATOR_NOT_EQUAL:
  case PARSER_TOKEN_OPERATOR_GREATER:
  case PARSER_TOKEN_OPERATOR_SMALLER:
  case PARSER_TOKEN_OPERATOR_GREATER_OR_EQUAL:
  case PARSER_TOKEN_OPERATOR_SMALLER_OR_EQUAL:
  case PARSER_TOKEN_TYPE_TYPE:
  case PARSER_TOKEN_TYPE_VOID:
  case PARSER_TOKEN_TYPE_BOOL:
  case PARSER_TOKEN_TYPE_I8:
  case PARSER_TOKEN_TYPE_U8:
  case PARSER_TOKEN_TYPE_I16:
  case PARSER_TOKEN_TYPE_U16:
  case PARSER_TOKEN_TYPE_I32:
  case PARSER_TOKEN_TYPE_U32:
  case PARSER_TOKEN_TYPE_I64:
  case PARSER_TOKEN_TYPE_U64:
  case PARSER_TOKEN_TYPE_F16:
  case PARSER_TOKEN_TYPE_F32:
  case PARSER_TOKEN_TYPE_F64:
  case PARSER_TOKEN_TYPE_F128:
  case PARSER_TOKEN_KEYWORD_IF:
    return true;
  case PARSER_TOKEN_TYPE_FUNCTION:
  case PARSER_TOKEN_CONSTANT:
  case PARSER_TOKEN_VARIABLE:
  case PARSER_TOKEN_SYMBOL_PARENTHESIS:
  case PARSER_TOKEN_ROOT:
  case PARSER_TOKEN_SYMBOL_EOL:
  case PARSER_TOKEN_SYMBOL_CURLY_BRACKET:
  case PARSER_TOKEN_SYMBOL_COMMA:
  case PARSER_TOKEN_KEYWORD_PRINT_U64:
  case PARSER_TOKEN_KEYWORD_RETURN:
    return false;
  case PARSER_TOKEN_NONE:
  }
  UNREACHABLE;
}