aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/metaprogramming.nom24
-rw-r--r--core/operators.nom2
-rw-r--r--nomsu_compiler.lua33
-rw-r--r--nomsu_compiler.moon29
-rw-r--r--syntax_tree.lua220
-rw-r--r--syntax_tree.moon164
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