// File: /workspace/github_c_makefile_star2_O2/goodpaul6[P]generic/script.c
// Function: compile_value_expr
static void compile_value_expr(script_t* script, expr_t* exp)
{
	compile_file_line_info(script, exp, 0);
	
	switch(exp->type)
	{
		case EXP_NULL:
		{
			append_code(script, OP_PUSH_NULL);
		} break;
		
		case EXP_STRUCT_NEW:
		{
			char* initialized_members = emalloc(exp->newx.type->ds.members.length);
			memset(initialized_members, 0, exp->newx.type->ds.members.length);
			
			int num_init = 0;
			for(int i = exp->newx.init.length - 1; i >= 0; --i)
			{
				expr_t* init = vec_get_value(&exp->newx.init, i, expr_t*);
				int index = get_struct_type_member_index(exp->newx.type, init->binx.lhs->varx.name);
				
				if(index < 0) error_exit_e(init, "Attempted to initialize non-existent member '%s' in struct %s instantiation\n", 
							  init->binx.lhs->varx.name, exp->newx.type->ds.name);
							  
				initialized_members[index] = 1;
				++num_init;
				
				append_code(script, OP_PUSH_NUMBER);
				append_int(script, register_number(script, index));
				
				compile_value_expr(script, init->binx.rhs);
			}
			
			// NOTE: iterate over all the member types, check if they've been
			// initialized; if they haven't, and they have a default initializer
			// then use that
			for(int i = exp->newx.type->ds.members.length - 1; i >= 0; --i)
			{
				if(!initialized_members[i])
				{
					type_tag_member_t* mem = vec_get(&exp->newx.type->ds.members, i);
					if(mem->default_value)
					{
						append_code(script, OP_PUSH_NUMBER);
						append_int(script, register_number(script, i));
						
						compile_value_expr(script, mem->default_value);
						++num_init;
					}
				}
			}
			
			append_code(script, OP_PUSH_STRUCT);
			// NOTE: Unions only have 1 member location
			if(exp->newx.type->ds.is_union)
				append_int(script, 1);
			else
				append_int(script, exp->newx.type->ds.members.length);
			append_int(script, num_init);
			
			free(initialized_members);
		} break;
		
		case EXP_DOT:
		{
			int index = get_struct_type_member_index(exp->dotx.value->tag, exp->dotx.name);
			if(index < 0) error_exit_e(exp, "Attempted to access non-existent member '%s' in struct %s\n", exp->dotx.name, exp->dotx.value->tag->ds.name);
			
			compile_value_expr(script, exp->dotx.value);
			append_code(script, OP_STRUCT_GET);
			append_int(script, index);		
		} break;

		case EXP_COLON:
		{
			func_decl_t* decl = get_struct_member_function(script, exp->dotx.value->tag->ds.name, exp->dotx.name);
			if (!decl)
				error_exit_e(exp, "Value of type '%s' has no member function '%s'\n", exp->dotx.value->tag->ds.name, exp->dotx.name);

			append_code(script, OP_PUSH_FUNC);
			append_int(script, decl->index);
		} break;
			
		case EXP_BOOL:
		{
			if(exp->boolean_value) append_code(script, OP_PUSH_TRUE);
			else append_code(script, OP_PUSH_FALSE);
		} break;
		
		case EXP_CHAR:
		{
			append_code(script, OP_PUSH_CHAR);
			append_int(script, exp->code);
		} break;
		
		case EXP_ARRAY_INDEX:
		{
			compile_value_expr(script, exp->array_index.index);
			compile_value_expr(script, exp->array_index.array);
			if(exp->array_index.array->tag->type == TAG_STRING)
				append_code(script, OP_STRING_GET);
			else
				append_code(script, OP_ARRAY_GET);
		} break;
		
		case EXP_ARRAY_LITERAL:
		{
			for(int i = 0; i < exp->array_literal.values.length; ++i)
			{
				expr_t* e = vec_get_value(&exp->array_literal.values, i, expr_t*);
				compile_value_expr(script, e);
			}
			append_code(script, OP_PUSH_ARRAY_BLOCK);
			append_int(script, (int)exp->array_literal.values.length);
		} break;
		
		case EXP_LEN:
		{
			compile_value_expr(script, exp->len);
			if(exp->len->tag->type == TAG_STRING) append_code(script, OP_STRING_LEN);
			else if(exp->len->tag->type == TAG_ARRAY) append_code(script, OP_ARRAY_LEN);
		} break;
		
		case EXP_VAR:
		{
			if(exp->varx.decl)
			{
				if(exp->varx.decl->parent)
					append_code(script, OP_GETLOCAL);
				else
					append_code(script, OP_GET);
					
				append_int(script, exp->varx.decl->index);
			}
			else
			{
				// NOTE: This assumes resolve_symbols checked for a function reference existing
				func_decl_t* decl = reference_function(script, exp->varx.name);
				
				// TODO: Switch here
				if(decl->type == DECL_FUNCTION) append_code(script, OP_PUSH_FUNC);
				else if (decl->type == DECL_EXTERN) append_code(script, OP_PUSH_EXTERN_FUNC);
				else error_exit_p("Invalid function declaration type\n");
				
				append_int(script, decl->index);
			}
		} break;
		
		case EXP_EXTERN:
		case EXP_EXTERN_LIST: break;
		
		case EXP_NUMBER:
		{
			append_code(script, OP_PUSH_NUMBER);
			append_int(script, exp->number_index);
		} break;
		
		case EXP_STRING:
		{
			append_code(script, OP_PUSH_STRING);
			append_int(script, exp->string_index);
		} break;
	
		case EXP_PAREN:
		{
			compile_value_expr(script, exp->paren);
		} break;
		
		case EXP_UNARY:
		{
			compile_value_expr(script, exp->unaryx.rhs);
			switch(exp->unaryx.op)
			{
				case TOK_MINUS: append_code(script, OP_NEG); break;
				case TOK_NOT: append_code(script, OP_NOT); break;
				// NOTE: perhaps error here
			}
		} break;
		
		case EXP_BINARY:
		{
			compile_value_expr(script, exp->binx.rhs);
			compile_value_expr(script, exp->binx.lhs);
			
			switch(exp->binx.op)
			{
				case TOK_PLUS: append_code(script, OP_ADD); break;
				case TOK_MINUS: append_code(script, OP_SUB); break;
				case TOK_MUL: append_code(script, OP_MUL); break;
				case TOK_DIV: append_code(script, OP_DIV); break;
				case TOK_MOD: append_code(script, OP_MOD); break;

				case TOK_LT: append_code(script, OP_LT); break;
				case TOK_GT: append_code(script, OP_GT); break;
				case TOK_LTE: append_code(script, OP_LTE); break;
				case TOK_GTE: append_code(script, OP_GTE); break;
				
				case TOK_LAND: append_code(script, OP_LAND); break;
				case TOK_LOR: append_code(script, OP_LOR); break;
				
				case TOK_EQUALS: append_code(script, OP_EQU); break;
				case TOK_NOTEQUAL: append_code(script, OP_EQU); append_code(script, OP_NOT); break;
				
				default: break;
			}
		} break;
		
		case EXP_CALL:
		{
			compile_call(script, exp);
			append_code(script, OP_PUSH_RETVAL);
			
			// NOTE: because branching
			compile_file_line_info(script, exp, 1);
		} break;
		
		default:
			error_exit_e(exp, "Non-value expression used in value context\n");
			break;
	}
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x18, %rsp
movq %rsi, %r14
movq %rdi, %rbx
leaq 0x1ffc(%rip), %r15      # 0xd534
movq %rbx, %rdi
movq %r14, %rsi
xorl %edx, %edx
callq 0xb473
movl 0x28(%r14), %eax
cmpq $0x18, %rax
ja 0xb9a6
movslq (%r15,%rax,4), %rax
addq %r15, %rax
jmpq *%rax
movq 0x38(%r14), %r14
jmp 0xb538
movq 0x40(%r14), %rsi
movq %rbx, %rdi
callq 0xb51a
movq 0x38(%r14), %rsi
movq %rbx, %rdi
callq 0xb51a
movl 0x48(%r14), %eax
addl $-0x25, %eax
cmpl $0xc, %eax
ja 0xb7b4
leaq 0x2007(%rip), %rcx      # 0xd598
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
pushq $0x13
jmp 0xb96b
leaq 0x40(%r14), %r15
xorl %r12d, %r12d
cmpq %r12, 0x50(%r14)
jbe 0xb5c9
movq %r15, %rdi
movq %r12, %rsi
callq 0xc15c
movq (%rax), %rsi
movq %rbx, %rdi
callq 0xb51a
incq %r12
jmp 0xb5a8
pushq $0x9
popq %rsi
movq %rbx, %rdi
callq 0x7117
movl 0x50(%r14), %esi
jmp 0xb831
movq %rbx, %rdi
movq %r14, %rsi
callq 0xba98
pushq $0xa
popq %rsi
movq %rbx, %rdi
callq 0x7117
pushq $0x1
popq %rdx
movq %rbx, %rdi
movq %r14, %rsi
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0xb473
pushq $0x5
jmp 0xb824
pushq $0x3
popq %rsi
movq %rbx, %rdi
callq 0x7117
movsbl 0x38(%r14), %esi
jmp 0xb831
movq 0x38(%r14), %rax
movq 0x40(%r14), %rdx
movq 0x30(%rax), %rax
movq 0x30(%rax), %rsi
movq %rbx, %rdi
callq 0x8759
testq %rax, %rax
je 0xb9d8
movq %rax, %r15
pushq $0x6
popq %rsi
movq %rbx, %rdi
callq 0x7117
movl 0x60(%r15), %esi
jmp 0xb831
movq %rbx, %rdi
xorl %esi, %esi
jmp 0xb96f
movq 0x38(%r14), %rax
movq 0x40(%r14), %rsi
movq 0x30(%rax), %rdi
callq 0x88d3
testl %eax, %eax
js 0xb9f1
movl %eax, %r15d
movq 0x38(%r14), %rsi
movq %rbx, %rdi
callq 0xb51a
pushq $0x11
popq %rsi
movq %rbx, %rdi
callq 0x7117
movq %rbx, %rdi
movl %r15d, %esi
jmp 0xb834
movq 0x38(%r14), %rsi
movq %rbx, %rdi
callq 0xb51a
movq 0x38(%r14), %rax
movq 0x30(%rax), %rax
movl 0x20(%rax), %eax
cmpl $0x7, %eax
je 0xb952
cmpl $0x5, %eax
jne 0xb7b4
pushq $0xc
jmp 0xb96b
movq 0x38(%r14), %rax
movq 0x70(%rax), %rdi
callq 0x325f
movq %rax, %rdi
movq 0x38(%r14), %rax
movq 0x70(%rax), %rdx
xorl %r12d, %r12d
movq %rdi, -0x30(%rbp)
xorl %esi, %esi
callq 0x2110
leaq 0x40(%r14), %rax
movq %rax, -0x38(%rbp)
movl 0x50(%r14), %eax
decq %rax
movq %rax, -0x40(%rbp)
movq -0x40(%rbp), %rax
leaq (%rax,%r12), %rsi
testl %esi, %esi
js 0xb859
andl $0x7fffffff, %esi       # imm = 0x7FFFFFFF
movq -0x38(%rbp), %rdi
callq 0xc15c
movq (%rax), %r15
movq 0x38(%r14), %rdi
movq 0x38(%r15), %rax
movq 0x38(%rax), %rsi
callq 0x88d3
testl %eax, %eax
js 0xb9b7
movl %eax, %r13d
movl %eax, %eax
movq -0x30(%rbp), %rcx
movb $0x1, (%rcx,%rax)
movq %rbx, %rdi
pushq $0x4
popq %rsi
callq 0x7117
cvtsi2sd %r13d, %xmm0
movq %rbx, %rdi
callq 0x79de
movq %rbx, %rdi
movl %eax, %esi
callq 0xba1b
movq 0x40(%r15), %rsi
movq %rbx, %rdi
callq 0xb51a
decq %r12
jmp 0xb714
movq 0x38(%r14), %rsi
movq %rbx, %rdi
callq 0xb51a
movl 0x40(%r14), %eax
cmpl $0x23, %eax
je 0xb969
cmpl $0x26, %eax
jne 0xb7b4
pushq $0x1e
jmp 0xb96b
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x40(%r14), %rax
testq %rax, %rax
je 0xb8ea
xorl %ecx, %ecx
cmpq $0x0, (%rax)
setne %cl
leal 0x26(,%rcx,2), %esi
movq %rbx, %rdi
callq 0x7117
movq 0x40(%r14), %rax
movl 0x1c(%rax), %esi
jmp 0xb831
movq 0x40(%r14), %rsi
movq %rbx, %rdi
callq 0xb51a
movq 0x38(%r14), %rsi
movq %rbx, %rdi
callq 0xb51a
movq 0x38(%r14), %rax
movq 0x30(%rax), %rax
cmpl $0x5, 0x20(%rax)
jne 0xb8e3
pushq $0xe
jmp 0xb96b
pushq $0x4
popq %rsi
movq %rbx, %rdi
callq 0x7117
movl 0x38(%r14), %esi
movq %rbx, %rdi
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0xba1b
cmpb $0x0, 0x38(%r14)
je 0xb921
pushq $0x1
jmp 0xb96b
movq 0x38(%r14), %rax
movl 0x70(%rax), %r13d
negl %r12d
decq %r13
testl %r13d, %r13d
js 0xb8c9
movl %r13d, %esi
andl $0x7fffffff, %esi       # imm = 0x7FFFFFFF
movq -0x30(%rbp), %rax
cmpb $0x0, (%rax,%rsi)
jne 0xb864
movq 0x38(%r14), %rdi
addq $0x60, %rdi
callq 0xc15c
cmpq $0x0, 0x18(%rax)
je 0xb864
movq %rax, %r15
movq %rbx, %rdi
pushq $0x4
popq %rsi
callq 0x7117
cvtsi2sd %r13d, %xmm0
movq %rbx, %rdi
callq 0x79de
movq %rbx, %rdi
movl %eax, %esi
callq 0xba1b
movq 0x18(%r15), %rsi
movq %rbx, %rdi
callq 0xb51a
incl %r12d
jmp 0xb864
pushq $0xb
popq %rsi
movq %rbx, %rdi
callq 0x7117
movq 0x38(%r14), %rax
cmpb $0x0, 0x28(%rax)
je 0xb925
pushq $0x1
popq %rsi
jmp 0xb928
pushq $0xf
jmp 0xb96b
movq 0x38(%r14), %rsi
movq %rbx, %rdi
callq 0x760e
movq %rax, %r14
movl 0x8(%rax), %ecx
movb $0x6, %al
testl %ecx, %ecx
je 0xb90d
cmpl $0x1, %ecx
jne 0xba0d
movb $0x7, %al
movzbl %al, %esi
movq %rbx, %rdi
callq 0x7117
movl 0x60(%r14), %esi
jmp 0xb831
pushq $0x2
jmp 0xb96b
movl 0x70(%rax), %esi
movq %rbx, %rdi
callq 0xba1b
movq %rbx, %rdi
movl %r12d, %esi
callq 0xba1b
movq -0x30(%rbp), %rdi
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x2030
pushq $0xd
jmp 0xb96b
pushq $0x20
jmp 0xb96b
pushq $0x17
jmp 0xb96b
pushq $0x20
popq %rsi
movq %rbx, %rdi
callq 0x7117
pushq $0x1f
popq %rsi
movq %rbx, %rdi
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x7117
pushq $0x1c
jmp 0xb96b
pushq $0x15
jmp 0xb96b
pushq $0x16
jmp 0xb96b
pushq $0x1a
jmp 0xb96b
pushq $0x14
jmp 0xb96b
pushq $0x18
jmp 0xb96b
pushq $0x19
jmp 0xb96b
pushq $0x1d
jmp 0xb96b
pushq $0x1b
jmp 0xb96b
leaq 0x3c4a(%rip), %rsi      # 0xf5f7
movq %r14, %rdi
xorl %eax, %eax
callq 0x882a
movq 0x38(%r15), %rax
movq 0x38(%rax), %rdx
movq 0x38(%r14), %rax
movq 0x30(%rax), %rcx
leaq 0x3b89(%rip), %rsi      # 0xf557
movq %r15, %rdi
xorl %eax, %eax
callq 0x882a
movq 0x38(%r14), %rax
movq 0x40(%r14), %rcx
movq 0x30(%rax), %rax
movq 0x30(%rax), %rdx
leaq 0x3bb5(%rip), %rsi      # 0xf5a4
jmp 0xba08
movq 0x38(%r14), %rax
movq 0x40(%r14), %rdx
movq 0x30(%rax), %rax
movq 0x30(%rax), %rcx
leaq 0x2e5c(%rip), %rsi      # 0xe864
movq %r14, %rdi
jmp 0xb9d1
leaq 0x3bc0(%rip), %rdi      # 0xf5d4
xorl %eax, %eax
callq 0x78e4