Source code

Revision control

Copy as Markdown

Other Tools

// Repeats the test from 'function/function-toString-discard-source.js' and
// additionally verifies the name matches the expected value.
//
// This behaviour is not required by the ECMAScript standard.
// The Function.prototype.toString() representation of sourceless functions
// must match the NativeFunction syntax.
function test() {
// Greatly (!) simplified patterns for the PropertyName production.
var propertyName = [
// PropertyName :: LiteralPropertyName :: IdentifierName
"\\w+",
// PropertyName :: LiteralPropertyName :: StringLiteral
"(?:'[^']*')",
"(?:\"[^\"]*\")",
// PropertyName :: LiteralPropertyName :: NumericLiteral
"\\d+",
// PropertyName :: ComputedPropertyName
"(?:\\[[^\\]]+\\])",
].join("|")
var nativeCode = RegExp([
"^", "function", ("(" + propertyName + ")?"), "\\(", "\\)", "\\{", "\\[native code\\]", "\\}", "$"
].join("\\s*"));
function assertFunctionName(fun, expected) {
var match = nativeCode.exec(fun.toString());
assertEq(match[1], expected);
}
// Function declarations.
eval(`
function funDecl() {}
function* genDecl() {}
async function asyncFunDecl() {}
async function* asyncGenDecl() {}
`);
assertFunctionName(funDecl, "funDecl");
assertFunctionName(genDecl, "genDecl");
assertFunctionName(asyncFunDecl, "asyncFunDecl");
assertFunctionName(asyncGenDecl, "asyncGenDecl");
// Named function expressions.
eval(`
var funExpr = function fn() {};
var genExpr = function* fn() {};
var asyncFunExpr = async function fn() {};
var asyncGenExpr = async function* fn() {};
`);
assertFunctionName(funExpr, "fn");
assertFunctionName(genExpr, "fn");
assertFunctionName(asyncFunExpr, "fn");
assertFunctionName(asyncGenExpr, "fn");
// Anonymous function expressions.
eval(`
var funExprAnon = function() {};
var genExprAnon = function*() {};
var asyncFunExprAnon = async function() {};
var asyncGenExprAnon = async function*() {};
`);
assertFunctionName(funExprAnon, undefined);
assertFunctionName(genExprAnon, undefined);
assertFunctionName(asyncFunExprAnon, undefined);
assertFunctionName(asyncGenExprAnon, undefined);
// Class declarations and expressions (implicit constructor).
eval(`
class classDecl {}
var classExpr = class C {};
var classExprAnon = class {};
var classExprAnonField = class {x = 1};
this.classDecl = classDecl;
`);
assertFunctionName(classDecl, "classDecl");
assertFunctionName(classExpr, "C");
assertFunctionName(classExprAnon, undefined);
assertFunctionName(classExprAnonField, undefined);
// Class declarations and expressions (explicit constructor).
eval(`
class classDecl { constructor() {} }
var classExpr = class C { constructor() {} };
var classExprAnon = class { constructor() {} };
this.classDecl = classDecl;
`);
assertFunctionName(classDecl, "classDecl");
assertFunctionName(classExpr, "C");
assertFunctionName(classExprAnon, undefined);
// Method definitions (identifier names).
eval(`
var obj = {
m() {},
*gm() {},
async am() {},
async* agm() {},
get x() {},
set x(_) {},
};
`);
assertFunctionName(obj.m, undefined);
assertFunctionName(obj.gm, undefined);
assertFunctionName(obj.am, undefined);
assertFunctionName(obj.agm, undefined);
assertFunctionName(Object.getOwnPropertyDescriptor(obj, "x").get, undefined);
assertFunctionName(Object.getOwnPropertyDescriptor(obj, "x").set, undefined);
// Method definitions (string names).
eval(`
var obj = {
"foo m"() {},
* "foo gm"() {},
async "foo am"() {},
async* "foo agm"() {},
get "foo x"() {},
set "foo x"(_) {},
};
`);
assertFunctionName(obj["foo m"], undefined);
assertFunctionName(obj["foo gm"], undefined);
assertFunctionName(obj["foo am"], undefined);
assertFunctionName(obj["foo agm"], undefined);
assertFunctionName(Object.getOwnPropertyDescriptor(obj, "foo x").get, undefined);
assertFunctionName(Object.getOwnPropertyDescriptor(obj, "foo x").set, undefined);
// Method definitions (number names).
eval(`
var obj = {
100() {},
*200() {},
async 300() {},
async* 400() {},
get 500() {},
set 500(_) {},
};
`);
assertFunctionName(obj[100], undefined);
assertFunctionName(obj[200], undefined);
assertFunctionName(obj[300], undefined);
assertFunctionName(obj[400], undefined);
assertFunctionName(Object.getOwnPropertyDescriptor(obj, 500).get, undefined);
assertFunctionName(Object.getOwnPropertyDescriptor(obj, 500).set, undefined);
// Method definitions (computed property names).
var sym1 = Symbol();
var sym2 = Symbol("desc");
var sym3 = Symbol.for("reg-sym");
var sym4 = Symbol.match;
var sym5 = Symbol();
eval(`
var obj = {
[sym1]() {},
*[sym2]() {},
async [sym3]() {},
async* [sym4]() {},
get [sym5]() {},
set [sym5](_) {},
};
`);
assertFunctionName(obj[sym1], undefined);
assertFunctionName(obj[sym2], undefined);
assertFunctionName(obj[sym3], undefined);
assertFunctionName(obj[sym4], undefined);
assertFunctionName(Object.getOwnPropertyDescriptor(obj, sym5).get, undefined);
assertFunctionName(Object.getOwnPropertyDescriptor(obj, sym5).set, undefined);
// Arrow functions.
eval(`
var arrowFn = () => {};
var asyncArrowFn = () => {};
`);
assertFunctionName(arrowFn, undefined);
assertFunctionName(asyncArrowFn, undefined);
// asm.js functions.
eval(`
function asm() {
"use asm";
function f(){ return 0|0; }
return {f: f};
}
`);
assertFunctionName(asm, "asm");
assertFunctionName(asm().f, "f");
}
var g = newGlobal({ discardSource: true });
g.evaluate(test.toString() + "test()");