// File: /workspace/github_c_makefile_star2_O0/vtereshkov[P]umka-lang/src/umka_stmt.c
// Function: parseFnBlock
void parseFnBlock(Compiler *comp, Ident *fn, const Type *upvaluesStructType)
{
    lexEat(&comp->lex, TOK_LBRACE);
    blocksEnterFn(&comp->blocks, fn, upvaluesStructType != NULL);

    const char *prevDebugFnName = comp->lex.debug->fnName;

    if (fn->kind == IDENT_CONST && fn->type->kind == TYPE_FN && fn->block == 0)
    {
        if (fn->type->sig.isMethod)
            comp->lex.debug->fnName = identMethodNameWithRcv(&comp->idents, fn);
        else
            comp->lex.debug->fnName = fn->name;
    }
    else
        comp->lex.debug->fnName = "<unknown>";

    if (fn->prototypeOffset >= 0)
    {
        genEntryPoint(&comp->gen, fn->prototypeOffset);
        fn->prototypeOffset = -1;
    }

    genEnterFrameStub(&comp->gen);

    // Formal parameters
    for (int i = 0; i < fn->type->sig.numParams; i++)
        identAllocParam(&comp->idents, &comp->types, &comp->modules, &comp->blocks, &fn->type->sig, i);

    // Upvalues
    if (upvaluesStructType)
    {
        // Extract upvalues structure from the "any" interface
        const Ident *upvaluesParamIdent = identAssertFind(&comp->idents, &comp->modules, &comp->blocks, comp->blocks.module, "#upvalues", NULL);
        const Type *upvaluesParamType = upvaluesParamIdent->type;

        doPushVarPtr(comp, upvaluesParamIdent);
        genDeref(&comp->gen, upvaluesParamIdent->type->kind);
        doExplicitTypeConv(comp, upvaluesStructType, &upvaluesParamType, NULL);

        // Copy upvalue structure fields to new local variables
        for (int i = 0; i < upvaluesStructType->numItems; i++)
        {
            const Field *upvalue = upvaluesStructType->field[i];

            genDup(&comp->gen);
            genGetFieldPtr(&comp->gen, upvalue->offset);
            genDeref(&comp->gen, upvalue->type->kind);

            const Ident *upvalueIdent = identAllocVar(&comp->idents, &comp->types, &comp->modules, &comp->blocks, upvalue->name, upvalue->type, false);
            doZeroVar(comp, upvalueIdent);
            doPushVarPtr(comp, upvalueIdent);

            genSwapChangeRefCntAssign(&comp->gen, upvalue->type);
        }

        genPop(&comp->gen);
    }

    // 'break'/'continue'/'return' prologs
    Gotos *outerBreaks = comp->gen.breaks;
    comp->gen.breaks = NULL;

    Gotos *outerContinues = comp->gen.continues;
    comp->gen.continues = NULL;

    Gotos returns, *outerReturns = comp->gen.returns;
    comp->gen.returns = &returns;
    genGotosProlog(&comp->gen, comp->gen.returns, blocksCurrent(&comp->blocks));

    // Additional scope embracing StmtList
    blocksEnter(&comp->blocks);

    // StmtList
    parseStmtList(comp);

    const bool hasReturn = comp->blocks.item[comp->blocks.top].hasReturn;

    // Additional scope embracing StmtList
    doGarbageCollection(comp);
    identWarnIfUnusedAll(&comp->idents, blocksCurrent(&comp->blocks));
    blocksLeave(&comp->blocks);

    // 'return'/'continue'/'break' epilogs
    genGotosEpilog(&comp->gen, comp->gen.returns);
    comp->gen.returns = outerReturns;
    comp->gen.continues = outerContinues;
    comp->gen.breaks = outerBreaks;

    doGarbageCollection(comp);
    identWarnIfUnusedAll(&comp->idents, blocksCurrent(&comp->blocks));
    identFree(&comp->idents, blocksCurrent(&comp->blocks));

    const int localVarSlots = align(comp->blocks.item[comp->blocks.top].localVarSize, sizeof(Slot)) / sizeof(Slot);

    const ParamLayout *paramLayout = typeMakeParamLayout(&comp->types, &fn->type->sig);

    genLeaveFrameFixup(&comp->gen, typeMakeParamAndLocalVarLayout(&comp->types, paramLayout, localVarSlots));
    genReturn(&comp->gen, paramLayout->numParamSlots);

    comp->lex.debug->fnName = prevDebugFnName;

    blocksLeave(&comp->blocks);
    lexEat(&comp->lex, TOK_RBRACE);

    if (!hasReturn && fn->type->sig.resultType->kind != TYPE_VOID)
        comp->error.handler(comp->error.context, "Function must return a value");
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x250, %rsp            # imm = 0x250
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq -0x8(%rbp), %rdi
addq $0x4ba8, %rdi           # imm = 0x4BA8
movl $0x3c, %esi
callq 0x1b150
movq -0x8(%rbp), %rdi
addq $0x4220, %rdi           # imm = 0x4220
movq -0x10(%rbp), %rsi
cmpq $0x0, -0x18(%rbp)
setne %al
movzbl %al, %edx
andl $0x1, %edx
callq 0x5e90
movq -0x8(%rbp), %rax
movq 0x4e08(%rax), %rax
movq 0x8(%rax), %rax
movq %rax, -0x20(%rbp)
movq -0x10(%rbp), %rax
cmpl $0x0, (%rax)
jne 0x1e689
movq -0x10(%rbp), %rax
movq 0x108(%rax), %rax
cmpl $0x1a, (%rax)
jne 0x1e689
movq -0x10(%rbp), %rax
cmpl $0x0, 0x114(%rax)
jne 0x1e689
movq -0x10(%rbp), %rax
movq 0x108(%rax), %rax
testb $0x1, 0x30(%rax)
je 0x1e670
movq -0x8(%rbp), %rdi
addq $0x4e38, %rdi           # imm = 0x4E38
movq -0x10(%rbp), %rsi
callq 0x1a6c0
movq %rax, %rcx
movq -0x8(%rbp), %rax
movq 0x4e08(%rax), %rax
movq %rcx, 0x8(%rax)
jmp 0x1e687
movq -0x10(%rbp), %rcx
addq $0x4, %rcx
movq -0x8(%rbp), %rax
movq 0x4e08(%rax), %rax
movq %rcx, 0x8(%rax)
jmp 0x1e69f
movq -0x8(%rbp), %rax
movq 0x4e08(%rax), %rax
leaq 0x1b5d1a(%rip), %rcx    # 0x1d43b5
movq %rcx, 0x8(%rax)
movq -0x10(%rbp), %rax
cmpl $0x0, 0x11c(%rax)
jl 0x1e6d4
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
movq -0x10(%rbp), %rax
movl 0x11c(%rax), %esi
callq 0x18b90
movq -0x10(%rbp), %rax
movl $0xffffffff, 0x11c(%rax) # imm = 0xFFFFFFFF
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
callq 0x18b00
movl $0x0, -0x24(%rbp)
movl -0x24(%rbp), %eax
movq -0x10(%rbp), %rcx
movq 0x108(%rcx), %rcx
cmpl 0x28(%rcx), %eax
jge 0x1e74d
movq -0x8(%rbp), %rdi
addq $0x4e38, %rdi           # imm = 0x4E38
movq -0x8(%rbp), %rsi
addq $0x4e18, %rsi           # imm = 0x4E18
movq -0x8(%rbp), %rdx
addq $0x100, %rdx            # imm = 0x100
movq -0x8(%rbp), %rcx
addq $0x4220, %rcx           # imm = 0x4220
movq -0x10(%rbp), %rax
movq 0x108(%rax), %r8
addq $0x28, %r8
movl -0x24(%rbp), %r9d
callq 0x1a610
movl -0x24(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x24(%rbp)
jmp 0x1e6eb
cmpq $0x0, -0x18(%rbp)
je 0x1e8f8
movq -0x8(%rbp), %rdi
addq $0x4e38, %rdi           # imm = 0x4E38
movq -0x8(%rbp), %rsi
addq $0x100, %rsi            # imm = 0x100
movq -0x8(%rbp), %rdx
addq $0x4220, %rdx           # imm = 0x4220
movq -0x8(%rbp), %rax
movl 0x4b88(%rax), %ecx
leaq 0x1b5c5e(%rip), %r8     # 0x1d43e8
xorl %eax, %eax
movl %eax, %r9d
callq 0x19880
movq %rax, -0x30(%rbp)
movq -0x30(%rbp), %rax
movq 0x108(%rax), %rax
movq %rax, -0x38(%rbp)
movq -0x8(%rbp), %rdi
movq -0x30(%rbp), %rsi
callq 0xd010
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
movq -0x30(%rbp), %rax
movq 0x108(%rax), %rax
movl (%rax), %esi
callq 0x16fa0
movq -0x8(%rbp), %rdi
movq -0x18(%rbp), %rsi
leaq -0x38(%rbp), %rdx
xorl %eax, %eax
movl %eax, %ecx
callq 0xd730
movl $0x0, -0x3c(%rbp)
movl -0x3c(%rbp), %eax
movq -0x18(%rbp), %rcx
cmpl 0x10(%rcx), %eax
jge 0x1e8e8
movq -0x18(%rbp), %rax
movq 0x28(%rax), %rax
movslq -0x3c(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0x48(%rbp)
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
callq 0x16eb0
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
movq -0x48(%rbp), %rax
movl 0x110(%rax), %esi
callq 0x17bb0
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
movq -0x48(%rbp), %rax
movq 0x108(%rax), %rax
movl (%rax), %esi
callq 0x16fa0
movq -0x8(%rbp), %rdi
addq $0x4e38, %rdi           # imm = 0x4E38
movq -0x8(%rbp), %rsi
addq $0x4e18, %rsi           # imm = 0x4E18
movq -0x8(%rbp), %rdx
addq $0x100, %rdx            # imm = 0x100
movq -0x8(%rbp), %rcx
addq $0x4220, %rcx           # imm = 0x4220
movq -0x48(%rbp), %r8
movq -0x48(%rbp), %rax
movq 0x108(%rax), %r9
xorl %eax, %eax
movl $0x0, (%rsp)
callq 0x1a450
movq %rax, -0x50(%rbp)
movq -0x8(%rbp), %rdi
movq -0x50(%rbp), %rsi
callq 0x1d5e0
movq -0x8(%rbp), %rdi
movq -0x50(%rbp), %rsi
callq 0xd010
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
movq -0x48(%rbp), %rax
movq 0x108(%rax), %rsi
callq 0x17500
movl -0x3c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x3c(%rbp)
jmp 0x1e7ed
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
callq 0x16d30
movq -0x8(%rbp), %rax
movq 0x5018(%rax), %rax
movq %rax, -0x58(%rbp)
movq -0x8(%rbp), %rax
movq $0x0, 0x5018(%rax)
movq -0x8(%rbp), %rax
movq 0x5020(%rax), %rax
movq %rax, -0x60(%rbp)
movq -0x8(%rbp), %rax
movq $0x0, 0x5020(%rax)
movq -0x8(%rbp), %rax
movq 0x5028(%rax), %rax
movq %rax, -0x208(%rbp)
movq -0x8(%rbp), %rax
leaq -0x200(%rbp), %rcx
movq %rcx, 0x5028(%rax)
movq -0x8(%rbp), %rax
addq $0x4e70, %rax           # imm = 0x4E70
movq %rax, -0x248(%rbp)
movq -0x8(%rbp), %rax
movq 0x5028(%rax), %rax
movq %rax, -0x240(%rbp)
movq -0x8(%rbp), %rdi
addq $0x4220, %rdi           # imm = 0x4220
callq 0x6020
movq -0x248(%rbp), %rdi
movq -0x240(%rbp), %rsi
movl %eax, %edx
callq 0x18cb0
movq -0x8(%rbp), %rdi
addq $0x4220, %rdi           # imm = 0x4220
callq 0x5e60
movq -0x8(%rbp), %rdi
callq 0x1ec10
movq -0x8(%rbp), %rax
addq $0x4220, %rax           # imm = 0x4220
movq -0x8(%rbp), %rcx
movslq 0x4b84(%rcx), %rcx
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
movb 0x14(%rax), %al
andb $0x1, %al
movb %al, -0x209(%rbp)
movq -0x8(%rbp), %rdi
callq 0x1d3a0
movq -0x8(%rbp), %rax
addq $0x4e38, %rax           # imm = 0x4E38
movq %rax, -0x238(%rbp)
movq -0x8(%rbp), %rdi
addq $0x4220, %rdi           # imm = 0x4220
callq 0x6020
movq -0x238(%rbp), %rdi
movl %eax, %esi
callq 0x1a7e0
movq -0x8(%rbp), %rdi
addq $0x4220, %rdi           # imm = 0x4220
callq 0x5fa0
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
movq -0x8(%rbp), %rax
movq 0x5028(%rax), %rsi
callq 0x18d60
movq -0x208(%rbp), %rcx
movq -0x8(%rbp), %rax
movq %rcx, 0x5028(%rax)
movq -0x60(%rbp), %rcx
movq -0x8(%rbp), %rax
movq %rcx, 0x5020(%rax)
movq -0x58(%rbp), %rcx
movq -0x8(%rbp), %rax
movq %rcx, 0x5018(%rax)
movq -0x8(%rbp), %rdi
callq 0x1d3a0
movq -0x8(%rbp), %rax
addq $0x4e38, %rax           # imm = 0x4E38
movq %rax, -0x230(%rbp)
movq -0x8(%rbp), %rdi
addq $0x4220, %rdi           # imm = 0x4220
callq 0x6020
movq -0x230(%rbp), %rdi
movl %eax, %esi
callq 0x1a7e0
movq -0x8(%rbp), %rax
addq $0x4e38, %rax           # imm = 0x4E38
movq %rax, -0x228(%rbp)
movq -0x8(%rbp), %rdi
addq $0x4220, %rdi           # imm = 0x4220
callq 0x6020
movq -0x228(%rbp), %rdi
movl %eax, %esi
callq 0x194d0
movq -0x8(%rbp), %rax
addq $0x4220, %rax           # imm = 0x4220
movq -0x8(%rbp), %rcx
movslq 0x4b84(%rcx), %rcx
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
movslq 0x10(%rax), %rdi
movl $0x8, %esi
callq 0x1ec60
shrq $0x3, %rax
movl %eax, -0x210(%rbp)
movq -0x8(%rbp), %rdi
addq $0x4e18, %rdi           # imm = 0x4E18
movq -0x10(%rbp), %rax
movq 0x108(%rax), %rsi
addq $0x28, %rsi
callq 0x239a0
movq %rax, -0x218(%rbp)
movq -0x8(%rbp), %rax
addq $0x4e70, %rax           # imm = 0x4E70
movq %rax, -0x220(%rbp)
movq -0x8(%rbp), %rdi
addq $0x4e18, %rdi           # imm = 0x4E18
movq -0x218(%rbp), %rsi
movl -0x210(%rbp), %edx
callq 0x23af0
movq -0x220(%rbp), %rdi
movq %rax, %rsi
callq 0x18b30
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
movq -0x218(%rbp), %rax
movq 0x10(%rax), %rax
movl %eax, %esi
callq 0x18350
movq -0x20(%rbp), %rcx
movq -0x8(%rbp), %rax
movq 0x4e08(%rax), %rax
movq %rcx, 0x8(%rax)
movq -0x8(%rbp), %rdi
addq $0x4220, %rdi           # imm = 0x4220
callq 0x5fa0
movq -0x8(%rbp), %rdi
addq $0x4ba8, %rdi           # imm = 0x4BA8
movl $0x3d, %esi
callq 0x1b150
testb $0x1, -0x209(%rbp)
jne 0x1ec07
movq -0x10(%rbp), %rax
movq 0x108(%rax), %rax
movq 0xb8(%rax), %rax
cmpl $0x2, (%rax)
je 0x1ec07
movq -0x8(%rbp), %rax
movq 0x50f8(%rax), %rcx
movq -0x8(%rbp), %rax
movq 0x5118(%rax), %rdi
leaq 0x1bae21(%rip), %rsi    # 0x1d9a24
movb $0x0, %al
callq *%rcx
addq $0x250, %rsp            # imm = 0x250
popq %rbp
retq