package.preload['moonscript.base'] = function() local compile = require("moonscript.compile") local parse = require("moonscript.parse") local concat, insert, remove do local _obj_0 = table concat, insert, remove = _obj_0.concat, _obj_0.insert, _obj_0.remove end local split, dump, get_options, unpack do local _obj_0 = require("moonscript.util") split, dump, get_options, unpack = _obj_0.split, _obj_0.dump, _obj_0.get_options, _obj_0.unpack end local lua = { loadstring = loadstring, load = load } local dirsep, line_tables, create_moonpath, to_lua, moon_loader, loadstring, loadfile, dofile, insert_loader, remove_loader 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() local res, err = loadstring(text, file_path) if not res then error(file_path .. ": " .. err) end return res end return nil, "Could not find moon file" 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 insert_loader = function(pos) if pos == nil then pos = 2 end if not package.moonpath then package.moonpath = create_moonpath(package.path) end local loaders = package.loaders or package.searchers for _index_0 = 1, #loaders do local loader = loaders[_index_0] if loader == moon_loader then return false end end insert(loaders, pos, moon_loader) return true end remove_loader = function() local loaders = package.loaders or package.searchers for i, loader in ipairs(loaders) do if loader == moon_loader then remove(loaders, i) return true end end return false end return { _NAME = "moonscript", insert_loader = insert_loader, remove_loader = remove_loader, to_lua = to_lua, moon_chunk = moon_chunk, moon_loader = moon_loader, dirsep = dirsep, dofile = dofile, loadfile = loadfile, loadstring = loadstring } end package.preload['moonscript.cmd.coverage'] = function() local log log = function(str) if str == nil then str = "" end return io.stderr:write(str .. "\n") end local create_counter create_counter = function() return setmetatable({ }, { __index = function(self, name) do local tbl = setmetatable({ }, { __index = function(self) return 0 end }) self[name] = tbl return tbl end end }) end local position_to_lines position_to_lines = function(file_content, positions) local lines = { } local current_pos = 0 local line_no = 1 for char in file_content:gmatch(".") do do local count = rawget(positions, current_pos) if count then lines[line_no] = count end end if char == "\n" then line_no = line_no + 1 end current_pos = current_pos + 1 end return lines end local format_file format_file = function(fname, positions) local file = assert(io.open(fname)) local content = file:read("*a") file:close() local lines = position_to_lines(content, positions) log("------| @" .. tostring(fname)) local line_no = 1 for line in (content .. "\n"):gmatch("(.-)\n") do local foramtted_no = ("% 5d"):format(line_no) local sym = lines[line_no] and "*" or " " log(tostring(sym) .. tostring(foramtted_no) .. "| " .. tostring(line)) line_no = line_no + 1 end return log() end local CodeCoverage do local _base_0 = { reset = function(self) self.line_counts = create_counter() end, start = function(self) return debug.sethook((function() local _base_1 = self local _fn_0 = _base_1.process_line return function(...) return _fn_0(_base_1, ...) end end)(), "l") end, stop = function(self) return debug.sethook() end, print_results = function(self) return self:format_results() end, process_line = function(self, _, line_no) local debug_data = debug.getinfo(2, "S") local source = debug_data.source self.line_counts[source][line_no] = self.line_counts[source][line_no] + 1 end, format_results = function(self) local line_table = require("moonscript.line_tables") local positions = create_counter() for file, lines in pairs(self.line_counts) do local _continue_0 = false repeat local file_table = line_table[file] if not (file_table) then _continue_0 = true break end for line, count in pairs(lines) do local _continue_1 = false repeat local position = file_table[line] if not (position) then _continue_1 = true break end positions[file][position] = positions[file][position] + count _continue_1 = true until true if not _continue_1 then break end end _continue_0 = true until true if not _continue_0 then break end end for file, ps in pairs(positions) do format_file(file, ps) end end } _base_0.__index = _base_0 local _class_0 = setmetatable({ __init = function(self) return self:reset() end, __base = _base_0, __name = "CodeCoverage" }, { __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) return _self_0 end }) _base_0.__class = _class_0 CodeCoverage = _class_0 end return { CodeCoverage = CodeCoverage } end package.preload['moonscript.cmd.lint'] = function() local insert do local _obj_0 = table insert = _obj_0.insert end local Set do local _obj_0 = require("moonscript.data") Set = _obj_0.Set end local Block do local _obj_0 = require("moonscript.compile") Block = _obj_0.Block end local default_whitelist = Set({ '_G', '_VERSION', 'assert', 'bit32', 'collectgarbage', 'coroutine', 'debug', 'dofile', 'error', 'getfenv', 'getmetatable', 'io', 'ipairs', 'load', 'loadfile', 'loadstring', 'math', 'module', 'next', 'os', 'package', 'pairs', 'pcall', 'print', 'rawequal', 'rawget', 'rawlen', 'rawset', 'require', 'select', 'setfenv', 'setmetatable', 'string', 'table', 'tonumber', 'tostring', 'type', 'unpack', 'xpcall', "nil", "true", "false" }) local LinterBlock do local _parent_0 = Block local _base_0 = { block = function(self, ...) do local _with_0 = _parent_0.block(self, ...) _with_0.block = self.block _with_0.value_compilers = self.value_compilers return _with_0 end end } _base_0.__index = _base_0 setmetatable(_base_0, _parent_0.__base) local _class_0 = setmetatable({ __init = function(self, whitelist_globals, ...) if whitelist_globals == nil then whitelist_globals = default_whitelist end _parent_0.__init(self, ...) self.lint_errors = { } local vc = self.value_compilers self.value_compilers = setmetatable({ ref = function(block, val) local name = val[2] if not (block:has_name(name) or whitelist_globals[name] or name:match("%.")) then insert(self.lint_errors, { "accessing global " .. tostring(name), val[-1] }) end return vc.ref(block, val) end }, { __index = vc }) end, __base = _base_0, __name = "LinterBlock", __parent = _parent_0 }, { __index = function(cls, name) local val = rawget(_base_0, name) if val == nil 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.__inherited then _parent_0.__inherited(_parent_0, _class_0) end LinterBlock = _class_0 end local format_lint format_lint = function(errors, code, header) if not (next(errors)) then return end local pos_to_line, get_line do local _obj_0 = require("moonscript.util") pos_to_line, get_line = _obj_0.pos_to_line, _obj_0.get_line end local formatted do local _accum_0 = { } local _len_0 = 1 for _index_0 = 1, #errors do local _des_0 = errors[_index_0] local msg, pos msg, pos = _des_0[1], _des_0[2] if pos then local line = pos_to_line(code, pos) msg = "line " .. tostring(line) .. ": " .. tostring(msg) local line_text = "> " .. get_line(code, line) local sep_len = math.max(#msg, #line_text) _accum_0[_len_0] = table.concat({ msg, ("="):rep(sep_len), line_text }, "\n") else _accum_0[_len_0] = msg end _len_0 = _len_0 + 1 end formatted = _accum_0 end if header then table.insert(formatted, 1, header) end return table.concat(formatted, "\n\n") end local whitelist_for_file do local lint_config whitelist_for_file = function(fname) if not (lint_config) then lint_config = { } pcall(function() lint_config = require("lint_config") end) end if not (lint_config.whitelist_globals) then return default_whitelist end local final_list = { } for pattern, list in pairs(lint_config.whitelist_globals) do if fname:match(pattern) then for _index_0 = 1, #list do local item = list[_index_0] insert(final_list, item) end end end return setmetatable(Set(final_list), { __index = default_whitelist }) end end local lint_code lint_code = function(code, name, whitelist_globals) if name == nil then name = "string input" end local parse = require("moonscript.parse") local tree, err = parse.string(code) if not (tree) then return nil, err end local scope = LinterBlock(whitelist_globals) scope:stms(tree) return format_lint(scope.lint_errors, code, name) end local lint_file lint_file = function(fname) local f, err = io.open(fname) if not (f) then return nil, err end return lint_code(f:read("*a"), fname, whitelist_for_file(fname)) end return { lint_code = lint_code, lint_file = lint_file } end package.preload['moonscript.compile.statement'] = function() local util = require("moonscript.util") local data = require("moonscript.data") local reversed, unpack reversed, unpack = util.reversed, util.unpack local ntype do local _obj_0 = require("moonscript.types") ntype = _obj_0.ntype end local concat, insert do local _obj_0 = table concat, insert = _obj_0.concat, _obj_0.insert end return { 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 for _index_0 = 1, #undeclared do local name = undeclared[_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 for _index_0 = 1, #names do local name = names[_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 for _index_0 = 1, #names do local name = names[_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 for _index_0 = 1, #values do local v = values[_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 for _index_0 = 4, #node do cond = node[_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 for _index_0 = 1, #names do local name = names[_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 for _index_0 = 1, #exps do local exp = exps[_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, noop = function(self) end } end package.preload['moonscript.compile.value'] = function() local util = require("moonscript.util") local data = require("moonscript.data") local ntype do local _obj_0 = require("moonscript.types") ntype = _obj_0.ntype end local user_error do local _obj_0 = require("moonscript.errors") user_error = _obj_0.user_error end local concat, insert do local _obj_0 = table concat, insert = _obj_0.concat, _obj_0.insert end local unpack unpack = util.unpack local table_delim = "," local string_chars = { ["\r"] = "\\r", ["\n"] = "\\n" } return { 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 for _index_0 = 2, #node do local v = node[_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] local callee_type = ntype(callee) 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 if callee_type == "ref" and callee[2] == "super" or callee == "super" then do local sup = self:get("super") if sup then return self:value(sup(self, node)) end end 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: " .. tostring(t)) end end if (callee_type == "self" or callee_type == "self_class") and node[3] and ntype(node[3]) == "call" then callee[1] = callee_type .. "_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() for _index_0 = 3, #node do local action = node[_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 do local _accum_0 = { } local _len_0 = 1 for _index_0 = 1, #args do local arg = args[_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 arg_names = _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 for _index_0 = 1, #arg_names do local name = arg_names[_index_0] _with_0:put_name(name) end for _index_0 = 1, #default_args do local default = default_args[_index_0] local name, value = unpack(default) if type(name) == "table" then name = name[2] end _with_0:stm({ 'if', { 'exp', { "ref", name }, '==', 'nil' }, { { 'assign', { name }, { value } } } }) end local self_arg_values do local _accum_0 = { } local _len_0 = 1 for _index_0 = 1, #self_args do local arg = self_args[_index_0] _accum_0[_len_0] = arg[2] _len_0 = _len_0 + 1 end self_arg_values = _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 do local _accum_0 = { } local _len_0 = 1 for _index_0 = 1, #args do local arg = args[_index_0] _accum_0[_len_0] = arg[1] _len_0 = _len_0 + 1 end arg_names = _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:name(node[2]) end, self_class = function(self, node) return "self.__class." .. self:name(node[2]) end, self_colon = function(self, node) return "self:" .. self:name(node[2]) end, self_class_colon = function(self, node) return "self.__class:" .. self:name(node[2]) end, ref = function(self, value) do local sup = value[2] == "super" and self:get("super") if sup then return self:value(sup(self)) end end return tostring(value[2]) end, raw_value = function(self, value) if value == "..." then self:send("varargs") end return tostring(value) end } 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 _obj_0 = require("moonscript.transform.names") NameProxy, LocalName = _obj_0.NameProxy, _obj_0.LocalName end local Set do local _obj_0 = require("moonscript.data") Set = _obj_0.Set end local ntype, has_value do local _obj_0 = require("moonscript.types") ntype, has_value = _obj_0.ntype, _obj_0.has_value end local statement_compilers = require("moonscript.compile.statement") local value_compilers = require("moonscript.compile.value") local concat, insert do local _obj_0 = table concat, insert = _obj_0.concat, _obj_0.insert end local pos_to_line, get_closest_line, trim, unpack 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 _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] for _ in l:gmatch("\n") do line_no = line_no + 1 end 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 local _accum_0 = { } local _len_0 = 1 for _index_0 = 1, #t do local v = t[_index_0] _accum_0[_len_0] = strip(v) _len_0 = _len_0 + 1 end return _accum_0 else return t end end return "Lines<" .. tostring(util.dump(strip(self)):sub(1, -2)) .. ">" end } _base_0.__index = _base_0 local _class_0 = setmetatable({ __init = function(self) self.posmap = { } end, __base = _base_0, __name = "Lines" }, { __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) return _self_0 end }) _base_0.__class = _class_0 Lines = _class_0 end do local _base_0 = { pos = nil, append_list = function(self, items, delim) for i = 1, #items do self:append(items[i]) if i < #items then insert(self, delim) end end return nil end, append = function(self, first, ...) if Line == mtype(first) then if not (self.pos) then self.pos = first.pos end for _index_0 = 1, #first do local value = first[_index_0] self:append(value) end else insert(self, first) end if ... then return self:append(...) end end, render = function(self, buffer) local current = { } local add_current add_current = function() buffer:add(concat(current)) return buffer:mark_pos(self.pos) end for _index_0 = 1, #self do local chunk = self[_index_0] local _exp_0 = mtype(chunk) if Block == _exp_0 then local _list_0 = chunk:render(Lines()) for _index_1 = 1, #_list_0 do local block_chunk = _list_0[_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[1] 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 local _class_0 = setmetatable({ __init = function() end, __base = _base_0, __name = "Line" }, { __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) return _self_0 end }) _base_0.__class = _class_0 Line = _class_0 end do local _base_0 = { prepare = function() end, render = function(self) self:prepare() return concat(self) end } _base_0.__index = _base_0 local _class_0 = setmetatable({ __init = function(self, fn) self.prepare = fn end, __base = _base_0, __name = "DelayedLine" }, { __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) return _self_0 end }) _base_0.__class = _class_0 DelayedLine = _class_0 end do local _base_0 = { header = "do", footer = "end", export_all = false, export_proper = false, value_compilers = value_compilers, __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 do local _accum_0 = { } local _len_0 = 1 for _index_0 = 1, #names do local _continue_0 = false repeat local name = names[_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 "table" == _exp_0 then real_name = name[1] == "ref" and name[2] 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 undeclared = _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, is_local = function(self, node) local t = mtype(node) if t == "string" then return self:has_name(node, false) end if t == NameProxy or t == LocalName then return true end if t == "table" then if node[1] == "ref" or (node[1] == "chain" and #node == 2) then return self:is_local(node[2]) end end return false 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 self.value_compilers[t] ~= nil or t == "value" end, name = function(self, node, ...) if type(node) == "string" then return node else return self:value(node, ...) end 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 = self.value_compilers[action] if not (fn) then error({ "compile-error", "Failed to find value compiler for: " .. dump.value(node), node[-1] }) 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 for _index_0 = 1, #values do local v = values[_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 current_stms, current_stm_i = self.current_stms, self.current_stm_i 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 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 self.transform = { value = transform.Value:bind(self), statement = transform.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" }, { __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) return _self_0 end }) _base_0.__class = _class_0 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 setmetatable(_base_0, _parent_0.__base) 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 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.__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_message if pos then 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 "" line_message = (" [%d] >> %s"):format(line, trim(line_str)) end return concat({ "Compile error: " .. msg, line_message }, "\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, error_pos if type(err) == "table" then local error_type = err[1] local _exp_0 = err[1] if "user-error" == _exp_0 or "compile-error" == _exp_0 then error_msg, error_pos = unpack(err, 2) else error_msg, error_pos = error("Unknown error thrown", util.dump(error_msg)) end else error_msg, error_pos = concat({ err, debug.traceback(runner) }, "\n") end return nil, error_msg, error_pos or scope.last_pos end local lua_code = scope:render() local posmap = scope._lines:flatten_posmap() return lua_code, posmap end do local data = require("moonscript.data") 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 do local _obj_0 = table concat, remove, insert = _obj_0.concat, _obj_0.remove, _obj_0.insert end local Set Set = function(items) local _tbl_0 = { } for _index_0 = 1, #items do local k = items[_index_0] _tbl_0[k] = true end return _tbl_0 end local Stack do local _base_0 = { __tostring = function(self) return "" end, pop = function(self) return remove(self) end, push = function(self, value, ...) insert(self, value) if ... then return self:push(...) else return value end end, top = function(self) return self[#self] end } _base_0.__index = _base_0 local _class_0 = setmetatable({ __init = function(self, ...) self:push(...) return nil end, __base = _base_0, __name = "Stack" }, { __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) return _self_0 end }) _base_0.__class = _class_0 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 do local _accum_0 = { } local _len_0 = 1 for _index_0 = 1, #op do local item = op[_index_0] _accum_0[_len_0] = flat_value(item, depth + 1) _len_0 = _len_0 + 1 end items = _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 do local _obj_0 = table concat, insert = _obj_0.concat, _obj_0.insert end local split, pos_to_line 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 do local _accum_0 = { } local _len_0 = 1 local _max_0 = stop for _index_0 = 1, _max_0 < 0 and #traceback + _max_0 or _max_0 do local t = traceback[_index_0] _accum_0[_len_0] = t _len_0 = _len_0 + 1 end traceback = _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 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, reverse_line_number = reverse_line_number } end package.preload['moonscript'] = function() do local _with_0 = require("moonscript.base") _with_0.insert_loader() return _with_0 end 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 * (S"uU"^-1 * S"lL"^2)^-1 + R"09"^1 * (S"uU"^-1 * S"lL"^2) + ( 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) if node == "..." then return false end local t = ntype(node) return t == "ref" or 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 VarArg = Space * P"..." / 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) * SpaceBreak^0 * key"from" * Exp / mark"import", ImportName = (sym"\\" * Ct(Cc"colon_stub" * Name) + Name), ImportNameList = SpaceBreak^0 * ImportName * ((SpaceBreak^1 + sym"," * SpaceBreak^0) * ImportName)^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 + SelfName, 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 = pos(Name / mark"ref") + SelfName + VarArg + 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":" * -SomeSpace * 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 * (sym"," * Ct(VarArg))^0 + Ct(VarArg), FnArgDef = Ct((Name + SelfName) * (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 parse_args = {...} local pass, err = xpcall(function() tree = self._g:match(str, unpack(parse_args)) end, function(err) return debug.traceback(err, 2) end) -- regular error, let it bubble up if type(err) == "string" then return nil, 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 _obj_0 = require("moonscript.types") ntype, mtype, build = _obj_0.ntype, _obj_0.mtype, _obj_0.build end local NameProxy do local _obj_0 = require("moonscript.transform.names") NameProxy = _obj_0.NameProxy end local insert do local _obj_0 = table insert = _obj_0.insert end local unpack do local _obj_0 = require("moonscript.util") unpack = _obj_0.unpack end local user_error do local _obj_0 = require("moonscript.errors") user_error = _obj_0.user_error end local util = require("moonscript.util") local join join = function(...) do local out = { } local i = 1 local _list_0 = { ... } for _index_0 = 1, #_list_0 do local tbl = _list_0[_index_0] for _index_1 = 1, #tbl do local v = tbl[_index_1] out[i] = v i = i + 1 end end return out end end local has_destructure has_destructure = function(names) for _index_0 = 1, #names do local n = names[_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 local key_name = key[2] if ntype(key_name) == "colon_stub" then s = key_name else s = { "dot", key_name } end else s = { "index", key } end value, suffix = tuple[2], s end suffix = join(prefix, { suffix }) local _exp_0 = ntype(value) if "value" == _exp_0 or "ref" == _exp_0 or "chain" == _exp_0 or "self" == _exp_0 then insert(accum, { value, suffix }) elseif "table" == _exp_0 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(scope, destruct_literal, receiver) local extracted_names = extract_assign_names(destruct_literal) local names = { } local values = { } local inner = { "assign", names, values } local obj if scope:is_local(receiver) then obj = receiver else do obj = NameProxy("obj") inner = build["do"]({ build.assign_one(obj, receiver), { "assign", names, values } }) obj = obj end end for _index_0 = 1, #extracted_names do local tuple = extracted_names[_index_0] insert(names, tuple[1]) insert(values, NameProxy.chain(obj, unpack(tuple[2]))) end return build.group({ { "declare", names }, inner }) end local split_assign split_assign = function(scope, 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(scope, 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 do 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 name_slice = _accum_0 end end local value_slice if total_values < start then value_slice = { "nil" } else do 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 value_slice = _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 _obj_0 = require("moonscript.types") build = _obj_0.build end local unpack do local _obj_0 = require("moonscript.util") unpack = _obj_0.unpack end local LocalName do local _base_0 = { get_name = function(self) return self.name end } _base_0.__index = _base_0 local _class_0 = setmetatable({ __init = function(self, name) self.name = name self[1] = "temp_name" end, __base = _base_0, __name = "LocalName" }, { __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) return _self_0 end }) _base_0.__class = _class_0 LocalName = _class_0 end local NameProxy do 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 = { base = self, ... } for k, v in ipairs(items) do if type(v) == "string" then items[k] = { "dot", v } else items[k] = v end end return build.chain(items) end, index = function(self, key) if type(key) == "string" then key = { "ref", key } end 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 local _class_0 = setmetatable({ __init = function(self, prefix) self.prefix = prefix self[1] = "temp_name" end, __base = _base_0, __name = "NameProxy" }, { __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) return _self_0 end }) _base_0.__class = _class_0 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 reversed, unpack = util.reversed, util.unpack local ntype, mtype, build, smart_node, is_slice, value_is_singular 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 do local _obj_0 = table insert = _obj_0.insert end local NameProxy, LocalName do local _obj_0 = require("moonscript.transform.names") NameProxy, LocalName = _obj_0.NameProxy, _obj_0.LocalName end local destructure = require("moonscript.transform.destructure") local NOOP = { "noop" } local Run, apply_to_last, is_singular, extract_declarations, expand_elseif_assign, constructor_name, with_continue_listener, Transformer, construct_comprehension, Statement, Accumulator, default_accumulator, implicitly_return, Value do local _base_0 = { call = function(self, state) return self.fn(state) end } _base_0.__index = _base_0 local _class_0 = setmetatable({ __init = function(self, fn) self.fn = fn self[1] = "run" end, __base = _base_0, __name = "Run" }, { __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) return _self_0 end }) _base_0.__class = _class_0 Run = _class_0 end 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] = { "transform", stm, fn } else _accum_0[_len_0] = stm end _len_0 = _len_0 + 1 end return _accum_0 end)() end 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 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 ntype(name) == "ref" then insert(out, name) elseif 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 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 constructor_name = "new" 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 do local _base_0 = { transform_once = function(self, scope, node, ...) if self.seen_nodes[node] then return node end self.seen_nodes[node] = true local transformer = self.transformers[ntype(node)] if transformer then return transformer(scope, node, ...) or node else return node end end, 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 local _class_0 = setmetatable({ __init = function(self, transformers) self.transformers = transformers self.seen_nodes = setmetatable({ }, { __mode = "k" }) end, __base = _base_0, __name = "Transformer" }, { __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) return _self_0 end }) _base_0.__class = _class_0 Transformer = _class_0 end 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 _, name, bounds = clause[1], clause[2], clause[3] current_stms = { "for", name, bounds, current_stms } elseif "foreach" == _exp_0 then local names, iter _, names, iter = clause[1], clause[2], clause[3] current_stms = { "foreach", names, { iter }, current_stms } elseif "when" == _exp_0 then local cond _, cond = clause[1], clause[2] 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 Statement = Transformer({ transform = function(self, tuple) local _, node, fn _, node, fn = tuple[1], tuple[2], tuple[3] return fn(node) end, root_stms = function(self, body) return apply_to_last(body, implicitly_return(self)) end, ["return"] = function(self, node) local ret_val = node[2] local ret_val_type = ntype(ret_val) if ret_val_type == "explist" and #ret_val == 2 then ret_val = ret_val[2] ret_val_type = ntype(ret_val) end if types.cascading[ret_val_type] then return implicitly_return(self)(ret_val) end if ret_val_type == "chain" or ret_val_type == "comprehension" or ret_val_type == "tblcomprehension" then ret_val = Value:transform_once(self, ret_val) if ntype(ret_val) == "block_exp" then return build.group(apply_to_last(ret_val[2], function(stm) return { "return", stm } end)) end end node[2] = ret_val return node end, declare_glob = function(self, node) local names = extract_declarations(self) if node[2] == "^" then do local _accum_0 = { } local _len_0 = 1 for _index_0 = 1, #names do local _continue_0 = false repeat local name = names[_index_0] if not (name[2]: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 names = _accum_0 end end return { "declare", names } end, assign = function(self, node) local names, values = unpack(node, 2) local num_values = #values local num_names = #values if num_names == 1 and num_values == 1 then local first_value = values[1] local first_name = names[1] local first_type = ntype(first_value) if first_type == "chain" then first_value = Value:transform_once(self, first_value) first_type = ntype(first_value) end local _exp_0 = ntype(first_value) if "block_exp" == _exp_0 then local block_body = first_value[2] local idx = #block_body block_body[idx] = build.assign_one(first_name, block_body[idx]) return build.group({ { "declare", { first_name } }, { "do", block_body } }) elseif "comprehension" == _exp_0 or "tblcomprehension" == _exp_0 or "foreach" == _exp_0 or "for" == _exp_0 or "while" == _exp_0 then return build.assign_one(first_name, Value:transform_once(self, first_value)) else values[1] = first_value end end local transformed if num_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(self, 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({ { "export", node[2] }, 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 table_values do local _accum_0 = { } local _len_0 = 1 for _index_0 = 1, #names do local name = names[_index_0] local dest_val if ntype(name) == "colon_stub" then dest_val = name[2] else dest_val = name end local _value_0 = { { "key_literal", name }, dest_val } _accum_0[_len_0] = _value_0 _len_0 = _len_0 + 1 end table_values = _accum_0 end local dest = { "table", table_values } return { "assign", { dest }, { source }, [-1] = node[-1] } 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 ntype(name) == "ref" 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(self, 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, 2) local copy_scope = true local scope_name, named_assign if ntype(exp) == "assign" then local names, values = unpack(exp, 2) local first_name = names[1] if ntype(first_name) == "ref" then scope_name = first_name named_assign = exp exp = values[1] copy_scope = false else scope_name = NameProxy("with") exp = values[1] values[1] = scope_name named_assign = { "assign", names, values } end elseif self:is_local(exp) then scope_name = exp copy_scope = false end scope_name = scope_name or NameProxy("with") return build["do"]({ Run(function(self) return self:set("scope_var", scope_name) end), copy_scope and build.assign_one(scope_name, exp) or NOOP, named_assign or NOOP, 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 = { } do local _accum_0 = { } local _len_0 = 1 for i, name in ipairs(node.names) do if ntype(name) == "table" then do local proxy = NameProxy("des") insert(destructures, destructure.build_assign(self, name, proxy)) _accum_0[_len_0] = proxy end else _accum_0[_len_0] = name end _len_0 = _len_0 + 1 end node.names = _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 = self:is_local(list) and list or 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 self:is_local(list) then list_name = list end 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({ list_name ~= list and build.assign_one(list_name, list) or NOOP, slice_var or NOOP, build["for"]({ name = index_name, bounds = bounds, body = { { "assign", node.names, { NameProxy.index(list_name, 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" } for _index_0 = 1, #conds do local cond = conds[_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) if parent_val == "" then parent_val = nil end local statements = { } local properties = { } for _index_0 = 1, #body do local item = body[_index_0] local _exp_0 = item[1] if "stm" == _exp_0 then insert(statements, item[2]) elseif "props" == _exp_0 then for _index_1 = 2, #item do local tuple = item[_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 do local _accum_0 = { } local _len_0 = 1 for _index_0 = 1, #properties do local _continue_0 = false repeat local tuple = properties[_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 properties = _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 if parent_val then constructor = build.fndef({ args = { { "..." } }, arrow = "fat", body = { build.chain({ base = "super", { "call", { "..." } } }) } }) else constructor = build.fndef() end 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 local name_t = type(real_name) local flattened_name if name_t == "string" then flattened_name = real_name elseif name_t == "table" and real_name[1] == "ref" then flattened_name = real_name[2] else flattened_name = error("don't know how to extract name from " .. tostring(name_t)) end real_name = { "string", '"', flattened_name } end local cls = build.table({ { "__init", constructor }, { "__base", base_name }, { "__name", real_name }, parent_val and { "__parent", parent_cls_name } or nil }) local class_index if parent_val then local class_lookup = build["if"]({ cond = { "exp", { "ref", "val" }, "==", "nil" }, ["then"] = { parent_cls_name:index("name") } }) insert(class_lookup, { "else", { "val" } }) class_index = build.fndef({ args = { { "cls" }, { "name" } }, body = { build.assign_one(LocalName("val"), build.chain({ base = "rawget", { "call", { base_name, { "ref", "name" } } } })), class_lookup } }) else class_index = base_name end local cls_mt = build.table({ { "__index", class_index }, { "__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 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 do local _accum_0 = { } local _len_0 = 1 for _index_0 = 3, #chain do local item = chain[_index_0] _accum_0[_len_0] = item _len_0 = _len_0 + 1 end slice = _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 for _index_0 = 1, #slice do local item = slice[_index_0] insert(new_chain, item) end return new_chain else return parent_cls_name end end) end), { "declare_glob", "*" }, parent_val and build.assign_one(parent_cls_name, parent_val) or NOOP, build.assign_one(base_name, { "table", properties }), build.assign_one(base_name:chain("__index"), base_name), parent_val and build.chain({ base = "setmetatable", { "call", { base_name, build.chain({ base = parent_cls_name, { "dot", "__base" } }) } } }) or NOOP, build.assign_one(cls_name, cls), build.assign_one(base_name:chain("__class"), cls_name), build.group((function() if #statements > 0 then return { build.assign_one(LocalName("self"), cls_name), build.group(statements) } end end)()), parent_val and build["if"]({ cond = { "exp", parent_cls_name:chain("__inherited") }, ["then"] = { parent_cls_name:chain("__inherited", { "call", { parent_cls_name, cls_name } }) } }) or NOOP, build.group((function() if name then return { build.assign_one(name, cls_name) } end end)()), (function() if ret then return ret(cls_name) end end)() } value = build.group({ build.group((function() if ntype(name) == "value" then return { build.declare({ names = { name } }) } end end)()), build["do"](out_body) }) end return value end }) do 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, group_type) if group_type == nil then group_type = "block_exp" end return build[group_type]({ build.assign_one(self.accum_name, build.table()), build.assign_one(self.len_name, 1), node, group_type == "block_exp" and self.accum_name or NOOP }) 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(NameProxy.index(self.accum_name, self.len_name), val), { "update", self.len_name, "+=", 1 } } insert(body, build.group(update)) return body end } _base_0.__index = _base_0 local _class_0 = setmetatable({ __init = function(self, accum_name) self.accum_name = NameProxy("accum") self.value_name = NameProxy("value") self.len_name = NameProxy("len") end, __base = _base_0, __name = "Accumulator" }, { __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) return _self_0 end }) _base_0.__class = _class_0 Accumulator = _class_0 end 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 NOOP 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 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 if type(node[3]) == "string" then return node else return convert_part(node[3]) 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 = ntype(node[2]) == "ref" and node[2][2] == "super" return 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 Set do local _obj_0 = require("moonscript.data") Set = _obj_0.Set end local insert do local _obj_0 = table insert = _obj_0.insert end local unpack unpack = util.unpack local manual_return = Set({ "foreach", "for", "while", "return" }) local cascading = 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 for _index_0 = 1, #tbl do local tuple = tbl[_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") if type(base) == "string" then base = { "ref", base } end local node = { "chain", base } for _index_0 = 1, #parts do local part = parts[_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 do local _obj_0 = table concat = _obj_0.concat end 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 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 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 do 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 lines = _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 do 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 tuples = _accum_0 end table.sort(tuples, function(a, b) return a[1] < b[1] end) local lines do local _accum_0 = { } local _len_0 = 1 for _index_0 = 1, #tuples do local pair = tuples[_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 lines = _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.5" function print_version() print("MoonScript version "..version) end end return package.preload["moonscript"]()