// File: /workspace/github_c_makefile_star2_O3/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 %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
pushq %rax
testq %rdi, %rdi
je 0x3672
movq %rdi, %r14
xorl %ebx, %ebx
leaq 0x99c2(%rip), %rax      # 0xd004
cmpl $0x1, (%r14)
jne 0x3848
movl 0x8(%r14), %ecx
decl %ecx
cmpl $0x25, %ecx
ja 0x3848
movslq (%rax,%rcx,4), %rcx
addq %rax, %rcx
jmpq *%rcx
movq 0x20(%r14), %r14
testq %r14, %r14
jne 0x3642
jmp 0x3848
xorl %ebx, %ebx
jmp 0x3848
movl $0x6, %edi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0xbf35
movq 0x20(%r14), %rdi
callq 0x3626
movq %rax, %r15
movq 0x28(%r14), %rdi
callq 0x3626
movq %rax, %r14
movl (%r15), %eax
movl (%r14), %ecx
cmpl $0x7, %eax
jne 0x36c7
cmpl $0x3, %ecx
jne 0x36d9
jmp 0x37f7
movq 0x58(%r14), %rdi
jmp 0x381c
cmpl $0x7, %ecx
jne 0x377a
cmpl $0x3, %eax
je 0x37f7
movl $0x7, %edi
callq 0xbf35
movq %rax, %rbx
movl (%r15), %eax
jmp 0x377c
movq 0x20(%r14), %rdi
callq 0x3626
testq %rax, %rax
je 0x382f
movq 0x18(%rax), %rbx
jmp 0x3831
movq 0x20(%r14), %rdi
callq 0x3626
movq %rax, %r15
cmpl $0x21, 0x8(%r14)
jne 0x3720
movq 0x18(%r15), %r15
movl 0x30(%r15), %ebp
testl %ebp, %ebp
jle 0x383e
xorl %r12d, %r12d
xorl %ebx, %ebx
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 0x375d
movq 0x8(%r13), %rdi
callq 0xc2cb
movq %rax, %rbx
movl 0x30(%r15), %ebp
incq %r12
movslq %ebp, %rax
cmpq %rax, %r12
jl 0x3731
jmp 0x3840
movq 0x18(%r14), %rax
movq 0x8(%rax), %rdi
jmp 0x381c
xorl %ebx, %ebx
movl (%r14), %ecx
cmpl $0x6, %eax
jne 0x378e
cmpl $0x3, %ecx
jne 0x3798
movq %r14, %rdi
jmp 0x37ed
cmpl $0x6, %ecx
jne 0x37f9
cmpl $0x3, %eax
je 0x37ea
movl $0x6, %edi
callq 0xbf35
jmp 0x37f2
movq 0x20(%r14), %rdi
callq 0x3626
movq %rax, %r14
movl $0x3, %edi
callq 0xbf35
movq %rax, %rbx
movq %r14, 0x18(%rax)
jmp 0x3848
movq 0x28(%r14), %r14
movq 0x20(%r14), %rdi
callq 0x3626
movq %rax, %r15
movq 0x28(%r14), %rdi
callq 0x3626
movq %rax, %r14
movl (%r15), %eax
cmpl (%r14), %eax
jne 0x37f7
movq %r15, %rdi
callq 0xc2cb
movq %rax, %rbx
jmp 0x37f9
xorl %ebx, %ebx
movq %r15, %rdi
callq 0xc233
movq %r14, %rdi
jmp 0x3843
movq 0x10(%r14), %rdi
jmp 0x381c
movq 0x20(%r14), %rax
movq 0x18(%rax), %rax
movq 0x8(%rax), %rax
movq 0x38(%rax), %rdi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0xc2cb
xorl %ebx, %ebx
movq $0x0, 0x18(%rax)
movq %rax, %rdi
jmp 0x3843
xorl %ebx, %ebx
movq %r15, %rdi
callq 0xc233
movq %rbx, %rax
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
nop