bigtwisty

btClass

Sep 4th, 2013
165
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 8.13 KB | None | 0 0
  1. function assert(value, message, throwback)
  2.   throwback = throwback == 0 and 0 or throwback and (throwback + 1) or 2
  3.   if not value then
  4.     error(message, throwback)
  5.   end
  6.   return value
  7. end
  8.  
  9. -- Validates a value against a given datatype
  10. -- Multiple datatypes separated by pipe "|" supported '
  11. -- Not nil supported via "!nil" datatype
  12. function validate( name, datatype, value, throwback )
  13.   throwback = throwback == 0 and 0 or throwback and (throwback + 1) or 2
  14.   local pass = false
  15.   local expected = nil
  16.   if datatype == "!nil" then
  17.     expected = "not nil"
  18.     pass = value ~= nil
  19.   else
  20.     for subtype in datatype:gmatch("[^|]+") do
  21.       expected = expected and ( expected.." or "..datatype ) or datatype
  22.       if type( value ) == datatype then
  23.         pass = true
  24.       end
  25.     end
  26.   end
  27.   return assert( pass, "("..name..") "..expected.." expected, got "..type(value), throwback )
  28. end
  29.  
  30. local metamethods = {
  31.   __mode = true,
  32.   __call = true,
  33.   __tostring = true,
  34.   __gc = true,
  35.   __unm = true,
  36.   __add = true,
  37.   __sub = true,
  38.   __mul = true,
  39.   __dif = true,
  40.   __pow = true,
  41.   __concat = true,
  42.   __eq = true,
  43.   __lt = true,
  44.   __le = true
  45. }
  46.  
  47. local function setMetamethod( meta, value, locked, throwback )
  48.   throwback = throwback + 1
  49.   validate( "metamethod", "table"   , value   , throwback )
  50.   validate( "name"      , "string"  , value[1], throwback )
  51.   assert  ( metamethods[value[1]] ~= nil,
  52.            "Metamethod not supported: "..value[1], throwback )
  53.   validate( "function"  , "function", value[2], throwback )
  54.   meta[value[1]] = value[2]
  55. end
  56.  
  57. local function validateInterface( interfaces, key, value, locked, throwback )
  58.   throwback = throwback + 1
  59.   local style = key:sub(5):lower()
  60.   assert( not locked, "Cannot add new "..style.." to a locked class.", throwback )
  61.   validate( style, "table" , value, throwback )
  62.   validate( style.." name", "string", value[1], throwback )
  63.   assert( interfaces[value[1]] == nil or not interfaces[value[1]].locked,
  64.           "Cannot override locked "..style,
  65.           throwback )
  66.   assert( value[1] ~= "_index" or style == "property",
  67.           "Reserved interface '_index' must be a property",
  68.           throwback )
  69. end
  70.  
  71. local function setMember( interfaces, key, value, locked, throwback )
  72.   throwback = throwback + 1
  73.   validateInterface( interfaces, key, value, locked, throwback )
  74.   validate( "member value", "!nil", value[2], throwback )
  75.   interfaces[value[1]] = { style  = "member",
  76.                            value  = value[2],
  77.                            type   = type(value[2]),
  78.                            locked = value.locked }
  79. end
  80.  
  81. local function setMethod( interfaces, key, value, locked, throwback )
  82.   throwback = throwback + 1
  83.   validateInterface( interfaces, key, value, locked, throwback )
  84.   validate( "method function", "function", value[2], throwback)
  85.   interfaces[value[1]] = { style  = "method",
  86.                            get    = (value.self == nil) and value[2] or
  87.                                     function(...) return value[2](value.self, ...) end,
  88.                            locked = value.locked }
  89. end
  90.  
  91. local function setProperty( interfaces, key, value, locked, throwback )
  92.   throwback = throwback + 1
  93.   validateInterface( interfaces, key, value, locked, throwback )
  94.   if value.get == nil then
  95.     validate( "property set with no get", "function", value.set, throwback )
  96.   end
  97.   assert( value.self == nil or
  98.             value.get == nil or
  99.             type(value.get) == "function",
  100.           "Implicit properties cannot reference a self object",
  101.           throwback )
  102.   if value.set ~= nil then
  103.     validate( "property set", "function", value.set, throwback )
  104.   end
  105.   interfaces[value[1]] = { style  = "property",
  106.                            type   = value.type,
  107.                            set    = value.set,
  108.                            get    = value.get,
  109.                            locked = value.locked }
  110.   if value.self ~= nil then
  111.     if value.get ~= nil then
  112.       interfaces[value[1]].get = function(...) return value.get(value.self, ...) end
  113.     end
  114.     if value.set ~= nil then
  115.       interfaces[value[1]].set = function(...) return value.set(value.self, ...) end
  116.     end
  117.   end
  118. end
  119.  
  120. local function setIndex( interfaces, key, value, locked, throwback )
  121.   throwback = throwback + 1
  122.   if interfaces._index == nil then return true end
  123.   assert( interfaces._index.set ~= nil, "Numeric keys are read-only", throwback )
  124.   if interfaces._index.type ~= nil then
  125.     validate( "index", interfaces._index.type, value, throwback )
  126.   end
  127.   interfaces._index.set(key, value)
  128.   return false
  129. end
  130.  
  131. -- Returns true if ok to rawset new table item
  132. local function set(interfaces, key, value, locked, meta)
  133.   local throwback = 3
  134.   if key == "_newMetamethod" then
  135.     setMetamethod( meta, value, locked, throwback )
  136.     return false
  137.   elseif key == "_newMember" then
  138.     setMember( interfaces, key, value, locked, throwback )
  139.     return false
  140.   elseif key == "_newMethod" then
  141.     setMethod( interfaces, key, value, locked, throwback )
  142.     return false
  143.   elseif key == "_newProperty" then
  144.     setProperty( interfaces, key, value, locked, throwback )
  145.     return false
  146.   elseif type(key) == "number" then
  147.     return setIndex( interfaces, key, value, locked, throwback )
  148.   end
  149.   interface = interfaces[key]
  150.   if interface == nil then
  151.     assert( not locked, "Cannot add to a locked class", throwback )
  152.     return true
  153.   end
  154.   if interface.style == "member" then
  155.     validate( key, interface.type, value, throwback )
  156.     interface.value = value
  157.     return false
  158.   end
  159.   assert( interface.style ~= "method",
  160.           "Cannot write to a defined method",
  161.           throwback )
  162.   assert( interface.set ~= nil,
  163.           "Cannot write to a read-only property",
  164.           throwback )
  165.   if interface.style == "property" and interface.type ~= nil then
  166.     validate( key, interface.type, value, throwback )
  167.   end
  168.   interface.set(value, key)
  169.   return false
  170. end
  171.  
  172. local function get(interfaces, key)
  173.   local throwback = 3
  174.   local interface = interfaces[key]
  175.   if interface ~= nil then
  176.     if interface.style == "member" then
  177.       return interface.value
  178.     end
  179.     assert( interface.get ~= nil,
  180.             "Cannot read from a write-only property",
  181.             throwback )
  182.     if interface.style == "property" and type(interface.get) == "function" then
  183.       if interface.self == nil then
  184.         return interface.get(key)
  185.       end
  186.       return interface.get(interface.self, key)
  187.     end
  188.     return interface.get
  189.   end
  190.   if type(key) == "number" then
  191.     if interfaces._index == nil then return nil end
  192.     assert( interfaces._index.get ~= nil,
  193.             "Numeric keys are write-only",
  194.             throwback )
  195.     return interfaces._index.get(key)
  196.   end
  197. end
  198.  
  199. local function interfaceList(interfaces)
  200.   local list = {}
  201.   for k,v in pairs(interfaces) do
  202.     table.insert(list, string.format("%s: %s%s",v.style,k,v.locked and " (locked)" or ""))
  203.   end
  204.   return list
  205. end
  206.  
  207. function new()
  208.   local _locked = false
  209.   local _interfaces = { }
  210.   local self = {}
  211.   local function _lock()
  212.     _locked = true
  213.   end
  214.   self.getMembers = function()
  215.     local ret = {}
  216.     for k,v in pairs(_members) do
  217.       table.insert(ret, string.format(" Name:%s Interface:%s Locked:%s",k,v.style,tostring(v.locked)))
  218.     end
  219.     return ret
  220.   end
  221.   meta = {
  222.     __index = function(_, k, v)
  223.       return get(_interfaces, k, v, _locked) end,
  224.     __newindex = function(_, k, v)
  225.       if set(_interfaces, k, v, _locked, meta) then
  226.         rawset(self, k, v)
  227.       end
  228.     end,
  229.     __metatable = {}
  230.   }
  231.   setmetatable(self, meta)
  232.   self._newProperty = { "_interfaces",
  233.                         get = interfaceList,
  234.                         self = _interfaces,
  235.                         locked = true }
  236.   self._newMethod   = { "_lock",
  237.                         _lock,
  238.                         locked = true }
  239.   self._newProperty = { "_locked",
  240.                         get = function() return _locked end,
  241.                         locked = true }
  242.   self._newMetamethod = { "__tostring",
  243.                           function() return "class" end }
  244.   return self
  245. end
Advertisement
Add Comment
Please, Sign In to add comment