Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- the 4 main tables:
- local temp_classes = {} --temp_classes[class_path] = {[id] = {class_environment}} (the table where all copies of classes are stored)
- local classes = {} -- the table where all metadata and data of classes is stored.
- local packages = {} -- the table where all class paths to classes that are in speciefied packages ares stored.
- local tasks = {} -- tasks[#tasks + 1] = {task = "implement", class_path_1, class_path_2} (the table where all tasks are stored)
- -- 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
- -- tried to implement is loaded, this class is going to be implemented in the other class.
- fs.delete("cllog")
- local w = fs.open("cllog", "w")
- w.close()
- fs.delete(".classlog")
- local function log(text)
- local w = fs.open("cllog", "a")
- w.writeLine(text)
- w.close()
- end
- local function classlog(class, text)
- if not fs.exists(".classlog") then
- fs.makeDir(".classlog")
- end
- local w
- if not fs.exists(".classlog/"..class) then
- w = fs.open(".classlog/"..class, "w")
- else
- w = fs.open(".classlog/"..class, "a")
- end
- w.writeLine(text)
- w.close()
- end
- local function split(str, pat)
- local t = {} -- NOTE: use {n = 0} in Lua-5.0
- local fpat = "(.-)" .. pat
- local last_end = 1
- local s, e, cap = str:find(fpat, 1)
- while s do
- if s ~= 1 or cap ~= "" then
- table.insert(t,cap)
- end
- last_end = e+1
- s, e, cap = str:find(fpat, last_end)
- end
- if last_end <= #str then
- cap = str:sub(last_end)
- table.insert(t, cap)
- end
- return t
- end
- function spliterator(s,pattern,plain)
- local next = 0
- return function()
- if not next then
- return nil
- end
- local left = next + 1
- local right
- right, next = string.find(s, pattern, left, plain)
- if not right then
- right = #s+1
- end
- return string.sub(s, left, right-1)
- end
- end
- local function newglobalid()
- local global_id = 1
- for a, b in pairs(temp_classes) do
- global_id = global_id + #b
- end
- return global_id
- end
- local function deepcopy(orig)
- local orig_type = type(orig)
- local copy
- if orig_type == 'table' then
- copy = {}
- for orig_key, orig_value in next, orig, nil do
- copy[deepcopy(orig_key)] = deepcopy(orig_value)
- end
- setmetatable(copy, deepcopy(getmetatable(orig)))
- else -- number, string, boolean, etc
- copy = orig
- end
- return copy
- end
- function loadclassraw(path_to_class, environment_2)
- local class_name = fs.getName(path_to_class)
- local class_path
- local package_name
- local implement_name
- local file_path = path_to_class
- local class_type
- local level_1_environment
- local level_2_environment
- local level_3_environment
- local level_4_environment
- local environment
- if not environment_2 then
- level_1_environment = {}
- level_2_environment = {
- package = function(package_name_2)
- package_name = package_name_2
- class_path = package_name.."."..class_name
- end,
- implement = function(implement_name_2)
- implement_name = implement_name2
- end,
- classtype = function(class_type_2)
- local class_types = {["interface"] = "interface", ["class"] = "class"}
- class_type = class_types[class_type_2] or "class"
- end,
- getpackage = function()
- return package_name
- end,
- getclasspath = function()
- return class_path
- end,
- getclasstype = function()
- return class_type
- end,
- getimplement = function()
- return implement_name
- end,
- log = function(...) classlog(class_path, table.concat({...}, "")) end,
- this = {}
- }
- level_3_environment = {}
- level_4_environment = {_C = {}}
- setmetatable(level_1_environment, {__index = level_2_environment})
- setmetatable(level_2_environment, {__index = level_3_environment})
- setmetatable(level_3_environment, {__index = level_4_environment})
- setmetatable(level_4_environment, {__index = _G})
- environment = level_1_environment
- level_2_environment.this = environment
- end
- local file_function, err = loadfile(path_to_class)
- if not file_function then
- return false, err
- end
- setfenv(file_function, environment)
- local ok, err = pcall(file_function)
- if not ok then
- return false, err
- end
- return {
- class_name = class_name,
- class_path = class_path,
- package_name = package_name,
- implement_name = implement_name,
- file_path = file_path,
- class_type = class_type,
- class_environment = level_1_environment,
- classloader_environment = level_2_environment,
- class_implement_environment = level_3_environment,
- class_access_environment = level_4_environment
- }
- end
- function newcopy(class_path)
- local class_data, err = loadclassraw(classes[class_path].file_path)
- if type(class_data) == "boolean" then
- return false, err
- end
- local class_implement_environment = deepcopy(classes[class_path].class_implement_environment)
- local class_access_environment = deepcopy(classes[class_path].class_access_environment)
- local class_env = deepcopy(classes[class_path].class_environment)
- setmetatable(class_access_environment, {__index = _G})
- setmetatable(class_implement_environment, {__index = class_access_environment})
- setmetatable(class_data.classloader_environment, {__index = class_implement_environment})
- local global_id = newglobalid()
- local class_id = 1
- if temp_classes[class_data.class_path] == nil then
- temp_classes[class_data.class_path] = {{class_environment = class_data.class_environment, global_id = global_id}}
- temp_classes[global_id] = class_data.class_environment
- else
- class_id = #temp_classes[class_data.class_path] + 1
- temp_classes[class_data.class_path][class_id] = {class_environment = class_data.class_environment, global_id = global_id}
- temp_classes[global_id] = class_data.class_environment
- end
- return global_id
- end
- function loadclass(path_to_class)
- log("Loading class "..path_to_class)
- local class_name = fs.getName(path_to_class)
- local class_as_function, err = loadfile(path_to_class)
- if not class_as_function then
- return false, err
- end
- -- declare class metadata
- local package_name = ""
- local implement_name = ""
- local class_path = ""
- local class_type = "class"
- -- set up environments
- local class_access_environment = {_C = {}} --4rd layer environment
- 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
- local class_implement_environment = {} --3rd layer environment
- setmetatable(class_implement_environment, {__index = class_access_environment})
- local classloader_environment = { --2nd layer environment
- package = function(package_name_2)
- package_name = package_name_2
- class_path = package_name.."."..class_name
- end,
- implement = function(implement_name_2)
- implement_name = implement_name_2
- end,
- classtype = function(class_type_2)
- local class_types = {["class"] = "class", ["interface"] = "interface"}
- class_type = class_type_2 or "class"
- end,
- getpackage = function()
- return package_name
- end,
- getimplement = function()
- return implement_name
- end,
- getclasspath = function()
- return class_path
- end,
- getclasstype = function()
- return class_type
- end,
- print = print,
- type = type,
- log = function(...) classlog(class_path, table.concat({...}, "")) end
- }
- setmetatable(classloader_environment, {__index = class_implement_environment})
- local class_environment = {} --1st layer environment
- setmetatable(class_environment, {__index = classloader_environment})
- setfenv(class_as_function, class_environment) -- push the class in the new environment
- class_as_function() -- run the class
- local global_id = 1
- for a, b in pairs(temp_classes) do
- n = n + #b
- end
- local return_function = function() end
- -- register in classes table
- classes[class_path] = {
- class = function(...) return return_function(...) end,
- class_path = class_path,
- class_name = class_name,
- package_name = package_name,
- implement_name = implement_name,
- class_type = class_type,
- class_environment = class_environment,
- classloader_environment = classloader_environment,
- class_implement_environment = class_implement_environment,
- class_access_environment = class_access_environment,
- file_path = path_to_class,
- constructor_called = false
- }
- -- implement implement_name class to class_implement_environment
- if classes[implement_name] ~= nil then
- if classes[implement_name].class_type == "interface" then
- log(" Implementing interface "..implement_name.." to "..class_type.." "..class_path)
- for a, b in pairs(classes[implement_name].class_environment) do
- classes[class_path].class_implement_environment[a] = classes[implement_name].class_environment[a]
- end
- elseif classes[implement_name].class_type == "class" then
- log(" Implementing class "..implement_name.." to "..class_type.." "..class_path)
- local global_id_new = newcopy(implement_name)
- if temp_classes[global_id_new].class_environment[implement_name] ~= nil then
- temp_classes[global_id_new].class_environment[implement_name]()
- end
- for a, b in pairs(temp_classes[global_id_new].class_environment) do
- classes[class_path].class_implement_environment[a] = temp_classes[global_id_new].class_environment[a]
- end
- end
- else
- -- if the implement_name class isnt loaded yet, create an entry in the tasks table
- if implement_name ~= "" then
- tasks[#tasks + 1] = {task = "implement", class_path_1 = implement_name, class_path_2 = class_path}
- end
- end
- -- register in packages table
- if packages[package_name] ~= nil then
- --add classes of the package to the class_access_environment
- for a = 1, #packages[package_name] do
- classes[class_path].class_access_environment._C[classes[packages[package_name][a]].class_name] = function(...) return classes[packages[package_name][a]].class(...) end
- classes[packages[package_name][a]].class_access_environment._C[class_name] = function(...) return classes[class_path].class(...) end
- end
- packages[package_name][#packages[package_name] + 1] = class_path
- else
- packages[package_name] = {class_path}
- end
- -- register class_path for all other classes
- local function addEnv(class_path_1, class_path_2)
- local access_list = {}
- local splitted = {}
- local counter = 0
- for a in spliterator(classes[class_path_1].package_name, ".", true) do
- counter = counter + 1
- access_list[counter] = '["'..a..'"]'
- splitted[counter] = a
- end
- local tfl = {}
- for c = 1, #access_list do
- 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")
- setfenv(temp, {classes = classes, class_path_2 = class_path_2})
- if err and err ~= "" then print(err) error() else tfl[c] = temp() end
- if tfl[c] == false then
- for d = c + 1, #splitted do
- tfl[d] = false
- end
- break
- end
- end
- local new_class_access_environment = setmetatable(deepcopy(classes[class_path_2].class_access_environment), {})
- local tlstr = ""
- for c = 1, #tfl do
- if tfl[c] == false then
- tlstr = tlstr.." class_access_environment"..table.concat(access_list, "", 1, c).." = {} "
- end
- end
- tlstr = tlstr.." class_access_environment"..table.concat(access_list, "")..'["'..classes[class_path_1].class_name..'"] = classes[class_path_1].class return class_access_environment'
- local ok, err = loadstring(tlstr, "af2")
- setfenv(ok, {classes = classes, class_access_environment = new_class_access_environment, class_path_1 = class_path_1})
- if not ok then print(err) end
- local class_access_environment_2 = ok()
- classes[class_path_2].class_access_environment = class_access_environment_2
- setmetatable(classes[class_path_2].classloader_environment, {__index = classes[class_path_2].class_access_environment})
- setmetatable(classes[class_path_2].class_access_environment, {__index = _G})
- local stack = 0
- local function prst(tab)
- for a, b in pairs(tab) do
- local typ = type(b)
- if typ == "table" then
- log(" "..string.rep(" ", stack).."Entering table "..a)
- stack = stack + 2
- prst(b)
- stack = stack - 2
- else
- log(" "..string.rep(" ", stack)..a..": "..type(b))
- end
- end
- end
- --log("\n LOGSTACK "..class_path_2)
- --prst(classes[class_path_2].class_access_environment)
- --log("")
- end
- -- do tasks list
- for a, b in pairs(tasks) do
- if b.task == "implement" then
- if b.class_path_1 == class_path and b.class_path_2 ~= class_path then
- if class_type == "interface" then
- log(" [TASK] Implementing class "..b.class_path_1.." to "..classes[b.class_path_2].class_type.." "..b.class_path_2)
- for c, d in pairs(classes[class_path].class_environment) do
- classes[b.class_path_2].class_implement_environment[c] = classes[class_path].class_environment[c]
- end
- elseif class_type == "class" then
- log(" [TASK] Implementing class "..b.class_path_1.." to "..classes[b.class_path_2].class_type.." "..b.class_path_2)
- local global_id_new = newcopy(class_path)
- if temp_classes[global_id_new].class_environment[class_name] ~= nil then
- temp_classes[global_id_new].class_environment[class_name]()
- end
- for c, d in pairs(temp_classes[global_id_new].class_environment) do
- classes[b.class_path_2].class_implement_environment[c] = temp_classes[global_id_new].class_environment[c]
- end
- end
- end
- end
- end
- -- create a return function
- local return_function
- local onErr, err
- if class_type == "class" then
- log(" Creating return function class "..class_path)
- return_function = function(...)
- local create_new_copy, err2 = newcopy(class_path)
- if type(create_new_copy) == "boolean" then
- onErr = true
- err = err2
- return false, err
- end
- if temp_classes[create_new_copy][class_name] ~= nil then
- temp_classes[create_new_copy][class_name](...)
- end
- return temp_classes[create_new_copy]
- end
- elseif class_type == "interface" then
- log(" Creating return function interface "..class_path)
- return_function = function(...)
- if classes[class_path].constructor_called == false then
- if classes[class_path].class_environment[class_name] ~= nil then
- classes[class_path].class_environment[class_name](...)
- end
- end
- return classes[class_path].class_environment
- end
- end
- classes[class_path].class = return_function
- log(" Adding classes to environment for class: "..class_path)
- for a, b in pairs(classes) do
- if a ~= class_path then
- log(" [OTHER] Adding own class to "..a.." environment")
- addEnv(class_path, a)
- log(" [OWN] Adding class "..a.." to OWN environment")
- addEnv(a, class_path)
- end
- end
- classloader_environment.this = class_environment
- log(" This type: "..type(classloader_environment.this))
- -- FINISHED.
- if onErr == true then
- return false, err
- end
- log(type(classes[class_path].class_implement_environment.getPluginManager))
- return return_function
- end
Advertisement
Add Comment
Please, Sign In to add comment