// File: /workspace/github_c_makefile_star2_O2/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
movq %rsi, %r14
movq %rdi, %rbx
leaq 0x2a27(%rip), %r15      # 0x86c8
testq %rbx, %rbx
je 0x61f3
movl (%rbx), %eax
addl $-0x2, %eax
cmpl $0xd, %eax
ja 0x61f3
movslq (%r15,%rax,4), %rax
addq %r15, %rax
jmpq *%rax
movq 0x8(%rbx), %rax
movq (%rax), %rdi
movq %r14, %rsi
callq 0x5c89
movq 0x8(%rbx), %rax
movq 0x8(%rax), %rdi
movq %r14, %rsi
callq 0x5c89
movq 0x8(%rbx), %rax
movq 0x10(%rax), %rbx
testq %rbx, %rbx
jne 0x5ca1
jmp 0x61f3
movq 0x8(%rbx), %rax
movq (%rax), %rdi
movq %r14, %rsi
callq 0x5c89
movq 0x8(%rbx), %rax
movq 0x8(%rax), %rdi
movq %r14, %rsi
callq 0x5c89
movq 0x8(%rbx), %rax
movq 0x18(%rax), %rdi
movq %r14, %rsi
callq 0x5c89
movq 0x8(%rbx), %rbx
addq $0x10, %rbx
jmp 0x5d2f
addq $0x8, %rbx
movq (%rbx), %rbx
jmp 0x5ca1
movq 0x8(%rbx), %rax
movq 0x10(%rax), %rdi
movq %r14, %rsi
callq 0x5c89
movq 0x8(%rbx), %rax
cmpq $0x0, 0x10(%rax)
je 0x61f3
movq (%rax), %rsi
movq %r14, %rdi
callq 0x72a9
movq %rax, %r14
movq 0x8(%rbx), %rax
movq 0x10(%rax), %rax
movq 0x10(%rax), %rax
movq (%rax), %rsi
movq %r14, %rdi
callq 0x7720
testl %eax, %eax
jne 0x61f3
movq 0x8(%rbx), %rsi
addq $0x10, %rsi
movq %r14, %rdi
callq 0x5c20
testl %eax, %eax
jne 0x61f3
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 0x5aa4
xorl %r14d, %r14d
movq 0x8(%rbx), %rax
movslq 0x8(%rax), %rcx
cmpq %rcx, %r14
jge 0x61f3
movq (%rax), %rcx
movq 0x10(%rax), %rsi
movq (%rcx,%r14,8), %rdi
callq 0x5c89
incq %r14
jmp 0x5dc6
xorl %edi, %edi
callq 0x73c8
movq 0x10(%rbx), %rcx
movq %rax, (%rcx)
movl $0x1, (%rax)
jmp 0x61f3
movq 0x8(%rbx), %rax
movq (%rax), %rsi
movq %r14, %rdi
callq 0x72a9
movq %rax, %rdi
callq 0x7460
movq 0x10(%rbx), %rcx
movq %rax, (%rcx)
testq %rax, %rax
jne 0x61f3
movq 0x8(%rbx), %rax
movq (%rax), %rsi
leaq 0x2927(%rip), %rdi      # 0x8761
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 0x5c89
movq 0x8(%rbx), %rax
movq 0x8(%rax), %rdi
movq %r14, %rsi
callq 0x5c89
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 0x7720
testl %eax, %eax
jne 0x5ed6
xorl %eax, %eax
cmpl $0x18, %ebp
setne %al
leal (%rax,%rax,2), %edx
movq 0x8(%rbx), %rdi
leaq 0x8(%rdi), %rsi
callq 0x5b39
testl %eax, %eax
jne 0x5ed6
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 0x5aa4
movq 0x8(%rbx), %rax
movq (%rax), %rdx
xorl %ecx, %ecx
testq %r14, %r14
je 0x5ef8
testq %rdx, %rdx
je 0x5ef8
movl 0x18(%r14), %esi
decl %esi
xorl %ecx, %ecx
cmpl $0x2, %esi
cmovbq %rdx, %rcx
movq 0x8(%rax), %r14
testq %r15, %r15
je 0x5ff9
testq %r14, %r14
je 0x5ff9
movl 0x18(%r15), %esi
decl %esi
cmpl $0x1, %esi
ja 0x5ff9
testq %rcx, %rcx
je 0x61c9
movb $0x1, %sil
cmpl $0x1, 0x10(%rax)
movq %r14, %rdi
je 0x6008
jmp 0x622f
xorl %r15d, %r15d
movq 0x8(%rbx), %rax
movslq 0x8(%rax), %rcx
cmpq %rcx, %r15
jge 0x61f3
movq (%rax), %rax
movq (%rax,%r15,8), %rdi
movq %r14, %rsi
callq 0x5c89
incq %r15
jmp 0x5f3e
movq 0x8(%rbx), %rax
movq 0x8(%rax), %rdi
movq %r14, %rsi
callq 0x5c89
movq 0x8(%rbx), %rax
movq 0x8(%rax), %rcx
movq 0x10(%rcx), %r13
movq (%r13), %r13
testq %r13, %r13
je 0x6051
movl 0x18(%r13), %ecx
cmpl $0x1, %ecx
jne 0x6058
addq $0x20, %r13
jmp 0x5f7f
movq 0x8(%rbx), %rax
movq (%rax), %rdi
movq %r14, %rsi
callq 0x5c89
movq 0x8(%rbx), %rax
movl 0x8(%rax), %ecx
cmpl $0x13, %ecx
je 0x6177
cmpl $0x12, %ecx
jne 0x61dd
pushq $0x1
popq %rdi
callq 0x73c8
movq 0x10(%rbx), %rcx
movq %rax, (%rcx)
movq 0x8(%rbx), %rax
movq (%rax), %rax
movq 0x10(%rax), %rax
movq (%rax), %rdi
callq 0x7460
movq 0x10(%rbx), %rcx
movq (%rcx), %rcx
movq %rax, 0x20(%rcx)
jmp 0x61f3
testq %rcx, %rcx
setne %sil
je 0x61d9
xorl %edi, %edi
cmpl $0x2, 0x10(%rax)
jae 0x622f
testb %sil, %sil
cmovneq %rcx, %rdi
movq 0x10(%rdi), %rax
movq (%rax), %rax
movq 0x20(%rax), %rdi
callq 0x7583
movl %eax, %ebp
testq %r14, %r14
je 0x6122
cmpl $0x4, (%r14)
jne 0x6122
movslq %ebp, %rax
movq 0x8(%r14), %rcx
imulq (%rcx), %rax
movq %rax, (%rcx)
jmp 0x61d9
movl 0x18, %ecx
cmpl $0x3, %ecx
jne 0x6202
movl (%r13), %ecx
cmpl (%rax), %ecx
jne 0x6226
pushq $0x1
popq %rdx
movl %edx, 0x4(%rsp)
xorl %r15d, %r15d
xorl %ebp, %ebp
movslq %ecx, %rcx
cmpq %rcx, %rbp
jge 0x6119
movq 0x10(%rax), %rax
movq (%rax,%r15), %rdi
movq %r14, %rsi
callq 0x5c89
movq 0x10(%r13), %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 0x7720
testl %eax, %eax
jne 0x6103
movq 0x8(%rbx), %rax
movq 0x10(%rax), %rsi
addq %r15, %rsi
movq %r12, %rdi
callq 0x5c20
testl %eax, %eax
jne 0x6103
leaq 0x26fa(%rip), %rdi      # 0x87d4
movl 0x4(%rsp), %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 0x5aa4
incq %rbp
movq 0x8(%rbx), %rax
movl (%rax), %ecx
incl 0x4(%rsp)
addq $0x8, %r15
jmp 0x6079
movq 0x20(%r13), %rdi
jmp 0x61e7
cmpl $0x1, %ebp
je 0x61d9
pushq $0x8
popq %rdi
callq 0x20f0
movslq %ebp, %rcx
movq %rcx, (%rax)
pushq $0x4
popq %rdi
movq %rax, %rsi
callq 0x5020
pushq $0x2
popq %rdi
movq %rax, %rsi
movq %r14, %rdx
callq 0x5404
movq %rax, %r15
movq 0x10(%r14), %rax
movq (%rax), %rdi
callq 0x7460
movq 0x10(%r15), %rcx
movq %rax, (%rcx)
movq 0x8(%rbx), %rax
cmpq (%rax), %r14
je 0x61d6
movq %r15, 0x8(%rax)
jmp 0x61d9
movq (%rax), %rax
movq 0x10(%rax), %rax
movq (%rax), %rax
movl 0x18(%rax), %ecx
addl $-0x3, %ecx
cmpl $-0x3, %ecx
ja 0x61c3
leaq 0x25fe(%rip), %rdi      # 0x8791
xorl %eax, %eax
callq 0x2080
movq 0x8(%rbx), %rax
movq (%rax), %rax
movq 0x10(%rax), %rax
movq (%rax), %rdi
callq 0x75e7
pushq $0xa
popq %rdi
callq 0x2040
movq 0x8(%rbx), %rax
movq (%rax), %rax
movq 0x10(%rax), %rax
movq (%rax), %rax
movq 0x20(%rax), %rdi
jmp 0x61e7
xorl %esi, %esi
movq %r14, %rdi
movq %rdx, %r14
jmp 0x6008
movq %r15, (%rax)
movq 0x8(%rbx), %rax
movq (%rax), %rax
movq 0x10(%rax), %rax
movq (%rax), %rdi
callq 0x7460
movq 0x10(%rbx), %rcx
movq %rax, (%rcx)
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x25b5(%rip), %rdi      # 0x87be
xorl %eax, %eax
callq 0x2080
movq %rbx, %rdi
callq 0x265d
leaq 0x2606(%rip), %rdi      # 0x8825
callq 0x2060
jmp 0x6243
leaq 0x25db(%rip), %rdi      # 0x8808
jmp 0x6236
leaq 0x261c(%rip), %rdi      # 0x8852
callq 0x2060
movq %rbx, %rdi
callq 0x265d
pushq $-0x1
popq %rdi
callq 0x2110
nop