aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/control_flow.nom24
-rw-r--r--core/metaprogramming.nom93
-rw-r--r--lib/object.nom22
-rw-r--r--lib/object2.nom22
-rw-r--r--nomsu.lua243
-rwxr-xr-xnomsu.moon160
6 files changed, 363 insertions, 201 deletions
diff --git a/core/control_flow.nom b/core/control_flow.nom
index 315c4ef..4066a97 100644
--- a/core/control_flow.nom
+++ b/core/control_flow.nom
@@ -104,14 +104,14 @@ immediately:
%body_lua <- (%body as lua)
%body_statements <- ((%body_lua's "statements") or "\(%body_lua's "expr");")
if %body has subtree % where:
- ((%'s "type") = "FunctionCall") and ((%'s "stub") is "do next repeat")
+ ((%'s "type") = "FunctionCall") and ((%'s stub) is "do next repeat")
..: %body_statments +<- "\n::continue_repeat::;"
%code <- ".."
while \(%condition as lua expr) do
\%body_statements
end --while-loop
if %body has subtree % where:
- ((%'s "type") = "FunctionCall") and ((%'s "stub") is "stop repeating")
+ ((%'s "type") = "FunctionCall") and ((%'s stub) is "stop repeating")
..:
%code <- ".."
do -- scope of "stop repeating" label
@@ -128,14 +128,14 @@ immediately:
%body_lua <- (%body as lua)
%body_statements <- ((%body_lua's "statements") or "\(%body_lua's "expr");")
if %body has subtree % where
- ((%'s "type") = "FunctionCall") and ((%'s "stub") is "do next repeat")
+ ((%'s "type") = "FunctionCall") and ((%'s stub) is "do next repeat")
..: %body_statements +<- "\n::continue_repeat::;"
%code <- ".."
for i=1,\(%n as lua expr) do
\%body_statements
end --numeric for-loop
if %body has subtree % where:
- ((%'s "type") = "FunctionCall") and ((%'s "stub") is "stop repeating")
+ ((%'s "type") = "FunctionCall") and ((%'s stub) is "stop repeating")
..:
%code <- ".."
do -- scope of "stop repeating" label
@@ -161,7 +161,7 @@ immediately:
%body_statements <- ((%body_lua's "statements") or "\(%body_lua's "expr");")
if %body has subtree % where:
((%'s "type") = "FunctionCall") and
- ((%'s "stub") is "do next %") and
+ ((%'s stub) is "do next %") and
((3rd in (%'s "value"))'s "value") is (%var's "value")
..: %body_statements +<- "\n::continue_\(%var as lua identifier)::;"
@@ -174,7 +174,7 @@ immediately:
if %body has subtree % where:
((%'s "type") = "FunctionCall") and:
- ((%'s "stub") is "stop %") and:
+ ((%'s stub) is "stop %") and:
((2nd in (%'s "value"))'s "value") is (%var's "value")
..:
%code <- ".."
@@ -200,7 +200,7 @@ immediately:
%body_statements <- ((%body_lua's "statements") or "\(%body_lua's "expr");")
if %body has subtree % where:
((%'s "type") = "FunctionCall") and
- ((%'s "stub") is "do next %") and
+ ((%'s stub) is "do next %") and
((3rd in (%'s "value"))'s "value") is (%var's "value")
..: %body_statements +<- "\n::continue_\(%var as lua identifier)::;"
# This uses Lua's approach of only allowing loop-scoped variables in a loop
@@ -211,7 +211,7 @@ immediately:
end --foreach-loop
if %body has subtree % where:
((%'s "type") = "FunctionCall") and
- ((%'s "stub") is "stop %") and
+ ((%'s stub) is "stop %") and
((2nd in (%'s "value"))'s "value") is (%var's "value")
..:
%code <- ".."
@@ -230,13 +230,13 @@ immediately:
%body_statements <- ((%body_lua's "statements") or "\(%body_lua's "expr");")
if %body has subtree % where:
((%'s "type") = "FunctionCall") and
- ((%'s "stub") is "do next %") and
+ ((%'s stub) is "do next %") and
((3rd in (%'s "value"))'s "value") is (%key's "value")
..: %body_statements +<- "\n::continue_\(%key as lua identifier)::;"
if %body has subtree % where:
((%'s "type") = "FunctionCall") and
- ((%'s "stub") is "do next %") and
+ ((%'s stub) is "do next %") and
((3rd in (%'s "value"))'s "value") is (%value's "value")
..: %body_statements +<- "\n::continue_\(%value as lua identifier)::;"
@@ -251,13 +251,13 @@ immediately:
%stop_labels <- ""
if %body has subtree % where:
((%'s "type") = "FunctionCall") and
- ((%'s "stub") is "stop %") and
+ ((%'s stub) is "stop %") and
((2nd in (%'s "value"))'s "value") is (%key's "value")
..: %stop_labels +<- "\n::stop_\(%key as lua identifier)::;"
if %body has subtree % where:
((%'s "type") = "FunctionCall") and
- ((%'s "stub") is "stop %") and
+ ((%'s stub) is "stop %") and
((2nd in (%'s "value"))'s "value") is (%value's "value")
..: %stop_labels +<- "\n::stop_\(%value as lua identifier)::;"
diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom
index b56f0e9..fa589bd 100644
--- a/core/metaprogramming.nom
+++ b/core/metaprogramming.nom
@@ -6,12 +6,16 @@
immediately:
lua> ".."
nomsu:define_compile_action("compile %actions to %lua", \(!! code location !!), function(\%actions, \%lua)
- local signature = {};
- for i, action in ipairs(\%actions.value) do signature[i] = action:get_src(); end
- local stubs = nomsu:get_stubs_from_signature(signature);
- local stub_args = nomsu:get_args_from_signature(signature);
+ local stubs = {};
+ for i, action in ipairs(\%actions.value) do
+ stubs[i] = nomsu:tree_to_named_stub(action);
+ end
+ local args = {};
+ for i,tok in ipairs(\%actions.value[1].value) do
+ if tok.type == "Var" then args[#args+1] = nomsu:var_to_lua_identifier(tok.value); end
+ end
local arg_set = {};
- for i, arg in ipairs(stub_args[1]) do arg_set[arg] = true; end
+ for i, arg in ipairs(args) do arg_set[arg] = true; end
if \%lua.type == "Text" then
error("Invalid type for 'compile % to %', expected a dict with expr/statements, but got text.", 0);
end
@@ -26,11 +30,11 @@ immediately:
if #undeclared_locals > 0 then
body_code = "local "..table.concat(undeclared_locals, ", ")..";\\n"..body_code;
end
- local lua_fn_args = table.concat(stub_args[1], ", ");
- local def_tree = nomsu.compilestack[#nomsu.compilestack];
- local code_location = ("%s:%s,%s"):format(def_tree.filename, def_tree.start, def_tree.stop);
+ local lua_fn_args = table.concat(args, ", ");
+ local def_metadata = nomsu.tree_metadata[nomsu.compilestack[#nomsu.compilestack]];
+ local code_location = ("%s:%s,%s"):format(def_metadata.filename, def_metadata.start, def_metadata.stop);
return {statements=([[
- nomsu:define_compile_action(]]..repr(signature)..[[, ]]..repr(code_location)..[[, function(]]..lua_fn_args..[[)
+ nomsu:define_compile_action(]]..repr(stubs)..[[, ]]..repr(code_location)..[[, function(]]..lua_fn_args..[[)
]]..body_code.."\\n"..[[
end);
]])};
@@ -40,12 +44,16 @@ immediately:
immediately:
compile [action %actions %body] to:
lua> ".."
- local signature = {};
- for i, action in ipairs(\%actions.value) do signature[i] = action:get_src(); end
- local stubs = nomsu:get_stubs_from_signature(signature);
- local stub_args = nomsu:get_args_from_signature(signature);
+ local stubs = {};
+ for i, action in ipairs(\%actions.value) do
+ stubs[i] = nomsu:tree_to_named_stub(action);
+ end
+ local args = {};
+ for i,tok in ipairs(\%actions.value[1].value) do
+ if tok.type == "Var" then args[#args+1] = nomsu:var_to_lua_identifier(tok.value); end
+ end
local arg_set = {};
- for i, arg in ipairs(stub_args[1]) do arg_set[arg] = true; end
+ for i, arg in ipairs(args) do arg_set[arg] = true; end
local body_lua = nomsu:tree_to_lua(\%body);
local body_code = body_lua.statements or ("return "..body_lua.expr..";");
local undeclared_locals = {};
@@ -57,11 +65,12 @@ immediately:
if #undeclared_locals > 0 then
body_code = "local "..table.concat(undeclared_locals, ", ")..";\\n"..body_code;
end
- local lua_fn_args = table.concat(stub_args[1], ", ");
- local def_tree = nomsu.compilestack[#nomsu.compilestack];
- local code_location = ("%s:%s,%s"):format(def_tree.filename, def_tree.start, def_tree.stop);
+ local lua_fn_args = table.concat(args, ", ");
+ local def_metadata = nomsu.tree_metadata[nomsu.compilestack[#nomsu.compilestack]];
+ assert(def_metadata, "No metadata found for: "..tostring(nomsu.compilestack[#nomsu.compilestack]));
+ local code_location = ("%s:%s,%s"):format(def_metadata.filename, def_metadata.start, def_metadata.stop);
return {statements=[[
- nomsu:define_action(]]..repr(signature)..[[, ]]..repr(code_location)..[[, function(]]..lua_fn_args..[[)
+ nomsu:define_action(]]..repr(stubs)..[[, ]]..repr(code_location)..[[, function(]]..lua_fn_args..[[)
]]..body_code.."\\n"..[[
end);
]]};
@@ -70,27 +79,31 @@ immediately:
immediately:
compile [parse %shorthand as %longhand] to:
lua> ".."
- local signature = {};
- for i, action in ipairs(\%shorthand.value) do signature[i] = action:get_src(); end
- local stubs = nomsu:get_stubs_from_signature(signature);
- local stub_args = nomsu:get_args_from_signature(signature);
- local lua_fn_args = table.concat(stub_args[1], ", ");
+ local stubs = {};
+ for i, action in ipairs(\%shorthand.value) do
+ stubs[i] = nomsu:tree_to_named_stub(action);
+ end
+ local args = {};
+ for i,tok in ipairs(\%shorthand.value[1].value) do
+ if tok.type == "Var" then args[#args+1] = nomsu:var_to_lua_identifier(tok.value); end
+ end
+ local lua_fn_args = table.concat(args, ", ");
local template;
if \%longhand.type == "Block" then
local lines = {};
- for i, line in ipairs(\%longhand.value) do lines[i] = nomsu:dedent(line:get_src()); end
+ for i, line in ipairs(\%longhand.value) do lines[i] = nomsu:get_source_code(line); end
template = repr(table.concat(lines, "\\n"));
else
- template = repr(nomsu:dedent(\%longhand:get_src()));
+ template = repr(nomsu:get_source_code(\%longhand));
end
local replacements = {};
- for i, a in ipairs(stub_args[1]) do replacements[i] = a.."="..a; end
+ for i, a in ipairs(args) do replacements[i] = a.."="..a; end
replacements = "{"..table.concat(replacements, ", ").."}";
- local def_tree = nomsu.compilestack[#nomsu.compilestack];
- local code_location = ("%s:%s,%s"):format(def_tree.filename, def_tree.start, def_tree.stop);
+ local def_metadata = nomsu.tree_metadata[nomsu.compilestack[#nomsu.compilestack]];
+ local code_location = ("%s:%s,%s"):format(def_metadata.filename, def_metadata.start, def_metadata.stop);
return {statements=[[
- nomsu:define_compile_action(]]..repr(signature)..[[, ]]..repr(code_location)..[[, function(]]..lua_fn_args..[[)
- local template = nomsu:parse(]]..template..[[, ]]..repr(def_tree.filename)..[[);
+ nomsu:define_compile_action(]]..repr(stubs)..[[, ]]..repr(code_location)..[[, function(]]..lua_fn_args..[[)
+ local template = nomsu:parse(]]..template..[[, ]]..repr(def_metadata.filename)..[[);
local replacement = nomsu:tree_with_replaced_vars(template, ]]..replacements..[[);
return nomsu:tree_to_lua(replacement);
end);
@@ -99,7 +112,7 @@ immediately:
action [remove action %stub]:
lua> ".."
local fn = ACTIONS[\%stub];
- local metadata = ACTION_METADATA[fn];
+ local metadata = nomsu.action_metadata[fn];
for i=#metadata.aliases,1,-1 do
metadata.arg_orders[metadata.aliases[i]] = nil;
table.remove(metadata.aliases, i);
@@ -114,7 +127,7 @@ immediately:
lua> ".."
local lua = nomsu:tree_to_lua(\%tree);
if lua.locals or not lua.expr then
- error("Invalid thing to convert to lua expr: "..\%tree:get_src());
+ error("Invalid thing to convert to lua expr: "..nomsu:get_source_code(\%tree));
end
return lua.expr;
@@ -130,8 +143,11 @@ immediately:
action [%tree as value]:
=lua "nomsu:tree_to_value(\%tree)"
+ action [%tree's stub]:
+ =lua "nomsu:tree_to_stub(\%tree)"
+
immediately:
- compile [%tree's source code, %tree' source code] to {expr:"\(%tree as lua expr):get_src()"}
+ compile [%tree's source code, %tree' source code] to {expr:"nomsu:get_source_code(\(%tree as lua expr))"}
compile [repr %obj] to {expr:"repr(\(%obj as lua expr))"}
compile [type of %obj] to {expr:"type(\(%obj as lua expr))"}
@@ -141,7 +157,7 @@ immediately:
compile [%var as lua identifier] to {expr:"nomsu:var_to_lua_identifier(\(%var as lua expr))"}
action [action %names metadata]:
- =lua "ACTION_METADATA[ACTIONS[\%names]]"
+ =lua "nomsu.action_metadata[ACTIONS[\%names]]"
# Get the source code for a function
action [help %action]:
@@ -155,7 +171,12 @@ action [help %action]:
# Compiler tools
immediately:
- compile [run %code] to {expr: "nomsu:run(\(%code as lua expr), '\(!! code location !!)')"}
+ #local def_metadata = nomsu.tree_metadata[nomsu.compilestack[#nomsu.compilestack]];
+ compile [run %code] to {..}
+ expr: ".."
+ nomsu:run(\(%code as lua expr), '\
+ =lua "nomsu.tree_metadata[nomsu.compilestack[#nomsu.compilestack]].filename"
+ ..')
parse [enable debugging] as: lua> "nomsu.debug = true;"
parse [disable debugging] as: lua> "nomsu.debug = false;"
@@ -186,7 +207,7 @@ immediately:
compile [barf] to {statements:"error(nil, 0);"}
compile [barf %msg] to {statements:"error(\(%msg as lua expr), 0);"}
compile [assume %condition] to:
- lua> "local \%assumption = 'Assumption failed: '..\%condition:get_src();"
+ lua> "local \%assumption = 'Assumption failed: '..nomsu:get_source_code(\%condition);"
return {..}
statements:".."
if not \(%condition as lua expr) then
diff --git a/lib/object.nom b/lib/object.nom
index 2f2f3ff..ca664b5 100644
--- a/lib/object.nom
+++ b/lib/object.nom
@@ -33,17 +33,21 @@ compile [define object %classname %class_body] to:
for %line in (%class_body's "value"):
if: (%line's "type") is "Comment"
do next %line
- assume (((%line's "type") == "FunctionCall") and ((%line's "stub") == "action % %"))
+ assume (((%line's "type") == "FunctionCall") and ((%line's stub) == "action % %"))
..or barf "Only action definitions are supported inside 'define object % %', not \(%line's "src")"
%actions <- (2nd in (%line's "value"))
%body <- (3rd in (%line's "value"))
lua> ".."
- local signature = {};
- for i, action in ipairs(\%actions.value) do signature[i] = action:get_src(); end
- local stubs = nomsu:get_stubs_from_signature(signature);
- local stub_args = nomsu:get_args_from_signature(signature);
+ local stubs = {};
+ for i, action in ipairs(\%actions.value) do
+ stubs[i] = nomsu:tree_to_named_stub(action);
+ end
+ local args = {};
+ for i,tok in ipairs(\%actions.value[1].value) do
+ if tok.type == "Var" then args[#args+1] = nomsu:var_to_lua_identifier(tok.value); end
+ end
local arg_set = {};
- for i, arg in ipairs(stub_args[1]) do arg_set[arg] = true; end
+ for i, arg in ipairs(args) do arg_set[arg] = true; end
local body_lua = nomsu:tree_to_lua(\%body);
local body_code = body_lua.statements or ("return "..body_lua.expr..";");
local undeclared_locals = {};
@@ -55,12 +59,12 @@ compile [define object %classname %class_body] to:
if #undeclared_locals > 0 then
body_code = "local "..table.concat(undeclared_locals, ", ")..";\\n"..body_code;
end
- local lua_fn_args = table.concat(stub_args[1], ", ");
+ local lua_fn_args = table.concat(args, ", ");
local def_tree = nomsu.compilestack[#nomsu.compilestack];
local code_location = ("%s:%s,%s"):format(def_tree.filename, def_tree.start, def_tree.stop);
local compiled_args = {};
- for i, arg in ipairs(stub_args[1]) do
+ for i, arg in ipairs(args) do
compiled_args[i] = "nomsu:tree_to_lua("..arg..").expr";
end
compiled_args = table.concat(compiled_args, "..', '..");
@@ -75,7 +79,7 @@ compile [define object %classname %class_body] to:
]==]):format(
\%class_identifier, repr(stubs[1]), lua_fn_args,
body_code,
- repr(signature), repr(code_location), lua_fn_args,
+ repr(stubs), repr(code_location), lua_fn_args,
repr(repr(stubs[1])), compiled_args,
\%class_identifier, repr(stubs[1]), repr(stubs[1])));
diff --git a/lib/object2.nom b/lib/object2.nom
index d27bbc0..0e8c6fb 100644
--- a/lib/object2.nom
+++ b/lib/object2.nom
@@ -53,7 +53,7 @@ compile [define object %classname %class_body] to:
for %line in (%class_body's "value"):
if: (%line's "type") is "Comment"
do next %line
- if: ((%line's "type") is "FunctionCall") and ((%line's "stub") is "slots %")
+ if: ((%line's "type") is "FunctionCall") and ((%line's stub) is "slots %")
%slot_index_clauses <- []
%slot_newindex_clauses <- []
%slots <- ("value" in (2nd in (%line's "value")))
@@ -78,17 +78,21 @@ compile [define object %classname %class_body] to:
error("Attempt to store data in "..repr(key)..", which is not a valid slot on "..tostring(self.class));
end
do next %line
- assume (((%line's "type") is "FunctionCall") and ((%line's "stub") is "action % %"))
+ assume (((%line's "type") is "FunctionCall") and ((%line's stub) is "action % %"))
..or barf "Only action definitions are supported inside 'define object % %', not \(%line's "src")"
%actions <- (2nd in (%line's "value"))
%body <- (3rd in (%line's "value"))
lua> ".."
- local signature = {};
- for i, action in ipairs(\%actions.value) do signature[i] = action:get_src(); end
- local stubs = nomsu:get_stubs_from_signature(signature);
- local stub_args = nomsu:get_args_from_signature(signature);
+ local stubs = {};
+ for i, action in ipairs(\%actions.value) do
+ stubs[i] = nomsu:tree_to_named_stub(action);
+ end
+ local args = {};
+ for i,tok in ipairs(\%actions.value[1].value) do
+ if tok.type == "Var" then args[#args+1] = nomsu:var_to_lua_identifier(tok.value); end
+ end
local arg_set = {};
- for i, arg in ipairs(stub_args[1]) do arg_set[arg] = true; end
+ for i, arg in ipairs(args) do arg_set[arg] = true; end
local body_lua = nomsu:tree_to_lua(\%body);
local body_code = body_lua.statements or ("return "..body_lua.expr..";");
local undeclared_locals = {};
@@ -100,12 +104,12 @@ compile [define object %classname %class_body] to:
if #undeclared_locals > 0 then
body_code = "local "..table.concat(undeclared_locals, ", ")..";\\n"..body_code;
end
- local lua_fn_args = table.concat({"self", unpack(stub_args[1])}, ", ");
+ local lua_fn_args = table.concat({"self", unpack(args)}, ", ");
local def_tree = nomsu.compilestack[#nomsu.compilestack];
local code_location = ("%s:%s,%s"):format(def_tree.filename, def_tree.start, def_tree.stop);
local compiled_args = {};
- for i, arg in ipairs(stub_args[1]) do
+ for i, arg in ipairs(args) do
compiled_args[i] = "nomsu:tree_to_lua("..arg..").expr";
end
compiled_args = table.concat(compiled_args, "..', '..");
diff --git a/nomsu.lua b/nomsu.lua
index 82465d1..096bf9e 100644
--- a/nomsu.lua
+++ b/nomsu.lua
@@ -22,6 +22,18 @@ do
local _obj_0 = table
insert, remove, concat = _obj_0.insert, _obj_0.remove, _obj_0.concat
end
+local cached
+cached = function(fn)
+ local cache = setmetatable({ }, {
+ __mode = "k"
+ })
+ return function(self, arg)
+ if not (cache[arg]) then
+ cache[arg] = fn(self, arg)
+ end
+ return cache[arg]
+ end
+end
do
local STRING_METATABLE = getmetatable("")
STRING_METATABLE.__add = function(self, other)
@@ -119,44 +131,23 @@ do
err_msg = err_msg .. "\n" .. tostring(prev_line) .. "\n" .. tostring(err_line) .. "\n" .. tostring(pointer) .. "\n" .. tostring(next_line) .. "\n"
return error(err_msg)
end
- _with_0.FunctionCall = function(start, value, stop)
- local stub = concat((function()
- local _accum_0 = { }
- local _len_0 = 1
- for _index_0 = 1, #value do
- local t = value[_index_0]
- _accum_0[_len_0] = (t.type == "Word" and t.value or "%")
- _len_0 = _len_0 + 1
- end
- return _accum_0
- end)(), " ")
- local src = lpeg.userdata.source_code:sub(start, stop - 1)
- return {
- type = "FunctionCall",
- start = start,
- stop = stop,
- value = value,
- stub = stub,
- filename = lpeg.userdata.filename,
- get_line_no = lpeg.userdata.get_line_no,
- get_src = lpeg.userdata.get_src
- }
- end
NOMSU_DEFS = _with_0
end
setmetatable(NOMSU_DEFS, {
__index = function(self, key)
local make_node
make_node = function(start, value, stop)
- return {
+ local node = {
type = key,
+ value = value
+ }
+ lpeg.userdata.tree_metadata[node] = {
start = start,
stop = stop,
- value = value,
filename = lpeg.userdata.filename,
- get_src = lpeg.userdata.get_src,
- get_line_no = lpeg.userdata.get_line_no
+ source_code = lpeg.userdata.source_code
}
+ return node
end
self[key] = make_node
return make_node
@@ -233,7 +224,7 @@ do
arg_orders[stub] = arg_positions
end
end
- self.environment.ACTION_METADATA[fn] = {
+ self.action_metadata[fn] = {
fn = fn,
source = source,
aliases = stubs,
@@ -244,7 +235,7 @@ do
end,
define_compile_action = function(self, signature, source, fn, src)
self:define_action(signature, source, fn)
- self.environment.ACTION_METADATA[fn].compile_time = true
+ self.action_metadata[fn].compile_time = true
end,
serialize_defs = function(self, scope, after)
if scope == nil then
@@ -301,36 +292,53 @@ do
end
return code:gsub("\n", "\n" .. (" "):rep(levels))
end,
+ get_line_number = cached(function(self, tree)
+ local metadata = self.tree_metadata[tree]
+ if not (metadata) then
+ error("Failed to find metatdata for tree: " .. tostring(tree), 0)
+ end
+ if not (self.file_metadata[metadata.filename]) then
+ error("Failed to find file metatdata for file: " .. tostring(metadata.filename), 0)
+ end
+ local line_starts = self.file_metadata[metadata.filename].line_starts
+ local first_line = 1
+ while first_line < #line_starts and line_starts[first_line + 1] < metadata.start do
+ first_line = first_line + 1
+ end
+ local last_line = first_line
+ while last_line < #line_starts and line_starts[last_line + 1] < metadata.stop do
+ last_line = last_line + 1
+ end
+ return tostring(metadata.filename) .. ":" .. tostring(first_line)
+ end),
+ get_source_code = function(self, tree)
+ local metadata = self.tree_metadata[tree]
+ if not (metadata) then
+ return self:tree_to_nomsu(tree)
+ end
+ return self:dedent(metadata.source_code:sub(metadata.start, metadata.stop - 1))
+ end,
parse = function(self, nomsu_code, filename)
assert(type(filename) == "string", "Bad filename type: " .. tostring(type(filename)))
if self.debug then
print(tostring(colored.bright("PARSING:")) .. "\n" .. tostring(colored.yellow(nomsu_code)))
end
- local userdata
- do
- local _with_0 = {
+ if not (self.file_metadata[filename]) then
+ self.file_metadata[filename] = {
source_code = nomsu_code,
filename = filename,
- indent_stack = {
- ""
- }
+ line_starts = line_counter:match(nomsu_code)
}
- _with_0.get_src = function(self)
- return nomsu_code:sub(self.start, self.stop - 1)
- end
- _with_0.line_starts = line_counter:match(_with_0.source_code)
- _with_0.get_line_no = function(self)
- if not (self._line_no) then
- local line_no = 1
- while line_no < #_with_0.line_starts and _with_0.line_starts[line_no + 1] < self.start do
- line_no = line_no + 1
- end
- self._line_no = tostring(_with_0.filename) .. ":" .. tostring(line_no)
- end
- return self._line_no
- end
- userdata = _with_0
end
+ local userdata = {
+ source_code = nomsu_code,
+ filename = filename,
+ indent_stack = {
+ ""
+ },
+ tree_metadata = self.tree_metadata,
+ line_starts = self.file_metadata[filename].line_starts
+ }
local old_userdata
old_userdata, lpeg.userdata = lpeg.userdata, userdata
local tree = NOMSU:match(nomsu_code)
@@ -789,7 +797,10 @@ do
for _index_0 = 1, #_list_0 do
local line = _list_0[_index_0]
nomsu = expression(line)
- assert(nomsu, "Failed to produce output for:\n" .. tostring(colored.yellow(line:get_src())))
+ if not (nomsu) then
+ local src = self:get_source_code(line)
+ error("Failed to produce output for:\n" .. tostring(colored.yellow(src)), 0)
+ end
insert(lines, nomsu)
end
return concat(lines, "\n")
@@ -853,6 +864,9 @@ do
if not tree.type then
error("Invalid tree: " .. tostring(repr(tree)), 0)
end
+ if not (self.tree_metadata[tree]) then
+ error("??? tree: " .. tostring(repr(tree)), 0)
+ end
local _exp_0 = tree.type
if "File" == _exp_0 then
if #tree.value == 1 then
@@ -906,7 +920,7 @@ do
}
elseif "Nomsu" == _exp_0 then
return {
- expr = "nomsu:parse(" .. tostring(repr(tree.value:get_src())) .. ", " .. tostring(repr(tree:get_line_no())) .. ").value[1]"
+ expr = "nomsu:parse(" .. tostring(repr(self:get_source_code(tree.value))) .. ", " .. tostring(repr(self:get_line_number(tree.value))) .. ").value[1]"
}
elseif "Block" == _exp_0 then
local lua_bits = { }
@@ -941,13 +955,14 @@ do
}
elseif "FunctionCall" == _exp_0 then
insert(self.compilestack, tree)
+ local stub = self:tree_to_stub(tree)
local ok, fn = pcall(function()
- return self.environment.ACTIONS[tree.stub]
+ return self.environment.ACTIONS[stub]
end)
if not ok then
fn = nil
end
- local metadata = self.environment.ACTION_METADATA[fn]
+ local metadata = self.action_metadata[fn]
if metadata and metadata.compile_time then
local args
do
@@ -968,7 +983,7 @@ do
do
local _accum_0 = { }
local _len_0 = 1
- local _list_0 = metadata.arg_orders[tree.stub]
+ local _list_0 = metadata.arg_orders[stub]
for _index_0 = 1, #_list_0 do
local p = _list_0[_index_0]
_accum_0[_len_0] = args[p]
@@ -979,22 +994,22 @@ do
args = new_args
end
if self.debug then
- print(tostring(colored.bright("RUNNING MACRO")) .. " " .. tostring(colored.underscore(colored.magenta(tree.stub))) .. " ")
- print(tostring(colored.bright("WITH ARGS:")) .. " " .. tostring(colored.dim(repr((function()
+ print(tostring(colored.bright("RUNNING MACRO")) .. " " .. tostring(colored.underscore(colored.magenta(stub))) .. " ")
+ print(tostring(colored.bright("WITH ARGS:")) .. " " .. tostring(colored.dim(concat((function()
local _accum_0 = { }
local _len_0 = 1
for _index_0 = 1, #args do
local a = args[_index_0]
- _accum_0[_len_0] = (repr(a)):sub(1, 50)
+ _accum_0[_len_0] = (repr(a)):sub(1, 100)
_len_0 = _len_0 + 1
end
return _accum_0
- end)()))))
+ end)(), ", "))))
end
local lua = fn(unpack(args))
remove(self.compilestack)
return lua
- elseif not metadata and self.__class.math_patt:match(tree.stub) then
+ elseif not metadata and self.__class.math_patt:match(stub) then
local bits = { }
local _list_0 = tree.value
for _index_0 = 1, #_list_0 do
@@ -1003,7 +1018,10 @@ do
insert(bits, tok.value)
else
local lua = self:tree_to_lua(tok)
- assert(lua.expr, "non-expression value inside math expression: " .. tostring(tok:get_src()))
+ if not (lua.expr) then
+ local src = self:get_source_code(tok)
+ error("non-expression value inside math expression: " .. tostring(colored.yellow(src)))
+ end
insert(bits, lua.expr)
end
end
@@ -1023,7 +1041,11 @@ do
break
end
local lua = self:tree_to_lua(tok)
- assert(lua.expr, tostring(tree:get_line_no()) .. ": Cannot use:\n" .. tostring(colored.yellow(tok:get_src())) .. "\nas an argument to " .. tostring(tree.stub) .. ", since it's not an expression, it produces: " .. tostring(repr(lua)))
+ if not (lua.expr) then
+ local line = self:get_line_number(tok)
+ local src = self:get_source_code(tok)
+ error(tostring(line) .. ": Cannot use:\n" .. tostring(colored.yellow(src)) .. "\nas an argument to " .. tostring(stub) .. ", since it's not an expression, it produces: " .. tostring(repr(lua)), 0)
+ end
insert(args, lua.expr)
_continue_0 = true
until true
@@ -1036,7 +1058,7 @@ do
do
local _accum_0 = { }
local _len_0 = 1
- local _list_1 = metadata.arg_orders[tree.stub]
+ local _list_1 = metadata.arg_orders[stub]
for _index_0 = 1, #_list_1 do
local p = _list_1[_index_0]
_accum_0[_len_0] = args[p]
@@ -1048,7 +1070,7 @@ do
end
remove(self.compilestack)
return {
- expr = self.__class:comma_separated_items("ACTIONS[" .. tostring(repr(tree.stub)) .. "](", args, ")")
+ expr = self.__class:comma_separated_items("ACTIONS[" .. tostring(repr(stub)) .. "](", args, ")")
}
elseif "Text" == _exp_0 then
local concat_parts = { }
@@ -1073,7 +1095,11 @@ do
self:print_tree(bit)
print(tostring(colored.bright("EXPR:")) .. " " .. tostring(lua.expr) .. ", " .. tostring(colored.bright("STATEMENT:")) .. " " .. tostring(lua.statements))
end
- assert(lua.expr, "Cannot use [[" .. tostring(bit:get_src()) .. "]] as a string interpolation value, since it's not an expression.")
+ if not (lua.expr) then
+ local line = self:get_line_number(bit)
+ local src = self:get_source_code(bit)
+ error(tostring(line) .. ": Cannot use " .. tostring(colored.yellow(bit)) .. " as a string interpolation value, since it's not an expression.", 0)
+ end
insert(concat_parts, "stringify(" .. tostring(lua.expr) .. ")")
_continue_0 = true
until true
@@ -1103,7 +1129,11 @@ do
for _index_0 = 1, #_list_0 do
local item = _list_0[_index_0]
local lua = self:tree_to_lua(item)
- assert(lua.expr, "Cannot use [[" .. tostring(item:get_src()) .. "]] as a list item, since it's not an expression.")
+ if not (lua.expr) then
+ local line = self:get_line_number(item)
+ local src = self:get_source_code(item)
+ error(tostring(line) .. ": Cannot use " .. tostring(colored.yellow(src)) .. " as a list item, since it's not an expression.", 0)
+ end
insert(items, lua.expr)
end
return {
@@ -1122,9 +1152,17 @@ do
else
key_lua = self:tree_to_lua(entry.dict_key)
end
- assert(key_lua.expr, "Cannot use [[" .. tostring(entry.dict_key:get_src()) .. "]] as a dict key, since it's not an expression.")
+ if not (key_lua.expr) then
+ local line = self:get_line_number(entry.dict_key)
+ local src = self:get_source_code(entry.dict_key)
+ error(tostring(line) .. ": Cannot use " .. tostring(colored.yellow(src)) .. " as a dict key, since it's not an expression.", 0)
+ end
local value_lua = self:tree_to_lua(entry.dict_value)
- assert(value_lua.expr, "Cannot use [[" .. tostring(entry.dict_value:get_src()) .. "]] as a dict value, since it's not an expression.")
+ if not (value_lua.expr) then
+ local line = self:get_line_number(entry.dict_value)
+ local src = self:get_source_code(entry.dict_value)
+ error(tostring(line) .. ": Cannot use " .. tostring(colored.yellow(src)) .. " as a dict value, since it's not an expression.", 0)
+ end
local key_str = key_lua.expr:match([=[["']([a-zA-Z_][a-zA-Z0-9_]*)['"]]=])
if key_str then
insert(items, tostring(key_str) .. "=" .. tostring(value_lua.expr))
@@ -1215,13 +1253,16 @@ do
elseif "File" == _exp_0 or "Nomsu" == _exp_0 or "Block" == _exp_0 or "List" == _exp_0 or "FunctionCall" == _exp_0 or "Text" == _exp_0 then
local new_value = self:tree_with_replaced_vars(tree.value, replacements)
if new_value ~= tree.value then
+ local new_tree
do
local _tbl_0 = { }
for k, v in pairs(tree) do
_tbl_0[k] = v
end
- tree = _tbl_0
+ new_tree = _tbl_0
end
+ self.tree_metadata[new_tree] = self.tree_metadata[tree]
+ tree = new_tree
tree.value = new_value
end
elseif "Dict" == _exp_0 then
@@ -1237,13 +1278,16 @@ do
}
end
if dirty then
+ local new_tree
do
local _tbl_0 = { }
for k, v in pairs(tree) do
_tbl_0[k] = v
end
- tree = _tbl_0
+ new_tree = _tbl_0
end
+ self.tree_metadata[new_tree] = self.tree_metadata[tree]
+ tree = new_tree
tree.value = replacements
end
elseif nil == _exp_0 then
@@ -1259,6 +1303,38 @@ do
end
return tree
end,
+ tree_to_stub = cached(function(self, tree)
+ if tree.type ~= "FunctionCall" then
+ error("Tried to get stub from non-functioncall tree: " .. tostring(tree.type), 0)
+ end
+ return concat((function()
+ local _accum_0 = { }
+ local _len_0 = 1
+ local _list_0 = tree.value
+ for _index_0 = 1, #_list_0 do
+ local t = _list_0[_index_0]
+ _accum_0[_len_0] = (t.type == "Word" and t.value or "%")
+ _len_0 = _len_0 + 1
+ end
+ return _accum_0
+ end)(), " ")
+ end),
+ tree_to_named_stub = cached(function(self, tree)
+ if tree.type ~= "FunctionCall" then
+ error("Tried to get stub from non-functioncall tree: " .. tostring(tree.type), 0)
+ end
+ return concat((function()
+ local _accum_0 = { }
+ local _len_0 = 1
+ local _list_0 = tree.value
+ for _index_0 = 1, #_list_0 do
+ local t = _list_0[_index_0]
+ _accum_0[_len_0] = (t.type == "Word" and t.value or "%" .. tostring(t.value))
+ _len_0 = _len_0 + 1
+ end
+ return _accum_0
+ end)(), " ")
+ end),
get_stubs_from_signature = function(self, signature)
if type(signature) ~= 'table' or signature.type then
error("Invalid signature: " .. tostring(repr(signature)), 0)
@@ -1307,12 +1383,6 @@ do
end
end))
end,
- source_code = function(self, level)
- if level == nil then
- level = 0
- end
- return self:dedent(self.compilestack[#self.compilestack - level]:get_src())
- end,
initialize_core = function(self)
local get_line_no
get_line_no = function()
@@ -1330,7 +1400,9 @@ do
else
local lua = nomsu:tree_to_lua(bit)
if not (lua.expr) then
- error("Cannot use [[" .. tostring(bit:get_src()) .. "]] as a string interpolation value, since it's not an expression.", 0)
+ local line = self:get_line_number(bit)
+ local src = self:get_source_code(bit)
+ error(tostring(line) .. ": Cannot use " .. tostring(colored.yellow(src)) .. " as a string interpolation value, since it's not an expression.", 0)
end
insert(concat_parts, lua.expr)
end
@@ -1369,8 +1441,9 @@ do
end)
self:define_compile_action("!! code location !!", get_line_no(), function()
local tree = nomsu.compilestack[#nomsu.compilestack - 1]
+ local metadata = self.tree_metadata[tree]
return {
- expr = repr(tostring(tree.filename) .. ":" .. tostring(tree.start) .. "," .. tostring(tree.stop))
+ expr = repr(tostring(metadata.filename) .. ":" .. tostring(metadata.start) .. "," .. tostring(metadata.stop))
}
end)
self:define_action("run file %filename", get_line_no(), function(_filename)
@@ -1405,6 +1478,15 @@ do
})
self.use_stack = { }
self.compilestack = { }
+ self.file_metadata = setmetatable({ }, {
+ __mode = "k"
+ })
+ self.tree_metadata = setmetatable({ }, {
+ __mode = "k"
+ })
+ self.action_metadata = setmetatable({ }, {
+ __mode = "k"
+ })
self.debug = false
self.environment = {
nomsu = self,
@@ -1455,9 +1537,6 @@ do
return error("Attempt to run undefined action: " .. tostring(key), 0)
end
})
- self.environment.ACTION_METADATA = setmetatable({ }, {
- __mode = "k"
- })
self.environment.LOADED = { }
return self:initialize_core()
end,
@@ -1623,7 +1702,7 @@ if arg and debug.getinfo(2).func ~= require then
end
local line = nil
do
- local metadata = nomsu.environment.ACTION_METADATA[calling_fn.func]
+ local metadata = nomsu.action_metadata[calling_fn.func]
if metadata then
local filename, start, stop = metadata.source:match("([^:]*):([0-9]*),([0-9]*)")
if filename then
diff --git a/nomsu.moon b/nomsu.moon
index ce4e5e2..10e57c4 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -20,6 +20,13 @@ colors = setmetatable({}, {__index:->""})
colored = setmetatable({}, {__index:(_,color)-> ((msg)-> colors[color]..(msg or '')..colors.reset)})
{:insert, :remove, :concat} = table
+cached = (fn)->
+ cache = setmetatable({}, {__mode:"k"})
+ return (self, arg)->
+ unless cache[arg]
+ cache[arg] = fn(self, arg)
+ return cache[arg]
+
-- Use + operator for string coercive concatenation (note: "asdf" + 3 == "asdf3")
-- Use [] for accessing string characters, or s[{3,4}] for s:sub(3,4)
-- Note: This globally affects all strings in this instance of Lua!
@@ -107,20 +114,13 @@ NOMSU_DEFS = with {}
err_msg ..="\n#{prev_line}\n#{err_line}\n#{pointer}\n#{next_line}\n"
error(err_msg)
- .FunctionCall = (start, value, stop)->
- stub = concat([(t.type == "Word" and t.value or "%") for t in *value], " ")
- src = lpeg.userdata.source_code\sub(start,stop-1)
- return {
- type: "FunctionCall", :start, :stop, :value, :stub, filename:lpeg.userdata.filename,
- get_line_no:lpeg.userdata.get_line_no, get_src:lpeg.userdata.get_src,
- }
-
setmetatable(NOMSU_DEFS, {__index:(key)=>
make_node = (start, value, stop)->
- {
- type: key, :start, :stop, :value, filename:lpeg.userdata.filename,
- get_src:lpeg.userdata.get_src, get_line_no:lpeg.userdata.get_line_no,
+ node = {type: key, :value}
+ lpeg.userdata.tree_metadata[node] = {
+ :start,:stop,filename:lpeg.userdata.filename,source_code:lpeg.userdata.source_code
}
+ return node
self[key] = make_node
return make_node
})
@@ -157,6 +157,9 @@ class NomsuCompiler
})
@use_stack = {}
@compilestack = {}
+ @file_metadata = setmetatable({}, {__mode:"k"})
+ @tree_metadata = setmetatable({}, {__mode:"k"})
+ @action_metadata = setmetatable({}, {__mode:"k"})
@debug = false
@environment = {
@@ -172,7 +175,6 @@ class NomsuCompiler
@environment.ACTIONS = setmetatable({}, {__index:(key)=>
error("Attempt to run undefined action: #{key}", 0)
})
- @environment.ACTION_METADATA = setmetatable({}, {__mode:"k"})
@environment.LOADED = {}
@initialize_core!
@@ -205,14 +207,14 @@ class NomsuCompiler
error("Mismatch in args between lua function's #{repr fn_arg_positions} and stub's #{repr args} for #{repr stub}", 0)
arg_orders[stub] = arg_positions
- @environment.ACTION_METADATA[fn] = {
+ @action_metadata[fn] = {
:fn, :source, aliases:stubs, :arg_orders,
arg_positions:fn_arg_positions, def_number:@@def_number,
}
define_compile_action: (signature, source, fn, src)=>
@define_action(signature, source, fn)
- @environment.ACTION_METADATA[fn].compile_time = true
+ @action_metadata[fn].compile_time = true
serialize_defs: (scope=nil, after=nil)=>
-- TODO: repair
@@ -239,6 +241,30 @@ class NomsuCompiler
indent: (code, levels=1)=>
return code\gsub("\n","\n"..(" ")\rep(levels))
+ get_line_number: cached (tree)=>
+ metadata = @tree_metadata[tree]
+ unless metadata
+ error "Failed to find metatdata for tree: #{tree}", 0
+ unless @file_metadata[metadata.filename]
+ error "Failed to find file metatdata for file: #{metadata.filename}", 0
+ line_starts = @file_metadata[metadata.filename].line_starts
+ first_line = 1
+ while first_line < #line_starts and line_starts[first_line+1] < metadata.start
+ first_line += 1
+ last_line = first_line
+ while last_line < #line_starts and line_starts[last_line+1] < metadata.stop
+ last_line += 1
+ --return first_line == last_line and "#{metadata.filename}:#{first_line}" or "#{metadata.filename}:#{first_line}-#{last_line}"
+ return "#{metadata.filename}:#{first_line}"
+
+ get_source_code: (tree)=>
+ -- Return the (dedented) source code of a tree, or construct some if the tree was
+ -- dynamically generated.
+ metadata = @tree_metadata[tree]
+ unless metadata
+ return @tree_to_nomsu(tree)
+ return @dedent metadata.source_code\sub(metadata.start, metadata.stop-1)
+
line_counter = re.compile([[
lines <- {| line (%nl line)* |}
line <- {} (!%nl .)*
@@ -248,16 +274,14 @@ class NomsuCompiler
if @debug
print "#{colored.bright "PARSING:"}\n#{colored.yellow nomsu_code}"
- userdata = with {source_code:nomsu_code, :filename, indent_stack: {""}}
- .get_src = => nomsu_code\sub(@start, @stop-1)
- .line_starts = line_counter\match(.source_code)
- .get_line_no = =>
- unless @_line_no
- line_no = 1
- while line_no < #.line_starts and .line_starts[line_no+1] < @start
- line_no += 1
- @_line_no = "#{.filename}:#{line_no}"
- return @_line_no
+ unless @file_metadata[filename]
+ @file_metadata[filename] = {
+ source_code:nomsu_code, :filename, line_starts:line_counter\match(nomsu_code)
+ }
+ userdata = {
+ source_code:nomsu_code, :filename, indent_stack: {""}, tree_metadata:@tree_metadata,
+ line_starts:@file_metadata[filename].line_starts,
+ }
old_userdata, lpeg.userdata = lpeg.userdata, userdata
tree = NOMSU\match(nomsu_code)
@@ -569,7 +593,9 @@ class NomsuCompiler
lines = {}
for line in *tree.value
nomsu = expression(line)
- assert nomsu, "Failed to produce output for:\n#{colored.yellow line\get_src!}"
+ unless nomsu
+ src = @get_source_code line
+ error "Failed to produce output for:\n#{colored.yellow src}", 0
insert lines, nomsu
return concat lines, "\n"
@@ -614,6 +640,8 @@ class NomsuCompiler
assert tree, "No tree provided."
if not tree.type
error("Invalid tree: #{repr(tree)}", 0)
+ unless @tree_metadata[tree]
+ error "??? tree: #{repr tree}", 0
switch tree.type
when "File"
if #tree.value == 1
@@ -638,7 +666,7 @@ class NomsuCompiler
return statements:"--"..tree.value\gsub("\n","\n--")
when "Nomsu"
- return expr:"nomsu:parse(#{repr tree.value\get_src!}, #{repr tree\get_line_no!}).value[1]"
+ return expr:"nomsu:parse(#{repr @get_source_code(tree.value)}, #{repr @get_line_number(tree.value)}).value[1]"
when "Block"
lua_bits = {}
@@ -657,22 +685,23 @@ class NomsuCompiler
when "FunctionCall"
insert @compilestack, tree
- ok, fn = pcall(-> @environment.ACTIONS[tree.stub])
+ stub = @tree_to_stub tree
+ ok, fn = pcall(-> @environment.ACTIONS[stub])
if not ok then fn = nil
- metadata = @environment.ACTION_METADATA[fn]
+ metadata = @action_metadata[fn]
if metadata and metadata.compile_time
args = [arg for arg in *tree.value when arg.type != "Word"]
if metadata and metadata.arg_orders
- new_args = [args[p] for p in *metadata.arg_orders[tree.stub]]
+ new_args = [args[p] for p in *metadata.arg_orders[stub]]
args = new_args
if @debug
- print "#{colored.bright "RUNNING MACRO"} #{colored.underscore colored.magenta(tree.stub)} "
- print "#{colored.bright "WITH ARGS:"} #{colored.dim repr [(repr a)\sub(1,50) for a in *args]}"
+ print "#{colored.bright "RUNNING MACRO"} #{colored.underscore colored.magenta(stub)} "
+ print "#{colored.bright "WITH ARGS:"} #{colored.dim concat([(repr a)\sub(1,100) for a in *args], ", ")}"
lua = fn(unpack(args))
remove @compilestack
return lua
- elseif not metadata and @@math_patt\match(tree.stub)
+ elseif not metadata and @@math_patt\match(stub)
-- This is a bit of a hack, but this code handles arbitrarily complex
-- math expressions like 2*x + 3^2 without having to define a single
-- action for every possibility.
@@ -682,7 +711,9 @@ class NomsuCompiler
insert bits, tok.value
else
lua = @tree_to_lua(tok)
- assert(lua.expr, "non-expression value inside math expression: #{tok\get_src!}")
+ unless lua.expr
+ src = @get_source_code(tok)
+ error("non-expression value inside math expression: #{colored.yellow src}")
insert bits, lua.expr
remove @compilestack
return expr:"(#{concat bits, " "})"
@@ -691,16 +722,18 @@ class NomsuCompiler
for tok in *tree.value
if tok.type == "Word" then continue
lua = @tree_to_lua(tok)
- assert lua.expr,
- "#{tree\get_line_no!}: Cannot use:\n#{colored.yellow tok\get_src!}\nas an argument to #{tree.stub}, since it's not an expression, it produces: #{repr lua}"
+ unless lua.expr
+ line = @get_line_number(tok)
+ src = @get_source_code(tok)
+ error "#{line}: Cannot use:\n#{colored.yellow src}\nas an argument to #{stub}, since it's not an expression, it produces: #{repr lua}", 0
insert args, lua.expr
if metadata and metadata.arg_orders
- new_args = [args[p] for p in *metadata.arg_orders[tree.stub]]
+ new_args = [args[p] for p in *metadata.arg_orders[stub]]
args = new_args
remove @compilestack
- return expr:@@comma_separated_items("ACTIONS[#{repr tree.stub}](", args, ")")
+ return expr:@@comma_separated_items("ACTIONS[#{repr stub}](", args, ")")
when "Text"
concat_parts = {}
@@ -717,8 +750,10 @@ class NomsuCompiler
print(colored.bright "INTERP:")
@print_tree bit
print "#{colored.bright "EXPR:"} #{lua.expr}, #{colored.bright "STATEMENT:"} #{lua.statements}"
- assert lua.expr,
- "Cannot use [[#{bit\get_src!}]] as a string interpolation value, since it's not an expression."
+ unless lua.expr
+ line = @get_line_number(bit)
+ src = @get_source_code(bit)
+ error "#{line}: Cannot use #{colored.yellow bit} as a string interpolation value, since it's not an expression.", 0
insert concat_parts, "stringify(#{lua.expr})"
if string_buffer ~= ""
@@ -734,8 +769,10 @@ class NomsuCompiler
items = {}
for item in *tree.value
lua = @tree_to_lua item
- assert lua.expr,
- "Cannot use [[#{item\get_src!}]] as a list item, since it's not an expression."
+ unless lua.expr
+ line = @get_line_number(item)
+ src = @get_source_code(item)
+ error "#{line}: Cannot use #{colored.yellow src} as a list item, since it's not an expression.", 0
insert items, lua.expr
return expr:@@comma_separated_items("{", items, "}")
@@ -746,11 +783,15 @@ class NomsuCompiler
{expr:repr(entry.dict_key.value)}
else
@tree_to_lua entry.dict_key
- assert key_lua.expr,
- "Cannot use [[#{entry.dict_key\get_src!}]] as a dict key, since it's not an expression."
+ unless key_lua.expr
+ line = @get_line_number(entry.dict_key)
+ src = @get_source_code(entry.dict_key)
+ error "#{line}: Cannot use #{colored.yellow src} as a dict key, since it's not an expression.", 0
value_lua = @tree_to_lua entry.dict_value
- assert value_lua.expr,
- "Cannot use [[#{entry.dict_value\get_src!}]] as a dict value, since it's not an expression."
+ unless value_lua.expr
+ line = @get_line_number(entry.dict_value)
+ src = @get_source_code(entry.dict_value)
+ error "#{line}: Cannot use #{colored.yellow src} as a dict value, since it's not an expression.", 0
key_str = key_lua.expr\match([=[["']([a-zA-Z_][a-zA-Z0-9_]*)['"]]=])
if key_str
insert items, "#{key_str}=#{value_lua.expr}"
@@ -828,7 +869,10 @@ class NomsuCompiler
when "File", "Nomsu", "Block", "List", "FunctionCall", "Text"
new_value = @tree_with_replaced_vars tree.value, replacements
if new_value != tree.value
- tree = {k,v for k,v in pairs(tree)}
+ new_tree = {k,v for k,v in pairs(tree)}
+ -- TODO: Maybe generate new metadata?
+ @tree_metadata[new_tree] = @tree_metadata[tree]
+ tree = new_tree
tree.value = new_value
when "Dict"
dirty = false
@@ -839,7 +883,10 @@ class NomsuCompiler
dirty or= new_key != e.dict_key or new_value != e.dict_value
replacements[i] = {dict_key:new_key, dict_value:new_value}
if dirty
- tree = {k,v for k,v in pairs(tree)}
+ new_tree = {k,v for k,v in pairs(tree)}
+ -- TODO: Maybe generate new metadata?
+ @tree_metadata[new_tree] = @tree_metadata[tree]
+ tree = new_tree
tree.value = replacements
when nil -- Raw table, probably from one of the .value of a multi-value tree (e.g. List)
new_values = {}
@@ -851,6 +898,13 @@ class NomsuCompiler
tree = new_values
return tree
+ tree_to_stub: cached (tree)=>
+ if tree.type != "FunctionCall" then error "Tried to get stub from non-functioncall tree: #{tree.type}", 0
+ return concat([(t.type == "Word" and t.value or "%") for t in *tree.value], " ")
+
+ tree_to_named_stub: cached (tree)=>
+ if tree.type != "FunctionCall" then error "Tried to get stub from non-functioncall tree: #{tree.type}", 0
+ return concat([(t.type == "Word" and t.value or "%#{t.value}") for t in *tree.value], " ")
stub_defs = {
space:(P(' ') + P('\n..'))^0
@@ -893,9 +947,6 @@ class NomsuCompiler
"_"..(var\gsub "%W", (verboten)->
if verboten == "_" then "__" else ("_%x")\format(verboten\byte!))
- source_code: (level=0)=>
- @dedent @compilestack[#@compilestack-level]\get_src!
-
initialize_core: =>
-- Sets up some core functionality
get_line_no = -> "nomsu.moon:#{debug.getinfo(2).currentline}"
@@ -908,7 +959,9 @@ class NomsuCompiler
else
lua = nomsu\tree_to_lua bit
unless lua.expr
- error("Cannot use [[#{bit\get_src!}]] as a string interpolation value, since it's not an expression.", 0)
+ line = @get_line_number(bit)
+ src = @get_source_code(bit)
+ error "#{line}: Cannot use #{colored.yellow src} as a string interpolation value, since it's not an expression.", 0
insert concat_parts, lua.expr
return concat(concat_parts)
@@ -933,7 +986,8 @@ class NomsuCompiler
@define_compile_action "!! code location !!", get_line_no!, ->
tree = nomsu.compilestack[#nomsu.compilestack-1]
- return expr: repr("#{tree.filename}:#{tree.start},#{tree.stop}")
+ metadata = @tree_metadata[tree]
+ return expr: repr("#{metadata.filename}:#{metadata.start},#{metadata.stop}")
@define_action "run file %filename", get_line_no!, (_filename)->
return nomsu\run_file(_filename)
@@ -1035,7 +1089,7 @@ if arg and debug.getinfo(2).func != require
name = calling_fn.name
if name == "run_lua_fn" then continue
line = nil
- if metadata = nomsu.environment.ACTION_METADATA[calling_fn.func]
+ if metadata = nomsu.action_metadata[calling_fn.func]
filename, start, stop = metadata.source\match("([^:]*):([0-9]*),([0-9]*)")
if filename
file = io.open(filename)\read("*a")