diff --git a/TODO.md b/TODO.md index b4a4426..bb2296d 100644 --- a/TODO.md +++ b/TODO.md @@ -1,18 +1,6 @@ # Wishlist of features ([X] = complete, [ ] = planned) - code unit count (not to be confused with code points) -code point # |utf8 |utf16| offset -000000 - 00007F | 1 | 1 | 0 -000080 - 0007FF | 2 | 1 | -1 -000800 - 00FFFF | 3 | 1 | -2 -010000 - 10FFFF | 4 | 2 | -2 - -utf8 chart -000000 - 00007F 0xxxxxxx -000080 - 0007FF 110xxxxx 10xxxxxx -000800 - 00FFFF 1110xxxx 10xxxxxx 10xxxxxx -010000 - 10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx My current goal is to work on completions a little bit more. - [ ] Fix crash-files.test2 @@ -86,6 +74,7 @@ Here is my feature wishlist. I don't expect to ever get all of this done, but th - [ ] hide or grey out the `self` in an `a:b` multisym call - [ ] Go-to-references - [x] lexical scope in the same file + - [ ] function names work properly and are counted once - [ ] fields - [ ] go to references of fields when tables are aliased - [ ] global search across other files diff --git a/fennel b/fennel index d184b61..d7f3dd9 100755 --- a/fennel +++ b/fennel @@ -1,19 +1,19 @@ #!/usr/bin/env lua package.preload["fennel.binary"] = package.preload["fennel.binary"] or function(...) local fennel = require("fennel") - local _743_ = require("fennel.utils") - local copy = _743_["copy"] - local warn = _743_["warn"] + local _770_ = require("fennel.utils") + local copy = _770_["copy"] + local warn = _770_["warn"] local function shellout(command) local f = io.popen(command) local stdout = f:read("*all") return (f:close() and stdout) end local function execute(cmd) - local _744_0 = os.execute(cmd) - if (_744_0 == 0) then + local _771_0 = os.execute(cmd) + if (_771_0 == 0) then return true - elseif (_744_0 == true) then + elseif (_771_0 == true) then return true end end @@ -39,13 +39,13 @@ package.preload["fennel.binary"] = package.preload["fennel.binary"] or function( local function module_name(open, rename, used_renames) local require_name = nil do - local _747_0 = rename[open] - if (nil ~= _747_0) then - local renamed = _747_0 + local _774_0 = rename[open] + if (nil ~= _774_0) then + local renamed = _774_0 used_renames[open] = true require_name = renamed else - local _ = _747_0 + local _ = _774_0 require_name = open end end @@ -84,14 +84,14 @@ package.preload["fennel.binary"] = package.preload["fennel.binary"] or function( local dotpath = filename:gsub("^%.%/", ""):gsub("[\\/]", ".") local dotpath_noextension = (dotpath:match("(.+)%.") or dotpath) local fennel_loader = nil - local _751_ + local _778_ do - _751_ = "(do (local bundle_2_ ...) (fn loader_3_ [name_4_] (match (or (. bundle_2_ name_4_) (. bundle_2_ (.. name_4_ \".init\"))) (mod_5_ ? (= \"function\" (type mod_5_))) mod_5_ (mod_5_ ? (= \"string\" (type mod_5_))) (assert (if (= _VERSION \"Lua 5.1\") (loadstring mod_5_ name_4_) (load mod_5_ name_4_))) nil (values nil (: \"\n\\tmodule '%%s' not found in fennel bundle\" \"format\" name_4_)))) (table.insert (or package.loaders package.searchers) 2 loader_3_) ((assert (loader_3_ \"%s\")) ((or unpack table.unpack) arg)))" + _778_ = "(do (local bundle_2_ ...) (fn loader_3_ [name_4_] (match (or (. bundle_2_ name_4_) (. bundle_2_ (.. name_4_ \".init\"))) (mod_5_ ? (= \"function\" (type mod_5_))) mod_5_ (mod_5_ ? (= \"string\" (type mod_5_))) (assert (if (= _VERSION \"Lua 5.1\") (loadstring mod_5_ name_4_) (load mod_5_ name_4_))) nil (values nil (: \"\n\\tmodule '%%s' not found in fennel bundle\" \"format\" name_4_)))) (table.insert (or package.loaders package.searchers) 2 loader_3_) ((assert (loader_3_ \"%s\")) ((or unpack table.unpack) arg)))" end - fennel_loader = _751_:format(dotpath_noextension) + fennel_loader = _778_:format(dotpath_noextension) local lua_loader = fennel["compile-string"](fennel_loader) - local _752_ = options - local rename_modules = _752_["rename-modules"] + local _779_ = options + local rename_modules = _779_["rename-modules"] return c_shim:format(string__3ec_hex_literal(lua_loader), basename_noextension, string__3ec_hex_literal(compile_fennel(filename, options)), dotpath_noextension, native_loader(native, {["rename-modules"] = rename_modules})) end local function write_c(filename, native, options) @@ -104,28 +104,28 @@ package.preload["fennel.binary"] = package.preload["fennel.binary"] or function( local function compile_binary(lua_c_path, executable_name, static_lua, lua_include_dir, native) local cc = (os.getenv("CC") or "cc") local rdynamic, bin_extension, ldl_3f = nil, nil, nil - local _754_ + local _781_ do - local _753_0 = shellout((cc .. " -dumpmachine")) - if (nil ~= _753_0) then - _754_ = _753_0:match("mingw") + local _780_0 = shellout((cc .. " -dumpmachine")) + if (nil ~= _780_0) then + _781_ = _780_0:match("mingw") else - _754_ = _753_0 + _781_ = _780_0 end end - if _754_ then + if _781_ then rdynamic, bin_extension, ldl_3f = "", ".exe", false else rdynamic, bin_extension, ldl_3f = "-rdynamic", "", true end local compile_command = nil - local _757_ + local _784_ if ldl_3f then - _757_ = "-ldl" + _784_ = "-ldl" else - _757_ = "" + _784_ = "" end - compile_command = {cc, "-Os", lua_c_path, table.concat(native, " "), static_lua, rdynamic, "-lm", _757_, "-o", (executable_name .. bin_extension), "-I", lua_include_dir, os.getenv("CC_OPTS")} + compile_command = {cc, "-Os", lua_c_path, table.concat(native, " "), static_lua, rdynamic, "-lm", _784_, "-o", (executable_name .. bin_extension), "-I", lua_include_dir, os.getenv("CC_OPTS")} if os.getenv("FENNEL_DEBUG") then print("Compiling with", table.concat(compile_command, " ")) end @@ -143,17 +143,17 @@ package.preload["fennel.binary"] = package.preload["fennel.binary"] or function( if (version_extension and (version_extension ~= "") and not version_extension:match("%.%d+")) then return false else - local _762_0 = extension - if (_762_0 == "a") then + local _789_0 = extension + if (_789_0 == "a") then return path - elseif (_762_0 == "o") then + elseif (_789_0 == "o") then return path - elseif (_762_0 == "so") then + elseif (_789_0 == "so") then return path - elseif (_762_0 == "dylib") then + elseif (_789_0 == "dylib") then return path else - local _ = _762_0 + local _ = _789_0 return false end end @@ -185,10 +185,10 @@ package.preload["fennel.binary"] = package.preload["fennel.binary"] or function( return native end local function compile(filename, executable_name, static_lua, lua_include_dir, options, args) - local _769_ = extract_native_args(args) - local libraries = _769_["libraries"] - local modules = _769_["modules"] - local rename_modules = _769_["rename-modules"] + local _796_ = extract_native_args(args) + local libraries = _796_["libraries"] + local modules = _796_["modules"] + local rename_modules = _796_["rename-modules"] local opts = {["rename-modules"] = rename_modules} copy(options, opts) return compile_binary(write_c(filename, modules, opts), executable_name, static_lua, lua_include_dir, libraries) @@ -205,14 +205,14 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) local view = require("fennel.view") local unpack = (table.unpack or _G.unpack) local function default_read_chunk(parser_state) - local function _591_() + local function _607_() if (0 < parser_state["stack-size"]) then return ".." else return ">> " end end - io.write(_591_()) + io.write(_607_()) io.flush() local input = io.read() return (input and (input .. "\n")) @@ -222,18 +222,18 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) return io.write("\n") end local function default_on_error(errtype, err, lua_source) - local function _593_() - local _592_0 = errtype - if (_592_0 == "Lua Compile") then + local function _609_() + local _608_0 = errtype + if (_608_0 == "Lua Compile") then return ("Bad code generated - likely a bug with the compiler:\n" .. "--- Generated Lua Start ---\n" .. lua_source .. "--- Generated Lua End ---\n") - elseif (_592_0 == "Runtime") then + elseif (_608_0 == "Runtime") then return (compiler.traceback(tostring(err), 4) .. "\n") else - local _ = _592_0 + local _ = _608_0 return ("%s error: %s\n"):format(errtype, tostring(err)) end end - return io.write(_593_()) + return io.write(_609_()) end local function splice_save_locals(env, lua_source, scope) local saves = nil @@ -241,7 +241,7 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) local tbl_17_ = {} local i_18_ = #tbl_17_ for name in pairs(env.___replLocals___) do - local val_19_ = ("local %s = ___replLocals___['%s']"):format(name, name) + local val_19_ = ("local %s = ___replLocals___['%s']"):format((scope.manglings[name] or name), name) if (nil ~= val_19_) then i_18_ = (i_18_ + 1) tbl_17_[i_18_] = val_19_ @@ -253,10 +253,10 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) do local tbl_17_ = {} local i_18_ = #tbl_17_ - for _, name in pairs(scope.manglings) do + for raw, name in pairs(scope.manglings) do local val_19_ = nil if not scope.gensyms[name] then - val_19_ = ("___replLocals___['%s'] = %s"):format(name, name) + val_19_ = ("___replLocals___['%s'] = %s"):format(raw, name) else val_19_ = nil end @@ -273,25 +273,25 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) else gap = " " end - local function _599_() + local function _615_() if next(saves) then return (table.concat(saves, " ") .. gap) else return "" end end - local function _602_() - local _600_0, _601_0 = lua_source:match("^(.*)[\n ](return .*)$") - if ((nil ~= _600_0) and (nil ~= _601_0)) then - local body = _600_0 - local _return = _601_0 + local function _618_() + local _616_0, _617_0 = lua_source:match("^(.*)[\n ](return .*)$") + if ((nil ~= _616_0) and (nil ~= _617_0)) then + local body = _616_0 + local _return = _617_0 return (body .. gap .. table.concat(binds, " ") .. gap .. _return) else - local _ = _600_0 + local _ = _616_0 return lua_source end end - return (_599_() .. _602_()) + return (_615_() .. _618_()) end local function completer(env, scope, text) local max_items = 2000 @@ -303,14 +303,14 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) local scope_first_3f = ((tbl == env) or (tbl == env.___replLocals___)) local tbl_17_ = matches local i_18_ = #tbl_17_ - local function _604_() + local function _620_() if scope_first_3f then return scope.manglings else return tbl end end - for k, is_mangled in utils.allpairs(_604_()) do + for k, is_mangled in utils.allpairs(_620_()) do if (max_items <= #matches) then break end local val_19_ = nil do @@ -378,7 +378,7 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) return input:match("^%s*,") end local function command_docs() - local _613_ + local _629_ do local tbl_17_ = {} local i_18_ = #tbl_17_ @@ -389,18 +389,18 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) tbl_17_[i_18_] = val_19_ end end - _613_ = tbl_17_ + _629_ = tbl_17_ end - return table.concat(_613_, "\n") + return table.concat(_629_, "\n") end commands.help = function(_, _0, on_values) return on_values({("Welcome to Fennel.\nThis is the REPL where you can enter code to be evaluated.\nYou can also run these repl commands:\n\n" .. command_docs() .. "\n ,exit - Leave the repl.\n\nUse ,doc something to see descriptions for individual macros and special forms.\n\nFor more information about the language, see https://fennel-lang.org/reference")}) end do end (compiler.metadata):set(commands.help, "fnl/docstring", "Show this message.") local function reload(module_name, env, on_values, on_error) - local _615_0, _616_0 = pcall(specials["load-code"]("return require(...)", env), module_name) - if ((_615_0 == true) and (nil ~= _616_0)) then - local old = _616_0 + local _631_0, _632_0 = pcall(specials["load-code"]("return require(...)", env), module_name) + if ((_631_0 == true) and (nil ~= _632_0)) then + local old = _632_0 local _ = nil package.loaded[module_name] = nil _ = nil @@ -425,8 +425,8 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) package.loaded[module_name] = old end return on_values({"ok"}) - elseif ((_615_0 == false) and (nil ~= _616_0)) then - local msg = _616_0 + elseif ((_631_0 == false) and (nil ~= _632_0)) then + local msg = _632_0 if msg:match("loop or previous error loading module") then package.loaded[module_name] = nil return reload(module_name, env, on_values, on_error) @@ -434,28 +434,32 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) specials["macro-loaded"][module_name] = nil return nil else - local function _621_() - local _620_0 = msg:gsub("\n.*", "") - return _620_0 + local function _637_() + local _636_0 = msg:gsub("\n.*", "") + return _636_0 end - return on_error("Runtime", _621_()) + return on_error("Runtime", _637_()) end end end local function run_command(read, on_error, f) - local _624_0, _625_0, _626_0 = pcall(read) - if ((_624_0 == true) and (_625_0 == true) and (nil ~= _626_0)) then - local val = _626_0 - return f(val) - elseif (_624_0 == false) then + local _640_0, _641_0, _642_0 = pcall(read) + if ((_640_0 == true) and (_641_0 == true) and (nil ~= _642_0)) then + local val = _642_0 + local _643_0, _644_0 = pcall(f, val) + if ((_643_0 == false) and (nil ~= _644_0)) then + local msg = _644_0 + return on_error("Runtime", msg) + end + elseif (_640_0 == false) then return on_error("Parse", "Couldn't parse input.") end end commands.reload = function(env, read, on_values, on_error) - local function _628_(_241) + local function _647_(_241) return reload(tostring(_241), env, on_values, on_error) end - return run_command(read, on_error, _628_) + return run_command(read, on_error, _647_) end do end (compiler.metadata):set(commands.reload, "fnl/docstring", "Reload the specified module.") commands.reset = function(env, _, on_values) @@ -464,28 +468,28 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) end do end (compiler.metadata):set(commands.reset, "fnl/docstring", "Erase all repl-local scope.") commands.complete = function(env, read, on_values, on_error, scope, chars) - local function _629_() - return on_values(completer(env, scope, string.char(unpack(chars)):gsub(",complete +", ""):sub(1, -2))) + local function _648_() + return on_values(completer(env, scope, table.concat(chars):gsub(",complete +", ""):sub(1, -2))) end - return run_command(read, on_error, _629_) + return run_command(read, on_error, _648_) end do end (compiler.metadata):set(commands.complete, "fnl/docstring", "Print all possible completions for a given input symbol.") local function apropos_2a(pattern, tbl, prefix, seen, names) for name, subtbl in pairs(tbl) do if (("string" == type(name)) and (package ~= subtbl)) then - local _630_0 = type(subtbl) - if (_630_0 == "function") then + local _649_0 = type(subtbl) + if (_649_0 == "function") then if ((prefix .. name)):match(pattern) then table.insert(names, (prefix .. name)) end - elseif (_630_0 == "table") then + elseif (_649_0 == "table") then if not seen[subtbl] then - local _632_ + local _651_ do seen[subtbl] = true - _632_ = seen + _651_ = seen end - apropos_2a(pattern, subtbl, (prefix .. name:gsub("%.", "/") .. "."), _632_, names) + apropos_2a(pattern, subtbl, (prefix .. name:gsub("%.", "/") .. "."), _651_, names) end end end @@ -506,10 +510,10 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) return tbl_17_ end commands.apropos = function(_env, read, on_values, on_error, _scope) - local function _637_(_241) + local function _656_(_241) return on_values(apropos(tostring(_241))) end - return run_command(read, on_error, _637_) + return run_command(read, on_error, _656_) end do end (compiler.metadata):set(commands.apropos, "fnl/docstring", "Print all functions matching a pattern in all loaded modules.") local function apropos_follow_path(path) @@ -529,12 +533,12 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) local tgt = package.loaded for _, path0 in ipairs(paths) do if (nil == tgt) then break end - local _640_ + local _659_ do - local _639_0 = path0:gsub("%/", ".") - _640_ = _639_0 + local _658_0 = path0:gsub("%/", ".") + _659_ = _658_0 end - tgt = tgt[_640_] + tgt = tgt[_659_] end return tgt end @@ -546,9 +550,9 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) do local tgt = apropos_follow_path(path) if ("function" == type(tgt)) then - local _641_0 = (compiler.metadata):get(tgt, "fnl/docstring") - if (nil ~= _641_0) then - local docstr = _641_0 + local _660_0 = (compiler.metadata):get(tgt, "fnl/docstring") + if (nil ~= _660_0) then + local docstr = _660_0 val_19_ = (docstr:match(pattern) and path) else val_19_ = nil @@ -565,10 +569,10 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) return tbl_17_ end commands["apropos-doc"] = function(_env, read, on_values, on_error, _scope) - local function _645_(_241) + local function _664_(_241) return on_values(apropos_doc(tostring(_241))) end - return run_command(read, on_error, _645_) + return run_command(read, on_error, _664_) end do end (compiler.metadata):set(commands["apropos-doc"], "fnl/docstring", "Print all functions that match the pattern in their docs") local function apropos_show_docs(on_values, pattern) @@ -582,92 +586,108 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) return nil end commands["apropos-show-docs"] = function(_env, read, on_values, on_error) - local function _647_(_241) + local function _666_(_241) return apropos_show_docs(on_values, tostring(_241)) end - return run_command(read, on_error, _647_) + return run_command(read, on_error, _666_) end do end (compiler.metadata):set(commands["apropos-show-docs"], "fnl/docstring", "Print all documentations matching a pattern in function name") - local function resolve(identifier, _648_0, scope) - local _649_ = _648_0 - local env = _649_ - local ___replLocals___ = _649_["___replLocals___"] + local function resolve(identifier, _667_0, scope) + local _668_ = _667_0 + local env = _668_ + local ___replLocals___ = _668_["___replLocals___"] local e = nil - local function _650_(_241, _242) - return (___replLocals___[_242] or env[_242]) + local function _669_(_241, _242) + return (___replLocals___[scope.unmanglings[_242]] or env[_242]) end - e = setmetatable({}, {__index = _650_}) - local _651_0, _652_0 = pcall(compiler["compile-string"], tostring(identifier), {scope = scope}) - if ((_651_0 == true) and (nil ~= _652_0)) then - local code = _652_0 - return specials["load-code"](code, e)() + e = setmetatable({}, {__index = _669_}) + local function _670_(...) + local _671_0, _672_0 = ... + if ((_671_0 == true) and (nil ~= _672_0)) then + local code = _672_0 + local function _673_(...) + local _674_0, _675_0 = ... + if ((_674_0 == true) and (nil ~= _675_0)) then + local val = _675_0 + return val + else + local _ = _674_0 + return nil + end + end + return _673_(pcall(specials["load-code"](code, e))) + else + local _ = _671_0 + return nil + end end + return _670_(pcall(compiler["compile-string"], tostring(identifier), {scope = scope})) end commands.find = function(env, read, on_values, on_error, scope) - local function _654_(_241) - local _655_0 = nil + local function _678_(_241) + local _679_0 = nil do - local _656_0 = utils["sym?"](_241) - if (nil ~= _656_0) then - local _657_0 = resolve(_656_0, env, scope) - if (nil ~= _657_0) then - _655_0 = debug.getinfo(_657_0) + local _680_0 = utils["sym?"](_241) + if (nil ~= _680_0) then + local _681_0 = resolve(_680_0, env, scope) + if (nil ~= _681_0) then + _679_0 = debug.getinfo(_681_0) else - _655_0 = _657_0 + _679_0 = _681_0 end else - _655_0 = _656_0 + _679_0 = _680_0 end end - if ((_G.type(_655_0) == "table") and (nil ~= _655_0.linedefined) and (nil ~= _655_0.short_src) and (nil ~= _655_0.source) and (_655_0.what == "Lua")) then - local line = _655_0.linedefined - local src = _655_0.short_src - local source = _655_0.source + if ((_G.type(_679_0) == "table") and (nil ~= _679_0.linedefined) and (nil ~= _679_0.short_src) and (nil ~= _679_0.source) and (_679_0.what == "Lua")) then + local line = _679_0.linedefined + local src = _679_0.short_src + local source = _679_0.source local fnlsrc = nil do - local _660_0 = compiler.sourcemap - if (nil ~= _660_0) then - _660_0 = _660_0[source] + local _684_0 = compiler.sourcemap + if (nil ~= _684_0) then + _684_0 = _684_0[source] end - if (nil ~= _660_0) then - _660_0 = _660_0[line] + if (nil ~= _684_0) then + _684_0 = _684_0[line] end - if (nil ~= _660_0) then - _660_0 = _660_0[2] + if (nil ~= _684_0) then + _684_0 = _684_0[2] end - fnlsrc = _660_0 + fnlsrc = _684_0 end return on_values({string.format("%s:%s", src, (fnlsrc or line))}) - elseif (_655_0 == nil) then + elseif (_679_0 == nil) then return on_error("Repl", "Unknown value") else - local _ = _655_0 + local _ = _679_0 return on_error("Repl", "No source info") end end - return run_command(read, on_error, _654_) + return run_command(read, on_error, _678_) end do end (compiler.metadata):set(commands.find, "fnl/docstring", "Print the filename and line number for a given function") commands.doc = function(env, read, on_values, on_error, scope) - local function _665_(_241) + local function _689_(_241) local name = tostring(_241) local path = (utils["multi-sym?"](name) or {name}) local ok_3f, target = nil, nil - local function _666_() + local function _690_() return (utils["get-in"](scope.specials, path) or utils["get-in"](scope.macros, path) or resolve(name, env, scope)) end - ok_3f, target = pcall(_666_) + ok_3f, target = pcall(_690_) if ok_3f then return on_values({specials.doc(target, name)}) else - return on_error("Repl", "Could not resolve value for docstring lookup") + return on_error("Repl", ("Could not find " .. name .. " for docs.")) end end - return run_command(read, on_error, _665_) + return run_command(read, on_error, _689_) end do end (compiler.metadata):set(commands.doc, "fnl/docstring", "Print the docstring and arglist for a function, macro, or special form.") commands.compile = function(env, read, on_values, on_error, scope) - local function _668_(_241) + local function _692_(_241) local allowedGlobals = specials["current-global-names"](env) local ok_3f, result = pcall(compiler.compile, _241, {allowedGlobals = allowedGlobals, env = env, scope = scope}) if ok_3f then @@ -676,16 +696,16 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) return on_error("Repl", ("Error compiling expression: " .. result)) end end - return run_command(read, on_error, _668_) + return run_command(read, on_error, _692_) end do end (compiler.metadata):set(commands.compile, "fnl/docstring", "compiles the expression into lua and prints the result.") local function load_plugin_commands(plugins) - for _, plugin in ipairs((plugins or {})) do - for name, f in pairs(plugin) do - local _670_0 = name:match("^repl%-command%-(.*)") - if (nil ~= _670_0) then - local cmd_name = _670_0 - commands[cmd_name] = (commands[cmd_name] or f) + for i = #(plugins or {}), 1, -1 do + for name, f in pairs(plugins[i]) do + local _694_0 = name:match("^repl%-command%-(.*)") + if (nil ~= _694_0) then + local cmd_name = _694_0 + commands[cmd_name] = f end end end @@ -694,12 +714,12 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) local function run_command_loop(input, read, loop, env, on_values, on_error, scope, chars) local command_name = input:match(",([^%s/]+)") do - local _672_0 = commands[command_name] - if (nil ~= _672_0) then - local command = _672_0 + local _696_0 = commands[command_name] + if (nil ~= _696_0) then + local command = _696_0 command(env, read, on_values, on_error, scope, chars) else - local _ = _672_0 + local _ = _696_0 if ("exit" ~= command_name) then on_values({"Unknown command", command_name}) end @@ -749,9 +769,9 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) end local function repl(_3foptions) local old_root_options = utils.root.options - local _681_ = utils.copy(_3foptions) - local opts = _681_ - local _3ffennelrc = _681_["fennelrc"] + local _705_ = utils.copy(_3foptions) + local opts = _705_ + local _3ffennelrc = _705_["fennelrc"] local _ = nil opts.fennelrc = nil _ = nil @@ -763,39 +783,43 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) _0 = nil end local env = specials["wrap-env"]((opts.env or rawget(_G, "_ENV") or _G)) + local callbacks = {env = env, onError = (opts.onError or default_on_error), onValues = (opts.onValues or default_on_values), pp = (opts.pp or view), readChunk = (opts.readChunk or default_read_chunk)} local save_locals_3f = (opts.saveLocals ~= false) - local read_chunk = (opts.readChunk or default_read_chunk) - local on_values = (opts.onValues or default_on_values) - local on_error = (opts.onError or default_on_error) - local pp = (opts.pp or view) - local byte_stream, clear_stream = parser.granulate(read_chunk) + local byte_stream, clear_stream = nil, nil + local function _707_(_241) + return callbacks.readChunk(_241) + end + byte_stream, clear_stream = parser.granulate(_707_) local chars = {} local read, reset = nil, nil - local function _683_(parser_state) - local c = byte_stream(parser_state) - table.insert(chars, c) - return c + local function _708_(parser_state) + local b = byte_stream(parser_state) + if b then + table.insert(chars, string.char(b)) + end + return b end - read, reset = parser.parser(_683_) + read, reset = parser.parser(_708_) + env.___repl___ = callbacks opts.env, opts.scope = env, compiler["make-scope"]() opts.useMetadata = (opts.useMetadata ~= false) if (opts.allowedGlobals == nil) then opts.allowedGlobals = specials["current-global-names"](env) end if opts.registerCompleter then - local function _686_() - local _685_0 = opts.scope - local function _687_(...) - return completer(env, _685_0, ...) + local function _712_() + local _711_0 = opts.scope + local function _713_(...) + return completer(env, _711_0, ...) end - return _687_ + return _713_ end - opts.registerCompleter(_686_()) + opts.registerCompleter(_712_()) end load_plugin_commands(opts.plugins) if save_locals_3f then local function newindex(t, k, v) - if opts.scope.unmanglings[k] then + if opts.scope.manglings[k] then return rawset(t, k, v) end end @@ -804,11 +828,12 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) local function print_values(...) local vals = {...} local out = {} + local pp = callbacks.pp env._, env.__ = vals[1], vals for i = 1, select("#", ...) do table.insert(out, pp(vals[i])) end - return on_values(out) + return callbacks.onValues(out) end local function loop() for k in pairs(chars) do @@ -816,51 +841,51 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) end reset() local ok, parser_not_eof_3f, x = pcall(read) - local src_string = string.char(unpack(chars)) + local src_string = table.concat(chars) local readline_not_eof_3f = (not readline or (src_string ~= "(null)")) local not_eof_3f = (readline_not_eof_3f and parser_not_eof_3f) if not ok then - on_error("Parse", not_eof_3f) + callbacks.onError("Parse", not_eof_3f) clear_stream() return loop() elseif command_3f(src_string) then - return run_command_loop(src_string, read, loop, env, on_values, on_error, opts.scope, chars) + return run_command_loop(src_string, read, loop, env, callbacks.onValues, callbacks.onError, opts.scope, chars) else if not_eof_3f then do - local _691_0, _692_0 = nil, nil - local function _693_() + local _717_0, _718_0 = nil, nil + local function _719_() opts["source"] = src_string return opts end - _691_0, _692_0 = pcall(compiler.compile, x, _693_()) - if ((_691_0 == false) and (nil ~= _692_0)) then - local msg = _692_0 + _717_0, _718_0 = pcall(compiler.compile, x, _719_()) + if ((_717_0 == false) and (nil ~= _718_0)) then + local msg = _718_0 clear_stream() - on_error("Compile", msg) - elseif ((_691_0 == true) and (nil ~= _692_0)) then - local src = _692_0 + callbacks.onError("Compile", msg) + elseif ((_717_0 == true) and (nil ~= _718_0)) then + local src = _718_0 local src0 = nil if save_locals_3f then src0 = splice_save_locals(env, src, opts.scope) else src0 = src end - local _695_0, _696_0 = pcall(specials["load-code"], src0, env) - if ((_695_0 == false) and (nil ~= _696_0)) then - local msg = _696_0 + local _721_0, _722_0 = pcall(specials["load-code"], src0, env) + if ((_721_0 == false) and (nil ~= _722_0)) then + local msg = _722_0 clear_stream() - on_error("Lua Compile", msg, src0) - elseif (true and (nil ~= _696_0)) then - local _1 = _695_0 - local chunk = _696_0 - local function _697_() + callbacks.onError("Lua Compile", msg, src0) + elseif (true and (nil ~= _722_0)) then + local _1 = _721_0 + local chunk = _722_0 + local function _723_() return print_values(chunk()) end - local function _698_(...) - return on_error("Runtime", ...) + local function _724_(...) + return callbacks.onError("Runtime", ...) end - xpcall(_697_, _698_) + xpcall(_723_, _724_) end end end @@ -884,14 +909,14 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct local unpack = (table.unpack or _G.unpack) local SPECIALS = compiler.scopes.global.specials local function wrap_env(env) - local function _407_(_, key) + local function _416_(_, key) if utils["string?"](key) then return env[compiler["global-unmangling"](key)] else return env[key] end end - local function _409_(_, key, value) + local function _418_(_, key, value) if utils["string?"](key) then env[compiler["global-unmangling"](key)] = value return nil @@ -900,26 +925,26 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct return nil end end - local function _411_() + local function _420_() local function putenv(k, v) - local _412_ + local _421_ if utils["string?"](k) then - _412_ = compiler["global-unmangling"](k) + _421_ = compiler["global-unmangling"](k) else - _412_ = k + _421_ = k end - return _412_, v + return _421_, v end return next, utils.kvmap(env, putenv), nil end - return setmetatable({}, {__index = _407_, __newindex = _409_, __pairs = _411_}) + return setmetatable({}, {__index = _416_, __newindex = _418_, __pairs = _420_}) end local function current_global_names(_3fenv) local mt = nil do - local _414_0 = getmetatable(_3fenv) - if ((_G.type(_414_0) == "table") and (nil ~= _414_0.__pairs)) then - local mtpairs = _414_0.__pairs + local _423_0 = getmetatable(_3fenv) + if ((_G.type(_423_0) == "table") and (nil ~= _423_0.__pairs)) then + local mtpairs = _423_0.__pairs local tbl_14_ = {} for k, v in mtpairs(_3fenv) do local k_15_, v_16_ = k, v @@ -928,7 +953,7 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end end mt = tbl_14_ - elseif (_414_0 == nil) then + elseif (_423_0 == nil) then mt = (_3fenv or _G) else mt = nil @@ -938,15 +963,15 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end local function load_code(code, _3fenv, _3ffilename) local env = (_3fenv or rawget(_G, "_ENV") or _G) - local _417_0, _418_0 = rawget(_G, "setfenv"), rawget(_G, "loadstring") - if ((nil ~= _417_0) and (nil ~= _418_0)) then - local setfenv = _417_0 - local loadstring = _418_0 + local _426_0, _427_0 = rawget(_G, "setfenv"), rawget(_G, "loadstring") + if ((nil ~= _426_0) and (nil ~= _427_0)) then + local setfenv = _426_0 + local loadstring = _427_0 local f = assert(loadstring(code, _3ffilename)) setfenv(f, env) return f else - local _ = _417_0 + local _ = _426_0 return assert(load(code, _3ffilename, "t", env)) end end @@ -958,13 +983,13 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct local mt = getmetatable(tgt) if ((type(tgt) == "function") or ((type(mt) == "table") and (type(mt.__call) == "function"))) then local arglist = table.concat(((compiler.metadata):get(tgt, "fnl/arglist") or {"#"}), " ") - local _420_ + local _429_ if (0 < #arglist) then - _420_ = " " + _429_ = " " else - _420_ = "" + _429_ = "" end - return string.format("(%s%s%s)\n %s", name, _420_, arglist, docstring) + return string.format("(%s%s%s)\n %s", name, _429_, arglist, docstring) else return string.format("%s\n %s", name, docstring) end @@ -1078,9 +1103,9 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct local opts = {nval = 1, tail = false} local scope = compiler["make-scope"]() local chunk = {} - local _431_ = compiler.compile1(v, scope, chunk, opts) - local _432_ = _431_[1] - local v0 = _432_[1] + local _440_ = compiler.compile1(v, scope, chunk, opts) + local _441_ = _440_[1] + local v0 = _441_[1] return v0 end local function insert_meta(meta, k, v) @@ -1088,23 +1113,23 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct compiler.assert((type(k) == "string"), ("expected string keys in metadata table, got: %s"):format(view(k, view_opts))) compiler.assert(literal_3f(v), ("expected literal value in metadata table, got: %s %s"):format(view(k, view_opts), view(v, view_opts))) table.insert(meta, view(k)) - local function _433_() + local function _442_() if ("string" == type(v)) then return view(v, view_opts) else return compile_value(v) end end - table.insert(meta, _433_()) + table.insert(meta, _442_()) return meta end local function insert_arglist(meta, arg_list) local view_opts = {["escape-newlines?"] = true, ["line-length"] = math.huge, ["one-line?"] = true} table.insert(meta, "\"fnl/arglist\"") - local function _434_(_241) + local function _443_(_241) return view(view(_241, view_opts)) end - table.insert(meta, ("{" .. table.concat(utils.map(arg_list, _434_), ", ") .. "}")) + table.insert(meta, ("{" .. table.concat(utils.map(arg_list, _443_), ", ") .. "}")) return meta end local function set_fn_metadata(f_metadata, parent, fn_name) @@ -1123,13 +1148,13 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end local function get_fn_name(ast, scope, fn_name, multi) if (fn_name and (fn_name[1] ~= "nil")) then - local _437_ + local _446_ if not multi then - _437_ = compiler["declare-local"](fn_name, {}, scope, ast) + _446_ = compiler["declare-local"](fn_name, {}, scope, ast) else - _437_ = compiler["symbol-to-expression"](fn_name, scope)[1] + _446_ = compiler["symbol-to-expression"](fn_name, scope)[1] end - return _437_, not multi, 3 + return _446_, not multi, 3 else return nil, true, 2 end @@ -1139,13 +1164,13 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct for i = (index + 1), #ast do compiler.compile1(ast[i], f_scope, f_chunk, {nval = (((i ~= #ast) and 0) or nil), tail = (i == #ast)}) end - local _440_ + local _449_ if local_3f then - _440_ = "local function %s(%s)" + _449_ = "local function %s(%s)" else - _440_ = "%s = function(%s)" + _449_ = "%s = function(%s)" end - compiler.emit(parent, string.format(_440_, fn_name, table.concat(arg_name_list, ", ")), ast) + compiler.emit(parent, string.format(_449_, fn_name, table.concat(arg_name_list, ", ")), ast) compiler.emit(parent, f_chunk, ast) compiler.emit(parent, "end", ast) set_fn_metadata(f_metadata, parent, fn_name) @@ -1156,52 +1181,39 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct local fn_name = compiler.gensym(scope) return compile_named_fn(ast, f_scope, f_chunk, parent, index, fn_name, true, arg_name_list, f_metadata) end - local function assoc_table_3f(t) - local len = #t - local nxt, t0, k = pairs(t) - local function _442_() - if (len == 0) then - return k - else - return len - end + local function maybe_metadata(ast, pred, handler, mt, index) + local index_2a = (index + 1) + local index_2a_before_ast_end_3f = (index_2a < #ast) + local expr = ast[index_2a] + if (index_2a_before_ast_end_3f and pred(expr)) then + return handler(mt, expr), index_2a + else + return mt, index end - return (nil ~= nxt(t0, _442_())) end local function get_function_metadata(ast, arg_list, index) - local f_metadata = {["fnl/arglist"] = arg_list} - local index_2a = (index + 1) - local expr = ast[index_2a] - if (utils["string?"](expr) and (index_2a < #ast)) then - local _443_ - do - f_metadata["fnl/docstring"] = expr - _443_ = f_metadata - end - return _443_, index_2a - elseif (utils["table?"](expr) and (index_2a < #ast) and assoc_table_3f(expr)) then - local _444_ - do - local tbl_14_ = f_metadata - for k, v in pairs(expr) do - local k_15_, v_16_ = k, v - if ((k_15_ ~= nil) and (v_16_ ~= nil)) then - tbl_14_[k_15_] = v_16_ - end + local function _452_(_241, _242) + local tbl_14_ = _241 + for k, v in pairs(_242) do + local k_15_, v_16_ = k, v + if ((k_15_ ~= nil) and (v_16_ ~= nil)) then + tbl_14_[k_15_] = v_16_ end - _444_ = tbl_14_ end - return _444_, index_2a - else - return f_metadata, index + return tbl_14_ end + local function _454_(_241, _242) + _241["fnl/docstring"] = _242 + return _241 + end + return maybe_metadata(ast, utils["kv-table?"], _452_, maybe_metadata(ast, utils["string?"], _454_, {["fnl/arglist"] = arg_list}, index)) end SPECIALS.fn = function(ast, scope, parent) local f_scope = nil do - local _447_0 = compiler["make-scope"](scope) - _447_0["vararg"] = false - f_scope = _447_0 + local _455_0 = compiler["make-scope"](scope) + _455_0["vararg"] = false + f_scope = _455_0 end local f_chunk = {} local fn_sym = utils["sym?"](ast[2]) @@ -1228,7 +1240,7 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct compiler.assert((arg == arg_list[#arg_list]), "expected vararg as last parameter", ast) f_scope.vararg = true return "..." - elseif (utils.sym("&") == arg) then + elseif utils["sym?"](arg, "&") then return destructure_amp(i) elseif (utils["sym?"](arg) and (tostring(arg) ~= "nil") and not utils["multi-sym?"](tostring(arg))) then return compiler["declare-local"](arg, {}, f_scope, ast) @@ -1261,36 +1273,36 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct doc_special("fn", {"name?", "args", "docstring?", "..."}, "Function syntax. May optionally include a name and docstring or a metadata table.\nIf a name is provided, the function will be bound in the current scope.\nWhen called with the wrong number of args, excess args will be discarded\nand lacking args will be nil, use lambda for arity-checked functions.", true) SPECIALS.lua = function(ast, _, parent) compiler.assert(((#ast == 2) or (#ast == 3)), "expected 1 or 2 arguments", ast) - local _452_ + local _460_ do - local _451_0 = utils["sym?"](ast[2]) - if (nil ~= _451_0) then - _452_ = tostring(_451_0) + local _459_0 = utils["sym?"](ast[2]) + if (nil ~= _459_0) then + _460_ = tostring(_459_0) else - _452_ = _451_0 + _460_ = _459_0 end end - if ("nil" ~= _452_) then + if ("nil" ~= _460_) then table.insert(parent, {ast = ast, leaf = tostring(ast[2])}) end - local _456_ + local _464_ do - local _455_0 = utils["sym?"](ast[3]) - if (nil ~= _455_0) then - _456_ = tostring(_455_0) + local _463_0 = utils["sym?"](ast[3]) + if (nil ~= _463_0) then + _464_ = tostring(_463_0) else - _456_ = _455_0 + _464_ = _463_0 end end - if ("nil" ~= _456_) then + if ("nil" ~= _464_) then return tostring(ast[3]) end end local function dot(ast, scope, parent) compiler.assert((1 < #ast), "expected table argument", ast) local len = #ast - local _459_ = compiler.compile1(ast[2], scope, parent, {nval = 1}) - local lhs = _459_[1] + local _467_ = compiler.compile1(ast[2], scope, parent, {nval = 1}) + local lhs = _467_[1] if (len == 2) then return tostring(lhs) else @@ -1300,12 +1312,12 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct if (utils["string?"](index) and utils["valid-lua-identifier?"](index)) then table.insert(indices, ("." .. index)) else - local _460_ = compiler.compile1(index, scope, parent, {nval = 1}) - local index0 = _460_[1] + local _468_ = compiler.compile1(index, scope, parent, {nval = 1}) + local index0 = _468_[1] table.insert(indices, ("[" .. tostring(index0) .. "]")) end end - if (tostring(lhs):find("[{\"0-9]") or ("nil" == tostring(lhs))) then + if (not (utils["sym?"](ast[2]) or utils["list?"](ast[2])) or ("nil" == tostring(lhs))) then return ("(" .. tostring(lhs) .. ")" .. table.concat(indices)) else return (tostring(lhs) .. table.concat(indices)) @@ -1346,7 +1358,7 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end doc_special("var", {"name", "val"}, "Introduce new mutable local.") local function kv_3f(t) - local _464_ + local _472_ do local tbl_17_ = {} local i_18_ = #tbl_17_ @@ -1362,9 +1374,9 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct tbl_17_[i_18_] = val_19_ end end - _464_ = tbl_17_ + _472_ = tbl_17_ end - return _464_[1] + return _472_[1] end SPECIALS.let = function(ast, scope, parent, opts) local bindings = ast[2] @@ -1391,22 +1403,22 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end end local function disambiguate_3f(rootstr, parent) - local function _469_() - local _468_0 = get_prev_line(parent) - if (nil ~= _468_0) then - local prev_line = _468_0 + local function _477_() + local _476_0 = get_prev_line(parent) + if (nil ~= _476_0) then + local prev_line = _476_0 return prev_line:match("%)$") end end - return (rootstr:match("^{") or _469_()) + return (rootstr:match("^{") or rootstr:match("^%(") or _477_()) end SPECIALS.tset = function(ast, scope, parent) compiler.assert((3 < #ast), "expected table, key, and value arguments", ast) local root = compiler.compile1(ast[2], scope, parent, {nval = 1})[1] local keys = {} for i = 3, (#ast - 1) do - local _471_ = compiler.compile1(ast[i], scope, parent, {nval = 1}) - local key = _471_[1] + local _479_ = compiler.compile1(ast[i], scope, parent, {nval = 1}) + local key = _479_[1] table.insert(keys, tostring(key)) end local value = compiler.compile1(ast[#ast], scope, parent, {nval = 1})[1] @@ -1438,82 +1450,89 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end local function if_2a(ast, scope, parent, opts) compiler.assert((2 < #ast), "expected condition and body", ast) - local do_scope = compiler["make-scope"](scope) - local branches = {} - local wrapper, inner_tail, inner_target, target_exprs = calculate_target(scope, opts) - local body_opts = {nval = opts.nval, tail = inner_tail, target = inner_target} - local function compile_body(i) - local chunk = {} - local cscope = compiler["make-scope"](do_scope) - compiler["keep-side-effects"](compiler.compile1(ast[i], cscope, chunk, body_opts), chunk, nil, ast[i]) - return {chunk = chunk, scope = cscope} + if ((1 == (#ast % 2)) and (ast[(#ast - 1)] == true)) then + table.remove(ast, (#ast - 1)) end if (1 == (#ast % 2)) then table.insert(ast, utils.sym("nil")) end - for i = 2, (#ast - 1), 2 do - local condchunk = {} - local res = compiler.compile1(ast[i], do_scope, condchunk, {nval = 1}) - local cond = res[1] - local branch = compile_body((i + 1)) - branch.cond = cond - branch.condchunk = condchunk - branch.nested = ((i ~= 2) and (next(condchunk, nil) == nil)) - table.insert(branches, branch) - end - local else_branch = compile_body(#ast) - local s = compiler.gensym(scope) - local buffer = {} - local last_buffer = buffer - for i = 1, #branches do - local branch = branches[i] - local fstr = nil - if not branch.nested then - fstr = "if %s then" - else - fstr = "elseif %s then" + if (#ast == 2) then + return SPECIALS["do"](utils.list(utils.sym("do"), ast[2]), scope, parent, opts) + else + local do_scope = compiler["make-scope"](scope) + local branches = {} + local wrapper, inner_tail, inner_target, target_exprs = calculate_target(scope, opts) + local body_opts = {nval = opts.nval, tail = inner_tail, target = inner_target} + local function compile_body(i) + local chunk = {} + local cscope = compiler["make-scope"](do_scope) + compiler["keep-side-effects"](compiler.compile1(ast[i], cscope, chunk, body_opts), chunk, nil, ast[i]) + return {chunk = chunk, scope = cscope} end - local cond = tostring(branch.cond) - local cond_line = fstr:format(cond) - if branch.nested then - compiler.emit(last_buffer, branch.condchunk, ast) - else - for _, v in ipairs(branch.condchunk) do - compiler.emit(last_buffer, v, ast) + for i = 2, (#ast - 1), 2 do + local condchunk = {} + local res = compiler.compile1(ast[i], do_scope, condchunk, {nval = 1}) + local cond = res[1] + local branch = compile_body((i + 1)) + branch.cond = cond + branch.condchunk = condchunk + branch.nested = ((i ~= 2) and (next(condchunk, nil) == nil)) + table.insert(branches, branch) + end + local else_branch = compile_body(#ast) + local s = compiler.gensym(scope) + local buffer = {} + local last_buffer = buffer + for i = 1, #branches do + local branch = branches[i] + local fstr = nil + if not branch.nested then + fstr = "if %s then" + else + fstr = "elseif %s then" + end + local cond = tostring(branch.cond) + local cond_line = fstr:format(cond) + if branch.nested then + compiler.emit(last_buffer, branch.condchunk, ast) + else + for _, v in ipairs(branch.condchunk) do + compiler.emit(last_buffer, v, ast) + end + end + compiler.emit(last_buffer, cond_line, ast) + compiler.emit(last_buffer, branch.chunk, ast) + if (i == #branches) then + compiler.emit(last_buffer, "else", ast) + compiler.emit(last_buffer, else_branch.chunk, ast) + compiler.emit(last_buffer, "end", ast) + elseif not branches[(i + 1)].nested then + local next_buffer = {} + compiler.emit(last_buffer, "else", ast) + compiler.emit(last_buffer, next_buffer, ast) + compiler.emit(last_buffer, "end", ast) + last_buffer = next_buffer end end - compiler.emit(last_buffer, cond_line, ast) - compiler.emit(last_buffer, branch.chunk, ast) - if (i == #branches) then - compiler.emit(last_buffer, "else", ast) - compiler.emit(last_buffer, else_branch.chunk, ast) - compiler.emit(last_buffer, "end", ast) - elseif not branches[(i + 1)].nested then - local next_buffer = {} - compiler.emit(last_buffer, "else", ast) - compiler.emit(last_buffer, next_buffer, ast) - compiler.emit(last_buffer, "end", ast) - last_buffer = next_buffer + if (wrapper == "iife") then + local iifeargs = ((scope.vararg and "...") or "") + compiler.emit(parent, ("local function %s(%s)"):format(tostring(s), iifeargs), ast) + compiler.emit(parent, buffer, ast) + compiler.emit(parent, "end", ast) + return utils.expr(("%s(%s)"):format(tostring(s), iifeargs), "statement") + elseif (wrapper == "none") then + for i = 1, #buffer do + compiler.emit(parent, buffer[i], ast) + end + return {returned = true} + else + compiler.emit(parent, ("local %s"):format(inner_target), ast) + for i = 1, #buffer do + compiler.emit(parent, buffer[i], ast) + end + return target_exprs end end - if (wrapper == "iife") then - local iifeargs = ((scope.vararg and "...") or "") - compiler.emit(parent, ("local function %s(%s)"):format(tostring(s), iifeargs), ast) - compiler.emit(parent, buffer, ast) - compiler.emit(parent, "end", ast) - return utils.expr(("%s(%s)"):format(tostring(s), iifeargs), "statement") - elseif (wrapper == "none") then - for i = 1, #buffer do - compiler.emit(parent, buffer[i], ast) - end - return {returned = true} - else - compiler.emit(parent, ("local %s"):format(inner_target), ast) - for i = 1, #buffer do - compiler.emit(parent, buffer[i], ast) - end - return target_exprs - end end SPECIALS["if"] = if_2a doc_special("if", {"cond1", "body1", "...", "condN", "bodyN"}, "Conditional form.\nTakes any number of condition/body pairs and evaluates the first body where\nthe condition evaluates to truthy. Similar to cond in other lisps.") @@ -1526,15 +1545,16 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end local function compile_until(condition, scope, chunk) if condition then - local _480_ = compiler.compile1(condition, scope, chunk, {nval = 1}) - local condition_lua = _480_[1] + local _490_ = compiler.compile1(condition, scope, chunk, {nval = 1}) + local condition_lua = _490_[1] return compiler.emit(chunk, ("if %s then break end"):format(tostring(condition_lua)), utils.expr(condition, "expression")) end end SPECIALS.each = function(ast, scope, parent) compiler.assert((3 <= #ast), "expected body expression", ast[1]) - local binding = compiler.assert(utils["table?"](ast[2]), "expected binding table", ast) - local _ = compiler.assert((2 <= #binding), "expected binding and iterator", binding) + compiler.assert(utils["table?"](ast[2]), "expected binding table", ast) + compiler.assert((2 <= #ast[2]), "expected binding and iterator", ast) + local binding = setmetatable(utils.copy(ast[2]), getmetatable(ast[2])) local until_condition = remove_until_condition(binding) local iter = table.remove(binding, #binding) local destructures = {} @@ -1588,15 +1608,17 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct SPECIALS["while"] = while_2a doc_special("while", {"condition", "..."}, "The classic while loop. Evaluates body until a condition is non-truthy.", true) local function for_2a(ast, scope, parent) - local ranges = compiler.assert(utils["table?"](ast[2]), "expected binding table", ast) - local until_condition = remove_until_condition(ast[2]) - local binding_sym = table.remove(ast[2], 1) + compiler.assert(utils["table?"](ast[2]), "expected binding table", ast) + local ranges = setmetatable(utils.copy(ast[2]), getmetatable(ast[2])) + local until_condition = remove_until_condition(ranges) + local binding_sym = table.remove(ranges, 1) local sub_scope = compiler["make-scope"](scope) local range_args = {} local chunk = {} compiler.assert(utils["sym?"](binding_sym), ("unable to bind %s %s"):format(type(binding_sym), tostring(binding_sym)), ast[2]) compiler.assert((3 <= #ast), "expected body expression", ast[1]) - compiler.assert((#ranges <= 3), "unexpected arguments", ranges[4]) + compiler.assert((#ranges <= 3), "unexpected arguments", ranges) + compiler.assert((1 < #ranges), "expected range to include start and stop", ranges) utils.hook("customhook-early-for", ast, binding_sym, sub_scope) for i = 1, math.min(#ranges, 3) do range_args[i] = tostring(compiler.compile1(ranges[i], scope, parent, {nval = 1})[1]) @@ -1610,10 +1632,10 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct SPECIALS["for"] = for_2a doc_special("for", {"[index start stop step?]", "..."}, "Numeric loop construct.\nEvaluates body once for each value between start and stop (inclusive).", true) local function native_method_call(ast, _scope, _parent, target, args) - local _484_ = ast - local _ = _484_[1] - local _0 = _484_[2] - local method_string = _484_[3] + local _494_ = ast + local _ = _494_[1] + local _0 = _494_[2] + local method_string = _494_[3] local call_string = nil if ((target.type == "literal") or (target.type == "varg") or (target.type == "expression")) then call_string = "(%s):%s(%s)" @@ -1635,18 +1657,18 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end local function method_call(ast, scope, parent) compiler.assert((2 < #ast), "expected at least 2 arguments", ast) - local _486_ = compiler.compile1(ast[2], scope, parent, {nval = 1}) - local target = _486_[1] + local _496_ = compiler.compile1(ast[2], scope, parent, {nval = 1}) + local target = _496_[1] local args = {} for i = 4, #ast do local subexprs = nil - local _487_ + local _497_ if (i ~= #ast) then - _487_ = 1 + _497_ = 1 else - _487_ = nil + _497_ = nil end - subexprs = compiler.compile1(ast[i], scope, parent, {nval = _487_}) + subexprs = compiler.compile1(ast[i], scope, parent, {nval = _497_}) utils.map(subexprs, tostring, args) end if (utils["string?"](ast[3]) and utils["valid-lua-identifier?"](ast[3])) then @@ -1660,11 +1682,27 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct SPECIALS[":"] = method_call doc_special(":", {"tbl", "method-name", "..."}, "Call the named method on tbl with the provided args.\nMethod name doesn't have to be known at compile-time; if it is, use\n(tbl:method-name ...) instead.") SPECIALS.comment = function(ast, _, parent) - local els = {} - for i = 2, #ast do - table.insert(els, view(ast[i], {["one-line?"] = true})) + local c = nil + local _500_ + do + local tbl_17_ = {} + local i_18_ = #tbl_17_ + for i, elt in ipairs(ast) do + local val_19_ = nil + if (i ~= 1) then + val_19_ = view(ast[i], {["one-line?"] = true}) + else + val_19_ = nil + end + if (nil ~= val_19_) then + i_18_ = (i_18_ + 1) + tbl_17_[i_18_] = val_19_ + end + end + _500_ = tbl_17_ end - return compiler.emit(parent, ("--[[ " .. table.concat(els, " ") .. " ]]"), ast) + c = table.concat(_500_, " "):gsub("%]%]", "]\\]") + return compiler.emit(parent, ("--[[ " .. c .. " ]]"), ast) end doc_special("comment", {"..."}, "Comment which will be emitted in Lua output.", true) local function hashfn_max_used(f_scope, i, max) @@ -1684,10 +1722,10 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct compiler.assert((#ast == 2), "expected one argument", ast) local f_scope = nil do - local _492_0 = compiler["make-scope"](scope) - _492_0["vararg"] = false - _492_0["hashfn"] = true - f_scope = _492_0 + local _505_0 = compiler["make-scope"](scope) + _505_0["vararg"] = false + _505_0["hashfn"] = true + f_scope = _505_0 end local f_chunk = {} local name = compiler.gensym(scope) @@ -1697,16 +1735,20 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct for i = 1, 9 do args[i] = compiler["declare-local"](utils.sym(("$" .. i)), {}, f_scope, ast) end - local function walker(idx, node, parent_node) - if (utils["sym?"](node) and (tostring(node) == "$...")) then - parent_node[idx] = utils.varg() + local function walker(idx, node, _3fparent_node) + if utils["sym?"](node, "$...") then f_scope.vararg = true - return nil + if _3fparent_node then + _3fparent_node[idx] = utils.varg() + return nil + else + return utils.varg() + end else - return (("table" == type(node)) and (utils.sym("hashfn") ~= node[1]) and (utils["list?"](node) or utils["table?"](node))) + return ((utils["list?"](node) and (not _3fparent_node or not utils["sym?"](node[1], "hashfn"))) or utils["table?"](node)) end end - utils["walk-tree"](ast[2], walker) + utils["walk-tree"](ast, walker) compiler.compile1(ast[2], f_scope, f_chunk, {tail = true}) local max_used = hashfn_max_used(f_scope, 1, 0) if f_scope.vararg then @@ -1724,9 +1766,9 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct return utils.expr(name, "sym") end doc_special("hashfn", {"..."}, "Function literal shorthand; args are either $... OR $1, $2, etc.") - local function maybe_short_circuit_protect(ast, i, name, _496_0) - local _497_ = _496_0 - local mac = _497_["macros"] + local function maybe_short_circuit_protect(ast, i, name, _510_0) + local _511_ = _510_0 + local mac = _511_["macros"] local call = (utils["list?"](ast) and tostring(ast[1])) if ((("or" == name) or ("and" == name)) and (1 < i) and (mac[call] or ("set" == call) or ("tset" == call) or ("global" == call))) then return utils.list(utils.sym("do"), ast) @@ -1747,35 +1789,37 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct table.insert(operands, tostring(subexprs[1])) end end - local _500_0 = #operands - if (_500_0 == 0) then - local _501_ + local _514_0 = #operands + if (_514_0 == 0) then + local _515_ do compiler.assert(zero_arity, "Expected more than 0 arguments", ast) - _501_ = zero_arity + _515_ = zero_arity end - return utils.expr(_501_, "literal") - elseif (_500_0 == 1) then - if unary_prefix then + return utils.expr(_515_, "literal") + elseif (_514_0 == 1) then + if utils["varg?"](ast[2]) then + return compiler.assert(false, "tried to use vararg with operator", ast) + elseif unary_prefix then return ("(" .. unary_prefix .. padded_op .. operands[1] .. ")") else return operands[1] end else - local _ = _500_0 + local _ = _514_0 return ("(" .. table.concat(operands, padded_op) .. ")") end end local function define_arithmetic_special(name, zero_arity, unary_prefix, _3flua_name) - local _505_ + local _519_ do - local _504_0 = (_3flua_name or name) - local function _506_(...) - return arithmetic_special(_504_0, zero_arity, unary_prefix, ...) + local _518_0 = (_3flua_name or name) + local function _520_(...) + return arithmetic_special(_518_0, zero_arity, unary_prefix, ...) end - _505_ = _506_ + _519_ = _520_ end - SPECIALS[name] = _505_ + SPECIALS[name] = _519_ return doc_special(name, {"a", "b", "..."}, "Arithmetic operator; works the same as Lua but accepts more arguments.") end define_arithmetic_special("+", "0") @@ -1804,13 +1848,13 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct local prefixed_lib_name = ("bit." .. lib_name) for i = 2, len do local subexprs = nil - local _507_ + local _521_ if (i ~= len) then - _507_ = 1 + _521_ = 1 else - _507_ = nil + _521_ = nil end - subexprs = compiler.compile1(ast[i], scope, parent, {nval = _507_}) + subexprs = compiler.compile1(ast[i], scope, parent, {nval = _521_}) utils.map(subexprs, tostring, operands) end if (#operands == 1) then @@ -1829,10 +1873,10 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end end local function define_bitop_special(name, zero_arity, unary_prefix, native) - local function _513_(...) + local function _527_(...) return bitop_special(native, name, zero_arity, unary_prefix, ...) end - SPECIALS[name] = _513_ + SPECIALS[name] = _527_ return nil end define_bitop_special("lshift", nil, "1", "<<") @@ -1845,16 +1889,27 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct doc_special("band", {"x1", "x2", "..."}, "Bitwise AND of any number of arguments.\nOnly works in Lua 5.3+ or LuaJIT with the --use-bit-lib flag.") doc_special("bor", {"x1", "x2", "..."}, "Bitwise OR of any number of arguments.\nOnly works in Lua 5.3+ or LuaJIT with the --use-bit-lib flag.") doc_special("bxor", {"x1", "x2", "..."}, "Bitwise XOR of any number of arguments.\nOnly works in Lua 5.3+ or LuaJIT with the --use-bit-lib flag.") + SPECIALS.bnot = function(ast, scope, parent) + compiler.assert((#ast == 2), "expected one argument", ast) + local _528_ = compiler.compile1(ast[2], scope, parent, {nval = 1}) + local value = _528_[1] + if utils.root.options.useBitLib then + return ("bit.bnot(" .. tostring(value) .. ")") + else + return ("~(" .. tostring(value) .. ")") + end + end + doc_special("bnot", {"x"}, "Bitwise negation; only works in Lua 5.3+ or LuaJIT with the --use-bit-lib flag.") doc_special("..", {"a", "b", "..."}, "String concatenation operator; works the same as Lua but accepts more arguments.") - local function native_comparator(op, _514_0, scope, parent) - local _515_ = _514_0 - local _ = _515_[1] - local lhs_ast = _515_[2] - local rhs_ast = _515_[3] - local _516_ = compiler.compile1(lhs_ast, scope, parent, {nval = 1}) - local lhs = _516_[1] - local _517_ = compiler.compile1(rhs_ast, scope, parent, {nval = 1}) - local rhs = _517_[1] + local function native_comparator(op, _530_0, scope, parent) + local _531_ = _530_0 + local _ = _531_[1] + local lhs_ast = _531_[2] + local rhs_ast = _531_[3] + local _532_ = compiler.compile1(lhs_ast, scope, parent, {nval = 1}) + local lhs = _532_[1] + local _533_ = compiler.compile1(rhs_ast, scope, parent, {nval = 1}) + local rhs = _533_[1] return string.format("(%s %s %s)", tostring(lhs), op, tostring(rhs)) end local function idempotent_comparator(op, chain_op, ast, scope, parent) @@ -1885,7 +1940,7 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct comparisons = tbl_17_ end local chain = string.format(" %s ", (chain_op or "and")) - return table.concat(comparisons, chain) + return ("(" .. table.concat(comparisons, chain) .. ")") end local function double_eval_protected_comparator(op, chain_op, ast, scope, parent) local arglist = {} @@ -1943,8 +1998,6 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end define_unary_special("not", "not ") doc_special("not", {"x"}, "Logical operator; works the same as Lua.") - define_unary_special("bnot", "~") - doc_special("bnot", {"x"}, "Bitwise negation; only works in Lua 5.3+ or LuaJIT with the --use-bit-lib flag.") define_unary_special("length", "#") doc_special("length", {"x"}, "Returns the length of a table or string.") SPECIALS["~="] = SPECIALS["not="] @@ -1969,21 +2022,21 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end local safe_require = nil local function safe_compiler_env() - local _524_ + local _540_ do - local _523_0 = rawget(_G, "utf8") - if (nil ~= _523_0) then - _524_ = utils.copy(_523_0) + local _539_0 = rawget(_G, "utf8") + if (nil ~= _539_0) then + _540_ = utils.copy(_539_0) else - _524_ = _523_0 + _540_ = _539_0 end end - return {_VERSION = _VERSION, assert = assert, bit = rawget(_G, "bit"), error = error, getmetatable = safe_getmetatable, ipairs = ipairs, math = utils.copy(math), next = next, pairs = utils.stablepairs, pcall = pcall, print = print, rawequal = rawequal, rawget = rawget, rawlen = rawget(_G, "rawlen"), rawset = rawset, require = safe_require, select = select, setmetatable = setmetatable, string = utils.copy(string), table = utils.copy(table), tonumber = tonumber, tostring = tostring, type = type, utf8 = _524_, xpcall = xpcall} + return {_VERSION = _VERSION, assert = assert, bit = rawget(_G, "bit"), error = error, getmetatable = safe_getmetatable, ipairs = ipairs, math = utils.copy(math), next = next, pairs = utils.stablepairs, pcall = pcall, print = print, rawequal = rawequal, rawget = rawget, rawlen = rawget(_G, "rawlen"), rawset = rawset, require = safe_require, select = select, setmetatable = setmetatable, string = utils.copy(string), table = utils.copy(table), tonumber = tonumber, tostring = tostring, type = type, utf8 = _540_, xpcall = xpcall} end local function combined_mt_pairs(env) local combined = {} - local _526_ = getmetatable(env) - local __index = _526_["__index"] + local _542_ = getmetatable(env) + local __index = _542_["__index"] if ("table" == type(__index)) then for k, v in pairs(__index) do combined[k] = v @@ -1997,40 +2050,40 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct local function make_compiler_env(ast, scope, parent, _3fopts) local provided = nil do - local _528_0 = (_3fopts or utils.root.options) - if ((_G.type(_528_0) == "table") and (_528_0["compiler-env"] == "strict")) then + local _544_0 = (_3fopts or utils.root.options) + if ((_G.type(_544_0) == "table") and (_544_0["compiler-env"] == "strict")) then provided = safe_compiler_env() - elseif ((_G.type(_528_0) == "table") and (nil ~= _528_0.compilerEnv)) then - local compilerEnv = _528_0.compilerEnv + elseif ((_G.type(_544_0) == "table") and (nil ~= _544_0.compilerEnv)) then + local compilerEnv = _544_0.compilerEnv provided = compilerEnv - elseif ((_G.type(_528_0) == "table") and (nil ~= _528_0["compiler-env"])) then - local compiler_env = _528_0["compiler-env"] + elseif ((_G.type(_544_0) == "table") and (nil ~= _544_0["compiler-env"])) then + local compiler_env = _544_0["compiler-env"] provided = compiler_env else - local _ = _528_0 + local _ = _544_0 provided = safe_compiler_env(false) end end local env = nil - local function _530_() + local function _546_() return compiler.scopes.macro end - local function _531_(symbol) + local function _547_(symbol) compiler.assert(compiler.scopes.macro, "must call from macro", ast) return compiler.scopes.macro.manglings[tostring(symbol)] end - local function _532_(base) + local function _548_(base) return utils.sym(compiler.gensym((compiler.scopes.macro or scope), base)) end - local function _533_(form) + local function _549_(form) compiler.assert(compiler.scopes.macro, "must call from macro", ast) return compiler.macroexpand(form, compiler.scopes.macro) end - env = {["assert-compile"] = compiler.assert, ["ast-source"] = utils["ast-source"], ["comment?"] = utils["comment?"], ["get-scope"] = _530_, ["in-scope?"] = _531_, ["list?"] = utils["list?"], ["macro-loaded"] = macro_loaded, ["multi-sym?"] = utils["multi-sym?"], ["sequence?"] = utils["sequence?"], ["sym?"] = utils["sym?"], ["table?"] = utils["table?"], ["varg?"] = utils["varg?"], _AST = ast, _CHUNK = parent, _IS_COMPILER = true, _SCOPE = scope, _SPECIALS = compiler.scopes.global.specials, _VARARG = utils.varg(), comment = utils.comment, gensym = _532_, list = utils.list, macroexpand = _533_, metadata = compiler.metadata, sequence = utils.sequence, sym = utils.sym, unpack = unpack, version = utils.version, view = view} + env = {["assert-compile"] = compiler.assert, ["ast-source"] = utils["ast-source"], ["comment?"] = utils["comment?"], ["get-scope"] = _546_, ["in-scope?"] = _547_, ["list?"] = utils["list?"], ["macro-loaded"] = macro_loaded, ["multi-sym?"] = utils["multi-sym?"], ["sequence?"] = utils["sequence?"], ["sym?"] = utils["sym?"], ["table?"] = utils["table?"], ["varg?"] = utils["varg?"], _AST = ast, _CHUNK = parent, _IS_COMPILER = true, _SCOPE = scope, _SPECIALS = compiler.scopes.global.specials, _VARARG = utils.varg(), comment = utils.comment, gensym = _548_, list = utils.list, macroexpand = _549_, metadata = compiler.metadata, sequence = utils.sequence, sym = utils.sym, unpack = unpack, version = utils.version, view = view} env._G = env return setmetatable(env, {__index = provided, __newindex = provided, __pairs = combined_mt_pairs}) end - local function _534_(...) + local function _550_(...) local tbl_17_ = {} local i_18_ = #tbl_17_ for c in string.gmatch((package.config or ""), "([^\n]+)") do @@ -2042,11 +2095,11 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end return tbl_17_ end - local _536_ = _534_(...) - local dirsep = _536_[1] - local pathsep = _536_[2] - local pathmark = _536_[3] - local pkg_config = {dirsep = (dirsep or "/"), pathmark = (pathmark or ";"), pathsep = (pathsep or "?")} + local _552_ = _550_(...) + local dirsep = _552_[1] + local pathsep = _552_[2] + local pathmark = _552_[3] + local pkg_config = {dirsep = (dirsep or "/"), pathmark = (pathmark or "?"), pathsep = (pathsep or ";")} local function escapepat(str) return string.gsub(str, "[^%w]", "%%%1") end @@ -2058,36 +2111,36 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct local function try_path(path) local filename = path:gsub(escapepat(pkg_config.pathmark), no_dot_module) local filename2 = path:gsub(escapepat(pkg_config.pathmark), modulename) - local _537_0 = (io.open(filename) or io.open(filename2)) - if (nil ~= _537_0) then - local file = _537_0 + local _553_0 = (io.open(filename) or io.open(filename2)) + if (nil ~= _553_0) then + local file = _553_0 file:close() return filename else - local _ = _537_0 + local _ = _553_0 return nil, ("no file '" .. filename .. "'") end end local function find_in_path(start, _3ftried_paths) - local _539_0 = fullpath:match(pattern, start) - if (nil ~= _539_0) then - local path = _539_0 - local _540_0, _541_0 = try_path(path) - if (nil ~= _540_0) then - local filename = _540_0 + local _555_0 = fullpath:match(pattern, start) + if (nil ~= _555_0) then + local path = _555_0 + local _556_0, _557_0 = try_path(path) + if (nil ~= _556_0) then + local filename = _556_0 return filename - elseif ((_540_0 == nil) and (nil ~= _541_0)) then - local error = _541_0 - local function _543_() - local _542_0 = (_3ftried_paths or {}) - table.insert(_542_0, error) - return _542_0 + elseif ((_556_0 == nil) and (nil ~= _557_0)) then + local error = _557_0 + local function _559_() + local _558_0 = (_3ftried_paths or {}) + table.insert(_558_0, error) + return _558_0 end - return find_in_path((start + #path + 1), _543_()) + return find_in_path((start + #path + 1), _559_()) end else - local _ = _539_0 - local function _545_() + local _ = _555_0 + local function _561_() local tried_paths = table.concat((_3ftried_paths or {}), "\n\9") if (_VERSION < "Lua 5.4") then return ("\n\9" .. tried_paths) @@ -2095,31 +2148,31 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct return tried_paths end end - return nil, _545_() + return nil, _561_() end end return find_in_path(1) end local function make_searcher(_3foptions) - local function _548_(module_name) + local function _564_(module_name) local opts = utils.copy(utils.root.options) for k, v in pairs((_3foptions or {})) do opts[k] = v end opts["module-name"] = module_name - local _549_0, _550_0 = search_module(module_name) - if (nil ~= _549_0) then - local filename = _549_0 - local function _551_(...) + local _565_0, _566_0 = search_module(module_name) + if (nil ~= _565_0) then + local filename = _565_0 + local function _567_(...) return utils["fennel-module"].dofile(filename, opts, ...) end - return _551_, filename - elseif ((_549_0 == nil) and (nil ~= _550_0)) then - local error = _550_0 + return _567_, filename + elseif ((_565_0 == nil) and (nil ~= _566_0)) then + local error = _566_0 return error end end - return _548_ + return _564_ end local function dofile_with_searcher(fennel_macro_searcher, filename, opts, ...) local searchers = (package.loaders or package.searchers or {}) @@ -2131,35 +2184,35 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct local function fennel_macro_searcher(module_name) local opts = nil do - local _553_0 = utils.copy(utils.root.options) - _553_0["module-name"] = module_name - _553_0["env"] = "_COMPILER" - _553_0["requireAsInclude"] = false - _553_0["allowedGlobals"] = nil - opts = _553_0 + local _569_0 = utils.copy(utils.root.options) + _569_0["module-name"] = module_name + _569_0["env"] = "_COMPILER" + _569_0["requireAsInclude"] = false + _569_0["allowedGlobals"] = nil + opts = _569_0 end - local _554_0 = search_module(module_name, utils["fennel-module"]["macro-path"]) - if (nil ~= _554_0) then - local filename = _554_0 - local _555_ + local _570_0 = search_module(module_name, utils["fennel-module"]["macro-path"]) + if (nil ~= _570_0) then + local filename = _570_0 + local _571_ if (opts["compiler-env"] == _G) then - local function _556_(...) + local function _572_(...) return dofile_with_searcher(fennel_macro_searcher, filename, opts, ...) end - _555_ = _556_ + _571_ = _572_ else - local function _557_(...) + local function _573_(...) return utils["fennel-module"].dofile(filename, opts, ...) end - _555_ = _557_ + _571_ = _573_ end - return _555_, filename + return _571_, filename end end local function lua_macro_searcher(module_name) - local _560_0 = search_module(module_name, package.path) - if (nil ~= _560_0) then - local filename = _560_0 + local _576_0 = search_module(module_name, package.path) + if (nil ~= _576_0) then + local filename = _576_0 local code = nil do local f = io.open(filename) @@ -2171,10 +2224,10 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct return error(..., 0) end end - local function _562_() + local function _578_() return assert(f:read("*a")) end - code = close_handlers_10_(_G.xpcall(_562_, (package.loaded.fennel or debug).traceback)) + code = close_handlers_10_(_G.xpcall(_578_, (package.loaded.fennel or debug).traceback)) end local chunk = load_code(code, make_compiler_env(), filename) return chunk, filename @@ -2182,16 +2235,16 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end local macro_searchers = {fennel_macro_searcher, lua_macro_searcher} local function search_macro_module(modname, n) - local _564_0 = macro_searchers[n] - if (nil ~= _564_0) then - local f = _564_0 - local _565_0, _566_0 = f(modname) - if ((nil ~= _565_0) and true) then - local loader = _565_0 - local _3ffilename = _566_0 + local _580_0 = macro_searchers[n] + if (nil ~= _580_0) then + local f = _580_0 + local _581_0, _582_0 = f(modname) + if ((nil ~= _581_0) and true) then + local loader = _581_0 + local _3ffilename = _582_0 return loader, _3ffilename else - local _ = _565_0 + local _ = _581_0 return search_macro_module(modname, (n + 1)) end end @@ -2201,16 +2254,16 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct return {metadata = compiler.metadata, view = view} end end - local function _570_(modname) - local function _571_() + local function _586_(modname) + local function _587_() local loader, filename = search_macro_module(modname, 1) compiler.assert(loader, (modname .. " module not found.")) macro_loaded[modname] = loader(modname, filename) return macro_loaded[modname] end - return (macro_loaded[modname] or sandbox_fennel_module(modname) or _571_()) + return (macro_loaded[modname] or sandbox_fennel_module(modname) or _587_()) end - safe_require = _570_ + safe_require = _586_ local function add_macros(macros_2a, ast, scope) compiler.assert(utils["table?"](macros_2a), "expected macros to be table", ast) for k, v in pairs(macros_2a) do @@ -2220,10 +2273,10 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end return nil end - local function resolve_module_name(_572_0, _scope, _parent, opts) - local _573_ = _572_0 - local second = _573_[2] - local filename = _573_["filename"] + local function resolve_module_name(_588_0, _scope, _parent, opts) + local _589_ = _588_0 + local second = _589_[2] + local filename = _589_["filename"] local filename0 = (filename or (utils["table?"](second) and second.filename)) local module_name = utils.root.options["module-name"] local modexpr = compiler.compile(second, opts) @@ -2280,10 +2333,10 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct return error(..., 0) end end - local function _579_() + local function _595_() return assert(f:read("*all")):gsub("[\13\n]*$", "") end - src = close_handlers_10_(_G.xpcall(_579_, (package.loaded.fennel or debug).traceback)) + src = close_handlers_10_(_G.xpcall(_595_, (package.loaded.fennel or debug).traceback)) end local ret = utils.expr(("require(\"" .. mod .. "\")"), "statement") local target = ("package.preload[%q]"):format(mod) @@ -2313,12 +2366,12 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct compiler.assert((#ast == 2), "expected one argument", ast) local modexpr = nil do - local _582_0, _583_0 = pcall(resolve_module_name, ast, scope, parent, opts) - if ((_582_0 == true) and (nil ~= _583_0)) then - local modname = _583_0 + local _598_0, _599_0 = pcall(resolve_module_name, ast, scope, parent, opts) + if ((_598_0 == true) and (nil ~= _599_0)) then + local modname = _599_0 modexpr = utils.expr(string.format("%q", modname), "literal") else - local _ = _582_0 + local _ = _598_0 modexpr = compiler.compile1(ast[2], scope, parent, {nval = 1})[1] end end @@ -2335,13 +2388,13 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct utils.root.options["module-name"] = mod _ = nil local res = nil - local function _587_() - local _586_0 = search_module(mod) - if (nil ~= _586_0) then - local fennel_path = _586_0 + local function _603_() + local _602_0 = search_module(mod) + if (nil ~= _602_0) then + local fennel_path = _602_0 return include_path(ast, opts, fennel_path, mod, true) else - local _0 = _586_0 + local _0 = _602_0 local lua_path = search_module(mod, package.path) if lua_path then return include_path(ast, opts, lua_path, mod, false) @@ -2352,7 +2405,7 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end end end - res = ((utils["member?"](mod, (utils.root.options.skipInclude or {})) and opts.fallback(modexpr, true)) or include_circular_fallback(mod, modexpr, opts.fallback, ast) or utils.root.scope.includes[mod] or _587_()) + res = ((utils["member?"](mod, (utils.root.options.skipInclude or {})) and opts.fallback(modexpr, true)) or include_circular_fallback(mod, modexpr, opts.fallback, ast) or utils.root.scope.includes[mod] or _603_()) utils.root.options["module-name"] = oldmod return res end @@ -2363,11 +2416,13 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct local opts = utils.copy(utils.root.options) opts.scope = compiler["make-scope"](compiler.scopes.compiler) opts.allowedGlobals = current_global_names(env) - return assert(load_code(compiler.compile(ast, opts), wrap_env(env)), opts["module-name"], ast.filename)() + return assert(load_code(compiler.compile(ast, opts), wrap_env(env)))(opts["module-name"], ast.filename) end SPECIALS.macros = function(ast, scope, parent) - compiler.assert(((#ast == 2) and utils["table?"](ast[2])), "Expected one table argument", ast) - return add_macros(eval_compiler_2a(ast[2], scope, parent), ast, scope, parent) + compiler.assert((#ast == 2), "Expected one table argument", ast) + local macro_tbl = eval_compiler_2a(ast[2], scope, parent) + compiler.assert(utils["table?"](macro_tbl), "Expected one table argument", ast) + return add_macros(macro_tbl, ast, scope, parent) end doc_special("macros", {"{:macro-name-1 (fn [...] ...) ... :macro-name-N macro-body-N}"}, "Define all functions in the given table as macros local to the current scope.") SPECIALS["eval-compiler"] = function(ast, scope, parent) @@ -2378,6 +2433,10 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct return val end doc_special("eval-compiler", {"..."}, "Evaluate the body at compile-time. Use the macro system instead if possible.", true) + SPECIALS.unquote = function(ast) + return compiler.assert(false, "tried to use unquote outside quote", ast) + end + doc_special("unquote", {"..."}, "Evaluate the argument even if it's in a quoted form.") return {["current-global-names"] = current_global_names, ["load-code"] = load_code, ["macro-loaded"] = macro_loaded, ["macro-searchers"] = macro_searchers, ["make-compiler-env"] = make_compiler_env, ["make-searcher"] = make_searcher, ["search-module"] = search_module, ["wrap-env"] = wrap_env, doc = doc_2a} end package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or function(...) @@ -2388,13 +2447,13 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct local scopes = {} local function make_scope(_3fparent) local parent = (_3fparent or scopes.global) - local _252_ + local _261_ if parent then - _252_ = ((parent.depth or 0) + 1) + _261_ = ((parent.depth or 0) + 1) else - _252_ = 0 + _261_ = 0 end - return {autogensyms = setmetatable({}, {__index = (parent and parent.autogensyms)}), depth = _252_, gensyms = setmetatable({}, {__index = (parent and parent.gensyms)}), hashfn = (parent and parent.hashfn), includes = setmetatable({}, {__index = (parent and parent.includes)}), macros = setmetatable({}, {__index = (parent and parent.macros)}), manglings = setmetatable({}, {__index = (parent and parent.manglings)}), parent = parent, refedglobals = {}, specials = setmetatable({}, {__index = (parent and parent.specials)}), symmeta = setmetatable({}, {__index = (parent and parent.symmeta)}), unmanglings = setmetatable({}, {__index = (parent and parent.unmanglings)}), vararg = (parent and parent.vararg)} + return {["gensym-base"] = setmetatable({}, {__index = (parent and parent["gensym-base"])}), autogensyms = setmetatable({}, {__index = (parent and parent.autogensyms)}), depth = _261_, gensyms = setmetatable({}, {__index = (parent and parent.gensyms)}), hashfn = (parent and parent.hashfn), includes = setmetatable({}, {__index = (parent and parent.includes)}), macros = setmetatable({}, {__index = (parent and parent.macros)}), manglings = setmetatable({}, {__index = (parent and parent.manglings)}), parent = parent, refedglobals = {}, specials = setmetatable({}, {__index = (parent and parent.specials)}), symmeta = setmetatable({}, {__index = (parent and parent.symmeta)}), unmanglings = setmetatable({}, {__index = (parent and parent.unmanglings)}), vararg = (parent and parent.vararg)} end local function assert_msg(ast, msg) local ast_tbl = nil @@ -2412,10 +2471,10 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct end local function assert_compile(condition, msg, ast, _3ffallback_ast) if not condition then - local _255_ = (utils.root.options or {}) - local error_pinpoint = _255_["error-pinpoint"] - local source = _255_["source"] - local unfriendly = _255_["unfriendly"] + local _264_ = (utils.root.options or {}) + local error_pinpoint = _264_["error-pinpoint"] + local source = _264_["source"] + local unfriendly = _264_["unfriendly"] local ast0 = nil if next(utils["ast-source"](ast)) then ast0 = ast @@ -2424,7 +2483,7 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct end if (nil == utils.hook("assert-compile", condition, msg, ast0, utils.root.reset)) then utils.root.reset() - if (unfriendly or not friend or not _G.io or not _G.io.read) then + if unfriendly then error(assert_msg(ast0, msg), 0) else friend["assert-compile"](condition, msg, ast0, source, {["error-pinpoint"] = error_pinpoint}) @@ -2439,33 +2498,33 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct scopes.macro = scopes.global local serialize_subst = {["\11"] = "\\v", ["\12"] = "\\f", ["\7"] = "\\a", ["\8"] = "\\b", ["\9"] = "\\t", ["\n"] = "n"} local function serialize_string(str) - local function _260_(_241) + local function _269_(_241) return ("\\" .. _241:byte()) end - return string.gsub(string.gsub(string.format("%q", str), ".", serialize_subst), "[\128-\255]", _260_) + return string.gsub(string.gsub(string.format("%q", str), ".", serialize_subst), "[\128-\255]", _269_) end local function global_mangling(str) if utils["valid-lua-identifier?"](str) then return str else - local function _261_(_241) + local function _270_(_241) return string.format("_%02x", _241:byte()) end - return ("__fnl_global__" .. str:gsub("[^%w]", _261_)) + return ("__fnl_global__" .. str:gsub("[^%w]", _270_)) end end local function global_unmangling(identifier) - local _263_0 = string.match(identifier, "^__fnl_global__(.*)$") - if (nil ~= _263_0) then - local rest = _263_0 - local _264_0 = nil - local function _265_(_241) + local _272_0 = string.match(identifier, "^__fnl_global__(.*)$") + if (nil ~= _272_0) then + local rest = _272_0 + local _273_0 = nil + local function _274_(_241) return string.char(tonumber(_241:sub(2), 16)) end - _264_0 = string.gsub(rest, "_[%da-f][%da-f]", _265_) - return _264_0 + _273_0 = string.gsub(rest, "_[%da-f][%da-f]", _274_) + return _273_0 else - local _ = _263_0 + local _ = _272_0 return identifier end end @@ -2474,7 +2533,7 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct return (not allowed_globals or utils["member?"](name, allowed_globals)) end local function unique_mangling(original, mangling, scope, append) - if (scope.unmanglings[mangling] and not scope.gensyms[mangling]) then + if scope.unmanglings[mangling] then return unique_mangling(original, (original .. append), scope, (append + 1)) else return mangling @@ -2489,12 +2548,12 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct raw = str end local mangling = nil - local function _269_(_241) + local function _278_(_241) return string.format("_%02x", _241:byte()) end - mangling = string.gsub(string.gsub(raw, "-", "_"), "[^%w_]", _269_) + mangling = string.gsub(string.gsub(raw, "-", "_"), "[^%w_]", _278_) local unique = unique_mangling(mangling, mangling, scope, 0) - scope.unmanglings[unique] = str + scope.unmanglings[unique] = (scope["gensym-base"][str] or str) do local manglings = (_3ftemp_manglings or scope.manglings) manglings[str] = unique @@ -2532,7 +2591,9 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct while scope.unmanglings[mangling] do mangling = ((_3fbase or "") .. next_append() .. (_3fsuffix or "")) end - scope.unmanglings[mangling] = (_3fbase or true) + if (_3fbase and (0 < #_3fbase)) then + scope["gensym-base"][mangling] = _3fbase + end scope.gensyms[mangling] = true return mangling end @@ -2545,29 +2606,29 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct return table.concat(parts, ".") end local function autogensym(base, scope) - local _272_0 = utils["multi-sym?"](base) - if (nil ~= _272_0) then - local parts = _272_0 + local _282_0 = utils["multi-sym?"](base) + if (nil ~= _282_0) then + local parts = _282_0 return combine_auto_gensym(parts, autogensym(parts[1], scope)) else - local _ = _272_0 - local function _273_() + local _ = _282_0 + local function _283_() local mangling = gensym(scope, base:sub(1, ( - 2)), "auto") scope.autogensyms[base] = mangling return mangling end - return (scope.autogensyms[base] or _273_()) + return (scope.autogensyms[base] or _283_()) end end local function check_binding_valid(symbol, scope, ast, _3fopts) local name = tostring(symbol) local macro_3f = nil do - local _275_0 = _3fopts - if (nil ~= _275_0) then - _275_0 = _275_0["macro?"] + local _285_0 = _3fopts + if (nil ~= _285_0) then + _285_0 = _285_0["macro?"] end - macro_3f = _275_0 + macro_3f = _285_0 end assert_compile(not name:find("&"), "invalid character: &", symbol) assert_compile(not name:find("^%."), "invalid character: .", symbol) @@ -2665,22 +2726,22 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct end local function flatten_chunk(file_sourcemap, chunk, tab, depth) if chunk.leaf then - local _287_ = utils["ast-source"](chunk.ast) - local filename = _287_["filename"] - local line = _287_["line"] + local _297_ = utils["ast-source"](chunk.ast) + local filename = _297_["filename"] + local line = _297_["line"] table.insert(file_sourcemap, {filename, line}) return chunk.leaf else local tab0 = nil do - local _288_0 = tab - if (_288_0 == true) then + local _298_0 = tab + if (_298_0 == true) then tab0 = " " - elseif (_288_0 == false) then + elseif (_298_0 == false) then tab0 = "" - elseif (_288_0 == tab) then + elseif (_298_0 == tab) then tab0 = tab - elseif (_288_0 == nil) then + elseif (_298_0 == nil) then tab0 = "" else tab0 = nil @@ -2726,17 +2787,21 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct end end local function make_metadata() - local function _296_(self, tgt, key) + local function _306_(self, tgt, _3fkey) if self[tgt] then - return self[tgt][key] + if (nil ~= _3fkey) then + return self[tgt][_3fkey] + else + return self[tgt] + end end end - local function _298_(self, tgt, key, value) + local function _309_(self, tgt, key, value) self[tgt] = (self[tgt] or {}) self[tgt][key] = value return tgt end - local function _299_(self, tgt, ...) + local function _310_(self, tgt, ...) local kv_len = select("#", ...) local kvs = {...} if ((kv_len % 2) ~= 0) then @@ -2748,7 +2813,7 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct end return tgt end - return setmetatable({}, {__index = {get = _296_, set = _298_, setall = _299_}, __mode = "k"}) + return setmetatable({}, {__index = {get = _306_, set = _309_, setall = _310_}, __mode = "k"}) end local function exprs1(exprs) return table.concat(utils.map(exprs, tostring), ", ") @@ -2794,14 +2859,14 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct end if opts.target then local result = exprs1(exprs) - local function _307_() + local function _318_() if (result == "") then return "nil" else return result end end - emit(parent, string.format("%s = %s", opts.target, _307_()), ast) + emit(parent, string.format("%s = %s", opts.target, _318_()), ast) end if (opts.tail or opts.target) then return {returned = true} @@ -2813,16 +2878,16 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct local function find_macro(ast, scope) local macro_2a = nil do - local _310_0 = utils["sym?"](ast[1]) - if (_310_0 ~= nil) then - local _311_0 = tostring(_310_0) - if (_311_0 ~= nil) then - macro_2a = scope.macros[_311_0] + local _321_0 = utils["sym?"](ast[1]) + if (_321_0 ~= nil) then + local _322_0 = tostring(_321_0) + if (_322_0 ~= nil) then + macro_2a = scope.macros[_322_0] else - macro_2a = _311_0 + macro_2a = _322_0 end else - macro_2a = _310_0 + macro_2a = _321_0 end end local multi_sym_parts = utils["multi-sym?"](ast[1]) @@ -2834,12 +2899,12 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct return macro_2a end end - local function propagate_trace_info(_315_0, _index, node) - local _316_ = _315_0 - local byteend = _316_["byteend"] - local bytestart = _316_["bytestart"] - local filename = _316_["filename"] - local line = _316_["line"] + local function propagate_trace_info(_326_0, _index, node) + local _327_ = _326_0 + local byteend = _327_["byteend"] + local bytestart = _327_["bytestart"] + local filename = _327_["filename"] + local line = _327_["line"] do local src = utils["ast-source"](node) if (("table" == type(node)) and (filename ~= src.filename)) then @@ -2852,8 +2917,8 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct local function quote_literal_nils(index, node, parent) if (parent and utils["list?"](parent)) then for i = 1, utils.maxn(parent) do - local _318_0 = parent[i] - if (_318_0 == nil) then + local _329_0 = parent[i] + if (_329_0 == nil) then parent[i] = utils.sym("nil") end end @@ -2861,10 +2926,10 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct return index, node, parent end local function comp(f, g) - local function _321_(...) + local function _332_(...) return f(g(...)) end - return _321_ + return _332_ end local function built_in_3f(m) local found_3f = false @@ -2875,36 +2940,36 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct return found_3f end local function macroexpand_2a(ast, scope, _3fonce) - local _322_0 = nil + local _333_0 = nil if utils["list?"](ast) then - _322_0 = find_macro(ast, scope) + _333_0 = find_macro(ast, scope) else - _322_0 = nil + _333_0 = nil end - if (_322_0 == false) then + if (_333_0 == false) then return ast - elseif (nil ~= _322_0) then - local macro_2a = _322_0 + elseif (nil ~= _333_0) then + local macro_2a = _333_0 local old_scope = scopes.macro local _ = nil scopes.macro = scope _ = nil local ok, transformed = nil, nil - local function _324_() + local function _335_() return macro_2a(unpack(ast, 2)) end - local function _325_() + local function _336_() if built_in_3f(macro_2a) then return tostring else return debug.traceback end end - ok, transformed = xpcall(_324_, _325_()) - local function _326_(...) + ok, transformed = xpcall(_335_, _336_()) + local function _337_(...) return propagate_trace_info(ast, ...) end - utils["walk-tree"](transformed, comp(_326_, quote_literal_nils)) + utils["walk-tree"](transformed, comp(_337_, quote_literal_nils)) scopes.macro = old_scope assert_compile(ok, transformed, ast) if (_3fonce or not transformed) then @@ -2913,7 +2978,7 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct return macroexpand_2a(transformed, scope) end else - local _ = _322_0 + local _ = _333_0 return ast end end @@ -2945,13 +3010,13 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct assert_compile((utils["sym?"](ast[1]) or utils["list?"](ast[1]) or ("string" == type(ast[1]))), ("cannot call literal value " .. tostring(ast[1])), ast) for i = 2, len do local subexprs = nil - local _332_ + local _343_ if (i ~= len) then - _332_ = 1 + _343_ = 1 else - _332_ = nil + _343_ = nil end - subexprs = compile1(ast[i], scope, parent, {nval = _332_}) + subexprs = compile1(ast[i], scope, parent, {nval = _343_}) table.insert(fargs, subexprs[1]) if (i == len) then for j = 2, #subexprs do @@ -2989,13 +3054,13 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct end end local function compile_varg(ast, scope, parent, opts) - local _337_ + local _348_ if scope.hashfn then - _337_ = "use $... in hashfn" + _348_ = "use $... in hashfn" else - _337_ = "unexpected vararg" + _348_ = "unexpected vararg" end - assert_compile(scope.vararg, _337_, ast) + assert_compile(scope.vararg, _348_, ast) return handle_compile_opts({utils.expr("...", "varg")}, parent, opts, ast) end local function compile_sym(ast, scope, parent, opts) @@ -3010,20 +3075,20 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct return handle_compile_opts({e}, parent, opts, ast) end local function serialize_number(n) - local _340_0 = string.gsub(tostring(n), ",", ".") - return _340_0 + local _351_0 = string.gsub(tostring(n), ",", ".") + return _351_0 end local function compile_scalar(ast, _scope, parent, opts) local serialize = nil do - local _341_0 = type(ast) - if (_341_0 == "nil") then + local _352_0 = type(ast) + if (_352_0 == "nil") then serialize = tostring - elseif (_341_0 == "boolean") then + elseif (_352_0 == "boolean") then serialize = tostring - elseif (_341_0 == "string") then + elseif (_352_0 == "string") then serialize = serialize_string - elseif (_341_0 == "number") then + elseif (_352_0 == "number") then serialize = serialize_number else serialize = nil @@ -3036,8 +3101,8 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct if ((type(k) == "string") and utils["valid-lua-identifier?"](k)) then return k else - local _343_ = compile1(k, scope, parent, {nval = 1}) - local compiled = _343_[1] + local _354_ = compile1(k, scope, parent, {nval = 1}) + local compiled = _354_[1] return ("[" .. tostring(compiled) .. "]") end end @@ -3066,8 +3131,8 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct for k, v in utils.stablepairs(ast) do local val_19_ = nil if not keys[k] then - local _346_ = compile1(ast[k], scope, parent, {nval = 1}) - local v0 = _346_[1] + local _357_ = compile1(ast[k], scope, parent, {nval = 1}) + local v0 = _357_[1] val_19_ = string.format("%s = %s", escape_key(k), tostring(v0)) else val_19_ = nil @@ -3099,12 +3164,12 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct end local function destructure(to, from, ast, scope, parent, opts) local opts0 = (opts or {}) - local _350_ = opts0 - local declaration = _350_["declaration"] - local forceglobal = _350_["forceglobal"] - local forceset = _350_["forceset"] - local isvar = _350_["isvar"] - local symtype = _350_["symtype"] + local _361_ = opts0 + local declaration = _361_["declaration"] + local forceglobal = _361_["forceglobal"] + local forceset = _361_["forceset"] + local isvar = _361_["isvar"] + local symtype = _361_["symtype"] local symtype0 = ("_" .. (symtype or "dst")) local setter = nil if declaration then @@ -3120,13 +3185,15 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct return declare_local(symbol, nil, scope, symbol, new_manglings) else local parts = (utils["multi-sym?"](raw) or {raw}) - local meta = scope.symmeta[parts[1]] + local _363_ = parts + local first = _363_[1] + local meta = scope.symmeta[first] assert_compile(not raw:find(":"), "cannot set method sym", symbol) if ((#parts == 1) and not forceset) then assert_compile(not (forceglobal and meta), string.format("global %s conflicts with local", tostring(symbol)), symbol) assert_compile(not (meta and not meta.var), ("expected var " .. raw), symbol) end - assert_compile((meta or not opts0.noundef or global_allowed_3f(parts[1])), ("expected local " .. parts[1]), symbol) + assert_compile((meta or not opts0.noundef or (scope.hashfn and ("$" == first)) or global_allowed_3f(first)), ("expected local " .. first), symbol) if forceglobal then assert_compile(not scope.symmeta[scope.unmanglings[raw]], ("global " .. raw .. " conflicts with local"), symbol) scope.manglings[raw] = global_mangling(raw) @@ -3140,14 +3207,14 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct end local function compile_top_target(lvalues) local inits = nil - local function _356_(_241) + local function _368_(_241) if scope.manglings[_241] then return _241 else return "nil" end end - inits = utils.map(lvalues, _356_) + inits = utils.map(lvalues, _368_) local init = table.concat(inits, ", ") local lvalue = table.concat(lvalues, ", ") local plast = parent[#parent] @@ -3185,7 +3252,7 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct local unpack_fn = "function (t, k, e)\n local mt = getmetatable(t)\n if 'table' == type(mt) and mt.__fennelrest then\n return mt.__fennelrest(t, k)\n elseif e then\n local rest = {}\n for k, v in pairs(t) do\n if not e[k] then rest[k] = v end\n end\n return rest\n else\n return {(table.unpack or unpack)(t, k)}\n end\n end" local function destructure_kv_rest(s, v, left, excluded_keys, destructure1) local exclude_str = nil - local _363_ + local _375_ do local tbl_17_ = {} local i_18_ = #tbl_17_ @@ -3196,9 +3263,9 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct tbl_17_[i_18_] = val_19_ end end - _363_ = tbl_17_ + _375_ = tbl_17_ end - exclude_str = table.concat(_363_, ", ") + exclude_str = table.concat(_375_, ", ") local subexpr = utils.expr(string.format(string.gsub(("(" .. unpack_fn .. ")(%s, %s, {%s})"), "\n%s*", " "), s, tostring(v), exclude_str), "expression") return destructure1(v, {subexpr}, left) end @@ -3213,16 +3280,16 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct local s = gensym(scope, symtype0) local right = nil do - local _365_0 = nil + local _377_0 = nil if top_3f then - _365_0 = exprs1(compile1(from, scope, parent)) + _377_0 = exprs1(compile1(from, scope, parent)) else - _365_0 = exprs1(rightexprs) + _377_0 = exprs1(rightexprs) end - if (_365_0 == "") then + if (_377_0 == "") then right = "nil" - elseif (nil ~= _365_0) then - local right0 = _365_0 + elseif (nil ~= _377_0) then + local right0 = _377_0 right = right0 else right = nil @@ -3313,61 +3380,55 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct end return scopes.global.specials.include(ast, scope, parent, opts) end - local function compile_stream(strm, options) + local function opts_for_compile(options) local opts = utils.copy(options) - local old_globals = allowed_globals - local scope = (opts.scope or make_scope(scopes.global)) - local vals = {} - local chunk = {} - local _378_ = utils.root - _378_["set-reset"](_378_) + opts.indent = (opts.indent or " ") allowed_globals = opts.allowedGlobals - if (opts.indent == nil) then - opts.indent = " " - end + return opts + end + local function compile_asts(asts, options) + local old_globals = allowed_globals + local opts = opts_for_compile(options) + local scope = (opts.scope or make_scope(scopes.global)) + local chunk = {} if opts.requireAsInclude then scope.specials.require = require_include end + local _391_ = utils.root + _391_["set-reset"](_391_) utils.root.chunk, utils.root.scope, utils.root.options = chunk, scope, opts - for _, val in parser.parser(strm, opts.filename, opts) do - table.insert(vals, val) - end - for i = 1, #vals do - local exprs = compile1(vals[i], scope, chunk, {nval = (((i < #vals) and 0) or nil), tail = (i == #vals)}) - keep_side_effects(exprs, chunk, nil, vals[i]) - if (i == #vals) then - utils.hook("chunk", vals[i], scope) + for i = 1, #asts do + local exprs = compile1(asts[i], scope, chunk, {nval = (((i < #asts) and 0) or nil), tail = (i == #asts)}) + keep_side_effects(exprs, chunk, nil, asts[i]) + if (i == #asts) then + utils.hook("chunk", asts[i], scope) end end allowed_globals = old_globals utils.root.reset() return flatten(chunk, opts) end - local function compile_string(str, _3fopts) - local opts = (_3fopts or {}) - return compile_stream(parser["string-stream"](str, opts), opts) + local function compile_stream(stream, opts) + local asts = nil + do + local tbl_17_ = {} + local i_18_ = #tbl_17_ + for _, ast in parser.parser(stream, opts.filename, opts) do + local val_19_ = ast + if (nil ~= val_19_) then + i_18_ = (i_18_ + 1) + tbl_17_[i_18_] = val_19_ + end + end + asts = tbl_17_ + end + return compile_asts(asts, opts) end - local function compile(ast, opts) - local opts0 = utils.copy(opts) - local old_globals = allowed_globals - local chunk = {} - local scope = (opts0.scope or make_scope(scopes.global)) - local _382_ = utils.root - _382_["set-reset"](_382_) - allowed_globals = opts0.allowedGlobals - if (opts0.indent == nil) then - opts0.indent = " " - end - if opts0.requireAsInclude then - scope.specials.require = require_include - end - utils.root.chunk, utils.root.scope, utils.root.options = chunk, scope, opts0 - local exprs = compile1(ast, scope, chunk, {tail = true}) - keep_side_effects(exprs, chunk, nil, ast) - utils.hook("chunk", ast, scope) - allowed_globals = old_globals - utils.root.reset() - return flatten(chunk, opts0) + local function compile_string(str, _3fopts) + return compile_stream(parser["string-stream"](str, (_3fopts or {})), (_3fopts or {})) + end + local function compile(ast, _3fopts) + return compile_asts({ast}, _3fopts) end local function traceback_frame(info) if ((info.what == "C") and info.name) then @@ -3385,14 +3446,14 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct info.currentline = (remap[info.currentline][2] or -1) end if (info.what == "Lua") then - local function _387_() + local function _396_() if info.name then return ("'" .. info.name .. "'") else return "?" end end - return string.format(" %s:%d: in function %s", info.short_src, info.currentline, _387_()) + return string.format(" %s:%d: in function %s", info.short_src, info.currentline, _396_()) elseif (info.short_src == "(tail call)") then return " (tail call)" else @@ -3416,11 +3477,11 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct local done_3f, level = false, (_3fstart or 2) while not done_3f do do - local _391_0 = debug.getinfo(level, "Sln") - if (_391_0 == nil) then + local _400_0 = debug.getinfo(level, "Sln") + if (_400_0 == nil) then done_3f = true - elseif (nil ~= _391_0) then - local info = _391_0 + elseif (nil ~= _400_0) then + local info = _400_0 table.insert(lines, traceback_frame(info)) end end @@ -3430,14 +3491,14 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct end end local function entry_transform(fk, fv) - local function _394_(k, v) + local function _403_(k, v) if (type(k) == "number") then return k, fv(v) else return fk(k), fv(v) end end - return _394_ + return _403_ end local function mixed_concat(t, joiner) local seen = {} @@ -3482,10 +3543,10 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct return res[1] elseif utils["list?"](form) then local mapped = nil - local function _399_() + local function _408_() return nil end - mapped = utils.kvmap(form, entry_transform(_399_, q)) + mapped = utils.kvmap(form, entry_transform(_408_, q)) local filename = nil if form.filename then filename = string.format("%q", form.filename) @@ -3503,13 +3564,13 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct else filename = "nil" end - local _402_ + local _411_ if source then - _402_ = source.line + _411_ = source.line else - _402_ = "nil" + _411_ = "nil" end - return string.format("setmetatable({%s}, {filename=%s, line=%s, sequence=%s})", mixed_concat(mapped, ", "), filename, _402_, "(getmetatable(sequence()))['sequence']") + return string.format("setmetatable({%s}, {filename=%s, line=%s, sequence=%s})", mixed_concat(mapped, ", "), filename, _411_, "(getmetatable(sequence()))['sequence']") elseif (type(form) == "table") then local mapped = utils.kvmap(form, entry_transform(q, q)) local source = getmetatable(form) @@ -3519,14 +3580,14 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct else filename = "nil" end - local function _405_() + local function _414_() if source then return source.line else return "nil" end end - return string.format("setmetatable({%s}, {filename=%s, line=%s})", mixed_concat(mapped, ", "), filename, _405_()) + return string.format("setmetatable({%s}, {filename=%s, line=%s})", mixed_concat(mapped, ", "), filename, _414_()) elseif (type(form) == "string") then return serialize_string(form) else @@ -3538,7 +3599,7 @@ end package.preload["fennel.friend"] = package.preload["fennel.friend"] or function(...) local utils = require("fennel.utils") local utf8_ok_3f, utf8 = pcall(require, "utf8") - local suggestions = {["$ and $... in hashfn are mutually exclusive"] = {"modifying the hashfn so it only contains $... or $, $1, $2, $3, etc"}, ["can't start multisym segment with a digit"] = {"removing the digit", "adding a non-digit before the digit"}, ["cannot call literal value"] = {"checking for typos", "checking for a missing function name", "making sure to use prefix operators, not infix"}, ["could not compile value of type "] = {"debugging the macro you're calling to return a list or table"}, ["could not read number (.*)"] = {"removing the non-digit character", "beginning the identifier with a non-digit if it is not meant to be a number"}, ["expected a function.* to call"] = {"removing the empty parentheses", "using square brackets if you want an empty table"}, ["expected at least one pattern/body pair"] = {"adding a pattern and a body to execute when the pattern matches"}, ["expected binding and iterator"] = {"making sure you haven't omitted a local name or iterator"}, ["expected binding sequence"] = {"placing a table here in square brackets containing identifiers to bind"}, ["expected body expression"] = {"putting some code in the body of this form after the bindings"}, ["expected each macro to be function"] = {"ensuring that the value for each key in your macros table contains a function", "avoid defining nested macro tables"}, ["expected even number of name/value bindings"] = {"finding where the identifier or value is missing"}, ["expected even number of pattern/body pairs"] = {"checking that every pattern has a body to go with it", "adding _ before the final body"}, ["expected even number of values in table literal"] = {"removing a key", "adding a value"}, ["expected local"] = {"looking for a typo", "looking for a local which is used out of its scope"}, ["expected macros to be table"] = {"ensuring your macro definitions return a table"}, ["expected parameters"] = {"adding function parameters as a list of identifiers in brackets"}, ["expected rest argument before last parameter"] = {"moving & to right before the final identifier when destructuring"}, ["expected symbol for function parameter: (.*)"] = {"changing %s to an identifier instead of a literal value"}, ["expected var (.*)"] = {"declaring %s using var instead of let/local", "introducing a new local instead of changing the value of %s"}, ["expected vararg as last parameter"] = {"moving the \"...\" to the end of the parameter list"}, ["expected whitespace before opening delimiter"] = {"adding whitespace"}, ["global (.*) conflicts with local"] = {"renaming local %s"}, ["invalid character: (.)"] = {"deleting or replacing %s", "avoiding reserved characters like \", \\, ', ~, ;, @, `, and comma"}, ["local (.*) was overshadowed by a special form or macro"] = {"renaming local %s"}, ["macro not found in macro module"] = {"checking the keys of the imported macro module's returned table"}, ["macro tried to bind (.*) without gensym"] = {"changing to %s# when introducing identifiers inside macros"}, ["malformed multisym"] = {"ensuring each period or colon is not followed by another period or colon"}, ["may only be used at compile time"] = {"moving this to inside a macro if you need to manipulate symbols/lists", "using square brackets instead of parens to construct a table"}, ["method must be last component"] = {"using a period instead of a colon for field access", "removing segments after the colon", "making the method call, then looking up the field on the result"}, ["mismatched closing delimiter (.), expected (.)"] = {"replacing %s with %s", "deleting %s", "adding matching opening delimiter earlier"}, ["missing subject"] = {"adding an item to operate on"}, ["multisym method calls may only be in call position"] = {"using a period instead of a colon to reference a table's fields", "putting parens around this"}, ["tried to reference a macro without calling it"] = {"renaming the macro so as not to conflict with locals"}, ["tried to reference a special form without calling it"] = {"making sure to use prefix operators, not infix", "wrapping the special in a function if you need it to be first class"}, ["unable to bind (.*)"] = {"replacing the %s with an identifier"}, ["unexpected arguments"] = {"removing an argument", "checking for typos"}, ["unexpected closing delimiter (.)"] = {"deleting %s", "adding matching opening delimiter earlier"}, ["unexpected iterator clause"] = {"removing an argument", "checking for typos"}, ["unexpected multi symbol (.*)"] = {"removing periods or colons from %s"}, ["unexpected vararg"] = {"putting \"...\" at the end of the fn parameters if the vararg was intended"}, ["unknown identifier: (.*)"] = {"looking to see if there's a typo", "using the _G table instead, eg. _G.%s if you really want a global", "moving this code to somewhere that %s is in scope", "binding %s as a local in the scope of this code"}, ["unused local (.*)"] = {"renaming the local to _%s if it is meant to be unused", "fixing a typo so %s is used", "disabling the linter which checks for unused locals"}, ["use of global (.*) is aliased by a local"] = {"renaming local %s", "refer to the global using _G.%s instead of directly"}} + local suggestions = {["$ and $... in hashfn are mutually exclusive"] = {"modifying the hashfn so it only contains $... or $, $1, $2, $3, etc"}, ["can't start multisym segment with a digit"] = {"removing the digit", "adding a non-digit before the digit"}, ["cannot call literal value"] = {"checking for typos", "checking for a missing function name", "making sure to use prefix operators, not infix"}, ["could not compile value of type "] = {"debugging the macro you're calling to return a list or table"}, ["could not read number (.*)"] = {"removing the non-digit character", "beginning the identifier with a non-digit if it is not meant to be a number"}, ["expected a function.* to call"] = {"removing the empty parentheses", "using square brackets if you want an empty table"}, ["expected at least one pattern/body pair"] = {"adding a pattern and a body to execute when the pattern matches"}, ["expected binding and iterator"] = {"making sure you haven't omitted a local name or iterator"}, ["expected binding sequence"] = {"placing a table here in square brackets containing identifiers to bind"}, ["expected body expression"] = {"putting some code in the body of this form after the bindings"}, ["expected each macro to be function"] = {"ensuring that the value for each key in your macros table contains a function", "avoid defining nested macro tables"}, ["expected even number of name/value bindings"] = {"finding where the identifier or value is missing"}, ["expected even number of pattern/body pairs"] = {"checking that every pattern has a body to go with it", "adding _ before the final body"}, ["expected even number of values in table literal"] = {"removing a key", "adding a value"}, ["expected local"] = {"looking for a typo", "looking for a local which is used out of its scope"}, ["expected macros to be table"] = {"ensuring your macro definitions return a table"}, ["expected parameters"] = {"adding function parameters as a list of identifiers in brackets"}, ["expected range to include start and stop"] = {"adding missing arguments"}, ["expected rest argument before last parameter"] = {"moving & to right before the final identifier when destructuring"}, ["expected symbol for function parameter: (.*)"] = {"changing %s to an identifier instead of a literal value"}, ["expected var (.*)"] = {"declaring %s using var instead of let/local", "introducing a new local instead of changing the value of %s"}, ["expected vararg as last parameter"] = {"moving the \"...\" to the end of the parameter list"}, ["expected whitespace before opening delimiter"] = {"adding whitespace"}, ["global (.*) conflicts with local"] = {"renaming local %s"}, ["invalid character: (.)"] = {"deleting or replacing %s", "avoiding reserved characters like \", \\, ', ~, ;, @, `, and comma"}, ["local (.*) was overshadowed by a special form or macro"] = {"renaming local %s"}, ["macro not found in macro module"] = {"checking the keys of the imported macro module's returned table"}, ["macro tried to bind (.*) without gensym"] = {"changing to %s# when introducing identifiers inside macros"}, ["malformed multisym"] = {"ensuring each period or colon is not followed by another period or colon"}, ["may only be used at compile time"] = {"moving this to inside a macro if you need to manipulate symbols/lists", "using square brackets instead of parens to construct a table"}, ["method must be last component"] = {"using a period instead of a colon for field access", "removing segments after the colon", "making the method call, then looking up the field on the result"}, ["mismatched closing delimiter (.), expected (.)"] = {"replacing %s with %s", "deleting %s", "adding matching opening delimiter earlier"}, ["missing subject"] = {"adding an item to operate on"}, ["multisym method calls may only be in call position"] = {"using a period instead of a colon to reference a table's fields", "putting parens around this"}, ["tried to reference a macro without calling it"] = {"renaming the macro so as not to conflict with locals"}, ["tried to reference a special form without calling it"] = {"making sure to use prefix operators, not infix", "wrapping the special in a function if you need it to be first class"}, ["tried to use unquote outside quote"] = {"moving the form to inside a quoted form", "removing the comma"}, ["tried to use vararg with operator"] = {"accumulating over the operands"}, ["unable to bind (.*)"] = {"replacing the %s with an identifier"}, ["unexpected arguments"] = {"removing an argument", "checking for typos"}, ["unexpected closing delimiter (.)"] = {"deleting %s", "adding matching opening delimiter earlier"}, ["unexpected iterator clause"] = {"removing an argument", "checking for typos"}, ["unexpected multi symbol (.*)"] = {"removing periods or colons from %s"}, ["unexpected vararg"] = {"putting \"...\" at the end of the fn parameters if the vararg was intended"}, ["unknown identifier: (.*)"] = {"looking to see if there's a typo", "using the _G table instead, eg. _G.%s if you really want a global", "moving this code to somewhere that %s is in scope", "binding %s as a local in the scope of this code"}, ["unused local (.*)"] = {"renaming the local to _%s if it is meant to be unused", "fixing a typo so %s is used", "disabling the linter which checks for unused locals"}, ["use of global (.*) is aliased by a local"] = {"renaming local %s", "refer to the global using _G.%s instead of directly"}} local unpack = (table.unpack or _G.unpack) local function suggest(msg) local s = nil @@ -3570,7 +3631,7 @@ package.preload["fennel.friend"] = package.preload["fennel.friend"] or function( end return matcher() else - local f = assert(io.open(filename)) + local f = assert(_G.io.open(filename)) local function close_handlers_10_(ok_11_, ...) f:close() if ok_11_ then @@ -3579,17 +3640,17 @@ package.preload["fennel.friend"] = package.preload["fennel.friend"] or function( return error(..., 0) end end - local function _178_() + local function _184_() for _ = 2, line do f:read() end return f:read() end - return close_handlers_10_(_G.xpcall(_178_, (package.loaded.fennel or debug).traceback)) + return close_handlers_10_(_G.xpcall(_184_, (package.loaded.fennel or debug).traceback)) end end local function sub(str, start, _end) - if ((_end < start) or (#str < start) or (#str < _end)) then + if ((_end < start) or (#str < start)) then return "" elseif utf8_ok_3f then return string.sub(str, utf8.offset(str, start), ((utf8.offset(str, (_end + 1)) or (utf8.len(str) + 1)) - 1)) @@ -3601,8 +3662,8 @@ package.preload["fennel.friend"] = package.preload["fennel.friend"] or function( if ((opts and (false == opts["error-pinpoint"])) or (os and os.getenv and os.getenv("NO_COLOR"))) then return codeline else - local _181_ = (opts or {}) - local error_pinpoint = _181_["error-pinpoint"] + local _187_ = (opts or {}) + local error_pinpoint = _187_["error-pinpoint"] local endcol = (_3fendcol or col) local eol = nil if utf8_ok_3f then @@ -3610,23 +3671,30 @@ package.preload["fennel.friend"] = package.preload["fennel.friend"] or function( else eol = string.len(codeline) end - local _183_ = (error_pinpoint or {"\27[7m", "\27[0m"}) - local open = _183_[1] - local close = _183_[2] + local _189_ = (error_pinpoint or {"\27[7m", "\27[0m"}) + local open = _189_[1] + local close = _189_[2] return (sub(codeline, 1, col) .. open .. sub(codeline, (col + 1), (endcol + 1)) .. close .. sub(codeline, (endcol + 2), eol)) end end - local function friendly_msg(msg, _185_0, source, opts) - local _186_ = _185_0 - local col = _186_["col"] - local endcol = _186_["endcol"] - local filename = _186_["filename"] - local line = _186_["line"] + local function friendly_msg(msg, _191_0, source, opts) + local _192_ = _191_0 + local col = _192_["col"] + local endcol = _192_["endcol"] + local endline = _192_["endline"] + local filename = _192_["filename"] + local line = _192_["line"] local ok, codeline = pcall(read_line, filename, line, source) + local endcol0 = nil + if (ok and codeline and (line ~= endline)) then + endcol0 = #codeline + else + endcol0 = endcol + end local out = {msg, ""} if (ok and codeline) then if col then - table.insert(out, highlight_line(codeline, col, endcol, opts)) + table.insert(out, highlight_line(codeline, col, endcol0, opts)) else table.insert(out, codeline) end @@ -3638,10 +3706,10 @@ package.preload["fennel.friend"] = package.preload["fennel.friend"] or function( end local function assert_compile(condition, msg, ast, source, opts) if not condition then - local _189_ = utils["ast-source"](ast) - local col = _189_["col"] - local filename = _189_["filename"] - local line = _189_["line"] + local _196_ = utils["ast-source"](ast) + local col = _196_["col"] + local filename = _196_["filename"] + local line = _196_["line"] error(friendly_msg(("%s:%s:%s Compile error: %s"):format((filename or "unknown"), (line or "?"), (col or "?"), msg), utils["ast-source"](ast), source, opts), 0) end return condition @@ -3657,36 +3725,36 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( local unpack = (table.unpack or _G.unpack) local function granulate(getchunk) local c, index, done_3f = "", 1, false - local function _191_(parser_state) + local function _198_(parser_state) if not done_3f then if (index <= #c) then local b = c:byte(index) index = (index + 1) return b else - local _192_0 = getchunk(parser_state) - local function _193_() - local char = _192_0 + local _199_0 = getchunk(parser_state) + local function _200_() + local char = _199_0 return (char ~= "") end - if ((nil ~= _192_0) and _193_()) then - local char = _192_0 + if ((nil ~= _199_0) and _200_()) then + local char = _199_0 c = char index = 2 return c:byte() else - local _ = _192_0 + local _ = _199_0 done_3f = true return nil end end end end - local function _197_() + local function _204_() c = "" return nil end - return _191_, _197_ + return _198_, _204_ end local function string_stream(str, _3foptions) local str0 = str:gsub("^#!", ";;") @@ -3694,12 +3762,12 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( _3foptions.source = str0 end local index = 1 - local function _199_() + local function _206_() local r = str0:byte(index) index = (index + 1) return r end - return _199_ + return _206_ end local delims = {[123] = 125, [125] = true, [40] = 41, [41] = true, [91] = 93, [93] = true} local function sym_char_3f(b) @@ -3715,12 +3783,12 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( local function char_starter_3f(b) return (((1 < b) and (b < 127)) or ((192 < b) and (b < 247))) end - local function parser_fn(getbyte, filename, _201_0) - local _202_ = _201_0 - local options = _202_ - local comments = _202_["comments"] - local source = _202_["source"] - local unfriendly = _202_["unfriendly"] + local function parser_fn(getbyte, filename, _208_0) + local _209_ = _208_0 + local options = _209_ + local comments = _209_["comments"] + local source = _209_["source"] + local unfriendly = _209_["unfriendly"] local stack = {} local line, byteindex, col, prev_col, lastb = 1, 0, 0, 0, nil local function ungetb(ub) @@ -3751,20 +3819,20 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( return r end local function whitespace_3f(b) - local function _209_() - local _208_0 = options.whitespace - if (nil ~= _208_0) then - _208_0 = _208_0[b] + local function _216_() + local _215_0 = options.whitespace + if (nil ~= _215_0) then + _215_0 = _215_0[b] end - return _208_0 + return _215_0 end - return ((b == 32) or ((9 <= b) and (b <= 13)) or _209_()) + return ((b == 32) or ((9 <= b) and (b <= 13)) or _216_()) end local function parse_error(msg, _3fcol_adjust) local col0 = (col + (_3fcol_adjust or -1)) if (nil == utils["hook-opts"]("parse-error", options, msg, filename, (line or "?"), col0, source, utils.root.reset)) then utils.root.reset() - if (unfriendly or not _G.io or not _G.io.read) then + if unfriendly then return error(string.format("%s:%s:%s Parse error: %s", filename, (line or "?"), col0, msg), 0) else return friend["parse-error"](msg, filename, (line or "?"), col0, source, options) @@ -3774,50 +3842,98 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( local function parse_stream() local whitespace_since_dispatch, done_3f, retval = true local function set_source_fields(source0) - source0.byteend, source0.endcol = byteindex, (col - 1) + source0.byteend, source0.endcol, source0.endline = byteindex, (col - 1), line return nil end local function dispatch(v) - local _213_0 = stack[#stack] - if (_213_0 == nil) then + local _220_0 = stack[#stack] + if (_220_0 == nil) then retval, done_3f, whitespace_since_dispatch = v, true, false return nil - elseif ((_G.type(_213_0) == "table") and (nil ~= _213_0.prefix)) then - local prefix = _213_0.prefix + elseif ((_G.type(_220_0) == "table") and (nil ~= _220_0.prefix)) then + local prefix = _220_0.prefix local source0 = nil do - local _214_0 = table.remove(stack) - set_source_fields(_214_0) - source0 = _214_0 + local _221_0 = table.remove(stack) + set_source_fields(_221_0) + source0 = _221_0 end local list = utils.list(utils.sym(prefix, source0), v) for k, v0 in pairs(source0) do list[k] = v0 end return dispatch(list) - elseif (nil ~= _213_0) then - local top = _213_0 + elseif (nil ~= _220_0) then + local top = _220_0 whitespace_since_dispatch = false return table.insert(top, v) end end + local close_table = nil + local function badend(cause) + local accum = utils.map(stack, "closer") + local _223_ + if (#stack == 1) then + _223_ = "" + else + _223_ = "s" + end + parse_error(string.format("expected closing delimiter%s %s", _223_, string.char(unpack(accum)))) + if (cause == "eof") then + for i = #accum, 2, -1 do + close_table(accum[i]) + end + return accum[1] + end + end + local function skip_whitespace(b) + if (b and whitespace_3f(b)) then + whitespace_since_dispatch = true + return skip_whitespace(getb()) + elseif (not b and (0 < #stack)) then + return badend("eof") + else + return b + end + end + local function parse_comment(b, contents) + if (b and (10 ~= b)) then + local function _227_() + table.insert(contents, string.char(b)) + return contents + end + return parse_comment(getb(), _227_()) + elseif comments then + ungetb(10) + return dispatch(utils.comment(table.concat(contents), {filename = filename, line = line})) + end + end + local function open_table(b) + if not whitespace_since_dispatch then + parse_error(("expected whitespace before opening delimiter " .. string.char(b))) + end + return table.insert(stack, {bytestart = byteindex, closer = delims[b], col = (col - 1), filename = filename, line = line}) + end local function close_list(list) return dispatch(setmetatable(list, getmetatable(utils.list()))) end local function close_sequence(tbl) - local val = utils.sequence(unpack(tbl)) + local mt = getmetatable(utils.sequence()) for k, v in pairs(tbl) do - getmetatable(val)[k] = v + if ("number" ~= type(k)) then + mt[k] = v + tbl[k] = nil + end end - return dispatch(val) + return dispatch(setmetatable(tbl, mt)) end local function add_comment_at(comments0, index, node) - local _216_0 = comments0[index] - if (nil ~= _216_0) then - local existing = _216_0 + local _231_0 = comments0[index] + if (nil ~= _231_0) then + local existing = _231_0 return table.insert(existing, node) else - local _ = _216_0 + local _ = _231_0 comments0[index] = {node} return nil end @@ -3825,7 +3941,7 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( local function next_noncomment(tbl, i) if utils["comment?"](tbl[i]) then return next_noncomment(tbl, (i + 1)) - elseif (utils.sym(":") == tbl[i]) then + elseif utils["sym?"](tbl[i], ":") then return tostring(tbl[(i + 1)]) else return tbl[i] @@ -3873,7 +3989,7 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( tbl.keys = keys return dispatch(val) end - local function close_table(b) + local function close_table0(b) local top = table.remove(stack) if (top == nil) then parse_error(("unexpected closing delimiter " .. string.char(b))) @@ -3890,64 +4006,23 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( return close_curly_table(top) end end - local function badend(cause) - local accum = utils.map(stack, "closer") - local _226_ - if (#stack == 1) then - _226_ = "" - else - _226_ = "s" - end - parse_error(string.format("expected closing delimiter%s %s", _226_, string.char(unpack(accum)))) - if (cause == "eof") then - for i = #accum, 2, -1 do - close_table(accum[i]) - end - return accum[1] - end - end - local function skip_whitespace(b) - if (b and whitespace_3f(b)) then - whitespace_since_dispatch = true - return skip_whitespace(getb()) - elseif (not b and (0 < #stack)) then - return badend("eof") - else - return b - end - end - local function parse_comment(b, contents) - if (b and (10 ~= b)) then - local function _230_() - table.insert(contents, string.char(b)) - return contents - end - return parse_comment(getb(), _230_()) - elseif comments then - ungetb(10) - return dispatch(utils.comment(table.concat(contents), {filename = filename, line = line})) - end - end - local function open_table(b) - if not whitespace_since_dispatch then - parse_error(("expected whitespace before opening delimiter " .. string.char(b))) - end - return table.insert(stack, {bytestart = byteindex, closer = delims[b], col = (col - 1), filename = filename, line = line}) - end + close_table = close_table0 local function parse_string_loop(chars, b, state) - table.insert(chars, b) + if b then + table.insert(chars, string.char(b)) + end local state0 = nil do - local _233_0 = {state, b} - if ((_G.type(_233_0) == "table") and (_233_0[1] == "base") and (_233_0[2] == 92)) then + local _242_0 = {state, b} + if ((_G.type(_242_0) == "table") and (_242_0[1] == "base") and (_242_0[2] == 92)) then state0 = "backslash" - elseif ((_G.type(_233_0) == "table") and (_233_0[1] == "base") and (_233_0[2] == 34)) then + elseif ((_G.type(_242_0) == "table") and (_242_0[1] == "base") and (_242_0[2] == 34)) then state0 = "done" - elseif ((_G.type(_233_0) == "table") and (_233_0[1] == "backslash") and (_233_0[2] == 10)) then + elseif ((_G.type(_242_0) == "table") and (_242_0[1] == "backslash") and (_242_0[2] == 10)) then table.remove(chars, (#chars - 1)) state0 = "base" else - local _ = _233_0 + local _ = _242_0 state0 = "base" end end @@ -3962,18 +4037,18 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( end local function parse_string() table.insert(stack, {closer = 34}) - local chars = {34} + local chars = {"\""} if not parse_string_loop(chars, getb(), "base") then badend("string") end table.remove(stack) - local raw = string.char(unpack(chars)) + local raw = table.concat(chars) local formatted = raw:gsub("[\7-\13]", escape_char) - local _237_0 = (rawget(_G, "loadstring") or load)(("return " .. formatted)) - if (nil ~= _237_0) then - local load_fn = _237_0 + local _246_0 = (rawget(_G, "loadstring") or load)(("return " .. formatted)) + if (nil ~= _246_0) then + local load_fn = _246_0 return dispatch(load_fn()) - elseif (_237_0 == nil) then + elseif (_246_0 == nil) then return parse_error(("Invalid string: " .. raw)) end end @@ -3991,7 +4066,7 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( end local function parse_sym_loop(chars, b) if (b and sym_char_3f(b)) then - table.insert(chars, b) + table.insert(chars, string.char(b)) return parse_sym_loop(chars, getb()) else if b then @@ -4006,13 +4081,13 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( dispatch((tonumber(number_with_stripped_underscores) or parse_error(("could not read number \"" .. rawstr .. "\"")))) return true else - local _243_0 = tonumber(number_with_stripped_underscores) - if (nil ~= _243_0) then - local x = _243_0 + local _252_0 = tonumber(number_with_stripped_underscores) + if (nil ~= _252_0) then + local x = _252_0 dispatch(x) return true else - local _ = _243_0 + local _ = _252_0 return false end end @@ -4036,7 +4111,7 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( end local function parse_sym(b) local source0 = {bytestart = byteindex, col = (col - 1), filename = filename, line = line} - local rawstr = string.char(unpack(parse_sym_loop({b}, getb()))) + local rawstr = table.concat(parse_sym_loop({string.char(b)}, getb())) set_source_fields(source0) if (rawstr == "true") then return dispatch(true) @@ -4057,7 +4132,7 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( elseif (type(delims[b]) == "number") then open_table(b) elseif delims[b] then - close_table(b) + close_table0(b) elseif (b == 34) then parse_string(b) elseif prefixes[b] then @@ -4077,11 +4152,11 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( end return parse_loop(skip_whitespace(getb())) end - local function _250_() + local function _259_() stack, line, byteindex, col, lastb = {}, 1, 0, 0, nil return nil end - return parse_stream, _250_ + return parse_stream, _259_ end local function parser(stream_or_string, _3ffilename, _3foptions) local filename = (_3ffilename or "unknown") @@ -4140,14 +4215,13 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) end end local function getopt(options, key) - local val = options[key] - local _9_0 = val + local _9_0 = options[key] if ((_G.type(_9_0) == "table") and (nil ~= _9_0.once)) then local val_2a = _9_0.once return val_2a else - local _ = _9_0 - return val + local _3fval = _9_0 + return _3fval end end local function normalize_opts(options) @@ -4287,15 +4361,15 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) end return seen0 end - local function detect_cycle(t, seen, _3fk) + local function detect_cycle(t, seen) if ("table" == type(t)) then seen[t] = true - local _36_0, _37_0 = next(t, _3fk) - if ((nil ~= _36_0) and (nil ~= _37_0)) then - local k = _36_0 - local v = _37_0 - return (seen[k] or detect_cycle(k, seen) or seen[v] or detect_cycle(v, seen) or detect_cycle(t, seen, k)) + local res = nil + for k, v in pairs(t) do + if res then break end + res = (seen[k] or detect_cycle(k, seen) or seen[v] or detect_cycle(v, seen)) end + return res end end local function visible_cycle_3f(t, options) @@ -4314,14 +4388,14 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) local function concat_table_lines(elements, options, multiline_3f, indent, table_type, prefix, last_comment_3f) local indent_str = ("\n" .. string.rep(" ", indent)) local open = nil - local function _41_() + local function _38_() if ("seq" == table_type) then return "[" else return "{" end end - open = ((prefix or "") .. _41_()) + open = ((prefix or "") .. _38_()) local close = nil if ("seq" == table_type) then close = "]" @@ -4330,14 +4404,14 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) end local oneline = (open .. table.concat(elements, " ") .. close) if (not getopt(options, "one-line?") and (multiline_3f or (options["line-length"] < (indent + length_2a(oneline))) or last_comment_3f)) then - local function _43_() + local function _40_() if last_comment_3f then return indent_str else return "" end end - return (open .. table.concat(elements, indent_str) .. _43_() .. close) + return (open .. table.concat(elements, indent_str) .. _40_() .. close) else return oneline end @@ -4372,10 +4446,10 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) if getopt(options, "utf8?") then slength = utf8_len else - local function _46_(_241) + local function _43_(_241) return #_241 end - slength = _46_ + slength = _43_ end local prefix = nil if visible_cycle_3f0 then @@ -4388,10 +4462,10 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) local options0 = normalize_opts(options) local tbl_17_ = {} local i_18_ = #tbl_17_ - for _, _49_0 in ipairs(kv) do - local _50_ = _49_0 - local k = _50_[1] - local v = _50_[2] + for _, _46_0 in ipairs(kv) do + local _47_ = _46_0 + local k = _47_[1] + local v = _47_[2] local val_19_ = nil do local k0 = pp(k, options0, (indent0 + 1), true) @@ -4432,10 +4506,10 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) local options0 = normalize_opts(options) local tbl_17_ = {} local i_18_ = #tbl_17_ - for _, _54_0 in ipairs(kv) do - local _55_ = _54_0 - local _0 = _55_[1] - local v = _55_[2] + for _, _51_0 in ipairs(kv) do + local _52_ = _51_0 + local _0 = _52_[1] + local v = _52_[2] local val_19_ = nil do local v0 = pp(v, options0, indent0) @@ -4461,7 +4535,7 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) end else local oneline = nil - local _59_ + local _56_ do local tbl_17_ = {} local i_18_ = #tbl_17_ @@ -4472,9 +4546,9 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) tbl_17_[i_18_] = val_19_ end end - _59_ = tbl_17_ + _56_ = tbl_17_ end - oneline = table.concat(_59_, " ") + oneline = table.concat(_56_, " ") if (not getopt(options, "one-line?") and (force_multi_line_3f or oneline:find("\n") or (options["line-length"] < (indent + length_2a(oneline))))) then return table.concat(lines, ("\n" .. string.rep(" ", indent))) else @@ -4491,10 +4565,10 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) end else local _ = nil - local function _64_(_241) + local function _61_(_241) return visible_cycle_3f(_241, options) end - options["visible-cycle?"] = _64_ + options["visible-cycle?"] = _61_ _ = nil local lines, force_multi_line_3f = nil, nil do @@ -4502,13 +4576,13 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) lines, force_multi_line_3f = metamethod(t, pp, options0, indent) end options["visible-cycle?"] = nil - local _65_0 = type(lines) - if (_65_0 == "string") then + local _62_0 = type(lines) + if (_62_0 == "string") then return lines - elseif (_65_0 == "table") then + elseif (_62_0 == "table") then return concat_lines(lines, options, indent, force_multi_line_3f) else - local _0 = _65_0 + local _0 = _62_0 return error("__fennelview metamethod must return a table of lines") end end @@ -4517,40 +4591,40 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) options.level = (options.level + 1) local x0 = nil do - local _68_0 = nil + local _65_0 = nil if getopt(options, "metamethod?") then - local _69_0 = x - if (nil ~= _69_0) then - local _70_0 = getmetatable(_69_0) - if (nil ~= _70_0) then - _68_0 = _70_0.__fennelview + local _66_0 = x + if (nil ~= _66_0) then + local _67_0 = getmetatable(_66_0) + if (nil ~= _67_0) then + _65_0 = _67_0.__fennelview else - _68_0 = _70_0 + _65_0 = _67_0 end else - _68_0 = _69_0 + _65_0 = _66_0 end else - _68_0 = nil + _65_0 = nil end - if (nil ~= _68_0) then - local metamethod = _68_0 + if (nil ~= _65_0) then + local metamethod = _65_0 x0 = pp_metamethod(x, metamethod, options, indent) else - local _ = _68_0 - local _74_0, _75_0 = table_kv_pairs(x, options) - if (true and (_75_0 == "empty")) then - local _0 = _74_0 + local _ = _65_0 + local _71_0, _72_0 = table_kv_pairs(x, options) + if (true and (_72_0 == "empty")) then + local _0 = _71_0 if getopt(options, "empty-as-sequence?") then x0 = "[]" else x0 = "{}" end - elseif ((nil ~= _74_0) and (_75_0 == "table")) then - local kv = _74_0 + elseif ((nil ~= _71_0) and (_72_0 == "table")) then + local kv = _71_0 x0 = pp_associative(x, kv, options, indent) - elseif ((nil ~= _74_0) and (_75_0 == "seq")) then - local kv = _74_0 + elseif ((nil ~= _71_0) and (_72_0 == "seq")) then + local kv = _71_0 x0 = pp_sequence(x, kv, options, indent) else x0 = nil @@ -4561,14 +4635,17 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) return x0 end local function number__3estring(n) - local _79_0 = string.gsub(tostring(n), ",", ".") - return _79_0 + local _76_0 = string.gsub(tostring(n), ",", ".") + return _76_0 end local function colon_string_3f(s) - return s:find("^[-%w?^_!$%&*+./@|<=>]+$") + return s:find("^[-%w?^_!$%&*+./|<=>]+$") end local utf8_inits = {{["max-byte"] = 127, ["max-code"] = 127, ["min-byte"] = 0, ["min-code"] = 0, len = 1}, {["max-byte"] = 223, ["max-code"] = 2047, ["min-byte"] = 192, ["min-code"] = 128, len = 2}, {["max-byte"] = 239, ["max-code"] = 65535, ["min-byte"] = 224, ["min-code"] = 2048, len = 3}, {["max-byte"] = 247, ["max-code"] = 1114111, ["min-byte"] = 240, ["min-code"] = 65536, len = 4}} - local function utf8_escape(str) + local function default_byte_escape(byte, _options) + return ("\\%03d"):format(byte) + end + local function utf8_escape(str, options) local function validate_utf8(str0, index) local inits = utf8_inits local byte = string.byte(str0, index) @@ -4577,12 +4654,12 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) local ret = nil for _, init0 in ipairs(inits) do if ret then break end - ret = (byte and (function(_80_,_81_,_82_) return (_80_ <= _81_) and (_81_ <= _82_) end)(init0["min-byte"],byte,init0["max-byte"]) and init0) + ret = (byte and (function(_77_,_78_,_79_) return (_77_ <= _78_) and (_78_ <= _79_) end)(init0["min-byte"],byte,init0["max-byte"]) and init0) end init = ret end local code = nil - local function _83_() + local function _80_() local code0 = nil if init then code0 = (byte - init["min-byte"]) @@ -4595,19 +4672,20 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) end return code0 end - code = (init and _83_()) - if (code and (function(_85_,_86_,_87_) return (_85_ <= _86_) and (_86_ <= _87_) end)(init["min-code"],code,init["max-code"]) and not ((55296 <= code) and (code <= 57343))) then + code = (init and _80_()) + if (code and (function(_82_,_83_,_84_) return (_82_ <= _83_) and (_83_ <= _84_) end)(init["min-code"],code,init["max-code"]) and not ((55296 <= code) and (code <= 57343))) then return init.len end end local index = 1 local output = {} + local byte_escape = (getopt(options, "byte-escape") or default_byte_escape) while (index <= #str) do local nexti = (string.find(str, "[\128-\255]", index) or (#str + 1)) local len = validate_utf8(str, nexti) table.insert(output, string.sub(str, index, (nexti + (len or 0) + -1))) if (not len and (nexti <= #str)) then - table.insert(output, string.format("\\%03d", string.byte(str, nexti))) + table.insert(output, byte_escape(str:byte(nexti), options)) end if len then index = (nexti + len) @@ -4620,20 +4698,21 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) local function pp_string(str, options, indent) local len = length_2a(str) local esc_newline_3f = ((len < 2) or (getopt(options, "escape-newlines?") and (len < (options["line-length"] - indent)))) + local byte_escape = (getopt(options, "byte-escape") or default_byte_escape) local escs = nil - local _91_ + local _88_ if esc_newline_3f then - _91_ = "\\n" + _88_ = "\\n" else - _91_ = "\n" + _88_ = "\n" end - local function _93_(_241, _242) - return ("\\%03d"):format(_242:byte()) + local function _90_(_241, _242) + return byte_escape(_242:byte(), options) end - escs = setmetatable({["\""] = "\\\"", ["\11"] = "\\v", ["\12"] = "\\f", ["\13"] = "\\r", ["\7"] = "\\a", ["\8"] = "\\b", ["\9"] = "\\t", ["\\"] = "\\\\", ["\n"] = _91_}, {__index = _93_}) + escs = setmetatable({["\""] = "\\\"", ["\11"] = "\\v", ["\12"] = "\\f", ["\13"] = "\\r", ["\7"] = "\\a", ["\8"] = "\\b", ["\9"] = "\\t", ["\\"] = "\\\\", ["\n"] = _88_}, {__index = _90_}) local str0 = ("\"" .. str:gsub("[%c\\\"]", escs) .. "\"") if getopt(options, "utf8?") then - return utf8_escape(str0) + return utf8_escape(str0, options) else return str0 end @@ -4659,7 +4738,7 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) end return defaults end - local function _96_(x, options, indent, colon_3f) + local function _93_(x, options, indent, colon_3f) local indent0 = (indent or 0) local options0 = (options or make_options(x)) local x0 = nil @@ -4669,20 +4748,19 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) x0 = x end local tv = type(x0) - local function _99_() - local _98_0 = getmetatable(x0) - if (nil ~= _98_0) then - return _98_0.__fennelview - else - return _98_0 + local function _96_() + local _95_0 = getmetatable(x0) + if ((_G.type(_95_0) == "table") and true) then + local __fennelview = _95_0.__fennelview + return __fennelview end end - if ((tv == "table") or ((tv == "userdata") and _99_())) then + if ((tv == "table") or ((tv == "userdata") and _96_())) then return pp_table(x0, options0, indent0) elseif (tv == "number") then return number__3estring(x0) else - local function _101_() + local function _98_() if (colon_3f ~= nil) then return colon_3f elseif ("function" == type(options0["prefer-colon?"])) then @@ -4691,7 +4769,7 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) return getopt(options0, "prefer-colon?") end end - if ((tv == "string") and colon_string_3f(x0) and _101_()) then + if ((tv == "string") and colon_string_3f(x0) and _98_()) then return (":" .. x0) elseif (tv == "string") then return pp_string(x0, options0, indent0) @@ -4702,7 +4780,7 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) end end end - pp = _96_ + pp = _93_ local function view(x, _3foptions) return pp(x, make_options(x, _3foptions), 0) end @@ -4710,7 +4788,7 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) end package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(...) local view = require("fennel.view") - local version = "1.3.1-dev" + local version = "1.3.2-dev" local function luajit_vm_3f() return ((nil ~= _G.jit) and (type(_G.jit) == "table") and (nil ~= _G.jit.on) and (nil ~= _G.jit.off) and (type(_G.jit.version_num) == "number")) end @@ -4738,8 +4816,12 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. return ("PUC " .. _VERSION) end end - local function runtime_version() - return ("Fennel " .. version .. " on " .. lua_vm_version()) + local function runtime_version(_3fas_table) + if _3fas_table then + return {fennel = version, lua = lua_vm_version()} + else + return ("Fennel " .. version .. " on " .. lua_vm_version()) + end end local function warn(message) if (_G.io and _G.io.stderr) then @@ -4748,43 +4830,77 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. end local len = nil do - local _106_0, _107_0 = pcall(require, "utf8") - if ((_106_0 == true) and (nil ~= _107_0)) then - local utf8 = _107_0 + local _104_0, _105_0 = pcall(require, "utf8") + if ((_104_0 == true) and (nil ~= _105_0)) then + local utf8 = _105_0 len = utf8.len else - local _ = _106_0 + local _ = _104_0 len = string.len end end - local function mt_keys_in_order(t, out, used_keys) - for _, k in ipairs(getmetatable(t).keys) do - if (t[k] and not used_keys[k]) then - used_keys[k] = true - table.insert(out, k) + local kv_order = {boolean = 2, number = 1, string = 3, table = 4} + local function kv_compare(a, b) + local _107_0, _108_0 = type(a), type(b) + if (((_107_0 == "number") and (_108_0 == "number")) or ((_107_0 == "string") and (_108_0 == "string"))) then + return (a < b) + else + local function _109_() + local a_t = _107_0 + local b_t = _108_0 + return (a_t ~= b_t) + end + if (((nil ~= _107_0) and (nil ~= _108_0)) and _109_()) then + local a_t = _107_0 + local b_t = _108_0 + return ((kv_order[a_t] or 5) < (kv_order[b_t] or 5)) + else + local _ = _107_0 + return (tostring(a) < tostring(b)) end end - for k in pairs(t) do - if not used_keys[k] then - table.insert(out, k) + end + local function add_stable_keys(succ, prev_key, src, _3fpred) + local first = prev_key + local last = nil + do + local prev = prev_key + for _, k in ipairs(src) do + if ((prev == k) or (succ[k] ~= nil) or (_3fpred and not _3fpred(k))) then + prev = prev + else + if (first == nil) then + first = k + prev = k + elseif (prev ~= nil) then + succ[prev] = k + prev = k + else + prev = k + end + end end + last = prev end - return out + return succ, last, first end local function stablepairs(t) - local keys = nil - local _112_ + local mt_keys = nil do - local _111_0 = getmetatable(t) - if (nil ~= _111_0) then - _111_0 = _111_0.keys + local _113_0 = getmetatable(t) + if (nil ~= _113_0) then + _113_0 = _113_0.keys end - _112_ = _111_0 + mt_keys = _113_0 end - if _112_ then - keys = mt_keys_in_order(t, {}, {}) - else - local _114_0 = nil + local succ, prev, first_mt = nil, nil, nil + local function _115_(_241) + return t[_241] + end + succ, prev, first_mt = add_stable_keys({}, nil, (mt_keys or {}), _115_) + local pairs_keys = nil + do + local _116_0 = nil do local tbl_17_ = {} local i_18_ = #tbl_17_ @@ -4795,33 +4911,34 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. tbl_17_[i_18_] = val_19_ end end - _114_0 = tbl_17_ + _116_0 = tbl_17_ end - local function _116_(_241, _242) - return (tostring(_241) < tostring(_242)) - end - table.sort(_114_0, _116_) - keys = _114_0 + table.sort(_116_0, kv_compare) + pairs_keys = _116_0 end - local succ = nil - do - local tbl_14_ = {} - for i, k in ipairs(keys) do - local k_15_, v_16_ = k, keys[(i + 1)] - if ((k_15_ ~= nil) and (v_16_ ~= nil)) then - tbl_14_[k_15_] = v_16_ - end - end - succ = tbl_14_ + local succ0, _, first_after_mt = add_stable_keys(succ, prev, pairs_keys) + local first = nil + if (first_mt == nil) then + first = first_after_mt + else + first = first_mt end local function stablenext(tbl, key) - local next_key = nil + local _119_0 = nil if (key == nil) then - next_key = keys[1] + _119_0 = first else - next_key = succ[key] + _119_0 = succ0[key] + end + if (nil ~= _119_0) then + local next_key = _119_0 + local _121_0 = tbl[next_key] + if (_121_0 ~= nil) then + return next_key, _121_0 + else + return _121_0 + end end - return next_key, tbl[next_key] end return stablenext, t, nil end @@ -4830,25 +4947,25 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. if (0 == #path) then return _3ffallback else - local _120_0 = nil + local _124_0 = nil do local t = tbl for _, k in ipairs(path) do if (nil == t) then break end - local _121_0 = type(t) - if (_121_0 == "table") then + local _125_0 = type(t) + if (_125_0 == "table") then t = t[k] else t = nil end end - _120_0 = t + _124_0 = t end - if (nil ~= _120_0) then - local res = _120_0 + if (nil ~= _124_0) then + local res = _124_0 return res else - local _ = _120_0 + local _ = _124_0 return _3ffallback end end @@ -4859,15 +4976,15 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. if (type(f) == "function") then f0 = f else - local function _125_(_241) + local function _129_(_241) return _241[f] end - f0 = _125_ + f0 = _129_ end for _, x in ipairs(t) do - local _127_0 = f0(x) - if (nil ~= _127_0) then - local v = _127_0 + local _131_0 = f0(x) + if (nil ~= _131_0) then + local v = _131_0 table.insert(out, v) end end @@ -4879,19 +4996,19 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. if (type(f) == "function") then f0 = f else - local function _129_(_241) + local function _133_(_241) return _241[f] end - f0 = _129_ + f0 = _133_ end for k, x in stablepairs(t) do - local _131_0, _132_0 = f0(k, x) - if ((nil ~= _131_0) and (nil ~= _132_0)) then - local key = _131_0 - local value = _132_0 + local _135_0, _136_0 = f0(k, x) + if ((nil ~= _135_0) and (nil ~= _136_0)) then + local key = _135_0 + local value = _136_0 out[key] = value - elseif (nil ~= _131_0) then - local value = _131_0 + elseif (nil ~= _135_0) then + local value = _135_0 table.insert(out, value) end end @@ -4908,13 +5025,13 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. return tbl_14_ end local function member_3f(x, tbl, _3fn) - local _135_0 = tbl[(_3fn or 1)] - if (_135_0 == x) then + local _139_0 = tbl[(_3fn or 1)] + if (_139_0 == x) then return true - elseif (_135_0 == nil) then + elseif (_139_0 == nil) then return nil else - local _ = _135_0 + local _ = _139_0 return member_3f(x, tbl, ((_3fn or 1) + 1)) end end @@ -4949,9 +5066,9 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. seen[next_state] = true return next_state, value else - local _138_0 = getmetatable(t) - if ((_G.type(_138_0) == "table") and true) then - local __index = _138_0.__index + local _142_0 = getmetatable(t) + if ((_G.type(_142_0) == "table") and true) then + local __index = _142_0.__index if ("table" == type(__index)) then t = __index return allpairs_next(t) @@ -4969,10 +5086,10 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. local safe = {} local view0 = nil if _3fview then - local function _142_(_241) + local function _146_(_241) return _3fview(_241, _3foptions, _3findent) end - view0 = _142_ + view0 = _146_ else view0 = view end @@ -4993,19 +5110,19 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. end local symbol_mt = {"SYMBOL", __eq = sym_3d, __fennelview = deref, __lt = sym_3c, __tostring = deref} local expr_mt = nil - local function _144_(x) + local function _148_(x) return tostring(deref(x)) end - expr_mt = {"EXPR", __tostring = _144_} + expr_mt = {"EXPR", __tostring = _148_} local list_mt = {"LIST", __fennelview = list__3estring, __tostring = list__3estring} local comment_mt = {"COMMENT", __eq = sym_3d, __fennelview = comment_view, __lt = sym_3c, __tostring = deref} local sequence_marker = {"SEQUENCE"} local varg_mt = {"VARARG", __fennelview = deref, __tostring = deref} local getenv = nil - local function _145_() + local function _149_() return nil end - getenv = ((os and os.getenv) or _145_) + getenv = ((os and os.getenv) or _149_) local function debug_on_3f(flag) local level = (getenv("FENNEL_DEBUG") or "") return ((level == "all") or level:find(flag)) @@ -5014,7 +5131,7 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. return setmetatable({...}, list_mt) end local function sym(str, _3fsource) - local _146_ + local _150_ do local tbl_14_ = {str} for k, v in pairs((_3fsource or {})) do @@ -5028,13 +5145,13 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. tbl_14_[k_15_] = v_16_ end end - _146_ = tbl_14_ + _150_ = tbl_14_ end - return setmetatable(_146_, symbol_mt) + return setmetatable(_150_, symbol_mt) end nil_sym = sym("nil") local function sequence(...) - local function _149_(seq, view0, inspector, indent) + local function _153_(seq, view0, inspector, indent) local opts = nil do inspector["empty-as-sequence?"] = {after = inspector["empty-as-sequence?"], once = true} @@ -5043,19 +5160,19 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. end return view0(seq, opts, indent) end - return setmetatable({...}, {__fennelview = _149_, sequence = sequence_marker}) + return setmetatable({...}, {__fennelview = _153_, sequence = sequence_marker}) end local function expr(strcode, etype) return setmetatable({strcode, type = etype}, expr_mt) end local function comment_2a(contents, _3fsource) - local _150_ = (_3fsource or {}) - local filename = _150_["filename"] - local line = _150_["line"] + local _154_ = (_3fsource or {}) + local filename = _154_["filename"] + local line = _154_["line"] return setmetatable({contents, filename = filename, line = line}, comment_mt) end local function varg(_3fsource) - local _151_ + local _155_ do local tbl_14_ = {"..."} for k, v in pairs((_3fsource or {})) do @@ -5069,9 +5186,9 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. tbl_14_[k_15_] = v_16_ end end - _151_ = tbl_14_ + _155_ = tbl_14_ end - return setmetatable(_151_, varg_mt) + return setmetatable(_155_, varg_mt) end local function expr_3f(x) return ((type(x) == "table") and (getmetatable(x) == expr_mt) and x) @@ -5082,8 +5199,8 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. local function list_3f(x) return ((type(x) == "table") and (getmetatable(x) == list_mt) and x) end - local function sym_3f(x) - return ((type(x) == "table") and (getmetatable(x) == symbol_mt) and x) + local function sym_3f(x, _3fname) + return ((type(x) == "table") and (getmetatable(x) == symbol_mt) and ((nil == _3fname) or (x[1] == _3fname)) and x) end local function sequence_3f(x) local mt = ((type(x) == "table") and getmetatable(x)) @@ -5095,6 +5212,19 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. local function table_3f(x) return ((type(x) == "table") and not varg_3f(x) and (getmetatable(x) ~= list_mt) and (getmetatable(x) ~= symbol_mt) and not comment_3f(x) and x) end + local function kv_table_3f(t) + if table_3f(t) then + local nxt, t0, k = pairs(t) + local len0 = #t0 + local next_state = nil + if (0 == len0) then + next_state = k + else + next_state = len0 + end + return ((nil ~= nxt(t0, next_state)) and t0) + end + end local function string_3f(x) return (type(x) == "string") end @@ -5104,7 +5234,7 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. elseif (type(str) ~= "string") then return false else - local function _154_() + local function _160_() local parts = {} for part in str:gmatch("[^%.%:]+[%.%:]?") do local last_char = part:sub(( - 1)) @@ -5119,7 +5249,7 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. end return ((0 < #parts) and parts) end - return ((str:match("%.") or str:match(":")) and not str:match("%.%.") and (str:byte() ~= string.byte(".")) and (str:byte(-1) ~= string.byte(".")) and (str:byte() ~= string.byte(":")) and (str:byte(-1) ~= string.byte(":")) and _154_()) + return ((str:match("%.") or str:match(":")) and not str:match("%.%.") and (str:byte() ~= string.byte(".")) and (str:byte(-1) ~= string.byte(".")) and (str:byte() ~= string.byte(":")) and (str:byte(-1) ~= string.byte(":")) and _160_()) end end local function quoted_3f(symbol) @@ -5149,10 +5279,7 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. walk((_3fcustom_iterator or pairs), nil, nil, root) return root end - local lua_keywords = {"and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while", "goto"} - for i, v in ipairs(lua_keywords) do - lua_keywords[v] = i - end + local lua_keywords = {["and"] = true, ["break"] = true, ["do"] = true, ["else"] = true, ["elseif"] = true, ["end"] = true, ["false"] = true, ["for"] = true, ["function"] = true, ["goto"] = true, ["if"] = true, ["in"] = true, ["local"] = true, ["nil"] = true, ["not"] = true, ["or"] = true, ["repeat"] = true, ["return"] = true, ["then"] = true, ["true"] = true, ["until"] = true, ["while"] = true} local function valid_lua_identifier_3f(str) return (str:match("^[%a_][%w_]*$") and not lua_keywords[str]) end @@ -5164,15 +5291,15 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. return subopts end local root = nil - local function _160_() + local function _166_() end - root = {chunk = nil, options = nil, reset = _160_, scope = nil} - root["set-reset"] = function(_161_0) - local _162_ = _161_0 - local chunk = _162_["chunk"] - local options = _162_["options"] - local reset = _162_["reset"] - local scope = _162_["scope"] + root = {chunk = nil, options = nil, reset = _166_, scope = nil} + root["set-reset"] = function(_167_0) + local _168_ = _167_0 + local chunk = _168_["chunk"] + local options = _168_["options"] + local reset = _168_["reset"] + local scope = _168_["scope"] root.reset = function() root.chunk, root.scope, root.options, root.reset = chunk, scope, options, reset return nil @@ -5180,11 +5307,11 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. return root.reset end local warned = {} - local function check_plugin_version(_163_0) - local _164_ = _163_0 - local plugin = _164_ - local name = _164_["name"] - local versions = _164_["versions"] + local function check_plugin_version(_169_0) + local _170_ = _169_0 + local plugin = _170_ + local name = _170_["name"] + local versions = _170_["versions"] if (not member_3f(version:gsub("-dev", ""), (versions or {})) and not warned[plugin]) then warned[plugin] = true return warn(string.format("plugin %s does not support Fennel version %s", (name or "unknown"), version)) @@ -5192,29 +5319,29 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. end local function hook_opts(event, _3foptions, ...) local plugins = nil - local function _167_(...) - local _166_0 = _3foptions - if (nil ~= _166_0) then - _166_0 = _166_0.plugins + local function _173_(...) + local _172_0 = _3foptions + if (nil ~= _172_0) then + _172_0 = _172_0.plugins end - return _166_0 + return _172_0 end - local function _170_(...) - local _169_0 = root.options - if (nil ~= _169_0) then - _169_0 = _169_0.plugins + local function _176_(...) + local _175_0 = root.options + if (nil ~= _175_0) then + _175_0 = _175_0.plugins end - return _169_0 + return _175_0 end - plugins = (_167_(...) or _170_(...)) + plugins = (_173_(...) or _176_(...)) if plugins then local result = nil for _, plugin in ipairs(plugins) do if result then break end check_plugin_version(plugin) - local _172_0 = plugin[event] - if (nil ~= _172_0) then - local f = _172_0 + local _178_0 = plugin[event] + if (nil ~= _178_0) then + local f = _178_0 result = f(...) else result = nil @@ -5226,7 +5353,7 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. local function hook(event, ...) return hook_opts(event, root.options, ...) end - return {["ast-source"] = ast_source, ["comment?"] = comment_3f, ["debug-on?"] = debug_on_3f, ["every?"] = every_3f, ["expr?"] = expr_3f, ["get-in"] = get_in, ["hook-opts"] = hook_opts, ["idempotent-expr?"] = idempotent_expr_3f, ["list?"] = list_3f, ["lua-keywords"] = lua_keywords, ["macro-path"] = table.concat({"./?.fnl", "./?/init-macros.fnl", "./?/init.fnl", getenv("FENNEL_MACRO_PATH")}, ";"), ["member?"] = member_3f, ["multi-sym?"] = multi_sym_3f, ["propagate-options"] = propagate_options, ["quoted?"] = quoted_3f, ["runtime-version"] = runtime_version, ["sequence?"] = sequence_3f, ["string?"] = string_3f, ["sym?"] = sym_3f, ["table?"] = table_3f, ["valid-lua-identifier?"] = valid_lua_identifier_3f, ["varg?"] = varg_3f, ["walk-tree"] = walk_tree, allpairs = allpairs, comment = comment_2a, copy = copy, expr = expr, hook = hook, kvmap = kvmap, len = len, list = list, map = map, maxn = maxn, path = table.concat({"./?.fnl", "./?/init.fnl", getenv("FENNEL_PATH")}, ";"), root = root, sequence = sequence, stablepairs = stablepairs, sym = sym, varg = varg, version = version, warn = warn} + return {["ast-source"] = ast_source, ["comment?"] = comment_3f, ["debug-on?"] = debug_on_3f, ["every?"] = every_3f, ["expr?"] = expr_3f, ["get-in"] = get_in, ["hook-opts"] = hook_opts, ["idempotent-expr?"] = idempotent_expr_3f, ["kv-table?"] = kv_table_3f, ["list?"] = list_3f, ["lua-keywords"] = lua_keywords, ["macro-path"] = table.concat({"./?.fnl", "./?/init-macros.fnl", "./?/init.fnl", getenv("FENNEL_MACRO_PATH")}, ";"), ["member?"] = member_3f, ["multi-sym?"] = multi_sym_3f, ["propagate-options"] = propagate_options, ["quoted?"] = quoted_3f, ["runtime-version"] = runtime_version, ["sequence?"] = sequence_3f, ["string?"] = string_3f, ["sym?"] = sym_3f, ["table?"] = table_3f, ["valid-lua-identifier?"] = valid_lua_identifier_3f, ["varg?"] = varg_3f, ["walk-tree"] = walk_tree, allpairs = allpairs, comment = comment_2a, copy = copy, expr = expr, hook = hook, kvmap = kvmap, len = len, list = list, map = map, maxn = maxn, path = table.concat({"./?.fnl", "./?/init.fnl", getenv("FENNEL_PATH")}, ";"), root = root, sequence = sequence, stablepairs = stablepairs, sym = sym, varg = varg, version = version, warn = warn} end package.preload["fennel"] = package.preload["fennel"] or function(...) local utils = require("fennel.utils") @@ -5259,24 +5386,24 @@ package.preload["fennel"] = package.preload["fennel"] or function(...) end return opts end - local function eval(str, options, ...) - local opts = eval_opts(options, str) + local function eval(str, _3foptions, ...) + local opts = eval_opts(_3foptions, str) local env = eval_env(opts.env, opts) local lua_source = compiler["compile-string"](str, opts) local loader = nil - local function _709_(...) + local function _735_(...) if opts.filename then return ("@" .. opts.filename) else return str end end - loader = specials["load-code"](lua_source, env, _709_(...)) + loader = specials["load-code"](lua_source, env, _735_(...)) opts.filename = nil return loader(...) end - local function dofile_2a(filename, options, ...) - local opts = utils.copy(options) + local function dofile_2a(filename, _3foptions, ...) + local opts = utils.copy(_3foptions) local f = assert(io.open(filename, "rb")) local source = assert(f:read("*all"), ("Could not read " .. filename)) f:close() @@ -5296,10 +5423,10 @@ package.preload["fennel"] = package.preload["fennel"] or function(...) out[k] = {["binding-form?"] = utils["member?"](k, binding_3f), ["body-form?"] = utils["member?"](k, body_3f), ["define?"] = utils["member?"](k, define_3f), ["macro?"] = true} end for k, v in pairs(_G) do - local _710_0 = type(v) - if (_710_0 == "function") then + local _736_0 = type(v) + if (_736_0 == "function") then out[k] = {["function?"] = true, ["global?"] = true} - elseif (_710_0 == "table") then + elseif (_736_0 == "table") then for k2, v2 in pairs(v) do if (("function" == type(v2)) and (k ~= "_G")) then out[(k .. "." .. k2)] = {["function?"] = true, ["global?"] = true} @@ -5319,17 +5446,17 @@ package.preload["fennel"] = package.preload["fennel"] or function(...) do local module_name = "fennel.macros" local _ = nil - local function _713_() + local function _739_() return mod end - package.preload[module_name] = _713_ + package.preload[module_name] = _739_ _ = nil local env = nil do - local _714_0 = specials["make-compiler-env"](nil, compiler.scopes.compiler, {}) - _714_0["utils"] = utils - _714_0["fennel"] = mod - env = _714_0 + local _740_0 = specials["make-compiler-env"](nil, compiler.scopes.compiler, {}) + _740_0["utils"] = utils + _740_0["fennel"] = mod + env = _740_0 end local built_ins = eval([===[;; These macros are awkward because their definition cannot rely on the any ;; built-in macros, only special forms. (no when, no icollect, etc) @@ -5445,8 +5572,7 @@ package.preload["fennel"] = package.preload["fennel"] or function(...) (var (into iter-out found?) (values [] (copy iter-tbl))) (for [i (length iter-tbl) 2 -1] (let [item (. iter-tbl i)] - (if (or (= `&into item) - (= :into item)) + (if (or (sym? item "&into") (= :into item)) (do (assert (not found?) "expected only one &into clause") (set found? true) @@ -5648,18 +5774,19 @@ package.preload["fennel"] = package.preload["fennel"] or function(...) Like `fn`, but will throw an exception if a declared argument is passed in as nil, unless that argument's name begins with a question mark." (let [args [...] + args-len (length args) has-internal-name? (sym? (. args 1)) arglist (if has-internal-name? (. args 2) (. args 1)) - docstring-position (if has-internal-name? 3 2) - has-docstring? (and (< docstring-position (length args)) - (= :string (type (. args docstring-position)))) + metadata-position (if has-internal-name? 3 2) + has-metadata? (and (< metadata-position args-len) + (or (= :string (type (. args metadata-position))) + (utils.kv-table? (. args metadata-position)))) arity-check-position (- 4 (if has-internal-name? 0 1) - (if has-docstring? 0 1)) - empty-body? (< (length args) arity-check-position)] + (if has-metadata? 0 1)) + empty-body? (< args-len arity-check-position)] (fn check! [a] (if (table? a) - (each [_ a (pairs a)] - (check! a)) + (each [_ a (pairs a)] (check! a)) (let [as (tostring a)] (and (not (as:match "^?")) (not= as "&") (not= as "_") (not= as "...") (not= as "&as"))) @@ -5671,8 +5798,7 @@ package.preload["fennel"] = package.preload["fennel"] or function(...) (or a.line "?")))))) (assert (= :table (type arglist)) "expected arg list") - (each [_ a (ipairs arglist)] - (check! a)) + (each [_ a (ipairs arglist)] (check! a)) (if empty-body? (table.insert args (sym :nil))) `(fn ,(unpack args)))) @@ -5775,7 +5901,7 @@ package.preload["fennel"] = package.preload["fennel"] or function(...) (let [condition `(and (= (_G.type ,val) :table)) bindings []] (each [k pat (pairs pattern)] - (if (= pat `&) + (if (sym? pat :&) (let [rest-pat (. pattern (+ k 1)) rest-val `(select ,k ((or table.unpack _G.unpack) ,val)) subcondition (case-table `(pick-values 1 ,rest-val) @@ -5787,19 +5913,19 @@ package.preload["fennel"] = package.preload["fennel"] or function(...) "expected & rest argument before last parameter") (table.insert bindings rest-pat) (table.insert bindings [rest-val])) - (= k `&as) + (sym? k :&as) (do (table.insert bindings pat) (table.insert bindings val)) - (and (= :number (type k)) (= `&as pat)) + (and (= :number (type k)) (sym? pat :&as)) (do (assert (= nil (. pattern (+ k 2))) "expected &as argument before last parameter") (table.insert bindings (. pattern (+ k 1))) (table.insert bindings val)) ;; don't process the pattern right after &/&as; already got it - (or (not= :number (type k)) (and (not= `&as (. pattern (- k 1))) - (not= `& (. pattern (- k 1))))) + (or (not= :number (type k)) (and (not (sym? (. pattern (- k 1)) :&as)) + (not (sym? (. pattern (- k 1)) :&)))) (let [subval `(. ,val ,k) (subcondition subbindings) (case-pattern [subval] pat unifications @@ -5820,16 +5946,19 @@ package.preload["fennel"] = package.preload["fennel"] or function(...) (fn symbols-in-pattern [pattern] "gives the set of symbols inside a pattern" (if (list? pattern) - (let [result {}] - (each [_ child-pattern (ipairs pattern)] - (collect [name symbol (pairs (symbols-in-pattern child-pattern)) &into result] - name symbol)) - result) + (if (or (sym? (. pattern 1) :where) + (sym? (. pattern 1) :=)) + (symbols-in-pattern (. pattern 2)) + (sym? (. pattern 2) :?) + (symbols-in-pattern (. pattern 1)) + (let [result {}] + (each [_ child-pattern (ipairs pattern)] + (collect [name symbol (pairs (symbols-in-pattern child-pattern)) &into result] + name symbol)) + result)) (sym? pattern) - (if (and (not= pattern `or) - (not= pattern `where) - (not= pattern `?) - (not= pattern `nil)) + (if (and (not (sym? pattern :or)) + (not (sym? pattern :nil))) {(tostring pattern) pattern} {}) (= (type pattern) :table) @@ -5912,10 +6041,10 @@ package.preload["fennel"] = package.preload["fennel"] or function(...) ;; of vals) or we're not, in which case we only care about the first one. (let [[val] vals] (if (and (sym? pattern) - (or (= pattern `nil) + (or (sym? pattern :nil) (and opts.infer-unification? (in-scope? pattern) - (not= pattern `_)) + (not (sym? pattern :_))) (and opts.infer-unification? (multi-sym? pattern) (in-scope? (. (multi-sym? pattern) 1))))) @@ -5931,33 +6060,33 @@ package.preload["fennel"] = package.preload["fennel"] or function(...) `(not= ,(sym :nil) ,val)) [pattern val])) ;; opt-in unify with (=) (and (list? pattern) - (= (. pattern 1) `=) + (sym? (. pattern 1) :=) (sym? (. pattern 2))) (let [bind (. pattern 2)] (assert-compile (= 2 (length pattern)) "(=) should take only one argument" pattern) (assert-compile (not opts.infer-unification?) "(=) cannot be used inside of match" pattern) (assert-compile opts.in-where? "(=) must be used in (where) patterns" pattern) - (assert-compile (and (sym? bind) (not= bind `nil) "= has to bind to a symbol" bind)) + (assert-compile (and (sym? bind) (not (sym? bind :nil)) "= has to bind to a symbol" bind)) (values `(= ,val ,bind) [])) ;; where-or clause - (and (list? pattern) (= (. pattern 1) `where) (list? (. pattern 2)) (= (. pattern 2 1) `or)) + (and (list? pattern) (sym? (. pattern 1) :where) (list? (. pattern 2)) (sym? (. pattern 2 1) :or)) (do (assert-compile top-level? "can't nest (where) pattern" pattern) (case-or vals (. pattern 2) [(unpack pattern 3)] unifications case-pattern (with opts :in-where?))) ;; where clause - (and (list? pattern) (= (. pattern 1) `where)) + (and (list? pattern) (sym? (. pattern 1) :where)) (do (assert-compile top-level? "can't nest (where) pattern" pattern) (case-guard vals (. pattern 2) [(unpack pattern 3)] unifications case-pattern (with opts :in-where?))) ;; or clause (not allowed on its own) - (and (list? pattern) (= (. pattern 1) `or)) + (and (list? pattern) (sym? (. pattern 1) :or)) (do (assert-compile top-level? "can't nest (or) pattern" pattern) ;; This assertion can be removed to make patterns more permissive (assert-compile false "(or) must be used in (where) patterns" pattern) (case-or vals pattern [] unifications case-pattern opts)) ;; guard clause - (and (list? pattern) (= (. pattern 2) `?)) + (and (list? pattern) (sym? (. pattern 2) :?)) (do (assert-compile opts.legacy-guard-allowed? "legacy guard clause not supported in case" pattern) (case-guard vals (. pattern 1) [(unpack pattern 3)] unifications case-pattern opts)) @@ -6010,11 +6139,11 @@ package.preload["fennel"] = package.preload["fennel"] or function(...) (fn count-case-multival [pattern] "Identify the amount of multival values that a pattern requires." - (if (and (list? pattern) (= (. pattern 2) `?)) + (if (and (list? pattern) (sym? (. pattern 2) :?)) (count-case-multival (. pattern 1)) - (and (list? pattern) (= (. pattern 1) `where)) + (and (list? pattern) (sym? (. pattern 1) :where)) (count-case-multival (. pattern 2)) - (and (list? pattern) (= (. pattern 1) `or)) + (and (list? pattern) (sym? (. pattern 1) :or)) (accumulate [longest 0 _ child-pattern (ipairs pattern)] (math.max longest (count-case-multival child-pattern))) @@ -6022,16 +6151,13 @@ package.preload["fennel"] = package.preload["fennel"] or function(...) (length pattern) 1)) - (fn case-val-syms [clauses] - "What is the length of the largest multi-valued clause? return a list of that - many gensyms." + (fn case-count-syms [clauses] + "Find the length of the largest multi-valued clause" (let [patterns (fcollect [i 1 (length clauses) 2] - (. clauses i)) - sym-count (accumulate [longest 0 - _ pattern (ipairs patterns)] - (math.max longest (count-case-multival pattern)))] - (fcollect [i 1 sym-count &into (list)] - (gensym)))) + (. clauses i))] + (accumulate [longest 0 + _ pattern (ipairs patterns)] + (math.max longest (count-case-multival pattern))))) (fn case-impl [match? val ...] "The shared implementation of case and match." @@ -6041,10 +6167,14 @@ package.preload["fennel"] = package.preload["fennel"] or function(...) (assert (not= 0 (select :# ...)) "expected at least one pattern/body pair") (let [clauses [...] - vals (case-val-syms clauses)] - ;; protect against multiple evaluation of the value, bind against as - ;; many values as we ever match against in the clauses. - (list `let [vals val] (case-condition vals clauses match?)))) + vals-count (case-count-syms clauses) + skips-multiple-eval-protection? (and (= vals-count 1) (sym? val) (not (multi-sym? val)))] + (if skips-multiple-eval-protection? + (case-condition (list val) clauses match?) + ;; protect against multiple evaluation of the value, bind against as + ;; many values as we ever match against in the clauses. + (let [vals (fcollect [i 1 vals-count &into (list)] (gensym))] + (list `let [vals val] (case-condition vals clauses match?)))))) (fn case* [val ...] "Perform pattern matching on val. See reference for details. @@ -6090,7 +6220,7 @@ package.preload["fennel"] = package.preload["fennel"] or function(...) (fn case-try-impl [how expr pattern body ...] (let [clauses [pattern body ...] last (. clauses (length clauses)) - catch (if (= `catch (and (= :table (type last)) (. last 1))) + catch (if (sym? (and (= :table (type last)) (. last 1)) :catch) (let [[_ & e] (table.remove clauses)] e) ; remove `catch sym [`_# `...])] (assert (= 0 (math.fmod (length clauses) 2)) @@ -6139,20 +6269,20 @@ package.preload["fennel"] = package.preload["fennel"] or function(...) end fennel = require("fennel") local unpack = (table.unpack or _G.unpack) -local help = "\nUsage: fennel [FLAG] [FILE]\n\nRun fennel, a lisp programming language for the Lua runtime.\n\n --repl : Command to launch an interactive repl session\n --compile FILES (-c) : Command to AOT compile files, writing Lua to stdout\n --eval SOURCE (-e) : Command to evaluate source code and print the result\n\n --no-searcher : Skip installing package.searchers entry\n --indent VAL : Indent compiler output with VAL\n --add-package-path PATH : Add PATH to package.path for finding Lua modules\n --add-fennel-path PATH : Add PATH to fennel.path for finding Fennel modules\n --add-macro-path PATH : Add PATH to fennel.macro-path for macro modules\n --globals G1[,G2...] : Allow these globals in addition to standard ones\n --globals-only G1[,G2] : Same as above, but exclude standard ones\n --require-as-include : Inline required modules in the output\n --skip-include M1[,M2] : Omit certain modules from output when included\n --use-bit-lib : Use LuaJITs bit library instead of operators\n --metadata : Enable function metadata, even in compiled output\n --no-metadata : Disable function metadata, even in REPL\n --correlate : Make Lua output line numbers match Fennel input\n --load FILE (-l) : Load the specified FILE before executing the command\n --lua LUA_EXE : Run in a child process with LUA_EXE\n --no-fennelrc : Skip loading ~/.fennelrc when launching repl\n --raw-errors : Disable friendly compile error reporting\n --plugin FILE : Activate the compiler plugin in FILE\n --compile-binary FILE\n OUT LUA_LIB LUA_DIR : Compile FILE to standalone binary OUT\n --compile-binary --help : Display further help for compiling binaries\n --no-compiler-sandbox : Do not limit compiler environment to minimal sandbox\n\n --help (-h) : Display this text\n --version (-v) : Show version\n\nGlobals are not checked when doing AOT (ahead-of-time) compilation unless\nthe --globals-only or --globals flag is provided. Use --globals \"*\" to disable\nstrict globals checking in other contexts.\n\nMetadata is typically considered a development feature and is not recommended\nfor production. It is used for docstrings and enabled by default in the REPL.\n\nWhen not given a command, runs the file given as the first argument.\nWhen given neither command nor file, launches a repl.\n\nUse the NO_COLOR environment variable to disable escape codes in error messages.\n\nIf ~/.fennelrc exists, it will be loaded before launching a repl." +local help = "\nUsage: fennel [FLAG] [FILE]\n\nRun fennel, a lisp programming language for the Lua runtime.\n\n --repl : Command to launch an interactive repl session\n --compile FILES (-c) : Command to AOT compile files, writing Lua to stdout\n --eval SOURCE (-e) : Command to evaluate source code and print result\n\n --no-searcher : Skip installing package.searchers entry\n --indent VAL : Indent compiler output with VAL\n --add-package-path PATH : Add PATH to package.path for finding Lua modules\n --add-package-cpath PATH : Add PATH to package.cpath for finding Lua modules\n --add-fennel-path PATH : Add PATH to fennel.path for finding Fennel modules\n --add-macro-path PATH : Add PATH to fennel.macro-path for macro modules\n --globals G1[,G2...] : Allow these globals in addition to standard ones\n --globals-only G1[,G2] : Same as above, but exclude standard ones\n --require-as-include : Inline required modules in the output\n --skip-include M1[,M2] : Omit certain modules from output when included\n --use-bit-lib : Use LuaJITs bit library instead of operators\n --metadata : Enable function metadata, even in compiled output\n --no-metadata : Disable function metadata, even in REPL\n --correlate : Make Lua output line numbers match Fennel input\n --load FILE (-l) : Load the specified FILE before executing command\n --lua LUA_EXE : Run in a child process with LUA_EXE\n --no-fennelrc : Skip loading ~/.fennelrc when launching repl\n --raw-errors : Disable friendly compile error reporting\n --plugin FILE : Activate the compiler plugin in FILE\n --compile-binary FILE\n OUT LUA_LIB LUA_DIR : Compile FILE to standalone binary OUT\n --compile-binary --help : Display further help for compiling binaries\n --no-compiler-sandbox : Don't limit compiler environment to minimal sandbox\n\n --help (-h) : Display this text\n --version (-v) : Show version\n\nGlobals are not checked when doing AOT (ahead-of-time) compilation unless\nthe --globals-only or --globals flag is provided. Use --globals \"*\" to disable\nstrict globals checking in other contexts.\n\nMetadata is typically considered a development feature and is not recommended\nfor production. It is used for docstrings and enabled by default in the REPL.\n\nWhen not given a command, runs the file given as the first argument.\nWhen given neither command nor file, launches a repl.\n\nUse the NO_COLOR environment variable to disable escape codes in error messages.\n\nIf ~/.fennelrc exists, it will be loaded before launching a repl." local options = {plugins = {}} local function pack(...) - local _715_0 = {...} - _715_0["n"] = select("#", ...) - return _715_0 + local _741_0 = {...} + _741_0["n"] = select("#", ...) + return _741_0 end local function dosafely(f, ...) local args = {...} local result = nil - local function _716_() + local function _742_() return f(unpack(args)) end - result = pack(xpcall(_716_, fennel.traceback)) + result = pack(xpcall(_742_, fennel.traceback)) if not result[1] then do end (io.stderr):write((result[2] .. "\n")) os.exit(1) @@ -6194,19 +6324,22 @@ local function handle_lua(i) for i0 = 1, #arg do table.insert(cmd, string.format("%q", arg[i0])) end - local ok = os.execute(table.concat(cmd, " ")) - local _720_ - if ok then - _720_ = 0 - else - _720_ = 1 + if (nil == arg[-1]) then + do end (io.stderr):write("WARNING: --lua argument only works from script, not binary.\n") end - return os.exit(_720_, true) + local ok = os.execute(table.concat(cmd, " ")) + local _747_ + if ok then + _747_ = 0 + else + _747_ = 1 + end + return os.exit(_747_, true) end assert(arg, "Using the launcher from non-CLI context; use fennel.lua instead.") for i = #arg, 1, -1 do - local _722_0 = arg[i] - if (_722_0 == "--lua") then + local _749_0 = arg[i] + if (_749_0 == "--lua") then handle_lua(i) end end @@ -6214,51 +6347,55 @@ do local commands = {["-"] = true, ["--compile"] = true, ["--compile-binary"] = true, ["--eval"] = true, ["--help"] = true, ["--repl"] = true, ["--version"] = true, ["-c"] = true, ["-e"] = true, ["-h"] = true, ["-v"] = true} local i = 1 while (arg[i] and not options["ignore-options"]) do - local _724_0 = arg[i] - if (_724_0 == "--no-searcher") then + local _751_0 = arg[i] + if (_751_0 == "--no-searcher") then options["no-searcher"] = true table.remove(arg, i) - elseif (_724_0 == "--indent") then + elseif (_751_0 == "--indent") then options.indent = table.remove(arg, (i + 1)) if (options.indent == "false") then options.indent = false end table.remove(arg, i) - elseif (_724_0 == "--add-package-path") then + elseif (_751_0 == "--add-package-path") then local entry = table.remove(arg, (i + 1)) package.path = (entry .. ";" .. package.path) table.remove(arg, i) - elseif (_724_0 == "--add-fennel-path") then + elseif (_751_0 == "--add-package-cpath") then + local entry = table.remove(arg, (i + 1)) + package.cpath = (entry .. ";" .. package.cpath) + table.remove(arg, i) + elseif (_751_0 == "--add-fennel-path") then local entry = table.remove(arg, (i + 1)) fennel.path = (entry .. ";" .. fennel.path) table.remove(arg, i) - elseif (_724_0 == "--add-macro-path") then + elseif (_751_0 == "--add-macro-path") then local entry = table.remove(arg, (i + 1)) fennel["macro-path"] = (entry .. ";" .. fennel["macro-path"]) table.remove(arg, i) - elseif (_724_0 == "--load") then + elseif (_751_0 == "--load") then handle_load(i) - elseif (_724_0 == "-l") then + elseif (_751_0 == "-l") then handle_load(i) - elseif (_724_0 == "--no-fennelrc") then + elseif (_751_0 == "--no-fennelrc") then options.fennelrc = false table.remove(arg, i) - elseif (_724_0 == "--correlate") then + elseif (_751_0 == "--correlate") then options.correlate = true table.remove(arg, i) - elseif (_724_0 == "--check-unused-locals") then + elseif (_751_0 == "--check-unused-locals") then options.checkUnusedLocals = true table.remove(arg, i) - elseif (_724_0 == "--globals") then + elseif (_751_0 == "--globals") then allow_globals(table.remove(arg, (i + 1)), _G) table.remove(arg, i) - elseif (_724_0 == "--globals-only") then + elseif (_751_0 == "--globals-only") then allow_globals(table.remove(arg, (i + 1)), {}) table.remove(arg, i) - elseif (_724_0 == "--require-as-include") then + elseif (_751_0 == "--require-as-include") then options.requireAsInclude = true table.remove(arg, i) - elseif (_724_0 == "--skip-include") then + elseif (_751_0 == "--skip-include") then local skip_names = table.remove(arg, (i + 1)) local skip = nil do @@ -6275,28 +6412,28 @@ do end options.skipInclude = skip table.remove(arg, i) - elseif (_724_0 == "--use-bit-lib") then + elseif (_751_0 == "--use-bit-lib") then options.useBitLib = true table.remove(arg, i) - elseif (_724_0 == "--metadata") then + elseif (_751_0 == "--metadata") then options.useMetadata = true table.remove(arg, i) - elseif (_724_0 == "--no-metadata") then + elseif (_751_0 == "--no-metadata") then options.useMetadata = false table.remove(arg, i) - elseif (_724_0 == "--no-compiler-sandbox") then + elseif (_751_0 == "--no-compiler-sandbox") then options["compiler-env"] = _G table.remove(arg, i) - elseif (_724_0 == "--raw-errors") then + elseif (_751_0 == "--raw-errors") then options.unfriendly = true table.remove(arg, i) - elseif (_724_0 == "--plugin") then + elseif (_751_0 == "--plugin") then local opts = {["compiler-env"] = _G, env = "_COMPILER", useMetadata = true} local plugin = fennel.dofile(table.remove(arg, (i + 1)), opts) table.insert(options.plugins, 1, plugin) table.remove(arg, i) else - local _ = _724_0 + local _ = _751_0 if not commands[arg[i]] then options["ignore-options"] = true i = (i + 1) @@ -6344,13 +6481,13 @@ local function repl() return fennel.repl(options) end local function eval(form) - local _734_ + local _761_ if (form == "-") then - _734_ = (io.stdin):read("*a") + _761_ = (io.stdin):read("*a") else - _734_ = form + _761_ = form end - return print(dosafely(fennel.eval, _734_, options)) + return print(dosafely(fennel.eval, _761_, options)) end local function compile(files) for _, filename in ipairs(files) do @@ -6362,17 +6499,17 @@ local function compile(files) f = assert(io.open(filename, "rb")) end do - local _737_0, _738_0 = nil, nil - local function _739_() + local _764_0, _765_0 = nil, nil + local function _766_() return fennel["compile-string"](f:read("*a"), options) end - _737_0, _738_0 = xpcall(_739_, fennel.traceback) - if ((_737_0 == true) and (nil ~= _738_0)) then - local val = _738_0 + _764_0, _765_0 = xpcall(_766_, fennel.traceback) + if ((_764_0 == true) and (nil ~= _765_0)) then + local val = _765_0 print(val) - elseif (true and (nil ~= _738_0)) then - local _0 = _737_0 - local msg = _738_0 + elseif (true and (nil ~= _765_0)) then + local _0 = _764_0 + local msg = _765_0 do end (io.stderr):write((msg .. "\n")) os.exit(1) end @@ -6381,57 +6518,57 @@ local function compile(files) end return nil end -local _741_0 = arg -local function _742_(...) +local _768_0 = arg +local function _769_(...) return (0 == #arg) end -if ((_G.type(_741_0) == "table") and _742_(...)) then +if ((_G.type(_768_0) == "table") and _769_(...)) then return repl() -elseif ((_G.type(_741_0) == "table") and (_741_0[1] == "--repl")) then +elseif ((_G.type(_768_0) == "table") and (_768_0[1] == "--repl")) then return repl() -elseif ((_G.type(_741_0) == "table") and (_741_0[1] == "--compile")) then - local files = {select(2, (table.unpack or _G.unpack)(_741_0))} +elseif ((_G.type(_768_0) == "table") and (_768_0[1] == "--compile")) then + local files = {select(2, (table.unpack or _G.unpack)(_768_0))} return compile(files) -elseif ((_G.type(_741_0) == "table") and (_741_0[1] == "-c")) then - local files = {select(2, (table.unpack or _G.unpack)(_741_0))} +elseif ((_G.type(_768_0) == "table") and (_768_0[1] == "-c")) then + local files = {select(2, (table.unpack or _G.unpack)(_768_0))} return compile(files) -elseif ((_G.type(_741_0) == "table") and (_741_0[1] == "--compile-binary") and (nil ~= _741_0[2]) and (nil ~= _741_0[3]) and (nil ~= _741_0[4]) and (nil ~= _741_0[5])) then - local filename = _741_0[2] - local out = _741_0[3] - local static_lua = _741_0[4] - local lua_include_dir = _741_0[5] - local args = {select(6, (table.unpack or _G.unpack)(_741_0))} +elseif ((_G.type(_768_0) == "table") and (_768_0[1] == "--compile-binary") and (nil ~= _768_0[2]) and (nil ~= _768_0[3]) and (nil ~= _768_0[4]) and (nil ~= _768_0[5])) then + local filename = _768_0[2] + local out = _768_0[3] + local static_lua = _768_0[4] + local lua_include_dir = _768_0[5] + local args = {select(6, (table.unpack or _G.unpack)(_768_0))} local bin = require("fennel.binary") options.filename = filename options.requireAsInclude = true return bin.compile(filename, out, static_lua, lua_include_dir, options, args) -elseif ((_G.type(_741_0) == "table") and (_741_0[1] == "--compile-binary")) then +elseif ((_G.type(_768_0) == "table") and (_768_0[1] == "--compile-binary")) then local cmd = (arg[0] or "fennel") return print((require("fennel.binary").help):format(cmd, cmd, cmd)) -elseif ((_G.type(_741_0) == "table") and (_741_0[1] == "--eval") and (nil ~= _741_0[2])) then - local form = _741_0[2] +elseif ((_G.type(_768_0) == "table") and (_768_0[1] == "--eval") and (nil ~= _768_0[2])) then + local form = _768_0[2] return eval(form) -elseif ((_G.type(_741_0) == "table") and (_741_0[1] == "-e") and (nil ~= _741_0[2])) then - local form = _741_0[2] +elseif ((_G.type(_768_0) == "table") and (_768_0[1] == "-e") and (nil ~= _768_0[2])) then + local form = _768_0[2] return eval(form) else - local function _770_(...) - local a = _741_0[1] + local function _797_(...) + local a = _768_0[1] return ((a == "-v") or (a == "--version")) end - if (((_G.type(_741_0) == "table") and (nil ~= _741_0[1])) and _770_(...)) then - local a = _741_0[1] + if (((_G.type(_768_0) == "table") and (nil ~= _768_0[1])) and _797_(...)) then + local a = _768_0[1] return print(fennel["runtime-version"]()) - elseif ((_G.type(_741_0) == "table") and (_741_0[1] == "--help")) then + elseif ((_G.type(_768_0) == "table") and (_768_0[1] == "--help")) then return print(help) - elseif ((_G.type(_741_0) == "table") and (_741_0[1] == "-h")) then + elseif ((_G.type(_768_0) == "table") and (_768_0[1] == "-h")) then return print(help) - elseif ((_G.type(_741_0) == "table") and (_741_0[1] == "-")) then - local args = {select(2, (table.unpack or _G.unpack)(_741_0))} + elseif ((_G.type(_768_0) == "table") and (_768_0[1] == "-")) then + local args = {select(2, (table.unpack or _G.unpack)(_768_0))} return dosafely(fennel.eval, (io.stdin):read("*a")) - elseif ((_G.type(_741_0) == "table") and (nil ~= _741_0[1])) then - local filename = _741_0[1] - local args = {select(2, (table.unpack or _G.unpack)(_741_0))} + elseif ((_G.type(_768_0) == "table") and (nil ~= _768_0[1])) then + local filename = _768_0[1] + local args = {select(2, (table.unpack or _G.unpack)(_768_0))} arg[-2] = arg[-1] arg[-1] = arg[0] arg[0] = table.remove(arg, 1) diff --git a/src/fennel-ls/compiler.fnl b/src/fennel-ls/compiler.fnl index c15e8bd..ff63aa5 100644 --- a/src/fennel-ls/compiler.fnl +++ b/src/fennel-ls/compiler.fnl @@ -40,10 +40,18 @@ later by fennel-ls.language to answer requests from the client." (tset self key val) val))}) +(位 line+byte->range [self file line byte] + (let [line (- line 1) + ;; TODO think about this further when upstream bug #180 is fixed + byte (math.max 0 byte) + position (utils.pos->position file.text line byte self.position-encoding)] + {:start position :end position})) + + (位 is-values? [?ast] (and (list? ?ast) (= (sym :values) (. ?ast 1)))) -(位 compile [{:configuration {: macro-path} : root-uri} file] +(位 compile [{:configuration {: macro-path} : root-uri &as self} file] "Compile the file, and record all the useful information from the compiler into the file object" ;; The useful information being recorded: (let [definitions-by-scope (doto {} (setmetatable has-tables-mt)) @@ -193,7 +201,7 @@ later by fennel-ls.language to answer requests from the client." ;; This cannot be done through the :fn feature of the compiler plugin system ;; because it needs to be called *before* the body of the function is processed. ;; TODO check if hashfn needs to be here - (where (or [(= -fn-)] [(= -lambda-)] [(= -位-)] false)) ;; TODO, this false pattern should not ever match, and should be removed once I update fennel + (where (or [(= -fn-)] [(= -lambda-)] [(= -位-)])) (define-function ast scope) (where [(= -require-) _modname]) (tset require-calls ast true) @@ -210,8 +218,8 @@ later by fennel-ls.language to answer requests from the client." (= 1 (msg:find "expected at least one pattern/body pair")))) (位 on-compile-error [_ msg ast call-me-to-reset-the-compiler] - (let [range (or (message.ast->range ast file) - (message.pos->range 0 0 0 0))] + (let [range (or (message.ast->range self file ast) + (line+byte->range self file 1 1))] (table.insert diagnostics {:range range :message msg @@ -224,10 +232,9 @@ later by fennel-ls.language to answer requests from the client." (call-me-to-reset-the-compiler) (error "__NOT_AN_ERROR")))) - (位 on-parse-error [msg file line byte] - ;; assume byte and char count is the same, ie no UTF-8 - (let [line (- line 1) - range (message.pos->range line byte line byte)] + (位 on-parse-error [msg filename line byte _source call-me-to-reset-the-compiler] + (let [line (if (= line "?") 1 line) + range (line+byte->range self file line byte)] (table.insert diagnostics {:range range :message msg @@ -236,7 +243,9 @@ later by fennel-ls.language to answer requests from the client." :codeDescription "parse error"})) (if (recoverable? msg) true - (error "__NOT_AN_ERROR"))) + (do + (call-me-to-reset-the-compiler) + (error "__NOT_AN_ERROR")))) (local allowed-globals (icollect [k _ (pairs _G)] @@ -247,7 +256,7 @@ later by fennel-ls.language to answer requests from the client." (let [macro-file? (= (: file.text :sub 1 24) ";; fennel-ls: macro-file") plugin {:name "fennel-ls" - :versions ["1.3.1"] + :versions ["1.3.2"] : symbol-to-expression : call : destructure @@ -266,8 +275,20 @@ later by fennel-ls.language to answer requests from the client." :allowedGlobals allowed-globals :requireAsInclude false : scope} - parser (partial pcall (fennel.parser file.text file.uri opts)) - ast (icollect [ok ok-2 ast parser &until (not (and ok ok-2))] ast)] + + parser (let [p (fennel.parser file.text file.uri opts)] + (fn p1 [p2 p3] + (case (xpcall #(p p2 p3) fennel.traceback) + (true r1 r2) (values r1 r2) + (where (or (nil err) (false err)) (not (err:find "^[^\n]-__NOT_AN_ERROR\n"))) + (if (os.getenv :TESTING) + (error (.. "\nYou have crashed the fennel parser or fennel-ls with the following message\n:" err + "\n\n^^^ the error message above here is the root problem\n\n")) + (table.insert diagnostics + {:range (line+byte->range self file 1 1) + :message (.. "unrecoverable compiler error: " err)}))))) + + ast (icollect [ok ast parser &until (not ok)] ast)] ;; This is bad; we mutate fennel.macro-path @@ -282,7 +303,7 @@ later by fennel-ls.language to answer requests from the client." (error (.. "\nYou have crashed the fennel compiler or fennel-ls with the following message\n:" err "\n\n^^^ the error message above here is the root problem\n\n")) (table.insert diagnostics - {:range (message.pos->range 0 0 0 0) + {:range (line+byte->range self file 1 1) :message (.. "unrecoverable compiler error: " err)})))) (set fennel.macro-path old-macro-path)) diff --git a/src/fennel-ls/diagnostics.fnl b/src/fennel-ls/diagnostics.fnl index 664c271..7c6995b 100644 --- a/src/fennel-ls/diagnostics.fnl +++ b/src/fennel-ls/diagnostics.fnl @@ -11,7 +11,7 @@ Goes through a file and mutates the `file.diagnostics` field, filling it with di (icollect [symbol definition (pairs file.definitions) &into file.diagnostics] (if (and (= 0 (length definition.referenced-by)) (not= "_" (: (tostring symbol) :sub 1 1))) - {:range (message.ast->range symbol file) + {:range (message.ast->range self file symbol) :message (.. "unused definition: " (tostring symbol)) :severity message.severity.WARN :code 301 @@ -24,7 +24,7 @@ Goes through a file and mutates the `file.diagnostics` field, filling it with di (let [opts {} item (language.search self file symbol [] opts)] (if (and (not item) opts.searched-through-require) - {:range (message.ast->range symbol file) + {:range (message.ast->range self file symbol) :message (.. "unknown field " (tostring symbol)) :severity message.severity.WARN :code 302 diff --git a/src/fennel-ls/handlers.fnl b/src/fennel-ls/handlers.fnl index b013e8e..6d89dec 100644 --- a/src/fennel-ls/handlers.fnl +++ b/src/fennel-ls/handlers.fnl @@ -18,7 +18,7 @@ Every time the client sends a message, it gets handled by a function in the corr (local notifications []) (local capabilities - {:textDocumentSync 1 ;; FIXME: upgrade to 2 + {:textDocumentSync {:openClose true :change 2} ;; :notebookDocumentSync nil :completionProvider {:workDoneProgress false} ;; TODO :hoverProvider {:workDoneProgress false @@ -69,25 +69,24 @@ Every time the client sends a message, it gets handled by a function in the corr (位 requests.textDocument/definition [self send {: position :textDocument {: uri}}] (let [file (state.get-by-uri self uri) - byte (utils.pos->byte file.text position.line position.character)] + byte (utils.position->byte file.text position self.position-encoding)] (case-try (language.find-symbol file.ast byte) - (symbol parents) - ;; TODO unruin this match-try - (let [parent (. parents 1)] - (if (. file.require-calls parent) - (language.search self file parent [] {:stop-early? true}) - (language.search-main self file symbol {:stop-early? true} byte))) + (symbol [parent]) + (if + ;; require call + (. file.require-calls parent) + (language.search self file parent [] {:stop-early? true}) + ;; regular symbol + (language.search-main self file symbol {:stop-early? true} byte)) (result result-file) - (message.range-and-uri - (or result.binding result.definition) - result-file) + (message.range-and-uri self result-file (or result.binding result.definition)) (catch _ nil)))) -(位 requests.textDocument/references [self send {:position {: line : character} +(位 requests.textDocument/references [self send {: position :textDocument {: uri} :context {:includeDeclaration ?include-declaration?}}] (let [file (state.get-by-uri self uri) - byte (utils.pos->byte file.text line character)] + byte (utils.position->byte file.text position self.position-encoding)] (case-try (language.find-symbol file.ast byte) symbol (if (. file.definitions symbol) @@ -97,10 +96,10 @@ Every time the client sends a message, it gets handled by a function in the corr (let [result (icollect [_ symbol (ipairs referenced-by)] ;; TODO I currently assume all references are in the same file - (message.range-and-uri symbol result-file))] + (message.range-and-uri self result-file symbol))] (if ?include-declaration? (table.insert result - (message.range-and-uri definition.binding result-file))) + (message.range-and-uri self result-file definition.binding))) ;; TODO don't include duplicates result) @@ -108,11 +107,11 @@ Every time the client sends a message, it gets handled by a function in the corr (位 requests.textDocument/hover [self send {: position :textDocument {: uri}}] (let [file (state.get-by-uri self uri) - byte (utils.pos->byte file.text position.line position.character)] + byte (utils.position->byte file.text position self.position-encoding)] (case-try (language.find-symbol file.ast byte) symbol (language.search-main self file symbol {} byte) result {:contents (formatter.hover-format result) - :range (message.ast->range symbol file)} + :range (message.ast->range self file symbol)} (catch _ nil)))) ;; All of the helper functions for textDocument/completion are here until I @@ -177,7 +176,7 @@ Every time the client sends a message, it gets handled by a function in the corr (位 requests.textDocument/completion [self send {: position :textDocument {: uri}}] (let [file (state.get-by-uri self uri) - byte (utils.pos->byte file.text position.line position.character) + byte (utils.position->byte file.text position self.position-encoding) (?symbol parents) (language.find-symbol file.ast byte)] (case (-?> ?symbol utils.multi-sym-split) (where (or nil [_ nil])) (scope-completion self file byte ?symbol parents) @@ -186,7 +185,7 @@ Every time the client sends a message, it gets handled by a function in the corr (位 notifications.textDocument/didChange [self send {: contentChanges :textDocument {: uri}}] (local file (state.get-by-uri self uri)) - (state.set-uri-contents self uri (utils.apply-changes file.text contentChanges)) + (state.set-uri-contents self uri (utils.apply-changes file.text contentChanges self.position-encoding)) (diagnostics.check self file) (send (message.diagnostics file))) diff --git a/src/fennel-ls/language.fnl b/src/fennel-ls/language.fnl index 2480971..8eff87d 100644 --- a/src/fennel-ls/language.fnl +++ b/src/fennel-ls/language.fnl @@ -2,7 +2,7 @@ The high level analysis system that does deep searches following the data provided by compiler.fnl." -(local {: sym? : list? : sequence? : varg? : sym : view : list} (require :fennel)) +(local {: sym? : list? : sequence? : varg? : sym : view} (require :fennel)) (local utils (require :fennel-ls.utils)) (local state (require :fennel-ls.state)) diff --git a/src/fennel-ls/message.fnl b/src/fennel-ls/message.fnl index 309d9b1..f00fbc4 100644 --- a/src/fennel-ls/message.fnl +++ b/src/fennel-ls/message.fnl @@ -52,26 +52,18 @@ to look to fix this in the future." : id :result ?result}) -(位 pos->range [sl sc el ec] - {:start {:line sl :character sc} - :end {:line el :character ec}}) - -(位 ast->range [?ast file] +(位 ast->range [self file ?ast] (case (values (utils.get-ast-info ?ast :bytestart) (utils.get-ast-info ?ast :byteend)) - (i j) - (let [(start-line start-col) (utils.byte->pos file.text i) - (end-line end-col) (utils.byte->pos file.text (+ j 1))] - (pos->range start-line start-col end-line end-col)))) + (bytestart byteend) + {:start (utils.byte->position file.text bytestart self.position-encoding) + :end (utils.byte->position file.text (+ byteend 1) self.position-encoding)})) -(位 range-and-uri [?ast {: uri &as file}] +(位 range-and-uri [self {: uri &as file} ?ast] "if possible, returns the location of a symbol" - (case (ast->range ?ast file) + (case (ast->range self file ?ast) range {: range : uri})) -(位 log [msg] - (create-notification :window/logMessage {: msg :type 4})) - (位 diagnostics [file] (create-notification "textDocument/publishDiagnostics" @@ -82,9 +74,7 @@ to look to fix this in the future." : create-request : create-response : create-error - : pos->range : ast->range - : log : range-and-uri : diagnostics : severity} diff --git a/src/fennel-ls/state.fnl b/src/fennel-ls/state.fnl index bfa00b3..0a7437f 100644 --- a/src/fennel-ls/state.fnl +++ b/src/fennel-ls/state.fnl @@ -26,21 +26,21 @@ in the \"self\" object." (位 get-by-module [self module] ;; check the cache - (match (. self.modules module) + (case (. self.modules module) uri (or (get-by-uri self uri) ;; if the cached uri isn't found, clear the cache and try again (do (tset self.modules module nil) (get-by-module self module))) nil - (match (searcher.lookup self module) + (case (searcher.lookup self module) uri (do (tset self.modules module uri) (get-by-uri self uri))))) (位 set-uri-contents [self uri text] - (match (. self.files uri) + (case (. self.files uri) ;; modify existing file file (do @@ -77,7 +77,7 @@ in the \"self\" object." (fn make-configuration-from-template [default ?user ?parent] (if (= option-mt (getmetatable default)) (let [setting - (match-try ?user + (case-try ?user nil (?. ?parent :all) nil (. default 1))] (assert (= (type (. default 1)) (type setting))) diff --git a/src/fennel-ls/utils-utf16-surrogate-pairs.fnl b/src/fennel-ls/utils-utf16-surrogate-pairs.fnl deleted file mode 100644 index c4f1022..0000000 --- a/src/fennel-ls/utils-utf16-surrogate-pairs.fnl +++ /dev/null @@ -1,50 +0,0 @@ -(fn utf [byte] - "returns the number of (utf8) bytes, and (utf-16) code units from the first byte of a character" - (if - (<= 0x00 byte 0x80) - (values 1 1) - (<= 0xC0 byte 0xDF) - (values 2 1) - (<= 0xE0 byte 0xEF) - (values 3 1) - (<= 0xF0 byte 0xF7) - (values 4 2) - (error :utf8-error))) - -(fn byte->unit16 [str ?byte] - "convert from normal units to utf16 garbage" - (let [unit8 (or ?byte (length str))] - (var o8 0) - (var o16 0) - (while (< o8 unit8) - (let [(a8 a16) (utf (str:byte (+ 1 o8)))] - (set o8 (+ o8 a8)) - (set o16 (+ o16 a16)))) - (if (= o8 unit8) - o16 - (error :utf8-error)))) - - -(fn unit16->byte [str unit16] - "convert from utf16 garbage to normal units" - (var o8 0) - (var o16 0) - (while (< o16 unit16) - (let [(a8 a16) (utf (str:byte (+ 1 o8)))] - (set o8 (+ o8 a8)) - (set o16 (+ o16 a16)))) - (if (= o16 unit16) - o8 - (error :utf8-error))) - - -(print (byte->unit16 "a位b饜悁" 1) 1) -(print (byte->unit16 "a位b饜悁" 3) 2) -(print (byte->unit16 "a位b饜悁" 4) 3) -(print (byte->unit16 "a位b饜悁") 5) - -(print (unit16->byte "a位b饜悁" 1) 1) -(print (unit16->byte "a位b饜悁" 2) 3) -(print (unit16->byte "a位b饜悁" 3) 4) -(print (unit16->byte "a位b饜悁" 5) 8) - diff --git a/src/fennel-ls/utils.fnl b/src/fennel-ls/utils.fnl index 2b35700..98d161a 100644 --- a/src/fennel-ls/utils.fnl +++ b/src/fennel-ls/utils.fnl @@ -3,6 +3,90 @@ A collection of utility functions. Many of these convert data between a Language-Server-Protocol representation and a Lua representation. These functions are all pure functions, which makes me happy." +(位 next-line [str ?from] + "Find the start of the next line from a given byte offset, or from the start of the string." + (let [from (or ?from 1)] + (case (str:find "[\r\n]" from) + i (+ i (length (str:match "\r?\n?" i))) + nil nil))) + +(位 next-lines [str nlines ?from] + "Find the start of the next line from a given byte offset, or from the start of the string." + (faccumulate [from (or ?from 1) + i 1 nlines] + (next-line str from))) + +(fn utf [byte] + "returns the number of (utf8) bytes, and (utf-16) code units from the first byte of a character" + (if + (<= 0x00 byte 0x80) + (values 1 1) + (<= 0xC0 byte 0xDF) + (values 2 1) + (<= 0xE0 byte 0xEF) + (values 3 1) + (<= 0xF0 byte 0xF7) + (values 4 2) + (error :utf8-error))) + +(fn byte->unit16 [str ?byte] + "convert from normal units to utf16 garbage" + ;; TODO reconsider this when upstream #180 is fixed + (let [unit8 (math.min (length str) ?byte)] + (var o8 0) + (var o16 0) + (while (< o8 unit8) + (let [(a8 a16) (utf (str:byte (+ 1 o8)))] + (set o8 (+ o8 a8)) + (set o16 (+ o16 a16)))) + (if (= o8 unit8) + o16 + (error :utf8-error)))) + + +(fn unit16->byte [str unit16] + "convert from utf16 garbage to normal units" + (var o8 0) + (var o16 0) + (while (< o16 unit16) + (let [(a8 a16) (utf (str:byte (+ 1 o8)))] + (set o8 (+ o8 a8)) + (set o16 (+ o16 a16)))) + (if (= o16 unit16) + o8 + (error :utf8-error))) + +(位 pos->position [str line character encoding] + (case encoding + :utf-8 {: line : character} + :utf-16 (let [pos (next-lines str line)] + {: line + :character (byte->unit16 (str:sub pos) character)}) + _ (error (.. "unknown encoding: " encoding)))) + +(位 byte->position [str byte encoding] + "take a 1-indexed byte, and convert it to an LSP position based on the given encoding" + (var line 0) + (var pos 1) + (while (let [npos (next-line str pos)] + (when (and npos (<= npos byte)) + (set pos npos) + (set line (+ line 1)) + true))) + (case encoding + :utf-8 {: line :character (- byte pos)} + :utf-16 {: line :character (byte->unit16 (str:sub pos) (- byte pos))} + _ (error (.. "unknown encoding: " encoding)))) + +(位 position->byte [str {: line : character} encoding] + "take an LSP position and convert it to a 1-indexed byte based on the given encoding" + (let [pos (next-lines str line)] + (assert pos :bad-pos) + (case encoding + :utf-8 (+ pos character) + :utf-16 (+ pos (unit16->byte (str:sub pos) character)) + _ (error (.. "unknown encoding: " encoding))))) + (位 startswith [str pre] (let [len (length pre)] (= (str:sub 1 len) pre))) @@ -17,55 +101,24 @@ These functions are all pure functions, which makes me happy." "Prepents the \"file://\" prefix to a path to turn it into a uri" (.. "file://" path)) -(位 next-line [str ?from] - "Find the start of the next line from a given byte offset, or from the start of the string." - (let [from (or ?from 1)] - (case (str:find "[\r\n]" from) - i (+ i (length (str:match "\r?\n?" i))) - nil nil))) - -(位 pos->byte [str line col] - "convert a 0-indexed line and column into a 1-indexed byte. Doesn't yet handle UTF8 UTF16 magic from the protocol" - (var sofar 1) - (for [_ 1 line &until (not sofar)] - (set sofar (next-line str sofar))) - (if sofar - (+ sofar col) - nil)) - -(位 byte->pos [str byte] - "convert a 1-indexed byte into a 0-indexed line and column. Doesn't yet handle UTF8 UTF16 magic from the protocol" - (local up-to (str:sub 1 (- byte 1))) - (var lines 0) - (var pos 1) - (var prev nil) - (while (do (set prev pos) - (set pos (next-line up-to pos)) - pos) - (set lines (+ 1 lines))) - (values lines (+ (length up-to) (- prev) 1))) - -(位 replace [text start-line start-col end-line end-col replacement] - "Replaces a range of text with a replacement, using the protocol's definition of range. Doesn't yet handle UTF8 UTF16 magic from the protocol" - (let [start (pos->byte text start-line start-col) - end (pos->byte text end-line end-col)] +(位 replace [text start-position end-position replacement encoding] + "Replaces a range of text with a replacement, using the protocol's definition of range." + (let [start (position->byte text start-position encoding) + end (position->byte text end-position encoding)] (.. (text:sub 1 (- start 1)) replacement (text:sub end)))) -(位 apply-changes [initial-text contentChanges] - "Takes a list of Language-Server-Protocol `contentChanges` and applies them to a piece of text. Doesn't yet handle UTF8 UTF16 magic from the protocol" +(位 apply-changes [initial-text changes encoding] + "Takes a list of Language-Server-Protocol `contentChanges` and applies them to a piece of text." (accumulate [contents initial-text - _ change (ipairs contentChanges)] + _ change (ipairs changes)] (case change ;; Handle a change {:range {: start : end} : text} - (replace contents - start.line start.character - end.line end.character - text) + (replace contents start end text encoding) ;; A replacment of the entire body {: text} text))) @@ -94,8 +147,9 @@ These functions are all pure functions, which makes me happy." {: uri->path : path->uri - : pos->byte - : byte->pos + : pos->position + : byte->position + : position->byte : apply-changes : multi-sym-split : get-ast-info diff --git a/src/fennel.lua b/src/fennel.lua index 976ac45..d8d1c2b 100644 --- a/src/fennel.lua +++ b/src/fennel.lua @@ -6,14 +6,14 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) local view = require("fennel.view") local unpack = (table.unpack or _G.unpack) local function default_read_chunk(parser_state) - local function _591_() + local function _607_() if (0 < parser_state["stack-size"]) then return ".." else return ">> " end end - io.write(_591_()) + io.write(_607_()) io.flush() local input = io.read() return (input and (input .. "\n")) @@ -23,18 +23,18 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) return io.write("\n") end local function default_on_error(errtype, err, lua_source) - local function _593_() - local _592_0 = errtype - if (_592_0 == "Lua Compile") then + local function _609_() + local _608_0 = errtype + if (_608_0 == "Lua Compile") then return ("Bad code generated - likely a bug with the compiler:\n" .. "--- Generated Lua Start ---\n" .. lua_source .. "--- Generated Lua End ---\n") - elseif (_592_0 == "Runtime") then + elseif (_608_0 == "Runtime") then return (compiler.traceback(tostring(err), 4) .. "\n") else - local _ = _592_0 + local _ = _608_0 return ("%s error: %s\n"):format(errtype, tostring(err)) end end - return io.write(_593_()) + return io.write(_609_()) end local function splice_save_locals(env, lua_source, scope) local saves = nil @@ -42,7 +42,7 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) local tbl_17_ = {} local i_18_ = #tbl_17_ for name in pairs(env.___replLocals___) do - local val_19_ = ("local %s = ___replLocals___['%s']"):format(name, name) + local val_19_ = ("local %s = ___replLocals___['%s']"):format((scope.manglings[name] or name), name) if (nil ~= val_19_) then i_18_ = (i_18_ + 1) tbl_17_[i_18_] = val_19_ @@ -54,10 +54,10 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) do local tbl_17_ = {} local i_18_ = #tbl_17_ - for _, name in pairs(scope.manglings) do + for raw, name in pairs(scope.manglings) do local val_19_ = nil if not scope.gensyms[name] then - val_19_ = ("___replLocals___['%s'] = %s"):format(name, name) + val_19_ = ("___replLocals___['%s'] = %s"):format(raw, name) else val_19_ = nil end @@ -74,25 +74,25 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) else gap = " " end - local function _599_() + local function _615_() if next(saves) then return (table.concat(saves, " ") .. gap) else return "" end end - local function _602_() - local _600_0, _601_0 = lua_source:match("^(.*)[\n ](return .*)$") - if ((nil ~= _600_0) and (nil ~= _601_0)) then - local body = _600_0 - local _return = _601_0 + local function _618_() + local _616_0, _617_0 = lua_source:match("^(.*)[\n ](return .*)$") + if ((nil ~= _616_0) and (nil ~= _617_0)) then + local body = _616_0 + local _return = _617_0 return (body .. gap .. table.concat(binds, " ") .. gap .. _return) else - local _ = _600_0 + local _ = _616_0 return lua_source end end - return (_599_() .. _602_()) + return (_615_() .. _618_()) end local function completer(env, scope, text) local max_items = 2000 @@ -104,14 +104,14 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) local scope_first_3f = ((tbl == env) or (tbl == env.___replLocals___)) local tbl_17_ = matches local i_18_ = #tbl_17_ - local function _604_() + local function _620_() if scope_first_3f then return scope.manglings else return tbl end end - for k, is_mangled in utils.allpairs(_604_()) do + for k, is_mangled in utils.allpairs(_620_()) do if (max_items <= #matches) then break end local val_19_ = nil do @@ -179,7 +179,7 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) return input:match("^%s*,") end local function command_docs() - local _613_ + local _629_ do local tbl_17_ = {} local i_18_ = #tbl_17_ @@ -190,18 +190,18 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) tbl_17_[i_18_] = val_19_ end end - _613_ = tbl_17_ + _629_ = tbl_17_ end - return table.concat(_613_, "\n") + return table.concat(_629_, "\n") end commands.help = function(_, _0, on_values) return on_values({("Welcome to Fennel.\nThis is the REPL where you can enter code to be evaluated.\nYou can also run these repl commands:\n\n" .. command_docs() .. "\n ,exit - Leave the repl.\n\nUse ,doc something to see descriptions for individual macros and special forms.\n\nFor more information about the language, see https://fennel-lang.org/reference")}) end do end (compiler.metadata):set(commands.help, "fnl/docstring", "Show this message.") local function reload(module_name, env, on_values, on_error) - local _615_0, _616_0 = pcall(specials["load-code"]("return require(...)", env), module_name) - if ((_615_0 == true) and (nil ~= _616_0)) then - local old = _616_0 + local _631_0, _632_0 = pcall(specials["load-code"]("return require(...)", env), module_name) + if ((_631_0 == true) and (nil ~= _632_0)) then + local old = _632_0 local _ = nil package.loaded[module_name] = nil _ = nil @@ -226,8 +226,8 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) package.loaded[module_name] = old end return on_values({"ok"}) - elseif ((_615_0 == false) and (nil ~= _616_0)) then - local msg = _616_0 + elseif ((_631_0 == false) and (nil ~= _632_0)) then + local msg = _632_0 if msg:match("loop or previous error loading module") then package.loaded[module_name] = nil return reload(module_name, env, on_values, on_error) @@ -235,28 +235,32 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) specials["macro-loaded"][module_name] = nil return nil else - local function _621_() - local _620_0 = msg:gsub("\n.*", "") - return _620_0 + local function _637_() + local _636_0 = msg:gsub("\n.*", "") + return _636_0 end - return on_error("Runtime", _621_()) + return on_error("Runtime", _637_()) end end end local function run_command(read, on_error, f) - local _624_0, _625_0, _626_0 = pcall(read) - if ((_624_0 == true) and (_625_0 == true) and (nil ~= _626_0)) then - local val = _626_0 - return f(val) - elseif (_624_0 == false) then + local _640_0, _641_0, _642_0 = pcall(read) + if ((_640_0 == true) and (_641_0 == true) and (nil ~= _642_0)) then + local val = _642_0 + local _643_0, _644_0 = pcall(f, val) + if ((_643_0 == false) and (nil ~= _644_0)) then + local msg = _644_0 + return on_error("Runtime", msg) + end + elseif (_640_0 == false) then return on_error("Parse", "Couldn't parse input.") end end commands.reload = function(env, read, on_values, on_error) - local function _628_(_241) + local function _647_(_241) return reload(tostring(_241), env, on_values, on_error) end - return run_command(read, on_error, _628_) + return run_command(read, on_error, _647_) end do end (compiler.metadata):set(commands.reload, "fnl/docstring", "Reload the specified module.") commands.reset = function(env, _, on_values) @@ -265,28 +269,28 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) end do end (compiler.metadata):set(commands.reset, "fnl/docstring", "Erase all repl-local scope.") commands.complete = function(env, read, on_values, on_error, scope, chars) - local function _629_() - return on_values(completer(env, scope, string.char(unpack(chars)):gsub(",complete +", ""):sub(1, -2))) + local function _648_() + return on_values(completer(env, scope, table.concat(chars):gsub(",complete +", ""):sub(1, -2))) end - return run_command(read, on_error, _629_) + return run_command(read, on_error, _648_) end do end (compiler.metadata):set(commands.complete, "fnl/docstring", "Print all possible completions for a given input symbol.") local function apropos_2a(pattern, tbl, prefix, seen, names) for name, subtbl in pairs(tbl) do if (("string" == type(name)) and (package ~= subtbl)) then - local _630_0 = type(subtbl) - if (_630_0 == "function") then + local _649_0 = type(subtbl) + if (_649_0 == "function") then if ((prefix .. name)):match(pattern) then table.insert(names, (prefix .. name)) end - elseif (_630_0 == "table") then + elseif (_649_0 == "table") then if not seen[subtbl] then - local _632_ + local _651_ do seen[subtbl] = true - _632_ = seen + _651_ = seen end - apropos_2a(pattern, subtbl, (prefix .. name:gsub("%.", "/") .. "."), _632_, names) + apropos_2a(pattern, subtbl, (prefix .. name:gsub("%.", "/") .. "."), _651_, names) end end end @@ -307,10 +311,10 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) return tbl_17_ end commands.apropos = function(_env, read, on_values, on_error, _scope) - local function _637_(_241) + local function _656_(_241) return on_values(apropos(tostring(_241))) end - return run_command(read, on_error, _637_) + return run_command(read, on_error, _656_) end do end (compiler.metadata):set(commands.apropos, "fnl/docstring", "Print all functions matching a pattern in all loaded modules.") local function apropos_follow_path(path) @@ -330,12 +334,12 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) local tgt = package.loaded for _, path0 in ipairs(paths) do if (nil == tgt) then break end - local _640_ + local _659_ do - local _639_0 = path0:gsub("%/", ".") - _640_ = _639_0 + local _658_0 = path0:gsub("%/", ".") + _659_ = _658_0 end - tgt = tgt[_640_] + tgt = tgt[_659_] end return tgt end @@ -347,9 +351,9 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) do local tgt = apropos_follow_path(path) if ("function" == type(tgt)) then - local _641_0 = (compiler.metadata):get(tgt, "fnl/docstring") - if (nil ~= _641_0) then - local docstr = _641_0 + local _660_0 = (compiler.metadata):get(tgt, "fnl/docstring") + if (nil ~= _660_0) then + local docstr = _660_0 val_19_ = (docstr:match(pattern) and path) else val_19_ = nil @@ -366,10 +370,10 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) return tbl_17_ end commands["apropos-doc"] = function(_env, read, on_values, on_error, _scope) - local function _645_(_241) + local function _664_(_241) return on_values(apropos_doc(tostring(_241))) end - return run_command(read, on_error, _645_) + return run_command(read, on_error, _664_) end do end (compiler.metadata):set(commands["apropos-doc"], "fnl/docstring", "Print all functions that match the pattern in their docs") local function apropos_show_docs(on_values, pattern) @@ -383,92 +387,108 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) return nil end commands["apropos-show-docs"] = function(_env, read, on_values, on_error) - local function _647_(_241) + local function _666_(_241) return apropos_show_docs(on_values, tostring(_241)) end - return run_command(read, on_error, _647_) + return run_command(read, on_error, _666_) end do end (compiler.metadata):set(commands["apropos-show-docs"], "fnl/docstring", "Print all documentations matching a pattern in function name") - local function resolve(identifier, _648_0, scope) - local _649_ = _648_0 - local env = _649_ - local ___replLocals___ = _649_["___replLocals___"] + local function resolve(identifier, _667_0, scope) + local _668_ = _667_0 + local env = _668_ + local ___replLocals___ = _668_["___replLocals___"] local e = nil - local function _650_(_241, _242) - return (___replLocals___[_242] or env[_242]) + local function _669_(_241, _242) + return (___replLocals___[scope.unmanglings[_242]] or env[_242]) end - e = setmetatable({}, {__index = _650_}) - local _651_0, _652_0 = pcall(compiler["compile-string"], tostring(identifier), {scope = scope}) - if ((_651_0 == true) and (nil ~= _652_0)) then - local code = _652_0 - return specials["load-code"](code, e)() + e = setmetatable({}, {__index = _669_}) + local function _670_(...) + local _671_0, _672_0 = ... + if ((_671_0 == true) and (nil ~= _672_0)) then + local code = _672_0 + local function _673_(...) + local _674_0, _675_0 = ... + if ((_674_0 == true) and (nil ~= _675_0)) then + local val = _675_0 + return val + else + local _ = _674_0 + return nil + end + end + return _673_(pcall(specials["load-code"](code, e))) + else + local _ = _671_0 + return nil + end end + return _670_(pcall(compiler["compile-string"], tostring(identifier), {scope = scope})) end commands.find = function(env, read, on_values, on_error, scope) - local function _654_(_241) - local _655_0 = nil + local function _678_(_241) + local _679_0 = nil do - local _656_0 = utils["sym?"](_241) - if (nil ~= _656_0) then - local _657_0 = resolve(_656_0, env, scope) - if (nil ~= _657_0) then - _655_0 = debug.getinfo(_657_0) + local _680_0 = utils["sym?"](_241) + if (nil ~= _680_0) then + local _681_0 = resolve(_680_0, env, scope) + if (nil ~= _681_0) then + _679_0 = debug.getinfo(_681_0) else - _655_0 = _657_0 + _679_0 = _681_0 end else - _655_0 = _656_0 + _679_0 = _680_0 end end - if ((_G.type(_655_0) == "table") and (nil ~= _655_0.linedefined) and (nil ~= _655_0.short_src) and (nil ~= _655_0.source) and (_655_0.what == "Lua")) then - local line = _655_0.linedefined - local src = _655_0.short_src - local source = _655_0.source + if ((_G.type(_679_0) == "table") and (nil ~= _679_0.linedefined) and (nil ~= _679_0.short_src) and (nil ~= _679_0.source) and (_679_0.what == "Lua")) then + local line = _679_0.linedefined + local src = _679_0.short_src + local source = _679_0.source local fnlsrc = nil do - local _660_0 = compiler.sourcemap - if (nil ~= _660_0) then - _660_0 = _660_0[source] + local _684_0 = compiler.sourcemap + if (nil ~= _684_0) then + _684_0 = _684_0[source] end - if (nil ~= _660_0) then - _660_0 = _660_0[line] + if (nil ~= _684_0) then + _684_0 = _684_0[line] end - if (nil ~= _660_0) then - _660_0 = _660_0[2] + if (nil ~= _684_0) then + _684_0 = _684_0[2] end - fnlsrc = _660_0 + fnlsrc = _684_0 end return on_values({string.format("%s:%s", src, (fnlsrc or line))}) - elseif (_655_0 == nil) then + elseif (_679_0 == nil) then return on_error("Repl", "Unknown value") else - local _ = _655_0 + local _ = _679_0 return on_error("Repl", "No source info") end end - return run_command(read, on_error, _654_) + return run_command(read, on_error, _678_) end do end (compiler.metadata):set(commands.find, "fnl/docstring", "Print the filename and line number for a given function") commands.doc = function(env, read, on_values, on_error, scope) - local function _665_(_241) + local function _689_(_241) local name = tostring(_241) local path = (utils["multi-sym?"](name) or {name}) local ok_3f, target = nil, nil - local function _666_() + local function _690_() return (utils["get-in"](scope.specials, path) or utils["get-in"](scope.macros, path) or resolve(name, env, scope)) end - ok_3f, target = pcall(_666_) + ok_3f, target = pcall(_690_) if ok_3f then return on_values({specials.doc(target, name)}) else - return on_error("Repl", "Could not resolve value for docstring lookup") + return on_error("Repl", ("Could not find " .. name .. " for docs.")) end end - return run_command(read, on_error, _665_) + return run_command(read, on_error, _689_) end do end (compiler.metadata):set(commands.doc, "fnl/docstring", "Print the docstring and arglist for a function, macro, or special form.") commands.compile = function(env, read, on_values, on_error, scope) - local function _668_(_241) + local function _692_(_241) local allowedGlobals = specials["current-global-names"](env) local ok_3f, result = pcall(compiler.compile, _241, {allowedGlobals = allowedGlobals, env = env, scope = scope}) if ok_3f then @@ -477,16 +497,16 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) return on_error("Repl", ("Error compiling expression: " .. result)) end end - return run_command(read, on_error, _668_) + return run_command(read, on_error, _692_) end do end (compiler.metadata):set(commands.compile, "fnl/docstring", "compiles the expression into lua and prints the result.") local function load_plugin_commands(plugins) - for _, plugin in ipairs((plugins or {})) do - for name, f in pairs(plugin) do - local _670_0 = name:match("^repl%-command%-(.*)") - if (nil ~= _670_0) then - local cmd_name = _670_0 - commands[cmd_name] = (commands[cmd_name] or f) + for i = #(plugins or {}), 1, -1 do + for name, f in pairs(plugins[i]) do + local _694_0 = name:match("^repl%-command%-(.*)") + if (nil ~= _694_0) then + local cmd_name = _694_0 + commands[cmd_name] = f end end end @@ -495,12 +515,12 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) local function run_command_loop(input, read, loop, env, on_values, on_error, scope, chars) local command_name = input:match(",([^%s/]+)") do - local _672_0 = commands[command_name] - if (nil ~= _672_0) then - local command = _672_0 + local _696_0 = commands[command_name] + if (nil ~= _696_0) then + local command = _696_0 command(env, read, on_values, on_error, scope, chars) else - local _ = _672_0 + local _ = _696_0 if ("exit" ~= command_name) then on_values({"Unknown command", command_name}) end @@ -550,9 +570,9 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) end local function repl(_3foptions) local old_root_options = utils.root.options - local _681_ = utils.copy(_3foptions) - local opts = _681_ - local _3ffennelrc = _681_["fennelrc"] + local _705_ = utils.copy(_3foptions) + local opts = _705_ + local _3ffennelrc = _705_["fennelrc"] local _ = nil opts.fennelrc = nil _ = nil @@ -564,39 +584,43 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) _0 = nil end local env = specials["wrap-env"]((opts.env or rawget(_G, "_ENV") or _G)) + local callbacks = {env = env, onError = (opts.onError or default_on_error), onValues = (opts.onValues or default_on_values), pp = (opts.pp or view), readChunk = (opts.readChunk or default_read_chunk)} local save_locals_3f = (opts.saveLocals ~= false) - local read_chunk = (opts.readChunk or default_read_chunk) - local on_values = (opts.onValues or default_on_values) - local on_error = (opts.onError or default_on_error) - local pp = (opts.pp or view) - local byte_stream, clear_stream = parser.granulate(read_chunk) + local byte_stream, clear_stream = nil, nil + local function _707_(_241) + return callbacks.readChunk(_241) + end + byte_stream, clear_stream = parser.granulate(_707_) local chars = {} local read, reset = nil, nil - local function _683_(parser_state) - local c = byte_stream(parser_state) - table.insert(chars, c) - return c + local function _708_(parser_state) + local b = byte_stream(parser_state) + if b then + table.insert(chars, string.char(b)) + end + return b end - read, reset = parser.parser(_683_) + read, reset = parser.parser(_708_) + env.___repl___ = callbacks opts.env, opts.scope = env, compiler["make-scope"]() opts.useMetadata = (opts.useMetadata ~= false) if (opts.allowedGlobals == nil) then opts.allowedGlobals = specials["current-global-names"](env) end if opts.registerCompleter then - local function _686_() - local _685_0 = opts.scope - local function _687_(...) - return completer(env, _685_0, ...) + local function _712_() + local _711_0 = opts.scope + local function _713_(...) + return completer(env, _711_0, ...) end - return _687_ + return _713_ end - opts.registerCompleter(_686_()) + opts.registerCompleter(_712_()) end load_plugin_commands(opts.plugins) if save_locals_3f then local function newindex(t, k, v) - if opts.scope.unmanglings[k] then + if opts.scope.manglings[k] then return rawset(t, k, v) end end @@ -605,11 +629,12 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) local function print_values(...) local vals = {...} local out = {} + local pp = callbacks.pp env._, env.__ = vals[1], vals for i = 1, select("#", ...) do table.insert(out, pp(vals[i])) end - return on_values(out) + return callbacks.onValues(out) end local function loop() for k in pairs(chars) do @@ -617,51 +642,51 @@ package.preload["fennel.repl"] = package.preload["fennel.repl"] or function(...) end reset() local ok, parser_not_eof_3f, x = pcall(read) - local src_string = string.char(unpack(chars)) + local src_string = table.concat(chars) local readline_not_eof_3f = (not readline or (src_string ~= "(null)")) local not_eof_3f = (readline_not_eof_3f and parser_not_eof_3f) if not ok then - on_error("Parse", not_eof_3f) + callbacks.onError("Parse", not_eof_3f) clear_stream() return loop() elseif command_3f(src_string) then - return run_command_loop(src_string, read, loop, env, on_values, on_error, opts.scope, chars) + return run_command_loop(src_string, read, loop, env, callbacks.onValues, callbacks.onError, opts.scope, chars) else if not_eof_3f then do - local _691_0, _692_0 = nil, nil - local function _693_() + local _717_0, _718_0 = nil, nil + local function _719_() opts["source"] = src_string return opts end - _691_0, _692_0 = pcall(compiler.compile, x, _693_()) - if ((_691_0 == false) and (nil ~= _692_0)) then - local msg = _692_0 + _717_0, _718_0 = pcall(compiler.compile, x, _719_()) + if ((_717_0 == false) and (nil ~= _718_0)) then + local msg = _718_0 clear_stream() - on_error("Compile", msg) - elseif ((_691_0 == true) and (nil ~= _692_0)) then - local src = _692_0 + callbacks.onError("Compile", msg) + elseif ((_717_0 == true) and (nil ~= _718_0)) then + local src = _718_0 local src0 = nil if save_locals_3f then src0 = splice_save_locals(env, src, opts.scope) else src0 = src end - local _695_0, _696_0 = pcall(specials["load-code"], src0, env) - if ((_695_0 == false) and (nil ~= _696_0)) then - local msg = _696_0 + local _721_0, _722_0 = pcall(specials["load-code"], src0, env) + if ((_721_0 == false) and (nil ~= _722_0)) then + local msg = _722_0 clear_stream() - on_error("Lua Compile", msg, src0) - elseif (true and (nil ~= _696_0)) then - local _1 = _695_0 - local chunk = _696_0 - local function _697_() + callbacks.onError("Lua Compile", msg, src0) + elseif (true and (nil ~= _722_0)) then + local _1 = _721_0 + local chunk = _722_0 + local function _723_() return print_values(chunk()) end - local function _698_(...) - return on_error("Runtime", ...) + local function _724_(...) + return callbacks.onError("Runtime", ...) end - xpcall(_697_, _698_) + xpcall(_723_, _724_) end end end @@ -685,14 +710,14 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct local unpack = (table.unpack or _G.unpack) local SPECIALS = compiler.scopes.global.specials local function wrap_env(env) - local function _407_(_, key) + local function _416_(_, key) if utils["string?"](key) then return env[compiler["global-unmangling"](key)] else return env[key] end end - local function _409_(_, key, value) + local function _418_(_, key, value) if utils["string?"](key) then env[compiler["global-unmangling"](key)] = value return nil @@ -701,26 +726,26 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct return nil end end - local function _411_() + local function _420_() local function putenv(k, v) - local _412_ + local _421_ if utils["string?"](k) then - _412_ = compiler["global-unmangling"](k) + _421_ = compiler["global-unmangling"](k) else - _412_ = k + _421_ = k end - return _412_, v + return _421_, v end return next, utils.kvmap(env, putenv), nil end - return setmetatable({}, {__index = _407_, __newindex = _409_, __pairs = _411_}) + return setmetatable({}, {__index = _416_, __newindex = _418_, __pairs = _420_}) end local function current_global_names(_3fenv) local mt = nil do - local _414_0 = getmetatable(_3fenv) - if ((_G.type(_414_0) == "table") and (nil ~= _414_0.__pairs)) then - local mtpairs = _414_0.__pairs + local _423_0 = getmetatable(_3fenv) + if ((_G.type(_423_0) == "table") and (nil ~= _423_0.__pairs)) then + local mtpairs = _423_0.__pairs local tbl_14_ = {} for k, v in mtpairs(_3fenv) do local k_15_, v_16_ = k, v @@ -729,7 +754,7 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end end mt = tbl_14_ - elseif (_414_0 == nil) then + elseif (_423_0 == nil) then mt = (_3fenv or _G) else mt = nil @@ -739,15 +764,15 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end local function load_code(code, _3fenv, _3ffilename) local env = (_3fenv or rawget(_G, "_ENV") or _G) - local _417_0, _418_0 = rawget(_G, "setfenv"), rawget(_G, "loadstring") - if ((nil ~= _417_0) and (nil ~= _418_0)) then - local setfenv = _417_0 - local loadstring = _418_0 + local _426_0, _427_0 = rawget(_G, "setfenv"), rawget(_G, "loadstring") + if ((nil ~= _426_0) and (nil ~= _427_0)) then + local setfenv = _426_0 + local loadstring = _427_0 local f = assert(loadstring(code, _3ffilename)) setfenv(f, env) return f else - local _ = _417_0 + local _ = _426_0 return assert(load(code, _3ffilename, "t", env)) end end @@ -759,13 +784,13 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct local mt = getmetatable(tgt) if ((type(tgt) == "function") or ((type(mt) == "table") and (type(mt.__call) == "function"))) then local arglist = table.concat(((compiler.metadata):get(tgt, "fnl/arglist") or {"#"}), " ") - local _420_ + local _429_ if (0 < #arglist) then - _420_ = " " + _429_ = " " else - _420_ = "" + _429_ = "" end - return string.format("(%s%s%s)\n %s", name, _420_, arglist, docstring) + return string.format("(%s%s%s)\n %s", name, _429_, arglist, docstring) else return string.format("%s\n %s", name, docstring) end @@ -879,9 +904,9 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct local opts = {nval = 1, tail = false} local scope = compiler["make-scope"]() local chunk = {} - local _431_ = compiler.compile1(v, scope, chunk, opts) - local _432_ = _431_[1] - local v0 = _432_[1] + local _440_ = compiler.compile1(v, scope, chunk, opts) + local _441_ = _440_[1] + local v0 = _441_[1] return v0 end local function insert_meta(meta, k, v) @@ -889,23 +914,23 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct compiler.assert((type(k) == "string"), ("expected string keys in metadata table, got: %s"):format(view(k, view_opts))) compiler.assert(literal_3f(v), ("expected literal value in metadata table, got: %s %s"):format(view(k, view_opts), view(v, view_opts))) table.insert(meta, view(k)) - local function _433_() + local function _442_() if ("string" == type(v)) then return view(v, view_opts) else return compile_value(v) end end - table.insert(meta, _433_()) + table.insert(meta, _442_()) return meta end local function insert_arglist(meta, arg_list) local view_opts = {["escape-newlines?"] = true, ["line-length"] = math.huge, ["one-line?"] = true} table.insert(meta, "\"fnl/arglist\"") - local function _434_(_241) + local function _443_(_241) return view(view(_241, view_opts)) end - table.insert(meta, ("{" .. table.concat(utils.map(arg_list, _434_), ", ") .. "}")) + table.insert(meta, ("{" .. table.concat(utils.map(arg_list, _443_), ", ") .. "}")) return meta end local function set_fn_metadata(f_metadata, parent, fn_name) @@ -924,13 +949,13 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end local function get_fn_name(ast, scope, fn_name, multi) if (fn_name and (fn_name[1] ~= "nil")) then - local _437_ + local _446_ if not multi then - _437_ = compiler["declare-local"](fn_name, {}, scope, ast) + _446_ = compiler["declare-local"](fn_name, {}, scope, ast) else - _437_ = compiler["symbol-to-expression"](fn_name, scope)[1] + _446_ = compiler["symbol-to-expression"](fn_name, scope)[1] end - return _437_, not multi, 3 + return _446_, not multi, 3 else return nil, true, 2 end @@ -940,13 +965,13 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct for i = (index + 1), #ast do compiler.compile1(ast[i], f_scope, f_chunk, {nval = (((i ~= #ast) and 0) or nil), tail = (i == #ast)}) end - local _440_ + local _449_ if local_3f then - _440_ = "local function %s(%s)" + _449_ = "local function %s(%s)" else - _440_ = "%s = function(%s)" + _449_ = "%s = function(%s)" end - compiler.emit(parent, string.format(_440_, fn_name, table.concat(arg_name_list, ", ")), ast) + compiler.emit(parent, string.format(_449_, fn_name, table.concat(arg_name_list, ", ")), ast) compiler.emit(parent, f_chunk, ast) compiler.emit(parent, "end", ast) set_fn_metadata(f_metadata, parent, fn_name) @@ -957,52 +982,39 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct local fn_name = compiler.gensym(scope) return compile_named_fn(ast, f_scope, f_chunk, parent, index, fn_name, true, arg_name_list, f_metadata) end - local function assoc_table_3f(t) - local len = #t - local nxt, t0, k = pairs(t) - local function _442_() - if (len == 0) then - return k - else - return len - end + local function maybe_metadata(ast, pred, handler, mt, index) + local index_2a = (index + 1) + local index_2a_before_ast_end_3f = (index_2a < #ast) + local expr = ast[index_2a] + if (index_2a_before_ast_end_3f and pred(expr)) then + return handler(mt, expr), index_2a + else + return mt, index end - return (nil ~= nxt(t0, _442_())) end local function get_function_metadata(ast, arg_list, index) - local f_metadata = {["fnl/arglist"] = arg_list} - local index_2a = (index + 1) - local expr = ast[index_2a] - if (utils["string?"](expr) and (index_2a < #ast)) then - local _443_ - do - f_metadata["fnl/docstring"] = expr - _443_ = f_metadata - end - return _443_, index_2a - elseif (utils["table?"](expr) and (index_2a < #ast) and assoc_table_3f(expr)) then - local _444_ - do - local tbl_14_ = f_metadata - for k, v in pairs(expr) do - local k_15_, v_16_ = k, v - if ((k_15_ ~= nil) and (v_16_ ~= nil)) then - tbl_14_[k_15_] = v_16_ - end + local function _452_(_241, _242) + local tbl_14_ = _241 + for k, v in pairs(_242) do + local k_15_, v_16_ = k, v + if ((k_15_ ~= nil) and (v_16_ ~= nil)) then + tbl_14_[k_15_] = v_16_ end - _444_ = tbl_14_ end - return _444_, index_2a - else - return f_metadata, index + return tbl_14_ end + local function _454_(_241, _242) + _241["fnl/docstring"] = _242 + return _241 + end + return maybe_metadata(ast, utils["kv-table?"], _452_, maybe_metadata(ast, utils["string?"], _454_, {["fnl/arglist"] = arg_list}, index)) end SPECIALS.fn = function(ast, scope, parent) local f_scope = nil do - local _447_0 = compiler["make-scope"](scope) - _447_0["vararg"] = false - f_scope = _447_0 + local _455_0 = compiler["make-scope"](scope) + _455_0["vararg"] = false + f_scope = _455_0 end local f_chunk = {} local fn_sym = utils["sym?"](ast[2]) @@ -1029,7 +1041,7 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct compiler.assert((arg == arg_list[#arg_list]), "expected vararg as last parameter", ast) f_scope.vararg = true return "..." - elseif (utils.sym("&") == arg) then + elseif utils["sym?"](arg, "&") then return destructure_amp(i) elseif (utils["sym?"](arg) and (tostring(arg) ~= "nil") and not utils["multi-sym?"](tostring(arg))) then return compiler["declare-local"](arg, {}, f_scope, ast) @@ -1062,36 +1074,36 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct doc_special("fn", {"name?", "args", "docstring?", "..."}, "Function syntax. May optionally include a name and docstring or a metadata table.\nIf a name is provided, the function will be bound in the current scope.\nWhen called with the wrong number of args, excess args will be discarded\nand lacking args will be nil, use lambda for arity-checked functions.", true) SPECIALS.lua = function(ast, _, parent) compiler.assert(((#ast == 2) or (#ast == 3)), "expected 1 or 2 arguments", ast) - local _452_ + local _460_ do - local _451_0 = utils["sym?"](ast[2]) - if (nil ~= _451_0) then - _452_ = tostring(_451_0) + local _459_0 = utils["sym?"](ast[2]) + if (nil ~= _459_0) then + _460_ = tostring(_459_0) else - _452_ = _451_0 + _460_ = _459_0 end end - if ("nil" ~= _452_) then + if ("nil" ~= _460_) then table.insert(parent, {ast = ast, leaf = tostring(ast[2])}) end - local _456_ + local _464_ do - local _455_0 = utils["sym?"](ast[3]) - if (nil ~= _455_0) then - _456_ = tostring(_455_0) + local _463_0 = utils["sym?"](ast[3]) + if (nil ~= _463_0) then + _464_ = tostring(_463_0) else - _456_ = _455_0 + _464_ = _463_0 end end - if ("nil" ~= _456_) then + if ("nil" ~= _464_) then return tostring(ast[3]) end end local function dot(ast, scope, parent) compiler.assert((1 < #ast), "expected table argument", ast) local len = #ast - local _459_ = compiler.compile1(ast[2], scope, parent, {nval = 1}) - local lhs = _459_[1] + local _467_ = compiler.compile1(ast[2], scope, parent, {nval = 1}) + local lhs = _467_[1] if (len == 2) then return tostring(lhs) else @@ -1101,12 +1113,12 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct if (utils["string?"](index) and utils["valid-lua-identifier?"](index)) then table.insert(indices, ("." .. index)) else - local _460_ = compiler.compile1(index, scope, parent, {nval = 1}) - local index0 = _460_[1] + local _468_ = compiler.compile1(index, scope, parent, {nval = 1}) + local index0 = _468_[1] table.insert(indices, ("[" .. tostring(index0) .. "]")) end end - if (tostring(lhs):find("[{\"0-9]") or ("nil" == tostring(lhs))) then + if (not (utils["sym?"](ast[2]) or utils["list?"](ast[2])) or ("nil" == tostring(lhs))) then return ("(" .. tostring(lhs) .. ")" .. table.concat(indices)) else return (tostring(lhs) .. table.concat(indices)) @@ -1147,7 +1159,7 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end doc_special("var", {"name", "val"}, "Introduce new mutable local.") local function kv_3f(t) - local _464_ + local _472_ do local tbl_17_ = {} local i_18_ = #tbl_17_ @@ -1163,9 +1175,9 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct tbl_17_[i_18_] = val_19_ end end - _464_ = tbl_17_ + _472_ = tbl_17_ end - return _464_[1] + return _472_[1] end SPECIALS.let = function(ast, scope, parent, opts) local bindings = ast[2] @@ -1192,22 +1204,22 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end end local function disambiguate_3f(rootstr, parent) - local function _469_() - local _468_0 = get_prev_line(parent) - if (nil ~= _468_0) then - local prev_line = _468_0 + local function _477_() + local _476_0 = get_prev_line(parent) + if (nil ~= _476_0) then + local prev_line = _476_0 return prev_line:match("%)$") end end - return (rootstr:match("^{") or _469_()) + return (rootstr:match("^{") or rootstr:match("^%(") or _477_()) end SPECIALS.tset = function(ast, scope, parent) compiler.assert((3 < #ast), "expected table, key, and value arguments", ast) local root = compiler.compile1(ast[2], scope, parent, {nval = 1})[1] local keys = {} for i = 3, (#ast - 1) do - local _471_ = compiler.compile1(ast[i], scope, parent, {nval = 1}) - local key = _471_[1] + local _479_ = compiler.compile1(ast[i], scope, parent, {nval = 1}) + local key = _479_[1] table.insert(keys, tostring(key)) end local value = compiler.compile1(ast[#ast], scope, parent, {nval = 1})[1] @@ -1239,82 +1251,89 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end local function if_2a(ast, scope, parent, opts) compiler.assert((2 < #ast), "expected condition and body", ast) - local do_scope = compiler["make-scope"](scope) - local branches = {} - local wrapper, inner_tail, inner_target, target_exprs = calculate_target(scope, opts) - local body_opts = {nval = opts.nval, tail = inner_tail, target = inner_target} - local function compile_body(i) - local chunk = {} - local cscope = compiler["make-scope"](do_scope) - compiler["keep-side-effects"](compiler.compile1(ast[i], cscope, chunk, body_opts), chunk, nil, ast[i]) - return {chunk = chunk, scope = cscope} + if ((1 == (#ast % 2)) and (ast[(#ast - 1)] == true)) then + table.remove(ast, (#ast - 1)) end if (1 == (#ast % 2)) then table.insert(ast, utils.sym("nil")) end - for i = 2, (#ast - 1), 2 do - local condchunk = {} - local res = compiler.compile1(ast[i], do_scope, condchunk, {nval = 1}) - local cond = res[1] - local branch = compile_body((i + 1)) - branch.cond = cond - branch.condchunk = condchunk - branch.nested = ((i ~= 2) and (next(condchunk, nil) == nil)) - table.insert(branches, branch) - end - local else_branch = compile_body(#ast) - local s = compiler.gensym(scope) - local buffer = {} - local last_buffer = buffer - for i = 1, #branches do - local branch = branches[i] - local fstr = nil - if not branch.nested then - fstr = "if %s then" - else - fstr = "elseif %s then" + if (#ast == 2) then + return SPECIALS["do"](utils.list(utils.sym("do"), ast[2]), scope, parent, opts) + else + local do_scope = compiler["make-scope"](scope) + local branches = {} + local wrapper, inner_tail, inner_target, target_exprs = calculate_target(scope, opts) + local body_opts = {nval = opts.nval, tail = inner_tail, target = inner_target} + local function compile_body(i) + local chunk = {} + local cscope = compiler["make-scope"](do_scope) + compiler["keep-side-effects"](compiler.compile1(ast[i], cscope, chunk, body_opts), chunk, nil, ast[i]) + return {chunk = chunk, scope = cscope} end - local cond = tostring(branch.cond) - local cond_line = fstr:format(cond) - if branch.nested then - compiler.emit(last_buffer, branch.condchunk, ast) - else - for _, v in ipairs(branch.condchunk) do - compiler.emit(last_buffer, v, ast) + for i = 2, (#ast - 1), 2 do + local condchunk = {} + local res = compiler.compile1(ast[i], do_scope, condchunk, {nval = 1}) + local cond = res[1] + local branch = compile_body((i + 1)) + branch.cond = cond + branch.condchunk = condchunk + branch.nested = ((i ~= 2) and (next(condchunk, nil) == nil)) + table.insert(branches, branch) + end + local else_branch = compile_body(#ast) + local s = compiler.gensym(scope) + local buffer = {} + local last_buffer = buffer + for i = 1, #branches do + local branch = branches[i] + local fstr = nil + if not branch.nested then + fstr = "if %s then" + else + fstr = "elseif %s then" + end + local cond = tostring(branch.cond) + local cond_line = fstr:format(cond) + if branch.nested then + compiler.emit(last_buffer, branch.condchunk, ast) + else + for _, v in ipairs(branch.condchunk) do + compiler.emit(last_buffer, v, ast) + end + end + compiler.emit(last_buffer, cond_line, ast) + compiler.emit(last_buffer, branch.chunk, ast) + if (i == #branches) then + compiler.emit(last_buffer, "else", ast) + compiler.emit(last_buffer, else_branch.chunk, ast) + compiler.emit(last_buffer, "end", ast) + elseif not branches[(i + 1)].nested then + local next_buffer = {} + compiler.emit(last_buffer, "else", ast) + compiler.emit(last_buffer, next_buffer, ast) + compiler.emit(last_buffer, "end", ast) + last_buffer = next_buffer end end - compiler.emit(last_buffer, cond_line, ast) - compiler.emit(last_buffer, branch.chunk, ast) - if (i == #branches) then - compiler.emit(last_buffer, "else", ast) - compiler.emit(last_buffer, else_branch.chunk, ast) - compiler.emit(last_buffer, "end", ast) - elseif not branches[(i + 1)].nested then - local next_buffer = {} - compiler.emit(last_buffer, "else", ast) - compiler.emit(last_buffer, next_buffer, ast) - compiler.emit(last_buffer, "end", ast) - last_buffer = next_buffer + if (wrapper == "iife") then + local iifeargs = ((scope.vararg and "...") or "") + compiler.emit(parent, ("local function %s(%s)"):format(tostring(s), iifeargs), ast) + compiler.emit(parent, buffer, ast) + compiler.emit(parent, "end", ast) + return utils.expr(("%s(%s)"):format(tostring(s), iifeargs), "statement") + elseif (wrapper == "none") then + for i = 1, #buffer do + compiler.emit(parent, buffer[i], ast) + end + return {returned = true} + else + compiler.emit(parent, ("local %s"):format(inner_target), ast) + for i = 1, #buffer do + compiler.emit(parent, buffer[i], ast) + end + return target_exprs end end - if (wrapper == "iife") then - local iifeargs = ((scope.vararg and "...") or "") - compiler.emit(parent, ("local function %s(%s)"):format(tostring(s), iifeargs), ast) - compiler.emit(parent, buffer, ast) - compiler.emit(parent, "end", ast) - return utils.expr(("%s(%s)"):format(tostring(s), iifeargs), "statement") - elseif (wrapper == "none") then - for i = 1, #buffer do - compiler.emit(parent, buffer[i], ast) - end - return {returned = true} - else - compiler.emit(parent, ("local %s"):format(inner_target), ast) - for i = 1, #buffer do - compiler.emit(parent, buffer[i], ast) - end - return target_exprs - end end SPECIALS["if"] = if_2a doc_special("if", {"cond1", "body1", "...", "condN", "bodyN"}, "Conditional form.\nTakes any number of condition/body pairs and evaluates the first body where\nthe condition evaluates to truthy. Similar to cond in other lisps.") @@ -1327,15 +1346,16 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end local function compile_until(condition, scope, chunk) if condition then - local _480_ = compiler.compile1(condition, scope, chunk, {nval = 1}) - local condition_lua = _480_[1] + local _490_ = compiler.compile1(condition, scope, chunk, {nval = 1}) + local condition_lua = _490_[1] return compiler.emit(chunk, ("if %s then break end"):format(tostring(condition_lua)), utils.expr(condition, "expression")) end end SPECIALS.each = function(ast, scope, parent) compiler.assert((3 <= #ast), "expected body expression", ast[1]) - local binding = compiler.assert(utils["table?"](ast[2]), "expected binding table", ast) - local _ = compiler.assert((2 <= #binding), "expected binding and iterator", binding) + compiler.assert(utils["table?"](ast[2]), "expected binding table", ast) + compiler.assert((2 <= #ast[2]), "expected binding and iterator", ast) + local binding = setmetatable(utils.copy(ast[2]), getmetatable(ast[2])) local until_condition = remove_until_condition(binding) local iter = table.remove(binding, #binding) local destructures = {} @@ -1389,15 +1409,17 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct SPECIALS["while"] = while_2a doc_special("while", {"condition", "..."}, "The classic while loop. Evaluates body until a condition is non-truthy.", true) local function for_2a(ast, scope, parent) - local ranges = compiler.assert(utils["table?"](ast[2]), "expected binding table", ast) - local until_condition = remove_until_condition(ast[2]) - local binding_sym = table.remove(ast[2], 1) + compiler.assert(utils["table?"](ast[2]), "expected binding table", ast) + local ranges = setmetatable(utils.copy(ast[2]), getmetatable(ast[2])) + local until_condition = remove_until_condition(ranges) + local binding_sym = table.remove(ranges, 1) local sub_scope = compiler["make-scope"](scope) local range_args = {} local chunk = {} compiler.assert(utils["sym?"](binding_sym), ("unable to bind %s %s"):format(type(binding_sym), tostring(binding_sym)), ast[2]) compiler.assert((3 <= #ast), "expected body expression", ast[1]) - compiler.assert((#ranges <= 3), "unexpected arguments", ranges[4]) + compiler.assert((#ranges <= 3), "unexpected arguments", ranges) + compiler.assert((1 < #ranges), "expected range to include start and stop", ranges) utils.hook("customhook-early-for", ast, binding_sym, sub_scope) for i = 1, math.min(#ranges, 3) do range_args[i] = tostring(compiler.compile1(ranges[i], scope, parent, {nval = 1})[1]) @@ -1411,10 +1433,10 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct SPECIALS["for"] = for_2a doc_special("for", {"[index start stop step?]", "..."}, "Numeric loop construct.\nEvaluates body once for each value between start and stop (inclusive).", true) local function native_method_call(ast, _scope, _parent, target, args) - local _484_ = ast - local _ = _484_[1] - local _0 = _484_[2] - local method_string = _484_[3] + local _494_ = ast + local _ = _494_[1] + local _0 = _494_[2] + local method_string = _494_[3] local call_string = nil if ((target.type == "literal") or (target.type == "varg") or (target.type == "expression")) then call_string = "(%s):%s(%s)" @@ -1436,18 +1458,18 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end local function method_call(ast, scope, parent) compiler.assert((2 < #ast), "expected at least 2 arguments", ast) - local _486_ = compiler.compile1(ast[2], scope, parent, {nval = 1}) - local target = _486_[1] + local _496_ = compiler.compile1(ast[2], scope, parent, {nval = 1}) + local target = _496_[1] local args = {} for i = 4, #ast do local subexprs = nil - local _487_ + local _497_ if (i ~= #ast) then - _487_ = 1 + _497_ = 1 else - _487_ = nil + _497_ = nil end - subexprs = compiler.compile1(ast[i], scope, parent, {nval = _487_}) + subexprs = compiler.compile1(ast[i], scope, parent, {nval = _497_}) utils.map(subexprs, tostring, args) end if (utils["string?"](ast[3]) and utils["valid-lua-identifier?"](ast[3])) then @@ -1461,11 +1483,27 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct SPECIALS[":"] = method_call doc_special(":", {"tbl", "method-name", "..."}, "Call the named method on tbl with the provided args.\nMethod name doesn't have to be known at compile-time; if it is, use\n(tbl:method-name ...) instead.") SPECIALS.comment = function(ast, _, parent) - local els = {} - for i = 2, #ast do - table.insert(els, view(ast[i], {["one-line?"] = true})) + local c = nil + local _500_ + do + local tbl_17_ = {} + local i_18_ = #tbl_17_ + for i, elt in ipairs(ast) do + local val_19_ = nil + if (i ~= 1) then + val_19_ = view(ast[i], {["one-line?"] = true}) + else + val_19_ = nil + end + if (nil ~= val_19_) then + i_18_ = (i_18_ + 1) + tbl_17_[i_18_] = val_19_ + end + end + _500_ = tbl_17_ end - return compiler.emit(parent, ("--[[ " .. table.concat(els, " ") .. " ]]"), ast) + c = table.concat(_500_, " "):gsub("%]%]", "]\\]") + return compiler.emit(parent, ("--[[ " .. c .. " ]]"), ast) end doc_special("comment", {"..."}, "Comment which will be emitted in Lua output.", true) local function hashfn_max_used(f_scope, i, max) @@ -1485,10 +1523,10 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct compiler.assert((#ast == 2), "expected one argument", ast) local f_scope = nil do - local _492_0 = compiler["make-scope"](scope) - _492_0["vararg"] = false - _492_0["hashfn"] = true - f_scope = _492_0 + local _505_0 = compiler["make-scope"](scope) + _505_0["vararg"] = false + _505_0["hashfn"] = true + f_scope = _505_0 end local f_chunk = {} local name = compiler.gensym(scope) @@ -1498,16 +1536,20 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct for i = 1, 9 do args[i] = compiler["declare-local"](utils.sym(("$" .. i)), {}, f_scope, ast) end - local function walker(idx, node, parent_node) - if (utils["sym?"](node) and (tostring(node) == "$...")) then - parent_node[idx] = utils.varg() + local function walker(idx, node, _3fparent_node) + if utils["sym?"](node, "$...") then f_scope.vararg = true - return nil + if _3fparent_node then + _3fparent_node[idx] = utils.varg() + return nil + else + return utils.varg() + end else - return (("table" == type(node)) and (utils.sym("hashfn") ~= node[1]) and (utils["list?"](node) or utils["table?"](node))) + return ((utils["list?"](node) and (not _3fparent_node or not utils["sym?"](node[1], "hashfn"))) or utils["table?"](node)) end end - utils["walk-tree"](ast[2], walker) + utils["walk-tree"](ast, walker) compiler.compile1(ast[2], f_scope, f_chunk, {tail = true}) local max_used = hashfn_max_used(f_scope, 1, 0) if f_scope.vararg then @@ -1525,9 +1567,9 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct return utils.expr(name, "sym") end doc_special("hashfn", {"..."}, "Function literal shorthand; args are either $... OR $1, $2, etc.") - local function maybe_short_circuit_protect(ast, i, name, _496_0) - local _497_ = _496_0 - local mac = _497_["macros"] + local function maybe_short_circuit_protect(ast, i, name, _510_0) + local _511_ = _510_0 + local mac = _511_["macros"] local call = (utils["list?"](ast) and tostring(ast[1])) if ((("or" == name) or ("and" == name)) and (1 < i) and (mac[call] or ("set" == call) or ("tset" == call) or ("global" == call))) then return utils.list(utils.sym("do"), ast) @@ -1548,35 +1590,37 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct table.insert(operands, tostring(subexprs[1])) end end - local _500_0 = #operands - if (_500_0 == 0) then - local _501_ + local _514_0 = #operands + if (_514_0 == 0) then + local _515_ do compiler.assert(zero_arity, "Expected more than 0 arguments", ast) - _501_ = zero_arity + _515_ = zero_arity end - return utils.expr(_501_, "literal") - elseif (_500_0 == 1) then - if unary_prefix then + return utils.expr(_515_, "literal") + elseif (_514_0 == 1) then + if utils["varg?"](ast[2]) then + return compiler.assert(false, "tried to use vararg with operator", ast) + elseif unary_prefix then return ("(" .. unary_prefix .. padded_op .. operands[1] .. ")") else return operands[1] end else - local _ = _500_0 + local _ = _514_0 return ("(" .. table.concat(operands, padded_op) .. ")") end end local function define_arithmetic_special(name, zero_arity, unary_prefix, _3flua_name) - local _505_ + local _519_ do - local _504_0 = (_3flua_name or name) - local function _506_(...) - return arithmetic_special(_504_0, zero_arity, unary_prefix, ...) + local _518_0 = (_3flua_name or name) + local function _520_(...) + return arithmetic_special(_518_0, zero_arity, unary_prefix, ...) end - _505_ = _506_ + _519_ = _520_ end - SPECIALS[name] = _505_ + SPECIALS[name] = _519_ return doc_special(name, {"a", "b", "..."}, "Arithmetic operator; works the same as Lua but accepts more arguments.") end define_arithmetic_special("+", "0") @@ -1605,13 +1649,13 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct local prefixed_lib_name = ("bit." .. lib_name) for i = 2, len do local subexprs = nil - local _507_ + local _521_ if (i ~= len) then - _507_ = 1 + _521_ = 1 else - _507_ = nil + _521_ = nil end - subexprs = compiler.compile1(ast[i], scope, parent, {nval = _507_}) + subexprs = compiler.compile1(ast[i], scope, parent, {nval = _521_}) utils.map(subexprs, tostring, operands) end if (#operands == 1) then @@ -1630,10 +1674,10 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end end local function define_bitop_special(name, zero_arity, unary_prefix, native) - local function _513_(...) + local function _527_(...) return bitop_special(native, name, zero_arity, unary_prefix, ...) end - SPECIALS[name] = _513_ + SPECIALS[name] = _527_ return nil end define_bitop_special("lshift", nil, "1", "<<") @@ -1646,16 +1690,27 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct doc_special("band", {"x1", "x2", "..."}, "Bitwise AND of any number of arguments.\nOnly works in Lua 5.3+ or LuaJIT with the --use-bit-lib flag.") doc_special("bor", {"x1", "x2", "..."}, "Bitwise OR of any number of arguments.\nOnly works in Lua 5.3+ or LuaJIT with the --use-bit-lib flag.") doc_special("bxor", {"x1", "x2", "..."}, "Bitwise XOR of any number of arguments.\nOnly works in Lua 5.3+ or LuaJIT with the --use-bit-lib flag.") + SPECIALS.bnot = function(ast, scope, parent) + compiler.assert((#ast == 2), "expected one argument", ast) + local _528_ = compiler.compile1(ast[2], scope, parent, {nval = 1}) + local value = _528_[1] + if utils.root.options.useBitLib then + return ("bit.bnot(" .. tostring(value) .. ")") + else + return ("~(" .. tostring(value) .. ")") + end + end + doc_special("bnot", {"x"}, "Bitwise negation; only works in Lua 5.3+ or LuaJIT with the --use-bit-lib flag.") doc_special("..", {"a", "b", "..."}, "String concatenation operator; works the same as Lua but accepts more arguments.") - local function native_comparator(op, _514_0, scope, parent) - local _515_ = _514_0 - local _ = _515_[1] - local lhs_ast = _515_[2] - local rhs_ast = _515_[3] - local _516_ = compiler.compile1(lhs_ast, scope, parent, {nval = 1}) - local lhs = _516_[1] - local _517_ = compiler.compile1(rhs_ast, scope, parent, {nval = 1}) - local rhs = _517_[1] + local function native_comparator(op, _530_0, scope, parent) + local _531_ = _530_0 + local _ = _531_[1] + local lhs_ast = _531_[2] + local rhs_ast = _531_[3] + local _532_ = compiler.compile1(lhs_ast, scope, parent, {nval = 1}) + local lhs = _532_[1] + local _533_ = compiler.compile1(rhs_ast, scope, parent, {nval = 1}) + local rhs = _533_[1] return string.format("(%s %s %s)", tostring(lhs), op, tostring(rhs)) end local function idempotent_comparator(op, chain_op, ast, scope, parent) @@ -1686,7 +1741,7 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct comparisons = tbl_17_ end local chain = string.format(" %s ", (chain_op or "and")) - return table.concat(comparisons, chain) + return ("(" .. table.concat(comparisons, chain) .. ")") end local function double_eval_protected_comparator(op, chain_op, ast, scope, parent) local arglist = {} @@ -1744,8 +1799,6 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end define_unary_special("not", "not ") doc_special("not", {"x"}, "Logical operator; works the same as Lua.") - define_unary_special("bnot", "~") - doc_special("bnot", {"x"}, "Bitwise negation; only works in Lua 5.3+ or LuaJIT with the --use-bit-lib flag.") define_unary_special("length", "#") doc_special("length", {"x"}, "Returns the length of a table or string.") SPECIALS["~="] = SPECIALS["not="] @@ -1770,21 +1823,21 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end local safe_require = nil local function safe_compiler_env() - local _524_ + local _540_ do - local _523_0 = rawget(_G, "utf8") - if (nil ~= _523_0) then - _524_ = utils.copy(_523_0) + local _539_0 = rawget(_G, "utf8") + if (nil ~= _539_0) then + _540_ = utils.copy(_539_0) else - _524_ = _523_0 + _540_ = _539_0 end end - return {_VERSION = _VERSION, assert = assert, bit = rawget(_G, "bit"), error = error, getmetatable = safe_getmetatable, ipairs = ipairs, math = utils.copy(math), next = next, pairs = utils.stablepairs, pcall = pcall, print = print, rawequal = rawequal, rawget = rawget, rawlen = rawget(_G, "rawlen"), rawset = rawset, require = safe_require, select = select, setmetatable = setmetatable, string = utils.copy(string), table = utils.copy(table), tonumber = tonumber, tostring = tostring, type = type, utf8 = _524_, xpcall = xpcall} + return {_VERSION = _VERSION, assert = assert, bit = rawget(_G, "bit"), error = error, getmetatable = safe_getmetatable, ipairs = ipairs, math = utils.copy(math), next = next, pairs = utils.stablepairs, pcall = pcall, print = print, rawequal = rawequal, rawget = rawget, rawlen = rawget(_G, "rawlen"), rawset = rawset, require = safe_require, select = select, setmetatable = setmetatable, string = utils.copy(string), table = utils.copy(table), tonumber = tonumber, tostring = tostring, type = type, utf8 = _540_, xpcall = xpcall} end local function combined_mt_pairs(env) local combined = {} - local _526_ = getmetatable(env) - local __index = _526_["__index"] + local _542_ = getmetatable(env) + local __index = _542_["__index"] if ("table" == type(__index)) then for k, v in pairs(__index) do combined[k] = v @@ -1798,40 +1851,40 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct local function make_compiler_env(ast, scope, parent, _3fopts) local provided = nil do - local _528_0 = (_3fopts or utils.root.options) - if ((_G.type(_528_0) == "table") and (_528_0["compiler-env"] == "strict")) then + local _544_0 = (_3fopts or utils.root.options) + if ((_G.type(_544_0) == "table") and (_544_0["compiler-env"] == "strict")) then provided = safe_compiler_env() - elseif ((_G.type(_528_0) == "table") and (nil ~= _528_0.compilerEnv)) then - local compilerEnv = _528_0.compilerEnv + elseif ((_G.type(_544_0) == "table") and (nil ~= _544_0.compilerEnv)) then + local compilerEnv = _544_0.compilerEnv provided = compilerEnv - elseif ((_G.type(_528_0) == "table") and (nil ~= _528_0["compiler-env"])) then - local compiler_env = _528_0["compiler-env"] + elseif ((_G.type(_544_0) == "table") and (nil ~= _544_0["compiler-env"])) then + local compiler_env = _544_0["compiler-env"] provided = compiler_env else - local _ = _528_0 + local _ = _544_0 provided = safe_compiler_env(false) end end local env = nil - local function _530_() + local function _546_() return compiler.scopes.macro end - local function _531_(symbol) + local function _547_(symbol) compiler.assert(compiler.scopes.macro, "must call from macro", ast) return compiler.scopes.macro.manglings[tostring(symbol)] end - local function _532_(base) + local function _548_(base) return utils.sym(compiler.gensym((compiler.scopes.macro or scope), base)) end - local function _533_(form) + local function _549_(form) compiler.assert(compiler.scopes.macro, "must call from macro", ast) return compiler.macroexpand(form, compiler.scopes.macro) end - env = {["assert-compile"] = compiler.assert, ["ast-source"] = utils["ast-source"], ["comment?"] = utils["comment?"], ["get-scope"] = _530_, ["in-scope?"] = _531_, ["list?"] = utils["list?"], ["macro-loaded"] = macro_loaded, ["multi-sym?"] = utils["multi-sym?"], ["sequence?"] = utils["sequence?"], ["sym?"] = utils["sym?"], ["table?"] = utils["table?"], ["varg?"] = utils["varg?"], _AST = ast, _CHUNK = parent, _IS_COMPILER = true, _SCOPE = scope, _SPECIALS = compiler.scopes.global.specials, _VARARG = utils.varg(), comment = utils.comment, gensym = _532_, list = utils.list, macroexpand = _533_, metadata = compiler.metadata, sequence = utils.sequence, sym = utils.sym, unpack = unpack, version = utils.version, view = view} + env = {["assert-compile"] = compiler.assert, ["ast-source"] = utils["ast-source"], ["comment?"] = utils["comment?"], ["get-scope"] = _546_, ["in-scope?"] = _547_, ["list?"] = utils["list?"], ["macro-loaded"] = macro_loaded, ["multi-sym?"] = utils["multi-sym?"], ["sequence?"] = utils["sequence?"], ["sym?"] = utils["sym?"], ["table?"] = utils["table?"], ["varg?"] = utils["varg?"], _AST = ast, _CHUNK = parent, _IS_COMPILER = true, _SCOPE = scope, _SPECIALS = compiler.scopes.global.specials, _VARARG = utils.varg(), comment = utils.comment, gensym = _548_, list = utils.list, macroexpand = _549_, metadata = compiler.metadata, sequence = utils.sequence, sym = utils.sym, unpack = unpack, version = utils.version, view = view} env._G = env return setmetatable(env, {__index = provided, __newindex = provided, __pairs = combined_mt_pairs}) end - local function _534_(...) + local function _550_(...) local tbl_17_ = {} local i_18_ = #tbl_17_ for c in string.gmatch((package.config or ""), "([^\n]+)") do @@ -1843,11 +1896,11 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end return tbl_17_ end - local _536_ = _534_(...) - local dirsep = _536_[1] - local pathsep = _536_[2] - local pathmark = _536_[3] - local pkg_config = {dirsep = (dirsep or "/"), pathmark = (pathmark or ";"), pathsep = (pathsep or "?")} + local _552_ = _550_(...) + local dirsep = _552_[1] + local pathsep = _552_[2] + local pathmark = _552_[3] + local pkg_config = {dirsep = (dirsep or "/"), pathmark = (pathmark or "?"), pathsep = (pathsep or ";")} local function escapepat(str) return string.gsub(str, "[^%w]", "%%%1") end @@ -1859,36 +1912,36 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct local function try_path(path) local filename = path:gsub(escapepat(pkg_config.pathmark), no_dot_module) local filename2 = path:gsub(escapepat(pkg_config.pathmark), modulename) - local _537_0 = (io.open(filename) or io.open(filename2)) - if (nil ~= _537_0) then - local file = _537_0 + local _553_0 = (io.open(filename) or io.open(filename2)) + if (nil ~= _553_0) then + local file = _553_0 file:close() return filename else - local _ = _537_0 + local _ = _553_0 return nil, ("no file '" .. filename .. "'") end end local function find_in_path(start, _3ftried_paths) - local _539_0 = fullpath:match(pattern, start) - if (nil ~= _539_0) then - local path = _539_0 - local _540_0, _541_0 = try_path(path) - if (nil ~= _540_0) then - local filename = _540_0 + local _555_0 = fullpath:match(pattern, start) + if (nil ~= _555_0) then + local path = _555_0 + local _556_0, _557_0 = try_path(path) + if (nil ~= _556_0) then + local filename = _556_0 return filename - elseif ((_540_0 == nil) and (nil ~= _541_0)) then - local error = _541_0 - local function _543_() - local _542_0 = (_3ftried_paths or {}) - table.insert(_542_0, error) - return _542_0 + elseif ((_556_0 == nil) and (nil ~= _557_0)) then + local error = _557_0 + local function _559_() + local _558_0 = (_3ftried_paths or {}) + table.insert(_558_0, error) + return _558_0 end - return find_in_path((start + #path + 1), _543_()) + return find_in_path((start + #path + 1), _559_()) end else - local _ = _539_0 - local function _545_() + local _ = _555_0 + local function _561_() local tried_paths = table.concat((_3ftried_paths or {}), "\n\9") if (_VERSION < "Lua 5.4") then return ("\n\9" .. tried_paths) @@ -1896,31 +1949,31 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct return tried_paths end end - return nil, _545_() + return nil, _561_() end end return find_in_path(1) end local function make_searcher(_3foptions) - local function _548_(module_name) + local function _564_(module_name) local opts = utils.copy(utils.root.options) for k, v in pairs((_3foptions or {})) do opts[k] = v end opts["module-name"] = module_name - local _549_0, _550_0 = search_module(module_name) - if (nil ~= _549_0) then - local filename = _549_0 - local function _551_(...) + local _565_0, _566_0 = search_module(module_name) + if (nil ~= _565_0) then + local filename = _565_0 + local function _567_(...) return utils["fennel-module"].dofile(filename, opts, ...) end - return _551_, filename - elseif ((_549_0 == nil) and (nil ~= _550_0)) then - local error = _550_0 + return _567_, filename + elseif ((_565_0 == nil) and (nil ~= _566_0)) then + local error = _566_0 return error end end - return _548_ + return _564_ end local function dofile_with_searcher(fennel_macro_searcher, filename, opts, ...) local searchers = (package.loaders or package.searchers or {}) @@ -1932,35 +1985,35 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct local function fennel_macro_searcher(module_name) local opts = nil do - local _553_0 = utils.copy(utils.root.options) - _553_0["module-name"] = module_name - _553_0["env"] = "_COMPILER" - _553_0["requireAsInclude"] = false - _553_0["allowedGlobals"] = nil - opts = _553_0 + local _569_0 = utils.copy(utils.root.options) + _569_0["module-name"] = module_name + _569_0["env"] = "_COMPILER" + _569_0["requireAsInclude"] = false + _569_0["allowedGlobals"] = nil + opts = _569_0 end - local _554_0 = search_module(module_name, utils["fennel-module"]["macro-path"]) - if (nil ~= _554_0) then - local filename = _554_0 - local _555_ + local _570_0 = search_module(module_name, utils["fennel-module"]["macro-path"]) + if (nil ~= _570_0) then + local filename = _570_0 + local _571_ if (opts["compiler-env"] == _G) then - local function _556_(...) + local function _572_(...) return dofile_with_searcher(fennel_macro_searcher, filename, opts, ...) end - _555_ = _556_ + _571_ = _572_ else - local function _557_(...) + local function _573_(...) return utils["fennel-module"].dofile(filename, opts, ...) end - _555_ = _557_ + _571_ = _573_ end - return _555_, filename + return _571_, filename end end local function lua_macro_searcher(module_name) - local _560_0 = search_module(module_name, package.path) - if (nil ~= _560_0) then - local filename = _560_0 + local _576_0 = search_module(module_name, package.path) + if (nil ~= _576_0) then + local filename = _576_0 local code = nil do local f = io.open(filename) @@ -1972,10 +2025,10 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct return error(..., 0) end end - local function _562_() + local function _578_() return assert(f:read("*a")) end - code = close_handlers_10_(_G.xpcall(_562_, (package.loaded.fennel or debug).traceback)) + code = close_handlers_10_(_G.xpcall(_578_, (package.loaded.fennel or debug).traceback)) end local chunk = load_code(code, make_compiler_env(), filename) return chunk, filename @@ -1983,16 +2036,16 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end local macro_searchers = {fennel_macro_searcher, lua_macro_searcher} local function search_macro_module(modname, n) - local _564_0 = macro_searchers[n] - if (nil ~= _564_0) then - local f = _564_0 - local _565_0, _566_0 = f(modname) - if ((nil ~= _565_0) and true) then - local loader = _565_0 - local _3ffilename = _566_0 + local _580_0 = macro_searchers[n] + if (nil ~= _580_0) then + local f = _580_0 + local _581_0, _582_0 = f(modname) + if ((nil ~= _581_0) and true) then + local loader = _581_0 + local _3ffilename = _582_0 return loader, _3ffilename else - local _ = _565_0 + local _ = _581_0 return search_macro_module(modname, (n + 1)) end end @@ -2002,16 +2055,16 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct return {metadata = compiler.metadata, view = view} end end - local function _570_(modname) - local function _571_() + local function _586_(modname) + local function _587_() local loader, filename = search_macro_module(modname, 1) compiler.assert(loader, (modname .. " module not found.")) macro_loaded[modname] = loader(modname, filename) return macro_loaded[modname] end - return (macro_loaded[modname] or sandbox_fennel_module(modname) or _571_()) + return (macro_loaded[modname] or sandbox_fennel_module(modname) or _587_()) end - safe_require = _570_ + safe_require = _586_ local function add_macros(macros_2a, ast, scope) compiler.assert(utils["table?"](macros_2a), "expected macros to be table", ast) for k, v in pairs(macros_2a) do @@ -2021,10 +2074,10 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end return nil end - local function resolve_module_name(_572_0, _scope, _parent, opts) - local _573_ = _572_0 - local second = _573_[2] - local filename = _573_["filename"] + local function resolve_module_name(_588_0, _scope, _parent, opts) + local _589_ = _588_0 + local second = _589_[2] + local filename = _589_["filename"] local filename0 = (filename or (utils["table?"](second) and second.filename)) local module_name = utils.root.options["module-name"] local modexpr = compiler.compile(second, opts) @@ -2081,10 +2134,10 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct return error(..., 0) end end - local function _579_() + local function _595_() return assert(f:read("*all")):gsub("[\13\n]*$", "") end - src = close_handlers_10_(_G.xpcall(_579_, (package.loaded.fennel or debug).traceback)) + src = close_handlers_10_(_G.xpcall(_595_, (package.loaded.fennel or debug).traceback)) end local ret = utils.expr(("require(\"" .. mod .. "\")"), "statement") local target = ("package.preload[%q]"):format(mod) @@ -2114,12 +2167,12 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct compiler.assert((#ast == 2), "expected one argument", ast) local modexpr = nil do - local _582_0, _583_0 = pcall(resolve_module_name, ast, scope, parent, opts) - if ((_582_0 == true) and (nil ~= _583_0)) then - local modname = _583_0 + local _598_0, _599_0 = pcall(resolve_module_name, ast, scope, parent, opts) + if ((_598_0 == true) and (nil ~= _599_0)) then + local modname = _599_0 modexpr = utils.expr(string.format("%q", modname), "literal") else - local _ = _582_0 + local _ = _598_0 modexpr = compiler.compile1(ast[2], scope, parent, {nval = 1})[1] end end @@ -2136,13 +2189,13 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct utils.root.options["module-name"] = mod _ = nil local res = nil - local function _587_() - local _586_0 = search_module(mod) - if (nil ~= _586_0) then - local fennel_path = _586_0 + local function _603_() + local _602_0 = search_module(mod) + if (nil ~= _602_0) then + local fennel_path = _602_0 return include_path(ast, opts, fennel_path, mod, true) else - local _0 = _586_0 + local _0 = _602_0 local lua_path = search_module(mod, package.path) if lua_path then return include_path(ast, opts, lua_path, mod, false) @@ -2153,7 +2206,7 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct end end end - res = ((utils["member?"](mod, (utils.root.options.skipInclude or {})) and opts.fallback(modexpr, true)) or include_circular_fallback(mod, modexpr, opts.fallback, ast) or utils.root.scope.includes[mod] or _587_()) + res = ((utils["member?"](mod, (utils.root.options.skipInclude or {})) and opts.fallback(modexpr, true)) or include_circular_fallback(mod, modexpr, opts.fallback, ast) or utils.root.scope.includes[mod] or _603_()) utils.root.options["module-name"] = oldmod return res end @@ -2164,11 +2217,13 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct local opts = utils.copy(utils.root.options) opts.scope = compiler["make-scope"](compiler.scopes.compiler) opts.allowedGlobals = current_global_names(env) - return assert(load_code(compiler.compile(ast, opts), wrap_env(env)), opts["module-name"], ast.filename)() + return assert(load_code(compiler.compile(ast, opts), wrap_env(env)))(opts["module-name"], ast.filename) end SPECIALS.macros = function(ast, scope, parent) - compiler.assert(((#ast == 2) and utils["table?"](ast[2])), "Expected one table argument", ast) - return add_macros(eval_compiler_2a(ast[2], scope, parent), ast, scope, parent) + compiler.assert((#ast == 2), "Expected one table argument", ast) + local macro_tbl = eval_compiler_2a(ast[2], scope, parent) + compiler.assert(utils["table?"](macro_tbl), "Expected one table argument", ast) + return add_macros(macro_tbl, ast, scope, parent) end doc_special("macros", {"{:macro-name-1 (fn [...] ...) ... :macro-name-N macro-body-N}"}, "Define all functions in the given table as macros local to the current scope.") SPECIALS["eval-compiler"] = function(ast, scope, parent) @@ -2179,6 +2234,10 @@ package.preload["fennel.specials"] = package.preload["fennel.specials"] or funct return val end doc_special("eval-compiler", {"..."}, "Evaluate the body at compile-time. Use the macro system instead if possible.", true) + SPECIALS.unquote = function(ast) + return compiler.assert(false, "tried to use unquote outside quote", ast) + end + doc_special("unquote", {"..."}, "Evaluate the argument even if it's in a quoted form.") return {["current-global-names"] = current_global_names, ["load-code"] = load_code, ["macro-loaded"] = macro_loaded, ["macro-searchers"] = macro_searchers, ["make-compiler-env"] = make_compiler_env, ["make-searcher"] = make_searcher, ["search-module"] = search_module, ["wrap-env"] = wrap_env, doc = doc_2a} end package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or function(...) @@ -2189,13 +2248,13 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct local scopes = {} local function make_scope(_3fparent) local parent = (_3fparent or scopes.global) - local _252_ + local _261_ if parent then - _252_ = ((parent.depth or 0) + 1) + _261_ = ((parent.depth or 0) + 1) else - _252_ = 0 + _261_ = 0 end - return {autogensyms = setmetatable({}, {__index = (parent and parent.autogensyms)}), depth = _252_, gensyms = setmetatable({}, {__index = (parent and parent.gensyms)}), hashfn = (parent and parent.hashfn), includes = setmetatable({}, {__index = (parent and parent.includes)}), macros = setmetatable({}, {__index = (parent and parent.macros)}), manglings = setmetatable({}, {__index = (parent and parent.manglings)}), parent = parent, refedglobals = {}, specials = setmetatable({}, {__index = (parent and parent.specials)}), symmeta = setmetatable({}, {__index = (parent and parent.symmeta)}), unmanglings = setmetatable({}, {__index = (parent and parent.unmanglings)}), vararg = (parent and parent.vararg)} + return {["gensym-base"] = setmetatable({}, {__index = (parent and parent["gensym-base"])}), autogensyms = setmetatable({}, {__index = (parent and parent.autogensyms)}), depth = _261_, gensyms = setmetatable({}, {__index = (parent and parent.gensyms)}), hashfn = (parent and parent.hashfn), includes = setmetatable({}, {__index = (parent and parent.includes)}), macros = setmetatable({}, {__index = (parent and parent.macros)}), manglings = setmetatable({}, {__index = (parent and parent.manglings)}), parent = parent, refedglobals = {}, specials = setmetatable({}, {__index = (parent and parent.specials)}), symmeta = setmetatable({}, {__index = (parent and parent.symmeta)}), unmanglings = setmetatable({}, {__index = (parent and parent.unmanglings)}), vararg = (parent and parent.vararg)} end local function assert_msg(ast, msg) local ast_tbl = nil @@ -2213,10 +2272,10 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct end local function assert_compile(condition, msg, ast, _3ffallback_ast) if not condition then - local _255_ = (utils.root.options or {}) - local error_pinpoint = _255_["error-pinpoint"] - local source = _255_["source"] - local unfriendly = _255_["unfriendly"] + local _264_ = (utils.root.options or {}) + local error_pinpoint = _264_["error-pinpoint"] + local source = _264_["source"] + local unfriendly = _264_["unfriendly"] local ast0 = nil if next(utils["ast-source"](ast)) then ast0 = ast @@ -2225,7 +2284,7 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct end if (nil == utils.hook("assert-compile", condition, msg, ast0, utils.root.reset)) then utils.root.reset() - if (unfriendly or not friend or not _G.io or not _G.io.read) then + if unfriendly then error(assert_msg(ast0, msg), 0) else friend["assert-compile"](condition, msg, ast0, source, {["error-pinpoint"] = error_pinpoint}) @@ -2240,33 +2299,33 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct scopes.macro = scopes.global local serialize_subst = {["\11"] = "\\v", ["\12"] = "\\f", ["\7"] = "\\a", ["\8"] = "\\b", ["\9"] = "\\t", ["\n"] = "n"} local function serialize_string(str) - local function _260_(_241) + local function _269_(_241) return ("\\" .. _241:byte()) end - return string.gsub(string.gsub(string.format("%q", str), ".", serialize_subst), "[\128-\255]", _260_) + return string.gsub(string.gsub(string.format("%q", str), ".", serialize_subst), "[\128-\255]", _269_) end local function global_mangling(str) if utils["valid-lua-identifier?"](str) then return str else - local function _261_(_241) + local function _270_(_241) return string.format("_%02x", _241:byte()) end - return ("__fnl_global__" .. str:gsub("[^%w]", _261_)) + return ("__fnl_global__" .. str:gsub("[^%w]", _270_)) end end local function global_unmangling(identifier) - local _263_0 = string.match(identifier, "^__fnl_global__(.*)$") - if (nil ~= _263_0) then - local rest = _263_0 - local _264_0 = nil - local function _265_(_241) + local _272_0 = string.match(identifier, "^__fnl_global__(.*)$") + if (nil ~= _272_0) then + local rest = _272_0 + local _273_0 = nil + local function _274_(_241) return string.char(tonumber(_241:sub(2), 16)) end - _264_0 = string.gsub(rest, "_[%da-f][%da-f]", _265_) - return _264_0 + _273_0 = string.gsub(rest, "_[%da-f][%da-f]", _274_) + return _273_0 else - local _ = _263_0 + local _ = _272_0 return identifier end end @@ -2275,7 +2334,7 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct return (not allowed_globals or utils["member?"](name, allowed_globals)) end local function unique_mangling(original, mangling, scope, append) - if (scope.unmanglings[mangling] and not scope.gensyms[mangling]) then + if scope.unmanglings[mangling] then return unique_mangling(original, (original .. append), scope, (append + 1)) else return mangling @@ -2290,12 +2349,12 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct raw = str end local mangling = nil - local function _269_(_241) + local function _278_(_241) return string.format("_%02x", _241:byte()) end - mangling = string.gsub(string.gsub(raw, "-", "_"), "[^%w_]", _269_) + mangling = string.gsub(string.gsub(raw, "-", "_"), "[^%w_]", _278_) local unique = unique_mangling(mangling, mangling, scope, 0) - scope.unmanglings[unique] = str + scope.unmanglings[unique] = (scope["gensym-base"][str] or str) do local manglings = (_3ftemp_manglings or scope.manglings) manglings[str] = unique @@ -2333,7 +2392,9 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct while scope.unmanglings[mangling] do mangling = ((_3fbase or "") .. next_append() .. (_3fsuffix or "")) end - scope.unmanglings[mangling] = (_3fbase or true) + if (_3fbase and (0 < #_3fbase)) then + scope["gensym-base"][mangling] = _3fbase + end scope.gensyms[mangling] = true return mangling end @@ -2346,29 +2407,29 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct return table.concat(parts, ".") end local function autogensym(base, scope) - local _272_0 = utils["multi-sym?"](base) - if (nil ~= _272_0) then - local parts = _272_0 + local _282_0 = utils["multi-sym?"](base) + if (nil ~= _282_0) then + local parts = _282_0 return combine_auto_gensym(parts, autogensym(parts[1], scope)) else - local _ = _272_0 - local function _273_() + local _ = _282_0 + local function _283_() local mangling = gensym(scope, base:sub(1, ( - 2)), "auto") scope.autogensyms[base] = mangling return mangling end - return (scope.autogensyms[base] or _273_()) + return (scope.autogensyms[base] or _283_()) end end local function check_binding_valid(symbol, scope, ast, _3fopts) local name = tostring(symbol) local macro_3f = nil do - local _275_0 = _3fopts - if (nil ~= _275_0) then - _275_0 = _275_0["macro?"] + local _285_0 = _3fopts + if (nil ~= _285_0) then + _285_0 = _285_0["macro?"] end - macro_3f = _275_0 + macro_3f = _285_0 end assert_compile(not name:find("&"), "invalid character: &", symbol) assert_compile(not name:find("^%."), "invalid character: .", symbol) @@ -2466,22 +2527,22 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct end local function flatten_chunk(file_sourcemap, chunk, tab, depth) if chunk.leaf then - local _287_ = utils["ast-source"](chunk.ast) - local filename = _287_["filename"] - local line = _287_["line"] + local _297_ = utils["ast-source"](chunk.ast) + local filename = _297_["filename"] + local line = _297_["line"] table.insert(file_sourcemap, {filename, line}) return chunk.leaf else local tab0 = nil do - local _288_0 = tab - if (_288_0 == true) then + local _298_0 = tab + if (_298_0 == true) then tab0 = " " - elseif (_288_0 == false) then + elseif (_298_0 == false) then tab0 = "" - elseif (_288_0 == tab) then + elseif (_298_0 == tab) then tab0 = tab - elseif (_288_0 == nil) then + elseif (_298_0 == nil) then tab0 = "" else tab0 = nil @@ -2527,17 +2588,21 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct end end local function make_metadata() - local function _296_(self, tgt, key) + local function _306_(self, tgt, _3fkey) if self[tgt] then - return self[tgt][key] + if (nil ~= _3fkey) then + return self[tgt][_3fkey] + else + return self[tgt] + end end end - local function _298_(self, tgt, key, value) + local function _309_(self, tgt, key, value) self[tgt] = (self[tgt] or {}) self[tgt][key] = value return tgt end - local function _299_(self, tgt, ...) + local function _310_(self, tgt, ...) local kv_len = select("#", ...) local kvs = {...} if ((kv_len % 2) ~= 0) then @@ -2549,7 +2614,7 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct end return tgt end - return setmetatable({}, {__index = {get = _296_, set = _298_, setall = _299_}, __mode = "k"}) + return setmetatable({}, {__index = {get = _306_, set = _309_, setall = _310_}, __mode = "k"}) end local function exprs1(exprs) return table.concat(utils.map(exprs, tostring), ", ") @@ -2595,14 +2660,14 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct end if opts.target then local result = exprs1(exprs) - local function _307_() + local function _318_() if (result == "") then return "nil" else return result end end - emit(parent, string.format("%s = %s", opts.target, _307_()), ast) + emit(parent, string.format("%s = %s", opts.target, _318_()), ast) end if (opts.tail or opts.target) then return {returned = true} @@ -2614,16 +2679,16 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct local function find_macro(ast, scope) local macro_2a = nil do - local _310_0 = utils["sym?"](ast[1]) - if (_310_0 ~= nil) then - local _311_0 = tostring(_310_0) - if (_311_0 ~= nil) then - macro_2a = scope.macros[_311_0] + local _321_0 = utils["sym?"](ast[1]) + if (_321_0 ~= nil) then + local _322_0 = tostring(_321_0) + if (_322_0 ~= nil) then + macro_2a = scope.macros[_322_0] else - macro_2a = _311_0 + macro_2a = _322_0 end else - macro_2a = _310_0 + macro_2a = _321_0 end end local multi_sym_parts = utils["multi-sym?"](ast[1]) @@ -2635,12 +2700,12 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct return macro_2a end end - local function propagate_trace_info(_315_0, _index, node) - local _316_ = _315_0 - local byteend = _316_["byteend"] - local bytestart = _316_["bytestart"] - local filename = _316_["filename"] - local line = _316_["line"] + local function propagate_trace_info(_326_0, _index, node) + local _327_ = _326_0 + local byteend = _327_["byteend"] + local bytestart = _327_["bytestart"] + local filename = _327_["filename"] + local line = _327_["line"] do local src = utils["ast-source"](node) if (("table" == type(node)) and (filename ~= src.filename)) then @@ -2653,8 +2718,8 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct local function quote_literal_nils(index, node, parent) if (parent and utils["list?"](parent)) then for i = 1, utils.maxn(parent) do - local _318_0 = parent[i] - if (_318_0 == nil) then + local _329_0 = parent[i] + if (_329_0 == nil) then parent[i] = utils.sym("nil") end end @@ -2662,10 +2727,10 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct return index, node, parent end local function comp(f, g) - local function _321_(...) + local function _332_(...) return f(g(...)) end - return _321_ + return _332_ end local function built_in_3f(m) local found_3f = false @@ -2676,36 +2741,36 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct return found_3f end local function macroexpand_2a(ast, scope, _3fonce) - local _322_0 = nil + local _333_0 = nil if utils["list?"](ast) then - _322_0 = find_macro(ast, scope) + _333_0 = find_macro(ast, scope) else - _322_0 = nil + _333_0 = nil end - if (_322_0 == false) then + if (_333_0 == false) then return ast - elseif (nil ~= _322_0) then - local macro_2a = _322_0 + elseif (nil ~= _333_0) then + local macro_2a = _333_0 local old_scope = scopes.macro local _ = nil scopes.macro = scope _ = nil local ok, transformed = nil, nil - local function _324_() + local function _335_() return macro_2a(unpack(ast, 2)) end - local function _325_() + local function _336_() if built_in_3f(macro_2a) then return tostring else return debug.traceback end end - ok, transformed = xpcall(_324_, _325_()) - local function _326_(...) + ok, transformed = xpcall(_335_, _336_()) + local function _337_(...) return propagate_trace_info(ast, ...) end - utils["walk-tree"](transformed, comp(_326_, quote_literal_nils)) + utils["walk-tree"](transformed, comp(_337_, quote_literal_nils)) scopes.macro = old_scope assert_compile(ok, transformed, ast) if (_3fonce or not transformed) then @@ -2714,7 +2779,7 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct return macroexpand_2a(transformed, scope) end else - local _ = _322_0 + local _ = _333_0 return ast end end @@ -2746,13 +2811,13 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct assert_compile((utils["sym?"](ast[1]) or utils["list?"](ast[1]) or ("string" == type(ast[1]))), ("cannot call literal value " .. tostring(ast[1])), ast) for i = 2, len do local subexprs = nil - local _332_ + local _343_ if (i ~= len) then - _332_ = 1 + _343_ = 1 else - _332_ = nil + _343_ = nil end - subexprs = compile1(ast[i], scope, parent, {nval = _332_}) + subexprs = compile1(ast[i], scope, parent, {nval = _343_}) table.insert(fargs, subexprs[1]) if (i == len) then for j = 2, #subexprs do @@ -2790,13 +2855,13 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct end end local function compile_varg(ast, scope, parent, opts) - local _337_ + local _348_ if scope.hashfn then - _337_ = "use $... in hashfn" + _348_ = "use $... in hashfn" else - _337_ = "unexpected vararg" + _348_ = "unexpected vararg" end - assert_compile(scope.vararg, _337_, ast) + assert_compile(scope.vararg, _348_, ast) return handle_compile_opts({utils.expr("...", "varg")}, parent, opts, ast) end local function compile_sym(ast, scope, parent, opts) @@ -2811,20 +2876,20 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct return handle_compile_opts({e}, parent, opts, ast) end local function serialize_number(n) - local _340_0 = string.gsub(tostring(n), ",", ".") - return _340_0 + local _351_0 = string.gsub(tostring(n), ",", ".") + return _351_0 end local function compile_scalar(ast, _scope, parent, opts) local serialize = nil do - local _341_0 = type(ast) - if (_341_0 == "nil") then + local _352_0 = type(ast) + if (_352_0 == "nil") then serialize = tostring - elseif (_341_0 == "boolean") then + elseif (_352_0 == "boolean") then serialize = tostring - elseif (_341_0 == "string") then + elseif (_352_0 == "string") then serialize = serialize_string - elseif (_341_0 == "number") then + elseif (_352_0 == "number") then serialize = serialize_number else serialize = nil @@ -2837,8 +2902,8 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct if ((type(k) == "string") and utils["valid-lua-identifier?"](k)) then return k else - local _343_ = compile1(k, scope, parent, {nval = 1}) - local compiled = _343_[1] + local _354_ = compile1(k, scope, parent, {nval = 1}) + local compiled = _354_[1] return ("[" .. tostring(compiled) .. "]") end end @@ -2867,8 +2932,8 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct for k, v in utils.stablepairs(ast) do local val_19_ = nil if not keys[k] then - local _346_ = compile1(ast[k], scope, parent, {nval = 1}) - local v0 = _346_[1] + local _357_ = compile1(ast[k], scope, parent, {nval = 1}) + local v0 = _357_[1] val_19_ = string.format("%s = %s", escape_key(k), tostring(v0)) else val_19_ = nil @@ -2900,12 +2965,12 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct end local function destructure(to, from, ast, scope, parent, opts) local opts0 = (opts or {}) - local _350_ = opts0 - local declaration = _350_["declaration"] - local forceglobal = _350_["forceglobal"] - local forceset = _350_["forceset"] - local isvar = _350_["isvar"] - local symtype = _350_["symtype"] + local _361_ = opts0 + local declaration = _361_["declaration"] + local forceglobal = _361_["forceglobal"] + local forceset = _361_["forceset"] + local isvar = _361_["isvar"] + local symtype = _361_["symtype"] local symtype0 = ("_" .. (symtype or "dst")) local setter = nil if declaration then @@ -2921,13 +2986,15 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct return declare_local(symbol, nil, scope, symbol, new_manglings) else local parts = (utils["multi-sym?"](raw) or {raw}) - local meta = scope.symmeta[parts[1]] + local _363_ = parts + local first = _363_[1] + local meta = scope.symmeta[first] assert_compile(not raw:find(":"), "cannot set method sym", symbol) if ((#parts == 1) and not forceset) then assert_compile(not (forceglobal and meta), string.format("global %s conflicts with local", tostring(symbol)), symbol) assert_compile(not (meta and not meta.var), ("expected var " .. raw), symbol) end - assert_compile((meta or not opts0.noundef or global_allowed_3f(parts[1])), ("expected local " .. parts[1]), symbol) + assert_compile((meta or not opts0.noundef or (scope.hashfn and ("$" == first)) or global_allowed_3f(first)), ("expected local " .. first), symbol) if forceglobal then assert_compile(not scope.symmeta[scope.unmanglings[raw]], ("global " .. raw .. " conflicts with local"), symbol) scope.manglings[raw] = global_mangling(raw) @@ -2941,14 +3008,14 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct end local function compile_top_target(lvalues) local inits = nil - local function _356_(_241) + local function _368_(_241) if scope.manglings[_241] then return _241 else return "nil" end end - inits = utils.map(lvalues, _356_) + inits = utils.map(lvalues, _368_) local init = table.concat(inits, ", ") local lvalue = table.concat(lvalues, ", ") local plast = parent[#parent] @@ -2986,7 +3053,7 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct local unpack_fn = "function (t, k, e)\n local mt = getmetatable(t)\n if 'table' == type(mt) and mt.__fennelrest then\n return mt.__fennelrest(t, k)\n elseif e then\n local rest = {}\n for k, v in pairs(t) do\n if not e[k] then rest[k] = v end\n end\n return rest\n else\n return {(table.unpack or unpack)(t, k)}\n end\n end" local function destructure_kv_rest(s, v, left, excluded_keys, destructure1) local exclude_str = nil - local _363_ + local _375_ do local tbl_17_ = {} local i_18_ = #tbl_17_ @@ -2997,9 +3064,9 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct tbl_17_[i_18_] = val_19_ end end - _363_ = tbl_17_ + _375_ = tbl_17_ end - exclude_str = table.concat(_363_, ", ") + exclude_str = table.concat(_375_, ", ") local subexpr = utils.expr(string.format(string.gsub(("(" .. unpack_fn .. ")(%s, %s, {%s})"), "\n%s*", " "), s, tostring(v), exclude_str), "expression") return destructure1(v, {subexpr}, left) end @@ -3014,16 +3081,16 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct local s = gensym(scope, symtype0) local right = nil do - local _365_0 = nil + local _377_0 = nil if top_3f then - _365_0 = exprs1(compile1(from, scope, parent)) + _377_0 = exprs1(compile1(from, scope, parent)) else - _365_0 = exprs1(rightexprs) + _377_0 = exprs1(rightexprs) end - if (_365_0 == "") then + if (_377_0 == "") then right = "nil" - elseif (nil ~= _365_0) then - local right0 = _365_0 + elseif (nil ~= _377_0) then + local right0 = _377_0 right = right0 else right = nil @@ -3114,61 +3181,55 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct end return scopes.global.specials.include(ast, scope, parent, opts) end - local function compile_stream(strm, options) + local function opts_for_compile(options) local opts = utils.copy(options) - local old_globals = allowed_globals - local scope = (opts.scope or make_scope(scopes.global)) - local vals = {} - local chunk = {} - local _378_ = utils.root - _378_["set-reset"](_378_) + opts.indent = (opts.indent or " ") allowed_globals = opts.allowedGlobals - if (opts.indent == nil) then - opts.indent = " " - end + return opts + end + local function compile_asts(asts, options) + local old_globals = allowed_globals + local opts = opts_for_compile(options) + local scope = (opts.scope or make_scope(scopes.global)) + local chunk = {} if opts.requireAsInclude then scope.specials.require = require_include end + local _391_ = utils.root + _391_["set-reset"](_391_) utils.root.chunk, utils.root.scope, utils.root.options = chunk, scope, opts - for _, val in parser.parser(strm, opts.filename, opts) do - table.insert(vals, val) - end - for i = 1, #vals do - local exprs = compile1(vals[i], scope, chunk, {nval = (((i < #vals) and 0) or nil), tail = (i == #vals)}) - keep_side_effects(exprs, chunk, nil, vals[i]) - if (i == #vals) then - utils.hook("chunk", vals[i], scope) + for i = 1, #asts do + local exprs = compile1(asts[i], scope, chunk, {nval = (((i < #asts) and 0) or nil), tail = (i == #asts)}) + keep_side_effects(exprs, chunk, nil, asts[i]) + if (i == #asts) then + utils.hook("chunk", asts[i], scope) end end allowed_globals = old_globals utils.root.reset() return flatten(chunk, opts) end - local function compile_string(str, _3fopts) - local opts = (_3fopts or {}) - return compile_stream(parser["string-stream"](str, opts), opts) + local function compile_stream(stream, opts) + local asts = nil + do + local tbl_17_ = {} + local i_18_ = #tbl_17_ + for _, ast in parser.parser(stream, opts.filename, opts) do + local val_19_ = ast + if (nil ~= val_19_) then + i_18_ = (i_18_ + 1) + tbl_17_[i_18_] = val_19_ + end + end + asts = tbl_17_ + end + return compile_asts(asts, opts) end - local function compile(ast, opts) - local opts0 = utils.copy(opts) - local old_globals = allowed_globals - local chunk = {} - local scope = (opts0.scope or make_scope(scopes.global)) - local _382_ = utils.root - _382_["set-reset"](_382_) - allowed_globals = opts0.allowedGlobals - if (opts0.indent == nil) then - opts0.indent = " " - end - if opts0.requireAsInclude then - scope.specials.require = require_include - end - utils.root.chunk, utils.root.scope, utils.root.options = chunk, scope, opts0 - local exprs = compile1(ast, scope, chunk, {tail = true}) - keep_side_effects(exprs, chunk, nil, ast) - utils.hook("chunk", ast, scope) - allowed_globals = old_globals - utils.root.reset() - return flatten(chunk, opts0) + local function compile_string(str, _3fopts) + return compile_stream(parser["string-stream"](str, (_3fopts or {})), (_3fopts or {})) + end + local function compile(ast, _3fopts) + return compile_asts({ast}, _3fopts) end local function traceback_frame(info) if ((info.what == "C") and info.name) then @@ -3186,14 +3247,14 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct info.currentline = (remap[info.currentline][2] or -1) end if (info.what == "Lua") then - local function _387_() + local function _396_() if info.name then return ("'" .. info.name .. "'") else return "?" end end - return string.format(" %s:%d: in function %s", info.short_src, info.currentline, _387_()) + return string.format(" %s:%d: in function %s", info.short_src, info.currentline, _396_()) elseif (info.short_src == "(tail call)") then return " (tail call)" else @@ -3217,11 +3278,11 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct local done_3f, level = false, (_3fstart or 2) while not done_3f do do - local _391_0 = debug.getinfo(level, "Sln") - if (_391_0 == nil) then + local _400_0 = debug.getinfo(level, "Sln") + if (_400_0 == nil) then done_3f = true - elseif (nil ~= _391_0) then - local info = _391_0 + elseif (nil ~= _400_0) then + local info = _400_0 table.insert(lines, traceback_frame(info)) end end @@ -3231,14 +3292,14 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct end end local function entry_transform(fk, fv) - local function _394_(k, v) + local function _403_(k, v) if (type(k) == "number") then return k, fv(v) else return fk(k), fv(v) end end - return _394_ + return _403_ end local function mixed_concat(t, joiner) local seen = {} @@ -3283,10 +3344,10 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct return res[1] elseif utils["list?"](form) then local mapped = nil - local function _399_() + local function _408_() return nil end - mapped = utils.kvmap(form, entry_transform(_399_, q)) + mapped = utils.kvmap(form, entry_transform(_408_, q)) local filename = nil if form.filename then filename = string.format("%q", form.filename) @@ -3304,13 +3365,13 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct else filename = "nil" end - local _402_ + local _411_ if source then - _402_ = source.line + _411_ = source.line else - _402_ = "nil" + _411_ = "nil" end - return string.format("setmetatable({%s}, {filename=%s, line=%s, sequence=%s})", mixed_concat(mapped, ", "), filename, _402_, "(getmetatable(sequence()))['sequence']") + return string.format("setmetatable({%s}, {filename=%s, line=%s, sequence=%s})", mixed_concat(mapped, ", "), filename, _411_, "(getmetatable(sequence()))['sequence']") elseif (type(form) == "table") then local mapped = utils.kvmap(form, entry_transform(q, q)) local source = getmetatable(form) @@ -3320,14 +3381,14 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct else filename = "nil" end - local function _405_() + local function _414_() if source then return source.line else return "nil" end end - return string.format("setmetatable({%s}, {filename=%s, line=%s})", mixed_concat(mapped, ", "), filename, _405_()) + return string.format("setmetatable({%s}, {filename=%s, line=%s})", mixed_concat(mapped, ", "), filename, _414_()) elseif (type(form) == "string") then return serialize_string(form) else @@ -3339,7 +3400,7 @@ end package.preload["fennel.friend"] = package.preload["fennel.friend"] or function(...) local utils = require("fennel.utils") local utf8_ok_3f, utf8 = pcall(require, "utf8") - local suggestions = {["$ and $... in hashfn are mutually exclusive"] = {"modifying the hashfn so it only contains $... or $, $1, $2, $3, etc"}, ["can't start multisym segment with a digit"] = {"removing the digit", "adding a non-digit before the digit"}, ["cannot call literal value"] = {"checking for typos", "checking for a missing function name", "making sure to use prefix operators, not infix"}, ["could not compile value of type "] = {"debugging the macro you're calling to return a list or table"}, ["could not read number (.*)"] = {"removing the non-digit character", "beginning the identifier with a non-digit if it is not meant to be a number"}, ["expected a function.* to call"] = {"removing the empty parentheses", "using square brackets if you want an empty table"}, ["expected at least one pattern/body pair"] = {"adding a pattern and a body to execute when the pattern matches"}, ["expected binding and iterator"] = {"making sure you haven't omitted a local name or iterator"}, ["expected binding sequence"] = {"placing a table here in square brackets containing identifiers to bind"}, ["expected body expression"] = {"putting some code in the body of this form after the bindings"}, ["expected each macro to be function"] = {"ensuring that the value for each key in your macros table contains a function", "avoid defining nested macro tables"}, ["expected even number of name/value bindings"] = {"finding where the identifier or value is missing"}, ["expected even number of pattern/body pairs"] = {"checking that every pattern has a body to go with it", "adding _ before the final body"}, ["expected even number of values in table literal"] = {"removing a key", "adding a value"}, ["expected local"] = {"looking for a typo", "looking for a local which is used out of its scope"}, ["expected macros to be table"] = {"ensuring your macro definitions return a table"}, ["expected parameters"] = {"adding function parameters as a list of identifiers in brackets"}, ["expected rest argument before last parameter"] = {"moving & to right before the final identifier when destructuring"}, ["expected symbol for function parameter: (.*)"] = {"changing %s to an identifier instead of a literal value"}, ["expected var (.*)"] = {"declaring %s using var instead of let/local", "introducing a new local instead of changing the value of %s"}, ["expected vararg as last parameter"] = {"moving the \"...\" to the end of the parameter list"}, ["expected whitespace before opening delimiter"] = {"adding whitespace"}, ["global (.*) conflicts with local"] = {"renaming local %s"}, ["invalid character: (.)"] = {"deleting or replacing %s", "avoiding reserved characters like \", \\, ', ~, ;, @, `, and comma"}, ["local (.*) was overshadowed by a special form or macro"] = {"renaming local %s"}, ["macro not found in macro module"] = {"checking the keys of the imported macro module's returned table"}, ["macro tried to bind (.*) without gensym"] = {"changing to %s# when introducing identifiers inside macros"}, ["malformed multisym"] = {"ensuring each period or colon is not followed by another period or colon"}, ["may only be used at compile time"] = {"moving this to inside a macro if you need to manipulate symbols/lists", "using square brackets instead of parens to construct a table"}, ["method must be last component"] = {"using a period instead of a colon for field access", "removing segments after the colon", "making the method call, then looking up the field on the result"}, ["mismatched closing delimiter (.), expected (.)"] = {"replacing %s with %s", "deleting %s", "adding matching opening delimiter earlier"}, ["missing subject"] = {"adding an item to operate on"}, ["multisym method calls may only be in call position"] = {"using a period instead of a colon to reference a table's fields", "putting parens around this"}, ["tried to reference a macro without calling it"] = {"renaming the macro so as not to conflict with locals"}, ["tried to reference a special form without calling it"] = {"making sure to use prefix operators, not infix", "wrapping the special in a function if you need it to be first class"}, ["unable to bind (.*)"] = {"replacing the %s with an identifier"}, ["unexpected arguments"] = {"removing an argument", "checking for typos"}, ["unexpected closing delimiter (.)"] = {"deleting %s", "adding matching opening delimiter earlier"}, ["unexpected iterator clause"] = {"removing an argument", "checking for typos"}, ["unexpected multi symbol (.*)"] = {"removing periods or colons from %s"}, ["unexpected vararg"] = {"putting \"...\" at the end of the fn parameters if the vararg was intended"}, ["unknown identifier: (.*)"] = {"looking to see if there's a typo", "using the _G table instead, eg. _G.%s if you really want a global", "moving this code to somewhere that %s is in scope", "binding %s as a local in the scope of this code"}, ["unused local (.*)"] = {"renaming the local to _%s if it is meant to be unused", "fixing a typo so %s is used", "disabling the linter which checks for unused locals"}, ["use of global (.*) is aliased by a local"] = {"renaming local %s", "refer to the global using _G.%s instead of directly"}} + local suggestions = {["$ and $... in hashfn are mutually exclusive"] = {"modifying the hashfn so it only contains $... or $, $1, $2, $3, etc"}, ["can't start multisym segment with a digit"] = {"removing the digit", "adding a non-digit before the digit"}, ["cannot call literal value"] = {"checking for typos", "checking for a missing function name", "making sure to use prefix operators, not infix"}, ["could not compile value of type "] = {"debugging the macro you're calling to return a list or table"}, ["could not read number (.*)"] = {"removing the non-digit character", "beginning the identifier with a non-digit if it is not meant to be a number"}, ["expected a function.* to call"] = {"removing the empty parentheses", "using square brackets if you want an empty table"}, ["expected at least one pattern/body pair"] = {"adding a pattern and a body to execute when the pattern matches"}, ["expected binding and iterator"] = {"making sure you haven't omitted a local name or iterator"}, ["expected binding sequence"] = {"placing a table here in square brackets containing identifiers to bind"}, ["expected body expression"] = {"putting some code in the body of this form after the bindings"}, ["expected each macro to be function"] = {"ensuring that the value for each key in your macros table contains a function", "avoid defining nested macro tables"}, ["expected even number of name/value bindings"] = {"finding where the identifier or value is missing"}, ["expected even number of pattern/body pairs"] = {"checking that every pattern has a body to go with it", "adding _ before the final body"}, ["expected even number of values in table literal"] = {"removing a key", "adding a value"}, ["expected local"] = {"looking for a typo", "looking for a local which is used out of its scope"}, ["expected macros to be table"] = {"ensuring your macro definitions return a table"}, ["expected parameters"] = {"adding function parameters as a list of identifiers in brackets"}, ["expected range to include start and stop"] = {"adding missing arguments"}, ["expected rest argument before last parameter"] = {"moving & to right before the final identifier when destructuring"}, ["expected symbol for function parameter: (.*)"] = {"changing %s to an identifier instead of a literal value"}, ["expected var (.*)"] = {"declaring %s using var instead of let/local", "introducing a new local instead of changing the value of %s"}, ["expected vararg as last parameter"] = {"moving the \"...\" to the end of the parameter list"}, ["expected whitespace before opening delimiter"] = {"adding whitespace"}, ["global (.*) conflicts with local"] = {"renaming local %s"}, ["invalid character: (.)"] = {"deleting or replacing %s", "avoiding reserved characters like \", \\, ', ~, ;, @, `, and comma"}, ["local (.*) was overshadowed by a special form or macro"] = {"renaming local %s"}, ["macro not found in macro module"] = {"checking the keys of the imported macro module's returned table"}, ["macro tried to bind (.*) without gensym"] = {"changing to %s# when introducing identifiers inside macros"}, ["malformed multisym"] = {"ensuring each period or colon is not followed by another period or colon"}, ["may only be used at compile time"] = {"moving this to inside a macro if you need to manipulate symbols/lists", "using square brackets instead of parens to construct a table"}, ["method must be last component"] = {"using a period instead of a colon for field access", "removing segments after the colon", "making the method call, then looking up the field on the result"}, ["mismatched closing delimiter (.), expected (.)"] = {"replacing %s with %s", "deleting %s", "adding matching opening delimiter earlier"}, ["missing subject"] = {"adding an item to operate on"}, ["multisym method calls may only be in call position"] = {"using a period instead of a colon to reference a table's fields", "putting parens around this"}, ["tried to reference a macro without calling it"] = {"renaming the macro so as not to conflict with locals"}, ["tried to reference a special form without calling it"] = {"making sure to use prefix operators, not infix", "wrapping the special in a function if you need it to be first class"}, ["tried to use unquote outside quote"] = {"moving the form to inside a quoted form", "removing the comma"}, ["tried to use vararg with operator"] = {"accumulating over the operands"}, ["unable to bind (.*)"] = {"replacing the %s with an identifier"}, ["unexpected arguments"] = {"removing an argument", "checking for typos"}, ["unexpected closing delimiter (.)"] = {"deleting %s", "adding matching opening delimiter earlier"}, ["unexpected iterator clause"] = {"removing an argument", "checking for typos"}, ["unexpected multi symbol (.*)"] = {"removing periods or colons from %s"}, ["unexpected vararg"] = {"putting \"...\" at the end of the fn parameters if the vararg was intended"}, ["unknown identifier: (.*)"] = {"looking to see if there's a typo", "using the _G table instead, eg. _G.%s if you really want a global", "moving this code to somewhere that %s is in scope", "binding %s as a local in the scope of this code"}, ["unused local (.*)"] = {"renaming the local to _%s if it is meant to be unused", "fixing a typo so %s is used", "disabling the linter which checks for unused locals"}, ["use of global (.*) is aliased by a local"] = {"renaming local %s", "refer to the global using _G.%s instead of directly"}} local unpack = (table.unpack or _G.unpack) local function suggest(msg) local s = nil @@ -3371,7 +3432,7 @@ package.preload["fennel.friend"] = package.preload["fennel.friend"] or function( end return matcher() else - local f = assert(io.open(filename)) + local f = assert(_G.io.open(filename)) local function close_handlers_10_(ok_11_, ...) f:close() if ok_11_ then @@ -3380,17 +3441,17 @@ package.preload["fennel.friend"] = package.preload["fennel.friend"] or function( return error(..., 0) end end - local function _178_() + local function _184_() for _ = 2, line do f:read() end return f:read() end - return close_handlers_10_(_G.xpcall(_178_, (package.loaded.fennel or debug).traceback)) + return close_handlers_10_(_G.xpcall(_184_, (package.loaded.fennel or debug).traceback)) end end local function sub(str, start, _end) - if ((_end < start) or (#str < start) or (#str < _end)) then + if ((_end < start) or (#str < start)) then return "" elseif utf8_ok_3f then return string.sub(str, utf8.offset(str, start), ((utf8.offset(str, (_end + 1)) or (utf8.len(str) + 1)) - 1)) @@ -3402,8 +3463,8 @@ package.preload["fennel.friend"] = package.preload["fennel.friend"] or function( if ((opts and (false == opts["error-pinpoint"])) or (os and os.getenv and os.getenv("NO_COLOR"))) then return codeline else - local _181_ = (opts or {}) - local error_pinpoint = _181_["error-pinpoint"] + local _187_ = (opts or {}) + local error_pinpoint = _187_["error-pinpoint"] local endcol = (_3fendcol or col) local eol = nil if utf8_ok_3f then @@ -3411,23 +3472,30 @@ package.preload["fennel.friend"] = package.preload["fennel.friend"] or function( else eol = string.len(codeline) end - local _183_ = (error_pinpoint or {"\27[7m", "\27[0m"}) - local open = _183_[1] - local close = _183_[2] + local _189_ = (error_pinpoint or {"\27[7m", "\27[0m"}) + local open = _189_[1] + local close = _189_[2] return (sub(codeline, 1, col) .. open .. sub(codeline, (col + 1), (endcol + 1)) .. close .. sub(codeline, (endcol + 2), eol)) end end - local function friendly_msg(msg, _185_0, source, opts) - local _186_ = _185_0 - local col = _186_["col"] - local endcol = _186_["endcol"] - local filename = _186_["filename"] - local line = _186_["line"] + local function friendly_msg(msg, _191_0, source, opts) + local _192_ = _191_0 + local col = _192_["col"] + local endcol = _192_["endcol"] + local endline = _192_["endline"] + local filename = _192_["filename"] + local line = _192_["line"] local ok, codeline = pcall(read_line, filename, line, source) + local endcol0 = nil + if (ok and codeline and (line ~= endline)) then + endcol0 = #codeline + else + endcol0 = endcol + end local out = {msg, ""} if (ok and codeline) then if col then - table.insert(out, highlight_line(codeline, col, endcol, opts)) + table.insert(out, highlight_line(codeline, col, endcol0, opts)) else table.insert(out, codeline) end @@ -3439,10 +3507,10 @@ package.preload["fennel.friend"] = package.preload["fennel.friend"] or function( end local function assert_compile(condition, msg, ast, source, opts) if not condition then - local _189_ = utils["ast-source"](ast) - local col = _189_["col"] - local filename = _189_["filename"] - local line = _189_["line"] + local _196_ = utils["ast-source"](ast) + local col = _196_["col"] + local filename = _196_["filename"] + local line = _196_["line"] error(friendly_msg(("%s:%s:%s Compile error: %s"):format((filename or "unknown"), (line or "?"), (col or "?"), msg), utils["ast-source"](ast), source, opts), 0) end return condition @@ -3458,36 +3526,36 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( local unpack = (table.unpack or _G.unpack) local function granulate(getchunk) local c, index, done_3f = "", 1, false - local function _191_(parser_state) + local function _198_(parser_state) if not done_3f then if (index <= #c) then local b = c:byte(index) index = (index + 1) return b else - local _192_0 = getchunk(parser_state) - local function _193_() - local char = _192_0 + local _199_0 = getchunk(parser_state) + local function _200_() + local char = _199_0 return (char ~= "") end - if ((nil ~= _192_0) and _193_()) then - local char = _192_0 + if ((nil ~= _199_0) and _200_()) then + local char = _199_0 c = char index = 2 return c:byte() else - local _ = _192_0 + local _ = _199_0 done_3f = true return nil end end end end - local function _197_() + local function _204_() c = "" return nil end - return _191_, _197_ + return _198_, _204_ end local function string_stream(str, _3foptions) local str0 = str:gsub("^#!", ";;") @@ -3495,12 +3563,12 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( _3foptions.source = str0 end local index = 1 - local function _199_() + local function _206_() local r = str0:byte(index) index = (index + 1) return r end - return _199_ + return _206_ end local delims = {[123] = 125, [125] = true, [40] = 41, [41] = true, [91] = 93, [93] = true} local function sym_char_3f(b) @@ -3516,12 +3584,12 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( local function char_starter_3f(b) return (((1 < b) and (b < 127)) or ((192 < b) and (b < 247))) end - local function parser_fn(getbyte, filename, _201_0) - local _202_ = _201_0 - local options = _202_ - local comments = _202_["comments"] - local source = _202_["source"] - local unfriendly = _202_["unfriendly"] + local function parser_fn(getbyte, filename, _208_0) + local _209_ = _208_0 + local options = _209_ + local comments = _209_["comments"] + local source = _209_["source"] + local unfriendly = _209_["unfriendly"] local stack = {} local line, byteindex, col, prev_col, lastb = 1, 0, 0, 0, nil local function ungetb(ub) @@ -3552,20 +3620,20 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( return r end local function whitespace_3f(b) - local function _209_() - local _208_0 = options.whitespace - if (nil ~= _208_0) then - _208_0 = _208_0[b] + local function _216_() + local _215_0 = options.whitespace + if (nil ~= _215_0) then + _215_0 = _215_0[b] end - return _208_0 + return _215_0 end - return ((b == 32) or ((9 <= b) and (b <= 13)) or _209_()) + return ((b == 32) or ((9 <= b) and (b <= 13)) or _216_()) end local function parse_error(msg, _3fcol_adjust) local col0 = (col + (_3fcol_adjust or -1)) if (nil == utils["hook-opts"]("parse-error", options, msg, filename, (line or "?"), col0, source, utils.root.reset)) then utils.root.reset() - if (unfriendly or not _G.io or not _G.io.read) then + if unfriendly then return error(string.format("%s:%s:%s Parse error: %s", filename, (line or "?"), col0, msg), 0) else return friend["parse-error"](msg, filename, (line or "?"), col0, source, options) @@ -3575,50 +3643,98 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( local function parse_stream() local whitespace_since_dispatch, done_3f, retval = true local function set_source_fields(source0) - source0.byteend, source0.endcol = byteindex, (col - 1) + source0.byteend, source0.endcol, source0.endline = byteindex, (col - 1), line return nil end local function dispatch(v) - local _213_0 = stack[#stack] - if (_213_0 == nil) then + local _220_0 = stack[#stack] + if (_220_0 == nil) then retval, done_3f, whitespace_since_dispatch = v, true, false return nil - elseif ((_G.type(_213_0) == "table") and (nil ~= _213_0.prefix)) then - local prefix = _213_0.prefix + elseif ((_G.type(_220_0) == "table") and (nil ~= _220_0.prefix)) then + local prefix = _220_0.prefix local source0 = nil do - local _214_0 = table.remove(stack) - set_source_fields(_214_0) - source0 = _214_0 + local _221_0 = table.remove(stack) + set_source_fields(_221_0) + source0 = _221_0 end local list = utils.list(utils.sym(prefix, source0), v) for k, v0 in pairs(source0) do list[k] = v0 end return dispatch(list) - elseif (nil ~= _213_0) then - local top = _213_0 + elseif (nil ~= _220_0) then + local top = _220_0 whitespace_since_dispatch = false return table.insert(top, v) end end + local close_table = nil + local function badend(cause) + local accum = utils.map(stack, "closer") + local _223_ + if (#stack == 1) then + _223_ = "" + else + _223_ = "s" + end + parse_error(string.format("expected closing delimiter%s %s", _223_, string.char(unpack(accum)))) + if (cause == "eof") then + for i = #accum, 2, -1 do + close_table(accum[i]) + end + return accum[1] + end + end + local function skip_whitespace(b) + if (b and whitespace_3f(b)) then + whitespace_since_dispatch = true + return skip_whitespace(getb()) + elseif (not b and (0 < #stack)) then + return badend("eof") + else + return b + end + end + local function parse_comment(b, contents) + if (b and (10 ~= b)) then + local function _227_() + table.insert(contents, string.char(b)) + return contents + end + return parse_comment(getb(), _227_()) + elseif comments then + ungetb(10) + return dispatch(utils.comment(table.concat(contents), {filename = filename, line = line})) + end + end + local function open_table(b) + if not whitespace_since_dispatch then + parse_error(("expected whitespace before opening delimiter " .. string.char(b))) + end + return table.insert(stack, {bytestart = byteindex, closer = delims[b], col = (col - 1), filename = filename, line = line}) + end local function close_list(list) return dispatch(setmetatable(list, getmetatable(utils.list()))) end local function close_sequence(tbl) - local val = utils.sequence(unpack(tbl)) + local mt = getmetatable(utils.sequence()) for k, v in pairs(tbl) do - getmetatable(val)[k] = v + if ("number" ~= type(k)) then + mt[k] = v + tbl[k] = nil + end end - return dispatch(val) + return dispatch(setmetatable(tbl, mt)) end local function add_comment_at(comments0, index, node) - local _216_0 = comments0[index] - if (nil ~= _216_0) then - local existing = _216_0 + local _231_0 = comments0[index] + if (nil ~= _231_0) then + local existing = _231_0 return table.insert(existing, node) else - local _ = _216_0 + local _ = _231_0 comments0[index] = {node} return nil end @@ -3626,7 +3742,7 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( local function next_noncomment(tbl, i) if utils["comment?"](tbl[i]) then return next_noncomment(tbl, (i + 1)) - elseif (utils.sym(":") == tbl[i]) then + elseif utils["sym?"](tbl[i], ":") then return tostring(tbl[(i + 1)]) else return tbl[i] @@ -3674,7 +3790,7 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( tbl.keys = keys return dispatch(val) end - local function close_table(b) + local function close_table0(b) local top = table.remove(stack) if (top == nil) then parse_error(("unexpected closing delimiter " .. string.char(b))) @@ -3691,64 +3807,23 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( return close_curly_table(top) end end - local function badend(cause) - local accum = utils.map(stack, "closer") - local _226_ - if (#stack == 1) then - _226_ = "" - else - _226_ = "s" - end - parse_error(string.format("expected closing delimiter%s %s", _226_, string.char(unpack(accum)))) - if (cause == "eof") then - for i = #accum, 2, -1 do - close_table(accum[i]) - end - return accum[1] - end - end - local function skip_whitespace(b) - if (b and whitespace_3f(b)) then - whitespace_since_dispatch = true - return skip_whitespace(getb()) - elseif (not b and (0 < #stack)) then - return badend("eof") - else - return b - end - end - local function parse_comment(b, contents) - if (b and (10 ~= b)) then - local function _230_() - table.insert(contents, string.char(b)) - return contents - end - return parse_comment(getb(), _230_()) - elseif comments then - ungetb(10) - return dispatch(utils.comment(table.concat(contents), {filename = filename, line = line})) - end - end - local function open_table(b) - if not whitespace_since_dispatch then - parse_error(("expected whitespace before opening delimiter " .. string.char(b))) - end - return table.insert(stack, {bytestart = byteindex, closer = delims[b], col = (col - 1), filename = filename, line = line}) - end + close_table = close_table0 local function parse_string_loop(chars, b, state) - table.insert(chars, b) + if b then + table.insert(chars, string.char(b)) + end local state0 = nil do - local _233_0 = {state, b} - if ((_G.type(_233_0) == "table") and (_233_0[1] == "base") and (_233_0[2] == 92)) then + local _242_0 = {state, b} + if ((_G.type(_242_0) == "table") and (_242_0[1] == "base") and (_242_0[2] == 92)) then state0 = "backslash" - elseif ((_G.type(_233_0) == "table") and (_233_0[1] == "base") and (_233_0[2] == 34)) then + elseif ((_G.type(_242_0) == "table") and (_242_0[1] == "base") and (_242_0[2] == 34)) then state0 = "done" - elseif ((_G.type(_233_0) == "table") and (_233_0[1] == "backslash") and (_233_0[2] == 10)) then + elseif ((_G.type(_242_0) == "table") and (_242_0[1] == "backslash") and (_242_0[2] == 10)) then table.remove(chars, (#chars - 1)) state0 = "base" else - local _ = _233_0 + local _ = _242_0 state0 = "base" end end @@ -3763,18 +3838,18 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( end local function parse_string() table.insert(stack, {closer = 34}) - local chars = {34} + local chars = {"\""} if not parse_string_loop(chars, getb(), "base") then badend("string") end table.remove(stack) - local raw = string.char(unpack(chars)) + local raw = table.concat(chars) local formatted = raw:gsub("[\7-\13]", escape_char) - local _237_0 = (rawget(_G, "loadstring") or load)(("return " .. formatted)) - if (nil ~= _237_0) then - local load_fn = _237_0 + local _246_0 = (rawget(_G, "loadstring") or load)(("return " .. formatted)) + if (nil ~= _246_0) then + local load_fn = _246_0 return dispatch(load_fn()) - elseif (_237_0 == nil) then + elseif (_246_0 == nil) then return parse_error(("Invalid string: " .. raw)) end end @@ -3792,7 +3867,7 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( end local function parse_sym_loop(chars, b) if (b and sym_char_3f(b)) then - table.insert(chars, b) + table.insert(chars, string.char(b)) return parse_sym_loop(chars, getb()) else if b then @@ -3807,13 +3882,13 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( dispatch((tonumber(number_with_stripped_underscores) or parse_error(("could not read number \"" .. rawstr .. "\"")))) return true else - local _243_0 = tonumber(number_with_stripped_underscores) - if (nil ~= _243_0) then - local x = _243_0 + local _252_0 = tonumber(number_with_stripped_underscores) + if (nil ~= _252_0) then + local x = _252_0 dispatch(x) return true else - local _ = _243_0 + local _ = _252_0 return false end end @@ -3837,7 +3912,7 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( end local function parse_sym(b) local source0 = {bytestart = byteindex, col = (col - 1), filename = filename, line = line} - local rawstr = string.char(unpack(parse_sym_loop({b}, getb()))) + local rawstr = table.concat(parse_sym_loop({string.char(b)}, getb())) set_source_fields(source0) if (rawstr == "true") then return dispatch(true) @@ -3858,7 +3933,7 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( elseif (type(delims[b]) == "number") then open_table(b) elseif delims[b] then - close_table(b) + close_table0(b) elseif (b == 34) then parse_string(b) elseif prefixes[b] then @@ -3878,11 +3953,11 @@ package.preload["fennel.parser"] = package.preload["fennel.parser"] or function( end return parse_loop(skip_whitespace(getb())) end - local function _250_() + local function _259_() stack, line, byteindex, col, lastb = {}, 1, 0, 0, nil return nil end - return parse_stream, _250_ + return parse_stream, _259_ end local function parser(stream_or_string, _3ffilename, _3foptions) local filename = (_3ffilename or "unknown") @@ -3942,14 +4017,13 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) end end local function getopt(options, key) - local val = options[key] - local _9_0 = val + local _9_0 = options[key] if ((_G.type(_9_0) == "table") and (nil ~= _9_0.once)) then local val_2a = _9_0.once return val_2a else - local _ = _9_0 - return val + local _3fval = _9_0 + return _3fval end end local function normalize_opts(options) @@ -4089,15 +4163,15 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) end return seen0 end - local function detect_cycle(t, seen, _3fk) + local function detect_cycle(t, seen) if ("table" == type(t)) then seen[t] = true - local _36_0, _37_0 = next(t, _3fk) - if ((nil ~= _36_0) and (nil ~= _37_0)) then - local k = _36_0 - local v = _37_0 - return (seen[k] or detect_cycle(k, seen) or seen[v] or detect_cycle(v, seen) or detect_cycle(t, seen, k)) + local res = nil + for k, v in pairs(t) do + if res then break end + res = (seen[k] or detect_cycle(k, seen) or seen[v] or detect_cycle(v, seen)) end + return res end end local function visible_cycle_3f(t, options) @@ -4116,14 +4190,14 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) local function concat_table_lines(elements, options, multiline_3f, indent, table_type, prefix, last_comment_3f) local indent_str = ("\n" .. string.rep(" ", indent)) local open = nil - local function _41_() + local function _38_() if ("seq" == table_type) then return "[" else return "{" end end - open = ((prefix or "") .. _41_()) + open = ((prefix or "") .. _38_()) local close = nil if ("seq" == table_type) then close = "]" @@ -4132,14 +4206,14 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) end local oneline = (open .. table.concat(elements, " ") .. close) if (not getopt(options, "one-line?") and (multiline_3f or (options["line-length"] < (indent + length_2a(oneline))) or last_comment_3f)) then - local function _43_() + local function _40_() if last_comment_3f then return indent_str else return "" end end - return (open .. table.concat(elements, indent_str) .. _43_() .. close) + return (open .. table.concat(elements, indent_str) .. _40_() .. close) else return oneline end @@ -4174,10 +4248,10 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) if getopt(options, "utf8?") then slength = utf8_len else - local function _46_(_241) + local function _43_(_241) return #_241 end - slength = _46_ + slength = _43_ end local prefix = nil if visible_cycle_3f0 then @@ -4190,10 +4264,10 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) local options0 = normalize_opts(options) local tbl_17_ = {} local i_18_ = #tbl_17_ - for _, _49_0 in ipairs(kv) do - local _50_ = _49_0 - local k = _50_[1] - local v = _50_[2] + for _, _46_0 in ipairs(kv) do + local _47_ = _46_0 + local k = _47_[1] + local v = _47_[2] local val_19_ = nil do local k0 = pp(k, options0, (indent0 + 1), true) @@ -4234,10 +4308,10 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) local options0 = normalize_opts(options) local tbl_17_ = {} local i_18_ = #tbl_17_ - for _, _54_0 in ipairs(kv) do - local _55_ = _54_0 - local _0 = _55_[1] - local v = _55_[2] + for _, _51_0 in ipairs(kv) do + local _52_ = _51_0 + local _0 = _52_[1] + local v = _52_[2] local val_19_ = nil do local v0 = pp(v, options0, indent0) @@ -4263,7 +4337,7 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) end else local oneline = nil - local _59_ + local _56_ do local tbl_17_ = {} local i_18_ = #tbl_17_ @@ -4274,9 +4348,9 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) tbl_17_[i_18_] = val_19_ end end - _59_ = tbl_17_ + _56_ = tbl_17_ end - oneline = table.concat(_59_, " ") + oneline = table.concat(_56_, " ") if (not getopt(options, "one-line?") and (force_multi_line_3f or oneline:find("\n") or (options["line-length"] < (indent + length_2a(oneline))))) then return table.concat(lines, ("\n" .. string.rep(" ", indent))) else @@ -4293,10 +4367,10 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) end else local _ = nil - local function _64_(_241) + local function _61_(_241) return visible_cycle_3f(_241, options) end - options["visible-cycle?"] = _64_ + options["visible-cycle?"] = _61_ _ = nil local lines, force_multi_line_3f = nil, nil do @@ -4304,13 +4378,13 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) lines, force_multi_line_3f = metamethod(t, pp, options0, indent) end options["visible-cycle?"] = nil - local _65_0 = type(lines) - if (_65_0 == "string") then + local _62_0 = type(lines) + if (_62_0 == "string") then return lines - elseif (_65_0 == "table") then + elseif (_62_0 == "table") then return concat_lines(lines, options, indent, force_multi_line_3f) else - local _0 = _65_0 + local _0 = _62_0 return error("__fennelview metamethod must return a table of lines") end end @@ -4319,40 +4393,40 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) options.level = (options.level + 1) local x0 = nil do - local _68_0 = nil + local _65_0 = nil if getopt(options, "metamethod?") then - local _69_0 = x - if (nil ~= _69_0) then - local _70_0 = getmetatable(_69_0) - if (nil ~= _70_0) then - _68_0 = _70_0.__fennelview + local _66_0 = x + if (nil ~= _66_0) then + local _67_0 = getmetatable(_66_0) + if (nil ~= _67_0) then + _65_0 = _67_0.__fennelview else - _68_0 = _70_0 + _65_0 = _67_0 end else - _68_0 = _69_0 + _65_0 = _66_0 end else - _68_0 = nil + _65_0 = nil end - if (nil ~= _68_0) then - local metamethod = _68_0 + if (nil ~= _65_0) then + local metamethod = _65_0 x0 = pp_metamethod(x, metamethod, options, indent) else - local _ = _68_0 - local _74_0, _75_0 = table_kv_pairs(x, options) - if (true and (_75_0 == "empty")) then - local _0 = _74_0 + local _ = _65_0 + local _71_0, _72_0 = table_kv_pairs(x, options) + if (true and (_72_0 == "empty")) then + local _0 = _71_0 if getopt(options, "empty-as-sequence?") then x0 = "[]" else x0 = "{}" end - elseif ((nil ~= _74_0) and (_75_0 == "table")) then - local kv = _74_0 + elseif ((nil ~= _71_0) and (_72_0 == "table")) then + local kv = _71_0 x0 = pp_associative(x, kv, options, indent) - elseif ((nil ~= _74_0) and (_75_0 == "seq")) then - local kv = _74_0 + elseif ((nil ~= _71_0) and (_72_0 == "seq")) then + local kv = _71_0 x0 = pp_sequence(x, kv, options, indent) else x0 = nil @@ -4363,14 +4437,17 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) return x0 end local function number__3estring(n) - local _79_0 = string.gsub(tostring(n), ",", ".") - return _79_0 + local _76_0 = string.gsub(tostring(n), ",", ".") + return _76_0 end local function colon_string_3f(s) - return s:find("^[-%w?^_!$%&*+./@|<=>]+$") + return s:find("^[-%w?^_!$%&*+./|<=>]+$") end local utf8_inits = {{["max-byte"] = 127, ["max-code"] = 127, ["min-byte"] = 0, ["min-code"] = 0, len = 1}, {["max-byte"] = 223, ["max-code"] = 2047, ["min-byte"] = 192, ["min-code"] = 128, len = 2}, {["max-byte"] = 239, ["max-code"] = 65535, ["min-byte"] = 224, ["min-code"] = 2048, len = 3}, {["max-byte"] = 247, ["max-code"] = 1114111, ["min-byte"] = 240, ["min-code"] = 65536, len = 4}} - local function utf8_escape(str) + local function default_byte_escape(byte, _options) + return ("\\%03d"):format(byte) + end + local function utf8_escape(str, options) local function validate_utf8(str0, index) local inits = utf8_inits local byte = string.byte(str0, index) @@ -4379,12 +4456,12 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) local ret = nil for _, init0 in ipairs(inits) do if ret then break end - ret = (byte and (function(_80_,_81_,_82_) return (_80_ <= _81_) and (_81_ <= _82_) end)(init0["min-byte"],byte,init0["max-byte"]) and init0) + ret = (byte and (function(_77_,_78_,_79_) return (_77_ <= _78_) and (_78_ <= _79_) end)(init0["min-byte"],byte,init0["max-byte"]) and init0) end init = ret end local code = nil - local function _83_() + local function _80_() local code0 = nil if init then code0 = (byte - init["min-byte"]) @@ -4397,19 +4474,20 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) end return code0 end - code = (init and _83_()) - if (code and (function(_85_,_86_,_87_) return (_85_ <= _86_) and (_86_ <= _87_) end)(init["min-code"],code,init["max-code"]) and not ((55296 <= code) and (code <= 57343))) then + code = (init and _80_()) + if (code and (function(_82_,_83_,_84_) return (_82_ <= _83_) and (_83_ <= _84_) end)(init["min-code"],code,init["max-code"]) and not ((55296 <= code) and (code <= 57343))) then return init.len end end local index = 1 local output = {} + local byte_escape = (getopt(options, "byte-escape") or default_byte_escape) while (index <= #str) do local nexti = (string.find(str, "[\128-\255]", index) or (#str + 1)) local len = validate_utf8(str, nexti) table.insert(output, string.sub(str, index, (nexti + (len or 0) + -1))) if (not len and (nexti <= #str)) then - table.insert(output, string.format("\\%03d", string.byte(str, nexti))) + table.insert(output, byte_escape(str:byte(nexti), options)) end if len then index = (nexti + len) @@ -4422,20 +4500,21 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) local function pp_string(str, options, indent) local len = length_2a(str) local esc_newline_3f = ((len < 2) or (getopt(options, "escape-newlines?") and (len < (options["line-length"] - indent)))) + local byte_escape = (getopt(options, "byte-escape") or default_byte_escape) local escs = nil - local _91_ + local _88_ if esc_newline_3f then - _91_ = "\\n" + _88_ = "\\n" else - _91_ = "\n" + _88_ = "\n" end - local function _93_(_241, _242) - return ("\\%03d"):format(_242:byte()) + local function _90_(_241, _242) + return byte_escape(_242:byte(), options) end - escs = setmetatable({["\""] = "\\\"", ["\11"] = "\\v", ["\12"] = "\\f", ["\13"] = "\\r", ["\7"] = "\\a", ["\8"] = "\\b", ["\9"] = "\\t", ["\\"] = "\\\\", ["\n"] = _91_}, {__index = _93_}) + escs = setmetatable({["\""] = "\\\"", ["\11"] = "\\v", ["\12"] = "\\f", ["\13"] = "\\r", ["\7"] = "\\a", ["\8"] = "\\b", ["\9"] = "\\t", ["\\"] = "\\\\", ["\n"] = _88_}, {__index = _90_}) local str0 = ("\"" .. str:gsub("[%c\\\"]", escs) .. "\"") if getopt(options, "utf8?") then - return utf8_escape(str0) + return utf8_escape(str0, options) else return str0 end @@ -4461,7 +4540,7 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) end return defaults end - local function _96_(x, options, indent, colon_3f) + local function _93_(x, options, indent, colon_3f) local indent0 = (indent or 0) local options0 = (options or make_options(x)) local x0 = nil @@ -4471,20 +4550,19 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) x0 = x end local tv = type(x0) - local function _99_() - local _98_0 = getmetatable(x0) - if (nil ~= _98_0) then - return _98_0.__fennelview - else - return _98_0 + local function _96_() + local _95_0 = getmetatable(x0) + if ((_G.type(_95_0) == "table") and true) then + local __fennelview = _95_0.__fennelview + return __fennelview end end - if ((tv == "table") or ((tv == "userdata") and _99_())) then + if ((tv == "table") or ((tv == "userdata") and _96_())) then return pp_table(x0, options0, indent0) elseif (tv == "number") then return number__3estring(x0) else - local function _101_() + local function _98_() if (colon_3f ~= nil) then return colon_3f elseif ("function" == type(options0["prefer-colon?"])) then @@ -4493,7 +4571,7 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) return getopt(options0, "prefer-colon?") end end - if ((tv == "string") and colon_string_3f(x0) and _101_()) then + if ((tv == "string") and colon_string_3f(x0) and _98_()) then return (":" .. x0) elseif (tv == "string") then return pp_string(x0, options0, indent0) @@ -4504,7 +4582,7 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) end end end - pp = _96_ + pp = _93_ local function view(x, _3foptions) return pp(x, make_options(x, _3foptions), 0) end @@ -4512,7 +4590,7 @@ package.preload["fennel.view"] = package.preload["fennel.view"] or function(...) end package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(...) local view = require("fennel.view") - local version = "1.3.1-dev" + local version = "1.3.2-dev" local function luajit_vm_3f() return ((nil ~= _G.jit) and (type(_G.jit) == "table") and (nil ~= _G.jit.on) and (nil ~= _G.jit.off) and (type(_G.jit.version_num) == "number")) end @@ -4540,8 +4618,12 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. return ("PUC " .. _VERSION) end end - local function runtime_version() - return ("Fennel " .. version .. " on " .. lua_vm_version()) + local function runtime_version(_3fas_table) + if _3fas_table then + return {fennel = version, lua = lua_vm_version()} + else + return ("Fennel " .. version .. " on " .. lua_vm_version()) + end end local function warn(message) if (_G.io and _G.io.stderr) then @@ -4550,43 +4632,77 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. end local len = nil do - local _106_0, _107_0 = pcall(require, "utf8") - if ((_106_0 == true) and (nil ~= _107_0)) then - local utf8 = _107_0 + local _104_0, _105_0 = pcall(require, "utf8") + if ((_104_0 == true) and (nil ~= _105_0)) then + local utf8 = _105_0 len = utf8.len else - local _ = _106_0 + local _ = _104_0 len = string.len end end - local function mt_keys_in_order(t, out, used_keys) - for _, k in ipairs(getmetatable(t).keys) do - if (t[k] and not used_keys[k]) then - used_keys[k] = true - table.insert(out, k) + local kv_order = {boolean = 2, number = 1, string = 3, table = 4} + local function kv_compare(a, b) + local _107_0, _108_0 = type(a), type(b) + if (((_107_0 == "number") and (_108_0 == "number")) or ((_107_0 == "string") and (_108_0 == "string"))) then + return (a < b) + else + local function _109_() + local a_t = _107_0 + local b_t = _108_0 + return (a_t ~= b_t) + end + if (((nil ~= _107_0) and (nil ~= _108_0)) and _109_()) then + local a_t = _107_0 + local b_t = _108_0 + return ((kv_order[a_t] or 5) < (kv_order[b_t] or 5)) + else + local _ = _107_0 + return (tostring(a) < tostring(b)) end end - for k in pairs(t) do - if not used_keys[k] then - table.insert(out, k) + end + local function add_stable_keys(succ, prev_key, src, _3fpred) + local first = prev_key + local last = nil + do + local prev = prev_key + for _, k in ipairs(src) do + if ((prev == k) or (succ[k] ~= nil) or (_3fpred and not _3fpred(k))) then + prev = prev + else + if (first == nil) then + first = k + prev = k + elseif (prev ~= nil) then + succ[prev] = k + prev = k + else + prev = k + end + end end + last = prev end - return out + return succ, last, first end local function stablepairs(t) - local keys = nil - local _112_ + local mt_keys = nil do - local _111_0 = getmetatable(t) - if (nil ~= _111_0) then - _111_0 = _111_0.keys + local _113_0 = getmetatable(t) + if (nil ~= _113_0) then + _113_0 = _113_0.keys end - _112_ = _111_0 + mt_keys = _113_0 end - if _112_ then - keys = mt_keys_in_order(t, {}, {}) - else - local _114_0 = nil + local succ, prev, first_mt = nil, nil, nil + local function _115_(_241) + return t[_241] + end + succ, prev, first_mt = add_stable_keys({}, nil, (mt_keys or {}), _115_) + local pairs_keys = nil + do + local _116_0 = nil do local tbl_17_ = {} local i_18_ = #tbl_17_ @@ -4597,33 +4713,34 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. tbl_17_[i_18_] = val_19_ end end - _114_0 = tbl_17_ + _116_0 = tbl_17_ end - local function _116_(_241, _242) - return (tostring(_241) < tostring(_242)) - end - table.sort(_114_0, _116_) - keys = _114_0 + table.sort(_116_0, kv_compare) + pairs_keys = _116_0 end - local succ = nil - do - local tbl_14_ = {} - for i, k in ipairs(keys) do - local k_15_, v_16_ = k, keys[(i + 1)] - if ((k_15_ ~= nil) and (v_16_ ~= nil)) then - tbl_14_[k_15_] = v_16_ - end - end - succ = tbl_14_ + local succ0, _, first_after_mt = add_stable_keys(succ, prev, pairs_keys) + local first = nil + if (first_mt == nil) then + first = first_after_mt + else + first = first_mt end local function stablenext(tbl, key) - local next_key = nil + local _119_0 = nil if (key == nil) then - next_key = keys[1] + _119_0 = first else - next_key = succ[key] + _119_0 = succ0[key] + end + if (nil ~= _119_0) then + local next_key = _119_0 + local _121_0 = tbl[next_key] + if (_121_0 ~= nil) then + return next_key, _121_0 + else + return _121_0 + end end - return next_key, tbl[next_key] end return stablenext, t, nil end @@ -4632,25 +4749,25 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. if (0 == #path) then return _3ffallback else - local _120_0 = nil + local _124_0 = nil do local t = tbl for _, k in ipairs(path) do if (nil == t) then break end - local _121_0 = type(t) - if (_121_0 == "table") then + local _125_0 = type(t) + if (_125_0 == "table") then t = t[k] else t = nil end end - _120_0 = t + _124_0 = t end - if (nil ~= _120_0) then - local res = _120_0 + if (nil ~= _124_0) then + local res = _124_0 return res else - local _ = _120_0 + local _ = _124_0 return _3ffallback end end @@ -4661,15 +4778,15 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. if (type(f) == "function") then f0 = f else - local function _125_(_241) + local function _129_(_241) return _241[f] end - f0 = _125_ + f0 = _129_ end for _, x in ipairs(t) do - local _127_0 = f0(x) - if (nil ~= _127_0) then - local v = _127_0 + local _131_0 = f0(x) + if (nil ~= _131_0) then + local v = _131_0 table.insert(out, v) end end @@ -4681,19 +4798,19 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. if (type(f) == "function") then f0 = f else - local function _129_(_241) + local function _133_(_241) return _241[f] end - f0 = _129_ + f0 = _133_ end for k, x in stablepairs(t) do - local _131_0, _132_0 = f0(k, x) - if ((nil ~= _131_0) and (nil ~= _132_0)) then - local key = _131_0 - local value = _132_0 + local _135_0, _136_0 = f0(k, x) + if ((nil ~= _135_0) and (nil ~= _136_0)) then + local key = _135_0 + local value = _136_0 out[key] = value - elseif (nil ~= _131_0) then - local value = _131_0 + elseif (nil ~= _135_0) then + local value = _135_0 table.insert(out, value) end end @@ -4710,13 +4827,13 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. return tbl_14_ end local function member_3f(x, tbl, _3fn) - local _135_0 = tbl[(_3fn or 1)] - if (_135_0 == x) then + local _139_0 = tbl[(_3fn or 1)] + if (_139_0 == x) then return true - elseif (_135_0 == nil) then + elseif (_139_0 == nil) then return nil else - local _ = _135_0 + local _ = _139_0 return member_3f(x, tbl, ((_3fn or 1) + 1)) end end @@ -4751,9 +4868,9 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. seen[next_state] = true return next_state, value else - local _138_0 = getmetatable(t) - if ((_G.type(_138_0) == "table") and true) then - local __index = _138_0.__index + local _142_0 = getmetatable(t) + if ((_G.type(_142_0) == "table") and true) then + local __index = _142_0.__index if ("table" == type(__index)) then t = __index return allpairs_next(t) @@ -4771,10 +4888,10 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. local safe = {} local view0 = nil if _3fview then - local function _142_(_241) + local function _146_(_241) return _3fview(_241, _3foptions, _3findent) end - view0 = _142_ + view0 = _146_ else view0 = view end @@ -4795,19 +4912,19 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. end local symbol_mt = {"SYMBOL", __eq = sym_3d, __fennelview = deref, __lt = sym_3c, __tostring = deref} local expr_mt = nil - local function _144_(x) + local function _148_(x) return tostring(deref(x)) end - expr_mt = {"EXPR", __tostring = _144_} + expr_mt = {"EXPR", __tostring = _148_} local list_mt = {"LIST", __fennelview = list__3estring, __tostring = list__3estring} local comment_mt = {"COMMENT", __eq = sym_3d, __fennelview = comment_view, __lt = sym_3c, __tostring = deref} local sequence_marker = {"SEQUENCE"} local varg_mt = {"VARARG", __fennelview = deref, __tostring = deref} local getenv = nil - local function _145_() + local function _149_() return nil end - getenv = ((os and os.getenv) or _145_) + getenv = ((os and os.getenv) or _149_) local function debug_on_3f(flag) local level = (getenv("FENNEL_DEBUG") or "") return ((level == "all") or level:find(flag)) @@ -4816,7 +4933,7 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. return setmetatable({...}, list_mt) end local function sym(str, _3fsource) - local _146_ + local _150_ do local tbl_14_ = {str} for k, v in pairs((_3fsource or {})) do @@ -4830,13 +4947,13 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. tbl_14_[k_15_] = v_16_ end end - _146_ = tbl_14_ + _150_ = tbl_14_ end - return setmetatable(_146_, symbol_mt) + return setmetatable(_150_, symbol_mt) end nil_sym = sym("nil") local function sequence(...) - local function _149_(seq, view0, inspector, indent) + local function _153_(seq, view0, inspector, indent) local opts = nil do inspector["empty-as-sequence?"] = {after = inspector["empty-as-sequence?"], once = true} @@ -4845,19 +4962,19 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. end return view0(seq, opts, indent) end - return setmetatable({...}, {__fennelview = _149_, sequence = sequence_marker}) + return setmetatable({...}, {__fennelview = _153_, sequence = sequence_marker}) end local function expr(strcode, etype) return setmetatable({strcode, type = etype}, expr_mt) end local function comment_2a(contents, _3fsource) - local _150_ = (_3fsource or {}) - local filename = _150_["filename"] - local line = _150_["line"] + local _154_ = (_3fsource or {}) + local filename = _154_["filename"] + local line = _154_["line"] return setmetatable({contents, filename = filename, line = line}, comment_mt) end local function varg(_3fsource) - local _151_ + local _155_ do local tbl_14_ = {"..."} for k, v in pairs((_3fsource or {})) do @@ -4871,9 +4988,9 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. tbl_14_[k_15_] = v_16_ end end - _151_ = tbl_14_ + _155_ = tbl_14_ end - return setmetatable(_151_, varg_mt) + return setmetatable(_155_, varg_mt) end local function expr_3f(x) return ((type(x) == "table") and (getmetatable(x) == expr_mt) and x) @@ -4884,8 +5001,8 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. local function list_3f(x) return ((type(x) == "table") and (getmetatable(x) == list_mt) and x) end - local function sym_3f(x) - return ((type(x) == "table") and (getmetatable(x) == symbol_mt) and x) + local function sym_3f(x, _3fname) + return ((type(x) == "table") and (getmetatable(x) == symbol_mt) and ((nil == _3fname) or (x[1] == _3fname)) and x) end local function sequence_3f(x) local mt = ((type(x) == "table") and getmetatable(x)) @@ -4897,6 +5014,19 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. local function table_3f(x) return ((type(x) == "table") and not varg_3f(x) and (getmetatable(x) ~= list_mt) and (getmetatable(x) ~= symbol_mt) and not comment_3f(x) and x) end + local function kv_table_3f(t) + if table_3f(t) then + local nxt, t0, k = pairs(t) + local len0 = #t0 + local next_state = nil + if (0 == len0) then + next_state = k + else + next_state = len0 + end + return ((nil ~= nxt(t0, next_state)) and t0) + end + end local function string_3f(x) return (type(x) == "string") end @@ -4906,7 +5036,7 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. elseif (type(str) ~= "string") then return false else - local function _154_() + local function _160_() local parts = {} for part in str:gmatch("[^%.%:]+[%.%:]?") do local last_char = part:sub(( - 1)) @@ -4921,7 +5051,7 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. end return ((0 < #parts) and parts) end - return ((str:match("%.") or str:match(":")) and not str:match("%.%.") and (str:byte() ~= string.byte(".")) and (str:byte(-1) ~= string.byte(".")) and (str:byte() ~= string.byte(":")) and (str:byte(-1) ~= string.byte(":")) and _154_()) + return ((str:match("%.") or str:match(":")) and not str:match("%.%.") and (str:byte() ~= string.byte(".")) and (str:byte(-1) ~= string.byte(".")) and (str:byte() ~= string.byte(":")) and (str:byte(-1) ~= string.byte(":")) and _160_()) end end local function quoted_3f(symbol) @@ -4951,10 +5081,7 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. walk((_3fcustom_iterator or pairs), nil, nil, root) return root end - local lua_keywords = {"and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while", "goto"} - for i, v in ipairs(lua_keywords) do - lua_keywords[v] = i - end + local lua_keywords = {["and"] = true, ["break"] = true, ["do"] = true, ["else"] = true, ["elseif"] = true, ["end"] = true, ["false"] = true, ["for"] = true, ["function"] = true, ["goto"] = true, ["if"] = true, ["in"] = true, ["local"] = true, ["nil"] = true, ["not"] = true, ["or"] = true, ["repeat"] = true, ["return"] = true, ["then"] = true, ["true"] = true, ["until"] = true, ["while"] = true} local function valid_lua_identifier_3f(str) return (str:match("^[%a_][%w_]*$") and not lua_keywords[str]) end @@ -4966,15 +5093,15 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. return subopts end local root = nil - local function _160_() + local function _166_() end - root = {chunk = nil, options = nil, reset = _160_, scope = nil} - root["set-reset"] = function(_161_0) - local _162_ = _161_0 - local chunk = _162_["chunk"] - local options = _162_["options"] - local reset = _162_["reset"] - local scope = _162_["scope"] + root = {chunk = nil, options = nil, reset = _166_, scope = nil} + root["set-reset"] = function(_167_0) + local _168_ = _167_0 + local chunk = _168_["chunk"] + local options = _168_["options"] + local reset = _168_["reset"] + local scope = _168_["scope"] root.reset = function() root.chunk, root.scope, root.options, root.reset = chunk, scope, options, reset return nil @@ -4982,11 +5109,11 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. return root.reset end local warned = {} - local function check_plugin_version(_163_0) - local _164_ = _163_0 - local plugin = _164_ - local name = _164_["name"] - local versions = _164_["versions"] + local function check_plugin_version(_169_0) + local _170_ = _169_0 + local plugin = _170_ + local name = _170_["name"] + local versions = _170_["versions"] if (not member_3f(version:gsub("-dev", ""), (versions or {})) and not warned[plugin]) then warned[plugin] = true return warn(string.format("plugin %s does not support Fennel version %s", (name or "unknown"), version)) @@ -4994,29 +5121,29 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. end local function hook_opts(event, _3foptions, ...) local plugins = nil - local function _167_(...) - local _166_0 = _3foptions - if (nil ~= _166_0) then - _166_0 = _166_0.plugins + local function _173_(...) + local _172_0 = _3foptions + if (nil ~= _172_0) then + _172_0 = _172_0.plugins end - return _166_0 + return _172_0 end - local function _170_(...) - local _169_0 = root.options - if (nil ~= _169_0) then - _169_0 = _169_0.plugins + local function _176_(...) + local _175_0 = root.options + if (nil ~= _175_0) then + _175_0 = _175_0.plugins end - return _169_0 + return _175_0 end - plugins = (_167_(...) or _170_(...)) + plugins = (_173_(...) or _176_(...)) if plugins then local result = nil for _, plugin in ipairs(plugins) do if result then break end check_plugin_version(plugin) - local _172_0 = plugin[event] - if (nil ~= _172_0) then - local f = _172_0 + local _178_0 = plugin[event] + if (nil ~= _178_0) then + local f = _178_0 result = f(...) else result = nil @@ -5028,7 +5155,7 @@ package.preload["fennel.utils"] = package.preload["fennel.utils"] or function(.. local function hook(event, ...) return hook_opts(event, root.options, ...) end - return {["ast-source"] = ast_source, ["comment?"] = comment_3f, ["debug-on?"] = debug_on_3f, ["every?"] = every_3f, ["expr?"] = expr_3f, ["get-in"] = get_in, ["hook-opts"] = hook_opts, ["idempotent-expr?"] = idempotent_expr_3f, ["list?"] = list_3f, ["lua-keywords"] = lua_keywords, ["macro-path"] = table.concat({"./?.fnl", "./?/init-macros.fnl", "./?/init.fnl", getenv("FENNEL_MACRO_PATH")}, ";"), ["member?"] = member_3f, ["multi-sym?"] = multi_sym_3f, ["propagate-options"] = propagate_options, ["quoted?"] = quoted_3f, ["runtime-version"] = runtime_version, ["sequence?"] = sequence_3f, ["string?"] = string_3f, ["sym?"] = sym_3f, ["table?"] = table_3f, ["valid-lua-identifier?"] = valid_lua_identifier_3f, ["varg?"] = varg_3f, ["walk-tree"] = walk_tree, allpairs = allpairs, comment = comment_2a, copy = copy, expr = expr, hook = hook, kvmap = kvmap, len = len, list = list, map = map, maxn = maxn, path = table.concat({"./?.fnl", "./?/init.fnl", getenv("FENNEL_PATH")}, ";"), root = root, sequence = sequence, stablepairs = stablepairs, sym = sym, varg = varg, version = version, warn = warn} + return {["ast-source"] = ast_source, ["comment?"] = comment_3f, ["debug-on?"] = debug_on_3f, ["every?"] = every_3f, ["expr?"] = expr_3f, ["get-in"] = get_in, ["hook-opts"] = hook_opts, ["idempotent-expr?"] = idempotent_expr_3f, ["kv-table?"] = kv_table_3f, ["list?"] = list_3f, ["lua-keywords"] = lua_keywords, ["macro-path"] = table.concat({"./?.fnl", "./?/init-macros.fnl", "./?/init.fnl", getenv("FENNEL_MACRO_PATH")}, ";"), ["member?"] = member_3f, ["multi-sym?"] = multi_sym_3f, ["propagate-options"] = propagate_options, ["quoted?"] = quoted_3f, ["runtime-version"] = runtime_version, ["sequence?"] = sequence_3f, ["string?"] = string_3f, ["sym?"] = sym_3f, ["table?"] = table_3f, ["valid-lua-identifier?"] = valid_lua_identifier_3f, ["varg?"] = varg_3f, ["walk-tree"] = walk_tree, allpairs = allpairs, comment = comment_2a, copy = copy, expr = expr, hook = hook, kvmap = kvmap, len = len, list = list, map = map, maxn = maxn, path = table.concat({"./?.fnl", "./?/init.fnl", getenv("FENNEL_PATH")}, ";"), root = root, sequence = sequence, stablepairs = stablepairs, sym = sym, varg = varg, version = version, warn = warn} end utils = require("fennel.utils") local parser = require("fennel.parser") @@ -5060,24 +5187,24 @@ local function eval_opts(options, str) end return opts end -local function eval(str, options, ...) - local opts = eval_opts(options, str) +local function eval(str, _3foptions, ...) + local opts = eval_opts(_3foptions, str) local env = eval_env(opts.env, opts) local lua_source = compiler["compile-string"](str, opts) local loader = nil - local function _709_(...) + local function _735_(...) if opts.filename then return ("@" .. opts.filename) else return str end end - loader = specials["load-code"](lua_source, env, _709_(...)) + loader = specials["load-code"](lua_source, env, _735_(...)) opts.filename = nil return loader(...) end -local function dofile_2a(filename, options, ...) - local opts = utils.copy(options) +local function dofile_2a(filename, _3foptions, ...) + local opts = utils.copy(_3foptions) local f = assert(io.open(filename, "rb")) local source = assert(f:read("*all"), ("Could not read " .. filename)) f:close() @@ -5097,10 +5224,10 @@ local function syntax() out[k] = {["binding-form?"] = utils["member?"](k, binding_3f), ["body-form?"] = utils["member?"](k, body_3f), ["define?"] = utils["member?"](k, define_3f), ["macro?"] = true} end for k, v in pairs(_G) do - local _710_0 = type(v) - if (_710_0 == "function") then + local _736_0 = type(v) + if (_736_0 == "function") then out[k] = {["function?"] = true, ["global?"] = true} - elseif (_710_0 == "table") then + elseif (_736_0 == "table") then for k2, v2 in pairs(v) do if (("function" == type(v2)) and (k ~= "_G")) then out[(k .. "." .. k2)] = {["function?"] = true, ["global?"] = true} @@ -5120,17 +5247,17 @@ utils["fennel-module"] = mod do local module_name = "fennel.macros" local _ = nil - local function _713_() + local function _739_() return mod end - package.preload[module_name] = _713_ + package.preload[module_name] = _739_ _ = nil local env = nil do - local _714_0 = specials["make-compiler-env"](nil, compiler.scopes.compiler, {}) - _714_0["utils"] = utils - _714_0["fennel"] = mod - env = _714_0 + local _740_0 = specials["make-compiler-env"](nil, compiler.scopes.compiler, {}) + _740_0["utils"] = utils + _740_0["fennel"] = mod + env = _740_0 end local built_ins = eval([===[;; These macros are awkward because their definition cannot rely on the any ;; built-in macros, only special forms. (no when, no icollect, etc) @@ -5246,8 +5373,7 @@ do (var (into iter-out found?) (values [] (copy iter-tbl))) (for [i (length iter-tbl) 2 -1] (let [item (. iter-tbl i)] - (if (or (= `&into item) - (= :into item)) + (if (or (sym? item "&into") (= :into item)) (do (assert (not found?) "expected only one &into clause") (set found? true) @@ -5449,18 +5575,19 @@ do Like `fn`, but will throw an exception if a declared argument is passed in as nil, unless that argument's name begins with a question mark." (let [args [...] + args-len (length args) has-internal-name? (sym? (. args 1)) arglist (if has-internal-name? (. args 2) (. args 1)) - docstring-position (if has-internal-name? 3 2) - has-docstring? (and (< docstring-position (length args)) - (= :string (type (. args docstring-position)))) + metadata-position (if has-internal-name? 3 2) + has-metadata? (and (< metadata-position args-len) + (or (= :string (type (. args metadata-position))) + (utils.kv-table? (. args metadata-position)))) arity-check-position (- 4 (if has-internal-name? 0 1) - (if has-docstring? 0 1)) - empty-body? (< (length args) arity-check-position)] + (if has-metadata? 0 1)) + empty-body? (< args-len arity-check-position)] (fn check! [a] (if (table? a) - (each [_ a (pairs a)] - (check! a)) + (each [_ a (pairs a)] (check! a)) (let [as (tostring a)] (and (not (as:match "^?")) (not= as "&") (not= as "_") (not= as "...") (not= as "&as"))) @@ -5472,8 +5599,7 @@ do (or a.line "?")))))) (assert (= :table (type arglist)) "expected arg list") - (each [_ a (ipairs arglist)] - (check! a)) + (each [_ a (ipairs arglist)] (check! a)) (if empty-body? (table.insert args (sym :nil))) `(fn ,(unpack args)))) @@ -5576,7 +5702,7 @@ do (let [condition `(and (= (_G.type ,val) :table)) bindings []] (each [k pat (pairs pattern)] - (if (= pat `&) + (if (sym? pat :&) (let [rest-pat (. pattern (+ k 1)) rest-val `(select ,k ((or table.unpack _G.unpack) ,val)) subcondition (case-table `(pick-values 1 ,rest-val) @@ -5588,19 +5714,19 @@ do "expected & rest argument before last parameter") (table.insert bindings rest-pat) (table.insert bindings [rest-val])) - (= k `&as) + (sym? k :&as) (do (table.insert bindings pat) (table.insert bindings val)) - (and (= :number (type k)) (= `&as pat)) + (and (= :number (type k)) (sym? pat :&as)) (do (assert (= nil (. pattern (+ k 2))) "expected &as argument before last parameter") (table.insert bindings (. pattern (+ k 1))) (table.insert bindings val)) ;; don't process the pattern right after &/&as; already got it - (or (not= :number (type k)) (and (not= `&as (. pattern (- k 1))) - (not= `& (. pattern (- k 1))))) + (or (not= :number (type k)) (and (not (sym? (. pattern (- k 1)) :&as)) + (not (sym? (. pattern (- k 1)) :&)))) (let [subval `(. ,val ,k) (subcondition subbindings) (case-pattern [subval] pat unifications @@ -5621,16 +5747,19 @@ do (fn symbols-in-pattern [pattern] "gives the set of symbols inside a pattern" (if (list? pattern) - (let [result {}] - (each [_ child-pattern (ipairs pattern)] - (collect [name symbol (pairs (symbols-in-pattern child-pattern)) &into result] - name symbol)) - result) + (if (or (sym? (. pattern 1) :where) + (sym? (. pattern 1) :=)) + (symbols-in-pattern (. pattern 2)) + (sym? (. pattern 2) :?) + (symbols-in-pattern (. pattern 1)) + (let [result {}] + (each [_ child-pattern (ipairs pattern)] + (collect [name symbol (pairs (symbols-in-pattern child-pattern)) &into result] + name symbol)) + result)) (sym? pattern) - (if (and (not= pattern `or) - (not= pattern `where) - (not= pattern `?) - (not= pattern `nil)) + (if (and (not (sym? pattern :or)) + (not (sym? pattern :nil))) {(tostring pattern) pattern} {}) (= (type pattern) :table) @@ -5713,10 +5842,10 @@ do ;; of vals) or we're not, in which case we only care about the first one. (let [[val] vals] (if (and (sym? pattern) - (or (= pattern `nil) + (or (sym? pattern :nil) (and opts.infer-unification? (in-scope? pattern) - (not= pattern `_)) + (not (sym? pattern :_))) (and opts.infer-unification? (multi-sym? pattern) (in-scope? (. (multi-sym? pattern) 1))))) @@ -5732,33 +5861,33 @@ do `(not= ,(sym :nil) ,val)) [pattern val])) ;; opt-in unify with (=) (and (list? pattern) - (= (. pattern 1) `=) + (sym? (. pattern 1) :=) (sym? (. pattern 2))) (let [bind (. pattern 2)] (assert-compile (= 2 (length pattern)) "(=) should take only one argument" pattern) (assert-compile (not opts.infer-unification?) "(=) cannot be used inside of match" pattern) (assert-compile opts.in-where? "(=) must be used in (where) patterns" pattern) - (assert-compile (and (sym? bind) (not= bind `nil) "= has to bind to a symbol" bind)) + (assert-compile (and (sym? bind) (not (sym? bind :nil)) "= has to bind to a symbol" bind)) (values `(= ,val ,bind) [])) ;; where-or clause - (and (list? pattern) (= (. pattern 1) `where) (list? (. pattern 2)) (= (. pattern 2 1) `or)) + (and (list? pattern) (sym? (. pattern 1) :where) (list? (. pattern 2)) (sym? (. pattern 2 1) :or)) (do (assert-compile top-level? "can't nest (where) pattern" pattern) (case-or vals (. pattern 2) [(unpack pattern 3)] unifications case-pattern (with opts :in-where?))) ;; where clause - (and (list? pattern) (= (. pattern 1) `where)) + (and (list? pattern) (sym? (. pattern 1) :where)) (do (assert-compile top-level? "can't nest (where) pattern" pattern) (case-guard vals (. pattern 2) [(unpack pattern 3)] unifications case-pattern (with opts :in-where?))) ;; or clause (not allowed on its own) - (and (list? pattern) (= (. pattern 1) `or)) + (and (list? pattern) (sym? (. pattern 1) :or)) (do (assert-compile top-level? "can't nest (or) pattern" pattern) ;; This assertion can be removed to make patterns more permissive (assert-compile false "(or) must be used in (where) patterns" pattern) (case-or vals pattern [] unifications case-pattern opts)) ;; guard clause - (and (list? pattern) (= (. pattern 2) `?)) + (and (list? pattern) (sym? (. pattern 2) :?)) (do (assert-compile opts.legacy-guard-allowed? "legacy guard clause not supported in case" pattern) (case-guard vals (. pattern 1) [(unpack pattern 3)] unifications case-pattern opts)) @@ -5811,11 +5940,11 @@ do (fn count-case-multival [pattern] "Identify the amount of multival values that a pattern requires." - (if (and (list? pattern) (= (. pattern 2) `?)) + (if (and (list? pattern) (sym? (. pattern 2) :?)) (count-case-multival (. pattern 1)) - (and (list? pattern) (= (. pattern 1) `where)) + (and (list? pattern) (sym? (. pattern 1) :where)) (count-case-multival (. pattern 2)) - (and (list? pattern) (= (. pattern 1) `or)) + (and (list? pattern) (sym? (. pattern 1) :or)) (accumulate [longest 0 _ child-pattern (ipairs pattern)] (math.max longest (count-case-multival child-pattern))) @@ -5823,16 +5952,13 @@ do (length pattern) 1)) - (fn case-val-syms [clauses] - "What is the length of the largest multi-valued clause? return a list of that - many gensyms." + (fn case-count-syms [clauses] + "Find the length of the largest multi-valued clause" (let [patterns (fcollect [i 1 (length clauses) 2] - (. clauses i)) - sym-count (accumulate [longest 0 - _ pattern (ipairs patterns)] - (math.max longest (count-case-multival pattern)))] - (fcollect [i 1 sym-count &into (list)] - (gensym)))) + (. clauses i))] + (accumulate [longest 0 + _ pattern (ipairs patterns)] + (math.max longest (count-case-multival pattern))))) (fn case-impl [match? val ...] "The shared implementation of case and match." @@ -5842,10 +5968,14 @@ do (assert (not= 0 (select :# ...)) "expected at least one pattern/body pair") (let [clauses [...] - vals (case-val-syms clauses)] - ;; protect against multiple evaluation of the value, bind against as - ;; many values as we ever match against in the clauses. - (list `let [vals val] (case-condition vals clauses match?)))) + vals-count (case-count-syms clauses) + skips-multiple-eval-protection? (and (= vals-count 1) (sym? val) (not (multi-sym? val)))] + (if skips-multiple-eval-protection? + (case-condition (list val) clauses match?) + ;; protect against multiple evaluation of the value, bind against as + ;; many values as we ever match against in the clauses. + (let [vals (fcollect [i 1 vals-count &into (list)] (gensym))] + (list `let [vals val] (case-condition vals clauses match?)))))) (fn case* [val ...] "Perform pattern matching on val. See reference for details. @@ -5891,7 +6021,7 @@ do (fn case-try-impl [how expr pattern body ...] (let [clauses [pattern body ...] last (. clauses (length clauses)) - catch (if (= `catch (and (= :table (type last)) (. last 1))) + catch (if (sym? (and (= :table (type last)) (. last 1)) :catch) (let [[_ & e] (table.remove clauses)] e) ; remove `catch sym [`_# `...])] (assert (= 0 (math.fmod (length clauses) 2)) diff --git a/test/completion-test.fnl b/test/completion-test.fnl index 13faf9f..c6fd48d 100644 --- a/test/completion-test.fnl +++ b/test/completion-test.fnl @@ -57,7 +57,7 @@ (describe "When the program doesn't compile" (it "still completes without requiring the close parentheses" - (check-completion "(fn foo [z]\n (let [x 10 y 20]\n " 1 2 [:x :y :z])) + (check-completion "(fn foo [z]\n (let [x 10 y 20]\n " 2 4 [:x :y :z])) (it "still completes with no body in the `let`" (check-completion "(let [x 10 y 20]\n )" 1 2 [:x :y])) diff --git a/test/init-macros.fnl b/test/init-macros.fnl index 90bb1e7..ea5f175 100644 --- a/test/init-macros.fnl +++ b/test/init-macros.fnl @@ -28,7 +28,7 @@ `(match ,item ,pattern nil ?otherwise# - (error + (is false (.. "Pattern did not match:\n" (let [fennel# (require :fennel)] (fennel#.view ?otherwise#)) diff --git a/test/lust.lua b/test/lust.lua index 9c7cf05..fc3d2ee 100644 --- a/test/lust.lua +++ b/test/lust.lua @@ -206,7 +206,7 @@ function lust.expect(v) err = nerr or err end if not res then - error(err or 'unknown failure', 2) + error(err or 'unknown failure') end end end diff --git a/test/references-test.fnl b/test/references-test.fnl index fcd3db5..27943bd 100644 --- a/test/references-test.fnl +++ b/test/references-test.fnl @@ -1,6 +1,5 @@ (import-macros {: is-matching : describe : it : before-each} :test) (local is (require :test.is)) -(local message (require :fennel-ls.message)) (local {: view} (require :fennel)) (local {: ROOT-URI @@ -8,6 +7,10 @@ (local filename (.. ROOT-URI "/imaginary-file.fnl")) +(fn range [a b c d] + {:start {:line a :character b} + :end {:line c :character d}}) + (fn check-references [body line col ?expected] (let [client (doto (create-client) (: :open-file! filename body)) @@ -20,22 +23,22 @@ (describe "references" (it "finds a reference from let" (check-references "(let [x 10] x)" 0 12 - [{:uri filename :range (message.pos->range 0 12 0 13)}])) + [{:uri filename :range (range 0 12 0 13)}])) (it "finds a reference from let" (check-references "(let [x 10] x)" 0 6 - [{:uri filename :range (message.pos->range 0 12 0 13)}])) + [{:uri filename :range (range 0 12 0 13)}])) (let [x 10] x x x) (it "finds multiple reference from let" (check-references "(let [x 10] x x x)" 0 6 - [{:uri filename :range (message.pos->range 0 12 0 13)} - {:uri filename :range (message.pos->range 0 14 0 15)} - {:uri filename :range (message.pos->range 0 16 0 17)}])) + [{:uri filename :range (range 0 12 0 13)} + {:uri filename :range (range 0 14 0 15)} + {:uri filename :range (range 0 16 0 17)}])) (it "finds a reference from fn" (check-references "(fn x []) x" 0 10 - [{:uri filename :range (message.pos->range 0 10 0 11)}])) + [{:uri filename :range (range 0 10 0 11)}])) ; (it "finds a reference from fn" ; (check-references "(fn x []) x" 0 4 diff --git a/test/string-processing-test.fnl b/test/string-processing-test.fnl index 32be186..7a49009 100644 --- a/test/string-processing-test.fnl +++ b/test/string-processing-test.fnl @@ -6,31 +6,67 @@ (describe "utils" - ;; fixme: - ;; test for errors on out of bounds - ;; test for multiline edits - ;; test for unicode utf8 utf16 nightmare + (fn position [line character] + {: line : character}) + + (fn range [start-line start-col end-line end-col] + {:start (position start-line start-col) :end (position end-line end-col)}) + + (it "converts position->byte properly" + (is.equal 1 (utils.position->byte "a饜悁位\nb位饜悁" (position 0 0) :utf-8)) + (is.equal 2 (utils.position->byte "a饜悁位\nb位饜悁" (position 0 1) :utf-8)) + (is.equal 6 (utils.position->byte "a饜悁位\nb位饜悁" (position 0 5) :utf-8)) + (is.equal 8 (utils.position->byte "a饜悁位\nb位饜悁" (position 0 7) :utf-8)) + (is.equal 9 (utils.position->byte "a饜悁位\nb位饜悁" (position 1 0) :utf-8)) + (is.equal 10 (utils.position->byte "a饜悁位\nb位饜悁" (position 1 1) :utf-8)) + (is.equal 12 (utils.position->byte "a饜悁位\nb位饜悁" (position 1 3) :utf-8)) + (is.equal 16 (utils.position->byte "a饜悁位\nb位饜悁" (position 1 7) :utf-8)) + (is.equal 1 (utils.position->byte "a饜悁位\nb位饜悁" (position 0 0) :utf-16)) + (is.equal 2 (utils.position->byte "a饜悁位\nb位饜悁" (position 0 1) :utf-16)) + (is.equal 6 (utils.position->byte "a饜悁位\nb位饜悁" (position 0 3) :utf-16)) + (is.equal 8 (utils.position->byte "a饜悁位\nb位饜悁" (position 0 4) :utf-16)) + (is.equal 9 (utils.position->byte "a饜悁位\nb位饜悁" (position 1 0) :utf-16)) + (is.equal 10 (utils.position->byte "a饜悁位\nb位饜悁" (position 1 1) :utf-16)) + (is.equal 12 (utils.position->byte "a饜悁位\nb位饜悁" (position 1 2) :utf-16)) + (is.equal 16 (utils.position->byte "a饜悁位\nb位饜悁" (position 1 4) :utf-16))) + + (it "converts byte->position properly" + (is.same (position 0 0) (utils.byte->position "a饜悁位\nb位饜悁" 1 :utf-8)) + (is.same (position 0 1) (utils.byte->position "a饜悁位\nb位饜悁" 2 :utf-8)) + (is.same (position 0 5) (utils.byte->position "a饜悁位\nb位饜悁" 6 :utf-8)) + (is.same (position 0 7) (utils.byte->position "a饜悁位\nb位饜悁" 8 :utf-8)) + (is.same (position 1 0) (utils.byte->position "a饜悁位\nb位饜悁" 9 :utf-8)) + (is.same (position 1 1) (utils.byte->position "a饜悁位\nb位饜悁" 10 :utf-8)) + (is.same (position 1 3) (utils.byte->position "a饜悁位\nb位饜悁" 12 :utf-8)) + (is.same (position 1 7) (utils.byte->position "a饜悁位\nb位饜悁" 16 :utf-8)) + (is.same (position 0 0) (utils.byte->position "a饜悁位\nb位饜悁" 1 :utf-16)) + (is.same (position 0 1) (utils.byte->position "a饜悁位\nb位饜悁" 2 :utf-16)) + (is.same (position 0 3) (utils.byte->position "a饜悁位\nb位饜悁" 6 :utf-16)) + (is.same (position 0 4) (utils.byte->position "a饜悁位\nb位饜悁" 8 :utf-16)) + (is.same (position 1 0) (utils.byte->position "a饜悁位\nb位饜悁" 9 :utf-16)) + (is.same (position 1 1) (utils.byte->position "a饜悁位\nb位饜悁" 10 :utf-16)) + (is.same (position 1 2) (utils.byte->position "a饜悁位\nb位饜悁" 12 :utf-16)) + (is.same (position 1 4) (utils.byte->position "a饜悁位\nb位饜悁" 16 :utf-16))) (describe "apply-changes" - (fn range [start-line start-col end-line end-col] - {:start {:line start-line :character start-col} - :end {:line end-line :character end-col}}) - (it "updates the start of a line" (is.equal (utils.apply-changes "replace beginning" [{:range (range 0 0 0 7) - :text "the"}]) + :text "the"}] + :utf-8) "the beginning")) + (it "updates the end of a line" (is.equal (utils.apply-changes "first line\nsecond line\nreplace end" [{:range (range 2 7 2 11) - :text "ment"}]) + :text "ment"}] + :utf-8) "first line\nsecond line\nreplacement")) (it "replaces a line" @@ -38,23 +74,25 @@ (utils.apply-changes "replace all" [{:range (range 0 0 0 11) - :text "new string"}]) + :text "new string"}] + :utf-8) "new string")) (it "can handle substituting things" (is.equal (utils.apply-changes "replace beginning" - [{:range {:start {:line 0 :character 0} - :end {:line 0 :character 7}} - :text "the"}]) + [{:range (range 0 0 0 7) + :text "the"}] + :utf-8) "the beginning")) (it "can handle replacing everything" (is.equal (utils.apply-changes "this is the\nold file" - [{:text "And this is the\nnew file"}]) + [{:text "And this is the\nnew file"}] + :utf-8) "And this is the\nnew file")))) ;; (it "can substitute multiple ranges")