
class ResolvedOperator;

/** Interface for expressions representing resolved operators. */
class Concept : public hilti::util::type_erasure::ConceptBase {
public:
    Concept() = default;
    Concept(const Concept&) = default;
    Concept(Concept&&) = default;
    virtual ~Concept() = default;
    /** Returns the operator expression that the expression has been resolved to.  */
    virtual Operator operator_() const = 0;
    /** Returns the type of the operator expressions's result. */
    virtual const hilti::Type& result() const = 0;
    /** Returns the operator expression's operands. */
    virtual hilti::node::Range<Expression> operands() const = 0;
    /**
* Returns the operator expression's 1st operand.
* @exception `std::out_of_range`` if the expression doesn't have that operand
*/
    virtual const Expression& op0() const = 0;
    /**
* Returns the operator expression's 2nd operand.
* @exception `std::out_of_range`` if the expression doesn't have that operand
*/
    virtual const Expression& op1() const = 0;
    /**
* Returns the operator expression's 3rd operand
* @exception `std::out_of_range`` if the expression doesn't have that operand
*/
    virtual const Expression& op2() const = 0;
    /** Returns true if the operator expression has at least one operand. */
    virtual bool hasOp0()  = 0;
    /** Returns true if the operator expression has at least two operands. */
    virtual bool hasOp1()  = 0;
    /** Returns true if the operator expression has at least three operands. */
    virtual bool hasOp2()  = 0;
    /** Sets the operator expressions 1st operand. */
    virtual void setOp0(Expression e)  = 0;
    /** Sets the operator expressions 2nd operand. */
    virtual void setOp1(Expression e)  = 0;
    /** Sets the operator expressions 3rd operand. */
    virtual void setOp2(Expression e)  = 0;
    /** Implements `Expression` interface. */
    virtual bool isLhs() const = 0;
    /** Implements `Expression` interface. */
    virtual bool isTemporary() const = 0;
    /** Implements the `Expression` interface. */
    virtual const hilti::Type& type() const = 0;
    /** Implements the `Expression` interface. */
    virtual bool isEqual(const Expression& other) const = 0;
    /** Implements the `Expression` interface. */
    virtual bool isConstant() const = 0;
    /** Implements the `Node` interface. */
    virtual hilti::node::Properties properties() const = 0;
    /** Implements the `Node` interface. */
    virtual const std::vector<hilti::Node>& children() const = 0;
    /** Implements the `Node` interface. */
    virtual std::vector<hilti::Node>& children()  = 0;
    /** Implements the `Node` interface. */
    virtual const Meta& meta() const = 0;
    /** Implements the `Node` interface. */
    virtual void setMeta(Meta m)  = 0;
    /** Implements the `Node` interface. */
    virtual bool pruneWalk() const = 0;
    Concept& operator=(const Concept&) = default;
    Concept& operator=(Concept&&) = default;
    virtual ResolvedOperator _clone() const = 0;
    virtual hilti::IntrusivePtr<Concept> _clone_ptr() const = 0;
private:
    
};

template<typename T>
using ModelBase = hilti::util::type_erasure::ModelBase<T, Concept>;

template<class T>
class Model : public ModelBase<T> {
public:
    using ModelBase<T>::ModelBase;
    using ModelBase<T>::data;

    Operator operator_() const final;
    const hilti::Type& result() const final;
    hilti::node::Range<Expression> operands() const final;
    const Expression& op0() const final;
    const Expression& op1() const final;
    const Expression& op2() const final;
    bool hasOp0()  final;
    bool hasOp1()  final;
    bool hasOp2()  final;
    void setOp0(Expression e)  final;
    void setOp1(Expression e)  final;
    void setOp2(Expression e)  final;
    bool isLhs() const final;
    bool isTemporary() const final;
    const hilti::Type& type() const final;
    bool isEqual(const Expression& other) const final;
    bool isConstant() const final;
    hilti::node::Properties properties() const final;
    const std::vector<hilti::Node>& children() const final;
    std::vector<hilti::Node>& children()  final;
    const Meta& meta() const final;
    void setMeta(Meta m)  final;
    bool pruneWalk() const final;
    ResolvedOperator _clone() const final;
    hilti::IntrusivePtr<Concept> _clone_ptr() const final;
};

using ErasedBase = hilti::util::type_erasure::ErasedBase<trait::isResolvedOperator, Concept, Model>;

class ResolvedOperator : public ErasedBase, public trait::isExpression {
public:
    using ErasedBase::ErasedBase;

    ResolvedOperator() noexcept = default;
    ResolvedOperator(ResolvedOperator&&) noexcept = default;
    ResolvedOperator& operator=(ResolvedOperator&&) = default;
    ~ResolvedOperator() override = default;
    ResolvedOperator(const ResolvedOperator& other) = default;
    ResolvedOperator& operator=(const ResolvedOperator& other) = default;

    Operator operator_() const;
    const hilti::Type& result() const;
    hilti::node::Range<Expression> operands() const;
    const Expression& op0() const;
    const Expression& op1() const;
    const Expression& op2() const;
    bool hasOp0() ;
    bool hasOp1() ;
    bool hasOp2() ;
    void setOp0(Expression e) ;
    void setOp1(Expression e) ;
    void setOp2(Expression e) ;
    bool isLhs() const;
    bool isTemporary() const;
    const hilti::Type& type() const;
    bool isEqual(const Expression& other) const;
    bool isConstant() const;
    hilti::node::Properties properties() const;
    const std::vector<hilti::Node>& children() const;
    std::vector<hilti::Node>& children() ;
    const Meta& meta() const;
    void setMeta(Meta m) ;
    bool pruneWalk() const;
    ResolvedOperator _clone() const;

