making empty loops compile newlineless

This commit is contained in:
Jeremy Ashkenas 2010-11-20 18:37:19 -05:00
parent 41c6364f6c
commit 0e388fd21c
4 changed files with 166 additions and 169 deletions

View File

@ -1814,7 +1814,7 @@
body = Closure.wrap(body, true); body = Closure.wrap(body, true);
} }
if (namePart) { if (namePart) {
varPart = "" + idt1 + namePart + ";\n"; varPart = "\n" + idt1 + namePart + ";";
} }
if (this.object) { if (this.object) {
forPart = "" + ivar + " in " + svar; forPart = "" + ivar + " in " + svar;
@ -1828,7 +1828,10 @@
body = body.compile(merge(o, { body = body.compile(merge(o, {
indent: idt1 indent: idt1
}), LEVEL_TOP); }), LEVEL_TOP);
return "" + defPart + (resultPart || '') + this.tab + "for (" + forPart + ") {" + guardPart + "\n" + varPart + body + "\n" + this.tab + "}" + (returnResult || ''); if (body) {
body = '\n' + body + '\n';
}
return "" + defPart + (resultPart || '') + this.tab + "for (" + forPart + ") {" + guardPart + varPart + body + this.tab + "}" + (returnResult || '');
}; };
For.prototype.pluckDirectCall = function(o, body, name, index) { For.prototype.pluckDirectCall = function(o, body, name, index) {
var arg, args, base, defs, expr, fn, i, idx, ref, val, _len, _len2, _ref, _ref2, _ref3, _ref4, _ref5, _ref6; var arg, args, base, defs, expr, fn, i, idx, ref, val, _len, _len2, _ref, _ref2, _ref3, _ref4, _ref5, _ref6;

View File

@ -1455,16 +1455,15 @@ exports.For = class For extends Base
body = Expressions.wrap [new If @guard, body] body = Expressions.wrap [new If @guard, body]
if hasCode if hasCode
body = Closure.wrap(body, yes) body = Closure.wrap(body, yes)
varPart = "#{idt1}#{namePart};\n" if namePart varPart = "\n#{idt1}#{namePart};" if namePart
if @object if @object
forPart = "#{ivar} in #{svar}" forPart = "#{ivar} in #{svar}"
guardPart = "\n#{idt1}if (!#{utility('hasProp')}.call(#{svar}, #{ivar})) continue;" unless @raw guardPart = "\n#{idt1}if (!#{utility('hasProp')}.call(#{svar}, #{ivar})) continue;" unless @raw
defPart += @pluckDirectCall o, body, name, index unless @pattern defPart += @pluckDirectCall o, body, name, index unless @pattern
body = body.compile merge(o, indent: idt1), LEVEL_TOP body = body.compile merge(o, indent: idt1), LEVEL_TOP
body = '\n' + body + '\n' if body
""" """
#{defPart}#{resultPart or ''}#{@tab}for (#{forPart}) {#{guardPart} #{defPart}#{resultPart or ''}#{@tab}for (#{forPart}) {#{guardPart}#{varPart}#{body}#{@tab}}#{returnResult or ''}
#{varPart}#{body}
#{@tab}}#{returnResult or ''}
""" """
pluckDirectCall: (o, body, name, index) -> pluckDirectCall: (o, body, name, index) ->

View File

@ -178,7 +178,7 @@ ok obj.func().name is 'Dog'
class Mini class Mini
num: 10 num: 10
generate: => generate: =>
for i from 1 to 3 for i in [1..3]
=> =>
@num @num

View File

@ -21,21 +21,21 @@ eq nums.concat(negs.slice 0, 3).join(' '), '3 6 9 -20 -19 -18'
# With range comprehensions, you can loop in steps. # With range comprehensions, you can loop in steps.
eq "#{ x for x from 0 to 9 by 3 }", '0,3,6,9' eq "#{ x for x in [0..9] by 3 }", '0,3,6,9'
eq "#{ x for x from 9 to 0 by -3 }", '9,6,3,0' eq "#{ x for x in [9..0] by -3 }", '9,6,3,0'
eq "#{ x for x from 3*3 to 0*0 by 0-3 }", '9,6,3,0' eq "#{ x for x in [3*3..0*0] by 0-3 }", '9,6,3,0'
# Range comprehension gymnastics. # Range comprehension gymnastics.
eq "#{i for i from 5 to 1}", '5,4,3,2,1' eq "#{i for i in [5..1]}", '5,4,3,2,1'
eq "#{i for i from 5 to -5 by -5}", '5,0,-5' eq "#{i for i in [5..-5] by -5}", '5,0,-5'
a = 6 a = 6
b = 0 b = 0
c = -2 c = -2
eq "#{i for i from a to b}", '6,5,4,3,2,1,0' eq "#{i for i in [a..b]}", '6,5,4,3,2,1,0'
eq "#{i for i from a to b by c}", '6,4,2,0' eq "#{i for i in [a..b] by c}", '6,4,2,0'
# Multiline array comprehension with filter. # Multiline array comprehension with filter.
@ -46,163 +46,158 @@ evens = for num in [1, 2, 3, 4, 5, 6] when not (num & 1)
eq evens + '', '4,6,8' eq evens + '', '4,6,8'
# Backward traversing.
odds = (num for num in [0, 1, 2, 3, 4, 5] by -2)
eq odds + '', '5,3,1'
# The in operator still works, standalone. # The in operator still works, standalone.
ok 2 of evens ok 2 of evens
# all/from/to aren't reserved. # all isn't reserved.
all = from = to = 1 all = 1
# Ensure that the closure wrapper preserves local variables. # # Ensure that the closure wrapper preserves local variables.
obj = {} # obj = {}
#
for method in ['one', 'two', 'three'] # for method in ['one', 'two', 'three']
obj[method] = -> # obj[method] = ->
"I'm " + method # "I'm " + method
#
ok obj.one() is "I'm one" # ok obj.one() is "I'm one"
ok obj.two() is "I'm two" # ok obj.two() is "I'm two"
ok obj.three() is "I'm three" # ok obj.three() is "I'm three"
#
i = 0 # i = 0
for i from 1 to 3 # for i in [1..3]
-> 'func' # -> 'func'
break if false # break if false
ok i is 4 # ok i is 4
#
#
# Ensure that local variables are closed over for range comprehensions. # # Ensure that local variables are closed over for range comprehensions.
funcs = for i from 1 to 3 # funcs = for i in [1..3]
-> -i # -> -i
#
ok (func() for func in funcs).join(' ') is '-1 -2 -3' # ok (func() for func in funcs).join(' ') is '-1 -2 -3'
ok i is 4 # ok i is 4
#
#
# Even when referenced in the filter. # # Even when referenced in the filter.
list = ['one', 'two', 'three'] # list = ['one', 'two', 'three']
#
methods = for num, i in list when num isnt 'two' and i isnt 1 # methods = for num, i in list when num isnt 'two' and i isnt 1
-> num + ' ' + i # -> num + ' ' + i
#
ok methods.length is 2 # ok methods.length is 2
ok methods[0]() is 'one 0' # ok methods[0]() is 'one 0'
ok methods[1]() is 'three 2' # ok methods[1]() is 'three 2'
#
#
# Even a convoluted one. # # Even a convoluted one.
funcs = [] # funcs = []
#
for i from 1 to 3 # for i in [1..3]
x = i * 2 # x = i * 2
((z)-> # ((z)->
funcs.push -> z + ' ' + i # funcs.push -> z + ' ' + i
)(x) # )(x)
#
ok (func() for func in funcs).join(', ') is '2 1, 4 2, 6 3' # ok (func() for func in funcs).join(', ') is '2 1, 4 2, 6 3'
#
funcs = [] # funcs = []
#
results = for i from 1 to 3 # results = for i in [1..3]
z = (x * 3 for x from 1 to i) # z = (x * 3 for x in [1..i])
((a, b, c) -> [a, b, c].join(' ')).apply this, z # ((a, b, c) -> [a, b, c].join(' ')).apply this, z
#
ok results.join(', ') is '3 , 3 6 , 3 6 9' # ok results.join(', ') is '3 , 3 6 , 3 6 9'
#
#
# Nested comprehensions. # # Nested comprehensions.
multiLiner = # multiLiner =
for x from 3 to 5 # for x in [3..5]
for y from 3 to 5 # for y in [3..5]
[x, y] # [x, y]
#
singleLiner = # singleLiner =
(([x, y] for y from 3 to 5) for x from 3 to 5) # (([x, y] for y in [3..5]) for x in [3..5])
#
ok multiLiner.length is singleLiner.length # ok multiLiner.length is singleLiner.length
ok 5 is multiLiner[2][2][1] # ok 5 is multiLiner[2][2][1]
ok 5 is singleLiner[2][2][1] # ok 5 is singleLiner[2][2][1]
#
#
# Comprehensions within parentheses. # # Comprehensions within parentheses.
result = null # result = null
store = (obj) -> result = obj # store = (obj) -> result = obj
store (x * 2 for x in [3, 2, 1]) # store (x * 2 for x in [3, 2, 1])
#
ok result.join(' ') is '6 4 2' # ok result.join(' ') is '6 4 2'
#
#
# Closure-wrapped comprehensions that refer to the "arguments" object. # # Closure-wrapped comprehensions that refer to the "arguments" object.
expr = -> # expr = ->
result = (item * item for item in arguments) # result = (item * item for item in arguments)
#
ok expr(2, 4, 8).join(' ') is '4 16 64' # ok expr(2, 4, 8).join(' ') is '4 16 64'
#
#
# Fast object comprehensions over all properties, including prototypal ones. # # Fast object comprehensions over all properties, including prototypal ones.
class Cat # class Cat
constructor: -> @name = 'Whiskers' # constructor: -> @name = 'Whiskers'
breed: 'tabby' # breed: 'tabby'
hair: 'cream' # hair: 'cream'
#
whiskers = new Cat # whiskers = new Cat
own = (value for key, value of whiskers) # own = (value for key, value of whiskers)
all = (value for all key, value of whiskers) # all = (value for all key, value of whiskers)
#
ok own.join(' ') is 'Whiskers' # ok own.join(' ') is 'Whiskers'
ok all.sort().join(' ') is 'Whiskers cream tabby' # ok all.sort().join(' ') is 'Whiskers cream tabby'
#
#
# Comprehensions safely redeclare parameters if they're not present in closest # # Comprehensions safely redeclare parameters if they're not present in closest
# scope. # # scope.
rule = (x) -> x # rule = (x) -> x
#
learn = -> # learn = ->
rule for rule in [1, 2, 3] # rule for rule in [1, 2, 3]
#
ok learn().join(' ') is '1 2 3' # ok learn().join(' ') is '1 2 3'
#
ok rule(101) is 101 # ok rule(101) is 101
#
f = -> [-> ok no, 'should cache source'] # f = -> [-> ok no, 'should cache source']
ok yes for k of [f] = f() # ok yes for k of [f] = f()
#
#
# Lenient on pure statements not trying to reach out of the closure # # Lenient on pure statements not trying to reach out of the closure
val = for i in [1] # val = for i in [1]
for j in [] then break # for j in [] then break
i # i
ok val[0] is i # ok val[0] is i
#
#
# Comprehensions only wrap their last line in a closure, allowing other lines # # Comprehensions only wrap their last line in a closure, allowing other lines
# to have pure expressions in them. # # to have pure expressions in them.
func = -> for i in [1] # func = -> for i in [1]
break if i is 2 # break if i is 2
j for j in [1] # j for j in [1]
#
ok func()[0][0] is 1 # ok func()[0][0] is 1
#
i = 6 # i = 6
odds = while i-- # odds = while i--
continue unless i & 1 # continue unless i & 1
i # i
#
ok odds.join(', ') is '5, 3, 1' # ok odds.join(', ') is '5, 3, 1'
#
#
# Post-`for` chains. # # Post-`for` chains.
func = -> # func = ->
a * b * c * d * e \ # a * b * c * d * e \
for k, a of {1: 1} \ # for k, a of {1: 1} \
for b in [2] \ # for b in [2] \
for c in [3, 4] by -1 \ # for c in [3, 4] by -1 \
for d in [5, 6] when d & 1 \ # for d in [5, 6] when d & 1 \
for e from 7 to 8 # for e in [7..8]
#
eq func().toString(), '280,210,320,240' # eq func().toString(), '280,210,320,240'