diff --git a/CMakeLists.txt b/CMakeLists.txt index a88c83e0..9c009aab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -321,6 +321,22 @@ xo_add_genfacetimpl( # ---------------------------------------------------------------- +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-syntaxstatemachine-expectqdictssm + FACET_PKG xo_reader2 + INPUT idl/ISyntaxStateMachine_DExpectQDictSsm.json5 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-printable-expectqdictssm + FACET_PKG xo_printable2 + INPUT idl/IPrintable_DExpectQDictSsm.json5 +) + +# ---------------------------------------------------------------- + # note: manual target; generated code committed to git xo_add_genfacetimpl( TARGET xo-reader2-facetimpl-syntaxstatemachine-expectqarrayssm diff --git a/idl/IPrintable_DExpectQDictSsm.json5 b/idl/IPrintable_DExpectQDictSsm.json5 new file mode 100644 index 00000000..0569712d --- /dev/null +++ b/idl/IPrintable_DExpectQDictSsm.json5 @@ -0,0 +1,16 @@ +{ + mode: "implementation", + output_cpp_dir: "src/reader2/facet", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "expect_qdict", + includes: [ "", + "" ], + local_types: [], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DExpectQDictSsm", + using_doxygen: true, + repr: "DExpectQDictSsm", + doc: [ "implement APrintable for DExpectQDictSsm" ], +} diff --git a/idl/ISyntaxStateMachine_DExpectQDictSsm.json5 b/idl/ISyntaxStateMachine_DExpectQDictSsm.json5 new file mode 100644 index 00000000..ee440bcd --- /dev/null +++ b/idl/ISyntaxStateMachine_DExpectQDictSsm.json5 @@ -0,0 +1,16 @@ +{ + mode: "implementation", + output_cpp_dir: "src/reader2/facet", + output_hpp_dir: "include/xo/reader2", + output_impl_subdir: "expect_qdict", + includes: [ "\"SyntaxStateMachine.hpp\"", + "\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/SyntaxStateMachine.json5", + brief: "provide ASyntaxStateMachine interface for DExpectQDictSsm", + using_doxygen: true, + repr: "DExpectQDictSsm", + doc: [ "implement ASyntaxStateMachine for DExpectQDictSsm" ], +} diff --git a/include/xo/reader2/DExpectQListSsm.hpp b/include/xo/reader2/DExpectQListSsm.hpp index 1ccd0bbe..770821bc 100644 --- a/include/xo/reader2/DExpectQListSsm.hpp +++ b/include/xo/reader2/DExpectQListSsm.hpp @@ -7,7 +7,6 @@ #include "DSyntaxStateMachine.hpp" #include -//#include #include namespace xo { @@ -16,13 +15,14 @@ namespace xo { * Already in quoted-literal context * * ( quote-expr ... ) - * ^ ^ ^ - * | qlist_1a qlist_2(done) - * qlist_0 + * ^ ^ ^ ^ + * | qlist_1a | qlist_2(done) + * qlist_0 qlist_1a * * 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] + * qlist_2 end state **/ class QListXst { public: diff --git a/include/xo/reader2/DExpectQLiteralSsm.hpp b/include/xo/reader2/DExpectQLiteralSsm.hpp index 7073283a..6beb3430 100644 --- a/include/xo/reader2/DExpectQLiteralSsm.hpp +++ b/include/xo/reader2/DExpectQLiteralSsm.hpp @@ -6,8 +6,6 @@ #pragma once #include "DSyntaxStateMachine.hpp" -//#include -//#include namespace xo { namespace scm { @@ -46,17 +44,23 @@ namespace xo { static const char * ssm_classname() { return "DExpectQLiteralSsm"; } /** update state for f64 token @p tk, with overall parser state in @p p_psm. - * delegates to parent ssm via @ref on_quoted_literal + * completes syntax + delegates to parent ssm via @ref on_quoted_literal **/ void on_f64_token(const Token & tk, ParserStateMachine * p_psm); /** update state for i64 token @p tk, with overall parser state in @p p_psm. - * delegates to parent ssm via @ref on_quoted_literal + * completes syntax + delegates to parent ssm via @ref on_quoted_literal **/ void on_i64_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for string token @p tk, with overall parser state in @p p_psm. + * completes syntax + delegates to parent ssm via @ref on_quoted_literal + **/ + void on_string_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state on incoming token @p tk, * with overall parser state in @p p_psm. * @@ -89,6 +93,14 @@ namespace xo { void on_rightbracket_token(const Token & tk, ParserStateMachine * p_psm); + /** update state on incoming leftbrace token @p tk, + * with overall parser state in @p p_psm. + * + * Forward in-place to ExpectQDictSsm + **/ + void on_leftbrace_token(const Token & tk, + ParserStateMachine * p_psm); + ///@} /** @defgroup scm-expectformalarglistssm-ssm-facet syntaxstatemachine facet methods **/ ///@{ diff --git a/include/xo/reader2/ExpectQDictSsm.hpp b/include/xo/reader2/ExpectQDictSsm.hpp new file mode 100644 index 00000000..447e5cc7 --- /dev/null +++ b/include/xo/reader2/ExpectQDictSsm.hpp @@ -0,0 +1,12 @@ +/** @file ExpectQDictSsm.hpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#pragma once + +#include "expect_qdict/DExpectQDictSsm.hpp" +#include "expect_qdict/ISyntaxStateMachine_DExpectQDictSsm.hpp" +#include "expect_qdict/IPrintable_DExpectQDictSsm.hpp" + +/* end ExpectQDictSsm.hpp */ diff --git a/include/xo/reader2/expect_qdict/DExpectQDictSsm.hpp b/include/xo/reader2/expect_qdict/DExpectQDictSsm.hpp new file mode 100644 index 00000000..c03b2414 --- /dev/null +++ b/include/xo/reader2/expect_qdict/DExpectQDictSsm.hpp @@ -0,0 +1,178 @@ +/** @file DExpectQDictSsm.hpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#pragma once + +#include "DSyntaxStateMachine.hpp" +#include +#include + +namespace xo { + namespace scm { + /** + * When this syntax is active, parser is already in a quoted-literal context + * + * { key(1) : value(1) ; ... ; } + * ^ ^ ^ ^ ^ ^ ^ ^ + * | | | qdict_1c | | | qdict_2(done) + * | | qdict_1b | | qdict_1d + * | qdict_1a | qdict_1a + * qdict_0 qdict_1d + * + * qdict_0 --on_leftbrace_token()--> qdict_1a [push ExpectSymbolSsm] + * qdict_1a --on_parsed_symbol()--> qdict_1b [remember key] + * qdict_1a --onrightbace_token()--> qdictZ(done) + * qdict_1b --on_colon_token()--> qdict_1c [push ExpectQLiteralSsm] + * qdict_1c --on_quoted_literal()--> qdict_1d [remember value] + * qdict_1d --on_semicolon_token()--> qdict_1a [loop] + * qdict_1d --on_rightbrace_token()--> qdict_2(done) + **/ + class QDictXst { + public: + enum class code { + invalid = -1, + + qdict_0, + qdict_1a, + qdict_1b, + qdict_1c, + qdict_1d, + qdict_2, + + N + }; + + explicit QDictXst(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, QDictXst x) { + os << QDictXst::_descr(x.code_); + return os; + } + + class DExpectQDictSsm : public DSyntaxStateMachine { + public: + using Super = DSyntaxStateMachine; + using DArena = xo::mm::DArena; + using ppindentinfo = xo::print::ppindentinfo; + + public: + /** @defgroup scm-expectqdictssm-ctors constructors **/ + ///@{ + + DExpectQDictSsm(); + + /** create instance using memory from @parser_mm **/ + static obj make(DArena & parser_mm); + /** create instance using memory from @parser_mm **/ + static DExpectQDictSsm * _make(DArena & parser_mm); + + /** start nested syntax for a quoted dictionary **/ + static void start(ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-expectqdictssm-methods general methods **/ + ///@{ + + static const char * ssm_classname() { return "DExpectQDictSsm"; } + + /** update state on incoming leftbrace token @p tk, + * with overall parser state in @p p_psm + * + * in qdict_0 advance state to qdict_1a; otherwise error + **/ + void on_leftbrace_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state on parsed symbol @p sym emitted by nested ssm, + * with overall parser state in @p p_psm + * + * in qdict_1a capture key string + advance to qdict_1b; otherwise error + **/ + void on_symbol_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state on incoming colon token @p tk, + * with overall parser state in @p p_psm + * + * in qdict_1b advance to qdict_1c + push ExpectQLiteralSsm; otherwise error + **/ + void on_colon_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state in on incoming semicolon token @p tk, + * with overall parser state in @p p_psm. + * + * in qdict_1d advance to qdict_1a (ready for another (key,value) pair); otherwise error + **/ + void on_semicolon_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state on incoming rightbrace token @p tk, + * with overall parser state in @p p_psm + * + * in qdict_1a complete syntax + report literal to parent ssm; otherwise error + **/ + void on_rightbrace_token(const Token & tk, + ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-expectqdictssm-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 on quoted literal @p lit, with overall parser state in @p p_psm + * + * in qdict_1c capture (key,value) pair into dictionary + advance to qdict_1d; otherwise error + **/ + void on_quoted_literal(obj lit, + ParserStateMachine * p_psm); + + ///@} + /** @defgroup scm-expectqdictssm-printable-facet printable facet methods **/ + ///@{ + + bool pretty(const ppindentinfo & ppii) const; + + ///@} + + private: + /** @defgroup ssm-expectqdictssm-member-vars **/ + ///@{ + + /** iddentifies qdict parsing state **/ + QDictXst state_; + + /** captured key in next (key,value) pair; + * expect to include in @ref dict_ + **/ + const DString * key_ = nullptr; + + /** literal dictionary (assembled incrementally) **/ + DDictionary * dict_ = nullptr; + + ///@} + }; + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DExpectQDictSsm.hpp */ diff --git a/include/xo/reader2/expect_qdict/IPrintable_DExpectQDictSsm.hpp b/include/xo/reader2/expect_qdict/IPrintable_DExpectQDictSsm.hpp new file mode 100644 index 00000000..b5bb39d9 --- /dev/null +++ b/include/xo/reader2/expect_qdict/IPrintable_DExpectQDictSsm.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DExpectQDictSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DExpectQDictSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DExpectQDictSsm.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DExpectQDictSsm.hpp" + +namespace xo { namespace scm { class IPrintable_DExpectQDictSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DExpectQDictSsm + **/ + class IPrintable_DExpectQDictSsm { + public: + /** @defgroup scm-printable-dexpectqdictssm-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-dexpectqdictssm-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DExpectQDictSsm & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/reader2/expect_qdict/ISyntaxStateMachine_DExpectQDictSsm.hpp b/include/xo/reader2/expect_qdict/ISyntaxStateMachine_DExpectQDictSsm.hpp new file mode 100644 index 00000000..5c46cdd9 --- /dev/null +++ b/include/xo/reader2/expect_qdict/ISyntaxStateMachine_DExpectQDictSsm.hpp @@ -0,0 +1,84 @@ +/** @file ISyntaxStateMachine_DExpectQDictSsm.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DExpectQDictSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DExpectQDictSsm.json5] + **/ + +#pragma once + +#include "SyntaxStateMachine.hpp" +#include "SyntaxStateMachine.hpp" +#include "ssm/ISyntaxStateMachine_Xfer.hpp" +#include "DExpectQDictSsm.hpp" + +namespace xo { namespace scm { class ISyntaxStateMachine_DExpectQDictSsm; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::ISyntaxStateMachine_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class ISyntaxStateMachine_DExpectQDictSsm + **/ + class ISyntaxStateMachine_DExpectQDictSsm { + public: + /** @defgroup scm-syntaxstatemachine-dexpectqdictssm-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-dexpectqdictssm-methods **/ + ///@{ + // const methods + /** identify a type of syntax state machine **/ + static syntaxstatetype ssm_type(const DExpectQDictSsm & self) noexcept; + /** text describing expected/allowed input to this ssm in current state **/ + static std::string_view get_expect_str(const DExpectQDictSsm & self) noexcept; + + // non-const methods + /** operate state machine for incoming token @p tk **/ + static void on_token(DExpectQDictSsm & self, const Token & tk, ParserStateMachine * p_psm); + /** update stat machine for incoming parsed symbol @p sym **/ + static void on_parsed_symbol(DExpectQDictSsm & self, std::string_view sym, ParserStateMachine * p_psm); + /** operate state machine for incoming type description @p td **/ + static void on_parsed_typedescr(DExpectQDictSsm & self, TypeDescr td, ParserStateMachine * p_psm); + /** update state machine for type emitted by nested ssm **/ + static void on_parsed_type(DExpectQDictSsm & self, obj type, ParserStateMachine * p_psm); + /** operate state machine for formal emitted by nested ssm **/ + static void on_parsed_formal(DExpectQDictSsm & 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(DExpectQDictSsm & 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(DExpectQDictSsm & self, DArray * arglist, ParserStateMachine * p_psm); + /** update state machine for nested parsed expression @p expr **/ + static void on_parsed_expression(DExpectQDictSsm & 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(DExpectQDictSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm); + /** update state machine for nested quoted literal @p lit **/ + static void on_quoted_literal(DExpectQDictSsm & 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 dd34054a..c1dbfae6 100644 --- a/include/xo/reader2/syntaxstatetype.hpp +++ b/include/xo/reader2/syntaxstatetype.hpp @@ -75,6 +75,9 @@ namespace xo { /** expecting a quoted array. See @ref DExpectQArraySsm **/ expect_qarray, + /** expecting a quoted dictionary. See @ref DExpectQDictSsm **/ + expect_qdict, + /** comes last, counts number of valid enums **/ N }; diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index dd88bbd6..73e9ea37 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -88,6 +88,10 @@ set(SELF_SRCS ISyntaxStateMachine_DExpectQArraySsm.cpp IPrintable_DExpectQArraySsm.cpp + DExpectQDictSsm.cpp + facet/ISyntaxStateMachine_DExpectQDictSsm.cpp + facet/IPrintable_DExpectQDictSsm.cpp + DProgressSsm.cpp ISyntaxStateMachine_DProgressSsm.cpp IPrintable_DProgressSsm.cpp @@ -107,8 +111,6 @@ xo_dependency(${SELF_LIB} xo_type) xo_dependency(${SELF_LIB} xo_tokenizer2) xo_dependency(${SELF_LIB} xo_expression2) #xo_dependency(${SELF_LIB} reflect) -#xo_dependency(${SELF_LIB} xo_object2) -#xo_dependency(${SELF_LIB} xo_printable2) #xo_dependency(${SELF_LIB} xo_flatstring) xo_dependency(${SELF_LIB} subsys) #xo_dependency(${SELF_LIB} indentlog) diff --git a/src/reader2/DExpectQDictSsm.cpp b/src/reader2/DExpectQDictSsm.cpp new file mode 100644 index 00000000..7566c130 --- /dev/null +++ b/src/reader2/DExpectQDictSsm.cpp @@ -0,0 +1,270 @@ +/** @file DExpectQDictSsm.cpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#include "ExpectQDictSsm.hpp" +#include "ExpectQLiteralSsm.hpp" + +namespace xo { + using xo::print::APrintable; + + namespace scm { + + const char * + QDictXst::_descr(enum code x) + { + switch (x) { + case code::invalid: break; + case code::qdict_0: return "qdict_0"; + case code::qdict_1a: return "qdict_1a"; + case code::qdict_1b: return "qdict_1b"; + case code::qdict_1c: return "qdict_1c"; + case code::qdict_1d: return "qdict_1d"; + case code::qdict_2: return "qdict_2"; + case code::N: break; + } + + return "?QDictXst"; + } + + DExpectQDictSsm::DExpectQDictSsm() : state_{QDictXst::code::qdict_0} {} + + obj + DExpectQDictSsm::make(DArena & parser_mm) + { + return obj(_make(parser_mm)); + } + + DExpectQDictSsm * + DExpectQDictSsm::_make(DArena & parser_mm) + { + void * mem = parser_mm.alloc_for(); + + return new (mem) DExpectQDictSsm(); + } + + void + DExpectQDictSsm::start(ParserStateMachine * p_psm) + { + DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); + + p_psm->push_ssm(ckp, DExpectQDictSsm::make(p_psm->parser_alloc())); + } + + syntaxstatetype + DExpectQDictSsm::ssm_type() const noexcept { + return syntaxstatetype::expect_qdict; + } + + std::string_view + DExpectQDictSsm::get_expect_str() const { + switch (state_.code()) { + case QDictXst::code::qdict_0: + return "leftbrace"; + case QDictXst::code::qdict_1a: + return "symbol|rightbrace"; + case QDictXst::code::qdict_1b: + return "colon"; + case QDictXst::code::qdict_1c: + return "literal"; + case QDictXst::code::qdict_1d: + return "semicolon|rightbrace"; + case QDictXst::code::qdict_2: + return "(done)"; + case QDictXst::code::invalid: + case QDictXst::code::N: + break; + } + + return "?DExpectQDictSsm"; + } + + void + DExpectQDictSsm::on_leftbrace_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (state_.code() == QDictXst::code::qdict_0) { + constexpr DDictionary::size_type hint_cap = 8; + + this->state_ = QDictXst(QDictXst::code::qdict_1a); + this->dict_ = DDictionary::empty(p_psm->expr_alloc(), hint_cap); + + return; + } + + Super::illegal_token(tk, p_psm); + } + + void + DExpectQDictSsm::on_rightbrace_token(const Token & tk, + ParserStateMachine * p_psm) + { + if ((state_.code() == QDictXst::code::qdict_1a) + || (state_.code() == QDictXst::code::qdict_1d)) + { + + this->state_ = QDictXst(QDictXst::code::qdict_2); + + obj lit = obj(dict_); + + p_psm->pop_ssm(); + p_psm->on_quoted_literal(lit); + return; + } + + Super::illegal_token(tk, p_psm); + } + + void + DExpectQDictSsm::on_symbol_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (state_.code() == QDictXst::code::qdict_1a) { + this->state_ = QDictXst(QDictXst::code::qdict_1b); + this->key_ = DString::from_view(p_psm->expr_alloc(), std::string_view(tk.text())); + return; + } + + Super::illegal_token(tk, p_psm); + } + + void + DExpectQDictSsm::on_colon_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (state_.code() == QDictXst::code::qdict_1b) { + this->state_ = QDictXst(QDictXst::code::qdict_1c); + + DExpectQLiteralSsm::start(p_psm, + false /*!cxl_on_rightparen*/); + return; + } + + Super::illegal_token(tk, p_psm); + } + + void + DExpectQDictSsm::on_semicolon_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (state_.code() == QDictXst::code::qdict_1d) { + this->state_ = QDictXst(QDictXst::code::qdict_1a); + return; + } + + Super::illegal_token(tk, p_psm); + } + + void + DExpectQDictSsm::on_token(const Token & tk, + ParserStateMachine * p_psm) + { + switch(tk.tk_type()) + { + case tokentype::tk_leftbrace: + this->on_leftbrace_token(tk, p_psm); + return; + + case tokentype::tk_symbol: + this->on_symbol_token(tk, p_psm); + return; + + case tokentype::tk_rightbrace: + this->on_rightbrace_token(tk, p_psm); + return; + + case tokentype::tk_colon: + this->on_colon_token(tk, p_psm); + return; + + case tokentype::tk_semicolon: + this->on_semicolon_token(tk, p_psm); + return; + + case tokentype::tk_rightparen: + case tokentype::tk_comma: + case tokentype::tk_lambda: + case tokentype::tk_def: + case tokentype::tk_deftype: + case tokentype::tk_if: + case tokentype::tk_singleassign: + case tokentype::tk_string: + case tokentype::tk_f64: + case tokentype::tk_i64: + case tokentype::tk_bool: + case tokentype::tk_invalid: + case tokentype::tk_quote: + case tokentype::tk_leftparen: + case tokentype::tk_leftbracket: + case tokentype::tk_rightbracket: + case tokentype::tk_leftangle: + case tokentype::tk_rightangle: + case tokentype::tk_cmple: + case tokentype::tk_cmpge: + 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_nil: + 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::illegal_token(tk, p_psm); + } + + void + DExpectQDictSsm::on_quoted_literal(obj lit, + ParserStateMachine * p_psm) + { + if (state_.code() == QDictXst::code::qdict_1c) { + // adjoin (key,value) pair into dictionary + + this->state_ = QDictXst(QDictXst::code::qdict_1d); + + assert(dict_); + + bool ok = dict_->upsert(p_psm->expr_alloc(), DDictionary::pair_type(key_, lit)); + + this->key_ = nullptr; + + assert(ok); + + return; + } + + Super::illegal_quoted_literal(lit, p_psm); + } + + bool + DExpectQDictSsm::pretty(const ppindentinfo & ppii) const + { + obj dict(dict_); + obj dict_pr(dict_); + + return ppii.pps()->pretty_struct(ppii, + "DExpectQDictSsm", + refrtag("state", state_), + refrtag("expect", this->get_expect_str()), + refrtag("key", key_, key_), + refrtag("dict", dict_pr)); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DExpectQDictSsm.cpp */ diff --git a/src/reader2/DExpectQListSsm.cpp b/src/reader2/DExpectQListSsm.cpp index 50cde338..b767f939 100644 --- a/src/reader2/DExpectQListSsm.cpp +++ b/src/reader2/DExpectQListSsm.cpp @@ -132,6 +132,8 @@ namespace xo { case tokentype::N: break; } + + Super::illegal_token(tk, p_psm); } void diff --git a/src/reader2/DExpectQLiteralSsm.cpp b/src/reader2/DExpectQLiteralSsm.cpp index 89e79b85..a1b7b2ce 100644 --- a/src/reader2/DExpectQLiteralSsm.cpp +++ b/src/reader2/DExpectQLiteralSsm.cpp @@ -6,14 +6,10 @@ #include "ExpectQLiteralSsm.hpp" #include "ExpectQListSsm.hpp" #include "ExpectQArraySsm.hpp" +#include "ExpectQDictSsm.hpp" #include #include -//#include "ssm/ISyntaxStateMachine_DExpectFormalArgSsm.hpp" -//#include -//#include -//#include -//#include -//#include +#include #include namespace xo { @@ -95,6 +91,10 @@ namespace xo { this->on_i64_token(tk, p_psm); return; + case tokentype::tk_string: + this->on_string_token(tk, p_psm); + return; + case tokentype::tk_leftparen: this->on_leftparen_token(tk, p_psm); return; @@ -111,6 +111,10 @@ namespace xo { this->on_rightbracket_token(tk, p_psm); return; + case tokentype::tk_leftbrace: + this->on_leftbrace_token(tk, p_psm); + return; + case tokentype::tk_comma: case tokentype::tk_lambda: case tokentype::tk_def: @@ -119,12 +123,10 @@ namespace xo { case tokentype::tk_symbol: case tokentype::tk_colon: case tokentype::tk_singleassign: - case tokentype::tk_string: case tokentype::tk_bool: case tokentype::tk_semicolon: case tokentype::tk_invalid: case tokentype::tk_quote: - case tokentype::tk_leftbrace: case tokentype::tk_rightbrace: case tokentype::tk_leftangle: case tokentype::tk_rightangle: @@ -176,49 +178,16 @@ namespace xo { p_psm->on_quoted_literal(literal); } -#ifdef NOT_YET void - DExpectQLiteralSsm::_accept_formal(obj expr_alloc, - DArena & parser_alloc, - const DUniqueString * param_name, - TypeDescr param_type) + DExpectQLiteralSsm::on_string_token(const Token & tk, + ParserStateMachine * p_psm) { - /* note: param_type can be nullptr */ - TypeRef typeref - = TypeRef::dwim(TypeRef::prefix_type::from_chars("formal"), param_type); + auto literal = obj(DString::from_view(p_psm->expr_alloc(), + std::string_view(tk.text()))); - 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 DExpectQLiteralSsm 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); + p_psm->pop_ssm(); + p_psm->on_quoted_literal(literal); } -#endif void DExpectQLiteralSsm::on_leftparen_token(const Token & tk, @@ -268,6 +237,17 @@ namespace xo { Super::illegal_token(tk, p_psm); } + void + DExpectQLiteralSsm::on_leftbrace_token(const Token & tk, + ParserStateMachine * p_psm) + { + // replace self with specialized version for parsing a literal dict + + p_psm->pop_ssm(); + DExpectQDictSsm::start(p_psm); + p_psm->on_token(tk); + } + bool DExpectQLiteralSsm::pretty(const ppindentinfo & ppii) const { diff --git a/src/reader2/SetupReader2.cpp b/src/reader2/SetupReader2.cpp index eef64bab..62536329 100644 --- a/src/reader2/SetupReader2.cpp +++ b/src/reader2/SetupReader2.cpp @@ -25,6 +25,7 @@ #include "ExpectExprSsm.hpp" #include "ExpectQLiteralSsm.hpp" #include "ExpectQListSsm.hpp" +#include "ExpectQDictSsm.hpp" #include "ExpectQArraySsm.hpp" #include @@ -107,6 +108,9 @@ namespace xo { FacetRegistry::register_impl(); FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); FacetRegistry::register_impl(); @@ -128,6 +132,7 @@ namespace xo { log && log(xtag("DExpectExprSsm.tseq", typeseq::id())); log && log(xtag("DExpectQLiteralSsm.tseq", typeseq::id())); log && log(xtag("DExpectQListSsm.tseq", typeseq::id())); + log && log(xtag("DExpectQDictSsm.tseq", typeseq::id())); log && log(xtag("DExpectQArraySsm.tseq", typeseq::id())); log && log(xtag("DProgressSsm.tseq", typeseq::id())); diff --git a/src/reader2/facet/IPrintable_DExpectQDictSsm.cpp b/src/reader2/facet/IPrintable_DExpectQDictSsm.cpp new file mode 100644 index 00000000..ae6f4423 --- /dev/null +++ b/src/reader2/facet/IPrintable_DExpectQDictSsm.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DExpectQDictSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DExpectQDictSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DExpectQDictSsm.json5] +**/ + +#include "expect_qdict/IPrintable_DExpectQDictSsm.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DExpectQDictSsm::pretty(const DExpectQDictSsm & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DExpectQDictSsm.cpp */ diff --git a/src/reader2/facet/ISyntaxStateMachine_DExpectQDictSsm.cpp b/src/reader2/facet/ISyntaxStateMachine_DExpectQDictSsm.cpp new file mode 100644 index 00000000..60ec4af4 --- /dev/null +++ b/src/reader2/facet/ISyntaxStateMachine_DExpectQDictSsm.cpp @@ -0,0 +1,84 @@ +/** @file ISyntaxStateMachine_DExpectQDictSsm.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISyntaxStateMachine_DExpectQDictSsm.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/ISyntaxStateMachine_DExpectQDictSsm.json5] +**/ + +#include "expect_qdict/ISyntaxStateMachine_DExpectQDictSsm.hpp" + +namespace xo { + namespace scm { + auto + ISyntaxStateMachine_DExpectQDictSsm::ssm_type(const DExpectQDictSsm & self) noexcept -> syntaxstatetype + { + return self.ssm_type(); + } + + auto + ISyntaxStateMachine_DExpectQDictSsm::get_expect_str(const DExpectQDictSsm & self) noexcept -> std::string_view + { + return self.get_expect_str(); + } + + auto + ISyntaxStateMachine_DExpectQDictSsm::on_token(DExpectQDictSsm & self, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectQDictSsm::on_parsed_symbol(DExpectQDictSsm & self, std::string_view sym, ParserStateMachine * p_psm) -> void + { + self.on_parsed_symbol(sym, p_psm); + } + auto + ISyntaxStateMachine_DExpectQDictSsm::on_parsed_typedescr(DExpectQDictSsm & self, TypeDescr td, ParserStateMachine * p_psm) -> void + { + self.on_parsed_typedescr(td, p_psm); + } + auto + ISyntaxStateMachine_DExpectQDictSsm::on_parsed_type(DExpectQDictSsm & self, obj type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_type(type, p_psm); + } + auto + ISyntaxStateMachine_DExpectQDictSsm::on_parsed_formal(DExpectQDictSsm & self, const DUniqueString * param_name, TypeDescr param_type, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal(param_name, param_type, p_psm); + } + auto + ISyntaxStateMachine_DExpectQDictSsm::on_parsed_formal_with_token(DExpectQDictSsm & 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_DExpectQDictSsm::on_parsed_formal_arglist(DExpectQDictSsm & self, DArray * arglist, ParserStateMachine * p_psm) -> void + { + self.on_parsed_formal_arglist(arglist, p_psm); + } + auto + ISyntaxStateMachine_DExpectQDictSsm::on_parsed_expression(DExpectQDictSsm & self, obj expr, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression(expr, p_psm); + } + auto + ISyntaxStateMachine_DExpectQDictSsm::on_parsed_expression_with_token(DExpectQDictSsm & self, obj expr, const Token & tk, ParserStateMachine * p_psm) -> void + { + self.on_parsed_expression_with_token(expr, tk, p_psm); + } + auto + ISyntaxStateMachine_DExpectQDictSsm::on_quoted_literal(DExpectQDictSsm & self, obj lit, ParserStateMachine * p_psm) -> void + { + self.on_quoted_literal(lit, p_psm); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ISyntaxStateMachine_DExpectQDictSsm.cpp */ diff --git a/src/reader2/syntaxstatetype.cpp b/src/reader2/syntaxstatetype.cpp index 5968b1bb..8ca07af2 100644 --- a/src/reader2/syntaxstatetype.cpp +++ b/src/reader2/syntaxstatetype.cpp @@ -51,6 +51,8 @@ namespace xo { return "expect-qlist"; case syntaxstatetype::expect_qarray: return "expect-qarray"; + case syntaxstatetype::expect_qdict: + return "expect-qdict"; case syntaxstatetype::N: break; } diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 4d3f943b..23821872 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -1609,6 +1609,96 @@ namespace xo { log && fixture.log_memory_layout(&log); } + TEST_CASE("SchematikaParser-batch-qdict0", "[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{ {} }; + * ^ ^ ^^ ^^ + * 0 1 2| 4| + * 3 5 + **/ + + std::vector tk_v{ + /* [ 0] */ Token::quote_token(), + /* [ 1] */ Token::leftbrace_token(), + + /* [ 2] */ Token::leftbrace_token(), + /* [ 3] */ Token::rightbrace_token(), + + /* [ 4] */ Token::rightbrace_token(), + /* [ 5] */ Token::semicolon_token(), + }; + + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + log && fixture.log_memory_layout(&log); + } + + TEST_CASE("SchematikaParser-batch-qdict1", "[reader2][SchematikaParser]") + { + // top-level recursive function definition + + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = false; + 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{ {name: "kobold"; alignment: "chaotic evil"; hp: 15} }; + * ^ ^ ^^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^^ + * 0 1 2| 4 5 6 7 8 9 a b c d e f| + * 3 g + **/ + + std::vector tk_v{ + /* [ 0] */ Token::quote_token(), + /* [ 1] */ Token::leftbrace_token(), + + /* [ 2] */ Token::leftbrace_token(), + + /* [ 3] */ Token::symbol_token("name"), + /* [ 4] */ Token::colon_token(), + /* [ 5] */ Token::string_token("kobold"), + /* [ 6] */ Token::semicolon_token(), + + /* [ 7] */ Token::symbol_token("alignment"), + /* [ 8] */ Token::colon_token(), + /* [ 9] */ Token::string_token("chaotic evil"), + /* [ a] */ Token::semicolon_token(), + + /* [ b] */ Token::symbol_token("hp"), + /* [ c] */ Token::colon_token(), + /* [ d] */ Token::i64_token("15"), + + /* [ e] */ Token::rightbrace_token(), + /* [ f] */ Token::rightbrace_token(), + /* [ g] */ Token::semicolon_token(), + }; + + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + log && fixture.log_memory_layout(&log); + } + } /*namespace ut*/ } /*namespace xo*/