diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f3a4520..a00bc2c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,18 @@ xo_add_genfacetimpl( OUTPUT_CPP_DIR src/reader2 ) +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-reader2-facetimpl-syntaxstatemachine-definessm + FACET_PKG xo_reader2 + FACET SyntaxStateMachine + REPR DefineSsm + INPUT idl/ISyntaxStateMachine_DDefineSsm.json5 + OUTPUT_HPP_DIR include/xo/reader2 + OUTPUT_IMPL_SUBDIR ssm + OUTPUT_CPP_DIR src/reader2 +) + # ---------------------------------------------------------------- # shared library diff --git a/idl/SyntaxStateMachine.json5 b/idl/SyntaxStateMachine.json5 index 0023a16e..f2058e9d 100644 --- a/idl/SyntaxStateMachine.json5 +++ b/idl/SyntaxStateMachine.json5 @@ -43,6 +43,15 @@ }, ], nonconst_methods: [ + { + name: "on_def_token", + doc: ["update state machine for incoming define-keyworkd-token @p tk"], + return_type: "void", + args: [ + {type: "const Token &", name: "tk"}, + {type: "ParserStateMachine *", name: "ps_psm"}, + ], + }, { name: "on_if_token", doc: ["update state machine for incoming if-keyword-token @p tk"], diff --git a/include/xo/reader2/DDefineSsm.hpp b/include/xo/reader2/DDefineSsm.hpp index 10ec3097..3a34d0a3 100644 --- a/include/xo/reader2/DDefineSsm.hpp +++ b/include/xo/reader2/DDefineSsm.hpp @@ -3,6 +3,8 @@ * @author Roland Conybeare, Jan 2026 **/ +#pragma once + #include "ParserStateMachine.hpp" #include "SyntaxStateMachine.hpp" #include "syntaxstatetype.hpp" @@ -67,8 +69,24 @@ namespace xo { **/ class DDefineSsm { public: + using DArena = xo::mm::DArena; public: + /** @defgroup scm-define-ssm-facet constructors **/ + ///@{ + + DDefineSsm(); + + /** create instance using memory from @p parser_mm **/ + static DDefineSsm * make(DArena & parser_mm); + + /** start nested parser for a define-expression, + * on top of parser state machine @p p_psm + **/ + static void start(DArena & parser_mm, + ParserStateMachine * p_psm); + + ///@} /** @defgroup scm-define-ssm-facet syntaxstatemachine facet methods **/ ///@{ @@ -83,7 +101,14 @@ namespace xo { /** update state for this syntax on incoming token @p tk, * overall parser state in @p p_psm **/ - void on_if_token(const Token & tk, ParserStateMachine * p_psm); + void on_def_token(const Token & tk, + ParserStateMachine * p_psm); + + /** update state for this syntax on incoming token @p tk, + * overall parser state in @p p_psm + **/ + void on_if_token(const Token & tk, + ParserStateMachine * p_psm); ///@} diff --git a/include/xo/reader2/DExprSeqState.hpp b/include/xo/reader2/DExprSeqState.hpp index f081691a..c0e0d8af 100644 --- a/include/xo/reader2/DExprSeqState.hpp +++ b/include/xo/reader2/DExprSeqState.hpp @@ -56,6 +56,11 @@ namespace xo { **/ std::string_view get_expect_str() const noexcept; + /** update state for this syntax on incoming token @p tk, + * overall parser state in @p p_psm + **/ + void on_def_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming token @p tk, * overall parser state in @p p_psm **/ diff --git a/include/xo/reader2/ParserResult.hpp b/include/xo/reader2/ParserResult.hpp index 3aadbdae..e179d4bd 100644 --- a/include/xo/reader2/ParserResult.hpp +++ b/include/xo/reader2/ParserResult.hpp @@ -40,6 +40,10 @@ namespace xo { obj result_expr() const { return result_expr_; } const DString * error_description() const { return error_description_; } + bool is_incomplete() const { return result_type_ == parser_result_type::none; } + bool is_expression() const { return result_type_ == parser_result_type::expression; } + bool is_error() const { return result_type_ == parser_result_type::error; } + private: parser_result_type result_type_ = parser_result_type::none; obj result_expr_; diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index 466e07f8..63d761c0 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -53,6 +53,9 @@ namespace xo { /** @defgroup scm-parserstatemachine-bookkeeping bookkeeping methods **/ ///@{ + /** allocator for parsing stack and ssm's **/ + DArena & parser_alloc() noexcept { return parser_alloc_; } + /** establish toplevel @p ssm. Must have empty stack **/ void establish_toplevel_ssm(obj ssm); @@ -75,6 +78,9 @@ namespace xo { **/ void on_token(const Token & tk); + /** update state for incoming define-token @p tk **/ + void on_def_token(const Token & tk); + /** update state for incoming if-token @p tk **/ void on_if_token(const Token & tk); diff --git a/include/xo/reader2/SchematikaParser.hpp b/include/xo/reader2/SchematikaParser.hpp index b0f78bff..075fb4fc 100644 --- a/include/xo/reader2/SchematikaParser.hpp +++ b/include/xo/reader2/SchematikaParser.hpp @@ -190,7 +190,7 @@ namespace xo { /** put parser into state for beginning of a translation unit * (i.e. input stream) **/ - void begin_translation_unit(); + void begin_batch_session(); /** include next token @p tk and increment parser state. * diff --git a/include/xo/reader2/SyntaxStateMachine.hpp b/include/xo/reader2/SyntaxStateMachine.hpp index deda9e1d..56a8271b 100644 --- a/include/xo/reader2/SyntaxStateMachine.hpp +++ b/include/xo/reader2/SyntaxStateMachine.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] * arguments: * --input [idl/SyntaxStateMachine.json5] * 2. jinja2 template for facet .hpp file: diff --git a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp index a519b246..a6586263 100644 --- a/include/xo/reader2/ssm/ASyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/ASyntaxStateMachine.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] * arguments: * --input [idl/SyntaxStateMachine.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -54,6 +54,8 @@ public: virtual std::string_view get_expect_str(Copaque data) const noexcept = 0; // nonconst methods + /** update state machine for incoming define-keyworkd-token @p tk **/ + virtual void on_def_token(Opaque data, const Token & tk, ParserStateMachine * ps_psm) = 0; /** update state machine for incoming if-keyword-token @p tk **/ virtual void on_if_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) = 0; ///@} diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp index 2d5dd0c3..35efd49e 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Any.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] * arguments: * --input [idl/SyntaxStateMachine.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -59,6 +59,7 @@ namespace scm { [[noreturn]] std::string_view get_expect_str(Copaque) const noexcept override { _fatal(); } // nonconst methods + [[noreturn]] void on_def_token(Opaque, const Token &, ParserStateMachine *) override; [[noreturn]] void on_if_token(Opaque, const Token &, ParserStateMachine *) override; ///@} diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp index b1d889b1..c3a540a8 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_DExprSeqState.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] * arguments: * --input [idl/ISyntaxStateMachine_DExprSeqState.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -53,6 +53,8 @@ namespace xo { static std::string_view get_expect_str(const DExprSeqState & self) noexcept; // non-const methods + /** update state machine for incoming define-keyworkd-token @p tk **/ + static void on_def_token(DExprSeqState & self, const Token & tk, ParserStateMachine * ps_psm); /** update state machine for incoming if-keyword-token @p tk **/ static void on_if_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm); ///@} diff --git a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp index c3aec83e..ad48c7af 100644 --- a/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp +++ b/include/xo/reader2/ssm/ISyntaxStateMachine_Xfer.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] * arguments: * --input [idl/SyntaxStateMachine.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -50,6 +50,9 @@ namespace scm { } // non-const methods + void on_def_token(Opaque data, const Token & tk, ParserStateMachine * ps_psm) override { + return I::on_def_token(_dcast(data), tk, ps_psm); + } void on_if_token(Opaque data, const Token & tk, ParserStateMachine * p_psm) override { return I::on_if_token(_dcast(data), tk, p_psm); } diff --git a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp index 5f920614..8841e242 100644 --- a/include/xo/reader2/ssm/RSyntaxStateMachine.hpp +++ b/include/xo/reader2/ssm/RSyntaxStateMachine.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] * arguments: * --input [idl/SyntaxStateMachine.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -55,6 +55,9 @@ public: } // non-const methods (still const in router!) + void on_def_token(const Token & tk, ParserStateMachine * ps_psm) { + return O::iface()->on_def_token(O::data(), tk, ps_psm); + } void on_if_token(const Token & tk, ParserStateMachine * p_psm) { return O::iface()->on_if_token(O::data(), tk, p_psm); } diff --git a/src/reader2/CMakeLists.txt b/src/reader2/CMakeLists.txt index ff8eb418..290f75cc 100644 --- a/src/reader2/CMakeLists.txt +++ b/src/reader2/CMakeLists.txt @@ -15,6 +15,7 @@ set(SELF_SRCS ISyntaxStateMachine_DExprSeqState.cpp DDefineSsm.cpp + ISyntaxStateMachine_DDefineSsm.cpp reader2_register_facets.cpp reader2_register_types.cpp diff --git a/src/reader2/DDefineSsm.cpp b/src/reader2/DDefineSsm.cpp index 609ec0db..87d1af35 100644 --- a/src/reader2/DDefineSsm.cpp +++ b/src/reader2/DDefineSsm.cpp @@ -4,6 +4,8 @@ **/ #include "DDefineSsm.hpp" +#include "ssm/ISyntaxStateMachine_DDefineSsm.hpp" + #ifdef NOT_YET #include "parserstatemachine.hpp" #include "expect_symbol_xs.hpp" @@ -13,6 +15,9 @@ #endif namespace xo { + using xo::facet::with_facet; + using xo::facet::typeseq; + namespace scm { // ----- defexprstatetype ----- @@ -46,16 +51,11 @@ namespace xo { define_xs::make() { return std::make_unique(define_xs(DefineExprAccess::make_empty())); } +#endif - void - define_xs::start(parserstatemachine * p_psm) - { - scope log(XO_DEBUG(p_psm->debug_flag())); - - p_psm->push_exprstate(define_xs::make()); - p_psm->top_exprstate().on_def_token(token_type::def(), p_psm); - } + // DDefineSsm::start +#ifdef NOT_YET define_xs::define_xs(rp def_expr) : exprstate(exprstatetype::defexpr), defxs_type_{defexprstatetype::def_0}, @@ -333,6 +333,36 @@ namespace xo { //////////////////////////////////////////////////////////////// + DDefineSsm::DDefineSsm() + : defstate_{defexprstatetype::def_0} + {} + + DDefineSsm * + DDefineSsm::make(DArena & mm) + { + void * mem = mm.alloc(typeseq::id(), + sizeof(DDefineSsm)); + + return new (mem) DDefineSsm(); + } + + void + DDefineSsm::start(DArena & mm, + ParserStateMachine * p_psm) + { + //scope log(XO_DEBUG(p_psm->debug_flag())); + + assert(p_psm->stack()); + + DDefineSsm * define_ssm = DDefineSsm::make(mm); + + obj ssm + = with_facet::mkobj(define_ssm); + + p_psm->push_ssm(ssm); + p_psm->on_def_token(Token::def_token()); + } + syntaxstatetype DDefineSsm::ssm_type() const noexcept { @@ -380,6 +410,21 @@ namespace xo { return "?expect"; } + void + DDefineSsm::on_def_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (this->defstate_ == defexprstatetype::def_0) { + this->defstate_ = defexprstatetype::def_1; + + // expect_symbol_xs::start(p_psm->parser_alloc(), p_psm); + } + + p_psm->illegal_input_on_token("DDefineSsm::on_define_token", + tk, + this->get_expect_str()); + } + void DDefineSsm::on_if_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/src/reader2/DExprSeqState.cpp b/src/reader2/DExprSeqState.cpp index 4d6ae613..2922dd7f 100644 --- a/src/reader2/DExprSeqState.cpp +++ b/src/reader2/DExprSeqState.cpp @@ -4,6 +4,7 @@ **/ #include "DExprSeqState.hpp" +#include "DDefineSsm.hpp" #include "ssm/ISyntaxStateMachine_DExprSeqState.hpp" namespace xo { @@ -73,13 +74,30 @@ namespace xo { return "impossible-DExprSeqState::get_expr_str"; } + void + DExprSeqState::on_def_token(const Token & tk, + ParserStateMachine * p_psm) + { + (void)tk; + + DDefineSsm::start(p_psm->parser_alloc(), p_psm); + + /* keyword 'def' introduces a definition: + * def pi : f64 = 3.14159265 + * def sq(x : f64) -> f64 { (x * x) } + */ + } + void DExprSeqState::on_if_token(const Token & tk, ParserStateMachine * p_psm) { switch (seqtype_) { case exprseqtype::toplevel_interactive: - assert(false); // DfElseState::start(p_psm); + p_psm->illegal_input_on_token("DExprSeqState::on_if_token", + tk, + this->get_expect_str()); + //assert(false); // DfElseState::start(p_psm); break; case exprseqtype::toplevel_batch: p_psm->illegal_input_on_token("DExprSeqState::on_if_token", diff --git a/src/reader2/ISyntaxStateMachine_Any.cpp b/src/reader2/ISyntaxStateMachine_Any.cpp index 8c4c0b42..ce85a9e0 100644 --- a/src/reader2/ISyntaxStateMachine_Any.cpp +++ b/src/reader2/ISyntaxStateMachine_Any.cpp @@ -34,6 +34,12 @@ ISyntaxStateMachine_Any::_valid // nonconst methods +auto +ISyntaxStateMachine_Any::on_def_token(Opaque, const Token &, ParserStateMachine *) -> void +{ + _fatal(); +} + auto ISyntaxStateMachine_Any::on_if_token(Opaque, const Token &, ParserStateMachine *) -> void { diff --git a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp index 87f4f2d8..a3abc520 100644 --- a/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp +++ b/src/reader2/ISyntaxStateMachine_DExprSeqState.cpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2-claude1/xo-facet/codegen/genfacet] + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] * arguments: * --input [idl/ISyntaxStateMachine_DExprSeqState.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -28,7 +28,16 @@ namespace xo { } auto - ISyntaxStateMachine_DExprSeqState::on_if_token(DExprSeqState & self, const Token & tk, ParserStateMachine * p_psm) -> void + ISyntaxStateMachine_DExprSeqState::on_def_token(DExprSeqState & self, + const Token & tk, + ParserStateMachine * p_psm) -> void + { + self.on_def_token(tk, p_psm); + } + auto + ISyntaxStateMachine_DExprSeqState::on_if_token(DExprSeqState & self, + const Token & tk, + ParserStateMachine * p_psm) -> void { self.on_if_token(tk, p_psm); } @@ -36,4 +45,4 @@ namespace xo { } /*namespace scm*/ } /*namespace xo*/ -/* end ISyntaxStateMachine_DExprSeqState.cpp */ \ No newline at end of file +/* end ISyntaxStateMachine_DExprSeqState.cpp */ diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 4756975a..25765466 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -48,8 +48,7 @@ namespace xo { auto alloc = with_facet::mkobj(&parser_alloc_); - this->stack_ = ParserStack::push(nullptr /*stack*/, - alloc, ssm); + this->stack_ = ParserStack::push(nullptr /*stack*/, alloc, ssm); this->parser_alloc_ckp_ = parser_alloc_.checkpoint(); } @@ -96,11 +95,14 @@ namespace xo { } switch (tk.tk_type()) { + case tokentype::tk_def: + this->on_def_token(tk); + break; + case tokentype::tk_if: this->on_if_token(tk); break; - // all the not-yet handled cases case tokentype::tk_invalid: case tokentype::tk_bool: @@ -133,7 +135,6 @@ namespace xo { case tokentype::tk_cmpeq: case tokentype::tk_cmpne: case tokentype::tk_type: - case tokentype::tk_def: case tokentype::tk_lambda: case tokentype::tk_then: case tokentype::tk_else: @@ -141,12 +142,21 @@ namespace xo { case tokentype::tk_in: case tokentype::tk_end: case tokentype::N: - throw std::runtime_error(tostr("NOT IMPLEMENTED", + throw std::runtime_error(tostr("ParserStateMachin::on_token:", + "NOT IMPLEMENTED", xtag("token", tk))); } } + void + ParserStateMachine::on_def_token(const Token & tk) + { + scope log(XO_DEBUG(debug_flag_), xtag("tk", tk)); + + stack_->top().on_def_token(tk, this); + } + void ParserStateMachine::on_if_token(const Token & tk) { diff --git a/src/reader2/SchematikaParser.cpp b/src/reader2/SchematikaParser.cpp index f9f0b482..47f6918b 100644 --- a/src/reader2/SchematikaParser.cpp +++ b/src/reader2/SchematikaParser.cpp @@ -43,7 +43,7 @@ namespace xo { } void - SchematikaParser::begin_translation_unit() { + SchematikaParser::begin_batch_session() { DExprSeqState::establish_batch(*(psm_.expr_alloc()), &psm_); } diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index 1f066f3e..b333ff0c 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -62,13 +62,38 @@ namespace xo { SchematikaParser parser(config, &expr_alloc, false /*debug_flag*/); - parser.begin_translation_unit(); + parser.begin_batch_session(); // after begin_translation_unit, parser has toplevel exprseq // but is still "at toplevel" in the sense of ready for input REQUIRE(parser.has_incomplete_expr() == false); } + TEST_CASE("SchematikaParser-batch-def", "[reader2][SchematikaParser]") + { + ArenaConfig config; + config.name_ = "test-arena"; + config.size_ = 16 * 1024; + + DArena expr_arena = DArena::map(config); + obj expr_alloc = with_facet::mkobj(&expr_arena); + + SchematikaParser parser(config, &expr_alloc, false /*debug_flag*/); + + parser.begin_batch_session(); + + auto & result = parser.on_token(Token::def_token()); + + // define-expressions not properly implemented + + // after begin_interactive_session, parser has toplevel exprseq + // but is still "at toplevel" in the sense of ready for input + REQUIRE(parser.has_incomplete_expr() == true); + REQUIRE(result.is_error()); + + REQUIRE(result.error_description()); + } + TEST_CASE("SchematikaParser-interactive-if", "[reader2][SchematikaParser]") { ArenaConfig config; @@ -82,11 +107,16 @@ namespace xo { parser.begin_interactive_session(); - parser.on_token(Token::if_token()); + auto & result = parser.on_token(Token::if_token()); // after begin_interactive_session, parser has toplevel exprseq // but is still "at toplevel" in the sense of ready for input REQUIRE(parser.has_incomplete_expr() == false); + + REQUIRE(result.is_error()); + + // illegal input on token + REQUIRE(result.error_description()); } } /*namespace ut*/