// File: /workspace/github_c_makefile_star2_O2/Yamsman[P]scc/src/ast.c
// Function: astn_type
s_type *astn_type(ast_n *node) {
	if (node == NULL) return NULL;
	if (node->kind != EXPR) return NULL;
	switch (node->dat.expr.kind) {
		//Expressions that always result in an integer
		case EXPR_LOGIC_OR:
		case EXPR_LOGIC_AND:
		case EXPR_OR:	
		case EXPR_XOR:	
		case EXPR_AND:	
		case EXPR_GTH:	
		case EXPR_LTH:	
		case EXPR_GEQ:	
		case EXPR_LEQ:	
		case EXPR_LSHIFT:
		case EXPR_RSHIFT:
		case EXPR_EQ:	
		case EXPR_NEQ:	
		case EXPR_MOD:	
		case EXPR_NOT:	
		case EXPR_LOGIC_NOT:
			return type_new(TYPE_INT);

		//Binary operations
		case EXPR_ADD:	
		case EXPR_SUB:	
		case EXPR_MUL:	
		case EXPR_DIV: {
			//Get types of LHS and RHS
			s_type *lhs = astn_type(node->dat.expr.left);
			s_type *rhs = astn_type(node->dat.expr.right);

			/*
			 * Valid cases:
			 * int/int (int)
			 * int/ptr ptr/int (ptr)
			 * int/float float/int float/float (float)
			 */
			s_type *type = NULL;
			if (lhs->kind == TYPE_FLOAT || rhs->kind == TYPE_FLOAT) {
				if (lhs->kind != TYPE_PTR && rhs->kind != TYPE_PTR)
					type = type_new(TYPE_FLOAT);
			}
			if (lhs->kind == TYPE_INT || rhs->kind == TYPE_INT) {
				if (lhs->kind == TYPE_PTR) {
					type = type_clone(lhs);
				} else if (rhs->kind == TYPE_PTR) {
					type = type_clone(rhs);
				} else {
					type = type_new(TYPE_INT);
				}
			}

			type_del(lhs);
			type_del(rhs);
			return type;
			}

		//Unary operations
		case EXPR_POS:	
		case EXPR_NEG:
		case EXPR_INC_PRE:
		case EXPR_DEC_PRE:
		case EXPR_INC_POST:
		case EXPR_DEC_POST:
			return astn_type(node->dat.expr.left);

		//Cast operation resulting in the casted type
		case EXPR_CAST:
			return type_clone(node->dat.expr.type);

		//Conditional
		case EXPR_COND:
			//Move to the result and fall through
			node = node->dat.expr.right;
		case EXPR_COND_RES: {
			s_type *lhs = astn_type(node->dat.expr.left);
			s_type *rhs = astn_type(node->dat.expr.right);
			
			//Ensure the two possible types are compatible
			s_type *type = NULL;
			if (lhs->kind == rhs->kind)
				type = type_clone(lhs);

			type_del(lhs);
			type_del(rhs);
			return type;
			}

		//Referencing
		case EXPR_REF: {
			//Add a new reference to the front of the pointer chain
			s_type *type = astn_type(node->dat.expr.left);
			s_type *r_type = type_new(TYPE_PTR);
			r_type->ref = type;
			return r_type;
		}

		//Dereferencing 
		case EXPR_DEREF:
		case EXPR_ARRAY: {
			//Follow the type chain
			s_type *type = astn_type(node->dat.expr.left);
			s_type *d_type = NULL;
			if (type != NULL) d_type = type->ref;
			type->ref = NULL;
			type_del(type);
			return d_type;
			}

		//Struct/union member access
		case EXPR_PTR_MEMB:
		case EXPR_MEMB:	{
			s_type *st_type = astn_type(node->dat.expr.left);
			s_type *m_type = NULL;
			if (node->dat.expr.kind == EXPR_PTR_MEMB)
				st_type = st_type->ref;

			//Find matching parameter
			for (int i=0; i<st_type->param.len; i++) {
				s_param *param = (s_param*)st_type->param.table[i];
				if (!strcmp(param->name, node->dat.expr.sym->name))
					m_type = type_clone(param->type);
			}

			type_del(st_type);
			return m_type;
			}

		//Return type
		case EXPR_CALL:	
			return type_clone(node->dat.expr.left->dat.expr.sym->type->ret);

		//Variable
		case EXPR_IDENT:
			return type_clone(node->dat.expr.sym->type);

		//Literals
		case EXPR_CONST:
		case EXPR_STR:
			return type_clone(node->tok.dtype);
	}
	return NULL;
}

