From 5f08b2f5324c968118a9eab54feebfdcbf2c6e7d Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 7 Nov 2011 20:57:07 -0800 Subject: [PATCH] transformers are instanced for for root blocks --- moonscript/compile.lua | 17 +++-- moonscript/compile.moon | 15 ++++- moonscript/transform.lua | 126 +++++++++++++++++++++++--------------- moonscript/transform.moon | 106 +++++++++++++++++--------------- 4 files changed, 156 insertions(+), 108 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index c9af1fc..72f74fa 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -317,7 +317,7 @@ Block = (function() return self:value(node) end, value = function(self, node, ...) - node = transform.Value(node) + node = self.root.transform.value(node) local action if type(node) ~= "table" then action = "raw_value" @@ -353,7 +353,7 @@ Block = (function() if not node then return end - node = transform.Statement(node) + node = self.root.transform.statement(node) local fn = line_compile[ntype(node)] if not fn then if has_value(node) then @@ -403,6 +403,7 @@ Block = (function() self._names = { } self._state = { } if self.parent then + self.root = self.parent.root self.indent = self.parent.indent + 1 return setmetatable(self._state, { __index = self.parent._state @@ -426,6 +427,9 @@ local RootBlock RootBlock = (function() local _parent_0 = Block local _base_0 = { + __tostring = function(self) + return "RootBlock<>" + end, render = function(self) self:_insert_breaks() return concat(self._lines, "\n") @@ -437,9 +441,12 @@ RootBlock = (function() end local _class_0 = setmetatable({ __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end + self.root = self + self.transform = { + value = transform.Value:instance(self), + statement = transform.Statement:instance(self) + } + return _parent_0.__init(self, ...) end }, { __index = _base_0, diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 2c876e4..af943f3 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -64,6 +64,7 @@ class Block @_state = {} if @parent + @root = @parent.root @indent = @parent.indent + 1 setmetatable @_state, { __index: @parent._state } else @@ -226,7 +227,7 @@ class Block -- line wise compile functions name: (node) => @value node value: (node, ...) => - node = transform.Value node + node = @root.transform.value node action = if type(node) != "table" "raw_value" else @@ -244,7 +245,7 @@ class Block stm: (node, ...) => return if not node -- slip blank statements - node = transform.Statement node + node = @root.transform.statement node fn = line_compile[ntype(node)] if not fn -- coerce value into statement @@ -264,6 +265,16 @@ class Block nil class RootBlock extends Block + new: (...) => + @root = self + @transform = { + value: transform.Value\instance self + statement: transform.Statement\instance self + } + super ... + + __tostring: => "RootBlock<>" + render: => @_insert_breaks! concat @_lines, "\n" diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 8589b4b..2c6ddf1 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -7,7 +7,7 @@ local ntype, build, smart_node, is_slice = types.ntype, types.build, types.smart local insert = table.insert local is_value is_value = function(stm) - return moonscript.compile.Block:is_value(stm) or Value.can_transform(stm) + return moonscript.compile.Block:is_value(stm) or Value:can_transform(stm) end NameProxy = (function() local _parent_0 = nil @@ -154,43 +154,63 @@ is_singular = function(body) end local constructor_name = "new" local Transformer -Transformer = function(transformers) - local seen_nodes = { } - local tf = { - transform = function(n, ...) - if seen_nodes[n] then - return n +Transformer = (function() + local _parent_0 = nil + local _base_0 = { + transform = function(self, scope, node, ...) + if self.seen_nodes[node] then + return node end - seen_nodes[n] = true + self.seen_nodes[node] = true while true do - local transformer = transformers[ntype(n)] + local transformer = self.transformers[ntype(node)] local res if transformer then - res = transformer(n, ...) or n + res = transformer(scope, node, ...) or node else - res = n + res = node end - if res == n then - return n + if res == node then + return node end - n = res + node = res end end, - can_transform = function(node) - return transformers[ntype(node)] ~= nil + __call = function(self, node, ...) + return self:transform(self.scope, node, ...) + end, + instance = function(self, scope) + return Transformer(self.transformers, scope) + end, + can_transform = function(self, node) + return self.transformers[ntype(node)] ~= nil end } - return setmetatable(tf, { - __call = function(self, ...) - return self.transform(...) + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, getmetatable(_parent_0).__index) + end + local _class_0 = setmetatable({ + __init = function(self, transformers, scope) + self.transformers, self.scope = transformers, scope + self.seen_nodes = { } + end + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 end }) -end + _base_0.__class = _class_0 + return _class_0 +end)() Statement = Transformer({ - assign = function(node) + assign = function(self, node) local _, names, values = unpack(node) if #values == 1 and types.cascading[ntype(values[1])] then - values[1] = Statement(values[1], function(stm) + values[1] = self.transform.statement(values[1], function(stm) local t = ntype(stm) if is_value(stm) then return { @@ -215,7 +235,7 @@ Statement = Transformer({ return node end end, - export = function(node) + export = function(self, node) if #node > 2 then if node[2] == "class" then local cls = smart_node(node[3]) @@ -241,7 +261,7 @@ Statement = Transformer({ return nil end end, - update = function(node) + update = function(self, node) local _, name, op, exp = unpack(node) local op_final = op:match("^(.+)=$") if not op_final then @@ -254,7 +274,7 @@ Statement = Transformer({ exp }) end, - import = function(node) + import = function(self, node) local _, names, source = unpack(node) local stubs = (function() local _accum_0 = { } @@ -340,7 +360,7 @@ Statement = Transformer({ }) end end, - comprehension = function(node, action) + comprehension = function(self, node, action) local _, exp, clauses = unpack(node) action = action or function(exp) return { @@ -376,7 +396,7 @@ Statement = Transformer({ end return current_stms[1] end, - ["if"] = function(node, ret) + ["if"] = function(self, node, ret) if ret then smart_node(node) node['then'] = apply_to_last(node['then'], ret) @@ -388,7 +408,7 @@ Statement = Transformer({ end return node end, - with = function(node, ret) + with = function(self, node, ret) local _, exp, block = unpack(node) local scope_name = NameProxy("with") return build["do"]({ @@ -404,7 +424,7 @@ Statement = Transformer({ end)() }) end, - foreach = function(node) + foreach = function(self, node) smart_node(node) if ntype(node.iter) == "unpack" then local list = node.iter[2] @@ -470,7 +490,7 @@ Statement = Transformer({ }) end end, - class = function(node) + class = function(self, node) local _, name, parent_val, tbl = unpack(node) local constructor = nil local properties = (function() @@ -766,58 +786,62 @@ Accumulator = (function() return _class_0 end)() local default_accumulator -default_accumulator = function(node) +default_accumulator = function(self, node) return Accumulator():convert(node) end local implicitly_return -implicitly_return = function(stm) - local t = ntype(stm) - if types.manual_return[t] or not is_value(stm) then - return stm - elseif types.cascading[t] then - return Statement(stm, implicitly_return) - else - return { - "return", - stm - } +implicitly_return = function(scope) + local fn + fn = function(stm) + local t = ntype(stm) + if types.manual_return[t] or not is_value(stm) then + return stm + elseif types.cascading[t] then + return scope.transform.statement(stm, fn) + else + return { + "return", + stm + } + end end + return fn end Value = Transformer({ ["for"] = default_accumulator, ["while"] = default_accumulator, foreach = default_accumulator, - comprehension = function(node) + comprehension = function(self, node) local a = Accumulator() - node = Statement(node, function(exp) + node = self.transform.statement(node, function(exp) return a:mutate_body({ exp }, false) end) return a:wrap(node) end, - fndef = function(node) + fndef = function(self, node) smart_node(node) - node.body = apply_to_last(node.body, implicitly_return) + node.body = apply_to_last(node.body, implicitly_return(self)) return node end, - ["if"] = function(node) + ["if"] = function(self, node) return build.block_exp({ node }) end, - with = function(node) + with = function(self, node) return build.block_exp({ node }) end, - chain = function(node) + chain = function(self, node) local stub = node[#node] if type(stub) == "table" and stub[1] == "colon_stub" then table.remove(node, #node) local base_name = NameProxy("base") local fn_name = NameProxy("fn") - return Value(build.block_exp({ + return self.transform.value(build.block_exp({ build.assign({ names = { base_name @@ -862,7 +886,7 @@ Value = Transformer({ })) end end, - block_exp = function(node) + block_exp = function(self, node) local _, body = unpack(node) local fn = nil local arg_list = { } diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 3803b39..7bac6c3 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -13,7 +13,7 @@ export Statement, Value, NameProxy, Run -- TODO refactor is_value = (stm) -> - moonscript.compile.Block\is_value(stm) or Value.can_transform stm + moonscript.compile.Block\is_value(stm) or Value\can_transform stm class NameProxy new: (@prefix) => @@ -82,35 +82,38 @@ is_singular = (body) -> constructor_name = "new" -Transformer = (transformers) -> - -- this is bad, instance it for compiler - seen_nodes = {} - tf = { - transform: (n, ...) -> - return n if seen_nodes[n] - seen_nodes[n] = true - while true - transformer = transformers[ntype n] - res = if transformer - transformer(n, ...) or n - else - n - return n if res == n - n = res - can_transform: (node) -> - transformers[ntype node] != nil - } +class Transformer + new: (@transformers, @scope) => + @seen_nodes = {} - setmetatable tf, { - __call: (...) => self.transform ... - } + transform: (scope, node, ...) => + -- print scope, node, ... + return node if @seen_nodes[node] + @seen_nodes[node] = true + while true + transformer = @transformers[ntype node] + res = if transformer + transformer(scope, node, ...) or node + else + node + return node if res == node + node = res + + __call: (node, ...) => + @transform @scope, node, ... + + instance: (scope) => + Transformer @transformers, scope + + can_transform: (node) => + @transformers[ntype node] != nil Statement = Transformer { - assign: (node) -> + assign: (node) => _, names, values = unpack node -- bubble cascading assigns if #values == 1 and types.cascading[ntype values[1]] - values[1] = Statement values[1], (stm) -> + values[1] = @transform.statement values[1], (stm) -> t = ntype stm if is_value stm {"assign", names, {stm}} @@ -124,7 +127,7 @@ Statement = Transformer { else node - export: (node) -> + export: (node) => -- assign values if they are included if #node > 2 if node[2] == "class" @@ -144,13 +147,13 @@ Statement = Transformer { else nil - update: (node) -> + update: (node) => _, name, op, exp = unpack node op_final = op\match "^(.+)=$" error "Unknown op: "..op if not op_final build.assign_one name, {"exp", name, op_final, exp} - import: (node) -> + import: (node) => _, names, source = unpack node stubs = for name in *names @@ -180,7 +183,7 @@ Statement = Transformer { } } - comprehension: (node, action) -> + comprehension: (node, action) => _, exp, clauses = unpack node action = action or (exp) -> {exp} @@ -201,7 +204,7 @@ Statement = Transformer { current_stms[1] -- handle cascading return decorator - if: (node, ret) -> + if: (node, ret) => if ret smart_node node -- mutate all the bodies @@ -212,7 +215,7 @@ Statement = Transformer { case[body_idx] = apply_to_last case[body_idx], ret node - with: (node, ret) -> + with: (node, ret) => _, exp, block = unpack node scope_name = NameProxy "with" build["do"] { @@ -223,7 +226,7 @@ Statement = Transformer { ret scope_name } - foreach: (node) -> + foreach: (node) => smart_node node if ntype(node.iter) == "unpack" list = node.iter[2] @@ -263,7 +266,7 @@ Statement = Transformer { } } - class: (node) -> + class: (node) => _, name, parent_val, tbl = unpack node constructor = nil @@ -422,39 +425,42 @@ class Accumulator body -default_accumulator = (node) -> +default_accumulator = (node) => Accumulator!\convert node -implicitly_return = (stm) -> - t = ntype stm - if types.manual_return[t] or not is_value stm - stm - elseif types.cascading[t] - Statement stm, implicitly_return - else - {"return", stm} +implicitly_return = (scope) -> + fn = (stm) -> + t = ntype stm + if types.manual_return[t] or not is_value stm + stm + elseif types.cascading[t] + scope.transform.statement stm, fn + else + {"return", stm} + + fn Value = Transformer { for: default_accumulator while: default_accumulator foreach: default_accumulator - comprehension: (node) -> + comprehension: (node) => a = Accumulator! - node = Statement node, (exp) -> + node = @transform.statement node, (exp) -> a\mutate_body {exp}, false a\wrap node - fndef: (node) -> + fndef: (node) => smart_node node - node.body = apply_to_last node.body, implicitly_return + node.body = apply_to_last node.body, implicitly_return self node - if: (node) -> build.block_exp { node } - with: (node) -> build.block_exp { node } + if: (node) => build.block_exp { node } + with: (node) => build.block_exp { node } -- pull out colon chain - chain: (node) -> + chain: (node) => stub = node[#node] if type(stub) == "table" and stub[1] == "colon_stub" table.remove node, #node @@ -462,7 +468,7 @@ Value = Transformer { base_name = NameProxy "base" fn_name = NameProxy "fn" - Value build.block_exp { + @transform.value build.block_exp { build.assign { names: {base_name} values: {node} @@ -485,7 +491,7 @@ Value = Transformer { } } - block_exp: (node) -> + block_exp: (node) => _, body = unpack node fn = nil