WIP: should be working
authorChristian Thaeter <ct@pipapo.org>
Tue, 4 Nov 2014 08:56:11 +0000 (09:56 +0100)
committerChristian Thaeter <ct@pipapo.org>
Tue, 4 Nov 2014 08:56:11 +0000 (09:56 +0100)
.gitignore [new file with mode: 0644]
proto.lua

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..b25c15b
--- /dev/null
@@ -0,0 +1 @@
+*~
index 36fe0f1..342f5b0 100644 (file)
--- a/proto.lua
+++ b/proto.lua
---proto Prototype based Objectsysten
---proto ----------------------------
---proto Objects are `cloned` from existing objects ,`Object` is the mother of all objects.
---proto One can introduce additional inheritance paths with 'inherit'. Lookup order is
---proto first the prototype chain from `clone` and then all parent chains in the order
---proto they where added.
---proto
---proto Differential inheritance
---proto ~~~~~~~~~~~~~~~~~~~~~~~~
---proto Dynamic changes in prototypes and parent objects are reflected in childs unless a
---proto child overidden a slot. Just doing `child.slot = child.slot` will copy the looked up
---proto slot into the child, this speeds up further lookup and protects the slot from changes
---proto in the parent.
---proto
---proto
---proto
-
--- override the buildin type() function
---local buildin_type = type
---function type (x)
---    local m = getmetatable(x)
---    return buildin_type(x) == "table" and x.__type or buildin_type(m) == "table" and m.__type or buildin_type(x)
---end
+--- Prototype based Objectsysten
+---   Objects are `cloned` from existing objects ,`Object` is the mother of all objects.
+---   One can introduce additional inheritance paths with 'inherit'. Lookup order is
+---   first the prototype chain from `clone` and then all parent chains in the order
+---   they where added.
+---
+---   Multiple inheritance
+---     Objects can have an ordered list of other objects where they inhterit from
+---
+---   Differential inheritance
+---     Dynamic changes in prototypes and parent objects are reflected in childs unless a
+---     child overidden a slot.
+---
+---   Normal member lookup is child first then for each parent depth first.
+---
+---
+---
+---
 
 
 -- Object is the root object for all objects to be created
 local Object = {}
+setmetatable(Object, Object)
+
+--- Object:proto_clone ()
+--- Object:proto_clone {...}
+---   takes an optional table for new mebers of the cloned object
+---   Sole strings on this table (aka, the integer part) define which members to copy up
+function Object:proto_clone(newobject)
+    assert(not newobject or type(newobject) == 'table')
+    newobject = newobject or {}
+    setmetatable(newobject, newobject)
+    newobject.__index = self
 
-Object.__index = Object
+    -- copy up members
+    for i=1,#newobject do
+        assert(type(newobject[i]) == 'string')
+        newobject[newobject[i]] = self[newobject[i]]
+        newobject[i] = nil
+    end
 
-function Object:__clone(t)
-    assert(not t or type(t) == 'table')
-    local newobject = t or {}
-    setmetatable(newobject, self)
-    newobject.__index = self
-    newobject.__proto = self
     return newobject
 end
 
 
