From f2a9aa3f524d355e76261759e9a5cad68d73bd1e Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 2 Mar 2026 23:21:10 +1100 Subject: [PATCH] xo-interpreter2 stack: parse literal lists (w/ implicit types) --- CMakeLists.txt | 20 ++ idl/IPrintable_DExpectQListSsm.json5 | 16 ++ idl/ISyntaxStateMachine_DExpectQListSsm.json5 | 16 ++ include/xo/reader2/DExpectQListSsm.hpp | 155 +++++++++++ include/xo/reader2/DExpectQLiteralSsm.hpp | 55 +--- include/xo/reader2/DSyntaxStateMachine.hpp | 19 +- include/xo/reader2/ExpectQListSsm.hpp | 12 + .../ssm/IPrintable_DExpectQListSsm.hpp | 62 +++++ .../ISyntaxStateMachine_DExpectQListSsm.hpp | 82 ++++++ include/xo/reader2/syntaxstatetype.hpp | 3 + src/reader2/CMakeLists.txt | 4 + src/reader2/DExepctQListSsm.cpp | 255 ++++++++++++++++++ src/reader2/DExpectQListSsm.cpp | 215 +++++++++++++++ src/reader2/DExpectQLiteralSsm.cpp | 75 +++--- src/reader2/IPrintable_DExpectQListSsm.cpp | 28 ++ .../ISyntaxStateMachine_DExpectQListSsm.cpp | 79 ++++++ src/reader2/reader2_register_facets.cpp | 11 +- src/reader2/syntaxstatetype.cpp | 2 + utest/SchematikaParser.test.cpp | 42 ++- 19 files changed, 1052 insertions(+), 99 deletions(-) create mode 100644 idl/IPrintable_DExpectQListSsm.json5 create mode 100644 idl/ISyntaxStateMachine_DExpectQListSsm.json5 create mode 100644 include/xo/reader2/DExpectQListSsm.hpp create mode 100644 include/xo/reader2/ExpectQListSsm.hpp create mode 100644 include/xo/reader2/ssm/IPrintable_DExpectQListSsm.hpp create mode 100644 include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQListSsm.hpp create mode 100644 src/reader2/DExepctQListSsm.cpp create mode 100644 src/reader2/DExpectQListSsm.cpp create mode 100644 src/reader2/IPrintable_DExpectQListSsm.cpp create mode 100644 src/reader2/ISyntaxStateMachine_DExpectQListSsm.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index eef3fddb..b7b5a5f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -333,6 +333,26 @@ xo_add_genfacetimpl( # ---------------------------------------------------------------- +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-syntaxstatemachine-expectqlistssm + FACET_PKG xo_reader2 + FACET SyntaxStateMachine + REPR ExpectQListSsm + INPUT idl/ISyntaxStateMachine_DExpectQListSsm.json5 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-printable-expectqlistssm + FACET_PKG xo_printable2 + FACET Printable + REPR ExpectQListSsm + INPUT idl/IPrintable_DExpectQListSsm.json5 +) + +# ---------------------------------------------------------------- + xo_add_genfacet_all(xo-reader2-genfacet-all) # ---------------------------------------------------------------- diff --git a/idl/IPrintable_DExpectQListSsm.json5 b/idl/IPrintable_DExpectQListSsm.json5 new file mode 100644 index 00000000..91f98f8f --- /dev/null +++ b/idl/IPrintable_DExpectQListSsm.json5 @@ -0,0 +1,16 @@ +{ + mode: "implementation", + output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", + includes: [ "", + "" ], + local_types: [], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DExpectQListSsm", + using_doxygen: true, + repr: "DExpectQListSsm", + doc: [ "implement APrintable for DExpectQListSsm" ], +} diff --git a/idl/ISyntaxStateMachine_DExpectQListSsm.json5 b/idl/ISyntaxStateMachine_DExpectQListSsm.json5 new file mode 100644 index 00000000..94d59ba0 --- /dev/null +++ b/idl/ISyntaxStateMachine_DExpectQListSsm.json5 @@ -0,0 +1,16 @@ +{ + mode: "implementation", + output_cpp_dir: "src/reader2", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "ssm", + includes: [ "\"SyntaxStateMachine.hpp\"", + "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/SyntaxStateMachine.json5", + brief: "provide ASyntaxStateMachine interface for DExpectQListSsm", + using_doxygen: true, + repr: "DExpectQListSsm", + doc: [ "implement ASyntaxStateMachine for DExpectQListSsm" ], +} diff --git a/include/xo/reader2/DExpectQListSsm.hpp b/include/xo/reader2/DExpectQListSsm.hpp new file mode 100644 index 00000000..2b4b70b2 --- /dev/null +++ b/include/xo/reader2/DExpectQListSsm.hpp @@ -0,0 +1,155 @@ +/** @file DExpectQListSsm.hpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#pragma once + +#include "DSyntaxStateMachine.hpp" +#include +//#include +#include + +namespace xo { + namespace scm { + /** + * Already in quoted-literal context + * + * ( quote-expr ... ) + * ^ ^ ^ + * | qlist_1a qlist_2(done) + * qlist_0 + * + * qlist_0 --on_leftparen_token()--> qlist_1a [push ExpectQLiteralSsm] + * qlist_1a --on_quoted_literal()--> qlist_1a [append literal] + * qlist_1a --on_rightparen_token()--> qlist_2(done) [report quoted list] + **/ + class QListXst { + public: + enum class code { + invalid = -1, + + qlist_0, + qlist_1a, + qlist_2, + + N + }; + + explicit QListXst(code x) : code_{x} {} + + /** @return string representation for enum @p x **/ + static const char * _descr(code x); + + code code() const noexcept { return code_; } + + enum code code_; + }; + + inline std::ostream & + operator<< (std::ostream & os, QListXst x) { + os << QListXst::_descr(x.code_); + return os; + } + + /** @class DExpectQListSsm + * @brief parser state-machine for a formal parameter list + **/ + class DExpectQListSsm : public DSyntaxStateMachine { + public: + using Super = DSyntaxStateMachine; + using AAllocator = xo::mm::AAllocator; + using DArena = xo::mm::DArena; + using TypeDescr = xo::reflect::TypeDescr; + using ppindentinfo = xo::print::ppindentinfo; + using size_type = std::uint32_t; + + public: + /** @defgroup scm-expectqlistssm-ctors constructors **/ + ///@{ + + DExpectQListSsm(); + + /** create instance, using memory from @parser_mm **/ + static obj make(DArena & parser_mm); + static DExpectQListSsm * _make(DArena & parser_mm); + + /** start nested syntax for a quoted literal **/ + static void start(ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-expectformalarglistssm-methods general methods **/ + ///@{ + + static const char * ssm_classname() { return "DExpectQListSsm"; } + + /** update state on incoming token @p tk, with overall parser state in @p p_psm **/ + void on_leftparen_token(const Token & tk, + ParserStateMachine * p_psm); + + void on_rightparen_token(const Token & tk, + ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-expectqlistssm-ssm-facet syntaxstatemachine facet methods **/ + ///@{ + + /** identifies the ssm implemented here **/ + syntaxstatetype ssm_type() const noexcept; + + /** mnemonic for expected input (for this ssm) in current state **/ + std::string_view get_expect_str() const; + + /** update state on incoming token @p tk, + * with overall parser state in @p p_psm + **/ + void on_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state for nested qliteral @p lit, with overall parser state in @p p_psm. + * Appends @p lit to target list + **/ + void on_quoted_literal(obj lit, + ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-expectqlistssm-printable-facet printable facet methods **/ + ///@{ + + bool pretty(const ppindentinfo & ppii) const; + + ///@} + + private: + /** @defgroup scm-expectqlistssm-impl-methods **/ + ///@{ + + /** update local state to include parsed formal (param_name, param_type). + * If stack memory needed, get from @p parser_alloc. + * Lifetime until formal arglist completely parsed + **/ + void _accept_formal(obj expr_alloc, + DArena & parser_alloc, + const DUniqueString * param_name, + TypeDescr param_type); + + ///@} + + private: + /** @defgroup scm-expectqlistssm-member-vars **/ + ///@{ + + /** identifies qlist parsing state **/ + QListXst state_; + + /** first node in literal list **/ + DList * start_ = nullptr; + /** last node in literal list **/ + DList * end_ = nullptr; + + ///@} + }; + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DExpectQListSsm.hpp */ diff --git a/include/xo/reader2/DExpectQLiteralSsm.hpp b/include/xo/reader2/DExpectQLiteralSsm.hpp index 407146a5..efb93f6d 100644 --- a/include/xo/reader2/DExpectQLiteralSsm.hpp +++ b/include/xo/reader2/DExpectQLiteralSsm.hpp @@ -11,37 +11,7 @@ namespace xo { namespace scm { -#ifdef NOT_USING - /** - * Already in quoted-literal context - * - * #q{ } - * ^ - * qliteral_0 - * - * qliteral_0 --on_leftparen_token()--> push QuotedListSsm - **/ - enum class formalarglstatetype { - invalid = -1, - - argl_0, - argl_1a, - argl_1b, - - n_formalarglstatetype, - }; - - extern const char * - formalarglstatetype_descr(formalarglstatetype x); - - inline std::ostream & - operator<< (std::ostream & os, formalarglstatetype x) { - os << formalarglstatetype_descr(x); - return os; - } -#endif - - /** @class expect_formal_arglist + /** @class DExpectQLiteralSsm * @brief parser state-machine for a formal parameter list **/ class DExpectQLiteralSsm : public DSyntaxStateMachine { @@ -54,14 +24,17 @@ namespace xo { using size_type = std::uint32_t; public: - DExpectQLiteralSsm(); + explicit DExpectQLiteralSsm(bool cxl_on_rightparen); /** create instance, using memory from @parser_mm **/ - static obj make(DArena & parser_mm); - static DExpectQLiteralSsm * _make(DArena & parser_mm); + static obj make(DArena & parser_mm, + bool cxl_on_rightparen); + static DExpectQLiteralSsm * _make(DArena & parser_mm, + bool cxl_on_rightparen); /** start nested syntax for a quoted literal **/ - static void start(ParserStateMachine * p_psm); + static void start(ParserStateMachine * p_psm, + bool cxl_on_rightparen = false); /** @defgroup scm-expectformalarglistssm-methods general methods **/ ///@{ @@ -126,16 +99,8 @@ namespace xo { ///@} private: -#ifdef NOT_USING - /** parsing state-machine state **/ - formalarglstatetype fastate_ = formalarglstatetype::argl_0; - /** populate with (parameter-name, parameter-type) list - * as they're encountered. - * - * Not using flexible array here since we don't know size at construction time - **/ - DArray * argl_ = nullptr; -#endif + /** if true rightparen pops + delegates to parent ssm **/ + bool cxl_on_rightparen_ = false; }; } /*namespace scm*/ } /*namespace xo*/ diff --git a/include/xo/reader2/DSyntaxStateMachine.hpp b/include/xo/reader2/DSyntaxStateMachine.hpp index b72a3e92..adce34e1 100644 --- a/include/xo/reader2/DSyntaxStateMachine.hpp +++ b/include/xo/reader2/DSyntaxStateMachine.hpp @@ -32,6 +32,18 @@ namespace xo { using TypeDescr = xo::reflect::TypeDescr; using AGCObject = xo::mm::AGCObject; + /** Explicit error path **/ + void illegal_token(const Token & tk, + ParserStateMachine * p_psm) + { + // starting with c++23 can use "this auto&& self" instead + Derived & self = reinterpret_cast(*this); + + p_psm->illegal_input_on_token(Derived::ssm_classname(), + tk, + self.get_expect_str()); + } + /** Explicit error path **/ void illegal_quoted_literal(obj lit, ParserStateMachine * p_psm) @@ -49,12 +61,7 @@ namespace xo { void on_token(const Token & tk, ParserStateMachine * p_psm) { - // starting with c++23 can use "this auto&& self" instead - Derived & self = reinterpret_cast(*this); - - p_psm->illegal_input_on_token(Derived::ssm_classname(), - tk, - self.get_expect_str()); + this->illegal_token(tk, p_psm); } void on_parsed_symbol(std::string_view sym, diff --git a/include/xo/reader2/ExpectQListSsm.hpp b/include/xo/reader2/ExpectQListSsm.hpp new file mode 100644 index 00000000..82a3c0ab --- /dev/null +++ b/include/xo/reader2/ExpectQListSsm.hpp @@ -0,0 +1,12 @@ +/** @file ExpectQListSsm.hpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#pragma once + +#include "DExpectQListSsm.hpp" +#include "ssm/ISyntaxStateMachine_DExpectQListSsm.hpp" +#include "ssm/IPrintable_DExpectQListSsm.hpp" + +/* end ExpectQListSsm.hpp */ diff --git a/include/xo/reader2/ssm/IPrintable_DExpectQListSsm.hpp b/include/xo/reader2/ssm/IPrintable_DExpectQListSsm.hpp new file mode 100644 index 00000000..45d72c07 --- /dev/null +++ b/include/xo/reader2/ssm/IPrintable_DExpectQListSsm.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DExpectQListSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DExpectQListSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DExpectQListSsm.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DExpectQListSsm.hpp" + +namespace xo { namespace scm { class IPrintable_DExpectQListSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DExpectQListSsm + **/ + class IPrintable_DExpectQListSsm { + public: + /** @defgroup scm-printable-dexpectqlistssm-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-dexpectqlistssm-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DExpectQListSsm & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQListSsm.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQListSsm.hpp new file mode 100644 index 00000000..6cd1a38b --- /dev/null +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExpectQListSsm.hpp @@ -0,0 +1,82 @@ +/** @file ISyntaxStateMachine_DExpectQListSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DExpectQListSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DExpectQListSsm.json5] + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +#include "SyntaxStateMachine.hpp" +#include "ssm/ISyntaxStateMachine_Xfer.hpp" +#include "DExpectQListSsm.hpp" + +namespace xo { namespace scm { class ISyntaxStateMachine_DExpectQListSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::ISyntaxStateMachine_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class ISyntaxStateMachine_DExpectQListSsm + **/ + class ISyntaxStateMachine_DExpectQListSsm { + public: + /** @defgroup scm-syntaxstatemachine-dexpectqlistssm-type-traits **/ + ///@{ + using TypeDescr = xo::scm::ASyntaxStateMachine::TypeDescr; + using AGCObject = xo::scm::ASyntaxStateMachine::AGCObject; + using Copaque = xo::scm::ASyntaxStateMachine::Copaque; + using Opaque = xo::scm::ASyntaxStateMachine::Opaque; + ///@} + /** @defgroup scm-syntaxstatemachine-dexpectqlistssm-methods **/ + ///@{ + // const methods + /** identify a type of syntax state machine **/ + static syntaxstatetype ssm_type(const DExpectQListSsm & self) noexcept; + /** text describing expected/allowed input to this ssm in current state **/ + static std::string_view get_expect_str(const DExpectQListSsm & self) noexcept; + + // non-const methods + /** operate state machine for incoming token @p tk **/ + static void on_token(DExpectQListSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update stat machine for incoming parsed symbol @p sym **/ + static void on_parsed_symbol(DExpectQListSsm & self, std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for incoming type description @p td **/ + static void on_parsed_typedescr(DExpectQListSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal(DExpectQListSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal_with_token(DExpectQListSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm); + /** consume formal arglist emitted by nested ssm **/ + static void on_parsed_formal_arglist(DExpectQListSsm & self, DArray * arglist, ParserStateMachine * p_psm); + /** update state machine for nested parsed expression @p expr **/ + static void on_parsed_expression(DExpectQListSsm & self, obj expr, ParserStateMachine * p_psm); + /** update state machine @p p_psm for incoming parsed expression @p expr followed by token @p tk **/ + static void on_parsed_expression_with_token(DExpectQListSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for nested quoted literal @p lit **/ + static void on_quoted_literal(DExpectQListSsm & self, obj lit, ParserStateMachine * p_psm); + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/syntaxstatetype.hpp b/include/xo/reader2/syntaxstatetype.hpp index 68656581..0a0c857c 100644 --- a/include/xo/reader2/syntaxstatetype.hpp +++ b/include/xo/reader2/syntaxstatetype.hpp @@ -63,6 +63,9 @@ namespace xo { /** expecting a quoted literal. See @ref DExpectQLiteralSsm **/ expect_qliteral, + /** expecint a quoted list. See @ref DExpectQListSsm **/ + expect_qlist, + /** comes lasts, counts number of valid enums **/ N }; diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index b00c4d04..fa88a4dd 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -69,6 +69,10 @@ set(SELF_SRCS ISyntaxStateMachine_DExpectQLiteralSsm.cpp IPrintable_DExpectQLiteralSsm.cpp + DExpectQListSsm.cpp + ISyntaxStateMachine_DExpectQListSsm.cpp + IPrintable_DExpectQListSsm.cpp + DProgressSsm.cpp ISyntaxStateMachine_DProgressSsm.cpp IPrintable_DProgressSsm.cpp diff --git a/src/reader2/DExepctQListSsm.cpp b/src/reader2/DExepctQListSsm.cpp new file mode 100644 index 00000000..44393451 --- /dev/null +++ b/src/reader2/DExepctQListSsm.cpp @@ -0,0 +1,255 @@ +/* @file DExpectQListSsm.cpp + * + * @author Roland Conybeare, Mar 2026 + */ + +#include "ExpectQLiteralSsm.hpp" +#include +//#include "DExpectFormalArgSsm.hpp" +//#include "ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp" +//#include +//#include +//#include +//#include +//#include +#include + +namespace xo { +// using xo::print::APrintable; +// using xo::print::ppstate; +// using xo::print::ppindentinfo; + using xo::mm::AGCObject; +// using xo::mm::AAllocator; +// using xo::facet::FacetRegistry; +// using xo::reflect::typeseq; + + namespace scm { +#ifdef NOT_USING + const char * + formalarglstatetype_descr(formalarglstatetype x) { + switch (x) { + case formalarglstatetype::invalid: + return "invalid"; + case formalarglstatetype::argl_0: + return "argl_0"; + case formalarglstatetype::argl_1a: + return "argl_1a"; + case formalarglstatetype::argl_1b: + return "argl_1b"; + case formalarglstatetype::n_formalarglstatetype: + break; + } + + return "?formalarglstatetype"; + } +#endif + + DExpectQListSsm::DExpectQListSsm() + {} + + DExpectQListSsm * + DExpectQListSsm::_make(DArena & arena) + { + /* out-of-order so argl follows ssm in arena, + * consistent with any subsequent arglist realloc. + * Not a load-bearing choice however + */ + + void * mem = arena.alloc_for(); + + return new (mem) DExpectQListSsm(); + } + + obj + DExpectQListSsm::make(DArena & arena) + { + obj retval(_make(arena)); + + return retval; + } + + void + DExpectQListSsm::start(ParserStateMachine * p_psm) + { + DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); + + p_psm->push_ssm(ckp, DExpectQListSsm::make(p_psm->parser_alloc())); + } + + syntaxstatetype + DExpectQListSsm::ssm_type() const noexcept { + return syntaxstatetype::expect_qliteral; + } + + std::string_view + DExpectQListSsm::get_expect_str() const + { + return "leftparen|leftbracket|leftbrace|string|f64|i64|bool"; + } + + void + DExpectQListSsm::on_token(const Token & tk, + ParserStateMachine * p_psm) + { + switch (tk.tk_type()) { + case tokentype::tk_f64: + this->on_f64_token(tk, p_psm); + return; + + case tokentype::tk_leftparen: + case tokentype::tk_comma: + case tokentype::tk_rightparen: + case tokentype::tk_lambda: + case tokentype::tk_def: + case tokentype::tk_if: + case tokentype::tk_symbol: + case tokentype::tk_colon: + case tokentype::tk_singleassign: + case tokentype::tk_string: + case tokentype::tk_i64: + case tokentype::tk_bool: + case tokentype::tk_semicolon: + case tokentype::tk_invalid: + case tokentype::tk_quote: + case tokentype::tk_leftbracket: + case tokentype::tk_rightbracket: + case tokentype::tk_leftbrace: + case tokentype::tk_rightbrace: + case tokentype::tk_leftangle: + case tokentype::tk_rightangle: + case tokentype::tk_lessequal: + case tokentype::tk_greatequal: + case tokentype::tk_dot: + case tokentype::tk_doublecolon: + case tokentype::tk_assign: + case tokentype::tk_yields: + case tokentype::tk_plus: + case tokentype::tk_minus: + case tokentype::tk_star: + case tokentype::tk_slash: + case tokentype::tk_cmpeq: + case tokentype::tk_cmpne: + case tokentype::tk_type: + case tokentype::tk_then: + case tokentype::tk_else: + case tokentype::tk_let: + case tokentype::tk_in: + case tokentype::tk_end: + case tokentype::N: + break; + } + + Super::on_token(tk, p_psm); + } + + void + DExpectQListSsm::on_f64_token(const Token & tk, + ParserStateMachine * p_psm) + { + auto literal = DFloat::box(p_psm->expr_alloc(), + tk.f64_value()); + + p_psm->pop_ssm(); + p_psm->on_quoted_literal(literal); + } + +#ifdef NOT_YET + void + DExpectQListSsm::_accept_formal(obj expr_alloc, + DArena & parser_alloc, + const DUniqueString * param_name, + TypeDescr param_type) + { + /* note: param_type can be nullptr */ + TypeRef typeref + = TypeRef::dwim(TypeRef::prefix_type::from_chars("formal"), param_type); + + DVariable * var = DVariable::make(expr_alloc, + param_name, + typeref); + + // need AGCObject facet to use DArray here. + // May want to have gc feature that allows it to use + // FacetRegistry on memory that stores obj + // + // In this case doesn't matter since DExpectQListSsm not actually collected! + + obj var_o(var); + + if (argl_->size() == argl_->capacity()) { + // need to expand argl_ capacity. + // If DArena were to allow it (i.e. offer a realloc() feature, + // could do this in place since this SSM is at the top of the parser stack. + + obj mm(&parser_alloc); + DArray * argl_2x = DArray::empty(mm, 2 * argl_->capacity()); + + for (DArray::size_type i = 0, n = argl_->size(); i < n; ++i) { + // TODO: prefer non-bounds-checked access here + argl_2x->push_back(argl_->at(i)); + } + + // update in place + this->argl_ = argl_2x; + } + + this->argl_->push_back(var_o); + } +#endif + +#ifdef NOT_YET + void + DExpectQListSsm::on_leftparen_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (fastate_ == formalarglstatetype::argl_0) { + this->fastate_ = formalarglstatetype::argl_1a; + + DExpectFormalArgSsm::start(p_psm); + return; + } + + Super::on_token(tk, p_psm); + } + + void + DExpectQListSsm::on_comma_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (fastate_ == formalarglstatetype::argl_1b) { + this->fastate_ = formalarglstatetype::argl_1a; + + DExpectFormalArgSsm::start(p_psm); + return; + } + + Super::on_token(tk, p_psm); + } + + void + DExpectQListSsm::on_rightparen_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (fastate_ == formalarglstatetype::argl_1b) { + DArray * args = argl_; + + p_psm->pop_ssm(); + p_psm->on_parsed_formal_arglist(args); + return; + } + + Super::on_token(tk, p_psm); + } +#endif + + bool + DExpectQListSsm::pretty(const ppindentinfo & ppii) const + { + return ppii.pps()->pretty_struct(ppii, + "DExpectQListSsm", + refrtag("expect", this->get_expect_str())); + } + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DExpectQListSsm.cpp */ diff --git a/src/reader2/DExpectQListSsm.cpp b/src/reader2/DExpectQListSsm.cpp new file mode 100644 index 00000000..2227a398 --- /dev/null +++ b/src/reader2/DExpectQListSsm.cpp @@ -0,0 +1,215 @@ +/** @file DExpectQListSsm.cpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#include "ExpectQListSsm.hpp" +#include "ExpectQLiteralSsm.hpp" +#include +#include +#include + +namespace xo { + using xo::print::APrintable; + using xo::facet::FacetRegistry; + using xo::mm::AGCObject; + + namespace scm { + const char * + QListXst::_descr(enum code x) + { + switch (x) { + case code::invalid: break; + case code::qlist_0: return "qlist_0"; + case code::qlist_1a: return "qlist_1a"; + case code::qlist_2: return "qlist_2"; + case code::N: break; + } + + return "?QListXst"; + } + + DExpectQListSsm::DExpectQListSsm() : state_{QListXst::code::qlist_0} {} + + obj + DExpectQListSsm::make(DArena & parser_mm) + { + return obj(_make(parser_mm)); + } + + DExpectQListSsm * + DExpectQListSsm::_make(DArena & parser_mm) + { + void * mem = parser_mm.alloc_for(); + + return new (mem) DExpectQListSsm(); + } + + void + DExpectQListSsm::start(ParserStateMachine * p_psm) + { + DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); + + p_psm->push_ssm(ckp, DExpectQListSsm::make(p_psm->parser_alloc())); + } + + syntaxstatetype + DExpectQListSsm::ssm_type() const noexcept { + return syntaxstatetype::expect_qlist; + } + + std::string_view + DExpectQListSsm::get_expect_str() const { + switch (state_.code()) { + case QListXst::code::qlist_0: + return "leftparen"; + case QListXst::code::qlist_1a: + return "qliteral|rightparen"; + case QListXst::code::qlist_2: + return "(done)"; + case QListXst::code::invalid: + case QListXst::code::N: + break; + } + + return "?DExpectQListSsm"; + } + + void + DExpectQListSsm::on_token(const Token & tk, + ParserStateMachine * p_psm) + { + switch(tk.tk_type()) + { + case tokentype::tk_leftparen: + this->on_leftparen_token(tk, p_psm); + return; + + case tokentype::tk_rightparen: + this->on_rightparen_token(tk, p_psm); + return; + + case tokentype::tk_comma: + case tokentype::tk_lambda: + case tokentype::tk_def: + case tokentype::tk_if: + case tokentype::tk_symbol: + case tokentype::tk_colon: + case tokentype::tk_singleassign: + case tokentype::tk_string: + case tokentype::tk_f64: + case tokentype::tk_i64: + case tokentype::tk_bool: + case tokentype::tk_semicolon: + case tokentype::tk_invalid: + case tokentype::tk_quote: + case tokentype::tk_leftbracket: + case tokentype::tk_rightbracket: + case tokentype::tk_leftbrace: + case tokentype::tk_rightbrace: + case tokentype::tk_leftangle: + case tokentype::tk_rightangle: + case tokentype::tk_lessequal: + case tokentype::tk_greatequal: + case tokentype::tk_dot: + case tokentype::tk_doublecolon: + case tokentype::tk_assign: + case tokentype::tk_yields: + case tokentype::tk_plus: + case tokentype::tk_minus: + case tokentype::tk_star: + case tokentype::tk_slash: + case tokentype::tk_cmpeq: + case tokentype::tk_cmpne: + case tokentype::tk_type: + case tokentype::tk_then: + case tokentype::tk_else: + case tokentype::tk_let: + case tokentype::tk_in: + case tokentype::tk_end: + case tokentype::N: + break; + } + } + + void + DExpectQListSsm::on_leftparen_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (state_.code() == QListXst::code::qlist_0) { + this->state_ = QListXst(QListXst::code::qlist_1a); + this->start_ = DList::_nil(); + this->end_ = nullptr; + + DExpectQLiteralSsm::start(p_psm, + true /*cxl_on_rightparen*/); + return; + } + + Super::illegal_token(tk, p_psm); + } + + void + DExpectQListSsm::on_rightparen_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (state_.code() == QListXst::code::qlist_1a) { + this->state_ = QListXst(QListXst::code::qlist_2); + + obj lit = obj(start_); + + p_psm->pop_ssm(); + p_psm->on_quoted_literal(lit); + return; + } + + Super::illegal_token(tk, p_psm); + } + + void + DExpectQListSsm::on_quoted_literal(obj lit, + ParserStateMachine * p_psm) + { + if(state_.code() == QListXst::code::qlist_1a) { + // append lit at the end of list start_ .. end_ + { + DList * new_last + = DList::_cons(p_psm->expr_alloc(), lit, DList::_nil()); + + if (this->end_) { + end_->assign_rest(new_last); + + this->end_ = new_last; + } else { + this->start_ = DList::_cons(p_psm->expr_alloc(), + lit, + DList::_nil()); + this->end_ = this->start_; + } + } + + // start syntax to receive next literal + DExpectQLiteralSsm::start(p_psm, + true /*cxl_on_rightparen*/); + return; + } + + Super::illegal_quoted_literal(lit, p_psm); + } + + bool + DExpectQListSsm::pretty(const ppindentinfo & ppii) const + { + obj list(start_); + auto list_pr = FacetRegistry::instance().variant(list); + + return ppii.pps()->pretty_struct(ppii, + "DExpectQListSsm", + refrtag("state", state_), + refrtag("expect", this->get_expect_str()), + refrtag("list", list_pr)); + } + } +} + +/* end DExpectQListSsm.cpp */ diff --git a/src/reader2/DExpectQLiteralSsm.cpp b/src/reader2/DExpectQLiteralSsm.cpp index 78c62430..efc92a48 100644 --- a/src/reader2/DExpectQLiteralSsm.cpp +++ b/src/reader2/DExpectQLiteralSsm.cpp @@ -4,6 +4,7 @@ */ #include "ExpectQLiteralSsm.hpp" +#include "ExpectQListSsm.hpp" #include //#include "DExpectFormalArgSsm.hpp" //#include "ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp" @@ -24,31 +25,13 @@ namespace xo { // using xo::reflect::typeseq; namespace scm { -#ifdef NOT_USING - const char * - formalarglstatetype_descr(formalarglstatetype x) { - switch (x) { - case formalarglstatetype::invalid: - return "invalid"; - case formalarglstatetype::argl_0: - return "argl_0"; - case formalarglstatetype::argl_1a: - return "argl_1a"; - case formalarglstatetype::argl_1b: - return "argl_1b"; - case formalarglstatetype::n_formalarglstatetype: - break; - } - - return "?formalarglstatetype"; - } -#endif - - DExpectQLiteralSsm::DExpectQLiteralSsm() + DExpectQLiteralSsm::DExpectQLiteralSsm(bool cxl_on_rightparen) + : cxl_on_rightparen_{cxl_on_rightparen} {} DExpectQLiteralSsm * - DExpectQLiteralSsm::_make(DArena & arena) + DExpectQLiteralSsm::_make(DArena & arena, + bool cxl_on_rightparen) { /* out-of-order so argl follows ssm in arena, * consistent with any subsequent arglist realloc. @@ -57,23 +40,26 @@ namespace xo { void * mem = arena.alloc_for(); - return new (mem) DExpectQLiteralSsm(); + return new (mem) DExpectQLiteralSsm(cxl_on_rightparen); } obj - DExpectQLiteralSsm::make(DArena & arena) + DExpectQLiteralSsm::make(DArena & arena, + bool cxl_on_rightparen) { - obj retval(_make(arena)); - + obj retval(_make(arena, + cxl_on_rightparen)); return retval; } void - DExpectQLiteralSsm::start(ParserStateMachine * p_psm) + DExpectQLiteralSsm::start(ParserStateMachine * p_psm, + bool cxl_on_rightparen) { DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); - p_psm->push_ssm(ckp, DExpectQLiteralSsm::make(p_psm->parser_alloc())); + p_psm->push_ssm(ckp, DExpectQLiteralSsm::make(p_psm->parser_alloc(), + cxl_on_rightparen)); } syntaxstatetype @@ -97,8 +83,14 @@ namespace xo { return; case tokentype::tk_leftparen: - case tokentype::tk_comma: + this->on_leftparen_token(tk, p_psm); + return; + case tokentype::tk_rightparen: + this->on_rightparen_token(tk, p_psm); + return; + + case tokentype::tk_comma: case tokentype::tk_lambda: case tokentype::tk_def: case tokentype::tk_if: @@ -197,21 +189,18 @@ namespace xo { } #endif -#ifdef NOT_YET void DExpectQLiteralSsm::on_leftparen_token(const Token & tk, - ParserStateMachine * p_psm) + ParserStateMachine * p_psm) { - if (fastate_ == formalarglstatetype::argl_0) { - this->fastate_ = formalarglstatetype::argl_1a; + // replace self with specialized version for parsing a literal list - DExpectFormalArgSsm::start(p_psm); - return; - } - - Super::on_token(tk, p_psm); + p_psm->pop_ssm(); + DExpectQListSsm::start(p_psm); + p_psm->on_token(tk); } +#ifdef NOT_YET void DExpectQLiteralSsm::on_comma_token(const Token & tk, ParserStateMachine * p_psm) @@ -225,22 +214,20 @@ namespace xo { Super::on_token(tk, p_psm); } +#endif void DExpectQLiteralSsm::on_rightparen_token(const Token & tk, - ParserStateMachine * p_psm) + ParserStateMachine * p_psm) { - if (fastate_ == formalarglstatetype::argl_1b) { - DArray * args = argl_; - + if (cxl_on_rightparen_) { p_psm->pop_ssm(); - p_psm->on_parsed_formal_arglist(args); + p_psm->on_token(tk); return; } Super::on_token(tk, p_psm); } -#endif bool DExpectQLiteralSsm::pretty(const ppindentinfo & ppii) const diff --git a/src/reader2/IPrintable_DExpectQListSsm.cpp b/src/reader2/IPrintable_DExpectQListSsm.cpp new file mode 100644 index 00000000..c8342703 --- /dev/null +++ b/src/reader2/IPrintable_DExpectQListSsm.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DExpectQListSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DExpectQListSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DExpectQListSsm.json5] +**/ + +#include "ssm/IPrintable_DExpectQListSsm.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DExpectQListSsm::pretty(const DExpectQListSsm & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DExpectQListSsm.cpp */ diff --git a/src/reader2/ISyntaxStateMachine_DExpectQListSsm.cpp b/src/reader2/ISyntaxStateMachine_DExpectQListSsm.cpp new file mode 100644 index 00000000..2d24b697 --- /dev/null +++ b/src/reader2/ISyntaxStateMachine_DExpectQListSsm.cpp @@ -0,0 +1,79 @@ +/** @file ISyntaxStateMachine_DExpectQListSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DExpectQListSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DExpectQListSsm.json5] +**/ + +#include "ssm/ISyntaxStateMachine_DExpectQListSsm.hpp" + +namespace xo { + namespace scm { + auto + ISyntaxStateMachine_DExpectQListSsm::ssm_type(const DExpectQListSsm & self) noexcept -> syntaxstatetype + { + return self.ssm_type(); + } + + auto + ISyntaxStateMachine_DExpectQListSsm::get_expect_str(const DExpectQListSsm & self) noexcept -> std::string_view + { + return self.get_expect_str(); + } + + auto + ISyntaxStateMachine_DExpectQListSsm::on_token(DExpectQListSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectQListSsm::on_parsed_symbol(DExpectQListSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void + { + self.on_parsed_symbol(sym, p_psm); + } + auto + ISyntaxStateMachine_DExpectQListSsm::on_parsed_typedescr(DExpectQListSsm & self, TypeDescr td, ParserStateMachine * p_psm) -> void + { + self.on_parsed_typedescr(td, p_psm); + } + auto + ISyntaxStateMachine_DExpectQListSsm::on_parsed_formal(DExpectQListSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal(param_name, param_type, p_psm); + } + auto + ISyntaxStateMachine_DExpectQListSsm::on_parsed_formal_with_token(DExpectQListSsm & self, const DUniqueString * param_name, TypeDescr param_type, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_with_token(param_name, param_type, tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectQListSsm::on_parsed_formal_arglist(DExpectQListSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_arglist(arglist, p_psm); + } + auto + ISyntaxStateMachine_DExpectQListSsm::on_parsed_expression(DExpectQListSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression(expr, p_psm); + } + auto + ISyntaxStateMachine_DExpectQListSsm::on_parsed_expression_with_token(DExpectQListSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression_with_token(expr, tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectQListSsm::on_quoted_literal(DExpectQListSsm & self, obj lit, ParserStateMachine * p_psm) -> void + { + self.on_quoted_literal(lit, p_psm); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ISyntaxStateMachine_DExpectQListSsm.cpp */ diff --git a/src/reader2/reader2_register_facets.cpp b/src/reader2/reader2_register_facets.cpp index b3fe47be..1df5cb82 100644 --- a/src/reader2/reader2_register_facets.cpp +++ b/src/reader2/reader2_register_facets.cpp @@ -14,14 +14,15 @@ #include "SequenceSsm.hpp" #include "ParenSsm.hpp" #include "QuoteSsm.hpp" +#include "ProgressSsm.hpp" +#include "SyntaxStateMachine.hpp" #include "ExpectFormalArglistSsm.hpp" #include "ExpectFormalArgSsm.hpp" #include "ExpectSymbolSsm.hpp" #include "ExpectTypeSsm.hpp" #include "ExpectExprSsm.hpp" #include "ExpectQLiteralSsm.hpp" -#include "ProgressSsm.hpp" -#include "SyntaxStateMachine.hpp" +#include "ExpectQListSsm.hpp" #include #include @@ -83,6 +84,9 @@ namespace xo { FacetRegistry::register_impl(); FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + // misc types showing up in aux arena TypeRegistry::register_type(); // misc types showing up in parser stack arena @@ -97,6 +101,9 @@ namespace xo { log && log(xtag("DExpectSymbolSsm.tseq", typeseq::id())); log && log(xtag("DExpectTypeSsm.tseq", typeseq::id())); log && log(xtag("DExpectExprSsm.tseq", typeseq::id())); + log && log(xtag("DExpectQLiteralSsm.tseq", typeseq::id())); + log && log(xtag("DExpectQListSsm.tseq", typeseq::id())); + log && log(xtag("DProgressSsm.tseq", typeseq::id())); log && log(xtag("DParenSsm.tseq", typeseq::id())); log && log(xtag("DQuoteSsm.tseq", typeseq::id())); diff --git a/src/reader2/syntaxstatetype.cpp b/src/reader2/syntaxstatetype.cpp index c4eb3667..f1d93239 100644 --- a/src/reader2/syntaxstatetype.cpp +++ b/src/reader2/syntaxstatetype.cpp @@ -43,6 +43,8 @@ namespace xo { return "expect-rhs-expression"; case syntaxstatetype::expect_qliteral: return "expect-qliteral"; + case syntaxstatetype::expect_qlist: + return "expect-qlist"; case syntaxstatetype::N: break; } diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 6637ad9a..17022d42 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -1209,7 +1209,7 @@ namespace xo { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ParserFixture fixture(testname, c_debug_flag); @@ -1244,7 +1244,7 @@ namespace xo { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ParserFixture fixture(testname, c_debug_flag); @@ -1281,6 +1281,44 @@ namespace xo { log && fixture.log_memory_layout(&log); } + TEST_CASE("SchematikaParser-batch-qlist", "[reader2][SchematikaParser]") + { + // top-level recursive function definition + + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); + + parser.begin_interactive_session(); + + /** Walkthrough parsing input equivalent to: + * + * #q{ (4.5 7.2) }; + * ^ ^ ^^ ^ ^ ^^ + * 0 1 2| 4 5 6| + * 3 7 + **/ + + std::vector tk_v{ + /* [ 0] */ Token::quote_token(), + /* [ 1] */ Token::leftbrace_token(), + /* [ 2] */ Token::leftparen_token(), + /* [ 3] */ Token::f64_token("4.5"), + /* [ 4] */ Token::f64_token("7.2"), + /* [ 5] */ Token::rightparen_token(), + /* [ 6] */ Token::rightbrace_token(), + /* [ 7] */ Token::semicolon_token(), + }; + + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + log && fixture.log_memory_layout(&log); + } + } /*namespace ut*/ } /*namespace xo*/