transformers are instanced for for root blocks

This commit is contained in:
leaf corcoran 2011-11-07 20:57:07 -08:00
parent 44167c327a
commit 5f08b2f532
4 changed files with 156 additions and 108 deletions

View File

@ -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,10 +441,13 @@ RootBlock = (function()
end
local _class_0 = setmetatable({
__init = function(self, ...)
if _parent_0 then
self.root = self
self.transform = {
value = transform.Value:instance(self),
statement = transform.Statement:instance(self)
}
return _parent_0.__init(self, ...)
end
end
}, {
__index = _base_0,
__call = function(cls, ...)

View File

@ -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"

View File

@ -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,16 +786,18 @@ 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)
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 Statement(stm, implicitly_return)
return scope.transform.statement(stm, fn)
else
return {
"return",
@ -783,41 +805,43 @@ implicitly_return = function(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 = { }

View File

@ -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) ->
implicitly_return = (scope) ->
fn = (stm) ->
t = ntype stm
if types.manual_return[t] or not is_value stm
stm
elseif types.cascading[t]
Statement stm, implicitly_return
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