/** @file DParenSsm.cpp * * @author Roland Conybeare, Feb 2026 **/ #include "ParenSsm.hpp" #include "ExpectExprSsm.hpp" #include "syntaxstatetype.hpp" #include namespace xo { using xo::facet::with_facet; using xo::facet::typeseq; namespace scm { extern const char * parenexprstatetype_descr(parenexprstatetype x) { switch(x) { case parenexprstatetype::invalid: return "invalid"; case parenexprstatetype::lparen_0: return "lparen_0"; case parenexprstatetype::lparen_1: return "lparen_1"; case parenexprstatetype::lparen_2: return "lparen_2"; case parenexprstatetype::N: break; } return "???parenexprstatetype"; } std::ostream & operator<<(std::ostream & os, parenexprstatetype x) { os << parenexprstatetype_descr(x); return os; } DParenSsm::DParenSsm() : parenstate_(parenexprstatetype::lparen_0), expr_{} {} DParenSsm * DParenSsm::_make(DArena & mm) { void * mem = mm.alloc(typeseq::id(), sizeof(DParenSsm)); return new (mem) DParenSsm(); } obj DParenSsm::make(DArena & mm) { return obj(_make(mm)); } void DParenSsm::start(ParserStateMachine * p_psm) { DArena::Checkpoint ckp = p_psm->parser_alloc().checkpoint(); auto paren_ssm = DParenSsm::make(p_psm->parser_alloc()); p_psm->push_ssm(ckp, paren_ssm); } syntaxstatetype DParenSsm::ssm_type() const noexcept { return syntaxstatetype::paren; } std::string_view DParenSsm::get_expect_str() const noexcept { switch (this->parenstate_) { case parenexprstatetype::invalid: case parenexprstatetype::N: break; case parenexprstatetype::lparen_0: return "leftparen"; case parenexprstatetype::lparen_1: return "expression"; case parenexprstatetype::lparen_2: return "rightparen"; } return "???parenexprstatetype"; } void DParenSsm::on_token(const Token & tk, ParserStateMachine * p_psm) { switch (tk.tk_type()) { case tokentype::tk_leftparen: this->on_leftparen_token(tk, p_psm); return; case tokentype::tk_rightparen: this->on_rightparen_token(tk, p_psm); return; // all the not-yet handled cases case tokentype::tk_symbol: case tokentype::tk_def: case tokentype::tk_colon: case tokentype::tk_singleassign: case tokentype::tk_semicolon: case tokentype::tk_invalid: case tokentype::tk_string: case tokentype::tk_f64: case tokentype::tk_i64: case tokentype::tk_bool: case tokentype::tk_if: 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_then: case tokentype::tk_else: case tokentype::tk_let: case tokentype::tk_in: case tokentype::tk_end: case tokentype::N: break; } Super::on_token(tk, p_psm); } void DParenSsm::on_leftparen_token(const Token & tk, ParserStateMachine * p_psm) { if (parenstate_ == parenexprstatetype::lparen_0) { this->parenstate_ = parenexprstatetype::lparen_1; /** 1. allow_defs=false not allowing definitions immediately * within a parenthesized expression. * e.g. * (def y : i64 = 4; x + y) // nope * 2. cxl_on_rightparen=false expression _must_ be followed * by rightparen. empty parentheses '()' * do not denote anything, in expression context **/ DExpectExprSsm::start(p_psm); return; } Super::on_token(tk, p_psm); } #ifdef OBSOLETE void paren_xs::start(parserstatemachine * p_psm) { p_psm->push_exprstate(paren_xs::make()); expect_expr_xs::start(p_psm); } bool paren_xs::admits_rightparen() const { switch (parenxs_type_) { case parenexprstatetype::lparen_0: /* unreachable */ assert(false); return false; case parenexprstatetype::lparen_1: return true; case parenexprstatetype::invalid: case parenexprstatetype::n_parenexprstatetype: /* unreachable */ assert(false); return false; } return false; } bool paren_xs::admits_f64() const { switch (parenxs_type_) { case parenexprstatetype::lparen_0: return true; case parenexprstatetype::lparen_1: return false; case parenexprstatetype::invalid: case parenexprstatetype::n_parenexprstatetype: /* unreachable */ assert(false); return false; } return false; } void paren_xs::on_def_token(const token_type & tk, parserstatemachine * /*p_psm*/) { constexpr const char * c_self_name = "paren_xs::on_def"; this->illegal_input_error(c_self_name, tk); } void paren_xs::on_symbol_token(const token_type & /*tk*/, parserstatemachine * p_psm) { constexpr bool c_debug_flag = true; scope log(XO_DEBUG(c_debug_flag)); log && log(xtag("exstype", p_psm->top_exprstate().exs_type())); //constexpr const char * self_name = "paren_xs::on_symbol"; /* TODO: lparen_0: treat as variable reference */ assert(false); } void paren_xs::on_typedescr(TypeDescr /*td*/, parserstatemachine * /*p_psm*/) { assert(false); return; } void paren_xs::on_colon_token(const token_type & tk, parserstatemachine * /*p_psm*/) { constexpr const char * c_self_name = "paren_xs::on_colon"; this->illegal_input_error(c_self_name, tk); } void paren_xs::on_semicolon_token(const token_type & tk, parserstatemachine * /*p_psm*/) { constexpr const char * c_self_name = "paren_xs::on_semicolon"; this->illegal_input_error(c_self_name, tk); } void paren_xs::on_singleassign_token(const token_type & tk, parserstatemachine * /*p_psm*/) { constexpr const char * c_self_name = "paren_xs::on_singleassign"; this->illegal_input_error(c_self_name, tk); } void paren_xs::on_leftparen_token(const token_type & tk, parserstatemachine * /*p_psm*/) { constexpr const char * c_self_name = "paren_xs::on_leftparen"; this->illegal_input_error(c_self_name, tk); } #endif void DParenSsm::on_rightparen_token(const Token & tk, ParserStateMachine * p_psm) { if (this->parenstate_ == parenexprstatetype::lparen_2) { // parenthesized expression successfully parsed p_psm->pop_ssm(); p_psm->on_parsed_expression(this->expr_); return; } Super::on_token(tk, p_psm); } #ifdef NOT_YET void paren_xs::on_rightparen_token(const token_type & tk, parserstatemachine * p_psm) { constexpr bool c_debug_flag = true; scope log(XO_DEBUG(c_debug_flag)); constexpr const char * c_self_name = "paren_xs::on_rightparen"; if (!this->admits_rightparen()) { this->illegal_input_error(c_self_name, tk); } if (this->parenxs_type_ == parenexprstatetype::lparen_1) { rp expr = this->gen_expr_; std::unique_ptr self = p_psm->pop_exprstate(); p_psm->top_exprstate().on_expr(expr, p_psm); } } void paren_xs::on_i64_token(const token_type & tk, parserstatemachine * /*p_psm*/) { constexpr bool c_debug_flag = true; scope log(XO_DEBUG(c_debug_flag)); constexpr const char * c_self_name = "paren_xs::on_i64"; this->illegal_input_error(c_self_name, tk); } void paren_xs::on_f64_token(const token_type & tk, parserstatemachine * /*p_psm*/) { constexpr bool c_debug_flag = true; scope log(XO_DEBUG(c_debug_flag)); constexpr const char * c_self_name = "paren_xs::on_f64"; this->illegal_input_error(c_self_name, tk); } #endif void DParenSsm::on_parsed_expression(obj expr, ParserStateMachine * p_psm) { if (parenstate_ == parenexprstatetype::lparen_1) { this->parenstate_ = parenexprstatetype::lparen_2; this->expr_ = expr; return; } Super::on_parsed_expression(expr, p_psm); } void DParenSsm::on_parsed_expression_with_token(obj expr, const Token & tk, ParserStateMachine * p_psm) { if (parenstate_ == parenexprstatetype::lparen_1) { this->parenstate_ = parenexprstatetype::lparen_2; this->expr_ = expr; this->on_token(tk, p_psm); return; } Super::on_parsed_expression(expr, p_psm); } #ifdef NOT_YET void paren_xs::on_expr(bp expr, parserstatemachine * p_psm) { constexpr bool c_debug_flag = true; scope log(XO_DEBUG(c_debug_flag)); log && log(xtag("exstype", this->exs_type_), xtag("expr", expr)); switch (this->parenxs_type_) { case parenexprstatetype::lparen_0: { this->parenxs_type_ = parenexprstatetype::lparen_1; /* wants on_rightparen */ progress_xs::start(expr.promote(), p_psm); return; } case parenexprstatetype::lparen_1: { this->gen_expr_ = expr.promote(); /* expect immediate incoming call, this time to on_rightparen() */ return; } default: /* unreachable */ assert(false); return; } } /*on_expr*/ void paren_xs::on_symbol(const std::string & /*symbol_name*/, parserstatemachine * /*p_psm*/) { switch(this->parenxs_type_) { case parenexprstatetype::lparen_0: case parenexprstatetype::lparen_1: /* NOT IMPLEMENTED */ assert(false); return; default: /* unreachable */ assert(false); return; } } void paren_xs::print(std::ostream & os) const { os << ""; } #endif bool DParenSsm::pretty(const ppindentinfo & ppii) const { return ppii.pps()->pretty_struct(ppii, "DParenSsm", refrtag("parenstate", parenstate_), refrtag("expect", this->get_expect_str())); } } /*namespace scm*/ } /*namespace xo*/ /* end DParenSsm.cpp */