Merge branch 'main' of github.com:Rconybea/xo-reader
This commit is contained in:
commit
fda9889207
8 changed files with 356 additions and 21 deletions
|
|
@ -125,6 +125,10 @@ namespace xo {
|
|||
virtual void on_rightparen_token(const token_type & tk,
|
||||
exprstatestack * p_stack,
|
||||
rp<Expression> * p_emit_expr);
|
||||
/** handle incoming operator token **/
|
||||
virtual void on_operator_token(const token_type & tk,
|
||||
exprstatestack * p_stack,
|
||||
rp<Expression> * p_emit_expr);
|
||||
/** handle incoming floating-point-literal token **/
|
||||
virtual void on_f64_token(const token_type & tk,
|
||||
exprstatestack * p_stack,
|
||||
|
|
|
|||
26
include/xo/reader/lambda_xs.hpp
Normal file
26
include/xo/reader/lambda_xs.hpp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/** @file lambda_xs.hpp
|
||||
*
|
||||
* Author: Roland Conybeare
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "exprstate.hpp"
|
||||
//#include <cstdint>
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
/** @class lambda_xs
|
||||
* @brief parsing state-machine for a lambda-expression
|
||||
**/
|
||||
class lambda_xs : public exprstate {
|
||||
public:
|
||||
lambda_xs();
|
||||
|
||||
private:
|
||||
};
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/** end lambda_xs.hpp **/
|
||||
|
|
@ -6,23 +6,49 @@
|
|||
#pragma once
|
||||
|
||||
#include "exprstate.hpp"
|
||||
#include <iostream>
|
||||
//#include <cstdint>
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
/* represent an infix operator */
|
||||
enum class optype {
|
||||
invalid = -1,
|
||||
|
||||
op_add,
|
||||
op_subtract,
|
||||
op_multiply,
|
||||
op_divide,
|
||||
|
||||
n_optype
|
||||
};
|
||||
|
||||
extern const char *
|
||||
optype_descr(optype x);
|
||||
|
||||
extern int
|
||||
precedence(optype x);
|
||||
|
||||
inline std::ostream &
|
||||
operator<< (std::ostream & os, optype x) {
|
||||
os << optype_descr(x);
|
||||
return os;
|
||||
}
|
||||
|
||||
/** @class progress_xs
|
||||
* @brief state machine for parsing a schematica runtime-value-expression
|
||||
**/
|
||||
class progress_xs : public exprstate {
|
||||
public:
|
||||
progress_xs(rp<Expression> valex);
|
||||
progress_xs(rp<Expression> valex, optype op);
|
||||
virtual ~progress_xs() = default;
|
||||
|
||||
static const progress_xs * from(const exprstate * x) {
|
||||
return dynamic_cast<const progress_xs *>(x);
|
||||
}
|
||||
|
||||
static std::unique_ptr<progress_xs> make(rp<Expression> valex);
|
||||
static std::unique_ptr<progress_xs> make(rp<Expression> valex,
|
||||
optype optype = optype::invalid);
|
||||
|
||||
bool admits_f64() const;
|
||||
|
||||
|
|
@ -51,6 +77,12 @@ namespace xo {
|
|||
virtual void on_rightparen_token(const token_type & tk,
|
||||
exprstatestack * p_stack,
|
||||
rp<Expression> * /*p_emit_expr*/) override;
|
||||
|
||||
/* entry point for an infix operator token */
|
||||
virtual void on_operator_token(const token_type & tk,
|
||||
exprstatestack * p_stack,
|
||||
rp<Expression> * p_emit_expr) override;
|
||||
|
||||
virtual void on_f64_token(const token_type & tk,
|
||||
exprstatestack * p_stack,
|
||||
rp<Expression> * /*p_emit_expr*/) override;
|
||||
|
|
@ -58,8 +90,25 @@ namespace xo {
|
|||
virtual void print(std::ostream & os) const override;
|
||||
|
||||
private:
|
||||
/** populate an expression here **/
|
||||
rp<Expression> gen_expr_;
|
||||
/** assemble expression representing
|
||||
* value of
|
||||
* @code
|
||||
* f(lhs_, rhs_)
|
||||
* @endcode
|
||||
*
|
||||
* where f determined by @ref op_type_
|
||||
**/
|
||||
rp<Expression> assemble_expr();
|
||||
|
||||
private:
|
||||
/** populate an expression here, may be followed by an operator **/
|
||||
rp<Expression> lhs_;
|
||||
|
||||
/** infix operator, if supplied **/
|
||||
optype op_type_ = optype::invalid;
|
||||
|
||||
/** populate an expression here, following infix operator */
|
||||
rp<Expression> rhs_;
|
||||
};
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ set(SELF_SRCS
|
|||
expect_expr_xs.cpp
|
||||
expect_symbol_xs.cpp
|
||||
expect_formal_xs.cpp
|
||||
expect_type_xs.cpp)
|
||||
expect_type_xs.cpp
|
||||
lambda_xs.cpp)
|
||||
|
||||
xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS})
|
||||
xo_dependency(${SELF_LIB} xo_expression)
|
||||
|
|
|
|||
|
|
@ -168,6 +168,19 @@ namespace xo {
|
|||
this->illegal_input_error(self_name, tk);
|
||||
}
|
||||
|
||||
void
|
||||
exprstate::on_operator_token(const token_type & tk,
|
||||
exprstatestack * /*p_stack*/,
|
||||
rp<Expression> * /*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*/,
|
||||
|
|
@ -252,6 +265,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:
|
||||
|
|
|
|||
13
src/reader/lambda_xs.cpp
Normal file
13
src/reader/lambda_xs.cpp
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
/* @file lambda_xs.cpp */
|
||||
|
||||
#include "lambda_xs.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
lambda_xs::lambda_xs() {}
|
||||
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end lambda_xs.cpp */
|
||||
|
|
@ -1,17 +1,61 @@
|
|||
/* @file progress_xs.cpp */
|
||||
|
||||
#include "progress_xs.hpp"
|
||||
#include "expect_expr_xs.hpp"
|
||||
#include "xo/expression/Apply.hpp"
|
||||
|
||||
namespace xo {
|
||||
using xo::ast::Expression;
|
||||
using xo::ast::Apply;
|
||||
|
||||
namespace scm {
|
||||
std::unique_ptr<progress_xs>
|
||||
progress_xs::make(rp<Expression> valex) {
|
||||
return std::make_unique<progress_xs>(progress_xs(std::move(valex)));
|
||||
const char *
|
||||
optype_descr(optype x) {
|
||||
switch (x) {
|
||||
case optype::invalid:
|
||||
return "?optype";
|
||||
case optype::op_add:
|
||||
return "op+";
|
||||
case optype::op_subtract:
|
||||
return "op-";
|
||||
case optype::op_multiply:
|
||||
return "op*";
|
||||
case optype::op_divide:
|
||||
return "op/";
|
||||
case optype::n_optype:
|
||||
break;
|
||||
}
|
||||
return "???";
|
||||
}
|
||||
|
||||
progress_xs::progress_xs(rp<Expression> valex)
|
||||
int
|
||||
precedence(optype x) {
|
||||
switch (x) {
|
||||
case optype::invalid:
|
||||
case optype::n_optype:
|
||||
return 0;
|
||||
|
||||
case optype::op_add:
|
||||
case optype::op_subtract:
|
||||
return 1;
|
||||
|
||||
case optype::op_multiply:
|
||||
case optype::op_divide:
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::unique_ptr<progress_xs>
|
||||
progress_xs::make(rp<Expression> valex, optype op) {
|
||||
return std::make_unique<progress_xs>(progress_xs(std::move(valex), op));
|
||||
}
|
||||
|
||||
progress_xs::progress_xs(rp<Expression> valex, optype op)
|
||||
: exprstate(exprstatetype::expr_progress),
|
||||
gen_expr_{std::move(valex)}
|
||||
lhs_{std::move(valex)},
|
||||
op_type_{op}
|
||||
{}
|
||||
|
||||
bool
|
||||
|
|
@ -27,13 +71,85 @@ namespace xo {
|
|||
this->illegal_input_error(self_name, tk) ;
|
||||
}
|
||||
|
||||
rp<Expression>
|
||||
progress_xs::assemble_expr() {
|
||||
/* need to defer building Apply incase expr followed by higher-precedence operator:
|
||||
* consider input like
|
||||
* 3.14 + 2.0 * ...
|
||||
*/
|
||||
|
||||
constexpr const char * c_self_name = "progress_xs::assemble_expr";
|
||||
|
||||
if ((op_type_ != optype::invalid) && (rhs_.get() == nullptr)) {
|
||||
throw std::runtime_error(tostr(c_self_name,
|
||||
": expected expr on rhs of operator",
|
||||
xtag("lhs", lhs_),
|
||||
xtag("op", op_type_)));
|
||||
}
|
||||
|
||||
/* consecutive expressions not legal, e.g:
|
||||
* 3.14 6.28
|
||||
* but expressions surrounding an infix operators is:
|
||||
* 3.14 / 6.28
|
||||
*/
|
||||
switch (op_type_) {
|
||||
case optype::invalid:
|
||||
return this->lhs_;
|
||||
|
||||
case optype::op_add:
|
||||
return Apply::make_add2_f64(this->lhs_,
|
||||
this->rhs_);
|
||||
|
||||
case optype::op_subtract:
|
||||
return Apply::make_sub2_f64(this->lhs_,
|
||||
this->rhs_);
|
||||
|
||||
case optype::op_multiply:
|
||||
return Apply::make_mul2_f64(this->lhs_,
|
||||
this->rhs_);
|
||||
|
||||
case optype::op_divide:
|
||||
return Apply::make_div2_f64(this->lhs_,
|
||||
this->rhs_);
|
||||
|
||||
case optype::n_optype:
|
||||
/* unreachable */
|
||||
assert(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
progress_xs::on_expr(ref::brw<Expression> /*expr*/,
|
||||
progress_xs::on_expr(ref::brw<Expression> expr,
|
||||
exprstatestack * /*p_stack*/,
|
||||
rp<Expression> * /*p_emit_expr*/)
|
||||
{
|
||||
/* consecutive expressions isn't legal */
|
||||
assert(false);
|
||||
/* note: previous token probably an operator,
|
||||
* handled from progress_xs::on_operator_token(),
|
||||
* which pushes expect_expr_xs::expect_rhs_expression()
|
||||
*/
|
||||
|
||||
constexpr const char * c_self_name = "progress_xs::on_expr";
|
||||
|
||||
|
||||
if (op_type_ == optype::invalid) {
|
||||
throw std::runtime_error(tostr(c_self_name,
|
||||
": consecutive unseparated exprs not legal"));
|
||||
}
|
||||
|
||||
#ifdef NOT_QUITE
|
||||
assert(result.get());
|
||||
|
||||
/* this expression complete.. */
|
||||
std::unique_ptr<exprstate> self = p_stack->pop_exprstate();
|
||||
|
||||
/* ..but more operators could follow, so don't commit yet */
|
||||
p_stack->push_exprstate(progress_xs::make(result));
|
||||
#endif
|
||||
|
||||
this->rhs_ = expr.promote();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -70,12 +186,14 @@ namespace xo {
|
|||
exprstatestack * p_stack,
|
||||
rp<Expression> * p_emit_expr)
|
||||
{
|
||||
/* note: implementation parllels .on_rightparen_token() */
|
||||
|
||||
constexpr bool c_debug_flag = true;
|
||||
scope log(XO_DEBUG(c_debug_flag));
|
||||
|
||||
rp<Expression> expr = this->gen_expr_;
|
||||
rp<Expression> expr = this->assemble_expr();
|
||||
|
||||
std::unique_ptr<exprstate> self = p_stack->pop_exprstate(); /* NOT KOSHER. invalidates *this */
|
||||
std::unique_ptr<exprstate> self = p_stack->pop_exprstate();
|
||||
|
||||
p_stack->top_exprstate().on_expr(expr,
|
||||
p_stack,
|
||||
|
|
@ -125,6 +243,9 @@ namespace xo {
|
|||
exprstatestack * p_stack,
|
||||
rp<Expression> * p_emit_expr)
|
||||
{
|
||||
/* note: implementation parallels .on_semicolon_token() */
|
||||
|
||||
|
||||
constexpr bool c_debug_flag = true;
|
||||
scope log(XO_DEBUG(c_debug_flag));
|
||||
|
||||
|
|
@ -142,7 +263,7 @@ namespace xo {
|
|||
*/
|
||||
|
||||
/* right paren confirms stack expression */
|
||||
rp<Expression> expr = this->gen_expr_;
|
||||
rp<Expression> expr = this->assemble_expr();
|
||||
|
||||
std::unique_ptr<exprstate> self = p_stack->pop_exprstate();
|
||||
|
||||
|
|
@ -160,25 +281,125 @@ namespace xo {
|
|||
|
||||
}
|
||||
|
||||
namespace {
|
||||
optype
|
||||
tk2op(const tokentype & tktype) {
|
||||
switch (tktype) {
|
||||
case tokentype::tk_plus:
|
||||
return optype::op_add;
|
||||
case tokentype::tk_minus:
|
||||
return optype::op_subtract;
|
||||
case tokentype::tk_star:
|
||||
return optype::op_multiply;
|
||||
case tokentype::tk_slash:
|
||||
return optype::op_divide;
|
||||
default:
|
||||
assert(false);
|
||||
return optype::invalid;
|
||||
}
|
||||
return optype::invalid;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
progress_xs::on_operator_token(const token_type & tk,
|
||||
exprstatestack * p_stack,
|
||||
rp<Expression> * /*p_emit_expr*/)
|
||||
{
|
||||
constexpr const char * c_self_name = "progress_xs::on_operator_token";
|
||||
|
||||
if (op_type_ == optype::invalid) {
|
||||
this->op_type_ = tk2op(tk.tk_type());
|
||||
|
||||
/* infix operator must be followed by non-empty expression */
|
||||
p_stack->push_exprstate(expect_expr_xs::expect_rhs_expression());
|
||||
} else if (rhs_) {
|
||||
/* already have complete expression stashed.
|
||||
* behavior depends on operator precedence for tk with stored operator
|
||||
* this->op_type_
|
||||
*/
|
||||
optype op2 = tk2op(tk.tk_type());
|
||||
|
||||
if (precedence(op2) <= precedence(this->op_type_)) {
|
||||
/* e.g.
|
||||
* 6.2 * 4.9 + ...
|
||||
*
|
||||
* in stack:
|
||||
* 1. progress_xs lhs=6.2, op=*, rhs=4.9
|
||||
*
|
||||
* out stack
|
||||
* 1. progress_xs lhs=apply(*,6.2,4.9), op=+
|
||||
*/
|
||||
|
||||
/* 1. instantiate expression for *this */
|
||||
auto expr = this->assemble_expr();
|
||||
|
||||
/* 2. remove from stack */
|
||||
std::unique_ptr<exprstate> self = p_stack->pop_exprstate();
|
||||
|
||||
/* 3. replace with new progress_xs: */
|
||||
p_stack->push_exprstate(progress_xs::make(expr, op2));
|
||||
|
||||
/* infix operator must be followed by non-empty expression */
|
||||
p_stack->push_exprstate(expect_expr_xs::expect_rhs_expression());
|
||||
} else {
|
||||
/* e.g.
|
||||
* 6.2 + 4.9 * ...
|
||||
*
|
||||
* in stack:
|
||||
* 1. progress_xs lhs=6.2, op=+, rhs=4.9
|
||||
*
|
||||
* out stack:
|
||||
* 1. progress_xs lhs=6.2, op=+
|
||||
* 2. expect_rhs_expression
|
||||
* 3. progress_xs lhs=4.9, op=*
|
||||
* 4. expect_rhs_expression
|
||||
*/
|
||||
|
||||
std::unique_ptr<exprstate> self = p_stack->pop_exprstate();
|
||||
|
||||
/* 1. replace with nested incomplete infix exprs */
|
||||
p_stack->push_exprstate(progress_xs::make(lhs_, op_type_));
|
||||
p_stack->push_exprstate(expect_expr_xs::expect_rhs_expression());
|
||||
p_stack->push_exprstate(progress_xs::make(rhs_, op2));
|
||||
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<Expression> * /*p_emit_expr*/)
|
||||
exprstatestack * p_stack,
|
||||
rp<Expression> * 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
|
||||
progress_xs::print(std::ostream & os) const {
|
||||
os << "<progress_xs"
|
||||
<< xtag("type", exs_type_);
|
||||
if (gen_expr_)
|
||||
os << xtag("gen_expr", gen_expr_);
|
||||
if (lhs_)
|
||||
os << xtag("lhs", lhs_);
|
||||
if (op_type_ != optype::invalid)
|
||||
os << xtag("op", op_type_);
|
||||
if (rhs_)
|
||||
os << xtag("rhs", rhs_);
|
||||
os << ">";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ namespace xo {
|
|||
|
||||
std::vector<test_case> 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;"}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue