mirror of
https://github.com/leafo/moonscript.git
synced 2024-11-22 02:44:23 +00:00
comprehensions moved to transformer
This commit is contained in:
parent
5cdbb68503
commit
096b4078ce
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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]
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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) ->
|
||||||
|
Loading…
Reference in New Issue
Block a user