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
return nil
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)
local _, exp, block = unpack(node)
do

View File

@ -167,28 +167,6 @@ line_compile =
@declare names
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) =>
_, exp, block = unpack node

View File

@ -103,31 +103,6 @@ value_compile = {
return _with_0
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)
local callee = node[2]
if callee == -1 then

View File

@ -52,25 +52,6 @@ value_compile =
with @block "(function()", "end)()"
\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) =>
callee = node[2]

View File

@ -2,6 +2,7 @@ module("moonscript.transform", package.seeall)
local types = require("moonscript.types")
local util = require("moonscript.util")
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 insert = table.insert
NameProxy = (function()
@ -136,11 +137,22 @@ apply_to_last = function(stms, fn)
return _accum_0
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 Transformer
Transformer = function(transformers)
local seen_nodes = { }
return function(n)
return function(n, ...)
if seen_nodes[n] then
return n
end
@ -149,7 +161,7 @@ Transformer = function(transformers)
local transformer = transformers[ntype(n)]
local res
if transformer then
res = transformer(n) or n
res = transformer(n, ...) or n
else
res = n
end
@ -161,6 +173,42 @@ Transformer = function(transformers)
end
end
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)
smart_node(node)
if ntype(node.iter) == "unpack" then
@ -437,45 +485,108 @@ stm = Transformer({
return value
end
})
local create_accumulator
create_accumulator = function(body_index)
return function(node)
local accum_name = NameProxy("accum")
local value_name = NameProxy("value")
local len_name = NameProxy("len")
local body = apply_to_last(node[body_index], function(n)
return build.assign_one(value_name, n)
end)
table.insert(body, build["if"]({
cond = {
"exp",
value_name,
"!=",
"nil"
},
["then"] = {
local Accumulator
Accumulator = (function()
local _parent_0 = nil
local _base_0 = {
body_idx = {
["for"] = 4,
["while"] = 3,
foreach = 4
},
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",
len_name,
self.len_name,
"+=",
1
},
build.assign_one(accum_name:index(len_name), value_name)
build.assign_one(self.accum_name:index(self.len_name), val)
}
}))
node[body_index] = body
return build.block_exp({
build.assign_one(accum_name, build.table()),
build.assign_one(len_name, 0),
node,
accum_name
})
if skip_nil then
table.insert(body, build["if"]({
cond = {
"exp",
self.value_name,
"!=",
"nil"
},
["then"] = update
}))
else
table.insert(body, build.group(update))
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
value = Transformer({
["for"] = create_accumulator(4),
["while"] = create_accumulator(3),
foreach = create_accumulator(4),
["for"] = default_accumulator,
["while"] = default_accumulator,
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)
local stub = node[#node]
if type(stub) == "table" and stub[1] == "colon_stub" then

View File

@ -5,6 +5,7 @@ types = require "moonscript.types"
util = require "moonscript.util"
data = require "moonscript.data"
import reversed from util
import ntype, build, smart_node, is_slice from types
import insert from table
@ -51,6 +52,7 @@ class Run
self.fn state
-- transform the last stm is a list of stms
-- will puke on group
apply_to_last = (stms, fn using nil) ->
-- find last (real) exp
last_exp_id = 0
@ -66,23 +68,52 @@ apply_to_last = (stms, fn using nil) ->
else
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"
Transformer = (transformers) ->
-- this is bad, instance it for compiler
seen_nodes = {}
(n) ->
(n, ...) ->
return n if seen_nodes[n]
seen_nodes[n] = true
while true
transformer = transformers[ntype n]
res = if transformer
transformer(n) or n
transformer(n, ...) or n
else
n
return n if res == n
n = res
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) ->
smart_node node
if ntype(node.iter) == "unpack"
@ -233,36 +264,68 @@ stm = Transformer {
value
}
create_accumulator = (body_index) ->
(node) ->
accum_name = NameProxy "accum"
value_name = NameProxy "value"
len_name = NameProxy "len"
class Accumulator
body_idx: { for: 4, while: 3, foreach: 4 }
body = apply_to_last node[body_index], (n) ->
build.assign_one value_name, n
new: =>
@accum_name = NameProxy "accum"
@value_name = NameProxy "value"
@len_name = NameProxy "len"
table.insert body, build["if"] {
cond: {"exp", value_name, "!=", "nil"}
then: {
{"update", len_name, "+=", 1}
build.assign_one accum_name\index(len_name), value_name
}
}
node[body_index] = body
-- wraps node and mutates body
convert: (node) =>
index = @body_idx[ntype node]
node[index] = @mutate_body node[index]
@wrap node
-- wrap the node into a block_exp
wrap: (node) =>
build.block_exp {
build.assign_one accum_name, build.table!
build.assign_one len_name, 0
build.assign_one @accum_name, build.table!
build.assign_one @len_name, 0
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 {
for: create_accumulator 4
while: create_accumulator 3
foreach: create_accumulator 4
for: default_accumulator
while: default_accumulator
foreach: default_accumulator
comprehension: (node) ->
a = Accumulator!
node = stm node, (exp) ->
a\mutate_body {exp}, false
a\wrap node
-- pull out colon chain
chain: (node) ->