Last active
April 17, 2016 01:15
-
-
Save bmwalters/065c57e4f3d5b60b607479b30748debd to your computer and use it in GitHub Desktop.
Lua SuperFuncs!
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
require("superfuncs") | |
-- example_variables | |
local function has_variables() | |
self.call = self.call + 1 | |
print("congratulations! you are has_variables caller number", self.call) | |
end | |
has_variables = f(has_variables) | |
has_variables.call = 0 | |
-- example_typecheck | |
local function requires_string(str) | |
print("we have a string!", str) | |
end | |
requires_string = f(requires_string, {"string"}) | |
-- example_overloads | |
local function printit_string(str) | |
print("str", str) | |
end | |
local function printit_number(num) | |
print("num", num) | |
end | |
local function printit_anything(any) | |
print("any", any) | |
end | |
printit = f(printit_string, {"string"}) + f(printit_number, {"number"}) + f(printit_anything, {"any"}) | |
has_variables() -- congratulations! you are has_variables caller number 1 | |
has_variables() -- congratulations! you are has_variables caller number 2 | |
has_variables.call = 999 | |
has_variables() -- congratulations! you are has_variables caller number 1000 | |
print(pcall(requires_string, 5)) -- false bad argument #1 to <function> (string expected, got number) | |
requires_string("hi") -- we have a string! hi | |
printit("hey") -- str hey | |
printit(53) -- num 53 | |
printit({}) -- any table: xxxxxxxx |
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
local FUNC = {} | |
-- calling; type checking, overloading | |
function FUNC:__call(...) | |
local args = {...} | |
local types = {} | |
if self.expected_types or (self.overloads and #self.overloads > 0) then | |
for i, arg in pairs(args) do | |
types[i] = type(arg) | |
end | |
end | |
-- first check all our overloads | |
local called = false | |
if self.overloads and #self.overloads > 0 then | |
for _, func in pairs(self.overloads) do | |
if not func.expected_types then error("Function overload without expected type information!") return end | |
if #types ~= #func.expected_types then goto continue_overloads end | |
for i, typ in ipairs(func.expected_types) do -- todo: prioritize funcs with less vagueness (less any) | |
if not (types[i] == typ or typ == "any") then goto continue_overloads end | |
end | |
func(table.unpack(args)) | |
called = true | |
break -- return | |
::continue_overloads:: | |
end | |
end | |
if called then return end | |
-- then check for our type requirements | |
if self.expected_types then | |
for i, expected_type in ipairs(self.expected_types) do | |
local provided_type = types[i] | |
if not (provided_type == expected_type or expected_type == "any") then | |
error("bad argument #" .. tostring(i) .. " to " .. self.fname .. " (" .. expected_type .. " expected, got " .. provided_type .. ")", 2) -- todo: expect multiple types thanks to overloads | |
end | |
end | |
end | |
-- then call ourselves | |
local old = _G.self | |
_G.self = self -- self.f | |
self.f(table.unpack(args)) | |
_G.self = old | |
end | |
-- overloading | |
function FUNC:__add(b) | |
if getmetatable(b) == FUNC then | |
self.overloads = self.overloads or {} | |
self.overloads[#self.overloads + 1] = b | |
return self | |
end | |
error("attempt to perform arithmetic on a func value", 2) | |
end | |
-- data storage | |
local function_data = setmetatable({}, {__mode = "k"}) | |
function FUNC:__newindex(k, v) | |
function_data[self] = function_data[self] or {} | |
function_data[self][k] = v | |
end | |
function FUNC:__index(k) | |
if FUNC[k] then return FUNC[k] end | |
if not function_data[self] then return nil end | |
return function_data[self][k] | |
end | |
-- initialization | |
function FUNC:init(f, types) | |
self.f = f | |
self.fname = "<function>" -- todo | |
self.expected_types = types | |
end | |
function f(...) | |
local o = setmetatable({}, FUNC) | |
o:init(...) | |
return o | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment