-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathclass.lua
155 lines (144 loc) · 4.22 KB
/
class.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
-- class.lua
-- defines C++ style classes using the same behavior as luaL_register
-- all classes are stored in the LUA_REGISTRYINDEX, support single
-- inheritance, metamethod inheritance, and implicit mixin support with
-- a user-defined table.merge.
-- distributed under the MIT license
local setmetatable = setmetatable
local package = package
local type = type
local error = error
local pcall = pcall
local unpack = unpack
local newproxy = newproxy
local gsub = string.gsub
local rawget = rawget
local ipairs = ipairs
local module = module
local _G = _G
local _R = debug.getregistry()
local function new (metatable)
local object = {}
setmetatable(object, metatable)
return object
end
local function getbaseclass (metatable)
local base = metatable.__base
return package.loaded[base]
end
_G.getbaseclass = getbaseclass
local eventnames = {
"__gc",
"__add", "__sub", "__mul", "__div", "__mod",
"__pow", "__unm", "__len", "__lt", "__le",
"__concat", "__call",
"__tostring"
}
local function metamethod (metatable, eventname)
return function (...)
local event = nil
local base = getbaseclass(metatable)
while base ~= nil do
if base[eventname] then
event = base[eventname]
break
end
base = getbaseclass(base)
end
local type = type(event)
if type ~= "function" then
error("attempt to call metamethod '" .. eventname .. "' " ..
"(a " .. type .. " value)", 2)
end
local returns = {pcall(event, ...)}
if returns[1] ~= true then
error(returns[2], 2)
else
return unpack(returns, 2)
end
end
end
local function setproxy (object)
local __newproxy = newproxy(true)
local metatable = getmetatable(__newproxy)
metatable.__gc = function ()
object:__gc()
end
object.__newproxy = __newproxy
end
_G.setproxy = setproxy
local function classinit (module)
module.__index = module
module.__type = gsub(module._NAME, module._PACKAGE, "")
-- Override modinit from loadlib.c
module._M = nil
module._NAME = nil
module._PACKAGE = nil
-- Create a shortcut to name()
setmetatable(module, {
__call = function (self, ...)
-- Create an instance of this object
local object = new(self)
-- Call its constructor (function name:name ( ... ) ... end) if it
-- exists
local constructor = rawget(self, self.__type)
if constructor ~= nil then
local type = type(constructor)
if type ~= "function" then
error("attempt to call constructor '" .. name .. "' " ..
"(a " .. type .. " value)", 2)
end
constructor(object, ...)
end
-- Return the instance
return object
end
})
end
local function inherit (base)
return function (metatable)
-- Set our base class
metatable.__base = base
-- Overwrite our existing __index value with a metamethod which checks
-- table fields, metatable, and base class, in that order, per behavior
-- via the Lua 5.1 manual's illustrative code for indexing access
metatable.__index = function (table, key)
local h
-- if type(table) == "table" then
local v = rawget(metatable, key)
if v ~= nil then return v end
local baseclass = getbaseclass(metatable)
if baseclass == nil then
error("attempt to index base class '" .. base .. "' " ..
"(a nil value)", 2)
end
h = baseclass.__index
if h == nil then return nil end
-- else
-- h = getmetatable(table).__index
-- if h == nil then
-- error(...)
-- end
-- end
if type(h) == "function" then
return (h(table, key)) -- call the handler
else return h[key] -- or repeat operation on it
end
end
-- Create inheritable metamethods
for _,event in ipairs(eventnames) do
metatable[event] = metatable[event] or metamethod(metatable, event)
end
end
end
function class (modname)
local function setmodule (modname)
module(modname, classinit)
end setmodule(modname)
_R[modname] = package.loaded[modname]
-- For syntactic sugar, return a function to set inheritance
return function (base)
local metatable = package.loaded[modname]
inherit(base)(metatable)
end
end