    hilti::IntrusivePtr<Concept> _clone_ptr() const;

protected:
    
};

template<typename T>
Operator Model<T>::operator_() const { return data().operator_(); }

template<typename T>
const hilti::Type& Model<T>::result() const { return data().result(); }

template<typename T>
hilti::node::Range<Expression> Model<T>::operands() const { return data().operands(); }

template<typename T>
const Expression& Model<T>::op0() const { return data().op0(); }

template<typename T>
const Expression& Model<T>::op1() const { return data().op1(); }

template<typename T>
const Expression& Model<T>::op2() const { return data().op2(); }

template<typename T>
bool Model<T>::hasOp0()  { return data().hasOp0(); }

template<typename T>
bool Model<T>::hasOp1()  { return data().hasOp1(); }

template<typename T>
bool Model<T>::hasOp2()  { return data().hasOp2(); }

template<typename T>
void Model<T>::setOp0(Expression e)  { return data().setOp0(e); }

template<typename T>
void Model<T>::setOp1(Expression e)  { return data().setOp1(e); }

template<typename T>
void Model<T>::setOp2(Expression e)  { return data().setOp2(e); }

template<typename T>
bool Model<T>::isLhs() const { return data().isLhs(); }

template<typename T>
bool Model<T>::isTemporary() const { return data().isTemporary(); }

template<typename T>
const hilti::Type& Model<T>::type() const { return data().type(); }

template<typename T>
bool Model<T>::isEqual(const Expression& other) const { return data().isEqual(other); }

template<typename T>
bool Model<T>::isConstant() const { return data().isConstant(); }

template<typename T>
hilti::node::Properties Model<T>::properties() const { return data().properties(); }

template<typename T>
const std::vector<hilti::Node>& Model<T>::children() const { return data().children(); }

template<typename T>
std::vector<hilti::Node>& Model<T>::children()  { return data().children(); }

template<typename T>
const Meta& Model<T>::meta() const { return data().meta(); }

template<typename T>
void Model<T>::setMeta(Meta m)  { return data().setMeta(m); }

template<typename T>
bool Model<T>::pruneWalk() const { return data().pruneWalk(); }

template<typename T>
ResolvedOperator Model<T>::_clone() const { return T(data()); }

template<typename T>
hilti::IntrusivePtr<Concept> Model<T>::_clone_ptr() const {
    if constexpr ( std::is_base_of<hilti::util::type_erasure::trait::Singleton, T>::value )
        return nullptr;
    else
        return hilti::make_intrusive<Model>(T(data()));
}

inline Operator ResolvedOperator::operator_() const { return data()->operator_(); }

inline const hilti::Type& ResolvedOperator::result() const { return data()->result(); }

inline hilti::node::Range<Expression> ResolvedOperator::operands() const { return data()->operands(); }

inline const Expression& ResolvedOperator::op0() const { return data()->op0(); }

inline const Expression& ResolvedOperator::op1() const { return data()->op1(); }

inline const Expression& ResolvedOperator::op2() const { return data()->op2(); }

inline bool ResolvedOperator::hasOp0()  { return data()->hasOp0(); }

inline bool ResolvedOperator::hasOp1()  { return data()->hasOp1(); }

inline bool ResolvedOperator::hasOp2()  { return data()->hasOp2(); }

inline void ResolvedOperator::setOp0(Expression e)  { return data()->setOp0(std::move(e)); }

inline void ResolvedOperator::setOp1(Expression e)  { return data()->setOp1(std::move(e)); }

inline void ResolvedOperator::setOp2(Expression e)  { return data()->setOp2(std::move(e)); }

inline bool ResolvedOperator::isLhs() const { return data()->isLhs(); }

inline bool ResolvedOperator::isTemporary() const { return data()->isTemporary(); }

inline const hilti::Type& ResolvedOperator::type() const { return data()->type(); }

inline bool ResolvedOperator::isEqual(const Expression& other) const { return data()->isEqual(other); }

inline bool ResolvedOperator::isConstant() const { return data()->isConstant(); }

inline hilti::node::Properties ResolvedOperator::properties() const { return data()->properties(); }

inline const std::vector<hilti::Node>& ResolvedOperator::children() const { return data()->children(); }

inline std::vector<hilti::Node>& ResolvedOperator::children()  { return data()->children(); }

inline const Meta& ResolvedOperator::meta() const { return data()->meta(); }

inline void ResolvedOperator::setMeta(Meta m)  { return data()->setMeta(std::move(m)); }

inline bool ResolvedOperator::pruneWalk() const { return data()->pruneWalk(); }

inline ResolvedOperator ResolvedOperator::_clone() const { return data() ? data()->_clone() : ResolvedOperator(); }

inline hilti::IntrusivePtr<Concept> ResolvedOperator::_clone_ptr() const {
    if ( data() )
        return data()->_clone_ptr();
    else
        return nullptr;
}



