diff --git a/Makefile b/Makefile index d90631d..30b3022 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ test:: - moonc test2.moon && TIME=1 busted test2.lua + busted -p "_spec.moon$$" local: luarocks make --local moonscript-dev-1.rockspec @@ -16,4 +16,4 @@ compile_global: moonc moon/ moonscript/ watch: - moonc -w moon/ moonscript/ + moonc moon/ moonscript/ && moonc -w moon/ moonscript/ diff --git a/README.md b/README.md index 52fa23f..abfd3d3 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,20 @@ See . Online demo/compiler at . +## Running Tests + +Tests are written in MoonScript and use [Busted](http://olivinelabs.com/busted/). +In order to run the tests you must have MoonScript installed. + +To run tests, execute from the root directory: + +```bash +busted +``` + ## License (MIT) -Copyright (C) 2012 by Leaf Corcoran +Copyright (C) 2013 by Leaf Corcoran Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/bin/moon b/bin/moon index 5ce9d41..b6ef27f 100755 --- a/bin/moon +++ b/bin/moon @@ -1,7 +1,7 @@ #!/usr/bin/env lua require "alt_getopt" -local moonscript = require "moonscript" +local moonscript = require "moonscript.base" local util = require "moonscript.util" local errors = require "moonscript.errors" @@ -15,6 +15,7 @@ local help = [=[Usage: %s [options] [script [args]] -h Print this message -d Disable stack trace rewriting + -c Collect and print code coverage -v Print version ]=] @@ -70,10 +71,23 @@ end util.getfenv(moonscript_chunk).arg = new_arg +local function run_chunk() + moonscript.insert_loader() + moonscript_chunk(unpack(new_arg)) + moonscript.remove_loader() +end + if not opts.d then local err, trace + local cov - xpcall(function() moonscript_chunk(unpack(new_arg)) end, function(_err) + if opts.c then + local coverage = require "moonscript.cmd.coverage" + cov = coverage.CodeCoverage() + cov:start() + end + + xpcall(run_chunk, function(_err) err = _err trace = debug.traceback("", 2) end) @@ -91,7 +105,12 @@ if not opts.d then util.trim(trace) }, "\n")) end + else + if cov then + cov:stop() + cov:print_results() + end end else - moonscript_chunk(unpack(new_arg)) + run_chunk() end diff --git a/bin/moonc b/bin/moonc index d7a9220..dec5ad7 100755 --- a/bin/moonc +++ b/bin/moonc @@ -9,8 +9,8 @@ local dump_tree = require"moonscript.dump".tree local alt_getopt = require "alt_getopt" local lfs = require "lfs" -local opts, ind = alt_getopt.get_opts(arg, "vhwt:pTXb", { - print = "p", tree = "T", version = "v", help = "h" +local opts, ind = alt_getopt.get_opts(arg, "lvhwt:pTXb", { + print = "p", tree = "T", version = "v", help = "h", lint = "l" }) local read_stdin = arg[1] == "--" @@ -25,6 +25,7 @@ local help = [[Usage: %s [options] files... -p Write output to standard out -T Write parse tree instead of code (to stdout) -X Write line rewrite map instead of code (to stdout) + -l Perform lint on the file instead of compiling -b Dump parse and compile time (doesn't write output) -v Print version @@ -39,9 +40,16 @@ if opts.v then end function print_help(err) - if err then print("Error: "..err) end - print(help:format(arg[0])) - os.exit() + local help_msg = help:format(arg[0]) + + if err then + io.stderr:write("Error: ".. err .. "\n") + io.stderr:write(help_msg .. "\n") + os.exit(1) + else + print(help_msg) + os.exit(0) + end end function mkdir(path) @@ -69,9 +77,9 @@ function convert_path(path) return (path:gsub("%.moon$", ".lua")) end -function msg(...) +function log_msg(...) if not opts.p then - print(...) + io.stderr:write(table.concat({...}, " ") .. "\n") end end @@ -301,12 +309,12 @@ function create_watcher(files) dirs = remove_dups(dirs) return coroutine.wrap(function() - print(("%s with inotify [%s]"):format(msg, plural(#dirs, "dir"))) + io.stderr:write(("%s with inotify [%s]"):format(msg, plural(#dirs, "dir")) .. "\n") local wd_table = {} local handle = inotify.init() for _, dir in ipairs(dirs) do - local wd = handle:addwatch(dir, inotify.IN_CLOSE_WRITE) + local wd = handle:addwatch(dir, inotify.IN_CLOSE_WRITE, inotify.IN_MOVED_TO) wd_table[wd] = dir end @@ -328,7 +336,7 @@ function create_watcher(files) -- poll the filesystem instead local sleep = get_sleep_func() return coroutine.wrap(function() - print(("%s with polling [%s]"):format(msg, plural(#files, "file"))) + io.stderr:write(("%s with polling [%s]"):format(msg, plural(#files, "file")) .. "\n") local mod_time = {} while true do @@ -367,24 +375,36 @@ if opts.w then local target = target_dir..convert_path(fname) local success, err = compile_and_write(fname, target) if not success then - print() - print("Error:", fname) - print(err) - print() + io.stderr:write(table.concat({ + "", + "Error: " .. fname, + err, + "\n", + }, "\n")) else - msg("Built:", fname, "->", target) + log_msg("Built:", fname, "->", target) end end - print "\nQuitting..." + io.stderr:write("\nQuitting...\n") +elseif opts.l then + for _, fname in pairs(files) do + lint = require "moonscript.cmd.lint" + local res, err = lint.lint_file(fname) + if res then + io.stderr:write(res .. "\n\n") + elseif err then + io.stderr:write(fname .. "\n" .. err.. "\n\n") + end + end else for _, fname in ipairs(files) do local success, err = compile_and_write(fname, target_dir..convert_path(fname)) if not success then - print(fname, err) + io.stderr:write(fname .. "\t" .. err .. "\n") os.exit(1) else - msg("Built", fname) + log_msg("Built", fname) end end end diff --git a/docs/reference.md b/docs/reference.md index 2d2b158..4299267 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -1,6 +1,6 @@ target: reference/index template: reference - title: MoonScript v0.2.3 - Language Guide + title: MoonScript v0.2.4 - Language Guide short_name: lang -- MoonScript is a programming language that compiles to @@ -8,7 +8,7 @@ MoonScript is a programming language that compiles to familiarity with Lua. For each code snippet below, the MoonScript is on the left and the compiled Lua is on right right. -This is the offical language reference manual, installation directions and the +This is the official language reference manual, installation directions and the homepage are located at .
@@ -18,6 +18,21 @@ homepage are located at . # The Language +## Whitespace + +MoonScript is a whitespace sensitive language. This means that +instead of using `do` and `end` (or `{` and `}`) to delimit sections of code we +use line-breaks and indentation. + +This means that how you indent you code is important. Luckily MoonScript +doesn't care how you do it but it's important to be consistent. + +An indent must be at least 1 space or 1 tab, but you can use as many as you +like. All the code snippets on this page will use two spaces. + +> Should you happen to mix tabs and spaces, a tab is equivalent to 4 spaces. I +> shouldn't be telling you this though because you should never do it. + ## Assignment Assigning to an undeclared name will cause it to be declared as a new local @@ -115,7 +130,7 @@ argument names in parentheses: sum = (x, y) -> print "sum", x + y ``` -Functions can be called by listing the arguments after the name of an expresion +Functions can be called by listing the arguments after the name of an expression that evaluates to a function. When chaining together function calls, the arguments are applied to the closest function to the left. @@ -541,7 +556,7 @@ for item in *items do print item for j = 1,10,3 do print j ``` -A for loop can also be used an expression. The last statement in the body of +A for loop can also be used as an expression. The last statement in the body of the for loop is coerced into an expression and appended to an accumulating array table. @@ -598,7 +613,7 @@ A `continue` statement can be used to skip the current iteration in a loop. ```moon i = 0 while i < 10 - continue if i % 2 ==0 + continue if i % 2 == 0 print i ``` `continue` can also be used with loop expressions to prevent that iteration @@ -629,7 +644,7 @@ have_coins = false if have_coins then print "Got coins" else print "No coins" ``` -Because if statements can be used as expressions, this can able be written as: +Because if statements can be used as expressions, this can also be written as: ```moon have_coins = false @@ -653,6 +668,17 @@ else print message -- prints: I am very tall ``` +The opposite of `if` is `unless`: + +```moon +unless os.date("%A") == "Monday" + print "it is not Monday!" +``` + +```moon +print "You're lucky!" unless math.random! > 0.1 +``` + ### With Assignment `if` and `elseif` blocks can take an assignment in place of a conditional @@ -701,7 +727,7 @@ is done with the `==` operator. name = "Dan" switch name when "Robert" - print "You are robert" + print "You are Robert" when "Dan", "Daniel" print "Your name, it's Dan" else @@ -1413,7 +1439,7 @@ my_object = { write: => print "the value:", @value } -run_callback (func) -> +run_callback = (func) -> print "running callback..." func! @@ -1689,7 +1715,7 @@ A full list of flags can be seen by passing the `-h` or `--help` flag. # License (MIT) - Copyright (C) 2011 by Leaf Corcoran + Copyright (C) 2013 by Leaf Corcoran Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/docs/standard_lib.md b/docs/standard_lib.md index 2138f5a..95c2a55 100644 --- a/docs/standard_lib.md +++ b/docs/standard_lib.md @@ -1,6 +1,6 @@ target: reference/standard_lib template: reference - title: MoonScript v0.2.3 - Standard Library + title: MoonScript v0.2.4 - Standard Library short_name: stdlib -- @@ -81,7 +81,7 @@ values when a missing key is looked up. ### `extend(arg1, arg2, [rest...])` Chains together a series of tables by their metatable's `__index` property. -Overwrites the metatable of all objects exept for the last with a new table +Overwrites the metatable of all objects except for the last with a new table whose `__index` is set to the next table. Returns the first argument. @@ -166,7 +166,7 @@ overwritten. ### `mixin_object(obj, other_obj, method_names)` -Inserts into `obj` methods from `other_obj` whose names are listen in +Inserts into `obj` methods from `other_obj` whose names are listed in `method_names`. The inserted methods are bound methods that will run with `other_obj` as the receiver. diff --git a/moon.lua b/moon.lua new file mode 100644 index 0000000..6b1536f --- /dev/null +++ b/moon.lua @@ -0,0 +1 @@ +return require "moon.init" diff --git a/moon/all.lua b/moon/all.lua index fd23b7e..945576d 100644 --- a/moon/all.lua +++ b/moon/all.lua @@ -1,3 +1,5 @@ -moon = moon or { } -moon.inject = true -return require("moon.init") +local moon = require("moon") +for k, v in pairs(moon) do + _G[k] = v +end +return moon diff --git a/moon/all.moon b/moon/all.moon index 86b3354..cb773c7 100644 --- a/moon/all.moon +++ b/moon/all.moon @@ -1,8 +1,6 @@ - --- insert all moon library functions into requiring scope - -export moon -moon = moon or {} -moon.inject = true -require "moon.init" +-- install moon into global scope +moon = require "moon" +for k,v in pairs moon + _G[k] = v +moon diff --git a/moon/init.lua b/moon/init.lua index 5cf4be8..0ca497c 100644 --- a/moon/init.lua +++ b/moon/init.lua @@ -1,11 +1,9 @@ -if not moon or not moon.inject then - module("moon", package.seeall) -end local util = require("moonscript.util") local lua = { debug = debug, type = type } +local dump, p, is_object, type, debug, run_with_scope, bind_methods, defaultbl, extend, copy, mixin, mixin_object, mixin_table, fold dump = util.dump p = function(...) return print(dump(...)) @@ -110,17 +108,14 @@ extend = function(...) return tbls[1] end copy = function(self) - return (function() - local _tbl_0 = { } - for key, val in pairs(self) do - _tbl_0[key] = val - end - return _tbl_0 - end)() + local _tbl_0 = { } + for key, val in pairs(self) do + _tbl_0[key] = val + end + return _tbl_0 end mixin = function(self, cls, ...) - local meta = getmetatable(cls) - for key, val in pairs(meta.__index) do + for key, val in pairs(cls.__base) do if not key:match("^__") then self[key] = val end @@ -128,9 +123,8 @@ mixin = function(self, cls, ...) return cls.__init(self, ...) end mixin_object = function(self, object, methods) - local _list_0 = methods - for _index_0 = 1, #_list_0 do - local name = _list_0[_index_0] + for _index_0 = 1, #methods do + local name = methods[_index_0] self[name] = function(parent, ...) return object[name](object, ...) end @@ -138,9 +132,8 @@ mixin_object = function(self, object, methods) end mixin_table = function(self, tbl, keys) if keys then - local _list_0 = keys - for _index_0 = 1, #_list_0 do - local key = _list_0[_index_0] + for _index_0 = 1, #keys do + local key = keys[_index_0] self[key] = tbl[key] end else @@ -161,4 +154,19 @@ fold = function(items, fn) return items[1] end end -return nil +return { + dump = dump, + p = p, + is_object = is_object, + type = type, + debug = debug, + run_with_scope = run_with_scope, + bind_methods = bind_methods, + defaultbl = defaultbl, + extend = extend, + copy = copy, + mixin = mixin, + mixin_object = mixin_object, + mixin_table = mixin_table, + fold = fold +} diff --git a/moon/init.moon b/moon/init.moon index 22cce0c..ef07bba 100644 --- a/moon/init.moon +++ b/moon/init.moon @@ -1,12 +1,8 @@ -if not moon or not moon.inject - module "moon", package.seeall - util = require "moonscript.util" - lua = { :debug, :type } -export * +local * dump = util.dump @@ -104,8 +100,7 @@ copy = => -- mixin class properties into self, call new mixin = (cls, ...) => - meta = getmetatable cls - for key, val in pairs meta.__index + for key, val in pairs cls.__base self[key] = val if not key\match"^__" cls.__init self, ... @@ -134,4 +129,7 @@ fold = (items, fn)-> else items[1] -nil +{ + :dump, :p, :is_object, :type, :debug, :run_with_scope, :bind_methods, + :defaultbl, :extend, :copy, :mixin, :mixin_object, :mixin_table, :fold +} diff --git a/moonscript-dev-1.rockspec b/moonscript-dev-1.rockspec index 457c016..7fd5ef1 100644 --- a/moonscript-dev-1.rockspec +++ b/moonscript-dev-1.rockspec @@ -14,7 +14,7 @@ description = { dependencies = { "lua >= 5.1", - "lpeg >= 0.10", + "lpeg >= 0.10, ~= 0.11", "alt-getopt >= 0.7", "luafilesystem >= 1.5" } @@ -26,6 +26,8 @@ build = { ["moon.all"] = "moon/all.lua", ["moonscript"] = "moonscript/init.lua", ["moonscript.base"] = "moonscript/base.lua", + ["moonscript.cmd.coverage"] = "moonscript/cmd/coverage.lua", + ["moonscript.cmd.lint"] = "moonscript/cmd/lint.lua", ["moonscript.compile"] = "moonscript/compile.lua", ["moonscript.compile.statement"] = "moonscript/compile/statement.lua", ["moonscript.compile.value"] = "moonscript/compile/value.lua", diff --git a/moonscript/base.lua b/moonscript/base.lua index 2636187..f3b6b39 100644 --- a/moonscript/base.lua +++ b/moonscript/base.lua @@ -1,2 +1,137 @@ -_G.moon_no_loader = true -return require("moonscript") +local compile = require("moonscript.compile") +local parse = require("moonscript.parse") +local concat, insert, remove +do + local _obj_0 = table + concat, insert, remove = _obj_0.concat, _obj_0.insert, _obj_0.remove +end +local split, dump, get_options, unpack +do + local _obj_0 = require("moonscript.util") + split, dump, get_options, unpack = _obj_0.split, _obj_0.dump, _obj_0.get_options, _obj_0.unpack +end +local lua = { + loadstring = loadstring, + load = load +} +local dirsep, line_tables, create_moonpath, to_lua, moon_loader, loadstring, loadfile, dofile, insert_loader, remove_loader +dirsep = "/" +line_tables = require("moonscript.line_tables") +create_moonpath = function(package_path) + local paths = split(package_path, ";") + for i, path in ipairs(paths) do + local p = path:match("^(.-)%.lua$") + if p then + paths[i] = p .. ".moon" + end + end + return concat(paths, ";") +end +to_lua = function(text, options) + if options == nil then + options = { } + end + if "string" ~= type(text) then + local t = type(text) + return nil, "expecting string (got " .. t .. ")", 2 + end + local tree, err = parse.string(text) + if not tree then + return nil, err + end + local code, ltable, pos = compile.tree(tree, options) + if not code then + return nil, compile.format_error(ltable, pos, text), 2 + end + return code, ltable +end +moon_loader = function(name) + local name_path = name:gsub("%.", dirsep) + local file, file_path + local _list_0 = split(package.moonpath, ";") + for _index_0 = 1, #_list_0 do + local path = _list_0[_index_0] + file_path = path:gsub("?", name_path) + file = io.open(file_path) + if file then + break + end + end + if file then + local text = file:read("*a") + file:close() + local res, err = loadstring(text, file_path) + if not res then + error(err) + end + return res + end + return nil, "Could not find moon file" +end +loadstring = function(...) + local options, str, chunk_name, mode, env = get_options(...) + chunk_name = chunk_name or "=(moonscript.loadstring)" + local code, ltable_or_err = to_lua(str, options) + if not (code) then + return nil, ltable_or_err + end + if chunk_name then + line_tables[chunk_name] = ltable_or_err + end + return (lua.loadstring or lua.load)(code, chunk_name, unpack({ + mode, + env + })) +end +loadfile = function(fname, ...) + local file, err = io.open(fname) + if not (file) then + return nil, err + end + local text = assert(file:read("*a")) + file:close() + return loadstring(text, fname, ...) +end +dofile = function(...) + local f = assert(loadfile(...)) + return f() +end +insert_loader = function(pos) + if pos == nil then + pos = 2 + end + if not package.moonpath then + package.moonpath = create_moonpath(package.path) + end + local loaders = package.loaders or package.searchers + for _index_0 = 1, #loaders do + local loader = loaders[_index_0] + if loader == moon_loader then + return false + end + end + insert(loaders, pos, moon_loader) + return true +end +remove_loader = function() + local loaders = package.loaders or package.searchers + for i, loader in ipairs(loaders) do + if loader == moon_loader then + remove(loaders, i) + return true + end + end + return false +end +return { + _NAME = "moonscript", + insert_loader = insert_loader, + remove_loader = remove_loader, + to_lua = to_lua, + moon_chunk = moon_chunk, + moon_loader = moon_loader, + dirsep = dirsep, + dofile = dofile, + loadfile = loadfile, + loadstring = loadstring +} diff --git a/moonscript/base.moon b/moonscript/base.moon index b5fae84..fe8e3de 100644 --- a/moonscript/base.moon +++ b/moonscript/base.moon @@ -1,2 +1,108 @@ -_G.moon_no_loader = true -require "moonscript" +compile = require "moonscript.compile" +parse = require "moonscript.parse" + +import concat, insert, remove from table +import split, dump, get_options, unpack from require "moonscript.util" + +lua = :loadstring, :load + +local * + +dirsep = "/" +line_tables = require "moonscript.line_tables" + +-- create moon path package from lua package path +create_moonpath = (package_path) -> + paths = split package_path, ";" + for i, path in ipairs paths + p = path\match "^(.-)%.lua$" + if p then paths[i] = p..".moon" + concat paths, ";" + +to_lua = (text, options={}) -> + if "string" != type text + t = type text + return nil, "expecting string (got ".. t ..")", 2 + + tree, err = parse.string text + if not tree + return nil, err + + code, ltable, pos = compile.tree tree, options + if not code + return nil, compile.format_error(ltable, pos, text), 2 + + code, ltable + +moon_loader = (name) -> + name_path = name\gsub "%.", dirsep + + local file, file_path + for path in *split package.moonpath, ";" + file_path = path\gsub "?", name_path + file = io.open file_path + break if file + + if file + text = file\read "*a" + file\close! + res, err = loadstring text, file_path + if not res + error err + + return res + + return nil, "Could not find moon file" + + +loadstring = (...) -> + options, str, chunk_name, mode, env = get_options ... + chunk_name or= "=(moonscript.loadstring)" + + code, ltable_or_err = to_lua str, options + unless code + return nil, ltable_or_err + + line_tables[chunk_name] = ltable_or_err if chunk_name + -- the unpack prevents us from passing nil + (lua.loadstring or lua.load) code, chunk_name, unpack { mode, env } + +loadfile = (fname, ...) -> + file, err = io.open fname + return nil, err unless file + text = assert file\read "*a" + file\close! + loadstring text, fname, ... + +-- throws errros +dofile = (...) -> + f = assert loadfile ... + f! + +insert_loader = (pos=2) -> + if not package.moonpath + package.moonpath = create_moonpath package.path + + loaders = package.loaders or package.searchers + for loader in *loaders + return false if loader == moon_loader + + insert loaders, pos, moon_loader + true + +remove_loader = -> + loaders = package.loaders or package.searchers + + for i, loader in ipairs loaders + if loader == moon_loader + remove loaders, i + return true + + false + +{ + _NAME: "moonscript" + :insert_loader, :remove_loader, :to_lua, :moon_chunk, :moon_loader, :dirsep, + :dofile, :loadfile, :loadstring +} + diff --git a/moonscript/cmd/coverage.lua b/moonscript/cmd/coverage.lua new file mode 100644 index 0000000..8c585e8 --- /dev/null +++ b/moonscript/cmd/coverage.lua @@ -0,0 +1,142 @@ +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 +} diff --git a/moonscript/cmd/coverage.moon b/moonscript/cmd/coverage.moon new file mode 100644 index 0000000..dd1d1fa --- /dev/null +++ b/moonscript/cmd/coverage.moon @@ -0,0 +1,79 @@ + +log = (str="") -> + io.stderr\write str .. "\n" + +create_counter = -> + setmetatable {}, __index: (name) => + with tbl = setmetatable {}, __index: => 0 + @[name] = tbl + +position_to_lines = (file_content, positions) -> + lines = {} + current_pos = 0 + line_no = 1 + for char in file_content\gmatch "." + if count = rawget positions, current_pos + lines[line_no] = count + + if char == "\n" + line_no += 1 + + current_pos += 1 + + lines + +format_file = (fname, positions) -> + file = assert io.open fname + content = file\read "*a" + file\close! + + lines = position_to_lines content, positions + log "------| @#{fname}" + line_no = 1 + for line in (content .. "\n")\gmatch "(.-)\n" + foramtted_no = "% 5d"\format(line_no) + sym = lines[line_no] and "*" or " " + log "#{sym}#{foramtted_no}| #{line}" + line_no += 1 + + log! + + +class CodeCoverage + new: => + @reset! + + reset: => + @line_counts = create_counter! + + start: => + debug.sethook @\process_line, "l" + + stop: => + debug.sethook! + + print_results: => + @format_results! + + process_line: (_, line_no) => + debug_data = debug.getinfo 2, "S" + source = debug_data.source + @line_counts[source][line_no] += 1 + + format_results: => + line_table = require "moonscript.line_tables" + positions = create_counter! + + for file, lines in pairs @line_counts + file_table = line_table[file] + continue unless file_table + + for line, count in pairs lines + position = file_table[line] + continue unless position + positions[file][position] += count + + for file, ps in pairs positions + format_file file, ps + +{ :CodeCoverage } diff --git a/moonscript/cmd/lint.lua b/moonscript/cmd/lint.lua new file mode 100644 index 0000000..a8c0890 --- /dev/null +++ b/moonscript/cmd/lint.lua @@ -0,0 +1,214 @@ +local insert +do + local _obj_0 = table + insert = _obj_0.insert +end +local Set +do + local _obj_0 = require("moonscript.data") + Set = _obj_0.Set +end +local Block +do + local _obj_0 = require("moonscript.compile") + Block = _obj_0.Block +end +local default_whitelist = Set({ + '_G', + '_VERSION', + 'assert', + 'bit32', + 'collectgarbage', + 'coroutine', + 'debug', + 'dofile', + 'error', + 'getfenv', + 'getmetatable', + 'io', + 'ipairs', + 'load', + 'loadfile', + 'loadstring', + 'math', + 'module', + 'next', + 'os', + 'package', + 'pairs', + 'pcall', + 'print', + 'rawequal', + 'rawget', + 'rawlen', + 'rawset', + 'require', + 'select', + 'setfenv', + 'setmetatable', + 'string', + 'table', + 'tonumber', + 'tostring', + 'type', + 'unpack', + 'xpcall', + "nil", + "true", + "false" +}) +local LinterBlock +do + local _parent_0 = Block + local _base_0 = { + block = function(self, ...) + do + local _with_0 = _parent_0.block(self, ...) + _with_0.block = self.block + _with_0.value_compilers = self.value_compilers + return _with_0 + end + end + } + _base_0.__index = _base_0 + setmetatable(_base_0, _parent_0.__base) + local _class_0 = setmetatable({ + __init = function(self, whitelist_globals, ...) + if whitelist_globals == nil then + whitelist_globals = default_whitelist + end + _parent_0.__init(self, ...) + self.lint_errors = { } + local vc = self.value_compilers + self.value_compilers = setmetatable({ + ref = function(block, val) + local name = val[2] + if not (block:has_name(name) or whitelist_globals[name] or name:match("%.")) then + insert(self.lint_errors, { + "accessing global " .. tostring(name), + val[-1] + }) + end + return vc.ref(block, val) + end + }, { + __index = vc + }) + end, + __base = _base_0, + __name = "LinterBlock", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + LinterBlock = _class_0 +end +local format_lint +format_lint = function(errors, code, header) + if not (next(errors)) then + return + end + local pos_to_line, get_line + do + local _obj_0 = require("moonscript.util") + pos_to_line, get_line = _obj_0.pos_to_line, _obj_0.get_line + end + local formatted + do + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #errors do + local _des_0 = errors[_index_0] + local msg, pos + msg, pos = _des_0[1], _des_0[2] + if pos then + local line = pos_to_line(code, pos) + msg = "line " .. tostring(line) .. ": " .. tostring(msg) + local line_text = "> " .. get_line(code, line) + local sep_len = math.max(#msg, #line_text) + _accum_0[_len_0] = table.concat({ + msg, + ("="):rep(sep_len), + line_text + }, "\n") + else + _accum_0[_len_0] = msg + end + _len_0 = _len_0 + 1 + end + formatted = _accum_0 + end + if header then + table.insert(formatted, 1, header) + end + return table.concat(formatted, "\n\n") +end +local whitelist_for_file +do + local lint_config + whitelist_for_file = function(fname) + if not (lint_config) then + lint_config = { } + pcall(function() + lint_config = require("lint_config") + end) + end + if not (lint_config.whitelist_globals) then + return default_whitelist + end + local final_list = { } + for pattern, list in pairs(lint_config.whitelist_globals) do + if fname:match(pattern) then + for _index_0 = 1, #list do + local item = list[_index_0] + insert(final_list, item) + end + end + end + return setmetatable(Set(final_list), { + __index = default_whitelist + }) + end +end +local lint_code +lint_code = function(code, name, whitelist_globals) + if name == nil then + name = "string input" + end + local parse = require("moonscript.parse") + local tree, err = parse.string(code) + if not (tree) then + return nil, err + end + local scope = LinterBlock(whitelist_globals) + scope:stms(tree) + return format_lint(scope.lint_errors, code, name) +end +local lint_file +lint_file = function(fname) + local f, err = io.open(fname) + if not (f) then + return nil, err + end + return lint_code(f:read("*a"), fname, whitelist_for_file(fname)) +end +return { + lint_code = lint_code, + lint_file = lint_file +} diff --git a/moonscript/cmd/lint.moon b/moonscript/cmd/lint.moon new file mode 100644 index 0000000..4add665 --- /dev/null +++ b/moonscript/cmd/lint.moon @@ -0,0 +1,138 @@ + +import insert from table +import Set from require "moonscript.data" +import Block from require "moonscript.compile" + +-- globals allowed to be referenced +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" +} + +class LinterBlock extends Block + new: (whitelist_globals=default_whitelist, ...) => + super ... + @lint_errors = {} + + vc = @value_compilers + @value_compilers = setmetatable { + ref: (block, val) -> + name = val[2] + unless block\has_name(name) or whitelist_globals[name] or name\match "%." + insert @lint_errors, { + "accessing global #{name}" + val[-1] + } + + vc.ref block, val + }, __index: vc + + block: (...) => + with super ... + .block = @block + .value_compilers = @value_compilers + +format_lint = (errors, code, header) -> + return unless next errors + + import pos_to_line, get_line from require "moonscript.util" + formatted = for {msg, pos} in *errors + if pos + line = pos_to_line code, pos + msg = "line #{line}: #{msg}" + line_text = "> " .. get_line code, line + + sep_len = math.max #msg, #line_text + table.concat { + msg + "="\rep sep_len + line_text + }, "\n" + + else + msg + + table.insert formatted, 1, header if header + table.concat formatted, "\n\n" + + +-- { +-- whitelist_globals: { +-- ["some_file_pattern"]: { +-- "some_var", "another_var" +-- } +-- } +-- } +whitelist_for_file = do + local lint_config + (fname) -> + unless lint_config + lint_config = {} + pcall -> lint_config = require "lint_config" + + return default_whitelist unless lint_config.whitelist_globals + final_list = {} + for pattern, list in pairs lint_config.whitelist_globals + if fname\match(pattern) + for item in *list + insert final_list, item + + setmetatable Set(final_list), __index: default_whitelist + +lint_code = (code, name="string input", whitelist_globals) -> + parse = require "moonscript.parse" + tree, err = parse.string code + return nil, err unless tree + + scope = LinterBlock whitelist_globals + scope\stms tree + format_lint scope.lint_errors, code, name + +lint_file = (fname) -> + f, err = io.open fname + return nil, err unless f + lint_code f\read("*a"), fname, whitelist_for_file fname + + +{ :lint_code, :lint_file } diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 6008749..368eead 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -3,36 +3,32 @@ local dump = require("moonscript.dump") local transform = require("moonscript.transform") local NameProxy, LocalName do - local _table_0 = require("moonscript.transform.names") - NameProxy, LocalName = _table_0.NameProxy, _table_0.LocalName + local _obj_0 = require("moonscript.transform.names") + NameProxy, LocalName = _obj_0.NameProxy, _obj_0.LocalName end local Set do - local _table_0 = require("moonscript.data") - Set = _table_0.Set + local _obj_0 = require("moonscript.data") + Set = _obj_0.Set end local ntype, has_value do - local _table_0 = require("moonscript.types") - ntype, has_value = _table_0.ntype, _table_0.has_value + local _obj_0 = require("moonscript.types") + ntype, has_value = _obj_0.ntype, _obj_0.has_value end -local statement_compilers +local statement_compilers = require("moonscript.compile.statement") +local value_compilers = require("moonscript.compile.value") +local concat, insert do - local _table_0 = require("moonscript.compile.statement") - statement_compilers = _table_0.statement_compilers + local _obj_0 = table + concat, insert = _obj_0.concat, _obj_0.insert end -local value_compilers -do - local _table_0 = require("moonscript.compile.value") - value_compilers = _table_0.value_compilers -end -local concat, insert = table.concat, table.insert -local pos_to_line, get_closest_line, trim, unpack = util.pos_to_line, util.get_closest_line, util.trim, util.unpack +local 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 _parent_0 = nil local _base_0 = { mark_pos = function(self, pos, line) if line == nil then @@ -115,17 +111,14 @@ do local strip strip = function(t) if "table" == type(t) then - return (function() - local _accum_0 = { } - local _len_0 = 1 - local _list_0 = t - for _index_0 = 1, #_list_0 do - local v = _list_0[_index_0] - _accum_0[_len_0] = strip(v) - _len_0 = _len_0 + 1 - end - return _accum_0 - end)() + 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 @@ -134,25 +127,14 @@ do end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ __init = function(self) self.posmap = { } end, __base = _base_0, - __name = "Lines", - __parent = _parent_0 + __name = "Lines" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -160,13 +142,9 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Lines = _class_0 end do - local _parent_0 = nil local _base_0 = { pos = nil, _append_single = function(self, item) @@ -174,9 +152,8 @@ do if not (self.pos) then self.pos = item.pos end - local _list_0 = item - for _index_0 = 1, #_list_0 do - local value = _list_0[_index_0] + for _index_0 = 1, #item do + local value = item[_index_0] self:_append_single(value) end else @@ -210,14 +187,13 @@ do buffer:add(concat(current)) return buffer:mark_pos(self.pos) end - local _list_0 = self - for _index_0 = 1, #_list_0 do - local chunk = _list_0[_index_0] + for _index_0 = 1, #self do + local chunk = self[_index_0] local _exp_0 = mtype(chunk) if Block == _exp_0 then - local _list_1 = chunk:render(Lines()) - for _index_1 = 1, #_list_1 do - local block_chunk = _list_1[_index_1] + 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 @@ -240,27 +216,12 @@ do end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "Line", - __parent = _parent_0 + __name = "Line" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -268,13 +229,9 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Line = _class_0 end do - local _parent_0 = nil local _base_0 = { prepare = function() end, render = function(self) @@ -283,25 +240,14 @@ do end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ __init = function(self, fn) self.prepare = fn end, __base = _base_0, - __name = "DelayedLine", - __parent = _parent_0 + __name = "DelayedLine" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -309,18 +255,15 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end DelayedLine = _class_0 end do - local _parent_0 = nil local _base_0 = { header = "do", footer = "end", export_all = false, export_proper = false, + value_compilers = value_compilers, __tostring = function(self) local h if "string" == type(self.header) then @@ -354,14 +297,14 @@ do end end, declare = function(self, names) - local undeclared = (function() + local undeclared + do local _accum_0 = { } local _len_0 = 1 - local _list_0 = names - for _index_0 = 1, #_list_0 do + for _index_0 = 1, #names do local _continue_0 = false repeat - local name = _list_0[_index_0] + local name = names[_index_0] local is_local = false local real_name local _exp_0 = mtype(name) @@ -370,6 +313,8 @@ do real_name = name:get_name(self) elseif NameProxy == _exp_0 then real_name = name:get_name(self) + elseif "table" == _exp_0 then + real_name = name[1] == "ref" and name[2] elseif "string" == _exp_0 then real_name = name end @@ -391,8 +336,8 @@ do break end end - return _accum_0 - end)() + undeclared = _accum_0 + end return undeclared end, whitelist_names = function(self, names) @@ -429,6 +374,21 @@ do 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 @@ -496,10 +456,14 @@ do end, is_value = function(self, node) local t = ntype(node) - return value_compilers[t] ~= nil or t == "value" + return self.value_compilers[t] ~= nil or t == "value" end, name = function(self, node, ...) - return self:value(node, ...) + if type(node) == "string" then + return node + else + return self:value(node, ...) + end end, value = function(self, node, ...) node = self.transform.value(node) @@ -509,7 +473,7 @@ do else action = node[1] end - local fn = value_compilers[action] + local fn = self.value_compilers[action] if not fn then error("Failed to compile value: " .. dump.value(node)) end @@ -533,9 +497,8 @@ do _with_0:append_list((function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = values - for _index_0 = 1, #_list_0 do - local v = _list_0[_index_0] + for _index_0 = 1, #values do + local v = values[_index_0] _accum_0[_len_0] = self:value(v) _len_0 = _len_0 + 1 end @@ -583,10 +546,7 @@ do error("deprecated stms call, use transformer") end local current_stms, current_stm_i - do - local _obj_0 = self - current_stms, current_stm_i = _obj_0.current_stms, _obj_0.current_stm_i - end + 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 @@ -606,9 +566,6 @@ do end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ __init = function(self, parent, header, footer) self.parent, self.header, self.footer = parent, header, footer @@ -617,10 +574,9 @@ do self._state = { } self._listeners = { } do - local _with_0 = transform self.transform = { - value = _with_0.Value:bind(self), - statement = _with_0.Statement:bind(self) + value = transform.Value:bind(self), + statement = transform.Statement:bind(self) } end if self.parent then @@ -637,17 +593,9 @@ do end end, __base = _base_0, - __name = "Block", - __parent = _parent_0 + __name = "Block" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -655,9 +603,6 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Block = _class_0 end do @@ -681,9 +626,7 @@ do end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end + setmetatable(_base_0, _parent_0.__base) local _class_0 = setmetatable({ __init = function(self, options) self.options = options @@ -696,7 +639,7 @@ do }, { __index = function(cls, name) local val = rawget(_base_0, name) - if val == nil and _parent_0 then + if val == nil then return _parent_0[name] else return val @@ -709,7 +652,7 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then + if _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end RootBlock = _class_0 @@ -769,8 +712,7 @@ tree = function(tree, options) end end do - local _with_0 = require("moonscript.data") - local data = _with_0 + local data = require("moonscript.data") for name, cls in pairs({ Line = Line, Lines = Lines, diff --git a/moonscript/compile.moon b/moonscript/compile.moon index c335b9e..27ab017 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -7,8 +7,8 @@ import NameProxy, LocalName from require "moonscript.transform.names" import Set from require "moonscript.data" import ntype, has_value from require "moonscript.types" -import statement_compilers from require "moonscript.compile.statement" -import value_compilers from require "moonscript.compile.value" +statement_compilers = require "moonscript.compile.statement" +value_compilers = require "moonscript.compile.value" import concat, insert from table import pos_to_line, get_closest_line, trim, unpack from util @@ -161,6 +161,8 @@ class Block export_all: false export_proper: false + value_compilers: value_compilers + __tostring: => h = if "string" == type @header @header @@ -217,7 +219,11 @@ class Block is_local = true name\get_name self when NameProxy then name\get_name self - when "string" then name + when "table" + name[1] == "ref" and name[2] + when "string" + -- TODO: don't use string literal as ref + name continue unless is_local or real_name and not @has_name real_name, true -- put exported names so they can be assigned to in deeper scope @@ -241,6 +247,8 @@ class Block name = name\get_name self if NameProxy == mtype name @_names[name] = value + -- Check if a name is defined in the current or any enclosing scope + -- skip_exports: ignore names that have been exported using `export` has_name: (name, skip_exports) => return true if not skip_exports and @name_exported name @@ -251,6 +259,18 @@ class Block else yes + is_local: (node) => + t = mtype node + + return @has_name(node, false) if t == "string" + return true if t == NameProxy or t == LocalName + + if t == "table" + if node[1] == "ref" or (node[1] == "chain" and #node == 2) + return @is_local node[2] + + false + free_name: (prefix, dont_put) => prefix = prefix or "moon" searching = true @@ -304,10 +324,14 @@ class Block is_value: (node) => t = ntype node - value_compilers[t] != nil or t == "value" + @value_compilers[t] != nil or t == "value" - -- line wise compile functions - name: (node, ...) => @value node, ... + -- compile name for assign + name: (node, ...) => + if type(node) == "string" + node + else + @value node, ... value: (node, ...) => node = @transform.value node @@ -316,7 +340,7 @@ class Block else node[1] - fn = value_compilers[action] + fn = @value_compilers[action] error "Failed to compile value: "..dump.value node if not fn out = fn self, node, ... diff --git a/moonscript/compile/statement.lua b/moonscript/compile/statement.lua index afdcf88..abccd62 100644 --- a/moonscript/compile/statement.lua +++ b/moonscript/compile/statement.lua @@ -1,13 +1,18 @@ local util = require("moonscript.util") local data = require("moonscript.data") -local reversed, unpack = util.reversed, util.unpack +local reversed, unpack +reversed, unpack = util.reversed, util.unpack local ntype do - local _table_0 = require("moonscript.types") - ntype = _table_0.ntype + local _obj_0 = require("moonscript.types") + ntype = _obj_0.ntype end -local concat, insert = table.concat, table.insert -local statement_compilers = { +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, @@ -27,9 +32,8 @@ local statement_compilers = { _with_0:append_list((function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = undeclared - for _index_0 = 1, #_list_0 do - local name = _list_0[_index_0] + for _index_0 = 1, #undeclared do + local name = undeclared[_index_0] _accum_0[_len_0] = self:name(name) _len_0 = _len_0 + 1 end @@ -47,9 +51,8 @@ local statement_compilers = { _with_0:append_list((function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = names - for _index_0 = 1, #_list_0 do - local name = _list_0[_index_0] + for _index_0 = 1, #names do + local name = names[_index_0] _accum_0[_len_0] = self:name(name) _len_0 = _len_0 + 1 end @@ -81,9 +84,8 @@ local statement_compilers = { _with_0:append_list((function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = names - for _index_0 = 1, #_list_0 do - local name = _list_0[_index_0] + for _index_0 = 1, #names do + local name = names[_index_0] _accum_0[_len_0] = self:value(name) _len_0 = _len_0 + 1 end @@ -94,9 +96,8 @@ local statement_compilers = { _with_0:append_list((function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = values - for _index_0 = 1, #_list_0 do - local v = _list_0[_index_0] + for _index_0 = 1, #values do + local v = values[_index_0] _accum_0[_len_0] = self:value(v) _len_0 = _len_0 + 1 end @@ -139,9 +140,8 @@ local statement_compilers = { current.next = next current = next end - local _list_0 = node - for _index_0 = 4, #_list_0 do - cond = _list_0[_index_0] + for _index_0 = 4, #node do + cond = node[_index_0] add_clause(cond) end return root @@ -190,9 +190,8 @@ local statement_compilers = { loop:append_list((function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = names - for _index_0 = 1, #_list_0 do - local name = _list_0[_index_0] + 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 @@ -202,9 +201,8 @@ local statement_compilers = { loop:append_list((function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = exps - for _index_0 = 1, #_list_0 do - local exp = _list_0[_index_0] + for _index_0 = 1, #exps do + local exp = exps[_index_0] _accum_0[_len_0] = self:value(exp) _len_0 = _len_0 + 1 end @@ -242,8 +240,6 @@ local statement_compilers = { _with_0:stms(node[2]) return _with_0 end - end -} -return { - statement_compilers = statement_compilers + end, + noop = function(self) end } diff --git a/moonscript/compile/statement.moon b/moonscript/compile/statement.moon index e48e397..996b385 100644 --- a/moonscript/compile/statement.moon +++ b/moonscript/compile/statement.moon @@ -6,7 +6,7 @@ import reversed, unpack from util import ntype from require "moonscript.types" import concat, insert from table -statement_compilers = +{ raw: (node) => @add node[2] lines: (node) => @@ -135,5 +135,5 @@ statement_compilers = with @block! \stms node[2] - -{ :statement_compilers } + noop: => -- nothing! +} diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index 28b2cb3..560352b 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -2,22 +2,27 @@ local util = require("moonscript.util") local data = require("moonscript.data") local ntype do - local _table_0 = require("moonscript.types") - ntype = _table_0.ntype + local _obj_0 = require("moonscript.types") + ntype = _obj_0.ntype end local user_error do - local _table_0 = require("moonscript.errors") - user_error = _table_0.user_error + local _obj_0 = require("moonscript.errors") + user_error = _obj_0.user_error end -local concat, insert = table.concat, table.insert -local unpack = util.unpack +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" } -local value_compilers = { +return { exp = function(self, node) local _comp _comp = function(i, value) @@ -48,9 +53,8 @@ local value_compilers = { _with_0:append_list((function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = node - for _index_0 = 2, #_list_0 do - local v = _list_0[_index_0] + for _index_0 = 2, #node do + local v = node[_index_0] _accum_0[_len_0] = self:value(v) _len_0 = _len_0 + 1 end @@ -72,15 +76,20 @@ local value_compilers = { 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 - local sup = self:get("super") - if callee == "super" and sup then - return self:value(sup(self, node)) + 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) @@ -96,12 +105,11 @@ local value_compilers = { elseif t == "colon_stub" then return user_error("Uncalled colon stub") else - return error("Unknown chain action: " .. t) + return error("Unknown chain action: " .. tostring(t)) end end - local t = ntype(callee) - if (t == "self" or t == "self_class") and node[3] and ntype(node[3]) == "call" then - callee[1] = t .. "_colon" + 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 @@ -110,9 +118,8 @@ local value_compilers = { local actions do local _with_0 = self:line() - local _list_0 = node - for _index_0 = 3, #_list_0 do - local action = _list_0[_index_0] + for _index_0 = 3, #node do + local action = node[_index_0] _with_0:append(chain_item(action)) end actions = _with_0 @@ -123,12 +130,12 @@ local value_compilers = { local _, args, whitelist, arrow, block = unpack(node) local default_args = { } local self_args = { } - local arg_names = (function() + local arg_names + do local _accum_0 = { } local _len_0 = 1 - local _list_0 = args - for _index_0 = 1, #_list_0 do - local arg = _list_0[_index_0] + for _index_0 = 1, #args do + local arg = args[_index_0] local name, default_value = unpack(arg) if type(name) == "string" then name = name @@ -145,8 +152,8 @@ local value_compilers = { _accum_0[_len_0] = _value_0 _len_0 = _len_0 + 1 end - return _accum_0 - end)() + arg_names = _accum_0 + end if arrow == "fat" then insert(arg_names, 1, "self") end @@ -155,14 +162,12 @@ local value_compilers = { if #whitelist > 0 then _with_0:whitelist_names(whitelist) end - local _list_0 = arg_names - for _index_0 = 1, #_list_0 do - local name = _list_0[_index_0] + for _index_0 = 1, #arg_names do + local name = arg_names[_index_0] _with_0:put_name(name) end - local _list_1 = default_args - for _index_0 = 1, #_list_1 do - local default = _list_1[_index_0] + 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] @@ -171,7 +176,10 @@ local value_compilers = { 'if', { 'exp', - name, + { + "ref", + name + }, '==', 'nil' }, @@ -188,17 +196,17 @@ local value_compilers = { } }) end - local self_arg_values = (function() + local self_arg_values + do local _accum_0 = { } local _len_0 = 1 - local _list_2 = self_args - for _index_0 = 1, #_list_2 do - local arg = _list_2[_index_0] + 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 - return _accum_0 - end)() + self_arg_values = _accum_0 + end if #self_args > 0 then _with_0:stm({ "assign", @@ -208,17 +216,16 @@ local value_compilers = { end _with_0:stms(block) if #args > #arg_names then - arg_names = (function() + do local _accum_0 = { } local _len_0 = 1 - local _list_2 = args - for _index_0 = 1, #_list_2 do - local arg = _list_2[_index_0] + for _index_0 = 1, #args do + local arg = args[_index_0] _accum_0[_len_0] = arg[1] _len_0 = _len_0 + 1 end - return _accum_0 - end)() + arg_names = _accum_0 + end end _with_0.header = "function(" .. concat(arg_names, ", ") .. ")" return _with_0 @@ -282,28 +289,30 @@ local value_compilers = { return self:line("not ", self:value(node[2])) end, self = function(self, node) - return "self." .. self:value(node[2]) + return "self." .. self:name(node[2]) end, self_class = function(self, node) - return "self.__class." .. self:value(node[2]) + return "self.__class." .. self:name(node[2]) end, self_colon = function(self, node) - return "self:" .. self:value(node[2]) + return "self:" .. self:name(node[2]) end, self_class_colon = function(self, node) - return "self.__class:" .. self:value(node[2]) + 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) - local sup = self:get("super") - if value == "super" and sup then - return self:value(sup(self)) - end if value == "..." then self:send("varargs") end return tostring(value) end } -return { - value_compilers = value_compilers -} diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index 89b21e9..515fed8 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -14,7 +14,7 @@ string_chars = { "\n": "\\n" } -value_compilers = +{ -- list of values separated by binary operators exp: (node) => _comp = (i, value) -> @@ -43,14 +43,16 @@ value_compilers = chain: (node) => callee = node[2] + callee_type = ntype callee if callee == -1 callee = @get "scope_var" if not callee then user_error "Short-dot syntax must be called within a with block" - sup = @get "super" - if callee == "super" and sup - return @value sup self, node + -- TODO: don't use string literals as ref + if callee_type == "ref" and callee[2] == "super" or callee == "super" + if sup = @get "super" + return @value sup self, node chain_item = (node) -> t, arg = unpack node @@ -66,11 +68,10 @@ value_compilers = elseif t == "colon_stub" user_error "Uncalled colon stub" else - error "Unknown chain action: "..t + error "Unknown chain action: #{t}" - t = ntype(callee) - if (t == "self" or t == "self_class") and node[3] and ntype(node[3]) == "call" - callee[1] = t.."_colon" + if (callee_type == "self" or callee_type == "self_class") and node[3] and ntype(node[3]) == "call" + callee[1] = callee_type.."_colon" callee_value = @value callee callee_value = @line "(", callee_value, ")" if ntype(callee) == "exp" @@ -109,7 +110,7 @@ value_compilers = name, value = unpack default name = name[2] if type(name) == "table" \stm { - 'if', {'exp', name, '==', 'nil'}, { + 'if', {'exp', {"ref", name}, '==', 'nil'}, { {'assign', {name}, {value}} } } @@ -172,27 +173,28 @@ value_compilers = @line "not ", @value node[2] self: (node) => - "self."..@value node[2] + "self."..@name node[2] self_class: (node) => - "self.__class."..@value node[2] + "self.__class."..@name node[2] self_colon: (node) => - "self:"..@value node[2] + "self:"..@name node[2] self_class_colon: (node) => - "self.__class:"..@value node[2] + "self.__class:"..@name node[2] + + -- a variable reference + ref: (value) => + if sup = value[2] == "super" and @get "super" + return @value sup @ + + tostring value[2] -- catch all pure string values raw_value: (value) => - sup = @get"super" - if value == "super" and sup - return @value sup self - if value == "..." @send "varargs" tostring value - - -{ :value_compilers } +} diff --git a/moonscript/data.lua b/moonscript/data.lua index b968d91..2e159c8 100644 --- a/moonscript/data.lua +++ b/moonscript/data.lua @@ -1,17 +1,19 @@ -local concat, remove, insert = table.concat, table.remove, table.insert +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 self = { } - local _list_0 = items - for _index_0 = 1, #_list_0 do - local key = _list_0[_index_0] - self[key] = true + local _tbl_0 = { } + for _index_0 = 1, #items do + local k = items[_index_0] + _tbl_0[k] = true end - return self + return _tbl_0 end local Stack do - local _parent_0 = nil local _base_0 = { __tostring = function(self) return "" @@ -19,41 +21,28 @@ do pop = function(self) return remove(self) end, - push = function(self, value) + push = function(self, value, ...) insert(self, value) - return value + if ... then + return self:push(...) + else + return value + end end, top = function(self) return self[#self] end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ __init = function(self, ...) - local _list_0 = { - ... - } - for _index_0 = 1, #_list_0 do - local v = _list_0[_index_0] - self:push(v) - end + self:push(...) return nil end, __base = _base_0, - __name = "Stack", - __parent = _parent_0 + __name = "Stack" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -61,9 +50,6 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Stack = _class_0 end local lua_keywords = Set({ diff --git a/moonscript/data.moon b/moonscript/data.moon index a9fbf32..4bb9b4f 100644 --- a/moonscript/data.moon +++ b/moonscript/data.moon @@ -2,30 +2,30 @@ import concat, remove, insert from table -Set = (items) -> - self = {} - self[key] = true for key in *items - self +Set = (items) -> {k,true for k in *items} class Stack __tostring: => "" new: (...) => - @push v for v in *{...} + @push ... nil pop: => - remove self + remove @ - push: (value) => - insert self, value - value + push: (value, ...) => + insert @, value + if ... + @push ... + else + value top: => self[#self] -lua_keywords = Set{ +lua_keywords = Set { 'and', 'break', 'do', 'else', 'elseif', 'end', 'false', 'for', 'function', 'if', 'in', 'local', 'nil', 'not', 'or', diff --git a/moonscript/dump.lua b/moonscript/dump.lua index edfe400..8b69ec9 100644 --- a/moonscript/dump.lua +++ b/moonscript/dump.lua @@ -9,17 +9,17 @@ flat_value = function(op, depth) if type(op) ~= "table" then return tostring(op) end - local items = (function() + local items + do local _accum_0 = { } local _len_0 = 1 - local _list_0 = op - for _index_0 = 1, #_list_0 do - local item = _list_0[_index_0] + 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 - return _accum_0 - end)() + items = _accum_0 + end local pos = op[-1] return "{" .. (pos and "[" .. pos .. "] " or "") .. table.concat(items, ", ") .. "}" end diff --git a/moonscript/errors.lua b/moonscript/errors.lua index 58d1d9c..f8d3254 100644 --- a/moonscript/errors.lua +++ b/moonscript/errors.lua @@ -1,7 +1,12 @@ local util = require("moonscript.util") local lpeg = require("lpeg") -local concat, insert = table.concat, table.insert -local split, pos_to_line = util.split, util.pos_to_line +local 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({ @@ -42,18 +47,17 @@ truncate_traceback = function(traceback, chunk_func) end stop = stop - 1 end - traceback = (function() + do local _accum_0 = { } local _len_0 = 1 - local _list_0 = traceback local _max_0 = stop - for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do - local t = _list_0[_index_0] + 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 - return _accum_0 - end)() + traceback = _accum_0 + end local rep = "function '" .. chunk_func .. "'" traceback[#traceback] = traceback[#traceback]:gsub(rep, "main chunk") return concat(traceback, "\n") @@ -61,7 +65,8 @@ end local rewrite_traceback rewrite_traceback = function(text, err) local line_tables = require("moonscript.line_tables") - local V, S, Ct, C = lpeg.V, lpeg.S, lpeg.Ct, lpeg.C + local 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") @@ -107,5 +112,6 @@ end return { rewrite_traceback = rewrite_traceback, truncate_traceback = truncate_traceback, - user_error = user_error + user_error = user_error, + reverse_line_number = reverse_line_number } diff --git a/moonscript/errors.moon b/moonscript/errors.moon index 3bba447..a5bd94e 100644 --- a/moonscript/errors.moon +++ b/moonscript/errors.moon @@ -84,5 +84,5 @@ rewrite_traceback = (text, err) -> }, "\n" -{ :rewrite_traceback, :truncate_traceback, :user_error } +{ :rewrite_traceback, :truncate_traceback, :user_error, :reverse_line_number } diff --git a/moonscript/init.lua b/moonscript/init.lua index deb1a8c..6de5f12 100644 --- a/moonscript/init.lua +++ b/moonscript/init.lua @@ -1,113 +1,5 @@ -local compile = require("moonscript.compile") -local parse = require("moonscript.parse") -local concat, insert = table.concat, table.insert -local split, dump, get_options, unpack do - local _table_0 = require("moonscript.util") - split, dump, get_options, unpack = _table_0.split, _table_0.dump, _table_0.get_options, _table_0.unpack + local _with_0 = require("moonscript.base") + _with_0.insert_loader() + return _with_0 end -local lua = { - loadstring = loadstring, - load = load -} -local dirsep, line_tables, create_moonpath, to_lua, moon_loader, init_loader, loadstring, loadfile, dofile -dirsep = "/" -line_tables = require("moonscript.line_tables") -create_moonpath = function(package_path) - local paths = split(package_path, ";") - for i, path in ipairs(paths) do - local p = path:match("^(.-)%.lua$") - if p then - paths[i] = p .. ".moon" - end - end - return concat(paths, ";") -end -to_lua = function(text, options) - if options == nil then - options = { } - end - if "string" ~= type(text) then - local t = type(text) - return nil, "expecting string (got " .. t .. ")", 2 - end - local tree, err = parse.string(text) - if not tree then - return nil, err - end - local code, ltable, pos = compile.tree(tree, options) - if not code then - return nil, compile.format_error(ltable, pos, text), 2 - end - return code, ltable -end -moon_loader = function(name) - local name_path = name:gsub("%.", dirsep) - local file, file_path - local _list_0 = split(package.moonpath, ";") - for _index_0 = 1, #_list_0 do - local path = _list_0[_index_0] - file_path = path:gsub("?", name_path) - file = io.open(file_path) - if file then - break - end - end - if file then - local text = file:read("*a") - file:close() - local res, err = loadstring(text, file_path) - if not res then - error(err) - end - return res - end - return nil, "Could not find moon file" -end -if not package.moonpath then - package.moonpath = create_moonpath(package.path) -end -init_loader = function() - return insert(package.loaders or package.searchers, 2, moon_loader) -end -if not (_G.moon_no_loader) then - init_loader() -end -loadstring = function(...) - local options, str, chunk_name, mode, env = get_options(...) - chunk_name = chunk_name or "=(moonscript.loadstring)" - local code, ltable_or_err = to_lua(str, options) - if not (code) then - return nil, ltable_or_err - end - if chunk_name then - line_tables[chunk_name] = ltable_or_err - end - return (lua.loadstring or lua.load)(code, chunk_name, unpack({ - mode, - env - })) -end -loadfile = function(fname, ...) - local file, err = io.open(fname) - if not (file) then - return nil, err - end - local text = assert(file:read("*a")) - file:close() - return loadstring(text, fname, ...) -end -dofile = function(...) - local f = assert(loadfile(...)) - return f() -end -return { - _NAME = "moonscript", - to_lua = to_lua, - moon_chunk = moon_chunk, - moon_loader = moon_loader, - dirsep = dirsep, - dofile = dofile, - loadfile = loadfile, - loadstring = loadstring -} diff --git a/moonscript/init.moon b/moonscript/init.moon index 977c63b..396686d 100644 --- a/moonscript/init.moon +++ b/moonscript/init.moon @@ -1,95 +1,2 @@ - -compile = require "moonscript.compile" -parse = require "moonscript.parse" - -import concat, insert from table -import split, dump, get_options, unpack from require "moonscript.util" - -lua = :loadstring, :load - -local * - -dirsep = "/" -line_tables = require "moonscript.line_tables" - --- create moon path package from lua package path -create_moonpath = (package_path) -> - paths = split package_path, ";" - for i, path in ipairs paths - p = path\match "^(.-)%.lua$" - if p then paths[i] = p..".moon" - concat paths, ";" - -to_lua = (text, options={}) -> - if "string" != type text - t = type text - return nil, "expecting string (got ".. t ..")", 2 - - tree, err = parse.string text - if not tree - return nil, err - - code, ltable, pos = compile.tree tree, options - if not code - return nil, compile.format_error(ltable, pos, text), 2 - - code, ltable - -moon_loader = (name) -> - name_path = name\gsub "%.", dirsep - - local file, file_path - for path in *split package.moonpath, ";" - file_path = path\gsub "?", name_path - file = io.open file_path - break if file - - if file - text = file\read "*a" - file\close! - res, err = loadstring text, file_path - if not res - error err - - return res - - return nil, "Could not find moon file" - -if not package.moonpath - package.moonpath = create_moonpath package.path - -init_loader = -> - insert package.loaders or package.searchers, 2, moon_loader - -init_loader! unless _G.moon_no_loader - -loadstring = (...) -> - options, str, chunk_name, mode, env = get_options ... - chunk_name or= "=(moonscript.loadstring)" - - code, ltable_or_err = to_lua str, options - unless code - return nil, ltable_or_err - - line_tables[chunk_name] = ltable_or_err if chunk_name - -- the unpack prevents us from passing nil - (lua.loadstring or lua.load) code, chunk_name, unpack { mode, env } - -loadfile = (fname, ...) -> - file, err = io.open fname - return nil, err unless file - text = assert file\read "*a" - file\close! - loadstring text, fname, ... - --- throws errros -dofile = (...) -> - f = assert loadfile ... - f! - -{ - _NAME: "moonscript" - :to_lua, :moon_chunk, :moon_loader, :dirsep, :dofile, :loadfile, - :loadstring -} - +with require "moonscript.base" + .insert_loader! diff --git a/moonscript/parse.lua b/moonscript/parse.lua index a4e36b9..499ae1b 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -174,8 +174,12 @@ end local _chain_assignable = { index = true, dot = true, slice = true } local function is_assignable(node) + if node == "..." then + return false + end + local t = ntype(node) - return t == "self" or t == "value" or t == "self_class" or + return t == "ref" or t == "self" or t == "value" or t == "self_class" or t == "chain" and _chain_assignable[ntype(node[#node])] or t == "table" end @@ -378,8 +382,7 @@ local build_grammar = wrap_env(function() _Name / mark"self" + Cc"self") local KeyName = SelfName + Space * _Name / mark"key_literal" - - local Name = SelfName + Name + Space * "..." / trim + local VarArg = Space * P"..." / trim local g = lpeg.P{ File, @@ -409,11 +412,9 @@ local build_grammar = wrap_env(function() Local = key"local" * ((op"*" + op"^") / mark"declare_glob" + Ct(NameList) / mark"declare_with_shadows"), - Import = key"import" * Ct(ImportNameList) * key"from" * Exp / mark"import", + Import = key"import" * Ct(ImportNameList) * SpaceBreak^0 * key"from" * Exp / mark"import", ImportName = (sym"\\" * Ct(Cc"colon_stub" * Name) + Name), - ImportNameList = ImportName * (sym"," * ImportName)^0, - - NameList = Name * (sym"," * Name)^0, + ImportNameList = SpaceBreak^0 * ImportName * ((SpaceBreak^1 + sym"," * SpaceBreak^0) * ImportName)^0, BreakLoop = Ct(key"break"/trim) + Ct(key"continue"/trim), @@ -461,8 +462,7 @@ local build_grammar = wrap_env(function() -- we can ignore precedence for now OtherOps = op"or" + op"and" + op"<=" + op">=" + op"~=" + op"!=" + op"==" + op".." + op"<" + op">", - Assignable = Cmt(DotChain + Chain, check_assignable) + Name, - AssignableList = Assignable * (sym"," * Assignable)^0, + Assignable = Cmt(DotChain + Chain, check_assignable) + Name + SelfName, Exp = Ct(Value * ((OtherOps + FactorOp + TermOp) * Value)^0) / flatten_or_mark"exp", @@ -511,7 +511,7 @@ local build_grammar = wrap_env(function() LuaStringOpen = sym"[" * P"="^0 * "[" / trim, LuaStringClose = "]" * P"="^0 * "]", - Callable = Name + Parens / mark"parens", + Callable = pos(Name / mark"ref") + SelfName + VarArg + Parens / mark"parens", Parens = sym"(" * Exp * sym")", FnArgs = symx"(" * Ct(ExpList^-1) * sym")" + sym"!" * -P"=" * Ct"", @@ -575,7 +575,7 @@ local build_grammar = wrap_env(function() op"*" + op"^" + Ct(NameList) * (sym"=" * Ct(ExpListLow))^-1) / mark"export", - KeyValue = (sym":" * Name) / self_assign + Ct((KeyName + sym"[" * Exp * sym"]" + DoubleString + SingleString) * symx":" * (Exp + TableBlock)), + KeyValue = (sym":" * -SomeSpace * Name) / self_assign + Ct((KeyName + sym"[" * Exp * sym"]" + DoubleString + SingleString) * symx":" * (Exp + TableBlock)), KeyValueList = KeyValue * (sym"," * KeyValue)^0, KeyValueLine = CheckIndent * KeyValueList * sym","^-1, @@ -583,8 +583,8 @@ local build_grammar = wrap_env(function() (key"using" * Ct(NameList + Space * "nil") + Ct"") * sym")" + Ct"" * Ct"", - FnArgDefList = FnArgDef * (sym"," * FnArgDef)^0, - FnArgDef = Ct(Name * (sym"=" * Exp)^-1), + 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") * diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 4247353..449e983 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -1,45 +1,41 @@ local types = require("moonscript.types") local util = require("moonscript.util") local data = require("moonscript.data") -local reversed, unpack = util.reversed, util.unpack -local ntype, mtype, build, smart_node, is_slice, value_is_singular = types.ntype, types.mtype, types.build, types.smart_node, types.is_slice, types.value_is_singular -local insert = table.insert +local reversed, unpack +reversed, unpack = util.reversed, util.unpack +local ntype, mtype, build, smart_node, is_slice, value_is_singular +ntype, mtype, build, smart_node, is_slice, value_is_singular = types.ntype, types.mtype, types.build, types.smart_node, types.is_slice, types.value_is_singular +local insert +do + local _obj_0 = table + insert = _obj_0.insert +end local NameProxy, LocalName do - local _table_0 = require("moonscript.transform.names") - NameProxy, LocalName = _table_0.NameProxy, _table_0.LocalName + local _obj_0 = require("moonscript.transform.names") + NameProxy, LocalName = _obj_0.NameProxy, _obj_0.LocalName end local destructure = require("moonscript.transform.destructure") -local implicitly_return -local Run +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 _parent_0 = nil local _base_0 = { call = function(self, state) return self.fn(state) end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ __init = function(self, fn) self.fn = fn self[1] = "run" end, __base = _base_0, - __name = "Run", - __parent = _parent_0 + __name = "Run" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -47,12 +43,8 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Run = _class_0 end -local apply_to_last apply_to_last = function(stms, fn) local last_exp_id = 0 for i = #stms, 1, -1 do @@ -67,7 +59,11 @@ apply_to_last = function(stms, fn) local _len_0 = 1 for i, stm in ipairs(stms) do if i == last_exp_id then - _accum_0[_len_0] = fn(stm) + _accum_0[_len_0] = { + "transform", + stm, + fn + } else _accum_0[_len_0] = stm end @@ -76,7 +72,6 @@ apply_to_last = function(stms, fn) return _accum_0 end)() end -local is_singular is_singular = function(body) if #body ~= 1 then return false @@ -87,7 +82,6 @@ is_singular = function(body) return body[1] end end -local extract_declarations extract_declarations = function(self, body, start, out) if body == nil then body = self.current_stms @@ -113,7 +107,9 @@ extract_declarations = function(self, body, start, out) local _list_0 = stm[2] for _index_0 = 1, #_list_0 do local name = _list_0[_index_0] - if type(name) == "string" then + if ntype(name) == "ref" then + insert(out, name) + elseif type(name) == "string" then insert(out, name) end end @@ -128,7 +124,6 @@ extract_declarations = function(self, body, start, out) end return out end -local expand_elseif_assign expand_elseif_assign = function(ifstm) for i = 4, #ifstm do local case = ifstm[i] @@ -152,8 +147,7 @@ expand_elseif_assign = function(ifstm) end return ifstm end -local constructor_name = "new" -local with_continue_listener +constructor_name = "new" with_continue_listener = function(body) local continue_name = nil return { @@ -216,10 +210,20 @@ with_continue_listener = function(body) end) } end -local Transformer do - local _parent_0 = nil 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 @@ -253,9 +257,6 @@ do end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ __init = function(self, transformers) self.transformers = transformers @@ -264,17 +265,9 @@ do }) end, __base = _base_0, - __name = "Transformer", - __parent = _parent_0 + __name = "Transformer" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -282,12 +275,8 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Transformer = _class_0 end -local construct_comprehension construct_comprehension = function(inner, clauses) local current_stms = inner for _, clause in reversed(clauses) do @@ -295,10 +284,7 @@ construct_comprehension = function(inner, clauses) local _exp_0 = t if "for" == _exp_0 then local name, bounds - do - local _obj_0 = clause - _, name, bounds = _obj_0[1], _obj_0[2], _obj_0[3] - end + _, name, bounds = clause[1], clause[2], clause[3] current_stms = { "for", name, @@ -307,10 +293,7 @@ construct_comprehension = function(inner, clauses) } elseif "foreach" == _exp_0 then local names, iter - do - local _obj_0 = clause - _, names, iter = _obj_0[1], _obj_0[2], _obj_0[3] - end + _, names, iter = clause[1], clause[2], clause[3] current_stms = { "foreach", names, @@ -321,10 +304,7 @@ construct_comprehension = function(inner, clauses) } elseif "when" == _exp_0 then local cond - do - local _obj_0 = clause - _, cond = _obj_0[1], _obj_0[2] - end + _, cond = clause[1], clause[2] current_stms = { "if", cond, @@ -339,22 +319,38 @@ construct_comprehension = function(inner, clauses) end return current_stms[1] end -local Statement = Transformer({ +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) + node[2] = Value:transform_once(self, node[2]) + if "block_exp" == ntype(node[2]) then + local block_exp = node[2] + local block_body = block_exp[2] + local idx = #block_body + node[2] = block_body[idx] + block_body[idx] = node + return build.group(block_body) + end + return node + end, declare_glob = function(self, node) local names = extract_declarations(self) if node[2] == "^" then - names = (function() + do local _accum_0 = { } local _len_0 = 1 - local _list_0 = names - for _index_0 = 1, #_list_0 do + for _index_0 = 1, #names do local _continue_0 = false repeat - local name = _list_0[_index_0] - if not (name:match("^%u")) then + local name = names[_index_0] + if not (name[2]:match("^%u")) then _continue_0 = true break end @@ -367,8 +363,8 @@ local Statement = Transformer({ break end end - return _accum_0 - end)() + names = _accum_0 + end end return { "declare", @@ -377,8 +373,34 @@ local Statement = Transformer({ 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 _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)) + end + end local transformed - if #values == 1 then + if num_values == 1 then local value = values[1] local t = ntype(value) if t == "decorated" then @@ -411,7 +433,7 @@ local Statement = Transformer({ end node = transformed or node if destructure.has_destructure(names) then - return destructure.split_assign(node) + return destructure.split_assign(self, node) end return node end, @@ -442,7 +464,10 @@ local Statement = Transformer({ }) else return build.group({ - node, + { + "export", + node[2] + }, build.assign({ names = node[2], values = node[3] @@ -474,82 +499,44 @@ local Statement = Transformer({ end, import = function(self, node) local _, names, source = unpack(node) - local stubs = (function() + local table_values + do local _accum_0 = { } local _len_0 = 1 - local _list_0 = names - for _index_0 = 1, #_list_0 do - local name = _list_0[_index_0] - if type(name) == "table" then - _accum_0[_len_0] = name + 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 - _accum_0[_len_0] = { - "dot", - name - } + dest_val = name end + local _value_0 = { + { + "key_literal", + name + }, + dest_val + } + _accum_0[_len_0] = _value_0 _len_0 = _len_0 + 1 end - return _accum_0 - end)() - local real_names = (function() - local _accum_0 = { } - local _len_0 = 1 - local _list_0 = names - for _index_0 = 1, #_list_0 do - local name = _list_0[_index_0] - _accum_0[_len_0] = type(name) == "table" and name[2] or name - _len_0 = _len_0 + 1 - end - return _accum_0 - end)() - if type(source) == "string" then - return build.assign({ - names = real_names, - values = (function() - local _accum_0 = { } - local _len_0 = 1 - local _list_0 = stubs - for _index_0 = 1, #_list_0 do - local stub = _list_0[_index_0] - _accum_0[_len_0] = build.chain({ - base = source, - stub - }) - _len_0 = _len_0 + 1 - end - return _accum_0 - end)() - }) - else - local source_name = NameProxy("table") - return build.group({ - { - "declare", - real_names - }, - build["do"]({ - build.assign_one(source_name, source), - build.assign({ - names = real_names, - values = (function() - local _accum_0 = { } - local _len_0 = 1 - local _list_0 = stubs - for _index_0 = 1, #_list_0 do - local stub = _list_0[_index_0] - _accum_0[_len_0] = build.chain({ - base = source_name, - stub - }) - _len_0 = _len_0 + 1 - end - return _accum_0 - end)() - }) - }) - }) + 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) @@ -614,7 +601,7 @@ local Statement = Transformer({ local _list_0 = stm[2] for _index_0 = 1, #_list_0 do local name = _list_0[_index_0] - if type(name) == "string" then + if ntype(name) == "ref" then _accum_0[_len_0] = name _len_0 = _len_0 + 1 end @@ -646,7 +633,7 @@ local Statement = Transformer({ if destructure.has_destructure(assign[2]) then local name = NameProxy("des") body = { - destructure.build_assign(assign[2][1], name), + destructure.build_assign(self, assign[2][1], name), build.group(node[3]) } return build["do"]({ @@ -683,28 +670,38 @@ local Statement = Transformer({ return node end, with = function(self, node, ret) - local _, exp, block = unpack(node) - local scope_name = NameProxy("with") - local named_assign + 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 assign_name = names[1] - exp = values[1] - values[1] = scope_name - named_assign = { - "assign", - names, - values - } + 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), - build.assign_one(scope_name, exp), - build.group({ - named_assign - }), + copy_scope and build.assign_one(scope_name, exp) or NOOP, + named_assign or NOOP, build.group(block), (function() if ret then @@ -713,28 +710,27 @@ local Statement = Transformer({ end)() }) end, - foreach = function(self, node) + foreach = function(self, node, _) smart_node(node) local source = unpack(node.iter) local destructures = { } - node.names = (function() + do local _accum_0 = { } local _len_0 = 1 for i, name in ipairs(node.names) do if ntype(name) == "table" then do - local _with_0 = NameProxy("des") - local proxy = _with_0 - insert(destructures, destructure.build_assign(name, proxy)) - _accum_0[_len_0] = _with_0 + 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 - return _accum_0 - end)() + node.names = _accum_0 + end if next(destructures) then insert(destructures, build.group(node.body)) node.body = destructures @@ -742,13 +738,16 @@ local Statement = Transformer({ if ntype(source) == "unpack" then local list = source[2] local index_name = NameProxy("index") - local list_name = NameProxy("list") + 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]) @@ -784,8 +783,8 @@ local Statement = Transformer({ } end return build.group({ - build.assign_one(list_name, list), - slice_var, + list_name ~= list and build.assign_one(list_name, list) or NOOP, + slice_var or NOOP, build["for"]({ name = index_name, bounds = bounds, @@ -794,7 +793,7 @@ local Statement = Transformer({ "assign", node.names, { - list_name:index(index_name) + NameProxy.index(list_name, index_name) } }, build.group(node.body) @@ -855,9 +854,8 @@ local Statement = Transformer({ local if_stm = { "if" } - local _list_0 = conds - for _index_0 = 1, #_list_0 do - local cond = _list_0[_index_0] + for _index_0 = 1, #conds do + local cond = conds[_index_0] local if_cond = convert_cond(cond) if first then first = false @@ -874,18 +872,19 @@ local Statement = Transformer({ 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 = { } - local _list_0 = body - for _index_0 = 1, #_list_0 do - local item = _list_0[_index_0] + 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 - local _list_1 = item - for _index_1 = 2, #_list_1 do - local tuple = _list_1[_index_1] + 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 @@ -895,14 +894,13 @@ local Statement = Transformer({ end end local constructor - properties = (function() + do local _accum_0 = { } local _len_0 = 1 - local _list_1 = properties - for _index_0 = 1, #_list_1 do + for _index_0 = 1, #properties do local _continue_0 = false repeat - local tuple = _list_1[_index_0] + local tuple = properties[_index_0] local key = tuple[1] local _value_0 if key[1] == "key_literal" and key[2] == constructor_name then @@ -920,37 +918,36 @@ local Statement = Transformer({ break end end - return _accum_0 - 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 - constructor = build.fndef({ - args = { - { - "..." - } - }, - arrow = "fat", - body = { - build["if"]({ - cond = parent_cls_name, - ["then"] = { - build.chain({ - base = "super", - { - "call", - { - "..." - } - } - }) + 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) @@ -971,10 +968,19 @@ local Statement = Transformer({ 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", '"', - real_name + flattened_name } end local cls = build.table({ @@ -990,56 +996,66 @@ local Statement = Transformer({ "__name", real_name }, - { + parent_val and { "__parent", parent_cls_name - } + } or nil }) - local class_lookup = build["if"]({ - cond = { - "exp", - "val", - "==", - "nil", - "and", - parent_cls_name - }, - ["then"] = { - parent_cls_name:index("name") - } - }) - insert(class_lookup, { - "else", - { - "val" - } - }) - local cls_mt = build.table({ - { - "__index", - build.fndef({ - args = { - { - "cls" - }, - { - "name" - } + local class_index + if parent_val then + local class_lookup = build["if"]({ + cond = { + "exp", + { + "ref", + "val" }, - body = { - build.assign_one(LocalName("val"), build.chain({ - base = "rawget", + "==", + "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", { - "call", + base_name, { - base_name, + "ref", "name" } } - })), - class_lookup - } - }) + } + })), + class_lookup + } + }) + else + class_index = base_name + end + local cls_mt = build.table({ + { + "__index", + class_index }, { "__call", @@ -1090,7 +1106,6 @@ local Statement = Transformer({ }) local value = nil do - local _with_0 = build local out_body = { Run(function(self) if name then @@ -1098,17 +1113,17 @@ local Statement = Transformer({ end return self:set("super", function(block, chain) if chain then - local slice = (function() + local slice + do local _accum_0 = { } local _len_0 = 1 - local _list_1 = chain - for _index_0 = 3, #_list_1 do - local item = _list_1[_index_0] + for _index_0 = 3, #chain do + local item = chain[_index_0] _accum_0[_len_0] = item _len_0 = _len_0 + 1 end - return _accum_0 - end)() + slice = _accum_0 + end local new_chain = { "chain", parent_cls_name @@ -1152,9 +1167,8 @@ local Statement = Transformer({ } } end - local _list_1 = slice - for _index_0 = 1, #_list_1 do - local item = _list_1[_index_0] + for _index_0 = 1, #slice do + local item = slice[_index_0] insert(new_chain, item) end return new_chain @@ -1167,48 +1181,41 @@ local Statement = Transformer({ "declare_glob", "*" }, - _with_0.assign_one(parent_cls_name, parent_val == "" and "nil" or parent_val), - _with_0.assign_one(base_name, { + parent_val and build.assign_one(parent_cls_name, parent_val) or NOOP, + build.assign_one(base_name, { "table", properties }), - _with_0.assign_one(base_name:chain("__index"), base_name), - _with_0["if"]({ - cond = parent_cls_name, - ["then"] = { - _with_0.chain({ - base = "setmetatable", - { - "call", + 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, { - base_name, - _with_0.chain({ - base = parent_cls_name, - { - "dot", - "__base" - } - }) + "dot", + "__base" } - } - }) + }) + } } - }), - _with_0.assign_one(cls_name, cls), - _with_0.assign_one(base_name:chain("__class"), cls_name), - _with_0.group((function() + }) 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 { - _with_0.assign_one(LocalName("self"), cls_name), - _with_0.group(statements) + build.assign_one(LocalName("self"), cls_name), + build.group(statements) } end end)()), - _with_0["if"]({ + parent_val and build["if"]({ cond = { "exp", - parent_cls_name, - "and", parent_cls_name:chain("__inherited") }, ["then"] = { @@ -1220,11 +1227,11 @@ local Statement = Transformer({ } }) } - }), - _with_0.group((function() + }) or NOOP, + build.group((function() if name then return { - _with_0.assign_one(name, cls_name) + build.assign_one(name, cls_name) } end end)()), @@ -1234,11 +1241,11 @@ local Statement = Transformer({ end end)() } - value = _with_0.group({ - _with_0.group((function() + value = build.group({ + build.group((function() if ntype(name) == "value" then return { - _with_0.declare({ + build.declare({ names = { name } @@ -1246,15 +1253,13 @@ local Statement = Transformer({ } end end)()), - _with_0["do"](out_body) + build["do"](out_body) }) end return value end }) -local Accumulator do - local _parent_0 = nil local _base_0 = { body_idx = { ["for"] = 4, @@ -1266,12 +1271,15 @@ do node[index] = self:mutate_body(node[index]) return self:wrap(node) end, - wrap = function(self, node) - return build.block_exp({ + 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, - self.accum_name + group_type == "block_exp" and self.accum_name or NOOP }) end, mutate_body = function(self, body) @@ -1299,7 +1307,7 @@ do val = self.value_name end local update = { - build.assign_one(self.accum_name:index(self.len_name), val), + build.assign_one(NameProxy.index(self.accum_name, self.len_name), val), { "update", self.len_name, @@ -1312,27 +1320,16 @@ do end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self) + __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", - __parent = _parent_0 + __name = "Accumulator" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -1340,12 +1337,8 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Accumulator = _class_0 end -local default_accumulator default_accumulator = function(self, node) return Accumulator():convert(node) end @@ -1363,7 +1356,7 @@ implicitly_return = function(scope) return scope.transform.statement(stm, fn) elseif types.manual_return[t] or not types.is_value(stm) then if is_top and t == "return" and stm[2] == "" then - return nil + return NOOP else return stm end @@ -1380,7 +1373,7 @@ implicitly_return = function(scope) end return fn end -local Value = Transformer({ +Value = Transformer({ ["for"] = default_accumulator, ["while"] = default_accumulator, foreach = default_accumulator, @@ -1544,7 +1537,7 @@ local Value = Transformer({ table.remove(node, #node) local base_name = NameProxy("base") local fn_name = NameProxy("fn") - local is_super = node[2] == "super" + local is_super = ntype(node[2]) == "ref" and node[2][2] == "super" return self.transform.value(build.block_exp({ build.assign({ names = { diff --git a/moonscript/transform.moon b/moonscript/transform.moon index c8e9531..9175d41 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -9,8 +9,9 @@ import insert from table import NameProxy, LocalName from require "moonscript.transform.names" destructure = require "moonscript.transform.destructure" +NOOP = {"noop"} -local implicitly_return +local * class Run new: (@fn) => @@ -32,7 +33,7 @@ apply_to_last = (stms, fn) -> return for i, stm in ipairs stms if i == last_exp_id - fn stm + {"transform", stm, fn} else stm @@ -54,7 +55,11 @@ extract_declarations = (body=@current_stms, start=@current_stm_i + 1, out={}) => switch stm[1] when "assign", "declare" for name in *stm[2] - insert out, name if type(name) == "string" + if ntype(name) == "ref" + insert out, name + elseif type(name) == "string" + -- TODO: don't use string literal as ref + insert out, name when "group" extract_declarations @, stm[2], 1, out out @@ -107,6 +112,16 @@ class Transformer new: (@transformers) => @seen_nodes = setmetatable {}, __mode: "k" + transform_once: (scope, node, ...) => + return node if @seen_nodes[node] + @seen_nodes[node] = true + + transformer = @transformers[ntype node] + if transformer + transformer(scope, node, ...) or node + else + node + transform: (scope, node, ...) => return node if @seen_nodes[node] @seen_nodes[node] = true @@ -150,15 +165,33 @@ construct_comprehension = (inner, clauses) -> current_stms[1] Statement = Transformer { + transform: (tuple) => + {_, node, fn} = tuple + fn node + root_stms: (body) => apply_to_last body, implicitly_return @ + return: (node) => + node[2] = Value\transform_once @, node[2] + + if "block_exp" == ntype node[2] + block_exp = node[2] + block_body = block_exp[2] + + idx = #block_body + node[2] = block_body[idx] + block_body[idx] = node + return build.group block_body + + node + declare_glob: (node) => names = extract_declarations @ if node[2] == "^" names = for name in *names - continue unless name\match "^%u" + continue unless name[2]\match "^%u" name {"declare", names} @@ -166,8 +199,30 @@ Statement = Transformer { assign: (node) => names, values = unpack node, 2 + num_values = #values + num_names = #values + + -- special code simplifications for single assigns + if num_names == 1 and num_values == 1 + first_value = values[1] + first_name = names[1] + + switch ntype first_value + when "block_exp" + block_body = first_value[2] + idx = #block_body + block_body[idx] = build.assign_one first_name, block_body[idx] + + return build.group { + {"declare", {first_name}} + {"do", block_body} + } + + when "comprehension", "tblcomprehension", "foreach", "for", "while" + return build.assign_one first_name, Value\transform_once @, first_value + -- bubble cascading assigns - transformed = if #values == 1 + transformed = if num_values == 1 value = values[1] t = ntype value @@ -190,9 +245,8 @@ Statement = Transformer { node = transformed or node if destructure.has_destructure names - return destructure.split_assign node + return destructure.split_assign @, node - -- print util.dump node node continue: (node) => @@ -213,8 +267,9 @@ Statement = Transformer { cls } else + -- pull out vawlues and assign them after the export build.group { - node + { "export", node[2] } build.assign { names: node[2] values: node[3] @@ -232,33 +287,16 @@ Statement = Transformer { import: (node) => _, names, source = unpack node - - stubs = for name in *names - if type(name) == "table" - name + table_values = for name in *names + dest_val = if ntype(name) == "colon_stub" + name[2] else - {"dot", name} + name - real_names = for name in *names - type(name) == "table" and name[2] or name + {{"key_literal", name}, dest_val} - if type(source) == "string" - build.assign { - names: real_names - values: [build.chain { base: source, stub} for stub in *stubs] - } - else - source_name = NameProxy "table" - build.group { - {"declare", real_names} - build["do"] { - build.assign_one source_name, source - build.assign { - names: real_names - values: [build.chain { base: source_name, stub} for stub in *stubs] - } - } - } + dest = { "table", table_values } + { "assign", {dest}, {source}, [-1]: node[-1] } comprehension: (node, action) => _, exp, clauses = unpack node @@ -287,7 +325,7 @@ Statement = Transformer { if ntype(stm) == "assign" wrapped = build.group { - build.declare names: [name for name in *stm[2] when type(name) == "string"] + build.declare names: [name for name in *stm[2] when ntype(name) == "ref"] wrapped } @@ -304,7 +342,7 @@ Statement = Transformer { name = NameProxy "des" body = { - destructure.build_assign assign[2][1], name + destructure.build_assign @, assign[2][1], name build.group node[3] } @@ -334,28 +372,44 @@ Statement = Transformer { node with: (node, ret) => - _, exp, block = unpack node + exp, block = unpack node, 2 - scope_name = NameProxy "with" + copy_scope = true + local scope_name, named_assign - named_assign = if ntype(exp) == "assign" + + if ntype(exp) == "assign" names, values = unpack exp, 2 - assign_name = names[1] - exp = values[1] - values[1] = scope_name - {"assign", names, values} + first_name = names[1] + + if ntype(first_name) == "ref" + 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} + + elseif @is_local exp + scope_name = exp + copy_scope = false + + scope_name or= NameProxy "with" build.do { Run => @set "scope_var", scope_name - build.assign_one scope_name, exp - build.group { named_assign } + copy_scope and build.assign_one(scope_name, exp) or NOOP + named_assign or NOOP build.group block if ret ret scope_name } - foreach: (node) => + foreach: (node, _) => smart_node node source = unpack node.iter @@ -363,7 +417,7 @@ Statement = Transformer { node.names = for i, name in ipairs node.names if ntype(name) == "table" with proxy = NameProxy "des" - insert destructures, destructure.build_assign name, proxy + insert destructures, destructure.build_assign @, name, proxy else name @@ -375,7 +429,8 @@ Statement = Transformer { list = source[2] index_name = NameProxy "index" - list_name = NameProxy "list" + + list_name = @is_local(list) and list or NameProxy "list" slice_var = nil bounds = if is_slice list @@ -383,6 +438,8 @@ Statement = Transformer { table.remove list table.remove slice, 1 + list_name = list if @is_local list + slice[2] = if slice[2] and slice[2] != "" max_tmp_name = NameProxy "max" slice_var = build.assign_one max_tmp_name, slice[2] @@ -397,13 +454,13 @@ Statement = Transformer { {1, {"length", list_name}} return build.group { - build.assign_one list_name, list - slice_var + 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, {list_name\index index_name}} + {"assign", node.names, { NameProxy.index list_name, index_name }} build.group node.body } } @@ -468,6 +525,7 @@ Statement = Transformer { class: (node, ret, parent_assign) => _, name, parent_val, body = unpack node + parent_val = nil if parent_val == "" -- split apart properties and statements statements = {} @@ -499,18 +557,16 @@ Statement = Transformer { cls_name = NameProxy "class" unless constructor - constructor = build.fndef { - args: {{"..."}} - arrow: "fat" - body: { - build["if"] { - cond: parent_cls_name - then: { - build.chain { base: "super", {"call", {"..."}} } - } + constructor = if parent_val + build.fndef { + args: {{"..."}} + arrow: "fat" + body: { + build.chain { base: "super", {"call", {"..."}} } } } - } + else + build.fndef! real_name = name or parent_assign and parent_assign[2][1] real_name = switch ntype real_name @@ -526,34 +582,48 @@ Statement = Transformer { when "nil" "nil" else - {"string", '"', real_name} + name_t = type real_name + -- TODO: don't use string literal as ref + flattened_name = if name_t == "string" + real_name + elseif name_t == "table" and real_name[1] == "ref" + real_name[2] + else + error "don't know how to extract name from #{name_t}" + + {"string", '"', flattened_name} cls = build.table { {"__init", constructor} {"__base", base_name} {"__name", real_name} -- "quote the string" - {"__parent", parent_cls_name} + parent_val and {"__parent", parent_cls_name} or nil } - -- look up a name in the class object - class_lookup = build["if"] { - cond: {"exp", "val", "==", "nil", "and", parent_cls_name} - then: { - parent_cls_name\index"name" + -- looking up a name in the class object + class_index = if parent_val + class_lookup = build["if"] { + cond: { "exp", {"ref", "val"}, "==", "nil" } + then: { + parent_cls_name\index"name" + } } - } - insert class_lookup, {"else", {"val"}} + insert class_lookup, {"else", {"val"}} - cls_mt = build.table { - {"__index", build.fndef { + build.fndef { args: {{"cls"}, {"name"}} body: { build.assign_one LocalName"val", build.chain { - base: "rawget", {"call", {base_name, "name"}} + base: "rawget", {"call", {base_name, {"ref", "name"}}} } class_lookup } - }} + } + else + base_name + + cls_mt = build.table { + {"__index", class_index} {"__call", build.fndef { args: {{"cls"}, {"..."}} body: { @@ -617,22 +687,18 @@ Statement = Transformer { {"declare_glob", "*"} - .assign_one parent_cls_name, parent_val == "" and "nil" or parent_val + parent_val and .assign_one(parent_cls_name, parent_val) or NOOP + .assign_one base_name, {"table", properties} .assign_one base_name\chain"__index", base_name - .if { - cond: parent_cls_name - then: { - .chain { - base: "setmetatable" - {"call", { - base_name, - .chain { base: parent_cls_name, {"dot", "__base"}} - }} - } - } - } + parent_val and .chain({ + base: "setmetatable" + {"call", { + base_name, + .chain { base: parent_cls_name, {"dot", "__base"}} + }} + }) or NOOP .assign_one cls_name, cls .assign_one base_name\chain"__class", cls_name @@ -643,16 +709,14 @@ Statement = Transformer { } -- run the inherited callback - .if { - cond: {"exp", - parent_cls_name, "and", parent_cls_name\chain "__inherited" - } + parent_val and .if({ + cond: {"exp", parent_cls_name\chain "__inherited" } then: { parent_cls_name\chain "__inherited", {"call", { parent_cls_name, cls_name }} } - } + }) or NOOP .group if name then { .assign_one name, cls_name @@ -676,7 +740,7 @@ Statement = Transformer { class Accumulator body_idx: { for: 4, while: 3, foreach: 4 } - new: => + new: (accum_name) => @accum_name = NameProxy "accum" @value_name = NameProxy "value" @len_name = NameProxy "len" @@ -688,12 +752,12 @@ class Accumulator @wrap node -- wrap the node into a block_exp - wrap: (node) => - build.block_exp { + wrap: (node, group_type="block_exp") => + build[group_type] { build.assign_one @accum_name, build.table! build.assign_one @len_name, 1 node - @accum_name + group_type == "block_exp" and @accum_name or NOOP } -- mutates the body of a loop construct to save last value into accumulator @@ -716,7 +780,7 @@ class Accumulator @value_name update = { - build.assign_one @accum_name\index(@len_name), val + build.assign_one NameProxy.index(@accum_name, @len_name), val {"update", @len_name, "+=", 1} } @@ -742,7 +806,7 @@ implicitly_return = (scope) -> elseif types.manual_return[t] or not types.is_value stm -- remove blank return statement if is_top and t == "return" and stm[2] == "" - nil + NOOP else stm else @@ -857,7 +921,7 @@ Value = Transformer { base_name = NameProxy "base" fn_name = NameProxy "fn" - is_super = node[2] == "super" + is_super = ntype(node[2]) == "ref" and node[2][2] == "super" @transform.value build.block_exp { build.assign { names: {base_name} diff --git a/moonscript/transform/destructure.lua b/moonscript/transform/destructure.lua index 3bc22ac..cb45071 100644 --- a/moonscript/transform/destructure.lua +++ b/moonscript/transform/destructure.lua @@ -1,50 +1,52 @@ local ntype, mtype, build do - local _table_0 = require("moonscript.types") - ntype, mtype, build = _table_0.ntype, _table_0.mtype, _table_0.build + local _obj_0 = require("moonscript.types") + ntype, mtype, build = _obj_0.ntype, _obj_0.mtype, _obj_0.build end local NameProxy do - local _table_0 = require("moonscript.transform.names") - NameProxy = _table_0.NameProxy + local _obj_0 = require("moonscript.transform.names") + NameProxy = _obj_0.NameProxy +end +local insert +do + local _obj_0 = table + insert = _obj_0.insert end -local insert = table.insert local unpack do - local _table_0 = require("moonscript.util") - unpack = _table_0.unpack + local _obj_0 = require("moonscript.util") + unpack = _obj_0.unpack end local user_error do - local _table_0 = require("moonscript.errors") - user_error = _table_0.user_error + local _obj_0 = require("moonscript.errors") + user_error = _obj_0.user_error end +local util = require("moonscript.util") local join join = function(...) do - local _with_0 = { } - local out = _with_0 + local out = { } local i = 1 local _list_0 = { ... } for _index_0 = 1, #_list_0 do local tbl = _list_0[_index_0] - local _list_1 = tbl - for _index_1 = 1, #_list_1 do - local v = _list_1[_index_1] + for _index_1 = 1, #tbl do + local v = tbl[_index_1] out[i] = v i = i + 1 end end - return _with_0 + return out end end local has_destructure has_destructure = function(names) - local _list_0 = names - for _index_0 = 1, #_list_0 do - local n = _list_0[_index_0] + for _index_0 = 1, #names do + local n = names[_index_0] if ntype(n) == "table" then return true end @@ -78,10 +80,15 @@ extract_assign_names = function(name, accum, prefix) local key = tuple[1] local s if ntype(key) == "key_literal" then - s = { - "dot", - key[2] - } + local key_name = key[2] + if ntype(key_name) == "colon_stub" then + s = key_name + else + s = { + "dot", + key_name + } + end else s = { "index", @@ -93,13 +100,13 @@ extract_assign_names = function(name, accum, prefix) suffix = join(prefix, { suffix }) - local t = ntype(value) - if t == "value" or t == "chain" or t == "self" then + 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 t == "table" then + elseif "table" == _exp_0 then extract_assign_names(value, accum, suffix) else user_error("Can't destructure value of type: " .. tostring(ntype(value))) @@ -108,7 +115,7 @@ extract_assign_names = function(name, accum, prefix) return accum end local build_assign -build_assign = function(destruct_literal, receiver) +build_assign = function(scope, destruct_literal, receiver) local extracted_names = extract_assign_names(destruct_literal) local names = { } local values = { } @@ -118,12 +125,11 @@ build_assign = function(destruct_literal, receiver) values } local obj - if mtype(receiver) == NameProxy then + if scope:is_local(receiver) then obj = receiver else do - local _with_0 = NameProxy("obj") - obj = _with_0 + obj = NameProxy("obj") inner = build["do"]({ build.assign_one(obj, receiver), { @@ -132,14 +138,13 @@ build_assign = function(destruct_literal, receiver) values } }) - obj = _with_0 + obj = obj end end - local _list_0 = extracted_names - for _index_0 = 1, #_list_0 do - local tuple = _list_0[_index_0] + for _index_0 = 1, #extracted_names do + local tuple = extracted_names[_index_0] insert(names, tuple[1]) - insert(values, obj:chain(unpack(tuple[2]))) + insert(values, NameProxy.chain(obj, unpack(tuple[2]))) end return build.group({ { @@ -150,7 +155,7 @@ build_assign = function(destruct_literal, receiver) }) end local split_assign -split_assign = function(assign) +split_assign = function(scope, assign) local names, values = unpack(assign, 2) local g = { } local total_names = #names @@ -182,7 +187,7 @@ split_assign = function(assign) end)() }) end - insert(g, build_assign(n, values[i])) + insert(g, build_assign(scope, n, values[i])) start = i + 1 end end @@ -193,15 +198,15 @@ split_assign = function(assign) "_" } else - name_slice = (function() + 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 - return _accum_0 - end)() + name_slice = _accum_0 + end end local value_slice if total_values < start then @@ -209,15 +214,15 @@ split_assign = function(assign) "nil" } else - value_slice = (function() + 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 - return _accum_0 - end)() + value_slice = _accum_0 + end end insert(g, { "assign", diff --git a/moonscript/transform/destructure.moon b/moonscript/transform/destructure.moon index 4863729..274e6ed 100644 --- a/moonscript/transform/destructure.moon +++ b/moonscript/transform/destructure.moon @@ -6,6 +6,8 @@ import unpack from require "moonscript.util" import user_error from require "moonscript.errors" +util = require "moonscript.util" + join = (...) -> with out = {} i = 1 @@ -29,7 +31,11 @@ extract_assign_names = (name, accum={}, prefix={}) -> else key = tuple[1] s = if ntype(key) == "key_literal" - {"dot", key[2]} + key_name = key[2] + if ntype(key_name) == "colon_stub" + key_name + else + {"dot", key_name} else {"index", key} @@ -37,17 +43,17 @@ extract_assign_names = (name, accum={}, prefix={}) -> suffix = join prefix, {suffix} - t = ntype value - if t == "value" or t == "chain" or t == "self" - insert accum, {value, suffix} - elseif t == "table" - extract_assign_names value, accum, suffix - else - user_error "Can't destructure value of type: #{ntype value}" + switch ntype value + when "value", "ref", "chain", "self" + insert accum, {value, suffix} + when "table" + extract_assign_names value, accum, suffix + else + user_error "Can't destructure value of type: #{ntype value}" accum -build_assign = (destruct_literal, receiver) -> +build_assign = (scope, destruct_literal, receiver) -> extracted_names = extract_assign_names destruct_literal names = {} @@ -55,7 +61,7 @@ build_assign = (destruct_literal, receiver) -> inner = {"assign", names, values} - obj = if mtype(receiver) == NameProxy + obj = if scope\is_local receiver receiver else with obj = NameProxy "obj" @@ -66,7 +72,7 @@ build_assign = (destruct_literal, receiver) -> for tuple in *extracted_names insert names, tuple[1] - insert values, obj\chain unpack tuple[2] + insert values, NameProxy.chain obj, unpack tuple[2] build.group { {"declare", names} @@ -74,7 +80,7 @@ build_assign = (destruct_literal, receiver) -> } -- applies to destructuring to a assign node -split_assign = (assign) -> +split_assign = (scope, assign) -> names, values = unpack assign, 2 g = {} @@ -96,7 +102,7 @@ split_assign = (assign) -> values[i] } - insert g, build_assign n, values[i] + insert g, build_assign scope, n, values[i] start = i + 1 diff --git a/moonscript/transform/names.lua b/moonscript/transform/names.lua index 5f43920..a7584da 100644 --- a/moonscript/transform/names.lua +++ b/moonscript/transform/names.lua @@ -1,42 +1,30 @@ local build do - local _table_0 = require("moonscript.types") - build = _table_0.build + local _obj_0 = require("moonscript.types") + build = _obj_0.build end local unpack do - local _table_0 = require("moonscript.util") - unpack = _table_0.unpack + local _obj_0 = require("moonscript.util") + unpack = _obj_0.unpack end local LocalName do - local _parent_0 = nil local _base_0 = { get_name = function(self) return self.name end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ __init = function(self, name) self.name = name self[1] = "temp_name" end, __base = _base_0, - __name = "LocalName", - __parent = _parent_0 + __name = "LocalName" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -44,14 +32,10 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end LocalName = _class_0 end local NameProxy do - local _parent_0 = nil local _base_0 = { get_name = function(self, scope, dont_put) if dont_put == nil then @@ -63,32 +47,29 @@ do return self.name end, chain = function(self, ...) - local items = (function(...) - local _accum_0 = { } - local _len_0 = 1 - local _list_0 = { - ... - } - for _index_0 = 1, #_list_0 do - local i = _list_0[_index_0] - if type(i) == "string" then - _accum_0[_len_0] = { - "dot", - i - } - else - _accum_0[_len_0] = i - end - _len_0 = _len_0 + 1 - end - return _accum_0 - end)(...) - return build.chain({ + local items = { base = self, - unpack(items) - }) + ... + } + 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, { @@ -106,26 +87,15 @@ do end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ __init = function(self, prefix) self.prefix = prefix self[1] = "temp_name" end, __base = _base_0, - __name = "NameProxy", - __parent = _parent_0 + __name = "NameProxy" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -133,9 +103,6 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end NameProxy = _class_0 end return { diff --git a/moonscript/transform/names.moon b/moonscript/transform/names.moon index 24fc126..220d862 100644 --- a/moonscript/transform/names.moon +++ b/moonscript/transform/names.moon @@ -18,18 +18,19 @@ class NameProxy @name chain: (...) => - items = for i in *{...} - if type(i) == "string" - {"dot", i} + items = { base: @, ... } + for k,v in ipairs items + items[k] = if type(v) == "string" + {"dot", v} else - i + v - build.chain { - base: self - unpack items - } + build.chain items index: (key) => + if type(key) == "string" + key = {"ref", key} + build.chain { base: self, {"index", key} } diff --git a/moonscript/types.lua b/moonscript/types.lua index 3b1ad95..aae50c9 100644 --- a/moonscript/types.lua +++ b/moonscript/types.lua @@ -1,14 +1,23 @@ local util = require("moonscript.util") -local data = require("moonscript.data") -local insert = table.insert -local unpack = util.unpack -local manual_return = data.Set({ +local Set +do + local _obj_0 = require("moonscript.data") + Set = _obj_0.Set +end +local insert +do + local _obj_0 = table + insert = _obj_0.insert +end +local unpack +unpack = util.unpack +local manual_return = Set({ "foreach", "for", "while", "return" }) -local cascading = data.Set({ +local cascading = Set({ "if", "unless", "with", @@ -232,9 +241,8 @@ build = setmetatable({ if tbl == nil then tbl = { } end - local _list_0 = tbl - for _index_0 = 1, #_list_0 do - local tuple = _list_0[_index_0] + for _index_0 = 1, #tbl do + local tuple = tbl[_index_0] if type(tuple[1]) == "string" then tuple[1] = { "key_literal", @@ -255,13 +263,18 @@ build = setmetatable({ 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 } - local _list_0 = parts - for _index_0 = 1, #_list_0 do - local part = _list_0[_index_0] + for _index_0 = 1, #parts do + local part = parts[_index_0] insert(node, part) end return node diff --git a/moonscript/types.moon b/moonscript/types.moon index 992ff77..9b41523 100644 --- a/moonscript/types.moon +++ b/moonscript/types.moon @@ -1,17 +1,17 @@ util = require "moonscript.util" -data = require "moonscript.data" +import Set from require "moonscript.data" import insert from table import unpack from util -- implicit return does not work on these statements -manual_return = data.Set{"foreach", "for", "while", "return"} +manual_return = Set{"foreach", "for", "while", "return"} -- Assigns and returns are bubbled into their bodies. -- All cascading statement transform functions accept a second arugment that -- is the transformation to apply to the last statement in their body -cascading = data.Set{ "if", "unless", "with", "switch", "class", "do" } +cascading = Set{ "if", "unless", "with", "switch", "class", "do" } -- type of node as string ntype = (node) -> @@ -122,8 +122,10 @@ build = nil build = setmetatable { group: (body={}) -> {"group", body} + do: (body) -> {"do", body} + assign_one: (name, value) -> build.assign { names: {name} @@ -139,8 +141,13 @@ build = setmetatable { {"table", tbl} block_exp: (body) -> {"block_exp", body} + chain: (parts) -> base = parts.base or error"expecting base property for chain" + + if type(base) == "string" + base = {"ref", base} + node = {"chain", base} for part in *parts insert node, part diff --git a/moonscript/util.lua b/moonscript/util.lua index 5449465..dfb4355 100644 --- a/moonscript/util.lua +++ b/moonscript/util.lua @@ -1,4 +1,8 @@ -local concat = table.concat +local concat +do + local _obj_0 = table + concat = _obj_0.concat +end local unpack = unpack or table.unpack local type = type local moon = { @@ -73,15 +77,13 @@ split = function(str, delim) return { } end str = str .. delim - return (function() - local _accum_0 = { } - local _len_0 = 1 - for m in str:gmatch("(.-)" .. delim) do - _accum_0[_len_0] = m - _len_0 = _len_0 + 1 - end - return _accum_0 - end)() + 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) @@ -100,15 +102,16 @@ dump = function(what) end seen[what] = true depth = depth + 1 - local lines = (function() + 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 - return _accum_0 - end)() + lines = _accum_0 + end seen[what] = false return "{\n" .. concat(lines) .. (" "):rep((depth - 1) * 4) .. "}\n" else @@ -119,7 +122,8 @@ dump = function(what) end local debug_posmap debug_posmap = function(posmap, moon_code, lua_code) - local tuples = (function() + local tuples + do local _accum_0 = { } local _len_0 = 1 for k, v in pairs(posmap) do @@ -129,17 +133,17 @@ debug_posmap = function(posmap, moon_code, lua_code) } _len_0 = _len_0 + 1 end - return _accum_0 - end)() + tuples = _accum_0 + end table.sort(tuples, function(a, b) return a[1] < b[1] end) - local lines = (function() + local lines + do local _accum_0 = { } local _len_0 = 1 - local _list_0 = tuples - for _index_0 = 1, #_list_0 do - local pair = _list_0[_index_0] + 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) @@ -148,8 +152,8 @@ debug_posmap = function(posmap, moon_code, lua_code) _accum_0[_len_0] = _value_0 _len_0 = _len_0 + 1 end - return _accum_0 - end)() + lines = _accum_0 + end return concat(lines, "\n") end local setfenv = setfenv or function(fn, env) diff --git a/moonscript/version.lua b/moonscript/version.lua index e9595d0..ce19da4 100644 --- a/moonscript/version.lua +++ b/moonscript/version.lua @@ -1,7 +1,7 @@ module("moonscript.version", package.seeall) -version = "0.2.3-2" +version = "0.2.4" function print_version() print("MoonScript version "..version) end diff --git a/spec/class_spec.moon b/spec/class_spec.moon new file mode 100644 index 0000000..c46b441 --- /dev/null +++ b/spec/class_spec.moon @@ -0,0 +1,137 @@ + +describe "class", -> + it "should make a class with constructor", -> + class Thing + new: => + @color = "blue" + + instance = Thing! + + assert.same instance, { color: "blue" } + + it "should have instance methods", -> + class Thing + get_color: => @color + + new: => + @color = "blue" + + instance = Thing! + assert.same instance\get_color!, "blue" + + + it "should have class property", -> + class Thing + color: "blue" + get_color: => @color + + instance = Thing! + assert.same instance\get_color!, "blue" + assert.same Thing.color, "blue" + + it "should inherit another class", -> + class Base + get_property: => @[@property] + + new: (@property) => + + class Thing extends Base + color: "green" + + instance = Thing "color" + assert.same instance\get_property!, "green" + + it "should call super constructor", -> + class Base + new: (@property) => + + class Thing extends Base + new: (@name) => + super "name" + + instance = Thing "the_thing" + + assert.same instance.property, "name" + assert.same instance.name, "the_thing" + + + it "should call super method", -> + class Base + _count: 111 + counter: => @_count + + class Thing extends Base + counter: => "%08d"\format super! + + instance = Thing! + assert.same instance\counter!, "00000111" + + it "should get super class", -> + class Base + class Thing extends Base + get_super: => super + + instance = Thing! + assert.is_true instance\get_super! == Base + + it "should get a bound method from super", -> + class Base + count: 1 + get_count: => @count + + class Thing extends Base + get_count: => "this is wrong" + get_method: => super\get_count + + instance = Thing! + assert.same instance\get_method!!, 1 + + it "should have class properties", -> + class Base + class Thing extends Base + + instance = Thing! + + assert.same Base.__name, "Base" + assert.same Thing.__name, "Thing" + assert.is_true Thing.__parent == Base + + assert.is_true instance.__class == Thing + + it "should have name when assigned", -> + Thing = class + assert.same Thing.__name, "Thing" + + + it "should not expose class properties on instance", -> + class Thing + @height: 10 + + Thing.color = "blue" + + instance = Thing! + assert.same instance.color, nil + assert.same instance.height, nil + + it "should expose new things added to __base", -> + class Thing + + instance = Thing! + Thing.__base.color = "green" + + assert.same instance.color, "green" + + it "should call with correct receiver", -> + local instance + + class Thing + is_class: => assert.is_true @ == Thing + is_instance: => assert.is_true @ == instance + + go: => + @@is_class! + @is_instance! + + instance = Thing! + instance\go! + diff --git a/spec/comprehension_spec.moon b/spec/comprehension_spec.moon new file mode 100644 index 0000000..2f07939 --- /dev/null +++ b/spec/comprehension_spec.moon @@ -0,0 +1,75 @@ + +describe "comprehension", -> + it "should double every number", -> + input = {1,2,3,4,5,6} + output_1 = [i * 2 for _, i in pairs input ] + output_2 = [i * 2 for i in *input ] + + assert.same output_1, {2,4,6,8,10,12} + + it "should create a slice", -> + input = {1,2,3,4,5,6} + + slice_1 = [i for i in *input[1,3]] + slice_2 = [i for i in *input[,3]] + + slice_3 = [i for i in *input[3,]] + slice_4 = [i for i in *input[,]] + + slice_5 = [i for i in *input[,,2]] + slice_6 = [i for i in *input[2,,2]] + + assert.same slice_1, {1,2,3} + assert.same slice_1, slice_2 + assert.same slice_3, {3,4,5,6} + assert.same slice_4, input + + assert.same slice_5, {1,3,5} + assert.same slice_6, {2,4,6} + + it "should be able to assign to self", -> + input = {1,2,3,4} + output = input + output = [i * 2 for i in *output] + + assert.same input, {1,2,3,4} + assert.same output, {2,4,6,8} + + output = input + output = [i * 2 for _,i in ipairs input] + + assert.same input, {1,2,3,4} + assert.same output, {2,4,6,8} + + +describe "table comprehension", -> + it "should copy table", -> + input = { 1,2,3, hello: "world", thing: true } + output = {k,v for k,v in pairs input } + + assert.is_true input != output + assert.same input, output + + it "should support when", -> + input = { + color: "red" + name: "fast" + width: 123 + } + + output = { k,v for k,v in pairs input when k != "color" } + + assert.same output, { name: "fast", width: 123 } + + it "should do unpack", -> + input = {4,9,16,25} + output = {i, math.sqrt i for i in *input} + + assert.same output, { [4]: 2, [9]: 3, [16]: 4, [25]: 5 } + + it "should use multiple return values", -> + input = { {"hello", "world"}, {"foo", "bar"} } + output = { unpack tuple for tuple in *input } + + assert.same output, { foo: "bar", hello: "world" } + diff --git a/spec/destructure_spec.moon b/spec/destructure_spec.moon new file mode 100644 index 0000000..fe30042 --- /dev/null +++ b/spec/destructure_spec.moon @@ -0,0 +1,32 @@ +describe "destructure", -> + it "should unpack array", -> + input = {1,2,3} + + {a,b,c} = {1,2,3} + {d,e,f} = input + + assert.same a, 1 + assert.same b, 2 + assert.same c, 3 + + assert.same d, 1 + assert.same e, 2 + assert.same f, 3 + + it "should destructure", -> + futurists = + sculptor: "Umberto Boccioni" + painter: "Vladimir Burliuk" + poet: + name: "F.T. Marinetti" + address: { + "Via Roma 42R" + "Bellagio, Italy 22021" + } + + {poet: {:name, address: {street, city}}} = futurists + + assert.same name, "F.T. Marinetti" + assert.same street, "Via Roma 42R" + assert.same city, "Bellagio, Italy 22021" + diff --git a/tests/error_inputs/first.moon b/spec/error_inputs/first.moon similarity index 95% rename from tests/error_inputs/first.moon rename to spec/error_inputs/first.moon index 15afa9e..c8d45fa 100644 --- a/tests/error_inputs/first.moon +++ b/spec/error_inputs/first.moon @@ -1,6 +1,8 @@ hello_world = false +print = -> + if hello_world print "sackman" x = 5 + 5 diff --git a/tests/error_inputs/second.moon b/spec/error_inputs/second.moon similarity index 92% rename from tests/error_inputs/second.moon rename to spec/error_inputs/second.moon index 053dcca..d9b7e68 100644 --- a/tests/error_inputs/second.moon +++ b/spec/error_inputs/second.moon @@ -1,4 +1,5 @@ +print = -> if false true diff --git a/tests/error_inputs/third.moon b/spec/error_inputs/third.moon similarity index 96% rename from tests/error_inputs/third.moon rename to spec/error_inputs/third.moon index 08ef1d7..b3c1e2e 100644 --- a/tests/error_inputs/third.moon +++ b/spec/error_inputs/third.moon @@ -1,4 +1,6 @@ +print = -> + if (-> print "hello world" print "who is this") diff --git a/spec/error_rewriting_spec.moon b/spec/error_rewriting_spec.moon new file mode 100644 index 0000000..d2f55c9 --- /dev/null +++ b/spec/error_rewriting_spec.moon @@ -0,0 +1,30 @@ + +moonscript = require "moonscript.base" +errors = require "moonscript.errors" +util = require "moonscript.util" + +get_rewritten_line_no = (fname) -> + fname = "spec/error_inputs/#{fname}.moon" + chunk = moonscript.loadfile fname + + success, err = pcall chunk + error "`#{fname}` is supposed to have runtime error!" if success + + source = tonumber err\match "]:(%d+)" + + line_table = require("moonscript.line_tables")[fname] + errors.reverse_line_number fname, line_table, source, {} + + +-- TODO: check entire stack trace +describe "error rewriting", -> + tests = { + "first": 24 + "second": 16 + "third": 11 + } + + for name, expected_no in pairs tests + it "should rewrite line number", -> + assert.same get_rewritten_line_no(name), expected_no + diff --git a/spec/import_spec.moon b/spec/import_spec.moon new file mode 100644 index 0000000..bb1472c --- /dev/null +++ b/spec/import_spec.moon @@ -0,0 +1,26 @@ +describe "import", -> + it "should import from table", -> + import sort, insert from table + t = { 4,2,6 } + insert t, 1 + sort t + + assert.same t, {1,2,4,6} + + it "should import from local", -> + thing = { var: 10, hello: "world", func: => @var } + import hello, \func from thing + + assert.same hello, thing.hello + assert.same func!, thing.var + + it "should not call source multiple times", -> + count = 0 + source = -> + count += 1 + { hello: "world", foo: "bar" } + + import hello, foo from source! + + assert.same count, 1 + diff --git a/tests/inputs/assign.moon b/spec/inputs/assign.moon similarity index 100% rename from tests/inputs/assign.moon rename to spec/inputs/assign.moon diff --git a/tests/inputs/bubbling.moon b/spec/inputs/bubbling.moon similarity index 100% rename from tests/inputs/bubbling.moon rename to spec/inputs/bubbling.moon diff --git a/tests/inputs/class.moon b/spec/inputs/class.moon similarity index 100% rename from tests/inputs/class.moon rename to spec/inputs/class.moon diff --git a/tests/inputs/comprehension.moon b/spec/inputs/comprehension.moon similarity index 100% rename from tests/inputs/comprehension.moon rename to spec/inputs/comprehension.moon diff --git a/tests/inputs/cond.moon b/spec/inputs/cond.moon similarity index 100% rename from tests/inputs/cond.moon rename to spec/inputs/cond.moon diff --git a/spec/inputs/destructure.moon b/spec/inputs/destructure.moon new file mode 100644 index 0000000..beb79d6 --- /dev/null +++ b/spec/inputs/destructure.moon @@ -0,0 +1,100 @@ + +do + {a, b} = hello + + {{a}, b, {c}} = hello + + { :hello, :world } = value + +do + { yes: no, thing } = world + + {:a,:b,:c,:d} = yeah + + {a} = one, two + {b}, c = one + {d}, e = one, two + + x, {y} = one, two + + xx, yy = 1, 2 + {yy, xx} = {xx, yy} + + {a, :b, c, :d, e, :f, g} = tbl + +--- + +do + futurists = + sculptor: "Umberto Boccioni" + painter: "Vladimir Burliuk" + poet: + name: "F.T. Marinetti" + address: { + "Via Roma 42R" + "Bellagio, Italy 22021" + } + + {poet: {:name, address: {street, city}}} = futurists + +-- + +do + { @world } = x + { a.b, c.y, func!.z } = x + + { world: @world } = x + +-- + +do + thing = {{1,2}, {3,4}} + + for {x,y} in *thing + print x,y + + +-- + +do + with {a,b} = thing + print a, b + + +-- + +do + thing = nil + if {a} = thing + print a + else + print "nothing" + + thang = {1,2} + if {a,b} = thang + print a,b + + if {a,b} = thing + print a,b + elseif {c,d} = thang + print c,d + else + print "NO" + +-- + +do + z = "yeah" + {a,b,c} = z + +do + {a,b,c} = z + +(z) -> + {a,b,c} = z + +do + z = "oo" + (k) -> + {a,b,c} = z + diff --git a/tests/inputs/do.moon b/spec/inputs/do.moon similarity index 100% rename from tests/inputs/do.moon rename to spec/inputs/do.moon diff --git a/tests/inputs/export.moon b/spec/inputs/export.moon similarity index 100% rename from tests/inputs/export.moon rename to spec/inputs/export.moon diff --git a/tests/inputs/funcs.moon b/spec/inputs/funcs.moon similarity index 100% rename from tests/inputs/funcs.moon rename to spec/inputs/funcs.moon diff --git a/tests/inputs/import.moon b/spec/inputs/import.moon similarity index 59% rename from tests/inputs/import.moon rename to spec/inputs/import.moon index dac4101..d86d724 100644 --- a/tests/inputs/import.moon +++ b/spec/inputs/import.moon @@ -20,3 +20,29 @@ import something from a table if indent import okay, \well from tables[100] +do + import a, b, c from z + +do + import a, + b, c from z + +do + import a + b + c from z + +do + import + a + b + c from z + + +do + import + a + b + c + from z + diff --git a/tests/inputs/lists.moon b/spec/inputs/lists.moon similarity index 97% rename from tests/inputs/lists.moon rename to spec/inputs/lists.moon index 48337cd..91e559e 100644 --- a/tests/inputs/lists.moon +++ b/spec/inputs/lists.moon @@ -3,8 +3,6 @@ hi = [x*2 for _, x in ipairs{1,2,3,4}] items = {1,2,3,4,5,6} -mm = [@x for @x in ipairs items] - [z for z in ipairs items when z > 4] rad = [{a} for a in ipairs { diff --git a/tests/inputs/literals.moon b/spec/inputs/literals.moon similarity index 100% rename from tests/inputs/literals.moon rename to spec/inputs/literals.moon diff --git a/tests/inputs/local.moon b/spec/inputs/local.moon similarity index 100% rename from tests/inputs/local.moon rename to spec/inputs/local.moon diff --git a/tests/inputs/loops.moon b/spec/inputs/loops.moon similarity index 95% rename from tests/inputs/loops.moon rename to spec/inputs/loops.moon index 6d37a82..fbdc638 100644 --- a/tests/inputs/loops.moon +++ b/spec/inputs/loops.moon @@ -114,3 +114,11 @@ for x=1,10 for y = 2,12 continue if y % 3 == 0 +-- + +do + xxx = {1,2,3,4} + for thing in *xxx + print thing + + diff --git a/tests/inputs/string.moon b/spec/inputs/string.moon similarity index 100% rename from tests/inputs/string.moon rename to spec/inputs/string.moon diff --git a/tests/inputs/stub.moon b/spec/inputs/stub.moon similarity index 100% rename from tests/inputs/stub.moon rename to spec/inputs/stub.moon diff --git a/tests/inputs/switch.moon b/spec/inputs/switch.moon similarity index 100% rename from tests/inputs/switch.moon rename to spec/inputs/switch.moon diff --git a/tests/inputs/syntax.moon b/spec/inputs/syntax.moon similarity index 100% rename from tests/inputs/syntax.moon rename to spec/inputs/syntax.moon diff --git a/tests/inputs/tables.moon b/spec/inputs/tables.moon similarity index 100% rename from tests/inputs/tables.moon rename to spec/inputs/tables.moon diff --git a/tests/inputs/using.moon b/spec/inputs/using.moon similarity index 100% rename from tests/inputs/using.moon rename to spec/inputs/using.moon diff --git a/tests/inputs/whitespace.moon b/spec/inputs/whitespace.moon similarity index 100% rename from tests/inputs/whitespace.moon rename to spec/inputs/whitespace.moon diff --git a/spec/inputs/with.moon b/spec/inputs/with.moon new file mode 100644 index 0000000..54aa509 --- /dev/null +++ b/spec/inputs/with.moon @@ -0,0 +1,98 @@ + +do + a = -> + with something + print .hello + print hi + print "world" + +do + with leaf + .world! + .world 1,2,3 + + g = .what.is.this + + .hi 1,2,3 + + \hi(1,2).world 2323 + + \hi "yeah", "man" + .world = 200 + +do + zyzyzy = with something + .set_state "hello world" + +do + x = 5 + with Something! + \write "hello world" + + +do + x = { + hello: with yeah + \okay! + } + +do + with foo + \prop"something".hello + .prop\send(one) + .prop\send one + + +-- + +do + with a, b -- b is lost + print .world + + mod = with _M = {} + .Thing = "hi" + + -- operate on a only + with a, b = something, pooh + print .world + + x = with a, b = 1, 2 + print a + b + + print with a, b = 1, 2 + print a + b + + -- assignment lhs must be evaluated in the order they appear + p = with hello!.x, world!.y = 1, 2 + print a + b + +-- + +do + x = "hello" + with x + x\upper! + +do + with k = "jo" + print \upper! + +do + with a,b,c = "", "", "" + print \upper! + +do + a = "bunk" + with a,b,c = "", "", "" + print \upper! + +do + with j + print \upper! + +do + with k.j = "jo" + print \upper! + + + + diff --git a/test2.moon b/spec/lang_spec.moon similarity index 96% rename from test2.moon rename to spec/lang_spec.moon index 49eec86..7fd1a3f 100644 --- a/test2.moon +++ b/spec/lang_spec.moon @@ -1,4 +1,3 @@ - lfs = require "lfs" parse = require "moonscript.parse" @@ -10,8 +9,8 @@ pattern = ... import unpack from util options = { - in_dir: "tests/inputs", - out_dir: "tests/outputs", + in_dir: "spec/inputs", + out_dir: "spec/outputs", input_pattern: "(.*)%.moon$", output_ext: ".lua" @@ -73,6 +72,7 @@ diff_str = (expected, got) -> string_assert = (expected, got) -> if expected != got diff = diff_str expected, got + error "string equality assert failed" if os.getenv "HIDE_DIFF" error "string equality assert failed:\n" .. diff input_fname = (base) -> diff --git a/spec/loops_spec.moon b/spec/loops_spec.moon new file mode 100644 index 0000000..68b5f97 --- /dev/null +++ b/spec/loops_spec.moon @@ -0,0 +1,9 @@ + +describe "loops", -> + it "should continue", -> + input = {1,2,3,4,5,6} + output = for x in *input + continue if x % 2 == 1 + x + + assert.same output, { 2,4,6 } diff --git a/spec/moon_spec.moon b/spec/moon_spec.moon new file mode 100644 index 0000000..145b5ee --- /dev/null +++ b/spec/moon_spec.moon @@ -0,0 +1,116 @@ +-- test moon library + +moon = require "moon" + +describe "moon", -> + it "should determine correct type", -> + class Test + + things = { + Test, Test!, 1, true, nil, "hello" + } + + types = [moon.type t for t in *things] + assert.same types, { Test, Test, "number", "boolean", "nil", "string" } + + it "should get upvalue", -> + fn = do + hello = "world" + -> hello + + assert.same moon.debug.upvalue(fn, "hello"), "world" + + it "should set upvalue", -> + fn = do + hello = "world" + -> hello + + moon.debug.upvalue fn, "hello", "foobar" + assert.same fn!, "foobar" + + it "should run with scope", -> + scope = hello: -> + spy.on scope, "hello" + moon.run_with_scope (-> hello!), scope + + assert.spy(scope.hello).was.called! + + + it "should have access to old environment", -> + scope = {} + res = moon.run_with_scope (-> math), scope + + assert.same res, math + + it "should created bound proxy", -> + class Hello + state: 10 + method: (val) => "the state: #{@state}, the val: #{val}" + + hello = Hello! + bound = moon.bind_methods hello + + assert.same bound.method("xxx"), "the state: 10, the val: xxx" + + it "should create defaulted table", -> + fib = moon.defaultbl {[0]: 0, [1]: 1}, (i) => self[i - 1] + self[i - 2] + fib[7] + + assert.same fib, { [0]: 0, 1, 1, 2, 3, 5, 8, 13 } + + it "should extend", -> + t1 = { hello: "world's", cool: "shortest" } + t2 = { cool: "boots", cowboy: "hat" } + + out = moon.extend t1, t2 + + assert.same { out.hello, out.cool, out.cowboy }, { "world's", "shortest", "hat"} + + it "should make a copy", -> + x = { "hello", yeah: "man" } + y = moon.copy x + + x[1] = "yikes" + x.yeah = "woman" + + assert.same y, { "hello", yeah: "man" } + + + it "should mixin", -> + class TestModule + new: (@var) => + show_var: => "var is: #{@var}" + + class Second + new: => + moon.mixin self, TestModule, "hi" + + obj = Second! + + assert.same obj\show_var!, "var is: hi" + + it "should mixin object", -> + class First + val: 10 + get_val: => "the val: #{@val}" + + class Second + val: 20 + new: => + moon.mixin_object @, First!, { "get_val" } + + obj = Second! + assert.same obj\get_val!, "the val: 10" + + it "should mixin table", -> + a = { hello: "world", cat: "dog" } + b = { cat: "mouse", foo: "bar" } + moon.mixin_table a, b + + assert.same a, { hello: "world", cat: "mouse", foo: "bar"} + + it "should fold", -> + numbers = {4,3,5,6,7,2,3} + sum = moon.fold numbers, (a,b) -> a + b + + assert.same sum, 30 diff --git a/tests/outputs/assign.lua b/spec/outputs/assign.lua similarity index 100% rename from tests/outputs/assign.lua rename to spec/outputs/assign.lua diff --git a/tests/outputs/bubbling.lua b/spec/outputs/bubbling.lua similarity index 63% rename from tests/outputs/bubbling.lua rename to spec/outputs/bubbling.lua index 651b0e2..247ff1c 100644 --- a/tests/outputs/bubbling.lua +++ b/spec/outputs/bubbling.lua @@ -6,19 +6,6 @@ f = function(...) end local dont_bubble dont_bubble = function() - return (function() - local _accum_0 = { } - local _len_0 = 1 - for x in (function(...) - return print(...) - end)("hello") do - _accum_0[_len_0] = x - _len_0 = _len_0 + 1 - end - return _accum_0 - end)() -end -local k = (function() local _accum_0 = { } local _len_0 = 1 for x in (function(...) @@ -28,8 +15,21 @@ local k = (function() _len_0 = _len_0 + 1 end return _accum_0 -end)() -local j = (function() +end +local k +do + local _accum_0 = { } + local _len_0 = 1 + for x in (function(...) + return print(...) + end)("hello") do + _accum_0[_len_0] = x + _len_0 = _len_0 + 1 + end + k = _accum_0 +end +local j +do local _accum_0 = { } local _len_0 = 1 for i = 1, 10 do @@ -38,27 +38,26 @@ local j = (function() end _len_0 = _len_0 + 1 end - return _accum_0 -end)() + j = _accum_0 +end local m m = function(...) - return (function(...) - local _accum_0 = { } - local _len_0 = 1 - local _list_0 = { - ... - } - for _index_0 = 1, #_list_0 do - local x = _list_0[_index_0] - if f(...) > 4 then - _accum_0[_len_0] = x - _len_0 = _len_0 + 1 - end + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local x = _list_0[_index_0] + if f(...) > 4 then + _accum_0[_len_0] = x + _len_0 = _len_0 + 1 end - return _accum_0 - end)(...) + end + return _accum_0 end -local x = (function(...) +local x +do local _accum_0 = { } local _len_0 = 1 local _list_0 = { @@ -69,9 +68,10 @@ local x = (function(...) _accum_0[_len_0] = i _len_0 = _len_0 + 1 end - return _accum_0 -end)(...) -local y = (function(...) + x = _accum_0 +end +local y +do local _accum_0 = { } local _len_0 = 1 local _list_0 = { @@ -82,9 +82,10 @@ local y = (function(...) _accum_0[_len_0] = x _len_0 = _len_0 + 1 end - return _accum_0 -end)(...) -local z = (function(...) + y = _accum_0 +end +local z +do local _accum_0 = { } local _len_0 = 1 for x in hallo do @@ -93,18 +94,20 @@ local z = (function(...) _len_0 = _len_0 + 1 end end - return _accum_0 -end)(...) -local a = (function(...) + z = _accum_0 +end +local a +do local _accum_0 = { } local _len_0 = 1 for i = 1, 10 do _accum_0[_len_0] = ... _len_0 = _len_0 + 1 end - return _accum_0 -end)(...) -local b = (function() + a = _accum_0 +end +local b +do local _accum_0 = { } local _len_0 = 1 for i = 1, 10 do @@ -113,5 +116,5 @@ local b = (function() end _len_0 = _len_0 + 1 end - return _accum_0 -end)() \ No newline at end of file + b = _accum_0 +end \ No newline at end of file diff --git a/tests/outputs/class.lua b/spec/outputs/class.lua similarity index 55% rename from tests/outputs/class.lua rename to spec/outputs/class.lua index e65b191..1e3a301 100644 --- a/tests/outputs/class.lua +++ b/spec/outputs/class.lua @@ -1,6 +1,5 @@ local Hello do - local _parent_0 = nil local _base_0 = { hello = function(self) return print(self.test, self.world) @@ -10,26 +9,15 @@ do end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ __init = function(self, test, world) self.test, self.world = test, world return print("creating object..") end, __base = _base_0, - __name = "Hello", - __parent = _parent_0 + __name = "Hello" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -37,9 +25,6 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Hello = _class_0 end local x = Hello(1, 2) @@ -47,34 +32,18 @@ x:hello() print(x) local Simple do - local _parent_0 = nil local _base_0 = { cool = function(self) return print("cool") end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "Simple", - __parent = _parent_0 + __name = "Simple" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -82,9 +51,6 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Simple = _class_0 end local Yikes @@ -92,9 +58,7 @@ do local _parent_0 = Simple local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end + setmetatable(_base_0, _parent_0.__base) local _class_0 = setmetatable({ __init = function(self) return print("created hello") @@ -105,7 +69,7 @@ do }, { __index = function(cls, name) local val = rawget(_base_0, name) - if val == nil and _parent_0 then + if val == nil then return _parent_0[name] else return val @@ -118,7 +82,7 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then + if _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end Yikes = _class_0 @@ -127,32 +91,20 @@ x = Yikes() x:cool() local Hi do - local _parent_0 = nil local _base_0 = { cool = function(self, num) return print("num", num) end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ __init = function(self, arg) return print("init arg", arg) end, __base = _base_0, - __name = "Hi", - __parent = _parent_0 + __name = "Hi" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -160,9 +112,6 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Hi = _class_0 end do @@ -173,9 +122,7 @@ do end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end + setmetatable(_base_0, _parent_0.__base) local _class_0 = setmetatable({ __init = function(self) return _parent_0.__init(self, "man") @@ -186,7 +133,7 @@ do }, { __index = function(cls, name) local val = rawget(_base_0, name) - if val == nil and _parent_0 then + if val == nil then return _parent_0[name] else return val @@ -199,7 +146,7 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then + if _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end Simple = _class_0 @@ -209,32 +156,16 @@ x:cool() print(x.__class == Simple) local Okay do - local _parent_0 = nil local _base_0 = { something = 20323 } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "Okay", - __parent = _parent_0 + __name = "Okay" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -242,9 +173,6 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Okay = _class_0 end local Biggie @@ -258,14 +186,10 @@ do end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end + setmetatable(_base_0, _parent_0.__base) local _class_0 = setmetatable({ __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end + return _parent_0.__init(self, ...) end, __base = _base_0, __name = "Biggie", @@ -273,7 +197,7 @@ do }, { __index = function(cls, name) local val = rawget(_base_0, name) - if val == nil and _parent_0 then + if val == nil then return _parent_0[name] else return val @@ -286,41 +210,25 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then + if _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end Biggie = _class_0 end local Yeah do - local _parent_0 = nil local _base_0 = { okay = function(self) return _parent_0.something(self, 1, 2, 3, 4) end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "Yeah", - __parent = _parent_0 + __name = "Yeah" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -328,41 +236,22 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Yeah = _class_0 end local What do - local _parent_0 = nil local _base_0 = { something = function(self) return print("val:", self.val) end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "What", - __parent = _parent_0 + __name = "What" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -370,9 +259,6 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end What = _class_0 end do @@ -390,14 +276,10 @@ do end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end + setmetatable(_base_0, _parent_0.__base) local _class_0 = setmetatable({ __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end + return _parent_0.__init(self, ...) end, __base = _base_0, __name = "Hello", @@ -405,7 +287,7 @@ do }, { __index = function(cls, name) local val = rawget(_base_0, name) - if val == nil and _parent_0 then + if val == nil then return _parent_0[name] else return val @@ -418,7 +300,7 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then + if _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end Hello = _class_0 @@ -431,7 +313,6 @@ do end local CoolSuper do - local _parent_0 = nil local _base_0 = { hi = function(self) _parent_0.hi(self, 1, 2, 3, 4)(1, 2, 3, 4) @@ -444,27 +325,12 @@ do end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "CoolSuper", - __parent = _parent_0 + __name = "CoolSuper" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -472,9 +338,6 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end CoolSuper = _class_0 end x = self.hello @@ -488,33 +351,17 @@ xx = function(hello, world, cool) end local ClassMan do - local _parent_0 = nil local _base_0 = { blue = function(self) end, green = function(self) end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "ClassMan", - __parent = _parent_0 + __name = "ClassMan" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -527,9 +374,6 @@ do self.hello = 3434 self.world = 23423 self.red = function(self) end - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end ClassMan = _class_0 end x = self @@ -543,30 +387,14 @@ local _ = hello[self].world local Whacko do local hello - local _parent_0 = nil local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "Whacko", - __parent = _parent_0 + __name = "Whacko" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -584,9 +412,6 @@ do if something then print("yeah") end - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Whacko = _class_0 end print("hello") @@ -594,30 +419,14 @@ local yyy yyy = function() local Cool do - local _parent_0 = nil local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "Cool", - __parent = _parent_0 + __name = "Cool" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -627,38 +436,19 @@ yyy = function() _base_0.__class = _class_0 local self = _class_0 _ = nil - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Cool = _class_0 return _class_0 end end do - local _parent_0 = nil local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "D", - __parent = _parent_0 + __name = "D" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -668,36 +458,17 @@ do _base_0.__class = _class_0 local self = _class_0 _ = nil - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end a.b.c.D = _class_0 end do - local _parent_0 = nil local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "hello", - __parent = _parent_0 + __name = "hello" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -707,23 +478,16 @@ do _base_0.__class = _class_0 local self = _class_0 _ = nil - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end a.b["hello"] = _class_0 end do local _parent_0 = Hello.World local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end + setmetatable(_base_0, _parent_0.__base) local _class_0 = setmetatable({ __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end + return _parent_0.__init(self, ...) end, __base = _base_0, __name = "Something", @@ -731,7 +495,7 @@ do }, { __index = function(cls, name) local val = rawget(_base_0, name) - if val == nil and _parent_0 then + if val == nil then return _parent_0[name] else return val @@ -746,7 +510,7 @@ do _base_0.__class = _class_0 local self = _class_0 _ = nil - if _parent_0 and _parent_0.__inherited then + if _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end (function() @@ -755,30 +519,14 @@ do end local a do - local _parent_0 = nil local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "a", - __parent = _parent_0 + __name = "a" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -786,38 +534,19 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end a = _class_0 end local b local Something do - local _parent_0 = nil local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "Something", - __parent = _parent_0 + __name = "Something" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -825,9 +554,6 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Something = _class_0 b = _class_0 end @@ -836,14 +562,10 @@ do local _parent_0 = Hello local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end + setmetatable(_base_0, _parent_0.__base) local _class_0 = setmetatable({ __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end + return _parent_0.__init(self, ...) end, __base = _base_0, __name = "Something", @@ -851,7 +573,7 @@ do }, { __index = function(cls, name) local val = rawget(_base_0, name) - if val == nil and _parent_0 then + if val == nil then return _parent_0[name] else return val @@ -864,7 +586,7 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then + if _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end Something = _class_0 @@ -875,14 +597,10 @@ do local _parent_0 = World local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end + setmetatable(_base_0, _parent_0.__base) local _class_0 = setmetatable({ __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end + return _parent_0.__init(self, ...) end, __base = _base_0, __name = "d", @@ -890,7 +608,7 @@ do }, { __index = function(cls, name) local val = rawget(_base_0, name) - if val == nil and _parent_0 then + if val == nil then return _parent_0[name] else return val @@ -903,7 +621,7 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then + if _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end d = _class_0 @@ -911,30 +629,14 @@ end print(((function() local WhatsUp do - local _parent_0 = nil local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "WhatsUp", - __parent = _parent_0 + __name = "WhatsUp" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -942,38 +644,19 @@ print(((function() end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end WhatsUp = _class_0 return _class_0 end end)()).__name) do - local _parent_0 = nil local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "Something", - __parent = _parent_0 + __name = "Something" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -983,35 +666,20 @@ do _base_0.__class = _class_0 local self = _class_0 _ = nil - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Something = _class_0 end do local val, insert - local _parent_0 = nil local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ __init = function(self) return print(insert, val) end, __base = _base_0, - __name = "Something", - __parent = _parent_0 + __name = "Something" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -1025,32 +693,17 @@ do local _obj_0 = table insert = _obj_0.insert end - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Something = _class_0 end do - local _parent_0 = nil local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ __init = hi, __base = _base_0, - __name = "X", - __parent = _parent_0 + __name = "X" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -1058,9 +711,6 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end X = _class_0 end return nil \ No newline at end of file diff --git a/tests/outputs/comprehension.lua b/spec/outputs/comprehension.lua similarity index 78% rename from tests/outputs/comprehension.lua rename to spec/outputs/comprehension.lua index 4ac5530..7512c5f 100644 --- a/tests/outputs/comprehension.lua +++ b/spec/outputs/comprehension.lua @@ -6,35 +6,38 @@ local items = { 5, 6 } -local out = (function() +local out +do local _tbl_0 = { } for k in items do _tbl_0[k] = k * 2 end - return _tbl_0 -end)() + out = _tbl_0 +end local x = { hello = "world", okay = 2323 } -local copy = (function() +local copy +do local _tbl_0 = { } for k, v in pairs(x) do if k ~= "okay" then _tbl_0[k] = v end end - return _tbl_0 -end)() -local _ = (function() + copy = _tbl_0 +end +local _ +do local _tbl_0 = { } for x in yes do local _key_0, _val_0 = unpack(x) _tbl_0[_key_0] = _val_0 end - return _tbl_0 -end)() -_ = (function() + _ = _tbl_0 +end +do local _tbl_0 = { } local _list_0 = yes for _index_0 = 1, #_list_0 do @@ -42,17 +45,17 @@ _ = (function() local _key_0, _val_0 = unpack(x) _tbl_0[_key_0] = _val_0 end - return _tbl_0 -end)() -_ = (function() + _ = _tbl_0 +end +do local _tbl_0 = { } for x in yes do local _key_0, _val_0 = xxxx _tbl_0[_key_0] = _val_0 end - return _tbl_0 -end)() -_ = (function() + _ = _tbl_0 +end +do local _tbl_0 = { } local _list_0 = { { @@ -77,18 +80,20 @@ _ = (function() end)()) _tbl_0[_key_0] = _val_0 end - return _tbl_0 -end)() -local n1 = (function() + _ = _tbl_0 +end +local n1 +do local _accum_0 = { } local _len_0 = 1 for i = 1, 10 do _accum_0[_len_0] = i _len_0 = _len_0 + 1 end - return _accum_0 -end)() -local n2 = (function() + n1 = _accum_0 +end +local n2 +do local _accum_0 = { } local _len_0 = 1 for i = 1, 10 do @@ -97,9 +102,10 @@ local n2 = (function() _len_0 = _len_0 + 1 end end - return _accum_0 -end)() -local aa = (function() + n2 = _accum_0 +end +local aa +do local _accum_0 = { } local _len_0 = 1 for x = 1, 10 do @@ -111,9 +117,10 @@ local aa = (function() _len_0 = _len_0 + 1 end end - return _accum_0 -end)() -local bb = (function() + aa = _accum_0 +end +local bb +do local _accum_0 = { } local _len_0 = 1 for thing in y do @@ -122,9 +129,10 @@ local bb = (function() _len_0 = _len_0 + 1 end end - return _accum_0 -end)() -local cc = (function() + bb = _accum_0 +end +local cc +do local _accum_0 = { } local _len_0 = 1 for i = 1, 10 do @@ -133,9 +141,10 @@ local cc = (function() _len_0 = _len_0 + 1 end end - return _accum_0 -end)() -local dd = (function() + cc = _accum_0 +end +local dd +do local _accum_0 = { } local _len_0 = 1 for i = 1, 10 do @@ -150,13 +159,13 @@ local dd = (function() end end end - return _accum_0 -end)() -_ = (function() + dd = _accum_0 +end +do local _tbl_0 = { } for i = 1, 10 do _tbl_0["hello"] = "world" end - return _tbl_0 -end)() + _ = _tbl_0 +end return nil \ No newline at end of file diff --git a/tests/outputs/cond.lua b/spec/outputs/cond.lua similarity index 100% rename from tests/outputs/cond.lua rename to spec/outputs/cond.lua diff --git a/spec/outputs/destructure.lua b/spec/outputs/destructure.lua new file mode 100644 index 0000000..2831543 --- /dev/null +++ b/spec/outputs/destructure.lua @@ -0,0 +1,186 @@ +do + local a, b + do + local _obj_0 = hello + a, b = _obj_0[1], _obj_0[2] + end + local c + do + local _obj_0 = hello + a, b, c = _obj_0[1][1], _obj_0[2], _obj_0[3][1] + end + local hello, world + do + local _obj_0 = value + hello, world = _obj_0.hello, _obj_0.world + end +end +do + local no, thing + do + local _obj_0 = world + no, thing = _obj_0.yes, _obj_0[1] + end + local a, b, c, d + do + local _obj_0 = yeah + a, b, c, d = _obj_0.a, _obj_0.b, _obj_0.c, _obj_0.d + end + do + local _obj_0 = one + a = _obj_0[1] + end + local _ = two + do + local _obj_0 = one + b = _obj_0[1] + end + c = nil + do + local _obj_0 = one + d = _obj_0[1] + end + local e = two + local x = one + local y + do + local _obj_0 = two + y = _obj_0[1] + end + local xx, yy = 1, 2 + do + local _obj_0 = { + xx, + yy + } + yy, xx = _obj_0[1], _obj_0[2] + end + local f, g + do + local _obj_0 = tbl + a, b, c, d, e, f, g = _obj_0[1], _obj_0.b, _obj_0[2], _obj_0.d, _obj_0[3], _obj_0.f, _obj_0[4] + end +end +do + local futurists = { + sculptor = "Umberto Boccioni", + painter = "Vladimir Burliuk", + poet = { + name = "F.T. Marinetti", + address = { + "Via Roma 42R", + "Bellagio, Italy 22021" + } + } + } + local name, street, city + name, street, city = futurists.poet.name, futurists.poet.address[1], futurists.poet.address[2] +end +do + do + local _obj_0 = x + self.world = _obj_0[1] + end + do + local _obj_0 = x + a.b, c.y, func().z = _obj_0[1], _obj_0[2], _obj_0[3] + end + do + local _obj_0 = x + self.world = _obj_0.world + end +end +do + local thing = { + { + 1, + 2 + }, + { + 3, + 4 + } + } + for _index_0 = 1, #thing do + local _des_0 = thing[_index_0] + local x, y + x, y = _des_0[1], _des_0[2] + print(x, y) + end +end +do + do + local _with_0 = thing + local a, b + a, b = _with_0[1], _with_0[2] + print(a, b) + end +end +do + local thing = nil + do + local _des_0 = thing + if _des_0 then + local a + a = _des_0[1] + print(a) + else + print("nothing") + end + end + local thang = { + 1, + 2 + } + do + local _des_0 = thang + if _des_0 then + local a, b + a, b = _des_0[1], _des_0[2] + print(a, b) + end + end + do + local _des_0 = thing + if _des_0 then + local a, b + a, b = _des_0[1], _des_0[2] + print(a, b) + else + do + local _des_1 = thang + if _des_1 then + local c, d + c, d = _des_1[1], _des_1[2] + print(c, d) + else + print("NO") + end + end + end + end +end +do + local z = "yeah" + local a, b, c + a, b, c = z[1], z[2], z[3] +end +do + local a, b, c + do + local _obj_0 = z + a, b, c = _obj_0[1], _obj_0[2], _obj_0[3] + end +end +local _ +_ = function(z) + local a, b, c + a, b, c = z[1], z[2], z[3] +end +do + local z = "oo" + return function(k) + local a, b, c + a, b, c = z[1], z[2], z[3] + end +end \ No newline at end of file diff --git a/tests/outputs/do.lua b/spec/outputs/do.lua similarity index 100% rename from tests/outputs/do.lua rename to spec/outputs/do.lua diff --git a/tests/outputs/export.lua b/spec/outputs/export.lua similarity index 63% rename from tests/outputs/export.lua rename to spec/outputs/export.lua index 44ac1e8..72ebade 100644 --- a/tests/outputs/export.lua +++ b/spec/outputs/export.lua @@ -4,32 +4,16 @@ do end do do - local _parent_0 = nil local _base_0 = { umm = "cool" } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "Something", - __parent = _parent_0 + __name = "Something" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -37,9 +21,6 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Something = _class_0 end end @@ -76,7 +57,6 @@ do local hallo = 3434 end do - local _with_0 = tmp local j = 2000 end end diff --git a/tests/outputs/funcs.lua b/spec/outputs/funcs.lua similarity index 100% rename from tests/outputs/funcs.lua rename to spec/outputs/funcs.lua diff --git a/spec/outputs/import.lua b/spec/outputs/import.lua new file mode 100644 index 0000000..f7467f4 --- /dev/null +++ b/spec/outputs/import.lua @@ -0,0 +1,83 @@ +local hello +do + local _obj_0 = yeah + hello = _obj_0.hello +end +local world +do + local _obj_0 = table["cool"] + hello, world = _obj_0.hello, _obj_0.world +end +local a, b, c +do + local _obj_0 = items + a, b, c = _obj_0.a, (function() + local _base_0 = _obj_0 + local _fn_0 = _base_0.b + return function(...) + return _fn_0(_base_0, ...) + end + end)(), _obj_0.c +end +local master, ghost +do + local _obj_0 = find("mytable") + master, ghost = _obj_0.master, (function() + local _base_0 = _obj_0 + local _fn_0 = _base_0.ghost + return function(...) + return _fn_0(_base_0, ...) + end + end)() +end +local yumm +a, yumm = 3434, "hello" +local _table_0 = 232 +local something +do + local _obj_0 = a(table) + something = _obj_0.something +end +if indent then + local okay, well + do + local _obj_0 = tables[100] + okay, well = _obj_0.okay, (function() + local _base_0 = _obj_0 + local _fn_0 = _base_0.well + return function(...) + return _fn_0(_base_0, ...) + end + end)() + end +end +do + do + local _obj_0 = z + a, b, c = _obj_0.a, _obj_0.b, _obj_0.c + end +end +do + do + local _obj_0 = z + a, b, c = _obj_0.a, _obj_0.b, _obj_0.c + end +end +do + do + local _obj_0 = z + a, b, c = _obj_0.a, _obj_0.b, _obj_0.c + end +end +do + do + local _obj_0 = z + a, b, c = _obj_0.a, _obj_0.b, _obj_0.c + end +end +do + do + local _obj_0 = z + a, b, c = _obj_0.a, _obj_0.b, _obj_0.c + end +end \ No newline at end of file diff --git a/tests/outputs/lists.lua b/spec/outputs/lists.lua similarity index 57% rename from tests/outputs/lists.lua rename to spec/outputs/lists.lua index b6f1b29..81aaa5b 100644 --- a/tests/outputs/lists.lua +++ b/spec/outputs/lists.lua @@ -1,4 +1,5 @@ -local hi = (function() +local hi +do local _accum_0 = { } local _len_0 = 1 for _, x in ipairs({ @@ -10,8 +11,8 @@ local hi = (function() _accum_0[_len_0] = x * 2 _len_0 = _len_0 + 1 end - return _accum_0 -end)() + hi = _accum_0 +end local items = { 1, 2, @@ -20,21 +21,13 @@ local items = { 5, 6 } -local mm = (function() - local _accum_0 = { } - local _len_0 = 1 - for self.x in ipairs(items) do - _accum_0[_len_0] = self.x - _len_0 = _len_0 + 1 - end - return _accum_0 -end)() for z in ipairs(items) do if z > 4 then local _ = z end end -local rad = (function() +local rad +do local _accum_0 = { } local _len_0 = 1 for a in ipairs({ @@ -52,8 +45,8 @@ local rad = (function() _len_0 = _len_0 + 1 end end - return _accum_0 -end)() + rad = _accum_0 +end for z in items do for j in list do if z > 4 then @@ -101,7 +94,8 @@ dump((function() end return _accum_0 end)()) -local things = (function() +local things +do local _accum_0 = { } local _len_0 = 1 for x in range(10) do @@ -114,8 +108,8 @@ local things = (function() end end end - return _accum_0 -end)() + things = _accum_0 +end for x in ipairs({ 1, 2, @@ -137,15 +131,16 @@ end for x in x do local _ = x end -local x = (function() +local x +do local _accum_0 = { } local _len_0 = 1 for x in x do _accum_0[_len_0] = x _len_0 = _len_0 + 1 end - return _accum_0 -end)() + x = _accum_0 +end for x in ipairs({ 1, 2, @@ -161,53 +156,50 @@ for x in ipairs({ end end end -local double = (function() +local double +do local _accum_0 = { } local _len_0 = 1 - local _list_0 = items - for _index_0 = 1, #_list_0 do - x = _list_0[_index_0] + for _index_0 = 1, #items do + x = items[_index_0] _accum_0[_len_0] = x * 2 _len_0 = _len_0 + 1 end - return _accum_0 -end)() -local _list_0 = double -for _index_0 = 1, #_list_0 do - x = _list_0[_index_0] + double = _accum_0 +end +for _index_0 = 1, #double do + x = double[_index_0] print(x) end -local cut = (function() +local cut +do local _accum_0 = { } local _len_0 = 1 - local _list_1 = items - for _index_0 = 1, #_list_1 do - x = _list_1[_index_0] + for _index_0 = 1, #items do + x = items[_index_0] if x > 3 then _accum_0[_len_0] = x _len_0 = _len_0 + 1 end end - return _accum_0 -end)() -local hello = (function() + cut = _accum_0 +end +local hello +do local _accum_0 = { } local _len_0 = 1 - local _list_1 = items - for _index_0 = 1, #_list_1 do - x = _list_1[_index_0] - local _list_2 = items - for _index_1 = 1, #_list_2 do - local y = _list_2[_index_1] + for _index_0 = 1, #items do + x = items[_index_0] + for _index_1 = 1, #items do + local y = items[_index_1] _accum_0[_len_0] = x + y _len_0 = _len_0 + 1 end end - return _accum_0 -end)() -local _list_1 = hello -for _index_0 = 1, #_list_1 do - local z = _list_1[_index_0] + hello = _accum_0 +end +for _index_0 = 1, #hello do + local z = hello[_index_0] print(z) end x = { @@ -219,83 +211,70 @@ x = { 6, 7 } -local _list_2 = x local _max_0 = -5 -for _index_0 = 2, _max_0 < 0 and #_list_2 + _max_0 or _max_0, 2 do - local y = _list_2[_index_0] +for _index_0 = 2, _max_0 < 0 and #x + _max_0 or _max_0, 2 do + local y = x[_index_0] print(y) end -local _list_3 = x local _max_1 = 3 -for _index_0 = 1, _max_1 < 0 and #_list_3 + _max_1 or _max_1 do - local y = _list_3[_index_0] +for _index_0 = 1, _max_1 < 0 and #x + _max_1 or _max_1 do + local y = x[_index_0] print(y) end -local _list_4 = x -for _index_0 = 2, #_list_4 do - local y = _list_4[_index_0] +for _index_0 = 2, #x do + local y = x[_index_0] print(y) end -local _list_5 = x -for _index_0 = 1, #_list_5, 2 do - local y = _list_5[_index_0] +for _index_0 = 1, #x, 2 do + local y = x[_index_0] print(y) end -local _list_6 = x -for _index_0 = 2, #_list_6, 2 do - local y = _list_6[_index_0] +for _index_0 = 2, #x, 2 do + local y = x[_index_0] print(y) end local a, b, c = 1, 5, 2 -local _list_7 = x local _max_2 = b -for _index_0 = a, _max_2 < 0 and #_list_7 + _max_2 or _max_2, c do - local y = _list_7[_index_0] +for _index_0 = a, _max_2 < 0 and #x + _max_2 or _max_2, c do + local y = x[_index_0] print(y) end local normal normal = function(hello) - return (function() - local _accum_0 = { } - local _len_0 = 1 - for x in yeah do - _accum_0[_len_0] = x - _len_0 = _len_0 + 1 - end - return _accum_0 - end)() + local _accum_0 = { } + local _len_0 = 1 + for x in yeah do + _accum_0[_len_0] = x + _len_0 = _len_0 + 1 + end + return _accum_0 end local test = x(1, 2, 3, 4, 5) -local _list_8 = test -for _index_0 = 1, #_list_8 do - local thing = _list_8[_index_0] +for _index_0 = 1, #test do + local thing = test[_index_0] print(thing) end local _ _ = function() - local _list_9 = rows - for _index_0 = 1, #_list_9 do - local row = _list_9[_index_0] + local _list_0 = rows + for _index_0 = 1, #_list_0 do + local row = _list_0[_index_0] a = b end end _ = function() - local _list_9 = things - for _index_0 = 1, #_list_9 do - x = _list_9[_index_0] + for _index_0 = 1, #things do + x = things[_index_0] _ = x end end return function() - return (function() - local _accum_0 = { } - local _len_0 = 1 - local _list_9 = things - for _index_0 = 1, #_list_9 do - x = _list_9[_index_0] - _accum_0[_len_0] = x - _len_0 = _len_0 + 1 - end - return _accum_0 - end)() + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #things do + x = things[_index_0] + _accum_0[_len_0] = x + _len_0 = _len_0 + 1 + end + return _accum_0 end \ No newline at end of file diff --git a/tests/outputs/literals.lua b/spec/outputs/literals.lua similarity index 100% rename from tests/outputs/literals.lua rename to spec/outputs/literals.lua diff --git a/tests/outputs/local.lua b/spec/outputs/local.lua similarity index 100% rename from tests/outputs/local.lua rename to spec/outputs/local.lua diff --git a/tests/outputs/loops.lua b/spec/outputs/loops.lua similarity index 88% rename from tests/outputs/loops.lua rename to spec/outputs/loops.lua index 87824e8..dcba0bc 100644 --- a/tests/outputs/loops.lua +++ b/spec/outputs/loops.lua @@ -48,37 +48,37 @@ local hello = { 4, 5 } -x = (function() +do local _accum_0 = { } local _len_0 = 1 - local _list_1 = hello - for _index_0 = 1, #_list_1 do - local y = _list_1[_index_0] + for _index_0 = 1, #hello do + local y = hello[_index_0] if y % 2 == 0 then _accum_0[_len_0] = y end _len_0 = _len_0 + 1 end - return _accum_0 -end)() + x = _accum_0 +end x = function() - local _list_1 = hello - for _index_0 = 1, #_list_1 do - x = _list_1[_index_0] + for _index_0 = 1, #hello do + x = hello[_index_0] local _ = y end end -local t = (function() +local t +do local _accum_0 = { } local _len_0 = 1 for i = 10, 20 do _accum_0[_len_0] = i * 2 _len_0 = _len_0 + 1 end - return _accum_0 -end)() + t = _accum_0 +end local hmm = 0 -local y = (function() +local y +do local _accum_0 = { } local _len_0 = 1 for j = 3, 30, 8 do @@ -87,8 +87,8 @@ local y = (function() _accum_0[_len_0] = _value_0 _len_0 = _len_0 + 1 end - return _accum_0 -end)() + y = _accum_0 +end local _ _ = function() for k = 10, 40 do @@ -118,7 +118,7 @@ while also do _ = "okay" end local i = 0 -x = (function() +do local _accum_0 = { } local _len_0 = 1 while i < 10 do @@ -127,9 +127,9 @@ x = (function() _accum_0[_len_0] = _value_0 _len_0 = _len_0 + 1 end - return _accum_0 -end)() -x = (function() + x = _accum_0 +end +do local _accum_0 = { } local _len_0 = 1 local _list_1 = 3 @@ -140,9 +140,9 @@ x = (function() _accum_0[_len_0] = _value_0 _len_0 = _len_0 + 1 end - return _accum_0 -end)() -x = (function() + x = _accum_0 +end +do local _accum_0 = { } local _len_0 = 1 for x = 1, 2 do @@ -151,8 +151,8 @@ x = (function() _accum_0[_len_0] = _value_0 _len_0 = _len_0 + 1 end - return _accum_0 -end)() + x = _accum_0 +end while true do local _continue_0 = false repeat @@ -185,7 +185,8 @@ for x = 1, 10 do break end end -local list = (function() +local list +do local _accum_0 = { } local _len_0 = 1 for x = 1, 10 do @@ -204,8 +205,8 @@ local list = (function() break end end - return _accum_0 -end)() + list = _accum_0 +end local _list_1 = { 1, 2, @@ -258,4 +259,16 @@ for x = 1, 10 do if not _continue_0 then break end +end +do + local xxx = { + 1, + 2, + 3, + 4 + } + for _index_0 = 1, #xxx do + local thing = xxx[_index_0] + print(thing) + end end \ No newline at end of file diff --git a/tests/outputs/string.lua b/spec/outputs/string.lua similarity index 100% rename from tests/outputs/string.lua rename to spec/outputs/string.lua diff --git a/tests/outputs/stub.lua b/spec/outputs/stub.lua similarity index 100% rename from tests/outputs/stub.lua rename to spec/outputs/stub.lua diff --git a/tests/outputs/switch.lua b/spec/outputs/switch.lua similarity index 100% rename from tests/outputs/switch.lua rename to spec/outputs/switch.lua diff --git a/tests/outputs/syntax.lua b/spec/outputs/syntax.lua similarity index 100% rename from tests/outputs/syntax.lua rename to spec/outputs/syntax.lua diff --git a/tests/outputs/tables.lua b/spec/outputs/tables.lua similarity index 100% rename from tests/outputs/tables.lua rename to spec/outputs/tables.lua diff --git a/tests/outputs/using.lua b/spec/outputs/using.lua similarity index 100% rename from tests/outputs/using.lua rename to spec/outputs/using.lua diff --git a/tests/outputs/whitespace.lua b/spec/outputs/whitespace.lua similarity index 100% rename from tests/outputs/whitespace.lua rename to spec/outputs/whitespace.lua diff --git a/spec/outputs/with.lua b/spec/outputs/with.lua new file mode 100644 index 0000000..d1d104a --- /dev/null +++ b/spec/outputs/with.lua @@ -0,0 +1,136 @@ +do + local a + a = function() + do + local _with_0 = something + print(_with_0.hello) + print(hi) + print("world") + return _with_0 + end + end +end +do + do + local _with_0 = leaf + _with_0.world() + _with_0.world(1, 2, 3) + local g = _with_0.what.is.this + _with_0.hi(1, 2, 3) + _with_0:hi(1, 2).world(2323) + _with_0:hi("yeah", "man") + _with_0.world = 200 + end +end +do + local zyzyzy + do + local _with_0 = something + _with_0.set_state("hello world") + zyzyzy = _with_0 + end +end +do + local x = 5 + (function() + do + local _with_0 = Something() + _with_0:write("hello world") + return _with_0 + end + end)() +end +do + local x = { + hello = (function() + do + local _with_0 = yeah + _with_0:okay() + return _with_0 + end + end)() + } +end +do + do + local _with_0 = foo + local _ = _with_0:prop("something").hello + _with_0.prop:send(one) + _with_0.prop:send(one) + end +end +do + do + local _with_0 = a, b + print(_with_0.world) + end + local mod + do + local _M = { } + _M.Thing = "hi" + mod = _M + end + do + local a, b = something, pooh + print(a.world) + end + local x + do + local a, b = 1, 2 + print(a + b) + x = a + end + print((function() + do + local a, b = 1, 2 + print(a + b) + return a + end + end)()) + local p + do + local _with_0 = 1 + hello().x, world().y = _with_0, 2 + print(a + b) + p = _with_0 + end +end +do + local x = "hello" + do + x:upper() + end +end +do + do + local k = "jo" + print(k:upper()) + end +end +do + do + local a, b, c = "", "", "" + print(a:upper()) + end +end +do + local a = "bunk" + do + local b, c + a, b, c = "", "", "" + print(a:upper()) + end +end +do + do + local _with_0 = j + print(_with_0:upper()) + end +end +do + do + local _with_0 = "jo" + k.j = _with_0 + print(_with_0:upper()) + return _with_0 + end +end \ No newline at end of file diff --git a/test.lua b/test.lua deleted file mode 100755 index 0b95e35..0000000 --- a/test.lua +++ /dev/null @@ -1,192 +0,0 @@ -#!/usr/bin/env lua - -require "lfs" -require "alt_getopt" - -local gettime = nil - -pcall(function() - require "socket" - gettime = socket.gettime -end) - -parse = require "moonscript.parse" -compile = require "moonscript.compile" - -local opts, ind = alt_getopt.get_opts(arg, "qd:", { }) - -local argv = {} -for i = ind, #arg do table.insert(argv, arg[i]) end - -local action = table.remove(argv, 1) or "run" - -local diff_tool = opts.d or "diff" -local quiet = opts.q - -local opts = { - in_dir = "tests/inputs", - out_dir = "tests/outputs", - input_pattern = "(.*)%.moon$", - output_ext = ".lua" -} - -local total_time = { - parse = 0, - compile = 0 -} - -local function format_time(sec) - return ("%.3fms"):format(sec*1000) -end - -local function diff(a_fname, b_fname) - return io.popen(diff_tool.." ".. a_fname.." "..b_fname, "r"):read("*a") -end - -local function input_name(name) return opts.in_dir.."/".. name end -local function output_name(name) - return opts.out_dir.."/"..name:match(opts.input_pattern)..opts.output_ext -end - -local function run_file(name, benchmark) - name = input_name(name) - file_str = io.open(name):read("*a") - - local start_parse - if benchmark then start_parse = gettime() end - - local tree, err = parse.string(file_str) - - local parse_time = 0 - if benchmark then parse_time = gettime() - start_parse end - - if not tree then - error("Parse error in "..name.."\n"..err) - end - - local start_compile - if benchmark then start_compile = gettime() end - - local code, err, pos = compile.tree(tree) - if not code then - print() - print(("Failed to compile: %s"):format(name)) - print(compile.format_error(err, pos, file_str)) - os.exit() - end - - -- local success, code = pcall(compile.tree, tree) - -- if not success then - -- error("Compile error in"..name..":\n"..code) - -- end - - if benchmark then - local compile_time = gettime() - start_compile - return code, parse_time, compile_time - end - - return code -end - -local function inputs(pattern) - return coroutine.wrap(function() - for file in lfs.dir(opts.in_dir) do - local body = file:match(opts.input_pattern) - if body then - if not pattern or body:match(pattern) then - coroutine.yield(file) - end - end - end - end) -end - -local actions = { - build = function(pattern) - for file in inputs(pattern) do - local out_fname = output_name(file) - print("Building: ", file, out_fname) - local result = run_file(file) - if result then - io.open(out_fname, "w"):write(result) - end - end - end, - run = function(pattern) - local failed = false - local tests_run, result = 0 - for file in inputs(pattern) do - tests_run = tests_run + 1 - local correct_fname = output_name(file) - result, parse_time, compile_time = run_file(file, gettime) - local handle = io.open(correct_fname) - - if not handle then - print("Test not built yet:", correct_fname) - else - local correct = handle:read("*a") - if result ~= correct then - print("Test", file, "failed") - local tmp_name = os.tmpname() - local tmp = io.open(tmp_name, "w") - tmp:write(result) - tmp:close() - - if not quiet then - print(diff(correct_fname, tmp_name)) - end - os.remove(tmp_name) - -- break - else - if parse_time then - total_time.parse = total_time.parse + parse_time - total_time.compile = total_time.compile + compile_time - - parse_time = format_time(parse_time) - compile_time = format_time(compile_time) - print("Test", file, "passed", "", - ("p: %s, c: %s"):format(parse_time, compile_time)) - else - print("Test", file, "passed") - end - end - end - end - - if gettime then - print"" - print"total:" - print(" parse time", format_time(total_time.parse)) - print(" compile time", format_time(total_time.compile)) - end - - - if tests_run == 0 then - if not pattern then - print("No tests found") - else - print("No tests matching pattern:", pattern) - end - elseif tests_run == 1 then - -- print(result) - end - end, - list = function(pattern) - local count = 0 - for file in inputs(pattern) do - count = count + 1 - print(file) - end - if count > 0 then print("") end - print("Count:", count) - end -} - -local fn = actions[action] -if fn then - fn(unpack(argv)) -else - print("Unknown action:", action) -end - - diff --git a/tests/inputs/destructure.moon b/tests/inputs/destructure.moon deleted file mode 100644 index e011834..0000000 --- a/tests/inputs/destructure.moon +++ /dev/null @@ -1,78 +0,0 @@ - -{a, b} = hello - -{{a}, b, {c}} = hello - -{ :hello, :world } = value - -{ yes: no, thing } = world - -{:a,:b,:c,:d} = yeah - -{a} = one, two -{b}, c = one -{d}, e = one, two - -x, {y} = one, two - -xx, yy = 1, 2 -{yy, xx} = {xx, yy} - -{a, :b, c, :d, e, :f, g} = tbl - ---- - -futurists = - sculptor: "Umberto Boccioni" - painter: "Vladimir Burliuk" - poet: - name: "F.T. Marinetti" - address: { - "Via Roma 42R" - "Bellagio, Italy 22021" - } - -{poet: {:name, address: {street, city}}} = futurists - -print name, street, city - --- - -{ @world } = x -{ a.b, c.y, func!.z } = x - -{ world: @world } = x - --- - -thing = {{1,2}, {3,4}} - -for {x,y} in *thing - print x,y - - --- - -with {a,b} = thing - print a, b - - --- - -thing = nil -if {a} = thing - print a -else - print "nothing" - -thang = {1,2} -if {a,b} = thang - print a,b - -if {a,b} = thing - print a,b -elseif {c,d} = thang - print c,d -else - print "NO" - diff --git a/tests/inputs/with.moon b/tests/inputs/with.moon deleted file mode 100644 index 2f0bcaf..0000000 --- a/tests/inputs/with.moon +++ /dev/null @@ -1,64 +0,0 @@ - -a = -> - with something - print .hello - print hi - print "world" - -with leaf - .world! - .world 1,2,3 - - g = .what.is.this - - .hi 1,2,3 - - \hi(1,2).world 2323 - - \hi "yeah", "man" - .world = 200 - -zyzyzy = with something - .set_state "hello world" - - -x = 5 + with Something! - \write "hello world" - - -x = { - hello: with yeah - \okay! -} - -with foo - \prop"something".hello - .prop\send(one) - .prop\send one - - --- - -with a, b -- b is lost - print .world - -mod = with _M = {} - .Thing = "hi" - --- operate on a only -with a, b = something, pooh - print .world - -x = with a, b = 1, 2 - print a + b - -print with a, b = 1, 2 - print a + b - --- assignment lhs must be evaluated in the order they appear -p = with hello!.x, world!.y = 1, 2 - print a + b - - - - diff --git a/tests/outputs/destructure.lua b/tests/outputs/destructure.lua deleted file mode 100644 index b2da4c3..0000000 --- a/tests/outputs/destructure.lua +++ /dev/null @@ -1,147 +0,0 @@ -local a, b -do - local _obj_0 = hello - a, b = _obj_0[1], _obj_0[2] -end -local c -do - local _obj_0 = hello - a, b, c = _obj_0[1][1], _obj_0[2], _obj_0[3][1] -end -local hello, world -do - local _obj_0 = value - hello, world = _obj_0.hello, _obj_0.world -end -local no, thing -do - local _obj_0 = world - no, thing = _obj_0.yes, _obj_0[1] -end -local d -do - local _obj_0 = yeah - a, b, c, d = _obj_0.a, _obj_0.b, _obj_0.c, _obj_0.d -end -do - local _obj_0 = one - a = _obj_0[1] -end -local _ = two -do - local _obj_0 = one - b = _obj_0[1] -end -c = nil -do - local _obj_0 = one - d = _obj_0[1] -end -local e = two -local x = one -local y -do - local _obj_0 = two - y = _obj_0[1] -end -local xx, yy = 1, 2 -do - local _obj_0 = { - xx, - yy - } - yy, xx = _obj_0[1], _obj_0[2] -end -local f, g -do - local _obj_0 = tbl - a, b, c, d, e, f, g = _obj_0[1], _obj_0.b, _obj_0[2], _obj_0.d, _obj_0[3], _obj_0.f, _obj_0[4] -end -local futurists = { - sculptor = "Umberto Boccioni", - painter = "Vladimir Burliuk", - poet = { - name = "F.T. Marinetti", - address = { - "Via Roma 42R", - "Bellagio, Italy 22021" - } - } -} -local name, street, city -do - local _obj_0 = futurists - name, street, city = _obj_0.poet.name, _obj_0.poet.address[1], _obj_0.poet.address[2] -end -print(name, street, city) -do - local _obj_0 = x - self.world = _obj_0[1] -end -do - local _obj_0 = x - a.b, c.y, func().z = _obj_0[1], _obj_0[2], _obj_0[3] -end -do - local _obj_0 = x - self.world = _obj_0.world -end -thing = { - { - 1, - 2 - }, - { - 3, - 4 - } -} -local _list_0 = thing -for _index_0 = 1, #_list_0 do - local _des_0 = _list_0[_index_0] - x, y = _des_0[1], _des_0[2] - print(x, y) -end -do - local _with_0 = thing - a, b = _with_0[1], _with_0[2] - print(a, b) -end -thing = nil -do - local _des_0 = thing - if _des_0 then - a = _des_0[1] - print(a) - else - print("nothing") - end -end -local thang = { - 1, - 2 -} -do - local _des_0 = thang - if _des_0 then - a, b = _des_0[1], _des_0[2] - print(a, b) - end -end -do - local _des_0 = thing - if _des_0 then - a, b = _des_0[1], _des_0[2] - print(a, b) - else - do - local _des_1 = thang - if _des_1 then - c, d = _des_1[1], _des_1[2] - print(c, d) - else - return print("NO") - end - end - end -end \ No newline at end of file diff --git a/tests/outputs/import.lua b/tests/outputs/import.lua deleted file mode 100644 index 9c3cf0e..0000000 --- a/tests/outputs/import.lua +++ /dev/null @@ -1,45 +0,0 @@ -local hello = yeah.hello -local world -do - local _table_0 = table["cool"] - hello, world = _table_0.hello, _table_0.world -end -local a, b, c = items.a, (function() - local _base_0 = items - local _fn_0 = _base_0.b - return function(...) - return _fn_0(_base_0, ...) - end -end)(), items.c -local master, ghost -do - local _table_0 = find("mytable") - master, ghost = _table_0.master, (function() - local _base_0 = _table_0 - local _fn_0 = _base_0.ghost - return function(...) - return _fn_0(_base_0, ...) - end - end)() -end -local yumm -a, yumm = 3434, "hello" -local _table_0 = 232 -local something -do - local _table_1 = a(table) - something = _table_1.something -end -if indent then - local okay, well - do - local _table_1 = tables[100] - okay, well = _table_1.okay, (function() - local _base_0 = _table_1 - local _fn_0 = _base_0.well - return function(...) - return _fn_0(_base_0, ...) - end - end)() - end -end \ No newline at end of file diff --git a/tests/outputs/with.lua b/tests/outputs/with.lua deleted file mode 100644 index 469e434..0000000 --- a/tests/outputs/with.lua +++ /dev/null @@ -1,88 +0,0 @@ -local a -a = function() - do - local _with_0 = something - print(_with_0.hello) - print(hi) - print("world") - return _with_0 - end -end -do - local _with_0 = leaf - _with_0.world() - _with_0.world(1, 2, 3) - local g = _with_0.what.is.this - _with_0.hi(1, 2, 3) - _with_0:hi(1, 2).world(2323) - _with_0:hi("yeah", "man") - _with_0.world = 200 -end -local zyzyzy -do - local _with_0 = something - _with_0.set_state("hello world") - zyzyzy = _with_0 -end -local x = 5 + (function() - do - local _with_0 = Something() - _with_0:write("hello world") - return _with_0 - end -end)() -x = { - hello = (function() - do - local _with_0 = yeah - _with_0:okay() - return _with_0 - end - end)() -} -do - local _with_0 = foo - local _ = _with_0:prop("something").hello - _with_0.prop:send(one) - _with_0.prop:send(one) -end -do - local _with_0 = a, b - print(_with_0.world) -end -local mod -do - local _with_0 = { } - local _M = _with_0 - _with_0.Thing = "hi" - mod = _with_0 -end -do - local _with_0 = something - local b - a, b = _with_0, pooh - print(_with_0.world) -end -do - local _with_0 = 1 - local b - a, b = _with_0, 2 - print(a + b) - x = _with_0 -end -print((function() - do - local _with_0 = 1 - local b - a, b = _with_0, 2 - print(a + b) - return _with_0 - end -end)()) -local p -do - local _with_0 = 1 - hello().x, world().y = _with_0, 2 - print(a + b) - p = _with_0 -end \ No newline at end of file diff --git a/thoughts b/thoughts new file mode 100644 index 0000000..dfd6b69 --- /dev/null +++ b/thoughts @@ -0,0 +1,31 @@ +# TODO +# +# +# + +- don't reuse _, put a local on it, so we don't keep around trash + +-- swithc X with Func + +- error with stray comma at end of line + +* multiline comments +* table slices (almost) + +* combine for and if line decorators + +* allow return anywhere in block + +-- all function literals have a string that is their function definition + +-- super should work here: + +thing = Thing! +thing.method = -> + super 1,2,3 + +-- goes to + +thing.method = function(self) do + self.__class:method(1,2,3) +end diff --git a/todo b/todo deleted file mode 100644 index ae5ecb9..0000000 --- a/todo +++ /dev/null @@ -1,40 +0,0 @@ -# TODO -# -# -# - --- local * and local ^ - --- seems like running in moon messes up require order - -- don't reuse _, put a local on it, so we don't keep around trash - --- swithc X with Func - -- or= and= - -- error with stray comma at end of line - -* multiline comments -* table slices (almost) - -* combine for and if line decorators - -* export later? nah - - x = 232 - export x - - -* allow return anywhere in block - -* any/every keywords for comprehensions? (what about iterators) - -* let array items in table be defined without {} when indented (no, too similar to arguments) - --- for searching? for returning to accumulator early? -x = for thing in *things - if is_important thing - break thing - -