xo-reader2: + DDefineSsm + utest
This commit is contained in:
parent
39fa1f7c9f
commit
d3066ef88d
13 changed files with 762 additions and 3 deletions
|
|
@ -20,7 +20,7 @@ add_definitions(${PROJECT_CXX_FLAGS})
|
||||||
# ----------------------------------------------------------------
|
# ----------------------------------------------------------------
|
||||||
# output targets
|
# output targets
|
||||||
|
|
||||||
#add_subdirectory(utest)
|
add_subdirectory(utest)
|
||||||
|
|
||||||
# note: manual target; generated code committed to git
|
# note: manual target; generated code committed to git
|
||||||
xo_add_genfacet(
|
xo_add_genfacet(
|
||||||
|
|
|
||||||
13
xo-reader2/idl/ISyntaxStateMachine_DDefineSsm.json5
Normal file
13
xo-reader2/idl/ISyntaxStateMachine_DDefineSsm.json5
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
mode: "implementation",
|
||||||
|
includes: [ "\"SyntaxStateMachine.hpp\"",
|
||||||
|
"\"ssm/ISyntaxStateMachine_Xfer.hpp\"" ],
|
||||||
|
local_types: [ ],
|
||||||
|
namespace1: "xo",
|
||||||
|
namespace2: "scm",
|
||||||
|
facet_idl: "idl/SyntaxStateMachine.json5",
|
||||||
|
brief: "provide ASyntaxStateMachine interface for DDefineSsm",
|
||||||
|
using_doxygen: true,
|
||||||
|
repr: "DDefineSsm",
|
||||||
|
doc: [ "implement ASyntaxStateMachine for DDefineSsm" ],
|
||||||
|
}
|
||||||
97
xo-reader2/include/xo/reader2/DDefineSsm.hpp
Normal file
97
xo-reader2/include/xo/reader2/DDefineSsm.hpp
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
/** @file DDefineSsm.hpp
|
||||||
|
*
|
||||||
|
* @author Roland Conybeare, Jan 2026
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include "ParserStateMachine.hpp"
|
||||||
|
#include "SyntaxStateMachine.hpp"
|
||||||
|
#include "syntaxstatetype.hpp"
|
||||||
|
#include <xo/facet/obj.hpp>
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
namespace scm {
|
||||||
|
/**
|
||||||
|
* @pre
|
||||||
|
*
|
||||||
|
* def foo : f64 = 1 ;
|
||||||
|
* ^ ^ ^ ^ ^ ^ ^ ^
|
||||||
|
* | | | | | | | (done)
|
||||||
|
* | | | | | | def_6:expect_rhs_expression:expr_progress
|
||||||
|
* | | | | | def_5:expect_rhs_expression
|
||||||
|
* | | | | def_4
|
||||||
|
* | | | def_3:expect_type
|
||||||
|
* | | def_2
|
||||||
|
* | def_1:expect_symbol
|
||||||
|
* def_0
|
||||||
|
* expect_toplevel_expression_sequence
|
||||||
|
*
|
||||||
|
* def_0 --on_def_token()--> def_1
|
||||||
|
* def_1 --on_symbol()--> def_2
|
||||||
|
* def_2 --on_colon_token()--> def_3
|
||||||
|
* --on_singleassign_token()--> def_5
|
||||||
|
* def_3 --on_typedescr()--> def_4
|
||||||
|
* def_4 --on_singleassign_token()--> def_5
|
||||||
|
* def_5 --on_expr()--> def_6
|
||||||
|
* def_6 --on_semicolon_token()--> (done)
|
||||||
|
*
|
||||||
|
* def_1:expect_symbol: got 'def' keyword, symbol to follow
|
||||||
|
* def_1: got symbol name
|
||||||
|
* def_3:expect_symbol got (optional) colon, type name to follow
|
||||||
|
* def_4: got symbol type
|
||||||
|
* def_6:expect_rhs_expression got (optional) equal sign, value to follow
|
||||||
|
* (done): definition complete, pop exprstate from stack
|
||||||
|
*
|
||||||
|
* @endpre
|
||||||
|
**/
|
||||||
|
enum class defexprstatetype {
|
||||||
|
invalid = -1,
|
||||||
|
|
||||||
|
def_0,
|
||||||
|
def_1,
|
||||||
|
def_2,
|
||||||
|
def_3,
|
||||||
|
def_4,
|
||||||
|
def_5,
|
||||||
|
def_6,
|
||||||
|
|
||||||
|
n_defexprstatetype,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const char * defexprstatetype_descr(defexprstatetype x);
|
||||||
|
|
||||||
|
std::ostream &
|
||||||
|
operator<<(std::ostream & os, defexprstatetype x);
|
||||||
|
|
||||||
|
/** @class DDefineSsm
|
||||||
|
* @brief state machine for parsing a define expression
|
||||||
|
**/
|
||||||
|
class DDefineSsm {
|
||||||
|
public:
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** @defgroup scm-define-ssm-facet syntaxstatemachine facet methods **/
|
||||||
|
///@{
|
||||||
|
|
||||||
|
/** identifies the ssm implemented here **/
|
||||||
|
syntaxstatetype ssm_type() const noexcept;
|
||||||
|
|
||||||
|
/** text describing expected/allowed input to this ssm in current state.
|
||||||
|
* Intended to drive error mesages
|
||||||
|
**/
|
||||||
|
std::string_view get_expect_str() const noexcept;
|
||||||
|
|
||||||
|
/** update state for this syntax on incoming token @p tk,
|
||||||
|
* overall parser state in @p p_psm
|
||||||
|
**/
|
||||||
|
void on_if_token(const Token & tk, ParserStateMachine * p_psm);
|
||||||
|
|
||||||
|
///@}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/** identify define-expression state **/
|
||||||
|
defexprstatetype defstate_;
|
||||||
|
};
|
||||||
|
} /*namespace scm*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
/* end DDefineSsm.hpp */
|
||||||
|
|
@ -198,7 +198,7 @@ namespace xo {
|
||||||
* @return parsed expression, if @p tk completes an expression.
|
* @return parsed expression, if @p tk completes an expression.
|
||||||
* otherwise nullptr
|
* otherwise nullptr
|
||||||
**/
|
**/
|
||||||
const ParserResult & include_token(const token_type & tk);
|
const ParserResult & on_token(const token_type & tk);
|
||||||
|
|
||||||
/** reset parsed result expression; use using return value from
|
/** reset parsed result expression; use using return value from
|
||||||
* @ref include_token. Complicating api here to avoid copying ParserResult
|
* @ref include_token. Complicating api here to avoid copying ParserResult
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
/** @file ISyntaxStateMachine_DDefineSsm.hpp
|
||||||
|
*
|
||||||
|
* Generated automagically from ingredients:
|
||||||
|
* 1. code generator:
|
||||||
|
* [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet]
|
||||||
|
* arguments:
|
||||||
|
* --input [idl/ISyntaxStateMachine_DDefineSsm.json5]
|
||||||
|
* 2. jinja2 template for abstract facet .hpp file:
|
||||||
|
* [iface_facet_repr.hpp.j2]
|
||||||
|
* 3. idl for facet methods
|
||||||
|
* [idl/ISyntaxStateMachine_DDefineSsm.json5]
|
||||||
|
**/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "SyntaxStateMachine.hpp"
|
||||||
|
#include "SyntaxStateMachine.hpp"
|
||||||
|
#include "ssm/ISyntaxStateMachine_Xfer.hpp"
|
||||||
|
#include "DDefineSsm.hpp"
|
||||||
|
|
||||||
|
namespace xo { namespace scm { class ISyntaxStateMachine_DDefineSsm; } }
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
namespace facet {
|
||||||
|
template <>
|
||||||
|
struct FacetImplementation<xo::scm::ASyntaxStateMachine,
|
||||||
|
xo::scm::DDefineSsm>
|
||||||
|
{
|
||||||
|
using ImplType = xo::scm::ISyntaxStateMachine_Xfer
|
||||||
|
<xo::scm::DDefineSsm,
|
||||||
|
xo::scm::ISyntaxStateMachine_DDefineSsm>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
namespace scm {
|
||||||
|
/** @class ISyntaxStateMachine_DDefineSsm
|
||||||
|
**/
|
||||||
|
class ISyntaxStateMachine_DDefineSsm {
|
||||||
|
public:
|
||||||
|
/** @defgroup scm-syntaxstatemachine-ddefinessm-type-traits **/
|
||||||
|
///@{
|
||||||
|
using Copaque = xo::scm::ASyntaxStateMachine::Copaque;
|
||||||
|
using Opaque = xo::scm::ASyntaxStateMachine::Opaque;
|
||||||
|
///@}
|
||||||
|
/** @defgroup scm-syntaxstatemachine-ddefinessm-methods **/
|
||||||
|
///@{
|
||||||
|
// const methods
|
||||||
|
/** identify a type of syntax state machine **/
|
||||||
|
static syntaxstatetype ssm_type(const DDefineSsm & self) noexcept;
|
||||||
|
/** text describing expected/allowed input to this ssm in current state **/
|
||||||
|
static std::string_view get_expect_str(const DDefineSsm & self) noexcept;
|
||||||
|
|
||||||
|
// non-const methods
|
||||||
|
/** update state machine for incoming define-keyworkd-token @p tk **/
|
||||||
|
static void on_def_token(DDefineSsm & self, const Token & tk, ParserStateMachine * ps_psm);
|
||||||
|
/** update state machine for incoming if-keyword-token @p tk **/
|
||||||
|
static void on_if_token(DDefineSsm & self, const Token & tk, ParserStateMachine * p_psm);
|
||||||
|
///@}
|
||||||
|
};
|
||||||
|
|
||||||
|
} /*namespace scm*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
/* end */
|
||||||
|
|
@ -21,6 +21,9 @@ namespace xo {
|
||||||
/** toplevel of some translation unit. See @ref DExprSeqState **/
|
/** toplevel of some translation unit. See @ref DExprSeqState **/
|
||||||
expect_toplevel_expression_sequence,
|
expect_toplevel_expression_sequence,
|
||||||
|
|
||||||
|
/** handle define-expression. See @ref DDefineSsm **/
|
||||||
|
defexpr,
|
||||||
|
|
||||||
/** comes lasts, counts number of valid enums **/
|
/** comes lasts, counts number of valid enums **/
|
||||||
N
|
N
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ set(SELF_SRCS
|
||||||
DExprSeqState.cpp
|
DExprSeqState.cpp
|
||||||
ISyntaxStateMachine_DExprSeqState.cpp
|
ISyntaxStateMachine_DExprSeqState.cpp
|
||||||
|
|
||||||
|
DDefineSsm.cpp
|
||||||
|
|
||||||
reader2_register_facets.cpp
|
reader2_register_facets.cpp
|
||||||
reader2_register_types.cpp
|
reader2_register_types.cpp
|
||||||
)
|
)
|
||||||
|
|
|
||||||
395
xo-reader2/src/reader2/DDefineSsm.cpp
Normal file
395
xo-reader2/src/reader2/DDefineSsm.cpp
Normal file
|
|
@ -0,0 +1,395 @@
|
||||||
|
/** @file DDefineSsm.cpp
|
||||||
|
*
|
||||||
|
* @author Roland Conybeare, Jan 2026
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include "DDefineSsm.hpp"
|
||||||
|
#ifdef NOT_YET
|
||||||
|
#include "parserstatemachine.hpp"
|
||||||
|
#include "expect_symbol_xs.hpp"
|
||||||
|
#include "expect_expr_xs.hpp"
|
||||||
|
#include "expect_type_xs.hpp"
|
||||||
|
#include "pretty_expression.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
namespace scm {
|
||||||
|
// ----- defexprstatetype -----
|
||||||
|
|
||||||
|
const char *
|
||||||
|
defexprstatetype_descr(defexprstatetype x) {
|
||||||
|
switch (x) {
|
||||||
|
case defexprstatetype::invalid: return "invalid";
|
||||||
|
case defexprstatetype::def_0: return "def_0";
|
||||||
|
case defexprstatetype::def_1: return "def_1";
|
||||||
|
case defexprstatetype::def_2: return "def_2";
|
||||||
|
case defexprstatetype::def_3: return "def_3";
|
||||||
|
case defexprstatetype::def_4: return "def_4";
|
||||||
|
case defexprstatetype::def_5: return "def_5";
|
||||||
|
case defexprstatetype::def_6: return "def_6";
|
||||||
|
case defexprstatetype::n_defexprstatetype: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "???defexprstatetype";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream &
|
||||||
|
operator<<(std::ostream & os, defexprstatetype x) {
|
||||||
|
os << defexprstatetype_descr(x);
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- define_xs -----
|
||||||
|
|
||||||
|
#ifdef NOT_YET
|
||||||
|
std::unique_ptr<define_xs>
|
||||||
|
define_xs::make() {
|
||||||
|
return std::make_unique<define_xs>(define_xs(DefineExprAccess::make_empty()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
define_xs::start(parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
scope log(XO_DEBUG(p_psm->debug_flag()));
|
||||||
|
|
||||||
|
p_psm->push_exprstate(define_xs::make());
|
||||||
|
p_psm->top_exprstate().on_def_token(token_type::def(), p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
define_xs::define_xs(rp<DefineExprAccess> def_expr)
|
||||||
|
: exprstate(exprstatetype::defexpr),
|
||||||
|
defxs_type_{defexprstatetype::def_0},
|
||||||
|
def_expr_{std::move(def_expr)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
// const char *
|
||||||
|
// define_xs::get_expect_str() const { ... }
|
||||||
|
|
||||||
|
void
|
||||||
|
define_xs::on_expr(bp<Expression> expr,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
scope log(XO_DEBUG(p_psm->debug_flag()));
|
||||||
|
|
||||||
|
log && log(xtag("defxs_type", defxs_type_));
|
||||||
|
|
||||||
|
if (this->defxs_type_ == defexprstatetype::def_5) {
|
||||||
|
/* have all the ingredients to create an expression
|
||||||
|
* representing a definition
|
||||||
|
*
|
||||||
|
* 1. if ir_type is a symbol, interpret as variable name.
|
||||||
|
* Need to be able to locate variable by type
|
||||||
|
* 2. if ir_type is an expression, adopt as rhs
|
||||||
|
*/
|
||||||
|
rp<Expression> rhs_value = expr.promote();
|
||||||
|
|
||||||
|
if (this->cvt_expr_) {
|
||||||
|
this->cvt_expr_->assign_arg(rhs_value);
|
||||||
|
} else {
|
||||||
|
/* note: establishes .def_expr_ valuetype */
|
||||||
|
this->def_expr_->assign_rhs(rhs_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
rp<Expression> def_expr = this->def_expr_;
|
||||||
|
|
||||||
|
this->defxs_type_ = defexprstatetype::def_6;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const char * c_self_name = "define_xs::on_expr";
|
||||||
|
const char * exp = get_expect_str();
|
||||||
|
|
||||||
|
this->illegal_input_on_expr(c_self_name, expr, exp, p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
define_xs::on_expr_with_semicolon(bp<Expression> expr,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
scope log(XO_DEBUG(p_psm->debug_flag()));
|
||||||
|
|
||||||
|
log && log(xtag("defxs_type", defxs_type_));
|
||||||
|
|
||||||
|
this->on_expr(expr, p_psm);
|
||||||
|
/* semicolon is allowed to terminate def expr */
|
||||||
|
this->on_semicolon_token(token_type::semicolon(), p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
define_xs::on_symbol(const std::string & symbol_name,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
scope log(XO_DEBUG(p_psm->debug_flag()));
|
||||||
|
|
||||||
|
log && log(xtag("defxs_type", defxs_type_), xtag("env_stack_size", p_psm->env_stack_size()));
|
||||||
|
|
||||||
|
if (this->defxs_type_ == defexprstatetype::def_1) {
|
||||||
|
this->defxs_type_ = defexprstatetype::def_2;
|
||||||
|
this->def_expr_->assign_lhs_name(symbol_name);
|
||||||
|
|
||||||
|
// if this is a genuine top-level define (i.e. nesting level = 0),
|
||||||
|
// then we need to upsert so we can refer to rhs later.
|
||||||
|
//
|
||||||
|
// In other contexts (e.g. body-of-lambda) will be rewriting
|
||||||
|
// {
|
||||||
|
// def y = foo(x,x);
|
||||||
|
// bar(y,y);
|
||||||
|
// }
|
||||||
|
// into something like
|
||||||
|
// {
|
||||||
|
// (lambda (y123) bar(y123,y123))(foo(x,x));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// This works in the body of lambda, because we don't evaluate anything
|
||||||
|
// until lambda definition is complete.
|
||||||
|
//
|
||||||
|
// For interactive top-level defs we want to evaluate as we go,
|
||||||
|
// so need incremental bindings.
|
||||||
|
|
||||||
|
if (p_psm->env_stack_size() == 1) {
|
||||||
|
/* remember variable binding in lexical context,
|
||||||
|
* so we can refer to it later
|
||||||
|
*/
|
||||||
|
p_psm->upsert_var(this->def_expr_->lhs_variable());
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const char * c_self_name = "define_xs::on_symbol";
|
||||||
|
const char * exp = this->get_expect_str();
|
||||||
|
|
||||||
|
this->illegal_input_on_symbol(c_self_name, symbol_name, exp, p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
define_xs::on_typedescr(TypeDescr td,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
scope log(XO_DEBUG(p_psm->debug_flag()));
|
||||||
|
|
||||||
|
log && log("defxs_type", defxs_type_);
|
||||||
|
|
||||||
|
if (this->defxs_type_ == defexprstatetype::def_3) {
|
||||||
|
this->defxs_type_ = defexprstatetype::def_4;
|
||||||
|
this->cvt_expr_ = ConvertExprAccess::make(td /*dest_type*/,
|
||||||
|
nullptr /*source_expr*/);
|
||||||
|
/* note: establishes .def_expr_ valuetype */
|
||||||
|
this->def_expr_->assign_rhs(this->cvt_expr_);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const char * c_self_name = "define_xs::on_symbol";
|
||||||
|
const char * exp = this->get_expect_str();
|
||||||
|
|
||||||
|
this->illegal_input_on_type(c_self_name, td, exp, p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
define_xs::on_def_token(const token_type & tk,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log("defxs_type", defxs_type_);
|
||||||
|
|
||||||
|
if (this->defxs_type_ == defexprstatetype::def_0) {
|
||||||
|
this->defxs_type_ = defexprstatetype::def_1;
|
||||||
|
|
||||||
|
expect_symbol_xs::start(p_psm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const char * c_self_name = "define_xs::on_def_token";
|
||||||
|
const char * exp = this->get_expect_str();
|
||||||
|
|
||||||
|
this->illegal_input_on_token(c_self_name, tk, exp, p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
define_xs::on_colon_token(const token_type & tk,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log("defxs_type", defxs_type_);
|
||||||
|
|
||||||
|
if (this->defxs_type_ == defexprstatetype::def_2) {
|
||||||
|
this->defxs_type_ = defexprstatetype::def_3;
|
||||||
|
|
||||||
|
expect_type_xs::start(p_psm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const char * c_self_name = "define_xs::on_symbol";
|
||||||
|
const char * exp = this->get_expect_str();
|
||||||
|
|
||||||
|
this->illegal_input_on_token(c_self_name, tk, exp, p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
define_xs::on_semicolon_token(const token_type & tk,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
/* def expr consumes semicolon */
|
||||||
|
|
||||||
|
scope log(XO_DEBUG(p_psm->debug_flag()));
|
||||||
|
|
||||||
|
log && log("defxs_type", defxs_type_);
|
||||||
|
|
||||||
|
if (this->defxs_type_ == defexprstatetype::def_6) {
|
||||||
|
rp<DefineExprAccess> def_expr = this->def_expr_;
|
||||||
|
|
||||||
|
std::unique_ptr<exprstate> self = p_psm->pop_exprstate();
|
||||||
|
|
||||||
|
p_psm->top_exprstate().on_expr(def_expr, p_psm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const char * c_self_name = "define_xs::on_symbol";
|
||||||
|
const char * exp = this->get_expect_str();
|
||||||
|
|
||||||
|
this->illegal_input_on_token(c_self_name, tk, exp, p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
define_xs::on_singleassign_token(const token_type & tk,
|
||||||
|
parserstatemachine * p_psm)
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
log && log("defxs_type", defxs_type_);
|
||||||
|
|
||||||
|
if ((this->defxs_type_ == defexprstatetype::def_2)
|
||||||
|
|| (this->defxs_type_ == defexprstatetype::def_4))
|
||||||
|
{
|
||||||
|
this->defxs_type_ = defexprstatetype::def_5;
|
||||||
|
expect_expr_xs::start(p_psm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const char * c_self_name = "define_xs::on_singleassign_token";
|
||||||
|
const char * exp = get_expect_str();
|
||||||
|
|
||||||
|
this->illegal_input_on_token(c_self_name, tk, exp, p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
define_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 = "define_xs::on_rightparen";
|
||||||
|
const char * exp = get_expect_str();
|
||||||
|
|
||||||
|
this->illegal_input_on_token(c_self_name, tk, exp, p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
define_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 = "define_xs::on_i64";
|
||||||
|
const char * exp = get_expect_str();
|
||||||
|
|
||||||
|
this->illegal_input_on_token(c_self_name, tk, exp, p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
define_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 = "define_xs::on_f64";
|
||||||
|
const char * exp = get_expect_str();
|
||||||
|
|
||||||
|
this->illegal_input_on_token(c_self_name, tk, exp, p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
define_xs::print(std::ostream & os) const {
|
||||||
|
os << "<define_xs"
|
||||||
|
<< xtag("defxs_type", defxs_type_);
|
||||||
|
os << ">";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
define_xs::pretty_print(const xo::print::ppindentinfo & ppii) const
|
||||||
|
{
|
||||||
|
return ppii.pps()->pretty_struct(ppii, "define_xs",
|
||||||
|
refrtag("defxs_type", defxs_type_));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
syntaxstatetype
|
||||||
|
DDefineSsm::ssm_type() const noexcept
|
||||||
|
{
|
||||||
|
return syntaxstatetype::defexpr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view
|
||||||
|
DDefineSsm::get_expect_str() const noexcept
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* def foo = 1 ;
|
||||||
|
* def foo : f64 = 1 ;
|
||||||
|
* ^ ^ ^ ^ ^ ^ ^ ^
|
||||||
|
* | | | | | | | (done)
|
||||||
|
* | | | | | | def_6
|
||||||
|
* | | | | | def_5:expect_rhs_expression
|
||||||
|
* | | | | def_4
|
||||||
|
* | | | def_3:expect_type
|
||||||
|
* | | def_2
|
||||||
|
* | def_1:expect_symbol
|
||||||
|
* expect_toplevel_expression_sequence
|
||||||
|
*
|
||||||
|
* note that we skip from def_2 -> def_5 if '=' instead of ':'
|
||||||
|
*/
|
||||||
|
switch (this->defstate_) {
|
||||||
|
case defexprstatetype::invalid:
|
||||||
|
case defexprstatetype::def_0:
|
||||||
|
case defexprstatetype::n_defexprstatetype:
|
||||||
|
assert(false); // impossible
|
||||||
|
return nullptr;
|
||||||
|
case defexprstatetype::def_1:
|
||||||
|
return "symbol";
|
||||||
|
case defexprstatetype::def_2:
|
||||||
|
return "singleassign|colon";
|
||||||
|
case defexprstatetype::def_4:
|
||||||
|
return "singleassign";
|
||||||
|
case defexprstatetype::def_3:
|
||||||
|
return "type";
|
||||||
|
case defexprstatetype::def_5:
|
||||||
|
return "expression";
|
||||||
|
case defexprstatetype::def_6:
|
||||||
|
return "semicolon";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "?expect";
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DDefineSsm::on_if_token(const Token & tk,
|
||||||
|
ParserStateMachine * p_psm)
|
||||||
|
{
|
||||||
|
p_psm->illegal_input_on_token("DDefineSsm::on_if_token",
|
||||||
|
tk,
|
||||||
|
this->get_expect_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
} /*namespace scm*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
/* end DDefineSsm.cpp */
|
||||||
50
xo-reader2/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp
Normal file
50
xo-reader2/src/reader2/ISyntaxStateMachine_DDefineSsm.cpp
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
/** @file ISyntaxStateMachine_DDefineSsm.cpp
|
||||||
|
*
|
||||||
|
* Generated automagically from ingredients:
|
||||||
|
* 1. code generator:
|
||||||
|
* [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet]
|
||||||
|
* arguments:
|
||||||
|
* --input [idl/ISyntaxStateMachine_DDefineSsm.json5]
|
||||||
|
* 2. jinja2 template for abstract facet .hpp file:
|
||||||
|
* [iface_facet_any.hpp.j2]
|
||||||
|
* 3. idl for facet methods
|
||||||
|
* [idl/ISyntaxStateMachine_DDefineSsm.json5]
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include "ssm/ISyntaxStateMachine_DDefineSsm.hpp"
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
namespace scm {
|
||||||
|
auto
|
||||||
|
ISyntaxStateMachine_DDefineSsm::ssm_type(const DDefineSsm & self) noexcept
|
||||||
|
-> syntaxstatetype
|
||||||
|
{
|
||||||
|
return self.ssm_type();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto
|
||||||
|
ISyntaxStateMachine_DDefineSsm::get_expect_str(const DDefineSsm & self) noexcept
|
||||||
|
-> std::string_view
|
||||||
|
{
|
||||||
|
return self.get_expect_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto
|
||||||
|
ISyntaxStateMachine_DDefineSsm::on_def_token(DDefineSsm & self,
|
||||||
|
const Token & tk,
|
||||||
|
ParserStateMachine * ps_psm) -> void
|
||||||
|
{
|
||||||
|
self.on_def_token(tk, ps_psm);
|
||||||
|
}
|
||||||
|
auto
|
||||||
|
ISyntaxStateMachine_DDefineSsm::on_if_token(DDefineSsm & self,
|
||||||
|
const Token & tk,
|
||||||
|
ParserStateMachine * p_psm) -> void
|
||||||
|
{
|
||||||
|
self.on_if_token(tk, p_psm);
|
||||||
|
}
|
||||||
|
|
||||||
|
} /*namespace scm*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
/* end ISyntaxStateMachine_DDefineSsm.cpp */
|
||||||
|
|
@ -48,7 +48,7 @@ namespace xo {
|
||||||
}
|
}
|
||||||
|
|
||||||
const ParserResult &
|
const ParserResult &
|
||||||
SchematikaParser::include_token(const token_type & tk)
|
SchematikaParser::on_token(const token_type & tk)
|
||||||
{
|
{
|
||||||
scope log(XO_DEBUG(debug_flag_), xtag("tk", tk));
|
scope log(XO_DEBUG(debug_flag_), xtag("tk", tk));
|
||||||
|
|
||||||
|
|
|
||||||
11
xo-reader2/utest/CMakeLists.txt
Normal file
11
xo-reader2/utest/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
# build unittest xo-reader2/utest
|
||||||
|
|
||||||
|
set(UTEST_EXE utest.reader2)
|
||||||
|
set(UTEST_SRCS
|
||||||
|
reader2_utest_main.cpp
|
||||||
|
SchematikaParser.test.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
xo_add_utest_executable(${UTEST_EXE} ${UTEST_SRCS})
|
||||||
|
xo_self_dependency(${UTEST_EXE} xo_reader2)
|
||||||
|
xo_external_target_dependency(${UTEST_EXE} Catch2 Catch2::Catch2)
|
||||||
95
xo-reader2/utest/SchematikaParser.test.cpp
Normal file
95
xo-reader2/utest/SchematikaParser.test.cpp
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
/** @file SchematikaParser.test.cpp
|
||||||
|
*
|
||||||
|
* @author Roland Conybeare, Jan 2026
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include <xo/reader2/SchematikaParser.hpp>
|
||||||
|
#include <xo/alloc2/arena/IAllocator_DArena.hpp>
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
using xo::scm::SchematikaParser;
|
||||||
|
using xo::scm::ParserResult;
|
||||||
|
using xo::scm::parser_result_type;
|
||||||
|
using xo::scm::Token;
|
||||||
|
using xo::mm::ArenaConfig;
|
||||||
|
using xo::mm::AAllocator;
|
||||||
|
using xo::mm::DArena;
|
||||||
|
using xo::facet::with_facet;
|
||||||
|
|
||||||
|
namespace ut {
|
||||||
|
TEST_CASE("SchematikaParser-ctor", "[reader2][SchematikaParser]")
|
||||||
|
{
|
||||||
|
ArenaConfig config;
|
||||||
|
config.name_ = "test-arena";
|
||||||
|
config.size_ = 16 * 1024;
|
||||||
|
|
||||||
|
DArena expr_arena = DArena::map(config);
|
||||||
|
obj<AAllocator> expr_alloc = with_facet<AAllocator>::mkobj(&expr_arena);
|
||||||
|
|
||||||
|
SchematikaParser parser(config, &expr_alloc, false /*debug_flag*/);
|
||||||
|
|
||||||
|
REQUIRE(parser.debug_flag() == false);
|
||||||
|
REQUIRE(parser.is_at_toplevel() == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("SchematikaParser-begin-interactive", "[reader2][SchematikaParser]")
|
||||||
|
{
|
||||||
|
ArenaConfig config;
|
||||||
|
config.name_ = "test-arena";
|
||||||
|
config.size_ = 16 * 1024;
|
||||||
|
|
||||||
|
DArena expr_arena = DArena::map(config);
|
||||||
|
obj<AAllocator> expr_alloc = with_facet<AAllocator>::mkobj(&expr_arena);
|
||||||
|
|
||||||
|
SchematikaParser parser(config, &expr_alloc, false /*debug_flag*/);
|
||||||
|
|
||||||
|
parser.begin_interactive_session();
|
||||||
|
|
||||||
|
// after begin_interactive_session, parser has toplevel exprseq
|
||||||
|
// but is still "at toplevel" in the sense of ready for input
|
||||||
|
REQUIRE(parser.has_incomplete_expr() == false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("SchematikaParser-begin-batch", "[reader2][SchematikaParser]")
|
||||||
|
{
|
||||||
|
ArenaConfig config;
|
||||||
|
config.name_ = "test-arena";
|
||||||
|
config.size_ = 16 * 1024;
|
||||||
|
|
||||||
|
DArena expr_arena = DArena::map(config);
|
||||||
|
obj<AAllocator> expr_alloc = with_facet<AAllocator>::mkobj(&expr_arena);
|
||||||
|
|
||||||
|
SchematikaParser parser(config, &expr_alloc, false /*debug_flag*/);
|
||||||
|
|
||||||
|
parser.begin_translation_unit();
|
||||||
|
|
||||||
|
// after begin_translation_unit, parser has toplevel exprseq
|
||||||
|
// but is still "at toplevel" in the sense of ready for input
|
||||||
|
REQUIRE(parser.has_incomplete_expr() == false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("SchematikaParser-interactive-if", "[reader2][SchematikaParser]")
|
||||||
|
{
|
||||||
|
ArenaConfig config;
|
||||||
|
config.name_ = "test-arena";
|
||||||
|
config.size_ = 16 * 1024;
|
||||||
|
|
||||||
|
DArena expr_arena = DArena::map(config);
|
||||||
|
obj<AAllocator> expr_alloc = with_facet<AAllocator>::mkobj(&expr_arena);
|
||||||
|
|
||||||
|
SchematikaParser parser(config, &expr_alloc, false /*debug_flag*/);
|
||||||
|
|
||||||
|
parser.begin_interactive_session();
|
||||||
|
|
||||||
|
parser.on_token(Token::if_token());
|
||||||
|
|
||||||
|
// after begin_interactive_session, parser has toplevel exprseq
|
||||||
|
// but is still "at toplevel" in the sense of ready for input
|
||||||
|
REQUIRE(parser.has_incomplete_expr() == false);
|
||||||
|
}
|
||||||
|
|
||||||
|
} /*namespace ut*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
/* end SchematikaParser.test.cpp */
|
||||||
27
xo-reader2/utest/reader2_utest_main.cpp
Normal file
27
xo-reader2/utest/reader2_utest_main.cpp
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
/** @file reader2_utest_main.cpp
|
||||||
|
*
|
||||||
|
* @author Roland Conybeare, Jan 2026
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include <xo/subsys/Subsystem.hpp>
|
||||||
|
|
||||||
|
#define CATCH_CONFIG_RUNNER
|
||||||
|
#include "catch2/catch.hpp"
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
using xo::Subsystem;
|
||||||
|
|
||||||
|
// initialize subsystems
|
||||||
|
Subsystem::initialize_all();
|
||||||
|
|
||||||
|
// Run Catch2's test session
|
||||||
|
int result = Catch::Session().run(argc, argv);
|
||||||
|
|
||||||
|
// cleanup here, if any
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end reader2_utest_main.cpp */
|
||||||
Loading…
Add table
Add a link
Reference in a new issue