From cb7107521bb9b3171f942e5f15fa2f864eca8e38 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 23 Jul 2025 23:19:16 -0500 Subject: [PATCH] xo-reader xo-expression xo-tokenizer xo-jit: comparison + apply --- include/xo/reader/apply_xs.hpp | 113 +++++++++++++++++ include/xo/reader/expect_expr_xs.hpp | 12 +- include/xo/reader/exprstate.hpp | 5 + include/xo/reader/progress_xs.hpp | 21 ++++ src/reader/CMakeLists.txt | 1 + src/reader/apply_xs.cpp | 174 +++++++++++++++++++++++++++ src/reader/define_xs.cpp | 86 ++++++------- src/reader/expect_expr_xs.cpp | 46 +++++-- src/reader/expect_type_xs.cpp | 4 +- src/reader/exprseq_xs.cpp | 2 +- src/reader/exprstate.cpp | 4 + src/reader/progress_xs.cpp | 98 ++++++++++++--- src/reader/reader.cpp | 3 +- 13 files changed, 486 insertions(+), 83 deletions(-) create mode 100644 include/xo/reader/apply_xs.hpp create mode 100644 src/reader/apply_xs.cpp diff --git a/include/xo/reader/apply_xs.hpp b/include/xo/reader/apply_xs.hpp new file mode 100644 index 00000000..f3975dab --- /dev/null +++ b/include/xo/reader/apply_xs.hpp @@ -0,0 +1,113 @@ +/* @file apply_xs.hpp */ + +#pragma once + +#include "exprstate.hpp" +#include "xo/expression/Apply.hpp" + + +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_applyexprstatetype + }; + + extern const char * applyexprstatetype_descr(applyexprstatetype x); + + std::ostream & + operator<<(std::ostream & os, applyexprstatetype x); + + /** @class apply_xs + * @brief state machine for parsing a schematic function-call-expression + * + */ + class apply_xs : public exprstate { + public: + using Apply = xo::ast::Apply; + + public: + explicit apply_xs(); + virtual ~apply_xs() = default; + + /** downcast from parent type **/ + static const apply_xs * from(const exprstate * x) { + return dynamic_cast(x); + } + + /** + * 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); + + virtual const char * get_expect_str() const override; + + 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; + + private: + static std::unique_ptr make(); + + private: + /** current state of parser for this apply expression **/ + applyexprstatetype applyxs_type_ = applyexprstatetype::apply_0; + /** evaluates to function to be invoked **/ + rp fn_expr_; + /** evaluates to the arguments to pass to @ref fn_ **/ + std::vector> args_expr_v_; + }; + + } /*namespace scm */ +} /*namespace xo*/ + +/* end apply_xs.hpp */ diff --git a/include/xo/reader/expect_expr_xs.hpp b/include/xo/reader/expect_expr_xs.hpp index 148d728f..bfca1603 100644 --- a/include/xo/reader/expect_expr_xs.hpp +++ b/include/xo/reader/expect_expr_xs.hpp @@ -35,9 +35,14 @@ namespace xo { bool cxl_on_rightbrace, parserstatemachine * p_psm); + virtual const char * get_expect_str() const override; + virtual void on_lambda_token(const token_type & tk, parserstatemachine * p_psm) override; + virtual void on_if_token(const token_type & tk, + parserstatemachine * p_psm) override; + virtual void on_def_token(const token_type & tk, parserstatemachine * p_psm) override; @@ -71,20 +76,21 @@ namespace xo { virtual void on_expr_with_semicolon(bp expr, parserstatemachine * p_psm) override; + virtual void print(std::ostream & os) const override; private: static std::unique_ptr make(bool allow_defs, bool cxl_on_rightbrace); private: - /* if true: allow a define-expression here */ + /** if true: allow a define-expression here **/ bool allow_defs_ = false; - /* if true: expecting either: + /** if true: expecting either: * - expression * - right brace '}', in which case no expression * if false: expecting * - expression - */ + **/ bool cxl_on_rightbrace_ = false; }; diff --git a/include/xo/reader/exprstate.hpp b/include/xo/reader/exprstate.hpp index 781026a1..6d3f8cd6 100644 --- a/include/xo/reader/exprstate.hpp +++ b/include/xo/reader/exprstate.hpp @@ -30,6 +30,11 @@ namespace xo { **/ lambdaexpr, + /** handle apply expression (aka function call) + * see @ref apply_xs + **/ + applyexpr, + /** handle parenthesized expression * see @ref paren_xs **/ diff --git a/include/xo/reader/progress_xs.hpp b/include/xo/reader/progress_xs.hpp index 808c964b..8713a9f0 100644 --- a/include/xo/reader/progress_xs.hpp +++ b/include/xo/reader/progress_xs.hpp @@ -19,12 +19,30 @@ namespace xo { enum class optype { invalid = -1, + /** op:= **/ op_assign, + /** op< **/ + op_less, + /** op<= **/ + op_less_equal, + /** op== **/ + op_equal, + /** op!= **/ + op_not_equal, + /** op> **/ + op_great, + /** op>= **/ + op_great_equal, + + /** op+ **/ op_add, + /** op- **/ op_subtract, + /** op* **/ op_multiply, + /** op/ **/ op_divide, n_optype @@ -104,6 +122,9 @@ namespace xo { virtual void on_operator_token(const token_type & tk, parserstatemachine * p_psm) override; + virtual void on_bool_token(const token_type & tk, + parserstatemachine * p_psm) override; + virtual void on_i64_token(const token_type & tk, parserstatemachine * p_psm) override; diff --git a/src/reader/CMakeLists.txt b/src/reader/CMakeLists.txt index 89e2cf98..e8e8bf02 100644 --- a/src/reader/CMakeLists.txt +++ b/src/reader/CMakeLists.txt @@ -11,6 +11,7 @@ set(SELF_SRCS define_xs.cpp if_else_xs.cpp progress_xs.cpp + apply_xs.cpp paren_xs.cpp sequence_xs.cpp exprseq_xs.cpp diff --git a/src/reader/apply_xs.cpp b/src/reader/apply_xs.cpp new file mode 100644 index 00000000..d5f5daed --- /dev/null +++ b/src/reader/apply_xs.cpp @@ -0,0 +1,174 @@ +/* @file apply_xs.cpp */ + +#include "apply_xs.hpp" +#include "parserstatemachine.hpp" +#include "expect_expr_xs.hpp" + +namespace xo { + 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_applyexprstatetype: break; + } + + return "???applyexprstatetype"; + } + + std::ostream & + operator<<(std::ostream & os, applyexprstatetype x) { + os << applyexprstatetype_descr(x); + return os; + } + + // ----- apply_xs ----- + + std::unique_ptr + apply_xs::make() { + return std::make_unique(apply_xs()); + } + + 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); + } + + apply_xs::apply_xs() + : exprstate(exprstatetype::applyexpr) + {} + + const char * + apply_xs::get_expect_str() const { + switch(applyxs_type_) { + 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_applyexprstatetype: break; + } + + return "?expect"; + } + + 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: + this->fn_expr_ = expr.promote(); + this->applyxs_type_ = applyexprstatetype::apply_1; + return; + case applyexprstatetype::apply_1: + // error, expecting lparen + break; + case applyexprstatetype::apply_2: + 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; + } 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; + } 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 */ + + 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 << ""; + } + + } /*namespace scm*/ +} /*namespace xo*/ + + +/* end apply_xs.cpp */ diff --git a/src/reader/define_xs.cpp b/src/reader/define_xs.cpp index 502d5dc5..c4e1a4a4 100644 --- a/src/reader/define_xs.cpp +++ b/src/reader/define_xs.cpp @@ -1,7 +1,6 @@ /* @file define_xs.cpp */ #include "define_xs.hpp" -#include "exprstatestack.hpp" #include "parserstatemachine.hpp" #include "expect_symbol_xs.hpp" #include "expect_expr_xs.hpp" @@ -45,8 +44,7 @@ namespace xo { void define_xs::start(parserstatemachine * p_psm) { - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + 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); @@ -103,8 +101,7 @@ namespace xo { define_xs::on_expr(bp expr, parserstatemachine * p_psm) { - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); log && log(xtag("defxs_type", defxs_type_)); @@ -118,10 +115,12 @@ namespace xo { */ rp rhs_value = expr.promote(); - if (this->cvt_expr_) + if (this->cvt_expr_) { this->cvt_expr_->assign_arg(rhs_value); - else - this->def_expr_->assign_rhs(rhs_value);; + } else { + /* note: establishes .def_expr_ valuetype */ + this->def_expr_->assign_rhs(rhs_value); + } rp def_expr = this->def_expr_; @@ -139,8 +138,7 @@ namespace xo { define_xs::on_expr_with_semicolon(bp expr, parserstatemachine * p_psm) { - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); log && log(xtag("defxs_type", defxs_type_)); @@ -153,14 +151,40 @@ namespace xo { define_xs::on_symbol(const std::string & symbol_name, parserstatemachine * p_psm) { - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); log && log("defxs_type", defxs_type_); if (this->defxs_type_ == defexprstatetype::def_1) { this->defxs_type_ = defexprstatetype::def_2; this->def_expr_->assign_lhs_name(symbol_name); + + // if this is a genuine top-level define (i.e. nesting level = 0), + // then we need to upsert so we can refer to rhs later. + // + // In other contexts (e.g. body-of-lambda) will be rewriting + // { + // def y = foo(x,x); + // bar(y,y); + // } + // into something like + // { + // (lambda (y123) bar(y123,y123))(foo(x,x)); + // } + // + // This works in the body of lambda, because we don't evaluate anything + // until lambda definition is complete. + // + // For interactive top-level defs we want to evaluate as we go, + // so need incremental bindings. + + if (p_psm->env_stack_size() == 2) { + /* remember variable binding in lexical context, + * so we can refer to it later + */ + p_psm->upsert_var(this->def_expr_->lhs_variable()); + } + return; } @@ -174,8 +198,7 @@ namespace xo { define_xs::on_typedescr(TypeDescr td, parserstatemachine * p_psm) { - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); log && log("defxs_type", defxs_type_); @@ -183,6 +206,7 @@ namespace xo { this->defxs_type_ = defexprstatetype::def_4; this->cvt_expr_ = ConvertExprAccess::make(td /*dest_type*/, nullptr /*source_expr*/); + /* note: establishes .def_expr_ valuetype */ this->def_expr_->assign_rhs(this->cvt_expr_); return; } @@ -243,8 +267,7 @@ namespace xo { { /* def expr consumes semicolon */ - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); log && log("defxs_type", defxs_type_); @@ -253,32 +276,6 @@ namespace xo { std::unique_ptr self = p_psm->pop_exprstate(); - // if this is a genuine top-level define (i.e. nesting level = 0), - // then we need to upsert so we can refer to rhs later. - // - // In other contexts (e.g. body-of-lambda) will be rewriting - // { - // def y = foo(x,x); - // bar(y,y); - // } - // into something like - // { - // (lambda (y123) bar(y123,y123))(foo(x,x)); - // } - // - // This works in the body of lambda, because we don't evaluate anything - // until lambda definition is complete. - // - // For interactive top-level defs we want to evaluate as we go, - // so need incremental bindings. - - if (p_psm->env_stack_size() == 1) { - /* remember variable binding in lexical context, - * so we can refer to it later - */ - p_psm->upsert_var(def_expr->lhs_variable()); - } - p_psm->top_exprstate().on_expr(def_expr, p_psm); return; } @@ -357,11 +354,6 @@ namespace xo { << xtag("this", (void*)this) //<< xtag("type", exs_type_) << xtag("defxs_type", defxs_type_); - - //if (def_expr_) - // os << xtag("def_expr", def_expr_); - //if (cvt_expr_) - // os << xtag("cvt_expr", cvt_expr_); os << ">"; } } /*namespace scm*/ diff --git a/src/reader/expect_expr_xs.cpp b/src/reader/expect_expr_xs.cpp index 68a489b0..e899f3cb 100644 --- a/src/reader/expect_expr_xs.cpp +++ b/src/reader/expect_expr_xs.cpp @@ -6,8 +6,9 @@ #include "expect_expr_xs.hpp" #include "parserstatemachine.hpp" #include "exprstatestack.hpp" -#include "lambda_xs.hpp" #include "define_xs.hpp" +#include "lambda_xs.hpp" +#include "if_else_xs.hpp" #include "paren_xs.hpp" #include "sequence_xs.hpp" #include "progress_xs.hpp" @@ -52,12 +53,21 @@ namespace xo { cxl_on_rightbrace_{cxl_on_rightbrace} {} + const char * + expect_expr_xs::get_expect_str() const + { + if (allow_defs_) { + return "def|lambda|lparen|lbrace|literal|var"; + } else { + return "lambda|lparen|lbrace|literal|var"; + } + } + void expect_expr_xs::on_def_token(const token_type & tk, parserstatemachine * p_psm) { - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); if (allow_defs_) { define_xs::start(p_psm); @@ -70,20 +80,25 @@ namespace xo { expect_expr_xs::on_lambda_token(const token_type & /*tk*/, parserstatemachine * p_psm) { - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); //constexpr const char * self_name = "exprstate::on_leftparen"; lambda_xs::start(p_psm); } + void + expect_expr_xs::on_if_token(const token_type & /*tk*/, + parserstatemachine * p_psm) + { + if_else_xs::start(p_psm); + } + void expect_expr_xs::on_leftparen_token(const token_type & /*tk*/, parserstatemachine * p_psm) { - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); //constexpr const char * self_name = "exprstate::on_leftparen"; @@ -95,8 +110,7 @@ namespace xo { expect_expr_xs::on_leftbrace_token(const token_type & /*tk*/, parserstatemachine * p_psm) { - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); /* push lparen_0 to remember to look for subsequent rightparen. */ sequence_xs::start(p_psm); @@ -124,8 +138,7 @@ namespace xo { expect_expr_xs::on_symbol_token(const token_type & tk, parserstatemachine * p_psm) { - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); log && log(xtag("tk", tk)); @@ -199,8 +212,7 @@ namespace xo { expect_expr_xs::on_f64_token(const token_type & tk, parserstatemachine * p_psm) { - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); //constexpr const char * self_name = "exprstate::on_f64_token"; @@ -243,6 +255,14 @@ namespace xo { p_psm->on_expr_with_semicolon(expr); } /*on_expr_with_semicolon*/ + void + expect_expr_xs::print(std::ostream & os) const { + os << ""; + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader/expect_type_xs.cpp b/src/reader/expect_type_xs.cpp index 430a7004..f986ab50 100644 --- a/src/reader/expect_type_xs.cpp +++ b/src/reader/expect_type_xs.cpp @@ -43,7 +43,9 @@ namespace xo { /* TODO: replace with typetable lookup */ - if (tk.text() == "f64") + if (tk.text() == "bool") + td = Reflect::require(); + else if (tk.text() == "f64") td = Reflect::require(); else if(tk.text() == "f32") td = Reflect::require(); diff --git a/src/reader/exprseq_xs.cpp b/src/reader/exprseq_xs.cpp index b689831e..03314cd7 100644 --- a/src/reader/exprseq_xs.cpp +++ b/src/reader/exprseq_xs.cpp @@ -72,7 +72,7 @@ namespace xo { { /* in interactive session, allow top-level if-expressions. * Could be: - * if sometest() do_something() do_otherthing(); + * if sometest() then do_something() else do_otherthing(); */ if_else_xs::start(p_psm); } else { diff --git a/src/reader/exprstate.cpp b/src/reader/exprstate.cpp index d4b5e34a..07612db4 100644 --- a/src/reader/exprstate.cpp +++ b/src/reader/exprstate.cpp @@ -34,6 +34,8 @@ namespace xo { return "defexpr"; case exprstatetype::lambdaexpr: return "lambdaexpr"; + case exprstatetype::applyexpr: + return "applyexpr"; case exprstatetype::parenexpr: return "parenexpr"; case exprstatetype::sequenceexpr: @@ -450,6 +452,8 @@ namespace xo { case tokentype::tk_minus: case tokentype::tk_star: case tokentype::tk_slash: + case tokentype::tk_cmpeq: + case tokentype::tk_cmpne: this->on_operator_token(tk, p_psm); return; diff --git a/src/reader/progress_xs.cpp b/src/reader/progress_xs.cpp index ca137fdd..a09b8c26 100644 --- a/src/reader/progress_xs.cpp +++ b/src/reader/progress_xs.cpp @@ -1,6 +1,7 @@ /* @file progress_xs.cpp */ #include "progress_xs.hpp" +#include "apply_xs.hpp" #include "exprstatestack.hpp" #include "expect_expr_xs.hpp" #include "parserstatemachine.hpp" @@ -23,6 +24,18 @@ namespace xo { return "?optype"; case optype::op_assign: return "op:="; + case optype::op_less: + return "op<"; + case optype::op_less_equal: + return "op<="; + case optype::op_equal: + return "op=="; + case optype::op_not_equal: + return "op!="; + case optype::op_great: + return "op>"; + case optype::op_great_equal: + return "op>="; case optype::op_add: return "op+"; case optype::op_subtract: @@ -47,13 +60,21 @@ namespace xo { case optype::op_assign: return 1; + case optype::op_less: + case optype::op_less_equal: + case optype::op_equal: + case optype::op_not_equal: + case optype::op_great: + case optype::op_great_equal: + return 2; + case optype::op_add: case optype::op_subtract: - return 2; + return 3; case optype::op_multiply: case optype::op_divide: - return 3; + return 4; } return 0; @@ -145,21 +166,27 @@ namespace xo { this->rhs_); } + case optype::op_equal: + return Apply::make_cmp_eq_i64(lhs_, rhs_); + + case optype::op_less: + case optype::op_less_equal: + case optype::op_not_equal: + case optype::op_great: + case optype::op_great_equal: + assert(false); + case optype::op_add: - return Apply::make_add2_f64(this->lhs_, - this->rhs_); + return Apply::make_add2_f64(lhs_, rhs_); case optype::op_subtract: - return Apply::make_sub2_f64(this->lhs_, - this->rhs_); + return Apply::make_sub2_f64(lhs_, rhs_); case optype::op_multiply: - return Apply::make_mul2_f64(this->lhs_, - this->rhs_); + return Apply::make_mul2_f64(lhs_, rhs_); case optype::op_divide: - return Apply::make_div2_f64(this->lhs_, - this->rhs_); + return Apply::make_div2_f64(lhs_, rhs_); case optype::n_optype: /* unreachable */ @@ -301,8 +328,25 @@ namespace xo { progress_xs::on_leftparen_token(const token_type & tk, parserstatemachine * p_psm) { - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); + + /* input like: + * 'foo(' -> expect function call. might continue 'foo(a,b,c)' + * 'foo+(' -> expect parenthesized expression. might continue 'foo+(bar/2)' + */ + + if (op_type_ == optype::invalid) { + /* start function call */ + assert(rhs_.get() == nullptr); + + /* unwind this progress_xs + replace with function call */ + + rp fn_expr = lhs_; + std::unique_ptr self = p_psm->pop_exprstate(); + + apply_xs::start(fn_expr, p_psm); + return; + } constexpr const char * c_self_name = "exprstate::on_leftparen"; const char * exp = get_expect_str(); @@ -320,7 +364,7 @@ namespace xo { constexpr const char * self_name = "progress_xs::on_rightparen"; - auto p_stack = p_psm->p_stack_; + auto & xs_stack = p_psm->xs_stack_; /* stack may be something like: * @@ -338,12 +382,12 @@ namespace xo { std::unique_ptr self = p_psm->pop_exprstate(); - if (p_stack->empty()) { + if (xs_stack.empty()) { throw std::runtime_error(tostr(self_name, ": expected non-empty parsing stack")); } - log && log(xtag("stack", p_stack)); + log && log(xtag("stack", &xs_stack)); p_psm->top_exprstate().on_expr(expr, p_psm); @@ -406,6 +450,10 @@ namespace xo { return optype::op_multiply; case tokentype::tk_slash: return optype::op_divide; + case tokentype::tk_cmpeq: + return optype::op_equal; + case tokentype::tk_cmpne: + return optype::op_not_equal; default: assert(false); return optype::invalid; @@ -487,6 +535,22 @@ namespace xo { } } + void + progress_xs::on_bool_token(const token_type & tk, + parserstatemachine * p_psm) + { + scope log(XO_DEBUG(p_psm->debug_flag())); + + constexpr const char * c_self_name = "progress_xs::on_bool_token"; + const char * exp = get_expect_str(); + + if (this->op_type_ == optype::invalid) { + this->illegal_input_on_token(c_self_name, tk, exp, p_psm); + } else { + exprstate::on_bool_token(tk, p_psm); + } + } + void progress_xs::on_i64_token(const token_type & tk, parserstatemachine * p_psm) @@ -494,7 +558,7 @@ namespace xo { constexpr bool c_debug_flag = true; scope log(XO_DEBUG(c_debug_flag)); - constexpr const char * c_self_name = "progress_xs::on_i64"; + constexpr const char * c_self_name = "progress_xs::on_i64_token"; const char * exp = get_expect_str(); if (this->op_type_ == optype::invalid) { @@ -511,7 +575,7 @@ namespace xo { constexpr bool c_debug_flag = true; scope log(XO_DEBUG(c_debug_flag)); - constexpr const char * c_self_name = "progress_xs::on_f64"; + constexpr const char * c_self_name = "progress_xs::on_f64_token"; const char * exp = get_expect_str(); if (this->op_type_ == optype::invalid) { diff --git a/src/reader/reader.cpp b/src/reader/reader.cpp index 7f1080f3..37a64d6b 100644 --- a/src/reader/reader.cpp +++ b/src/reader/reader.cpp @@ -128,7 +128,8 @@ namespace xo { } } - log && log(xtag("outcome", "noop")); + log && log(xtag("outcome", "noop"), + xtag("parser.stack_size", parser_.stack_size())); return reader_result(nullptr, expr_span, parser_.stack_size(), reader_error()); }