LuaWeaver

[v1.2.2] wOOP

Mar 26th, 2013
210
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 8.17 KB | None | 0 0
  1. local config=
  2. {
  3.     imply_self=true; --Remove the need for setting a self value in functions (removes the need for a colon)
  4.     self_name="self"; --What the name is for the self value
  5.    
  6.     using_userdata=true; --Use userdata to allow __gc and __len metamethods.
  7.    
  8.     strict_errors=true; --Error if 1) Value inside an object does not exist or 2) Attempt to set a value of an object where the field does not exist
  9.    
  10.     private_values=true; --Use private values
  11.     private_value_index="__"; --How to start private values
  12.    
  13.     read_only_values=true; --Use read only values
  14.     read_only_value_index="_"; --How to start read only values
  15.    
  16.     class_config_location="__settings"; --Where the config is located. Set to "class" for directly in the class.
  17.     class_config_setup= --How the config is setup.
  18.     {
  19.         new="new";
  20.         mt="mt";
  21.     };
  22. }
  23.  
  24. if common_class then
  25.     config.imply_self=false
  26.     config.using_userdata=false
  27.     config.class_config_location="class"
  28.     config.class_config_setup.new="init"
  29.     config.class_config_setup.mt=""
  30. elseif common_class==false then --don't do it, yo
  31.     return
  32. end
  33.  
  34. local classes={}
  35. local objects={}
  36.  
  37. local function locals(lev)
  38.     local variables = {}
  39.     local names={}
  40.     local idx = 1
  41.     while true do
  42.             local ln, lv = debug.getlocal(lev, idx)
  43.             if ln ~= nil then
  44.                 variables[idx] = lv
  45.                 names[idx]=ln
  46.             else
  47.                 break
  48.             end
  49.             idx = 1 + idx
  50.     end
  51.     return variables,names
  52. end
  53.  
  54. function remove(usd)
  55.     local lev=2
  56.     repeat
  57.         local valid=debug.getinfo(lev)
  58.         if not valid then break end
  59.         local list,names=locals(lev)
  60.         local num=0
  61.         for i,v in pairs(list) do
  62.             if rawequal(v,usd) then
  63.                 num=num+1
  64.                 debug.setlocal(lev,i,nil)
  65.             end
  66.         end
  67.         lev=lev+1
  68.     until false
  69.     usd=nil
  70.     collectgarbage()
  71. end
  72.  
  73. local function giveTabAProxy(tab,metatable,userdata) --Create a userdata representation of a table with a metatable
  74.     if common_class then return tab end
  75.     local proxy=userdata and newproxy(true) or setmetatable({},{})
  76.    
  77.     local mt=getmetatable(proxy)
  78.    
  79.     mt.__origtab=tab
  80.    
  81.     mt.__index=
  82.     function(usd,ind)
  83.         if config["private_values"] then
  84.             local start=config["private_value_index"]
  85.             if ind:sub(1,#start)==start then
  86.                 error("Attempt to index '"..ind.."' (a private value) of "..tostring(proxy)..", a wOOP object.") --Oops! Can't do that.
  87.             end
  88.         end
  89.         if config["strict_errors"] then
  90.             if not tab[ind]==nil then
  91.                 error("Attempt to index '"..ind.."' (a nil value) of "..tostring(proxy)..", a wOOP object.") --Oops! You did something you're not supposed to.
  92.             end
  93.         end
  94.         return tab[ind]
  95.     end
  96.    
  97.     mt.__newindex=
  98.     function(usd,ind,val)
  99.         if config["read_only_values"] then
  100.             local start=config["read_only_value_index"]
  101.             if ind:sub(1,#start)==start then
  102.                 error("Attempt to set '"..ind.."' (a read only value) of "..tostring(proxy)..", a wOOP object.") --Oops! Can't set read onlys (onlies?).
  103.             end
  104.         end
  105.         if config["private_values"] then
  106.             local start=config["private_value_index"]
  107.             if ind:sub(1,#start)==start then
  108.                 error("Attempt to set '"..ind.."' (a private value) of "..tostring(proxy)..", a wOOP object.") --Oops! Can't do that.
  109.             end
  110.         end
  111.         if config["strict_errors"] then
  112.             if not tab[ind]==nil then
  113.                 error("Attempt to set '"..ind.."' (a nil value) of "..tostring(proxy)..", a wOOP object.") --Oops! You did something you're not supposed to.
  114.             end
  115.         end
  116.         tab[ind]=val
  117.     end
  118.    
  119.     for method,val in pairs(metatable or {}) do
  120.         if not mt[method] then
  121.             mt[method]=val
  122.         end
  123.     end
  124.    
  125.     for method,val in pairs({__tostring=function(a) return "wOOP object : "..a.className end,__concat=function(a,b) return tostring(a)..tostring(b) end}) do
  126.         if not mt[method] then
  127.             mt[method]=val
  128.         end
  129.     end
  130.    
  131.     return proxy
  132. end
  133.  
  134. local function implySelfToFunctions(tab) --Change all functions to tables with __call metamethod set to do a little dance
  135.     for i,v in pairs(tab) do
  136.         if type(v)=="function" then
  137.             local func=v
  138.             local tabWithMt={}
  139.                    
  140.             setmetatable(tabWithMt,
  141.             {
  142.                 __call=
  143.                 function(_,...)
  144.                     if config["imply_self"] then
  145.                             local oldenv=getfenv(func)
  146.                             setfenv(func,setmetatable({[config.self_name]=tab},{__index=oldenv}))
  147.                             local args={func(...)}
  148.                             setfenv(func,oldenv)
  149.                             return unpack(args)
  150.                     else
  151.                             return func(...)
  152.                     end
  153.             end
  154.             })
  155.                    
  156.             tab[i]=tabWithMt
  157.         end
  158.     end
  159. end
  160.  
  161. local function inheritVals(to,from)
  162.     for i,v in pairs(from) do
  163.         if type(v)=="table" and to[i] then
  164.             inheritVals(to[i],v)
  165.         elseif to[i]==nil then
  166.             to[i]=v
  167.         end
  168.     end
  169. end
  170.  
  171. local function newObj(name,...)
  172.     if not classes[name] then error("Class not found : "..name) end
  173.     local userdata=config["using_userdata"]
  174.     local implySelf=config["imply_self"]
  175.     local configLoc=config["class_config_location"]
  176.     local configTab=config["class_config_setup"]
  177.     local settings=classes[name][configLoc]
  178.    
  179.     if configLoc=="class" then
  180.         settings=classes[name]
  181.     end
  182.    
  183.     local new=settings[configTab['new']]
  184.     local mt=settings[configTab['mt']] or {}
  185.    
  186.     mt.__index=classes[name]
  187.     for method,val in pairs({__tostring=function(a) return "wOOP object : "..a.className end,__concat=function(a,b) return tostring(a)..tostring(b) end}) do
  188.         if not mt[method] then
  189.             mt[method]=val
  190.         end
  191.     end
  192.     local args={...}
  193.     if not common_class then
  194.         table.remove(args,1)
  195.     end
  196.     local tab=new(unpack(args))
  197.     if not tab then tab={} end
  198.     inheritVals(tab,classes[name])
  199.     if implySelf then
  200.         implySelfToFunctions(tab)
  201.     end
  202.     local prox
  203.     prox=giveTabAProxy(tab,mt,userdata)
  204.     if not common_class then
  205.         setmetatable(tab,mt)
  206.     end
  207.     return prox
  208. end
  209.    
  210. local function realClass(tab,name,extends) --Do a short jig to remove the parentheses
  211.     local mt={}
  212.     local index={}
  213.     if extends and classes[extends] then
  214.         index=classes[extends]
  215.     elseif classes.base then
  216.         index=classes.base
  217.     end
  218.     inheritVals(tab,index)
  219.     for i,v in pairs(tab) do
  220.         print(i,v)
  221.     end
  222.    
  223.     local configLoc=config["class_config_location"]
  224.     if not configLoc=="class" and not tab[configLoc] then
  225.         tab[configLoc]={}
  226.     end
  227.    
  228.     mt.__tostring=function() return "wOOP Class "..name end
  229.     mt.__metatable=false
  230.     mt.__concat=function(a,b) return tostring(a)..tostring(b) end
  231.     mt.__call=function(...) return newObj(name,...) end
  232.     tab.className=name
  233.     if not common_class then
  234.         tab.extends=extends or "base"
  235.     else
  236.         tab.super=extends
  237.     end
  238.    
  239.     if not common_class then
  240.         setmetatable(tab,mt)
  241.         _G[name]=tab
  242.     end
  243.     classes[name]=tab
  244. end
  245.  
  246. local function class3(tab,name)
  247.     return function(arg)
  248.         realClass(arg,name,tab)
  249.     end
  250. end
  251.  
  252. local function class2(name)
  253.     return function(arg)
  254.         if type(arg)=="table" then
  255.                 realClass(arg,name)
  256.         else
  257.                 return class3(arg,name)
  258.         end
  259.     end
  260. end
  261.  
  262. function class(name)
  263.     return class2(name)
  264. end
  265.  
  266.  
  267. if config["imply_self"] then
  268.     class "base"
  269.     {
  270.         isA=
  271.         function(name)
  272.             local _,self=next(getfenv(debug.getinfo(1).func))
  273.             if self.className==name then
  274.                 return true
  275.             end
  276.             local var=self.extends
  277.             while var~=name do
  278.                 var=classes[var].extends
  279.                 if var=="base" or not var then
  280.                     return false
  281.                 end
  282.             end
  283.             return var
  284.         end,
  285.        
  286.         [config["class_config_location"]]=
  287.         {
  288.             [config.class_config_setup.new]=function(...) return {} end,
  289.             [config.class_config_setup.mt]={}
  290.         }
  291.     }
  292. else
  293.     class "base"
  294.     {
  295.         isA=
  296.         function(self,name)
  297.             if self.className==name then
  298.                 return true
  299.             end
  300.             local var=self.super
  301.             while var~=name do
  302.                 var=classes[var].super
  303.                 if var=="base" or not var then
  304.                     return false
  305.                 end
  306.             end
  307.             return var
  308.         end,
  309.        
  310.         [config["class_config_location"]]=
  311.         {
  312.             [config.class_config_setup.new]=function(...) return {} end,
  313.             [config.class_config_setup.mt]={}
  314.         }
  315.     }
  316. end
  317. if config.class_config_location=="class" then
  318.     classes.base[config.class_config_setup.new]=classes.base.class[config.class_config_setup.new]
  319.     classes.base[config.class_config_setup.mt]=classes.base.class[config.class_config_setup.mt]
  320.     classes.base.class=nil
  321. end
  322.  
  323. if common_class then
  324.     _G.common={}
  325.     common.class=
  326.     function(name,data,extends)
  327.         realClass(data,name,extends and extends.className or "base")
  328.         return classes[name]
  329.     end
  330.     common.instance=
  331.     function(class,...)
  332.         local args={...}
  333.         return newObj(class.className,unpack(args))
  334.     end
  335. end
Advertisement
Add Comment
Please, Sign In to add comment