// File: ConsoleTVs[P]VirtualMachine/src/vm.cpp
// Function: VM::Instance::run()
void Instance::run()
{
    this->program_counter = 0;
    // The run basically is a big loop with a switch inside
    // We stop the loop when the exit OPCODE is found.
    for (uint32_t instruction;;this->program_counter++) {
        // Get need a way to get the instruction that we need to run
        // thus we need a program counter :)
        // This will get the current executing instruction
        instruction = GET_INSTRUCTION(this->program_counter);

        // Let's define what our opcodes actually do!
        switch (instruction) {
            case OP_CONSTANT: {
                // We add a new constant to the stack.
                // We got the index of the constant pool in the next program_counter
                //
                push(this->program->constants.at(GET_INSTRUCTION(++this->program_counter)));
                break;
            }
            case OP_ADD: {
                // We pop the last 2 values on the stack and further perform an addition
                Value *a = this->pop();
                Value *b = this->pop();

                // The following addition need to be done by a separate action, since two classes cannot be added!
                // We need a way to add two separate values of diferent types. An example would be to define them in
                // the class. As we defined a to_float method, we can now push a new value to the stack that's the
                // addition of the 2 poped values as a float. Keep in mind it's b - a, not a - b because of how
                // a stack works. First in, last out!

                // Check if you're adding a string at some of the operans:
                if (a->type == VALUE_STRING || b->type == VALUE_STRING) push(new Value(new std::string(b->to_string() + a->to_string())));
                else push(new Value(b->to_float() + a->to_float()));

                break;
            }
            case OP_SUB: {
                // We pop the last 2 values on the stack and further perform a substraction
                Value *a = this->pop();
                Value *b = this->pop();

                push(new Value(b->to_float() - a->to_float()));
                break;
            }
            case OP_MUL: {
                // We pop the last 2 values on the stack and further perform a multiplication
                Value *a = this->pop();
                Value *b = this->pop();

                // Check if we want to multiply a string.
                if (b->type == VALUE_STRING && a->type == VALUE_STRING) { printf("Can't multiply two strings\n"); return; }
                else if (b->type == VALUE_STRING) push(new Value(multiplyString(b->svalue, a->to_float())));
                else if (a->type == VALUE_STRING) push(new Value(multiplyString(a->svalue, b->to_float())));
                else push(new Value(b->to_float() * a->to_float()));

                break;
            }
            case OP_DIV: {
                // We pop the last 2 values on the stack and further perform a division
                Value *a = this->pop();
                Value *b = this->pop();

                // Keep in mind a division by 0 cannot be performed.
                // Let's check to avoid that:
                if (a->to_float() == 0) {
                    printf("A division by 0 was found. Aborting.\n");
                    return;
                }

                push(new Value(b->to_float() * a->to_float()));
                break;
            }
            case OP_PRINT: {
                // When the print opcode is found, we pop and print the last
                // value on the stack. So we need a way to represent the values as string
                auto value = pop();
                printf("%s\n", value->to_string().c_str());
                break;
            }
            case OP_EXIT: { return; }
        }
    }
}

