#ifndef GOOSE_LLR_INSTRUCTION_H
#define GOOSE_LLR_INSTRUCTION_H

namespace goose::llr
{
    class CFG;

    class Instruction
    {
        public:
            Instruction() {}

            Instruction( Call&& c ) :
                m_content( move( c ) )
            {}

            Instruction( ptr< CFG >&& ic ) :
                m_content( move( ic ) )
            {}

            Instruction( CreateTemporary&& ct ) :
                m_content( move( ct ) )
            {}

            Instruction( GetTemporary&& gt ) :
                m_content( move( gt ) )
            {}

            Instruction( AllocVar&& av ) :
                m_content( move( av ) )
            {}

            Instruction( GetVar&& gv ) :
                m_content( move( gv ) )
            {}

            Instruction( SetVar&& gv ) :
                m_content( move( gv ) )
            {}

            Instruction( Phi&& p ) :
                m_content( move( p ) )
            {}

            Instruction( LoadConstStr&& lcs ) :
                m_content( move( lcs ) )
            {}

            Instruction( Not&& x ) :
                m_content( move( x ) )
            {}

            Instruction( And&& x ) :
                m_content( move( x ) )
            {}

            Instruction( Or&& x ) :
                m_content( move( x ) )
            {}

            Instruction( Xor&& x ) :
                m_content( move( x ) )
            {}

            Instruction( Shl&& x ) :
                m_content( move( x ) )
            {}

            Instruction( LShr&& x ) :
                m_content( move( x ) )
            {}

            Instruction( AShr&& x ) :
                m_content( move( x ) )
            {}

            Instruction( Add&& x ) :
                m_content( move( x ) )
            {}

            Instruction( Sub&& x ) :
                m_content( move( x ) )
            {}

            Instruction( Mul&& x ) :
                m_content( move( x ) )
            {}

            Instruction( UDiv&& x ) :
                m_content( move( x ) )
            {}

            Instruction( SDiv&& x ) :
                m_content( move( x ) )
            {}

            Instruction( URem&& x ) :
                m_content( move( x ) )
            {}

            Instruction( SRem&& x ) :
                m_content( move( x ) )
            {}

            Instruction( Eq&& x ) :
                m_content( move( x ) )
            {}

            Instruction( Neq&& x ) :
                m_content( move( x ) )
            {}

            Instruction( UGT&& x ) :
                m_content( move( x ) )
            {}

            Instruction( UGE&& x ) :
                m_content( move( x ) )
            {}

            Instruction( ULT&& x ) :
                m_content( move( x ) )
            {}

            Instruction( ULE&& x ) :
                m_content( move( x ) )
            {}

            Instruction( SGT&& x ) :
                m_content( move( x ) )
            {}

            Instruction( SGE&& x ) :
                m_content( move( x ) )
            {}

            Instruction( SLT&& x ) :
                m_content( move( x ) )
            {}

            Instruction( SLE&& x ) :
                m_content( move( x ) )
            {}

            Instruction( Assert&& x ) :
                m_content( move( x ) )
            {}

            Instruction( Placeholder&& x ) :
                m_content( move( x ) )
            {}

            using Content = variant
            <
                ptr< CFG >, // CFG inlining
                Call,
                CreateTemporary,
                GetTemporary,
                AllocVar,
                GetVar,
                SetVar,
                Phi,
                LoadConstStr,

                Not,
                And,
                Or,
                Xor,
                Shl,
                LShr,
                AShr,

                Add,
                Sub,
                Mul,
                UDiv,
                SDiv,
                URem,
                SRem,

                Eq,
                Neq,
                UGT,
                UGE,
                ULT,
                ULE,
                SGT,
                SGE,
                SLT,
                SLE,

                Assert,
                Placeholder
            >;

            const auto& content() const { return m_content; }

            bool canBeExecuted() const;
            bool canBeEagerlyEvaluated() const;

        private:
            Content m_content;
    };
}

#endif
