Skip to content

Commit ad1bc1e

Browse files
committed
closes #1669; loop results are now collected in the same way as auto-returns are generated
1 parent 2ea51b0 commit ad1bc1e

File tree

4 files changed

+95
-96
lines changed

4 files changed

+95
-96
lines changed

lib/coffee-script/nodes.js

+39-52
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/nodes.coffee

+30-43
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,12 @@ exports.Base = class Base
7676
# Construct a node that returns the current node's result.
7777
# Note that this is overridden for smarter behavior for
7878
# many statement nodes (e.g. If, For)...
79-
makeReturn: ->
80-
new Return this
79+
makeReturn: (res) ->
80+
me = @unwrapAll()
81+
if res
82+
new Call new Literal("#{res}.push"), [me]
83+
else
84+
new Return me
8185

8286
# Does this node, or any of its children, contain a node of a certain kind?
8387
# Recursively traverses down the *children* of the nodes, yielding to a block
@@ -191,12 +195,12 @@ exports.Block = class Block extends Base
191195

192196
# A Block node does not return its entire body, rather it
193197
# ensures that the final expression is returned.
194-
makeReturn: ->
198+
makeReturn: (res) ->
195199
len = @expressions.length
196200
while len--
197201
expr = @expressions[len]
198202
if expr not instanceof Comment
199-
@expressions[len] = expr.makeReturn()
203+
@expressions[len] = expr.makeReturn res
200204
@expressions.splice(len, 1) if expr instanceof Return and not expr.expression
201205
break
202206
this
@@ -281,7 +285,7 @@ exports.Literal = class Literal extends Base
281285
constructor: (@value) ->
282286

283287
makeReturn: ->
284-
if @isStatement() then this else new Return this
288+
if @isStatement() then this else super
285289

286290
isAssignable: ->
287291
IDENTIFIER.test @value
@@ -374,9 +378,6 @@ exports.Value = class Value extends Base
374378
isSplice: ->
375379
last(@properties) instanceof Slice
376380

377-
makeReturn: ->
378-
if @properties.length then super() else @base.makeReturn()
379-
380381
# The value can be unwrapped as its inner node, if there are no attached
381382
# properties.
382383
unwrap: ->
@@ -1210,9 +1211,12 @@ exports.While = class While extends Base
12101211

12111212
isStatement: YES
12121213

1213-
makeReturn: ->
1214-
@returns = yes
1215-
this
1214+
makeReturn: (res) ->
1215+
if res
1216+
super
1217+
else
1218+
@returns = yes
1219+
this
12161220

12171221
addBody: (@body) ->
12181222
this
@@ -1234,10 +1238,9 @@ exports.While = class While extends Base
12341238
if body.isEmpty()
12351239
body = ''
12361240
else
1237-
if o.level > LEVEL_TOP or @returns
1238-
rvar = o.scope.freeVariable 'results'
1241+
if @returns
1242+
body.makeReturn rvar = o.scope.freeVariable 'results'
12391243
set = "#{@tab}#{rvar} = [];\n"
1240-
body = Push.wrap rvar, body if body
12411244
if @guard
12421245
if body.expressions.length > 1
12431246
body.expressions.unshift new If (new Parens @guard).invert(), new Literal "continue"
@@ -1419,9 +1422,9 @@ exports.Try = class Try extends Base
14191422

14201423
jumps: (o) -> @attempt.jumps(o) or @recovery?.jumps(o)
14211424

1422-
makeReturn: ->
1423-
@attempt = @attempt .makeReturn() if @attempt
1424-
@recovery = @recovery.makeReturn() if @recovery
1425+
makeReturn: (res) ->
1426+
@attempt = @attempt .makeReturn res if @attempt
1427+
@recovery = @recovery.makeReturn res if @recovery
14251428
this
14261429

14271430
# Compilation is more or less as you would expect -- the *finally* clause
@@ -1497,7 +1500,6 @@ exports.Parens = class Parens extends Base
14971500

