Skip to content

Commit 636c242

Browse files
committed
added key,value table comprehensions
1 parent 652e59c commit 636c242

File tree

7 files changed

+157
-48
lines changed

7 files changed

+157
-48
lines changed

docs/reference.md

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -281,10 +281,16 @@ same as the variable names, then the `:` prefix operator can be used:
281281

282282
print_table :hair, :height
283283

284-
## Table Comprehensions
284+
## Comprehensions
285285

286-
Table comprehensions provide a quick way to iterate over a table's values while
287-
applying a statement and accumulating the result.
286+
Compiling provide a convenient syntax for constructing a new table by iterating
287+
over some existing object and applying an expression to its values. There are
288+
two kinds of comprehensions: list comprehensions and table comprehensions. They
289+
both produce Lua tables; _list comprehensions_ accumulate values into an
290+
array-like table, and _table comprehensions_ let you set both the key and the
291+
value on each iteration.
292+
293+
### List Comprehensions
288294

289295
The following creates a copy of the `items` table but with all the values
290296
doubled.
@@ -312,6 +318,33 @@ Using multiple `for` clauses is the same as using nested loops:
312318

313319
points = [{x,y} for x in *x_coords for y in *y_coords]
314320

321+
### Table Comprehensions
322+
323+
The syntax for table comprehensions is very similar, differing by using `{` and
324+
`}` and taking two values from each iteration.
325+
326+
This example copies the key-value table `thing`:
327+
328+
thing = {
329+
color: "red"
330+
name: "fast"
331+
width: 123
332+
}
333+
334+
thing_copy = {k,v for k,v in pairs thing}
335+
336+
Table comprehensions, like list comprehensions, also support multiple `for` and
337+
`when` clauses`. In this example we use a `where` clause to prevent the value
338+
associated with the `color` key from being copied.
339+
340+
no_color = {k,v for k,v in pairs thing when k != "color"}
341+
342+
The `*` operator is also supported. Here we create a square root look up table
343+
for a few numbers.
344+
345+
numbers = {1,2,3,4}
346+
sqrts = {i, math.sqrt i for i in *numbers}
347+
315348
### Slicing
316349

317350
A special syntax is provided to restrict the items that are iterated over when

moonscript/transform.lua

Lines changed: 49 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,35 @@ Transformer = (function()
206206
_base_0.__class = _class_0
207207
return _class_0
208208
end)()
209+
local construct_comprehension
210+
construct_comprehension = function(inner, clauses)
211+
local current_stms = inner
212+
for _, clause in reversed(clauses) do
213+
local t = clause[1]
214+
if t == "for" then
215+
local _, names, iter = unpack(clause)
216+
current_stms = {
217+
"foreach",
218+
names,
219+
iter,
220+
current_stms
221+
}
222+
elseif t == "when" then
223+
local _, cond = unpack(clause)
224+
current_stms = {
225+
"if",
226+
cond,
227+
current_stms
228+
}
229+
else
230+
current_stms = error("Unknown comprehension clause: " .. t)
231+
end
232+
current_stms = {
233+
current_stms
234+
}
235+
end
236+
return current_stms[1]
237+
end
209238
Statement = Transformer({
210239
assign = function(self, node)
211240
local _, names, values = unpack(node)
@@ -367,34 +396,7 @@ Statement = Transformer({
367396
exp
368397
}
369398
end
370-
local current_stms = action(exp)
371-
for _, clause in reversed(clauses) do
372-
local t = clause[1]
373-
if t == "for" then
374-
local names, iter
375-
_, names, iter = unpack(clause)
376-
current_stms = {
377-
"foreach",
378-
names,
379-
iter,
380-
current_stms
381-
}
382-
elseif t == "when" then
383-
local cond
384-
_, cond = unpack(clause)
385-
current_stms = {
386-
"if",
387-
cond,
388-
current_stms
389-
}
390-
else
391-
current_stms = error("Unknown comprehension clause: " .. t)
392-
end
393-
current_stms = {
394-
current_stms
395-
}
396-
end
397-
return current_stms[1]
399+
return construct_comprehension(action(exp), clauses)
398400
end,
399401
["if"] = function(self, node, ret)
400402
if ret then
@@ -820,6 +822,25 @@ Value = Transformer({
820822
end)
821823
return a:wrap(node)
822824
end,
825+
tblcomprehension = function(self, node)
826+
local _, key_exp, value_exp, clauses = unpack(node)
827+
local accum = NameProxy("tbl")
828+
local dest = build.chain({
829+
base = accum,
830+
{
831+
"index",
832+
key_exp
833+
}
834+
})
835+
local inner = build.assign_one(dest, value_exp)
836+
return build.block_exp({
837+
build.assign_one(accum, build.table()),
838+
construct_comprehension({
839+
inner
840+
}, clauses),
841+
accum
842+
})
843+
end,
823844
fndef = function(self, node)
824845
smart_node(node)
825846
node.body = apply_to_last(node.body, implicitly_return(self))

moonscript/transform.moon

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,22 @@ class Transformer
108108
can_transform: (node) =>
109109
@transformers[ntype node] != nil
110110

111+
construct_comprehension = (inner, clauses) ->
112+
current_stms = inner
113+
for _, clause in reversed clauses
114+
t = clause[1]
115+
current_stms = if t == "for"
116+
_, names, iter = unpack clause
117+
{"foreach", names, iter, current_stms}
118+
elseif t == "when"
119+
_, cond = unpack clause
120+
{"if", cond, current_stms}
121+
else
122+
error "Unknown comprehension clause: "..t
123+
current_stms = {current_stms}
124+
125+
current_stms[1]
126+
111127
Statement = Transformer {
112128
assign: (node) =>
113129
_, names, values = unpack node
@@ -185,23 +201,8 @@ Statement = Transformer {
185201

186202
comprehension: (node, action) =>
187203
_, exp, clauses = unpack node
188-
189204
action = action or (exp) -> {exp}
190-
191-
current_stms = action exp
192-
for _, clause in reversed clauses
193-
t = clause[1]
194-
current_stms = if t == "for"
195-
_, names, iter = unpack clause
196-
{"foreach", names, iter, current_stms}
197-
elseif t == "when"
198-
_, cond = unpack clause
199-
{"if", cond, current_stms}
200-
else
201-
error "Unknown comprehension clause: "..t
202-
current_stms = {current_stms}
203-
204-
current_stms[1]
205+
construct_comprehension action(exp), clauses
205206

206207
-- handle cascading return decorator
207208
if: (node, ret) =>
@@ -428,6 +429,7 @@ class Accumulator
428429
default_accumulator = (node) =>
429430
Accumulator!\convert node
430431

432+
431433
implicitly_return = (scope) ->
432434
fn = (stm) ->
433435
t = ntype stm
@@ -451,6 +453,19 @@ Value = Transformer {
451453
a\mutate_body {exp}, false
452454
a\wrap node
453455

456+
tblcomprehension: (node) =>
457+
_, key_exp, value_exp, clauses = unpack node
458+
459+
accum = NameProxy "tbl"
460+
dest = build.chain { base: accum, {"index", key_exp} }
461+
inner = build.assign_one dest, value_exp
462+
463+
build.block_exp {
464+
build.assign_one accum, build.table!
465+
construct_comprehension {inner}, clauses
466+
accum
467+
}
468+
454469
fndef: (node) =>
455470
smart_node node
456471
node.body = apply_to_last node.body, implicitly_return self

moonscript/types.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,9 @@ build = setmetatable({
173173
})
174174
end,
175175
table = function(tbl)
176+
if tbl == nil then
177+
tbl = { }
178+
end
176179
return {
177180
"table",
178181
tbl

moonscript/types.moon

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ build = setmetatable {
9494
names: {name}
9595
values: {value}
9696
}
97-
table: (tbl) ->
97+
table: (tbl={}) ->
9898
{"table", tbl}
9999
block_exp: (body) ->
100100
{"block_exp", body}

tests/inputs/comprehension.moon

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
items = {1,2,3,4,5,6}
3+
out = {k,k*2 for k in items}
4+
5+
6+
x = hello: "world", okay: 2323
7+
8+
copy = {k,v for k,v in pairs x when k != "okay"}
9+

tests/outputs/comprehension.lua

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
local items = {
2+
1,
3+
2,
4+
3,
5+
4,
6+
5,
7+
6
8+
}
9+
local out = (function()
10+
local _tbl_0 = { }
11+
for k in items do
12+
_tbl_0[k] = k * 2
13+
end
14+
return _tbl_0
15+
end)()
16+
local x = {
17+
hello = "world",
18+
okay = 2323
19+
}
20+
local copy = (function()
21+
local _tbl_0 = { }
22+
for k, v in pairs(x) do
23+
if k ~= "okay" then
24+
_tbl_0[k] = v
25+
end
26+
end
27+
return _tbl_0
28+
end)()

0 commit comments

Comments
 (0)