// File: /workspace/github_c_makefile_star2_O1/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 0x2fb1(%rip), %r15      # 0x96ec
testq %rbx, %rbx
je 0x6c9e
movl (%rbx), %eax
addl $-0x2, %eax
cmpl $0xd, %eax
ja 0x6c9e
movslq (%r15,%rax,4), %rax
addq %r15, %rax
jmpq *%rax
movq 0x8(%rbx), %rax
movq (%rax), %rdi
movq %r14, %rsi
callq 0x6723
movq 0x8(%rbx), %rax
movq 0x8(%rax), %rdi
movq %r14, %rsi
callq 0x6723
movq 0x8(%rbx), %rax
movq 0x10(%rax), %rbx
testq %rbx, %rbx
jne 0x673b
jmp 0x6c9e
movq 0x8(%rbx), %rax
movq (%rax), %rdi
movq %r14, %rsi
callq 0x6723
movq 0x8(%rbx), %rax
movq 0x8(%rax), %rdi
movq %r14, %rsi
callq 0x6723
movq 0x8(%rbx), %rax
movq 0x18(%rax), %rdi
movq %r14, %rsi
callq 0x6723
movq 0x8(%rbx), %rax
movq 0x10(%rax), %rbx
jmp 0x673b
movq 0x8(%rbx), %rbx
jmp 0x673b
movq 0x8(%rbx), %rax
movq 0x10(%rax), %rdi
movq %r14, %rsi
callq 0x6723
movq 0x8(%rbx), %rax
cmpq $0x0, 0x10(%rax)
je 0x6c9e
movq (%rax), %rsi
movq %r14, %rdi
callq 0x7e78
movq %rax, %r14
movq 0x8(%rbx), %rax
movq 0x10(%rax), %rax
movq 0x10(%rax), %rax
movq (%rax), %rsi
movq %r14, %rdi
callq 0x832f
testl %eax, %eax
jne 0x6c9e
movq 0x8(%rbx), %rsi
addq $0x10, %rsi
movq %r14, %rdi
callq 0x669d
testl %eax, %eax
jne 0x6c9e
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 0x6494
movq 0x8(%rbx), %rax
cmpl $0x0, 0x8(%rax)
jle 0x6c9e
xorl %r14d, %r14d
movq (%rax), %rcx
movq 0x10(%rax), %rsi
movq (%rcx,%r14,8), %rdi
callq 0x6723
incq %r14
movq 0x8(%rbx), %rax
movslq 0x8(%rax), %rcx
cmpq %rcx, %r14
jl 0x686e
jmp 0x6c9e
xorl %edi, %edi
callq 0x7f9c
movq 0x10(%rbx), %rcx
movq %rax, (%rcx)
movl $0x1, (%rax)
jmp 0x6c9e
movq 0x8(%rbx), %rax
movq (%rax), %rsi
movq %r14, %rdi
callq 0x7e78
movq %rax, %rdi
callq 0x8040
movq 0x10(%rbx), %rcx
movq %rax, (%rcx)
testq %rax, %rax
jne 0x6c9e
movq 0x8(%rbx), %rax
movq (%rax), %rsi
leaq 0x2ea4(%rip), %rdi      # 0x9785
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 0x6723
movq 0x8(%rbx), %rax
movq 0x8(%rax), %rdi
movq %r14, %rsi
callq 0x6723
movq 0x8(%rbx), %rax
movq (%rax), %rcx
movq 0x8(%rax), %rdx
movq 0x10(%rcx), %rcx
movq (%rcx), %r12
movq 0x10(%rdx), %rcx
movq (%rcx), %r15
movl 0x10(%rax), %ebp
movq %r12, %rdi
movq %r15, %rsi
callq 0x832f
testl %eax, %eax
jne 0x697d
xorl %eax, %eax
cmpl $0x18, %ebp
setne %al
leal (%rax,%rax,2), %edx
movq 0x8(%rbx), %rdi
leaq 0x8(%rdi), %rsi
callq 0x652d
testl %eax, %eax
jne 0x697d
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 0x6494
movq 0x8(%rbx), %rax
movq (%rax), %r14
xorl %ecx, %ecx
testq %r12, %r12
je 0x69a0
testq %r14, %r14
je 0x69a0
movl 0x18(%r12), %edx
decl %edx
xorl %ecx, %ecx
cmpl $0x2, %edx
cmovbq %r14, %rcx
movq 0x8(%rax), %rsi
xorl %edx, %edx
testq %r15, %r15
je 0x69bf
testq %rsi, %rsi
je 0x69bf
movl 0x18(%r15), %edi
decl %edi
xorl %edx, %edx
cmpl $0x2, %edi
cmovbq %rsi, %rdx
testq %rcx, %rcx
je 0x69d3
testq %rdx, %rdx
je 0x69d3
cmpl $0x1, 0x10(%rax)
jne 0x6cd1
movq %rcx, %rdi
orq %rdx, %rdi
je 0x6c84
testq %rdx, %rdx
cmovneq %rdx, %rsi
testq %rcx, %rcx
cmovneq %rsi, %r14
cmpl $0x2, 0x10(%rax)
jae 0x6cd1
testq %rcx, %rcx
cmovneq %rcx, %rdx
movq 0x10(%rdx), %rax
movq (%rax), %rax
movq 0x20(%rax), %rdi
callq 0x8178
movl %eax, %ebp
testq %r14, %r14
je 0x6bd2
cmpl $0x4, (%r14)
jne 0x6bd2
movslq %ebp, %rax
movq 0x8(%r14), %rcx
imulq (%rcx), %rax
movq %rax, (%rcx)
jmp 0x6c84
movq 0x8(%rbx), %rax
cmpl $0x0, 0x8(%rax)
jle 0x6c9e
xorl %r15d, %r15d
movq (%rax), %rax
movq (%rax,%r15,8), %rdi
movq %r14, %rsi
callq 0x6723
incq %r15
movq 0x8(%rbx), %rax
movslq 0x8(%rax), %rcx
cmpq %rcx, %r15
jl 0x6a47
jmp 0x6c9e
movq 0x8(%rbx), %rax
movq 0x8(%rax), %rdi
movq %r14, %rsi
callq 0x6723
movq 0x8(%rbx), %rax
movq 0x8(%rax), %rcx
movq 0x10(%rcx), %rcx
movq (%rcx), %r12
testq %r12, %r12
je 0x6a9e
cmpl $0x1, 0x18(%r12)
jne 0x6a9e
movq 0x20(%r12), %r12
jmp 0x6a8a
cmpl $0x3, 0x18(%r12)
jne 0x6cad
movl (%r12), %ecx
cmpl (%rax), %ecx
jne 0x6cda
movq 0x8(%rbx), %rax
cmpl $0x0, (%rax)
jle 0x6b6c
movl $0x1, %ebp
xorl %r15d, %r15d
xorl %r13d, %r13d
movq %r12, (%rsp)
movq 0x10(%rax), %rax
movq (%rax,%r15), %rdi
movq %r14, %rsi
callq 0x6723
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 0x832f
testl %eax, %eax
jne 0x6b4f
movq 0x8(%rbx), %rax
movq 0x10(%rax), %rsi
addq %r15, %rsi
movq %r12, %rdi
callq 0x669d
testl %eax, %eax
jne 0x6b4f
leaq 0x2cd0(%rip), %rdi      # 0x97f8
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 0x6494
incq %r13
movq 0x8(%rbx), %rax
movslq (%rax), %rcx
incl %ebp
addq $0x8, %r15
cmpq %rcx, %r13
movq (%rsp), %r12
jl 0x6ad2
movq 0x20(%r12), %rdi
jmp 0x6c92
movq 0x8(%rbx), %rax
movq (%rax), %rdi
movq %r14, %rsi
callq 0x6723
movq 0x8(%rbx), %rax
movl 0x8(%rax), %ecx
cmpl $0x13, %ecx
je 0x6c2d
cmpl $0x12, %ecx
jne 0x6c88
movl $0x1, %edi
callq 0x7f9c
movq 0x10(%rbx), %rcx
movq %rax, (%rcx)
movq 0x8(%rbx), %rax
movq (%rax), %rax
movq 0x10(%rax), %rax
movq (%rax), %rdi
callq 0x8040
movq 0x10(%rbx), %rcx
movq (%rcx), %rcx
movq %rax, 0x20(%rcx)
jmp 0x6c9e
cmpl $0x1, %ebp
je 0x6c84
movl $0x8, %edi
callq 0x2100
movslq %ebp, %rcx
movq %rcx, (%rax)
movl $0x4, %edi
movq %rax, %rsi
callq 0x57a0
movl $0x2, %edi
movq %rax, %rsi
movq %r14, %rdx
callq 0x5cd8
movq %rax, %r15
movq 0x10(%r14), %rax
movq (%rax), %rdi
callq 0x8040
movq 0x10(%r15), %rcx
movq %rax, (%rcx)
movq 0x8(%rbx), %rax
cmpq (%rax), %r14
je 0x6c81
movq %r15, 0x8(%rax)
jmp 0x6c84
movq (%rax), %rax
movq 0x10(%rax), %rax
movq (%rax), %rax
movl 0x18(%rax), %eax
addl $-0x3, %eax
cmpl $-0x3, %eax
ja 0x6c6d
leaq 0x2b6c(%rip), %rdi      # 0x97b5
xorl %eax, %eax
callq 0x2080
movq 0x8(%rbx), %rax
movq (%rax), %rax
movq 0x10(%rax), %rax
movq (%rax), %rdi
callq 0x81ed
movl $0xa, %edi
callq 0x2040
movq 0x8(%rbx), %rax
movq (%rax), %rax
movq 0x10(%rax), %rax
movq (%rax), %rax
movq 0x20(%rax), %rdi
jmp 0x6c92
movq %r15, (%rax)
movq 0x8(%rbx), %rax
movq (%rax), %rax
movq 0x10(%rax), %rax
movq (%rax), %rdi
callq 0x8040
movq 0x10(%rbx), %rcx
movq %rax, (%rcx)
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x2b2e(%rip), %rdi      # 0x97e2
xorl %eax, %eax
callq 0x2080
movq %rbx, %rdi
callq 0x26d1
leaq 0x2b7f(%rip), %rdi      # 0x9849
callq 0x2060
jmp 0x6cee
leaq 0x2b9e(%rip), %rdi      # 0x9876
jmp 0x6ce1
leaq 0x2b4b(%rip), %rdi      # 0x982c
callq 0x2060
movq %rbx, %rdi
callq 0x26d1
movl $0xffffffff, %edi       # imm = 0xFFFFFFFF
callq 0x2120