#ifndef GOOSE_EIR_TERM_H
#define GOOSE_EIR_TERM_H

namespace goose::eir
{
    class Vector;
    using pvec = ptr< Vector >;

    enum class Delimiter
    {
        OpenParen,
        OpenBrace,
        OpenBracket,

        CloseParen,
        CloseBrace,
        CloseBracket
    };

    struct STerm;

    class Hole
    {
      public:
        enum class Behavior
        {
            Standard,
            Pack,
            Any
        };

        Hole() = default;

        Hole( StringId name, StringId kind = ""_sid, Behavior bhv = Behavior::Standard ) :
            m_name( name ),
            m_kind( kind ),
            m_bhv( bhv )
        {
        }

        const auto& name() const { return m_name; }

        const auto& kind() const { return m_kind; }

        auto behavior() const { return m_bhv; }

        bool operator<( const Hole& rhs ) const;
        bool operator==( const Hole& rhs ) const;

      private:
        StringId m_name;
        StringId m_kind;
        Behavior m_bhv = Behavior::Standard;
    };

    using Term = variant< uint64_t, LocationId, string, StringId, Delimiter, Hole, AnyTerm,
        VecOfLength, pvec,

        // Representation for ct_int, the compile time only integers
        // with "unlimited" precision
        BigInt,

        // Compile time representation for normal, fixed size integers
        APSInt,

        ptr< void >, void* >;

    extern bool operator==( const Term& lhs, const Term& rhs );
    extern bool operator!=( const Term& lhs, const Term& rhs );
    extern ostream& operator<<( ostream& out, const Term& t );

    // A term associated with a location id.
    // Used to represent tokens and tokens/values coming out of the resolver.
    using TermLoc = pair< eir::Term, LocationId >;
} // namespace goose::eir

#define TERM( x ) eir::Term( x )
#define TSTR( x ) TERM( string( x ) )
#define TSID( x ) TERM( #x##_sid )
#define HOLE( ... ) TERM( ( eir::Hole{ __VA_ARGS__ } ) )
#define ANYTERM( x ) TERM( eir::AnyTerm( #x##_sid ) )
#define VECOFLENGTH( x ) TERM( eir::VecOfLength( #x##_sid ) )
#define VEC( ... ) TERM( eir::Vector::Make( __VA_ARGS__ ) )
#define REPEAT( x ) eir::Repetition( x )

#endif
