// File: /workspace/github_c_makefile_star2_O0/vtereshkov[P]umka-lang/src/umka_expr.c
// Function: parseClosureLiteral
static void parseClosureLiteral(Compiler *comp, const Type **type, Const *constant)
{
    if (constant)
    {
        // Allocate closure
        Closure *closure = (Closure *)storageAdd(&comp->storage, typeSize(&comp->types, *type));

        // ["|" ident {"," ident} "|"]
        if (comp->lex.tok.kind == TOK_OR)
            comp->error.handler(comp->error.context, "Cannot capture variables in a constant closure literal");

        // fnBlock
        int beforeEntry = comp->gen.ip;

        if (comp->blocks.top != 0)
            genNop(&comp->gen);                                     // Jump over the nested function block (stub)

        const Field *fn = typeAssertFindField(&comp->types, *type, "#fn", NULL);

        const Const fnConstant = {.intVal = comp->gen.ip};
        Ident *fnConstantIdent = identAddTempConst(&comp->idents, &comp->modules, &comp->blocks, fn->type, fnConstant);
        parseFnBlock(comp, fnConstantIdent, NULL);

        if (comp->blocks.top != 0)
            genGoFromTo(&comp->gen, beforeEntry, comp->gen.ip);     // Jump over the nested function block (fixup)

        // Assign closure function
        closure->entryOffset = fnConstant.intVal;
        constant->ptrVal = closure;
    }
    else
    {
        // Allocate closure
        const Ident *closureIdent = identAllocTempVar(&comp->idents, &comp->types, &comp->modules, &comp->blocks, *type, false);
        doZeroVar(comp, closureIdent);

        Type *upvaluesStructType = NULL;

        // ["|" ident {"," ident} "|"]
        if (comp->lex.tok.kind == TOK_OR)
        {
            lexNext(&comp->lex);

            // Determine upvalues structure type
            upvaluesStructType = typeAdd(&comp->types, &comp->blocks, TYPE_STRUCT);
            while (1)
            {
                lexCheck(&comp->lex, TOK_IDENT);

                const Ident *capturedIdent = identAssertFind(&comp->idents, &comp->modules, &comp->blocks, comp->blocks.module, comp->lex.tok.name, NULL);

                if (capturedIdent->kind != IDENT_VAR)
                    comp->error.handler(comp->error.context, "%s is not a variable", capturedIdent->name);

                if (identIsOuterLocalVar(&comp->blocks, capturedIdent))
                    comp->error.handler(comp->error.context, "%s is not specified as a captured variable", capturedIdent->name);

                typeAddField(&comp->types, upvaluesStructType, capturedIdent->type, capturedIdent->name);

                lexNext(&comp->lex);

                if (comp->lex.tok.kind != TOK_COMMA)
                    break;
                lexNext(&comp->lex);
            }

            lexEat(&comp->lex, TOK_OR);

            // Allocate upvalues structure
            const Ident *upvaluesStructIdent = identAllocTempVar(&comp->idents, &comp->types, &comp->modules, &comp->blocks, upvaluesStructType, false);
            doZeroVar(comp, upvaluesStructIdent);

            // Assign upvalues structure fields
            for (int i = 0; i < upvaluesStructType->numItems; i++)
            {
                const Field *upvalue = upvaluesStructType->field[i];
                const Ident *capturedIdent = identAssertFind(&comp->idents, &comp->modules, &comp->blocks, comp->blocks.module, upvalue->name, NULL);

                doPushVarPtr(comp, upvaluesStructIdent);
                genGetFieldPtr(&comp->gen, upvalue->offset);

                doPushVarPtr(comp, capturedIdent);
                genDeref(&comp->gen, capturedIdent->type->kind);

                genChangeRefCntAssign(&comp->gen, upvalue->type);
            }

            // Assign closure upvalues
            const Field *upvalues = typeAssertFindField(&comp->types, closureIdent->type, "#upvalues", NULL);
            const Type *upvaluesType = upvaluesStructIdent->type;

            doPushVarPtr(comp, closureIdent);
            genGetFieldPtr(&comp->gen, upvalues->offset);

            doPushVarPtr(comp, upvaluesStructIdent);
            genDeref(&comp->gen, upvaluesStructIdent->type->kind);
            doAssertImplicitTypeConv(comp, upvalues->type, &upvaluesType, NULL);

            genChangeRefCntAssign(&comp->gen, upvalues->type);
        }

        // fnBlock
        const int beforeEntry = comp->gen.ip;

        genNop(&comp->gen);                                     // Jump over the nested function block (stub)

        const Field *fn = typeAssertFindField(&comp->types, closureIdent->type, "#fn", NULL);

        const Const fnConstant = {.intVal = comp->gen.ip};
        Ident *fnConstantIdent = identAddTempConst(&comp->idents, &comp->modules, &comp->blocks, fn->type, fnConstant);
        parseFnBlock(comp, fnConstantIdent, upvaluesStructType);

        genGoFromTo(&comp->gen, beforeEntry, comp->gen.ip);     // Jump over the nested function block (fixup)

        // Assign closure function
        doPushVarPtr(comp, closureIdent);
        genGetFieldPtr(&comp->gen, fn->offset);

        doPushConst(comp, fn->type, &fnConstant);

        genChangeRefCntAssign(&comp->gen, fn->type);

        doPushVarPtr(comp, closureIdent);
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xb0, %rsp
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
cmpq $0x0, -0x18(%rbp)
je 0x144b9
movq -0x8(%rbp), %rax
addq $0xf0, %rax
movq %rax, -0xb0(%rbp)
movq -0x8(%rbp), %rdi
addq $0x4e18, %rdi           # imm = 0x4E18
movq -0x10(%rbp), %rax
movq (%rax), %rsi
callq 0x21fe0
movq -0xb0(%rbp), %rdi
movslq %eax, %rsi
callq 0x4b20
movq %rax, -0x20(%rbp)
movq -0x8(%rbp), %rax
cmpl $0x1c, 0x4bd0(%rax)
jne 0x143cb
movq -0x8(%rbp), %rax
movq 0x50f8(%rax), %rcx
movq -0x8(%rbp), %rax
movq 0x5118(%rax), %rdi
leaq 0x1c4a68(%rip), %rsi    # 0x1d8e2f
movb $0x0, %al
callq *%rcx
movq -0x8(%rbp), %rax
movl 0x4e78(%rax), %eax
movl %eax, -0x24(%rbp)
movq -0x8(%rbp), %rax
cmpl $0x0, 0x4b84(%rax)
je 0x143f5
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
callq 0x16760
movq -0x8(%rbp), %rdi
addq $0x4e18, %rdi           # imm = 0x4E18
movq -0x10(%rbp), %rax
movq (%rax), %rsi
leaq 0x1bffe4(%rip), %rdx    # 0x1d43f2
xorl %eax, %eax
movl %eax, %ecx
callq 0x23000
movq %rax, -0x30(%rbp)
movq -0x8(%rbp), %rax
movslq 0x4e78(%rax), %rax
movq %rax, -0x38(%rbp)
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 -0x30(%rbp), %rax
movq 0x108(%rax), %rcx
movq -0x38(%rbp), %r8
callq 0x1a030
movq %rax, -0x40(%rbp)
movq -0x8(%rbp), %rdi
movq -0x40(%rbp), %rsi
xorl %eax, %eax
movl %eax, %edx
callq 0x1e5b0
movq -0x8(%rbp), %rax
cmpl $0x0, 0x4b84(%rax)
je 0x1449e
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
movl -0x24(%rbp), %esi
movq -0x8(%rbp), %rax
movl 0x4e78(%rax), %edx
callq 0x18490
movq -0x38(%rbp), %rcx
movq -0x20(%rbp), %rax
movq %rcx, (%rax)
movq -0x20(%rbp), %rcx
movq -0x18(%rbp), %rax
movq %rcx, (%rax)
jmp 0x149d2
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 (%rax), %r8
xorl %r9d, %r9d
callq 0x1a540
movq %rax, -0x48(%rbp)
movq -0x8(%rbp), %rdi
movq -0x48(%rbp), %rsi
callq 0x1d5e0
movq $0x0, -0x50(%rbp)
movq -0x8(%rbp), %rax
cmpl $0x1c, 0x4bd0(%rax)
jne 0x1488a
movq -0x8(%rbp), %rdi
addq $0x4ba8, %rdi           # imm = 0x4BA8
callq 0x1ad90
movq -0x8(%rbp), %rdi
addq $0x4e18, %rdi           # imm = 0x4E18
movq -0x8(%rbp), %rsi
addq $0x4220, %rsi           # imm = 0x4220
movl $0x16, %edx
callq 0x21950
movq %rax, -0x50(%rbp)
movq -0x8(%rbp), %rdi
addq $0x4ba8, %rdi           # imm = 0x4BA8
movl $0x45, %esi
callq 0x1b080
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
movq -0x8(%rbp), %r8
addq $0x4ba8, %r8            # imm = 0x4BA8
addq $0x28, %r8
addq $0x8, %r8
xorl %eax, %eax
movl %eax, %r9d
callq 0x19880
movq %rax, -0x58(%rbp)
movq -0x58(%rbp), %rax
cmpl $0x1, (%rax)
je 0x145e5
movq -0x8(%rbp), %rax
movq 0x50f8(%rax), %rcx
movq -0x8(%rbp), %rax
movq 0x5118(%rax), %rdi
movq -0x58(%rbp), %rdx
addq $0x4, %rdx
leaq 0x1c4885(%rip), %rsi    # 0x1d8e66
movb $0x0, %al
callq *%rcx
movq -0x8(%rbp), %rdi
addq $0x4220, %rdi           # imm = 0x4220
movq -0x58(%rbp), %rsi
callq 0x199e0
testb $0x1, %al
jne 0x145ff
jmp 0x14628
movq -0x8(%rbp), %rax
movq 0x50f8(%rax), %rcx
movq -0x8(%rbp), %rax
movq 0x5118(%rax), %rdi
movq -0x58(%rbp), %rdx
addq $0x4, %rdx
leaq 0x1c4248(%rip), %rsi    # 0x1d886c
movb $0x0, %al
callq *%rcx
movq -0x8(%rbp), %rdi
addq $0x4e18, %rdi           # imm = 0x4E18
movq -0x50(%rbp), %rsi
movq -0x58(%rbp), %rax
movq 0x108(%rax), %rdx
movq -0x58(%rbp), %rcx
addq $0x4, %rcx
callq 0x23070
movq -0x8(%rbp), %rdi
addq $0x4ba8, %rdi           # imm = 0x4BA8
callq 0x1ad90
movq -0x8(%rbp), %rax
cmpl $0x3f, 0x4bd0(%rax)
je 0x1466e
jmp 0x14683
movq -0x8(%rbp), %rdi
addq $0x4ba8, %rdi           # imm = 0x4BA8
callq 0x1ad90
jmp 0x14552
movq -0x8(%rbp), %rdi
addq $0x4ba8, %rdi           # imm = 0x4BA8
movl $0x1c, %esi
callq 0x1b150
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 -0x50(%rbp), %r8
xorl %r9d, %r9d
callq 0x1a540
movq %rax, -0x60(%rbp)
movq -0x8(%rbp), %rdi
movq -0x60(%rbp), %rsi
callq 0x1d5e0
movl $0x0, -0x64(%rbp)
movl -0x64(%rbp), %eax
movq -0x50(%rbp), %rcx
cmpl 0x10(%rcx), %eax
jge 0x147c3
movq -0x50(%rbp), %rax
movq 0x28(%rax), %rax
movslq -0x64(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0x70(%rbp)
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
movq -0x70(%rbp), %r8
xorl %eax, %eax
movl %eax, %r9d
callq 0x19880
movq %rax, -0x78(%rbp)
movq -0x8(%rbp), %rdi
movq -0x60(%rbp), %rsi
callq 0xd010
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
movq -0x70(%rbp), %rax
movl 0x110(%rax), %esi
callq 0x17bb0
movq -0x8(%rbp), %rdi
movq -0x78(%rbp), %rsi
callq 0xd010
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
movq -0x78(%rbp), %rax
movq 0x108(%rax), %rax
movl (%rax), %esi
callq 0x16fa0
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
movq -0x70(%rbp), %rax
movq 0x108(%rax), %rsi
callq 0x17470
movl -0x64(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x64(%rbp)
jmp 0x146e8
movq -0x8(%rbp), %rdi
addq $0x4e18, %rdi           # imm = 0x4E18
movq -0x48(%rbp), %rax
movq 0x108(%rax), %rsi
leaq 0x1bfc08(%rip), %rdx    # 0x1d43e8
xorl %eax, %eax
movl %eax, %ecx
callq 0x23000
movq %rax, -0x80(%rbp)
movq -0x60(%rbp), %rax
movq 0x108(%rax), %rax
movq %rax, -0x88(%rbp)
movq -0x8(%rbp), %rdi
movq -0x48(%rbp), %rsi
callq 0xd010
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
movq -0x80(%rbp), %rax
movl 0x110(%rax), %esi
callq 0x17bb0
movq -0x8(%rbp), %rdi
movq -0x60(%rbp), %rsi
callq 0xd010
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
movq -0x60(%rbp), %rax
movq 0x108(%rax), %rax
movl (%rax), %esi
callq 0x16fa0
movq -0x8(%rbp), %rdi
movq -0x80(%rbp), %rax
movq 0x108(%rax), %rsi
leaq -0x88(%rbp), %rdx
xorl %eax, %eax
movl %eax, %ecx
callq 0xd6e0
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
movq -0x80(%rbp), %rax
movq 0x108(%rax), %rsi
callq 0x17470
movq -0x8(%rbp), %rax
movl 0x4e78(%rax), %eax
movl %eax, -0x8c(%rbp)
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
callq 0x16760
movq -0x8(%rbp), %rdi
addq $0x4e18, %rdi           # imm = 0x4E18
movq -0x48(%rbp), %rax
movq 0x108(%rax), %rsi
leaq 0x1bfb2b(%rip), %rdx    # 0x1d43f2
xorl %eax, %eax
movl %eax, %ecx
callq 0x23000
movq %rax, -0x98(%rbp)
movq -0x8(%rbp), %rax
movslq 0x4e78(%rax), %rax
movq %rax, -0xa0(%rbp)
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 -0x98(%rbp), %rax
movq 0x108(%rax), %rcx
movq -0xa0(%rbp), %r8
callq 0x1a030
movq %rax, -0xa8(%rbp)
movq -0x8(%rbp), %rdi
movq -0xa8(%rbp), %rsi
movq -0x50(%rbp), %rdx
callq 0x1e5b0
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
movl -0x8c(%rbp), %esi
movq -0x8(%rbp), %rax
movl 0x4e78(%rax), %edx
callq 0x18490
movq -0x8(%rbp), %rdi
movq -0x48(%rbp), %rsi
callq 0xd010
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
movq -0x98(%rbp), %rax
movl 0x110(%rax), %esi
callq 0x17bb0
movq -0x8(%rbp), %rdi
movq -0x98(%rbp), %rax
movq 0x108(%rax), %rsi
leaq -0xa0(%rbp), %rdx
callq 0xce30
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
movq -0x98(%rbp), %rax
movq 0x108(%rax), %rsi
callq 0x17470
movq -0x8(%rbp), %rdi
movq -0x48(%rbp), %rsi
callq 0xd010
addq $0xb0, %rsp
popq %rbp
retq
nopl (%rax,%rax)