diff --git a/include/xo/reader/let1_xs.hpp b/include/xo/reader/let1_xs.hpp new file mode 100644 index 00000000..4486869f --- /dev/null +++ b/include/xo/reader/let1_xs.hpp @@ -0,0 +1,57 @@ +/* file let1_xs.hpp + * + * author: Roland Conybeare, Aug 2024 + */ + +#pragma once + +#include "exprstate.hpp" + +namespace xo { + namespace scm { + class let1_xs : public exprstate { + public: + + /** given local definition equivalent to + * def lhs_name = rhs + * rest... + * parse sequence of incoming expressions rest... (until '}') + * + * Result expression creates and inits @p lhs_name, + * then evaluates expressions that follow definition + * up to same-level '}' + **/ + static void start(const std::string & lhs_name, + const rp & rhs, + parserstatemachine * p_psm); + + virtual void on_expr(ref::brw expr, + parserstatemachine * p_psm) override; + + virtual void on_rightbrace_token(const token_type & tk, + parserstatemachine * p_psm) override; + + private: + let1_xs(std::string lhs_name, + rp rhs); + + /** named ctor idiom **/ + static std::unique_ptr make(std::string lhs_name, + rp rhs); + + private: + /** name for new local variable **/ + std::string lhs_name_; + /** set initial value for @ref lhs_name_ from value of this expression **/ + rp rhs_; + + /** evaluate expressions in this sequence, in order, in environment + * with variable @ref lhs_name_ defined + **/ + std::vector> expr_v_; + }; + } /*namespace scm*/ +} /*namespace xo*/ + + +/* end let1_xs.hpp */ diff --git a/include/xo/reader/sequence_xs.hpp b/include/xo/reader/sequence_xs.hpp index a33cf3e1..b361bbf7 100644 --- a/include/xo/reader/sequence_xs.hpp +++ b/include/xo/reader/sequence_xs.hpp @@ -6,13 +6,22 @@ #pragma once #include "exprstate.hpp" +#include namespace xo { + namespace ast { class Sequence; } + namespace ast { class Lambda; } + namespace scm { class sequence_xs : public exprstate { public: - sequence_xs(); + using Sequence = xo::ast::Sequence; + using Lambda = xo::ast::Lambda; + public: + /** start parsing a sequence-expr. + * input begins with first expression in the sequence. + **/ static void start(parserstatemachine * p_psm); virtual void on_expr(ref::brw expr, @@ -22,9 +31,13 @@ namespace xo { parserstatemachine * p_psm) override; private: + sequence_xs(); + + /** named ctor idiom **/ static std::unique_ptr make(); private: + /** will build SequenceExpr from in-order contents of this vector **/ std::vector> expr_v_; }; } /*namespace scm*/ diff --git a/src/reader/CMakeLists.txt b/src/reader/CMakeLists.txt index 5db87d7a..0a3dee3e 100644 --- a/src/reader/CMakeLists.txt +++ b/src/reader/CMakeLists.txt @@ -18,6 +18,7 @@ set(SELF_SRCS expect_formal_arglist_xs.cpp expect_type_xs.cpp lambda_xs.cpp + let1_xs.cpp envframestack.cpp envframe.cpp) diff --git a/src/reader/let1_xs.cpp b/src/reader/let1_xs.cpp new file mode 100644 index 00000000..f248d1dd --- /dev/null +++ b/src/reader/let1_xs.cpp @@ -0,0 +1,116 @@ +/* file let1_xs.cpp + * + * author: Roland Conybeare + */ + +#include "let1_xs.hpp" +#include "expect_expr_xs.hpp" +#include "parserstatemachine.hpp" +#include "xo/expression/Sequence.hpp" +#include "xo/expression/DefineExpr.hpp" +#include "xo/expression/Apply.hpp" +#include "xo/expression/Lambda.hpp" + +namespace xo { + using Sequence = xo::ast::Sequence; + using DefineExpr = xo::ast::DefineExpr; + using Apply = xo::ast::Apply; + using Lambda = xo::ast::Lambda; + using LambdaAccess = xo::ast::LambdaAccess; + using Variable = xo::ast::Variable; + + namespace { + std::string gensym() { + return "genanotherxx"; + } + } + + namespace scm { + std::unique_ptr + let1_xs::make(std::string lhs_name, + rp rhs) + { + return std::make_unique(let1_xs(std::move(lhs_name), + std::move(rhs))); + } + + void + let1_xs::start(const std::string & lhs_name, + const rp & rhs, + parserstatemachine * p_psm) + { + p_psm->push_exprstate(let1_xs::make(std::move(lhs_name), + std::move(rhs))); + + expect_expr_xs::start(true /*allow_defs*/, + true /*cxl_on_rightbrace*/, + p_psm); + } + + let1_xs::let1_xs(std::string lhs_name, + rp rhs) + : lhs_name_{std::move(lhs_name)}, + rhs_{std::move(rhs)} + {} + + void + let1_xs::on_expr(ref::brw expr, + parserstatemachine * p_psm) + { + ref::brw def_expr = DefineExpr::from(expr); + + if (def_expr) { + /** nested_start: control returns via + * .on_expr(x) + * with x something like: + * Apply(Lambda(gensym(), + * [Variable(def_expr->lhs_name(), + * def_expr->valuetype())], + * body...)) + * followed immediately by + * .on_rightbrace_token() + **/ + let1_xs::start(def_expr->lhs_name(), + def_expr->rhs(), + p_psm); + } else { + this->expr_v_.push_back(expr.promote()); + + expect_expr_xs::start(true /*allow_defs*/, + true /*cxl_on_rightbrace*/, + p_psm); + } + } + + void + let1_xs::on_rightbrace_token(const token_type & tk, + parserstatemachine * p_psm) + { + auto self = p_psm->pop_exprstate(); + + auto expr = Sequence::make(this->expr_v_); + + std::string argname = gensym(); + + rp lambda + = Lambda::make(this->lhs_name_, + {Variable::make(argname, + this->rhs_->valuetype())}, + expr); + + rp result + = Apply::make(lambda, {this->rhs_}); + + p_psm->top_exprstate().on_expr(result, p_psm); + + /* caller of let1_xs expects the same rightbrace '}' + * -- remember we pushed let1_xs to handle an embedded def-expr + * in a sequence + */ + p_psm->top_exprstate().on_rightbrace_token(tk, p_psm); + } + } /*namespace scm*/ +} /*namespace xo*/ + + +/* end let1_xs.cpp */ diff --git a/src/reader/sequence_xs.cpp b/src/reader/sequence_xs.cpp index 68694e53..c9ee71f3 100644 --- a/src/reader/sequence_xs.cpp +++ b/src/reader/sequence_xs.cpp @@ -3,10 +3,12 @@ #include "sequence_xs.hpp" #include "parserstatemachine.hpp" #include "expect_expr_xs.hpp" +#include "let1_xs.hpp" +#include "xo/expression/DefineExpr.hpp" #include "xo/expression/Sequence.hpp" namespace xo { - using xo::ast::Sequence; + using xo::ast::DefineExpr; namespace scm { std::unique_ptr @@ -42,19 +44,47 @@ namespace xo { * * becomes: * + * /-- .outer_seq_expr_ + * v * Sequence( * ...prefix, - * Apply(Lambda(gen999, [Variable(lhs_name, type(rhs))], sequencify(rest...)), + * + * /-- .inner_lm_expr_ + * v + * Apply(Lambda(gen999, + * [Variable(lhs_name, type(rhs))], + * /-- .expr_v_ + * v + * sequencify(rest...)), * rhs)) * * so amongst other things, - * helpful to have nested seequence_xs that propagates '}' instead of swallowing it. + * helpful to have nested seequence_xs that propagates '}' + * instead of swallowing it. */ + ref::brw def_expr = DefineExpr::from(expr); - this->expr_v_.push_back(expr.promote()); - expect_expr_xs::start(true /*allow_defs*/, - true /*cxl_on_rightbrace*/, - p_psm); + if (def_expr) { + /** nested_start: control returns via + * .on_expr(x) + * with x something like: + * Apply(Lambda(gensym(), + * [Variable(def_expr->lhs_name(), + * def_expr->valuetype())], + * body...)) + * followed immediately by + * .on_rightbrace_token() + **/ + let1_xs::start(def_expr->lhs_name(), + def_expr->rhs(), + p_psm); + } else { + this->expr_v_.push_back(expr.promote()); + + expect_expr_xs::start(true /*allow_defs*/, + true /*cxl_on_rightbrace*/, + p_psm); + } } void