summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorolpc user <olpc@xo-5d-f7-86.localdomain>2019-11-24 10:50:02 -0800
committerolpc user <olpc@xo-5d-f7-86.localdomain>2019-11-24 10:50:02 -0800
commit50be8bb8697b23ff469de142eaebe9666c2a9537 (patch)
tree396d7fbe92312e956de4ec021355c688e2b446b2
parentb3dea01d1ad6803b96865a846b56494506ccc74e (diff)
downloadstandingwithresilience-50be8bb8697b23ff469de142eaebe9666c2a9537.tar.gz
standingwithresilience-50be8bb8697b23ff469de142eaebe9666c2a9537.zip
wip fixing up, decided to refactor: see top of helpers.cpp
-rw-r--r--starts/meaning-vm/concept.cpp18
-rw-r--r--starts/meaning-vm/concept.hpp32
-rw-r--r--starts/meaning-vm/helpers.cpp284
-rw-r--r--starts/meaning-vm/helpers.hpp39
-rw-r--r--starts/meaning-vm/main.cpp3
-rw-r--r--starts/meaning-vm/meaning.cpp6
6 files changed, 257 insertions, 125 deletions
diff --git a/starts/meaning-vm/concept.cpp b/starts/meaning-vm/concept.cpp
index e9fd8e5..993ac62 100644
--- a/starts/meaning-vm/concept.cpp
+++ b/starts/meaning-vm/concept.cpp
@@ -5,14 +5,14 @@ ref concept::id()
return this;
}
-bool concept::linked(ref type)
+bool concept::linked(ref const & type) const
{
return links.count(type.ptr) > 0;
}
-bool concept::linked(ref type, ref target)
+bool concept::linked(ref const & type, ref const & target) const
{
- for (ref t : getAll(type)) {
+ for (ref const & t : getAll(type)) {
if (t == target) {
return true;
}
@@ -20,7 +20,7 @@ bool concept::linked(ref type, ref target)
return false;
}
-ref concept::get(ref type, bool quick)
+ref concept::get(ref const & type, bool quick) const
{
// this is called by name(), so it passes quick=true
auto result = links.equal_range(type.ptr);
@@ -34,7 +34,7 @@ ref concept::get(ref type, bool quick)
return result.first->second;
}
-concept::array concept::getAll(ref type)
+concept::array concept::getAll(ref const & type) const
{
array ret;
for (
@@ -42,17 +42,17 @@ concept::array concept::getAll(ref type)
range.first != range.second;
++ range.first
) {
- ret.push_back(range.first->second);
+ ret.emplace_back(range.first->second);
}
return ret;
}
-void concept::link(ref type, ref target)
+void concept::link(ref const & type, ref const & target)
{
links.insert({type.ptr, target.ptr});
}
-void concept::unlink(ref type, ref target)
+void concept::unlink(ref const & type, ref const & target)
{
auto ls = links.equal_range(type.ptr);
for (auto l = ls.first; l != ls.second; ++ l) {
@@ -64,7 +64,7 @@ void concept::unlink(ref type, ref target)
throw std::out_of_range("no such concept link to erase");
}
-void concept::unlink(ref type)
+void concept::unlink(ref const & type)
{
auto ls = links.equal_range(type.ptr);
if (ls.first == ls.second) {
diff --git a/starts/meaning-vm/concept.hpp b/starts/meaning-vm/concept.hpp
index eca2fa5..3308e10 100644
--- a/starts/meaning-vm/concept.hpp
+++ b/starts/meaning-vm/concept.hpp
@@ -8,13 +8,13 @@
template <typename T> struct vref;
struct concept;
template <typename T> struct value;
-class statementevaluable;
+struct statementcallref;
struct ref
{
ref(concept *p) : ptr(p) { if (p == 0) throw std::logic_error("null reference"); }
- ref(ref const &) = default;
concept* operator->() { return ptr; }
+ concept const * operator->() const { return ptr; }
bool operator==(ref const & that) const { return this->ptr == that.ptr; }
bool operator!=(ref const & that) const { return this->ptr != that.ptr; }
@@ -29,14 +29,22 @@ struct ref
operator const char *() const;
// helper linking syntax sugar
- statementevaluable operator=(ref that);
- ref operator<<(ref target);
+ statementcallref operator=(ref that);
+ //ref operator<<(ref target);
ref operator[](ref links);
bool isa(ref what) const;
bool isan(ref what) const;
concept * ptr;
+
+ /*
+ // destructor handles evaluating refs as statements
+ ~ref() noexcept;
+ ref(ref & that);
+ ref(ref && that) noexcept;
+ void destatement();
+ */
};
template <typename T>
@@ -64,15 +72,15 @@ struct concept
using array = std::vector<ref>;
ref id();
- bool linked(ref type);
- bool linked(ref type, ref target);
- ref get(ref type, bool quick = false); // returns first
+ bool linked(ref const & type) const;
+ bool linked(ref const & type, ref const & target) const;
+ ref get(ref const & type, bool quick = false) const; // returns first
template <typename T>
- vref<T> vget(ref type, bool quick = false) { return get(type, quick); }
- array getAll(ref type);
- void link(ref type, ref target);
- void unlink(ref type, ref target);
- void unlink(ref type);
+ vref<T> vget(ref const & type, bool quick = false) const { return get(type, quick); }
+ array getAll(ref const & type) const;
+ void link(ref const & type, ref const & target);
+ void unlink(ref const & type, ref const & target);
+ void unlink(ref const & type);
};
template <typename T>
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)
{
diff --git a/starts/meaning-vm/helpers.hpp b/starts/meaning-vm/helpers.hpp
index 12d1e9c..3caf10a 100644
--- a/starts/meaning-vm/helpers.hpp
+++ b/starts/meaning-vm/helpers.hpp
@@ -28,29 +28,36 @@
#include "concept.hpp"
#include "memorystore.hpp"
+
#include <sstream>
+#include <functional>
inline std::string operator+(vref<std::string> a, char const * b) { return std::string(a) + b; }
inline std::string operator+(vref<std::string> a, std::string b) { return std::string(a) + b; }
inline std::string operator+(char const * a, vref<std::string> b) { return a + std::string(b); }
inline std::string operator+(std::string a, vref<std::string> b) { return a + std::string(b); }
-// TODO TODO
-// actually, get rid of this, and set the function as a value on a normal ref.
-// then use ref destructor.
-// have to delete ref copy constructor. use move constructor instead.
-// could also alter ref copy constructor to tell copied ref is okay.
-class statementevaluable : public ref
+// reasons to use special struct:
+// the reason not to use ref directly is because we want to pass a ref to the function handler,
+// and it is easier to use if it is a bare copy. the bare copy triggers destruction and eval.
+// an alternate would be to add an evaluation flag to ref, but this might make it big.
+// reasons to not use special struct:
+// the operator, takes a ref type and returns a ref type
+struct statementcallref
{
-public:
- statementevaluable(ref r, std::function<void(ref)> evaluation)
- : ref(r.ptr),
- evaluation(evaluation)
- { }
- statementevaluable(statementevaluable const &) = delete;
- ~statementevaluable() { if (evaluate) { evaluation(*this); } }
-private:
- std::function<void(ref)> evaluation;
+ statementcallref(ref type, std::function<void(ref)> func);
+ statementcallref(ref const & that);
+
+ // handles evaluating refs as statements
+ ~statementcallref();
+ statementcallref(statementcallref & that);
+ statementcallref(statementcallref && that) noexcept;
+
+ operator ref();
+
+ void destatement();
+
+ ref r;
};
template <>
@@ -100,7 +107,7 @@ void lnks(T ... passedrefs)
declrefs(__VA_ARGS__); \
lnks(__VA_ARGS__)
-ref operator,(ref a, ref b);
+statementcallref operator,(statementcallref a, statementcallref b);
ref operator-(ref a, ref b);
ref a(ref what);
diff --git a/starts/meaning-vm/main.cpp b/starts/meaning-vm/main.cpp
index 1d25975..513efd2 100644
--- a/starts/meaning-vm/main.cpp
+++ b/starts/meaning-vm/main.cpp
@@ -2,7 +2,6 @@
#include "helpers.hpp"
#include "meaning.hpp"
-using namespace std;
#include <iostream>
@@ -14,7 +13,7 @@ void dumpconcept(ref r)
if (ref(l.first) == name) {
continue;
}
- cout << r << " " << ref(l.first) << " " << ref(l.second) << endl;
+ std::cout << r << " " << ref(l.first) << " " << ref(l.second) << std::endl;
}
if (!r->linked(dumped)) {
r[dumped = true];
diff --git a/starts/meaning-vm/meaning.cpp b/starts/meaning-vm/meaning.cpp
index a6156bf..a47a0ce 100644
--- a/starts/meaning-vm/meaning.cpp
+++ b/starts/meaning-vm/meaning.cpp
@@ -13,9 +13,9 @@ ref link(ref sourceref, ref typeref, ref targetref)
declrefs(link, source, type, target);
lnks(link-source, link-type, link-target);
return a(link)[
- link-source << sourceref,
- link-type << typeref,
- link-target << targetref
+ link-source = sourceref,
+ link-type = typeref,
+ link-target = targetref
];
}