Merge branch 'main' of github.com:Rconybea/xo-reader

This commit is contained in:
Roland Conybeare 2024-08-16 22:15:26 -04:00
commit fda9889207
8 changed files with 356 additions and 21 deletions

View file

@ -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,

View 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 **/

View file

@ -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*/

View file

@ -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)

View file

@ -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
View 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 */

View file

@ -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 << ">";
}

View file

@ -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;"}
};
}