diff --git a/bootstrap.lua b/bootstrap.lua index 27a1953..97a565d 100644 --- a/bootstrap.lua +++ b/bootstrap.lua @@ -14,7 +14,7 @@ local fail_at fail_at = require('nomsu_compiler').fail_at local MAX_LINE = 80 local compile_actions = { - [""] = function(self, fn, ...) + [""] = function(self, _t, fn, ...) local lua = LuaCode() local fn_lua = self:compile(fn) lua:add(fn_lua) @@ -31,7 +31,7 @@ local compile_actions = { lua:add(")") return lua end, - ["Lua"] = function(self, code) + ["Lua"] = function(self, _t, code) if not code then return LuaCode("LuaCode()") end @@ -62,7 +62,7 @@ local compile_actions = { end return operate_on_text(code) end, - ["lua >"] = function(self, code) + ["lua >"] = function(self, _t, code) if code.type ~= "Text" then return code end @@ -83,7 +83,7 @@ local compile_actions = { end return operate_on_text(code) end, - ["= lua"] = function(self, code) + ["= lua"] = function(self, _t, code) return self:compile(SyntaxTree({ type = "Action", "lua", @@ -91,19 +91,19 @@ local compile_actions = { code })) end, - ["1 as lua"] = function(self, code) + ["1 as lua"] = function(self, _t, code) return LuaCode("_ENV:compile(", self:compile(code), ")") end, - ["use"] = function(self, path) + ["use"] = function(self, _t, path) return LuaCode("_ENV:use(" .. tostring(self:compile(path)) .. ")") end, - ["export"] = function(self, path) + ["export"] = function(self, _t, path) return LuaCode("_ENV:export(" .. tostring(self:compile(path)) .. ")") end, - ["run"] = function(self, path) + ["run"] = function(self, _t, path) return LuaCode("_ENV:run(" .. tostring(self:compile(path)) .. ")") end, - ["test"] = function(self, body) + ["test"] = function(self, _t, body) if not (body.type == 'Block') then fail_at(body, "Compile error: This should be a Block") end @@ -121,22 +121,22 @@ local compile_actions = { })) return LuaCode("TESTS[" .. tostring(tostring(body.source):as_lua()) .. "] = ", test_text) end, - ["is jit"] = function(self, code) + ["is jit"] = function(self, _t, code) return LuaCode("jit") end, - ["Lua version"] = function(self, code) + ["Lua version"] = function(self, _t, code) return LuaCode("_VERSION") end, - ["nomsu environment"] = function(self) + ["nomsu environment"] = function(self, _t) return LuaCode("_ENV") end, - ["nomsu environment name"] = function(self) + ["nomsu environment name"] = function(self, _t) return LuaCode('"_ENV"') end, - ["this file was run directly"] = function(self) + ["this file was run directly"] = function(self, _t) return LuaCode('WAS_RUN_DIRECTLY') end, - ["the command line arguments"] = function(self) + ["the command line arguments"] = function(self, _t) return LuaCode('COMMAND_LINE_ARGS') end } diff --git a/bootstrap.moon b/bootstrap.moon index aca2dd7..d30e56b 100644 --- a/bootstrap.moon +++ b/bootstrap.moon @@ -8,7 +8,7 @@ Files = require "files" MAX_LINE = 80 -- For beautification purposes, try not to make lines much longer than this value compile_actions = { - [""]: (fn, ...)=> + [""]: (_t, fn, ...)=> lua = LuaCode! fn_lua = @compile(fn) lua\add fn_lua @@ -21,7 +21,7 @@ compile_actions = { lua\add ")" return lua - ["Lua"]: (code)=> + ["Lua"]: (_t, code)=> if not code return LuaCode("LuaCode()") if code.type != "Text" @@ -58,7 +58,7 @@ compile_actions = { return operate_on_text code - ["lua >"]: (code)=> + ["lua >"]: (_t, code)=> if code.type != "Text" return code operate_on_text = (text)-> @@ -73,22 +73,22 @@ compile_actions = { return lua return operate_on_text code - ["= lua"]: (code)=> + ["= lua"]: (_t, code)=> @compile(SyntaxTree{type:"Action", "lua", ">", code}) - ["1 as lua"]: (code)=> + ["1 as lua"]: (_t, code)=> LuaCode("_ENV:compile(", @compile(code), ")") - ["use"]: (path)=> + ["use"]: (_t, path)=> LuaCode("_ENV:use(#{@compile(path)})") - ["export"]: (path)=> + ["export"]: (_t, path)=> LuaCode("_ENV:export(#{@compile(path)})") - ["run"]: (path)=> + ["run"]: (_t, path)=> LuaCode("_ENV:run(#{@compile(path)})") - ["test"]: (body)=> + ["test"]: (_t, body)=> unless body.type == 'Block' fail_at(body, "Compile error: This should be a Block") test_nomsu = body\get_source_code!\match(":[ ]*(.*)") @@ -97,12 +97,12 @@ compile_actions = { test_text = @compile(SyntaxTree{type:"Text", source:body.source, test_nomsu}) return LuaCode "TESTS[#{tostring(body.source)\as_lua!}] = ", test_text - ["is jit"]: (code)=> LuaCode("jit") - ["Lua version"]: (code)=> LuaCode("_VERSION") - ["nomsu environment"]: ()=> LuaCode("_ENV") - ["nomsu environment name"]: ()=> LuaCode('"_ENV"') - ["this file was run directly"]: => LuaCode('WAS_RUN_DIRECTLY') - ["the command line arguments"]: => LuaCode('COMMAND_LINE_ARGS') + ["is jit"]: (_t, code)=> LuaCode("jit") + ["Lua version"]: (_t, code)=> LuaCode("_VERSION") + ["nomsu environment"]: (_t)=> LuaCode("_ENV") + ["nomsu environment name"]: (_t)=> LuaCode('"_ENV"') + ["this file was run directly"]: (_t)=> LuaCode('WAS_RUN_DIRECTLY') + ["the command line arguments"]: (_t)=> LuaCode('COMMAND_LINE_ARGS') } return compile_actions diff --git a/lib/compatibility/4.10.12.7.nom b/lib/compatibility/4.10.12.7.nom index eeff2f2..be53cb6 100644 --- a/lib/compatibility/4.10.12.7.nom +++ b/lib/compatibility/4.10.12.7.nom @@ -63,10 +63,8 @@ upgrade $tree to "4.10.12.7" as: $i += 1 return --- (insert chunk) --- - [$chunk1, $chunk2] = [ - SyntaxTree {.type = "Block", .source = $first_chunk.source} - SyntaxTree {.type = "Block", .source = $first_chunk.source} - ] + [$chunk1, $chunk2] = + ["Block" tree from $first_chunk.source, "Block" tree from $first_chunk.source] for $j in 1 to ($i - 1): $chunk1.$j = $first_chunk.$j @@ -74,8 +72,7 @@ upgrade $tree to "4.10.12.7" as: for $j in $i to (size of $first_chunk): $chunk2.($j - $i + 1) = $first_chunk.$j - $new_tree = - SyntaxTree {.source = $tree.source, .type = "FileChunks"} $chunk1 $chunk2 + $new_tree = ("FileChunks" tree from $tree.source with $chunk1 $chunk2) for $i in 2 to (size of $tree): $new_tree.($i + 1) = $tree.$i diff --git a/lib/compatibility/4.11.nom b/lib/compatibility/4.11.nom index 053e1c8..e30734d 100644 --- a/lib/compatibility/4.11.nom +++ b/lib/compatibility/4.11.nom @@ -25,7 +25,7 @@ upgrade action "set" to "4.11" via for $entry in $tree.2 at $i: $lhs.$i = $entry.1 $rhs.$i = $entry.2 - return (SyntaxTree {.type = "Action", .source = $tree.source} $lhs "=" $rhs) + return ("Action" tree from $tree.source with $lhs "=" $rhs) upgrade action "1 with 2 ~>" to "4.11" via for $tree: diff --git a/lib/compatibility/6.14.nom b/lib/compatibility/6.14.nom index 0e742d0..b11474b 100644 --- a/lib/compatibility/6.14.nom +++ b/lib/compatibility/6.14.nom @@ -28,11 +28,11 @@ upgrade action (assume $assumption or barf $err) to "6.14" as upgrade action (barf $msg) to "6.14" as (fail $msg) upgrade action (\(1's meaning)).stub to "6.14" via - $tree -> (SyntaxTree {.source = $tree.source, .type = "Var", $tree.1}) + $tree -> ("Var" tree from $tree.source with $tree.1) upgrade action (log base $b of $n) to "6.14" as (log $n base $b) upgrade action "use" to "6.14" via for $tree: $path = $tree.2.1 $path = ($path, with "%.nom$" -> "") $path = ($path, with "^lib/" -> "") - return \(use (SyntaxTree {.source = $tree.2.source, .type = "Text"} $path)) + return \(use ("Text" tree from $tree.2.source with $path)) diff --git a/lib/compatibility/compatibility.nom b/lib/compatibility/compatibility.nom index 419f589..45ea1d6 100644 --- a/lib/compatibility/compatibility.nom +++ b/lib/compatibility/compatibility.nom @@ -43,7 +43,7 @@ external: ($t is syntax tree): $args = [] for $k = $v in $t: - if ((type of $k) == "number"): + if ((type of $k) == "a number"): $args, add (make tree $v) ..else: $args, add "\($k)=\(make tree $v)" diff --git a/lib/consolecolor/init.nom b/lib/consolecolor/init.nom index 19dc5ea..27823b8 100644 --- a/lib/consolecolor/init.nom +++ b/lib/consolecolor/init.nom @@ -18,9 +18,8 @@ $colors = { for $name = $colornum in $colors: $colornum = "\$colornum" - $(COMPILE RULES).$name = - for ($compile $text): - if $text: - return (Lua "('\\027[\($colornum)m'..\($text as lua expr)..'\\027[0m')") - ..else: - return (Lua "'\\027[\($colornum)m'") + \($name \$text) compiles to: + if $text: + return (Lua "('\\027[\($colornum)m'..\($text as lua expr)..'\\027[0m')") + ..else: + return (Lua "'\\027[\($colornum)m'") diff --git a/lib/core/errors.nom b/lib/core/errors.nom index 0b67400..8027228 100644 --- a/lib/core/errors.nom +++ b/lib/core/errors.nom @@ -8,14 +8,15 @@ use "core/control_flow" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -(fail $msg) compiles to - LuaCode - "at_1_fail(\(quote $msg.source), 'Failure: '..\($msg as lua expr))" - ..if $msg else "error('Failure', 0)" +(fail $msg) compiles to (" + at_1_fail(\(quote (this tree).source), 'Failure: \( + "'..\($msg as lua expr)" if $msg else "A failure was triggered here'" + )) +") (assume $condition) compiles to (" if not \($condition as lua expr) then - at_1_fail(\(quote "\($condition.source)"), "Assumption failed: This is not true.") + at_1_fail(\(quote "\($condition.source)"), "Assumption failed: This was not true.") end ") @@ -24,7 +25,7 @@ use "core/control_flow" local _a, _b = \($a as lua expr), \($b as lua expr) if _a ~= _b then at_1_fail(\(quote "\($a.source)"), - "Assumption failed: This value is "..tostring(_a)..", but it was supposed to be "..tostring(_b)..".") + "Assumption failed: This value was "..tostring(_a).." when it was supposed to be "..tostring(_b)..".") end end ") @@ -34,7 +35,7 @@ use "core/control_flow" local _a, _b = \($a as lua expr), \($b as lua expr) if _a == _b then at_1_fail(\(quote "\($a.source)"), - "Assumption failed: This value is "..tostring(_a)..", but it wasn't supposed to be.") + "Assumption failed: This value was "..tostring(_a).." when it wasn't supposed to be.") end end ") diff --git a/lib/core/metaprogramming.nom b/lib/core/metaprogramming.nom index 76ccf4a..bfcc0bf 100644 --- a/lib/core/metaprogramming.nom +++ b/lib/core/metaprogramming.nom @@ -16,13 +16,16 @@ lua> (" end end end - COMPILE_RULES["define mangler"] = function(\(nomsu environment)) + COMPILE_RULES["define mangler"] = function(\(nomsu environment), _tree) return LuaCode("local mangle = mangler()") end + COMPILE_RULES["this tree"] = function(\(nomsu environment), _tree) + return LuaCode("_tree") + end ") lua> (" - COMPILE_RULES["1 ->"] = function(\(nomsu environment), \$args, \$body) + COMPILE_RULES["1 ->"] = function(\(nomsu environment), _tree, \$args, \$body) if \$args and not \$body then \$args, \$body = {}, \$args end local body_lua = SyntaxTree:is_instance(\$body) and \(nomsu environment):compile(\$body) or \$body if SyntaxTree:is_instance(\$body) and \$body.type ~= "Block" then body_lua:prepend("return ") end @@ -41,7 +44,7 @@ lua> (" elseif not arg_lua:is_lua_id() then at_1_fail(SyntaxTree:is_instance(arg) and arg or nil, "Compile error: This does not compile to a Lua identifier, so it ".. - "can't be used as a function argument.".. + "can't be used as a function argument. ".. "Hint: This should probably be a Nomsu variable instead (like $x).") end lua:add(i > 1 and ", " or "", arg_lua) @@ -84,13 +87,29 @@ test: fail "compile to is leaking variables" lua> (" - COMPILE_RULES["1 compiles to"] = function(\(nomsu environment), \$action, \$body) - local \$args = List{"\(nomsu environment)", unpack(\$action:get_args())} + COMPILE_RULES["1 compiles to"] = function(\(nomsu environment), \(this tree), \$action, \$body) + local \$args = List{"\(nomsu environment)", "\(this tree)"} if \$body.type == "Text" then \$body = SyntaxTree{source=\$body.source, type="Action", "Lua", \$body} end - return LuaCode("COMPILE_RULES[", \$action:get_stub():as_lua(), - "] = ", \(\($args -> $body) as lua)) + if not (\$action.type == "Action" or (\$action.type == "EscapedNomsu" and \$action[1]\ + ...type == "Action")) then + at_1_fail(\$action.source, "Compile error: ".. + "This is neither an action nor an escaped action. ".. + "Hint: This should probably be an action like:\\n" + .."(foo $x) compiles to \\"(\\\\($x as lua) + 1)\\"") + end + if \$action.type == "EscapedNomsu" then + for _,a in ipairs(\$action[1]) do + if a.type == "EscapedNomsu" then \$args:add(a[1]) end + end + return LuaCode("COMPILE_RULES[", \($action as lua), ":get_stub()] = ", + \(\($args -> $body) as lua)) + else + for _,a in ipairs(\$action:get_args()) do \$args:add(a) end + return LuaCode("COMPILE_RULES[", \$action:get_stub():as_lua(), + "] = ", \(\($args -> $body) as lua)) + end end ") @@ -102,19 +121,19 @@ lua> (" at_1_fail(\$actions, "Compile error: This should be a list of actions.") end local lua = \(\($actions.1 compiles to $body) as lua) - local \$args = List{"\(nomsu environment)", unpack(\$actions[1]:get_args())} - local \$compiled_args = List{"\(nomsu environment)"}; - for i=2,#\$args do \$compiled_args[i] = \(nomsu environment):compile(\$args[i]) end + local \$args = List{"\(nomsu environment)", "\(this tree)", unpack(\$actions[1]:get_args())} + local \$compiled_args = List{"\(nomsu environment)", "\(this tree)"}; + for i=3,#\$args do \$compiled_args[i] = \(nomsu environment):compile(\$args[i]) end for i=2,#\$actions do local alias = \$actions[i] - local \$alias_args = List{"\(nomsu environment)", unpack(alias:get_args())} + local \$alias_args = List{"\(nomsu environment)", "\(this tree)", unpack(alias:get_args())} lua:add("\\nCOMPILE_RULES[", alias:get_stub():as_lua(), "] = ") if \$alias_args == \$args then lua:add("COMPILE_RULES[", \$actions[1]:get_stub():as_lua(), "]") else lua:add("function(") - local \$compiled_alias_args = List{"\(nomsu environment)"}; - for i=2,#\$alias_args do \$compiled_alias_args[i] = \(nomsu environment):compile(\$alias_args[i]) end + local \$compiled_alias_args = List{"\(nomsu environment)", "\(this tree)"}; + for i=3,#\$alias_args do \$compiled_alias_args[i] = \(nomsu environment):compile(\$alias_args[i]) end lua:concat_add(\$compiled_alias_args, ", ") lua:add(") return COMPILE_RULES[", \$actions[1]:get_stub():as_lua(), "](") lua:concat_add(\$compiled_args, ", ") @@ -152,7 +171,7 @@ test: lua:add(\$action:get_stub():as_lua_id()) lua:add_free_vars({\$action:get_stub():as_lua_id()}) else - at_1_fail(\$action, "Compile error: Expected an action or method call here") + at_1_fail(\$action, "Compile error: This is not an action or method call.") end lua:add(" = ", \(\($action -> $body) as lua), ";") return lua @@ -415,6 +434,7 @@ external: lua> (" local lua_type = \(lua type of $) if lua_type == 'string' then return 'Text' + elseif lua_type == 'nil' then return 'nil' elseif lua_type == 'table' or lua_type == 'userdata' then local mt = getmetatable(\$) if mt and mt.__type then return mt.__type end @@ -427,6 +447,17 @@ external: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +test: + assume ("Action" tree with "foo" ("Var" tree with "x")) == \(foo \$x) + +external: + ($type tree with (*extra arguments*)) means + SyntaxTree (=lua "{type=\$type, ...}") + ($type tree from $source) means + SyntaxTree (=lua "{type=\$type, source=\$source}") + ($type tree from $source with (*extra arguments*)) means + SyntaxTree (=lua "{type=\$type, source=\$source, ...}") + test: (foo) means: return 100 200 300 diff --git a/lib/core/things.nom b/lib/core/things.nom index 104c8d0..5f74b1a 100644 --- a/lib/core/things.nom +++ b/lib/core/things.nom @@ -101,8 +101,8 @@ external: $class_body with vars { : for $v in $vars: add ($v as lua expr, text) = - SyntaxTree {.type = "IndexChain"} (SyntaxTree {.type = "Var"} "self") - SyntaxTree {.type = "Index"} (SyntaxTree {.type = "Text"} $v.1) + "IndexChain" tree with ("Var" tree with "self") + "Index" tree with ("Text" tree with $v.1) } $lua = Lua (" diff --git a/lib/shell/init.nom b/lib/shell/init.nom index d58894e..13dde56 100644 --- a/lib/shell/init.nom +++ b/lib/shell/init.nom @@ -1,12 +1,26 @@ # This file defines some actions for running shell commands. - + external: - (=sh $cmd) means: - lua> (" - local result = io.popen(\$cmd) - local contents = result:read("*a") - result:close() - return contents - ") - $(sh> $) = $os.execute + (at $callsite =sh $cmd) means: + $f = ($io.popen $cmd) + $contents = ($f, read "*a") + [$ok, $return_type, $return] = ($f, close) + unless $ok: + if ($return_type == "exit"): + at $callsite fail "Command failure: Command `\$cmd` failed with exit code \$return" + ..else: + at $callsite fail "Command failure: Command `\$cmd` was terminated by signal \$return" + return $contents + + (at $callsite sh> $cmd) means: + [$ok, $return_type, $return] = ($os.execute $cmd) + unless $ok: + if ($return_type == "exit"): + at $callsite fail "Command failure: Command `\$cmd` failed with exit code \$return" + ..else: + at $callsite fail "Command failure: Command `\$cmd` was terminated by signal \$return" + + # Attach callsite information for better error reporting + (=sh $cmd) compiles to (\(at ("Text" tree with "\($cmd.source)") =sh $cmd) as lua) + (sh> $cmd) compiles to (\(at ("Text" tree with "\($cmd.source)") sh> $cmd) as lua) diff --git a/lib/tools/repl.nom b/lib/tools/repl.nom index 63d9e30..ea0cc8a 100755 --- a/lib/tools/repl.nom +++ b/lib/tools/repl.nom @@ -68,7 +68,7 @@ command line program with $args: $ret = (run $lua) ..if it fails with $err: say $err ..if it succeeds: - if (type of $ret) is: + if (lua type of $ret) is: "nil": do nothing diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua index c2502d8..542afe5 100644 --- a/nomsu_compiler.lua +++ b/nomsu_compiler.lua @@ -93,7 +93,7 @@ compile = function(self, tree) end args = _accum_0 end - local ret = compile_action(self, unpack(args)) + local ret = compile_action(self, tree, unpack(args)) if ret == nil then local info = debug.getinfo(compile_action, "S") local filename = Source:from_string(info.source).filename diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon index 0bb020c..e17d5e2 100644 --- a/nomsu_compiler.moon +++ b/nomsu_compiler.moon @@ -65,7 +65,7 @@ compile = (tree)=> args = [arg for arg in *tree when type(arg) != "string"] -- Force Lua to avoid tail call optimization for debugging purposes -- TODO: use tail call? - ret = compile_action(@, unpack(args)) + ret = compile_action(@, tree, unpack(args)) if ret == nil info = debug.getinfo(compile_action, "S") filename = Source\from_string(info.source).filename