Created
November 24, 2021 08:24
-
-
Save snightshade/eec8573d78c80fb5a0d858e619f5c812 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
classes.lua | |
version 1.1.1 | |
changelog: | |
+ 1.1.0: getters and setters | |
+ 1.1.1: made errors bubble up properly because yeah | |
"Rin, what the actual fuck" | |
(c) 2021 rin/luna bitch studies incorporated | |
]] | |
local _classes = {} | |
local _supers = {} | |
local _properties = {} | |
local forbidden = { | |
"__new" | |
} | |
local function contains(tb,v)for _,l in pairs(tb)do if l==v then return true end end return false end | |
local function build(t, ignore, custforbidden) | |
local o = {} | |
if not custforbidden then | |
custforbidden = forbidden | |
end | |
for i, j in pairs(t) do | |
if not ignore and contains(forbidden,i) then goto please_5_5_add_fucking_continue_i_beg_you end | |
if i == "__THIS_IS_A_PROPERTY_ACCESSOR__" then | |
return nil -- Don't. | |
end | |
if type(j) == "table" then | |
local rv = build(j) | |
o[i] = rv | |
else | |
o[i] = j | |
end | |
local mt = getmetatable(o[i]) | |
if mt ~= nil and type(o[i]) == "table" then | |
setmetatable(o[i], mt) | |
end | |
::please_5_5_add_fucking_continue_i_beg_you:: | |
end | |
return o | |
end | |
local function _construct(n, args) | |
if _classes[n] == nil then | |
error("wtf") | |
end | |
local cls = _classes[n] | |
local mem = build(cls.definition) | |
if _supers[n] then | |
if not cls.ctor then | |
-- Call the constructor | |
_supers[n](mem, table.unpack(args)) | |
else | |
mem.super = _supers[n] | |
end | |
end | |
if cls.ctor then | |
cls.ctor(mem, table.unpack(args)) | |
mem.super = nil -- Destroy it | |
end | |
return mem | |
end | |
local function _extends(og, new, tb) | |
local n = build(_classes[og].definition, true, {}) | |
if _classes[og].ctor and tb.__new then | |
_supers[new] = _classes[og].ctor | |
n.__new = tb.__new | |
end | |
if _classes[og].static then | |
local newstatics = build(_classes[og].static, true) | |
for a, b in pairs(_classes[new].static or {}) do | |
newstatics[a] = b | |
end | |
_classes[new].static = newstatics | |
end | |
for i, j in pairs(tb) do | |
n[i] = j | |
end | |
class(new)(n) | |
end | |
local _current_class = nil | |
function static(the) | |
if not _classes[_current_class] then | |
_classes[_current_class] = {} | |
end | |
_classes[_current_class].static = the | |
end | |
function property(tb) | |
if not tb.get and not tb.set then | |
error("cannot define empty property") | |
end | |
local ret = { | |
__THIS_IS_A_PROPERTY_ACCESSOR__ = "don't touch this" | |
} | |
if tb.get then | |
ret.get = tb.get | |
end | |
if tb.set then | |
ret.set = tb.set | |
end | |
return ret | |
end | |
function class(name) | |
-- lord | |
local the = {} | |
_current_class = name | |
local theCall = function(_, theTable) | |
if not _classes[name] then | |
_classes[name] = {} | |
end | |
_classes[name].definition = build(theTable, false, {"__static"}) | |
_classes[name].ctor = theTable.__new | |
_properties[name] = {} | |
for a, b in pairs(theTable) do | |
if type(b) == "table" and b.__THIS_IS_A_PROPERTY_ACCESSOR__ then | |
-- It is in fact a property accessor | |
_properties[name][a] = b | |
end | |
end | |
local obj = {} | |
setmetatable(obj, { | |
__call = function(self, ...) | |
local c = _construct(name, {...}) | |
setmetatable(c, { | |
__index = function(self, key) | |
if _properties[name][key] then | |
if not _properties[name][key].get then | |
error("attempted to read a property '"..key.."' with no getter defined", 2) | |
end | |
return _properties[name][key].get(self) | |
end | |
return rawget(self, key) | |
end, | |
__newindex = function(self, key, value) | |
if _properties[name][key] then | |
if not _properties[name][key].set then | |
error("attempted to write to a property '"..key.."' with no setter defined", 2) | |
end | |
return _properties[name][key].set(self, value) | |
end | |
rawset(self, key, value) | |
end | |
}) | |
return c | |
end, | |
__index = function(self, key) | |
if not _classes[name].static then | |
-- shit fuck uhhh | |
return nil | |
end | |
return _classes[name].static[key] | |
end | |
}) | |
_G[name] = obj | |
end | |
the.extends = function(self, og) | |
return function(t) | |
_extends(og, name, t) | |
end | |
end | |
setmetatable(the, { | |
__call = theCall | |
}) | |
return the | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment