# Function Invocation # ------------------- # * Function Invocation # * Splats in Function Invocations # * Implicit Returns # * Explicit Returns # shared identity function id = (_) -> if arguments.length is 1 then _ else [arguments...] test "basic argument passing", -> a = {} b = {} c = {} eq 1, (id 1) eq 2, (id 1, 2)[1] eq a, (id a) eq c, (id a, b, c)[2] test "passing arguments on separate lines", -> a = {} b = {} c = {} ok(id( a b c )[1] is b) eq(0, id( 0 10 )[0]) eq(a,id( a )) eq b, (id b) test "optional parens can be used in a nested fashion", -> call = (func) -> func() add = (a,b) -> a + b result = call -> inner = call -> add 5, 5 ok result is 10 test "hanging commas and semicolons in argument list", -> fn = () -> arguments.length eq 2, fn(0,1,) eq 3, fn 0, 1, 2 eq 2, fn(0, 1;) # TODO: this test fails (the string compiles), but should it? #throwsCompileError "fn(0,1,;)" throwsCompileError "fn(0,1,;;)" throwsCompileError "fn(0, 1;,)" throwsCompileError "fn(,0)" throwsCompileError "fn(;0)" test "function invocation", -> func = -> return if true eq undefined, func() result = ("hello".slice) 3 ok result is 'lo' test "And even with strange things like this:", -> funcs = [((x) -> x), ((x) -> x * x)] result = funcs[1] 5 ok result is 25 test "More fun with optional parens.", -> fn = (arg) -> arg ok fn(fn {prop: 101}).prop is 101 okFunc = (f) -> ok(f()) okFunc -> true test "chained function calls", -> nonce = {} identityWrap = (x) -> -> x eq nonce, identityWrap(identityWrap(nonce))()() eq nonce, (identityWrap identityWrap nonce)()() test "Multi-blocks with optional parens.", -> fn = (arg) -> arg result = fn( -> fn -> "Wrapped" ) ok result()() is 'Wrapped' test "method calls", -> fnId = (fn) -> -> fn.apply this, arguments math = { add: (a, b) -> a + b anonymousAdd: (a, b) -> a + b fastAdd: fnId (a, b) -> a + b } ok math.add(5, 5) is 10 ok math.anonymousAdd(10, 10) is 20 ok math.fastAdd(20, 20) is 40 test "Ensure that functions can have a trailing comma in their argument list", -> mult = (x, mids..., y) -> x *= n for n in mids x *= y #ok mult(1, 2,) is 2 #ok mult(1, 2, 3,) is 6 ok mult(10, (i for i in [1..6])...) is 7200 test "`@` and `this` should both be able to invoke a method", -> nonce = {} fn = (arg) -> eq nonce, arg fn.withAt = -> @ nonce fn.withThis = -> this nonce fn.withAt() fn.withThis() test "Trying an implicit object call with a trailing function.", -> a = null meth = (arg, obj, func) -> a = [obj.a, arg, func()].join ' ' meth 'apple', b: 1, a: 13, -> 'orange' ok a is '13 apple orange' test "Ensure that empty functions don't return mistaken values.", -> obj = func: (@param, @rest...) -> ok obj.func(101, 102, 103, 104) is undefined ok obj.param is 101 ok obj.rest.join(' ') is '102 103 104' test "Passing multiple functions without paren-wrapping is legal, and should compile.", -> sum = (one, two) -> one() + two() result = sum -> 7 + 9 , -> 1 + 3 ok result is 20 test "Implicit call with a trailing if statement as a param.", -> func = -> arguments[1] result = func 'one', if false then 100 else 13 ok result is 13 test "Test more function passing:", -> sum = (one, two) -> one() + two() result = sum( -> 1 + 2 , -> 2 + 1 ) ok result is 6 sum = (a, b) -> a + b result = sum(1 , 2) ok result is 3 test "Chained blocks, with proper indentation levels:", -> counter = results: [] tick: (func) -> @results.push func() this counter .tick -> 3 .tick -> 2 .tick -> 1 arrayEq [3,2,1], counter.results test "This is a crazy one.", -> x = (obj, func) -> func obj ident = (x) -> x result = x {one: ident 1}, (obj) -> inner = ident(obj) ident inner ok result.one is 1 test "More paren compilation tests:", -> reverse = (obj) -> obj.reverse() ok reverse([1, 2].concat 3).join(' ') is '3 2 1' test "Test for inline functions with parentheses and implicit calls.", -> combine = (func, num) -> func() * num result = combine (-> 1 + 2), 3 ok result is 9 test "Test for calls/parens/multiline-chains.", -> f = (x) -> x result = (f 1).toString() .length ok result is 1 test "Test implicit calls in functions in parens:", -> result = ((val) -> [].push val val )(10) ok result is 10 test "Ensure that chained calls with indented implicit object literals below are alright.", -> result = null obj = method: (val) -> this second: (hash) -> result = hash.three obj .method( 101 ).second( one: two: 2 three: 3 ) eq result, 3 test "Test newline-supressed call chains with nested functions.", -> obj = call: -> this func = -> obj .call -> one two .call -> three four 101 eq func(), 101 test "Implicit objects with number arguments.", -> func = (x, y) -> y obj = prop: func "a", 1 ok obj.prop is 1 test "Non-spaced unary and binary operators should cause a function call.", -> func = (val) -> val + 1 ok (func +5) is 6 ok (func -5) is -4 test "Prefix unary assignment operators are allowed in parenless calls.", -> func = (val) -> val + 1 val = 5 ok (func --val) is 5 test "#855: execution context for `func arr...` should be `null`", -> contextTest = -> eq @, if window? then window else global array = [] contextTest array contextTest.apply null, array contextTest array... test "#904: Destructuring function arguments with same-named variables in scope", -> a = b = nonce = {} fn = ([a,b]) -> {a:a,b:b} result = fn([c={},d={}]) eq c, result.a eq d, result.b eq nonce, a eq nonce, b test "Simple Destructuring function arguments with same-named variables in scope", -> x = 1 f = ([x]) -> x eq f([2]), 2 eq x, 1 test "#4843: Bad output when assigning to @prop in destructuring assignment with defaults", -> works = "maybe" drinks = "beer" class A constructor: ({@works = 'no', @drinks = 'wine'}) -> a = new A {works: 'yes', drinks: 'coffee'} eq a.works, 'yes' eq a.drinks, 'coffee' test "caching base value", -> obj = index: 0 0: {method: -> this is obj[0]} ok obj[obj.index++].method([]...) test "passing splats to functions", -> arrayEq [0..4], id id [0..4]... fn = (a, b, c..., d) -> [a, b, c, d] range = [0..3] [first, second, others, last] = fn range..., 4, [5...8]... eq 0, first eq 1, second arrayEq [2..6], others eq 7, last # Should not trigger implicit call, e.g. rest ... => rest(...) arrayEq [0..4], id id [0..4] ... fn = (a, b, c ..., d) -> [a, b, c, d] range = [0..3] [first, second, others, last] = fn range ..., 4, [5 ... 8] ... eq 0, first eq 1, second arrayEq [2..6], others eq 7, last test "splat variables are local to the function", -> outer = "x" clobber = (avar, outer...) -> outer clobber "foo", "bar" eq "x", outer test "Issue 4631: left and right spread dots with preceding space", -> a = [] f = (a) -> a eq yes, (f ...a) is (f ... a) is (f a...) is (f a ...) is f(a...) is f(...a) is f(a ...) is f(... a) test "Issue 894: Splatting against constructor-chained functions.", -> x = null class Foo bar: (y) -> x = y new Foo().bar([101]...) eq x, 101 test "Functions with splats being called with too few arguments.", -> pen = null method = (first, variable..., penultimate, ultimate) -> pen = penultimate method 1, 2, 3, 4, 5, 6, 7, 8, 9 ok pen is 8 method 1, 2, 3 ok pen is 2 method 1, 2 ok pen is 2 test "splats with super() within classes.", -> class Parent meth: (args...) -> args class Child extends Parent meth: -> nums = [3, 2, 1] super nums... ok (new Child).meth().join(' ') is '3 2 1' # Should not trigger implicit call, e.g. rest ... => rest(...) class Parent meth: (args ...) -> args class Child extends Parent meth: -> nums = [3, 2, 1] super nums ... ok (new Child).meth().join(' ') is '3 2 1' test "#1011: passing a splat to a method of a number", -> eq '1011', 11.toString [2]... eq '1011', (31).toString [3]... eq '1011', 69.0.toString [4]... eq '1011', (131.0).toString [5]... # Should not trigger implicit call, e.g. rest ... => rest(...) eq '1011', 11.toString [2] ... eq '1011', (31).toString [3] ... eq '1011', 69.0.toString [4] ... eq '1011', (131.0).toString [5] ... test "splats and the `new` operator: functions that return `null` should construct their instance", -> args = [] child = new (constructor = -> null) args... ok child instanceof constructor # Should not trigger implicit call, e.g. rest ... => rest(...) child = new (constructor = -> null) args ... ok child instanceof constructor test "splats and the `new` operator: functions that return functions should construct their return value", -> args = [] fn = -> child = new (constructor = -> fn) args... ok child not instanceof constructor eq fn, child test "implicit return", -> eq ok, new -> ok ### Should `return` implicitly ### ### even with trailing comments. ### test "implicit returns with multiple branches", -> nonce = {} fn = -> if false for a in b return c if d else nonce eq nonce, fn() test "implicit returns with switches", -> nonce = {} fn = -> switch nonce when nonce then nonce else return undefined eq nonce, fn() test "preserve context when generating closure wrappers for expression conversions", -> nonce = {} obj = property: nonce method: -> this.result = if false 10 else "a" "b" this.property eq nonce, obj.method() eq nonce, obj.property test "don't wrap 'pure' statements in a closure", -> nonce = {} items = [0, 1, 2, 3, nonce, 4, 5] fn = (items) -> for item in items return item if item is nonce eq nonce, fn items test "usage of `new` is careful about where the invocation parens end up", -> eq 'object', typeof new try Array eq 'object', typeof new do -> -> a = b: -> eq 'object', typeof new (do -> a).b test "implicit call against control structures", -> result = null save = (obj) -> result = obj save switch id false when true 'true' when false 'false' eq result, 'false' save if id false 'false' else 'true' eq result, 'true' save unless id false 'true' else 'false' eq result, 'true' save try doesnt exist catch error 'caught' eq result, 'caught' save try doesnt(exist) catch error then 'caught2' eq result, 'caught2' test "#1420: things like `(fn() ->)`; there are no words for this one", -> fn = -> (f) -> f() nonce = {} eq nonce, (fn() -> nonce) test "#1416: don't omit one 'new' when compiling 'new new'", -> nonce = {} obj = new new -> -> {prop: nonce} eq obj.prop, nonce test "#1416: don't omit one 'new' when compiling 'new new fn()()'", -> nonce = {} argNonceA = {} argNonceB = {} fn = (a) -> (b) -> {a, b, prop: nonce} obj = new new fn(argNonceA)(argNonceB) eq obj.prop, nonce eq obj.a, argNonceA eq obj.b, argNonceB test "#1840: accessing the `prototype` after function invocation should compile", -> doesNotThrowCompileError 'fn()::prop' nonce = {} class Test then id: nonce dotAccess = -> Test:: protoAccess = -> Test eq dotAccess().id, nonce eq protoAccess()::id, nonce test "#960: improved 'do'", -> do (nonExistent = 'one') -> eq nonExistent, 'one' overridden = 1 do (overridden = 2) -> eq overridden, 2 two = 2 do (one = 1, two, three = 3) -> eq one, 1 eq two, 2 eq three, 3 ret = do func = (two) -> eq two, 2 func eq ret, func test "#2617: implicit call before unrelated implicit object", -> pass = -> true result = if pass 1 one: 1 eq result.one, 1 test "#2292, b: f (z),(x)", -> f = (x, y) -> y one = 1 two = 2 o = b: f (one),(two) eq o.b, 2 test "#2297, Different behaviors on interpreting literal", -> foo = (x, y) -> y bar = baz: foo 100, on eq bar.baz, on qux = (x) -> x quux = qux corge: foo 100, true eq quux.corge, on xyzzy = e: 1 f: foo a: 1 b: 2 , one: 1 two: 2 three: 3 g: a: 1 b: 2 c: foo 2, one: 1 two: 2 three: 3 d: 3 four: 4 h: foo one: 1, two: 2, three: three: three: 3, 2 eq xyzzy.f.two, 2 eq xyzzy.g.c.three, 3 eq xyzzy.four, 4 eq xyzzy.h, 2 test "#2715, Chained implicit calls", -> first = (x) -> x second = (x, y) -> y foo = first first one: 1 eq foo.one, 1 bar = first second one: 1, 2 eq bar, 2 baz = first second one: 1, 2 eq baz, 2 test "Implicit calls and new", -> first = (x) -> x foo = (@x) -> bar = first new foo first 1 eq bar.x, 1 third = (x, y, z) -> z baz = first new foo new foo third one: 1 two: 2 1 three: 3 2 eq baz.x.x.three, 3 test "Loose tokens inside of explicit call lists", -> first = (x) -> x second = (x, y) -> y one = 1 foo = second( one 2) eq foo, 2 bar = first( first one: 1) eq bar.one, 1 test "Non-callable literals shouldn't compile", -> throwsCompileError '1(2)' throwsCompileError '1 2' throwsCompileError '/t/(2)' throwsCompileError '/t/ 2' throwsCompileError '///t///(2)' throwsCompileError '///t/// 2' throwsCompileError "''(2)" throwsCompileError "'' 2" throwsCompileError '""(2)' throwsCompileError '"" 2' throwsCompileError '""""""(2)' throwsCompileError '"""""" 2' throwsCompileError '{}(2)' throwsCompileError '{} 2' throwsCompileError '[](2)' throwsCompileError '[] 2' throwsCompileError '[2..9] 2' throwsCompileError '[2..9](2)' throwsCompileError '[1..10][2..9] 2' throwsCompileError '[1..10][2..9](2)' test "implicit invocation with implicit object literal", -> f = (obj) -> eq 1, obj.a f a: 1 obj = if f a: 2 else a: 1 eq 2, obj.a f "a": 1 obj = if f "a": 2 else "a": 1 eq 2, obj.a # #3935: Implicit call when the first key of an implicit object has interpolation. a = 'a' f "#{a}": 1 obj = if f "#{a}": 2 else "#{a}": 1 eq 2, obj.a test "get and set can be used as function names when not ambiguous with `get`/`set` keywords", -> get = (val) -> val set = (val) -> val eq 2, get(2) eq 3, set(3) eq 'a', get('a') eq 'b', set('b') eq 4, get 4 eq 5, set 5 eq 'c', get 'c' eq 'd', set 'd' @get = get @set = set eq 6, @get 6 eq 7, @set 7 get = ({val}) -> val set = ({val}) -> val eq 8, get({val: 8}) eq 9, set({val: 9}) eq 'e', get({val: 'e'}) eq 'f', set({val: 'f'}) eq 10, get {val: 10} eq 11, set {val: 11} eq 'g', get {val: 'g'} eq 'h', set {val: 'h'} test "get and set can be used as variable and property names", -> get = 2 set = 3 eq 2, get eq 3, set {get} = {get: 4} {set} = {set: 5} eq 4, get eq 5, set test "get and set can be used as class method names", -> class A get: -> 2 set: -> 3 a = new A() eq 2, a.get() eq 3, a.set() class B @get = -> 4 @set = -> 5 eq 4, B.get() eq 5, B.set() test "#4524: functions named get or set can be used without parentheses when attached to an object", -> obj = get: (x) -> x + 2 set: (x) -> x + 3 class A get: (x) -> x + 4 set: (x) -> x + 5 a = new A() class B get: (x) -> x.value + 6 set: (x) -> x.value + 7 b = new B() eq 12, obj.get 10 eq 13, obj.set 10 eq 12, obj?.get 10 eq 13, obj?.set 10 eq 14, a.get 10 eq 15, a.set 10 @ten = 10 eq 12, obj.get @ten eq 13, obj.set @ten eq 14, a.get @ten eq 15, a.set @ten obj.obj = obj eq 12, obj.obj.get @ten eq 13, obj.obj.set @ten eq 16, b.get value: 10 eq 17, b.set value: 10 eq 16, b.get value: @ten eq 17, b.set value: @ten test "#4836: functions named get or set can be used without parentheses when attached to this or @", -> @get = (x) -> x + 2 @set = (x) -> x + 3 @a = 4 eq 12, this.get 10 eq 13, this.set 10 eq 12, this?.get 10 eq 13, this?.set 10 eq 6, this.get @a eq 7, this.set @a eq 6, this?.get @a eq 7, this?.set @a eq 12, @get 10 eq 13, @set 10 eq 12, @?.get 10 eq 13, @?.set 10 eq 6, @get @a eq 7, @set @a eq 6, @?.get @a eq 7, @?.set @a test "#4852: functions named get or set can be used without parentheses when attached to this or @, with an argument of an implicit object", -> @get = ({ x }) -> x + 2 @set = ({ x }) -> x + 3 eq 12, @get x: 10 eq 13, @set x: 10 eq 12, @?.get x: 10 eq 13, @?.set x: 10 eq 12, this?.get x: 10 eq 13, this?.set x: 10 test "#4473: variable scope in chained calls", -> obj = foo: -> this bar: (a) -> a() this obj.foo(a = 1).bar(-> a = 2) eq a, 2 obj.bar(-> b = 2).foo(b = 1) eq b, 1 obj.foo(c = 1).bar(-> c = 2).foo(c = 3) eq c, 3 obj.foo([d, e] = [1, 2]).bar(-> d = 4) eq d, 4 obj.foo({f} = {f: 1}).bar(-> f = 5) eq f, 5 test "#5052: implicit call of class with no body", -> doesNotThrowCompileError 'f class' doesNotThrowCompileError 'f class A' doesNotThrowCompileError 'f class A extends B' f = (args...) -> args a = 1 [klass, shouldBeA] = f class A, a eq shouldBeA, a [shouldBeA] = f a, class A eq shouldBeA, a [obj, klass, shouldBeA] = f b: 1 class A a eq shouldBeA, a