aboutsummaryrefslogtreecommitdiff
path: root/core/metaprogramming.nom
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2019-01-14 15:42:48 -0800
committerBruce Hill <bruce@bruce-hill.com>2019-01-14 15:43:24 -0800
commitc1c32688a4afc43f6addb99b8b5fa878944a70e3 (patch)
treec886f21b5b08a9053aa74fcba4b241dae5ede76d /core/metaprogramming.nom
parent2309b696fc34b24f05f6658b94f9105ca8ee76e4 (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.nom454
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)
- ")