From 79d4bd5125de7ff220fbf8a8a5493d437ed16963 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Tue, 18 Sep 2018 19:48:58 -0700 Subject: Got rid of repr() use and replaced with :as_lua() or :as_nomsu() in as many places as possible. --- code_obj.lua | 20 +++++------ code_obj.moon | 15 ++++---- containers.lua | 90 +++++++++++++++++++++++++++++++++++++++++++++--- containers.moon | 30 ++++++++++++++-- core/collections.nom | 2 ++ core/metaprogramming.nom | 24 +++++++------ lib/object.nom | 10 ++++-- nomsu.lua | 8 +++-- nomsu.moon | 6 ++-- nomsu_compiler.lua | 39 +++++++++++++-------- nomsu_compiler.moon | 37 ++++++++++++-------- parser.lua | 2 -- parser.moon | 1 - string2.lua | 18 ++++++++++ string2.moon | 14 ++++++++ syntax_tree.lua | 58 ++++++++++++++++++++++++++++--- syntax_tree.moon | 23 +++++++++++-- 17 files changed, 312 insertions(+), 85 deletions(-) diff --git a/code_obj.lua b/code_obj.lua index d51d63f..5be92e6 100644 --- a/code_obj.lua +++ b/code_obj.lua @@ -3,8 +3,6 @@ do local _obj_0 = table insert, remove, concat = _obj_0.insert, _obj_0.remove, _obj_0.concat end -local repr -repr = require('utils').repr local unpack = unpack or table.unpack local LuaCode, NomsuCode, Source do @@ -13,8 +11,8 @@ do __tostring = function(self) return "@" .. tostring(self.filename) .. "[" .. tostring(self.start) .. tostring(self.stop and ':' .. self.stop or '') .. "]" end, - __repr = function(self) - return "Source(" .. tostring(repr(self.filename)) .. ", " .. tostring(self.start) .. tostring(self.stop and ', ' .. self.stop or '') .. ")" + as_lua = function(self) + return "Source(" .. tostring(self.filename:as_lua()) .. ", " .. tostring(self.start) .. tostring(self.stop and ', ' .. self.stop or '') .. ")" end, __eq = function(self, other) return getmetatable(self) == getmetatable(other) and self.filename == other.filename and self.start == other.start and self.stop == other.stop @@ -108,16 +106,16 @@ do end return self.__str end, - __repr = function(self) + as_lua = function(self) return tostring(self.__class.__name) .. "(" .. tostring(concat({ - repr(tostring(self.source)), + tostring(self.source):as_lua(), unpack((function() local _accum_0 = { } local _len_0 = 1 local _list_0 = self.bits for _index_0 = 1, #_list_0 do local b = _list_0[_index_0] - _accum_0[_len_0] = repr(b) + _accum_0[_len_0] = b:as_lua() _len_0 = _len_0 + 1 end return _accum_0 @@ -158,7 +156,7 @@ do b.dirty = error end if type(b) ~= 'string' and not (type(b) == 'table' and b.is_code) then - b = repr(b) + b = b:as_lua() end bits[#bits + 1] = b _continue_0 = true @@ -236,7 +234,7 @@ do b.dirty = error end if type(b) ~= 'string' and not (type(b) == 'table' and b.is_code) then - b = repr(b) + b = b:as_lua() end bits[i] = b end @@ -276,7 +274,7 @@ do local _parent_0 = Code local _base_0 = { __tostring = Code.__tostring, - __repr = Code.__repr, + as_lua = Code.as_lua, __len = Code.__len, add_free_vars = function(self, vars) if not (#vars > 0) then @@ -469,7 +467,7 @@ do local _parent_0 = Code local _base_0 = { __tostring = Code.__tostring, - __repr = Code.__repr, + as_lua = Code.as_lua, __len = Code.__len } _base_0.__index = _base_0 diff --git a/code_obj.moon b/code_obj.moon index bd53c5b..4e70784 100644 --- a/code_obj.moon +++ b/code_obj.moon @@ -2,7 +2,6 @@ -- build up generated code, while keeping track of where it came from, and managing -- indentation levels. {:insert, :remove, :concat} = table -{:repr} = require 'utils' unpack or= table.unpack local LuaCode, NomsuCode, Source @@ -19,7 +18,7 @@ class Source __tostring: => "@#{@filename}[#{@start}#{@stop and ':'..@stop or ''}]" - __repr: => "Source(#{repr @filename}, #{@start}#{@stop and ', '..@stop or ''})" + as_lua: => "Source(#{@filename\as_lua!}, #{@start}#{@stop and ', '..@stop or ''})" __eq: (other)=> getmetatable(@) == getmetatable(other) and @filename == other.filename and @start == other.start and @stop == other.stop @@ -67,8 +66,8 @@ class Code @__str = concat(buff, "") return @__str - __repr: => - "#{@__class.__name}(#{concat {repr(tostring(@source)), unpack([repr(b) for b in *@bits])}, ", "})" + as_lua: => + "#{@__class.__name}(#{concat {tostring(@source)\as_lua!, unpack([b\as_lua! for b in *@bits])}, ", "})" __len: => #tostring(@) @@ -93,7 +92,7 @@ class Code if b == '' then continue b.dirty = error if b.is_code if type(b) != 'string' and not (type(b) == 'table' and b.is_code) - b = repr(b) + b = b\as_lua! bits[#bits+1] = b @dirty! @@ -148,7 +147,7 @@ class Code b = select(i, ...) b.dirty = error if b.is_code if type(b) != 'string' and not (type(b) == 'table' and b.is_code) - b = repr(b) + b = b\as_lua! bits[i] = b @dirty! @@ -158,7 +157,7 @@ class Code class LuaCode extends Code __tostring: Code.__tostring - __repr: Code.__repr + as_lua: Code.as_lua __len: Code.__len new: (...)=> super ... @@ -253,7 +252,7 @@ class LuaCode extends Code class NomsuCode extends Code __tostring: Code.__tostring - __repr: Code.__repr + as_lua: Code.as_lua __len: Code.__len Code.__base.append_1 = assert Code.__base.append diff --git a/containers.lua b/containers.lua index 1b3fd94..a7819ec 100644 --- a/containers.lua +++ b/containers.lua @@ -3,14 +3,50 @@ do local _obj_0 = table insert, remove, concat = _obj_0.insert, _obj_0.remove, _obj_0.concat end -local repr, stringify, equivalent, nth_to_last, size +local equivalent, nth_to_last, size do local _obj_0 = require('utils') - repr, stringify, equivalent, nth_to_last, size = _obj_0.repr, _obj_0.stringify, _obj_0.equivalent, _obj_0.nth_to_last, _obj_0.size + equivalent, nth_to_last, size = _obj_0.equivalent, _obj_0.nth_to_last, _obj_0.size end local lpeg = require('lpeg') local re = require('re') local List, Dict +local as_nomsu +as_nomsu = function(self) + if type(self) == 'number' then + return tostring(self) + end + do + local mt = getmetatable(self) + if mt then + do + local _as_nomsu = mt.as_nomsu + if _as_nomsu then + return _as_nomsu(self) + end + end + end + end + return error("Not supported: " .. tostring(self)) +end +local as_lua +as_lua = function(self) + if type(self) == 'number' then + return tostring(self) + end + do + local mt = getmetatable(self) + if mt then + do + local _as_lua = mt.as_lua + if _as_lua then + return _as_lua(self) + end + end + end + end + return error("Not supported: " .. tostring(self)) +end local _list_mt = { __eq = equivalent, __tostring = function(self) @@ -19,12 +55,36 @@ local _list_mt = { local _len_0 = 1 for _index_0 = 1, #self do local b = self[_index_0] - _accum_0[_len_0] = repr(b) + _accum_0[_len_0] = tostring(b) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)(), ", ") .. "]" + end, + as_nomsu = function(self) + return "[" .. concat((function() + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #self do + local b = self[_index_0] + _accum_0[_len_0] = as_nomsu(b) _len_0 = _len_0 + 1 end return _accum_0 end)(), ", ") .. "]" end, + as_lua = function(self) + return "_List{" .. concat((function() + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #self do + local b = self[_index_0] + _accum_0[_len_0] = as_lua(b) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)(), ", ") .. "}" + end, __lt = function(self, other) assert(type(self) == 'table' and type(other) == 'table', "Incompatible types for comparison") for i = 1, math.max(#self, #other) do @@ -162,7 +222,29 @@ local _dict_mt = { local _accum_0 = { } local _len_0 = 1 for k, v in pairs(self) do - _accum_0[_len_0] = tostring(repr(k)) .. ": " .. tostring(repr(v)) + _accum_0[_len_0] = tostring(tostring(k)) .. ": " .. tostring(tostring(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)(), ", ") .. "}" + end, + as_nomsu = function(self) + return "{" .. concat((function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self) do + _accum_0[_len_0] = tostring(as_nomsu(k)) .. ": " .. tostring(as_nomsu(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)(), ", ") .. "}" + end, + as_lua = function(self) + return "_Dict{" .. concat((function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self) do + _accum_0[_len_0] = "[ " .. tostring(as_lua(k)) .. "]= " .. tostring(as_lua(v)) _len_0 = _len_0 + 1 end return _accum_0 diff --git a/containers.moon b/containers.moon index eaf007a..70a9f70 100644 --- a/containers.moon +++ b/containers.moon @@ -1,19 +1,39 @@ -- This file contains container classes, i.e. Lists, Dicts, and Sets {:insert,:remove,:concat} = table -{:repr, :stringify, :equivalent, :nth_to_last, :size} = require 'utils' +{:equivalent, :nth_to_last, :size} = require 'utils' lpeg = require 'lpeg' re = require 're' local List, Dict +as_nomsu = => + if type(@) == 'number' + return tostring(@) + if mt = getmetatable(@) + if _as_nomsu = mt.as_nomsu + return _as_nomsu(@) + error("Not supported: #{@}") + +as_lua = => + if type(@) == 'number' + return tostring(@) + if mt = getmetatable(@) + if _as_lua = mt.as_lua + return _as_lua(@) + error("Not supported: #{@}") + -- List and Dict classes to provide basic equality/tostring functionality for the tables -- used in Nomsu. This way, they retain a notion of whether they were originally lists or dicts. _list_mt = __eq:equivalent -- Could consider adding a __newindex to enforce list-ness, but would hurt performance __tostring: => - "["..concat([repr(b) for b in *@], ", ").."]" + "["..concat([tostring(b) for b in *@], ", ").."]" + as_nomsu: => + "["..concat([as_nomsu(b) for b in *@], ", ").."]" + as_lua: => + "_List{"..concat([as_lua(b) for b in *@], ", ").."}" __lt: (other)=> assert type(@) == 'table' and type(other) == 'table', "Incompatible types for comparison" for i=1,math.max(#@, #other) @@ -74,7 +94,11 @@ _dict_mt = __eq:equivalent __len:size __tostring: => - "{"..concat(["#{repr(k)}: #{repr(v)}" for k,v in pairs @], ", ").."}" + "{"..concat(["#{tostring(k)}: #{tostring(v)}" for k,v in pairs @], ", ").."}" + as_nomsu: => + "{"..concat(["#{as_nomsu(k)}: #{as_nomsu(v)}" for k,v in pairs @], ", ").."}" + as_lua: => + "_Dict{"..concat(["[ #{as_lua(k)}]= #{as_lua(v)}" for k,v in pairs @], ", ").."}" __ipairs: => walk_items, {table:@, key:nil}, 0 __band: (other)=> Dict{k,v for k,v in pairs(@) when other[k] != nil} diff --git a/core/collections.nom b/core/collections.nom index 8dbc79d..3877d31 100644 --- a/core/collections.nom +++ b/core/collections.nom @@ -149,6 +149,8 @@ test: assume ("\%t" == "XXX") compile [set %dict 's metatable to %metatable] to (..) Lua "setmetatable(\(%dict as lua expr), \(%metatable as lua expr));" +compile [%'s metatable, %' metatable] to (..) + Lua value "getmetatable(\(% as lua expr))" test: assume (({} with fallback % -> (% + 1)).10 == 11) diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom index c50f783..51831ec 100644 --- a/core/metaprogramming.nom +++ b/core/metaprogramming.nom @@ -34,7 +34,7 @@ lua> "\ lua> "\ ..COMPILE_ACTIONS["compile as 1"] = function(nomsu, tree, \%action) - local lua = LuaCode.Value(tree.source, "COMPILE_ACTIONS[", repr(\%action.stub), "](") + local lua = LuaCode.Value(tree.source, "COMPILE_ACTIONS[", \%action.stub:as_lua(), "](") 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") @@ -66,19 +66,19 @@ lua> "\ ..COMPILE_ACTIONS["compile 1 to 2"] = 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, "COMPILE_ACTIONS[", repr(\%actions[1].stub), + local lua = LuaCode(tree.source, "COMPILE_ACTIONS[", \%actions[1].stub:as_lua(), "] = ", \(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("\\nCOMPILE_ACTIONS[", repr(alias.stub), "] = ") + lua:append("\\nCOMPILE_ACTIONS[", alias.stub:as_lua(), "] = ") if utils.equivalent(\%args, \%alias_args) then - lua:append("COMPILE_ACTIONS[", repr(\%actions[1].stub), "]") + lua:append("COMPILE_ACTIONS[", \%actions[1].stub:as_lua(), "]") else lua:append("function(") lua:concat_append(\%alias_args, ", ") - lua:append(")\\n return COMPILE_ACTIONS[", repr(\%actions[1].stub), "](") + lua:append(")\\n return COMPILE_ACTIONS[", \%actions[1].stub:as_lua(), "](") lua:concat_append(\%args, ", ") lua:append(")\\nend") end @@ -173,7 +173,7 @@ compile [parse %actions as %body] to (..) if replacements[t[1]] then return replacements[t[1]] else - return t.type.."{mangle("..repr(t[1]).."), source="..repr(tostring(t.source)).."}" + return t.type.."{mangle("..t[1]:as_lua().."), source="..tostring(t.source):as_lua().."}" end elseif AST.is_syntax_tree(t) then local ret = {} @@ -183,7 +183,7 @@ compile [parse %actions as %body] to (..) ret[#ret+1] = make_tree(t[i]) i = i + 1 elseif k == "source" then - ret[#ret+1] = k.."= "..repr(tostring(v)) + ret[#ret+1] = k.."= "..tostring(v):as_lua() elseif type(k) == 'string' and k:match("[_a-zA-Z][_a-zA-Z0-9]*") then ret[#ret+1] = k.."= "..make_tree(v) else @@ -191,8 +191,10 @@ compile [parse %actions as %body] to (..) end end return t.type.."{"..table.concat(ret, ", ").."}" + elseif type(t) == 'number' then + return tostring(t) else - return repr(t) + return t:as_lua() end end local \%new_body = LuaCode(\%body.source, @@ -257,7 +259,7 @@ action [%tree with vars %replacements] (..) compile [tree %tree with vars %replacements] to (..) Lua value "\ - ..\(=lua "repr(\%tree)"):map(function(t) + ..\(=lua "(\%tree):as_lua()"):map(function(t) if t.type == "Var" then return \(%replacements as lua expr)[t[1]] end @@ -312,7 +314,7 @@ test: ..one "two"" ..== "\"one\\n\\\"two\\\"\"" -compile [quote %s] to (Lua value "repr(\(%s as lua expr))") +compile [quote %s] to (Lua value "tostring(\(%s as lua expr)):as_lua()") test: assume ((type of {}) == "table") or barf "type of failed." @@ -340,7 +342,7 @@ test: compile [run %nomsu_code] to (..) Lua value "\ ..nomsu:run(NomsuCode(\(..) - =lua "repr(tostring(\(%nomsu_code.source)))" + =lua "tostring(\(%nomsu_code.source)):as_lua()" .., \(%nomsu_code as lua expr)))" test: diff --git a/lib/object.nom b/lib/object.nom index b49b8f2..600ecf6 100644 --- a/lib/object.nom +++ b/lib/object.nom @@ -46,7 +46,7 @@ compile [my action %actions %body] to: lua> "\ ..local fn_name = \%actions[1].stub:as_lua_id() local \%args = table.map(\%actions[1]:get_args(), function(a) return tostring(nomsu:compile(a)) end) - table.insert(\%args, \(\%me as lua id)) + table.insert(\%args, 1, \(\%me as lua id)) local lua = LuaCode(tree.source, "class.", fn_name, " = ", \(..) compile as (%args -> %body) ..) @@ -54,7 +54,7 @@ compile [my action %actions %body] to: local alias = \%actions[i] local alias_name = alias.stub:as_lua_id() local \%alias_args = table.map(alias:get_args(), function(a) return tostring(nomsu:compile(a)) end) - table.insert(\%alias_args, \(\%me as lua id)) + table.insert(\%alias_args, 1, \(\%me as lua id)) lua:append("\\nclass.", alias_name, " = ") if utils.equivalent(\%args, \%alias_args) then lua:append("class.", fn_name) @@ -110,3 +110,9 @@ compile [object %classname extends %parent %class_body] to: parse [object %classname %class_body] as (..) object %classname extends (nil) %class_body + +parse [%obj is a %class] as (..) + all of [..] + (type of %obj) == "table" + %obj's metatable + (%obj's metatable).__index == %class diff --git a/nomsu.lua b/nomsu.lua index 3d78dd1..fa6a6ce 100644 --- a/nomsu.lua +++ b/nomsu.lua @@ -91,8 +91,6 @@ do local _obj_0 = require("code_obj") NomsuCode, LuaCode, Source = _obj_0.NomsuCode, _obj_0.LuaCode, _obj_0.Source end -local repr -repr = require("utils").repr if not arg or debug.getinfo(2).func == require then return NomsuCompiler end @@ -324,7 +322,11 @@ say "\ local ret ok, ret = xpcall(nomsu.run, err_hand, nomsu, buff, Source(pseudo_filename, 1, #buff)) if ok and ret ~= nil then - print("= " .. repr(ret)) + if type(ret) == 'number' then + print("= " .. tostring(ret)) + else + print("= " .. tostring(ret:as_nomsu())) + end elseif not ok then Errhand.print_error(ret) end diff --git a/nomsu.moon b/nomsu.moon index 382a5b5..1ab9637 100755 --- a/nomsu.moon +++ b/nomsu.moon @@ -48,7 +48,6 @@ Files = require "files" Errhand = require "error_handling" NomsuCompiler = require "nomsu_compiler" {:NomsuCode, :LuaCode, :Source} = require "code_obj" -{:repr} = require "utils" -- If this file was reached via require(), then just return the Nomsu compiler if not arg or debug.getinfo(2).func == require @@ -222,7 +221,10 @@ say "\ Errhand.print_error error_message ok, ret = xpcall(nomsu.run, err_hand, nomsu, buff, Source(pseudo_filename, 1, #buff)) if ok and ret != nil - print "= "..repr(ret) + if type(ret) == 'number' + print "= #{ret}" + else + print "= #{ret\as_nomsu!}" elseif not ok Errhand.print_error ret diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua index 2e286b7..89d247a 100644 --- a/nomsu_compiler.lua +++ b/nomsu_compiler.lua @@ -4,8 +4,8 @@ R, P, S = lpeg.R, lpeg.P, lpeg.S local re = require('re') local utils = require('utils') local Files = require('files') -local repr, stringify, equivalent -repr, stringify, equivalent = utils.repr, utils.stringify, utils.equivalent +local stringify, equivalent +stringify, equivalent = utils.stringify, utils.equivalent local List, Dict, Text do local _obj_0 = require('containers') @@ -193,7 +193,6 @@ do ipairs = ipairs, _List = List, _Dict = Dict, - repr = repr, stringify = stringify, utils = utils, lpeg = lpeg, @@ -385,7 +384,7 @@ do add_lua_string_bits = function(self, val_or_stmt, code) local cls_str = val_or_stmt == "value" and "LuaCode.Value(" or "LuaCode(" if code.type ~= "Text" then - return LuaCode.Value(code.source, cls_str, repr(tostring(code.source)), ", ", self:compile(code), ")") + return LuaCode.Value(code.source, cls_str, tostring(code.source):as_lua(), ", ", self:compile(code), ")") end local add_bit_lua add_bit_lua = function(lua, bit_lua) @@ -395,11 +394,11 @@ do end local operate_on_text operate_on_text = function(text) - local lua = LuaCode.Value(text.source, cls_str, repr(tostring(text.source))) + local lua = LuaCode.Value(text.source, cls_str, tostring(text.source):as_lua()) for _index_0 = 1, #text do local bit = text[_index_0] if type(bit) == "string" then - add_bit_lua(lua, repr(bit)) + add_bit_lua(lua, bit:as_lua()) elseif bit.type == "Text" then add_bit_lua(lua, operate_on_text(bit)) else @@ -480,13 +479,13 @@ do end return _accum_0 end)(), "\n") - return LuaCode(tree.source, "TESTS[" .. tostring(repr(tostring(tree.source))) .. "] = ", repr(test_str)) + return LuaCode(tree.source, "TESTS[" .. tostring(tostring(tree.source):as_lua()) .. "] = ", test_str:as_lua()) end, ["is jit"] = function(self, tree, code) return LuaCode.Value(tree.source, jit and "true" or "false") end, ["Lua version"] = function(self, tree, code) - return LuaCode.Value(tree.source, repr(_VERSION)) + return LuaCode.Value(tree.source, _VERSION:as_lua()) end, __parent = setmetatable({ }, { __index = function(self, key) @@ -744,9 +743,9 @@ do if tok.type == "Block" then self:compile_error(tok, "Can't compile action (" .. tostring(stub) .. ") with a Block as an argument.", "Maybe there should be a compile-time action with that name that isn't being found?") elseif tok.type == "Action" then - self:compile_error(tok, "Can't use this as an argument to (" .. tostring(stub) .. "), since it's not an expression, it produces: " .. tostring(repr(arg_lua)), "Check the implementation of (" .. tostring(tok.stub) .. ") to see if it is actually meant to produce an expression.") + self:compile_error(tok, "Can't use this as an argument to (" .. tostring(stub) .. "), since it's not an expression, it produces: " .. tostring(tostring(arg_lua)), "Check the implementation of (" .. tostring(tok.stub) .. ") to see if it is actually meant to produce an expression.") else - self:compile_error(tok, "Can't use this as an argument to (" .. tostring(stub) .. "), since it's not an expression, it produces: " .. tostring(repr(arg_lua))) + self:compile_error(tok, "Can't use this as an argument to (" .. tostring(stub) .. "), since it's not an expression, it produces: " .. tostring(tostring(arg_lua))) end end insert(args, arg_lua) @@ -762,6 +761,16 @@ do elseif "EscapedNomsu" == _exp_0 then local lua = LuaCode.Value(tree.source, tree[1].type, "{") local needs_comma, i = false, 1 + local as_lua + as_lua = function(x) + if type(x) == 'number' then + return tostring(x) + elseif AST.is_syntax_tree(x) then + return self:compile(x, compile_actions) + else + return x:as_lua() + end + end for k, v in pairs(AST.is_syntax_tree(tree[1], "EscapedNomsu") and tree or tree[1]) do if needs_comma then lua:append(", ") @@ -773,12 +782,12 @@ do elseif type(k) == 'string' and match(k, "[_a-zA-Z][_a-zA-Z0-9]*") then lua:append(k, "= ") else - lua:append("[", (AST.is_syntax_tree(k) and self:compile(k, compile_actions) or repr(k)), "]= ") + lua:append("[", as_lua(k), "]= ") end if k == "source" then - lua:append(repr(tostring(v))) + lua:append(tostring(v):as_lua()) else - lua:append(AST.is_syntax_tree(v) and self:compile(v, compile_actions) or repr(v)) + lua:append(as_lua(v)) end end lua:append("}") @@ -849,7 +858,7 @@ do if #lua.bits > 0 then lua:append("..") end - lua:append(repr(string_buffer)) + lua:append(string_buffer:as_lua()) string_buffer = "" end local bit_lua = self:compile(bit, compile_actions) @@ -875,7 +884,7 @@ do if #lua.bits > 0 then lua:append("..") end - lua:append(repr(string_buffer)) + lua:append(string_buffer:as_lua()) end if #lua.bits > 1 then lua:parenthesize() diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon index 19d4049..0718bca 100644 --- a/nomsu_compiler.moon +++ b/nomsu_compiler.moon @@ -14,7 +14,7 @@ lpeg = require 'lpeg' re = require 're' utils = require 'utils' Files = require 'files' -{:repr, :stringify, :equivalent} = utils +{:stringify, :equivalent} = utils {:List, :Dict, :Text} = require 'containers' export colors, colored colors = require 'consolecolors' @@ -104,7 +104,7 @@ with NomsuCompiler -- Nomsu types: _List:List, _Dict:Dict, -- Utilities and misc. - repr:repr, stringify:stringify, utils:utils, lpeg:lpeg, re:re, Files:Files, + stringify:stringify, utils:utils, lpeg:lpeg, re:re, Files:Files, :AST, TESTS: Dict{}, globals: Dict{} :LuaCode, :NomsuCode, :Source nomsu:NomsuCompiler @@ -202,16 +202,16 @@ with NomsuCompiler add_lua_string_bits = (val_or_stmt, code)=> cls_str = val_or_stmt == "value" and "LuaCode.Value(" or "LuaCode(" if code.type != "Text" - return LuaCode.Value(code.source, cls_str, repr(tostring(code.source)), ", ", @compile(code), ")") + return LuaCode.Value(code.source, cls_str, tostring(code.source)\as_lua!, ", ", @compile(code), ")") add_bit_lua = (lua, bit_lua)-> bit_leading_len = #(bit_lua\match("^[^\n]*")) lua\append(lua\trailing_line_len! + bit_leading_len > MAX_LINE and ",\n " or ", ") lua\append(bit_lua) operate_on_text = (text)-> - lua = LuaCode.Value(text.source, cls_str, repr(tostring(text.source))) + lua = LuaCode.Value(text.source, cls_str, tostring(text.source)\as_lua!) for bit in *text if type(bit) == "string" - add_bit_lua(lua, repr(bit)) + add_bit_lua(lua, bit\as_lua!) elseif bit.type == "Text" add_bit_lua(lua, operate_on_text(bit)) else @@ -270,13 +270,13 @@ with NomsuCompiler ["tests"]: (tree)=> LuaCode.Value(tree.source, "TESTS") ["test 1"]: (tree, body)=> test_str = table.concat [tostring(@tree_to_nomsu(line)) for line in *body], "\n" - LuaCode tree.source, "TESTS[#{repr(tostring(tree.source))}] = ", repr(test_str) + LuaCode tree.source, "TESTS[#{tostring(tree.source)\as_lua!}] = ", test_str\as_lua! ["is jit"]: (tree, code)=> return LuaCode.Value(tree.source, jit and "true" or "false") ["Lua version"]: (tree, code)=> - return LuaCode.Value(tree.source, repr(_VERSION)) + return LuaCode.Value(tree.source, _VERSION\as_lua!) __parent: setmetatable({}, { __index: (key)=> @@ -439,11 +439,11 @@ with NomsuCompiler elseif tok.type == "Action" @compile_error tok, - "Can't use this as an argument to (#{stub}), since it's not an expression, it produces: #{repr arg_lua}", + "Can't use this as an argument to (#{stub}), since it's not an expression, it produces: #{tostring(arg_lua)}", "Check the implementation of (#{tok.stub}) to see if it is actually meant to produce an expression." else @compile_error tok, - "Can't use this as an argument to (#{stub}), since it's not an expression, it produces: #{repr arg_lua}" + "Can't use this as an argument to (#{stub}), since it's not an expression, it produces: #{tostring(arg_lua)}" insert args, arg_lua lua\concat_append args, ", " lua\append ")" @@ -452,6 +452,13 @@ with NomsuCompiler when "EscapedNomsu" lua = LuaCode.Value tree.source, tree[1].type, "{" needs_comma, i = false, 1 + as_lua = (x)-> + if type(x) == 'number' + tostring(x) + elseif AST.is_syntax_tree(x) + @compile(x, compile_actions) + else x\as_lua! + for k,v in pairs(AST.is_syntax_tree(tree[1], "EscapedNomsu") and tree or tree[1]) if needs_comma then lua\append ", " else needs_comma = true @@ -460,11 +467,11 @@ with NomsuCompiler elseif type(k) == 'string' and match(k,"[_a-zA-Z][_a-zA-Z0-9]*") lua\append(k, "= ") else - lua\append("[", (AST.is_syntax_tree(k) and @compile(k, compile_actions) or repr(k)), "]= ") + lua\append("[", as_lua(k), "]= ") if k == "source" - lua\append repr(tostring(v)) + lua\append tostring(v)\as_lua! else - lua\append(AST.is_syntax_tree(v) and @compile(v, compile_actions) or repr(v)) + lua\append as_lua(v) lua\append "}" return lua @@ -499,9 +506,9 @@ with NomsuCompiler if type(bit) == "string" string_buffer ..= bit continue - if string_buffer ~= "" + if string_buffer != "" if #lua.bits > 0 then lua\append ".." - lua\append repr(string_buffer) + lua\append string_buffer\as_lua! string_buffer = "" bit_lua = @compile(bit, compile_actions) unless bit_lua.is_value @@ -516,7 +523,7 @@ with NomsuCompiler if string_buffer ~= "" or #lua.bits == 0 if #lua.bits > 0 then lua\append ".." - lua\append repr(string_buffer) + lua\append string_buffer\as_lua! if #lua.bits > 1 lua\parenthesize! diff --git a/parser.lua b/parser.lua index 0694e3e..5eee8ca 100644 --- a/parser.lua +++ b/parser.lua @@ -3,8 +3,6 @@ local re = require('re') lpeg.setmaxstack(20000) local P, R, S, C, Cmt, Carg, Cc P, R, S, C, Cmt, Carg, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Cmt, lpeg.Carg, lpeg.Cc -local repr -repr = require('utils').repr local DEFS do local _with_0 = { } diff --git a/parser.moon b/parser.moon index 9a2e2ff..78e6291 100644 --- a/parser.moon +++ b/parser.moon @@ -3,7 +3,6 @@ lpeg = require 'lpeg' re = require 're' lpeg.setmaxstack 20000 {:P,:R,:S,:C,:Cmt,:Carg,:Cc} = lpeg -{:repr} = require 'utils' DEFS = with {} -- Newline supports either windows-style CR+LF or unix-style LF diff --git a/string2.lua b/string2.lua index 5995de2..2cdfefc 100644 --- a/string2.lua +++ b/string2.lua @@ -119,6 +119,24 @@ local string2 = { end return table.concat(lines, "\n") end, + as_lua = function(self) + local escaped = gsub(self, "\\", "\\\\") + escaped = gsub(escaped, "\n", "\\n") + escaped = gsub(escaped, '"', '\\"') + escaped = gsub(escaped, "[^ %g]", function(c) + return format("\\%03d", byte(c, 1)) + end) + return '"' .. escaped .. '"' + end, + as_nomsu = function(self) + local escaped = gsub(self, "\\", "\\\\") + escaped = gsub(escaped, "\n", "\\n") + escaped = gsub(escaped, '"', '\\"') + escaped = gsub(escaped, "[^ %g]", function(c) + return format("\\%03d", byte(c, 1)) + end) + return '"' .. escaped .. '"' + end, as_lua_id = function(str) local orig = str str = gsub(str, "^ *$", "%1 ") diff --git a/string2.moon b/string2.moon index 2259272..662cd0d 100644 --- a/string2.moon +++ b/string2.moon @@ -45,6 +45,20 @@ string2 = { lines[#lines+1] = line return table.concat(lines, "\n") + as_lua: => + escaped = gsub(@, "\\", "\\\\") + escaped = gsub(escaped, "\n", "\\n") + escaped = gsub(escaped, '"', '\\"') + escaped = gsub(escaped, "[^ %g]", (c)-> format("\\%03d", byte(c, 1))) + return '"'..escaped..'"' + + as_nomsu: => + escaped = gsub(@, "\\", "\\\\") + escaped = gsub(escaped, "\n", "\\n") + escaped = gsub(escaped, '"', '\\"') + escaped = gsub(escaped, "[^ %g]", (c)-> format("\\%03d", byte(c, 1))) + return '"'..escaped..'"' + -- Convert an arbitrary text into a valid Lua identifier. This function is injective, -- but not idempotent. In logic terms: (x != y) => (as_lua_id(x) != as_lua_id(y)), -- but not (as_lua_id(a) == b) => (as_lua_id(b) == b). diff --git a/syntax_tree.lua b/syntax_tree.lua index 72b510e..afdb631 100644 --- a/syntax_tree.lua +++ b/syntax_tree.lua @@ -1,5 +1,3 @@ -local repr -repr = require('utils').repr local insert, remove, concat do local _obj_0 = table @@ -15,6 +13,24 @@ AST.is_syntax_tree = function(n, t) end return type(n) == 'table' and getmetatable(n) and AST[n.type] == getmetatable(n) and (t == nil or n.type == t) end +local as_lua +as_lua = function(self) + if type(self) == 'number' then + return tostring(self) + end + do + local mt = getmetatable(self) + if mt then + do + local _as_lua = mt.as_lua + if _as_lua then + return _as_lua(self) + end + end + end + end + return error("Not supported: " .. tostring(self)) +end local types = { "Number", "Var", @@ -42,10 +58,42 @@ for _index_0 = 1, #types do return getmetatable(x) == self end cls.__tostring = function(self) - return tostring(self.type) .. tostring(repr(self, (function() end))) + local bits + do + local _accum_0 = { } + local _len_0 = 1 + for _index_1 = 1, #self do + local b = self[_index_1] + _accum_0[_len_0] = tostring(b) + _len_0 = _len_0 + 1 + end + bits = _accum_0 + end + for k, v in pairs(self) do + if not (bits[k]) then + table.insert(bits, "[ " .. tostring(tostring(k)) .. "]=" .. tostring(tostring(v))) + end + end + return tostring(self.type) .. "{" .. tostring(table.concat(bits, ", ")) .. "}" end - cls.__repr = function(self) - return tostring(self.type) .. tostring(repr(self, (function() end))) + cls.as_lua = function(self) + local bits + do + local _accum_0 = { } + local _len_0 = 1 + for _index_1 = 1, #self do + local b = self[_index_1] + _accum_0[_len_0] = as_lua(b) + _len_0 = _len_0 + 1 + end + bits = _accum_0 + end + for k, v in pairs(self) do + if not (bits[k]) then + table.insert(bits, "[ " .. tostring(as_lua(k)) .. "]=" .. tostring(as_lua(v))) + end + end + return tostring(self.type) .. "{" .. tostring(table.concat(bits, ", ")) .. "}" end cls.source_code_for_tree = setmetatable({ }, { __index = function(self, t) diff --git a/syntax_tree.moon b/syntax_tree.moon index 305a1ee..d2f5d37 100644 --- a/syntax_tree.moon +++ b/syntax_tree.moon @@ -1,6 +1,5 @@ -- This file contains the datastructures used to represent parsed Nomsu syntax trees, -- as well as the logic for converting them to Lua code. -{:repr} = require 'utils' {:insert, :remove, :concat} = table {:Source} = require "code_obj" unpack or= table.unpack @@ -9,6 +8,14 @@ AST = {} 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) +as_lua = => + if type(@) == 'number' + return tostring(@) + if mt = getmetatable(@) + if _as_lua = mt.as_lua + return _as_lua(@) + error("Not supported: #{@}") + types = {"Number", "Var", "Block", "EscapedNomsu", "Text", "List", "Dict", "DictEntry", "IndexChain", "Action", "FileChunks", "Error", "Comment"} for name in *types @@ -19,8 +26,18 @@ for name in *types .__name = name .type = name .is_instance = (x)=> getmetatable(x) == @ - .__tostring = => "#{@type}#{repr @, (->)}" - .__repr = => "#{@type}#{repr @, (->)}" + .__tostring = => + bits = [tostring(b) for b in *@] + for k,v in pairs(@) + unless bits[k] + table.insert(bits, "[ #{tostring(k)}]=#{tostring(v)}") + return "#{@type}{#{table.concat(bits, ", ")}}" + .as_lua = => + bits = [as_lua(b) for b in *@] + for k,v in pairs(@) + unless bits[k] + table.insert(bits, "[ #{as_lua(k)}]=#{as_lua(v)}") + return "#{@type}{#{table.concat(bits, ", ")}}" .source_code_for_tree = setmetatable({}, {__index:(t)=> s = t.source Files = require 'files' -- cgit v1.2.3 From f2048235f5cc7ff02db39a0e2fe5c79c7f390e0b Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Fri, 21 Sep 2018 00:30:28 -0700 Subject: Incremental checkin, currently not working, just saving progress. --- containers.moon | 10 +- core/control_flow.nom | 31 ++++- core/metaprogramming.nom | 34 ++++- lib/object.nom | 42 +++--- nomnom/ast.nom | 88 ++++++++++++ nomnom/code_obj.nom | 180 +++++++++++++++++++++++++ nomnom/compile.nom | 207 +++++++++++++++++++++++++++++ nomnom/decompile.nom | 339 +++++++++++++++++++++++++++++++++++++++++++++++ nomnom/files.nom | 123 +++++++++++++++++ nomnom/parser.nom | 81 +++++++++++ nomnom/pretty_errors.nom | 75 +++++++++++ nomnom/source.nom | 49 +++++++ nomsu_compiler.moon | 2 +- string2.moon | 27 ++-- 14 files changed, 1242 insertions(+), 46 deletions(-) create mode 100644 nomnom/ast.nom create mode 100644 nomnom/code_obj.nom create mode 100644 nomnom/compile.nom create mode 100644 nomnom/decompile.nom create mode 100644 nomnom/files.nom create mode 100644 nomnom/parser.nom create mode 100644 nomnom/pretty_errors.nom create mode 100644 nomnom/source.nom diff --git a/containers.moon b/containers.moon index 70a9f70..039a4ea 100644 --- a/containers.moon +++ b/containers.moon @@ -133,9 +133,11 @@ for i,entry in ipairs(Dict({x:99})) do {:reverse, :upper, :lower, :find, :byte, :match, :gmatch, :gsub, :sub, :format, :rep} = string string2 = require 'string2' - {:lines, :line, :line_at, :as_lua_id} = string2 + {:lines, :line, :line_at, :as_lua_id, :is_lua_id} = string2 text_methods = formatted_with_1:format, byte_1:byte, position_of_1:find, position_of_1_after_2:find, + as_a_lua_identifier: as_lua_id, is_a_lua_identifier: is_lua_id, + as_a_lua_id: as_lua_id, is_a_lua_id: is_lua_id, bytes_1_to_2: (start, stop)=> List{byte(tostring(@), start, stop)} [as_lua_id "with 1 -> 2"]: gsub bytes: => List{byte(tostring(@), 1, -1)}, @@ -157,8 +159,10 @@ do line_number_of_1: (i)=> select(2, line_at(@, i)) line_position_of_1: (i)=> select(3, line_at(@, i)) matches_1: (patt)=> match(@, patt) and true or false + matching_1: (patt)=> (match(@, patt)) + matching_groups_1: (patt)=> {match(@, patt)} [as_lua_id "* 1"]: (n)=> rep(@, n) - matching_1: (patt)=> + all_matches_of_1: (patt)=> result = {} stepper,x,i = gmatch(@, patt) while true @@ -176,4 +180,6 @@ do elseif type(i) == 'table' then return sub(@, i[1], i[2]) else return text_methods[i] + getmetatable("").__add = (x)=> tostring(@)..tostring(x) + return {:List, :Dict} diff --git a/core/control_flow.nom b/core/control_flow.nom index a9e0ae0..c496d18 100644 --- a/core/control_flow.nom +++ b/core/control_flow.nom @@ -79,6 +79,10 @@ test: %i += 1 unless (%i == 10): go to %loop assume (%i == 10) + === (Loop) === + %i -= 1 + unless (%i == 0): go to (Loop) + assume (%i == 0) compile [=== %label ===, --- %label ---, *** %label ***] to (..) Lua "::label_\(%label as lua identifier)::" @@ -240,10 +244,8 @@ test: # For-each loop (lua's "ipairs()") compile [for %var in %iterable %body] to: - # This uses Lua's approach of only allowing loop-scoped variables in a loop - unless (%var.type is "Var"): - compile error at %var "Expected a variable here, not a \(%var.type)." define mangler + # This uses Lua's approach of only allowing loop-scoped variables in a loop %lua = (..) Lua "\ ..for \(mangle "i"),\(%var as lua identifier) in ipairs(\(%iterable as lua expr)) do @@ -264,6 +266,29 @@ compile [for %var in %iterable %body] to: return %lua +# TODO: reduce code duplication +compile [for %var in %iterable at %i %body] to: + # This uses Lua's approach of only allowing loop-scoped variables in a loop + %lua = (..) + Lua "\ + ..for \(%i as lua identifier),\(%var as lua identifier) in ipairs(\(%iterable as lua expr)) do + \(%body as lua statements)" + + if (%body has subtree \(do next)): + %lua::append "\n ::continue::" + if (%body has subtree \(do next %var)): + %lua::append (Lua "\n\(compile as (===next %var ===))") + %lua::append "\nend --foreach-loop" + if (%body has subtree \(stop %var)): + %lua = (..) + Lua "\ + ..do -- scope for stopping for-loop + \%lua + \(compile as (===stop %var ===)) + end -- end of scope for stopping for-loop" + + return %lua + test: %d = {a:10, b:20, c:30, d:40, e:50} %result = [] diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom index 51831ec..1503905 100644 --- a/core/metaprogramming.nom +++ b/core/metaprogramming.nom @@ -145,7 +145,7 @@ compile [action %actions %body] to (..) test: assume ((action (say %)) == (=lua "say_1")) -compile [action %action] to (Lua value (%action as lua id)) +compile [action %action] to (Lua value (%action.stub as lua id)) test: parse [swap %x and %y] as (..) @@ -233,7 +233,12 @@ action [%var as lua identifier, %var as lua id] (..) lua> "\ ..if type(\%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, 'Action') then return \%var.stub: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.") + end + return lua else error("Unknown type: "..tostring(\%var)) end" @@ -317,8 +322,29 @@ test: compile [quote %s] to (Lua value "tostring(\(%s as lua expr)):as_lua()") test: - assume ((type of {}) == "table") or barf "type of failed." -compile [type of %obj] to (Lua value "type(\(%obj as lua expr))") + assume (lua type of {}) == "Lua table" + assume (type of {}) == "Dict" + assume ({} is a "Dict") + 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 %]: + lua> "\ + local lua_type = \(lua type of %) + if lua_type == 'string' then return 'Text' + elseif lua_type == 'table' then + local mt = getmetatable(\%) + if mt and mt.__type then return mt.__type end + return 'Lua table' + else return lua_type end" +parse [% is a %type, % is an %type] as ((type of %) == %type) +parse [% isn't a %type, % isn't an %type, % is not a %type, % is not an %type] +..as ((type of %) == %type) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/lib/object.nom b/lib/object.nom index 600ecf6..65da2a1 100644 --- a/lib/object.nom +++ b/lib/object.nom @@ -3,7 +3,7 @@ This file contains the implementation of an Object-Oriented programming system. test: - object "Dog": + object (Dog): (Dog).genus = "Canus" my action [set up]: %me.barks or= 0 my action [bark, woof]: @@ -12,8 +12,10 @@ test: my action [get pissed off]: %me.barks += 1 - %d = (new Dog {barks:2}) - assume (%d.barks == 2) + %d = (Dog {barks:2}) + assume (type of %d) == "Dog" + assume (%d is a "Dog") + assume %d.barks == 2 assume ((%d::bark) == "Bark! Bark!") assume ((%d::woof) == "Bark! Bark!") %d::get pissed off @@ -23,24 +25,24 @@ test: assume ("\(%d.class)" == "Dog") assume (%d.genus == "Canus") assume (%d.barks == 3) - %d2 = (new Dog) + %d2 = (Dog {}) assume (%d2.barks == 0) or barf "Default initializer failed" - with {%d:new Dog {barks:1}}: + with {%d:Dog {barks:1}}: assume ((%d::bark) == "Bark!") - object "Corgi" extends (Dog): + object (Corgi) extends (Dog): my action [sploot] "splooted" my action [bark, woof]: %barks = ("Yip!" for % in 1 to %me.barks) return (%barks::joined with " ") - %corg = (new Corgi) + %corg = (Corgi {}) assume (%corg.barks == 0) - with {%d:new Corgi {barks:1}}: + with {%d:Corgi {barks:1}}: assume ((%d::sploot) == "splooted") or barf "subclass method failed" assume ((%d::bark) == "Yip!") or barf "inheritance failed" assume ((%d::woof) == "Yip!") - with {%d:new Dog {barks:2}}: + with {%d:Dog {barks:2}}: assume ((%d::bark) == "Bark! Bark!") compile [my action %actions %body] to: lua> "\ @@ -69,12 +71,18 @@ compile [my action %actions %body] to: return lua" compile [object %classname extends %parent %class_body] to: + unless (%classname.type == "Action"): + compile error at %classname "Expected this to be an action, not a \(%classname.type)" + for % in %classname: + unless (% is text): + compile error at % "Class names should not have arguments." return (..) Lua "\ ..do - local class = {name=\(%classname as lua expr)} + local class = {name=\(quote %classname.stub)} setmetatable(class, { __index=\(%parent as lua expr), + __type=class.name, __tostring=function(cls) return cls.name end, __call=function(cls, inst) inst = setmetatable(inst or {}, cls) @@ -84,24 +92,21 @@ compile [object %classname extends %parent %class_body] to: return inst end, }) - nomsu.environment[("new "..class.name):as_lua_id()] = class - nomsu.environment[("new "..class.name.." 1"):as_lua_id()] = class + nomsu.environment[(class.name.." 1"):as_lua_id()] = class nomsu.environment[class.name:as_lua_id()] = function() return class end class.__index = class class.class = class class.__tostring = function(inst) return inst.name..getmetatable(_Dict{}).__tostring(inst) end - \(%class_body as lua statements) - local metamethod_map = {["as text"]="__tostring", ["clean up"]="__gc", ["+ 1"]="__add", ["- 1"]="__sub", ["* 1"]="__mul", ["/ 1"]="__div", ["-"]="__unm", ["// 1"]="__idiv", ["mod 1"]="__mod", ["^ 1"]="__pow", ["& 1"]="__band", ["| 1"]="__bor", ["~ 1"]="__bxor", ["~"]="__bnot", ["<< 1"]="__bshl", [">> 1"]="__bshr", ["== 1"]="__eq", ["< 1"]="__lt", - ["<= 1"]="__le", ["set 1 = 2"]="__newindex", ["length"]="__len", - ["__ipairs"]="__ipairs", ["__pairs"]="__pairs", + ["<= 1"]="__le", ["set 1 = 2"]="__newindex", ["size"]="__len", + ["iterate"]="__ipairs", ["iterate all"]="__pairs", } for stub,metamethod in pairs(metamethod_map) do class[metamethod] = class[stub:as_lua_id()] @@ -111,8 +116,3 @@ compile [object %classname extends %parent %class_body] to: parse [object %classname %class_body] as (..) object %classname extends (nil) %class_body -parse [%obj is a %class] as (..) - all of [..] - (type of %obj) == "table" - %obj's metatable - (%obj's metatable).__index == %class diff --git a/nomnom/ast.nom b/nomnom/ast.nom new file mode 100644 index 0000000..2d5a894 --- /dev/null +++ b/nomnom/ast.nom @@ -0,0 +1,88 @@ +use "lib/object.nom" + +#%types = [..] + "Number", "Var", "Block", "EscapedNomsu", "Text", "List", "Dict", "DictEntry", + "IndexChain", "Action", "FileChunks", "Error", "Comment" + +object (Syntax Tree): + my action [set up]: + if (%me.type == "Action"): + %stub_bits = [] + %argnum = 1 + for %bit in %me: + if: + (%bit is text): %stub_bits::add %bit + (%bit.type != "Comment"): + %stub_bits::add "\%argnum" + %argnum += 1 + %me.stub = (%stub_bits::joined with " ") + + (Syntax Tree).source_code_for_tree = (..) + {} with fallback % -> (read file %.source.filename) + + my action [children]: + %children = [] + for % in %me: + if ((% is a "Syntax Tree") and (%.type != "Comment")): + %children::add % + if ((%me.type == "Action") and %me.target): + %children::add %me.target + return %children + + my action [as lua] (..) + "Syntax_Tree(\(call ({}'s metatable).as_lua with [%me]))" + + my action [as nomsu] (..) + "(Syntax Tree \(call ({}'s metatable).as_nomsu with [%me]))" + + my action [as text] (..) + "(Syntax Tree \(call ({}'s metatable).__tostring with [%me]))" + + my action [get source code] (..) + (Syntax Tree).source_code_for_tree.%me + + my action [map %fn]: + %replacement = (call %fn with [%me]) + if %replacement: + if (%replacement is a "Syntax Tree"): + %replacement = (%k = %v for %k = %v in %replacement) + %replacement.source = %me.source + return (Syntax Tree %replacement) + return %replacement + ..else: + %replacement = {} + %changes = (no) + for %k = %v in %me: + %replacement.%k = %v + if (%v is a "Syntax Tree"): + %r = (%v::map %fn) + if ((%r == %v) or (%r == (nil))): + do next %k + %changes = (yes) + %replacement.%k = %r + unless %changes: return %me + return (Syntax Tree %replacement) + + my action [== %other]: + unless (..) + all of [..] + (type of %me) == (type of %other) + (%me's metatable) == (%other's metatable) + (size of %me) == (size of %other) + %me.type == %other.type + ..: return (no) + + for %item in %me at %i: + if (%other.%i != %item): return (no) + if (%me.type == "Action"): + if (%me.target != %other.target): return (no) + return (yes) + + my action [get args]: + assume (%me.type == "Action") or barf "Only actions have arguments, not \(%me.type)" + %args = [] + for % in %me: + unless ((% is text) or (%.type == "Comment")): + %args::add % + return %args + diff --git a/nomnom/code_obj.nom b/nomnom/code_obj.nom new file mode 100644 index 0000000..4df312e --- /dev/null +++ b/nomnom/code_obj.nom @@ -0,0 +1,180 @@ +# This file contains objects that are used to track code positions and incrementally + build up generated code, while keeping track of where it came from, and managing + indentation levels. + +use "lib/object.nom" + +object (Code): + my action [set up]: + %old_bits = %me.bits + %me.bits = [] + if (%me.source is text): + %me.source = (Source from text %me.source) + for % in %old_bits: + %me::add % + + my action [as text]: + if (%me.__str == (nil)): + set {%buff:[], %indent:0} + for % in %me.bits: + if (% is text): + %spaces = (%::matching "\n([ ]*)[^\n]*$") + if %spaces.1: %indent = (size of %spaces) + ..else: + % = "\%" + if (%indent > 0): + % = (%::with "\n" -> "\n\(" "::* %indent)") + %buff::add % + %me.__str = (%buff::joined) + return %me.__str + + my action [as lua] (..) + "\(%me.class.name::as lua id)_1_2(\(%me.source::as lua), \(%me.bits::as lua))" + + my action [as nomsu] (..) + "(\(%me.class.name) \(%me.source::as nomsu) \(%me.bits::as nomsu))" + + my action [size] (size of "\%me") + + my action [mark as dirty]: + %me.__str = (nil) + %me._trailing_line_len = (nil) + %me._num_lines = (nil) + + my action [add %new_bits]: + unless (%new_bits is a "List"): + %new_bits = [%new_bits] + for % in %new_bits: + if (% == ""): do next % + if ((% isn't text) and (% isn't a (Code))): + % = (%::as lua) + %me.bits::add % + %me::mark as dirty + + my action [trailing line length]: + if (%me._trailing_line_len == (nil)): + %me._trailing_line_len = (size of ("\%me"::matching "[^\n]*$")) + return %me._trailing_line_len + + my action [number of lines]: + unless %me._num_lines: + %num_lines = 1 + for % in %me: + if (% is text): + %num_lines += (size of (%::all matches of "\n")) + ..else: + %num_lines += ((%::number of lines) - 1) + %me._num_lines = %num_lines + return %me._num_lines + + my action [is multiline, is multi-line] ((%me::number of lines) > 1) + my action [is one line, is single line] ((%me::number of lines) == 1) + + my action [add %values joined with %joiner]: + %me::add %values joined with %joiner or %joiner + + my action [add %values joined with %joiner or %wrapping_joiner]: + %line_len = 0 + %bits = %me.bits + for %i = % in %values: + if (%i > 1): + if (%line_len > 80): + %bits::add %wrapping_joiner + %line_len = 0 + ..else: + %bits::add %joiner + %bits::add % + %line = ("\%"::matching "\n([^\n]*)$") + if %line: + %line_len = (size of %line) + ..else: + %line_len += (size of %) + %me::mark as dirty + + my action [prepend %]: + if ((% isn't text) and (% isn't a %me.__type)): + % = (%::as lua) + %me.bits::add % at index 1 + %me::mark as dirty + + my action [parenthesize]: + %me.bits::add "(" at index 1 + %me.bits::add ")" + %me::mark as dirty + + +object (Lua Code) extends (Code): + my action [add free vars %vars]: + if ((size of %vars) == 0): return + %seen = (%v = (yes) for %v in %me.free_vars) + for %var in %vars: + assume (%var is text) + unless %seen.%var: + %me.free_vars::add %var + %seen.%var = (yes) + %me::mark as dirty + + my action [remove free vars %vars]: + if ((size of %vars) == 0): return + %removals = {} + for %var in %vars: + assume (%var is text) + %removals.%var = (yes) + + %stack = [%me] + while ((size of %stack) > 0): + %lua = (%stack::pop) + for %i in (size of %lua.free_vars) to 1 by -1: + if %removals.(%lua.%free_vars.%i): + %lua.free_vars::remove index %i + for % in %lua.bits: + if (% is a "Lua Code"): + %stack::add % + %me::mark as dirty + + my action [declare locals]: + set {%to_declare:[], %seen:{}} + for %lua in recursive %me: + for %var in %lua.free_vars: + unless %seen.%var: + %seen.%var = (yes) + %to_declare::add %var + for % in %lua.bits: + if (% is a "Lua Code"): + recurse %lua on % + return (%me::declare locals %to_declare) + + my action [declare locals %to_declare]: + if ((size of %to_declare) > 0): + %me::remove free vars %to_declare + %me::prepend "local \(%to_declare::joined with ", ");\n" + return %to_declare + + my action [as statements] (%me::as statements "" ";") + my action [as statements %prefix] (%me::as statements %prefix ";") + my action [as statements %prefix %suffix]: + unless %me.is_value: + return %me + %statements = (Lua Code %me.source []) + if (%prefix != ""): + %statements::add %prefix + %statements::add %me + if (%suffix != ""): + %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:[]} + +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} diff --git a/nomnom/compile.nom b/nomnom/compile.nom new file mode 100644 index 0000000..ec48f05 --- /dev/null +++ b/nomnom/compile.nom @@ -0,0 +1,207 @@ +# This file contains the code to convert syntax trees to Lua code + +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 %tree.type is: + "Action": + %stub = %tree.stub + %compile_action = %compile_actions.%stub + if %compile_action: + %args = [%tree, %compile_actions] + for % in (%tree::get args): %args::add % + %result = (call %compile_action with %args) + if (%result == (nil)): + compile error at %tree.source "\ + ..The compile-time action here (\(%tree.stub)) failed to return any value." + ..hint "\ + ..Look at the implementation of (\(%tree.stub)) and make sure it's returning something." + if (%result is a "Syntax Tree"): + if (%result == %tree): + compile error at %tree.source "\ + ..The compile-time action here (\(%tree.stub)) is producing an endless loop." + ..hint "\ + ..Look at the implementation of (\(%tree.stub)) and make sure it's not just returning the original tree." + return (compile %result using %compile_actions) + return %result + + %lua = (new 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]*$")): + %lua::add [%target_lua, ":"] + ..else: + %lua::add ["(", %target_lua, "):"] + %lua:add [%stub as lua id, "("] + %args = [] + for %tok in %tree: + if (%tok is text): do next %tok + # TODO: maybe translate Lua comments + if (%tok.type == "Comment"): do next %tok + if (%tok.type == "Block"): + %values = (..) + (compile %line using %compile_actions) for %line in %tok + ..unless (%line.type == "Comment") + 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::add %values joined with " and nil or " + %arg_lua::add ")" + ..else: + %arg_lua = (new 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 ""))) + %arg_lua::add ["\n ", %v] + %arg_lua::add "\nend)())" + ..else: + %arg_lua = (compile %tok using %compile_actions) + unless %arg_lua.is_value: + if (%tok.type == "Action"): + compile error at %tok "\ + ..Can't use this as an argument to (\%stub), since it's not \ + ..an expression, it produces: \%arg_lua" + ..hint "\ + ..Check the implementation of (\(%tok.stub)) to see if it \ + ..is actually meant to produce an expression." + ..else: + compile error at %tok "\ + ..Can't use this as an argument to (\%stub), since it's \ + ..not an expression, it produces: \%arg_lua" + %args::add %arg_lua + %lua::add %args joined with ", " + %lua::add ")" + return %lua + + "EscapedNomsu": + return (new Lua Value from %tree ((%tree.1)::as nomsu)) + + "Block": + %lua = (new Lua Code from %tree) + %lua::add (..) + ((compile %line using %compile_actions)::as statements) + ..for %line in %tree + ..joined with "\n" + return %lua + + "Text": + %lua = (new Lua Code from %tree) + %lua_bits = [] + %string_buffer = "" + for % in %tree: + if (% is text): + %string_buffer = "\%string_buffer\%" + do next % + if (%string_buffer != ""): + %lua_bits::add (%string_buffer::as lua) + %string_buffer = "" + %bit_lua = (compile %bit using %compile_actions) + unless %bit_lua.is_value: + 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,")"]) + %lua_bits::add %bit_lua + + if ((%string_buffer != "") or ((size of %lua_bits) == 0)): + %lua_bits::add (%string_buffer::as lua) + + %lua::add %lua_bits joined with ("..") + if ((size of %lua_bits) > 1): + %lua::parenthesize + return %lua + + "List": + %lua = (new 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::add ((compile % using %compile_actions) for % in %tree) joined with ", " or ",\n " + %lua::add "}" + return %lua + + "DictEntry": + set {%key:%tree.1, %value:%tree.2} + %key_lua = (compile %key using %compile_actions) + unless %key_lua.is_value: + compile error at %tree.1 "\ + ..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"])) + 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]) + ("\%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]) + else: + return (new Lua Code from %tree ["[", %key_lua, "]=", %value_lua]) + + "IndexChain": + %lua = (compile %tree.1 using %compile_actions) + unless %lua.is_value: + compile error at %tree.1 "\ + ..Can't index into this, since it's not an expression." + %first_char = "\%lua".1 + if (any of [%first_char == "{", %first_char == "\"", %first_char == "["]): + %lua::parenthesize + + for %i in 2 to (size of %tree): + %key = %tree.%i + %key_lua = (compile %key using %compile_actions) + unless %key_lua.is_value: + compile error at %key "\ + ..Can't use this as an index, since it's not an expression." + %key_lua_str = "\%key_lua" + %lua_id = (%key_lua_str::matching "^['\"]([a-zA-Z_][a-zA-Z0-9_]*)['\"]$") + if: + %lua_id: + %lua::add [".", %lua_id] + (%key_lua_str.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"] + %lua::add ["[ ", %key_lua, " ]"] + else: + %lua::add ["[", %key_lua, "]"] + return %lua + + "Number": + return (new Lua Value from %tree ["\(%tree.1)"]) + + "Var": + return (new Lua Value from %tree [%tree.1::as lua id]) + + "FileChunks": + barf "\ + ..Can't convert FileChunks to a single block of lua, since each chunk's \ + ..compilation depends on the earlier chunks" + + "Comment": + # TODO: implement? + return (new Lua Code from %tree) + + "Error": + barf "Can't compile errors" + + else: + barf "Unknown type: \(%tree.type)" diff --git a/nomnom/decompile.nom b/nomnom/decompile.nom new file mode 100644 index 0000000..27ef406 --- /dev/null +++ b/nomnom/decompile.nom @@ -0,0 +1,339 @@ +# This file contains the code to convert syntax trees to Nomsu code +use "nomnom/code_obj.nom" +use "nomnom/parser.nom" + +# TODO: maybe re-implement the fancy coroutine checker that aborts early if nomsu gets too long +action [decompile %tree inline]: + assume (%tree is a "Syntax Tree") + if %tree.type is: + "Action": + %nomsu = (Nomsu Code from %tree) + if %tree.target: + %target_nomsu = (decompile %tree.target inline) + if %tree.target.type is: + ("Action", "Block"): + %target_nomsu::parenthesize + %nomsu::add [%target_nomsu, "::"] + + for %bit in %tree at %i: + if (%bit is text): + unless (..) + any of [..] + %i == 1, + %tree.(%i - 1) isn't text, + (%bit::is a nomsu operator) == (%tree.(%i - 1)::is a nomsu operator) + ..: %nomsu::add " " + %nomsu::add %bit + ..else: + %arg_nomsu = (decompile %bit inline) + unless ((%i == (size of %tree)) and (%bit.type == "Block")): + %nomsu::add " " + if ((%bit.type == "Action") or (%bit.type == "Block")): + %arg_nomsu::parenthesize + %nomsu::add %arg_nomsu + return %nomsu + + "EscapedNomsu": + %inner_nomsu = (decompile %tree.1 inline) + unless (..) + any of [..] + %tree.1.type == "List", %tree.1.type == "Dict", + %tree.1.type == "Var" + ..: %inner_nomsu::parenthesize + %nomsu = (Nomsu Code from %tree ["\\", %inner_nomsu]) + return %nomsu + + "Block": + %nomsu = (Nomsu Code from %tree [":"]) + for i,line in ipairs tree + %nomsu::add(i == 1 and " " or "; ") + %nomsu::add recurse(line, nomsu, i == 1 or i < #tree) + return %nomsu + + "Text": + %nomsu = (Nomsu Code from %tree ["\""]) + for %text in recursive %tree: + for %bit in %text at %i: + if: + (%bit is text): + %nomsu::add %bit + if %bit.type is: + "Text": + recurse %text on %bit + "Var": + %interp_nomsu = (decompile %bit inline) + # Make sure "...\(%x)y..." isn't confused with "...\(%xy)..." + # TODO: make this more robust against "...\%x\("y").." + if (..) + (%tree.(%i + 1) is text) and (..) + not (%tree.(%i + 1)::matches "^[ \n\t,.:;#(){}%[%]]") + ..: %interp_nomsu::parenthesize + %nomsu::add ["\\", %interp_nomsu] + ("List", "Dict"): + %nomsu::add ["\\", decompile %bit inline] + else: + %nomsu::add ["\\(", decompile %bit inline, ")"] + return (Nomsu Code from %tree ["\"", %nomsu, "\""]) + + ("List", "Dict"): + %nomsu = (Nomsu Code from %tree ["[" if (%tree.type == "List") else "{"]) + for %item in %tree at %i: + if (%i > 1): %nomsu::add ", " + %nomsu::add (decompile %item inline) + %nomsu::add ("]" if (%tree.type == "List") else "}") + return %nomsu + + "DictEntry": + set {%key:%tree.1, %value:%tree.2} + if (all of [%key.type == "Text", (size of %key) == 1, %key.1::is a nomsu identifier]): + %nomsu = (Nomsu Code from %key [key.1]) + ..else: + %nomsu = (decompile %key inline) + + if (%key.type == "Action"): + %nomsu::parenthesize + %nomsu::add ":" + if %value: + %nomsu::add (decompile %value inline) + return %nomsu + + "IndexChain": + %nomsu = (Nomsu Code from %tree) + for %bit in %tree at %i: + if (%i > 1): nomsu::add "." + if (..) + all of [..] + %i > 1, %bit.type == "Text", (size of %bit) == 1, %bit.1 is text, + %bit.1::is a nomsu identifier + %nomsu::add %bit.1 + ..else: + %bit_nomsu = (decompile %bit inline) + if (..) + any of [..] + %bit.type == "Action" + %bit.type == "Block" + %bit.type == "IndexChain" + (%bit.type == "Number") and (%i < (size of %tree)) + ..: %bit_nomsu::parenthesize + %nomsu::add %bit_nomsu + return %nomsu + + "Number": + return (Nomsu Code from %tree [(%tree.1 as hex) if %tree.hex else "\(%tree.1)"]) + + "Var": + return (Nomsu Code from %tree ["%\(%tree.1)"]) + + "Comment": + return (nil) + + "FileChunks": + barf "Can't inline a FileChunks" + + "Error": + barf "Can't compile errors" + + else: + barf "Unknown type: \(%tree.type)" + +%MAX_LINE = 90 +action [decompile %tree]: + %nomsu = (Nomsu Code from %tree) + # For concision: + local action [recurse on %t]: + %space = (%MAX_LINE - (%nomsu::trailing line length)) + if (%space <= 0): go to (Indented) + for %subtree in recursive %tree: + if %subtree.type is: + "Block": + if ((size of %subtree) > 1): + go to (Use Indented) + if ((size of "\(decompile %subtree inline)") > 20): + go to (Use Indented) + for %k = %v in %subtree: + if (%v is a "Syntax Tree"): + recurse %subtree on %v + + %inline_nomsu = (decompile %t inline) + if (%inline_nomsu and ((size of "\%inline_nomsu") <= %space)): + return %inline_nomsu + + === (Use Indented) === + %indented = (decompile %t) + if (%t.type == "Action"): + %indented = (Nomsu Code from %t ["(..)\n ", %indented]) + return %indented + + if %tree.type is: + "FileChunks": + local action [%1 and %2 should clump]: + if ((%1.type == "Action") and (%2.type == "Action")): + if (%1.stub == "use 1"): return (%2.stub == "use 1") + if (%1.stub == "test 1"): return (yes) + if (%2.stub == "test 1"): return (no) + return (not ((recurse on %1)::is multi-line)) + for %chunk in %tree at %chunk_no: + if (%chunk_no > 1): + %nomsu::add "\n\n\("~"::* 80)\n\n" + %nomsu::add (pop comments at %chunk.source.start) + if (%chunk.type == "Block"): + for %line in %chunk at %line_no: + if (%line_no > 1): + if (%chunk.(%line_no - 1) and %line should clump): + %nomsu::add ["\n", pop comments at %line.source.start "\n"] + ..else: + %nomsu::add ["\n\n", pop comments at %line.source.start] + %nomsu::add (decompile %line %pop_comments) + %nomsu::add (pop comments at %chunk.source.stop "\n") + ..else: + %nomsu::add (decompile %chunk %pop_comments) + %nomsu::add (pop comments at %tree.source.stop "\n") + unless ("\%nomsu"::matches "\n$"): + %nomsu::add "\n" + return %nomsu + + "Action": + %pos = %tree.source.start + %next_space = "" + if %tree.target: + %target_nomsu = (recurse on %tree.target) + if ((%tree.target.type == "Action") and (%target_nomsu::is one line)): + %target_nomsu::parenthesize + %nomsu::add %target_nomsu + %pos = %tree.target.source.stop + %next_space = ("\n..::" if (%target_nomsu::is multi-line) else "::") + + for %bit in %tree at %i: + if ((%next_space == " ") and ((%nomsu::trailing line length) > %MAX_LINE)): + %next_space = " \\\n" + + %nomsu::add %next_space + + if (%bit is text): + unless (..) + all of [..] + %tree.(%i - 1) is text + (%tree.(%i - 1)::is a nomsu operator) != (%bit::is a nomsu operator) + ..: %nomsu::add %next_space + %nomsu::add %bit + %next_space = " " + do next %bit + + %bit_nomsu = (recurse on %bit) + if (%bit.type == "Comment"): + %next_space = "\n" + ..else: + %next_space = (" " if (%bit_nomsu::is one line) else "\n..") + if (%bit.type == "Action"): + %bit_nomsu::parenthesize + + return %nomsu + + "EscapedNomsu": + %nomsu::add "\\" + %val_nomsu = (recurse on %tree.1) + if ((%tree.(1).type == "Action") and (%val_nomsu::is one line)): + %val_nomsu::parenthesize + %nomsu::add %val_nomsu + return %nomsu + + "Block": + for %line in %tree at %i: + if ((%i > 1) and (%line.type == "Comment")): + %nomsu::add "\n" + %line_nomsu = (recurse on %line) + %nomsu::add + if (%i < (size of %tree)): + if ((%line_nomsu::number of lines) > 2): + %nomsu::add "\n\n" + ..else: + %nomsu::add "\n" + return (Nomsu Code from %tree [":\n ", %nomsu]) + + "Text": + # Multi-line text has more generous wrap margins + %max_line = ((1.5 * %MAX_LINE) rounded down) + %nomsu = (Nomsu Code from %tree) + local action [add text from %tree]: + for %bit in %tree at %i: + if (%bit is text): + # TODO: escape properly? + %bit = (escape text %bit) + for %line in (%bit::lines) at %j: + if: + (%j > 1): nomsu::add "\n" + (((size of %line) > 10) and ((%nomsu::trailing line length) > %max_line)): + %nomsu::add "\\\n.." + + while ((size of %line) > 0): + %space = (%max_line - (%nomsu::trailing line length)) + %split = (%line::position of "[%p%s]" after %space) + if ((not %split) or (%split > %space + 10)): + %split = (%space + 10) + if ((%line - %split) < 10): + %split = (size of %line) + set {%bite:%line.[1, %split], %line:%line.[%split + 1, -1]} + %nomsu::add %bite + if ((size of %line) > 0): + %nomsu::add "\\\n.." + if (%bit.type == "Text"): + add text from %bit + ..else: + %nomsu::add "\\" + %interp_nomsu = (recurse on %bit) + unless (%interp_nomsu::is multi-line): + if %bit.type is: + "Var": + if ((%tree.(%i+1) is text) and (not (%tree.(%i+1)::matches "^[ \n\t,.:#(){}[%]]"))): + %interp_nomsu::parenthesize + ("List", "Dict"): + %interp_nomsu::parenthesize + %nomsu::add %interp_nomsu + if (%interp_nomsu::is multi-line): + %nomsu::add "\n.." + add text from %tree + return (Nomsu Code from %tree ["\"\\\n ..", %nomsu, "\""]) + + ("List", "Dict"): + if ((size of %tree) == 0): + %nomsu::add ("[]" if (%tree.type == "List") else "{}") + return %nomsu + for %item in %tree at %i: + %item_nomsu = (decompile %item inline) + if ((not %item_nomsu) or ((size of "\%item_nomsu") > %MAX_LINE)): + %item_nomsu = (recurse on %item_nomsu) + %nomsu::add %item_nomsu + if (%i < (size of %tree)): + if (..) + (%item_nomsu::is multi-line) or (..) + (%nomsu::trailing line length) + (size of "\%item_nomsu")) >= %MAX_LINE + ..: %nomsu::add "\n" + ..else: %nomsu::add ", " + return (..) + Nomsu Code from %tree [..] + "[..]\n " if tree.type == "List" else "{..}\n " + %nomsu + + "DictEntry": + set {%key:%tree.1, %value:%tree.2} + if (all of [%key.type == "Text", (size of %key) == 1, %key.1::is a nomsu identifier]): + %nomsu::add %key.1 + ..else: + %nomsu::add (decompile %key inline) + if ((%key.type == "Action") or (%key.type == "Block")): + %nomsu::parenthesize + %nomsu::add [": ", recurse on %value] + return %nomsu + + "Comment": + %nomsu::add ["#", %tree.1::with "\n" -> "\n "] + return %nomsu + + ("IndexChain", "Number", "Var"): + return (decompile %tree inline) + + "Error": + barf "Cannot decompile an error" + + else: + barf "Unknown type: \(%tree.type)" diff --git a/nomnom/files.nom b/nomnom/files.nom new file mode 100644 index 0000000..8fd8f24 --- /dev/null +++ b/nomnom/files.nom @@ -0,0 +1,123 @@ +# Some file utilities for searching for files recursively and using package.nomsupath +use "lib/os.nom" + +%_SPOOFED_FILES = {} +%_FILE_CACHE = ({} with fallback %_SPOOFED_FILES) +%_BROWSE_CACHE = {} + +# Create a fake file and put it in the cache +action [spoof file %filename %contents]: + %_SPOOFED_FILES.%filename = %contents + return %contents + +# Read a file's contents +action [read file %filename]: + %contents = %_FILE_CACHE.%filename + if %contents: return %contents + if (%filename == "stdin"): + return (spoof file "stdin" (=lua "io.read('*a')")) + %file = (=lua "io.open(\%filename)") + unless %file: return (nil) + %contents = (call %file.read with [%file, "*a"]) + %file::close + %_FILE_CACHE.%filename = %contents + return %contents + +action [%path sanitized]: + %path = (%path::with "\\" -> "\\\\") + %path = (%path::with "`" -> "") + %path = (%path::with "\"" -> "\\\"") + %path = (%path::with "$" -> "") + %path = (%path::with "%.%." -> "\\..") + return %path + +try: + %lfs = (=lua "require('lfs')") +..and if it succeeds: + local action [filesystem has %filename]: + %mode = (call %lfs.attributes with [%filename, "mode"]) + if %mode is: + ("file", "directory", "link", "char device"): + return (yes) + else: return (no) + + action [file %path exists]: + if (..) + any of [..] + %_SPOOFED_FILES.%path + %path == "stdin" + filesystem has %path + ..: return (yes) + for %nomsupath in (%package.nomsupath::all matches of "[^;]+"): + if (filesystem has "\%nomsupath/\%path"): + return (yes) + return (no) + + action [files in %path]: + unless %_BROWSE_CACHE.%path: + if (%_SPOOFED_FILES.%path or (%filename == "stdin")): + %_BROWSE_CACHE.%path = [%path] + ..else: + if (call %lfs.attributes with [%filename, "mode"]) is: + ("file", "char device"): + %_BROWSE_CACHE.%path = [%filename] + ("directory", "link"): + for %nomsupath in (%package.nomsupath::all matches of "[^;]+"): + %files = [] + for %member in (call %lfs.dir with ["\%nomsupath/\%filename"]): + if ((%member == ".") or (%member == "..")): + do next %member + for % in (files in %member): %files::add % + if ((size of %files) > 0): + %_BROWSE_CACHE.%path = %files + go to (Found Files) + + %_BROWSE_CACHE.%path = [] + else: + %_BROWSE_CACHE.%path = [] + + === (Found Files) === + return %_BROWSE_CACHE.%filename + +..or if it barfs: + # LFS not found! Fall back to shell commands, if available. + unless (sh> "find . -maxdepth 0"): + url = if jit + 'https://github.com/spacewander/luafilesystem' + else + barf "\ + ..Could not find 'luafilesystem' module and couldn't run system command 'find' \ + ..(this might happen on Windows). Please install 'luafilesystem' (which can be \ + ..found at \(..) + "https://github.com/spacewander/luafilesystem" + ..if %jit else "https://github.com/keplerproject/luafilesystem" + .. or obtained through `luarocks install luafilesystem`)" + + + action [file %path exists]: + if (..) + any of [..] + %_SPOOFED_FILES.%path + %path == "stdin" + sh> "ls \(%path sanitized)" + ..: return (yes) + for %nomsupath in (%package.nomsupath::all matches of "[^;]+"): + if (sh> "ls \(%nomsupath)/\(%path)"): + return (yes) + return (no) + + action [files in %path]: + unless %_BROWSE_CACHE.%path: + if %_SPOOFED_FILES.%path: + %_BROWSE_CACHE.%path = [%_SPOOFED_FILES.%path] + ..else: + for %nomsupath in (%package.nomsupath::all matches of "[^;]+"): + %files = (sh> "find -L '\%path' -not -path '*/\\.*' -type f'") + if %files: + %_BROWSE_CACHE.%path = (%files::lines) + go to (Found Files) + %_BROWSE_CACHE.%path = [] + + === (Found Files) === + return %_BROWSE_CACHE.%path + diff --git a/nomnom/parser.nom b/nomnom/parser.nom new file mode 100644 index 0000000..60c356f --- /dev/null +++ b/nomnom/parser.nom @@ -0,0 +1,81 @@ +# This file contains the parser, which converts text into abstract syntax trees +use "nomonom/ast.nom" + +%lpeg = (=lua "require('lpeg')") +%re = (=lua "require('re')") +call %lpeg.setmaxstack with [20_000] +set {..} + (action (P 1)): %lpeg.P, (action (R 1)): %lpeg.R, (action (Carg 1)): %lpeg.Carg, + (action (Cc 1)): %lpeg.Cc, (action (lpeg re pattern 1)): %re.compile, + (action (lpeg re pattern 1 using 2)): %re.compile + +%source_code_for_tree = {} +%defs = (..) + {..} + nl: (P "\r")^(-1) * (P "\n") + tab: P "\t" + tonumber: %tonumber + tochar: %string.char + unpack: %unpack + nil: Cc (nil) + userdata: Carg 1 + utf8_char: (..) + (R "\194\223")*(R "\128\191") + + (R "\224\239")*(R "\128\191")*(R "\128\191") + + (R "\240\244")*(R "\128\191")*(R "\128\191")*(R "\128\191") + + Tree: [%t, %userdata] ->: + %source = (..) + Source {filename:%userdata.filename, start:%tree.start, stop:%tree.stop} + set {%t.start: nil, %t.stop: nil} + %t = (Syntax Tree %t) + (Syntax Tree).source_code_for_tree.%t = %userdata.source + return %t + + ..with fallback %key ->: + if: + (%key::matches "^ascii_(%d+)$"): + %i = (%key::matching "^ascii_(%d+)$") + return (call %string.char with [%i as a number]) + (%key::matches "^number_(%d+)$"): + %i = (%key::matching "^number_(%d+)$") + return (Cc (%i as a number)) + +%id_patt = (((P "") - (R "09")) * ((%defs.utf8_char + (R "az") + (R "AZ") + (P "_") + (R "09"))^1 * -1)) +%operator_patt = ((S "'`~!@$^&*+=|<>?/-")^1 * -1) +%text_methods = (""'s metatable).__index +%text_methods.(action (is a nomsu identifier)) = (..) + [%str] -> (call %id_patt.match with [%id_patt, %str]) +%text_methods.(action (is a nomsu id)) = %text_methods.(action (is a nomsu identifier)) +%text_methods.(action (is a nomsu operator)) = (..) + [%str] -> (call %operator_patt.match with [%operator_patt, %str]) + +%peg_tidier = (..) + lpeg re pattern "\ + file <- %nl* {~ (def/comment) (%nl+ (def/comment))* %nl* ~} + def <- anon_def / captured_def + anon_def <- + ({ident} (" "*) ":" {[^%nl]* (%nl+ " "+ [^%nl]*)*}) + -> "%1 <- %2" + captured_def <- + ({ident} (" "*) "(" {ident} ")" (" "*) ":" {[^%nl]* (%nl+ " "+ [^%nl]*)*}) + -> "%1 <- ({| {:start:{}:} %3 {:stop:{}:} {:type: (''->'%2') :} |} %%userdata) -> Tree" + ident <- [a-zA-Z_][a-zA-Z0-9_]* + comment <- "--" [^%nl]* + " + +action [make parser from %peg] (make parser from %peg using (nil)) + +action [make parser from %peg using %make_tree]: + %peg = (call %peg_tidier.match with [%peg_tidier, %peg]) + %peg = (lpeg re pattern %peg using %defs) + local action [parse %input from %filename]: + %input = "\%input" + %tree_mt = {__index: {source:%input, filename:%filename}} + %userdata = {..} + make_tree: %make_tree or ([%]-> (: set %'s metatable to %tree_mt; return %)) + filename:%filename, source:%input + %tree = (call %peg.match with [%peg, %input, (nil), %userdata]) + assume %tree or barf "File \%filename failed to parse:\n\%input" + return %tree + return (action (parse 1 from 2)) diff --git a/nomnom/pretty_errors.nom b/nomnom/pretty_errors.nom new file mode 100644 index 0000000..732f3b9 --- /dev/null +++ b/nomnom/pretty_errors.nom @@ -0,0 +1,75 @@ +# This file has code for converting errors to user-friendly format, with colors, + line numbers, code excerpts, and so on. + +local action [visible size of %text]: + return (size of (%text::with "\027%[[0-9;]*m" -> "")) + +local action [boxed %text]: + %max_line = (..) + max of ((visible size of %line) for %line in (%text::lines)) + %ret = (..) + "\n\%text"::with "\n([^\n]*)" as % -> (..) + "\n\%\(" "::* (%max_line - (visible size of %))) \027[0m" + return %ret.[2,-1] + +action [%err as a pretty error]: + %context = 2 + %err_code = (%err::get source code) + %err_line = (%err_code::line at %err.source.start) + %err_linenum = (%err_code::line number at %err.source.start) + %err_linepos = (%err_code::line position at %err.source.start) + # TODO: better handle multi-line errors + %err_size = (..) + min of [..] + %err.source.stop - %err.source.start + (size of %err_line) - %err_linepos + 1 + %nl_indicator = (" " if (%err_linepos > (size of %err_line)) else "") + %fmt_str = " %\(size of "\(%err_linenum + %context)")d|" + local action [num %i] (%fmt_str::formatted with 0) + %linenum_size = (size of (num 0)) + + %pointer = "\(" "::* (%err_linepos + %linenum_size - 1))" + if (%err_size >= 2): + %pointer += "\(%pointer)╚\("═"::* (%err_size - 2))╝" + ..else: + %pointer += "\(%pointer)⬆" + + %err_msg = "\027[33;41;1m\(%err.title or "Error") at \(%err.source.filename or "???"):\(%err_linenum)\027[0m" + for %i in (%err_linenum - %context) to (%err_linenum - 1): + %line = (%err_code::line %i) + if %line: + %err_msg += "\n\027[2m\(num %i)\027[0m\(%line)\027[0m" + if %err_line: + %before = %err_line.[1, %err_linepos - 1] + %during = %err_line.[%err_linepos, %err_linepos + %err_size - 1] + %after = %err_line.[%err_linepos + %err_size, -1] + %err_line = "\027[0m\(%before)\027[41;30m\(%during)\(%nl_indicator)\027[0m\(%after)" + %err_msg += "\n\027[2m\(%fmt_str::formated with %err_linenum)\(%err_line)\027[0m" + %err_linenum_end = (%err_code::line number at %err.source.stop) + %err_linepos_end = (%err_code::line position at %err.source.stop) + %err_linenum_end or= %err_linenum + if (%err_linenum_end == %err_linenum): + %err_msg += "\n\(%pointer)" + ..else: + for %i in (%err_linenum + 1) to %err_linenum_end: + %line = (%err_code::line %i) + if %line: + if (%i == %err_linenum_end): + %during = %line.[1, %err_linepos_end - 1] + %after = %line.[%err_linepos_end, -1] + %err_msg += "\n\027[2m\(num %i)\027[0;41;30m\(%during)\027[0m\(%after)" + ..else: + %err_msg += "\n\027[2m\(num %i)\027[0;41;30m\(%line)\027[0m" + + %box_width = 70 + %err_text = "\ + ..\027[47;31;1m\((" \(%err.error)"::wrapped to %box_width)::with "\n" -> "\n\027[47;31;1m ")" + if %err.hint: + err_text += "\n\027[47;30m\((" Suggestion: \(%err.hint)"::wrapped to %box_width)::with "\n" -> "\n\027[47;30m ")" + %err_msg += "\n\027[33;1m \((%err_text boxed) with "\n" -> "\n ")" + + for %i in (%err_linenum_end + 1) to (%err_linenum_end + %context): + %line = (%err_code::line %i) + if %line: + %err_msg += "\n\027[2m\(num %i)\027[0m\(%line)\027[0m" + return %err_msg diff --git a/nomnom/source.nom b/nomnom/source.nom new file mode 100644 index 0000000..e05b314 --- /dev/null +++ b/nomnom/source.nom @@ -0,0 +1,49 @@ +use "lib/object.nom" + +object (Source): + action [Source from text %text]: + %match = (%text::matching groups "^@(.-)%[(%d+):(%d+)%]$") + set {%filename:%match.1, %start:%match.2, %stop:%match.3} + unless %filename: + %match = (%text::matching groups "^@(.-)%[(%d+)%]$") + set {%filename:%match.1, %start:%match.2} + return (Source {filename:%filename, start:(%start or 1) as number, stop: %stop as number}) + + my action [as text] "\ + ..@\(%me.filename)[\(%me.start)\(":\(%me.stop)" if %me.stop else "")]" + + my action [as lua] "\ + ..Source{filename=\(%me.filename::as lua), start=\(%me.start)\ + ..\(", stop=\(%me.stop)" if %stop else "")}" + + my action [as nomsu] "\ + ..(Source {filename:\(%me.filename::as nomsu), start:\(%me.start)\ + ..\(", stop:\(%me.stop)" if %stop else "")})" + + my action [== %other] (..) + all of [..] + (%me's metatable) == (%other's metatable) + %me.filename == %other.filename + %me.start == %other.start + %me.stop == %other.stop + + my action [< %other]: + assume %me.filename == %other.filename + if (%start == %other.start): + return ((%me.stop or %me.start) < (%other.stop or %other.start)) + ..else: + return (%me.start < %other.start) + + my action [<= %other]: + assume %me.filename == %other.filename + if (%start == %other.start): + return ((%me.stop or %me.start) <= (%other.stop or %other.start)) + ..else: + return (%me.start <= %other.start) + + my action [+ %offset]: + if ((type of %me) == "number"): + set {%me:%offset, %offset:%me} + ..else: + assume (type of %offset) == "number" + return (Source {filename:%me.filename, start:%me.start + %offset, stop:%me.stop}) diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon index 0718bca..34c2ab0 100644 --- a/nomsu_compiler.moon +++ b/nomsu_compiler.moon @@ -99,7 +99,7 @@ with NomsuCompiler :next, :unpack, :setmetatable, :coroutine, :rawequal, :getmetatable, :pcall, :error, :package, :os, :require, :tonumber, :tostring, :string, :xpcall, :module, :print, :loadfile, :rawset, :_VERSION, :collectgarbage, :rawget, :rawlen, - :table, :assert, :dofile, :loadstring, :type, :select, :math, :io, :load, + :table, :assert, :dofile, :loadstring, lua_type_of_1:type, :select, :math, :io, :load, :pairs, :ipairs, -- Nomsu types: _List:List, _Dict:Dict, diff --git a/string2.moon b/string2.moon index 662cd0d..1b0037f 100644 --- a/string2.moon +++ b/string2.moon @@ -13,8 +13,10 @@ isplit = (sep='%s+')=> return step, {str:@, pos:1, :sep}, 0 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 } string2 = { @@ -76,24 +78,19 @@ string2 = { 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 = gsub str, "^_*%d", "_%1" - -- This pattern is guaranteed to match all keywords, but also matches some other stuff. - if match str, "^_*[abdefgilnortuw][aefhilnoru][acdefiklnoprstu]*$" - for kw in *lua_keywords - if match str, ("^_*"..kw.."$") - str = "_"..str + + unless string2.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)-> - -- This pattern is guaranteed to match all keywords, but also matches some other stuff. - if match str, "^_+[abdefgilnortuw][aefhilnoru][acdefiklnoprstu]*$" - for kw in *lua_keywords - if match str, ("^_+"..kw.."$") - str = str\sub(2,-1) - str = gsub(str, "^_(_*%d.*)", "%1") + unless string2.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))) str = gsub(str, "^ ([ ]*)$", "%1") -- cgit v1.2.3 From 28d0792e69bbb9c467c616eb3dc89a60085c35f2 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Fri, 21 Sep 2018 00:30:53 -0700 Subject: Rebuild. --- containers.lua | 21 ++++++++++++++++++--- nomsu_compiler.lua | 2 +- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/containers.lua b/containers.lua index a7819ec..d31c786 100644 --- a/containers.lua +++ b/containers.lua @@ -353,13 +353,17 @@ do reverse, upper, lower, find, byte, match, gmatch, gsub, sub, format, rep = _obj_0.reverse, _obj_0.upper, _obj_0.lower, _obj_0.find, _obj_0.byte, _obj_0.match, _obj_0.gmatch, _obj_0.gsub, _obj_0.sub, _obj_0.format, _obj_0.rep end local string2 = require('string2') - local lines, line, line_at, as_lua_id - lines, line, line_at, as_lua_id = string2.lines, string2.line, string2.line_at, string2.as_lua_id + local lines, line, line_at, as_lua_id, is_lua_id + lines, line, line_at, as_lua_id, is_lua_id = string2.lines, string2.line, string2.line_at, string2.as_lua_id, string2.is_lua_id local text_methods = { formatted_with_1 = format, byte_1 = byte, position_of_1 = find, position_of_1_after_2 = find, + as_a_lua_identifier = as_lua_id, + is_a_lua_identifier = is_lua_id, + as_a_lua_id = as_lua_id, + is_a_lua_id = is_lua_id, bytes_1_to_2 = function(self, start, stop) return List({ byte(tostring(self), start, stop) @@ -403,10 +407,18 @@ do matches_1 = function(self, patt) return match(self, patt) and true or false end, + matching_1 = function(self, patt) + return (match(self, patt)) + end, + matching_groups_1 = function(self, patt) + return { + match(self, patt) + } + end, [as_lua_id("* 1")] = function(self, n) return rep(self, n) end, - matching_1 = function(self, patt) + all_matches_of_1 = function(self, patt) local result = { } local stepper, x, i = gmatch(self, patt) while true do @@ -434,6 +446,9 @@ do return text_methods[i] end end + getmetatable("").__add = function(self, x) + return tostring(self) .. tostring(x) + end end return { List = List, diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua index 89d247a..870be9a 100644 --- a/nomsu_compiler.lua +++ b/nomsu_compiler.lua @@ -184,7 +184,7 @@ do assert = assert, dofile = dofile, loadstring = loadstring, - type = type, + lua_type_of_1 = type, select = select, math = math, io = io, -- cgit v1.2.3 From 692fae5416ce1f2702b599ffb27b2e3d2235eba7 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Wed, 26 Sep 2018 12:45:08 -0700 Subject: 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 -- cgit v1.2.3 From b43432e647fbb3bb76aa2836e3899d5e407c50f9 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Wed, 26 Sep 2018 13:05:28 -0700 Subject: Fixed all syntax errors, got original (non-nomnom) tests passing. --- containers.lua | 2 ++ containers.moon | 2 ++ core/control_flow.nom | 21 +++++++++++++-------- core/metaprogramming.nom | 6 +++--- lib/object.nom | 2 +- nomnom/compile.nom | 2 +- nomnom/decompile.nom | 21 +++++++++++---------- nomnom/files.nom | 3 --- nomnom/parser.nom | 4 ++-- 9 files changed, 35 insertions(+), 28 deletions(-) diff --git a/containers.lua b/containers.lua index 682932f..2018581 100644 --- a/containers.lua +++ b/containers.lua @@ -48,6 +48,7 @@ as_lua = function(self) return error("Not supported: " .. tostring(self)) end local _list_mt = { + __type = "List", __eq = equivalent, __tostring = function(self) return "[" .. concat((function() @@ -231,6 +232,7 @@ walk_items = function(self, i) end end local _dict_mt = { + __type = "Dict", __eq = equivalent, __len = size, __tostring = function(self) diff --git a/containers.moon b/containers.moon index 8a7d7fa..f8f678c 100644 --- a/containers.moon +++ b/containers.moon @@ -26,6 +26,7 @@ as_lua = => -- List and Dict classes to provide basic equality/tostring functionality for the tables -- used in Nomsu. This way, they retain a notion of whether they were originally lists or dicts. _list_mt = + __type: "List" __eq:equivalent -- Could consider adding a __newindex to enforce list-ness, but would hurt performance __tostring: => @@ -96,6 +97,7 @@ walk_items = (i)=> return i, Dict{key:k, value:v} _dict_mt = + __type: "Dict" __eq:equivalent __len:size __tostring: => diff --git a/core/control_flow.nom b/core/control_flow.nom index c496d18..a3814b7 100644 --- a/core/control_flow.nom +++ b/core/control_flow.nom @@ -72,6 +72,8 @@ compile [..] end end)())" +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + # GOTOs test: %i = 0 @@ -84,9 +86,10 @@ test: unless (%i == 0): go to (Loop) assume (%i == 0) compile [=== %label ===, --- %label ---, *** %label ***] to (..) - Lua "::label_\(%label as lua identifier)::" + Lua "::label_\((%label.stub if (%label.type == "Action") else %label) as lua identifier)::" -compile [go to %label] to (Lua "goto label_\(%label as lua identifier)") +compile [go to %label] to (..) + Lua "goto label_\((%label.stub if (%label.type == "Action") else %label) as lua identifier)" # Basic loop control compile [do next] to (Lua "goto continue") @@ -165,13 +168,15 @@ compile [repeat %n times %body] to: return %lua # For loop control flow -compile [stop %var] to (Lua "goto stop_\(%var as lua identifier)") -compile [do next %var] to (Lua "goto continue_\(%var as lua identifier)") +compile [stop %var] to (..) + Lua "goto stop_\((%var.stub if (%var.type == "Action") else %var) as lua identifier)" +compile [do next %var] to (..) + Lua "goto continue_\((%var.stub if (%var.type == "Action") else %var) as lua identifier)" compile [===stop %var ===, ---stop %var ---, ***stop %var ***] to (..) - Lua "::stop_\(%var as lua identifier)::" + Lua "::stop_\((%var.stub if (%var.type == "Action") else %var) as lua identifier)::" compile [===next %var ===, ---next %var ---, ***next %var ***] to (..) - Lua "::continue_\(%var as lua identifier)::" + Lua "::continue_\((%var.stub if (%var.type == "Action") else %var) as lua identifier)::" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -516,11 +521,11 @@ test: %t = [1, [2, [[3], 4], 5, [[[6]]]]] %flat = [] for % in recursive %t: - if ((type of %) is "table"): + if ((lua type of %) is "table"): for %2 in %: recurse % on %2 ..else: %flat::add % - assume ((sorted %flat) == [1, 2, 3, 4, 5, 6]) + assume (sorted %flat) == [1, 2, 3, 4, 5, 6] # Recurion control flow compile [for %var in recursive %structure %body] to (..) diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom index 8b75ccd..f92fb0c 100644 --- a/core/metaprogramming.nom +++ b/core/metaprogramming.nom @@ -236,7 +236,7 @@ action [%var as lua identifier, %var 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_1_2(\%var, "This is not a valid Lua identifier.") + nomsu:compile_error(\%var, "This is not a valid Lua identifier.") end return lua else error("Unknown type: "..tostring(\%var)) @@ -322,7 +322,7 @@ test: compile [quote %s] to (Lua value "tostring(\(%s as lua expr)):as_lua()") test: - assume (lua type of {}) == "Lua table" + assume (lua type of {}) == "table" assume (type of {}) == "Dict" assume ({} is a "Dict") assume ("" is text) @@ -341,7 +341,7 @@ action [type of %]: else return lua_type end" parse [% is a %type, % is an %type] as ((type of %) == %type) parse [% isn't a %type, % isn't an %type, % is not a %type, % is not an %type] -..as ((type of %) == %type) +..as ((type of %) != %type) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/lib/object.nom b/lib/object.nom index 65da2a1..25ff644 100644 --- a/lib/object.nom +++ b/lib/object.nom @@ -80,9 +80,9 @@ compile [object %classname extends %parent %class_body] to: Lua "\ ..do local class = {name=\(quote %classname.stub)} + class.__type = class.name setmetatable(class, { __index=\(%parent as lua expr), - __type=class.name, __tostring=function(cls) return cls.name end, __call=function(cls, inst) inst = setmetatable(inst or {}, cls) diff --git a/nomnom/compile.nom b/nomnom/compile.nom index ff3b71f..43e6d84 100644 --- a/nomnom/compile.nom +++ b/nomnom/compile.nom @@ -140,7 +140,7 @@ 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 (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." diff --git a/nomnom/decompile.nom b/nomnom/decompile.nom index 27ef406..0d8d4d2 100644 --- a/nomnom/decompile.nom +++ b/nomnom/decompile.nom @@ -45,9 +45,10 @@ action [decompile %tree inline]: "Block": %nomsu = (Nomsu Code from %tree [":"]) - for i,line in ipairs tree - %nomsu::add(i == 1 and " " or "; ") - %nomsu::add recurse(line, nomsu, i == 1 or i < #tree) + for %line in %tree at %i: + %nomsu::add [..] + " " if (%i == 1) else "; " + decompile %line inline return %nomsu "Text": @@ -100,12 +101,12 @@ action [decompile %tree inline]: "IndexChain": %nomsu = (Nomsu Code from %tree) for %bit in %tree at %i: - if (%i > 1): nomsu::add "." + if (%i > 1): %nomsu::add "." if (..) all of [..] %i > 1, %bit.type == "Text", (size of %bit) == 1, %bit.1 is text, %bit.1::is a nomsu identifier - %nomsu::add %bit.1 + ..:%nomsu::add %bit.1 ..else: %bit_nomsu = (decompile %bit inline) if (..) @@ -261,7 +262,7 @@ action [decompile %tree]: %bit = (escape text %bit) for %line in (%bit::lines) at %j: if: - (%j > 1): nomsu::add "\n" + (%j > 1): %nomsu::add "\n" (((size of %line) > 10) and ((%nomsu::trailing line length) > %max_line)): %nomsu::add "\\\n.." @@ -304,14 +305,14 @@ action [decompile %tree]: %item_nomsu = (recurse on %item_nomsu) %nomsu::add %item_nomsu if (%i < (size of %tree)): - if (..) - (%item_nomsu::is multi-line) or (..) - (%nomsu::trailing line length) + (size of "\%item_nomsu")) >= %MAX_LINE + if any of [..] + %item_nomsu::is multi-line + ((%nomsu::trailing line length) + (size of "\%item_nomsu")) >= %MAX_LINE ..: %nomsu::add "\n" ..else: %nomsu::add ", " return (..) Nomsu Code from %tree [..] - "[..]\n " if tree.type == "List" else "{..}\n " + "[..]\n " if (%tree.type == "List") else "{..}\n " %nomsu "DictEntry": diff --git a/nomnom/files.nom b/nomnom/files.nom index 8fd8f24..a17ec85 100644 --- a/nomnom/files.nom +++ b/nomnom/files.nom @@ -82,9 +82,6 @@ try: ..or if it barfs: # LFS not found! Fall back to shell commands, if available. unless (sh> "find . -maxdepth 0"): - url = if jit - 'https://github.com/spacewander/luafilesystem' - else barf "\ ..Could not find 'luafilesystem' module and couldn't run system command 'find' \ ..(this might happen on Windows). Please install 'luafilesystem' (which can be \ diff --git a/nomnom/parser.nom b/nomnom/parser.nom index 60c356f..1f460bd 100644 --- a/nomnom/parser.nom +++ b/nomnom/parser.nom @@ -21,8 +21,8 @@ set {..} userdata: Carg 1 utf8_char: (..) (R "\194\223")*(R "\128\191") + - (R "\224\239")*(R "\128\191")*(R "\128\191") + - (R "\240\244")*(R "\128\191")*(R "\128\191")*(R "\128\191") + ..(R "\224\239")*(R "\128\191")*(R "\128\191") + + ..(R "\240\244")*(R "\128\191")*(R "\128\191")*(R "\128\191") Tree: [%t, %userdata] ->: %source = (..) -- cgit v1.2.3 From dcff9ecfcf0c3f81cc22bacd082472ea744c9070 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Wed, 26 Sep 2018 13:57:13 -0700 Subject: Fix for calling function with non-literal list. --- core/metaprogramming.nom | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom index f92fb0c..00151d5 100644 --- a/core/metaprogramming.nom +++ b/core/metaprogramming.nom @@ -91,7 +91,11 @@ lua> "\ compile [call %fn with %args] to: lua> "\ ..local lua = LuaCode.Value(tree.source, nomsu:compile(\%fn), "(") - lua:concat_append(table.map(\%args, function(a) return nomsu:compile(a) end), ", ") + if \%args.type == 'List' then + lua:concat_append(table.map(\%args, function(a) return nomsu:compile(a) end), ", ") + else + lua:append('unpack(', nomsu:compile(\%args), ')') + end lua:append(")") return lua" -- cgit v1.2.3 From 8a8940c9bcacfd8bcb6c724a383c75615acd3af8 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Wed, 26 Sep 2018 13:58:29 -0700 Subject: Fixes for actions with targets colliding with compiler actions, and lua keywords as dict keys. --- nomsu_compiler.lua | 68 +++++++++++++++++++++++++---------------------------- nomsu_compiler.moon | 9 +++---- 2 files changed, 37 insertions(+), 40 deletions(-) diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua index 870be9a..ff923ab 100644 --- a/nomsu_compiler.lua +++ b/nomsu_compiler.lua @@ -687,38 +687,36 @@ do local _exp_0 = tree.type if "Action" == _exp_0 then local stub = tree.stub - do - local compile_action = compile_actions[stub] - if compile_action then - local args - do - local _accum_0 = { } - local _len_0 = 1 - for _index_0 = 1, #tree do - local arg = tree[_index_0] - if type(arg) ~= "string" then - _accum_0[_len_0] = arg - _len_0 = _len_0 + 1 - end + local compile_action = compile_actions[stub] + if compile_action and not tree.target then + local args + do + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #tree do + local arg = tree[_index_0] + if type(arg) ~= "string" then + _accum_0[_len_0] = arg + _len_0 = _len_0 + 1 end - args = _accum_0 end - local ret = compile_action(self, tree, unpack(args)) - if ret == nil then + args = _accum_0 + end + local ret = compile_action(self, tree, unpack(args)) + if ret == nil then + local info = debug.getinfo(compile_action, "S") + local filename = Source:from_string(info.source).filename + self:compile_error(tree, "The compile-time action here (" .. tostring(stub) .. ") failed to return any value.", "Look at the implementation of (" .. tostring(stub) .. ") in " .. tostring(filename) .. ":" .. tostring(info.linedefined) .. " and make sure it's returning something.") + end + if AST.is_syntax_tree(ret) then + if ret == tree then local info = debug.getinfo(compile_action, "S") local filename = Source:from_string(info.source).filename - self:compile_error(tree, "The compile-time action here (" .. tostring(stub) .. ") failed to return any value.", "Look at the implementation of (" .. tostring(stub) .. ") in " .. tostring(filename) .. ":" .. tostring(info.linedefined) .. " and make sure it's returning something.") - end - if AST.is_syntax_tree(ret) then - if ret == tree then - local info = debug.getinfo(compile_action, "S") - local filename = Source:from_string(info.source).filename - self:compile_error(tree, "The compile-time action here (" .. tostring(stub) .. ") is producing an endless loop.", "Look at the implementation of (" .. tostring(stub) .. ") in " .. tostring(filename) .. ":" .. tostring(info.linedefined) .. " and make sure it's not just returning the original tree.") - end - return self:compile(ret, compile_actions) + self:compile_error(tree, "The compile-time action here (" .. tostring(stub) .. ") is producing an endless loop.", "Look at the implementation of (" .. tostring(stub) .. ") in " .. tostring(filename) .. ":" .. tostring(info.linedefined) .. " and make sure it's not just returning the original tree.") end - return ret + return self:compile(ret, compile_actions) end + return ret end local lua = LuaCode.Value(tree.source) if tree.target then @@ -929,7 +927,7 @@ do self:compile_error(tree[2], "Can't use this as a dict value, since it's not an expression.") end local key_str = match(tostring(key_lua), [=[^["']([a-zA-Z_][a-zA-Z0-9_]*)['"]$]=]) - if key_str then + if key_str and key_str:is_lua_id() then return LuaCode(tree.source, key_str, "=", value_lua) elseif sub(tostring(key_lua), 1, 1) == "[" then return LuaCode(tree.source, "[ ", key_lua, "]=", value_lua) @@ -952,15 +950,13 @@ do self:compile_error(key, "Can't use this as an index, since it's not an expression.") end local key_lua_str = tostring(key_lua) - do - local lua_id = match(key_lua_str, "^['\"]([a-zA-Z_][a-zA-Z0-9_]*)['\"]$") - if lua_id then - lua:append("." .. tostring(lua_id)) - elseif sub(key_lua_str, 1, 1) == '[' then - lua:append("[ ", key_lua, " ]") - else - lua:append("[", key_lua, "]") - end + local lua_id = match(key_lua_str, "^['\"]([a-zA-Z_][a-zA-Z0-9_]*)['\"]$") + if lua_id and lua_id:is_lua_id() then + lua:append("." .. tostring(lua_id)) + elseif sub(key_lua_str, 1, 1) == '[' then + lua:append("[ ", key_lua, " ]") + else + lua:append("[", key_lua, "]") end end return lua diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon index 34c2ab0..e91db80 100644 --- a/nomsu_compiler.moon +++ b/nomsu_compiler.moon @@ -398,7 +398,8 @@ with NomsuCompiler switch tree.type when "Action" stub = tree.stub - if compile_action = compile_actions[stub] + compile_action = compile_actions[stub] + if compile_action and not tree.target args = [arg for arg in *tree when type(arg) != "string"] -- Force Lua to avoid tail call optimization for debugging purposes -- TODO: use tail call? @@ -551,9 +552,8 @@ with NomsuCompiler unless value_lua.is_value @compile_error tree[2], "Can't use this as a dict value, since it's not an expression." - -- TODO: support arbitrary words here, like operators and unicode key_str = match(tostring(key_lua), [=[^["']([a-zA-Z_][a-zA-Z0-9_]*)['"]$]=]) - return if key_str + return if key_str and key_str\is_lua_id! LuaCode tree.source, key_str,"=",value_lua elseif sub(tostring(key_lua),1,1) == "[" -- NOTE: this *must* use a space after the [ to avoid freaking out @@ -579,7 +579,8 @@ with NomsuCompiler @compile_error key, "Can't use this as an index, since it's not an expression." key_lua_str = tostring(key_lua) - if lua_id = match(key_lua_str, "^['\"]([a-zA-Z_][a-zA-Z0-9_]*)['\"]$") + lua_id = match(key_lua_str, "^['\"]([a-zA-Z_][a-zA-Z0-9_]*)['\"]$") + if lua_id and lua_id\is_lua_id! lua\append ".#{lua_id}" elseif sub(key_lua_str,1,1) == '[' -- NOTE: this *must* use a space after the [ to avoid freaking out -- cgit v1.2.3 From 17dfd248640caae5eecc13be8974378c39953f39 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Wed, 26 Sep 2018 13:59:42 -0700 Subject: Added field to remember text methods. --- containers.lua | 1 + containers.moon | 1 + 2 files changed, 2 insertions(+) diff --git a/containers.lua b/containers.lua index 2018581..1490a85 100644 --- a/containers.lua +++ b/containers.lua @@ -455,6 +455,7 @@ do setmetatable(text_methods, { __index = string2 }) + getmetatable("").__methods = text_methods getmetatable("").__index = function(self, i) if type(i) == 'number' then return sub(self, i, i) diff --git a/containers.moon b/containers.moon index f8f678c..3c78037 100644 --- a/containers.moon +++ b/containers.moon @@ -181,6 +181,7 @@ do setmetatable(text_methods, {__index:string2}) + getmetatable("").__methods = text_methods getmetatable("").__index = (i)=> -- Use [] for accessing text characters, or s[{3,4}] for s:sub(3,4) if type(i) == 'number' then return sub(@, i, i) -- cgit v1.2.3 From 3f31b09e7404e1ea374bbeb230bf34664b641efb Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Wed, 26 Sep 2018 14:00:05 -0700 Subject: Updated to the point of actually compiling. --- nomnom/code_obj.nom | 9 ++++++--- nomnom/compile.nom | 2 +- nomnom/decompile.nom | 12 ++++++------ nomnom/files.nom | 2 +- nomnom/parser.nom | 13 +++++++------ nomnom/pretty_errors.nom | 7 ++++--- 6 files changed, 25 insertions(+), 20 deletions(-) diff --git a/nomnom/code_obj.nom b/nomnom/code_obj.nom index 057748f..cc7bc04 100644 --- a/nomnom/code_obj.nom +++ b/nomnom/code_obj.nom @@ -163,20 +163,23 @@ object (Lua Code) extends (Code): %statements::add %suffix return %statements - action [Lua Code from %source {%bits:[]}]: + 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:[]}]: + action [Lua Code from %source] (Lua Code from %source []) + 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:[]} + action [Lua Value from %tree] (Lua Value from %tree []) object (Nomsu Code) extends (Code): - action [Nomsu Code from %source {%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} + action [Nomsu Code from %source] (Nomsu Code from %source []) diff --git a/nomnom/compile.nom b/nomnom/compile.nom index 43e6d84..cbe775a 100644 --- a/nomnom/compile.nom +++ b/nomnom/compile.nom @@ -1,6 +1,6 @@ # This file contains the code to convert syntax trees to Lua code -use "nomnom/code_obj.nom" +#use "nomnom/code_obj.nom" action [compile %tree using %compile_actions]: assume (%tree is a "Syntax Tree") diff --git a/nomnom/decompile.nom b/nomnom/decompile.nom index 0d8d4d2..478b09e 100644 --- a/nomnom/decompile.nom +++ b/nomnom/decompile.nom @@ -1,6 +1,6 @@ # This file contains the code to convert syntax trees to Nomsu code -use "nomnom/code_obj.nom" -use "nomnom/parser.nom" +#use "nomnom/code_obj.nom" +#use "nomnom/parser.nom" # TODO: maybe re-implement the fancy coroutine checker that aborts early if nomsu gets too long action [decompile %tree inline]: @@ -55,9 +55,9 @@ action [decompile %tree inline]: %nomsu = (Nomsu Code from %tree ["\""]) for %text in recursive %tree: for %bit in %text at %i: - if: - (%bit is text): - %nomsu::add %bit + if (%bit is text): + %nomsu::add %bit + ..else: if %bit.type is: "Text": recurse %text on %bit @@ -143,7 +143,7 @@ action [decompile %tree]: # For concision: local action [recurse on %t]: %space = (%MAX_LINE - (%nomsu::trailing line length)) - if (%space <= 0): go to (Indented) + if (%space <= 0): go to (Use Indented) for %subtree in recursive %tree: if %subtree.type is: "Block": diff --git a/nomnom/files.nom b/nomnom/files.nom index a17ec85..e4b5aa2 100644 --- a/nomnom/files.nom +++ b/nomnom/files.nom @@ -2,7 +2,7 @@ use "lib/os.nom" %_SPOOFED_FILES = {} -%_FILE_CACHE = ({} with fallback %_SPOOFED_FILES) +%_FILE_CACHE = ({} with fallback % -> %_SPOOFED_FILES.%) %_BROWSE_CACHE = {} # Create a fake file and put it in the cache diff --git a/nomnom/parser.nom b/nomnom/parser.nom index 1f460bd..dc98c24 100644 --- a/nomnom/parser.nom +++ b/nomnom/parser.nom @@ -1,11 +1,12 @@ # This file contains the parser, which converts text into abstract syntax trees -use "nomonom/ast.nom" +#use "nomonom/ast.nom" %lpeg = (=lua "require('lpeg')") %re = (=lua "require('re')") -call %lpeg.setmaxstack with [20_000] +call %lpeg.setmaxstack with [20000] set {..} (action (P 1)): %lpeg.P, (action (R 1)): %lpeg.R, (action (Carg 1)): %lpeg.Carg, + (action (S 1)): %lpeg.S, (action (Cc 1)): %lpeg.Cc, (action (lpeg re pattern 1)): %re.compile, (action (lpeg re pattern 1 using 2)): %re.compile @@ -43,11 +44,11 @@ set {..} %id_patt = (((P "") - (R "09")) * ((%defs.utf8_char + (R "az") + (R "AZ") + (P "_") + (R "09"))^1 * -1)) %operator_patt = ((S "'`~!@$^&*+=|<>?/-")^1 * -1) -%text_methods = (""'s metatable).__index -%text_methods.(action (is a nomsu identifier)) = (..) +%text_methods = (""'s metatable).__methods +%text_methods.("is a nomsu identifier"::as lua id) = (..) [%str] -> (call %id_patt.match with [%id_patt, %str]) -%text_methods.(action (is a nomsu id)) = %text_methods.(action (is a nomsu identifier)) -%text_methods.(action (is a nomsu operator)) = (..) +%text_methods.("is a nomsu id"::as lua id) = %text_methods.("is a nomsu identifier"::as lua id) +%text_methods.("is a nomsu operator"::as lua id) = (..) [%str] -> (call %operator_patt.match with [%operator_patt, %str]) %peg_tidier = (..) diff --git a/nomnom/pretty_errors.nom b/nomnom/pretty_errors.nom index 732f3b9..ffc6fd1 100644 --- a/nomnom/pretty_errors.nom +++ b/nomnom/pretty_errors.nom @@ -8,8 +8,9 @@ local action [boxed %text]: %max_line = (..) max of ((visible size of %line) for %line in (%text::lines)) %ret = (..) - "\n\%text"::with "\n([^\n]*)" as % -> (..) - "\n\%\(" "::* (%max_line - (visible size of %))) \027[0m" + "\n\%text"::with "\n([^\n]*)" -> (..) + [%] -> (..) + "\n\%\(" "::* (%max_line - (visible size of %))) \027[0m" return %ret.[2,-1] action [%err as a pretty error]: @@ -66,7 +67,7 @@ action [%err as a pretty error]: ..\027[47;31;1m\((" \(%err.error)"::wrapped to %box_width)::with "\n" -> "\n\027[47;31;1m ")" if %err.hint: err_text += "\n\027[47;30m\((" Suggestion: \(%err.hint)"::wrapped to %box_width)::with "\n" -> "\n\027[47;30m ")" - %err_msg += "\n\027[33;1m \((%err_text boxed) with "\n" -> "\n ")" + %err_msg += "\n\027[33;1m \((%err_text boxed)::with "\n" -> "\n ")" for %i in (%err_linenum_end + 1) to (%err_linenum_end + %context): %line = (%err_code::line %i) -- cgit v1.2.3 From 84931a6f0e0c8627a4835a9ce886aba28b0e76bc Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Fri, 28 Sep 2018 18:34:40 -0700 Subject: Fixes for indentation of generated lua code. --- core/control_flow.nom | 106 ++++++++++++++++++++++++-------------------------- 1 file changed, 50 insertions(+), 56 deletions(-) diff --git a/core/control_flow.nom b/core/control_flow.nom index a3814b7..4254abc 100644 --- a/core/control_flow.nom +++ b/core/control_flow.nom @@ -129,12 +129,13 @@ compile [repeat while %condition %body] to: %lua::append "\n ::continue_repeat::" %lua::append "\nend --while-loop" if (%body has subtree \(stop repeating)): - %lua = (..) - Lua "\ - ..do -- scope of "stop repeating" label - \%lua + %inner_lua = %lua + %lua = (Lua "do -- scope of 'stop repeating' label\n ") + %lua::append %inner_lua + %lua::append "\ + .. ::stop_repeat:: - end -- end of "stop repeating" label scope" + end -- end of 'stop repeating' label scope" return %lua @@ -158,12 +159,13 @@ compile [repeat %n times %body] to: %lua::append "\n ::continue_repeat::" %lua::append "\nend --numeric for-loop" if (%body has subtree \(stop repeating)): - %lua = (..) - Lua "\ - ..do -- scope of "stop repeating" label - \%lua + %inner_lua = %lua + %lua = (Lua "do -- scope of 'stop repeating' label\n ") + %lua::append %inner_lua + %lua::append "\ + .. ::stop_repeat:: - end -- end of "stop repeating" label scope" + end -- end of 'stop repeating' label scope" return %lua @@ -220,12 +222,12 @@ compile [..] %lua::append "\n \(compile as (===next %var ===))" %lua::append "\nend --numeric for-loop" if (%body has subtree \(stop %var)): - %lua = (..) - Lua "\ - ..do -- scope for stopping for-loop - \%lua - \(compile as (===stop %var ===)) - end -- end of scope for stopping for-loop" + %inner_lua = %lua + %lua = (Lua "do -- scope for stopping for-loop\n ") + %lua::append %inner_lua + %lua::append "\n " + %lua::append (compile as (===stop %var ===)) + %lua::append "\nend -- end of scope for stopping for-loop" return %lua @@ -262,12 +264,12 @@ compile [for %var in %iterable %body] to: %lua::append (Lua "\n\(compile as (===next %var ===))") %lua::append "\nend --foreach-loop" if (%body has subtree \(stop %var)): - %lua = (..) - Lua "\ - ..do -- scope for stopping for-loop - \%lua - \(compile as (===stop %var ===)) - end -- end of scope for stopping for-loop" + %inner_lua = %lua + %lua = (Lua "do -- scope for stopping for-loop\n ") + %lua::append %inner_lua + %lua::append "\n " + %lua::append (compile as (===stop %var ===)) + %lua::append "\nend -- end of scope for stopping for-loop" return %lua @@ -285,12 +287,12 @@ compile [for %var in %iterable at %i %body] to: %lua::append (Lua "\n\(compile as (===next %var ===))") %lua::append "\nend --foreach-loop" if (%body has subtree \(stop %var)): - %lua = (..) - Lua "\ - ..do -- scope for stopping for-loop - \%lua - \(compile as (===stop %var ===)) - end -- end of scope for stopping for-loop" + %inner_lua = %lua + %lua = (Lua "do -- scope for stopping for-loop\n ") + %lua::append %inner_lua + %lua::append "\n " + %lua::append (compile as (===stop %var ===)) + %lua::append "\nend -- end of scope for stopping for-loop" return %lua @@ -333,11 +335,11 @@ compile [..] if (%body has subtree \(stop %value)): %stop_labels::append "\n\(compile as (===stop %value ===))" if ((size of "\%stop_labels") > 0): - %lua = (..) - Lua "\ - ..do -- scope for stopping for % = % loop - \%lua\%stop_labels - end" + %inner_lua = %lua + %lua = (Lua "do -- scope for stopping for % = % loop\n ") + %lua::append %inner_lua + %lua::append %stop_labels + %lua::append "\nend" return %lua @@ -384,11 +386,8 @@ compile [if %body, when %body] to: ..need a conditional block around it. Otherwise, make sure the 'else' \ ..block comes last." - %code::append "\ - .. - else - \(%action as lua statements)" - + %code::append "\nelse\n " + %code::append (%action as lua statements) %else_allowed = (no) ..else: %code::append "\%clause " @@ -397,10 +396,8 @@ compile [if %body, when %body] to: %code::append " or " %code::append (%line.%i as lua expr) - %code::append "\ - .. then - \(%action as lua statements)" - + %code::append " then\n " + %code::append (%action as lua statements) %clause = "\nelseif" if ((size of "\%code") == 0): @@ -449,11 +446,8 @@ compile [if %branch_value is %body, when %branch_value is %body] to: ..need a conditional block around it. Otherwise, make sure the 'else' \ ..block comes last." - %code::append "\ - .. - else - \(%action as lua statements)" - + %code::append "\nelse\n " + %code::append (%action as lua statements) %else_allowed = (no) ..else: %code::append "\%clause " @@ -462,22 +456,22 @@ compile [if %branch_value is %body, when %branch_value is %body] to: %code::append " or " %code::append "\(mangle "branch value") == \(%line.%i as lua expr)" - %code::append "\ - .. then - \(%action as lua statements)" - + %code::append " then\n " + %code::append (%action as lua statements) %clause = "\nelseif" if ((size of "\%code") == 0): compile error at %body "'if' block has an empty body." ..hint "This means nothing would happen, so the 'if' block should be deleted." %code::append "\nend --when" - return (..) + %lua = (..) Lua "\ - ..do --if % is - local \(mangle "branch value") = \(%branch_value as lua expr) - \%code - end --if % is" + ..do --if % is... + local \(mangle "branch value") = \(%branch_value as lua expr)" + %lua::append "\n " + %lua::append %code + %lua::append "\nend --if % is..." + return %lua # Do/finally compile [do %action] to (..) -- cgit v1.2.3 From 258527750cea3372a932552e0f18cd48e132def5 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Fri, 28 Sep 2018 18:35:12 -0700 Subject: Slightly more robust. --- code_obj.lua | 2 +- code_obj.moon | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code_obj.lua b/code_obj.lua index 5be92e6..577eaf3 100644 --- a/code_obj.lua +++ b/code_obj.lua @@ -355,7 +355,7 @@ do local _list_1 = self.bits for _index_0 = 1, #_list_1 do local bit = _list_1[_index_0] - if bit.__class == LuaCode then + if not (type(bit) == 'string') then gather_from(bit) end end diff --git a/code_obj.moon b/code_obj.moon index 4e70784..07b7618 100644 --- a/code_obj.moon +++ b/code_obj.moon @@ -207,7 +207,7 @@ class LuaCode extends Code seen[var] = true to_declare[#to_declare+1] = var for bit in *@bits - if bit.__class == LuaCode + unless type(bit) == 'string' gather_from bit gather_from self if #to_declare > 0 -- cgit v1.2.3 From 7b127fca6165399226afc831c07268da850c3d6a Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Fri, 28 Sep 2018 18:35:37 -0700 Subject: Slight API tweaks. --- containers.lua | 10 +++++----- containers.moon | 11 ++++++----- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/containers.lua b/containers.lua index 1490a85..ab632c4 100644 --- a/containers.lua +++ b/containers.lua @@ -27,7 +27,7 @@ as_nomsu = function(self) end end end - return error("Not supported: " .. tostring(self)) + return tostring(self) end local as_lua as_lua = function(self) @@ -45,7 +45,7 @@ as_lua = function(self) end end end - return error("Not supported: " .. tostring(self)) + return tostring(self) end local _list_mt = { __type = "List", @@ -56,7 +56,7 @@ local _list_mt = { local _len_0 = 1 for _index_0 = 1, #self do local b = self[_index_0] - _accum_0[_len_0] = tostring(b) + _accum_0[_len_0] = as_nomsu(b) _len_0 = _len_0 + 1 end return _accum_0 @@ -194,7 +194,7 @@ local _list_mt = { end return nil end, - slice_1_to_2 = function(self, start, stop) + from_1_to_2 = function(self, start, stop) local n = #self if n < 0 then start = (n + 1 - start) @@ -240,7 +240,7 @@ local _dict_mt = { local _accum_0 = { } local _len_0 = 1 for k, v in pairs(self) do - _accum_0[_len_0] = tostring(tostring(k)) .. ": " .. tostring(tostring(v)) + _accum_0[_len_0] = tostring(as_nomsu(k)) .. ": " .. tostring(as_nomsu(v)) _len_0 = _len_0 + 1 end return _accum_0 diff --git a/containers.moon b/containers.moon index 3c78037..8a91241 100644 --- a/containers.moon +++ b/containers.moon @@ -13,7 +13,7 @@ as_nomsu = => if mt = getmetatable(@) if _as_nomsu = mt.as_nomsu return _as_nomsu(@) - error("Not supported: #{@}") + return tostring(@) as_lua = => if type(@) == 'number' @@ -21,16 +21,17 @@ as_lua = => if mt = getmetatable(@) if _as_lua = mt.as_lua return _as_lua(@) - error("Not supported: #{@}") + return tostring(@) -- List and Dict classes to provide basic equality/tostring functionality for the tables -- used in Nomsu. This way, they retain a notion of whether they were originally lists or dicts. + _list_mt = __type: "List" __eq:equivalent -- Could consider adding a __newindex to enforce list-ness, but would hurt performance __tostring: => - "["..concat([tostring(b) for b in *@], ", ").."]" + "["..concat([as_nomsu(b) for b in *@], ", ").."]" as_nomsu: => "["..concat([as_nomsu(b) for b in *@], ", ").."]" as_lua: => @@ -77,7 +78,7 @@ _list_mt = if x == item return i return nil - slice_1_to_2: (start, stop)=> + from_1_to_2: (start, stop)=> n = #@ start = (n+1-start) if n < 0 stop = (n+1-stop) if n < 0 @@ -101,7 +102,7 @@ _dict_mt = __eq:equivalent __len:size __tostring: => - "{"..concat(["#{tostring(k)}: #{tostring(v)}" for k,v in pairs @], ", ").."}" + "{"..concat(["#{as_nomsu(k)}: #{as_nomsu(v)}" for k,v in pairs @], ", ").."}" as_nomsu: => "{"..concat(["#{as_nomsu(k)}: #{as_nomsu(v)}" for k,v in pairs @], ", ").."}" as_lua: => -- cgit v1.2.3 From 678344182b1f04e35063d7185ac1d74317b011ea Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Fri, 28 Sep 2018 18:36:36 -0700 Subject: Forward progress on getting nomnom working. --- nomnom/ast.nom | 2 +- nomnom/code_obj.nom | 31 +++++++++++++++++++------------ nomnom/compile.nom | 44 +++++++++++++++++++++++++++----------------- nomnom/decompile.nom | 14 +++++++------- nomnom/parser.nom | 20 +++++++++++--------- 5 files changed, 65 insertions(+), 46 deletions(-) diff --git a/nomnom/ast.nom b/nomnom/ast.nom index 2d5a894..da1d0c4 100644 --- a/nomnom/ast.nom +++ b/nomnom/ast.nom @@ -1,6 +1,6 @@ use "lib/object.nom" -#%types = [..] +# The types are [..] "Number", "Var", "Block", "EscapedNomsu", "Text", "List", "Dict", "DictEntry", "IndexChain", "Action", "FileChunks", "Error", "Comment" diff --git a/nomnom/code_obj.nom b/nomnom/code_obj.nom index cc7bc04..7ff1b23 100644 --- a/nomnom/code_obj.nom +++ b/nomnom/code_obj.nom @@ -6,6 +6,7 @@ use "lib/object.nom" object (Code): my action [set up]: + assume %me.source %old_bits = %me.bits %me.bits = [] if (%me.source is text): @@ -13,19 +14,24 @@ object (Code): for % in %old_bits: %me::add % + %depth = 0 my action [as text]: + external %depth = (%depth + 1) + if (%depth > 10): + lua> "require('ldt').breakpoint()" if (%me.__str == (nil)): set {%buff:[], %indent:0} - for % in %me.bits: - if (% is text): - %spaces = (%::matching "\n([ ]*)[^\n]*$") - if %spaces.1: %indent = (size of %spaces) + for %bit in %me.bits: + if (%bit is text): + %spaces = (%bit::matching "\n([ ]*)[^\n]*$") + if %spaces: %indent = (size of %spaces.1) ..else: - % = "\%" + %bit = "\%bit" if (%indent > 0): - % = (%::with "\n" -> "\n\(" "::* %indent)") - %buff::add % + %bit = (%bit::with "\n" -> "\n\(" "::* %indent)") + %buff::add %bit %me.__str = (%buff::joined) + external %depth = (%depth - 1) return %me.__str my action [as lua] (..) @@ -76,19 +82,20 @@ object (Code): my action [add %values joined with %joiner or %wrapping_joiner]: %line_len = 0 %bits = %me.bits - for %i = % in %values: + for %value in %values at %i: + assume (%value != %me) if (%i > 1): if (%line_len > 80): %bits::add %wrapping_joiner %line_len = 0 ..else: %bits::add %joiner - %bits::add % - %line = ("\%"::matching "\n([^\n]*)$") + %bits::add %value + %line = ("\%value"::matching "\n([^\n]*)$") if %line: %line_len = (size of %line) ..else: - %line_len += (size of %) + %line_len += (size of %value) %me::mark as dirty my action [prepend %]: @@ -155,7 +162,7 @@ object (Lua Code) extends (Code): my action [as statements %prefix %suffix]: unless %me.is_value: return %me - %statements = (Lua Code %me.source []) + %statements = (Lua Code from %me.source []) if (%prefix != ""): %statements::add %prefix %statements::add %me diff --git a/nomnom/compile.nom b/nomnom/compile.nom index cbe775a..19daa6a 100644 --- a/nomnom/compile.nom +++ b/nomnom/compile.nom @@ -1,6 +1,14 @@ # This file contains the code to convert syntax trees to Lua code -#use "nomnom/code_obj.nom" +use "nomnom/code_obj.nom" +use "nomnom/parser.nom" +use "nomnom/pretty_errors.nom" + +local action [report compile error at %pos %err]: + barf "Compile error at \%pos: \%err" + +local action [report compile error at %pos %err hint %hint]: + barf "Compile error at \%pos: \%err\n\%hint" action [compile %tree using %compile_actions]: assume (%tree is a "Syntax Tree") @@ -15,17 +23,17 @@ action [compile %tree using %compile_actions]: %compile_action = %compile_actions.%stub # Don't apply compiler actions to methods if (%compile_action and (not %tree.target)): - %args = [%tree, %compile_actions] + %args = ["tree", "compile_actions"] for % in (%tree::get args): %args::add % %result = (call %compile_action with %args) if (%result == (nil)): - compile error at %tree.source "\ + report compile error at %tree.source "\ ..The compile-time action here (\(%tree.stub)) failed to return any value." ..hint "\ ..Look at the implementation of (\(%tree.stub)) and make sure it's returning something." if (%result is a "Syntax Tree"): if (%result == %tree): - compile error at %tree.source "\ + report compile error at %tree.source "\ ..The compile-time action here (\(%tree.stub)) is producing an endless loop." ..hint "\ ..Look at the implementation of (\(%tree.stub)) and make sure it's not just returning the original tree." @@ -39,9 +47,9 @@ action [compile %tree using %compile_actions]: %lua::add [%target_lua, ":"] ..else: %lua::add ["(", %target_lua, "):"] - %lua:add [%stub as lua id, "("] + %lua::add [%stub as lua id, "("] %args = [] - for %tok in %tree: + for %tok in %tree at %i: if (%tok is text): do next %tok # TODO: maybe translate Lua comments if (%tok.type == "Comment"): do next %tok @@ -67,16 +75,17 @@ action [compile %tree using %compile_actions]: %arg_lua = (compile %tok using %compile_actions) unless %arg_lua.is_value: if (%tok.type == "Action"): - compile error at %tok "\ + report compile error at %tok "\ ..Can't use this as an argument to (\%stub), since it's not \ ..an expression, it produces: \%arg_lua" ..hint "\ ..Check the implementation of (\(%tok.stub)) to see if it \ ..is actually meant to produce an expression." ..else: - compile error at %tok "\ + report compile error at %tok "\ ..Can't use this as an argument to (\%stub), since it's \ ..not an expression, it produces: \%arg_lua" + assume (%arg_lua != %lua) or barf "Huh? \%tree .\%i = \%tok -> \%arg_lua" %args::add %arg_lua %lua::add %args joined with ", " %lua::add ")" @@ -94,7 +103,7 @@ action [compile %tree using %compile_actions]: return %lua "Text": - %lua = (Lua Code from %tree) + %lua = (Lua Value from %tree) %lua_bits = [] %string_buffer = "" for % in %tree: @@ -104,12 +113,12 @@ action [compile %tree using %compile_actions]: if (%string_buffer != ""): %lua_bits::add (%string_buffer::as lua) %string_buffer = "" - %bit_lua = (compile %bit using %compile_actions) + %bit_lua = (compile % using %compile_actions) unless %bit_lua.is_value: - compile error at %bit "\ + report compile error at % "\ ..Can't use this as a string interpolation value, since it doesn't have a value." - if (%bit.type != "Text"): - %bit_lua = (Lua Value from %bit ["tostring(",%bit_lua,")"]) + if (%.type != "Text"): + %bit_lua = (Lua Value from % ["tostring(",%bit_lua,")"]) %lua_bits::add %bit_lua if ((%string_buffer != "") or ((size of %lua_bits) == 0)): @@ -136,13 +145,13 @@ action [compile %tree using %compile_actions]: set {%key:%tree.1, %value:%tree.2} %key_lua = (compile %key using %compile_actions) unless %key_lua.is_value: - compile error at %tree.1 "\ + report compile error at %tree.1 "\ ..Can't use this as a dict key, since it's not an expression." %value_lua = (..) (compile %value using %compile_actions) if %value ..else (Lua Value from %key ["true"]) unless %value_lua.is_value: - compile error at %tree.2 "\ + report 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: @@ -159,7 +168,7 @@ action [compile %tree using %compile_actions]: "IndexChain": %lua = (compile %tree.1 using %compile_actions) unless %lua.is_value: - compile error at %tree.1 "\ + report compile error at %tree.1 "\ ..Can't index into this, since it's not an expression." %first_char = "\%lua".1 if (any of [%first_char == "{", %first_char == "\"", %first_char == "["]): @@ -169,7 +178,7 @@ action [compile %tree using %compile_actions]: %key = %tree.%i %key_lua = (compile %key using %compile_actions) unless %key_lua.is_value: - compile error at %key "\ + report compile error at %key "\ ..Can't use this as an index, since it's not an expression." %key_lua_str = "\%key_lua" %lua_id = (%key_lua_str::matching "^['\"]([a-zA-Z_][a-zA-Z0-9_]*)['\"]$") @@ -205,3 +214,4 @@ action [compile %tree using %compile_actions]: else: barf "Unknown type: \(%tree.type)" + diff --git a/nomnom/decompile.nom b/nomnom/decompile.nom index 478b09e..e002f61 100644 --- a/nomnom/decompile.nom +++ b/nomnom/decompile.nom @@ -1,6 +1,6 @@ # This file contains the code to convert syntax trees to Nomsu code -#use "nomnom/code_obj.nom" -#use "nomnom/parser.nom" +use "nomnom/code_obj.nom" +use "nomnom/parser.nom" # TODO: maybe re-implement the fancy coroutine checker that aborts early if nomsu gets too long action [decompile %tree inline]: @@ -21,7 +21,7 @@ action [decompile %tree inline]: any of [..] %i == 1, %tree.(%i - 1) isn't text, - (%bit::is a nomsu operator) == (%tree.(%i - 1)::is a nomsu operator) + (%bit is a nomsu operator) == (%tree.(%i - 1) is a nomsu operator) ..: %nomsu::add " " %nomsu::add %bit ..else: @@ -86,7 +86,7 @@ action [decompile %tree inline]: "DictEntry": set {%key:%tree.1, %value:%tree.2} - if (all of [%key.type == "Text", (size of %key) == 1, %key.1::is a nomsu identifier]): + if (all of [%key.type == "Text", (size of %key) == 1, %key.1 is a nomsu identifier]): %nomsu = (Nomsu Code from %key [key.1]) ..else: %nomsu = (decompile %key inline) @@ -105,7 +105,7 @@ action [decompile %tree inline]: if (..) all of [..] %i > 1, %bit.type == "Text", (size of %bit) == 1, %bit.1 is text, - %bit.1::is a nomsu identifier + %bit.1 is a nomsu identifier ..:%nomsu::add %bit.1 ..else: %bit_nomsu = (decompile %bit inline) @@ -214,7 +214,7 @@ action [decompile %tree]: unless (..) all of [..] %tree.(%i - 1) is text - (%tree.(%i - 1)::is a nomsu operator) != (%bit::is a nomsu operator) + (%tree.(%i - 1) is a nomsu operator) != (%bit is a nomsu operator) ..: %nomsu::add %next_space %nomsu::add %bit %next_space = " " @@ -317,7 +317,7 @@ action [decompile %tree]: "DictEntry": set {%key:%tree.1, %value:%tree.2} - if (all of [%key.type == "Text", (size of %key) == 1, %key.1::is a nomsu identifier]): + if (all of [%key.type == "Text", (size of %key) == 1, %key.1 is a nomsu identifier]): %nomsu::add %key.1 ..else: %nomsu::add (decompile %key inline) diff --git a/nomnom/parser.nom b/nomnom/parser.nom index dc98c24..ef06e08 100644 --- a/nomnom/parser.nom +++ b/nomnom/parser.nom @@ -9,6 +9,8 @@ set {..} (action (S 1)): %lpeg.S, (action (Cc 1)): %lpeg.Cc, (action (lpeg re pattern 1)): %re.compile, (action (lpeg re pattern 1 using 2)): %re.compile + (action (lpeg pattern 1's match of 2)): %lpeg.match + (action (lpeg pattern 1's match of 2 with 3)): [%1, %2, %3] -> (call %lpeg.match with [%1, %2, nil, %3]) %source_code_for_tree = {} %defs = (..) @@ -27,7 +29,7 @@ set {..} Tree: [%t, %userdata] ->: %source = (..) - Source {filename:%userdata.filename, start:%tree.start, stop:%tree.stop} + Source {filename:%userdata.filename, start:%t.start, stop:%t.stop} set {%t.start: nil, %t.stop: nil} %t = (Syntax Tree %t) (Syntax Tree).source_code_for_tree.%t = %userdata.source @@ -44,12 +46,12 @@ set {..} %id_patt = (((P "") - (R "09")) * ((%defs.utf8_char + (R "az") + (R "AZ") + (P "_") + (R "09"))^1 * -1)) %operator_patt = ((S "'`~!@$^&*+=|<>?/-")^1 * -1) -%text_methods = (""'s metatable).__methods -%text_methods.("is a nomsu identifier"::as lua id) = (..) - [%str] -> (call %id_patt.match with [%id_patt, %str]) -%text_methods.("is a nomsu id"::as lua id) = %text_methods.("is a nomsu identifier"::as lua id) -%text_methods.("is a nomsu operator"::as lua id) = (..) - [%str] -> (call %operator_patt.match with [%operator_patt, %str]) + +action [%text is a nomsu id, %text is a nomsu identifier] (..) + lpeg pattern %id_patt's match of %text + +action [%text is a nomsu operator] (..) + lpeg pattern %operator_patt's match of %text %peg_tidier = (..) lpeg re pattern "\ @@ -68,7 +70,7 @@ set {..} action [make parser from %peg] (make parser from %peg using (nil)) action [make parser from %peg using %make_tree]: - %peg = (call %peg_tidier.match with [%peg_tidier, %peg]) + %peg = (lpeg pattern %peg_tidier's match of %peg) %peg = (lpeg re pattern %peg using %defs) local action [parse %input from %filename]: %input = "\%input" @@ -76,7 +78,7 @@ action [make parser from %peg using %make_tree]: %userdata = {..} make_tree: %make_tree or ([%]-> (: set %'s metatable to %tree_mt; return %)) filename:%filename, source:%input - %tree = (call %peg.match with [%peg, %input, (nil), %userdata]) + %tree = (lpeg pattern %peg's match of %input with %userdata) assume %tree or barf "File \%filename failed to parse:\n\%input" return %tree return (action (parse 1 from 2)) -- cgit v1.2.3 From 63d8b1cd3f34b15bf86210b99209e8b57e7019bb Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Fri, 28 Sep 2018 22:15:06 -0700 Subject: Fully working, I think? (with a lot of shims) --- code_obj.moon | 30 ++++++----- containers.moon | 2 + core/control_flow.nom | 129 +++++++++++++++++++++++++++-------------------- core/math.nom | 8 +-- core/metaprogramming.nom | 18 +++---- core/operators.nom | 8 +-- nomnom/ast.nom | 3 ++ nomnom/code_obj.nom | 74 ++++++++++++++------------- nomnom/compile.nom | 30 ++++++----- nomnom/decompile.nom | 2 +- nomnom/parser.nom | 2 +- syntax_tree.moon | 3 +- 12 files changed, 174 insertions(+), 135 deletions(-) diff --git a/code_obj.moon b/code_obj.moon index 07b7618..3e43b16 100644 --- a/code_obj.moon +++ b/code_obj.moon @@ -47,10 +47,10 @@ class Code @bits = {} if type(@source) == 'string' @source = Source\from_string(@source) - assert(@source and Source\is_instance(@source), "Source has the wrong type") + --assert(@source and Source\is_instance(@source), "Source has the wrong type") @append(...) - __tostring: => + as_smext: => if @__str == nil buff, indent = {}, 0 {:match, :gsub, :rep} = string @@ -59,21 +59,23 @@ class Code if spaces = match(b, "\n([ ]*)[^\n]*$") indent = #spaces else - b = tostring(b) + b = b\as_smext! if indent > 0 b = gsub(b, "\n", "\n"..rep(" ", indent)) buff[#buff+1] = b @__str = concat(buff, "") return @__str + __tostring: => @as_smext! + as_lua: => "#{@__class.__name}(#{concat {tostring(@source)\as_lua!, unpack([b\as_lua! for b in *@bits])}, ", "})" - __len: => #tostring(@) + __len: => #@as_smext! - match: (...)=> tostring(@)\match(...) + match: (...)=> @as_smext!\match(...) - gmatch: (...)=> tostring(@)\gmatch(...) + gmatch: (...)=> @as_smext!\gmatch(...) dirty: => @__str = nil @@ -91,14 +93,14 @@ class Code assert(not Source\is_instance(b), "code bit is a Source") if b == '' then continue b.dirty = error if b.is_code - if type(b) != 'string' and not (type(b) == 'table' and b.is_code) - b = b\as_lua! + --if type(b) != 'string' and not (type(b) == 'table' and b.is_code) + -- b = b\as_lua! bits[#bits+1] = b @dirty! trailing_line_len: => if @_trailing_line_len == nil - @_trailing_line_len = #tostring(@)\match("[^\n]*$") + @_trailing_line_len = #@as_smext!\match("[^\n]*$") return @_trailing_line_len is_multiline: => @@ -130,7 +132,8 @@ class Code bits[#bits+1] = joiner bits[#bits+1] = b b.dirty = error if b.is_code - b = tostring(b) + unless type(b) == 'string' + b = b\as_smext! line = match(b, "\n([^\n]*)$") if line line_len = #line @@ -146,8 +149,8 @@ class Code for i=1,n b = select(i, ...) b.dirty = error if b.is_code - if type(b) != 'string' and not (type(b) == 'table' and b.is_code) - b = b\as_lua! + --if type(b) != 'string' and not (type(b) == 'table' and b.is_code) + -- b = b\as_lua! bits[i] = b @dirty! @@ -237,7 +240,8 @@ class LuaCode extends Code nomsu_to_lua[lua.source.start] = pos else walk b, pos - pos += #tostring(b) + b = b\as_smext! + pos += #b walk self, 1 return { nomsu_filename:@source.filename diff --git a/containers.moon b/containers.moon index 8a91241..0fb9271 100644 --- a/containers.moon +++ b/containers.moon @@ -87,6 +87,8 @@ _list_mt = __newindex: (k,v)=> assert type(k) == 'number', "List indices must be numbers" rawset(@, k, v) +_list_mt.__index.as_lua = _list_mt.as_lua +_list_mt.__index.as_nomsu = _list_mt.as_nomsu List = (t)-> setmetatable(t, _list_mt) diff --git a/core/control_flow.nom b/core/control_flow.nom index 4254abc..243df96 100644 --- a/core/control_flow.nom +++ b/core/control_flow.nom @@ -16,11 +16,13 @@ compile [do nothing] to (Lua "") test: if (no): barf "conditional fail" -compile [if %condition %if_body] to (..) - Lua "\ - ..if \(%condition as lua expr) then - \(%if_body as lua statements) - end" +compile [if %condition %if_body] to: + %lua = (Lua "if ") + %lua::append (%condition as lua expr) + %lua::append " then\n " + %lua::append (%if_body as lua statements) + %lua::append "\nend" + return %lua test: unless (yes): @@ -28,13 +30,15 @@ test: parse [unless %condition %unless_body] as (if (not %condition) %unless_body) compile [..] if %condition %if_body else %else_body, unless %condition %else_body else %if_body -..to (..) - Lua "\ - ..if \(%condition as lua expr) then - \(%if_body as lua statements) - else - \(%else_body as lua statements) - end" +..to: + %lua = (Lua "if ") + %lua::append (%condition as lua expr) + %lua::append " then\n " + %lua::append (%if_body as lua statements) + %lua::append "\nelse\n " + %lua::append (%else_body as lua statements) + %lua::append "\nend" + return %lua ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -149,9 +153,8 @@ test: compile [repeat %n times %body] to: define mangler %lua = (..) - Lua "\ - ..for \(mangle "i")=1,\(%n as lua expr) do - \(%body as lua statements)" + Lua "for \(mangle "i")=1,\(%n as lua expr) do\n " + %lua::append (%body as lua statements) if (%body has subtree \(do next)): %lua::append "\n ::continue::" @@ -208,18 +211,20 @@ compile [..] ..to: # This uses Lua's approach of only allowing loop-scoped variables in a loop unless (%var.type is "Var"): - compile error at %var "Expected a variable here, not a \(%var.type)." + compile error at %var "Expected a variable here, not a \(%var.type)" %lua = (..) Lua "\ ..for \(%var as lua expr)=\(%start as lua expr),\(%stop as lua expr),\(..) %step as lua expr - .. do - \(%body as lua statements)" + .. do" + %lua::append "\n " + %lua::append (%body as lua statements) if (%body has subtree \(do next)): %lua::append "\n ::continue::" if (%body has subtree \(do next %var)): - %lua::append "\n \(compile as (===next %var ===))" + %lua::append "\n " + %lua::append (compile as (===next %var ===)) %lua::append "\nend --numeric for-loop" if (%body has subtree \(stop %var)): %inner_lua = %lua @@ -254,14 +259,14 @@ compile [for %var in %iterable %body] to: define mangler # This uses Lua's approach of only allowing loop-scoped variables in a loop %lua = (..) - Lua "\ - ..for \(mangle "i"),\(%var as lua identifier) in ipairs(\(%iterable as lua expr)) do - \(%body as lua statements)" + Lua "for \(mangle "i"),\(%var as lua identifier) in ipairs(\(%iterable as lua expr)) do\n " + %lua::append (%body as lua statements) if (%body has subtree \(do next)): %lua::append "\n ::continue::" if (%body has subtree \(do next %var)): - %lua::append (Lua "\n\(compile as (===next %var ===))") + %lua::append "\n " + %lua::append (compile as (===next %var ===)) %lua::append "\nend --foreach-loop" if (%body has subtree \(stop %var)): %inner_lua = %lua @@ -277,14 +282,14 @@ compile [for %var in %iterable %body] to: compile [for %var in %iterable at %i %body] to: # This uses Lua's approach of only allowing loop-scoped variables in a loop %lua = (..) - Lua "\ - ..for \(%i as lua identifier),\(%var as lua identifier) in ipairs(\(%iterable as lua expr)) do - \(%body as lua statements)" + Lua "for \(%i as lua identifier),\(%var as lua identifier) in ipairs(\(%iterable as lua expr)) do\n " + %lua::append (%body as lua statements) if (%body has subtree \(do next)): %lua::append "\n ::continue::" if (%body has subtree \(do next %var)): - %lua::append (Lua "\n\(compile as (===next %var ===))") + %lua::append "\n " + %lua::append (compile as (===next %var ===)) %lua::append "\nend --foreach-loop" if (%body has subtree \(stop %var)): %inner_lua = %lua @@ -312,28 +317,33 @@ compile [..] ..to: # This uses Lua's approach of only allowing loop-scoped variables in a loop unless (%key.type is "Var"): - compile error at %key "Expected a variable here, not a \(%key.type)." + compile error at %key "Expected a variable here, not a \(%key.type)" unless (%value.type is "Var"): - compile error at %value "Expected a variable here, not a \(%value.type)." + compile error at %value "Expected a variable here, not a \(%value.type)" %lua = (..) Lua "\ ..for \(%key as lua identifier),\(%value as lua identifier) in pairs(\(..) %iterable as lua expr - ..) do - \(%body as lua statements)" + ..) do" + %lua::append "\n " + %lua::append (%body as lua statements) if (%body has subtree \(do next)): %lua::append "\n ::continue::" if (%body has subtree \(do next %key)): - %lua::append (Lua "\n\(compile as (===next %key ===))") + %lua::append "\n " + %lua::append (compile as (===next %key ===)) if (%body has subtree \(do next %value)): - %lua::append (Lua "\n\(compile as (===next %value ===))") + %lua::append "\n " + %lua::append (compile as (===next %value ===)) %lua::append "\nend --foreach-loop" %stop_labels = (Lua "") if (%body has subtree \(stop %key)): - %stop_labels::append "\n\(compile as (===stop %key ===))" + %stop_labels::append "\n" + %stop_labels::append (compile as (===stop %key ===)) if (%body has subtree \(stop %value)): - %stop_labels::append "\n\(compile as (===stop %value ===))" + %stop_labels::append "\n" + %stop_labels::append (compile as (===stop %value ===)) if ((size of "\%stop_labels") > 0): %inner_lua = %lua %lua = (Lua "do -- scope for stopping for % = % loop\n ") @@ -390,7 +400,8 @@ compile [if %body, when %body] to: %code::append (%action as lua statements) %else_allowed = (no) ..else: - %code::append "\%clause " + %code::append %clause + %code::append " " for %i in 1 to ((size of %line) - 1): if (%i > 1): %code::append " or " @@ -450,11 +461,13 @@ compile [if %branch_value is %body, when %branch_value is %body] to: %code::append (%action as lua statements) %else_allowed = (no) ..else: - %code::append "\%clause " + %code::append %clause + %code::append " " for %i in 1 to ((size of %line) - 1): if (%i > 1): %code::append " or " - %code::append "\(mangle "branch value") == \(%line.%i as lua expr)" + %code::append "\(mangle "branch value") == " + %code::append (%line.%i as lua expr) %code::append " then\n " %code::append (%action as lua statements) @@ -467,18 +480,19 @@ compile [if %branch_value is %body, when %branch_value is %body] to: %lua = (..) Lua "\ ..do --if % is... - local \(mangle "branch value") = \(%branch_value as lua expr)" + local \(mangle "branch value") = " + %lua::append (%branch_value as lua expr) %lua::append "\n " %lua::append %code %lua::append "\nend --if % is..." return %lua # Do/finally -compile [do %action] to (..) - Lua "\ - ..do - \(%action as lua statements) - end --do" +compile [do %action] to: + %lua = (Lua "do\n ") + %lua::append (%action as lua statements) + %lua::append "\nend -- do" + return %lua test: %d = {} @@ -492,18 +506,22 @@ test: assume (%d.x == "good") compile [do %action then always %final_action] to: define mangler - return (..) + %lua = (..) Lua "\ ..do local \(mangle "fell_through") = false - local \(mangle "ok"), \(mangle "ret") = pcall(function() - \(%action as lua statements) - \(mangle "fell_through") = true - end) - \(%final_action as lua statements) - if not \(mangle "ok") then error(ret, 0) end - if not \(mangle "fell_through") then return ret end - end" + local \(mangle "ok"), \(mangle "ret") = pcall(function()" + %lua::append "\n " + %lua::append (%action as lua statements) + %lua::append "\ + .. \(mangle "fell_through") = true + end)" + %lua::append "\n " + %lua::append (%final_action as lua statements) + %lua::append "\ + .. if not \(mangle "ok") then error(ret, 0) end + if not \(mangle "fell_through") then return ret end + end" test: assume ((result of (: return 99)) == 99) @@ -532,8 +550,9 @@ compile [for %var in recursive %structure %body] to (..) ..do local \(mangle "stack \(%var.1)") = _List{\(%structure as lua expr)} while #\(mangle "stack \(%var.1)") > 0 do - \(%var as lua expr) = table.remove(\(mangle "stack \(%var.1)"), 1) - \(%body as lua statements)" + \(%var as lua expr) = table.remove(\(mangle "stack \(%var.1)"), 1)" + %lua::append "\n " + %lua::append (%body as lua statements) if (%body has subtree \(do next)): %lua::append "\n ::continue::" diff --git a/core/math.nom b/core/math.nom index 5daa2d8..feb64cb 100644 --- a/core/math.nom +++ b/core/math.nom @@ -72,21 +72,21 @@ action [%n to the nearest %rounder] (..) compile [all of %items, all %items] to: unless (%items.type is "List"): return (Lua value "utils.all(\(%items as lua expr))") - %clauses = ((% as lua expr) for % in %items) + %clauses = (((% as lua expr)::as smext) for % in %items) return (Lua value "(\(%clauses::joined with " and "))") parse [not all of %items, not all %items] as (not (all of %items)) compile [any of %items, any %items] to: unless (%items.type is "List"): return (Lua value "utils.any(\(%items as lua expr))") - %clauses = ((% as lua expr) for % in %items) + %clauses = (((% as lua expr)::as smext) for % in %items) return (Lua value "(\(%clauses::joined with " or "))") parse [none of %items, none %items] as (not (any of %items)) compile [sum of %items, sum %items] to: unless (%items.type is "List"): return (Lua value "utils.sum(\(%items as lua expr))") - %clauses = ((% as lua expr) for % in %items) + %clauses = (((% as lua expr)::as smext) for % in %items) return (Lua value "(\(%clauses::joined with " + "))") parse [if all of %items %body, if all of %items then %body] as (..) @@ -118,7 +118,7 @@ parse [unless none of %items %body else %else, unless none of %items then %body compile [product of %items, product %items] to: unless (%items.type is "List"): return (Lua value "utils.product(\(%items as lua expr))") - %clauses = ((% as lua expr) for % in %items) + %clauses = (((% as lua expr)::as smext) for % in %items) return (Lua value "(\(%clauses::joined with " * "))") action [avg of %items, average of %items] (=lua "(utils.sum(\%items)/#\%items)") diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom index 00151d5..6a457d9 100644 --- a/core/metaprogramming.nom +++ b/core/metaprogramming.nom @@ -23,7 +23,7 @@ lua> "\ ..COMPILE_ACTIONS["1 -> 2"] = function(nomsu, tree, \%args, \%body) local lua = LuaCode.Value(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) + local lua_args = table.map(\%args, function(a) return AST.is_syntax_tree(a) and nomsu:compile(a):as_smext() 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) @@ -64,14 +64,14 @@ test: assume (%tmp is (nil)) or barf "compile to is leaking variables" lua> "\ ..COMPILE_ACTIONS["compile 1 to 2"] = 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 \%args = {"nomsu", "tree", unpack(table.map(\%actions[1]:get_args(), function(a) return nomsu:compile(\ + ..a):as_smext() end))} local lua = LuaCode(tree.source, "COMPILE_ACTIONS[", \%actions[1].stub:as_lua(), "] = ", \(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))} + local \%alias_args = {"nomsu", "tree", unpack(table.map(alias:get_args(), function(a) return nomsu:compile(\ + ..a):as_smext() end))} lua:append("\\nCOMPILE_ACTIONS[", alias.stub:as_lua(), "] = ") if utils.equivalent(\%args, \%alias_args) then lua:append("COMPILE_ACTIONS[", \%actions[1].stub:as_lua(), "]") @@ -114,14 +114,14 @@ test: compile [local action %actions %body] to: lua> "\ ..local fn_name = \%actions[1].stub:as_lua_id() - local \%args = table.map(\%actions[1]:get_args(), function(a) return tostring(nomsu:compile(a)) end) + local \%args = table.map(\%actions[1]:get_args(), function(a) return nomsu:compile(a):as_smext() 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 = alias.stub:as_lua_id() lua:add_free_vars({alias_name}) - local \%alias_args = table.map(alias:get_args(), function(a) return tostring(nomsu:compile(a)) end) + local \%alias_args = table.map(alias:get_args(), function(a) return nomsu:compile(a):as_smext() end) lua:append("\\n", alias_name, " = ") if utils.equivalent(\%args, \%alias_args) then lua:append(fn_name) @@ -170,7 +170,7 @@ 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)) + replacements[arg[1]] = nomsu:compile(arg):as_smext() end local function make_tree(t) if AST.is_syntax_tree(t, "Var") then @@ -239,7 +239,7 @@ action [%var as lua identifier, %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 + if not lua:as_smext():match("^[_a-zA-Z][_a-zA-Z0-9]*$") then nomsu:compile_error(\%var, "This is not a valid Lua identifier.") end return lua diff --git a/core/operators.nom b/core/operators.nom index 3ae7c2f..960440e 100644 --- a/core/operators.nom +++ b/core/operators.nom @@ -34,7 +34,7 @@ compile [%var = %value] to: lua> "\ ..local lua = LuaCode(tree.source, \%var_lua, ' = ', \%value_lua, ';') if \%var.type == 'Var' then - lua:add_free_vars({tostring(nomsu:compile(\%var))}) + lua:add_free_vars({nomsu:compile(\%var):as_smext()}) end return lua" @@ -66,7 +66,7 @@ compile [set %assignments] to: %value as text ..) end if \%target.type == "Var" then - lhs:add_free_vars({tostring(target_lua)}) + lhs:add_free_vars({target_lua:as_smext()}) end if i > 1 then lhs:append(", ") @@ -107,7 +107,7 @@ test: compile [with external %externs %body] to: %body_lua = (%body as lua statements) lua> "\ - ..\%body_lua:remove_free_vars(table.map(\%externs, function(v) return tostring(nomsu:compile(v)) end))" + ..\%body_lua:remove_free_vars(table.map(\%externs, function(v) return nomsu:compile(v):as_smext() end))" return %body_lua test: @@ -141,7 +141,7 @@ compile [with %assignments %body] to: lhs:append(target_lua) rhs:append(value_lua) if \%target.type == "Var" then - vars[i] = tostring(target_lua) + vars[i] = target_lua:as_smext() end end \%lua:remove_free_vars(vars) diff --git a/nomnom/ast.nom b/nomnom/ast.nom index da1d0c4..377f4ae 100644 --- a/nomnom/ast.nom +++ b/nomnom/ast.nom @@ -16,6 +16,8 @@ object (Syntax Tree): %stub_bits::add "\%argnum" %argnum += 1 %me.stub = (%stub_bits::joined with " ") + if (%me.stub == "Lua Code 1 2"): + lua> "require('ldt').breakpoint()" (Syntax Tree).source_code_for_tree = (..) {} with fallback % -> (read file %.source.filename) @@ -86,3 +88,4 @@ object (Syntax Tree): %args::add % return %args +(Syntax Tree).map = (Syntax Tree).map_1 diff --git a/nomnom/code_obj.nom b/nomnom/code_obj.nom index 7ff1b23..f573599 100644 --- a/nomnom/code_obj.nom +++ b/nomnom/code_obj.nom @@ -14,11 +14,10 @@ object (Code): for % in %old_bits: %me::add % - %depth = 0 my action [as text]: - external %depth = (%depth + 1) - if (%depth > 10): - lua> "require('ldt').breakpoint()" + barf "Not implemented" + + my action [as smext]: if (%me.__str == (nil)): set {%buff:[], %indent:0} for %bit in %me.bits: @@ -26,21 +25,21 @@ object (Code): %spaces = (%bit::matching "\n([ ]*)[^\n]*$") if %spaces: %indent = (size of %spaces.1) ..else: - %bit = "\%bit" + %bit = (%bit::as smext) if (%indent > 0): %bit = (%bit::with "\n" -> "\n\(" "::* %indent)") %buff::add %bit %me.__str = (%buff::joined) - external %depth = (%depth - 1) return %me.__str - my action [as lua] (..) - "\(%me.class.name::as lua id)_1_2(\(%me.source::as lua), \(%me.bits::as lua))" + my action [as lua]: + barf + return "\(%me.class.name::as lua id)_from_1_2(\(%me.source::as lua), \(%me.bits::as lua))" my action [as nomsu] (..) "(\(%me.class.name) \(%me.source::as nomsu) \(%me.bits::as nomsu))" - my action [size] (size of "\%me") + my action [size] (size of (%me::as smext)) my action [mark as dirty]: %me.__str = (nil) @@ -52,14 +51,14 @@ object (Code): %new_bits = [%new_bits] for % in %new_bits: if (% == ""): do next % - if ((% isn't text) and (% isn't a (Code))): + #if ((% isn't text) and (% isn't a (Code))): % = (%::as lua) %me.bits::add % %me::mark as dirty my action [trailing line length]: if (%me._trailing_line_len == (nil)): - %me._trailing_line_len = (size of ("\%me"::matching "[^\n]*$")) + %me._trailing_line_len = (size of ((%me::as smext)::matching "[^\n]*$")) return %me._trailing_line_len my action [number of lines]: @@ -83,7 +82,6 @@ object (Code): %line_len = 0 %bits = %me.bits for %value in %values at %i: - assume (%value != %me) if (%i > 1): if (%line_len > 80): %bits::add %wrapping_joiner @@ -91,7 +89,9 @@ object (Code): ..else: %bits::add %joiner %bits::add %value - %line = ("\%value"::matching "\n([^\n]*)$") + unless (%value is text): + %value = (%value::as smext) + %line = (%value::matching "\n([^\n]*)$") if %line: %line_len = (size of %line) ..else: @@ -99,7 +99,7 @@ object (Code): %me::mark as dirty my action [prepend %]: - if ((% isn't text) and (% isn't a %me.__type)): + #if ((% isn't text) and (% isn't a %me.__type)): % = (%::as lua) %me.bits::add % at index 1 %me::mark as dirty @@ -129,29 +129,30 @@ object (Lua Code) extends (Code): %removals.%var = (yes) %stack = [%me] - while ((size of %stack) > 0): + repeat while ((size of %stack) > 0): %lua = (%stack::pop) for %i in (size of %lua.free_vars) to 1 by -1: - if %removals.(%lua.%free_vars.%i): - %lua.free_vars::remove index %i + if %removals.(%lua.free_vars.%i): + lua> "table.remove(\%lua.free_vars, \%i)" + #TODO: reinstate this + #%lua.free_vars::remove at index %i for % in %lua.bits: - if (% is a "Lua Code"): + unless (% is text): %stack::add % %me::mark as dirty - my action [declare locals]: - set {%to_declare:[], %seen:{}} - for %lua in recursive %me: - for %var in %lua.free_vars: - unless %seen.%var: - %seen.%var = (yes) - %to_declare::add %var - for % in %lua.bits: - if (% is a "Lua Code"): - recurse %lua on % - return (%me::declare locals %to_declare) - + my action [declare locals] (%me::declare locals (nil)) my action [declare locals %to_declare]: + unless %to_declare: + set {%to_declare:[], %seen:{}} + for %lua in recursive %me: + for %var in %lua.free_vars: + unless %seen.%var: + %seen.%var = (yes) + %to_declare::add %var + for % in %lua.bits: + unless (% is text): + recurse %lua on % if ((size of %to_declare) > 0): %me::remove free vars %to_declare %me::prepend "local \(%to_declare::joined with ", ");\n" @@ -163,11 +164,11 @@ object (Lua Code) extends (Code): unless %me.is_value: return %me %statements = (Lua Code from %me.source []) - if (%prefix != ""): + if ((%prefix or "") != ""): %statements::add %prefix %statements::add %me if (%suffix != ""): - %statements::add %suffix + %statements::add (%suffix or ";") return %statements action [Lua Code from %source %bits]: @@ -176,12 +177,17 @@ object (Lua Code) extends (Code): return (..) Lua Code {source:%source, bits:%bits, is_value:(no), free_vars:[]} action [Lua Code from %source] (Lua Code from %source []) - action [Lua Value from %tree %bits]: + action [Lua Value 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:(yes), free_vars:[]} - action [Lua Value from %tree] (Lua Value from %tree []) + action [Lua Value from %source] (Lua Value from %source []) + +(Lua Code).add_free_vars = (Lua Code).add_free_vars_1 +(Lua Code).remove_free_vars = (Lua Code).remove_free_vars_1 +(Lua Code).declare_locals = (Lua Code).declare_locals_1 +(Lua Code).as_statements = (Lua Code).as_statements_1_2 object (Nomsu Code) extends (Code): action [Nomsu Code from %source %bits]: diff --git a/nomnom/compile.nom b/nomnom/compile.nom index 19daa6a..64465bd 100644 --- a/nomnom/compile.nom +++ b/nomnom/compile.nom @@ -4,6 +4,7 @@ use "nomnom/code_obj.nom" use "nomnom/parser.nom" use "nomnom/pretty_errors.nom" +# TODO: use pretty_errors local action [report compile error at %pos %err]: barf "Compile error at \%pos: \%err" @@ -23,7 +24,9 @@ action [compile %tree using %compile_actions]: %compile_action = %compile_actions.%stub # Don't apply compiler actions to methods if (%compile_action and (not %tree.target)): - %args = ["tree", "compile_actions"] + # TODO: restore this: + #%args = [%tree, %compile_actions] + %args = [%nomsu, %tree] for % in (%tree::get args): %args::add % %result = (call %compile_action with %args) if (%result == (nil)): @@ -43,7 +46,7 @@ action [compile %tree using %compile_actions]: %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]*$")): + if (((%target_lua::as smext)::matches "^%(.*%)$") or ((%target_lua::as smext)::matches "^[_a-zA-Z][_a-zA-Z0-9]*$")): %lua::add [%target_lua, ":"] ..else: %lua::add ["(", %target_lua, "):"] @@ -51,12 +54,13 @@ action [compile %tree using %compile_actions]: %args = [] for %tok in %tree at %i: if (%tok is text): do next %tok - # TODO: maybe translate Lua comments - if (%tok.type == "Comment"): do next %tok + # TODO: maybe don't translate Lua comments + #if (%tok.type == "Comment"): do next %tok if (%tok.type == "Block"): - %values = (..) - (compile %line using %compile_actions) for %line in %tok - ..unless (%line.type == "Comment") + %values = [] + for %line in %tok: + #unless (%line.type == "Comment"): + %values::add (compile %line using %compile_actions) if all of (%.is_value for % in %values): if ((size of %values) == 1): %arg_lua = %values.1 @@ -153,11 +157,11 @@ action [compile %tree using %compile_actions]: unless %value_lua.is_value: report 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_]*)['\"]$") + %key_str = ((%key_lua::as smext)::matching "^[\"']([a-zA-Z_][a-zA-Z0-9_]*)['\"]$") if: %key_str: return (Lua Code from %tree [%key_str, "=", %value_lua]) - ("\%key_lua".1 == "["): + ((%key_lua::as smext).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"] @@ -170,7 +174,7 @@ action [compile %tree using %compile_actions]: unless %lua.is_value: report compile error at %tree.1 "\ ..Can't index into this, since it's not an expression." - %first_char = "\%lua".1 + %first_char = (%lua::as smext).1 if (any of [%first_char == "{", %first_char == "\"", %first_char == "["]): %lua::parenthesize @@ -180,7 +184,7 @@ action [compile %tree using %compile_actions]: unless %key_lua.is_value: report compile error at %key "\ ..Can't use this as an index, since it's not an expression." - %key_lua_str = "\%key_lua" + %key_lua_str = (%key_lua::as smext) %lua_id = (%key_lua_str::matching "^['\"]([a-zA-Z_][a-zA-Z0-9_]*)['\"]$") if: %lua_id: @@ -206,8 +210,8 @@ action [compile %tree using %compile_actions]: ..compilation depends on the earlier chunks" "Comment": - # TODO: implement? - return (Lua Code from %tree) + # TODO: de-implement? + return (Lua Code from %tree "-- \(%tree.1::with "\n" -> "\n-- ")") "Error": barf "Can't compile errors" diff --git a/nomnom/decompile.nom b/nomnom/decompile.nom index e002f61..58679a2 100644 --- a/nomnom/decompile.nom +++ b/nomnom/decompile.nom @@ -266,7 +266,7 @@ action [decompile %tree]: (((size of %line) > 10) and ((%nomsu::trailing line length) > %max_line)): %nomsu::add "\\\n.." - while ((size of %line) > 0): + repeat while ((size of %line) > 0): %space = (%max_line - (%nomsu::trailing line length)) %split = (%line::position of "[%p%s]" after %space) if ((not %split) or (%split > %space + 10)): diff --git a/nomnom/parser.nom b/nomnom/parser.nom index ef06e08..0be394c 100644 --- a/nomnom/parser.nom +++ b/nomnom/parser.nom @@ -30,7 +30,7 @@ set {..} Tree: [%t, %userdata] ->: %source = (..) Source {filename:%userdata.filename, start:%t.start, stop:%t.stop} - set {%t.start: nil, %t.stop: nil} + set {%t.start: nil, %t.stop: nil, %t.source: %source} %t = (Syntax Tree %t) (Syntax Tree).source_code_for_tree.%t = %userdata.source return %t diff --git a/syntax_tree.moon b/syntax_tree.moon index d2f5d37..926ea09 100644 --- a/syntax_tree.moon +++ b/syntax_tree.moon @@ -6,7 +6,7 @@ unpack or= table.unpack AST = {} 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) + type(n) == 'table' and getmetatable(n) and getmetatable(n).__type == "Syntax Tree" and (t == nil or n.type == t) as_lua = => if type(@) == 'number' @@ -25,6 +25,7 @@ for name in *types .__index = cls .__name = name .type = name + .__type = "Syntax Tree" .is_instance = (x)=> getmetatable(x) == @ .__tostring = => bits = [tostring(b) for b in *@] -- cgit v1.2.3 From b7e768a2f826f6643e47b35272dbb35136d489b6 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Fri, 28 Sep 2018 22:15:24 -0700 Subject: Rebuild. --- code_obj.lua | 29 ++++++++++++++--------------- containers.lua | 2 ++ syntax_tree.lua | 3 ++- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/code_obj.lua b/code_obj.lua index 577eaf3..a8d7adf 100644 --- a/code_obj.lua +++ b/code_obj.lua @@ -78,7 +78,7 @@ do local _class_0 local _base_0 = { is_code = true, - __tostring = function(self) + as_smext = function(self) if self.__str == nil then local buff, indent = { }, 0 local match, gsub, rep @@ -95,7 +95,7 @@ do end end else - b = tostring(b) + b = b:as_smext() if indent > 0 then b = gsub(b, "\n", "\n" .. rep(" ", indent)) end @@ -106,6 +106,9 @@ do end return self.__str end, + __tostring = function(self) + return self:as_smext() + end, as_lua = function(self) return tostring(self.__class.__name) .. "(" .. tostring(concat({ tostring(self.source):as_lua(), @@ -123,13 +126,13 @@ do }, ", ")) .. ")" end, __len = function(self) - return #tostring(self) + return #self:as_smext() end, match = function(self, ...) - return tostring(self):match(...) + return self:as_smext():match(...) end, gmatch = function(self, ...) - return tostring(self):gmatch(...) + return self:as_smext():gmatch(...) end, dirty = function(self) self.__str = nil @@ -155,9 +158,6 @@ do if b.is_code then b.dirty = error end - if type(b) ~= 'string' and not (type(b) == 'table' and b.is_code) then - b = b:as_lua() - end bits[#bits + 1] = b _continue_0 = true until true @@ -169,7 +169,7 @@ do end, trailing_line_len = function(self) if self._trailing_line_len == nil then - self._trailing_line_len = #tostring(self):match("[^\n]*$") + self._trailing_line_len = #self:as_smext():match("[^\n]*$") end return self._trailing_line_len end, @@ -212,7 +212,9 @@ do if b.is_code then b.dirty = error end - b = tostring(b) + if not (type(b) == 'string') then + b = b:as_smext() + end local line = match(b, "\n([^\n]*)$") if line then line_len = #line @@ -233,9 +235,6 @@ do if b.is_code then b.dirty = error end - if type(b) ~= 'string' and not (type(b) == 'table' and b.is_code) then - b = b:as_lua() - end bits[i] = b end return self:dirty() @@ -253,7 +252,6 @@ do if type(self.source) == 'string' then self.source = Source:from_string(self.source) end - assert(self.source and Source:is_instance(self.source), "Source has the wrong type") return self:append(...) end, __base = _base_0, @@ -402,8 +400,9 @@ do end else walk(b, pos) + b = b:as_smext() end - pos = pos + #tostring(b) + pos = pos + #b end end walk(self, 1) diff --git a/containers.lua b/containers.lua index ab632c4..b51b133 100644 --- a/containers.lua +++ b/containers.lua @@ -216,6 +216,8 @@ local _list_mt = { return rawset(self, k, v) end } +_list_mt.__index.as_lua = _list_mt.as_lua +_list_mt.__index.as_nomsu = _list_mt.as_nomsu List = function(t) return setmetatable(t, _list_mt) end diff --git a/syntax_tree.lua b/syntax_tree.lua index afdb631..851711a 100644 --- a/syntax_tree.lua +++ b/syntax_tree.lua @@ -11,7 +11,7 @@ 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) + return type(n) == 'table' and getmetatable(n) and getmetatable(n).__type == "Syntax Tree" and (t == nil or n.type == t) end local as_lua as_lua = function(self) @@ -54,6 +54,7 @@ for _index_0 = 1, #types do cls.__index = cls cls.__name = name cls.type = name + cls.__type = "Syntax Tree" cls.is_instance = function(self, x) return getmetatable(x) == self end -- cgit v1.2.3 From 0c982d2aa285e6c095470667c1d0c21999ddad58 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Fri, 28 Sep 2018 22:16:10 -0700 Subject: Oops, refactor bug. --- core/control_flow.nom | 1 + 1 file changed, 1 insertion(+) diff --git a/core/control_flow.nom b/core/control_flow.nom index 243df96..48b9c85 100644 --- a/core/control_flow.nom +++ b/core/control_flow.nom @@ -522,6 +522,7 @@ compile [do %action then always %final_action] to: .. if not \(mangle "ok") then error(ret, 0) end if not \(mangle "fell_through") then return ret end end" + return %lua test: assume ((result of (: return 99)) == 99) -- cgit v1.2.3 From 1a3137a210f7886677c6672c26081152318252a3 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Mon, 1 Oct 2018 15:25:11 -0700 Subject: Fixed some misnamed functions. --- containers.lua | 6 +++--- containers.moon | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/containers.lua b/containers.lua index b51b133..ab8647e 100644 --- a/containers.lua +++ b/containers.lua @@ -399,7 +399,7 @@ do return List(lines(self)) end, line_1 = line, - wrap_to_1 = function(self, maxlen) + wrapped_to_1 = function(self, maxlen) local _lines = { } local _list_0 = self:lines() for _index_0 = 1, #_list_0 do @@ -418,10 +418,10 @@ do line_at_1 = function(self, i) return (line_at(self, i)) end, - line_number_of_1 = function(self, i) + line_number_at_1 = function(self, i) return select(2, line_at(self, i)) end, - line_position_of_1 = function(self, i) + line_position_at_1 = function(self, i) return select(3, line_at(self, i)) end, matches_1 = function(self, patt) diff --git a/containers.moon b/containers.moon index 0fb9271..1b0e650 100644 --- a/containers.moon +++ b/containers.moon @@ -153,7 +153,7 @@ do bytes: => List{byte(tostring(@), 1, -1)}, lines: => List(lines(@)) line_1: line - wrap_to_1: (maxlen)=> + wrapped_to_1: (maxlen)=> _lines = {} for line in *@lines! while #line > maxlen @@ -166,8 +166,8 @@ do return table.concat(_lines, "\n") line_at_1: (i)=> (line_at(@, i)) - line_number_of_1: (i)=> select(2, line_at(@, i)) - line_position_of_1: (i)=> select(3, line_at(@, i)) + line_number_at_1: (i)=> select(2, line_at(@, i)) + line_position_at_1: (i)=> select(3, line_at(@, i)) matches_1: (patt)=> match(@, patt) and true or false matching_1: (patt)=> (match(@, patt)) matching_groups_1: (patt)=> {match(@, patt)} -- cgit v1.2.3 From 331b22b3a3b61313a65ea6c49e2930b67f7ce82b Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Mon, 1 Oct 2018 15:25:27 -0700 Subject: Got compiler errors actually working. --- nomnom/compile.nom | 10 ++++----- nomnom/pretty_errors.nom | 57 ++++++++++++++++++++++++++++-------------------- 2 files changed, 38 insertions(+), 29 deletions(-) diff --git a/nomnom/compile.nom b/nomnom/compile.nom index 64465bd..3d7c5b0 100644 --- a/nomnom/compile.nom +++ b/nomnom/compile.nom @@ -5,11 +5,11 @@ use "nomnom/parser.nom" use "nomnom/pretty_errors.nom" # TODO: use pretty_errors -local action [report compile error at %pos %err]: - barf "Compile error at \%pos: \%err" +local action [report compile error at %tree %err]: + barf (pretty "Compile Error" error at %tree %err) local action [report compile error at %pos %err hint %hint]: - barf "Compile error at \%pos: \%err\n\%hint" + barf (pretty "Compile Error" error at %tree %err hint %hint) action [compile %tree using %compile_actions]: assume (%tree is a "Syntax Tree") @@ -30,13 +30,13 @@ action [compile %tree using %compile_actions]: for % in (%tree::get args): %args::add % %result = (call %compile_action with %args) if (%result == (nil)): - report compile error at %tree.source "\ + report compile error at %tree "\ ..The compile-time action here (\(%tree.stub)) failed to return any value." ..hint "\ ..Look at the implementation of (\(%tree.stub)) and make sure it's returning something." if (%result is a "Syntax Tree"): if (%result == %tree): - report compile error at %tree.source "\ + report compile error at %tree "\ ..The compile-time action here (\(%tree.stub)) is producing an endless loop." ..hint "\ ..Look at the implementation of (\(%tree.stub)) and make sure it's not just returning the original tree." diff --git a/nomnom/pretty_errors.nom b/nomnom/pretty_errors.nom index ffc6fd1..f32b849 100644 --- a/nomnom/pretty_errors.nom +++ b/nomnom/pretty_errors.nom @@ -4,7 +4,7 @@ local action [visible size of %text]: return (size of (%text::with "\027%[[0-9;]*m" -> "")) -local action [boxed %text]: +local action [%text boxed]: %max_line = (..) max of ((visible size of %line) for %line in (%text::lines)) %ret = (..) @@ -13,31 +13,35 @@ local action [boxed %text]: "\n\%\(" "::* (%max_line - (visible size of %))) \027[0m" return %ret.[2,-1] -action [%err as a pretty error]: - %context = 2 - %err_code = (%err::get source code) - %err_line = (%err_code::line at %err.source.start) - %err_linenum = (%err_code::line number at %err.source.start) - %err_linepos = (%err_code::line position at %err.source.start) +%CONTEXT = 2 +action [pretty %title error at %tree %err hint %hint]: + %source_code = (%tree::get source code) + %start = %tree.source.start + %stop = %tree.source.stop + %filename = (%tree.source.filename or "???") + + %err_line = (%source_code::line at %start) + %err_linenum = (%source_code::line number at %start) + %err_linepos = (%source_code::line position at %start) # TODO: better handle multi-line errors %err_size = (..) min of [..] - %err.source.stop - %err.source.start + %stop - %start (size of %err_line) - %err_linepos + 1 %nl_indicator = (" " if (%err_linepos > (size of %err_line)) else "") - %fmt_str = " %\(size of "\(%err_linenum + %context)")d|" - local action [num %i] (%fmt_str::formatted with 0) + %fmt_str = " %\(size of "\(%err_linenum + %CONTEXT)")d|" + local action [num %i] (%fmt_str::formatted with %i) %linenum_size = (size of (num 0)) %pointer = "\(" "::* (%err_linepos + %linenum_size - 1))" if (%err_size >= 2): - %pointer += "\(%pointer)╚\("═"::* (%err_size - 2))╝" + %pointer += "╚\("═"::* (%err_size - 2))╝" ..else: - %pointer += "\(%pointer)⬆" + %pointer += "⬆" - %err_msg = "\027[33;41;1m\(%err.title or "Error") at \(%err.source.filename or "???"):\(%err_linenum)\027[0m" - for %i in (%err_linenum - %context) to (%err_linenum - 1): - %line = (%err_code::line %i) + %err_msg = "\027[33;41;1m\(%title or "Error") at \(%filename):\(%err_linenum)\027[0m" + for %i in (%err_linenum - %CONTEXT) to (%err_linenum - 1): + %line = (%source_code::line %i) if %line: %err_msg += "\n\027[2m\(num %i)\027[0m\(%line)\027[0m" if %err_line: @@ -45,15 +49,15 @@ action [%err as a pretty error]: %during = %err_line.[%err_linepos, %err_linepos + %err_size - 1] %after = %err_line.[%err_linepos + %err_size, -1] %err_line = "\027[0m\(%before)\027[41;30m\(%during)\(%nl_indicator)\027[0m\(%after)" - %err_msg += "\n\027[2m\(%fmt_str::formated with %err_linenum)\(%err_line)\027[0m" - %err_linenum_end = (%err_code::line number at %err.source.stop) - %err_linepos_end = (%err_code::line position at %err.source.stop) + %err_msg += "\n\027[2m\(num %err_linenum)\(%err_line)\027[0m" + %err_linenum_end = (%source_code::line number at %stop) + %err_linepos_end = (%source_code::line position at %stop) %err_linenum_end or= %err_linenum if (%err_linenum_end == %err_linenum): %err_msg += "\n\(%pointer)" ..else: for %i in (%err_linenum + 1) to %err_linenum_end: - %line = (%err_code::line %i) + %line = (%source_code::line %i) if %line: if (%i == %err_linenum_end): %during = %line.[1, %err_linepos_end - 1] @@ -64,13 +68,18 @@ action [%err as a pretty error]: %box_width = 70 %err_text = "\ - ..\027[47;31;1m\((" \(%err.error)"::wrapped to %box_width)::with "\n" -> "\n\027[47;31;1m ")" - if %err.hint: - err_text += "\n\027[47;30m\((" Suggestion: \(%err.hint)"::wrapped to %box_width)::with "\n" -> "\n\027[47;30m ")" + ..\027[47;31;1m\((" \(%err)"::wrapped to %box_width)::with "\n" -> "\n\027[47;31;1m ")" + if %hint: + %err_text += "\n\027[47;30m\((" Suggestion: \(%hint)"::wrapped to %box_width)::with "\n" -> "\n\027[47;30m ")" %err_msg += "\n\027[33;1m \((%err_text boxed)::with "\n" -> "\n ")" - for %i in (%err_linenum_end + 1) to (%err_linenum_end + %context): - %line = (%err_code::line %i) + for %i in (%err_linenum_end + 1) to (%err_linenum_end + %CONTEXT): + %line = (%source_code::line %i) if %line: %err_msg += "\n\027[2m\(num %i)\027[0m\(%line)\027[0m" return %err_msg + +action [pretty %title error at %tree %err] (pretty %title error at %tree %err (nil)) + +action [%err_tree as a pretty error] (..) + pretty %err_tree.title error at %err_tree %err_tree.error hint %err_tree.hint -- cgit v1.2.3 From b615cb5c8e638cffe77bbe5cb86c9362e2b2fc18 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Wed, 3 Oct 2018 16:14:17 -0700 Subject: Fixed up some edge cases with as_lua_id and from_lua_id that were producing bad results. --- string2.lua | 25 +++++++++++++++++++++---- string2.moon | 13 +++++++------ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/string2.lua b/string2.lua index 1f15fed..ae0e49d 100644 --- a/string2.lua +++ b/string2.lua @@ -143,8 +143,6 @@ local string2 = { return '"' .. escaped .. '"' end, as_lua_id = function(str) - local orig = str - str = gsub(str, "^ *$", "%1 ") str = gsub(str, "x([0-9A-F][0-9A-F])", "x78%1") str = gsub(str, "%W", function(c) if c == ' ' then @@ -159,18 +157,37 @@ local string2 = { return str end, from_lua_id = function(str) - if not (is_lua_id("^_+(.*)$")) then + if not (is_lua_id(str:match("^_*(.*)$"))) then str = str:sub(2, -1) end str = gsub(str, "_", " ") str = gsub(str, "x([0-9A-F][0-9A-F])", function(hex) return char(tonumber(hex, 16)) end) - str = gsub(str, "^ ([ ]*)$", "%1") return str end } for k, v in pairs(string) do string2[k] = string2[k] or v end +local _list_0 = { + "", + "_", + " ", + "return", + "asdf", + "one two", + "one_two", + "Hex2Dec", + "He-ec", + "\3" +} +for _index_0 = 1, #_list_0 do + local test = _list_0[_index_0] + local lua_id = string2.as_lua_id(test) + assert(is_lua_id(lua_id), "failed to convert '" .. tostring(test) .. "' to a valid Lua identifier (got '" .. tostring(lua_id) .. "')") + local roundtrip = string2.from_lua_id(lua_id) + assert(roundtrip == test, "Failed lua_id roundtrip: '" .. tostring(test) .. "' -> " .. tostring(lua_id) .. " -> " .. tostring(roundtrip)) +end +assert(string2.as_lua_id('') == '_') return string2 diff --git a/string2.moon b/string2.moon index 140c586..8d2f3f9 100644 --- a/string2.moon +++ b/string2.moon @@ -67,10 +67,6 @@ string2 = { -- but not idempotent. In logic terms: (x != y) => (as_lua_id(x) != as_lua_id(y)), -- but not (as_lua_id(a) == b) => (as_lua_id(b) == b). as_lua_id: (str)-> - orig = str - -- Empty strings are not valid lua identifiers, so treat them like " ", - -- and treat " " as " ", etc. to preserve injectivity. - str = gsub str, "^ *$", "%1 " -- Escape 'x' (\x78) 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. @@ -88,13 +84,18 @@ string2 = { -- 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 is_lua_id("^_+(.*)$") + unless is_lua_id(str\match("^_*(.*)$")) str = str\sub(2,-1) str = gsub(str, "_", " ") str = gsub(str, "x([0-9A-F][0-9A-F])", (hex)-> char(tonumber(hex, 16))) - str = gsub(str, "^ ([ ]*)$", "%1") return str } for k,v in pairs(string) do string2[k] or= v +for test in *{"", "_", " ", "return", "asdf", "one two", "one_two", "Hex2Dec", "He-ec", "\3"} + lua_id = string2.as_lua_id(test) + assert is_lua_id(lua_id), "failed to convert '#{test}' to a valid Lua identifier (got '#{lua_id}')" + roundtrip = string2.from_lua_id(lua_id) + assert roundtrip == test, "Failed lua_id roundtrip: '#{test}' -> #{lua_id} -> #{roundtrip}" + return string2 -- cgit v1.2.3 From 2f68357cb6800e97edd31abfc707d7c7905faa64 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Wed, 3 Oct 2018 16:26:24 -0700 Subject: Some incremental progress. --- nomnom/ast.nom | 5 ++++ nomnom/code_obj.nom | 55 +++++++++++++++++++++++++++++++----- nomnom/compile.nom | 78 ++++++++++++++++++++++++++++++++++++++++------------ nomnom/decompile.nom | 49 ++++++++++++++++----------------- nomnom/parser.nom | 4 +-- string2.lua | 1 - string2.moon | 2 +- syntax_tree.lua | 2 -- syntax_tree.moon | 4 +-- 9 files changed, 142 insertions(+), 58 deletions(-) diff --git a/nomnom/ast.nom b/nomnom/ast.nom index 377f4ae..816554c 100644 --- a/nomnom/ast.nom +++ b/nomnom/ast.nom @@ -64,6 +64,11 @@ object (Syntax Tree): %replacement.%k = %r unless %changes: return %me return (Syntax Tree %replacement) + + my action [with %overrides]: + %new = (%k = %v for %k = %v in %me) + for %k = %v in %overrides: %new.%k = %v + return (Syntax Tree %new) my action [== %other]: unless (..) diff --git a/nomnom/code_obj.nom b/nomnom/code_obj.nom index f573599..363713c 100644 --- a/nomnom/code_obj.nom +++ b/nomnom/code_obj.nom @@ -4,10 +4,27 @@ use "lib/object.nom" +object (Hole): + action [Hole from %lua]: + return (Hole {lua:%lua}) + + my action [as lua]: + return %me.lua + + my action [as nomsu]: + return "(Hole {lua:\(%me.lua)})" + + my action [as text]: + barf "Not implemented" + + my action [as smext]: + barf "Must fill in holes before smexting" + + object (Code): my action [set up]: assume %me.source - %old_bits = %me.bits + %old_bits = (%me.bits if (%me.bits is a "List") else [%me.bits]) %me.bits = [] if (%me.source is text): %me.source = (Source from text %me.source) @@ -34,10 +51,10 @@ object (Code): my action [as lua]: barf - return "\(%me.class.name::as lua id)_from_1_2(\(%me.source::as lua), \(%me.bits::as lua))" + return "\(%me.class.name::as lua id)_from_1_2(\((%me.source::as lua) if %me.source else "nil"), \(%me.bits::as lua))" my action [as nomsu] (..) - "(\(%me.class.name) \(%me.source::as nomsu) \(%me.bits::as nomsu))" + "(\(%me.class.name) \((%me.source::as nomsu) if %me.source else "(nil)") \(%me.bits::as nomsu))" my action [size] (size of (%me::as smext)) @@ -170,20 +187,42 @@ object (Lua Code) extends (Code): if (%suffix != ""): %statements::add (%suffix or ";") return %statements + + my action [variables]: + %vars = [] + for %code in recursive %me: + if %code.is_variable: + %vars::add (%code::as smext) + for % in %code.bits: + unless (% is text): + recurse %code on % + return %vars action [Lua Code from %source %bits]: - if (%bits is text): %bits = [%bits] + assume %source + unless (%bits is a "List"): %bits = [%bits] if (%source is a "Syntax Tree"): %source = %source.source return (..) - Lua Code {source:%source, bits:%bits, is_value:(no), free_vars:[]} + Lua Code {source:%source, bits:%bits, is_value: no, free_vars:[]} action [Lua Code from %source] (Lua Code from %source []) + action [Lua Value from %source %bits]: - if (%bits is text): %bits = [%bits] + assume %source + unless (%bits is a "List"): %bits = [%bits] if (%source is a "Syntax Tree"): %source = %source.source return (..) - Lua Code {source:%source, bits:%bits, is_value:(yes), free_vars:[]} + Lua Code {source:%source, bits:%bits, is_value: yes, free_vars:[]} action [Lua Value from %source] (Lua Value from %source []) + action [Lua Variable from %source] (Lua Variable from %source []) + action [Lua Variable from %source %bits]: + assume %source + unless (%bits is a "List"): %bits = [%bits] + if (%source is a "Syntax Tree"): %source = %source.source + return (..) + Lua Code {source:%source, bits:%bits, is_value: yes, is_variable: yes, free_vars:[]} + +# TODO: remove this shim (Lua Code).add_free_vars = (Lua Code).add_free_vars_1 (Lua Code).remove_free_vars = (Lua Code).remove_free_vars_1 (Lua Code).declare_locals = (Lua Code).declare_locals_1 @@ -196,3 +235,5 @@ object (Nomsu Code) extends (Code): return (..) Nomsu Code {source:%source, bits:%bits} action [Nomsu Code from %source] (Nomsu Code from %source []) + action [Nomsu Code %bits] (Nomsu Code from (nil) %bits) + action [Nomsu Code] (Nomsu Code from (nil) []) diff --git a/nomnom/compile.nom b/nomnom/compile.nom index 3d7c5b0..989bc04 100644 --- a/nomnom/compile.nom +++ b/nomnom/compile.nom @@ -4,14 +4,31 @@ use "nomnom/code_obj.nom" use "nomnom/parser.nom" use "nomnom/pretty_errors.nom" -# TODO: use pretty_errors local action [report compile error at %tree %err]: barf (pretty "Compile Error" error at %tree %err) local action [report compile error at %pos %err hint %hint]: barf (pretty "Compile Error" error at %tree %err hint %hint) -action [compile %tree using %compile_actions]: +action [barf any errors in %t]: + assume (%t is a "Syntax Tree") + %errs = [] + for % in recursive %t: + if (%.type == "Error"): + %errs::add % + for %k = %v in %: + if (%v is a "Syntax Tree"): + recurse % on %v + sort %errs by % -> %.source + %errs = ((% as a pretty error) for % in %errs) + if ((size of %errs) > 0): + if ((size of %errs) > 3): + %n = ((size of %errs) - 3) + for %i in 4 to (size of %errs): %errs.%i = (nil) + %errs::add "\027[31;1m +\%n additional errors...\027[0m\n" + barf (%errs::joined with "\n\n") + +action [%tree compiled with %compile_actions]: assume (%tree is a "Syntax Tree") if all of [..] %tree.version, action (Nomsu version) @@ -40,12 +57,12 @@ action [compile %tree using %compile_actions]: ..The compile-time action here (\(%tree.stub)) is producing an endless loop." ..hint "\ ..Look at the implementation of (\(%tree.stub)) and make sure it's not just returning the original tree." - return (compile %result using %compile_actions) + return (%result compiled with %compile_actions) return %result %lua = (Lua Value from %tree) if %tree.target: # Method call - %target_lua = (compile %tree.target using %compile_actions) + %target_lua = (%tree.target compiled with %compile_actions) if (((%target_lua::as smext)::matches "^%(.*%)$") or ((%target_lua::as smext)::matches "^[_a-zA-Z][_a-zA-Z0-9]*$")): %lua::add [%target_lua, ":"] ..else: @@ -60,7 +77,7 @@ action [compile %tree using %compile_actions]: %values = [] for %line in %tok: #unless (%line.type == "Comment"): - %values::add (compile %line using %compile_actions) + %values::add (%line compiled with %compile_actions) if all of (%.is_value for % in %values): if ((size of %values) == 1): %arg_lua = %values.1 @@ -76,7 +93,7 @@ action [compile %tree using %compile_actions]: %arg_lua::add ["\n ", %v] %arg_lua::add "\nend)())" ..else: - %arg_lua = (compile %tok using %compile_actions) + %arg_lua = (%tok compiled with %compile_actions) unless %arg_lua.is_value: if (%tok.type == "Action"): report compile error at %tok "\ @@ -96,12 +113,39 @@ action [compile %tree using %compile_actions]: return %lua "EscapedNomsu": - return (Lua Value from %tree ((%tree.1)::as nomsu)) + #return (Lua Value from %tree ((%tree.1)::as lua)) + + %lua = (Lua Value from %tree ["Syntax_Tree_1{type=", quote %tree.1.type]) + set {%needs_comma:no, %i:1} + local action [% as shmua]: + if (% is a "Lua number"): + return "\%" + if (% is a "Syntax Tree"): + return (% compiled with %compile_actions) + if (% is text): + return (quote %) + return (%::as lua) + + for %k = %v in (((%tree.1.type == "EscapedNomsu") and %tree) or %tree.1): + %lua::add ", " + if: + (%k == %i): + %i += 1 + ((%k is text) and (%k::is a lua identifier)): + %lua::add [%k, "= "] + else: + %lua::add ["[", % as shmua, "]= "] + if (%k == "source"): + %lua::add (quote "\%v") + ..else: + %lua::add (%v as shmua) + %lua::add "}" + return %lua "Block": %lua = (Lua Code from %tree) %lua::add (..) - ((compile %line using %compile_actions)::as statements) + ((%line compiled with %compile_actions)::as statements) ..for %line in %tree ..joined with "\n" return %lua @@ -117,7 +161,7 @@ action [compile %tree using %compile_actions]: if (%string_buffer != ""): %lua_bits::add (%string_buffer::as lua) %string_buffer = "" - %bit_lua = (compile % using %compile_actions) + %bit_lua = (% compiled with %compile_actions) unless %bit_lua.is_value: report compile error at % "\ ..Can't use this as a string interpolation value, since it doesn't have a value." @@ -135,24 +179,24 @@ action [compile %tree using %compile_actions]: "List": %lua = (Lua Value from %tree ["List{"]) - %lua::add ((compile % using %compile_actions) for % in %tree) joined with ", " or ",\n " + %lua::add ((% compiled with %compile_actions) for % in %tree) joined with ", " or ",\n " %lua::add "}" return %lua "Dict": %lua = (Lua Value from %tree ["Dict{"]) - %lua::add ((compile % using %compile_actions) for % in %tree) joined with ", " or ",\n " + %lua::add ((% compiled with %compile_actions) for % in %tree) joined with ", " or ",\n " %lua::add "}" return %lua "DictEntry": set {%key:%tree.1, %value:%tree.2} - %key_lua = (compile %key using %compile_actions) + %key_lua = (%key compiled with %compile_actions) unless %key_lua.is_value: report compile error at %tree.1 "\ ..Can't use this as a dict key, since it's not an expression." %value_lua = (..) - (compile %value using %compile_actions) if %value + (%value compiled with %compile_actions) if %value ..else (Lua Value from %key ["true"]) unless %value_lua.is_value: report compile error at %tree.2 "\ @@ -170,7 +214,7 @@ action [compile %tree using %compile_actions]: return (Lua Code from %tree ["[", %key_lua, "]=", %value_lua]) "IndexChain": - %lua = (compile %tree.1 using %compile_actions) + %lua = (%tree.1 compiled with %compile_actions) unless %lua.is_value: report compile error at %tree.1 "\ ..Can't index into this, since it's not an expression." @@ -180,7 +224,7 @@ action [compile %tree using %compile_actions]: for %i in 2 to (size of %tree): %key = %tree.%i - %key_lua = (compile %key using %compile_actions) + %key_lua = (%key compiled with %compile_actions) unless %key_lua.is_value: report compile error at %key "\ ..Can't use this as an index, since it's not an expression." @@ -202,7 +246,7 @@ action [compile %tree using %compile_actions]: return (Lua Value from %tree ["\(%tree.1)"]) "Var": - return (Lua Value from %tree [%tree.1::as lua id]) + return (Lua Variable from %tree [%tree.1::as lua id]) "FileChunks": barf "\ @@ -214,7 +258,7 @@ action [compile %tree using %compile_actions]: return (Lua Code from %tree "-- \(%tree.1::with "\n" -> "\n-- ")") "Error": - barf "Can't compile errors" + barf (%tree as a pretty error) else: barf "Unknown type: \(%tree.type)" diff --git a/nomnom/decompile.nom b/nomnom/decompile.nom index 58679a2..54afb08 100644 --- a/nomnom/decompile.nom +++ b/nomnom/decompile.nom @@ -3,13 +3,13 @@ use "nomnom/code_obj.nom" use "nomnom/parser.nom" # TODO: maybe re-implement the fancy coroutine checker that aborts early if nomsu gets too long -action [decompile %tree inline]: +action [%tree decompiled inline]: assume (%tree is a "Syntax Tree") if %tree.type is: "Action": %nomsu = (Nomsu Code from %tree) if %tree.target: - %target_nomsu = (decompile %tree.target inline) + %target_nomsu = (%tree.target decompiled inline) if %tree.target.type is: ("Action", "Block"): %target_nomsu::parenthesize @@ -25,7 +25,7 @@ action [decompile %tree inline]: ..: %nomsu::add " " %nomsu::add %bit ..else: - %arg_nomsu = (decompile %bit inline) + %arg_nomsu = (%bit decompiled inline) unless ((%i == (size of %tree)) and (%bit.type == "Block")): %nomsu::add " " if ((%bit.type == "Action") or (%bit.type == "Block")): @@ -34,7 +34,7 @@ action [decompile %tree inline]: return %nomsu "EscapedNomsu": - %inner_nomsu = (decompile %tree.1 inline) + %inner_nomsu = (%tree.1 decompiled inline) unless (..) any of [..] %tree.1.type == "List", %tree.1.type == "Dict", @@ -48,7 +48,7 @@ action [decompile %tree inline]: for %line in %tree at %i: %nomsu::add [..] " " if (%i == 1) else "; " - decompile %line inline + %line decompiled inline return %nomsu "Text": @@ -62,7 +62,7 @@ action [decompile %tree inline]: "Text": recurse %text on %bit "Var": - %interp_nomsu = (decompile %bit inline) + %interp_nomsu = (%bit decompiled inline) # Make sure "...\(%x)y..." isn't confused with "...\(%xy)..." # TODO: make this more robust against "...\%x\("y").." if (..) @@ -71,16 +71,16 @@ action [decompile %tree inline]: ..: %interp_nomsu::parenthesize %nomsu::add ["\\", %interp_nomsu] ("List", "Dict"): - %nomsu::add ["\\", decompile %bit inline] + %nomsu::add ["\\", %bit decompiled inline] else: - %nomsu::add ["\\(", decompile %bit inline, ")"] + %nomsu::add ["\\(", %bit decompiled inline, ")"] return (Nomsu Code from %tree ["\"", %nomsu, "\""]) ("List", "Dict"): %nomsu = (Nomsu Code from %tree ["[" if (%tree.type == "List") else "{"]) for %item in %tree at %i: if (%i > 1): %nomsu::add ", " - %nomsu::add (decompile %item inline) + %nomsu::add (%item decompiled inline) %nomsu::add ("]" if (%tree.type == "List") else "}") return %nomsu @@ -89,13 +89,13 @@ action [decompile %tree inline]: if (all of [%key.type == "Text", (size of %key) == 1, %key.1 is a nomsu identifier]): %nomsu = (Nomsu Code from %key [key.1]) ..else: - %nomsu = (decompile %key inline) + %nomsu = (%key decompiled inline) if (%key.type == "Action"): %nomsu::parenthesize %nomsu::add ":" if %value: - %nomsu::add (decompile %value inline) + %nomsu::add (%value decompiled inline) return %nomsu "IndexChain": @@ -108,7 +108,7 @@ action [decompile %tree inline]: %bit.1 is a nomsu identifier ..:%nomsu::add %bit.1 ..else: - %bit_nomsu = (decompile %bit inline) + %bit_nomsu = (%bit decompiled inline) if (..) any of [..] %bit.type == "Action" @@ -138,7 +138,7 @@ action [decompile %tree inline]: barf "Unknown type: \(%tree.type)" %MAX_LINE = 90 -action [decompile %tree]: +action [%tree decompiled]: %nomsu = (Nomsu Code from %tree) # For concision: local action [recurse on %t]: @@ -149,18 +149,18 @@ action [decompile %tree]: "Block": if ((size of %subtree) > 1): go to (Use Indented) - if ((size of "\(decompile %subtree inline)") > 20): + if ((size of "\(%subtree decompiled inline)") > 20): go to (Use Indented) for %k = %v in %subtree: if (%v is a "Syntax Tree"): recurse %subtree on %v - %inline_nomsu = (decompile %t inline) + %inline_nomsu = (%t decompiled inline) if (%inline_nomsu and ((size of "\%inline_nomsu") <= %space)): return %inline_nomsu === (Use Indented) === - %indented = (decompile %t) + %indented = (%t decompiled) if (%t.type == "Action"): %indented = (Nomsu Code from %t ["(..)\n ", %indented]) return %indented @@ -176,19 +176,16 @@ action [decompile %tree]: for %chunk in %tree at %chunk_no: if (%chunk_no > 1): %nomsu::add "\n\n\("~"::* 80)\n\n" - %nomsu::add (pop comments at %chunk.source.start) if (%chunk.type == "Block"): for %line in %chunk at %line_no: if (%line_no > 1): if (%chunk.(%line_no - 1) and %line should clump): - %nomsu::add ["\n", pop comments at %line.source.start "\n"] + %nomsu::add "\n" ..else: - %nomsu::add ["\n\n", pop comments at %line.source.start] - %nomsu::add (decompile %line %pop_comments) - %nomsu::add (pop comments at %chunk.source.stop "\n") + %nomsu::add "\n\n" + %nomsu::add (%line decompiled) ..else: - %nomsu::add (decompile %chunk %pop_comments) - %nomsu::add (pop comments at %tree.source.stop "\n") + %nomsu::add (%chunk decompiled) unless ("\%nomsu"::matches "\n$"): %nomsu::add "\n" return %nomsu @@ -300,7 +297,7 @@ action [decompile %tree]: %nomsu::add ("[]" if (%tree.type == "List") else "{}") return %nomsu for %item in %tree at %i: - %item_nomsu = (decompile %item inline) + %item_nomsu = (%item decompiled inline) if ((not %item_nomsu) or ((size of "\%item_nomsu") > %MAX_LINE)): %item_nomsu = (recurse on %item_nomsu) %nomsu::add %item_nomsu @@ -320,7 +317,7 @@ action [decompile %tree]: if (all of [%key.type == "Text", (size of %key) == 1, %key.1 is a nomsu identifier]): %nomsu::add %key.1 ..else: - %nomsu::add (decompile %key inline) + %nomsu::add (%key decompiled inline) if ((%key.type == "Action") or (%key.type == "Block")): %nomsu::parenthesize %nomsu::add [": ", recurse on %value] @@ -331,7 +328,7 @@ action [decompile %tree]: return %nomsu ("IndexChain", "Number", "Var"): - return (decompile %tree inline) + return (%tree decompiled inline) "Error": barf "Cannot decompile an error" diff --git a/nomnom/parser.nom b/nomnom/parser.nom index 0be394c..dfd5253 100644 --- a/nomnom/parser.nom +++ b/nomnom/parser.nom @@ -72,7 +72,7 @@ action [make parser from %peg] (make parser from %peg using (nil)) action [make parser from %peg using %make_tree]: %peg = (lpeg pattern %peg_tidier's match of %peg) %peg = (lpeg re pattern %peg using %defs) - local action [parse %input from %filename]: + local action [%input from %filename parsed]: %input = "\%input" %tree_mt = {__index: {source:%input, filename:%filename}} %userdata = {..} @@ -81,4 +81,4 @@ action [make parser from %peg using %make_tree]: %tree = (lpeg pattern %peg's match of %input with %userdata) assume %tree or barf "File \%filename failed to parse:\n\%input" return %tree - return (action (parse 1 from 2)) + return (action (1 from 2 parsed)) diff --git a/string2.lua b/string2.lua index ae0e49d..1cb89ba 100644 --- a/string2.lua +++ b/string2.lua @@ -189,5 +189,4 @@ for _index_0 = 1, #_list_0 do local roundtrip = string2.from_lua_id(lua_id) assert(roundtrip == test, "Failed lua_id roundtrip: '" .. tostring(test) .. "' -> " .. tostring(lua_id) .. " -> " .. tostring(roundtrip)) end -assert(string2.as_lua_id('') == '_') return string2 diff --git a/string2.moon b/string2.moon index 8d2f3f9..d70abe6 100644 --- a/string2.moon +++ b/string2.moon @@ -96,6 +96,6 @@ for test in *{"", "_", " ", "return", "asdf", "one two", "one_two", "Hex2Dec", " lua_id = string2.as_lua_id(test) assert is_lua_id(lua_id), "failed to convert '#{test}' to a valid Lua identifier (got '#{lua_id}')" roundtrip = string2.from_lua_id(lua_id) - assert roundtrip == test, "Failed lua_id roundtrip: '#{test}' -> #{lua_id} -> #{roundtrip}" + assert roundtrip == test, "Failed lua_id roundtrip: '#{test}' -> '#{lua_id}' -> '#{roundtrip}'" return string2 diff --git a/syntax_tree.lua b/syntax_tree.lua index 851711a..63c24ee 100644 --- a/syntax_tree.lua +++ b/syntax_tree.lua @@ -196,8 +196,6 @@ for _index_0 = 1, #types do __call = function(self, t) if type(t.source) == 'string' then t.source = Source:from_string(t.source) - else - assert(Source:is_instance(t.source)) end setmetatable(t, self) do diff --git a/syntax_tree.moon b/syntax_tree.moon index 926ea09..f3d3aee 100644 --- a/syntax_tree.moon +++ b/syntax_tree.moon @@ -82,8 +82,8 @@ for name in *types __call: (t)=> if type(t.source) == 'string' t.source = Source\from_string(t.source) - else - assert(Source\is_instance(t.source)) + --else + -- assert(Source\is_instance(t.source)) setmetatable(t, @) if init = t.__init then init(t) return t -- cgit v1.2.3 From be1df7ccd3fb5352ca666129aee93c56b5b27b40 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Wed, 3 Oct 2018 16:26:50 -0700 Subject: Recompile --- string2.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/string2.lua b/string2.lua index 1cb89ba..8e13171 100644 --- a/string2.lua +++ b/string2.lua @@ -187,6 +187,6 @@ for _index_0 = 1, #_list_0 do local lua_id = string2.as_lua_id(test) assert(is_lua_id(lua_id), "failed to convert '" .. tostring(test) .. "' to a valid Lua identifier (got '" .. tostring(lua_id) .. "')") local roundtrip = string2.from_lua_id(lua_id) - assert(roundtrip == test, "Failed lua_id roundtrip: '" .. tostring(test) .. "' -> " .. tostring(lua_id) .. " -> " .. tostring(roundtrip)) + assert(roundtrip == test, "Failed lua_id roundtrip: '" .. tostring(test) .. "' -> '" .. tostring(lua_id) .. "' -> '" .. tostring(roundtrip) .. "'") end return string2 -- cgit v1.2.3 From 23abab4f809e8d4b825746580082292db700036b Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Mon, 29 Oct 2018 13:00:08 -0700 Subject: Some cleanups and fixes, made the parser more permissive of prematurely terminated files. --- containers.lua | 7 +++++++ containers.moon | 4 ++++ core/control_flow.nom | 4 ++-- core/metaprogramming.nom | 2 +- core/operators.nom | 2 +- lib/object.nom | 23 +++++++++++------------ nomnom/decompile.nom | 6 +++--- nomsu.4.peg | 16 +++++++++------- nomsu_compiler.lua | 28 ++++++++++++++++------------ nomsu_compiler.moon | 20 +++++++++++++------- tools/find_action.nom | 4 ++-- 11 files changed, 69 insertions(+), 47 deletions(-) diff --git a/containers.lua b/containers.lua index ab8647e..8ab6c80 100644 --- a/containers.lua +++ b/containers.lua @@ -186,6 +186,13 @@ local _list_mt = { end return false end, + remove_1 = function(self, item) + for i, x in ipairs(self) do + if x == item then + remove(self, i) + end + end + end, index_of_1 = function(self, item) for i, x in ipairs(self) do if x == item then diff --git a/containers.moon b/containers.moon index 1b0e650..30dcfc8 100644 --- a/containers.moon +++ b/containers.moon @@ -73,6 +73,10 @@ _list_mt = if x == item return true return false + remove_1: (item)=> + for i,x in ipairs @ + if x == item + remove(@, i) index_of_1: (item)=> for i,x in ipairs @ if x == item diff --git a/core/control_flow.nom b/core/control_flow.nom index 48b9c85..37b2b9c 100644 --- a/core/control_flow.nom +++ b/core/control_flow.nom @@ -53,7 +53,7 @@ compile [..] %when_true_expr if %condition otherwise %when_false_expr %when_false_expr unless %condition else %when_true_expr %when_false_expr unless %condition then %when_true_expr -..to (..) +..to: # If %when_true_expr is guaranteed to be truthy, we can use Lua's idiomatic equivalent of a conditional expression: (cond and if_true or if_false) if {Text:yes, List:yes, Dict:yes, Number:yes}.(%when_true_expr.type): @@ -541,7 +541,7 @@ test: assume (sorted %flat) == [1, 2, 3, 4, 5, 6] # Recurion control flow -compile [for %var in recursive %structure %body] to (..) +compile [for %var in recursive %structure %body] to: with local compile actions: define mangler compile [recurse %v on %x] to (..) diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom index 6a457d9..d85c1ad 100644 --- a/core/metaprogramming.nom +++ b/core/metaprogramming.nom @@ -231,7 +231,7 @@ compile [%tree as nomsu] to (..) Lua value "nomsu:tree_to_nomsu(\(%tree as lua expr))" compile [%tree as inline nomsu] to (..) - Lua value "nomsu:tree_to_nomsu(\(%tree as lua expr), true)" + Lua value "nomsu:tree_to_inline_nomsu(\(%tree as lua expr), true)" action [%var as lua identifier, %var as lua id] (..) lua> "\ diff --git a/core/operators.nom b/core/operators.nom index 960440e..55756bb 100644 --- a/core/operators.nom +++ b/core/operators.nom @@ -157,7 +157,7 @@ compile [with %assignments %body] to: test: assume ((5 wrapped around 2) == 1) or barf "mod not working" compile [%x wrapped around %y, %x mod %y] to (..) - Lua value "(\(%x as lua expr) % \(%y as lua expr))" + Lua value "((\(%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) diff --git a/lib/object.nom b/lib/object.nom index 25ff644..bbc6e06 100644 --- a/lib/object.nom +++ b/lib/object.nom @@ -2,6 +2,15 @@ # This file contains the implementation of an Object-Oriented programming system. +%globals.METAMETHOD_MAP = {..} + "as text": "__tostring", "clean up": "__gc", + "+ 1": "__add", "- 1": "__sub", "* 1": "__mul", "/ 1": "__div", + "-": "__unm", "// 1": "__idiv", "mod 1": "__mod", "^ 1": "__pow", + "& 1": "__band", "| 1": "__bor", "~ 1": "__bxor", "~": "__bnot", + "<< 1": "__bshl", ">> 1": "__bshr", "== 1": "__eq", "< 1": "__lt", + "<= 1": "__le", "set 1 = 2": "__newindex", "size": "__len", + "iterate": "__ipairs", "iterate all": "__pairs", + test: object (Dog): (Dog).genus = "Canus" @@ -86,9 +95,7 @@ compile [object %classname extends %parent %class_body] to: __tostring=function(cls) return cls.name end, __call=function(cls, inst) inst = setmetatable(inst or {}, cls) - if inst.set_up then - inst:set_up() - end + if inst.set_up then inst:set_up() end return inst end, }) @@ -100,15 +107,7 @@ compile [object %classname extends %parent %class_body] to: return inst.name..getmetatable(_Dict{}).__tostring(inst) end \(%class_body as lua statements) - local metamethod_map = {["as text"]="__tostring", ["clean up"]="__gc", - ["+ 1"]="__add", ["- 1"]="__sub", ["* 1"]="__mul", ["/ 1"]="__div", - ["-"]="__unm", ["// 1"]="__idiv", ["mod 1"]="__mod", ["^ 1"]="__pow", - ["& 1"]="__band", ["| 1"]="__bor", ["~ 1"]="__bxor", ["~"]="__bnot", - ["<< 1"]="__bshl", [">> 1"]="__bshr", ["== 1"]="__eq", ["< 1"]="__lt", - ["<= 1"]="__le", ["set 1 = 2"]="__newindex", ["size"]="__len", - ["iterate"]="__ipairs", ["iterate all"]="__pairs", - } - for stub,metamethod in pairs(metamethod_map) do + for stub,metamethod in pairs(globals.METAMETHOD_MAP) do class[metamethod] = class[stub:as_lua_id()] end end" diff --git a/nomnom/decompile.nom b/nomnom/decompile.nom index 54afb08..fb64f7c 100644 --- a/nomnom/decompile.nom +++ b/nomnom/decompile.nom @@ -52,7 +52,7 @@ action [%tree decompiled inline]: return %nomsu "Text": - %nomsu = (Nomsu Code from %tree ["\""]) + %nomsu = (Nomsu Code from %tree []) for %text in recursive %tree: for %bit in %text at %i: if (%bit is text): @@ -87,14 +87,14 @@ action [%tree decompiled inline]: "DictEntry": set {%key:%tree.1, %value:%tree.2} if (all of [%key.type == "Text", (size of %key) == 1, %key.1 is a nomsu identifier]): - %nomsu = (Nomsu Code from %key [key.1]) + %nomsu = (Nomsu Code from %key [%key.1]) ..else: %nomsu = (%key decompiled inline) if (%key.type == "Action"): %nomsu::parenthesize - %nomsu::add ":" if %value: + %nomsu::add ":" %nomsu::add (%value decompiled inline) return %nomsu diff --git a/nomsu.4.peg b/nomsu.4.peg index 32a170f..06bfead 100644 --- a/nomsu.4.peg +++ b/nomsu.4.peg @@ -8,6 +8,8 @@ file: shebang: "#!" (!"nomsu" [^%nl])* "nomsu" ws+ "-V" ws* {:version: [0-9.]+ :} [^%nl]* +eof: !. + file_chunks (FileChunks): {:curr_indent: ' '* :} shebang? comment? blank_lines? @@ -71,7 +73,7 @@ tab_error (Error): section_division: ("~")^+3 eol inline_block: - "(" ws* inline_block ws* ")" / raw_inline_block + "(" ws* inline_block ws* (eof / ")") / raw_inline_block raw_inline_block (Block): (!"::") ":" ws* ((inline_statement (ws* ";" ws* inline_statement)*) / !(eol nl_indent)) indented_block (Block): @@ -89,7 +91,7 @@ noindex_inline_expression: / ( "(" ws* (inline_action / inline_expression) ws* (ws* ',' ws* (inline_action / inline_expression) ws*)* - (")" / missing_paren_err / unexpected_code) + (")" / eof / missing_paren_err / unexpected_code) ) inline_expression: index_chain / noindex_inline_expression indented_expression: @@ -130,7 +132,7 @@ text_word (Text): word inline_text (Text): !(indented_text) - '"' _inline_text* ('"' / missing_quote_err / unexpected_code) + '"' _inline_text* ('"' / eof / missing_quote_err / unexpected_code) _inline_text: {~ (('\"' -> '"') / ('\\' -> '\') / escaped_char / text_char+)+ ~} / inline_text_interpolation / illegal_char @@ -140,7 +142,7 @@ inline_text_interpolation: / ("(" ws* (inline_action / inline_expression) ws* (ws* ',' ws* (inline_action / inline_expression) ws*)* - (")" / missing_paren_err / unexpected_code)) + (")" / eof / missing_paren_err / unexpected_code)) ) text_char: %utf8_char / !["\] %print / %tab @@ -156,7 +158,7 @@ indented_text (Text): (('\' %nl+ {:curr_indent: indent :} ('..')?) / disallowed_interpolation? {%nl+} {:curr_indent: indent :}) (indented_plain_text / text_interpolation / illegal_char / {~ %nl+ (=curr_indent -> "") ~})* - ('"' eol / missing_quote_err) + ('"' eol / eof / missing_quote_err) {:curr_indent: %nil :} -- Tracking text-lines-within-indented-text as separate objects allows for better debugging line info indented_plain_text (Text): @@ -180,7 +182,7 @@ inline_list (List): !('[..]') "[" ws* (inline_list_item (ws* ',' ws* inline_list_item)* (ws* ',')?)? ws* - ("]" / (","? (missing_bracket_error / unexpected_code))) + ("]" / eof / (","? (missing_bracket_error / unexpected_code))) indented_list (List): "[..]" eol nl_indent list_line (nl_nodent list_line)* @@ -195,7 +197,7 @@ inline_dict (Dict): !('{..}') "{" ws* (inline_dict_entry (ws* ',' ws* inline_dict_entry)*)? ws* - ("}" / (","? (missing_brace_error / unexpected_code))) + ("}" / eof / (","? (missing_brace_error / unexpected_code))) indented_dict (Dict): "{..}" eol nl_indent dict_line (nl_nodent dict_line)* diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua index ff923ab..3d0580a 100644 --- a/nomsu_compiler.lua +++ b/nomsu_compiler.lua @@ -129,17 +129,21 @@ make_tree = function(tree, userdata) return tree end local Parsers = { } -local max_parser_version = 0 -for version = 1, 999 do - do - local peg_contents = Files.read("nomsu." .. tostring(version) .. ".peg") - if peg_contents then - max_parser_version = version - Parsers[version] = make_parser(peg_contents, make_tree) - else - break +local max_parser_version = 4 +for version = 1, max_parser_version do + local peg_file = io.open("nomsu." .. tostring(version) .. ".peg") + if not peg_file and package.nomsupath then + for path in package.nomsupath:gmatch("[^;]+") do + peg_file = io.open(path .. "/nomsu." .. tostring(version) .. ".peg") + if peg_file then + break + end end end + assert(peg_file, "could not find nomsu .peg file") + local peg_contents = peg_file:read('*a') + peg_file:close() + Parsers[version] = make_parser(peg_contents, make_tree) end local MAX_LINE = 80 local NomsuCompiler = setmetatable({ }, { @@ -199,9 +203,8 @@ do re = re, Files = Files, AST = AST, - TESTS = Dict({ }, { - globals = Dict({ }) - }), + TESTS = Dict({ }), + globals = Dict({ }), LuaCode = LuaCode, NomsuCode = NomsuCode, Source = Source, @@ -209,6 +212,7 @@ do __imported = Dict({ }), __parent = nil } + assert(NomsuCompiler.environment.globals) setmetatable(NomsuCompiler.environment, { __index = function(self, key) do diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon index e91db80..83cba68 100644 --- a/nomsu_compiler.moon +++ b/nomsu_compiler.moon @@ -77,12 +77,17 @@ make_tree = (tree, userdata)-> return tree Parsers = {} -max_parser_version = 0 -for version=1,999 - if peg_contents = Files.read("nomsu.#{version}.peg") - max_parser_version = version - Parsers[version] = make_parser(peg_contents, make_tree) - else break +max_parser_version = 4 +for version=1,max_parser_version + peg_file = io.open("nomsu.#{version}.peg") + if not peg_file and package.nomsupath + for path in package.nomsupath\gmatch("[^;]+") + peg_file = io.open(path.."/nomsu.#{version}.peg") + break if peg_file + assert(peg_file, "could not find nomsu .peg file") + peg_contents = peg_file\read('*a') + peg_file\close! + Parsers[version] = make_parser(peg_contents, make_tree) MAX_LINE = 80 -- For beautification purposes, try not to make lines much longer than this value NomsuCompiler = setmetatable {}, {__tostring: => "Nomsu"} @@ -105,12 +110,13 @@ with NomsuCompiler _List:List, _Dict:Dict, -- Utilities and misc. stringify:stringify, utils:utils, lpeg:lpeg, re:re, Files:Files, - :AST, TESTS: Dict{}, globals: Dict{} + :AST, TESTS: Dict({}), globals: Dict({}), :LuaCode, :NomsuCode, :Source nomsu:NomsuCompiler __imported: Dict{} __parent: nil } + assert .environment.globals setmetatable(.environment, { __index: (key)=> if imported = rawget(@, "__imported") diff --git a/tools/find_action.nom b/tools/find_action.nom index 8381855..e30f155 100755 --- a/tools/find_action.nom +++ b/tools/find_action.nom @@ -23,8 +23,8 @@ for %path in %files: %results::add {..} line: %line_num text: "\ - ..\(blue "\%filename:\%line_num:") - \(yellow (source lines of %t))" + ..\(blue "\%filename:\%line_num:") + \(yellow (source lines of %t))" if (%t is syntax tree): for %sub in %t: recurse %t on %sub -- cgit v1.2.3 From 8515a874271401927210e100b6dc0299c6afd0bf Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Mon, 29 Oct 2018 13:03:13 -0700 Subject: Bumped compiler version. --- nomsu_compiler.moon | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon index 83cba68..eb9ea45 100644 --- a/nomsu_compiler.moon +++ b/nomsu_compiler.moon @@ -93,7 +93,7 @@ MAX_LINE = 80 -- For beautification purposes, try not to make lines much longer NomsuCompiler = setmetatable {}, {__tostring: => "Nomsu"} _anon_chunk = 0 with NomsuCompiler - .NOMSU_COMPILER_VERSION = 9 + .NOMSU_COMPILER_VERSION = 10 .NOMSU_SYNTAX_VERSION = max_parser_version .can_optimize = -> false @@ -116,7 +116,6 @@ with NomsuCompiler __imported: Dict{} __parent: nil } - assert .environment.globals setmetatable(.environment, { __index: (key)=> if imported = rawget(@, "__imported") -- cgit v1.2.3 From fdf7a537c8ae13fc7ccb32278e5e364a52005443 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Tue, 30 Oct 2018 19:50:15 -0700 Subject: Versioning fixes. --- nomsu_compiler.lua | 5 +---- nomsu_compiler.moon | 4 +--- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua index 3d0580a..7aa117c 100644 --- a/nomsu_compiler.lua +++ b/nomsu_compiler.lua @@ -153,13 +153,11 @@ local NomsuCompiler = setmetatable({ }, { }) local _anon_chunk = 0 do - NomsuCompiler.NOMSU_COMPILER_VERSION = 9 - NomsuCompiler.NOMSU_SYNTAX_VERSION = max_parser_version NomsuCompiler.can_optimize = function() return false end NomsuCompiler.environment = { - NOMSU_COMPILER_VERSION = 8, + NOMSU_COMPILER_VERSION = 9, NOMSU_SYNTAX_VERSION = max_parser_version, next = next, unpack = unpack, @@ -212,7 +210,6 @@ do __imported = Dict({ }), __parent = nil } - assert(NomsuCompiler.environment.globals) setmetatable(NomsuCompiler.environment, { __index = function(self, key) do diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon index eb9ea45..387c901 100644 --- a/nomsu_compiler.moon +++ b/nomsu_compiler.moon @@ -93,13 +93,11 @@ MAX_LINE = 80 -- For beautification purposes, try not to make lines much longer NomsuCompiler = setmetatable {}, {__tostring: => "Nomsu"} _anon_chunk = 0 with NomsuCompiler - .NOMSU_COMPILER_VERSION = 10 - .NOMSU_SYNTAX_VERSION = max_parser_version .can_optimize = -> false -- Discretionary/convenience stuff .environment = { - NOMSU_COMPILER_VERSION: 8, NOMSU_SYNTAX_VERSION: max_parser_version + NOMSU_COMPILER_VERSION: 9, NOMSU_SYNTAX_VERSION: max_parser_version -- Lua stuff: :next, :unpack, :setmetatable, :coroutine, :rawequal, :getmetatable, :pcall, :error, :package, :os, :require, :tonumber, :tostring, :string, :xpcall, :module, -- cgit v1.2.3 From e7e84c9eda38c930f5475301de4a449dcf59e8b6 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Tue, 30 Oct 2018 20:32:14 -0700 Subject: Fix for compiler not parenthesizing method targets, fix for parser not recognizing \ line continuation, and improvements to upgrade tool API. --- nomsu.4.peg | 6 +++--- nomsu_compiler.lua | 6 +++++- nomsu_compiler.moon | 5 ++++- tools/upgrade.nom | 27 +++++++++++++++++---------- 4 files changed, 29 insertions(+), 15 deletions(-) diff --git a/nomsu.4.peg b/nomsu.4.peg index 06bfead..a3677c6 100644 --- a/nomsu.4.peg +++ b/nomsu.4.peg @@ -121,9 +121,9 @@ inline_action (Action): inline_arg: inline_expression / inline_block action (Action): !section_division - ({:target: arg :} (eol nl_nodent "..")? ws* "::" (eol nl_nodent "..")? ws*)? - ( (arg ((eol nl_nodent "..")? ws* (arg / word))+) - / (word ((eol nl_nodent "..")? ws* (arg / word))*)) + ({:target: arg :} ((ws* "\")? eol nl_nodent "..")? ws* "::" ((ws* "\")? eol nl_nodent "..")? ws*)? + ( (arg (((ws* "\")? eol nl_nodent "..")? ws* (arg / word))+) + / (word (((ws* "\")? eol nl_nodent "..")? ws* (arg / word))*)) arg: expression / inline_block / indented_block word: !number { operator_char+ / ident_char+ } diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua index 7aa117c..f9ba314 100644 --- a/nomsu_compiler.lua +++ b/nomsu_compiler.lua @@ -1005,7 +1005,11 @@ do elseif "Action" == _exp_0 then local nomsu = NomsuCode(tree.source) if tree.target then - nomsu:append(self:tree_to_inline_nomsu(tree.target), "::") + local inline_target = self:tree_to_inline_nomsu(tree.target) + if tree.target.type == "Action" then + inline_target:parenthesize() + end + nomsu:append(inline_target, "::") end for i, bit in ipairs(tree) do if type(bit) == "string" then diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon index 387c901..1106382 100644 --- a/nomsu_compiler.moon +++ b/nomsu_compiler.moon @@ -631,7 +631,10 @@ with NomsuCompiler when "Action" nomsu = NomsuCode(tree.source) if tree.target - nomsu\append @tree_to_inline_nomsu(tree.target), "::" + inline_target = @tree_to_inline_nomsu(tree.target) + if tree.target.type == "Action" + inline_target\parenthesize! + nomsu\append inline_target, "::" for i,bit in ipairs tree if type(bit) == "string" clump_words = (type(tree[i-1]) == 'string' and is_operator(bit) != is_operator(tree[i-1])) diff --git a/tools/upgrade.nom b/tools/upgrade.nom index cd3fbbb..4e03945 100755 --- a/tools/upgrade.nom +++ b/tools/upgrade.nom @@ -10,22 +10,29 @@ use "lib/os.nom" %args = (command line args) %inplace = (no) -if (%args.1 is "-i"): - %inplace = (yes) - %args::remove index 1 - -if (%args.1 is "-t"): - use "lib/consolecolor.nom" - %test = (yes) - %args::remove index 1 +%version = (Nomsu version) +repeat: + if %args.1 is: + "-i": + %inplace = (yes) + %args::remove index 1 + "-t": + use "lib/consolecolor.nom" + %test = (yes) + %args::remove index 1 + "-V": + %version = %args.2 + %args::remove index 1 + %args::remove index 1 + else: stop for %path in %args: for file %filename in %path: unless (%filename::matches "%.nom$"): do next %filename %tree = (parse (read file %filename) from %filename) - %uptree = (%tree upgraded) + %uptree = (%tree upgraded to %version) %text = "\ - ..#!/usr/bin/env nomsu -V\(Nomsu version) + ..#!/usr/bin/env nomsu -V\%version \(%uptree as nomsu)" if: -- cgit v1.2.3 From ea3197aaffba00318920ed5e1e33ca5f2a5e6c5c Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Tue, 30 Oct 2018 23:42:04 -0700 Subject: Fully working version of (action [foo]: baz) -> ((foo) means: baz) refactor and misc other changes. --- README.md | 8 +- compatibility/compatibility.nom | 43 ++++++----- core/collections.nom | 57 ++++++++------- core/control_flow.nom | 140 ++++++++++++++++++----------------- core/coroutines.nom | 10 +-- core/errors.nom | 33 +++++---- core/id.nom | 6 +- core/io.nom | 6 +- core/math.nom | 158 +++++++++++++++++++++++----------------- core/metaprogramming.nom | 151 ++++++++++++++++++++------------------ core/operators.nom | 90 +++++++++++------------ core/scopes.nom | 10 +-- core/text.nom | 6 +- examples/how_do_i.nom | 40 +++++----- lib/base64.nom | 8 +- lib/consolecolor.nom | 5 +- lib/file_hash.nom | 10 +-- lib/object.nom | 24 +++--- lib/os.nom | 28 +++---- lib/training_wheels.nom | 46 ++++++------ lib/version.nom | 2 +- nomsu_compiler.lua | 11 ++- nomsu_compiler.moon | 9 ++- tools/upgrade.nom | 2 +- 24 files changed, 485 insertions(+), 418 deletions(-) diff --git a/README.md b/README.md index 6744001..1de0910 100644 --- a/README.md +++ b/README.md @@ -25,12 +25,12 @@ say "Hello" for %num in %my_nums: say "\%num is one of my nums" -action [sing %n bottles of beer]: +(sing %n bottles of beer) means: for %i in %n to 1 by -1: - say ".." - \%i bottle\("s" if (%i > 1) else "") of beer on the wall, + say "\ + ..\%i bottle\("s" if (%i > 1) else "") of beer on the wall, \%i bottle\("s" if (%i > 1) else "") of beer! - Take one down, pass it around... + Take one down, pass it around..." say "No bottles of beer on the wall. Go to the store, buy some more..." sing 99 bottles of beer diff --git a/compatibility/compatibility.nom b/compatibility/compatibility.nom index acd1d11..6da7063 100644 --- a/compatibility/compatibility.nom +++ b/compatibility/compatibility.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file contains code for defining ways to upgrade code between different versions of Nomsu. @@ -6,17 +6,17 @@ use "lib/os.nom" %UPGRADES = {} -action [upgrade to %version via %upgrade_fn]: +externally (upgrade to %version via %upgrade_fn) means: %UPGRADES.%version = %upgrade_fn %ACTION_UPGRADES = ({} with fallback % -> {}) -action [upgrade action %stub to %version via %upgrade_fn]: +externally (upgrade action %stub to %version via %upgrade_fn) means: %ACTION_UPGRADES.%version.%stub = %upgrade_fn -parse [upgrade %tree to %version as %body] as (..) - upgrade to %version via ([%] -> (% with %tree -> %body)) +(upgrade %tree to %version as %body) parses as (..) + upgrade to %version via ([%, %end_version] -> (% with %tree -> %body)) -compile [upgrade action %actions to %version as %body] to: +(upgrade action %actions to %version as %body) compiles to: if (%actions is "Action" syntax tree): %actions = \[%actions] %lua = (Lua "") @@ -27,7 +27,7 @@ compile [upgrade action %actions to %version as %body] to: %replacements.(%action.%i.1) = "\(\%tree as lua id)[\%i]" define mangler - local action [make tree %t]: + (make tree %t) means: when: (%t is "Var" syntax tree): if %replacements.(%t.1): @@ -60,11 +60,12 @@ compile [upgrade action %actions to %version as %body] to: return %lua -action [..] +externally [..] %tree upgraded from %start_version to %end_version %tree upgraded to %end_version from %start_version -..: - local action [%ver as list] ((% as number) for % in %ver matching "[0-9]+") +..all mean: + unless (%tree is syntax tree): return %tree + (%ver as list) means ((% as number) for % in %ver matching "[0-9]+") %versions = {} for %v = % in %UPGRADES: %versions.%v = (yes) @@ -78,25 +79,31 @@ action [..] %tree = (..) %tree with % -> (..) if ((% is "Action" syntax tree) and %ACTION_UPGRADES.%ver.(%.stub)): - return (call %ACTION_UPGRADES.%ver.(%.stub) with [%]) + %with_upgraded_args = (..) + %k = (%v upgraded from %start_version to %end_version) \ + ..for %k = %v in % + set %with_upgraded_args's metatable to (%'s metatable) + return (call %ACTION_UPGRADES.%ver.(%.stub) with [%with_upgraded_args, %end_version]) if %UPGRADES.%ver: - %tree = (call %UPGRADES.%ver with [%tree]) + %with_upgraded_args = (..) + %k = (%v upgraded from %start_version to %end_version) \ + ..for %k = %v in %tree + set %with_upgraded_args's metatable to (%tree's metatable) + %tree = (call %UPGRADES.%ver with [%with_upgraded_args, %end_version]) return %tree -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -parse [%tree upgraded from %start_version] as (..) +externally (%tree upgraded from %start_version) means (..) %tree upgraded from %start_version to (Nomsu version) -parse [%tree upgraded to %end_version] as (..) +externally (%tree upgraded to %end_version) means (..) %tree upgraded from (%tree.version or (Nomsu version)) to %end_version -parse [%tree upgraded] as (..) +externally (%tree upgraded) means (..) %tree upgraded from (%tree.version or (Nomsu version)) to (Nomsu version) -action [use %path from version %version]: +externally (use %path from version %version) means: for file %filename in %path: if (=lua "LOADED[\%filename]"): do next %filename %file = (read file %filename) diff --git a/core/collections.nom b/core/collections.nom index 3877d31..ae7f5f1 100644 --- a/core/collections.nom +++ b/core/collections.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file contains code that supports manipulating and using collections like lists and dictionaries. @@ -45,17 +45,17 @@ test: # List Comprehension test: assume (((% * %) for % in [1, 2, 3]) == [1, 4, 9]) -parse [%expression for %item in %iterable] as (..) +(%expression for %item in %iterable) parses as (..) result of: %comprehension = [] for %item in %iterable: %comprehension::add %expression return %comprehension -parse [..] +[..] %expression for %index in %start to %stop via %step %expression for %index in %start to %stop by %step -..as (..) +..all parse as (..) result of: %comprehension = [] for %index in %start to %stop via %step: @@ -66,15 +66,15 @@ parse [..] test: assume (((% * %) for % in 1 to 3) == [1, 4, 9]) -parse [%expression for %var in %start to %stop] as (..) +(%expression for %var in %start to %stop) parses as (..) %expression for %var in %start to %stop via 1 test: assume (("\%k,\%v" for %k = %v in {x:1}) == ["x,1"]) -parse [..] +[..] %expression for %key = %value in %iterable %expression for %key %value in %iterable -..as (..) +..all parse as (..) result of: %comprehension = [] for %key = %value in %iterable: @@ -84,7 +84,9 @@ parse [..] # Dict comprehensions test: assume (((% * %) = % for % in [1, 2, 3]) == {1:1, 4:2, 9:3}) -parse [%key = %value for %item in %iterable, %key %value for %item in %iterable] as (..) +[..] + %key = %value for %item in %iterable, %key %value for %item in %iterable +..all parse as (..) result of: %comprehension = {} for %item in %iterable: @@ -93,20 +95,20 @@ parse [%key = %value for %item in %iterable, %key %value for %item in %iterable] test: assume ((%k = (%v * %v) for %k = %v in {x:1, y:2, z:3}) == {x:1, y:4, z:9}) -parse [..] +[..] %key = %value for %src_key = %src_value in %iterable %key %value for %src_key %src_value in %iterable -..as (..) +..all parse as (..) result of: %comprehension = {} for %src_key = %src_value in %iterable: %comprehension.%key = %value return %comprehension -parse [..] +[..] %key = %value for %item in %start to %stop via %step %key %value for %item in %start to %stop via %step -..as (..) +..all parse as (..) result of: %comprehension = {} for %item in %start to %stop via %step: @@ -117,14 +119,14 @@ parse [..] test: assume (((% * %) = % for % in 1 to 3) == {1:1, 4:2, 9:3}) -parse [..] +[..] %key = %value for %item in %start to %stop %key %value for %item in %start to %stop -..as (%key = %value for %item in %start to %stop via 1) +..all parse as (%key = %value for %item in %start to %stop via 1) test: assume (([[1, 2], [3, 4]] flattened) == [1, 2, 3, 4]) -action [%lists flattened]: +externally (%lists flattened) means: %flat = [] for %list in %lists: for %item in %list: %flat::add %item @@ -132,29 +134,30 @@ action [%lists flattened]: test: assume ((entries in {x:1}) == [{key:"x", value:1}]) -parse [entries in %dict] as ({key:%k, value:%v} for %k = %v in %dict) +(entries in %dict) parses as ({key:%k, value:%v} for %k = %v in %dict) test: assume ((keys in {x:1}) == ["x"]) -parse [keys in %dict, keys of %dict] as (%k for %k = %v in %dict) +[keys in %dict, keys of %dict] all parse as (%k for %k = %v in %dict) test: assume ((values in {x:1}) == [1]) -parse [values in %dict, values of %dict] as (%v for %k = %v in %dict) +[values in %dict, values of %dict] all parse as (%v for %k = %v in %dict) # Metatable stuff test: %t = {} set %t 's metatable to {__tostring:[%] -> "XXX"} assume ("\%t" == "XXX") -compile [set %dict 's metatable to %metatable] to (..) +(set %dict 's metatable to %metatable) compiles to (..) Lua "setmetatable(\(%dict as lua expr), \(%metatable as lua expr));" -compile [%'s metatable, %' metatable] to (..) + +[% 's metatable, % 'metatable] all compile to (..) Lua value "getmetatable(\(% as lua expr))" test: assume (({} with fallback % -> (% + 1)).10 == 11) -compile [%dict with fallback %key -> %value] to (..) +(%dict with fallback %key -> %value) compiles to (..) Lua value "\ ..(function(d) local mt = {} @@ -177,8 +180,10 @@ test: %keys = {1:999, 2:0, 3:50} sort %x by % = %keys.% assume (%x == [2, 3, 1]) -compile [sort %items] to (Lua "table.sort(\(%items as lua expr));") -parse [sort %items by %item = %key_expr, sort %items by %item -> %key_expr] as (..) +(sort %items) compiles to (Lua "table.sort(\(%items as lua expr));") +[..] + sort %items by %item = %key_expr, sort %items by %item -> %key_expr +..all parse as (..) do: %keys = ({} with fallback %item -> %key_expr) lua> "table.sort(\%items, function(x,y) return \%keys[x] < \%keys[y] end)" @@ -187,12 +192,12 @@ parse [sort %items by %item = %key_expr, sort %items by %item -> %key_expr] as ( test: assume ((sorted [3, 1, 2]) == [1, 2, 3]) -action [%items sorted, sorted %items]: +externally [%items sorted, sorted %items] all mean: %copy = (% for % in %items) sort %copy return %copy -parse [%items sorted by %item = %key, %items sorted by %item -> %key] as (..) +[%items sorted by %item = %key, %items sorted by %item -> %key] all parse as (..) result of: %copy = (% for % in %items) sort %copy by %item = %key @@ -200,7 +205,7 @@ parse [%items sorted by %item = %key, %items sorted by %item -> %key] as (..) test: assume ((unique [1, 2, 1, 3, 2, 3]) == [1, 2, 3]) -action [unique %items]: +externally (unique %items) means: %unique = [] %seen = {} for % in %items: diff --git a/core/control_flow.nom b/core/control_flow.nom index 37b2b9c..2b53ce7 100644 --- a/core/control_flow.nom +++ b/core/control_flow.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file contains compile-time actions that define basic control flow structures like "if" statements and loops. @@ -10,13 +10,13 @@ use "core/errors.nom" # No-Op test: do nothing -compile [do nothing] to (Lua "") +(do nothing) compiles to (Lua "") # Conditionals test: if (no): barf "conditional fail" -compile [if %condition %if_body] to: +(if %condition %if_body) compiles to: %lua = (Lua "if ") %lua::append (%condition as lua expr) %lua::append " then\n " @@ -27,10 +27,10 @@ compile [if %condition %if_body] to: test: unless (yes): barf "conditional fail" -parse [unless %condition %unless_body] as (if (not %condition) %unless_body) -compile [..] +(unless %condition %unless_body) parses as (if (not %condition) %unless_body) +[..] if %condition %if_body else %else_body, unless %condition %else_body else %if_body -..to: +..all compile to: %lua = (Lua "if ") %lua::append (%condition as lua expr) %lua::append " then\n " @@ -48,12 +48,12 @@ compile [..] test: assume ((1 if (yes) else 2) == 1) assume ((1 if (no) else 2) == 2) -compile [..] +[..] %when_true_expr if %condition else %when_false_expr %when_true_expr if %condition otherwise %when_false_expr %when_false_expr unless %condition else %when_true_expr %when_false_expr unless %condition then %when_true_expr -..to: +..all compile to: # If %when_true_expr is guaranteed to be truthy, we can use Lua's idiomatic equivalent of a conditional expression: (cond and if_true or if_false) if {Text:yes, List:yes, Dict:yes, Number:yes}.(%when_true_expr.type): @@ -89,15 +89,21 @@ test: %i -= 1 unless (%i == 0): go to (Loop) assume (%i == 0) -compile [=== %label ===, --- %label ---, *** %label ***] to (..) - Lua "::label_\((%label.stub if (%label.type == "Action") else %label) as lua identifier)::" - -compile [go to %label] to (..) - Lua "goto label_\((%label.stub if (%label.type == "Action") else %label) as lua identifier)" +[=== %label ===, --- %label ---, *** %label ***] all compile to (..) + Lua "\ + ..::label_\(..) + (%label.stub if (%label.type == "Action") else %label) as lua identifier + ..::" + +(go to %label) compiles to (..) + Lua "\ + ..goto label_\(..) + (%label.stub if (%label.type == "Action") else %label) as lua identifier + .." # Basic loop control -compile [do next] to (Lua "goto continue") -compile [stop] to (Lua "break") +(do next) compiles to (Lua "goto continue") +(stop) compiles to (Lua "break") # While loops test: @@ -119,9 +125,9 @@ test: barf "Failed to 'do next repeat'" assume (%x == 30) -compile [do next repeat] to (Lua "goto continue_repeat") -compile [stop repeating] to (Lua "goto stop_repeat") -compile [repeat while %condition %body] to: +(do next repeat) compiles to (Lua "goto continue_repeat") +(stop repeating) compiles to (Lua "goto stop_repeat") +(repeat while %condition %body) compiles to: %lua = (..) Lua "\ ..while \(%condition as lua expr) do @@ -137,25 +143,24 @@ compile [repeat while %condition %body] to: %lua = (Lua "do -- scope of 'stop repeating' label\n ") %lua::append %inner_lua %lua::append "\ - .. - ::stop_repeat:: - end -- end of 'stop repeating' label scope" + .. + ::stop_repeat:: + end -- end of 'stop repeating' label scope" return %lua -parse [repeat %body] as (repeat while (yes) %body) -parse [repeat until %condition %body] as (repeat while (not %condition) %body) +(repeat %body) parses as (repeat while (yes) %body) +(repeat until %condition %body) parses as (repeat while (not %condition) %body) test: %x = 0 repeat 10 times: %x += 1 assume (%x == 10) -compile [repeat %n times %body] to: +(repeat %n times %body) compiles to: define mangler %lua = (..) Lua "for \(mangle "i")=1,\(%n as lua expr) do\n " %lua::append (%body as lua statements) - if (%body has subtree \(do next)): %lua::append "\n ::continue::" if (%body has subtree \(do next repeat)): @@ -166,21 +171,20 @@ compile [repeat %n times %body] to: %lua = (Lua "do -- scope of 'stop repeating' label\n ") %lua::append %inner_lua %lua::append "\ - .. - ::stop_repeat:: - end -- end of 'stop repeating' label scope" + .. + ::stop_repeat:: + end -- end of 'stop repeating' label scope" return %lua # For loop control flow -compile [stop %var] to (..) +(stop %var) compiles to (..) Lua "goto stop_\((%var.stub if (%var.type == "Action") else %var) as lua identifier)" -compile [do next %var] to (..) +(do next %var) compiles to (..) Lua "goto continue_\((%var.stub if (%var.type == "Action") else %var) as lua identifier)" -compile [===stop %var ===, ---stop %var ---, ***stop %var ***] to (..) +[===stop %var ===, ---stop %var ---, ***stop %var ***] all compile to (..) Lua "::stop_\((%var.stub if (%var.type == "Action") else %var) as lua identifier)::" - -compile [===next %var ===, ---next %var ---, ***next %var ***] to (..) +[===next %var ===, ---next %var ---, ***next %var ***] all compile to (..) Lua "::continue_\((%var.stub if (%var.type == "Action") else %var) as lua identifier)::" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -205,10 +209,10 @@ test: assume (%nums == [1, -2, 3, -2, 3, 4, 3, 4, 5]) # Numeric range for loops -compile [..] +[..] for %var in %start to %stop by %step %body for %var in %start to %stop via %step %body -..to: +..all compile to: # This uses Lua's approach of only allowing loop-scoped variables in a loop unless (%var.type is "Var"): compile error at %var "Expected a variable here, not a \(%var.type)" @@ -217,28 +221,29 @@ compile [..] ..for \(%var as lua expr)=\(%start as lua expr),\(%stop as lua expr),\(..) %step as lua expr .. do" + %lua::append "\n " %lua::append (%body as lua statements) - if (%body has subtree \(do next)): %lua::append "\n ::continue::" if (%body has subtree \(do next %var)): %lua::append "\n " - %lua::append (compile as (===next %var ===)) + %lua::append (what (===next %var ===) compiles to) + %lua::append "\nend --numeric for-loop" if (%body has subtree \(stop %var)): %inner_lua = %lua %lua = (Lua "do -- scope for stopping for-loop\n ") %lua::append %inner_lua %lua::append "\n " - %lua::append (compile as (===stop %var ===)) + %lua::append (what (===stop %var ===) compiles to) %lua::append "\nend -- end of scope for stopping for-loop" return %lua ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -parse [for %var in %start to %stop %body] as (..) +(for %var in %start to %stop %body) parses as (..) for %var in %start to %stop via 1 %body test: @@ -255,48 +260,48 @@ test: assume (%b == [20, 30, 40]) # For-each loop (lua's "ipairs()") -compile [for %var in %iterable %body] to: +(for %var in %iterable %body) compiles to: define mangler # This uses Lua's approach of only allowing loop-scoped variables in a loop %lua = (..) Lua "for \(mangle "i"),\(%var as lua identifier) in ipairs(\(%iterable as lua expr)) do\n " %lua::append (%body as lua statements) - if (%body has subtree \(do next)): %lua::append "\n ::continue::" if (%body has subtree \(do next %var)): %lua::append "\n " - %lua::append (compile as (===next %var ===)) + %lua::append (what (===next %var ===) compiles to) + %lua::append "\nend --foreach-loop" if (%body has subtree \(stop %var)): %inner_lua = %lua %lua = (Lua "do -- scope for stopping for-loop\n ") %lua::append %inner_lua %lua::append "\n " - %lua::append (compile as (===stop %var ===)) + %lua::append (what (===stop %var ===) compiles to) %lua::append "\nend -- end of scope for stopping for-loop" return %lua # TODO: reduce code duplication -compile [for %var in %iterable at %i %body] to: +(for %var in %iterable at %i %body) compiles to: # This uses Lua's approach of only allowing loop-scoped variables in a loop %lua = (..) Lua "for \(%i as lua identifier),\(%var as lua identifier) in ipairs(\(%iterable as lua expr)) do\n " %lua::append (%body as lua statements) - if (%body has subtree \(do next)): %lua::append "\n ::continue::" if (%body has subtree \(do next %var)): %lua::append "\n " - %lua::append (compile as (===next %var ===)) + %lua::append (what (===next %var ===) compiles to) + %lua::append "\nend --foreach-loop" if (%body has subtree \(stop %var)): %inner_lua = %lua %lua = (Lua "do -- scope for stopping for-loop\n ") %lua::append %inner_lua %lua::append "\n " - %lua::append (compile as (===stop %var ===)) + %lua::append (what (===stop %var ===) compiles to) %lua::append "\nend -- end of scope for stopping for-loop" return %lua @@ -312,9 +317,9 @@ test: assume ((%result sorted) == ["c = 30", "d = 40", "e = 50"]) # Dict iteration (lua's "pairs()") -compile [..] +[..] for %key = %value in %iterable %body, for %key %value in %iterable %body -..to: +..all compile to: # This uses Lua's approach of only allowing loop-scoped variables in a loop unless (%key.type is "Var"): compile error at %key "Expected a variable here, not a \(%key.type)" @@ -325,25 +330,29 @@ compile [..] ..for \(%key as lua identifier),\(%value as lua identifier) in pairs(\(..) %iterable as lua expr ..) do" + %lua::append "\n " %lua::append (%body as lua statements) - if (%body has subtree \(do next)): %lua::append "\n ::continue::" if (%body has subtree \(do next %key)): %lua::append "\n " - %lua::append (compile as (===next %key ===)) + %lua::append (what (===next %key ===) compiles to) + if (%body has subtree \(do next %value)): %lua::append "\n " - %lua::append (compile as (===next %value ===)) + %lua::append (what (===next %value ===) compiles to) + %lua::append "\nend --foreach-loop" %stop_labels = (Lua "") if (%body has subtree \(stop %key)): %stop_labels::append "\n" - %stop_labels::append (compile as (===stop %key ===)) + %stop_labels::append (what (===stop %key ===) compiles to) + if (%body has subtree \(stop %value)): %stop_labels::append "\n" - %stop_labels::append (compile as (===stop %value ===)) + %stop_labels::append (what (===stop %value ===) compiles to) + if ((size of "\%stop_labels") > 0): %inner_lua = %lua %lua = (Lua "do -- scope for stopping for % = % loop\n ") @@ -368,13 +377,14 @@ test: barf "bad conditional" # Multi-branch conditional (if..elseif..else) -compile [if %body, when %body] to: +[if %body, when %body] all compile to: %code = (Lua "") %clause = "if" %else_allowed = (yes) unless (%body.type is "Block"): compile error at %body "'if' expected a Block, but got a \(%body.type)." ..hint "Perhaps you forgot to put a ':' after 'if'?" + for %line in %body: unless (..) ((%line.type is "Action") and ((size of %line) >= 2)) and (..) @@ -389,13 +399,14 @@ compile [if %body, when %body] to: unless %else_allowed: compile error at %line "You can't have two 'else' blocks." ..hint "Merge all of the 'else' blocks together." + unless ((size of "\%code") > 0): compile error at %line "\ ..You can't have an 'else' block without a preceeding condition" ..hint "If you want the code in this block to always execute, you don't \ ..need a conditional block around it. Otherwise, make sure the 'else' \ ..block comes last." - + %code::append "\nelse\n " %code::append (%action as lua statements) %else_allowed = (no) @@ -428,7 +439,7 @@ test: barf "bad switch statement" # Switch statement -compile [if %branch_value is %body, when %branch_value is %body] to: +[if %branch_value is %body, when %branch_value is %body] all compile to: %code = (Lua "") %clause = "if" %else_allowed = (yes) @@ -488,7 +499,7 @@ compile [if %branch_value is %body, when %branch_value is %body] to: return %lua # Do/finally -compile [do %action] to: +(do %action) compiles to: %lua = (Lua "do\n ") %lua::append (%action as lua statements) %lua::append "\nend -- do" @@ -504,7 +515,7 @@ test: ..and if it barfs: do nothing assume (%d.x == "good") -compile [do %action then always %final_action] to: +(do %action then always %final_action) compiles to: define mangler %lua = (..) Lua "\ @@ -528,7 +539,7 @@ test: assume ((result of (: return 99)) == 99) # Inline thunk: -compile [result of %body] to (Lua value "\(compile as ([] -> %body))()") +(result of %body) compiles to (Lua value "\(what ([] -> %body) compiles to)()") test: %t = [1, [2, [[3], 4], 5, [[[6]]]]] @@ -541,10 +552,10 @@ test: assume (sorted %flat) == [1, 2, 3, 4, 5, 6] # Recurion control flow -compile [for %var in recursive %structure %body] to: +(for %var in recursive %structure %body) compiles to: with local compile actions: define mangler - compile [recurse %v on %x] to (..) + (recurse %v on %x) compiles to (..) Lua "table.insert(\(mangle "stack \(%v.1)"), \(%x as lua expr))" %lua = (..) Lua "\ @@ -554,13 +565,12 @@ compile [for %var in recursive %structure %body] to: \(%var as lua expr) = table.remove(\(mangle "stack \(%var.1)"), 1)" %lua::append "\n " %lua::append (%body as lua statements) - if (%body has subtree \(do next)): %lua::append "\n ::continue::" if (%body has subtree \(do next %var)): - %lua::append "\n \(compile as (===next %var ===))" + %lua::append "\n \(what (===next %var ===) compiles to)" %lua::append "\n end -- Recursive loop" if (%body has subtree \(stop %var)): - %lua::append "\n \(compile as (===stop %var ===))" + %lua::append "\n \(what (===stop %var ===) compiles to)" %lua::append "\nend -- Recursive scope" return %lua diff --git a/core/coroutines.nom b/core/coroutines.nom index e7ec41e..246a2ef 100644 --- a/core/coroutines.nom +++ b/core/coroutines.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file defines the code that creates and manipulates coroutines @@ -14,15 +14,15 @@ test: for % in coroutine %co: %nums::add % assume (%nums == [4, 5, 6, 6, 6]) or barf "Coroutine iteration failed" -compile [coroutine %body, generator %body] to (..) +[coroutine %body, generator %body] all compile to (..) Lua value "\ ..(function() \(%body as lua statements) end)" -compile [->] to (Lua value "coroutine.yield(true)") -compile [-> %] to (Lua value "coroutine.yield(true, \(% as lua expr))") -compile [for % in coroutine %co %body] to (..) +(->) compiles to (Lua value "coroutine.yield(true)") +(-> %) compiles to (Lua value "coroutine.yield(true, \(% as lua expr))") +(for % in coroutine %co %body) compiles to (..) Lua "\ ..for junk,\(% as lua expr) in coroutine.wrap(\(%co as lua expr)) do \(%body as lua statements) diff --git a/core/errors.nom b/core/errors.nom index 1157cb1..70dea0c 100644 --- a/core/errors.nom +++ b/core/errors.nom @@ -1,17 +1,17 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file contains basic error reporting code use "core/metaprogramming.nom" -compile [barf] to (Lua "error(nil, 0);") -compile [barf %msg] to (Lua "error(\(%msg as lua expr), 0);") -compile [compile error at %tree %msg] to (..) +(barf) compiles to (Lua "error(nil, 0);") +(barf %msg) compiles to (Lua "error(\(%msg as lua expr), 0);") +(compile error at %tree %msg) compiles to (..) Lua "nomsu:compile_error(\(%tree as lua expr), \(%msg as lua expr))" -compile [compile error at %tree %msg hint %hint] to (..) +(compile error at %tree %msg hint %hint) compiles to (..) Lua "nomsu:compile_error(\(%tree as lua expr), \(%msg as lua expr), \(%hint as lua expr))" -compile [assume %condition] to: +(assume %condition) compiles to: lua> "\ ..local \%assumption = 'Assumption failed: '..tostring(nomsu:tree_to_nomsu(\%condition))" return (..) @@ -20,7 +20,7 @@ compile [assume %condition] to: error(\(quote "\%assumption"), 0) end" -compile [assume %a == %b] to: +(assume %a == %b) compiles to: lua> "\ ..local \%assumption = 'Assumption failed: '..tostring(nomsu:tree_to_nomsu(\(\(%a == %b))))" define mangler @@ -35,7 +35,7 @@ compile [assume %a == %b] to: end end" -compile [assume %condition or barf %message] to (..) +(assume %condition or barf %message) compiles to (..) Lua "\ ..if not \(%condition as lua expr) then error(\(%message as lua expr), 0) @@ -55,10 +55,10 @@ test: assume (%x == 3) or barf "do/then always failed" # Try/except -compile [..] +[..] try %action and if it succeeds %success or if it barfs %msg %fallback try %action and if it barfs %msg %fallback or if it succeeds %success -..to (..) +..all compile to (..) Lua "\ ..do local fell_through = false @@ -84,21 +84,22 @@ compile [..] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -parse [..] +[..] try %action and if it succeeds %success or if it barfs %fallback try %action and if it barfs %fallback or if it succeeds %success -..as (try %action and if it succeeds %success or if it barfs (=lua "") %fallback) +..all parse as (..) + try %action and if it succeeds %success or if it barfs (=lua "") %fallback ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -parse [try %action] as (..) +(try %action) parses as (..) try %action and if it succeeds (do nothing) or if it barfs (do nothing) -parse [try %action and if it barfs %fallback] as (..) +(try %action and if it barfs %fallback) parses as (..) try %action and if it succeeds (do nothing) or if it barfs %fallback -parse [try %action and if it barfs %msg %fallback] as (..) +(try %action and if it barfs %msg %fallback) parses as (..) try %action and if it succeeds (do nothing) or if it barfs %msg %fallback -parse [try %action and if it succeeds %success] as (..) +(try %action and if it succeeds %success) parses as (..) try %action and if it succeeds %success or if it barfs (do nothing) diff --git a/core/id.nom b/core/id.nom index d3b2b71..a9231b9 100644 --- a/core/id.nom +++ b/core/id.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # A simple UUID function based on RFC 4122: http://www.ietf.org/rfc/rfc4122.txt @@ -27,7 +27,7 @@ set %id_by_obj 's metatable to {..} %obj_by_id.%id = %key return %id -action [uuid]: +externally (uuid) means: # Set all the other bits to randomly (or pseudo-randomly) chosen values. %bytes = [..] # time-low, time-mid, time-high-and-version @@ -56,4 +56,4 @@ test: seed random with 0 assume ((id of %x) != (id of [])) seed random -action [id of %, %'s id, %' id] %id_by_obj.% +externally [id of %, %'s id, %'id] all mean %id_by_obj.% diff --git a/core/io.nom b/core/io.nom index 1e87209..6b67b50 100644 --- a/core/io.nom +++ b/core/io.nom @@ -1,10 +1,10 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file contains basic input/output code use "core/metaprogramming.nom" -compile [say %message] to (..) +(say %message) compiles to (..) lua> "\ ..if \%message.type == "Text" then return LuaCode(tree.source, "print(", \(%message as lua expr), ");"); @@ -12,7 +12,7 @@ compile [say %message] to (..) return LuaCode(tree.source, "print(tostring(", \(%message as lua expr), "));"); end" -compile [ask %prompt] to (..) +(ask %prompt) compiles to (..) lua> "\ ..if \%prompt.type == "Text" then return LuaCode.Value(tree.source, "(io.write(", \(%prompt as lua expr), ") and io.read())"); diff --git a/core/math.nom b/core/math.nom index feb64cb..538b068 100644 --- a/core/math.nom +++ b/core/math.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file defines some common math literals and functions @@ -14,17 +14,18 @@ test: ..math constants failed" %nan = (NaN) assume (%nan != %nan) or barf "NaN failed" -compile [infinity, inf] to (Lua value "math.huge") -compile [not a number, NaN, nan] to (Lua value "(0/0)") -compile [pi, Pi, PI] to (Lua value "math.pi") -compile [tau, Tau, TAU] to (Lua value "(2*math.pi)") -compile [golden ratio] to (Lua value "((1+math.sqrt(5))/2)") -compile [e] to (Lua value "math.exp(1)") +[infinity, inf] all compile to (Lua value "math.huge") +[not a number, NaN, nan] all compile to (Lua value "(0/0)") +[pi, Pi, PI] all compile to (Lua value "math.pi") +[tau, Tau, TAU] all compile to (Lua value "(2*math.pi)") +(golden ratio) compiles to (Lua value "((1+math.sqrt(5))/2)") +(e) compiles to (Lua value "math.exp(1)") # Functions: test: assume (("5" as a number) == 5) -compile [% as a number, % as number] to (Lua value "tonumber(\(% as lua expr))") +[% as a number, % as number] all compile to (..) + Lua value "tonumber(\(% as lua expr))" test: assume (..) @@ -33,105 +34,127 @@ test: arc tangent 5, arc tangent 5 / 10, hyperbolic sine 5, hyperbolic cosine 5 hyperbolic tangent 5, e^ 5, ln 5, log base 2 of 5, floor 5, ceiling 5, round 5 ..or barf "math functions failed" -compile [absolute value %, | % |, abs %] to (..) +[absolute value %, | % |, abs %] all compile to (..) Lua value "math.abs(\(% as lua expr))" -compile [square root %, square root of %, √ %, sqrt %] to (..) +[square root %, square root of %, √ %, sqrt %] all compile to (..) Lua value "math.sqrt(\(% as lua expr))" -compile [sine %, sin %] to (Lua value "math.sin(\(% as lua expr))") -compile [cosine %, cos %] to (Lua value "math.cos(\(% as lua expr))") -compile [tangent %, tan %] to (Lua value "math.tan(\(% as lua expr))") -compile [arc sine %, asin %] to (Lua value "math.asin(\(% as lua expr))") -compile [arc cosine %, acos %] to (Lua value "math.acos(\(% as lua expr))") -compile [arc tangent %, atan %] to (Lua value "math.atan(\(% as lua expr))") -compile [arc tangent %y / %x, atan2 %y %x] to (..) +[sine %, sin %] all compile to (Lua value "math.sin(\(% as lua expr))") +[cosine %, cos %] all compile to (Lua value "math.cos(\(% as lua expr))") +[tangent %, tan %] all compile to (Lua value "math.tan(\(% as lua expr))") +[arc sine %, asin %] all compile to (Lua value "math.asin(\(% as lua expr))") +[arc cosine %, acos %] all compile to (Lua value "math.acos(\(% as lua expr))") +[arc tangent %, atan %] all compile to (Lua value "math.atan(\(% as lua expr))") +[arc tangent %y / %x, atan2 %y %x] all compile to (..) Lua value "math.atan2(\(%y as lua expr), \(%x as lua expr))" -compile [hyperbolic sine %, sinh %] to (Lua value "math.sinh(\(% as lua expr))") -compile [hyperbolic cosine %, cosh %] to (Lua value "math.cosh(\(% as lua expr))") -compile [hyperbolic tangent %, tanh %] to (..) +[hyperbolic sine %, sinh %] all compile to (..) + Lua value "math.sinh(\(% as lua expr))" + +[hyperbolic cosine %, cosh %] all compile to (..) + Lua value "math.cosh(\(% as lua expr))" + +[hyperbolic tangent %, tanh %] all compile to (..) Lua value "math.tanh(\(% as lua expr))" -compile [e^ %, exp %] to (Lua value "math.exp(\(% as lua expr))") -compile [natural log %, ln %, log %] to (Lua value "math.log(\(% as lua expr))") -compile [log % base %base, log base %base of %] to (..) +[e^ %, exp %] all compile to (Lua value "math.exp(\(% as lua expr))") +[natural log %, ln %, log %] all compile to (..) + Lua value "math.log(\(% as lua expr))" + +[log % base %base, log base %base of %] all compile to (..) Lua value "math.log(\(% as lua expr), \(%base as lua expr))" -compile [floor %] to (Lua value "math.floor(\(% as lua expr))") -compile [ceiling %, ceil %] to (Lua value "math.ceil(\(% as lua expr))") -compile [round %, % rounded] to (Lua value "math.floor(\(% as lua expr) + .5)") +(floor %) compiles to (Lua value "math.floor(\(% as lua expr))") +[ceiling %, ceil %] all compile to (Lua value "math.ceil(\(% as lua expr))") +[round %, % rounded] all compile to (..) + Lua value "math.floor(\(% as lua expr) + .5)" test: assume ((463 to the nearest 100) == 500) or barf "rounding failed" assume ((2.6 to the nearest 0.25) == 2.5) or barf "rounding failed" -action [%n to the nearest %rounder] (..) +externally (%n to the nearest %rounder) means (..) =lua "(\%rounder)*math.floor((\%n / \%rounder) + .5)" # Any/all/none -compile [all of %items, all %items] to: +[all of %items, all %items] all compile to: unless (%items.type is "List"): return (Lua value "utils.all(\(%items as lua expr))") %clauses = (((% as lua expr)::as smext) for % in %items) return (Lua value "(\(%clauses::joined with " and "))") -parse [not all of %items, not all %items] as (not (all of %items)) -compile [any of %items, any %items] to: +[not all of %items, not all %items] all parse as (not (all of %items)) +[any of %items, any %items] all compile to: unless (%items.type is "List"): return (Lua value "utils.any(\(%items as lua expr))") %clauses = (((% as lua expr)::as smext) for % in %items) return (Lua value "(\(%clauses::joined with " or "))") -parse [none of %items, none %items] as (not (any of %items)) -compile [sum of %items, sum %items] to: +[none of %items, none %items] all parse as (not (any of %items)) +[sum of %items, sum %items] all compile to: unless (%items.type is "List"): return (Lua value "utils.sum(\(%items as lua expr))") %clauses = (((% as lua expr)::as smext) 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, if all of %items then %body] all parse as (..) if (all of %items) %body -parse [unless all of %items %body, unless all of %items then %body] as (..) + +[unless all of %items %body, unless all of %items then %body] all parse 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, if any of %items then %body] all parse as (..) if (any of %items) %body -parse [unless any of %items %body, unless any of %items then %body] as (..) + +[unless any of %items %body, unless any of %items then %body] all parse as (..) if (not (any of %items)) %body -parse [if none of %items %body, if none of %items then %body] as (..) + +[if none of %items %body, if none of %items then %body] all parse as (..) if (not (any of %items)) %body -parse [unless none of %items %body, unless none of %items then %body] as (..) + +[unless none of %items %body, unless none of %items then %body] all parse 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: +[if all of %items %body else %else, if all of %items then %body else %else] all parse \ +..as (if (all of %items) %body else %else) + +[..] + unless all of %items %body else %else, unless all of %items then %body else %else +..all parse as (if (not (all of %items)) %body else %else) + +[if any of %items %body else %else, if any of %items then %body else %else] all parse \ +..as (if (any of %items) %body else %else) + +[..] + unless any of %items %body else %else, unless any of %items then %body else %else +..all parse as (if (not (any of %items)) %body else %else) + +[if none of %items %body else %else, if none of %items then %body else %else] all \ +..parse as (if (not (any of %items)) %body else %else) + +[..] + unless none of %items %body else %else, unless none of %items then %body else %else +..all parse as (if (any of %items) %body else %else) + +[product of %items, product %items] all compile to: unless (%items.type is "List"): return (Lua value "utils.product(\(%items as lua expr))") %clauses = (((% as lua expr)::as smext) for % in %items) return (Lua value "(\(%clauses::joined with " * "))") -action [avg of %items, average of %items] (=lua "(utils.sum(\%items)/#\%items)") -compile [min of %items, smallest of %items, lowest of %items] to (..) +externally [avg of %items, average of %items] all mean (..) + =lua "(utils.sum(\%items)/#\%items)" + +[min of %items, smallest of %items, lowest of %items] all compile to (..) Lua value "utils.min(\(%items as lua expr))" -compile [max of %items, biggest of %items, largest of %items, highest of %items] to (..) - Lua value "utils.max(\(%items as lua expr))" +[max of %items, biggest of %items, largest of %items, highest of %items] all compile \ +..to (Lua value "utils.max(\(%items as lua expr))") test: assume ((min of [3, -4, 1, 2] by % = (% * %)) == 1) assume ((max of [3, -4, 1, 2] by % = (% * %)) == -4) -parse [min of %items by %item = %value_expr] as (..) +(min of %items by %item = %value_expr) parses as (..) result of: set {%best:nil, %best_key:nil} for %item in %items: @@ -141,7 +164,7 @@ parse [min of %items by %item = %value_expr] as (..) return %best -parse [max of %items by %item = %value_expr] as (..) +(max of %items by %item = %value_expr) parses as (..) result of: set {%best:nil, %best_key:nil} for %item in %items: @@ -152,20 +175,19 @@ parse [max of %items by %item = %value_expr] as (..) return %best # Random functions -action [seed random with %] (..) +externally (seed random with %) means (..) lua> "\ ..math.randomseed(\%); for i=1,20 do math.random(); end" -parse [seed random] as (seed random with (=lua "os.time()")) -compile [random number, random, rand] to (Lua value "math.random()") -compile [random int %n, random integer %n, randint %n] to (..) +(seed random) parses as (seed random with (=lua "os.time()")) +[random number, random, rand] all compile to (Lua value "math.random()") +[random int %n, random integer %n, randint %n] all compile to (..) Lua value "math.random(\(%n as lua expr))" -compile [..] - random from %low to %high, random number from %low to %high - rand %low %high -..to (Lua value "math.random(\(%low as lua expr), \(%high as lua expr))") +[random from %low to %high, random number from %low to %high, rand %low %high] all \ +..compile to (Lua value "math.random(\(%low as lua expr), \(%high as lua expr))") -action [random choice from %elements, random choice %elements, random %elements] (..) - =lua "\%elements[math.random(#\%elements)]" +externally [..] + random choice from %elements, random choice %elements, random %elements +..all mean (=lua "\%elements[math.random(#\%elements)]") diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom index d85c1ad..a2f15a1 100644 --- a/core/metaprogramming.nom +++ b/core/metaprogramming.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This File contains actions for making actions and compile-time actions and some helper functions to make that easier. @@ -33,7 +33,7 @@ lua> "\ end" lua> "\ - ..COMPILE_ACTIONS["compile as 1"] = function(nomsu, tree, \%action) + ..COMPILE_ACTIONS["what 1 compiles to"] = function(nomsu, tree, \%action) local lua = LuaCode.Value(tree.source, "COMPILE_ACTIONS[", \%action.stub:as_lua(), "](") local lua_args = table.map(\%action:get_args(), function(a) return nomsu:compile(a) end) table.insert(lua_args, 1, "nomsu") @@ -46,32 +46,32 @@ lua> "\ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ test: - compile [five] to (Lua value "5") + (five) compiles to (Lua value "5") test: assume ((five) == 5) or barf "Compile to expression failed." - compile [loc x] to (Lua "local x = 99;") + (loc x) compiles to (Lua "local x = 99;") test: lua> "do" loc x assume (%x is 99) or barf "Compile to statements with locals failed." lua> "end" assume (%x is (nil)) or barf "Failed to properly localize a variable." - compile [asdf] to: + (asdf) compiles to: %tmp = "" return (Lua %tmp) test: asdf assume (%tmp is (nil)) or barf "compile to is leaking variables" lua> "\ - ..COMPILE_ACTIONS["compile 1 to 2"] = function(nomsu, tree, \%actions, \%body) - local \%args = {"nomsu", "tree", unpack(table.map(\%actions[1]:get_args(), function(a) return nomsu:compile(\ - ..a):as_smext() end))} + ..COMPILE_ACTIONS["1 compiles to 2"] = function(nomsu, tree, \%actions, \%body) + if \%actions.type ~= "List" then \%actions = {\%actions, type="List"} end + local \%args = {"nomsu", "tree", unpack(table.map(\%actions[1]:get_args(), function(a) return nomsu:compile(a):as_smext() end))} local lua = LuaCode(tree.source, "COMPILE_ACTIONS[", \%actions[1].stub:as_lua(), - "] = ", \(compile as (%args -> %body))) + "] = ", \(what (%args -> %body) compiles to)) for i=2,#\%actions do local alias = \%actions[i] - local \%alias_args = {"nomsu", "tree", unpack(table.map(alias:get_args(), function(a) return nomsu:compile(\ - ..a):as_smext() end))} + local \%alias_args = {"nomsu", "tree", unpack(table.map(alias:get_args(), function(a) return nomsu:compile(a):as_\ + ..smext() end))} lua:append("\\nCOMPILE_ACTIONS[", alias.stub:as_lua(), "] = ") if utils.equivalent(\%args, \%alias_args) then lua:append("COMPILE_ACTIONS[", \%actions[1].stub:as_lua(), "]") @@ -84,11 +84,12 @@ lua> "\ end end return lua - end" + end + COMPILE_ACTIONS["1 all compile to 2"] = COMPILE_ACTIONS["1 compiles to 2"]" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -compile [call %fn with %args] to: +(call %fn with %args) compiles to: lua> "\ ..local lua = LuaCode.Value(tree.source, nomsu:compile(\%fn), "(") if \%args.type == 'List' then @@ -100,22 +101,23 @@ compile [call %fn with %args] to: return lua" test: - local action [foo %x]: return "outer" + (foo %x) means (return "outer") with local [action (foo %)]: - local action [foo %x]: + (foo %x) means: %y = (%x + 1) return %y assume ((foo 10) == 11) or barf "Action didn't work." assume (%y is (nil)) or barf "Action leaked a local into globals." - parse [baz %] as (foo %) + (baz %) parses as (foo %) assume ((foo 1) == "outer") -compile [local action %actions %body] to: +[%actions means %body, %actions all mean %body] all compile to: lua> "\ - ..local fn_name = \%actions[1].stub:as_lua_id() + ..if \%actions.type ~= "List" then \%actions = {\%actions, type="List"} end + local fn_name = \%actions[1].stub:as_lua_id() local \%args = table.map(\%actions[1]:get_args(), function(a) return nomsu:compile(a):as_smext() end) - local lua = LuaCode(tree.source, fn_name, " = ", \(compile as (%args -> %body))) + local lua = LuaCode(tree.source, fn_name, " = ", \(what (%args -> %body) compiles to)) lua:add_free_vars({fn_name}) for i=2,#\%actions do local alias = \%actions[i] @@ -136,23 +138,24 @@ compile [local action %actions %body] to: return lua" test: - action [baz1]: return "baz1" - action [baz2] "baz2" + externally (baz1) means: return "baz1" + externally (baz2) means "baz2" test: assume ((baz1) == "baz1") assume ((baz2) == "baz2") -compile [action %actions %body] to (..) +[externally %actions means %body, externally %actions all mean %body] all compile to: lua> "\ - ..local lua = \(compile as (local action %actions %body)) + ..local lua = \(what (%actions means %body) compiles to) + if \%actions.type ~= "List" then \%actions = {\%actions, type="List"} end lua:remove_free_vars(table.map(\%actions, function(a) return a.stub:as_lua_id() end)) return lua" test: assume ((action (say %)) == (=lua "say_1")) -compile [action %action] to (Lua value (%action.stub as lua id)) +(action %action) compiles to (Lua value (%action.stub as lua id)) test: - parse [swap %x and %y] as (..) + (swap %x and %y) parses as (..) do: %tmp = %x %x = %y @@ -166,9 +169,10 @@ test: swap %tmp and %tmp2 assume ((%tmp == 2) and (%tmp2 == 1)) or barf "\ ..'parse % as %' variable mangling failed." -compile [parse %actions as %body] to (..) +[%actions parses as %body, %actions all parse as %body] all compile to: lua> "\ ..local replacements = {} + if \%actions.type ~= "List" then \%actions = {\%actions, type="List"} end for i,arg in ipairs(\%actions[1]:get_args()) do replacements[arg[1]] = nomsu:compile(arg):as_smext() end @@ -204,36 +208,37 @@ compile [parse %actions as %body] to (..) local \%new_body = LuaCode(\%body.source, "local mangle = mangler()", "\\nreturn ", make_tree(\%body)) - local ret = \(compile as (compile %actions to %new_body)) + local ret = \(what (%actions compiles to %new_body) compiles to) return ret" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # TODO: add check for .is_value -compile [%tree as lua expr] to (Lua value "nomsu:compile(\(=lua "nomsu:compile(\%tree, nil, true)"), nil, true)") +(%tree as lua expr) compiles to (..) + Lua value "nomsu:compile(\(=lua "nomsu:compile(\%tree, nil, true)"), nil, true)" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -compile [%tree as lua] to (Lua value "nomsu:compile(\(%tree as lua expr))") -compile [%tree as lua statements] to (..) +(%tree as lua) compiles to (Lua value "nomsu:compile(\(%tree as lua expr))") +(%tree as lua statements) compiles to (..) Lua value "nomsu:compile(\(%tree as lua expr)):as_statements()" -compile [%tree as lua return] to (..) +(%tree as lua return) compiles to (..) Lua value "nomsu:compile(\(%tree as lua expr)):as_statements('return ')" -compile [remove action %action] to (..) +(remove action %action) compiles to (..) Lua "\(=lua "(\(%action.stub)):as_lua_id()") = nil" test: assume ("\(\(foo \%x) as nomsu)" == "foo %x") or barf "\ ..action source code failed." -compile [%tree as nomsu] to (..) +(%tree as nomsu) compiles to (..) Lua value "nomsu:tree_to_nomsu(\(%tree as lua expr))" -compile [%tree as inline nomsu] to (..) +(%tree as inline nomsu) compiles to (..) Lua value "nomsu:tree_to_inline_nomsu(\(%tree as lua expr), true)" -action [%var as lua identifier, %var as lua id] (..) +externally [%var as lua identifier, %var as lua id] all mean: lua> "\ ..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() @@ -248,17 +253,17 @@ action [%var as lua identifier, %var as lua id] (..) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -compile [% is syntax tree] to (Lua value "AST.is_syntax_tree(\(% as lua expr))") -compile [% is %kind syntax tree] to (..) +(% is syntax tree) compiles to (Lua value "AST.is_syntax_tree(\(% as lua expr))") +(% is %kind syntax tree) compiles to (..) Lua value "AST.is_syntax_tree(\(% as lua expr), \(%kind as lua expr))" -compile [%tree with %t -> %replacement] to (..) +(%tree with %t -> %replacement) compiles to (..) Lua value "\ ..\(%tree as lua expr):map(function(\(%t as lua expr)) \(%replacement as lua return) end)" -action [%tree with vars %replacements] (..) +externally (%tree with vars %replacements) means (..) =lua "\ ..\%tree:map(function(\%t) if \%t.type == "Var" then @@ -266,7 +271,7 @@ action [%tree with vars %replacements] (..) end end)" -compile [tree %tree with vars %replacements] to (..) +(tree %tree with vars %replacements) compiles to (..) Lua value "\ ..\(=lua "(\%tree):as_lua()"):map(function(t) if t.type == "Var" then @@ -274,7 +279,7 @@ compile [tree %tree with vars %replacements] to (..) end end)" -compile [%tree has subtree %match_tree] to (..) +(%tree has subtree %match_tree) compiles to (..) Lua value "\ ..(function() local match_tree = \(%match_tree as lua expr) @@ -283,7 +288,7 @@ compile [%tree has subtree %match_tree] to (..) end end)()" -action [match %tree with %patt]: +externally (match %tree with %patt) means: lua> "\ ..if \%patt.type == "Var" then return _Dict{[\%patt[1]]=\%tree} end if \%patt.type == "Action" and \%patt.stub ~= \%tree.stub then return nil end @@ -301,7 +306,7 @@ action [match %tree with %patt]: end return matches" -action [%tree with %patt ~> %replacement]: +externally (%tree with %patt ~> %replacement) means: lua> "\ ..return \%tree:map(function(\%t) local \%vars = \(match %t with %patt) @@ -323,7 +328,7 @@ test: ..one "two"" ..== "\"one\\n\\\"two\\\"\"" -compile [quote %s] to (Lua value "tostring(\(%s as lua expr)):as_lua()") +(quote %s) compiles to (Lua value "tostring(\(%s as lua expr)):as_lua()") test: assume (lua type of {}) == "table" @@ -331,21 +336,23 @@ test: assume ({} is a "Dict") assume ("" is text) assume ("" isn't a "Dict") +externally (% is text) means (=lua "\(lua type of %) == 'string'") +externally [% is not text, % isn't text] all mean (..) + =lua "\(lua type of %) ~= 'string'" -action [% is text] (=lua "\(lua type of %) == 'string'") -action [% is not text, % isn't text] (=lua "\(lua type of %) ~= 'string'") -action [type of %]: +externally (type of %) means: lua> "\ - local lua_type = \(lua type of %) + ..local lua_type = \(lua type of %) if lua_type == 'string' then return 'Text' elseif lua_type == 'table' then local mt = getmetatable(\%) if mt and mt.__type then return mt.__type end return 'Lua table' else return lua_type end" -parse [% is a %type, % is an %type] as ((type of %) == %type) -parse [% isn't a %type, % isn't an %type, % is not a %type, % is not an %type] -..as ((type of %) != %type) + +[% is a %type, % is an %type] all parse as ((type of %) == %type) +[% isn't a %type, % isn't an %type, % is not a %type, % is not an %type] all parse as (..) + (type of %) != %type ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -354,8 +361,8 @@ test: %a = (parse "\\1") %b = \(\(1)) assume ((parse "\\1") == \(\(1))) -compile [parse %text] to (Lua value "nomsu:parse(\(%text as lua expr))") -compile [parse %text from %filename] to (..) +(parse %text) compiles to (Lua value "nomsu:parse(\(%text as lua expr))") +(parse %text from %filename) compiles to (..) Lua value "\ ..nomsu:parse(NomsuCode(Source(\(%filename as lua expr), 1, #\(%text as lua expr)), \(..) %text as lua expr @@ -366,37 +373,39 @@ test: external %passed = (no) run "external %passed = (yes)" assume %passed -compile [run %nomsu_code] to (..) +(run %nomsu_code) compiles to (..) Lua value "\ - ..nomsu:run(NomsuCode(\(..) - =lua "tostring(\(%nomsu_code.source)):as_lua()" - .., \(%nomsu_code as lua expr)))" + ..nomsu:run(NomsuCode(\(=lua "tostring(\(%nomsu_code.source)):as_lua()"), \(..) + %nomsu_code as lua expr + ..))" test: assume ((\(\(5) + \(5)) as value) == 10) or barf "%tree as value failed." -compile [run tree %tree, %tree as value] to (Lua value "nomsu:run(\(%tree as lua expr))") -compile [compile %block, compiled %block, %block compiled] to (..) +[run tree %tree, %tree as value] all compile to (..) + Lua value "nomsu:run(\(%tree as lua expr))" + +[compile %block, compiled %block, %block compiled] all compile to (..) Lua value "nomsu:compile(\(%block as lua))" # 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 (Lua "do return; end") -compile [return %return_value] to (..) +(return) compiles to (Lua "do return; end") +(return %return_value) compiles to (..) Lua "do return \(%return_value as lua expr) end" # Literals -compile [yes] to (Lua value "true") -compile [no] to (Lua value "false") -compile [nothing, nil, null] to (Lua value "nil") -compile [Nomsu syntax version] to (Lua value "NOMSU_SYNTAX_VERSION") -compile [Nomsu compiler version] to (Lua value "NOMSU_COMPILER_VERSION") -compile [core version] to (Lua value "NOMSU_CORE_VERSION") -compile [lib version] to (Lua value "NOMSU_LIB_VERSION") -compile [command line args] to (Lua value "arg") +(yes) compiles to (Lua value "true") +(no) compiles to (Lua value "false") +[nothing, nil, null] all compile to (Lua value "nil") +(Nomsu syntax version) compiles to (Lua value "NOMSU_SYNTAX_VERSION") +(Nomsu compiler version) compiles to (Lua value "NOMSU_COMPILER_VERSION") +(core version) compiles to (Lua value "NOMSU_CORE_VERSION") +(lib version) compiles to (Lua value "NOMSU_LIB_VERSION") +(command line args) compiles to (Lua value "arg") ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -compile [with local compile actions %body] to (..) +(with local compile actions %body) compiles to (..) Lua "\ ..do local nomsu = nomsu:fork() @@ -404,7 +413,7 @@ compile [with local compile actions %body] to (..) \(%body as lua statements) end" -action [Nomsu version]: +externally (Nomsu version) means: use "lib/version.nom" return "\ ..\(Nomsu syntax version).\(core version).\(Nomsu compiler version).\(lib version)" diff --git a/core/operators.nom b/core/operators.nom index 55756bb..489bbfe 100644 --- a/core/operators.nom +++ b/core/operators.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file contains definitions of operators like "+" and "and". @@ -9,14 +9,14 @@ test: assume (all [1 < 2, 2 > 1, 1 <= 2, 2 >= 1, 1 == 1, 1 != 2]) # Comparison Operators -compile [%x < %y] to (Lua value "(\(%x as lua expr) < \(%y as lua expr))") -compile [%x > %y] to (Lua value "(\(%x as lua expr) > \(%y as lua expr))") -compile [%x <= %y] to (Lua value "(\(%x as lua expr) <= \(%y as lua expr))") -compile [%x >= %y] to (Lua value "(\(%x as lua expr) >= \(%y as lua expr))") -compile [%a is %b, %a == %b] to (..) +(%x < %y) compiles to (Lua value "(\(%x as lua expr) < \(%y as lua expr))") +(%x > %y) compiles to (Lua value "(\(%x as lua expr) > \(%y as lua expr))") +(%x <= %y) compiles to (Lua value "(\(%x as lua expr) <= \(%y as lua expr))") +(%x >= %y) compiles to (Lua value "(\(%x as lua expr) >= \(%y as lua expr))") +[%a is %b, %a == %b] all compile to (..) Lua value "(\(%a as lua expr) == \(%b as lua expr))" -compile [%a isn't %b, %a is not %b, %a not= %b, %a != %b] to (..) +[%a isn't %b, %a is not %b, %a not= %b, %a != %b] all compile to (..) Lua value "(\(%a as lua expr) ~= \(%b as lua expr))" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -26,7 +26,7 @@ test: assume (%x == 10) # Variable assignment operator -compile [%var = %value] to: +(%var = %value) compiles to: lua> "local \%var_lua = \(%var as lua expr)" assume %var_lua.is_value or barf "Invalid target for assignment: \%var" lua> "local \%value_lua = \(%value as lua expr)" @@ -45,7 +45,7 @@ test: assume ((%y == 10) and (%x == 20)) or barf "swapping vars failed." # Simultaneous mutli-assignments like: x,y,z = 1,x,3; -compile [set %assignments] to: +(set %assignments) compiles to: assume (%assignments.type is "Dict") or barf "\ ..Expected a Dict for the assignments part of '<- %' statement, not \%assignments" lua> "\ @@ -81,13 +81,13 @@ compile [set %assignments] to: test: set {%foozle:"outer", %y:"outer"} - action [set global x local y]: + externally (set global x local y) means: external %foozle = "inner" %y = "inner" set global x local y assume ((%foozle == "inner") and (%y == "outer")) or barf "external failed." -compile [external %var = %value] to: +(external %var = %value) compiles to: %var_lua = (%var as lua) assume %var_lua.is_value or barf "Invalid target for assignment: \%var" %value_lua = (%value as lua) @@ -96,7 +96,7 @@ compile [external %var = %value] to: test: set {%foozle:"outer", %y:"outer"} - action [set global x local y] (..) + externally (set global x local y) means (..) with external [%foozle]: %foozle = "inner" %y = "inner" @@ -104,7 +104,7 @@ test: set global x local y assume ((%foozle == "inner") and (%y == "outer")) or barf "\ ..'with external' failed." -compile [with external %externs %body] to: +(with external %externs %body) compiles to: %body_lua = (%body as lua statements) lua> "\ ..\%body_lua:remove_free_vars(table.map(\%externs, function(v) return nomsu:compile(v):as_smext() end))" @@ -119,7 +119,7 @@ test: assume (%x == 1) or barf "'with' scoping failed" assume (%z == (nil)) or barf "'with' scoping failed" -compile [with %assignments %body] to: +(with %assignments %body) compiles to: %lua = (%body as lua statements) lua> "\ ..local lhs, rhs = LuaCode(tree.source), LuaCode(tree.source) @@ -156,53 +156,53 @@ compile [with %assignments %body] to: # Math Operators test: assume ((5 wrapped around 2) == 1) or barf "mod not working" -compile [%x wrapped around %y, %x mod %y] to (..) +[%x wrapped around %y, %x mod %y] all compile to (..) Lua value "((\(%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) test: %calls = 0 - local action [one]: + (one) means: external %calls = (%calls + 1) return 1 assume (0 <= (one) <= 2) or barf "Three-way chained comparison failed." assume (%calls == 1) or barf "\ ..Three-way comparison evaluated middle value multiple times" -parse [%x < %y < %z] as (..) +(%x < %y < %z) parses as (..) call ([%a, %b, %c] -> ((%a < %b) and (%b < %c))) with [%x, %y, %z] -parse [%x <= %y < %z] as (..) +(%x <= %y < %z) parses as (..) call ([%a, %b, %c] -> ((%a <= %b) and (%b < %c))) with [%x, %y, %z] -parse [%x < %y <= %z] as (..) +(%x < %y <= %z) parses as (..) call ([%a, %b, %c] -> ((%a < %b) and (%b <= %c))) with [%x, %y, %z] -parse [%x <= %y <= %z] as (..) +(%x <= %y <= %z) parses as (..) call ([%a, %b, %c] -> ((%a <= %b) and (%b <= %c))) with [%x, %y, %z] -parse [%x > %y > %z] as (..) +(%x > %y > %z) parses as (..) call ([%a, %b, %c] -> ((%a > %b) and (%b > %c))) with [%x, %y, %z] -parse [%x >= %y > %z] as (..) +(%x >= %y > %z) parses as (..) call ([%a, %b, %c] -> ((%a >= %b) and (%b > %c))) with [%x, %y, %z] -parse [%x > %y >= %z] as (..) +(%x > %y >= %z) parses as (..) call ([%a, %b, %c] -> ((%a > %b) and (%b >= %c))) with [%x, %y, %z] -parse [%x >= %y >= %z] as (..) +(%x >= %y >= %z) parses as (..) call ([%a, %b, %c] -> ((%a >= %b) and (%b >= %c))) with [%x, %y, %z] # TODO: optimize for common case where x,y,z are all either variables or number literals # Boolean Operators test: - local action [barfer] (barf "short circuiting failed") + (barfer) means (barf "short circuiting failed") assume (((no) and (barfer)) == (no)) assume ((no) or (yes)) assume ((yes) or (barfer)) -compile [%x and %y] to (Lua value "(\(%x as lua expr) and \(%y as lua expr))") -compile [%x or %y] to (Lua value "(\(%x as lua expr) or \(%y as lua expr))") +(%x and %y) compiles to (Lua value "(\(%x as lua expr) and \(%y as lua expr))") +(%x or %y) compiles to (Lua value "(\(%x as lua expr) or \(%y as lua expr))") ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -219,31 +219,31 @@ test: # Lua 5.3 introduced bit operators like | and &. Use them when possible, otherwise fall back to bit.bor(), bit.band(), etc. %use_bitops = ((is jit) or ((Lua version) == "Lua 5.2")) -compile [NOT %, ~ %] to (..) +[NOT %, ~ %] all compile to (..) Lua value (..) (%use_bitops and "bit.bnot(\(% as lua expr))") or "~(\(% as lua expr))" -compile [%a OR %b, %a | %b] to (..) +[%a OR %b, %a | %b] all compile to (..) Lua value (..) (%use_bitops and "bit.bor(\(%a as lua expr), \(%b as lua expr))") or "\ ..(\(%a as lua expr) | \(%b as lua expr))" -compile [%a XOR %b, %a ~ %b] to (..) +[%a XOR %b, %a ~ %b] all compile to (..) Lua value (..) (%use_bitops and "bit.bxor(\(%a as lua expr), \(%b as lua expr))") or "\ ..(\(%a as lua expr) ~ \(%b as lua expr))" -compile [%a AND %b, %a & %b] to (..) +[%a AND %b, %a & %b] all compile to (..) Lua value (..) (%use_bitops and "bit.band(\(%a as lua expr), \(%b as lua expr))") or "\ ..(\(%a as lua expr) & \(%b as lua expr))" -compile [%x LSHIFT %shift, %x << %shift] to (..) +[%x LSHIFT %shift, %x << %shift] all compile to (..) Lua value (..) (%use_bitops and "bit.lshift(\(%x as lua expr), \(%shift as lua expr))") or "\ ..(\(%x as lua expr) << \(%shift as lua expr))" -compile [%x RSHIFT %shift, %x >> %shift] to (..) +[%x RSHIFT %shift, %x >> %shift] all compile to (..) Lua value (..) (%use_bitops and "bit.rshift(\(%x as lua expr), \(%shift as lua expr))") or "\ ..(\(%x as lua expr) >> \(%shift as lua expr))" @@ -252,15 +252,15 @@ compile [%x RSHIFT %shift, %x >> %shift] to (..) test: assume ((- 5) == -5) assume ((not (yes)) == (no)) -compile [- %] to (Lua value "(- \(% as lua expr))") -compile [not %] to (Lua value "(not \(% as lua expr))") +(- %) compiles to (Lua value "(- \(% as lua expr))") +(not %) compiles to (Lua value "(not \(% as lua expr))") test: assume ((size of [1, 2, 3]) == 3) -compile [size of %list, size of %list, size of %list, size of %list] to (..) +[size of %list, size of %list, size of %list, size of %list] all compile to (..) Lua value "(#\(%list as lua expr))" -compile [%list is empty] to (Lua value "(#\(%list as lua expr) == 0)") +(%list is empty) compiles to (Lua value "(#\(%list as lua expr) == 0)") ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -273,11 +273,11 @@ test: assume (%x == 4) or barf "*= failed" wrap %x around 3 assume (%x == 1) or barf "wrap around failed" -parse [%var += %] as (%var = (%var + %)) -parse [%var -= %] as (%var = (%var - %)) -parse [%var *= %] as (%var = (%var * %)) -parse [%var /= %] as (%var = (%var / %)) -parse [%var ^= %] as (%var = (%var ^ %)) -parse [%var and= %] as (%var = (%var and %)) -parse [%var or= %] as (%var = (%var or %)) -parse [wrap %var around %] as (%var = (%var wrapped around %)) +(%var += %) parses as (%var = (%var + %)) +(%var -= %) parses as (%var = (%var - %)) +(%var *= %) parses as (%var = (%var * %)) +(%var /= %) parses as (%var = (%var / %)) +(%var ^= %) parses as (%var = (%var ^ %)) +(%var and= %) parses as (%var = (%var and %)) +(%var or= %) parses as (%var = (%var or %)) +(wrap %var around %) parses as (%var = (%var wrapped around %)) diff --git a/core/scopes.nom b/core/scopes.nom index c01a361..715409c 100644 --- a/core/scopes.nom +++ b/core/scopes.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file contains definitions pertaining to variable scoping @@ -14,19 +14,19 @@ test: assume (%x == "inner") assume (%x == "outer") - action [foo] "outer foo" + externally (foo) means "outer foo" with local [action (foo)]: - action [foo] "inner foo" + externally (foo) means "inner foo" assume ((foo) == "inner foo") assume ((foo) == "outer foo") -compile [with local %locals %body, with local %locals do %body] to: +[with local %locals %body, with local %locals do %body] all compile to: %body_lua = (%body as lua statements) if %locals.type is: "Dict": %body_lua = (..) Lua "\ - ..\(compile as (<- %locals)) + ..\(what (<- %locals) compiles to) \%body_lua" %body_lua::declare locals ("\(%.1 as lua)" for % in %locals) diff --git a/core/text.nom b/core/text.nom index 25e9c3c..05ec409 100644 --- a/core/text.nom +++ b/core/text.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file contains some definitions of text escape sequences, including ANSI console color codes. @@ -22,12 +22,12 @@ test: assume ("asdf"::uppercase) == "ASDF" assume ("asdf"::with "s" -> "X") == "aXdf" assume ("one\ntwo\n"::lines) == ["one", "two", ""] - parse [アクション %spec %body] as (action %spec %body) + (アクション %spec %body) parses as (externally %spec means %body) test: %こんにちは = "こんにちは" アクション [% と言う] "\(%)世界" assume (%こんにちは と言う) == "こんにちは世界" -compile [%expr for %match in %text matching %patt] to (..) +(%expr for %match in %text matching %patt) compiles to (..) Lua value "\ ..(function() local ret = _List{} diff --git a/examples/how_do_i.nom b/examples/how_do_i.nom index 1d43982..e8e838b 100644 --- a/examples/how_do_i.nom +++ b/examples/how_do_i.nom @@ -1,10 +1,10 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # How do I... # Write a comment? Put a # and go till the end of the line # How do I write a multi-line comment? After a comment line, any indented text is considered part of the comment - (including any deeper-level indented text) + (including any deeper-level indented text) The comment ends when the indentation ends # How do I import a file? use "lib/os.nom" @@ -167,14 +167,14 @@ do: # How do I define a function/method/procedure? # In nomsu, they're called "action"s, and they can be declared like this: -action [say both %first and also %second]: +(say both %first and also %second) means: say %first # Function arguments are accessed just like variables say %second # Actions can use "return" to return a value early -action [first fibonacci above %n]: +(first fibonacci above %n) means: %f1 = 0 %f2 = 1 repeat: @@ -186,11 +186,11 @@ action [first fibonacci above %n]: say (first fibonacci above 10) # Actions can have aliases, which may or may not have the arguments in different order -action [..] +[..] I hate %worse_things more than %better_things I think %worse_things are worse than %better_things I like %better_things more than %worse_things -..: +..all mean: say "\(%better_things::capitalized) rule and \%worse_things drool!" I like "dogs" more than "cats" @@ -201,7 +201,7 @@ I think "chihuahuas" are worse than "corgis" say both "Hello" and also "again!" # Actions can even start with a parameter -action [%what_she_said is what she said]: +(%what_she_said is what she said) means: say %what_she_said say "-- she said" @@ -209,7 +209,7 @@ action [%what_she_said is what she said]: # The language only reserves []{}().,:;% as special characters, so actions can have really funky names! -action [>> %foo_bar $$$^ --> % @&_~-^-~_~-^ %1 !]: +(>> %foo_bar $$$^ --> % @&_~-^-~_~-^ %1 !) means: say %foo_bar say % say %1 @@ -218,7 +218,7 @@ action [>> %foo_bar $$$^ --> % @&_~-^-~_~-^ %1 !]: # There's also full unicode support %こんにちは = "こんにちは" -action [% と言う] "\%世界" +(% と言う) means "\%世界" say (%こんにちは と言う) # Math and logic operations are just treated the same as actions in the syntax @@ -226,7 +226,7 @@ say (2 + 3) # So you can define your own operators, although they will need to be parenthesized to play nicely with other operators -action [%a ++ %b] (2 * (%a + %b)) +(%a ++ %b) means (2 * (%a + %b)) say (1 ++ (2 * 3)) # How do I do grouping? @@ -240,36 +240,38 @@ say (2 + 3) say both "Very long first argument that needs its own line" and also "\ ..short second arg" -action [my favorite number] (21 + 2) +(my favorite number) means (21 + 2) # This can be nested: say both (my favorite number) and also "foo" # Macros: # The "lua> %" and "=lua %" macros can be used to write raw lua code: -action [say the time] (lua> "io.write(\"The OS time is: \", os.time(), \"\\n\");") +(say the time) means (..) + lua> "io.write(\"The OS time is: \", os.time(), \"\\n\");" + say the time say "Math expression result is: \(=lua "(1 + 2*3 + 3*4)^2")" # Variables can be accessed via \%varname -action [square root of %n] (=lua "math.sqrt(\%n)") +(square root of %n) means (=lua "math.sqrt(\%n)") say "The square root of 2 is \(square root of 2)" # Macros can be defined to transform one bit of nomsu code into another using "parse % as %": -parse [if %condition is untrue %body] as (if (not %condition) %body) +(if %condition is untrue %body) parses as (if (not %condition) %body) # Or to transform nomsu code into custom lua code using "compile % to %" -compile [if %condition on opposite day %body] to (..) +(if %condition on opposite day %body) compiles to (..) Lua "\ ..if not \(%condition as lua expr) then \(%body as lua statements) end" # Constants can be defined as macros -parse [TWENTY] as 20 +(TWENTY) parses as 20 # When they're invoked, they'll need parentheses just like a function call -parse [TWENTY ONE] as 21 +(TWENTY ONE) parses as 21 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -286,7 +288,7 @@ if (1 > (TWENTY)) on opposite day: # How do I use an action as a value? # Well... it's always *possible* to fall back to Lua behavior for something like this: -action [best of %items according to %key_fn]: +(best of %items according to %key_fn) means: set {%best:nil, %best_key:nil} for %item in %items: %key = (=lua "\%key_fn(\%item)") @@ -301,7 +303,7 @@ say (best of [2, -3, 4, -8] according to ([%x] -> (%x * %x))) one-off function to pass to another function and get called a bunch of times, you could use a macro to generate a single block of code that inlines the expression you want to use: -parse [best of %items where %item_var has score %key_expr] as (..) +(best of %items where %item_var has score %key_expr) parses as (..) result of: set {%best:nil, %best_key:nil} for %item_var in %items: diff --git a/lib/base64.nom b/lib/base64.nom index 8fc4e6b..2091615 100644 --- a/lib/base64.nom +++ b/lib/base64.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file defines actions for encoding/decoding base 64, as specified in: https://tools.ietf.org/html/rfc4648 @@ -13,7 +13,7 @@ test: %plain = "foobar".[1, %len - 1] assume (base64 %plain) == %encoded assume (base64 decode %encoded) == %plain -action [base64 %str, base64 encode %str, %str base64]: +externally [base64 %str, base64 encode %str, %str base64] all mean: %chars = [] for %i in 1 to (size of %str) via 3: %bytes = [=lua "\%str:byte(\%i, \(%i + 2))"] @@ -36,8 +36,8 @@ action [base64 %str, base64 encode %str, %str base64]: return (%chars::joined) -action [chr %] (=lua "string.char(\%)") -action [decode base64 %str, %str base64 decoded, base64 decode %str]: +externally (chr %) means (=lua "string.char(\%)") +externally [decode base64 %str, %str base64 decoded, base64 decode %str] all mean: %chars = [] for %i in 1 to (size of %str) via 4: %indices = (%reverse_b64.(%str.%) for % in %i to (%i + 3)) diff --git a/lib/consolecolor.nom b/lib/consolecolor.nom index f4c4df9..e0e032d 100644 --- a/lib/consolecolor.nom +++ b/lib/consolecolor.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file defines actions for ANSI console color escape codes. @@ -15,8 +15,7 @@ test: for %name = %colornum in %colors: %colornum = "\%colornum" (=lua "COMPILE_ACTIONS").%name = (..) - [%nomsu, %tree] -> (..) - Lua value "'\\027[\(%colornum)m'" + [%nomsu, %tree] -> (Lua value "'\\027[\(%colornum)m'") (=lua "COMPILE_ACTIONS")."\%name 1" = (..) [%nomsu, %tree, %text] -> (..) Lua value "('\\027[\(%colornum)m'..\(%text as lua expr)..'\\027[0m')" diff --git a/lib/file_hash.nom b/lib/file_hash.nom index 6fdb2f4..6c815f5 100644 --- a/lib/file_hash.nom +++ b/lib/file_hash.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file defines some actions for hashing files and looking up files by hash. @@ -26,14 +26,14 @@ test: if %use_sha1: assume ((hash "hello world") == "Kq5sNclPz7QV2+lfQIuc6R7oRu0=") if %use_sha1: - action [hash %]: + externally (hash %) means: %hash = (=lua "\%hashlib.new('sha1'):final(\%)") return (base64 %hash) ..else: # TODO: remove warning? say "\ ..\027[31;1mWARNING: OpenSSL module not found. Defaulting to a non-cryptographically secure hash function.\027[0m" - action [hash %]: + externally (hash %) means: %bytes = (%::bytes) %hash = (%bytes.1 << 7) for %i in 2 to (size of %bytes): @@ -41,10 +41,10 @@ if %use_sha1: %hash = (%hash ~ (size of %bytes)) return "\%hash" -action [file with hash %hash]: +externally (file with hash %hash) means: for file %filename in ".": %contents = (read file %filename) %file_hash = (hash %contents) if (%file_hash == %hash): return %filename -parse [hash of file %filename] as (hash (read file %filename)) +(hash of file %filename) parses as (hash (read file %filename)) diff --git a/lib/object.nom b/lib/object.nom index bbc6e06..4f45188 100644 --- a/lib/object.nom +++ b/lib/object.nom @@ -1,15 +1,13 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file contains the implementation of an Object-Oriented programming system. %globals.METAMETHOD_MAP = {..} - "as text": "__tostring", "clean up": "__gc", - "+ 1": "__add", "- 1": "__sub", "* 1": "__mul", "/ 1": "__div", - "-": "__unm", "// 1": "__idiv", "mod 1": "__mod", "^ 1": "__pow", - "& 1": "__band", "| 1": "__bor", "~ 1": "__bxor", "~": "__bnot", - "<< 1": "__bshl", ">> 1": "__bshr", "== 1": "__eq", "< 1": "__lt", - "<= 1": "__le", "set 1 = 2": "__newindex", "size": "__len", - "iterate": "__ipairs", "iterate all": "__pairs", + "as text":"__tostring", "clean up":"__gc", "+ 1":"__add", "- 1":"__sub" + "* 1":"__mul", "/ 1":"__div", "-":"__unm", "// 1":"__idiv", "mod 1":"__mod" + "^ 1":"__pow", "& 1":"__band", "| 1":"__bor", "~ 1":"__bxor", "~":"__bnot" + "<< 1":"__bshl", ">> 1":"__bshr", "== 1":"__eq", "< 1":"__lt", "<= 1":"__le" + "set 1 = 2":"__newindex", size:"__len", iterate:"__ipairs", "iterate all":"__pairs" test: object (Dog): @@ -53,13 +51,13 @@ test: with {%d:Dog {barks:2}}: assume ((%d::bark) == "Bark! Bark!") -compile [my action %actions %body] to: +(my action %actions %body) compiles to: lua> "\ ..local fn_name = \%actions[1].stub:as_lua_id() local \%args = table.map(\%actions[1]:get_args(), function(a) return tostring(nomsu:compile(a)) end) table.insert(\%args, 1, \(\%me as lua id)) local lua = LuaCode(tree.source, "class.", fn_name, " = ", \(..) - compile as (%args -> %body) + what (%args -> %body) compiles to ..) for i=2,#\%actions do local alias = \%actions[i] @@ -79,12 +77,13 @@ compile [my action %actions %body] to: end return lua" -compile [object %classname extends %parent %class_body] to: +(object %classname extends %parent %class_body) compiles to: unless (%classname.type == "Action"): compile error at %classname "Expected this to be an action, not a \(%classname.type)" for % in %classname: unless (% is text): compile error at % "Class names should not have arguments." + return (..) Lua "\ ..do @@ -112,6 +111,5 @@ compile [object %classname extends %parent %class_body] to: end end" -parse [object %classname %class_body] as (..) +(object %classname %class_body) parses as (..) object %classname extends (nil) %class_body - diff --git a/lib/os.nom b/lib/os.nom index e6faa18..2bd91ad 100644 --- a/lib/os.nom +++ b/lib/os.nom @@ -1,14 +1,14 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file defines some actions that interact with the operating system and filesystem. test: path of Nomsu file "lib/os.nom" -action [path of Nomsu file %filename]: +externally (path of Nomsu file %filename) means: lua> "for i,f in Files.walk(\%filename) do return f end" barf "Could not find file: \%filename" -action [sh> %cmd]: +externally (sh> %cmd) means: lua> "\ ..local result = io.popen(\%cmd) local contents = result:read("*a") @@ -17,19 +17,19 @@ action [sh> %cmd]: test: read file "lib/os.nom" -action [read file %filename] (=lua "Files.read(\%filename)") +externally (read file %filename) means (=lua "Files.read(\%filename)") test: for file %f in "core": do nothing -compile [for file %f in %path %body] to (..) +(for file %f in %path %body) compiles to (..) Lua "\ ..for i,\(%f as lua expr) in Files.walk(\(%path as lua expr)) do \(%body as lua statements) - \(compile as (===next %f ===)) + \(what (===next %f ===) compiles to) end - \(compile as (===stop %f ===))" + \(what (===stop %f ===) compiles to)" -compile [%expr for file %f in %path] to (..) +(%expr for file %f in %path) compiles to (..) Lua value "\ ..(function() local ret = _List{} @@ -39,10 +39,10 @@ compile [%expr for file %f in %path] to (..) return ret end)()" -action [..] +externally [..] write to file %filename %text, to file %filename write %text write %text to file %filename -..: +..all mean: assume (%filename != "stdin") or barf "Cannot write to stdin" lua> "\ ..local file = io.open(\%filename, 'w') @@ -51,15 +51,17 @@ action [..] test: assume (line number of 3 in "x\ny") == 2 -action [line number of %pos in %str] (=lua "Files.get_line_number(\%str, \%pos)") +externally (line number of %pos in %str) means (..) + =lua "Files.get_line_number(\%str, \%pos)" test: assume (line 2 in "one\ntwo\nthree") == "two" -action [line %line_num in %str] (=lua "Files.get_line(\%str, \%line_num)") +externally (line %line_num in %str) means (..) + =lua "Files.get_line(\%str, \%line_num)" test: assume (source lines of \(this)) -action [source lines of %tree]: +externally (source lines of %tree) means: %source = (%tree.source if (%tree is syntax tree) else %tree) %file = (read file %source.filename) return (..) diff --git a/lib/training_wheels.nom b/lib/training_wheels.nom index 6155069..f16b700 100644 --- a/lib/training_wheels.nom +++ b/lib/training_wheels.nom @@ -1,26 +1,28 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file contains a set of definitions that bring some familiar language features from other languages into nomsu (e.g. "||" and "continue") -parse [%a === %b] as ((%a 's id) is (%b 's id)) -parse [%a !== %b] as ((%a 's id) is not (%b 's id)) -parse [function %names %body, def %names %body] as (action %names %body) -parse [switch %branch_value %body] as (if %branch_value is %body) -parse [None, Null] as (nil) -parse [True, true] as (yes) -parse [False, false] as (no) -parse [pass] as (do nothing) -parse [%a || %b] as (%a or %b) -parse [%a && %b] as (%a and %b) -parse [continue] as (do next) -parse [break] as (stop) -parse [let %thing = %value in %action] as (with local {%thing:%value}) -parse [print %, println %] as (say %) -parse [error!, panic!, fail!, abort!] as (barf!) -parse [error %, panic %, fail %, abort %] as (barf %) -parse [assert %condition] as (assume %condition) -parse [assert %condition %message] as (assume %condition or barf %message) -parse [%cond ? %if_true %if_false] as (%if_true if %cond else %if_false) -parse [lambda %args %body] as (%args -> %body) -parse [function %name %args %body] as (%name = (%args -> %body)) +(%a === %b) parses as ((%a 's id) is (%b 's id)) +(%a !== %b) parses as ((%a 's id) is not (%b 's id)) +[function %names %body, def %names %body] all parse as (..) + externally %names means %body + +(switch %branch_value %body) parses as (if %branch_value is %body) +[None, Null] all parse as (nil) +[True, true] all parse as (yes) +[False, false] all parse as (no) +(pass) parses as (do nothing) +(%a || %b) parses as (%a or %b) +(%a && %b) parses as (%a and %b) +(continue) parses as (do next) +(break) parses as (stop) +(let %thing = %value in %action) parses as (with local {%thing:%value}) +[print %, println %] all parse as (say %) +[error!, panic!, fail!, abort!] all parse as (barf!) +[error %, panic %, fail %, abort %] all parse as (barf %) +(assert %condition) parses as (assume %condition) +(assert %condition %message) parses as (assume %condition or barf %message) +(%cond ? %if_true %if_false) parses as (%if_true if %cond else %if_false) +(lambda %args %body) parses as (%args -> %body) +(function %name %args %body) parses as (%name = (%args -> %body)) diff --git a/lib/version.nom b/lib/version.nom index afb9e14..2f4003f 100644 --- a/lib/version.nom +++ b/lib/version.nom @@ -1,3 +1,3 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file sets the current library version. lua> "NOMSU_LIB_VERSION = 6" diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua index f9ba314..dff7eb7 100644 --- a/nomsu_compiler.lua +++ b/nomsu_compiler.lua @@ -459,12 +459,19 @@ do return add_lua_bits(self, "value", code) end, ["use 1"] = function(self, tree, path) + local lua = LuaCode(tree.source) if path.type == 'Text' and #path == 1 and type(path[1]) == 'string' then for _, f in Files.walk(path[1]) do - self:import(self:run_file(f)) + if match(f, "%.lua$") or match(f, "%.nom$") or match(f, "^/dev/fd/[012]$") then + self:import(self:run_file(f)) + if #lua.bits > 0 then + lua:append("\n") + end + lua:append("nomsu:import(nomsu:run_file(" .. tostring(f:as_lua()) .. "))") + end end end - return LuaCode(tree.source, "for i,f in Files.walk(", self:compile(path), ") do nomsu:import(nomsu:run_file(f)) end") + return lua end, ["tests"] = function(self, tree) return LuaCode.Value(tree.source, "TESTS") diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon index 1106382..4746e10 100644 --- a/nomsu_compiler.moon +++ b/nomsu_compiler.moon @@ -264,11 +264,14 @@ with NomsuCompiler return add_lua_bits(@, "value", code) ["use 1"]: (tree, path)=> + lua = LuaCode(tree.source) if path.type == 'Text' and #path == 1 and type(path[1]) == 'string' for _,f in Files.walk(path[1]) - @import(@run_file(f)) - - return LuaCode(tree.source, "for i,f in Files.walk(", @compile(path), ") do nomsu:import(nomsu:run_file(f)) end") + if match(f, "%.lua$") or match(f, "%.nom$") or match(f, "^/dev/fd/[012]$") + @import(@run_file(f)) + if #lua.bits > 0 then lua\append "\n" + lua\append "nomsu:import(nomsu:run_file(#{f\as_lua!}))" + return lua ["tests"]: (tree)=> LuaCode.Value(tree.source, "TESTS") ["test 1"]: (tree, body)=> diff --git a/tools/upgrade.nom b/tools/upgrade.nom index 4e03945..7d36793 100755 --- a/tools/upgrade.nom +++ b/tools/upgrade.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # Tool to automatically update code from old versions of Nomsu. Usage: nomsu tools/upgrade.nom [-i] file1 file2 directory1 ... -- cgit v1.2.3 From 83219f8522271ae4f278abc5687921cc8267bb33 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Wed, 31 Oct 2018 03:51:37 -0700 Subject: Bumped version number, fixed REPL, and simplified/fixed (use %). --- files.lua | 22 ++++++++++------------ files.moon | 10 +++------- nomsu.lua | 15 +++++---------- nomsu.moon | 15 ++++++--------- nomsu_compiler.lua | 22 ++++++++++------------ nomsu_compiler.moon | 16 ++++++++-------- 6 files changed, 42 insertions(+), 58 deletions(-) diff --git a/files.lua b/files.lua index c04f703..48e047f 100644 --- a/files.lua +++ b/files.lua @@ -191,20 +191,18 @@ Files.walk = function(path, flush_cache) end end end - local iter - iter = function(files, i) - if not (files) then - return - end - i = i + 1 - do - local f = files[i] - if f then - return i, f - end + files = files or { } + do + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #files do + local f = files[_index_0] + _accum_0[_len_0] = gsub(f, "^%./", "") + _len_0 = _len_0 + 1 end + files = _accum_0 end - return iter, files, 0 + return ipairs(files) end local line_counter = re.compile([[ lines <- {| line (%nl line)* |} line <- {} (!%nl .)* diff --git a/files.moon b/files.moon index becc3fb..e0fe02b 100644 --- a/files.moon +++ b/files.moon @@ -33,7 +33,6 @@ Files.read = (filename)-> _FILE_CACHE[filename] = contents return contents --- `walk` returns an iterator over all files matching a path. {:match, :gsub} = string -- TODO: improve sanitization @@ -108,12 +107,9 @@ Files.walk = (path, flush_cache=false)-> else for nomsupath in package.nomsupath\gmatch("[^;]+") if files = browse(nomsupath.."/"..path) then break - iter = (files, i)-> - return unless files - i += 1 - if f = files[i] - return i, f - return iter, files, 0 + files or= {} + files = [gsub(f, "^%./", "") for f in *files] + return ipairs(files) line_counter = re.compile([[ lines <- {| line (%nl line)* |} diff --git a/nomsu.lua b/nomsu.lua index fa6a6ce..bd1ee85 100644 --- a/nomsu.lua +++ b/nomsu.lua @@ -133,8 +133,7 @@ end local nomsu = NomsuCompiler nomsu.environment.arg = NomsuCompiler.environment._List(args.nomsu_args) if args.version then - nomsu:run([[use "core" -say (Nomsu version)]]) + nomsu:run([[(: use "core"; say (Nomsu version))]]) os.exit(EXIT_SUCCESS) end FILE_CACHE = setmetatable({ }, { @@ -183,11 +182,7 @@ run = function() return true end if not (args.no_core) then - for _, filename in Files.walk('core') do - if filename:match("%.nom$") then - nomsu:import(nomsu:run_file(filename)) - end - end + nomsu:import_file('core') end local get_file_and_source get_file_and_source = function(filename) @@ -280,8 +275,8 @@ run = function() if not (args.primary_file or args.exec_strings) then nomsu:run([[#!/usr/bin/env nomsu -V4 use "lib/consolecolor.nom" -action [quit, exit]: lua> "os.exit(0)" -action [help]: +[quit, exit] all mean: lua> "os.exit(0)" +(help) means: say "\ ..This is the Nomsu v\(Nomsu version) interactive console. You can type in Nomsu code here and hit 'enter' twice to run it. @@ -320,7 +315,7 @@ say "\ return Errhand.print_error(error_message) end local ret - ok, ret = xpcall(nomsu.run, err_hand, nomsu, buff, Source(pseudo_filename, 1, #buff)) + ok, ret = xpcall(nomsu.run, err_hand, nomsu, NomsuCode(Source(pseudo_filename, 1, #buff), buff)) if ok and ret ~= nil then if type(ret) == 'number' then print("= " .. tostring(ret)) diff --git a/nomsu.moon b/nomsu.moon index 1ab9637..c4a96f1 100755 --- a/nomsu.moon +++ b/nomsu.moon @@ -89,9 +89,7 @@ nomsu = NomsuCompiler nomsu.environment.arg = NomsuCompiler.environment._List(args.nomsu_args) if args.version - nomsu\run [[ -use "core" -say (Nomsu version)]] + nomsu\run [[(: use "core"; say (Nomsu version))]] os.exit(EXIT_SUCCESS) export FILE_CACHE @@ -123,9 +121,7 @@ run = -> return true unless args.no_core - for _,filename in Files.walk('core') - if filename\match "%.nom$" - nomsu\import(nomsu\run_file(filename)) + nomsu\import_file('core') get_file_and_source = (filename)-> local file, source @@ -185,8 +181,8 @@ run = -> nomsu\run [[ #!/usr/bin/env nomsu -V4 use "lib/consolecolor.nom" -action [quit, exit]: lua> "os.exit(0)" -action [help]: +[quit, exit] all mean: lua> "os.exit(0)" +(help) means: say "\ ..This is the Nomsu v\(Nomsu version) interactive console. You can type in Nomsu code here and hit 'enter' twice to run it. @@ -215,11 +211,12 @@ say "\ break -- Exit buff = table.concat(buff) + pseudo_filename = "user input #"..repl_line Files.spoof(pseudo_filename, buff) err_hand = (error_message)-> Errhand.print_error error_message - ok, ret = xpcall(nomsu.run, err_hand, nomsu, buff, Source(pseudo_filename, 1, #buff)) + ok, ret = xpcall nomsu.run, err_hand, nomsu, NomsuCode(Source(pseudo_filename,1,#buff), buff) if ok and ret != nil if type(ret) == 'number' print "= #{ret}" diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua index dff7eb7..8c2d90b 100644 --- a/nomsu_compiler.lua +++ b/nomsu_compiler.lua @@ -157,7 +157,7 @@ do return false end NomsuCompiler.environment = { - NOMSU_COMPILER_VERSION = 9, + NOMSU_COMPILER_VERSION = 10, NOMSU_SYNTAX_VERSION = max_parser_version, next = next, unpack = unpack, @@ -459,19 +459,10 @@ do return add_lua_bits(self, "value", code) end, ["use 1"] = function(self, tree, path) - local lua = LuaCode(tree.source) if path.type == 'Text' and #path == 1 and type(path[1]) == 'string' then - for _, f in Files.walk(path[1]) do - if match(f, "%.lua$") or match(f, "%.nom$") or match(f, "^/dev/fd/[012]$") then - self:import(self:run_file(f)) - if #lua.bits > 0 then - lua:append("\n") - end - lua:append("nomsu:import(nomsu:run_file(" .. tostring(f:as_lua()) .. "))") - end - end + self:import_file(path[1]) end - return lua + return LuaCode(tree.source, "nomsu:import_file(" .. tostring(self:compile(path)) .. ")") end, ["tests"] = function(self, tree) return LuaCode.Value(tree.source, "TESTS") @@ -533,6 +524,13 @@ do end end end + NomsuCompiler.import_file = function(self, path) + for _, f in Files.walk(path) do + if match(f, "%.lua$") or match(f, "%.nom$") or match(f, "^/dev/fd/[012]$") then + self:import(self:run_file(f)) + end + end + end NomsuCompiler.run = function(self, to_run, compile_actions) local source = to_run.source or Source(to_run, 1, #to_run) if type(source) == 'string' then diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon index 4746e10..304f6b9 100644 --- a/nomsu_compiler.moon +++ b/nomsu_compiler.moon @@ -97,7 +97,7 @@ with NomsuCompiler -- Discretionary/convenience stuff .environment = { - NOMSU_COMPILER_VERSION: 9, NOMSU_SYNTAX_VERSION: max_parser_version + NOMSU_COMPILER_VERSION: 10, NOMSU_SYNTAX_VERSION: max_parser_version -- Lua stuff: :next, :unpack, :setmetatable, :coroutine, :rawequal, :getmetatable, :pcall, :error, :package, :os, :require, :tonumber, :tostring, :string, :xpcall, :module, @@ -264,14 +264,9 @@ with NomsuCompiler return add_lua_bits(@, "value", code) ["use 1"]: (tree, path)=> - lua = LuaCode(tree.source) if path.type == 'Text' and #path == 1 and type(path[1]) == 'string' - for _,f in Files.walk(path[1]) - if match(f, "%.lua$") or match(f, "%.nom$") or match(f, "^/dev/fd/[012]$") - @import(@run_file(f)) - if #lua.bits > 0 then lua\append "\n" - lua\append "nomsu:import(nomsu:run_file(#{f\as_lua!}))" - return lua + @import_file(path[1]) + return LuaCode(tree.source, "nomsu:import_file(#{@compile(path)})") ["tests"]: (tree)=> LuaCode.Value(tree.source, "TESTS") ["test 1"]: (tree, body)=> @@ -299,6 +294,11 @@ with NomsuCompiler continue if k == "__imported" or k == "__parent" @environment.COMPILE_ACTIONS.__imported[k] or= v + .import_file = (path)=> + for _,f in Files.walk(path) + if match(f, "%.lua$") or match(f, "%.nom$") or match(f, "^/dev/fd/[012]$") + @import(@run_file(f)) + .run = (to_run, compile_actions)=> source = to_run.source or Source(to_run, 1, #to_run) if type(source) == 'string' then source = Source\from_string(source) -- cgit v1.2.3 From f43d8c58f755a7f208d84b43071490ab356c5ac8 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Wed, 31 Oct 2018 03:54:16 -0700 Subject: Added upgrade file. --- compatibility/4.8.10.nom | 59 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 compatibility/4.8.10.nom diff --git a/compatibility/4.8.10.nom b/compatibility/4.8.10.nom new file mode 100644 index 0000000..58fd376 --- /dev/null +++ b/compatibility/4.8.10.nom @@ -0,0 +1,59 @@ +#!/usr/bin/env nomsu -V4.8.10.6 +# + This file defines upgrades from Nomsu <4.8.10 to 4.8.10 (renaming "action" -> "means") +use "compatibility/compatibility.nom" + +upgrade action "local action 1 2" to "4.8.10" via (..) + [%tree, %end_version] ->: + %spec = %tree.3 + %body = %tree.4 + if %spec.type is: + "List": + if ((size of %spec) == 1): + return \(%spec.1 means %body) + ..else: + return \(%spec all mean %body) + else: + return \(%spec means %body) + +upgrade action "action 1 2" to "4.8.10" via (..) + [%tree, %end_version] ->: + %spec = %tree.2 + %body = %tree.3 + if %spec.type is: + "List": + if ((size of %spec) == 1): + return \(externally %spec.1 means %body) + ..else: + return \(externally %spec all mean %body) + else: + return \(externally %spec means %body) + +upgrade action "compile 1 to 2" to "4.8.10" via (..) + [%tree, %end_version] ->: + %spec = %tree.2 + %body = %tree.4 + if %spec.type is: + "List": + if ((size of %spec) == 1): + return \(%spec.1 compiles to %body) + ..else: + return \(%spec all compile to %body) + else: + return \(%spec compiles to %body) + +upgrade action "parse 1 as 2" to "4.8.10" via (..) + [%tree, %end_version] ->: + %spec = %tree.2 + %body = %tree.4 + if %spec.type is: + "List": + if ((size of %spec) == 1): + return \(%spec.1 parses as %body) + ..else: + return \(%spec all parse as %body) + else: + return \(%spec parse as %body) + +upgrade action (compile as %) to "4.8.10" as (what % compiles to) + -- cgit v1.2.3 From 7a35e38d8778670fe0662f203e82638355db3bba Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Wed, 31 Oct 2018 15:05:17 -0700 Subject: Renamed (action %) -> (%'s meaning) --- compatibility/2.3.nom | 2 +- compatibility/2.4.nom | 2 +- compatibility/2.5.5.5.nom | 2 +- compatibility/2.5.nom | 2 +- compatibility/2.nom | 2 +- compatibility/3.5.5.6.nom | 2 +- compatibility/3.6.nom | 2 +- compatibility/3.7.nom | 2 +- compatibility/3.8.nom | 2 +- compatibility/3.nom | 2 +- compatibility/4.8.10.nom | 2 +- compatibility/compatibility.nom | 13 ++- core/control_flow.nom | 2 +- core/metaprogramming.nom | 6 +- core/scopes.nom | 2 +- examples/how_do_i.nom | 2 +- nomnom/ast.nom | 53 +++++------- nomnom/code_obj.nom | 132 ++++++++++++++-------------- nomnom/compile.nom | 124 ++++++++++++++------------ nomnom/decompile.nom | 187 +++++++++++++++++++++------------------- nomnom/files.nom | 78 +++++++---------- nomnom/parser.nom | 49 ++++++----- nomnom/pretty_errors.nom | 50 +++++------ nomnom/source.nom | 29 ++++--- tools/autoformat.nom | 4 +- tools/find_action.nom | 8 +- tools/parse.nom | 6 +- tools/replace.nom | 4 +- tools/test.nom | 5 +- tools/upgrade.nom | 14 ++- 30 files changed, 411 insertions(+), 379 deletions(-) diff --git a/compatibility/2.3.nom b/compatibility/2.3.nom index fb137b8..7de353e 100644 --- a/compatibility/2.3.nom +++ b/compatibility/2.3.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file defines upgrades from Nomsu <2.3 to Nomsu 2.3 diff --git a/compatibility/2.4.nom b/compatibility/2.4.nom index b770840..1a7c9c3 100644 --- a/compatibility/2.4.nom +++ b/compatibility/2.4.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file defines upgrades from Nomsu <2.4 to Nomsu 2.4 diff --git a/compatibility/2.5.5.5.nom b/compatibility/2.5.5.5.nom index a3f8b27..efed78d 100644 --- a/compatibility/2.5.5.5.nom +++ b/compatibility/2.5.5.5.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file defines upgrades from Nomsu <2.5.5.5 to Nomsu 2.5.5.5 diff --git a/compatibility/2.5.nom b/compatibility/2.5.nom index fe17dfb..b1e01b0 100644 --- a/compatibility/2.5.nom +++ b/compatibility/2.5.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file defines upgrades from Nomsu <2.5 to Nomsu 2.5 diff --git a/compatibility/2.nom b/compatibility/2.nom index 2364f56..d7a1489 100644 --- a/compatibility/2.nom +++ b/compatibility/2.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file defines upgrades from Nomsu 1 to Nomsu 2 diff --git a/compatibility/3.5.5.6.nom b/compatibility/3.5.5.6.nom index 068e65d..89fbc8a 100644 --- a/compatibility/3.5.5.6.nom +++ b/compatibility/3.5.5.6.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file defines upgrades from Nomsu <3.5.5.6 to Nomsu 3.5.5.6 diff --git a/compatibility/3.6.nom b/compatibility/3.6.nom index eec97eb..7cd5c64 100644 --- a/compatibility/3.6.nom +++ b/compatibility/3.6.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file defines upgrades from Nomsu <3.6 to 3.6 diff --git a/compatibility/3.7.nom b/compatibility/3.7.nom index 5b458de..599e0d5 100644 --- a/compatibility/3.7.nom +++ b/compatibility/3.7.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file defines upgrades from Nomsu <3.7 to 3.7 diff --git a/compatibility/3.8.nom b/compatibility/3.8.nom index 9538770..0709688 100644 --- a/compatibility/3.8.nom +++ b/compatibility/3.8.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file defines upgrades from Nomsu <3.8 to 3.8 (Text method changes) diff --git a/compatibility/3.nom b/compatibility/3.nom index 36df17d..5156aa8 100644 --- a/compatibility/3.nom +++ b/compatibility/3.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file defines upgrades from Nomsu <=2 to Nomsu 3 diff --git a/compatibility/4.8.10.nom b/compatibility/4.8.10.nom index 58fd376..d20448e 100644 --- a/compatibility/4.8.10.nom +++ b/compatibility/4.8.10.nom @@ -56,4 +56,4 @@ upgrade action "parse 1 as 2" to "4.8.10" via (..) return \(%spec parse as %body) upgrade action (compile as %) to "4.8.10" as (what % compiles to) - +upgrade action (action %) to "4.8.10" as (%'s meaning) diff --git a/compatibility/compatibility.nom b/compatibility/compatibility.nom index 6da7063..c61b5a9 100644 --- a/compatibility/compatibility.nom +++ b/compatibility/compatibility.nom @@ -80,16 +80,15 @@ externally [..] %tree with % -> (..) if ((% is "Action" syntax tree) and %ACTION_UPGRADES.%ver.(%.stub)): %with_upgraded_args = (..) - %k = (%v upgraded from %start_version to %end_version) \ - ..for %k = %v in % - set %with_upgraded_args's metatable to (%'s metatable) - return (call %ACTION_UPGRADES.%ver.(%.stub) with [%with_upgraded_args, %end_version]) + %k = (%v upgraded from %start_version to %end_version) for %k = %v in % + set %with_upgraded_args 's metatable to (% 's metatable) + return (..) + call %ACTION_UPGRADES.%ver.(%.stub) with [%with_upgraded_args, %end_version] if %UPGRADES.%ver: %with_upgraded_args = (..) - %k = (%v upgraded from %start_version to %end_version) \ - ..for %k = %v in %tree - set %with_upgraded_args's metatable to (%tree's metatable) + %k = (%v upgraded from %start_version to %end_version) for %k = %v in %tree + set %with_upgraded_args 's metatable to (%tree 's metatable) %tree = (call %UPGRADES.%ver with [%with_upgraded_args, %end_version]) return %tree diff --git a/core/control_flow.nom b/core/control_flow.nom index 2b53ce7..0cabf95 100644 --- a/core/control_flow.nom +++ b/core/control_flow.nom @@ -406,7 +406,7 @@ test: ..hint "If you want the code in this block to always execute, you don't \ ..need a conditional block around it. Otherwise, make sure the 'else' \ ..block comes last." - + %code::append "\nelse\n " %code::append (%action as lua statements) %else_allowed = (no) diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom index a2f15a1..c999191 100644 --- a/core/metaprogramming.nom +++ b/core/metaprogramming.nom @@ -102,7 +102,7 @@ lua> "\ test: (foo %x) means (return "outer") - with local [action (foo %)]: + with local [(foo %)'s meaning]: (foo %x) means: %y = (%x + 1) return %y @@ -151,8 +151,8 @@ test: return lua" test: - assume ((action (say %)) == (=lua "say_1")) -(action %action) compiles to (Lua value (%action.stub as lua id)) + assume (((say %)'s meaning) == (=lua "say_1")) +(%action's meaning) compiles to (Lua value (%action.stub as lua id)) test: (swap %x and %y) parses as (..) diff --git a/core/scopes.nom b/core/scopes.nom index 715409c..2d86ca4 100644 --- a/core/scopes.nom +++ b/core/scopes.nom @@ -15,7 +15,7 @@ test: assume (%x == "outer") externally (foo) means "outer foo" - with local [action (foo)]: + with local [(foo)'s meaning]: externally (foo) means "inner foo" assume ((foo) == "inner foo") diff --git a/examples/how_do_i.nom b/examples/how_do_i.nom index e8e838b..ec75596 100644 --- a/examples/how_do_i.nom +++ b/examples/how_do_i.nom @@ -247,7 +247,7 @@ say both (my favorite number) and also "foo" # Macros: # The "lua> %" and "=lua %" macros can be used to write raw lua code: -(say the time) means (..) +(say the time) means: lua> "io.write(\"The OS time is: \", os.time(), \"\\n\");" say the time diff --git a/nomnom/ast.nom b/nomnom/ast.nom index 816554c..4d261aa 100644 --- a/nomnom/ast.nom +++ b/nomnom/ast.nom @@ -1,9 +1,9 @@ +#!/usr/bin/env nomsu -V4.8.10 use "lib/object.nom" # The types are [..] "Number", "Var", "Block", "EscapedNomsu", "Text", "List", "Dict", "DictEntry", "IndexChain", "Action", "FileChunks", "Error", "Comment" - object (Syntax Tree): my action [set up]: if (%me.type == "Action"): @@ -11,38 +11,33 @@ object (Syntax Tree): %argnum = 1 for %bit in %me: if: - (%bit is text): %stub_bits::add %bit + (%bit is text): + %stub_bits::add %bit (%bit.type != "Comment"): %stub_bits::add "\%argnum" %argnum += 1 + %me.stub = (%stub_bits::joined with " ") if (%me.stub == "Lua Code 1 2"): lua> "require('ldt').breakpoint()" - + (Syntax Tree).source_code_for_tree = (..) {} with fallback % -> (read file %.source.filename) - my action [children]: %children = [] for % in %me: - if ((% is a "Syntax Tree") and (%.type != "Comment")): - %children::add % + if ((% is a "Syntax Tree") and (%.type != "Comment")): %children::add % if ((%me.type == "Action") and %me.target): %children::add %me.target return %children - - my action [as lua] (..) - "Syntax_Tree(\(call ({}'s metatable).as_lua with [%me]))" - - my action [as nomsu] (..) - "(Syntax Tree \(call ({}'s metatable).as_nomsu with [%me]))" - - my action [as text] (..) - "(Syntax Tree \(call ({}'s metatable).__tostring with [%me]))" - - my action [get source code] (..) - (Syntax Tree).source_code_for_tree.%me - + + my action [as lua] "\ + ..a_Syntax_Tree_with_1(\(call ({} 's metatable).as_lua with [%me]))" + my action [as nomsu] "\ + ..(a Syntax Tree with \(call ({} 's metatable).as_nomsu with [%me]))" + my action [as text] "\ + ..(Syntax Tree \(call ({} 's metatable).__tostring with [%me]))" + my action [get source code] (Syntax Tree).source_code_for_tree.%me my action [map %fn]: %replacement = (call %fn with [%me]) if %replacement: @@ -58,25 +53,23 @@ object (Syntax Tree): %replacement.%k = %v if (%v is a "Syntax Tree"): %r = (%v::map %fn) - if ((%r == %v) or (%r == (nil))): - do next %k + if ((%r == %v) or (%r == (nil))): do next %k %changes = (yes) %replacement.%k = %r + unless %changes: return %me return (Syntax Tree %replacement) - + my action [with %overrides]: %new = (%k = %v for %k = %v in %me) for %k = %v in %overrides: %new.%k = %v return (Syntax Tree %new) - + my action [== %other]: unless (..) all of [..] - (type of %me) == (type of %other) - (%me's metatable) == (%other's metatable) - (size of %me) == (size of %other) - %me.type == %other.type + (type of %me) == (type of %other), (%me 's metatable) == (%other 's metatable) + (size of %me) == (size of %other), %me.type == %other.type ..: return (no) for %item in %me at %i: @@ -86,11 +79,11 @@ object (Syntax Tree): return (yes) my action [get args]: - assume (%me.type == "Action") or barf "Only actions have arguments, not \(%me.type)" + assume (%me.type == "Action") or barf "\ + ..Only actions have arguments, not \(%me.type)" %args = [] for % in %me: - unless ((% is text) or (%.type == "Comment")): - %args::add % + unless ((% is text) or (%.type == "Comment")): %args::add % return %args (Syntax Tree).map = (Syntax Tree).map_1 diff --git a/nomnom/code_obj.nom b/nomnom/code_obj.nom index 363713c..8379f36 100644 --- a/nomnom/code_obj.nom +++ b/nomnom/code_obj.nom @@ -1,25 +1,19 @@ +#!/usr/bin/env nomsu -V4.8.10 # This file contains objects that are used to track code positions and incrementally build up generated code, while keeping track of where it came from, and managing indentation levels. - use "lib/object.nom" object (Hole): - action [Hole from %lua]: + externally (Hole from %lua) means: return (Hole {lua:%lua}) - - my action [as lua]: - return %me.lua - + my action [as lua]: return %me.lua my action [as nomsu]: return "(Hole {lua:\(%me.lua)})" - my action [as text]: barf "Not implemented" - my action [as smext]: barf "Must fill in holes before smexting" - object (Code): my action [set up]: @@ -28,12 +22,10 @@ object (Code): %me.bits = [] if (%me.source is text): %me.source = (Source from text %me.source) - for % in %old_bits: - %me::add % - + for % in %old_bits: %me::add % + my action [as text]: barf "Not implemented" - my action [as smext]: if (%me.__str == (nil)): set {%buff:[], %indent:0} @@ -45,32 +37,41 @@ object (Code): %bit = (%bit::as smext) if (%indent > 0): %bit = (%bit::with "\n" -> "\n\(" "::* %indent)") + %buff::add %bit + %me.__str = (%buff::joined) + return %me.__str - + my action [as lua]: barf - return "\(%me.class.name::as lua id)_from_1_2(\((%me.source::as lua) if %me.source else "nil"), \(%me.bits::as lua))" - - my action [as nomsu] (..) - "(\(%me.class.name) \((%me.source::as nomsu) if %me.source else "(nil)") \(%me.bits::as nomsu))" - - my action [size] (size of (%me::as smext)) + return "\ + ..\(%me.class.name::as lua id)_from_1_2(\(..) + (%me.source::as lua) if %me.source else "nil" + .., \(%me.bits::as lua))" + + my action [as nomsu] "\ + ..(\(%me.class.name) \((%me.source::as nomsu) if %me.source else "(nil)") \(..) + %me.bits::as nomsu + ..)" + my action [size] (size of (%me::as smext)) my action [mark as dirty]: %me.__str = (nil) %me._trailing_line_len = (nil) %me._num_lines = (nil) - + my action [add %new_bits]: unless (%new_bits is a "List"): %new_bits = [%new_bits] for % in %new_bits: if (% == ""): do next % + #if ((% isn't text) and (% isn't a (Code))): % = (%::as lua) %me.bits::add % + %me::mark as dirty my action [trailing line length]: @@ -86,15 +87,15 @@ object (Code): %num_lines += (size of (%::all matches of "\n")) ..else: %num_lines += ((%::number of lines) - 1) + %me._num_lines = %num_lines + return %me._num_lines - + my action [is multiline, is multi-line] ((%me::number of lines) > 1) my action [is one line, is single line] ((%me::number of lines) == 1) - my action [add %values joined with %joiner]: %me::add %values joined with %joiner or %joiner - my action [add %values joined with %joiner or %wrapping_joiner]: %line_len = 0 %bits = %me.bits @@ -103,8 +104,8 @@ object (Code): if (%line_len > 80): %bits::add %wrapping_joiner %line_len = 0 - ..else: - %bits::add %joiner + ..else: %bits::add %joiner + %bits::add %value unless (%value is text): %value = (%value::as smext) @@ -113,6 +114,7 @@ object (Code): %line_len = (size of %line) ..else: %line_len += (size of %value) + %me::mark as dirty my action [prepend %]: @@ -120,13 +122,12 @@ object (Code): % = (%::as lua) %me.bits::add % at index 1 %me::mark as dirty - + my action [parenthesize]: %me.bits::add "(" at index 1 %me.bits::add ")" %me::mark as dirty - object (Lua Code) extends (Code): my action [add free vars %vars]: if ((size of %vars) == 0): return @@ -136,6 +137,7 @@ object (Lua Code) extends (Code): unless %seen.%var: %me.free_vars::add %var %seen.%var = (yes) + %me::mark as dirty my action [remove free vars %vars]: @@ -153,11 +155,13 @@ object (Lua Code) extends (Code): lua> "table.remove(\%lua.free_vars, \%i)" #TODO: reinstate this #%lua.free_vars::remove at index %i + + for % in %lua.bits: - unless (% is text): - %stack::add % + unless (% is text): %stack::add % + %me::mark as dirty - + my action [declare locals] (%me::declare locals (nil)) my action [declare locals %to_declare]: unless %to_declare: @@ -167,19 +171,19 @@ object (Lua Code) extends (Code): unless %seen.%var: %seen.%var = (yes) %to_declare::add %var + for % in %lua.bits: - unless (% is text): - recurse %lua on % + unless (% is text): recurse %lua on % + if ((size of %to_declare) > 0): %me::remove free vars %to_declare %me::prepend "local \(%to_declare::joined with ", ");\n" return %to_declare - + my action [as statements] (%me::as statements "" ";") my action [as statements %prefix] (%me::as statements %prefix ";") my action [as statements %prefix %suffix]: - unless %me.is_value: - return %me + unless %me.is_value: return %me %statements = (Lua Code from %me.source []) if ((%prefix or "") != ""): %statements::add %prefix @@ -194,46 +198,48 @@ object (Lua Code) extends (Code): if %code.is_variable: %vars::add (%code::as smext) for % in %code.bits: - unless (% is text): - recurse %code on % + unless (% is text): recurse %code on % + return %vars - - action [Lua Code from %source %bits]: + + externally (Lua Code from %source %bits) means: assume %source unless (%bits is a "List"): %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 Code from %source] (Lua Code from %source []) - - action [Lua Value from %source %bits]: + if (%source is a "Syntax Tree"): + %source = %source.source + return (Lua Code {source:%source, bits:%bits, is_value:no, free_vars:[]}) + + externally (Lua Code from %source) means (Lua Code from %source []) + externally (Lua Value from %source %bits) means: assume %source unless (%bits is a "List"): %bits = [%bits] - if (%source is a "Syntax Tree"): %source = %source.source - return (..) - Lua Code {source:%source, bits:%bits, is_value: yes, free_vars:[]} - action [Lua Value from %source] (Lua Value from %source []) - - action [Lua Variable from %source] (Lua Variable from %source []) - action [Lua Variable from %source %bits]: + if (%source is a "Syntax Tree"): + %source = %source.source + return (Lua Code {source:%source, bits:%bits, is_value:yes, free_vars:[]}) + + externally (Lua Value from %source) means (Lua Value from %source []) + externally (Lua Variable from %source) means (Lua Variable from %source []) + externally (Lua Variable from %source %bits) means: assume %source unless (%bits is a "List"): %bits = [%bits] - if (%source is a "Syntax Tree"): %source = %source.source + if (%source is a "Syntax Tree"): + %source = %source.source return (..) - Lua Code {source:%source, bits:%bits, is_value: yes, is_variable: yes, free_vars:[]} + Lua Code {..} + source:%source, bits:%bits, is_value:yes, is_variable:yes, free_vars:[] # TODO: remove this shim (Lua Code).add_free_vars = (Lua Code).add_free_vars_1 (Lua Code).remove_free_vars = (Lua Code).remove_free_vars_1 (Lua Code).declare_locals = (Lua Code).declare_locals_1 (Lua Code).as_statements = (Lua Code).as_statements_1_2 - object (Nomsu Code) extends (Code): - action [Nomsu Code from %source %bits]: + externally (Nomsu Code from %source %bits) means: if (%bits is text): %bits = [%bits] - if (%source is a "Syntax Tree"): %source = %source.source - return (..) - Nomsu Code {source:%source, bits:%bits} - action [Nomsu Code from %source] (Nomsu Code from %source []) - action [Nomsu Code %bits] (Nomsu Code from (nil) %bits) - action [Nomsu Code] (Nomsu Code from (nil) []) + if (%source is a "Syntax Tree"): + %source = %source.source + return (Nomsu Code {source:%source, bits:%bits}) + + externally (Nomsu Code from %source) means (Nomsu Code from %source []) + externally (Nomsu Code %bits) means (Nomsu Code from (nil) %bits) + externally (Nomsu Code) means (Nomsu Code from (nil) []) diff --git a/nomnom/compile.nom b/nomnom/compile.nom index 989bc04..18afe3c 100644 --- a/nomnom/compile.nom +++ b/nomnom/compile.nom @@ -1,24 +1,23 @@ +#!/usr/bin/env nomsu -V4.8.10 # This file contains the code to convert syntax trees to Lua code - use "nomnom/code_obj.nom" use "nomnom/parser.nom" use "nomnom/pretty_errors.nom" -local action [report compile error at %tree %err]: +externally (report compile error at %tree %err) means: barf (pretty "Compile Error" error at %tree %err) -local action [report compile error at %pos %err hint %hint]: +externally (report compile error at %pos %err hint %hint) means: barf (pretty "Compile Error" error at %tree %err hint %hint) -action [barf any errors in %t]: +externally (barf any errors in %t) means: assume (%t is a "Syntax Tree") %errs = [] for % in recursive %t: - if (%.type == "Error"): - %errs::add % + if (%.type == "Error"): %errs::add % for %k = %v in %: - if (%v is a "Syntax Tree"): - recurse % on %v + if (%v is a "Syntax Tree"): recurse % on %v + sort %errs by % -> %.source %errs = ((% as a pretty error) for % in %errs) if ((size of %errs) > 0): @@ -28,17 +27,19 @@ action [barf any errors in %t]: %errs::add "\027[31;1m +\%n additional errors...\027[0m\n" barf (%errs::joined with "\n\n") -action [%tree compiled with %compile_actions]: +externally (%tree compiled with %compile_actions) means: 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) - ..then: %tree = (upgrade %tree from %tree.version to (Nomsu version)) + %tree.version, (Nomsu version)'s meaning, %tree.version != (Nomsu version) + (1 upgraded from 2 to 3)'s meaning + ..then: + %tree = (upgrade %tree from %tree.version to (Nomsu version)) + if %tree.type is: "Action": %stub = %tree.stub %compile_action = %compile_actions.%stub + # Don't apply compiler actions to methods if (%compile_action and (not %tree.target)): # TODO: restore this: @@ -51,26 +52,35 @@ action [%tree compiled with %compile_actions]: ..The compile-time action here (\(%tree.stub)) failed to return any value." ..hint "\ ..Look at the implementation of (\(%tree.stub)) and make sure it's returning something." + if (%result is a "Syntax Tree"): if (%result == %tree): report compile error at %tree "\ ..The compile-time action here (\(%tree.stub)) is producing an endless loop." ..hint "\ ..Look at the implementation of (\(%tree.stub)) and make sure it's not just returning the original tree." + return (%result compiled with %compile_actions) + return %result - + %lua = (Lua Value from %tree) - if %tree.target: # Method call + if %tree.target: + # Method call %target_lua = (%tree.target compiled with %compile_actions) - if (((%target_lua::as smext)::matches "^%(.*%)$") or ((%target_lua::as smext)::matches "^[_a-zA-Z][_a-zA-Z0-9]*$")): + if (..) + ((%target_lua::as smext)::matches "^%(.*%)$") or (..) + (%target_lua::as smext)::matches "^[_a-zA-Z][_a-zA-Z0-9]*$" + ..: %lua::add [%target_lua, ":"] ..else: %lua::add ["(", %target_lua, "):"] + %lua::add [%stub as lua id, "("] %args = [] for %tok in %tree at %i: if (%tok is text): do next %tok + # TODO: maybe don't translate Lua comments #if (%tok.type == "Comment"): do next %tok if (%tok.type == "Block"): @@ -78,6 +88,7 @@ action [%tree compiled with %compile_actions]: for %line in %tok: #unless (%line.type == "Comment"): %values::add (%line compiled with %compile_actions) + if all of (%.is_value for % in %values): if ((size of %values) == 1): %arg_lua = %values.1 @@ -91,65 +102,63 @@ action [%tree compiled with %compile_actions]: if %v.is_value: %v = (%v::as statements ("return " if (%i == (size of %values) else ""))) %arg_lua::add ["\n ", %v] + %arg_lua::add "\nend)())" ..else: %arg_lua = (%tok compiled with %compile_actions) unless %arg_lua.is_value: if (%tok.type == "Action"): report compile error at %tok "\ - ..Can't use this as an argument to (\%stub), since it's not \ - ..an expression, it produces: \%arg_lua" + ..Can't use this as an argument to (\%stub), since it's not an expression, it produces: \%arg_lua" ..hint "\ - ..Check the implementation of (\(%tok.stub)) to see if it \ - ..is actually meant to produce an expression." + ..Check the implementation of (\(%tok.stub)) to see if it is actually meant to produce an expression." ..else: report compile error at %tok "\ - ..Can't use this as an argument to (\%stub), since it's \ - ..not an expression, it produces: \%arg_lua" + ..Can't use this as an argument to (\%stub), since it's not an expression, it produces: \%arg_lua" + assume (%arg_lua != %lua) or barf "Huh? \%tree .\%i = \%tok -> \%arg_lua" %args::add %arg_lua + %lua::add %args joined with ", " %lua::add ")" return %lua - + "EscapedNomsu": #return (Lua Value from %tree ((%tree.1)::as lua)) - - %lua = (Lua Value from %tree ["Syntax_Tree_1{type=", quote %tree.1.type]) + %lua = (Lua Value from %tree ["a_Syntax_Tree_with_1{type=", quote %tree.(1).type]) set {%needs_comma:no, %i:1} - local action [% as shmua]: - if (% is a "Lua number"): - return "\%" + (% as shmua) means: + if (% is a "Lua number"): return "\%" if (% is a "Syntax Tree"): return (% compiled with %compile_actions) - if (% is text): - return (quote %) + if (% is text): return (quote %) return (%::as lua) - - for %k = %v in (((%tree.1.type == "EscapedNomsu") and %tree) or %tree.1): + + for %k = %v in (((%tree.(1).type == "EscapedNomsu") and %tree) or %tree.1): %lua::add ", " if: - (%k == %i): - %i += 1 + (%k == %i): %i += 1 ((%k is text) and (%k::is a lua identifier)): %lua::add [%k, "= "] else: %lua::add ["[", % as shmua, "]= "] + if (%k == "source"): %lua::add (quote "\%v") ..else: %lua::add (%v as shmua) + %lua::add "}" return %lua "Block": %lua = (Lua Code from %tree) %lua::add (..) - ((%line compiled with %compile_actions)::as statements) - ..for %line in %tree + ((%line compiled with %compile_actions)::as statements) for %line in %tree ..joined with "\n" + return %lua - + "Text": %lua = (Lua Value from %tree) %lua_bits = [] @@ -158,49 +167,53 @@ action [%tree compiled with %compile_actions]: if (% is text): %string_buffer = "\%string_buffer\%" do next % + if (%string_buffer != ""): %lua_bits::add (%string_buffer::as lua) %string_buffer = "" + %bit_lua = (% compiled with %compile_actions) unless %bit_lua.is_value: report compile error at % "\ ..Can't use this as a string interpolation value, since it doesn't have a value." + if (%.type != "Text"): - %bit_lua = (Lua Value from % ["tostring(",%bit_lua,")"]) + %bit_lua = (Lua Value from % ["tostring(", %bit_lua, ")"]) %lua_bits::add %bit_lua - + if ((%string_buffer != "") or ((size of %lua_bits) == 0)): %lua_bits::add (%string_buffer::as lua) - - %lua::add %lua_bits joined with ("..") - if ((size of %lua_bits) > 1): - %lua::parenthesize + %lua::add %lua_bits joined with ".." + if ((size of %lua_bits) > 1): %lua::parenthesize return %lua - + "List": %lua = (Lua Value from %tree ["List{"]) %lua::add ((% compiled with %compile_actions) for % in %tree) joined with ", " or ",\n " %lua::add "}" return %lua - + "Dict": %lua = (Lua Value from %tree ["Dict{"]) %lua::add ((% compiled with %compile_actions) for % in %tree) joined with ", " or ",\n " %lua::add "}" return %lua - + "DictEntry": set {%key:%tree.1, %value:%tree.2} %key_lua = (%key compiled with %compile_actions) unless %key_lua.is_value: report compile error at %tree.1 "\ ..Can't use this as a dict key, since it's not an expression." + %value_lua = (..) - (%value compiled with %compile_actions) if %value - ..else (Lua Value from %key ["true"]) + (%value compiled with %compile_actions) if %value else (..) + Lua Value from %key ["true"] + unless %value_lua.is_value: report compile error at %tree.2 "\ ..Can't use this as a dict value, since it's not an expression." + %key_str = ((%key_lua::as smext)::matching "^[\"']([a-zA-Z_][a-zA-Z0-9_]*)['\"]$") if: %key_str: @@ -210,6 +223,7 @@ action [%tree compiled with %compile_actions]: Lua's parser if the inner expression is a long string. Lua parses x[[[y]]] as x("[y]"), not as x["y"] return (Lua Code from %tree ["[ ", %key_lua, "]=", %value_lua]) + else: return (Lua Code from %tree ["[", %key_lua, "]=", %value_lua]) @@ -218,16 +232,17 @@ action [%tree compiled with %compile_actions]: unless %lua.is_value: report compile error at %tree.1 "\ ..Can't index into this, since it's not an expression." + %first_char = (%lua::as smext).1 if (any of [%first_char == "{", %first_char == "\"", %first_char == "["]): %lua::parenthesize - for %i in 2 to (size of %tree): %key = %tree.%i %key_lua = (%key compiled with %compile_actions) unless %key_lua.is_value: report compile error at %key "\ ..Can't use this as an index, since it's not an expression." + %key_lua_str = (%key_lua::as smext) %lua_id = (%key_lua_str::matching "^['\"]([a-zA-Z_][a-zA-Z0-9_]*)['\"]$") if: @@ -238,20 +253,19 @@ action [%tree compiled with %compile_actions]: Lua's parser if the inner expression is a long string. Lua parses x[[[y]]] as x("[y]"), not as x["y"] %lua::add ["[ ", %key_lua, " ]"] + else: %lua::add ["[", %key_lua, "]"] + return %lua - + "Number": return (Lua Value from %tree ["\(%tree.1)"]) - "Var": return (Lua Variable from %tree [%tree.1::as lua id]) - "FileChunks": barf "\ - ..Can't convert FileChunks to a single block of lua, since each chunk's \ - ..compilation depends on the earlier chunks" + ..Can't convert FileChunks to a single block of lua, since each chunk's compilation depends on the earlier chunks" "Comment": # TODO: de-implement? @@ -259,7 +273,5 @@ action [%tree compiled with %compile_actions]: "Error": barf (%tree as a pretty error) - else: barf "Unknown type: \(%tree.type)" - diff --git a/nomnom/decompile.nom b/nomnom/decompile.nom index fb64f7c..7db61c8 100644 --- a/nomnom/decompile.nom +++ b/nomnom/decompile.nom @@ -1,9 +1,10 @@ +#!/usr/bin/env nomsu -V4.8.10 # This file contains the code to convert syntax trees to Nomsu code use "nomnom/code_obj.nom" use "nomnom/parser.nom" # TODO: maybe re-implement the fancy coroutine checker that aborts early if nomsu gets too long -action [%tree decompiled inline]: +externally (%tree decompiled inline) means: assume (%tree is a "Syntax Tree") if %tree.type is: "Action": @@ -11,18 +12,18 @@ action [%tree decompiled inline]: if %tree.target: %target_nomsu = (%tree.target decompiled inline) if %tree.target.type is: - ("Action", "Block"): + "Action" "Block": %target_nomsu::parenthesize + %nomsu::add [%target_nomsu, "::"] - + for %bit in %tree at %i: if (%bit is text): unless (..) any of [..] - %i == 1, - %tree.(%i - 1) isn't text, - (%bit is a nomsu operator) == (%tree.(%i - 1) is a nomsu operator) + %i == 1, %tree.(%i - 1) isn't text, (%bit is a nomsu operator) == (%tree.(%i - 1) is a nomsu operator) ..: %nomsu::add " " + %nomsu::add %bit ..else: %arg_nomsu = (%bit decompiled inline) @@ -30,39 +31,40 @@ action [%tree decompiled inline]: %nomsu::add " " if ((%bit.type == "Action") or (%bit.type == "Block")): %arg_nomsu::parenthesize + %nomsu::add %arg_nomsu + return %nomsu - + "EscapedNomsu": %inner_nomsu = (%tree.1 decompiled inline) unless (..) any of [..] - %tree.1.type == "List", %tree.1.type == "Dict", - %tree.1.type == "Var" - ..: %inner_nomsu::parenthesize + %tree.(1).type == "List", %tree.(1).type == "Dict", %tree.(1).type == "Var" + ..: + %inner_nomsu::parenthesize + %nomsu = (Nomsu Code from %tree ["\\", %inner_nomsu]) return %nomsu - + "Block": %nomsu = (Nomsu Code from %tree [":"]) for %line in %tree at %i: - %nomsu::add [..] - " " if (%i == 1) else "; " - %line decompiled inline + %nomsu::add [" " if (%i == 1) else "; ", %line decompiled inline] return %nomsu - + "Text": %nomsu = (Nomsu Code from %tree []) for %text in recursive %tree: for %bit in %text at %i: - if (%bit is text): - %nomsu::add %bit + if (%bit is text): %nomsu::add %bit ..else: if %bit.type is: "Text": recurse %text on %bit "Var": %interp_nomsu = (%bit decompiled inline) + # Make sure "...\(%x)y..." isn't confused with "...\(%xy)..." # TODO: make this more robust against "...\%x\("y").." if (..) @@ -70,32 +72,38 @@ action [%tree decompiled inline]: not (%tree.(%i + 1)::matches "^[ \n\t,.:;#(){}%[%]]") ..: %interp_nomsu::parenthesize %nomsu::add ["\\", %interp_nomsu] - ("List", "Dict"): + + "List" "Dict": %nomsu::add ["\\", %bit decompiled inline] else: %nomsu::add ["\\(", %bit decompiled inline, ")"] + return (Nomsu Code from %tree ["\"", %nomsu, "\""]) - - ("List", "Dict"): + + "List" "Dict": %nomsu = (Nomsu Code from %tree ["[" if (%tree.type == "List") else "{"]) for %item in %tree at %i: if (%i > 1): %nomsu::add ", " %nomsu::add (%item decompiled inline) + %nomsu::add ("]" if (%tree.type == "List") else "}") return %nomsu "DictEntry": set {%key:%tree.1, %value:%tree.2} - if (all of [%key.type == "Text", (size of %key) == 1, %key.1 is a nomsu identifier]): + if (..) + all of [%key.type == "Text", (size of %key) == 1, %key.1 is a nomsu identifier] + ..: %nomsu = (Nomsu Code from %key [%key.1]) ..else: %nomsu = (%key decompiled inline) - + if (%key.type == "Action"): %nomsu::parenthesize if %value: %nomsu::add ":" %nomsu::add (%value decompiled inline) + return %nomsu "IndexChain": @@ -104,46 +112,42 @@ action [%tree decompiled inline]: if (%i > 1): %nomsu::add "." if (..) all of [..] - %i > 1, %bit.type == "Text", (size of %bit) == 1, %bit.1 is text, - %bit.1 is a nomsu identifier - ..:%nomsu::add %bit.1 + %i > 1, %bit.type == "Text", (size of %bit) == 1, %bit.1 is text, %bit.1 is a nomsu identifier + ..: %nomsu::add %bit.1 ..else: %bit_nomsu = (%bit decompiled inline) if (..) any of [..] - %bit.type == "Action" - %bit.type == "Block" - %bit.type == "IndexChain" + %bit.type == "Action", %bit.type == "Block", %bit.type == "IndexChain" (%bit.type == "Number") and (%i < (size of %tree)) - ..: %bit_nomsu::parenthesize + ..: + %bit_nomsu::parenthesize + %nomsu::add %bit_nomsu + return %nomsu "Number": return (Nomsu Code from %tree [(%tree.1 as hex) if %tree.hex else "\(%tree.1)"]) - "Var": return (Nomsu Code from %tree ["%\(%tree.1)"]) - - "Comment": - return (nil) - + "Comment": return (nil) "FileChunks": barf "Can't inline a FileChunks" - "Error": barf "Can't compile errors" - else: barf "Unknown type: \(%tree.type)" %MAX_LINE = 90 -action [%tree decompiled]: +externally (%tree decompiled) means: %nomsu = (Nomsu Code from %tree) + # For concision: - local action [recurse on %t]: + (recurse on %t) means: %space = (%MAX_LINE - (%nomsu::trailing line length)) - if (%space <= 0): go to (Use Indented) + if (%space <= 0): + go to (Use Indented) for %subtree in recursive %tree: if %subtree.type is: "Block": @@ -151,45 +155,50 @@ action [%tree decompiled]: go to (Use Indented) if ((size of "\(%subtree decompiled inline)") > 20): go to (Use Indented) + for %k = %v in %subtree: if (%v is a "Syntax Tree"): recurse %subtree on %v - + %inline_nomsu = (%t decompiled inline) if (%inline_nomsu and ((size of "\%inline_nomsu") <= %space)): return %inline_nomsu - === (Use Indented) === %indented = (%t decompiled) if (%t.type == "Action"): - %indented = (Nomsu Code from %t ["(..)\n ", %indented]) + %indented = (..) + Nomsu Code from %t [..] + "(..)\n ", %indented + return %indented - + if %tree.type is: "FileChunks": - local action [%1 and %2 should clump]: + (%1 and %2 should clump) means: if ((%1.type == "Action") and (%2.type == "Action")): - if (%1.stub == "use 1"): return (%2.stub == "use 1") + if (%1.stub == "use 1"): + return (%2.stub == "use 1") if (%1.stub == "test 1"): return (yes) if (%2.stub == "test 1"): return (no) + return (not ((recurse on %1)::is multi-line)) + for %chunk in %tree at %chunk_no: if (%chunk_no > 1): %nomsu::add "\n\n\("~"::* 80)\n\n" if (%chunk.type == "Block"): for %line in %chunk at %line_no: if (%line_no > 1): - if (%chunk.(%line_no - 1) and %line should clump): - %nomsu::add "\n" - ..else: - %nomsu::add "\n\n" + if (%chunk.(%line_no - 1) and %line should clump): %nomsu::add "\n" + ..else: %nomsu::add "\n\n" + %nomsu::add (%line decompiled) ..else: %nomsu::add (%chunk decompiled) - unless ("\%nomsu"::matches "\n$"): - %nomsu::add "\n" + + unless ("\%nomsu"::matches "\n$"): %nomsu::add "\n" return %nomsu - + "Action": %pos = %tree.source.start %next_space = "" @@ -200,33 +209,32 @@ action [%tree decompiled]: %nomsu::add %target_nomsu %pos = %tree.target.source.stop %next_space = ("\n..::" if (%target_nomsu::is multi-line) else "::") - + for %bit in %tree at %i: if ((%next_space == " ") and ((%nomsu::trailing line length) > %MAX_LINE)): %next_space = " \\\n" - + %nomsu::add %next_space - if (%bit is text): unless (..) all of [..] - %tree.(%i - 1) is text - (%tree.(%i - 1) is a nomsu operator) != (%bit is a nomsu operator) - ..: %nomsu::add %next_space + %tree.(%i - 1) is text, (%tree.(%i - 1) is a nomsu operator) != (%bit is a nomsu operator) + ..: + %nomsu::add %next_space + %nomsu::add %bit %next_space = " " do next %bit - + %bit_nomsu = (recurse on %bit) - if (%bit.type == "Comment"): - %next_space = "\n" + if (%bit.type == "Comment"): %next_space = "\n" ..else: %next_space = (" " if (%bit_nomsu::is one line) else "\n..") if (%bit.type == "Action"): %bit_nomsu::parenthesize - + return %nomsu - + "EscapedNomsu": %nomsu::add "\\" %val_nomsu = (recurse on %tree.1) @@ -234,25 +242,25 @@ action [%tree decompiled]: %val_nomsu::parenthesize %nomsu::add %val_nomsu return %nomsu - + "Block": for %line in %tree at %i: - if ((%i > 1) and (%line.type == "Comment")): - %nomsu::add "\n" + if ((%i > 1) and (%line.type == "Comment")): %nomsu::add "\n" %line_nomsu = (recurse on %line) %nomsu::add if (%i < (size of %tree)): - if ((%line_nomsu::number of lines) > 2): - %nomsu::add "\n\n" - ..else: - %nomsu::add "\n" - return (Nomsu Code from %tree [":\n ", %nomsu]) - + if ((%line_nomsu::number of lines) > 2): %nomsu::add "\n\n" + ..else: %nomsu::add "\n" + + return (..) + Nomsu Code from %tree [..] + ":\n ", %nomsu + "Text": # Multi-line text has more generous wrap margins %max_line = ((1.5 * %MAX_LINE) rounded down) %nomsu = (Nomsu Code from %tree) - local action [add text from %tree]: + (add text from %tree) means: for %bit in %tree at %i: if (%bit is text): # TODO: escape properly? @@ -262,7 +270,7 @@ action [%tree decompiled]: (%j > 1): %nomsu::add "\n" (((size of %line) > 10) and ((%nomsu::trailing line length) > %max_line)): %nomsu::add "\\\n.." - + repeat while ((size of %line) > 0): %space = (%max_line - (%nomsu::trailing line length)) %split = (%line::position of "[%p%s]" after %space) @@ -284,18 +292,23 @@ action [%tree decompiled]: "Var": if ((%tree.(%i+1) is text) and (not (%tree.(%i+1)::matches "^[ \n\t,.:#(){}[%]]"))): %interp_nomsu::parenthesize - ("List", "Dict"): + + "List" "Dict": %interp_nomsu::parenthesize + %nomsu::add %interp_nomsu - if (%interp_nomsu::is multi-line): - %nomsu::add "\n.." + if (%interp_nomsu::is multi-line): %nomsu::add "\n.." + add text from %tree - return (Nomsu Code from %tree ["\"\\\n ..", %nomsu, "\""]) - - ("List", "Dict"): + return (..) + Nomsu Code from %tree [..] + "\"\\\n ..", %nomsu, "\"" + + "List" "Dict": if ((size of %tree) == 0): %nomsu::add ("[]" if (%tree.type == "List") else "{}") return %nomsu + for %item in %tree at %i: %item_nomsu = (%item decompiled inline) if ((not %item_nomsu) or ((size of "\%item_nomsu") > %MAX_LINE)): @@ -303,10 +316,10 @@ action [%tree decompiled]: %nomsu::add %item_nomsu if (%i < (size of %tree)): if any of [..] - %item_nomsu::is multi-line - ((%nomsu::trailing line length) + (size of "\%item_nomsu")) >= %MAX_LINE + %item_nomsu::is multi-line, ((%nomsu::trailing line length) + (size of "\%item_nomsu")) >= %MAX_LINE ..: %nomsu::add "\n" ..else: %nomsu::add ", " + return (..) Nomsu Code from %tree [..] "[..]\n " if (%tree.type == "List") else "{..}\n " @@ -314,10 +327,12 @@ action [%tree decompiled]: "DictEntry": set {%key:%tree.1, %value:%tree.2} - if (all of [%key.type == "Text", (size of %key) == 1, %key.1 is a nomsu identifier]): - %nomsu::add %key.1 + if (..) + all of [%key.type == "Text", (size of %key) == 1, %key.1 is a nomsu identifier] + ..: %nomsu::add %key.1 ..else: %nomsu::add (%key decompiled inline) + if ((%key.type == "Action") or (%key.type == "Block")): %nomsu::parenthesize %nomsu::add [": ", recurse on %value] @@ -327,11 +342,9 @@ action [%tree decompiled]: %nomsu::add ["#", %tree.1::with "\n" -> "\n "] return %nomsu - ("IndexChain", "Number", "Var"): + "IndexChain" "Number" "Var": return (%tree decompiled inline) - "Error": barf "Cannot decompile an error" - else: barf "Unknown type: \(%tree.type)" diff --git a/nomnom/files.nom b/nomnom/files.nom index e4b5aa2..352ddfa 100644 --- a/nomnom/files.nom +++ b/nomnom/files.nom @@ -1,3 +1,4 @@ +#!/usr/bin/env nomsu -V4.8.10 # Some file utilities for searching for files recursively and using package.nomsupath use "lib/os.nom" @@ -6,12 +7,12 @@ use "lib/os.nom" %_BROWSE_CACHE = {} # Create a fake file and put it in the cache -action [spoof file %filename %contents]: +externally (spoof file %filename %contents) means: %_SPOOFED_FILES.%filename = %contents return %contents # Read a file's contents -action [read file %filename]: +externally (read file %filename) means: %contents = %_FILE_CACHE.%filename if %contents: return %contents if (%filename == "stdin"): @@ -23,7 +24,7 @@ action [read file %filename]: %_FILE_CACHE.%filename = %contents return %contents -action [%path sanitized]: +externally (%path sanitized) means: %path = (%path::with "\\" -> "\\\\") %path = (%path::with "`" -> "") %path = (%path::with "\"" -> "\\\"") @@ -34,87 +35,74 @@ action [%path sanitized]: try: %lfs = (=lua "require('lfs')") ..and if it succeeds: - local action [filesystem has %filename]: + (filesystem has %filename) means: %mode = (call %lfs.attributes with [%filename, "mode"]) if %mode is: - ("file", "directory", "link", "char device"): - return (yes) + "file" "directory" "link" "char device": return (yes) else: return (no) - action [file %path exists]: - if (..) - any of [..] - %_SPOOFED_FILES.%path - %path == "stdin" - filesystem has %path - ..: return (yes) + externally (file %path exists) means: + if (any of [%_SPOOFED_FILES.%path, %path == "stdin", filesystem has %path]): + return (yes) for %nomsupath in (%package.nomsupath::all matches of "[^;]+"): - if (filesystem has "\%nomsupath/\%path"): - return (yes) + if (filesystem has "\(%nomsupath)/\%path"): return (yes) return (no) - - action [files in %path]: + + externally (files in %path) means: unless %_BROWSE_CACHE.%path: if (%_SPOOFED_FILES.%path or (%filename == "stdin")): %_BROWSE_CACHE.%path = [%path] ..else: if (call %lfs.attributes with [%filename, "mode"]) is: - ("file", "char device"): + "file" "char device": %_BROWSE_CACHE.%path = [%filename] - ("directory", "link"): + "directory" "link": for %nomsupath in (%package.nomsupath::all matches of "[^;]+"): %files = [] - for %member in (call %lfs.dir with ["\%nomsupath/\%filename"]): - if ((%member == ".") or (%member == "..")): - do next %member + for %member in (call %lfs.dir with ["\(%nomsupath)/\%filename"]): + if ((%member == ".") or (%member == "..")): do next %member for % in (files in %member): %files::add % + if ((size of %files) > 0): %_BROWSE_CACHE.%path = %files go to (Found Files) - + %_BROWSE_CACHE.%path = [] + else: %_BROWSE_CACHE.%path = [] - + === (Found Files) === return %_BROWSE_CACHE.%filename - ..or if it barfs: # LFS not found! Fall back to shell commands, if available. unless (sh> "find . -maxdepth 0"): barf "\ - ..Could not find 'luafilesystem' module and couldn't run system command 'find' \ - ..(this might happen on Windows). Please install 'luafilesystem' (which can be \ - ..found at \(..) - "https://github.com/spacewander/luafilesystem" - ..if %jit else "https://github.com/keplerproject/luafilesystem" + ..Could not find 'luafilesystem' module and couldn't run system command 'find' (this might happen on Windows). Please install \ + ..'luafilesystem' (which can be found at \(..) + "https://github.com/spacewander/luafilesystem" if %jit else "\ + ..https://github.com/keplerproject/luafilesystem" .. or obtained through `luarocks install luafilesystem`)" - - - action [file %path exists]: - if (..) - any of [..] - %_SPOOFED_FILES.%path - %path == "stdin" - sh> "ls \(%path sanitized)" + + externally (file %path exists) means: + if (any of [%_SPOOFED_FILES.%path, %path == "stdin", sh> "ls \(%path sanitized)"]) \ ..: return (yes) for %nomsupath in (%package.nomsupath::all matches of "[^;]+"): - if (sh> "ls \(%nomsupath)/\(%path)"): - return (yes) + if (sh> "ls \(%nomsupath)/\%path"): return (yes) return (no) - - action [files in %path]: + + externally (files in %path) means: unless %_BROWSE_CACHE.%path: if %_SPOOFED_FILES.%path: %_BROWSE_CACHE.%path = [%_SPOOFED_FILES.%path] ..else: for %nomsupath in (%package.nomsupath::all matches of "[^;]+"): - %files = (sh> "find -L '\%path' -not -path '*/\\.*' -type f'") + %files = (sh> "find -L '\(%path)' -not -path '*/\\.*' -type f'") if %files: %_BROWSE_CACHE.%path = (%files::lines) go to (Found Files) + %_BROWSE_CACHE.%path = [] - + === (Found Files) === return %_BROWSE_CACHE.%path - diff --git a/nomnom/parser.nom b/nomnom/parser.nom index dfd5253..13d6112 100644 --- a/nomnom/parser.nom +++ b/nomnom/parser.nom @@ -1,16 +1,17 @@ +#!/usr/bin/env nomsu -V4.8.10 # This file contains the parser, which converts text into abstract syntax trees #use "nomonom/ast.nom" - %lpeg = (=lua "require('lpeg')") %re = (=lua "require('re')") call %lpeg.setmaxstack with [20000] set {..} - (action (P 1)): %lpeg.P, (action (R 1)): %lpeg.R, (action (Carg 1)): %lpeg.Carg, - (action (S 1)): %lpeg.S, - (action (Cc 1)): %lpeg.Cc, (action (lpeg re pattern 1)): %re.compile, - (action (lpeg re pattern 1 using 2)): %re.compile - (action (lpeg pattern 1's match of 2)): %lpeg.match - (action (lpeg pattern 1's match of 2 with 3)): [%1, %2, %3] -> (call %lpeg.match with [%1, %2, nil, %3]) + ((P 1)'s meaning):%lpeg.P, ((R 1)'s meaning):%lpeg.R + ((Carg 1)'s meaning):%lpeg.Carg, ((S 1)'s meaning):%lpeg.S + ((Cc 1)'s meaning):%lpeg.Cc, ((lpeg re pattern 1)'s meaning):%re.compile + ((lpeg re pattern 1 using 2)'s meaning):%re.compile + ((lpeg pattern 1's match of 2)'s meaning):%lpeg.match + ((lpeg pattern 1's match of 2 with 3)'s meaning): (..) + [%1, %2, %3] -> (call %lpeg.match with [%1, %2, nil, %3]) %source_code_for_tree = {} %defs = (..) @@ -34,28 +35,30 @@ set {..} %t = (Syntax Tree %t) (Syntax Tree).source_code_for_tree.%t = %userdata.source return %t - ..with fallback %key ->: if: (%key::matches "^ascii_(%d+)$"): %i = (%key::matching "^ascii_(%d+)$") return (call %string.char with [%i as a number]) + (%key::matches "^number_(%d+)$"): %i = (%key::matching "^number_(%d+)$") return (Cc (%i as a number)) -%id_patt = (((P "") - (R "09")) * ((%defs.utf8_char + (R "az") + (R "AZ") + (P "_") + (R "09"))^1 * -1)) -%operator_patt = ((S "'`~!@$^&*+=|<>?/-")^1 * -1) +%id_patt = (..) + ((P "") - (R "09")) * (..) + (%defs.utf8_char + (R "az") + (R "AZ") + (P "_") + (R "09")) ^ 1 * -1 -action [%text is a nomsu id, %text is a nomsu identifier] (..) +%operator_patt = ((S "'`~!@$^&*+=|<>?/-") ^ 1 * -1) +externally [%text is a nomsu id, %text is a nomsu identifier] all mean (..) lpeg pattern %id_patt's match of %text -action [%text is a nomsu operator] (..) +externally (%text is a nomsu operator) means (..) lpeg pattern %operator_patt's match of %text %peg_tidier = (..) lpeg re pattern "\ - file <- %nl* {~ (def/comment) (%nl+ (def/comment))* %nl* ~} + ..file <- %nl* {~ (def/comment) (%nl+ (def/comment))* %nl* ~} def <- anon_def / captured_def anon_def <- ({ident} (" "*) ":" {[^%nl]* (%nl+ " "+ [^%nl]*)*}) @@ -67,18 +70,22 @@ action [%text is a nomsu operator] (..) comment <- "--" [^%nl]* " -action [make parser from %peg] (make parser from %peg using (nil)) - -action [make parser from %peg using %make_tree]: +externally (make parser from %peg) means (make parser from %peg using (nil)) +externally (make parser from %peg using %make_tree) means: %peg = (lpeg pattern %peg_tidier's match of %peg) %peg = (lpeg re pattern %peg using %defs) - local action [%input from %filename parsed]: + (%input from %filename parsed) means: %input = "\%input" - %tree_mt = {__index: {source:%input, filename:%filename}} + %tree_mt = {__index:{source:%input, filename:%filename}} %userdata = {..} - make_tree: %make_tree or ([%]-> (: set %'s metatable to %tree_mt; return %)) + make_tree:%make_tree or ([%] -> (: set %'s metatable to %tree_mt; return %)) filename:%filename, source:%input + %tree = (lpeg pattern %peg's match of %input with %userdata) - assume %tree or barf "File \%filename failed to parse:\n\%input" + assume %tree or barf "\ + ..File \%filename failed to parse: + \%input" + return %tree - return (action (1 from 2 parsed)) + + return ((1 from 2 parsed)'s meaning) diff --git a/nomnom/pretty_errors.nom b/nomnom/pretty_errors.nom index f32b849..db4be5a 100644 --- a/nomnom/pretty_errors.nom +++ b/nomnom/pretty_errors.nom @@ -1,12 +1,11 @@ +#!/usr/bin/env nomsu -V4.8.10 # This file has code for converting errors to user-friendly format, with colors, line numbers, code excerpts, and so on. - -local action [visible size of %text]: +(visible size of %text) means: return (size of (%text::with "\027%[[0-9;]*m" -> "")) -local action [%text boxed]: - %max_line = (..) - max of ((visible size of %line) for %line in (%text::lines)) +(%text boxed) means: + %max_line = (max of ((visible size of %line) for %line in (%text::lines))) %ret = (..) "\n\%text"::with "\n([^\n]*)" -> (..) [%] -> (..) @@ -14,47 +13,45 @@ local action [%text boxed]: return %ret.[2,-1] %CONTEXT = 2 -action [pretty %title error at %tree %err hint %hint]: +externally (pretty %title error at %tree %err hint %hint) means: %source_code = (%tree::get source code) %start = %tree.source.start %stop = %tree.source.stop %filename = (%tree.source.filename or "???") - %err_line = (%source_code::line at %start) %err_linenum = (%source_code::line number at %start) %err_linepos = (%source_code::line position at %start) + # TODO: better handle multi-line errors - %err_size = (..) - min of [..] - %stop - %start - (size of %err_line) - %err_linepos + 1 + %err_size = (min of [%stop - %start, (size of %err_line) - %err_linepos + 1]) %nl_indicator = (" " if (%err_linepos > (size of %err_line)) else "") %fmt_str = " %\(size of "\(%err_linenum + %CONTEXT)")d|" - local action [num %i] (%fmt_str::formatted with %i) + (num %i) means (%fmt_str::formatted with %i) %linenum_size = (size of (num 0)) - %pointer = "\(" "::* (%err_linepos + %linenum_size - 1))" if (%err_size >= 2): %pointer += "╚\("═"::* (%err_size - 2))╝" - ..else: - %pointer += "⬆" - - %err_msg = "\027[33;41;1m\(%title or "Error") at \(%filename):\(%err_linenum)\027[0m" + ..else: %pointer += "⬆" + + %err_msg = "\ + ..\027[33;41;1m\(%title or "Error") at \%filename:\%err_linenum\027[0m" for %i in (%err_linenum - %CONTEXT) to (%err_linenum - 1): %line = (%source_code::line %i) if %line: %err_msg += "\n\027[2m\(num %i)\027[0m\(%line)\027[0m" + if %err_line: %before = %err_line.[1, %err_linepos - 1] %during = %err_line.[%err_linepos, %err_linepos + %err_size - 1] %after = %err_line.[%err_linepos + %err_size, -1] - %err_line = "\027[0m\(%before)\027[41;30m\(%during)\(%nl_indicator)\027[0m\(%after)" + %err_line = "\027[0m\(%before)\027[41;30m\%during\(%nl_indicator)\027[0m\%after" %err_msg += "\n\027[2m\(num %err_linenum)\(%err_line)\027[0m" + %err_linenum_end = (%source_code::line number at %stop) %err_linepos_end = (%source_code::line position at %stop) %err_linenum_end or= %err_linenum if (%err_linenum_end == %err_linenum): - %err_msg += "\n\(%pointer)" + %err_msg += "\n\%pointer" ..else: for %i in (%err_linenum + 1) to %err_linenum_end: %line = (%source_code::line %i) @@ -62,24 +59,27 @@ action [pretty %title error at %tree %err hint %hint]: if (%i == %err_linenum_end): %during = %line.[1, %err_linepos_end - 1] %after = %line.[%err_linepos_end, -1] - %err_msg += "\n\027[2m\(num %i)\027[0;41;30m\(%during)\027[0m\(%after)" + %err_msg += "\n\027[2m\(num %i)\027[0;41;30m\(%during)\027[0m\%after" ..else: %err_msg += "\n\027[2m\(num %i)\027[0;41;30m\(%line)\027[0m" - + %box_width = 70 %err_text = "\ - ..\027[47;31;1m\((" \(%err)"::wrapped to %box_width)::with "\n" -> "\n\027[47;31;1m ")" + ..\027[47;31;1m\((" \%err"::wrapped to %box_width)::with "\n" -> "\n\027[47;31;1m ")" if %hint: %err_text += "\n\027[47;30m\((" Suggestion: \(%hint)"::wrapped to %box_width)::with "\n" -> "\n\027[47;30m ")" %err_msg += "\n\027[33;1m \((%err_text boxed)::with "\n" -> "\n ")" - + + %err_msg += "\n\027[33;1m \((%err_text boxed)::with "\n" -> "\n ")" for %i in (%err_linenum_end + 1) to (%err_linenum_end + %CONTEXT): %line = (%source_code::line %i) if %line: %err_msg += "\n\027[2m\(num %i)\027[0m\(%line)\027[0m" + return %err_msg -action [pretty %title error at %tree %err] (pretty %title error at %tree %err (nil)) +externally (pretty %title error at %tree %err) means (..) + pretty %title error at %tree %err (nil) -action [%err_tree as a pretty error] (..) +externally (%err_tree as a pretty error) means (..) pretty %err_tree.title error at %err_tree %err_tree.error hint %err_tree.hint diff --git a/nomnom/source.nom b/nomnom/source.nom index e05b314..c36216f 100644 --- a/nomnom/source.nom +++ b/nomnom/source.nom @@ -1,24 +1,28 @@ +#!/usr/bin/env nomsu -V4.8.10 use "lib/object.nom" object (Source): - action [Source from text %text]: + externally (Source from text %text) means: %match = (%text::matching groups "^@(.-)%[(%d+):(%d+)%]$") set {%filename:%match.1, %start:%match.2, %stop:%match.3} unless %filename: %match = (%text::matching groups "^@(.-)%[(%d+)%]$") set {%filename:%match.1, %start:%match.2} - return (Source {filename:%filename, start:(%start or 1) as number, stop: %stop as number}) - + + return (..) + Source {filename:%filename, start:(%start or 1) as number, stop:%stop as number} + my action [as text] "\ ..@\(%me.filename)[\(%me.start)\(":\(%me.stop)" if %me.stop else "")]" - my action [as lua] "\ - ..Source{filename=\(%me.filename::as lua), start=\(%me.start)\ - ..\(", stop=\(%me.stop)" if %stop else "")}" - + ..Source{filename=\(%me.filename::as lua), start=\(%me.start)\(..) + ", stop=\(%me.stop)" if %stop else "" + ..}" + my action [as nomsu] "\ - ..(Source {filename:\(%me.filename::as nomsu), start:\(%me.start)\ - ..\(", stop:\(%me.stop)" if %stop else "")})" + ..(Source {filename:\(%me.filename::as nomsu), start:\(%me.start)\(..) + ", stop:\(%me.stop)" if %stop else "" + ..})" my action [== %other] (..) all of [..] @@ -26,24 +30,25 @@ object (Source): %me.filename == %other.filename %me.start == %other.start %me.stop == %other.stop - + my action [< %other]: assume %me.filename == %other.filename if (%start == %other.start): return ((%me.stop or %me.start) < (%other.stop or %other.start)) ..else: return (%me.start < %other.start) - + my action [<= %other]: assume %me.filename == %other.filename if (%start == %other.start): return ((%me.stop or %me.start) <= (%other.stop or %other.start)) ..else: return (%me.start <= %other.start) - + my action [+ %offset]: if ((type of %me) == "number"): set {%me:%offset, %offset:%me} ..else: assume (type of %offset) == "number" + return (Source {filename:%me.filename, start:%me.start + %offset, stop:%me.stop}) diff --git a/tools/autoformat.nom b/tools/autoformat.nom index a915fa4..13f54ef 100755 --- a/tools/autoformat.nom +++ b/tools/autoformat.nom @@ -1,7 +1,7 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # Auto-format Nomsu code. Usage: - nomsu tools/autoformat.nom [-i] file1 file2 directory1 ... + nomsu tools/autoformat.nom [-i] file1 file2 directory1 ... If the first argument is "-i", modifications will be performed in-place. Otherwise, the formatted code will be printed. diff --git a/tools/find_action.nom b/tools/find_action.nom index e30f155..e7e3f49 100755 --- a/tools/find_action.nom +++ b/tools/find_action.nom @@ -1,7 +1,7 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # Find an action by its stub. Usage: - nomsu tools/find_action.nom "foo %" file1 file2 directory1 ... + nomsu tools/find_action.nom "foo %" file1 file2 directory1 ... Will print all the code locations and code that uses the stub. use "lib/os.nom" @@ -28,6 +28,6 @@ for %path in %files: if (%t is syntax tree): for %sub in %t: recurse %t on %sub + sort %results by % -> %.line - for % in %results: - say %.text + for % in %results: say %.text diff --git a/tools/parse.nom b/tools/parse.nom index 9d728e8..de6aff4 100755 --- a/tools/parse.nom +++ b/tools/parse.nom @@ -1,11 +1,11 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # Tool to print out a parse tree of files in an easy-to-read format. Usage: - nomsu tools/parse.nom file1 file2 directory1 ... + nomsu tools/parse.nom file1 file2 directory1 ... use "lib/os.nom" -action [print tree %t at indent %indent]: +externally (print tree %t at indent %indent) means: if %t.type is: "Action": say "\(%indent)Action (\(%t.stub)):" diff --git a/tools/replace.nom b/tools/replace.nom index c55793a..25ae0ae 100755 --- a/tools/replace.nom +++ b/tools/replace.nom @@ -1,7 +1,7 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # Tool to find and replace one tree with another. - nomsu tools/replace.nom [-i] tree_to_replace replacement file1 file2 directory1 ... + nomsu tools/replace.nom [-i] tree_to_replace replacement file1 file2 directory1 ... If "-i" is the first argument, replacements will be performed in-place. Otherwise, the upgraded code will be printed. diff --git a/tools/test.nom b/tools/test.nom index 6d557ea..fb70d1c 100755 --- a/tools/test.nom +++ b/tools/test.nom @@ -1,7 +1,7 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # Tool to run all tests in a file (i.e. the code block inside a call to 'test %'). Usage: - nomsu tools/test.nom file1 file2 directory1 ... + nomsu tools/test.nom file1 file2 directory1 ... use "lib/os.nom" use "lib/consolecolor.nom" @@ -17,7 +17,6 @@ for %path in (command line args): if (%filename::matches "%.nom$"): use %filename for %path in (command line args): use %path - %tests = ((=lua "Source:from_string(\%s)") = %t for %s = %t in (tests)) for %path in (command line args): for file %filename in %path: diff --git a/tools/upgrade.nom b/tools/upgrade.nom index 7d36793..575646e 100755 --- a/tools/upgrade.nom +++ b/tools/upgrade.nom @@ -1,7 +1,7 @@ #!/usr/bin/env nomsu -V4.8.10 # Tool to automatically update code from old versions of Nomsu. Usage: - nomsu tools/upgrade.nom [-i] file1 file2 directory1 ... + nomsu tools/upgrade.nom [-i] file1 file2 directory1 ... If "-i" is the first argument, upgrades will be performed in-place. Otherwise, the upgraded code will be printed. @@ -10,27 +10,37 @@ use "lib/os.nom" %args = (command line args) %inplace = (no) +%start_version = (nil) %version = (Nomsu version) repeat: if %args.1 is: "-i": %inplace = (yes) %args::remove index 1 + "-t": use "lib/consolecolor.nom" %test = (yes) %args::remove index 1 + "-V": %version = %args.2 %args::remove index 1 %args::remove index 1 + + "-S": + %start_version = %args.2 + %args::remove index 1 + %args::remove index 1 + else: stop for %path in %args: for file %filename in %path: unless (%filename::matches "%.nom$"): do next %filename %tree = (parse (read file %filename) from %filename) - %uptree = (%tree upgraded to %version) + %uptree = (..) + %tree upgraded from (%start_version or (%tree.version or (Nomsu version))) to %version %text = "\ ..#!/usr/bin/env nomsu -V\%version \(%uptree as nomsu)" -- cgit v1.2.3 From ec92b0fccd70f06b5348fa355f49557aa71fdb3c Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Wed, 31 Oct 2018 15:10:03 -0700 Subject: More explicit. --- nomnom/compile.nom | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nomnom/compile.nom b/nomnom/compile.nom index 18afe3c..70f32b8 100644 --- a/nomnom/compile.nom +++ b/nomnom/compile.nom @@ -30,8 +30,8 @@ externally (barf any errors in %t) means: externally (%tree compiled with %compile_actions) means: assume (%tree is a "Syntax Tree") if all of [..] - %tree.version, (Nomsu version)'s meaning, %tree.version != (Nomsu version) - (1 upgraded from 2 to 3)'s meaning + %tree.version, ((Nomsu version)'s meaning) != (nil), %tree.version != (Nomsu version) + ((1 upgraded from 2 to 3)'s meaning) != (nil) ..then: %tree = (upgrade %tree from %tree.version to (Nomsu version)) -- cgit v1.2.3 From d0c3c57f7b25c8d912c426e48cb5ab09cd738f65 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Wed, 31 Oct 2018 15:54:18 -0700 Subject: Simplified AST to just use a single moonscript class called "SyntaxTree" instead of a different metatable for each type of syntax tree. --- core/metaprogramming.nom | 24 +++--- core/operators.nom | 2 +- nomsu_compiler.lua | 33 +++---- nomsu_compiler.moon | 29 +++---- syntax_tree.lua | 220 +++++++++++++++++++++-------------------------- syntax_tree.moon | 164 +++++++++++++++++------------------ 6 files changed, 212 insertions(+), 260 deletions(-) diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom index c999191..dbc45a4 100644 --- a/core/metaprogramming.nom +++ b/core/metaprogramming.nom @@ -22,10 +22,10 @@ lua> "\ lua> "\ ..COMPILE_ACTIONS["1 -> 2"] = function(nomsu, tree, \%args, \%body) local lua = LuaCode.Value(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 nomsu:compile(a):as_smext() or a end) + if SyntaxTree:is_instance(\%args) and \%args.type == "Action" then \%args = \%args:get_args() end + local lua_args = table.map(\%args, function(a) return SyntaxTree:is_instance(a) and nomsu:compile(a):as_smext() 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 + local body_lua = SyntaxTree:is_instance(\%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)") @@ -177,13 +177,13 @@ test: replacements[arg[1]] = nomsu:compile(arg):as_smext() end local function make_tree(t) - if AST.is_syntax_tree(t, "Var") then + if SyntaxTree:is_instance(t) and t.type == "Var" then if replacements[t[1]] then return replacements[t[1]] else - return t.type.."{mangle("..t[1]:as_lua().."), source="..tostring(t.source):as_lua().."}" + return "SyntaxTree{mangle("..t[1]:as_lua().."), type="..t.type:as_lua()..", source="..tostring(t.source):as_lua().."}" end - elseif AST.is_syntax_tree(t) then + elseif SyntaxTree:is_instance(t) then local ret = {} local i = 1 for k, v in pairs(t) do @@ -198,7 +198,7 @@ test: ret[#ret+1] = "["..make_tree(k).."]= "..make_tree(v) end end - return t.type.."{"..table.concat(ret, ", ").."}" + return "SyntaxTree{"..table.concat(ret, ", ").."}" elseif lua_type_of_1(t) == 'number' then return tostring(t) else @@ -241,8 +241,8 @@ test: externally [%var as lua identifier, %var as lua id] all mean: lua> "\ ..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 + elseif SyntaxTree:is_instance(\%var, 'Var') then return \%var[1]:as_lua_id() + elseif SyntaxTree:is_instance(\%var) then local lua = \(%var as lua expr) if not lua:as_smext():match("^[_a-zA-Z][_a-zA-Z0-9]*$") then nomsu:compile_error(\%var, "This is not a valid Lua identifier.") @@ -253,9 +253,9 @@ externally [%var as lua identifier, %var as lua id] all mean: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -(% is syntax tree) compiles to (Lua value "AST.is_syntax_tree(\(% as lua expr))") +(% is syntax tree) compiles to (Lua value "SyntaxTree:is_instance(\(% as lua expr))") (% is %kind syntax tree) compiles to (..) - Lua value "AST.is_syntax_tree(\(% as lua expr), \(%kind as lua expr))" + Lua value "SyntaxTree:is_instance(\(% as lua expr), \(%kind as lua expr))" (%tree with %t -> %replacement) compiles to (..) Lua value "\ @@ -295,7 +295,7 @@ externally (match %tree with %patt) means: if #\%patt ~= #\%tree then return nil end local matches = _Dict{} for \%i=1,#\%patt do - if AST.is_syntax_tree(\%tree[\%i]) then + if SyntaxTree:is_instance(\%tree[\%i]) then local submatch = \(match %tree.%i with %patt.%i) if not submatch then return nil end for k,v in pairs(submatch) do diff --git a/core/operators.nom b/core/operators.nom index 489bbfe..bd93cd5 100644 --- a/core/operators.nom +++ b/core/operators.nom @@ -53,7 +53,7 @@ test: for i, item in ipairs(\%assignments) do local \%target, \%value = item[1], item[2] \%value = \%value:map(function(t) - if Action:is_instance(t) and t.stub == "?" then + if SyntaxTree:is_instance(t) and t.type == "Action" and t.stub == "?" then return \%target end end) diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua index 8c2d90b..848999a 100644 --- a/nomsu_compiler.lua +++ b/nomsu_compiler.lua @@ -35,7 +35,7 @@ do local _obj_0 = require("code_obj") NomsuCode, LuaCode, Source = _obj_0.NomsuCode, _obj_0.LuaCode, _obj_0.Source end -local AST = require("syntax_tree") +local SyntaxTree = require("syntax_tree") local make_parser = require("parser") local pretty_error = require("pretty_errors") SOURCE_MAP = { } @@ -97,16 +97,14 @@ escape = function(s) end local make_tree make_tree = function(tree, userdata) - local cls = AST[tree.type] tree.source = Source(userdata.filename, tree.start, tree.stop) tree.start, tree.stop = nil, nil - tree.type = nil do local _accum_0 = { } local _len_0 = 1 for _index_0 = 1, #tree do local t = tree[_index_0] - if AST.is_syntax_tree(t, "Comment") then + if SyntaxTree:is_instance(t) and t.type == "Comment" then _accum_0[_len_0] = t _len_0 = _len_0 + 1 end @@ -117,15 +115,11 @@ make_tree = function(tree, userdata) tree.comments = nil end for i = #tree, 1, -1 do - if AST.is_syntax_tree(tree[i], "Comment") then + if SyntaxTree:is_instance(tree[i]) and tree[i].type == "Comment" then table.remove(tree, i) end end - tree = setmetatable(tree, cls) - cls.source_code_for_tree[tree] = userdata.source - if tree.__init then - tree:__init() - end + tree = SyntaxTree(tree) return tree end local Parsers = { } @@ -200,7 +194,7 @@ do lpeg = lpeg, re = re, Files = Files, - AST = AST, + SyntaxTree = SyntaxTree, TESTS = Dict({ }), globals = Dict({ }), LuaCode = LuaCode, @@ -245,9 +239,6 @@ do if jit or _VERSION == "Lua 5.2" then NomsuCompiler.environment.bit = require("bitops") end - for k, v in pairs(AST) do - NomsuCompiler.environment[k] = v - end NomsuCompiler.fork = function(self) local f = setmetatable({ }, { __index = self @@ -288,7 +279,7 @@ do for k, v in pairs(t) do local _continue_0 = false repeat - if not (AST.is_syntax_tree(v)) then + if not (SyntaxTree:is_instance(v)) then _continue_0 = true break end @@ -540,7 +531,7 @@ do Files.spoof(source.filename, to_run) end local tree - if AST.is_syntax_tree(to_run) then + if SyntaxTree:is_instance(to_run) then tree = to_run else tree = self:parse(to_run, source) @@ -714,7 +705,7 @@ do local filename = Source:from_string(info.source).filename self:compile_error(tree, "The compile-time action here (" .. tostring(stub) .. ") failed to return any value.", "Look at the implementation of (" .. tostring(stub) .. ") in " .. tostring(filename) .. ":" .. tostring(info.linedefined) .. " and make sure it's returning something.") end - if AST.is_syntax_tree(ret) then + if SyntaxTree:is_instance(ret) then if ret == tree then local info = debug.getinfo(compile_action, "S") local filename = Source:from_string(info.source).filename @@ -763,19 +754,19 @@ do lua:append(")") return lua elseif "EscapedNomsu" == _exp_0 then - local lua = LuaCode.Value(tree.source, tree[1].type, "{") + local lua = LuaCode.Value(tree.source, "SyntaxTree{") local needs_comma, i = false, 1 local as_lua as_lua = function(x) if type(x) == 'number' then return tostring(x) - elseif AST.is_syntax_tree(x) then + elseif SyntaxTree:is_instance(x) then return self:compile(x, compile_actions) else return x:as_lua() end end - for k, v in pairs(AST.is_syntax_tree(tree[1], "EscapedNomsu") and tree or tree[1]) do + for k, v in pairs((SyntaxTree:is_instance(tree[1]) and tree[1].type == "EscapedNomsu" and tree) or tree[1]) do if needs_comma then lua:append(", ") else @@ -1175,7 +1166,7 @@ do local _list_0 = t for _index_0 = 1, #_list_0 do local x = _list_0[_index_0] - if AST.is_syntax_tree(x) then + if SyntaxTree:is_instance(x) then find_comments(x) end end diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon index 304f6b9..cbddf51 100644 --- a/nomsu_compiler.moon +++ b/nomsu_compiler.moon @@ -23,7 +23,7 @@ colored = setmetatable({}, {__index:(_,color)-> ((msg)-> colors[color]..tostring unpack or= table.unpack {:match, :sub, :gsub, :format, :byte, :find} = string {:NomsuCode, :LuaCode, :Source} = require "code_obj" -AST = require "syntax_tree" +SyntaxTree = require "syntax_tree" make_parser = require("parser") pretty_error = require("pretty_errors") -- Mapping from source string (e.g. "@core/metaprogramming.nom[1:100]") to a mapping @@ -62,18 +62,14 @@ escape = (s)-> -- Re-implement nomsu-to-lua comment translation? make_tree = (tree, userdata)-> - cls = AST[tree.type] tree.source = Source(userdata.filename, tree.start, tree.stop) tree.start, tree.stop = nil, nil - tree.type = nil - tree.comments = [t for t in *tree when AST.is_syntax_tree(t, "Comment")] + tree.comments = [t for t in *tree when SyntaxTree\is_instance(t) and t.type == "Comment"] if #tree.comments == 0 then tree.comments = nil for i=#tree,1,-1 - if AST.is_syntax_tree(tree[i], "Comment") + if SyntaxTree\is_instance(tree[i]) and tree[i].type == "Comment" table.remove(tree, i) - tree = setmetatable(tree, cls) - cls.source_code_for_tree[tree] = userdata.source - if tree.__init then tree\__init! + tree = SyntaxTree(tree) return tree Parsers = {} @@ -108,7 +104,7 @@ with NomsuCompiler _List:List, _Dict:Dict, -- Utilities and misc. stringify:stringify, utils:utils, lpeg:lpeg, re:re, Files:Files, - :AST, TESTS: Dict({}), globals: Dict({}), + :SyntaxTree, TESTS: Dict({}), globals: Dict({}), :LuaCode, :NomsuCode, :Source nomsu:NomsuCompiler __imported: Dict{} @@ -130,7 +126,6 @@ with NomsuCompiler return ipairs(x) if jit or _VERSION == "Lua 5.2" .environment.bit = require("bitops") - for k,v in pairs(AST) do .environment[k] = v .fork = => f = setmetatable({}, {__index:@}) @@ -160,7 +155,7 @@ with NomsuCompiler coroutine.yield t else for k,v in pairs(t) - continue unless AST.is_syntax_tree(v) + continue unless SyntaxTree\is_instance(v) find_errors(v) errs = [err for err in coroutine.wrap(-> find_errors(tree))] @@ -303,7 +298,7 @@ with NomsuCompiler source = to_run.source or Source(to_run, 1, #to_run) if type(source) == 'string' then source = Source\from_string(source) if not Files.read(source.filename) then Files.spoof(source.filename, to_run) - tree = if AST.is_syntax_tree(to_run) then to_run else @parse(to_run, source) + tree = if SyntaxTree\is_instance(to_run) then to_run else @parse(to_run, source) if tree == nil -- Happens if pattern matches, but there are no captures, e.g. an empty string return nil if tree.type != "FileChunks" @@ -416,7 +411,7 @@ with NomsuCompiler @compile_error tree, "The compile-time action here (#{stub}) failed to return any value.", "Look at the implementation of (#{stub}) in #{filename}:#{info.linedefined} and make sure it's returning something." - if AST.is_syntax_tree(ret) + if SyntaxTree\is_instance(ret) if ret == tree info = debug.getinfo(compile_action, "S") filename = Source\from_string(info.source).filename @@ -457,16 +452,16 @@ with NomsuCompiler return lua when "EscapedNomsu" - lua = LuaCode.Value tree.source, tree[1].type, "{" + lua = LuaCode.Value tree.source, "SyntaxTree{" needs_comma, i = false, 1 as_lua = (x)-> if type(x) == 'number' tostring(x) - elseif AST.is_syntax_tree(x) + elseif SyntaxTree\is_instance(x) @compile(x, compile_actions) else x\as_lua! - for k,v in pairs(AST.is_syntax_tree(tree[1], "EscapedNomsu") and tree or tree[1]) + for k,v in pairs((SyntaxTree\is_instance(tree[1]) and tree[1].type == "EscapedNomsu" and tree) or tree[1]) if needs_comma then lua\append ", " else needs_comma = true if k == i @@ -743,7 +738,7 @@ with NomsuCompiler find_comments = (t)-> if t.comments and t.source.filename == tree.source.filename comment_set[c] = true for c in *t.comments - find_comments(x) for x in *t when AST.is_syntax_tree x + find_comments(x) for x in *t when SyntaxTree\is_instance x find_comments(tree) -- Sort in reversed order so they can be easily popped comments = [c for c in pairs comment_set] diff --git a/syntax_tree.lua b/syntax_tree.lua index 63c24ee..92cee59 100644 --- a/syntax_tree.lua +++ b/syntax_tree.lua @@ -6,13 +6,6 @@ end local Source Source = require("code_obj").Source local unpack = unpack or table.unpack -local AST = { } -AST.is_syntax_tree = function(n, t) - if t == nil then - t = nil - end - return type(n) == 'table' and getmetatable(n) and getmetatable(n).__type == "Syntax Tree" and (t == nil or n.type == t) -end local as_lua as_lua = function(self) if type(self) == 'number' then @@ -31,40 +24,17 @@ as_lua = function(self) end return error("Not supported: " .. tostring(self)) end -local types = { - "Number", - "Var", - "Block", - "EscapedNomsu", - "Text", - "List", - "Dict", - "DictEntry", - "IndexChain", - "Action", - "FileChunks", - "Error", - "Comment" -} -for _index_0 = 1, #types do - local name = types[_index_0] - local cls = { } - do - cls.__class = cls - cls.__index = cls - cls.__name = name - cls.type = name - cls.__type = "Syntax Tree" - cls.is_instance = function(self, x) - return getmetatable(x) == self - end - cls.__tostring = function(self) +local SyntaxTree +do + local _class_0 + local _base_0 = { + __tostring = function(self) local bits do local _accum_0 = { } local _len_0 = 1 - for _index_1 = 1, #self do - local b = self[_index_1] + for _index_0 = 1, #self do + local b = self[_index_0] _accum_0[_len_0] = tostring(b) _len_0 = _len_0 + 1 end @@ -75,15 +45,29 @@ for _index_0 = 1, #types do table.insert(bits, "[ " .. tostring(tostring(k)) .. "]=" .. tostring(tostring(v))) end end - return tostring(self.type) .. "{" .. tostring(table.concat(bits, ", ")) .. "}" - end - cls.as_lua = function(self) + return "SyntaxTree{" .. tostring(table.concat(bits, ", ")) .. "}" + end, + __eq = function(self, other) + if type(self) ~= type(other) or #self ~= #other or getmetatable(self) ~= getmetatable(other) then + return false + end + for i = 1, #self do + if self[i] ~= other[i] then + return false + end + end + if self.target ~= other.target then + return false + end + return true + end, + as_lua = function(self) local bits do local _accum_0 = { } local _len_0 = 1 - for _index_1 = 1, #self do - local b = self[_index_1] + for _index_0 = 1, #self do + local b = self[_index_0] _accum_0[_len_0] = as_lua(b) _len_0 = _len_0 + 1 end @@ -94,45 +78,32 @@ for _index_0 = 1, #types do table.insert(bits, "[ " .. tostring(as_lua(k)) .. "]=" .. tostring(as_lua(v))) end end - return tostring(self.type) .. "{" .. tostring(table.concat(bits, ", ")) .. "}" - end - cls.source_code_for_tree = setmetatable({ }, { - __index = function(self, t) - local s = t.source - local Files = require('files') - local f = Files.read(s.filename) - return f - end - }) - cls.get_source_code = function(self) - return self.source_code_for_tree[self] - end - cls.map = function(self, fn) + return "SyntaxTree{" .. tostring(table.concat(bits, ", ")) .. "}" + end, + get_source_code = function(self) + return self.__class.source_code_for_tree[self] + end, + map = function(self, fn) local replacement = fn(self) if replacement == false then return nil end if replacement then - if AST.is_syntax_tree(replacement) then - replacement = setmetatable((function() + if SyntaxTree:is_instance(replacement) then + do local _tbl_0 = { } for k, v in pairs(replacement) do _tbl_0[k] = v end - return _tbl_0 - end)(), getmetatable(replacement)) + replacement = _tbl_0 + end replacement.source = self.source if self.comments then replacement.comments = { unpack(self.comments) } end - do - local init = replacement.__init - if init then - init(replacement) - end - end + replacement = SyntaxTree(replacement) end else replacement = { @@ -146,7 +117,7 @@ for _index_0 = 1, #types do local _continue_0 = false repeat replacement[k] = v - if AST.is_syntax_tree(v) then + if SyntaxTree:is_instance(v) then local r = v:map(fn) if r == v or r == nil then _continue_0 = true @@ -164,74 +135,75 @@ for _index_0 = 1, #types do if not (changes) then return self end - replacement = setmetatable(replacement, getmetatable(self)) - do - local init = replacement.__init - if init then - init(replacement) - end - end + replacement = SyntaxTree(replacement) end return replacement - end - cls.__eq = function(self, other) - if type(self) ~= type(other) or #self ~= #other or getmetatable(self) ~= getmetatable(other) then - return false - end - for i = 1, #self do - if self[i] ~= other[i] then - return false + end, + get_args = function(self) + assert(self.type == "Action", "Only actions have arguments") + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #self do + local tok = self[_index_0] + if type(tok) ~= 'string' then + _accum_0[_len_0] = tok + _len_0 = _len_0 + 1 end end - if self.target ~= other.target then - return false - end - return true - end - end - AST[name] = setmetatable(cls, { - __tostring = function(self) - return self.__name + return _accum_0 end, - __call = function(self, t) - if type(t.source) == 'string' then - t.source = Source:from_string(t.source) - end - setmetatable(t, self) - do - local init = t.__init - if init then - init(t) + get_stub = function(self) + local stub_bits = { } + local arg_i = 1 + for _index_0 = 1, #self do + local a = self[_index_0] + if type(a) == 'string' then + stub_bits[#stub_bits + 1] = a + else + stub_bits[#stub_bits + 1] = tostring(arg_i) + arg_i = arg_i + 1 end end - return t + return concat(stub_bits, " ") + end + } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function() end, + __base = _base_0, + __name = "SyntaxTree" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 end }) -end -AST.Action.__init = function(self) - local stub_bits = { } - local arg_i = 1 - for _index_0 = 1, #self do - local a = self[_index_0] - if type(a) == 'string' then - stub_bits[#stub_bits + 1] = a - else - stub_bits[#stub_bits + 1] = tostring(arg_i) - arg_i = arg_i + 1 + _base_0.__class = _class_0 + local self = _class_0 + self.__type = "Syntax Tree" + self.source_code_for_tree = setmetatable({ }, { + __index = function(self, t) + local s = t.source + local Files = require('files') + local f = Files.read(s.filename) + return f end + }) + self.is_instance = function(self, t) + return type(t) == 'table' and getmetatable(t) == self.__base end - self.stub = concat(stub_bits, " ") + SyntaxTree = _class_0 end -AST.Action.get_args = function(self) - local _accum_0 = { } - local _len_0 = 1 - for _index_0 = 1, #self do - local tok = self[_index_0] - if type(tok) ~= 'string' then - _accum_0[_len_0] = tok - _len_0 = _len_0 + 1 - end +getmetatable(SyntaxTree).__call = function(self, t) + if type(t.source) == 'string' then + t.source = Source:from_string(t.source) + end + setmetatable(t, self.__base) + if t.type == 'Action' then + t.stub = t:get_stub() end - return _accum_0 + return t end -return AST +return SyntaxTree diff --git a/syntax_tree.moon b/syntax_tree.moon index f3d3aee..228f560 100644 --- a/syntax_tree.moon +++ b/syntax_tree.moon @@ -4,10 +4,6 @@ {:Source} = require "code_obj" unpack or= table.unpack -AST = {} -AST.is_syntax_tree = (n, t=nil)-> - type(n) == 'table' and getmetatable(n) and getmetatable(n).__type == "Syntax Tree" and (t == nil or n.type == t) - as_lua = => if type(@) == 'number' return tostring(@) @@ -16,90 +12,88 @@ as_lua = => return _as_lua(@) error("Not supported: #{@}") -types = {"Number", "Var", "Block", "EscapedNomsu", "Text", "List", "Dict", "DictEntry", - "IndexChain", "Action", "FileChunks", "Error", "Comment"} -for name in *types - cls = {} - with cls - .__class = cls - .__index = cls - .__name = name - .type = name - .__type = "Syntax Tree" - .is_instance = (x)=> getmetatable(x) == @ - .__tostring = => - bits = [tostring(b) for b in *@] - for k,v in pairs(@) - unless bits[k] - table.insert(bits, "[ #{tostring(k)}]=#{tostring(v)}") - return "#{@type}{#{table.concat(bits, ", ")}}" - .as_lua = => - bits = [as_lua(b) for b in *@] +--types = {"Number", "Var", "Block", "EscapedNomsu", "Text", "List", "Dict", "DictEntry", +-- "IndexChain", "Action", "FileChunks", "Error", "Comment"} +class SyntaxTree + @__type: "Syntax Tree" + + __tostring: => + bits = [tostring(b) for b in *@] + for k,v in pairs(@) + unless bits[k] + table.insert(bits, "[ #{tostring(k)}]=#{tostring(v)}") + return "SyntaxTree{#{table.concat(bits, ", ")}}" + + __eq: (other)=> + return false if type(@) != type(other) or #@ != #other or getmetatable(@) != getmetatable(other) + for i=1,#@ + return false if @[i] != other[i] + return false if @target != other.target + return true + + as_lua: => + bits = [as_lua(b) for b in *@] + for k,v in pairs(@) + unless bits[k] + table.insert(bits, "[ #{as_lua(k)}]=#{as_lua(v)}") + return "SyntaxTree{#{table.concat(bits, ", ")}}" + + @source_code_for_tree: setmetatable({}, {__index:(t)=> + s = t.source + Files = require 'files' + f = Files.read(s.filename) + return f + }) + get_source_code: => @@source_code_for_tree[@] + map: (fn)=> + replacement = fn(@) + if replacement == false then return nil + if replacement + -- Clone the replacement, so we can give it a proper source/comments + if SyntaxTree\is_instance(replacement) + replacement = {k,v for k,v in pairs replacement} + replacement.source = @source + replacement.comments = {unpack(@comments)} if @comments + replacement = SyntaxTree(replacement) + else + replacement = {source:@source, comments:@comments and {unpack(@comments)}} + changes = false for k,v in pairs(@) - unless bits[k] - table.insert(bits, "[ #{as_lua(k)}]=#{as_lua(v)}") - return "#{@type}{#{table.concat(bits, ", ")}}" - .source_code_for_tree = setmetatable({}, {__index:(t)=> - s = t.source - Files = require 'files' - f = Files.read(s.filename) - return f - }) - .get_source_code = => @source_code_for_tree[@] - .map = (fn)=> - replacement = fn(@) - if replacement == false then return nil - if replacement - -- Clone the replacement, so we can give it a proper source/comments - if AST.is_syntax_tree(replacement) - replacement = setmetatable {k,v for k,v in pairs replacement}, getmetatable(replacement) - replacement.source = @source - replacement.comments = {unpack(@comments)} if @comments - if init = replacement.__init then init(replacement) + replacement[k] = v + if SyntaxTree\is_instance(v) + r = v\map(fn) + continue if r == v or r == nil + changes = true + replacement[k] = r + return @ unless changes + replacement = SyntaxTree(replacement) + return replacement + + get_args: => + assert(@type == "Action", "Only actions have arguments") + return [tok for tok in *@ when type(tok) != 'string'] + + get_stub: => + stub_bits = {} + arg_i = 1 + for a in *@ + if type(a) == 'string' + stub_bits[#stub_bits+1] = a else - replacement = {source:@source, comments:@comments and {unpack(@comments)}} - changes = false - for k,v in pairs(@) - replacement[k] = v - if AST.is_syntax_tree(v) - r = v\map(fn) - continue if r == v or r == nil - changes = true - replacement[k] = r - return @ unless changes - replacement = setmetatable replacement, getmetatable(@) - if init = replacement.__init then init(replacement) - return replacement - .__eq = (other)=> - return false if type(@) != type(other) or #@ != #other or getmetatable(@) != getmetatable(other) - for i=1,#@ - return false if @[i] != other[i] - return false if @target != other.target - return true + stub_bits[#stub_bits+1] = tostring(arg_i) + arg_i += 1 + return concat stub_bits, " " - AST[name] = setmetatable cls, - __tostring: => @__name - __call: (t)=> - if type(t.source) == 'string' - t.source = Source\from_string(t.source) - --else - -- assert(Source\is_instance(t.source)) - setmetatable(t, @) - if init = t.__init then init(t) - return t + @is_instance: (t)=> + type(t) == 'table' and getmetatable(t) == @__base -AST.Action.__init = => - stub_bits = {} - arg_i = 1 - for a in *@ - if type(a) == 'string' - stub_bits[#stub_bits+1] = a - else - stub_bits[#stub_bits+1] = tostring(arg_i) - arg_i += 1 - @stub = concat stub_bits, " " -AST.Action.get_args = => - [tok for tok in *@ when type(tok) != 'string'] +getmetatable(SyntaxTree).__call = (t)=> + if type(t.source) == 'string' + t.source = Source\from_string(t.source) + setmetatable(t, @__base) + if t.type == 'Action' + t.stub = t\get_stub! + return t -return AST +return SyntaxTree -- cgit v1.2.3 From 307dea18815ba4a06a3098edb170d7ad90708815 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Fri, 2 Nov 2018 14:38:24 -0700 Subject: Changed stub convention to (foo 1 baz 2) -> foo_1_baz instead of foo_1_baz_2, removed "smext", made some cleanup changes. --- code_obj.lua | 25 ++-- code_obj.moon | 25 ++-- compatibility/4.8.10.nom | 1 + compatibility/compatibility.nom | 2 +- containers.lua | 50 ++++---- containers.moon | 42 +++---- core/control_flow.nom | 32 ++--- core/errors.nom | 22 ++-- core/math.nom | 8 +- core/metaprogramming.nom | 37 +++--- core/operators.nom | 8 +- files.lua | 2 + files.moon | 2 + lib/consolecolor.nom | 10 +- lib/object.nom | 6 +- nomnom/ast.nom | 3 +- nomnom/code_obj.nom | 269 +++++++++++++++++----------------------- nomnom/compile.nom | 49 ++++---- nomnom/decompile.nom | 39 +++--- nomnom/parser.nom | 2 +- nomsu.moon | 1 + nomsu_compiler.lua | 35 +++--- nomsu_compiler.moon | 32 ++--- string2.lua | 17 +-- string2.moon | 15 +-- syntax_tree.lua | 5 +- syntax_tree.moon | 4 +- tools/find_action.nom | 7 +- 28 files changed, 364 insertions(+), 386 deletions(-) diff --git a/code_obj.lua b/code_obj.lua index a8d7adf..b5213c9 100644 --- a/code_obj.lua +++ b/code_obj.lua @@ -78,7 +78,7 @@ do local _class_0 local _base_0 = { is_code = true, - as_smext = function(self) + text = function(self) if self.__str == nil then local buff, indent = { }, 0 local match, gsub, rep @@ -95,7 +95,7 @@ do end end else - b = b:as_smext() + b = b:text() if indent > 0 then b = gsub(b, "\n", "\n" .. rep(" ", indent)) end @@ -107,7 +107,7 @@ do return self.__str end, __tostring = function(self) - return self:as_smext() + return self:text() end, as_lua = function(self) return tostring(self.__class.__name) .. "(" .. tostring(concat({ @@ -126,13 +126,13 @@ do }, ", ")) .. ")" end, __len = function(self) - return #self:as_smext() + return #self:text() end, match = function(self, ...) - return self:as_smext():match(...) + return self:text():match(...) end, gmatch = function(self, ...) - return self:as_smext():gmatch(...) + return self:text():gmatch(...) end, dirty = function(self) self.__str = nil @@ -169,7 +169,7 @@ do end, trailing_line_len = function(self) if self._trailing_line_len == nil then - self._trailing_line_len = #self:as_smext():match("[^\n]*$") + self._trailing_line_len = #self:text():match("[^\n]*$") end return self._trailing_line_len end, @@ -213,7 +213,7 @@ do b.dirty = error end if not (type(b) == 'string') then - b = b:as_smext() + b = b:text() end local line = match(b, "\n([^\n]*)$") if line then @@ -400,7 +400,7 @@ do end else walk(b, pos) - b = b:as_smext() + b = b:text() end pos = pos + #b end @@ -502,12 +502,7 @@ do end NomsuCode = _class_0 end -Code.__base.append_1 = assert(Code.__base.append) -Code.__base.append_1_joined_by_2 = assert(Code.__base.concat_append) -Code.__base.prepend_1 = assert(Code.__base.prepend) -LuaCode.__base.declare_locals_1 = assert(LuaCode.__base.declare_locals) -LuaCode.__base.remove_free_vars_1 = assert(LuaCode.__base.remove_free_vars) -LuaCode.__base.add_free_vars_1 = assert(LuaCode.__base.add_free_vars) +Code.__base.add_1_joined_with = assert(Code.__base.concat_append) return { Code = Code, NomsuCode = NomsuCode, diff --git a/code_obj.moon b/code_obj.moon index 3e43b16..22969a4 100644 --- a/code_obj.moon +++ b/code_obj.moon @@ -50,7 +50,7 @@ class Code --assert(@source and Source\is_instance(@source), "Source has the wrong type") @append(...) - as_smext: => + text: => if @__str == nil buff, indent = {}, 0 {:match, :gsub, :rep} = string @@ -59,23 +59,23 @@ class Code if spaces = match(b, "\n([ ]*)[^\n]*$") indent = #spaces else - b = b\as_smext! + b = b\text! if indent > 0 b = gsub(b, "\n", "\n"..rep(" ", indent)) buff[#buff+1] = b @__str = concat(buff, "") return @__str - __tostring: => @as_smext! + __tostring: => @text! as_lua: => "#{@__class.__name}(#{concat {tostring(@source)\as_lua!, unpack([b\as_lua! for b in *@bits])}, ", "})" - __len: => #@as_smext! + __len: => #@text! - match: (...)=> @as_smext!\match(...) + match: (...)=> @text!\match(...) - gmatch: (...)=> @as_smext!\gmatch(...) + gmatch: (...)=> @text!\gmatch(...) dirty: => @__str = nil @@ -100,7 +100,7 @@ class Code trailing_line_len: => if @_trailing_line_len == nil - @_trailing_line_len = #@as_smext!\match("[^\n]*$") + @_trailing_line_len = #@text!\match("[^\n]*$") return @_trailing_line_len is_multiline: => @@ -133,7 +133,7 @@ class Code bits[#bits+1] = b b.dirty = error if b.is_code unless type(b) == 'string' - b = b\as_smext! + b = b\text! line = match(b, "\n([^\n]*)$") if line line_len = #line @@ -240,7 +240,7 @@ class LuaCode extends Code nomsu_to_lua[lua.source.start] = pos else walk b, pos - b = b\as_smext! + b = b\text! pos += #b walk self, 1 return { @@ -259,11 +259,6 @@ class NomsuCode extends Code as_lua: Code.as_lua __len: Code.__len -Code.__base.append_1 = assert Code.__base.append -Code.__base.append_1_joined_by_2 = assert Code.__base.concat_append -Code.__base.prepend_1 = assert Code.__base.prepend -LuaCode.__base.declare_locals_1 = assert LuaCode.__base.declare_locals -LuaCode.__base.remove_free_vars_1 = assert LuaCode.__base.remove_free_vars -LuaCode.__base.add_free_vars_1 = assert LuaCode.__base.add_free_vars +Code.__base.add_1_joined_with = assert Code.__base.concat_append return {:Code, :NomsuCode, :LuaCode, :Source} diff --git a/compatibility/4.8.10.nom b/compatibility/4.8.10.nom index d20448e..66152b5 100644 --- a/compatibility/4.8.10.nom +++ b/compatibility/4.8.10.nom @@ -57,3 +57,4 @@ upgrade action "parse 1 as 2" to "4.8.10" via (..) upgrade action (compile as %) to "4.8.10" as (what % compiles to) upgrade action (action %) to "4.8.10" as (%'s meaning) +upgrade action (remove action %) to "4.8.10" as ((%'s meaning) = (nil)) diff --git a/compatibility/compatibility.nom b/compatibility/compatibility.nom index c61b5a9..1153ab4 100644 --- a/compatibility/compatibility.nom +++ b/compatibility/compatibility.nom @@ -52,7 +52,7 @@ externally (upgrade action %stub to %version via %upgrade_fn) means: %retval = (make tree %body) %lua::append (..) Lua "\ - ..upgrade_action_1_to_2_via_3(\(quote %action.stub), \(%version as lua expr), function(\(..) + ..upgrade_action_1_to_2_via(\(quote %action.stub), \(%version as lua expr), function(\(..) \%tree as lua id ..) return \%retval diff --git a/containers.lua b/containers.lua index 8ab6c80..3148dcf 100644 --- a/containers.lua +++ b/containers.lua @@ -134,15 +134,15 @@ local _list_mt = { return ret end, __index = { - add_1 = insert, - append_1 = insert, - add_1_at_index_2 = function(t, x, i) + add = insert, + append = insert, + add_1_at_index = function(t, x, i) return insert(t, i, x) end, - at_index_1_add_2 = insert, + at_index_1_add = insert, pop = remove, remove_last = remove, - remove_index_1 = remove, + remove_index = remove, last = (function(self) return self[#self] end), @@ -165,7 +165,7 @@ local _list_mt = { return _accum_0 end)()) end, - joined_with_1 = function(self, glue) + joined_with = function(self, glue) return table.concat((function() local _accum_0 = { } local _len_0 = 1 @@ -177,7 +177,7 @@ local _list_mt = { return _accum_0 end)(), glue) end, - has_1 = function(self, item) + has = function(self, item) for _index_0 = 1, #self do local x = self[_index_0] if x == item then @@ -186,14 +186,14 @@ local _list_mt = { end return false end, - remove_1 = function(self, item) + remove = function(self, item) for i, x in ipairs(self) do if x == item then remove(self, i) end end end, - index_of_1 = function(self, item) + index_of = function(self, item) for i, x in ipairs(self) do if x == item then return i @@ -201,7 +201,7 @@ local _list_mt = { end return nil end, - from_1_to_2 = function(self, start, stop) + from_1_to = function(self, start, stop) local n = #self if n < 0 then start = (n + 1 - start) @@ -383,20 +383,20 @@ do local lines, line, line_at, as_lua_id, is_lua_id lines, line, line_at, as_lua_id, is_lua_id = string2.lines, string2.line, string2.line_at, string2.as_lua_id, string2.is_lua_id local text_methods = { - formatted_with_1 = format, - byte_1 = byte, - position_of_1 = find, - position_of_1_after_2 = find, + formatted_with = format, + byte = byte, + position_of = find, + position_of_1_after = find, as_a_lua_identifier = as_lua_id, is_a_lua_identifier = is_lua_id, as_a_lua_id = as_lua_id, is_a_lua_id = is_lua_id, - bytes_1_to_2 = function(self, start, stop) + bytes_1_to = function(self, start, stop) return List({ byte(tostring(self), start, stop) }) end, - [as_lua_id("with 1 -> 2")] = gsub, + [as_lua_id("with 1 ->")] = gsub, bytes = function(self) return List({ byte(tostring(self), 1, -1) @@ -405,8 +405,8 @@ do lines = function(self) return List(lines(self)) end, - line_1 = line, - wrapped_to_1 = function(self, maxlen) + line = line, + wrapped_to = function(self, maxlen) local _lines = { } local _list_0 = self:lines() for _index_0 = 1, #_list_0 do @@ -422,22 +422,22 @@ do end return table.concat(_lines, "\n") end, - line_at_1 = function(self, i) + line_at = function(self, i) return (line_at(self, i)) end, - line_number_at_1 = function(self, i) + line_number_at = function(self, i) return select(2, line_at(self, i)) end, - line_position_at_1 = function(self, i) + line_position_at = function(self, i) return select(3, line_at(self, i)) end, - matches_1 = function(self, patt) + matches = function(self, patt) return match(self, patt) and true or false end, - matching_1 = function(self, patt) + matching = function(self, patt) return (match(self, patt)) end, - matching_groups_1 = function(self, patt) + matching_groups = function(self, patt) return { match(self, patt) } @@ -445,7 +445,7 @@ do [as_lua_id("* 1")] = function(self, n) return rep(self, n) end, - all_matches_of_1 = function(self, patt) + all_matches_of = function(self, patt) local result = { } local stepper, x, i = gmatch(self, patt) while true do diff --git a/containers.moon b/containers.moon index 30dcfc8..4671f6b 100644 --- a/containers.moon +++ b/containers.moon @@ -58,31 +58,31 @@ _list_mt = insert(ret, x) return ret __index: - add_1: insert, append_1: insert - add_1_at_index_2: (t,x,i)-> insert(t,i,x) - at_index_1_add_2: insert - pop: remove, remove_last: remove, remove_index_1: remove + add: insert, append: insert + add_1_at_index: (t,x,i)-> insert(t,i,x) + at_index_1_add: insert + pop: remove, remove_last: remove, remove_index: remove last: (=> @[#@]), first: (=> @[1]) _1_st_to_last:nth_to_last, _1_nd_to_last:nth_to_last _1_rd_to_last:nth_to_last, _1_th_to_last:nth_to_last -- TODO: use stringify() to allow joining misc. objects? joined: => table.concat([tostring(x) for x in *@]), - joined_with_1: (glue)=> table.concat([tostring(x) for x in *@], glue), - has_1: (item)=> + joined_with: (glue)=> table.concat([tostring(x) for x in *@], glue), + has: (item)=> for x in *@ if x == item return true return false - remove_1: (item)=> + remove: (item)=> for i,x in ipairs @ if x == item remove(@, i) - index_of_1: (item)=> + index_of: (item)=> for i,x in ipairs @ if x == item return i return nil - from_1_to_2: (start, stop)=> + from_1_to: (start, stop)=> n = #@ start = (n+1-start) if n < 0 stop = (n+1-stop) if n < 0 @@ -149,15 +149,15 @@ do string2 = require 'string2' {:lines, :line, :line_at, :as_lua_id, :is_lua_id} = string2 text_methods = - formatted_with_1:format, byte_1:byte, position_of_1:find, position_of_1_after_2:find, + formatted_with:format, byte:byte, position_of:find, position_of_1_after:find, as_a_lua_identifier: as_lua_id, is_a_lua_identifier: is_lua_id, as_a_lua_id: as_lua_id, is_a_lua_id: is_lua_id, - bytes_1_to_2: (start, stop)=> List{byte(tostring(@), start, stop)} - [as_lua_id "with 1 -> 2"]: gsub + bytes_1_to: (start, stop)=> List{byte(tostring(@), start, stop)} + [as_lua_id "with 1 ->"]: gsub bytes: => List{byte(tostring(@), 1, -1)}, lines: => List(lines(@)) - line_1: line - wrapped_to_1: (maxlen)=> + line: line + wrapped_to: (maxlen)=> _lines = {} for line in *@lines! while #line > maxlen @@ -169,14 +169,14 @@ do _lines[#_lines+1] = line return table.concat(_lines, "\n") - line_at_1: (i)=> (line_at(@, i)) - line_number_at_1: (i)=> select(2, line_at(@, i)) - line_position_at_1: (i)=> select(3, line_at(@, i)) - matches_1: (patt)=> match(@, patt) and true or false - matching_1: (patt)=> (match(@, patt)) - matching_groups_1: (patt)=> {match(@, patt)} + line_at: (i)=> (line_at(@, i)) + line_number_at: (i)=> select(2, line_at(@, i)) + line_position_at: (i)=> select(3, line_at(@, i)) + matches: (patt)=> match(@, patt) and true or false + matching: (patt)=> (match(@, patt)) + matching_groups: (patt)=> {match(@, patt)} [as_lua_id "* 1"]: (n)=> rep(@, n) - all_matches_of_1: (patt)=> + all_matches_of: (patt)=> result = {} stepper,x,i = gmatch(@, patt) while true diff --git a/core/control_flow.nom b/core/control_flow.nom index 0cabf95..bbc98f1 100644 --- a/core/control_flow.nom +++ b/core/control_flow.nom @@ -102,8 +102,20 @@ test: .." # Basic loop control -(do next) compiles to (Lua "goto continue") -(stop) compiles to (Lua "break") +(stop %var) compiles to: + if %var: + return (..) + Lua "goto stop_\((%var.stub if (%var.type == "action") else %var) as lua identifier)" + ..else: return (Lua "break") +(do next %var) compiles to: + if %var: + return (..) + Lua "goto continue_\((%var.stub if (%var.type == "action") else %var) as lua identifier)" + ..else: return (Lua "goto continue") +[===stop %var ===, ---stop %var ---, ***stop %var ***] all compile to (..) + Lua "::stop_\((%var.stub if (%var.type == "action") else %var) as lua identifier)::" +[===next %var ===, ---next %var ---, ***next %var ***] all compile to (..) + Lua "::continue_\((%var.stub if (%var.type == "action") else %var) as lua identifier)::" # While loops test: @@ -177,16 +189,6 @@ test: return %lua -# For loop control flow -(stop %var) compiles to (..) - Lua "goto stop_\((%var.stub if (%var.type == "Action") else %var) as lua identifier)" -(do next %var) compiles to (..) - Lua "goto continue_\((%var.stub if (%var.type == "Action") else %var) as lua identifier)" -[===stop %var ===, ---stop %var ---, ***stop %var ***] all compile to (..) - Lua "::stop_\((%var.stub if (%var.type == "Action") else %var) as lua identifier)::" -[===next %var ===, ---next %var ---, ***next %var ***] all compile to (..) - Lua "::continue_\((%var.stub if (%var.type == "Action") else %var) as lua identifier)::" - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ test: @@ -365,7 +367,7 @@ test: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ test: - if: + when: (1 == 2) (100 < 0): barf "bad conditional" (1 == 0) (1 == 1) %not_a_variable.x: do nothing @@ -377,7 +379,7 @@ test: barf "bad conditional" # Multi-branch conditional (if..elseif..else) -[if %body, when %body] all compile to: +(when %body) compiles to: %code = (Lua "") %clause = "if" %else_allowed = (yes) @@ -512,8 +514,6 @@ test: %d.x = "bad" barf ..then always: %d.x = "good" - ..and if it barfs: do nothing - assume (%d.x == "good") (do %action then always %final_action) compiles to: define mangler diff --git a/core/errors.nom b/core/errors.nom index 70dea0c..0b0a6a3 100644 --- a/core/errors.nom +++ b/core/errors.nom @@ -4,8 +4,7 @@ use "core/metaprogramming.nom" -(barf) compiles to (Lua "error(nil, 0);") -(barf %msg) compiles to (Lua "error(\(%msg as lua expr), 0);") +(barf %msg) compiles to (Lua "error(\(=lua "\%msg and \(%msg as lua expr) or 'nil'"), 0);") (compile error at %tree %msg) compiles to (..) Lua "nomsu:compile_error(\(%tree as lua expr), \(%msg as lua expr))" (compile error at %tree %msg hint %hint) compiles to (..) @@ -66,9 +65,9 @@ test: local ok, ret = xpcall(function() \(%action as lua statements) fell_through = true - end, function(\(%msg as lua expr)) + end, function(\(=lua "\%fallback and \(%msg as lua expr) or ''")) local ok, ret = pcall(function() - \(%fallback as lua statements) + \((=lua "\%fallback or \%msg") as lua statements) end) if not ok then err, erred = ret, true end end) @@ -84,18 +83,19 @@ test: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -[..] - try %action and if it succeeds %success or if it barfs %fallback - try %action and if it barfs %fallback or if it succeeds %success -..all parse as (..) - try %action and if it succeeds %success or if it barfs (=lua "") %fallback +# + [..] + try %action and if it succeeds %success or if it barfs %fallback + try %action and if it barfs %fallback or if it succeeds %success + ..all parse as (..) + try %action and if it succeeds %success or if it barfs (=lua "") %fallback -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (try %action) parses as (..) try %action and if it succeeds (do nothing) or if it barfs (do nothing) -(try %action and if it barfs %fallback) parses as (..) +#(try %action and if it barfs %fallback) parses as (..) try %action and if it succeeds (do nothing) or if it barfs %fallback (try %action and if it barfs %msg %fallback) parses as (..) diff --git a/core/math.nom b/core/math.nom index 538b068..66f5aba 100644 --- a/core/math.nom +++ b/core/math.nom @@ -80,21 +80,21 @@ externally (%n to the nearest %rounder) means (..) [all of %items, all %items] all compile to: unless (%items.type is "List"): return (Lua value "utils.all(\(%items as lua expr))") - %clauses = (((% as lua expr)::as smext) for % in %items) + %clauses = (((% as lua expr)::text) for % in %items) return (Lua value "(\(%clauses::joined with " and "))") [not all of %items, not all %items] all parse as (not (all of %items)) [any of %items, any %items] all compile to: unless (%items.type is "List"): return (Lua value "utils.any(\(%items as lua expr))") - %clauses = (((% as lua expr)::as smext) for % in %items) + %clauses = (((% as lua expr)::text) for % in %items) return (Lua value "(\(%clauses::joined with " or "))") [none of %items, none %items] all parse as (not (any of %items)) [sum of %items, sum %items] all compile to: unless (%items.type is "List"): return (Lua value "utils.sum(\(%items as lua expr))") - %clauses = (((% as lua expr)::as smext) for % in %items) + %clauses = (((% as lua expr)::text) for % in %items) return (Lua value "(\(%clauses::joined with " + "))") [if all of %items %body, if all of %items then %body] all parse as (..) @@ -139,7 +139,7 @@ externally (%n to the nearest %rounder) means (..) [product of %items, product %items] all compile to: unless (%items.type is "List"): return (Lua value "utils.product(\(%items as lua expr))") - %clauses = (((% as lua expr)::as smext) for % in %items) + %clauses = (((% as lua expr)::text) for % in %items) return (Lua value "(\(%clauses::joined with " * "))") externally [avg of %items, average of %items] all mean (..) diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom index dbc45a4..61c877f 100644 --- a/core/metaprogramming.nom +++ b/core/metaprogramming.nom @@ -3,7 +3,7 @@ This File contains actions for making actions and compile-time actions and some helper functions to make that easier. -lua> "NOMSU_CORE_VERSION = 8" +lua> "NOMSU_CORE_VERSION = 9" lua> "\ ..do local mangle_index = 0 @@ -16,14 +16,14 @@ lua> "\ end end COMPILE_ACTIONS["define mangler"] = function(nomsu, tree) - return LuaCode(tree.source, "local mangle_1 = mangler()") + return LuaCode(tree.source, "local mangle = mangler()") end" lua> "\ - ..COMPILE_ACTIONS["1 -> 2"] = function(nomsu, tree, \%args, \%body) + ..COMPILE_ACTIONS["1 ->"] = function(nomsu, tree, \%args, \%body) local lua = LuaCode.Value(tree.source, "(function(") if SyntaxTree:is_instance(\%args) and \%args.type == "Action" then \%args = \%args:get_args() end - local lua_args = table.map(\%args, function(a) return SyntaxTree:is_instance(a) and nomsu:compile(a):as_smext() or a end) + local lua_args = table.map(\%args, function(a) return SyntaxTree:is_instance(a) and nomsu:compile(a):text() or a end) lua:concat_append(lua_args, ", ") local body_lua = SyntaxTree:is_instance(\%body) and nomsu:compile(\%body):as_statements("return ") or \%body body_lua:remove_free_vars(lua_args) @@ -63,15 +63,15 @@ test: asdf assume (%tmp is (nil)) or barf "compile to is leaking variables" lua> "\ - ..COMPILE_ACTIONS["1 compiles to 2"] = function(nomsu, tree, \%actions, \%body) + ..COMPILE_ACTIONS["1 compiles to"] = function(nomsu, tree, \%actions, \%body) if \%actions.type ~= "List" then \%actions = {\%actions, type="List"} end - local \%args = {"nomsu", "tree", unpack(table.map(\%actions[1]:get_args(), function(a) return nomsu:compile(a):as_smext() end))} + local \%args = {"nomsu", "tree", unpack(table.map(\%actions[1]:get_args(), function(a) return nomsu:compile(a):text() end))} local lua = LuaCode(tree.source, "COMPILE_ACTIONS[", \%actions[1].stub:as_lua(), "] = ", \(what (%args -> %body) compiles to)) for i=2,#\%actions do local alias = \%actions[i] - local \%alias_args = {"nomsu", "tree", unpack(table.map(alias:get_args(), function(a) return nomsu:compile(a):as_\ - ..smext() end))} + local \%alias_args = {"nomsu", "tree", unpack(table.map(alias:get_args(), function(a) return nomsu:compile(a):text() \ + ..end))} lua:append("\\nCOMPILE_ACTIONS[", alias.stub:as_lua(), "] = ") if utils.equivalent(\%args, \%alias_args) then lua:append("COMPILE_ACTIONS[", \%actions[1].stub:as_lua(), "]") @@ -85,7 +85,7 @@ lua> "\ end return lua end - COMPILE_ACTIONS["1 all compile to 2"] = COMPILE_ACTIONS["1 compiles to 2"]" + COMPILE_ACTIONS["1 all compile to"] = COMPILE_ACTIONS["1 compiles to"]" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -116,14 +116,14 @@ test: lua> "\ ..if \%actions.type ~= "List" then \%actions = {\%actions, type="List"} end local fn_name = \%actions[1].stub:as_lua_id() - local \%args = table.map(\%actions[1]:get_args(), function(a) return nomsu:compile(a):as_smext() end) + local \%args = table.map(\%actions[1]:get_args(), function(a) return nomsu:compile(a):text() end) local lua = LuaCode(tree.source, fn_name, " = ", \(what (%args -> %body) compiles to)) lua:add_free_vars({fn_name}) for i=2,#\%actions do local alias = \%actions[i] local alias_name = alias.stub:as_lua_id() lua:add_free_vars({alias_name}) - local \%alias_args = table.map(alias:get_args(), function(a) return nomsu:compile(a):as_smext() end) + local \%alias_args = table.map(alias:get_args(), function(a) return nomsu:compile(a):text() end) lua:append("\\n", alias_name, " = ") if utils.equivalent(\%args, \%alias_args) then lua:append(fn_name) @@ -151,7 +151,7 @@ test: return lua" test: - assume (((say %)'s meaning) == (=lua "say_1")) + assume (((say %)'s meaning) == (=lua "say")) (%action's meaning) compiles to (Lua value (%action.stub as lua id)) test: @@ -174,7 +174,7 @@ test: ..local replacements = {} if \%actions.type ~= "List" then \%actions = {\%actions, type="List"} end for i,arg in ipairs(\%actions[1]:get_args()) do - replacements[arg[1]] = nomsu:compile(arg):as_smext() + replacements[arg[1]] = nomsu:compile(arg):text() end local function make_tree(t) if SyntaxTree:is_instance(t) and t.type == "Var" then @@ -192,14 +192,14 @@ test: i = i + 1 elseif k == "source" then ret[#ret+1] = k.."= "..tostring(v):as_lua() - elseif lua_type_of_1(k) == 'string' and k:match("[_a-zA-Z][_a-zA-Z0-9]*") then + elseif lua_type_of(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 "SyntaxTree{"..table.concat(ret, ", ").."}" - elseif lua_type_of_1(t) == 'number' then + elseif lua_type_of(t) == 'number' then return tostring(t) else return t:as_lua() @@ -226,9 +226,6 @@ test: (%tree as lua return) compiles to (..) Lua value "nomsu:compile(\(%tree as lua expr)):as_statements('return ')" -(remove action %action) compiles to (..) - Lua "\(=lua "(\(%action.stub)):as_lua_id()") = nil" - test: assume ("\(\(foo \%x) as nomsu)" == "foo %x") or barf "\ ..action source code failed." @@ -240,11 +237,11 @@ test: externally [%var as lua identifier, %var as lua id] all mean: lua> "\ - ..if lua_type_of_1(\%var) == 'string' then return \%var:as_lua_id() + ..if lua_type_of(\%var) == 'string' then return \%var:as_lua_id() elseif SyntaxTree:is_instance(\%var, 'Var') then return \%var[1]:as_lua_id() elseif SyntaxTree:is_instance(\%var) then local lua = \(%var as lua expr) - if not lua:as_smext():match("^[_a-zA-Z][_a-zA-Z0-9]*$") then + if not lua:text():match("^[_a-zA-Z][_a-zA-Z0-9]*$") then nomsu:compile_error(\%var, "This is not a valid Lua identifier.") end return lua diff --git a/core/operators.nom b/core/operators.nom index bd93cd5..6d574b7 100644 --- a/core/operators.nom +++ b/core/operators.nom @@ -34,7 +34,7 @@ test: lua> "\ ..local lua = LuaCode(tree.source, \%var_lua, ' = ', \%value_lua, ';') if \%var.type == 'Var' then - lua:add_free_vars({nomsu:compile(\%var):as_smext()}) + lua:add_free_vars({nomsu:compile(\%var):text()}) end return lua" @@ -66,7 +66,7 @@ test: %value as text ..) end if \%target.type == "Var" then - lhs:add_free_vars({target_lua:as_smext()}) + lhs:add_free_vars({target_lua:text()}) end if i > 1 then lhs:append(", ") @@ -107,7 +107,7 @@ test: (with external %externs %body) compiles to: %body_lua = (%body as lua statements) lua> "\ - ..\%body_lua:remove_free_vars(table.map(\%externs, function(v) return nomsu:compile(v):as_smext() end))" + ..\%body_lua:remove_free_vars(table.map(\%externs, function(v) return nomsu:compile(v):text() end))" return %body_lua test: @@ -141,7 +141,7 @@ test: lhs:append(target_lua) rhs:append(value_lua) if \%target.type == "Var" then - vars[i] = target_lua:as_smext() + vars[i] = target_lua:text() end end \%lua:remove_free_vars(vars) diff --git a/files.lua b/files.lua index 48e047f..13679e3 100644 --- a/files.lua +++ b/files.lua @@ -181,6 +181,8 @@ Files.walk = function(path, flush_cache) files = { path } + elseif path:match("^[~/]") or path:match("^%./") or path:match("^%.%./") then + files = browse(path) else for nomsupath in package.nomsupath:gmatch("[^;]+") do do diff --git a/files.moon b/files.moon index e0fe02b..738c5f8 100644 --- a/files.moon +++ b/files.moon @@ -104,6 +104,8 @@ Files.walk = (path, flush_cache=false)-> local files if path == 'stdin' or _SPOOFED_FILES[path] files = {path} + elseif path\match("^[~/]") or path\match("^%./") or path\match("^%.%./") + files = browse(path) else for nomsupath in package.nomsupath\gmatch("[^;]+") if files = browse(nomsupath.."/"..path) then break diff --git a/lib/consolecolor.nom b/lib/consolecolor.nom index e0e032d..fe7da4c 100644 --- a/lib/consolecolor.nom +++ b/lib/consolecolor.nom @@ -14,8 +14,10 @@ test: for %name = %colornum in %colors: %colornum = "\%colornum" - (=lua "COMPILE_ACTIONS").%name = (..) + #(=lua "COMPILE_ACTIONS").%name = (..) [%nomsu, %tree] -> (Lua value "'\\027[\(%colornum)m'") - (=lua "COMPILE_ACTIONS")."\%name 1" = (..) - [%nomsu, %tree, %text] -> (..) - Lua value "('\\027[\(%colornum)m'..\(%text as lua expr)..'\\027[0m')" + (=lua "COMPILE_ACTIONS")."\%name" = (..) + [%nomsu, %tree, %text] ->: + if %text: + return (Lua value "('\\027[\(%colornum)m'..\(%text as lua expr)..'\\027[0m')") + ..else: return (Lua value "'\\027[\(%colornum)m'") diff --git a/lib/object.nom b/lib/object.nom index 4f45188..d5555df 100644 --- a/lib/object.nom +++ b/lib/object.nom @@ -93,13 +93,13 @@ test: __index=\(%parent as lua expr), __tostring=function(cls) return cls.name end, __call=function(cls, inst) - inst = setmetatable(inst or {}, cls) + if inst == nil then return cls end + inst = setmetatable(inst, cls) if inst.set_up then inst:set_up() end return inst end, }) - nomsu.environment[(class.name.." 1"):as_lua_id()] = class - nomsu.environment[class.name:as_lua_id()] = function() return class end + nomsu.environment[class.name:as_lua_id()] = class class.__index = class class.class = class class.__tostring = function(inst) diff --git a/nomnom/ast.nom b/nomnom/ast.nom index 4d261aa..ef41b26 100644 --- a/nomnom/ast.nom +++ b/nomnom/ast.nom @@ -32,7 +32,7 @@ object (Syntax Tree): return %children my action [as lua] "\ - ..a_Syntax_Tree_with_1(\(call ({} 's metatable).as_lua with [%me]))" + ..a_Syntax_Tree_with(\(call ({} 's metatable).as_lua with [%me]))" my action [as nomsu] "\ ..(a Syntax Tree with \(call ({} 's metatable).as_nomsu with [%me]))" my action [as text] "\ @@ -86,4 +86,3 @@ object (Syntax Tree): unless ((% is text) or (%.type == "Comment")): %args::add % return %args -(Syntax Tree).map = (Syntax Tree).map_1 diff --git a/nomnom/code_obj.nom b/nomnom/code_obj.nom index 8379f36..c8d2784 100644 --- a/nomnom/code_obj.nom +++ b/nomnom/code_obj.nom @@ -2,103 +2,89 @@ # This file contains objects that are used to track code positions and incrementally build up generated code, while keeping track of where it came from, and managing indentation levels. -use "lib/object.nom" +use "lib/things.nom" -object (Hole): - externally (Hole from %lua) means: - return (Hole {lua:%lua}) - my action [as lua]: return %me.lua - my action [as nomsu]: - return "(Hole {lua:\(%me.lua)})" - my action [as text]: - barf "Not implemented" - my action [as smext]: - barf "Must fill in holes before smexting" +a (Code Buffer) is a thing: + that can (set up) by: + assume %its.source + %old_bits = (%its.bits if (%its.bits is a "List") else [%its.bits]) + %its.bits = [] + if (type of %its.source) is: + "Text": + %its.source = (Source from text %its.source) + "Syntax Tree": + %its.source = %its.source.source -object (Code): - my action [set up]: - assume %me.source - %old_bits = (%me.bits if (%me.bits is a "List") else [%me.bits]) - %me.bits = [] - if (%me.source is text): - %me.source = (Source from text %me.source) - for % in %old_bits: %me::add % - - my action [as text]: - barf "Not implemented" - my action [as smext]: - if (%me.__str == (nil)): - set {%buff:[], %indent:0} - for %bit in %me.bits: + for % in %old_bits: %its::add % + + whose (text) means: + if (%its._text == (nil)): + %buff = [] + %indent = 0 + for %bit in %its.bits: if (%bit is text): %spaces = (%bit::matching "\n([ ]*)[^\n]*$") if %spaces: %indent = (size of %spaces.1) ..else: - %bit = (%bit::as smext) + %bit = (%bit::text) if (%indent > 0): %bit = (%bit::with "\n" -> "\n\(" "::* %indent)") - %buff::add %bit - - %me.__str = (%buff::joined) - - return %me.__str - - my action [as lua]: - barf - return "\ - ..\(%me.class.name::as lua id)_from_1_2(\(..) - (%me.source::as lua) if %me.source else "nil" - .., \(%me.bits::as lua))" - - my action [as nomsu] "\ - ..(\(%me.class.name) \((%me.source::as nomsu) if %me.source else "(nil)") \(..) - %me.bits::as nomsu - ..)" - - my action [size] (size of (%me::as smext)) - my action [mark as dirty]: - %me.__str = (nil) - %me._trailing_line_len = (nil) - %me._num_lines = (nil) - - my action [add %new_bits]: + %its._text = (%buff::joined) + return %its._text + + whose (lua code) means "\ + ..a_\(%its.class.name::as lua id)_with{source=\(..) + (%its.source::as lua) if %its.source else "nil" + .., \(%its.bits::as lua)}" + + whose (nomsu code) means "\ + ..(a \(%its.class.name) with {source: \((%its.source::as nomsu) if %its.source else "(nil)"), bits: \(..) + %its.bits::as nomsu + ..})" + + whose (size) means (size of (%its::text)) + + that can (mark as dirty) by: + %its._text = (nil) + %its._trailing_line_len = (nil) + %its._num_lines = (nil) + + that can (add %new_bits) by: unless (%new_bits is a "List"): %new_bits = [%new_bits] for % in %new_bits: if (% == ""): do next % - #if ((% isn't text) and (% isn't a (Code))): % = (%::as lua) - %me.bits::add % - - %me::mark as dirty + %its.bits::add % + %its::mark as dirty - my action [trailing line length]: - if (%me._trailing_line_len == (nil)): - %me._trailing_line_len = (size of ((%me::as smext)::matching "[^\n]*$")) - return %me._trailing_line_len + whose (trailing line length) means: + if (%its._trailing_line_len == (nil)): + %its._trailing_line_len = (size of ((%its::text)::matching "[^\n]*$")) + return %its._trailing_line_len - my action [number of lines]: - unless %me._num_lines: + whose (number of lines) means: + unless %its._num_lines: %num_lines = 1 - for % in %me: + for % in %its: if (% is text): %num_lines += (size of (%::all matches of "\n")) ..else: %num_lines += ((%::number of lines) - 1) - %me._num_lines = %num_lines + %its._num_lines = %num_lines - return %me._num_lines + return %its._num_lines - my action [is multiline, is multi-line] ((%me::number of lines) > 1) - my action [is one line, is single line] ((%me::number of lines) == 1) - my action [add %values joined with %joiner]: - %me::add %values joined with %joiner or %joiner - my action [add %values joined with %joiner or %wrapping_joiner]: + whose [is multiline, is multi-line] all mean ((%its::number of lines) > 1) + whose [is one line, is single line] all mean ((%its::number of lines) == 1) + that can (add %values joined with %joiner) by: + %its::add %values joined with %joiner or %joiner + that can [add %values joined with %joiner or %wrapping_joiner] by: %line_len = 0 - %bits = %me.bits + %bits = %its.bits for %value in %values at %i: if (%i > 1): if (%line_len > 80): @@ -108,65 +94,71 @@ object (Code): %bits::add %value unless (%value is text): - %value = (%value::as smext) + %value = (%value::text) %line = (%value::matching "\n([^\n]*)$") if %line: %line_len = (size of %line) ..else: %line_len += (size of %value) - - %me::mark as dirty + %its::mark as dirty - my action [prepend %]: - #if ((% isn't text) and (% isn't a %me.__type)): + that can (prepend %) by: + #if ((% isn't text) and (% isn't a %its.__type)): % = (%::as lua) - %me.bits::add % at index 1 - %me::mark as dirty + %its.bits::add % at index 1 + %its::mark as dirty - my action [parenthesize]: - %me.bits::add "(" at index 1 - %me.bits::add ")" - %me::mark as dirty + that can (parenthesize) by: + %its.bits::add "(" at index 1 + %its.bits::add ")" + %its::mark as dirty -object (Lua Code) extends (Code): - my action [add free vars %vars]: +a (Lua Buffer) is a thing: + that has [..] + text, lua code, nomsu code, trailing line length, size, number of lines, + is multiline, is multi-line, is one line, is single line, + ..like a (Code Buffer) + that can [..] + set up, mark as dirty, add %, prepend %, parenthesize, + add % joined with %, add % joined with % or %, + ..like a (Code Buffer) + + that can (add free vars %vars) by: if ((size of %vars) == 0): return - %seen = (%v = (yes) for %v in %me.free_vars) + %seen = (%v = (yes) for %v in %its.free_vars) for %var in %vars: assume (%var is text) unless %seen.%var: - %me.free_vars::add %var + %its.free_vars::add %var %seen.%var = (yes) - %me::mark as dirty + %its::mark as dirty - my action [remove free vars %vars]: + that can (remove free vars %vars) by: if ((size of %vars) == 0): return %removals = {} for %var in %vars: assume (%var is text) %removals.%var = (yes) - %stack = [%me] + %stack = [%its] repeat while ((size of %stack) > 0): %lua = (%stack::pop) for %i in (size of %lua.free_vars) to 1 by -1: if %removals.(%lua.free_vars.%i): - lua> "table.remove(\%lua.free_vars, \%i)" - #TODO: reinstate this - #%lua.free_vars::remove at index %i - + %lua.free_vars::remove at index %i for % in %lua.bits: unless (% is text): %stack::add % - %me::mark as dirty + %its::mark as dirty - my action [declare locals] (%me::declare locals (nil)) - my action [declare locals %to_declare]: + that can (declare locals) by (%its::declare locals (nil)) + that can (declare locals %to_declare) by: unless %to_declare: - set {%to_declare:[], %seen:{}} - for %lua in recursive %me: + %to_declare = [] + %seen = {} + for %lua in recursive %its: for %var in %lua.free_vars: unless %seen.%var: %seen.%var = (yes) @@ -176,70 +168,43 @@ object (Lua Code) extends (Code): unless (% is text): recurse %lua on % if ((size of %to_declare) > 0): - %me::remove free vars %to_declare - %me::prepend "local \(%to_declare::joined with ", ");\n" + %its::remove free vars %to_declare + %its::prepend "local \(%to_declare::joined with ", ");\n" return %to_declare - my action [as statements] (%me::as statements "" ";") - my action [as statements %prefix] (%me::as statements %prefix ";") - my action [as statements %prefix %suffix]: - unless %me.is_value: return %me - %statements = (Lua Code from %me.source []) + whose (as statements) means (%its::as statements with "") + whose (as statements with %prefix) means: + unless %its.is_value: return %its + %statements = (a Lua Buffer with {source:%its.source}) if ((%prefix or "") != ""): %statements::add %prefix - %statements::add %me - if (%suffix != ""): - %statements::add (%suffix or ";") + %statements::add %its + %statements::add ";" return %statements - my action [variables]: + that can (mark as value) by: + %its.is_value = (yes) + + that can (mark as variable) by: + %its.is_variable = (yes) + %its.is_value = (yes) + + that can (variables) by: %vars = [] - for %code in recursive %me: + for %code in recursive %its: if %code.is_variable: - %vars::add (%code::as smext) + %vars::add (%code::text) for % in %code.bits: unless (% is text): recurse %code on % return %vars - externally (Lua Code from %source %bits) means: - assume %source - unless (%bits is a "List"): %bits = [%bits] - if (%source is a "Syntax Tree"): - %source = %source.source - return (Lua Code {source:%source, bits:%bits, is_value:no, free_vars:[]}) - - externally (Lua Code from %source) means (Lua Code from %source []) - externally (Lua Value from %source %bits) means: - assume %source - unless (%bits is a "List"): %bits = [%bits] - if (%source is a "Syntax Tree"): - %source = %source.source - return (Lua Code {source:%source, bits:%bits, is_value:yes, free_vars:[]}) - - externally (Lua Value from %source) means (Lua Value from %source []) - externally (Lua Variable from %source) means (Lua Variable from %source []) - externally (Lua Variable from %source %bits) means: - assume %source - unless (%bits is a "List"): %bits = [%bits] - if (%source is a "Syntax Tree"): - %source = %source.source - return (..) - Lua Code {..} - source:%source, bits:%bits, is_value:yes, is_variable:yes, free_vars:[] - -# TODO: remove this shim -(Lua Code).add_free_vars = (Lua Code).add_free_vars_1 -(Lua Code).remove_free_vars = (Lua Code).remove_free_vars_1 -(Lua Code).declare_locals = (Lua Code).declare_locals_1 -(Lua Code).as_statements = (Lua Code).as_statements_1_2 -object (Nomsu Code) extends (Code): - externally (Nomsu Code from %source %bits) means: - if (%bits is text): %bits = [%bits] - if (%source is a "Syntax Tree"): - %source = %source.source - return (Nomsu Code {source:%source, bits:%bits}) - - externally (Nomsu Code from %source) means (Nomsu Code from %source []) - externally (Nomsu Code %bits) means (Nomsu Code from (nil) %bits) - externally (Nomsu Code) means (Nomsu Code from (nil) []) +a (Nomsu Buffer) is a thing: + that has [..] + text, lua code, nomsu code, trailing line length, size, number of lines, + is multiline, is multi-line, is one line, is single line, + ..like a (Code Buffer) + that can [..] + set up, mark as dirty, add %, prepend %, parenthesize, + add % joined with %, add % joined with % or %, + ..like a (Code Buffer) diff --git a/nomnom/compile.nom b/nomnom/compile.nom index 70f32b8..8241ef2 100644 --- a/nomnom/compile.nom +++ b/nomnom/compile.nom @@ -45,7 +45,7 @@ externally (%tree compiled with %compile_actions) means: # TODO: restore this: #%args = [%tree, %compile_actions] %args = [%nomsu, %tree] - for % in (%tree::get args): %args::add % + for % in (%tree::arguments): %args::add % %result = (call %compile_action with %args) if (%result == (nil)): report compile error at %tree "\ @@ -64,13 +64,13 @@ externally (%tree compiled with %compile_actions) means: return %result - %lua = (Lua Value from %tree) + %lua = (a Lua Buffer with {source:%tree}) if %tree.target: # Method call %target_lua = (%tree.target compiled with %compile_actions) if (..) - ((%target_lua::as smext)::matches "^%(.*%)$") or (..) - (%target_lua::as smext)::matches "^[_a-zA-Z][_a-zA-Z0-9]*$" + ((%target_lua::text)::matches "^%(.*%)$") or (..) + (%target_lua::text)::matches "^[_a-zA-Z][_a-zA-Z0-9]*$" ..: %lua::add [%target_lua, ":"] ..else: @@ -93,14 +93,14 @@ externally (%tree compiled with %compile_actions) means: if ((size of %values) == 1): %arg_lua = %values.1 ..else: - %arg_lua = (Lua Value from %tok ["("]) + %arg_lua = (a Lua Buffer with {source:%tok, is_value:yes, bits:["("]}) %arg_lua::add %values joined with " and nil or " %arg_lua::add ")" ..else: - %arg_lua = (Lua Value from %tok ["((function()"]) + %arg_lua = (a Lua Buffer with {source:%tok, is_value:yes, bits:["((function()"]}) for %v in %values at %i: if %v.is_value: - %v = (%v::as statements ("return " if (%i == (size of %values) else ""))) + %v = (%v::as statements with ("return " if (%i == (size of %values) else ""))) %arg_lua::add ["\n ", %v] %arg_lua::add "\nend)())" @@ -124,8 +124,7 @@ externally (%tree compiled with %compile_actions) means: return %lua "EscapedNomsu": - #return (Lua Value from %tree ((%tree.1)::as lua)) - %lua = (Lua Value from %tree ["a_Syntax_Tree_with_1{type=", quote %tree.(1).type]) + %lua = (a Lua Buffer with {source:%tree, is_value:yes, bits:["a_Syntax_Tree_with{type=", quote %tree.(1).type]}) set {%needs_comma:no, %i:1} (% as shmua) means: if (% is a "Lua number"): return "\%" @@ -152,7 +151,7 @@ externally (%tree compiled with %compile_actions) means: return %lua "Block": - %lua = (Lua Code from %tree) + %lua = (a Lua Buffer with {source:%tree}) %lua::add (..) ((%line compiled with %compile_actions)::as statements) for %line in %tree ..joined with "\n" @@ -160,7 +159,7 @@ externally (%tree compiled with %compile_actions) means: return %lua "Text": - %lua = (Lua Value from %tree) + %lua = (a Lua Buffer with {source:%tree}) %lua_bits = [] %string_buffer = "" for % in %tree: @@ -178,7 +177,7 @@ externally (%tree compiled with %compile_actions) means: ..Can't use this as a string interpolation value, since it doesn't have a value." if (%.type != "Text"): - %bit_lua = (Lua Value from % ["tostring(", %bit_lua, ")"]) + %bit_lua = (a Lua Buffer with {source:%, is_value:yes, bits:["tostring(", %bit_lua, ")"]}) %lua_bits::add %bit_lua if ((%string_buffer != "") or ((size of %lua_bits) == 0)): @@ -188,13 +187,13 @@ externally (%tree compiled with %compile_actions) means: return %lua "List": - %lua = (Lua Value from %tree ["List{"]) + %lua = (a Lua Buffer with {source:%tree, is_value:yes, bits:["List{"]}) %lua::add ((% compiled with %compile_actions) for % in %tree) joined with ", " or ",\n " %lua::add "}" return %lua "Dict": - %lua = (Lua Value from %tree ["Dict{"]) + %lua = (a Lua Buffer with {source:%tree, is_value:yes, bits:["Dict{"]}) %lua::add ((% compiled with %compile_actions) for % in %tree) joined with ", " or ",\n " %lua::add "}" return %lua @@ -208,24 +207,24 @@ externally (%tree compiled with %compile_actions) means: %value_lua = (..) (%value compiled with %compile_actions) if %value else (..) - Lua Value from %key ["true"] + a Lua Buffer with {source:%key, is_value:yes, bits:["true"]} unless %value_lua.is_value: report compile error at %tree.2 "\ ..Can't use this as a dict value, since it's not an expression." - %key_str = ((%key_lua::as smext)::matching "^[\"']([a-zA-Z_][a-zA-Z0-9_]*)['\"]$") + %key_str = ((%key_lua::text)::matching "^[\"']([a-zA-Z_][a-zA-Z0-9_]*)['\"]$") if: %key_str: - return (Lua Code from %tree [%key_str, "=", %value_lua]) - ((%key_lua::as smext).1 == "["): + return (a Lua Buffer with {source:%tree, bits:[%key_str, "=", %value_lua]}) + ((%key_lua::text).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 (Lua Code from %tree ["[ ", %key_lua, "]=", %value_lua]) + return (a Lua Buffer with {source:%tree, bits:["[ ", %key_lua, "]=", %value_lua]}) else: - return (Lua Code from %tree ["[", %key_lua, "]=", %value_lua]) + return (a Lua Buffer with {source:%tree, bits:["[", %key_lua, "]=", %value_lua]}) "IndexChain": %lua = (%tree.1 compiled with %compile_actions) @@ -233,7 +232,7 @@ externally (%tree compiled with %compile_actions) means: report compile error at %tree.1 "\ ..Can't index into this, since it's not an expression." - %first_char = (%lua::as smext).1 + %first_char = (%lua::text).1 if (any of [%first_char == "{", %first_char == "\"", %first_char == "["]): %lua::parenthesize for %i in 2 to (size of %tree): @@ -243,7 +242,7 @@ externally (%tree compiled with %compile_actions) means: report compile error at %key "\ ..Can't use this as an index, since it's not an expression." - %key_lua_str = (%key_lua::as smext) + %key_lua_str = (%key_lua::text) %lua_id = (%key_lua_str::matching "^['\"]([a-zA-Z_][a-zA-Z0-9_]*)['\"]$") if: %lua_id: @@ -260,16 +259,16 @@ externally (%tree compiled with %compile_actions) means: return %lua "Number": - return (Lua Value from %tree ["\(%tree.1)"]) + return (a Lua Buffer with {source:%tree, is_value:yes, bits:["\(%tree.1)"]}) "Var": - return (Lua Variable from %tree [%tree.1::as lua id]) + return (a Lua Buffer with {source:%tree, is_value:yes, is_variable:yes, bits:[%tree.1::as lua id]}) "FileChunks": barf "\ ..Can't convert FileChunks to a single block of lua, since each chunk's compilation depends on the earlier chunks" "Comment": # TODO: de-implement? - return (Lua Code from %tree "-- \(%tree.1::with "\n" -> "\n-- ")") + return (a Lua Buffer with {source:%tree, bits:["-- \(%tree.1::with "\n" -> "\n-- ")"]}) "Error": barf (%tree as a pretty error) diff --git a/nomnom/decompile.nom b/nomnom/decompile.nom index 7db61c8..11ec233 100644 --- a/nomnom/decompile.nom +++ b/nomnom/decompile.nom @@ -8,7 +8,7 @@ externally (%tree decompiled inline) means: assume (%tree is a "Syntax Tree") if %tree.type is: "Action": - %nomsu = (Nomsu Code from %tree) + %nomsu = (a Nomsu Buffer with {source: %tree}) if %tree.target: %target_nomsu = (%tree.target decompiled inline) if %tree.target.type is: @@ -44,17 +44,17 @@ externally (%tree decompiled inline) means: ..: %inner_nomsu::parenthesize - %nomsu = (Nomsu Code from %tree ["\\", %inner_nomsu]) + %nomsu = (a Nomsu Buffer with {source: %tree, bits: ["\\", %inner_nomsu]}) return %nomsu "Block": - %nomsu = (Nomsu Code from %tree [":"]) + %nomsu = (a Nomsu Buffer with {source: %tree, bits: [":"]}) for %line in %tree at %i: %nomsu::add [" " if (%i == 1) else "; ", %line decompiled inline] return %nomsu "Text": - %nomsu = (Nomsu Code from %tree []) + %nomsu = (a Nomsu Buffer with {source: %tree, bits: []}) for %text in recursive %tree: for %bit in %text at %i: if (%bit is text): %nomsu::add %bit @@ -78,10 +78,10 @@ externally (%tree decompiled inline) means: else: %nomsu::add ["\\(", %bit decompiled inline, ")"] - return (Nomsu Code from %tree ["\"", %nomsu, "\""]) + return (a Nomsu Buffer with {source: %tree, bits: ["\"", %nomsu, "\""]}) "List" "Dict": - %nomsu = (Nomsu Code from %tree ["[" if (%tree.type == "List") else "{"]) + %nomsu = (a Nomsu Buffer with {source: %tree, bits: ["[" if (%tree.type == "List") else "{"]}) for %item in %tree at %i: if (%i > 1): %nomsu::add ", " %nomsu::add (%item decompiled inline) @@ -94,7 +94,7 @@ externally (%tree decompiled inline) means: if (..) all of [%key.type == "Text", (size of %key) == 1, %key.1 is a nomsu identifier] ..: - %nomsu = (Nomsu Code from %key [%key.1]) + %nomsu = (a Nomsu Buffer with {source: %key, bits: [%key.1]}) ..else: %nomsu = (%key decompiled inline) @@ -107,7 +107,7 @@ externally (%tree decompiled inline) means: return %nomsu "IndexChain": - %nomsu = (Nomsu Code from %tree) + %nomsu = (a Nomsu Buffer with {source: %tree}) for %bit in %tree at %i: if (%i > 1): %nomsu::add "." if (..) @@ -128,9 +128,9 @@ externally (%tree decompiled inline) means: return %nomsu "Number": - return (Nomsu Code from %tree [(%tree.1 as hex) if %tree.hex else "\(%tree.1)"]) + return (a Nomsu Buffer with {source: %tree, bits: [(%tree.1 as hex) if %tree.hex else "\(%tree.1)"]}) "Var": - return (Nomsu Code from %tree ["%\(%tree.1)"]) + return (a Nomsu Buffer with {source: %tree, bits: ["%\(%tree.1)"]}) "Comment": return (nil) "FileChunks": barf "Can't inline a FileChunks" @@ -141,7 +141,7 @@ externally (%tree decompiled inline) means: %MAX_LINE = 90 externally (%tree decompiled) means: - %nomsu = (Nomsu Code from %tree) + %nomsu = (a Nomsu Buffer with {source: %tree}) # For concision: (recurse on %t) means: @@ -167,8 +167,7 @@ externally (%tree decompiled) means: %indented = (%t decompiled) if (%t.type == "Action"): %indented = (..) - Nomsu Code from %t [..] - "(..)\n ", %indented + a Nomsu Buffer with {source: %t, bits: ["(..)\n ", %indented]} return %indented @@ -253,13 +252,12 @@ externally (%tree decompiled) means: ..else: %nomsu::add "\n" return (..) - Nomsu Code from %tree [..] - ":\n ", %nomsu + a Nomsu Buffer with {source: %tree, bits: [":\n ", %nomsu]} "Text": # Multi-line text has more generous wrap margins %max_line = ((1.5 * %MAX_LINE) rounded down) - %nomsu = (Nomsu Code from %tree) + %nomsu = (a Nomsu Buffer with {source: %tree}) (add text from %tree) means: for %bit in %tree at %i: if (%bit is text): @@ -301,8 +299,7 @@ externally (%tree decompiled) means: add text from %tree return (..) - Nomsu Code from %tree [..] - "\"\\\n ..", %nomsu, "\"" + a Nomsu Buffer with {source: %tree, bits: ["\"\\\n ..", %nomsu, "\""]} "List" "Dict": if ((size of %tree) == 0): @@ -321,9 +318,9 @@ externally (%tree decompiled) means: ..else: %nomsu::add ", " return (..) - Nomsu Code from %tree [..] - "[..]\n " if (%tree.type == "List") else "{..}\n " - %nomsu + a Nomsu Buffer with {..} + source: %tree, bits: [..] + "[..]\n " if (%tree.type == "List") else "{..}\n ", %nomsu "DictEntry": set {%key:%tree.1, %value:%tree.2} diff --git a/nomnom/parser.nom b/nomnom/parser.nom index 13d6112..fe237e8 100644 --- a/nomnom/parser.nom +++ b/nomnom/parser.nom @@ -32,7 +32,7 @@ set {..} %source = (..) Source {filename:%userdata.filename, start:%t.start, stop:%t.stop} set {%t.start: nil, %t.stop: nil, %t.source: %source} - %t = (Syntax Tree %t) + %t = (a Syntax Tree with %t) (Syntax Tree).source_code_for_tree.%t = %userdata.source return %t ..with fallback %key ->: diff --git a/nomsu.moon b/nomsu.moon index c4a96f1..2c4d21f 100755 --- a/nomsu.moon +++ b/nomsu.moon @@ -212,6 +212,7 @@ say "\ buff = table.concat(buff) + -- TODO: support local variables pseudo_filename = "user input #"..repl_line Files.spoof(pseudo_filename, buff) err_hand = (error_message)-> diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua index 848999a..67e9621 100644 --- a/nomsu_compiler.lua +++ b/nomsu_compiler.lua @@ -151,7 +151,7 @@ do return false end NomsuCompiler.environment = { - NOMSU_COMPILER_VERSION = 10, + NOMSU_COMPILER_VERSION = 11, NOMSU_SYNTAX_VERSION = max_parser_version, next = next, unpack = unpack, @@ -180,7 +180,7 @@ do assert = assert, dofile = dofile, loadstring = loadstring, - lua_type_of_1 = type, + lua_type_of = type, select = select, math = math, io = io, @@ -406,7 +406,7 @@ do end return operate_on_text(code) end - local math_expression = re.compile([[ ([+-] " ")* [0-9]+ (" " [*/^+-] (" " [+-])* " " [0-9]+)+ !. ]]) + local math_expression = re.compile([[ (([*/^+-] / [0-9]+) " ")* [*/^+-] !. ]]) local compile_math_expression compile_math_expression = function(self, tree, ...) local lua = LuaCode.Value(tree.source) @@ -431,34 +431,36 @@ do end NomsuCompiler.environment.COMPILE_ACTIONS = setmetatable({ __imported = Dict({ }), - ["Lua 1"] = function(self, tree, code) + ["Lua"] = function(self, tree, code) return add_lua_string_bits(self, 'statements', code) end, - ["Lua value 1"] = function(self, tree, code) + ["Lua value"] = function(self, tree, code) return add_lua_string_bits(self, 'value', code) end, - ["lua > 1"] = function(self, tree, code) + ["lua >"] = function(self, tree, code) if code.type ~= "Text" then return LuaCode(tree.source, "nomsu:run_lua(", self:compile(code), ", nomsu);") end return add_lua_bits(self, "statements", code) end, - ["= lua 1"] = function(self, tree, code) + ["= lua"] = function(self, tree, code) if code.type ~= "Text" then return LuaCode.Value(tree.source, "nomsu:run_lua(", self:compile(code), ":as_statements('return '), nomsu)") end return add_lua_bits(self, "value", code) end, - ["use 1"] = function(self, tree, path) + ["use"] = function(self, tree, path) if path.type == 'Text' and #path == 1 and type(path[1]) == 'string' then - self:import_file(path[1]) + if not (self:import_file(path[1])) then + self:compile_error(tree, "Could not find anything to import for " .. tostring(path)) + end end return LuaCode(tree.source, "nomsu:import_file(" .. tostring(self:compile(path)) .. ")") end, ["tests"] = function(self, tree) return LuaCode.Value(tree.source, "TESTS") end, - ["test 1"] = function(self, tree, body) + ["test"] = function(self, tree, body) local test_str = table.concat((function() local _accum_0 = { } local _len_0 = 1 @@ -516,11 +518,14 @@ do end end NomsuCompiler.import_file = function(self, path) + local found = false for _, f in Files.walk(path) do if match(f, "%.lua$") or match(f, "%.nom$") or match(f, "^/dev/fd/[012]$") then + found = true self:import(self:run_file(f)) end end + return found end NomsuCompiler.run = function(self, to_run, compile_actions) local source = to_run.source or Source(to_run, 1, #to_run) @@ -673,7 +678,7 @@ do local get_version = self[("Nomsu version"):as_lua_id()] if get_version then do - local upgrade = self[("1 upgraded from 2 to 3"):as_lua_id()] + local upgrade = self[("1 upgraded from 2 to"):as_lua_id()] if upgrade then tree = upgrade(tree, tree.version, get_version()) end @@ -1273,13 +1278,13 @@ do local should_clump should_clump = function(prev_line, line) if prev_line.type == "Action" and line.type == "Action" then - if prev_line.stub == "use 1" then - return line.stub == "use 1" + if prev_line.stub == "use" then + return line.stub == "use" end - if prev_line.stub == "test 1" then + if prev_line.stub == "test" then return true end - if line.stub == "test 1" then + if line.stub == "test" then return false end end diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon index cbddf51..a1194d9 100644 --- a/nomsu_compiler.moon +++ b/nomsu_compiler.moon @@ -93,12 +93,12 @@ with NomsuCompiler -- Discretionary/convenience stuff .environment = { - NOMSU_COMPILER_VERSION: 10, NOMSU_SYNTAX_VERSION: max_parser_version + NOMSU_COMPILER_VERSION: 11, NOMSU_SYNTAX_VERSION: max_parser_version -- Lua stuff: :next, :unpack, :setmetatable, :coroutine, :rawequal, :getmetatable, :pcall, :error, :package, :os, :require, :tonumber, :tostring, :string, :xpcall, :module, :print, :loadfile, :rawset, :_VERSION, :collectgarbage, :rawget, :rawlen, - :table, :assert, :dofile, :loadstring, lua_type_of_1:type, :select, :math, :io, :load, + :table, :assert, :dofile, :loadstring, lua_type_of:type, :select, :math, :io, :load, :pairs, :ipairs, -- Nomsu types: _List:List, _Dict:Dict, @@ -225,7 +225,7 @@ with NomsuCompiler -- This is a bit of a hack, but this code handles arbitrarily complex -- math expressions like 2*x + 3^2 without having to define a single -- action for every possibility. - math_expression = re.compile [[ ([+-] " ")* [0-9]+ (" " [*/^+-] (" " [+-])* " " [0-9]+)+ !. ]] + math_expression = re.compile [[ (([*/^+-] / [0-9]+) " ")* [*/^+-] !. ]] compile_math_expression = (tree, ...)=> lua = LuaCode.Value(tree.source) for i,tok in ipairs tree @@ -242,29 +242,30 @@ with NomsuCompiler return lua .environment.COMPILE_ACTIONS = setmetatable({ __imported: Dict{} - ["Lua 1"]: (tree, code)=> + ["Lua"]: (tree, code)=> return add_lua_string_bits(@, 'statements', code) - ["Lua value 1"]: (tree, code)=> + ["Lua value"]: (tree, code)=> return add_lua_string_bits(@, 'value', code) - ["lua > 1"]: (tree, code)=> + ["lua >"]: (tree, code)=> if code.type != "Text" return LuaCode tree.source, "nomsu:run_lua(", @compile(code), ", nomsu);" return add_lua_bits(@, "statements", code) - ["= lua 1"]: (tree, code)=> + ["= lua"]: (tree, code)=> if code.type != "Text" return LuaCode.Value tree.source, "nomsu:run_lua(", @compile(code), ":as_statements('return '), nomsu)" return add_lua_bits(@, "value", code) - ["use 1"]: (tree, path)=> + ["use"]: (tree, path)=> if path.type == 'Text' and #path == 1 and type(path[1]) == 'string' - @import_file(path[1]) + unless @import_file(path[1]) + @compile_error tree, "Could not find anything to import for #{path}" return LuaCode(tree.source, "nomsu:import_file(#{@compile(path)})") ["tests"]: (tree)=> LuaCode.Value(tree.source, "TESTS") - ["test 1"]: (tree, body)=> + ["test"]: (tree, body)=> test_str = table.concat [tostring(@tree_to_nomsu(line)) for line in *body], "\n" LuaCode tree.source, "TESTS[#{tostring(tree.source)\as_lua!}] = ", test_str\as_lua! @@ -290,9 +291,12 @@ with NomsuCompiler @environment.COMPILE_ACTIONS.__imported[k] or= v .import_file = (path)=> + found = false for _,f in Files.walk(path) if match(f, "%.lua$") or match(f, "%.nom$") or match(f, "^/dev/fd/[012]$") + found = true @import(@run_file(f)) + return found .run = (to_run, compile_actions)=> source = to_run.source or Source(to_run, 1, #to_run) @@ -394,7 +398,7 @@ with NomsuCompiler compile_actions or= @environment.COMPILE_ACTIONS if tree.version if get_version = @[("Nomsu version")\as_lua_id!] - if upgrade = @[("1 upgraded from 2 to 3")\as_lua_id!] + if upgrade = @[("1 upgraded from 2 to")\as_lua_id!] tree = upgrade(tree, tree.version, get_version!) switch tree.type when "Action" @@ -787,9 +791,9 @@ with NomsuCompiler nomsu = NomsuCode(tree.source, pop_comments(tree.source.start)) should_clump = (prev_line, line)-> if prev_line.type == "Action" and line.type == "Action" - if prev_line.stub == "use 1" then return line.stub == "use 1" - if prev_line.stub == "test 1" then return true - if line.stub == "test 1" then return false + if prev_line.stub == "use" then return line.stub == "use" + if prev_line.stub == "test" then return true + if line.stub == "test" then return false return not recurse(prev_line)\is_multiline! for chunk_no, chunk in ipairs tree nomsu\append "\n\n#{("~")\rep(80)}\n\n" if chunk_no > 1 diff --git a/string2.lua b/string2.lua index 8e13171..cf86026 100644 --- a/string2.lua +++ b/string2.lua @@ -78,6 +78,9 @@ local string2 = { end return _accum_0 end, + starts_with = function(self, s) + return sub(self, 1, #s) == s + end, lines = function(self) local _accum_0 = { } local _len_0 = 1 @@ -114,10 +117,10 @@ local string2 = { for _index_0 = 1, #_list_0 do local line = _list_0[_index_0] while #line > maxlen do - local chunk = line:sub(1, maxlen) - local split = chunk:find(' ', maxlen - buffer, true) or maxlen - chunk = line:sub(1, split) - line = line:sub(split + 1, -1) + local chunk = sub(line, 1, maxlen) + local split = find(chunk, ' ', maxlen - buffer, true) or maxlen + chunk = sub(line, 1, split) + line = sub(line, split + 1, -1) lines[#lines + 1] = chunk end lines[#lines + 1] = line @@ -151,14 +154,14 @@ local string2 = { return format("x%02X", byte(c)) end end) - if not (is_lua_id(str:match("^_*(.*)$"))) then + if not (is_lua_id(match(str, "^_*(.*)$"))) then str = "_" .. str end return str end, from_lua_id = function(str) - if not (is_lua_id(str:match("^_*(.*)$"))) then - str = str:sub(2, -1) + if not (is_lua_id(match(str, "^_*(.*)$"))) then + str = sub(str, 2, -1) end str = gsub(str, "_", " ") str = gsub(str, "x([0-9A-F][0-9A-F])", function(hex) diff --git a/string2.moon b/string2.moon index d70abe6..e4ee482 100644 --- a/string2.moon +++ b/string2.moon @@ -26,6 +26,7 @@ string2 = { 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)] + starts_with: (s)=> sub(@, 1, #s) == s lines: => [line for i,line in isplit(@, '\n')] line: (line_num)=> for i, line, start in isplit(@, '\n') @@ -41,10 +42,10 @@ string2 = { lines = {} for line in *@lines! while #line > maxlen - chunk = line\sub(1, maxlen) - split = chunk\find(' ', maxlen-buffer, true) or maxlen - chunk = line\sub(1, split) - line = line\sub(split+1, -1) + chunk = sub(line, 1, maxlen) + split = find(chunk, ' ', maxlen-buffer, true) or maxlen + chunk = sub(line, 1, split) + line = sub(line, split+1, -1) lines[#lines+1] = chunk lines[#lines+1] = line return table.concat(lines, "\n") @@ -77,15 +78,15 @@ string2 = { if c == ' ' then '_' else format("x%02X", byte(c)) - unless is_lua_id(str\match("^_*(.*)$")) + unless is_lua_id(match(str, "^_*(.*)$")) str = "_"..str return 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 is_lua_id(str\match("^_*(.*)$")) - str = str\sub(2,-1) + unless is_lua_id(match(str, "^_*(.*)$")) + str = sub(str,2,-1) str = gsub(str, "_", " ") str = gsub(str, "x([0-9A-F][0-9A-F])", (hex)-> char(tonumber(hex, 16))) return str diff --git a/syntax_tree.lua b/syntax_tree.lua index 92cee59..fe4f6dc 100644 --- a/syntax_tree.lua +++ b/syntax_tree.lua @@ -160,10 +160,13 @@ do if type(a) == 'string' then stub_bits[#stub_bits + 1] = a else - stub_bits[#stub_bits + 1] = tostring(arg_i) + stub_bits[#stub_bits + 1] = arg_i arg_i = arg_i + 1 end end + while type(stub_bits[#stub_bits]) == 'number' do + stub_bits[#stub_bits] = nil + end return concat(stub_bits, " ") end } diff --git a/syntax_tree.moon b/syntax_tree.moon index 228f560..03596f8 100644 --- a/syntax_tree.moon +++ b/syntax_tree.moon @@ -80,8 +80,10 @@ class SyntaxTree if type(a) == 'string' stub_bits[#stub_bits+1] = a else - stub_bits[#stub_bits+1] = tostring(arg_i) + stub_bits[#stub_bits+1] = arg_i arg_i += 1 + while type(stub_bits[#stub_bits]) == 'number' + stub_bits[#stub_bits] = nil return concat stub_bits, " " @is_instance: (t)=> diff --git a/tools/find_action.nom b/tools/find_action.nom index e7e3f49..02abdbc 100755 --- a/tools/find_action.nom +++ b/tools/find_action.nom @@ -14,7 +14,12 @@ for %path in %files: for file %filename in %path: unless (%filename::matches "%.nom$") (do next %filename) %file = (read file %filename) - %tree = (parse %file from %filename) + try: + %tree = (parse %file from %filename) + ..and if it barfs: + say (red "\%filename failed to parse") + %tree = (nil) + unless %tree: do next %filename %results = [] for %t in recursive %tree: if (%t is "Action" syntax tree): -- cgit v1.2.3 From dc41f30c73c9686685e3a4183c1213fb4ba55c90 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Fri, 2 Nov 2018 15:10:17 -0700 Subject: Tweak --- string2.lua | 3 +++ string2.moon | 1 + 2 files changed, 4 insertions(+) diff --git a/string2.lua b/string2.lua index cf86026..09cb5ea 100644 --- a/string2.lua +++ b/string2.lua @@ -81,6 +81,9 @@ local string2 = { starts_with = function(self, s) return sub(self, 1, #s) == s end, + ends_with = function(self, s) + return #self >= #s and sub(self, #self - #s, -1) == s + end, lines = function(self) local _accum_0 = { } local _len_0 = 1 diff --git a/string2.moon b/string2.moon index e4ee482..e6db628 100644 --- a/string2.moon +++ b/string2.moon @@ -27,6 +27,7 @@ string2 = { byte: byte, bytes: (i, j)=> {byte(@, i or 1, j or -1)} split: (sep)=> [chunk for i,chunk in isplit(@, sep)] starts_with: (s)=> sub(@, 1, #s) == s + ends_with: (s)=> #@ >= #s and sub(@, #@-#s, -1) == s lines: => [line for i,line in isplit(@, '\n')] line: (line_num)=> for i, line, start in isplit(@, '\n') -- cgit v1.2.3