/** @file DConstant.hpp
 *
 *  @author Roland Conybeare, Jan 2026
 **/

#pragma once

#include "Expression.hpp"
#include "TypeRef.hpp"
#include "exprtype.hpp"
#include <xo/alloc2/GCObject.hpp>
#include <xo/alloc2/GCObjectVisitor.hpp>
#include <xo/reflect/TaggedPtr.hpp>

namespace xo {
    namespace scm {
        /** @class DConstant
         *  @brief Schematika expression respresenting a literal constant
         **/
        struct DConstant {
        public:
            using TaggedPtr = xo::reflect::TaggedPtr;
            using TypeDescr = xo::reflect::TypeDescr;
            using AGCObject = xo::mm::AGCObject;
            using VisitReason = xo::mm::VisitReason;
            using AGCObjectVisitor = xo::mm::AGCObjectVisitor;
            using AAllocator = xo::mm::AAllocator;
            using typeseq = xo::reflect::typeseq;
            using ppindentinfo = xo::print::ppindentinfo;

        public:
            explicit DConstant(obj<AGCObject> value) noexcept;

            /** create isntance
             *  @p mm     memory allocator
             *  @p value  literal constant
             **/
            static obj<AExpression,DConstant> make(obj<AAllocator> mm,
                                                   obj<AGCObject> value);

            /** create instance
             *  @p mm     memory allocator
             *  @p value  literal constant
             **/
            static DConstant * _make(obj<AAllocator> mm,
                                     obj<AGCObject> value);

            bool is_resolved() const noexcept { return typeref_.is_resolved(); }

            obj<AGCObject> value() const noexcept { return value_; }
            TypeDescr value_td() const noexcept { return typeref_.td(); }
            TaggedPtr value_tp() const noexcept { return TaggedPtr(typeref_.td(), value_.data()); }

            /** @defgroup scm-constant-expression-facet **/
            ///@{

            exprtype extype() const noexcept { return exprtype::constant; }
            TypeRef typeref() const noexcept { return typeref_; }
            TypeDescr valuetype() const noexcept { return typeref_.td(); }
            void assign_valuetype(TypeDescr td) noexcept { typeref_.resolve(td); }

            ///@}
            /** @defgroup scm-constant-gcobject-facet **/
            ///@{

            DConstant * gco_shallow_move(obj<AGCObjectVisitor> gc) noexcept;
            void visit_gco_children(VisitReason reason, obj<AGCObjectVisitor> gc) noexcept;

            ///@}
            /** @defgroup scm-constant-printable-facet **/
            ///@{

            bool pretty(const ppindentinfo & ppii) const;

            ///@}

        private:
            static TypeDescr _lookup_td(typeseq tseq);

        private:
            /** type for value of this expression
             *  or unification breadcrumb before unification
             **/
            TypeRef typeref_;
            /** literal value **/
            obj<AGCObject> value_;
        };
    } /*namespace scm*/
} /*namespace xo*/

/* end DConstant.hpp */
