From 29596a7c1dc3f91bd8719fbbb9d16c6e7e8ac11e Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 14 Aug 2024 23:44:17 -0400 Subject: [PATCH] xo-reader: feat: parse infix exprs for +,-,*,/ operators --- include/xo/reader/exprstate.hpp | 4 ++ include/xo/reader/progress_xs.hpp | 21 +++++++ src/reader/exprstate.cpp | 20 ++++++ src/reader/progress_xs.cpp | 101 +++++++++++++++++++++++++++--- utest/reader.test.cpp | 3 +- 5 files changed, 141 insertions(+), 8 deletions(-) diff --git a/include/xo/reader/exprstate.hpp b/include/xo/reader/exprstate.hpp index ef65e8f5..d109f280 100644 --- a/include/xo/reader/exprstate.hpp +++ b/include/xo/reader/exprstate.hpp @@ -121,6 +121,10 @@ namespace xo { virtual void on_rightparen_token(const token_type & tk, exprstatestack * p_stack, rp * p_emit_expr); + /** handle incoming operator token **/ + virtual void on_operator_token(const token_type & tk, + exprstatestack * p_stack, + rp * p_emit_expr); /** handle incoming floating-point-literal token **/ virtual void on_f64_token(const token_type & tk, exprstatestack * p_stack, diff --git a/include/xo/reader/progress_xs.hpp b/include/xo/reader/progress_xs.hpp index 361e6d3d..9a7381c7 100644 --- a/include/xo/reader/progress_xs.hpp +++ b/include/xo/reader/progress_xs.hpp @@ -10,6 +10,18 @@ namespace xo { namespace scm { + /* represent an infix operator */ + enum class optype { + invalid = -1, + + op_add, + op_subtract, + op_multiply, + op_divide, + + n_optype + }; + /** @class progress_xs * @brief state machine for parsing a schematica runtime-value-expression **/ @@ -49,6 +61,12 @@ namespace xo { virtual void on_rightparen_token(const token_type & tk, exprstatestack * p_stack, rp * /*p_emit_expr*/) override; + + /* entry point for an infix operator token */ + virtual void on_operator_token(const token_type & tk, + exprstatestack * p_stack, + rp * p_emit_expr) override; + virtual void on_f64_token(const token_type & tk, exprstatestack * p_stack, rp * /*p_emit_expr*/) override; @@ -58,6 +76,9 @@ namespace xo { private: /** populate an expression here **/ rp gen_expr_; + + /** infix operator, if supplied **/ + optype op_type_ = optype::invalid; }; } /*namespace scm*/ } /*namespace xo*/ diff --git a/src/reader/exprstate.cpp b/src/reader/exprstate.cpp index e7933d7c..1985aa7d 100644 --- a/src/reader/exprstate.cpp +++ b/src/reader/exprstate.cpp @@ -136,6 +136,19 @@ namespace xo { this->illegal_input_error(self_name, tk); } + void + exprstate::on_operator_token(const token_type & tk, + exprstatestack * /*p_stack*/, + rp * /*p_emit_expr*/) + { + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag)); + + constexpr const char * self_name = "exprstate::on_operator_token"; + + this->illegal_input_error(self_name, tk); + } + void exprstate::on_f64_token(const token_type & tk, exprstatestack * /*p_stack*/, @@ -220,6 +233,13 @@ namespace xo { case tokentype::tk_assign: case tokentype::tk_yields: + case tokentype::tk_plus: + case tokentype::tk_minus: + case tokentype::tk_star: + case tokentype::tk_slash: + this->on_operator_token(tk, p_stack, p_emit_expr); + return; + case tokentype::tk_type: case tokentype::tk_lambda: case tokentype::tk_if: diff --git a/src/reader/progress_xs.cpp b/src/reader/progress_xs.cpp index 4d78fb8a..241c5da4 100644 --- a/src/reader/progress_xs.cpp +++ b/src/reader/progress_xs.cpp @@ -1,8 +1,12 @@ /* @file progress_xs.cpp */ #include "progress_xs.hpp" +#include "expect_expr_xs.hpp" +#include "xo/expression/Apply.hpp" namespace xo { + using xo::ast::Apply; + namespace scm { std::unique_ptr progress_xs::make(rp valex) { @@ -28,12 +32,54 @@ namespace xo { } void - progress_xs::on_expr(ref::brw /*expr*/, - exprstatestack * /*p_stack*/, + progress_xs::on_expr(ref::brw expr, + exprstatestack * p_stack, rp * /*p_emit_expr*/) { + constexpr const char * c_self_name = "progress_xs::on_expr"; + + rp result; + /* consecutive expressions isn't legal */ - assert(false); + switch (op_type_) { + case optype::invalid: + throw std::runtime_error(tostr(c_self_name, + ": consecutive unseparated exprs not legal")); + + break; + + case optype::op_add: + result = Apply::make_add2_f64(this->gen_expr_ /*lhs*/, + expr.promote() /*rhs*/); + break; + + case optype::op_subtract: + result = Apply::make_sub2_f64(this->gen_expr_ /*lhs*/, + expr.promote() /*rhs*/); + break; + + case optype::op_multiply: + result = Apply::make_mul2_f64(this->gen_expr_ /*lhs*/, + expr.promote() /*rhs*/); + break; + + case optype::op_divide: + result = Apply::make_div2_f64(this->gen_expr_ /*lhs*/, + expr.promote() /*rhs*/); + break; + + case optype::n_optype: + /* unreachable */ + assert(false); + } + + assert(result.get()); + + /* this expression complete.. */ + std::unique_ptr self = p_stack->pop_exprstate(); + + /* ..but more operators could follow, so don't commit yet */ + p_stack->push_exprstate(progress_xs::make(result)); } void @@ -75,7 +121,7 @@ namespace xo { rp expr = this->gen_expr_; - std::unique_ptr self = p_stack->pop_exprstate(); /* NOT KOSHER. invalidates *this */ + std::unique_ptr self = p_stack->pop_exprstate(); p_stack->top_exprstate().on_expr(expr, p_stack, @@ -160,17 +206,58 @@ namespace xo { } + void + progress_xs::on_operator_token(const token_type & tk, + exprstatestack * p_stack, + rp * p_emit_expr) + { + constexpr const char * c_self_name = "progress_xs::on_operator_token"; + + if (op_type_ == optype::invalid) { + switch(tk.tk_type()) { + case tokentype::tk_plus: + this->op_type_ = optype::op_add; + break; + case tokentype::tk_minus: + this->op_type_ = optype::op_subtract; + break; + case tokentype::tk_star: + this->op_type_ = optype::op_multiply; + break; + case tokentype::tk_slash: + this->op_type_ = optype::op_divide; + break; + default: + /* unreachable */ + assert(false); + exprstate::on_operator_token(tk, p_stack, p_emit_expr); + } + + /* infix operator must be followed by non-empty expression */ + p_stack->push_exprstate(expect_expr_xs::expect_rhs_expression()); + } else { + throw std::runtime_error(tostr(c_self_name, + ": expected expression following operator", + xtag("tk", tk))); + } + } + void progress_xs::on_f64_token(const token_type & tk, - exprstatestack * /*p_stack*/, - rp * /*p_emit_expr*/) + exprstatestack * p_stack, + rp * p_emit_expr) { constexpr bool c_debug_flag = true; scope log(XO_DEBUG(c_debug_flag)); constexpr const char * self_name = "progress_xs::on_f64"; - this->illegal_input_error(self_name, tk); + if (this->op_type_ == optype::invalid) { + this->illegal_input_error(self_name, tk); + } else { + assert(false); + exprstate::on_f64_token(tk, p_stack, p_emit_expr); + } } void diff --git a/utest/reader.test.cpp b/utest/reader.test.cpp index 8aff0011..fb4a170d 100644 --- a/utest/reader.test.cpp +++ b/utest/reader.test.cpp @@ -14,7 +14,8 @@ namespace xo { std::vector s_testcase_v = { {"def foo : f64 = 3.14159265;"}, - {"def foo : f64 = (3.14159265);"} + {"def foo : f64 = (3.14159265);"}, + {"def foo : f64 = 2.0 * 3.14159265;"} }; }