diff --git a/xo-reader/include/xo/reader/define_xs.hpp b/xo-reader/include/xo/reader/define_xs.hpp index 4f2eb66a..0c6d46c8 100644 --- a/xo-reader/include/xo/reader/define_xs.hpp +++ b/xo-reader/include/xo/reader/define_xs.hpp @@ -79,9 +79,9 @@ namespace xo { defexprstatetype defxs_type() const { return defxs_type_; } - virtual void on_expr(ref::brw expr, + virtual void on_expr(bp expr, parserstatemachine * p_psm) override; - virtual void on_expr_with_semicolon(ref::brw expr, + virtual void on_expr_with_semicolon(bp expr, parserstatemachine * p_psm) override; virtual void on_symbol(const std::string & symbol_name, parserstatemachine * p_psm) override; diff --git a/xo-reader/include/xo/reader/envframe.hpp b/xo-reader/include/xo/reader/envframe.hpp index a0fcfb7d..a6bfee29 100644 --- a/xo-reader/include/xo/reader/envframe.hpp +++ b/xo-reader/include/xo/reader/envframe.hpp @@ -25,11 +25,14 @@ namespace xo { const std::vector> & argl() const { return argl_; } - /** lookup variable by name. If found, return it. + /** lookup variable by @p name. If found, return it. * Otherwise return nullptr **/ rp lookup(const std::string & name) const; + /** establish (replacing if already exists) binding for variable @p var **/ + void upsert(bp var); + void print (std::ostream & os) const; private: @@ -44,5 +47,4 @@ namespace xo { } /*namespace scm*/ } /*namespace xo*/ - /* end envframe.hpp */ diff --git a/xo-reader/include/xo/reader/envframestack.hpp b/xo-reader/include/xo/reader/envframestack.hpp index e438f47f..60314756 100644 --- a/xo-reader/include/xo/reader/envframestack.hpp +++ b/xo-reader/include/xo/reader/envframestack.hpp @@ -28,6 +28,11 @@ namespace xo { **/ rp lookup(const std::string & x) const; + /** update/replace binding for variable @p target. + * New binding may have a different type. + **/ + void upsert(bp target); + envframe & top_envframe(); void push_envframe(envframe x); void pop_envframe(); diff --git a/xo-reader/include/xo/reader/expect_expr_xs.hpp b/xo-reader/include/xo/reader/expect_expr_xs.hpp index 900ee1de..b416c7eb 100644 --- a/xo-reader/include/xo/reader/expect_expr_xs.hpp +++ b/xo-reader/include/xo/reader/expect_expr_xs.hpp @@ -48,12 +48,12 @@ namespace xo { parserstatemachine * p_psm) override; /** update exprstate in response to a successfully-parsed subexpression **/ - virtual void on_expr(ref::brw expr, + virtual void on_expr(bp expr, parserstatemachine * p_psm) override; /** update exprstate in response to a successfully-parsed subexpression, * that's terminated by semicolon ';' **/ - virtual void on_expr_with_semicolon(ref::brw expr, + virtual void on_expr_with_semicolon(bp expr, parserstatemachine * p_psm) override; diff --git a/xo-reader/include/xo/reader/exprseq_xs.hpp b/xo-reader/include/xo/reader/exprseq_xs.hpp index 52ec315c..c41e3cf3 100644 --- a/xo-reader/include/xo/reader/exprseq_xs.hpp +++ b/xo-reader/include/xo/reader/exprseq_xs.hpp @@ -56,9 +56,9 @@ namespace xo { virtual void on_typedescr(TypeDescr td, parserstatemachine * p_psm) override; - virtual void on_expr(ref::brw expr, + virtual void on_expr(bp expr, parserstatemachine * p_psm) override; - virtual void on_expr_with_semicolon(ref::brw expr, + virtual void on_expr_with_semicolon(bp expr, parserstatemachine * p_psm) override; private: diff --git a/xo-reader/include/xo/reader/exprstate.hpp b/xo-reader/include/xo/reader/exprstate.hpp index 467348df..f6d592db 100644 --- a/xo-reader/include/xo/reader/exprstate.hpp +++ b/xo-reader/include/xo/reader/exprstate.hpp @@ -106,11 +106,11 @@ namespace xo { parserstatemachine * p_psm); /** update exprstate in response to a successfully-parsed subexpression **/ - virtual void on_expr(ref::brw expr, + virtual void on_expr(bp expr, parserstatemachine * p_psm); /** update exprstate in response to a successfully-parsed subexpression, that ends with semicolon **/ - virtual void on_expr_with_semicolon(ref::brw expr, + virtual void on_expr_with_semicolon(bp expr, parserstatemachine * p_psm); /** update exprstate when expecting a symbol **/ @@ -189,6 +189,11 @@ namespace xo { void illegal_input_error(const char * self_name, const token_type & tk) const; + /** throw exception when unable to locate definition for a variable + **/ + void unknown_variable_error(const char * self_name, + const token_type & tk) const; + protected: /** explicit subtype: identifies derived class **/ exprstatetype exs_type_; diff --git a/xo-reader/include/xo/reader/lambda_xs.hpp b/xo-reader/include/xo/reader/lambda_xs.hpp index 728bc9e3..43f161a1 100644 --- a/xo-reader/include/xo/reader/lambda_xs.hpp +++ b/xo-reader/include/xo/reader/lambda_xs.hpp @@ -55,9 +55,9 @@ namespace xo { parserstatemachine * p_psm) override; virtual void on_formal_arglist(const std::vector> & argl, parserstatemachine * p_psm) override; - virtual void on_expr(ref::brw expr, + virtual void on_expr(bp expr, parserstatemachine * p_psm) override; - virtual void on_expr_with_semicolon(ref::brw expr, + virtual void on_expr_with_semicolon(bp expr, parserstatemachine * p_psm) override; virtual void on_semicolon_token(const token_type & tk, parserstatemachine * p_psm) override; diff --git a/xo-reader/include/xo/reader/let1_xs.hpp b/xo-reader/include/xo/reader/let1_xs.hpp index 4486869f..b510f50e 100644 --- a/xo-reader/include/xo/reader/let1_xs.hpp +++ b/xo-reader/include/xo/reader/let1_xs.hpp @@ -25,7 +25,7 @@ namespace xo { const rp & rhs, parserstatemachine * p_psm); - virtual void on_expr(ref::brw expr, + virtual void on_expr(bp expr, parserstatemachine * p_psm) override; virtual void on_rightbrace_token(const token_type & tk, diff --git a/xo-reader/include/xo/reader/paren_xs.hpp b/xo-reader/include/xo/reader/paren_xs.hpp index 0d251a76..ab7da4fc 100644 --- a/xo-reader/include/xo/reader/paren_xs.hpp +++ b/xo-reader/include/xo/reader/paren_xs.hpp @@ -43,7 +43,7 @@ namespace xo { bool admits_f64() const; bool admits_rightparen() const; - virtual void on_expr(ref::brw expr, + virtual void on_expr(bp expr, parserstatemachine * p_psm) override; virtual void on_symbol(const std::string & symbol, parserstatemachine * p_psm) override; diff --git a/xo-reader/include/xo/reader/parser.hpp b/xo-reader/include/xo/reader/parser.hpp index 01a3b9b9..850a5513 100644 --- a/xo-reader/include/xo/reader/parser.hpp +++ b/xo-reader/include/xo/reader/parser.hpp @@ -154,7 +154,7 @@ namespace xo { /** create parser in initial state; * parser is ready to receive tokens via @ref include_token **/ - parser() = default; + parser(); /** for diagnostics: number of entries in parser stack **/ std::size_t stack_size() const { return xs_stack_.size(); } diff --git a/xo-reader/include/xo/reader/parserstatemachine.hpp b/xo-reader/include/xo/reader/parserstatemachine.hpp index 0e69d44c..24868e12 100644 --- a/xo-reader/include/xo/reader/parserstatemachine.hpp +++ b/xo-reader/include/xo/reader/parserstatemachine.hpp @@ -40,13 +40,18 @@ namespace xo { **/ rp lookup_var(const std::string & x) const; + /** update/replace binding for variable @p x in lexical context + * represented by this psm. Always acts on innermost frame. + **/ + void upsert_var(bp x); + void push_envframe(envframe x); void pop_envframe(); // ----- parsing outputs ----- - void on_expr(ref::brw expr); - void on_expr_with_semicolon(ref::brw expr); + void on_expr(bp expr); + void on_expr_with_semicolon(bp expr); void on_symbol(const std::string & symbol); // ---- parsing inputs ----- diff --git a/xo-reader/include/xo/reader/progress_xs.hpp b/xo-reader/include/xo/reader/progress_xs.hpp index 03bd933e..4277ba73 100644 --- a/xo-reader/include/xo/reader/progress_xs.hpp +++ b/xo-reader/include/xo/reader/progress_xs.hpp @@ -47,6 +47,10 @@ namespace xo { /** @class progress_xs * @brief state machine for parsing a schematica runtime-value-expression + * + * Handles an expression that produces a value, for example appearing on the + * right-hand side of a definition. + * **/ class progress_xs : public exprstate { public: @@ -65,7 +69,7 @@ namespace xo { bool admits_f64() const; - virtual void on_expr(ref::brw expr, + virtual void on_expr(bp expr, parserstatemachine * p_psm) override; virtual void on_symbol_token(const token_type & tk, parserstatemachine * p_psm) override; diff --git a/xo-reader/include/xo/reader/sequence_xs.hpp b/xo-reader/include/xo/reader/sequence_xs.hpp index b361bbf7..fd16ffb5 100644 --- a/xo-reader/include/xo/reader/sequence_xs.hpp +++ b/xo-reader/include/xo/reader/sequence_xs.hpp @@ -24,7 +24,7 @@ namespace xo { **/ static void start(parserstatemachine * p_psm); - virtual void on_expr(ref::brw expr, + virtual void on_expr(bp expr, parserstatemachine * p_psm) override; virtual void on_rightbrace_token(const token_type & tk, diff --git a/xo-reader/src/reader/define_xs.cpp b/xo-reader/src/reader/define_xs.cpp index fdd3c410..a6faea78 100644 --- a/xo-reader/src/reader/define_xs.cpp +++ b/xo-reader/src/reader/define_xs.cpp @@ -58,7 +58,7 @@ namespace xo { {} void - define_xs::on_expr(ref::brw expr, + define_xs::on_expr(bp expr, parserstatemachine * p_psm) { constexpr bool c_debug_flag = true; @@ -90,7 +90,7 @@ namespace xo { } void - define_xs::on_expr_with_semicolon(ref::brw expr, + define_xs::on_expr_with_semicolon(bp expr, parserstatemachine * p_psm) { this->on_expr(expr, p_psm); @@ -186,11 +186,16 @@ namespace xo { log && log("defxs_type", defxs_type_); if (this->defxs_type_ == defexprstatetype::def_6) { - rp expr = this->def_expr_; + rp def_expr = this->def_expr_; std::unique_ptr self = p_psm->pop_exprstate(); - p_psm->top_exprstate().on_expr(expr, p_psm); + /* remember variable binding in lexical context, + * so we can refer to it later + */ + p_psm->upsert_var(def_expr->lhs_variable()); + + p_psm->top_exprstate().on_expr(def_expr, p_psm); } else { exprstate::on_semicolon_token(tk, p_psm); } diff --git a/xo-reader/src/reader/envframe.cpp b/xo-reader/src/reader/envframe.cpp index 38ff1fcb..c0e39693 100644 --- a/xo-reader/src/reader/envframe.cpp +++ b/xo-reader/src/reader/envframe.cpp @@ -20,6 +20,20 @@ namespace xo { return nullptr; } + void + envframe::upsert(bp target) { + for (auto & var : this->argl_) { + if (var->name() == target->name()) { + /* replace existing variable -- may change type */ + var = target.promote(); + return; + } + } + + /* here: target not already present in this frame, append it */ + this->argl_.push_back(target.promote()); + } + void envframe::print(std::ostream & os) const { os << " x) { + /* upsert should always happen in the innermost lexical context. + * We are providing new variable binding (perhaps shadowing an existing binding) + */ + this->top_envframe().upsert(x); + } + void envframestack::print(std::ostream & os) const { os << " expr, + expect_expr_xs::on_expr(bp expr, parserstatemachine * p_psm) { constexpr bool c_debug_flag = true; @@ -218,7 +218,7 @@ namespace xo { } /*on_expr*/ void - expect_expr_xs::on_expr_with_semicolon(ref::brw expr, + expect_expr_xs::on_expr_with_semicolon(bp expr, parserstatemachine * p_psm) { constexpr bool c_debug_flag = true; diff --git a/xo-reader/src/reader/exprseq_xs.cpp b/xo-reader/src/reader/exprseq_xs.cpp index e650e238..bf5fea79 100644 --- a/xo-reader/src/reader/exprseq_xs.cpp +++ b/xo-reader/src/reader/exprseq_xs.cpp @@ -4,9 +4,11 @@ #include "parserstatemachine.hpp" #include "exprstatestack.hpp" #include "exprseq_xs.hpp" -#include "expect_expr_xs.hpp" +//#include "expect_expr_xs.hpp" +#include "progress_xs.hpp" #include "define_xs.hpp" #include "expect_symbol_xs.hpp" +#include "xo/expression/Constant.hpp" namespace xo { namespace scm { @@ -47,17 +49,41 @@ namespace xo { void exprseq_xs::on_symbol_token(const token_type & tk, - parserstatemachine * /*p_psm*/) + parserstatemachine * p_psm) { constexpr const char * c_self_name = "exprseq_xs::on_symbol_token"; - this->illegal_input_error(c_self_name, tk); + if (xseqtype_ == exprseqtype::toplevel_interactive) + { + /* In interactive session, allow top-level variable reference. + * This could be: + * a; // variable references + * a = 1; // single assignment + * a == 1; // rhs expression + * a + b; // rhs expression + * Variable must have been defined! + */ + rp var = p_psm->lookup_var(tk.text()); + + if (var.get()) { + progress_xs::start(var, p_psm); + } else { + this->unknown_variable_error(c_self_name, tk); + } + } else { + /* policy: don't allow variable references as toplevel expressions + * unless interactive session + */ + this->illegal_input_error(c_self_name, tk); + } } void exprseq_xs::on_i64_token(const token_type & tk, parserstatemachine * p_psm) { + using xo::ast::Constant; + constexpr bool c_debug_flag = true; scope log(XO_DEBUG(c_debug_flag)); @@ -65,9 +91,11 @@ namespace xo { if (xseqtype_ == exprseqtype::toplevel_interactive) { - expect_expr_xs::start(p_psm); - p_psm->top_exprstate().on_i64_token(tk, p_psm); + progress_xs::start(Constant::make(tk.i64_value()), p_psm); } else { + /* policy: don't allow literals as toplevel expressions + * unless interactive session. + */ this->illegal_input_error(c_self_name, tk); } } @@ -82,7 +110,7 @@ namespace xo { } void - exprseq_xs::on_expr(ref::brw expr, + exprseq_xs::on_expr(bp expr, parserstatemachine * p_psm) { /* toplevel expression sequence accepts an @@ -95,7 +123,7 @@ namespace xo { } /*on_expr*/ void - exprseq_xs::on_expr_with_semicolon(ref::brw expr, + exprseq_xs::on_expr_with_semicolon(bp expr, parserstatemachine * p_psm) { /* toplevel expression sequence accepts an diff --git a/xo-reader/src/reader/exprstate.cpp b/xo-reader/src/reader/exprstate.cpp index 8145c550..c255a182 100644 --- a/xo-reader/src/reader/exprstate.cpp +++ b/xo-reader/src/reader/exprstate.cpp @@ -58,8 +58,13 @@ namespace xo { void exprstate::on_def_token(const token_type & tk, - parserstatemachine * /*p_psm*/) + parserstatemachine * p_psm) { + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag)); + + log && log(xtag("exstype", p_psm->top_exprstate().exs_type())); + this->illegal_input_error("exprstate::on_def_token", tk); } @@ -387,7 +392,7 @@ namespace xo { } void - exprstate::on_expr(ref::brw expr, + exprstate::on_expr(bp expr, parserstatemachine * /*p_psm*/) { constexpr bool c_debug_flag = true; @@ -400,7 +405,7 @@ namespace xo { } /*on_expr*/ void - exprstate::on_expr_with_semicolon(ref::brw expr, + exprstate::on_expr_with_semicolon(bp expr, parserstatemachine * /*p_psm*/) { constexpr bool c_debug_flag = true; @@ -454,6 +459,16 @@ namespace xo { xtag("token", tk), xtag("state", *this))); } + + void + exprstate::unknown_variable_error(const char * self_name, + const token_type & tk) const + { + throw std::runtime_error + (tostr(self_name, + ": unknown variable name", + xtag("var", tk.text()))); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/xo-reader/src/reader/lambda_xs.cpp b/xo-reader/src/reader/lambda_xs.cpp index ab9b73d8..c7d664f7 100644 --- a/xo-reader/src/reader/lambda_xs.cpp +++ b/xo-reader/src/reader/lambda_xs.cpp @@ -71,7 +71,7 @@ namespace xo { } void - lambda_xs::on_expr(ref::brw expr, + lambda_xs::on_expr(bp expr, parserstatemachine * p_psm) { if (lmxs_type_ == lambdastatetype::lm_2) { @@ -83,7 +83,7 @@ namespace xo { } void - lambda_xs::on_expr_with_semicolon(ref::brw expr, + lambda_xs::on_expr_with_semicolon(bp expr, parserstatemachine * p_psm) { this->on_expr(expr, p_psm); diff --git a/xo-reader/src/reader/let1_xs.cpp b/xo-reader/src/reader/let1_xs.cpp index 0afbd415..f1f4e1b1 100644 --- a/xo-reader/src/reader/let1_xs.cpp +++ b/xo-reader/src/reader/let1_xs.cpp @@ -54,13 +54,13 @@ namespace xo { {} void - let1_xs::on_expr(ref::brw expr, + let1_xs::on_expr(bp expr, parserstatemachine * p_psm) { constexpr bool c_debug_flag = true; scope log(XO_DEBUG(c_debug_flag)); - ref::brw def_expr = DefineExpr::from(expr); + bp def_expr = DefineExpr::from(expr); if (def_expr) { /** nested_start: control returns via diff --git a/xo-reader/src/reader/paren_xs.cpp b/xo-reader/src/reader/paren_xs.cpp index 357d377a..8ac163ea 100644 --- a/xo-reader/src/reader/paren_xs.cpp +++ b/xo-reader/src/reader/paren_xs.cpp @@ -195,7 +195,7 @@ namespace xo { } void - paren_xs::on_expr(ref::brw expr, + paren_xs::on_expr(bp expr, parserstatemachine * p_psm) { constexpr bool c_debug_flag = true; diff --git a/xo-reader/src/reader/parser.cpp b/xo-reader/src/reader/parser.cpp index 4250e028..7495077c 100644 --- a/xo-reader/src/reader/parser.cpp +++ b/xo-reader/src/reader/parser.cpp @@ -24,6 +24,15 @@ namespace xo { namespace scm { // ----- parser ----- + parser::parser() + : xs_stack_{}, env_stack_{} + { + /* top-level environment. initially empty */ + envframe toplevel_env; + + this->env_stack_.push_envframe(toplevel_env); + } + bool parser::has_incomplete_expr() const { return !xs_stack_.empty(); diff --git a/xo-reader/src/reader/parserstatemachine.cpp b/xo-reader/src/reader/parserstatemachine.cpp index 373e83e3..c4be496f 100644 --- a/xo-reader/src/reader/parserstatemachine.cpp +++ b/xo-reader/src/reader/parserstatemachine.cpp @@ -15,6 +15,11 @@ namespace xo { return p_env_stack_->lookup(x); } + void + parserstatemachine::upsert_var(bp x) { + p_env_stack_->upsert(x); + } + std::unique_ptr parserstatemachine::pop_exprstate() { return p_stack_->pop_exprstate(); @@ -49,7 +54,7 @@ namespace xo { } void - parserstatemachine::on_expr(ref::brw x) + parserstatemachine::on_expr(bp x) { constexpr bool c_debug_flag = true; scope log(XO_DEBUG(c_debug_flag)); @@ -62,7 +67,7 @@ namespace xo { } void - parserstatemachine::on_expr_with_semicolon(ref::brw x) + parserstatemachine::on_expr_with_semicolon(bp x) { constexpr bool c_debug_flag = true; scope log(XO_DEBUG(c_debug_flag)); diff --git a/xo-reader/src/reader/progress_xs.cpp b/xo-reader/src/reader/progress_xs.cpp index 44938fca..930ef734 100644 --- a/xo-reader/src/reader/progress_xs.cpp +++ b/xo-reader/src/reader/progress_xs.cpp @@ -118,7 +118,7 @@ namespace xo { case optype::op_assign: { - ref::brw lhs = Variable::from(this->lhs_); + bp lhs = Variable::from(this->lhs_); if (!lhs) { throw std::runtime_error @@ -158,7 +158,7 @@ namespace xo { } void - progress_xs::on_expr(ref::brw expr, + progress_xs::on_expr(bp expr, parserstatemachine * /*p_psm*/) { /* note: previous token probably an operator, @@ -218,7 +218,7 @@ namespace xo { progress_xs::on_semicolon_token(const token_type & /*tk*/, parserstatemachine * p_psm) { - /* note: implementation parllels .on_rightparen_token() */ + /* note: implementation parallels .on_rightparen_token() */ constexpr bool c_debug_flag = true; scope log(XO_DEBUG(c_debug_flag)); diff --git a/xo-reader/src/reader/sequence_xs.cpp b/xo-reader/src/reader/sequence_xs.cpp index 97aa0955..39e38365 100644 --- a/xo-reader/src/reader/sequence_xs.cpp +++ b/xo-reader/src/reader/sequence_xs.cpp @@ -32,7 +32,7 @@ namespace xo { {} void - sequence_xs::on_expr(ref::brw expr, + sequence_xs::on_expr(bp expr, parserstatemachine * p_psm) { constexpr bool c_debug_flag = true; @@ -67,7 +67,7 @@ namespace xo { * helpful to have nested seequence_xs that propagates '}' * instead of swallowing it. */ - ref::brw def_expr = DefineExpr::from(expr); + bp def_expr = DefineExpr::from(expr); if (def_expr) { /** nested_start: control returns via