Added tree back as a parameter to compile actions, which helps with

better error reporting, e.g. for (fail) (no arguments). Overall better
error reporting now. Also added shorthand ("Action" tree with ...) for
(SyntaxTree {.type = "Action", .1 = ...}).
This commit is contained in:
Bruce Hill 2019-01-18 14:22:17 -08:00
parent 520acd3979
commit 10bd72e858
14 changed files with 123 additions and 81 deletions

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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))

View File

@ -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)"

View File

@ -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'")

View File

@ -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
")

View File

@ -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

View File

@ -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 ("

View File

@ -2,11 +2,25 @@
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)

View File

@ -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

View File

@ -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

View File

@ -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