Working version.
This commit is contained in:
parent
b0997a7dbf
commit
63a19db0dc
@ -83,6 +83,7 @@ do
|
|||||||
local match = string.match
|
local match = string.match
|
||||||
for i = 1, n do
|
for i = 1, n do
|
||||||
local b = select(i, ...)
|
local b = select(i, ...)
|
||||||
|
assert(b)
|
||||||
bits[#bits + 1] = b
|
bits[#bits + 1] = b
|
||||||
if type(b) == 'string' then
|
if type(b) == 'string' then
|
||||||
do
|
do
|
||||||
@ -171,7 +172,6 @@ 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]
|
||||||
assert(var.type == "Var")
|
|
||||||
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
|
||||||
@ -186,7 +186,6 @@ do
|
|||||||
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]
|
||||||
assert(var.type == "Var")
|
|
||||||
removals[var[1]] = true
|
removals[var[1]] = true
|
||||||
end
|
end
|
||||||
local stack = {
|
local stack = {
|
||||||
@ -264,7 +263,7 @@ do
|
|||||||
local _len_0 = 1
|
local _len_0 = 1
|
||||||
for _index_0 = 1, #to_declare do
|
for _index_0 = 1, #to_declare do
|
||||||
local v = to_declare[_index_0]
|
local v = to_declare[_index_0]
|
||||||
_accum_0[_len_0] = string.as_lua_id(v[1])
|
_accum_0[_len_0] = type(v) == 'string' and v or string.as_lua_id(v[1])
|
||||||
_len_0 = _len_0 + 1
|
_len_0 = _len_0 + 1
|
||||||
end
|
end
|
||||||
return _accum_0
|
return _accum_0
|
||||||
|
@ -57,6 +57,7 @@ class Code
|
|||||||
match = string.match
|
match = string.match
|
||||||
for i=1,n
|
for i=1,n
|
||||||
b = select(i, ...)
|
b = select(i, ...)
|
||||||
|
assert(b)
|
||||||
bits[#bits+1] = b
|
bits[#bits+1] = b
|
||||||
if type(b) == 'string'
|
if type(b) == 'string'
|
||||||
if spaces = match(b, "\n([ ]*)[^\n]*$")
|
if spaces = match(b, "\n([ ]*)[^\n]*$")
|
||||||
@ -98,7 +99,6 @@ class Lua extends Code
|
|||||||
return unless #vars > 0
|
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
|
||||||
assert(var.type == "Var")
|
|
||||||
unless seen[var]
|
unless seen[var]
|
||||||
@free_vars[#@free_vars+1] = var
|
@free_vars[#@free_vars+1] = var
|
||||||
seen[var] = true
|
seen[var] = true
|
||||||
@ -108,7 +108,6 @@ class Lua extends Code
|
|||||||
return unless #vars > 0
|
return unless #vars > 0
|
||||||
removals = {}
|
removals = {}
|
||||||
for var in *vars
|
for var in *vars
|
||||||
assert(var.type == "Var")
|
|
||||||
removals[var[1]] = true
|
removals[var[1]] = true
|
||||||
|
|
||||||
stack = {self}
|
stack = {self}
|
||||||
@ -147,7 +146,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 [string.as_lua_id(v[1]) for v in *to_declare], ", "};\n"
|
@prepend "local #{concat [type(v) == 'string' and v or string.as_lua_id(v[1]) for v in *to_declare], ", "};\n"
|
||||||
return to_declare
|
return to_declare
|
||||||
|
|
||||||
__tostring: =>
|
__tostring: =>
|
||||||
|
@ -5,85 +5,112 @@
|
|||||||
# Compile-time action to make compile-time actions:
|
# Compile-time action to make compile-time actions:
|
||||||
immediately
|
immediately
|
||||||
lua> ".."
|
lua> ".."
|
||||||
nomsu:define_compile_action("compile %actions to %lua", function(tree, \%actions, \%lua)
|
_ENV['ACTION'..string.as_lua_id("compile % to %")] = function(tree, \%actions, \%lua)
|
||||||
local lua = Lua(tree.source, "nomsu:define_compile_action(")
|
local lua = Lua(tree.source)
|
||||||
local specs = {}
|
local canonical = \%actions[1]
|
||||||
for i, action in ipairs(\%actions) do
|
lua:append("ACTION", string.as_lua_id(canonical.stub), ' = function(tree')
|
||||||
specs[i] = action:get_spec()
|
|
||||||
end
|
|
||||||
specs = repr(specs)
|
|
||||||
if #specs > 80 then
|
|
||||||
lua:append("\n ",specs,",\n ")
|
|
||||||
else
|
|
||||||
lua:append(specs,", ")
|
|
||||||
end
|
|
||||||
lua:append("function(tree")
|
|
||||||
local args = {}
|
local args = {}
|
||||||
for i,tok in ipairs(\%actions[1]) do
|
for i,tok in ipairs(canonical) do
|
||||||
if tok.type == "Var" then args[#args+1] = tok end
|
if tok.type == "Var" then args[#args+1] = tok end
|
||||||
end
|
end
|
||||||
|
local canonical_arg_positions = {}
|
||||||
for i, arg in ipairs(args) do
|
for i, arg in ipairs(args) do
|
||||||
|
canonical_arg_positions[arg[1]] = i
|
||||||
lua:append(", ", nomsu:tree_to_lua(arg))
|
lua:append(", ", nomsu:tree_to_lua(arg))
|
||||||
end
|
end
|
||||||
local body_lua = nomsu:tree_to_lua(\%lua):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")
|
||||||
|
lua:append("\nCOMPILE_TIME[ACTION", string.as_lua_id(canonical.stub), "] = true")
|
||||||
|
|
||||||
|
for i=2,#\%actions do
|
||||||
|
local action = \%actions[i]
|
||||||
|
lua:append("\n", "ACTION", string.as_lua_id(action.stub), " = ACTION", string.as_lua_id(canonical.stub))
|
||||||
|
|
||||||
|
local arg_positions = {}
|
||||||
|
for _,tok in ipairs(action) do
|
||||||
|
if tok.type == 'Var' then
|
||||||
|
arg_positions[#arg_positions+1] = canonical_arg_positions[tok[1]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
lua:append("\n", "ARG_ORDERS[", repr(action.stub), "] = ", repr(arg_positions))
|
||||||
|
lua:append("\nCOMPILE_TIME[ACTION", string.as_lua_id(action.stub), "] = true")
|
||||||
|
end
|
||||||
|
lua:append("\nALIASES[ACTION", string.as_lua_id(canonical.stub), "] = {")
|
||||||
|
for i,action in ipairs(\%actions) do
|
||||||
|
if i > 1 then lua:append(", ") end
|
||||||
|
lua:append(repr(action.stub))
|
||||||
|
end
|
||||||
|
lua:append("}")
|
||||||
return lua
|
return lua
|
||||||
end);
|
end
|
||||||
|
COMPILE_TIME[_ENV['ACTION'..string.as_lua_id("compile % to %")]] = true
|
||||||
|
|
||||||
# Compile-time action to make actions
|
# Compile-time action to make actions
|
||||||
immediately
|
immediately
|
||||||
compile [action %actions %body] to
|
compile [action %actions %body] to
|
||||||
lua> ".."
|
lua> ".."
|
||||||
local lua = Lua(tree.source, "nomsu:define_action(")
|
local lua = Lua(tree.source)
|
||||||
local specs = {}
|
local canonical = \%actions[1]
|
||||||
for i, action in ipairs(\%actions) do
|
lua:append("ACTION", string.as_lua_id(canonical.stub), ' = function(')
|
||||||
specs[i] = action:get_spec()
|
|
||||||
end
|
|
||||||
specs = repr(specs)
|
|
||||||
if #specs > 80 then
|
|
||||||
lua:append("\n ",specs,",\n ")
|
|
||||||
else
|
|
||||||
lua:append(specs,", ")
|
|
||||||
end
|
|
||||||
lua:append("function(")
|
|
||||||
local args = {}
|
local args = {}
|
||||||
for i,tok in ipairs(\%actions[1]) do
|
for i,tok in ipairs(canonical) do
|
||||||
if tok.type == "Var" then args[#args+1] = tok end
|
if tok.type == "Var" then args[#args+1] = tok end
|
||||||
end
|
end
|
||||||
|
local canonical_arg_positions = {}
|
||||||
for i, arg in ipairs(args) do
|
for i, arg in ipairs(args) do
|
||||||
|
canonical_arg_positions[arg[1]] = i
|
||||||
lua:append(nomsu:tree_to_lua(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 = nomsu:tree_to_lua(\%body):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")
|
||||||
|
|
||||||
|
for i=2,#\%actions do
|
||||||
|
local action = \%actions[i]
|
||||||
|
lua:append("\n", "ACTION", string.as_lua_id(action.stub), " = ACTION", string.as_lua_id(canonical.stub))
|
||||||
|
|
||||||
|
local arg_positions = {}
|
||||||
|
for _,tok in ipairs(action) do
|
||||||
|
if tok.type == 'Var' then
|
||||||
|
arg_positions[#arg_positions+1] = canonical_arg_positions[tok[1]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
lua:append("\n", "ARG_ORDERS[", repr(action.stub), "] = ", repr(arg_positions))
|
||||||
|
end
|
||||||
|
lua:append("\nALIASES[ACTION", string.as_lua_id(canonical.stub), "] = {")
|
||||||
|
for i,action in ipairs(\%actions) do
|
||||||
|
if i > 1 then lua:append(", ") end
|
||||||
|
lua:append(repr(action.stub))
|
||||||
|
end
|
||||||
|
lua:append("}")
|
||||||
return lua
|
return lua
|
||||||
|
|
||||||
# Macro to make nomsu macros
|
# Macro to make nomsu macros
|
||||||
immediately
|
immediately
|
||||||
compile [parse %shorthand as %longhand] to
|
compile [parse %shorthand as %longhand] to
|
||||||
lua> ".."
|
lua> ".."
|
||||||
local lua = Lua(tree.source, "nomsu:define_compile_action(")
|
local lua = Lua(tree.source)
|
||||||
local specs = {}
|
local canonical = \%shorthand[1]
|
||||||
for i, action in ipairs(\%shorthand) do
|
lua:append("ACTION", string.as_lua_id(canonical.stub), ' = function(tree')
|
||||||
specs[i] = action:get_spec()
|
local args = {}
|
||||||
|
for i,tok in ipairs(canonical) do
|
||||||
|
if tok.type == "Var" then args[#args+1] = tok end
|
||||||
end
|
end
|
||||||
specs = repr(specs)
|
local canonical_arg_positions = {}
|
||||||
if #specs > 80 then
|
for i, arg in ipairs(args) do
|
||||||
lua:append("\n ",specs,",\n ")
|
canonical_arg_positions[arg[1]] = i
|
||||||
else
|
lua:append(", ", nomsu:tree_to_lua(arg))
|
||||||
lua:append(specs,", ")
|
|
||||||
end
|
end
|
||||||
lua:append("function(tree")
|
|
||||||
local replacements = {}
|
local replacements = {}
|
||||||
for i,tok in ipairs(\%shorthand[1]) do
|
for i,tok in ipairs(canonical) do
|
||||||
if tok.type == "Var" then
|
if tok.type == "Var" then
|
||||||
local lua_var = tostring(nomsu:tree_to_lua(tok))
|
local lua_var = tostring(nomsu:tree_to_lua(tok))
|
||||||
replacements[tok[1]] = lua_var
|
replacements[tok[1]] = lua_var
|
||||||
lua:append(", ", lua_var)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
MANGLE_INDEX = (MANGLE_INDEX or 0) + 1
|
MANGLE_INDEX = (MANGLE_INDEX or 0) + 1
|
||||||
@ -102,18 +129,39 @@ immediately
|
|||||||
return t.type.."("..table.concat(bits, ", ")..")"
|
return t.type.."("..table.concat(bits, ", ")..")"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
lua:append(")\n local tree = ", make_tree(\%longhand), "\n return nomsu:tree_to_lua(tree)\nend);")
|
lua:append(")\n local tree = ", make_tree(\%longhand), "\n return nomsu:tree_to_lua(tree)\nend")
|
||||||
|
lua:append("\nCOMPILE_TIME[ACTION", string.as_lua_id(canonical.stub), "] = true")
|
||||||
|
|
||||||
|
for i=2,#\%shorthand do
|
||||||
|
local action = \%shorthand[i]
|
||||||
|
lua:append("\n", "ACTION", string.as_lua_id(action.stub), " = ACTION", string.as_lua_id(canonical.stub))
|
||||||
|
|
||||||
|
local arg_positions = {}
|
||||||
|
for _,tok in ipairs(action) do
|
||||||
|
if tok.type == 'Var' then
|
||||||
|
arg_positions[#arg_positions+1] = canonical_arg_positions[tok[1]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
lua:append("\n", "ARG_ORDERS[", repr(action.stub), "] = ", repr(arg_positions))
|
||||||
|
lua:append("\nCOMPILE_TIME[ACTION", string.as_lua_id(action.stub), "] = true")
|
||||||
|
end
|
||||||
|
lua:append("\nALIASES[ACTION", string.as_lua_id(canonical.stub), "] = {")
|
||||||
|
for i,action in ipairs(\%shorthand) do
|
||||||
|
if i > 1 then lua:append(", ") end
|
||||||
|
lua:append(repr(action.stub))
|
||||||
|
end
|
||||||
|
lua:append("}")
|
||||||
return lua
|
return lua
|
||||||
|
|
||||||
compile [remove action %action] to
|
compile [remove action %action] to
|
||||||
Lua ".."
|
Lua ".."
|
||||||
do
|
do
|
||||||
local fn = ACTIONS[\(=lua "repr(\%action.stub)")]
|
local fn = ACTION\(=lua "string.as_lua_id(\(%action.stub))")
|
||||||
local stubs = ARG_ORDERS[fn]
|
for stub in pairs(ALIASES[fn]) do
|
||||||
for stub in pairs(stubs) do
|
_ENV['ACTION'..string.as_lua_id(stub)] = nil
|
||||||
ACTIONS[stub] = nil
|
|
||||||
end
|
end
|
||||||
ARG_ORDERS[fn] = nil
|
ARG_ORDERS[fn] = nil
|
||||||
|
COMPILE_TIME[fn] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
immediately
|
immediately
|
||||||
|
93
nomsu.lua
93
nomsu.lua
@ -43,13 +43,18 @@ do
|
|||||||
end
|
end
|
||||||
local STDIN, STDOUT, STDERR = "/dev/fd/0", "/dev/fd/1", "/dev/fd/2"
|
local STDIN, STDOUT, STDERR = "/dev/fd/0", "/dev/fd/1", "/dev/fd/2"
|
||||||
string.as_lua_id = function(str)
|
string.as_lua_id = function(str)
|
||||||
return "_" .. (gsub(str, "%W", function(c)
|
local argnum = 0
|
||||||
if c == "_" then
|
str = gsub(str, "%W", function(c)
|
||||||
return "__"
|
if c == ' ' then
|
||||||
|
return '_'
|
||||||
|
elseif c == '%' then
|
||||||
|
argnum = argnum + 1
|
||||||
|
return tostring(argnum)
|
||||||
else
|
else
|
||||||
return format("_%x", byte(c))
|
return format("x%X", byte(c))
|
||||||
end
|
end
|
||||||
end))
|
end)
|
||||||
|
return '_' .. str
|
||||||
end
|
end
|
||||||
FILE_CACHE = setmetatable({ }, {
|
FILE_CACHE = setmetatable({ }, {
|
||||||
__index = function(self, filename)
|
__index = function(self, filename)
|
||||||
@ -237,6 +242,9 @@ setmetatable(NOMSU_DEFS, {
|
|||||||
if value.__init then
|
if value.__init then
|
||||||
value:__init()
|
value:__init()
|
||||||
end
|
end
|
||||||
|
for i = 1, #value do
|
||||||
|
assert(value[i])
|
||||||
|
end
|
||||||
return value
|
return value
|
||||||
end
|
end
|
||||||
self[key] = make_node
|
self[key] = make_node
|
||||||
@ -262,10 +270,7 @@ do
|
|||||||
local _class_0
|
local _class_0
|
||||||
local compile_error, stub_pattern, var_pattern, _running_files, MAX_LINE, math_expression
|
local compile_error, stub_pattern, var_pattern, _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)
|
||||||
if is_compile_action == nil then
|
|
||||||
is_compile_action = false
|
|
||||||
end
|
|
||||||
if type(fn) ~= 'function' then
|
if type(fn) ~= 'function' then
|
||||||
error("Not a function: " .. tostring(repr(fn)))
|
error("Not a function: " .. tostring(repr(fn)))
|
||||||
end
|
end
|
||||||
@ -286,13 +291,12 @@ do
|
|||||||
end
|
end
|
||||||
fn_arg_positions = _tbl_0
|
fn_arg_positions = _tbl_0
|
||||||
end
|
end
|
||||||
local actions = (is_compile_action and self.environment.COMPILE_ACTIONS or self.environment.ACTIONS)
|
|
||||||
local arg_orders = { }
|
local arg_orders = { }
|
||||||
for _index_0 = 1, #signature do
|
for _index_0 = 1, #signature do
|
||||||
local alias = signature[_index_0]
|
local alias = signature[_index_0]
|
||||||
local stub = concat(assert(stub_pattern:match(alias)), ' ')
|
local stub = concat(assert(stub_pattern:match(alias)), ' ')
|
||||||
local stub_args = assert(var_pattern:match(alias))
|
local stub_args = assert(var_pattern:match(alias))
|
||||||
actions[stub] = fn
|
self.environment['ACTION' .. string.as_lua_id(stub)] = fn
|
||||||
do
|
do
|
||||||
local _accum_0 = { }
|
local _accum_0 = { }
|
||||||
local _len_0 = 1
|
local _len_0 = 1
|
||||||
@ -307,7 +311,8 @@ do
|
|||||||
self.environment.ARG_ORDERS[fn] = arg_orders
|
self.environment.ARG_ORDERS[fn] = arg_orders
|
||||||
end,
|
end,
|
||||||
define_compile_action = function(self, signature, fn)
|
define_compile_action = function(self, signature, fn)
|
||||||
return self:define_action(signature, fn, true)
|
self:define_action(signature, fn)
|
||||||
|
self.environment.COMPILE_TIME[fn] = true
|
||||||
end,
|
end,
|
||||||
parse = function(self, nomsu_code)
|
parse = function(self, nomsu_code)
|
||||||
assert(type(nomsu_code) ~= 'string')
|
assert(type(nomsu_code) ~= 'string')
|
||||||
@ -426,7 +431,7 @@ do
|
|||||||
run_lua = function(self, lua)
|
run_lua = function(self, lua)
|
||||||
assert(type(lua) ~= 'string', "Attempt to run lua string instead of Lua (object)")
|
assert(type(lua) ~= 'string', "Attempt to run lua string instead of Lua (object)")
|
||||||
local lua_string = tostring(lua)
|
local lua_string = tostring(lua)
|
||||||
local run_lua_fn, err = load(lua_string, tostring(lua.source), "t", self.environment)
|
local run_lua_fn, err = load(lua_string, nil and tostring(lua.source), "t", self.environment)
|
||||||
if not run_lua_fn then
|
if not run_lua_fn then
|
||||||
local n = 1
|
local n = 1
|
||||||
local fn
|
local fn
|
||||||
@ -475,8 +480,8 @@ do
|
|||||||
local _exp_0 = tree.type
|
local _exp_0 = tree.type
|
||||||
if "Action" == _exp_0 then
|
if "Action" == _exp_0 then
|
||||||
local stub = tree.stub
|
local stub = tree.stub
|
||||||
local compile_action = self.environment.COMPILE_ACTIONS[stub]
|
local action = self.environment['ACTION' .. string.as_lua_id(stub)]
|
||||||
if compile_action then
|
if action and self.environment.COMPILE_TIME[action] then
|
||||||
local args
|
local args
|
||||||
do
|
do
|
||||||
local _accum_0 = { }
|
local _accum_0 = { }
|
||||||
@ -490,25 +495,27 @@ do
|
|||||||
end
|
end
|
||||||
args = _accum_0
|
args = _accum_0
|
||||||
end
|
end
|
||||||
local arg_orders = self.environment.ARG_ORDERS[compile_action]
|
do
|
||||||
|
local arg_orders = self.environment.ARG_ORDERS[stub]
|
||||||
|
if arg_orders then
|
||||||
do
|
do
|
||||||
local _accum_0 = { }
|
local _accum_0 = { }
|
||||||
local _len_0 = 1
|
local _len_0 = 1
|
||||||
local _list_0 = arg_orders[stub]
|
for _index_0 = 1, #arg_orders do
|
||||||
for _index_0 = 1, #_list_0 do
|
local p = arg_orders[_index_0]
|
||||||
local p = _list_0[_index_0]
|
_accum_0[_len_0] = args[p]
|
||||||
_accum_0[_len_0] = args[p - 1]
|
|
||||||
_len_0 = _len_0 + 1
|
_len_0 = _len_0 + 1
|
||||||
end
|
end
|
||||||
args = _accum_0
|
args = _accum_0
|
||||||
end
|
end
|
||||||
local ret = compile_action(tree, unpack(args))
|
end
|
||||||
|
end
|
||||||
|
local ret = action(tree, unpack(args))
|
||||||
if not ret then
|
if not ret then
|
||||||
compile_error(tree, "Compile-time action:\n%s\nfailed to produce any Lua")
|
compile_error(tree, "Compile-time action:\n%s\nfailed to produce any Lua")
|
||||||
end
|
end
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
local action = rawget(self.environment.ACTIONS, stub)
|
|
||||||
local lua = Lua.Value(tree.source)
|
local lua = Lua.Value(tree.source)
|
||||||
if not action and math_expression:match(stub) then
|
if not action and math_expression:match(stub) then
|
||||||
for i, tok in ipairs(tree) do
|
for i, tok in ipairs(tree) do
|
||||||
@ -550,19 +557,23 @@ do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
if action then
|
if action then
|
||||||
|
do
|
||||||
|
local arg_orders = self.environment.ARG_ORDERS[stub]
|
||||||
|
if arg_orders then
|
||||||
do
|
do
|
||||||
local _accum_0 = { }
|
local _accum_0 = { }
|
||||||
local _len_0 = 1
|
local _len_0 = 1
|
||||||
local _list_0 = self.environment.ARG_ORDERS[action][stub]
|
for _index_0 = 1, #arg_orders do
|
||||||
for _index_0 = 1, #_list_0 do
|
local p = arg_orders[_index_0]
|
||||||
local p = _list_0[_index_0]
|
|
||||||
_accum_0[_len_0] = args[p]
|
_accum_0[_len_0] = args[p]
|
||||||
_len_0 = _len_0 + 1
|
_len_0 = _len_0 + 1
|
||||||
end
|
end
|
||||||
args = _accum_0
|
args = _accum_0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
lua:append("ACTIONS[", repr(stub), "](")
|
end
|
||||||
|
end
|
||||||
|
lua:append("ACTION", string.as_lua_id(stub), "(")
|
||||||
for i, arg in ipairs(args) do
|
for i, arg in ipairs(args) do
|
||||||
lua:append(arg)
|
lua:append(arg)
|
||||||
if i < #args then
|
if i < #args then
|
||||||
@ -1085,22 +1096,31 @@ do
|
|||||||
end)
|
end)
|
||||||
local add_lua_string_bits
|
local add_lua_string_bits
|
||||||
add_lua_string_bits = function(lua, code)
|
add_lua_string_bits = function(lua, code)
|
||||||
|
local line_len = 0
|
||||||
if code.type ~= "Text" then
|
if code.type ~= "Text" then
|
||||||
lua:append(", ", nomsu:tree_to_lua(code))
|
lua:append(", ", nomsu:tree_to_lua(code))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
for _index_0 = 1, #code do
|
for _index_0 = 1, #code do
|
||||||
local bit = code[_index_0]
|
local bit = code[_index_0]
|
||||||
lua:append(", ")
|
local bit_lua
|
||||||
if type(bit) == "string" then
|
if type(bit) == "string" then
|
||||||
lua:append(repr(bit))
|
bit_lua = repr(bit)
|
||||||
else
|
else
|
||||||
local bit_lua = nomsu:tree_to_lua(bit)
|
bit_lua = nomsu:tree_to_lua(bit)
|
||||||
if not (bit_lua.is_value) then
|
if not (bit_lua.is_value) then
|
||||||
compile_error(bit, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression.")
|
compile_error(bit, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression.")
|
||||||
end
|
end
|
||||||
lua:append(bit_lua)
|
bit_lua = bit_lua
|
||||||
end
|
end
|
||||||
|
line_len = line_len + #tostring(bit_lua)
|
||||||
|
if line_len > MAX_LINE then
|
||||||
|
lua:append(",\n ")
|
||||||
|
line_len = 4
|
||||||
|
else
|
||||||
|
lua:append(", ")
|
||||||
|
end
|
||||||
|
lua:append(bit_lua)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self:define_compile_action("Lua %code", function(self, _code)
|
self:define_compile_action("Lua %code", function(self, _code)
|
||||||
@ -1262,19 +1282,16 @@ do
|
|||||||
self.environment.Lua = Lua
|
self.environment.Lua = Lua
|
||||||
self.environment.Nomsu = Nomsu
|
self.environment.Nomsu = Nomsu
|
||||||
self.environment.Source = Source
|
self.environment.Source = Source
|
||||||
self.environment.ACTIONS = setmetatable({ }, {
|
|
||||||
__index = function(self, key)
|
|
||||||
return function(...)
|
|
||||||
return error("Attempt to run undefined action: " .. tostring(key), 0)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
})
|
|
||||||
self.environment.COMPILE_ACTIONS = { }
|
|
||||||
self.environment.ARG_ORDERS = setmetatable({ }, {
|
self.environment.ARG_ORDERS = setmetatable({ }, {
|
||||||
__mode = "k"
|
__mode = "k"
|
||||||
})
|
})
|
||||||
|
self.environment.ALIASES = setmetatable({ }, {
|
||||||
|
__mode = "k"
|
||||||
|
})
|
||||||
|
self.environment.COMPILE_TIME = { }
|
||||||
self.environment.LOADED = { }
|
self.environment.LOADED = { }
|
||||||
self.environment.AST = AST
|
self.environment.AST = AST
|
||||||
|
self.environment._ENV = self.environment
|
||||||
return self:initialize_core()
|
return self:initialize_core()
|
||||||
end,
|
end,
|
||||||
__base = _base_0,
|
__base = _base_0,
|
||||||
|
59
nomsu.moon
59
nomsu.moon
@ -36,7 +36,14 @@ debug_getinfo = debug.getinfo
|
|||||||
STDIN, STDOUT, STDERR = "/dev/fd/0", "/dev/fd/1", "/dev/fd/2"
|
STDIN, STDOUT, STDERR = "/dev/fd/0", "/dev/fd/1", "/dev/fd/2"
|
||||||
|
|
||||||
string.as_lua_id = (str)->
|
string.as_lua_id = (str)->
|
||||||
"_"..(gsub(str, "%W", (c)-> if c == "_" then "__" else format("_%x", byte(c))))
|
argnum = 0
|
||||||
|
str = gsub str, "%W", (c)->
|
||||||
|
if c == ' ' then '_'
|
||||||
|
elseif c == '%' then
|
||||||
|
argnum += 1
|
||||||
|
tostring(argnum)
|
||||||
|
else format("x%X", byte(c))
|
||||||
|
return '_'..str
|
||||||
|
|
||||||
-- TODO:
|
-- TODO:
|
||||||
-- consider non-linear codegen, rather than doing thunks for things like comprehensions
|
-- consider non-linear codegen, rather than doing thunks for things like comprehensions
|
||||||
@ -194,6 +201,7 @@ setmetatable(NOMSU_DEFS, {__index:(key)=>
|
|||||||
value.source = source
|
value.source = source
|
||||||
setmetatable(value, AST[key])
|
setmetatable(value, AST[key])
|
||||||
if value.__init then value\__init!
|
if value.__init then value\__init!
|
||||||
|
for i=1,#value do assert(value[i])
|
||||||
return value
|
return value
|
||||||
|
|
||||||
self[key] = make_node
|
self[key] = make_node
|
||||||
@ -273,14 +281,12 @@ class NomsuCompiler
|
|||||||
@environment.Lua = Lua
|
@environment.Lua = Lua
|
||||||
@environment.Nomsu = Nomsu
|
@environment.Nomsu = Nomsu
|
||||||
@environment.Source = Source
|
@environment.Source = Source
|
||||||
@environment.ACTIONS = setmetatable({}, {__index:(key)=>
|
|
||||||
(...)->
|
|
||||||
error("Attempt to run undefined action: #{key}", 0)
|
|
||||||
})
|
|
||||||
@environment.COMPILE_ACTIONS = {}
|
|
||||||
@environment.ARG_ORDERS = setmetatable({}, {__mode:"k"})
|
@environment.ARG_ORDERS = setmetatable({}, {__mode:"k"})
|
||||||
|
@environment.ALIASES = setmetatable({}, {__mode:"k"})
|
||||||
|
@environment.COMPILE_TIME = {}
|
||||||
@environment.LOADED = {}
|
@environment.LOADED = {}
|
||||||
@environment.AST = AST
|
@environment.AST = AST
|
||||||
|
@environment._ENV = @environment
|
||||||
@initialize_core!
|
@initialize_core!
|
||||||
|
|
||||||
local stub_defs
|
local stub_defs
|
||||||
@ -294,7 +300,7 @@ class NomsuCompiler
|
|||||||
tok <- ({'%'} %varname) / {%word}
|
tok <- ({'%'} %varname) / {%word}
|
||||||
]=], stub_defs
|
]=], stub_defs
|
||||||
var_pattern = re.compile "{| ((('%' {%varname}) / %word) ([ ])*)+ !. |}", stub_defs
|
var_pattern = re.compile "{| ((('%' {%varname}) / %word) ([ ])*)+ !. |}", stub_defs
|
||||||
define_action: (signature, fn, is_compile_action=false)=>
|
define_action: (signature, fn)=>
|
||||||
if type(fn) != 'function'
|
if type(fn) != 'function'
|
||||||
error("Not a function: #{repr fn}")
|
error("Not a function: #{repr fn}")
|
||||||
if type(signature) == 'string'
|
if type(signature) == 'string'
|
||||||
@ -305,17 +311,17 @@ class NomsuCompiler
|
|||||||
fn_info = debug_getinfo(fn, "u")
|
fn_info = debug_getinfo(fn, "u")
|
||||||
assert(not fn_info.isvararg, "Vararg functions aren't supported. Sorry, use a list instead.")
|
assert(not fn_info.isvararg, "Vararg functions aren't supported. Sorry, use a list instead.")
|
||||||
fn_arg_positions = {debug.getlocal(fn, i), i for i=1,fn_info.nparams}
|
fn_arg_positions = {debug.getlocal(fn, i), i for i=1,fn_info.nparams}
|
||||||
actions = (is_compile_action and @environment.COMPILE_ACTIONS or @environment.ACTIONS)
|
|
||||||
arg_orders = {}
|
arg_orders = {}
|
||||||
for alias in *signature
|
for alias in *signature
|
||||||
stub = concat(assert(stub_pattern\match(alias)), ' ')
|
stub = concat(assert(stub_pattern\match(alias)), ' ')
|
||||||
stub_args = assert(var_pattern\match(alias))
|
stub_args = assert(var_pattern\match(alias))
|
||||||
actions[stub] = fn
|
@environment['ACTION'..string.as_lua_id(stub)] = fn
|
||||||
arg_orders[stub] = [fn_arg_positions[string.as_lua_id a] for a in *stub_args]
|
arg_orders[stub] = [fn_arg_positions[string.as_lua_id a] 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)=>
|
||||||
return @define_action(signature, fn, true)
|
@define_action(signature, fn)
|
||||||
|
@environment.COMPILE_TIME[fn] = true
|
||||||
|
|
||||||
parse: (nomsu_code)=>
|
parse: (nomsu_code)=>
|
||||||
assert(type(nomsu_code) != 'string')
|
assert(type(nomsu_code) != 'string')
|
||||||
@ -391,7 +397,7 @@ class NomsuCompiler
|
|||||||
run_lua: (lua)=>
|
run_lua: (lua)=>
|
||||||
assert(type(lua) != 'string', "Attempt to run lua string instead of Lua (object)")
|
assert(type(lua) != 'string', "Attempt to run lua string instead of Lua (object)")
|
||||||
lua_string = tostring(lua)
|
lua_string = tostring(lua)
|
||||||
run_lua_fn, err = load(lua_string, tostring(lua.source), "t", @environment)
|
run_lua_fn, err = load(lua_string, nil and tostring(lua.source), "t", @environment)
|
||||||
if not run_lua_fn
|
if not run_lua_fn
|
||||||
n = 1
|
n = 1
|
||||||
fn = ->
|
fn = ->
|
||||||
@ -431,20 +437,19 @@ class NomsuCompiler
|
|||||||
switch tree.type
|
switch tree.type
|
||||||
when "Action"
|
when "Action"
|
||||||
stub = tree.stub
|
stub = tree.stub
|
||||||
compile_action = @environment.COMPILE_ACTIONS[stub]
|
action = @environment['ACTION'..string.as_lua_id(stub)]
|
||||||
if compile_action
|
if action and @environment.COMPILE_TIME[action]
|
||||||
args = [arg for arg in *tree when type(arg) != "string"]
|
args = [arg for arg in *tree when type(arg) != "string"]
|
||||||
-- Force all compile-time actions to take a tree location
|
-- Force all compile-time actions to take a tree location
|
||||||
arg_orders = @environment.ARG_ORDERS[compile_action]
|
if arg_orders = @environment.ARG_ORDERS[stub]
|
||||||
args = [args[p-1] for p in *arg_orders[stub]]
|
args = [args[p] for p in *arg_orders]
|
||||||
-- Force Lua to avoid tail call optimization for debugging purposes
|
-- Force Lua to avoid tail call optimization for debugging purposes
|
||||||
-- TODO: use tail call
|
-- TODO: use tail call
|
||||||
ret = compile_action(tree, unpack(args))
|
ret = action(tree, unpack(args))
|
||||||
if not ret
|
if not ret
|
||||||
compile_error tree,
|
compile_error tree,
|
||||||
"Compile-time action:\n%s\nfailed to produce any Lua"
|
"Compile-time action:\n%s\nfailed to produce any Lua"
|
||||||
return ret
|
return ret
|
||||||
action = rawget(@environment.ACTIONS, stub)
|
|
||||||
lua = Lua.Value(tree.source)
|
lua = Lua.Value(tree.source)
|
||||||
if not action and math_expression\match(stub)
|
if not action and math_expression\match(stub)
|
||||||
-- This is a bit of a hack, but this code handles arbitrarily complex
|
-- This is a bit of a hack, but this code handles arbitrarily complex
|
||||||
@ -476,11 +481,10 @@ class NomsuCompiler
|
|||||||
insert args, arg_lua
|
insert args, arg_lua
|
||||||
|
|
||||||
if action
|
if action
|
||||||
args = [args[p] for p in *@environment.ARG_ORDERS[action][stub]]
|
if arg_orders = @environment.ARG_ORDERS[stub]
|
||||||
|
args = [args[p] for p in *arg_orders]
|
||||||
|
|
||||||
-- Not really worth bothering with ACTIONS.foo(...) style since almost every action
|
lua\append "ACTION",string.as_lua_id(stub),"("
|
||||||
-- has arguments, so it won't work
|
|
||||||
lua\append "ACTIONS[",repr(stub),"]("
|
|
||||||
for i, arg in ipairs args
|
for i, arg in ipairs args
|
||||||
lua\append arg
|
lua\append arg
|
||||||
if i < #args then lua\append ", "
|
if i < #args then lua\append ", "
|
||||||
@ -883,18 +887,25 @@ class NomsuCompiler
|
|||||||
return Lua(_block.source, "if IMMEDIATE then\n ", lua, "\nend")
|
return Lua(_block.source, "if IMMEDIATE then\n ", lua, "\nend")
|
||||||
|
|
||||||
add_lua_string_bits = (lua, code)->
|
add_lua_string_bits = (lua, code)->
|
||||||
|
line_len = 0
|
||||||
if code.type != "Text"
|
if code.type != "Text"
|
||||||
lua\append ", ", nomsu\tree_to_lua(code)
|
lua\append ", ", nomsu\tree_to_lua(code)
|
||||||
return
|
return
|
||||||
for bit in *code
|
for bit in *code
|
||||||
lua\append ", "
|
bit_lua = if type(bit) == "string"
|
||||||
if type(bit) == "string"
|
repr(bit)
|
||||||
lua\append repr(bit)
|
|
||||||
else
|
else
|
||||||
bit_lua = nomsu\tree_to_lua(bit)
|
bit_lua = nomsu\tree_to_lua(bit)
|
||||||
unless bit_lua.is_value
|
unless bit_lua.is_value
|
||||||
compile_error bit,
|
compile_error bit,
|
||||||
"Cannot use:\n%s\nas a string interpolation value, since it's not an expression."
|
"Cannot use:\n%s\nas a string interpolation value, since it's not an expression."
|
||||||
|
bit_lua
|
||||||
|
line_len += #tostring(bit_lua)
|
||||||
|
if line_len > MAX_LINE
|
||||||
|
lua\append ",\n "
|
||||||
|
line_len = 4
|
||||||
|
else
|
||||||
|
lua\append ", "
|
||||||
lua\append bit_lua
|
lua\append bit_lua
|
||||||
|
|
||||||
@define_compile_action "Lua %code", (_code)=>
|
@define_compile_action "Lua %code", (_code)=>
|
||||||
|
@ -62,6 +62,9 @@ Tree = function(name, methods)
|
|||||||
if type(source) == 'string' then
|
if type(source) == 'string' then
|
||||||
source = Source:from_string(source)
|
source = Source:from_string(source)
|
||||||
end
|
end
|
||||||
|
for i = 1, select('#', ...) do
|
||||||
|
assert(select(i, ...))
|
||||||
|
end
|
||||||
assert(Source:is_instance(source))
|
assert(Source:is_instance(source))
|
||||||
local inst = {
|
local inst = {
|
||||||
source = source,
|
source = source,
|
||||||
|
@ -37,6 +37,7 @@ Tree = (name, methods)->
|
|||||||
__call: (source, ...)=>
|
__call: (source, ...)=>
|
||||||
if type(source) == 'string'
|
if type(source) == 'string'
|
||||||
source = Source\from_string(source)
|
source = Source\from_string(source)
|
||||||
|
for i=1,select('#', ...) do assert(select(i,...))
|
||||||
assert(Source\is_instance(source))
|
assert(Source\is_instance(source))
|
||||||
inst = {:source, ...}
|
inst = {:source, ...}
|
||||||
setmetatable(inst, @)
|
setmetatable(inst, @)
|
||||||
|
@ -49,6 +49,7 @@ assume ((%1 = 2) and (%2 = 1)) or barf "'parse % as %' failed on 'swap % and %'"
|
|||||||
swap %tmp and %tmp2
|
swap %tmp and %tmp2
|
||||||
assume ((%tmp = 2) and (%tmp2 = 1)) or barf "'parse % as %' variable mangling failed."
|
assume ((%tmp = 2) and (%tmp2 = 1)) or barf "'parse % as %' variable mangling failed."
|
||||||
|
|
||||||
|
#
|
||||||
remove action (foo %)
|
remove action (foo %)
|
||||||
try: foo 99
|
try: foo 99
|
||||||
..and if it succeeds: barf "Failed to delete action"
|
..and if it succeeds: barf "Failed to delete action"
|
||||||
|
@ -15,10 +15,10 @@ using
|
|||||||
action [baz]
|
action [baz]
|
||||||
return "outer"
|
return "outer"
|
||||||
|
|
||||||
using
|
#
|
||||||
action [baz]
|
do
|
||||||
|
local action [baz]
|
||||||
return "inner"
|
return "inner"
|
||||||
..do
|
|
||||||
assume: (baz) = "inner"
|
assume: (baz) = "inner"
|
||||||
assume: (baz) = "outer"
|
assume: (baz) = "outer"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user