Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- function assert(value, message, throwback)
- throwback = throwback == 0 and 0 or throwback and (throwback + 1) or 2
- if not value then
- error(message, throwback)
- end
- return value
- end
- -- Validates a value against a given datatype
- -- Multiple datatypes separated by pipe "|" supported '
- -- Not nil supported via "!nil" datatype
- function validate( name, datatype, value, throwback )
- throwback = throwback == 0 and 0 or throwback and (throwback + 1) or 2
- local pass = false
- local expected = nil
- if datatype == "!nil" then
- expected = "not nil"
- pass = value ~= nil
- else
- for subtype in datatype:gmatch("[^|]+") do
- expected = expected and ( expected.." or "..datatype ) or datatype
- if type( value ) == datatype then
- pass = true
- end
- end
- end
- return assert( pass, "("..name..") "..expected.." expected, got "..type(value), throwback )
- end
- local metamethods = {
- __mode = true,
- __call = true,
- __tostring = true,
- __gc = true,
- __unm = true,
- __add = true,
- __sub = true,
- __mul = true,
- __dif = true,
- __pow = true,
- __concat = true,
- __eq = true,
- __lt = true,
- __le = true
- }
- local function setMetamethod( meta, value, locked, throwback )
- throwback = throwback + 1
- validate( "metamethod", "table" , value , throwback )
- validate( "name" , "string" , value[1], throwback )
- assert ( metamethods[value[1]] ~= nil,
- "Metamethod not supported: "..value[1], throwback )
- validate( "function" , "function", value[2], throwback )
- meta[value[1]] = value[2]
- end
- local function validateInterface( interfaces, key, value, locked, throwback )
- throwback = throwback + 1
- local style = key:sub(5):lower()
- assert( not locked, "Cannot add new "..style.." to a locked class.", throwback )
- validate( style, "table" , value, throwback )
- validate( style.." name", "string", value[1], throwback )
- assert( interfaces[value[1]] == nil or not interfaces[value[1]].locked,
- "Cannot override locked "..style,
- throwback )
- assert( value[1] ~= "_index" or style == "property",
- "Reserved interface '_index' must be a property",
- throwback )
- end
- local function setMember( interfaces, key, value, locked, throwback )
- throwback = throwback + 1
- validateInterface( interfaces, key, value, locked, throwback )
- validate( "member value", "!nil", value[2], throwback )
- interfaces[value[1]] = { style = "member",
- value = value[2],
- type = type(value[2]),
- locked = value.locked }
- end
- local function setMethod( interfaces, key, value, locked, throwback )
- throwback = throwback + 1
- validateInterface( interfaces, key, value, locked, throwback )
- validate( "method function", "function", value[2], throwback)
- interfaces[value[1]] = { style = "method",
- get = (value.self == nil) and value[2] or
- function(...) return value[2](value.self, ...) end,
- locked = value.locked }
- end
- local function setProperty( interfaces, key, value, locked, throwback )
- throwback = throwback + 1
- validateInterface( interfaces, key, value, locked, throwback )
- if value.get == nil then
- validate( "property set with no get", "function", value.set, throwback )
- end
- assert( value.self == nil or
- value.get == nil or
- type(value.get) == "function",
- "Implicit properties cannot reference a self object",
- throwback )
- if value.set ~= nil then
- validate( "property set", "function", value.set, throwback )
- end
- interfaces[value[1]] = { style = "property",
- type = value.type,
- set = value.set,
- get = value.get,
- locked = value.locked }
- if value.self ~= nil then
- if value.get ~= nil then
- interfaces[value[1]].get = function(...) return value.get(value.self, ...) end
- end
- if value.set ~= nil then
- interfaces[value[1]].set = function(...) return value.set(value.self, ...) end
- end
- end
- end
- local function setIndex( interfaces, key, value, locked, throwback )
- throwback = throwback + 1
- if interfaces._index == nil then return true end
- assert( interfaces._index.set ~= nil, "Numeric keys are read-only", throwback )
- if interfaces._index.type ~= nil then
- validate( "index", interfaces._index.type, value, throwback )
- end
- interfaces._index.set(key, value)
- return false
- end
- -- Returns true if ok to rawset new table item
- local function set(interfaces, key, value, locked, meta)
- local throwback = 3
- if key == "_newMetamethod" then
- setMetamethod( meta, value, locked, throwback )
- return false
- elseif key == "_newMember" then
- setMember( interfaces, key, value, locked, throwback )
- return false
- elseif key == "_newMethod" then
- setMethod( interfaces, key, value, locked, throwback )
- return false
- elseif key == "_newProperty" then
- setProperty( interfaces, key, value, locked, throwback )
- return false
- elseif type(key) == "number" then
- return setIndex( interfaces, key, value, locked, throwback )
- end
- interface = interfaces[key]
- if interface == nil then
- assert( not locked, "Cannot add to a locked class", throwback )
- return true
- end
- if interface.style == "member" then
- validate( key, interface.type, value, throwback )
- interface.value = value
- return false
- end
- assert( interface.style ~= "method",
- "Cannot write to a defined method",
- throwback )
- assert( interface.set ~= nil,
- "Cannot write to a read-only property",
- throwback )
- if interface.style == "property" and interface.type ~= nil then
- validate( key, interface.type, value, throwback )
- end
- interface.set(value, key)
- return false
- end
- local function get(interfaces, key)
- local throwback = 3
- local interface = interfaces[key]
- if interface ~= nil then
- if interface.style == "member" then
- return interface.value
- end
- assert( interface.get ~= nil,
- "Cannot read from a write-only property",
- throwback )
- if interface.style == "property" and type(interface.get) == "function" then
- if interface.self == nil then
- return interface.get(key)
- end
- return interface.get(interface.self, key)
- end
- return interface.get
- end
- if type(key) == "number" then
- if interfaces._index == nil then return nil end
- assert( interfaces._index.get ~= nil,
- "Numeric keys are write-only",
- throwback )
- return interfaces._index.get(key)
- end
- end
- local function interfaceList(interfaces)
- local list = {}
- for k,v in pairs(interfaces) do
- table.insert(list, string.format("%s: %s%s",v.style,k,v.locked and " (locked)" or ""))
- end
- return list
- end
- function new()
- local _locked = false
- local _interfaces = { }
- local self = {}
- local function _lock()
- _locked = true
- end
- self.getMembers = function()
- local ret = {}
- for k,v in pairs(_members) do
- table.insert(ret, string.format(" Name:%s Interface:%s Locked:%s",k,v.style,tostring(v.locked)))
- end
- return ret
- end
- meta = {
- __index = function(_, k, v)
- return get(_interfaces, k, v, _locked) end,
- __newindex = function(_, k, v)
- if set(_interfaces, k, v, _locked, meta) then
- rawset(self, k, v)
- end
- end,
- __metatable = {}
- }
- setmetatable(self, meta)
- self._newProperty = { "_interfaces",
- get = interfaceList,
- self = _interfaces,
- locked = true }
- self._newMethod = { "_lock",
- _lock,
- locked = true }
- self._newProperty = { "_locked",
- get = function() return _locked end,
- locked = true }
- self._newMetamethod = { "__tostring",
- function() return "class" end }
- return self
- end
Advertisement
Add Comment
Please, Sign In to add comment