-
Notifications
You must be signed in to change notification settings - Fork 6
/
yaci-1.2.0.lua
228 lines (173 loc) · 7.33 KB
/
yaci-1.2.0.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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
-----------------------------------------------------------------------------------
-- Yet Another Class Implementation (version 1.2)
--
-- Julien Patte [julien.patte AT gmail DOT com] - 25 Feb 2007
--
-- Inspired from code written by Kevin Baca, Sam Lie, Christian Lindig and others
-- Thanks to Damian Stewart and Frederic Thomas for their interest and comments
-----------------------------------------------------------------------------------
do -- keep local things inside
-- associations between an object an its meta-informations
-- e.g its class, its "lower" object (if any), ...
local metaObj = {}
setmetatable(metaObj, {__mode = "k"})
-----------------------------------------------------------------------------------
-- internal function 'duplicate'
-- return a shallow copy of table t
local function duplicate(t)
t2 = {}
for k,v in pairs(t) do t2[k] = v end
return t2
end
-----------------------------------------------------------------------------------
-- internal function 'newInstance'
local function newInstance(class, ...)
local function makeInstance(class, virtuals)
local inst = duplicate(virtuals)
metaObj[inst] = { obj = inst, class = class }
if class:super()~=nil then
inst.super = makeInstance(class:super(), virtuals)
metaObj[inst].super = metaObj[inst.super] -- meta-info about inst
metaObj[inst.super].lower = metaObj[inst]
else
inst.super = {}
end
setmetatable(inst, class.static)
return inst
end
local inst = makeInstance(class, metaObj[class].virtuals)
inst:init(...)
return inst
end
-----------------------------------------------------------------------------------
-- internal function 'makeVirtual'
local function makeVirtual(class, fname)
local func = class.static[fname]
if func == nil then
func = function() error("Attempt to call an undefined abstract method '"..fname.."'") end
end
metaObj[class].virtuals[fname] = func
end
-----------------------------------------------------------------------------------
-- internal function 'trycast'
-- try to cast an instance into an instance of one of its super- or subclasses
local function tryCast(class, inst)
local meta = metaObj[inst]
if meta.class==class then return inst end -- is it already the right class?
while meta~=nil do -- search lower in the hierarchy
if meta.class==class then return meta.obj end
meta = meta.lower
end
meta = metaObj[inst].super -- not found, search through the superclasses
while meta~=nil do
if meta.class==class then return meta.obj end
meta = meta.super
end
return nil -- could not execute casting
end
-----------------------------------------------------------------------------------
-- internal function 'secureCast'
-- same as trycast but raise an error in case of failure
local function secureCast(class, inst)
local casted = tryCast(class, inst)
if casted == nil then
error("Failed to cast " .. tostring(inst) .. " to a " .. class:name())
end
return casted
end
-----------------------------------------------------------------------------------
-- internal function 'classMade'
local function classMade(class, obj)
if metaObj[obj]==nil then return false end -- is this really an object?
return (tryCast(class,obj) ~= nil) -- check if that class could cast the object
end
-----------------------------------------------------------------------------------
-- internal function 'callup'
-- Function used to transfer a method call from a class to its superclass
local callup_inst
local callup_target
local function callup(inst, ...)
return callup_target(callup_inst, ...) -- call the superclass' method
end
-----------------------------------------------------------------------------------
-- internal function 'subclass'
local function inst_init_def(inst,...)
inst.super:init()
end
local function inst_newindex(inst,key,value)
if inst.super[key] ~= nil then -- First check if this field isn't already
-- defined higher in the hierarchy
inst.super[key] = value; -- Update the old value
else
rawset(inst,key,value); -- Create the field
end
end
local function subclass(baseClass, name)
if type(name)~="string" then name = "Unnamed" end
local theClass = {}
-- need to copy everything here because events can't be found through metatables
local b = baseClass.static
local inst_stuff = { __tostring=b.__tostring, __eq=b.__eq, __add=b.__add, __sub=b.__sub,
__mul=b.__mul, __div=b.__div, __mod=b.__mod, __pow=b.__pow, __unm=b.__unm,
__len=b.__len, __lt=b.__lt, __le=b.__le, __concat=b.__concat, __call=b.__call}
inst_stuff.init = inst_init_def
inst_stuff.__newindex = inst_newindex
function inst_stuff.class() return theClass end
function inst_stuff.__index(inst, key) -- Look for field 'key' in instance 'inst'
local res = inst_stuff[key] -- Is it present?
if res~=nil then return res end -- Okay, return it
res = inst.super[key] -- Is it somewhere higher in the hierarchy?
if type(res)=='function' and
res ~= callup then -- If it is a method of the superclass,
callup_inst = inst.super -- we will need to do a special forwarding
callup_target = res -- to call 'res' with the correct 'self'
return callup -- The 'callup' function will do that
end
return res
end
local class_stuff = { static = inst_stuff, made = classMade, new = newInstance,
subclass = subclass, virtual = makeVirtual, cast = secureCast, trycast = tryCast }
metaObj[theClass] = { virtuals = duplicate(metaObj[baseClass].virtuals) }
function class_stuff.name(class) return name end
function class_stuff.super(class) return baseClass end
function class_stuff.inherits(class, other)
return (baseClass==other or baseClass:inherits(other))
end
local function newmethod(class, name, meth)
inst_stuff[name] = meth;
if metaObj[class].virtuals[name]~=nil then
metaObj[class].virtuals[name] = meth
end
end
local function tos() return ("class "..name) end
setmetatable(theClass, { __newindex = newmethod, __index = class_stuff,
__tostring = tos, __call = newInstance } )
return theClass
end
-----------------------------------------------------------------------------------
-- The 'Object' class
Object = {}
local function obj_newitem() error "May not modify the class 'Object'. Subclass it instead." end
local obj_inst_stuff = {}
function obj_inst_stuff.init(inst,...) end
obj_inst_stuff.__index = obj_inst_stuff
obj_inst_stuff.__newindex = obj_newitem
function obj_inst_stuff.class() return Object end
function obj_inst_stuff.__tostring(inst) return ("a "..inst:class():name()) end
local obj_class_stuff = { static = obj_inst_stuff, made = classMade, new = newInstance,
subclass = subclass, cast = secureCast, trycast = tryCast }
function obj_class_stuff.name(class) return "Object" end
function obj_class_stuff.super(class) return nil end
function obj_class_stuff.inherits(class, other) return false end
metaObj[Object] = { virtuals={} }
local function tos() return ("class Object") end
setmetatable(Object, { __newindex = obj_newitem, __index = obj_class_stuff,
__tostring = tos, __call = newInstance } )
----------------------------------------------------------------------
-- function 'newclass'
function newclass(name, baseClass)
baseClass = baseClass or Object
return baseClass:subclass(name)
end
end -- 2 global things remain: 'Object' and 'newclass'
-- end of code