// File: /workspace/github_c_makefile_star2_O2/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 $0x2, %r14d
jb 0x523f
leal -0x32(%r14), %eax
cmpl $0x2, %eax
jb 0x5272
cmpl $0x5, %r14d
je 0x52e7
cmpl $0x11, %r14d
je 0x530e
cmpl $0x3b, %r14d
je 0x52be
cmpl $0x16, %r14d
je 0x523f
cmpl $0x15, %r14d
jne 0x53f4
leaq 0x9051(%rip), %rsi      # 0xe264
leaq -0x170(%rbp), %r14
movq %r14, %rdi
callq 0x4edd
leaq -0x70(%rbp), %r15
movq %r15, %rdi
callq 0x81b0
pushq $0x15
popq %rdx
movq %rbx, %rdi
movq %r14, %rsi
movq %r15, %rcx
jmp 0x5360
leaq 0x9553(%rip), %rsi      # 0xe799
leaq -0x170(%rbp), %r15
movq %r15, %rdi
callq 0x4f46
leaq -0x70(%rbp), %r12
movq %r12, %rdi
callq 0x81b0
movq %rbx, %rdi
movq %r15, %rsi
movl %r14d, %edx
movq %r12, %rcx
jmp 0x5360
leaq -0x170(%rbp), %r12
movq %rbx, %rdi
movq %r12, %rsi
movl %r14d, %edx
movq %r12, %rcx
callq 0x50a8
cmpl $0x1, (%r12)
jne 0x5365
leaq -0x70(%rbp), %r14
leaq -0x170(%rbp), %rsi
movq %r14, %rdi
callq 0x85ad
movq %r15, %rdi
movq %r14, %rsi
callq 0x1e24
movl %eax, 0xf4(%rbx)
jmp 0x5365
movq %rbx, %rdi
callq 0x81b0
leaq -0x120(%rbp), %rsi
movq %r15, %rdi
callq 0x1e24
movl %eax, 0xc8(%rbx)
movl $0x9, 0xa0(%rbx)
jmp 0x5365
cmpl $0x3, -0x170(%rbp)
jne 0x5378
movl $0x100, %edx            # imm = 0x100
movq %rbx, %rdi
movq %r12, %rsi
callq 0x1100
movq %rbx, %rdi
callq 0x5038
jmp 0x5365
pushq $0xa
popq %rcx
leaq -0x70(%rbp), %rax
movq %rax, %rdi
movq %r12, %rsi
rep  movsq (%rsi), %es:(%rdi)
cmpl $0x1, (%rax)
jne 0x533d
cmpl $0x2, -0x120(%rbp)
jne 0x533d
addq $0x50, %r12
pushq $0xa
popq %rcx
leaq -0x70(%rbp), %rdi
movq %r12, %rsi
rep  movsq (%rsi), %es:(%rdi)
leaq -0x1c0(%rbp), %r14
leaq -0x70(%rbp), %rsi
movq %r14, %rdi
callq 0x862d
leaq -0x170(%rbp), %rsi
pushq $0x11
popq %rdx
movq %rbx, %rdi
movq %r14, %rcx
callq 0x50a8
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 0x85ad
cmpl $0x3, (%r14)
jne 0x53a7
leaq -0x170(%rbp), %rsi
movl $0x100, %edx            # imm = 0x100
movq %rbx, %rdi
callq 0x1100
jmp 0x5365
pushq $0xa
popq %r14
leaq -0x1c0(%rbp), %r15
leaq -0x70(%rbp), %r12
movq %r14, %rcx
movq %r15, %rdi
movq %r12, %rsi
rep  movsq (%rsi), %es:(%rdi)
movq %r15, %rdi
callq 0x861c
leaq -0x170(%rbp), %rsi
pushq $0x5
popq %rdx
movq %rbx, %rdi
movq %r15, %rcx
callq 0x50a8
movq %rbx, %rdi
addq $0x50, %rdi
movq %r14, %rcx
movq %r12, %rsi
rep  movsq (%rsi), %es:(%rdi)
jmp 0x5365
movq 0x10bfd(%rip), %rax     # 0x15ff8
movq (%rax), %rdi
leaq 0x93c1(%rip), %rsi      # 0xe7c6
movl %r14d, %edx
xorl %eax, %eax
callq 0x10f0
pushq $0x1
popq %rdi
callq 0x1170