// File: /workspace/github_c_makefile_star2_O3/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 0x12a3a
movl $0x10234980, %eax       # imm = 0x10234980
btl %r13d, %eax
jb 0x12a57
movl $0x20c00000, %eax       # imm = 0x20C00000
btl %r13d, %eax
jb 0x12aba
cmpl $0x1b, %r13d
jne 0x12a3a
testq %r12, %r12
je 0x12c9e
movq 0x5118(%r14), %rdi
leaq 0x644bb(%rip), %rsi     # 0x76ec7
xorl %eax, %eax
callq *0x50f8(%r14)
movq %r15, %rdi
callq 0x15914
leaq 0xb(%rsp), %rcx
leaq 0xc(%rsp), %r8
leaq 0xa(%rsp), %r9
movq %r14, %rdi
movq %rbx, %rsi
movq %r12, %rdx
jmp 0x12cbd
leal -0x33(%r13), %eax
cmpl $0x16, %eax
ja 0x12bdb
leaq 0x63c9e(%rip), %rcx     # 0x766ec
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 0xddf6
cmpb $0x1, (%r15)
jne 0x12d35
movq (%rbx), %rax
movl (%rax), %ecx
cmpl $0x18, %ecx
ja 0x12a99
movl $0x1ec0000, %edx        # imm = 0x1EC0000
btl %ecx, %edx
jb 0x12d35
addq $0x4e70, %r14           # imm = 0x4E70
movq 0x8(%rax), %rax
movl (%rax), %esi
movq %r14, %rdi
callq 0x132bc
movq (%rbx), %rax
movq 0x8(%rax), %rax
jmp 0x12d32
movq %r15, %rdi
callq 0x15914
movq %r14, %rdi
movq %rbx, %rsi
movq %r12, %rdx
callq 0x129ab
leaq 0x4e18(%r14), %rdi
movq (%rbx), %rsi
movl %r13d, %edx
callq 0x1a4dd
movq (%rbx), %rcx
testq %r12, %r12
je 0x12b0c
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 0x9eb8
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 0x136fc
testq %r12, %r12
je 0x12c01
movq 0x4bd8(%r14), %rax
movq %rax, (%r12)
jmp 0x12c14
testq %r12, %r12
je 0x12c3c
movsd 0x4bd8(%r14), %xmm0
movsd %xmm0, (%r12)
jmp 0x12c51
movq 0x4bd8(%r14), %rsi
testq %rsi, %rsi
js 0x12c65
testq %r12, %r12
je 0x12d43
movq %rsi, (%r12)
jmp 0x12d4f
movq %r15, %rdi
movl $0x38, %esi
callq 0x1637d
movq $0x0, (%rbx)
movq %r14, %rdi
movq %rbx, %rsi
movq %r12, %rdx
callq 0x111c3
movq %r15, %rdi
movl $0x39, %esi
addq $0x10, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
jmp 0x1637d
testq %r12, %r12
je 0x12c77
movq 0x4bd8(%r14), %rax
movq %rax, (%r12)
jmp 0x12c8a
movq 0x50f8(%r14), %rcx
movq 0x5118(%r14), %rdi
leaq 0x64323(%rip), %rsi     # 0x76f13
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 0x12f6d
movq %r15, %rdi
callq 0x15914
leaq 0x4e18(%r14), %rdi
addq $0x4220, %r14           # imm = 0x4220
movq %r14, %rsi
movl $0x14, %edx
callq 0x19a70
jmp 0x12d32
leaq 0x4e70(%r14), %rdi
movsd 0x4bd8(%r14), %xmm0
callq 0x12f45
movq %r15, %rdi
callq 0x15914
movq 0x5280(%r14), %rax
jmp 0x12d32
testq %r12, %r12
je 0x12d56
movq %rsi, (%r12)
jmp 0x12d62
leaq 0x4e70(%r14), %rdi
movq 0x4bd8(%r14), %rsi
callq 0x12ef1
movq %r15, %rdi
callq 0x15914
movq 0x5270(%r14), %rax
jmp 0x12d32
movq %r15, %rdi
callq 0x15914
leaq 0xb(%rsp), %rcx
leaq 0xc(%rsp), %r8
leaq 0xa(%rsp), %r9
movq %r14, %rdi
movq %rbx, %rsi
xorl %edx, %edx
callq 0xddf6
cmpb $0x0, 0xb(%rsp)
jne 0x12ce0
movq 0x5118(%r14), %rdi
leaq 0x64228(%rip), %rsi     # 0x76eff
xorl %eax, %eax
callq *0x50f8(%r14)
cmpb $0x1, 0xa(%rsp)
jne 0x12d08
leaq 0x4e18(%r14), %rdi
leaq 0x4220(%r14), %rsi
movq (%rbx), %rdx
callq 0x19e01
movq %r14, %rdi
movq %rax, %rsi
callq 0x12128
movq (%rbx), %rdx
movl (%rdx), %eax
cmpl $0x18, %eax
ja 0x12d35
movl $0x1ec0000, %ecx        # imm = 0x1EC0000
btl %eax, %ecx
jae 0x12d35
leaq 0x4e18(%r14), %rdi
addq $0x4220, %r14           # imm = 0x4220
movq %r14, %rsi
callq 0x19e01
movq %rax, (%rbx)
addq $0x10, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
retq
leaq 0x4e70(%r14), %rdi
callq 0x12ef1
movl $0x5240, %eax           # imm = 0x5240
jmp 0x12d67
leaq 0x4e70(%r14), %rdi
callq 0x12f1b
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 0x15914
nop