forked from Moln1kas/CCode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclass.lua
More file actions
201 lines (169 loc) · 5.98 KB
/
class.lua
File metadata and controls
201 lines (169 loc) · 5.98 KB
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
local classes = {}
local currentClassName
local workingField
local nextClassIsLocal = false
local nextFieldDecorators = {}
function table.copy(t)
local t2 = {};
for k,v in pairs(t) do
if type(v) == "table" then
t2[k] = table.copy(v)
else
t2[k] = v
end
end
return t2
end
local function isNameUniqueInCurrentClass(name)
for _, field in ipairs(classes[currentClassName].fields) do
if field.name == name then return false end
end
return true
end
local function createNewEmptyField(scope, name)
if not isNameUniqueInCurrentClass(name) then return error('"' ..name .. '" field already exists in class ' .. currentClassName) end
classes[currentClassName].fields[#classes[currentClassName].fields + 1] = {
name = name,
type = scope,
value = nil
}
workingField = #classes[currentClassName].fields
end
local function checkAndAddFieldToStatics(name, value)
if classes[currentClassName].fields[workingField].type == "static" then
classes[currentClassName].statics[name] = value
end
end
local function safeCallMethodWithContext(method, decorators, this, privateThis, ...)
local currentContext = _G.this ~= nil and "inside" or "outside"
_G.pub = this
_G.this = privateThis
for _, decorator in ipairs(decorators or {}) do
decorator()
end
local returned = method(...)
if currentContext == "outside" then
_G.pub = nil
_G.this = nil
end
return returned
end
function localClass(name)
nextClassIsLocal = true
return class(name)
end
function class(name)
classes[name] = {
fields = {},
statics = {},
onConstructor = function() end
}
currentClassName = name
local mt = {
__call = function(self, ...)
local newClass = {}
local privateNewClass = {}
for i = 1, #classes[name].fields do
local currentField = table.copy(classes[name].fields[i])
if currentField.type == "public" then
if type(currentField.value) == "function" then
newClass[currentField.name] = function(...)
return safeCallMethodWithContext(currentField.value, currentField.decorators, newClass, privateNewClass, ...)
end
else
newClass[currentField.name] = currentField.value
end
end
if currentField.type == "private" then
if type(currentField.value) == "function" then
privateNewClass[currentField.name] = function(...)
return safeCallMethodWithContext(currentField.value, newClass, privateNewClass, ...)
end
else
privateNewClass[currentField.name] = currentField.value
end
end
end
safeCallMethodWithContext(classes[name].onConstructor, {}, newClass, privateNewClass, ...)
return newClass
end
}
local thisClass = classes[name].statics
setmetatable(thisClass, mt)
if nextClassIsLocal then
nextClassIsLocal = false
return thisClass
end
_G[name] = thisClass
end
function extends(parentClassName)
local parentClass = classes[parentClassName]
if parentClass == nil then
return error("Class " .. parentClassName .. " is undefined")
end
for k, v in pairs(table.copy(parentClass.fields)) do
classes[currentClassName].fields[k] = {
name = v.name,
value = v.value,
type = "public"
}
end
classes[currentClassName].parent = parentClass
end
function super(...)
classes[currentClassName].parent.onConstructor(...)
end
function override(fieldName)
if isNameUniqueInCurrentClass(fieldName) then return error("You can't override of undefined field " .. fieldName) end
for i, field in ipairs(classes[currentClassName].fields) do
if field.name == fieldName then
field.value = nil
workingField = i
end
end
end
function private(fieldName)
createNewEmptyField("private", fieldName)
end
function public(fieldName)
createNewEmptyField("public", fieldName)
end
function static(fieldName)
createNewEmptyField("static", fieldName)
end
function Decorators(decoratorList)
for _, v in ipairs(decoratorList) do
nextFieldDecorators[#nextFieldDecorators + 1] = v
end
end
function method(methodName)
if workingField ~= nil then
if not isNameUniqueInCurrentClass(methodName) then return error('"' .. methodName .. '" field already exists in class ' .. currentClassName) end
classes[currentClassName].fields[workingField].name = methodName
classes[currentClassName].fields[workingField].value = function() end
checkAndAddFieldToStatics(classes[currentClassName].fields[workingField].name, methodName)
else
public()
method(methodName)
end
end
function define(value)
if workingField == nil then return error("You can't set value of undefined field. At class " .. currentClassName) end
classes[currentClassName].fields[workingField].value = value
checkAndAddFieldToStatics(classes[currentClassName].fields[workingField].name, value)
workingField = nil
end
function undefined()
workingField = nil
end
function callback(callbackFn)
if not workingField then return error("You can't set callback function to undefined method. At class " .. currentClassName) end
classes[currentClassName].fields[workingField].value = callbackFn
classes[currentClassName].fields[workingField].decorators = nextFieldDecorators
checkAndAddFieldToStatics(classes[currentClassName].fields[workingField].name, callbackFn)
nextFieldDecorators = {}
workingField = nil
end
function constructor(callbackFn)
classes[currentClassName].onConstructor = callbackFn
end