14981501
unwrap : -> @body
14991502
isComplex : -> @body.isComplex()
1500-
makeReturn: -> @body.makeReturn()
15011503

15021504
compileNode: (o) ->
15031505
expr = @body.unwrap()
@@ -1518,7 +1520,7 @@ exports.Parens = class Parens extends Base
15181520
# Unlike Python array comprehensions, they can be multi-line, and you can pass
15191521
# the current index of the loop as a second parameter. Unlike Ruby blocks,
15201522
# you can map and filter in a single pass.
1521-
exports.For = class For extends Base
1523+
exports.For = class For extends While
15221524
constructor: (body, source) ->
15231525
{@source, @guard, @step, @name, @index} = source
15241526
@body = Block.wrap [body]
@@ -1534,14 +1536,6 @@ exports.For = class For extends Base
15341536

15351537
children: ['body', 'source', 'guard', 'step']
15361538

1537-
isStatement: YES
1538-
1539-
jumps: While::jumps
1540-
1541-
makeReturn: ->
1542-
@returns = yes
1543-
this
1544-
15451539
# Welcome to the hairiest method in all of CoffeeScript. Handles the inner
15461540
# loop, filtering, stepping, and result saving for array, object, and range
15471541
# comprehensions. Some of the generated code can be shared in common, and
@@ -1582,7 +1576,7 @@ exports.For = class For extends Base
15821576
if @returns
15831577
resultPart = "#{@tab}#{rvar} = [];\n"
15841578
returnResult = "\n#{@tab}return #{rvar};"
1585-
body = Push.wrap rvar, body
1579+
body.makeReturn rvar
15861580
if @guard
15871581
if body.expressions.length > 1
15881582
body.expressions.unshift new If (new Parens @guard).invert(), new Literal "continue"
@@ -1636,9 +1630,10 @@ exports.Switch = class Switch extends Base
16361630
return block if block.jumps o
16371631
@otherwise?.jumps o
16381632

1639-
makeReturn: ->
1640-
pair[1].makeReturn() for pair in @cases
1641-
@otherwise?.makeReturn()
1633+
makeReturn: (res) ->
1634+
pair[1].makeReturn res for pair in @cases
1635+
@otherwise or= new Block [new Literal 'void 0'] if res
1636+
@otherwise?.makeReturn res
16421637
this
16431638

16441639
compileNode: (o) ->
@@ -1696,9 +1691,10 @@ exports.If = class If extends Base
16961691
compileNode: (o) ->
16971692
if @isStatement o then @compileStatement o else @compileExpression o
16981693

1699-
makeReturn: ->
1700-
@body and= new Block [@body.makeReturn()]
1701-
@elseBody and= new Block [@elseBody.makeReturn()]
1694+
makeReturn: (res) ->
1695+
@elseBody or= new Block [new Literal 'void 0'] if res
1696+
@body and= new Block [@body.makeReturn res]
1697+
@elseBody and= new Block [@elseBody.makeReturn res]
17021698
this
17031699

17041700
ensureBlock: (node) ->
@@ -1752,15 +1748,6 @@ exports.If = class If extends Base
17521748
# Faux-nodes are never created by the grammar, but are used during code
17531749
# generation to generate other combinations of nodes.
17541750

1755-
#### Push
1756-
1757-
# The **Push** creates the tree for `array.push(value)`,
1758-
# which is helpful for recording the result arrays from comprehensions.
1759-
Push =
1760-
wrap: (name, exps) ->
1761-
return exps if exps.isEmpty() or last(exps.expressions).jumps()
1762-
exps.push new Call new Value(new Literal(name), [new Access new Literal 'push']), [exps.pop()]
1763-
17641751
#### Closure
17651752

17661753
# A faux-node used to wrap an expressions body in a closure.

0 commit comments

Comments
 (0)