From 692fae5416ce1f2702b599ffb27b2e3d2235eba7 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Wed, 26 Sep 2018 12:45:08 -0700 Subject: [PATCH] Incremental fixes and more nomnom ports. --- containers.lua | 16 ++++++++++ containers.moon | 5 +++ core/math.nom | 26 +++++++++++++++ core/metaprogramming.nom | 11 +++---- nomnom/code_obj.nom | 28 ++++++++-------- nomnom/compile.nom | 48 ++++++++++++++-------------- string2.lua | 69 ++++++++++++++++++---------------------- string2.moon | 19 ++++++----- tools/find_action.nom | 11 +++++-- 9 files changed, 139 insertions(+), 94 deletions(-) diff --git a/containers.lua b/containers.lua index d31c786..682932f 100644 --- a/containers.lua +++ b/containers.lua @@ -192,6 +192,22 @@ local _list_mt = { end end return nil + end, + slice_1_to_2 = function(self, start, stop) + local n = #self + if n < 0 then + start = (n + 1 - start) + end + if n < 0 then + stop = (n + 1 - stop) + end + local _accum_0 = { } + local _len_0 = 1 + for i = start, stop do + _accum_0[_len_0] = self[i] + _len_0 = _len_0 + 1 + end + return _accum_0 end }, __newindex = function(self, k, v) diff --git a/containers.moon b/containers.moon index 039a4ea..8a7d7fa 100644 --- a/containers.moon +++ b/containers.moon @@ -76,6 +76,11 @@ _list_mt = if x == item return i return nil + slice_1_to_2: (start, stop)=> + n = #@ + start = (n+1-start) if n < 0 + stop = (n+1-stop) if n < 0 + return [@[i] for i=start,stop] -- TODO: remove this safety check to get better performance? __newindex: (k,v)=> assert type(k) == 'number', "List indices must be numbers" diff --git a/core/math.nom b/core/math.nom index d6ddbce..5daa2d8 100644 --- a/core/math.nom +++ b/core/math.nom @@ -89,6 +89,32 @@ compile [sum of %items, sum %items] to: %clauses = ((% as lua expr) for % in %items) return (Lua value "(\(%clauses::joined with " + "))") +parse [if all of %items %body, if all of %items then %body] as (..) + if (all of %items) %body +parse [unless all of %items %body, unless all of %items then %body] as (..) + if (not (all of %items)) %body +parse [if any of %items %body, if any of %items then %body] as (..) + if (any of %items) %body +parse [unless any of %items %body, unless any of %items then %body] as (..) + if (not (any of %items)) %body +parse [if none of %items %body, if none of %items then %body] as (..) + if (not (any of %items)) %body +parse [unless none of %items %body, unless none of %items then %body] as (..) + if (any of %items) %body + +parse [if all of %items %body else %else, if all of %items then %body else %else] as (..) + if (all of %items) %body else %else +parse [unless all of %items %body else %else, unless all of %items then %body else %else] as (..) + if (not (all of %items)) %body else %else +parse [if any of %items %body else %else, if any of %items then %body else %else] as (..) + if (any of %items) %body else %else +parse [unless any of %items %body else %else, unless any of %items then %body else %else] as (..) + if (not (any of %items)) %body else %else +parse [if none of %items %body else %else, if none of %items then %body else %else] as (..) + if (not (any of %items)) %body else %else +parse [unless none of %items %body else %else, unless none of %items then %body else %else] as (..) + if (any of %items) %body else %else + compile [product of %items, product %items] to: unless (%items.type is "List"): return (Lua value "utils.product(\(%items as lua expr))") diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom index 1503905..8b75ccd 100644 --- a/core/metaprogramming.nom +++ b/core/metaprogramming.nom @@ -184,14 +184,14 @@ compile [parse %actions as %body] to (..) i = i + 1 elseif k == "source" then ret[#ret+1] = k.."= "..tostring(v):as_lua() - elseif type(k) == 'string' and k:match("[_a-zA-Z][_a-zA-Z0-9]*") then + elseif lua_type_of_1(k) == 'string' and k:match("[_a-zA-Z][_a-zA-Z0-9]*") then ret[#ret+1] = k.."= "..make_tree(v) else ret[#ret+1] = "["..make_tree(k).."]= "..make_tree(v) end end return t.type.."{"..table.concat(ret, ", ").."}" - elseif type(t) == 'number' then + elseif lua_type_of_1(t) == 'number' then return tostring(t) else return t:as_lua() @@ -231,12 +231,12 @@ compile [%tree as inline nomsu] to (..) action [%var as lua identifier, %var as lua id] (..) lua> "\ - ..if type(\%var) == 'string' then return \%var:as_lua_id() + ..if lua_type_of_1(\%var) == 'string' then return \%var:as_lua_id() elseif AST.is_syntax_tree(\%var, 'Var') then return \%var[1]:as_lua_id() elseif AST.is_syntax_tree(\%var) then local lua = \(%var as lua expr) if not tostring(lua):match("^[_a-zA-Z][_a-zA-Z0-9]*$") then - \(compile error at %var "This is not a valid Lua identifier.") + compile_error_at_1_2(\%var, "This is not a valid Lua identifier.") end return lua else error("Unknown type: "..tostring(\%var)) @@ -328,9 +328,6 @@ test: assume ("" is text) assume ("" isn't a "Dict") -%dict_mt = (=lua "getmetatable(\{})") -%list_mt = (=lua "getmetatable(\[])") - action [% is text] (=lua "\(lua type of %) == 'string'") action [% is not text, % isn't text] (=lua "\(lua type of %) ~= 'string'") action [type of %]: diff --git a/nomnom/code_obj.nom b/nomnom/code_obj.nom index 4df312e..057748f 100644 --- a/nomnom/code_obj.nom +++ b/nomnom/code_obj.nom @@ -163,18 +163,20 @@ object (Lua Code) extends (Code): %statements::add %suffix return %statements - action [Lua Code from %tree] (..) - Lua Code {source:%tree.source, bits:[], is_value:(no), free_vars:[]} - action [Lua Code from %tree %bits] (..) - Lua Code {source:%tree.source, bits:%bits, is_value:(no), free_vars:[]} - - action [Lua Value from %tree] (..) - Lua Code {source:%tree.source, bits:[], is_value:(yes), free_vars:[]} - action [Lua Value from %tree %bits] (..) - Lua Code {source:%tree.source, bits:%bits, is_value:(yes), free_vars:[]} + action [Lua Code from %source {%bits:[]}]: + if (%bits is text): %bits = [%bits] + if (%source is a "Syntax Tree"): %source = %source.source + return (..) + Lua Code {source:%source, bits:%bits, is_value:(no), free_vars:[]} + action [Lua Value from %tree {%bits:[]}]: + if (%bits is text): %bits = [%bits] + if (%source is a "Syntax Tree"): %source = %source.source + return (..) + Lua Code {source:%source, bits:%bits, is_value:(yes), free_vars:[]} object (Nomsu Code) extends (Code): - action [Nomsu Code from %tree] (..) - Nomsu Code {source:%tree.source, bits:[]} - action [Nomsu Code from %tree %bits] (..) - Nomsu Code {source:%tree.source, bits:%bits} + action [Nomsu Code from %source {%bits:[]}]: + if (%bits is text): %bits = [%bits] + if (%source is a "Syntax Tree"): %source = %source.source + return (..) + Nomsu Code {source:%source, bits:%bits} diff --git a/nomnom/compile.nom b/nomnom/compile.nom index ec48f05..ff3b71f 100644 --- a/nomnom/compile.nom +++ b/nomnom/compile.nom @@ -4,17 +4,17 @@ use "nomnom/code_obj.nom" action [compile %tree using %compile_actions]: assume (%tree is a "Syntax Tree") - if (..) - all of [..] - %tree.version, action (Nomsu version) - %tree.version != (Nomsu version) - action (1 upgraded from 2 to 3) - ..: %tree = (upgrade %tree from %tree.version to (Nomsu version)) + if all of [..] + %tree.version, action (Nomsu version) + %tree.version != (Nomsu version) + action (1 upgraded from 2 to 3) + ..then: %tree = (upgrade %tree from %tree.version to (Nomsu version)) if %tree.type is: "Action": %stub = %tree.stub %compile_action = %compile_actions.%stub - if %compile_action: + # Don't apply compiler actions to methods + if (%compile_action and (not %tree.target)): %args = [%tree, %compile_actions] for % in (%tree::get args): %args::add % %result = (call %compile_action with %args) @@ -32,7 +32,7 @@ action [compile %tree using %compile_actions]: return (compile %result using %compile_actions) return %result - %lua = (new Lua Value from %tree) + %lua = (Lua Value from %tree) if %tree.target: # Method call %target_lua = (compile %tree.target using %compile_actions) if (("\%target_lua"::matches "^%(.*%)$") or ("\%target_lua"::matches "^[_a-zA-Z][_a-zA-Z0-9]*$")): @@ -49,15 +49,15 @@ action [compile %tree using %compile_actions]: %values = (..) (compile %line using %compile_actions) for %line in %tok ..unless (%line.type == "Comment") - if (all of (%.is_value for % in %values)): + if all of (%.is_value for % in %values): if ((size of %values) == 1): %arg_lua = %values.1 ..else: - %arg_lua = (new Lua Value from %tok ["("]) + %arg_lua = (Lua Value from %tok ["("]) %arg_lua::add %values joined with " and nil or " %arg_lua::add ")" ..else: - %arg_lua = (new Lua Value from %tok ["((function()"]) + %arg_lua = (Lua Value from %tok ["((function()"]) for %v in %values at %i: if %v.is_value: %v = (%v::as statements ("return " if (%i == (size of %values) else ""))) @@ -83,10 +83,10 @@ action [compile %tree using %compile_actions]: return %lua "EscapedNomsu": - return (new Lua Value from %tree ((%tree.1)::as nomsu)) + return (Lua Value from %tree ((%tree.1)::as nomsu)) "Block": - %lua = (new Lua Code from %tree) + %lua = (Lua Code from %tree) %lua::add (..) ((compile %line using %compile_actions)::as statements) ..for %line in %tree @@ -94,7 +94,7 @@ action [compile %tree using %compile_actions]: return %lua "Text": - %lua = (new Lua Code from %tree) + %lua = (Lua Code from %tree) %lua_bits = [] %string_buffer = "" for % in %tree: @@ -109,7 +109,7 @@ action [compile %tree using %compile_actions]: compile error at %bit "\ ..Can't use this as a string interpolation value, since it doesn't have a value." if (%bit.type != "Text"): - %bit_lua = (new Lua Value from %bit ["tostring(",%bit_lua,")"]) + %bit_lua = (Lua Value from %bit ["tostring(",%bit_lua,")"]) %lua_bits::add %bit_lua if ((%string_buffer != "") or ((size of %lua_bits) == 0)): @@ -121,13 +121,13 @@ action [compile %tree using %compile_actions]: return %lua "List": - %lua = (new Lua Value from %tree ["_List{"]) + %lua = (Lua Value from %tree ["List{"]) %lua::add ((compile % using %compile_actions) for % in %tree) joined with ", " or ",\n " %lua::add "}" return %lua "Dict": - %lua = (new Lua Value from %tree ["_Dict{"]) + %lua = (Lua Value from %tree ["Dict{"]) %lua::add ((compile % using %compile_actions) for % in %tree) joined with ", " or ",\n " %lua::add "}" return %lua @@ -140,21 +140,21 @@ action [compile %tree using %compile_actions]: ..Can't use this as a dict key, since it's not an expression." %value_lua = (..) (compile %value using %compile_actions) if %value - ..else (new Lua Value from %key ["true"])) + ..else (Lua Value from %key ["true"])) unless %value_lua.is_value: compile error at %tree.2 "\ ..Can't use this as a dict value, since it's not an expression." %key_str = ("\%key_lua"::matching "^[\"']([a-zA-Z_][a-zA-Z0-9_]*)['\"]$") if: %key_str: - return (new Lua Code from %tree [%key_str, "=", %value_lua]) + return (Lua Code from %tree [%key_str, "=", %value_lua]) ("\%key_lua".1 == "["): # NOTE: this *must* use a space after the [ to avoid freaking out Lua's parser if the inner expression is a long string. Lua parses x[[[y]]] as x("[y]"), not as x["y"] - return (new Lua Code from %tree ["[ ", %key_lua, "]=", %value_lua]) + return (Lua Code from %tree ["[ ", %key_lua, "]=", %value_lua]) else: - return (new Lua Code from %tree ["[", %key_lua, "]=", %value_lua]) + return (Lua Code from %tree ["[", %key_lua, "]=", %value_lua]) "IndexChain": %lua = (compile %tree.1 using %compile_actions) @@ -186,10 +186,10 @@ action [compile %tree using %compile_actions]: return %lua "Number": - return (new Lua Value from %tree ["\(%tree.1)"]) + return (Lua Value from %tree ["\(%tree.1)"]) "Var": - return (new Lua Value from %tree [%tree.1::as lua id]) + return (Lua Value from %tree [%tree.1::as lua id]) "FileChunks": barf "\ @@ -198,7 +198,7 @@ action [compile %tree using %compile_actions]: "Comment": # TODO: implement? - return (new Lua Code from %tree) + return (Lua Code from %tree) "Error": barf "Can't compile errors" diff --git a/string2.lua b/string2.lua index 2cdfefc..1f15fed 100644 --- a/string2.lua +++ b/string2.lua @@ -27,34 +27,39 @@ isplit = function(self, sep) }, 0 end local lua_keywords = { - "and", - "break", - "do", - "else", - "elseif", - "end", - "false", - "for", - "function", - "goto", - "if", - "in", - "local", - "nil", - "not", - "or", - "repeat", - "return", - "then", - "true", - "until", - "while" + ["and"] = true, + ["break"] = true, + ["do"] = true, + ["else"] = true, + ["elseif"] = true, + ["end"] = true, + ["false"] = true, + ["for"] = true, + ["function"] = true, + ["goto"] = true, + ["if"] = true, + ["in"] = true, + ["local"] = true, + ["nil"] = true, + ["not"] = true, + ["or"] = true, + ["repeat"] = true, + ["return"] = true, + ["then"] = true, + ["true"] = true, + ["until"] = true, + ["while"] = true } +local is_lua_id +is_lua_id = function(str) + return match(str, "^[_a-zA-Z][_a-zA-Z0-9]*$") and not lua_keywords[str] +end local string2 = { isplit = isplit, uppercase = upper, lowercase = lower, reversed = reverse, + is_lua_id = is_lua_id, capitalized = function(self) return gsub(self, '%l', upper, 1) end, @@ -148,27 +153,15 @@ local string2 = { return format("x%02X", byte(c)) end end) - str = gsub(str, "^_*%d", "_%1") - if match(str, "^_*[abdefgilnortuw][aefhilnoru][acdefiklnoprstu]*$") then - for _index_0 = 1, #lua_keywords do - local kw = lua_keywords[_index_0] - if match(str, ("^_*" .. kw .. "$")) then - str = "_" .. str - end - end + if not (is_lua_id(str:match("^_*(.*)$"))) then + str = "_" .. str end return str end, from_lua_id = function(str) - if match(str, "^_+[abdefgilnortuw][aefhilnoru][acdefiklnoprstu]*$") then - for _index_0 = 1, #lua_keywords do - local kw = lua_keywords[_index_0] - if match(str, ("^_+" .. kw .. "$")) then - str = str:sub(2, -1) - end - end + if not (is_lua_id("^_+(.*)$")) then + str = str:sub(2, -1) end - str = gsub(str, "^_(_*%d.*)", "%1") str = gsub(str, "_", " ") str = gsub(str, "x([0-9A-F][0-9A-F])", function(hex) return char(tonumber(hex, 16)) diff --git a/string2.moon b/string2.moon index 1b0037f..140c586 100644 --- a/string2.moon +++ b/string2.moon @@ -13,14 +13,16 @@ isplit = (sep='%s+')=> return step, {str:@, pos:1, :sep}, 0 lua_keywords = { - ["and"]=true, ["break"]=true, ["do"]=true, ["else"]=true, ["elseif"]=true, ["end"]=true, - ["false"]=true, ["for"]=true, ["function"]=true, ["goto"]=true, ["if"]=true, - ["in"]=true, ["local"]=true, ["nil"]=true, ["not"]=true, ["or"]=true, ["repeat"]=true, - ["return"]=true, ["then"]=true, ["true"]=true, ["until"]=true, ["while"]=true + ["and"]:true, ["break"]:true, ["do"]:true, ["else"]:true, ["elseif"]:true, ["end"]:true, + ["false"]:true, ["for"]:true, ["function"]:true, ["goto"]:true, ["if"]:true, + ["in"]:true, ["local"]:true, ["nil"]:true, ["not"]:true, ["or"]:true, ["repeat"]:true, + ["return"]:true, ["then"]:true, ["true"]:true, ["until"]:true, ["while"]:true } +is_lua_id = (str)-> + match(str, "^[_a-zA-Z][_a-zA-Z0-9]*$") and not lua_keywords[str] string2 = { - :isplit, uppercase:upper, lowercase:lower, reversed:reverse + :isplit, uppercase:upper, lowercase:lower, reversed:reverse, :is_lua_id capitalized: => gsub(@, '%l', upper, 1) byte: byte, bytes: (i, j)=> {byte(@, i or 1, j or -1)} split: (sep)=> [chunk for i,chunk in isplit(@, sep)] @@ -79,17 +81,14 @@ string2 = { if c == ' ' then '_' else format("x%02X", byte(c)) - unless string2.is_lua_id(str\match("^_*(.*)$")) + unless is_lua_id(str\match("^_*(.*)$")) str = "_"..str return str - is_lua_id: (str)-> - match(str, "^[_a-zA-Z][_a-zA-Z0-9]*$") and not lua_keywords[str] - -- from_lua_id(as_lua_id(str)) == str, but behavior is unspecified for inputs that -- did not come from as_lua_id() from_lua_id: (str)-> - unless string2.is_lua_id("^_+(.*)$") + unless is_lua_id("^_+(.*)$") str = str\sub(2,-1) str = gsub(str, "_", " ") str = gsub(str, "x([0-9A-F][0-9A-F])", (hex)-> char(tonumber(hex, 16))) diff --git a/tools/find_action.nom b/tools/find_action.nom index e6fe90a..8381855 100755 --- a/tools/find_action.nom +++ b/tools/find_action.nom @@ -15,12 +15,19 @@ for %path in %files: unless (%filename::matches "%.nom$") (do next %filename) %file = (read file %filename) %tree = (parse %file from %filename) + %results = [] for %t in recursive %tree: if (%t is "Action" syntax tree): if (%t.stub is %stub): %line_num = (line number of %t.source.start in %file) - say (blue "\%filename:\%line_num:") - say (yellow (source lines of %t)) + %results::add {..} + line: %line_num + text: "\ + ..\(blue "\%filename:\%line_num:") + \(yellow (source lines of %t))" if (%t is syntax tree): for %sub in %t: recurse %t on %sub + sort %results by % -> %.line + for % in %results: + say %.text