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, loadstring, loadfile, dofile dirsep = "/" line_tables = require("moonscript.line_tables") create_moonpath = function(package_path) local paths = split(package_path, ";") for i, path in ipairs(paths) do local p = path:match("^(.-)%.lua$") if p then paths[i] = p .. ".moon" end end return concat(paths, ";") end to_lua = function(text, options) if options == nil then options = { } end if "string" ~= type(text) then local t = type(text) return nil, "expecting string (got " .. t .. ")" 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) end return code, ltable 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, "@" .. tostring(fname), ...) end dofile = function(...) local f = assert(loadfile(...)) return f() end return { _NAME = "moonscript", to_lua = to_lua, 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 insert = table.insert local Set Set = require("moonscript.data").Set local Block Block = require("moonscript.compile").Block local mtype mtype = require("moonscript.util").moon.type 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 = { lint_mark_used = function(self, name) if self.lint_unused_names and self.lint_unused_names[name] then self.lint_unused_names[name] = false return end if self.parent then return self.parent:lint_mark_used(name) end end, lint_check_unused = function(self) if not (self.lint_unused_names and next(self.lint_unused_names)) then return end local names_by_position = { } for name, pos in pairs(self.lint_unused_names) do local _continue_0 = false repeat if not (pos) then _continue_0 = true break end names_by_position[pos] = names_by_position[pos] or { } insert(names_by_position[pos], name) _continue_0 = true until true if not _continue_0 then break end end local tuples do local _accum_0 = { } local _len_0 = 1 for pos, names in pairs(names_by_position) do _accum_0[_len_0] = { pos, names } _len_0 = _len_0 + 1 end tuples = _accum_0 end table.sort(tuples, function(a, b) return a[1] < b[1] end) for _index_0 = 1, #tuples do local _des_0 = tuples[_index_0] local pos, names pos, names = _des_0[1], _des_0[2] insert(self:get_root_block().lint_errors, { "assigned but unused " .. tostring(table.concat((function() local _accum_0 = { } local _len_0 = 1 for _index_1 = 1, #names do local n = names[_index_1] _accum_0[_len_0] = "`" .. tostring(n) .. "`" _len_0 = _len_0 + 1 end return _accum_0 end)(), ", ")), pos }) end end, render = function(self, ...) self:lint_check_unused() return _parent_0.render(self, ...) end, block = function(self, ...) do local _with_0 = _parent_0.block(self, ...) _with_0.block = self.block _with_0.render = self.render _with_0.get_root_block = self.get_root_block _with_0.lint_check_unused = self.lint_check_unused _with_0.lint_mark_used = self.lint_mark_used _with_0.value_compilers = self.value_compilers _with_0.statement_compilers = self.statement_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.get_root_block = function() return self end 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 block:lint_mark_used(name) return vc.ref(block, val) end }, { __index = vc }) local sc = self.statement_compilers self.statement_compilers = setmetatable({ assign = function(block, node) local names = node[2] for _index_0 = 1, #names do local _continue_0 = false repeat local name = names[_index_0] if type(name) == "table" and name[1] == "temp_name" then _continue_0 = true break end local real_name, is_local = block:extract_assign_name(name) if not (is_local or real_name and not block:has_name(real_name, true)) then _continue_0 = true break end if real_name == "_" then _continue_0 = true break end block.lint_unused_names = block.lint_unused_names or { } block.lint_unused_names[real_name] = node[-1] or 0 _continue_0 = true until true if not _continue_0 then break end end return sc.assign(block, node) end }, { __index = sc }) 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) scope:lint_check_unused() 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.cmd.moonc'] = function() local lfs = require("lfs") local split split = require("moonscript.util").split local dirsep, dirsep_chars, mkdir, normalize_dir, parse_dir, parse_file, convert_path, format_time, gettime, compile_file_text, write_file, compile_and_write, is_abs_path, path_to_target dirsep = package.config:sub(1, 1) if dirsep == "\\" then dirsep_chars = "\\/" else dirsep_chars = dirsep end mkdir = function(path) local chunks = split(path, dirsep) local accum for _index_0 = 1, #chunks do local dir = chunks[_index_0] accum = accum and tostring(accum) .. tostring(dirsep) .. tostring(dir) or dir lfs.mkdir(accum) end return lfs.attributes(path, "mode") end normalize_dir = function(path) return path:match("^(.-)[" .. tostring(dirsep_chars) .. "]*$") .. dirsep end parse_dir = function(path) return (path:match("^(.-)[^" .. tostring(dirsep_chars) .. "]*$")) end parse_file = function(path) return (path:match("^.-([^" .. tostring(dirsep_chars) .. "]*)$")) end convert_path = function(path) local new_path = path:gsub("%.moon$", ".lua") if new_path == path then new_path = path .. ".lua" end return new_path end format_time = function(time) return ("%.3fms"):format(time * 1000) end do local socket gettime = function() if socket == nil then pcall(function() socket = require("socket") end) if not (socket) then socket = false end end if socket then return socket.gettime() else return nil, "LuaSocket needed for benchmark" end end end compile_file_text = function(text, opts) if opts == nil then opts = { } end local parse = require("moonscript.parse") local compile = require("moonscript.compile") local parse_time if opts.benchmark then parse_time = assert(gettime()) end local tree, err = parse.string(text) if not (tree) then return nil, err end if parse_time then parse_time = gettime() - parse_time end if opts.show_parse_tree then local dump = require("moonscript.dump") dump.tree(tree) return true end local compile_time if opts.benchmark then compile_time = gettime() end local code, posmap_or_err, err_pos = compile.tree(tree) if not (code) then return nil, compile.format_error(posmap_or_err, err_pos, text) end if compile_time then compile_time = gettime() - compile_time end if opts.show_posmap then local debug_posmap debug_posmap = require("moonscript.util").debug_posmap print("Pos", "Lua", ">>", "Moon") print(debug_posmap(posmap_or_err, text, code)) return true end if opts.benchmark then print(table.concat({ opts.fname or "stdin", "Parse time \t" .. format_time(parse_time), "Compile time\t" .. format_time(compile_time), "" }, "\n")) return nil end return code end write_file = function(fname, code) mkdir(parse_dir(fname)) local f, err = io.open(fname, "w") if not (f) then return nil, err end assert(f:write(code)) assert(f:write("\n")) f:close() return "build" end compile_and_write = function(src, dest, opts) if opts == nil then opts = { } end local f = io.open(src) if not (f) then return nil, "Can't find file" end local text = assert(f:read("*a")) f:close() local code, err = compile_file_text(text, opts) if not code then return nil, err end if code == true then return true end if opts.print then print(code) return true end return write_file(dest, code) end is_abs_path = function(path) local first = path:sub(1, 1) if dirsep == "\\" then return first == "/" or first == "\\" or path:sub(2, 1) == ":" else return first == dirsep end end path_to_target = function(path, target_dir, base_dir) if target_dir == nil then target_dir = nil end if base_dir == nil then base_dir = nil end local target = convert_path(path) if target_dir then target_dir = normalize_dir(target_dir) end if base_dir and target_dir then local head = base_dir:match("^(.-)[^" .. tostring(dirsep_chars) .. "]*[" .. tostring(dirsep_chars) .. "]?$") if head then local start, stop = target:find(head, 1, true) if start == 1 then target = target:sub(stop + 1) end end end if target_dir then if is_abs_path(target) then target = parse_file(target) end target = target_dir .. target end return target end return { dirsep = dirsep, mkdir = mkdir, normalize_dir = normalize_dir, parse_dir = parse_dir, parse_file = parse_file, convert_path = convert_path, gettime = gettime, format_time = format_time, path_to_target = path_to_target, compile_file_text = compile_file_text, compile_and_write = compile_and_write } end package.preload['moonscript.compile.statement'] = function() local util = require("moonscript.util") local reversed, unpack reversed, unpack = util.reversed, util.unpack local ntype ntype = require("moonscript.types").ntype 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, node[-1]) 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 ntype = require("moonscript.types").ntype local user_error user_error = require("moonscript.errors").user_error 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 Set = require("moonscript.data").Set 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") 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, statement_compilers = statement_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, extract_assign_name = function(self, node) local is_local = false local real_name local _exp_0 = mtype(node) if LocalName == _exp_0 then is_local = true real_name = node:get_name(self) elseif NameProxy == _exp_0 then real_name = node:get_name(self) elseif "table" == _exp_0 then real_name = node[1] == "ref" and node[2] elseif "string" == _exp_0 then real_name = node end return real_name, is_local 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 real_name, is_local = self:extract_assign_name(name) 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, pos) do local _with_0 = self._lines _with_0:add(item) if pos then _with_0:mark_pos(pos) end end 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 self.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 = self.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 _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 = assert(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('^(.-):(%d+): (.*)$') local tbl = line_tables["@" .. tostring(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") return _with_0 end end package.preload['moonscript.line_tables'] = function() return { } end package.preload['moonscript.parse.env'] = function() local getfenv, setfenv do local _obj_0 = require("moonscript.util") getfenv, setfenv = _obj_0.getfenv, _obj_0.setfenv end local wrap_env wrap_env = function(debug, fn) local V, Cmt do local _obj_0 = require("lpeg") V, Cmt = _obj_0.V, _obj_0.Cmt end local env = getfenv(fn) local wrap_name = V if debug then local indent = 0 local indent_char = " " local iprint iprint = function(...) local args = table.concat((function(...) local _accum_0 = { } local _len_0 = 1 local _list_0 = { ... } for _index_0 = 1, #_list_0 do local a = _list_0[_index_0] _accum_0[_len_0] = tostring(a) _len_0 = _len_0 + 1 end return _accum_0 end)(...), ", ") return io.stderr:write(tostring(indent_char:rep(indent)) .. tostring(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) return v end return error("unknown variable referenced: " .. tostring(name)) end })) end return { wrap_env = wrap_env } end package.preload['moonscript.parse.literals'] = function() local safe_module safe_module = require("moonscript.util").safe_module local S, P, R, C do local _obj_0 = require("lpeg") S, P, R, C = _obj_0.S, _obj_0.P, _obj_0.R, _obj_0.C end local White = S(" \t\r\n") ^ 0 local plain_space = S(" \t") ^ 0 local Break = P("\r") ^ -1 * P("\n") local Stop = Break + -1 local Comment = P("--") * (1 - S("\r\n")) ^ 0 * #Stop local Space = plain_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 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 local Shebang = P("#!") * P(1 - Stop) ^ 0 return safe_module("moonscript.parse.literals", { White = White, Break = Break, Stop = Stop, Comment = Comment, Space = Space, SomeSpace = SomeSpace, SpaceBreak = SpaceBreak, EmptyLine = EmptyLine, AlphaNum = AlphaNum, Name = Name, Num = Num, Shebang = Shebang }) end package.preload['moonscript.parse.util'] = function() local unpack unpack = require("moonscript.util").unpack local P, C, S, Cp, Cmt, V do local _obj_0 = require("lpeg") P, C, S, Cp, Cmt, V = _obj_0.P, _obj_0.C, _obj_0.S, _obj_0.Cp, _obj_0.Cmt, _obj_0.V end local ntype ntype = require("moonscript.types").ntype local Space Space = require("moonscript.parse.literals").Space local Indent = C(S("\t ") ^ 0) / function(str) do local sum = 0 for v in str:gmatch("[\t ]") do local _exp_0 = v if " " == _exp_0 then sum = sum + 1 elseif "\t" == _exp_0 then sum = sum + 4 end end return sum end end local Cut = P(function() return false end) local ensure ensure = function(patt, finally) return patt * finally + finally * Cut end local extract_line extract_line = function(str, start_pos) str = str:sub(start_pos) do local m = str:match("^(.-)\n") if m then return m end end return str:match("^.-$") end local mark mark = function(name) return function(...) return { name, ... } end end local pos pos = function(patt) return (Cp() * patt) / function(pos, value) if type(value) == "table" then value[-1] = pos end return value end end local got got = function(what) return Cmt("", function(str, pos) print("++ got " .. tostring(what), "[" .. tostring(extract_line(str, pos)) .. "]") return true end) end local flatten_or_mark flatten_or_mark = function(name) return function(tbl) if #tbl == 1 then return tbl[1] end table.insert(tbl, 1, name) return tbl end end local is_assignable do local chain_assignable = { index = true, dot = true, slice = true } is_assignable = function(node) if node == "..." then return false end local _exp_0 = ntype(node) if "ref" == _exp_0 or "self" == _exp_0 or "value" == _exp_0 or "self_class" == _exp_0 or "table" == _exp_0 then return true elseif "chain" == _exp_0 then return chain_assignable[ntype(node[#node])] else return false end end end local check_assignable check_assignable = function(str, pos, value) if is_assignable(value) then return true, value else return false end end local format_assign do local flatten_explist = flatten_or_mark("explist") format_assign = function(lhs_exps, assign) if not (assign) then return flatten_explist(lhs_exps) end for _index_0 = 1, #lhs_exps do local assign_exp = lhs_exps[_index_0] if not (is_assignable(assign_exp)) then error({ assign_exp, "left hand expression is not assignable" }) end end local t = ntype(assign) local _exp_0 = t if "assign" == _exp_0 then return { "assign", lhs_exps, unpack(assign, 2) } elseif "update" == _exp_0 then return { "update", lhs_exps[1], unpack(assign, 2) } else return error("unknown assign expression: " .. tostring(t)) end end end local format_single_assign format_single_assign = function(lhs, assign) if assign then return format_assign({ lhs }, assign) else return lhs end end local sym sym = function(chars) return Space * chars end local symx symx = function(chars) return chars end local simple_string simple_string = function(delim, allow_interpolation) local inner = P("\\" .. tostring(delim)) + "\\\\" + (1 - P(delim)) if allow_interpolation then local interp = symx('#{') * V("Exp") * sym('}') inner = (C((inner - interp) ^ 1) + interp / mark("interpolate")) ^ 0 else inner = C(inner ^ 0) end return C(symx(delim)) * inner * sym(delim) / mark("string") end local wrap_func_arg wrap_func_arg = function(value) return { "call", { value } } end local flatten_func flatten_func = function(callee, args) if #args == 0 then return callee end args = { "call", args } if ntype(callee) == "chain" then local stub = callee[#callee] if ntype(stub) == "colon_stub" then stub[1] = "colon" table.insert(stub, args) else table.insert(callee, args) end return callee end return { "chain", callee, args } end local flatten_string_chain flatten_string_chain = function(str, chain, args) if not (chain) then return str end return flatten_func({ "chain", str, unpack(chain) }, args) end local wrap_decorator wrap_decorator = function(stm, dec) if not (dec) then return stm end return { "decorated", stm, dec } end local check_lua_string check_lua_string = function(str, pos, right, left) return #left == #right end local self_assign self_assign = function(name, pos) return { { "key_literal", name }, { "ref", name, [-1] = pos } } end return { Indent = Indent, Cut = Cut, ensure = ensure, extract_line = extract_line, mark = mark, pos = pos, flatten_or_mark = flatten_or_mark, is_assignable = is_assignable, check_assignable = check_assignable, format_assign = format_assign, format_single_assign = format_single_assign, sym = sym, symx = symx, simple_string = simple_string, wrap_func_arg = wrap_func_arg, flatten_func = flatten_func, flatten_string_chain = flatten_string_chain, wrap_decorator = wrap_decorator, check_lua_string = check_lua_string, self_assign = self_assign } end package.preload['moonscript.parse'] = function() local debug_grammar = false local lpeg = require("lpeg") lpeg.setmaxstack(10000) local err_msg = "Failed to parse:%s\n [%d] >> %s" local Stack Stack = require("moonscript.data").Stack local trim, pos_to_line, get_line do local _obj_0 = require("moonscript.util") trim, pos_to_line, get_line = _obj_0.trim, _obj_0.pos_to_line, _obj_0.get_line end local unpack unpack = require("moonscript.util").unpack local wrap_env wrap_env = require("moonscript.parse.env").wrap_env local R, S, V, P, C, Ct, Cmt, Cg, Cb, Cc R, S, V, P, C, Ct, Cmt, Cg, Cb, Cc = lpeg.R, lpeg.S, lpeg.V, lpeg.P, lpeg.C, lpeg.Ct, lpeg.Cmt, lpeg.Cg, lpeg.Cb, lpeg.Cc local White, Break, Stop, Comment, Space, SomeSpace, SpaceBreak, EmptyLine, AlphaNum, Num, Shebang, _Name do local _obj_0 = require("moonscript.parse.literals") White, Break, Stop, Comment, Space, SomeSpace, SpaceBreak, EmptyLine, AlphaNum, Num, Shebang, _Name = _obj_0.White, _obj_0.Break, _obj_0.Stop, _obj_0.Comment, _obj_0.Space, _obj_0.SomeSpace, _obj_0.SpaceBreak, _obj_0.EmptyLine, _obj_0.AlphaNum, _obj_0.Num, _obj_0.Shebang, _obj_0.Name end local SpaceName = Space * _Name Num = Space * (Num / function(v) return { "number", v } end) local Indent, Cut, ensure, extract_line, mark, pos, flatten_or_mark, is_assignable, check_assignable, format_assign, format_single_assign, sym, symx, simple_string, wrap_func_arg, flatten_func, flatten_string_chain, wrap_decorator, check_lua_string, self_assign do local _obj_0 = require("moonscript.parse.util") Indent, Cut, ensure, extract_line, mark, pos, flatten_or_mark, is_assignable, check_assignable, format_assign, format_single_assign, sym, symx, simple_string, wrap_func_arg, flatten_func, flatten_string_chain, wrap_decorator, check_lua_string, self_assign = _obj_0.Indent, _obj_0.Cut, _obj_0.ensure, _obj_0.extract_line, _obj_0.mark, _obj_0.pos, _obj_0.flatten_or_mark, _obj_0.is_assignable, _obj_0.check_assignable, _obj_0.format_assign, _obj_0.format_single_assign, _obj_0.sym, _obj_0.symx, _obj_0.simple_string, _obj_0.wrap_func_arg, _obj_0.flatten_func, _obj_0.flatten_string_chain, _obj_0.wrap_decorator, _obj_0.check_lua_string, _obj_0.self_assign end local build_grammar = wrap_env(debug_grammar, function() local _indent = Stack(0) local _do_stack = Stack(0) local last_pos = 0 local check_indent check_indent = function(str, pos, indent) last_pos = pos return _indent:top() == indent end local advance_indent advance_indent = function(str, pos, indent) local top = _indent:top() if top ~= -1 and indent > top then _indent:push(indent) return true end end local push_indent push_indent = function(str, pos, indent) _indent:push(indent) return true end local pop_indent pop_indent = function() assert(_indent:pop(), "unexpected outdent") return true end local check_do check_do = function(str, pos, do_node) local top = _do_stack:top() if top == nil or top then return true, do_node end return false end local disable_do disable_do = function() _do_stack:push(false) return true end local pop_do pop_do = function() assert(_do_stack:pop() ~= nil, "unexpected do pop") return true end local DisableDo = Cmt("", disable_do) local PopDo = Cmt("", pop_do) local keywords = { } local key key = function(chars) keywords[chars] = true return Space * chars * -AlphaNum end local op op = function(chars) local patt = Space * C(chars) if chars:match("^%w*$") then keywords[chars] = true patt = patt * -AlphaNum end return patt end local Name = Cmt(SpaceName, 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 = P({ File, File = Shebang ^ -1 * (Block + Ct("")), Block = Ct(Line * (Break ^ 1 * Line) ^ 0), CheckIndent = Cmt(Indent, check_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 * ((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), Advance = #Cmt(Indent, advance_indent), 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"), CharOperators = Space * C(S("+-*/%^><")), WordOperators = op("or") + op("and") + op("<=") + op(">=") + op("~=") + op("!=") + op("==") + op(".."), BinaryOperator = (WordOperators + CharOperators) * SpaceBreak ^ 0, Assignable = Cmt(DotChain + Chain, check_assignable) + Name + SelfName, Exp = Ct(Value * (BinaryOperator * 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 = 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("(") * SpaceBreak ^ 0 * Exp * SpaceBreak ^ 0 * sym(")"), FnArgs = symx("(") * SpaceBreak ^ 0 * Ct(ExpList ^ -1) * SpaceBreak ^ 0 * sym(")") + sym("!") * -P("=") * Ct(""), ChainTail = ChainItem ^ 1 * ColonSuffix ^ -1 + ColonSuffix, Chain = Callable * ChainTail / mark("chain"), 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, 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 * lpeg.Cp()) / self_assign + Ct((KeyName + sym("[") * Exp * sym("]") + DoubleString + SingleString) * symx(":") * (Exp + TableBlock + SpaceBreak ^ 1 * Exp)), 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 }) local file_grammar = White * g * White * -1 return { match = function(self, str) local tree local _, err = xpcall((function() tree = file_grammar:match(str) end), function(err) return debug.traceback(err, 2) end) if type(err) == "string" then return nil, err end if not (tree) then local msg local err_pos = last_pos if err then local node node, msg = unpack(err) if msg then msg = " " .. msg end err_pos = node[-1] end local line_no = pos_to_line(str, err_pos) local line_str = get_line(str, 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, string = function(str) return build_grammar():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 NameProxy = require("moonscript.transform.names").NameProxy local insert insert = table.insert local unpack unpack = require("moonscript.util").unpack local user_error user_error = require("moonscript.errors").user_error 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) or #extracted_names == 1 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]) local chain if obj then chain = NameProxy.chain(obj, unpack(tuple[2])) else chain = "nil" end insert(values, chain) 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 build = require("moonscript.types").build local unpack unpack = require("moonscript.util").unpack 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 insert = table.insert 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 Set = require("moonscript.data").Set local insert insert = table.insert 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 concat = table.concat local unpack = unpack or table.unpack local type = type local moon = { is_object = function(value) return type(value) == "table" and value.__class end, is_a = function(thing, t) if not (type(thing) == "table") then return false end local cls = thing.__class while cls do if cls == t then return true end cls = cls.__parent end return false end, type = function(value) local base_type = type(value) if base_type == "table" then local cls = value.__class if cls then return cls end end return base_type end } local pos_to_line pos_to_line = function(str, pos) local line = 1 for _ in str:sub(1, pos):gmatch("\n") do line = line + 1 end return line end local trim trim = function(str) return str:match("^%s*(.-)%s*$") end local get_line get_line = function(str, line_num) for line in str:gmatch("([^\n]*)\n?") do if line_num == 1 then return line end line_num = line_num - 1 end end local get_closest_line get_closest_line = function(str, line_num) local line = get_line(str, line_num) if (not line or trim(line) == "") and line_num > 1 then return get_closest_line(str, line_num - 1) else return line, line_num end end local reversed reversed = function(seq) return coroutine.wrap(function() for i = #seq, 1, -1 do coroutine.yield(i, seq[i]) end end) end local split split = function(str, delim) if str == "" then return { } end str = str .. delim 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 local safe_module safe_module = function(name, tbl) return setmetatable(tbl, { __index = function(self, key) return error("Attempted to import non-existent `" .. tostring(key) .. "` from " .. tostring(name)) 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, safe_module = safe_module } end package.preload['moonscript.version'] = function() local version = "0.3.0" return { version = version, print_version = function() return print("MoonScript version " .. tostring(version)) end } end return package.preload["moonscript"]()