diff --git a/include/xo/reader2/DProgressSsm.hpp b/include/xo/reader2/DProgressSsm.hpp index 85126bed..792d6eb2 100644 --- a/include/xo/reader2/DProgressSsm.hpp +++ b/include/xo/reader2/DProgressSsm.hpp @@ -166,6 +166,8 @@ namespace xo { ParserStateMachine * p_psm); void on_semicolon_token(const Token & tk, ParserStateMachine * p_psm); + void on_rightbrace_token(const Token & tk, + ParserStateMachine * p_psm); void on_parsed_expression_with_semicolon(obj expr, ParserStateMachine * p_psm); @@ -183,27 +185,12 @@ namespace xo { void on_typedescr(TypeDescr td, parserstatemachine * p_psm) override; - void on_semicolon_token(const token_type & tk, - parserstatemachine * p_psm) override; void on_assign_token(const token_type & tk, parserstatemachine * p_psm) final override; void on_leftparen_token(const token_type & tk, parserstatemachine * p_psm) override; void on_rightparen_token(const token_type & tk, parserstatemachine * p_psm) override; - void on_rightbrace_token(const token_type & tk, - parserstatemachine * p_psm) override; - - /* entry point for an infix operator token */ - void on_operator_token(const token_type & tk, - parserstatemachine * p_psm) final override; - - void on_bool_token(const token_type & tk, - parserstatemachine * p_psm) override; - - void on_i64_token(const token_type & tk, - parserstatemachine * p_psm) override; - void print(std::ostream & os) const override; #endif diff --git a/include/xo/reader2/DSequenceSsm.hpp b/include/xo/reader2/DSequenceSsm.hpp index 6423ee29..e2943ae8 100644 --- a/include/xo/reader2/DSequenceSsm.hpp +++ b/include/xo/reader2/DSequenceSsm.hpp @@ -7,12 +7,25 @@ #include "DSyntaxStateMachine.hpp" #include +#include "syntaxstatetype.hpp" +#include +#include +#include namespace xo { namespace scm { class Sequence; } namespace scm { class Lambda; } namespace scm { + // TODO: need switching between 1a,1b states. + // Allow + // { } + // { 1 } + // { 1; } + // Reject + // { 1 2 } + // + class DSequenceSsm : public DSyntaxStateMachine { public: //using Sequence = xo::scm::Sequence; @@ -38,15 +51,14 @@ namespace xo { obj expr_mm); #ifdef NOT_YET - virtual void on_expr(bp expr, - parserstatemachine * p_psm) override; virtual void on_expr_with_semicolon(bp expr, parserstatemachine * p_psm) override; - - virtual void on_rightbrace_token(const token_type & tk, - parserstatemachine * p_psm) override; #endif + /** update ssm for incoming rightbrace token '}' **/ + void on_rightbrace_token(const Token & tk, + ParserStateMachine * p_psm); + /** @defgroup scm-sequencessm-syntaxstatemachine-facet ssm facet **/ ///@{ @@ -56,6 +68,16 @@ namespace xo { /** mnemonic for syntax sequence ssm expects given current state **/ std::string_view get_expect_str() const noexcept; + /** operate state machine for this syntax on incoming token @p tk + * with overall parser state in @p p_psm + **/ + void on_token(const Token & tk, + ParserStateMachine * p_psm); + + /** consume expression @p expr produced by nested ssm; overall parser state in @p p_psm **/ + void on_parsed_expression(obj expr, + ParserStateMachine * p_psm); + ///@} /** @defgroup scm-sequencessm-printable-facet printable facet **/ ///@{ diff --git a/include/xo/reader2/ParserStateMachine.hpp b/include/xo/reader2/ParserStateMachine.hpp index a57247c7..91c84ef1 100644 --- a/include/xo/reader2/ParserStateMachine.hpp +++ b/include/xo/reader2/ParserStateMachine.hpp @@ -142,6 +142,18 @@ namespace xo { **/ void on_parsed_expression_with_semicolon(obj expr); + /** update state to respond to parsed expression @p expr + * (from nested parsing state), with trailing token @p tk. + * + * Need to distinguish cases like: + * 6 // ) ? ; allowed } ? + * f(6 // ) allowed ; forbidden } forbidden + * 6 + // ) forbidden ; forbidden } forbidden + * + **/ + void on_parsed_expression_with_token(obj expr, + const Token & tk); + /** update state to respond to input token @p tk. * record output (if any) in @ref result_ **/ diff --git a/src/reader2/DLambdaSsm.cpp b/src/reader2/DLambdaSsm.cpp index 99351533..4b2d7df8 100644 --- a/src/reader2/DLambdaSsm.cpp +++ b/src/reader2/DLambdaSsm.cpp @@ -336,6 +336,23 @@ namespace xo { DLambdaSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) { + if (lm_state_ == lambdastatetype::lm_4) { + this->lmstate_ = lambdastatetype::lm_5; + this->body_ = expr; + + // assemble lambda + + obj lm_expr = DLambda::make(p_psm->expr_alloc(), + xxx typeref, + xxx name, + local_symtab_, + body_); + + p_psm->pop_ssm(); // this lambda + p_psm->on_parsed_expression(lm_expr); + return; + } + Super::on_parsed_expression(expr, p_psm); } diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 3c617fae..9fd6e7b1 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -205,7 +205,7 @@ namespace xo { std::string_view DProgressSsm::get_expect_str() const noexcept { if (op_type_ == optype::invalid) { - return "oper|semicolon|rightparen"; + return "oper|semicolon|rightparen|righbrace"; } else { return "expr|leftparen"; } @@ -255,6 +255,10 @@ namespace xo { this->on_semicolon_token(tk, p_psm); return; + case tokentype::tk_rightbrace: + this->on_rightbrace_token(tk, p_psm); + return; + // all the not-yet handled cases case tokentype::tk_invalid: case tokentype::tk_def: @@ -264,7 +268,6 @@ namespace xo { 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: @@ -448,7 +451,8 @@ namespace xo { obj expr = this->assemble_expr(p_psm); { - obj expr_pr = FacetRegistry::instance().variant(expr); + obj expr_pr + = FacetRegistry::instance().variant(expr); assert(expr_pr); log && log(xtag("expr", expr_pr)); } @@ -475,6 +479,27 @@ namespace xo { #endif } + void + DProgressSsm::on_rightbrace_token(const Token & tk, + ParserStateMachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + (void)tk; + + obj expr = this->assemble_expr(p_psm); + + { + obj expr_pr + = FacetRegistry::instance().variant(expr); + assert(expr_pr); + log && log(xtag("expr", expr_pr)); + } + + p_psm->pop_ssm(); + p_psm->on_parsed_expression_with_token(expr, tk); + } + void DProgressSsm::on_parsed_expression_with_semicolon(obj expr, ParserStateMachine * p_psm) @@ -1024,7 +1049,8 @@ namespace xo { "DProgressSsm", refrtag("lhs", lhs), refrtag("op", op_type_), - cond(rhs, refrtag("rhs", rhs), "nullptr") + cond(rhs, refrtag("rhs", rhs), "nullptr"), + refrtag("expect", this->get_expect_str()) ); } @@ -1048,6 +1074,7 @@ namespace xo { std::string_view(errmsg_string)); p_psm->capture_error(c_self_name, errmsg); + return obj(); } /* consecutive expressions not legal, e.g: diff --git a/src/reader2/DSequenceSsm.cpp b/src/reader2/DSequenceSsm.cpp index 6a6b8c76..56efb896 100644 --- a/src/reader2/DSequenceSsm.cpp +++ b/src/reader2/DSequenceSsm.cpp @@ -55,12 +55,6 @@ namespace xo { DSequenceSsm::DSequenceSsm(DSequenceExpr * seq_expr) : seq_expr_{seq_expr} {} -#ifdef NOT_YET - sequence_xs::sequence_xs() - : exprstate(exprstatetype::sequenceexpr) - {} -#endif - syntaxstatetype DSequenceSsm::ssm_type() const noexcept { @@ -73,15 +67,93 @@ namespace xo { return "expr|semicolon|rightbrace"; } -#ifdef NOT_YET void - sequence_xs::on_expr(bp expr, - parserstatemachine * p_psm) + DSequenceSsm::on_token(const Token & tk, + ParserStateMachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag()), xtag("tk", tk)); + + switch (tk.tk_type()) { + case tokentype::tk_rightbrace: + this->on_rightbrace_token(tk, p_psm); + return; + case tokentype::tk_symbol: + case tokentype::tk_def: + case tokentype::tk_if: + case tokentype::tk_then: + case tokentype::tk_else: + 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_leftparen: + case tokentype::tk_rightparen: + case tokentype::tk_leftbracket: + case tokentype::tk_rightbracket: + case tokentype::tk_leftbrace: + case tokentype::tk_leftangle: + case tokentype::tk_rightangle: + case tokentype::tk_lessequal: + case tokentype::tk_greatequal: + case tokentype::tk_dot: + case tokentype::tk_comma: + 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_lambda: + case tokentype::tk_let: + case tokentype::tk_in: + case tokentype::tk_end: + case tokentype::N: + break; + } + + // default = illegal token error + DSyntaxStateMachine::on_token(tk, p_psm); + } + + void + DSequenceSsm::on_rightbrace_token(const Token & tk, + ParserStateMachine * p_psm) + { + (void)tk; + + /** rightbrace ends DSequenceSsm **/ + + obj expr(seq_expr_); + + p_psm->pop_ssm(); + + /* make sequence from expressions seen at this level, + * and report it to parent + */ + p_psm->top_ssm().on_parsed_expression(expr, p_psm); + } + + void + DSequenceSsm::on_parsed_expression(obj expr, + ParserStateMachine * p_psm) { scope log(XO_DEBUG(p_psm->debug_flag())); - log && log(xtag("expr", expr.promote())); + // TODO: stream inserter that sets up pretty-printing. + // Or integrate with indentlog. + // Maybe trouble is that indentlog doesn't #include Printable ? + // + log && log(xtag("expr", expr)); +#ifdef NOT_YET /* TODO: if expr is a DefineExpr, * then need to rewrite... * @@ -132,8 +204,13 @@ namespace xo { true /*cxl_on_rightbrace*/, p_psm); } +#endif + + this->seq_expr_->push_back(p_psm->expr_alloc(), + expr); } +#ifdef NOT_YET void sequence_xs::on_expr_with_semicolon(bp expr, parserstatemachine * p_psm) @@ -141,25 +218,6 @@ namespace xo { /* sequence continues until right brace */ this->on_expr(expr, p_psm); } - - void - sequence_xs::on_rightbrace_token(const token_type & /*tk*/, - parserstatemachine * p_psm) - { - auto self = p_psm->pop_exprstate(); - - /* make sequence from expressions seen at this level, - * and report it to parent - */ - auto expr = Sequence::make(this->expr_v_); - - p_psm->top_exprstate().on_expr(expr, p_psm); - } - - void - sequence_xs::print(std::ostream & os) const { - os << ""; - } #endif bool @@ -167,9 +225,9 @@ namespace xo { { return ppii.pps()->pretty_struct (ppii, - "SequenceSsm", - xrefrtag("seq_expr.size", seq_expr_->size()), - xrefrtag("expect", this->get_expect_str())); + "DSequenceSsm", + refrtag("seq_expr.size", seq_expr_->size()), + refrtag("expect", this->get_expect_str())); } } /*namespace scm*/ diff --git a/src/reader2/ParserStateMachine.cpp b/src/reader2/ParserStateMachine.cpp index 085cce56..82435b50 100644 --- a/src/reader2/ParserStateMachine.cpp +++ b/src/reader2/ParserStateMachine.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -16,6 +17,7 @@ namespace xo { using xo::print::APrintable; + using xo::facet::FacetRegistry; using xo::facet::with_facet; namespace scm { @@ -188,6 +190,21 @@ namespace xo { this->top_ssm().on_parsed_expression_with_semicolon(expr, this); } + void + ParserStateMachine::on_parsed_expression_with_token(obj expr, + const Token & tk) + { + scope log(XO_DEBUG(debug_flag_), xtag("expr", expr), xtag("tk", tk)); + + assert(stack_); + + this->top_ssm().on_parsed_expression(expr, this); + + assert(stack_); + + this->top_ssm().on_token(tk, this); + } + void ParserStateMachine::on_token(const Token & tk) { @@ -215,7 +232,11 @@ namespace xo { ParserStateMachine::capture_error(std::string_view ssm_name, const DString * errmsg) { - this->result_ = ParserResult::error(ssm_name, errmsg); + if (result_.is_error()) { + /* in case one error triggers another, remmber just the first one */ + } else { + this->result_ = ParserResult::error(ssm_name, errmsg); + } } void @@ -302,7 +323,7 @@ namespace xo { xtag("param_type", param_type), xtag("expecting", expect_str), xtag("ssm", ssm_name), - xtag("via", "ParserStateMachine::illegal_parsed_expression")); + xtag("via", "ParserStateMachine::illegal_parsed_formal")); assert(expr_alloc_); @@ -341,8 +362,16 @@ namespace xo { // - want to write error message using DArena // - need something like log_streambuf and/or tostr() that's arena-aware + obj expr_pr + = FacetRegistry::instance().variant(expr); + assert(expr_pr); + + /** TODO + * problem here: we have pretty() support for obj, + * but not "ordinary printing" support. So expression doesn't get printed + **/ auto errmsg_string = tostr("Unexpected expression", - xtag("expr", expr), + xtag("expr", expr_pr), xtag("expecting", expect_str), xtag("ssm", ssm_name), xtag("via", "ParserStateMachine::illegal_parsed_expression")); diff --git a/utest/SchematikaParser.test.cpp b/utest/SchematikaParser.test.cpp index ef487af3..b30b67f3 100644 --- a/utest/SchematikaParser.test.cpp +++ b/utest/SchematikaParser.test.cpp @@ -215,7 +215,7 @@ namespace xo { /** Walkthrough parsing input equivalent to: * - * lambda (n : i64, + * lambda (n : i64, r : i64) -> i64 { 123 } * **/ @@ -375,11 +375,10 @@ namespace xo { REQUIRE(result.is_incomplete()); } -#ifdef NOT_YET { - auto & result = parser.on_token(Token::string_token("fooey")); + auto & result = parser.on_token(Token::i64_token("123")); - log && log("after string token:"); + log && log("after f64(123) token:"); log && log(xtag("parser", &parser)); log && log(xtag("result", result)); @@ -389,17 +388,16 @@ namespace xo { } { - auto & result = parser.on_token(Token::semicolon_token()); + auto & result = parser.on_token(Token::rightbrace_token()); - log && log("after semicolon token:"); + log && log("after rightbrace token:"); log && log(xtag("parser", &parser)); log && log(xtag("result", result)); - REQUIRE(parser.has_incomplete_expr() == false); + REQUIRE(parser.has_incomplete_expr() == true); REQUIRE(!result.is_error()); - REQUIRE(!result.is_incomplete()); + REQUIRE(result.is_incomplete()); } -#endif //REQUIRE(result.is_error()); //// illegal input on token