/** @file DProgressSsm.hpp * * @author Roland Conybeare, Jan 2026 **/ #pragma once #include "DSyntaxStateMachine.hpp" #include "syntaxstatetype.hpp" #include #ifdef NOT_YET #include "exprstate.hpp" #include "xo/reflect/TypeDescr.hpp" #include //#include #endif namespace xo { namespace scm { /** represent an infix operator. * * See @ref progress_xs::assemble_expr() for translation * to Expression **/ enum class optype { invalid = -1, /** op:= **/ op_assign, /** op< **/ op_less, /** op<= **/ op_less_equal, /** op== **/ op_equal, /** op!= **/ op_not_equal, /** op> **/ op_great, /** op>= **/ op_great_equal, /** op+ **/ op_add, /** op- **/ op_subtract, /** op* **/ op_multiply, /** op/ **/ op_divide, n_optype }; extern const char * optype_descr(optype x); /** report operator precedence. * lowest operator precedence is 1 **/ extern int precedence(optype x); inline std::ostream & operator<< (std::ostream & os, optype x) { os << optype_descr(x); return os; } /** @class DProgressSsm * @brief syntax state machine for parsing a schematica rhs-value-expression * * Handles an expression that produces a value, for example appearing on the * right-hand side of a definition. * * Deals with: * 1. infix operators including operator precedence. * 2. generates argument-type-specific arithmetic expressions, * for example using ``Apply::make_add2_f64()`` when adding floating-point numbers * * One reason for this to exist is to simulate one-token lookahead. * To look at but not consume a token T, can push a progress_xs instance P, * then send T to P. **/ class DProgressSsm : public DSyntaxStateMachine { public: using Super = DSyntaxStateMachine; using TypeDescr = xo::reflect::TypeDescr; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using VisitReason = xo::mm::VisitReason; using DArena = xo::mm::DArena; using ppindentinfo = xo::print::ppindentinfo; public: DProgressSsm(obj lhs, optype op); static DProgressSsm * _make(DArena & parser_mm, obj lhs, optype op); /** create fop referring to new DProgressSsm **/ static obj make(DArena & parser_mm, obj lhs, optype op); static void start(DArena & parser_mm, ParserStateMachine * p_psm); static void start(DArena & parser_mm, obj lhs, ParserStateMachine * p_psm); static void start(DArena & parsermm, obj lhs, optype optype, ParserStateMachine * p_psm); syntaxstatetype ssm_type() const noexcept; #ifdef NOT_YET bool admits_f64() const; void apply_type_error(const char * self_name, optype op, bp expr1, bp expr2, parserstatemachine * p_psm) const; #endif static const char * ssm_classname() { return "DProgressSsm"; } std::string_view get_expect_str() const noexcept; /** assemble expression from collected inputs. * Usually triggered by syntax like ';' or ')' **/ obj assemble_expr(ParserStateMachine * p_psm); /** @defgroup scm-progressssm-methods general methods **/ ///@{ /** handle leftparen token @p tk. Overall parser state in @p p_psm **/ void on_leftparen_token(const Token & tk, ParserStateMachine * p_psm); void on_rightparen_token(const Token & tk, ParserStateMachine * p_psm); void on_symbol_token(const Token & tk, ParserStateMachine * p_psm); void on_comma_token(const Token & tk, ParserStateMachine * p_psm); void on_colon_token(const Token & tk, ParserStateMachine * p_psm); void on_singleassign_token(const Token & tk, ParserStateMachine * p_psm); void on_operator_token(const Token & tk, ParserStateMachine * p_psm); void on_string_token(const Token & tk, ParserStateMachine * p_psm); void on_f64_token(const Token & tk, ParserStateMachine * p_psm); void on_i64_token(const Token & tk, ParserStateMachine * p_psm); void on_bool_token(const Token & tk, ParserStateMachine * p_psm); void on_semicolon_token(const Token & tk, ParserStateMachine * p_psm); void on_rightbrace_token(const Token & tk, ParserStateMachine * p_psm); /** token belongs to surrounding syntax, * -> lock in current progress **/ void on_completing_token(const Token & tk, ParserStateMachine * p_psm); ///@} /** @defgroup scm-progressssm-ssm-facet syntaxstatemachine facet methods **/ /// @{ /** operate state machine for this syntax on incoming token @p tk * with overall parser state in @p p_psm **/ void on_token(const Token & tk, ParserStateMachine * p_psm); void on_parsed_expression(obj expr, ParserStateMachine * p_psm); void on_parsed_expression_with_token(obj expr, const Token & tk, ParserStateMachine * p_psm); ///@} /** @defgroup scm-progressssm-printable-facet printable facet methods **/ ///@{ bool pretty(const ppindentinfo & ppii) const; ///@} #ifdef NOT_YET void on_comma_token(const token_type & tk, parserstatemachine * p_psm) final override; void on_typedescr(TypeDescr td, parserstatemachine * p_psm) override; void on_assign_token(const token_type & tk, parserstatemachine * p_psm) final override; void on_leftparen_token(const token_type & tk, parserstatemachine * p_psm) override; void on_rightparen_token(const token_type & tk, parserstatemachine * p_psm) override; void print(std::ostream & os) const override; #endif /** @defgroup scm-progressssm-gc-support gc support methods **/ ///@{ void visit_gco_children(VisitReason reason, obj gc) noexcept; ///@} private: /** populate an expression here, may be followed by an operator **/ obj lhs_; /** infix operator, if supplied **/ optype op_type_ = optype::invalid; /** populate an expression here, that follows an infix operator. * * Note this may not resolve immediately. * Consider input * 5 + 6 * Need to know if following token is * * before deciding if 6 belongs to addition 5 + 6 **/ obj rhs_; }; } /*namespace scm*/ #ifndef ppdetail_atomic namespace print { PPDETAIL_ATOMIC(xo::scm::optype); } #endif } /*namespace xo*/ /* end DProgressSsm.hpp */