xo-reader2: bugfix: need pattern match to fix operator precedence
This commit is contained in:
parent
2a03143127
commit
1fbbf70beb
3 changed files with 192 additions and 10 deletions
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "ExpectExprSsm.hpp"
|
||||
#include "ParserStateMachine.hpp"
|
||||
#include "ParserStack.hpp"
|
||||
#include "SyntaxStateMachine.hpp"
|
||||
#include "ssm/ISyntaxStateMachine_DProgressSsm.hpp"
|
||||
#include "DSequenceSsm.hpp"
|
||||
|
|
@ -28,15 +29,10 @@
|
|||
#include "paren_xs.hpp"
|
||||
#include "sequence_xs.hpp"
|
||||
#include "progress_xs.hpp"
|
||||
#include "xo/expression/Lambda.hpp"
|
||||
#include "xo/expression/Constant.hpp"
|
||||
#include "xo/expression/pretty_expression.hpp"
|
||||
#endif
|
||||
|
||||
namespace xo {
|
||||
#ifdef NOT_YET
|
||||
using xo::scm::Constant;
|
||||
#endif
|
||||
using xo::scm::DFloat;
|
||||
using xo::mm::AGCObject;
|
||||
|
||||
|
|
@ -372,6 +368,32 @@ namespace xo {
|
|||
|
||||
auto expr = DConstant::make(p_psm->expr_alloc(), i64o);
|
||||
|
||||
// Consider parser stack, with control here at b
|
||||
//
|
||||
// a * b - c
|
||||
// ^
|
||||
//
|
||||
// [1] ExpectExpr <-- this
|
||||
// [0] ProgressSsm :lhs k(b) :op * :rhs _
|
||||
//
|
||||
// if parent is ProgressSsm [0], need to deliver k(b) to it;
|
||||
// Then let that ProgressSsm [0] establish whether next token
|
||||
// is operator.
|
||||
//
|
||||
assert((void*)p_psm->stack()->top().data() == (void*)this);
|
||||
|
||||
if (p_psm->stack()->parent()) {
|
||||
auto parent_ssm = (obj<ASyntaxStateMachine,DProgressSsm>::from
|
||||
(p_psm->stack()->parent()->top()));
|
||||
|
||||
if (parent_ssm) {
|
||||
// parent is-a DProgressSsm instance
|
||||
p_psm->pop_ssm();
|
||||
p_psm->on_parsed_expression(expr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// DProgressSsm responsible for resolving cases like
|
||||
// 1,
|
||||
// 1;
|
||||
|
|
|
|||
|
|
@ -125,13 +125,13 @@ namespace xo {
|
|||
return optype::op_add;
|
||||
case tokentype::tk_minus: // [-]
|
||||
return optype::op_subtract;
|
||||
case tokentype::tk_star: // [*]
|
||||
case tokentype::tk_star: // [*]
|
||||
return optype::op_multiply;
|
||||
case tokentype::tk_slash: // [/]
|
||||
case tokentype::tk_slash: // [/]
|
||||
return optype::op_divide;
|
||||
case tokentype::tk_cmpeq: // [==]
|
||||
case tokentype::tk_cmpeq: // [==]
|
||||
return optype::op_equal;
|
||||
case tokentype::tk_cmpne:
|
||||
case tokentype::tk_cmpne: // [!=]
|
||||
return optype::op_not_equal;
|
||||
case tokentype::tk_leftangle:
|
||||
return optype::op_less;
|
||||
|
|
@ -362,7 +362,12 @@ namespace xo {
|
|||
ParserStateMachine * p_psm)
|
||||
{
|
||||
if (op_type_ == optype::invalid) {
|
||||
// tk is the operator this instance was waiting for
|
||||
// tk is the operator this instance was waiting for.
|
||||
// But need to consider precedence.
|
||||
// possibly need to take lhs_ expression and rotate it into new lhs of
|
||||
// surrounding ProgressSsm
|
||||
|
||||
|
||||
this->op_type_ = tk2op(tk.tk_type());
|
||||
|
||||
DExpectExprSsm::start(p_psm);
|
||||
|
|
@ -393,6 +398,7 @@ namespace xo {
|
|||
lhs2,
|
||||
op_type2,
|
||||
p_psm);
|
||||
DExpectExprSsm::start(p_psm);
|
||||
return;
|
||||
} else {
|
||||
/* associate to the right
|
||||
|
|
@ -512,6 +518,19 @@ namespace xo {
|
|||
log && log("accepting expr1");
|
||||
|
||||
this->lhs_ = expr;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
assert (op_type_ != optype::invalid);
|
||||
|
||||
if (!rhs_) {
|
||||
this->rhs_ = expr;
|
||||
|
||||
// need next token before we know whether this DProgressSsm
|
||||
// is complete. Consider input like 7 + 2 * 3 vs 7 * 2 + 3
|
||||
//
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -641,6 +641,147 @@ namespace xo {
|
|||
log && fixture.log_memory_layout(&log);
|
||||
}
|
||||
|
||||
TEST_CASE("SchematikaParser-interactive-arith3", "[reader2][SchematikaParser]")
|
||||
{
|
||||
const auto & testname = Catch::getResultCapture().getCurrentTestName();
|
||||
|
||||
constexpr bool c_debug_flag = false;
|
||||
scope log(XO_DEBUG(c_debug_flag), xtag("test", testname));
|
||||
|
||||
ParserFixture fixture(testname, c_debug_flag);
|
||||
auto & parser = *(fixture.parser_);
|
||||
|
||||
parser.begin_interactive_session();
|
||||
|
||||
/** Walkthrough parsing input equivalent to:
|
||||
*
|
||||
* 7 * 2 - 3;
|
||||
*
|
||||
**/
|
||||
|
||||
std::vector<Token> tk_v{
|
||||
Token::i64_token("7"),
|
||||
Token::star_token(),
|
||||
Token::i64_token("2"),
|
||||
Token::minus_token(),
|
||||
Token::i64_token("3"),
|
||||
Token::semicolon_token(),
|
||||
};
|
||||
|
||||
INFO(testname);
|
||||
|
||||
utest_tokenizer_loop(&parser, tk_v, c_debug_flag);
|
||||
|
||||
const auto & result = parser.result();
|
||||
{
|
||||
auto expr = obj<AExpression,DApplyExpr>::from(result.result_expr());
|
||||
REQUIRE(expr);
|
||||
REQUIRE(expr->n_args() == 2);
|
||||
|
||||
auto fn = obj<AExpression,DConstant>::from(expr->fn());
|
||||
REQUIRE(fn);
|
||||
|
||||
auto pm = obj<AGCObject,DPrimitive_gco_2_gco_gco>::from(fn->value());
|
||||
REQUIRE(pm);
|
||||
REQUIRE(pm->name() == "_sub");
|
||||
|
||||
auto lhs = obj<AExpression,DApplyExpr>::from(expr->arg(0));
|
||||
REQUIRE(lhs);
|
||||
|
||||
auto lhs_lhs = obj<AExpression,DConstant>::from(lhs->arg(0));
|
||||
REQUIRE(lhs_lhs);
|
||||
auto lhs_lhs_i64 = obj<AGCObject,DInteger>::from(lhs_lhs->value());
|
||||
REQUIRE(lhs_lhs_i64);
|
||||
REQUIRE(lhs_lhs_i64->value() == 7);
|
||||
|
||||
auto lhs_rhs = obj<AExpression,DConstant>::from(lhs->arg(1));
|
||||
REQUIRE(lhs_rhs);
|
||||
auto lhs_rhs_i64 = obj<AGCObject,DInteger>::from(lhs_rhs->value());
|
||||
REQUIRE(lhs_rhs_i64);
|
||||
REQUIRE(lhs_rhs_i64->value() == 2);
|
||||
|
||||
auto rhs = obj<AExpression,DConstant>::from(expr->arg(1));
|
||||
REQUIRE(rhs);
|
||||
|
||||
auto rhs_i64 = obj<AGCObject,DInteger>::from(rhs->value());
|
||||
REQUIRE(rhs_i64);
|
||||
REQUIRE(rhs_i64->value() == 3);
|
||||
}
|
||||
|
||||
log && fixture.log_memory_layout(&log);
|
||||
}
|
||||
|
||||
TEST_CASE("SchematikaParser-interactive-arith3-bad", "[reader2][SchematikaParser]")
|
||||
{
|
||||
const auto & testname = Catch::getResultCapture().getCurrentTestName();
|
||||
|
||||
constexpr bool c_debug_flag = true;
|
||||
scope log(XO_DEBUG(c_debug_flag), xtag("test", testname));
|
||||
|
||||
ParserFixture fixture(testname, c_debug_flag);
|
||||
auto & parser = *(fixture.parser_);
|
||||
|
||||
parser.begin_interactive_session();
|
||||
|
||||
/** Walkthrough parsing input equivalent to:
|
||||
*
|
||||
* 7 * 2 - 3 4;
|
||||
*
|
||||
**/
|
||||
|
||||
std::vector<Token> tk_v{
|
||||
Token::i64_token("7"),
|
||||
Token::star_token(),
|
||||
Token::i64_token("2"),
|
||||
Token::minus_token(),
|
||||
Token::i64_token("3"),
|
||||
Token::i64_token("4"),
|
||||
Token::semicolon_token(),
|
||||
};
|
||||
|
||||
INFO(testname);
|
||||
|
||||
utest_tokenizer_loop(&parser, tk_v, c_debug_flag);
|
||||
|
||||
const auto & result = parser.result();
|
||||
{
|
||||
auto expr = obj<AExpression,DApplyExpr>::from(result.result_expr());
|
||||
REQUIRE(expr);
|
||||
REQUIRE(expr->n_args() == 2);
|
||||
|
||||
auto fn = obj<AExpression,DConstant>::from(expr->fn());
|
||||
REQUIRE(fn);
|
||||
|
||||
auto pm = obj<AGCObject,DPrimitive_gco_2_gco_gco>::from(fn->value());
|
||||
REQUIRE(pm);
|
||||
REQUIRE(pm->name() == "_sub");
|
||||
|
||||
auto lhs = obj<AExpression,DApplyExpr>::from(expr->arg(0));
|
||||
REQUIRE(lhs);
|
||||
|
||||
auto lhs_lhs = obj<AExpression,DConstant>::from(lhs->arg(0));
|
||||
REQUIRE(lhs_lhs);
|
||||
auto lhs_lhs_i64 = obj<AGCObject,DInteger>::from(lhs_lhs->value());
|
||||
REQUIRE(lhs_lhs_i64);
|
||||
REQUIRE(lhs_lhs_i64->value() == 7);
|
||||
|
||||
auto lhs_rhs = obj<AExpression,DConstant>::from(lhs->arg(1));
|
||||
REQUIRE(lhs_rhs);
|
||||
auto lhs_rhs_i64 = obj<AGCObject,DInteger>::from(lhs_rhs->value());
|
||||
REQUIRE(lhs_rhs_i64);
|
||||
REQUIRE(lhs_rhs_i64->value() == 2);
|
||||
|
||||
auto rhs = obj<AExpression,DConstant>::from(expr->arg(1));
|
||||
REQUIRE(rhs);
|
||||
|
||||
auto rhs_i64 = obj<AGCObject,DInteger>::from(rhs->value());
|
||||
REQUIRE(rhs_i64);
|
||||
REQUIRE(rhs_i64->value() == 3);
|
||||
}
|
||||
|
||||
log && fixture.log_memory_layout(&log);
|
||||
}
|
||||
|
||||
TEST_CASE("SchematikaParser-interactive-cmp", "[reader2][SchematikaParser]")
|
||||
{
|
||||
const auto & testname = Catch::getResultCapture().getCurrentTestName();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue