diff --git a/xo-expression2/include/xo/expression2/Binding.hpp b/xo-expression2/include/xo/expression2/Binding.hpp index 6dffb16b..a27de6b3 100644 --- a/xo-expression2/include/xo/expression2/Binding.hpp +++ b/xo-expression2/include/xo/expression2/Binding.hpp @@ -24,6 +24,9 @@ namespace xo { static Binding global() { return Binding(s_link_global, 0); } static Binding local(int32_t j_slot) { return Binding(0, j_slot); } + bool is_null() const { + return (i_link_ == s_link_sentinel) && (j_slot_ == -1); + } bool is_global() const { return i_link_ == s_link_global; } bool is_local() const { return (i_link_ == 0) && (j_slot_ >= 0); } diff --git a/xo-expression2/include/xo/expression2/Variable.hpp b/xo-expression2/include/xo/expression2/Variable.hpp new file mode 100644 index 00000000..26ef649b --- /dev/null +++ b/xo-expression2/include/xo/expression2/Variable.hpp @@ -0,0 +1,13 @@ +/** @file Variable.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DVariable.hpp" +#include "detail/IExpression_DVariable.hpp" +#include "detail/IGCObject_DVariable.hpp" +#include "detail/IPrintable_DVariable.hpp" + +/* end Variable.hpp */ diff --git a/xo-interpreter2/CMakeLists.txt b/xo-interpreter2/CMakeLists.txt index 259c3f03..25d8cd0d 100644 --- a/xo-interpreter2/CMakeLists.txt +++ b/xo-interpreter2/CMakeLists.txt @@ -77,6 +77,20 @@ xo_add_genfacetimpl( # ---------------------------------------------------------------- +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-interpreter2-facetimpl-procedure-closure + FACET_PKG xo_procedure2 + FACET Printable + REPR DClosure + INPUT idl/IProcedure_DClosure.json5 + OUTPUT_HPP_DIR include/xo/interpreter2 + OUTPUT_IMPL_SUBDIR detail + OUTPUT_CPP_DIR src/interpreter2 +) + +# ---------------------------------------------------------------- + xo_add_genfacet_all(xo-interpreter2-genfacet-all) # ---------------------------------------------------------------- diff --git a/xo-interpreter2/idl/IProcedure_DClosure.json5 b/xo-interpreter2/idl/IProcedure_DClosure.json5 new file mode 100644 index 00000000..d503f5c6 --- /dev/null +++ b/xo-interpreter2/idl/IProcedure_DClosure.json5 @@ -0,0 +1,17 @@ +{ + mode: "implementation", + includes: [ + "", + "", + "", + "", + ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Procedure.json5", + brief: "provide AProcedure interface for DClosure", + using_doxygen: true, + repr: "DClosure", + doc: [ "implement AProcedure for DClosure" ], +} diff --git a/xo-interpreter2/include/xo/interpreter2/Closure.hpp b/xo-interpreter2/include/xo/interpreter2/Closure.hpp new file mode 100644 index 00000000..f352e7f0 --- /dev/null +++ b/xo-interpreter2/include/xo/interpreter2/Closure.hpp @@ -0,0 +1,11 @@ +/** @file Closure.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DClosure.hpp" +#include "detail/IProcedure_DClosure.hpp" + +/* end Closure.hpp */ diff --git a/xo-interpreter2/include/xo/interpreter2/DClosure.hpp b/xo-interpreter2/include/xo/interpreter2/DClosure.hpp index 09966038..bcf85c97 100644 --- a/xo-interpreter2/include/xo/interpreter2/DClosure.hpp +++ b/xo-interpreter2/include/xo/interpreter2/DClosure.hpp @@ -3,8 +3,11 @@ * @author Roland Conybeare, Feb 2026 **/ +#pragma once + #include "LocalEnv.hpp" #include +#include namespace xo { namespace scm { @@ -15,7 +18,10 @@ namespace xo { **/ class DClosure { public: + using ARuntimeContext = xo::scm::ARuntimeContext; using AAllocator = xo::mm::AAllocator; + using AGCObject = xo::mm::AGCObject; + using ppindentinfo = xo::print::ppindentinfo; using size_type = std::int32_t; public: @@ -29,11 +35,35 @@ namespace xo { const DLambdaExpr * lm, const DLocalEnv * env); + /** @defgroup scm-closure-general-methods **/ + ///@{ + + const DLambdaExpr * lambda() const noexcept { return lambda_; } + const DLocalEnv * env() const noexcept { return env_; } + + ///@} + /** @defgroup scm-closure-procedure-facet **/ + ///@{ + /** for now, support just fixed-arity procedures **/ bool is_nary() const noexcept { return false; } /** number of arguments expected by this procedure (-1 if nary) **/ size_type n_args() const noexcept { return lambda_->n_args(); } + obj apply_nocheck(obj rcx, const DArray * args); + + ///@} + /** @defgroup scm-closure-gcobject-facet **/ + ///@{ + + ///@} + /** @defgroup scm-closure-printable-facet **/ + ///@{ + + bool pretty(const ppindentinfo & ppii) const; + + ///@} + private: /** lambda expression **/ const DLambdaExpr * lambda_ = nullptr; diff --git a/xo-interpreter2/include/xo/interpreter2/detail/IProcedure_DClosure.hpp b/xo-interpreter2/include/xo/interpreter2/detail/IProcedure_DClosure.hpp new file mode 100644 index 00000000..2c966a50 --- /dev/null +++ b/xo-interpreter2/include/xo/interpreter2/detail/IProcedure_DClosure.hpp @@ -0,0 +1,67 @@ +/** @file IProcedure_DClosure.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IProcedure_DClosure.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IProcedure_DClosure.json5] + **/ + +#pragma once + +#include "Procedure.hpp" +#include +#include +#include +#include +#include "DClosure.hpp" + +namespace xo { namespace scm { class IProcedure_DClosure; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::IProcedure_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IProcedure_DClosure + **/ + class IProcedure_DClosure { + public: + /** @defgroup scm-procedure-dclosure-type-traits **/ + ///@{ + using AGCObject = xo::scm::AProcedure::AGCObject; + using Copaque = xo::scm::AProcedure::Copaque; + using Opaque = xo::scm::AProcedure::Opaque; + ///@} + /** @defgroup scm-procedure-dclosure-methods **/ + ///@{ + // const methods + /** true iff procedure takes n arguments **/ + static bool is_nary(const DClosure & self) noexcept; + /** number of arguments. -1 for n-ary **/ + static std::int32_t n_args(const DClosure & self) noexcept; + + // non-const methods + /** invoke procedure; assume arguments satisfy type system **/ + static obj apply_nocheck(DClosure & self, obj rcx, const DArray * args); + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/xo-interpreter2/src/interpreter2/CMakeLists.txt b/xo-interpreter2/src/interpreter2/CMakeLists.txt index e0903be8..b47ea31d 100644 --- a/xo-interpreter2/src/interpreter2/CMakeLists.txt +++ b/xo-interpreter2/src/interpreter2/CMakeLists.txt @@ -16,6 +16,8 @@ set(SELF_SRCS IGCObject_DVsmApplyFrame.cpp IPrintable_DVsmApplyFrame.cpp + IProcedure_DClosure.cpp + VsmInstr.cpp DClosure.cpp diff --git a/xo-interpreter2/src/interpreter2/DClosure.cpp b/xo-interpreter2/src/interpreter2/DClosure.cpp index 6d9bc446..1057a25d 100644 --- a/xo-interpreter2/src/interpreter2/DClosure.cpp +++ b/xo-interpreter2/src/interpreter2/DClosure.cpp @@ -6,6 +6,8 @@ #include "DClosure.hpp" namespace xo { + using xo::mm::AGCObject; + namespace scm { DClosure::DClosure(const DLambdaExpr * lm, @@ -23,6 +25,16 @@ namespace xo { return new (mem) DClosure(lm, env); } + obj + DClosure::apply_nocheck(obj rcx, + const DArray * args) + { + (void)rcx; + (void)args; + + assert(false); + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/xo-interpreter2/src/interpreter2/IProcedure_DClosure.cpp b/xo-interpreter2/src/interpreter2/IProcedure_DClosure.cpp new file mode 100644 index 00000000..b41c7be1 --- /dev/null +++ b/xo-interpreter2/src/interpreter2/IProcedure_DClosure.cpp @@ -0,0 +1,39 @@ +/** @file IProcedure_DClosure.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IProcedure_DClosure.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IProcedure_DClosure.json5] +**/ + +#include "detail/IProcedure_DClosure.hpp" + +namespace xo { + namespace scm { + auto + IProcedure_DClosure::is_nary(const DClosure & self) noexcept -> bool + { + return self.is_nary(); + } + + auto + IProcedure_DClosure::n_args(const DClosure & self) noexcept -> std::int32_t + { + return self.n_args(); + } + + auto + IProcedure_DClosure::apply_nocheck(DClosure & self, obj rcx, const DArray * args) -> obj + { + return self.apply_nocheck(rcx, args); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IProcedure_DClosure.cpp */ diff --git a/xo-interpreter2/src/interpreter2/interpreter2_register_facets.cpp b/xo-interpreter2/src/interpreter2/interpreter2_register_facets.cpp index b16d33ef..820dac2c 100644 --- a/xo-interpreter2/src/interpreter2/interpreter2_register_facets.cpp +++ b/xo-interpreter2/src/interpreter2/interpreter2_register_facets.cpp @@ -8,6 +8,8 @@ #include "VsmApplyFrame.hpp" #include "VsmEvalArgsFrame.hpp" +#include "Closure.hpp" + #include #include #include @@ -36,8 +38,15 @@ namespace xo { FacetRegistry::register_impl(); FacetRegistry::register_impl(); + // Procedure + // +- Primitive_gco_2_gco_gco + // \- Closure + + FacetRegistry::register_impl(); + log && log(xtag("DVsmApplyFrame.tseq", typeseq::id())); log && log(xtag("DVsmEvalArgsFrame.tseq", typeseq::id())); + log && log(xtag("DClosure.tseq", typeseq::id())); return true; } diff --git a/xo-interpreter2/utest/VirtualSchematikaMachine.test.cpp b/xo-interpreter2/utest/VirtualSchematikaMachine.test.cpp index 32cf7cab..90805af7 100644 --- a/xo-interpreter2/utest/VirtualSchematikaMachine.test.cpp +++ b/xo-interpreter2/utest/VirtualSchematikaMachine.test.cpp @@ -186,6 +186,43 @@ namespace xo { vsm.visit_pools(visitor); } + TEST_CASE("VirtualSchematikaMachine-lambda1", "[interpreter2][VSM]") + { + scope log(XO_DEBUG(true)); + + VsmConfig cfg; + VirtualSchematikaMachine vsm(cfg); + + bool eof_flag = false; + + vsm.begin_interactive_session(); + VsmResultExt res = vsm.read_eval_print(span_type::from_cstr("lambda (x : i64) -> i64 { x * x; };"), eof_flag); + + REQUIRE(res.is_value()); + REQUIRE(res.value()); + + log && log(xtag("res.tseq", res.value()->_typeseq())); + + auto x = obj::from(*res.value()); + + REQUIRE(x); + REQUIRE(x.data()->value() == 1.570796325); + + REQUIRE(res.remaining_.size() == 1); + REQUIRE(*res.remaining_.lo() == '\n'); + + auto visitor = [&log](const MemorySizeInfo & info) { + log && log(xtag("resource", info.resource_name_), + xtag("used", info.used_), + xtag("alloc", info.allocated_), + xtag("commit", info.committed_), + xtag("resv", info.reserved_)); + }; + + FacetRegistry::instance().visit_pools(visitor); + vsm.visit_pools(visitor); + } + } /*namespace ut*/ } /*namespace xo*/ diff --git a/xo-object2/include/xo/object2/Boolean.hpp b/xo-object2/include/xo/object2/Boolean.hpp new file mode 100644 index 00000000..a246ffc0 --- /dev/null +++ b/xo-object2/include/xo/object2/Boolean.hpp @@ -0,0 +1,12 @@ +/** @file Boolean.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DBoolean.hpp" +#include "boolean/IGCObject_DBoolean.hpp" +#include "boolean/IPrintable_DBoolean.hpp" + +/* end Boolean.hpp */ diff --git a/xo-object2/include/xo/object2/String.hpp b/xo-object2/include/xo/object2/String.hpp index b2e6d09b..111b04fb 100644 --- a/xo-object2/include/xo/object2/String.hpp +++ b/xo-object2/include/xo/object2/String.hpp @@ -1,6 +1,6 @@ /** @file String.hpp * - * @author Roland Conybeare, Feb 22026 + * @author Roland Conybeare, Feb 2026 **/ #pragma once diff --git a/xo-procedure2/idl/Procedure.json5 b/xo-procedure2/idl/Procedure.json5 index 91c8bdf3..449414f0 100644 --- a/xo-procedure2/idl/Procedure.json5 +++ b/xo-procedure2/idl/Procedure.json5 @@ -65,4 +65,5 @@ ] } ], + router_facet_explicit_content: [ ], } diff --git a/xo-reader2/include/xo/reader2/ExpectExprSsm.hpp b/xo-reader2/include/xo/reader2/ExpectExprSsm.hpp new file mode 100644 index 00000000..d46ef489 --- /dev/null +++ b/xo-reader2/include/xo/reader2/ExpectExprSsm.hpp @@ -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 */ diff --git a/xo-reader2/include/xo/reader2/ParserStateMachine.hpp b/xo-reader2/include/xo/reader2/ParserStateMachine.hpp index 3fae8903..2bee6a96 100644 --- a/xo-reader2/include/xo/reader2/ParserStateMachine.hpp +++ b/xo-reader2/include/xo/reader2/ParserStateMachine.hpp @@ -89,6 +89,9 @@ namespace xo { /** get unique (within stringtable) string, beginning with @p 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; * restore previous symtab at the end of lambda-expression definition. * See @ref pop_local_symtab @@ -229,6 +232,11 @@ namespace xo { obj, 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: diff --git a/xo-reader2/src/reader2/DExpectExprSsm.cpp b/xo-reader2/src/reader2/DExpectExprSsm.cpp index cddfb865..b1b0701b 100644 --- a/xo-reader2/src/reader2/DExpectExprSsm.cpp +++ b/xo-reader2/src/reader2/DExpectExprSsm.cpp @@ -3,23 +3,18 @@ * @author Roland Conybeare, Jan 2026 **/ -#include "DExpectExprSsm.hpp" +#include "ExpectExprSsm.hpp" #include "ParserStateMachine.hpp" #include "SyntaxStateMachine.hpp" -#include "ssm/ISyntaxStateMachine_DExpectExprSsm.hpp" #include "ssm/ISyntaxStateMachine_DProgressSsm.hpp" #include "DSequenceSsm.hpp" #include "syntaxstatetype.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include @@ -196,7 +191,27 @@ namespace xo { DExpectExprSsm::on_symbol_token(const Token & tk, 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(const_cast(var)), + p_psm); } #ifdef NOT_YET diff --git a/xo-reader2/src/reader2/DIfElseSsm.cpp b/xo-reader2/src/reader2/DIfElseSsm.cpp index 7efb4a7e..0782f23a 100644 --- a/xo-reader2/src/reader2/DIfElseSsm.cpp +++ b/xo-reader2/src/reader2/DIfElseSsm.cpp @@ -68,8 +68,7 @@ namespace xo { obj expr_mm, ParserStateMachine * p_psm) { - constexpr bool c_debug_flag = true; - scope log(XO_DEBUG(c_debug_flag)); + scope log(XO_DEBUG(p_psm->debug_flag())); DIfElseExpr * if_expr = DIfElseExpr::_make_empty(expr_mm); DIfElseSsm * if_ssm = DIfElseSsm::_make(parser_mm, if_expr); diff --git a/xo-reader2/src/reader2/ParserStateMachine.cpp b/xo-reader2/src/reader2/ParserStateMachine.cpp index 38f7ff4a..bd1effbb 100644 --- a/xo-reader2/src/reader2/ParserStateMachine.cpp +++ b/xo-reader2/src/reader2/ParserStateMachine.cpp @@ -107,6 +107,48 @@ namespace xo { 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 ParserStateMachine::push_local_symtab(DLocalSymtab * symtab) { @@ -400,6 +442,21 @@ namespace xo { 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 xo*/ diff --git a/xo-reader2/utest/SchematikaParser.test.cpp b/xo-reader2/utest/SchematikaParser.test.cpp index 2fb10ea5..48983353 100644 --- a/xo-reader2/utest/SchematikaParser.test.cpp +++ b/xo-reader2/utest/SchematikaParser.test.cpp @@ -220,7 +220,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)); ArenaConfig config; @@ -285,7 +285,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)); ArenaConfig config; @@ -350,7 +350,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)); ArenaConfig config; @@ -415,7 +415,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)); ArenaConfig config; @@ -517,7 +517,7 @@ namespace xo { 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)); ArenaConfig config; @@ -725,7 +725,7 @@ namespace xo { 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)); ArenaConfig config; @@ -834,6 +834,168 @@ namespace xo { //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 expr_alloc = with_facet::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 xo*/