Guest User

classloader 1.1

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