From a79f4aef2b7ecf0327c5a752dc52ad809c6336f3 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 11 Feb 2026 16:02:41 -0500 Subject: [PATCH] xo-reader2: DApplySsm for apply expressions [WIP] --- xo-reader2/include/xo/reader2/DApplySsm.hpp | 165 +++++++++++++ xo-reader2/include/xo/reader2/DDefineSsm.hpp | 4 +- .../include/xo/reader2/syntaxstatetype.hpp | 5 +- xo-reader2/src/reader2/CMakeLists.txt | 4 + xo-reader2/src/reader2/DApplySsm.cpp | 221 ++++++++++++++++++ xo-reader2/src/reader2/DProgressSsm.cpp | 7 +- xo-reader2/src/reader2/syntaxstatetype.cpp | 2 + 7 files changed, 402 insertions(+), 6 deletions(-) create mode 100644 xo-reader2/include/xo/reader2/DApplySsm.hpp create mode 100644 xo-reader2/src/reader2/DApplySsm.cpp diff --git a/xo-reader2/include/xo/reader2/DApplySsm.hpp b/xo-reader2/include/xo/reader2/DApplySsm.hpp new file mode 100644 index 00000000..34c78f78 --- /dev/null +++ b/xo-reader2/include/xo/reader2/DApplySsm.hpp @@ -0,0 +1,165 @@ +/** @file DApplySsm.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DSyntaxStateMachine.hpp" +#include "syntaxstatetype.hpp" +#include +//#include +#include + + +namespace xo { + namespace scm { + /** + * fn ( arg1 , arg2 , .. , argn ) + * ^ ^ ^ ^ ^ ^ ^ ^ ^ + * | | | | | | | | (done) + * | | | | | | | apply_3 + * | | | | | | apply_2:expect_rhs_expression + * | | | | | apply_3 + * | | | | apply_2:expect_rhs_expression + * | | | apply_3 + * | | apply_2:expect_rhs_expression + * | apply_1 + * apply_0:expect_rhs_expression + * + * apply_0 --on_expr()--> apply_1 + * apply_1 --on_leftparen()--> apply_2 + * apply_2 --on_expr()--> apply_3 + * apply_3 --on_comma()--> apply_2 + * --on_rightparen()-> (done) + * + * apply_0: start + * apply_1: leftparen following expr allows parser to recognize apply + * apply_2: expect next argument + * apply_3: got argument, expect comma or rightparen to continue + * (done): apply complete, pop exprstate from stack + * + * In practice will start in state apply_1 + **/ + enum class applyexprstatetype { + invalid = -1, + + apply_0, + apply_1, + apply_2, + apply_3, + + N + }; + + extern const char * applyexprstatetype_descr(applyexprstatetype x); + + std::ostream & + operator<<(std::ostream & os, applyexprstatetype x); + + /** @class DApplySsm + * @brief state machine for parsing a schematika function-call-expression + **/ + class DApplySsm : public DSyntaxStateMachine { + public: + using Super = DSyntaxStateMachine; + using TypeDescr = xo::reflect::TypeDescr; + using AAllocator = xo::mm::AAllocator; + using DArena = xo::mm::DArena; + using ppindentinfo = xo::print::ppindentinfo; + + //using Apply = xo::scm::Apply; + + public: + /** @defgroup scm-applyssm-ctors constructors **/ + ///@{ + + /** construct apply ssm with @p fn_expr + * supplying function to be invoked. + * + * Expect during parsing of input like f(...) + * that we parse f before parser knows that it will be + * followed by leftparen + **/ + explicit DApplySsm(obj fn_expr); + + /** create instance using memory from @p parser_mm. + * with function to be called supplied by @p fn_expr. + **/ + static DApplySsm * make(DArena & parser_mm, + obj fn_expr); + +#ifdef NOT_YET + /** + * Start apply. Will trigger this after input like + * "fn(" + * + * apply_xs remains on expr stack until closing right paren + * fn(arg1-expr, arg2-expr, ...) + * + * @p fnex expression in function position + * @p p_psm parser state machine + **/ + static void start(rp fnex, + parserstatemachine * p_psm); +#endif + + ///@} + /** @defgroup scm-applyssm-access methods **/ + ///@{ + + /** identify this nested state machine **/ + static const char * ssm_classname() { return "DApplySsm"; } + + /** current internal state **/ + applyexprstatetype applystate() const noexcept { return applystate_; } + + ///@} + /** @defgroup ssm-applyssm-facet syntaxstatemachine facet methods **/ + ///@{ + + /** identifies the ssm implemented here **/ + syntaxstatetype ssm_type() const noexcept; + + /** mnemonic for expected remaining syntax for current parsing state **/ + std::string_view get_expect_str() const noexcept; + +#ifdef NOT_YET + + virtual void on_expr(bp expr, + parserstatemachine * p_psm) override; + + virtual void on_comma_token(const token_type & tk, + parserstatemachine * p_psm) override; + virtual void on_leftparen_token(const token_type & tk, + parserstatemachine * p_psm) override; + virtual void on_rightparen_token(const token_type & tk, + parserstatemachine * p_psm) override; + + virtual void print(std::ostream & os) const override; + virtual bool pretty_print(const print::ppindentinfo & ppii) const final override; + + private: + static std::unique_ptr make(); +#endif + + private: + /** current state of parser for this apply expression **/ + applyexprstatetype applystate_ = applyexprstatetype::apply_0; + /** evaluates to function to be invoked **/ + obj fn_expr_; +#ifdef NOT_YET + /** evaluates to the arguments to pass to @ref fn_ **/ + std::vector> args_expr_v_; +#endif + }; + } /*namespace scm */ + + namespace print { +#ifndef ppdetail_atomic + PPDETAIL_ATOMIC(xo::scm::applyexprstatetype); +#endif + } +} /*namespace xo*/ + +/* end DApplySsm.hpp */ diff --git a/xo-reader2/include/xo/reader2/DDefineSsm.hpp b/xo-reader2/include/xo/reader2/DDefineSsm.hpp index f71477dd..d42246ef 100644 --- a/xo-reader2/include/xo/reader2/DDefineSsm.hpp +++ b/xo-reader2/include/xo/reader2/DDefineSsm.hpp @@ -78,7 +78,7 @@ namespace xo { using ppindentinfo = xo::print::ppindentinfo; public: - /** @defgroup scm-define-ssm-facet constructors **/ + /** @defgroup scm-definessm-ctors constructors **/ ///@{ /** constructor; using @p def_expr for initial expression scaffold **/ @@ -110,7 +110,7 @@ namespace xo { defexprstatetype defstate() const noexcept { return defstate_; } ///@} - /** @defgroup scm-define-ssm-facet syntaxstatemachine facet methods **/ + /** @defgroup scm-definessm-facet syntaxstatemachine facet methods **/ ///@{ /** identifies the ssm implemented here **/ diff --git a/xo-reader2/include/xo/reader2/syntaxstatetype.hpp b/xo-reader2/include/xo/reader2/syntaxstatetype.hpp index 3031a444..147b7770 100644 --- a/xo-reader2/include/xo/reader2/syntaxstatetype.hpp +++ b/xo-reader2/include/xo/reader2/syntaxstatetype.hpp @@ -27,9 +27,12 @@ namespace xo { /** handle ifelse-expression. See @ref DIfElseSsm **/ ifelseexpr, - /** handle sequence-expression. See @ref DSequenceSsm **/ + /** handle sequence-expression syntax. See @ref DSequenceSsm **/ sequence, + /** handle apply-expression syntax. See @ref DApplySsm **/ + apply, + /** rhs expression. state exists to achieve 1-token lookahead **/ progress, diff --git a/xo-reader2/src/reader2/CMakeLists.txt b/xo-reader2/src/reader2/CMakeLists.txt index 4a813900..b6d9bed0 100644 --- a/xo-reader2/src/reader2/CMakeLists.txt +++ b/xo-reader2/src/reader2/CMakeLists.txt @@ -37,6 +37,10 @@ set(SELF_SRCS ISyntaxStateMachine_DLambdaSsm.cpp IPrintable_DLambdaSsm.cpp + DApplySsm.cpp + # ISyntaxStateMachine_DApplySsm.cpp + # IPrintable_DApplySsm.cpp + DParenSsm.cpp ISyntaxStateMachine_DParenSsm.cpp IPrintable_DParenSsm.cpp diff --git a/xo-reader2/src/reader2/DApplySsm.cpp b/xo-reader2/src/reader2/DApplySsm.cpp new file mode 100644 index 00000000..f58ce7d4 --- /dev/null +++ b/xo-reader2/src/reader2/DApplySsm.cpp @@ -0,0 +1,221 @@ +/** @file DApplySsm.cpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#include "DApplySsm.hpp" +#include + +//#include "parserstatemachine.hpp" +//#include "expect_expr_xs.hpp" + +namespace xo { + using xo::reflect::typeseq; + + namespace scm { + + // ----- applyexprstatetype ----- + + const char * + applyexprstatetype_descr(applyexprstatetype x) { + switch (x) { + case applyexprstatetype::invalid: return "invalid"; + case applyexprstatetype::apply_0: return "apply_0"; + case applyexprstatetype::apply_1: return "apply_1"; + case applyexprstatetype::apply_2: return "apply_2"; + case applyexprstatetype::apply_3: return "apply_3"; + case applyexprstatetype::N: break; + } + + return "???applyexprstatetype"; + } + + std::ostream & + operator<<(std::ostream & os, applyexprstatetype x) { + os << applyexprstatetype_descr(x); + return os; + } + + // ----- DApplySsm ----- + + DApplySsm::DApplySsm(obj fn_expr) + : applystate_{applyexprstatetype::apply_0}, + fn_expr_{fn_expr} + { + if (fn_expr) { + this->applystate_ = applyexprstatetype::apply_1; + } + } + + DApplySsm * + DApplySsm::make(DArena & mm, + obj fn_expr) + { + void * mem = mm.alloc(typeseq::id(), + sizeof(DApplySsm)); + + // TODO: revisit if we use flexible array for + // arguments + + return new (mem) DApplySsm(fn_expr); + } + +#ifdef NOT_YET + void + apply_xs::start(rp fn_expr, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + p_psm->push_exprstate(apply_xs::make()); + p_psm->top_exprstate().on_expr(fn_expr.get(), p_psm); + p_psm->top_exprstate().on_leftparen_token(token_type::leftparen(), p_psm); + } +#endif + + syntaxstatetype + DApplySsm::ssm_type() const noexcept { + return syntaxstatetype::apply; + } + + + std::string_view + DApplySsm::get_expect_str() const noexcept + { + switch(applystate_) { + case applyexprstatetype::invalid: return "invalid"; + case applyexprstatetype::apply_0: return "expr"; + case applyexprstatetype::apply_1: return "lparen"; + case applyexprstatetype::apply_2: return "expr"; + case applyexprstatetype::apply_3: return "comma|rparen"; + case applyexprstatetype::N: break; + } + + return "?expect"; + } + +#ifdef NOT_YET + void + apply_xs::on_expr(bp expr, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + switch (applyxs_type_) { + case applyexprstatetype::invalid: + case applyexprstatetype::n_applyexprstatetype: + // unreachable + break; + case applyexprstatetype::apply_0: + log && log("stash fn -> new state apply_1"); + this->fn_expr_ = expr.promote(); + this->applyxs_type_ = applyexprstatetype::apply_1; + return; + case applyexprstatetype::apply_1: + log && log("error: was expecting lparen"); + // error, expecting lparen + break; + case applyexprstatetype::apply_2: + log && log(xtag("expr", expr), xtag("do", "stash expr -> new state apply_3")); + this->args_expr_v_.push_back(expr.promote()); + this->applyxs_type_ = applyexprstatetype::apply_3; + return; + case applyexprstatetype::apply_3: + // error, expecting comma|rparen + break; + } + + /* control here --implies-> error state */ + + constexpr const char * c_self_name = "apply_xs::on_expr"; + const char * exp = this->get_expect_str(); + + this->illegal_input_on_expr(c_self_name, expr, exp, p_psm); + } + + void + apply_xs::on_comma_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + if (this->applyxs_type_ == applyexprstatetype::apply_3) { + this->applyxs_type_ = applyexprstatetype::apply_2; + expect_expr_xs::start(p_psm); + } else { + constexpr const char * c_self_name = "apply_xs::on_comma_token"; + const char * exp = this->get_expect_str(); + + this->illegal_input_on_token(c_self_name, tk, exp, p_psm); + } + } + + void + apply_xs::on_leftparen_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + log && log("applyxs_type", applyxs_type_); + + if (this->applyxs_type_ == applyexprstatetype::apply_1) { + this->applyxs_type_ = applyexprstatetype::apply_2; + expect_expr_xs::start(p_psm); + } else { + constexpr const char * c_self_name = "apply_xs::on_leftparen_token"; + const char * exp = this->get_expect_str(); + + this->illegal_input_on_token(c_self_name, tk, exp, p_psm); + } + } + + void + apply_xs::on_rightparen_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + log && log("applyxs_type", applyxs_type_); + + if (this->applyxs_type_ == applyexprstatetype::apply_3) { + /* (done) state */ + log("apply complete -> pop + send expr"); + + rp apply_expr = Apply::make(this->fn_expr_, this->args_expr_v_); + + std::unique_ptr self = p_psm->pop_exprstate(); + + p_psm->top_exprstate().on_expr(apply_expr, p_psm); + return; + } + + constexpr const char * c_self_name = "apply_xs::on_rightparen_token"; + const char * exp = this->get_expect_str(); + + this->illegal_input_on_token(c_self_name, tk, exp, p_psm); + } + + void + apply_xs::print(std::ostream & os) const + { + os << ""; + } + + bool + apply_xs::pretty_print(const xo::print::ppindentinfo & ppii) const + { + return ppii.pps()->pretty_struct(ppii, "apply_xs", + refrtag("applyxs_type", applyxs_type_), + refrtag("fn_expr", fn_expr_), + refrtag("args_expr_v", args_expr_v_)); + } + +#endif + } /*namespace scm*/ +} /*namespace xo*/ + + +/* end DApplySsm.cpp */ diff --git a/xo-reader2/src/reader2/DProgressSsm.cpp b/xo-reader2/src/reader2/DProgressSsm.cpp index d774c269..0a28fd60 100644 --- a/xo-reader2/src/reader2/DProgressSsm.cpp +++ b/xo-reader2/src/reader2/DProgressSsm.cpp @@ -538,7 +538,7 @@ namespace xo { } #endif - // here: have lhs_ expression + // here: have lhs_ expression if (op_type_ == optype::invalid) { // e.g. control here on input like @@ -911,12 +911,13 @@ namespace xo { return; } - if (optype_ == optype::invalid) { + if (op_type_ == optype::invalid) { // leftparen begins function call arguments. // .lhs_ now understood to be expression that evaluates to a // function - + + } Super::on_token(tk, p_psm); diff --git a/xo-reader2/src/reader2/syntaxstatetype.cpp b/xo-reader2/src/reader2/syntaxstatetype.cpp index 18acb000..01ab1005 100644 --- a/xo-reader2/src/reader2/syntaxstatetype.cpp +++ b/xo-reader2/src/reader2/syntaxstatetype.cpp @@ -21,6 +21,8 @@ namespace xo { return "ifelseexpr"; case syntaxstatetype::sequence: return "sequence"; + case syntaxstatetype::apply: + return "apply"; case syntaxstatetype::progress: return "progress"; case syntaxstatetype::paren: