
class Item;

class Concept : public hilti::util::type_erasure::ConceptBase {
public:
    Concept() = default;
    Concept(const Concept&) = default;
    Concept(Concept&&) = default;
    virtual ~Concept() = default;
    /** Returns the type of the parsed unit item. */
    virtual const Type& itemType() const = 0;
    /** Returns true if the item's type has been resolved. */
    virtual bool isResolved() const = 0;
    /** Returns true if the unit item is equivalent to another one. */
    virtual bool isEqual(const Item& other) 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 Item _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;

    const Type& itemType() const final;
    bool isResolved() const final;
    bool isEqual(const Item& other) 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;
    Item _clone() const final;
    hilti::IntrusivePtr<Concept> _clone_ptr() const final;
};

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

class Item : public ErasedBase, public hilti::trait::isNode {
public:
    using ErasedBase::ErasedBase;

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

    const Type& itemType() const;
    bool isResolved() const;
    bool isEqual(const Item& other) 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;
    Item _clone() const;

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

protected:
    
};

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

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

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

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>
Item 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 const Type& Item::itemType() const { return data()->itemType(); }

inline bool Item::isResolved() const { return data()->isResolved(); }

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

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

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

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

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

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

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

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

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



