// File: /workspace/github_c_makefile_star2_O0/vtereshkov[P]umka-lang/src/umka_expr.c
// Function: parseArrayOrStructLiteral
static void parseArrayOrStructLiteral(Compiler *comp, const Type **type, Const *constant)
{
    lexEat(&comp->lex, TOK_LBRACE);

    bool namedFields = false;
    bool *fieldInitialized = NULL;

    if ((*type)->kind == TYPE_STRUCT)
    {
        if (comp->lex.tok.kind == TOK_RBRACE)
            namedFields = true;
        else if (comp->lex.tok.kind == TOK_IDENT)
        {
            Lexer lookaheadLex = comp->lex;
            lexNext(&lookaheadLex);
            namedFields = lookaheadLex.tok.kind == TOK_COLON;
        }
    }

    if (namedFields)
        fieldInitialized = storageAdd(&comp->storage, (*type)->numItems + 1);

    const int size = typeSize(&comp->types, *type);
    const Ident *arrayOrStruct = NULL;

    if (constant)
    {
        constant->ptrVal = storageAdd(&comp->storage, size);
        if (namedFields)
            constZero(constant->ptrVal, size);
    }
    else
    {
        arrayOrStruct = identAllocTempVar(&comp->idents, &comp->types, &comp->modules, &comp->blocks, *type, false);
        doZeroVar(comp, arrayOrStruct);
    }

    int numItems = 0, itemOffset = 0;
    while (comp->lex.tok.kind != TOK_RBRACE)
    {
        if (!namedFields && numItems > (*type)->numItems - 1)
            comp->error.handler(comp->error.context, "Too many elements in literal");

        // [ident ":"]
        const Field *field = NULL;
        if (namedFields)
        {
            lexCheck(&comp->lex, TOK_IDENT);

            int fieldIndex = 0;
            field = typeAssertFindField(&comp->types, *type, comp->lex.tok.name, &fieldIndex);

            if (field && fieldInitialized[fieldIndex])
                comp->error.handler(comp->error.context, "Duplicate field %s", field->name);

            fieldInitialized[fieldIndex] = true;
            itemOffset = field->offset;

            lexNext(&comp->lex);
            lexEat(&comp->lex, TOK_COLON);
        }
        else if ((*type)->kind == TYPE_STRUCT)
        {
            field = (*type)->field[numItems];
            if (field && identIsHidden(field->name))
                comp->error.handler(comp->error.context, "Cannot initialize hidden field");

            itemOffset = field->offset;
        }

        if (!constant)
            genPushLocalPtr(&comp->gen, arrayOrStruct->offset + itemOffset);

        const Type *expectedItemType = (*type)->kind == TYPE_ARRAY ? (*type)->base : field->type;
        const Type *itemType = expectedItemType;
        Const itemConstantBuf, *itemConstant = constant ? &itemConstantBuf : NULL;
        const int itemSize = typeSize(&comp->types, expectedItemType);

        // expr
        parseExpr(comp, &itemType, itemConstant);
        doAssertImplicitTypeConv(comp, expectedItemType, &itemType, itemConstant);

        if (constant)
            constAssign(&comp->consts, (char *)constant->ptrVal + itemOffset, itemConstant, expectedItemType->kind, itemSize);
        else
        {
            if (doTryRemoveCopyResultToTempVar(comp))
            {
                // Optimization: if the right-hand side is a function call, assume its reference count to be already increased before return
                // The left-hand side will hold this additional reference, so we can remove the temporary "reference holder" variable
                genAssign(&comp->gen, expectedItemType->kind, itemSize);
            }
            else
            {
                // General case: update reference counts for both sides
                genChangeRefCntAssign(&comp->gen, expectedItemType);
            }
        }

        numItems++;
        if ((*type)->kind == TYPE_ARRAY)
            itemOffset += itemSize;

        if (comp->lex.tok.kind != TOK_COMMA)
            break;
        lexNext(&comp->lex);
    }

    if (!namedFields && numItems < (*type)->numItems)
        comp->error.handler(comp->error.context, "Too few elements in literal");

    if (!constant)
        doPushVarPtr(comp, arrayOrStruct);

    // Allow closing brace on a new line
    if (comp->lex.tok.kind == TOK_IMPLICIT_SEMICOLON)
        lexNext(&comp->lex);

    lexEat(&comp->lex, TOK_RBRACE);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x300, %rsp            # imm = 0x300
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
movb $0x0, -0x19(%rbp)
movq $0x0, -0x28(%rbp)
movq -0x10(%rbp), %rax
movq (%rax), %rax
cmpl $0x16, (%rax)
jne 0x1380f
movq -0x8(%rbp), %rax
cmpl $0x3d, 0x4bd0(%rax)
jne 0x137c7
movb $0x1, -0x19(%rbp)
jmp 0x1380d
movq -0x8(%rbp), %rax
cmpl $0x45, 0x4bd0(%rax)
jne 0x1380b
movq -0x8(%rbp), %rsi
addq $0x4ba8, %rsi           # imm = 0x4BA8
leaq -0x298(%rbp), %rdi
movl $0x270, %edx            # imm = 0x270
callq 0x3270
leaq -0x298(%rbp), %rdi
callq 0x1ad90
cmpl $0x41, -0x270(%rbp)
sete %al
andb $0x1, %al
movb %al, -0x19(%rbp)
jmp 0x1380d
jmp 0x1380f
testb $0x1, -0x19(%rbp)
je 0x13839
movq -0x8(%rbp), %rdi
addq $0xf0, %rdi
movq -0x10(%rbp), %rax
movq (%rax), %rax
movl 0x10(%rax), %eax
addl $0x1, %eax
movslq %eax, %rsi
callq 0x4b20
movq %rax, -0x28(%rbp)
movq -0x8(%rbp), %rdi
addq $0x4e18, %rdi           # imm = 0x4E18
movq -0x10(%rbp), %rax
movq (%rax), %rsi
callq 0x21fe0
movl %eax, -0x29c(%rbp)
movq $0x0, -0x2a8(%rbp)
cmpq $0x0, -0x18(%rbp)
je 0x138a3
movq -0x8(%rbp), %rdi
addq $0xf0, %rdi
movslq -0x29c(%rbp), %rsi
callq 0x4b20
movq %rax, %rcx
movq -0x18(%rbp), %rax
movq %rcx, (%rax)
testb $0x1, -0x19(%rbp)
je 0x138a1
movq -0x18(%rbp), %rax
movq (%rax), %rdi
movl -0x29c(%rbp), %esi
callq 0x8680
jmp 0x138f5
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, -0x2a8(%rbp)
movq -0x8(%rbp), %rdi
movq -0x2a8(%rbp), %rsi
callq 0x1d5e0
movl $0x0, -0x2ac(%rbp)
movl $0x0, -0x2b0(%rbp)
movq -0x8(%rbp), %rax
cmpl $0x3d, 0x4bd0(%rax)
je 0x13caa
testb $0x1, -0x19(%rbp)
jne 0x13958
movl -0x2ac(%rbp), %eax
movq -0x10(%rbp), %rcx
movq (%rcx), %rcx
movl 0x10(%rcx), %ecx
subl $0x1, %ecx
cmpl %ecx, %eax
jle 0x13958
movq -0x8(%rbp), %rax
movq 0x50f8(%rax), %rcx
movq -0x8(%rbp), %rax
movq 0x5118(%rax), %rdi
leaq 0x1c5445(%rip), %rsi    # 0x1d8d99
movb $0x0, %al
callq *%rcx
movq $0x0, -0x2b8(%rbp)
testb $0x1, -0x19(%rbp)
je 0x13a50
movq -0x8(%rbp), %rdi
addq $0x4ba8, %rdi           # imm = 0x4BA8
movl $0x45, %esi
callq 0x1b080
movl $0x0, -0x2bc(%rbp)
movq -0x8(%rbp), %rdi
addq $0x4e18, %rdi           # imm = 0x4E18
movq -0x10(%rbp), %rax
movq (%rax), %rsi
movq -0x8(%rbp), %rdx
addq $0x4ba8, %rdx           # imm = 0x4BA8
addq $0x28, %rdx
addq $0x8, %rdx
leaq -0x2bc(%rbp), %rcx
callq 0x23000
movq %rax, -0x2b8(%rbp)
cmpq $0x0, -0x2b8(%rbp)
je 0x13a07
movq -0x28(%rbp), %rax
movslq -0x2bc(%rbp), %rcx
testb $0x1, (%rax,%rcx)
je 0x13a07
movq -0x8(%rbp), %rax
movq 0x50f8(%rax), %rcx
movq -0x8(%rbp), %rax
movq 0x5118(%rax), %rdi
movq -0x2b8(%rbp), %rdx
leaq 0x1c53b3(%rip), %rsi    # 0x1d8db6
movb $0x0, %al
callq *%rcx
movq -0x28(%rbp), %rax
movslq -0x2bc(%rbp), %rcx
movb $0x1, (%rax,%rcx)
movq -0x2b8(%rbp), %rax
movl 0x110(%rax), %eax
movl %eax, -0x2b0(%rbp)
movq -0x8(%rbp), %rdi
addq $0x4ba8, %rdi           # imm = 0x4BA8
callq 0x1ad90
movq -0x8(%rbp), %rdi
addq $0x4ba8, %rdi           # imm = 0x4BA8
movl $0x41, %esi
callq 0x1b150
jmp 0x13acb
movq -0x10(%rbp), %rax
movq (%rax), %rax
cmpl $0x16, (%rax)
jne 0x13ac9
movq -0x10(%rbp), %rax
movq (%rax), %rax
movq 0x28(%rax), %rax
movslq -0x2ac(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0x2b8(%rbp)
cmpq $0x0, -0x2b8(%rbp)
je 0x13ab6
movq -0x2b8(%rbp), %rdi
callq 0x149e0
testb $0x1, %al
jne 0x13a95
jmp 0x13ab6
movq -0x8(%rbp), %rax
movq 0x50f8(%rax), %rcx
movq -0x8(%rbp), %rax
movq 0x5118(%rax), %rdi
leaq 0x1c5317(%rip), %rsi    # 0x1d8dc9
movb $0x0, %al
callq *%rcx
movq -0x2b8(%rbp), %rax
movl 0x110(%rax), %eax
movl %eax, -0x2b0(%rbp)
jmp 0x13acb
cmpq $0x0, -0x18(%rbp)
jne 0x13afc
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
movq -0x2a8(%rbp), %rax
movq 0x120(%rax), %rax
movslq -0x2b0(%rbp), %rcx
addq %rcx, %rax
movl %eax, %esi
callq 0x169a0
movq -0x10(%rbp), %rax
movq (%rax), %rax
cmpl $0x12, (%rax)
jne 0x13b1c
movq -0x10(%rbp), %rax
movq (%rax), %rax
movq 0x8(%rax), %rax
movq %rax, -0x2f0(%rbp)
jmp 0x13b31
movq -0x2b8(%rbp), %rax
movq 0x108(%rax), %rax
movq %rax, -0x2f0(%rbp)
movq -0x2f0(%rbp), %rax
movq %rax, -0x2c8(%rbp)
movq -0x2c8(%rbp), %rax
movq %rax, -0x2d0(%rbp)
cmpq $0x0, -0x18(%rbp)
je 0x13b64
leaq -0x2d8(%rbp), %rax
movq %rax, -0x2f8(%rbp)
jmp 0x13b6f
xorl %eax, %eax
movq %rax, -0x2f8(%rbp)
jmp 0x13b6f
movq -0x2f8(%rbp), %rax
movq %rax, -0x2e0(%rbp)
movq -0x8(%rbp), %rdi
addq $0x4e18, %rdi           # imm = 0x4E18
movq -0x2c8(%rbp), %rsi
callq 0x21fe0
movl %eax, -0x2e4(%rbp)
movq -0x8(%rbp), %rdi
movq -0x2e0(%rbp), %rdx
leaq -0x2d0(%rbp), %rsi
callq 0xe8c0
movq -0x8(%rbp), %rdi
movq -0x2c8(%rbp), %rsi
movq -0x2e0(%rbp), %rcx
leaq -0x2d0(%rbp), %rdx
callq 0xd6e0
cmpq $0x0, -0x18(%rbp)
je 0x13c10
movq -0x8(%rbp), %rdi
addq $0x4e68, %rdi           # imm = 0x4E68
movq -0x18(%rbp), %rax
movq (%rax), %rsi
movslq -0x2b0(%rbp), %rax
addq %rax, %rsi
movq -0x2e0(%rbp), %rdx
movq -0x2c8(%rbp), %rax
movl (%rax), %ecx
movl -0x2e4(%rbp), %r8d
callq 0x88c0
jmp 0x13c59
movq -0x8(%rbp), %rdi
callq 0xd0f0
testb $0x1, %al
jne 0x13c1f
jmp 0x13c40
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
movq -0x2c8(%rbp), %rax
movl (%rax), %esi
movl -0x2e4(%rbp), %edx
callq 0x170d0
jmp 0x13c57
movq -0x8(%rbp), %rdi
addq $0x4e70, %rdi           # imm = 0x4E70
movq -0x2c8(%rbp), %rsi
callq 0x17470
jmp 0x13c59
movl -0x2ac(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x2ac(%rbp)
movq -0x10(%rbp), %rax
movq (%rax), %rax
cmpl $0x12, (%rax)
jne 0x13c86
movl -0x2e4(%rbp), %eax
addl -0x2b0(%rbp), %eax
movl %eax, -0x2b0(%rbp)
movq -0x8(%rbp), %rax
cmpl $0x3f, 0x4bd0(%rax)
je 0x13c95
jmp 0x13caa
movq -0x8(%rbp), %rdi
addq $0x4ba8, %rdi           # imm = 0x4BA8
callq 0x1ad90
jmp 0x13909
testb $0x1, -0x19(%rbp)
jne 0x13ce3
movl -0x2ac(%rbp), %eax
movq -0x10(%rbp), %rcx
movq (%rcx), %rcx
cmpl 0x10(%rcx), %eax
jge 0x13ce3
movq -0x8(%rbp), %rax
movq 0x50f8(%rax), %rcx
movq -0x8(%rbp), %rax
movq 0x5118(%rax), %rdi
leaq 0x1c5109(%rip), %rsi    # 0x1d8de8
movb $0x0, %al
callq *%rcx
cmpq $0x0, -0x18(%rbp)
jne 0x13cfa
movq -0x8(%rbp), %rdi
movq -0x2a8(%rbp), %rsi
callq 0xd010
movq -0x8(%rbp), %rax
cmpl $0x4a, 0x4bd0(%rax)
jne 0x13d17
movq -0x8(%rbp), %rdi
addq $0x4ba8, %rdi           # imm = 0x4BA8
callq 0x1ad90
movq -0x8(%rbp), %rdi
addq $0x4ba8, %rdi           # imm = 0x4BA8
movl $0x3d, %esi
callq 0x1b150
addq $0x300, %rsp            # imm = 0x300
popq %rbp
retq
nopw %cs:(%rax,%rax)