From 25e06d1fce660e7c8144425b440f7b1c698e2fb7 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Fri, 13 Apr 2018 15:29:16 -0700 Subject: [PATCH] Getting closer. --- core/metaprogramming.nom | 9 ++- core/operators.nom | 156 ++++++++++++++------------------------- core/text.nom | 6 +- lua_obj.lua | 7 +- lua_obj.moon | 4 +- nomsu.lua | 7 +- nomsu.moon | 4 +- 7 files changed, 84 insertions(+), 109 deletions(-) diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom index 0c7cada..8b1546b 100644 --- a/core/metaprogramming.nom +++ b/core/metaprogramming.nom @@ -82,7 +82,7 @@ immediately: for i, a in ipairs(args) do replacements[i] = a.."="..a; end replacements = "{"..table.concat(replacements, ", ").."}"; lua:append([[) - local template = nomsu_parse(]]..template..[[, ]]..repr(tree.source.filename)..[[); + local template = nomsu:parse(]]..template..[[, ]]..repr(tree.source.filename)..[[); local replacement = nomsu:tree_with_replaced_vars(template, ]]..replacements..[[); return nomsu:tree_to_lua(replacement, nomsu.compilestack[#nomsu.compilestack].source.filename); end); @@ -190,6 +190,13 @@ immediately: if not \(%condition as lua expr) then error(\(repr %assumption), 0); end + + # TODO: factor this out and replace with "unless %condition: barf %message" + compile [assume %condition or barf %message] to: + Lua ".." + if not \(%condition as lua expr) then + error(\(%message as lua expr), 0); + end # Literals immediately: diff --git a/core/operators.nom b/core/operators.nom index 7d3f79f..358962d 100644 --- a/core/operators.nom +++ b/core/operators.nom @@ -18,140 +18,98 @@ immediately: # Comparison Operators immediately: - compile [%x < %y] to {expr:"(\(%x as lua expr) < \(%y as lua expr))"} - compile [%x > %y] to {expr:"(\(%x as lua expr) > \(%y as lua expr))"} - compile [%x <= %y] to {expr:"(\(%x as lua expr) <= \(%y as lua expr))"} - compile [%x >= %y] to {expr:"(\(%x as lua expr) >= \(%y as lua expr))"} + compile [%x < %y] to: LuaValue "(\(%x as lua expr) < \(%y as lua expr))" + compile [%x > %y] to: LuaValue "(\(%x as lua expr) > \(%y as lua expr))" + compile [%x <= %y] to: LuaValue "(\(%x as lua expr) <= \(%y as lua expr))" + compile [%x >= %y] to: LuaValue "(\(%x as lua expr) >= \(%y as lua expr))" # TODO: optimize case of [%x,%y] = [1,2] compile [%a is %b, %a = %b, %a == %b] to: lua> ".." local safe = {Text=true, Number=true}; - local a_lua, b_lua = nomsu:tree_to_lua(\%a).expr, nomsu:tree_to_lua(\%b).expr; + local a_lua, b_lua = nomsu:tree_to_lua(\%a), nomsu:tree_to_lua(\%b); if safe[\%a.type] or safe[\%b.type] then - return {expr="("..a_lua.." == "..b_lua..")"}; + return LuaValue(tree.source, "(", a_lua, " == ", b_lua, ")"); else - return {expr="utils.equivalent("..a_lua..", "..b_lua..")"}; + return LuaValue(tree.source, "utils.equivalent(", a_lua, ", ", b_lua, ")"); end compile [%a isn't %b, %a is not %b, %a not= %b, %a != %b] to: lua> ".." local safe = {Text=true, Number=true}; - local a_lua, b_lua = nomsu:tree_to_lua(\%a).expr, nomsu:tree_to_lua(\%b).expr; + local a_lua, b_lua = nomsu:tree_to_lua(\%a), nomsu:tree_to_lua(\%b); if safe[\%a.type] or safe[\%b.type] then - return {expr="("..a_lua.." ~= "..b_lua..")"}; + return LuaValue(tree.source, "(", a_lua, " ~= ", b_lua, ")"); else - return {expr="(not utils.equivalent("..a_lua..", "..b_lua.."))"}; + return LuaValue(tree.source, "(not utils.equivalent(", a_lua, ", ", b_lua, "))"); end # For strict identity checking, use (%x's id) is (%y's id) - compile [%'s id, id of %] to {expr:"nomsu.ids[\(% as lua expr)]"} + compile [%'s id, id of %] to: LuaValue "nomsu.ids[\(% as lua expr)]" # Variable assignment operator immediately: compile [%var <- %value] to: lua> "local \%var_lua = nomsu:tree_to_lua(\%var);" - assume %var_lua.expr or barf "Invalid target for assignment: \(%var's source code)" + assume %var_lua.is_value or barf "Invalid target for assignment: \(%var's source code)" lua> "local \%value_lua = nomsu:tree_to_lua(\%value);" - assume %value_lua.expr or barf "Invalid value for assignment: \(%value's source code)" - return {..} - statements:"\(%var_lua.expr) = \(%value_lua.expr);" - locals: =lua "(\%var.type == 'Var' and {\%var_lua.expr} or nil)" + assume %value_lua.is_value or barf "Invalid value for assignment: \(%value's source code)" + lua> ".." + local \%lua = Lua(tree.source, \%var_lua, ' = ', \%value_lua, ';'); + if \%var.type == 'Var' then + \%lua:add_free_vars(nomsu:var_to_lua_identifier(\%var.value)); + end + return \%lua; immediately: # Simultaneous mutli-assignments like: x,y,z = 1,x,3; compile [<- %assignments] to: - %locals <- [] - %targets <- [] - %values <- [] assume ((%assignments' "type") is "Dict") or barf ".." Expected a Dict for the assignments part of '<- %' statement, not \(%assignments' source code) lua> ".." + local lhs, rhs = Lua(tree.source), Lua(\%assignments.source); for i, item in ipairs(\%assignments.value) do local target, value = item.key, item.value; local target_lua = nomsu:tree_to_lua(target); - if not target_lua.expr then error("Invalid target for assignment: "..target:get_src()); end + if not target_lua.is_value then error("Invalid target for assignment: "..target:get_src()); end local value_lua = nomsu:tree_to_lua(value); - if not value_lua.expr then error("Invalid value for assignment: "..value:get_src()); end + if not value_lua.is_value then error("Invalid value for assignment: "..value:get_src()); end if target.type == "Var" then - table.insert(\%locals, target_lua.expr); + lhs:add_free_var(nomsu:var_to_lua_identifier(target.value)); end - table.insert(\%targets, target_lua.expr); - table.insert(\%values, value_lua.expr); + if i > 1 then + lhs:append(", "); + rhs:append(", "); + end + lhs:append(target_lua); + rhs:append(value_lua); end - utils.deduplicate(\%locals); - return {locals=\%locals, statements=(table.concat(\%targets, ", ").." = "..table.concat(\%values, ", ")..";")}; + return Lua(tree.source, lhs, " = ", rhs, ";"); immediately: compile [export %var <- %value] to: %var_lua <- (%var as lua) - assume %var_lua.expr or barf "Invalid target for assignment: \(%var's source code)" + assume %var_lua.is_value or barf "Invalid target for assignment: \(%var's source code)" %value_lua <- (%value as lua) - assume %value_lua.expr or barf "Invalid value for assignment: \(%value's source code)" - return {statements:"\(%var_lua.expr) = \(%value_lua.expr);"} + assume %value_lua.is_value or barf "Invalid value for assignment: \(%value's source code)" + return: Lua "\(%var_lua) = \(%value_lua);" compile [exporting %exported %body] to: %body_lua <- (%body as lua) - %leftover_locals <- (=lua "{unpack(\%body_lua.locals or {})}") - assume (%exported.type = "List") or barf ".." - Expected a List for the export part of 'exporting' statement, not \(%exported's source code) - lua> ".." - for i, item in ipairs(\%exported.value) do - if item.type ~= "Var" then - error("'exporting' statement expects Vars, not: "..item:get_src()); - end - local var = nomsu:tree_to_lua(item).expr; - utils.remove_from_list(\%leftover_locals, var); - end - return {locals:%leftover_locals, statements:=lua "\%body_lua.statements or (\%body_lua.expr..';')"} + lua> "\%body_lua:declare_locals(\%exported);" + return %body_lua - compile [with %assignments %body] to: - %body_lua <- (%body as lua) - %locals <- [] - %declarations <- [] - %leftover_locals <- (=lua "{unpack(\%body_lua.locals or {})}") - assume ((%assignments' "type") is "List") or barf ".." - Expected a List for the assignments part of 'with' statement, not \(%assignments' source code) - lua> ".." - for i, item in ipairs(\%assignments.value) do - if item.type == "Var" then - local var = nomsu:tree_to_lua(item).expr; - utils.remove_from_list(\%leftover_locals, var); - table.insert(\%locals, var); - else - if not (item.type == "FunctionCall" and #item.value == 3 and item.value[2].value == "<-") then - error("'with' statement expects entries of the form: '%var <- %value', not: "..item:get_src()); - end - local target, value = item.value[1], item.value[3]; - local target_lua = nomsu:tree_to_lua(target); - if not target_lua.expr then error("Invalid target for assignment: "..target:get_src()); end - local value_lua = nomsu:tree_to_lua(value); - if not value_lua.expr then error("Invalid value for assignment: "..value:get_src()); end - if target.type == "Var" then - utils.remove_from_list(\%leftover_locals, target_lua.expr); - end - table.insert(\%declarations, (("local %s = %s;\\n "):format( - target_lua.expr, value_lua.expr))); - end - end - local locals_code = ""; - if #\%locals > 0 then - locals_code = "\\nlocal "..table.concat(\%locals, ", ")..";"; - end - local declaration_code = ""; - if #\%declarations > 0 then - declaration_code = "\\n"..table.concat(\%declarations, "\\n"); - end - return {locals=\%leftover_locals, statements=([[ - do%s%s - %s - end]]):format(locals_code, declaration_code, \%body_lua.statements or (\%body_lua.expr..";"))}; + parse [with %assignments %body] as: + # TODO: clean up and handle: with {%x:1}: %y <- 2 + lua> "do" + <- %assignments + lua> "end" immediately: # Math Operators - compile [%x + %y] to {expr:"(\(%x as lua expr) + \(%y as lua expr))"} - compile [%x - %y] to {expr:"(\(%x as lua expr) - \(%y as lua expr))"} - compile [%x * %y] to {expr:"(\(%x as lua expr) * \(%y as lua expr))"} - compile [%x / %y] to {expr:"(\(%x as lua expr) / \(%y as lua expr))"} - compile [%x ^ %y] to {expr:"(\(%x as lua expr) ^ \(%y as lua expr))"} - compile [%x wrapped around %y, %x mod %y] to {expr:"(\(%x as lua expr) % \(%y as lua expr))"} + compile [%x + %y] to: LuaValue "(\(%x as lua expr) + \(%y as lua expr))" + compile [%x - %y] to: LuaValue "(\(%x as lua expr) - \(%y as lua expr))" + compile [%x * %y] to: LuaValue "(\(%x as lua expr) * \(%y as lua expr))" + compile [%x / %y] to: LuaValue "(\(%x as lua expr) / \(%y as lua expr))" + compile [%x ^ %y] to: LuaValue "(\(%x as lua expr) ^ \(%y as lua expr))" + compile [%x wrapped around %y, %x mod %y] to: LuaValue "(\(%x as lua expr) % \(%y as lua expr))" # 3-part chained comparisons # (uses a lambda to avoid re-evaluating middle value, while still being an expression) @@ -166,22 +124,22 @@ immediately: # TODO: optimize for common case where x,y,z are all either variables or number literals # Boolean Operators - compile [%x and %y] to {expr:"(\(%x as lua expr) and \(%y as lua expr))"} - compile [%x or %y] to {expr:"(\(%x as lua expr) or \(%y as lua expr))"} + compile [%x and %y] to: LuaValue "(\(%x as lua expr) and \(%y as lua expr))" + compile [%x or %y] to: LuaValue "(\(%x as lua expr) or \(%y as lua expr))" # Bitwise Operators - compile [%a OR %b, %a | %b] to {expr:"bit32.bor(\(%a as lua expr), \(%b as lua expr))"} - compile [%a XOR %b] to {expr:"bit32.bxor(\(%a as lua expr), \(%b as lua expr))"} - compile [%a AND %b, %a & %b] to {expr:"bit32.band(\(%a as lua expr), \(%b as lua expr))"} - compile [NOT %, ~ %] to {expr:"bit32.bnot(\(% as lua expr))"} - compile [%x LSHIFT %shift, %x << %shift] to {expr:"bit32.lshift(\(%x as lua expr), \(%shift as lua expr))"} - compile [%x RSHIFT %shift, %x >>> %shift] to {expr:"bit32.rshift(\(%x as lua expr), \(%shift as lua expr))"} - compile [%x ARSHIFT %shift, %x >> %shift] to {expr:"bit32.arshift(\(%x as lua expr), \(%shift as lua expr))"} + compile [%a OR %b, %a | %b] to: LuaValue "bit32.bor(\(%a as lua expr), \(%b as lua expr))" + compile [%a XOR %b] to: LuaValue "bit32.bxor(\(%a as lua expr), \(%b as lua expr))" + compile [%a AND %b, %a & %b] to: LuaValue "bit32.band(\(%a as lua expr), \(%b as lua expr))" + compile [NOT %, ~ %] to: LuaValue "bit32.bnot(\(% as lua expr))" + compile [%x LSHIFT %shift, %x << %shift] to: LuaValue "bit32.lshift(\(%x as lua expr), \(%shift as lua expr))" + compile [%x RSHIFT %shift, %x >>> %shift] to: LuaValue "bit32.rshift(\(%x as lua expr), \(%shift as lua expr))" + compile [%x ARSHIFT %shift, %x >> %shift] to: LuaValue "bit32.arshift(\(%x as lua expr), \(%shift as lua expr))" # TODO: implement OR, XOR, AND for multiple operands? # Unary operators - compile [- %] to {expr:"(- \(% as lua expr))"} - compile [not %] to {expr:"(not \(% as lua expr))"} + compile [- %] to: LuaValue "(- \(% as lua expr))" + compile [not %] to: LuaValue "(not \(% as lua expr))" # Update operators immediately: diff --git a/core/text.nom b/core/text.nom index b3a2b6a..8213988 100644 --- a/core/text.nom +++ b/core/text.nom @@ -32,7 +32,7 @@ lua> ".." }; for name, e in pairs(escapes) do local lua = "'"..e.."'"; - nomsu:define_compile_action(name, \(!! code location !!), function(__callsite) return {expr=lua}; end); + nomsu:define_compile_action(name, \(!! code location !!), function() return {expr=lua}; end); end local colors = { ["reset color"]="\\\\27[0m", bright="\\\\27[1m", dim="\\\\27[2m", underscore="\\\\27[4m", @@ -47,8 +47,8 @@ lua> ".." for name, c in pairs(colors) do local color = "'"..c.."'"; local reset = "'"..colors["reset color"].."'"; - nomsu:define_compile_action(name, \(!! code location !!), function(__callsite) return {expr=color}; end); - nomsu:define_compile_action(name.." %", \(!! code location !!), function(__callsite, \%) + nomsu:define_compile_action(name, \(!! code location !!), function() return {expr=color}; end); + nomsu:define_compile_action(name.." %", \(!! code location !!), function(\%) return {expr=color..".."..nomsu:tree_to_lua(\%).expr..".."..reset}; end); end diff --git a/lua_obj.lua b/lua_obj.lua index a0ff4db..1378643 100644 --- a/lua_obj.lua +++ b/lua_obj.lua @@ -126,10 +126,11 @@ do end, __tostring = function(self) local buff = { } - local _list_0 = self.bits - for _index_0 = 1, #_list_0 do - local b = _list_0[_index_0] + for i, b in ipairs(self.bits) do buff[#buff + 1] = tostring(b) + if i < #self.bits and type(b) ~= 'string' and b.is_statement then + buff[#buff + 1] = "\n" + end end local ret = concat(buff, "") assert(not ret:match(".*table: 0x.*")) diff --git a/lua_obj.moon b/lua_obj.moon index 1979c94..21017d7 100644 --- a/lua_obj.moon +++ b/lua_obj.moon @@ -73,8 +73,10 @@ class Lua __tostring: => buff = {} - for b in *@bits + for i,b in ipairs @bits buff[#buff+1] = tostring(b) + if i < #@bits and type(b) != 'string' and b.is_statement + buff[#buff+1] = "\n" ret = concat(buff, "") assert(not ret\match(".*table: 0x.*")) return ret diff --git a/nomsu.lua b/nomsu.lua index 2df72be..3f88b2f 100644 --- a/nomsu.lua +++ b/nomsu.lua @@ -1658,7 +1658,12 @@ if arg and debug_getinfo(2).func ~= require then local metadata = nomsu.action_metadata[info.func] if metadata then info.name = metadata.aliases[1] - local filename = metadata.source:match("^[^[:]*") + local filename + if type(metadata.source) == 'string' then + filename = metadata.source:match("^[^[:]*") + else + filename = metadata.source.filename + end info.short_src = filename info.source = FILE_CACHE[filename] local linedefined diff --git a/nomsu.moon b/nomsu.moon index e840fb3..d22b891 100755 --- a/nomsu.moon +++ b/nomsu.moon @@ -1133,7 +1133,9 @@ if arg and debug_getinfo(2).func != require if info.short_src or info.source or info.linedefine or info.currentline if metadata = nomsu.action_metadata[info.func] info.name = metadata.aliases[1] - filename = metadata.source\match("^[^[:]*") + filename = if type(metadata.source) == 'string' + metadata.source\match("^[^[:]*") + else metadata.source.filename info.short_src = filename info.source = FILE_CACHE[filename] ok, linedefined = pcall(lua_line_to_nomsu_line, info.short_src, info.linedefined)