comprehensions moved to transformer

This commit is contained in:
leaf corcoran 2011-11-06 09:52:03 -08:00
parent 5cdbb68503
commit 096b4078ce
6 changed files with 230 additions and 160 deletions

View File

@ -305,44 +305,6 @@ line_compile = {
end end
return nil return nil
end, end,
comprehension = function(self, node, action)
local _, exp, clauses = unpack(node)
if not action then
action = function(exp)
return {
exp
}
end
end
local current_stms = action(exp)
for _, clause in reversed(clauses) do
local t = clause[1]
if t == "for" then
local names, iter
_, names, iter = unpack(clause)
current_stms = {
"foreach",
names,
iter,
current_stms
}
elseif t == "when" then
local cond
_, cond = unpack(clause)
current_stms = {
"if",
cond,
current_stms
}
else
current_stms = error("Unknown comprehension clause: " .. t)
end
current_stms = {
current_stms
}
end
return self:stms(current_stms)
end,
with = function(self, node, ret) with = function(self, node, ret)
local _, exp, block = unpack(node) local _, exp, block = unpack(node)
do do

View File

@ -167,28 +167,6 @@ line_compile =
@declare names @declare names
nil nil
comprehension: (node, action) =>
_, exp, clauses = unpack node
if not action
action = (exp) -> {exp}
current_stms = action exp
for _, clause in reversed clauses
t = clause[1]
current_stms = if t == "for"
_, names, iter = unpack clause
{"foreach", names, iter, current_stms}
elseif t == "when"
_, cond = unpack clause
{"if", cond, current_stms}
else
error "Unknown comprehension clause: "..t
current_stms = {current_stms}
@stms current_stms
with: (node, ret) => with: (node, ret) =>
_, exp, block = unpack node _, exp, block = unpack node

View File

@ -103,31 +103,6 @@ value_compile = {
return _with_0 return _with_0
end end
end, end,
comprehension = function(self, node)
local _, exp, iter = unpack(node)
do
local _with_0 = self:block()
local tmp_name = _with_0:init_free_var("accum", {
"table"
})
local len_name = _with_0:init_free_var("len", 0)
local action
action = function(value)
return table_append(tmp_name, len_name, value)
end
_with_0:stm(node, action)
_with_0:stm({
"return",
tmp_name
})
if _with_0.has_varargs then
_with_0.header, _with_0.footer = "(function(...)", "end)(...)"
else
_with_0.header, _with_0.footer = "(function()", "end)()"
end
return _with_0
end
end,
chain = function(self, node) chain = function(self, node)
local callee = node[2] local callee = node[2]
if callee == -1 then if callee == -1 then

View File

@ -52,25 +52,6 @@ value_compile =
with @block "(function()", "end)()" with @block "(function()", "end)()"
\stm node, default_return \stm node, default_return
-- todo: convert to transformation
comprehension: (node) =>
_, exp, iter = unpack node
with @block!
tmp_name = \init_free_var "accum", {"table"}
len_name = \init_free_var "len", 0
action = (value) ->
table_append tmp_name, len_name, value
\stm node, action
\stm {"return", tmp_name}
.header, .footer = if .has_varargs
"(function(...)", "end)(...)"
else
"(function()", "end)()"
chain: (node) => chain: (node) =>
callee = node[2] callee = node[2]

View File

@ -2,6 +2,7 @@ module("moonscript.transform", package.seeall)
local types = require("moonscript.types") local types = require("moonscript.types")
local util = require("moonscript.util") local util = require("moonscript.util")
local data = require("moonscript.data") local data = require("moonscript.data")
local reversed = util.reversed
local ntype, build, smart_node, is_slice = types.ntype, types.build, types.smart_node, types.is_slice local ntype, build, smart_node, is_slice = types.ntype, types.build, types.smart_node, types.is_slice
local insert = table.insert local insert = table.insert
NameProxy = (function() NameProxy = (function()
@ -136,11 +137,22 @@ apply_to_last = function(stms, fn)
return _accum_0 return _accum_0
end)() end)()
end end
local is_singular
is_singular = function(body)
if #body ~= 1 then
return false
end
if "group" == ntype(body) then
return is_singular(body[2])
else
return true
end
end
local constructor_name = "new" local constructor_name = "new"
local Transformer local Transformer
Transformer = function(transformers) Transformer = function(transformers)
local seen_nodes = { } local seen_nodes = { }
return function(n) return function(n, ...)
if seen_nodes[n] then if seen_nodes[n] then
return n return n
end end
@ -149,7 +161,7 @@ Transformer = function(transformers)
local transformer = transformers[ntype(n)] local transformer = transformers[ntype(n)]
local res local res
if transformer then if transformer then
res = transformer(n) or n res = transformer(n, ...) or n
else else
res = n res = n
end end
@ -161,6 +173,42 @@ Transformer = function(transformers)
end end
end end
stm = Transformer({ stm = Transformer({
comprehension = function(node, action)
local _, exp, clauses = unpack(node)
action = action or function(exp)
return {
exp
}
end
local current_stms = action(exp)
for _, clause in reversed(clauses) do
local t = clause[1]
if t == "for" then
local names, iter
_, names, iter = unpack(clause)
current_stms = {
"foreach",
names,
iter,
current_stms
}
elseif t == "when" then
local cond
_, cond = unpack(clause)
current_stms = {
"if",
cond,
current_stms
}
else
current_stms = error("Unknown comprehension clause: " .. t)
end
current_stms = {
current_stms
}
end
return current_stms[1]
end,
foreach = function(node) foreach = function(node)
smart_node(node) smart_node(node)
if ntype(node.iter) == "unpack" then if ntype(node.iter) == "unpack" then
@ -437,45 +485,108 @@ stm = Transformer({
return value return value
end end
}) })
local create_accumulator local Accumulator
create_accumulator = function(body_index) Accumulator = (function()
return function(node) local _parent_0 = nil
local accum_name = NameProxy("accum") local _base_0 = {
local value_name = NameProxy("value") body_idx = {
local len_name = NameProxy("len") ["for"] = 4,
local body = apply_to_last(node[body_index], function(n) ["while"] = 3,
return build.assign_one(value_name, n) foreach = 4
end)
table.insert(body, build["if"]({
cond = {
"exp",
value_name,
"!=",
"nil"
}, },
["then"] = { convert = function(self, node)
local index = self.body_idx[ntype(node)]
node[index] = self:mutate_body(node[index])
return self:wrap(node)
end,
wrap = function(self, node)
return build.block_exp({
build.assign_one(self.accum_name, build.table()),
build.assign_one(self.len_name, 0),
node,
self.accum_name
})
end,
mutate_body = function(self, body, skip_nil)
if skip_nil == nil then
skip_nil = true
end
local val
if not skip_nil and is_singular(body) then
do
local _with_0 = body[1]
body = { }
val = _with_0
end
else
body = apply_to_last(body, function(n)
return build.assign_one(self.value_name, n)
end)
val = self.value_name
end
local update = {
{ {
"update", "update",
len_name, self.len_name,
"+=", "+=",
1 1
}, },
build.assign_one(accum_name:index(len_name), value_name) build.assign_one(self.accum_name:index(self.len_name), val)
} }
if skip_nil then
table.insert(body, build["if"]({
cond = {
"exp",
self.value_name,
"!=",
"nil"
},
["then"] = update
})) }))
node[body_index] = body else
return build.block_exp({ table.insert(body, build.group(update))
build.assign_one(accum_name, build.table()),
build.assign_one(len_name, 0),
node,
accum_name
})
end end
return body
end
}
_base_0.__index = _base_0
if _parent_0 then
setmetatable(_base_0, getmetatable(_parent_0).__index)
end
local _class_0 = setmetatable({
__init = function(self)
self.accum_name = NameProxy("accum")
self.value_name = NameProxy("value")
self.len_name = NameProxy("len")
end
}, {
__index = _base_0,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
return _class_0
end)()
local default_accumulator
default_accumulator = function(node)
return Accumulator():convert(node)
end end
value = Transformer({ value = Transformer({
["for"] = create_accumulator(4), ["for"] = default_accumulator,
["while"] = create_accumulator(3), ["while"] = default_accumulator,
foreach = create_accumulator(4), foreach = default_accumulator,
comprehension = function(node)
local a = Accumulator()
node = stm(node, function(exp)
return a:mutate_body({
exp
}, false)
end)
return a:wrap(node)
end,
chain = function(node) chain = function(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

View File

@ -5,6 +5,7 @@ types = require "moonscript.types"
util = require "moonscript.util" util = require "moonscript.util"
data = require "moonscript.data" data = require "moonscript.data"
import reversed from util
import ntype, build, smart_node, is_slice from types import ntype, build, smart_node, is_slice from types
import insert from table import insert from table
@ -51,6 +52,7 @@ class Run
self.fn state self.fn state
-- transform the last stm is a list of stms -- transform the last stm is a list of stms
-- will puke on group
apply_to_last = (stms, fn using nil) -> apply_to_last = (stms, fn using nil) ->
-- find last (real) exp -- find last (real) exp
last_exp_id = 0 last_exp_id = 0
@ -66,23 +68,52 @@ apply_to_last = (stms, fn using nil) ->
else else
stm stm
-- is a body a sindle expression/statement
is_singular = (body) ->
return false if #body != 1
if "group" == ntype body
is_singular body[2]
else
true
constructor_name = "new" constructor_name = "new"
Transformer = (transformers) -> Transformer = (transformers) ->
-- this is bad, instance it for compiler
seen_nodes = {} seen_nodes = {}
(n) -> (n, ...) ->
return n if seen_nodes[n] return n if seen_nodes[n]
seen_nodes[n] = true seen_nodes[n] = true
while true while true
transformer = transformers[ntype n] transformer = transformers[ntype n]
res = if transformer res = if transformer
transformer(n) or n transformer(n, ...) or n
else else
n n
return n if res == n return n if res == n
n = res n = res
stm = Transformer { stm = Transformer {
comprehension: (node, action) ->
_, exp, clauses = unpack node
action = action or (exp) -> {exp}
current_stms = action exp
for _, clause in reversed clauses
t = clause[1]
current_stms = if t == "for"
_, names, iter = unpack clause
{"foreach", names, iter, current_stms}
elseif t == "when"
_, cond = unpack clause
{"if", cond, current_stms}
else
error "Unknown comprehension clause: "..t
current_stms = {current_stms}
current_stms[1]
foreach: (node) -> foreach: (node) ->
smart_node node smart_node node
if ntype(node.iter) == "unpack" if ntype(node.iter) == "unpack"
@ -233,36 +264,68 @@ stm = Transformer {
value value
} }
create_accumulator = (body_index) -> class Accumulator
(node) -> body_idx: { for: 4, while: 3, foreach: 4 }
accum_name = NameProxy "accum"
value_name = NameProxy "value"
len_name = NameProxy "len"
body = apply_to_last node[body_index], (n) -> new: =>
build.assign_one value_name, n @accum_name = NameProxy "accum"
@value_name = NameProxy "value"
@len_name = NameProxy "len"
table.insert body, build["if"] { -- wraps node and mutates body
cond: {"exp", value_name, "!=", "nil"} convert: (node) =>
then: { index = @body_idx[ntype node]
{"update", len_name, "+=", 1} node[index] = @mutate_body node[index]
build.assign_one accum_name\index(len_name), value_name @wrap node
}
}
node[body_index] = body
-- wrap the node into a block_exp
wrap: (node) =>
build.block_exp { build.block_exp {
build.assign_one accum_name, build.table! build.assign_one @accum_name, build.table!
build.assign_one len_name, 0 build.assign_one @len_name, 0
node node
accum_name @accum_name
} }
-- mutates the body of a loop construct to save last value into accumulator
-- can optionally skip nil results
mutate_body: (body, skip_nil=true) =>
val = if not skip_nil and is_singular body
with body[1]
body = {}
else
body = apply_to_last body, (n) ->
build.assign_one @value_name, n
@value_name
update = {
{"update", @len_name, "+=", 1}
build.assign_one @accum_name\index(@len_name), val
}
if skip_nil
table.insert body, build["if"] {
cond: {"exp", @value_name, "!=", "nil"}
then: update
}
else
table.insert body, build.group update
body
default_accumulator = (node) ->
Accumulator!\convert node
value = Transformer { value = Transformer {
for: create_accumulator 4 for: default_accumulator
while: create_accumulator 3 while: default_accumulator
foreach: create_accumulator 4 foreach: default_accumulator
comprehension: (node) ->
a = Accumulator!
node = stm node, (exp) ->
a\mutate_body {exp}, false
a\wrap node
-- pull out colon chain -- pull out colon chain
chain: (node) -> chain: (node) ->