// File: /workspace/github_c_makefile_star2_O2/naleksiev[P]fin/src/fin_mod.c
// Function: fin_mod_compile_expr
static void fin_mod_compile_expr(fin_ctx_t* ctx, fin_mod_compiler_t* cmp, fin_ast_expr_t* expr) {
    switch (expr->type) {
        case fin_ast_expr_type_id: {
            fin_ast_id_expr_t* id_expr = (fin_ast_id_expr_t*)expr;
            if (id_expr->primary) {
                fin_mod_compile_expr(ctx, cmp, id_expr->primary);
                fin_str_t* type_name = fin_mod_resolve_type(ctx, cmp, id_expr->primary);
                int32_t field_idx = fin_mod_resolve_field(ctx, cmp->mod, type_name, id_expr->name);
                fin_str_destroy(ctx, type_name);
                if (field_idx >= 0) {
                    fin_mod_code_emit_uint8(ctx, &cmp->code, fin_op_load_field);
                    fin_mod_code_emit_uint8(ctx, &cmp->code, field_idx);
                    FIN_LOG("\tload_fld   %2d         // %s\n", field_idx, fin_str_cstr(id_expr->name));
                    break;
                }
            }
            else {
                fin_mod_local_t* local = fin_mod_resolve_local(cmp, id_expr->name);
                assert(local);
                fin_mod_code_emit_uint8(ctx, &cmp->code, local->is_param ? fin_op_load_arg : fin_op_load_local);
                fin_mod_code_emit_uint8(ctx, &cmp->code, local->idx);
                FIN_LOG("\t%s   %2d         // %s\n",
                    local->is_param ? "load_arg" : "load_loc", local->idx, fin_str_cstr(local->name));
            }
            break;
        }
        case fin_ast_expr_type_bool: {
            fin_ast_bool_expr_t* bool_expr = (fin_ast_bool_expr_t*)expr;
            fin_val_t val = { .b = bool_expr->value };
            int16_t idx = fin_mod_const_idx(cmp, val);
            fin_mod_code_emit_uint8(ctx, &cmp->code, fin_op_load_const);
            fin_mod_code_emit_uint16(ctx, &cmp->code, idx);
            FIN_LOG("\tload_const %2d         // %s\n", idx, bool_expr->value ? "true" : "false");
            break;
        }
        case fin_ast_expr_type_int: {
            fin_ast_int_expr_t* int_expr = (fin_ast_int_expr_t*)expr;
            fin_val_t val = { .i = int_expr->value };
            int16_t idx = fin_mod_const_idx(cmp, val);
            fin_mod_code_emit_uint8(ctx, &cmp->code, fin_op_load_const);
            fin_mod_code_emit_uint16(ctx, &cmp->code, idx);
            FIN_LOG("\tload_const %2d         // %d\n", idx, (int32_t)int_expr->value);
            break;
        }
        case fin_ast_expr_type_float: {
            fin_ast_float_expr_t* float_expr = (fin_ast_float_expr_t*)expr;
            fin_val_t val = { .f = float_expr->value };
            int16_t idx = fin_mod_const_idx(cmp, val);
            fin_mod_code_emit_uint8(ctx, &cmp->code, fin_op_load_const);
            fin_mod_code_emit_uint16(ctx, &cmp->code, idx);
            FIN_LOG("\tload_const %2d         // %f\n", idx, float_expr->value);
            break;
        }
        case fin_ast_expr_type_str: {
            fin_ast_str_expr_t* str_expr = (fin_ast_str_expr_t*)expr;
            fin_val_t val = { .s = str_expr->value };
            if (val.s)
                val.s = fin_str_clone(val.s);
            int16_t idx = fin_mod_const_idx(cmp, val);
            fin_mod_code_emit_uint8(ctx, &cmp->code, fin_op_load_const);
            fin_mod_code_emit_uint16(ctx, &cmp->code, idx);
            FIN_LOG("\tload_const %2d         // \"%s\"\n", idx, fin_str_cstr(str_expr->value));
            break;
        }
        case fin_ast_expr_type_str_interp: {
            fin_ast_str_interp_expr_t* interp_expr = (fin_ast_str_interp_expr_t*)expr;
            fin_mod_compile_expr(ctx, cmp, interp_expr->expr);
            fin_str_t* type = fin_mod_resolve_type(ctx, cmp, interp_expr->expr);
            if (strcmp(fin_str_cstr(type), "string") != 0) {
                char signature[256];
                signature[0] = '\0';
                strcat(signature, "string(");
                strcat(signature, fin_str_cstr(type));
                strcat(signature, ")");
                fin_str_t* sign = fin_str_create(ctx, signature, -1);
                int16_t idx = fin_mod_bind_idx(cmp, sign);
                fin_mod_code_emit_uint8(ctx, &cmp->code, fin_op_call);
                fin_mod_code_emit_uint16(ctx, &cmp->code, idx);
                FIN_LOG("\tcall       %2d         // %s\n", idx, fin_str_cstr(sign));
                fin_str_destroy(ctx, sign);
            }
            fin_str_destroy(ctx, type);
            if (interp_expr->next) {
                fin_mod_compile_expr(ctx, cmp, &interp_expr->next->base);
                fin_str_t* sign = fin_str_create(ctx, "__op_add(string,string)", -1);
                int16_t idx = fin_mod_bind_idx(cmp, sign);
                fin_mod_code_emit_uint8(ctx, &cmp->code, fin_op_call);
                fin_mod_code_emit_uint16(ctx, &cmp->code, idx);
                FIN_LOG("\tcall       %2d         // %s\n", idx, fin_str_cstr(sign));
                fin_str_destroy(ctx, sign);
            }
            break;
        }
        case fin_ast_expr_type_unary: {
            fin_ast_unary_expr_t* unary_expr = (fin_ast_unary_expr_t*)expr;
            fin_mod_compile_expr(ctx, cmp, unary_expr->expr);

            fin_str_t* sign = fin_mod_unary_get_signature(ctx, cmp, unary_expr);
            int16_t idx = fin_mod_bind_idx(cmp, sign);
            fin_mod_code_emit_uint8(ctx, &cmp->code, fin_op_call);
            fin_mod_code_emit_uint16(ctx, &cmp->code, idx);
            FIN_LOG("\tcall       %2d         // %s\n", idx, fin_str_cstr(sign));
            fin_str_destroy(ctx, sign);
            break;
        }
        case fin_ast_expr_type_binary: {
            fin_ast_binary_expr_t* bin_expr = (fin_ast_binary_expr_t*)expr;
            fin_mod_compile_expr(ctx, cmp, bin_expr->lhs);
            fin_mod_compile_expr(ctx, cmp, bin_expr->rhs);

            fin_str_t* sign = fin_mod_binary_get_signature(ctx, cmp, bin_expr);
            int16_t idx = fin_mod_bind_idx(cmp, sign);
            fin_mod_code_emit_uint8(ctx, &cmp->code, fin_op_call);
            fin_mod_code_emit_uint16(ctx, &cmp->code, idx);
            FIN_LOG("\tcall       %2d         // %s\n", idx, fin_str_cstr(sign));
            fin_str_destroy(ctx, sign);
            break;
        }
        case fin_ast_expr_type_cond: {
            fin_ast_cond_expr_t* cond_expr = (fin_ast_cond_expr_t*)expr;
            fin_mod_compile_expr(ctx, cmp, cond_expr->cond);
            fin_mod_code_emit_uint8(ctx, &cmp->code, fin_op_branch_if_n);
            uint8_t* lbl_else = cmp->code.top;
            fin_mod_code_emit_uint16(ctx, &cmp->code, 0);
            FIN_LOG("\tbr_if_n     lbl_%d\n", (int32_t)(lbl_else - cmp->code.begin));
            fin_mod_compile_expr(ctx, cmp, cond_expr->true_expr);
            if (cond_expr->false_expr) {
                fin_mod_code_emit_uint8(ctx, &cmp->code, fin_op_branch);
                uint8_t* lbl_end = cmp->code.top;
                fin_mod_code_emit_uint16(ctx, &cmp->code, 0);
                FIN_LOG("\tbr          lbl_%d\n", (int32_t)(lbl_end - cmp->code.begin));
                FIN_LOG("lbl_%d:\n", (int32_t)(lbl_else - cmp->code.begin));
                uint16_t offset = cmp->code.top - lbl_else - 2;
                *lbl_else++ = offset & 0xFF;
                *lbl_else++ = (offset >> 8) & 0xFF;
                fin_mod_compile_expr(ctx, cmp, cond_expr->false_expr);
                FIN_LOG("lbl_%d:\n", (int32_t)(lbl_end - cmp->code.begin));
                offset = cmp->code.top - lbl_end - 2;
                *lbl_end++ = offset & 0xFF;
                *lbl_end++ = (offset >> 8) & 0xFF;
            }
            else {
                FIN_LOG("lbl_%d:\n", (int32_t)(lbl_else - cmp->code.begin));
                uint16_t offset = cmp->code.top - lbl_else - 2;
                *lbl_else++ = offset & 0xFF;
                *lbl_else++ = (offset >> 8) & 0xFF;
            }
            break;
        }
        case fin_ast_expr_type_arg: {
            fin_ast_arg_expr_t* arg_expr = (fin_ast_arg_expr_t*)expr;
            fin_mod_compile_expr(ctx, cmp, arg_expr->expr);
            break;
        }
        case fin_ast_expr_type_invoke: {
            fin_ast_invoke_expr_t* invoke_expr = (fin_ast_invoke_expr_t*)expr;
            for (fin_ast_arg_expr_t* e = invoke_expr->args; e; e = e->next)
                fin_mod_compile_expr(ctx, cmp, &e->base);
            fin_str_t* sign = fin_mod_invoke_get_signature(ctx, cmp, invoke_expr);
            int16_t idx = fin_mod_bind_idx(cmp, sign);
            fin_mod_code_emit_uint8(ctx, &cmp->code, fin_op_call);
            fin_mod_code_emit_uint16(ctx, &cmp->code, idx);
            FIN_LOG("\tcall       %2d         // %s\n", idx, fin_str_cstr(sign));
            fin_str_destroy(ctx, sign);
            break;
        }
        case fin_ast_expr_type_assign: {
            fin_ast_assign_expr_t* assign_expr = (fin_ast_assign_expr_t*)expr;
            assert(assign_expr->op == fin_ast_assign_type_assign); // rest not supported yet
            assert(assign_expr->lhs->type == fin_ast_expr_type_id);
            fin_ast_id_expr_t* id_expr = (fin_ast_id_expr_t*)assign_expr->lhs;
            if (id_expr->primary)
                fin_mod_compile_expr(ctx, cmp, id_expr->primary);
            fin_mod_compile_expr(ctx, cmp, assign_expr->rhs);
            if (id_expr->primary) {
                fin_str_t* type_name = fin_mod_resolve_type(ctx, cmp, id_expr->primary);
                int32_t field_idx = fin_mod_resolve_field(ctx, cmp->mod, type_name, id_expr->name);
                fin_str_destroy(ctx, type_name);
                if (field_idx >= 0) {
                    fin_mod_code_emit_uint8(ctx, &cmp->code, fin_op_store_field);
                    fin_mod_code_emit_uint8(ctx, &cmp->code, field_idx);
                    FIN_LOG("\tstore_fld  %2d         // %s\n", field_idx, fin_str_cstr(id_expr->name));
                    break;
                }
            }
            else {
                fin_mod_local_t* local = fin_mod_resolve_local(cmp, id_expr->name);
                assert(local);
                fin_mod_code_emit_uint8(ctx, &cmp->code, local->is_param ? fin_op_store_arg : fin_op_store_local);
                fin_mod_code_emit_uint8(ctx, &cmp->code, local->idx);
                FIN_LOG("\t%s  %2d         // %s\n",
                local->is_param ? "store_arg" : "store_loc", local->idx, fin_str_cstr(local->name));
            }
            break;
        }
        default:
            assert(0);
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x118, %rsp            # imm = 0x118
movq %rdx, %r15
movq %rsi, %r14
movq %rdi, %rbx
leaq 0x2ddd(%rip), %rax      # 0x9360
movl (%r15), %ecx
cmpq $0xc, %rcx
ja 0x6a68
movslq (%rax,%rcx,4), %rcx
addq %rax, %rcx
jmpq *%rcx
movq 0x8(%r15), %r15
jmp 0x6583
movq 0x8(%r15), %rsi
jmp 0x69b5
movq %r15, %r12
movq 0x10(%r12), %r12
movq %rbx, %rdi
movq %r14, %rsi
testq %r12, %r12
je 0x65c5
movq %r12, %rdx
callq 0x655f
jmp 0x65ab
movq %r15, %rdx
callq 0x7410
jmp 0x689a
movq 0x8(%r15), %rdx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x655f
movq 0x10(%r15), %rdx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x655f
movq %rbx, %rdi
movq %r14, %rsi
movq %r15, %rdx
callq 0x7104
jmp 0x689a
movq 0x8(%r15), %rdx
testq %rdx, %rdx
je 0x6984
movq %rbx, %rdi
movq %r14, %rsi
callq 0x655f
movq 0x8(%r15), %rdx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x6cc3
movq %rax, %r12
movq (%r14), %rsi
movq 0x10(%r15), %rcx
movq %rbx, %rdi
movq %rax, %rdx
callq 0x6ecf
movl %eax, %r15d
movq %rbx, %rdi
movq %r12, %rsi
callq 0x79ab
testl %r15d, %r15d
js 0x6a00
addq $0x18, %r14
pushq $0x5
jmp 0x696f
movzbl 0x4(%r15), %esi
jmp 0x69b5
movq 0x8(%r15), %rdi
testq %rdi, %rdi
je 0x69b3
callq 0x79dd
movq %rax, %rsi
jmp 0x69b5
movq 0x8(%r15), %rdx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x655f
movq 0x8(%r15), %rdx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x6cc3
movq %rax, %r12
movq %rax, %rdi
callq 0x7b28
leaq 0x2eac(%rip), %rsi      # 0x9561
movq %rax, %rdi
callq 0x3180
testl %eax, %eax
je 0x6764
leaq -0x140(%rbp), %r13
movb $0x0, (%r13)
movq %r13, %rdi
callq 0x3100
movabsq $0x28676e69727473, %rcx # imm = 0x28676E69727473
movq %rcx, -0x140(%rbp,%rax)
movq %r12, %rdi
callq 0x7b28
movq %r13, %rdi
movq %rax, %rsi
callq 0x3280
movq %r13, %rdi
callq 0x3100
movw $0x29, -0x140(%rbp,%rax)
pushq $-0x1
popq %rdx
movq %rbx, %rdi
movq %r13, %rsi
callq 0x781e
movq %rax, %r13
movq %r14, %rdi
movq %rax, %rsi
callq 0x6f49
movw %ax, -0x2a(%rbp)
movq %r12, -0x38(%rbp)
leaq 0x18(%r14), %r12
pushq $0x7
popq %rdx
movq %rbx, %rdi
movq %r12, %rsi
callq 0x653a
movzwl -0x2a(%rbp), %edx
movq %rbx, %rdi
movq %r12, %rsi
movq -0x38(%rbp), %r12
callq 0x6c2d
movq %rbx, %rdi
movq %r13, %rsi
callq 0x79ab
movq %rbx, %rdi
movq %r12, %rsi
callq 0x79ab
movq 0x10(%r15), %rdx
testq %rdx, %rdx
je 0x6a00
movq %rbx, %rdi
movq %r14, %rsi
callq 0x655f
leaq 0x36b5(%rip), %rsi      # 0x9e43
pushq $-0x1
popq %rdx
movq %rbx, %rdi
callq 0x781e
movq %rax, %r15
movq %r14, %rdi
movq %rax, %rsi
callq 0x6f49
movl %eax, %r12d
addq $0x18, %r14
pushq $0x7
popq %rdx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x653a
movzwl %r12w, %edx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x6c2d
movq %rbx, %rdi
movq %r15, %rsi
callq 0x79ab
jmp 0x6a00
movq 0x8(%r15), %rdx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x655f
leaq 0x18(%r14), %r12
pushq $0xa
popq %rdx
movq %rbx, %rdi
movq %r12, %rsi
callq 0x653a
movq 0x18(%r14), %r13
movq %rbx, %rdi
movq %r12, %rsi
xorl %edx, %edx
callq 0x6c2d
movq 0x10(%r15), %rdx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x655f
cmpq $0x0, 0x18(%r15)
je 0x69f1
pushq $0x8
popq %rdx
movq %rbx, %rdi
movq %r12, %rsi
callq 0x653a
movq 0x18(%r14), %rax
movq %rax, -0x38(%rbp)
movq %rbx, %rdi
movq %r12, %rsi
xorl %edx, %edx
callq 0x6c2d
movl 0x18(%r14), %eax
subl %r13d, %eax
addl $-0x2, %eax
movw %ax, (%r13)
movq 0x18(%r15), %rdx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x655f
movl 0x18(%r14), %eax
movq -0x38(%rbp), %rcx
subl %ecx, %eax
addl $-0x2, %eax
movw %ax, (%rcx)
jmp 0x6a00
movq 0x8(%r15), %rdx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x655f
movq %rbx, %rdi
movq %r14, %rsi
movq %r15, %rdx
callq 0x6fa7
movq %rax, %r15
movq %r14, %rdi
movq %rax, %rsi
callq 0x6f49
movl %eax, %r12d
addq $0x18, %r14
pushq $0x7
popq %rdx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x653a
movzwl %r12w, %edx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x6c2d
movq %rbx, %rdi
movq %r15, %rsi
addq $0x118, %rsp            # imm = 0x118
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x79ab
cmpl $0x0, 0x18(%r15)
jne 0x6a87
movq 0x8(%r15), %r13
cmpl $0x0, (%r13)
jne 0x6aa6
movq 0x8(%r13), %rdx
testq %rdx, %rdx
je 0x6916
movq %rbx, %rdi
movq %r14, %rsi
callq 0x655f
movq 0x10(%r15), %rdx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x655f
movq 0x8(%r13), %rdx
testq %rdx, %rdx
je 0x6a12
movq %rbx, %rdi
movq %r14, %rsi
callq 0x6cc3
movq %rax, %r12
movq (%r14), %rsi
movq 0x10(%r13), %rcx
movq %rbx, %rdi
movq %rax, %rdx
callq 0x6ecf
movl %eax, %r15d
movq %rbx, %rdi
movq %r12, %rsi
callq 0x79ab
testl %r15d, %r15d
js 0x6a00
addq $0x18, %r14
pushq $0x6
popq %rdx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x653a
movzbl %r15b, %edx
jmp 0x6a4c
movq 0x10(%r15), %rsi
movq %r14, %rdi
callq 0x6c96
testq %rax, %rax
je 0x6ac5
movq %rax, %r15
addq $0x18, %r14
movzbl 0x11(%rax), %eax
xorl $0x1, %eax
leal 0x1(,%rax,2), %edx
jmp 0x6a3c
xorl %esi, %esi
movq %r14, %rdi
callq 0x6f0f
movl %eax, %r15d
addq $0x18, %r14
movq %rbx, %rdi
movq %r14, %rsi
xorl %edx, %edx
callq 0x653a
movzwl %r15w, %edx
movq %rbx, %rdi
movq %r14, %rsi
addq $0x118, %rsp            # imm = 0x118
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x6c2d
movl (%r12), %eax
subl %r13d, %eax
addl $-0x2, %eax
movw %ax, (%r13)
addq $0x118, %rsp            # imm = 0x118
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x10(%r13), %rsi
movq %r14, %rdi
callq 0x6c96
testq %rax, %rax
je 0x6ae4
movq %rax, %r15
addq $0x18, %r14
movzbl 0x11(%rax), %eax
xorl $0x1, %eax
leal 0x2(,%rax,2), %edx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x653a
movzbl 0x10(%r15), %edx
movq %rbx, %rdi
movq %r14, %rsi
addq $0x118, %rsp            # imm = 0x118
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x653a
leaq 0x2652(%rip), %rdi      # 0x90c1
leaq 0x29dc(%rip), %rsi      # 0x9452
leaq 0x2a95(%rip), %rcx      # 0x9512
movl $0x20d, %edx            # imm = 0x20D
callq 0x3120
leaq 0x2ada(%rip), %rdi      # 0x9568
leaq 0x29bd(%rip), %rsi      # 0x9452
leaq 0x2a76(%rip), %rcx      # 0x9512
movl $0x1f1, %edx            # imm = 0x1F1
callq 0x3120
leaq 0x2ae9(%rip), %rdi      # 0x9596
leaq 0x299e(%rip), %rsi      # 0x9452
leaq 0x2a57(%rip), %rcx      # 0x9512
movl $0x1f2, %edx            # imm = 0x1F2
callq 0x3120
leaq 0x2a40(%rip), %rdi      # 0x950c
leaq 0x297f(%rip), %rsi      # 0x9452
leaq 0x2a38(%rip), %rcx      # 0x9512
movl $0x15b, %edx            # imm = 0x15B
callq 0x3120
leaq 0x2a21(%rip), %rdi      # 0x950c
leaq 0x2960(%rip), %rsi      # 0x9452
leaq 0x2a19(%rip), %rcx      # 0x9512
movl $0x204, %edx            # imm = 0x204
callq 0x3120