refactoring

This commit is contained in:
Manuel Simon Hirsig
2016-08-26 19:00:54 +02:00
parent e3565015ad
commit 270fee6575
+69 -75
View File
@@ -1,7 +1,7 @@
if module then return end
local type, setmetatable, setfenv, unpack, next, pcall, _G = type, setmetatable, setfenv, unpack, next, pcall, getfenv(0)
local start_declaration, declaration, env_mt, interface_mt
local typeof, setmetatable, setfenv, unpack, next, pcall, _G = type, setmetatable, setfenv, unpack, next, pcall, getfenv(0)
local PUBLIC, PRIVATE = 1, 2
local INDEX, NEWINDEX, CALL = 1, 2, 3
local function error(msg, ...) return _G.error(format(msg or '', unpack(arg))..'\n'..debugstack(), 0) end
@@ -10,81 +10,67 @@ local function declaration_error() error 'Invalid declaration.' end
local function collision_error(key) error('"%s" already exists.', key) end
local function nop() end
local function id(_) return _ end
local function const(_) return function() return _ end end
--local function vararg_id(...) return unpack(arg) end
--local function vararg_const(...) return function() return unpack(arg) end end
local _state, _public = {}, {[nop]=true}
local function id(v) return v end
local function const(v) return function() return v end end
local c
do
local function declare(self, public, type, name, value)
if _G.type(value) ~= 'function' and (not type or declaration_error()) then value, type = const(value), INDEX end
if self[type][name] then declaration_error() end
self[type][name], _public[value] = value, public
if self[CALL][name] and self[INDEX][name] then declaration_error() end
end
local mt = {__metatable=false, index=error, newindex=error}
function c() return setmetatable({}, mt) end
end
declaration = nop
local _state = {}
local env_mt, start_declaration
do
local intercept, declare, extract
local state, access, type, name
local declaration = nop
function start_declaration(self, access, type)
if declaration ~= nop then declaration_error() end
declaration, state, access, type, name = intercept, self, access, type, nil
end
do
local function extract(v)
local call, get, set
call, get, set, v.call, v.get, v.set = v.call, v.get, v.set, nil, nil, nil
if next(v) then error() end
return call, get, set
end
local PUBLIC = {public=true, private=false}
local PREFIX_TYPE = {method=CALL, getter=INDEX, setter=NEWINDEX}
local SUFFIX_TYPE = {call=CALL, get=INDEX, set=NEWINDEX}
local state, public, type, name
local function intercept(self, event, key, value)
local ACCESS = {public=PUBLIC, private=PRIVATE}
local TYPE = {call=CALL, get=INDEX, set=NEWINDEX}
function intercept(self, event, key, value)
if self ~= state then declaration_error() end
if event == INDEX and (not name or declaration_error()) then
if PUBLIC[key] then
public = (public ~= nil and declaration_error()) or PUBLIC[key]
elseif PREFIX_TYPE[key] then
type = (type and declaration_error()) or PREFIX_TYPE[key]
elseif not type or declaration_error() then
if ACCESS[key] and (not access or declaration_error()) then
access = ACCESS[key]
else
name = key
end
return true
elseif event == NEWINDEX then
if name then
type = SUFFIX_TYPE[key] or declaration_error()
key = name
type = TYPE[key] or declaration_error()
else
name, type = key, CALL
end
declare(self, public, type, key, value)
declare(self, access, name, {[type]=value})
declaration = nop
return true
elseif event == CALL then
if name then
local success, call, get, set = pcall(extract, value)
if not success then declaration_error() end
if call then declare(self, public, type, name, call) end
if get then declare(self, public, type, name, get) end
if set then declare(self, public, type, name, set) end
declare(self, access, name, {[CALL]=call, [INDEX]=get, [NEWINDEX]=set})
else
self.access, self.type = public, type
self.access, self.type = access, type
end
declaration = nop
return true
end
end
function start_declaration(self, public, type)
if declaration ~= nop then declaration_error() end
declaration, state, public, type, name = intercept, self, public, type, nil
end
end
env_mt = {__metatable=false}
function env_mt:__index(key) local state=_state[self]
if declaration(state, INDEX, key) then return self end
if state[INDEX][key] then
return state[INDEX][key]()
elseif state[CALL][key] then
return state[CALL][key]
else
return _G[key]
return state[CALL][key] or _G[key]
end
end
function env_mt:__newindex(key, value) local state=_state[self]
@@ -95,50 +81,58 @@ do
function env_mt:__call(key, value)
declaration(_state[self], CALL, key, value)
end
function declare(self, access, name, t)
self.access[name] = self.access[name] and collision_error(name) or access or self.default_access
for k, v in t do
if typeof(v) ~= 'function' then declaration_error() end
self[k][name] = v
end
end
function extract(v)
local call, get, set
call, get, set, v.call, v.get, v.set = v.call, v.get, v.set, nil, nil, nil
if next(v) or call ~= nil and get ~= nil then error() end
return call, get, set
end
end
interface_mt = {__metatable=false}
local interface_mt = {__metatable=false}
function interface_mt:__index(key) local state=_state[self]
local call = state[CALL][key]
if call and _public[call] then
return call
else
if state.access[key] == PUBLIC then
local index = state[INDEX][key]
return (_public[index] and index or nop)()
if index then return index() else return state[CALL][key] end
end
end
function interface_mt:__newindex(key, value) local state=_state[self]
local f = state[NEWINDEX][key] or state[CALL][key] or nop
if _public[f] then f(value) end
if state.access[key] == PUBLIC then (state[NEWINDEX][key] or state[CALL][key])(value) end
end
--function interface_mt:__call(key, ...) local state=_state[self]
-- -- TODO new instance
--end
function module(...)
local env, interface = setmetatable({}, env_mt), setmetatable({}, interface_mt)
local state; state = {
[CALL]={error=error, nop=nop, id=id, const=const},
[INDEX]={
_G = const(_G),
M = const(env),
I = const(interface),
private = function() start_declaration(state, false); return env end,
public = function() start_declaration(state, true); return env end,
accessor = function() start_declaration(state, nil, INDEX); return env end,
mutator = function() start_declaration(state, nil, NEWINDEX); return env end,
},
[NEWINDEX]={},
public=false,
local state, env, interface, access, call, index, newindex
env, interface = setmetatable({}, env_mt), setmetatable({}, interface_mt)
state = {default_access=PRIVATE}
state.access = {error=PRIVATE, c=PRIVATE, nop=PRIVATE, id=PRIVATE, const=PRIVATE, _G=PRIVATE, M=PRIVATE, I=PRIVATE, access=PRIVATE, public=PRIVATE, private=PRIVATE}
state[CALL] = {error=error, nop=nop, id=id, const=const}
state[INDEX] = {
c = c,
_G = const(_G),
M = const(env),
I = const(interface),
public = function() start_declaration(state, PUBLIC); return env end,
private = function() start_declaration(state, PRIVATE); return env end,
}
state[NEWINDEX] = {access=function(access) state.default_access = access end}
for i=1,arg.n do
local module = state[arg[i] or import_error()] or import_error()
local call, index, newindex = state[CALL], state[INDEX], state[NEWINDEX]
for _, type in {CALL, INDEX, NEWINDEX} do
for k, f in module[type] do
if _public[f] and (not (call[k] or index[k] or newindex[k]) or import_error()) then
state[type] = f
end
local module = _state[arg[i] or import_error()] or import_error()
local import_call, import_index, import_newindex = module[CALL], module[INDEX], module[NEWINDEX]
for k, v in module.access do
if v == PUBLIC and (not access[k] or import_error()) then
call[k], index[k], newindex[k] = import_call[k], import_index[k], import_newindex[k]
access[k] = PRIVATE
end
end
end