From 5ef44cf6484b9dfd49c0174ac2969a29587a1bbd Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Mon, 19 Mar 2018 15:47:10 +0100 Subject: Part 1: Implement ES6 function name property semantics Issue #78 --- .../ecma_6/Function/function-name-assignment.js | 139 +++++++++++++++++++++ .../tests/ecma_6/Function/function-name-binding.js | 54 ++++++++ .../tests/ecma_6/Function/function-name-class.js | 32 +++++ js/src/tests/ecma_6/Function/function-name-for.js | 31 +++++ .../tests/ecma_6/Function/function-name-method.js | 70 +++++++++++ .../ecma_6/Function/function-name-property.js | 58 +++++++++ 6 files changed, 384 insertions(+) create mode 100644 js/src/tests/ecma_6/Function/function-name-assignment.js create mode 100644 js/src/tests/ecma_6/Function/function-name-binding.js create mode 100644 js/src/tests/ecma_6/Function/function-name-class.js create mode 100644 js/src/tests/ecma_6/Function/function-name-for.js create mode 100644 js/src/tests/ecma_6/Function/function-name-method.js create mode 100644 js/src/tests/ecma_6/Function/function-name-property.js (limited to 'js/src/tests') diff --git a/js/src/tests/ecma_6/Function/function-name-assignment.js b/js/src/tests/ecma_6/Function/function-name-assignment.js new file mode 100644 index 000000000..5e4d1c004 --- /dev/null +++ b/js/src/tests/ecma_6/Function/function-name-assignment.js @@ -0,0 +1,139 @@ +var BUGNUMBER = 883377; +var summary = "Anonymous function name should be set based on assignment"; + +print(BUGNUMBER + ": " + summary); + +var fooSymbol = Symbol("foo"); +var emptySymbol = Symbol(""); +var undefSymbol = Symbol(); +var globalVar; + +var exprs = [ + ["function() {}", false], + ["function named() {}", true], + ["function*() {}", false], + ["function* named() {}", true], + ["async function() {}", false], + ["async function named() {}", true], + ["() => {}", false], + ["async () => {}", false], + ["class {}", false], + ["class named {}", true], +]; + +function testAssignmentExpression(expr, named) { + eval(` + var assignment; + assignment = ${expr}; + assertEq(assignment.name, named ? "named" : "assignment"); + + globalVar = ${expr}; + assertEq(globalVar.name, named ? "named" : "globalVar"); + + var obj = { dynamic: null }; + with (obj) { + dynamic = ${expr}; + } + assertEq(obj.dynamic.name, named ? "named" : "dynamic"); + + (function namedLambda(param1, param2) { + var assignedToNamedLambda; + assignedToNamedLambda = namedLambda = ${expr}; + assertEq(namedLambda.name, "namedLambda"); + assertEq(assignedToNamedLambda.name, named ? "named" : "namedLambda"); + + param1 = ${expr}; + assertEq(param1.name, named ? "named" : "param1"); + + { + let param1 = ${expr}; + assertEq(param1.name, named ? "named" : "param1"); + + param2 = ${expr}; + assertEq(param2.name, named ? "named" : "param2"); + } + })(); + + { + let nextedLexical1, nextedLexical2; + { + let nextedLexical1 = ${expr}; + assertEq(nextedLexical1.name, named ? "named" : "nextedLexical1"); + + nextedLexical2 = ${expr}; + assertEq(nextedLexical2.name, named ? "named" : "nextedLexical2"); + } + } + `); + + // Not applicable cases: not IsIdentifierRef. + eval(` + var inParen; + (inParen) = ${expr}; + assertEq(inParen.name, named ? "named" : ""); + `); + + // Not applicable cases: not direct RHS. + if (!expr.includes("=>")) { + eval(` + var a = true && ${expr}; + assertEq(a.name, named ? "named" : ""); + `); + } else { + // Arrow function cannot be RHS of &&. + eval(` + var a = true && (${expr}); + assertEq(a.name, named ? "named" : ""); + `); + } + + // Not applicable cases: property. + eval(` + var obj = {}; + + obj.prop = ${expr}; + assertEq(obj.prop.name, named ? "named" : ""); + + obj["literal"] = ${expr}; + assertEq(obj["literal"].name, named ? "named" : ""); + `); + + // Not applicable cases: assigned again. + eval(` + var tmp = [${expr}]; + assertEq(tmp[0].name, named ? "named" : ""); + + var assignment; + assignment = tmp[0]; + assertEq(assignment.name, named ? "named" : ""); + `); +} +for (var [expr, named] of exprs) { + testAssignmentExpression(expr, named); +} + +function testVariableDeclaration(expr, named) { + eval(` + var varDecl = ${expr}; + assertEq(varDecl.name, named ? "named" : "varDecl"); + `); +} +for (var [expr, named] of exprs) { + testVariableDeclaration(expr, named); +} + +function testLexicalBinding(expr, named) { + eval(` + let lexical = ${expr}; + assertEq(lexical.name, named ? "named" : "lexical"); + + const constLexical = ${expr}; + assertEq(constLexical.name, named ? "named" : "constLexical"); + `); +} +for (var [expr, named] of exprs) { + testLexicalBinding(expr, named); +} + +if (typeof reportCompare === "function") + reportCompare(0, 0); diff --git a/js/src/tests/ecma_6/Function/function-name-binding.js b/js/src/tests/ecma_6/Function/function-name-binding.js new file mode 100644 index 000000000..bdd6c131c --- /dev/null +++ b/js/src/tests/ecma_6/Function/function-name-binding.js @@ -0,0 +1,54 @@ +var BUGNUMBER = 883377; +var summary = "Anonymous function name should be set based on binding pattern"; + +print(BUGNUMBER + ": " + summary); + +var exprs = [ + ["function() {}", false], + ["function named() {}", true], + ["function*() {}", false], + ["function* named() {}", true], + ["async function() {}", false], + ["async function named() {}", true], + ["() => {}", false], + ["async () => {}", false], + ["class {}", false], + ["class named {}", true], +]; + +function testAssignmentProperty(expr, named) { + var f = eval(`(function({ prop1 = ${expr} }) { return prop1; })`); + assertEq(f({}).name, named ? "named" : "prop1"); + + eval(` + var { prop1 = ${expr} } = {}; + assertEq(prop1.name, named ? "named" : "prop1"); + `); +} +for (var [expr, named] of exprs) { + testAssignmentProperty(expr, named); +} + +function testAssignmentElement(expr, named) { + var f = eval(`(function([elem1 = ${expr}]) { return elem1; })`); + assertEq(f([]).name, named ? "named" : "elem1"); + + eval(` + var [elem1 = ${expr}] = []; + assertEq(elem1.name, named ? "named" : "elem1"); + `); +} +for (var [expr, named] of exprs) { + testAssignmentElement(expr, named); +} + +function testSingleNameBinding(expr, named) { + var f = eval(`(function(param1 = ${expr}) { return param1; })`); + assertEq(f().name, named ? "named" : "param1"); +} +for (var [expr, named] of exprs) { + testSingleNameBinding(expr, named); +} + +if (typeof reportCompare === "function") + reportCompare(0, 0); diff --git a/js/src/tests/ecma_6/Function/function-name-class.js b/js/src/tests/ecma_6/Function/function-name-class.js new file mode 100644 index 000000000..edde69055 --- /dev/null +++ b/js/src/tests/ecma_6/Function/function-name-class.js @@ -0,0 +1,32 @@ +var BUGNUMBER = 883377; +var summary = "Anonymous class with name method shouldn't be affected by assignment"; + +print(BUGNUMBER + ": " + summary); + +var classWithStaticNameMethod = class { static name() {} }; +assertEq(typeof classWithStaticNameMethod.name, "function"); + +var classWithStaticNameGetter = class { static get name() { return "static name"; } }; +assertEq(typeof Object.getOwnPropertyDescriptor(classWithStaticNameGetter, "name").get, "function"); +assertEq(classWithStaticNameGetter.name, "static name"); + +var classWithStaticNameSetter = class { static set name(v) {} }; +assertEq(typeof Object.getOwnPropertyDescriptor(classWithStaticNameSetter, "name").set, "function"); + +var n = "NAME".toLowerCase(); +var classWithStaticNameMethodComputed = class { static [n]() {} }; +assertEq(typeof classWithStaticNameMethodComputed.name, "function"); + +// It doesn't apply for non-static method. + +var classWithNameMethod = class { name() {} }; +assertEq(classWithNameMethod.name, "classWithNameMethod"); + +var classWithNameGetter = class { get name() { return "name"; } }; +assertEq(classWithNameGetter.name, "classWithNameGetter"); + +var classWithNameSetter = class { set name(v) {} }; +assertEq(classWithNameSetter.name, "classWithNameSetter"); + +if (typeof reportCompare === "function") + reportCompare(0, 0); diff --git a/js/src/tests/ecma_6/Function/function-name-for.js b/js/src/tests/ecma_6/Function/function-name-for.js new file mode 100644 index 000000000..2f04a5fa8 --- /dev/null +++ b/js/src/tests/ecma_6/Function/function-name-for.js @@ -0,0 +1,31 @@ +var BUGNUMBER = 883377; +var summary = "Anonymous function name should be set based on for-in initializer"; + +print(BUGNUMBER + ": " + summary); + +var exprs = [ + ["function() {}", false], + ["function named() {}", true], + ["function*() {}", false], + ["function* named() {}", true], + ["async function() {}", false], + ["async function named() {}", true], + ["() => {}", false], + ["async () => {}", false], + ["class {}", false], + ["class named {}", true], +]; + +function testForInHead(expr, named) { + eval(` + for (var forInHead = ${expr} in {}) { + } + `); + assertEq(forInHead.name, named ? "named" : "forInHead"); +} +for (var [expr, named] of exprs) { + testForInHead(expr, named); +} + +if (typeof reportCompare === "function") + reportCompare(0, 0); diff --git a/js/src/tests/ecma_6/Function/function-name-method.js b/js/src/tests/ecma_6/Function/function-name-method.js new file mode 100644 index 000000000..3b2eeee79 --- /dev/null +++ b/js/src/tests/ecma_6/Function/function-name-method.js @@ -0,0 +1,70 @@ +var BUGNUMBER = 883377; +var summary = "Anonymous function name should be set based on method definition"; + +print(BUGNUMBER + ": " + summary); + +var fooSymbol = Symbol("foo"); +var emptySymbol = Symbol(""); +var undefSymbol = Symbol(); + +function testMethod(prefix, classPrefix="", prototype=false) { + var param = (prefix == "set" || prefix == "static set") ? "v" : ""; + var sep = classPrefix ? "" : ","; + var objOrClass = eval(`(${classPrefix}{ + ${prefix} prop(${param}) {} ${sep} + ${prefix} "literal"(${param}) {} ${sep} + ${prefix} ""(${param}) {} ${sep} + ${prefix} 5(${param}) {} ${sep} + ${prefix} [Symbol.iterator](${param}) {} ${sep} + ${prefix} [fooSymbol](${param}) {} ${sep} + ${prefix} [emptySymbol](${param}) {} ${sep} + ${prefix} [undefSymbol](${param}) {} ${sep} + ${prefix} [/a/](${param}) {} ${sep} + })`); + + var target = prototype ? objOrClass.prototype : objOrClass; + + function testOne(methodName, expectedName) { + var f; + if (prefix == "get" || prefix == "static get") { + f = Object.getOwnPropertyDescriptor(target, methodName).get; + expectedName = "get " + expectedName; + } else if (prefix == "set" || prefix == "static set") { + f = Object.getOwnPropertyDescriptor(target, methodName).set; + expectedName = "set " + expectedName; + } else { + f = Object.getOwnPropertyDescriptor(target, methodName).value; + } + + assertEq(f.name, expectedName); + } + testOne("prop", "prop"); + testOne("literal", "literal"); + testOne("", ""); + testOne(5, "5"); + testOne(Symbol.iterator, "[Symbol.iterator]"); + testOne(fooSymbol, "[foo]"); + testOne(emptySymbol, "[]"); + testOne(undefSymbol, ""); + testOne(/a/, "/a/"); +} +testMethod(""); +testMethod("*"); +testMethod("async"); +testMethod("get"); +testMethod("set"); + +testMethod("", "class", true); +testMethod("*", "class", true); +testMethod("async", "class", true); +testMethod("get", "class", true); +testMethod("set", "class", true); + +testMethod("static", "class"); +testMethod("static *", "class"); +testMethod("static async", "class"); +testMethod("static get", "class"); +testMethod("static set", "class"); + +if (typeof reportCompare === "function") + reportCompare(0, 0); diff --git a/js/src/tests/ecma_6/Function/function-name-property.js b/js/src/tests/ecma_6/Function/function-name-property.js new file mode 100644 index 000000000..7ad174b10 --- /dev/null +++ b/js/src/tests/ecma_6/Function/function-name-property.js @@ -0,0 +1,58 @@ +var BUGNUMBER = 883377; +var summary = "Anonymous function name should be set based on property name"; + +print(BUGNUMBER + ": " + summary); + +var fooSymbol = Symbol("foo"); +var emptySymbol = Symbol(""); +var undefSymbol = Symbol(); + +var exprs = [ + ["function() {}", false], + ["function named() {}", true], + ["function*() {}", false], + ["function* named() {}", true], + ["async function() {}", false], + ["async function named() {}", true], + ["() => {}", false], + ["async () => {}", false], + ["class {}", false], + ["class named {}", true], +]; + +function testPropertyDefinition(expr, named) { + var obj = eval(`({ + prop: ${expr}, + "literal": ${expr}, + "": ${expr}, + 5: ${expr}, + 0.4: ${expr}, + [Symbol.iterator]: ${expr}, + [fooSymbol]: ${expr}, + [emptySymbol]: ${expr}, + [undefSymbol]: ${expr}, + [/a/]: ${expr}, + })`); + assertEq(obj.prop.name, named ? "named" : "prop"); + assertEq(obj["literal"].name, named ? "named" : "literal"); + assertEq(obj[""].name, named ? "named" : ""); + assertEq(obj[5].name, named ? "named" : "5"); + assertEq(obj[0.4].name, named ? "named" : "0.4"); + assertEq(obj[Symbol.iterator].name, named ? "named" : "[Symbol.iterator]"); + assertEq(obj[fooSymbol].name, named ? "named" : "[foo]"); + assertEq(obj[emptySymbol].name, named ? "named" : "[]"); + assertEq(obj[undefSymbol].name, named ? "named" : ""); + assertEq(obj[/a/].name, named ? "named" : "/a/"); + + // Not applicable cases: __proto__. + obj = { + __proto__: function() {} + }; + assertEq(obj.__proto__.name, ""); +} +for (var [expr, named] of exprs) { + testPropertyDefinition(expr, named); +} + +if (typeof reportCompare === "function") + reportCompare(0, 0); -- cgit v1.2.3