2010-12-03 19:43:45 +00:00
|
|
|
#### Operators
|
|
|
|
|
2010-12-03 18:01:13 +00:00
|
|
|
# binary (2-ary) math operators do not require spaces
|
|
|
|
(->
|
|
|
|
a = 1
|
|
|
|
b = -1
|
2010-12-03 19:43:45 +00:00
|
|
|
eq a*-b, 1
|
|
|
|
eq a*+b, -1
|
|
|
|
eq a/-b, 1
|
|
|
|
eq a/+b, -1
|
2010-12-03 18:01:13 +00:00
|
|
|
)()
|
2010-09-12 15:08:05 +00:00
|
|
|
|
2010-12-03 18:01:13 +00:00
|
|
|
# operators should respect new lines as spaced
|
|
|
|
(->
|
|
|
|
a = 123 +
|
|
|
|
456
|
2010-12-03 19:43:45 +00:00
|
|
|
eq a, 579
|
2010-09-12 15:08:05 +00:00
|
|
|
|
2010-12-03 18:01:13 +00:00
|
|
|
b = "1#{2}3" +
|
|
|
|
"456"
|
2010-12-03 19:43:45 +00:00
|
|
|
eq b, '123456'
|
2010-12-03 18:01:13 +00:00
|
|
|
)()
|
2010-09-12 15:08:05 +00:00
|
|
|
|
2010-12-03 18:01:13 +00:00
|
|
|
# multiple operators should space themselves
|
2010-12-03 19:43:45 +00:00
|
|
|
eq (+ +1), (- -1)
|
2010-09-12 15:08:05 +00:00
|
|
|
|
2010-12-03 18:01:13 +00:00
|
|
|
# bitwise operators
|
|
|
|
(->
|
2010-12-03 19:43:45 +00:00
|
|
|
eq (10 & 3), 2
|
|
|
|
eq (10 | 3), 11
|
|
|
|
eq (10 ^ 3), 9
|
|
|
|
eq (10 << 3), 80
|
|
|
|
eq (10 >> 3), 1
|
|
|
|
eq (10 >>> 3), 1
|
|
|
|
|
|
|
|
num = 10; eq (num &= 3), 2
|
|
|
|
num = 10; eq (num |= 3), 11
|
|
|
|
num = 10; eq (num ^= 3), 9
|
|
|
|
num = 10; eq (num <<= 3), 80
|
|
|
|
num = 10; eq (num >>= 3), 1
|
|
|
|
num = 10; eq (num >>>= 3), 1
|
2010-12-03 18:01:13 +00:00
|
|
|
)()
|
2010-09-12 15:08:05 +00:00
|
|
|
|
2010-12-03 18:01:13 +00:00
|
|
|
# `instanceof`
|
|
|
|
(->
|
|
|
|
ok new String instanceof String
|
|
|
|
ok new Boolean instanceof Boolean
|
|
|
|
# `instanceof` supports negation by prefixing the operator with `not`
|
|
|
|
ok new Number not instanceof String
|
|
|
|
ok new Array not instanceof Boolean
|
|
|
|
)()
|
2010-08-08 04:07:00 +00:00
|
|
|
|
2010-08-11 23:24:59 +00:00
|
|
|
|
2010-12-03 19:43:45 +00:00
|
|
|
#### compound assignment operators
|
2010-12-03 18:01:13 +00:00
|
|
|
(->
|
2010-08-11 23:24:59 +00:00
|
|
|
|
2010-12-03 18:01:13 +00:00
|
|
|
# boolean operators
|
|
|
|
(->
|
|
|
|
a = 0
|
|
|
|
a or= 2
|
|
|
|
eq a, 2
|
|
|
|
|
|
|
|
b = 1
|
|
|
|
b or= 2
|
|
|
|
eq b, 1
|
|
|
|
|
|
|
|
c = 0
|
|
|
|
c and= 2
|
|
|
|
eq c, 0
|
|
|
|
|
|
|
|
d = 1
|
|
|
|
d and= 2
|
|
|
|
eq d, 2
|
|
|
|
|
|
|
|
# ensure that RHS is treated as a group
|
|
|
|
e = f = false
|
|
|
|
e and= f or true
|
2010-12-03 19:43:45 +00:00
|
|
|
eq e, false
|
2010-12-03 18:01:13 +00:00
|
|
|
)()
|
|
|
|
|
|
|
|
# compound assignment as a sub expression
|
|
|
|
(->
|
|
|
|
[a, b, c] = [1, 2, 3]
|
2010-12-03 19:43:45 +00:00
|
|
|
eq (a + b += c), 6
|
|
|
|
eq a, 1
|
|
|
|
eq b, 5
|
|
|
|
eq c, 3
|
2010-12-03 18:01:13 +00:00
|
|
|
)()
|
|
|
|
|
|
|
|
# compound assignment should be careful about caching variables
|
|
|
|
(->
|
|
|
|
count = 0
|
|
|
|
list = []
|
|
|
|
|
|
|
|
list[++count] or= 1
|
|
|
|
eq list[1], 1
|
|
|
|
eq count, 1
|
|
|
|
|
|
|
|
list[++count] ?= 2
|
|
|
|
eq list[2], 2
|
|
|
|
eq count, 2
|
|
|
|
|
|
|
|
list[count++] and= 'two'
|
|
|
|
eq list[2], 'two'
|
|
|
|
eq count, 3
|
|
|
|
|
|
|
|
base = ->
|
|
|
|
++count
|
|
|
|
base
|
|
|
|
|
|
|
|
base().four or= 4
|
|
|
|
eq base.four, 4
|
|
|
|
eq count, 4
|
|
|
|
|
|
|
|
base().five ?= 5
|
|
|
|
eq base.five, 5
|
|
|
|
eq count, 5
|
|
|
|
)()
|
|
|
|
|
|
|
|
# compound assignment with implicit objects
|
|
|
|
(->
|
|
|
|
obj = undefined
|
|
|
|
obj ?=
|
|
|
|
one: 1
|
|
|
|
|
2010-12-03 19:43:45 +00:00
|
|
|
eq obj.one, 1
|
2010-12-03 18:01:13 +00:00
|
|
|
|
|
|
|
obj and=
|
|
|
|
two: 2
|
|
|
|
|
2010-12-03 19:43:45 +00:00
|
|
|
eq obj.one, undefined
|
|
|
|
eq obj.two, 2
|
2010-12-03 18:01:13 +00:00
|
|
|
)()
|
2010-08-11 23:24:59 +00:00
|
|
|
|
2010-12-03 18:01:13 +00:00
|
|
|
)()
|
2010-08-11 23:24:59 +00:00
|
|
|
|
|
|
|
|
2010-12-03 19:43:45 +00:00
|
|
|
#### `is`,`isnt`,`==`,`!=`
|
2010-12-03 18:01:13 +00:00
|
|
|
(->
|
2010-08-12 03:14:50 +00:00
|
|
|
|
2010-12-03 18:01:13 +00:00
|
|
|
# `==` and `is` should be interchangeable.
|
|
|
|
(->
|
|
|
|
a = b = 1
|
|
|
|
ok a is 1 and b == 1
|
|
|
|
ok a == b
|
|
|
|
ok a is b
|
|
|
|
)()
|
|
|
|
|
|
|
|
# `!=` and `isnt` should be interchangeable.
|
|
|
|
(->
|
|
|
|
a = 0
|
|
|
|
b = 1
|
|
|
|
ok a isnt 1 and b != 0
|
|
|
|
ok a != b
|
|
|
|
ok a isnt b
|
|
|
|
)()
|
2010-08-12 03:14:50 +00:00
|
|
|
|
2010-12-03 18:01:13 +00:00
|
|
|
)()
|
2010-08-12 03:14:50 +00:00
|
|
|
|
2010-08-14 18:43:25 +00:00
|
|
|
|
2010-12-03 19:43:45 +00:00
|
|
|
#### `in`, `of`
|
2010-12-03 18:01:13 +00:00
|
|
|
(->
|
2010-08-14 18:43:25 +00:00
|
|
|
|
2010-12-03 18:01:13 +00:00
|
|
|
# `in` should check if an array contains a value using `indexOf`
|
|
|
|
# `of` should check if a property is defined on an object using `in`
|
|
|
|
(->
|
|
|
|
arr = [1]
|
|
|
|
ok 0 of arr
|
|
|
|
ok 1 in arr
|
|
|
|
# prefixing `not` to `in and `of` should negate them
|
|
|
|
ok 1 not of arr
|
|
|
|
ok 0 not in arr
|
|
|
|
)()
|
|
|
|
|
|
|
|
# `in` should be able to operate on an array literal
|
|
|
|
(->
|
|
|
|
ok 2 in [0, 1, 2, 3]
|
|
|
|
ok 4 not in [0, 1, 2, 3]
|
|
|
|
arr = [0, 1, 2, 3]
|
|
|
|
ok 2 in arr
|
|
|
|
ok 4 not in arr
|
|
|
|
# should cache the value used to test the array
|
|
|
|
arr = [0]
|
|
|
|
val = 0
|
|
|
|
ok val++ in arr
|
|
|
|
ok val++ not in arr
|
|
|
|
val = 0
|
|
|
|
ok val++ of arr
|
|
|
|
ok val++ not of arr
|
|
|
|
)()
|
|
|
|
|
|
|
|
# `of` and `in` should be able to operate on instance variables
|
|
|
|
(->
|
|
|
|
obj = {
|
|
|
|
list: [2,3]
|
|
|
|
in_list: (value) -> value in @list
|
|
|
|
not_in_list: (value) -> value not in @list
|
|
|
|
of_list: (value) -> value of @list
|
|
|
|
not_of_list: (value) -> value not of @list
|
|
|
|
}
|
|
|
|
ok obj.in_list 3
|
|
|
|
ok obj.not_in_list 1
|
|
|
|
ok obj.of_list 0
|
|
|
|
ok obj.not_of_list 2
|
|
|
|
)()
|
|
|
|
|
|
|
|
#???: `in` with cache and `__indexOf` should work in argument lists
|
|
|
|
eq [Object() in Array()].length, 1
|
|
|
|
|
|
|
|
#737: `in` should have higher precedence than logical operators.
|
|
|
|
eq 1, 1 in [1] and 1
|
|
|
|
|
|
|
|
#768: `in` should preserve evaluation order.
|
|
|
|
(->
|
|
|
|
share = 0
|
|
|
|
a = -> share++ if share is 0
|
|
|
|
b = -> share++ if share is 1
|
|
|
|
c = -> share++ if share is 2
|
2010-12-03 19:43:45 +00:00
|
|
|
ok a() not in [b(),c()]
|
|
|
|
eq share, 3
|
2010-12-03 18:01:13 +00:00
|
|
|
)()
|
2010-08-21 12:56:25 +00:00
|
|
|
|
2010-12-03 18:01:13 +00:00
|
|
|
)()
|
2010-08-21 12:56:25 +00:00
|
|
|
|
2010-10-05 19:46:17 +00:00
|
|
|
|
2010-12-03 19:43:45 +00:00
|
|
|
#### chainable operators
|
2010-12-03 18:01:13 +00:00
|
|
|
(->
|
2010-10-05 19:46:17 +00:00
|
|
|
|
2010-12-03 18:01:13 +00:00
|
|
|
ok 100 > 10 > 1 > 0 > -1
|
|
|
|
ok -1 < 0 < 1 < 10 < 100
|
2010-10-13 16:12:24 +00:00
|
|
|
|
2010-12-03 18:01:13 +00:00
|
|
|
# `is` and `isnt` may be chained
|
|
|
|
ok true is not false is true is not false
|
|
|
|
ok 0 is 0 isnt 1 is 1
|
2010-10-21 13:13:39 +00:00
|
|
|
|
2010-12-03 18:01:13 +00:00
|
|
|
# different comparison operators (`>`,`<`,`is`,etc.) may be combined
|
|
|
|
ok 1 < 2 > 1
|
|
|
|
ok 10 < 20 > 2+3 is 5
|
2010-10-21 01:27:25 +00:00
|
|
|
|
2010-12-03 18:01:13 +00:00
|
|
|
# some chainable operators can be negated by `unless`
|
|
|
|
ok (true unless 0==10!=100)
|
2010-10-21 01:27:25 +00:00
|
|
|
|
2010-12-03 18:01:13 +00:00
|
|
|
# operator precedence: `|` lower than `<`
|
|
|
|
eq 1, 1 | 2 < 3 < 4
|
2010-10-21 01:37:58 +00:00
|
|
|
|
2010-12-03 18:01:13 +00:00
|
|
|
# preserve references
|
|
|
|
(->
|
|
|
|
a = b = c = 1
|
|
|
|
# `a == b <= c` should become `a === b && b <= c`
|
|
|
|
ok a == b <= c
|
|
|
|
)()
|
2010-10-23 11:01:26 +00:00
|
|
|
|
2010-12-03 18:01:13 +00:00
|
|
|
# chained operations should evaluate each value only once
|
|
|
|
(->
|
|
|
|
a = 0
|
|
|
|
ok 1 > a++ < 1
|
|
|
|
)()
|
2010-10-23 11:01:26 +00:00
|
|
|
|
2010-12-03 18:01:13 +00:00
|
|
|
#891: incorrect inversion of chained comparisons
|
|
|
|
(->
|
|
|
|
ok (true unless 0 > 1 > 2)
|
|
|
|
ok (true unless (NaN = 0/0) < 0/0 < NaN)
|
|
|
|
)()
|
2010-12-02 17:52:43 +00:00
|
|
|
|
2010-12-03 01:54:15 +00:00
|
|
|
)()
|