// File: cphinton42[P]hinton-language/src/check.cpp
// Function: typecheck_access(Context*, unsigned int, Expr_AST*, Access_AST*)
internal
bool typecheck_access(Context *ctx, u32 stage, Expr_AST *type, Access_AST *access_ast)
{
    u32 new_stage = 0;
    bool add_job = false;
    Expr_AST *lhs = access_ast->lhs;
    
    switch(stage)
    {
        case 0: {
            add_job = true;
        } // fall through
        case 1: {
            new_stage = 1;
            if(!type_resolved(lhs) && add_job)
            {
                auto job = make_typecheck_job(nullptr, lhs);
                do_typecheck_job(ctx, job);
            }
            if(!type_resolved(lhs))
            {
                break;
            }
            add_job = true;
        } // fall through
        case 2: {
            new_stage = 2;
            if((access_ast->lhs->flags & EXPR_FLAG_LVALUE_MASK) == 0)
            {
                break;
            }
            Expr_AST *lookup_type;
            Status status = reduce_type(ctx, lhs->resolved_type, &lookup_type);
            if(status != Status::good)
            {
                break;
            }
            bool pointer = false;
            if(lookup_type->type == AST_Type::unary_ast)
            {
                Unary_Operator_AST *unop_ast = static_cast<Unary_Operator_AST*>(lookup_type);
                assert(unop_ast->op == Unary_Operator::ref);
                pointer = true;
                status = reduce_type(ctx, unop_ast->operand, &lookup_type);
                if(status != Status::good)
                {
                    break;
                }
            }
            Expr_AST *expr;
            
            if(lookup_type->type == AST_Type::struct_ast)
            {
                Struct_AST *struct_ast = static_cast<Struct_AST*>(lookup_type);
                expr = scope_find(struct_ast->constant_scope, access_ast->atom, 0, false);
                if(!expr)
                {
                    expr = scope_find(struct_ast->field_scope, access_ast->atom, 0, false);
                }
            }
            else if(lookup_type->type == AST_Type::enum_ast && !pointer)
            {
                Enum_AST *enum_ast = static_cast<Enum_AST*>(lookup_type);
                expr = scope_find(enum_ast->scope, access_ast->atom, 0, false);
            }
            else
            {
                report_error("Expected enum, struct, or pointer to struct", lhs);
                ctx->success = false;
                break;
            }
            if(expr)
            {
                access_ast->expr = expr;
            }
            else
            {
                report_error("No such member or field", access_ast);
                ctx->success = false;
                break;
            }
            if(pointer)
            {
                access_ast->flags |= EXPR_FLAG_LVALUE;
            }
            else
            {
                access_ast->flags |= (access_ast->lhs->flags & EXPR_FLAG_LVALUE_MASK);
            }
            add_job = true;
        } // fall through
        case 3: {
            new_stage = 3;
            if(!type_resolved(access_ast->expr))
            {
                break;
            }
            set_resolved_type(access_ast, access_ast->expr->resolved_type);
            new_stage = 4;
        } // fall through
    }
    
    if(new_stage < 4)
    {
        auto job = make_typecheck_job(type, access_ast, new_stage);
        array_add(ctx->waiting_jobs, job);
    }
    return new_stage != stage;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x110, %rsp            # imm = 0x110
movq %rdi, -0x8(%rbp)
movl %esi, -0xc(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movl $0x0, -0x24(%rbp)
movb $0x0, -0x25(%rbp)
movq -0x20(%rbp), %rax
movq 0x20(%rax), %rax
movq %rax, -0x30(%rbp)
movl -0xc(%rbp), %eax
movq %rax, -0xf0(%rbp)
subq $0x3, %rax
ja 0x7166
movq -0xf0(%rbp), %rax
leaq 0x1222d(%rip), %rcx     # 0x190d0
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movb $0x1, -0x25(%rbp)
movl $0x1, -0x24(%rbp)
movq -0x30(%rbp), %rdi
callq 0x5600
testb $0x1, %al
jne 0x6f1b
testb $0x1, -0x25(%rbp)
je 0x6f1b
movq -0x30(%rbp), %rdx
leaq -0x48(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
xorl %ecx, %ecx
callq 0x4a80
movq -0x8(%rbp), %rdi
movq -0x48(%rbp), %rax
movq %rax, -0x60(%rbp)
movq -0x40(%rbp), %rax
movq %rax, -0x58(%rbp)
movq -0x38(%rbp), %rax
movq %rax, -0x50(%rbp)
leaq -0x60(%rbp), %rax
movq (%rax), %rcx
movq %rcx, (%rsp)
movq 0x8(%rax), %rcx
movq %rcx, 0x8(%rsp)
movq 0x10(%rax), %rax
movq %rax, 0x10(%rsp)
callq 0x4b40
movq -0x30(%rbp), %rdi
callq 0x5600
testb $0x1, %al
jne 0x6f2d
jmp 0x7166
movb $0x1, -0x25(%rbp)
movl $0x2, -0x24(%rbp)
movq -0x20(%rbp), %rax
movq 0x20(%rax), %rax
movzwl 0x2(%rax), %eax
andl $0x30, %eax
cmpl $0x0, %eax
jne 0x6f51
jmp 0x7166
movq -0x8(%rbp), %rdi
movq -0x30(%rbp), %rax
movq 0x18(%rax), %rsi
leaq -0x68(%rbp), %rdx
callq 0x9040
movl %eax, -0x6c(%rbp)
cmpl $0x0, -0x6c(%rbp)
je 0x6f74
jmp 0x7166
movb $0x0, -0x6d(%rbp)
movq -0x68(%rbp), %rax
cmpw $0x10, (%rax)
jne 0x6fdf
movq -0x68(%rbp), %rax
movq %rax, -0x78(%rbp)
movq -0x78(%rbp), %rax
cmpq $0x3, 0x20(%rax)
jne 0x6f97
jmp 0x6fb6
leaq 0x13055(%rip), %rdi     # 0x19ff3
leaq 0x12f47(%rip), %rsi     # 0x19eec
movl $0x2c3, %edx            # imm = 0x2C3
leaq 0x13a02(%rip), %rcx     # 0x1a9b3
callq 0x3080
movb $0x1, -0x6d(%rbp)
movq -0x8(%rbp), %rdi
movq -0x78(%rbp), %rax
movq 0x28(%rax), %rsi
leaq -0x68(%rbp), %rdx
callq 0x9040
movl %eax, -0x6c(%rbp)
cmpl $0x0, -0x6c(%rbp)
je 0x6fdd
jmp 0x7166
jmp 0x6fdf
movq -0x68(%rbp), %rax
cmpw $0xf, (%rax)
jne 0x705d
movq -0x68(%rbp), %rax
movq %rax, -0x88(%rbp)
movq -0x88(%rbp), %rax
movq 0x40(%rax), %rdi
movq -0x20(%rbp), %rax
movq 0x28(%rax), %rax
movq %rax, -0x90(%rbp)
movq -0x90(%rbp), %rsi
xorl %eax, %eax
movl %eax, %edx
xorl %ecx, %ecx
callq 0xd4d0
movq %rax, -0x80(%rbp)
cmpq $0x0, -0x80(%rbp)
jne 0x705b
movq -0x88(%rbp), %rax
movq 0x48(%rax), %rdi
movq -0x20(%rbp), %rax
movq 0x28(%rax), %rax
movq %rax, -0x98(%rbp)
movq -0x98(%rbp), %rsi
xorl %eax, %eax
movl %eax, %edx
xorl %ecx, %ecx
callq 0xd4d0
movq %rax, -0x80(%rbp)
jmp 0x70c9
movq -0x68(%rbp), %rax
cmpw $0xe, (%rax)
jne 0x70aa
testb $0x1, -0x6d(%rbp)
jne 0x70aa
movq -0x68(%rbp), %rax
movq %rax, -0xa0(%rbp)
movq -0xa0(%rbp), %rax
movq 0x30(%rax), %rdi
movq -0x20(%rbp), %rax
movq 0x28(%rax), %rax
movq %rax, -0xa8(%rbp)
movq -0xa8(%rbp), %rsi
xorl %eax, %eax
movl %eax, %edx
xorl %ecx, %ecx
callq 0xd4d0
movq %rax, -0x80(%rbp)
jmp 0x70c7
movq -0x30(%rbp), %rsi
leaq 0x1393e(%rip), %rdi     # 0x1a9f3
callq 0x4950
movq -0x8(%rbp), %rax
movb $0x0, 0x10(%rax)
jmp 0x7166
jmp 0x70c9
cmpq $0x0, -0x80(%rbp)
je 0x70de
movq -0x80(%rbp), %rcx
movq -0x20(%rbp), %rax
movq %rcx, 0x30(%rax)
jmp 0x70f8
movq -0x20(%rbp), %rsi
leaq 0x13936(%rip), %rdi     # 0x1aa1f
callq 0x4950
movq -0x8(%rbp), %rax
movb $0x0, 0x10(%rax)
jmp 0x7166
testb $0x1, -0x6d(%rbp)
je 0x710f
movq -0x20(%rbp), %rax
movzwl 0x2(%rax), %ecx
orl $0x10, %ecx
movw %cx, 0x2(%rax)
jmp 0x712c
movq -0x20(%rbp), %rax
movq 0x20(%rax), %rax
movzwl 0x2(%rax), %edx
andl $0x30, %edx
movq -0x20(%rbp), %rax
movzwl 0x2(%rax), %ecx
orl %edx, %ecx
movw %cx, 0x2(%rax)
movb $0x1, -0x25(%rbp)
movl $0x3, -0x24(%rbp)
movq -0x20(%rbp), %rax
movq 0x30(%rax), %rdi
callq 0x5600
testb $0x1, %al
jne 0x714a
jmp 0x7166
movq -0x20(%rbp), %rdi
movq -0x20(%rbp), %rax
movq 0x30(%rax), %rax
movq 0x18(%rax), %rsi
callq 0x3be0
movl $0x4, -0x24(%rbp)
cmpl $0x4, -0x24(%rbp)
jae 0x7208
movq -0x18(%rbp), %rsi
movq -0x20(%rbp), %rdx
movl -0x24(%rbp), %ecx
leaq -0xc0(%rbp), %rdi
callq 0x4a80
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rdi
movq -0xc0(%rbp), %rax
movq %rax, -0xd8(%rbp)
movq -0xb8(%rbp), %rax
movq %rax, -0xd0(%rbp)
movq -0xb0(%rbp), %rax
movq %rax, -0xc8(%rbp)
movq 0x18ac0(%rip), %rax     # 0x1fc80
movq %rax, -0xe8(%rbp)
movq 0x18aba(%rip), %rax     # 0x1fc88
movq %rax, -0xe0(%rbp)
movq -0xe8(%rbp), %rsi
movq -0xe0(%rbp), %rdx
leaq -0xd8(%rbp), %rax
movq (%rax), %rcx
movq %rcx, (%rsp)
movq 0x8(%rax), %rcx
movq %rcx, 0x8(%rsp)
movq 0x10(%rax), %rax
movq %rax, 0x10(%rsp)
callq 0x17c30
movl -0x24(%rbp), %eax
cmpl -0xc(%rbp), %eax
setne %al
andb $0x1, %al
addq $0x110, %rsp            # imm = 0x110
popq %rbp
retq
nopl (%rax)