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) return self:value(node)
end, end,
value = function(self, node, ...) value = function(self, node, ...)
node = transform.Value(node) node = self.root.transform.value(node)
local action local action
if type(node) ~= "table" then if type(node) ~= "table" then
action = "raw_value" action = "raw_value"
@ -353,7 +353,7 @@ Block = (function()
if not node then if not node then
return return
end end
node = transform.Statement(node) node = self.root.transform.statement(node)
local fn = line_compile[ntype(node)] local fn = line_compile[ntype(node)]
if not fn then if not fn then
if has_value(node) then if has_value(node) then
@ -403,6 +403,7 @@ Block = (function()
self._names = { } self._names = { }
self._state = { } self._state = { }
if self.parent then if self.parent then
self.root = self.parent.root
self.indent = self.parent.indent + 1 self.indent = self.parent.indent + 1
return setmetatable(self._state, { return setmetatable(self._state, {
__index = self.parent._state __index = self.parent._state
@ -426,6 +427,9 @@ local RootBlock
RootBlock = (function() RootBlock = (function()
local _parent_0 = Block local _parent_0 = Block
local _base_0 = { local _base_0 = {
__tostring = function(self)
return "RootBlock<>"
end,
render = function(self) render = function(self)
self:_insert_breaks() self:_insert_breaks()
return concat(self._lines, "\n") return concat(self._lines, "\n")
@ -437,10 +441,13 @@ RootBlock = (function()
end end
local _class_0 = setmetatable({ local _class_0 = setmetatable({
__init = function(self, ...) __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, ...) return _parent_0.__init(self, ...)
end end
end
}, { }, {
__index = _base_0, __index = _base_0,
__call = function(cls, ...) __call = function(cls, ...)

View File

@ -64,6 +64,7 @@ class Block
@_state = {} @_state = {}
if @parent if @parent
@root = @parent.root
@indent = @parent.indent + 1 @indent = @parent.indent + 1
setmetatable @_state, { __index: @parent._state } setmetatable @_state, { __index: @parent._state }
else else
@ -226,7 +227,7 @@ class Block
-- line wise compile functions -- line wise compile functions
name: (node) => @value node name: (node) => @value node
value: (node, ...) => value: (node, ...) =>
node = transform.Value node node = @root.transform.value node
action = if type(node) != "table" action = if type(node) != "table"
"raw_value" "raw_value"
else else
@ -244,7 +245,7 @@ class Block
stm: (node, ...) => stm: (node, ...) =>
return if not node -- slip blank statements return if not node -- slip blank statements
node = transform.Statement node node = @root.transform.statement node
fn = line_compile[ntype(node)] fn = line_compile[ntype(node)]
if not fn if not fn
-- coerce value into statement -- coerce value into statement
@ -264,6 +265,16 @@ class Block
nil nil
class RootBlock extends Block class RootBlock extends Block
new: (...) =>
@root = self
@transform = {
value: transform.Value\instance self
statement: transform.Statement\instance self
}
super ...
__tostring: => "RootBlock<>"
render: => render: =>
@_insert_breaks! @_insert_breaks!
concat @_lines, "\n" 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 insert = table.insert
local is_value local is_value
is_value = function(stm) 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 end
NameProxy = (function() NameProxy = (function()
local _parent_0 = nil local _parent_0 = nil
@ -154,43 +154,63 @@ is_singular = function(body)
end end
local constructor_name = "new" local constructor_name = "new"
local Transformer local Transformer
Transformer = function(transformers) Transformer = (function()
local seen_nodes = { } local _parent_0 = nil
local tf = { local _base_0 = {
transform = function(n, ...) transform = function(self, scope, node, ...)
if seen_nodes[n] then if self.seen_nodes[node] then
return n return node
end end
seen_nodes[n] = true self.seen_nodes[node] = true
while true do while true do
local transformer = transformers[ntype(n)] local transformer = self.transformers[ntype(node)]
local res local res
if transformer then if transformer then
res = transformer(n, ...) or n res = transformer(scope, node, ...) or node
else else
res = n res = node
end end
if res == n then if res == node then
return n return node
end end
n = res node = res
end end
end, end,
can_transform = function(node) __call = function(self, node, ...)
return transformers[ntype(node)] ~= nil 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 end
} }
return setmetatable(tf, { _base_0.__index = _base_0
__call = function(self, ...) if _parent_0 then
return self.transform(...) 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
}) })
end _base_0.__class = _class_0
return _class_0
end)()
Statement = Transformer({ Statement = Transformer({
assign = function(node) assign = function(self, node)
local _, names, values = unpack(node) local _, names, values = unpack(node)
if #values == 1 and types.cascading[ntype(values[1])] then 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) local t = ntype(stm)
if is_value(stm) then if is_value(stm) then
return { return {
@ -215,7 +235,7 @@ Statement = Transformer({
return node return node
end end
end, end,
export = function(node) export = function(self, node)
if #node > 2 then if #node > 2 then
if node[2] == "class" then if node[2] == "class" then
local cls = smart_node(node[3]) local cls = smart_node(node[3])
@ -241,7 +261,7 @@ Statement = Transformer({
return nil return nil
end end
end, end,
update = function(node) update = function(self, node)
local _, name, op, exp = unpack(node) local _, name, op, exp = unpack(node)
local op_final = op:match("^(.+)=$") local op_final = op:match("^(.+)=$")
if not op_final then if not op_final then
@ -254,7 +274,7 @@ Statement = Transformer({
exp exp
}) })
end, end,
import = function(node) import = function(self, node)
local _, names, source = unpack(node) local _, names, source = unpack(node)
local stubs = (function() local stubs = (function()
local _accum_0 = { } local _accum_0 = { }
@ -340,7 +360,7 @@ Statement = Transformer({
}) })
end end
end, end,
comprehension = function(node, action) comprehension = function(self, node, action)
local _, exp, clauses = unpack(node) local _, exp, clauses = unpack(node)
action = action or function(exp) action = action or function(exp)
return { return {
@ -376,7 +396,7 @@ Statement = Transformer({
end end
return current_stms[1] return current_stms[1]
end, end,
["if"] = function(node, ret) ["if"] = function(self, node, ret)
if ret then if ret then
smart_node(node) smart_node(node)
node['then'] = apply_to_last(node['then'], ret) node['then'] = apply_to_last(node['then'], ret)
@ -388,7 +408,7 @@ Statement = Transformer({
end end
return node return node
end, end,
with = function(node, ret) with = function(self, node, ret)
local _, exp, block = unpack(node) local _, exp, block = unpack(node)
local scope_name = NameProxy("with") local scope_name = NameProxy("with")
return build["do"]({ return build["do"]({
@ -404,7 +424,7 @@ Statement = Transformer({
end)() end)()
}) })
end, end,
foreach = function(node) foreach = function(self, node)
smart_node(node) smart_node(node)
if ntype(node.iter) == "unpack" then if ntype(node.iter) == "unpack" then
local list = node.iter[2] local list = node.iter[2]
@ -470,7 +490,7 @@ Statement = Transformer({
}) })
end end
end, end,
class = function(node) class = function(self, node)
local _, name, parent_val, tbl = unpack(node) local _, name, parent_val, tbl = unpack(node)
local constructor = nil local constructor = nil
local properties = (function() local properties = (function()
@ -766,16 +786,18 @@ Accumulator = (function()
return _class_0 return _class_0
end)() end)()
local default_accumulator local default_accumulator
default_accumulator = function(node) default_accumulator = function(self, node)
return Accumulator():convert(node) return Accumulator():convert(node)
end end
local implicitly_return local implicitly_return
implicitly_return = function(stm) implicitly_return = function(scope)
local fn
fn = function(stm)
local t = ntype(stm) local t = ntype(stm)
if types.manual_return[t] or not is_value(stm) then if types.manual_return[t] or not is_value(stm) then
return stm return stm
elseif types.cascading[t] then elseif types.cascading[t] then
return Statement(stm, implicitly_return) return scope.transform.statement(stm, fn)
else else
return { return {
"return", "return",
@ -783,41 +805,43 @@ implicitly_return = function(stm)
} }
end end
end end
return fn
end
Value = Transformer({ Value = Transformer({
["for"] = default_accumulator, ["for"] = default_accumulator,
["while"] = default_accumulator, ["while"] = default_accumulator,
foreach = default_accumulator, foreach = default_accumulator,
comprehension = function(node) comprehension = function(self, node)
local a = Accumulator() local a = Accumulator()
node = Statement(node, function(exp) node = self.transform.statement(node, function(exp)
return a:mutate_body({ return a:mutate_body({
exp exp
}, false) }, false)
end) end)
return a:wrap(node) return a:wrap(node)
end, end,
fndef = function(node) fndef = function(self, node)
smart_node(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 return node
end, end,
["if"] = function(node) ["if"] = function(self, node)
return build.block_exp({ return build.block_exp({
node node
}) })
end, end,
with = function(node) with = function(self, node)
return build.block_exp({ return build.block_exp({
node node
}) })
end, end,
chain = function(node) chain = function(self, node)
local stub = node[#node] local stub = node[#node]
if type(stub) == "table" and stub[1] == "colon_stub" then if type(stub) == "table" and stub[1] == "colon_stub" then
table.remove(node, #node) table.remove(node, #node)
local base_name = NameProxy("base") local base_name = NameProxy("base")
local fn_name = NameProxy("fn") local fn_name = NameProxy("fn")
return Value(build.block_exp({ return self.transform.value(build.block_exp({
build.assign({ build.assign({
names = { names = {
base_name base_name
@ -862,7 +886,7 @@ Value = Transformer({
})) }))
end end
end, end,
block_exp = function(node) block_exp = function(self, node)
local _, body = unpack(node) local _, body = unpack(node)
local fn = nil local fn = nil
local arg_list = { } local arg_list = { }

View File

@ -13,7 +13,7 @@ export Statement, Value, NameProxy, Run
-- TODO refactor -- TODO refactor
is_value = (stm) -> 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 class NameProxy
new: (@prefix) => new: (@prefix) =>
@ -82,35 +82,38 @@ is_singular = (body) ->
constructor_name = "new" constructor_name = "new"
Transformer = (transformers) -> class Transformer
-- this is bad, instance it for compiler new: (@transformers, @scope) =>
seen_nodes = {} @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
}
setmetatable tf, { transform: (scope, node, ...) =>
__call: (...) => self.transform ... -- 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 { Statement = Transformer {
assign: (node) -> assign: (node) =>
_, names, values = unpack node _, names, values = unpack node
-- bubble cascading assigns -- bubble cascading assigns
if #values == 1 and types.cascading[ntype values[1]] 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 t = ntype stm
if is_value stm if is_value stm
{"assign", names, {stm}} {"assign", names, {stm}}
@ -124,7 +127,7 @@ Statement = Transformer {
else else
node node
export: (node) -> export: (node) =>
-- assign values if they are included -- assign values if they are included
if #node > 2 if #node > 2
if node[2] == "class" if node[2] == "class"
@ -144,13 +147,13 @@ Statement = Transformer {
else else
nil nil
update: (node) -> update: (node) =>
_, name, op, exp = unpack node _, name, op, exp = unpack node
op_final = op\match "^(.+)=$" op_final = op\match "^(.+)=$"
error "Unknown op: "..op if not op_final error "Unknown op: "..op if not op_final
build.assign_one name, {"exp", name, op_final, exp} build.assign_one name, {"exp", name, op_final, exp}
import: (node) -> import: (node) =>
_, names, source = unpack node _, names, source = unpack node
stubs = for name in *names stubs = for name in *names
@ -180,7 +183,7 @@ Statement = Transformer {
} }
} }
comprehension: (node, action) -> comprehension: (node, action) =>
_, exp, clauses = unpack node _, exp, clauses = unpack node
action = action or (exp) -> {exp} action = action or (exp) -> {exp}
@ -201,7 +204,7 @@ Statement = Transformer {
current_stms[1] current_stms[1]
-- handle cascading return decorator -- handle cascading return decorator
if: (node, ret) -> if: (node, ret) =>
if ret if ret
smart_node node smart_node node
-- mutate all the bodies -- mutate all the bodies
@ -212,7 +215,7 @@ Statement = Transformer {
case[body_idx] = apply_to_last case[body_idx], ret case[body_idx] = apply_to_last case[body_idx], ret
node node
with: (node, ret) -> with: (node, ret) =>
_, exp, block = unpack node _, exp, block = unpack node
scope_name = NameProxy "with" scope_name = NameProxy "with"
build["do"] { build["do"] {
@ -223,7 +226,7 @@ Statement = Transformer {
ret scope_name ret scope_name
} }
foreach: (node) -> foreach: (node) =>
smart_node node smart_node node
if ntype(node.iter) == "unpack" if ntype(node.iter) == "unpack"
list = node.iter[2] list = node.iter[2]
@ -263,7 +266,7 @@ Statement = Transformer {
} }
} }
class: (node) -> class: (node) =>
_, name, parent_val, tbl = unpack node _, name, parent_val, tbl = unpack node
constructor = nil constructor = nil
@ -422,39 +425,42 @@ class Accumulator
body body
default_accumulator = (node) -> default_accumulator = (node) =>
Accumulator!\convert node Accumulator!\convert node
implicitly_return = (stm) -> implicitly_return = (scope) ->
fn = (stm) ->
t = ntype stm t = ntype stm
if types.manual_return[t] or not is_value stm if types.manual_return[t] or not is_value stm
stm stm
elseif types.cascading[t] elseif types.cascading[t]
Statement stm, implicitly_return scope.transform.statement stm, fn
else else
{"return", stm} {"return", stm}
fn
Value = Transformer { Value = Transformer {
for: default_accumulator for: default_accumulator
while: default_accumulator while: default_accumulator
foreach: default_accumulator foreach: default_accumulator
comprehension: (node) -> comprehension: (node) =>
a = Accumulator! a = Accumulator!
node = Statement node, (exp) -> node = @transform.statement node, (exp) ->
a\mutate_body {exp}, false a\mutate_body {exp}, false
a\wrap node a\wrap node
fndef: (node) -> fndef: (node) =>
smart_node node smart_node node
node.body = apply_to_last node.body, implicitly_return node.body = apply_to_last node.body, implicitly_return self
node node
if: (node) -> build.block_exp { node } if: (node) => build.block_exp { node }
with: (node) -> build.block_exp { node } with: (node) => build.block_exp { node }
-- pull out colon chain -- pull out colon chain
chain: (node) -> chain: (node) =>
stub = node[#node] stub = node[#node]
if type(stub) == "table" and stub[1] == "colon_stub" if type(stub) == "table" and stub[1] == "colon_stub"
table.remove node, #node table.remove node, #node
@ -462,7 +468,7 @@ Value = Transformer {
base_name = NameProxy "base" base_name = NameProxy "base"
fn_name = NameProxy "fn" fn_name = NameProxy "fn"
Value build.block_exp { @transform.value build.block_exp {
build.assign { build.assign {
names: {base_name} names: {base_name}
values: {node} values: {node}
@ -485,7 +491,7 @@ Value = Transformer {
} }
} }
block_exp: (node) -> block_exp: (node) =>
_, body = unpack node _, body = unpack node
fn = nil fn = nil