xo-interpreter2 stack: work on variable references [WIP]
This commit is contained in:
parent
2aa6dfd942
commit
4cd4328f07
6 changed files with 274 additions and 21 deletions
12
include/xo/reader2/ExpectExprSsm.hpp
Normal file
12
include/xo/reader2/ExpectExprSsm.hpp
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
/** @file ExpectExprSsm.hpp
|
||||||
|
*
|
||||||
|
* @author Roland Conybeare, Feb 2026
|
||||||
|
**/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "DExpectExprSsm.hpp"
|
||||||
|
#include "ssm/ISyntaxStateMachine_DExpectExprSsm.hpp"
|
||||||
|
#include "ssm/IPrintable_DExpectExprSsm.hpp"
|
||||||
|
|
||||||
|
/* end ExpectExprSsm.hpp */
|
||||||
|
|
@ -89,6 +89,9 @@ namespace xo {
|
||||||
/** get unique (within stringtable) string, beginning with @p prefix **/
|
/** get unique (within stringtable) string, beginning with @p prefix **/
|
||||||
const DUniqueString * gensym(std::string_view prefix);
|
const DUniqueString * gensym(std::string_view prefix);
|
||||||
|
|
||||||
|
/** get variable defn for @p symbolname, or else nullptr **/
|
||||||
|
Binding lookup_binding(std::string_view symbolname);
|
||||||
|
|
||||||
/** push nested local symtab while parsing the body of a lambda expression;
|
/** push nested local symtab while parsing the body of a lambda expression;
|
||||||
* restore previous symtab at the end of lambda-expression definition.
|
* restore previous symtab at the end of lambda-expression definition.
|
||||||
* See @ref pop_local_symtab
|
* See @ref pop_local_symtab
|
||||||
|
|
@ -229,6 +232,11 @@ namespace xo {
|
||||||
obj<AExpression>,
|
obj<AExpression>,
|
||||||
std::string_view expect_str);
|
std::string_view expect_str);
|
||||||
|
|
||||||
|
/** report error - no binding for variable @p sym
|
||||||
|
**/
|
||||||
|
void error_unbound_variable(std::string_view ssm_name,
|
||||||
|
std::string_view sym);
|
||||||
|
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -3,23 +3,18 @@
|
||||||
* @author Roland Conybeare, Jan 2026
|
* @author Roland Conybeare, Jan 2026
|
||||||
**/
|
**/
|
||||||
|
|
||||||
#include "DExpectExprSsm.hpp"
|
#include "ExpectExprSsm.hpp"
|
||||||
#include "ParserStateMachine.hpp"
|
#include "ParserStateMachine.hpp"
|
||||||
#include "SyntaxStateMachine.hpp"
|
#include "SyntaxStateMachine.hpp"
|
||||||
#include "ssm/ISyntaxStateMachine_DExpectExprSsm.hpp"
|
|
||||||
#include "ssm/ISyntaxStateMachine_DProgressSsm.hpp"
|
#include "ssm/ISyntaxStateMachine_DProgressSsm.hpp"
|
||||||
#include "DSequenceSsm.hpp"
|
#include "DSequenceSsm.hpp"
|
||||||
#include "syntaxstatetype.hpp"
|
#include "syntaxstatetype.hpp"
|
||||||
#include <xo/expression2/DConstant.hpp>
|
#include <xo/expression2/Variable.hpp>
|
||||||
#include <xo/expression2/detail/IExpression_DConstant.hpp>
|
#include <xo/expression2/Constant.hpp>
|
||||||
#include <xo/object2/DBoolean.hpp>
|
#include <xo/object2/Boolean.hpp>
|
||||||
#include <xo/object2/boolean/IGCObject_DBoolean.hpp>
|
#include <xo/object2/Integer.hpp>
|
||||||
#include <xo/object2/DInteger.hpp>
|
#include <xo/object2/Float.hpp>
|
||||||
#include <xo/object2/number/IGCObject_DInteger.hpp>
|
#include <xo/object2/String.hpp>
|
||||||
#include <xo/object2/DFloat.hpp>
|
|
||||||
#include <xo/object2/number/IGCObject_DFloat.hpp>
|
|
||||||
#include <xo/object2/DString.hpp>
|
|
||||||
#include <xo/object2/string/IGCObject_DString.hpp>
|
|
||||||
#include <xo/gc/GCObject.hpp>
|
#include <xo/gc/GCObject.hpp>
|
||||||
#include <xo/facet/facet_implementation.hpp>
|
#include <xo/facet/facet_implementation.hpp>
|
||||||
|
|
||||||
|
|
@ -196,7 +191,27 @@ namespace xo {
|
||||||
DExpectExprSsm::on_symbol_token(const Token & tk,
|
DExpectExprSsm::on_symbol_token(const Token & tk,
|
||||||
ParserStateMachine * p_psm)
|
ParserStateMachine * p_psm)
|
||||||
{
|
{
|
||||||
Super::on_token(tk, p_psm);
|
scope log(XO_DEBUG(p_psm->debug_flag()));
|
||||||
|
|
||||||
|
log && log(xtag("tk", tk));
|
||||||
|
|
||||||
|
const DVariable * var = p_psm->lookup_variable(tk.text());
|
||||||
|
|
||||||
|
if (!var) {
|
||||||
|
p_psm->error_unbound_variable(ssm_classname(),
|
||||||
|
tk.text());
|
||||||
|
}
|
||||||
|
|
||||||
|
// examples of possible continuations from symbol foo
|
||||||
|
// foo ; // (1) foo is entire rvalue expression
|
||||||
|
// foo + ... // (2) foo begin operator expression
|
||||||
|
// foo(..); // (3) foo begin apply function
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
DProgressSsm::start(p_psm->parser_alloc(),
|
||||||
|
obj<AExpression,DVariable>(const_cast<DVariable *>(var)),
|
||||||
|
p_psm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef NOT_YET
|
#ifdef NOT_YET
|
||||||
|
|
|
||||||
|
|
@ -68,8 +68,7 @@ namespace xo {
|
||||||
obj<AAllocator> expr_mm,
|
obj<AAllocator> expr_mm,
|
||||||
ParserStateMachine * p_psm)
|
ParserStateMachine * p_psm)
|
||||||
{
|
{
|
||||||
constexpr bool c_debug_flag = true;
|
scope log(XO_DEBUG(p_psm->debug_flag()));
|
||||||
scope log(XO_DEBUG(c_debug_flag));
|
|
||||||
|
|
||||||
DIfElseExpr * if_expr = DIfElseExpr::_make_empty(expr_mm);
|
DIfElseExpr * if_expr = DIfElseExpr::_make_empty(expr_mm);
|
||||||
DIfElseSsm * if_ssm = DIfElseSsm::_make(parser_mm, if_expr);
|
DIfElseSsm * if_ssm = DIfElseSsm::_make(parser_mm, if_expr);
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,48 @@ namespace xo {
|
||||||
return stringtable_.gensym(str);
|
return stringtable_.gensym(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Binding
|
||||||
|
ParserStateMachine::lookup_binding(std::string_view symbolname)
|
||||||
|
{
|
||||||
|
scope log(XO_DEBUG(debug_flag_));
|
||||||
|
|
||||||
|
if (!local_symtab_)
|
||||||
|
return Binding::null();
|
||||||
|
|
||||||
|
const DUniqueString * ustr = stringtable_.lookup(symbolname);
|
||||||
|
|
||||||
|
if (!ustr) {
|
||||||
|
// if not in string table, then can't be a variable either
|
||||||
|
return Binding::null();
|
||||||
|
}
|
||||||
|
|
||||||
|
DLocalSymtab * symtab = local_symtab_;
|
||||||
|
|
||||||
|
// count #of nested scopes to cross, to reach symbol
|
||||||
|
//
|
||||||
|
int32_t link_count = 0;
|
||||||
|
|
||||||
|
while (symtab) {
|
||||||
|
Binding b = symtab->lookup_binding(ustr);
|
||||||
|
|
||||||
|
if (b.is_local()) {
|
||||||
|
assert(b.i_link() == 0);
|
||||||
|
|
||||||
|
return Binding(link_count, b.j_slot());
|
||||||
|
}
|
||||||
|
|
||||||
|
++link_count;
|
||||||
|
symtab = symtab->parent();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check global symtab also
|
||||||
|
|
||||||
|
log.retroactively_enable();
|
||||||
|
log("STUB: check global symtab");
|
||||||
|
|
||||||
|
return Binding::null();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ParserStateMachine::push_local_symtab(DLocalSymtab * symtab)
|
ParserStateMachine::push_local_symtab(DLocalSymtab * symtab)
|
||||||
{
|
{
|
||||||
|
|
@ -400,6 +442,21 @@ namespace xo {
|
||||||
|
|
||||||
this->capture_error(ssm_name, errmsg);
|
this->capture_error(ssm_name, errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ParserStateMachine::error_unbound_variable(std::string_view ssm_name,
|
||||||
|
std::string_view sym)
|
||||||
|
{
|
||||||
|
auto errmsg_string = tostr("No binding for symbol",
|
||||||
|
xtag("symbol", sym),
|
||||||
|
xtag("ssm", ssm_name));
|
||||||
|
|
||||||
|
auto errmsg = DString::from_view(expr_alloc_,
|
||||||
|
std::string_view(errmsg_string));
|
||||||
|
|
||||||
|
this->capture_error(ssm_name, errmsg);
|
||||||
|
}
|
||||||
|
|
||||||
} /*namespace scm*/
|
} /*namespace scm*/
|
||||||
} /*namespace xo*/
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,7 @@ namespace xo {
|
||||||
{
|
{
|
||||||
const auto & testname = Catch::getResultCapture().getCurrentTestName();
|
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));
|
scope log(XO_DEBUG(c_debug_flag), xtag("test", testname));
|
||||||
|
|
||||||
ArenaConfig config;
|
ArenaConfig config;
|
||||||
|
|
@ -285,7 +285,7 @@ namespace xo {
|
||||||
{
|
{
|
||||||
const auto & testname = Catch::getResultCapture().getCurrentTestName();
|
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));
|
scope log(XO_DEBUG(c_debug_flag), xtag("test", testname));
|
||||||
|
|
||||||
ArenaConfig config;
|
ArenaConfig config;
|
||||||
|
|
@ -350,7 +350,7 @@ namespace xo {
|
||||||
{
|
{
|
||||||
const auto & testname = Catch::getResultCapture().getCurrentTestName();
|
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));
|
scope log(XO_DEBUG(c_debug_flag), xtag("test", testname));
|
||||||
|
|
||||||
ArenaConfig config;
|
ArenaConfig config;
|
||||||
|
|
@ -415,7 +415,7 @@ namespace xo {
|
||||||
{
|
{
|
||||||
const auto & testname = Catch::getResultCapture().getCurrentTestName();
|
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));
|
scope log(XO_DEBUG(c_debug_flag), xtag("test", testname));
|
||||||
|
|
||||||
ArenaConfig config;
|
ArenaConfig config;
|
||||||
|
|
@ -517,7 +517,7 @@ namespace xo {
|
||||||
|
|
||||||
TEST_CASE("SchematikaParser-interactive-lambda", "[reader2][SchematikaParser]")
|
TEST_CASE("SchematikaParser-interactive-lambda", "[reader2][SchematikaParser]")
|
||||||
{
|
{
|
||||||
constexpr bool c_debug_flag = true;
|
constexpr bool c_debug_flag = false;
|
||||||
scope log(XO_DEBUG(c_debug_flag));
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
ArenaConfig config;
|
ArenaConfig config;
|
||||||
|
|
@ -725,7 +725,7 @@ namespace xo {
|
||||||
|
|
||||||
TEST_CASE("SchematikaParser-interactive-if", "[reader2][SchematikaParser]")
|
TEST_CASE("SchematikaParser-interactive-if", "[reader2][SchematikaParser]")
|
||||||
{
|
{
|
||||||
constexpr bool c_debug_flag = true;
|
constexpr bool c_debug_flag = false;
|
||||||
scope log(XO_DEBUG(c_debug_flag));
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
ArenaConfig config;
|
ArenaConfig config;
|
||||||
|
|
@ -834,6 +834,168 @@ namespace xo {
|
||||||
//REQUIRE(result.error_description());
|
//REQUIRE(result.error_description());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("SchematikaParser-interactive-lambda2", "[reader2][SchematikaParser]")
|
||||||
|
{
|
||||||
|
constexpr bool c_debug_flag = true;
|
||||||
|
scope log(XO_DEBUG(c_debug_flag));
|
||||||
|
|
||||||
|
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, 4096, expr_alloc, false /*debug_flag*/);
|
||||||
|
|
||||||
|
parser.begin_interactive_session();
|
||||||
|
|
||||||
|
/** Walkthrough parsing input equivalent to:
|
||||||
|
*
|
||||||
|
* lambda (x : i64) -> i64 { x * x };
|
||||||
|
*
|
||||||
|
**/
|
||||||
|
|
||||||
|
{
|
||||||
|
auto & result = parser.on_token(Token::lambda_token());
|
||||||
|
|
||||||
|
log && log("after lambda token:");
|
||||||
|
log && log(xtag("parser", &parser));
|
||||||
|
log && log(xtag("result", result));
|
||||||
|
|
||||||
|
REQUIRE(parser.has_incomplete_expr() == true);
|
||||||
|
REQUIRE(!result.is_error());
|
||||||
|
REQUIRE(result.is_incomplete());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto & result = parser.on_token(Token::leftparen_token());
|
||||||
|
|
||||||
|
log && log("after lparen token:");
|
||||||
|
log && log(xtag("parser", &parser));
|
||||||
|
log && log(xtag("result", result));
|
||||||
|
|
||||||
|
REQUIRE(parser.has_incomplete_expr() == true);
|
||||||
|
REQUIRE(!result.is_error());
|
||||||
|
REQUIRE(result.is_incomplete());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto & result = parser.on_token(Token::symbol_token("x"));
|
||||||
|
|
||||||
|
log && log("after symbol(n) token:");
|
||||||
|
log && log(xtag("parser", &parser));
|
||||||
|
log && log(xtag("result", result));
|
||||||
|
|
||||||
|
REQUIRE(parser.has_incomplete_expr() == true);
|
||||||
|
REQUIRE(!result.is_error());
|
||||||
|
REQUIRE(result.is_incomplete());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto & result = parser.on_token(Token::colon_token());
|
||||||
|
|
||||||
|
log && log("after colon token:");
|
||||||
|
log && log(xtag("parser", &parser));
|
||||||
|
log && log(xtag("result", result));
|
||||||
|
|
||||||
|
REQUIRE(parser.has_incomplete_expr() == true);
|
||||||
|
REQUIRE(!result.is_error());
|
||||||
|
REQUIRE(result.is_incomplete());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto & result = parser.on_token(Token::symbol_token("i64"));
|
||||||
|
|
||||||
|
log && log("after symbol(i64) token:");
|
||||||
|
log && log(xtag("parser", &parser));
|
||||||
|
log && log(xtag("result", result));
|
||||||
|
|
||||||
|
REQUIRE(parser.has_incomplete_expr() == true);
|
||||||
|
REQUIRE(!result.is_error());
|
||||||
|
REQUIRE(result.is_incomplete());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto & result = parser.on_token(Token::rightparen_token());
|
||||||
|
|
||||||
|
log && log("after rightparen token:");
|
||||||
|
log && log(xtag("parser", &parser));
|
||||||
|
log && log(xtag("result", result));
|
||||||
|
|
||||||
|
REQUIRE(parser.has_incomplete_expr() == true);
|
||||||
|
REQUIRE(!result.is_error());
|
||||||
|
REQUIRE(result.is_incomplete());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto & result = parser.on_token(Token::yields_token());
|
||||||
|
|
||||||
|
log && log("after yields token:");
|
||||||
|
log && log(xtag("parser", &parser));
|
||||||
|
log && log(xtag("result", result));
|
||||||
|
|
||||||
|
REQUIRE(parser.has_incomplete_expr() == true);
|
||||||
|
REQUIRE(!result.is_error());
|
||||||
|
REQUIRE(result.is_incomplete());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto & result = parser.on_token(Token::symbol_token("i64"));
|
||||||
|
|
||||||
|
log && log("after symbol(i64) token:");
|
||||||
|
log && log(xtag("parser", &parser));
|
||||||
|
log && log(xtag("result", result));
|
||||||
|
|
||||||
|
REQUIRE(parser.has_incomplete_expr() == true);
|
||||||
|
REQUIRE(!result.is_error());
|
||||||
|
REQUIRE(result.is_incomplete());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto & result = parser.on_token(Token::leftbrace_token());
|
||||||
|
|
||||||
|
log && log("after leftbrace token:");
|
||||||
|
log && log(xtag("parser", &parser));
|
||||||
|
log && log(xtag("result", result));
|
||||||
|
|
||||||
|
REQUIRE(parser.has_incomplete_expr() == true);
|
||||||
|
REQUIRE(!result.is_error());
|
||||||
|
REQUIRE(result.is_incomplete());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto & result = parser.on_token(Token::symbol_token("x"));
|
||||||
|
|
||||||
|
log && log("after symbol(x) token:");
|
||||||
|
log && log(xtag("parser", &parser));
|
||||||
|
log && log(xtag("result", result));
|
||||||
|
|
||||||
|
REQUIRE(parser.has_incomplete_expr() == true);
|
||||||
|
REQUIRE(!result.is_error());
|
||||||
|
REQUIRE(result.is_incomplete());
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef NOPE
|
||||||
|
{
|
||||||
|
auto & result = parser.on_token(Token::rightbrace_token());
|
||||||
|
|
||||||
|
log && log("after rightbrace token:");
|
||||||
|
log && log(xtag("parser", &parser));
|
||||||
|
log && log(xtag("result", result));
|
||||||
|
|
||||||
|
REQUIRE(parser.has_incomplete_expr() == false);
|
||||||
|
REQUIRE(!result.is_error());
|
||||||
|
REQUIRE(result.is_expression());
|
||||||
|
REQUIRE(result.result_expr());
|
||||||
|
}
|
||||||
|
|
||||||
|
//REQUIRE(result.is_error());
|
||||||
|
//// illegal input on token
|
||||||
|
//REQUIRE(result.error_description());
|
||||||
|
#endif
|
||||||
|
REQUIRE(false);
|
||||||
|
}
|
||||||
} /*namespace ut*/
|
} /*namespace ut*/
|
||||||
} /*namespace xo*/
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue