Skip to content

Commit 0cf96b9

Browse files
committed
add numeric for loop comprehensions/decorator, fixes #45
1 parent c421798 commit 0cf96b9

File tree

8 files changed

+177
-30
lines changed

8 files changed

+177
-30
lines changed

docs/reference.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,12 @@ Using multiple `for` clauses is the same as using nested loops:
415415
points = [{x,y} for x in *x_coords for y in *y_coords]
416416
```
417417

418+
Numeric for loops can also be used in comprehensions:
419+
420+
```moon
421+
evens = [i for i=1,100 when i % 2 == 0]
422+
```
423+
418424
### Table Comprehensions
419425

420426
The syntax for table comprehensions is very similar, only differing by using `{` and

moonscript/parse.lua

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -447,9 +447,10 @@ local build_grammar = wrap_env(function()
447447

448448
TblComprehension = sym"{" * Ct(Exp * (sym"," * Exp)^-1) * CompInner * sym"}" / mark"tblcomprehension",
449449

450-
CompInner = Ct(CompFor * CompClause^0),
451-
CompFor = key"for" * Ct(NameList) * key"in" * (sym"*" * Exp / mark"unpack" + Exp) / mark"for",
452-
CompClause = CompFor + key"when" * Exp / mark"when",
450+
CompInner = Ct((CompForEach + CompFor) * CompClause^0),
451+
CompForEach = key"for" * Ct(NameList) * key"in" * (sym"*" * Exp / mark"unpack" + Exp) / mark"foreach",
452+
CompFor = key "for" * Name * sym"=" * Ct(Exp * sym"," * Exp * (sym"," * Exp)^-1) / mark"for",
453+
CompClause = CompFor + CompForEach + key"when" * Exp / mark"when",
453454

454455
Assign = sym"=" * (Ct(With + If + Switch) + Ct(TableBlock + ExpListLow)) / mark"assign",
455456
Update = ((sym"..=" + sym"+=" + sym"-=" + sym"*=" + sym"/=" + sym"%=" + sym"or=" + sym"and=") / trim) * Exp / mark"update",

moonscript/transform.lua

Lines changed: 53 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,16 @@ apply_to_last = function(stms, fn)
6666
local _accum_0 = { }
6767
local _len_0 = 1
6868
for i, stm in ipairs(stms) do
69+
local _value_0
6970
if i == last_exp_id then
70-
_accum_0[_len_0] = fn(stm)
71+
_value_0 = fn(stm)
7172
else
72-
_accum_0[_len_0] = stm
73+
_value_0 = stm
74+
end
75+
if _value_0 ~= nil then
76+
_accum_0[_len_0] = _value_0
77+
_len_0 = _len_0 + 1
7378
end
74-
_len_0 = _len_0 + 1
7579
end
7680
return _accum_0
7781
end)()
@@ -291,9 +295,25 @@ construct_comprehension = function(inner, clauses)
291295
local current_stms = inner
292296
for _, clause in reversed(clauses) do
293297
local t = clause[1]
294-
if t == "for" then
298+
local _exp_0 = t
299+
if "for" == _exp_0 then
300+
local name, bounds
301+
do
302+
local _obj_0 = clause
303+
_, name, bounds = _obj_0[1], _obj_0[2], _obj_0[3]
304+
end
305+
current_stms = {
306+
"for",
307+
name,
308+
bounds,
309+
current_stms
310+
}
311+
elseif "foreach" == _exp_0 then
295312
local names, iter
296-
_, names, iter = unpack(clause)
313+
do
314+
local _obj_0 = clause
315+
_, names, iter = _obj_0[1], _obj_0[2], _obj_0[3]
316+
end
297317
current_stms = {
298318
"foreach",
299319
names,
@@ -302,9 +322,12 @@ construct_comprehension = function(inner, clauses)
302322
},
303323
current_stms
304324
}
305-
elseif t == "when" then
325+
elseif "when" == _exp_0 then
306326
local cond
307-
_, cond = unpack(clause)
327+
do
328+
local _obj_0 = clause
329+
_, cond = _obj_0[1], _obj_0[2]
330+
end
308331
current_stms = {
309332
"if",
310333
cond,
@@ -440,15 +463,19 @@ local Statement = Transformer({
440463
local _list_0 = names
441464
for _index_0 = 1, #_list_0 do
442465
local name = _list_0[_index_0]
466+
local _value_0
443467
if type(name) == "table" then
444-
_accum_0[_len_0] = name
468+
_value_0 = name
445469
else
446-
_accum_0[_len_0] = {
470+
_value_0 = {
447471
"dot",
448472
name
449473
}
450474
end
451-
_len_0 = _len_0 + 1
475+
if _value_0 ~= nil then
476+
_accum_0[_len_0] = _value_0
477+
_len_0 = _len_0 + 1
478+
end
452479
end
453480
return _accum_0
454481
end)()
@@ -458,8 +485,11 @@ local Statement = Transformer({
458485
local _list_0 = names
459486
for _index_0 = 1, #_list_0 do
460487
local name = _list_0[_index_0]
461-
_accum_0[_len_0] = type(name) == "table" and name[2] or name
462-
_len_0 = _len_0 + 1
488+
local _value_0 = type(name) == "table" and name[2] or name
489+
if _value_0 ~= nil then
490+
_accum_0[_len_0] = _value_0
491+
_len_0 = _len_0 + 1
492+
end
463493
end
464494
return _accum_0
465495
end)()
@@ -681,17 +711,21 @@ local Statement = Transformer({
681711
local _accum_0 = { }
682712
local _len_0 = 1
683713
for i, name in ipairs(node.names) do
714+
local _value_0
684715
if ntype(name) == "table" then
685716
do
686717
local _with_0 = NameProxy("des")
687718
local proxy = _with_0
688719
insert(destructures, destructure.build_assign(name, proxy))
689-
_accum_0[_len_0] = _with_0
720+
_value_0 = _with_0
690721
end
691722
else
692-
_accum_0[_len_0] = name
723+
_value_0 = name
724+
end
725+
if _value_0 ~= nil then
726+
_accum_0[_len_0] = _value_0
727+
_len_0 = _len_0 + 1
693728
end
694-
_len_0 = _len_0 + 1
695729
end
696730
return _accum_0
697731
end)()
@@ -872,8 +906,10 @@ local Statement = Transformer({
872906
else
873907
_value_0 = tuple
874908
end
875-
_accum_0[_len_0] = _value_0
876-
_len_0 = _len_0 + 1
909+
if _value_0 ~= nil then
910+
_accum_0[_len_0] = _value_0
911+
_len_0 = _len_0 + 1
912+
end
877913
_continue_0 = true
878914
until true
879915
if not _continue_0 then

moonscript/transform.moon

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -140,14 +140,19 @@ construct_comprehension = (inner, clauses) ->
140140
current_stms = inner
141141
for _, clause in reversed clauses
142142
t = clause[1]
143-
current_stms = if t == "for"
144-
_, names, iter = unpack clause
145-
{"foreach", names, {iter}, current_stms}
146-
elseif t == "when"
147-
_, cond = unpack clause
148-
{"if", cond, current_stms}
149-
else
150-
error "Unknown comprehension clause: "..t
143+
current_stms = switch t
144+
when "for"
145+
{_, name, bounds} = clause
146+
{"for", name, bounds, current_stms}
147+
when "foreach"
148+
{_, names, iter} = clause
149+
{"foreach", names, {iter}, current_stms}
150+
when "when"
151+
{_, cond} = clause
152+
{"if", cond, current_stms}
153+
else
154+
error "Unknown comprehension clause: "..t
155+
151156
current_stms = {current_stms}
152157

153158
current_stms[1]

tests/inputs/comprehension.moon

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,17 @@ copy = {k,v for k,v in pairs x when k != "okay"}
1717
{ xxxx for x in yes }
1818
{ unpack [a*i for i, a in ipairs x] for x in *{{1,2}, {3,4}} }
1919

20+
21+
--
22+
23+
n1 = [i for i=1,10]
24+
n2 = [i for i=1,10 when i % 2 == 1]
25+
26+
aa = [{x,y} for x=1,10 for y=5,14]
27+
bb = [y for thing in y for i=1,10]
28+
cc = [y for i=1,10 for thing in y]
29+
dd = [y for i=1,10 when cool for thing in y when x > 3 when c + 3]
30+
31+
{"hello", "world" for i=1,10}
32+
33+
nil

tests/inputs/syntax.moon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ x = -[x for x in x]
104104
print "hello" if cool
105105
print "hello" unless cool
106106
print "hello" unless 1212 and 3434 -- hello
107+
print "hello" for i=1,10
107108

108109
print "nutjob"
109110

tests/outputs/comprehension.lua

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ _ = (function()
5252
end
5353
return _tbl_0
5454
end)()
55-
return (function()
55+
_ = (function()
5656
local _tbl_0 = { }
5757
local _list_0 = {
5858
{
@@ -78,4 +78,85 @@ return (function()
7878
_tbl_0[_key_0] = _val_0
7979
end
8080
return _tbl_0
81-
end)()
81+
end)()
82+
local n1 = (function()
83+
local _accum_0 = { }
84+
local _len_0 = 1
85+
for i = 1, 10 do
86+
_accum_0[_len_0] = i
87+
_len_0 = _len_0 + 1
88+
end
89+
return _accum_0
90+
end)()
91+
local n2 = (function()
92+
local _accum_0 = { }
93+
local _len_0 = 1
94+
for i = 1, 10 do
95+
if i % 2 == 1 then
96+
_accum_0[_len_0] = i
97+
_len_0 = _len_0 + 1
98+
end
99+
end
100+
return _accum_0
101+
end)()
102+
local aa = (function()
103+
local _accum_0 = { }
104+
local _len_0 = 1
105+
for x = 1, 10 do
106+
for y = 5, 14 do
107+
_accum_0[_len_0] = {
108+
x,
109+
y
110+
}
111+
_len_0 = _len_0 + 1
112+
end
113+
end
114+
return _accum_0
115+
end)()
116+
local bb = (function()
117+
local _accum_0 = { }
118+
local _len_0 = 1
119+
for thing in y do
120+
for i = 1, 10 do
121+
_accum_0[_len_0] = y
122+
_len_0 = _len_0 + 1
123+
end
124+
end
125+
return _accum_0
126+
end)()
127+
local cc = (function()
128+
local _accum_0 = { }
129+
local _len_0 = 1
130+
for i = 1, 10 do
131+
for thing in y do
132+
_accum_0[_len_0] = y
133+
_len_0 = _len_0 + 1
134+
end
135+
end
136+
return _accum_0
137+
end)()
138+
local dd = (function()
139+
local _accum_0 = { }
140+
local _len_0 = 1
141+
for i = 1, 10 do
142+
if cool then
143+
for thing in y do
144+
if x > 3 then
145+
if c + 3 then
146+
_accum_0[_len_0] = y
147+
_len_0 = _len_0 + 1
148+
end
149+
end
150+
end
151+
end
152+
end
153+
return _accum_0
154+
end)()
155+
_ = (function()
156+
local _tbl_0 = { }
157+
for i = 1, 10 do
158+
_tbl_0["hello"] = "world"
159+
end
160+
return _tbl_0
161+
end)()
162+
return nil

tests/outputs/syntax.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ end
107107
if not (1212 and 3434) then
108108
print("hello")
109109
end
110+
for i = 1, 10 do
111+
print("hello")
112+
end
110113
print("nutjob")
111114
if hello then
112115
_ = 343

0 commit comments

Comments
 (0)