Skip to content

Commit 0d5abf6

Browse files
committed
continue support in foreach loop
1 parent 9d64679 commit 0d5abf6

File tree

7 files changed

+178
-13
lines changed

7 files changed

+178
-13
lines changed

moonscript/compile.lua

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,17 @@ Block = (function()
134134
get = function(self, name)
135135
return self._state[name]
136136
end,
137+
listen = function(self, name, fn)
138+
self._listeners[name] = fn
139+
end,
140+
send = function(self, name, ...)
141+
do
142+
local fn = self._listeners[name]
143+
if fn then
144+
return fn(self, ...)
145+
end
146+
end
147+
end,
137148
declare = function(self, names)
138149
local undeclared = (function()
139150
local _accum_0 = { }
@@ -173,11 +184,15 @@ Block = (function()
173184
whitelist_names = function(self, names)
174185
self._name_whitelist = Set(names)
175186
end,
176-
put_name = function(self, name)
187+
put_name = function(self, name, ...)
188+
value = ...
189+
if select("#", ...) == 0 then
190+
value = true
191+
end
177192
if util.moon.type(name) == NameProxy then
178193
name = name:get_name(self)
179194
end
180-
self._names[name] = true
195+
self._names[name] = value
181196
end,
182197
has_name = function(self, name, skip_exports)
183198
if not skip_exports then
@@ -415,6 +430,14 @@ Block = (function()
415430
self:stm(stm)
416431
end
417432
return nil
433+
end,
434+
splice = function(self, fn)
435+
local lines = {
436+
"lines",
437+
self._lines
438+
}
439+
self._lines = { }
440+
return self:stms(fn(lines))
418441
end
419442
}
420443
_base_0.__index = _base_0
@@ -429,6 +452,7 @@ Block = (function()
429452
self._posmap = { }
430453
self._names = { }
431454
self._state = { }
455+
self._listeners = { }
432456
do
433457
local _with_0 = transform
434458
self.transform = {
@@ -439,9 +463,12 @@ Block = (function()
439463
if self.parent then
440464
self.root = self.parent.root
441465
self.indent = self.parent.indent + 1
442-
return setmetatable(self._state, {
466+
setmetatable(self._state, {
443467
__index = self.parent._state
444468
})
469+
return setmetatable(self._listeners, {
470+
__index = self.parent._listeners
471+
})
445472
else
446473
self.indent = 0
447474
end

moonscript/compile.moon

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ class Block
7070
@_posmap = {}
7171
@_names = {}
7272
@_state = {}
73+
@_listeners = {}
7374

7475
with transform
7576
@transform = {
@@ -81,6 +82,7 @@ class Block
8182
@root = @parent.root
8283
@indent = @parent.indent + 1
8384
setmetatable @_state, { __index: @parent._state }
85+
setmetatable @_listeners, { __index: @parent._listeners }
8486
else
8587
@indent = 0
8688

@@ -98,6 +100,13 @@ class Block
98100
get: (name) =>
99101
@_state[name]
100102

103+
listen: (name, fn) =>
104+
@_listeners[name] = fn
105+
106+
send: (name, ...) =>
107+
if fn = @_listeners[name]
108+
fn self, ...
109+
101110
declare: (names) =>
102111
undeclared = for name in *names
103112
is_local = false
@@ -116,9 +125,12 @@ class Block
116125
whitelist_names: (names) =>
117126
@_name_whitelist = Set names
118127

119-
put_name: (name) =>
128+
put_name: (name, ...) =>
129+
value = ...
130+
value = true if select("#", ...) == 0
131+
120132
name = name\get_name self if util.moon.type(name) == NameProxy
121-
@_names[name] = true
133+
@_names[name] = value
122134

123135
has_name: (name, skip_exports) =>
124136
if not skip_exports
@@ -282,6 +294,11 @@ class Block
282294
@stm stm for stm in *stms
283295
nil
284296

297+
splice: (fn) =>
298+
lines = {"lines", @_lines}
299+
@_lines = {}
300+
@stms fn lines
301+
285302
class RootBlock extends Block
286303
new: (...) =>
287304
@root = self

moonscript/compile/statement.lua

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ module("moonscript.compile", package.seeall)
22
local util = require("moonscript.util")
33
require("moonscript.compile.format")
44
local dump = require("moonscript.dump")
5+
local transform = require("moonscript.transform")
6+
local NameProxy = transform.NameProxy
57
local reversed = util.reversed
68
local ntype
79
do
@@ -11,8 +13,14 @@ end
1113
local concat, insert = table.concat, table.insert
1214
line_compile = {
1315
raw = function(self, node)
14-
local _, text = unpack(node)
15-
return self:add(text)
16+
return self:add(node[2])
17+
end,
18+
lines = function(self, node)
19+
local _list_0 = node[2]
20+
for _index_0 = 1, #_list_0 do
21+
local line = _list_0[_index_0]
22+
self:add(line)
23+
end
1624
end,
1725
declare = function(self, node)
1826
local names = node[2]
@@ -142,6 +150,14 @@ line_compile = {
142150
end
143151
return root
144152
end,
153+
["repeat"] = function(self, node)
154+
local cond, block = unpack(node, 2)
155+
do
156+
local _with_0 = self:block("repeat", self:line("until ", self:value(cond)))
157+
_with_0:stms(block)
158+
return _with_0
159+
end
160+
end,
145161
["while"] = function(self, node)
146162
local _, cond, block = unpack(node)
147163
local out
@@ -215,12 +231,66 @@ line_compile = {
215231
_with_0:append(" do")
216232
loop = _with_0
217233
end
234+
local continue_name = nil
235+
local out
218236
do
219237
local _with_0 = self:block(loop)
238+
_with_0:listen("continue", function()
239+
if not (continue_name) then
240+
continue_name = NameProxy("continue")
241+
_with_0:put_name(continue_name)
242+
end
243+
return continue_name
244+
end)
220245
_with_0:declare(names)
221246
_with_0:stms(block)
222-
return _with_0
247+
out = _with_0
248+
end
249+
if continue_name then
250+
out:put_name(continue_name, nil)
251+
out:splice(function(lines)
252+
return {
253+
{
254+
"assign",
255+
{
256+
continue_name
257+
},
258+
{
259+
"false"
260+
}
261+
},
262+
{
263+
"repeat",
264+
"true",
265+
{
266+
lines,
267+
{
268+
"assign",
269+
{
270+
continue_name
271+
},
272+
{
273+
"true"
274+
}
275+
}
276+
}
277+
},
278+
{
279+
"if",
280+
{
281+
"not",
282+
continue_name
283+
},
284+
{
285+
{
286+
"break"
287+
}
288+
}
289+
}
290+
}
291+
end)
223292
end
293+
return out
224294
end,
225295
export = function(self, node)
226296
local _, names = unpack(node)

moonscript/compile/statement.moon

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,21 @@ util = require "moonscript.util"
44

55
require "moonscript.compile.format"
66
dump = require "moonscript.dump"
7+
transform = require "moonscript.transform"
78

9+
import NameProxy from transform
810
import reversed from util
911
import ntype from require "moonscript.types"
1012
import concat, insert from table
1113

1214
export line_compile
1315

1416
line_compile =
15-
raw: (node) =>
16-
_, text = unpack node
17-
@add text
17+
raw: (node) => @add node[2]
18+
19+
lines: (node) =>
20+
for line in *node[2]
21+
@add line
1822

1923
declare: (node) =>
2024
names = node[2]
@@ -82,6 +86,11 @@ line_compile =
8286
add_clause cond for cond in *node[4,]
8387
root
8488

89+
repeat: (node) =>
90+
cond, block = unpack node, 2
91+
with @block "repeat", @line "until ", @value cond
92+
\stms block
93+
8594
while: (node) =>
8695
_, cond, block = unpack node
8796

@@ -113,10 +122,33 @@ line_compile =
113122
\append_list [@value exp for exp in *exps], ","
114123
\append " do"
115124

116-
with @block loop
125+
continue_name = nil
126+
out = with @block loop
127+
\listen "continue", ->
128+
unless continue_name
129+
continue_name = NameProxy"continue"
130+
\put_name continue_name
131+
continue_name
132+
117133
\declare names
118134
\stms block
119135

136+
-- todo: figure out how to put this in the transformer
137+
if continue_name
138+
out\put_name continue_name, nil
139+
out\splice (lines) -> {
140+
{"assign", {continue_name}, {"false"}}
141+
{"repeat", "true", {
142+
lines
143+
{"assign", {continue_name}, {"true"}}
144+
}}
145+
{"if", {"not", continue_name}, {
146+
{"break"}
147+
}}
148+
}
149+
150+
out
151+
120152
export: (node) =>
121153
_, names = unpack node
122154
if type(names) == "string"

moonscript/parse.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ local build_grammar = wrap_env(function()
368368

369369
NameList = Name * (sym"," * Name)^0,
370370

371-
BreakLoop = Ct(key"break"/trim),
371+
BreakLoop = Ct(key"break"/trim) + Ct(key"continue"/trim),
372372

373373
Return = key"return" * (ExpListLow/mark"explist" + C"") / mark"return",
374374

moonscript/transform.lua

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,18 @@ Statement = Transformer({
414414
end
415415
return transformed or node
416416
end,
417+
continue = function(self, node)
418+
local continue_name = self:send("continue")
419+
if not (continue_name) then
420+
error("continue must be inside of a loop")
421+
end
422+
return build.group({
423+
build.assign_one(continue_name, "true"),
424+
{
425+
"break"
426+
}
427+
})
428+
end,
417429
export = function(self, node)
418430
if #node > 2 then
419431
if node[2] == "class" then

moonscript/transform.moon

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,13 @@ Statement = Transformer {
181181

182182
transformed or node
183183

184+
continue: (node) =>
185+
continue_name = @send"continue"
186+
error "continue must be inside of a loop" unless continue_name
187+
build.group {
188+
build.assign_one continue_name, "true"
189+
{"break"}
190+
}
184191

185192
export: (node) =>
186193
-- assign values if they are included

0 commit comments

Comments
 (0)