use num_derive::{FromPrimitive, ToPrimitive};

#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, ToPrimitive)]
pub enum Op {
    Noop,
    Nothing,
    Nil,
    True,
    False,
    Constant,
    Jump,
    JumpIfFalse,
    JumpIfTrue,
    Pop,
    PopN,
    PushBinding,
    PushGlobal,
    Store,
    StoreN,
    Stash,
    Load,
    LoadN,
    ResetMatch,
    UnconditionalMatch,
    MatchNil,
    MatchTrue,
    MatchFalse,
    MatchConstant,
    MatchString,
    PushStringMatches,
    MatchType,
    MatchTuple,
    MatchSplattedTuple,
    PushTuple,
    LoadTuple,
    LoadSplattedTuple,
    MatchList,
    MatchSplattedList,
    LoadList,
    LoadSplattedList,
    PushList,
    AppendList,
    ConcatList,
    PushDict,
    AppendDict,
    ConcatDict,
    LoadDictValue,
    MatchDict,
    MatchSplattedDict,
    DropDictEntry,
    PushBox,
    GetKey,
    PanicWhenFallthrough,
    JumpIfNoMatch,
    JumpIfMatch,
    PanicNoMatch,
    PanicNoLetMatch,
    PanicNoFnMatch,
    TypeOf,
    JumpBack,
    JumpIfZero,
    Duplicate,
    Decrement,
    ToInt,
    MatchDepth,
    Panic,
    EmptyString,
    ConcatStrings,
    Stringify,

    Call,
    TailCall,
    Return,
    Partial,

    Eq,
    Add,
    Sub,
    Mult,
    Div,
    Unbox,
    BoxStore,
    Assert,
    Get,
    At,
    // Inc,
    // Dec,
    // Gt,
    // Gte,
    // Lt,
    // Lte,
    // Mod,
    // First,
    // Rest
    // Sqrt,
    // Append,
    Not,
    Print,
    SetUpvalue,
    GetUpvalue,

    Msg,

    LoadMessage,
    NextMessage,
    MatchMessage,
    ClearMessage,
    SendMethod,

    LoadScrutinee,
}

impl std::fmt::Display for Op {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        use Op::*;
        let rep = match self {
            Msg => "msg",
            Noop => "noop",
            Nothing => "nothing",
            Nil => "nil",
            True => "true",
            False => "false",
            Constant => "constant",
            Jump => "jump",
            JumpIfFalse => "jump_if_false",
            JumpIfTrue => "jump_if_true",
            Pop => "pop",
            PopN => "pop_n",
            PushBinding => "push_binding",
            PushGlobal => "push_global",
            Store => "store",
            StoreN => "store_n",
            Stash => "stash",
            Load => "load",
            LoadN => "load_n",
            UnconditionalMatch => "match",
            MatchNil => "match_nil",
            MatchTrue => "match_true",
            MatchFalse => "match_false",
            ResetMatch => "reset_match",
            MatchConstant => "match_constant",
            MatchString => "match_string",
            PushStringMatches => "push_string_matches",
            MatchType => "match_type",
            MatchTuple => "match_tuple",
            MatchSplattedTuple => "match_splatted_tuple",
            PushTuple => "push_tuple",
            LoadTuple => "load_tuple",
            LoadSplattedTuple => "load_splatted_tuple",
            MatchList => "match_list",
            MatchSplattedList => "match_splatted_list",
            LoadList => "load_list",
            LoadSplattedList => "load_splatted_list",
            PushList => "push_list",
            AppendList => "append_list",
            ConcatList => "concat_list",
            PushDict => "push_dict",
            AppendDict => "append_dict",
            ConcatDict => "concat_dict",
            LoadDictValue => "load_dict_value",
            MatchDict => "match_dict",
            MatchSplattedDict => "match_splatted_dict",
            DropDictEntry => "drop_dict_entry",
            PushBox => "push_box",
            GetKey => "get_key",
            PanicWhenFallthrough => "panic_no_when",
            JumpIfNoMatch => "jump_if_no_match",
            JumpIfMatch => "jump_if_match",
            PanicNoMatch => "panic_no_match",
            PanicNoFnMatch => "panic_no_fn_match",
            PanicNoLetMatch => "panic_no_let_match",
            TypeOf => "type_of",
            JumpBack => "jump_back",
            JumpIfZero => "jump_if_zero",
            Decrement => "decrement",
            ToInt => "truncate",
            Duplicate => "duplicate",
            MatchDepth => "match_depth",
            Panic => "panic",
            EmptyString => "empty_string",
            ConcatStrings => "concat_strings",
            Stringify => "stringify",
            Print => "print",

            Eq => "eq",
            Add => "add",
            Sub => "sub",
            Mult => "mult",
            Div => "div",
            Unbox => "unbox",
            BoxStore => "box_store",
            Assert => "assert",
            Get => "get",
            At => "at",

            Not => "not",

            Call => "call",
            Return => "return",
            Partial => "partial",
            TailCall => "tail_call",

            SetUpvalue => "set_upvalue",
            GetUpvalue => "get_upvalue",

            LoadMessage => "load_message",
            NextMessage => "next_message",
            MatchMessage => "match_message",
            ClearMessage => "clear_message",
            SendMethod => "send_method",

            LoadScrutinee => "load_scrutinee",
        };
        write!(f, "{rep}")
    }
}
