// File: /workspace/github_c_makefile_star2_O2/Encryptr[P]O-plus-plus/opp/analysis/analysis.c
// Function: opp_analize_time_eval
static struct Opp_Node* opp_analize_time_eval(struct Opp_Analize* ctx, struct Opp_Node* expr)
{
	#define CLEAR_NODE(node, lhs) { \
		temp.line = node->debug.line;\
		temp.colum = node->debug.colum; \
		memset(node, 0, sizeof(struct Opp_Node)); \
		node->type = EUNARY; \
		node->debug = temp; \
		if (lhs->unary_expr.type == TSTR || lhs->unary_expr.type == TINTEGER) \
			node->unary_expr.type = TINTEGER; \
		else \
			node->unary_expr.type = TFLOAT; \
	}

	#define NUM_OP(op) { \
		if (lhs->unary_expr.type == TINTEGER || lhs->unary_expr.type == TSTR) { \
			if (rhs->unary_expr.type == TFLOAT) \
				expr->unary_expr.val.i64val = lhs->unary_expr.val.i64val op (int64_t)rhs->unary_expr.val.f64val; \
			else \
				expr->unary_expr.val.i64val = lhs->unary_expr.val.i64val op rhs->unary_expr.val.i64val; \
		} \
		else { \
			if (rhs->unary_expr.type == TINTEGER) \
				expr->unary_expr.val.f64val = lhs->unary_expr.val.f64val op (double)rhs->unary_expr.val.i64val; \
			else \
				expr->unary_expr.val.f64val = lhs->unary_expr.val.f64val op rhs->unary_expr.val.f64val; \
		} \
	}

	#define CMP_OP(op) { \
		if (lhs->unary_expr.type == TINTEGER || lhs->unary_expr.type == TSTR) { \
			if (rhs->unary_expr.type == TFLOAT) \
				expr->unary_expr.val.i64val = lhs->unary_expr.val.i64val op (int64_t)rhs->unary_expr.val.f64val; \
			else \
				expr->unary_expr.val.i64val = lhs->unary_expr.val.i64val op rhs->unary_expr.val.i64val; \
		} \
		else { \
			if (rhs->unary_expr.type == TINTEGER) \
				expr->unary_expr.val.i64val = lhs->unary_expr.val.f64val op (double)rhs->unary_expr.val.i64val; \
			else \
				expr->unary_expr.val.i64val = lhs->unary_expr.val.f64val op rhs->unary_expr.val.f64val; \
		} \
	}

	struct Opp_Node* lhs = NULL;
	struct Opp_Node* rhs = NULL;
	struct Opp_Debug temp;

	switch (expr->type)
	{
		case EUNARY: {
			if (expr->unary_expr.type == TIDENT)
				return NULL;
			return expr;
		}

		case EBIN: {
			// TODO: add x * 0 and x* 1 optimizations
			lhs = opp_analize_time_eval(ctx, expr->bin_expr.left);
			rhs = opp_analize_time_eval(ctx, expr->bin_expr.right);
			
			if (lhs == NULL || rhs == NULL) return NULL;

			const int op = expr->bin_expr.tok;
			CLEAR_NODE(expr, lhs);


			switch (op)
			{
				case TADD: NUM_OP(+=); break;
				case TMIN: NUM_OP(-=); break;
				case TMUL: NUM_OP(*=); break;
				case TDIV: NUM_OP(/=); break;
				case TMOD: 
					if (lhs->unary_expr.type != TINTEGER && lhs->unary_expr.type != TSTR)
						opp_semantics_error(ctx, expr, "Mod operation can only be preformed on integers");
					lhs->unary_expr.val.i64val %= rhs->unary_expr.val.i64val;
					break;

				default: break;
			}

			return expr;
		}

		case ELOGIC: {
			lhs = opp_analize_time_eval(ctx, expr->logic_expr.left);
			rhs = opp_analize_time_eval(ctx, expr->logic_expr.right);
			
			if (lhs == NULL || rhs == NULL) return NULL;

			const int op = expr->logic_expr.tok;
			CLEAR_NODE(expr, lhs);
			expr->unary_expr.type = TINTEGER;

			switch (op)
			{
				case TEQEQ:  CMP_OP(==); break;
				case TNOTEQ: CMP_OP(!=); break;
				case TLT:    CMP_OP(<);  break;
				case TLE:    CMP_OP(<=); break;
				case TGT:    CMP_OP(>);  break;
				case TGE:    CMP_OP(>=); break;
				case TOR:    CMP_OP(||); break;
				case TAND:   CMP_OP(&&); break;
				default: break;
			}

			return expr;
		}

		case ESUB: {
			lhs = opp_analize_time_eval(ctx, expr->sub_expr.unary);
			
			if (lhs == NULL) return NULL;
			
			CLEAR_NODE(expr, lhs);
			if (lhs->unary_expr.type == TSTR)
				opp_semantics_error(ctx, expr, "Attempting to negate str '%s'",
					lhs->unary_expr.val.strval);

			if (lhs->unary_expr.type == TINTEGER)
				expr->unary_expr.val.i64val = -lhs->unary_expr.val.i64val;
			else
				expr->unary_expr.val.f64val = -lhs->unary_expr.val.f64val;

			return expr;
		}

		// TODO: Add sizeof here

		default: break;
	}
	return NULL;
}

