#pragma once

#include "utils/type.h"
#include <stddef.h>
#include <stdio.h>

typedef enum LexerToken {
  LEXER_TOKEN_SYMBOL_CLOSE_CURLY_BRACKET,
  LEXER_TOKEN_ORDER0 = LEXER_TOKEN_SYMBOL_CLOSE_CURLY_BRACKET,

  LEXER_TOKEN_SYMBOL_CLOSE_PARENTHESIS,
  LEXER_TOKEN_ORDER1 = LEXER_TOKEN_SYMBOL_CLOSE_PARENTHESIS,
  LEXER_TOKEN_SYMBOL_CLOSE_BRACKET,
  LEXER_TOKEN_IDENTIFIER,
  LEXER_TOKEN_BUILTIN,
  LEXER_TOKEN_BUILTIN_CAST,
  LEXER_TOKEN_BUILTIN_TYPE_OF,
  LEXER_TOKEN_BUILTIN_SIZE_OF,
  LEXER_TOKEN_BUILTIN_IMPORT,
  LEXER_TOKEN_BUILTIN_IS_COMPTIME,
  LEXER_TOKEN_BUILTIN_STACK_ALLOC,
  LEXER_TOKEN_BUILTIN_HEAP_ALLOC,
  LEXER_TOKEN_BUILTIN_NEG,
  LEXER_TOKEN_BUILTIN_ADD,
  LEXER_TOKEN_BUILTIN_SUB,
  LEXER_TOKEN_BUILTIN_MUL,
  LEXER_TOKEN_BUILTIN_DIV,
  LEXER_TOKEN_BUILTIN_MOD,
  LEXER_TOKEN_BUILTIN_EQUAL,
  LEXER_TOKEN_BUILTIN_NOT_EQUAL,
  LEXER_TOKEN_BUILTIN_GREATER,
  LEXER_TOKEN_BUILTIN_SMALLER,
  LEXER_TOKEN_BUILTIN_GREATER_OR_EQUAL,
  LEXER_TOKEN_BUILTIN_SMALLER_OR_EQUAL,
  LEXER_TOKEN_BUILTIN_PUTC,
  LEXER_TOKEN_BUILTIN_C_LIBRARY,
  LEXER_TOKEN_BUILTIN_C_FUNCTION,
  LEXER_TOKEN_BUILTIN_BITWISE_NOT,
  LEXER_TOKEN_BUILTIN_BITWISE_AND,
  LEXER_TOKEN_BUILTIN_BITWISE_XOR,
  LEXER_TOKEN_BUILTIN_BITWISE_OR,
  LEXER_TOKEN_BUILTIN_SHIFT_LEFT,
  LEXER_TOKEN_BUILTIN_SHIFT_RIGHT,
  LEXER_TOKEN_KEYWORD_TYPE,
  LEXER_TOKEN_KEYWORD_ANY_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,
#ifdef FLOAT_16_SUPPORT
  LEXER_TOKEN_KEYWORD_F16,
#endif
  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_KEYWORD_NULL,
  LEXER_TOKEN_KEYWORD_CODE,
  LEXER_TOKEN_KEYWORD_NAMESPACE,
  LEXER_TOKEN_KEYWORD_SHAPE_SHIFTER,
  LEXER_TOKEN_KEYWORD_C_LIBRARY,
  LEXER_TOKEN_KEYWORD_C_FUNCTION,
  LEXER_TOKEN_NUMBER,
  LEXER_TOKEN_CHAR,
  LEXER_TOKEN_STRING,
  LEXER_TOKEN_KEYWORD_UNDEFINED,

  LEXER_TOKEN_SYMBOL_FUNCTION_ARROW,
  LEXER_TOKEN_ORDER2 = LEXER_TOKEN_SYMBOL_FUNCTION_ARROW,
  LEXER_TOKEN_KEYWORD_STRUCT,
  LEXER_TOKEN_SYMBOL_CLOSE_BRACKET_LEFT,

  LEXER_TOKEN_SYMBOL_DEREFERENCE,
  LEXER_TOKEN_ORDER3 = LEXER_TOKEN_SYMBOL_DEREFERENCE,
  LEXER_TOKEN_SYMBOL_ACCESS,
  LEXER_TOKEN_SYMBOL_FUNCTION_CALL,

  LEXER_TOKEN_SYMBOL_PLUS,
  LEXER_TOKEN_ORDER4 = LEXER_TOKEN_SYMBOL_PLUS,
  LEXER_TOKEN_SYMBOL_POINTER,
  LEXER_TOKEN_SYMBOL_MINUS,
  LEXER_TOKEN_SYMBOL_ADDRESS,
  LEXER_TOKEN_SYMBOL_LOGICAL_NOT,
  LEXER_TOKEN_SYMBOL_BITWISE_NOT,

  LEXER_TOKEN_SYMBOL_MULTIPLY,
  LEXER_TOKEN_ORDER5 = LEXER_TOKEN_SYMBOL_MULTIPLY,
  LEXER_TOKEN_SYMBOL_DIVIDE,
  LEXER_TOKEN_SYMBOL_MODULO,

  LEXER_TOKEN_SYMBOL_SUM,
  LEXER_TOKEN_ORDER6 = LEXER_TOKEN_SYMBOL_SUM,
  LEXER_TOKEN_SYMBOL_SUB,

  LEXER_TOKEN_SYMBOL_LEFT_SHIFT,
  LEXER_TOKEN_ORDER7 = LEXER_TOKEN_SYMBOL_LEFT_SHIFT,
  LEXER_TOKEN_SYMBOL_RIGHT_SHIFT,

  LEXER_TOKEN_SYMBOL_EQUAL,
  LEXER_TOKEN_ORDER8 = 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,

  LEXER_TOKEN_SYMBOL_BITWISE_AND,
  LEXER_TOKEN_ORDER9 = LEXER_TOKEN_SYMBOL_BITWISE_AND,
  LEXER_TOKEN_SYMBOL_BITWISE_XOR,
  LEXER_TOKEN_SYMBOL_BITWISE_OR,

  LEXER_TOKEN_SYMBOL_LOGICAL_AND,
  LEXER_TOKEN_ORDER10 = LEXER_TOKEN_SYMBOL_LOGICAL_AND,
  LEXER_TOKEN_SYMBOL_LOGICAL_OR,

  LEXER_TOKEN_SYMBOL_COLON,
  LEXER_TOKEN_ORDER11 = LEXER_TOKEN_SYMBOL_COLON,

  LEXER_TOKEN_SYMBOL_ASSIGN,
  LEXER_TOKEN_ORDER12 = LEXER_TOKEN_SYMBOL_ASSIGN,
  LEXER_TOKEN_SYMBOL_SUM_ASSIGN,
  LEXER_TOKEN_SYMBOL_SUB_ASSIGN,
  LEXER_TOKEN_SYMBOL_MULTIPLY_ASSIGN,
  LEXER_TOKEN_SYMBOL_DIVIDE_ASSIGN,
  LEXER_TOKEN_SYMBOL_MODULO_ASSIGN,

  LEXER_TOKEN_KEYWORD_RETURN,
  LEXER_TOKEN_ORDER13 = LEXER_TOKEN_KEYWORD_RETURN,
  LEXER_TOKEN_KEYWORD_BREAK,
  LEXER_TOKEN_KEYWORD_CONTINUE,
  LEXER_TOKEN_KEYWORD_COMPTIME,

  LEXER_TOKEN_SYMBOL_EOL,
  LEXER_TOKEN_ORDER14 = LEXER_TOKEN_SYMBOL_EOL,
  LEXER_TOKEN_SYMBOL_COMMA,

  LEXER_TOKEN_KEYWORD_IF,
  LEXER_TOKEN_ORDER15 = LEXER_TOKEN_KEYWORD_IF,
  LEXER_TOKEN_KEYWORD_WHILE,

  LEXER_TOKEN_KEYWORD_ELSE,
  LEXER_TOKEN_END_ORDERS = LEXER_TOKEN_KEYWORD_ELSE,

  LEXER_TOKEN_SYMBOL,
  LEXER_TOKEN_SYMBOL_OPEN_PARENTHESIS,
  LEXER_TOKEN_SYMBOL_OPEN_BRACKET,
  LEXER_TOKEN_SYMBOL_OPEN_CURLY_BRACKET,
  LEXER_TOKEN_KEYWORD_LAZY,

  LEXER_TOKEN_NONE,
} LexerToken;

extern const char *LEXER_TOKEN_STRINGS[];

typedef struct LexerNode {
  char const *str_begin;
  char const *str_end;
  struct ParserNode *parserNode;
  LexerToken token;
} LexerNode;

typedef struct LexerNodeArray {
  LexerNode *data;
  size_t size;
} LexerNodeArray;

extern const LexerNodeArray LEXER_NODE_ARRAY_ERROR;

extern bool lexerNodeArrayIsError(LexerNodeArray array);
#ifdef PRINT_COMPILE_TREE
extern void lexerNodeArrayPrint(LexerNodeArray array);
#endif
extern void lexerNodeArrayDestroy(LexerNodeArray array);

extern LexerNodeArray lexer(const char *str);

extern void lexerPushClear(LexerNodeArray *array, size_t *array_size,
                           const char *iter, char const **node_str_begin,
                           LexerToken *node_token, LexerToken token);

extern bool isIdentifier(char c);
extern bool isNumber(char c);
extern bool isSymbol(char c);
extern bool isCompleteSymbol(const char *str, size_t str_size);
extern bool isSpace(char c);
extern bool isString(char c);