/** @file SchematikaReader.hpp * * @author Roland Conybeare, Jan 2026 **/ #pragma once #include "ReaderConfig.hpp" #include "SchematikaParser.hpp" #include #include namespace xo { namespace scm { struct ReaderResult { using ACollector = xo::mm::ACollector; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using span_type = xo::mm::span; bool is_tk_error() const { return tk_error_.is_error(); } /** forward gc-aware pointers (called during gc cycle) **/ void visit_gco_children(obj gc) noexcept; /** schematika expression parsed from input **/ obj expr_; /** unconsumed portion of input span * only relevant when result type is expression. * (otherwise input consumed) **/ span_type remaining_input_; /** {src_function, error_description, input_state, error_pos} **/ TokenizerError tk_error_; }; /** @class SchematikaReader * @brief Pipeline comprising Schematika tokenizer and parser * * Consumes text; produces expressions **/ class SchematikaReader { public: using ACollector = xo::mm::ACollector; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using AAllocator = xo::mm::AAllocator; using MemorySizeVisitor = xo::mm::MemorySizeVisitor; using span_type = xo::mm::span; using size_type = std::size_t; public: /** * @p expr_alloc. allocator for Schematika expressions * @p aux_alloc. allocator for miscellaneous objects * (e.g. DArenaHashMap for global symtab) * that have lifetime bounded by Schematika reader itself. **/ SchematikaReader(const ReaderConfig & config, obj expr_alloc, obj aux_alloc); /** non-trivial dtor because of @p parser **/ ~SchematikaReader() = default; /** top-level symbol table **/ DGlobalSymtab * global_symtab() const noexcept; /** top-level global environment (e.g. contains built-in primitives) **/ DGlobalEnv * global_env() const noexcept; /** global unique-string table **/ StringTable * stringtable() noexcept; /** visit reader-owned memory pools; call visitor(info) for each. * Specifically exclude expr_alloc, since we don't consider * that reader-owned **/ void visit_pools(const MemorySizeVisitor & visitor) const; /** true iff parser is at top-level. * false iff parser is working on incomplete expression **/ bool is_at_toplevel() const noexcept; /** prepare interactive session * (allows rvalue expressions at toplevel) **/ void begin_interactive_session(); /** prepare batch session * (limits expression types at toplevel) **/ void begin_batch_session(); /** intern string @p str in global string table **/ const DUniqueString * intern_string(std::string_view str); /** consume input @p input_cstr **/ const ReaderResult & read_expr(span_type input_span, bool eof); /** reset @ref result_ to nominal value **/ void reset_result(); /** reset to known starting point after encountering an error. * - remainder of stashed current line. * Necesary for well-formatted error reporting. * - current parsing state **/ void reset_to_idle_toplevel(); /** update gc-aware child pointers **/ void visit_gco_children(obj gc) noexcept; private: /** tokenizer converts a stream of chars * to a stream of lexical tokens **/ Tokenizer tokenizer_; /** parser converts a stream of tokens * to a stream of expressions **/ DSchematikaParser parser_; /** current output from reader **/ ReaderResult result_; /** true to enable reader debug logging **/ bool debug_flag_ = false; }; } /*namespace scm*/ } /*namespace xo*/ /* end SchematikaReader.hpp */