// Assembly:
subq $0x188, %rsp            # imm = 0x188
movq %rdi, 0x180(%rsp)
movq 0x180(%rsp), %rax
movq %rax, 0xb0(%rsp)
movl $0x0, 0x810(%rax)
movq 0xb0(%rsp), %rax
movq 0x808(%rax), %rdi
movl 0x810(%rax), %eax
movl %eax, %esi
callq 0x5000
movl (%rax), %eax
movl %eax, 0x17c(%rsp)
movl 0x17c(%rsp), %eax
movq %rax, 0xa8(%rsp)
subq $0x6, %rax
ja 0x4ef7
movq 0xa8(%rsp), %rax
leaq 0x290a(%rip), %rcx      # 0x70b0
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq 0xb0(%rsp), %rcx
movq 0x808(%rcx), %rax
addq $0x18, %rax
movq %rax, 0xa0(%rsp)
movq 0x808(%rcx), %rdi
movl 0x810(%rcx), %eax
addl $0x1, %eax
movl %eax, 0x810(%rcx)
movl %eax, %eax
movl %eax, %esi
callq 0x5000
movq 0xa0(%rsp), %rdi
movl (%rax), %eax
movl %eax, %esi
callq 0x5040
movq 0xb0(%rsp), %rdi
movq (%rax), %rsi
callq 0x4700
jmp 0x4ef7
movq 0xb0(%rsp), %rdi
callq 0x46e0
movq 0xb0(%rsp), %rdi
movq %rax, 0x170(%rsp)
callq 0x46e0
movq %rax, 0x168(%rsp)
movq 0x170(%rsp), %rax
movzbl (%rax), %eax
cmpl $0x3, %eax
je 0x485d
movq 0x168(%rsp), %rax
movzbl (%rax), %eax
cmpl $0x3, %eax
jne 0x49e4
movl $0x10, %edi
callq 0x2180
movq %rax, 0x90(%rsp)
movb $0x1, 0x116(%rsp)
movl $0x20, %edi
callq 0x2180
movq %rax, 0x98(%rsp)
jmp 0x488b
movb $0x1, 0x117(%rsp)
movq 0x168(%rsp), %rsi
leaq 0x138(%rsp), %rdi
callq 0x6420
jmp 0x48aa
movq 0x170(%rsp), %rsi
leaq 0x118(%rsp), %rdi
callq 0x6420
jmp 0x48c1
movq 0x98(%rsp), %rdi
leaq 0x138(%rsp), %rsi
leaq 0x118(%rsp), %rdx
callq 0x5080
jmp 0x48e0
movq 0x98(%rsp), %rsi
movq 0x90(%rsp), %rdi
movb $0x0, 0x117(%rsp)
callq 0x3c80
jmp 0x48ff
movq 0x90(%rsp), %rsi
movq 0xb0(%rsp), %rdi
movb $0x0, 0x116(%rsp)
callq 0x4700
leaq 0x118(%rsp), %rdi
callq 0x20e0
leaq 0x138(%rsp), %rdi
callq 0x20e0
jmp 0x4a82
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x160(%rsp)
movl %eax, 0x15c(%rsp)
jmp 0x49c6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x160(%rsp)
movl %eax, 0x15c(%rsp)
jmp 0x49ab
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x160(%rsp)
movl %eax, 0x15c(%rsp)
jmp 0x499e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x160(%rsp)
movl %eax, 0x15c(%rsp)
leaq 0x118(%rsp), %rdi
callq 0x20e0
leaq 0x138(%rsp), %rdi
callq 0x20e0
testb $0x1, 0x117(%rsp)
jne 0x49b7
jmp 0x49c4
movq 0x98(%rsp), %rdi
callq 0x2170
jmp 0x49c6
testb $0x1, 0x116(%rsp)
jne 0x49d2
jmp 0x49df
movq 0x90(%rsp), %rdi
callq 0x2170
jmp 0x4f1d
movl $0x10, %edi
callq 0x2180
movq %rax, 0x80(%rsp)
movq 0x168(%rsp), %rdi
callq 0x62d0
movss %xmm0, 0x8c(%rsp)
jmp 0x4a0e
movq 0x170(%rsp), %rdi
callq 0x62d0
movss %xmm0, 0x7c(%rsp)
jmp 0x4a23
movq 0x80(%rsp), %rdi
movss 0x7c(%rsp), %xmm1
movss 0x8c(%rsp), %xmm0
addss %xmm1, %xmm0
callq 0x3cd0
jmp 0x4a45
movq 0x80(%rsp), %rsi
movq 0xb0(%rsp), %rdi
callq 0x4700
jmp 0x4a82
movq 0x80(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x160(%rsp)
movl %eax, 0x15c(%rsp)
callq 0x2170
jmp 0x4f1d
jmp 0x4ef7
movq 0xb0(%rsp), %rdi
callq 0x46e0
movq 0xb0(%rsp), %rdi
movq %rax, 0x108(%rsp)
callq 0x46e0
movq %rax, 0x100(%rsp)
movl $0x10, %edi
callq 0x2180
movq %rax, 0x70(%rsp)
movq 0x100(%rsp), %rdi
callq 0x62d0
movss %xmm0, 0x78(%rsp)
jmp 0x4ad5
movq 0x108(%rsp), %rdi
callq 0x62d0
movss %xmm0, 0x6c(%rsp)
jmp 0x4aea
movq 0x70(%rsp), %rdi
movss 0x6c(%rsp), %xmm1
movss 0x78(%rsp), %xmm0
subss %xmm1, %xmm0
callq 0x3cd0
jmp 0x4b06
movq 0x70(%rsp), %rsi
movq 0xb0(%rsp), %rdi
callq 0x4700
jmp 0x4ef7
movq 0x70(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x160(%rsp)
movl %eax, 0x15c(%rsp)
callq 0x2170
jmp 0x4f1d
movq 0xb0(%rsp), %rdi
callq 0x46e0
movq 0xb0(%rsp), %rdi
movq %rax, 0xf8(%rsp)
callq 0x46e0
movq %rax, 0xf0(%rsp)
movq 0xf0(%rsp), %rax
movzbl (%rax), %eax
cmpl $0x3, %eax
jne 0x4b9d
movq 0xf8(%rsp), %rax
movzbl (%rax), %eax
cmpl $0x3, %eax
jne 0x4b9d
leaq 0x253b(%rip), %rdi      # 0x70cc
movb $0x0, %al
callq 0x2040
jmp 0x4f15
movq 0xf0(%rsp), %rax
movzbl (%rax), %eax
cmpl $0x3, %eax
jne 0x4c4f
movl $0x10, %edi
callq 0x2180
movq %rax, 0x58(%rsp)
movq 0xf0(%rsp), %rax
movq 0x8(%rax), %rax
movq %rax, 0x60(%rsp)
movq 0xf8(%rsp), %rdi
callq 0x62d0
movss %xmm0, 0x68(%rsp)
jmp 0x4be6
movq 0x60(%rsp), %rdi
movss 0x68(%rsp), %xmm0
cvttss2si %xmm0, %rax
movl %eax, %esi
callq 0x4f30
movq %rax, 0x50(%rsp)
jmp 0x4c04
movq 0x50(%rsp), %rsi
movq 0x58(%rsp), %rdi
callq 0x3c80
jmp 0x4c15
movq 0x58(%rsp), %rsi
movq 0xb0(%rsp), %rdi
callq 0x4700
jmp 0x4d8f
movq 0x58(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x160(%rsp)
movl %eax, 0x15c(%rsp)
callq 0x2170
jmp 0x4f1d
movq 0xf8(%rsp), %rax
movzbl (%rax), %eax
cmpl $0x3, %eax
jne 0x4d01
movl $0x10, %edi
callq 0x2180
movq %rax, 0x38(%rsp)
movq 0xf8(%rsp), %rax
movq 0x8(%rax), %rax
movq %rax, 0x40(%rsp)
movq 0xf0(%rsp), %rdi
callq 0x62d0
movss %xmm0, 0x4c(%rsp)
jmp 0x4c98
movq 0x40(%rsp), %rdi
movss 0x4c(%rsp), %xmm0
cvttss2si %xmm0, %rax
movl %eax, %esi
callq 0x4f30
movq %rax, 0x30(%rsp)
jmp 0x4cb6
movq 0x30(%rsp), %rsi
movq 0x38(%rsp), %rdi
callq 0x3c80
jmp 0x4cc7
movq 0x38(%rsp), %rsi
movq 0xb0(%rsp), %rdi
callq 0x4700
jmp 0x4d8d
movq 0x38(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x160(%rsp)
movl %eax, 0x15c(%rsp)
callq 0x2170
jmp 0x4f1d
movl $0x10, %edi
callq 0x2180
movq %rax, 0x20(%rsp)
movq 0xf0(%rsp), %rdi
callq 0x62d0
movss %xmm0, 0x2c(%rsp)
jmp 0x4d25
movq 0xf8(%rsp), %rdi
callq 0x62d0
movss %xmm0, 0x1c(%rsp)
jmp 0x4d3a
movq 0x20(%rsp), %rdi
movss 0x1c(%rsp), %xmm1
movss 0x2c(%rsp), %xmm0
mulss %xmm1, %xmm0
callq 0x3cd0
jmp 0x4d56
movq 0x20(%rsp), %rsi
movq 0xb0(%rsp), %rdi
callq 0x4700
jmp 0x4d8d
movq 0x20(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x160(%rsp)
movl %eax, 0x15c(%rsp)
callq 0x2170
jmp 0x4f1d
jmp 0x4d8f
jmp 0x4d91
jmp 0x4ef7
movq 0xb0(%rsp), %rdi
callq 0x46e0
movq 0xb0(%rsp), %rdi
movq %rax, 0xe8(%rsp)
callq 0x46e0
movq %rax, 0xe0(%rsp)
movq 0xe8(%rsp), %rdi
callq 0x62d0
xorps %xmm1, %xmm1
ucomiss %xmm1, %xmm0
jne 0x4dea
jp 0x4dea
leaq 0x230a(%rip), %rdi      # 0x70e8
movb $0x0, %al
callq 0x2040
jmp 0x4f15
movl $0x10, %edi
callq 0x2180
movq %rax, 0x10(%rsp)
movq 0xe0(%rsp), %rdi
callq 0x62d0
movss %xmm0, 0x18(%rsp)
jmp 0x4e0e
movq 0xe8(%rsp), %rdi
callq 0x62d0
movss %xmm0, 0xc(%rsp)
jmp 0x4e23
movq 0x10(%rsp), %rdi
movss 0xc(%rsp), %xmm1
movss 0x18(%rsp), %xmm0
mulss %xmm1, %xmm0
callq 0x3cd0
jmp 0x4e3f
movq 0x10(%rsp), %rsi
movq 0xb0(%rsp), %rdi
callq 0x4700
jmp 0x4ef7
movq 0x10(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x160(%rsp)
movl %eax, 0x15c(%rsp)
callq 0x2170
jmp 0x4f1d
movq 0xb0(%rsp), %rdi
callq 0x46e0
movq %rax, 0xd8(%rsp)
movq 0xd8(%rsp), %rsi
leaq 0xb8(%rsp), %rdi
movq %rdi, (%rsp)
callq 0x6420
movq (%rsp), %rdi
callq 0x20a0
movq %rax, %rsi
leaq 0x2254(%rip), %rdi      # 0x710e
xorl %eax, %eax
callq 0x2040
jmp 0x4ec3
leaq 0xb8(%rsp), %rdi
callq 0x20e0
jmp 0x4ef7
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x160(%rsp)
movl %eax, 0x15c(%rsp)
leaq 0xb8(%rsp), %rdi
callq 0x20e0
jmp 0x4f1d
jmp 0x4f15
jmp 0x4ef9
movq 0xb0(%rsp), %rax
movl 0x810(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x810(%rax)
jmp 0x4759
addq $0x188, %rsp            # imm = 0x188
retq
movq 0x160(%rsp), %rdi
callq 0x2260
nopw (%rax,%rax)