// Assembly:
pushq %r15
pushq %r14
pushq %rbx
movl (%rsi), %ecx
xorl %eax, %eax
decl %ecx
cmpl $0x5, %ecx
ja 0x34ab
movq %rsi, %rbx
movq %rdi, %r15
leaq 0x76a1(%rip), %rdx      # 0xa4d8
movslq (%rdx,%rcx,4), %rcx
addq %rdx, %rcx
jmpq *%rcx
movq 0x20(%rbx), %rsi
movq %r15, %rdi
callq 0x2e16
movq %rax, %r14
movq 0x18(%rbx), %rsi
movq %r15, %rdi
callq 0x2e16
movq %rax, %rcx
testq %r14, %r14
sete %al
testq %rcx, %rcx
sete %dl
orb %al, %dl
jne 0x302a
movl 0x8(%rbx), %edx
movl 0x10(%rbx), %eax
xorpd %xmm0, %xmm0
movupd %xmm0, 0x8(%rbx)
movupd %xmm0, 0x18(%rbx)
movupd %xmm0, 0x28(%rbx)
movupd %xmm0, 0x38(%rbx)
movl $0x5, (%rbx)
movl %edx, 0x8(%rbx)
movl 0x10(%r14), %edx
cmpl $0x5, %edx
sete %sil
cmpl $0x2, %edx
sete %dl
orb %sil, %dl
movzbl %dl, %edx
xorl $0x3, %edx
movl %edx, 0x10(%rbx)
addl $-0x13, %eax
cmpl $0x4, %eax
ja 0x34a8
leaq 0x7647(%rip), %rdx      # 0xa510
movslq (%rdx,%rax,4), %rax
addq %rdx, %rax
jmpq *%rax
movl 0x10(%r14), %eax
cmpl $0x5, %eax
je 0x2ee4
cmpl $0x2, %eax
jne 0x32b6
cmpl $0x3, 0x10(%rcx)
jne 0x3266
cvttsd2si 0x18(%rcx), %rax
addq 0x18(%r14), %rax
jmp 0x3278
xorl %eax, %eax
cmpl $0x1, 0x10(%rbx)
cmovneq %rbx, %rax
jmp 0x34ab
movq 0x20(%rbx), %rsi
movq %r15, %rdi
callq 0x2e16
movq %rax, %r14
movq 0x18(%rbx), %rsi
movq %r15, %rdi
callq 0x2e16
testq %r14, %r14
sete %cl
testq %rax, %rax
sete %dl
orb %cl, %dl
jne 0x302a
movl 0x8(%rbx), %edx
movl 0x10(%rbx), %ecx
xorpd %xmm0, %xmm0
movupd %xmm0, 0x8(%rbx)
movupd %xmm0, 0x18(%rbx)
movupd %xmm0, 0x28(%rbx)
movupd %xmm0, 0x38(%rbx)
movl $0x5, (%rbx)
movl %edx, 0x8(%rbx)
movl $0x2, 0x10(%rbx)
addl $-0x7, %ecx
cmpl $0x7, %ecx
ja 0x34a8
leaq 0x7574(%rip), %rdx      # 0xa4f0
movslq (%rdx,%rcx,4), %rcx
addq %rdx, %rcx
jmpq *%rcx
movl 0x10(%r14), %ecx
cmpl $0x5, %ecx
je 0x2f97
cmpl $0x2, %ecx
jne 0x33d3
cmpl $0x3, 0x10(%rax)
movq 0x18(%r14), %rcx
jne 0x3321
testq %rcx, %rcx
jne 0x34f6
jmp 0x31dc
movq 0x10(%rbx), %rsi
movq %r15, %rdi
callq 0x2e16
testq %rax, %rax
je 0x302a
movl 0x8(%rbx), %ecx
xorpd %xmm0, %xmm0
movupd %xmm0, 0x8(%rbx)
movupd %xmm0, 0x18(%rbx)
movupd %xmm0, 0x28(%rbx)
movupd %xmm0, 0x38(%rbx)
movl $0x5, (%rbx)
movl %ecx, 0x8(%rbx)
movl 0x10(%rax), %ecx
cmpl $0x5, %ecx
sete %dl
cmpl $0x2, %ecx
sete %cl
orb %dl, %cl
movzbl %cl, %ecx
xorl $0x3, %ecx
movl %ecx, 0x10(%rbx)
movl 0x10(%rax), %ecx
cmpl $0x2, %ecx
je 0x3031
cmpl $0x5, %ecx
je 0x353c
movsd 0x18(%rax), %xmm0
xorpd 0x7560(%rip), %xmm0     # 0xa580
movlpd %xmm0, 0x18(%rbx)
jmp 0x34a8
xorl %eax, %eax
jmp 0x34ab
xorl %ecx, %ecx
subq 0x18(%rax), %rcx
movq %rcx, 0x18(%rbx)
jmp 0x34a8
movl 0x10(%r14), %eax
cmpl $0x2, %eax
je 0x3052
cmpl $0x5, %eax
jne 0x3554
movq 0x18(%r14), %rax
cqto
idivq 0x18(%rcx)
movq %rdx, 0x18(%r14)
jmp 0x34a8
movl 0x10(%r14), %eax
cmpl $0x5, %eax
je 0x3077
cmpl $0x2, %eax
jne 0x3285
cmpl $0x3, 0x10(%rcx)
jne 0x324f
cvttsd2si 0x18(%rcx), %rcx
movq 0x18(%r14), %rax
cqto
idivq %rcx
jmp 0x3278
movl 0x10(%r14), %eax
cmpl $0x5, %eax
je 0x30a7
cmpl $0x2, %eax
jne 0x32a1
cmpl $0x3, 0x10(%rcx)
jne 0x325b
cvttsd2si 0x18(%rcx), %rax
imulq 0x18(%r14), %rax
jmp 0x3278
movl 0x10(%r14), %eax
cmpl $0x5, %eax
je 0x30d3
cmpl $0x2, %eax
jne 0x32cb
cmpl $0x3, 0x10(%rcx)
jne 0x3270
cvttsd2si 0x18(%rcx), %rax
movq 0x18(%r14), %rcx
subq %rax, %rcx
movq %rcx, 0x18(%r14)
jmp 0x3037
movl 0x10(%r14), %ecx
cmpl $0x5, %ecx
je 0x3105
cmpl $0x2, %ecx
jne 0x333f
cmpl $0x3, 0x10(%rax)
movq 0x18(%r14), %rcx
jne 0x32f5
cvttsd2si 0x18(%rax), %rax
xorl %edx, %edx
cmpq %rax, %rcx
jmp 0x32fb
movl 0x10(%r14), %ecx
cmpl $0x5, %ecx
je 0x3135
cmpl $0x2, %ecx
jne 0x3377
cmpl $0x3, 0x10(%rax)
movq 0x18(%r14), %rcx
jne 0x3300
cvttsd2si 0x18(%rax), %rax
xorl %edx, %edx
cmpq %rax, %rcx
jmp 0x3306
movl 0x10(%r14), %ecx
cmpl $0x5, %ecx
je 0x3165
cmpl $0x2, %ecx
jne 0x3398
cmpl $0x3, 0x10(%rax)
movq 0x18(%r14), %rcx
jne 0x330b
cvttsd2si 0x18(%rax), %rax
xorl %edx, %edx
cmpq %rax, %rcx
jmp 0x3311
movl 0x10(%r14), %ecx
cmpl $0x5, %ecx
je 0x3195
cmpl $0x2, %ecx
jne 0x33b3
cmpl $0x3, 0x10(%rax)
movq 0x18(%r14), %rcx
jne 0x3316
cvttsd2si 0x18(%rax), %rax
xorl %edx, %edx
cmpq %rax, %rcx
jmp 0x331c
movl 0x10(%r14), %ecx
cmpl $0x5, %ecx
je 0x31c5
cmpl $0x2, %ecx
jne 0x33fb
cmpl $0x3, 0x10(%rax)
movq 0x18(%r14), %rcx
jne 0x332f
testq %rcx, %rcx
je 0x3513
cvttsd2si 0x18(%rax), %rcx
xorl %eax, %eax
testq %rcx, %rcx
setne %al
jmp 0x327c
movl 0x10(%r14), %ecx
cmpl $0x5, %ecx
je 0x3201
cmpl $0x2, %ecx
jne 0x342a
cmpl $0x3, 0x10(%rax)
movq 0x18(%r14), %rcx
jne 0x335a
cvttsd2si 0x18(%rax), %rax
xorl %edx, %edx
cmpq %rax, %rcx
jmp 0x3360
movl 0x10(%r14), %ecx
cmpl $0x5, %ecx
je 0x3231
cmpl $0x2, %ecx
jne 0x344b
cmpl $0x3, 0x10(%rax)
movq 0x18(%r14), %rcx
jne 0x3365
cvttsd2si 0x18(%rax), %rax
xorl %edx, %edx
cmpq %rax, %rcx
jmp 0x336b
movq 0x18(%r14), %rax
cqto
idivq 0x18(%rcx)
jmp 0x3278
movq 0x18(%r14), %rax
imulq 0x18(%rcx), %rax
jmp 0x3278
movq 0x18(%r14), %rax
addq 0x18(%rcx), %rax
jmp 0x3278
movq 0x18(%r14), %rax
subq 0x18(%rcx), %rax
movq %rax, 0x18(%r14)
movq %rax, 0x18(%rbx)
jmp 0x34a8
cmpl $0x2, 0x10(%rcx)
jne 0x346b
cvtsi2sdq 0x18(%rcx), %xmm0
movsd 0x18(%r14), %xmm1
divsd %xmm0, %xmm1
jmp 0x32e5
cmpl $0x2, 0x10(%rcx)
jne 0x3478
cvtsi2sdq 0x18(%rcx), %xmm0
jmp 0x347d
cmpl $0x2, 0x10(%rcx)
jne 0x3485
cvtsi2sdq 0x18(%rcx), %xmm0
jmp 0x348a
cmpl $0x2, 0x10(%rcx)
jne 0x3492
cvtsi2sdq 0x18(%rcx), %xmm0
movsd 0x18(%r14), %xmm1
subsd %xmm0, %xmm1
movsd %xmm1, 0x18(%r14)
movsd %xmm1, 0x18(%rbx)
jmp 0x34a8
xorl %edx, %edx
cmpq 0x18(%rax), %rcx
setl %dl
jmp 0x336e
xorl %edx, %edx
cmpq 0x18(%rax), %rcx
setg %dl
jmp 0x336e
xorl %edx, %edx
cmpq 0x18(%rax), %rcx
setle %dl
jmp 0x336e
xorl %edx, %edx
cmpq 0x18(%rax), %rcx
setne %dl
jmp 0x336e
testq %rcx, %rcx
jne 0x33ef
jmp 0x33f7
testq %rcx, %rcx
jne 0x33f7
xorl %ecx, %ecx
jmp 0x3037
cmpl $0x2, 0x10(%rax)
movsd 0x18(%r14), %xmm0
jne 0x34b1
cvtsi2sdq 0x18(%rax), %xmm1
jmp 0x34b6
xorl %edx, %edx
cmpq 0x18(%rax), %rcx
setge %dl
jmp 0x336e
xorl %edx, %edx
cmpq 0x18(%rax), %rcx
sete %dl
movq %rdx, 0x18(%rbx)
jmp 0x34a8
cmpl $0x2, 0x10(%rax)
movsd 0x18(%r14), %xmm0
jne 0x34c4
cvtsi2sdq 0x18(%rax), %xmm1
xorl %eax, %eax
ucomisd %xmm1, %xmm0
jmp 0x34bc
cmpl $0x2, 0x10(%rax)
movsd 0x18(%r14), %xmm0
jne 0x34d3
cvtsi2sdq 0x18(%rax), %xmm1
jmp 0x34d8
cmpl $0x2, 0x10(%rax)
movsd 0x18(%r14), %xmm0
jne 0x34e6
cvtsi2sdq 0x18(%rax), %xmm1
cmpneqsd %xmm1, %xmm0
jmp 0x352f
cmpl $0x2, 0x10(%rax)
movsd 0x18(%r14), %xmm0
xorpd %xmm1, %xmm1
jne 0x34ee
ucomisd %xmm1, %xmm0
jne 0x33ef
jnp 0x33f7
pushq $0x1
popq %rcx
jmp 0x3037
xorl %ecx, %ecx
jmp 0x341d
cmpl $0x2, 0x10(%rax)
movsd 0x18(%r14), %xmm0
xorpd %xmm1, %xmm1
jne 0x34fe
xorl %ecx, %ecx
ucomisd %xmm1, %xmm0
jne 0x341d
jnp 0x3037
cmpq $0x0, 0x18(%rax)
setne %cl
jmp 0x3037
cmpl $0x2, 0x10(%rax)
movsd 0x18(%r14), %xmm0
jne 0x351a
cvtsi2sdq 0x18(%rax), %xmm1
xorl %eax, %eax
ucomisd %xmm1, %xmm0
jmp 0x34de
cmpl $0x2, 0x10(%rax)
movsd 0x18(%r14), %xmm0
jne 0x3529
cvtsi2sdq 0x18(%rax), %xmm1
cmpeqsd %xmm1, %xmm0
jmp 0x352f
movsd 0x18(%r14), %xmm0
divsd 0x18(%rcx), %xmm0
jmp 0x349d
movsd 0x18(%rcx), %xmm0
mulsd 0x18(%r14), %xmm0
jmp 0x349d
movsd 0x18(%rcx), %xmm0
addsd 0x18(%r14), %xmm0
jmp 0x349d
movsd 0x18(%r14), %xmm0
subsd 0x18(%rcx), %xmm0
movsd %xmm0, 0x18(%r14)
movsd %xmm0, 0x18(%rbx)
movq %rbx, %rax
popq %rbx
popq %r14
popq %r15
retq
movsd 0x18(%rax), %xmm1
xorl %eax, %eax
ucomisd %xmm0, %xmm1
seta %al
jmp 0x327c
xorl %ecx, %ecx
ucomisd 0x18(%rax), %xmm0
seta %cl
jmp 0x3037
movsd 0x18(%rax), %xmm1
xorl %eax, %eax
ucomisd %xmm0, %xmm1
setae %al
jmp 0x327c
cmpneqsd 0x18(%rax), %xmm0
jmp 0x352f
ucomisd %xmm1, %xmm0
jne 0x34f6
jnp 0x3506
pushq $0x1
popq %rax
jmp 0x327c
ucomisd %xmm1, %xmm0
jne 0x3506
jnp 0x3513
cmpneqsd 0x18(%rax), %xmm1
movq %xmm1, %rax
jmp 0x3534
xorl %eax, %eax
jmp 0x327c
xorl %ecx, %ecx
ucomisd 0x18(%rax), %xmm0
setae %cl
jmp 0x3037
cmpeqsd 0x18(%rax), %xmm0
movq %xmm0, %rax
andl $0x1, %eax
jmp 0x327c
movq 0x18(%rax), %rcx
leaq 0x74a2(%rip), %rdx      # 0xa9e9
movq %r15, %rdi
movq %rbx, %rsi
xorl %eax, %eax
callq 0x2228
leaq 0x745e(%rip), %rdx      # 0xa9b9
movq %r15, %rdi
movq %rbx, %rsi
xorl %eax, %eax
callq 0x2228