// File: /workspace/github_c_makefile_star2_O3/hsjoihs[P]c-compiler/typecheck_expression.c
// Function: typecheck_unary_expression
struct Expr typecheck_unary_expression(const struct AnalyzerState *ptr_ps,
                                       const struct Expr *ref_expr,
                                       enum TokenKind kind)
{
	const struct Expr expr = *ref_expr;
	switch (kind) {
	case OP_NOT: {
		expect_scalar(&expr.details.type, "operand of logical not");
		struct Type t = INT_TYPE();
		return unary_op_(&expr, kind, &t);
	}
	case OP_TILDA:
	case OP_PLUS:
	case OP_MINUS: {
		expect_integral(&expr.details.type,
		                "operand of bitnot, unary plus or unary minus");

		/* integral promotion */
		struct Type t = INT_TYPE();
		return unary_op_(&expr, kind, &t);
	}

	case OP_PLUS_PLUS:
	case OP_MINUS_MINUS: {
		struct Expr new_expr = unary_op_(&expr, kind, &expr.details.type);
		if (expr.details.type.type_category == PTR_) {
			const struct Type deref = deref_type(&expr.details.type);
			new_expr.size_info_for_pointer_arith = size_of(ptr_ps, &deref);
		}
		return new_expr;
	}

	case OP_AND: {
		struct Type type = expr.details.type;
		if (type.type_category == PTR_ &&
		    expr.details.true_type.type_category == ARRAY) {
			type = expr.details.true_type;
		}
		const struct Type ptr_to_type_ = ptr_to_type(&type);
		return unary_op_(&expr, OP_AND, &ptr_to_type_);
	}
	case OP_ASTERISK: {

		/* function type, automatically converted to a function pointer,
		 * gets dereferenced to become a function type, which is again
		 * automatically converted to a function pointer
		 */
		if (expr.details.type.type_category == FN) {
			struct Expr e = expr;
			if_function_cast_to_pointer(&e);
			return e;
		}

		const struct Type type = deref_type(&expr.details.type);

		if (type.type_category ==
		    FN) { /* function reverts to function pointer */
			return expr;
		}

		struct Type t2 = type;
		if_array_convert_to_ptr_(&t2);

		struct Expr new_expr = unary_op_(&expr, OP_ASTERISK, &t2);
		new_expr.details.true_type = type;

		return new_expr;
	}
	case RES_SIZEOF: {
		struct Expr new_expr;
		new_expr.details.type = INT_TYPE();
		new_expr.int_value = size_of(ptr_ps, &expr.details.true_type);
		new_expr.category = INT_VALUE;
		return new_expr;
	}
	default: {
		fprintf(stderr, "FAILURE::::::: INVALID TOKEN %d in unary\n", kind);
		exit(EXIT_FAILURE);
	}
	}
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r12
pushq %rbx
subq $0x1a0, %rsp            # imm = 0x1A0
movl %ecx, %r14d
movq %rdx, %r12
movq %rsi, %r15
movq %rdi, %rbx
leaq -0x170(%rbp), %rdi
movl $0x100, %edx            # imm = 0x100
movq %r12, %rsi
callq 0x1100
cmpl $0x14, %r14d
jle 0x63ed
cmpl $0x31, %r14d
jle 0x648d
leal -0x32(%r14), %eax
cmpl $0x2, %eax
jae 0x64d9
leaq -0x170(%rbp), %r12
movq %rbx, %rdi
movq %r12, %rsi
movl %r14d, %edx
movq %r12, %rcx
callq 0x625a
cmpl $0x1, (%r12)
jne 0x659b
leaq -0x70(%rbp), %r14
leaq -0x170(%rbp), %rsi
movq %r14, %rdi
callq 0x96bb
movq %r15, %rdi
movq %r14, %rsi
callq 0x2ffc
movl %eax, 0xf4(%rbx)
jmp 0x659b
cmpl $0x2, %r14d
jb 0x64a1
cmpl $0x5, %r14d
je 0x650f
cmpl $0x11, %r14d
jne 0x666a
leaq -0x70(%rbp), %rax
movl $0xa, %ecx
movq %rax, %rdi
movq %r12, %rsi
rep  movsq (%rsi), %es:(%rdi)
cmpl $0x1, (%rax)
jne 0x643e
cmpl $0x2, -0x120(%rbp)
jne 0x643e
addq $0x50, %r12
leaq -0x70(%rbp), %rdi
movl $0xa, %ecx
movq %r12, %rsi
rep  movsq (%rsi), %es:(%rdi)
leaq -0x70(%rbp), %rsi
movq %rbx, %rdi
callq 0x96ed
movl $0x1, %edi
movl $0x100, %esi            # imm = 0x100
callq 0x10d0
movq %rax, %r14
leaq -0x170(%rbp), %rsi
movl $0x100, %edx            # imm = 0x100
movq %rax, %rdi
callq 0x1100
movl $0x6, %eax
movl %eax, 0xa0(%rbx)
movl %eax, 0xa8(%rbx)
movq %r14, 0xb0(%rbx)
jmp 0x6591
cmpl $0x15, %r14d
je 0x6536
cmpl $0x16, %r14d
jne 0x666a
leaq 0x92cd(%rip), %rsi      # 0xf775
leaq -0x170(%rbp), %r15
movq %r15, %rdi
callq 0x614b
leaq -0x70(%rbp), %r12
movq %r12, %rdi
callq 0x95ac
movq %rbx, %rdi
movq %r15, %rsi
movl %r14d, %edx
movq %r12, %rcx
callq 0x625a
jmp 0x659b
cmpl $0x3b, %r14d
jne 0x666a
movq %rbx, %rdi
callq 0x95ac
leaq -0x120(%rbp), %rsi
movq %r15, %rdi
callq 0x2ffc
movl %eax, 0xc8(%rbx)
movl $0x9, 0xa0(%rbx)
jmp 0x659b
cmpl $0x3, -0x170(%rbp)
jne 0x65ae
movl $0x100, %edx            # imm = 0x100
movq %rbx, %rdi
movq %r12, %rsi
callq 0x1100
movq %rbx, %rdi
callq 0x61b8
jmp 0x659b
leaq 0x8d03(%rip), %rsi      # 0xf240
leaq -0x170(%rbp), %r14
movq %r14, %rdi
callq 0x6130
movq %rbx, %rdi
callq 0x95ac
movl $0x1, %edi
movl $0x100, %esi            # imm = 0x100
callq 0x10d0
movq %rax, %r15
movl $0x100, %edx            # imm = 0x100
movq %rax, %rdi
movq %r14, %rsi
callq 0x1100
movl $0x6, 0xa0(%rbx)
movl $0x0, 0xa8(%rbx)
movq %r15, 0xb0(%rbx)
xorps %xmm0, %xmm0
movups %xmm0, 0xb8(%rbx)
movq %rbx, %rax
addq $0x1a0, %rsp            # imm = 0x1A0
popq %rbx
popq %r12
popq %r14
popq %r15
popq %rbp
retq
leaq -0x70(%rbp), %r14
leaq -0x170(%rbp), %rsi
movq %r14, %rdi
callq 0x96bb
cmpl $0x3, (%r14)
jne 0x65dd
leaq -0x170(%rbp), %rsi
movl $0x100, %edx            # imm = 0x100
movq %rbx, %rdi
callq 0x1100
jmp 0x659b
leaq -0x1c0(%rbp), %r15
movl $0xa, %ecx
movq %r15, %rdi
movq %r14, %rsi
rep  movsq (%rsi), %es:(%rdi)
movq %r15, %rdi
callq 0x96dc
movl $0x1, %edi
movl $0x100, %esi            # imm = 0x100
callq 0x10d0
movq %rax, %r12
leaq -0x170(%rbp), %rsi
movl $0x100, %edx            # imm = 0x100
movq %rax, %rdi
callq 0x1100
movl $0xa, %ecx
movq %rbx, %rdi
movq %r15, %rsi
rep  movsq (%rsi), %es:(%rdi)
movl $0x6, 0xa0(%rbx)
movl $0x7, 0xa8(%rbx)
movq %r12, 0xb0(%rbx)
xorps %xmm0, %xmm0
movups %xmm0, 0xb8(%rbx)
movq %rbx, %rdi
addq $0x50, %rdi
movl $0xa, %ecx
movq %r14, %rsi
rep  movsq (%rsi), %es:(%rdi)
jmp 0x659b
movl %r14d, %edi
callq 0x181d