-function Object:__inherit (...)
-    if self.__parents then
-        local parents = self.__parents
-        local args = {...}
+--- Object:proto_inherit (...)
+---   adds some more Objects to the inheritance list
+function Object:proto_inherit (...)
+    local args = {...}
+    if #args > 0 then
+        local parents = rawget(self,"__proto_parents") or rawset(self,"__proto_parents", {self.__index} or {}) and rawget(self,"__proto_parents")
+
         for i=1,#args do
             assert((pcall(function () return args[i].indexable end)), "object not indexable")
             parents[#parents + 1] = args[i]
         end
-    else
-        self.__parents = {self.__index, ...}
-        self.__index = function(self, key)
-                           local parents = self.__parents
-                           for i=1,#parents do
-                               local value = parents[i][key]
-                               if value then
-                                   return value
+
+        if type(self.__index) == 'table' then
+            self.__index = function(self, key)
+                               local parents = rawget(self,"__proto_parents")
+                               for i=1,#parents do
+                                   local value = parents[i][key]
+                                   if value then
+                                       return value
+                                   end
                                end
                            end
-                       end
+        end
     end
     return self
 end
 
 
-function Object:__pairs()
-    local state = {self=self, keys_done = {}, parents = self.__parents or {self.__index} or {}, ppos = 1}
-    local function itr (state)
-        local value
-        while state.self do
-            state.pos, value  = next(state.self, state.pos)
-            if state.pos then
-                state.keys_done[state.pos] = true
-                return state.pos, value
-            else
-                state.self = nil
-            end
+
+
+--- Object:proto_prototypes ()
+---   iterator over all prototypes of an object in search order (depth first, no duplicates, including self)
+---    for parent in object:prototypes()
+local function next_prototype(state)
+    local object, mystate
+    repeat
+        mystate = state.state
+
+        repeat
+            mystate.pos = (mystate.pos or 0) +1
+            object = mystate.parents[mystate.pos]
+        until not object or not state.objects_done[object]
+
+        if object then
+            state.objects_done[object] = true
+            state.state = {oldstate = mystate, parents= rawget(object, "__proto_parents") or {object.__index} or {}}
+            return object
         end
 
-        while state.parents[state.ppos] do
-            state.pos, value  = next(state.parents[state.ppos], state.pos)
-            if state.pos then
-                if not state.keys_done[state.pos] then
-                    state.keys_done[state.pos] = true
-                    return state.pos, value
-                end
-            else
-                state.ppos = state.ppos + 1
-            end
+        state.state = state.state.oldstate
+    until not state.state
+end
+
+function Object:proto_prototypes()
+    local state = {objects_done = {}, state={parents = {self}}}
+    return next_prototype, state
+end
+
+
+--- Object:proto_members ()
+---   iterate over members including inherited ones of a object, no duplicates
+---   returns member, value
+local function next_member(state)
+    local value, mystate
+
+    repeat
+        mystate = state.state
+
+        repeat
+            mystate.mpos,value = next(state.object, mystate.mpos)
+        until not value or not state.members_done[mystate.mpos]
+
+        if value then
+            state.members_done[mystate.mpos] = true
+            return mystate.mpos, value
         end
-    end
 
-    return itr, state
+        state.object = next_prototype(state)
+    until not state.object
 end
 
 
-if arg[1] == "test" then
-    Object.foo = "foo"
+function Object:proto_members()
+    local state = {members_done = {}, objects_done = {}, state={parents = {self}}}
+    state.object = next_prototype(state)
+    return next_member, state
+end
+
+
+
+
+--- Object:proto_findall (name)
+---   finds all members including inherited ones of a given name
+---   returns object, value
+local function next_value(state)
+    local mystate
+
+    repeat
+        mystate = state.state
+        state.object = next_prototype(state)
+        if state.object then
+            local value = rawget(state.object, state.name)
+            if value then
+                return state.object, value
+            end
+        end
+    until not state.object
+end
 
-    O2 = Object:__clone { bar = "bar"}
+function Object:proto_findall(name)
+    local state = {objects_done = {}, name=name, state={parents = {self}}}
+    return next_value, state
+end
 
 
-    O3 = Object:__clone {baz = "baz" }
-    O3:__inherit(O2)
 
-    for k,v in pairs(O3) do
-        print(k,v)
+--- Object:proto_object (name)
+---   return the object where a member is actually defined
+function Object:proto_objectof(name)
+    if rawget(self, name) then
+        return self
+    else
+        local parents = rawget(self, "__proto_parents") or {self.__index} or {}
+        for i=1,#parents do
+            local obj = parents[i]:proto_objectof(name)
+            if obj then
+                return obj
+            end
+        end
     end
-else
-    return Object
 end
 
+
+return Object
+
 -- Local Variables:
 -- mode: lua
 -- lua-indent-level: 4