xo-reader xo-expression: nested lambdas working properly + docs
This commit is contained in:
parent
f5a7bcc8ac
commit
f164a3ab67
12 changed files with 198 additions and 39 deletions
|
|
@ -98,12 +98,7 @@ namespace xo {
|
|||
return xform_fn(this);
|
||||
}
|
||||
|
||||
virtual void attach_envs(bp<Environment> p) override {
|
||||
fn_->attach_envs(p);
|
||||
|
||||
for (const auto & arg : argv_)
|
||||
arg->attach_envs(p);
|
||||
}
|
||||
virtual void attach_envs(bp<Environment> p) override;
|
||||
|
||||
virtual void display(std::ostream & os) const override;
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,15 @@ namespace xo {
|
|||
* returns llvm::Value representing code that produces a value for vname
|
||||
**/
|
||||
virtual bp<Expression> lookup_var(const std::string & vname) const = 0;
|
||||
|
||||
virtual void print(std::ostream & os) const = 0;
|
||||
};
|
||||
|
||||
inline std::ostream &
|
||||
operator<< (std::ostream & os, const Environment & x) {
|
||||
x.print(os);
|
||||
return os;
|
||||
}
|
||||
} /*namespace ast*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
|
|
|||
|
|
@ -17,10 +17,7 @@ namespace xo {
|
|||
static rp<GlobalEnv> make() { return new GlobalEnv(); }
|
||||
|
||||
bp<Expression> require_global(const std::string & vname,
|
||||
bp<Expression> expr) {
|
||||
global_map_[vname] = expr.get();
|
||||
return expr;
|
||||
} /*require_global*/
|
||||
bp<Expression> expr);
|
||||
|
||||
// ----- Environment -----
|
||||
|
||||
|
|
@ -44,8 +41,10 @@ namespace xo {
|
|||
return ix->second;
|
||||
}
|
||||
|
||||
virtual void print(std::ostream & os) const override;
|
||||
|
||||
private:
|
||||
GlobalEnv() = default;
|
||||
GlobalEnv();
|
||||
|
||||
private:
|
||||
/* for assignable globals, need to allocate memory
|
||||
|
|
|
|||
|
|
@ -26,10 +26,21 @@ namespace xo {
|
|||
* @p name Name for this lambda -- must be unique
|
||||
* @p argv Formal parameters, in left-to-right order
|
||||
* @p body Expression for body of this function
|
||||
* @p parent_env Environment for enclosing lexical scope
|
||||
**/
|
||||
static rp<Lambda> make(const std::string & name,
|
||||
const std::vector<rp<Variable>> & argv,
|
||||
const rp<Expression> & body);
|
||||
const rp<Expression> & body,
|
||||
const rp<Environment> & parent_env);
|
||||
|
||||
/**
|
||||
* @p name Name for this lambda -- must be unique
|
||||
* @p env Environment with {name,type} for each formal parameter
|
||||
* @p body Expression for body of function
|
||||
**/
|
||||
static rp<Lambda> make_from_env(const std::string & name,
|
||||
const rp<LocalEnv> & env,
|
||||
const rp<Expression> & body);
|
||||
|
||||
/** downcast from Expression **/
|
||||
static bp<Lambda> from(bp<Expression> x) {
|
||||
|
|
@ -174,16 +185,18 @@ namespace xo {
|
|||
inline rp<Lambda>
|
||||
make_lambda(const std::string & name,
|
||||
const std::vector<rp<Variable>> & argv,
|
||||
const rp<Expression> & body)
|
||||
const rp<Expression> & body,
|
||||
const rp<Environment> & parent_env)
|
||||
{
|
||||
return Lambda::make(name, argv, body);
|
||||
return Lambda::make(name, argv, body, parent_env);
|
||||
}
|
||||
|
||||
class LambdaAccess : public Lambda {
|
||||
public:
|
||||
static rp<LambdaAccess> make(const std::string & name,
|
||||
const std::vector<rp<Variable>> & argv,
|
||||
const rp<Expression> & body);
|
||||
const rp<Expression> & body,
|
||||
const rp<Environment> & parent_env);
|
||||
static rp<LambdaAccess> make_empty();
|
||||
|
||||
/** assign body + compute derived members
|
||||
|
|
|
|||
|
|
@ -25,10 +25,13 @@ namespace xo {
|
|||
using TypeDescr = xo::reflect::TypeDescr;
|
||||
|
||||
public:
|
||||
static rp<LocalEnv> make_empty();
|
||||
/** named ctor idiom. Create instance with local variables per @p argv **/
|
||||
static rp<LocalEnv> make(const std::vector<rp<Variable>> & argv) {
|
||||
return new LocalEnv(argv);
|
||||
}
|
||||
static rp<LocalEnv> make(const std::vector<rp<Variable>> & argv,
|
||||
const rp<Environment> & parent_env);
|
||||
/** Create instance with single local variable @ap argv1 **/
|
||||
static rp<LocalEnv> make1(const rp<Variable> & arg1,
|
||||
const rp<Environment> & parent_env);
|
||||
|
||||
Lambda * origin() const { return origin_; }
|
||||
const std::vector<rp<Variable>> & argv() const { return argv_; }
|
||||
|
|
@ -48,10 +51,14 @@ namespace xo {
|
|||
}
|
||||
|
||||
/** single-assign this environment's parent **/
|
||||
void assign_parent(bp<Environment> p) {
|
||||
assert(parent_env_.get() == nullptr);
|
||||
parent_env_ = p.get();
|
||||
}
|
||||
void assign_parent(bp<Environment> p);
|
||||
|
||||
/** create/replace local variable @p target.
|
||||
* Narrow use case: intended for when LocalEnv represents a top-level session environment
|
||||
**/
|
||||
void upsert_local(bp<Variable> target);
|
||||
|
||||
bp<Variable> lookup_local(const std::string & vname) const;
|
||||
|
||||
// ----- Environment -----
|
||||
|
||||
|
|
@ -71,9 +78,10 @@ namespace xo {
|
|||
return parent_env_->lookup_var(target);
|
||||
}
|
||||
|
||||
virtual void print(std::ostream & os) const override;
|
||||
|
||||
private:
|
||||
LocalEnv(const std::vector<rp<Variable>> & argv)
|
||||
: origin_{nullptr}, argv_(argv) {}
|
||||
LocalEnv(const std::vector<rp<Variable>> & argv, const rp<Environment> & parent_env);
|
||||
|
||||
private:
|
||||
/** Lambnda for which this environment created.
|
||||
|
|
@ -93,6 +101,7 @@ namespace xo {
|
|||
**/
|
||||
rp<Environment> parent_env_;
|
||||
};
|
||||
|
||||
} /*namespace ast*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,11 @@ namespace xo {
|
|||
**/
|
||||
class Variable : public Expression {
|
||||
public:
|
||||
/** Generate unique symbol-name beginning with @p prefix.
|
||||
* Relies on static counter
|
||||
**/
|
||||
static std::string gensym(const std::string & prefix);
|
||||
|
||||
/** create expression representing a variable
|
||||
* identified by @p name, that can take on values
|
||||
* described by @p var_type.
|
||||
|
|
|
|||
|
|
@ -58,6 +58,14 @@ namespace xo {
|
|||
{lhs, rhs});
|
||||
}
|
||||
|
||||
void
|
||||
Apply::attach_envs(bp<Environment> p) {
|
||||
fn_->attach_envs(p);
|
||||
|
||||
for (const auto & arg : argv_)
|
||||
arg->attach_envs(p);
|
||||
}
|
||||
|
||||
void
|
||||
Apply::display(std::ostream & os) const {
|
||||
os << "<Apply"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ set(SELF_SRCS
|
|||
Variable.cpp
|
||||
IfExpr.cpp
|
||||
Sequence.cpp
|
||||
GlobalEnv.cpp
|
||||
LocalEnv.cpp
|
||||
ConvertExpr.cpp
|
||||
Primitive.cpp
|
||||
|
|
|
|||
26
src/expression/GlobalEnv.cpp
Normal file
26
src/expression/GlobalEnv.cpp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/* file GlobalEnv.cpp
|
||||
*
|
||||
* author: Roland Conybeare, Jul 2025
|
||||
*/
|
||||
|
||||
#include "GlobalEnv.hpp"
|
||||
#include "Expression.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace ast {
|
||||
GlobalEnv::GlobalEnv() = default;
|
||||
|
||||
bp<Expression>
|
||||
GlobalEnv::require_global(const std::string & vname,
|
||||
bp<Expression> expr)
|
||||
{
|
||||
this->global_map_[vname] = expr.get();
|
||||
return expr;
|
||||
} /*require_global*/
|
||||
|
||||
void
|
||||
GlobalEnv::print(std::ostream & os) const {
|
||||
os << "<globalenv" << xtag("size", global_map_.size()) << ">";
|
||||
}
|
||||
} /*namespace ast*/
|
||||
} /*namespace xo*/
|
||||
|
|
@ -66,15 +66,11 @@ namespace xo {
|
|||
}
|
||||
|
||||
rp<Lambda>
|
||||
Lambda::make(const std::string & name,
|
||||
const std::vector<rp<Variable>> & argv,
|
||||
const rp<Expression> & body)
|
||||
Lambda::make_from_env(const std::string & name,
|
||||
const rp<LocalEnv> & env,
|
||||
const rp<Expression> & body)
|
||||
{
|
||||
using xo::reflect::FunctionTdx;
|
||||
|
||||
rp<LocalEnv> env = LocalEnv::make(argv);
|
||||
|
||||
TypeDescr lambda_td = assemble_lambda_td(argv, body);
|
||||
TypeDescr lambda_td = assemble_lambda_td(env->argv(), body);
|
||||
|
||||
rp<Lambda> retval
|
||||
= new Lambda(name,
|
||||
|
|
@ -86,6 +82,17 @@ namespace xo {
|
|||
env->assign_origin(retval.get());
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
rp<Lambda>
|
||||
Lambda::make(const std::string & name,
|
||||
const std::vector<rp<Variable>> & argv,
|
||||
const rp<Expression> & body,
|
||||
const rp<Environment> & parent_env)
|
||||
{
|
||||
rp<LocalEnv> env = LocalEnv::make(argv, parent_env);
|
||||
|
||||
return make_from_env(name, env, body);
|
||||
} /*make*/
|
||||
|
||||
std::set<std::string>
|
||||
|
|
@ -315,10 +322,11 @@ namespace xo {
|
|||
rp<LambdaAccess>
|
||||
LambdaAccess::make(const std::string & name,
|
||||
const std::vector<rp<Variable>> & argv,
|
||||
const rp<Expression> & body)
|
||||
const rp<Expression> & body,
|
||||
const rp<Environment> & parent_env)
|
||||
{
|
||||
TypeDescr lambda_td = assemble_lambda_td(argv, body);
|
||||
rp<LocalEnv> env = LocalEnv::make(argv);
|
||||
rp<LocalEnv> env = LocalEnv::make(argv, parent_env);
|
||||
|
||||
rp<LambdaAccess> retval
|
||||
= new LambdaAccess(name,
|
||||
|
|
|
|||
|
|
@ -4,12 +4,43 @@
|
|||
*/
|
||||
|
||||
#include "LocalEnv.hpp"
|
||||
#include "xo/indentlog/print/vector.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace ast {
|
||||
binding_path
|
||||
LocalEnv::lookup_local_binding(const std::string & vname) const
|
||||
rp<LocalEnv>
|
||||
LocalEnv::make_empty() {
|
||||
return new LocalEnv(std::vector<rp<Variable>>(), nullptr);
|
||||
}
|
||||
|
||||
rp<LocalEnv>
|
||||
LocalEnv::make(const std::vector<rp<Variable>> & argv,
|
||||
const rp<Environment> & parent_env)
|
||||
{
|
||||
return new LocalEnv(argv, parent_env);
|
||||
}
|
||||
|
||||
rp<LocalEnv>
|
||||
LocalEnv::make1(const rp<Variable> & arg1,
|
||||
const rp<Environment> & parent_env)
|
||||
{
|
||||
std::vector<rp<Variable>> argv = { arg1 };
|
||||
|
||||
return make(argv, parent_env);
|
||||
}
|
||||
|
||||
LocalEnv::LocalEnv(const std::vector<rp<Variable>> & argv,
|
||||
const rp<Environment> & parent_env)
|
||||
: origin_{nullptr},
|
||||
argv_(argv),
|
||||
parent_env_{parent_env}
|
||||
{
|
||||
constexpr bool c_debug_flag = true;
|
||||
scope log(XO_DEBUG(c_debug_flag), xtag("this", (void*)this), xtag("argv", argv_));
|
||||
}
|
||||
|
||||
binding_path
|
||||
LocalEnv::lookup_local_binding(const std::string & vname) const {
|
||||
int j_slot = 0;
|
||||
for (const auto & arg : argv_) {
|
||||
if (arg->name() == vname)
|
||||
|
|
@ -21,11 +52,9 @@ namespace xo {
|
|||
} /*lookup_local_binding*/
|
||||
|
||||
binding_path
|
||||
LocalEnv::lookup_binding(const std::string & vname) const
|
||||
{
|
||||
LocalEnv::lookup_binding(const std::string & vname) const {
|
||||
{
|
||||
auto local = this->lookup_local_binding(vname);
|
||||
|
||||
if (local.i_link_ == 0)
|
||||
return local;
|
||||
}
|
||||
|
|
@ -37,6 +66,52 @@ namespace xo {
|
|||
else
|
||||
return { free.i_link_ + 1, free.j_slot_ };
|
||||
} /*lookup_binding*/
|
||||
|
||||
bp<Variable>
|
||||
LocalEnv::lookup_local(const std::string & vname) const {
|
||||
for (const auto & var : this->argv_) {
|
||||
if (var->name() == vname)
|
||||
return var;
|
||||
}
|
||||
|
||||
return bp<Variable>::from_native(nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
LocalEnv::assign_parent(bp<Environment> p) {
|
||||
if ((parent_env_.get() != nullptr) && (parent_env_.get() != p.get())) {
|
||||
throw std::runtime_error(tostr("LocalEnv::assign_parent(P2): already have established parent P1",
|
||||
xtag("P1", parent_env_),
|
||||
xtag("P2", p)));
|
||||
|
||||
assert(false);
|
||||
}
|
||||
|
||||
parent_env_ = p.promote();
|
||||
}
|
||||
|
||||
void
|
||||
LocalEnv::upsert_local(bp<Variable> target) {
|
||||
for (auto & var : this->argv_) {
|
||||
if (var->name() == target->name()) {
|
||||
/* replace existing variable. May change its type */
|
||||
var = target.promote();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* control here: target not already present in this frame -> append */
|
||||
|
||||
this->argv_.push_back(target.promote());
|
||||
}
|
||||
|
||||
void
|
||||
LocalEnv::print(std::ostream& os) const {
|
||||
os << "<localenv"
|
||||
<< xtag("this", (void*)this)
|
||||
<< xtag("argv", argv_)
|
||||
<< ">";
|
||||
}
|
||||
} /*namespace ast*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,18 @@
|
|||
|
||||
namespace xo {
|
||||
namespace ast {
|
||||
std::string
|
||||
Variable::gensym(const std::string & prefix) {
|
||||
static std::size_t s_counter = 0;
|
||||
|
||||
++s_counter;
|
||||
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof(buf), "%ld", s_counter);
|
||||
|
||||
return prefix + std::string(buf);
|
||||
}
|
||||
|
||||
void
|
||||
Variable::attach_envs(bp<Environment> e) {
|
||||
/** e makes accessible all enclosing lexical scopes **/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue