// File: /workspace/github_c_makefile_star2_O1/vtereshkov[P]umka-lang/src/umka_expr.c
// Function: parseFactor
static void parseFactor(Compiler *comp, const Type **type, Const *constant)
{
    switch (comp->lex.tok.kind)
    {
        case TOK_IDENT:
        case TOK_CARET:
        case TOK_WEAK:
        case TOK_LBRACKET:
        case TOK_STR:
        case TOK_ENUM:
        case TOK_MAP:
        case TOK_STRUCT:
        case TOK_INTERFACE:
        case TOK_FN:
        case TOK_LBRACE:
        case TOK_OR:
        case TOK_PERIOD:
        {
            // A designator that isVar is always an addressable quantity (a structured type or a pointer to a value type)
            bool isVar, isCall, isCompLit;
            parseDesignator(comp, type, constant, &isVar, &isCall, &isCompLit);
            if (isVar)
            {
                if (!typeStructured(*type))
                {
                    genDeref(&comp->gen, (*type)->base->kind);
                    *type = (*type)->base;
                }
            }
            break;
        }

        case TOK_INTNUMBER:
        {
            if (comp->lex.tok.uintVal > (uint64_t)INT64_MAX)
            {
                if (constant)
                    constant->uintVal = comp->lex.tok.uintVal;
                else
                    genPushUIntConst(&comp->gen, comp->lex.tok.uintVal);
                *type = comp->uintType;
            }
            else
            {
                if (constant)
                    constant->intVal = comp->lex.tok.intVal;
                else
                    genPushIntConst(&comp->gen, comp->lex.tok.intVal);
                *type = comp->intType;
            }
            lexNext(&comp->lex);
            break;
        }

        case TOK_REALNUMBER:
        {
            if (constant)
                constant->realVal = comp->lex.tok.realVal;
            else
                genPushRealConst(&comp->gen, comp->lex.tok.realVal);
            lexNext(&comp->lex);
            *type = comp->realType;
            break;
        }

        case TOK_CHARLITERAL:
        {
            if (constant)
                constant->uintVal = comp->lex.tok.uintVal;
            else
                genPushIntConst(&comp->gen, comp->lex.tok.intVal);
            lexNext(&comp->lex);
            *type = comp->charType;
            break;
        }

        case TOK_STRLITERAL:
        {
            if (constant)
                constant->ptrVal = comp->lex.tok.strVal;
            else
                genPushGlobalPtr(&comp->gen, comp->lex.tok.strVal);
            lexNext(&comp->lex);

            *type = typeAdd(&comp->types, &comp->blocks, TYPE_STR);
            break;
        }

        case TOK_PLUS:
        case TOK_MINUS:
        case TOK_NOT:
        case TOK_XOR:
        {
            TokenKind op = comp->lex.tok.kind;
            lexNext(&comp->lex);

            parseFactor(comp, type, constant);
            typeAssertValidOperator(&comp->types, *type, op);

            if (constant)
                constUnary(&comp->consts, constant, op, *type);
            else
                genUnary(&comp->gen, op, *type);
            break;
        }

        case TOK_AND:
        {
            if (constant)
                comp->error.handler(comp->error.context, "Address operator is not allowed in constant expressions");

            lexNext(&comp->lex);

            bool isVar, isCall, isCompLit;
            parseDesignator(comp, type, constant, &isVar, &isCall, &isCompLit);

            if (!isVar)
                comp->error.handler(comp->error.context, "Cannot take address");

            if (isCompLit)
                doEscapeToHeap(comp, typeAddPtrTo(&comp->types, &comp->blocks, *type));

            // A value type is already a pointer, a structured type needs to have it added
            if (typeStructured(*type))
                *type = typeAddPtrTo(&comp->types, &comp->blocks, *type);

            break;
        }

        case TOK_LPAR:
        {
            lexEat(&comp->lex, TOK_LPAR);

            *type = NULL;
            parseExpr(comp, type, constant);

            lexEat(&comp->lex, TOK_RPAR);
            break;
        }

        default: comp->error.handler(comp->error.context, "Illegal expression");
    }
}

