diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2018-10-31 15:54:18 -0700 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2018-10-31 15:54:51 -0700 |
| commit | d0c3c57f7b25c8d912c426e48cb5ab09cd738f65 (patch) | |
| tree | bc783d59d13c859343a9225f003062adb455ecac | |
| parent | ec92b0fccd70f06b5348fa355f49557aa71fdb3c (diff) | |
Simplified AST to just use a single moonscript class called "SyntaxTree"
instead of a different metatable for each type of syntax tree.
| -rw-r--r-- | core/metaprogramming.nom | 24 | ||||
| -rw-r--r-- | core/operators.nom | 2 | ||||
| -rw-r--r-- | nomsu_compiler.lua | 33 | ||||
| -rw-r--r-- | nomsu_compiler.moon | 29 | ||||
| -rw-r--r-- | syntax_tree.lua | 220 | ||||
| -rw-r--r-- | 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 |
