// File: AgathokakologicalBit[P]wit/src/parsing/lexing.cpp
// Function: akbit::system::parsing::get_next_token(akbit::system::parsing::LexerState&)
parsing::Token get_next_token(parsing::LexerState &state)
  {
    while (std::isspace(state.peek()))
      state.move();

    if (state.is_eof())
    {
      return parsing::Token{
        state.index, state.line, state.column,
        "##EOF##",
        TokenType::t_eof, TokenSubType::t_eof
      };
    }

    auto sub_type = get_character_type(state.peek());
    if (sub_type != TokenSubType::t_unknown)
    {
      state.move();

      // skipping comments
      if (sub_type == TokenSubType::t_slash && state.peek() == '/')
      {
        do state.move();
        while (state.peek() != '\n');

        // TODO: remove the recursion
        return get_next_token(state);
      }

      return parsing::Token{
        state.index - 1, state.line, state.column - 1,
        state.source.substr(state.index - 1, 1),
        TokenType::t_operator,
        sub_type
      };
    }

    if (state.peek() == '"')
    {
      std::uint32_t length = 1;
      do
      {
        state.move(), ++length;

        if (state.peek() == '\\')
          state.move(), ++length;
        
        if (state.peek() == '\0')
        {
          state.error.code = error_t::t_unexpected_eof;
          state.error.message = "String was not closed";
          break;
        }
      } while (state.peek() != '"');
      state.move();

      return parsing::Token{
        state.index - length, state.line, state.column - length,

        state.source.substr(state.index - length, length),

        TokenType::t_string,
        TokenSubType::t_string
      };
    }

    if (state.peek() == '\'')
    {
      state.move();
      std::uint32_t length = 1;

      if (std::isspace(state.peek()) || std::iscntrl(state.peek()))
      {
        state.error.code = error_t::t_misleading_character;
        state.error.message =
          "Character definition is misleading\n"
          "Whitespace symbols should be written using escape sequences:\n"
          "  \\s - space\n"
          "  \\t - tabulation\n"
          "  \\n - new line\n"
          "  \\r - carriage return";
      }

      if (state.peek() == '\\')
      {
        state.move(), ++length;
        switch(state.peek())
        {
          case 'r': case 'n': case 't': case 's': break;
          default:
          state.error.code = error_t::t_special_character_does_not_exist;
          state.error.message = std::string("Special character identifier '")
            + state.peek() + "' does not exists";
        }
      }

      state.move();

      return parsing::Token{
        state.index - length, state.line, state.column - length,

        state.source.substr(state.index - length, length),

        TokenType::t_character, TokenSubType::t_character,
      };
    }

    if ('0' <= state.peek() && state.peek() <= '9')
    {
      std::uint32_t length = 0;
      bool is_decimal = false;
      do state.move(), ++length;
      while (false
             || std::isdigit(state.peek())
             || (state.peek() == '.' && !is_decimal && (is_decimal = true)));

      return parsing::Token{
        state.index - length, state.line, state.column - length,

        state.source.substr(state.index - length, length),

        TokenType::t_number,
        (is_decimal
         ? TokenSubType::t_decimal
         : TokenSubType::t_integer)
      };
    }

    if (false
        || std::isalpha(state.peek())
        || state.peek() == '_' || state.peek() == '$')
    {
      std::uint32_t length = 0;
      do state.move(), ++length;
      while (false
             || std::isalnum(state.peek())
             || state.peek() == '_' || state.peek() == '$');

      return parsing::Token{
        state.index - length, state.line, state.column - length,
        state.source.substr(state.index - length, length),

        TokenType::t_identifier, TokenSubType::t_identifier
      };
    }

    auto ret = parsing::Token{
      state.index, state.line, state.column,
      state.source.substr(state.index, 1),

      TokenType::t_unknown, TokenSubType::t_unknown
    };

    state.move();
    return ret;
  }

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xe0, %rsp
movq %rdi, -0xb8(%rbp)
movq %rdi, %rax
movq %rax, -0xb0(%rbp)
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq -0x10(%rbp), %rdi
callq 0x119e0
movsbl %al, %edi
callq 0x4070
cmpl $0x0, %eax
je 0x11075
movq -0x10(%rbp), %rdi
callq 0x10e60
jmp 0x11054
movq -0x10(%rbp), %rdi
callq 0x11a10
testb $0x1, %al
jne 0x11087
jmp 0x1111e
movq -0xb8(%rbp), %rax
movq -0x10(%rbp), %rcx
movl (%rcx), %ecx
movl %ecx, (%rax)
movq -0x10(%rbp), %rcx
movl 0x4(%rcx), %ecx
movl %ecx, 0x4(%rax)
movq -0x10(%rbp), %rcx
movl 0x8(%rcx), %ecx
movl %ecx, 0x8(%rax)
addq $0x10, %rax
movq %rax, -0xc8(%rbp)
leaq -0x11(%rbp), %rdi
movq %rdi, -0xc0(%rbp)
callq 0x4570
movq -0xc8(%rbp), %rdi
movq -0xc0(%rbp), %rdx
leaq 0x2536c(%rip), %rsi     # 0x36446
callq 0x9e70
jmp 0x110e1
movq -0xb8(%rbp), %rax
movl $0x7, 0x30(%rax)
movl $0x22, 0x34(%rax)
leaq -0x11(%rbp), %rdi
callq 0x4370
jmp 0x11856
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x20(%rbp)
movl %eax, -0x24(%rbp)
leaq -0x11(%rbp), %rdi
callq 0x4370
jmp 0x11866
movq -0x10(%rbp), %rdi
callq 0x119e0
movsbl %al, %edi
callq 0x10ee0
movl %eax, -0x28(%rbp)
cmpl $0x0, -0x28(%rbp)
je 0x111f2
movq -0x10(%rbp), %rdi
callq 0x10e60
cmpl $0x15, -0x28(%rbp)
jne 0x1118d
movq -0x10(%rbp), %rdi
callq 0x119e0
movsbl %al, %eax
cmpl $0x2f, %eax
jne 0x1118d
jmp 0x1115e
movq -0x10(%rbp), %rdi
callq 0x10e60
movq -0x10(%rbp), %rdi
callq 0x119e0
movsbl %al, %eax
cmpl $0xa, %eax
jne 0x1115e
movq -0xb8(%rbp), %rdi
movq -0x10(%rbp), %rsi
callq 0x11030
jmp 0x11856
movq -0xb8(%rbp), %rdi
movq -0x10(%rbp), %rax
movl (%rax), %eax
subl $0x1, %eax
movl %eax, (%rdi)
movq -0x10(%rbp), %rax
movl 0x4(%rax), %eax
movl %eax, 0x4(%rdi)
movq -0x10(%rbp), %rax
movl 0x8(%rax), %eax
subl $0x1, %eax
movl %eax, 0x8(%rdi)
addq $0x10, %rdi
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rsi
movq -0x10(%rbp), %rax
movl (%rax), %eax
subl $0x1, %eax
movl %eax, %eax
movl %eax, %edx
movl $0x1, %ecx
callq 0x4320
movq -0xb8(%rbp), %rax
movl $0x6, 0x30(%rax)
movl -0x28(%rbp), %ecx
movl %ecx, 0x34(%rax)
jmp 0x11856
movq -0x10(%rbp), %rdi
callq 0x119e0
movsbl %al, %eax
cmpl $0x22, %eax
jne 0x112fb
movl $0x1, -0x2c(%rbp)
movq -0x10(%rbp), %rdi
callq 0x10e60
movl -0x2c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x2c(%rbp)
movq -0x10(%rbp), %rdi
callq 0x119e0
movsbl %al, %eax
cmpl $0x5c, %eax
jne 0x11243
movq -0x10(%rbp), %rdi
callq 0x10e60
movl -0x2c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x2c(%rbp)
movq -0x10(%rbp), %rdi
callq 0x119e0
movsbl %al, %eax
cmpl $0x0, %eax
jne 0x11279
movq -0x10(%rbp), %rax
movl $0x3f2, 0x18(%rax)      # imm = 0x3F2
movq -0x10(%rbp), %rdi
addq $0x18, %rdi
addq $0x8, %rdi
leaq 0x25522(%rip), %rsi     # 0x36794
callq 0x4440
jmp 0x1128c
jmp 0x1127b
movq -0x10(%rbp), %rdi
callq 0x119e0
movsbl %al, %eax
cmpl $0x22, %eax
jne 0x1120e
movq -0x10(%rbp), %rdi
callq 0x10e60
movq -0xb8(%rbp), %rdi
movq -0x10(%rbp), %rax
movl (%rax), %eax
subl -0x2c(%rbp), %eax
movl %eax, (%rdi)
movq -0x10(%rbp), %rax
movl 0x4(%rax), %eax
movl %eax, 0x4(%rdi)
movq -0x10(%rbp), %rax
movl 0x8(%rax), %eax
subl -0x2c(%rbp), %eax
movl %eax, 0x8(%rdi)
addq $0x10, %rdi
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rsi
movq -0x10(%rbp), %rax
movl (%rax), %eax
subl -0x2c(%rbp), %eax
movl %eax, %eax
movl %eax, %edx
movl -0x2c(%rbp), %eax
movl %eax, %ecx
callq 0x4320
movq -0xb8(%rbp), %rax
movl $0x4, 0x30(%rax)
movl $0x6, 0x34(%rax)
jmp 0x11856
movq -0x10(%rbp), %rdi
callq 0x119e0
movsbl %al, %eax
cmpl $0x27, %eax
jne 0x1153d
movq -0x10(%rbp), %rdi
callq 0x10e60
movl $0x1, -0x30(%rbp)
movq -0x10(%rbp), %rdi
callq 0x119e0
movsbl %al, %edi
callq 0x4070
cmpl $0x0, %eax
jne 0x1134c
movq -0x10(%rbp), %rdi
callq 0x119e0
movsbl %al, %edi
callq 0x4480
cmpl $0x0, %eax
je 0x1136f
movq -0x10(%rbp), %rax
movl $0x407, 0x18(%rax)      # imm = 0x407
movq -0x10(%rbp), %rdi
addq $0x18, %rdi
addq $0x8, %rdi
leaq 0x25440(%rip), %rsi     # 0x367aa
callq 0x4440
movq -0x10(%rbp), %rdi
callq 0x119e0
movsbl %al, %eax
cmpl $0x5c, %eax
jne 0x114ce
movq -0x10(%rbp), %rdi
callq 0x10e60
movl -0x30(%rbp), %eax
incl %eax
movl %eax, -0x30(%rbp)
movq -0x10(%rbp), %rdi
callq 0x119e0
movsbl %al, %eax
movl %eax, -0xcc(%rbp)
subl $0x6e, %eax
je 0x113be
jmp 0x113ae
movl -0xcc(%rbp), %eax
addl $-0x72, %eax
subl $0x2, %eax
ja 0x113c3
jmp 0x113be
jmp 0x1147e
movq -0x10(%rbp), %rax
movl $0x406, 0x18(%rax)      # imm = 0x406
leaq -0x91(%rbp), %rdi
movq %rdi, -0xd8(%rbp)
callq 0x4570
movq -0xd8(%rbp), %rdx
leaq 0x25461(%rip), %rsi     # 0x36850
leaq -0x90(%rbp), %rdi
callq 0x9e70
jmp 0x113fd
movq -0x10(%rbp), %rdi
callq 0x119e0
movb %al, -0xd9(%rbp)
jmp 0x1140e
movb -0xd9(%rbp), %al
movsbl %al, %edx
leaq -0x70(%rbp), %rdi
leaq -0x90(%rbp), %rsi
callq 0x11aa0
jmp 0x11429
leaq 0x2543f(%rip), %rdx     # 0x3686f
leaq -0x50(%rbp), %rdi
leaq -0x70(%rbp), %rsi
callq 0x11a50
jmp 0x1143f
movq -0x10(%rbp), %rdi
addq $0x18, %rdi
addq $0x8, %rdi
leaq -0x50(%rbp), %rsi
callq 0x43e0
leaq -0x50(%rbp), %rdi
callq 0x4210
leaq -0x70(%rbp), %rdi
callq 0x4210
leaq -0x90(%rbp), %rdi
callq 0x4210
leaq -0x91(%rbp), %rdi
callq 0x4370
jmp 0x114ce
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x20(%rbp)
movl %eax, -0x24(%rbp)
jmp 0x114bd
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x20(%rbp)
movl %eax, -0x24(%rbp)
jmp 0x114b1
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x20(%rbp)
movl %eax, -0x24(%rbp)
leaq -0x70(%rbp), %rdi
callq 0x4210
leaq -0x90(%rbp), %rdi
callq 0x4210
leaq -0x91(%rbp), %rdi
callq 0x4370
jmp 0x11866
movq -0x10(%rbp), %rdi
callq 0x10e60
movq -0xb8(%rbp), %rdi
movq -0x10(%rbp), %rax
movl (%rax), %eax
subl -0x30(%rbp), %eax
movl %eax, (%rdi)
movq -0x10(%rbp), %rax
movl 0x4(%rax), %eax
movl %eax, 0x4(%rdi)
movq -0x10(%rbp), %rax
movl 0x8(%rax), %eax
subl -0x30(%rbp), %eax
movl %eax, 0x8(%rdi)
addq $0x10, %rdi
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rsi
movq -0x10(%rbp), %rax
movl (%rax), %eax
subl -0x30(%rbp), %eax
movl %eax, %eax
movl %eax, %edx
movl -0x30(%rbp), %eax
movl %eax, %ecx
callq 0x4320
movq -0xb8(%rbp), %rax
movl $0x5, 0x30(%rax)
movl $0x7, 0x34(%rax)
jmp 0x11856
movq -0x10(%rbp), %rdi
callq 0x119e0
movsbl %al, %ecx
movl $0x30, %eax
cmpl %ecx, %eax
jg 0x1168d
movq -0x10(%rbp), %rdi
callq 0x119e0
movsbl %al, %eax
cmpl $0x39, %eax
jg 0x1168d
movl $0x0, -0x98(%rbp)
movb $0x0, -0x99(%rbp)
movq -0x10(%rbp), %rdi
callq 0x10e60
movl -0x98(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x98(%rbp)
movq -0x10(%rbp), %rdi
callq 0x119e0
movsbl %al, %edi
callq 0x42b0
movl %eax, %ecx
movb $0x1, %al
cmpl $0x0, %ecx
movb %al, -0xda(%rbp)
jne 0x115f9
movq -0x10(%rbp), %rdi
callq 0x119e0
movsbl %al, %ecx
xorl %eax, %eax
cmpl $0x2e, %ecx
movb %al, -0xdb(%rbp)
jne 0x115ed
xorl %eax, %eax
testb $0x1, -0x99(%rbp)
movb %al, -0xdb(%rbp)
jne 0x115ed
movb $0x1, -0x99(%rbp)
movb $0x1, %al
movb %al, -0xdb(%rbp)
movb -0xdb(%rbp), %al
movb %al, -0xda(%rbp)
movb -0xda(%rbp), %al
testb $0x1, %al
jne 0x1157c
movq -0xb8(%rbp), %rdi
movq -0x10(%rbp), %rax
movl (%rax), %eax
subl -0x98(%rbp), %eax
movl %eax, (%rdi)
movq -0x10(%rbp), %rax
movl 0x4(%rax), %eax
movl %eax, 0x4(%rdi)
movq -0x10(%rbp), %rax
movl 0x8(%rax), %eax
subl -0x98(%rbp), %eax
movl %eax, 0x8(%rdi)
addq $0x10, %rdi
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rsi
movq -0x10(%rbp), %rax
movl (%rax), %eax
subl -0x98(%rbp), %eax
movl %eax, %eax
movl %eax, %edx
movl -0x98(%rbp), %eax
movl %eax, %ecx
callq 0x4320
movq -0xb8(%rbp), %rax
movl $0x3, 0x30(%rax)
movb -0x99(%rbp), %sil
movl $0x4, %ecx
movl $0x5, %edx
testb $0x1, %sil
cmovnel %edx, %ecx
movl %ecx, 0x34(%rax)
jmp 0x11856
movq -0x10(%rbp), %rdi
callq 0x119e0
movsbl %al, %edi
callq 0x44f0
cmpl $0x0, %eax
jne 0x116c9
movq -0x10(%rbp), %rdi
callq 0x119e0
movsbl %al, %eax
cmpl $0x5f, %eax
je 0x116c9
movq -0x10(%rbp), %rdi
callq 0x119e0
movsbl %al, %eax
cmpl $0x24, %eax
jne 0x117b8
movl $0x0, -0xa0(%rbp)
movq -0x10(%rbp), %rdi
callq 0x10e60
movl -0xa0(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xa0(%rbp)
movq -0x10(%rbp), %rdi
callq 0x119e0
movsbl %al, %edi
callq 0x4310
movl %eax, %ecx
movb $0x1, %al
cmpl $0x0, %ecx
movb %al, -0xdc(%rbp)
jne 0x1173c
movq -0x10(%rbp), %rdi
callq 0x119e0
movsbl %al, %ecx
movb $0x1, %al
cmpl $0x5f, %ecx
movb %al, -0xdc(%rbp)
je 0x1173c
movq -0x10(%rbp), %rdi
callq 0x119e0
movsbl %al, %eax
cmpl $0x24, %eax
sete %al
movb %al, -0xdc(%rbp)
movb -0xdc(%rbp), %al
testb $0x1, %al
jne 0x116d3
movq -0xb8(%rbp), %rdi
movq -0x10(%rbp), %rax
movl (%rax), %eax
subl -0xa0(%rbp), %eax
movl %eax, (%rdi)
movq -0x10(%rbp), %rax
movl 0x4(%rax), %eax
movl %eax, 0x4(%rdi)
movq -0x10(%rbp), %rax
movl 0x8(%rax), %eax
subl -0xa0(%rbp), %eax
movl %eax, 0x8(%rdi)
addq $0x10, %rdi
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rsi
movq -0x10(%rbp), %rax
movl (%rax), %eax
subl -0xa0(%rbp), %eax
movl %eax, %eax
movl %eax, %edx
movl -0xa0(%rbp), %eax
movl %eax, %ecx
callq 0x4320
movq -0xb8(%rbp), %rax
movl $0x2, 0x30(%rax)
movl $0x3, 0x34(%rax)
jmp 0x11856
movq -0xb8(%rbp), %rdi
movb $0x0, -0xa1(%rbp)
movq -0x10(%rbp), %rax
movl (%rax), %eax
movl %eax, (%rdi)
movq -0x10(%rbp), %rax
movl 0x4(%rax), %eax
movl %eax, 0x4(%rdi)
movq -0x10(%rbp), %rax
movl 0x8(%rax), %eax
movl %eax, 0x8(%rdi)
addq $0x10, %rdi
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rsi
movl (%rax), %eax
movl %eax, %edx
movl $0x1, %ecx
callq 0x4320
movq -0xb8(%rbp), %rax
movl $0x0, 0x30(%rax)
movl $0x0, 0x34(%rax)
movq -0x10(%rbp), %rdi
callq 0x10e60
jmp 0x1181c
movb $0x1, -0xa1(%rbp)
testb $0x1, -0xa1(%rbp)
jne 0x11854
jmp 0x11848
movq -0xb8(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x20(%rbp)
movl %eax, -0x24(%rbp)
callq 0xec00
jmp 0x11866
movq -0xb8(%rbp), %rdi
callq 0xec00
jmp 0x11856
movq -0xb0(%rbp), %rax
addq $0xe0, %rsp
popq %rbp
retq
movq -0x20(%rbp), %rdi
callq 0x4560
nop