// File: cphinton42[P]hinton-language/src/check.cpp
// Function: typecheck_number(Context*, Expr_AST*, Number_AST*)
internal
bool typecheck_number(Context *ctx, Expr_AST *type, Number_AST *number_ast)
{
    number_ast->flags |= EXPR_FLAG_NOT_LVALUE;
    bool number_float_like = (number_ast->flags & NUMBER_FLAG_FLOATLIKE);
    Primitive_AST *number_type;
    if(type)
    {
        Expr_AST *reduced;
        Status status = reduce_type(ctx, type, &reduced);
        if(status != Status::good)
        {
            goto finish;
        }
        if(reduced->type != AST_Type::primitive_ast)
        {
            report_error("Expected primitive type", type);
            ctx->success = false;
            goto finish;
        }
        number_type = static_cast<Primitive_AST*>(reduced);
        u64 prim = number_type->primitive;
        if(!(prim & PRIM_NUMBERLIKE))
        {
            report_error("Expected number type", type);
            ctx->success = false;
            goto finish;
        }
    }
    else if(number_float_like)
    {
        number_type = &f64_t_ast;
    }
    else
    {
        number_type = &s64_t_ast;
    }
    
    {
        u64 prim = number_type->primitive;
        u64 size = prim & PRIM_SIZE_MASK;
        if(number_float_like)
        {
            if(!(prim & PRIM_FLOATLIKE))
            {
                report_error("Got float, expected other number", number_ast);
                ctx->success = false;
                goto finish;
            }
            
            switch(size)
            {
                case PRIM_SIZE4: {
                    set_resolved_type(number_ast, &f32_t_ast);
                } break;
                case PRIM_NO_SIZE:
                case PRIM_SIZE8: {
                    set_resolved_type(number_ast, &f64_t_ast);
                } break;
                default: {
                    // Note: no floatlike type should have a different size
                    assert(false);
                } break;
            }
        }
        else
        {
            if(!(prim & PRIM_INTLIKE))
            {
                report_error("Got int, expected other number", number_ast);
                ctx->success = false;
                goto finish;
            }
            u64 sign = prim & PRIM_SIGN_MASK;
            if(sign == PRIM_UNSIGNED_INT)
            {
                switch(size)
                {
                    case PRIM_SIZE1: {
                        set_resolved_type(number_ast, &u8_t_ast);
                    } break;
                    case PRIM_SIZE2: {
                        set_resolved_type(number_ast, &u16_t_ast);
                    } break;
                    case PRIM_SIZE4: {
                        set_resolved_type(number_ast, &u32_t_ast);
                    } break;
                    case PRIM_NO_SIZE:
                    case PRIM_SIZE8: {
                        set_resolved_type(number_ast, &u64_t_ast);
                    } break;
                    default: {
                        assert(false);
                    } break;
                }
            }
            else
            {
                // Note: if signed, or not specified
                switch(size)
                {
                    case PRIM_SIZE1: {
                        set_resolved_type(number_ast, &s8_t_ast);
                    } break;
                    case PRIM_SIZE2: {
                        set_resolved_type(number_ast, &s16_t_ast);
                    } break;
                    case PRIM_SIZE4: {
                        set_resolved_type(number_ast, &s32_t_ast);
                    } break;
                    case PRIM_NO_SIZE:
                    case PRIM_SIZE8: {
                        set_resolved_type(number_ast, &s64_t_ast);
                    } break;
                    default: {
                        assert(false);
                    } break;
                }
            }
        }
    }
    finish:
    
    if(type_resolved(number_ast))
    {
        return true;
    }
    else
    {
        auto job = make_typecheck_job(type, number_ast);
        array_add(ctx->waiting_jobs, job);
        return false;
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xd0, %rsp
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq %rdx, -0x20(%rbp)
movq -0x20(%rbp), %rax
movzwl 0x2(%rax), %ecx
orl $0x20, %ecx
movw %cx, 0x2(%rax)
movq -0x20(%rbp), %rax
movzwl 0x2(%rax), %eax
andl $0x40, %eax
cmpl $0x0, %eax
setne %al
andb $0x1, %al
movb %al, -0x21(%rbp)
cmpq $0x0, -0x18(%rbp)
je 0x7d1e
movq -0x10(%rbp), %rdi
movq -0x18(%rbp), %rsi
leaq -0x38(%rbp), %rdx
callq 0x9040
movl %eax, -0x3c(%rbp)
cmpl $0x0, -0x3c(%rbp)
je 0x7cb6
jmp 0x7f6e
movq -0x38(%rbp), %rax
cmpw $0x11, (%rax)
je 0x7cdd
movq -0x18(%rbp), %rsi
leaq 0x12eb7(%rip), %rdi     # 0x1ab82
callq 0x4950
movq -0x10(%rbp), %rax
movb $0x0, 0x10(%rax)
jmp 0x7f6e
movq -0x38(%rbp), %rax
movq %rax, -0x30(%rbp)
movq -0x30(%rbp), %rax
movq 0x20(%rax), %rax
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rax
andq $0x60, %rax
cmpq $0x0, %rax
jne 0x7d1c
movq -0x18(%rbp), %rsi
leaq 0x12de2(%rip), %rdi     # 0x1aaec
callq 0x4950
movq -0x10(%rbp), %rax
movb $0x0, 0x10(%rax)
jmp 0x7f6e
jmp 0x7d3e
testb $0x1, -0x21(%rbp)
je 0x7d31
leaq 0x18175(%rip), %rax     # 0x1fea0
movq %rax, -0x30(%rbp)
jmp 0x7d3c
leaq 0x18078(%rip), %rax     # 0x1fdb0
movq %rax, -0x30(%rbp)
jmp 0x7d3e
movq -0x30(%rbp), %rax
movq 0x20(%rax), %rax
movq %rax, -0x50(%rbp)
movq -0x50(%rbp), %rax
andq $0x7, %rax
movq %rax, -0x58(%rbp)
testb $0x1, -0x21(%rbp)
je 0x7e03
movq -0x50(%rbp), %rax
andq $0x40, %rax
cmpq $0x0, %rax
jne 0x7d8b
movq -0x20(%rbp), %rsi
leaq 0x12e21(%rip), %rdi     # 0x1ab9a
callq 0x4950
movq -0x10(%rbp), %rax
movb $0x0, 0x10(%rax)
jmp 0x7f6e
movq -0x58(%rbp), %rax
movq %rax, -0xa8(%rbp)
testq %rax, %rax
je 0x7dcd
jmp 0x7d9d
movq -0xa8(%rbp), %rax
subq $0x3, %rax
je 0x7dbb
jmp 0x7dac
movq -0xa8(%rbp), %rax
subq $0x4, %rax
je 0x7dcd
jmp 0x7ddf
movq -0x20(%rbp), %rdi
leaq 0x180b2(%rip), %rsi     # 0x1fe78
callq 0x3be0
jmp 0x7dfe
movq -0x20(%rbp), %rdi
leaq 0x180c8(%rip), %rsi     # 0x1fea0
callq 0x3be0
jmp 0x7dfe
leaq 0x1203c(%rip), %rdi     # 0x19e22
leaq 0x120ff(%rip), %rsi     # 0x19eec
movl $0x42d, %edx            # imm = 0x42D
leaq 0x12dc2(%rip), %rcx     # 0x1abbb
callq 0x3080
jmp 0x7f6c
movq -0x50(%rbp), %rax
andq $0x20, %rax
cmpq $0x0, %rax
jne 0x7e2e
movq -0x20(%rbp), %rsi
leaq 0x12dda(%rip), %rdi     # 0x1abf6
callq 0x4950
movq -0x10(%rbp), %rax
movb $0x0, 0x10(%rax)
jmp 0x7f6e
movq -0x50(%rbp), %rax
andq $0x18, %rax
movq %rax, -0x60(%rbp)
cmpq $0x10, -0x60(%rbp)
jne 0x7ed9
movq -0x58(%rbp), %rax
movq %rax, -0xb0(%rbp)
subq $0x4, %rax
ja 0x7eb5
movq -0xb0(%rbp), %rax
leaq 0x112d4(%rip), %rcx     # 0x19138
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq -0x20(%rbp), %rdi
leaq 0x17e20(%rip), %rsi     # 0x1fc98
callq 0x3be0
jmp 0x7ed4
movq -0x20(%rbp), %rdi
leaq 0x17e36(%rip), %rsi     # 0x1fcc0
callq 0x3be0
jmp 0x7ed4
movq -0x20(%rbp), %rdi
leaq 0x17e4c(%rip), %rsi     # 0x1fce8
callq 0x3be0
jmp 0x7ed4
movq -0x20(%rbp), %rdi
leaq 0x17e62(%rip), %rsi     # 0x1fd10
callq 0x3be0
jmp 0x7ed4
leaq 0x11f66(%rip), %rdi     # 0x19e22
leaq 0x12029(%rip), %rsi     # 0x19eec
movl $0x44c, %edx            # imm = 0x44C
leaq 0x12cec(%rip), %rcx     # 0x1abbb
callq 0x3080
jmp 0x7f6a
movq -0x58(%rbp), %rax
movq %rax, -0xb8(%rbp)
subq $0x4, %rax
ja 0x7f49
movq -0xb8(%rbp), %rax
leaq 0x1122c(%rip), %rcx     # 0x19124
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq -0x20(%rbp), %rdi
leaq 0x17e2c(%rip), %rsi     # 0x1fd38
callq 0x3be0
jmp 0x7f68
movq -0x20(%rbp), %rdi
leaq 0x17e42(%rip), %rsi     # 0x1fd60
callq 0x3be0
jmp 0x7f68
movq -0x20(%rbp), %rdi
leaq 0x17e58(%rip), %rsi     # 0x1fd88
callq 0x3be0
jmp 0x7f68
movq -0x20(%rbp), %rdi
leaq 0x17e6e(%rip), %rsi     # 0x1fdb0
callq 0x3be0
jmp 0x7f68
leaq 0x11ed2(%rip), %rdi     # 0x19e22
leaq 0x11f95(%rip), %rsi     # 0x19eec
movl $0x463, %edx            # imm = 0x463
leaq 0x12c58(%rip), %rcx     # 0x1abbb
callq 0x3080
jmp 0x7f6a
jmp 0x7f6c
jmp 0x7f6e
movq -0x20(%rbp), %rdi
callq 0x5600
testb $0x1, %al
jne 0x7f7d
jmp 0x7f86
movb $0x1, -0x1(%rbp)
jmp 0x8012
movq -0x18(%rbp), %rsi
movq -0x20(%rbp), %rdx
leaq -0x78(%rbp), %rdi
xorl %ecx, %ecx
callq 0x4a80
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdi
movq -0x78(%rbp), %rax
movq %rax, -0x90(%rbp)
movq -0x70(%rbp), %rax
movq %rax, -0x88(%rbp)
movq -0x68(%rbp), %rax
movq %rax, -0x80(%rbp)
movq 0x17cba(%rip), %rax     # 0x1fc80
movq %rax, -0xa0(%rbp)
movq 0x17cb4(%rip), %rax     # 0x1fc88
movq %rax, -0x98(%rbp)
movq -0xa0(%rbp), %rsi
movq -0x98(%rbp), %rdx
leaq -0x90(%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
movb $0x0, -0x1(%rbp)
movb -0x1(%rbp), %al
andb $0x1, %al
addq $0xd0, %rsp
popq %rbp
retq