diff --git a/code_obj.lua b/code_obj.lua index f628fcc..6dbffca 100644 --- a/code_obj.lua +++ b/code_obj.lua @@ -195,6 +195,7 @@ do end for _index_0 = 1, #vars do local var = vars[_index_0] + assert(type(var) == 'string') if not (seen[var]) then self.free_vars[#self.free_vars + 1] = var seen[var] = true @@ -209,7 +210,8 @@ do local removals = { } for _index_0 = 1, #vars do local var = vars[_index_0] - removals[var[1]] = true + assert(type(var) == 'string') + removals[var] = true end local stack = { self @@ -218,7 +220,8 @@ do local lua lua, stack[#stack] = stack[#stack], nil for i = #lua.free_vars, 1, -1 do - if removals[lua.free_vars[i][1]] then + local free_var = lua.free_vars[i] + if removals[free_var] then remove(lua.free_vars, i) end end @@ -232,26 +235,6 @@ do end self.__str = nil end, - as_statements = function(self, prefix, suffix) - if prefix == nil then - prefix = "" - end - if suffix == nil then - suffix = ";" - end - if not (self.is_value) then - return self - end - local statements = LuaCode(self.source) - if prefix ~= "" then - statements:append(prefix) - end - statements:append(self) - if suffix ~= "" then - statements:append(suffix) - end - return statements - end, declare_locals = function(self, to_declare) if to_declare == nil then to_declare = nil @@ -281,19 +264,30 @@ do end if #to_declare > 0 then self:remove_free_vars(to_declare) - self:prepend("local " .. tostring(concat((function() - local _accum_0 = { } - local _len_0 = 1 - for _index_0 = 1, #to_declare do - local v = to_declare[_index_0] - _accum_0[_len_0] = type(v) == 'string' and v or string.as_lua_id(v[1]) - _len_0 = _len_0 + 1 - end - return _accum_0 - end)(), ", ")) .. ";\n") + self:prepend("local " .. tostring(concat(to_declare, ", ")) .. ";\n") end return to_declare end, + as_statements = function(self, prefix, suffix) + if prefix == nil then + prefix = "" + end + if suffix == nil then + suffix = ";" + end + if not (self.is_value) then + return self + end + local statements = LuaCode(self.source) + if prefix ~= "" then + statements:append(prefix) + end + statements:append(self) + if suffix ~= "" then + statements:append(suffix) + end + return statements + end, __tostring = function(self) if self.__str == nil then local buff, indents = { }, self.indents diff --git a/code_obj.moon b/code_obj.moon index 3daed04..9e2e324 100644 --- a/code_obj.moon +++ b/code_obj.moon @@ -115,6 +115,7 @@ class LuaCode extends Code return unless #vars > 0 seen = {[v]:true for v in *@free_vars} for var in *vars + assert type(var) == 'string' unless seen[var] @free_vars[#@free_vars+1] = var seen[var] = true @@ -124,30 +125,21 @@ class LuaCode extends Code return unless #vars > 0 removals = {} for var in *vars - removals[var[1]] = true + assert type(var) == 'string' + removals[var] = true stack = {self} while #stack > 0 lua, stack[#stack] = stack[#stack], nil for i=#lua.free_vars,1,-1 - if removals[lua.free_vars[i][1]] + free_var = lua.free_vars[i] + if removals[free_var] remove lua.free_vars, i for b in *lua.bits if type(b) != 'string' stack[#stack+1] = b @__str = nil - as_statements: (prefix="", suffix=";")=> - unless @is_value - return self - statements = LuaCode(@source) - if prefix != "" - statements\append prefix - statements\append self - if suffix != "" - statements\append suffix - return statements - declare_locals: (to_declare=nil)=> if to_declare == nil to_declare, seen = {}, {} @@ -162,9 +154,20 @@ class LuaCode extends Code gather_from self if #to_declare > 0 @remove_free_vars to_declare - @prepend "local #{concat [type(v) == 'string' and v or string.as_lua_id(v[1]) for v in *to_declare], ", "};\n" + @prepend "local #{concat to_declare, ", "};\n" return to_declare + as_statements: (prefix="", suffix=";")=> + unless @is_value + return self + statements = LuaCode(@source) + if prefix != "" + statements\append prefix + statements\append self + if suffix != "" + statements\append suffix + return statements + __tostring: => if @__str == nil buff, indents = {}, @indents diff --git a/core/collections.nom b/core/collections.nom index 69a51c7..6ba806a 100644 --- a/core/collections.nom +++ b/core/collections.nom @@ -55,6 +55,8 @@ compile [pop from %list, remove last from %list] to compile [remove index %index from %list] to Lua "table.remove(\(%list as lua expr), \(%index as lua expr))" +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + # List Comprehension parse [%expression for %item in %iterable] as result of @@ -73,6 +75,7 @@ parse [..] add %expression to %comprehension return %comprehension +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ parse [%expression for %var in %start to %stop] as %expression for %var in %start to %stop via 1 diff --git a/core/control_flow.nom b/core/control_flow.nom index fccdfca..5a96d3e 100644 --- a/core/control_flow.nom +++ b/core/control_flow.nom @@ -152,7 +152,7 @@ compile [..] %body has subtree % where (%.type = "Action") and (%.stub is "do next %") and - %.3 = %var + %.(3).1 = %var.1 ..: to %lua write "\n ::continue_\(%var as lua identifier)::" to %lua write "\nend --numeric for-loop" @@ -160,7 +160,7 @@ compile [..] %body has subtree % where (%.type = "Action") and (%.stub is "stop %") and - %.2 = %var + %.(2).1 = %var.1 .. %lua <- Lua ".." @@ -246,7 +246,7 @@ compile [..] %.2.(1) = %value.(1) ..: to %stop_labels write "\n::stop_\(%value as lua identifier)::" - if: (length of %stop_labels) > 0 + if: (length of "\%stop_labels") > 0 %lua <- Lua ".." do -- scope for stopping for % = % loop @@ -300,7 +300,7 @@ compile [when %body] to %is_first <- (no) assume (%fallthroughs = []) or barf "Unfinished fallthrough conditions in 'when' block" - assume ((length of %code) > 0) or barf "Empty body for 'when' block" + assume ((length of "\%code") > 0) or barf "Empty body for 'when' block" to %code write "\nend --when" return %code @@ -346,7 +346,7 @@ compile [when %branch_value = ? %body, when %branch_value is ? %body] to %is_first <- (no) assume (%fallthroughs = []) or barf "Unfinished fallthrough conditions in 'when' block" - assume ((length of %code) > 0) or barf "No body for 'when % = ?' block!" + assume ((length of "\%code") > 0) or barf "No body for 'when % = ?' block!" to %code write "\nend" %code <- Lua ".." diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom index d04ced3..a7da3d8 100644 --- a/core/metaprogramming.nom +++ b/core/metaprogramming.nom @@ -2,46 +2,92 @@ This File contains actions for making actions and compile-time actions and some helper functions to make that easier. -# Compile-time action to make compile-time actions: lua> ".." - nomsu.COMPILE_ACTIONS["give % nickname %"] = (function(nomsu, tree, \%action, \%nickname, is_compile_time) - local function arg_to_string(a) return tostring(nomsu:compile(a)) end - local action_args = table.map(\%action:get_args(), arg_to_string) - local nickname_args = table.map(\%nickname:get_args(), arg_to_string) - if utils.equivalent(action_args, nickname_args) then - if is_compile_time then - return LuaCode(tree.source, "nomsu.COMPILE_ACTIONS[", repr(\%nickname.stub), "] = nomsu.COMPILE_ACTIONS[", repr(\%action.stub), "]") + 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 - return LuaCode(tree.source, "A", string.as_lua_id(\%nickname.stub), " = A", string.as_lua_id(\%action.stub)) + 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 - local lua = LuaCode(tree.source) - if is_compile_time then - lua:append("nomsu.COMPILE_ACTIONS[", repr(\%nickname.stub), "] = ") - table.insert(action_args, 1, "nomsu") - table.insert(nickname_args, 1, "nomsu") - table.insert(action_args, 2, "tree") - table.insert(nickname_args, 2, "tree") - else - lua:append("A", string.as_lua_id(\%nickname.stub), " = ") - end - lua:append("(function(") - lua:concat_append(nickname_args, ", ") - if is_compile_time then - lua:append(")\n return nomsu.COMPILE_ACTIONS[", repr(\%action.stub), "](") - else - lua:append(")\n return A", string.as_lua_id(\%action.stub), "(") - end - lua:concat_append(action_args, ", ") - lua:append(")\nend)") - if not is_compile_time then - lua:add_free_vars({"A"..string.as_lua_id(\%nickname.stub)}) + 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 - end) - __MANGLE_INDEX = 0 - nomsu.COMPILE_ACTIONS["parse % as %"] = (function(nomsu, tree, \%actions, \%body) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +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)) @@ -50,81 +96,25 @@ lua> ".." if not AST.is_syntax_tree(t) then return repr(t) elseif t.type ~= 'Var' then - local args = table.map(t, make_tree) - table.insert(args, 1, repr(tostring(t.source))) + 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").."..('%X'):format(__MANGLE_INDEX))" + return t.type.."("..repr(tostring(t.source))..", "..repr(t[1].." \\0").."..string.format('%X', __MANGLE_INDEX))" end end - local lua = LuaCode(tree.source, "nomsu.COMPILE_ACTIONS[", repr(\%actions[1].stub), "] = (function(nomsu, tree") - lua:add_free_vars({"A"..string.as_lua_id(\%actions[1].stub)}) - for _,arg in ipairs(\%actions[1]:get_args()) do - lua:append(", ", nomsu:compile(arg)) - end - lua:append(")\n __MANGLE_INDEX = __MANGLE_INDEX + 1", - "\n local tree = ", make_tree(\%body), - "\n local lua = nomsu:compile(tree)", - "\n lua:remove_free_vars({") - local vars = table.map(\%actions[1]:get_args(), function(a) - return "Var("..repr(tostring(a.source))..", "..repr(a[1])..")" - end) - lua:concat_append(vars, ", ") - lua:append("})\n return lua\nend)") - - for i=2,#\%actions do - lua:append("\n", nomsu.COMPILE_ACTIONS["give % nickname %"](nomsu, \%actions[i], \%actions[1], \%actions[i], true)) - end - return lua - end) - - nomsu.COMPILE_ACTIONS["local action % %"] = (function(nomsu, tree, \%actions, \%body, is_compile_time) - local lua = LuaCode(tree.source) - if is_compile_time then - lua:append("nomsu.COMPILE_ACTIONS[", repr(\%actions[1].stub), "] = ") - else - lua:append("A", string.as_lua_id(\%actions[1].stub), " = ") - lua:add_free_vars({"A"..string.as_lua_id(\%actions[1].stub)}) - end - lua:append("(function(") - local args = \%actions[1]:get_args() - local lua_args = table.map(args, function(a) return nomsu:compile(a) end) - if is_compile_time then - table.insert(lua_args, 1, "nomsu") - table.insert(lua_args, 2, "tree") - end - lua:concat_append(lua_args, ", ") - local body_lua = nomsu:compile(\%body):as_statements("return ") - body_lua:remove_free_vars(args) - body_lua:declare_locals() - lua:append(")\n ", body_lua, "\nend)") - for i=2,#\%actions do - lua:append("\n", nomsu.COMPILE_ACTIONS["give % nickname %"](nomsu, \%actions[i], \%actions[1], \%actions[i], is_compile_time)) - end - return lua - end) - - -- Compile-time actions are always global, since they affect the state of the compiler - nomsu.COMPILE_ACTIONS["compile % to %"] = (function(nomsu, tree, \%actions, \%body) - local lua = nomsu.COMPILE_ACTIONS["local action % %"](nomsu, tree, \%actions, \%body, true) - return lua - end) - - nomsu.COMPILE_ACTIONS["action % %"] = (function(nomsu, tree, \%actions, \%body) - local lua = nomsu.COMPILE_ACTIONS["local action % %"](nomsu, tree, \%actions, \%body) - lua:remove_free_vars(table.map(\%actions, function(a) return "A"..a.stub:as_lua_id() end)) - return lua - 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 - ARG_ORDERS[fn] = nil - COMPILE_TIME[fn] = nil action [%tree as nomsu] =lua "nomsu:tree_to_nomsu(\%tree)" diff --git a/core/operators.nom b/core/operators.nom index b4567b1..0756751 100644 --- a/core/operators.nom +++ b/core/operators.nom @@ -50,7 +50,7 @@ compile [%var <- %value] to lua> ".." local lua = LuaCode(tree.source, \%var_lua, ' = ', \%value_lua, ';') if \%var.type == 'Var' then - lua:add_free_vars({\%var}) + lua:add_free_vars({tostring(nomsu:compile(\%var))}) end return lua @@ -72,7 +72,7 @@ compile [<- %assignments, assign %assignments] to local value_lua = \(%value as lua) if not value_lua.is_value then error("Invalid value for assignment: "..\(%value as text)) end if \%target.type == "Var" then - lhs:add_free_vars({\%target}) + lhs:add_free_vars({tostring(target_lua)}) end if i > 1 then lhs:append(", ") @@ -94,7 +94,7 @@ compile [external %var <- %value] to compile [with external %externs %body] to %body_lua <- (%body as lua statements) - lua> "\%body_lua:remove_free_vars(\%externs);" + lua> "\%body_lua:remove_free_vars(table.map(\%externs, function(v) return tostring(nomsu:compile(v)) end))" return %body_lua compile [with %assignments %body] to @@ -112,16 +112,15 @@ compile [with %assignments %body] to if not value_lua.is_value then error("Invalid value for assignment: "..tostring(\%value)) end - if \%target.type == "Var" then - lhs:add_free_vars({\%target}) - end if i > 1 then lhs:append(", ") rhs:append(", ") end lhs:append(target_lua) rhs:append(value_lua) - vars[i] = \%target + if \%target.type == "Var" then + vars[i] = tostring(target_lua) + end end \%lua:remove_free_vars(vars) \%lua:prepend("local ", lhs, " = ", rhs, ";\n") diff --git a/nomsu.lua b/nomsu.lua index 1ea73ec..f322abf 100644 --- a/nomsu.lua +++ b/nomsu.lua @@ -512,7 +512,6 @@ do if source == nil then source = nil end - assert(type(lua) ~= 'string', "Attempt to run lua string instead of Lua (object)") local lua_string = tostring(lua) local run_lua_fn, err = load(lua_string, nil and tostring(source or lua.source), "t", self) if not run_lua_fn then diff --git a/nomsu.moon b/nomsu.moon index b99d6f4..1e6a89f 100755 --- a/nomsu.moon +++ b/nomsu.moon @@ -345,7 +345,6 @@ with NomsuCompiler return ret .run_lua = (lua, source=nil)=> - assert(type(lua) != 'string', "Attempt to run lua string instead of Lua (object)") lua_string = tostring(lua) run_lua_fn, err = load(lua_string, nil and tostring(source or lua.source), "t", self) if not run_lua_fn diff --git a/nomsu_tree.lua b/nomsu_tree.lua index 05fb22c..227a674 100644 --- a/nomsu_tree.lua +++ b/nomsu_tree.lua @@ -9,8 +9,11 @@ local Source Source = require("code_obj").Source local unpack = unpack or table.unpack local AST = { } -AST.is_syntax_tree = function(n) - return type(n) == 'table' and getmetatable(n) and AST[n.type] == getmetatable(n) +AST.is_syntax_tree = function(n, t) + if t == nil then + t = nil + end + return type(n) == 'table' and getmetatable(n) and AST[n.type] == getmetatable(n) and (t == nil or n.type == t) end local types = { "Number", @@ -37,7 +40,7 @@ for _index_0 = 1, #types do return getmetatable(x) == self end cls.__tostring = function(self) - return tostring(self.name) .. "(" .. tostring(concat((function() + return tostring(self.type) .. "(" .. tostring(repr(tostring(self.source))) .. ", " .. tostring(concat((function() local _accum_0 = { } local _len_0 = 1 for _index_1 = 1, #self do diff --git a/nomsu_tree.moon b/nomsu_tree.moon index 71bcff9..b754cd8 100644 --- a/nomsu_tree.moon +++ b/nomsu_tree.moon @@ -6,8 +6,8 @@ unpack or= table.unpack AST = {} -AST.is_syntax_tree = (n)-> - type(n) == 'table' and getmetatable(n) and AST[n.type] == getmetatable(n) +AST.is_syntax_tree = (n, t=nil)-> + type(n) == 'table' and getmetatable(n) and AST[n.type] == getmetatable(n) and (t == nil or n.type == t) types = {"Number", "Var", "Block", "EscapedNomsu", "Text", "List", "Dict", "DictEntry", "IndexChain", "Action", "FileChunks"} @@ -19,7 +19,7 @@ for name in *types .__name = name .type = name .is_instance = (x)=> getmetatable(x) == @ - .__tostring = => "#{@name}(#{concat([repr(v) for v in *@], ', ')})" + .__tostring = => "#{@type}(#{repr tostring(@source)}, #{concat([repr(v) for v in *@], ', ')})" .map = (fn)=> if replacement = fn(@) then return replacement replacements = [AST.is_syntax_tree(v) and v\map(fn) or nil for v in *@] diff --git a/parser.lua b/parser.lua index d48c435..e995c3c 100644 --- a/parser.lua +++ b/parser.lua @@ -9,6 +9,11 @@ do local _obj_0 = string match, sub, rep, gsub, format, byte, match, find = _obj_0.match, _obj_0.sub, _obj_0.rep, _obj_0.gsub, _obj_0.format, _obj_0.byte, _obj_0.match, _obj_0.find end +local NomsuCode, LuaCode, Source +do + local _obj_0 = require("code_obj") + NomsuCode, LuaCode, Source = _obj_0.NomsuCode, _obj_0.LuaCode, _obj_0.Source +end local AST = require("nomsu_tree") local NOMSU_DEFS do