// Assembly:
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x10, %rsp
movq %rdx, %r12
movq %rsi, %rbx
movq %rdi, %r14
leaq 0x4ba8(%rdi), %r15
movl 0x4bd0(%rdi), %r13d
cmpl $0x1d, %r13d
ja 0x17abb
movl $0x10234980, %eax       # imm = 0x10234980
btl %r13d, %eax
jb 0x17ad8
movl $0x20c00000, %eax       # imm = 0x20C00000
btl %r13d, %eax
jb 0x17b3b
cmpl $0x1b, %r13d
jne 0x17abb
testq %r12, %r12
je 0x17a17
movq 0x5118(%r14), %rdi
leaq 0x604b9(%rip), %rsi     # 0x77ec7
xorl %eax, %eax
callq *0x50f8(%r14)
movq %r15, %rdi
callq 0x1a984
leaq 0xc(%rsp), %r15
leaq 0xb(%rsp), %r8
leaq 0xa(%rsp), %r9
movq %r14, %rdi
movq %rbx, %rsi
movq %r12, %rdx
movq %r15, %rcx
callq 0x12ee0
cmpb $0x0, (%r15)
jne 0x17a5c
movq 0x5118(%r14), %rdi
leaq 0x604ac(%rip), %rsi     # 0x77eff
xorl %eax, %eax
callq *0x50f8(%r14)
cmpb $0x1, 0xa(%rsp)
jne 0x17a84
leaq 0x4e18(%r14), %rdi
leaq 0x4220(%r14), %rsi
movq (%rbx), %rdx
callq 0x1edd3
movq %r14, %rdi
movq %rax, %rsi
callq 0x170f1
movq (%rbx), %rdx
movl (%rdx), %eax
cmpl $0x18, %eax
ja 0x17d10
movl $0x1ec0000, %ecx        # imm = 0x1EC0000
btl %eax, %ecx
jae 0x17d10
leaq 0x4e18(%r14), %rdi
addq $0x4220, %r14           # imm = 0x4220
movq %r14, %rsi
callq 0x1edd3
jmp 0x17d0d
leal -0x33(%r13), %eax
cmpl $0x16, %eax
ja 0x17c5c
leaq 0x5fc1d(%rip), %rcx     # 0x776ec
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
leaq 0xf(%rsp), %r15
leaq 0xe(%rsp), %r8
leaq 0xd(%rsp), %r9
movq %r14, %rdi
movq %rbx, %rsi
movq %r12, %rdx
movq %r15, %rcx
callq 0x12ee0
cmpb $0x1, (%r15)
jne 0x17d10
movq (%rbx), %rax
movl (%rax), %ecx
cmpl $0x18, %ecx
ja 0x17b1a
movl $0x1ec0000, %edx        # imm = 0x1EC0000
btl %ecx, %edx
jb 0x17d10
addq $0x4e70, %r14           # imm = 0x4E70
movq 0x8(%rax), %rax
movl (%rax), %esi
movq %r14, %rdi
callq 0x182ba
movq (%rbx), %rax
movq 0x8(%rax), %rax
jmp 0x17d0d
movq %r15, %rdi
callq 0x1a984
movq %r14, %rdi
movq %rbx, %rsi
movq %r12, %rdx
callq 0x179a5
leaq 0x4e18(%r14), %rdi
movq (%rbx), %rsi
movl %r13d, %edx
callq 0x1f51c
movq (%rbx), %rcx
testq %r12, %r12
je 0x17b8d
addq $0x4e68, %r14           # imm = 0x4E68
movq %r14, %rdi
movq %r12, %rsi
movl %r13d, %edx
addq $0x10, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
jmp 0xf0e0
addq $0x4e70, %r14           # imm = 0x4E70
movq %r14, %rdi
movl %r13d, %esi
movq %rcx, %rdx
addq $0x10, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
jmp 0x1872d
testq %r12, %r12
je 0x17c82
movq 0x4bd8(%r14), %rax
movq %rax, (%r12)
jmp 0x17c95
testq %r12, %r12
je 0x17cba
movsd 0x4bd8(%r14), %xmm0
movsd %xmm0, (%r12)
jmp 0x17ccf
movq 0x4bd8(%r14), %rsi
testq %rsi, %rsi
js 0x17ce0
testq %r12, %r12
je 0x17d1e
movq %rsi, (%r12)
jmp 0x17d2a
movq %r15, %rdi
movl $0x38, %esi
callq 0x1b41f
movq $0x0, (%rbx)
movq %r14, %rdi
movq %rbx, %rsi
movq %r12, %rdx
callq 0x1617b
movq %r15, %rdi
movl $0x39, %esi
addq $0x10, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
jmp 0x1b41f
testq %r12, %r12
je 0x17ceb
movq 0x4bd8(%r14), %rax
movq %rax, (%r12)
jmp 0x17cfe
movq 0x50f8(%r14), %rcx
movq 0x5118(%r14), %rdi
leaq 0x602a2(%rip), %rsi     # 0x77f13
xorl %eax, %eax
addq $0x10, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
jmpq *%rcx
leaq 0x4e70(%r14), %rdi
movq 0x4bd8(%r14), %rsi
callq 0x17f4c
movq %r15, %rdi
callq 0x1a984
leaq 0x4e18(%r14), %rdi
addq $0x4220, %r14           # imm = 0x4220
movq %r14, %rsi
movl $0x14, %edx
callq 0x1ea48
jmp 0x17d0d
leaq 0x4e70(%r14), %rdi
movsd 0x4bd8(%r14), %xmm0
callq 0x17f22
movq %r15, %rdi
callq 0x1a984
movq 0x5280(%r14), %rax
jmp 0x17d0d
testq %r12, %r12
je 0x17d31
movq %rsi, (%r12)
jmp 0x17d3d
leaq 0x4e70(%r14), %rdi
movq 0x4bd8(%r14), %rsi
callq 0x17eca
movq %r15, %rdi
callq 0x1a984
movq 0x5270(%r14), %rax
movq %rax, (%rbx)
addq $0x10, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
retq
leaq 0x4e70(%r14), %rdi
callq 0x17eca
movl $0x5240, %eax           # imm = 0x5240
jmp 0x17d42
leaq 0x4e70(%r14), %rdi
callq 0x17ef6
movl $0x5260, %eax           # imm = 0x5260
movq (%r14,%rax), %rax
movq %rax, (%rbx)
movq %r15, %rdi
addq $0x10, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
jmp 0x1a984
nop