Skip to content

Instantly share code, notes, and snippets.

@kurapica
Last active June 28, 2021 14:07
Show Gist options
  • Save kurapica/76bbe39835ffc9aac9ac09287c7981ea to your computer and use it in GitHub Desktop.
Save kurapica/76bbe39835ffc9aac9ac09287c7981ea to your computer and use it in GitHub Desktop.
PLoop-Switcher
require "PLoop" (function(_ENV)
__Sealed__()
struct "Case" (function(_ENV)
import "System.Text"
export { unpack = unpack or table.unpack }
member "vars" { type = Variables, require = true }
member "func" { type = Callable, require = true }
-- Auto gen
member "min" { type = Number }
member "max" { type = Number }
member "validate" { type = Function }
member "process" { type = Function }
_ValTemplate = TemplateString[[
return function(
@for i = 1, count do
var@i @(i < count and "," or "")
@end
)
return function(
@for i = 1, count do
arg@i @(i < count and "," or "")
@end
)
local ret, msg
@for i = 1, count do
local var = var@i
if arg@i ~= null then
ret, msg = var.validate(var.type, arg@i, true)
if msg then return false end
elseif not var.optional then
return false
end
@end
return true
end
end
]]
_ValVargsTemplate = TemplateString[[
return function(
@for i = 1, count do
var@i @(i < count and "," or "")
@end
)
return function(
@for i = 1, count - 1 do
arg@i,
@end
...
)
local ret, msg
@for i = 1, count - 1 do
local var = var@i
if arg@i ~= null then
ret, msg = var.validate(var.type, arg@i, true)
if msg then return false end
elseif not var.optional then
return false
end
@end
local var = var@count
for i = 1, select("#", ...) do
local val = select(i, ...)
if val ~= null then
ret, msg = var.validate(var.type, val, true)
if msg then return false end
elseif i < var.mincount then
return false
end
end
return true
end
end
]]
_PassTemplate = TemplateString[[
return function(
@for i = 1, count do
var@i @(i < count and "," or "")
@end
)
return function(
@for i = 1, count do
arg@i @(i < count and "," or "")
@end
)
@for i = 1, count do
local var = var@i
if arg@i ~= null then
if not var.immutable then
arg@i = var.validate(var.type, arg@i)
end
else
arg@i = var.default
end
@end
return
@for i = 1, count do
arg@i @(i < count and "," or "")
@end
end
end
]]
_PassVargsTemplate = TemplateString[[
return function(
@for i = 1, count do
var@i @(i < count and "," or "")
@end
)
return function(
@for i = 1, count - 1 do
arg@i,
@end
...
)
@for i = 1, count - 1 do
local var = var@i
if arg@i ~= null then
if not var.immutable then
arg@i = var.validate(var.type, arg@i)
end
else
arg@i = var.default
end
@end
local var = var@count
if var.immutable then
return
@for i = 1, count - 1 do
arg@i,
@end
...
else
local rets = { ... }
for i, v in ipairs(rets) do
if v ~= null then
v = var.validate(var.type, v)
end
rets[i] = v
end
return
@for i = 1, count - 1 do
arg@i,
@end
unpack(rets)
end
end
end
]]
_AutoValidGen = setmetatable( { [0] = function() return true end }, {
__index = function(self, count)
local func = Toolset.loadsnippet(_ValTemplate{ count = count }, "Case_Val_" .. count, _ENV)()
rawset(self, count, func)
return func
end
})
_AutoValidVargGen = setmetatable({}, {
__index = function(self, count)
local func = Toolset.loadsnippet(_ValVargsTemplate{ count = count }, "Case_VargsVal_" .. count, _ENV)()
rawset(self, count, func)
return func
end
})
_AutoPassGen = setmetatable( { [0] = function() return end }, {
__index = function(self, count)
local func = Toolset.loadsnippet(_PassTemplate{ count = count }, "Case_Pass_" .. count, _ENV)()
rawset(self, count, func)
return func
end
})
_AutoPassVargGen = setmetatable({}, {
__index = function(self, count)
local func = Toolset.loadsnippet(_PassVargsTemplate{ count = count }, "Case_VargsPass_" .. count, _ENV)()
rawset(self, count, func)
return func
end
})
function __init(self)
local len = #self.vars
local min
local max = len
local immutable = true
local isvaragrs = false
for i = 1, len do
local var = self.vars[i]
if var.optional then
min = min or i - 1
end
if var.varargs then
isvargs = true
max = 255
if not var.mincount or var.mincount == 0 then
min = min or i - 1
else
min = i + var.mincount - 1
end
end
if not var.immutable then immutable = false end
end
self.min = min or len
self.max = max
self.validate = (isvaragrs and _AutoValidVargGen or _AutoValidGen)[len](unpack(self.vars))
if immutable then
self.process= self.func
else
local pass = (isvaragrs and _AutoPassVargGen or _AutoPassGen)[len](unpack(self.vars))
local func = self.func
self.process= function(...) return func(pass(...)) end
end
end
end)
__Sealed__()
class "Switch" (function(_ENV)
__Arguments__{ Case * 1 }
function __new(cls, ...)
return { ... }, true
end
function __ctor(self)
local count = #self
end
function __call(self, ...)
local count = select("#", ...)
for i = 1, #self do
local case = self[i]
if case.min <= count and count <= case.max then
if case.validate(...) then
return case.process(...)
end
end
end
end
end)
switcher = Switch(
Case (
{ Number/0 },
function (num) print("Age", num) end
),
Case (
{ String },
"x => print('Name', x)"
)
)
switcher(3)
switcher("Ann")
switcher()
end)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment