diff --git a/aegisub/automation/autoload/select-overlaps.lua b/aegisub/automation/autoload/select-overlaps.lua deleted file mode 100644 index 16d6c029b..000000000 --- a/aegisub/automation/autoload/select-overlaps.lua +++ /dev/null @@ -1,31 +0,0 @@ -local tr = aegisub.gettext -script_name = tr("Select overlaps") -script_description = tr("Select lines which begin while another non-comment line is active") -script_author = "Thomas Goyne" -script_version = "2" -local select_overlaps -select_overlaps = function(subs) - local dialogue = { } - for i, line in ipairs(subs) do - if line.class == "dialogue" then - line.i = i - table.insert(dialogue, line) - end - end - table.sort(dialogue, function(a, b) - return a.start_time < b.start_time or (a.start_time == b.start_time and a.i < b.i) - end) - local end_time = 0 - local overlaps = { } - local _list_0 = dialogue - for _index_0 = 1, #_list_0 do - local line = _list_0[_index_0] - if line.start_time >= end_time then - end_time = line.end_time - else - table.insert(overlaps, line.i) - end - end - return overlaps -end -return aegisub.register_macro(script_name, script_description, select_overlaps) diff --git a/aegisub/automation/include/aegisub/re.lua b/aegisub/automation/include/aegisub/re.lua deleted file mode 100644 index 32413ed9c..000000000 --- a/aegisub/automation/include/aegisub/re.lua +++ /dev/null @@ -1,314 +0,0 @@ -local regex = aegisub.__init_regex() -local select_first -select_first = function(n, a, ...) - if n == 0 then - return - end - return a, select_first(n - 1, ...) -end -local unpack_args -unpack_args = function(...) - local userdata_start = nil - for i = 1, select('#', ...) do - local v = select(i, ...) - if type(v) == 'userdata' then - userdata_start = i - break - end - end - if not (userdata_start) then - return 0, ... - end - local flags = regex.process_flags(select(userdata_start, ...)) - if type(flags) == 'string' then - error(flags, 3) - end - return flags, select_first(userdata_start - 1, ...) -end -local check_arg -check_arg = function(arg, expected_type, argn, func_name, level) - if type(arg) ~= expected_type then - return error("Argument " .. tostring(argn) .. " to " .. tostring(func_name) .. " should be a '" .. tostring(expected_type) .. "', is '" .. tostring(type(arg)) .. "' (" .. tostring(arg) .. ")", level + 1) - end -end -local replace_match -replace_match = function(match, func, str, last, acc) - if last < match.last then - acc[#acc + 1] = str:sub(last, match.first - 1) - end - local repl = func(match.str, match.first, match.last) - if type(repl) == 'string' then - acc[#acc + 1] = repl - else - acc[#acc + 1] = match.str - end - return match.first, match.last + 1 -end -local do_single_replace_fun -do_single_replace_fun = function(re, func, str, acc, pos) - local matches = re:match(str, pos) - if not (matches) then - return pos - end - local start - if #matches == 1 then - start = 1 - else - start = 2 - end - local last = pos - local first - for i = start, #matches do - first, last = replace_match(matches[i], func, str, last, acc) - end - if first == last then - acc[#acc + 1] = str:sub(last, last) - last = last + 1 - end - return last, matches[1].first <= str:len() -end -local do_replace_fun -do_replace_fun = function(re, func, str, max) - local acc = { } - local pos = 1 - local i - for i = 1, max do - local more - pos, more = do_single_replace_fun(re, func, str, acc, pos) - if not (more) then - max = i - break - end - end - return table.concat(acc, '') .. str:sub(pos) -end -local RegEx -do - local start - local _parent_0 = nil - local _base_0 = { - _check_self = function(self) - if not (self.__class == RegEx) then - return error('re method called with invalid self. You probably used . when : is needed.', 3) - end - end, - gsplit = function(self, str, skip_empty, max_split) - self:_check_self() - check_arg(str, 'string', 2, 'gsplit', self._level) - if not max_split or max_split <= 0 then - max_split = str:len() - end - start = 1 - local prev = 1 - local do_split - do_split = function() - if not str or str:len() == 0 then - return - end - local first, last - if max_split > 0 then - first, last = regex.search(self._regex, str, start) - end - if not first or first > str:len() then - local ret = str:sub(prev, str:len()) - str = nil - return ret - end - local ret = str:sub(prev, first - 1) - prev = last + 1 - start = 1 + (function() - if start >= last then - return start - else - return last - end - end)() - if skip_empty and ret:len() == 0 then - return do_split() - else - max_split = max_split - 1 - return ret - end - end - return do_split - end, - split = function(self, str, skip_empty, max_split) - self:_check_self() - check_arg(str, 'string', 2, 'split', self._level) - return (function() - local _accum_0 = { } - local _len_0 = 1 - for v in self:gsplit(str, skip_empty, max_split) do - _accum_0[_len_0] = v - _len_0 = _len_0 + 1 - end - return _accum_0 - end)() - end, - gfind = function(self, str) - self:_check_self() - check_arg(str, 'string', 2, 'gfind', self._level) - start = 1 - return function() - local first, last = regex.search(self._regex, str, start) - if not (first) then - return - end - if last >= start then - start = last + 1 - else - start = start + 1 - end - return str:sub(first, last), first, last - end - end, - find = function(self, str) - self:_check_self() - check_arg(str, 'string', 2, 'find', self._level) - local ret = (function() - local _accum_0 = { } - local _len_0 = 1 - for s, f, l in self:gfind(str) do - _accum_0[_len_0] = { - str = s, - first = f, - last = l - } - _len_0 = _len_0 + 1 - end - return _accum_0 - end)() - return next(ret) and ret - end, - sub = function(self, str, repl, max_count) - self:_check_self() - check_arg(str, 'string', 2, 'sub', self._level) - if max_count ~= nil then - check_arg(max_count, 'number', 4, 'sub', self._level) - end - if not max_count or max_count == 0 then - max_count = str:len() + 1 - end - if type(repl) == 'function' then - return do_replace_fun(self, repl, str, max_count) - elseif type(repl) == 'string' then - return regex.replace(self._regex, repl, str, max_count) - else - return error("Argument 2 to sub should be a string or function, is '" .. tostring(type(repl)) .. "' (" .. tostring(repl) .. ")", self._level) - end - end, - gmatch = function(self, str, start) - self:_check_self() - check_arg(str, 'string', 2, 'gmatch', self._level) - if start then - start = start - 1 - else - start = 0 - end - local match = regex.match(self._regex, str, start) - local i = 1 - return function() - if not (match) then - return - end - local first, last = regex.get_match(match, i) - if not (first) then - return - end - i = i + 1 - return { - str = str:sub(first + start, last + start), - first = first + start, - last = last + start - } - end - end, - match = function(self, str, start) - self:_check_self() - check_arg(str, 'string', 2, 'match', self._level) - local ret = (function() - local _accum_0 = { } - local _len_0 = 1 - for v in self:gmatch(str, start) do - _accum_0[_len_0] = v - _len_0 = _len_0 + 1 - end - return _accum_0 - end)() - if next(ret) == nil then - return nil - end - return ret - end - } - _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end - local _class_0 = setmetatable({ - __init = function(self, _regex, _level) - self._regex, self._level = _regex, _level - end, - __base = _base_0, - __name = "RegEx", - __parent = _parent_0 - }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - 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 - local self = _class_0 - start = 1 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end - RegEx = _class_0 -end -local real_compile -real_compile = function(pattern, level, flags, stored_level) - if pattern == '' then - error('Regular expression must not be empty', level + 1) - end - local re = regex.compile(pattern, flags) - if type(re) == 'string' then - error(regex, level + 1) - end - return RegEx(re, stored_level or level + 1) -end -local invoke -invoke = function(str, pattern, fn, flags, ...) - local compiled_regex = real_compile(pattern, 3, flags) - return compiled_regex[fn](compiled_regex, str, ...) -end -local gen_wrapper -gen_wrapper = function(impl_name) - return function(str, pattern, ...) - check_arg(str, 'string', 1, impl_name, 2) - check_arg(pattern, 'string', 2, impl_name, 2) - return invoke(str, pattern, impl_name, unpack_args(...)) - end -end -local re = regex.init_flags(re) -re.compile = function(pattern, ...) - check_arg(pattern, 'string', 1, 'compile', 2) - return real_compile(pattern, 2, regex.process_flags(...), 2) -end -re.split = gen_wrapper('split') -re.gsplit = gen_wrapper('gsplit') -re.find = gen_wrapper('find') -re.gfind = gen_wrapper('gfind') -re.match = gen_wrapper('match') -re.gmatch = gen_wrapper('gmatch') -re.sub = gen_wrapper('sub') -return re diff --git a/aegisub/automation/include/aegisub/unicode.lua b/aegisub/automation/include/aegisub/unicode.lua deleted file mode 100644 index e889b0202..000000000 --- a/aegisub/automation/include/aegisub/unicode.lua +++ /dev/null @@ -1,58 +0,0 @@ -local unicode -unicode = { - charwidth = function(s, i) - local b = s:byte(i or 1) - if not b then - return 1 - elseif b < 128 then - return 1 - elseif b < 224 then - return 2 - elseif b < 240 then - return 3 - else - return 4 - end - end, - chars = function(s) - local curchar, i = 0, 1 - return function() - if i > s:len() then - return - end - local j = i - curchar = curchar + 1 - i = i + unicode.charwidth(s, i) - return s:sub(j, i - 1), curchar - end - end, - len = function(s) - local n = 0 - for c in unicode.chars(s) do - n = n + 1 - end - return n - end, - codepoint = function(s) - local b = s:byte(1) - if b < 128 then - return b - end - local res, w - if b < 224 then - res = b - 192 - w = 2 - elseif b < 240 then - res = b - 224 - w = 3 - else - res = b - 240 - w = 4 - end - for i = 2, w do - res = res * 64 + s:byte(i) - 128 - end - return res - end -} -return unicode diff --git a/aegisub/automation/include/aegisub/util.lua b/aegisub/automation/include/aegisub/util.lua deleted file mode 100644 index cd0380657..000000000 --- a/aegisub/automation/include/aegisub/util.lua +++ /dev/null @@ -1,242 +0,0 @@ -local sformat = string.format -local copy -copy = function(tbl) - return (function() - local _tbl_0 = { } - for k, v in pairs(tbl) do - _tbl_0[k] = v - end - return _tbl_0 - end)() -end -local deep_copy -deep_copy = function(tbl) - local seen = { } - copy = function(val) - if type(tbl) ~= 'table' then - return val - end - if seen[tbl] then - return seen[val] - end - seen[val] = tbl - return (function() - local _tbl_0 = { } - for k, v in pairs(val) do - _tbl_0[k] = copy(v) - end - return _tbl_0 - end)() - end - return copy(tbl) -end -local ass_color -ass_color = function(r, g, b) - return sformat("&H%02X%02X%02X&", b, g, r) -end -local ass_alpha -ass_alpha = function(a) - return sformat("&H%02X&", a) -end -local ass_style_color -ass_style_color = function(r, g, b, a) - return sformat("&H%02X%02X%02X%02X", a, b, g, r) -end -local extract_color -extract_color = function(s) - local a, b, g, r - a, b, g, r = s:match('&H(%x%x)(%x%x)(%x%x)(%x%x)') - if a then - return tonumber(r, 16), tonumber(g, 16), tonumber(b, 16), tonumber(a, 16) - end - b, g, r = s:match('&H(%x%x)(%x%x)(%x%x)&') - if b then - return tonumber(r, 16), tonumber(g, 16), tonumber(b, 16), 0 - end - a = s:match('&H(%x%x)&') - if a then - return 0, 0, 0, tonumber(a, 16) - end - r, g, b, a = s:match('#(%x%x)(%x?%x?)(%x?%x?)(%x?%x?)') - if r then - return tonumber(r, 16), tonumber(g, 16) or 0, tonumber(b, 16) or 0, tonumber(a, 16) or 0 - end -end -local alpha_from_style -alpha_from_style = function(scolor) - return ass_alpha(select(4, extract_color(scolor))) -end -local color_from_style -color_from_style = function(scolor) - local r, g, b = extract_color(scolor) - return ass_color(r or 0, g or 0, b or 0) -end -local HSV_to_RGB -HSV_to_RGB = function(H, S, V) - local r, g, b = 0, 0, 0 - if S == 0 then - r = self:clamp(V * 255, 0, 255) - g = r - b = r - else - H = math.abs(H) % 360 - local Hi = math.floor(H / 60) - local f = H / 60.0 - Hi - local p = V * (1 - S) - local q = V * (1 - f * S) - local t = V * (1 - (1 - f) * S) - if Hi == 0 then - r = V * 255.0 - g = t * 255.0 - b = p * 255.0 - elseif Hi == 1 then - r = q * 255.0 - g = V * 255.0 - b = p * 255.0 - elseif Hi == 2 then - r = p * 255.0 - g = V * 255.0 - b = t * 255.0 - elseif Hi == 3 then - r = p * 255.0 - g = q * 255.0 - b = V * 255.0 - elseif Hi == 4 then - r = t * 255.0 - g = p * 255.0 - b = V * 255.0 - elseif Hi == 5 then - r = V * 255.0 - g = p * 255.0 - b = q * 255.0 - else - error("math.floor(H % 360 / 60) should be [0, 6), is " .. tostring(Hi) .. "?") - end - end - return r, g, b -end -local HSL_to_RGB -HSL_to_RGB = function(H, S, L) - local r, g, b - H = math.abs(H) % 360 - S = clamp(S, 0, 1) - L = clamp(L, 0, 1) - if S == 0 then - r = L - g = L - b = L - else - local Q - if L < 0.5 then - Q = L * (1.0 + S) - else - Q = L + S - (L * S) - end - local P = 2.0 * L - Q - local Hk = H / 360 - local Tr, Tg, Tb - if Hk < 1 / 3 then - Tr = Hk + 1 / 3 - Tg = Hk - Tb = Hk + 2 / 3 - elseif Hk > 2 / 3 then - Tr = Hk - 2 / 3 - Tg = Hk - Tb = Hk - 1 / 3 - else - Tr = Hk + 1 / 3 - Tg = Hk - Tb = Hk - 1 / 3 - end - local get_component - get_component = function(T) - if T < 1 / 6 then - return P + ((Q - P) * 6.0 * T) - elseif 1 / 6 <= T and T < 1 / 2 then - return Q - elseif 1 / 2 <= T and T < 2 / 3 then - return P + ((Q - P) * (2 / 3 - T) * 6.0) - else - return P - end - end - r = get_component(Tr) - g = get_component(Tg) - b = get_component(Tb) - end - return math.floor(r * 255 + 0.5), math.floor(g * 255 + 0.5), math.floor(b * 255 + 0.5) -end -local trim -trim = function(s) - return s:gsub('^%s*(.-)%s*$', '%1') -end -local headtail -headtail = function(s) - local a, b, head, tail = s:find('(.-)%s+(.*)') - if a then - return head, tail - else - return s, '' - end -end -local words -words = function(s) - return function() - if s == '' then - return - end - local head, tail = headtail(s) - s = tail - return head - end -end -local clamp -clamp = function(val, min, max) - if val < min then - return min - elseif val > max then - return max - else - return val - end -end -local interpolate -interpolate = function(pct, min, max) - if pct <= 0 then - return min - elseif pct >= 1 then - return max - else - return pct * (max - min) + min - end -end -local interpolate_color -interpolate_color = function(pct, first, last) - local r1, g1, b1 = extract_color(first) - local r2, g2, b2 = extract_color(last) - local r, g, b = interpolate(pct, r1, r2), interpolate(pct, g1, g2), interpolate(pct, b1, b2) - return ass_color(r, g, b) -end -local interpolate_alpha -interpolate_alpha = function(pct, first, last) - return ass_alpha(interpolate(pct, select(4, extract_color(first)), select(4, extract_color(last)))) -end -return { - copy = copy, - deep_copy = deep_copy, - ass_color = ass_color, - ass_alpha = ass_alpha, - ass_style_color = ass_style_color, - extract_color = extract_color, - alpha_from_style = alpha_from_style, - color_from_style = color_from_style, - HSV_to_RGB = HSV_to_RGB, - HSL_to_RGB = HSL_to_RGB, - trim = trim, - headtail = headtail, - words = words, - clamp = clamp, - interpolate = interpolate, - interpolate_color = interpolate_color, - interpolate_alpha = interpolate_alpha -} diff --git a/aegisub/automation/include/moonscript.lua b/aegisub/automation/include/moonscript.lua new file mode 100644 index 000000000..4d31f9cda --- /dev/null +++ b/aegisub/automation/include/moonscript.lua @@ -0,0 +1,4952 @@ +package.preload['moonscript.base'] = function() + _G.moon_no_loader = true + return require("moonscript") + +end +package.preload['moonscript.compile.statement'] = function() + local util = require("moonscript.util") + local data = require("moonscript.data") + local reversed, unpack = util.reversed, util.unpack + local ntype + do + local _table_0 = require("moonscript.types") + ntype = _table_0.ntype + end + local concat, insert = table.concat, table.insert + local statement_compilers = { + raw = function(self, node) + return self:add(node[2]) + end, + lines = function(self, node) + local _list_0 = node[2] + for _index_0 = 1, #_list_0 do + local line = _list_0[_index_0] + self:add(line) + end + end, + declare = function(self, node) + local names = node[2] + local undeclared = self:declare(names) + if #undeclared > 0 then + do + local _with_0 = self:line("local ") + _with_0:append_list((function() + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = undeclared + for _index_0 = 1, #_list_0 do + local name = _list_0[_index_0] + _accum_0[_len_0] = self:name(name) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)(), ", ") + return _with_0 + end + end + end, + declare_with_shadows = function(self, node) + local names = node[2] + self:declare(names) + do + local _with_0 = self:line("local ") + _with_0:append_list((function() + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = names + for _index_0 = 1, #_list_0 do + local name = _list_0[_index_0] + _accum_0[_len_0] = self:name(name) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)(), ", ") + return _with_0 + end + end, + assign = function(self, node) + local _, names, values = unpack(node) + local undeclared = self:declare(names) + local declare = "local " .. concat(undeclared, ", ") + local has_fndef = false + local i = 1 + while i <= #values do + if ntype(values[i]) == "fndef" then + has_fndef = true + end + i = i + 1 + end + do + local _with_0 = self:line() + if #undeclared == #names and not has_fndef then + _with_0:append(declare) + else + if #undeclared > 0 then + self:add(declare) + end + _with_0:append_list((function() + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = names + for _index_0 = 1, #_list_0 do + local name = _list_0[_index_0] + _accum_0[_len_0] = self:value(name) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)(), ", ") + end + _with_0:append(" = ") + _with_0:append_list((function() + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = values + for _index_0 = 1, #_list_0 do + local v = _list_0[_index_0] + _accum_0[_len_0] = self:value(v) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)(), ", ") + return _with_0 + end + end, + ["return"] = function(self, node) + return self:line("return ", (function() + if node[2] ~= "" then + return self:value(node[2]) + end + end)()) + end, + ["break"] = function(self, node) + return "break" + end, + ["if"] = function(self, node) + local cond, block = node[2], node[3] + local root + do + local _with_0 = self:block(self:line("if ", self:value(cond), " then")) + _with_0:stms(block) + root = _with_0 + end + local current = root + local add_clause + add_clause = function(clause) + local type = clause[1] + local i = 2 + local next + if type == "else" then + next = self:block("else") + else + i = i + 1 + next = self:block(self:line("elseif ", self:value(clause[2]), " then")) + end + next:stms(clause[i]) + current.next = next + current = next + end + local _list_0 = node + for _index_0 = 4, #_list_0 do + cond = _list_0[_index_0] + add_clause(cond) + end + return root + end, + ["repeat"] = function(self, node) + local cond, block = unpack(node, 2) + do + local _with_0 = self:block("repeat", self:line("until ", self:value(cond))) + _with_0:stms(block) + return _with_0 + end + end, + ["while"] = function(self, node) + local _, cond, block = unpack(node) + do + local _with_0 = self:block(self:line("while ", self:value(cond), " do")) + _with_0:stms(block) + return _with_0 + end + end, + ["for"] = function(self, node) + local _, name, bounds, block = unpack(node) + local loop = self:line("for ", self:name(name), " = ", self:value({ + "explist", + unpack(bounds) + }), " do") + do + local _with_0 = self:block(loop) + _with_0:declare({ + name + }) + _with_0:stms(block) + return _with_0 + end + end, + foreach = function(self, node) + local _, names, exps, block = unpack(node) + local loop + do + local _with_0 = self:line() + _with_0:append("for ") + loop = _with_0 + end + do + local _with_0 = self:block(loop) + loop:append_list((function() + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = names + for _index_0 = 1, #_list_0 do + local name = _list_0[_index_0] + _accum_0[_len_0] = _with_0:name(name, false) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)(), ", ") + loop:append(" in ") + loop:append_list((function() + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = exps + for _index_0 = 1, #_list_0 do + local exp = _list_0[_index_0] + _accum_0[_len_0] = self:value(exp) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)(), ",") + loop:append(" do") + _with_0:declare(names) + _with_0:stms(block) + return _with_0 + end + end, + export = function(self, node) + local _, names = unpack(node) + if type(names) == "string" then + if names == "*" then + self.export_all = true + elseif names == "^" then + self.export_proper = true + end + else + self:declare(names) + end + return nil + end, + run = function(self, code) + code:call(self) + return nil + end, + group = function(self, node) + return self:stms(node[2]) + end, + ["do"] = function(self, node) + do + local _with_0 = self:block() + _with_0:stms(node[2]) + return _with_0 + end + end + } + return { + statement_compilers = statement_compilers + } + +end +package.preload['moonscript.compile.value'] = function() + local util = require("moonscript.util") + local data = require("moonscript.data") + local ntype + do + local _table_0 = require("moonscript.types") + ntype = _table_0.ntype + end + local user_error + do + local _table_0 = require("moonscript.errors") + user_error = _table_0.user_error + end + local concat, insert = table.concat, table.insert + local unpack = util.unpack + local table_delim = "," + local string_chars = { + ["\r"] = "\\r", + ["\n"] = "\\n" + } + local value_compilers = { + exp = function(self, node) + local _comp + _comp = function(i, value) + if i % 2 == 1 and value == "!=" then + value = "~=" + end + return self:value(value) + end + do + local _with_0 = self:line() + _with_0:append_list((function() + local _accum_0 = { } + local _len_0 = 1 + for i, v in ipairs(node) do + if i > 1 then + _accum_0[_len_0] = _comp(i, v) + _len_0 = _len_0 + 1 + end + end + return _accum_0 + end)(), " ") + return _with_0 + end + end, + explist = function(self, node) + do + local _with_0 = self:line() + _with_0:append_list((function() + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = node + for _index_0 = 2, #_list_0 do + local v = _list_0[_index_0] + _accum_0[_len_0] = self:value(v) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)(), ", ") + return _with_0 + end + end, + parens = function(self, node) + return self:line("(", self:value(node[2]), ")") + end, + string = function(self, node) + local _, delim, inner = unpack(node) + local end_delim = delim:gsub("%[", "]") + if delim == "'" or delim == '"' then + inner = inner:gsub("[\r\n]", string_chars) + end + return delim .. inner .. end_delim + end, + chain = function(self, node) + local callee = node[2] + if callee == -1 then + callee = self:get("scope_var") + if not callee then + user_error("Short-dot syntax must be called within a with block") + end + end + local sup = self:get("super") + if callee == "super" and sup then + return self:value(sup(self, node)) + end + local chain_item + chain_item = function(node) + local t, arg = unpack(node) + if t == "call" then + return "(", self:values(arg), ")" + elseif t == "index" then + return "[", self:value(arg), "]" + elseif t == "dot" then + return ".", tostring(arg) + elseif t == "colon" then + return ":", arg, chain_item(node[3]) + elseif t == "colon_stub" then + return user_error("Uncalled colon stub") + else + return error("Unknown chain action: " .. t) + end + end + local t = ntype(callee) + if (t == "self" or t == "self_class") and node[3] and ntype(node[3]) == "call" then + callee[1] = t .. "_colon" + end + local callee_value = self:value(callee) + if ntype(callee) == "exp" then + callee_value = self:line("(", callee_value, ")") + end + local actions + do + local _with_0 = self:line() + local _list_0 = node + for _index_0 = 3, #_list_0 do + local action = _list_0[_index_0] + _with_0:append(chain_item(action)) + end + actions = _with_0 + end + return self:line(callee_value, actions) + end, + fndef = function(self, node) + local _, args, whitelist, arrow, block = unpack(node) + local default_args = { } + local self_args = { } + local arg_names = (function() + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = args + for _index_0 = 1, #_list_0 do + local arg = _list_0[_index_0] + local name, default_value = unpack(arg) + if type(name) == "string" then + name = name + else + if name[1] == "self" or name[1] == "self_class" then + insert(self_args, name) + end + name = name[2] + end + if default_value then + insert(default_args, arg) + end + local _value_0 = name + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + if arrow == "fat" then + insert(arg_names, 1, "self") + end + do + local _with_0 = self:block() + if #whitelist > 0 then + _with_0:whitelist_names(whitelist) + end + local _list_0 = arg_names + for _index_0 = 1, #_list_0 do + local name = _list_0[_index_0] + _with_0:put_name(name) + end + local _list_1 = default_args + for _index_0 = 1, #_list_1 do + local default = _list_1[_index_0] + local name, value = unpack(default) + if type(name) == "table" then + name = name[2] + end + _with_0:stm({ + 'if', + { + 'exp', + name, + '==', + 'nil' + }, + { + { + 'assign', + { + name + }, + { + value + } + } + } + }) + end + local self_arg_values = (function() + local _accum_0 = { } + local _len_0 = 1 + local _list_2 = self_args + for _index_0 = 1, #_list_2 do + local arg = _list_2[_index_0] + _accum_0[_len_0] = arg[2] + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + if #self_args > 0 then + _with_0:stm({ + "assign", + self_args, + self_arg_values + }) + end + _with_0:stms(block) + if #args > #arg_names then + arg_names = (function() + local _accum_0 = { } + local _len_0 = 1 + local _list_2 = args + for _index_0 = 1, #_list_2 do + local arg = _list_2[_index_0] + _accum_0[_len_0] = arg[1] + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + end + _with_0.header = "function(" .. concat(arg_names, ", ") .. ")" + return _with_0 + end + end, + table = function(self, node) + local _, items = unpack(node) + do + local _with_0 = self:block("{", "}") + local format_line + format_line = function(tuple) + if #tuple == 2 then + local key, value = unpack(tuple) + if ntype(key) == "key_literal" and data.lua_keywords[key[2]] then + key = { + "string", + '"', + key[2] + } + end + local assign + if ntype(key) == "key_literal" then + assign = key[2] + else + assign = self:line("[", _with_0:value(key), "]") + end + _with_0:set("current_block", key) + local out = self:line(assign, " = ", _with_0:value(value)) + _with_0:set("current_block", nil) + return out + else + return self:line(_with_0:value(tuple[1])) + end + end + if items then + local count = #items + for i, tuple in ipairs(items) do + local line = format_line(tuple) + if not (count == i) then + line:append(table_delim) + end + _with_0:add(line) + end + end + return _with_0 + end + end, + minus = function(self, node) + return self:line("-", self:value(node[2])) + end, + temp_name = function(self, node, ...) + return node:get_name(self, ...) + end, + number = function(self, node) + return node[2] + end, + length = function(self, node) + return self:line("#", self:value(node[2])) + end, + ["not"] = function(self, node) + return self:line("not ", self:value(node[2])) + end, + self = function(self, node) + return "self." .. self:value(node[2]) + end, + self_class = function(self, node) + return "self.__class." .. self:value(node[2]) + end, + self_colon = function(self, node) + return "self:" .. self:value(node[2]) + end, + self_class_colon = function(self, node) + return "self.__class:" .. self:value(node[2]) + end, + raw_value = function(self, value) + local sup = self:get("super") + if value == "super" and sup then + return self:value(sup(self)) + end + if value == "..." then + self:send("varargs") + end + return tostring(value) + end + } + return { + value_compilers = value_compilers + } + +end +package.preload['moonscript.compile'] = function() + local util = require("moonscript.util") + local dump = require("moonscript.dump") + local transform = require("moonscript.transform") + local NameProxy, LocalName + do + local _table_0 = require("moonscript.transform.names") + NameProxy, LocalName = _table_0.NameProxy, _table_0.LocalName + end + local Set + do + local _table_0 = require("moonscript.data") + Set = _table_0.Set + end + local ntype, has_value + do + local _table_0 = require("moonscript.types") + ntype, has_value = _table_0.ntype, _table_0.has_value + end + local statement_compilers + do + local _table_0 = require("moonscript.compile.statement") + statement_compilers = _table_0.statement_compilers + end + local value_compilers + do + local _table_0 = require("moonscript.compile.value") + value_compilers = _table_0.value_compilers + end + local concat, insert = table.concat, table.insert + local pos_to_line, get_closest_line, trim, unpack = util.pos_to_line, util.get_closest_line, util.trim, util.unpack + local mtype = util.moon.type + local indent_char = " " + local Line, DelayedLine, Lines, Block, RootBlock + do + local _parent_0 = nil + local _base_0 = { + mark_pos = function(self, pos, line) + if line == nil then + line = #self + end + if not (self.posmap[line]) then + self.posmap[line] = pos + end + end, + add = function(self, item) + local _exp_0 = mtype(item) + if Line == _exp_0 then + item:render(self) + elseif Block == _exp_0 then + item:render(self) + else + self[#self + 1] = item + end + return self + end, + flatten_posmap = function(self, line_no, out) + if line_no == nil then + line_no = 0 + end + if out == nil then + out = { } + end + local posmap = self.posmap + for i, l in ipairs(self) do + local _exp_0 = mtype(l) + if "string" == _exp_0 or DelayedLine == _exp_0 then + line_no = line_no + 1 + out[line_no] = posmap[i] + elseif Lines == _exp_0 then + local _ + _, line_no = l:flatten_posmap(line_no, out) + else + error("Unknown item in Lines: " .. tostring(l)) + end + end + return out, line_no + end, + flatten = function(self, indent, buffer) + if indent == nil then + indent = nil + end + if buffer == nil then + buffer = { } + end + for i = 1, #self do + local l = self[i] + local t = mtype(l) + if t == DelayedLine then + l = l:render() + t = "string" + end + local _exp_0 = t + if "string" == _exp_0 then + if indent then + insert(buffer, indent) + end + insert(buffer, l) + if "string" == type(self[i + 1]) then + local lc = l:sub(-1) + if (lc == ")" or lc == "]") and self[i + 1]:sub(1, 1) == "(" then + insert(buffer, ";") + end + end + insert(buffer, "\n") + local last = l + elseif Lines == _exp_0 then + l:flatten(indent and indent .. indent_char or indent_char, buffer) + else + error("Unknown item in Lines: " .. tostring(l)) + end + end + return buffer + end, + __tostring = function(self) + local strip + strip = function(t) + if "table" == type(t) then + return (function() + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = t + for _index_0 = 1, #_list_0 do + local v = _list_0[_index_0] + _accum_0[_len_0] = strip(v) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + else + return t + end + end + return "Lines<" .. tostring(util.dump(strip(self)):sub(1, -2)) .. ">" + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.posmap = { } + end, + __base = _base_0, + __name = "Lines", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + 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 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Lines = _class_0 + end + do + local _parent_0 = nil + local _base_0 = { + pos = nil, + _append_single = function(self, item) + if Line == mtype(item) then + if not (self.pos) then + self.pos = item.pos + end + local _list_0 = item + for _index_0 = 1, #_list_0 do + local value = _list_0[_index_0] + self:_append_single(value) + end + else + insert(self, item) + end + return nil + end, + append_list = function(self, items, delim) + for i = 1, #items do + self:_append_single(items[i]) + if i < #items then + insert(self, delim) + end + end + return nil + end, + append = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local item = _list_0[_index_0] + self:_append_single(item) + end + return nil + end, + render = function(self, buffer) + local current = { } + local add_current + add_current = function() + buffer:add(concat(current)) + return buffer:mark_pos(self.pos) + end + local _list_0 = self + for _index_0 = 1, #_list_0 do + local chunk = _list_0[_index_0] + local _exp_0 = mtype(chunk) + if Block == _exp_0 then + local _list_1 = chunk:render(Lines()) + for _index_1 = 1, #_list_1 do + local block_chunk = _list_1[_index_1] + if "string" == type(block_chunk) then + insert(current, block_chunk) + else + add_current() + buffer:add(block_chunk) + current = { } + end + end + else + insert(current, chunk) + end + end + if #current > 0 then + add_current() + end + return buffer + end, + __tostring = function(self) + return "Line<" .. tostring(util.dump(self):sub(1, -2)) .. ">" + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, ...) + if _parent_0 then + return _parent_0.__init(self, ...) + end + end, + __base = _base_0, + __name = "Line", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + 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 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Line = _class_0 + end + do + local _parent_0 = nil + local _base_0 = { + prepare = function() end, + render = function(self) + self:prepare() + return concat(self) + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, fn) + self.prepare = fn + end, + __base = _base_0, + __name = "DelayedLine", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + 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 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + DelayedLine = _class_0 + end + do + local _parent_0 = nil + local _base_0 = { + header = "do", + footer = "end", + export_all = false, + export_proper = false, + __tostring = function(self) + local h + if "string" == type(self.header) then + h = self.header + else + h = unpack(self.header:render({ })) + end + return "Block<" .. tostring(h) .. "> <- " .. tostring(self.parent) + end, + set = function(self, name, value) + self._state[name] = value + end, + get = function(self, name) + return self._state[name] + end, + get_current = function(self, name) + return rawget(self._state, name) + end, + listen = function(self, name, fn) + self._listeners[name] = fn + end, + unlisten = function(self, name) + self._listeners[name] = nil + end, + send = function(self, name, ...) + do + local fn = self._listeners[name] + if fn then + return fn(self, ...) + end + end + end, + declare = function(self, names) + local undeclared = (function() + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = names + for _index_0 = 1, #_list_0 do + local _continue_0 = false + repeat + local name = _list_0[_index_0] + local is_local = false + local real_name + local _exp_0 = mtype(name) + if LocalName == _exp_0 then + is_local = true + real_name = name:get_name(self) + elseif NameProxy == _exp_0 then + real_name = name:get_name(self) + elseif "string" == _exp_0 then + real_name = name + end + if not (is_local or real_name and not self:has_name(real_name, true)) then + _continue_0 = true + break + end + self:put_name(real_name) + if self:name_exported(real_name) then + _continue_0 = true + break + end + local _value_0 = real_name + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 + _continue_0 = true + until true + if not _continue_0 then + break + end + end + return _accum_0 + end)() + return undeclared + end, + whitelist_names = function(self, names) + self._name_whitelist = Set(names) + end, + name_exported = function(self, name) + if self.export_all then + return true + end + if self.export_proper and name:match("^%u") then + return true + end + end, + put_name = function(self, name, ...) + local value = ... + if select("#", ...) == 0 then + value = true + end + if NameProxy == mtype(name) then + name = name:get_name(self) + end + self._names[name] = value + end, + has_name = function(self, name, skip_exports) + if not skip_exports and self:name_exported(name) then + return true + end + local yes = self._names[name] + if yes == nil and self.parent then + if not self._name_whitelist or self._name_whitelist[name] then + return self.parent:has_name(name, true) + end + else + return yes + end + end, + free_name = function(self, prefix, dont_put) + prefix = prefix or "moon" + local searching = true + local name, i = nil, 0 + while searching do + name = concat({ + "", + prefix, + i + }, "_") + i = i + 1 + searching = self:has_name(name, true) + end + if not dont_put then + self:put_name(name) + end + return name + end, + init_free_var = function(self, prefix, value) + local name = self:free_name(prefix, true) + self:stm({ + "assign", + { + name + }, + { + value + } + }) + return name + end, + add = function(self, item) + self._lines:add(item) + return item + end, + render = function(self, buffer) + buffer:add(self.header) + buffer:mark_pos(self.pos) + if self.next then + buffer:add(self._lines) + self.next:render(buffer) + else + if #self._lines == 0 and "string" == type(buffer[#buffer]) then + buffer[#buffer] = buffer[#buffer] .. (" " .. (unpack(Lines():add(self.footer)))) + else + buffer:add(self._lines) + buffer:add(self.footer) + buffer:mark_pos(self.pos) + end + end + return buffer + end, + block = function(self, header, footer) + return Block(self, header, footer) + end, + line = function(self, ...) + do + local _with_0 = Line() + _with_0:append(...) + return _with_0 + end + end, + is_stm = function(self, node) + return statement_compilers[ntype(node)] ~= nil + end, + is_value = function(self, node) + local t = ntype(node) + return value_compilers[t] ~= nil or t == "value" + end, + name = function(self, node, ...) + return self:value(node, ...) + end, + value = function(self, node, ...) + node = self.transform.value(node) + local action + if type(node) ~= "table" then + action = "raw_value" + else + action = node[1] + end + local fn = value_compilers[action] + if not fn then + error("Failed to compile value: " .. dump.value(node)) + end + local out = fn(self, node, ...) + if type(node) == "table" and node[-1] then + if type(out) == "string" then + do + local _with_0 = Line() + _with_0:append(out) + out = _with_0 + end + end + out.pos = node[-1] + end + return out + end, + values = function(self, values, delim) + delim = delim or ', ' + do + local _with_0 = Line() + _with_0:append_list((function() + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = values + for _index_0 = 1, #_list_0 do + local v = _list_0[_index_0] + _accum_0[_len_0] = self:value(v) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)(), delim) + return _with_0 + end + end, + stm = function(self, node, ...) + if not node then + return + end + node = self.transform.statement(node) + local result + do + local fn = statement_compilers[ntype(node)] + if fn then + result = fn(self, node, ...) + else + if has_value(node) then + result = self:stm({ + "assign", + { + "_" + }, + { + node + } + }) + else + result = self:value(node) + end + end + end + if result then + if type(node) == "table" and type(result) == "table" and node[-1] then + result.pos = node[-1] + end + self:add(result) + end + return nil + end, + stms = function(self, stms, ret) + if ret then + error("deprecated stms call, use transformer") + end + local current_stms, current_stm_i + do + local _obj_0 = self + current_stms, current_stm_i = _obj_0.current_stms, _obj_0.current_stm_i + end + self.current_stms = stms + for i = 1, #stms do + self.current_stm_i = i + self:stm(stms[i]) + end + self.current_stms = current_stms + self.current_stm_i = current_stm_i + return nil + end, + splice = function(self, fn) + local lines = { + "lines", + self._lines + } + self._lines = Lines() + return self:stms(fn(lines)) + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, parent, header, footer) + self.parent, self.header, self.footer = parent, header, footer + self._lines = Lines() + self._names = { } + self._state = { } + self._listeners = { } + do + local _with_0 = transform + self.transform = { + value = _with_0.Value:bind(self), + statement = _with_0.Statement:bind(self) + } + end + if self.parent then + self.root = self.parent.root + self.indent = self.parent.indent + 1 + setmetatable(self._state, { + __index = self.parent._state + }) + return setmetatable(self._listeners, { + __index = self.parent._listeners + }) + else + self.indent = 0 + end + end, + __base = _base_0, + __name = "Block", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + 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 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Block = _class_0 + end + do + local _parent_0 = Block + local _base_0 = { + __tostring = function(self) + return "RootBlock<>" + end, + root_stms = function(self, stms) + if not (self.options.implicitly_return_root == false) then + stms = transform.Statement.transformers.root_stms(self, stms) + end + return self:stms(stms) + end, + render = function(self) + local buffer = self._lines:flatten() + if buffer[#buffer] == "\n" then + buffer[#buffer] = nil + end + return table.concat(buffer) + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, options) + self.options = options + self.root = self + return _parent_0.__init(self) + end, + __base = _base_0, + __name = "RootBlock", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + 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 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + RootBlock = _class_0 + end + local format_error + format_error = function(msg, pos, file_str) + local line = pos_to_line(file_str, pos) + local line_str + line_str, line = get_closest_line(file_str, line) + line_str = line_str or "" + return concat({ + "Compile error: " .. msg, + (" [%d] >> %s"):format(line, trim(line_str)) + }, "\n") + end + local value + value = function(value) + local out = nil + do + local _with_0 = RootBlock() + _with_0:add(_with_0:value(value)) + out = _with_0:render() + end + return out + end + local tree + tree = function(tree, options) + if options == nil then + options = { } + end + assert(tree, "missing tree") + local scope = (options.scope or RootBlock)(options) + local runner = coroutine.create(function() + return scope:root_stms(tree) + end) + local success, err = coroutine.resume(runner) + if not success then + local error_msg + if type(err) == "table" then + local error_type = err[1] + if error_type == "user-error" then + error_msg = err[2] + else + error_msg = error("Unknown error thrown", util.dump(error_msg)) + end + else + error_msg = concat({ + err, + debug.traceback(runner) + }, "\n") + end + return nil, error_msg, scope.last_pos + else + local lua_code = scope:render() + local posmap = scope._lines:flatten_posmap() + return lua_code, posmap + end + end + do + local _with_0 = require("moonscript.data") + local data = _with_0 + for name, cls in pairs({ + Line = Line, + Lines = Lines, + DelayedLine = DelayedLine + }) do + data[name] = cls + end + end + return { + tree = tree, + value = value, + format_error = format_error, + Block = Block, + RootBlock = RootBlock + } + +end +package.preload['moonscript.data'] = function() + local concat, remove, insert = table.concat, table.remove, table.insert + local Set + Set = function(items) + local self = { } + local _list_0 = items + for _index_0 = 1, #_list_0 do + local key = _list_0[_index_0] + self[key] = true + end + return self + end + local Stack + do + local _parent_0 = nil + local _base_0 = { + __tostring = function(self) + return "" + end, + pop = function(self) + return remove(self) + end, + push = function(self, value) + insert(self, value) + return value + end, + top = function(self) + return self[#self] + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local v = _list_0[_index_0] + self:push(v) + end + return nil + end, + __base = _base_0, + __name = "Stack", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + 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 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Stack = _class_0 + end + local lua_keywords = Set({ + 'and', + 'break', + 'do', + 'else', + 'elseif', + 'end', + 'false', + 'for', + 'function', + 'if', + 'in', + 'local', + 'nil', + 'not', + 'or', + 'repeat', + 'return', + 'then', + 'true', + 'until', + 'while' + }) + return { + Set = Set, + Stack = Stack, + lua_keywords = lua_keywords + } + +end +package.preload['moonscript.dump'] = function() + local flat_value + flat_value = function(op, depth) + if depth == nil then + depth = 1 + end + if type(op) == "string" then + return '"' .. op .. '"' + end + if type(op) ~= "table" then + return tostring(op) + end + local items = (function() + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = op + for _index_0 = 1, #_list_0 do + local item = _list_0[_index_0] + _accum_0[_len_0] = flat_value(item, depth + 1) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local pos = op[-1] + return "{" .. (pos and "[" .. pos .. "] " or "") .. table.concat(items, ", ") .. "}" + end + local value + value = function(op) + return flat_value(op) + end + local tree + tree = function(block) + local _list_0 = block + for _index_0 = 1, #_list_0 do + value = _list_0[_index_0] + print(flat_value(value)) + end + end + return { + value = value, + tree = tree + } + +end +package.preload['moonscript.errors'] = function() + local util = require("moonscript.util") + local lpeg = require("lpeg") + local concat, insert = table.concat, table.insert + local split, pos_to_line = util.split, util.pos_to_line + local user_error + user_error = function(...) + return error({ + "user-error", + ... + }) + end + local lookup_line + lookup_line = function(fname, pos, cache) + if not cache[fname] then + do + local _with_0 = io.open(fname) + cache[fname] = _with_0:read("*a") + _with_0:close() + end + end + return pos_to_line(cache[fname], pos) + end + local reverse_line_number + reverse_line_number = function(fname, line_table, line_num, cache) + for i = line_num, 0, -1 do + if line_table[i] then + return lookup_line(fname, line_table[i], cache) + end + end + return "unknown" + end + local truncate_traceback + truncate_traceback = function(traceback, chunk_func) + if chunk_func == nil then + chunk_func = "moonscript_chunk" + end + traceback = split(traceback, "\n") + local stop = #traceback + while stop > 1 do + if traceback[stop]:match(chunk_func) then + break + end + stop = stop - 1 + end + traceback = (function() + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = traceback + local _max_0 = stop + for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do + local t = _list_0[_index_0] + _accum_0[_len_0] = t + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local rep = "function '" .. chunk_func .. "'" + traceback[#traceback] = traceback[#traceback]:gsub(rep, "main chunk") + return concat(traceback, "\n") + end + local rewrite_traceback + rewrite_traceback = function(text, err) + local line_tables = require("moonscript.line_tables") + local V, S, Ct, C = lpeg.V, lpeg.S, lpeg.Ct, lpeg.C + local header_text = "stack traceback:" + local Header, Line = V("Header"), V("Line") + local Break = lpeg.S("\n") + local g = lpeg.P({ + Header, + Header = header_text * Break * Ct(Line ^ 1), + Line = "\t" * C((1 - Break) ^ 0) * (Break + -1) + }) + local cache = { } + local rewrite_single + rewrite_single = function(trace) + local fname, line, msg = trace:match('^%[string "(.-)"]:(%d+): (.*)$') + local tbl = line_tables[fname] + if fname and tbl then + return concat({ + fname, + ":", + reverse_line_number(fname, tbl, line, cache), + ": ", + "(", + line, + ") ", + msg + }) + else + return trace + end + end + err = rewrite_single(err) + local match = g:match(text) + if not (match) then + return nil + end + for i, trace in ipairs(match) do + match[i] = rewrite_single(trace) + end + return concat({ + "moon: " .. err, + header_text, + "\t" .. concat(match, "\n\t") + }, "\n") + end + return { + rewrite_traceback = rewrite_traceback, + truncate_traceback = truncate_traceback, + user_error = user_error + } + +end +package.preload['moonscript'] = function() + local compile = require("moonscript.compile") + local parse = require("moonscript.parse") + local concat, insert = table.concat, table.insert + local split, dump, get_options, unpack + do + local _table_0 = require("moonscript.util") + split, dump, get_options, unpack = _table_0.split, _table_0.dump, _table_0.get_options, _table_0.unpack + end + local lua = { + loadstring = loadstring, + load = load + } + local dirsep, line_tables, create_moonpath, to_lua, moon_loader, init_loader, loadstring, loadfile, dofile + dirsep = "/" + line_tables = require("moonscript.line_tables") + create_moonpath = function(package_path) + local paths = split(package_path, ";") + for i, path in ipairs(paths) do + local p = path:match("^(.-)%.lua$") + if p then + paths[i] = p .. ".moon" + end + end + return concat(paths, ";") + end + to_lua = function(text, options) + if options == nil then + options = { } + end + if "string" ~= type(text) then + local t = type(text) + return nil, "expecting string (got " .. t .. ")", 2 + end + local tree, err = parse.string(text) + if not tree then + return nil, err + end + local code, ltable, pos = compile.tree(tree, options) + if not code then + return nil, compile.format_error(ltable, pos, text), 2 + end + return code, ltable + end + moon_loader = function(name) + local name_path = name:gsub("%.", dirsep) + local file, file_path + local _list_0 = split(package.moonpath, ";") + for _index_0 = 1, #_list_0 do + local path = _list_0[_index_0] + file_path = path:gsub("?", name_path) + file = io.open(file_path) + if file then + break + end + end + if file then + local text = file:read("*a") + file:close() + return loadstring(text, file_path) + else + return nil, "Could not find moon file" + end + end + if not package.moonpath then + package.moonpath = create_moonpath(package.path) + end + init_loader = function() + return insert(package.loaders or package.searchers, 2, moon_loader) + end + if not (_G.moon_no_loader) then + init_loader() + end + loadstring = function(...) + local options, str, chunk_name, mode, env = get_options(...) + chunk_name = chunk_name or "=(moonscript.loadstring)" + local code, ltable_or_err = to_lua(str, options) + if not (code) then + return nil, ltable_or_err + end + if chunk_name then + line_tables[chunk_name] = ltable_or_err + end + return (lua.loadstring or lua.load)(code, chunk_name, unpack({ + mode, + env + })) + end + loadfile = function(fname, ...) + local file, err = io.open(fname) + if not (file) then + return nil, err + end + local text = assert(file:read("*a")) + file:close() + return loadstring(text, fname, ...) + end + dofile = function(...) + local f = assert(loadfile(...)) + return f() + end + return { + _NAME = "moonscript", + to_lua = to_lua, + moon_chunk = moon_chunk, + moon_loader = moon_loader, + dirsep = dirsep, + dofile = dofile, + loadfile = loadfile, + loadstring = loadstring + } + +end +package.preload['moonscript.line_tables'] = function() + return { } + +end +package.preload['moonscript.parse'] = function() + + local util = require"moonscript.util" + + local lpeg = require"lpeg" + + local debug_grammar = false + + local data = require"moonscript.data" + local types = require"moonscript.types" + + local ntype = types.ntype + + local dump = util.dump + local trim = util.trim + + local getfenv = util.getfenv + local setfenv = util.setfenv + local unpack = util.unpack + + local Stack = data.Stack + + local function count_indent(str) + local sum = 0 + for v in str:gmatch("[\t ]") do + if v == ' ' then sum = sum + 1 end + if v == '\t' then sum = sum + 4 end + end + return sum + end + + local R, S, V, P = lpeg.R, lpeg.S, lpeg.V, lpeg.P + local C, Ct, Cmt, Cg, Cb, Cc = lpeg.C, lpeg.Ct, lpeg.Cmt, lpeg.Cg, lpeg.Cb, lpeg.Cc + + lpeg.setmaxstack(10000) + + local White = S" \t\r\n"^0 + local _Space = S" \t"^0 + local Break = P"\r"^-1 * P"\n" + local Stop = Break + -1 + local Indent = C(S"\t "^0) / count_indent + + local Comment = P"--" * (1 - S"\r\n")^0 * #Stop + local Space = _Space * Comment^-1 + local SomeSpace = S" \t"^1 * Comment^-1 + + local SpaceBreak = Space * Break + local EmptyLine = SpaceBreak + + local AlphaNum = R("az", "AZ", "09", "__") + + local _Name = C(R("az", "AZ", "__") * AlphaNum^0) + local Name = Space * _Name + + local Num = P"0x" * R("09", "af", "AF")^1 + + ( + R"09"^1 * (P"." * R"09"^1)^-1 + + P"." * R"09"^1 + ) * (S"eE" * P"-"^-1 * R"09"^1)^-1 + + Num = Space * (Num / function(value) return {"number", value} end) + + local FactorOp = Space * C(S"+-") + local TermOp = Space * C(S"*/%^") + + local Shebang = P"#!" * P(1 - Stop)^0 + + -- can't have P(false) because it causes preceding patterns not to run + local Cut = P(function() return false end) + + local function ensure(patt, finally) + return patt * finally + finally * Cut + end + + -- auto declare Proper variables with lpeg.V + local function wrap_env(fn) + local env = getfenv(fn) + local wrap_name = V + + if debug_grammar then + local indent = 0 + local indent_char = " " + + local function iprint(...) + local args = {...} + for i=1,#args do + args[i] = tostring(args[i]) + end + + io.stdout:write(indent_char:rep(indent) .. table.concat(args, ", ") .. "\n") + end + + wrap_name = function(name) + local v = V(name) + v = Cmt("", function() + iprint("* " .. name) + indent = indent + 1 + return true + end) * Cmt(v, function(str, pos, ...) + iprint(name, true) + indent = indent - 1 + return true, ... + end) + Cmt("", function() + iprint(name, false) + indent = indent - 1 + return false + end) + return v + end + end + + return setfenv(fn, setmetatable({}, { + __index = function(self, name) + local value = env[name] + if value ~= nil then return value end + + if name:match"^[A-Z][A-Za-z0-9]*$" then + local v = wrap_name(name) + rawset(self, name, v) + return v + end + error("unknown variable referenced: "..name) + end + })) + end + + local function extract_line(str, start_pos) + str = str:sub(start_pos) + m = str:match"^(.-)\n" + if m then return m end + return str:match"^.-$" + end + + local function mark(name) + return function(...) + return {name, ...} + end + end + + local function insert_pos(pos, value) + if type(value) == "table" then + value[-1] = pos + end + return value + end + + local function pos(patt) + return (lpeg.Cp() * patt) / insert_pos + end + + local function got(what) + return Cmt("", function(str, pos, ...) + local cap = {...} + print("++ got "..what, "["..extract_line(str, pos).."]") + return true + end) + end + + local function flatten(tbl) + if #tbl == 1 then + return tbl[1] + end + return tbl + end + + local function flatten_or_mark(name) + return function(tbl) + if #tbl == 1 then return tbl[1] end + table.insert(tbl, 1, name) + return tbl + end + end + + -- makes sure the last item in a chain is an index + local _chain_assignable = { index = true, dot = true, slice = true } + + local function is_assignable(node) + local t = ntype(node) + return t == "self" or t == "value" or t == "self_class" or + t == "chain" and _chain_assignable[ntype(node[#node])] or + t == "table" + end + + local function check_assignable(str, pos, value) + if is_assignable(value) then + return true, value + end + return false + end + + local flatten_explist = flatten_or_mark"explist" + local function format_assign(lhs_exps, assign) + if not assign then + return flatten_explist(lhs_exps) + end + + for _, assign_exp in ipairs(lhs_exps) do + if not is_assignable(assign_exp) then + error {assign_exp, "left hand expression is not assignable"} + end + end + + local t = ntype(assign) + if t == "assign" then + return {"assign", lhs_exps, unpack(assign, 2)} + elseif t == "update" then + return {"update", lhs_exps[1], unpack(assign, 2)} + end + + error "unknown assign expression" + end + + -- the if statement only takes a single lhs, so we wrap in table to git to + -- "assign" tuple format + local function format_single_assign(lhs, assign) + if assign then + return format_assign({lhs}, assign) + end + return lhs + end + + local function sym(chars) + return Space * chars + end + + local function symx(chars) + return chars + end + + local function simple_string(delim, allow_interpolation) + local inner = P('\\'..delim) + "\\\\" + (1 - P(delim)) + if allow_interpolation then + inter = symx"#{" * V"Exp" * sym"}" + inner = (C((inner - inter)^1) + inter / mark"interpolate")^0 + else + inner = C(inner^0) + end + + return C(symx(delim)) * + inner * sym(delim) / mark"string" + end + + local function wrap_func_arg(value) + return {"call", {value}} + end + + -- DOCME + local function flatten_func(callee, args) + if #args == 0 then return callee end + + args = {"call", args} + if ntype(callee) == "chain" then + -- check for colon stub that needs arguments + if ntype(callee[#callee]) == "colon_stub" then + local stub = callee[#callee] + stub[1] = "colon" + table.insert(stub, args) + else + table.insert(callee, args) + end + + return callee + end + + return {"chain", callee, args} + end + + local function flatten_string_chain(str, chain, args) + if not chain then return str end + return flatten_func({"chain", str, unpack(chain)}, args) + end + + -- transforms a statement that has a line decorator + local function wrap_decorator(stm, dec) + if not dec then return stm end + return { "decorated", stm, dec } + end + + -- wrap if statement if there is a conditional decorator + local function wrap_if(stm, cond) + if cond then + local pass, fail = unpack(cond) + if fail then fail = {"else", {fail}} end + return {"if", cond[2], {stm}, fail} + end + return stm + end + + local function check_lua_string(str, pos, right, left) + return #left == #right + end + + -- :name in table literal + local function self_assign(name) + return {{"key_literal", name}, name} + end + + local err_msg = "Failed to parse:%s\n [%d] >> %s" + + local build_grammar = wrap_env(function() + local _indent = Stack(0) -- current indent + local _do_stack = Stack(0) + + local last_pos = 0 -- used to know where to report error + local function check_indent(str, pos, indent) + last_pos = pos + return _indent:top() == indent + end + + local function advance_indent(str, pos, indent) + local top = _indent:top() + if top ~= -1 and indent > _indent:top() then + _indent:push(indent) + return true + end + end + + local function push_indent(str, pos, indent) + _indent:push(indent) + return true + end + + local function pop_indent(str, pos) + if not _indent:pop() then error("unexpected outdent") end + return true + end + + + local function check_do(str, pos, do_node) + local top = _do_stack:top() + if top == nil or top then + return true, do_node + end + return false + end + + local function disable_do(str_pos) + _do_stack:push(false) + return true + end + + local function enable_do(str_pos) + _do_stack:push(true) + return true + end + + local function pop_do(str, pos) + if nil == _do_stack:pop() then error("unexpected do pop") end + return true + end + + local DisableDo = Cmt("", disable_do) + local EnableDo = Cmt("", enable_do) + local PopDo = Cmt("", pop_do) + + local keywords = {} + local function key(chars) + keywords[chars] = true + return Space * chars * -AlphaNum + end + + local function op(word) + local patt = Space * C(word) + if word:match("^%w*$") then + keywords[word] = true + patt = patt * -AlphaNum + end + return patt + end + + -- make sure name is not a keyword + local Name = Cmt(Name, function(str, pos, name) + if keywords[name] then return false end + return true + end) / trim + + local SelfName = Space * "@" * ( + "@" * (_Name / mark"self_class" + Cc"self.__class") + + _Name / mark"self" + Cc"self") + + local KeyName = SelfName + Space * _Name / mark"key_literal" + + local Name = SelfName + Name + Space * "..." / trim + + local g = lpeg.P{ + File, + File = Shebang^-1 * (Block + Ct""), + Block = Ct(Line * (Break^1 * Line)^0), + CheckIndent = Cmt(Indent, check_indent), -- validates line is in correct indent + Line = (CheckIndent * Statement + Space * #Stop), + + Statement = pos( + Import + While + With + For + ForEach + Switch + Return + + Local + Export + BreakLoop + + Ct(ExpList) * (Update + Assign)^-1 / format_assign + ) * Space * (( + -- statement decorators + key"if" * Exp * (key"else" * Exp)^-1 * Space / mark"if" + + key"unless" * Exp / mark"unless" + + CompInner / mark"comprehension" + ) * Space)^-1 / wrap_decorator, + + Body = Space^-1 * Break * EmptyLine^0 * InBlock + Ct(Statement), -- either a statement, or an indented block + + Advance = #Cmt(Indent, advance_indent), -- Advances the indent, gives back whitespace for CheckIndent + PushIndent = Cmt(Indent, push_indent), + PreventIndent = Cmt(Cc(-1), push_indent), + PopIndent = Cmt("", pop_indent), + InBlock = Advance * Block * PopIndent, + + Local = key"local" * ((op"*" + op"^") / mark"declare_glob" + Ct(NameList) / mark"declare_with_shadows"), + + Import = key"import" * Ct(ImportNameList) * key"from" * Exp / mark"import", + ImportName = (sym"\\" * Ct(Cc"colon_stub" * Name) + Name), + ImportNameList = ImportName * (sym"," * ImportName)^0, + + NameList = Name * (sym"," * Name)^0, + + BreakLoop = Ct(key"break"/trim) + Ct(key"continue"/trim), + + Return = key"return" * (ExpListLow/mark"explist" + C"") / mark"return", + + WithExp = Ct(ExpList) * Assign^-1 / format_assign, + With = key"with" * DisableDo * ensure(WithExp, PopDo) * key"do"^-1 * Body / mark"with", + + Switch = key"switch" * DisableDo * ensure(Exp, PopDo) * key"do"^-1 * Space^-1 * Break * SwitchBlock / mark"switch", + + SwitchBlock = EmptyLine^0 * Advance * Ct(SwitchCase * (Break^1 * SwitchCase)^0 * (Break^1 * SwitchElse)^-1) * PopIndent, + SwitchCase = key"when" * Ct(ExpList) * key"then"^-1 * Body / mark"case", + SwitchElse = key"else" * Body / mark"else", + + IfCond = Exp * Assign^-1 / format_single_assign, + + If = key"if" * IfCond * key"then"^-1 * Body * + ((Break * CheckIndent)^-1 * EmptyLine^0 * key"elseif" * pos(IfCond) * key"then"^-1 * Body / mark"elseif")^0 * + ((Break * CheckIndent)^-1 * EmptyLine^0 * key"else" * Body / mark"else")^-1 / mark"if", + + Unless = key"unless" * IfCond * key"then"^-1 * Body * + ((Break * CheckIndent)^-1 * EmptyLine^0 * key"else" * Body / mark"else")^-1 / mark"unless", + + While = key"while" * DisableDo * ensure(Exp, PopDo) * key"do"^-1 * Body / mark"while", + + For = key"for" * DisableDo * ensure(Name * sym"=" * Ct(Exp * sym"," * Exp * (sym"," * Exp)^-1), PopDo) * + key"do"^-1 * Body / mark"for", + + ForEach = key"for" * Ct(AssignableNameList) * key"in" * DisableDo * ensure(Ct(sym"*" * Exp / mark"unpack" + ExpList), PopDo) * key"do"^-1 * Body / mark"foreach", + + Do = key"do" * Body / mark"do", + + Comprehension = sym"[" * Exp * CompInner * sym"]" / mark"comprehension", + + TblComprehension = sym"{" * Ct(Exp * (sym"," * Exp)^-1) * CompInner * sym"}" / mark"tblcomprehension", + + CompInner = Ct((CompForEach + CompFor) * CompClause^0), + CompForEach = key"for" * Ct(NameList) * key"in" * (sym"*" * Exp / mark"unpack" + Exp) / mark"foreach", + CompFor = key "for" * Name * sym"=" * Ct(Exp * sym"," * Exp * (sym"," * Exp)^-1) / mark"for", + CompClause = CompFor + CompForEach + key"when" * Exp / mark"when", + + Assign = sym"=" * (Ct(With + If + Switch) + Ct(TableBlock + ExpListLow)) / mark"assign", + Update = ((sym"..=" + sym"+=" + sym"-=" + sym"*=" + sym"/=" + sym"%=" + sym"or=" + sym"and=") / trim) * Exp / mark"update", + + -- we can ignore precedence for now + OtherOps = op"or" + op"and" + op"<=" + op">=" + op"~=" + op"!=" + op"==" + op".." + op"<" + op">", + + Assignable = Cmt(DotChain + Chain, check_assignable) + Name, + AssignableList = Assignable * (sym"," * Assignable)^0, + + Exp = Ct(Value * ((OtherOps + FactorOp + TermOp) * Value)^0) / flatten_or_mark"exp", + + -- Exp = Ct(Factor * (OtherOps * Factor)^0) / flatten_or_mark"exp", + -- Factor = Ct(Term * (FactorOp * Term)^0) / flatten_or_mark"exp", + -- Term = Ct(Value * (TermOp * Value)^0) / flatten_or_mark"exp", + + SimpleValue = + If + Unless + + Switch + + With + + ClassDecl + + ForEach + For + While + + Cmt(Do, check_do) + + sym"-" * -SomeSpace * Exp / mark"minus" + + sym"#" * Exp / mark"length" + + key"not" * Exp / mark"not" + + TblComprehension + + TableLit + + Comprehension + + FunLit + + Num, + + ChainValue = -- a function call or an object access + StringChain + + ((Chain + DotChain + Callable) * Ct(InvokeArgs^-1)) / flatten_func, + + Value = pos( + SimpleValue + + Ct(KeyValueList) / mark"table" + + ChainValue), + + SliceValue = SimpleValue + ChainValue, + + StringChain = String * + (Ct((ColonCall + ColonSuffix) * ChainTail^-1) * Ct(InvokeArgs^-1))^-1 / flatten_string_chain, + + String = Space * DoubleString + Space * SingleString + LuaString, + SingleString = simple_string("'"), + DoubleString = simple_string('"', true), + + LuaString = Cg(LuaStringOpen, "string_open") * Cb"string_open" * Break^-1 * + C((1 - Cmt(C(LuaStringClose) * Cb"string_open", check_lua_string))^0) * + LuaStringClose / mark"string", + + LuaStringOpen = sym"[" * P"="^0 * "[" / trim, + LuaStringClose = "]" * P"="^0 * "]", + + Callable = Name + Parens / mark"parens", + Parens = sym"(" * Exp * sym")", + + FnArgs = symx"(" * Ct(ExpList^-1) * sym")" + sym"!" * -P"=" * Ct"", + + ChainTail = ChainItem^1 * ColonSuffix^-1 + ColonSuffix, + + -- a list of funcalls and indexes on a callable + Chain = Callable * ChainTail / mark"chain", + + -- shorthand dot call for use in with statement + DotChain = + (sym"." * Cc(-1) * (_Name / mark"dot") * ChainTail^-1) / mark"chain" + + (sym"\\" * Cc(-1) * ( + (_Name * Invoke / mark"colon") * ChainTail^-1 + + (_Name / mark"colon_stub") + )) / mark"chain", + + ChainItem = + Invoke + + Slice + + symx"[" * Exp/mark"index" * sym"]" + + symx"." * _Name/mark"dot" + + ColonCall, + + Slice = symx"[" * (SliceValue + Cc(1)) * sym"," * (SliceValue + Cc"") * + (sym"," * SliceValue)^-1 *sym"]" / mark"slice", + + ColonCall = symx"\\" * (_Name * Invoke) / mark"colon", + ColonSuffix = symx"\\" * _Name / mark"colon_stub", + + Invoke = FnArgs/mark"call" + + SingleString / wrap_func_arg + + DoubleString / wrap_func_arg, + + TableValue = KeyValue + Ct(Exp), + + TableLit = sym"{" * Ct( + TableValueList^-1 * sym","^-1 * + (SpaceBreak * TableLitLine * (sym","^-1 * SpaceBreak * TableLitLine)^0 * sym","^-1)^-1 + ) * White * sym"}" / mark"table", + + TableValueList = TableValue * (sym"," * TableValue)^0, + TableLitLine = PushIndent * ((TableValueList * PopIndent) + (PopIndent * Cut)) + Space, + + -- the unbounded table + TableBlockInner = Ct(KeyValueLine * (SpaceBreak^1 * KeyValueLine)^0), + TableBlock = SpaceBreak^1 * Advance * ensure(TableBlockInner, PopIndent) / mark"table", + + ClassDecl = key"class" * -P":" * (Assignable + Cc(nil)) * (key"extends" * PreventIndent * ensure(Exp, PopIndent) + C"")^-1 * (ClassBlock + Ct("")) / mark"class", + + ClassBlock = SpaceBreak^1 * Advance * + Ct(ClassLine * (SpaceBreak^1 * ClassLine)^0) * PopIndent, + ClassLine = CheckIndent * (( + KeyValueList / mark"props" + + Statement / mark"stm" + + Exp / mark"stm" + ) * sym","^-1), + + Export = key"export" * ( + Cc"class" * ClassDecl + + op"*" + op"^" + + Ct(NameList) * (sym"=" * Ct(ExpListLow))^-1) / mark"export", + + KeyValue = (sym":" * Name) / self_assign + Ct((KeyName + sym"[" * Exp * sym"]" + DoubleString + SingleString) * symx":" * (Exp + TableBlock)), + KeyValueList = KeyValue * (sym"," * KeyValue)^0, + KeyValueLine = CheckIndent * KeyValueList * sym","^-1, + + FnArgsDef = sym"(" * Ct(FnArgDefList^-1) * + (key"using" * Ct(NameList + Space * "nil") + Ct"") * + sym")" + Ct"" * Ct"", + + FnArgDefList = FnArgDef * (sym"," * FnArgDef)^0, + FnArgDef = Ct(Name * (sym"=" * Exp)^-1), + + FunLit = FnArgsDef * + (sym"->" * Cc"slim" + sym"=>" * Cc"fat") * + (Body + Ct"") / mark"fndef", + + NameList = Name * (sym"," * Name)^0, + NameOrDestructure = Name + TableLit, + AssignableNameList = NameOrDestructure * (sym"," * NameOrDestructure)^0, + + ExpList = Exp * (sym"," * Exp)^0, + ExpListLow = Exp * ((sym"," + sym";") * Exp)^0, + + InvokeArgs = -P"-" * (ExpList * (sym"," * (TableBlock + SpaceBreak * Advance * ArgBlock * TableBlock^-1) + TableBlock)^-1 + TableBlock), + ArgBlock = ArgLine * (sym"," * SpaceBreak * ArgLine)^0 * PopIndent, + ArgLine = CheckIndent * ExpList + } + + return { + _g = White * g * White * -1, + match = function(self, str, ...) + + local pos_to_line = function(pos) + return util.pos_to_line(str, pos) + end + + local get_line = function(num) + return util.get_line(str, num) + end + + local tree + local pass, err = pcall(function(...) + tree = self._g:match(str, ...) + end, ...) + + -- regular error, let it bubble up + if type(err) == "string" then + error(err) + end + + if not tree then + local pos = last_pos + local msg + + if err then + local node + node, msg = unpack(err) + msg = msg and " " .. msg + pos = node[-1] + end + + local line_no = pos_to_line(pos) + local line_str = get_line(line_no) or "" + + return nil, err_msg:format(msg or "", line_no, trim(line_str)) + end + return tree + end + } + end) + + return { + extract_line = extract_line, + + -- parse a string + -- returns tree, or nil and error message + string = function (str) + local g = build_grammar() + return g:match(str) + end + } + + +end +package.preload['moonscript.transform.destructure'] = function() + local ntype, mtype, build + do + local _table_0 = require("moonscript.types") + ntype, mtype, build = _table_0.ntype, _table_0.mtype, _table_0.build + end + local NameProxy + do + local _table_0 = require("moonscript.transform.names") + NameProxy = _table_0.NameProxy + end + local insert = table.insert + local unpack + do + local _table_0 = require("moonscript.util") + unpack = _table_0.unpack + end + local user_error + do + local _table_0 = require("moonscript.errors") + user_error = _table_0.user_error + end + local join + join = function(...) + do + local _with_0 = { } + local out = _with_0 + local i = 1 + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local tbl = _list_0[_index_0] + local _list_1 = tbl + for _index_1 = 1, #_list_1 do + local v = _list_1[_index_1] + out[i] = v + i = i + 1 + end + end + return _with_0 + end + end + local has_destructure + has_destructure = function(names) + local _list_0 = names + for _index_0 = 1, #_list_0 do + local n = _list_0[_index_0] + if ntype(n) == "table" then + return true + end + end + return false + end + local extract_assign_names + extract_assign_names = function(name, accum, prefix) + if accum == nil then + accum = { } + end + if prefix == nil then + prefix = { } + end + local i = 1 + local _list_0 = name[2] + for _index_0 = 1, #_list_0 do + local tuple = _list_0[_index_0] + local value, suffix + if #tuple == 1 then + local s = { + "index", + { + "number", + i + } + } + i = i + 1 + value, suffix = tuple[1], s + else + local key = tuple[1] + local s + if ntype(key) == "key_literal" then + s = { + "dot", + key[2] + } + else + s = { + "index", + key + } + end + value, suffix = tuple[2], s + end + suffix = join(prefix, { + suffix + }) + local t = ntype(value) + if t == "value" or t == "chain" or t == "self" then + insert(accum, { + value, + suffix + }) + elseif t == "table" then + extract_assign_names(value, accum, suffix) + else + user_error("Can't destructure value of type: " .. tostring(ntype(value))) + end + end + return accum + end + local build_assign + build_assign = function(destruct_literal, receiver) + local extracted_names = extract_assign_names(destruct_literal) + local names = { } + local values = { } + local inner = { + "assign", + names, + values + } + local obj + if mtype(receiver) == NameProxy then + obj = receiver + else + do + local _with_0 = NameProxy("obj") + obj = _with_0 + inner = build["do"]({ + build.assign_one(obj, receiver), + { + "assign", + names, + values + } + }) + obj = _with_0 + end + end + local _list_0 = extracted_names + for _index_0 = 1, #_list_0 do + local tuple = _list_0[_index_0] + insert(names, tuple[1]) + insert(values, obj:chain(unpack(tuple[2]))) + end + return build.group({ + { + "declare", + names + }, + inner + }) + end + local split_assign + split_assign = function(assign) + local names, values = unpack(assign, 2) + local g = { } + local total_names = #names + local total_values = #values + local start = 1 + for i, n in ipairs(names) do + if ntype(n) == "table" then + if i > start then + local stop = i - 1 + insert(g, { + "assign", + (function() + local _accum_0 = { } + local _len_0 = 1 + for i = start, stop do + _accum_0[_len_0] = names[i] + _len_0 = _len_0 + 1 + end + return _accum_0 + end)(), + (function() + local _accum_0 = { } + local _len_0 = 1 + for i = start, stop do + _accum_0[_len_0] = values[i] + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + }) + end + insert(g, build_assign(n, values[i])) + start = i + 1 + end + end + if total_names >= start or total_values >= start then + local name_slice + if total_names < start then + name_slice = { + "_" + } + else + name_slice = (function() + local _accum_0 = { } + local _len_0 = 1 + for i = start, total_names do + _accum_0[_len_0] = names[i] + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + end + local value_slice + if total_values < start then + value_slice = { + "nil" + } + else + value_slice = (function() + local _accum_0 = { } + local _len_0 = 1 + for i = start, total_values do + _accum_0[_len_0] = values[i] + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + end + insert(g, { + "assign", + name_slice, + value_slice + }) + end + return build.group(g) + end + return { + has_destructure = has_destructure, + split_assign = split_assign, + build_assign = build_assign + } + +end +package.preload['moonscript.transform.names'] = function() + local build + do + local _table_0 = require("moonscript.types") + build = _table_0.build + end + local unpack + do + local _table_0 = require("moonscript.util") + unpack = _table_0.unpack + end + local LocalName + do + local _parent_0 = nil + local _base_0 = { + get_name = function(self) + return self.name + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, name) + self.name = name + self[1] = "temp_name" + end, + __base = _base_0, + __name = "LocalName", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + 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 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + LocalName = _class_0 + end + local NameProxy + do + local _parent_0 = nil + local _base_0 = { + get_name = function(self, scope, dont_put) + if dont_put == nil then + dont_put = true + end + if not self.name then + self.name = scope:free_name(self.prefix, dont_put) + end + return self.name + end, + chain = function(self, ...) + local items = (function(...) + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local i = _list_0[_index_0] + if type(i) == "string" then + _accum_0[_len_0] = { + "dot", + i + } + else + _accum_0[_len_0] = i + end + _len_0 = _len_0 + 1 + end + return _accum_0 + end)(...) + return build.chain({ + base = self, + unpack(items) + }) + end, + index = function(self, key) + return build.chain({ + base = self, + { + "index", + key + } + }) + end, + __tostring = function(self) + if self.name then + return ("name<%s>"):format(self.name) + else + return ("name"):format(self.prefix) + end + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, prefix) + self.prefix = prefix + self[1] = "temp_name" + end, + __base = _base_0, + __name = "NameProxy", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + 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 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + NameProxy = _class_0 + end + return { + NameProxy = NameProxy, + LocalName = LocalName + } + +end +package.preload['moonscript.transform'] = function() + local types = require("moonscript.types") + local util = require("moonscript.util") + local data = require("moonscript.data") + local reversed, unpack = util.reversed, util.unpack + local ntype, mtype, build, smart_node, is_slice, value_is_singular = types.ntype, types.mtype, types.build, types.smart_node, types.is_slice, types.value_is_singular + local insert = table.insert + local NameProxy, LocalName + do + local _table_0 = require("moonscript.transform.names") + NameProxy, LocalName = _table_0.NameProxy, _table_0.LocalName + end + local destructure = require("moonscript.transform.destructure") + local implicitly_return + local Run + do + local _parent_0 = nil + local _base_0 = { + call = function(self, state) + return self.fn(state) + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, fn) + self.fn = fn + self[1] = "run" + end, + __base = _base_0, + __name = "Run", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + 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 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Run = _class_0 + end + local apply_to_last + apply_to_last = function(stms, fn) + local last_exp_id = 0 + for i = #stms, 1, -1 do + local stm = stms[i] + if stm and mtype(stm) ~= Run then + last_exp_id = i + break + end + end + return (function() + local _accum_0 = { } + local _len_0 = 1 + for i, stm in ipairs(stms) do + if i == last_exp_id then + _accum_0[_len_0] = fn(stm) + else + _accum_0[_len_0] = stm + end + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + end + local is_singular + is_singular = function(body) + if #body ~= 1 then + return false + end + if "group" == ntype(body) then + return is_singular(body[2]) + else + return body[1] + end + end + local extract_declarations + extract_declarations = function(self, body, start, out) + if body == nil then + body = self.current_stms + end + if start == nil then + start = self.current_stm_i + 1 + end + if out == nil then + out = { } + end + for i = start, #body do + local _continue_0 = false + repeat + local stm = body[i] + if stm == nil then + _continue_0 = true + break + end + stm = self.transform.statement(stm) + body[i] = stm + local _exp_0 = stm[1] + if "assign" == _exp_0 or "declare" == _exp_0 then + local _list_0 = stm[2] + for _index_0 = 1, #_list_0 do + local name = _list_0[_index_0] + if type(name) == "string" then + insert(out, name) + end + end + elseif "group" == _exp_0 then + extract_declarations(self, stm[2], 1, out) + end + _continue_0 = true + until true + if not _continue_0 then + break + end + end + return out + end + local expand_elseif_assign + expand_elseif_assign = function(ifstm) + for i = 4, #ifstm do + local case = ifstm[i] + if ntype(case) == "elseif" and ntype(case[2]) == "assign" then + local split = { + unpack(ifstm, 1, i - 1) + } + insert(split, { + "else", + { + { + "if", + case[2], + case[3], + unpack(ifstm, i + 1) + } + } + }) + return split + end + end + return ifstm + end + local constructor_name = "new" + local with_continue_listener + with_continue_listener = function(body) + local continue_name = nil + return { + Run(function(self) + return self:listen("continue", function() + if not (continue_name) then + continue_name = NameProxy("continue") + self:put_name(continue_name) + end + return continue_name + end) + end), + build.group(body), + Run(function(self) + if not (continue_name) then + return + end + self:put_name(continue_name, nil) + return self:splice(function(lines) + return { + { + "assign", + { + continue_name + }, + { + "false" + } + }, + { + "repeat", + "true", + { + lines, + { + "assign", + { + continue_name + }, + { + "true" + } + } + } + }, + { + "if", + { + "not", + continue_name + }, + { + { + "break" + } + } + } + } + end) + end) + } + end + local Transformer + do + local _parent_0 = nil + local _base_0 = { + transform = function(self, scope, node, ...) + if self.seen_nodes[node] then + return node + end + self.seen_nodes[node] = true + while true do + local transformer = self.transformers[ntype(node)] + local res + if transformer then + res = transformer(scope, node, ...) or node + else + res = node + end + if res == node then + return node + end + node = res + end + return node + end, + bind = function(self, scope) + return function(...) + return self:transform(scope, ...) + end + end, + __call = function(self, ...) + return self:transform(...) + end, + can_transform = function(self, node) + return self.transformers[ntype(node)] ~= nil + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, transformers) + self.transformers = transformers + self.seen_nodes = setmetatable({ }, { + __mode = "k" + }) + end, + __base = _base_0, + __name = "Transformer", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + 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 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Transformer = _class_0 + end + local construct_comprehension + construct_comprehension = function(inner, clauses) + local current_stms = inner + for _, clause in reversed(clauses) do + local t = clause[1] + local _exp_0 = t + if "for" == _exp_0 then + local name, bounds + do + local _obj_0 = clause + _, name, bounds = _obj_0[1], _obj_0[2], _obj_0[3] + end + current_stms = { + "for", + name, + bounds, + current_stms + } + elseif "foreach" == _exp_0 then + local names, iter + do + local _obj_0 = clause + _, names, iter = _obj_0[1], _obj_0[2], _obj_0[3] + end + current_stms = { + "foreach", + names, + { + iter + }, + current_stms + } + elseif "when" == _exp_0 then + local cond + do + local _obj_0 = clause + _, cond = _obj_0[1], _obj_0[2] + end + current_stms = { + "if", + cond, + current_stms + } + else + current_stms = error("Unknown comprehension clause: " .. t) + end + current_stms = { + current_stms + } + end + return current_stms[1] + end + local Statement = Transformer({ + root_stms = function(self, body) + return apply_to_last(body, implicitly_return(self)) + end, + declare_glob = function(self, node) + local names = extract_declarations(self) + if node[2] == "^" then + names = (function() + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = names + for _index_0 = 1, #_list_0 do + local _continue_0 = false + repeat + local name = _list_0[_index_0] + if not (name:match("^%u")) then + _continue_0 = true + break + end + local _value_0 = name + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 + _continue_0 = true + until true + if not _continue_0 then + break + end + end + return _accum_0 + end)() + end + return { + "declare", + names + } + end, + assign = function(self, node) + local names, values = unpack(node, 2) + local transformed + if #values == 1 then + local value = values[1] + local t = ntype(value) + if t == "decorated" then + value = self.transform.statement(value) + t = ntype(value) + end + if types.cascading[t] then + local ret + ret = function(stm) + if types.is_value(stm) then + return { + "assign", + names, + { + stm + } + } + else + return stm + end + end + transformed = build.group({ + { + "declare", + names + }, + self.transform.statement(value, ret, node) + }) + end + end + node = transformed or node + if destructure.has_destructure(names) then + return destructure.split_assign(node) + end + return node + end, + continue = function(self, node) + local continue_name = self:send("continue") + if not (continue_name) then + error("continue must be inside of a loop") + end + return build.group({ + build.assign_one(continue_name, "true"), + { + "break" + } + }) + end, + export = function(self, node) + if #node > 2 then + if node[2] == "class" then + local cls = smart_node(node[3]) + return build.group({ + { + "export", + { + cls.name + } + }, + cls + }) + else + return build.group({ + node, + build.assign({ + names = node[2], + values = node[3] + }) + }) + end + else + return nil + end + end, + update = function(self, node) + local _, name, op, exp = unpack(node) + local op_final = op:match("^(.+)=$") + if not op_final then + error("Unknown op: " .. op) + end + if not (value_is_singular(exp)) then + exp = { + "parens", + exp + } + end + return build.assign_one(name, { + "exp", + name, + op_final, + exp + }) + end, + import = function(self, node) + local _, names, source = unpack(node) + local stubs = (function() + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = names + for _index_0 = 1, #_list_0 do + local name = _list_0[_index_0] + if type(name) == "table" then + _accum_0[_len_0] = name + else + _accum_0[_len_0] = { + "dot", + name + } + end + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local real_names = (function() + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = names + for _index_0 = 1, #_list_0 do + local name = _list_0[_index_0] + _accum_0[_len_0] = type(name) == "table" and name[2] or name + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + if type(source) == "string" then + return build.assign({ + names = real_names, + values = (function() + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = stubs + for _index_0 = 1, #_list_0 do + local stub = _list_0[_index_0] + _accum_0[_len_0] = build.chain({ + base = source, + stub + }) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + }) + else + local source_name = NameProxy("table") + return build.group({ + { + "declare", + real_names + }, + build["do"]({ + build.assign_one(source_name, source), + build.assign({ + names = real_names, + values = (function() + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = stubs + for _index_0 = 1, #_list_0 do + local stub = _list_0[_index_0] + _accum_0[_len_0] = build.chain({ + base = source_name, + stub + }) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + }) + }) + }) + end + end, + comprehension = function(self, node, action) + local _, exp, clauses = unpack(node) + action = action or function(exp) + return { + exp + } + end + return construct_comprehension(action(exp), clauses) + end, + ["do"] = function(self, node, ret) + if ret then + node[2] = apply_to_last(node[2], ret) + end + return node + end, + decorated = function(self, node) + local stm, dec = unpack(node, 2) + local wrapped + local _exp_0 = dec[1] + if "if" == _exp_0 then + local cond, fail = unpack(dec, 2) + if fail then + fail = { + "else", + { + fail + } + } + end + wrapped = { + "if", + cond, + { + stm + }, + fail + } + elseif "unless" == _exp_0 then + wrapped = { + "unless", + dec[2], + { + stm + } + } + elseif "comprehension" == _exp_0 then + wrapped = { + "comprehension", + stm, + dec[2] + } + else + wrapped = error("Unknown decorator " .. dec[1]) + end + if ntype(stm) == "assign" then + wrapped = build.group({ + build.declare({ + names = (function() + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = stm[2] + for _index_0 = 1, #_list_0 do + local name = _list_0[_index_0] + if type(name) == "string" then + _accum_0[_len_0] = name + _len_0 = _len_0 + 1 + end + end + return _accum_0 + end)() + }), + wrapped + }) + end + return wrapped + end, + unless = function(self, node) + return { + "if", + { + "not", + { + "parens", + node[2] + } + }, + unpack(node, 3) + } + end, + ["if"] = function(self, node, ret) + if ntype(node[2]) == "assign" then + local _, assign, body = unpack(node) + if destructure.has_destructure(assign[2]) then + local name = NameProxy("des") + body = { + destructure.build_assign(assign[2][1], name), + build.group(node[3]) + } + return build["do"]({ + build.assign_one(name, assign[3][1]), + { + "if", + name, + body, + unpack(node, 4) + } + }) + else + local name = assign[2][1] + return build["do"]({ + assign, + { + "if", + name, + unpack(node, 3) + } + }) + end + end + node = expand_elseif_assign(node) + if ret then + smart_node(node) + node['then'] = apply_to_last(node['then'], ret) + for i = 4, #node do + local case = node[i] + local body_idx = #node[i] + case[body_idx] = apply_to_last(case[body_idx], ret) + end + end + return node + end, + with = function(self, node, ret) + local _, exp, block = unpack(node) + local scope_name = NameProxy("with") + local named_assign + if ntype(exp) == "assign" then + local names, values = unpack(exp, 2) + local assign_name = names[1] + exp = values[1] + values[1] = scope_name + named_assign = { + "assign", + names, + values + } + end + return build["do"]({ + Run(function(self) + return self:set("scope_var", scope_name) + end), + build.assign_one(scope_name, exp), + build.group({ + named_assign + }), + build.group(block), + (function() + if ret then + return ret(scope_name) + end + end)() + }) + end, + foreach = function(self, node) + smart_node(node) + local source = unpack(node.iter) + local destructures = { } + node.names = (function() + local _accum_0 = { } + local _len_0 = 1 + for i, name in ipairs(node.names) do + if ntype(name) == "table" then + do + local _with_0 = NameProxy("des") + local proxy = _with_0 + insert(destructures, destructure.build_assign(name, proxy)) + _accum_0[_len_0] = _with_0 + end + else + _accum_0[_len_0] = name + end + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + if next(destructures) then + insert(destructures, build.group(node.body)) + node.body = destructures + end + if ntype(source) == "unpack" then + local list = source[2] + local index_name = NameProxy("index") + local list_name = NameProxy("list") + local slice_var = nil + local bounds + if is_slice(list) then + local slice = list[#list] + table.remove(list) + table.remove(slice, 1) + if slice[2] and slice[2] ~= "" then + local max_tmp_name = NameProxy("max") + slice_var = build.assign_one(max_tmp_name, slice[2]) + slice[2] = { + "exp", + max_tmp_name, + "<", + 0, + "and", + { + "length", + list_name + }, + "+", + max_tmp_name, + "or", + max_tmp_name + } + else + slice[2] = { + "length", + list_name + } + end + bounds = slice + else + bounds = { + 1, + { + "length", + list_name + } + } + end + return build.group({ + build.assign_one(list_name, list), + slice_var, + build["for"]({ + name = index_name, + bounds = bounds, + body = { + { + "assign", + node.names, + { + list_name:index(index_name) + } + }, + build.group(node.body) + } + }) + }) + end + node.body = with_continue_listener(node.body) + end, + ["while"] = function(self, node) + smart_node(node) + node.body = with_continue_listener(node.body) + end, + ["for"] = function(self, node) + smart_node(node) + node.body = with_continue_listener(node.body) + end, + switch = function(self, node, ret) + local _, exp, conds = unpack(node) + local exp_name = NameProxy("exp") + local convert_cond + convert_cond = function(cond) + local t, case_exps, body = unpack(cond) + local out = { } + insert(out, t == "case" and "elseif" or "else") + if t ~= "else" then + local cond_exp = { } + for i, case in ipairs(case_exps) do + if i == 1 then + insert(cond_exp, "exp") + else + insert(cond_exp, "or") + end + if not (value_is_singular(case)) then + case = { + "parens", + case + } + end + insert(cond_exp, { + "exp", + case, + "==", + exp_name + }) + end + insert(out, cond_exp) + else + body = case_exps + end + if ret then + body = apply_to_last(body, ret) + end + insert(out, body) + return out + end + local first = true + local if_stm = { + "if" + } + local _list_0 = conds + for _index_0 = 1, #_list_0 do + local cond = _list_0[_index_0] + local if_cond = convert_cond(cond) + if first then + first = false + insert(if_stm, if_cond[2]) + insert(if_stm, if_cond[3]) + else + insert(if_stm, if_cond) + end + end + return build.group({ + build.assign_one(exp_name, exp), + if_stm + }) + end, + class = function(self, node, ret, parent_assign) + local _, name, parent_val, body = unpack(node) + local statements = { } + local properties = { } + local _list_0 = body + for _index_0 = 1, #_list_0 do + local item = _list_0[_index_0] + local _exp_0 = item[1] + if "stm" == _exp_0 then + insert(statements, item[2]) + elseif "props" == _exp_0 then + local _list_1 = item + for _index_1 = 2, #_list_1 do + local tuple = _list_1[_index_1] + if ntype(tuple[1]) == "self" then + insert(statements, build.assign_one(unpack(tuple))) + else + insert(properties, tuple) + end + end + end + end + local constructor + properties = (function() + local _accum_0 = { } + local _len_0 = 1 + local _list_1 = properties + for _index_0 = 1, #_list_1 do + local _continue_0 = false + repeat + local tuple = _list_1[_index_0] + local key = tuple[1] + local _value_0 + if key[1] == "key_literal" and key[2] == constructor_name then + constructor = tuple[2] + _continue_0 = true + break + else + _value_0 = tuple + end + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 + _continue_0 = true + until true + if not _continue_0 then + break + end + end + return _accum_0 + end)() + local parent_cls_name = NameProxy("parent") + local base_name = NameProxy("base") + local self_name = NameProxy("self") + local cls_name = NameProxy("class") + if not (constructor) then + constructor = build.fndef({ + args = { + { + "..." + } + }, + arrow = "fat", + body = { + build["if"]({ + cond = parent_cls_name, + ["then"] = { + build.chain({ + base = "super", + { + "call", + { + "..." + } + } + }) + } + }) + } + }) + end + local real_name = name or parent_assign and parent_assign[2][1] + local _exp_0 = ntype(real_name) + if "chain" == _exp_0 then + local last = real_name[#real_name] + local _exp_1 = ntype(last) + if "dot" == _exp_1 then + real_name = { + "string", + '"', + last[2] + } + elseif "index" == _exp_1 then + real_name = last[2] + else + real_name = "nil" + end + elseif "nil" == _exp_0 then + real_name = "nil" + else + real_name = { + "string", + '"', + real_name + } + end + local cls = build.table({ + { + "__init", + constructor + }, + { + "__base", + base_name + }, + { + "__name", + real_name + }, + { + "__parent", + parent_cls_name + } + }) + local class_lookup = build["if"]({ + cond = { + "exp", + "val", + "==", + "nil", + "and", + parent_cls_name + }, + ["then"] = { + parent_cls_name:index("name") + } + }) + insert(class_lookup, { + "else", + { + "val" + } + }) + local cls_mt = build.table({ + { + "__index", + build.fndef({ + args = { + { + "cls" + }, + { + "name" + } + }, + body = { + build.assign_one(LocalName("val"), build.chain({ + base = "rawget", + { + "call", + { + base_name, + "name" + } + } + })), + class_lookup + } + }) + }, + { + "__call", + build.fndef({ + args = { + { + "cls" + }, + { + "..." + } + }, + body = { + build.assign_one(self_name, build.chain({ + base = "setmetatable", + { + "call", + { + "{}", + base_name + } + } + })), + build.chain({ + base = "cls.__init", + { + "call", + { + self_name, + "..." + } + } + }), + self_name + } + }) + } + }) + cls = build.chain({ + base = "setmetatable", + { + "call", + { + cls, + cls_mt + } + } + }) + local value = nil + do + local _with_0 = build + local out_body = { + Run(function(self) + if name then + self:put_name(name) + end + return self:set("super", function(block, chain) + if chain then + local slice = (function() + local _accum_0 = { } + local _len_0 = 1 + local _list_1 = chain + for _index_0 = 3, #_list_1 do + local item = _list_1[_index_0] + _accum_0[_len_0] = item + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local new_chain = { + "chain", + parent_cls_name + } + local head = slice[1] + if head == nil then + return parent_cls_name + end + local _exp_1 = head[1] + if "call" == _exp_1 then + local calling_name = block:get("current_block") + slice[1] = { + "call", + { + "self", + unpack(head[2]) + } + } + if ntype(calling_name) == "key_literal" then + insert(new_chain, { + "dot", + calling_name[2] + }) + else + insert(new_chain, { + "index", + calling_name + }) + end + elseif "colon" == _exp_1 then + local call = head[3] + insert(new_chain, { + "dot", + head[2] + }) + slice[1] = { + "call", + { + "self", + unpack(call[2]) + } + } + end + local _list_1 = slice + for _index_0 = 1, #_list_1 do + local item = _list_1[_index_0] + insert(new_chain, item) + end + return new_chain + else + return parent_cls_name + end + end) + end), + { + "declare_glob", + "*" + }, + _with_0.assign_one(parent_cls_name, parent_val == "" and "nil" or parent_val), + _with_0.assign_one(base_name, { + "table", + properties + }), + _with_0.assign_one(base_name:chain("__index"), base_name), + _with_0["if"]({ + cond = parent_cls_name, + ["then"] = { + _with_0.chain({ + base = "setmetatable", + { + "call", + { + base_name, + _with_0.chain({ + base = parent_cls_name, + { + "dot", + "__base" + } + }) + } + } + }) + } + }), + _with_0.assign_one(cls_name, cls), + _with_0.assign_one(base_name:chain("__class"), cls_name), + _with_0.group((function() + if #statements > 0 then + return { + _with_0.assign_one(LocalName("self"), cls_name), + _with_0.group(statements) + } + end + end)()), + _with_0["if"]({ + cond = { + "exp", + parent_cls_name, + "and", + parent_cls_name:chain("__inherited") + }, + ["then"] = { + parent_cls_name:chain("__inherited", { + "call", + { + parent_cls_name, + cls_name + } + }) + } + }), + _with_0.group((function() + if name then + return { + _with_0.assign_one(name, cls_name) + } + end + end)()), + (function() + if ret then + return ret(cls_name) + end + end)() + } + value = _with_0.group({ + _with_0.group((function() + if ntype(name) == "value" then + return { + _with_0.declare({ + names = { + name + } + }) + } + end + end)()), + _with_0["do"](out_body) + }) + end + return value + end + }) + local Accumulator + do + local _parent_0 = nil + local _base_0 = { + body_idx = { + ["for"] = 4, + ["while"] = 3, + foreach = 4 + }, + convert = function(self, node) + local index = self.body_idx[ntype(node)] + node[index] = self:mutate_body(node[index]) + return self:wrap(node) + end, + wrap = function(self, node) + return build.block_exp({ + build.assign_one(self.accum_name, build.table()), + build.assign_one(self.len_name, 1), + node, + self.accum_name + }) + end, + mutate_body = function(self, body) + local single_stm = is_singular(body) + local val + if single_stm and types.is_value(single_stm) then + body = { } + val = single_stm + else + body = apply_to_last(body, function(n) + if types.is_value(n) then + return build.assign_one(self.value_name, n) + else + return build.group({ + { + "declare", + { + self.value_name + } + }, + n + }) + end + end) + val = self.value_name + end + local update = { + build.assign_one(self.accum_name:index(self.len_name), val), + { + "update", + self.len_name, + "+=", + 1 + } + } + insert(body, build.group(update)) + return body + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.accum_name = NameProxy("accum") + self.value_name = NameProxy("value") + self.len_name = NameProxy("len") + end, + __base = _base_0, + __name = "Accumulator", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + 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 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Accumulator = _class_0 + end + local default_accumulator + default_accumulator = function(self, node) + return Accumulator():convert(node) + end + implicitly_return = function(scope) + local is_top = true + local fn + fn = function(stm) + local t = ntype(stm) + if t == "decorated" then + stm = scope.transform.statement(stm) + t = ntype(stm) + end + if types.cascading[t] then + is_top = false + return scope.transform.statement(stm, fn) + elseif types.manual_return[t] or not types.is_value(stm) then + if is_top and t == "return" and stm[2] == "" then + return nil + else + return stm + end + else + if t == "comprehension" and not types.comprehension_has_value(stm) then + return stm + else + return { + "return", + stm + } + end + end + end + return fn + end + local Value = Transformer({ + ["for"] = default_accumulator, + ["while"] = default_accumulator, + foreach = default_accumulator, + ["do"] = function(self, node) + return build.block_exp(node[2]) + end, + decorated = function(self, node) + return self.transform.statement(node) + end, + class = function(self, node) + return build.block_exp({ + node + }) + end, + string = function(self, node) + local delim = node[2] + local convert_part + convert_part = function(part) + if type(part) == "string" or part == nil then + return { + "string", + delim, + part or "" + } + else + return build.chain({ + base = "tostring", + { + "call", + { + part[2] + } + } + }) + end + end + if #node <= 3 then + return (function() + if type(node[3]) == "string" then + return node + else + return convert_part(node[3]) + end + end)() + end + local e = { + "exp", + convert_part(node[3]) + } + for i = 4, #node do + insert(e, "..") + insert(e, convert_part(node[i])) + end + return e + end, + comprehension = function(self, node) + local a = Accumulator() + node = self.transform.statement(node, function(exp) + return a:mutate_body({ + exp + }) + end) + return a:wrap(node) + end, + tblcomprehension = function(self, node) + local _, explist, clauses = unpack(node) + local key_exp, value_exp = unpack(explist) + local accum = NameProxy("tbl") + local inner + if value_exp then + local dest = build.chain({ + base = accum, + { + "index", + key_exp + } + }) + inner = { + build.assign_one(dest, value_exp) + } + else + local key_name, val_name = NameProxy("key"), NameProxy("val") + local dest = build.chain({ + base = accum, + { + "index", + key_name + } + }) + inner = { + build.assign({ + names = { + key_name, + val_name + }, + values = { + key_exp + } + }), + build.assign_one(dest, val_name) + } + end + return build.block_exp({ + build.assign_one(accum, build.table()), + construct_comprehension(inner, clauses), + accum + }) + end, + fndef = function(self, node) + smart_node(node) + node.body = apply_to_last(node.body, implicitly_return(self)) + node.body = { + Run(function(self) + return self:listen("varargs", function() end) + end), + unpack(node.body) + } + return node + end, + ["if"] = function(self, node) + return build.block_exp({ + node + }) + end, + unless = function(self, node) + return build.block_exp({ + node + }) + end, + with = function(self, node) + return build.block_exp({ + node + }) + end, + switch = function(self, node) + return build.block_exp({ + node + }) + end, + chain = function(self, node) + local stub = node[#node] + for i = 3, #node do + local part = node[i] + if ntype(part) == "dot" and data.lua_keywords[part[2]] then + node[i] = { + "index", + { + "string", + '"', + part[2] + } + } + end + end + if ntype(node[2]) == "string" then + node[2] = { + "parens", + node[2] + } + elseif type(stub) == "table" and stub[1] == "colon_stub" then + table.remove(node, #node) + local base_name = NameProxy("base") + local fn_name = NameProxy("fn") + local is_super = node[2] == "super" + return self.transform.value(build.block_exp({ + build.assign({ + names = { + base_name + }, + values = { + node + } + }), + build.assign({ + names = { + fn_name + }, + values = { + build.chain({ + base = base_name, + { + "dot", + stub[2] + } + }) + } + }), + build.fndef({ + args = { + { + "..." + } + }, + body = { + build.chain({ + base = fn_name, + { + "call", + { + is_super and "self" or base_name, + "..." + } + } + }) + } + }) + })) + end + end, + block_exp = function(self, node) + local _, body = unpack(node) + local fn = nil + local arg_list = { } + fn = smart_node(build.fndef({ + body = { + Run(function(self) + return self:listen("varargs", function() + insert(arg_list, "...") + insert(fn.args, { + "..." + }) + return self:unlisten("varargs") + end) + end), + unpack(body) + } + })) + return build.chain({ + base = { + "parens", + fn + }, + { + "call", + arg_list + } + }) + end + }) + return { + Statement = Statement, + Value = Value, + Run = Run + } + +end +package.preload['moonscript.types'] = function() + local util = require("moonscript.util") + local data = require("moonscript.data") + local insert = table.insert + local unpack = util.unpack + local manual_return = data.Set({ + "foreach", + "for", + "while", + "return" + }) + local cascading = data.Set({ + "if", + "unless", + "with", + "switch", + "class", + "do" + }) + local ntype + ntype = function(node) + local _exp_0 = type(node) + if "nil" == _exp_0 then + return "nil" + elseif "table" == _exp_0 then + return node[1] + else + return "value" + end + end + local mtype + do + local moon_type = util.moon.type + mtype = function(val) + local mt = getmetatable(val) + if mt and mt.smart_node then + return "table" + end + return moon_type(val) + end + end + local has_value + has_value = function(node) + if ntype(node) == "chain" then + local ctype = ntype(node[#node]) + return ctype ~= "call" and ctype ~= "colon" + else + return true + end + end + local is_value + is_value = function(stm) + local compile = require("moonscript.compile") + local transform = require("moonscript.transform") + return compile.Block:is_value(stm) or transform.Value:can_transform(stm) + end + local comprehension_has_value + comprehension_has_value = function(comp) + return is_value(comp[2]) + end + local value_is_singular + value_is_singular = function(node) + return type(node) ~= "table" or node[1] ~= "exp" or #node == 2 + end + local is_slice + is_slice = function(node) + return ntype(node) == "chain" and ntype(node[#node]) == "slice" + end + local t = { } + local node_types = { + class = { + { + "name", + "Tmp" + }, + { + "body", + t + } + }, + fndef = { + { + "args", + t + }, + { + "whitelist", + t + }, + { + "arrow", + "slim" + }, + { + "body", + t + } + }, + foreach = { + { + "names", + t + }, + { + "iter" + }, + { + "body", + t + } + }, + ["for"] = { + { + "name" + }, + { + "bounds", + t + }, + { + "body", + t + } + }, + ["while"] = { + { + "cond", + t + }, + { + "body", + t + } + }, + assign = { + { + "names", + t + }, + { + "values", + t + } + }, + declare = { + { + "names", + t + } + }, + ["if"] = { + { + "cond", + t + }, + { + "then", + t + } + } + } + local build_table + build_table = function() + local key_table = { } + for node_name, args in pairs(node_types) do + local index = { } + for i, tuple in ipairs(args) do + local prop_name = tuple[1] + index[prop_name] = i + 1 + end + key_table[node_name] = index + end + return key_table + end + local key_table = build_table() + local make_builder + make_builder = function(name) + local spec = node_types[name] + if not spec then + error("don't know how to build node: " .. name) + end + return function(props) + if props == nil then + props = { } + end + local node = { + name + } + for i, arg in ipairs(spec) do + local key, default_value = unpack(arg) + local val + if props[key] then + val = props[key] + else + val = default_value + end + if val == t then + val = { } + end + node[i + 1] = val + end + return node + end + end + local build = nil + build = setmetatable({ + group = function(body) + if body == nil then + body = { } + end + return { + "group", + body + } + end, + ["do"] = function(body) + return { + "do", + body + } + end, + assign_one = function(name, value) + return build.assign({ + names = { + name + }, + values = { + value + } + }) + end, + table = function(tbl) + if tbl == nil then + tbl = { } + end + local _list_0 = tbl + for _index_0 = 1, #_list_0 do + local tuple = _list_0[_index_0] + if type(tuple[1]) == "string" then + tuple[1] = { + "key_literal", + tuple[1] + } + end + end + return { + "table", + tbl + } + end, + block_exp = function(body) + return { + "block_exp", + body + } + end, + chain = function(parts) + local base = parts.base or error("expecting base property for chain") + local node = { + "chain", + base + } + local _list_0 = parts + for _index_0 = 1, #_list_0 do + local part = _list_0[_index_0] + insert(node, part) + end + return node + end + }, { + __index = function(self, name) + self[name] = make_builder(name) + return rawget(self, name) + end + }) + local smart_node_mt = setmetatable({ }, { + __index = function(self, node_type) + local index = key_table[node_type] + local mt = { + smart_node = true, + __index = function(node, key) + if index[key] then + return rawget(node, index[key]) + elseif type(key) == "string" then + return error("unknown key: `" .. key .. "` on node type: `" .. ntype(node) .. "`") + end + end, + __newindex = function(node, key, value) + if index[key] then + key = index[key] + end + return rawset(node, key, value) + end + } + self[node_type] = mt + return mt + end + }) + local smart_node + smart_node = function(node) + return setmetatable(node, smart_node_mt[ntype(node)]) + end + return { + ntype = ntype, + smart_node = smart_node, + build = build, + is_value = is_value, + is_slice = is_slice, + manual_return = manual_return, + cascading = cascading, + value_is_singular = value_is_singular, + comprehension_has_value = comprehension_has_value, + has_value = has_value, + mtype = mtype + } + +end +package.preload['moonscript.util'] = function() + local concat = table.concat + local unpack = unpack or table.unpack + local type = type + local moon = { + is_object = function(value) + return type(value) == "table" and value.__class + end, + is_a = function(thing, t) + if not (type(thing) == "table") then + return false + end + local cls = thing.__class + while cls do + if cls == t then + return true + end + cls = cls.__parent + end + return false + end, + type = function(value) + local base_type = type(value) + if base_type == "table" then + local cls = value.__class + if cls then + return cls + end + end + return base_type + end + } + local pos_to_line + pos_to_line = function(str, pos) + local line = 1 + for _ in str:sub(1, pos):gmatch("\n") do + line = line + 1 + end + return line + end + local trim + trim = function(str) + return str:match("^%s*(.-)%s*$") + end + local get_line + get_line = function(str, line_num) + for line in str:gmatch("([^\n]*)\n?") do + if line_num == 1 then + return line + end + line_num = line_num - 1 + end + end + local get_closest_line + get_closest_line = function(str, line_num) + local line = get_line(str, line_num) + if (not line or trim(line) == "") and line_num > 1 then + return get_closest_line(str, line_num - 1) + else + return line, line_num + end + end + local reversed + reversed = function(seq) + return coroutine.wrap(function() + for i = #seq, 1, -1 do + coroutine.yield(i, seq[i]) + end + end) + end + local split + split = function(str, delim) + if str == "" then + return { } + end + str = str .. delim + return (function() + local _accum_0 = { } + local _len_0 = 1 + for m in str:gmatch("(.-)" .. delim) do + _accum_0[_len_0] = m + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + end + local dump + dump = function(what) + local seen = { } + local _dump + _dump = function(what, depth) + if depth == nil then + depth = 0 + end + local t = type(what) + if t == "string" then + return '"' .. what .. '"\n' + elseif t == "table" then + if seen[what] then + return "recursion(" .. tostring(what) .. ")...\n" + end + seen[what] = true + depth = depth + 1 + local lines = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(what) do + _accum_0[_len_0] = (" "):rep(depth * 4) .. "[" .. tostring(k) .. "] = " .. _dump(v, depth) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + seen[what] = false + return "{\n" .. concat(lines) .. (" "):rep((depth - 1) * 4) .. "}\n" + else + return tostring(what) .. "\n" + end + end + return _dump(what) + end + local debug_posmap + debug_posmap = function(posmap, moon_code, lua_code) + local tuples = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(posmap) do + _accum_0[_len_0] = { + k, + v + } + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + table.sort(tuples, function(a, b) + return a[1] < b[1] + end) + local lines = (function() + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = tuples + for _index_0 = 1, #_list_0 do + local pair = _list_0[_index_0] + local lua_line, pos = unpack(pair) + local moon_line = pos_to_line(moon_code, pos) + local lua_text = get_line(lua_code, lua_line) + local moon_text = get_closest_line(moon_code, moon_line) + local _value_0 = tostring(pos) .. "\t " .. tostring(lua_line) .. ":[ " .. tostring(trim(lua_text)) .. " ] >> " .. tostring(moon_line) .. ":[ " .. tostring(trim(moon_text)) .. " ]" + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + return concat(lines, "\n") + end + local setfenv = setfenv or function(fn, env) + local name + local i = 1 + while true do + name = debug.getupvalue(fn, i) + if not name or name == "_ENV" then + break + end + i = i + 1 + end + if name then + debug.upvaluejoin(fn, i, (function() + return env + end), 1) + end + return fn + end + local getfenv = getfenv or function(fn) + local i = 1 + while true do + local name, val = debug.getupvalue(fn, i) + if not (name) then + break + end + if name == "_ENV" then + return val + end + i = i + 1 + end + return nil + end + local get_options + get_options = function(...) + local count = select("#", ...) + local opts = select(count, ...) + if type(opts) == "table" then + return opts, unpack({ + ... + }, nil, count - 1) + else + return { }, ... + end + end + return { + moon = moon, + pos_to_line = pos_to_line, + get_closest_line = get_closest_line, + get_line = get_line, + reversed = reversed, + trim = trim, + split = split, + dump = dump, + debug_posmap = debug_posmap, + getfenv = getfenv, + setfenv = setfenv, + get_options = get_options, + unpack = unpack + } + +end +package.preload['moonscript.version'] = function() + + module("moonscript.version", package.seeall) + + version = "0.2.3-2" + function print_version() + print("MoonScript version "..version) + end + +end +return package.preload["moonscript"]() diff --git a/aegisub/src/auto4_base.cpp b/aegisub/src/auto4_base.cpp index f141cf3a3..92c7ecfef 100644 --- a/aegisub/src/auto4_base.cpp +++ b/aegisub/src/auto4_base.cpp @@ -51,6 +51,7 @@ #include #include +#include #include #include #include @@ -517,8 +518,10 @@ namespace Automation4 { if (fact->GetEngineName().empty() || fact->GetFilenamePattern().empty()) continue; - fnfilter += str(boost::format("%s scripts (%s)|%s|") % fact->GetEngineName() % fact->GetFilenamePattern() % fact->GetFilenamePattern()); - catchall += fact->GetFilenamePattern() + ";"; + std::string filter(fact->GetFilenamePattern()); + boost::replace_all(filter, ",", ";"); + fnfilter += str(boost::format("%s scripts (%s)|%s|") % fact->GetEngineName() % fact->GetFilenamePattern() % filter); + catchall += filter + ";"; } fnfilter += from_wx(_("All Files")) + " (*.*)|*.*"; diff --git a/aegisub/src/auto4_lua.cpp b/aegisub/src/auto4_lua.cpp index bd772d13b..4455e2b8a 100644 --- a/aegisub/src/auto4_lua.cpp +++ b/aegisub/src/auto4_lua.cpp @@ -191,6 +191,103 @@ namespace { TableIter::init(L); return 3; } + + int frame_from_ms(lua_State *L) + { + const agi::Context *c = get_context(L); + int ms = lua_tointeger(L, -1); + lua_pop(L, 1); + if (c && c->videoController->TimecodesLoaded()) + push_value(L, c->videoController->FrameAtTime(ms, agi::vfr::START)); + else + lua_pushnil(L); + + return 1; + } + + int ms_from_frame(lua_State *L) + { + const agi::Context *c = get_context(L); + int frame = lua_tointeger(L, -1); + lua_pop(L, 1); + if (c && c->videoController->TimecodesLoaded()) + push_value(L, c->videoController->TimeAtFrame(frame, agi::vfr::START)); + else + lua_pushnil(L); + return 1; + } + + int video_size(lua_State *L) + { + const agi::Context *c = get_context(L); + if (c && c->videoController->IsLoaded()) { + push_value(L, c->videoController->GetWidth()); + push_value(L, c->videoController->GetHeight()); + push_value(L, c->videoController->GetAspectRatioValue()); + push_value(L, (int)c->videoController->GetAspectRatioType()); + return 4; + } + else { + lua_pushnil(L); + return 1; + } + } + + int get_keyframes(lua_State *L) + { + const agi::Context *c = get_context(L); + if (!c) { + lua_pushnil(L); + return 1; + } + + std::vector const& kf = c->videoController->GetKeyFrames(); + + lua_newtable(L); + for (size_t i = 0; i < kf.size(); ++i) { + push_value(L, kf[i]); + lua_rawseti(L, -2, i); + } + + return 1; + } + + int decode_path(lua_State *L) + { + std::string path = luaL_checkstring(L, 1); + lua_pop(L, 1); + push_value(L, config::path->Decode(path)); + return 1; + } + + int cancel_script(lua_State *L) + { + lua_pushnil(L); + return lua_error(L); + } + + int lua_text_textents(lua_State *L) + { + luaL_argcheck(L, lua_istable(L, 1), 1, ""); + luaL_argcheck(L, lua_isstring(L, 2), 2, ""); + + lua_pushvalue(L, 1); + agi::scoped_ptr et(Automation4::LuaAssFile::LuaToAssEntry(L)); + AssStyle *st = dynamic_cast(et.get()); + lua_pop(L, 1); + if (!st) + return luaL_error(L, "Not a style entry"); + + double width, height, descent, extlead; + if (!Automation4::CalculateTextExtents(st, luaL_checkstring(L, 2), width, height, descent, extlead)) + return luaL_error(L, "Some internal error occurred calculating text_extents"); + + push_value(L, width); + push_value(L, height); + push_value(L, descent); + push_value(L, extlead); + return 4; + } } extern "C" int luaopen_lpeg (lua_State *L); @@ -198,19 +295,56 @@ extern "C" int luaopen_lpeg (lua_State *L); namespace Automation4 { int regex_init(lua_State *L); - // LuaScript + class LuaScript : public Script { + lua_State *L; + + std::string name; + std::string description; + std::string author; + std::string version; + + std::vector macros; + std::vector filters; + + /// load script and create internal structures etc. + void Create(); + /// destroy internal structures, unreg features and delete environment + void Destroy(); + + static int LuaInclude(lua_State *L); + static int LuaModuleLoader(lua_State *L); + + public: + LuaScript(agi::fs::path const& filename); + ~LuaScript() { Destroy(); } + + void RegisterCommand(LuaCommand *command); + void UnregisterCommand(LuaCommand *command); + void RegisterFilter(LuaExportFilter *filter); + + static LuaScript* GetScriptObject(lua_State *L); + + // Script implementation + void Reload() { Create(); } + + std::string GetName() const { return name; } + std::string GetDescription() const { return description; } + std::string GetAuthor() const { return author; } + std::string GetVersion() const { return version; } + bool GetLoadedState() const { return L != 0; } + + std::vector GetMacros() const { return macros; } + std::vector GetFilters() const { return filters; } + std::vector GetFormats() const { return std::vector(); } + }; + LuaScript::LuaScript(agi::fs::path const& filename) : Script(filename) - , L(0) + , L(nullptr) { Create(); } - LuaScript::~LuaScript() - { - Destroy(); - } - void LuaScript::Create() { Destroy(); @@ -283,13 +417,13 @@ namespace Automation4 { set_field(L, "register_macro", LuaCommand::LuaRegister); set_field(L, "register_filter", LuaExportFilter::LuaRegister); - set_field(L, "text_extents", LuaTextExtents); - set_field(L, "frame_from_ms", LuaFrameFromMs); - set_field(L, "ms_from_frame", LuaMsFromFrame); - set_field(L, "video_size", LuaVideoSize); - set_field(L, "keyframes", LuaGetKeyframes); - set_field(L, "decode_path", LuaDecodePath); - set_field(L, "cancel", LuaCancel); + set_field(L, "text_extents", lua_text_textents); + set_field(L, "frame_from_ms", frame_from_ms); + set_field(L, "ms_from_frame", ms_from_frame); + set_field(L, "video_size", video_size); + set_field(L, "keyframes", get_keyframes); + set_field(L, "decode_path", decode_path); + set_field(L, "cancel", cancel_script); set_field(L, "lua_automation_version", 4); set_field(L, "__init_regex", regex_init); set_field(L, "__init_clipboard", clipboard_init); @@ -301,8 +435,7 @@ namespace Automation4 { _stackcheck.check_stack(0); // load user script - LuaScriptReader script_reader(GetFilename()); - if (lua_load(L, script_reader.reader_func, &script_reader, GetPrettyFilename().string().c_str())) { + if (!LoadFile(L, GetFilename())) { std::string err = str(boost::format("Error loading Lua script \"%s\":\n\n%s") % GetPrettyFilename().string() % get_string_or_default(L, -1)); lua_pop(L, 1); throw ScriptLoadError(err); @@ -359,12 +492,7 @@ namespace Automation4 { delete_clear(filters); lua_close(L); - L = 0; - } - - void LuaScript::Reload() - { - Create(); + L = nullptr; } void LuaScript::RegisterCommand(LuaCommand *command) @@ -397,29 +525,6 @@ namespace Automation4 { return (LuaScript*)ptr; } - int LuaScript::LuaTextExtents(lua_State *L) - { - luaL_argcheck(L, lua_istable(L, 1), 1, ""); - luaL_argcheck(L, lua_isstring(L, 2), 2, ""); - - lua_pushvalue(L, 1); - agi::scoped_ptr et(LuaAssFile::LuaToAssEntry(L)); - AssStyle *st = dynamic_cast(et.get()); - lua_pop(L, 1); - if (!st) - return luaL_error(L, "Not a style entry"); - - double width, height, descent, extlead; - if (!CalculateTextExtents(st, luaL_checkstring(L, 2), width, height, descent, extlead)) - return luaL_error(L, "Some internal error occurred calculating text_extents"); - - push_value(L, width); - push_value(L, height); - push_value(L, descent); - push_value(L, extlead); - return 4; - } - /// @brief Module loader which uses our include rather than Lua's, for unicode file support /// @param L The Lua state /// @return Always 1 per loader_Lua? @@ -431,18 +536,27 @@ namespace Automation4 { // Get the lua package include path (which the user may have modified) lua_getglobal(L, "package"); - push_value(L, "path"); - lua_gettable(L, -2); + lua_getfield(L, -1, "path"); std::string package_paths(luaL_checkstring(L, -1)); lua_pop(L, 2); boost::char_separator sep(";"); for (auto filename : boost::tokenizer>(package_paths, sep)) { boost::replace_all(filename, "?", module); + + // If there's a .moon file at that path, load it instead of the + // .lua file + agi::fs::path path = filename; + if (agi::fs::HasExtension(path, "lua")) { + agi::fs::path moonpath = path; + moonpath.replace_extension("moon"); + if (agi::fs::FileExists(moonpath)) + path = moonpath; + } + try { - LuaScriptReader script_reader(filename); - if (lua_load(L, script_reader.reader_func, &script_reader, filename.c_str())) - return luaL_error(L, "Error loading Lua module \"%s\":\n\n%s", filename.c_str(), luaL_checkstring(L, -1)); + if (!LoadFile(L, path)) + return luaL_error(L, "Error loading Lua module \"%s\":\n\n%s", path.string().c_str(), luaL_checkstring(L, -1)); break; } catch (agi::fs::FileNotFound const&) { @@ -452,7 +566,7 @@ namespace Automation4 { // Not an error so swallow and continue on } catch (agi::Exception const& e) { - return luaL_error(L, "Error loading Lua module \"%s\":\n\n%s", filename.c_str(), e.GetChainedMessage().c_str()); + return luaL_error(L, "Error loading Lua module \"%s\":\n\n%s", path.string().c_str(), e.GetChainedMessage().c_str()); } } @@ -480,8 +594,7 @@ namespace Automation4 { if (!agi::fs::FileExists(filepath)) return luaL_error(L, "Lua include not found: %s", filename.c_str()); - LuaScriptReader script_reader(filepath); - if (lua_load(L, script_reader.reader_func, &script_reader, filename.c_str())) + if (!LoadFile(L, filepath)) return luaL_error(L, "Error loading Lua include \"%s\":\n\n%s", filename.c_str(), luaL_checkstring(L, -1)); int pretop = lua_gettop(L) - 1; // don't count the function value itself @@ -489,80 +602,6 @@ namespace Automation4 { return lua_gettop(L) - pretop; } - int LuaScript::LuaFrameFromMs(lua_State *L) - { - const agi::Context *c = get_context(L); - int ms = lua_tointeger(L, -1); - lua_pop(L, 1); - if (c && c->videoController->TimecodesLoaded()) - push_value(L, c->videoController->FrameAtTime(ms, agi::vfr::START)); - else - lua_pushnil(L); - - return 1; - } - - int LuaScript::LuaMsFromFrame(lua_State *L) - { - const agi::Context *c = get_context(L); - int frame = lua_tointeger(L, -1); - lua_pop(L, 1); - if (c && c->videoController->TimecodesLoaded()) - push_value(L, c->videoController->TimeAtFrame(frame, agi::vfr::START)); - else - lua_pushnil(L); - return 1; - } - - int LuaScript::LuaVideoSize(lua_State *L) - { - const agi::Context *c = get_context(L); - if (c && c->videoController->IsLoaded()) { - push_value(L, c->videoController->GetWidth()); - push_value(L, c->videoController->GetHeight()); - push_value(L, c->videoController->GetAspectRatioValue()); - push_value(L, (int)c->videoController->GetAspectRatioType()); - return 4; - } - else { - lua_pushnil(L); - return 1; - } - } - - int LuaScript::LuaGetKeyframes(lua_State *L) - { - const agi::Context *c = get_context(L); - if (!c) { - lua_pushnil(L); - return 1; - } - - std::vector const& kf = c->videoController->GetKeyFrames(); - - lua_newtable(L); - for (size_t i = 0; i < kf.size(); ++i) { - push_value(L, kf[i]); - lua_rawseti(L, -2, i); - } - - return 1; - } - - int LuaScript::LuaDecodePath(lua_State *L) - { - std::string path = luaL_checkstring(L, 1); - lua_pop(L, 1); - push_value(L, config::path->Decode(path)); - return 1; - } - - int LuaScript::LuaCancel(lua_State *L) - { - lua_pushnil(L); - return lua_error(L); - } - void LuaThreadedCall(lua_State *L, int nargs, int nresults, std::string const& title, wxWindow *parent, bool can_open_config) { bool failed = false; @@ -934,18 +973,15 @@ namespace Automation4 { } LuaScriptFactory::LuaScriptFactory() - : ScriptFactory("Lua", "*.lua") + : ScriptFactory("Lua", "*.lua,*.moon") { Register(this); } Script* LuaScriptFactory::Produce(agi::fs::path const& filename) const { - // Just check if file extension is .lua - // Reject anything else - if (agi::fs::HasExtension(filename, "lua")) + if (agi::fs::HasExtension(filename, "lua") || agi::fs::HasExtension(filename, "moon")) return new LuaScript(filename); - else - return 0; + return nullptr; } } diff --git a/aegisub/src/auto4_lua.h b/aegisub/src/auto4_lua.h index 80ed7eca1..8949efe3d 100644 --- a/aegisub/src/auto4_lua.h +++ b/aegisub/src/auto4_lua.h @@ -276,54 +276,4 @@ namespace Automation4 { void ProcessSubs(AssFile *subs, wxWindow *export_dialog); }; - - class LuaScript : public Script { - lua_State *L; - - std::string name; - std::string description; - std::string author; - std::string version; - - std::vector macros; - std::vector filters; - - /// load script and create internal structures etc. - void Create(); - /// destroy internal structures, unreg features and delete environment - void Destroy(); - - static int LuaTextExtents(lua_State *L); - static int LuaInclude(lua_State *L); - static int LuaModuleLoader(lua_State *L); - static int LuaFrameFromMs(lua_State *L); - static int LuaMsFromFrame(lua_State *L); - static int LuaVideoSize(lua_State *L); - static int LuaGetKeyframes(lua_State *L); - static int LuaDecodePath(lua_State *L); - static int LuaCancel(lua_State *L); - - public: - LuaScript(agi::fs::path const& filename); - ~LuaScript(); - - void RegisterCommand(LuaCommand *command); - void UnregisterCommand(LuaCommand *command); - void RegisterFilter(LuaExportFilter *filter); - - static LuaScript* GetScriptObject(lua_State *L); - - // Script implementation - void Reload(); - - std::string GetName() const { return name; } - std::string GetDescription() const { return description; } - std::string GetAuthor() const { return author; } - std::string GetVersion() const { return version; } - bool GetLoadedState() const { return L != 0; } - - std::vector GetMacros() const { return macros; } - std::vector GetFilters() const { return filters; } - std::vector GetFormats() const { return std::vector(); } - }; } diff --git a/aegisub/src/auto4_lua_scriptreader.cpp b/aegisub/src/auto4_lua_scriptreader.cpp index edec70875..a588cd7ea 100644 --- a/aegisub/src/auto4_lua_scriptreader.cpp +++ b/aegisub/src/auto4_lua_scriptreader.cpp @@ -22,33 +22,41 @@ #include "auto4_lua_scriptreader.h" #include +#include #include +#include +#include namespace Automation4 { - LuaScriptReader::LuaScriptReader(agi::fs::path const& filename) - : file(agi::io::Open(filename)) - , first(true) - { - } + bool LoadFile(lua_State *L, agi::fs::path const& filename) { + std::unique_ptr file(agi::io::Open(filename, true)); + file->seekg(0, std::ios::end); + size_t size = file->tellg(); + file->seekg(0, std::ios::beg); - LuaScriptReader::~LuaScriptReader() { } + std::string buff; + buff.resize(size); - const char *LuaScriptReader::Read(size_t *bytes_read) { - file->read(buf, sizeof(buf)); - *bytes_read = file->gcount(); - if (first) { - first = false; - // Skip the bom - if (*bytes_read >= 3 && buf[0] == -17 && buf[1] == -69 && buf[2] == -65) { - *bytes_read -= 3; - return buf + 3; - } + // Discard the BOM if present + file->read(&buff[0], 3); + size_t start = file->gcount(); + if (start == 3 && buff[0] == -17 && buff[1] == -69 && buff[2] == -65) { + buff.resize(size - 3); + start = 0; } - return buf; - } - const char* LuaScriptReader::reader_func(lua_State *, void *data, size_t *size) { - return static_cast(data)->Read(size); + file->read(&buff[start], size - start); + + if (!agi::fs::HasExtension(filename, "moon")) + return luaL_loadbuffer(L, &buff[0], buff.size(), filename.string().c_str()) == 0; + + // We have a MoonScript file, so we need to load it with that + // It might be nice to have a dedicated lua state for compiling + // MoonScript to Lua + if (luaL_dostring(L, "return require('moonscript').loadstring")) + return false; // Leaves error message on stack + lua_pushlstring(L, &buff[0], buff.size()); + return lua_pcall(L, 1, 1, 0) == 0; // Leaves script or error message on stack } } diff --git a/aegisub/src/auto4_lua_scriptreader.h b/aegisub/src/auto4_lua_scriptreader.h index b1166ca3d..f833c876d 100644 --- a/aegisub/src/auto4_lua_scriptreader.h +++ b/aegisub/src/auto4_lua_scriptreader.h @@ -19,23 +19,8 @@ #include -#include -#include -#include - struct lua_State; namespace Automation4 { - class LuaScriptReader { - std::unique_ptr file; - bool first; - char buf[512]; - - const char *Read(size_t *bytes_read); - public: - LuaScriptReader(agi::fs::path const& filename); - ~LuaScriptReader(); - - static const char* reader_func(lua_State *, void *data, size_t *size); - }; + bool LoadFile(lua_State *L, agi::fs::path const& filename); }