diff --git a/xo-interpreter2/src/interpreter2/VirtualSchematikaMachine.cpp b/xo-interpreter2/src/interpreter2/VirtualSchematikaMachine.cpp index 8807a72c..6bcbe8bf 100644 --- a/xo-interpreter2/src/interpreter2/VirtualSchematikaMachine.cpp +++ b/xo-interpreter2/src/interpreter2/VirtualSchematikaMachine.cpp @@ -15,6 +15,7 @@ #include "VsmRcx.hpp" #include "Closure.hpp" #include +#include #include #include #include @@ -914,7 +915,7 @@ namespace xo { static DPrimitive_gco_0 s_cwd_pm("_cwd", &xfer_cwd); - // ----- primitive: fn_nth() ----- + // ----- primitive: nth() ----- // TODO: seq_gc -> obj // n_gco -> obj @@ -934,6 +935,24 @@ namespace xo { static DPrimitive_gco_2_gco_gco s_nth_pm("_nth", &xfer_nth); + // ----- primitive: cons() ----- + + obj + xfer_cons(obj rcx, + obj car, + obj cdr) + { + (void)rcx; + + auto cdr_list = obj::from(cdr); + + return DList::cons(rcx.allocator(), + car, + cdr_list.data()); + } + + static DPrimitive_gco_2_gco_gco s_cons_pm("_cons", &xfer_cons); + // ----- primitive: fn_n_args() ----- obj @@ -1038,6 +1057,18 @@ namespace xo { obj(&s_nth_pm)); } + /* cons */ + { + const DUniqueString * name + = reader_.intern_string("cons"); + + global_env_->_upsert_value + (mm_.to_op(), + name, + Reflect::require(), + obj(&s_cons_pm)); + } + /* fn_n_args */ { const DUniqueString * name diff --git a/xo-interpreter2/utest/VirtualSchematikaMachine.test.cpp b/xo-interpreter2/utest/VirtualSchematikaMachine.test.cpp index 21b5faa3..9fb85ffc 100644 --- a/xo-interpreter2/utest/VirtualSchematikaMachine.test.cpp +++ b/xo-interpreter2/utest/VirtualSchematikaMachine.test.cpp @@ -31,7 +31,7 @@ namespace xo { using xo::scm::DFloat; using xo::scm::DBoolean; using xo::scm::DInteger; - using xo::scm::DRuntimeError; +// using xo::scm::DRuntimeError; using xo::mm::AGCObject; using xo::mm::MemorySizeInfo; using xo::mm::AAllocator; diff --git a/xo-object2/include/xo/object2/DList.hpp b/xo-object2/include/xo/object2/DList.hpp index 01ef3eb6..8009f7b5 100644 --- a/xo-object2/include/xo/object2/DList.hpp +++ b/xo-object2/include/xo/object2/DList.hpp @@ -26,11 +26,14 @@ namespace xo { DList(xo::obj h, DList * r) : head_{h}, rest_{r} {} - /** sentinel for null list. + /** sentinel for null list. Idempotent. * Application code may prefer ListOps::nil() **/ static DList * _nil(); + /** like _nil(), but retrn fop wrapper **/ + static obj nil(); + /** list with first element @p car, * followed by contents of list @p cdr. * Shares structure with @p cdr @@ -40,6 +43,11 @@ namespace xo { obj car, DList * cdr); + /** like @c _cons(mm,car,cdr), but return fop wrapper **/ + static obj cons(obj mm, + obj car, + DList * cdr); + /** DList length is at least 1 **/ bool is_empty() const noexcept; /** DList models a finite sequence **/ diff --git a/xo-object2/src/object2/DList.cpp b/xo-object2/src/object2/DList.cpp index 25770d01..7ef06f36 100644 --- a/xo-object2/src/object2/DList.cpp +++ b/xo-object2/src/object2/DList.cpp @@ -17,7 +17,7 @@ namespace xo { using xo::print::APrintable; using xo::mm::AGCObject; using xo::facet::FacetRegistry; - using xo::facet::typeseq; + //using xo::facet::typeseq; namespace scm { static DList s_null(obj(), nullptr); @@ -28,6 +28,12 @@ namespace xo { return &s_null; } + obj + DList::nil() + { + return obj(_nil()); + } + DList * DList::_cons(obj mm, obj car, @@ -38,6 +44,14 @@ namespace xo { return new (mem) DList(car, cdr); } + obj + DList::cons(obj mm, + obj car, + DList * cdr) + { + return obj(_cons(mm, car, cdr)); + } + #ifdef OBSOLETE DList * DList::list(obj mm, @@ -137,8 +151,6 @@ namespace xo { obj elt = FacetRegistry::instance().variant(l->head_); - - assert(elt.data()); if (!pps->print_upto(elt)) diff --git a/xo-reader2/include/xo/reader2/DExpectExprSsm.hpp b/xo-reader2/include/xo/reader2/DExpectExprSsm.hpp index 539fbb39..66189754 100644 --- a/xo-reader2/include/xo/reader2/DExpectExprSsm.hpp +++ b/xo-reader2/include/xo/reader2/DExpectExprSsm.hpp @@ -84,12 +84,18 @@ namespace xo { void on_quote_token(const Token & tk, ParserStateMachine * p_psm); - /** step state machine for this syntax on incoming boolean literal token @p tkk + /** step state machine for this syntax on incoming boolean literal token @p tk * with overall parser state in @p p_psm **/ void on_bool_token(const Token & tk, ParserStateMachine * p_psm); + /** step state machine for this syntax on incoming nil literal token @p tk + * with overall parser state in @p p_psm. + **/ + void on_nil_token(const Token & tk, + ParserStateMachine * p_psm); + /** update state for this syntax on incoming f64 token @p tk, * overall parser state in @p p_psm **/ diff --git a/xo-reader2/include/xo/reader2/DToplevelSeqSsm.hpp b/xo-reader2/include/xo/reader2/DToplevelSeqSsm.hpp index 9bb9b076..2466ed1e 100644 --- a/xo-reader2/include/xo/reader2/DToplevelSeqSsm.hpp +++ b/xo-reader2/include/xo/reader2/DToplevelSeqSsm.hpp @@ -119,6 +119,11 @@ namespace xo { **/ void on_bool_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming nil token @p tk, + * overall parser state in @p p_psm + **/ + void on_nil_token(const Token & tk, ParserStateMachine * p_psm); + /** update state for this syntax on incoming leftparen token @p tk, * overall parser state in @p p_psm **/ diff --git a/xo-reader2/src/reader2/DApplySsm.cpp b/xo-reader2/src/reader2/DApplySsm.cpp index ad9a4e50..cd591c9c 100644 --- a/xo-reader2/src/reader2/DApplySsm.cpp +++ b/xo-reader2/src/reader2/DApplySsm.cpp @@ -171,6 +171,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_lambda: case tokentype::tk_let: diff --git a/xo-reader2/src/reader2/DDefineSsm.cpp b/xo-reader2/src/reader2/DDefineSsm.cpp index 344e1fc1..2f7f99be 100644 --- a/xo-reader2/src/reader2/DDefineSsm.cpp +++ b/xo-reader2/src/reader2/DDefineSsm.cpp @@ -546,6 +546,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_lambda: case tokentype::tk_then: diff --git a/xo-reader2/src/reader2/DDeftypeSsm.cpp b/xo-reader2/src/reader2/DDeftypeSsm.cpp index ec36391a..383f4fee 100644 --- a/xo-reader2/src/reader2/DDeftypeSsm.cpp +++ b/xo-reader2/src/reader2/DDeftypeSsm.cpp @@ -150,6 +150,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_lambda: case tokentype::tk_then: diff --git a/xo-reader2/src/reader2/DExpectExprSsm.cpp b/xo-reader2/src/reader2/DExpectExprSsm.cpp index c2d46140..f4fabfc9 100644 --- a/xo-reader2/src/reader2/DExpectExprSsm.cpp +++ b/xo-reader2/src/reader2/DExpectExprSsm.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -155,6 +156,10 @@ namespace xo { this->on_bool_token(tk, p_psm); return; + case tokentype::tk_nil: + this->on_nil_token(tk, p_psm); + return; + case tokentype::tk_if: this->on_if_token(tk, p_psm); return; @@ -372,6 +377,23 @@ namespace xo { p_psm); } + void + DExpectExprSsm::on_nil_token(const Token & tk, + ParserStateMachine * p_psm) + { + (void)tk; + + auto nil = DList::nil(); + auto expr = DConstant::make(p_psm->expr_alloc(), nil); + + // DProgressSsm responsible for resolving cases like + // nil ++ nil; + + DProgressSsm::start(p_psm->parser_alloc(), + expr, + p_psm); + } + void DExpectExprSsm::on_f64_token(const Token & tk, ParserStateMachine * p_psm) diff --git a/xo-reader2/src/reader2/DExpectFormalArgSsm.cpp b/xo-reader2/src/reader2/DExpectFormalArgSsm.cpp index db287abf..a17d094c 100644 --- a/xo-reader2/src/reader2/DExpectFormalArgSsm.cpp +++ b/xo-reader2/src/reader2/DExpectFormalArgSsm.cpp @@ -135,6 +135,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_then: case tokentype::tk_else: diff --git a/xo-reader2/src/reader2/DExpectFormalArglistSsm.cpp b/xo-reader2/src/reader2/DExpectFormalArglistSsm.cpp index 67f327e1..9f7da033 100644 --- a/xo-reader2/src/reader2/DExpectFormalArglistSsm.cpp +++ b/xo-reader2/src/reader2/DExpectFormalArglistSsm.cpp @@ -165,6 +165,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_then: case tokentype::tk_else: diff --git a/xo-reader2/src/reader2/DExpectListTypeSsm.cpp b/xo-reader2/src/reader2/DExpectListTypeSsm.cpp index 3b040962..1f42d171 100644 --- a/xo-reader2/src/reader2/DExpectListTypeSsm.cpp +++ b/xo-reader2/src/reader2/DExpectListTypeSsm.cpp @@ -127,6 +127,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_lambda: case tokentype::tk_then: diff --git a/xo-reader2/src/reader2/DExpectQArraySsm.cpp b/xo-reader2/src/reader2/DExpectQArraySsm.cpp index 33ccd7c8..aa89862f 100644 --- a/xo-reader2/src/reader2/DExpectQArraySsm.cpp +++ b/xo-reader2/src/reader2/DExpectQArraySsm.cpp @@ -122,6 +122,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_then: case tokentype::tk_else: diff --git a/xo-reader2/src/reader2/DExpectQListSsm.cpp b/xo-reader2/src/reader2/DExpectQListSsm.cpp index 9584bfea..f3f50b81 100644 --- a/xo-reader2/src/reader2/DExpectQListSsm.cpp +++ b/xo-reader2/src/reader2/DExpectQListSsm.cpp @@ -122,6 +122,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_then: case tokentype::tk_else: diff --git a/xo-reader2/src/reader2/DExpectQLiteralSsm.cpp b/xo-reader2/src/reader2/DExpectQLiteralSsm.cpp index 92309ddc..4cb26099 100644 --- a/xo-reader2/src/reader2/DExpectQLiteralSsm.cpp +++ b/xo-reader2/src/reader2/DExpectQLiteralSsm.cpp @@ -140,6 +140,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_then: case tokentype::tk_else: diff --git a/xo-reader2/src/reader2/DExpectSymbolSsm.cpp b/xo-reader2/src/reader2/DExpectSymbolSsm.cpp index 79ae0622..17cdca06 100644 --- a/xo-reader2/src/reader2/DExpectSymbolSsm.cpp +++ b/xo-reader2/src/reader2/DExpectSymbolSsm.cpp @@ -101,6 +101,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_lambda: case tokentype::tk_then: diff --git a/xo-reader2/src/reader2/DExpectTypeSsm.cpp b/xo-reader2/src/reader2/DExpectTypeSsm.cpp index 600b7650..9eb2b15d 100644 --- a/xo-reader2/src/reader2/DExpectTypeSsm.cpp +++ b/xo-reader2/src/reader2/DExpectTypeSsm.cpp @@ -107,6 +107,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_lambda: case tokentype::tk_then: diff --git a/xo-reader2/src/reader2/DIfElseSsm.cpp b/xo-reader2/src/reader2/DIfElseSsm.cpp index 5752dbdc..b915c061 100644 --- a/xo-reader2/src/reader2/DIfElseSsm.cpp +++ b/xo-reader2/src/reader2/DIfElseSsm.cpp @@ -186,6 +186,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_lambda: case tokentype::tk_let: diff --git a/xo-reader2/src/reader2/DLambdaSsm.cpp b/xo-reader2/src/reader2/DLambdaSsm.cpp index 9364476a..ac19c7e0 100644 --- a/xo-reader2/src/reader2/DLambdaSsm.cpp +++ b/xo-reader2/src/reader2/DLambdaSsm.cpp @@ -163,6 +163,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_then: case tokentype::tk_else: diff --git a/xo-reader2/src/reader2/DParenSsm.cpp b/xo-reader2/src/reader2/DParenSsm.cpp index d3fb5cfa..7bf28d02 100644 --- a/xo-reader2/src/reader2/DParenSsm.cpp +++ b/xo-reader2/src/reader2/DParenSsm.cpp @@ -132,6 +132,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_lambda: case tokentype::tk_then: diff --git a/xo-reader2/src/reader2/DProgressSsm.cpp b/xo-reader2/src/reader2/DProgressSsm.cpp index edb55001..be927bef 100644 --- a/xo-reader2/src/reader2/DProgressSsm.cpp +++ b/xo-reader2/src/reader2/DProgressSsm.cpp @@ -309,6 +309,7 @@ namespace xo { this->on_operator_token(tk, p_psm); return; + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_lambda: break; diff --git a/xo-reader2/src/reader2/DQuoteSsm.cpp b/xo-reader2/src/reader2/DQuoteSsm.cpp index 7f6dd00d..c61ed632 100644 --- a/xo-reader2/src/reader2/DQuoteSsm.cpp +++ b/xo-reader2/src/reader2/DQuoteSsm.cpp @@ -133,6 +133,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_lambda: case tokentype::tk_then: diff --git a/xo-reader2/src/reader2/DSequenceSsm.cpp b/xo-reader2/src/reader2/DSequenceSsm.cpp index 8bb2f779..b2b237dd 100644 --- a/xo-reader2/src/reader2/DSequenceSsm.cpp +++ b/xo-reader2/src/reader2/DSequenceSsm.cpp @@ -114,6 +114,7 @@ namespace xo { case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: + case tokentype::tk_nil: case tokentype::tk_type: case tokentype::tk_lambda: case tokentype::tk_let: diff --git a/xo-reader2/src/reader2/DToplevelSeqSsm.cpp b/xo-reader2/src/reader2/DToplevelSeqSsm.cpp index 2b5b0dcb..612f64fd 100644 --- a/xo-reader2/src/reader2/DToplevelSeqSsm.cpp +++ b/xo-reader2/src/reader2/DToplevelSeqSsm.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -152,6 +153,10 @@ namespace xo { this->on_bool_token(tk, p_psm); return; + case tokentype::tk_nil: + this->on_nil_token(tk, p_psm); + return; + case tokentype::tk_leftparen: this->on_leftparen_token(tk, p_psm); return; @@ -378,7 +383,7 @@ namespace xo { break; } - Super::on_token(tk, p_psm); + Super::illegal_token(tk, p_psm); } void @@ -404,7 +409,32 @@ namespace xo { break; } - Super::on_token(tk, p_psm); + Super::illegal_token(tk, p_psm); + } + + void + DToplevelSeqSsm::on_nil_token(const Token & tk, + ParserStateMachine * p_psm) + { + switch (seqtype_) { + case exprseqtype::toplevel_interactive: + { + auto dvalue = DList::nil(); + auto expr = DConstant::make(p_psm->expr_alloc(), dvalue); + + DProgressSsm::start(p_psm->parser_alloc(), + expr, + p_psm); + return; + } + case exprseqtype::toplevel_batch: + break; + case exprseqtype::N: + assert(false); + break; + } + + Super::illegal_token(tk, p_psm); } void @@ -431,7 +461,7 @@ namespace xo { break; } - Super::on_token(tk, p_psm); + Super::illegal_token(tk, p_psm); } void @@ -454,7 +484,7 @@ namespace xo { break; } - Super::on_token(tk, p_psm); + Super::illegal_token(tk, p_psm); } void diff --git a/xo-reader2/utest/SchematikaParser.test.cpp b/xo-reader2/utest/SchematikaParser.test.cpp index 0b1fea58..6f97d7a0 100644 --- a/xo-reader2/utest/SchematikaParser.test.cpp +++ b/xo-reader2/utest/SchematikaParser.test.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,7 @@ namespace xo { using xo::scm::Token; using xo::mm::AGCObject; using xo::scm::DPrimitive_gco_2_gco_gco; + using xo::scm::DList; using xo::scm::DString; using xo::scm::DFloat; using xo::scm::DInteger; @@ -603,6 +605,67 @@ namespace xo { log && fixture.log_memory_layout(&log); } + TEST_CASE("SchematikaParser-interactive-nil", "[reader2][SchematikaParser]") + { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = false; + 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: + * + * nil ; + * + **/ + + { + auto & result = parser.on_token(Token::nil_token()); + + log && log("after nil 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::semicolon_token()); + + log && log("after semicolon 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()); + + auto expr = obj::from(result.result_expr()); + REQUIRE(expr); + + REQUIRE(expr->value()); + + auto value_list = obj::from(expr->value()); + + REQUIRE(value_list); + + REQUIRE(value_list->is_empty()); + } + + //REQUIRE(result.is_error()); + //// illegal input on token + //REQUIRE(result.error_description()); + + log && fixture.log_memory_layout(&log); + } + TEST_CASE("SchematikaParser-interactive-arith", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); diff --git a/xo-tokenizer2/include/xo/tokenizer2/Token.hpp b/xo-tokenizer2/include/xo/tokenizer2/Token.hpp index 7537a2b0..0968a9e9 100644 --- a/xo-tokenizer2/include/xo/tokenizer2/Token.hpp +++ b/xo-tokenizer2/include/xo/tokenizer2/Token.hpp @@ -134,6 +134,8 @@ namespace xo { /** token for @c "==" **/ static Token cmpeq_token() { return Token(tokentype::tk_cmpeq); } + /** token representing keyword @c nil **/ + static Token nil_token() { return Token(tokentype::tk_nil); } /** token representing keyword @c type **/ static Token type() { return Token(tokentype::tk_type); } /** token representing keyword @c def **/ diff --git a/xo-tokenizer2/include/xo/tokenizer2/tokentype.hpp b/xo-tokenizer2/include/xo/tokenizer2/tokentype.hpp index d0290b05..5f7e1937 100644 --- a/xo-tokenizer2/include/xo/tokenizer2/tokentype.hpp +++ b/xo-tokenizer2/include/xo/tokenizer2/tokentype.hpp @@ -140,6 +140,9 @@ namespace xo { /** operator @c '!=' **/ tk_cmpne, + /** keyword @c 'nil' **/ + tk_nil, + /** keyword @c 'type' **/ tk_type, diff --git a/xo-tokenizer2/src/tokenizer2/Tokenizer.cpp b/xo-tokenizer2/src/tokenizer2/Tokenizer.cpp index f6ac7c2f..2a6f8ed9 100644 --- a/xo-tokenizer2/src/tokenizer2/Tokenizer.cpp +++ b/xo-tokenizer2/src/tokenizer2/Tokenizer.cpp @@ -587,6 +587,8 @@ namespace xo { if ((tk_text == "true") || (tk_text == "false")) { tk_type = tokentype::tk_bool; keep_text = true; + } else if (tk_text == "nil") { + tk_type = tokentype::tk_nil; } else if (tk_text == "type") { tk_type = tokentype::tk_type; } else if (tk_text == "def") { diff --git a/xo-tokenizer2/src/tokenizer2/tokentype.cpp b/xo-tokenizer2/src/tokenizer2/tokentype.cpp index 7df59eec..b8a013da 100644 --- a/xo-tokenizer2/src/tokenizer2/tokentype.cpp +++ b/xo-tokenizer2/src/tokenizer2/tokentype.cpp @@ -49,6 +49,7 @@ namespace xo { CASE(tk_cmpeq); CASE(tk_cmpne); + CASE(tk_nil); CASE(tk_type); CASE(tk_def); CASE(tk_deftype);