diff options
Diffstat (limited to 'starts/meaning-vm/helpers.cpp')
-rw-r--r-- | starts/meaning-vm/helpers.cpp | 284 |
1 files changed, 201 insertions, 83 deletions
diff --git a/starts/meaning-vm/helpers.cpp b/starts/meaning-vm/helpers.cpp index e29962b..da1a974 100644 --- a/starts/meaning-vm/helpers.cpp +++ b/starts/meaning-vm/helpers.cpp @@ -4,74 +4,111 @@ #include "memorystore.hpp" #include <unordered_map> +#include <functional> + +// sometimes we use an assignment as an expression. +// is there any reason not to support this? +// well, we would evaluate the assignment when it is converted to a ref +// and currently that is used for something else +// what is it used for? +// I don't remember ... the assignment is destroyed and unevaluated, so it's likely +// throughout the internal implemntation +// it's used for the comma operator, which doesn't want evaluation. +// okay, hmm. +// well, if we wanted to support this, we could change the comma operator to not do the +// conversion. use some other trick. +// [ ] change comma operator to not do conversion: instead take statementcallref object +// [ ] change statementcallref::operator ref() to evaluate and return the statement +// since we're accumulating more possible bugs, let's think about design. +// really, ref should be different from syntax sugar. we should have a special syntax sugar +// object, and it should not use its own functions at all. that means not using meaning functions +// that use them eiher. +// work also brings to light how the product will be made in layers, with each layer using more interdependence and automatic meaning, etc, than the lower one. +// layer0 is raw references and allocations +// layer1 is very core meaning +// layer2 is very core syntax sugar +// each layer can only use layers below it. + +// concept names are for bootstrapping convenience, +// to make hardcoding structures easier. +// hence there is just one single list of them +std::unordered_map<std::string,concept*,std::hash<std::string>,std::equal_to<std::string>> conceptsByName; + +struct name_t : public ref +{ + name_t(); +} name; + +static ref statement_function("statement-function"); +static ref statement_evaluated("statement-evaluated"); +static ref true_ref("true"); +static ref false_ref("false"); ref operator-(ref a, ref b) { return ref(a.name() + "-" + b.name()); } -statementevaluable ref::operator=(ref that) +statementcallref ref::operator=(ref that) { // for single-line evaluation, we'll need to return a special object declrefs(assign, expression); decllnks(value, to); - return { - a(assign-expression)[ - to = *this, - value = that - ], - [](ref expr) { - declrefs(link, target, unknown, source, type); - decllnks(value, to); - lnks(link-target, link-type, link-source); - decllnks(name, is); - ref lhs = expr.get(to); - ref rhs = expr.get(value); - if (lhs.isa(link) && lhs->get(link-target) == unknown) { - // we are a link missing a target: our assignment is making the link happen - lhs->unlink(link-target, unknown); - lhs->link(link-target, rhs); - ref src = lhs->get(link-source); - if (lhs->get(link-type) != unknown && src != unknown) { - src->link(lhs->get(link-type), rhs); - dealloc(lhs); - dealloc(expr); - } else { - throw std::logic_error("not sure what to do with incomplete link assignment"); - } - } else if (rhs->linked(anonymous, true) && !lhs->linked(anonymous, true)) { - // this is assignment of anonymous content to empty named concept - bool donealready = false; - for (auto & l : lhs->links) { - if (ref(l.first) == name) { continue; } - if (ref(l.first) == is && ref(l.second) == link-type) { continue; } - donealready = true; - } - if (donealready) { - // if we have links, and that has links we do not have, an error has been made - for (auto & link : rhs->links) { - if (ref(link.first) == anonymous) { continue; } - if (ref(link.first) == name) { continue; } - if (!lhs->linked(ref(link.first), ref(link.second))) { - throw std::logic_error(lhs.name() + " already defined otherwise from " + rhs->get(is).name()); - } + statementcallref ret(assign-expression, [](ref expr){ + declrefs(link, target, unknown, source, type); + decllnks(value, to); + lnks(link-target, link-type, link-source); + decllnks(name, is, anonymous); + ref lhs = expr->get(to); + ref rhs = expr->get(value); + if (lhs.isa(link) && lhs->get(link-target) == unknown) { + // we are a link missing a target: our assignment is making the link happen + lhs->unlink(link-target, unknown); + lhs->link(link-target, rhs); + ref src = lhs->get(link-source); + if (lhs->get(link-type) != unknown && src != unknown) { + src->link(lhs->get(link-type), rhs); + expr->unlink(to, lhs); + dealloc(lhs); + } else { + throw std::logic_error("not sure what to do with incomplete link assignment"); + } + } else if (rhs->linked(anonymous, true) && !lhs->linked(anonymous, true)) { + // this is assignment of anonymous content to empty named concept + bool donealready = false; + for (auto & l : lhs->links) { + if (ref(l.first) == name) { continue; } + if (ref(l.first) == is && ref(l.second) == link-type) { continue; } + donealready = true; + } + if (donealready) { + // if we have links, and that has links we do not have, an error has been made + for (auto & link : rhs->links) { + if (ref(link.first) == anonymous) { continue; } + if (ref(link.first) == name) { continue; } + if (!lhs->linked(ref(link.first), ref(link.second))) { + throw std::logic_error(lhs.name() + " already defined otherwise from " + rhs->get(is).name()); } - donealready = true; - } - rhs->unlink(anonymous, true); - auto nam = rhs->get(name); - rhs->unlink(name, nam); - if (!donealready) { - ptr->links.insert(rhs->links.begin(), rhs->links.end()); } - rhs->link(name, nam); - dealloc(rhs); - dealloc(nam); - } else { - throw std::logic_error("unexpected bare assignment"); + donealready = true; + } + rhs->unlink(anonymous, true); + auto nam = rhs->get(name); + rhs->unlink(name, nam); + if (!donealready) { + lhs->links.insert(rhs->links.begin(), rhs->links.end()); } + rhs->link(name, nam); + expr->unlink(value, rhs); + dealloc(rhs); + dealloc(nam); + } else { + throw std::logic_error("unexpected bare assignment"); } - } + }); + ret.r->link(to, *this); + ret.r->link(value, that); + return ret; /* decllnks(anonymous, is, name); declrefs(link, source, type, target, unknown); @@ -95,49 +132,127 @@ statementevaluable ref::operator=(ref that) */ } -ref ref::operator<<(ref target) +/*ref ref::operator<<(ref target) { // prep a link ref ret = alloc(); ret->link(*this, target); return ret; +}*/ + +void statementcallref::destatement() +{ + auto func = r->get(statement_function); + r->unlink(statement_function); + dealloc(func); } -ref ref::operator[](ref expr) { - declrefs(assign, expression); - decllnks(value, to); - declrefs(link, type, unknown); +statementcallref::statementcallref(ref type, std::function<void(ref)> func) +: r(a(type).ptr) +{ + r->link(statement_function, valloc<std::function<void(ref)>>(func)); +} - if (expr.isa(assign-expression)) { +statementcallref::statementcallref(ref const & that) +: r(that.ptr) +{ + if (!that->linked(statement_function)) { + throw std::logic_error(std::string(that) + " has no statement-function"); } - expr.take(); - ref lhs = expr.get(to); - ref rhs = expr.get(value); - if (that.isa(link-type)) { - return ::link(*this, that, unknown); - } else { - ptr->links.insert(that->links.begin(), that->links.end()); - dealloc(that); - return *this; +} + +statementcallref::operator ref() +{ + ref ret(r); + destatement(); + r.ptr = 0; + return ret; +} + +#include <iostream> +statementcallref::~statementcallref() noexcept +{ + if (r.ptr == 0) { return; } + if (r->linked(statement_evaluated, true_ref)) { + std::cerr << "statement already evaluated: " << r << std::endl; + return; } + try { + auto func = r->vget<std::function<void(ref)>>(statement_function, true); + func->data(r); + destatement(); + r->link(statement_evaluated, true_ref); + dealloc(r); + r.ptr = 0; + } catch (std::out_of_range &) { } } -ref operator,(ref a, ref b) +statementcallref::statementcallref(statementcallref && that) noexcept +: r(that.r.ptr) { - a->links.insert(b->links.begin(), b->links.end()); - dealloc(b); - return a; + that.r.ptr = 0; } -// concept names are for bootstrapping convenience, -// to make hardcoding structures easier. -// hence there is just one single list of them -std::unordered_map<std::string,concept*,std::hash<std::string>,std::equal_to<std::string>> conceptsByName; +statementcallref::statementcallref(statementcallref & that) +: r(that.r.ptr) +{ + if (that.r.ptr == 0) { throw std::logic_error("empty ref"); } + if (that.r->linked(statement_function)) { + // statements are moved, for evaluation + that.r.ptr = 0; + } +} -struct name_t : public ref +ref ref::operator[](ref expr) { + declrefs(assign, comma, expression); + decllnks(value, to, what); + declrefs(link, type, unknown); + + if (expr.isa(assign-expression)) { + ref lhs = expr->get(to); + ref rhs = expr->get(value); + ptr->link(lhs, rhs); + dealloc(expr); + return *this; + } else if (expr.isa(comma-expression)) { + auto parts = expr->getAll(what); + dealloc(expr); + for (ref part : parts) { + if (!part.isa(assign-expression)) { + throw std::logic_error("[,] argument is not an assignment"); + } + operator[](part); + } + return *this; + } else if (expr.isa(link-type)) { + return ::link(*this, expr, unknown); + } else { + throw std::logic_error("[] argument is neither a link nor an assignment"); + } +} + +statementcallref operator,(statementcallref a, statementcallref b) { - name_t(); -} name; + declrefs(comma, expression); + decllnks(what); + if (a.r.isa(comma-expression)) { + if (b.r.isa(comma-expression)) { + a.r->links.insert(b.r->links.begin(), b.r->links.end()); + dealloc(b); b.r.ptr = 0; + } else { + a.r->link(what, b.r); b.r.ptr = 0; + } + return a; + } else if (b.r.isa(comma-expression)) { + b.r->link(what, a.r); a.r.ptr = 0; + return b; + } else { + statementcallref ret(comma-expression, [](ref) { throw std::logic_error("bare comma-expression"); }); + ret.r->link(what, a.r); a.r.ptr = 0; + ret.r->link(what, b.r); b.r.ptr = 0; + return ret; + } +} template <> vref<std::string>::vref(std::string const & s) @@ -146,7 +261,7 @@ vref<std::string>::vref(std::string const & s) ptr->link(::name, ptr); } name_t::name_t() -: ref(alloc()) +: ref(alloc().ptr) { vref nam(std::string("name")); ptr->link(::name, nam); @@ -171,7 +286,7 @@ vref<std::string> ref::name() const { try { return ptr->vget<std::string>(::name, true); - } catch (std::out_of_range) { + } catch (std::out_of_range &) { declrefs(UNNAMED); return UNNAMED.name(); } @@ -185,7 +300,10 @@ ref a(ref what) { static unsigned long long gid = 0; decllnks(is, anonymous); - return ref(what.name() + "-" + std::to_string(gid++))[is = what, anonymous = true]; + ref ret(what.name() + "-" + std::to_string(gid++)); + ret->link(is, what); + ret->link(anonymous, true); + return ret; } ref a(ref what, ref name) { |