Last active
January 21, 2020 00:23
-
-
Save lennyRBLX/65bd1c66f91c2f9bf140b94e0be72112 to your computer and use it in GitHub Desktop.
A custom Pure Lua compiler to allow for static file inclusion.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- credits to louka | merge.lua | |
-- helped a lot | |
local pattern_regex = "C_INCLUDE%s*%(?%s*['\"]([%w_/\\%.]+)['\"]%s*%)?" | |
local directory = "" -- adds onto all calls to get contents of files, really easy and helpful | |
local wrap_includes = false -- wraps files with pcall that has custom error message | |
local function get_line_count(string) | |
local result = 1 | |
for _ in tostring(string):gmatch("\n") do | |
result = result + 1 | |
end | |
return result | |
end | |
local function parse_path(path) | |
return directory .. tostring(path) | |
end | |
local function get_include_paths(include_string) | |
include_string = tostring(include_string) | |
local result = {} | |
for path in include_string:gmatch(pattern_regex) do | |
result[#result + 1] = path | |
end | |
return result | |
end | |
local function get_include_path(include_string) | |
include_string = tostring(include_string) | |
return get_include_paths(include_string)[1] | |
end | |
local function get_line(sent_script, include_string) | |
sent_script = tostring(sent_script) | |
include_string = tostring(include_string) | |
local s_index, e_index = sent_script:find(include_string) | |
local start_index | |
repeat | |
if sent_script:sub(s_index, s_index) == "\n" or (s_index < 1) then | |
start_index = s_index + 1 | |
end | |
s_index = s_index - 1 | |
until start_index ~= nil | |
local end_index | |
repeat | |
if sent_script:sub(e_index, e_index) == "\n" or (e_index > #sent_script) then | |
end_index = e_index - 1 | |
end | |
e_index = e_index + 1 | |
until end_index ~= nil | |
return sent_script:sub(start_index, end_index), start_index, end_index | |
end | |
local function get_path_contents(sent_path) | |
local contents, content_io | |
if not sent_path:find('%w.%w') then | |
-- assume .lua file extension | |
sent_path = sent_path .. ".lua" | |
else | |
sent_path = sent_path | |
end | |
sent_path = parse_path(sent_path) | |
content_io = io.open(sent_path, "rb") | |
if content_io then | |
contents = content_io:read("*a") | |
content_io:close() | |
end | |
return contents | |
end | |
local function format_contents(contents, white_space) | |
local result = "" | |
local prev_char | |
for i = 1, #contents, 1 do | |
local char = contents:sub(i, i) | |
if prev_char then | |
if char:match(".") and prev_char:match("\n") then | |
result = result .. white_space:sub(1, #white_space - 1) .. char | |
elseif char ~= "\n" then | |
result = result .. char | |
end | |
end | |
prev_char = char | |
end | |
return result | |
end | |
local function replace_string(source, start_i, end_i, repl) | |
source = tostring(source) | |
repl = tostring(repl) | |
local result = "" | |
if tonumber(start_i) and tonumber(end_i) then | |
result = source:sub(1, start_i) .. repl .. source:sub(end_i, #source) | |
else | |
result = source | |
end | |
return result | |
end | |
local function in_table(includes, path) | |
path = tostring(path) | |
local result = false | |
for _, include in pairs(includes) do | |
if include.path == path then | |
result = include | |
end | |
end | |
return result | |
end | |
local function build(sent_script, includes) | |
local result = sent_script | |
local included = {} | |
repeat | |
for _, path in pairs(get_include_paths(result)) do | |
local include = in_table(includes, path) | |
local s_index, e_index = result:find(path) | |
s_index = (s_index - 1) - #("C_INCLUDE('") | |
e_index = (e_index + 1) + #("')") | |
if included[path] then | |
result = replace_string(result, s_index, e_index, "") | |
else | |
local white_space = include.white_space | |
local wrap_front, wrap_end = "", "" | |
if wrap_includes then | |
white_space = ("\t"):sub(1, 1) .. white_space | |
local format_path = path:lower():gsub(" ", "_"):gsub("%s", ""):gsub("'", ""):gsub('"', ""):gsub(string.char(91), ""):gsub(string.char(93), "") | |
wrap_front = "local error, msg = pcall(function()\n" .. white_space:sub(1, #white_space - 1) .. "\n\t" | |
wrap_end = "\nif not error then\n" .. string.format("error(%s .. ' | message: ' .. msg)\n", "'" .. format_path .. "'") .. "end\n" | |
end | |
result = replace_string( | |
result, s_index, e_index, | |
wrap_front .. format_contents(include.contents, white_space) .. wrap_end | |
) | |
included[path] = true | |
print("built: " .. parse_path(path)) | |
end | |
end | |
until #get_include_paths(result) == 0 | |
return result | |
end | |
local include_table = {} | |
local function compile(sent_script) | |
sent_script = tostring(sent_script) | |
local l_unpack = unpack or table.unpack -- local unpack | |
for _, path in pairs(get_include_paths(sent_script)) do | |
if not in_table(include_table, path) then | |
print("compiled: " .. parse_path(path)) | |
local contents = get_path_contents(path) | |
local include_line = get_line(sent_script, path) | |
local s_index, e_index = sent_script:find(path) | |
s_index = (s_index - 1) - #("C_INCLUDE('") | |
e_index = (e_index + 1) + #("')") | |
local white_space = "" | |
if include_line:find("%s") then | |
white_space = include_line:sub(0, s_index) | |
end | |
include_table[#include_table + 1] = { | |
["path"] = path, | |
["contents"] = contents, | |
["start_index"] = s_index, | |
["end_index"] = e_index, | |
["white_space"] = white_space | |
} | |
-- recursive | |
compile(contents) | |
end | |
end | |
end | |
local function main(path, out_path) | |
if not path or not out_path then return end | |
local in_io = io.open(path, "rb") | |
if not in_io then | |
print("failed to get contents for: " .. path) | |
return | |
end | |
local out_io = io.open(out_path, "w+b") | |
if not out_io then | |
print("failed to get contents for: " .. out_path) | |
return | |
end | |
local sent_script = in_io:read("*a") | |
compile(sent_script) | |
out_io:write( | |
build(sent_script, include_table) | |
) | |
in_io:close() | |
out_io:close() | |
end | |
return main(...) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment