converted the tests to use optional parentheses -- lot's of little subtleties to work out

This commit is contained in:
Jeremy Ashkenas 2010-01-24 23:40:45 -05:00
parent 70e3a6ef2f
commit a5d39efdd2
25 changed files with 106 additions and 101 deletions

View File

@ -55,7 +55,7 @@
<key>name</key> <key>name</key>
<string>variable.parameter.function.coffee</string> <string>variable.parameter.function.coffee</string>
</dict> </dict>
<key>2</key> <key>3</key>
<dict> <dict>
<key>name</key> <key>name</key>
<string>storage.type.function.coffee</string> <string>storage.type.function.coffee</string>
@ -64,7 +64,7 @@
<key>comment</key> <key>comment</key>
<string>match stuff like: a =&gt; … </string> <string>match stuff like: a =&gt; … </string>
<key>match</key> <key>match</key>
<string>([a-zA-Z0-9_?., $*]*)\s*(=+&gt;)</string> <string>([a-zA-Z0-9_?.$]*(,\s*[a-zA-Z0-9_?.$]+)*)\s*(=+&gt;)</string>
<key>name</key> <key>name</key>
<string>meta.inline.function.coffee</string> <string>meta.inline.function.coffee</string>
</dict> </dict>

View File

@ -163,7 +163,7 @@ module CoffeeScript
@line += indent.scan(MULTILINER).size @line += indent.scan(MULTILINER).size
@i += indent.size @i += indent.size
next_character = @chunk[MULTI_DENT, 4] next_character = @chunk[MULTI_DENT, 4]
no_newlines = next_character == '.' || (last_value.to_s.match(NO_NEWLINE) && !last_value.match(CODE)) no_newlines = next_character == '.' || (last_value.to_s.match(NO_NEWLINE) && @tokens[-2][0] != '.' && !last_value.match(CODE))
return suppress_newlines(indent) if no_newlines return suppress_newlines(indent) if no_newlines
size = indent.scan(LAST_DENT).last.last.length size = indent.scan(LAST_DENT).last.last.length
return newline_token(indent) if size == @indent return newline_token(indent) if size == @indent
@ -242,13 +242,19 @@ module CoffeeScript
# make use of splats. # make use of splats.
def tag_parameters def tag_parameters
i = 0 i = 0
tagged = false
loop do loop do
i -= 1 i -= 1
tok = @tokens[i] tok = @tokens[i]
return if !tok return if !tok
next if ['.', ','].include?(tok[0]) if ['.', ','].include?(tok[0])
tagged = false
next
end
return if tagged
return if tok[0] != :IDENTIFIER return if tok[0] != :IDENTIFIER
tok[0] = :PARAM tok[0] = :PARAM
tagged = true
end end
end end

View File

@ -17,9 +17,11 @@ module CoffeeScript
# Tokens that indicate the close of a clause of an expression. # Tokens that indicate the close of a clause of an expression.
EXPRESSION_CLOSE = [:CATCH, :WHEN, :ELSE, :FINALLY] + EXPRESSION_TAIL EXPRESSION_CLOSE = [:CATCH, :WHEN, :ELSE, :FINALLY] + EXPRESSION_TAIL
# Tokens that, when immediately following an identifier, activate an # Tokens pairs that, in immediate succession, indicate an implicit call.
# implicit method call. IMPLICIT_FUNC = [:IDENTIFIER, :SUPER]
IMPLICIT_CALL = [:IDENTIFIER, :NUMBER, :STRING, :JS, :REGEX] IMPLICIT_CALL = [:IDENTIFIER, :NUMBER, :STRING, :JS, :REGEX, :NEW, :PARAM,
:TRY, :DELETE, :INSTANCEOF, :TYPEOF, :SWITCH, :ARGUMENTS,
:TRUE, :FALSE, :YES, :NO, :ON, :OFF, '!', '!!', :NOT]
# The inverse mappings of token pairs we're trying to fix up. # The inverse mappings of token pairs we're trying to fix up.
INVERSES = BALANCED_PAIRS.inject({}) do |memo, pair| INVERSES = BALANCED_PAIRS.inject({}) do |memo, pair|
@ -42,8 +44,8 @@ module CoffeeScript
remove_leading_newlines remove_leading_newlines
remove_mid_expression_newlines remove_mid_expression_newlines
move_commas_outside_outdents move_commas_outside_outdents
add_implicit_indentation
add_implicit_parentheses add_implicit_parentheses
add_implicit_indentation
ensure_balance(*BALANCED_PAIRS) ensure_balance(*BALANCED_PAIRS)
rewrite_closing_parens rewrite_closing_parens
@tokens @tokens
@ -156,7 +158,7 @@ module CoffeeScript
open = false open = false
next 2 next 2
end end
next 1 unless prev[0] == :IDENTIFIER && IMPLICIT_CALL.include?(token[0]) next 1 unless IMPLICIT_FUNC.include?(prev[0]) && IMPLICIT_CALL.include?(token[0])
@tokens.insert(i, ['(', Value.new('(', token[1].line)]) @tokens.insert(i, ['(', Value.new('(', token[1].line)])
open = true open = true
next 2 next 2

View File

@ -1,4 +1,4 @@
results: [1, 2, 3].map() x => results: [1, 2, 3].map() x =>
x * x x * x
print(results.join(' ') is '1 4 9') print results.join(' ') is '1 4 9'

View File

@ -18,19 +18,19 @@ ThirdChild extends SecondChild
ThirdChild::func: string => ThirdChild::func: string =>
super('three/') + string super('three/') + string
result: (new ThirdChild()).func('four') result: (new ThirdChild()).func 'four'
print(result is 'zero/one/two/three/four') print result is 'zero/one/two/three/four'
TopClass: arg => TopClass: arg =>
this.prop: 'top-' + arg this.prop: 'top-' + arg
SuperClass: arg => SuperClass: arg =>
super('super-' + arg) super 'super-' + arg
SubClass: => SubClass: =>
super('sub') super 'sub'
SuperClass extends TopClass SuperClass extends TopClass
SubClass extends SuperClass SubClass extends SuperClass

View File

@ -2,7 +2,7 @@ identity_wrap: x => => x
result: identity_wrap(identity_wrap(true))()() result: identity_wrap(identity_wrap(true))()()
print(result) print result
str: 'god' str: 'god'
@ -13,7 +13,7 @@ result: str.
reverse(). reverse().
reverse() reverse()
print(result.join('') is 'dog') print result.join('') is 'dog'
result: str result: str
.split('') .split('')
@ -21,4 +21,4 @@ result: str
.reverse() .reverse()
.reverse() .reverse()
print(result.join('') is 'dog') print result.join('') is 'dog'

View File

@ -3,26 +3,26 @@ b: -2
[a, b]: [b, a] [a, b]: [b, a]
print(a is -2) print a is -2
print(b is -1) print b is -1
arr: [1, 2, 3] arr: [1, 2, 3]
[a, b, c]: arr [a, b, c]: arr
print(a is 1) print a is 1
print(b is 2) print b is 2
print(c is 3) print c is 3
obj: {x: 10, y: 20, z: 30} obj: {x: 10, y: 20, z: 30}
{x: a, y: b, z: c}: obj {x: a, y: b, z: c}: obj
print(a is 10) print a is 10
print(b is 20) print b is 20
print(c is 30) print c is 30
person: { person: {
@ -42,8 +42,8 @@ person: {
{name: a, family: {brother: {addresses: [one, {city: b}]}}}: person {name: a, family: {brother: {addresses: [one, {city: b}]}}}: person
print(a is "Bob") print a is "Bob"
print(b is "Moquasset NY, 10021") print b is "Moquasset NY, 10021"
test: { test: {
@ -59,4 +59,4 @@ test: {
{person: {address: [ignore, addr...]}}: test {person: {address: [ignore, addr...]}}: test
print(addr.join(', ') is "Street 101, Apt 101, City 101") print addr.join(', ') is "Street 101, Apt 101, City 101"

View File

@ -3,7 +3,7 @@ func: =>
b: [] b: []
while a >= 0 while a >= 0
b.push('o') b.push 'o'
a-- a--
c: { c: {
@ -26,4 +26,4 @@ func: =>
c.single: c.list[1..1][0] c.single: c.list[1..1][0]
print(func() is '-') print func() is '-'

View File

@ -12,7 +12,7 @@ a: null
a ?= 10 a ?= 10
b ?= 10 b ?= 10
print(a is 10 and b is 10) print a is 10 and b is 10
# The existential operator. # The existential operator.
@ -20,7 +20,7 @@ print(a is 10 and b is 10)
z: null z: null
x: z ? "EX" x: z ? "EX"
print(z is null and x is "EX") print z is null and x is "EX"
# Only evaluate once. # Only evaluate once.
@ -39,17 +39,17 @@ obj: {
prop: "hello" prop: "hello"
} }
print(obj?.prop is "hello") print obj?.prop is "hello"
print(obj?.prop?.non?.existent?.property is undefined) print obj?.prop?.non?.existent?.property is undefined
# Soaks and caches method calls as well. # Soaks and caches method calls as well.
arr: ["--", "----"] arr: ["--", "----"]
print(arr.pop()?.length is 4) print arr.pop()?.length is 4
print(arr.pop()?.length is 2) print arr.pop()?.length is 2
print(arr.pop()?.length is undefined) print arr.pop()?.length is undefined
print(arr[0]?.length is undefined) print arr[0]?.length is undefined
print(arr.pop()?.length?.non?.existent()?.property is undefined) print arr.pop()?.length?.non?.existent()?.property is undefined

View File

@ -9,7 +9,7 @@ findit: items =>
for item in items for item in items
return item if item is "bacon" return item if item is "bacon"
print(findit(items) is "bacon") print findit(items) is "bacon"
# When when a closure wrapper is generated for expression conversion, make sure # When when a closure wrapper is generated for expression conversion, make sure
@ -26,5 +26,5 @@ obj: {
this.num this.num
} }
print(obj.num is obj.func()) print obj.num is obj.func()
print(obj.num is obj.result) print obj.num is obj.result

View File

@ -7,4 +7,4 @@ result: if a
if d if d
true true
print(result) print result

View File

@ -2,10 +2,10 @@ x: 1
y: {} y: {}
y.x: => 3 y.x: => 3
print(x is 1) print x is 1
print(typeof(y.x) is 'function') print typeof(y.x) is 'function'
print(y.x() is 3) print y.x() is 3
print(y.x.name is 'x') print y.x.name is 'x'
# The empty function should not cause a syntax error. # The empty function should not cause a syntax error.
@ -40,9 +40,9 @@ memoize: fn =>
Math: { Math: {
Add: a, b => a + b Add: a, b => a + b
AnonymousAdd: (a, b => a + b) AnonymousAdd: (a, b => a + b)
FastAdd: memoize() a, b => a + b FastAdd: memoize a, b => a + b
} }
print(Math.Add(5, 5) is 10) print Math.Add(5, 5) is 10
print(Math.AnonymousAdd(10, 10) is 20) print Math.AnonymousAdd(10, 10) is 20
print(Math.FastAdd(20, 20) is 40) print Math.FastAdd(20, 20) is 40

View File

@ -18,4 +18,4 @@ switch 'string'
code() code()
# comment # comment
print(func()) print func()

View File

@ -3,7 +3,7 @@ a: """
on two lines on two lines
""" """
print(a is "basic heredoc\non two lines") print a is "basic heredoc\non two lines"
a: ''' a: '''
@ -12,12 +12,12 @@ a: '''
c c
''' '''
print(a is "a\n \"b\nc") print a is "a\n \"b\nc"
a: '''one-liner''' a: '''one-liner'''
print(a is 'one-liner') print a is 'one-liner'
a: """ a: """
@ -25,7 +25,7 @@ a: """
here here
""" """
print(a is "out\nhere") print a is "out\nhere"
a: ''' a: '''
@ -34,7 +34,7 @@ a: '''
c c
''' '''
print(a is " a\n b\nc") print a is " a\n b\nc"
a: ''' a: '''
a a
@ -43,4 +43,4 @@ a
b c b c
''' '''
print(a is "a\n\n\nb c") print a is "a\n\n\nb c"

View File

@ -1,10 +1,10 @@
num: 1 + 2 + (a: 3) num: 1 + 2 + (a: 3)
print(num is 6) print num is 6
result: if true result: if true
false false
other: "result" other: "result"
print(result is "result" and other is "result") print result is "result" and other is "result"

View File

@ -1,37 +1,37 @@
a: [(x => x), (x => x * x)] a: [(x => x), (x => x * x)]
print(a.length is 2) print a.length is 2
regex: /match/i regex: /match/i
words: "I think there is a match in here." words: "I think there is a match in here."
print(!!words.match(regex)) print !!words.match(regex)
neg: (3 -4) neg: (3 -4)
print(neg is -1) print neg is -1
func: => func: =>
return if true return if true
print(func() is null) print func() is null
str: "\\" str: "\\"
reg: /\\/ reg: /\\/
print(reg(str) and str is '\\') print reg(str) and str is '\\'
i: 10 i: 10
while i -= 1 while i -= 1
print(i is 0) print i is 0
money$: 'dollars' money$: 'dollars'
print(money$ is 'dollars') print money$ is 'dollars'

View File

@ -6,6 +6,6 @@ multi_liner:
single_liner: single_liner:
[x, y] for y in [3..5] for x in [3..5] [x, y] for y in [3..5] for x in [3..5]
print(multi_liner.length is single_liner.length) print multi_liner.length is single_liner.length
print(5 is multi_liner[2][2][1]) print 5 is multi_liner[2][2][1]
print(5 is single_liner[2][2][1]) print 5 is single_liner[2][2][1]

View File

@ -3,4 +3,4 @@ six:
2 + 2 +
3 3
print(six is 6) print six is 6

View File

@ -1,12 +1,12 @@
# CoffeeScript's operations should be chainable, like Python's. # CoffeeScript's operations should be chainable, like Python's.
print(500 > 50 > 5 > -5) print 500 > 50 > 5 > -5
print(true is not false is true is not false) print true is not false is true is not false
print(10 < 20 > 10) print 10 < 20 > 10
print(50 > 10 > 5 is parseInt('5', 10)) print 50 > 10 > 5 is parseInt('5', 10)
# Make sure that each argument is only evaluated once, even if used # Make sure that each argument is only evaluated once, even if used
@ -15,4 +15,4 @@ print(50 > 10 > 5 is parseInt('5', 10))
i: 0 i: 0
func: => i++ func: => i++
print(1 > func() < 1) print 1 > func() < 1

View File

@ -5,16 +5,16 @@ negs: negs[0..2]
result: nums.concat(negs).join(', ') result: nums.concat(negs).join(', ')
print(result is '3, 6, 9, -20, -19, -18') print result is '3, 6, 9, -20, -19, -18'
# Ensure that ranges are safe. This used to infinite loop: # Ensure that ranges are safe. This used to infinite loop:
j = 5 j = 5
result: for j in [j..(j+3)] result: for j in [j..(j+3)]
j j
print(result.join(' ') is '5 6 7 8') print result.join(' ') is '5 6 7 8'
# With range comprehensions, you can loop in steps. # With range comprehensions, you can loop in steps.
results: x for x in [0..25] by 5 results: x for x in [0..25] by 5
print(results.join(' ') is '0 5 10 15 20 25') print results.join(' ') is '0 5 10 15 20 25'

View File

@ -5,7 +5,7 @@ b: array[2...4]
result: a.concat(b).join(' ') result: a.concat(b).join(' ')
print(result is "7 8 9 2 3") print result is "7 8 9 2 3"
countdown: [10..1].join(' ') countdown: [10..1].join(' ')
print(countdown is "10 9 8 7 6 5 4 3 2 1") print countdown is "10 9 8 7 6 5 4 3 2 1"

View File

@ -1,9 +1,9 @@
func: first, second, rest... => func: first, second, rest... =>
rest.join(' ') rest.join ' '
result: func(1, 2, 3, 4, 5) result: func 1, 2, 3, 4, 5
print(result is "3 4 5") print result is "3 4 5"
gold: silver: bronze: the_field: null gold: silver: bronze: the_field: null
@ -27,9 +27,9 @@ contenders: [
"Usain Bolt" "Usain Bolt"
] ]
medalists("Mighty Mouse", contenders...) medalists "Mighty Mouse", contenders...
print(gold is "Mighty Mouse") print gold is "Mighty Mouse"
print(silver is "Michael Phelps") print silver is "Michael Phelps"
print(bronze is "Liu Xiang") print bronze is "Liu Xiang"
print(the_field.length is 8) print the_field.length is 8

View File

@ -1,7 +1,5 @@
array: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] array: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
array[5..10]: [0, 0, 0] array[5..10]: [0, 0, 0]
print(array.join(' ') is '0 1 2 3 4 0 0 0') print array.join(' ') is '0 1 2 3 4 0 0 0'

View File

@ -14,8 +14,7 @@ result: switch num
when 11 then false when 11 then false
else false else false
print(result) print result
func: num => func: num =>
switch num switch num
@ -25,7 +24,7 @@ func: num =>
false false
else false else false
print(func(2)) print func(2)
print(func(6)) print func(6)
print(!func(3)) print !func(3)
print(!func(8)) print !func(8)

View File

@ -1,17 +1,17 @@
i: 100 i: 100
while i -= 1 while i -= 1
print(i is 0) print i is 0
i: 5 i: 5
list: while i -= 1 list: while i -= 1
i * 2 i * 2
print(list.join(' ') is "8 6 4 2") print list.join(' ') is "8 6 4 2"
i: 5 i: 5
list: (i * 3 while i -= 1) list: (i * 3 while i -= 1)
print(list.join(' ') is "12 9 6 3") print list.join(' ') is "12 9 6 3"