Pretty much mostly working.
This commit is contained in:
parent
09b64e0341
commit
53a9d4eae8
@ -105,14 +105,13 @@ compile [%expression for %item in %iterable] to:
|
||||
assert ((%item's "type") == "Var") ".."
|
||||
List comprehension has the wrong type for the loop variable. Expected Var, but got: \(%item's "type")
|
||||
return ".."
|
||||
(function(nomsu, vars);
|
||||
(function(nomsu);
|
||||
local comprehension = {};
|
||||
for i,item in ipairs(\(%iterable as lua)) do;
|
||||
\(%item as lua) = item;
|
||||
for i,\(%item as lua) in ipairs(\(%iterable as lua)) do;
|
||||
comprehension[i] = \(%expression as lua);
|
||||
end;
|
||||
return comprehension;
|
||||
end)(nomsu, setmetatable({}, {__index=vars}))
|
||||
end)(nomsu)
|
||||
parse [%expression for all %iterable] as: %expression for % in %iterable
|
||||
|
||||
compile [%expression for %key = %value in %iterable] to:
|
||||
@ -121,14 +120,13 @@ compile [%expression for %key = %value in %iterable] to:
|
||||
assert ((%value's "type") == "Var") ".."
|
||||
List comprehension has the wrong type for the value loop variable. Expected Var, but got: \(%value's "type")
|
||||
return ".."
|
||||
(function(nomsu, vars);
|
||||
(function(nomsu);
|
||||
local comprehension = {};
|
||||
for key,value in pairs(\(%iterable as lua)) do;
|
||||
\(%key as lua), \(%value as lua) = key, value;
|
||||
for \(%key as lua), \(%value as lua) in pairs(\(%iterable as lua)) do;
|
||||
comprehension[i] = \(%expression as lua);
|
||||
end;
|
||||
return comprehension;
|
||||
end)(nomsu, setmetatable({}, {__index=vars}))
|
||||
end)(nomsu)
|
||||
|
||||
rule [%items sorted] =:
|
||||
%copy = (% for all %items)
|
||||
@ -166,14 +164,13 @@ compile [%key = %value for %item in %iterable] to:
|
||||
assert ((%item's "type") == "Var") ".."
|
||||
Dict comprehension has the wrong type for the loop variable. Expected Var, but got: \(%item's "type")
|
||||
return ".."
|
||||
(function(nomsu, vars);
|
||||
(function(nomsu);
|
||||
local comprehension = {};
|
||||
for i,value in ipairs(\(%iterable as lua)) do;
|
||||
\(%item as lua) = value;
|
||||
for i,\(%item as lua) in ipairs(\(%iterable as lua)) do;
|
||||
comprehension[\(%key as lua)] = \(%value as lua);
|
||||
end;
|
||||
return comprehension;
|
||||
end)(nomsu, setmetatable({}, {__index=vars}))
|
||||
end)(nomsu)
|
||||
parse [%key = %value for all %iterable] as: %key = %value for % in %iterable
|
||||
|
||||
compile [%key = %value for %src_key = %src_value in %iterable] to:
|
||||
@ -182,12 +179,11 @@ compile [%key = %value for %src_key = %src_value in %iterable] to:
|
||||
assert ((%src_value's "type") == "Var") ".."
|
||||
Dict comprehension has the wrong type for the value loop variable. Expected Var, but got: \(%src_value's "type")
|
||||
return ".."
|
||||
(function(nomsu, vars);
|
||||
(function(nomsu);
|
||||
local comprehension = {};
|
||||
for key,value in pairs(\(%iterable as lua)) do;
|
||||
\(%src_key as lua), \(%src_value as lua) = key, value;
|
||||
for \(%src_key as lua), \(%src_value as lua) in pairs(\(%iterable as lua)) do;
|
||||
comprehension[\(%key as lua)] = \(%value as lua);
|
||||
end;
|
||||
return comprehension;
|
||||
end)(nomsu, setmetatable({}, {__index=vars}))
|
||||
end)(nomsu)
|
||||
|
||||
|
@ -91,6 +91,7 @@ immediately:
|
||||
for %var from %start to %stop by %step %body
|
||||
for %var from %start to %stop via %step %body
|
||||
..to code:
|
||||
lua> "local \%continue_labels, \%code, \%stop_labels"
|
||||
%continue_labels = ""
|
||||
if (tree %body has function call \(do next for-loop)):
|
||||
%continue_labels join= "\n::continue_for::;"
|
||||
@ -126,6 +127,7 @@ immediately:
|
||||
|
||||
immediately:
|
||||
compile [for %var in %iterable %body] to code:
|
||||
lua> "local \%continue_labels, \%stop_labels, \%code, \%stop_labels"
|
||||
%continue_labels = ""
|
||||
if (tree %body has function call \(do next for-loop)):
|
||||
%continue_labels join= "\n::continue_for::;"
|
||||
@ -143,12 +145,12 @@ immediately:
|
||||
%stop_labels join= "\n::stop_for::;"
|
||||
if (tree %body has function call (tree \(stop %) with {""=%var})):
|
||||
%stop_labels join= "\n::stop_\(nomsu "var_to_lua_identifier" [%var])::;"
|
||||
return (..)
|
||||
".."
|
||||
if %stop_labels != "":
|
||||
%code = ".."
|
||||
do --for-loop label scope
|
||||
\%code\%stop_labels
|
||||
end --for-loop label scope
|
||||
..if %stop_labels != "" else %code
|
||||
return %code
|
||||
parse [for all %iterable %body] as: for % in %iterable %body
|
||||
|
||||
# Dict iteration (lua's "pairs()")
|
||||
@ -186,10 +188,12 @@ immediately:
|
||||
# Switch statement/multi-branch if
|
||||
immediately:
|
||||
compile [when %body] to code:
|
||||
lua> "local \%result, \%fallthroughs, \%first"
|
||||
%result = ""
|
||||
%fallthroughs = []
|
||||
%first = (yes)
|
||||
for %func_call in (%body's "value"):
|
||||
lua> "local \%tokens, \%star, \%condition, \%action"
|
||||
assert ((%func_call's "type") == "FunctionCall") ".."
|
||||
Invalid format for 'when' statement. Only '*' blocks are allowed.
|
||||
%tokens = (%func_call's "value")
|
||||
@ -286,10 +290,10 @@ immediately:
|
||||
..to code: ".."
|
||||
do
|
||||
local fell_through = false;
|
||||
local ok, ret1, ret2 = pcall(function(nomsu, vars)
|
||||
local ok, ret1, ret2 = pcall(function(nomsu)
|
||||
\(%action as lua statements)
|
||||
fell_through = true;
|
||||
end, nomsu, vars);
|
||||
end, nomsu);
|
||||
if ok then
|
||||
\(%success as lua statements)
|
||||
end
|
||||
@ -313,13 +317,13 @@ immediately:
|
||||
compile [do %action then always %final_action] to code: ".."
|
||||
do
|
||||
local fell_through = false;
|
||||
local ok, ret1, ret2 = pcall(function(nomsu, vars)
|
||||
local ok, ret1, ret2 = pcall(function(nomsu)
|
||||
\(%action as lua statements)
|
||||
fell_through = true;
|
||||
end, nomsu, vars);
|
||||
local ok2, _ = pcall(function(nomsu, vars)
|
||||
end, nomsu);
|
||||
local ok2, _ = pcall(function(nomsu)
|
||||
\(%final_action as lua statements)
|
||||
end, nomsu, vars);
|
||||
end, nomsu);
|
||||
if not ok then nomsu:error(ret1); end
|
||||
if not ok2 then nomsu:error(ret2); end
|
||||
if not fell_through then
|
||||
|
@ -5,53 +5,59 @@
|
||||
# Rule to make macros:
|
||||
immediately:
|
||||
lua> ".."
|
||||
nomsu:defmacro("compile %macro_def to %body", function(nomsu, vars)
|
||||
nomsu.parse_spec = function(nomsu, spec)
|
||||
local signature = {};
|
||||
for i, alias in ipairs(spec.value) do
|
||||
signature[i] = alias.src;
|
||||
end
|
||||
local _, arg_names, _ = nomsu:get_stub(spec.value[1]);
|
||||
local args = {"nomsu"};
|
||||
for i, a in ipairs(arg_names) do args[i+1] = "_"..nomsu:var_to_lua_identifier(a); end
|
||||
signature, args = nomsu:repr(signature), table.concat(args, ", ");
|
||||
return signature, args;
|
||||
end
|
||||
|
||||
immediately:
|
||||
lua> ".."
|
||||
nomsu:defmacro("compile %macro_def to %body", function(nomsu, \%macro_def, \%body)
|
||||
nomsu:assert(\%macro_def.type == "List",
|
||||
"Invalid type for compile definition signature. Expected List, but got: "..tostring(\%macro_def.type));
|
||||
nomsu:assert(\%body.type == "Block",
|
||||
"Invalid type for compile definition body. Expected Block, but got: "..tostring(\%body.type));
|
||||
local signature = {};
|
||||
for i, alias in ipairs(\%macro_def.value) do
|
||||
signature[i] = alias.src;
|
||||
end
|
||||
local signature, args = nomsu:parse_spec(\%macro_def);
|
||||
local body_lua = nomsu:tree_to_lua(\%body);
|
||||
body_lua = body_lua.statements or ("return "..body_lua.expr..";");
|
||||
local lua = ([[
|
||||
do
|
||||
local function macro(nomsu, vars)
|
||||
local function macro(%s)
|
||||
%s
|
||||
end
|
||||
local function macro_wrapper(...) return {expr=macro(...)}; end
|
||||
nomsu:defmacro(%s, macro_wrapper, %s);
|
||||
end]]):format(body_lua, nomsu:repr(signature), nomsu:repr(("compile %s\\n..to code %s"):format(\%macro_def.src, \%body.src)));
|
||||
end]]):format(args, body_lua, signature, nomsu:repr(("compile %s\\n..to code %s"):format(\%macro_def.src, \%body.src)));
|
||||
return {statements=lua};
|
||||
end, \(__src__ 1));
|
||||
|
||||
lua> ".."
|
||||
nomsu:defmacro("compile %macro_def to code %body", function(nomsu, vars)
|
||||
nomsu:defmacro("compile %macro_def to code %body", function(nomsu, \%macro_def, \%body)
|
||||
nomsu:assert(\%macro_def.type == "List",
|
||||
"Invalid type for compile definition signature. Expected List, but got: "..tostring(\%macro_def.type));
|
||||
nomsu:assert(\%body.type == "Block",
|
||||
"Invalid type for compile definition body. Expected Block, but got: "..tostring(\%body.type));
|
||||
local signature = {};
|
||||
for i, alias in ipairs(\%macro_def.value) do
|
||||
signature[i] = alias.src;
|
||||
end
|
||||
local signature, args = nomsu:parse_spec(\%macro_def);
|
||||
local body_lua = nomsu:tree_to_lua(\%body);
|
||||
body_lua = body_lua.statements or ("return "..body_lua.expr..";");
|
||||
local lua = ([[
|
||||
do
|
||||
local function macro(nomsu, vars)
|
||||
local function macro(%s)
|
||||
%s
|
||||
end
|
||||
local function macro_wrapper(...) return {statements=macro(...)}; end
|
||||
nomsu:defmacro(%s, macro_wrapper, %s);
|
||||
end]]):format(body_lua, nomsu:repr(signature), nomsu:repr(("compile %s\\n..to code %s"):format(\%macro_def.src, \%body.src)));
|
||||
end]]):format(args, body_lua, signature, nomsu:repr(("compile %s\\n..to code %s"):format(\%macro_def.src, \%body.src)));
|
||||
return {statements=lua};
|
||||
end, \(__src__ 1));
|
||||
|
||||
compile [rand] to: "math.random()"
|
||||
|
||||
# Rule to make rules:
|
||||
immediately:
|
||||
compile [rule %signature = %body] to code:
|
||||
@ -60,43 +66,41 @@ immediately:
|
||||
"Invalid type for rule definition signature. Expected List, but got: "..tostring(\%signature.type));
|
||||
nomsu:assert(\%body.type == "Block",
|
||||
"Invalid type for rule definition body. Expected Block, but got: "..tostring(\%body.type));
|
||||
local signature = {};
|
||||
for i, alias in ipairs(\%signature.value) do
|
||||
signature[i] = alias.src;
|
||||
end
|
||||
local signature, args = nomsu:parse_spec(\%signature);
|
||||
local body_lua = nomsu:tree_to_lua(\%body);
|
||||
body_lua = body_lua.statements or ("return "..body_lua.expr..";");
|
||||
local src = nomsu:dedent(nomsu:source_code(0));
|
||||
local def_lua = ([[
|
||||
nomsu:def(%s, function(nomsu, vars)
|
||||
nomsu:def(%s, function(%s)
|
||||
%s
|
||||
end, %s);]]):format(nomsu:repr(signature), body_lua, nomsu:repr(src));
|
||||
end, %s);]]):format(signature, args, body_lua, nomsu:repr(src));
|
||||
return def_lua;
|
||||
|
||||
# Rule to make nomsu macros:
|
||||
immediately:
|
||||
lua> ".."
|
||||
nomsu:defmacro("parse %shorthand as %longhand", (function(nomsu, vars)
|
||||
nomsu:defmacro("parse %shorthand as %longhand", (function(nomsu, \%shorthand, \%longhand)
|
||||
nomsu:assert(\%shorthand.type == "List",
|
||||
"Invalid type for parse definition signature. Expected List, but got: "..tostring(\%shorthand.type));
|
||||
nomsu:assert(\%longhand.type == "Block",
|
||||
"Invalid type for parse definition body. Expected Block, but got: "..tostring(\%longhand.type));
|
||||
local signature = {};
|
||||
for i, alias in ipairs(\%shorthand.value) do
|
||||
signature[i] = alias.src;
|
||||
end
|
||||
local signature, args = nomsu:parse_spec(\%shorthand);
|
||||
local template = {};
|
||||
for i, line in ipairs(\%longhand.value) do
|
||||
template[i] = nomsu:dedent(line.src);
|
||||
end
|
||||
signature, template = nomsu:repr(signature), nomsu:repr(table.concat(template, "\\n"));
|
||||
return {expr=([[
|
||||
nomsu:defmacro(%s, (function(nomsu, vars)
|
||||
template = nomsu:repr(table.concat(template, "\\n"));
|
||||
local _, arg_names, _ = nomsu:get_stub(\%shorthand.value[1]);
|
||||
local replacements = {};
|
||||
for i, a in ipairs(arg_names) do replacements[i] = "["..nomsu:repr(a).."]=_"..nomsu:var_to_lua_identifier(a); end
|
||||
replacements = "{"..table.concat(replacements, ", ").."}";
|
||||
local lua_code = ([[
|
||||
nomsu:defmacro(%s, (function(%s)
|
||||
local template = nomsu:parse(%s, %s);
|
||||
if #template.value == 1 then template = template.value[1]; end
|
||||
local replacement = nomsu:replaced_vars(template, vars);
|
||||
local replacement = nomsu:replaced_vars(template, %s);
|
||||
return nomsu:tree_to_lua(replacement);
|
||||
end), %s)]]):format(signature, template, nomsu:repr(\%shorthand.line_no), nomsu:repr(nomsu:source_code(0)))};
|
||||
end), %s)]]):format(signature, args, template, nomsu:repr(\%shorthand:get_line_no()), replacements, nomsu:repr(nomsu:source_code(0)));
|
||||
return {statements=lua_code};
|
||||
end), \(__src__ 1));
|
||||
|
||||
rule [remove rule %stub] =:
|
||||
@ -114,7 +118,7 @@ immediately:
|
||||
local lua = nomsu:tree_to_lua(\%tree);
|
||||
return lua.statements or (lua.expr..";");
|
||||
rule [%tree as value] =:
|
||||
=lua "nomsu:tree_to_value(\%tree, vars)"
|
||||
=lua "nomsu:tree_to_value(\%tree)"
|
||||
compile [repr %obj] to:
|
||||
"nomsu:repr(\(%obj as lua))"
|
||||
compile [indented %obj] to:
|
||||
@ -124,12 +128,14 @@ immediately:
|
||||
compile [type %obj, type of %obj] to:
|
||||
"type(\(%obj as lua))"
|
||||
|
||||
parse [lua do> %block] as:
|
||||
lua> "do"
|
||||
lua> %block
|
||||
lua> "end"
|
||||
immediately:
|
||||
parse [lua do> %block] as:
|
||||
lua> "do"
|
||||
lua> %block
|
||||
lua> "end"
|
||||
|
||||
compile [nomsu] to: "nomsu"
|
||||
|
||||
compile [nomsu's %key] to: "nomsu[\(%key as lua)]"
|
||||
compile [nomsu %method %args] to: "nomsu[\(%method as lua)](nomsu, unpack(\(%args as lua)))"
|
||||
compile [tree %tree with %replacements] to: ".."
|
||||
|
@ -20,13 +20,13 @@ compile [..]
|
||||
%when_false_expr unless %condition else %when_true_expr
|
||||
%when_false_expr unless %condition then %when_true_expr
|
||||
..to: ".."
|
||||
(function(nomsu, vars)
|
||||
if \(%condition as lua) then
|
||||
(function(nomsu, condition)
|
||||
if condition then
|
||||
return \(%when_true_expr as lua);
|
||||
else
|
||||
return \(%when_false_expr as lua);
|
||||
end
|
||||
end)(nomsu, vars)
|
||||
end)(nomsu, \(%condition as lua))
|
||||
parse [..]
|
||||
%true if %x == %y else %false, %true if %x == %y otherwise %false
|
||||
%false unless %x == %y else %true, %false unless %x == %y otherwise %true
|
||||
|
@ -13,6 +13,8 @@ compile [str %] to: "tostring(\(% as lua))"
|
||||
compile [scope] to: "nomsu.defs"
|
||||
compile [parent scope] to: "getmetatable(nomsu.defs).__index"
|
||||
|
||||
# TODO: fix this file
|
||||
return
|
||||
compile [using %scoped do %actions] to code: ".."
|
||||
do
|
||||
local old_scope, old_vars = nomsu.defs, vars;
|
||||
|
@ -7,7 +7,7 @@ rule [error %msg] =:
|
||||
nomsu "error"[%msg]
|
||||
compile [assert %condition %msg] to code: ".."
|
||||
if not (\(%condition as lua)) then
|
||||
nomsu:error(\(%msg as lua))
|
||||
nomsu:error(\(%msg as lua));
|
||||
end
|
||||
|
||||
parse [assert %condition] as: assert %condition (nil)
|
||||
@ -80,19 +80,17 @@ compile [min of %items, smallest of %items, lowest of %items] to:
|
||||
compile [max of %items, biggest of %items, largest of %items, highest of %items] to:
|
||||
"nomsu.utils.max(\(%items as lua))"
|
||||
compile [min of %items by %value_expr] to: ".."
|
||||
nomsu.utils.min(\(%items as lua), function(item)
|
||||
local vars = setmetatable({['']=item}, {__index=vars})
|
||||
nomsu.utils.min(\(%items as lua), function(\(\% as lua))
|
||||
return \(%value_expr as lua)
|
||||
end)
|
||||
compile [max of %items by %value_expr] to: ".."
|
||||
nomsu.utils.max(\(%items as lua), function(item)
|
||||
local vars = setmetatable({['']=item}, {__index=vars})
|
||||
nomsu.utils.max(\(%items as lua), function(\(\% as lua))
|
||||
return \(%value_expr as lua)
|
||||
end)
|
||||
compile [sort %items] to: "table.sort(\(%items as lua))"
|
||||
rule [sort %items by %key] =: =lua ".."
|
||||
nomsu.utils.sort(\%items, function(x)
|
||||
return (\%key)(nomsu, {['']=x});
|
||||
compile [sort %items by %key_expr] to: ".."
|
||||
nomsu.utils.sort(\(%items as lua), function(\(\% as lua))
|
||||
return \(%key_expr as lua);
|
||||
end)
|
||||
|
||||
# String utilities
|
||||
|
@ -11,7 +11,7 @@ compile [say %str] to:
|
||||
|
||||
compile [do %action] to code:
|
||||
(%action as lua statements) if ((%action's "type") == "Thunk")
|
||||
..else "(\(%action as lua))(nomsu, vars);"
|
||||
..else "(\(%action as lua))(nomsu);"
|
||||
|
||||
# With statement
|
||||
compile [with %assignments %action] to code:
|
||||
@ -33,10 +33,10 @@ compile [with %assignments %action] to code:
|
||||
do
|
||||
\%setup
|
||||
local fell_through = false;
|
||||
local ok, ret1, ret2 = pcall(function(nomsu, vars)
|
||||
local ok, ret1, ret2 = pcall(function(nomsu)
|
||||
\(%action as lua statements);
|
||||
fell_through = true;
|
||||
end, nomsu, vars);
|
||||
end, nomsu);
|
||||
\(join ("\((%->"var") as lua) = old_value\(%->"i");" for all %data) with glue "\n ")
|
||||
if not ok then nomsu:error(ret1); end
|
||||
if not fell_through then
|
||||
|
210
nomsu.lua
210
nomsu.lua
@ -126,15 +126,13 @@ do
|
||||
end
|
||||
return _accum_0
|
||||
end)(), " ")
|
||||
local line_no = 1
|
||||
while (ctx.line_starts[line_no + 1] or math.huge) < start do
|
||||
line_no = line_no + 1
|
||||
end
|
||||
local src = ctx.source_code:sub(start, stop - 1)
|
||||
return {
|
||||
start = start,
|
||||
stop = stop,
|
||||
type = "FunctionCall",
|
||||
src = src,
|
||||
line_no = tostring(ctx.filename) .. ":" .. tostring(line_no),
|
||||
get_line_no = ctx.get_line_no,
|
||||
value = value,
|
||||
stub = stub
|
||||
}
|
||||
@ -149,6 +147,7 @@ do
|
||||
stop = stop,
|
||||
value = value,
|
||||
src = ctx.source_code:sub(start, stop - 1),
|
||||
get_line_no = ctx.get_line_no,
|
||||
type = key
|
||||
}
|
||||
end
|
||||
@ -168,15 +167,26 @@ do
|
||||
local nomsu = peg_tidier:match(io.open("nomsu.peg"):read("*a"))
|
||||
nomsu = re.compile(nomsu, defs)
|
||||
parse = function(source_code, filename)
|
||||
local old_ctx = ctx
|
||||
ctx = {
|
||||
local _ctx = {
|
||||
source_code = source_code,
|
||||
filename = filename,
|
||||
indent_stack = {
|
||||
0
|
||||
}
|
||||
}
|
||||
ctx.line_starts = re.compile("lines <- {| line ('\n' line)* |} line <- {} [^\n]*"):match(source_code)
|
||||
_ctx.line_starts = re.compile("lines <- {| line ('\n' line)* |} line <- {} [^\n]*"):match(source_code)
|
||||
_ctx.get_line_no = function(self)
|
||||
if not (self._line_no) then
|
||||
local line_no = 1
|
||||
while (_ctx.line_starts[line_no + 1] or math.huge) < self.start do
|
||||
line_no = line_no + 1
|
||||
end
|
||||
self._line_no = tostring(_ctx.filename) .. ":" .. tostring(line_no)
|
||||
end
|
||||
return self._line_no
|
||||
end
|
||||
local old_ctx = ctx
|
||||
ctx = _ctx
|
||||
local tree = nomsu:match(source_code)
|
||||
ctx = old_ctx
|
||||
return tree
|
||||
@ -206,8 +216,6 @@ do
|
||||
signature = self:get_stubs(signature)
|
||||
end
|
||||
self:assert(type(fn) == 'function', "Bad fn: " .. tostring(repr(fn)))
|
||||
local canonical_args = nil
|
||||
local canonical_escaped_args = nil
|
||||
local aliases = { }
|
||||
self.__class.def_number = self.__class.def_number + 1
|
||||
local def = {
|
||||
@ -221,6 +229,7 @@ do
|
||||
local where_defs_go = (getmetatable(self.defs) or { }).__newindex or self.defs
|
||||
for sig_i = 1, #signature do
|
||||
local stub, arg_names, escaped_args = unpack(signature[sig_i])
|
||||
local arg_positions = { }
|
||||
self:assert(stub, "NO STUB FOUND: " .. tostring(repr(signature)))
|
||||
if self.debug then
|
||||
self:writeln(tostring(colored.bright("DEFINING RULE:")) .. " " .. tostring(colored.underscore(colored.magenta(repr(stub)))) .. " " .. tostring(colored.bright("WITH ARGS")) .. " " .. tostring(colored.dim(repr(arg_names))))
|
||||
@ -232,22 +241,34 @@ do
|
||||
end
|
||||
end
|
||||
end
|
||||
if canonical_args then
|
||||
self:assert(equivalent(set(arg_names), canonical_args), "Mismatched args")
|
||||
else
|
||||
canonical_args = set(arg_names)
|
||||
end
|
||||
if canonical_escaped_args then
|
||||
self:assert(equivalent(escaped_args, canonical_escaped_args), "Mismatched escaped args")
|
||||
else
|
||||
canonical_escaped_args = escaped_args
|
||||
if sig_i == 1 then
|
||||
do
|
||||
local _accum_0 = { }
|
||||
local _len_0 = 1
|
||||
for i = 1, #arg_names do
|
||||
_accum_0[_len_0] = i
|
||||
_len_0 = _len_0 + 1
|
||||
end
|
||||
arg_positions = _accum_0
|
||||
end
|
||||
def.args = arg_names
|
||||
def.escaped_args = escaped_args
|
||||
else
|
||||
self:assert(equivalent(set(def.args), set(arg_names)), "Mismatched args")
|
||||
self:assert(equivalent(def.escaped_args, escaped_args), "Mismatched escaped args")
|
||||
for j, a in ipairs(arg_names) do
|
||||
for i, c_a in ipairs(def.args) do
|
||||
if a == c_a then
|
||||
arg_positions[j] = i
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
insert(def.aliases, stub)
|
||||
local stub_def = setmetatable({
|
||||
stub = stub,
|
||||
arg_names = arg_names,
|
||||
escaped_args = escaped_args
|
||||
arg_positions = arg_positions
|
||||
}, {
|
||||
__index = def
|
||||
})
|
||||
@ -361,27 +382,30 @@ do
|
||||
if not (def.is_macro) then
|
||||
self:assert_permission(stub)
|
||||
end
|
||||
local fn, arg_names
|
||||
fn, arg_names = def.fn, def.arg_names
|
||||
local fn, arg_positions
|
||||
fn, arg_positions = def.fn, def.arg_positions
|
||||
local args
|
||||
do
|
||||
local _tbl_0 = { }
|
||||
for i, name in ipairs(arg_names) do
|
||||
_tbl_0[name] = select(i, ...)
|
||||
local _accum_0 = { }
|
||||
local _len_0 = 1
|
||||
for _index_0 = 1, #arg_positions do
|
||||
local p = arg_positions[_index_0]
|
||||
_accum_0[_len_0] = select(p, ...)
|
||||
_len_0 = _len_0 + 1
|
||||
end
|
||||
args = _tbl_0
|
||||
args = _accum_0
|
||||
end
|
||||
if self.debug then
|
||||
self:write(tostring(colored.bright("CALLING")) .. " " .. tostring(colored.magenta(colored.underscore(stub))) .. " ")
|
||||
self:writeln(tostring(colored.bright("WITH ARGS:")))
|
||||
for name, value in pairs(args) do
|
||||
self:writeln(" " .. tostring(colored.bright("* " .. tostring(name))) .. " = " .. tostring(colored.dim(repr(value))))
|
||||
for i, value in ipairs(args) do
|
||||
self:writeln(" " .. tostring(colored.bright("* " .. tostring(def.args[i]))) .. " = " .. tostring(colored.dim(repr(value))))
|
||||
end
|
||||
end
|
||||
local old_defs
|
||||
old_defs, self.defs = self.defs, def.defs
|
||||
local rets = {
|
||||
fn(self, args)
|
||||
fn(self, unpack(args))
|
||||
}
|
||||
self.defs = old_defs
|
||||
remove(self.callstack)
|
||||
@ -407,7 +431,7 @@ do
|
||||
self:writeln(tostring(colored.bright("WITH ARGS:")) .. " " .. tostring(colored.dim(repr(args))))
|
||||
end
|
||||
insert(self.callstack, "#macro")
|
||||
local ret = self:call(tree.stub, tree.line_no, unpack(args))
|
||||
local ret = self:call(tree.stub, tree:get_line_no(), unpack(args))
|
||||
remove(self.callstack)
|
||||
return ret
|
||||
end,
|
||||
@ -495,6 +519,7 @@ do
|
||||
return false
|
||||
end,
|
||||
parse = function(self, str, filename)
|
||||
self:assert(type(filename) == "string", "Bad filename type: " .. tostring(type(filename)))
|
||||
if self.debug then
|
||||
self:writeln(tostring(colored.bright("PARSING:")) .. "\n" .. tostring(colored.yellow(str)))
|
||||
end
|
||||
@ -507,10 +532,7 @@ do
|
||||
end
|
||||
return tree
|
||||
end,
|
||||
run = function(self, src, filename, vars, max_operations, output_file)
|
||||
if vars == nil then
|
||||
vars = { }
|
||||
end
|
||||
run = function(self, src, filename, max_operations, output_file)
|
||||
if max_operations == nil then
|
||||
max_operations = nil
|
||||
end
|
||||
@ -518,7 +540,7 @@ do
|
||||
output_file = nil
|
||||
end
|
||||
if src == "" then
|
||||
return nil, "", vars
|
||||
return nil, ""
|
||||
end
|
||||
if max_operations then
|
||||
local timeout
|
||||
@ -534,21 +556,18 @@ do
|
||||
local lua = self:tree_to_lua(tree, filename)
|
||||
local lua_code = lua.statements or (lua.expr .. ";")
|
||||
lua_code = "-- File: " .. tostring(filename) .. "\n" .. lua_code
|
||||
local ret = self:run_lua(lua_code, vars)
|
||||
local ret = self:run_lua(lua_code)
|
||||
if max_operations then
|
||||
debug.sethook()
|
||||
end
|
||||
if output_file then
|
||||
output_file:write(lua_code)
|
||||
end
|
||||
return ret, lua_code, vars
|
||||
return ret, lua_code
|
||||
end,
|
||||
run_file = function(self, filename, vars)
|
||||
if vars == nil then
|
||||
vars = { }
|
||||
end
|
||||
run_file = function(self, filename)
|
||||
if filename:match(".*%.lua") then
|
||||
return dofile(filename)(self, vars)
|
||||
return dofile(filename)(self)
|
||||
end
|
||||
if filename:match(".*%.nom") then
|
||||
if not self.skip_precompiled then
|
||||
@ -556,7 +575,7 @@ do
|
||||
if file then
|
||||
local lua_code = file:read("*a")
|
||||
file:close()
|
||||
return self:run_lua(lua_code, vars)
|
||||
return self:run_lua(lua_code)
|
||||
end
|
||||
end
|
||||
local file = file or io.open(filename)
|
||||
@ -570,23 +589,20 @@ do
|
||||
return self:error("Invalid filetype for " .. tostring(filename))
|
||||
end
|
||||
end,
|
||||
require_file = function(self, filename, vars)
|
||||
if vars == nil then
|
||||
vars = { }
|
||||
end
|
||||
require_file = function(self, filename)
|
||||
local loaded = self.defs["#loaded_files"]
|
||||
if not loaded[filename] then
|
||||
loaded[filename] = self:run_file(filename, vars) or true
|
||||
loaded[filename] = self:run_file(filename) or true
|
||||
end
|
||||
return loaded[filename]
|
||||
end,
|
||||
run_lua = function(self, lua_code, vars)
|
||||
if vars == nil then
|
||||
vars = { }
|
||||
end
|
||||
local load_lua_fn, err = load(([[return function(nomsu, vars)
|
||||
run_lua = function(self, lua_code)
|
||||
local load_lua_fn, err = load(([[return function(nomsu)
|
||||
%s
|
||||
end]]):format(lua_code))
|
||||
if self.debug then
|
||||
self:writeln(tostring(colored.bright("RUNNING LUA:")) .. "\n" .. tostring(colored.blue(colored.bright(lua_code))))
|
||||
end
|
||||
if not load_lua_fn then
|
||||
local n = 1
|
||||
local fn
|
||||
@ -598,15 +614,15 @@ end]]):format(lua_code))
|
||||
self:error("Failed to compile generated code:\n" .. tostring(colored.bright(colored.blue(colored.onblack(code)))) .. "\n\n" .. tostring(err))
|
||||
end
|
||||
local run_lua_fn = load_lua_fn()
|
||||
local ok, ret = pcall(run_lua_fn, self, vars)
|
||||
local ok, ret = pcall(run_lua_fn, self)
|
||||
if not ok then
|
||||
self:errorln(debug.traceback())
|
||||
self:error(ret)
|
||||
end
|
||||
return ret
|
||||
end,
|
||||
tree_to_value = function(self, tree, vars, filename)
|
||||
local code = "return (function(nomsu, vars)\nreturn " .. tostring(self:tree_to_lua(tree, filename).expr) .. ";\nend);"
|
||||
tree_to_value = function(self, tree, filename)
|
||||
local code = "return (function(nomsu)\nreturn " .. tostring(self:tree_to_lua(tree, filename).expr) .. ";\nend);"
|
||||
code = "-- Tree to value: " .. tostring(filename) .. "\n" .. code
|
||||
if self.debug then
|
||||
self:writeln(tostring(colored.bright("RUNNING LUA TO GET VALUE:")) .. "\n" .. tostring(colored.blue(colored.bright(code))))
|
||||
@ -615,7 +631,7 @@ end]]):format(lua_code))
|
||||
if not lua_thunk then
|
||||
self:error("Failed to compile generated code:\n" .. tostring(colored.bright(colored.blue(colored.onblack(code)))) .. "\n\n" .. tostring(colored.red(err)))
|
||||
end
|
||||
return (lua_thunk())(self, vars or { })
|
||||
return (lua_thunk())(self)
|
||||
end,
|
||||
tree_to_nomsu = function(self, tree, force_inline)
|
||||
if force_inline == nil then
|
||||
@ -841,7 +857,7 @@ end]]):format(lua_code))
|
||||
}
|
||||
elseif "Nomsu" == _exp_0 then
|
||||
return {
|
||||
expr = "nomsu:parse(" .. tostring(repr(tree.value.src)) .. ", " .. tostring(repr(tree.line_no)) .. ").value[1]"
|
||||
expr = "nomsu:parse(" .. tostring(repr(tree.value.src)) .. ", " .. tostring(repr(tree:get_line_no())) .. ").value[1]"
|
||||
}
|
||||
elseif "Block" == _exp_0 then
|
||||
local lua_bits = { }
|
||||
@ -891,7 +907,7 @@ end]]):format(lua_code))
|
||||
end
|
||||
local args = {
|
||||
repr(tree.stub),
|
||||
repr(tree.line_no)
|
||||
repr(tree:get_line_no())
|
||||
}
|
||||
local arg_names, escaped_args
|
||||
if def then
|
||||
@ -922,7 +938,7 @@ end]]):format(lua_code))
|
||||
break
|
||||
end
|
||||
if escaped_args[arg_names[arg_num]] then
|
||||
insert(args, "nomsu:parse(" .. tostring(repr(arg.src)) .. ", " .. tostring(repr(tree.line_no)) .. ").value[1]")
|
||||
insert(args, "nomsu:parse(" .. tostring(repr(arg.src)) .. ", " .. tostring(repr(tree:get_line_no())) .. ").value[1]")
|
||||
else
|
||||
local lua = self:tree_to_lua(arg, filename)
|
||||
if lua.statements then
|
||||
@ -1039,15 +1055,9 @@ end]]):format(lua_code))
|
||||
expr = repr(tree.value)
|
||||
}
|
||||
elseif "Var" == _exp_0 then
|
||||
if tree.value:match("^[a-zA-Z_][a-zA-Z0-9_]*$") then
|
||||
return {
|
||||
expr = "vars." .. tostring(tree.value)
|
||||
}
|
||||
else
|
||||
return {
|
||||
expr = "vars[" .. tostring(repr(tree.value)) .. "]"
|
||||
}
|
||||
end
|
||||
return {
|
||||
expr = ("_" .. self:var_to_lua_identifier(tree.value))
|
||||
}
|
||||
else
|
||||
return self:error("Unknown/unimplemented thingy: " .. tostring(tree.type))
|
||||
end
|
||||
@ -1256,13 +1266,15 @@ end]]):format(lua_code))
|
||||
msg = ''
|
||||
end
|
||||
if not condition then
|
||||
return self:error(msg)
|
||||
return self:error("Assertion failed: " .. msg)
|
||||
end
|
||||
end,
|
||||
error = function(self, msg)
|
||||
local error_msg = colored.red("ERROR!")
|
||||
if msg then
|
||||
if msg and #msg > 0 then
|
||||
error_msg = error_msg .. ("\n" .. (colored.bright(colored.yellow(colored.onred(msg)))))
|
||||
else
|
||||
error_msg = error_msg .. "\n<no message>"
|
||||
end
|
||||
error_msg = error_msg .. "\nCallstack:"
|
||||
local maxlen = max((function()
|
||||
@ -1301,20 +1313,6 @@ end]]):format(lua_code))
|
||||
self.callstack = { }
|
||||
return error(error_msg, 3)
|
||||
end,
|
||||
typecheck = function(self, vars, varname, desired_type)
|
||||
local x = vars[varname]
|
||||
local x_type = type(x)
|
||||
if x_type == desired_type then
|
||||
return x
|
||||
end
|
||||
if x_type == 'table' then
|
||||
x_type = x.type or x_type
|
||||
if x_type == desired_type then
|
||||
return x
|
||||
end
|
||||
end
|
||||
return self:error("Invalid type for %" .. tostring(varname) .. ". Expected " .. tostring(desired_type) .. ", but got " .. tostring(x_type) .. ":\n" .. tostring(repr(x)))
|
||||
end,
|
||||
source_code = function(self, level)
|
||||
if level == nil then
|
||||
level = 0
|
||||
@ -1340,51 +1338,51 @@ end]]):format(lua_code))
|
||||
end
|
||||
return concat(concat_parts)
|
||||
end
|
||||
self:defmacro("do %block", function(self, vars)
|
||||
self:defmacro("do %block", function(self, _block)
|
||||
local make_line
|
||||
make_line = function(lua)
|
||||
return lua.expr and (lua.expr .. ";") or lua.statements
|
||||
end
|
||||
if vars.block.type == "Block" then
|
||||
return self:tree_to_lua(vars.block)
|
||||
if _block.type == "Block" then
|
||||
return self:tree_to_lua(_block)
|
||||
else
|
||||
return {
|
||||
expr = tostring(self:tree_to_lua(vars.block)) .. "(nomsu, vars)"
|
||||
expr = tostring(self:tree_to_lua(_block)) .. "(nomsu)"
|
||||
}
|
||||
end
|
||||
end)
|
||||
self:defmacro("immediately %block", function(self, vars)
|
||||
local lua = self:tree_to_lua(vars.block)
|
||||
self:defmacro("immediately %block", function(self, _block)
|
||||
local lua = self:tree_to_lua(_block)
|
||||
local lua_code = lua.statements or (lua.expr .. ";")
|
||||
lua_code = "-- Immediately:\n" .. lua_code
|
||||
self:run_lua(lua_code, vars)
|
||||
self:run_lua(lua_code)
|
||||
return {
|
||||
statements = lua_code
|
||||
}
|
||||
end)
|
||||
self:defmacro("lua> %code", function(self, vars)
|
||||
local lua = nomsu_string_as_lua(self, vars.code)
|
||||
self:defmacro("lua> %code", function(self, _code)
|
||||
local lua = nomsu_string_as_lua(self, _code)
|
||||
return {
|
||||
statements = lua
|
||||
}
|
||||
end)
|
||||
self:defmacro("=lua %code", function(self, vars)
|
||||
local lua = nomsu_string_as_lua(self, vars.code)
|
||||
self:defmacro("=lua %code", function(self, _code)
|
||||
local lua = nomsu_string_as_lua(self, _code)
|
||||
return {
|
||||
expr = lua
|
||||
}
|
||||
end)
|
||||
self:defmacro("__src__ %level", function(self, vars)
|
||||
self:defmacro("__src__ %level", function(self, _level)
|
||||
return {
|
||||
expr = repr(self:source_code(self:tree_to_value(vars.level)))
|
||||
expr = repr(self:source_code(self:tree_to_value(_level)))
|
||||
}
|
||||
end)
|
||||
self:def("run file %filename", function(self, vars)
|
||||
return self:run_file(vars.filename, vars)
|
||||
self:def("run file %filename", function(self, _filename)
|
||||
return self:run_file(_filename)
|
||||
end)
|
||||
return self:defmacro("require %filename", function(self, vars)
|
||||
local filename = self:tree_to_value(vars.filename)
|
||||
self:require_file(filename, vars)
|
||||
return self:defmacro("require %filename", function(self, _filename)
|
||||
local filename = self:tree_to_value(_filename)
|
||||
self:require_file(filename)
|
||||
return {
|
||||
statements = "nomsu:require_file(" .. tostring(repr(filename)) .. ");"
|
||||
}
|
||||
@ -1513,8 +1511,7 @@ if arg then
|
||||
else
|
||||
input = io.open(args.input):read("*a")
|
||||
end
|
||||
local vars = { }
|
||||
local retval, code = c:run(input, args.input, vars)
|
||||
local retval, code = c:run(input, args.input)
|
||||
if args.output then
|
||||
compiled_output:write(code)
|
||||
end
|
||||
@ -1524,7 +1521,6 @@ if arg then
|
||||
end
|
||||
end
|
||||
if args.flags["-i"] then
|
||||
local vars = { }
|
||||
c:run('require "lib/core.nom"', "stdin")
|
||||
while true do
|
||||
local buff = ""
|
||||
@ -1540,7 +1536,7 @@ if arg then
|
||||
break
|
||||
end
|
||||
local ok, ret = pcall(function()
|
||||
return c:run(buff, "stdin", vars)
|
||||
return c:run(buff, "stdin")
|
||||
end)
|
||||
if ok and ret ~= nil then
|
||||
print("= " .. repr(ret))
|
||||
|
154
nomsu.moon
154
nomsu.moon
@ -100,14 +100,12 @@ do
|
||||
error(err_msg)
|
||||
FunctionCall: (start, value, stop)->
|
||||
stub = concat([(t.type == "Word" and t.value or "%") for t in *value], " ")
|
||||
line_no = 1
|
||||
while (ctx.line_starts[line_no+1] or math.huge) < start do line_no += 1
|
||||
src = ctx.source_code\sub(start,stop-1)
|
||||
return {type: "FunctionCall", :src, line_no: "#{ctx.filename}:#{line_no}", :value, :stub}
|
||||
return {:start, :stop, type: "FunctionCall", :src, get_line_no:ctx.get_line_no, :value, :stub}
|
||||
|
||||
setmetatable(defs, {__index:(key)=>
|
||||
make_node = (start, value, stop)->
|
||||
{:start, :stop, :value, src:ctx.source_code\sub(start,stop-1), type: key}
|
||||
{:start, :stop, :value, src:ctx.source_code\sub(start,stop-1), get_line_no:ctx.get_line_no, type: key}
|
||||
self[key] = make_node
|
||||
return make_node
|
||||
})
|
||||
@ -129,10 +127,18 @@ do
|
||||
nomsu = re.compile(nomsu, defs)
|
||||
|
||||
parse = (source_code, filename)->
|
||||
_ctx = {:source_code, :filename, indent_stack: {0}}
|
||||
_ctx.line_starts = re.compile("lines <- {| line ('\n' line)* |} line <- {} [^\n]*")\match(source_code)
|
||||
_ctx.get_line_no = =>
|
||||
unless @_line_no
|
||||
line_no = 1
|
||||
while (_ctx.line_starts[line_no+1] or math.huge) < @start do line_no += 1
|
||||
@_line_no = "#{_ctx.filename}:#{line_no}"
|
||||
return @_line_no
|
||||
|
||||
old_ctx = ctx
|
||||
export ctx
|
||||
ctx = {:source_code, :filename, indent_stack: {0}}
|
||||
ctx.line_starts = re.compile("lines <- {| line ('\n' line)* |} line <- {} [^\n]*")\match(source_code)
|
||||
ctx = _ctx
|
||||
tree = nomsu\match(source_code)
|
||||
ctx = old_ctx
|
||||
return tree
|
||||
@ -171,28 +177,31 @@ class NomsuCompiler
|
||||
elseif type(signature) == 'table' and type(signature[1]) == 'string'
|
||||
signature = @get_stubs signature
|
||||
@assert type(fn) == 'function', "Bad fn: #{repr fn}"
|
||||
canonical_args = nil
|
||||
canonical_escaped_args = nil
|
||||
aliases = {}
|
||||
@@def_number += 1
|
||||
def = {:fn, :src, :is_macro, aliases:{}, def_number:@@def_number, defs:@defs}
|
||||
where_defs_go = (getmetatable(@defs) or {}).__newindex or @defs
|
||||
for sig_i=1,#signature
|
||||
stub, arg_names, escaped_args = unpack(signature[sig_i])
|
||||
arg_positions = {}
|
||||
@assert stub, "NO STUB FOUND: #{repr signature}"
|
||||
if @debug then @writeln "#{colored.bright "DEFINING RULE:"} #{colored.underscore colored.magenta repr(stub)} #{colored.bright "WITH ARGS"} #{colored.dim repr(arg_names)}"
|
||||
for i=1,#arg_names-1 do for j=i+1,#arg_names
|
||||
if arg_names[i] == arg_names[j] then @error "Duplicate argument in function #{stub}: '#{arg_names[i]}'"
|
||||
if canonical_args
|
||||
@assert equivalent(set(arg_names), canonical_args), "Mismatched args"
|
||||
else canonical_args = set(arg_names)
|
||||
if canonical_escaped_args
|
||||
@assert equivalent(escaped_args, canonical_escaped_args), "Mismatched escaped args"
|
||||
else
|
||||
canonical_escaped_args = escaped_args
|
||||
|
||||
if sig_i == 1
|
||||
arg_positions = [i for i=1,#arg_names]
|
||||
def.args = arg_names
|
||||
def.escaped_args = escaped_args
|
||||
else
|
||||
@assert equivalent(set(def.args), set(arg_names)), "Mismatched args"
|
||||
@assert equivalent(def.escaped_args, escaped_args), "Mismatched escaped args"
|
||||
for j,a in ipairs(arg_names)
|
||||
for i,c_a in ipairs(def.args)
|
||||
if a == c_a
|
||||
arg_positions[j] = i
|
||||
insert def.aliases, stub
|
||||
stub_def = setmetatable({:stub, :arg_names, :escaped_args}, {__index:def})
|
||||
stub_def = setmetatable({:stub, :arg_names, :arg_positions}, {__index:def})
|
||||
rawset(where_defs_go, stub, stub_def)
|
||||
|
||||
defmacro: (signature, fn, src)=>
|
||||
@ -255,15 +264,15 @@ class NomsuCompiler
|
||||
@error "Attempt to call undefined function: #{stub}"
|
||||
unless def.is_macro
|
||||
@assert_permission(stub)
|
||||
{:fn, :arg_names} = def
|
||||
args = {name, select(i,...) for i,name in ipairs(arg_names)}
|
||||
{:fn, :arg_positions} = def
|
||||
args = [select(p, ...) for p in *arg_positions]
|
||||
if @debug
|
||||
@write "#{colored.bright "CALLING"} #{colored.magenta(colored.underscore stub)} "
|
||||
@writeln "#{colored.bright "WITH ARGS:"}"
|
||||
for name, value in pairs(args)
|
||||
@writeln " #{colored.bright "* #{name}"} = #{colored.dim repr(value)}"
|
||||
for i, value in ipairs(args)
|
||||
@writeln " #{colored.bright "* #{def.args[i]}"} = #{colored.dim repr(value)}"
|
||||
old_defs, @defs = @defs, def.defs
|
||||
rets = {fn(self,args)}
|
||||
rets = {fn(self,unpack(args))}
|
||||
@defs = old_defs
|
||||
remove @callstack
|
||||
return unpack(rets)
|
||||
@ -274,7 +283,7 @@ class NomsuCompiler
|
||||
@write "#{colored.bright "RUNNING MACRO"} #{colored.underscore colored.magenta(tree.stub)} "
|
||||
@writeln "#{colored.bright "WITH ARGS:"} #{colored.dim repr args}"
|
||||
insert @callstack, "#macro"
|
||||
ret = @call(tree.stub, tree.line_no, unpack(args))
|
||||
ret = @call(tree.stub, tree\get_line_no!, unpack(args))
|
||||
remove @callstack
|
||||
return ret
|
||||
|
||||
@ -324,6 +333,7 @@ class NomsuCompiler
|
||||
return false
|
||||
|
||||
parse: (str, filename)=>
|
||||
@assert type(filename) == "string", "Bad filename type: #{type filename}"
|
||||
if @debug
|
||||
@writeln("#{colored.bright "PARSING:"}\n#{colored.yellow str}")
|
||||
str = str\gsub("\r","")
|
||||
@ -334,8 +344,8 @@ class NomsuCompiler
|
||||
@print_tree tree, " "
|
||||
return tree
|
||||
|
||||
run: (src, filename, vars={}, max_operations=nil, output_file=nil)=>
|
||||
if src == "" then return nil, "", vars
|
||||
run: (src, filename, max_operations=nil, output_file=nil)=>
|
||||
if src == "" then return nil, ""
|
||||
if max_operations
|
||||
timeout = ->
|
||||
debug.sethook!
|
||||
@ -348,23 +358,23 @@ class NomsuCompiler
|
||||
lua = @tree_to_lua(tree, filename)
|
||||
lua_code = lua.statements or (lua.expr..";")
|
||||
lua_code = "-- File: #{filename}\n"..lua_code
|
||||
ret = @run_lua(lua_code, vars)
|
||||
ret = @run_lua(lua_code)
|
||||
if max_operations
|
||||
debug.sethook!
|
||||
if output_file
|
||||
output_file\write(lua_code)
|
||||
return ret, lua_code, vars
|
||||
return ret, lua_code
|
||||
|
||||
run_file: (filename, vars={})=>
|
||||
run_file: (filename)=>
|
||||
if filename\match(".*%.lua")
|
||||
return dofile(filename)(@, vars)
|
||||
return dofile(filename)(@)
|
||||
if filename\match(".*%.nom")
|
||||
if not @skip_precompiled -- Look for precompiled version
|
||||
file = io.open(filename\gsub("%.nom", ".lua"), "r")
|
||||
if file
|
||||
lua_code = file\read("*a")
|
||||
file\close!
|
||||
return @run_lua(lua_code, vars)
|
||||
return @run_lua(lua_code)
|
||||
file = file or io.open(filename)
|
||||
if not file
|
||||
@error "File does not exist: #{filename}"
|
||||
@ -374,17 +384,19 @@ class NomsuCompiler
|
||||
else
|
||||
@error "Invalid filetype for #{filename}"
|
||||
|
||||
require_file: (filename, vars={})=>
|
||||
require_file: (filename)=>
|
||||
loaded = @defs["#loaded_files"]
|
||||
if not loaded[filename]
|
||||
loaded[filename] = @run_file(filename, vars) or true
|
||||
loaded[filename] = @run_file(filename) or true
|
||||
return loaded[filename]
|
||||
|
||||
run_lua: (lua_code, vars={})=>
|
||||
run_lua: (lua_code)=>
|
||||
load_lua_fn, err = load([[
|
||||
return function(nomsu, vars)
|
||||
return function(nomsu)
|
||||
%s
|
||||
end]]\format(lua_code))
|
||||
if @debug
|
||||
@writeln "#{colored.bright "RUNNING LUA:"}\n#{colored.blue colored.bright(lua_code)}"
|
||||
if not load_lua_fn
|
||||
n = 1
|
||||
fn = ->
|
||||
@ -393,22 +405,22 @@ end]]\format(lua_code))
|
||||
code = "1 |"..lua_code\gsub("\n", fn)
|
||||
@error("Failed to compile generated code:\n#{colored.bright colored.blue colored.onblack code}\n\n#{err}")
|
||||
run_lua_fn = load_lua_fn!
|
||||
ok,ret = pcall(run_lua_fn, self, vars)
|
||||
ok,ret = pcall(run_lua_fn, self)
|
||||
if not ok
|
||||
--@errorln "#{colored.red "Error occurred in statement:"}\n#{colored.yellow tree.src}"
|
||||
@errorln debug.traceback!
|
||||
@error(ret)
|
||||
return ret
|
||||
|
||||
tree_to_value: (tree, vars, filename)=>
|
||||
code = "return (function(nomsu, vars)\nreturn #{@tree_to_lua(tree, filename).expr};\nend);"
|
||||
tree_to_value: (tree, filename)=>
|
||||
code = "return (function(nomsu)\nreturn #{@tree_to_lua(tree, filename).expr};\nend);"
|
||||
code = "-- Tree to value: #{filename}\n"..code
|
||||
if @debug
|
||||
@writeln "#{colored.bright "RUNNING LUA TO GET VALUE:"}\n#{colored.blue colored.bright(code)}"
|
||||
lua_thunk, err = load(code)
|
||||
if not lua_thunk
|
||||
@error("Failed to compile generated code:\n#{colored.bright colored.blue colored.onblack code}\n\n#{colored.red err}")
|
||||
return (lua_thunk!)(self, vars or {})
|
||||
return (lua_thunk!)(self)
|
||||
|
||||
tree_to_nomsu: (tree, force_inline=false)=>
|
||||
-- Return <nomsu code>, <is safe for inline use>
|
||||
@ -562,7 +574,7 @@ end]]\format(lua_code))
|
||||
return statements:concat(lua_bits, "\n")
|
||||
|
||||
when "Nomsu"
|
||||
return expr:"nomsu:parse(#{repr tree.value.src}, #{repr tree.line_no}).value[1]"
|
||||
return expr:"nomsu:parse(#{repr tree.value.src}, #{repr tree\get_line_no!}).value[1]"
|
||||
|
||||
when "Block"
|
||||
lua_bits = {}
|
||||
@ -597,7 +609,7 @@ end]]\format(lua_code))
|
||||
remove @compilestack
|
||||
return expr:"(#{concat bits, " "})"
|
||||
|
||||
args = {repr(tree.stub), repr(tree.line_no)}
|
||||
args = {repr(tree.stub), repr(tree\get_line_no!)}
|
||||
local arg_names, escaped_args
|
||||
if def
|
||||
arg_names, escaped_args = def.arg_names, def.escaped_args
|
||||
@ -607,7 +619,7 @@ end]]\format(lua_code))
|
||||
for arg in *tree.value
|
||||
if arg.type == 'Word' then continue
|
||||
if escaped_args[arg_names[arg_num]]
|
||||
insert args, "nomsu:parse(#{repr arg.src}, #{repr tree.line_no}).value[1]"
|
||||
insert args, "nomsu:parse(#{repr arg.src}, #{repr tree\get_line_no!}).value[1]"
|
||||
else
|
||||
lua = @tree_to_lua arg, filename
|
||||
if lua.statements
|
||||
@ -678,10 +690,7 @@ end]]\format(lua_code))
|
||||
return expr:repr(tree.value)
|
||||
|
||||
when "Var"
|
||||
if tree.value\match("^[a-zA-Z_][a-zA-Z0-9_]*$")
|
||||
return expr:"vars.#{tree.value}"
|
||||
else
|
||||
return expr:"vars[#{repr tree.value}]"
|
||||
return expr:("_"..@var_to_lua_identifier(tree.value))
|
||||
|
||||
else
|
||||
@error("Unknown/unimplemented thingy: #{tree.type}")
|
||||
@ -808,12 +817,14 @@ end]]\format(lua_code))
|
||||
|
||||
assert: (condition, msg='')=>
|
||||
if not condition
|
||||
@error(msg)
|
||||
@error("Assertion failed: "..msg)
|
||||
|
||||
error: (msg)=>
|
||||
error_msg = colored.red "ERROR!"
|
||||
if msg
|
||||
if msg and #msg > 0
|
||||
error_msg ..= "\n" .. (colored.bright colored.yellow colored.onred msg)
|
||||
else
|
||||
error_msg ..= "\n<no message>"
|
||||
error_msg ..= "\nCallstack:"
|
||||
maxlen = max([#c[2] for c in *@callstack when c != "#macro"])
|
||||
for i=#@callstack,1,-1
|
||||
@ -827,15 +838,6 @@ end]]\format(lua_code))
|
||||
@callstack = {}
|
||||
error error_msg, 3
|
||||
|
||||
typecheck: (vars, varname, desired_type)=>
|
||||
x = vars[varname]
|
||||
x_type = type(x)
|
||||
if x_type == desired_type then return x
|
||||
if x_type == 'table'
|
||||
x_type = x.type or x_type
|
||||
if x_type == desired_type then return x
|
||||
@error "Invalid type for %#{varname}. Expected #{desired_type}, but got #{x_type}:\n#{repr x}"
|
||||
|
||||
source_code: (level=0)=>
|
||||
@dedent @compilestack[#@compilestack-level].src
|
||||
|
||||
@ -853,37 +855,37 @@ end]]\format(lua_code))
|
||||
insert concat_parts, lua.expr
|
||||
return concat(concat_parts)
|
||||
|
||||
@defmacro "do %block", (vars)=>
|
||||
@defmacro "do %block", (_block)=>
|
||||
make_line = (lua)-> lua.expr and (lua.expr..";") or lua.statements
|
||||
if vars.block.type == "Block"
|
||||
return @tree_to_lua(vars.block)
|
||||
if _block.type == "Block"
|
||||
return @tree_to_lua(_block)
|
||||
else
|
||||
return expr:"#{@tree_to_lua vars.block}(nomsu, vars)"
|
||||
return expr:"#{@tree_to_lua _block}(nomsu)"
|
||||
|
||||
@defmacro "immediately %block", (vars)=>
|
||||
lua = @tree_to_lua(vars.block)
|
||||
@defmacro "immediately %block", (_block)=>
|
||||
lua = @tree_to_lua(_block)
|
||||
lua_code = lua.statements or (lua.expr..";")
|
||||
lua_code = "-- Immediately:\n"..lua_code
|
||||
@run_lua(lua_code, vars)
|
||||
@run_lua(lua_code)
|
||||
return statements:lua_code
|
||||
|
||||
@defmacro "lua> %code", (vars)=>
|
||||
lua = nomsu_string_as_lua(@, vars.code)
|
||||
@defmacro "lua> %code", (_code)=>
|
||||
lua = nomsu_string_as_lua(@, _code)
|
||||
return statements:lua
|
||||
|
||||
@defmacro "=lua %code", (vars)=>
|
||||
lua = nomsu_string_as_lua(@, vars.code)
|
||||
@defmacro "=lua %code", (_code)=>
|
||||
lua = nomsu_string_as_lua(@, _code)
|
||||
return expr:lua
|
||||
|
||||
@defmacro "__src__ %level", (vars)=>
|
||||
expr: repr(@source_code(@tree_to_value(vars.level)))
|
||||
@defmacro "__src__ %level", (_level)=>
|
||||
expr: repr(@source_code(@tree_to_value(_level)))
|
||||
|
||||
@def "run file %filename", (vars)=>
|
||||
@run_file(vars.filename, vars)
|
||||
@def "run file %filename", (_filename)=>
|
||||
@run_file(_filename)
|
||||
|
||||
@defmacro "require %filename", (vars)=>
|
||||
filename = @tree_to_value(vars.filename)
|
||||
@require_file(filename, vars)
|
||||
@defmacro "require %filename", (_filename)=>
|
||||
filename = @tree_to_value(_filename)
|
||||
@require_file(filename)
|
||||
return statements:"nomsu:require_file(#{repr filename});"
|
||||
|
||||
if arg
|
||||
@ -926,8 +928,7 @@ if arg
|
||||
input = if args.input == '-'
|
||||
io.read('*a')
|
||||
else io.open(args.input)\read("*a")
|
||||
vars = {}
|
||||
retval, code = c\run(input, args.input, vars)
|
||||
retval, code = c\run(input, args.input)
|
||||
if args.output
|
||||
compiled_output\write(code)
|
||||
|
||||
@ -936,7 +937,6 @@ if arg
|
||||
|
||||
if args.flags["-i"]
|
||||
-- REPL
|
||||
vars = {}
|
||||
c\run('require "lib/core.nom"', "stdin")
|
||||
while true
|
||||
buff = ""
|
||||
@ -948,7 +948,7 @@ if arg
|
||||
buff ..= line
|
||||
if #buff == 0
|
||||
break
|
||||
ok, ret = pcall(-> c\run(buff, "stdin", vars))
|
||||
ok, ret = pcall(-> c\run(buff, "stdin"))
|
||||
if ok and ret != nil
|
||||
print "= "..repr(ret)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user