diff options
| author | Bruce Hill <bitbucket@bruce-hill.com> | 2018-01-25 17:34:49 -0800 |
|---|---|---|
| committer | Bruce Hill <bitbucket@bruce-hill.com> | 2018-01-25 17:36:05 -0800 |
| commit | c79bea44016daf43f05300b772011b14125fa0df (patch) | |
| tree | 10dbbc3bef495662be829b73893660622bd2d2c1 /lib/metaprogramming.nom | |
| parent | f769351556cceed58ab6bf844c671114ec1862c2 (diff) | |
Overhaul of compiling API (eliminated some of the expr/statements
helpers and forced the use of {expr=..., locals=...}-type syntax. This
helped fix up all of the cases like loops where locals were being
mishandled and led to some cleaner code.
Diffstat (limited to 'lib/metaprogramming.nom')
| -rw-r--r-- | lib/metaprogramming.nom | 245 |
1 files changed, 115 insertions, 130 deletions
diff --git a/lib/metaprogramming.nom b/lib/metaprogramming.nom index e7de602..49e20ee 100644 --- a/lib/metaprogramming.nom +++ b/lib/metaprogramming.nom @@ -2,134 +2,99 @@ This File contains actions for making actions and compile-time actions and some helper functions to make that easier. -# Helper function -immediately - lua> ".." - nomsu.parse_spec = function(nomsu, spec) - if spec.type == 'List' then - local names = {}; - for i, alias in ipairs(spec.value) do - if alias.type == "FunctionCall" then - names[i] = alias.src; - elseif alias.type == "Text" then - names[i] = nomsu:tree_to_value(alias); - end - end - local junk, arg_names, junk = nomsu:get_stub(names[1]); - local args = {}; - for i, a in ipairs(arg_names) do args[i] = nomsu:var_to_lua_identifier(a); end - return names, args; - else - local alias = nomsu:tree_to_value(spec); - local junk, arg_names, junk = nomsu:get_stub(alias); - local args = {}; - for i, a in ipairs(arg_names) do args[i] = nomsu:var_to_lua_identifier(a); end - return {alias}, args; - end - end - # Compile-time action to make compile-time actions: -# TODO: reduce code duplication here immediately lua> ".." - do - local function compile_to(name_tree, body_tree, kind) - local names, args = nomsu:parse_spec(name_tree); - local declared_locals = {}; - for i, arg in ipairs(args) do declared_locals[arg] = true; end - names, args = repr(names), table.concat(args, ", "); - local body_lua = nomsu:tree_to_lua(body_tree); - if body_lua.expr and not body_lua.locals then - return [[ - nomsu:define_compile_action(]]..names..[[, ]]..repr(name_tree:get_line_no())..[[, function(]]..args..[[) - return {]]..kind..[[=]]..body_lua.expr..[[}; - end, ]]..repr(nomsu:source_code())..[[); - ]]; - end - local body_code = body_lua.statements or ("return "..body_lua.expr..";"); - local undeclared_locals = {}; - for i, body_local in ipairs(body_lua.locals or {}) do - if not declared_locals[body_local] then - table.insert(undeclared_locals, body_local); - end - end - if #undeclared_locals > 0 then - body_code = "local "..table.concat(undeclared_locals, ", ")..";\\n"..body_code; + nomsu:define_compile_action("compile %actions to %lua", \(!! code location !!), function(\%actions, \%lua) + local signature = {}; + for i, action in ipairs(\%actions.value) do signature[i] = action:get_src(); end + local stubs = nomsu:get_stubs_from_signature(signature); + local stub_args = nomsu:get_args_from_signature(signature); + local arg_set = {}; + for i, arg in ipairs(stub_args[1]) do arg_set[arg] = true; end + if \%lua.type == "Text" then + error("Invalid type for 'compile % to %', expected a dict with expr/statements, but got text.", 0); + end + local body_lua = nomsu:tree_to_lua(\%lua); + local body_code = body_lua.statements or ("return "..body_lua.expr..";"); + local undeclared_locals = {}; + for i, body_local in ipairs(body_lua.locals or {}) do + if not arg_set[body_local] then + table.insert(undeclared_locals, body_local); end - return [[ - do - local function compile_action(]]..args..[[) - ]]..body_code.."\\n"..[[ end - nomsu:define_compile_action(]]..names..[[, ]]..repr(name_tree:get_line_no())..[[, function(]]..args..[[) - return {]]..kind..[[=compile_action(]]..args..[[)}; - end, ]]..repr(nomsu:source_code())..[[); - end]]; + if #undeclared_locals > 0 then + body_code = "local "..table.concat(undeclared_locals, ", ")..";\\n"..body_code; end - local src = \(__src__ 1); - nomsu:define_compile_action("compile %names to %body", \(__line_no__), function(\%names, \%body) - return {statements=compile_to(\%names, \%body, "expr")}; - end, src); - nomsu:define_compile_action("compile %names to code %body", \(__line_no__), function(\%names, \%body) - return {statements=compile_to(\%names, \%body, "statements")}; - end, src); - end + local lua_fn_args = table.concat(stub_args[1], ", "); + local def_tree = nomsu.compilestack[#nomsu.compilestack]; + local code_location = ("%s:%s,%s"):format(def_tree.filename, def_tree.start, def_tree.stop); + return {statements=([[ + nomsu:define_compile_action(]]..repr(signature)..[[, ]]..repr(code_location)..[[, function(]]..lua_fn_args..[[) + ]]..body_code.."\\n"..[[ + end); + ]])}; + end); # Compile-time action to make actions immediately - compile [action %names %body] to code + compile [action %actions %body] to lua> ".." - local names, args = nomsu:parse_spec(\%names); - local declared_locals = {}; - for i, arg in ipairs(args) do declared_locals[arg] = true; end - names, args = repr(names), table.concat(args, ", "); + local signature = {}; + for i, action in ipairs(\%actions.value) do signature[i] = action:get_src(); end + local stubs = nomsu:get_stubs_from_signature(signature); + local stub_args = nomsu:get_args_from_signature(signature); + local arg_set = {}; + for i, arg in ipairs(stub_args[1]) do arg_set[arg] = true; end local body_lua = nomsu:tree_to_lua(\%body); local body_code = body_lua.statements or ("return "..body_lua.expr..";"); local undeclared_locals = {}; for i, body_local in ipairs(body_lua.locals or {}) do - if not declared_locals[body_local] then + if not arg_set[body_local] then table.insert(undeclared_locals, body_local); end end if #undeclared_locals > 0 then body_code = "local "..table.concat(undeclared_locals, ", ")..";\\n"..body_code; end - local src = nomsu:dedent(nomsu:source_code(0)); - local def_lua = ([[ - nomsu:define_action(%s, \(__line_no__), function(%s) - %s - end, %s);]]):format(names, args, body_code, repr(src)); - return def_lua; + local lua_fn_args = table.concat(stub_args[1], ", "); + local def_tree = nomsu.compilestack[#nomsu.compilestack]; + local code_location = ("%s:%s,%s"):format(def_tree.filename, def_tree.start, def_tree.stop); + return {statements=[[ + nomsu:define_action(]]..repr(signature)..[[, ]]..repr(code_location)..[[, function(]]..lua_fn_args..[[) + ]]..body_code.."\\n"..[[ + end); + ]]}; # Macro to make nomsu macros: immediately - lua> ".." - nomsu:define_compile_action("parse %shorthand as %longhand", \(__line_no__), (function(\%shorthand, \%longhand) - local names, args = nomsu:parse_spec(\%shorthand); - names, args = repr(names), table.concat(args, ", "); + compile [parse %shorthand as %longhand] to + lua> ".." + local signature = {}; + for i, action in ipairs(\%shorthand.value) do signature[i] = action:get_src(); end + local stubs = nomsu:get_stubs_from_signature(signature); + local stub_args = nomsu:get_args_from_signature(signature); + local lua_fn_args = table.concat(stub_args[1], ", "); local template; if \%longhand.type == "Block" then - template = {}; - for i, line in ipairs(\%longhand.value) do - template[i] = nomsu:dedent(line.src); - end - template = repr(table.concat(template, "\\n")); + local lines = {}; + for i, line in ipairs(\%longhand.value) do lines[i] = nomsu:dedent(line:get_src()); end + template = repr(table.concat(lines, "\\n")); else - template = repr(nomsu:dedent(\%longhand.src)); + template = repr(nomsu:dedent(\%longhand:get_src())); end - local junk, arg_names, junk = nomsu:get_stub(\%shorthand.value[1]); local replacements = {}; - for i, a in ipairs(arg_names) do replacements[i] = "["..repr(a).."]="..nomsu:var_to_lua_identifier(a); end + for i, a in ipairs(stub_args[1]) do replacements[i] = a.."="..a; end replacements = "{"..table.concat(replacements, ", ").."}"; - local lua_code = ([[ - nomsu:define_compile_action(%s, %s, (function(%s) - local template = nomsu:parse(%s, %s); - local replacement = nomsu:tree_with_replaced_vars(template, %s); - return nomsu:tree_to_lua(replacement); - end), %s)]]):format(names, repr(\%shorthand:get_line_no()), args, template, - repr(\%shorthand:get_line_no()), replacements, repr(nomsu:source_code(0))); - return {statements=lua_code}; - end), \(__src__ 1)); + local def_tree = nomsu.compilestack[#nomsu.compilestack]; + local code_location = ("%s:%s,%s"):format(def_tree.filename, def_tree.start, def_tree.stop); + return {statements=[[ + nomsu:define_compile_action(]]..repr(signature)..[[, ]]..repr(code_location)..[[, function(]]..lua_fn_args..[[) + local template = nomsu:parse(]]..template..[[, ]]..repr(def_tree.filename)..[[); + local replacement = nomsu:tree_with_replaced_vars(template, ]]..replacements..[[); + return nomsu:tree_to_lua(replacement); + end); + ]]}; action [remove action %stub] lua> ".." @@ -143,33 +108,41 @@ action [remove action %stub] immediately action [%tree as lua] - =lua "nomsu:tree_to_lua(\%tree).expr" + =lua "nomsu:tree_to_lua(\%tree)" + + action [%tree as lua expr] + lua> ".." + local lua = nomsu:tree_to_lua(\%tree); + if lua.locals or not lua.expr then + error("Invalid thing to convert to lua expr: "..\%tree:get_src()); + end + return lua.expr; + action [%tree as lua statements] lua> ".." local lua = nomsu:tree_to_lua(\%tree); - return lua.statements or (lua.expr..";"); + local code = lua.statements or (lua.expr..";"); + if lua.locals then + code = "local "..table.concat(lua.locals, ", ")..";\\n"..code; + end + return code; + action [%tree as value] =lua "nomsu:tree_to_value(\%tree)" - compile [repr %obj] to - "repr(\(%obj as lua))" - compile [type of %obj] to - "type(\(%obj as lua))" - + immediately - parse [lua do> %block] as - lua> "do" - lua> %block - lua> "end" + compile [%tree's source code, %tree' source code] to {expr:"\(%tree as lua expr):get_src()"} -compile [nomsu] to "nomsu" + compile [repr %obj] to {expr:"repr(\(%obj as lua expr))"} + compile [type of %obj] to {expr:"type(\(%obj as lua expr))"} -compile [nomsu's %key] to "nomsu[\(%key as lua)]" -compile [nomsu %method %args] to "nomsu[\(%method as lua)](nomsu, unpack(\(%args as lua)))" -compile [tree %tree with %replacements] to ".." - nomsu:tree_with_replaced_vars(\(%tree as lua), \(%replacements as lua)) +compile [nomsu] to {expr:"nomsu"} + +compile [nomsu's %key] to {expr:"nomsu[\(%key as lua expr)]"} +compile [nomsu %method %args] to {expr:"nomsu[\(%method as lua expr)](nomsu, unpack(\(%args as lua expr)))"} action [action %names metadata] - =lua "ACTION_METADATA[ACTIONS[\%names]]" + =lua "ACTION_METADATA[ACTIONS[\%names]]" # Get the source code for a function action [help %action] @@ -186,22 +159,34 @@ parse [run %code] as: nomsu "run" [%code] parse [enable debugging] as: lua> "nomsu.debug = true" parse [disable debugging] as: lua> "nomsu.debug = false" -compile [say %message] to - lua> ".." - if \%message.type == "Text" then - return "nomsu:writeln("..\(%message as lua)..")"; - else - return "nomsu:writeln(stringify("..\(%message as lua).."))"; - end +immediately + compile [say %message] to + lua> ".." + if \%message.type == "Text" then + return {statements="nomsu:writeln("..\(%message as lua expr)..");"}; + else + return {statements="nomsu:writeln(stringify("..\(%message as lua expr).."));"}; + end + +# Return +immediately + #.. 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 {statements:"do return; end"} + compile [return %return_value] to {statements:"do return \(%return_value as lua expr); end"} # Error functions -compile [barf!] to "error(nil, 0)" -compile [barf %msg] to "error(\(%msg as lua), 0)" -compile [assume %condition] to "assert(\(%condition as lua))" -compile [assume %condition or barf %msg] to "assert(\(%condition as lua), \(%msg as lua))" +immediately + compile [barf!] to {statements:"error(nil, 0);"} + compile [barf %msg] to {statements:"error(\(%msg as lua expr), 0);"} + compile [assume %condition] to {..} + statements:"if not \(%condition as lua expr) then error('Assumption failed: '..\%condition:get_src(), 0); end" + compile [assume %condition or barf %msg] to {..} + statements:"if not \(%condition as lua expr) then error(\(%msg as lua expr), 0); end" # Literals -compile [yes] to "true" -compile [no] to "false" -compile [nothing, nil, null] to "nil" +immediately + compile [yes] to {expr:"true"} + compile [no] to {expr:"false"} + compile [nothing, nil, null] to {expr:"nil"} |
