Moved all the tree->lua and tree->nomsu code back into single functions
in nomsu.moon, and cleaned up how Vars are treated, since they are not atomic.
This commit is contained in:
parent
6f6c4377b2
commit
ad94ed3653
32
code_obj.lua
32
code_obj.lua
@ -201,6 +201,9 @@ do
|
|||||||
local _parent_0 = Code
|
local _parent_0 = Code
|
||||||
local _base_0 = {
|
local _base_0 = {
|
||||||
add_free_vars = function(self, vars)
|
add_free_vars = function(self, vars)
|
||||||
|
if not (#vars > 0) then
|
||||||
|
return
|
||||||
|
end
|
||||||
local seen
|
local seen
|
||||||
do
|
do
|
||||||
local _tbl_0 = { }
|
local _tbl_0 = { }
|
||||||
@ -216,12 +219,7 @@ do
|
|||||||
end
|
end
|
||||||
for _index_0 = 1, #vars do
|
for _index_0 = 1, #vars do
|
||||||
local var = vars[_index_0]
|
local var = vars[_index_0]
|
||||||
if type(var) == 'userdata' and var.type == "Var" then
|
assert(type(var) == 'userdata' and var.type == "Var")
|
||||||
var = tostring(var:as_lua())
|
|
||||||
elseif type(var) ~= 'string' then
|
|
||||||
var = tostring(var)
|
|
||||||
end
|
|
||||||
assert(var:match("^[_a-zA-Z][_a-zA-Z0-9]*$"))
|
|
||||||
if not (seen[var]) then
|
if not (seen[var]) then
|
||||||
self.free_vars[#self.free_vars + 1] = var
|
self.free_vars[#self.free_vars + 1] = var
|
||||||
seen[var] = true
|
seen[var] = true
|
||||||
@ -230,15 +228,13 @@ do
|
|||||||
self.__str = nil
|
self.__str = nil
|
||||||
end,
|
end,
|
||||||
remove_free_vars = function(self, vars)
|
remove_free_vars = function(self, vars)
|
||||||
|
if not (#vars > 0) then
|
||||||
|
return
|
||||||
|
end
|
||||||
local removals = { }
|
local removals = { }
|
||||||
for _index_0 = 1, #vars do
|
for _index_0 = 1, #vars do
|
||||||
local var = vars[_index_0]
|
local var = vars[_index_0]
|
||||||
if type(var) == 'userdata' and var.type == "Var" then
|
assert(type(var) == 'userdata' and var.type == "Var")
|
||||||
var = tostring(var:as_lua())
|
|
||||||
elseif type(var) ~= 'string' then
|
|
||||||
var = tostring(var)
|
|
||||||
end
|
|
||||||
assert(var:match("^[_a-zA-Z][_a-zA-Z0-9]*$"))
|
|
||||||
removals[var] = true
|
removals[var] = true
|
||||||
end
|
end
|
||||||
local stack = {
|
local stack = {
|
||||||
@ -296,7 +292,6 @@ do
|
|||||||
local var = _list_0[_index_0]
|
local var = _list_0[_index_0]
|
||||||
if not (seen[var]) then
|
if not (seen[var]) then
|
||||||
seen[var] = true
|
seen[var] = true
|
||||||
assert(var:match("^[_a-zA-Z][_a-zA-Z0-9]*$"))
|
|
||||||
to_declare[#to_declare + 1] = var
|
to_declare[#to_declare + 1] = var
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -312,7 +307,16 @@ do
|
|||||||
end
|
end
|
||||||
if #to_declare > 0 then
|
if #to_declare > 0 then
|
||||||
self:remove_free_vars(to_declare)
|
self:remove_free_vars(to_declare)
|
||||||
self:prepend("local " .. tostring(concat(to_declare, ", ")) .. ";\n")
|
self:prepend("local " .. tostring(concat((function()
|
||||||
|
local _accum_0 = { }
|
||||||
|
local _len_0 = 1
|
||||||
|
for _index_0 = 1, #to_declare do
|
||||||
|
local v = to_declare[_index_0]
|
||||||
|
_accum_0[_len_0] = v:as_lua_id()
|
||||||
|
_len_0 = _len_0 + 1
|
||||||
|
end
|
||||||
|
return _accum_0
|
||||||
|
end)(), ", ")) .. ";\n")
|
||||||
end
|
end
|
||||||
return to_declare
|
return to_declare
|
||||||
end,
|
end,
|
||||||
|
@ -134,26 +134,20 @@ class Lua extends Code
|
|||||||
return lua
|
return lua
|
||||||
|
|
||||||
add_free_vars: (vars)=>
|
add_free_vars: (vars)=>
|
||||||
|
return unless #vars > 0
|
||||||
seen = {[v]:true for v in *@free_vars}
|
seen = {[v]:true for v in *@free_vars}
|
||||||
for var in *vars
|
for var in *vars
|
||||||
if type(var) == 'userdata' and var.type == "Var"
|
assert(type(var) == 'userdata' and var.type == "Var")
|
||||||
var = tostring(var\as_lua!)
|
|
||||||
elseif type(var) != 'string'
|
|
||||||
var = tostring(var)
|
|
||||||
assert(var\match("^[_a-zA-Z][_a-zA-Z0-9]*$"))
|
|
||||||
unless seen[var]
|
unless seen[var]
|
||||||
@free_vars[#@free_vars+1] = var
|
@free_vars[#@free_vars+1] = var
|
||||||
seen[var] = true
|
seen[var] = true
|
||||||
@__str = nil
|
@__str = nil
|
||||||
|
|
||||||
remove_free_vars: (vars)=>
|
remove_free_vars: (vars)=>
|
||||||
|
return unless #vars > 0
|
||||||
removals = {}
|
removals = {}
|
||||||
for var in *vars
|
for var in *vars
|
||||||
if type(var) == 'userdata' and var.type == "Var"
|
assert(type(var) == 'userdata' and var.type == "Var")
|
||||||
var = tostring(var\as_lua!)
|
|
||||||
elseif type(var) != 'string'
|
|
||||||
var = tostring(var)
|
|
||||||
assert(var\match("^[_a-zA-Z][_a-zA-Z0-9]*$"))
|
|
||||||
removals[var] = true
|
removals[var] = true
|
||||||
|
|
||||||
stack = {self}
|
stack = {self}
|
||||||
@ -185,7 +179,6 @@ class Lua extends Code
|
|||||||
for var in *@free_vars
|
for var in *@free_vars
|
||||||
unless seen[var]
|
unless seen[var]
|
||||||
seen[var] = true
|
seen[var] = true
|
||||||
assert(var\match("^[_a-zA-Z][_a-zA-Z0-9]*$"))
|
|
||||||
to_declare[#to_declare+1] = var
|
to_declare[#to_declare+1] = var
|
||||||
for bit in *@bits
|
for bit in *@bits
|
||||||
if bit.__class == Lua
|
if bit.__class == Lua
|
||||||
@ -193,7 +186,7 @@ class Lua extends Code
|
|||||||
gather_from self
|
gather_from self
|
||||||
if #to_declare > 0
|
if #to_declare > 0
|
||||||
@remove_free_vars to_declare
|
@remove_free_vars to_declare
|
||||||
@prepend "local #{concat to_declare, ", "};\n"
|
@prepend "local #{concat [v\as_lua_id! for v in *to_declare], ", "};\n"
|
||||||
return to_declare
|
return to_declare
|
||||||
|
|
||||||
__tostring: =>
|
__tostring: =>
|
||||||
|
@ -20,12 +20,12 @@ immediately
|
|||||||
lua:append("function(tree")
|
lua:append("function(tree")
|
||||||
local args = {}
|
local args = {}
|
||||||
for i,tok in ipairs(\%actions[1]) do
|
for i,tok in ipairs(\%actions[1]) do
|
||||||
if tok.type == "Var" then args[#args+1] = tok:as_lua(nomsu) end
|
if tok.type == "Var" then args[#args+1] = tok end
|
||||||
end
|
end
|
||||||
for i, arg in ipairs(args) do
|
for i, arg in ipairs(args) do
|
||||||
lua:append(", ", arg)
|
lua:append(", ", nomsu:tree_to_lua(arg))
|
||||||
end
|
end
|
||||||
local body_lua = \%lua:as_lua(nomsu):as_statements("return ")
|
local body_lua = nomsu:tree_to_lua(\%lua):as_statements("return ")
|
||||||
body_lua:remove_free_vars(args)
|
body_lua:remove_free_vars(args)
|
||||||
body_lua:declare_locals()
|
body_lua:declare_locals()
|
||||||
lua:append(")\n ", body_lua, "\nend);")
|
lua:append(")\n ", body_lua, "\nend);")
|
||||||
@ -50,13 +50,13 @@ immediately
|
|||||||
lua:append("function(")
|
lua:append("function(")
|
||||||
local args = {}
|
local args = {}
|
||||||
for i,tok in ipairs(\%actions[1]) do
|
for i,tok in ipairs(\%actions[1]) do
|
||||||
if tok.type == "Var" then args[#args+1] = tok:as_lua(nomsu) end
|
if tok.type == "Var" then args[#args+1] = tok end
|
||||||
end
|
end
|
||||||
for i, arg in ipairs(args) do
|
for i, arg in ipairs(args) do
|
||||||
lua:append(arg)
|
lua:append(nomsu:tree_to_lua(arg))
|
||||||
if i < #args then lua:append(", ") end
|
if i < #args then lua:append(", ") end
|
||||||
end
|
end
|
||||||
local body_lua = \%body:as_lua(nomsu):as_statements("return ")
|
local body_lua = nomsu:tree_to_lua(\%body):as_statements("return ")
|
||||||
body_lua:remove_free_vars(args)
|
body_lua:remove_free_vars(args)
|
||||||
body_lua:declare_locals()
|
body_lua:declare_locals()
|
||||||
lua:append(")\n ", body_lua, "\nend);")
|
lua:append(")\n ", body_lua, "\nend);")
|
||||||
@ -81,7 +81,7 @@ immediately
|
|||||||
local replacements = {}
|
local replacements = {}
|
||||||
for i,tok in ipairs(\%shorthand[1]) do
|
for i,tok in ipairs(\%shorthand[1]) do
|
||||||
if tok.type == "Var" then
|
if tok.type == "Var" then
|
||||||
local lua_var = tostring(tok:as_lua(nomsu))
|
local lua_var = tostring(nomsu:tree_to_lua(tok))
|
||||||
replacements[tok] = lua_var
|
replacements[tok] = lua_var
|
||||||
lua:append(", ", lua_var)
|
lua:append(", ", lua_var)
|
||||||
end
|
end
|
||||||
@ -104,7 +104,7 @@ immediately
|
|||||||
lua:append([[)
|
lua:append([[)
|
||||||
local tree = ]], make_tree(\%longhand), [[
|
local tree = ]], make_tree(\%longhand), [[
|
||||||
|
|
||||||
return tree:as_lua(nomsu)
|
return nomsu:tree_to_lua(tree)
|
||||||
end);]])
|
end);]])
|
||||||
return lua
|
return lua
|
||||||
|
|
||||||
@ -119,27 +119,27 @@ action [remove action %stub]
|
|||||||
|
|
||||||
immediately
|
immediately
|
||||||
action [%tree as nomsu]
|
action [%tree as nomsu]
|
||||||
=lua "\%tree:as_nomsu()"
|
=lua "nomsu:tree_to_nomsu(\%tree)"
|
||||||
|
|
||||||
action [%tree as inline nomsu]
|
action [%tree as inline nomsu]
|
||||||
=lua "\%tree:as_nomsu(true)"
|
=lua "nomsu:tree_to_nomsu(\%tree, true)"
|
||||||
|
|
||||||
action [%tree as lua]
|
action [%tree as lua]
|
||||||
=lua "\%tree:as_lua(nomsu)"
|
=lua "nomsu:tree_to_lua(\%tree)"
|
||||||
|
|
||||||
action [%tree as lua expr]
|
action [%tree as lua expr]
|
||||||
lua> ".."
|
lua> ".."
|
||||||
local lua = \%tree:as_lua(nomsu)
|
local lua = nomsu:tree_to_lua(\%tree)
|
||||||
if not lua.is_value then
|
if not lua.is_value then
|
||||||
error("Invalid thing to convert to lua expr: "..\%tree)
|
error("Invalid thing to convert to lua expr: "..\%tree)
|
||||||
end
|
end
|
||||||
return lua
|
return lua
|
||||||
|
|
||||||
action [%tree as lua statements]
|
action [%tree as lua statements]
|
||||||
=lua "\%tree:as_lua(nomsu):as_statements()"
|
=lua "nomsu:tree_to_lua(\%tree):as_statements()"
|
||||||
|
|
||||||
action [%tree with vars %vars]
|
action [%tree with vars %vars]
|
||||||
=lua "nomsu:tree_with_replacements(\%tree, \%vars)"
|
=lua "\%tree:map(\%vars)"
|
||||||
|
|
||||||
compile [declare locals in %code] to
|
compile [declare locals in %code] to
|
||||||
Lua value "\(%code as lua expr):declare_locals()"
|
Lua value "\(%code as lua expr):declare_locals()"
|
||||||
@ -168,7 +168,7 @@ immediately
|
|||||||
|
|
||||||
immediately
|
immediately
|
||||||
compile [nomsu] to: Lua value "nomsu"
|
compile [nomsu] to: Lua value "nomsu"
|
||||||
compile [%var as lua identifier] to: Lua value "\(%var as lua expr):as_lua(nomsu)"
|
compile [%var as lua identifier] to: Lua value "nomsu:tree_to_lua(\(%var as lua expr))"
|
||||||
|
|
||||||
# Compiler tools
|
# Compiler tools
|
||||||
immediately
|
immediately
|
||||||
@ -178,7 +178,7 @@ immediately
|
|||||||
immediately
|
immediately
|
||||||
compile [show lua %block] to
|
compile [show lua %block] to
|
||||||
lua> ".."
|
lua> ".."
|
||||||
local \%lua = \%block:as_lua(nomsu);
|
local \%lua = nomsu:tree_to_lua(\%block);
|
||||||
return Lua(nil, "print(", repr(tostring(\%lua)), ");");
|
return Lua(nil, "print(", repr(tostring(\%lua)), ");");
|
||||||
|
|
||||||
immediately
|
immediately
|
||||||
@ -202,7 +202,7 @@ immediately
|
|||||||
compile [barf] to: Lua "error(nil, 0);"
|
compile [barf] to: Lua "error(nil, 0);"
|
||||||
compile [barf %msg] to: Lua "error(\(%msg as lua expr), 0);"
|
compile [barf %msg] to: Lua "error(\(%msg as lua expr), 0);"
|
||||||
compile [assume %condition] to
|
compile [assume %condition] to
|
||||||
lua> "local \%assumption = 'Assumption failed: '..tostring(\%condition:as_nomsu());"
|
lua> "local \%assumption = 'Assumption failed: '..tostring(nomsu:tree_to_nomsu(\%condition));"
|
||||||
return
|
return
|
||||||
Lua ".."
|
Lua ".."
|
||||||
if not \(%condition as lua expr) then
|
if not \(%condition as lua expr) then
|
||||||
|
@ -25,21 +25,21 @@ immediately
|
|||||||
# TODO: optimize case of [%x,%y] = [1,2]
|
# TODO: optimize case of [%x,%y] = [1,2]
|
||||||
compile [%a is %b, %a = %b, %a == %b] to
|
compile [%a is %b, %a = %b, %a == %b] to
|
||||||
lua> ".."
|
lua> ".."
|
||||||
local safe = {Text=true, Number=true};
|
local safe = {Text=true, Number=true}
|
||||||
local a_lua, b_lua = \%a:as_lua(nomsu), \%b:as_lua(nomsu);
|
local a_lua, b_lua = \(%a as lua), \(%b as lua)
|
||||||
if safe[\%a.type] or safe[\%b.type] then
|
if safe[\%a.type] or safe[\%b.type] then
|
||||||
return Lua.Value(nil, "(", a_lua, " == ", b_lua, ")");
|
return Lua.Value(nil, "(", a_lua, " == ", b_lua, ")")
|
||||||
else
|
else
|
||||||
return Lua.Value(nil, "utils.equivalent(", a_lua, ", ", b_lua, ")");
|
return Lua.Value(nil, "utils.equivalent(", a_lua, ", ", b_lua, ")")
|
||||||
end
|
end
|
||||||
compile [%a isn't %b, %a is not %b, %a not= %b, %a != %b] to
|
compile [%a isn't %b, %a is not %b, %a not= %b, %a != %b] to
|
||||||
lua> ".."
|
lua> ".."
|
||||||
local safe = {Text=true, Number=true};
|
local safe = {Text=true, Number=true}
|
||||||
local a_lua, b_lua = \%a:as_lua(nomsu), \%b:as_lua(nomsu);
|
local a_lua, b_lua = \(%a as lua), \(%b as lua)
|
||||||
if safe[\%a.type] or safe[\%b.type] then
|
if safe[\%a.type] or safe[\%b.type] then
|
||||||
return Lua.Value(nil, "(", a_lua, " ~= ", b_lua, ")");
|
return Lua.Value(nil, "(", a_lua, " ~= ", b_lua, ")")
|
||||||
else
|
else
|
||||||
return Lua.Value(nil, "(not utils.equivalent(", a_lua, ", ", b_lua, "))");
|
return Lua.Value(nil, "(not utils.equivalent(", a_lua, ", ", b_lua, "))")
|
||||||
end
|
end
|
||||||
# For strict identity checking, use (%x's id) is (%y's id)
|
# For strict identity checking, use (%x's id) is (%y's id)
|
||||||
compile [%'s id, id of %] to: Lua value "nomsu.ids[\(% as lua expr)]"
|
compile [%'s id, id of %] to: Lua value "nomsu.ids[\(% as lua expr)]"
|
||||||
@ -47,14 +47,14 @@ immediately
|
|||||||
# Variable assignment operator
|
# Variable assignment operator
|
||||||
immediately
|
immediately
|
||||||
compile [%var <- %value] to
|
compile [%var <- %value] to
|
||||||
lua> "local \%var_lua = \%var:as_lua(nomsu);"
|
lua> "local \%var_lua = \(%var as lua);"
|
||||||
assume %var_lua.is_value or barf "Invalid target for assignment: \%var"
|
assume %var_lua.is_value or barf "Invalid target for assignment: \%var"
|
||||||
lua> "local \%value_lua = \%value:as_lua(nomsu);"
|
lua> "local \%value_lua = \(%value as lua);"
|
||||||
assume %value_lua.is_value or barf "Invalid value for assignment: \%value"
|
assume %value_lua.is_value or barf "Invalid value for assignment: \%value"
|
||||||
lua> ".."
|
lua> ".."
|
||||||
local lua = Lua(nil, \%var_lua, ' = ', \%value_lua, ';');
|
local lua = Lua(nil, \%var_lua, ' = ', \%value_lua, ';')
|
||||||
if \%var.type == 'Var' then
|
if \%var.type == 'Var' then
|
||||||
lua:add_free_vars({\%var});
|
lua:add_free_vars({\%var})
|
||||||
end
|
end
|
||||||
return lua;
|
return lua;
|
||||||
|
|
||||||
@ -64,24 +64,24 @@ immediately
|
|||||||
assume ((%assignments' "type") is "Dict") or barf ".."
|
assume ((%assignments' "type") is "Dict") or barf ".."
|
||||||
Expected a Dict for the assignments part of '<- %' statement, not \%assignments
|
Expected a Dict for the assignments part of '<- %' statement, not \%assignments
|
||||||
lua> ".."
|
lua> ".."
|
||||||
local lhs, rhs = Lua(), Lua();
|
local lhs, rhs = Lua(), Lua()
|
||||||
for i, item in ipairs(\%assignments) do
|
for i, item in ipairs(\%assignments) do
|
||||||
local target, value = item[1], item[2];
|
local \%target, \%value = item[1], item[2]
|
||||||
local target_lua = target:as_lua(nomsu);
|
local target_lua = \(%target as lua)
|
||||||
if not target_lua.is_value then error("Invalid target for assignment: "..target:get_src()); end
|
if not target_lua.is_value then error("Invalid target for assignment: "..\(%target as text)) end
|
||||||
local value_lua = value:as_lua(nomsu);
|
local value_lua = \(%value as lua)
|
||||||
if not value_lua.is_value then error("Invalid value for assignment: "..value:get_src()); end
|
if not value_lua.is_value then error("Invalid value for assignment: "..\(%value as text)) end
|
||||||
if target.type == "Var" then
|
if \%target.type == "Var" then
|
||||||
lhs:add_free_vars({target});
|
lhs:add_free_vars({\%target})
|
||||||
end
|
end
|
||||||
if i > 1 then
|
if i > 1 then
|
||||||
lhs:append(", ");
|
lhs:append(", ")
|
||||||
rhs:append(", ");
|
rhs:append(", ")
|
||||||
end
|
end
|
||||||
lhs:append(target_lua);
|
lhs:append(target_lua)
|
||||||
rhs:append(value_lua);
|
rhs:append(value_lua)
|
||||||
end
|
end
|
||||||
return Lua(nil, lhs, " = ", rhs, ";");
|
return Lua(nil, lhs, " = ", rhs, ";")
|
||||||
|
|
||||||
immediately
|
immediately
|
||||||
compile [external %var <- %value] to
|
compile [external %var <- %value] to
|
||||||
@ -99,31 +99,31 @@ immediately
|
|||||||
compile [with %assignments %body] to
|
compile [with %assignments %body] to
|
||||||
%lua <- (%body as lua statements)
|
%lua <- (%body as lua statements)
|
||||||
lua> ".."
|
lua> ".."
|
||||||
local lhs, rhs = Lua(), Lua();
|
local lhs, rhs = Lua(), Lua()
|
||||||
local vars = {};
|
local vars = {}
|
||||||
for i, item in ipairs(\%assignments) do
|
for i, item in ipairs(\%assignments) do
|
||||||
local target, value = item[1], item[2];
|
local \%target, \%value = item[1], item[2]
|
||||||
if not target.type == "Var" then
|
if not \%target.type == "Var" then
|
||||||
error("Invalid target for 'with' assignment: "..tostring(target));
|
error("Invalid target for 'with' assignment: "..tostring(\%target))
|
||||||
end
|
end
|
||||||
local target_lua = target:as_lua(nomsu);
|
local target_lua = \(%target as lua)
|
||||||
local value_lua = value:as_lua(nomsu);
|
local value_lua = \(%value as lua)
|
||||||
if not value_lua.is_value then
|
if not value_lua.is_value then
|
||||||
error("Invalid value for assignment: "..tostring(value));
|
error("Invalid value for assignment: "..tostring(\%value))
|
||||||
end
|
end
|
||||||
if target.type == "Var" then
|
if \%target.type == "Var" then
|
||||||
lhs:add_free_vars({target});
|
lhs:add_free_vars({\%target})
|
||||||
end
|
end
|
||||||
if i > 1 then
|
if i > 1 then
|
||||||
lhs:append(", ");
|
lhs:append(", ")
|
||||||
rhs:append(", ");
|
rhs:append(", ")
|
||||||
end
|
end
|
||||||
lhs:append(target_lua);
|
lhs:append(target_lua)
|
||||||
rhs:append(value_lua);
|
rhs:append(value_lua)
|
||||||
vars[i] = tostring(target_lua);
|
vars[i] = \%target
|
||||||
end
|
end
|
||||||
\%lua:remove_free_vars(vars);
|
\%lua:remove_free_vars(vars)
|
||||||
\%lua:prepend("local ", lhs, " = ", rhs, ";\n");
|
\%lua:prepend("local ", lhs, " = ", rhs, ";\n")
|
||||||
return
|
return
|
||||||
Lua ".."
|
Lua ".."
|
||||||
do
|
do
|
||||||
|
@ -44,7 +44,7 @@ lua> ".."
|
|||||||
local reset = "'"..colors["reset color"].."'";
|
local reset = "'"..colors["reset color"].."'";
|
||||||
nomsu:define_compile_action(name, function(tree) return Lua.Value(nil, color); end);
|
nomsu:define_compile_action(name, function(tree) return Lua.Value(nil, color); end);
|
||||||
nomsu:define_compile_action(name.." %", function(\%)
|
nomsu:define_compile_action(name.." %", function(\%)
|
||||||
return Lua.Value(nil, color, "..", \%:as_lua(nomsu), "..", reset);
|
return Lua.Value(nil, color, "..", \(% as lua), "..", reset);
|
||||||
end);
|
end);
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
663
nomsu.lua
663
nomsu.lua
@ -249,7 +249,7 @@ end
|
|||||||
local NomsuCompiler
|
local NomsuCompiler
|
||||||
do
|
do
|
||||||
local _class_0
|
local _class_0
|
||||||
local stub_defs, stub_pattern, var_pattern, _nomsu_chunk_counter, _running_files
|
local stub_defs, stub_pattern, var_pattern, _nomsu_chunk_counter, _running_files, MAX_LINE, math_expression
|
||||||
local _base_0 = {
|
local _base_0 = {
|
||||||
define_action = function(self, signature, fn, is_compile_action)
|
define_action = function(self, signature, fn, is_compile_action)
|
||||||
if is_compile_action == nil then
|
if is_compile_action == nil then
|
||||||
@ -284,7 +284,7 @@ do
|
|||||||
local _len_0 = 1
|
local _len_0 = 1
|
||||||
for _index_1 = 1, #stub_args do
|
for _index_1 = 1, #stub_args do
|
||||||
local a = stub_args[_index_1]
|
local a = stub_args[_index_1]
|
||||||
_accum_0[_len_0] = fn_arg_positions[Types.Var.as_lua_id(a)]
|
_accum_0[_len_0] = fn_arg_positions[Types.Var(a):as_lua_id()]
|
||||||
_len_0 = _len_0 + 1
|
_len_0 = _len_0 + 1
|
||||||
end
|
end
|
||||||
arg_orders[stub] = _accum_0
|
arg_orders[stub] = _accum_0
|
||||||
@ -341,7 +341,7 @@ do
|
|||||||
end
|
end
|
||||||
local tree = self:parse(nomsu_code)
|
local tree = self:parse(nomsu_code)
|
||||||
assert(tree, "Failed to parse: " .. tostring(nomsu_code))
|
assert(tree, "Failed to parse: " .. tostring(nomsu_code))
|
||||||
local lua = tree:as_lua(self):as_statements()
|
local lua = self:tree_to_lua(tree):as_statements()
|
||||||
lua:declare_locals()
|
lua:declare_locals()
|
||||||
lua:prepend("-- File: " .. tostring(nomsu_code.source or "") .. "\n")
|
lua:prepend("-- File: " .. tostring(nomsu_code.source or "") .. "\n")
|
||||||
if compile_fn then
|
if compile_fn then
|
||||||
@ -432,11 +432,628 @@ do
|
|||||||
end
|
end
|
||||||
return run_lua_fn()
|
return run_lua_fn()
|
||||||
end,
|
end,
|
||||||
|
tree_to_lua = function(self, tree)
|
||||||
|
local _exp_0 = tree.type
|
||||||
|
if "Action" == _exp_0 then
|
||||||
|
local stub = tree:get_stub()
|
||||||
|
local compile_action = self.environment.COMPILE_ACTIONS[stub]
|
||||||
|
if compile_action then
|
||||||
|
local args
|
||||||
|
do
|
||||||
|
local _accum_0 = { }
|
||||||
|
local _len_0 = 1
|
||||||
|
for _index_0 = 1, #tree do
|
||||||
|
local arg = tree[_index_0]
|
||||||
|
if arg.type ~= "Word" then
|
||||||
|
_accum_0[_len_0] = arg
|
||||||
|
_len_0 = _len_0 + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
args = _accum_0
|
||||||
|
end
|
||||||
|
do
|
||||||
|
local _accum_0 = { }
|
||||||
|
local _len_0 = 1
|
||||||
|
local _list_0 = self.environment.ARG_ORDERS[compile_action][stub]
|
||||||
|
for _index_0 = 1, #_list_0 do
|
||||||
|
local p = _list_0[_index_0]
|
||||||
|
_accum_0[_len_0] = args[p - 1]
|
||||||
|
_len_0 = _len_0 + 1
|
||||||
|
end
|
||||||
|
args = _accum_0
|
||||||
|
end
|
||||||
|
local ret = compile_action(tree, unpack(args))
|
||||||
|
if not ret then
|
||||||
|
error("Failed to produce any Lua")
|
||||||
|
end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
local action = rawget(self.environment.ACTIONS, stub)
|
||||||
|
local lua = Lua.Value()
|
||||||
|
if not action and math_expression:match(stub) then
|
||||||
|
for i, tok in ipairs(tree) do
|
||||||
|
if tok.type == "Word" then
|
||||||
|
lua:append(tok.value)
|
||||||
|
else
|
||||||
|
local tok_lua = self:tree_to_lua(tok)
|
||||||
|
if not (tok_lua.is_value) then
|
||||||
|
error("non-expression value inside math expression: " .. tostring(colored.yellow(repr(tok))))
|
||||||
|
end
|
||||||
|
if tok.type == "Action" then
|
||||||
|
tok_lua:parenthesize()
|
||||||
|
end
|
||||||
|
lua:append(tok_lua)
|
||||||
|
end
|
||||||
|
if i < #tree then
|
||||||
|
lua:append(" ")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return lua
|
||||||
|
end
|
||||||
|
local args = { }
|
||||||
|
for i, tok in ipairs(tree) do
|
||||||
|
local _continue_0 = false
|
||||||
|
repeat
|
||||||
|
if tok.type == "Word" then
|
||||||
|
_continue_0 = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
local arg_lua = self:tree_to_lua(tok)
|
||||||
|
if not (arg_lua.is_value) then
|
||||||
|
error("Cannot use:\n" .. tostring(colored.yellow(repr(tok))) .. "\nas an argument to " .. tostring(stub) .. ", since it's not an expression, it produces: " .. tostring(repr(arg_lua)), 0)
|
||||||
|
end
|
||||||
|
insert(args, arg_lua)
|
||||||
|
_continue_0 = true
|
||||||
|
until true
|
||||||
|
if not _continue_0 then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if action then
|
||||||
|
do
|
||||||
|
local _accum_0 = { }
|
||||||
|
local _len_0 = 1
|
||||||
|
local _list_0 = self.environment.ARG_ORDERS[action][stub]
|
||||||
|
for _index_0 = 1, #_list_0 do
|
||||||
|
local p = _list_0[_index_0]
|
||||||
|
_accum_0[_len_0] = args[p]
|
||||||
|
_len_0 = _len_0 + 1
|
||||||
|
end
|
||||||
|
args = _accum_0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
lua:append("ACTIONS[", repr(stub), "](")
|
||||||
|
for i, arg in ipairs(args) do
|
||||||
|
lua:append(arg)
|
||||||
|
if i < #args then
|
||||||
|
lua:append(", ")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
lua:append(")")
|
||||||
|
return lua
|
||||||
|
elseif "EscapedNomsu" == _exp_0 then
|
||||||
|
local make_tree
|
||||||
|
make_tree = function(t)
|
||||||
|
if type(t) ~= 'userdata' then
|
||||||
|
return repr(t)
|
||||||
|
end
|
||||||
|
if t.is_multi then
|
||||||
|
local bits
|
||||||
|
do
|
||||||
|
local _accum_0 = { }
|
||||||
|
local _len_0 = 1
|
||||||
|
for _index_0 = 1, #t do
|
||||||
|
local bit = t[_index_0]
|
||||||
|
_accum_0[_len_0] = make_tree(bit)
|
||||||
|
_len_0 = _len_0 + 1
|
||||||
|
end
|
||||||
|
bits = _accum_0
|
||||||
|
end
|
||||||
|
return t.type .. "(" .. table.concat(bits, ", ") .. ")"
|
||||||
|
else
|
||||||
|
return t.type .. "(" .. make_tree(t.value) .. ")"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return Lua.Value(nil, make_tree(tree.value))
|
||||||
|
elseif "Block" == _exp_0 then
|
||||||
|
local lua = Lua()
|
||||||
|
for i, line in ipairs(tree) do
|
||||||
|
local line_lua = self:tree_to_lua(line)
|
||||||
|
if i > 1 then
|
||||||
|
lua:append("\n")
|
||||||
|
end
|
||||||
|
lua:append(line_lua:as_statements())
|
||||||
|
end
|
||||||
|
return lua
|
||||||
|
elseif "Text" == _exp_0 then
|
||||||
|
local lua = Lua.Value()
|
||||||
|
local string_buffer = ""
|
||||||
|
for _index_0 = 1, #tree do
|
||||||
|
local _continue_0 = false
|
||||||
|
repeat
|
||||||
|
local bit = tree[_index_0]
|
||||||
|
if type(bit) == "string" then
|
||||||
|
string_buffer = string_buffer .. bit
|
||||||
|
_continue_0 = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
if string_buffer ~= "" then
|
||||||
|
if #lua.bits > 0 then
|
||||||
|
lua:append("..")
|
||||||
|
end
|
||||||
|
lua:append(repr(string_buffer))
|
||||||
|
string_buffer = ""
|
||||||
|
end
|
||||||
|
local bit_lua = self:tree_to_lua(bit)
|
||||||
|
if not (bit_lua.is_value) then
|
||||||
|
error("Cannot use " .. tostring(colored.yellow(repr(bit))) .. " as a string interpolation value, since it's not an expression.", 0)
|
||||||
|
end
|
||||||
|
if #lua.bits > 0 then
|
||||||
|
lua:append("..")
|
||||||
|
end
|
||||||
|
if bit.type ~= "Text" then
|
||||||
|
bit_lua = Lua.Value(nil, "stringify(", bit_lua, ")")
|
||||||
|
end
|
||||||
|
lua:append(bit_lua)
|
||||||
|
_continue_0 = true
|
||||||
|
until true
|
||||||
|
if not _continue_0 then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if string_buffer ~= "" or #lua.bits == 0 then
|
||||||
|
if #lua.bits > 0 then
|
||||||
|
lua:append("..")
|
||||||
|
end
|
||||||
|
lua:append(repr(string_buffer))
|
||||||
|
end
|
||||||
|
if #lua.bits > 1 then
|
||||||
|
lua:parenthesize()
|
||||||
|
end
|
||||||
|
return lua
|
||||||
|
elseif "List" == _exp_0 then
|
||||||
|
local lua = Lua.Value(nil, "{")
|
||||||
|
local line_length = 0
|
||||||
|
for i, item in ipairs(tree) do
|
||||||
|
local item_lua = self:tree_to_lua(item)
|
||||||
|
if not (item_lua.is_value) then
|
||||||
|
error("Cannot use " .. tostring(colored.yellow(repr(item))) .. " as a list item, since it's not an expression.", 0)
|
||||||
|
end
|
||||||
|
lua:append(item_lua)
|
||||||
|
local item_string = tostring(item_lua)
|
||||||
|
local last_line = item_string:match("[^\n]*$")
|
||||||
|
if item_string:match("\n") then
|
||||||
|
line_length = #last_line
|
||||||
|
else
|
||||||
|
line_length = line_length + #last_line
|
||||||
|
end
|
||||||
|
if i < #tree then
|
||||||
|
if line_length >= MAX_LINE then
|
||||||
|
lua:append(",\n ")
|
||||||
|
line_length = 0
|
||||||
|
else
|
||||||
|
lua:append(", ")
|
||||||
|
line_length = line_length + 2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
lua:append("}")
|
||||||
|
return lua
|
||||||
|
elseif "Dict" == _exp_0 then
|
||||||
|
local lua = Lua.Value(nil, "{")
|
||||||
|
local line_length = 0
|
||||||
|
for i, entry in ipairs(tree) do
|
||||||
|
local entry_lua = self:tree_to_lua(entry)
|
||||||
|
lua:append(entry_lua)
|
||||||
|
local entry_lua_str = tostring(entry_lua)
|
||||||
|
local last_line = entry_lua_str:match("\n([^\n]*)$")
|
||||||
|
if last_line then
|
||||||
|
line_length = #last_line
|
||||||
|
else
|
||||||
|
line_length = line_length + #entry_lua_str
|
||||||
|
end
|
||||||
|
if i < #tree then
|
||||||
|
if line_length >= MAX_LINE then
|
||||||
|
lua:append(",\n ")
|
||||||
|
line_length = 0
|
||||||
|
else
|
||||||
|
lua:append(", ")
|
||||||
|
line_length = line_length + 2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
lua:append("}")
|
||||||
|
return lua
|
||||||
|
elseif "DictEntry" == _exp_0 then
|
||||||
|
local key, value = tree[1], tree[2]
|
||||||
|
local key_lua = self:tree_to_lua(key)
|
||||||
|
if not (key_lua.is_value) then
|
||||||
|
error("Cannot use " .. tostring(colored.yellow(repr(key))) .. " as a dict key, since it's not an expression.", 0)
|
||||||
|
end
|
||||||
|
local value_lua = value and self:tree_to_lua(value) or Lua.Value(nil, "true")
|
||||||
|
if not (value_lua.is_value) then
|
||||||
|
error("Cannot use " .. tostring(colored.yellow(repr(value))) .. " as a dict value, since it's not an expression.", 0)
|
||||||
|
end
|
||||||
|
local key_str = tostring(key_lua):match([=[["']([a-zA-Z_][a-zA-Z0-9_]*)['"]]=])
|
||||||
|
if key_str then
|
||||||
|
return Lua(nil, key_str, "=", value_lua)
|
||||||
|
elseif tostring(key_lua):sub(1, 1) == "[" then
|
||||||
|
return Lua(nil, "[ ", key_lua, "]=", value_lua)
|
||||||
|
else
|
||||||
|
return Lua(nil, "[", key_lua, "]=", value_lua)
|
||||||
|
end
|
||||||
|
elseif "IndexChain" == _exp_0 then
|
||||||
|
local lua = self:tree_to_lua(tree[1])
|
||||||
|
if not (lua.is_value) then
|
||||||
|
error("Cannot index " .. tostring(colored.yellow(repr(tree[1]))) .. ", since it's not an expression.", 0)
|
||||||
|
end
|
||||||
|
local first_char = tostring(lua):sub(1, 1)
|
||||||
|
if first_char == "{" or first_char == '"' or first_char == "[" then
|
||||||
|
lua:parenthesize()
|
||||||
|
end
|
||||||
|
for i = 2, #tree do
|
||||||
|
local key = tree[i]
|
||||||
|
local key_lua = self:tree_to_lua(key)
|
||||||
|
if not (key_lua.is_value) then
|
||||||
|
error("Cannot use " .. tostring(colored.yellow(repr(key))) .. " as an index, since it's not an expression.", 0)
|
||||||
|
end
|
||||||
|
local key_lua_str = tostring(key_lua)
|
||||||
|
do
|
||||||
|
local lua_id = key_lua_str:match("^['\"]([a-zA-Z_][a-zA-Z0-9_]*)['\"]$")
|
||||||
|
if lua_id then
|
||||||
|
lua:append("." .. tostring(lua_id))
|
||||||
|
elseif key_lua_str:sub(1, 1) == '[' then
|
||||||
|
lua:append("[ ", key_lua, " ]")
|
||||||
|
else
|
||||||
|
lua:append("[", key_lua, "]")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return lua
|
||||||
|
elseif "Number" == _exp_0 then
|
||||||
|
return Lua.Value(nil, tostring(tree.value))
|
||||||
|
elseif "Var" == _exp_0 then
|
||||||
|
return Lua.Value(nil, tree:as_lua_id())
|
||||||
|
elseif "Word" == _exp_0 then
|
||||||
|
return error("Cannot convert a Word to lua")
|
||||||
|
elseif "Comment" == _exp_0 then
|
||||||
|
return Lua(nil, "--" .. tree.value:gsub("\n", "\n--") .. "\n")
|
||||||
|
else
|
||||||
|
return error("Unknown type: " .. tostring(tree.type))
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
tree_to_nomsu = function(self, tree, inline, can_use_colon)
|
||||||
|
if inline == nil then
|
||||||
|
inline = false
|
||||||
|
end
|
||||||
|
if can_use_colon == nil then
|
||||||
|
can_use_colon = false
|
||||||
|
end
|
||||||
|
local _exp_0 = tree.type
|
||||||
|
if "Action" == _exp_0 then
|
||||||
|
if inline then
|
||||||
|
local nomsu = Nomsu()
|
||||||
|
for i, bit in ipairs(tree) do
|
||||||
|
if bit.type == "Word" then
|
||||||
|
if i > 1 then
|
||||||
|
nomsu:append(" ")
|
||||||
|
end
|
||||||
|
nomsu:append(bit.value)
|
||||||
|
else
|
||||||
|
local arg_nomsu = self:tree_to_nomsu(bit, true)
|
||||||
|
if not (arg_nomsu) then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
if not (i == 1) then
|
||||||
|
nomsu:append(" ")
|
||||||
|
end
|
||||||
|
if bit.type == "Action" or bit.type == "Block" then
|
||||||
|
arg_nomsu:parenthesize()
|
||||||
|
end
|
||||||
|
nomsu:append(arg_nomsu)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nomsu
|
||||||
|
else
|
||||||
|
local nomsu = Nomsu()
|
||||||
|
local next_space = ""
|
||||||
|
local last_colon = nil
|
||||||
|
for i, bit in ipairs(tree) do
|
||||||
|
if bit.type == "Word" then
|
||||||
|
nomsu:append(next_space, bit.value)
|
||||||
|
next_space = " "
|
||||||
|
else
|
||||||
|
local arg_nomsu
|
||||||
|
if last_colon == i - 1 and bit.type == "Action" then
|
||||||
|
arg_nomsu = nil
|
||||||
|
elseif bit.type == "Block" then
|
||||||
|
arg_nomsu = nil
|
||||||
|
else
|
||||||
|
arg_nomsu = self:tree_to_nomsu(bit, true)
|
||||||
|
end
|
||||||
|
if arg_nomsu and #arg_nomsu < MAX_LINE then
|
||||||
|
if bit.type == "Action" then
|
||||||
|
if can_use_colon and i > 1 then
|
||||||
|
nomsu:append(next_space:match("[^ ]*"), ": ", arg_nomsu)
|
||||||
|
next_space = "\n.."
|
||||||
|
last_colon = i
|
||||||
|
else
|
||||||
|
nomsu:append(next_space, "(", arg_nomsu, ")")
|
||||||
|
next_space = " "
|
||||||
|
end
|
||||||
|
else
|
||||||
|
nomsu:append(next_space, arg_nomsu)
|
||||||
|
next_space = " "
|
||||||
|
end
|
||||||
|
else
|
||||||
|
arg_nomsu = self:tree_to_nomsu(bit, nil, true)
|
||||||
|
if not (nomsu) then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
if bit.type ~= "List" and bit.type ~= "Dict" and bit.type ~= "Text" then
|
||||||
|
if i == 1 then
|
||||||
|
arg_nomsu = Nomsu(nil, "(..)\n ", arg_nomsu)
|
||||||
|
else
|
||||||
|
arg_nomsu = Nomsu(nil, "\n ", arg_nomsu)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if last_colon == i - 1 and (bit.type == "Action" or bit.type == "Block") then
|
||||||
|
next_space = ""
|
||||||
|
end
|
||||||
|
nomsu:append(next_space, arg_nomsu)
|
||||||
|
next_space = "\n.."
|
||||||
|
end
|
||||||
|
if next_space == " " and #(tostring(nomsu):match("[^\n]*$")) > MAX_LINE then
|
||||||
|
next_space = "\n.."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nomsu
|
||||||
|
end
|
||||||
|
elseif "EscapedNomsu" == _exp_0 then
|
||||||
|
local nomsu = self:tree_to_nomsu(tree.value, true)
|
||||||
|
if nomsu == nil and not inline then
|
||||||
|
nomsu = self:tree_to_nomsu(tree.value)
|
||||||
|
return nomsu and Nomsu(nil, "\\:\n ", nomsu)
|
||||||
|
end
|
||||||
|
return nomsu and Nomsu(nil, "\\(", nomsu, ")")
|
||||||
|
elseif "Block" == _exp_0 then
|
||||||
|
if inline then
|
||||||
|
local nomsu = Nomsu()
|
||||||
|
for i, line in ipairs(self) do
|
||||||
|
if i > 1 then
|
||||||
|
nomsu:append("; ")
|
||||||
|
end
|
||||||
|
local line_nomsu = self:tree_to_nomsu(line, true)
|
||||||
|
if not (line_nomsu) then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
nomsu:append(line_nomsu)
|
||||||
|
end
|
||||||
|
return nomsu
|
||||||
|
end
|
||||||
|
local nomsu = Nomsu()
|
||||||
|
for i, line in ipairs(self) do
|
||||||
|
line = assert(self:tree_to_nomsu(line, nil, true), "Could not convert line to nomsu")
|
||||||
|
nomsu:append(line)
|
||||||
|
if i < #self then
|
||||||
|
nomsu:append("\n")
|
||||||
|
if tostring(line):match("\n") then
|
||||||
|
nomsu:append("\n")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nomsu
|
||||||
|
elseif "Text" == _exp_0 then
|
||||||
|
if inline then
|
||||||
|
local nomsu = Nomsu(nil, '"')
|
||||||
|
for _index_0 = 1, #tree do
|
||||||
|
local bit = tree[_index_0]
|
||||||
|
if type(bit) == 'string' then
|
||||||
|
nomsu:append((bit:gsub("\\", "\\\\"):gsub("\n", "\\n")))
|
||||||
|
else
|
||||||
|
local interp_nomsu = self:tree_to_nomsu(bit, true)
|
||||||
|
if interp_nomsu then
|
||||||
|
if bit.type ~= "Word" and bit.type ~= "List" and bit.type ~= "Dict" and bit.type ~= "Text" then
|
||||||
|
interp_nomsu:parenthesize()
|
||||||
|
end
|
||||||
|
nomsu:append("\\", interp_nomsu)
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
nomsu:append('"')
|
||||||
|
return nomsu
|
||||||
|
else
|
||||||
|
local inline_version = self:tree_to_nomsu(tree, true)
|
||||||
|
if inline_version and #inline_version <= MAX_LINE then
|
||||||
|
return inline_version
|
||||||
|
end
|
||||||
|
local nomsu = Nomsu(nil, '".."\n ')
|
||||||
|
for i, bit in ipairs(self) do
|
||||||
|
if type(bit) == 'string' then
|
||||||
|
nomsu:append((bit:gsub("\\", "\\\\"):gsub("\n", "\n ")))
|
||||||
|
else
|
||||||
|
local interp_nomsu = self:tree_to_nomsu(bit, true)
|
||||||
|
if interp_nomsu then
|
||||||
|
if bit.type ~= "Word" and bit.type ~= "List" and bit.type ~= "Dict" and bit.type ~= "Text" then
|
||||||
|
interp_nomsu:parenthesize()
|
||||||
|
end
|
||||||
|
nomsu:append("\\", interp_nomsu)
|
||||||
|
else
|
||||||
|
interp_nomsu = self:tree_to_nomsu(bit)
|
||||||
|
if not (interp_nomsu) then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
nomsu:append("\\\n ", interp_nomsu)
|
||||||
|
if i < #self then
|
||||||
|
nomsu:append("\n ..")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nomsu
|
||||||
|
end
|
||||||
|
elseif "List" == _exp_0 then
|
||||||
|
if inline then
|
||||||
|
local nomsu = Nomsu(nil, "[")
|
||||||
|
for i, item in ipairs(tree) do
|
||||||
|
local item_nomsu = self:tree_to_nomsu(item, true)
|
||||||
|
if not (item_nomsu) then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
if i > 1 then
|
||||||
|
nomsu:append(", ")
|
||||||
|
end
|
||||||
|
nomsu:append(item_nomsu)
|
||||||
|
end
|
||||||
|
nomsu:append("]")
|
||||||
|
return nomsu
|
||||||
|
else
|
||||||
|
local inline_version = self:tree_to_nomsu(tree, true)
|
||||||
|
if inline_version and #inline_version <= MAX_LINE then
|
||||||
|
return inline_version
|
||||||
|
end
|
||||||
|
local nomsu = Nomsu(nil, "[..]")
|
||||||
|
local line = Nomsu(nil, "\n ")
|
||||||
|
for _index_0 = 1, #tree do
|
||||||
|
local item = tree[_index_0]
|
||||||
|
local item_nomsu = self:tree_to_nomsu(item, true)
|
||||||
|
if item_nomsu and #line + #", " + #item_nomsu <= MAX_LINE then
|
||||||
|
if #line.bits > 1 then
|
||||||
|
line:append(", ")
|
||||||
|
end
|
||||||
|
line:append(item_nomsu)
|
||||||
|
else
|
||||||
|
if not (item_nomsu) then
|
||||||
|
item_nomsu = self:tree_to_nomsu(item)
|
||||||
|
if not (item_nomsu) then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if #line.bits > 1 then
|
||||||
|
nomsu:append(line)
|
||||||
|
line = Nomsu(nil, "\n ")
|
||||||
|
end
|
||||||
|
line:append(item_nomsu)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if #line.bits > 1 then
|
||||||
|
nomsu:append(line)
|
||||||
|
end
|
||||||
|
return nomsu
|
||||||
|
end
|
||||||
|
elseif "Dict" == _exp_0 then
|
||||||
|
if inline then
|
||||||
|
local nomsu = Nomsu(nil, "{")
|
||||||
|
for i, entry in ipairs(tree) do
|
||||||
|
local entry_nomsu = self:tree_to_nomsu(entry, true)
|
||||||
|
if not (entry_nomsu) then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
if i > 1 then
|
||||||
|
nomsu:append(", ")
|
||||||
|
end
|
||||||
|
nomsu:append(entry_nomsu)
|
||||||
|
end
|
||||||
|
nomsu:append("}")
|
||||||
|
return nomsu
|
||||||
|
else
|
||||||
|
local inline_version = self:tree_to_nomsu(tree, true)
|
||||||
|
if inline_version then
|
||||||
|
return inline_version
|
||||||
|
end
|
||||||
|
local nomsu = Nomsu(nil, "{..}")
|
||||||
|
local line = Nomsu(nil, "\n ")
|
||||||
|
for _index_0 = 1, #tree do
|
||||||
|
local entry = tree[_index_0]
|
||||||
|
local entry_nomsu = self:tree_to_nomsu(entry)
|
||||||
|
if not (entry_nomsu) then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
if #line + #tostring(entry_nomsu) <= MAX_LINE then
|
||||||
|
if #line.bits > 1 then
|
||||||
|
line:append(", ")
|
||||||
|
end
|
||||||
|
line:append(entry_nomsu)
|
||||||
|
else
|
||||||
|
if #line.bits > 1 then
|
||||||
|
nomsu:append(line)
|
||||||
|
line = Nomsu(nil, "\n ")
|
||||||
|
end
|
||||||
|
line:append(entry_nomsu)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if #line.bits > 1 then
|
||||||
|
nomsu:append(line)
|
||||||
|
end
|
||||||
|
return nomsu
|
||||||
|
end
|
||||||
|
elseif "DictEntry" == _exp_0 then
|
||||||
|
local key, value = tree[1], tree[2]
|
||||||
|
local key_nomsu = self:tree_to_nomsu(key, true)
|
||||||
|
if not (key_nomsu) then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
if key.type == "Action" or key.type == "Block" then
|
||||||
|
key_nomsu:parenthesize()
|
||||||
|
end
|
||||||
|
local value_nomsu
|
||||||
|
if value then
|
||||||
|
value_nomsu = self:tree_to_nomsu(value, true)
|
||||||
|
else
|
||||||
|
value_nomsu = Nomsu(nil, "")
|
||||||
|
end
|
||||||
|
if inline and not value_nomsu then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
if not value_nomsu then
|
||||||
|
if inline then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
value_nomsu = self:tree_to_nomsu(value)
|
||||||
|
if not (value_nomsu) then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return Nomsu(nil, key_nomsu, ":", value_nomsu)
|
||||||
|
elseif "IndexChain" == _exp_0 then
|
||||||
|
local nomsu = Nomsu()
|
||||||
|
for i, bit in ipairs(tree) do
|
||||||
|
if i > 1 then
|
||||||
|
nomsu:append(".")
|
||||||
|
end
|
||||||
|
local bit_nomsu = self:tree_to_nomsu(bit, true)
|
||||||
|
if not (bit_nomsu) then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
if bit.type == "Action" or bit.type == "Block" then
|
||||||
|
bit_nomsu:parenthesize()
|
||||||
|
end
|
||||||
|
nomsu:append(bit_nomsu)
|
||||||
|
end
|
||||||
|
return nomsu
|
||||||
|
elseif "Number" == _exp_0 then
|
||||||
|
return Nomsu(nil, tostring(tree.value))
|
||||||
|
elseif "Var" == _exp_0 then
|
||||||
|
return Nomsu(nil, "%", tree.value)
|
||||||
|
elseif "Word" == _exp_0 then
|
||||||
|
return Nomsu(nil, tree.value)
|
||||||
|
elseif "Comment" == _exp_0 then
|
||||||
|
if inline then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
return Nomsu(nil, "#", tree.value:gsub("\n", "\n "))
|
||||||
|
else
|
||||||
|
return error("Unknown type: " .. tostring(tree.type))
|
||||||
|
end
|
||||||
|
end,
|
||||||
tree_to_value = function(self, tree)
|
tree_to_value = function(self, tree)
|
||||||
if tree.type == 'Text' and #tree == 1 and type(tree[1]) == 'string' then
|
if tree.type == 'Text' and #tree == 1 and type(tree[1]) == 'string' then
|
||||||
return tree[1]
|
return tree[1]
|
||||||
end
|
end
|
||||||
local lua = Lua(nil, "return ", tree:as_lua(self), ";")
|
local lua = Lua(nil, "return ", self:tree_to_lua(tree), ";")
|
||||||
return self:run_lua(lua)
|
return self:run_lua(lua)
|
||||||
end,
|
end,
|
||||||
walk_tree = function(self, tree, depth)
|
walk_tree = function(self, tree, depth)
|
||||||
@ -456,32 +1073,10 @@ do
|
|||||||
return self:walk_tree(v, depth + 1)
|
return self:walk_tree(v, depth + 1)
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
tree_with_replacements = function(self, tree, replacements)
|
|
||||||
if not (next(replacements)) then
|
|
||||||
return tree
|
|
||||||
end
|
|
||||||
if next(replacements).type == "Var" then
|
|
||||||
do
|
|
||||||
local _tbl_0 = { }
|
|
||||||
for k, v in pairs(replacements) do
|
|
||||||
_tbl_0[tostring(k:as_lua(self))] = v
|
|
||||||
end
|
|
||||||
replacements = _tbl_0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return tree:map(function(t)
|
|
||||||
if t.type == "Var" then
|
|
||||||
local id = tostring(t:as_lua(self))
|
|
||||||
if replacements[id] ~= nil then
|
|
||||||
return replacements[id]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end,
|
|
||||||
initialize_core = function(self)
|
initialize_core = function(self)
|
||||||
local nomsu = self
|
local nomsu = self
|
||||||
self:define_compile_action("immediately %block", function(self, _block)
|
self:define_compile_action("immediately %block", function(self, _block)
|
||||||
local lua = _block:as_lua(nomsu):as_statements()
|
local lua = nomsu:tree_to_lua(_block):as_statements()
|
||||||
lua:declare_locals()
|
lua:declare_locals()
|
||||||
nomsu:run_lua(lua)
|
nomsu:run_lua(lua)
|
||||||
return Lua(nil, "if IMMEDIATE then\n ", lua, "\nend")
|
return Lua(nil, "if IMMEDIATE then\n ", lua, "\nend")
|
||||||
@ -489,7 +1084,7 @@ do
|
|||||||
local add_lua_string_bits
|
local add_lua_string_bits
|
||||||
add_lua_string_bits = function(lua, code)
|
add_lua_string_bits = function(lua, code)
|
||||||
if code.type ~= "Text" then
|
if code.type ~= "Text" then
|
||||||
lua:append(", ", code:as_lua(nomsu))
|
lua:append(", ", nomsu:tree_to_lua(code))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
for _index_0 = 1, #code do
|
for _index_0 = 1, #code do
|
||||||
@ -498,7 +1093,7 @@ do
|
|||||||
if type(bit) == "string" then
|
if type(bit) == "string" then
|
||||||
lua:append(repr(bit))
|
lua:append(repr(bit))
|
||||||
else
|
else
|
||||||
local bit_lua = bit:as_lua(nomsu)
|
local bit_lua = nomsu:tree_to_lua(bit)
|
||||||
if not (bit_lua.is_value) then
|
if not (bit_lua.is_value) then
|
||||||
error("Cannot use " .. tostring(colored.yellow(repr(bit))) .. " as a string interpolation value, since it's not an expression.")
|
error("Cannot use " .. tostring(colored.yellow(repr(bit))) .. " as a string interpolation value, since it's not an expression.")
|
||||||
end
|
end
|
||||||
@ -525,7 +1120,7 @@ do
|
|||||||
if type(bit) == "string" then
|
if type(bit) == "string" then
|
||||||
lua:append(bit)
|
lua:append(bit)
|
||||||
else
|
else
|
||||||
local bit_lua = bit:as_lua(nomsu)
|
local bit_lua = nomsu:tree_to_lua(bit)
|
||||||
if not (bit_lua.is_value) then
|
if not (bit_lua.is_value) then
|
||||||
error("Cannot use " .. tostring(colored.yellow(repr(bit))) .. " as a string interpolation value, since it's not an expression.", 0)
|
error("Cannot use " .. tostring(colored.yellow(repr(bit))) .. " as a string interpolation value, since it's not an expression.", 0)
|
||||||
end
|
end
|
||||||
@ -536,13 +1131,13 @@ do
|
|||||||
end
|
end
|
||||||
self:define_compile_action("lua> %code", function(self, _code)
|
self:define_compile_action("lua> %code", function(self, _code)
|
||||||
if _code.type ~= "Text" then
|
if _code.type ~= "Text" then
|
||||||
return Lua(nil, "nomsu:run_lua(", _code:as_lua(nomsu), ");")
|
return Lua(nil, "nomsu:run_lua(", nomsu:tree_to_lua(_code), ");")
|
||||||
end
|
end
|
||||||
return add_lua_bits(Lua(), _code)
|
return add_lua_bits(Lua(), _code)
|
||||||
end)
|
end)
|
||||||
self:define_compile_action("=lua %code", function(self, _code)
|
self:define_compile_action("=lua %code", function(self, _code)
|
||||||
if _code.type ~= "Text" then
|
if _code.type ~= "Text" then
|
||||||
return Lua.Value(nil, "nomsu:run_lua(", _code:as_lua(nomsu), ":as_statements('return '))")
|
return Lua.Value(nil, "nomsu:run_lua(", nomsu:tree_to_lua(_code), ":as_statements('return '))")
|
||||||
end
|
end
|
||||||
return add_lua_bits(Lua.Value(), _code)
|
return add_lua_bits(Lua.Value(), _code)
|
||||||
end)
|
end)
|
||||||
@ -715,6 +1310,8 @@ do
|
|||||||
var_pattern = re.compile("{| %space ((('%' {%varname}) / %word) %space)+ |}", stub_defs)
|
var_pattern = re.compile("{| %space ((('%' {%varname}) / %word) %space)+ |}", stub_defs)
|
||||||
_nomsu_chunk_counter = 0
|
_nomsu_chunk_counter = 0
|
||||||
_running_files = { }
|
_running_files = { }
|
||||||
|
MAX_LINE = 80
|
||||||
|
math_expression = re.compile([[ ([+-] " ")* "%" (" " [*/^+-] (" " [+-])* " %")+ !. ]])
|
||||||
NomsuCompiler = _class_0
|
NomsuCompiler = _class_0
|
||||||
end
|
end
|
||||||
if arg and debug_getinfo(2).func ~= require then
|
if arg and debug_getinfo(2).func ~= require then
|
||||||
@ -953,7 +1550,7 @@ OPTIONS
|
|||||||
elseif args.format then
|
elseif args.format then
|
||||||
for input_file in all_files(input) do
|
for input_file in all_files(input) do
|
||||||
local tree = nomsu:parse(io.open(input_file):read("*a"))
|
local tree = nomsu:parse(io.open(input_file):read("*a"))
|
||||||
local formatted = tostring(tree:as_nomsu())
|
local formatted = tostring(self:tree_to_nomsu(tree))
|
||||||
if output_file then
|
if output_file then
|
||||||
output_file:write(formatted, "\n")
|
output_file:write(formatted, "\n")
|
||||||
output_file:flush()
|
output_file:flush()
|
||||||
|
479
nomsu.moon
479
nomsu.moon
@ -306,7 +306,7 @@ class NomsuCompiler
|
|||||||
stub = assert(stub_pattern\match(alias))
|
stub = assert(stub_pattern\match(alias))
|
||||||
stub_args = assert(var_pattern\match(alias))
|
stub_args = assert(var_pattern\match(alias))
|
||||||
(is_compile_action and @environment.COMPILE_ACTIONS or @environment.ACTIONS)[stub] = fn
|
(is_compile_action and @environment.COMPILE_ACTIONS or @environment.ACTIONS)[stub] = fn
|
||||||
arg_orders[stub] = [fn_arg_positions[Types.Var.as_lua_id(a)] for a in *stub_args]
|
arg_orders[stub] = [fn_arg_positions[Types.Var(a)\as_lua_id!] for a in *stub_args]
|
||||||
@environment.ARG_ORDERS[fn] = arg_orders
|
@environment.ARG_ORDERS[fn] = arg_orders
|
||||||
|
|
||||||
define_compile_action: (signature, fn)=>
|
define_compile_action: (signature, fn)=>
|
||||||
@ -341,7 +341,7 @@ class NomsuCompiler
|
|||||||
if #tostring(nomsu_code) == 0 then return nil
|
if #tostring(nomsu_code) == 0 then return nil
|
||||||
tree = @parse(nomsu_code)
|
tree = @parse(nomsu_code)
|
||||||
assert tree, "Failed to parse: #{nomsu_code}"
|
assert tree, "Failed to parse: #{nomsu_code}"
|
||||||
lua = tree\as_lua(@)\as_statements!
|
lua = @tree_to_lua(tree)\as_statements!
|
||||||
lua\declare_locals!
|
lua\declare_locals!
|
||||||
lua\prepend "-- File: #{nomsu_code.source or ""}\n"
|
lua\prepend "-- File: #{nomsu_code.source or ""}\n"
|
||||||
if compile_fn
|
if compile_fn
|
||||||
@ -401,12 +401,461 @@ class NomsuCompiler
|
|||||||
line_numbered_lua = "1 |"..lua_string\gsub("\n", fn)
|
line_numbered_lua = "1 |"..lua_string\gsub("\n", fn)
|
||||||
error("Failed to compile generated code:\n#{colored.bright colored.blue colored.onblack line_numbered_lua}\n\n#{err}", 0)
|
error("Failed to compile generated code:\n#{colored.bright colored.blue colored.onblack line_numbered_lua}\n\n#{err}", 0)
|
||||||
return run_lua_fn!
|
return run_lua_fn!
|
||||||
|
|
||||||
|
MAX_LINE = 80 -- For beautification purposes, try not to make lines much longer than this value
|
||||||
|
math_expression = re.compile [[ ([+-] " ")* "%" (" " [*/^+-] (" " [+-])* " %")+ !. ]]
|
||||||
|
tree_to_lua: (tree)=>
|
||||||
|
switch tree.type
|
||||||
|
when "Action"
|
||||||
|
stub = tree\get_stub!
|
||||||
|
compile_action = @environment.COMPILE_ACTIONS[stub]
|
||||||
|
if compile_action
|
||||||
|
args = [arg for arg in *tree when arg.type != "Word"]
|
||||||
|
-- Force all compile-time actions to take a tree location
|
||||||
|
args = [args[p-1] for p in *@environment.ARG_ORDERS[compile_action][stub]]
|
||||||
|
-- Force Lua to avoid tail call optimization for debugging purposes
|
||||||
|
ret = compile_action(tree, unpack(args))
|
||||||
|
if not ret then error("Failed to produce any Lua")
|
||||||
|
return ret
|
||||||
|
action = rawget(@environment.ACTIONS, stub)
|
||||||
|
lua = Lua.Value!
|
||||||
|
if not action and math_expression\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.
|
||||||
|
for i,tok in ipairs tree
|
||||||
|
if tok.type == "Word"
|
||||||
|
lua\append tok.value
|
||||||
|
else
|
||||||
|
tok_lua = @tree_to_lua(tok)
|
||||||
|
unless tok_lua.is_value
|
||||||
|
error("non-expression value inside math expression: #{colored.yellow repr(tok)}")
|
||||||
|
if tok.type == "Action"
|
||||||
|
tok_lua\parenthesize!
|
||||||
|
lua\append tok_lua
|
||||||
|
if i < #tree
|
||||||
|
lua\append " "
|
||||||
|
return lua
|
||||||
|
|
||||||
|
args = {}
|
||||||
|
for i, tok in ipairs tree
|
||||||
|
if tok.type == "Word" then continue
|
||||||
|
arg_lua = @tree_to_lua(tok)
|
||||||
|
unless arg_lua.is_value
|
||||||
|
error "Cannot use:\n#{colored.yellow repr(tok)}\nas an argument to #{stub}, since it's not an expression, it produces: #{repr arg_lua}", 0
|
||||||
|
insert args, arg_lua
|
||||||
|
|
||||||
|
if action
|
||||||
|
args = [args[p] for p in *@environment.ARG_ORDERS[action][stub]]
|
||||||
|
|
||||||
|
-- Not really worth bothering with ACTIONS.foo(...) style since almost every action
|
||||||
|
-- has arguments, so it won't work
|
||||||
|
lua\append "ACTIONS[",repr(stub),"]("
|
||||||
|
for i, arg in ipairs args
|
||||||
|
lua\append arg
|
||||||
|
if i < #args then lua\append ", "
|
||||||
|
lua\append ")"
|
||||||
|
return lua
|
||||||
|
|
||||||
|
when "EscapedNomsu"
|
||||||
|
make_tree = (t)->
|
||||||
|
if type(t) != 'userdata'
|
||||||
|
return repr(t)
|
||||||
|
if t.is_multi
|
||||||
|
bits = [make_tree(bit) for bit in *t]
|
||||||
|
return t.type.."("..table.concat(bits, ", ")..")"
|
||||||
|
else
|
||||||
|
return t.type.."("..make_tree(t.value)..")"
|
||||||
|
Lua.Value nil, make_tree(tree.value)
|
||||||
|
|
||||||
|
when "Block"
|
||||||
|
lua = Lua!
|
||||||
|
for i,line in ipairs tree
|
||||||
|
line_lua = @tree_to_lua(line)
|
||||||
|
if i > 1
|
||||||
|
lua\append "\n"
|
||||||
|
lua\append line_lua\as_statements!
|
||||||
|
return lua
|
||||||
|
|
||||||
|
when "Text"
|
||||||
|
lua = Lua.Value!
|
||||||
|
string_buffer = ""
|
||||||
|
for bit in *tree
|
||||||
|
if type(bit) == "string"
|
||||||
|
string_buffer ..= bit
|
||||||
|
continue
|
||||||
|
if string_buffer ~= ""
|
||||||
|
if #lua.bits > 0 then lua\append ".."
|
||||||
|
lua\append repr(string_buffer)
|
||||||
|
string_buffer = ""
|
||||||
|
bit_lua = @tree_to_lua(bit)
|
||||||
|
unless bit_lua.is_value
|
||||||
|
error "Cannot use #{colored.yellow repr(bit)} as a string interpolation value, since it's not an expression.", 0
|
||||||
|
if #lua.bits > 0 then lua\append ".."
|
||||||
|
if bit.type != "Text"
|
||||||
|
bit_lua = Lua.Value(nil, "stringify(",bit_lua,")")
|
||||||
|
lua\append bit_lua
|
||||||
|
|
||||||
|
if string_buffer ~= "" or #lua.bits == 0
|
||||||
|
if #lua.bits > 0 then lua\append ".."
|
||||||
|
lua\append repr(string_buffer)
|
||||||
|
|
||||||
|
if #lua.bits > 1
|
||||||
|
lua\parenthesize!
|
||||||
|
return lua
|
||||||
|
|
||||||
|
when "List"
|
||||||
|
lua = Lua.Value nil, "{"
|
||||||
|
line_length = 0
|
||||||
|
for i, item in ipairs tree
|
||||||
|
item_lua = @tree_to_lua(item)
|
||||||
|
unless item_lua.is_value
|
||||||
|
error "Cannot use #{colored.yellow repr(item)} as a list item, since it's not an expression.", 0
|
||||||
|
lua\append item_lua
|
||||||
|
item_string = tostring(item_lua)
|
||||||
|
last_line = item_string\match("[^\n]*$")
|
||||||
|
if item_string\match("\n")
|
||||||
|
line_length = #last_line
|
||||||
|
else
|
||||||
|
line_length += #last_line
|
||||||
|
if i < #tree
|
||||||
|
if line_length >= MAX_LINE
|
||||||
|
lua\append ",\n "
|
||||||
|
line_length = 0
|
||||||
|
else
|
||||||
|
lua\append ", "
|
||||||
|
line_length += 2
|
||||||
|
lua\append "}"
|
||||||
|
return lua
|
||||||
|
|
||||||
|
when "Dict"
|
||||||
|
lua = Lua.Value nil, "{"
|
||||||
|
line_length = 0
|
||||||
|
for i, entry in ipairs tree
|
||||||
|
entry_lua = @tree_to_lua(entry)
|
||||||
|
lua\append entry_lua
|
||||||
|
entry_lua_str = tostring(entry_lua)
|
||||||
|
-- TODO: maybe make this more accurate? It's only a heuristic, so eh...
|
||||||
|
last_line = entry_lua_str\match("\n([^\n]*)$")
|
||||||
|
if last_line
|
||||||
|
line_length = #last_line
|
||||||
|
else
|
||||||
|
line_length += #entry_lua_str
|
||||||
|
if i < #tree
|
||||||
|
if line_length >= MAX_LINE
|
||||||
|
lua\append ",\n "
|
||||||
|
line_length = 0
|
||||||
|
else
|
||||||
|
lua\append ", "
|
||||||
|
line_length += 2
|
||||||
|
lua\append "}"
|
||||||
|
return lua
|
||||||
|
|
||||||
|
when "DictEntry"
|
||||||
|
key, value = tree[1], tree[2]
|
||||||
|
key_lua = @tree_to_lua(key)
|
||||||
|
unless key_lua.is_value
|
||||||
|
error "Cannot use #{colored.yellow repr(key)} as a dict key, since it's not an expression.", 0
|
||||||
|
value_lua = value and @tree_to_lua(value) or Lua.Value(nil, "true")
|
||||||
|
unless value_lua.is_value
|
||||||
|
error "Cannot use #{colored.yellow repr(value)} as a dict value, since it's not an expression.", 0
|
||||||
|
key_str = tostring(key_lua)\match([=[["']([a-zA-Z_][a-zA-Z0-9_]*)['"]]=])
|
||||||
|
return if key_str
|
||||||
|
Lua nil, key_str,"=",value_lua
|
||||||
|
elseif tostring(key_lua)\sub(1,1) == "["
|
||||||
|
-- NOTE: this *must* use a space after the [ to avoid freaking out
|
||||||
|
-- Lua's parser if the inner expression is a long string. Lua
|
||||||
|
-- parses x[[[y]]] as x("[y]"), not as x["y"]
|
||||||
|
Lua nil, "[ ",key_lua,"]=",value_lua
|
||||||
|
else
|
||||||
|
Lua nil, "[",key_lua,"]=",value_lua
|
||||||
|
|
||||||
|
when "IndexChain"
|
||||||
|
lua = @tree_to_lua(tree[1])
|
||||||
|
unless lua.is_value
|
||||||
|
error "Cannot index #{colored.yellow repr(tree[1])}, since it's not an expression.", 0
|
||||||
|
first_char = tostring(lua)\sub(1,1)
|
||||||
|
if first_char == "{" or first_char == '"' or first_char == "["
|
||||||
|
lua\parenthesize!
|
||||||
|
|
||||||
|
for i=2,#tree
|
||||||
|
key = tree[i]
|
||||||
|
key_lua = @tree_to_lua(key)
|
||||||
|
unless key_lua.is_value
|
||||||
|
error "Cannot use #{colored.yellow repr(key)} as an index, since it's not an expression.", 0
|
||||||
|
key_lua_str = tostring(key_lua)
|
||||||
|
if lua_id = key_lua_str\match("^['\"]([a-zA-Z_][a-zA-Z0-9_]*)['\"]$")
|
||||||
|
lua\append ".#{lua_id}"
|
||||||
|
elseif key_lua_str\sub(1,1) == '['
|
||||||
|
-- NOTE: this *must* use a space after the [ to avoid freaking out
|
||||||
|
-- Lua's parser if the inner expression is a long string. Lua
|
||||||
|
-- parses x[[[y]]] as x("[y]"), not as x["y"]
|
||||||
|
lua\append "[ ",key_lua," ]"
|
||||||
|
else
|
||||||
|
lua\append "[",key_lua,"]"
|
||||||
|
return lua
|
||||||
|
|
||||||
|
when "Number"
|
||||||
|
Lua.Value(nil, tostring(tree.value))
|
||||||
|
|
||||||
|
when "Var"
|
||||||
|
Lua.Value(nil, tree\as_lua_id!)
|
||||||
|
|
||||||
|
when "Word"
|
||||||
|
error("Cannot convert a Word to lua")
|
||||||
|
|
||||||
|
when "Comment"
|
||||||
|
Lua(nil, "--"..tree.value\gsub("\n","\n--").."\n")
|
||||||
|
|
||||||
|
else
|
||||||
|
error("Unknown type: #{tree.type}")
|
||||||
|
|
||||||
|
|
||||||
|
tree_to_nomsu: (tree, inline=false, can_use_colon=false)=>
|
||||||
|
switch tree.type
|
||||||
|
when "Action"
|
||||||
|
if inline
|
||||||
|
nomsu = Nomsu!
|
||||||
|
for i,bit in ipairs tree
|
||||||
|
if bit.type == "Word"
|
||||||
|
if i > 1
|
||||||
|
nomsu\append " "
|
||||||
|
nomsu\append bit.value
|
||||||
|
else
|
||||||
|
arg_nomsu = @tree_to_nomsu(bit,true)
|
||||||
|
return nil unless arg_nomsu
|
||||||
|
unless i == 1
|
||||||
|
nomsu\append " "
|
||||||
|
if bit.type == "Action" or bit.type == "Block"
|
||||||
|
arg_nomsu\parenthesize!
|
||||||
|
nomsu\append arg_nomsu
|
||||||
|
return nomsu
|
||||||
|
else
|
||||||
|
nomsu = Nomsu!
|
||||||
|
next_space = ""
|
||||||
|
-- TODO: track line length as we go and use 80-that instead of 80 for wrapping
|
||||||
|
last_colon = nil
|
||||||
|
for i,bit in ipairs tree
|
||||||
|
if bit.type == "Word"
|
||||||
|
nomsu\append next_space, bit.value
|
||||||
|
next_space = " "
|
||||||
|
else
|
||||||
|
arg_nomsu = if last_colon == i-1 and bit.type == "Action" then nil
|
||||||
|
elseif bit.type == "Block" then nil
|
||||||
|
else @tree_to_nomsu(bit,true)
|
||||||
|
|
||||||
|
if arg_nomsu and #arg_nomsu < MAX_LINE
|
||||||
|
if bit.type == "Action"
|
||||||
|
if can_use_colon and i > 1
|
||||||
|
nomsu\append next_space\match("[^ ]*"), ": ", arg_nomsu
|
||||||
|
next_space = "\n.."
|
||||||
|
last_colon = i
|
||||||
|
else
|
||||||
|
nomsu\append next_space, "(", arg_nomsu, ")"
|
||||||
|
next_space = " "
|
||||||
|
else
|
||||||
|
nomsu\append next_space, arg_nomsu
|
||||||
|
next_space = " "
|
||||||
|
else
|
||||||
|
arg_nomsu = @tree_to_nomsu(bit, nil, true)
|
||||||
|
return nil unless nomsu
|
||||||
|
-- These types carry their own indentation
|
||||||
|
if bit.type != "List" and bit.type != "Dict" and bit.type != "Text"
|
||||||
|
if i == 1
|
||||||
|
arg_nomsu = Nomsu(nil, "(..)\n ", arg_nomsu)
|
||||||
|
else
|
||||||
|
arg_nomsu = Nomsu(nil, "\n ", arg_nomsu)
|
||||||
|
|
||||||
|
if last_colon == i-1 and (bit.type == "Action" or bit.type == "Block")
|
||||||
|
next_space = ""
|
||||||
|
nomsu\append next_space, arg_nomsu
|
||||||
|
next_space = "\n.."
|
||||||
|
|
||||||
|
if next_space == " " and #(tostring(nomsu)\match("[^\n]*$")) > MAX_LINE
|
||||||
|
next_space = "\n.."
|
||||||
|
return nomsu
|
||||||
|
|
||||||
|
when "EscapedNomsu"
|
||||||
|
nomsu = @tree_to_nomsu(tree.value, true)
|
||||||
|
if nomsu == nil and not inline
|
||||||
|
nomsu = @tree_to_nomsu(tree.value)
|
||||||
|
return nomsu and Nomsu nil, "\\:\n ", nomsu
|
||||||
|
return nomsu and Nomsu nil, "\\(", nomsu, ")"
|
||||||
|
|
||||||
|
when "Block"
|
||||||
|
if inline
|
||||||
|
nomsu = Nomsu!
|
||||||
|
for i,line in ipairs @
|
||||||
|
if i > 1
|
||||||
|
nomsu\append "; "
|
||||||
|
line_nomsu = @tree_to_nomsu(line,true)
|
||||||
|
return nil unless line_nomsu
|
||||||
|
nomsu\append line_nomsu
|
||||||
|
return nomsu
|
||||||
|
nomsu = Nomsu!
|
||||||
|
for i, line in ipairs @
|
||||||
|
line = assert(@tree_to_nomsu(line, nil, true), "Could not convert line to nomsu")
|
||||||
|
nomsu\append line
|
||||||
|
if i < #@
|
||||||
|
nomsu\append "\n"
|
||||||
|
if tostring(line)\match("\n")
|
||||||
|
nomsu\append "\n"
|
||||||
|
return nomsu
|
||||||
|
|
||||||
|
when "Text"
|
||||||
|
if inline
|
||||||
|
nomsu = Nomsu(nil, '"')
|
||||||
|
for bit in *tree
|
||||||
|
if type(bit) == 'string'
|
||||||
|
-- TODO: unescape better?
|
||||||
|
nomsu\append (bit\gsub("\\","\\\\")\gsub("\n","\\n"))
|
||||||
|
else
|
||||||
|
interp_nomsu = @tree_to_nomsu(bit, true)
|
||||||
|
if interp_nomsu
|
||||||
|
if bit.type != "Word" and bit.type != "List" and bit.type != "Dict" and bit.type != "Text"
|
||||||
|
interp_nomsu\parenthesize!
|
||||||
|
nomsu\append "\\", interp_nomsu
|
||||||
|
else return nil
|
||||||
|
nomsu\append '"'
|
||||||
|
return nomsu
|
||||||
|
else
|
||||||
|
inline_version = @tree_to_nomsu(tree, true)
|
||||||
|
if inline_version and #inline_version <= MAX_LINE
|
||||||
|
return inline_version
|
||||||
|
nomsu = Nomsu(nil, '".."\n ')
|
||||||
|
for i, bit in ipairs @
|
||||||
|
if type(bit) == 'string'
|
||||||
|
nomsu\append (bit\gsub("\\","\\\\")\gsub("\n","\n "))
|
||||||
|
else
|
||||||
|
interp_nomsu = @tree_to_nomsu(bit, true)
|
||||||
|
if interp_nomsu
|
||||||
|
if bit.type != "Word" and bit.type != "List" and bit.type != "Dict" and bit.type != "Text"
|
||||||
|
interp_nomsu\parenthesize!
|
||||||
|
nomsu\append "\\", interp_nomsu
|
||||||
|
else
|
||||||
|
interp_nomsu = @tree_to_nomsu(bit)
|
||||||
|
return nil unless interp_nomsu
|
||||||
|
nomsu\append "\\\n ", interp_nomsu
|
||||||
|
if i < #@
|
||||||
|
nomsu\append "\n .."
|
||||||
|
return nomsu
|
||||||
|
|
||||||
|
when "List"
|
||||||
|
if inline
|
||||||
|
nomsu = Nomsu(nil, "[")
|
||||||
|
for i, item in ipairs tree
|
||||||
|
item_nomsu = @tree_to_nomsu(item, true)
|
||||||
|
return nil unless item_nomsu
|
||||||
|
if i > 1
|
||||||
|
nomsu\append ", "
|
||||||
|
nomsu\append item_nomsu
|
||||||
|
nomsu\append "]"
|
||||||
|
return nomsu
|
||||||
|
else
|
||||||
|
inline_version = @tree_to_nomsu(tree, true)
|
||||||
|
if inline_version and #inline_version <= MAX_LINE
|
||||||
|
return inline_version
|
||||||
|
nomsu = Nomsu(nil, "[..]")
|
||||||
|
line = Nomsu(nil, "\n ")
|
||||||
|
for item in *tree
|
||||||
|
item_nomsu = @tree_to_nomsu(item, true)
|
||||||
|
if item_nomsu and #line + #", " + #item_nomsu <= MAX_LINE
|
||||||
|
if #line.bits > 1
|
||||||
|
line\append ", "
|
||||||
|
line\append item_nomsu
|
||||||
|
else
|
||||||
|
unless item_nomsu
|
||||||
|
item_nomsu = @tree_to_nomsu(item)
|
||||||
|
return nil unless item_nomsu
|
||||||
|
if #line.bits > 1
|
||||||
|
nomsu\append line
|
||||||
|
line = Nomsu(nil, "\n ")
|
||||||
|
line\append item_nomsu
|
||||||
|
if #line.bits > 1
|
||||||
|
nomsu\append line
|
||||||
|
return nomsu
|
||||||
|
|
||||||
|
when "Dict"
|
||||||
|
if inline
|
||||||
|
nomsu = Nomsu(nil, "{")
|
||||||
|
for i, entry in ipairs tree
|
||||||
|
entry_nomsu = @tree_to_nomsu(entry, true)
|
||||||
|
return nil unless entry_nomsu
|
||||||
|
if i > 1
|
||||||
|
nomsu\append ", "
|
||||||
|
nomsu\append entry_nomsu
|
||||||
|
nomsu\append "}"
|
||||||
|
return nomsu
|
||||||
|
else
|
||||||
|
inline_version = @tree_to_nomsu(tree, true)
|
||||||
|
if inline_version then return inline_version
|
||||||
|
nomsu = Nomsu(nil, "{..}")
|
||||||
|
line = Nomsu(nil, "\n ")
|
||||||
|
for entry in *tree
|
||||||
|
entry_nomsu = @tree_to_nomsu(entry)
|
||||||
|
return nil unless entry_nomsu
|
||||||
|
if #line + #tostring(entry_nomsu) <= MAX_LINE
|
||||||
|
if #line.bits > 1
|
||||||
|
line\append ", "
|
||||||
|
line\append entry_nomsu
|
||||||
|
else
|
||||||
|
if #line.bits > 1
|
||||||
|
nomsu\append line
|
||||||
|
line = Nomsu(nil, "\n ")
|
||||||
|
line\append entry_nomsu
|
||||||
|
if #line.bits > 1
|
||||||
|
nomsu\append line
|
||||||
|
return nomsu
|
||||||
|
|
||||||
|
when "DictEntry"
|
||||||
|
key, value = tree[1], tree[2]
|
||||||
|
key_nomsu = @tree_to_nomsu(key, true)
|
||||||
|
return nil unless key_nomsu
|
||||||
|
if key.type == "Action" or key.type == "Block"
|
||||||
|
key_nomsu\parenthesize!
|
||||||
|
value_nomsu = if value
|
||||||
|
@tree_to_nomsu(value, true)
|
||||||
|
else Nomsu(nil, "")
|
||||||
|
if inline and not value_nomsu then return nil
|
||||||
|
if not value_nomsu
|
||||||
|
return nil if inline
|
||||||
|
value_nomsu = @tree_to_nomsu(value)
|
||||||
|
return nil unless value_nomsu
|
||||||
|
return Nomsu nil, key_nomsu, ":", value_nomsu
|
||||||
|
|
||||||
|
when "IndexChain"
|
||||||
|
nomsu = Nomsu!
|
||||||
|
for i, bit in ipairs tree
|
||||||
|
if i > 1
|
||||||
|
nomsu\append "."
|
||||||
|
bit_nomsu = @tree_to_nomsu(bit, true)
|
||||||
|
return nil unless bit_nomsu
|
||||||
|
if bit.type == "Action" or bit.type == "Block"
|
||||||
|
bit_nomsu\parenthesize!
|
||||||
|
nomsu\append bit_nomsu
|
||||||
|
return nomsu
|
||||||
|
|
||||||
|
when "Number"
|
||||||
|
return Nomsu(nil, tostring(tree.value))
|
||||||
|
|
||||||
|
when "Var"
|
||||||
|
return Nomsu(nil, "%", tree.value)
|
||||||
|
|
||||||
|
when "Word"
|
||||||
|
return Nomsu(nil, tree.value)
|
||||||
|
|
||||||
|
when "Comment"
|
||||||
|
return nil if inline
|
||||||
|
return Nomsu(nil, "#", tree.value\gsub("\n", "\n "))
|
||||||
|
|
||||||
|
else
|
||||||
|
error("Unknown type: #{tree.type}")
|
||||||
|
|
||||||
tree_to_value: (tree)=>
|
tree_to_value: (tree)=>
|
||||||
-- Special case for text literals
|
-- Special case for text literals
|
||||||
if tree.type == 'Text' and #tree == 1 and type(tree[1]) == 'string'
|
if tree.type == 'Text' and #tree == 1 and type(tree[1]) == 'string'
|
||||||
return tree[1]
|
return tree[1]
|
||||||
lua = Lua(nil, "return ",tree\as_lua(@),";")
|
lua = Lua(nil, "return ",@tree_to_lua(tree),";")
|
||||||
return @run_lua(lua)
|
return @run_lua(lua)
|
||||||
|
|
||||||
walk_tree: (tree, depth=0)=>
|
walk_tree: (tree, depth=0)=>
|
||||||
@ -418,35 +867,25 @@ class NomsuCompiler
|
|||||||
else
|
else
|
||||||
@walk_tree(v, depth+1)
|
@walk_tree(v, depth+1)
|
||||||
|
|
||||||
tree_with_replacements: (tree, replacements)=>
|
|
||||||
return tree unless next(replacements)
|
|
||||||
if next(replacements).type == "Var"
|
|
||||||
replacements = {tostring(k\as_lua(@)),v for k,v in pairs(replacements)}
|
|
||||||
tree\map (t)->
|
|
||||||
if t.type == "Var"
|
|
||||||
id = tostring(t\as_lua(self))
|
|
||||||
if replacements[id] != nil
|
|
||||||
return replacements[id]
|
|
||||||
|
|
||||||
initialize_core: =>
|
initialize_core: =>
|
||||||
-- Sets up some core functionality
|
-- Sets up some core functionality
|
||||||
nomsu = self
|
nomsu = self
|
||||||
@define_compile_action "immediately %block", (_block)=>
|
@define_compile_action "immediately %block", (_block)=>
|
||||||
lua = _block\as_lua(nomsu)\as_statements!
|
lua = nomsu\tree_to_lua(_block)\as_statements!
|
||||||
lua\declare_locals!
|
lua\declare_locals!
|
||||||
nomsu\run_lua(lua)
|
nomsu\run_lua(lua)
|
||||||
return Lua(nil, "if IMMEDIATE then\n ", lua, "\nend")
|
return Lua(nil, "if IMMEDIATE then\n ", lua, "\nend")
|
||||||
|
|
||||||
add_lua_string_bits = (lua, code)->
|
add_lua_string_bits = (lua, code)->
|
||||||
if code.type != "Text"
|
if code.type != "Text"
|
||||||
lua\append ", ", code\as_lua(nomsu)
|
lua\append ", ", nomsu\tree_to_lua(code)
|
||||||
return
|
return
|
||||||
for bit in *code
|
for bit in *code
|
||||||
lua\append ", "
|
lua\append ", "
|
||||||
if type(bit) == "string"
|
if type(bit) == "string"
|
||||||
lua\append repr(bit)
|
lua\append repr(bit)
|
||||||
else
|
else
|
||||||
bit_lua = bit\as_lua(nomsu)
|
bit_lua = nomsu\tree_to_lua(bit)
|
||||||
unless bit_lua.is_value
|
unless bit_lua.is_value
|
||||||
error "Cannot use #{colored.yellow repr(bit)} as a string interpolation value, since it's not an expression."
|
error "Cannot use #{colored.yellow repr(bit)} as a string interpolation value, since it's not an expression."
|
||||||
lua\append bit_lua
|
lua\append bit_lua
|
||||||
@ -468,7 +907,7 @@ class NomsuCompiler
|
|||||||
if type(bit) == "string"
|
if type(bit) == "string"
|
||||||
lua\append bit
|
lua\append bit
|
||||||
else
|
else
|
||||||
bit_lua = bit\as_lua(nomsu)
|
bit_lua = nomsu\tree_to_lua(bit)
|
||||||
unless bit_lua.is_value
|
unless bit_lua.is_value
|
||||||
error "Cannot use #{colored.yellow repr(bit)} as a string interpolation value, since it's not an expression.", 0
|
error "Cannot use #{colored.yellow repr(bit)} as a string interpolation value, since it's not an expression.", 0
|
||||||
lua\append bit_lua
|
lua\append bit_lua
|
||||||
@ -476,12 +915,12 @@ class NomsuCompiler
|
|||||||
|
|
||||||
@define_compile_action "lua> %code", (_code)=>
|
@define_compile_action "lua> %code", (_code)=>
|
||||||
if _code.type != "Text"
|
if _code.type != "Text"
|
||||||
return Lua nil, "nomsu:run_lua(", _code\as_lua(nomsu), ");"
|
return Lua nil, "nomsu:run_lua(", nomsu\tree_to_lua(_code), ");"
|
||||||
return add_lua_bits(Lua!, _code)
|
return add_lua_bits(Lua!, _code)
|
||||||
|
|
||||||
@define_compile_action "=lua %code", (_code)=>
|
@define_compile_action "=lua %code", (_code)=>
|
||||||
if _code.type != "Text"
|
if _code.type != "Text"
|
||||||
return Lua.Value nil, "nomsu:run_lua(", _code\as_lua(nomsu), ":as_statements('return '))"
|
return Lua.Value nil, "nomsu:run_lua(", nomsu\tree_to_lua(_code), ":as_statements('return '))"
|
||||||
return add_lua_bits(Lua.Value!, _code)
|
return add_lua_bits(Lua.Value!, _code)
|
||||||
|
|
||||||
@define_compile_action "use %path", (_path)=>
|
@define_compile_action "use %path", (_path)=>
|
||||||
@ -669,7 +1108,7 @@ OPTIONS
|
|||||||
-- Auto-format
|
-- Auto-format
|
||||||
for input_file in all_files(input)
|
for input_file in all_files(input)
|
||||||
tree = nomsu\parse(io.open(input_file)\read("*a"))
|
tree = nomsu\parse(io.open(input_file)\read("*a"))
|
||||||
formatted = tostring(tree\as_nomsu!)
|
formatted = tostring(@tree_to_nomsu(tree))
|
||||||
if output_file
|
if output_file
|
||||||
output_file\write(formatted, "\n")
|
output_file\write(formatted, "\n")
|
||||||
output_file\flush!
|
output_file\flush!
|
||||||
|
726
nomsu_tree.lua
726
nomsu_tree.lua
@ -19,6 +19,7 @@ Types.is_node = function(n)
|
|||||||
end
|
end
|
||||||
local Tree
|
local Tree
|
||||||
Tree = function(name, kind, methods)
|
Tree = function(name, kind, methods)
|
||||||
|
methods = methods or { }
|
||||||
assert((kind == 'single') or (kind == 'multi'))
|
assert((kind == 'single') or (kind == 'multi'))
|
||||||
local is_multi = (kind == 'multi')
|
local is_multi = (kind == 'multi')
|
||||||
do
|
do
|
||||||
@ -28,6 +29,21 @@ Tree = function(name, kind, methods)
|
|||||||
methods.type = name
|
methods.type = name
|
||||||
methods.name = name
|
methods.name = name
|
||||||
methods.is_multi = is_multi
|
methods.is_multi = is_multi
|
||||||
|
methods.map = function(self, fn)
|
||||||
|
if type(fn) == 'table' then
|
||||||
|
if not (next(fn)) then
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
if type(next(fn)) == 'string' then
|
||||||
|
error("SHIT")
|
||||||
|
end
|
||||||
|
local _replacements = fn
|
||||||
|
fn = function(k)
|
||||||
|
return _replacements[k]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return self:_map(fn)
|
||||||
|
end
|
||||||
if is_multi then
|
if is_multi then
|
||||||
methods.__tostring = function(self)
|
methods.__tostring = function(self)
|
||||||
return tostring(self.name) .. "(" .. tostring(table.concat((function()
|
return tostring(self.name) .. "(" .. tostring(table.concat((function()
|
||||||
@ -79,191 +95,32 @@ Tree = function(name, kind, methods)
|
|||||||
}, methods)
|
}, methods)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Tree("Block", 'multi')
|
||||||
|
Tree("Text", 'multi')
|
||||||
|
Tree("List", 'multi')
|
||||||
|
Tree("Dict", 'multi')
|
||||||
|
Tree("DictEntry", 'multi')
|
||||||
|
Tree("IndexChain", 'multi')
|
||||||
|
Tree("Number", 'single')
|
||||||
|
Tree("Word", 'single')
|
||||||
|
Tree("Comment", 'single')
|
||||||
Tree("EscapedNomsu", 'single', {
|
Tree("EscapedNomsu", 'single', {
|
||||||
as_lua = function(self, nomsu)
|
|
||||||
local make_tree
|
|
||||||
make_tree = function(t)
|
|
||||||
if type(t) ~= 'userdata' then
|
|
||||||
return repr(t)
|
|
||||||
end
|
|
||||||
if t.is_multi then
|
|
||||||
local bits
|
|
||||||
do
|
|
||||||
local _accum_0 = { }
|
|
||||||
local _len_0 = 1
|
|
||||||
for _index_0 = 1, #t do
|
|
||||||
local bit = t[_index_0]
|
|
||||||
_accum_0[_len_0] = make_tree(bit)
|
|
||||||
_len_0 = _len_0 + 1
|
|
||||||
end
|
|
||||||
bits = _accum_0
|
|
||||||
end
|
|
||||||
return t.type .. "(" .. table.concat(bits, ", ") .. ")"
|
|
||||||
else
|
|
||||||
return t.type .. "(" .. make_tree(t.value) .. ")"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return Lua.Value(nil, make_tree(self.value))
|
|
||||||
end,
|
|
||||||
as_nomsu = function(self, inline)
|
|
||||||
if inline == nil then
|
|
||||||
inline = false
|
|
||||||
end
|
|
||||||
local nomsu = self.value:as_nomsu(true)
|
|
||||||
if nomsu == nil and not inline then
|
|
||||||
nomsu = self.value:as_nomsu()
|
|
||||||
return nomsu and Nomsu(nil, "\\:\n ", nomsu)
|
|
||||||
end
|
|
||||||
return nomsu and Nomsu(nil, "\\(", nomsu, ")")
|
|
||||||
end,
|
|
||||||
map = function(self, fn)
|
map = function(self, fn)
|
||||||
return fn(self) or self:map(fn)
|
return fn(self) or self:map(fn)
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
Tree("Block", 'multi', {
|
Tree("Var", 'single', {
|
||||||
as_lua = function(self, nomsu)
|
as_lua_id = function(self)
|
||||||
local lua = Lua()
|
return "_" .. (self.value:gsub("%W", function(c)
|
||||||
for i, line in ipairs(self) do
|
if c == "_" then
|
||||||
local line_lua = line:as_lua(nomsu)
|
return "__"
|
||||||
if i > 1 then
|
else
|
||||||
lua:append("\n")
|
return ("_%x"):format(c:byte())
|
||||||
end
|
end
|
||||||
lua:append(line_lua:as_statements())
|
end))
|
||||||
end
|
|
||||||
return lua
|
|
||||||
end,
|
|
||||||
as_nomsu = function(self, inline)
|
|
||||||
if inline == nil then
|
|
||||||
inline = false
|
|
||||||
end
|
|
||||||
if inline then
|
|
||||||
local nomsu = Nomsu()
|
|
||||||
for i, line in ipairs(self) do
|
|
||||||
if i > 1 then
|
|
||||||
nomsu:append("; ")
|
|
||||||
end
|
|
||||||
local line_nomsu = line:as_nomsu(true)
|
|
||||||
if not (line_nomsu) then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
nomsu:append(line_nomsu)
|
|
||||||
end
|
|
||||||
return nomsu
|
|
||||||
end
|
|
||||||
local nomsu = Nomsu()
|
|
||||||
for i, line in ipairs(self) do
|
|
||||||
line = assert(line:as_nomsu(nil, true), "Could not convert line to nomsu")
|
|
||||||
nomsu:append(line)
|
|
||||||
if i < #self then
|
|
||||||
nomsu:append("\n")
|
|
||||||
if tostring(line):match("\n") then
|
|
||||||
nomsu:append("\n")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return nomsu
|
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
local math_expression = re.compile([[ ([+-] " ")* "%" (" " [*/^+-] (" " [+-])* " %")+ !. ]])
|
|
||||||
Tree("Action", 'multi', {
|
Tree("Action", 'multi', {
|
||||||
as_lua = function(self, nomsu)
|
|
||||||
local stub = self:get_stub()
|
|
||||||
local compile_action = nomsu.environment.COMPILE_ACTIONS[stub]
|
|
||||||
if compile_action then
|
|
||||||
local args
|
|
||||||
do
|
|
||||||
local _accum_0 = { }
|
|
||||||
local _len_0 = 1
|
|
||||||
for _index_0 = 1, #self do
|
|
||||||
local arg = self[_index_0]
|
|
||||||
if arg.type ~= "Word" then
|
|
||||||
_accum_0[_len_0] = arg
|
|
||||||
_len_0 = _len_0 + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
args = _accum_0
|
|
||||||
end
|
|
||||||
do
|
|
||||||
local _accum_0 = { }
|
|
||||||
local _len_0 = 1
|
|
||||||
local _list_0 = nomsu.environment.ARG_ORDERS[compile_action][stub]
|
|
||||||
for _index_0 = 1, #_list_0 do
|
|
||||||
local p = _list_0[_index_0]
|
|
||||||
_accum_0[_len_0] = args[p - 1]
|
|
||||||
_len_0 = _len_0 + 1
|
|
||||||
end
|
|
||||||
args = _accum_0
|
|
||||||
end
|
|
||||||
local ret = compile_action(self, unpack(args))
|
|
||||||
if not ret then
|
|
||||||
error("Failed to produce any Lua")
|
|
||||||
end
|
|
||||||
return ret
|
|
||||||
end
|
|
||||||
local action = rawget(nomsu.environment.ACTIONS, stub)
|
|
||||||
local lua = Lua.Value()
|
|
||||||
if not action and math_expression:match(stub) then
|
|
||||||
for i, tok in ipairs(self) do
|
|
||||||
if tok.type == "Word" then
|
|
||||||
lua:append(tok.value)
|
|
||||||
else
|
|
||||||
local tok_lua = tok:as_lua(nomsu)
|
|
||||||
if not (tok_lua.is_value) then
|
|
||||||
error("non-expression value inside math expression: " .. tostring(colored.yellow(repr(tok))))
|
|
||||||
end
|
|
||||||
if tok.type == "Action" then
|
|
||||||
tok_lua:parenthesize()
|
|
||||||
end
|
|
||||||
lua:append(tok_lua)
|
|
||||||
end
|
|
||||||
if i < #self then
|
|
||||||
lua:append(" ")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return lua
|
|
||||||
end
|
|
||||||
local args = { }
|
|
||||||
for i, tok in ipairs(self) do
|
|
||||||
local _continue_0 = false
|
|
||||||
repeat
|
|
||||||
if tok.type == "Word" then
|
|
||||||
_continue_0 = true
|
|
||||||
break
|
|
||||||
end
|
|
||||||
local arg_lua = tok:as_lua(nomsu)
|
|
||||||
if not (arg_lua.is_value) then
|
|
||||||
error("Cannot use:\n" .. tostring(colored.yellow(repr(tok))) .. "\nas an argument to " .. tostring(stub) .. ", since it's not an expression, it produces: " .. tostring(repr(arg_lua)), 0)
|
|
||||||
end
|
|
||||||
insert(args, arg_lua)
|
|
||||||
_continue_0 = true
|
|
||||||
until true
|
|
||||||
if not _continue_0 then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if action then
|
|
||||||
do
|
|
||||||
local _accum_0 = { }
|
|
||||||
local _len_0 = 1
|
|
||||||
local _list_0 = nomsu.environment.ARG_ORDERS[action][stub]
|
|
||||||
for _index_0 = 1, #_list_0 do
|
|
||||||
local p = _list_0[_index_0]
|
|
||||||
_accum_0[_len_0] = args[p]
|
|
||||||
_len_0 = _len_0 + 1
|
|
||||||
end
|
|
||||||
args = _accum_0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
lua:append("ACTIONS[", repr(stub), "](")
|
|
||||||
for i, arg in ipairs(args) do
|
|
||||||
lua:append(arg)
|
|
||||||
if i < #args then
|
|
||||||
lua:append(", ")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
lua:append(")")
|
|
||||||
return lua
|
|
||||||
end,
|
|
||||||
get_stub = function(self, include_names)
|
get_stub = function(self, include_names)
|
||||||
if include_names == nil then
|
if include_names == nil then
|
||||||
include_names = false
|
include_names = false
|
||||||
@ -293,523 +150,6 @@ Tree("Action", 'multi', {
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
return concat(bits, " ")
|
return concat(bits, " ")
|
||||||
end,
|
|
||||||
as_nomsu = function(self, inline, can_use_colon)
|
|
||||||
if inline == nil then
|
|
||||||
inline = false
|
|
||||||
end
|
|
||||||
if can_use_colon == nil then
|
|
||||||
can_use_colon = false
|
|
||||||
end
|
|
||||||
if inline then
|
|
||||||
local nomsu = Nomsu()
|
|
||||||
for i, bit in ipairs(self) do
|
|
||||||
if bit.type == "Word" then
|
|
||||||
if i > 1 then
|
|
||||||
nomsu:append(" ")
|
|
||||||
end
|
|
||||||
nomsu:append(bit.value)
|
|
||||||
else
|
|
||||||
local arg_nomsu = bit:as_nomsu(true)
|
|
||||||
if not (arg_nomsu) then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
if not (i == 1) then
|
|
||||||
nomsu:append(" ")
|
|
||||||
end
|
|
||||||
if bit.type == "Action" or bit.type == "Block" then
|
|
||||||
arg_nomsu:parenthesize()
|
|
||||||
end
|
|
||||||
nomsu:append(arg_nomsu)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return nomsu
|
|
||||||
else
|
|
||||||
local nomsu = Nomsu()
|
|
||||||
local next_space = ""
|
|
||||||
local last_colon = nil
|
|
||||||
for i, bit in ipairs(self) do
|
|
||||||
if bit.type == "Word" then
|
|
||||||
nomsu:append(next_space, bit.value)
|
|
||||||
next_space = " "
|
|
||||||
else
|
|
||||||
local arg_nomsu
|
|
||||||
if last_colon == i - 1 and bit.type == "Action" then
|
|
||||||
arg_nomsu = nil
|
|
||||||
elseif bit.type == "Block" then
|
|
||||||
arg_nomsu = nil
|
|
||||||
else
|
|
||||||
arg_nomsu = bit:as_nomsu(true)
|
|
||||||
end
|
|
||||||
if arg_nomsu and #arg_nomsu < MAX_LINE then
|
|
||||||
if bit.type == "Action" then
|
|
||||||
if can_use_colon and i > 1 then
|
|
||||||
nomsu:append(next_space:match("[^ ]*"), ": ", arg_nomsu)
|
|
||||||
next_space = "\n.."
|
|
||||||
last_colon = i
|
|
||||||
else
|
|
||||||
nomsu:append(next_space, "(", arg_nomsu, ")")
|
|
||||||
next_space = " "
|
|
||||||
end
|
|
||||||
else
|
|
||||||
nomsu:append(next_space, arg_nomsu)
|
|
||||||
next_space = " "
|
|
||||||
end
|
|
||||||
else
|
|
||||||
arg_nomsu = bit:as_nomsu(nil, true)
|
|
||||||
if not (nomsu) then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
if bit.type ~= "List" and bit.type ~= "Dict" and bit.type ~= "Text" then
|
|
||||||
if i == 1 then
|
|
||||||
arg_nomsu = Nomsu(nil, "(..)\n ", arg_nomsu)
|
|
||||||
else
|
|
||||||
arg_nomsu = Nomsu(nil, "\n ", arg_nomsu)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if last_colon == i - 1 and (bit.type == "Action" or bit.type == "Block") then
|
|
||||||
next_space = ""
|
|
||||||
end
|
|
||||||
nomsu:append(next_space, arg_nomsu)
|
|
||||||
next_space = "\n.."
|
|
||||||
end
|
|
||||||
if next_space == " " and #(tostring(nomsu):match("[^\n]*$")) > MAX_LINE then
|
|
||||||
next_space = "\n.."
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return nomsu
|
|
||||||
end
|
|
||||||
end
|
|
||||||
})
|
|
||||||
Tree("Text", 'multi', {
|
|
||||||
as_lua = function(self, nomsu)
|
|
||||||
local lua = Lua.Value()
|
|
||||||
local string_buffer = ""
|
|
||||||
for _index_0 = 1, #self do
|
|
||||||
local _continue_0 = false
|
|
||||||
repeat
|
|
||||||
local bit = self[_index_0]
|
|
||||||
if type(bit) == "string" then
|
|
||||||
string_buffer = string_buffer .. bit
|
|
||||||
_continue_0 = true
|
|
||||||
break
|
|
||||||
end
|
|
||||||
if string_buffer ~= "" then
|
|
||||||
if #lua.bits > 0 then
|
|
||||||
lua:append("..")
|
|
||||||
end
|
|
||||||
lua:append(repr(string_buffer))
|
|
||||||
string_buffer = ""
|
|
||||||
end
|
|
||||||
local bit_lua = bit:as_lua(nomsu)
|
|
||||||
if not (bit_lua.is_value) then
|
|
||||||
error("Cannot use " .. tostring(colored.yellow(repr(bit))) .. " as a string interpolation value, since it's not an expression.", 0)
|
|
||||||
end
|
|
||||||
if #lua.bits > 0 then
|
|
||||||
lua:append("..")
|
|
||||||
end
|
|
||||||
if bit.type ~= "Text" then
|
|
||||||
bit_lua = Lua.Value(nil, "stringify(", bit_lua, ")")
|
|
||||||
end
|
|
||||||
lua:append(bit_lua)
|
|
||||||
_continue_0 = true
|
|
||||||
until true
|
|
||||||
if not _continue_0 then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if string_buffer ~= "" or #lua.bits == 0 then
|
|
||||||
if #lua.bits > 0 then
|
|
||||||
lua:append("..")
|
|
||||||
end
|
|
||||||
lua:append(repr(string_buffer))
|
|
||||||
end
|
|
||||||
if #lua.bits > 1 then
|
|
||||||
lua:parenthesize()
|
|
||||||
end
|
|
||||||
return lua
|
|
||||||
end,
|
|
||||||
as_nomsu = function(self, inline)
|
|
||||||
if inline == nil then
|
|
||||||
inline = false
|
|
||||||
end
|
|
||||||
if inline then
|
|
||||||
local nomsu = Nomsu(nil, '"')
|
|
||||||
for _index_0 = 1, #self do
|
|
||||||
local bit = self[_index_0]
|
|
||||||
if type(bit) == 'string' then
|
|
||||||
nomsu:append((bit:gsub("\\", "\\\\"):gsub("\n", "\\n")))
|
|
||||||
else
|
|
||||||
local interp_nomsu = bit:as_nomsu(true)
|
|
||||||
if interp_nomsu then
|
|
||||||
if bit.type ~= "Word" and bit.type ~= "List" and bit.type ~= "Dict" and bit.type ~= "Text" then
|
|
||||||
interp_nomsu:parenthesize()
|
|
||||||
end
|
|
||||||
nomsu:append("\\", interp_nomsu)
|
|
||||||
else
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
nomsu:append('"')
|
|
||||||
return nomsu
|
|
||||||
else
|
|
||||||
local inline_version = self:as_nomsu(true)
|
|
||||||
if inline_version and #inline_version <= MAX_LINE then
|
|
||||||
return inline_version
|
|
||||||
end
|
|
||||||
local nomsu = Nomsu(nil, '".."\n ')
|
|
||||||
for i, bit in ipairs(self) do
|
|
||||||
if type(bit) == 'string' then
|
|
||||||
nomsu:append((bit:gsub("\\", "\\\\"):gsub("\n", "\n ")))
|
|
||||||
else
|
|
||||||
local interp_nomsu = bit:as_nomsu(true)
|
|
||||||
if interp_nomsu then
|
|
||||||
if bit.type ~= "Word" and bit.type ~= "List" and bit.type ~= "Dict" and bit.type ~= "Text" then
|
|
||||||
interp_nomsu:parenthesize()
|
|
||||||
end
|
|
||||||
nomsu:append("\\", interp_nomsu)
|
|
||||||
else
|
|
||||||
interp_nomsu = bit:as_nomsu()
|
|
||||||
if not (interp_nomsu) then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
nomsu:append("\\\n ", interp_nomsu)
|
|
||||||
if i < #self then
|
|
||||||
nomsu:append("\n ..")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return nomsu
|
|
||||||
end
|
|
||||||
end
|
|
||||||
})
|
|
||||||
Tree("List", 'multi', {
|
|
||||||
as_lua = function(self, nomsu)
|
|
||||||
local lua = Lua.Value(nil, "{")
|
|
||||||
local line_length = 0
|
|
||||||
for i, item in ipairs(self) do
|
|
||||||
local item_lua = item:as_lua(nomsu)
|
|
||||||
if not (item_lua.is_value) then
|
|
||||||
error("Cannot use " .. tostring(colored.yellow(repr(item))) .. " as a list item, since it's not an expression.", 0)
|
|
||||||
end
|
|
||||||
lua:append(item_lua)
|
|
||||||
local item_string = tostring(item_lua)
|
|
||||||
local last_line = item_string:match("[^\n]*$")
|
|
||||||
if item_string:match("\n") then
|
|
||||||
line_length = #last_line
|
|
||||||
else
|
|
||||||
line_length = line_length + #last_line
|
|
||||||
end
|
|
||||||
if i < #self then
|
|
||||||
if line_length >= MAX_LINE then
|
|
||||||
lua:append(",\n ")
|
|
||||||
line_length = 0
|
|
||||||
else
|
|
||||||
lua:append(", ")
|
|
||||||
line_length = line_length + 2
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
lua:append("}")
|
|
||||||
return lua
|
|
||||||
end,
|
|
||||||
as_nomsu = function(self, inline)
|
|
||||||
if inline == nil then
|
|
||||||
inline = false
|
|
||||||
end
|
|
||||||
if inline then
|
|
||||||
local nomsu = Nomsu(nil, "[")
|
|
||||||
for i, item in ipairs(self) do
|
|
||||||
local item_nomsu = item:as_nomsu(true)
|
|
||||||
if not (item_nomsu) then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
if i > 1 then
|
|
||||||
nomsu:append(", ")
|
|
||||||
end
|
|
||||||
nomsu:append(item_nomsu)
|
|
||||||
end
|
|
||||||
nomsu:append("]")
|
|
||||||
return nomsu
|
|
||||||
else
|
|
||||||
local inline_version = self:as_nomsu(true)
|
|
||||||
if inline_version and #inline_version <= MAX_LINE then
|
|
||||||
return inline_version
|
|
||||||
end
|
|
||||||
local nomsu = Nomsu(nil, "[..]")
|
|
||||||
local line = Nomsu(nil, "\n ")
|
|
||||||
for _index_0 = 1, #self do
|
|
||||||
local item = self[_index_0]
|
|
||||||
local item_nomsu = item:as_nomsu(true)
|
|
||||||
if item_nomsu and #line + #", " + #item_nomsu <= MAX_LINE then
|
|
||||||
if #line.bits > 1 then
|
|
||||||
line:append(", ")
|
|
||||||
end
|
|
||||||
line:append(item_nomsu)
|
|
||||||
else
|
|
||||||
if not (item_nomsu) then
|
|
||||||
item_nomsu = item:as_nomsu()
|
|
||||||
if not (item_nomsu) then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if #line.bits > 1 then
|
|
||||||
nomsu:append(line)
|
|
||||||
line = Nomsu(nil, "\n ")
|
|
||||||
end
|
|
||||||
line:append(item_nomsu)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if #line.bits > 1 then
|
|
||||||
nomsu:append(line)
|
|
||||||
end
|
|
||||||
return nomsu
|
|
||||||
end
|
|
||||||
end
|
|
||||||
})
|
|
||||||
Tree("Dict", 'multi', {
|
|
||||||
as_lua = function(self, nomsu)
|
|
||||||
local lua = Lua.Value(nil, "{")
|
|
||||||
local line_length = 0
|
|
||||||
for i, entry in ipairs(self) do
|
|
||||||
local entry_lua = entry:as_lua(nomsu)
|
|
||||||
lua:append(entry_lua)
|
|
||||||
local entry_lua_str = tostring(entry_lua)
|
|
||||||
local last_line = entry_lua_str:match("\n([^\n]*)$")
|
|
||||||
if last_line then
|
|
||||||
line_length = #last_line
|
|
||||||
else
|
|
||||||
line_length = line_length + #entry_lua_str
|
|
||||||
end
|
|
||||||
if i < #self then
|
|
||||||
if line_length >= MAX_LINE then
|
|
||||||
lua:append(",\n ")
|
|
||||||
line_length = 0
|
|
||||||
else
|
|
||||||
lua:append(", ")
|
|
||||||
line_length = line_length + 2
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
lua:append("}")
|
|
||||||
return lua
|
|
||||||
end,
|
|
||||||
as_nomsu = function(self, inline)
|
|
||||||
if inline == nil then
|
|
||||||
inline = false
|
|
||||||
end
|
|
||||||
if inline then
|
|
||||||
local nomsu = Nomsu(nil, "{")
|
|
||||||
for i, entry in ipairs(self) do
|
|
||||||
local entry_nomsu = entry:as_nomsu(true)
|
|
||||||
if not (entry_nomsu) then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
if i > 1 then
|
|
||||||
nomsu:append(", ")
|
|
||||||
end
|
|
||||||
nomsu:append(entry_nomsu)
|
|
||||||
end
|
|
||||||
nomsu:append("}")
|
|
||||||
return nomsu
|
|
||||||
else
|
|
||||||
local inline_version = self:as_nomsu(true)
|
|
||||||
if inline_version then
|
|
||||||
return inline_version
|
|
||||||
end
|
|
||||||
local nomsu = Nomsu(nil, "{..}")
|
|
||||||
local line = Nomsu(nil, "\n ")
|
|
||||||
for _index_0 = 1, #self do
|
|
||||||
local entry = self[_index_0]
|
|
||||||
local entry_nomsu = entry:as_nomsu()
|
|
||||||
if not (entry_nomsu) then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
if #line + #tostring(entry_nomsu) <= MAX_LINE then
|
|
||||||
if #line.bits > 1 then
|
|
||||||
line:append(", ")
|
|
||||||
end
|
|
||||||
line:append(entry_nomsu)
|
|
||||||
else
|
|
||||||
if #line.bits > 1 then
|
|
||||||
nomsu:append(line)
|
|
||||||
line = Nomsu(nil, "\n ")
|
|
||||||
end
|
|
||||||
line:append(entry_nomsu)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if #line.bits > 1 then
|
|
||||||
nomsu:append(line)
|
|
||||||
end
|
|
||||||
return nomsu
|
|
||||||
end
|
|
||||||
end
|
|
||||||
})
|
|
||||||
Tree("DictEntry", 'multi', {
|
|
||||||
as_lua = function(self, nomsu)
|
|
||||||
local key, value = self[1], self[2]
|
|
||||||
local key_lua = key:as_lua(nomsu)
|
|
||||||
if not (key_lua.is_value) then
|
|
||||||
error("Cannot use " .. tostring(colored.yellow(repr(key))) .. " as a dict key, since it's not an expression.", 0)
|
|
||||||
end
|
|
||||||
local value_lua = value and value:as_lua(nomsu) or Lua.Value(nil, "true")
|
|
||||||
if not (value_lua.is_value) then
|
|
||||||
error("Cannot use " .. tostring(colored.yellow(repr(value))) .. " as a dict value, since it's not an expression.", 0)
|
|
||||||
end
|
|
||||||
local key_str = tostring(key_lua):match([=[["']([a-zA-Z_][a-zA-Z0-9_]*)['"]]=])
|
|
||||||
if key_str then
|
|
||||||
return Lua(nil, key_str, "=", value_lua)
|
|
||||||
elseif tostring(key_lua):sub(1, 1) == "[" then
|
|
||||||
return Lua(nil, "[ ", key_lua, "]=", value_lua)
|
|
||||||
else
|
|
||||||
return Lua(nil, "[", key_lua, "]=", value_lua)
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
as_nomsu = function(self, inline)
|
|
||||||
if inline == nil then
|
|
||||||
inline = true
|
|
||||||
end
|
|
||||||
local key, value = self[1], self[2]
|
|
||||||
local key_nomsu = key:as_nomsu(true)
|
|
||||||
if not (key_nomsu) then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
if key.type == "Action" or key.type == "Block" then
|
|
||||||
key_nomsu:parenthesize()
|
|
||||||
end
|
|
||||||
local value_nomsu
|
|
||||||
if value then
|
|
||||||
value_nomsu = value:as_nomsu(true)
|
|
||||||
else
|
|
||||||
value_nomsu = Nomsu(nil, "")
|
|
||||||
end
|
|
||||||
if inline and not value_nomsu then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
if not value_nomsu then
|
|
||||||
if inline then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
value_nomsu = value:as_nomsu()
|
|
||||||
if not (value_nomsu) then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return Nomsu(nil, key_nomsu, ":", value_nomsu)
|
|
||||||
end
|
|
||||||
})
|
|
||||||
Tree("IndexChain", 'multi', {
|
|
||||||
as_lua = function(self, nomsu)
|
|
||||||
local lua = self[1]:as_lua(nomsu)
|
|
||||||
if not (lua.is_value) then
|
|
||||||
error("Cannot index " .. tostring(colored.yellow(repr(self[1]))) .. ", since it's not an expression.", 0)
|
|
||||||
end
|
|
||||||
local first_char = tostring(lua):sub(1, 1)
|
|
||||||
if first_char == "{" or first_char == '"' or first_char == "[" then
|
|
||||||
lua:parenthesize()
|
|
||||||
end
|
|
||||||
for i = 2, #self do
|
|
||||||
local key = self[i]
|
|
||||||
local key_lua = key:as_lua(nomsu)
|
|
||||||
if not (key_lua.is_value) then
|
|
||||||
error("Cannot use " .. tostring(colored.yellow(repr(key))) .. " as an index, since it's not an expression.", 0)
|
|
||||||
end
|
|
||||||
local key_lua_str = tostring(key_lua)
|
|
||||||
do
|
|
||||||
local lua_id = key_lua_str:match("^['\"]([a-zA-Z_][a-zA-Z0-9_]*)['\"]$")
|
|
||||||
if lua_id then
|
|
||||||
lua:append("." .. tostring(lua_id))
|
|
||||||
elseif key_lua_str:sub(1, 1) == '[' then
|
|
||||||
lua:append("[ ", key_lua, " ]")
|
|
||||||
else
|
|
||||||
lua:append("[", key_lua, "]")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return lua
|
|
||||||
end,
|
|
||||||
as_nomsu = function(self, inline)
|
|
||||||
if inline == nil then
|
|
||||||
inline = false
|
|
||||||
end
|
|
||||||
local nomsu = Nomsu()
|
|
||||||
for i, bit in ipairs(self) do
|
|
||||||
if i > 1 then
|
|
||||||
nomsu:append(".")
|
|
||||||
end
|
|
||||||
local bit_nomsu = bit:as_nomsu(true)
|
|
||||||
if not (bit_nomsu) then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
if bit.type == "Action" or bit.type == "Block" then
|
|
||||||
bit_nomsu:parenthesize()
|
|
||||||
end
|
|
||||||
nomsu:append(bit_nomsu)
|
|
||||||
end
|
|
||||||
return nomsu
|
|
||||||
end
|
|
||||||
})
|
|
||||||
Tree("Number", 'single', {
|
|
||||||
as_lua = function(self, nomsu)
|
|
||||||
return Lua.Value(nil, tostring(self.value))
|
|
||||||
end,
|
|
||||||
as_nomsu = function(self, inline)
|
|
||||||
if inline == nil then
|
|
||||||
inline = false
|
|
||||||
end
|
|
||||||
return Nomsu(nil, tostring(self.value))
|
|
||||||
end
|
|
||||||
})
|
|
||||||
Tree("Var", 'single', {
|
|
||||||
as_lua_id = function(v)
|
|
||||||
return "_" .. (v:gsub("%W", function(c)
|
|
||||||
if c == "_" then
|
|
||||||
return "__"
|
|
||||||
else
|
|
||||||
return ("_%x"):format(c:byte())
|
|
||||||
end
|
|
||||||
end))
|
|
||||||
end,
|
|
||||||
as_lua = function(self, nomsu)
|
|
||||||
return Lua.Value(nil, self.as_lua_id(self.value))
|
|
||||||
end,
|
|
||||||
as_nomsu = function(self, inline)
|
|
||||||
if inline == nil then
|
|
||||||
inline = false
|
|
||||||
end
|
|
||||||
return Nomsu(nil, "%", self.value)
|
|
||||||
end
|
|
||||||
})
|
|
||||||
Tree("Word", 'single', {
|
|
||||||
as_lua = function(self, nomsu)
|
|
||||||
return error("Attempt to convert Word to lua")
|
|
||||||
end,
|
|
||||||
as_nomsu = function(self, inline)
|
|
||||||
if inline == nil then
|
|
||||||
inline = false
|
|
||||||
end
|
|
||||||
return Nomsu(nil, self.value)
|
|
||||||
end
|
|
||||||
})
|
|
||||||
Tree("Comment", 'single', {
|
|
||||||
as_lua = function(self, nomsu)
|
|
||||||
return Lua(nil, "--" .. self.value:gsub("\n", "\n--") .. "\n")
|
|
||||||
end,
|
|
||||||
as_nomsu = function(self, inline)
|
|
||||||
if inline == nil then
|
|
||||||
inline = false
|
|
||||||
end
|
|
||||||
if inline then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
if self.value:match("\n") then
|
|
||||||
return Nomsu(nil, "#..", self.value:gsub("\n", "\n "))
|
|
||||||
else
|
|
||||||
return Nomsu(nil, "#", self.value)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
return Types
|
return Types
|
||||||
|
477
nomsu_tree.moon
477
nomsu_tree.moon
@ -14,6 +14,7 @@ Types.is_node = (n)->
|
|||||||
|
|
||||||
-- Helper method:
|
-- Helper method:
|
||||||
Tree = (name, kind, methods)->
|
Tree = (name, kind, methods)->
|
||||||
|
methods or= {}
|
||||||
assert((kind == 'single') or (kind == 'multi'))
|
assert((kind == 'single') or (kind == 'multi'))
|
||||||
is_multi = (kind == 'multi')
|
is_multi = (kind == 'multi')
|
||||||
with methods
|
with methods
|
||||||
@ -21,6 +22,14 @@ Tree = (name, kind, methods)->
|
|||||||
.type = name
|
.type = name
|
||||||
.name = name
|
.name = name
|
||||||
.is_multi = is_multi
|
.is_multi = is_multi
|
||||||
|
.map = (fn)=>
|
||||||
|
if type(fn) == 'table'
|
||||||
|
return @ unless next(fn)
|
||||||
|
if type(next(fn)) == 'string'
|
||||||
|
error("SHIT")
|
||||||
|
_replacements = fn
|
||||||
|
fn = (k)-> _replacements[k]
|
||||||
|
return @_map(fn)
|
||||||
if is_multi
|
if is_multi
|
||||||
.__tostring = => "#{@name}(#{table.concat [repr(v) for v in *@], ', '})"
|
.__tostring = => "#{@name}(#{table.concat [repr(v) for v in *@], ', '})"
|
||||||
.map = (fn)=>
|
.map = (fn)=>
|
||||||
@ -31,476 +40,36 @@ Tree = (name, kind, methods)->
|
|||||||
return ret
|
return ret
|
||||||
else
|
else
|
||||||
.__tostring = => "#{@name}(#{repr(@value)})"
|
.__tostring = => "#{@name}(#{repr(@value)})"
|
||||||
.map = (fn)=> fn(@) or @
|
.map = (fn)=>
|
||||||
|
fn(@) or @
|
||||||
|
|
||||||
if is_multi
|
if is_multi
|
||||||
Types[name] = immutable nil, methods
|
Types[name] = immutable nil, methods
|
||||||
else
|
else
|
||||||
Types[name] = immutable {"value"}, methods
|
Types[name] = immutable {"value"}, methods
|
||||||
|
|
||||||
|
Tree "Block", 'multi'
|
||||||
|
Tree "Text", 'multi'
|
||||||
|
Tree "List", 'multi'
|
||||||
|
Tree "Dict", 'multi'
|
||||||
|
Tree "DictEntry", 'multi'
|
||||||
|
Tree "IndexChain", 'multi'
|
||||||
|
Tree "Number", 'single'
|
||||||
|
Tree "Word", 'single'
|
||||||
|
Tree "Comment", 'single'
|
||||||
|
|
||||||
Tree "EscapedNomsu", 'single',
|
Tree "EscapedNomsu", 'single',
|
||||||
as_lua: (nomsu)=>
|
|
||||||
make_tree = (t)->
|
|
||||||
if type(t) != 'userdata'
|
|
||||||
return repr(t)
|
|
||||||
if t.is_multi
|
|
||||||
bits = [make_tree(bit) for bit in *t]
|
|
||||||
return t.type.."("..table.concat(bits, ", ")..")"
|
|
||||||
else
|
|
||||||
return t.type.."("..make_tree(t.value)..")"
|
|
||||||
Lua.Value nil, make_tree(@value)
|
|
||||||
|
|
||||||
as_nomsu: (inline=false)=>
|
|
||||||
nomsu = @value\as_nomsu(true)
|
|
||||||
if nomsu == nil and not inline
|
|
||||||
nomsu = @value\as_nomsu!
|
|
||||||
return nomsu and Nomsu nil, "\\:\n ", nomsu
|
|
||||||
return nomsu and Nomsu nil, "\\(", nomsu, ")"
|
|
||||||
|
|
||||||
map: (fn)=> fn(@) or @\map(fn)
|
map: (fn)=> fn(@) or @\map(fn)
|
||||||
|
|
||||||
Tree "Block", 'multi',
|
Tree "Var", 'single',
|
||||||
as_lua: (nomsu)=>
|
as_lua_id: =>
|
||||||
lua = Lua!
|
"_"..(@value\gsub("%W", (c)-> if c == "_" then "__" else ("_%x")\format(c\byte!)))
|
||||||
for i,line in ipairs @
|
|
||||||
line_lua = line\as_lua(nomsu)
|
|
||||||
if i > 1
|
|
||||||
lua\append "\n"
|
|
||||||
lua\append line_lua\as_statements!
|
|
||||||
return lua
|
|
||||||
|
|
||||||
as_nomsu: (inline=false)=>
|
|
||||||
if inline
|
|
||||||
nomsu = Nomsu!
|
|
||||||
for i,line in ipairs @
|
|
||||||
if i > 1
|
|
||||||
nomsu\append "; "
|
|
||||||
line_nomsu = line\as_nomsu(true)
|
|
||||||
return nil unless line_nomsu
|
|
||||||
nomsu\append line_nomsu
|
|
||||||
return nomsu
|
|
||||||
nomsu = Nomsu!
|
|
||||||
for i, line in ipairs @
|
|
||||||
line = assert(line\as_nomsu(nil, true), "Could not convert line to nomsu")
|
|
||||||
nomsu\append line
|
|
||||||
if i < #@
|
|
||||||
nomsu\append "\n"
|
|
||||||
if tostring(line)\match("\n")
|
|
||||||
nomsu\append "\n"
|
|
||||||
return nomsu
|
|
||||||
|
|
||||||
math_expression = re.compile [[ ([+-] " ")* "%" (" " [*/^+-] (" " [+-])* " %")+ !. ]]
|
|
||||||
Tree "Action", 'multi',
|
Tree "Action", 'multi',
|
||||||
as_lua: (nomsu)=>
|
|
||||||
stub = @get_stub!
|
|
||||||
compile_action = nomsu.environment.COMPILE_ACTIONS[stub]
|
|
||||||
if compile_action
|
|
||||||
args = [arg for arg in *@ when arg.type != "Word"]
|
|
||||||
-- Force all compile-time actions to take a tree location
|
|
||||||
args = [args[p-1] for p in *nomsu.environment.ARG_ORDERS[compile_action][stub]]
|
|
||||||
-- Force Lua to avoid tail call optimization for debugging purposes
|
|
||||||
ret = compile_action(self, unpack(args))
|
|
||||||
if not ret then error("Failed to produce any Lua")
|
|
||||||
return ret
|
|
||||||
action = rawget(nomsu.environment.ACTIONS, stub)
|
|
||||||
lua = Lua.Value!
|
|
||||||
if not action and math_expression\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.
|
|
||||||
for i,tok in ipairs @
|
|
||||||
if tok.type == "Word"
|
|
||||||
lua\append tok.value
|
|
||||||
else
|
|
||||||
tok_lua = tok\as_lua(nomsu)
|
|
||||||
unless tok_lua.is_value
|
|
||||||
error("non-expression value inside math expression: #{colored.yellow repr(tok)}")
|
|
||||||
if tok.type == "Action"
|
|
||||||
tok_lua\parenthesize!
|
|
||||||
lua\append tok_lua
|
|
||||||
if i < #@
|
|
||||||
lua\append " "
|
|
||||||
return lua
|
|
||||||
|
|
||||||
args = {}
|
|
||||||
for i, tok in ipairs @
|
|
||||||
if tok.type == "Word" then continue
|
|
||||||
arg_lua = tok\as_lua(nomsu)
|
|
||||||
unless arg_lua.is_value
|
|
||||||
error "Cannot use:\n#{colored.yellow repr(tok)}\nas an argument to #{stub}, since it's not an expression, it produces: #{repr arg_lua}", 0
|
|
||||||
insert args, arg_lua
|
|
||||||
|
|
||||||
if action
|
|
||||||
args = [args[p] for p in *nomsu.environment.ARG_ORDERS[action][stub]]
|
|
||||||
|
|
||||||
-- Not really worth bothering with ACTIONS.foo(...) style since almost every action
|
|
||||||
-- has arguments, so it won't work
|
|
||||||
lua\append "ACTIONS[",repr(stub),"]("
|
|
||||||
for i, arg in ipairs args
|
|
||||||
lua\append arg
|
|
||||||
if i < #args then lua\append ", "
|
|
||||||
lua\append ")"
|
|
||||||
return lua
|
|
||||||
|
|
||||||
get_stub: (include_names=false)=>
|
get_stub: (include_names=false)=>
|
||||||
bits = if include_names
|
bits = if include_names
|
||||||
[(t.type == "Word" and t.value or "%#{t.value}") for t in *@]
|
[(t.type == "Word" and t.value or "%#{t.value}") for t in *@]
|
||||||
else [(t.type == "Word" and t.value or "%") for t in *@]
|
else [(t.type == "Word" and t.value or "%") for t in *@]
|
||||||
return concat(bits, " ")
|
return concat(bits, " ")
|
||||||
|
|
||||||
as_nomsu: (inline=false, can_use_colon=false)=>
|
|
||||||
if inline
|
|
||||||
nomsu = Nomsu!
|
|
||||||
for i,bit in ipairs @
|
|
||||||
if bit.type == "Word"
|
|
||||||
if i > 1
|
|
||||||
nomsu\append " "
|
|
||||||
nomsu\append bit.value
|
|
||||||
else
|
|
||||||
arg_nomsu = bit\as_nomsu(true)
|
|
||||||
return nil unless arg_nomsu
|
|
||||||
unless i == 1
|
|
||||||
nomsu\append " "
|
|
||||||
if bit.type == "Action" or bit.type == "Block"
|
|
||||||
arg_nomsu\parenthesize!
|
|
||||||
nomsu\append arg_nomsu
|
|
||||||
return nomsu
|
|
||||||
else
|
|
||||||
nomsu = Nomsu!
|
|
||||||
next_space = ""
|
|
||||||
-- TODO: track line length as we go and use 80-that instead of 80 for wrapping
|
|
||||||
last_colon = nil
|
|
||||||
for i,bit in ipairs @
|
|
||||||
if bit.type == "Word"
|
|
||||||
nomsu\append next_space, bit.value
|
|
||||||
next_space = " "
|
|
||||||
else
|
|
||||||
arg_nomsu = if last_colon == i-1 and bit.type == "Action" then nil
|
|
||||||
elseif bit.type == "Block" then nil
|
|
||||||
else bit\as_nomsu(true)
|
|
||||||
|
|
||||||
if arg_nomsu and #arg_nomsu < MAX_LINE
|
|
||||||
if bit.type == "Action"
|
|
||||||
if can_use_colon and i > 1
|
|
||||||
nomsu\append next_space\match("[^ ]*"), ": ", arg_nomsu
|
|
||||||
next_space = "\n.."
|
|
||||||
last_colon = i
|
|
||||||
else
|
|
||||||
nomsu\append next_space, "(", arg_nomsu, ")"
|
|
||||||
next_space = " "
|
|
||||||
else
|
|
||||||
nomsu\append next_space, arg_nomsu
|
|
||||||
next_space = " "
|
|
||||||
else
|
|
||||||
arg_nomsu = bit\as_nomsu(nil, true)
|
|
||||||
return nil unless nomsu
|
|
||||||
-- These types carry their own indentation
|
|
||||||
if bit.type != "List" and bit.type != "Dict" and bit.type != "Text"
|
|
||||||
if i == 1
|
|
||||||
arg_nomsu = Nomsu(nil, "(..)\n ", arg_nomsu)
|
|
||||||
else
|
|
||||||
arg_nomsu = Nomsu(nil, "\n ", arg_nomsu)
|
|
||||||
|
|
||||||
if last_colon == i-1 and (bit.type == "Action" or bit.type == "Block")
|
|
||||||
next_space = ""
|
|
||||||
nomsu\append next_space, arg_nomsu
|
|
||||||
next_space = "\n.."
|
|
||||||
|
|
||||||
if next_space == " " and #(tostring(nomsu)\match("[^\n]*$")) > MAX_LINE
|
|
||||||
next_space = "\n.."
|
|
||||||
return nomsu
|
|
||||||
|
|
||||||
Tree "Text", 'multi',
|
|
||||||
as_lua: (nomsu)=>
|
|
||||||
lua = Lua.Value!
|
|
||||||
string_buffer = ""
|
|
||||||
for bit in *@
|
|
||||||
if type(bit) == "string"
|
|
||||||
string_buffer ..= bit
|
|
||||||
continue
|
|
||||||
if string_buffer ~= ""
|
|
||||||
if #lua.bits > 0 then lua\append ".."
|
|
||||||
lua\append repr(string_buffer)
|
|
||||||
string_buffer = ""
|
|
||||||
bit_lua = bit\as_lua(nomsu)
|
|
||||||
unless bit_lua.is_value
|
|
||||||
error "Cannot use #{colored.yellow repr(bit)} as a string interpolation value, since it's not an expression.", 0
|
|
||||||
if #lua.bits > 0 then lua\append ".."
|
|
||||||
if bit.type != "Text"
|
|
||||||
bit_lua = Lua.Value(nil, "stringify(",bit_lua,")")
|
|
||||||
lua\append bit_lua
|
|
||||||
|
|
||||||
if string_buffer ~= "" or #lua.bits == 0
|
|
||||||
if #lua.bits > 0 then lua\append ".."
|
|
||||||
lua\append repr(string_buffer)
|
|
||||||
|
|
||||||
if #lua.bits > 1
|
|
||||||
lua\parenthesize!
|
|
||||||
return lua
|
|
||||||
|
|
||||||
as_nomsu: (inline=false)=>
|
|
||||||
if inline
|
|
||||||
nomsu = Nomsu(nil, '"')
|
|
||||||
for bit in *@
|
|
||||||
if type(bit) == 'string'
|
|
||||||
-- TODO: unescape better?
|
|
||||||
nomsu\append (bit\gsub("\\","\\\\")\gsub("\n","\\n"))
|
|
||||||
else
|
|
||||||
interp_nomsu = bit\as_nomsu(true)
|
|
||||||
if interp_nomsu
|
|
||||||
if bit.type != "Word" and bit.type != "List" and bit.type != "Dict" and bit.type != "Text"
|
|
||||||
interp_nomsu\parenthesize!
|
|
||||||
nomsu\append "\\", interp_nomsu
|
|
||||||
else return nil
|
|
||||||
nomsu\append '"'
|
|
||||||
return nomsu
|
|
||||||
else
|
|
||||||
inline_version = @as_nomsu(true)
|
|
||||||
if inline_version and #inline_version <= MAX_LINE
|
|
||||||
return inline_version
|
|
||||||
nomsu = Nomsu(nil, '".."\n ')
|
|
||||||
for i, bit in ipairs @
|
|
||||||
if type(bit) == 'string'
|
|
||||||
nomsu\append (bit\gsub("\\","\\\\")\gsub("\n","\n "))
|
|
||||||
else
|
|
||||||
interp_nomsu = bit\as_nomsu(true)
|
|
||||||
if interp_nomsu
|
|
||||||
if bit.type != "Word" and bit.type != "List" and bit.type != "Dict" and bit.type != "Text"
|
|
||||||
interp_nomsu\parenthesize!
|
|
||||||
nomsu\append "\\", interp_nomsu
|
|
||||||
else
|
|
||||||
interp_nomsu = bit\as_nomsu!
|
|
||||||
return nil unless interp_nomsu
|
|
||||||
nomsu\append "\\\n ", interp_nomsu
|
|
||||||
if i < #@
|
|
||||||
nomsu\append "\n .."
|
|
||||||
return nomsu
|
|
||||||
|
|
||||||
Tree "List", 'multi',
|
|
||||||
as_lua: (nomsu)=>
|
|
||||||
lua = Lua.Value nil, "{"
|
|
||||||
line_length = 0
|
|
||||||
for i, item in ipairs @
|
|
||||||
item_lua = item\as_lua(nomsu)
|
|
||||||
unless item_lua.is_value
|
|
||||||
error "Cannot use #{colored.yellow repr(item)} as a list item, since it's not an expression.", 0
|
|
||||||
lua\append item_lua
|
|
||||||
item_string = tostring(item_lua)
|
|
||||||
last_line = item_string\match("[^\n]*$")
|
|
||||||
if item_string\match("\n")
|
|
||||||
line_length = #last_line
|
|
||||||
else
|
|
||||||
line_length += #last_line
|
|
||||||
if i < #@
|
|
||||||
if line_length >= MAX_LINE
|
|
||||||
lua\append ",\n "
|
|
||||||
line_length = 0
|
|
||||||
else
|
|
||||||
lua\append ", "
|
|
||||||
line_length += 2
|
|
||||||
lua\append "}"
|
|
||||||
return lua
|
|
||||||
|
|
||||||
as_nomsu: (inline=false)=>
|
|
||||||
if inline
|
|
||||||
nomsu = Nomsu(nil, "[")
|
|
||||||
for i, item in ipairs @
|
|
||||||
item_nomsu = item\as_nomsu(true)
|
|
||||||
return nil unless item_nomsu
|
|
||||||
if i > 1
|
|
||||||
nomsu\append ", "
|
|
||||||
nomsu\append item_nomsu
|
|
||||||
nomsu\append "]"
|
|
||||||
return nomsu
|
|
||||||
else
|
|
||||||
inline_version = @as_nomsu(true)
|
|
||||||
if inline_version and #inline_version <= MAX_LINE
|
|
||||||
return inline_version
|
|
||||||
nomsu = Nomsu(nil, "[..]")
|
|
||||||
line = Nomsu(nil, "\n ")
|
|
||||||
for item in *@
|
|
||||||
item_nomsu = item\as_nomsu(true)
|
|
||||||
if item_nomsu and #line + #", " + #item_nomsu <= MAX_LINE
|
|
||||||
if #line.bits > 1
|
|
||||||
line\append ", "
|
|
||||||
line\append item_nomsu
|
|
||||||
else
|
|
||||||
unless item_nomsu
|
|
||||||
item_nomsu = item\as_nomsu!
|
|
||||||
return nil unless item_nomsu
|
|
||||||
if #line.bits > 1
|
|
||||||
nomsu\append line
|
|
||||||
line = Nomsu(nil, "\n ")
|
|
||||||
line\append item_nomsu
|
|
||||||
if #line.bits > 1
|
|
||||||
nomsu\append line
|
|
||||||
return nomsu
|
|
||||||
|
|
||||||
Tree "Dict", 'multi',
|
|
||||||
as_lua: (nomsu)=>
|
|
||||||
lua = Lua.Value nil, "{"
|
|
||||||
line_length = 0
|
|
||||||
for i, entry in ipairs @
|
|
||||||
entry_lua = entry\as_lua(nomsu)
|
|
||||||
lua\append entry_lua
|
|
||||||
entry_lua_str = tostring(entry_lua)
|
|
||||||
-- TODO: maybe make this more accurate? It's only a heuristic, so eh...
|
|
||||||
last_line = entry_lua_str\match("\n([^\n]*)$")
|
|
||||||
if last_line
|
|
||||||
line_length = #last_line
|
|
||||||
else
|
|
||||||
line_length += #entry_lua_str
|
|
||||||
if i < #@
|
|
||||||
if line_length >= MAX_LINE
|
|
||||||
lua\append ",\n "
|
|
||||||
line_length = 0
|
|
||||||
else
|
|
||||||
lua\append ", "
|
|
||||||
line_length += 2
|
|
||||||
lua\append "}"
|
|
||||||
return lua
|
|
||||||
|
|
||||||
as_nomsu: (inline=false)=>
|
|
||||||
if inline
|
|
||||||
nomsu = Nomsu(nil, "{")
|
|
||||||
for i, entry in ipairs @
|
|
||||||
entry_nomsu = entry\as_nomsu(true)
|
|
||||||
return nil unless entry_nomsu
|
|
||||||
if i > 1
|
|
||||||
nomsu\append ", "
|
|
||||||
nomsu\append entry_nomsu
|
|
||||||
nomsu\append "}"
|
|
||||||
return nomsu
|
|
||||||
else
|
|
||||||
inline_version = @as_nomsu(true)
|
|
||||||
if inline_version then return inline_version
|
|
||||||
nomsu = Nomsu(nil, "{..}")
|
|
||||||
line = Nomsu(nil, "\n ")
|
|
||||||
for entry in *@
|
|
||||||
entry_nomsu = entry\as_nomsu!
|
|
||||||
return nil unless entry_nomsu
|
|
||||||
if #line + #tostring(entry_nomsu) <= MAX_LINE
|
|
||||||
if #line.bits > 1
|
|
||||||
line\append ", "
|
|
||||||
line\append entry_nomsu
|
|
||||||
else
|
|
||||||
if #line.bits > 1
|
|
||||||
nomsu\append line
|
|
||||||
line = Nomsu(nil, "\n ")
|
|
||||||
line\append entry_nomsu
|
|
||||||
if #line.bits > 1
|
|
||||||
nomsu\append line
|
|
||||||
return nomsu
|
|
||||||
|
|
||||||
Tree "DictEntry", 'multi',
|
|
||||||
as_lua: (nomsu)=>
|
|
||||||
key, value = @[1], @[2]
|
|
||||||
key_lua = key\as_lua(nomsu)
|
|
||||||
unless key_lua.is_value
|
|
||||||
error "Cannot use #{colored.yellow repr(key)} as a dict key, since it's not an expression.", 0
|
|
||||||
value_lua = value and value\as_lua(nomsu) or Lua.Value(nil, "true")
|
|
||||||
unless value_lua.is_value
|
|
||||||
error "Cannot use #{colored.yellow repr(value)} as a dict value, since it's not an expression.", 0
|
|
||||||
key_str = tostring(key_lua)\match([=[["']([a-zA-Z_][a-zA-Z0-9_]*)['"]]=])
|
|
||||||
return if key_str
|
|
||||||
Lua nil, key_str,"=",value_lua
|
|
||||||
elseif tostring(key_lua)\sub(1,1) == "["
|
|
||||||
-- NOTE: this *must* use a space after the [ to avoid freaking out
|
|
||||||
-- Lua's parser if the inner expression is a long string. Lua
|
|
||||||
-- parses x[[[y]]] as x("[y]"), not as x["y"]
|
|
||||||
Lua nil, "[ ",key_lua,"]=",value_lua
|
|
||||||
else
|
|
||||||
Lua nil, "[",key_lua,"]=",value_lua
|
|
||||||
|
|
||||||
as_nomsu: (inline=true)=>
|
|
||||||
key, value = @[1], @[2]
|
|
||||||
key_nomsu = key\as_nomsu(true)
|
|
||||||
return nil unless key_nomsu
|
|
||||||
if key.type == "Action" or key.type == "Block"
|
|
||||||
key_nomsu\parenthesize!
|
|
||||||
value_nomsu = if value
|
|
||||||
value\as_nomsu(true)
|
|
||||||
else Nomsu(nil, "")
|
|
||||||
if inline and not value_nomsu then return nil
|
|
||||||
if not value_nomsu
|
|
||||||
return nil if inline
|
|
||||||
value_nomsu = value\as_nomsu!
|
|
||||||
return nil unless value_nomsu
|
|
||||||
return Nomsu nil, key_nomsu, ":", value_nomsu
|
|
||||||
|
|
||||||
|
|
||||||
Tree "IndexChain", 'multi',
|
|
||||||
as_lua: (nomsu)=>
|
|
||||||
lua = @[1]\as_lua(nomsu)
|
|
||||||
unless lua.is_value
|
|
||||||
error "Cannot index #{colored.yellow repr(@[1])}, since it's not an expression.", 0
|
|
||||||
first_char = tostring(lua)\sub(1,1)
|
|
||||||
if first_char == "{" or first_char == '"' or first_char == "["
|
|
||||||
lua\parenthesize!
|
|
||||||
|
|
||||||
for i=2,#@
|
|
||||||
key = @[i]
|
|
||||||
key_lua = key\as_lua(nomsu)
|
|
||||||
unless key_lua.is_value
|
|
||||||
error "Cannot use #{colored.yellow repr(key)} as an index, since it's not an expression.", 0
|
|
||||||
key_lua_str = tostring(key_lua)
|
|
||||||
if lua_id = key_lua_str\match("^['\"]([a-zA-Z_][a-zA-Z0-9_]*)['\"]$")
|
|
||||||
lua\append ".#{lua_id}"
|
|
||||||
elseif key_lua_str\sub(1,1) == '['
|
|
||||||
-- NOTE: this *must* use a space after the [ to avoid freaking out
|
|
||||||
-- Lua's parser if the inner expression is a long string. Lua
|
|
||||||
-- parses x[[[y]]] as x("[y]"), not as x["y"]
|
|
||||||
lua\append "[ ",key_lua," ]"
|
|
||||||
else
|
|
||||||
lua\append "[",key_lua,"]"
|
|
||||||
return lua
|
|
||||||
|
|
||||||
as_nomsu: (inline=false)=>
|
|
||||||
nomsu = Nomsu!
|
|
||||||
for i, bit in ipairs @
|
|
||||||
if i > 1
|
|
||||||
nomsu\append "."
|
|
||||||
bit_nomsu = bit\as_nomsu(true)
|
|
||||||
return nil unless bit_nomsu
|
|
||||||
if bit.type == "Action" or bit.type == "Block"
|
|
||||||
bit_nomsu\parenthesize!
|
|
||||||
nomsu\append bit_nomsu
|
|
||||||
return nomsu
|
|
||||||
|
|
||||||
Tree "Number", 'single',
|
|
||||||
as_lua: (nomsu)=>
|
|
||||||
Lua.Value(nil, tostring(@value))
|
|
||||||
|
|
||||||
as_nomsu: (inline=false)=>
|
|
||||||
return Nomsu(nil, tostring(@value))
|
|
||||||
|
|
||||||
Tree "Var", 'single',
|
|
||||||
as_lua_id: (v)->
|
|
||||||
"_"..(v\gsub("%W", (c)-> if c == "_" then "__" else ("_%x")\format(c\byte!)))
|
|
||||||
|
|
||||||
as_lua: (nomsu)=>
|
|
||||||
Lua.Value(nil, self.as_lua_id(@value))
|
|
||||||
|
|
||||||
as_nomsu: (inline=false)=>
|
|
||||||
return Nomsu(nil, "%", @value)
|
|
||||||
|
|
||||||
Tree "Word", 'single',
|
|
||||||
as_lua: (nomsu)=>
|
|
||||||
error("Attempt to convert Word to lua")
|
|
||||||
|
|
||||||
as_nomsu: (inline=false)=>
|
|
||||||
return Nomsu(nil, @value)
|
|
||||||
|
|
||||||
Tree "Comment", 'single',
|
|
||||||
as_lua: (nomsu)=>
|
|
||||||
Lua(nil, "--"..@value\gsub("\n","\n--").."\n")
|
|
||||||
|
|
||||||
as_nomsu: (inline=false)=>
|
|
||||||
return nil if inline
|
|
||||||
if @value\match("\n")
|
|
||||||
return Nomsu(nil, "#..", @value\gsub("\n", "\n "))
|
|
||||||
else
|
|
||||||
return Nomsu(nil, "#", @value)
|
|
||||||
|
|
||||||
return Types
|
return Types
|
||||||
|
Loading…
Reference in New Issue
Block a user