// Assembly:
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
movq %rdi, %r14
xorl %ebx, %ebx
leaq 0x8c02(%rip), %rax      # 0xc004
testq %r14, %r14
je 0x35d6
cmpl $0x1, (%r14)
jne 0x35d6
movl 0x8(%r14), %ecx
decl %ecx
cmpl $0x25, %ecx
ja 0x35d6
movslq (%rax,%rcx,4), %rcx
addq %rax, %rcx
jmpq *%rcx
movq 0x20(%r14), %r14
jmp 0x3402
pushq $0x6
popq %rdi
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
jmp 0xb5ed
movq 0x20(%r14), %rdi
callq 0x33ed
movq %rax, %r15
movq 0x28(%r14), %rdi
callq 0x33ed
movq %rax, %r14
movl (%r15), %eax
movl (%r14), %ecx
cmpl $0x7, %eax
jne 0x348c
cmpl $0x3, %ecx
jne 0x349e
jmp 0x357d
movq 0x20(%r14), %rdi
callq 0x33ed
testq %rax, %rax
je 0x35c7
movq 0x18(%rax), %rbx
jmp 0x35c9
cmpl $0x7, %ecx
jne 0x351e
cmpl $0x3, %eax
je 0x357d
pushq $0x7
popq %rdi
callq 0xb5ed
movq %rax, %rbx
movl (%r15), %eax
jmp 0x3520
movq 0x58(%r14), %rdi
jmp 0x35b9
movq 0x20(%r14), %rdi
callq 0x33ed
movq %rax, %r15
cmpl $0x21, 0x8(%r14)
jne 0x34ce
movq 0x18(%r15), %r15
xorl %r12d, %r12d
xorl %ebx, %ebx
movslq 0x30(%r15), %rax
cmpq %rax, %r12
jge 0x3509
movq 0x28(%r15), %rax
movq (%rax,%r12,8), %r13
movq (%r13), %rdi
movq 0x18(%r14), %rax
movq (%rax), %rsi
callq 0x3110
testl %eax, %eax
jne 0x3504
movq 0x8(%r13), %rdi
callq 0xb949
movq %rax, %rbx
incq %r12
jmp 0x34d3
movq %r15, %rdi
jmp 0x35d1
movq 0x18(%r14), %rax
movq 0x8(%rax), %rdi
jmp 0x35b9
xorl %ebx, %ebx
movl (%r14), %ecx
cmpl $0x6, %eax
jne 0x3532
cmpl $0x3, %ecx
jne 0x353c
movq %r14, %rdi
jmp 0x3573
cmpl $0x6, %ecx
jne 0x357f
cmpl $0x3, %eax
je 0x3570
pushq $0x6
popq %rdi
callq 0xb5ed
jmp 0x3578
movq 0x10(%r14), %rdi
jmp 0x35b9
movq 0x28(%r14), %r14
movq 0x20(%r14), %rdi
callq 0x33ed
movq %rax, %r15
movq 0x28(%r14), %rdi
callq 0x33ed
movq %rax, %r14
movl (%r15), %eax
cmpl (%r14), %eax
jne 0x357d
movq %r15, %rdi
callq 0xb949
movq %rax, %rbx
jmp 0x357f
xorl %ebx, %ebx
movq %r15, %rdi
callq 0xb8ba
movq %r14, %rdi
jmp 0x35d1
movq 0x20(%r14), %rdi
callq 0x33ed
movq %rax, %r14
pushq $0x3
popq %rdi
callq 0xb5ed
movq %rax, %rbx
movq %r14, 0x18(%rax)
jmp 0x35d6
movq 0x20(%r14), %rax
movq 0x18(%rax), %rax
movq 0x8(%rax), %rax
movq 0x38(%rax), %rdi
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
jmp 0xb949
xorl %ebx, %ebx
andq $0x0, 0x18(%rax)
movq %rax, %rdi
callq 0xb8ba
movq %rbx, %rax
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
retq
nop