Guest User

classloader

a guest
Sep 25th, 2013
65
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 15.12 KB | None | 0 0
  1. -- the 4 main tables:
  2. local temp_classes = {} --temp_classes[class_path] = {[id] = {class_environment}} (the table where all copies of classes are stored)
  3. local classes = {} -- the table where all metadata and data of classes is stored.
  4. local packages = {} -- the table where all class paths to classes that are in speciefied packages ares stored.
  5. local tasks = {} -- tasks[#tasks + 1] = {task = "implement", class_path_1, class_path_2}  (the table where all tasks are stored)
  6.     -- for example: If a class tries to implement a class that doesn't exist, but is going to be loaded later, a task is created in this table, and if the class that the other class
  7.     -- tried to implement is loaded, this class is going to be implemented in the other class.
  8. fs.delete("cllog")
  9. local w = fs.open("cllog", "w")
  10. w.close()
  11.  
  12. fs.delete(".classlog")
  13.  
  14. local function log(text)
  15.     local w = fs.open("cllog", "a")
  16.     w.writeLine(text)
  17.     w.close()
  18. end
  19.  
  20. local function classlog(class, text)
  21.     if not fs.exists(".classlog") then
  22.         fs.makeDir(".classlog")
  23.     end
  24.     local w
  25.     if not fs.exists(".classlog/"..class) then
  26.         w = fs.open(".classlog/"..class, "w")
  27.     else
  28.         w = fs.open(".classlog/"..class, "a")
  29.     end
  30.     w.writeLine(text)
  31.     w.close()
  32. end
  33.  
  34. local function split(str, pat)
  35.     local t = {}  -- NOTE: use {n = 0} in Lua-5.0
  36.     local fpat = "(.-)" .. pat
  37.     local last_end = 1
  38.     local s, e, cap = str:find(fpat, 1)
  39.     while s do
  40.         if s ~= 1 or cap ~= "" then
  41.             table.insert(t,cap)
  42.         end
  43.         last_end = e+1
  44.         s, e, cap = str:find(fpat, last_end)
  45.     end
  46.     if last_end <= #str then
  47.         cap = str:sub(last_end)
  48.         table.insert(t, cap)
  49.     end
  50.     return t
  51. end
  52.  
  53. function spliterator(s,pattern,plain)
  54.     local next = 0
  55.     return function()
  56.         if not next then
  57.             return nil
  58.         end
  59.         local left = next + 1
  60.         local right
  61.         right, next = string.find(s, pattern, left, plain)
  62.         if not right then
  63.             right = #s+1
  64.         end
  65.         return string.sub(s, left, right-1)
  66.     end
  67. end
  68.  
  69. local function newglobalid()
  70.     local global_id = 1
  71.     for a, b in pairs(temp_classes) do
  72.         global_id = global_id + #b
  73.     end
  74.     return global_id
  75. end
  76.  
  77. local function deepcopy(orig)
  78.     local orig_type = type(orig)
  79.     local copy
  80.     if orig_type == 'table' then
  81.         copy = {}
  82.         for orig_key, orig_value in next, orig, nil do
  83.             copy[deepcopy(orig_key)] = deepcopy(orig_value)
  84.         end
  85.         setmetatable(copy, deepcopy(getmetatable(orig)))
  86.     else -- number, string, boolean, etc
  87.         copy = orig
  88.     end
  89.     return copy
  90. end
  91.  
  92. function loadclassraw(path_to_class, environment_2)
  93.     local class_name = fs.getName(path_to_class)
  94.     local class_path
  95.     local package_name
  96.     local implement_name
  97.     local file_path = path_to_class
  98.     local class_type
  99.     local level_1_environment
  100.     local level_2_environment
  101.     local level_3_environment
  102.     local level_4_environment
  103.     local environment
  104.     if not environment_2 then
  105.         level_1_environment = {}
  106.         level_2_environment = {
  107.             package = function(package_name_2)
  108.                 package_name = package_name_2
  109.                 class_path = package_name.."."..class_name
  110.             end,
  111.             implement = function(implement_name_2)
  112.                 implement_name = implement_name2
  113.             end,
  114.             classtype = function(class_type_2)
  115.                 local class_types = {["interface"] = "interface", ["class"] = "class"}
  116.                 class_type = class_types[class_type_2] or "class"
  117.             end,
  118.             getpackage = function()
  119.                 return package_name
  120.             end,
  121.             getclasspath = function()
  122.                 return class_path
  123.             end,
  124.             getclasstype = function()
  125.                 return class_type
  126.             end,
  127.             getimplement = function()
  128.                 return implement_name
  129.             end,
  130.             log = function(...) classlog(class_path, table.concat({...}, "")) end,
  131.             this = {}
  132.         }
  133.         level_3_environment = {}
  134.         level_4_environment = {_C = {}}
  135.        
  136.         setmetatable(level_1_environment, {__index = level_2_environment})
  137.         setmetatable(level_2_environment, {__index = level_3_environment})
  138.         setmetatable(level_3_environment, {__index = level_4_environment})
  139.         setmetatable(level_4_environment, {__index = _G})
  140.        
  141.         environment = level_1_environment
  142.         level_2_environment.this = environment
  143.     end
  144.    
  145.     local file_function, err = loadfile(path_to_class)
  146.     if not file_function then
  147.         return false, err
  148.     end
  149.    
  150.     setfenv(file_function, environment)
  151.    
  152.     local ok, err = pcall(file_function)
  153.     if not ok then
  154.         return false, err
  155.     end
  156.    
  157.     return {
  158.         class_name = class_name,
  159.         class_path = class_path,
  160.         package_name = package_name,
  161.         implement_name = implement_name,
  162.         file_path = file_path,
  163.         class_type = class_type,
  164.         class_environment = level_1_environment,
  165.         classloader_environment = level_2_environment,
  166.         class_implement_environment = level_3_environment,
  167.         class_access_environment = level_4_environment
  168.     }
  169. end
  170.  
  171. function newcopy(class_path)
  172.     local class_data, err = loadclassraw(classes[class_path].file_path)
  173.     if type(class_data) == "boolean" then
  174.         return false, err
  175.     end
  176.     local class_implement_environment = deepcopy(classes[class_path].class_implement_environment)
  177.     local class_access_environment = deepcopy(classes[class_path].class_access_environment)
  178.     local class_env = deepcopy(classes[class_path].class_environment)
  179.     setmetatable(class_access_environment, {__index = _G})
  180.     setmetatable(class_implement_environment, {__index = class_access_environment})
  181.     setmetatable(class_data.classloader_environment, {__index = class_implement_environment})
  182.    
  183.     local global_id = newglobalid()
  184.     local class_id = 1
  185.     if temp_classes[class_data.class_path] == nil then
  186.         temp_classes[class_data.class_path] = {{class_environment = class_data.class_environment, global_id = global_id}}
  187.         temp_classes[global_id] = class_data.class_environment
  188.     else
  189.         class_id = #temp_classes[class_data.class_path] + 1
  190.         temp_classes[class_data.class_path][class_id] = {class_environment = class_data.class_environment, global_id = global_id}
  191.         temp_classes[global_id] = class_data.class_environment
  192.     end
  193.  
  194.     return global_id
  195. end
  196.  
  197. function loadclass(path_to_class)
  198.     log("Loading class "..path_to_class)
  199.     local class_name = fs.getName(path_to_class)
  200.    
  201.     local class_as_function, err = loadfile(path_to_class)
  202.     if not class_as_function then
  203.         return false, err
  204.     end
  205.    
  206.     -- declare class metadata
  207.     local package_name = ""
  208.     local implement_name = ""
  209.     local class_path = ""
  210.     local class_type = "class"
  211.     -- set up environments
  212.     local class_access_environment = {_C = {}} --4rd layer environment
  213.     setmetatable(class_access_environment, {__index = _G}) -- (__index will be set to _G later, but at this time the class shall not run any function except the classloader functions
  214.    
  215.     local class_implement_environment = {} --3rd layer environment
  216.     setmetatable(class_implement_environment, {__index = class_access_environment})
  217.    
  218.     local classloader_environment = { --2nd layer environment
  219.         package = function(package_name_2)
  220.             package_name = package_name_2
  221.             class_path = package_name.."."..class_name
  222.         end,
  223.         implement = function(implement_name_2)
  224.             implement_name = implement_name_2
  225.         end,
  226.         classtype = function(class_type_2)
  227.             local class_types = {["class"] = "class", ["interface"] = "interface"}
  228.             class_type = class_type_2 or "class"
  229.         end,
  230.         getpackage = function()
  231.             return package_name
  232.         end,
  233.         getimplement = function()
  234.             return implement_name
  235.         end,
  236.         getclasspath = function()
  237.             return class_path
  238.         end,
  239.         getclasstype = function()
  240.             return class_type
  241.         end,
  242.         print = print,
  243.         type = type,
  244.         log = function(...) classlog(class_path, table.concat({...}, "")) end
  245.     }
  246.     setmetatable(classloader_environment, {__index = class_implement_environment})
  247.    
  248.     local class_environment = {} --1st layer environment
  249.     setmetatable(class_environment, {__index = classloader_environment})
  250.    
  251.     setfenv(class_as_function, class_environment) -- push the class in the new environment
  252.     class_as_function() -- run the class
  253.        
  254.     local global_id = 1
  255.     for a, b in pairs(temp_classes) do
  256.         n = n + #b
  257.     end
  258.    
  259.     local return_function = function() end
  260.    
  261.     -- register in classes table
  262.     classes[class_path] = {
  263.         class = function(...) return return_function(...) end,
  264.         class_path = class_path,
  265.         class_name = class_name,
  266.         package_name = package_name,
  267.         implement_name = implement_name,
  268.         class_type = class_type,
  269.         class_environment = class_environment,
  270.         classloader_environment = classloader_environment,
  271.         class_implement_environment = class_implement_environment,
  272.         class_access_environment = class_access_environment,
  273.         file_path = path_to_class,
  274.         constructor_called = false
  275.     }
  276.    
  277.     -- implement implement_name class to class_implement_environment
  278.     if classes[implement_name] ~= nil then
  279.         if classes[implement_name].class_type == "interface" then
  280.             log("  Implementing interface "..implement_name.." to "..class_type.." "..class_path)
  281.             for a, b in pairs(classes[implement_name].class_environment) do
  282.                 classes[class_path].class_implement_environment[a] = classes[implement_name].class_environment[a]
  283.             end
  284.         elseif classes[implement_name].class_type == "class" then
  285.             log("  Implementing class "..implement_name.." to "..class_type.." "..class_path)
  286.             local global_id_new = newcopy(implement_name)
  287.            
  288.             if temp_classes[global_id_new].class_environment[implement_name] ~= nil then
  289.                 temp_classes[global_id_new].class_environment[implement_name]()
  290.             end
  291.            
  292.             for a, b in pairs(temp_classes[global_id_new].class_environment) do
  293.                 classes[class_path].class_implement_environment[a] = temp_classes[global_id_new].class_environment[a]
  294.             end
  295.         end
  296.     else
  297.         -- if the implement_name class isnt loaded yet, create an entry in the tasks table
  298.         if implement_name ~= "" then
  299.             tasks[#tasks + 1] = {task = "implement", class_path_1 = implement_name, class_path_2 = class_path}
  300.         end
  301.     end
  302.    
  303.     -- register in packages table
  304.     if packages[package_name] ~= nil then
  305.         --add classes of the package to the class_access_environment
  306.         for a = 1, #packages[package_name] do
  307.             classes[class_path].class_access_environment._C[classes[packages[package_name][a]].class_name] = function(...) return classes[packages[package_name][a]].class(...) end
  308.             classes[packages[package_name][a]].class_access_environment._C[class_name] = function(...) return classes[class_path].class(...) end
  309.         end
  310.         packages[package_name][#packages[package_name] + 1] = class_path
  311.     else
  312.         packages[package_name] = {class_path}
  313.     end
  314.    
  315.     -- register class_path for all other classes
  316.     local function addEnv(class_path_1, class_path_2)
  317.         local access_list = {}
  318.         local splitted = {}
  319.         local counter = 0
  320.         for a in spliterator(classes[class_path_1].package_name, ".", true) do
  321.             counter = counter + 1
  322.             access_list[counter] = '["'..a..'"]'
  323.             splitted[counter] = a
  324.         end
  325.        
  326.         local tfl = {}
  327.         for c = 1, #access_list do
  328.             local temp, err = loadstring("if classes[class_path_2].class_access_environment"..table.concat(access_list, "", 1, c).." ~= nil then return true else return false end", "af 1")
  329.             setfenv(temp, {classes = classes, class_path_2 = class_path_2})
  330.             if err and err ~= "" then print(err) error() else tfl[c] = temp() end
  331.             if tfl[c] == false then
  332.                 for d = c + 1, #splitted do
  333.                     tfl[d] = false
  334.                 end
  335.                 break
  336.             end
  337.         end
  338.        
  339.         local new_class_access_environment = setmetatable(deepcopy(classes[class_path_2].class_access_environment), {})
  340.         local tlstr = ""
  341.         for c = 1, #tfl do
  342.             if tfl[c] == false then
  343.                 tlstr = tlstr.." class_access_environment"..table.concat(access_list, "", 1, c).." = {} "
  344.             end
  345.         end
  346.         tlstr = tlstr.." class_access_environment"..table.concat(access_list, "")..'["'..classes[class_path_1].class_name..'"] = classes[class_path_1].class return class_access_environment'
  347.         local ok, err = loadstring(tlstr, "af2")
  348.         setfenv(ok, {classes = classes, class_access_environment = new_class_access_environment, class_path_1 = class_path_1})
  349.         if not ok then print(err) end
  350.         local class_access_environment_2 = ok()
  351.         classes[class_path_2].class_access_environment = class_access_environment_2
  352.         setmetatable(classes[class_path_2].classloader_environment, {__index = classes[class_path_2].class_access_environment})
  353.         setmetatable(classes[class_path_2].class_access_environment, {__index = _G})
  354.        
  355.         local stack = 0
  356.         local function prst(tab)
  357.             for a, b in pairs(tab) do
  358.                 local typ = type(b)
  359.                 if typ == "table" then
  360.                     log("  "..string.rep(" ", stack).."Entering table "..a)
  361.                     stack = stack + 2
  362.                     prst(b)
  363.                     stack = stack - 2
  364.                 else
  365.                     log("  "..string.rep(" ", stack)..a..": "..type(b))
  366.                 end
  367.             end
  368.         end
  369.         --log("\n  LOGSTACK "..class_path_2)
  370.         --prst(classes[class_path_2].class_access_environment)
  371.         --log("")
  372.        
  373.     end
  374.    
  375.     -- do tasks list
  376.     for a, b in pairs(tasks) do
  377.         if b.task == "implement" then
  378.             if b.class_path_1 == class_path and b.class_path_2 ~= class_path then
  379.                 if class_type == "interface" then
  380.                     log("  [TASK] Implementing class "..b.class_path_1.." to "..classes[b.class_path_2].class_type.." "..b.class_path_2)
  381.                     for c, d in pairs(classes[class_path].class_environment) do
  382.                         classes[b.class_path_2].class_implement_environment[c] = classes[class_path].class_environment[c]
  383.                     end
  384.                 elseif class_type == "class" then
  385.                     log("  [TASK] Implementing class "..b.class_path_1.." to "..classes[b.class_path_2].class_type.." "..b.class_path_2)
  386.                     local global_id_new = newcopy(class_path)
  387.                    
  388.                     if temp_classes[global_id_new].class_environment[class_name] ~= nil then
  389.                         temp_classes[global_id_new].class_environment[class_name]()
  390.                     end
  391.            
  392.                     for c, d in pairs(temp_classes[global_id_new].class_environment) do
  393.                         classes[b.class_path_2].class_implement_environment[c] = temp_classes[global_id_new].class_environment[c]
  394.                     end
  395.                 end
  396.             end
  397.         end
  398.     end
  399.    
  400.     -- create a return function
  401.     local return_function
  402.     local onErr, err
  403.     if class_type == "class" then
  404.         log("  Creating return function class "..class_path)
  405.         return_function = function(...)
  406.             local create_new_copy, err2 = newcopy(class_path)
  407.             if type(create_new_copy) == "boolean" then
  408.                 onErr = true
  409.                 err = err2
  410.                 return false, err
  411.             end
  412.             if temp_classes[create_new_copy][class_name] ~= nil then
  413.                 temp_classes[create_new_copy][class_name](...)
  414.             end
  415.             return temp_classes[create_new_copy]
  416.         end
  417.     elseif class_type == "interface" then
  418.         log("  Creating return function interface "..class_path)
  419.         return_function = function(...)
  420.             if classes[class_path].constructor_called == false then
  421.                 if classes[class_path].class_environment[class_name] ~= nil then
  422.                     classes[class_path].class_environment[class_name](...)
  423.                 end
  424.             end
  425.             return classes[class_path].class_environment
  426.         end
  427.     end
  428.     classes[class_path].class = return_function
  429.    
  430.     log("  Adding classes to environment for class: "..class_path)
  431.     for a, b in pairs(classes) do
  432.         if a ~= class_path then
  433.             log("    [OTHER] Adding own class to "..a.." environment")
  434.             addEnv(class_path, a)
  435.             log("    [OWN]   Adding class "..a.." to OWN environment")
  436.             addEnv(a, class_path)
  437.         end
  438.     end
  439.    
  440.     classloader_environment.this = class_environment
  441.     log("  This type: "..type(classloader_environment.this))
  442.     -- FINISHED.
  443.     if onErr == true then
  444.         return false, err
  445.     end
  446.    
  447.     log(type(classes[class_path].class_implement_environment.getPluginManager))
  448.     return return_function
  449. end
Advertisement
Add Comment
Please, Sign In to add comment