// File: cphinton42[P]hinton-language/src/parse.cpp
// Function: parse_expr(Parsing_Context*, Token**, unsigned int)
internal Expr_AST* parse_expr(Parsing_Context *ctx, Token **current_ptr, u32 precedence = 7)
{
    Token *current = *current_ptr;
    Token *start_section = current;
    defer {
        *current_ptr = current;
    };
    
    Expr_AST *lhs = parse_base_expr(ctx, &current, precedence);
    if(!lhs)
    {
        return nullptr;
    }
    
    while(true)
    {
        Binary_Operator op;
        bool found_op;
        u32 rhs_precedence;
        
        switch(precedence)
        {
            case 7:
            if(current->type == Token_Type::lor)
            {
                op = Binary_Operator::lor;
                found_op = true;
                rhs_precedence = 6;
                break;
            }
            case 6:
            if(current->type == Token_Type::land)
            {
                op = Binary_Operator::land;
                found_op = true;
                rhs_precedence = 5;
                break;
            }
            case 5:
            if(current->type == Token_Type::double_equal)
            {
                op = Binary_Operator::cmp_eq;
                found_op = true;
                rhs_precedence = 4;
                break;
            }
            if(current->type == Token_Type::not_equal)
            {
                op = Binary_Operator::cmp_neq;
                found_op = true;
                rhs_precedence = 4;
                break;
            }
            case 4:
            if(current->type == Token_Type::lt)
            {
                op = Binary_Operator::cmp_lt;
                found_op = true;
                rhs_precedence = 3;
                break;
            }
            if(current->type == Token_Type::le)
            {
                op = Binary_Operator::cmp_le;
                found_op = true;
                rhs_precedence = 3;
                break;
            }
            if(current->type == Token_Type::gt)
            {
                op = Binary_Operator::cmp_gt;
                found_op = true;
                rhs_precedence = 3;
                break;
            }
            if(current->type == Token_Type::ge)
            {
                op = Binary_Operator::cmp_ge;
                found_op = true;
                rhs_precedence = 3;
                break;
            }
            case 3:
            if(current->type == Token_Type::add)
            {
                op = Binary_Operator::add;
                found_op = true;
                rhs_precedence = 2;
                break;
            }
            if(current->type == Token_Type::sub)
            {
                op = Binary_Operator::sub;
                found_op = true;
                rhs_precedence = 2;
                break;
            }
            case 2:
            if(current->type == Token_Type::mul)
            {
                op = Binary_Operator::mul;
                found_op = true;
                rhs_precedence = 1;
                break;
            }
            if(current->type == Token_Type::div)
            {
                op = Binary_Operator::div;
                found_op = true;
                rhs_precedence = 1;
                break;
            }
            case 1:
            if(current->type == Token_Type::open_paren)
            {
                ++current;
                
                Dynamic_Array<Expr_AST*> args = {0};
                
                if(current->type != Token_Type::eof && current->type != Token_Type::close_paren)
                {
                    Expr_AST *first_expr = parse_expr(ctx, &current);
                    if(!first_expr)
                    {
                        return nullptr;
                    }
                    array_add(&args, first_expr);
                }
                
                while(current->type != Token_Type::eof && current->type != Token_Type::close_paren)
                {
                    if(current->type != Token_Type::comma)
                    {
                        report_error(ctx, start_section, current, "Expected ','");
                        return nullptr;
                    }
                    ++current;
                    
                    Expr_AST *expr = parse_expr(ctx, &current);
                    if(!expr)
                    {
                        return nullptr;
                    }
                    array_add(&args, expr);
                }
                if(current->type != Token_Type::close_paren)
                {
                    report_error(ctx, start_section, current, "Expected ')'");
                    return nullptr;
                }
                ++current;
                
                Function_Call_AST *call_ast = construct_ast(ctx->ast_pool, Function_Call_AST, lhs->line_number, lhs->line_offset);
                call_ast->types_count = 0;
                call_ast->resolved_type = nullptr;
                call_ast->function = lhs;
                call_ast->args.count = args.count;
                call_ast->args.data = pool_alloc(Expr_AST*, args.count, ctx->ast_pool);
                
                for(u64 i = 0; i < args.count; ++i)
                {
                    call_ast->args[i] = args[i];
                }
                
                // TODO memory leak
                lhs = call_ast;
                
                continue;
            }
            if(current->type == Token_Type::open_sqr)
            {
                op = Binary_Operator::subscript;
                
                ++current;
                Expr_AST *rhs = parse_expr(ctx, &current);
                if(rhs)
                {
                    if(current->type == Token_Type::close_sqr)
                    {
                        ++current;
                        
                        Binary_Operator_AST *result = construct_ast(ctx->ast_pool, Binary_Operator_AST, lhs->line_number, lhs->line_offset);
                        result->types_count = 0;
                        result->resolved_type = nullptr;
                        result->op = op;
                        result->lhs = lhs;
                        result->rhs = rhs;
                        
                        lhs = result;
                        
                        continue;
                    }
                    else
                    {
                        report_error(ctx, start_section, current, "Expected ']'");
                        return nullptr;
                    }
                }
                else
                {
                    return nullptr;
                }
                
                break;
            }
            if(current->type == Token_Type::dot)
            {
                ++current;
                if(current->type == Token_Type::ident)
                {
                    Access_AST *result = construct_ast(ctx->ast_pool, Access_AST, lhs->line_number, lhs->line_offset);
                    result->types_count = 0;
                    result->resolved_type = nullptr;
                    result->lhs = lhs;
                    result->ident = current->contents;
                    ++current;
                    
                    lhs = result;
                    
                    continue;
                }
                else
                {
                    report_error(ctx, start_section, current, "Expected identifier");
                    return nullptr;
                }
                
                break;
            }
            case 0:
            found_op = false;
            break;
            default: {
                assert(false);
            } break;
        }
        
        if(found_op)
        {
            ++current;
            Expr_AST *rhs = parse_expr(ctx, &current, rhs_precedence);
            if(rhs)
            {
                Binary_Operator_AST *result = construct_ast(ctx->ast_pool, Binary_Operator_AST, lhs->line_number, lhs->line_offset);
                result->types_count = 0;
                result->resolved_type = nullptr;
                result->op = op;
                result->lhs = lhs;
                result->rhs = rhs;
                
                lhs = result;
            }
            else
            {
                return nullptr;
            }
        }
        else
        {
            return lhs;
        }
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x190, %rsp            # imm = 0x190
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movl %edx, -0x1c(%rbp)
movq -0x18(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x28(%rbp)
movq -0x28(%rbp), %rax
movq %rax, -0x30(%rbp)
leaq -0x18(%rbp), %rax
movq %rax, -0x50(%rbp)
leaq -0x28(%rbp), %rax
movq %rax, -0x118(%rbp)
movq %rax, -0x48(%rbp)
leaq -0x40(%rbp), %rdi
xorl %esi, %esi
leaq -0x50(%rbp), %rdx
callq 0x12de0
movq -0x118(%rbp), %rsi
movq -0x10(%rbp), %rdi
movl -0x1c(%rbp), %edx
callq 0x12e10
movq %rax, -0x110(%rbp)
jmp 0x123fb
movq -0x110(%rbp), %rax
movq %rax, -0x58(%rbp)
cmpq $0x0, -0x58(%rbp)
jne 0x1243b
movq $0x0, -0x8(%rbp)
movl $0x1, -0x68(%rbp)
jmp 0x12ceb
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x60(%rbp)
movl %eax, -0x64(%rbp)
leaq -0x40(%rbp), %rdi
callq 0x14800
jmp 0x12d01
jmp 0x1243d
jmp 0x1243f
movl -0x1c(%rbp), %eax
movq %rax, -0x120(%rbp)
subq $0x7, %rax
ja 0x12bb8
movq -0x120(%rbp), %rax
leaq 0x72f7(%rip), %rcx      # 0x19758
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq -0x28(%rbp), %rax
cmpq $0x35, (%rax)
jne 0x1248c
movq $0xb, -0x70(%rbp)
movb $0x1, -0x71(%rbp)
movl $0x6, -0x78(%rbp)
jmp 0x12bd7
jmp 0x1248e
movq -0x28(%rbp), %rax
cmpq $0x37, (%rax)
jne 0x124b0
movq $0xc, -0x70(%rbp)
movb $0x1, -0x71(%rbp)
movl $0x5, -0x78(%rbp)
jmp 0x12bd7
jmp 0x124b2
movq -0x28(%rbp), %rax
cmpq $0x3c, (%rax)
jne 0x124d4
movq $0x0, -0x70(%rbp)
movb $0x1, -0x71(%rbp)
movl $0x4, -0x78(%rbp)
jmp 0x12bd7
movq -0x28(%rbp), %rax
cmpq $0x3a, (%rax)
jne 0x124f6
movq $0x1, -0x70(%rbp)
movb $0x1, -0x71(%rbp)
movl $0x4, -0x78(%rbp)
jmp 0x12bd7
jmp 0x124f8
movq -0x28(%rbp), %rax
cmpq $0x2e, (%rax)
jne 0x1251a
movq $0x2, -0x70(%rbp)
movb $0x1, -0x71(%rbp)
movl $0x3, -0x78(%rbp)
jmp 0x12bd7
movq -0x28(%rbp), %rax
cmpq $0x2f, (%rax)
jne 0x1253c
movq $0x3, -0x70(%rbp)
movb $0x1, -0x71(%rbp)
movl $0x3, -0x78(%rbp)
jmp 0x12bd7
movq -0x28(%rbp), %rax
cmpq $0x30, (%rax)
jne 0x1255e
movq $0x4, -0x70(%rbp)
movb $0x1, -0x71(%rbp)
movl $0x3, -0x78(%rbp)
jmp 0x12bd7
movq -0x28(%rbp), %rax
cmpq $0x31, (%rax)
jne 0x12580
movq $0x5, -0x70(%rbp)
movb $0x1, -0x71(%rbp)
movl $0x3, -0x78(%rbp)
jmp 0x12bd7
jmp 0x12582
movq -0x28(%rbp), %rax
cmpq $0x33, (%rax)
jne 0x125a4
movq $0x6, -0x70(%rbp)
movb $0x1, -0x71(%rbp)
movl $0x2, -0x78(%rbp)
jmp 0x12bd7
movq -0x28(%rbp), %rax
cmpq $0x34, (%rax)
jne 0x125c6
movq $0x7, -0x70(%rbp)
movb $0x1, -0x71(%rbp)
movl $0x2, -0x78(%rbp)
jmp 0x12bd7
jmp 0x125c8
movq -0x28(%rbp), %rax
cmpq $0x32, (%rax)
jne 0x125ea
movq $0x8, -0x70(%rbp)
movb $0x1, -0x71(%rbp)
movl $0x1, -0x78(%rbp)
jmp 0x12bd7
movq -0x28(%rbp), %rax
cmpq $0x38, (%rax)
jne 0x1260c
movq $0x9, -0x70(%rbp)
movb $0x1, -0x71(%rbp)
movl $0x1, -0x78(%rbp)
jmp 0x12bd7
jmp 0x1260e
movq -0x28(%rbp), %rax
cmpq $0x28, (%rax)
jne 0x12959
movq -0x28(%rbp), %rax
addq $0x20, %rax
movq %rax, -0x28(%rbp)
leaq -0x90(%rbp), %rdi
xorl %esi, %esi
movl $0x18, %edx
callq 0x3060
movq -0x28(%rbp), %rax
cmpq $0x41, (%rax)
je 0x126cd
movq -0x28(%rbp), %rax
cmpq $0x29, (%rax)
je 0x126cd
movq -0x10(%rbp), %rdi
leaq -0x28(%rbp), %rsi
movl $0x7, %edx
callq 0x12390
movq %rax, -0x128(%rbp)
jmp 0x1266e
movq -0x128(%rbp), %rax
movq %rax, -0x98(%rbp)
cmpq $0x0, -0x98(%rbp)
jne 0x1269a
movq $0x0, -0x8(%rbp)
movl $0x1, -0x68(%rbp)
jmp 0x12ceb
movq -0x98(%rbp), %rsi
movups 0xd5d8(%rip), %xmm0     # 0x1fc80
movaps %xmm0, -0xb0(%rbp)
movq -0xb0(%rbp), %rdx
movq -0xa8(%rbp), %rcx
leaq -0x90(%rbp), %rdi
callq 0x17f20
jmp 0x126cb
jmp 0x126cd
jmp 0x126cf
movq -0x28(%rbp), %rcx
xorl %eax, %eax
cmpq $0x41, (%rcx)
movb %al, -0x129(%rbp)
je 0x126f2
movq -0x28(%rbp), %rax
cmpq $0x29, (%rax)
setne %al
movb %al, -0x129(%rbp)
movb -0x129(%rbp), %al
testb $0x1, %al
jne 0x12701
jmp 0x127c2
movq -0x28(%rbp), %rax
cmpq $0x20, (%rax)
je 0x12739
movq -0x10(%rbp), %rdi
movq -0x30(%rbp), %rsi
movq -0x28(%rbp), %rdx
leaq 0x8740(%rip), %rcx      # 0x1ae5e
callq 0xc650
jmp 0x12725
movq $0x0, -0x8(%rbp)
movl $0x1, -0x68(%rbp)
jmp 0x12ceb
movq -0x28(%rbp), %rax
addq $0x20, %rax
movq %rax, -0x28(%rbp)
movq -0x10(%rbp), %rdi
leaq -0x28(%rbp), %rsi
movl $0x7, %edx
callq 0x12390
movq %rax, -0x138(%rbp)
jmp 0x12760
movq -0x138(%rbp), %rax
movq %rax, -0xb8(%rbp)
cmpq $0x0, -0xb8(%rbp)
jne 0x1278c
movq $0x0, -0x8(%rbp)
movl $0x1, -0x68(%rbp)
jmp 0x12ceb
movq -0xb8(%rbp), %rsi
movups 0xd4e6(%rip), %xmm0     # 0x1fc80
movaps %xmm0, -0xd0(%rbp)
movq -0xd0(%rbp), %rdx
movq -0xc8(%rbp), %rcx
leaq -0x90(%rbp), %rdi
callq 0x17f20
jmp 0x127bd
jmp 0x126cf
movq -0x28(%rbp), %rax
cmpq $0x29, (%rax)
je 0x127fa
movq -0x10(%rbp), %rdi
movq -0x30(%rbp), %rsi
movq -0x28(%rbp), %rdx
leaq 0x868c(%rip), %rcx      # 0x1ae6b
callq 0xc650
jmp 0x127e6
movq $0x0, -0x8(%rbp)
movl $0x1, -0x68(%rbp)
jmp 0x12ceb
movq -0x28(%rbp), %rax
addq $0x20, %rax
movq %rax, -0x28(%rbp)
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rdi
movl $0x38, %esi
callq 0xcd80
movq %rax, -0x140(%rbp)
jmp 0x12821
movq -0x140(%rbp), %rdi
movq -0x58(%rbp), %rax
movl 0x8(%rax), %ecx
movl 0xc(%rax), %eax
movl %ecx, %edx
movl %eax, %ecx
movl $0xa, %esi
callq 0x3c10
movq %rax, -0xd8(%rbp)
movq -0xd8(%rbp), %rax
movq $0x0, 0x10(%rax)
movq -0xd8(%rbp), %rax
movq $0x0, 0x18(%rax)
movq -0x58(%rbp), %rcx
movq -0xd8(%rbp), %rax
movq %rcx, 0x20(%rax)
movq -0x90(%rbp), %rcx
movq -0xd8(%rbp), %rax
movq %rcx, 0x28(%rax)
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rdi
movq -0x90(%rbp), %rsi
shlq $0x3, %rsi
callq 0xcd80
movq %rax, -0x148(%rbp)
jmp 0x128a7
movq -0x148(%rbp), %rcx
movq -0xd8(%rbp), %rax
movq %rcx, 0x30(%rax)
movq $0x0, -0xe0(%rbp)
movq -0xe0(%rbp), %rax
cmpq -0x90(%rbp), %rax
jae 0x12949
movq -0xe0(%rbp), %rsi
leaq -0x90(%rbp), %rdi
callq 0x17fc0
movq %rax, -0x150(%rbp)
jmp 0x128f0
movq -0x150(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x160(%rbp)
movq -0xd8(%rbp), %rdi
addq $0x28, %rdi
movq -0xe0(%rbp), %rsi
callq 0x17050
movq %rax, -0x158(%rbp)
jmp 0x12921
movq -0x158(%rbp), %rax
movq -0x160(%rbp), %rcx
movq %rcx, (%rax)
movq -0xe0(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xe0(%rbp)
jmp 0x128c4
movq -0xd8(%rbp), %rax
movq %rax, -0x58(%rbp)
jmp 0x1243d
movq -0x28(%rbp), %rax
cmpq $0x2a, (%rax)
jne 0x12ab1
movq $0xa, -0x70(%rbp)
movq -0x28(%rbp), %rax
addq $0x20, %rax
movq %rax, -0x28(%rbp)
movq -0x10(%rbp), %rdi
leaq -0x28(%rbp), %rsi
movl $0x7, %edx
callq 0x12390
movq %rax, -0x168(%rbp)
jmp 0x12996
movq -0x168(%rbp), %rax
movq %rax, -0xe8(%rbp)
cmpq $0x0, -0xe8(%rbp)
je 0x12a9d
movq -0x28(%rbp), %rax
cmpq $0x2b, (%rax)
jne 0x12a6f
movq -0x28(%rbp), %rax
addq $0x20, %rax
movq %rax, -0x28(%rbp)
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rdi
movl $0x38, %esi
callq 0xcd80
movq %rax, -0x170(%rbp)
jmp 0x129e7
movq -0x170(%rbp), %rdi
movq -0x58(%rbp), %rax
movl 0x8(%rax), %eax
movl %eax, %edx
movq -0x58(%rbp), %rax
movl 0xc(%rax), %eax
movl %eax, %ecx
movl $0xc, %esi
callq 0x3c10
movq %rax, -0xf0(%rbp)
movq -0xf0(%rbp), %rax
movq $0x0, 0x10(%rax)
movq -0xf0(%rbp), %rax
movq $0x0, 0x18(%rax)
movq -0x70(%rbp), %rcx
movq -0xf0(%rbp), %rax
movq %rcx, 0x20(%rax)
movq -0x58(%rbp), %rcx
movq -0xf0(%rbp), %rax
movq %rcx, 0x28(%rax)
movq -0xe8(%rbp), %rcx
movq -0xf0(%rbp), %rax
movq %rcx, 0x30(%rax)
movq -0xf0(%rbp), %rax
movq %rax, -0x58(%rbp)
jmp 0x1243d
movq -0x10(%rbp), %rdi
movq -0x30(%rbp), %rsi
movq -0x28(%rbp), %rdx
leaq 0x83f6(%rip), %rcx      # 0x1ae78
callq 0xc650
jmp 0x12a89
movq $0x0, -0x8(%rbp)
movl $0x1, -0x68(%rbp)
jmp 0x12ceb
movq $0x0, -0x8(%rbp)
movl $0x1, -0x68(%rbp)
jmp 0x12ceb
movq -0x28(%rbp), %rax
cmpq $0x25, (%rax)
jne 0x12bb0
movq -0x28(%rbp), %rax
addq $0x20, %rax
movq %rax, -0x28(%rbp)
movq -0x28(%rbp), %rax
cmpq $0x0, (%rax)
jne 0x12b82
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rdi
movl $0x38, %esi
callq 0xcd80
movq %rax, -0x178(%rbp)
jmp 0x12af4
movq -0x178(%rbp), %rdi
movq -0x58(%rbp), %rax
movl 0x8(%rax), %eax
movl %eax, %edx
movq -0x58(%rbp), %rax
movl 0xc(%rax), %eax
movl %eax, %ecx
movl $0xb, %esi
callq 0x3c10
movq %rax, -0xf8(%rbp)
movq -0xf8(%rbp), %rax
movq $0x0, 0x10(%rax)
movq -0xf8(%rbp), %rax
movq $0x0, 0x18(%rax)
movq -0x58(%rbp), %rcx
movq -0xf8(%rbp), %rax
movq %rcx, 0x20(%rax)
movq -0x28(%rbp), %rcx
movq -0xf8(%rbp), %rax
movq 0x10(%rcx), %rdx
movq %rdx, 0x28(%rax)
movq 0x18(%rcx), %rcx
movq %rcx, 0x30(%rax)
movq -0x28(%rbp), %rax
addq $0x20, %rax
movq %rax, -0x28(%rbp)
movq -0xf8(%rbp), %rax
movq %rax, -0x58(%rbp)
jmp 0x1243d
movq -0x10(%rbp), %rdi
movq -0x30(%rbp), %rsi
movq -0x28(%rbp), %rdx
leaq 0x82f0(%rip), %rcx      # 0x1ae85
callq 0xc650
jmp 0x12b9c
movq $0x0, -0x8(%rbp)
movl $0x1, -0x68(%rbp)
jmp 0x12ceb
jmp 0x12bb2
movb $0x0, -0x71(%rbp)
jmp 0x12bd7
leaq 0x7263(%rip), %rdi      # 0x19e22
leaq 0x82d3(%rip), %rsi      # 0x1ae99
movl $0x1b9, %edx            # imm = 0x1B9
leaq 0x82d5(%rip), %rcx      # 0x1aea7
callq 0x3080
testb $0x1, -0x71(%rbp)
je 0x12cd5
movq -0x28(%rbp), %rax
addq $0x20, %rax
movq %rax, -0x28(%rbp)
movq -0x10(%rbp), %rdi
movl -0x78(%rbp), %edx
leaq -0x28(%rbp), %rsi
callq 0x12390
movq %rax, -0x180(%rbp)
jmp 0x12c06
movq -0x180(%rbp), %rax
movq %rax, -0x100(%rbp)
cmpq $0x0, -0x100(%rbp)
je 0x12cc2
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rdi
movl $0x38, %esi
callq 0xcd80
movq %rax, -0x188(%rbp)
jmp 0x12c3d
movq -0x188(%rbp), %rdi
movq -0x58(%rbp), %rax
movl 0x8(%rax), %eax
movl %eax, %edx
movq -0x58(%rbp), %rax
movl 0xc(%rax), %eax
movl %eax, %ecx
movl $0xc, %esi
callq 0x3c10
movq %rax, -0x108(%rbp)
movq -0x108(%rbp), %rax
movq $0x0, 0x10(%rax)
movq -0x108(%rbp), %rax
movq $0x0, 0x18(%rax)
movq -0x70(%rbp), %rcx
movq -0x108(%rbp), %rax
movq %rcx, 0x20(%rax)
movq -0x58(%rbp), %rcx
movq -0x108(%rbp), %rax
movq %rcx, 0x28(%rax)
movq -0x100(%rbp), %rcx
movq -0x108(%rbp), %rax
movq %rcx, 0x30(%rax)
movq -0x108(%rbp), %rax
movq %rax, -0x58(%rbp)
jmp 0x12cd3
movq $0x0, -0x8(%rbp)
movl $0x1, -0x68(%rbp)
jmp 0x12ceb
jmp 0x12ce6
movq -0x58(%rbp), %rax
movq %rax, -0x8(%rbp)
movl $0x1, -0x68(%rbp)
jmp 0x12ceb
jmp 0x1243d
leaq -0x40(%rbp), %rdi
callq 0x14800
movq -0x8(%rbp), %rax
addq $0x190, %rsp            # imm = 0x190
popq %rbp
retq
movq -0x60(%rbp), %rdi
callq 0x3100
nopw (%rax,%rax)