Skip to content

Instantly share code, notes, and snippets.

@tilkinsc
Created May 12, 2022 01:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tilkinsc/c2a64044adf8f23a030939b9e3272ca1 to your computer and use it in GitHub Desktop.
Save tilkinsc/c2a64044adf8f23a030939b9e3272ca1 to your computer and use it in GitHub Desktop.
Function Environment go boom
local class = {}
-- Derived from: http://lua-users.org/wiki/CopyTable
-- Copies a table
local shallowcopy = function(o)
local c = {}
if (type(o) ~= "table")then
c = o
return c
end
for i, v in pairs(o)do
c[i] = v
end
return c
end
-- Deletes class out of function env, calling if not specifying
local remove = function(lst, env)
if(not env)then
getfenv(2)[lst] = nil
return
end
env[lst] = nil
end
-- Deletes a class, calls its deconstructor using meta's Name for the class
local delete = function(data)
if(data["_"..data.meta.Name])then
data["_"..data.meta.Name]()
end
data = nil
end
-- Makes a class super to a base
local extend = function(base, super)
base.super = super
end
setmetatable(class, {
__call = function(self, str)
return function(tab)
assert(type(str) == "string", "Invalid parameters specified, expected 'string' got '" .. type(str) .."'")
assert(type(tab) == "table", "No or an incorrect body defined for class " .. str)
if(not tab.env)then
tab.env = getfenv(2)
end
tab.env["remove"] = remove
tab.env["delete"] = delete
tab.env["extend"] = extend
tab.env[str] = {
new = function(...)
local this = {
[str] = tab[str];
public = shallowcopy(tab.public);
meta = {Name=str};
}
local proxy = newproxy(true)
local private = shallowcopy(tab.private);
local list = {}
local deconst_name = "_"..str
local this_deconst = this[deconst_name]
local tab_deconst = tab[deconst_name]
local const_name = str
local this_const = this[const_name]
local indx_tab = {__index = getfenv(2)}
local list_meta = setmetatable(list, {__index = getfenv()})
local index_meta = {
__index = function(a, b)
if(b == "meta")then
return this.meta
end
if(b == const_name)then
return this_const
end
if(b == deconst_name)then
return this_deconst
end
if(this.public[b])then
return list[b]
end
if(private.super)then
if(private.super[b])then
return private.super[b]
end
end
end;
__newindex = function(a, b, c)
this.public[b] = c
end;
}
local self_meta = {
__index = function(a,b)
if(b == "meta")then
return this.meta
end
return list[b]
end;
__newindex = function(a,b,c)
if(list[b])then
list[b] = c
return
end
error("Attempt to create a new variable in global space")
end;
}
-- Setup self indexing
list.self = newproxy(true)
for i, v in pairs(self_meta)do
getmetatable(list.self)[i] = v
end
-- Setup main proxy indexing
for i, v in pairs(index_meta)do
getmetatable(proxy)[i] = v
end
-- Add deconstructor
if(tab_deconst)then
this_deconst = tab_deconst
end
-- Feed references into the function space
for i, v in pairs(this.public)do
list[i] = v
end
for i, v in pairs(private)do
list[i] = v
end
-- For all functions, apply feed references to function space
for i, v in pairs(list)do
if(type(v) == "function")then
setfenv(v, setmetatable(list, indx_tab))
end
end
-- Apply feed references to constructor, and if has, deconstructor function space
if(this_const)then
setfenv(this_const, list_meta)
end
if(this_deconst)then
setfenv(this_deconst, list_meta)
end
-- If has a super class, setup the super() constructor
if(tab.env[const_name].super)then
private.super = function(...)
private.super = tab.env[const_name].super.new(...)
end
end
-- Execute constructor, if have
if(this_const)then
this_const(...)
end
return proxy
end;
}
end
end;
})
return class
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment