nomsu/core/metaprogramming.nom
2018-06-18 18:11:09 -07:00

203 lines
8.1 KiB
Plaintext

#
This File contains actions for making actions and compile-time actions and some helper
functions to make that easier.
lua> ".."
nomsu.COMPILE_ACTIONS["% -> %"] = function(nomsu, tree, \%args, \%body)
local lua = LuaCode(tree.source, "function(")
if AST.is_syntax_tree(\%args, "Action") then \%args = \%args:get_args() end
local lua_args = table.map(\%args, function(a) return AST.is_syntax_tree(a) and tostring(nomsu:compile(a)) or a end)
lua:concat_append(lua_args, ", ")
local body_lua = AST.is_syntax_tree(\%body) and nomsu:compile(\%body):as_statements("return ") or \%body
body_lua:remove_free_vars(lua_args)
body_lua:declare_locals()
lua:append(")\n ", body_lua, "\nend")
return lua
end
lua> ".."
nomsu.COMPILE_ACTIONS["compile as %"] = function(nomsu, tree, \%action)
local lua = LuaCode.Value(tree.source, "nomsu.COMPILE_ACTIONS[", repr(\%action.stub), "](")
local lua_args = table.map(\%action:get_args(), function(a) return nomsu:compile(a) end)
table.insert(lua_args, 1, "nomsu")
table.insert(lua_args, 2, "tree")
lua:concat_append(lua_args, ", ")
lua:append(")")
return lua
end
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
lua> ".."
nomsu.COMPILE_ACTIONS["compile % to %"] = function(nomsu, tree, \%actions, \%body)
local \%args = {"nomsu", "tree", unpack(table.map(\%actions[1]:get_args(), function(a) return tostring(nomsu:compile(a)) end))}
local lua = LuaCode(tree.source, "nomsu.COMPILE_ACTIONS[", repr(\%actions[1].stub),
"] = ", \(compile as: %args -> %body))
for i=2,#\%actions do
local alias = \%actions[i]
local \%alias_args = {"nomsu", "tree", unpack(table.map(alias:get_args(), function(a) return tostring(nomsu:compile(a)) end))}
lua:append("\nnomsu.COMPILE_ACTIONS[", repr(alias.stub), "] = ")
if utils.equivalent(\%args, \%alias_args) then
lua:append("nomsu.COMPILE_ACTIONS[", repr(\%actions[1].stub), "]")
else
lua:append("function(")
lua:concat_append(\%alias_args, ", ")
lua:append(")\n return nomsu.COMPILE_ACTIONS[", repr(\%actions[1].stub), "](")
lua:concat_append(\%args, ", ")
lua:append(")\nend")
end
end
return lua
end
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compile [local action %actions %body] to
lua> ".."
local fn_name = "A"..string.as_lua_id(\%actions[1].stub)
local \%args = table.map(\%actions[1]:get_args(), function(a) return tostring(nomsu:compile(a)) end)
local lua = LuaCode(tree.source, fn_name, " = ", \(compile as: %args -> %body))
lua:add_free_vars({fn_name})
for i=2,#\%actions do
local alias = \%actions[i]
local alias_name = "A"..string.as_lua_id(alias.stub)
lua:add_free_vars({alias_name})
local \%alias_args = table.map(alias:get_args(), function(a) return tostring(nomsu:compile(a)) end)
lua:append("\n", alias_name, " = ")
if utils.equivalent(\%args, \%alias_args) then
lua:append(fn_name)
else
lua:append("function(")
lua:concat_append(\%alias_args, ", ")
lua:append(")\n return ", fn_name, "(")
lua:concat_append(\%args, ", ")
lua:append(")\nend")
end
end
return lua
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compile [action %actions %body] to
lua> ".."
local lua = \(compile as: local action %actions %body)
lua:remove_free_vars(table.map(\%actions, function(a) return "A"..string.as_lua_id(a.stub) end))
return lua
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compile [parse %actions as %body] to
lua> ".."
local replacements = {}
for i,arg in ipairs(\%actions[1]:get_args()) do
replacements[arg[1]] = tostring(nomsu:compile(arg))
end
local function make_tree(t)
if not AST.is_syntax_tree(t) then
return repr(t)
elseif t.type ~= 'Var' then
local args = {repr(tostring(t.source)), unpack(table.map(t, make_tree))}
return t.type.."("..table.concat(args, ", ")..")"
elseif replacements[t[1]] then
return replacements[t[1]]
else
return t.type.."("..repr(tostring(t.source))..", "..repr(t[1].." \\0").."..string.format('%X', __MANGLE_INDEX))"
end
end
local \%new_body = LuaCode(\%body.source,
"__MANGLE_INDEX = (__MANGLE_INDEX or 0) + 1",
"\nlocal tree = ", make_tree(\%body),
"\nreturn nomsu:compile(tree)")
return \(compile as: compile %actions to %new_body)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compile [remove action %action] to
Lua ".."
A\(=lua "string.as_lua_id(\(%action.stub))") = nil
action [%tree as nomsu]
=lua "nomsu:tree_to_nomsu(\%tree)"
action [%tree as inline nomsu]
=lua "nomsu:tree_to_nomsu(\%tree, true)"
action [%tree as lua]
=lua "nomsu:compile(\%tree)"
action [%tree as lua expr]
lua> ".."
local lua = nomsu:compile(\%tree)
if not lua.is_value then
nomsu:compile_error(\%tree, "Invalid thing to convert to lua expr:\n%s")
end
return lua
action [%tree as lua statements]
=lua "nomsu:compile(\%tree):as_statements()"
action [%tree as lua return]
=lua "nomsu:compile(\%tree):as_statements('return ')"
action [%var as lua identifier, %var as lua id]
lua> ".."
if type(\%var) == 'string' then return string.as_lua_id(\%var)
elseif \%var.type == 'Var' then return string.as_lua_id(\%var[1])
elseif \%var.type == 'Action' then return "A"..string.as_lua_id(\%var.stub)
end
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compile [%tree with %t -> %replacement] to
Lua value ".."
\(%tree as lua expr):map(function(\(%t as lua expr))
\(%replacement as lua return)
end)
compile [declare locals in %code] to
Lua value "\(%code as lua expr):declare_locals()"
compile [declare locals %locals in %code] to
Lua value "\(%code as lua expr):declare_locals(\(%locals as lua expr))"
compile [remove free vars %vars from %code] to
Lua "\(%code as lua expr):remove_free_vars(\(%vars as lua expr));"
parse [%lua <-write %code, to %lua write %code] as: lua> "\%lua:append(\%code);"
compile [quote %s] to
Lua value ".."
('"'..\(%s as lua expr):gsub("\\\\", "\\\\\\\\"):gsub("\n","\\\\n"):gsub('"', '\\\\"')..'"')
compile [type of %obj] to: Lua value "type(\(%obj as lua expr))"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compile [parse %text] to
Lua value ".."
nomsu:parse(NomsuCode("\("\(%text.source)")", \(%text as lua expr)))
compile [run %nomsu_code] to
Lua value "nomsu:run(NomsuCode(\(quote "\(%nomsu_code.source)"), \(%nomsu_code as lua expr)))"
action [run tree %tree, %tree as value]
lua> ".."
if \%tree.type == 'Text' and #\%tree == 1 and type(\%tree[1]) == 'string' then
return \%tree[1]
end
local lua = LuaCode(\%tree.source, "return ",nomsu:compile(\%tree))
return nomsu:run_lua(lua)
compile [compile %block, compiled %block, %block compiled] to
Lua value "nomsu:compile(\(%block as lua))"
# Return statement is wrapped in a do..end block because Lua is unhappy if you
put code after a return statement, unless you wrap it in a block.
compile [return] to: Lua "do return; end"
compile [return %return_value] to: Lua "do return \(%return_value as lua expr); end"
# Literals
compile [yes] to: Lua value "true"
compile [no] to: Lua value "false"
compile [nothing, nil, null] to: Lua value "nil"