nomsu/code_obj.lua

543 lines
15 KiB
Lua
Raw Permalink Normal View History

2018-04-13 14:55:20 -07:00
local insert, remove, concat
do
local _obj_0 = table
insert, remove, concat = _obj_0.insert, _obj_0.remove, _obj_0.concat
end
local unpack = unpack or table.unpack
2018-06-18 15:44:29 -07:00
local LuaCode, NomsuCode, Source
do
local _class_0
local _base_0 = {
__tostring = function(self)
return "@" .. tostring(self.filename) .. "[" .. tostring(self.start) .. tostring(self.stop and ':' .. self.stop or '') .. "]"
end,
as_lua = function(self)
return "Source(" .. tostring(self.filename:as_lua()) .. ", " .. tostring(self.start) .. tostring(self.stop and ', ' .. self.stop or '') .. ")"
end,
__eq = function(self, other)
return getmetatable(self) == getmetatable(other) and self.filename == other.filename and self.start == other.start and self.stop == other.stop
end,
__lt = function(self, other)
assert(self.filename == other.filename, "Cannot compare sources from different files")
if self.start == other.start then
return (self.stop or self.start) < (other.stop or other.start)
else
return self.start < other.start
end
end,
__le = function(self, other)
assert(self.filename == other.filename, "Cannot compare sources from different files")
if self.start == other.start then
return (self.stop or self.start) <= (other.stop or other.start)
else
return self.start <= other.start
end
end,
__add = function(self, offset)
if type(self) == 'number' then
offset, self = self, offset
else
if type(offset) ~= 'number' then
error("Cannot add Source and " .. tostring(type(offset)))
end
end
return Source(self.filename, self.start + offset, self.stop)
end
}
_base_0.__index = _base_0
_class_0 = setmetatable({
__init = function(self, filename, start, stop)
self.filename, self.start, self.stop = filename, start, stop
end,
__base = _base_0,
__name = "Source"
}, {
__index = _base_0,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
local self = _class_0
self.from_string = function(self, str)
local filename, start, stop = str:match("^@(.-)%[(%d+):(%d+)%]$")
if not (filename) then
filename, start = str:match("^@(.-)%[(%d+)%]$")
end
return self(filename or str, tonumber(start or 1), tonumber(stop))
2018-04-13 14:55:20 -07:00
end
self.is_instance = function(self, x)
return type(x) == 'table' and x.__class == self
end
Source = _class_0
end
local Code
2018-04-13 14:55:20 -07:00
do
local _class_0
local _base_0 = {
text = function(self)
2018-07-23 15:25:53 -07:00
if self.__str == nil then
local buff, indent = { }, 0
local match, gsub, rep
do
local _obj_0 = string
match, gsub, rep = _obj_0.match, _obj_0.gsub, _obj_0.rep
end
for i, b in ipairs(self.bits) do
if type(b) == 'string' then
do
local spaces = match(b, "\n([ ]*)[^\n]*$")
if spaces then
indent = #spaces
end
end
else
b = b:text()
2018-07-23 15:25:53 -07:00
if indent > 0 then
b = gsub(b, "\n", "\n" .. rep(" ", indent))
end
end
buff[#buff + 1] = b
end
self.__str = concat(buff, "")
end
return self.__str
end,
last = function(self, n)
if self.__str then
return self.__str:sub(-n, -1)
end
local last = ""
for i = #self.bits, 1, -1 do
local b = self.bits[i]
last = (type(b) == 'string' and b:sub(-(n - #last)) or b:last(n - #last)) .. last
if #last == n then
break
end
end
return last
end,
first = function(self, n)
if self.__str then
return self.__str:sub(1, n)
end
local first = ""
local _list_0 = self.bits
for _index_0 = 1, #_list_0 do
local b = _list_0[_index_0]
first = first .. (type(b) == 'string' and b:sub(1, n - #first + 1) or b:first(n - #first + 1))
if #first == n then
break
end
end
return first
end,
2018-09-28 22:15:24 -07:00
__tostring = function(self)
return self:text()
2018-09-28 22:15:24 -07:00
end,
as_lua = function(self)
if self.source then
return tostring(self.__class.__name) .. ":from(" .. tostring(concat({
tostring(self.source):as_lua(),
unpack((function()
local _accum_0 = { }
local _len_0 = 1
local _list_0 = self.bits
for _index_0 = 1, #_list_0 do
local b = _list_0[_index_0]
_accum_0[_len_0] = b:as_lua()
_len_0 = _len_0 + 1
end
return _accum_0
end)())
}, ", ")) .. ")"
else
return tostring(self.__class.__name) .. "(" .. tostring(concat((function()
local _accum_0 = { }
local _len_0 = 1
local _list_0 = self.bits
for _index_0 = 1, #_list_0 do
local b = _list_0[_index_0]
_accum_0[_len_0] = b:as_lua()
_len_0 = _len_0 + 1
end
return _accum_0
end)(), ", ")) .. ")"
end
end,
2018-07-23 15:25:53 -07:00
__len = function(self)
if self.__str then
return #self.__str
end
local len = 0
local _list_0 = self.bits
for _index_0 = 1, #_list_0 do
local b = _list_0[_index_0]
len = len + #b
end
return len
2018-07-23 15:25:53 -07:00
end,
match = function(self, ...)
return self:text():match(...)
end,
gmatch = function(self, ...)
return self:text():gmatch(...)
end,
dirty = function(self)
self.__str = nil
self._trailing_line_len = nil
if self._is_multiline == false then
self._is_multiline = nil
end
end,
add = function(self, ...)
local n = select("#", ...)
local match = string.match
2018-07-17 16:13:35 -07:00
local bits = self.bits
for i = 1, n do
local _continue_0 = false
repeat
local b = select(i, ...)
2018-07-10 17:34:39 -07:00
assert(b, "code bit is nil")
2018-07-13 14:30:32 -07:00
assert(not Source:is_instance(b), "code bit is a Source")
if b == '' then
_continue_0 = true
break
end
bits[#bits + 1] = b
2018-07-17 16:13:35 -07:00
_continue_0 = true
until true
if not _continue_0 then
break
end
end
return self:dirty()
2018-07-17 16:13:35 -07:00
end,
trailing_line_len = function(self)
if self._trailing_line_len == nil then
self._trailing_line_len = #self:text():match("[^\n]*$")
end
2018-07-17 16:13:35 -07:00
return self._trailing_line_len
end,
is_multiline = function(self)
if self._is_multiline == nil then
local match = string.match
self._is_multiline = false
local _list_0 = self.bits
for _index_0 = 1, #_list_0 do
local b = _list_0[_index_0]
if type(b) == 'string' then
if match(b, '\n') then
self._is_multiline = true
break
end
elseif b:is_multiline() then
self._is_multiline = true
break
end
end
end
return self._is_multiline
end,
concat_add = function(self, values, joiner, wrapping_joiner)
2018-06-19 00:44:17 -07:00
wrapping_joiner = wrapping_joiner or joiner
local match = string.match
2018-07-17 16:13:35 -07:00
local bits = self.bits
2018-06-19 00:44:17 -07:00
local line_len = 0
for i = 1, #values do
local b = values[i]
if i > 1 then
2018-06-19 00:44:17 -07:00
if line_len > 80 then
bits[#bits + 1] = wrapping_joiner
line_len = 0
else
bits[#bits + 1] = joiner
end
end
bits[#bits + 1] = b
if type(b) ~= 'string' then
b.dirty = error
end
local line = b:match("\n([^\n]*)$")
2018-07-17 16:13:35 -07:00
if line then
2018-06-19 00:44:17 -07:00
line_len = #line
else
line_len = line_len + #b
end
end
return self:dirty()
end,
prepend = function(self, ...)
local n = select("#", ...)
2018-07-17 16:13:35 -07:00
local bits = self.bits
for i = #bits + n, n + 1, -1 do
bits[i] = bits[i - n]
end
for i = 1, n do
local b = select(i, ...)
if type(b) ~= 'string' then
b.dirty = error
end
bits[i] = b
end
return self:dirty()
2018-07-23 15:25:53 -07:00
end,
parenthesize = function(self)
self:prepend("(")
return self:add(")")
end
}
_base_0.__index = _base_0
_class_0 = setmetatable({
__init = function(self, ...)
2018-07-10 17:34:39 -07:00
self.bits = { }
return self:add(...)
end,
__base = _base_0,
__name = "Code"
}, {
__index = _base_0,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
local self = _class_0
self.from = function(self, source, ...)
local inst = self(...)
if type(source) == 'string' then
source = Source:from_string(source)
end
inst.source = source
return inst
end
self.is_instance = function(self, x)
return type(x) == 'table' and x.__class == self
end
Code = _class_0
end
do
local _class_0
local _parent_0 = Code
local _base_0 = {
2018-07-23 15:25:53 -07:00
__tostring = Code.__tostring,
as_lua = Code.as_lua,
2018-07-23 15:25:53 -07:00
__len = Code.__len,
add_free_vars = function(self, vars)
if not (#vars > 0) then
return
end
2018-04-13 14:55:20 -07:00
local seen
do
local _tbl_0 = { }
local _list_0 = self.free_vars
for _index_0 = 1, #_list_0 do
local v = _list_0[_index_0]
local _key_0, _val_0 = {
[v] = true
}
_tbl_0[_key_0] = _val_0
end
seen = _tbl_0
end
for _index_0 = 1, #vars do
local var = vars[_index_0]
2018-06-18 18:10:59 -07:00
assert(type(var) == 'string')
2018-04-13 14:55:20 -07:00
if not (seen[var]) then
self.free_vars[#self.free_vars + 1] = var
seen[var] = true
end
end
return self:dirty()
2018-04-13 14:55:20 -07:00
end,
remove_free_vars = function(self, vars)
if vars == nil then
vars = nil
end
vars = vars or self:get_free_vars()
if not (#vars > 0) then
return
end
2018-04-19 17:23:44 -07:00
local removals = { }
for _index_0 = 1, #vars do
local var = vars[_index_0]
2018-06-18 18:10:59 -07:00
assert(type(var) == 'string')
removals[var] = true
2018-04-19 17:23:44 -07:00
end
2018-04-20 16:23:53 -07:00
local stack = {
self
}
while #stack > 0 do
local lua
lua, stack[#stack] = stack[#stack], nil
for i = #lua.free_vars, 1, -1 do
2018-06-18 18:10:59 -07:00
local free_var = lua.free_vars[i]
if removals[free_var] then
2018-04-20 16:23:53 -07:00
remove(lua.free_vars, i)
2018-04-19 17:23:44 -07:00
end
end
2018-04-20 16:23:53 -07:00
local _list_0 = lua.bits
2018-04-19 17:23:44 -07:00
for _index_0 = 1, #_list_0 do
local b = _list_0[_index_0]
if type(b) ~= 'string' then
2018-04-20 16:23:53 -07:00
stack[#stack + 1] = b
2018-04-19 17:23:44 -07:00
end
end
end
return self:dirty()
2018-04-19 17:23:44 -07:00
end,
get_free_vars = function(self)
local vars, seen = { }, { }
local gather_from
gather_from = function(self)
local _list_0 = self.free_vars
for _index_0 = 1, #_list_0 do
local var = _list_0[_index_0]
if not (seen[var]) then
seen[var] = true
vars[#vars + 1] = var
end
end
local _list_1 = self.bits
for _index_0 = 1, #_list_1 do
local bit = _list_1[_index_0]
if not (type(bit) == 'string') then
gather_from(bit)
end
end
end
gather_from(self)
return vars
end,
declare_locals = function(self, to_declare)
if to_declare == nil then
to_declare = nil
end
to_declare = to_declare or self:get_free_vars()
if #to_declare > 0 then
self:remove_free_vars(to_declare)
2018-06-18 18:10:59 -07:00
self:prepend("local " .. tostring(concat(to_declare, ", ")) .. ";\n")
2018-04-13 14:55:20 -07:00
end
return to_declare
2018-04-13 14:55:20 -07:00
end,
make_offset_table = function(self)
assert(self.source, "This code doesn't have a source")
2018-04-20 16:23:53 -07:00
local lua_to_nomsu, nomsu_to_lua = { }, { }
2018-04-13 14:55:20 -07:00
local walk
2018-04-20 14:33:49 -07:00
walk = function(lua, pos)
local _list_0 = lua.bits
for _index_0 = 1, #_list_0 do
local b = _list_0[_index_0]
if type(b) == 'string' then
2018-04-20 16:23:53 -07:00
if lua.source then
lua_to_nomsu[pos] = lua.source.start
nomsu_to_lua[lua.source.start] = pos
end
else
2018-04-20 16:23:53 -07:00
walk(b, pos)
2018-04-13 14:55:20 -07:00
end
2018-09-28 22:15:24 -07:00
pos = pos + #b
2018-04-13 14:55:20 -07:00
end
end
2018-04-20 14:33:49 -07:00
walk(self, 1)
2018-04-20 16:23:53 -07:00
return {
nomsu_filename = self.source.filename,
lua_filename = tostring(self.source) .. ".lua",
lua_file = self:text(),
2018-04-20 16:23:53 -07:00
lua_to_nomsu = lua_to_nomsu,
nomsu_to_lua = nomsu_to_lua
}
end,
parenthesize = function(self)
2018-07-23 15:25:53 -07:00
self:prepend("(")
return self:add(")")
2018-04-13 14:55:20 -07:00
end
}
_base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base)
2018-04-13 14:55:20 -07:00
_class_0 = setmetatable({
__init = function(self, ...)
_class_0.__parent.__init(self, ...)
2018-04-13 14:55:20 -07:00
self.free_vars = { }
end,
__base = _base_0,
2018-06-18 15:44:29 -07:00
__name = "LuaCode",
__parent = _parent_0
2018-04-13 14:55:20 -07:00
}, {
__index = function(cls, name)
local val = rawget(_base_0, name)
if val == nil then
local parent = rawget(cls, "__parent")
if parent then
return parent[name]
end
else
return val
end
end,
2018-04-13 14:55:20 -07:00
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
if _parent_0.__inherited then
_parent_0.__inherited(_parent_0, _class_0)
end
2018-06-18 15:44:29 -07:00
LuaCode = _class_0
2018-04-13 14:55:20 -07:00
end
do
local _class_0
local _parent_0 = Code
local _base_0 = {
2018-07-23 15:25:53 -07:00
__tostring = Code.__tostring,
as_lua = Code.as_lua,
2018-07-23 15:25:53 -07:00
__len = Code.__len
}
_base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({
__init = function(self, ...)
return _class_0.__parent.__init(self, ...)
end,
__base = _base_0,
2018-06-18 15:44:29 -07:00
__name = "NomsuCode",
__parent = _parent_0
}, {
__index = function(cls, name)
local val = rawget(_base_0, name)
if val == nil then
local parent = rawget(cls, "__parent")
if parent then
return parent[name]
end
else
return val
end
end,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
if _parent_0.__inherited then
_parent_0.__inherited(_parent_0, _class_0)
end
2018-06-18 15:44:29 -07:00
NomsuCode = _class_0
end
Code.__base.add_1_joined_with = assert(Code.__base.concat_add)
Code.__base.add = assert(Code.__base.add)
2018-04-13 14:55:20 -07:00
return {
Code = Code,
2018-06-18 15:44:29 -07:00
NomsuCode = NomsuCode,
LuaCode = LuaCode,
Source = Source
2018-04-13 14:55:20 -07:00
}