From 57f6f9073e2a9b7158b63f5b4f0255d76b9af9cf Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 16 Feb 2026 23:25:34 -0500 Subject: [PATCH] xo-reader2: utest with variable reference. Works ! --- xo-expression2/src/expression2/Binding.cpp | 2 +- .../src/expression2/DGlobalSymtab.cpp | 9 ++- xo-reader2/src/reader2/DToplevelSeqSsm.cpp | 21 +++--- xo-reader2/src/reader2/ParserStateMachine.cpp | 70 ++++++++++--------- xo-reader2/utest/SchematikaParser.test.cpp | 70 ++++++++++++++++++- 5 files changed, 125 insertions(+), 47 deletions(-) diff --git a/xo-expression2/src/expression2/Binding.cpp b/xo-expression2/src/expression2/Binding.cpp index 6802ba69..94be9b6b 100644 --- a/xo-expression2/src/expression2/Binding.cpp +++ b/xo-expression2/src/expression2/Binding.cpp @@ -27,7 +27,7 @@ namespace xo { Binding::print(std::ostream & os) const { if (i_link_ == c_link_global) { - os << "{path:global}"; + os << "{path:global:" << j_slot_ << "}"; } else if (i_link_ == c_link_sentinel) { os << "{path}"; } else { diff --git a/xo-expression2/src/expression2/DGlobalSymtab.cpp b/xo-expression2/src/expression2/DGlobalSymtab.cpp index 89d10f32..38809a38 100644 --- a/xo-expression2/src/expression2/DGlobalSymtab.cpp +++ b/xo-expression2/src/expression2/DGlobalSymtab.cpp @@ -69,6 +69,8 @@ namespace xo { DGlobalSymtab::upsert_variable(obj mm, DVariable * var) { + scope log(XO_DEBUG(true), std::string_view(*var->name())); + // It's possible there's already a global variable // with the same name. // @@ -78,6 +80,8 @@ namespace xo { DVariable * existing = this->lookup_variable(var->name()); if (existing) { + log && log("variable with this symbol already exists"); + if (existing == var) { // impossible, but.. noop, right? return; @@ -91,6 +95,8 @@ namespace xo { // (*vars_)[existing->path().j_slot()] = obj(var); } else { + log && log("variable is new"); + DArray::size_type n = vars_->size(); // NOTE: expansion of var_ array here is moot at present (Feb 2026), @@ -146,8 +152,7 @@ namespace xo { { assert(sym); - scope log(XO_DEBUG(true), "stub"); - log && log(xtag("sym", std::string_view(*sym))); + scope log(XO_DEBUG(true), std::string_view(*sym)); auto ix = map_->find(sym); diff --git a/xo-reader2/src/reader2/DToplevelSeqSsm.cpp b/xo-reader2/src/reader2/DToplevelSeqSsm.cpp index e294d078..42c870b6 100644 --- a/xo-reader2/src/reader2/DToplevelSeqSsm.cpp +++ b/xo-reader2/src/reader2/DToplevelSeqSsm.cpp @@ -11,6 +11,7 @@ #include "DIfElseSsm.hpp" #include "ParenSsm.hpp" #include "ExpectExprSsm.hpp" +#include "VarRef.hpp" #include #include @@ -204,23 +205,23 @@ namespace xo { void DToplevelSeqSsm::on_symbol_token(const Token & tk, - ParserStateMachine * p_psm) + ParserStateMachine * p_psm) { switch (seqtype_) { case exprseqtype::toplevel_interactive: { -#ifdef NOT_YET - obj var = p_psm->lookup_var(tk.text()); + auto varref = obj(p_psm->lookup_varref(tk.text())); - if (var) { - DProgressSsm::start(var, p_psm); + if (varref) { + DProgressSsm::start(p_psm->parser_alloc(), + varref, + p_psm); + return; } else { - p_psm->unknown_variable_error("DToplevelSeqSsm::on_symbol_token", - tk, - this->get_expect_str(), - p_psm); + p_psm->error_unbound_variable("DToplevelSeqSsm", + tk.text()); + return; } -#endif } break; case exprseqtype::toplevel_batch: diff --git a/xo-reader2/src/reader2/ParserStateMachine.cpp b/xo-reader2/src/reader2/ParserStateMachine.cpp index 6df9133b..856a8215 100644 --- a/xo-reader2/src/reader2/ParserStateMachine.cpp +++ b/xo-reader2/src/reader2/ParserStateMachine.cpp @@ -156,6 +156,16 @@ namespace xo { { scope log(XO_DEBUG(debug_flag_)); + const DUniqueString * ustr = stringtable_.lookup(symbolname); + + if (!ustr) { + // if we don't already know the symbol, + // -> can't be a valid variable reference + // (whether global or local) + + return nullptr; + } + // TODO: // 1. check global symtab // 2. combine local+global symtab into indept struct @@ -163,52 +173,46 @@ namespace xo { // if (local_symtab_) { - const DUniqueString * ustr = stringtable_.lookup(symbolname); + DLocalSymtab * symtab = local_symtab_; - if (ustr) { - DLocalSymtab * symtab = local_symtab_; + // count #of nested scopes to cross, to reach symbol + // + int32_t link_count = 0; - // count #of nested scopes to cross, to reach symbol - // - int32_t link_count = 0; + while (symtab) { + Binding b = symtab->lookup_binding(ustr); - while (symtab) { - Binding b = symtab->lookup_binding(ustr); + if (b.is_local()) { + assert(b.i_link() == 0); - if (b.is_local()) { - assert(b.i_link() == 0); + DVariable * vardef = symtab->lookup_var(b); + assert(vardef); - DVariable * vardef = symtab->lookup_var(b); - assert(vardef); + /** ascii diagram here + **/ - - /** ascii diagram here - **/ - - return DVarRef::make(expr_alloc_, - vardef, - link_count); - } else { - assert(b.is_null()); - } - - ++link_count; - symtab = symtab->parent(); + return DVarRef::make(expr_alloc_, + vardef, + link_count); + } else { + assert(b.is_null()); } - } else { - // if we don't already know the symbol, - // -> can't be a valid variable reference - // (whether global or local) - return nullptr; + ++link_count; + symtab = symtab->parent(); } } - // TODO: check global symtab also + DVariable * vardef = global_symtab_->lookup_variable(ustr); - log.retroactively_enable(); - log("STUB: check global symtab"); + if (vardef) { + return DVarRef::make(expr_alloc_, + vardef, + 0 /*link_count -- n/a for globals*/); + } + + // symbol not found return nullptr; } diff --git a/xo-reader2/utest/SchematikaParser.test.cpp b/xo-reader2/utest/SchematikaParser.test.cpp index 665342dc..e4a0e1de 100644 --- a/xo-reader2/utest/SchematikaParser.test.cpp +++ b/xo-reader2/utest/SchematikaParser.test.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -31,6 +32,7 @@ namespace xo { using xo::scm::AExpression; using xo::scm::DDefineExpr; using xo::scm::DApplyExpr; + using xo::scm::DVarRef; using xo::scm::DConstant; //using xo::scm::ParserResult; @@ -232,7 +234,7 @@ namespace xo { { const auto & testname = Catch::getResultCapture().getCurrentTestName(); - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); ParserFixture fixture(testname, c_debug_flag); @@ -267,6 +269,72 @@ namespace xo { log && fixture.log_memory_layout(&log); } + TEST_CASE("SchematikaParser-interactive-def2", "[reader2][SchematikaParser]") + { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); + + parser.begin_interactive_session(); + + { + /** Walkthrough parsing input equivalent to: + * + * def foo : f64 = 3.141593 ; + * + **/ + + std::vector tk_v{ + Token::def_token(), + Token::symbol_token("foo"), + Token::colon_token(), + Token::symbol_token("f64"), + Token::singleassign_token(), + Token::f64_token("3.141593"), + Token::semicolon_token(), + }; + + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + const auto & result = parser.result(); + { + auto expr = obj::from(result.result_expr()); + REQUIRE(expr); + } + + parser.reset_result(); + } + + { + /** Walkthrough parsing input equivalent to: + * + * foo ; + * + **/ + + std::vector tk_v{ +// Token::f64_token("2.0"), +// Token::star_token(), + Token::symbol_token("foo"), + Token::semicolon_token(), + }; + + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + const auto & result = parser.result(); + { + auto expr = obj::from(result.result_expr()); + REQUIRE(expr); + } + } + + log && fixture.log_memory_layout(&log); + } + TEST_CASE("SchematikaParser-interactive-integer", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName();