diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2019-01-14 15:42:48 -0800 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2019-01-14 15:43:24 -0800 |
| commit | c1c32688a4afc43f6addb99b8b5fa878944a70e3 (patch) | |
| tree | c886f21b5b08a9053aa74fcba4b241dae5ede76d /core/metaprogramming.nom | |
| parent | 2309b696fc34b24f05f6658b94f9105ca8ee76e4 (diff) | |
Overhaul in progress, mostly working. Moved all the nomsu packages into
lib/, including core/*. Changes to how nomsu environments and importing
work.
Diffstat (limited to 'core/metaprogramming.nom')
| -rw-r--r-- | core/metaprogramming.nom | 454 |
1 files changed, 0 insertions, 454 deletions
diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom deleted file mode 100644 index fa29a8a..0000000 --- a/core/metaprogramming.nom +++ /dev/null @@ -1,454 +0,0 @@ -#!/usr/bin/env nomsu -V6.14 -# - This File contains actions for making actions and compile-time actions and some helper - functions to make that easier. - -lua> "NOMSU_CORE_VERSION = 14" -lua> "NOMSU_LIB_VERSION = 8" -lua> (" - do - local mangle_index = 0 - function mangler() - local my_mangle_index = mangle_index - mangle_index = mangle_index + 1 - return function(varname) - return (varname..(("\\3%X"):format(my_mangle_index))):as_lua_id() - end - end - end - COMPILE_RULES["define mangler"] = function(\(nomsu environment)) - return LuaCode("local mangle = mangler()") - end -") - -lua> (" - COMPILE_RULES["1 ->"] = function(\(nomsu environment), \$args, \$body) - if \$args and not \$body then \$args, \$body = {}, \$args end - local body_lua = SyntaxTree:is_instance(\$body) and \(nomsu environment):compile(\$body) or \$body - if SyntaxTree:is_instance(\$body) and \$body.type ~= "Block" then body_lua:prepend("\ - ..return ") end - local lua = LuaCode("(function(") - if SyntaxTree:is_instance(\$args) and (\$args.type == "Action" or \$args.type == "MethodCall") then - \$args = \$args:get_args() - elseif SyntaxTree:is_instance(\$args) and \$args.type == "Var" then \$args = {\$args} end - for i, arg in ipairs(\$args) do - local arg_lua = SyntaxTree:is_instance(arg) and \(nomsu environment):compile(arg):text() or arg - if arg_lua == "..." then - if i < #\$args then - compile_error_at(SyntaxTree:is_instance(arg) and arg or nil, - "Extra arguments must come last.", "Try removing any arguments after \ - ..(*extra arguments*)") - end - elseif not arg_lua:is_lua_id() then - compile_error_at(SyntaxTree:is_instance(arg) and arg or nil, - "This does not compile to a Lua identifier, so it can't be used as a function \ - ..argument.", - "This should probably be a Nomsu variable instead (like $x).") - end - lua:add(i > 1 and ", " or "", arg_lua) - body_lua:remove_free_vars({arg_lua}) - end - body_lua:declare_locals() - lua:add(")\\n ", body_lua, "\\nend)") - return lua - end - COMPILE_RULES["->"] = COMPILE_RULES["1 ->"] - COMPILE_RULES["for"] = COMPILE_RULES["1 ->"] -") - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -test: - (five) compiles to "5" - -test: - unless ((five) == 5): - fail "Compile to expression failed." - (loc x) compiles to "local x = 99;" - -test: - lua> "do" - loc x - unless ($x is 99): - fail "Compile to statements with locals failed." - lua> "end" - unless ($x is (nil)): - fail "Failed to properly localize a variable." - - (asdf) compiles to: - $tmp = "" - return (Lua $tmp) - -test: - asdf - unless ($tmp is (nil)): - fail "compile to is leaking variables" - -lua> (" - COMPILE_RULES["1 compiles to"] = function(env, \$action, \$body) - local \$args = List{"\(nomsu environment)", unpack(\$action:get_args())} - if \$body.type == "Text" then - \$body = SyntaxTree{source=\$body.source, type="Action", "Lua", \$body} - end - return LuaCode("COMPILE_RULES[", \$action:get_stub():as_lua(), - "] = ", \(\($args -> $body) as lua)) - end -") - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -($actions all compile to $body) compiles to: - lua> (" - if \$actions.type ~= "List" then - compile_error(\$actions, "This should be a list of actions.") - end - local lua = \(\($actions.1 compiles to $body) as lua) - local \$args = List{"\(nomsu environment)", unpack(\$actions[1]:get_args())} - local \$compiled_args = List{"\(nomsu environment)"}; - for i=2,#\$args do \$compiled_args[i] = \(nomsu environment):compile(\$args[i]) end - for i=2,#\$actions do - local alias = \$actions[i] - local \$alias_args = List{"\(nomsu environment)", unpack(alias:get_args())} - lua:add("\\nCOMPILE_RULES[", alias:get_stub():as_lua(), "] = ") - if \$alias_args == \$args then - lua:add("COMPILE_RULES[", \$actions[1]:get_stub():as_lua(), "]") - else - lua:add("function(") - local \$compiled_alias_args = List{"\(nomsu environment)"}; - for i=2,#\$alias_args do \$compiled_alias_args[i] = \(nomsu environment):compile(\$alias_args[i]) end - lua:concat_add(\$compiled_alias_args, ", ") - lua:add(") return COMPILE_RULES[", \$actions[1]:get_stub():as_lua(), "](") - lua:concat_add(\$compiled_args, ", ") - lua:add(") end") - end - end - return lua - ") - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -test: - (foo $x) means "outer" - with [$(foo $)]: - (foo $x) means: - $y = ($x + 1) - return $y - - unless ((foo 10) == 11): - fail "Action didn't work." - - unless ($y is (nil)): - fail "Action leaked a local into globals." - - (baz $) parses as (foo $) - assume ((foo 1) == "outer") - -($action means $body) compiles to: - lua> (" - - local lua = LuaCode() - if \$action.type == "MethodCall" then - lua:add(\(nomsu environment):compile(\$action[1]), ".", \$action[2]:get_stub():as_lua_id()) - elseif \$action.type == "Action" then - lua:add(\$action:get_stub():as_lua_id()) - lua:add_free_vars({\$action:get_stub():as_lua_id()}) - else - compile_error_at(\$action, "Expected an action or method call here") - end - lua:add(" = ", \(\($action -> $body) as lua), ";") - return lua - ") - -($actions all mean $body) compiles to: - lua> (" - local lua = \(\($actions.1 means $body) as lua) - local first_def = (\$actions[1].type == "MethodCall" - and LuaCode(\(nomsu environment):compile(\$actions[1][1]), ".", \$actions[1]:get_stub():as_lua_id()) - or LuaCode(\$actions[1]:get_stub():as_lua_id())) - local \$args = List(\$actions[1]:get_args()) - for i=2,#\$actions do - local alias = \$actions[i] - local \$alias_args = List(alias:get_args()) - lua:add("\\n") - if alias.type == "MethodCall" then - lua:add(\(nomsu environment):compile(alias[1]), ".", alias:get_stub():as_lua_id()) - else - lua:add(alias:get_stub():as_lua_id()) - lua:add_free_vars({alias_name}) - end - if \$args == \$alias_args then - lua:add(" = ", first_def, ";") - else - lua:add(" = ", \(\($alias_args -> $actions.1) as lua), ";") - end - end - return lua - ") - -test: - externally (baz1) means: - return "baz1" - externally (baz2) means "baz2" - -test: - assume ((baz1) == "baz1") - assume ((baz2) == "baz2") - -(externally $action means $body) compiles to: - lua> (" - local lua = \(\($action means $body) as lua) - lua:remove_free_vars({\$action:get_stub():as_lua_id()}) - return lua - ") - -(externally $actions all mean $body) compiles to: - lua> (" - local lua = \(\($actions all mean $body) as lua) - lua:remove_free_vars(table.map(\$actions, function(a) return a:get_stub():as_lua_id() end)) - return lua - ") - -test: - (swap $x and $y) parses as - do: - $tmp = $x - $x = $y - $y = $tmp - -test: - [$1, $2] = [1, 2] - swap $1 and $2 - unless (($1 == 2) and ($2 == 1)): - fail "'parse $ as $' failed on 'swap $ and $'" - [$tmp, $tmp2] = [1, 2] - swap $tmp and $tmp2 - unless (($tmp == 2) and ($tmp2 == 1)): - fail "'parse $ as $' variable mangling failed." - -($actions all parse as $body) compiles to: - lua> (" - local replacements = {} - if \$actions.type ~= "List" then - compile_error(\$actions, "This should be a list.") - end - for i,arg in ipairs(\$actions[1]:get_args()) do - replacements[arg[1]] = \(nomsu environment):compile(arg):text() - end - local function make_tree(t) - if SyntaxTree:is_instance(t) and t.type == "Var" then - if replacements[t:as_var()] then - return replacements[t:as_var()] - else - return "SyntaxTree{mangle("..t:as_var():as_lua().."), type="..t.type:as_lua()..", \ - ..source="..tostring(t.source):as_lua().."}" - end - elseif SyntaxTree:is_instance(t) then - local ret = {} - local i = 1 - for k, v in pairs(t) do - if k == i then - ret[#ret+1] = make_tree(t[i]) - i = i + 1 - elseif k == "source" then - ret[#ret+1] = k.."= "..tostring(v):as_lua() - elseif lua_type_of(k) == 'string' and k:is_a_lua_id() then - ret[#ret+1] = k.."= "..make_tree(v) - else - ret[#ret+1] = "["..make_tree(k).."]= "..make_tree(v) - end - end - return "SyntaxTree{"..table.concat(ret, ", ").."}" - elseif lua_type_of(t) == 'number' then - return tostring(t) - else - return t:as_lua() - end - end - local \$new_body = LuaCode:from(\$body.source, - "local mangle = mangler()", - "\\nreturn ", make_tree(\$body)) - local ret = \(\($actions all compile to $new_body) as lua) - return ret - ") - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -[$action parses as $body] all parse as ([$action] all parse as $body) -externally ($tree as lua expr) means: - lua> (" - local tree_lua = \(nomsu environment):compile(\$tree) - if \$tree.type == 'Block' then - tree_lua = LuaCode:from(\$tree.source, '(function()\\n ', tree_lua, '\\nend)()') - elseif \$tree.type == 'MethodCall' and #\$tree > 2 then - compile_error_at(\$tree, "This must be a single value instead of "..(#\$tree - 1).."\ - .. method calls.", - "Replace this with a single method call.") - end - return tree_lua - ") - -externally [$var as lua identifier, $var as lua id] all mean: - lua> (" - local lua = \($var as lua) - if not lua:text():is_a_lua_id() then - compile_error(\$var, - "This is supposed to be something that compiles to a valid Lua identifier.", - "This should probably be a variable.") - end - return lua - ") - -test: - (num args (*extra arguments*)) means (select "#" (*extra arguments*)) - assume (num args 1 2 3) == 3 - (extra args (*extra arguments*)) means [*extra arguments*] - assume (extra args 1 2 3) == [1, 2, 3] - (third arg (*extra arguments*)) means (select 3 (*extra arguments*)) - assume (third arg 5 6 7 8) == 7 - -(*extra arguments*) compiles to "..." - -($ is syntax tree) compiles to "SyntaxTree:is_instance(\($ as lua expr))" - -externally ($ is $kind syntax tree) means - =lua "SyntaxTree:is_instance(\$) and \$.type == \$kind" - -($tree with $t -> $replacement) compiles to (" - \($tree as lua expr):map(function(\($t as lua expr)) - \( - =lua (" - \$replacement.type == 'Block' and \($replacement as lua) or 'return '..\ - ..\($replacement as lua expr):text() - ") - ) - end) -") - -externally ($tree with vars $replacements) means - =lua (" - \$tree:map(function(\$t) - if \$t.type == "Var" then - return \$replacements[\$t:as_var()] - end - end) - ") - -(tree $tree with vars $replacements) compiles to (" - \(=lua "(\$tree):as_lua()"):map(function(t) - if t.type == "Var" then - return \($replacements as lua expr)[t:as_var()] - end - end) -") - -($tree has subtree $match_tree) compiles to (" - (function() - local match_tree = \($match_tree as lua expr) - for subtree in coroutine_wrap(function() \($tree as lua expr):map(yield) end) do - if subtree == match_tree then return true end - end - end)() -") - -externally (match $tree with $patt) means: - lua> (" - if \$patt.type == "Var" then return Dict{[\$patt:as_var()]=\$tree} end - if \$patt.type == "Action" and \$patt:get_stub() ~= \$tree:get_stub() then return nil end - if #\$patt ~= #\$tree then return nil end - local matches = Dict{} - for \($i)=1,#\$patt do - if SyntaxTree:is_instance(\$tree[\$i]) then - local submatch = \(match $tree.$i with $patt.$i) - if not submatch then return nil end - for k,v in pairs(submatch) do - if matches[k] and matches[k] ~= v then return nil end - matches[k] = v - end - end - end - return matches - ") - -test: - assume - ( - quote (" - one - "two" - ") - ) == "\"one\\n\\\"two\\\"\"" - -(quote $s) compiles to "tostring(\($s as lua expr)):as_lua()" -test: - assume (lua type of {}) == "table" - assume (type of {}) == "Dict" - assume ({} is a "Dict") - assume ("" is text) - assume ("" isn't a "Dict") -externally ($ is text) means (=lua "\(lua type of $) == 'string'") -externally [$ is not text, $ isn't text] all mean - =lua "\(lua type of $) ~= 'string'" - -externally (type of $) means: - lua> (" - local lua_type = \(lua type of $) - if lua_type == 'string' then return 'Text' - elseif lua_type == 'table' or lua_type == 'userdata' then - local mt = getmetatable(\$) - if mt and mt.__type then return mt.__type end - end - return lua_type - ") - -[$ is a $type, $ is an $type] all parse as ((type of $) == $type) -[$ isn't a $type, $ isn't an $type, $ is not a $type, $ is not an $type] -..all parse as ((type of $) != $type) - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -test: - (foo) means: - return 100 200 300 - assume (select 2 (foo)) == 200 - -# 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. -(return (*extra arguments*)) compiles to: - lua> (" - local lua = \(Lua "do return ") - for i=1,select('#',...) do - if i > 1 then lua:add(", ") end - lua:add(\(nomsu environment):compile((select(i, ...)))) - end - lua:add(" end") - return lua - ") - -# Literals -(yes) compiles to "true" -(no) compiles to "false" -[nothing, nil, null] all compile to "nil" -(Nomsu syntax version) compiles to "NOMSU_SYNTAX_VERSION" -(Nomsu compiler version) compiles to "NOMSU_COMPILER_VERSION" -(core version) compiles to "NOMSU_CORE_VERSION" -(lib version) compiles to "NOMSU_LIB_VERSION" -(command line args) compiles to "COMMAND_LINE_ARGS" - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -# - (with local compile actions $body) compiles to (" - do - local OLD_RULES = COMPILE_RULES - local OLD_ENV = \(nomsu environment) - local \(nomsu environment) = setmetatable({ - COMPILE_RULES=setmetatable({}, {__index=OLD_RULES}) - }, {__index=OLD_ENV}) - \($body as lua) - end - ") - -externally (Nomsu version) means: - return (" - \(Nomsu syntax version).\(core version).\(Nomsu compiler version).\(lib version) - ") |
