xo-alloc/xo-reader2/src/reader2/DIfElseSsm.cpp

455 lines
15 KiB
C++

/** @file DIfElseSsm.cpp
*
* @author Roland Conybeare, Jul 2025
**/
#include "DIfElseSsm.hpp"
#include "ssm/ISyntaxStateMachine_DIfElseSsm.hpp"
#include "ssm/IPrintable_DDefineSsm.hpp"
#include "DExpectExprSsm.hpp"
#include <xo/expression2/detail/IPrintable_DIfElseExpr.hpp>
#include <xo/printable2/Printable.hpp>
#include <xo/facet/FacetRegistry.hpp>
//#include "exprstatestack.hpp"
//#include "parserstatemachine.hpp"
//#include "expect_expr_xs.hpp"
//#include "xo/indentlog/print/ppdetail_atomic.hpp"
namespace xo {
using xo::print::APrintable;
using xo::facet::FacetRegistry;
using xo::facet::with_facet;
using xo::reflect::typeseq;
namespace scm {
// ----- ifexprstatetype -----
const char *
ifexprstatetype_descr(ifexprstatetype x) {
switch (x) {
case ifexprstatetype::invalid: return "invalid";
case ifexprstatetype::if_0: return "if_0";
case ifexprstatetype::if_1: return "if_1";
case ifexprstatetype::if_2: return "if_2";
case ifexprstatetype::if_3: return "if_3";
case ifexprstatetype::if_4: return "if_4";
case ifexprstatetype::if_5: return "if_5";
case ifexprstatetype::if_6: return "if_6";
case ifexprstatetype::N: break;
}
return "ifexprstatetype?";
}
std::ostream &
operator<<(std::ostream & os, ifexprstatetype x) {
os << ifexprstatetype_descr(x);
return os;
}
// ----- DIfElseSsm -----
DIfElseSsm::DIfElseSsm(DIfElseExpr * ifelse_expr) : ifstate_{ifexprstatetype::if_0},
if_expr_{ifelse_expr}
{}
DIfElseSsm *
DIfElseSsm::_make(DArena & mm,
DIfElseExpr * ifelse_expr)
{
void * mem = mm.alloc(typeseq::id<DIfElseSsm>(),
sizeof(DIfElseSsm));
return new (mem) DIfElseSsm(ifelse_expr);
}
obj<ASyntaxStateMachine,DIfElseSsm>
DIfElseSsm::make(DArena & mm,
DIfElseExpr * ifelse_expr)
{
return obj<ASyntaxStateMachine,DIfElseSsm>(_make(mm, ifelse_expr));
}
void
DIfElseSsm::start(DArena & parser_mm,
obj<AAllocator> expr_mm,
ParserStateMachine * p_psm)
{
scope log(XO_DEBUG(p_psm->debug_flag()));
DArena::Checkpoint ckp = parser_mm.checkpoint();
DIfElseExpr * if_expr = DIfElseExpr::_make_empty(expr_mm);
auto ssm = DIfElseSsm::make(parser_mm, if_expr);
p_psm->push_ssm(ckp, ssm);
// note: triggers poly dispatch
p_psm->on_token(Token::if_token());
}
syntaxstatetype
DIfElseSsm::ssm_type() const noexcept
{
return syntaxstatetype::ifelseexpr;
}
std::string_view
DIfElseSsm::get_expect_str() const noexcept
{
/**
* if test-expr then then-expr else else-expr ;
* ^ ^ ^ ^ ^ ^ ^
* | | | | | | |
* | if_1 if_2 if_3 if_4 if_5 if_6
* if_0
*
* if_0 --on_if_token()--> if_1
* if_1 --on_expr()--> if_2
* if_2 --on_then_token()--> if_3
* if_3 --on_expr()--> if_4
* if_4 --on_else_token()--> if_5
* --on_semicolon_token()--> (done)
* if_5 --on_expr()-->if_6
* if_6 --on_semicolon_token()--> (done)
**/
switch (this->ifstate_) {
case ifexprstatetype::invalid:
case ifexprstatetype::N:
assert(false); // unreachable
break;
case ifexprstatetype::if_0:
return "if";
case ifexprstatetype::if_1:
return "expression";
case ifexprstatetype::if_2:
return "then";
case ifexprstatetype::if_3:
return "expression";
case ifexprstatetype::if_4:
return "else|semicolon";
case ifexprstatetype::if_5:
return "expression";
case ifexprstatetype::if_6:
return "semicolon";
}
return "?expect";
}
void
DIfElseSsm::on_token(const Token & tk,
ParserStateMachine * p_psm)
{
scope log(XO_DEBUG(p_psm->debug_flag()), xtag("tk", tk));
switch (tk.tk_type()) {
case tokentype::tk_symbol:
case tokentype::tk_def:
break;
case tokentype::tk_if:
this->on_if_token(tk, p_psm);
return;
case tokentype::tk_then:
this->on_then_token(tk, p_psm);
return;
case tokentype::tk_else:
this->on_else_token(tk, p_psm);
return;
case tokentype::tk_semicolon:
this->on_semicolon_token(tk, p_psm);
return;
case tokentype::tk_colon:
case tokentype::tk_singleassign:
case tokentype::tk_string:
case tokentype::tk_f64:
case tokentype::tk_i64:
case tokentype::tk_bool:
case tokentype::tk_invalid:
case tokentype::tk_leftparen:
case tokentype::tk_rightparen:
case tokentype::tk_leftbracket:
case tokentype::tk_rightbracket:
case tokentype::tk_leftbrace:
case tokentype::tk_rightbrace:
case tokentype::tk_leftangle:
case tokentype::tk_rightangle:
case tokentype::tk_lessequal:
case tokentype::tk_greatequal:
case tokentype::tk_dot:
case tokentype::tk_comma:
case tokentype::tk_doublecolon:
case tokentype::tk_assign:
case tokentype::tk_yields:
case tokentype::tk_plus:
case tokentype::tk_minus:
case tokentype::tk_star:
case tokentype::tk_slash:
case tokentype::tk_cmpeq:
case tokentype::tk_cmpne:
case tokentype::tk_type:
case tokentype::tk_lambda:
case tokentype::tk_let:
case tokentype::tk_in:
case tokentype::tk_end:
case tokentype::N:
break;
}
DSyntaxStateMachine<DIfElseSsm>::on_token(tk, p_psm);
}
void
DIfElseSsm::on_if_token(const Token & tk,
ParserStateMachine * p_psm)
{
scope log(XO_DEBUG(p_psm->debug_flag()));
log && log("ifstate", ifstate_);
if (ifstate_ == ifexprstatetype::if_0) {
this->ifstate_ = ifexprstatetype::if_1;
DExpectExprSsm::start(p_psm);
return;
}
DSyntaxStateMachine<DIfElseSsm>::on_token(tk, p_psm);
}
void
DIfElseSsm::on_then_token(const Token & tk,
ParserStateMachine * p_psm)
{
scope log(XO_DEBUG(p_psm->debug_flag()));
log && log("ifstate", ifstate_);
if (ifstate_ == ifexprstatetype::if_2) {
this->ifstate_ = ifexprstatetype::if_3;
DExpectExprSsm::start(p_psm);
return;
}
DSyntaxStateMachine<DIfElseSsm>::on_token(tk, p_psm);
}
void
DIfElseSsm::on_else_token(const Token & tk,
ParserStateMachine * p_psm)
{
scope log(XO_DEBUG(p_psm->debug_flag()));
log && log("ifstate", ifstate_);
if (ifstate_ == ifexprstatetype::if_4) {
this->ifstate_ = ifexprstatetype::if_5;
DExpectExprSsm::start(p_psm);
return;
}
DSyntaxStateMachine<DIfElseSsm>::on_token(tk, p_psm);
}
#ifdef NOT_YET
void
if_else_xs::finish_and_continue(parserstatemachine * p_psm)
{
rp<IfExprAccess> if_expr = this->if_expr_;
std::unique_ptr<exprstate> self = p_psm->pop_exprstate();
if (this->ifxs_type_ == ifexprstatetype::if_4) {
/* if no else-branch, then if-expr can't have valuetype */
if_expr->assign_valuetype(nullptr);
}
p_psm->top_exprstate().on_expr(if_expr, p_psm);
}
#endif
void
DIfElseSsm::finish_and_continue(ParserStateMachine * p_psm)
{
p_psm->pop_ssm();
// rp<IfExprAccess> if_expr = this->if_expr_;
// std::unique_ptr<exprstate> self = p_psm->pop_exprstate();
p_psm->on_parsed_expression(if_expr_);
}
#ifdef NOT_YET
void
if_else_xs::on_rightbrace_token(const token_type & tk,
parserstatemachine * p_psm)
{
scope log(XO_DEBUG(p_psm->debug_flag()));
this->finish_and_continue(p_psm);
p_psm->on_rightbrace_token(tk);
}
#endif
void
DIfElseSsm::on_semicolon_token(const Token & tk,
ParserStateMachine * p_psm)
{
scope log(XO_DEBUG(p_psm->debug_flag()));
log && log("ifstate", ifstate_);
switch (ifstate_) {
case ifexprstatetype::invalid:
case ifexprstatetype::N:
// unreachable
assert(false);
break;
case ifexprstatetype::if_0:
case ifexprstatetype::if_1:
case ifexprstatetype::if_2:
case ifexprstatetype::if_3:
case ifexprstatetype::if_5:
break;
case ifexprstatetype::if_4:
case ifexprstatetype::if_6:
this->finish_and_continue(p_psm);
return;
}
DSyntaxStateMachine<DIfElseSsm>::on_token(tk, p_psm);
}
#ifdef NOT_YET
void
if_else_xs::on_expr(bp<Expression> expr,
parserstatemachine * p_psm)
{
scope log(XO_DEBUG(p_psm->debug_flag()));
log && log(xtag("ifxs_type", ifxs_type_));
switch (this->ifxs_type_) {
case ifexprstatetype::invalid:
case ifexprstatetype::if_0:
case ifexprstatetype::n_ifexprstatetype:
assert(false); // unreachable
return;
case ifexprstatetype::if_1:
if_expr_->assign_test(expr.promote());
ifxs_type_ = ifexprstatetype::if_2;
return;
case ifexprstatetype::if_2:
/** error: expecting 'then' **/
break;
case ifexprstatetype::if_3:
if_expr_->assign_when_true(expr.promote());
ifxs_type_ = ifexprstatetype::if_4;
return;
case ifexprstatetype::if_4:
/** error: expecting 'else' or ';' **/
break;
case ifexprstatetype::if_5:
if_expr_->assign_when_false(expr.promote());
ifxs_type_ = ifexprstatetype::if_6;
return;
case ifexprstatetype::if_6:
/** error: expecting ';' **/
break;
}
constexpr const char* c_self_name = "if_else_xs::on_expr";
const char * exp = get_expect_str();
this->illegal_input_on_expr(c_self_name, expr, exp, p_psm);
}
#endif
void
DIfElseSsm::on_parsed_expression(obj<AExpression> expr,
ParserStateMachine * p_psm)
{
scope log(XO_DEBUG(p_psm->debug_flag()));
log && log(xtag("ifstate", ifstate_));
// if (ifstate_ == ...) { .... return; }
switch (ifstate_) {
case ifexprstatetype::invalid:
case ifexprstatetype::N:
assert(false);
break;
case ifexprstatetype::if_0:
// should be unreachable
break;
case ifexprstatetype::if_1:
if_expr_.data()->assign_test(expr);
this->ifstate_ = ifexprstatetype::if_2;
return;
case ifexprstatetype::if_2:
// error: expecting "then" token here
break;
case ifexprstatetype::if_3:
if_expr_.data()->assign_when_true(expr);
this->ifstate_ = ifexprstatetype::if_4;
return;
case ifexprstatetype::if_4:
// error: expecting "else" or ";"
break;
case ifexprstatetype::if_5:
if_expr_.data()->assign_when_false(expr);
this->ifstate_ = ifexprstatetype::if_6;
return;
case ifexprstatetype::if_6:
// error: expecting ";"
break;
}
DSyntaxStateMachine<DIfElseSsm>::on_parsed_expression(expr, p_psm);
}
void
DIfElseSsm::on_parsed_expression_with_token(obj<AExpression> expr,
const Token & tk,
ParserStateMachine * p_psm)
{
scope log(XO_DEBUG(p_psm->debug_flag()));
// TODO: may consider allowing if-else to terminate on other particular tokens
// e.g. ')'
if ((tk.tk_type() == tokentype::tk_then)
|| (tk.tk_type() == tokentype::tk_else)
|| (tk.tk_type() == tokentype::tk_semicolon))
{
this->on_parsed_expression(expr, p_psm);
this->on_token(tk, p_psm);
return;
}
Super::on_parsed_expression_with_token(expr, tk, p_psm);
}
bool
DIfElseSsm::pretty(const ppindentinfo & ppii) const
{
auto expr
= FacetRegistry::instance().variant<APrintable,
AExpression>(if_expr_);
assert(expr.data());
(void)expr;
return ppii.pps()->pretty_struct
(ppii,
"DIfElseSsm",
refrtag("ifstate", ifstate_),
refrtag("if_expr", expr));
}
} /*namespace scm*/
} /*namespace xo*/