first green version using unified method/metamethod resolver

This commit is contained in:
kikito 2015-12-27 15:42:49 +01:00
parent 13173150de
commit fc61416c81

View File

@ -28,16 +28,9 @@ local middleclass = {
]] ]]
} }
local _metamethods = {}
for m in ([[ add band bor bxor bnot call concat div eq
gc index ipairs idiv le len lt metatable mod mode
mul newindex pairs pow shl shr sub tostring unm ]]):gmatch("%S+") do
_metamethods['__' .. m] = true
end
local function _setClassDictionariesMetatables(aClass) local function _setClassDictionariesMetatables(aClass)
local dict = aClass.__instanceDict local dict = aClass.__instanceDict
aClass.__instanceMeta.__index = dict aClass.__instanceDict.__index = dict
local super = aClass.super local super = aClass.super
if super then if super then
@ -53,63 +46,51 @@ local function _createIndexWrapper(aClass, f)
if f == nil then if f == nil then
return aClass.__instanceDict return aClass.__instanceDict
else else
return function(self, key) return function(self, name)
local value = aClass.__instanceDict[key] local value = aClass.__instanceDict[name]
if value ~= nil then if value ~= nil then
return value return value
elseif type(f) == "function" then elseif type(f) == "function" then
return (f(self, key)) return (f(self, name))
else else
return f[key] return f[name]
end end
end end
end end
end end
local function _setMetamethod(aClass, name, f) local function _propagateInstanceMethod(aClass, name, f)
if name == "__index" then aClass.__instanceDict[name] = name == "__index" and _createIndexWrapper(aClass, f) or f
f = _createIndexWrapper(aClass, f)
end
aClass.__instanceMeta[name] = f
end
local function _propagateMetamethod(aClass, name, f)
_setMetamethod(aClass, name, f)
for subclass in pairs(aClass.subclasses) do for subclass in pairs(aClass.subclasses) do
if rawget(subclass.__instanceDict, name) == nil then if rawget(subclass.__declaredMethods, name) == nil then
_propagateMetamethod(subclass, name, f) _propagateInstanceMethod(subclass, name, f)
end end
end end
end end
local function _updateClassDict(aClass, key, value) local function _declareInstanceMethod(aClass, name, f)
aClass.__instanceDict[key] = value aClass.__declaredMethods[name] = f
if _metamethods[key] then if f == nil and aClass.super then
if value == nil then f = aClass.super.__instanceDict[name]
if aClass.super then
value = aClass.super.__instanceDict[key]
end
end
_propagateMetamethod(aClass, key, value)
end end
_propagateInstanceMethod(aClass, name, f)
end end
local function _setClassMetatable(aClass) local function _setClassMetatable(aClass)
setmetatable(aClass, { setmetatable(aClass, {
__tostring = function() return "class " .. aClass.name end, __tostring = function() return "class " .. aClass.name end,
__index = aClass.static, __index = aClass.static,
__newindex = _updateClassDict, __newindex = _declareInstanceMethod,
__call = function(self, ...) return self:new(...) end __call = function(self, ...) return self:new(...) end
}) })
end end
local function _createClass(name, super) local function _createClass(name, super)
local aClass = { name = name, super = super, static = {}, __instanceDict = {}, __instanceMeta = {} } local aClass = { name = name, super = super, static = {}, __instanceDict = {}, __declaredMethods = {} }
aClass.subclasses = setmetatable({}, {__mode = "k"}) aClass.subclasses = setmetatable({}, {__mode = "k"})
_setClassDictionariesMetatables(aClass) _setClassDictionariesMetatables(aClass)
@ -118,18 +99,6 @@ local function _createClass(name, super)
return aClass return aClass
end end
local function _setSubclassMetamethods(aClass, subclass)
for m in pairs(_metamethods) do
_setMetamethod(subclass, m, aClass.__instanceDict[m])
end
end
local function _setDefaultInitializeMethod(aClass, super)
aClass.initialize = function(instance, ...)
return super.initialize(instance, ...)
end
end
local function _includeMixin(aClass, mixin) local function _includeMixin(aClass, mixin)
assert(type(mixin)=='table', "mixin must be a table") assert(type(mixin)=='table', "mixin must be a table")
for name,method in pairs(mixin) do for name,method in pairs(mixin) do
@ -145,7 +114,9 @@ end
local Object = { local Object = {
__tostring = function(self) return "instance of " .. tostring(self.class) end, __tostring = function(self) return "instance of " .. tostring(self.class) end,
initialize = function(self) end,
initialize = function(self, ...) end,
isInstanceOf = function(self, aClass) isInstanceOf = function(self, aClass)
return type(self) == 'table' and return type(self) == 'table' and
type(self.class) == 'table' and type(self.class) == 'table' and
@ -160,7 +131,7 @@ local Object = {
allocate = function(self) allocate = function(self)
assert(type(self) == 'table', "Make sure that you are using 'Class:allocate' instead of 'Class.allocate'") assert(type(self) == 'table', "Make sure that you are using 'Class:allocate' instead of 'Class.allocate'")
return setmetatable({ class = self }, self.__instanceMeta) return setmetatable({ class = self }, self.__instanceDict)
end, end,
new = function(self, ...) new = function(self, ...)
@ -174,8 +145,12 @@ local Object = {
assert(type(name) == "string", "You must provide a name(string) for your class") assert(type(name) == "string", "You must provide a name(string) for your class")
local subclass = _createClass(name, self) local subclass = _createClass(name, self)
_setSubclassMetamethods(self, subclass)
_setDefaultInitializeMethod(subclass, self) for name, f in pairs(self.__instanceDict) do
_propagateInstanceMethod(subclass, name, f)
end
subclass.initialize = function(instance, ...) return self.initialize(instance, ...) end
self.subclasses[subclass] = true self.subclasses[subclass] = true
self:subclassed(subclass) self:subclassed(subclass)