@@ -76,8 +76,12 @@ exports.Base = class Base
76
76
# Construct a node that returns the current node's result.
77
77
# Note that this is overridden for smarter behavior for
78
78
# 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
81
85
82
86
# Does this node, or any of its children, contain a node of a certain kind?
83
87
# Recursively traverses down the *children* of the nodes, yielding to a block
@@ -191,12 +195,12 @@ exports.Block = class Block extends Base
191
195
192
196
# A Block node does not return its entire body, rather it
193
197
# ensures that the final expression is returned.
194
- makeReturn : ->
198
+ makeReturn : ( res ) ->
195
199
len = @expressions .length
196
200
while len--
197
201
expr = @expressions [len]
198
202
if expr not instanceof Comment
199
- @expressions [len] = expr .makeReturn ()
203
+ @expressions [len] = expr .makeReturn res
200
204
@expressions .splice (len, 1 ) if expr instanceof Return and not expr .expression
201
205
break
202
206
this
@@ -281,7 +285,7 @@ exports.Literal = class Literal extends Base
281
285
constructor : (@value ) ->
282
286
283
287
makeReturn : ->
284
- if @ isStatement () then this else new Return this
288
+ if @ isStatement () then this else super
285
289
286
290
isAssignable : ->
287
291
IDENTIFIER .test @value
@@ -374,9 +378,6 @@ exports.Value = class Value extends Base
374
378
isSplice : ->
375
379
last (@properties ) instanceof Slice
376
380
377
- makeReturn : ->
378
- if @properties .length then super () else @base .makeReturn ()
379
-
380
381
# The value can be unwrapped as its inner node, if there are no attached
381
382
# properties.
382
383
unwrap : ->
@@ -1210,9 +1211,12 @@ exports.While = class While extends Base
1210
1211
1211
1212
isStatement : YES
1212
1213
1213
- makeReturn : ->
1214
- @returns = yes
1215
- this
1214
+ makeReturn : (res ) ->
1215
+ if res
1216
+ super
1217
+ else
1218
+ @returns = yes
1219
+ this
1216
1220
1217
1221
addBody : (@body ) ->
1218
1222
this
@@ -1234,10 +1238,9 @@ exports.While = class While extends Base
1234
1238
if body .isEmpty ()
1235
1239
body = ' '
1236
1240
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'
1239
1243
set = " #{ @tab }#{ rvar} = [];\n "
1240
- body = Push .wrap rvar, body if body
1241
1244
if @guard
1242
1245
if body .expressions .length > 1
1243
1246
body .expressions .unshift new If (new Parens @guard ).invert (), new Literal " continue"
@@ -1419,9 +1422,9 @@ exports.Try = class Try extends Base
1419
1422
1420
1423
jumps : (o ) -> @attempt .jumps (o) or @recovery ? .jumps (o)
1421
1424
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
1425
1428
this
1426
1429
1427
1430
# Compilation is more or less as you would expect -- the *finally* clause
@@ -1497,7 +1500,6 @@ exports.Parens = class Parens extends Base
1497
1500
1498
1501
unwrap : -> @body
1499
1502
isComplex : -> @body .isComplex ()
1500
- makeReturn : -> @body .makeReturn ()
1501
1503
1502
1504
compileNode : (o ) ->
1503
1505
expr = @body .unwrap ()
@@ -1518,7 +1520,7 @@ exports.Parens = class Parens extends Base
1518
1520
# Unlike Python array comprehensions, they can be multi-line, and you can pass
1519
1521
# the current index of the loop as a second parameter. Unlike Ruby blocks,
1520
1522
# you can map and filter in a single pass.
1521
- exports .For = class For extends Base
1523
+ exports .For = class For extends While
1522
1524
constructor : (body , source ) ->
1523
1525
{@source , @guard , @step , @name , @index } = source
1524
1526
@body = Block .wrap [body]
@@ -1534,14 +1536,6 @@ exports.For = class For extends Base
1534
1536
1535
1537
children : [' body' , ' source' , ' guard' , ' step' ]
1536
1538
1537
- isStatement : YES
1538
-
1539
- jumps : While :: jumps
1540
-
1541
- makeReturn : ->
1542
- @returns = yes
1543
- this
1544
-
1545
1539
# Welcome to the hairiest method in all of CoffeeScript. Handles the inner
1546
1540
# loop, filtering, stepping, and result saving for array, object, and range
1547
1541
# comprehensions. Some of the generated code can be shared in common, and
@@ -1582,7 +1576,7 @@ exports.For = class For extends Base
1582
1576
if @returns
1583
1577
resultPart = " #{ @tab }#{ rvar} = [];\n "
1584
1578
returnResult = " \n #{ @tab } return #{ rvar} ;"
1585
- body = Push . wrap rvar, body
1579
+ body . makeReturn rvar
1586
1580
if @guard
1587
1581
if body .expressions .length > 1
1588
1582
body .expressions .unshift new If (new Parens @guard ).invert (), new Literal " continue"
@@ -1636,9 +1630,10 @@ exports.Switch = class Switch extends Base
1636
1630
return block if block .jumps o
1637
1631
@otherwise ? .jumps o
1638
1632
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
1642
1637
this
1643
1638
1644
1639
compileNode : (o ) ->
@@ -1696,9 +1691,10 @@ exports.If = class If extends Base
1696
1691
compileNode : (o ) ->
1697
1692
if @ isStatement o then @ compileStatement o else @ compileExpression o
1698
1693
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]
1702
1698
this
1703
1699
1704
1700
ensureBlock : (node ) ->
@@ -1752,15 +1748,6 @@ exports.If = class If extends Base
1752
1748
# Faux-nodes are never created by the grammar, but are used during code
1753
1749
# generation to generate other combinations of nodes.
1754
1750
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
-
1764
1751
# ### Closure
1765
1752
1766
1753
# A faux-node used to wrap an expressions body in a closure.
0 commit comments