// File: ConsoleTVs[P]VirtualMachine/sample/main.cpp
// Function: main
int main()
{
    auto virtual_machine = new VM::Instance();

    // We can manually add the opcodes using
    // the virtual_machine->add_op_code() function
    // or pass the whole code as a parameter
    auto program = new VM::Program();

    // Let's define the opcodes of our program

    // Multiply 10 by 10
    // SHould print this:
    // 100.000000
    program->add_op_code(VM::OP_CONSTANT);
    program->add_constant_code(new VM::Value(10));
    program->add_op_code(VM::OP_CONSTANT);
    program->add_constant_code(new VM::Value(10));
    program->add_op_code(VM::OP_MUL);
    program->add_op_code(VM::OP_PRINT);

    // Multiply a string by 2
    // SHould print this:
    // ABCABC
    program->add_op_code(VM::OP_CONSTANT);
    program->add_constant_code(new VM::Value(new std::string("ABC")));
    program->add_op_code(VM::OP_CONSTANT);
    program->add_constant_code(new VM::Value(2));
    program->add_op_code(VM::OP_MUL);
    program->add_op_code(VM::OP_PRINT);

    // Print a list constant (a bit messy I know)
    // Should print this:
    // [1, Hello, 0, 5.100000, [1, 2, 3]]
    program->add_op_code(VM::OP_CONSTANT);
    program->add_constant_code(new VM::Value(new std::vector<VM::Value *>({
        new VM::Value(1),
        new VM::Value(new std::string("Hello")),
        new VM::Value(false),
        new VM::Value((float) 5.10),
        new VM::Value(new std::vector<VM::Value *>({ new VM::Value(1), new VM::Value(2), new VM::Value(3), })),
    })));
    program->add_op_code(VM::OP_PRINT);

    // Add a string with another type
    // SHould print this:
    // ABC100
    program->add_op_code(VM::OP_CONSTANT);
    program->add_constant_code(new VM::Value(new std::string("ABC")));
    program->add_op_code(VM::OP_CONSTANT);
    program->add_constant_code(new VM::Value(100));
    program->add_op_code(VM::OP_ADD);
    program->add_op_code(VM::OP_PRINT);

    // Very important to add the OP_EXIT if we want our VM to exit when done
    program->add_op_code(VM::OP_EXIT);

    // Se the program to the virtual machine
    virtual_machine->program = program;

    // You can also debug the program defined in the screen to know what is happening
    printf("\nProgram defined:\n\n");
    program->debug();

    // Now we can run the virtual machine :D
    printf("\nStart the virtual machine...\n\n");
    virtual_machine->run();

    return 0;
}

