diff options
-rw-r--r-- | starts/meaning-vm/concept.cpp | 9 | ||||
-rw-r--r-- | starts/meaning-vm/concept.hpp | 23 | ||||
-rw-r--r-- | starts/meaning-vm/helpers.cpp | 68 | ||||
-rw-r--r-- | starts/meaning-vm/helpers.hpp | 16 | ||||
-rw-r--r-- | starts/meaning-vm/main.cpp | 30 | ||||
-rw-r--r-- | starts/meaning-vm/makefile | 4 | ||||
-rw-r--r-- | starts/meaning-vm/meaning.cpp | 27 | ||||
-rw-r--r-- | starts/meaning-vm/meaning.hpp | 36 | ||||
-rw-r--r-- | starts/meaning-vm/memorystore.cpp | 13 |
9 files changed, 176 insertions, 50 deletions
diff --git a/starts/meaning-vm/concept.cpp b/starts/meaning-vm/concept.cpp index c064ed4..03c784f 100644 --- a/starts/meaning-vm/concept.cpp +++ b/starts/meaning-vm/concept.cpp @@ -20,11 +20,16 @@ bool concept::linked(ref type, ref target) return false; } -ref concept::get(ref type) +ref concept::get(ref type, bool quick) { + // this is called by name(), so it passes quick=true auto result = links.equal_range(type.ptr); if (result.first == result.second) { - throw std::out_of_range("no such concept link to get: " + type.name()); + if (quick) { + throw std::out_of_range("no such concept link to get"); + } else { + throw std::out_of_range("no such concept link to get: " + type.name()); + } } return result.first->second; } diff --git a/starts/meaning-vm/concept.hpp b/starts/meaning-vm/concept.hpp index e5cddec..c69ff10 100644 --- a/starts/meaning-vm/concept.hpp +++ b/starts/meaning-vm/concept.hpp @@ -15,19 +15,22 @@ struct ref ref(ref const &) = default; concept* operator->() { return ptr; } bool operator==(ref const & that) const { return this->ptr == that.ptr; } + bool operator!=(ref const & that) const { return this->ptr != that.ptr; } bool operator<(ref const &) const { throw std::logic_error("ref has redefined syntax sugar: do not use in containers"); } - // for helpers + // for helpers, mostly names ref(std::string const &); ref(char const * str) : ref(std::string(str)) { } ref(bool b) : ref(b ? "true" : "false") { } ref() : ref("nothing") { } - value<std::string> & name() const; + value<std::string> & name() const; // this is a reference so that its char pointer lasts operator const char *() const; - ref operator=(ref other); // helper constructs new concept with this as link - ref operator[](ref links); // helper sets all links from passed concept + // helper linking syntax sugar + ref operator=(ref that); + ref operator<<(ref target); + ref operator[](ref links); bool isa(ref what) const; bool isan(ref what) const; @@ -42,11 +45,13 @@ struct vref value<T>* operator->() { return ptr; } operator T const &() const { return *ptr; } - vref(ref const & other) : ptr(static_cast<value<T>*>(other.ptr)) { } + vref(T const & val); + + vref(ref const & that) : ptr(static_cast<value<T>*>(that.ptr)) { } operator ref() { return ptr; } // for use by containers - //bool operator<(ref const & other) const { return ptr < other.ptr; } + //bool operator<(ref const & that) const { return ptr < that.ptr; } value<T> * ptr; }; @@ -60,9 +65,9 @@ struct concept ref id(); bool linked(ref type); bool linked(ref type, ref target); - ref get(ref type); // returns first + ref get(ref type, bool quick = false); // returns first template <typename T> - vref<T> vget(ref type) { return get(type); } + 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); @@ -72,7 +77,7 @@ struct concept template <typename T> struct value : public concept, public T { - value(T const & val) : T(val) {} + value(T const & val) : T(val) { } value(value<T> const & val) = default; static value<T>& of(ref c) { diff --git a/starts/meaning-vm/helpers.cpp b/starts/meaning-vm/helpers.cpp index dae149f..810d30c 100644 --- a/starts/meaning-vm/helpers.cpp +++ b/starts/meaning-vm/helpers.cpp @@ -1,5 +1,6 @@ #include "helpers.hpp" +#include "meaning.hpp" #include "memorystore.hpp" #include <unordered_map> @@ -11,9 +12,25 @@ ref operator-(ref a, ref b) ref ref::operator=(ref that) { - // if this is not anonymous, and that is, then we are naming it - declrefs(anonymous, name, is); - if (that->linked(anonymous, true) && !ptr->linked(anonymous, true)) { + decllnks(anonymous, is, name); + declrefs(link, source, type, target, unknown); + lnks(link-target, link-source, link-target); + if (this->isa(link) && ptr->get(link-target) == unknown) { + // we are a link missing a target: our assignment is making the link happen + ptr->unlink(link-target, unknown); + ptr->link(link-target, that); + ref src = ptr->get(link-source); + if (ptr->get(link-type) != unknown && src != unknown) { + src->link(ptr->get(link-type), ptr->get(link-target)); + dealloc(ptr); + return src; + } else { + throw std::logic_error("not sure what to do with incomplete link assignment"); + } + } else if (isa(link-type)) { + // assignment to a link-type is likely inside a [type1=target1,type2=target2] expression + return (*this) << that; + } else if (that->linked(anonymous, true) && !ptr->linked(anonymous, true)) { // this is assignment of anonymous content to empty named concept bool donealready = false; if (ptr->links.size() != 1) { @@ -30,24 +47,34 @@ ref ref::operator=(ref that) that->unlink(anonymous, true); auto nam = that->get(name); that->unlink(name, nam); - dealloc(nam); if (!donealready) { ptr->links.insert(that->links.begin(), that->links.end()); } + that->link(name, nam); dealloc(that); + dealloc(nam); return *this; } + throw std::logic_error("unexpected use of assignment"); +} - // if this is link-type, make new concept [not checked, might want to assume] +ref ref::operator<<(ref target) +{ + // prep a link ref ret = alloc(); - ret->link(*this, that); + ret->link(*this, target); return ret; } -ref ref::operator[](ref links) { - ptr->links.insert(links->links.begin(), links->links.end()); - dealloc(links); - return *this; +ref ref::operator[](ref that) { + declrefs(link, type, unknown); + if (that.isa(link-type)) { + return ::link(*this, that, unknown); + } else { + ptr->links.insert(that->links.begin(), that->links.end()); + dealloc(that); + return *this; + } } ref operator,(ref a, ref b) @@ -66,10 +93,17 @@ struct name_t : public ref { name_t(); } name; + +template <> +vref<std::string>::vref(std::string const & s) +: ptr(valloc(s).ptr) +{ + ptr->link(::name, ptr); +} name_t::name_t() : ref(alloc()) { - auto nam = valloc(std::string("name")); + vref nam(std::string("name")); ptr->link(::name, nam); conceptsByName.emplace(nam, ptr); } @@ -81,7 +115,7 @@ ref::ref(std::string const & s) ptr = res->second; } else { ref con = alloc(); - auto nam = valloc<std::string>(s); + vref<std::string> nam(s); conceptsByName.emplace(nam, con.ptr); con->link(::name, nam); ptr = con.ptr; @@ -90,7 +124,12 @@ ref::ref(std::string const & s) value<std::string> & ref::name() const { - return *ptr->vget<std::string>(::name).ptr; + try { + return *ptr->vget<std::string>(::name, true).ptr; + } catch (std::out_of_range) { + declrefs(UNNAMED); + return UNNAMED.name(); + } } ref::operator const char *() const { @@ -100,7 +139,7 @@ ref::operator const char *() const { ref a(ref what) { static unsigned long long gid = 0; - declrefs(is, anonymous); + decllnks(is, anonymous); return ref(what.name() + "-" + std::to_string(gid++))[is = what, anonymous = true]; } ref a(ref what, ref name) @@ -121,6 +160,7 @@ bool ref::isa(ref what) const declrefs(is); for (auto group : ptr->getAll(is)) { if (group == what) return true; + if (group == *this) continue; if (group.isa(what)) return true; } return false; diff --git a/starts/meaning-vm/helpers.hpp b/starts/meaning-vm/helpers.hpp index eca2479..8c7e307 100644 --- a/starts/meaning-vm/helpers.hpp +++ b/starts/meaning-vm/helpers.hpp @@ -48,6 +48,22 @@ void __helper_init_ref_names(std::string names, T &... refrefs) ref __VA_ARGS__; \ __helper_init_ref_names(#__VA_ARGS__, __VA_ARGS__) +template <typename... T> +void lnks(T ... passedrefs) +{ + std::initializer_list<ref> refs = { passedrefs... }; + declrefs(link, type, is); + for (ref r : refs) { + if (!r->linked(is, link-type)) { + r->link(is, link-type); + } + } +} + +#define decllnks(...) \ + declrefs(__VA_ARGS__); \ + lnks(__VA_ARGS__) + ref operator,(ref a, ref b); ref operator-(ref a, ref b); diff --git a/starts/meaning-vm/main.cpp b/starts/meaning-vm/main.cpp index c4207cb..6919791 100644 --- a/starts/meaning-vm/main.cpp +++ b/starts/meaning-vm/main.cpp @@ -1,5 +1,6 @@ #include "concept.hpp" #include "helpers.hpp" +#include "meaning.hpp" using namespace std; @@ -7,7 +8,7 @@ using namespace std; void dumpconcept(ref r) { - declrefs(dumped, name); + decllnks(dumped, name); for (auto & l : r->links) { if (ref(l.first) == name) { @@ -27,27 +28,22 @@ void dumpconcept(ref r) int main() { - declrefs(is, link, type); - is->link(is, link-type); - - declrefs(source, target); - declrefs(linked, A, B, C, abc, variable); - declrefs(trueness, truth, what, not); - - declrefs(add, unique, habit, needs, assumes, makes); - A = a(variable); - B = a(variable); - C = a(variable); + declrefs(make, linked, habit); + declrefs(A, B, C); + decllnks(needs, assumes, makes); // add a new unique link to a concept // given A, B, C // and assuming A is not linked by B to C, // makes A be linked by B to C. - add-link-unique = a(habit)[ - needs = a(variable, A), needs = a(variable, B), needs = a(variable, C), - makes = a(link, abc-linked)[link-source = A, link-type = B, link-target = C], - assumes = a(trueness, abc-not-linked)[what = abc-linked, truth = false] + // NEXT? make code for make-linked that takes a ref + // change the needs structure to use a model for the ref, + // with needed values specified as 'provided' + make-linked = a(habit)[ + needs = and(avariable(A), avariable(B), avariable(C)), + assumes = not(A-B-C-linked = link(A, B, C)), + makes = A-B-C-linked ]; - dumpconcept(add-link-unique); + dumpconcept(make-linked); } diff --git a/starts/meaning-vm/makefile b/starts/meaning-vm/makefile index 29f07e5..c037661 100644 --- a/starts/meaning-vm/makefile +++ b/starts/meaning-vm/makefile @@ -1,7 +1,7 @@ -CXXFLAGS=-std=c++17 -fno-operator-names -ggdb +CXXFLAGS=-std=c++17 -fno-operator-names -ggdb -O0 LINK.o=$(LINK.cc) -main: main.o concept.o helpers.o memorystore.o +main: main.o concept.o helpers.o memorystore.o meaning.o *.o: *.hpp clean: -rm *.o main diff --git a/starts/meaning-vm/meaning.cpp b/starts/meaning-vm/meaning.cpp new file mode 100644 index 0000000..a47a0ce --- /dev/null +++ b/starts/meaning-vm/meaning.cpp @@ -0,0 +1,27 @@ +#include "meaning.hpp" + +#include "helpers.hpp" + +ref avariable(ref name) +{ + declrefs(variable); + return a(variable, name); +} + +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 + ]; +} + +ref not(ref whatref) +{ + declrefs(not); + decllnks(what); + return a(not, not-whatref)[what] = whatref; +} diff --git a/starts/meaning-vm/meaning.hpp b/starts/meaning-vm/meaning.hpp new file mode 100644 index 0000000..c358d69 --- /dev/null +++ b/starts/meaning-vm/meaning.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include "concept.hpp" +#include "helpers.hpp" + +// get a named variable +ref avariable(ref name); + +template <typename... T> +ref and(T... refs) +{ + std::initializer_list<ref> rs = { refs... }; + declrefs(and); + decllnks(what); + ref ret = a(and); + ref name; int count = 0; + for (auto r : rs) { + ret[what] = r; + if (count == 0) { + name.ptr = r.ptr; + } else { + name.ptr = (name-and-r).ptr; + } + ++ count; + } + if (count == 1) { + throw std::logic_error("and needs at least two subjects"); + } + return name = ret; +} + +// make a reference to a link +ref link(ref sourceref, ref typeref, ref targetref); + +// invert a meaning +ref not(ref whatref); diff --git a/starts/meaning-vm/memorystore.cpp b/starts/meaning-vm/memorystore.cpp index c759051..19e40db 100644 --- a/starts/meaning-vm/memorystore.cpp +++ b/starts/meaning-vm/memorystore.cpp @@ -16,26 +16,27 @@ ref alloc(concept * moved) { return r; } -bool referenced(ref r) { +concept* referenced(ref r) { for (ref r2 : concepts()) { if (r2 == r) { continue; } for (auto & l : r2->links) { if (ref(l.first) == r) { - return true; + return r2.ptr; } if (ref(l.second) == r) { - return true; + return r2.ptr; } } } - return false; + return 0; } void dealloc(ref r) { - if (referenced(r)) { - throw std::logic_error("concept is referenced"); + concept * referenced = ::referenced(r); + if (referenced) { + throw std::logic_error("concept '" + r.name() + "' is referenced by '" + ref(referenced).name() + '"'); } for ( auto it = concepts().begin(); |