// File: /workspace/github_c_makefile_star2_O3/Mithreindeir[P]ewcc/src/frontend/checker.c
// Function: node_check
void node_check(struct node *n, struct symbol_table *scope)
{
	if (!n)
		return;
	switch (n->type) {
	case node_ident:
		TYPE(n) = type_copy(get_type(scope, IDENT(n)));
		if (!TYPE(n)) {
			printf("Use of undeclared or out of scope variables %s\n", IDENT(n));
		}
		break;
	case node_cnum:
		TYPE(n) = type_init(type_datatype);
		TYPE(n)->info.data_type = type_int;
		break;
	case node_unop:
		node_check(UNOP(n)->term, scope);
		if (UNOP(n)->op == o_ref) {
			TYPE(n) = type_init(type_ptr);
			TYPE(n)->next = type_copy(UNOP(n)->term->inf->type);
		} else if (UNOP(n)->op == o_deref) {
			/**/
			int term_t = TYPE(UNOP(n)->term)->type;
			if (term_t != type_ptr && term_t != type_array) {
				printf("Dereferencing variable not of pointer type: ");
				print_type(TYPE(UNOP(n)->term));
				printf("\n");
			}
			TYPE(n) = type_copy(TYPE(UNOP(n)->term)->next);
		} else {
			TYPE(n) = type_copy(TYPE(UNOP(n)->term));
		}
		break;
	case node_binop:
		node_check(BINOP(n)->lhs, scope);
		node_check(BINOP(n)->rhs, scope);
		int favor = NEUTRAL;
		struct type *lt = TYPE(BINOP(n)->lhs), *rt = TYPE(BINOP(n)->rhs);
		/*Cast in binary operations goes to larger size unless it is an assignment, then favor lhs*/
		if (BINOP(n)->op == o_asn) favor = LHS;
		if (!cmp_types(lt, rt)) {
			struct binop *b = BINOP(n);
			if (!implicit_cast(&b->lhs, &b->rhs, favor)) {
				type_error(n, TYPE(BINOP(n)->lhs), TYPE(BINOP(n)->rhs));
			}
		}
		/*Pointer arithmetic check*/
		struct node *v1=NULL, *v2=NULL;
		if (BINOP(n)->lhs && lt && (lt->type == type_ptr || lt->type == type_array)) {
			v1 = BINOP(n)->lhs;
		} if (BINOP(n)->rhs && rt && (rt->type == type_ptr || rt->type == type_array)) {
			v2 = BINOP(n)->rhs;
		}
		/*The only valid operation with two pointers is subtraction*/
		if (v1 && v2 && BINOP(n)->op != o_sub) {
			printf("Invalid pointer arithmetic\n");
			node_debug(n);
			exit(-1);
		}
		if (v1 || v2) {
			if (!v1) {
				v1 = v2;
				v2 = BINOP(n)->lhs;
			} else if (!v2) {
				v2 = BINOP(n)->rhs;
			}
			/*v1 is a pointer*/
			if (BINOP(n)->op != o_add && BINOP(n)->op != o_sub) {
				printf("Invalid pointer arithmetic\n");
				node_debug(n);
				exit(-1);
			}
			/*Syntactic sugar for scaling pointer by their size*/
			//if its a constant, just multiply it
			int psize = resolve_size(TYPE(v1)->next);
			//if its a constant, just multiply it
			if (v2 && v2->type == node_cnum) {
				CNUM(v2) *= psize;
			} else if (psize != 1) {//otherwise add multiplication operation in AST
				union value *s = malloc(sizeof(union value));
				s->cnum = psize;
				struct expr *scale = binop_init(o_mul, node_init(node_cnum, s), v2);
				TYPE(scale) = type_copy(TYPE(v2));
				if (v2 == BINOP(n)->lhs) BINOP(n)->lhs = scale;
				else BINOP(n)->rhs = scale;
			}
		}
		TYPE(n) = type_copy(TYPE(BINOP(n)->lhs));
		break;
	case node_unit:
		for (int i = 0; i < UNIT(n)->num_decls; i++)
			node_check(UNIT(n)->edecls[i], scope);
		break;
	case node_block:
		for (int i = 0; i < BLOCK(n)->num_stmt; i++) {
			node_check(BLOCK(n)->stmt_list[i],
				   BLOCK(n)->scope);
		}
		break;
	case node_func:
		node_check(FUNC(n)->body, scope);
		break;
	case node_return:
		node_check(RET(n), scope);
		break;
	case node_call:
		node_check(CALL(n)->func, scope);
		struct type *ct = TYPE(CALL(n)->func);
		while (ct && ct->type == type_ptr) ct = ct->next;
		if (ct->type != type_fcn) {
			printf("Error: called object ");
			node_debug(n);
			printf(" is not of function or function pointer type\n");
			exit(-1);
		}
		if (ct->info.fcn.paramc != CALL(n)->argc) {
			printf("Number of parameter mismatch\n");
			node_debug(n);
			exit(-1);
		}
		/*Type check parameters*/
		for (int i = 0; i < CALL(n)->argc; i++) {
			node_check(CALL(n)->argv[i], scope);
			struct type *pt = ct->info.fcn.paramt[i];
			if (!cmp_types(pt, TYPE(CALL(n)->argv[i]))) {
				if (!explicit_cast(pt, &CALL(n)->argv[i])) {
					printf("In argument %d:\n", i+1);
					type_error(n, pt, TYPE(CALL(n)->argv[i]));
				}
			}
		}
		TYPE(n) = type_copy(ct->next);
		break;
	case node_cond:
		node_check(COND(n)->condition, scope);
		node_check(COND(n)->body, scope);
		if (COND(n)->otherwise) {
			node_check(COND(n)->otherwise, scope);
		}
		break;
	case node_loop:
		node_check(LOOP(n)->init, scope);
		node_check(LOOP(n)->condition, scope);
		node_check(LOOP(n)->body, scope);
		node_check(LOOP(n)->iter, scope);
		break;
	case node_decl:
		node_check(DECL(n)->initializer, scope);
		if (!DECL(n)->initializer)
			break;
		struct type *dtype = get_type(scope, DECL(n)->ident);
		if (!cmp_types(dtype, TYPE(DECL(n)->initializer))) {
			if (!explicit_cast(dtype, &DECL(n)->initializer)) {
				type_error(n, dtype, TYPE(DECL(n)->initializer));
			}
		}
		break;
	default:
		break;
	}
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
pushq %rax
testq %rdi, %rdi
je 0x6c52
movq %rsi, %r14
movq %rdi, %rbx
leaq 0x2ff0(%rip), %r15      # 0x96c8
movl (%rbx), %eax
addl $-0x2, %eax
cmpl $0xd, %eax
ja 0x6c52
movslq (%r15,%rax,4), %rax
addq %r15, %rax
jmpq *%rax
movq 0x8(%rbx), %rax
movq (%rax), %rdi
movq %r14, %rsi
callq 0x66b7
movq 0x8(%rbx), %rax
movq 0x8(%rax), %rdi
movq %r14, %rsi
callq 0x66b7
movq 0x8(%rbx), %rax
movq 0x10(%rax), %rbx
testq %rbx, %rbx
jne 0x6760
jmp 0x6c52
movq 0x8(%rbx), %rax
movq (%rax), %rdi
movq %r14, %rsi
callq 0x66b7
movq 0x8(%rbx), %rax
movq 0x8(%rax), %rdi
movq %r14, %rsi
callq 0x66b7
movq 0x8(%rbx), %rax
movq 0x18(%rax), %rdi
movq %r14, %rsi
callq 0x66b7
movq 0x8(%rbx), %rbx
addq $0x10, %rbx
jmp 0x675d
addq $0x8, %rbx
movq (%rbx), %rbx
testq %rbx, %rbx
jne 0x66d8
jmp 0x6c52
movq 0x8(%rbx), %rax
movq 0x10(%rax), %rdi
movq %r14, %rsi
callq 0x66b7
movq 0x8(%rbx), %rax
cmpq $0x0, 0x10(%rax)
je 0x6c52
movq (%rax), %rsi
movq %r14, %rdi
callq 0x7dee
movq %rax, %r14
movq 0x8(%rbx), %rax
movq 0x10(%rax), %rax
movq 0x10(%rax), %rax
movq (%rax), %rsi
movq %r14, %rdi
callq 0x829d
testl %eax, %eax
jne 0x6c52
movq 0x8(%rbx), %rsi
addq $0x10, %rsi
movq %r14, %rdi
callq 0x662b
testl %eax, %eax
jne 0x6c52
movq 0x8(%rbx), %rax
movq 0x10(%rax), %rax
movq 0x10(%rax), %rax
movq (%rax), %rdx
movq %rbx, %rdi
movq %r14, %rsi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x6458
movq 0x8(%rbx), %rax
movq (%rax), %rdi
movq %r14, %rsi
callq 0x66b7
movq 0x8(%rbx), %rax
movq 0x8(%rax), %rdi
movq %r14, %rsi
callq 0x66b7
movq 0x8(%rbx), %rax
movq (%rax), %rcx
movq 0x8(%rax), %rdx
movq 0x10(%rcx), %rcx
movq (%rcx), %r14
movq 0x10(%rdx), %rcx
movq (%rcx), %r15
movl 0x10(%rax), %ebp
movq %r14, %rdi
movq %r15, %rsi
callq 0x829d
testl %eax, %eax
jne 0x6881
xorl %eax, %eax
cmpl $0x18, %ebp
setne %al
leal (%rax,%rax,2), %edx
movq 0x8(%rbx), %rdi
leaq 0x8(%rdi), %rsi
callq 0x64f1
testl %eax, %eax
jne 0x6881
movq 0x8(%rbx), %rax
movq (%rax), %rcx
movq 0x8(%rax), %rax
movq 0x10(%rcx), %rcx
movq (%rcx), %rsi
movq 0x10(%rax), %rax
movq (%rax), %rdx
movq %rbx, %rdi
callq 0x6458
movq 0x8(%rbx), %rax
movq (%rax), %rdx
xorl %ecx, %ecx
testq %r14, %r14
je 0x68a3
testq %rdx, %rdx
je 0x68a3
movl 0x18(%r14), %esi
decl %esi
xorl %ecx, %ecx
cmpl $0x2, %esi
cmovbq %rdx, %rcx
movq 0x8(%rax), %r14
testq %r15, %r15
je 0x6a4b
testq %r14, %r14
je 0x6a4b
movl 0x18(%r15), %esi
decl %esi
cmpl $0x1, %esi
ja 0x6a4b
testq %rcx, %rcx
je 0x6c28
movb $0x1, %sil
cmpl $0x1, 0x10(%rax)
movq %r14, %rdi
je 0x6a5a
jmp 0x6c8e
movq 0x8(%rbx), %rax
movq (%rax), %rsi
movq %r14, %rdi
callq 0x7dee
movq %rax, %rdi
callq 0x7fb8
movq 0x10(%rbx), %rcx
movq %rax, (%rcx)
testq %rax, %rax
jne 0x6c52
movq 0x8(%rbx), %rax
movq (%rax), %rsi
leaq 0x2e46(%rip), %rdi      # 0x9761
xorl %eax, %eax
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x2080
movq 0x8(%rbx), %rax
movq (%rax), %rdi
movq %r14, %rsi
callq 0x66b7
movq 0x8(%rbx), %rax
movl 0x8(%rax), %ecx
cmpl $0x13, %ecx
je 0x6bd4
cmpl $0x12, %ecx
jne 0x6c3c
movl $0x1, %edi
callq 0x7f14
movq 0x10(%rbx), %rcx
movq %rax, (%rcx)
movq 0x8(%rbx), %rax
movq (%rax), %rax
movq 0x10(%rax), %rax
movq (%rax), %rdi
callq 0x7fb8
movq 0x10(%rbx), %rcx
movq (%rcx), %rcx
movq %rax, 0x20(%rcx)
jmp 0x6c52
movq 0x8(%rbx), %rax
cmpl $0x0, 0x8(%rax)
jle 0x6c52
xorl %r15d, %r15d
movq (%rax), %rax
movq (%rax,%r15,8), %rdi
movq %r14, %rsi
callq 0x66b7
incq %r15
movq 0x8(%rbx), %rax
movslq 0x8(%rax), %rcx
cmpq %rcx, %r15
jl 0x699d
jmp 0x6c52
xorl %edi, %edi
callq 0x7f14
movq 0x10(%rbx), %rcx
movq %rax, (%rcx)
movl $0x1, (%rax)
jmp 0x6c52
movq 0x8(%rbx), %rax
movq 0x8(%rax), %rdi
movq %r14, %rsi
callq 0x66b7
movq 0x8(%rbx), %rax
movq 0x8(%rax), %rcx
movq 0x10(%rcx), %rcx
movq (%rcx), %r12
testq %r12, %r12
je 0x6aa3
cmpl $0x1, 0x18(%r12)
jne 0x6aa6
movq 0x20(%r12), %r12
jmp 0x69f9
movq 0x8(%rbx), %rax
cmpl $0x0, 0x8(%rax)
jle 0x6c52
xorl %r14d, %r14d
movq (%rax), %rcx
movq 0x10(%rax), %rsi
movq (%rcx,%r14,8), %rdi
callq 0x66b7
incq %r14
movq 0x8(%rbx), %rax
movslq 0x8(%rax), %rcx
cmpq %rcx, %r14
jl 0x6a26
jmp 0x6c52
testq %rcx, %rcx
setne %sil
je 0x6c38
xorl %edi, %edi
cmpl $0x2, 0x10(%rax)
jae 0x6c8e
testb %sil, %sil
cmovneq %rcx, %rdi
movq 0x10(%rdi), %rax
movq (%rax), %rax
movq 0x20(%rax), %rdi
callq 0x80f0
movl %eax, %ebp
testq %r14, %r14
je 0x6b79
cmpl $0x4, (%r14)
jne 0x6b79
movslq %ebp, %rax
movq 0x8(%r14), %rcx
imulq (%rcx), %rax
movq %rax, (%rcx)
jmp 0x6c38
xorl %r12d, %r12d
cmpl $0x3, 0x18(%r12)
jne 0x6c61
movl (%r12), %ecx
cmpl (%rax), %ecx
jne 0x6c85
testl %ecx, %ecx
jle 0x6b6f
movl $0x1, %ebp
xorl %r15d, %r15d
xorl %r13d, %r13d
movq %r12, (%rsp)
movq 0x10(%rax), %rax
movq (%rax,%r15), %rdi
movq %r14, %rsi
callq 0x66b7
movq 0x10(%r12), %rax
movq (%rax,%r15), %r12
movq 0x8(%rbx), %rax
movq 0x10(%rax), %rax
movq (%rax,%r15), %rax
movq 0x10(%rax), %rax
movq (%rax), %rsi
movq %r12, %rdi
callq 0x829d
testl %eax, %eax
jne 0x6b52
movq 0x8(%rbx), %rax
movq 0x10(%rax), %rsi
addq %r15, %rsi
movq %r12, %rdi
callq 0x662b
testl %eax, %eax
jne 0x6b52
leaq 0x2ca9(%rip), %rdi      # 0x97d4
movl %ebp, %esi
xorl %eax, %eax
callq 0x2080
movq 0x8(%rbx), %rax
movq 0x10(%rax), %rax
movq (%rax,%r15), %rax
movq 0x10(%rax), %rax
movq (%rax), %rdx
movq %rbx, %rdi
movq %r12, %rsi
callq 0x6458
incq %r13
movq 0x8(%rbx), %rax
movslq (%rax), %rcx
incl %ebp
addq $0x8, %r15
cmpq %rcx, %r13
movq (%rsp), %r12
jl 0x6ad5
movq 0x20(%r12), %rdi
jmp 0x6c46
cmpl $0x1, %ebp
je 0x6c38
movl $0x8, %edi
callq 0x2100
movslq %ebp, %rcx
movq %rcx, (%rax)
movl $0x4, %edi
movq %rax, %rsi
callq 0x5764
movl $0x2, %edi
movq %rax, %rsi
movq %r14, %rdx
callq 0x5cb2
movq %rax, %r15
movq 0x10(%r14), %rax
movq (%rax), %rdi
callq 0x7fb8
movq 0x10(%r15), %rcx
movq %rax, (%rcx)
movq 0x8(%rbx), %rax
cmpq (%rax), %r14
je 0x6c35
movq %r15, 0x8(%rax)
jmp 0x6c38
movq (%rax), %rax
movq 0x10(%rax), %rax
movq (%rax), %rax
movl 0x18(%rax), %ecx
addl $-0x3, %ecx
cmpl $-0x3, %ecx
ja 0x6c22
leaq 0x2ba1(%rip), %rdi      # 0x9791
xorl %eax, %eax
callq 0x2080
movq 0x8(%rbx), %rax
movq (%rax), %rax
movq 0x10(%rax), %rax
movq (%rax), %rdi
callq 0x815b
movl $0xa, %edi
callq 0x2040
movq 0x8(%rbx), %rax
movq (%rax), %rax
movq 0x10(%rax), %rax
movq (%rax), %rax
movq 0x20(%rax), %rdi
jmp 0x6c46
xorl %esi, %esi
movq %r14, %rdi
movq %rdx, %r14
jmp 0x6a5a
movq %r15, (%rax)
movq 0x8(%rbx), %rax
movq (%rax), %rax
movq 0x10(%rax), %rax
movq (%rax), %rdi
callq 0x7fb8
movq 0x10(%rbx), %rcx
movq %rax, (%rcx)
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x2b56(%rip), %rdi      # 0x97be
xorl %eax, %eax
callq 0x2080
movq %rbx, %rdi
callq 0x26cb
leaq 0x2ba7(%rip), %rdi      # 0x9825
callq 0x2060
jmp 0x6ca2
leaq 0x2b7c(%rip), %rdi      # 0x9808
jmp 0x6c95
leaq 0x2bbd(%rip), %rdi      # 0x9852
callq 0x2060
movq %rbx, %rdi
callq 0x26cb
movl $0xffffffff, %edi       # imm = 0xFFFFFFFF
callq 0x2120