// Assembly:
subq $0x1e8, %rsp            # imm = 0x1E8
movl $0x0, 0x1e4(%rsp)
movl $0x818, %edi            # imm = 0x818
callq 0x2180
movq %rax, %rdi
movq %rdi, %rax
movq %rax, 0x138(%rsp)
callq 0x3c10
jmp 0x3001
movq 0x138(%rsp), %rax
movq %rax, 0x1d8(%rsp)
movl $0x30, %edi
callq 0x2180
movq %rax, %rdi
movq %rdi, %rax
movq %rax, 0x130(%rsp)
callq 0x3c30
jmp 0x3030
movq 0x130(%rsp), %rax
movq %rax, 0x1c0(%rsp)
movq 0x1c0(%rsp), %rdi
xorl %esi, %esi
callq 0x52d0
movq 0x1c0(%rsp), %rax
movq %rax, 0x120(%rsp)
movl $0x10, %edi
callq 0x2180
movq %rax, %rdi
movq %rdi, %rax
movq %rax, 0x128(%rsp)
movl $0xa, %esi
callq 0x3c60
jmp 0x3083
movq 0x128(%rsp), %rsi
movq 0x120(%rsp), %rdi
callq 0x5300
movq 0x1c0(%rsp), %rdi
xorl %esi, %esi
callq 0x52d0
movq 0x1c0(%rsp), %rax
movq %rax, 0x110(%rsp)
movl $0x10, %edi
callq 0x2180
movq %rax, %rdi
movq %rdi, %rax
movq %rax, 0x118(%rsp)
movl $0xa, %esi
callq 0x3c60
jmp 0x30db
movq 0x118(%rsp), %rsi
movq 0x110(%rsp), %rdi
callq 0x5300
movq 0x1c0(%rsp), %rdi
movl $0x3, %esi
callq 0x52d0
movq 0x1c0(%rsp), %rdi
movl $0x5, %esi
callq 0x52d0
movq 0x1c0(%rsp), %rdi
xorl %esi, %esi
callq 0x52d0
movq 0x1c0(%rsp), %rax
movq %rax, 0xf8(%rsp)
movl $0x10, %edi
callq 0x2180
movq %rax, 0x100(%rsp)
movb $0x1, 0x1bd(%rsp)
movl $0x20, %edi
callq 0x2180
movq %rax, 0x108(%rsp)
jmp 0x3161
movb $0x1, 0x1be(%rsp)
leaq 0x1bf(%rsp), %rdi
movq %rdi, 0xf0(%rsp)
callq 0x2270
movq 0x108(%rsp), %rdi
movq 0xf0(%rsp), %rdx
leaq 0x3eac(%rip), %rsi      # 0x7041
callq 0x21f0
jmp 0x319c
movq 0x108(%rsp), %rsi
movq 0x100(%rsp), %rdi
movb $0x0, 0x1be(%rsp)
callq 0x3c80
jmp 0x31bb
movq 0x100(%rsp), %rsi
movq 0xf8(%rsp), %rdi
movb $0x0, 0x1bd(%rsp)
callq 0x5300
jmp 0x31da
leaq 0x1bf(%rsp), %rdi
callq 0x21a0
movq 0x1c0(%rsp), %rdi
xorl %esi, %esi
callq 0x52d0
movq 0x1c0(%rsp), %rax
movq %rax, 0xe0(%rsp)
movl $0x10, %edi
callq 0x2180
movq %rax, %rdi
movq %rdi, %rax
movq %rax, 0xe8(%rsp)
movl $0x2, %esi
callq 0x3c60
jmp 0x322a
movq 0xe8(%rsp), %rsi
movq 0xe0(%rsp), %rdi
callq 0x5300
movq 0x1c0(%rsp), %rdi
movl $0x3, %esi
callq 0x52d0
movq 0x1c0(%rsp), %rdi
movl $0x5, %esi
callq 0x52d0
movq 0x1c0(%rsp), %rdi
xorl %esi, %esi
callq 0x52d0
movq 0x1c0(%rsp), %rax
movq %rax, 0xc8(%rsp)
movl $0x10, %edi
callq 0x2180
movq %rax, 0xd0(%rsp)
movb $0x1, 0x14a(%rsp)
movl $0x18, %edi
callq 0x2180
movq %rax, 0xd8(%rsp)
jmp 0x32b0
movb $0x1, 0x14b(%rsp)
movl $0x10, %edi
callq 0x2180
movq %rax, 0xc0(%rsp)
jmp 0x32cc
movq 0xc0(%rsp), %rdi
movl $0x1, %esi
callq 0x3c60
jmp 0x32e0
movq 0xc0(%rsp), %rax
movq %rax, 0x180(%rsp)
leaq 0x188(%rsp), %rax
movq %rax, 0xb0(%rsp)
movl $0x10, %edi
callq 0x2180
movq %rax, 0xb8(%rsp)
jmp 0x3314
movb $0x1, 0x17d(%rsp)
movl $0x20, %edi
callq 0x2180
movq %rax, 0xa8(%rsp)
jmp 0x3330
movb $0x1, 0x17e(%rsp)
leaq 0x17f(%rsp), %rdi
movq %rdi, 0xa0(%rsp)
callq 0x2270
movq 0xa8(%rsp), %rdi
movq 0xa0(%rsp), %rdx
leaq 0x3ce1(%rip), %rsi      # 0x7045
callq 0x21f0
jmp 0x336b
movq 0xa8(%rsp), %rsi
movq 0xb8(%rsp), %rdi
movb $0x0, 0x17e(%rsp)
callq 0x3c80
jmp 0x338a
movq 0xb0(%rsp), %rax
movq 0xb8(%rsp), %rcx
movb $0x0, 0x17d(%rsp)
movq %rcx, (%rax)
leaq 0x190(%rsp), %rax
movq %rax, 0x90(%rsp)
movl $0x10, %edi
callq 0x2180
movq %rax, 0x98(%rsp)
jmp 0x33c9
movq 0x98(%rsp), %rdi
xorl %esi, %esi
callq 0x3ca0
jmp 0x33da
movq 0x90(%rsp), %rax
movq 0x98(%rsp), %rcx
movq %rcx, (%rax)
leaq 0x198(%rsp), %rax
movq %rax, 0x80(%rsp)
movl $0x10, %edi
callq 0x2180
movq %rax, 0x88(%rsp)
jmp 0x3411
movq 0x88(%rsp), %rdi
movss 0x3be3(%rip), %xmm0     # 0x7004
callq 0x3cd0
jmp 0x3428
movq 0x80(%rsp), %rax
movq 0x88(%rsp), %rcx
movq %rcx, (%rax)
leaq 0x1a0(%rsp), %rax
movq %rax, 0x70(%rsp)
movl $0x10, %edi
callq 0x2180
movq %rax, 0x78(%rsp)
jmp 0x3459
movb $0x1, 0x14d(%rsp)
movl $0x18, %edi
callq 0x2180
movq %rax, 0x68(%rsp)
jmp 0x3472
movb $0x1, 0x14e(%rsp)
movl $0x10, %edi
callq 0x2180
movq %rax, 0x60(%rsp)
jmp 0x348b
movq 0x60(%rsp), %rdi
movl $0x1, %esi
callq 0x3c60
jmp 0x349c
movq 0x60(%rsp), %rax
movq %rax, 0x150(%rsp)
leaq 0x158(%rsp), %rax
movq %rax, 0x50(%rsp)
movl $0x10, %edi
callq 0x2180
movq %rax, 0x58(%rsp)
jmp 0x34c7
movq 0x58(%rsp), %rdi
movl $0x2, %esi
callq 0x3c60
jmp 0x34d8
movq 0x50(%rsp), %rax
movq 0x58(%rsp), %rcx
movq %rcx, (%rax)
leaq 0x160(%rsp), %rax
movq %rax, 0x40(%rsp)
movl $0x10, %edi
callq 0x2180
movq %rax, 0x48(%rsp)
jmp 0x3503
movq 0x48(%rsp), %rdi
movl $0x3, %esi
callq 0x3c60
jmp 0x3514
movq 0x40(%rsp), %rax
movq 0x48(%rsp), %rcx
movq %rcx, (%rax)
leaq 0x150(%rsp), %rax
movq %rax, 0x168(%rsp)
movq $0x3, 0x170(%rsp)
leaq 0x14f(%rsp), %rdi
movq %rdi, 0x38(%rsp)
callq 0x3cf0
movq 0x68(%rsp), %rdi
movq 0x38(%rsp), %rcx
movq 0x168(%rsp), %rsi
movq 0x170(%rsp), %rdx
callq 0x3d00
jmp 0x3570
movq 0x68(%rsp), %rsi
movq 0x78(%rsp), %rdi
movb $0x0, 0x14e(%rsp)
callq 0x3d90
jmp 0x3589
movq 0x70(%rsp), %rax
movq 0x78(%rsp), %rcx
movb $0x0, 0x14d(%rsp)
movq %rcx, (%rax)
leaq 0x180(%rsp), %rax
movq %rax, 0x1a8(%rsp)
movq $0x5, 0x1b0(%rsp)
leaq 0x14c(%rsp), %rdi
movq %rdi, 0x30(%rsp)
callq 0x3cf0
movq 0xd8(%rsp), %rdi
movq 0x30(%rsp), %rcx
movq 0x1a8(%rsp), %rsi
movq 0x1b0(%rsp), %rdx
callq 0x3d00
jmp 0x35f0
movq 0xd8(%rsp), %rsi
movq 0xd0(%rsp), %rdi
movb $0x0, 0x14b(%rsp)
callq 0x3d90
jmp 0x360f
movq 0xd0(%rsp), %rsi
movq 0xc8(%rsp), %rdi
movb $0x0, 0x14a(%rsp)
callq 0x5300
jmp 0x362e
leaq 0x14c(%rsp), %rdi
callq 0x3db0
leaq 0x14f(%rsp), %rdi
callq 0x3db0
leaq 0x17f(%rsp), %rdi
callq 0x21a0
movq 0x1c0(%rsp), %rdi
movl $0x5, %esi
callq 0x52d0
movq 0x1c0(%rsp), %rdi
xorl %esi, %esi
callq 0x52d0
movq 0x1c0(%rsp), %rax
movq %rax, 0x18(%rsp)
movl $0x10, %edi
callq 0x2180
movq %rax, 0x20(%rsp)
movb $0x1, 0x147(%rsp)
movl $0x20, %edi
callq 0x2180
movq %rax, 0x28(%rsp)
jmp 0x36ab
movb $0x1, 0x148(%rsp)
leaq 0x149(%rsp), %rdi
movq %rdi, 0x10(%rsp)
callq 0x2270
movq 0x28(%rsp), %rdi
movq 0x10(%rsp), %rdx
leaq 0x396b(%rip), %rsi      # 0x7041
callq 0x21f0
jmp 0x36dd
movq 0x28(%rsp), %rsi
movq 0x20(%rsp), %rdi
movb $0x0, 0x148(%rsp)
callq 0x3c80
jmp 0x36f6
movq 0x20(%rsp), %rsi
movq 0x18(%rsp), %rdi
movb $0x0, 0x147(%rsp)
callq 0x5300
jmp 0x370f
leaq 0x149(%rsp), %rdi
callq 0x21a0
movq 0x1c0(%rsp), %rdi
xorl %esi, %esi
callq 0x52d0
movq 0x1c0(%rsp), %rax
movq %rax, (%rsp)
movl $0x10, %edi
callq 0x2180
movq %rax, %rdi
movq %rdi, %rax
movq %rax, 0x8(%rsp)
movl $0x64, %esi
callq 0x3c60
jmp 0x3758
movq 0x8(%rsp), %rsi
movq (%rsp), %rdi
callq 0x5300
movq 0x1c0(%rsp), %rdi
movl $0x1, %esi
callq 0x52d0
movq 0x1c0(%rsp), %rdi
movl $0x5, %esi
callq 0x52d0
movq 0x1c0(%rsp), %rdi
movl $0x6, %esi
callq 0x52d0
movq 0x1c0(%rsp), %rcx
movq 0x1d8(%rsp), %rax
movq %rcx, 0x808(%rax)
leaq 0x3891(%rip), %rdi      # 0x704b
movb $0x0, %al
callq 0x2040
movq 0x1c0(%rsp), %rdi
callq 0x5380
leaq 0x388a(%rip), %rdi      # 0x705f
movb $0x0, %al
callq 0x2040
movq 0x1d8(%rsp), %rdi
callq 0x4730
xorl %eax, %eax
addq $0x1e8, %rsp            # imm = 0x1E8
retq
movq 0x138(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1d0(%rsp)
movl %eax, 0x1cc(%rsp)
callq 0x2170
jmp 0x3c01
movq 0x130(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1d0(%rsp)
movl %eax, 0x1cc(%rsp)
callq 0x2170
jmp 0x3c01
movq 0x128(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1d0(%rsp)
movl %eax, 0x1cc(%rsp)
callq 0x2170
jmp 0x3c01
movq 0x118(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1d0(%rsp)
movl %eax, 0x1cc(%rsp)
callq 0x2170
jmp 0x3c01
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1d0(%rsp)
movl %eax, 0x1cc(%rsp)
jmp 0x38dd
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1d0(%rsp)
movl %eax, 0x1cc(%rsp)
leaq 0x1bf(%rsp), %rdi
callq 0x21a0
testb $0x1, 0x1be(%rsp)
jne 0x38ce
jmp 0x38db
movq 0x108(%rsp), %rdi
callq 0x2170
jmp 0x38dd
testb $0x1, 0x1bd(%rsp)
jne 0x38e9
jmp 0x38f6
movq 0x100(%rsp), %rdi
callq 0x2170
jmp 0x3c01
movq 0xe8(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1d0(%rsp)
movl %eax, 0x1cc(%rsp)
callq 0x2170
jmp 0x3c01
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1d0(%rsp)
movl %eax, 0x1cc(%rsp)
jmp 0x3b5e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1d0(%rsp)
movl %eax, 0x1cc(%rsp)
jmp 0x3b43
movq 0xc0(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1d0(%rsp)
movl %eax, 0x1cc(%rsp)
callq 0x2170
jmp 0x3b43
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1d0(%rsp)
movl %eax, 0x1cc(%rsp)
jmp 0x3b28
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1d0(%rsp)
movl %eax, 0x1cc(%rsp)
jmp 0x3b00
movq 0x98(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1d0(%rsp)
movl %eax, 0x1cc(%rsp)
callq 0x2170
jmp 0x3b00
movq 0x88(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1d0(%rsp)
movl %eax, 0x1cc(%rsp)
callq 0x2170
jmp 0x3b00
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1d0(%rsp)
movl %eax, 0x1cc(%rsp)
jmp 0x3ae8
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1d0(%rsp)
movl %eax, 0x1cc(%rsp)
jmp 0x3ad0
movq 0x60(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1d0(%rsp)
movl %eax, 0x1cc(%rsp)
callq 0x2170
jmp 0x3ad0
movq 0x58(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1d0(%rsp)
movl %eax, 0x1cc(%rsp)
callq 0x2170
jmp 0x3ad0
movq 0x48(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1d0(%rsp)
movl %eax, 0x1cc(%rsp)
callq 0x2170
jmp 0x3ad0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1d0(%rsp)
movl %eax, 0x1cc(%rsp)
jmp 0x3ac3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1d0(%rsp)
movl %eax, 0x1cc(%rsp)
leaq 0x14c(%rsp), %rdi
callq 0x3db0
leaq 0x14f(%rsp), %rdi
callq 0x3db0
testb $0x1, 0x14e(%rsp)
jne 0x3adc
jmp 0x3ae6
movq 0x68(%rsp), %rdi
callq 0x2170
jmp 0x3ae8
testb $0x1, 0x14d(%rsp)
jne 0x3af4
jmp 0x3afe
movq 0x78(%rsp), %rdi
callq 0x2170
jmp 0x3b00
leaq 0x17f(%rsp), %rdi
callq 0x21a0
testb $0x1, 0x17e(%rsp)
jne 0x3b19
jmp 0x3b26
movq 0xa8(%rsp), %rdi
callq 0x2170
jmp 0x3b28
testb $0x1, 0x17d(%rsp)
jne 0x3b34
jmp 0x3b41
movq 0xb8(%rsp), %rdi
callq 0x2170
jmp 0x3b43
testb $0x1, 0x14b(%rsp)
jne 0x3b4f
jmp 0x3b5c
movq 0xd8(%rsp), %rdi
callq 0x2170
jmp 0x3b5e
testb $0x1, 0x14a(%rsp)
jne 0x3b6a
jmp 0x3b77
movq 0xd0(%rsp), %rdi
callq 0x2170
jmp 0x3c01
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1d0(%rsp)
movl %eax, 0x1cc(%rsp)
jmp 0x3bcb
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1d0(%rsp)
movl %eax, 0x1cc(%rsp)
leaq 0x149(%rsp), %rdi
callq 0x21a0
testb $0x1, 0x148(%rsp)
jne 0x3bbf
jmp 0x3bc9
movq 0x28(%rsp), %rdi
callq 0x2170
jmp 0x3bcb
testb $0x1, 0x147(%rsp)
jne 0x3bd7
jmp 0x3be1
movq 0x20(%rsp), %rdi
callq 0x2170
jmp 0x3c01
movq 0x8(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1d0(%rsp)
movl %eax, 0x1cc(%rsp)
callq 0x2170
movq 0x1d0(%rsp), %rdi
callq 0x2260
nop