/** @file ParserStack.hpp * * @author Roland Conybeare, Jan 2026 **/ #pragma once #include "SyntaxStateMachine.hpp" #include #include #include namespace xo { namespace scm { /** @brief A stack of expression state machines * * Each state machine is dedicated to a particular syntax instance. * The innermost machine is in xsm; machines for surrounding expressions * are in progressively removed frames reached via parent links. **/ class ParserStack { public: using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; public: ParserStack(DArena::Checkpoint ckp, obj ssm, ParserStack * parent); /** create new top of stack for syntax @p ssm, using memory from @p mm. * previous stack given by @p parent. * Checkpoint @p ckp will refer to stack _before_ allocating @p ssm **/ static ParserStack * push(ParserStack * stack, DArena::Checkpoint ckp, DArena & mm, obj ssm); /** unwind effect of last call to @ref push **/ static ParserStack * pop(ParserStack * stack, DArena & mm); DArena::Checkpoint ckp() const noexcept { return ckp_; } obj top() const noexcept { return ssm_; } ParserStack * parent() const noexcept { return parent_; } /** regular printing **/ void print(std::ostream & os) const; /** pretty-printer support **/ bool pretty(const ppindentinfo & ppii) const; private: /** stack pointer: top of stack just before this instance created **/ DArena::Checkpoint ckp_; /** top of parsing stack: always non-null **/ obj ssm_; /** remainder of parsing stack excluding top **/ ParserStack * parent_ = nullptr; }; inline std::ostream & operator<< (std::ostream & os, const ParserStack * x) { if (x) { x->print(os); } else { os << "nullptr"; } return os; } } /*namespace scm*/ namespace print { /** pretty printer in relies on this specialization * to handle ParserResult instances **/ template <> struct ppdetail { static inline bool print_pretty(const ppindentinfo & ppii, const xo::scm::ParserStack * p) { if (p) return p->pretty(ppii); else return ppii.pps()->print_upto("nullptr"); } }; } } /*namespace xo*/ /* end ParserStack.hpp */