lambda1.js 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. // ES6 Lambda Arrow Function tests -- verifies basic functionality and parsing
  6. WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
  7. var globalObject = this;
  8. var globalVar = 123;
  9. var globalLambdaThis = () => this;
  10. var globalLambdaThisProperty = () => this.globalVar;
  11. var globalLambdaEvalThis = () => eval('this');
  12. var globalLambdaEvalThisProperty = () => eval('this.globalVar');
  13. var globalEvalLambdaThis = eval('() => this');
  14. var globalEvalLambdaThisProperty = eval('() => this.globalVar');
  15. var globalLambdaEvalLambdaThis = () => eval('() => this');
  16. var globalLambdaEvalLambdaThisCall = globalLambdaEvalLambdaThis();
  17. var globalLambdaEvalLambdaThisProperty = () => eval('() => this.globalVar');
  18. var globalLambdaEvalLambdaThisPropertyCall = globalLambdaEvalLambdaThisProperty();
  19. var globalEvalLambdaEvalThis = eval('() => eval("this")');
  20. var globalEvalLambdaEvalThisProperty = eval('() => eval("this.globalVar")');
  21. var globalEvalLambdaThisWithNestedEval = eval('eval(""); () => this');
  22. var globalEvalNestedEvalLambdaThis = eval('eval("() => this")');
  23. var globalEvalNestedEvalLambdaThisWithNestedEval = eval('eval("eval(\'\'); () => this")');
  24. var tests = [
  25. {
  26. name: "Some simple basic arrow functions testing variation of the different syntaxes",
  27. body: function () {
  28. var empty = () => {};
  29. var product = (x, y) => { return x * y; };
  30. var nil = x => { var x; };
  31. var twox = x => x + x;
  32. var manyformals = (a, b, c, d, e, f) => { return '' + a + b + c + d + e + f; };
  33. // These nested forms add coverage for bug BLUE 513592
  34. var nested = x => () => x;
  35. var nestedoverride = x => x => x;
  36. var nestedblock = x => { return () => x; }
  37. var nestedblockoverride = x => { return x => x; }
  38. assert.areEqual(undefined, empty(), "empty lambda body returns undefined");
  39. assert.areEqual(6, product(2, 3), "simple lambda with two formals returns product of the arguments");
  40. assert.areEqual(undefined, nil(0), "simple block lambda without return statement returns undefined");
  41. assert.areEqual(2, twox(1), "simple expression lambda with single formal returns double the argument");
  42. assert.areEqual('123456', manyformals(1, 2, 3, 4, 5, 6), "lambda with more than two formal parameters");
  43. assert.areEqual('abc', nested('abc')('123'), "expression lambda returning nested lambda that captures outer formal and returns it");
  44. assert.areEqual('123', nestedoverride('abc')('123'), "expression lambda returning nested lambda that shadows outer formal and returns its own");
  45. assert.areEqual('abc', nestedblock('abc')('123'), "block lambda returning nested lambda that captures outer formal and returns it");
  46. assert.areEqual('123', nestedblockoverride('abc')('123'), "block lambda returning nested lambda that shadows outer formal and returns its own");
  47. }
  48. },
  49. {
  50. name: "Lambdas cannot be used as constructors for new expressions and do not have a .prototype property",
  51. body: function () {
  52. var empty = () => {};
  53. var simple = x => x;
  54. var multi = (x, y, z) => x + y + z;
  55. var nested = x => () => x;
  56. var block = (x, y) => { return x + y; };
  57. var blocknested = () => { return () => { return this; } };
  58. assert.throws(function () { new empty(); }, TypeError, "Lambdas cannot be used as constructor: empty", "Function is not a constructor");
  59. assert.throws(function () { new simple(0); }, TypeError, "Lambdas cannot be used as constructor: simple", "Function is not a constructor");
  60. assert.throws(function () { new multi(2, 3, 4); }, TypeError, "Lambdas cannot be used as constructor: multi", "Function is not a constructor");
  61. assert.throws(function () { new nested(''); }, TypeError, "Lambdas cannot be used as constructor: nested", "Function is not a constructor");
  62. assert.throws(function () { new block(null, 0); }, TypeError, "Lambdas cannot be used as constructor: block", "Function is not a constructor");
  63. assert.throws(function () { new blocknested(); }, TypeError, "Lambdas cannot be used as constructor: blocknested", "Function is not a constructor");
  64. assert.isFalse(empty.hasOwnProperty('prototype'), "Lambda function objects do not have a 'prototype' property: empty");
  65. assert.isFalse(simple.hasOwnProperty('prototype'), "Lambda function objects do not have a 'prototype' property: simple");
  66. assert.isFalse(multi.hasOwnProperty('prototype'), "Lambda function objects do not have a 'prototype' property: multi");
  67. assert.isFalse(nested.hasOwnProperty('prototype'), "Lambda function objects do not have a 'prototype' property: nested");
  68. assert.isFalse(block.hasOwnProperty('prototype'), "Lambda function objects do not have a 'prototype' property: block");
  69. assert.isFalse(blocknested.hasOwnProperty('prototype'), "Lambda function objects do not have a 'prototype' property: blocknested");
  70. }
  71. },
  72. {
  73. name: "Quick checks on global lambda this binding",
  74. body: function () {
  75. assert.areEqual(globalObject, globalLambdaThis(), "lambda at global scope captures global object this");
  76. assert.areEqual(globalVar, globalLambdaThisProperty(), "lambda at global scope captures global object for this and accesses global properties");
  77. var fake = { steal: globalLambdaThis };
  78. var fake2 = { globalVar: 'abc', steal: globalLambdaThisProperty };
  79. assert.areNotEqual(fake, fake.steal(), "lambda at global scope doesn't bind this dynamically");
  80. assert.areNotEqual(fake2.globalVar, fake2.steal(), "lambda at global scope doesn't bind this dynamically, does not access target object's property");
  81. assert.areEqual(globalObject, fake.steal(), "lambda at global scope is not confused, still has lexical this binding");
  82. assert.areEqual(globalVar, fake2.steal(), "lambda at global scope is not confused, still has lexical this binding and returns global property");
  83. }
  84. },
  85. {
  86. name: "Arrow function has lexical 'this'; normal function still has dynamic 'this'",
  87. body: function () {
  88. // ''=>'' has only lexical ''this'', no dynamic ''this''
  89. var obj = {
  90. method: function () {
  91. return () => this;
  92. }
  93. };
  94. assert.areEqual(obj, obj.method()(), "''=>'' has only lexical ''this'', no dynamic ''this''");
  95. var fake = {steal: obj.method()};
  96. assert.areEqual(obj, fake.steal(), "lambda on different object still has original lexical ''this''");
  97. // But ''function'' still has dynamic ''this'' of course
  98. var real = {borrow: obj.method};
  99. assert.areEqual(real, real.borrow()(), "''function'' still has dynamic ''this''");
  100. // type of scope (e.g. ActivationObject) should not affect binding of ''this''
  101. obj = {
  102. method: function () {
  103. eval('');
  104. return () => this;
  105. }
  106. };
  107. assert.areEqual(obj, obj.method()(), "[ActivationObject] ''=>'' has only lexical ''this'', no dynamic ''this''");
  108. fake = {steal: obj.method()};
  109. assert.areEqual(obj, fake.steal(), "[ActivationObject] lambda on different object still has original lexical ''this''");
  110. // But ''function'' still has dynamic ''this'' of course
  111. real = {borrow: obj.method};
  112. assert.areEqual(real, real.borrow()(), "[ActivationObject] ''function'' still has dynamic ''this''");
  113. }
  114. },
  115. {
  116. name: "Arrow function that refers to this more than once (Blue bug 538880)",
  117. body: function () {
  118. var obj = {
  119. a: 5,
  120. b: 10,
  121. method: function () {
  122. return () => this.a + this.b;
  123. }
  124. };
  125. assert.areEqual(15, obj.method()(), "lambda can refer to this more than once");
  126. }
  127. },
  128. {
  129. name: "Lambdas and closures",
  130. body: function () {
  131. var f = (function() {
  132. var x = 'outer';
  133. var lambda = () => {
  134. assert.areEqual(undefined, x);
  135. var x = 'lambda';
  136. return function() {
  137. assert.areEqual('lambda', x);
  138. }
  139. }
  140. assert.areEqual('outer', x);
  141. return lambda;
  142. })();
  143. f()();
  144. }
  145. },
  146. {
  147. name: "Interesting valid and invalid syntax",
  148. body: function () {
  149. assert.throws(() => { eval('(var x) => {};'); }, SyntaxError, "var not used in formals declaration", "Syntax error");
  150. assert.throws(() => { eval('(x, ) => {};'); }, SyntaxError, "missing formal identifier in parameter list", "Syntax error");
  151. assert.throws(() => { eval('a.x => {};'); }, SyntaxError, "valid expression syntax that is invalid parameter list syntax on lhs of =>", "Syntax error");
  152. assert.throws(() => { eval('(x, y)[7] => {};'); }, SyntaxError, "valid expression syntax that is invalid parameter list syntax on lhs of =>", "Expected '=>'");
  153. assert.throws(() => { eval('x() => {};'); }, SyntaxError, "valid expression syntax that is invalid parameter list syntax on lhs of =>", "Syntax error");
  154. assert.throws(() => { eval('0 || () => 0'); }, SyntaxError, "Arrow function no params is not valid on RHS of ||", "Expected '('");
  155. assert.throws(() => { eval('0 || x => 0'); }, SyntaxError, "Arrow function naked param is not valid on RHS of ||", "Expected '('");
  156. assert.throws(() => { eval('0 || (x) => 0'); }, SyntaxError, "Arrow function single param is not valid on RHS of ||", "Expected '('");
  157. assert.throws(() => { eval('0 || (x,y) => 0'); }, SyntaxError, "Arrow function more than single param is not valid on RHS of ||", "Expected '('");
  158. assert.throws(() => { eval('!()=>{}'); }, SyntaxError, "Arrow function preceded by UnaryOperator is a SyntaxError", "Expected '('");
  159. assert.doesNotThrow(function () { eval('function foo() { }; foo(x => x);'); }, "lambda with one formal and nor parentheses parses as argument to function call");
  160. assert.doesNotThrow(function () { eval('function foo() { }; foo(() => "abc"); foo(() => "abc", 123);'); }, "lambda with no formals parses as argument to function call");
  161. assert.doesNotThrow(function () { eval('function foo() { }; foo((x, y) => "abc"); foo(b => "abc", 123);'); }, "lambda with multiple formals parses as argument to function call");
  162. assert.doesNotThrow(function () { eval('({})[x => x]'); }, "lambda parses as argument to element access operator");
  163. assert.doesNotThrow(function () { eval('() => () => 0'); }, "lambda nested in lambda");
  164. assert.doesNotThrow(function () { eval('() => x => (a, b, c) => 0'); }, "lambda nested in lambda nested in lambda with parameters");
  165. assert.doesNotThrow(function () { eval('y => () => (a) => 0'); }, "lambda nested in lambda nested in lambda with other parameters");
  166. assert.doesNotThrow(() => { eval('function * foo() { yield ()=>{}; }'); }, "Arrow function preceded by yield is not an Error");
  167. }
  168. },
  169. {
  170. name: "toString on a lambda",
  171. body: function () {
  172. assert.areEqual("() => { }", (() => { }).toString(), "toString() on no formals empty body lambda");
  173. assert.areEqual("x => { }", (x => { }).toString(), "toString() on non-parenthesized single formal empty body lambda");
  174. assert.areEqual("x => x", (x => x).toString(), "toString() on non-parenthesized single formal trivial expression lambda");
  175. assert.areEqual("(a, b) => { return a * b; }", ((a, b) => { return a * b; }).toString(), "toString() on parenthesized formals non-empty body lambda");
  176. assert.areEqual("(a, b) => a - 2*b", ((a, b) => a - 2*b).toString(), "toString() on parenthesized formals non-trivial expression lambda");
  177. }
  178. },
  179. {
  180. name: "lambdas do not have an arguments object",
  181. body: function () {
  182. var arguments = 'not arguments object';
  183. assert.areEqual(arguments, (() => arguments)(), "arguments in lambda should bind to outside arguments since it is not given its own arguments binding");
  184. function f (x, y, z) {
  185. return () => [this, x, y, z, arguments];
  186. }
  187. function g (x, y, z) {
  188. eval('');
  189. return () => [this, x, y, z, arguments];
  190. }
  191. function verify(f, n) {
  192. let e = ['_this_', '_x_', '_y_', '_z_', '[object Arguments]'];
  193. let r = f.call('_this_', '_x_', '_y_', '_z_')();
  194. assert.areEqual(e.length, r.length, n + ": result array length matches expected array length");
  195. for (let i = 0; i < e.length; i += 1) {
  196. assert.areEqual(e[i], r[i] + '', n + ": this, formals, and arguments object are all captured correctly: " + e[i]);
  197. }
  198. }
  199. verify(f, 'f');
  200. verify(g, 'g');
  201. function h () {
  202. return () => {
  203. assert.areEqual(5, arguments.length, "captured arguments length is respected");
  204. assert.areEqual(h, arguments.callee, "arguments caller is respected");
  205. assert.areEqual(1, arguments[0], "first argument is 1");
  206. assert.areEqual(2, arguments[1], "second argument is 2");
  207. assert.areEqual(3, arguments[2], "third argument is 3");
  208. assert.areEqual('abc', arguments[3], "fourth argument is 'abc'");
  209. assert.areEqual(null, arguments[4], "fifth argument is null");
  210. };
  211. }
  212. h(1, 2, 3, 'abc', null)();
  213. function i () {
  214. return () => () => { return () => arguments; };
  215. }
  216. var args = i('a', 'b', 'c', 123, undefined)()()();
  217. assert.areEqual(5, args.length, "captured arguments (through multiple lambdas) length is respected");
  218. assert.areEqual(i, args.callee, "arguments (through multiple lambdas) caller is respected");
  219. assert.areEqual('a', args[0], "first argument (through multiple lambdas) is 'a'");
  220. assert.areEqual('b', args[1], "second argument (through multiple lambdas) is 'b'");
  221. assert.areEqual('c', args[2], "third argument (through multiple lambdas) is 'c'");
  222. assert.areEqual(123, args[3], "fourth argument (through multiple lambdas) is 123");
  223. assert.areEqual(undefined, args[4], "fifth argument (through multiple lambdas) is undefined");
  224. function j () {
  225. var arguments = 'not an arguments object';
  226. return () => arguments;
  227. }
  228. assert.areEqual('not an arguments object', j()(), "lambda captures local variables named arguments");
  229. function k (arguments) {
  230. return () => arguments;
  231. }
  232. assert.areEqual('foo', k('foo')(), "lambda captures formal parameters named arguments");
  233. }
  234. },
  235. {
  236. name: "Capturing dynamically scoped variables",
  237. body: function () {
  238. eval("var a = 10;");
  239. var lambda1 = () => a;
  240. assert.areEqual(10, lambda1(), "lambda can capture dynamically scoped variables introduced by eval");
  241. var lambdaobj1 = {
  242. method: function () {
  243. return () => {
  244. a;
  245. return this;
  246. };
  247. }
  248. };
  249. assert.areEqual(lambdaobj1, lambdaobj1.method()(), "lambda's lexical ''this'' binding is unaffected by capturing a dynamically scoped variable introduced by eval");
  250. var obj = { b: 20 };
  251. with (obj) {
  252. let lambda2 = () => b;
  253. assert.areEqual(20, lambda2(), "lambda can capture properties introduced by with blocks");
  254. var lambdaobj2 = {
  255. method: function () {
  256. return () => {
  257. b;
  258. return this;
  259. };
  260. }
  261. };
  262. assert.areEqual(lambdaobj2, lambdaobj2.method()(), "lambda's lexical ''this'' binding is unaffected by capturing a property introduced by a with block");
  263. }
  264. }
  265. },
  266. {
  267. name: "'arguments' and 'eval' allowed as formal parameter names in non-strict mode",
  268. body: function () {
  269. var a = eval => eval + 1;
  270. var b = arguments => arguments + 2;
  271. var c = (eval, arguments) => eval + arguments;
  272. assert.areEqual(2, a(1), "'eval' allowed as lambda formal parameter name in non-strict mode of single parameter list");
  273. assert.areEqual(3, b(1), "'arguments' allowed as lambda formal parameter name in non-strict mode of single parameter list");
  274. assert.areEqual(5, c(2, 3), "'arguments' and 'eval' allowed as lambda formal parameter names in non-strict mode of multiple parameter list");
  275. assert.throws(function () { eval("eval => { 'use strict'; return eval + 1; }"); }, SyntaxError, "'eval' is not allowed as a lambda formal parameter name in a single parameter list when the lambda turns on strict mode", "Invalid usage of 'eval' in strict mode");
  276. assert.throws(function () { eval("arguments => { 'use strict'; return arguments + 2; }"); }, SyntaxError, "'arguments' is not allowed as a lambda formal parameter name in a single parameter list when the lambda turns on strict mode", "Invalid usage of 'arguments' in strict mode");
  277. assert.throws(function () { eval("(eval, a) => { 'use strict'; return eval + a; }"); }, SyntaxError, "'eval' is not allowed as a lambda formal parameter name in a multiple parameter list when the lambda turns on strict mode", "Invalid usage of 'eval' in strict mode");
  278. assert.throws(function () { eval("(e, arguments) => { 'use strict'; return e + arguments; }"); }, SyntaxError, "'arguments' is not allowed as a lambda formal parameter name in a multiple parameter list when the lambda turns on strict mode", "Invalid usage of 'arguments' in strict mode");
  279. assert.throws(function () { "use strict"; eval("eval => eval + 1"); }, SyntaxError, "'eval' is not allowed as a lambda formal parameter name in a single parameter list when the lambda is in strict mode", "Invalid usage of 'eval' in strict mode");
  280. assert.throws(function () { "use strict"; eval("arguments => arguments + 2"); }, SyntaxError, "'arguments' is not allowed as a lambda formal parameter name in a single parameter list when the lambda is in strict mode", "Invalid usage of 'arguments' in strict mode");
  281. assert.throws(function () { "use strict"; eval("(eval, a) => eval + a"); }, SyntaxError, "'eval' is not allowed as a lambda formal parameter name in a multiple parameter list when the lambda is in strict mode", "Invalid usage of 'eval' in strict mode");
  282. assert.throws(function () { "use strict"; eval("(e, arguments) => e + arguments"); }, SyntaxError, "'arguments' is not allowed as a lambda formal parameter name in a multiple parameter list when the lambda is in strict mode", "Invalid usage of 'arguments' in strict mode");
  283. }
  284. },
  285. {
  286. name: "Duplicate names not allowed in formal parameter name list in non-strict mode",
  287. body: function () {
  288. assert.throws(function () { eval('(x, x) => { }'); }, SyntaxError, "duplicate names are not allowed in a lambda formal parameter list in non-strict mode", "Duplicate formal parameter names not allowed in this context");
  289. assert.throws(function () { eval('(a, b, a) => { }'); }, SyntaxError, "duplicate names are not allowed in a lambda formal parameter list in non-strict mode (when there are other names)", "Duplicate formal parameter names not allowed in this context");
  290. assert.throws(function () { eval('(a, b, ...a) => { }'); }, SyntaxError, "duplicate names are not allowed in a lambda formal parameter list when the list is a non-simple parameter list in non-strict mode", "Duplicate formal parameter names not allowed in this context");
  291. assert.throws(function () { eval('(x, x) => { "use strict"; }'); }, SyntaxError, "duplicate names are not allowed in a lambda formal parameter list (when lambda turns on strict mode)", "Duplicate formal parameter names not allowed in this context");
  292. assert.throws(function () { eval('(a, b, a) => { "use strict"; }'); }, SyntaxError, "duplicate names are not allowed in a lambda formal parameter list (when lambda turns on strict mode and there are other names)", "Duplicate formal parameter names not allowed in this context");
  293. assert.throws(function () { eval('(a, b, ...a) => { "use strict"; }'); }, SyntaxError, "duplicate names are not allowed in a lambda formal parameter list when the list is a non-simple parameter list (when lambda turns on strict mode)", "Duplicate formal parameter names not allowed in this context");
  294. assert.throws(function () { "use strict"; eval('(x, x) => { }'); }, SyntaxError, "duplicate names are not allowed in a lambda formal parameter list (when lambda is in strict mode)", "Duplicate formal parameter names not allowed in strict mode");
  295. assert.throws(function () { "use strict"; eval('(a, b, a) => { }'); }, SyntaxError, "duplicate names are not allowed in a lambda formal parameter list (when lambda is in strict mode and there are other names)", "Duplicate formal parameter names not allowed in strict mode");
  296. assert.throws(function () { "use strict"; eval('(a, b, ...a) => { }'); }, SyntaxError, "duplicate names are not allowed in a lambda formal parameter list when the list is a non-simple parameter list (when lambda is in strict mode)", "Duplicate formal parameter names not allowed in strict mode");
  297. }
  298. },
  299. {
  300. name: "Formal names redeclared by local variables behave as if formals are var-like",
  301. body: function () {
  302. assert.doesNotThrow(function () { eval('x => { var x; }'); }, "lambda formal parameters do not cause redeclaration error with local var bindings of the same name", "Let/Const redeclaration");
  303. assert.throws(function () { eval('x => { let x; }'); }, SyntaxError, "lambda formal parameters cause redeclaration error with local function scoped let bindings of the same name", "Let/Const redeclaration");
  304. assert.throws(function () { eval('x => { const x = 0; }'); }, SyntaxError, "lambda formal parameters cause redeclaration error with local function scoped const bindings of the same name", "Let/Const redeclaration");
  305. }
  306. },
  307. {
  308. name: "Formal names shadow parent scope parameter and local variable names",
  309. body: function () {
  310. assert.areEqual(10, (function (x) { return x => x; })(20)(10), "lambda formal parameters should shadow outside local variables of the same name [parameter]");
  311. assert.areEqual(10, (function () { var x = 20; return x => x; })()(10), "lambda formal parameters should shadow outside local variables of the same name [var]");
  312. assert.areEqual(10, (function () { let x = 20; return x => x; })()(10), "lambda formal parameters should shadow outside local variables of the same name [let]");
  313. assert.areEqual(10, (function () { const x = 20; return x => x; })()(10), "lambda formal parameters should shadow outside local variables of the same name [const]");
  314. }
  315. },
  316. {
  317. name: "Lexical this and eval",
  318. body: function () {
  319. var thisVal = { localVar: 456 };
  320. function test () {
  321. var localLambdaEvalThis = () => eval('this');
  322. var localLambdaEvalThisProperty = () => eval('this.localVar');
  323. var localEvalLambdaThis = eval('() => this');
  324. var localEvalLambdaThisProperty = eval('() => this.localVar');
  325. var localLambdaEvalLambdaThis = () => eval('() => this');
  326. var localLambdaEvalLambdaThisCall = localLambdaEvalLambdaThis();
  327. var localLambdaEvalLambdaThisProperty = () => eval('() => this.localVar');
  328. var localLambdaEvalLambdaThisPropertyCall = localLambdaEvalLambdaThisProperty();
  329. var localEvalLambdaEvalThis = eval('() => eval("this")');
  330. var localEvalLambdaEvalThisProperty = eval('() => eval("this.localVar")');
  331. var localEvalLambdaNested3This = eval('() => () => () => this');
  332. var localLambdaNested3EvalThis = () => () => () => eval('this');
  333. var localEvalLambdaThisWithNestedEval = eval('eval(""); () => this');
  334. var localEvalNestedEvalLambdaThis = eval('eval("() => this")');
  335. var localEvalNestedEvalLambdaThisWithNestedEval = eval('eval("eval(\'\'); () => this")');
  336. assert.areEqual(this, localLambdaEvalThis(), "localLambdaEvalThis() should equal test()'s this value");
  337. assert.areEqual(this.localVar, localLambdaEvalThisProperty(), "localLambdaEvalThisProperty() should equal the localVar property");
  338. assert.areEqual(this, localEvalLambdaThis(), "localEvalLambdaThis() should equal test()'s this value");
  339. assert.areEqual(this.localVar, localEvalLambdaThisProperty(), "localEvalLambdaThisProperty() should equal the localVar property");
  340. assert.areEqual(this, localLambdaEvalLambdaThis()(), "localLambdaEvalLambdaThis()() should equal test()'s this value");
  341. assert.areEqual(this, localLambdaEvalLambdaThisCall(), "localLambdaEvalLambdaThisCall() should equal test()'s this value");
  342. assert.areEqual(this.localVar, localLambdaEvalLambdaThisProperty()(), "localLambdaEvalLambdaThisProperty()() should equal the localVar property");
  343. assert.areEqual(this.localVar, localLambdaEvalLambdaThisPropertyCall(), "localLambdaEvalLambdaThisPropertyCall() should equal the localVar property");
  344. assert.areEqual(this, localEvalLambdaEvalThis(), "localEvalLambdaEvalThis() should equal test()'s this value");
  345. assert.areEqual(this.localVar, localEvalLambdaEvalThisProperty(), "localEvalLambdaEvalThisProperty() should equal the localVar property");
  346. assert.areEqual(this, localEvalLambdaNested3This()()(), "localEvalLambdaNested3This()()() should equal test()'s this value");
  347. assert.areEqual(this, localLambdaNested3EvalThis()()(), "localLambdaNested3EvalThis()()() should equal test()'s this value");
  348. assert.areEqual(this, localEvalLambdaThisWithNestedEval(), "localEvalLambdaThisWithNestedEval() should equal test()'s this value");
  349. assert.areEqual(this, localEvalNestedEvalLambdaThis(), "localEvalNestedEvalLambdaThis() should equal test()'s this value");
  350. assert.areEqual(this, localEvalNestedEvalLambdaThisWithNestedEval(), "localEvalNestedEvalLambdaThisWithNestedEval() should equal test()'s this value");
  351. // Global equivalents
  352. assert.areEqual(globalObject, globalLambdaEvalThis(), "globalLambdaEvalThis() should equal the global object");
  353. assert.areEqual(globalVar, globalLambdaEvalThisProperty(), "globalLambdaEvalThisProperty() should equal the global object's globalVar property");
  354. assert.areEqual(globalObject, globalEvalLambdaThis(), "globalEvalLambdaThis() should equal the global object");
  355. assert.areEqual(globalVar, globalEvalLambdaThisProperty(), "globalEvalLambdaThisProperty() should equal the global object's globalVar property");
  356. assert.areEqual(globalObject, globalLambdaEvalLambdaThis()(), "globalLambdaEvalLambdaThis()() should equal the global object");
  357. assert.areEqual(globalObject, globalLambdaEvalLambdaThisCall(), "globalLambdaEvalLambdaThisCall() should equal the global object");
  358. assert.areEqual(globalVar, globalLambdaEvalLambdaThisProperty()(), "globalLambdaEvalLambdaThisProperty()() should equal the global object's globalVar property");
  359. assert.areEqual(globalVar, globalLambdaEvalLambdaThisPropertyCall(), "globalLambdaEvalLambdaThisPropertyCall() should equal the global object's globalVar property");
  360. assert.areEqual(globalObject, globalEvalLambdaEvalThis(), "globalEvalLambdaEvalThis() should equal the global object");
  361. assert.areEqual(globalVar, globalEvalLambdaEvalThisProperty(), "globalEvalLambdaEvalThisProperty() should equal the global object");
  362. assert.areEqual(globalObject, globalEvalLambdaThisWithNestedEval(), "globalEvalLambdaThisWithNestedEval() should equal the global object");
  363. assert.areEqual(globalObject, globalEvalNestedEvalLambdaThis(), "globalEvalNestedEvalLambdaThis() should equal the global object");
  364. assert.areEqual(globalObject, globalEvalNestedEvalLambdaThisWithNestedEval(), "globalEvalNestedEvalLambdaThisWithNestedEval() should equal the global object");
  365. this.x = 10;
  366. with ({x : 100}) {
  367. lambdaInsideWithEval = (s) => eval(s);
  368. assert.areEqual(10, lambdaInsideWithEval("this.x"), "Arrow function should be able to access this variable within eval");
  369. assert.areEqual(100, x, "Property access on the with construct should work with eval and arrow in the body");
  370. }
  371. }
  372. test.call(thisVal);
  373. }
  374. },
  375. {
  376. name: "New line characters are not allowed between arrow parameters and =>",
  377. body: function () {
  378. assert.throws(function () { eval('x \n => d;'); }, SyntaxError, "Arrow with simple expression body and simple parameter", "Syntax error");
  379. assert.throws(function () { eval('var a = x \n => d;'); }, SyntaxError, "Arrow with simple expression body and simple parameter assigned to a var", "Syntax error");
  380. assert.throws(function () { eval('(x) \n => d;'); }, SyntaxError, "Arrow with simple expression body and single parameter", "Syntax error");
  381. assert.throws(function () { eval('var a = (x) \n => d;'); }, SyntaxError, "Arrow with simple expression body and single parameter assigned to a var", "Syntax error");
  382. assert.throws(function () { eval('() \n => d;'); }, SyntaxError, "Arrow with simple expression body and empty parameter list", "Syntax error");
  383. assert.throws(function () { eval('var a = () \n => d;'); }, SyntaxError, "Arrow with simple expression body and empty parameter list assigned to a var", "Syntax error");
  384. assert.throws(function () { eval('x \n => { return d };'); }, SyntaxError, "Arrow with block body and simple parameter", "Syntax error");
  385. assert.throws(function () { eval('var a = x \n => { return d };'); }, SyntaxError, "Arrow with block body and simple parameter assigned to a var", "Syntax error");
  386. assert.throws(function () { eval('(x) \n => { return d };'); }, SyntaxError, "Arrow with block body and single parameter", "Syntax error");
  387. assert.throws(function () { eval('var a = (x) \n => { return d };'); }, SyntaxError, "Arrow with block body and single parameter assigned to a var", "Syntax error");
  388. assert.throws(function () { eval('() \n => { return d };'); }, SyntaxError, "Arrow with block body and empty parameter list", "Syntax error");
  389. assert.throws(function () { eval('var a = () \n => { return d };'); }, SyntaxError, "Arrow with block body and empty parameter list assigned to a var", "Syntax error");
  390. assert.throws(function () { eval('var a = {}; a.x \n => d;'); }, SyntaxError, "Verify that badly formed arrow functions return correct error even if a newline is before the => token", "Syntax error");
  391. assert.throws(function () { eval('var a = {}; a\n.x => d;'); }, SyntaxError, "Verify that badly formed arrow functions return correct error even if a newline is before the => token", "Syntax error");
  392. }
  393. },
  394. {
  395. name: "Lambda consisting of single expression wrapped in parens should have correct source string",
  396. body: function () {
  397. var l = () => (123)
  398. assert.areEqual('() => (123)', '' + l, "Lambda to string should include the parens wrapping the return expression");
  399. var l = () => (('๏บบ'))
  400. assert.areEqual("() => (('๏บบ'))", '' + l, "Multi-byte characters should not break the string");
  401. var s = "() => ('\u{20ac}')";
  402. var l = eval(s);
  403. assert.areEqual(s, '' + l, "Unicode byte sequences should not break the string");
  404. var l = async() => ({});
  405. assert.areEqual('async() => ({})', '' + l, "Async lambda should also be correct");
  406. var l = () => (() => (123))
  407. assert.areEqual('() => (() => (123))', '' + l, "Nested lambda to string should be correct");
  408. var l = async() => (async() => ('str'));
  409. assert.areEqual("async() => (async() => ('str'))", '' + l, "Nested async lambda should be correct");
  410. }
  411. },
  412. {
  413. name: "Lambda consisting of assignment expression should have correct source string",
  414. body: function () {
  415. var l = () => a = (123)
  416. assert.areEqual('() => a = (123)', '' + l, "Lambda to string should include the parens wrapping the return expression");
  417. var l = () => a = (('๏บบ'))
  418. assert.areEqual("() => a = (('๏บบ'))", '' + l, "Multi-byte characters should not break the string");
  419. var s = "() => a = ('\u{20ac}')";
  420. var l = eval(s);
  421. assert.areEqual(s, '' + l, "Unicode byte sequences should not break the string");
  422. var l = async() => a = ({});
  423. assert.areEqual('async() => a = ({})', '' + l, "Async lambda should also be correct");
  424. var l = () => a = (() => b = (123))
  425. assert.areEqual('() => a = (() => b = (123))', '' + l, "Nested lambda to string should be correct");
  426. var l = async() => a = (async() => b = ('str'));
  427. assert.areEqual("async() => a = (async() => b = ('str'))", '' + l, "Nested async lambda should be correct");
  428. }
  429. },
  430. {
  431. // Regression test for issue: https://github.com/Microsoft/ChakraCore/issues/2746
  432. name: "Lambda expression with syntax error.",
  433. body: function () {
  434. assert.throws(() => { eval('--par=>'); }, SyntaxError, "Expected syntax error.");
  435. }
  436. },
  437. {
  438. name: "Lambda consisting of question-mark operator with false-branch wrapped in parens",
  439. body: function () {
  440. var l = () => true ? 1 : (0)
  441. assert.areEqual('() => true ? 1 : (0)', '' + l, "Lambda to string should include the parens wrapping the false branch");
  442. var l = () => true ? 1 : ('๏บบ')
  443. assert.areEqual("() => true ? 1 : ('๏บบ')", '' + l, "Multi-byte characters should not break the string");
  444. var s = "() => true ? 1 : ('\u{20ac}')";
  445. var l = eval(s);
  446. assert.areEqual(s, '' + l, "Unicode byte sequences should not break the string");
  447. var l = async() => true ? 1 : (0);
  448. assert.areEqual('async() => true ? 1 : (0)', '' + l, "Async lambda should also be correct");
  449. var l = () => true ? 1 : (() => false ? 1 : (0))
  450. assert.areEqual('() => true ? 1 : (() => false ? 1 : (0))', '' + l, "Nested lambda to string should be correct");
  451. var l = async() => true ? 1 : (() => false ? 1 : (0))
  452. assert.areEqual("async() => true ? 1 : (() => false ? 1 : (0))", '' + l, "Nested async lambda should be correct");
  453. }
  454. },
  455. {
  456. name: "Lambda consisting of new expression where constructor is wrapped in parens",
  457. body: function () {
  458. var l = () => new (Boolean)
  459. assert.areEqual('() => new (Boolean)', '' + l, "Lambda to string should include the parens wrapping the constructor");
  460. var l = async () => new (Boolean)
  461. assert.areEqual('async () => new (Boolean)', '' + l, "Async lambda should work");
  462. }
  463. },
  464. {
  465. name: "Async lambda consisting of single await which is wrapped in parens",
  466. body: function () {
  467. var l = async () => await (5)
  468. assert.areEqual('async () => await (5)', '' + l, "Lambda to string should include the parens wrapping the await argument");
  469. var l = () => await (5)
  470. assert.areEqual('() => await (5)', '' + l, "Regular lambda should also work, though this await looks like a function call");
  471. }
  472. }
  473. ];
  474. testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });