// File: /workspace/github_c_makefile_star2_O0/vtereshkov[P]umka-lang/src/umka_expr.c
// Function: parseCall
static void parseCall(Compiler *comp, const Type **type)
{
    lexEat(&comp->lex, TOK_LPAR);

    // Decide whether a (default) indirect call can be replaced with a direct call
    int immediateEntryPoint = (*type)->kind == TYPE_FN ? genTryRemoveImmediateEntryPoint(&comp->gen) : -1;

    // Actual parameters: [#self,] param1, param2 ...[#result]
    int numExplicitParams = 0, numPreHiddenParams = 0, numPostHiddenParams = 0;
    int i = 0;

    if ((*type)->kind == TYPE_CLOSURE)
    {
        // Closure upvalue
        const Field *fn = typeAssertFindField(&comp->types, *type, "#fn", NULL);
        *type = fn->type;

        genPushUpvalue(&comp->gen);
        doPassParam(comp, (*type)->sig.param[0]->type);

        numPreHiddenParams++;
        i++;
    }
    else if ((*type)->sig.isMethod)
    {
        // Method receiver
        genPushReg(&comp->gen, REG_SELF);

        // Increase receiver's reference count
        genChangeRefCnt(&comp->gen, TOK_PLUSPLUS, (*type)->sig.param[0]->type);

        numPreHiddenParams++;
        i++;
    }
    else
    {
        // Dummy upvalue
        genPushZero(&comp->gen, sizeof(Interface) / sizeof(Slot));

        numPreHiddenParams++;
        i++;
    }

    // #result
    if (typeStructured((*type)->sig.resultType))
        numPostHiddenParams++;

    if (comp->lex.tok.kind != TOK_RPAR)
    {
        while (1)
        {
            if (numPreHiddenParams + numExplicitParams + numPostHiddenParams > (*type)->sig.numParams - 1)
            {
                char fnTypeBuf[DEFAULT_STR_LEN + 1];
                comp->error.handler(comp->error.context, "Too many actual parameters to %s", typeSpelling(*type, fnTypeBuf));
            }

            const Type *formalParamType = (*type)->sig.param[i]->type;
            const Type *actualParamType = formalParamType;

            if (formalParamType->isVariadicParamList)
            {
                // Variadic parameter list
                parseDynArrayLiteral(comp, &formalParamType, NULL);
                actualParamType = formalParamType;
            }
            else
            {
                // Regular parameter
                parseExpr(comp, &actualParamType, NULL);

                doImplicitTypeConv(comp, formalParamType, &actualParamType, NULL);
                typeAssertCompatibleParam(&comp->types, formalParamType, actualParamType, *type, numExplicitParams + 1);
            }

            doPassParam(comp, formalParamType);
            numExplicitParams++;
            i++;

            if (comp->lex.tok.kind != TOK_COMMA)
                break;
            lexNext(&comp->lex);
        }
    }

    // Allow closing parenthesis on a new line
    if (comp->lex.tok.kind == TOK_IMPLICIT_SEMICOLON)
        lexNext(&comp->lex);

    int numDefaultOrVariadicFormalParams = 0;

    if ((*type)->sig.numDefaultParams > 0)
        numDefaultOrVariadicFormalParams = (*type)->sig.numDefaultParams;
    else if ((*type)->sig.numParams > 0 && (*type)->sig.param[(*type)->sig.numParams - 1]->type->isVariadicParamList)
        numDefaultOrVariadicFormalParams = 1;

    if (numPreHiddenParams + numExplicitParams + numPostHiddenParams < (*type)->sig.numParams - numDefaultOrVariadicFormalParams)
    {
        char fnTypeBuf[DEFAULT_STR_LEN + 1];
        comp->error.handler(comp->error.context, "Too few actual parameters to %s", typeSpelling(*type, fnTypeBuf));
    }

    // Push default or variadic parameters, if not specified explicitly
    while (i + numPostHiddenParams < (*type)->sig.numParams)
    {
        const Type *formalParamType = (*type)->sig.param[i]->type;

        if ((*type)->sig.numDefaultParams > 0)
            doPushConst(comp, formalParamType, &((*type)->sig.param[i]->defaultVal));   // Default parameter
        else
            parseDynArrayLiteral(comp, &formalParamType, NULL);                         // Variadic parameter (empty dynamic array)

        doPassParam(comp, formalParamType);
        i++;
    }

    // Push #result pointer
    if (typeStructured((*type)->sig.resultType))
    {
        int offset = identAllocStack(&comp->idents, &comp->types, &comp->blocks, (*type)->sig.resultType);
        genPushLocalPtr(&comp->gen, offset);
        i++;
    }

    if (immediateEntryPoint > 0)
        genCall(&comp->gen, immediateEntryPoint);                                           // Direct call
    else if (immediateEntryPoint < 0)
    {
        int paramSlots = typeParamSizeTotal(&comp->types, &(*type)->sig) / sizeof(Slot);
        genCallIndirect(&comp->gen, paramSlots);                                            // Indirect call
        genPop(&comp->gen);                                                                 // Pop entry point
    }
    else
        comp->error.handler(comp->error.context, "Called function is not defined");

    *type = (*type)->sig.resultType;

    lexEat(&comp->lex, TOK_RPAR);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x290, %rsp            # imm = 0x290
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq -0x8(%rbp), %rdi
addq $0x4ba8, %rdi           # imm = 0x4BA8
movl $0x38, %esi
callq 0x1b150
movq -0x10(%rbp), %rax
movq (%rax), %rax
cmpl $0x1a, (%rax)
jne 0x155bc
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
callq 0x18bc0
movl %eax, -0x264(%rbp)
jmp 0x155c9
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
movl %eax, -0x264(%rbp)
jmp 0x155c9
movl -0x264(%rbp), %eax
movl %eax, -0x14(%rbp)
movl $0x0, -0x18(%rbp)
movl $0x0, -0x1c(%rbp)
movl $0x0, -0x20(%rbp)
movl $0x0, -0x24(%rbp)
movq -0x10(%rbp), %rax
movq (%rax), %rax
cmpl $0x18, (%rax)
jne 0x15674
movq -0x8(%rbp), %rdi
addq $0x4e18, %rdi           # imm = 0x4E18
movq -0x10(%rbp), %rax
movq (%rax), %rsi
leaq 0x1beddf(%rip), %rdx    # 0x1d43f2
xorl %eax, %eax
movl %eax, %ecx
callq 0x23000
movq %rax, -0x30(%rbp)
movq -0x30(%rbp), %rax
movq 0x108(%rax), %rcx
movq -0x10(%rbp), %rax
movq %rcx, (%rax)
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
callq 0x16c20
movq -0x8(%rbp), %rdi
movq -0x10(%rbp), %rax
movq (%rax), %rax
movq 0x38(%rax), %rax
movq 0x108(%rax), %rsi
callq 0x15b70
movl -0x1c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1c(%rbp)
movl -0x24(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x24(%rbp)
jmp 0x156fa
movq -0x10(%rbp), %rax
movq (%rax), %rax
testb $0x1, 0x30(%rax)
je 0x156d1
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
movl $0x1, %esi
callq 0x16b60
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
movq -0x10(%rbp), %rax
movq (%rax), %rax
movq 0x38(%rax), %rax
movq 0x108(%rax), %rdx
movl $0x2c, %esi
callq 0x17270
movl -0x1c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1c(%rbp)
movl -0x24(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x24(%rbp)
jmp 0x156f8
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
movl $0x2, %esi
callq 0x16c70
movl -0x1c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1c(%rbp)
movl -0x24(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x24(%rbp)
jmp 0x156fa
movq -0x10(%rbp), %rax
movq (%rax), %rax
movq 0xb8(%rax), %rdi
callq 0xcfa0
testb $0x1, %al
jne 0x15713
jmp 0x1571c
movl -0x20(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x20(%rbp)
movq -0x8(%rbp), %rax
cmpl $0x39, 0x4bd0(%rax)
je 0x1589d
jmp 0x1572f
movl -0x1c(%rbp), %eax
addl -0x18(%rbp), %eax
addl -0x20(%rbp), %eax
movq -0x10(%rbp), %rcx
movq (%rcx), %rcx
movl 0x28(%rcx), %ecx
subl $0x1, %ecx
cmpl %ecx, %eax
jle 0x1579c
movq -0x8(%rbp), %rax
movq 0x50f8(%rax), %rax
movq %rax, -0x270(%rbp)
movq -0x8(%rbp), %rax
movq 0x5118(%rax), %rax
movq %rax, -0x278(%rbp)
movq -0x10(%rbp), %rax
movq (%rax), %rdi
leaq -0x130(%rbp), %rsi
callq 0x22070
movq -0x278(%rbp), %rdi
movq -0x270(%rbp), %rcx
movq %rax, %rdx
leaq 0x1c37b7(%rip), %rsi    # 0x1d8f4f
movb $0x0, %al
callq *%rcx
movq -0x10(%rbp), %rax
movq (%rax), %rax
movslq -0x24(%rbp), %rcx
movq 0x38(%rax,%rcx,8), %rax
movq 0x108(%rax), %rax
movq %rax, -0x138(%rbp)
movq -0x138(%rbp), %rax
movq %rax, -0x140(%rbp)
movq -0x138(%rbp), %rax
testb $0x1, 0x15(%rax)
je 0x157f9
movq -0x8(%rbp), %rdi
leaq -0x138(%rbp), %rsi
xorl %eax, %eax
movl %eax, %edx
callq 0x13d40
movq -0x138(%rbp), %rax
movq %rax, -0x140(%rbp)
jmp 0x15855
movq -0x8(%rbp), %rdi
leaq -0x140(%rbp), %rsi
xorl %eax, %eax
movl %eax, %edx
callq 0xe8c0
movq -0x8(%rbp), %rdi
movq -0x138(%rbp), %rsi
leaq -0x140(%rbp), %rdx
xorl %eax, %eax
movl %eax, %ecx
callq 0xd190
movq -0x8(%rbp), %rdi
addq $0x4e18, %rdi           # imm = 0x4E18
movq -0x138(%rbp), %rsi
movq -0x140(%rbp), %rdx
movq -0x10(%rbp), %rax
movq (%rax), %rcx
movl -0x18(%rbp), %r8d
addl $0x1, %r8d
callq 0x22920
movq -0x8(%rbp), %rdi
movq -0x138(%rbp), %rsi
callq 0x15b70
movl -0x18(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x18(%rbp)
movl -0x24(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x24(%rbp)
movq -0x8(%rbp), %rax
cmpl $0x3f, 0x4bd0(%rax)
je 0x15886
jmp 0x1589b
movq -0x8(%rbp), %rdi
addq $0x4ba8, %rdi           # imm = 0x4BA8
callq 0x1ad90
jmp 0x1572f
jmp 0x1589d
movq -0x8(%rbp), %rax
cmpl $0x4a, 0x4bd0(%rax)
jne 0x158ba
movq -0x8(%rbp), %rdi
addq $0x4ba8, %rdi           # imm = 0x4BA8
callq 0x1ad90
movl $0x0, -0x144(%rbp)
movq -0x10(%rbp), %rax
movq (%rax), %rax
cmpl $0x0, 0x2c(%rax)
jle 0x158e3
movq -0x10(%rbp), %rax
movq (%rax), %rax
movl 0x2c(%rax), %eax
movl %eax, -0x144(%rbp)
jmp 0x15925
movq -0x10(%rbp), %rax
movq (%rax), %rax
cmpl $0x0, 0x28(%rax)
jle 0x15923
movq -0x10(%rbp), %rax
movq (%rax), %rax
movq -0x10(%rbp), %rcx
movq (%rcx), %rcx
movl 0x28(%rcx), %ecx
subl $0x1, %ecx
movslq %ecx, %rcx
movq 0x38(%rax,%rcx,8), %rax
movq 0x108(%rax), %rax
testb $0x1, 0x15(%rax)
je 0x15923
movl $0x1, -0x144(%rbp)
jmp 0x15925
movl -0x1c(%rbp), %eax
addl -0x18(%rbp), %eax
addl -0x20(%rbp), %eax
movq -0x10(%rbp), %rcx
movq (%rcx), %rcx
movl 0x28(%rcx), %ecx
subl -0x144(%rbp), %ecx
cmpl %ecx, %eax
jge 0x15995
movq -0x8(%rbp), %rax
movq 0x50f8(%rax), %rax
movq %rax, -0x280(%rbp)
movq -0x8(%rbp), %rax
movq 0x5118(%rax), %rax
movq %rax, -0x288(%rbp)
movq -0x10(%rbp), %rax
movq (%rax), %rdi
leaq -0x250(%rbp), %rsi
callq 0x22070
movq -0x288(%rbp), %rdi
movq -0x280(%rbp), %rcx
movq %rax, %rdx
leaq 0x1c35df(%rip), %rsi    # 0x1d8f70
movb $0x0, %al
callq *%rcx
jmp 0x15997
movl -0x24(%rbp), %eax
addl -0x20(%rbp), %eax
movq -0x10(%rbp), %rcx
movq (%rcx), %rcx
cmpl 0x28(%rcx), %eax
jge 0x15a33
movq -0x10(%rbp), %rax
movq (%rax), %rax
movslq -0x24(%rbp), %rcx
movq 0x38(%rax,%rcx,8), %rax
movq 0x108(%rax), %rax
movq %rax, -0x258(%rbp)
movq -0x10(%rbp), %rax
movq (%rax), %rax
cmpl $0x0, 0x2c(%rax)
jle 0x15a01
movq -0x8(%rbp), %rdi
movq -0x258(%rbp), %rsi
movq -0x10(%rbp), %rax
movq (%rax), %rax
movslq -0x24(%rbp), %rcx
movq 0x38(%rax,%rcx,8), %rdx
addq $0x110, %rdx            # imm = 0x110
callq 0xce30
jmp 0x15a15
movq -0x8(%rbp), %rdi
leaq -0x258(%rbp), %rsi
xorl %eax, %eax
movl %eax, %edx
callq 0x13d40
movq -0x8(%rbp), %rdi
movq -0x258(%rbp), %rsi
callq 0x15b70
movl -0x24(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x24(%rbp)
jmp 0x15997
movq -0x10(%rbp), %rax
movq (%rax), %rax
movq 0xb8(%rax), %rdi
callq 0xcfa0
testb $0x1, %al
jne 0x15a4c
jmp 0x15aa5
movq -0x8(%rbp), %rdi
addq $0x4e38, %rdi           # imm = 0x4E38
movq -0x8(%rbp), %rsi
addq $0x4e18, %rsi           # imm = 0x4E18
movq -0x8(%rbp), %rdx
addq $0x4220, %rdx           # imm = 0x4220
movq -0x10(%rbp), %rax
movq (%rax), %rax
movq 0xb8(%rax), %rcx
callq 0x1a320
movl %eax, -0x25c(%rbp)
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
movl -0x25c(%rbp), %esi
callq 0x169a0
movl -0x24(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x24(%rbp)
cmpl $0x0, -0x14(%rbp)
jle 0x15ac0
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
movl -0x14(%rbp), %esi
callq 0x17f50
jmp 0x15b38
cmpl $0x0, -0x14(%rbp)
jge 0x15b15
movq -0x8(%rbp), %rdi
addq $0x4e18, %rdi           # imm = 0x4E18
movq -0x10(%rbp), %rax
movq (%rax), %rsi
addq $0x28, %rsi
callq 0x23920
cltq
shrq $0x3, %rax
movl %eax, -0x260(%rbp)
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
movl -0x260(%rbp), %esi
callq 0x17fa0
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
callq 0x16d30
jmp 0x15b36
movq -0x8(%rbp), %rax
movq 0x50f8(%rax), %rcx
movq -0x8(%rbp), %rax
movq 0x5118(%rax), %rdi
leaq 0x1c345e(%rip), %rsi    # 0x1d8f90
movb $0x0, %al
callq *%rcx
jmp 0x15b38
movq -0x10(%rbp), %rax
movq (%rax), %rax
movq 0xb8(%rax), %rcx
movq -0x10(%rbp), %rax
movq %rcx, (%rax)
movq -0x8(%rbp), %rdi
addq $0x4ba8, %rdi           # imm = 0x4BA8
movl $0x39, %esi
callq 0x1b150
addq $0x290, %rsp            # imm = 0x290
popq %rbp
retq
nopl (%rax,%rax)