From 6795c1bc15285b5ceedba58fa764e68d0e4e9d59 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 28 Feb 2026 13:21:54 +1100 Subject: [PATCH] xo-reader2: support 0-argument apply-expressions --- include/xo/reader2/DApplySsm.hpp | 21 ++++++-- include/xo/reader2/DExpectExprSsm.hpp | 32 ++++++++--- src/reader2/DApplySsm.cpp | 78 ++++++++++++++++++--------- src/reader2/DExpectExprSsm.cpp | 73 +++++++++++++------------ src/reader2/DParenSsm.cpp | 5 +- src/reader2/DProgressSsm.cpp | 2 +- src/reader2/DSequenceSsm.cpp | 4 +- 7 files changed, 138 insertions(+), 77 deletions(-) diff --git a/include/xo/reader2/DApplySsm.hpp b/include/xo/reader2/DApplySsm.hpp index d53b3c5c..9357fc39 100644 --- a/include/xo/reader2/DApplySsm.hpp +++ b/include/xo/reader2/DApplySsm.hpp @@ -30,12 +30,13 @@ namespace xo { * apply_0 --on_expr()--> apply_1 * apply_1 --on_leftparen()--> apply_2 * apply_2 --on_expr()--> apply_3 + * --on_rightparen()--> (done) * apply_3 --on_comma()--> apply_2 - * --on_rightparen()-> (done) + * --on_rightparen()--> (done) * * apply_0: start * apply_1: leftparen following expr allows parser to recognize apply - * apply_2: expect next argument + * apply_2: expect next argument, or rightparent to continue * apply_3: got argument, expect comma or rightparen to continue * (done): apply complete, pop exprstate from stack * @@ -129,6 +130,15 @@ namespace xo { void on_leftparen_token(const Token & tk, ParserStateMachine * p_psm); + /** handle rightparen token @p tk for this ssm, + * with overall parser state in @p p_psm. + * + * Rightparen will complete apply-expression, + * terminating this syntax. + **/ + void on_rightparen_token(const Token & tk, + ParserStateMachine * p_psm); + ///@} /** @defgroup ssm-applyssm-facet syntaxstatemachine facet methods **/ ///@{ @@ -177,9 +187,14 @@ namespace xo { ///@} private: - /** @defgroup ssm-applyssm-mpl-methods **/ + /** @defgroup ssm-applyssm-impl-methods **/ ///@{ + /** create final apply-expression for this syntax, + * using @p mm for memory + **/ + obj assemble_expr(obj mm); + ///@} private: diff --git a/include/xo/reader2/DExpectExprSsm.hpp b/include/xo/reader2/DExpectExprSsm.hpp index 7600948c..16739006 100644 --- a/include/xo/reader2/DExpectExprSsm.hpp +++ b/include/xo/reader2/DExpectExprSsm.hpp @@ -22,21 +22,24 @@ namespace xo { using ppindentinfo = xo::print::ppindentinfo; public: - explicit DExpectExprSsm(bool allow_defs, - bool cxl_on_rightparen); + DExpectExprSsm(bool allow_defs, + bool cxl_on_rightbrace, + bool cxl_on_rightparen); static DExpectExprSsm * _make(DArena & parser_mm, bool allow_defs, - bool cxl_on_rightbrace); + bool cxl_on_rightbrace, + bool cxl_on_rightparen); /** create fop referring to new DExpectExprSsm **/ static obj make(DArena & parser_mm, bool allow_defs, - bool cxl_on_rightbrace); + bool cxl_on_rightbrace, + bool cxl_on_rightparen); - static void start(DArena & parser_mm, - bool allow_defs, + static void start(bool allow_defs, bool cxl_on_rightbrace, + bool cxl_on_rightparen, ParserStateMachine * p_psm); static void start(ParserStateMachine * p_psm); @@ -46,6 +49,7 @@ namespace xo { static const char * ssm_classname() { return "DExpectExprSsm"; } bool allow_defs() const noexcept { return allow_defs_; } bool cxl_on_rightbrace() const noexcept { return cxl_on_rightbrace_; } + bool cxl_on_rightparen() const noexcept { return cxl_on_rightparen_; } ///@} /** @defgroup scm-expectexpr-methods general methods **/ @@ -57,6 +61,15 @@ namespace xo { void on_leftparen_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming rightparen token @p tk, + * with overall parser state in @p p_psm. + * + * Generally treats as illegal, but cancels gracefully when + * @ref cxl_on_rightparen_ set. + **/ + void on_rightparen_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state for this syntax on incoming leftbrace token @p tk, * with overall parser state in @p p_psm **/ @@ -165,8 +178,11 @@ namespace xo { * 2a. expression **/ bool cxl_on_rightbrace_ = false; - - + /** if true: expecting either: + * 1a. expression + * 1b. right paren ')', in which case no expression + **/ + bool cxl_on_rightparen_ = false; }; } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader2/DApplySsm.cpp b/src/reader2/DApplySsm.cpp index d6f5e151..867bf33b 100644 --- a/src/reader2/DApplySsm.cpp +++ b/src/reader2/DApplySsm.cpp @@ -116,7 +116,7 @@ namespace xo { 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_2: return "expr|rparen"; case applyexprstatetype::apply_3: return "comma|rparen"; case applyexprstatetype::N: break; } @@ -134,6 +134,9 @@ namespace xo { 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_symbol: case tokentype::tk_def: case tokentype::tk_if: @@ -147,7 +150,6 @@ namespace xo { case tokentype::tk_i64: case tokentype::tk_bool: case tokentype::tk_invalid: - case tokentype::tk_rightparen: case tokentype::tk_leftbracket: case tokentype::tk_rightbracket: case tokentype::tk_leftbrace: @@ -186,7 +188,25 @@ namespace xo { if (applystate_ == applyexprstatetype::apply_1) { this->applystate_ = applyexprstatetype::apply_2; - DExpectExprSsm::start(p_psm); + DExpectExprSsm::start(false /*!allow_defs*/, + false /*!cxl_on_rightbrace*/, + true /*cxl_on_rightparen*/, + p_psm); + return; + } + + Super::on_token(tk, p_psm); + } + + void + DApplySsm::on_rightparen_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (applystate_ == applyexprstatetype::apply_2) { + obj apply = this->assemble_expr(p_psm->expr_alloc()); + + p_psm->pop_ssm(); + p_psm->on_parsed_expression(apply); return; } @@ -226,28 +246,7 @@ namespace xo { args_expr_v_->push_back(expr_gco); if (tk.tk_type() == tokentype::tk_rightparen) { - // begin assemble_expr().. - - std::uint32_t n_args = args_expr_v_->size(); - - DApplyExpr * apply - = (DApplyExpr::scaffold - (mm, - TypeRef::dwim(TypeRef::prefix_type::from_chars("apply"), - nullptr), - fn_expr_, - n_args)); - - for (std::uint32_t i_arg = 0; i_arg < n_args; ++i_arg) { - auto arg_expr - = args_expr_v_->at(i_arg).to_facet(); - - apply->assign_arg(i_arg, arg_expr); - } - - // ..end assemble_expr() - - obj apply_ex(apply); + obj apply_ex = this->assemble_expr(p_psm->expr_alloc()); p_psm->pop_ssm(); p_psm->on_parsed_expression(apply_ex); @@ -266,6 +265,35 @@ namespace xo { Super::on_parsed_expression_with_token(expr, tk, p_psm); } + obj + DApplySsm::assemble_expr(obj mm) + { + // begin assemble_expr().. + + std::uint32_t n_args = args_expr_v_->size(); + + DApplyExpr * apply + = (DApplyExpr::scaffold + (mm, + TypeRef::dwim(TypeRef::prefix_type::from_chars("apply"), + nullptr), + fn_expr_, + n_args)); + + for (std::uint32_t i_arg = 0; i_arg < n_args; ++i_arg) { + auto arg_expr + = args_expr_v_->at(i_arg).to_facet(); + + apply->assign_arg(i_arg, arg_expr); + } + + // ..end assemble_expr() + + obj apply_ex(apply); + + return apply_ex; + } + #ifdef NOT_YET void apply_xs::on_expr(bp expr, diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index 459e3176..ba1fa33f 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -42,41 +42,48 @@ namespace xo { namespace scm { DExpectExprSsm::DExpectExprSsm(bool allow_defs, - bool cxl_on_rightbrace) + bool cxl_on_rightbrace, + bool cxl_on_rightparen) : allow_defs_{allow_defs}, - cxl_on_rightbrace_{cxl_on_rightbrace} + cxl_on_rightbrace_{cxl_on_rightbrace}, + cxl_on_rightparen_{cxl_on_rightparen} { } DExpectExprSsm * DExpectExprSsm::_make(DArena & mm, bool allow_defs, - bool cxl_on_rightbrace) + bool cxl_on_rightbrace, + bool cxl_on_rightparen) { void * mem = mm.alloc(typeseq::id(), sizeof(DExpectExprSsm)); return new (mem) DExpectExprSsm(allow_defs, - cxl_on_rightbrace); + cxl_on_rightbrace, + cxl_on_rightparen); } obj DExpectExprSsm::make(DArena & mm, bool allow_defs, - bool cxl_on_rightbrace) + bool cxl_on_rightbrace, + bool cxl_on_rightparen) { - return obj(_make(mm, allow_defs, cxl_on_rightbrace)); + return obj(_make(mm, allow_defs, cxl_on_rightbrace, cxl_on_rightparen)); } void - DExpectExprSsm::start(DArena & mm, - bool allow_defs, + DExpectExprSsm::start(bool allow_defs, bool cxl_on_rightbrace, + bool cxl_on_rightparen, ParserStateMachine * p_psm) { + auto & mm = p_psm->parser_alloc(); + DArena::Checkpoint ckp = mm.checkpoint(); - auto ssm = DExpectExprSsm::make(mm, allow_defs, cxl_on_rightbrace); + auto ssm = DExpectExprSsm::make(mm, allow_defs, cxl_on_rightbrace, cxl_on_rightparen); p_psm->push_ssm(ckp, ssm); } @@ -84,9 +91,9 @@ namespace xo { void DExpectExprSsm::start(ParserStateMachine * p_psm) { - start(p_psm->parser_alloc(), - false /*!allow_defs*/, + start(false /*!allow_defs*/, false /*!cxl_on_rightbrace*/, + false /*cxl_on_rightparen*/, p_psm); } @@ -117,6 +124,10 @@ namespace xo { this->on_leftparen_token(tk, p_psm); return; + case tokentype::tk_rightparen: + this->on_rightparen_token(tk, p_psm); + return; + case tokentype::tk_leftbrace: this->on_leftbrace_token(tk, p_psm); return; @@ -158,7 +169,6 @@ namespace xo { case tokentype::tk_singleassign: case tokentype::tk_colon: case tokentype::tk_semicolon: - case tokentype::tk_rightparen: case tokentype::tk_leftbracket: case tokentype::tk_rightbracket: case tokentype::tk_rightbrace: @@ -206,6 +216,21 @@ namespace xo { p_psm->on_token(tk); } + void + DExpectExprSsm::on_rightparen_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (cxl_on_rightparen_) { + /* abandon expression, delegate rightparen to parent */ + + p_psm->pop_ssm(); + p_psm->on_token(tk); + return; + } + + Super::on_token(tk, p_psm); + } + void DExpectExprSsm::on_leftbrace_token(const Token & tk, ParserStateMachine * p_psm) @@ -482,8 +507,8 @@ namespace xo { "DExpectExprSsm", refrtag("allow_defs", allow_defs_), refrtag("cxl_on_rightbrace", cxl_on_rightbrace_), - refrtag("expect", this->get_expect_str()) - ); + refrtag("cxl_on_rightparen", cxl_on_rightparen_), + refrtag("expect", this->get_expect_str())); } #ifdef NOT_YET @@ -494,18 +519,6 @@ namespace xo { if_else_xs::start(p_psm); } - void - expect_expr_xs::on_leftparen_token(const token_type & /*tk*/, - parserstatemachine * p_psm) - { - scope log(XO_DEBUG(p_psm->debug_flag())); - - //constexpr const char * self_name = "exprstate::on_leftparen"; - - /* push lparen_0 to remember to look for subsequent rightparen. */ - paren_xs::start(p_psm); - } - void expect_expr_xs::on_rightbrace_token(const token_type & tk, parserstatemachine * p_psm) @@ -561,14 +574,6 @@ namespace xo { << xtag("cxl_on_rightbrace", cxl_on_rightbrace_) << ">"; } - - bool - expect_expr_xs::pretty_print(const xo::print::ppindentinfo & ppii) const - { - return ppii.pps()->pretty_struct(ppii, "expect_expr_xs", - refrtag("allow_defs", allow_defs_), - refrtag("cxl_on_rightbrace", cxl_on_rightbrace_)); - } #endif } /*namespace scm*/ diff --git a/src/reader2/DParenSsm.cpp b/src/reader2/DParenSsm.cpp index b89dec52..acfeb65c 100644 --- a/src/reader2/DParenSsm.cpp +++ b/src/reader2/DParenSsm.cpp @@ -159,10 +159,7 @@ namespace xo { * by rightparen. empty parentheses '()' * do not denote anything, in expression context **/ - DExpectExprSsm::start(p_psm->parser_alloc(), - false /*!allow_defs*/, - false /*cx_on_rightbrace*/, - p_psm); + DExpectExprSsm::start(p_psm); return; } diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 4954dc49..65c39d74 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -218,7 +218,7 @@ namespace xo { if (!lhs_) { return "expr1|leftparen"; } else if (op_type_ == optype::invalid) { - return "oper|semicolon|rightparen|rightbrace"; + return "oper|semicolon|leftparen|rightparen|rightbrace"; } else { return "expr2|leftparen"; } diff --git a/src/reader2/DSequenceSsm.cpp b/src/reader2/DSequenceSsm.cpp index 87460804..f9884b78 100644 --- a/src/reader2/DSequenceSsm.cpp +++ b/src/reader2/DSequenceSsm.cpp @@ -29,9 +29,9 @@ namespace xo { /* want to accept anything that starts an expression, * except that rightbrace '}' ends it */ - DExpectExprSsm::start(p_psm->parser_alloc(), - true /*allow_defs*/, + DExpectExprSsm::start(true /*allow_defs*/, true /*cxl_on_rightbrace*/, + false /*!cxl_on_rightparen*/, p_psm); }