// File: /workspace/github_c_makefile_star2_O2/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 0xe6a2
movl $0x10234980, %eax       # imm = 0x10234980
btl %r13d, %eax
jb 0xe6bf
movl $0x20c00000, %eax       # imm = 0x20C00000
btl %r13d, %eax
jb 0xe722
cmpl $0x1b, %r13d
jne 0xe6a2
testq %r12, %r12
je 0xe5fe
movq 0x5118(%r14), %rdi
leaq 0x5c876(%rip), %rsi     # 0x6ae6b
xorl %eax, %eax
callq *0x50f8(%r14)
movq %r15, %rdi
callq 0x10f6e
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 0xa337
cmpb $0x0, (%r15)
jne 0xe643
movq 0x5118(%r14), %rdi
leaq 0x5c869(%rip), %rsi     # 0x6aea3
xorl %eax, %eax
callq *0x50f8(%r14)
cmpb $0x1, 0xa(%rsp)
jne 0xe66b
leaq 0x4e18(%r14), %rdi
leaq 0x4220(%r14), %rsi
movq (%rbx), %rdx
callq 0x15100
movq %r14, %rdi
movq %rax, %rsi
callq 0xddbc
movq (%rbx), %rdx
movl (%rdx), %eax
cmpl $0x18, %eax
ja 0xe8ee
movl $0x1ec0000, %ecx        # imm = 0x1EC0000
btl %eax, %ecx
jae 0xe8ee
leaq 0x4e18(%r14), %rdi
addq $0x4220, %r14           # imm = 0x4220
movq %r14, %rsi
callq 0x15100
jmp 0xe8eb
leal -0x33(%r13), %eax
cmpl $0x16, %eax
ja 0xe83c
leaq 0x5bfda(%rip), %rcx     # 0x6a690
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 0xa337
cmpb $0x1, (%r15)
jne 0xe8ee
movq (%rbx), %rax
movl (%rax), %ecx
cmpl $0x18, %ecx
ja 0xe701
movl $0x1ec0000, %edx        # imm = 0x1EC0000
btl %ecx, %edx
jb 0xe8ee
addq $0x4e70, %r14           # imm = 0x4E70
movq 0x8(%rax), %rax
movl (%rax), %esi
movq %r14, %rdi
callq 0xee17
movq (%rbx), %rax
movq 0x8(%rax), %rax
jmp 0xe8eb
movq %r15, %rdi
callq 0x10f6e
movq %r14, %rdi
movq %rbx, %rsi
movq %r12, %rdx
callq 0xe58c
leaq 0x4e18(%r14), %rdi
movq (%rbx), %rsi
movl %r13d, %edx
callq 0x1584b
movq (%rbx), %rcx
testq %r12, %r12
je 0xe774
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 0x6394
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 0xf1d3
testq %r12, %r12
je 0xe862
movq 0x4bd8(%r14), %rax
movq %rax, (%r12)
jmp 0xe875
testq %r12, %r12
je 0xe898
movsd 0x4bd8(%r14), %xmm0
movsd %xmm0, (%r12)
jmp 0xe8ad
movq 0x4bd8(%r14), %rsi
testq %rsi, %rsi
js 0xe8be
testq %r12, %r12
je 0xe8fc
movq %rsi, (%r12)
jmp 0xe908
pushq $0x38
popq %rsi
movq %r15, %rdi
callq 0x118d3
andq $0x0, (%rbx)
movq %r14, %rdi
movq %rbx, %rsi
movq %r12, %rdx
callq 0xd3a5
pushq $0x39
popq %rsi
movq %r15, %rdi
addq $0x10, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
jmp 0x118d3
testq %r12, %r12
je 0xe8c9
movq 0x4bd8(%r14), %rax
movq %rax, (%r12)
jmp 0xe8dc
movq 0x50f8(%r14), %rcx
movq 0x5118(%r14), %rdi
leaq 0x5c666(%rip), %rsi     # 0x6aeb7
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 0xeb11
movq %r15, %rdi
callq 0x10f6e
leaq 0x4e18(%r14), %rdi
addq $0x4220, %r14           # imm = 0x4220
pushq $0x14
popq %rdx
movq %r14, %rsi
callq 0x14da9
jmp 0xe8eb
leaq 0x4e70(%r14), %rdi
movsd 0x4bd8(%r14), %xmm0
callq 0xeaec
movq %r15, %rdi
callq 0x10f6e
movq 0x5280(%r14), %rax
jmp 0xe8eb
testq %r12, %r12
je 0xe90f
movq %rsi, (%r12)
jmp 0xe91b
leaq 0x4e70(%r14), %rdi
movq 0x4bd8(%r14), %rsi
callq 0xea9e
movq %r15, %rdi
callq 0x10f6e
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 0xea9e
movl $0x5240, %eax           # imm = 0x5240
jmp 0xe920
leaq 0x4e70(%r14), %rdi
callq 0xeac5
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 0x10f6e