#pragma once

#include <ostream>

namespace gasp::torricelly
{

enum class torricelly_inst_code : unsigned short
{
   NOOP = 0x0001,
   DUP,

   POP_BYTE,
   POP_SHORT,
   POP_INTEGER,
   POP_LONG,
   POP_BOOLEAN,
   POP_CHAR,
   POP_FLOAT,
   POP_DOUBLE,

   LOAD_BYTE,
   LOAD_SHORT,
   LOAD_INTEGER,
   LOAD_LONG,
   LOAD_BOOLEAN,
   LOAD_CHAR,
   LOAD_FLOAT,
   LOAD_DOUBLE,
   LOAD_ARRAY,
   LOAD_ARRAY_BYTE,
   LOAD_ARRAY_SHORT,
   LOAD_ARRAY_INTEGER,
   LOAD_ARRAY_LONG,
   LOAD_ARRAY_BOOLEAN,
   LOAD_ARRAY_CHAR,
   LOAD_ARRAY_FLOAT,
   LOAD_ARRAY_DOUBLE,

   STORE_BYTE,
   STORE_SHORT,
   STORE_INTEGER,
   STORE_LONG,
   STORE_BOOLEAN,
   STORE_CHAR,
   STORE_FLOAT,
   STORE_DOUBLE,
   STORE_ARRAY,
   STORE_ARRAY_BYTE,
   STORE_ARRAY_SHORT,
   STORE_ARRAY_INTEGER,
   STORE_ARRAY_LONG,
   STORE_ARRAY_BOOLEAN,
   STORE_ARRAY_CHAR,
   STORE_ARRAY_FLOAT,
   STORE_ARRAY_DOUBLE,

   ADD_BYTE,
   ADD_SHORT,
   ADD_INTEGER,
   ADD_LONG,
   ADD_FLOAT,
   ADD_DOUBLE,

   SUBTRACT_BYTE,
   SUBTRACT_SHORT,
   SUBTRACT_INTEGER,
   SUBTRACT_LONG,
   SUBTRACT_FLOAT,
   SUBTRACT_DOUBLE,

   MULTIPLY_BYTE,
   MULTIPLY_SHORT,
   MULTIPLY_INTEGER,
   MULTIPLY_LONG,
   MULTIPLY_FLOAT,
   MULTIPLY_DOUBLE,

   DIVIDE_BYTE,
   DIVIDE_SHORT,
   DIVIDE_INTEGER,
   DIVIDE_LONG,
   DIVIDE_FLOAT,
   DIVIDE_DOUBLE,

   REMINDER_BYTE,
   REMINDER_SHORT,
   REMINDER_INTEGER,
   REMINDER_LONG,

   NEGATE_BYTE,
   NEGATE_SHORT,
   NEGATE_INTEGER,
   NEGATE_LONG,
   NEGATE_FLOAT,
   NEGATE_DOUBLE,

   CMP_BYTE,
   CMP_SHORT,
   CMP_INTEGER,
   CMP_LONG,
   CMP_BOOLEAN,
   CMP_CHAR,
   CMP_FLOAT,
   CMP_DOUBLE,

   JUMP,
   JUMP_EQ_ZERO,
   JUMP_LT_ZERO,
   JUMP_LTE_ZERO,
   JUMP_GT_ZERO,
   JUMP_GTE_ZERO,
   JUMP_NOT_ZERO,

   CAST_BYTE_SHORT,
   CAST_BYTE_INT,
   CAST_BYTE_LONG,
   CAST_BYTE_FLOAT,
   CAST_BYTE_DOUBLE,
   CAST_BYTE_BOOLEAN,
   CAST_BYTE_CHAR,
   CAST_SHORT_BYTE,
   CAST_SHORT_INT,
   CAST_SHORT_LONG,
   CAST_SHORT_FLOAT,
   CAST_SHORT_DOUBLE,
   CAST_SHORT_BOOLEAN,
   CAST_SHORT_CHAR,
   CAST_INT_BYTE,
   CAST_INT_SHORT,
   CAST_INT_LONG,
   CAST_INT_FLOAT,
   CAST_INT_DOUBLE,
   CAST_INT_BOOLEAN,
   CAST_INT_CHAR,
   CAST_LONG_BYTE,
   CAST_LONG_SHORT,
   CAST_LONG_INT,
   CAST_LONG_FLOAT,
   CAST_LONG_DOUBLE,
   CAST_LONG_BOOLEAN,
   CAST_LONG_CHAR,
   CAST_BOOLEAN_BYTE,
   CAST_BOOLEAN_SHORT,
   CAST_BOOLEAN_INT,
   CAST_CHAR_BYTE,
   CAST_CHAR_SHORT,
   CAST_CHAR_INT,   
   CAST_FLOAT_BYTE,
   CAST_FLOAT_SHORT,
   CAST_FLOAT_INT,
   CAST_FLOAT_LONG,
   CAST_FLOAT_DOUBLE,
   CAST_DOUBLE_BYTE,
   CAST_DOUBLE_SHORT,
   CAST_DOUBLE_INT,
   CAST_DOUBLE_LONG,
   CAST_DOUBLE_FLOAT,

   NOT,
   AND,
   OR,

   STATIC_INVOKE,
   NATIVE_INVOKE,
   VIRTUAL_INVOKE,
   DYNAMIC_INVOKE,
   RET,

   HALT,

   ALLOCATE_BYTE_ARRAY,
   ALLOCATE_SHORT_ARRAY,
   ALLOCATE_INT_ARRAY,
   ALLOCATE_LONG_ARRAY,
   ALLOCATE_CHAR_ARRAY,
   ALLOCATE_FLOAT_ARRAY,
   ALLOCATE_DOUBLE_ARRAY,
   ALLOCATE_BOOLEAN_ARRAY,
   FREE_ARRAY

};

class torricelly_inst_code_helper
{
public:
   static bool accept_parameter(torricelly_inst_code code);
   static bool accept_reference(torricelly_inst_code code);
   static bool accept_label(torricelly_inst_code code);
};

const char *to_string(torricelly_inst_code code);
std::ostream &operator<<(std::ostream &os, torricelly_inst_code code);

} // namespace gasp::torricelly