From e1bc075bb5319b3903f66e141810dcb9ef53042e Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Fri, 31 Aug 2018 15:21:47 -0700 Subject: [PATCH] Removing the "A_" prefix on action names, and improving the quality of as_lua_id() (guaranteed injectivity). --- core/metaprogramming.nom | 12 ++++++------ lib/object.nom | 6 +++--- nomsu_compiler.lua | 33 ++++++++++++++++----------------- nomsu_compiler.moon | 29 ++++++++++++++++++----------- 4 files changed, 43 insertions(+), 37 deletions(-) diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom index 0f894b8..0f64bac 100644 --- a/core/metaprogramming.nom +++ b/core/metaprogramming.nom @@ -94,13 +94,13 @@ test: assume ((foo 1) == "outer") compile [local action %actions %body] to: lua> ".." - local fn_name = "A_"..string.as_lua_id(\%actions[1].stub) + local fn_name = 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) + local alias_name = 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, " = ") @@ -125,11 +125,11 @@ test: 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)) + lua:remove_free_vars(table.map(\%actions, function(a) return string.as_lua_id(a.stub) end)) return lua test: - assume ((action (say %)) == (=lua "A_say_1")) + assume ((action (say %)) == (=lua "say_1")) compile [action %action] to (Lua value (%action as lua id)) test: @@ -209,7 +209,7 @@ compile [%tree as lua return] to (..) Lua value "nomsu:compile(\(%tree as lua expr)):as_statements('return ')" compile [remove action %action] to (..) - Lua "A_\(=lua "string.as_lua_id(\(%action.stub))") = nil" + Lua "\(=lua "string.as_lua_id(\(%action.stub))") = nil" test: assume ("\(\(foo \%x) as nomsu)" == "foo %x") or barf ".." @@ -224,7 +224,7 @@ action [%var as lua identifier, %var as lua id] (..) lua> ".." if type(\%var) == 'string' then return string.as_lua_id(\%var) elseif \%var.type == 'Var' then return "_"..string.as_lua_id(\%var[1]) - elseif \%var.type == 'Action' then return "A_"..string.as_lua_id(\%var.stub) + elseif \%var.type == 'Action' then return string.as_lua_id(\%var.stub) end ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/lib/object.nom b/lib/object.nom index 6aa0630..8d59190 100644 --- a/lib/object.nom +++ b/lib/object.nom @@ -84,9 +84,9 @@ compile [object %classname extends %parent %class_body] to: return inst end, }) - nomsu["A_"..string.as_lua_id("new "..class.name)] = class - nomsu["A_"..string.as_lua_id("new "..class.name.." 1")] = class - nomsu["A_"..string.as_lua_id(class.name)] = function() return class end + nomsu[string.as_lua_id("new "..class.name)] = class + nomsu[string.as_lua_id("new "..class.name.." 1")] = class + nomsu[string.as_lua_id(class.name)] = function() return class end class.__index = class class.class = class class.__tostring = function(inst) diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua index 11bdc9d..f37960f 100644 --- a/nomsu_compiler.lua +++ b/nomsu_compiler.lua @@ -37,7 +37,8 @@ local AST = require("syntax_tree") local Parser = require("parser") SOURCE_MAP = { } string.as_lua_id = function(str) - str = gsub(str, "x([0-9A-F][0-9A-F])", "x\0%1") + str = gsub(str, "^\0*$", "%1\0") + str = gsub(str, "x([0-9A-F][0-9A-F])", "x78%1") str = gsub(str, "%W", function(c) if c == ' ' then return '_' @@ -45,16 +46,19 @@ string.as_lua_id = function(str) return format("x%02X", byte(c)) end end) + str = str:gsub("^_*%d", "_%1") return str end -table.map = function(self, fn) - local _accum_0 = { } - local _len_0 = 1 - for _, v in ipairs(self) do - _accum_0[_len_0] = fn(v) - _len_0 = _len_0 + 1 - end - return _accum_0 +table.map = function(t, fn) + return setmetatable((function() + local _accum_0 = { } + local _len_0 = 1 + for _, v in ipairs(t) do + _accum_0[_len_0] = fn(v) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)(), getmetatable(t)) end table.fork = function(t, values) return setmetatable(values or { }, { @@ -106,7 +110,7 @@ local NomsuCompiler = setmetatable({ end }) do - NomsuCompiler.NOMSU_COMPILER_VERSION = 5 + NomsuCompiler.NOMSU_COMPILER_VERSION = 6 NomsuCompiler.NOMSU_SYNTAX_VERSION = Parser.version NomsuCompiler.nomsu = NomsuCompiler NomsuCompiler.parse = function(self, ...) @@ -489,10 +493,10 @@ do NomsuCompiler.compile = function(self, tree) if tree.version then do - local get_version = self['A_' .. string.as_lua_id("Nomsu version")] + local get_version = self[string.as_lua_id("Nomsu version")] if get_version then do - local upgrade = self['A_' .. string.as_lua_id("1 upgraded from 2 to 3")] + local upgrade = self[string.as_lua_id("1 upgraded from 2 to 3")] if upgrade then tree = upgrade(tree, tree.version, get_version()) end @@ -529,11 +533,6 @@ do local lua = LuaCode.Value(tree.source) if tree.target then lua:append(self:compile(tree.target), ":") - if string.as_lua_id(stub):match("^[0-9]") then - lua:append("_") - end - else - lua:append("A_") end lua:append(string.as_lua_id(stub), "(") local args = { } diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon index 70e3f40..439285e 100644 --- a/nomsu_compiler.moon +++ b/nomsu_compiler.moon @@ -29,16 +29,27 @@ Parser = require("parser") export SOURCE_MAP SOURCE_MAP = {} +-- Convert an arbitrary string into a valid Lua identifier. This function is injective, +-- but not idempotent, i.e. if (x != y) then (as_lua_id(x) != as_lua_id(y)), +-- but as_lua_id(x) is not necessarily equal to as_lua_id(as_lua_id(x)) string.as_lua_id = (str)-> - -- Cut up escape-sequence-like chunks - str = gsub str, "x([0-9A-F][0-9A-F])", "x\0%1" - -- Alphanumeric unchanged, spaces to underscores, and everything else to hex escape sequences + -- Empty strings are not valid lua identifiers, so treat them like "\0", + -- and treat "\0" as "\0\0", etc. to preserve injectivity. + str = gsub str, "^\0*$", "%1\0" + -- Escape 'x' when it precedes something that looks like an uppercase hex sequence. + -- This way, all Lua IDs can be unambiguously reverse-engineered, but normal usage + -- of 'x' won't produce ugly Lua IDs. + -- i.e. "x" -> "x", "oxen" -> "oxen", but "Hex2Dec" -> "Hex782Dec" and "He-ec" -> "Hex2Dec" + str = gsub str, "x([0-9A-F][0-9A-F])", "x78%1" + -- Map spaces to underscores, and everything else non-alphanumeric to hex escape sequences str = gsub str, "%W", (c)-> if c == ' ' then '_' else format("x%02X", byte(c)) + -- Lua IDs can't start with numbers, so map "1" -> "_1", "_1" -> "__1", etc. + str = str\gsub "^_*%d", "_%1" return str -table.map = (fn)=> [fn(v) for _,v in ipairs(@)] +table.map = (t, fn)-> setmetatable([fn(v) for _,v in ipairs(t)], getmetatable(t)) table.fork = (t, values)-> setmetatable(values or {}, {__index:t}) table.copy = (t)-> setmetatable({k,v for k,v in pairs(t)}, getmetatable(t)) @@ -63,7 +74,7 @@ NomsuCompiler = setmetatable {name:"Nomsu"}, __index: (k)=> if _self = rawget(@, "self") then _self[k] else nil __tostring: => @name with NomsuCompiler - .NOMSU_COMPILER_VERSION = 5 + .NOMSU_COMPILER_VERSION = 6 .NOMSU_SYNTAX_VERSION = Parser.version .nomsu = NomsuCompiler .parse = (...)=> Parser.parse(...) @@ -312,8 +323,8 @@ with NomsuCompiler .compile = (tree)=> if tree.version - if get_version = @['A_'..string.as_lua_id("Nomsu version")] - if upgrade = @['A_'..string.as_lua_id("1 upgraded from 2 to 3")] + if get_version = @[string.as_lua_id("Nomsu version")] + if upgrade = @[string.as_lua_id("1 upgraded from 2 to 3")] tree = upgrade(tree, tree.version, get_version!) switch tree.type when "Action" @@ -331,10 +342,6 @@ with NomsuCompiler lua = LuaCode.Value(tree.source) if tree.target lua\append @compile(tree.target), ":" - if string.as_lua_id(stub)\match("^[0-9]") - lua\append "_" - else - lua\append "A_" lua\append(string.as_lua_id(stub),"(") args = {} for i, tok in ipairs tree