mirror of
https://github.com/facebookarchive/prepack.git
synced 2024-09-11 14:46:37 +03:00
Ran Prettier over codebase.
Summary: Closes https://github.com/facebook/prepack/pull/778 Differential Revision: D5367120 Pulled By: NTillmann fbshipit-source-id: 4c8810efee816d699157e59ea9ba0c8d57950015
This commit is contained in:
parent
d182dcda70
commit
4824b47038
@ -51,20 +51,24 @@ exec("flow check --profile", function(error, stdout, stderr) {
|
||||
// NB: This doesn't prevent cycles using "import type" because those are
|
||||
// erased in the lib folder but madge doesn't work with flow type imports.
|
||||
|
||||
madge('./lib/').then((res) => {
|
||||
madge("./lib/").then(res => {
|
||||
let deps = res.obj();
|
||||
let idx_deps = res.depends('intrinsics/index');
|
||||
if (idx_deps.length !== 1 || idx_deps[0] !== 'construct_realm') {
|
||||
let idx_deps = res.depends("intrinsics/index");
|
||||
if (idx_deps.length !== 1 || idx_deps[0] !== "construct_realm") {
|
||||
console.log("Invalid Dependency: Intrinsics index depends on " + idx_deps[0]);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
for (let dep in deps) {
|
||||
// Nothing in intrinsics/ecma262 depends on anything but intrinsics/index except Error and global.
|
||||
if (dep.startsWith("intrinsics/ecma262") && dep !== "intrinsics/ecma262/Error" && dep !== "intrinsics/ecma262/global") {
|
||||
let ext_deps =
|
||||
res.depends(dep).filter(
|
||||
(depend) => depend !== "intrinsics/index" && !depend.startsWith("intrinsics/ecma262"));
|
||||
if (
|
||||
dep.startsWith("intrinsics/ecma262") &&
|
||||
dep !== "intrinsics/ecma262/Error" &&
|
||||
dep !== "intrinsics/ecma262/global"
|
||||
) {
|
||||
let ext_deps = res
|
||||
.depends(dep)
|
||||
.filter(depend => depend !== "intrinsics/index" && !depend.startsWith("intrinsics/ecma262"));
|
||||
if (ext_deps.length > 0) {
|
||||
console.log("Invalid Dependency: " + dep + " depends on " + ext_deps);
|
||||
process.exit(1);
|
||||
|
@ -14,8 +14,8 @@ import { prepackFileSync } from "../lib/prepack-node.js";
|
||||
import invariant from "../lib/invariant.js";
|
||||
|
||||
let chalk = require("chalk");
|
||||
let path = require("path");
|
||||
let fs = require("fs");
|
||||
let path = require("path");
|
||||
let fs = require("fs");
|
||||
|
||||
function search(dir, relative) {
|
||||
let tests = [];
|
||||
@ -42,10 +42,8 @@ let tests = search(`${__dirname}/../test/source-maps`, "test/source-maps");
|
||||
|
||||
function errorHandler(diagnostic: CompilerDiagnostics): ErrorHandlerResult {
|
||||
let loc = diagnostic.location;
|
||||
if (loc)
|
||||
console.log(`${loc.start.line}:${loc.start.column + 1} ${diagnostic.errorCode} ${diagnostic.message}`);
|
||||
else
|
||||
console.log(`unknown location: ${diagnostic.errorCode} ${diagnostic.message}`);
|
||||
if (loc) console.log(`${loc.start.line}:${loc.start.column + 1} ${diagnostic.errorCode} ${diagnostic.message}`);
|
||||
else console.log(`unknown location: ${diagnostic.errorCode} ${diagnostic.message}`);
|
||||
return "Fail";
|
||||
}
|
||||
|
||||
@ -79,8 +77,7 @@ function generateTest(name: string, test_path: string, code: string): boolean {
|
||||
process.exit(1);
|
||||
invariant(false);
|
||||
}
|
||||
newCode2 = s.code +
|
||||
"\nf();\n\n//# sourceMappingURL=" + name + ".new2.js.map\n";
|
||||
newCode2 = s.code + "\nf();\n\n//# sourceMappingURL=" + name + ".new2.js.map\n";
|
||||
fs.writeFileSync(name + ".new2.js", newCode2);
|
||||
newMap2 = s.map;
|
||||
fs.writeFileSync(name + ".new2.js.map", JSON.stringify(newMap2));
|
||||
@ -105,7 +102,7 @@ function generateTest(name: string, test_path: string, code: string): boolean {
|
||||
function run() {
|
||||
let failed = 0;
|
||||
let passed = 0;
|
||||
let total = 0;
|
||||
let total = 0;
|
||||
|
||||
for (let test of tests) {
|
||||
// filter hidden files
|
||||
@ -113,15 +110,12 @@ function run() {
|
||||
if (test.name.endsWith("~")) continue;
|
||||
|
||||
total++;
|
||||
if (generateTest(test.name, test.path, test.file))
|
||||
passed++;
|
||||
else
|
||||
failed++;
|
||||
if (generateTest(test.name, test.path, test.file)) passed++;
|
||||
else failed++;
|
||||
}
|
||||
|
||||
console.log("Generated:", `${passed}/${total}`, (Math.round((passed / total) * 100) || 0) + "%");
|
||||
console.log("Generated:", `${passed}/${total}`, (Math.round(passed / total * 100) || 0) + "%");
|
||||
return failed === 0;
|
||||
}
|
||||
|
||||
if (!run())
|
||||
process.exit(1);
|
||||
if (!run()) process.exit(1);
|
||||
|
@ -17,23 +17,22 @@ let fs = require("fs");
|
||||
import type { BabelNodeSourceLocation, BabelNodeBlockStatement } from "babel-types";
|
||||
|
||||
function createLogStatement(loc: BabelNodeSourceLocation) {
|
||||
return t.expressionStatement(t.callExpression(
|
||||
t.memberExpression(t.identifier("console"), t.identifier("log")),
|
||||
[t.stringLiteral(`[instrumentation] #${loc.start.line}`)]));
|
||||
return t.expressionStatement(
|
||||
t.callExpression(t.memberExpression(t.identifier("console"), t.identifier("log")), [
|
||||
t.stringLiteral(`[instrumentation] #${loc.start.line}`),
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
function instrument(inputFilename: string, outputFilename: string) {
|
||||
let code = fs.readFileSync(inputFilename, "utf8");
|
||||
let ast = parse(code, { inputFilename, sourceType: "script" });
|
||||
traverse(
|
||||
ast,
|
||||
function (node) {
|
||||
if (node.type === "BlockStatement") {
|
||||
if (node.loc) ((node: any): BabelNodeBlockStatement).body.unshift(createLogStatement(node.loc));
|
||||
}
|
||||
return false;
|
||||
traverse(ast, function(node) {
|
||||
if (node.type === "BlockStatement") {
|
||||
if (node.loc) ((node: any): BabelNodeBlockStatement).body.unshift(createLogStatement(node.loc));
|
||||
}
|
||||
);
|
||||
return false;
|
||||
});
|
||||
code = generate(ast, {}, "").code;
|
||||
if (!outputFilename) outputFilename = inputFilename + "-instrumented.js";
|
||||
fs.writeFileSync(outputFilename, code);
|
||||
@ -45,9 +44,11 @@ args.splice(0, 2);
|
||||
let inputFilename;
|
||||
let outputFilename;
|
||||
while (args.length) {
|
||||
let arg = args[0]; args.shift();
|
||||
let arg = args[0];
|
||||
args.shift();
|
||||
if (arg === "--out") {
|
||||
arg = args[0]; args.shift();
|
||||
arg = args[0];
|
||||
args.shift();
|
||||
outputFilename = arg;
|
||||
} else if (arg === "--help") {
|
||||
console.log("Usage: instrumentor.js [ --out output.js ] [ -- | input.js ]");
|
||||
|
@ -14,8 +14,8 @@ import { prepackFileSync } from "../lib/prepack-node.js";
|
||||
import invariant from "../lib/invariant.js";
|
||||
|
||||
let chalk = require("chalk");
|
||||
let path = require("path");
|
||||
let fs = require("fs");
|
||||
let path = require("path");
|
||||
let fs = require("fs");
|
||||
|
||||
function search(dir, relative) {
|
||||
let tests = [];
|
||||
@ -28,7 +28,7 @@ function search(dir, relative) {
|
||||
if (stat.isFile()) {
|
||||
tests.push({
|
||||
file: fs.readFileSync(loc, "utf8"),
|
||||
name: path.join(relative, name)
|
||||
name: path.join(relative, name),
|
||||
});
|
||||
} else if (stat.isDirectory()) {
|
||||
tests = tests.concat(search(loc, path.join(relative, name)));
|
||||
@ -41,7 +41,11 @@ function search(dir, relative) {
|
||||
|
||||
let tests = search(`${__dirname}/../test/error-handler`, "test/error-handler");
|
||||
|
||||
function errorHandler(retval: ErrorHandlerResult, errors: Array<CompilerDiagnostics>, error: CompilerDiagnostics): ErrorHandlerResult {
|
||||
function errorHandler(
|
||||
retval: ErrorHandlerResult,
|
||||
errors: Array<CompilerDiagnostics>,
|
||||
error: CompilerDiagnostics
|
||||
): ErrorHandlerResult {
|
||||
errors.push(error);
|
||||
return retval;
|
||||
}
|
||||
@ -63,7 +67,7 @@ function runTest(name: string, code: string): boolean {
|
||||
prepackFileSync(name, {
|
||||
internalDebug: false,
|
||||
mathRandomSeed: "0",
|
||||
onError: errorHandler.bind(null, recover ? 'Recover' : 'Fail', errors),
|
||||
onError: errorHandler.bind(null, recover ? "Recover" : "Fail", errors),
|
||||
serialize: true,
|
||||
speculate: true,
|
||||
});
|
||||
@ -101,7 +105,7 @@ function runTest(name: string, code: string): boolean {
|
||||
function run() {
|
||||
let failed = 0;
|
||||
let passed = 0;
|
||||
let total = 0;
|
||||
let total = 0;
|
||||
|
||||
for (let test of tests) {
|
||||
// filter hidden files
|
||||
@ -109,15 +113,12 @@ function run() {
|
||||
if (test.name.endsWith("~")) continue;
|
||||
|
||||
total++;
|
||||
if (runTest(test.name, test.file))
|
||||
passed++;
|
||||
else
|
||||
failed++;
|
||||
if (runTest(test.name, test.file)) passed++;
|
||||
else failed++;
|
||||
}
|
||||
|
||||
console.log("Passed:", `${passed}/${total}`, (Math.round((passed / total) * 100) || 0) + "%");
|
||||
console.log("Passed:", `${passed}/${total}`, (Math.round(passed / total * 100) || 0) + "%");
|
||||
return failed === 0;
|
||||
}
|
||||
|
||||
if (!run())
|
||||
process.exit(1);
|
||||
if (!run()) process.exit(1);
|
||||
|
@ -14,8 +14,8 @@ import type { BabelNodeSourceLocation } from "babel-types";
|
||||
import { prepackFileSync } from "../lib/prepack-node.js";
|
||||
|
||||
let chalk = require("chalk");
|
||||
let path = require("path");
|
||||
let fs = require("fs");
|
||||
let path = require("path");
|
||||
let fs = require("fs");
|
||||
|
||||
function search(dir, relative) {
|
||||
let tests = [];
|
||||
@ -28,7 +28,7 @@ function search(dir, relative) {
|
||||
if (stat.isFile()) {
|
||||
tests.push({
|
||||
file: fs.readFileSync(loc, "utf8"),
|
||||
name: path.join(relative, name)
|
||||
name: path.join(relative, name),
|
||||
});
|
||||
} else if (stat.isDirectory()) {
|
||||
tests = tests.concat(search(loc, path.join(relative, name)));
|
||||
@ -43,8 +43,7 @@ let tests = search(`${__dirname}/../facebook/test`, "facebook/test");
|
||||
|
||||
let errors: Map<BabelNodeSourceLocation, CompilerDiagnostics> = new Map();
|
||||
function errorHandler(diagnostic: CompilerDiagnostics): ErrorHandlerResult {
|
||||
if (diagnostic.location)
|
||||
errors.set(diagnostic.location, diagnostic);
|
||||
if (diagnostic.location) errors.set(diagnostic.location, diagnostic);
|
||||
return "Fail";
|
||||
}
|
||||
|
||||
@ -78,7 +77,7 @@ function runTest(name: string, code: string): boolean {
|
||||
function run() {
|
||||
let failed = 0;
|
||||
let passed = 0;
|
||||
let total = 0;
|
||||
let total = 0;
|
||||
|
||||
for (let test of tests) {
|
||||
// filter hidden files
|
||||
@ -86,15 +85,12 @@ function run() {
|
||||
if (test.name.endsWith("~")) continue;
|
||||
|
||||
total++;
|
||||
if (runTest(test.name, test.file))
|
||||
passed++;
|
||||
else
|
||||
failed++;
|
||||
if (runTest(test.name, test.file)) passed++;
|
||||
else failed++;
|
||||
}
|
||||
|
||||
console.log("Passed:", `${passed}/${total}`, (Math.round((passed / total) * 100) || 0) + "%");
|
||||
console.log("Passed:", `${passed}/${total}`, (Math.round(passed / total * 100) || 0) + "%");
|
||||
return failed === 0;
|
||||
}
|
||||
|
||||
if (!run())
|
||||
process.exit(1);
|
||||
if (!run()) process.exit(1);
|
||||
|
@ -16,9 +16,9 @@ let IntrospectionThrowCompletion = require("../lib/completions.js").Introspectio
|
||||
let ThrowCompletion = require("../lib/completions.js").ThrowCompletion;
|
||||
|
||||
let chalk = require("chalk");
|
||||
let path = require("path");
|
||||
let fs = require("fs");
|
||||
let vm = require("vm");
|
||||
let path = require("path");
|
||||
let fs = require("fs");
|
||||
let vm = require("vm");
|
||||
|
||||
function search(dir, relative) {
|
||||
let tests = [];
|
||||
@ -30,7 +30,7 @@ function search(dir, relative) {
|
||||
if (stat.isFile()) {
|
||||
tests.push({
|
||||
file: fs.readFileSync(loc, "utf8"),
|
||||
name: path.join(relative, name)
|
||||
name: path.join(relative, name),
|
||||
});
|
||||
} else if (stat.isDirectory()) {
|
||||
tests = tests.concat(search(loc, path.join(relative, name)));
|
||||
@ -43,8 +43,11 @@ function search(dir, relative) {
|
||||
let tests = search(`${__dirname}/../test/residual`, "test/residual");
|
||||
|
||||
function exec(code) {
|
||||
let script = new vm.Script(`var global = this; var self = this; var __result = ${code} // keep newline here as code may end with comment
|
||||
; report(__result);`, { cachedDataProduced: false });
|
||||
let script = new vm.Script(
|
||||
`var global = this; var self = this; var __result = ${code} // keep newline here as code may end with comment
|
||||
; report(__result);`,
|
||||
{ cachedDataProduced: false }
|
||||
);
|
||||
|
||||
let result = "";
|
||||
let logOutput = "";
|
||||
@ -70,8 +73,8 @@ function exec(code) {
|
||||
},
|
||||
error(...s) {
|
||||
write("ERROR:", s);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
return result + logOutput;
|
||||
}
|
||||
@ -126,7 +129,7 @@ return __result; }).call(this);`);
|
||||
}
|
||||
}
|
||||
if (markersIssue) break;
|
||||
actual = exec(`(function () { ${newCode}; // keep newline here as code may end with comment
|
||||
actual = exec(`(function () { ${newCode}; // keep newline here as code may end with comment
|
||||
return __result; }).call(this);`);
|
||||
if (expected !== actual) {
|
||||
console.log(chalk.red("Output mismatch!"));
|
||||
@ -160,7 +163,7 @@ return __result; }).call(this);`);
|
||||
function run() {
|
||||
let failed = 0;
|
||||
let passed = 0;
|
||||
let total = 0;
|
||||
let total = 0;
|
||||
|
||||
for (let test of tests) {
|
||||
// filter hidden files
|
||||
@ -169,15 +172,12 @@ function run() {
|
||||
if (test.file.includes("// skip")) continue;
|
||||
|
||||
total++;
|
||||
if (runTest(test.name, test.file))
|
||||
passed++;
|
||||
else
|
||||
failed++;
|
||||
if (runTest(test.name, test.file)) passed++;
|
||||
else failed++;
|
||||
}
|
||||
|
||||
console.log("Passed:", `${passed}/${total}`, (Math.round((passed / total) * 100) || 0) + "%");
|
||||
console.log("Passed:", `${passed}/${total}`, (Math.round(passed / total * 100) || 0) + "%");
|
||||
return failed === 0;
|
||||
}
|
||||
|
||||
if (!run())
|
||||
process.exit(1);
|
||||
if (!run()) process.exit(1);
|
||||
|
@ -18,10 +18,10 @@ let initializeGlobals = require("../lib/globals.js").default;
|
||||
let IsIntrospectionError = require("../lib/methods/index.js").IsIntrospectionError;
|
||||
|
||||
let chalk = require("chalk");
|
||||
let path = require("path");
|
||||
let fs = require("fs");
|
||||
let vm = require("vm");
|
||||
let os = require("os");
|
||||
let path = require("path");
|
||||
let fs = require("fs");
|
||||
let vm = require("vm");
|
||||
let os = require("os");
|
||||
let minimist = require("minimist");
|
||||
const EOL = os.EOL;
|
||||
|
||||
@ -35,7 +35,7 @@ function search(dir, relative) {
|
||||
if (stat.isFile()) {
|
||||
tests.push({
|
||||
file: fs.readFileSync(loc, "utf8"),
|
||||
name: path.join(relative, name)
|
||||
name: path.join(relative, name),
|
||||
});
|
||||
} else if (stat.isDirectory()) {
|
||||
tests = tests.concat(search(loc, path.join(relative, name)));
|
||||
@ -48,8 +48,11 @@ function search(dir, relative) {
|
||||
let tests = search(`${__dirname}/../test/serializer`, "test/serializer");
|
||||
|
||||
function exec(code) {
|
||||
let script = new vm.Script(`var global = this; var self = this; ${code}; // keep newline here as code may end with comment
|
||||
report(inspect());`, { cachedDataProduced: false });
|
||||
let script = new vm.Script(
|
||||
`var global = this; var self = this; ${code}; // keep newline here as code may end with comment
|
||||
report(inspect());`,
|
||||
{ cachedDataProduced: false }
|
||||
);
|
||||
|
||||
let result = "";
|
||||
let logOutput = "";
|
||||
@ -75,8 +78,8 @@ report(inspect());`, { cachedDataProduced: false });
|
||||
},
|
||||
error(...s) {
|
||||
write("ERROR:", s);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
return result + logOutput;
|
||||
}
|
||||
@ -95,12 +98,11 @@ function runTest(name, code, args) {
|
||||
delayUnsupportedRequires,
|
||||
internalDebug: true,
|
||||
serialize: true,
|
||||
uniqueSuffix: ""
|
||||
uniqueSuffix: "",
|
||||
};
|
||||
if (code.includes("// throws introspection error")) {
|
||||
let onError = (realm, e) => {
|
||||
if (IsIntrospectionError(realm, e))
|
||||
throw new Success();
|
||||
if (IsIntrospectionError(realm, e)) throw new Success();
|
||||
};
|
||||
try {
|
||||
let realmOptions = { serialize: true, compatibility, uniqueSuffix: "" };
|
||||
@ -201,11 +203,20 @@ function runTest(name, code, args) {
|
||||
if (i === 0 && functionCloneCountMatch) {
|
||||
let functionCount = parseInt(functionCloneCountMatch[1], 10);
|
||||
if (serialized.statistics && functionCount !== serialized.statistics.functionClones) {
|
||||
console.log(chalk.red(`Code generation serialized an unexpected number of clone functions. Expected: ${functionCount}, Got: ${serialized.statistics.functionClones}`));
|
||||
console.log(
|
||||
chalk.red(
|
||||
`Code generation serialized an unexpected number of clone functions. Expected: ${functionCount}, Got: ${serialized
|
||||
.statistics.functionClones}`
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (oldCode.replace(new RegExp(oldUniqueSuffix, "g"), "") === newCode.replace(new RegExp(newUniqueSuffix, "g"), "") || delayUnsupportedRequires) {
|
||||
if (
|
||||
oldCode.replace(new RegExp(oldUniqueSuffix, "g"), "") ===
|
||||
newCode.replace(new RegExp(newUniqueSuffix, "g"), "") ||
|
||||
delayUnsupportedRequires
|
||||
) {
|
||||
// The generated code reached a fixed point!
|
||||
return true;
|
||||
}
|
||||
@ -237,7 +248,7 @@ function runTest(name, code, args) {
|
||||
function run(args) {
|
||||
let failed = 0;
|
||||
let passed = 0;
|
||||
let total = 0;
|
||||
let total = 0;
|
||||
|
||||
for (let test of tests) {
|
||||
// filter hidden files
|
||||
@ -248,17 +259,14 @@ function run(args) {
|
||||
if (!test.name.includes(args.filter)) continue;
|
||||
|
||||
total++;
|
||||
if (runTest(test.name, test.file, args))
|
||||
passed++;
|
||||
else
|
||||
failed++;
|
||||
if (runTest(test.name, test.file, args)) passed++;
|
||||
else failed++;
|
||||
}
|
||||
|
||||
console.log("Passed:", `${passed}/${total}`, (Math.round((passed / total) * 100) || 0) + "%");
|
||||
console.log("Passed:", `${passed}/${total}`, (Math.round(passed / total * 100) || 0) + "%");
|
||||
return failed === 0;
|
||||
}
|
||||
|
||||
|
||||
// Object to store all command line arguments
|
||||
class ProgramArgs {
|
||||
verbose: boolean;
|
||||
@ -287,16 +295,13 @@ function main(): number {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
// Helper function to provide correct usage information to the user
|
||||
function usage(): string {
|
||||
return `Usage: ${process.argv[0]} ${process.argv[1]} ` + EOL +
|
||||
`[--verbose] [--filter <string>]`;
|
||||
return `Usage: ${process.argv[0]} ${process.argv[1]} ` + EOL + `[--verbose] [--filter <string>]`;
|
||||
}
|
||||
|
||||
|
||||
// NOTE: inheriting from Error does not seem to pass through an instanceof
|
||||
// check
|
||||
class ArgsParseError {
|
||||
@ -309,27 +314,22 @@ class ArgsParseError {
|
||||
// Parses through the command line arguments and throws errors if usage is incorrect
|
||||
function argsParse(): ProgramArgs {
|
||||
let parsedArgs = minimist(process.argv.slice(2), {
|
||||
string: [
|
||||
"filter"
|
||||
],
|
||||
boolean: [
|
||||
"verbose"
|
||||
],
|
||||
string: ["filter"],
|
||||
boolean: ["verbose"],
|
||||
default: {
|
||||
verbose: false,
|
||||
filter: ""
|
||||
}
|
||||
filter: "",
|
||||
},
|
||||
});
|
||||
if (typeof parsedArgs.verbose !== "boolean") {
|
||||
throw new ArgsParseError("verbose must be a boolean (either --verbose or not)");
|
||||
}
|
||||
if (typeof parsedArgs.filter !== "string") {
|
||||
throw new ArgsParseError("filter must be a string (relative path from serialize dirctory) (--filter abstract/Residual.js)");
|
||||
throw new ArgsParseError(
|
||||
"filter must be a string (relative path from serialize dirctory) (--filter abstract/Residual.js)"
|
||||
);
|
||||
}
|
||||
let programArgs = new ProgramArgs(
|
||||
parsedArgs.verbose,
|
||||
parsedArgs.filter
|
||||
);
|
||||
let programArgs = new ProgramArgs(parsedArgs.verbose, parsedArgs.filter);
|
||||
return programArgs;
|
||||
}
|
||||
|
||||
|
@ -33,9 +33,9 @@ import minimist from "minimist";
|
||||
|
||||
const EOL = os.EOL;
|
||||
const numCPUs = os.cpus().length;
|
||||
require('source-map-support').install();
|
||||
require("source-map-support").install();
|
||||
|
||||
type HarnessMap = { [key: string]: string; };
|
||||
type HarnessMap = { [key: string]: string };
|
||||
type TestRecord = { test: TestFileInfo, result: TestResult[] };
|
||||
type GroupsMap = { [key: string]: TestRecord[] };
|
||||
|
||||
@ -57,9 +57,7 @@ class TestTask {
|
||||
if ("file" in obj && typeof obj.file === "object") {
|
||||
return new TestTask(TestFileInfo.fromObject(obj.file));
|
||||
} else {
|
||||
throw new Error(
|
||||
`Cannot be converted to a TestTask: ${JSON.stringify(obj)}`
|
||||
);
|
||||
throw new Error(`Cannot be converted to a TestTask: ${JSON.stringify(obj)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -83,15 +81,10 @@ class TestFileInfo {
|
||||
// eslint-disable-next-line flowtype/no-weak-types
|
||||
static fromObject(obj: Object): TestFileInfo {
|
||||
// attempt to coerce the object into a TestFileInfo
|
||||
if (
|
||||
"location" in obj && typeof obj.location === "string" &&
|
||||
"isES6" in obj && typeof obj.isES6 === "boolean"
|
||||
) {
|
||||
if ("location" in obj && typeof obj.location === "string" && "isES6" in obj && typeof obj.isES6 === "boolean") {
|
||||
return new TestFileInfo(obj.location, obj.isES6);
|
||||
} else {
|
||||
throw new Error(
|
||||
`Cannot be converted to a TestFileInfo: ${JSON.stringify(obj)}`
|
||||
);
|
||||
throw new Error(`Cannot be converted to a TestFileInfo: ${JSON.stringify(obj)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -113,19 +106,13 @@ class DoneMessage {
|
||||
// eslint-disable-next-line flowtype/no-weak-types
|
||||
static fromObject(obj: Object): DoneMessage {
|
||||
if (!("type" in obj && typeof obj.type === "string" && obj.type === DoneMessage.sentinel)) {
|
||||
throw new Error(
|
||||
`Cannot be converted to a DoneMessage: ${JSON.stringify(obj)}`
|
||||
);
|
||||
throw new Error(`Cannot be converted to a DoneMessage: ${JSON.stringify(obj)}`);
|
||||
}
|
||||
if (!("test" in obj && typeof obj.test === "object")) {
|
||||
throw new Error("A DoneMessage must have a test");
|
||||
}
|
||||
let msg = new DoneMessage(obj.test);
|
||||
if (
|
||||
"testResults" in obj &&
|
||||
typeof obj.testResults === "object" &&
|
||||
Array.isArray(obj.testResults)
|
||||
) {
|
||||
if ("testResults" in obj && typeof obj.testResults === "object" && Array.isArray(obj.testResults)) {
|
||||
msg.testResults = obj.testResults;
|
||||
}
|
||||
return msg;
|
||||
@ -145,14 +132,10 @@ class ErrorMessage {
|
||||
// eslint-disable-next-line flowtype/no-weak-types
|
||||
static fromObject(obj: Object): ErrorMessage {
|
||||
if (!("type" in obj && typeof obj.type === "string" && obj.type === ErrorMessage.sentinel)) {
|
||||
throw new Error(
|
||||
`Cannot be converted to an ErrorMessage: ${JSON.stringify(obj)}`
|
||||
);
|
||||
throw new Error(`Cannot be converted to an ErrorMessage: ${JSON.stringify(obj)}`);
|
||||
}
|
||||
if (!("err" in obj && typeof obj.err === "object")) {
|
||||
throw new Error(
|
||||
`Cannot be converted to an ErrorMessage: ${JSON.stringify(obj)}`
|
||||
);
|
||||
throw new Error(`Cannot be converted to an ErrorMessage: ${JSON.stringify(obj)}`);
|
||||
}
|
||||
return new ErrorMessage(obj.err);
|
||||
}
|
||||
@ -166,11 +149,7 @@ class TestResult {
|
||||
strict: boolean;
|
||||
err: ?Error;
|
||||
|
||||
constructor(
|
||||
passed: boolean,
|
||||
strict: boolean,
|
||||
err: ?Error = null,
|
||||
) {
|
||||
constructor(passed: boolean, strict: boolean, err: ?Error = null) {
|
||||
this.passed = passed;
|
||||
this.strict = strict;
|
||||
this.err = err;
|
||||
@ -261,7 +240,7 @@ class MasterProgramArgs {
|
||||
cpuScale: number,
|
||||
statusFile: string,
|
||||
filterString: string,
|
||||
singleThreaded: boolean,
|
||||
singleThreaded: boolean
|
||||
) {
|
||||
this.verbose = verbose;
|
||||
this.timeout = timeout;
|
||||
@ -291,18 +270,19 @@ class ArgsParseError {
|
||||
}
|
||||
}
|
||||
|
||||
if (!('toJSON' in Error.prototype)) {
|
||||
if (!("toJSON" in Error.prototype)) {
|
||||
// $FlowFixMe this needs to become defined for Error to be serialized
|
||||
Object.defineProperty(Error.prototype, 'toJSON', { // eslint-disable-line
|
||||
value: function () {
|
||||
Object.defineProperty(Error.prototype, "toJSON", {
|
||||
// eslint-disable-line
|
||||
value: function() {
|
||||
let alt = {};
|
||||
Object.getOwnPropertyNames(this).forEach(function (key) {
|
||||
Object.getOwnPropertyNames(this).forEach(function(key) {
|
||||
alt[key] = this[key];
|
||||
}, this);
|
||||
return alt;
|
||||
},
|
||||
configurable: true,
|
||||
writable: true
|
||||
writable: true,
|
||||
});
|
||||
}
|
||||
|
||||
@ -311,8 +291,8 @@ main();
|
||||
function main(): number {
|
||||
try {
|
||||
if (cluster.isMaster) {
|
||||
let args = masterArgsParse();
|
||||
masterRun(args);
|
||||
let args = masterArgsParse();
|
||||
masterRun(args);
|
||||
} else if (cluster.isWorker) {
|
||||
let args = workerArgsParse();
|
||||
workerRun(args);
|
||||
@ -331,28 +311,27 @@ function main(): number {
|
||||
}
|
||||
|
||||
function usage(): string {
|
||||
return `Usage: ${process.argv[0]} ${process.argv[1]} ` + EOL +
|
||||
`[--verbose] [--timeout <number>] [--bailAfter <number>] ` + EOL +
|
||||
`[--cpuScale <number>] [--statusFile <string>] [--singleThreaded]`;
|
||||
return (
|
||||
`Usage: ${process.argv[0]} ${process.argv[1]} ` +
|
||||
EOL +
|
||||
`[--verbose] [--timeout <number>] [--bailAfter <number>] ` +
|
||||
EOL +
|
||||
`[--cpuScale <number>] [--statusFile <string>] [--singleThreaded]`
|
||||
);
|
||||
}
|
||||
|
||||
function masterArgsParse(): MasterProgramArgs {
|
||||
let parsedArgs = minimist(process.argv.slice(2), {
|
||||
string: [
|
||||
"statusFile"
|
||||
],
|
||||
boolean: [
|
||||
"verbose",
|
||||
"singleThreaded"
|
||||
],
|
||||
string: ["statusFile"],
|
||||
boolean: ["verbose", "singleThreaded"],
|
||||
default: {
|
||||
verbose: (process.stdout instanceof tty.WriteStream) ? false : true,
|
||||
verbose: process.stdout instanceof tty.WriteStream ? false : true,
|
||||
statusFile: "",
|
||||
timeout: 10,
|
||||
cpuScale: 1,
|
||||
bailAfter: Infinity,
|
||||
singleThreaded: false
|
||||
}
|
||||
singleThreaded: false,
|
||||
},
|
||||
});
|
||||
let filterString = parsedArgs._[0];
|
||||
if (typeof parsedArgs.verbose !== "boolean") {
|
||||
@ -380,7 +359,7 @@ function masterArgsParse(): MasterProgramArgs {
|
||||
parsedArgs.cpuScale,
|
||||
parsedArgs.statusFile,
|
||||
filterString,
|
||||
parsedArgs.singleThreaded,
|
||||
parsedArgs.singleThreaded
|
||||
);
|
||||
if (programArgs.filterString) {
|
||||
// if filterstring is provided, assume that verbosity is desired
|
||||
@ -393,7 +372,7 @@ function workerArgsParse(): WorkerProgramArgs {
|
||||
let parsedArgs = minimist(process.argv.slice(2), {
|
||||
default: {
|
||||
timeout: 10,
|
||||
}
|
||||
},
|
||||
});
|
||||
if (typeof parsedArgs.timeout !== "number") {
|
||||
throw new ArgsParseError("timeout must be a number (in seconds) (--timeout 10)");
|
||||
@ -405,7 +384,7 @@ function masterRun(args: MasterProgramArgs) {
|
||||
let tests = getFilesSync(`${__dirname}/../test/test262/test`);
|
||||
// remove tests that don't need to be ran
|
||||
const originalTestLength = tests.length;
|
||||
tests = tests.filter((test) => {
|
||||
tests = tests.filter(test => {
|
||||
return testFilterByMetadata(test, args.filterString);
|
||||
});
|
||||
let groups: GroupsMap = {};
|
||||
@ -423,7 +402,7 @@ function masterRunSingleProcess(
|
||||
args: MasterProgramArgs,
|
||||
groups: GroupsMap,
|
||||
tests: TestFileInfo[],
|
||||
numFiltered: number,
|
||||
numFiltered: number
|
||||
): void {
|
||||
console.log("Running the tests as a single process");
|
||||
// print out every 5 percent (more granularity than multi-process because multi-process
|
||||
@ -462,7 +441,7 @@ function masterRunMultiProcess(
|
||||
args: MasterProgramArgs,
|
||||
groups: GroupsMap,
|
||||
tests: TestFileInfo[],
|
||||
numFiltered: number,
|
||||
numFiltered: number
|
||||
): void {
|
||||
if (!cluster.on) {
|
||||
// stop flow errors on "cluster.on"
|
||||
@ -478,14 +457,14 @@ function masterRunMultiProcess(
|
||||
}
|
||||
|
||||
let exitCount = 0;
|
||||
cluster.on('exit', (worker, code, signal) => {
|
||||
cluster.on("exit", (worker, code, signal) => {
|
||||
exitCount++;
|
||||
if (exitCount === numWorkers) {
|
||||
process.exit(handleFinished(args, groups, numFiltered));
|
||||
}
|
||||
});
|
||||
|
||||
const giveTask = (worker) => {
|
||||
const giveTask = worker => {
|
||||
// grab another test to run and give it to the child process
|
||||
if (tests.length === 0) {
|
||||
worker.send(new QuitMessage());
|
||||
@ -494,7 +473,7 @@ function masterRunMultiProcess(
|
||||
}
|
||||
};
|
||||
|
||||
cluster.on('message', (worker, message, handle) => {
|
||||
cluster.on("message", (worker, message, handle) => {
|
||||
switch (message.type) {
|
||||
case ErrorMessage.sentinel:
|
||||
let errMsg = ErrorMessage.fromObject(message);
|
||||
@ -521,22 +500,16 @@ function masterRunMultiProcess(
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Error(
|
||||
`Master got an unexpected message: ${JSON.stringify(message)}`
|
||||
);
|
||||
throw new Error(`Master got an unexpected message: ${JSON.stringify(message)}`);
|
||||
}
|
||||
});
|
||||
|
||||
cluster.on('online', (worker) => {
|
||||
cluster.on("online", worker => {
|
||||
giveTask(worker);
|
||||
});
|
||||
}
|
||||
|
||||
function handleFinished(
|
||||
args: MasterProgramArgs,
|
||||
groups: GroupsMap,
|
||||
earlierNumSkipped: number,
|
||||
): number {
|
||||
function handleFinished(args: MasterProgramArgs, groups: GroupsMap, earlierNumSkipped: number): number {
|
||||
let numPassedES5 = 0;
|
||||
let numPassedES6 = 0;
|
||||
let numFailedES5 = 0;
|
||||
@ -566,13 +539,8 @@ function handleFinished(
|
||||
}
|
||||
} else {
|
||||
if (args.verbose) {
|
||||
errmsg += create_test_message(
|
||||
testName,
|
||||
testResult.passed,
|
||||
testResult.err,
|
||||
t.test.isES6,
|
||||
testResult.strict
|
||||
) + EOL;
|
||||
errmsg +=
|
||||
create_test_message(testName, testResult.passed, testResult.err, t.test.isES6, testResult.strict) + EOL;
|
||||
}
|
||||
if (testResult.err && testResult.err.message === "Timed out") {
|
||||
numTimeouts++;
|
||||
@ -587,7 +555,8 @@ function handleFinished(
|
||||
msg +=
|
||||
`Passed: ${group_es5_passed} / ${group_es5_passed + group_es5_failed} ` +
|
||||
`(${toPercentage(group_es5_passed, group_es5_passed + group_es5_failed)}%) ` +
|
||||
chalk.yellow("(es6)") + `: ${group_es6_passed} / ` +
|
||||
chalk.yellow("(es6)") +
|
||||
`: ${group_es6_passed} / ` +
|
||||
`${group_es6_passed + group_es6_failed} ` +
|
||||
`(${toPercentage(group_es6_passed, group_es6_passed + group_es6_failed)}%)`;
|
||||
if (args.verbose) {
|
||||
@ -604,13 +573,18 @@ function handleFinished(
|
||||
numFailedES6 += group_es6_failed;
|
||||
}
|
||||
let status =
|
||||
`=== RESULTS ===` + EOL +
|
||||
`=== RESULTS ===` +
|
||||
EOL +
|
||||
`Passes: ${numPassedES5} / ${numPassedES5 + numFailedES5} ` +
|
||||
`(${toPercentage(numPassedES5, numPassedES5 + numFailedES5)}%)` + EOL +
|
||||
`(${toPercentage(numPassedES5, numPassedES5 + numFailedES5)}%)` +
|
||||
EOL +
|
||||
`ES6 passes: ${numPassedES6} / ${numPassedES6 + numFailedES6} ` +
|
||||
`(${toPercentage(numPassedES6, numPassedES6 + numFailedES6)}%)` + EOL +
|
||||
`Skipped: ${numSkipped}` + EOL +
|
||||
`Timeouts: ${numTimeouts}` + EOL;
|
||||
`(${toPercentage(numPassedES6, numPassedES6 + numFailedES6)}%)` +
|
||||
EOL +
|
||||
`Skipped: ${numSkipped}` +
|
||||
EOL +
|
||||
`Timeouts: ${numTimeouts}` +
|
||||
EOL;
|
||||
console.log(status);
|
||||
if (failed_groups.length !== 0) {
|
||||
console.log("Groups with failures:");
|
||||
@ -632,11 +606,7 @@ function handleFinished(
|
||||
}
|
||||
}
|
||||
|
||||
function getProgressBar(
|
||||
currentTestLength: number,
|
||||
originalTestLength: number,
|
||||
granularity: number
|
||||
): string {
|
||||
function getProgressBar(currentTestLength: number, originalTestLength: number, granularity: number): string {
|
||||
if (currentTestLength % granularity === 0 && currentTestLength !== 0) {
|
||||
// print out a percent of tests completed to keep the user informed
|
||||
return `Running... ${toPercentage(originalTestLength - currentTestLength, originalTestLength)}%`;
|
||||
@ -668,16 +638,10 @@ function toPercentage(x: number, total: number): number {
|
||||
if (total === 0) {
|
||||
return 100;
|
||||
}
|
||||
return Math.floor((x / total) * 100);
|
||||
return Math.floor(x / total * 100);
|
||||
}
|
||||
|
||||
function create_test_message(
|
||||
name: string,
|
||||
success: boolean,
|
||||
err: ?Error,
|
||||
isES6: boolean,
|
||||
isStrict: boolean
|
||||
): string {
|
||||
function create_test_message(name: string, success: boolean, err: ?Error, isES6: boolean, isStrict: boolean): string {
|
||||
const checkmark = chalk.green("\u2713");
|
||||
const xmark = chalk.red("\u2717");
|
||||
let msg = "\t";
|
||||
@ -706,9 +670,7 @@ function getHarnesses(): HarnessMap {
|
||||
for (let harness of harnessesList) {
|
||||
// sync is fine, it's an initialization stage and there's not that many
|
||||
// harnesses
|
||||
harnesses[path.basename(harness.location)] = fs.readFileSync(
|
||||
harness.location
|
||||
).toString();
|
||||
harnesses[path.basename(harness.location)] = fs.readFileSync(harness.location).toString();
|
||||
}
|
||||
return harnesses;
|
||||
}
|
||||
@ -721,7 +683,7 @@ function workerRun(args: WorkerProgramArgs) {
|
||||
// get all the harnesses
|
||||
let harnesses = getHarnesses();
|
||||
// we're a worker, run a portion of the tests
|
||||
process.on('message', (message) => {
|
||||
process.on("message", message => {
|
||||
switch (message.type) {
|
||||
case TestTask.sentinel:
|
||||
// begin executing this TestTask
|
||||
@ -742,11 +704,7 @@ function workerRun(args: WorkerProgramArgs) {
|
||||
});
|
||||
}
|
||||
|
||||
function handleTestResultsMultiProcess(
|
||||
err: ?Error,
|
||||
test: TestFileInfo,
|
||||
testResults: TestResult[]
|
||||
): void {
|
||||
function handleTestResultsMultiProcess(err: ?Error, test: TestFileInfo, testResults: TestResult[]): void {
|
||||
if (err) {
|
||||
// $FlowFixMe flow says "process.send" could be undefined
|
||||
process.send(new ErrorMessage(err));
|
||||
@ -791,8 +749,13 @@ function handleTest(
|
||||
} else {
|
||||
invariant(testFileContents, "testFileContents should not be null if banners are not None");
|
||||
// filter out by flags, features, and includes
|
||||
let keepThisTest = filterFeatures(banners) && filterFlags(banners) && filterIncludes(banners) &&
|
||||
filterDescription(banners) && filterCircleCI(banners) && filterSneakyGenerators(banners, testFileContents);
|
||||
let keepThisTest =
|
||||
filterFeatures(banners) &&
|
||||
filterFlags(banners) &&
|
||||
filterIncludes(banners) &&
|
||||
filterDescription(banners) &&
|
||||
filterCircleCI(banners) &&
|
||||
filterSneakyGenerators(banners, testFileContents);
|
||||
let testResults = [];
|
||||
if (keepThisTest) {
|
||||
// now run the test
|
||||
@ -849,17 +812,17 @@ function getFiles(
|
||||
* This function synchronously fetches from the filesystem, as such it should
|
||||
* only be used in initialization code that only runs once.
|
||||
*/
|
||||
function getFilesSync(
|
||||
filepath: string,
|
||||
): TestFileInfo[] {
|
||||
function getFilesSync(filepath: string): TestFileInfo[] {
|
||||
let stat = fs.statSync(filepath);
|
||||
if (stat.isFile()) {
|
||||
return [new TestFileInfo(filepath, false)];
|
||||
} else if (stat.isDirectory()) {
|
||||
let subFiles = fs.readdirSync(filepath);
|
||||
return flatten(subFiles.map((f) => {
|
||||
return getFilesSync(path.join(filepath, f));
|
||||
}));
|
||||
return flatten(
|
||||
subFiles.map(f => {
|
||||
return getFilesSync(path.join(filepath, f));
|
||||
})
|
||||
);
|
||||
} else {
|
||||
throw new Error("That type of file is not supported");
|
||||
}
|
||||
@ -919,7 +882,7 @@ function createRealm(timeout: number): { realm: Realm, $: ObjectValue } {
|
||||
// Create the Host-Defined functions.
|
||||
let $ = new ObjectValue(realm);
|
||||
|
||||
$.defineNativeMethod("createRealm", 0, (context) => {
|
||||
$.defineNativeMethod("createRealm", 0, context => {
|
||||
return createRealm(timeout).$;
|
||||
});
|
||||
|
||||
@ -956,7 +919,7 @@ function runTest(
|
||||
// eslint-disable-next-line flowtype/no-weak-types
|
||||
harnesses: Object,
|
||||
strict: boolean,
|
||||
timeout: number,
|
||||
timeout: number
|
||||
): ?TestResult {
|
||||
let { realm } = createRealm(timeout);
|
||||
|
||||
@ -971,26 +934,21 @@ function runTest(
|
||||
}
|
||||
|
||||
let completion = realm.$GlobalEnv.execute(
|
||||
(strict ? "\"use strict\";" + EOL : "") + testFileContents,
|
||||
(strict ? '"use strict";' + EOL : "") + testFileContents,
|
||||
test.location
|
||||
);
|
||||
if (completion instanceof ThrowCompletion) throw completion;
|
||||
if (completion instanceof AbruptCompletion)
|
||||
return new TestResult(false, strict, new Error(
|
||||
"Unexpected abrupt completion"
|
||||
));
|
||||
return new TestResult(false, strict, new Error("Unexpected abrupt completion"));
|
||||
} catch (err) {
|
||||
if (err.message === "Timed out")
|
||||
return new TestResult(false, strict, err);
|
||||
if (err.message === "Timed out") return new TestResult(false, strict, err);
|
||||
if (!data.negative || data.negative !== err.name) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
if (data.negative.type) {
|
||||
throw new Error(
|
||||
"Was supposed to error with type " + data.negative.type + " but passed"
|
||||
);
|
||||
throw new Error("Was supposed to error with type " + data.negative.type + " but passed");
|
||||
}
|
||||
|
||||
// succeeded
|
||||
@ -1005,8 +963,7 @@ function runTest(
|
||||
case "expected single name":
|
||||
return null;
|
||||
default:
|
||||
if (err.value && err.value.$Prototype &&
|
||||
err.value.$Prototype.intrinsicName === "SyntaxError.prototype") {
|
||||
if (err.value && err.value.$Prototype && err.value.$Prototype.intrinsicName === "SyntaxError.prototype") {
|
||||
return null;
|
||||
}
|
||||
break;
|
||||
@ -1015,9 +972,7 @@ function runTest(
|
||||
let stack = err.stack;
|
||||
if (data.negative.type) {
|
||||
let type = data.negative.type;
|
||||
if (err && err instanceof ThrowCompletion &&
|
||||
Get(realm, err.value, "name").value === type
|
||||
) {
|
||||
if (err && err instanceof ThrowCompletion && Get(realm, err.value, "name").value === type) {
|
||||
// Expected an error and got one.
|
||||
return new TestResult(true, strict);
|
||||
} else {
|
||||
@ -1025,9 +980,7 @@ function runTest(
|
||||
if (err && err instanceof ThrowCompletion) {
|
||||
return new TestResult(false, strict, err);
|
||||
} else {
|
||||
return new TestResult(false, strict, new Error(
|
||||
`Expected an error, but got something else: ${err.message}`
|
||||
));
|
||||
return new TestResult(false, strict, new Error(`Expected an error, but got something else: ${err.message}`));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -1068,13 +1021,7 @@ function runTest(
|
||||
stack = _err.stack;
|
||||
}
|
||||
|
||||
return new TestResult(
|
||||
false,
|
||||
strict,
|
||||
new Error(
|
||||
`Got an error, but was not expecting one:${EOL}${stack}`
|
||||
)
|
||||
);
|
||||
return new TestResult(false, strict, new Error(`Got an error, but was not expecting one:${EOL}${stack}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1082,10 +1029,7 @@ function runTest(
|
||||
/**
|
||||
* Returns true if ${test} should be run, false otherwise
|
||||
*/
|
||||
function testFilterByMetadata(
|
||||
test: TestFileInfo,
|
||||
filterString: string,
|
||||
): boolean {
|
||||
function testFilterByMetadata(test: TestFileInfo, filterString: string): boolean {
|
||||
// filter hidden files
|
||||
if (path.basename(test.location)[0] === ".") return false;
|
||||
|
||||
@ -1100,7 +1044,7 @@ function testFilterByMetadata(
|
||||
if (test.location.includes("Simd")) return false;
|
||||
|
||||
// temporarily disable intl402 tests (ES5)
|
||||
if (test.location.includes("intl402") && !test.location.includes('/Date/')) {
|
||||
if (test.location.includes("intl402") && !test.location.includes("/Date/")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1127,7 +1071,8 @@ function testFilterByMetadata(
|
||||
if (test.location.includes("tco")) return false;
|
||||
|
||||
// disable nasty unicode tests.
|
||||
if (test.location.includes("U180") || test.location.includes("u180") || test.location.includes("mongolian")) return false;
|
||||
if (test.location.includes("U180") || test.location.includes("u180") || test.location.includes("mongolian"))
|
||||
return false;
|
||||
|
||||
// disable function toString tests.
|
||||
if (test.location.includes("Function/prototype/toString")) return false;
|
||||
@ -1157,10 +1102,7 @@ function testFilterByMetadata(
|
||||
return true;
|
||||
}
|
||||
|
||||
function testFilterByContents(
|
||||
test: TestFileInfo,
|
||||
testFileContents: string
|
||||
): boolean {
|
||||
function testFilterByContents(test: TestFileInfo, testFileContents: string): boolean {
|
||||
// ES6 tests (can only be verified by contents, not by metadata)
|
||||
let is_es6 = testFileContents.includes(EOL + "es6id: ");
|
||||
test.isES6 = is_es6;
|
||||
@ -1168,15 +1110,15 @@ function testFilterByContents(
|
||||
// Ignore phase: early tests because those are errors that babel should catch
|
||||
// not issues related to Prepack
|
||||
let phase_early = testFileContents.indexOf(" phase: early");
|
||||
let end_of_comment = testFileContents.indexOf("---\*/");
|
||||
let end_of_comment = testFileContents.indexOf("---*/");
|
||||
if (phase_early > 0 && phase_early < end_of_comment) return false;
|
||||
|
||||
let esid_pending = testFileContents.indexOf("esid: pending");
|
||||
if (esid_pending > 0 && esid_pending < end_of_comment) return false;
|
||||
|
||||
// disable tests that require parser to throw SyntaxError in strict Mode
|
||||
if (test.location.includes("/directive-prologue/") &&
|
||||
testFileContents.includes("assert.throws(SyntaxError,")) return false;
|
||||
if (test.location.includes("/directive-prologue/") && testFileContents.includes("assert.throws(SyntaxError,"))
|
||||
return false;
|
||||
|
||||
// disable SharedArrayBuffer tests
|
||||
if (testFileContents.includes("SharedArrayBuffer")) return false;
|
||||
@ -1205,26 +1147,38 @@ function filterDescription(data: BannerData): boolean {
|
||||
// For now, "Complex tests" is used in the description of some
|
||||
// encode/decodeURI tests to indicate that they are long running.
|
||||
// Filter these
|
||||
return !data.description.includes("Complex tests") &&
|
||||
return (
|
||||
!data.description.includes("Complex tests") &&
|
||||
!data.description.includes("iterating") &&
|
||||
!data.description.includes("iterable");
|
||||
!data.description.includes("iterable")
|
||||
);
|
||||
}
|
||||
|
||||
function filterCircleCI(data: BannerData): boolean {
|
||||
let skipTests = ['7.8.5_A1.4_T2', '7.8.5_A2.4_T2', '7.8.5_A2.1_T2', '7.8.5_A1.1_T2',
|
||||
'15.1.2.2_A8', '15.1.2.3_A6', '7.4_A5', '7.4_A6',
|
||||
'15.10.2.12_A3_T1', '15.10.2.12_A4_T1', '15.10.2.12_A5_T1', '15.10.2.12_A6_T1'];
|
||||
let skipTests6 = ['22.1.3.1_3'];
|
||||
let skipTests = [
|
||||
"7.8.5_A1.4_T2",
|
||||
"7.8.5_A2.4_T2",
|
||||
"7.8.5_A2.1_T2",
|
||||
"7.8.5_A1.1_T2",
|
||||
"15.1.2.2_A8",
|
||||
"15.1.2.3_A6",
|
||||
"7.4_A5",
|
||||
"7.4_A6",
|
||||
"15.10.2.12_A3_T1",
|
||||
"15.10.2.12_A4_T1",
|
||||
"15.10.2.12_A5_T1",
|
||||
"15.10.2.12_A6_T1",
|
||||
];
|
||||
let skipTests6 = ["22.1.3.1_3"];
|
||||
|
||||
return (!!process.env.NIGHTLY_BUILD ||
|
||||
(skipTests.indexOf(data.es5id) < 0 && skipTests6.indexOf(data.es6id) < 0));
|
||||
return !!process.env.NIGHTLY_BUILD || (skipTests.indexOf(data.es5id) < 0 && skipTests6.indexOf(data.es6id) < 0);
|
||||
}
|
||||
|
||||
function filterSneakyGenerators(data: BannerData, testFileContents: string) {
|
||||
// There are some sneaky tests that use generators but are not labeled with
|
||||
// the "generators" or "generator" feature tag. Here we use a simple heuristic
|
||||
// to filter out tests with sneaky generators.
|
||||
if (data.features.includes('destructuring-binding')) {
|
||||
if (data.features.includes("destructuring-binding")) {
|
||||
return !testFileContents.includes("function*") && !testFileContents.includes("*method");
|
||||
}
|
||||
return true;
|
||||
@ -1241,30 +1195,17 @@ function runTestWithStrictness(
|
||||
data: BannerData,
|
||||
// eslint-disable-next-line flowtype/no-weak-types
|
||||
harnesses: Object,
|
||||
timeout: number,
|
||||
timeout: number
|
||||
): Array<TestResult> {
|
||||
let fn = (strict: boolean) => {
|
||||
return runTest(
|
||||
test,
|
||||
testFileContents,
|
||||
data,
|
||||
harnesses,
|
||||
strict,
|
||||
timeout,
|
||||
);
|
||||
return runTest(test, testFileContents, data, harnesses, strict, timeout);
|
||||
};
|
||||
if (data.flags.includes("onlyStrict")) {
|
||||
if (testFileContents.includes("assert.throws(SyntaxError"))
|
||||
return [];
|
||||
if (testFileContents.includes("assert.throws(SyntaxError")) return [];
|
||||
let result = fn(true);
|
||||
return result ? [result] : [];
|
||||
} else if (
|
||||
data.flags.includes("noStrict") ||
|
||||
test.location.includes("global/global-object.js")
|
||||
) {
|
||||
if (testFileContents.includes("\"use strict\";") &&
|
||||
testFileContents.includes("assert.throws(SyntaxError"))
|
||||
return [];
|
||||
} else if (data.flags.includes("noStrict") || test.location.includes("global/global-object.js")) {
|
||||
if (testFileContents.includes('"use strict";') && testFileContents.includes("assert.throws(SyntaxError")) return [];
|
||||
let result = fn(false);
|
||||
return result ? [result] : [];
|
||||
} else {
|
||||
@ -1278,7 +1219,7 @@ function runTestWithStrictness(
|
||||
if (unStrictResult) {
|
||||
finalResult.push(unStrictResult);
|
||||
}
|
||||
return finalResult;
|
||||
return finalResult;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1286,18 +1227,15 @@ function runTestWithStrictness(
|
||||
* Parses the banners, and returns the banners as arbitrary object data if they
|
||||
* were found, or returns an error if the banner it couldn't be parsed.
|
||||
*/
|
||||
function getBanners(
|
||||
test: TestFileInfo,
|
||||
fileContents: string
|
||||
): ?BannerData {
|
||||
function getBanners(test: TestFileInfo, fileContents: string): ?BannerData {
|
||||
let banners = fileContents.match(/---[\s\S]+---/);
|
||||
let data = {};
|
||||
if (banners) {
|
||||
let bannerText = banners[0] || "";
|
||||
if (bannerText.includes("StrictMode")) {
|
||||
if (bannerText.includes("\'arguments\'")) return null;
|
||||
if (bannerText.includes("\'caller\'")) return null;
|
||||
} else if (bannerText.includes("properties \"caller\" or \"arguments\"")) {
|
||||
if (bannerText.includes("'arguments'")) return null;
|
||||
if (bannerText.includes("'caller'")) return null;
|
||||
} else if (bannerText.includes('properties "caller" or "arguments"')) {
|
||||
return null;
|
||||
} else if (bannerText.includes("function caller")) {
|
||||
return null;
|
||||
@ -1305,8 +1243,7 @@ function getBanners(
|
||||
return null;
|
||||
} else if (bannerText.includes("attribute of 'arguments'")) {
|
||||
return null;
|
||||
} else if (bannerText.includes("poisoned"))
|
||||
return null;
|
||||
} else if (bannerText.includes("poisoned")) return null;
|
||||
data = yaml.safeLoad(banners[0].slice(3, -3));
|
||||
}
|
||||
return BannerData.fromObject(data);
|
||||
|
@ -15,15 +15,15 @@ import construct_realm from "./construct_realm.js";
|
||||
import initializeGlobals from "./globals.js";
|
||||
import invariant from "./invariant.js";
|
||||
|
||||
let chalk = require("chalk");
|
||||
let jsdom = require("jsdom");
|
||||
let zlib = require("zlib");
|
||||
let fs = require("fs");
|
||||
let vm = require("vm");
|
||||
let chalk = require("chalk");
|
||||
let jsdom = require("jsdom");
|
||||
let zlib = require("zlib");
|
||||
let fs = require("fs");
|
||||
let vm = require("vm");
|
||||
|
||||
function getTime() {
|
||||
let stamp = process.hrtime();
|
||||
return ((stamp[0] * 1e9) + stamp[1]) / 1e6;
|
||||
return (stamp[0] * 1e9 + stamp[1]) / 1e6;
|
||||
}
|
||||
|
||||
function exec(code: string, compatibility: Compatibility) {
|
||||
@ -34,7 +34,7 @@ function exec(code: string, compatibility: Compatibility) {
|
||||
error() {},
|
||||
log(s) {
|
||||
console.log(s);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -52,7 +52,8 @@ Object.getOwnPropertyNames(global).forEach(function(name){ if (name !== "Object"
|
||||
sandbox.location = window.location;
|
||||
}
|
||||
if (compatibility === "jsc-600-1-4-17") {
|
||||
beforeCode += "delete global.clearInterval; delete global.clearImmediate; delete global.clearTimeout; delete global.setImmediate; delete Object.assign;";
|
||||
beforeCode +=
|
||||
"delete global.clearInterval; delete global.clearImmediate; delete global.clearTimeout; delete global.setImmediate; delete Object.assign;";
|
||||
}
|
||||
|
||||
code = `${beforeCode} ${code}; // keep newline here as code may end with comment
|
||||
@ -69,7 +70,7 @@ ${afterCode}`;
|
||||
gzip: zlib.gzipSync(code).length,
|
||||
executed: executedEnd - executedStart,
|
||||
compiled: executedStart - start,
|
||||
total: executedEnd - start
|
||||
total: executedEnd - start,
|
||||
};
|
||||
}
|
||||
|
||||
@ -77,18 +78,23 @@ function line(type, code, compatibility: Compatibility, moreOut = {}, compareSta
|
||||
let stats = exec(code, compatibility);
|
||||
|
||||
function wrapTime(key) {
|
||||
return wrap(key, (ms) => `${ms.toFixed(2)}ms`, "faster", "slower");
|
||||
return wrap(key, ms => `${ms.toFixed(2)}ms`, "faster", "slower");
|
||||
}
|
||||
|
||||
function wrapSize(key) {
|
||||
return wrap(key, function (b) {
|
||||
let kilobytes = Math.round(b / 1000);
|
||||
if (kilobytes > 1000) {
|
||||
return `${(kilobytes / 1000).toFixed(2)}MB`;
|
||||
} else {
|
||||
return `${kilobytes}KB`;
|
||||
}
|
||||
}, "smaller", "bigger");
|
||||
return wrap(
|
||||
key,
|
||||
function(b) {
|
||||
let kilobytes = Math.round(b / 1000);
|
||||
if (kilobytes > 1000) {
|
||||
return `${(kilobytes / 1000).toFixed(2)}MB`;
|
||||
} else {
|
||||
return `${kilobytes}KB`;
|
||||
}
|
||||
},
|
||||
"smaller",
|
||||
"bigger"
|
||||
);
|
||||
}
|
||||
|
||||
function wrap(key, format, positive, negative) {
|
||||
@ -115,7 +121,7 @@ function line(type, code, compatibility: Compatibility, moreOut = {}, compareSta
|
||||
"VM Execution Time": wrapTime("executed"),
|
||||
"Raw Code Size": wrapSize("raw"),
|
||||
"Gzip Code Size": wrapSize("gzip"),
|
||||
...moreOut
|
||||
...moreOut,
|
||||
};
|
||||
|
||||
console.log(chalk.bold(type));
|
||||
@ -127,7 +133,13 @@ function line(type, code, compatibility: Compatibility, moreOut = {}, compareSta
|
||||
return stats;
|
||||
}
|
||||
|
||||
function dump(name: string, raw: string, min: string = raw, compatibility?: "browser" | "jsc-600-1-4-17" = "browser", outputFilename?: string) {
|
||||
function dump(
|
||||
name: string,
|
||||
raw: string,
|
||||
min: string = raw,
|
||||
compatibility?: "browser" | "jsc-600-1-4-17" = "browser",
|
||||
outputFilename?: string
|
||||
) {
|
||||
console.log(chalk.inverse(name));
|
||||
let beforeStats = line("Before", min, compatibility);
|
||||
|
||||
@ -141,18 +153,24 @@ function dump(name: string, raw: string, min: string = raw, compatibility?: "bro
|
||||
process.exit(1);
|
||||
invariant(false);
|
||||
}
|
||||
let code = serialized.code;
|
||||
let code = serialized.code;
|
||||
let total = Date.now() - start;
|
||||
|
||||
if (code.length >= 1000 || outputFilename) {
|
||||
let filename = outputFilename || (name + "-processed.js");
|
||||
let filename = outputFilename || name + "-processed.js";
|
||||
console.log(`Prepacked source code written to ${filename}.`);
|
||||
fs.writeFileSync(filename, code);
|
||||
}
|
||||
|
||||
line("After", code, compatibility, {
|
||||
"Prepack Compile Time": `${total}ms`
|
||||
}, beforeStats);
|
||||
line(
|
||||
"After",
|
||||
code,
|
||||
compatibility,
|
||||
{
|
||||
"Prepack Compile Time": `${total}ms`,
|
||||
},
|
||||
beforeStats
|
||||
);
|
||||
|
||||
if (code.length <= 1000 && !outputFilename) {
|
||||
console.log("+++++++++++++++++ Prepacked source code");
|
||||
@ -167,12 +185,15 @@ let inputFilename;
|
||||
let outputFilename;
|
||||
let compatibility;
|
||||
while (args.length) {
|
||||
let arg = args[0]; args.shift();
|
||||
let arg = args[0];
|
||||
args.shift();
|
||||
if (arg === "--out") {
|
||||
arg = args[0]; args.shift();
|
||||
arg = args[0];
|
||||
args.shift();
|
||||
outputFilename = arg;
|
||||
} else if (arg === "--compatibility") {
|
||||
arg = args[0]; args.shift();
|
||||
arg = args[0];
|
||||
args.shift();
|
||||
if (arg !== "jsc-600-1-4-17") {
|
||||
console.error(`Unsupported compatibility: ${arg}`);
|
||||
process.exit(1);
|
||||
|
@ -15,7 +15,7 @@ import invariant from "./invariant.js";
|
||||
|
||||
export class Completion {
|
||||
constructor(value: Value, target?: ?string) {
|
||||
this.value = value;
|
||||
this.value = value;
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@ -31,8 +31,9 @@ export class NormalCompletion extends Completion {}
|
||||
export class ThrowCompletion extends AbruptCompletion {
|
||||
constructor(value: Value, nativeStack?: ?string) {
|
||||
super(value);
|
||||
invariant(value.getType() !== value.$Realm.intrinsics.__IntrospectionError ||
|
||||
this instanceof IntrospectionThrowCompletion);
|
||||
invariant(
|
||||
value.getType() !== value.$Realm.intrinsics.__IntrospectionError || this instanceof IntrospectionThrowCompletion
|
||||
);
|
||||
this.nativeStack = nativeStack || new Error().stack;
|
||||
}
|
||||
|
||||
@ -47,12 +48,13 @@ export class ReturnCompletion extends AbruptCompletion {}
|
||||
|
||||
export class JoinedAbruptCompletions extends AbruptCompletion {
|
||||
constructor(
|
||||
realm: Realm,
|
||||
joinCondition: AbstractValue,
|
||||
consequent: AbruptCompletion,
|
||||
consequentEffects: Effects,
|
||||
alternate: AbruptCompletion,
|
||||
alternateEffects: Effects) {
|
||||
realm: Realm,
|
||||
joinCondition: AbstractValue,
|
||||
consequent: AbruptCompletion,
|
||||
consequentEffects: Effects,
|
||||
alternate: AbruptCompletion,
|
||||
alternateEffects: Effects
|
||||
) {
|
||||
super(realm.intrinsics.empty, undefined);
|
||||
this.joinCondition = joinCondition;
|
||||
this.consequent = consequent;
|
||||
@ -73,19 +75,30 @@ export class JoinedAbruptCompletions extends AbruptCompletion {
|
||||
// action must be taken to deal with the possibly abrupt case of the completion.
|
||||
export class PossiblyNormalCompletion extends NormalCompletion {
|
||||
constructor(
|
||||
value: Value,
|
||||
joinCondition: AbstractValue,
|
||||
consequent: Completion | Value,
|
||||
consequentEffects: Effects,
|
||||
alternate: Completion | Value,
|
||||
alternateEffects: Effects) {
|
||||
invariant(consequent instanceof NormalCompletion || consequent instanceof Value ||
|
||||
alternate instanceof NormalCompletion || alternate instanceof Value);
|
||||
value: Value,
|
||||
joinCondition: AbstractValue,
|
||||
consequent: Completion | Value,
|
||||
consequentEffects: Effects,
|
||||
alternate: Completion | Value,
|
||||
alternateEffects: Effects
|
||||
) {
|
||||
invariant(
|
||||
consequent instanceof NormalCompletion ||
|
||||
consequent instanceof Value ||
|
||||
alternate instanceof NormalCompletion ||
|
||||
alternate instanceof Value
|
||||
);
|
||||
invariant(consequent instanceof AbruptCompletion || alternate instanceof AbruptCompletion);
|
||||
invariant(value === consequent || consequent instanceof AbruptCompletion ||
|
||||
(consequent instanceof NormalCompletion && value === consequent.value));
|
||||
invariant(value === alternate || alternate instanceof AbruptCompletion ||
|
||||
(alternate instanceof NormalCompletion && value === alternate.value));
|
||||
invariant(
|
||||
value === consequent ||
|
||||
consequent instanceof AbruptCompletion ||
|
||||
(consequent instanceof NormalCompletion && value === consequent.value)
|
||||
);
|
||||
invariant(
|
||||
value === alternate ||
|
||||
alternate instanceof AbruptCompletion ||
|
||||
(alternate instanceof NormalCompletion && value === alternate.value)
|
||||
);
|
||||
super(value);
|
||||
this.joinCondition = joinCondition;
|
||||
this.consequent = consequent;
|
||||
|
@ -28,6 +28,6 @@ export default function(opts: RealmOptions = {}): Realm {
|
||||
initializeGlobal(r);
|
||||
for (let name in evaluators) r.evaluators[name] = evaluators[name];
|
||||
for (let name in partialEvaluators) r.partialEvaluators[name] = partialEvaluators[name];
|
||||
r.$GlobalEnv = NewGlobalEnvironment(r, r.$GlobalObject, r.$GlobalObject);
|
||||
r.$GlobalEnv = NewGlobalEnvironment(r, r.$GlobalObject, r.$GlobalObject);
|
||||
return r;
|
||||
}
|
||||
|
@ -9,7 +9,15 @@
|
||||
|
||||
/* @flow */
|
||||
|
||||
import { AbstractValue, ConcreteValue, FunctionValue, ObjectValue, PrimitiveValue, UndefinedValue, Value } from "../values/index.js";
|
||||
import {
|
||||
AbstractValue,
|
||||
ConcreteValue,
|
||||
FunctionValue,
|
||||
ObjectValue,
|
||||
PrimitiveValue,
|
||||
UndefinedValue,
|
||||
Value,
|
||||
} from "../values/index.js";
|
||||
import invariant from "../invariant.js";
|
||||
|
||||
/* An abstract domain for the type of value a variable might have. */
|
||||
@ -31,29 +39,23 @@ export default class TypesDomain {
|
||||
static joinValues(v1: void | Value, v2: void | Value): TypesDomain {
|
||||
if (v1 === undefined && v2 === undefined) return new TypesDomain(UndefinedValue);
|
||||
if (v1 === undefined || v2 === undefined) return TypesDomain.topVal;
|
||||
if (v1 instanceof AbstractValue)
|
||||
return v1.types.joinWith(v2.getType());
|
||||
if (v2 instanceof AbstractValue)
|
||||
return v2.types.joinWith(v1.getType());
|
||||
return (new TypesDomain(v1.getType())).joinWith(v2.getType());
|
||||
if (v1 instanceof AbstractValue) return v1.types.joinWith(v2.getType());
|
||||
if (v2 instanceof AbstractValue) return v2.types.joinWith(v1.getType());
|
||||
return new TypesDomain(v1.getType()).joinWith(v2.getType());
|
||||
}
|
||||
|
||||
joinWith(t: typeof Value): TypesDomain {
|
||||
joinWith(t: typeof Value): TypesDomain {
|
||||
let type = this.getType();
|
||||
if (type === t) return this;
|
||||
if (Value.isTypeCompatibleWith(type, FunctionValue) &&
|
||||
Value.isTypeCompatibleWith(t, FunctionValue)) {
|
||||
if (Value.isTypeCompatibleWith(type, FunctionValue) && Value.isTypeCompatibleWith(t, FunctionValue)) {
|
||||
return new TypesDomain(FunctionValue);
|
||||
}
|
||||
if (Value.isTypeCompatibleWith(type, ObjectValue) &&
|
||||
Value.isTypeCompatibleWith(t, ObjectValue)) {
|
||||
if (Value.isTypeCompatibleWith(type, ObjectValue) && Value.isTypeCompatibleWith(t, ObjectValue)) {
|
||||
return new TypesDomain(ObjectValue);
|
||||
}
|
||||
if (Value.isTypeCompatibleWith(type, PrimitiveValue) &&
|
||||
Value.isTypeCompatibleWith(t, PrimitiveValue)) {
|
||||
if (Value.isTypeCompatibleWith(type, PrimitiveValue) && Value.isTypeCompatibleWith(t, PrimitiveValue)) {
|
||||
return new TypesDomain(PrimitiveValue);
|
||||
}
|
||||
return TypesDomain.topVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -80,8 +80,10 @@ export default class ValuesDomain {
|
||||
if (v1 instanceof AbstractValue) return v1.values.joinWith(v2);
|
||||
if (v2 instanceof AbstractValue) return v2.values.joinWith(v1);
|
||||
let union = new Set();
|
||||
invariant(v1 instanceof ConcreteValue); union.add(v1);
|
||||
invariant(v2 instanceof ConcreteValue); union.add(v2);
|
||||
invariant(v1 instanceof ConcreteValue);
|
||||
union.add(v1);
|
||||
invariant(v2 instanceof ConcreteValue);
|
||||
union.add(v2);
|
||||
return new ValuesDomain(union);
|
||||
}
|
||||
|
||||
@ -90,7 +92,7 @@ export default class ValuesDomain {
|
||||
let union = new Set(this.getElements());
|
||||
if (y instanceof AbstractValue) {
|
||||
if (y.values.isTop()) return y.values;
|
||||
y.values.getElements().forEach((v) => union.add(v));
|
||||
y.values.getElements().forEach(v => union.add(v));
|
||||
} else {
|
||||
invariant(y instanceof ConcreteValue);
|
||||
union.add(y);
|
||||
@ -115,7 +117,7 @@ export default class ValuesDomain {
|
||||
let elements = this._elements;
|
||||
if (y instanceof AbstractValue) {
|
||||
if (y.values.isTop()) return this;
|
||||
y.values.getElements().forEach((v) => {
|
||||
y.values.getElements().forEach(v => {
|
||||
if (elements === undefined || elements.has(v)) intersection.add(v);
|
||||
});
|
||||
} else {
|
||||
@ -129,10 +131,8 @@ export default class ValuesDomain {
|
||||
if (this.isTop()) return this;
|
||||
let newSet = new Set();
|
||||
for (let cval of this.getElements()) {
|
||||
if (cval instanceof EmptyValue)
|
||||
newSet.add(cval.$Realm.intrinsics.undefined);
|
||||
else
|
||||
newSet.add(cval);
|
||||
if (cval instanceof EmptyValue) newSet.add(cval.$Realm.intrinsics.undefined);
|
||||
else newSet.add(cval);
|
||||
}
|
||||
return new ValuesDomain(newSet);
|
||||
}
|
||||
|
@ -13,11 +13,29 @@ import type { BabelNode, BabelNodeFile, BabelNodeStatement } from "babel-types";
|
||||
import type { Realm } from "./realm.js";
|
||||
import type { SourceFile, SourceMap, SourceType } from "./types.js";
|
||||
|
||||
import { AbruptCompletion, Completion, JoinedAbruptCompletions, NormalCompletion, PossiblyNormalCompletion, ThrowCompletion } from "./completions.js";
|
||||
import {
|
||||
AbruptCompletion,
|
||||
Completion,
|
||||
JoinedAbruptCompletions,
|
||||
NormalCompletion,
|
||||
PossiblyNormalCompletion,
|
||||
ThrowCompletion,
|
||||
} from "./completions.js";
|
||||
import { defaultOptions, type Options } from "./options";
|
||||
import { ExecutionContext } from "./realm.js";
|
||||
import { Value } from "./values/index.js";
|
||||
import { AbstractValue, NullValue, SymbolValue, BooleanValue, FunctionValue, NumberValue, ObjectValue, AbstractObjectValue, StringValue, UndefinedValue } from "./values/index.js";
|
||||
import {
|
||||
AbstractValue,
|
||||
NullValue,
|
||||
SymbolValue,
|
||||
BooleanValue,
|
||||
FunctionValue,
|
||||
NumberValue,
|
||||
ObjectValue,
|
||||
AbstractObjectValue,
|
||||
StringValue,
|
||||
UndefinedValue,
|
||||
} from "./values/index.js";
|
||||
import generate from "babel-generator";
|
||||
import parse from "./utils/parse.js";
|
||||
import invariant from "./invariant.js";
|
||||
@ -36,7 +54,7 @@ import {
|
||||
} from "./methods/index.js";
|
||||
import * as t from "babel-types";
|
||||
|
||||
const sourceMap = require('source-map');
|
||||
const sourceMap = require("source-map");
|
||||
|
||||
// ECMA262 8.1.1
|
||||
export class EnvironmentRecord {
|
||||
@ -61,15 +79,17 @@ export class EnvironmentRecord {
|
||||
+GetThisBinding: () => NullValue | ObjectValue | AbstractObjectValue | UndefinedValue;
|
||||
+HasSuperBinding: () => boolean;
|
||||
+WithBaseObject: () => Value;
|
||||
+BindThisValue: (V: NullValue | ObjectValue | AbstractObjectValue | UndefinedValue) => NullValue | ObjectValue | AbstractObjectValue | UndefinedValue;
|
||||
+BindThisValue: (
|
||||
V: NullValue | ObjectValue | AbstractObjectValue | UndefinedValue
|
||||
) => NullValue | ObjectValue | AbstractObjectValue | UndefinedValue;
|
||||
}
|
||||
|
||||
export type Binding = {
|
||||
value?: Value;
|
||||
initialized?: boolean;
|
||||
mutable?: boolean;
|
||||
deletable?: boolean;
|
||||
}
|
||||
value?: Value,
|
||||
initialized?: boolean,
|
||||
mutable?: boolean,
|
||||
deletable?: boolean,
|
||||
};
|
||||
|
||||
// ECMA262 8.1.1.1
|
||||
export class DeclarativeEnvironmentRecord extends EnvironmentRecord {
|
||||
@ -103,11 +123,14 @@ export class DeclarativeEnvironmentRecord extends EnvironmentRecord {
|
||||
invariant(!envRec.bindings[N], `shouldn't have the binding ${N}`);
|
||||
|
||||
// 3. Create a mutable binding in envRec for N and record that it is uninitialized. If D is true, record that the newly created binding may be deleted by a subsequent DeleteBinding call.
|
||||
this.bindings[N] = realm.recordModifiedBinding({
|
||||
initialized: false,
|
||||
mutable: true,
|
||||
deletable: D
|
||||
}, envRec);
|
||||
this.bindings[N] = realm.recordModifiedBinding(
|
||||
{
|
||||
initialized: false,
|
||||
mutable: true,
|
||||
deletable: D,
|
||||
},
|
||||
envRec
|
||||
);
|
||||
|
||||
// 4. Return NormalCompletion(empty).
|
||||
return realm.intrinsics.undefined;
|
||||
@ -124,11 +147,14 @@ export class DeclarativeEnvironmentRecord extends EnvironmentRecord {
|
||||
invariant(!envRec.bindings[N], `shouldn't have the binding ${N}`);
|
||||
|
||||
// 3. Create an immutable binding in envRec for N and record that it is uninitialized. If S is true, record that the newly created binding is a strict binding.
|
||||
this.bindings[N] = realm.recordModifiedBinding({
|
||||
initialized: false,
|
||||
strict: S,
|
||||
deletable: false
|
||||
}, envRec);
|
||||
this.bindings[N] = realm.recordModifiedBinding(
|
||||
{
|
||||
initialized: false,
|
||||
strict: S,
|
||||
deletable: false,
|
||||
},
|
||||
envRec
|
||||
);
|
||||
|
||||
// 4. Return NormalCompletion(empty).
|
||||
return realm.intrinsics.undefined;
|
||||
@ -186,9 +212,11 @@ export class DeclarativeEnvironmentRecord extends EnvironmentRecord {
|
||||
// 4. If the binding for N in envRec has not yet been initialized, throw a ReferenceError exception.
|
||||
if (!binding.initialized) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.ReferenceError, `${N} has not yet been initialized`);
|
||||
} else if (binding.mutable) { // 5. Else if the binding for N in envRec is a mutable binding, change its bound value to V.
|
||||
realm.recordModifiedBinding(binding, envRec).value = V;
|
||||
} else { // 6. Else,
|
||||
} else if (binding.mutable) {
|
||||
// 5. Else if the binding for N in envRec is a mutable binding, change its bound value to V.
|
||||
realm.recordModifiedBinding(binding, envRec).value = V;
|
||||
} else {
|
||||
// 6. Else,
|
||||
// a. Assert: This is an attempt to change the value of an immutable binding.
|
||||
|
||||
// b. If S is true, throw a TypeError exception.
|
||||
@ -320,12 +348,15 @@ export class ObjectEnvironmentRecord extends EnvironmentRecord {
|
||||
let configValue = D ? true : false;
|
||||
|
||||
// 4. Return ? DefinePropertyOrThrow(bindings, N, PropertyDescriptor{[[Value]]: undefined, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: configValue}).
|
||||
return new BooleanValue(realm, DefinePropertyOrThrow(realm, bindings, N, {
|
||||
value: realm.intrinsics.undefined,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: configValue
|
||||
}));
|
||||
return new BooleanValue(
|
||||
realm,
|
||||
DefinePropertyOrThrow(realm, bindings, N, {
|
||||
value: realm.intrinsics.undefined,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: configValue,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// ECMA262 8.1.1.2.3
|
||||
@ -432,7 +463,9 @@ export class FunctionEnvironmentRecord extends DeclarativeEnvironmentRecord {
|
||||
$FunctionObject: FunctionValue;
|
||||
|
||||
// ECMA262 8.1.1.3.1
|
||||
BindThisValue(V: NullValue | ObjectValue | AbstractObjectValue | UndefinedValue): NullValue | ObjectValue | AbstractObjectValue | UndefinedValue {
|
||||
BindThisValue(
|
||||
V: NullValue | ObjectValue | AbstractObjectValue | UndefinedValue
|
||||
): NullValue | ObjectValue | AbstractObjectValue | UndefinedValue {
|
||||
let realm = this.realm;
|
||||
|
||||
// 1. Let envRec be the function Environment Record for which the method was invoked.
|
||||
@ -890,7 +923,8 @@ export class GlobalEnvironmentRecord extends EnvironmentRecord {
|
||||
if (!existingProp || existingProp.configurable) {
|
||||
// a. Let desc be the PropertyDescriptor{[[Value]]: V, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: D}.
|
||||
desc = { value: V, writable: true, enumerable: true, configurable: D };
|
||||
} else { // 6. Else,
|
||||
} else {
|
||||
// 6. Else,
|
||||
ThrowIfMightHaveBeenDeleted(existingProp.value);
|
||||
// a. Let desc be the PropertyDescriptor{[[Value]]: V }.
|
||||
desc = { value: V };
|
||||
@ -920,7 +954,9 @@ export class GlobalEnvironmentRecord extends EnvironmentRecord {
|
||||
// ECMA262 8.1.1.5
|
||||
export class ModuleEnvironmentRecord extends DeclarativeEnvironmentRecord {
|
||||
// ECMA262 8.1.1.3.1
|
||||
BindThisValue(V: NullValue | ObjectValue | AbstractObjectValue | UndefinedValue): NullValue | ObjectValue | AbstractObjectValue | UndefinedValue {
|
||||
BindThisValue(
|
||||
V: NullValue | ObjectValue | AbstractObjectValue | UndefinedValue
|
||||
): NullValue | ObjectValue | AbstractObjectValue | UndefinedValue {
|
||||
throw new Error("TODO: implement modules");
|
||||
}
|
||||
|
||||
@ -940,7 +976,7 @@ export class ModuleEnvironmentRecord extends DeclarativeEnvironmentRecord {
|
||||
}
|
||||
|
||||
// ECMA262 8.1.1.3.5
|
||||
GetSuperBase(): NullValue | ObjectValue | UndefinedValue {
|
||||
GetSuperBase(): NullValue | ObjectValue | UndefinedValue {
|
||||
throw new Error("TODO: implement modules");
|
||||
}
|
||||
}
|
||||
@ -957,7 +993,9 @@ export class LexicalEnvironment {
|
||||
realm: Realm;
|
||||
|
||||
partiallyEvaluateCompletionDeref(
|
||||
ast: BabelNode, strictCode: boolean, metadata?: any
|
||||
ast: BabelNode,
|
||||
strictCode: boolean,
|
||||
metadata?: any
|
||||
): [Completion | Value, BabelNode, Array<BabelNodeStatement>] {
|
||||
let [result, partial_ast, partial_io] = this.partiallyEvaluateCompletion(ast, strictCode, metadata);
|
||||
if (result instanceof Reference) {
|
||||
@ -967,13 +1005,14 @@ export class LexicalEnvironment {
|
||||
}
|
||||
|
||||
partiallyEvaluateCompletion(
|
||||
ast: BabelNode, strictCode: boolean, metadata?: any
|
||||
ast: BabelNode,
|
||||
strictCode: boolean,
|
||||
metadata?: any
|
||||
): [Completion | Reference | Value, BabelNode, Array<BabelNodeStatement>] {
|
||||
try {
|
||||
return this.partiallyEvaluate(ast, strictCode, metadata);
|
||||
} catch (err) {
|
||||
if (err instanceof Completion)
|
||||
return [err, ast, []];
|
||||
if (err instanceof Completion) return [err, ast, []];
|
||||
if (err instanceof Error)
|
||||
// rethrowing Error should preserve stack trace
|
||||
throw err;
|
||||
@ -984,8 +1023,7 @@ export class LexicalEnvironment {
|
||||
|
||||
evaluateCompletionDeref(ast: BabelNode, strictCode: boolean, metadata?: any): AbruptCompletion | Value {
|
||||
let result = this.evaluateCompletion(ast, strictCode, metadata);
|
||||
if (result instanceof Reference)
|
||||
result = GetValue(this.realm, result);
|
||||
if (result instanceof Reference) result = GetValue(this.realm, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -995,8 +1033,7 @@ export class LexicalEnvironment {
|
||||
} catch (err) {
|
||||
if (err instanceof JoinedAbruptCompletions || err instanceof PossiblyNormalCompletion)
|
||||
return AbstractValue.createIntrospectionErrorThrowCompletion(err.joinCondition);
|
||||
if (err instanceof AbruptCompletion)
|
||||
return err;
|
||||
if (err instanceof AbruptCompletion) return err;
|
||||
if (err instanceof Error)
|
||||
// rethrowing Error should preserve stack trace
|
||||
throw err;
|
||||
@ -1009,20 +1046,24 @@ export class LexicalEnvironment {
|
||||
try {
|
||||
return this.evaluateAbstract(ast, strictCode, metadata);
|
||||
} catch (err) {
|
||||
if (err instanceof Completion)
|
||||
return err;
|
||||
if (err instanceof Completion) return err;
|
||||
if (err instanceof Error)
|
||||
// rethrowing Error should preserve stack trace
|
||||
throw err;
|
||||
// let's wrap into a proper Error to create stack trace
|
||||
if (err instanceof Object)
|
||||
throw new Error(err.constructor.name + ": " + err);
|
||||
if (err instanceof Object) throw new Error(err.constructor.name + ": " + err);
|
||||
throw new Error(err);
|
||||
}
|
||||
}
|
||||
|
||||
execute(code: string, filename: string, map: string = "",
|
||||
sourceType: SourceType = "script", onParse: void | ((BabelNodeFile) => void) = undefined, profile ?: boolean): AbruptCompletion | Value {
|
||||
execute(
|
||||
code: string,
|
||||
filename: string,
|
||||
map: string = "",
|
||||
sourceType: SourceType = "script",
|
||||
onParse: void | (BabelNodeFile => void) = undefined,
|
||||
profile?: boolean
|
||||
): AbruptCompletion | Value {
|
||||
let context = new ExecutionContext();
|
||||
context.lexicalEnvironment = this;
|
||||
context.variableEnvironment = this;
|
||||
@ -1053,7 +1094,9 @@ export class LexicalEnvironment {
|
||||
}
|
||||
|
||||
executePartialEvaluator(
|
||||
sources: Array<SourceFile>, options: Options = defaultOptions, sourceType: SourceType = "script"
|
||||
sources: Array<SourceFile>,
|
||||
options: Options = defaultOptions,
|
||||
sourceType: SourceType = "script"
|
||||
): AbruptCompletion | { code: string, map?: SourceMap } {
|
||||
let body: Array<BabelNodeStatement> = [];
|
||||
let code = {};
|
||||
@ -1086,20 +1129,16 @@ export class LexicalEnvironment {
|
||||
}
|
||||
let prog = t.program(body);
|
||||
this.fixup_filenames(prog);
|
||||
return generate(
|
||||
prog,
|
||||
{ sourceMaps: options.sourceMaps },
|
||||
(code: any));
|
||||
return generate(prog, { sourceMaps: options.sourceMaps }, (code: any));
|
||||
}
|
||||
|
||||
fixup_source_locations(ast: BabelNode, map: string) {
|
||||
const smc = new sourceMap.SourceMapConsumer(map);
|
||||
traverse(ast, function (node) {
|
||||
traverse(ast, function(node) {
|
||||
let loc = node.loc;
|
||||
if (loc == null || loc.start == null) return false;
|
||||
let new_pos = loc.start;
|
||||
let old_pos = smc.originalPositionFor(
|
||||
{ line: new_pos.line, column: new_pos.column });
|
||||
let old_pos = smc.originalPositionFor({ line: new_pos.line, column: new_pos.column });
|
||||
if (old_pos.source == null) return false;
|
||||
new_pos.line = old_pos.line;
|
||||
new_pos.column = old_pos.column;
|
||||
@ -1109,10 +1148,9 @@ export class LexicalEnvironment {
|
||||
}
|
||||
|
||||
fixup_filenames(ast: BabelNode) {
|
||||
traverse(ast, function (node) {
|
||||
traverse(ast, function(node) {
|
||||
let loc = node.loc;
|
||||
if (!!loc && !!loc.source)
|
||||
(loc: any).filename = loc.source;
|
||||
if (!!loc && !!loc.source) (loc: any).filename = loc.source;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
@ -1138,7 +1176,9 @@ export class LexicalEnvironment {
|
||||
}
|
||||
|
||||
partiallyEvaluate(
|
||||
ast: BabelNode, strictCode: boolean, metadata?: any
|
||||
ast: BabelNode,
|
||||
strictCode: boolean,
|
||||
metadata?: any
|
||||
): [Completion | Reference | Value, BabelNode, Array<BabelNodeStatement>] {
|
||||
let partialEvaluator = this.realm.partialEvaluators[(ast.type: string)];
|
||||
if (partialEvaluator) {
|
||||
@ -1148,7 +1188,6 @@ export class LexicalEnvironment {
|
||||
let err = new TypeError(`Unsupported node type ${ast.type}`);
|
||||
throw err;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ECMA262 6.2.3
|
||||
@ -1170,11 +1209,19 @@ export class Reference {
|
||||
strict: boolean;
|
||||
thisValue: void | Value;
|
||||
|
||||
constructor(base: BaseValue | AbstractValue,
|
||||
refName: ReferenceName | AbstractValue,
|
||||
strict: boolean, thisValue?: void | Value) {
|
||||
invariant(base instanceof AbstractObjectValue || base === undefined || base instanceof ObjectValue ||
|
||||
base instanceof EnvironmentRecord || canBecomeAnObject(base));
|
||||
constructor(
|
||||
base: BaseValue | AbstractValue,
|
||||
refName: ReferenceName | AbstractValue,
|
||||
strict: boolean,
|
||||
thisValue?: void | Value
|
||||
) {
|
||||
invariant(
|
||||
base instanceof AbstractObjectValue ||
|
||||
base === undefined ||
|
||||
base instanceof ObjectValue ||
|
||||
base instanceof EnvironmentRecord ||
|
||||
canBecomeAnObject(base)
|
||||
);
|
||||
this.base = base;
|
||||
this.referencedName = refName;
|
||||
invariant(!(refName instanceof AbstractValue) || !refName.mightNotBeString());
|
||||
|
@ -11,9 +11,9 @@
|
||||
|
||||
import type { BabelNodeSourceLocation } from "babel-types";
|
||||
|
||||
export type Severity = 'FatalError' | 'RecoverableError' | 'Warning' | 'Information';
|
||||
export type ErrorHandlerResult = 'Fail' | 'Recover';
|
||||
export type ErrorCode = 'PP0001';
|
||||
export type Severity = "FatalError" | "RecoverableError" | "Warning" | "Information";
|
||||
export type ErrorHandlerResult = "Fail" | "Recover";
|
||||
export type ErrorCode = "PP0001";
|
||||
|
||||
// This is the error format used to report errors to the caller-supplied
|
||||
// error-handler
|
||||
|
@ -22,7 +22,12 @@ import { IteratorStep, IteratorValue } from "../methods/iterator.js";
|
||||
import type { BabelNodeArrayExpression } from "babel-types";
|
||||
|
||||
// ECMA262 2.2.5.3
|
||||
export default function (ast: BabelNodeArrayExpression, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeArrayExpression,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
// 1. Let array be ArrayCreate(0).
|
||||
let array = ArrayCreate(realm, 0);
|
||||
|
||||
|
@ -19,7 +19,12 @@ import * as t from "babel-types";
|
||||
import type { BabelNodeArrowFunctionExpression } from "babel-types";
|
||||
|
||||
// ECMA262 14.2.16
|
||||
export default function (ast: BabelNodeArrowFunctionExpression, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeArrowFunctionExpression,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
let ConciseBody = ast.body;
|
||||
if (ConciseBody.type !== "BlockStatement") {
|
||||
ConciseBody = t.blockStatement([t.returnStatement(ConciseBody)]);
|
||||
|
@ -28,23 +28,26 @@ import type { BabelNodeAssignmentExpression, BabelBinaryOperator } from "babel-t
|
||||
import { computeBinary } from "./BinaryExpression.js";
|
||||
|
||||
// ECMA262 12.15 Assignment Operators
|
||||
export default function (ast: BabelNodeAssignmentExpression, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
if ((!ast.hasOwnProperty("operator")) || (ast.operator === null))
|
||||
throw Error("Unexpected AST form");
|
||||
export default function(
|
||||
ast: BabelNodeAssignmentExpression,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
if (!ast.hasOwnProperty("operator") || ast.operator === null) throw Error("Unexpected AST form");
|
||||
|
||||
let LeftHandSideExpression = ast.left;
|
||||
let AssignmentExpression = ast.right;
|
||||
let AssignmentOperator = ast.operator;
|
||||
|
||||
// AssignmentExpression : LeftHandSideExpression = AssignmentExpression
|
||||
if (AssignmentOperator === "="){
|
||||
if (AssignmentOperator === "=") {
|
||||
// 1. If LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral, then
|
||||
//
|
||||
// The spec assumes we haven't yet distinguished between literals and
|
||||
// patterns, but our parser does that work for us. That means we check for
|
||||
// "*Pattern" instead of "*Literal" like the spec text suggests.
|
||||
if (LeftHandSideExpression.type !== "ObjectPattern" &&
|
||||
LeftHandSideExpression.type !== "ArrayPattern") {
|
||||
if (LeftHandSideExpression.type !== "ObjectPattern" && LeftHandSideExpression.type !== "ArrayPattern") {
|
||||
// a. Let lref be the result of evaluating LeftHandSideExpression.
|
||||
let lref = env.evaluate(LeftHandSideExpression, strictCode);
|
||||
// b. ReturnIfAbrupt(lref). -- Not neccessary
|
||||
@ -53,13 +56,15 @@ export default function (ast: BabelNodeAssignmentExpression, strictCode: boolean
|
||||
// d. Let rval be ? GetValue(rref).
|
||||
let rval = GetValue(realm, rref);
|
||||
// e. If IsAnonymousFunctionDefinition(AssignmentExpression) and IsIdentifierRef of LeftHandSideExpression are both true, then
|
||||
if (IsAnonymousFunctionDefinition(realm, AssignmentExpression) &&
|
||||
IsIdentifierRef(realm, LeftHandSideExpression)) {
|
||||
if (
|
||||
IsAnonymousFunctionDefinition(realm, AssignmentExpression) &&
|
||||
IsIdentifierRef(realm, LeftHandSideExpression)
|
||||
) {
|
||||
invariant(rval instanceof ObjectValue);
|
||||
// i. Let hasNameProperty be ? HasOwnProperty(rval, "name").
|
||||
let hasNameProperty = HasOwnProperty(realm, rval, "name");
|
||||
// ii. If hasNameProperty is false, perform SetFunctionName(rval, GetReferencedName(lref)).
|
||||
if (!hasNameProperty){
|
||||
if (!hasNameProperty) {
|
||||
invariant(lref instanceof Reference);
|
||||
SetFunctionName(realm, rval, GetReferencedName(realm, lref));
|
||||
}
|
||||
@ -99,7 +104,7 @@ export default function (ast: BabelNodeAssignmentExpression, strictCode: boolean
|
||||
// 4. Let rval be ? GetValue(rref).
|
||||
let rval = GetValue(realm, rref);
|
||||
// 5. Let op be the @ where AssignmentOperator is @=.
|
||||
let op = ((AssignmentOperator.slice(0, -1): any): BabelBinaryOperator);
|
||||
let op = ((AssignmentOperator.slice(0, -1): any): BabelBinaryOperator);
|
||||
// 6. Let r be the result of applying op to lval and rval as if evaluating the expression lval op rval.
|
||||
let r = GetValue(realm, computeBinary(realm, op, lval, rval, ast.left.loc, ast.right.loc));
|
||||
// 7. Perform ? PutValue(lref, r).
|
||||
|
@ -15,6 +15,11 @@ import type { Value } from "../values/index.js";
|
||||
import type { Reference } from "../environment.js";
|
||||
import type { BabelNodeAwaitExpression } from "babel-types";
|
||||
|
||||
export default function (ast: BabelNodeAwaitExpression, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeAwaitExpression,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
throw new Error("TODO: AwaitExpression");
|
||||
}
|
||||
|
@ -12,17 +12,42 @@
|
||||
import type { Realm } from "../realm.js";
|
||||
import type { LexicalEnvironment } from "../environment.js";
|
||||
import { CompilerDiagnostics, FatalError } from "../errors.js";
|
||||
import { Value, AbstractValue, AbstractObjectValue, ConcreteValue, UndefinedValue, NullValue, BooleanValue, NumberValue, ObjectValue, StringValue } from "../values/index.js";
|
||||
import {
|
||||
Value,
|
||||
AbstractValue,
|
||||
AbstractObjectValue,
|
||||
ConcreteValue,
|
||||
UndefinedValue,
|
||||
NullValue,
|
||||
BooleanValue,
|
||||
NumberValue,
|
||||
ObjectValue,
|
||||
StringValue,
|
||||
} from "../values/index.js";
|
||||
import { GetValue } from "../methods/index.js";
|
||||
import { HasProperty, HasSomeCompatibleType } from "../methods/index.js";
|
||||
import { Add, AbstractEqualityComparison, StrictEqualityComparison, AbstractRelationalComparison, InstanceofOperator, IsToPrimitivePure, GetToPrimitivePureResultType, IsToNumberPure } from "../methods/index.js";
|
||||
import {
|
||||
Add,
|
||||
AbstractEqualityComparison,
|
||||
StrictEqualityComparison,
|
||||
AbstractRelationalComparison,
|
||||
InstanceofOperator,
|
||||
IsToPrimitivePure,
|
||||
GetToPrimitivePureResultType,
|
||||
IsToNumberPure,
|
||||
} from "../methods/index.js";
|
||||
import { ToUint32, ToInt32, ToNumber, ToPrimitive, ToString, ToPropertyKey } from "../methods/index.js";
|
||||
import { TypesDomain, ValuesDomain } from "../domains/index.js";
|
||||
import * as t from "babel-types";
|
||||
import type { BabelNodeBinaryExpression, BabelBinaryOperator, BabelNodeSourceLocation } from "babel-types";
|
||||
import invariant from "../invariant.js";
|
||||
|
||||
export default function (ast: BabelNodeBinaryExpression, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value {
|
||||
export default function(
|
||||
ast: BabelNodeBinaryExpression,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value {
|
||||
// evaluate left
|
||||
let lref = env.evaluate(ast.left, strictCode);
|
||||
let lval = GetValue(realm, lref);
|
||||
@ -38,15 +63,20 @@ let unknownValueOfOrToString = "might be an object with an unknown valueOf or to
|
||||
|
||||
// Returns result type if binary operation is pure (terminates, does not throw exception, does not read or write heap), otherwise undefined.
|
||||
export function getPureBinaryOperationResultType(
|
||||
realm: Realm, op: BabelBinaryOperator, lval: Value, rval: Value, lloc: ?BabelNodeSourceLocation, rloc: ?BabelNodeSourceLocation
|
||||
realm: Realm,
|
||||
op: BabelBinaryOperator,
|
||||
lval: Value,
|
||||
rval: Value,
|
||||
lloc: ?BabelNodeSourceLocation,
|
||||
rloc: ?BabelNodeSourceLocation
|
||||
): typeof Value {
|
||||
function reportErrorIfNotPure(purityTest: (Realm, Value) => boolean, typeIfPure: typeof Value): typeof Value {
|
||||
let leftPure = purityTest(realm, lval);
|
||||
let rightPure = purityTest(realm, rval);
|
||||
if (leftPure && rightPure) return typeIfPure;
|
||||
let loc = !leftPure ? lloc : rloc;
|
||||
let error = new CompilerDiagnostics(unknownValueOfOrToString, loc, 'PP0002', 'RecoverableError');
|
||||
if (realm.handleError(error) === 'Recover') {
|
||||
let error = new CompilerDiagnostics(unknownValueOfOrToString, loc, "PP0002", "RecoverableError");
|
||||
if (realm.handleError(error) === "Recover") {
|
||||
// Assume that an unknown value is actually a primitive or otherwise a well behaved object.
|
||||
return typeIfPure;
|
||||
}
|
||||
@ -57,8 +87,8 @@ export function getPureBinaryOperationResultType(
|
||||
let rtype = GetToPrimitivePureResultType(realm, rval);
|
||||
if (ltype === undefined || rtype === undefined) {
|
||||
let loc = ltype === undefined ? lloc : rloc;
|
||||
let error = new CompilerDiagnostics(unknownValueOfOrToString, loc, 'PP0002', 'RecoverableError');
|
||||
if (realm.handleError(error) === 'Recover') {
|
||||
let error = new CompilerDiagnostics(unknownValueOfOrToString, loc, "PP0002", "RecoverableError");
|
||||
if (realm.handleError(error) === "Recover") {
|
||||
// Assume that the unknown value is actually a primitive or otherwise a well behaved object.
|
||||
ltype = lval.getType();
|
||||
rtype = rval.getType();
|
||||
@ -66,7 +96,7 @@ export function getPureBinaryOperationResultType(
|
||||
if (ltype === NumberValue && rtype === NumberValue) return NumberValue;
|
||||
return Value;
|
||||
}
|
||||
throw new FatalError();
|
||||
throw new FatalError();
|
||||
}
|
||||
if (ltype === StringValue || rtype === StringValue) return StringValue;
|
||||
return NumberValue;
|
||||
@ -74,26 +104,45 @@ export function getPureBinaryOperationResultType(
|
||||
return reportErrorIfNotPure(IsToPrimitivePure, BooleanValue);
|
||||
} else if (op === "===" || op === "!==") {
|
||||
return BooleanValue;
|
||||
} else if (op === ">>>" || op === "<<" || op === ">>" || op === "&" || op === "|" || op === "^" ||
|
||||
op === "**" || op === "%" || op === "/" || op === "*" || op === "-") {
|
||||
} else if (
|
||||
op === ">>>" ||
|
||||
op === "<<" ||
|
||||
op === ">>" ||
|
||||
op === "&" ||
|
||||
op === "|" ||
|
||||
op === "^" ||
|
||||
op === "**" ||
|
||||
op === "%" ||
|
||||
op === "/" ||
|
||||
op === "*" ||
|
||||
op === "-"
|
||||
) {
|
||||
return reportErrorIfNotPure(IsToNumberPure, NumberValue);
|
||||
} else if (op === "in" || op === "instanceof") {
|
||||
if (rval.mightNotBeObject()) {
|
||||
let error = new CompilerDiagnostics(
|
||||
`might not be an object, hence the ${op} operator might throw a TypeError`, rloc, 'PP0003', 'RecoverableError');
|
||||
if (realm.handleError(error) === 'Recover') {
|
||||
`might not be an object, hence the ${op} operator might throw a TypeError`,
|
||||
rloc,
|
||||
"PP0003",
|
||||
"RecoverableError"
|
||||
);
|
||||
if (realm.handleError(error) === "Recover") {
|
||||
// Assume that the object is actually a well behaved object.
|
||||
return BooleanValue;
|
||||
}
|
||||
throw new FatalError();
|
||||
}
|
||||
if (rval instanceof ObjectValue || rval instanceof AbstractObjectValue) {
|
||||
// Simple object won't throw here, aren't proxy objects or typed arrays and do not have @@hasInstance properties.
|
||||
// Simple object won't throw here, aren't proxy objects or typed arrays and do not have @@hasInstance properties.
|
||||
if (rval.isSimple()) return BooleanValue;
|
||||
}
|
||||
let error = new CompilerDiagnostics(
|
||||
`might be an object that behaves badly for the ${op} operator`, rloc, 'PP0004', 'RecoverableError');
|
||||
if (realm.handleError(error) === 'Recover') {
|
||||
`might be an object that behaves badly for the ${op} operator`,
|
||||
rloc,
|
||||
"PP0004",
|
||||
"RecoverableError"
|
||||
);
|
||||
if (realm.handleError(error) === "Recover") {
|
||||
// Assume that the object is actually a well behaved object.
|
||||
return BooleanValue;
|
||||
}
|
||||
@ -103,19 +152,27 @@ export function getPureBinaryOperationResultType(
|
||||
}
|
||||
|
||||
export function computeBinary(
|
||||
realm: Realm, op: BabelBinaryOperator, lval: Value, rval: Value, lloc: ?BabelNodeSourceLocation, rloc: ?BabelNodeSourceLocation
|
||||
realm: Realm,
|
||||
op: BabelBinaryOperator,
|
||||
lval: Value,
|
||||
rval: Value,
|
||||
lloc: ?BabelNodeSourceLocation,
|
||||
rloc: ?BabelNodeSourceLocation
|
||||
): Value {
|
||||
// partial evaluation shortcut for a particular pattern
|
||||
if (op === "==" || op === "===" || op === "!=" || op === "!==") {
|
||||
if (!lval.mightNotBeObject() && HasSomeCompatibleType(rval, NullValue, UndefinedValue) ||
|
||||
HasSomeCompatibleType(lval, NullValue, UndefinedValue) && !rval.mightNotBeObject())
|
||||
if (
|
||||
(!lval.mightNotBeObject() && HasSomeCompatibleType(rval, NullValue, UndefinedValue)) ||
|
||||
(HasSomeCompatibleType(lval, NullValue, UndefinedValue) && !rval.mightNotBeObject())
|
||||
)
|
||||
return new BooleanValue(realm, op[0] !== "=");
|
||||
}
|
||||
|
||||
if ((lval instanceof AbstractValue) || (rval instanceof AbstractValue)) {
|
||||
if (lval instanceof AbstractValue || rval instanceof AbstractValue) {
|
||||
let type = getPureBinaryOperationResultType(realm, op, lval, rval, lloc, rloc);
|
||||
return realm.createAbstract(new TypesDomain(type), ValuesDomain.topVal, [lval, rval],
|
||||
([lnode, rnode]) => t.binaryExpression(op, lnode, rnode));
|
||||
return realm.createAbstract(new TypesDomain(type), ValuesDomain.topVal, [lval, rval], ([lnode, rnode]) =>
|
||||
t.binaryExpression(op, lnode, rnode)
|
||||
);
|
||||
}
|
||||
|
||||
invariant(lval instanceof ConcreteValue);
|
||||
|
@ -19,7 +19,12 @@ import { StringValue, Value } from "../values/index.js";
|
||||
import { EvaluateStatements, NewDeclarativeEnvironment, BlockDeclarationInstantiation } from "../methods/index.js";
|
||||
|
||||
// ECMA262 13.2.13
|
||||
export default function (ast: BabelNodeBlockStatement, strictCode: boolean, env: LexicalEnvironment, realm: Realm): NormalCompletion | Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeBlockStatement,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): NormalCompletion | Value | Reference {
|
||||
// 1. Let oldEnv be the running execution context's LexicalEnvironment.
|
||||
let oldEnv = realm.getRunningContext().lexicalEnvironment;
|
||||
|
||||
@ -37,7 +42,7 @@ export default function (ast: BabelNodeBlockStatement, strictCode: boolean, env:
|
||||
let blockValue: void | NormalCompletion | Value;
|
||||
|
||||
if (ast.directives) {
|
||||
for (let directive of (ast.directives)) {
|
||||
for (let directive of ast.directives) {
|
||||
blockValue = new StringValue(realm, directive.value.value);
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,11 @@ import type { Reference } from "../environment.js";
|
||||
import { BooleanValue } from "../values/index.js";
|
||||
import type { BabelNodeBooleanLiteral } from "babel-types";
|
||||
|
||||
export default function (ast: BabelNodeBooleanLiteral, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeBooleanLiteral,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
return new BooleanValue(realm, ast.value);
|
||||
}
|
||||
|
@ -16,6 +16,11 @@ import type { Reference } from "../environment.js";
|
||||
import { BreakCompletion } from "../completions.js";
|
||||
import type { BabelNodeBreakStatement } from "babel-types";
|
||||
|
||||
export default function (ast: BabelNodeBreakStatement, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeBreakStatement,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
throw new BreakCompletion(realm.intrinsics.empty, ast.label && ast.label.name);
|
||||
}
|
||||
|
@ -28,16 +28,21 @@ import {
|
||||
joinEffects,
|
||||
GetReferencedName,
|
||||
EvaluateDirectCall,
|
||||
ArgumentListEvaluation
|
||||
ArgumentListEvaluation,
|
||||
} from "../methods/index.js";
|
||||
import type { BabelNode, BabelNodeCallExpression, BabelNodeExpression, BabelNodeSpreadElement } from "babel-types";
|
||||
import invariant from "../invariant.js";
|
||||
import * as t from "babel-types";
|
||||
import { TypesDomain, ValuesDomain } from "../domains/index.js";
|
||||
import SuperCall from './SuperCall';
|
||||
import SuperCall from "./SuperCall";
|
||||
|
||||
export default function (ast: BabelNodeCallExpression, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Completion | Value | Reference {
|
||||
if (ast.callee.type === 'Super') {
|
||||
export default function(
|
||||
ast: BabelNodeCallExpression,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Completion | Value | Reference {
|
||||
if (ast.callee.type === "Super") {
|
||||
return SuperCall(ast.arguments, strictCode, env, realm);
|
||||
}
|
||||
|
||||
@ -53,22 +58,32 @@ export default function (ast: BabelNodeCallExpression, strictCode: boolean, env:
|
||||
return EvaluateCall(ref, func, ast, strictCode, env, realm);
|
||||
}
|
||||
|
||||
function callBothFunctionsAndJoinTheirEffects(args: Array<Value>, ast: BabelNodeCallExpression, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Completion | Value | Reference {
|
||||
function callBothFunctionsAndJoinTheirEffects(
|
||||
args: Array<Value>,
|
||||
ast: BabelNodeCallExpression,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Completion | Value | Reference {
|
||||
let [cond, func1, func2] = args;
|
||||
invariant(cond instanceof AbstractValue && cond.getType() === BooleanValue);
|
||||
invariant(func1.getType() === FunctionValue);
|
||||
invariant(func2.getType() === FunctionValue);
|
||||
|
||||
let [compl1, gen1, bindings1, properties1, createdObj1] =
|
||||
realm.evaluateForEffects(() => EvaluateCall(func1, func1, ast, strictCode, env, realm));
|
||||
let [compl1, gen1, bindings1, properties1, createdObj1] = realm.evaluateForEffects(() =>
|
||||
EvaluateCall(func1, func1, ast, strictCode, env, realm)
|
||||
);
|
||||
|
||||
let [compl2, gen2, bindings2, properties2, createdObj2] =
|
||||
realm.evaluateForEffects(() => EvaluateCall(func2, func2, ast, strictCode, env, realm));
|
||||
let [compl2, gen2, bindings2, properties2, createdObj2] = realm.evaluateForEffects(() =>
|
||||
EvaluateCall(func2, func2, ast, strictCode, env, realm)
|
||||
);
|
||||
|
||||
let joinedEffects =
|
||||
joinEffects(realm, cond,
|
||||
[compl1, gen1, bindings1, properties1, createdObj1],
|
||||
[compl2, gen2, bindings2, properties2, createdObj2]);
|
||||
let joinedEffects = joinEffects(
|
||||
realm,
|
||||
cond,
|
||||
[compl1, gen1, bindings1, properties1, createdObj1],
|
||||
[compl2, gen2, bindings2, properties2, createdObj2]
|
||||
);
|
||||
let completion = joinedEffects[0];
|
||||
if (completion instanceof NormalCompletion) {
|
||||
// in this case one of the branches may complete abruptly, which means that
|
||||
@ -89,27 +104,26 @@ function callBothFunctionsAndJoinTheirEffects(args: Array<Value>, ast: BabelNode
|
||||
}
|
||||
|
||||
function EvaluateCall(
|
||||
ref: Value | Reference, func: Value, ast: BabelNodeCallExpression,
|
||||
strictCode: boolean, env: LexicalEnvironment, realm: Realm
|
||||
ref: Value | Reference,
|
||||
func: Value,
|
||||
ast: BabelNodeCallExpression,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Completion | Value | Reference {
|
||||
function generateRuntimeCall() {
|
||||
let args =
|
||||
[func].concat(ArgumentListEvaluation(realm, strictCode, env, ((ast.arguments: any): Array<BabelNode>)));
|
||||
return realm.deriveAbstract(
|
||||
TypesDomain.topVal,
|
||||
ValuesDomain.topVal,
|
||||
args,
|
||||
(nodes) => {
|
||||
let fun_args = ((nodes.slice(1): any): Array<BabelNodeExpression | BabelNodeSpreadElement>);
|
||||
return t.callExpression(nodes[0], fun_args);
|
||||
});
|
||||
let args = [func].concat(ArgumentListEvaluation(realm, strictCode, env, ((ast.arguments: any): Array<BabelNode>)));
|
||||
return realm.deriveAbstract(TypesDomain.topVal, ValuesDomain.topVal, args, nodes => {
|
||||
let fun_args = ((nodes.slice(1): any): Array<BabelNodeExpression | BabelNodeSpreadElement>);
|
||||
return t.callExpression(nodes[0], fun_args);
|
||||
});
|
||||
}
|
||||
|
||||
if (func instanceof AbstractValue) {
|
||||
if (func.getType() !== FunctionValue) {
|
||||
let loc = ast.callee.type === "MemberExpression" ? ast.callee.property.loc : ast.callee.loc;
|
||||
let error = new CompilerDiagnostics("might not be a function", loc, 'PP0005', 'RecoverableError');
|
||||
if (realm.handleError(error) === 'Fail') throw new FatalError();
|
||||
let error = new CompilerDiagnostics("might not be a function", loc, "PP0005", "RecoverableError");
|
||||
if (realm.handleError(error) === "Fail") throw new FatalError();
|
||||
} else if (func.kind === "conditional") {
|
||||
return callBothFunctionsAndJoinTheirEffects(func.args, ast, strictCode, env, realm);
|
||||
} else {
|
||||
@ -136,8 +150,8 @@ function EvaluateCall(
|
||||
// vi. Return ? PerformEval(evalText, evalRealm, strictCaller, true).
|
||||
if (evalText instanceof AbstractValue) {
|
||||
let loc = ast.arguments[0].loc;
|
||||
let error = new CompilerDiagnostics("eval argument must be a known value", loc, 'PP0006', 'RecoverableError');
|
||||
if (realm.handleError(error) === 'Fail') throw new FatalError();
|
||||
let error = new CompilerDiagnostics("eval argument must be a known value", loc, "PP0006", "RecoverableError");
|
||||
if (realm.handleError(error) === "Fail") throw new FatalError();
|
||||
// Assume that it is a safe eval with no visible heap changes or abrupt control flow.
|
||||
return generateRuntimeCall();
|
||||
}
|
||||
@ -153,7 +167,8 @@ function EvaluateCall(
|
||||
if (IsPropertyReference(realm, ref)) {
|
||||
// i. Let thisValue be GetThisValue(ref).
|
||||
thisValue = GetThisValue(realm, ref);
|
||||
} else { // b. Else, the base of ref is an Environment Record
|
||||
} else {
|
||||
// b. Else, the base of ref is an Environment Record
|
||||
// i. Let refEnv be GetBase(ref).
|
||||
let refEnv = GetBase(realm, ref);
|
||||
invariant(refEnv instanceof EnvironmentRecord);
|
||||
@ -161,7 +176,8 @@ function EvaluateCall(
|
||||
// ii. Let thisValue be refEnv.WithBaseObject().
|
||||
thisValue = refEnv.WithBaseObject();
|
||||
}
|
||||
} else { // 5. Else Type(ref) is not Reference,
|
||||
} else {
|
||||
// 5. Else Type(ref) is not Reference,
|
||||
// a. Let thisValue be undefined.
|
||||
thisValue = realm.intrinsics.undefined;
|
||||
}
|
||||
@ -173,5 +189,14 @@ function EvaluateCall(
|
||||
let tailCall = IsInTailPosition(realm, thisCall);
|
||||
|
||||
// 8. Return ? EvaluateDirectCall(func, thisValue, Arguments, tailCall).
|
||||
return EvaluateDirectCall(realm, strictCode, env, ref, func, thisValue, ((ast.arguments: any): Array<BabelNode>), tailCall);
|
||||
return EvaluateDirectCall(
|
||||
realm,
|
||||
strictCode,
|
||||
env,
|
||||
ref,
|
||||
func,
|
||||
thisValue,
|
||||
((ast.arguments: any): Array<BabelNode>),
|
||||
tailCall
|
||||
);
|
||||
}
|
||||
|
@ -19,7 +19,13 @@ import { NewDeclarativeEnvironment, BoundNames, BindingInitialization } from "..
|
||||
import type { BabelNodeCatchClause } from "babel-types";
|
||||
|
||||
// ECAM262 13.15.7
|
||||
export default function (ast: BabelNodeCatchClause, strictCode: boolean, env: LexicalEnvironment, realm: Realm, thrownValue: any): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeCatchClause,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm,
|
||||
thrownValue: any
|
||||
): Value | Reference {
|
||||
invariant(thrownValue instanceof ThrowCompletion, "Metadata isn't a throw completion");
|
||||
|
||||
// 1. Let oldEnv be the running execution context's LexicalEnvironment.
|
||||
@ -45,8 +51,8 @@ export default function (ast: BabelNodeCatchClause, strictCode: boolean, env: Le
|
||||
BindingInitialization(realm, ast.param, thrownValue.value, strictCode, catchEnv);
|
||||
|
||||
// 7. If status is an abrupt completion, then
|
||||
// a. Set the running execution context's LexicalEnvironment to oldEnv.
|
||||
// b. Return Completion(status).
|
||||
// a. Set the running execution context's LexicalEnvironment to oldEnv.
|
||||
// b. Return Completion(status).
|
||||
|
||||
// 8. Let B be the result of evaluating Block.
|
||||
let B = catchEnv.evaluate(ast.body, strictCode);
|
||||
|
@ -13,7 +13,7 @@ import type { Realm } from "../realm.js";
|
||||
import type { LexicalEnvironment, Reference } from "../environment.js";
|
||||
import { AbstractValue, Value } from "../values/index.js";
|
||||
import { CompilerDiagnostics, FatalError } from "../errors.js";
|
||||
import { NullValue, EmptyValue, ObjectValue } from '../values/index.js';
|
||||
import { NullValue, EmptyValue, ObjectValue } from "../values/index.js";
|
||||
import type {
|
||||
BabelNodeClassDeclaration,
|
||||
BabelNodeClassExpression,
|
||||
@ -41,13 +41,16 @@ import {
|
||||
} from "../methods/index.js";
|
||||
import invariant from "../invariant.js";
|
||||
|
||||
function EvaluateClassHeritage(realm: Realm, ClassHeritage: BabelNodeExpression, strictCode: boolean): ObjectValue | null {
|
||||
function EvaluateClassHeritage(
|
||||
realm: Realm,
|
||||
ClassHeritage: BabelNodeExpression,
|
||||
strictCode: boolean
|
||||
): ObjectValue | null {
|
||||
let ref = realm.getRunningContext().lexicalEnvironment.evaluate(ClassHeritage, strictCode);
|
||||
let val = GetValue(realm, ref);
|
||||
if (val instanceof AbstractValue) {
|
||||
let error = new CompilerDiagnostics(
|
||||
"unknown super class", ClassHeritage.loc, 'PP0009', 'RecoverableError');
|
||||
if (realm.handleError(error) === 'Fail') throw new FatalError();
|
||||
let error = new CompilerDiagnostics("unknown super class", ClassHeritage.loc, "PP0009", "RecoverableError");
|
||||
if (realm.handleError(error) === "Fail") throw new FatalError();
|
||||
}
|
||||
if (!(val instanceof ObjectValue)) {
|
||||
return null;
|
||||
@ -56,7 +59,13 @@ function EvaluateClassHeritage(realm: Realm, ClassHeritage: BabelNodeExpression,
|
||||
}
|
||||
|
||||
// ECMA262 14.5.14
|
||||
export function ClassDefinitionEvaluation(realm: Realm, ast: BabelNodeClassDeclaration | BabelNodeClassExpression, className: string | void, strictCode: boolean, env: LexicalEnvironment) {
|
||||
export function ClassDefinitionEvaluation(
|
||||
realm: Realm,
|
||||
ast: BabelNodeClassDeclaration | BabelNodeClassExpression,
|
||||
className: string | void,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment
|
||||
) {
|
||||
// 1. Let lex be the LexicalEnvironment of the running execution context.
|
||||
let lex = env;
|
||||
|
||||
@ -82,7 +91,8 @@ export function ClassDefinitionEvaluation(realm: Realm, ast: BabelNodeClassDecla
|
||||
|
||||
// b. Let constructorParent be the intrinsic object %FunctionPrototype%.
|
||||
constructorParent = realm.intrinsics.FunctionPrototype;
|
||||
} else { // 6. Else
|
||||
} else {
|
||||
// 6. Else
|
||||
// a. Set the running execution context’s LexicalEnvironment to classScope.
|
||||
realm.getRunningContext().lexicalEnvironment = classScope;
|
||||
let superclass = null;
|
||||
@ -103,12 +113,14 @@ export function ClassDefinitionEvaluation(realm: Realm, ast: BabelNodeClassDecla
|
||||
|
||||
// ii. Let constructorParent be the intrinsic object %FunctionPrototype%.
|
||||
constructorParent = realm.intrinsics.FunctionPrototype;
|
||||
} else if (!IsConstructor(realm, superclass)) { // f. Else if IsConstructor(superclass) is false, throw a TypeError exception.
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, 'superclass must be a constructor');
|
||||
} else { // g. Else
|
||||
} else if (!IsConstructor(realm, superclass)) {
|
||||
// f. Else if IsConstructor(superclass) is false, throw a TypeError exception.
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "superclass must be a constructor");
|
||||
} else {
|
||||
// g. Else
|
||||
// i. If superclass has a [[FunctionKind]] internal slot whose value is "generator", throw a TypeError exception.
|
||||
if (superclass.$FunctionKind === 'generator') {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, 'superclass cannot be a generator');
|
||||
if (superclass.$FunctionKind === "generator") {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "superclass cannot be a generator");
|
||||
}
|
||||
|
||||
// ii. Let protoParent be Get(superclass, "prototype").
|
||||
@ -120,11 +132,18 @@ export function ClassDefinitionEvaluation(realm: Realm, ast: BabelNodeClassDecla
|
||||
if (!(protoParent instanceof ObjectValue || protoParent instanceof NullValue)) {
|
||||
if (protoParent instanceof AbstractValue) {
|
||||
let error = new CompilerDiagnostics(
|
||||
"unknown super class prototype", ClassHeritage.loc, 'PP0010', 'RecoverableError');
|
||||
if (realm.handleError(error) === 'Fail') throw new FatalError();
|
||||
"unknown super class prototype",
|
||||
ClassHeritage.loc,
|
||||
"PP0010",
|
||||
"RecoverableError"
|
||||
);
|
||||
if (realm.handleError(error) === "Fail") throw new FatalError();
|
||||
protoParent = realm.intrinsics.ObjectPrototype;
|
||||
} else {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, 'protoParent must be an instance of Object or Null');
|
||||
throw realm.createErrorThrowCompletion(
|
||||
realm.intrinsics.TypeError,
|
||||
"protoParent must be an instance of Object or Null"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,16 +156,17 @@ export function ClassDefinitionEvaluation(realm: Realm, ast: BabelNodeClassDecla
|
||||
let proto = ObjectCreate(realm, protoParent);
|
||||
|
||||
let constructor;
|
||||
let ClassBody : Array<BabelNodeClassMethod> = [];
|
||||
let ClassBody: Array<BabelNodeClassMethod> = [];
|
||||
for (let elem of ast.body.body) {
|
||||
if (elem.type === 'ClassMethod') {
|
||||
if (elem.type === "ClassMethod") {
|
||||
ClassBody.push(elem);
|
||||
}
|
||||
}
|
||||
// 8. If ClassBody opt is not present, let constructor be empty.
|
||||
if (ClassBody.length === 0) {
|
||||
constructor = realm.intrinsics.empty;
|
||||
} else { // 9. Else, let constructor be ConstructorMethod of ClassBody.
|
||||
} else {
|
||||
// 9. Else, let constructor be ConstructorMethod of ClassBody.
|
||||
constructor = ConstructorMethod(realm, ClassBody);
|
||||
}
|
||||
|
||||
@ -158,18 +178,19 @@ export function ClassDefinitionEvaluation(realm: Realm, ast: BabelNodeClassDecla
|
||||
// i. Let constructor be the result of parsing the source text
|
||||
// constructor(... args){ super (...args);}
|
||||
// using the syntactic grammar with the goal symbol MethodDefinition.
|
||||
constructorFile = parse(realm, 'class NeedClassForParsing { constructor(... args){ super (...args);} }', '');
|
||||
} else { // b. Else,
|
||||
constructorFile = parse(realm, "class NeedClassForParsing { constructor(... args){ super (...args);} }", "");
|
||||
} else {
|
||||
// b. Else,
|
||||
// i. Let constructor be the result of parsing the source text
|
||||
// constructor( ){ }
|
||||
// using the syntactic grammar with the goal symbol MethodDefinition.
|
||||
constructorFile = parse(realm, 'class NeedClassForParsing { constructor( ){ } }', '');
|
||||
constructorFile = parse(realm, "class NeedClassForParsing { constructor( ){ } }", "");
|
||||
}
|
||||
|
||||
let { program: { body: [classDeclaration] } } = constructorFile;
|
||||
invariant(classDeclaration.type === "ClassDeclaration");
|
||||
let { body } = ((classDeclaration: any): BabelNodeClassDeclaration);
|
||||
invariant(body.body[0].type === 'ClassMethod');
|
||||
invariant(body.body[0].type === "ClassMethod");
|
||||
constructor = ((body.body[0]: any): BabelNodeClassMethod);
|
||||
}
|
||||
|
||||
@ -204,7 +225,8 @@ export function ClassDefinitionEvaluation(realm: Realm, ast: BabelNodeClassDecla
|
||||
// 19. If ClassBody opt is not present, let methods be a new empty List.
|
||||
if (ClassBody.length === 0) {
|
||||
methods = [];
|
||||
} else { // 20. Else, let methods be NonConstructorMethodDefinitions of ClassBody.
|
||||
} else {
|
||||
// 20. Else, let methods be NonConstructorMethodDefinitions of ClassBody.
|
||||
methods = NonConstructorMethodDefinitions(realm, ClassBody);
|
||||
}
|
||||
|
||||
@ -214,13 +236,14 @@ export function ClassDefinitionEvaluation(realm: Realm, ast: BabelNodeClassDecla
|
||||
if (!IsStatic(m)) {
|
||||
// Let status be the result of performing PropertyDefinitionEvaluation for m with arguments proto and false.
|
||||
PropertyDefinitionEvaluation(realm, m, proto, env, strictCode, false);
|
||||
} else { // Else,
|
||||
} else {
|
||||
// Else,
|
||||
// Let status be the result of performing PropertyDefinitionEvaluation for m with arguments F and false.
|
||||
PropertyDefinitionEvaluation(realm, m, F, env, strictCode, false);
|
||||
}
|
||||
// c. If status is an abrupt completion, then
|
||||
// i. Set the running execution context's LexicalEnvironment to lex.
|
||||
// ii. Return Completion(status).
|
||||
// i. Set the running execution context's LexicalEnvironment to lex.
|
||||
// ii. Return Completion(status).
|
||||
}
|
||||
} finally {
|
||||
// 22. Set the running execution context’s LexicalEnvironment to lex.
|
||||
@ -237,7 +260,12 @@ export function ClassDefinitionEvaluation(realm: Realm, ast: BabelNodeClassDecla
|
||||
}
|
||||
|
||||
// ECMA2 14.5.15
|
||||
function BindingClassDeclarationEvaluation(realm: Realm, ast: BabelNodeClassDeclaration, strictCode: boolean, env: LexicalEnvironment) {
|
||||
function BindingClassDeclarationEvaluation(
|
||||
realm: Realm,
|
||||
ast: BabelNodeClassDeclaration,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment
|
||||
) {
|
||||
// ClassDeclaration : class BindingIdentifier ClassTail
|
||||
if (ast.id) {
|
||||
// 1. Let className be StringValue of BindingIdentifier.
|
||||
@ -267,14 +295,20 @@ function BindingClassDeclarationEvaluation(realm: Realm, ast: BabelNodeClassDecl
|
||||
|
||||
// 10. Return value.
|
||||
return value;
|
||||
} else { // ClassDeclaration : class ClassTail
|
||||
} else {
|
||||
// ClassDeclaration : class ClassTail
|
||||
// 1. Return the result of ClassDefinitionEvaluation of ClassTail with argument undefined.
|
||||
return ClassDefinitionEvaluation(realm, ast, undefined, strictCode, env);
|
||||
}
|
||||
}
|
||||
|
||||
// ECMA262 14.5.16
|
||||
export default function (ast: BabelNodeClassDeclaration, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeClassDeclaration,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
// 1. Let status be the result of BindingClassDeclarationEvaluation of this ClassDeclaration.
|
||||
BindingClassDeclarationEvaluation(realm, ast, strictCode, env);
|
||||
|
||||
|
@ -15,10 +15,15 @@ import type { Value } from "../values/index.js";
|
||||
import type { Reference } from "../environment.js";
|
||||
import type { BabelNodeClassExpression } from "babel-types";
|
||||
import { HasOwnProperty, SetFunctionName } from "../methods/index.js";
|
||||
import { ClassDefinitionEvaluation } from './ClassDeclaration';
|
||||
import { ClassDefinitionEvaluation } from "./ClassDeclaration";
|
||||
|
||||
// ECMA262 14.5.16
|
||||
export default function (ast: BabelNodeClassExpression, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeClassExpression,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
// 1. If BindingIdentifieropt is not present, let className be undefined.
|
||||
let className;
|
||||
// 2. Else, let className be StringValue of BindingIdentifier.
|
||||
|
@ -19,9 +19,12 @@ import type { BabelNodeConditionalExpression } from "babel-types";
|
||||
import invariant from "../invariant.js";
|
||||
import type { Realm } from "../realm.js";
|
||||
|
||||
export default function (
|
||||
ast: BabelNodeConditionalExpression, strictCode: boolean,
|
||||
env: LexicalEnvironment, realm: Realm): NormalCompletion | Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeConditionalExpression,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): NormalCompletion | Value | Reference {
|
||||
let exprRef = env.evaluate(ast.test, strictCode);
|
||||
let exprValue = GetValue(realm, exprRef);
|
||||
|
||||
@ -34,8 +37,6 @@ export default function (
|
||||
}
|
||||
invariant(exprValue instanceof AbstractValue);
|
||||
|
||||
if (!exprValue.mightNotBeObject())
|
||||
return env.evaluate(ast.consequent, strictCode);
|
||||
else
|
||||
return evaluateWithAbstractConditional(exprValue, ast.consequent, ast.alternate, strictCode, env, realm);
|
||||
if (!exprValue.mightNotBeObject()) return env.evaluate(ast.consequent, strictCode);
|
||||
else return evaluateWithAbstractConditional(exprValue, ast.consequent, ast.alternate, strictCode, env, realm);
|
||||
}
|
||||
|
@ -16,6 +16,11 @@ import type { Reference } from "../environment.js";
|
||||
import { ContinueCompletion } from "../completions.js";
|
||||
import type { BabelNodeContinueStatement } from "babel-types";
|
||||
|
||||
export default function (ast: BabelNodeContinueStatement, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeContinueStatement,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
throw new ContinueCompletion(realm.intrinsics.empty, ast.label && ast.label.name);
|
||||
}
|
||||
|
@ -15,6 +15,11 @@ import type { Value } from "../values/index.js";
|
||||
import type { Reference } from "../environment.js";
|
||||
import type { BabelNodeDirective } from "babel-types";
|
||||
|
||||
export default function (ast: BabelNodeDirective, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeDirective,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
return env.evaluate(ast.value, strictCode);
|
||||
}
|
||||
|
@ -20,7 +20,13 @@ import { AbruptCompletion, BreakCompletion } from "../completions.js";
|
||||
import invariant from "../invariant.js";
|
||||
import type { BabelNodeDoWhileStatement } from "babel-types";
|
||||
|
||||
export default function (ast: BabelNodeDoWhileStatement, strictCode: boolean, env: LexicalEnvironment, realm: Realm, labelSet: ?Array<string>): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeDoWhileStatement,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm,
|
||||
labelSet: ?Array<string>
|
||||
): Value | Reference {
|
||||
let { body, test } = ast;
|
||||
|
||||
// 1. Let V be undefined.
|
||||
@ -36,8 +42,7 @@ export default function (ast: BabelNodeDoWhileStatement, strictCode: boolean, en
|
||||
invariant(stmt instanceof AbruptCompletion);
|
||||
// ECMA262 13.1.7
|
||||
if (stmt instanceof BreakCompletion) {
|
||||
if (!stmt.target)
|
||||
return (UpdateEmpty(realm, stmt, V): any).value;
|
||||
if (!stmt.target) return (UpdateEmpty(realm, stmt, V): any).value;
|
||||
}
|
||||
throw UpdateEmpty(realm, stmt, V);
|
||||
}
|
||||
|
@ -15,6 +15,11 @@ import type { Value } from "../values/index.js";
|
||||
import type { Reference } from "../environment.js";
|
||||
import type { BabelNodeEmptyStatement } from "babel-types";
|
||||
|
||||
export default function (ast: BabelNodeEmptyStatement, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeEmptyStatement,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
return realm.intrinsics.empty;
|
||||
}
|
||||
|
@ -16,7 +16,12 @@ import type { Reference } from "../environment.js";
|
||||
import { GetValue } from "../methods/index.js";
|
||||
import type { BabelNodeExpressionStatement } from "babel-types";
|
||||
|
||||
export default function (ast: BabelNodeExpressionStatement, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeExpressionStatement,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
// ECMA262 13.5.1
|
||||
// 1. Let exprRef be the result of evaluating Expression.
|
||||
let exprRef = env.evaluate(ast.expression, strictCode);
|
||||
|
@ -15,6 +15,11 @@ import type { Value } from "../values/index.js";
|
||||
import type { Reference } from "../environment.js";
|
||||
import type { BabelNodeFile } from "babel-types";
|
||||
|
||||
export default function (ast: BabelNodeFile, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeFile,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
return env.evaluate(ast.program, strictCode);
|
||||
}
|
||||
|
@ -16,18 +16,34 @@ import { TypesDomain, ValuesDomain } from "../domains/index.js";
|
||||
import { DeclarativeEnvironmentRecord } from "../environment.js";
|
||||
import { ForInOfHeadEvaluation, ForInOfBodyEvaluation } from "./ForOfStatement.js";
|
||||
import { BoundNames, EnumerableOwnProperties, NewDeclarativeEnvironment, UpdateEmpty } from "../methods/index.js";
|
||||
import { AbstractValue, AbstractObjectValue, ArrayValue, ObjectValue, StringValue, SymbolValue, UndefinedValue, Value } from "../values/index.js";
|
||||
import {
|
||||
AbstractValue,
|
||||
AbstractObjectValue,
|
||||
ArrayValue,
|
||||
ObjectValue,
|
||||
StringValue,
|
||||
SymbolValue,
|
||||
UndefinedValue,
|
||||
Value,
|
||||
} from "../values/index.js";
|
||||
import type { BabelNodeForInStatement, BabelNodeStatement, BabelNodeVariableDeclaration } from "babel-types";
|
||||
import invariant from "../invariant.js";
|
||||
import * as t from "babel-types";
|
||||
|
||||
// ECMA262 13.7.5.11
|
||||
export default function (ast: BabelNodeForInStatement, strictCode: boolean, env: LexicalEnvironment, realm: Realm, labelSet: ?Array<string>): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeForInStatement,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm,
|
||||
labelSet: ?Array<string>
|
||||
): Value | Reference {
|
||||
let { left, right, body } = ast;
|
||||
|
||||
try {
|
||||
if (left.type === "VariableDeclaration") {
|
||||
if (left.kind === "var") { // for (var ForBinding in Expression) Statement
|
||||
if (left.kind === "var") {
|
||||
// for (var ForBinding in Expression) Statement
|
||||
// 1. Let keyResult be ? ForIn/OfHeadEvaluation(« », Expression, enumerate).
|
||||
let keyResult = ForInOfHeadEvaluation(realm, env, [], right, "enumerate", strictCode);
|
||||
|
||||
@ -36,8 +52,18 @@ export default function (ast: BabelNodeForInStatement, strictCode: boolean, env:
|
||||
}
|
||||
|
||||
// 2. Return ? ForIn/OfBodyEvaluation(ForBinding, Statement, keyResult, varBinding, labelSet).
|
||||
return ForInOfBodyEvaluation(realm, env, left.declarations[0].id, body, keyResult, "varBinding", labelSet, strictCode);
|
||||
} else { // for (ForDeclaration in Expression) Statement
|
||||
return ForInOfBodyEvaluation(
|
||||
realm,
|
||||
env,
|
||||
left.declarations[0].id,
|
||||
body,
|
||||
keyResult,
|
||||
"varBinding",
|
||||
labelSet,
|
||||
strictCode
|
||||
);
|
||||
} else {
|
||||
// for (ForDeclaration in Expression) Statement
|
||||
// 1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(BoundNames of ForDeclaration, Expression, enumerate).
|
||||
let keyResult = ForInOfHeadEvaluation(realm, env, BoundNames(realm, left), right, "enumerate", strictCode);
|
||||
keyResult = keyResult.throwIfNotConcreteObject();
|
||||
@ -45,7 +71,8 @@ export default function (ast: BabelNodeForInStatement, strictCode: boolean, env:
|
||||
// 2. Return ? ForIn/OfBodyEvaluation(ForDeclaration, Statement, keyResult, lexicalBinding, labelSet).
|
||||
return ForInOfBodyEvaluation(realm, env, left, body, keyResult, "lexicalBinding", labelSet, strictCode);
|
||||
}
|
||||
} else { // for (LeftHandSideExpression in Expression) Statement
|
||||
} else {
|
||||
// for (LeftHandSideExpression in Expression) Statement
|
||||
// 1. Let keyResult be ? ForIn/OfHeadEvaluation(« », Expression, enumerate).
|
||||
let keyResult = ForInOfHeadEvaluation(realm, env, [], right, "enumerate", strictCode);
|
||||
keyResult = keyResult.throwIfNotConcreteObject();
|
||||
@ -55,15 +82,21 @@ export default function (ast: BabelNodeForInStatement, strictCode: boolean, env:
|
||||
}
|
||||
} catch (e) {
|
||||
if (e instanceof BreakCompletion) {
|
||||
if (!e.target)
|
||||
return (UpdateEmpty(realm, e, realm.intrinsics.undefined): any).value;
|
||||
if (!e.target) return (UpdateEmpty(realm, e, realm.intrinsics.undefined): any).value;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
function emitResidualLoopIfSafe(ast: BabelNodeForInStatement, strictCode: boolean, env: LexicalEnvironment, realm: Realm,
|
||||
lh: BabelNodeVariableDeclaration, ob: AbstractObjectValue, body: BabelNodeStatement) {
|
||||
function emitResidualLoopIfSafe(
|
||||
ast: BabelNodeForInStatement,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm,
|
||||
lh: BabelNodeVariableDeclaration,
|
||||
ob: AbstractObjectValue,
|
||||
body: BabelNodeStatement
|
||||
) {
|
||||
let oldEnv = realm.getRunningContext().lexicalEnvironment;
|
||||
let blockEnv = NewDeclarativeEnvironment(realm, oldEnv);
|
||||
realm.getRunningContext().lexicalEnvironment = blockEnv;
|
||||
@ -71,7 +104,11 @@ function emitResidualLoopIfSafe(ast: BabelNodeForInStatement, strictCode: boolea
|
||||
let envRec = blockEnv.environmentRecord;
|
||||
invariant(envRec instanceof DeclarativeEnvironmentRecord, "expected declarative environment record");
|
||||
let absStr = realm.createAbstract(
|
||||
new TypesDomain(StringValue), ValuesDomain.topVal, [], t.stringLiteral("never used"));
|
||||
new TypesDomain(StringValue),
|
||||
ValuesDomain.topVal,
|
||||
[],
|
||||
t.stringLiteral("never used")
|
||||
);
|
||||
let boundName;
|
||||
for (let n of BoundNames(realm, lh)) {
|
||||
invariant(boundName === undefined);
|
||||
@ -79,10 +116,8 @@ function emitResidualLoopIfSafe(ast: BabelNodeForInStatement, strictCode: boolea
|
||||
envRec.CreateMutableBinding(n, false);
|
||||
envRec.InitializeBinding(n, absStr);
|
||||
}
|
||||
let [compl, gen, bindings, properties, createdObj] =
|
||||
realm.evaluateNodeForEffects(body, strictCode, blockEnv);
|
||||
if (compl instanceof Value && gen.body.length === 0 && bindings.size === 0 &&
|
||||
properties.size === 1) {
|
||||
let [compl, gen, bindings, properties, createdObj] = realm.evaluateNodeForEffects(body, strictCode, blockEnv);
|
||||
if (compl instanceof Value && gen.body.length === 0 && bindings.size === 0 && properties.size === 1) {
|
||||
invariant(createdObj.size === 0); // or there will be more than one property
|
||||
let targetObject;
|
||||
let sourceObject;
|
||||
@ -101,7 +136,11 @@ function emitResidualLoopIfSafe(ast: BabelNodeForInStatement, strictCode: boolea
|
||||
// an expression of the form sourceObject[absStr].
|
||||
let mem = sourceValue.args[1];
|
||||
while (mem instanceof AbstractValue) {
|
||||
if (mem.kind === "sentinel member expression" && mem.args[0] instanceof ObjectValue && mem.args[1] === absStr) {
|
||||
if (
|
||||
mem.kind === "sentinel member expression" &&
|
||||
mem.args[0] instanceof ObjectValue &&
|
||||
mem.args[1] === absStr
|
||||
) {
|
||||
sourceObject = mem.args[0];
|
||||
break;
|
||||
}
|
||||
@ -123,11 +162,15 @@ function emitResidualLoopIfSafe(ast: BabelNodeForInStatement, strictCode: boolea
|
||||
if (targetObject instanceof ObjectValue && sourceObject !== undefined) {
|
||||
let oe = ob.values.getElements();
|
||||
if (oe.size !== 1) ob.throwIfNotConcreteObject();
|
||||
let o; for (let co of oe) o = co; invariant(o !== undefined);
|
||||
let generator = realm.generator; invariant(generator !== undefined);
|
||||
let o;
|
||||
for (let co of oe) o = co;
|
||||
invariant(o !== undefined);
|
||||
let generator = realm.generator;
|
||||
invariant(generator !== undefined);
|
||||
// make target object simple and partial, so that it returns a fully
|
||||
// abstract value for every property it is queried for.
|
||||
targetObject.makeSimple(); targetObject.makePartial();
|
||||
targetObject.makeSimple();
|
||||
targetObject.makePartial();
|
||||
if (sourceObject === o && sourceObject.isSimple()) {
|
||||
// Known enumerable properties of sourceObject can become known
|
||||
// properties of targetObject.
|
||||
@ -150,10 +193,19 @@ function emitResidualLoopIfSafe(ast: BabelNodeForInStatement, strictCode: boolea
|
||||
args: [o, targetObject, sourceObject, targetObject, sourceObject],
|
||||
buildNode: ([obj, tgt, src, obj1, tgt1, src1]) => {
|
||||
invariant(boundName !== undefined);
|
||||
return t.forInStatement(lh, obj,
|
||||
t.blockStatement([t.expressionStatement(t.assignmentExpression("=",
|
||||
t.memberExpression(tgt, boundName, true),
|
||||
t.memberExpression(src, boundName, true)))]));
|
||||
return t.forInStatement(
|
||||
lh,
|
||||
obj,
|
||||
t.blockStatement([
|
||||
t.expressionStatement(
|
||||
t.assignmentExpression(
|
||||
"=",
|
||||
t.memberExpression(tgt, boundName, true),
|
||||
t.memberExpression(src, boundName, true)
|
||||
)
|
||||
),
|
||||
])
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -33,9 +33,15 @@ import {
|
||||
DestructuringAssignmentEvaluation,
|
||||
GetIterator,
|
||||
IsDestructuring,
|
||||
HasSomeCompatibleType
|
||||
HasSomeCompatibleType,
|
||||
} from "../methods/index.js";
|
||||
import type { BabelNodeForOfStatement, BabelNodeVariableDeclaration, BabelNodeLVal, BabelNode, BabelNodeStatement } from "babel-types";
|
||||
import type {
|
||||
BabelNodeForOfStatement,
|
||||
BabelNodeVariableDeclaration,
|
||||
BabelNodeLVal,
|
||||
BabelNode,
|
||||
BabelNodeStatement,
|
||||
} from "babel-types";
|
||||
|
||||
export type IterationKind = "iterate" | "enumerate";
|
||||
export type LhsKind = "lexicalBinding" | "varBinding" | "assignment";
|
||||
@ -50,7 +56,11 @@ export function InternalGetResultValue(realm: Realm, result: Reference | Value |
|
||||
}
|
||||
|
||||
// ECMA262 13.7.1.2
|
||||
export function LoopContinues(realm: Realm, completion: Reference | Value | AbruptCompletion, labelSet: ?Array<string>): boolean {
|
||||
export function LoopContinues(
|
||||
realm: Realm,
|
||||
completion: Reference | Value | AbruptCompletion,
|
||||
labelSet: ?Array<string>
|
||||
): boolean {
|
||||
// 1. If completion.[[Type]] is normal, return true.
|
||||
if (completion instanceof Value || completion instanceof Reference) return true;
|
||||
invariant(completion instanceof AbruptCompletion);
|
||||
@ -80,13 +90,13 @@ function BindingInstantiation(realm: Realm, ast: BabelNodeVariableDeclaration, e
|
||||
|
||||
// 3. For each element name of the BoundNames of ForBinding do
|
||||
for (let decl of ast.declarations) {
|
||||
if (decl.id.type !== "Identifier")
|
||||
throw new Error("TODO: Patterns aren't supported yet");
|
||||
if (decl.id.type !== "Identifier") throw new Error("TODO: Patterns aren't supported yet");
|
||||
// a. If IsConstantDeclaration of LetOrConst is true, then
|
||||
if (ast.kind === "const") {
|
||||
// i. Perform ! envRec.CreateImmutableBinding(name, true).
|
||||
envRec.CreateImmutableBinding(decl.id.name, true);
|
||||
} else { // b.
|
||||
} else {
|
||||
// b.
|
||||
// i. Perform ! envRec.CreateMutableBinding(name, false).
|
||||
envRec.CreateMutableBinding(decl.id.name, false);
|
||||
}
|
||||
@ -94,7 +104,14 @@ function BindingInstantiation(realm: Realm, ast: BabelNodeVariableDeclaration, e
|
||||
}
|
||||
|
||||
// ECMA262 13.7.5.12
|
||||
export function ForInOfHeadEvaluation(realm: Realm, env: LexicalEnvironment, TDZnames: Array<string>, expr: BabelNode, iterationKind: IterationKind, strictCode: boolean) {
|
||||
export function ForInOfHeadEvaluation(
|
||||
realm: Realm,
|
||||
env: LexicalEnvironment,
|
||||
TDZnames: Array<string>,
|
||||
expr: BabelNode,
|
||||
iterationKind: IterationKind,
|
||||
strictCode: boolean
|
||||
) {
|
||||
// 1. Let oldEnv be the running execution context's LexicalEnvironment.
|
||||
let oldEnv = realm.getRunningContext().lexicalEnvironment;
|
||||
|
||||
@ -156,7 +173,8 @@ export function ForInOfHeadEvaluation(realm: Realm, env: LexicalEnvironment, TDZ
|
||||
} else {
|
||||
return EnumerateObjectProperties(realm, obj);
|
||||
}
|
||||
} else { // 8. Else,
|
||||
} else {
|
||||
// 8. Else,
|
||||
// 1. Assert: iterationKind is iterate.
|
||||
invariant(iterationKind === "iterate", "expected iterationKind to be iterate");
|
||||
|
||||
@ -166,7 +184,16 @@ export function ForInOfHeadEvaluation(realm: Realm, env: LexicalEnvironment, TDZ
|
||||
}
|
||||
|
||||
// ECMA262 13.7.5.13
|
||||
export function ForInOfBodyEvaluation(realm: Realm, env: LexicalEnvironment, lhs: BabelNodeVariableDeclaration | BabelNodeLVal, stmt: BabelNodeStatement, iterator: ObjectValue, lhsKind: LhsKind, labelSet: ?Array<string>, strictCode: boolean) {
|
||||
export function ForInOfBodyEvaluation(
|
||||
realm: Realm,
|
||||
env: LexicalEnvironment,
|
||||
lhs: BabelNodeVariableDeclaration | BabelNodeLVal,
|
||||
stmt: BabelNodeStatement,
|
||||
iterator: ObjectValue,
|
||||
lhsKind: LhsKind,
|
||||
labelSet: ?Array<string>,
|
||||
strictCode: boolean
|
||||
) {
|
||||
// 1. Let oldEnv be the running execution context's LexicalEnvironment.
|
||||
let oldEnv = realm.getRunningContext().lexicalEnvironment;
|
||||
|
||||
@ -196,7 +223,7 @@ export function ForInOfBodyEvaluation(realm: Realm, env: LexicalEnvironment, lhs
|
||||
let nextValue = IteratorValue(realm, nextResult);
|
||||
|
||||
// d. If lhsKind is either assignment or varBinding, then
|
||||
let iterationEnv : void | LexicalEnvironment;
|
||||
let iterationEnv: void | LexicalEnvironment;
|
||||
let lhsRef;
|
||||
if (lhsKind === "assignment" || lhsKind === "varBinding") {
|
||||
// i. If destructuring is false, then
|
||||
@ -204,7 +231,8 @@ export function ForInOfBodyEvaluation(realm: Realm, env: LexicalEnvironment, lhs
|
||||
// 1. Let lhsRef be the result of evaluating lhs. (It may be evaluated repeatedly.)
|
||||
lhsRef = env.evaluateCompletion(lhs, strictCode);
|
||||
}
|
||||
} else { // e. Else,
|
||||
} else {
|
||||
// e. Else,
|
||||
// i. Assert: lhsKind is lexicalBinding.
|
||||
invariant(lhsKind === "lexicalBinding", "expected lhsKind to be lexicalBinding");
|
||||
invariant(lhs.type === "VariableDeclaration");
|
||||
@ -244,29 +272,34 @@ export function ForInOfBodyEvaluation(realm: Realm, env: LexicalEnvironment, lhs
|
||||
if (lhsRef instanceof AbruptCompletion) {
|
||||
// 1. Let status be lhsRef.
|
||||
status = lhsRef;
|
||||
} else if (lhsKind === "lexicalBinding") { // ii. Else if lhsKind is lexicalBinding, then
|
||||
} else if (lhsKind === "lexicalBinding") {
|
||||
// ii. Else if lhsKind is lexicalBinding, then
|
||||
// 1. Let status be InitializeReferencedBinding(lhsRef, nextValue).
|
||||
invariant(lhsRef instanceof Reference);
|
||||
status = InitializeReferencedBinding(realm, lhsRef, nextValue);
|
||||
} else { // iii. Else,
|
||||
} else {
|
||||
// iii. Else,
|
||||
// 1. Let status be PutValue(lhsRef, nextValue).
|
||||
invariant(lhsRef !== undefined);
|
||||
status = PutValue(realm, lhsRef, nextValue);
|
||||
}
|
||||
} else { // g. Else,
|
||||
} else {
|
||||
// g. Else,
|
||||
// i. If lhsKind is assignment, then
|
||||
if (lhsKind === "assignment") {
|
||||
invariant(lhs.type === "ArrayPattern" || lhs.type === "ObjectPattern");
|
||||
|
||||
// 1. Let status be the result of performing DestructuringAssignmentEvaluation of assignmentPattern using nextValue as the argument.
|
||||
status = DestructuringAssignmentEvaluation(realm, lhs, nextValue, strictCode, iterationEnv || env);
|
||||
} else if (lhsKind === "varBinding") { // ii. Else if lhsKind is varBinding, then
|
||||
} else if (lhsKind === "varBinding") {
|
||||
// ii. Else if lhsKind is varBinding, then
|
||||
// 1. Assert: lhs is a ForBinding.
|
||||
invariant(lhs.type !== "VariableDeclaration");
|
||||
|
||||
// 2. Let status be the result of performing BindingInitialization for lhs passing nextValue and undefined as the arguments.
|
||||
status = BindingInitialization(realm, lhs, nextValue, strictCode, undefined);
|
||||
} else { // iii. Else,
|
||||
} else {
|
||||
// iii. Else,
|
||||
// 1. Assert: lhsKind is lexicalBinding.
|
||||
invariant(lhsKind === "lexicalBinding");
|
||||
|
||||
@ -319,18 +352,35 @@ export function ForInOfBodyEvaluation(realm: Realm, env: LexicalEnvironment, lhs
|
||||
}
|
||||
|
||||
// ECMA262 13.7.5.11
|
||||
export default function (ast: BabelNodeForOfStatement, strictCode: boolean, env: LexicalEnvironment, realm: Realm, labelSet: ?Array<string>): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeForOfStatement,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm,
|
||||
labelSet: ?Array<string>
|
||||
): Value | Reference {
|
||||
let { left, right, body } = ast;
|
||||
|
||||
if (left.type === "VariableDeclaration") {
|
||||
if (left.kind === "var") { // for (var ForBinding o fAssignmentExpression) Statement
|
||||
if (left.kind === "var") {
|
||||
// for (var ForBinding o fAssignmentExpression) Statement
|
||||
// 1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« », AssignmentExpression, iterate).
|
||||
let keyResult = ForInOfHeadEvaluation(realm, env, [], right, "iterate", strictCode);
|
||||
keyResult = keyResult.throwIfNotConcreteObject();
|
||||
|
||||
// 2. Return ? ForIn/OfBodyEvaluation(ForBinding, Statement, keyResult, varBinding, labelSet).
|
||||
return ForInOfBodyEvaluation(realm, env, left.declarations[0].id, body, keyResult, "varBinding", labelSet, strictCode);
|
||||
} else { // for (ForDeclaration of AssignmentExpression) Statement
|
||||
return ForInOfBodyEvaluation(
|
||||
realm,
|
||||
env,
|
||||
left.declarations[0].id,
|
||||
body,
|
||||
keyResult,
|
||||
"varBinding",
|
||||
labelSet,
|
||||
strictCode
|
||||
);
|
||||
} else {
|
||||
// for (ForDeclaration of AssignmentExpression) Statement
|
||||
// 1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(BoundNames of ForDeclaration, AssignmentExpression, iterate).
|
||||
let keyResult = ForInOfHeadEvaluation(realm, env, BoundNames(realm, left), right, "iterate", strictCode);
|
||||
keyResult = keyResult.throwIfNotConcreteObject();
|
||||
@ -338,7 +388,8 @@ export default function (ast: BabelNodeForOfStatement, strictCode: boolean, env:
|
||||
// 2. Return ? ForIn/OfBodyEvaluation(ForDeclaration, Statement, keyResult, lexicalBinding, labelSet).
|
||||
return ForInOfBodyEvaluation(realm, env, left, body, keyResult, "lexicalBinding", labelSet, strictCode);
|
||||
}
|
||||
} else { // for (LeftHandSideExpression of AssignmentExpression) Statement
|
||||
} else {
|
||||
// for (LeftHandSideExpression of AssignmentExpression) Statement
|
||||
// 1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« », AssignmentExpression, iterate).
|
||||
let keyResult = ForInOfHeadEvaluation(realm, env, [], right, "iterate", strictCode);
|
||||
keyResult = keyResult.throwIfNotConcreteObject();
|
||||
|
@ -51,7 +51,15 @@ export function CreatePerIterationEnvironment(realm: Realm, perIterationBindings
|
||||
}
|
||||
|
||||
// ECMA262 13.7.4.8
|
||||
function ForBodyEvaluation(realm: Realm, test, increment, stmt, perIterationBindings: Array<string>, labelSet, strictCode: boolean): Value {
|
||||
function ForBodyEvaluation(
|
||||
realm: Realm,
|
||||
test,
|
||||
increment,
|
||||
stmt,
|
||||
perIterationBindings: Array<string>,
|
||||
labelSet,
|
||||
strictCode: boolean
|
||||
): Value {
|
||||
// 1. Let V be undefined.
|
||||
let V: Value = realm.intrinsics.undefined;
|
||||
|
||||
@ -81,8 +89,7 @@ function ForBodyEvaluation(realm: Realm, test, increment, stmt, perIterationBind
|
||||
invariant(result instanceof AbruptCompletion);
|
||||
// ECMA262 13.1.7
|
||||
if (result instanceof BreakCompletion) {
|
||||
if (!result.target)
|
||||
return (UpdateEmpty(realm, result, V): any).value;
|
||||
if (!result.target) return (UpdateEmpty(realm, result, V): any).value;
|
||||
}
|
||||
throw UpdateEmpty(realm, result, V);
|
||||
}
|
||||
@ -109,11 +116,18 @@ function ForBodyEvaluation(realm: Realm, test, increment, stmt, perIterationBind
|
||||
}
|
||||
|
||||
// ECMA262 13.7.4.7
|
||||
export default function (ast: BabelNodeForStatement, strictCode: boolean, env: LexicalEnvironment, realm: Realm, labelSet: ?Array<string>): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeForStatement,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm,
|
||||
labelSet: ?Array<string>
|
||||
): Value | Reference {
|
||||
let { init, test, update, body } = ast;
|
||||
|
||||
if (init && init.type === "VariableDeclaration") {
|
||||
if (init.kind === "var") { // for (var VariableDeclarationList; Expression; Expression) Statement
|
||||
if (init.kind === "var") {
|
||||
// for (var VariableDeclarationList; Expression; Expression) Statement
|
||||
// 1. Let varDcl be the result of evaluating VariableDeclarationList.
|
||||
let varDcl = env.evaluate(init, strictCode);
|
||||
|
||||
@ -122,7 +136,8 @@ export default function (ast: BabelNodeForStatement, strictCode: boolean, env: L
|
||||
|
||||
// 3. Return ? ForBodyEvaluation(the first Expression, the second Expression, Statement, « », labelSet).
|
||||
return ForBodyEvaluation(realm, test, update, body, [], labelSet, strictCode);
|
||||
} else { // for (LexicalDeclaration Expression; Expression) Statement
|
||||
} else {
|
||||
// for (LexicalDeclaration Expression; Expression) Statement
|
||||
// 1. Let oldEnv be the running execution context's LexicalEnvironment.
|
||||
let oldEnv = env;
|
||||
|
||||
@ -144,7 +159,8 @@ export default function (ast: BabelNodeForStatement, strictCode: boolean, env: L
|
||||
if (isConst) {
|
||||
// i. Perform ! loopEnvRec.CreateImmutableBinding(dn, true).
|
||||
loopEnvRec.CreateImmutableBinding(dn, true);
|
||||
} else { // b. Else,
|
||||
} else {
|
||||
// b. Else,
|
||||
// i. Perform ! loopEnvRec.CreateMutableBinding(dn, false).
|
||||
loopEnvRec.CreateMutableBinding(dn, false);
|
||||
}
|
||||
@ -179,7 +195,8 @@ export default function (ast: BabelNodeForStatement, strictCode: boolean, env: L
|
||||
// 13. Return Completion(bodyResult).
|
||||
return bodyResult;
|
||||
}
|
||||
} else { // for (Expression; Expression; Expression) Statement
|
||||
} else {
|
||||
// for (Expression; Expression; Expression) Statement
|
||||
// 1. If the first Expression is present, then
|
||||
if (init) {
|
||||
// a. Let exprRef be the result of evaluating the first Expression.
|
||||
|
@ -22,7 +22,12 @@ import IsStrict from "../utils/strict.js";
|
||||
import type { BabelNodeFunctionDeclaration } from "babel-types";
|
||||
|
||||
// ECMA262 14.1.20
|
||||
export default function (ast: BabelNodeFunctionDeclaration, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeFunctionDeclaration,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
if (ast.generator) {
|
||||
// 1. If the function code for GeneratorDeclaration is strict mode code, let strict be true. Otherwise let strict be false.
|
||||
let strict = strictCode || IsStrict(ast.body);
|
||||
@ -45,7 +50,7 @@ export default function (ast: BabelNodeFunctionDeclaration, strictCode: boolean,
|
||||
DefinePropertyOrThrow(realm, F, "prototype", {
|
||||
value: prototype,
|
||||
writable: true,
|
||||
configurable: false
|
||||
configurable: false,
|
||||
});
|
||||
|
||||
// 6. Perform SetFunctionName(F, name).
|
||||
|
@ -13,7 +13,7 @@ import type { Realm } from "../realm.js";
|
||||
import type { LexicalEnvironment } from "../environment.js";
|
||||
import type { Value } from "../values/index.js";
|
||||
import type { Reference } from "../environment.js";
|
||||
import { NewDeclarativeEnvironment, SetFunctionName, FunctionCreate, MakeConstructor } from "../methods/index.js";
|
||||
import { NewDeclarativeEnvironment, SetFunctionName, FunctionCreate, MakeConstructor } from "../methods/index.js";
|
||||
import { ObjectCreate } from "../methods/create.js";
|
||||
import { GeneratorFunctionCreate } from "../methods/function.js";
|
||||
import { DefinePropertyOrThrow } from "../methods/properties.js";
|
||||
@ -22,7 +22,12 @@ import IsStrict from "../utils/strict.js";
|
||||
import type { BabelNodeFunctionExpression } from "babel-types";
|
||||
import invariant from "../invariant.js";
|
||||
|
||||
export default function (ast: BabelNodeFunctionExpression, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeFunctionExpression,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
// ECMA262 14.1.21
|
||||
|
||||
if (ast.id) {
|
||||
@ -59,7 +64,7 @@ export default function (ast: BabelNodeFunctionExpression, strictCode: boolean,
|
||||
value: prototype,
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: false
|
||||
configurable: false,
|
||||
});
|
||||
|
||||
// 10. Perform SetFunctionName(closure, name).
|
||||
@ -126,7 +131,7 @@ export default function (ast: BabelNodeFunctionExpression, strictCode: boolean,
|
||||
value: prototype,
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: false
|
||||
configurable: false,
|
||||
});
|
||||
|
||||
// 6. Return closure.
|
||||
|
@ -17,7 +17,12 @@ import { ResolveBinding } from "../methods/index.js";
|
||||
import type { BabelNodeIdentifier } from "babel-types";
|
||||
|
||||
// ECMA262 12.1.6
|
||||
export default function (ast: BabelNodeIdentifier, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeIdentifier,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
// 1. Return ? ResolveBinding(StringValue of Identifier).
|
||||
return ResolveBinding(realm, ast.name, strictCode, env);
|
||||
}
|
||||
|
@ -19,9 +19,12 @@ import { GetValue, joinEffects, ToBoolean, UpdateEmpty } from "../methods/index.
|
||||
import type { BabelNode, BabelNodeIfStatement } from "babel-types";
|
||||
import invariant from "../invariant.js";
|
||||
|
||||
export function evaluate (
|
||||
ast: BabelNodeIfStatement, strictCode: boolean, env: LexicalEnvironment,
|
||||
realm: Realm): Completion | Value | Reference {
|
||||
export function evaluate(
|
||||
ast: BabelNodeIfStatement,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Completion | Value | Reference {
|
||||
// 1. Let exprRef be the result of evaluating Expression
|
||||
let exprRef = env.evaluate(ast.test, strictCode);
|
||||
// 2. Let exprValue be ToBoolean(? GetValue(exprRef))
|
||||
@ -41,8 +44,7 @@ export function evaluate (
|
||||
stmtCompletion = realm.intrinsics.undefined;
|
||||
}
|
||||
// 5. Return Completion(UpdateEmpty(stmtCompletion, undefined)
|
||||
if (stmtCompletion instanceof Reference)
|
||||
return stmtCompletion;
|
||||
if (stmtCompletion instanceof Reference) return stmtCompletion;
|
||||
stmtCompletion = UpdateEmpty(realm, stmtCompletion, realm.intrinsics.undefined);
|
||||
if (stmtCompletion instanceof AbruptCompletion) {
|
||||
throw stmtCompletion;
|
||||
@ -58,24 +60,29 @@ export function evaluate (
|
||||
}
|
||||
}
|
||||
|
||||
export function evaluateWithAbstractConditional(condValue: AbstractValue,
|
||||
consequent: BabelNode, alternate: ?BabelNode, strictCode: boolean,
|
||||
env: LexicalEnvironment, realm: Realm): NormalCompletion | Value | Reference {
|
||||
export function evaluateWithAbstractConditional(
|
||||
condValue: AbstractValue,
|
||||
consequent: BabelNode,
|
||||
alternate: ?BabelNode,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): NormalCompletion | Value | Reference {
|
||||
// Evaluate consequent and alternate in sandboxes and get their effects.
|
||||
let [compl1, gen1, bindings1, properties1, createdObj1] =
|
||||
realm.evaluateNodeForEffects(consequent, strictCode, env);
|
||||
let [compl1, gen1, bindings1, properties1, createdObj1] = realm.evaluateNodeForEffects(consequent, strictCode, env);
|
||||
|
||||
let [compl2, gen2, bindings2, properties2, createdObj2] =
|
||||
alternate ?
|
||||
realm.evaluateNodeForEffects(alternate, strictCode, env) :
|
||||
construct_empty_effects(realm);
|
||||
let [compl2, gen2, bindings2, properties2, createdObj2] = alternate
|
||||
? realm.evaluateNodeForEffects(alternate, strictCode, env)
|
||||
: construct_empty_effects(realm);
|
||||
|
||||
// Join the effects, creating an abstract view of what happened, regardless
|
||||
// of the actual value of condValue.
|
||||
let joinedEffects =
|
||||
joinEffects(realm, condValue,
|
||||
[compl1, gen1, bindings1, properties1, createdObj1],
|
||||
[compl2, gen2, bindings2, properties2, createdObj2]);
|
||||
let joinedEffects = joinEffects(
|
||||
realm,
|
||||
condValue,
|
||||
[compl1, gen1, bindings1, properties1, createdObj1],
|
||||
[compl2, gen2, bindings2, properties2, createdObj2]
|
||||
);
|
||||
let completion = joinedEffects[0];
|
||||
if (completion instanceof NormalCompletion) {
|
||||
// in this case one of the branches may complete abruptly, which means that
|
||||
|
@ -17,10 +17,16 @@ import { BreakCompletion } from "../completions.js";
|
||||
import type { BabelNodeLabeledStatement, BabelNode } from "babel-types";
|
||||
|
||||
// ECMA262 13.13.14
|
||||
function LabelledEvaluation(labelSet: Array<string>, ast: BabelNode, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
function LabelledEvaluation(
|
||||
labelSet: Array<string>,
|
||||
ast: BabelNode,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
// LabelledStatement:LabelIdentifier:LabelledItem
|
||||
switch (ast.type) {
|
||||
case 'LabeledStatement':
|
||||
case "LabeledStatement":
|
||||
let labeledAst = ((ast: any): BabelNodeLabeledStatement);
|
||||
// 1. Let label be the StringValue of LabelIdentifier.
|
||||
let label = labeledAst.label.name;
|
||||
@ -45,15 +51,14 @@ function LabelledEvaluation(labelSet: Array<string>, ast: BabelNode, strictCode:
|
||||
// 5. Return Completion(stmtResult).
|
||||
return normalCompletionStmtResult;
|
||||
|
||||
case 'VariableDeclaration':
|
||||
if (ast.kind === 'var') {
|
||||
case "VariableDeclaration":
|
||||
if (ast.kind === "var") {
|
||||
return env.evaluate(ast, strictCode);
|
||||
}
|
||||
// fall through to throw
|
||||
case 'FunctionDeclaration':
|
||||
case 'ClassDeclaration':
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.SyntaxError,
|
||||
ast.type + " may not have a label");
|
||||
// fall through to throw
|
||||
case "FunctionDeclaration":
|
||||
case "ClassDeclaration":
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.SyntaxError, ast.type + " may not have a label");
|
||||
|
||||
default:
|
||||
return env.evaluate(ast, strictCode, labelSet);
|
||||
@ -61,7 +66,12 @@ function LabelledEvaluation(labelSet: Array<string>, ast: BabelNode, strictCode:
|
||||
}
|
||||
|
||||
// ECMA262 13.13.15
|
||||
export default function (ast: BabelNodeLabeledStatement, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeLabeledStatement,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
//1. Let newLabelSet be a new empty List.
|
||||
let newLabelSet = [];
|
||||
|
||||
|
@ -19,8 +19,12 @@ import { GetValue, joinEffects, ToBoolean } from "../methods/index.js";
|
||||
import type { BabelNodeLogicalExpression } from "babel-types";
|
||||
import invariant from "../invariant.js";
|
||||
|
||||
export default function (ast: BabelNodeLogicalExpression, strictCode: boolean,
|
||||
env: LexicalEnvironment, realm: Realm): Completion | Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeLogicalExpression,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Completion | Value | Reference {
|
||||
let lref = env.evaluate(ast.left, strictCode);
|
||||
let lval = GetValue(realm, lref);
|
||||
|
||||
@ -41,21 +45,18 @@ export default function (ast: BabelNodeLogicalExpression, strictCode: boolean,
|
||||
invariant(lval instanceof AbstractValue);
|
||||
|
||||
if (!lval.mightNotBeObject()) {
|
||||
if (ast.operator === "&&")
|
||||
return env.evaluate(ast.right, strictCode);
|
||||
if (ast.operator === "&&") return env.evaluate(ast.right, strictCode);
|
||||
else {
|
||||
return lval;
|
||||
}
|
||||
}
|
||||
|
||||
// Create empty effects for the case where ast.right is not evaluated
|
||||
let [compl1, gen1, bindings1, properties1, createdObj1] =
|
||||
construct_empty_effects(realm);
|
||||
let [compl1, gen1, bindings1, properties1, createdObj1] = construct_empty_effects(realm);
|
||||
compl1; // ignore
|
||||
|
||||
// Evaluate ast.right in a sandbox to get its effects
|
||||
let [compl2, gen2, bindings2, properties2, createdObj2] =
|
||||
realm.evaluateNodeForEffects(ast.right, strictCode, env);
|
||||
let [compl2, gen2, bindings2, properties2, createdObj2] = realm.evaluateNodeForEffects(ast.right, strictCode, env);
|
||||
|
||||
// Join the effects, creating an abstract view of what happened, regardless
|
||||
// of the actual value of lval.
|
||||
@ -63,13 +64,19 @@ export default function (ast: BabelNodeLogicalExpression, strictCode: boolean,
|
||||
// use lval as is for the join condition.
|
||||
let joinedEffects;
|
||||
if (ast.operator === "&&") {
|
||||
joinedEffects = joinEffects(realm, lval,
|
||||
joinedEffects = joinEffects(
|
||||
realm,
|
||||
lval,
|
||||
[compl2, gen2, bindings2, properties2, createdObj2],
|
||||
[lval, gen1, bindings1, properties1, createdObj1]);
|
||||
[lval, gen1, bindings1, properties1, createdObj1]
|
||||
);
|
||||
} else {
|
||||
joinedEffects = joinEffects(realm, lval,
|
||||
joinedEffects = joinEffects(
|
||||
realm,
|
||||
lval,
|
||||
[lval, gen1, bindings1, properties1, createdObj1],
|
||||
[compl2, gen2, bindings2, properties2, createdObj2]);
|
||||
[compl2, gen2, bindings2, properties2, createdObj2]
|
||||
);
|
||||
}
|
||||
let completion = joinedEffects[0];
|
||||
if (completion instanceof NormalCompletion) {
|
||||
|
@ -16,11 +16,16 @@ import { Reference } from "../environment.js";
|
||||
import { StringValue } from "../values/index.js";
|
||||
import { GetValue, ToPropertyKeyPartial, RequireObjectCoercible } from "../methods/index.js";
|
||||
import type { BabelNodeMemberExpression } from "babel-types";
|
||||
import SuperProperty from './SuperProperty';
|
||||
import SuperProperty from "./SuperProperty";
|
||||
|
||||
// ECMA262 12.3.2.1
|
||||
export default function (ast: BabelNodeMemberExpression, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
if (ast.object.type === 'Super') {
|
||||
export default function(
|
||||
ast: BabelNodeMemberExpression,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
if (ast.object.type === "Super") {
|
||||
return SuperProperty(ast, strictCode, env, realm);
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,11 @@ import { GetNewTarget } from "../methods/get.js";
|
||||
import type { BabelNodeMetaProperty } from "babel-types";
|
||||
|
||||
// ECMA 12.3.8.1
|
||||
export default function (ast: BabelNodeMetaProperty, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
return GetNewTarget(realm);
|
||||
export default function(
|
||||
ast: BabelNodeMetaProperty,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
return GetNewTarget(realm);
|
||||
}
|
||||
|
@ -19,7 +19,12 @@ import { Construct } from "../methods/index.js";
|
||||
import invariant from "../invariant.js";
|
||||
import type { BabelNodeNewExpression } from "babel-types";
|
||||
|
||||
export default function (ast: BabelNodeNewExpression, strictCode: boolean, env: LexicalEnvironment, realm: Realm): ObjectValue {
|
||||
export default function(
|
||||
ast: BabelNodeNewExpression,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): ObjectValue {
|
||||
realm.setNextExecutionContextLocation(ast.loc);
|
||||
|
||||
// ECMA262 12.3.3.1 We just implement this method inline since it's only called here.
|
||||
@ -45,7 +50,8 @@ export default function (ast: BabelNodeNewExpression, strictCode: boolean, env:
|
||||
// 5. If arguments is empty, let argList be a new empty List.
|
||||
if (!args.length) {
|
||||
argsList = [];
|
||||
} else { // 6. Else,
|
||||
} else {
|
||||
// 6. Else,
|
||||
// a. Let argList be ArgumentListEvaluation of arguments.
|
||||
argsList = ArgumentListEvaluation(realm, strictCode, env, args);
|
||||
|
||||
|
@ -15,6 +15,11 @@ import type { Value } from "../values/index.js";
|
||||
import type { Reference } from "../environment.js";
|
||||
import type { BabelNodeNullLiteral } from "babel-types";
|
||||
|
||||
export default function (ast: BabelNodeNullLiteral, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeNullLiteral,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
return realm.intrinsics.null;
|
||||
}
|
||||
|
@ -16,6 +16,11 @@ import type { Reference } from "../environment.js";
|
||||
import { NumberValue } from "../values/index.js";
|
||||
import type { BabelNodeNumericLiteral } from "babel-types";
|
||||
|
||||
export default function (ast: BabelNodeNumericLiteral, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeNumericLiteral,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
return new NumberValue(realm, ast.value);
|
||||
}
|
||||
|
@ -25,19 +25,34 @@ import {
|
||||
HasOwnProperty,
|
||||
PropertyDefinitionEvaluation,
|
||||
ToPropertyKey,
|
||||
ToString
|
||||
ToString,
|
||||
} from "../methods/index.js";
|
||||
import invariant from "../invariant.js";
|
||||
import type { BabelNodeObjectExpression, BabelNodeObjectProperty, BabelNodeObjectMethod, BabelNodeClassMethod } from "babel-types";
|
||||
import type {
|
||||
BabelNodeObjectExpression,
|
||||
BabelNodeObjectProperty,
|
||||
BabelNodeObjectMethod,
|
||||
BabelNodeClassMethod,
|
||||
} from "babel-types";
|
||||
|
||||
// Returns the result of evaluating PropertyName.
|
||||
export function EvalPropertyNamePartial(prop: BabelNodeObjectProperty | BabelNodeObjectMethod | BabelNodeClassMethod, env: LexicalEnvironment, realm: Realm, strictCode: boolean): PropertyKeyValue {
|
||||
export function EvalPropertyNamePartial(
|
||||
prop: BabelNodeObjectProperty | BabelNodeObjectMethod | BabelNodeClassMethod,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm,
|
||||
strictCode: boolean
|
||||
): PropertyKeyValue {
|
||||
let result = EvalPropertyName(prop, env, realm, strictCode);
|
||||
if (result instanceof AbstractValue) result.throwIfNotConcrete();
|
||||
return (result: any);
|
||||
}
|
||||
|
||||
function EvalPropertyName(prop: BabelNodeObjectProperty | BabelNodeObjectMethod | BabelNodeClassMethod, env: LexicalEnvironment, realm: Realm, strictCode: boolean): AbstractValue | PropertyKeyValue {
|
||||
function EvalPropertyName(
|
||||
prop: BabelNodeObjectProperty | BabelNodeObjectMethod | BabelNodeClassMethod,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm,
|
||||
strictCode: boolean
|
||||
): AbstractValue | PropertyKeyValue {
|
||||
if (prop.computed) {
|
||||
let propertyKeyName = GetValue(realm, env.evaluate(prop.key, strictCode));
|
||||
if (propertyKeyName instanceof AbstractValue) return propertyKeyName;
|
||||
@ -55,7 +70,12 @@ function EvalPropertyName(prop: BabelNodeObjectProperty | BabelNodeObjectMethod
|
||||
}
|
||||
|
||||
// ECMA262 12.2.6.8
|
||||
export default function (ast: BabelNodeObjectExpression, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeObjectExpression,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
// 1. Let obj be ObjectCreate(%ObjectPrototype%).
|
||||
let obj = ObjectCreate(realm, realm.intrinsics.ObjectPrototype);
|
||||
|
||||
@ -91,9 +111,8 @@ export default function (ast: BabelNodeObjectExpression, strictCode: boolean, en
|
||||
// 7. Return CreateDataPropertyOrThrow(object, propKey, propValue).
|
||||
if (propKey instanceof AbstractValue) {
|
||||
if (propKey.mightNotBeString()) {
|
||||
let error = new CompilerDiagnostics(
|
||||
"property key value is unknown", prop.loc, 'PP0011', 'FatalError');
|
||||
if (realm.handleError(error) === 'Fail') throw new FatalError();
|
||||
let error = new CompilerDiagnostics("property key value is unknown", prop.loc, "PP0011", "FatalError");
|
||||
if (realm.handleError(error) === "Fail") throw new FatalError();
|
||||
continue; // recover by ignoring the property, which is only ever safe to do if the property is dead,
|
||||
// which is assuming a bit much, hence the designation as a FatalError.
|
||||
}
|
||||
|
@ -22,7 +22,12 @@ import traverse from "../traverse.js";
|
||||
import type { BabelNodeProgram } from "babel-types";
|
||||
|
||||
// ECMA262 15.1.11
|
||||
export function GlobalDeclarationInstantiation(realm: Realm, ast: BabelNodeProgram, env: LexicalEnvironment, strictCode: boolean) {
|
||||
export function GlobalDeclarationInstantiation(
|
||||
realm: Realm,
|
||||
ast: BabelNodeProgram,
|
||||
env: LexicalEnvironment,
|
||||
strictCode: boolean
|
||||
) {
|
||||
// 1. Let envRec be env's EnvironmentRecord.
|
||||
let envRec = env.environmentRecord;
|
||||
|
||||
@ -35,7 +40,7 @@ export function GlobalDeclarationInstantiation(realm: Realm, ast: BabelNodeProgr
|
||||
// 4. Let varNames be the VarDeclaredNames of script.
|
||||
let varNames = [];
|
||||
|
||||
traverse(ast, function (node) {
|
||||
traverse(ast, function(node) {
|
||||
if (node.type === "VariableDeclaration") {
|
||||
if (node.kind === "var") {
|
||||
varNames = varNames.concat(BoundNames(realm, node));
|
||||
@ -52,14 +57,15 @@ export function GlobalDeclarationInstantiation(realm: Realm, ast: BabelNodeProgr
|
||||
for (let name of lexNames) {
|
||||
// a. If envRec.HasVarDeclaration(name) is true, throw a SyntaxError exception.
|
||||
if (envRec.HasVarDeclaration(name)) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.SyntaxError,
|
||||
name + " already declared with var");
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.SyntaxError, name + " already declared with var");
|
||||
}
|
||||
|
||||
// b. If envRec.HasLexicalDeclaration(name) is true, throw a SyntaxError exception.
|
||||
if (envRec.HasLexicalDeclaration(name)) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.SyntaxError,
|
||||
name + " already declared with let or const");
|
||||
throw realm.createErrorThrowCompletion(
|
||||
realm.intrinsics.SyntaxError,
|
||||
name + " already declared with let or const"
|
||||
);
|
||||
}
|
||||
|
||||
// c. Let hasRestrictedGlobal be ? envRec.HasRestrictedGlobalProperty(name).
|
||||
@ -67,8 +73,7 @@ export function GlobalDeclarationInstantiation(realm: Realm, ast: BabelNodeProgr
|
||||
|
||||
// d. If hasRestrictedGlobal is true, throw a SyntaxError exception.
|
||||
if (hasRestrictedGlobal) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.SyntaxError,
|
||||
name + " global object is restricted");
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.SyntaxError, name + " global object is restricted");
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,8 +81,10 @@ export function GlobalDeclarationInstantiation(realm: Realm, ast: BabelNodeProgr
|
||||
for (let name of varNames) {
|
||||
// a. If envRec.HasLexicalDeclaration(name) is true, throw a SyntaxError exception.
|
||||
if (envRec.HasLexicalDeclaration(name)) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.SyntaxError,
|
||||
name + " already declared with let or const");
|
||||
throw realm.createErrorThrowCompletion(
|
||||
realm.intrinsics.SyntaxError,
|
||||
name + " already declared with let or const"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,8 +116,10 @@ export function GlobalDeclarationInstantiation(realm: Realm, ast: BabelNodeProgr
|
||||
|
||||
// 2. If fnDefinable is false, throw a TypeError exception.
|
||||
if (!fnDefinable) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError,
|
||||
fn + ": global function declarations are not allowed");
|
||||
throw realm.createErrorThrowCompletion(
|
||||
realm.intrinsics.TypeError,
|
||||
fn + ": global function declarations are not allowed"
|
||||
);
|
||||
}
|
||||
|
||||
// 3. Append fn to declaredFunctionNames.
|
||||
@ -138,8 +147,10 @@ export function GlobalDeclarationInstantiation(realm: Realm, ast: BabelNodeProgr
|
||||
|
||||
// 2. If vnDefinable is false, throw a TypeError exception.
|
||||
if (!vnDefinable) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError,
|
||||
vn + ": global variable declarations are not allowed");
|
||||
throw realm.createErrorThrowCompletion(
|
||||
realm.intrinsics.TypeError,
|
||||
vn + ": global variable declarations are not allowed"
|
||||
);
|
||||
}
|
||||
|
||||
// 3. If vn is not an element of declaredVarNames, then
|
||||
@ -174,7 +185,8 @@ export function GlobalDeclarationInstantiation(realm: Realm, ast: BabelNodeProgr
|
||||
if (d.kind === "const") {
|
||||
// 1. Perform ? envRec.CreateImmutableBinding(dn, true).
|
||||
envRec.CreateImmutableBinding(dn, true);
|
||||
} else { // ii. Else,
|
||||
} else {
|
||||
// ii. Else,
|
||||
// 1. Perform ? envRec.CreateMutableBinding(dn, false).
|
||||
envRec.CreateMutableBinding(dn, false);
|
||||
}
|
||||
@ -204,7 +216,12 @@ export function GlobalDeclarationInstantiation(realm: Realm, ast: BabelNodeProgr
|
||||
return realm.intrinsics.empty;
|
||||
}
|
||||
|
||||
export default function (ast: BabelNodeProgram, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeProgram,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
strictCode = IsStrict(ast);
|
||||
|
||||
GlobalDeclarationInstantiation(realm, ast, env, strictCode);
|
||||
|
@ -16,6 +16,15 @@ import { Value, StringValue } from "../values/index.js";
|
||||
import { RegExpCreate } from "../methods/index.js";
|
||||
import type { BabelNodeRegExpLiteral } from "babel-types";
|
||||
|
||||
export default function (ast: BabelNodeRegExpLiteral, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
return RegExpCreate(realm, new StringValue(realm, ast.pattern), ast.flags ? new StringValue(realm, ast.flags) : undefined);
|
||||
export default function(
|
||||
ast: BabelNodeRegExpLiteral,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
return RegExpCreate(
|
||||
realm,
|
||||
new StringValue(realm, ast.pattern),
|
||||
ast.flags ? new StringValue(realm, ast.flags) : undefined
|
||||
);
|
||||
}
|
||||
|
@ -17,7 +17,12 @@ import { GetValue } from "../methods/index.js";
|
||||
import { ReturnCompletion } from "../completions.js";
|
||||
import type { BabelNodeReturnStatement } from "babel-types";
|
||||
|
||||
export default function (ast: BabelNodeReturnStatement, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeReturnStatement,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
let arg;
|
||||
if (ast.argument) {
|
||||
arg = GetValue(realm, env.evaluate(ast.argument, strictCode));
|
||||
|
@ -17,7 +17,12 @@ import { GetValue } from "../methods/index.js";
|
||||
import type { BabelNodeSequenceExpression } from "babel-types";
|
||||
import invariant from "../invariant.js";
|
||||
|
||||
export default function (ast: BabelNodeSequenceExpression, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeSequenceExpression,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
invariant(ast.expressions.length > 0);
|
||||
let val;
|
||||
for (let node of ast.expressions) {
|
||||
|
@ -16,6 +16,11 @@ import type { Reference } from "../environment.js";
|
||||
import { StringValue } from "../values/index.js";
|
||||
import type { BabelNodeStringLiteral } from "babel-types";
|
||||
|
||||
export default function (ast: BabelNodeStringLiteral, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeStringLiteral,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
return new StringValue(realm, ast.value);
|
||||
}
|
||||
|
@ -11,11 +11,17 @@
|
||||
|
||||
import type { Realm } from "../realm.js";
|
||||
import type { LexicalEnvironment } from "../environment.js";
|
||||
import { FunctionEnvironmentRecord } from '../environment.js';
|
||||
import { FunctionEnvironmentRecord } from "../environment.js";
|
||||
import { Completion } from "../completions.js";
|
||||
import { Value, UndefinedValue, ObjectValue } from "../values/index.js";
|
||||
import { Reference } from "../environment.js";
|
||||
import { GetNewTarget, ArgumentListEvaluation, Construct, GetThisEnvironment, IsConstructor } from "../methods/index.js";
|
||||
import {
|
||||
GetNewTarget,
|
||||
ArgumentListEvaluation,
|
||||
Construct,
|
||||
GetThisEnvironment,
|
||||
IsConstructor,
|
||||
} from "../methods/index.js";
|
||||
import invariant from "../invariant.js";
|
||||
|
||||
function GetSuperConstructor(realm: Realm) {
|
||||
@ -44,7 +50,12 @@ function GetSuperConstructor(realm: Realm) {
|
||||
}
|
||||
|
||||
// ECMA262 12.3.5.1
|
||||
export default function SuperCall(Arguments: Array<BabelNode>, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Completion | Value | Reference {
|
||||
export default function SuperCall(
|
||||
Arguments: Array<BabelNode>,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Completion | Value | Reference {
|
||||
// 1. Let newTarget be GetNewTarget().
|
||||
let newTarget = GetNewTarget(realm);
|
||||
|
||||
|
@ -26,7 +26,7 @@ function MakeSuperPropertyReference(realm: Realm, propertyKey, strict: boolean):
|
||||
|
||||
// 2. If env.HasSuperBinding() is false, throw a ReferenceError exception.
|
||||
if (!env.HasSuperBinding()) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.ReferenceError, 'env does not have super binding');
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.ReferenceError, "env does not have super binding");
|
||||
}
|
||||
|
||||
// 3. Let actualThis be env.GetThisBinding().
|
||||
@ -47,7 +47,12 @@ function MakeSuperPropertyReference(realm: Realm, propertyKey, strict: boolean):
|
||||
}
|
||||
|
||||
// ECMA262 12.3.5.1
|
||||
export default function SuperProperty(ast: BabelNodeMemberExpression, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function SuperProperty(
|
||||
ast: BabelNodeMemberExpression,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
// SuperProperty : super [ Expression ]
|
||||
if (ast.computed) {
|
||||
// 1. Let propertyNameReference be the result of evaluating Expression.
|
||||
@ -66,7 +71,8 @@ export default function SuperProperty(ast: BabelNodeMemberExpression, strictCode
|
||||
|
||||
// 6. Return MakeSuperPropertyReference(propertyKey, strict).
|
||||
return MakeSuperPropertyReference(realm, propertyKey, strict);
|
||||
} else { // SuperProperty : super . IdentifierName
|
||||
} else {
|
||||
// SuperProperty : super . IdentifierName
|
||||
// 1. Let propertyKey be StringValue of IdentifierName.
|
||||
let propertyKey = new StringValue(realm, ast.property.name);
|
||||
|
||||
|
@ -26,7 +26,12 @@ import type { BabelNodeSwitchStatement, BabelNodeSwitchCase, BabelNodeExpression
|
||||
import invariant from "../invariant.js";
|
||||
|
||||
// 13.12.10 Runtime Semantics: CaseSelectorEvaluation
|
||||
function CaseSelectorEvaluation(expression: BabelNodeExpression, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value {
|
||||
function CaseSelectorEvaluation(
|
||||
expression: BabelNodeExpression,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value {
|
||||
// 1. Let exprRef be the result of evaluating Expression.
|
||||
let exprRef = env.evaluate(expression, strictCode);
|
||||
|
||||
@ -34,14 +39,18 @@ function CaseSelectorEvaluation(expression: BabelNodeExpression, strictCode: boo
|
||||
return GetValue(realm, exprRef);
|
||||
}
|
||||
|
||||
function CaseBlockEvaluation(cases: Array<BabelNodeSwitchCase>, input: Value, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Reference | Value {
|
||||
|
||||
function CaseBlockEvaluation(
|
||||
cases: Array<BabelNodeSwitchCase>,
|
||||
input: Value,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Reference | Value {
|
||||
let EvaluateCase = (c: BabelNodeSwitchCase): Reference | Value | AbruptCompletion => {
|
||||
let r = realm.intrinsics.empty;
|
||||
for (let node of c.consequent) {
|
||||
let res = env.evaluateCompletion(node, strictCode);
|
||||
if (res instanceof AbruptCompletion)
|
||||
return (UpdateEmpty(realm, res, r): any);
|
||||
if (res instanceof AbruptCompletion) return (UpdateEmpty(realm, res, r): any);
|
||||
if (!(res instanceof EmptyValue)) r = res;
|
||||
}
|
||||
return r;
|
||||
@ -69,7 +78,8 @@ function CaseBlockEvaluation(cases: Array<BabelNodeSwitchCase>, input: Value, st
|
||||
// iii. Let found be the result of performing Strict Equality Comparison input === clauseSelector.[[Value]].
|
||||
found = StrictEqualityComparisonPartial(realm, input, clauseSelector);
|
||||
}
|
||||
if (found) { // b. If found is true, then
|
||||
if (found) {
|
||||
// b. If found is true, then
|
||||
// i. Let R be the result of evaluating C.
|
||||
let R = EvaluateCase(C);
|
||||
|
||||
@ -91,7 +101,7 @@ function CaseBlockEvaluation(cases: Array<BabelNodeSwitchCase>, input: Value, st
|
||||
if (cases.length === 0) return realm.intrinsics.undefined;
|
||||
|
||||
// CaseBlock:{CaseClauses DefaultClause CaseClauses}
|
||||
let default_case_num = cases.findIndex((clause) => {
|
||||
let default_case_num = cases.findIndex(clause => {
|
||||
return clause.test === null;
|
||||
});
|
||||
|
||||
@ -144,7 +154,8 @@ function CaseBlockEvaluation(cases: Array<BabelNodeSwitchCase>, input: Value, st
|
||||
|
||||
// 13. Return NormalCompletion(V).
|
||||
return V;
|
||||
} else { // CaseBlock:{CaseClauses}
|
||||
} else {
|
||||
// CaseBlock:{CaseClauses}
|
||||
let V;
|
||||
[, V] = EvaluateCaseClauses(cases, realm.intrinsics.undefined);
|
||||
return V;
|
||||
@ -152,9 +163,15 @@ function CaseBlockEvaluation(cases: Array<BabelNodeSwitchCase>, input: Value, st
|
||||
}
|
||||
|
||||
// 13.12.11
|
||||
export default function (ast: BabelNodeSwitchStatement, strictCode: boolean, env: LexicalEnvironment, realm: Realm, labelSet: Array<string>): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeSwitchStatement,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm,
|
||||
labelSet: Array<string>
|
||||
): Value | Reference {
|
||||
let expression = ast.discriminant;
|
||||
let cases : Array<BabelNodeSwitchCase> = ast.cases;
|
||||
let cases: Array<BabelNodeSwitchCase> = ast.cases;
|
||||
|
||||
// 1. Let exprRef be the result of evaluating Expression.
|
||||
let exprRef = env.evaluate(expression, strictCode);
|
||||
@ -169,8 +186,7 @@ export default function (ast: BabelNodeSwitchStatement, strictCode: boolean, env
|
||||
let blockEnv = NewDeclarativeEnvironment(realm, oldEnv);
|
||||
|
||||
// 5. Perform BlockDeclarationInstantiation(CaseBlock, blockEnv).
|
||||
let CaseBlock = cases.map(c => c.consequent).reduce(
|
||||
(stmts, case_blk) => stmts.concat(case_blk), []);
|
||||
let CaseBlock = cases.map(c => c.consequent).reduce((stmts, case_blk) => stmts.concat(case_blk), []);
|
||||
BlockDeclarationInstantiation(realm, strictCode, CaseBlock, blockEnv);
|
||||
|
||||
// 6. Set the running execution context's LexicalEnvironment to blockEnv.
|
||||
@ -185,8 +201,7 @@ export default function (ast: BabelNodeSwitchStatement, strictCode: boolean, env
|
||||
return R;
|
||||
} catch (e) {
|
||||
if (e instanceof BreakCompletion) {
|
||||
if (!e.target)
|
||||
return (UpdateEmpty(realm, e, realm.intrinsics.undefined): any).value;
|
||||
if (!e.target) return (UpdateEmpty(realm, e, realm.intrinsics.undefined): any).value;
|
||||
}
|
||||
throw e;
|
||||
} finally {
|
||||
|
@ -17,7 +17,12 @@ import { EvaluateCall } from "../methods/call.js";
|
||||
import type { BabelNodeTaggedTemplateExpression } from "babel-types";
|
||||
|
||||
// ECMA262 12.3.7
|
||||
export default function (ast: BabelNodeTaggedTemplateExpression, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeTaggedTemplateExpression,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
// 1. Let tagRef be the result of evaluating MemberExpression.
|
||||
let tagRef = env.evaluate(ast.tag, strictCode);
|
||||
|
||||
|
@ -19,7 +19,12 @@ import { GetValue } from "../methods/environment.js";
|
||||
import type { BabelNodeTemplateLiteral } from "babel-types";
|
||||
|
||||
// ECMA262 12.2.9
|
||||
export default function (ast: BabelNodeTemplateLiteral, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeTemplateLiteral,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
let str = "";
|
||||
|
||||
for (let i = 0; i < ast.quasis.length; i++) {
|
||||
|
@ -17,7 +17,12 @@ import { ResolveThisBinding } from "../methods/index.js";
|
||||
import type { BabelNodeThisExpression } from "babel-types";
|
||||
|
||||
// ECMA262 12.2.2.1
|
||||
export default function (ast: BabelNodeThisExpression, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeThisExpression,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
// 1. Return ? ResolveThisBinding( ).
|
||||
return ResolveThisBinding(realm);
|
||||
}
|
||||
|
@ -17,7 +17,12 @@ import { ThrowCompletion } from "../completions.js";
|
||||
import { GetValue } from "../methods/index.js";
|
||||
import type { BabelNodeThrowStatement } from "babel-types";
|
||||
|
||||
export default function (ast: BabelNodeThrowStatement, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeThrowStatement,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
let exprRef = env.evaluate(ast.argument, strictCode);
|
||||
let exprValue = GetValue(realm, exprRef);
|
||||
throw new ThrowCompletion(exprValue);
|
||||
|
@ -17,7 +17,12 @@ import { UpdateEmpty } from "../methods/index.js";
|
||||
import { Value } from "../values/index.js";
|
||||
import type { BabelNodeTryStatement } from "babel-types";
|
||||
|
||||
export default function (ast: BabelNodeTryStatement, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeTryStatement,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
let completions = [];
|
||||
|
||||
let blockRes = env.evaluateCompletion(ast.block, strictCode);
|
||||
|
@ -12,7 +12,19 @@
|
||||
import type { Realm } from "../realm.js";
|
||||
import type { LexicalEnvironment } from "../environment.js";
|
||||
import { CompilerDiagnostics, FatalError } from "../errors.js";
|
||||
import { AbstractObjectValue, Value, BooleanValue, ConcreteValue, NumberValue, StringValue, UndefinedValue, NullValue, SymbolValue, ObjectValue, AbstractValue } from "../values/index.js";
|
||||
import {
|
||||
AbstractObjectValue,
|
||||
Value,
|
||||
BooleanValue,
|
||||
ConcreteValue,
|
||||
NumberValue,
|
||||
StringValue,
|
||||
UndefinedValue,
|
||||
NullValue,
|
||||
SymbolValue,
|
||||
ObjectValue,
|
||||
AbstractValue,
|
||||
} from "../values/index.js";
|
||||
import { Reference, EnvironmentRecord } from "../environment.js";
|
||||
import { TypesDomain, ValuesDomain } from "../domains/index.js";
|
||||
import invariant from "../invariant.js";
|
||||
@ -29,7 +41,7 @@ import {
|
||||
IsUnresolvableReference,
|
||||
IsStrictReference,
|
||||
IsPropertyReference,
|
||||
IsToNumberPure
|
||||
IsToNumberPure,
|
||||
} from "../methods/index.js";
|
||||
import * as t from "babel-types";
|
||||
import type { BabelNodeUnaryExpression } from "babel-types";
|
||||
@ -39,16 +51,25 @@ function isInstance(proto, Constructor): boolean {
|
||||
}
|
||||
|
||||
function computeAbstractly(realm, type, op, val) {
|
||||
return realm.createAbstract(new TypesDomain(type), ValuesDomain.topVal, [val],
|
||||
([node]) => t.unaryExpression(op, node));
|
||||
return realm.createAbstract(new TypesDomain(type), ValuesDomain.topVal, [val], ([node]) =>
|
||||
t.unaryExpression(op, node)
|
||||
);
|
||||
}
|
||||
|
||||
export default function (ast: BabelNodeUnaryExpression, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeUnaryExpression,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
function reportError() {
|
||||
let error = new CompilerDiagnostics(
|
||||
"might be a symbol or an object with an unknown valueOf or toString or Symbol.toPrimitive method",
|
||||
ast.argument.loc, 'PP0008', 'RecoverableError');
|
||||
if (realm.handleError(error) === 'Fail') throw new FatalError();
|
||||
ast.argument.loc,
|
||||
"PP0008",
|
||||
"RecoverableError"
|
||||
);
|
||||
if (realm.handleError(error) === "Fail") throw new FatalError();
|
||||
}
|
||||
|
||||
let expr = env.evaluate(ast.argument, strictCode);
|
||||
|
@ -21,7 +21,12 @@ import type { BabelNodeUpdateExpression } from "babel-types";
|
||||
import invariant from "../invariant.js";
|
||||
import * as t from "babel-types";
|
||||
|
||||
export default function (ast: BabelNodeUpdateExpression, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeUpdateExpression,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
// ECMA262 12.4 Update Expressions
|
||||
|
||||
// Let expr be the result of evaluating UnaryExpression.
|
||||
@ -33,11 +38,14 @@ export default function (ast: BabelNodeUpdateExpression, strictCode: boolean, en
|
||||
if (!IsToNumberPure(realm, oldExpr)) {
|
||||
let error = new CompilerDiagnostics(
|
||||
"might be a symbol or an object with an unknown valueOf or toString or Symbol.toPrimitive method",
|
||||
ast.argument.loc, 'PP0008', 'RecoverableError');
|
||||
if (realm.handleError(error) === 'Fail') throw new FatalError();
|
||||
ast.argument.loc,
|
||||
"PP0008",
|
||||
"RecoverableError"
|
||||
);
|
||||
if (realm.handleError(error) === "Fail") throw new FatalError();
|
||||
}
|
||||
invariant(ast.operator === '++' || ast.operator === '--'); // As per BabelNodeUpdateExpression
|
||||
let op = ast.operator === '++' ? '+' : '-';
|
||||
invariant(ast.operator === "++" || ast.operator === "--"); // As per BabelNodeUpdateExpression
|
||||
let op = ast.operator === "++" ? "+" : "-";
|
||||
let newAbstractValue = realm.createAbstract(
|
||||
new TypesDomain(NumberValue),
|
||||
ValuesDomain.topVal,
|
||||
@ -104,5 +112,4 @@ export default function (ast: BabelNodeUpdateExpression, strictCode: boolean, en
|
||||
}
|
||||
invariant(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,7 +27,12 @@ import invariant from "../invariant.js";
|
||||
import type { BabelNodeVariableDeclaration } from "babel-types";
|
||||
|
||||
// ECMA262 13.3.1.4
|
||||
function letAndConst (ast: BabelNodeVariableDeclaration, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
function letAndConst(
|
||||
ast: BabelNodeVariableDeclaration,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
for (let declar of ast.declarations) {
|
||||
if (declar.id.type !== "Identifier") {
|
||||
throw new Error("TODO: Patterns aren't supported yet");
|
||||
@ -77,7 +82,12 @@ function letAndConst (ast: BabelNodeVariableDeclaration, strictCode: boolean, en
|
||||
}
|
||||
|
||||
// ECMA262 13.3.2.4
|
||||
export default function (ast: BabelNodeVariableDeclaration, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeVariableDeclaration,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
if (ast.kind === "let" || ast.kind === "const") {
|
||||
return letAndConst(ast, strictCode, env, realm);
|
||||
}
|
||||
|
@ -15,12 +15,22 @@ import type { Value } from "../values/index.js";
|
||||
import type { Reference } from "../environment.js";
|
||||
import type { BabelNodeWhileStatement, BabelNode } from "babel-types";
|
||||
|
||||
export default function (ast: BabelNodeWhileStatement, strictCode: boolean, env: LexicalEnvironment, realm: Realm, labelSet: ?Array<string>): Value | Reference {
|
||||
return env.evaluate((({
|
||||
type: "ForStatement",
|
||||
init: null,
|
||||
test: ast.test,
|
||||
update: null,
|
||||
body: ast.body
|
||||
}: any): BabelNode), strictCode, labelSet);
|
||||
export default function(
|
||||
ast: BabelNodeWhileStatement,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm,
|
||||
labelSet: ?Array<string>
|
||||
): Value | Reference {
|
||||
return env.evaluate(
|
||||
(({
|
||||
type: "ForStatement",
|
||||
init: null,
|
||||
test: ast.test,
|
||||
update: null,
|
||||
body: ast.body,
|
||||
}: any): BabelNode),
|
||||
strictCode,
|
||||
labelSet
|
||||
);
|
||||
}
|
||||
|
@ -20,7 +20,12 @@ import invariant from "../invariant.js";
|
||||
import type { BabelNodeWithStatement } from "babel-types";
|
||||
|
||||
// ECMA262 13.11.7
|
||||
export default function (ast: BabelNodeWithStatement, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeWithStatement,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
// 1. Let val be the result of evaluating Expression.
|
||||
let val = env.evaluate(ast.object, strictCode);
|
||||
|
||||
@ -28,7 +33,7 @@ export default function (ast: BabelNodeWithStatement, strictCode: boolean, env:
|
||||
val = GetValue(realm, val);
|
||||
if (val instanceof AbstractValue) {
|
||||
let loc = ast.object.loc;
|
||||
let error = new CompilerDiagnostics("with object must be a known value", loc, 'PP0007', 'RecoverableError');
|
||||
let error = new CompilerDiagnostics("with object must be a known value", loc, "PP0007", "RecoverableError");
|
||||
if (realm.handleError(error) === "Fail") throw new FatalError();
|
||||
}
|
||||
let obj = ToObjectPartial(realm, val);
|
||||
|
@ -15,6 +15,11 @@ import type { Value } from "../values/index.js";
|
||||
import type { Reference } from "../environment.js";
|
||||
import type { BabelNodeYieldExpression } from "babel-types";
|
||||
|
||||
export default function (ast: BabelNodeYieldExpression, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value | Reference {
|
||||
export default function(
|
||||
ast: BabelNodeYieldExpression,
|
||||
strictCode: boolean,
|
||||
env: LexicalEnvironment,
|
||||
realm: Realm
|
||||
): Value | Reference {
|
||||
throw new Error("TODO: YieldExpression");
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import initializePrepackGlobals from "./intrinsics/prepack/global.js";
|
||||
import initializeDOMGlobals from "./intrinsics/dom/global.js";
|
||||
import initializeReactNativeGlobals from "./intrinsics/react-native/global.js";
|
||||
|
||||
export default function (realm: Realm): Realm {
|
||||
export default function(realm: Realm): Realm {
|
||||
initializePrepackGlobals(realm);
|
||||
if (realm.isCompatibleWith("browser")) {
|
||||
initializeDOMGlobals(realm);
|
||||
|
@ -12,7 +12,7 @@
|
||||
import type { Realm } from "../../realm.js";
|
||||
import { ObjectValue } from "../../values/index.js";
|
||||
|
||||
export default function (realm: Realm): ObjectValue {
|
||||
export default function(realm: Realm): ObjectValue {
|
||||
let obj = new ObjectValue(realm, realm.intrinsics.ObjectPrototype, "console");
|
||||
|
||||
obj.defineNativeMethod("log", 0, (context, args) => {
|
||||
|
@ -12,7 +12,7 @@
|
||||
import type { Realm } from "../../realm.js";
|
||||
import { ObjectValue } from "../../values/index.js";
|
||||
|
||||
export default function (realm: Realm): ObjectValue {
|
||||
export default function(realm: Realm): ObjectValue {
|
||||
let obj = new ObjectValue(realm, realm.intrinsics.ObjectPrototype, "document");
|
||||
|
||||
return obj;
|
||||
|
@ -17,35 +17,35 @@ import initializeConsole from "../common/console.js";
|
||||
import invariant from "../../invariant.js";
|
||||
import { TypesDomain, ValuesDomain } from "../../domains/index.js";
|
||||
|
||||
export default function (realm: Realm): void {
|
||||
export default function(realm: Realm): void {
|
||||
let global = realm.$GlobalObject;
|
||||
|
||||
global.$DefineOwnProperty("console", {
|
||||
value: initializeConsole(realm),
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
global.$DefineOwnProperty("self", {
|
||||
value: global,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
global.$DefineOwnProperty("window", {
|
||||
value: global,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
global.$DefineOwnProperty("document", {
|
||||
value: initializeDocument(realm),
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
global.$DefineOwnProperty("setTimeout", {
|
||||
@ -57,12 +57,15 @@ export default function (realm: Realm): void {
|
||||
invariant(realm.generator !== undefined);
|
||||
let generator = realm.generator;
|
||||
return generator.emitCallAndCaptureResult(
|
||||
TypesDomain.topVal, ValuesDomain.topVal,
|
||||
() => generator.preludeGenerator.memoizeReference("::global.setTimeout"), args);
|
||||
TypesDomain.topVal,
|
||||
ValuesDomain.topVal,
|
||||
() => generator.preludeGenerator.memoizeReference("::global.setTimeout"),
|
||||
args
|
||||
);
|
||||
}),
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
global.$DefineOwnProperty("clearTimeout", {
|
||||
@ -70,13 +73,12 @@ export default function (realm: Realm): void {
|
||||
if (!realm.useAbstractInterpretation) throw new Error("TODO: implement global.clearTimeout");
|
||||
invariant(realm.generator !== undefined);
|
||||
let generator = realm.generator;
|
||||
generator.emitCall(
|
||||
() => generator.preludeGenerator.memoizeReference("::global.clearTimeout"), args);
|
||||
generator.emitCall(() => generator.preludeGenerator.memoizeReference("::global.clearTimeout"), args);
|
||||
return realm.intrinsics.undefined;
|
||||
}),
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
global.$DefineOwnProperty("setInterval", {
|
||||
@ -88,12 +90,15 @@ export default function (realm: Realm): void {
|
||||
invariant(realm.generator !== undefined);
|
||||
let generator = realm.generator;
|
||||
return generator.emitCallAndCaptureResult(
|
||||
TypesDomain.topVal, ValuesDomain.topVal,
|
||||
() => generator.preludeGenerator.memoizeReference("::global.setInterval"), args);
|
||||
TypesDomain.topVal,
|
||||
ValuesDomain.topVal,
|
||||
() => generator.preludeGenerator.memoizeReference("::global.setInterval"),
|
||||
args
|
||||
);
|
||||
}),
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
global.$DefineOwnProperty("clearInterval", {
|
||||
@ -101,12 +106,11 @@ export default function (realm: Realm): void {
|
||||
if (!realm.useAbstractInterpretation) throw new Error("TODO: implement global.clearInterval");
|
||||
invariant(realm.generator !== undefined);
|
||||
let generator = realm.generator;
|
||||
generator.emitCall(
|
||||
() => generator.preludeGenerator.memoizeReference("::global.clearInterval"), args);
|
||||
generator.emitCall(() => generator.preludeGenerator.memoizeReference("::global.clearInterval"), args);
|
||||
return realm.intrinsics.undefined;
|
||||
}),
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
|
@ -14,33 +14,33 @@ import { NativeFunctionValue } from "../../values/index.js";
|
||||
import { AbruptCompletion } from "../../completions.js";
|
||||
import { CompilerDiagnostics } from "../../errors.js";
|
||||
import {
|
||||
AbstractValue,
|
||||
BooleanValue,
|
||||
NumberValue,
|
||||
UndefinedValue,
|
||||
StringValue,
|
||||
ObjectValue,
|
||||
AbstractValue,
|
||||
BooleanValue,
|
||||
NumberValue,
|
||||
UndefinedValue,
|
||||
StringValue,
|
||||
ObjectValue,
|
||||
} from "../../values/index.js";
|
||||
import {
|
||||
ArrayCreate,
|
||||
Construct,
|
||||
Call,
|
||||
CreateDataProperty,
|
||||
CreateDataPropertyOrThrow,
|
||||
Get,
|
||||
GetPrototypeFromConstructor,
|
||||
GetMethod,
|
||||
IsArray,
|
||||
IsConstructor,
|
||||
IsCallable,
|
||||
Set,
|
||||
ToStringPartial,
|
||||
ArrayCreate,
|
||||
Construct,
|
||||
Call,
|
||||
CreateDataProperty,
|
||||
CreateDataPropertyOrThrow,
|
||||
Get,
|
||||
GetPrototypeFromConstructor,
|
||||
GetMethod,
|
||||
IsArray,
|
||||
IsConstructor,
|
||||
IsCallable,
|
||||
Set,
|
||||
ToStringPartial,
|
||||
} from "../../methods/index.js";
|
||||
import { ToString, ToUint32, ToObject, ToLength } from "../../methods/to.js";
|
||||
import { GetIterator, IteratorClose, IteratorStep, IteratorValue } from "../../methods/iterator.js";
|
||||
import invariant from "../../invariant.js";
|
||||
|
||||
export default function (realm: Realm): NativeFunctionValue {
|
||||
export default function(realm: Realm): NativeFunctionValue {
|
||||
let func = new NativeFunctionValue(realm, "Array", "Array", 1, (context, [...items], argCount, NewTarget) => {
|
||||
if (argCount === 0) {
|
||||
// 1. Let numberOfArgs be the number of arguments passed to this function call.
|
||||
@ -86,7 +86,8 @@ export default function (realm: Realm): NativeFunctionValue {
|
||||
|
||||
// c. Let intLen be 1.
|
||||
intLen = 1;
|
||||
} else { // 7. Else,
|
||||
} else {
|
||||
// 7. Else,
|
||||
|
||||
try {
|
||||
len = len.throwIfNotConcreteNumber();
|
||||
@ -95,12 +96,14 @@ export default function (realm: Realm): NativeFunctionValue {
|
||||
invariant(value instanceof ObjectValue);
|
||||
value = ((value: any): ObjectValue);
|
||||
|
||||
realm.handleError(new CompilerDiagnostics(
|
||||
ToStringPartial(realm, Get(realm, value, "message")),
|
||||
realm.currentLocation,
|
||||
'PP0001',
|
||||
'FatalError',
|
||||
));
|
||||
realm.handleError(
|
||||
new CompilerDiagnostics(
|
||||
ToStringPartial(realm, Get(realm, value, "message")),
|
||||
realm.currentLocation,
|
||||
"PP0001",
|
||||
"FatalError"
|
||||
)
|
||||
);
|
||||
|
||||
// Rethrow.
|
||||
// TODO: In the future, we can try and recover from the error based on the
|
||||
@ -182,226 +185,231 @@ export default function (realm: Realm): NativeFunctionValue {
|
||||
|
||||
// ECMA262 22.1.2.3
|
||||
if (!realm.isCompatibleWith(realm.MOBILE_JSC_VERSION))
|
||||
func.defineNativeMethod("of", 0, (context, [...items], argCount) => {
|
||||
// 1. Let len be the actual number of arguments passed to this function.
|
||||
let len = argCount;
|
||||
func.defineNativeMethod("of", 0, (context, [...items], argCount) => {
|
||||
// 1. Let len be the actual number of arguments passed to this function.
|
||||
let len = argCount;
|
||||
|
||||
// 2. Let items be the List of arguments passed to this function.
|
||||
items;
|
||||
// 2. Let items be the List of arguments passed to this function.
|
||||
items;
|
||||
|
||||
// 3. Let C be the this value.
|
||||
let C = context;
|
||||
// 3. Let C be the this value.
|
||||
let C = context;
|
||||
|
||||
// 4. If IsConstructor(C) is true, then
|
||||
let A;
|
||||
if (IsConstructor(realm, C)) {
|
||||
invariant(C instanceof ObjectValue);
|
||||
// a. Let A be ? Construct(C, « len »).
|
||||
A = Construct(realm, C, [new NumberValue(realm, len)]);
|
||||
} else { // 5. Else,
|
||||
// a. Let A be ? ArrayCreate(len).
|
||||
A = ArrayCreate(realm, len);
|
||||
}
|
||||
// 4. If IsConstructor(C) is true, then
|
||||
let A;
|
||||
if (IsConstructor(realm, C)) {
|
||||
invariant(C instanceof ObjectValue);
|
||||
// a. Let A be ? Construct(C, « len »).
|
||||
A = Construct(realm, C, [new NumberValue(realm, len)]);
|
||||
} else {
|
||||
// 5. Else,
|
||||
// a. Let A be ? ArrayCreate(len).
|
||||
A = ArrayCreate(realm, len);
|
||||
}
|
||||
|
||||
// 6. Let k be 0.
|
||||
let k = 0;
|
||||
// 6. Let k be 0.
|
||||
let k = 0;
|
||||
|
||||
// 7. Repeat, while k < len
|
||||
while (k < len) {
|
||||
// a. Let kValue be items[k].
|
||||
let kValue = items[k];
|
||||
// 7. Repeat, while k < len
|
||||
while (k < len) {
|
||||
// a. Let kValue be items[k].
|
||||
let kValue = items[k];
|
||||
|
||||
// b. Let Pk be ! ToString(k).
|
||||
let Pk = ToString(realm, new NumberValue(realm, k));
|
||||
// b. Let Pk be ! ToString(k).
|
||||
let Pk = ToString(realm, new NumberValue(realm, k));
|
||||
|
||||
// c. Perform ? CreateDataPropertyOrThrow(A, Pk, kValue).
|
||||
CreateDataPropertyOrThrow(realm, A, Pk, kValue);
|
||||
// c. Perform ? CreateDataPropertyOrThrow(A, Pk, kValue).
|
||||
CreateDataPropertyOrThrow(realm, A, Pk, kValue);
|
||||
|
||||
// d. Increase k by 1.
|
||||
k += 1;
|
||||
}
|
||||
// d. Increase k by 1.
|
||||
k += 1;
|
||||
}
|
||||
|
||||
// 8. Perform ? Set(A, "length", len, true).
|
||||
Set(realm, A, "length", new NumberValue(realm, len), true);
|
||||
// 8. Perform ? Set(A, "length", len, true).
|
||||
Set(realm, A, "length", new NumberValue(realm, len), true);
|
||||
|
||||
// 9. Return A.
|
||||
return A;
|
||||
});
|
||||
// 9. Return A.
|
||||
return A;
|
||||
});
|
||||
|
||||
// ECMA262 22.1.2.1
|
||||
if (!realm.isCompatibleWith(realm.MOBILE_JSC_VERSION))
|
||||
func.defineNativeMethod("from", 1, (context, [items, mapfn, thisArg], argCount) => {
|
||||
// 1. Let C be the this value.
|
||||
let C = context;
|
||||
func.defineNativeMethod("from", 1, (context, [items, mapfn, thisArg], argCount) => {
|
||||
// 1. Let C be the this value.
|
||||
let C = context;
|
||||
|
||||
let mapping, T;
|
||||
// 2. If mapfn is undefined, let mapping be false.
|
||||
if (!mapfn || mapfn instanceof UndefinedValue) {
|
||||
mapping = false;
|
||||
} else if (mapfn.mightBeUndefined()) {
|
||||
invariant(mapfn instanceof AbstractValue);
|
||||
mapfn.throwIfNotConcrete();
|
||||
} else { // 3. Else,
|
||||
// a. If IsCallable(mapfn) is false, throw a TypeError exception.
|
||||
if (IsCallable(realm, mapfn) === false) {
|
||||
let mapping, T;
|
||||
// 2. If mapfn is undefined, let mapping be false.
|
||||
if (!mapfn || mapfn instanceof UndefinedValue) {
|
||||
mapping = false;
|
||||
} else if (mapfn.mightBeUndefined()) {
|
||||
invariant(mapfn instanceof AbstractValue);
|
||||
mapfn.throwIfNotConcrete();
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "IsCallable(mapfn) is false");
|
||||
} else {
|
||||
// 3. Else,
|
||||
// a. If IsCallable(mapfn) is false, throw a TypeError exception.
|
||||
if (IsCallable(realm, mapfn) === false) {
|
||||
mapfn.throwIfNotConcrete();
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "IsCallable(mapfn) is false");
|
||||
}
|
||||
|
||||
// b. If thisArg was supplied, let T be thisArg; else let T be undefined.
|
||||
T = thisArg !== undefined ? thisArg : realm.intrinsics.undefined;
|
||||
|
||||
// c. Let mapping be true.
|
||||
mapping = true;
|
||||
}
|
||||
|
||||
// b. If thisArg was supplied, let T be thisArg; else let T be undefined.
|
||||
T = (thisArg !== undefined) ? thisArg : realm.intrinsics.undefined;
|
||||
// 4. Let usingIterator be ? GetMethod(items, @@iterator).
|
||||
let usingIterator = GetMethod(realm, items, realm.intrinsics.SymbolIterator);
|
||||
|
||||
// c. Let mapping be true.
|
||||
mapping = true;
|
||||
}
|
||||
// 5. If usingIterator is not undefined, then
|
||||
if (!usingIterator.mightBeUndefined()) {
|
||||
let A;
|
||||
// a. If IsConstructor(C) is true, then
|
||||
if (IsConstructor(realm, C)) {
|
||||
invariant(C instanceof ObjectValue);
|
||||
// i. Let A be ? Construct(C).
|
||||
A = Construct(realm, C);
|
||||
} else {
|
||||
// b. Else,
|
||||
// i. Let A be ArrayCreate(0).
|
||||
A = ArrayCreate(realm, 0);
|
||||
}
|
||||
|
||||
// 4. Let usingIterator be ? GetMethod(items, @@iterator).
|
||||
let usingIterator = GetMethod(realm, items, realm.intrinsics.SymbolIterator);
|
||||
// c. Let iterator be ? GetIterator(items, usingIterator).
|
||||
let iterator = GetIterator(realm, items, usingIterator);
|
||||
|
||||
// d. Let k be 0.
|
||||
let k = 0;
|
||||
|
||||
// e. Repeat
|
||||
while (true) {
|
||||
// i. If k ≥ 2^53-1, then
|
||||
if (k >= Math.pow(2, 53) - 1) {
|
||||
// 1. Let error be Completion{[[Type]]: throw, [[Value]]: a newly created TypeError object, [[Target]]: empty}.
|
||||
let error = realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "k >= 2^53 - 1");
|
||||
|
||||
// 2. Return ? IteratorClose(iterator, error).
|
||||
throw IteratorClose(realm, iterator, error);
|
||||
}
|
||||
|
||||
// ii. Let Pk be ! ToString(k).
|
||||
let Pk = ToString(realm, new NumberValue(realm, k));
|
||||
|
||||
// iii. Let next be ? IteratorStep(iterator).
|
||||
let next = IteratorStep(realm, iterator);
|
||||
|
||||
// iv. If next is false, then
|
||||
if (next === false) {
|
||||
// 1. Perform ? Set(A, "length", k, true).
|
||||
Set(realm, A, "length", new NumberValue(realm, k), true);
|
||||
|
||||
// 2. Return A.
|
||||
return A;
|
||||
}
|
||||
|
||||
// v. Let nextValue be ? IteratorValue(next).
|
||||
let nextValue = IteratorValue(realm, next);
|
||||
|
||||
let mappedValue;
|
||||
// vi. If mapping is true, then
|
||||
if (mapping === true) {
|
||||
// 1. Let mappedValue be Call(mapfn, T, « nextValue, k »).
|
||||
try {
|
||||
invariant(T !== undefined);
|
||||
mappedValue = Call(realm, mapfn, T, [nextValue, new NumberValue(realm, k)]);
|
||||
} catch (mappedValueCompletion) {
|
||||
if (mappedValueCompletion instanceof AbruptCompletion) {
|
||||
// 2. If mappedValue is an abrupt completion, return ? IteratorClose(iterator, mappedValue).
|
||||
throw IteratorClose(realm, iterator, mappedValueCompletion);
|
||||
} else {
|
||||
throw mappedValueCompletion;
|
||||
}
|
||||
}
|
||||
// 3. Let mappedValue be mappedValue.[[Value]].
|
||||
} else {
|
||||
// vii. Else, let mappedValue be nextValue.
|
||||
mappedValue = nextValue;
|
||||
}
|
||||
|
||||
// viii. Let defineStatus be CreateDataPropertyOrThrow(A, Pk, mappedValue).
|
||||
try {
|
||||
CreateDataPropertyOrThrow(realm, A, Pk, mappedValue);
|
||||
} catch (completion) {
|
||||
if (completion instanceof AbruptCompletion) {
|
||||
// ix. If defineStatus is an abrupt completion, return ? IteratorClose(iterator, defineStatus).
|
||||
throw IteratorClose(realm, iterator, completion);
|
||||
} else throw completion;
|
||||
}
|
||||
|
||||
// x. Increase k by 1.
|
||||
k = k + 1;
|
||||
}
|
||||
} else {
|
||||
usingIterator.throwIfNotConcrete();
|
||||
}
|
||||
|
||||
// 6. NOTE: items is not an Iterable so assume it is an array-like object.
|
||||
items = items.throwIfNotConcrete();
|
||||
invariant(items instanceof ObjectValue);
|
||||
|
||||
// 7. Let arrayLike be ! ToObject(items).
|
||||
let arrayLike = ToObject(realm, items);
|
||||
|
||||
// 8. Let len be ? ToLength(? Get(arrayLike, "length")).
|
||||
let len = ToLength(realm, Get(realm, arrayLike, "length"));
|
||||
|
||||
// 5. If usingIterator is not undefined, then
|
||||
if (!usingIterator.mightBeUndefined()) {
|
||||
let A;
|
||||
// a. If IsConstructor(C) is true, then
|
||||
// 9. If IsConstructor(C) is true, then
|
||||
if (IsConstructor(realm, C)) {
|
||||
invariant(C instanceof ObjectValue);
|
||||
// i. Let A be ? Construct(C).
|
||||
A = Construct(realm, C);
|
||||
} else { // b. Else,
|
||||
// i. Let A be ArrayCreate(0).
|
||||
A = ArrayCreate(realm, 0);
|
||||
// a. Let A be ? Construct(C, « len »).
|
||||
A = Construct(realm, C, [new NumberValue(realm, len)]);
|
||||
} else {
|
||||
// 10. Else,
|
||||
// a. Let A be ? ArrayCreate(len).
|
||||
A = ArrayCreate(realm, len);
|
||||
}
|
||||
|
||||
// c. Let iterator be ? GetIterator(items, usingIterator).
|
||||
let iterator = GetIterator(realm, items, usingIterator);
|
||||
|
||||
// d. Let k be 0.
|
||||
// 11. Let k be 0.
|
||||
let k = 0;
|
||||
|
||||
// e. Repeat
|
||||
while (true) {
|
||||
// i. If k ≥ 2^53-1, then
|
||||
if (k >= Math.pow(2, 53) - 1) {
|
||||
// 1. Let error be Completion{[[Type]]: throw, [[Value]]: a newly created TypeError object, [[Target]]: empty}.
|
||||
let error = realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "k >= 2^53 - 1");
|
||||
|
||||
// 2. Return ? IteratorClose(iterator, error).
|
||||
throw IteratorClose(realm, iterator, error);
|
||||
}
|
||||
|
||||
// ii. Let Pk be ! ToString(k).
|
||||
// 12. Repeat, while k < len
|
||||
while (k < len) {
|
||||
// a. Let Pk be ! ToString(k).
|
||||
let Pk = ToString(realm, new NumberValue(realm, k));
|
||||
|
||||
// iii. Let next be ? IteratorStep(iterator).
|
||||
let next = IteratorStep(realm, iterator);
|
||||
|
||||
// iv. If next is false, then
|
||||
if (next === false) {
|
||||
// 1. Perform ? Set(A, "length", k, true).
|
||||
Set(realm, A, "length", new NumberValue(realm, k), true);
|
||||
|
||||
// 2. Return A.
|
||||
return A;
|
||||
}
|
||||
|
||||
// v. Let nextValue be ? IteratorValue(next).
|
||||
let nextValue = IteratorValue(realm, next);
|
||||
// b. Let kValue be ? Get(arrayLike, Pk).
|
||||
let kValue = Get(realm, arrayLike, Pk);
|
||||
|
||||
let mappedValue;
|
||||
// vi. If mapping is true, then
|
||||
// c. If mapping is true, then
|
||||
if (mapping === true) {
|
||||
// 1. Let mappedValue be Call(mapfn, T, « nextValue, k »).
|
||||
try {
|
||||
invariant(T !== undefined);
|
||||
mappedValue = Call(realm, mapfn, T, [nextValue, new NumberValue(realm, k)]);
|
||||
} catch (mappedValueCompletion) {
|
||||
if (mappedValueCompletion instanceof AbruptCompletion) {
|
||||
// 2. If mappedValue is an abrupt completion, return ? IteratorClose(iterator, mappedValue).
|
||||
throw IteratorClose(realm, iterator, mappedValueCompletion);
|
||||
} else {
|
||||
throw mappedValueCompletion;
|
||||
}
|
||||
}
|
||||
// 3. Let mappedValue be mappedValue.[[Value]].
|
||||
} else { // vii. Else, let mappedValue be nextValue.
|
||||
mappedValue = nextValue;
|
||||
// i. Let mappedValue be ? Call(mapfn, T, « kValue, k »).
|
||||
invariant(T !== undefined);
|
||||
mappedValue = Call(realm, mapfn, T, [kValue, new NumberValue(realm, k)]);
|
||||
} else {
|
||||
// d. Else, let mappedValue be kValue.
|
||||
mappedValue = kValue;
|
||||
}
|
||||
|
||||
// viii. Let defineStatus be CreateDataPropertyOrThrow(A, Pk, mappedValue).
|
||||
try {
|
||||
CreateDataPropertyOrThrow(realm, A, Pk, mappedValue);
|
||||
} catch (completion) {
|
||||
if (completion instanceof AbruptCompletion) {
|
||||
// ix. If defineStatus is an abrupt completion, return ? IteratorClose(iterator, defineStatus).
|
||||
throw IteratorClose(realm, iterator, completion);
|
||||
} else
|
||||
throw completion;
|
||||
}
|
||||
// e. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).
|
||||
CreateDataPropertyOrThrow(realm, A, new StringValue(realm, Pk), mappedValue);
|
||||
|
||||
// x. Increase k by 1.
|
||||
// f. Increase k by 1.
|
||||
k = k + 1;
|
||||
}
|
||||
} else {
|
||||
usingIterator.throwIfNotConcrete();
|
||||
}
|
||||
|
||||
// 6. NOTE: items is not an Iterable so assume it is an array-like object.
|
||||
items = items.throwIfNotConcrete();
|
||||
invariant(items instanceof ObjectValue);
|
||||
// 13. Perform ? Set(A, "length", len, true).
|
||||
Set(realm, A, "length", new NumberValue(realm, len), true);
|
||||
|
||||
// 7. Let arrayLike be ! ToObject(items).
|
||||
let arrayLike = ToObject(realm, items);
|
||||
|
||||
// 8. Let len be ? ToLength(? Get(arrayLike, "length")).
|
||||
let len = ToLength(realm, Get(realm, arrayLike, "length"));
|
||||
|
||||
let A;
|
||||
// 9. If IsConstructor(C) is true, then
|
||||
if (IsConstructor(realm, C)) {
|
||||
invariant(C instanceof ObjectValue);
|
||||
// a. Let A be ? Construct(C, « len »).
|
||||
A = Construct(realm, C, [new NumberValue(realm, len)]);
|
||||
} else { // 10. Else,
|
||||
// a. Let A be ? ArrayCreate(len).
|
||||
A = ArrayCreate(realm, len);
|
||||
}
|
||||
|
||||
// 11. Let k be 0.
|
||||
let k = 0;
|
||||
|
||||
// 12. Repeat, while k < len
|
||||
while (k < len) {
|
||||
// a. Let Pk be ! ToString(k).
|
||||
let Pk = ToString(realm, new NumberValue(realm, k));
|
||||
|
||||
// b. Let kValue be ? Get(arrayLike, Pk).
|
||||
let kValue = Get(realm, arrayLike, Pk);
|
||||
|
||||
let mappedValue;
|
||||
// c. If mapping is true, then
|
||||
if (mapping === true) {
|
||||
// i. Let mappedValue be ? Call(mapfn, T, « kValue, k »).
|
||||
invariant(T !== undefined);
|
||||
mappedValue = Call(realm, mapfn, T, [kValue, new NumberValue(realm, k)]);
|
||||
} else { // d. Else, let mappedValue be kValue.
|
||||
mappedValue = kValue;
|
||||
}
|
||||
|
||||
// e. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).
|
||||
CreateDataPropertyOrThrow(realm, A, new StringValue(realm, Pk), mappedValue);
|
||||
|
||||
// f. Increase k by 1.
|
||||
k = k + 1;
|
||||
}
|
||||
|
||||
// 13. Perform ? Set(A, "length", len, true).
|
||||
Set(realm, A, "length", new NumberValue(realm, len), true);
|
||||
|
||||
// 14. Return A.
|
||||
return A;
|
||||
});
|
||||
// 14. Return A.
|
||||
return A;
|
||||
});
|
||||
|
||||
// ECMA262 22.1.2.5
|
||||
func.defineNativeGetter(realm.intrinsics.SymbolSpecies, (context) => {
|
||||
func.defineNativeGetter(realm.intrinsics.SymbolSpecies, context => {
|
||||
// 1. Return the this value
|
||||
return context;
|
||||
});
|
||||
|
@ -14,20 +14,26 @@ import { NativeFunctionValue } from "../../values/index.js";
|
||||
import { ToIndexPartial } from "../../methods/to.js";
|
||||
import { AllocateArrayBuffer } from "../../methods/arraybuffer.js";
|
||||
|
||||
export default function (realm: Realm): NativeFunctionValue {
|
||||
export default function(realm: Realm): NativeFunctionValue {
|
||||
// ECMA262 24.1.2.1
|
||||
let func = new NativeFunctionValue(realm, "ArrayBuffer", "ArrayBuffer", 1, (context, [length], argCount, NewTarget) => {
|
||||
// 1. If NewTarget is undefined, throw a TypeError exception.
|
||||
if (!NewTarget) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
|
||||
let func = new NativeFunctionValue(
|
||||
realm,
|
||||
"ArrayBuffer",
|
||||
"ArrayBuffer",
|
||||
1,
|
||||
(context, [length], argCount, NewTarget) => {
|
||||
// 1. If NewTarget is undefined, throw a TypeError exception.
|
||||
if (!NewTarget) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
|
||||
}
|
||||
|
||||
// 2. Let byteLength be ToIndex(numberLength).
|
||||
let byteLength = ToIndexPartial(realm, length);
|
||||
|
||||
// 3. Return ? AllocateArrayBuffer(NewTarget, byteLength).
|
||||
return AllocateArrayBuffer(realm, NewTarget, byteLength);
|
||||
}
|
||||
|
||||
// 2. Let byteLength be ToIndex(numberLength).
|
||||
let byteLength = ToIndexPartial(realm, length);
|
||||
|
||||
// 3. Return ? AllocateArrayBuffer(NewTarget, byteLength).
|
||||
return AllocateArrayBuffer(realm, NewTarget, byteLength);
|
||||
});
|
||||
);
|
||||
|
||||
// ECMA262 24.1.3.1
|
||||
func.defineNativeMethod("isView", 1, (context, [arg]) => {
|
||||
@ -36,14 +42,14 @@ export default function (realm: Realm): NativeFunctionValue {
|
||||
|
||||
// 2. If arg has a [[ViewedArrayBuffer]] internal slot, return true.
|
||||
arg = arg.throwIfNotConcreteObject();
|
||||
if ('$ViewedArrayBuffer' in arg) return realm.intrinsics.true;
|
||||
if ("$ViewedArrayBuffer" in arg) return realm.intrinsics.true;
|
||||
|
||||
// 3. Return false.
|
||||
return realm.intrinsics.false;
|
||||
});
|
||||
|
||||
// ECMA262 24.1.3.3
|
||||
func.defineNativeGetter(realm.intrinsics.SymbolSpecies, (context) => {
|
||||
func.defineNativeGetter(realm.intrinsics.SymbolSpecies, context => {
|
||||
// 1. Return the this value
|
||||
return context;
|
||||
});
|
||||
|
@ -11,12 +11,19 @@
|
||||
|
||||
import type { Realm } from "../../realm.js";
|
||||
import { ObjectValue, StringValue, NumberValue, UndefinedValue } from "../../values/index.js";
|
||||
import { Construct, SpeciesConstructor, IsDetachedBuffer, ToInteger, SameValue, CopyDataBlockBytes } from "../../methods/index.js";
|
||||
import {
|
||||
Construct,
|
||||
SpeciesConstructor,
|
||||
IsDetachedBuffer,
|
||||
ToInteger,
|
||||
SameValue,
|
||||
CopyDataBlockBytes,
|
||||
} from "../../methods/index.js";
|
||||
import invariant from "../../invariant.js";
|
||||
|
||||
export default function (realm: Realm, obj: ObjectValue): void {
|
||||
export default function(realm: Realm, obj: ObjectValue): void {
|
||||
// ECMA262 24.1.4.1
|
||||
obj.defineNativeGetter("byteLength", (context) => {
|
||||
obj.defineNativeGetter("byteLength", context => {
|
||||
// 1. Let O be the this value.
|
||||
let O = context.throwIfNotConcrete();
|
||||
|
||||
@ -26,8 +33,11 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
}
|
||||
|
||||
// 3. If O does not have an [[ArrayBufferData]] internal slot, throw a TypeError exception.
|
||||
if (!('$ArrayBufferData' in O)) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "O does not have an [[ArrayBufferData]] internal slot");
|
||||
if (!("$ArrayBufferData" in O)) {
|
||||
throw realm.createErrorThrowCompletion(
|
||||
realm.intrinsics.TypeError,
|
||||
"O does not have an [[ArrayBufferData]] internal slot"
|
||||
);
|
||||
}
|
||||
|
||||
// 4. If IsDetachedBuffer(O) is true, throw a TypeError exception.
|
||||
@ -54,8 +64,11 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
}
|
||||
|
||||
// 3. If O does not have an [[ArrayBufferData]] internal slot, throw a TypeError exception.
|
||||
if (!('$ArrayBufferData' in O)) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "O does not have an [[ArrayBufferData]] internal slot");
|
||||
if (!("$ArrayBufferData" in O)) {
|
||||
throw realm.createErrorThrowCompletion(
|
||||
realm.intrinsics.TypeError,
|
||||
"O does not have an [[ArrayBufferData]] internal slot"
|
||||
);
|
||||
}
|
||||
|
||||
// 4. If IsDetachedBuffer(O) is true, throw a TypeError exception.
|
||||
@ -89,8 +102,11 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
let New = Construct(realm, ctor, [new NumberValue(realm, newLen)]);
|
||||
|
||||
// 13. If New does not have an [[ArrayBufferData]] internal slot, throw a TypeError exception.
|
||||
if (!('$ArrayBufferData' in New)) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "new does not have an [[ArrayBufferData]] internal slot");
|
||||
if (!("$ArrayBufferData" in New)) {
|
||||
throw realm.createErrorThrowCompletion(
|
||||
realm.intrinsics.TypeError,
|
||||
"new does not have an [[ArrayBufferData]] internal slot"
|
||||
);
|
||||
}
|
||||
|
||||
// 14. If IsDetachedBuffer(New) is true, throw a TypeError exception.
|
||||
@ -116,10 +132,12 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
}
|
||||
|
||||
// 19. Let fromBuf be O.[[ArrayBufferData]].
|
||||
let fromBuf = O.$ArrayBufferData; invariant(fromBuf);
|
||||
let fromBuf = O.$ArrayBufferData;
|
||||
invariant(fromBuf);
|
||||
|
||||
// 20. Let toBuf be New.[[ArrayBufferData]].
|
||||
let toBuf = New.$ArrayBufferData; invariant(toBuf);
|
||||
let toBuf = New.$ArrayBufferData;
|
||||
invariant(toBuf);
|
||||
|
||||
// 21. Perform CopyDataBlockBytes(toBuf, 0, fromBuf, first, newLen).
|
||||
CopyDataBlockBytes(realm, toBuf, 0, fromBuf, first, newLen);
|
||||
@ -129,5 +147,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 24.1.4.4
|
||||
obj.defineNativeProperty(realm.intrinsics.SymbolToStringTag, new StringValue(realm, "ArrayBuffer"), { writable: false });
|
||||
obj.defineNativeProperty(realm.intrinsics.SymbolToStringTag, new StringValue(realm, "ArrayBuffer"), {
|
||||
writable: false,
|
||||
});
|
||||
}
|
||||
|
@ -16,9 +16,9 @@ import { ToLength } from "../../methods/to.js";
|
||||
import { Get } from "../../methods/get.js";
|
||||
import invariant from "../../invariant.js";
|
||||
|
||||
export default function (realm: Realm, obj: ObjectValue): void {
|
||||
export default function(realm: Realm, obj: ObjectValue): void {
|
||||
// ECMA262 22.1.5.2.1
|
||||
obj.defineNativeMethod("next", 0, (context) => {
|
||||
obj.defineNativeMethod("next", 0, context => {
|
||||
// 1. Let O be the this value.
|
||||
let O = context.throwIfNotConcrete();
|
||||
|
||||
@ -28,7 +28,11 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
}
|
||||
|
||||
// 3. If O does not have all of the internal slots of an Array Iterator Instance (22.1.5.3), throw a TypeError exception.
|
||||
if (O.$IteratedObject === undefined || O.$ArrayIteratorNextIndex === undefined || O.$ArrayIterationKind === undefined) {
|
||||
if (
|
||||
O.$IteratedObject === undefined ||
|
||||
O.$ArrayIteratorNextIndex === undefined ||
|
||||
O.$ArrayIterationKind === undefined
|
||||
) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "ArrayIteratorPrototype.next isn't generic");
|
||||
}
|
||||
|
||||
@ -53,7 +57,8 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
// a. Let len be the value of a's [[ArrayLength]] internal slot.
|
||||
len = a.$ArrayLength;
|
||||
invariant(typeof len === "number");
|
||||
} else { // 9. Else,
|
||||
} else {
|
||||
// 9. Else,
|
||||
// a. Let len be ? ToLength(? Get(a, "length")).
|
||||
len = ToLength(realm, Get(realm, a, "length"));
|
||||
}
|
||||
@ -85,7 +90,8 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
let result;
|
||||
if (itemKind === "value") {
|
||||
result = elementValue;
|
||||
} else { // 16. Else,
|
||||
} else {
|
||||
// 16. Else,
|
||||
// a. Assert: itemKind is "key+value".
|
||||
invariant(itemKind === "key+value", "expected item kind to be key+value");
|
||||
|
||||
@ -98,5 +104,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 22.1.5.2.2
|
||||
obj.defineNativeProperty(realm.intrinsics.SymbolToStringTag, new StringValue(realm, "Array Iterator"), { writable: false });
|
||||
obj.defineNativeProperty(realm.intrinsics.SymbolToStringTag, new StringValue(realm, "Array Iterator"), {
|
||||
writable: false,
|
||||
});
|
||||
}
|
||||
|
@ -16,20 +16,26 @@ import { Get } from "../../methods/get.js";
|
||||
import { Call } from "../../methods/call.js";
|
||||
import { IsCallable } from "../../methods/is.js";
|
||||
|
||||
export default function (realm: Realm): NativeFunctionValue {
|
||||
export default function(realm: Realm): NativeFunctionValue {
|
||||
// ECMA262 22.1.3.30
|
||||
return new NativeFunctionValue(realm, "Array.prototype.toString", "toString", 0, (context) => {
|
||||
// 1. Let array be ? ToObject(this value).
|
||||
let array = ToObjectPartial(realm, context);
|
||||
return new NativeFunctionValue(
|
||||
realm,
|
||||
"Array.prototype.toString",
|
||||
"toString",
|
||||
0,
|
||||
context => {
|
||||
// 1. Let array be ? ToObject(this value).
|
||||
let array = ToObjectPartial(realm, context);
|
||||
|
||||
// 2. Let func be ? Get(array, "join").
|
||||
let func = Get(realm, array, "join");
|
||||
// 2. Let func be ? Get(array, "join").
|
||||
let func = Get(realm, array, "join");
|
||||
|
||||
// 3. If IsCallable(func) is false, let func be the intrinsic function %ObjProto_toString%.
|
||||
if (!IsCallable(realm, func))
|
||||
func = realm.intrinsics.ObjectProto_toString;
|
||||
// 3. If IsCallable(func) is false, let func be the intrinsic function %ObjProto_toString%.
|
||||
if (!IsCallable(realm, func)) func = realm.intrinsics.ObjectProto_toString;
|
||||
|
||||
// 4. Return ? Call(func, array).
|
||||
return Call(realm, func, array);
|
||||
}, false);
|
||||
// 4. Return ? Call(func, array).
|
||||
return Call(realm, func, array);
|
||||
},
|
||||
false
|
||||
);
|
||||
}
|
||||
|
@ -13,9 +13,9 @@ import type { Realm } from "../../realm.js";
|
||||
import { NativeFunctionValue } from "../../values/index.js";
|
||||
import { ToObject, CreateArrayIterator } from "../../methods/index.js";
|
||||
|
||||
export default function (realm: Realm): NativeFunctionValue {
|
||||
export default function(realm: Realm): NativeFunctionValue {
|
||||
// ECMA262 22.1.3.30
|
||||
return new NativeFunctionValue(realm, "Array.prototype.values", "values", 0, (context) => {
|
||||
return new NativeFunctionValue(realm, "Array.prototype.values", "values", 0, context => {
|
||||
// 1. Let O be ? ToObject(this value).
|
||||
let O = ToObject(realm, context.throwIfNotConcrete());
|
||||
|
||||
|
@ -37,10 +37,10 @@ import {
|
||||
DeletePropertyOrThrow,
|
||||
Set,
|
||||
HasSomeCompatibleType,
|
||||
ThrowIfMightHaveBeenDeleted
|
||||
ThrowIfMightHaveBeenDeleted,
|
||||
} from "../../methods/index.js";
|
||||
|
||||
export default function (realm: Realm, obj: ObjectValue): void {
|
||||
export default function(realm: Realm, obj: ObjectValue): void {
|
||||
// ECMA262 22.1.3.31
|
||||
obj.defineNativeProperty(realm.intrinsics.SymbolIterator, realm.intrinsics.ArrayProto_values);
|
||||
|
||||
@ -107,7 +107,8 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
// 5. Increase k by 1.
|
||||
k++;
|
||||
}
|
||||
} else { // d. Else E is added as a single item rather than spread,
|
||||
} else {
|
||||
// d. Else E is added as a single item rather than spread,
|
||||
// i. If n≥2^53-1, throw a TypeError exception.
|
||||
if (n > Math.pow(2, 53) - 1) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "too damn high");
|
||||
@ -130,88 +131,90 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
|
||||
// ECMA262 22.1.3.3
|
||||
if (!realm.isCompatibleWith(realm.MOBILE_JSC_VERSION))
|
||||
obj.defineNativeMethod("copyWithin", 2, (context, [target, start, end]) => {
|
||||
// 1. Let O be ? ToObject(this value).
|
||||
let O = ToObject(realm, context.throwIfNotConcrete());
|
||||
obj.defineNativeMethod("copyWithin", 2, (context, [target, start, end]) => {
|
||||
// 1. Let O be ? ToObject(this value).
|
||||
let O = ToObject(realm, context.throwIfNotConcrete());
|
||||
|
||||
// 2. Let len be ? ToLength(? Get(O, "length")).
|
||||
let len = ToLength(realm, Get(realm, O, "length"));
|
||||
// 2. Let len be ? ToLength(? Get(O, "length")).
|
||||
let len = ToLength(realm, Get(realm, O, "length"));
|
||||
|
||||
// 3. Let relativeTarget be ? ToInteger(target).
|
||||
let relativeTarget = ToInteger(realm, target);
|
||||
// 3. Let relativeTarget be ? ToInteger(target).
|
||||
let relativeTarget = ToInteger(realm, target);
|
||||
|
||||
// 4. If relativeTarget < 0, let to be max((len + relativeTarget), 0); else let to be min(relativeTarget, len).
|
||||
let to = relativeTarget < 0 ? Math.max(len + relativeTarget, 0) : Math.min(relativeTarget, len);
|
||||
// 4. If relativeTarget < 0, let to be max((len + relativeTarget), 0); else let to be min(relativeTarget, len).
|
||||
let to = relativeTarget < 0 ? Math.max(len + relativeTarget, 0) : Math.min(relativeTarget, len);
|
||||
|
||||
// 5. Let relativeStart be ? ToInteger(start).
|
||||
let relativeStart = ToInteger(realm, start);
|
||||
// 5. Let relativeStart be ? ToInteger(start).
|
||||
let relativeStart = ToInteger(realm, start);
|
||||
|
||||
// 6. If relativeStart < 0, let from be max((len + relativeStart), 0); else let from be min(relativeStart, len).
|
||||
let from = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len);
|
||||
// 6. If relativeStart < 0, let from be max((len + relativeStart), 0); else let from be min(relativeStart, len).
|
||||
let from = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len);
|
||||
|
||||
// 7. If end is undefined, let relativeEnd be len; else let relativeEnd be ? ToInteger(end).
|
||||
let relativeEnd = (!end || end instanceof UndefinedValue) ? len : ToInteger(realm, end.throwIfNotConcrete());
|
||||
// 7. If end is undefined, let relativeEnd be len; else let relativeEnd be ? ToInteger(end).
|
||||
let relativeEnd = !end || end instanceof UndefinedValue ? len : ToInteger(realm, end.throwIfNotConcrete());
|
||||
|
||||
// 8. If relativeEnd < 0, let final be max((len + relativeEnd), 0); else let final be min(relativeEnd, len).
|
||||
let final = relativeEnd < 0 ? Math.max(len + relativeEnd, 0) : Math.min(relativeEnd, len);
|
||||
// 8. If relativeEnd < 0, let final be max((len + relativeEnd), 0); else let final be min(relativeEnd, len).
|
||||
let final = relativeEnd < 0 ? Math.max(len + relativeEnd, 0) : Math.min(relativeEnd, len);
|
||||
|
||||
// 9. Let count be min(final-from, len-to).
|
||||
let count = Math.min(final - from, len - to);
|
||||
// 9. Let count be min(final-from, len-to).
|
||||
let count = Math.min(final - from, len - to);
|
||||
|
||||
let direction;
|
||||
// 10. If from<to and to<from+count, then
|
||||
if (from < to && to < from + count) {
|
||||
// a. Let direction be -1.
|
||||
direction = -1;
|
||||
let direction;
|
||||
// 10. If from<to and to<from+count, then
|
||||
if (from < to && to < from + count) {
|
||||
// a. Let direction be -1.
|
||||
direction = -1;
|
||||
|
||||
// b. Let from be from + count - 1.
|
||||
from = from + count - 1;
|
||||
// b. Let from be from + count - 1.
|
||||
from = from + count - 1;
|
||||
|
||||
// c. Let to be to + count - 1.
|
||||
to = to + count - 1;
|
||||
} else { // 11. Else,
|
||||
// a. Let direction be 1.
|
||||
direction = 1;
|
||||
}
|
||||
|
||||
// 12. Repeat, while count > 0
|
||||
while (count > 0) {
|
||||
// a. Let fromKey be ! ToString(from).
|
||||
let fromKey = ToString(realm, new NumberValue(realm, from));
|
||||
|
||||
// b. Let toKey be ! ToString(to).
|
||||
let toKey = ToString(realm, new NumberValue(realm, to));
|
||||
|
||||
// c. Let fromPresent be ? HasProperty(O, fromKey).
|
||||
let fromPresent = HasProperty(realm, O, fromKey);
|
||||
|
||||
// d. If fromPresent is true, then
|
||||
if (fromPresent === true) {
|
||||
// i. Let fromVal be ? Get(O, fromKey).
|
||||
let fromVal = Get(realm, O, fromKey);
|
||||
// ii. Perform ? Set(O, toKey, fromVal, true).
|
||||
Set(realm, O, toKey, fromVal, true);
|
||||
} else { // e. Else fromPresent is false,
|
||||
// i. Perform ? DeletePropertyOrThrow(O, toKey).
|
||||
DeletePropertyOrThrow(realm, O, toKey);
|
||||
// c. Let to be to + count - 1.
|
||||
to = to + count - 1;
|
||||
} else {
|
||||
// 11. Else,
|
||||
// a. Let direction be 1.
|
||||
direction = 1;
|
||||
}
|
||||
|
||||
// f. Let from be from + direction.
|
||||
from = from + direction;
|
||||
// 12. Repeat, while count > 0
|
||||
while (count > 0) {
|
||||
// a. Let fromKey be ! ToString(from).
|
||||
let fromKey = ToString(realm, new NumberValue(realm, from));
|
||||
|
||||
// g. Let to be to + direction.
|
||||
to = to + direction;
|
||||
// b. Let toKey be ! ToString(to).
|
||||
let toKey = ToString(realm, new NumberValue(realm, to));
|
||||
|
||||
// h. Let count be count - 1.
|
||||
count = count - 1;
|
||||
}
|
||||
// c. Let fromPresent be ? HasProperty(O, fromKey).
|
||||
let fromPresent = HasProperty(realm, O, fromKey);
|
||||
|
||||
// 13. Return O.
|
||||
return O;
|
||||
});
|
||||
// d. If fromPresent is true, then
|
||||
if (fromPresent === true) {
|
||||
// i. Let fromVal be ? Get(O, fromKey).
|
||||
let fromVal = Get(realm, O, fromKey);
|
||||
// ii. Perform ? Set(O, toKey, fromVal, true).
|
||||
Set(realm, O, toKey, fromVal, true);
|
||||
} else {
|
||||
// e. Else fromPresent is false,
|
||||
// i. Perform ? DeletePropertyOrThrow(O, toKey).
|
||||
DeletePropertyOrThrow(realm, O, toKey);
|
||||
}
|
||||
|
||||
// f. Let from be from + direction.
|
||||
from = from + direction;
|
||||
|
||||
// g. Let to be to + direction.
|
||||
to = to + direction;
|
||||
|
||||
// h. Let count be count - 1.
|
||||
count = count - 1;
|
||||
}
|
||||
|
||||
// 13. Return O.
|
||||
return O;
|
||||
});
|
||||
|
||||
// ECMA262 22.1.3.4
|
||||
obj.defineNativeMethod("entries", 0, (context) => {
|
||||
obj.defineNativeMethod("entries", 0, context => {
|
||||
// 1. Let O be ? ToObject(this value).
|
||||
let O = ToObject(realm, context.throwIfNotConcrete());
|
||||
|
||||
@ -281,7 +284,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
let k = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len);
|
||||
|
||||
// 5. If end is undefined, let relativeEnd be len; else let relativeEnd be ? ToInteger(end).
|
||||
let relativeEnd = (!end || end instanceof UndefinedValue) ? len : ToInteger(realm, end.throwIfNotConcrete());
|
||||
let relativeEnd = !end || end instanceof UndefinedValue ? len : ToInteger(realm, end.throwIfNotConcrete());
|
||||
|
||||
// 6. If relativeEnd < 0, let final be max((len + relativeEnd), 0); else let final be min(relativeEnd, len).
|
||||
let final = relativeEnd < 0 ? Math.max(len + relativeEnd, 0) : Math.min(relativeEnd, len);
|
||||
@ -489,46 +492,47 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
|
||||
// ECMA262 22.1.3.11
|
||||
if (!realm.isCompatibleWith(realm.MOBILE_JSC_VERSION))
|
||||
obj.defineNativeMethod("includes", 1, (context, [searchElement, fromIndex]) => {
|
||||
// 1. Let O be ? ToObject(this value).
|
||||
let O = ToObject(realm, context.throwIfNotConcrete());
|
||||
obj.defineNativeMethod("includes", 1, (context, [searchElement, fromIndex]) => {
|
||||
// 1. Let O be ? ToObject(this value).
|
||||
let O = ToObject(realm, context.throwIfNotConcrete());
|
||||
|
||||
// 2. Let len be ? ToLength(? Get(O, "length")).
|
||||
let len = ToLength(realm, Get(realm, O, "length"));
|
||||
// 2. Let len be ? ToLength(? Get(O, "length")).
|
||||
let len = ToLength(realm, Get(realm, O, "length"));
|
||||
|
||||
// 3. If len is 0, return false.
|
||||
if (len === 0) return realm.intrinsics.false;
|
||||
// 3. If len is 0, return false.
|
||||
if (len === 0) return realm.intrinsics.false;
|
||||
|
||||
// 4. Let n be ? ToInteger(fromIndex). (If fromIndex is undefined, this step produces the value 0.)
|
||||
let n = ToInteger(realm, fromIndex || realm.intrinsics.undefined);
|
||||
// 4. Let n be ? ToInteger(fromIndex). (If fromIndex is undefined, this step produces the value 0.)
|
||||
let n = ToInteger(realm, fromIndex || realm.intrinsics.undefined);
|
||||
|
||||
let k;
|
||||
// 5. If n ≥ 0, then
|
||||
if (n >= 0) {
|
||||
// a. Let k be n.
|
||||
k = n;
|
||||
} else { // 6. Else n < 0,
|
||||
// a. Let k be len + n.
|
||||
k = len + n;
|
||||
// b. If k < 0, let k be 0.
|
||||
if (k < 0) k = 0;
|
||||
}
|
||||
let k;
|
||||
// 5. If n ≥ 0, then
|
||||
if (n >= 0) {
|
||||
// a. Let k be n.
|
||||
k = n;
|
||||
} else {
|
||||
// 6. Else n < 0,
|
||||
// a. Let k be len + n.
|
||||
k = len + n;
|
||||
// b. If k < 0, let k be 0.
|
||||
if (k < 0) k = 0;
|
||||
}
|
||||
|
||||
// 7. Repeat, while k < len
|
||||
while (k < len) {
|
||||
// a. Let elementK be the result of ? Get(O, ! ToString(k)).
|
||||
let elementK = Get(realm, O, ToString(realm, new NumberValue(realm, k)));
|
||||
// 7. Repeat, while k < len
|
||||
while (k < len) {
|
||||
// a. Let elementK be the result of ? Get(O, ! ToString(k)).
|
||||
let elementK = Get(realm, O, ToString(realm, new NumberValue(realm, k)));
|
||||
|
||||
// b. If SameValueZero(searchElement, elementK) is true, return true.
|
||||
if (SameValueZeroPartial(realm, searchElement, elementK) === true) return realm.intrinsics.true;
|
||||
// b. If SameValueZero(searchElement, elementK) is true, return true.
|
||||
if (SameValueZeroPartial(realm, searchElement, elementK) === true) return realm.intrinsics.true;
|
||||
|
||||
// c. Increase k by 1.
|
||||
k = k + 1;
|
||||
}
|
||||
// c. Increase k by 1.
|
||||
k = k + 1;
|
||||
}
|
||||
|
||||
// 8. Return false.
|
||||
return realm.intrinsics.false;
|
||||
});
|
||||
// 8. Return false.
|
||||
return realm.intrinsics.false;
|
||||
});
|
||||
|
||||
// ECMA262 22.1.3.12
|
||||
obj.defineNativeMethod("indexOf", 1, (context, [searchElement, fromIndex]) => {
|
||||
@ -552,7 +556,8 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
if (n >= 0) {
|
||||
// a. If n is -0, let k be +0; else let k be n.
|
||||
k = Object.is(n, -0) ? +0 : n;
|
||||
} else { // 7. Else n < 0,
|
||||
} else {
|
||||
// 7. Else n < 0,
|
||||
// a. Let k be len + n.
|
||||
k = len + n;
|
||||
|
||||
@ -644,7 +649,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 22.1.3.14
|
||||
obj.defineNativeMethod("keys", 0, (context) => {
|
||||
obj.defineNativeMethod("keys", 0, context => {
|
||||
// 1. Let O be ? ToObject(this value).
|
||||
let O = ToObject(realm, context.throwIfNotConcrete());
|
||||
|
||||
@ -671,7 +676,8 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
if (n >= 0) {
|
||||
// a. If n is -0, let k be +0; else let k be min(n, len - 1).
|
||||
k = Object.is(n, -0) ? +0 : Math.min(n, len - 1);
|
||||
} else { // 6. Else n < 0,
|
||||
} else {
|
||||
// 6. Else n < 0,
|
||||
// a. Let k be len + n.
|
||||
k = len + n;
|
||||
}
|
||||
@ -752,7 +758,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 22.1.3.17
|
||||
obj.defineNativeMethod("pop", 0, (context) => {
|
||||
obj.defineNativeMethod("pop", 0, context => {
|
||||
// 1. Let O be ? ToObject(this value).
|
||||
let O = ToObject(realm, context.throwIfNotConcrete());
|
||||
|
||||
@ -766,7 +772,8 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
|
||||
// b. Return undefined.
|
||||
return realm.intrinsics.undefined;
|
||||
} else { // 4. Else len > 0,
|
||||
} else {
|
||||
// 4. Else len > 0,
|
||||
// a. Let newLen be len-1.
|
||||
let newLen = len - 1;
|
||||
|
||||
@ -851,7 +858,8 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
if (initialValue) {
|
||||
// a. Set accumulator to initialValue.
|
||||
accumulator = initialValue;
|
||||
} else { // 7. Else initialValue is not present,
|
||||
} else {
|
||||
// 7. Else initialValue is not present,
|
||||
// a. Let kPresent be false.
|
||||
let kPresent = false;
|
||||
|
||||
@ -895,7 +903,12 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
let kValue = Get(realm, O, Pk);
|
||||
|
||||
// ii. Let accumulator be ? Call(callbackfn, undefined, « accumulator, kValue, k, O »).
|
||||
accumulator = Call(realm, callbackfn, realm.intrinsics.undefined, [accumulator, kValue, new NumberValue(realm, k), O]);
|
||||
accumulator = Call(realm, callbackfn, realm.intrinsics.undefined, [
|
||||
accumulator,
|
||||
kValue,
|
||||
new NumberValue(realm, k),
|
||||
O,
|
||||
]);
|
||||
}
|
||||
|
||||
// d. Increase k by 1.
|
||||
@ -932,7 +945,8 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
if (initialValue) {
|
||||
// 1. Set accumulator to initialValue.
|
||||
accumulator = initialValue;
|
||||
} else { // 7. Else initialValue is not present,
|
||||
} else {
|
||||
// 7. Else initialValue is not present,
|
||||
// a. Let kPresent be false.
|
||||
let kPresent = false;
|
||||
|
||||
@ -974,7 +988,12 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
let kValue = Get(realm, O, Pk);
|
||||
|
||||
// ii. Let accumulator be ? Call(callbackfn, undefined, « accumulator, kValue, k, O »).
|
||||
accumulator = Call(realm, callbackfn, realm.intrinsics.undefined, [accumulator, kValue, new NumberValue(realm, k), O]);
|
||||
accumulator = Call(realm, callbackfn, realm.intrinsics.undefined, [
|
||||
accumulator,
|
||||
kValue,
|
||||
new NumberValue(realm, k),
|
||||
O,
|
||||
]);
|
||||
}
|
||||
|
||||
// d. Decrease k by 1.
|
||||
@ -986,7 +1005,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 22.1.3.21
|
||||
obj.defineNativeMethod("reverse", 0, (context) => {
|
||||
obj.defineNativeMethod("reverse", 0, context => {
|
||||
// 1. Let O be ? ToObject(this value).
|
||||
let O = ToObject(realm, context.throwIfNotConcrete());
|
||||
|
||||
@ -1040,7 +1059,8 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
|
||||
// ii. Perform ? Set(O, upperP, lowerValue, true).
|
||||
Set(realm, O, upperP, lowerValue, true);
|
||||
} else if (!lowerExists && upperExists) { // i. Else if lowerExists is false and upperExists is true, then
|
||||
} else if (!lowerExists && upperExists) {
|
||||
// i. Else if lowerExists is false and upperExists is true, then
|
||||
invariant(upperValue, "expected upper value to exist");
|
||||
|
||||
// i. Perform ? Set(O, lowerP, upperValue, true).
|
||||
@ -1048,7 +1068,8 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
|
||||
// ii. Perform ? DeletePropertyOrThrow(O, upperP).
|
||||
DeletePropertyOrThrow(realm, O, upperP);
|
||||
} else if (lowerExists && !upperExists) { // j. Else if lowerExists is true and upperExists is false, then
|
||||
} else if (lowerExists && !upperExists) {
|
||||
// j. Else if lowerExists is true and upperExists is false, then
|
||||
invariant(lowerValue, "expected lower value to exist");
|
||||
|
||||
// i. Perform ? DeletePropertyOrThrow(O, lowerP).
|
||||
@ -1056,7 +1077,8 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
|
||||
// ii. Perform ? Set(O, upperP, lowerValue, true).
|
||||
Set(realm, O, upperP, lowerValue, true);
|
||||
} else { // k. Else both lowerExists and upperExists are false,
|
||||
} else {
|
||||
// k. Else both lowerExists and upperExists are false,
|
||||
// i. No action is required.
|
||||
}
|
||||
|
||||
@ -1069,7 +1091,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 22.1.3.22
|
||||
obj.defineNativeMethod("shift", 0, (context) => {
|
||||
obj.defineNativeMethod("shift", 0, context => {
|
||||
// 1. Let O be ? ToObject(this value).
|
||||
let O = ToObject(realm, context.throwIfNotConcrete());
|
||||
|
||||
@ -1097,7 +1119,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
let frm = new StringValue(realm, k + "");
|
||||
|
||||
// b. Let to be ! ToString(k-1).
|
||||
let to = new StringValue(realm, (k - 1) + "");
|
||||
let to = new StringValue(realm, k - 1 + "");
|
||||
|
||||
// c. Let fromPresent be ? HasProperty(O, from).
|
||||
let fromPresent = HasProperty(realm, O, frm);
|
||||
@ -1109,7 +1131,8 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
|
||||
// ii. Perform ? Set(O, to, fromVal, true).
|
||||
Set(realm, O, to, fromVal, true);
|
||||
} else { // d. Else fromPresent is false,
|
||||
} else {
|
||||
// d. Else fromPresent is false,
|
||||
// i. Perform ? DeletePropertyOrThrow(O, to).
|
||||
DeletePropertyOrThrow(realm, O, to);
|
||||
}
|
||||
@ -1119,7 +1142,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
}
|
||||
|
||||
// 7. Perform ? DeletePropertyOrThrow(O, ! ToString(len-1)).
|
||||
DeletePropertyOrThrow(realm, O, new StringValue(realm, (len - 1) + ""));
|
||||
DeletePropertyOrThrow(realm, O, new StringValue(realm, len - 1 + ""));
|
||||
|
||||
// 8. Perform ? Set(O, "length", len-1, true).
|
||||
Set(realm, O, "length", new NumberValue(realm, len - 1), true);
|
||||
@ -1198,8 +1221,10 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
|
||||
// 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
|
||||
if (!IsCallable(realm, callbackfn)) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError,
|
||||
"callback passed to Array.prototype.some isn't callable");
|
||||
throw realm.createErrorThrowCompletion(
|
||||
realm.intrinsics.TypeError,
|
||||
"callback passed to Array.prototype.some isn't callable"
|
||||
);
|
||||
}
|
||||
|
||||
// 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
|
||||
@ -1238,7 +1263,6 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
|
||||
// ECMA262 22.1.3.25
|
||||
obj.defineNativeMethod("sort", 1, (context, [comparefn]) => {
|
||||
|
||||
// 1. Let obj be ? ToObject(this value).
|
||||
let O = ToObject(realm, context.throwIfNotConcrete());
|
||||
|
||||
@ -1248,7 +1272,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
// Within this specification of the sort method, an object, obj, is said to be sparse if the following algorithm returns true:
|
||||
let isSparse = () => {
|
||||
// 1.For each integer i in the range 0≤i< len
|
||||
for (let i = 0; i < len; i++){
|
||||
for (let i = 0; i < len; i++) {
|
||||
// a.Let elem be obj.[[GetOwnProperty]](! ToString(i)).
|
||||
let elem = O.$GetOwnProperty(i.toString());
|
||||
// b.If elem is undefined, return true.
|
||||
@ -1265,29 +1289,32 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
|
||||
// If proto is not null
|
||||
if (!(proto instanceof NullValue)) {
|
||||
// and there exists an integer j such that all of the conditions below are satisfied then the sort order is implementation-defined:
|
||||
for (let j = 0; j < len; j++){
|
||||
// HasProperty(proto, ToString(j)) is true.
|
||||
if (HasProperty(realm, proto, j.toString())
|
||||
// obj is sparse
|
||||
&& sparse)
|
||||
// We abord when the result of the sort is implementation defined.
|
||||
throw Error("Implentation defined behavior detected");
|
||||
}
|
||||
// and there exists an integer j such that all of the conditions below are satisfied then the sort order is implementation-defined:
|
||||
for (let j = 0; j < len; j++) {
|
||||
// HasProperty(proto, ToString(j)) is true.
|
||||
if (
|
||||
HasProperty(realm, proto, j.toString()) &&
|
||||
// obj is sparse
|
||||
sparse
|
||||
)
|
||||
// We abord when the result of the sort is implementation defined.
|
||||
throw Error("Implentation defined behavior detected");
|
||||
}
|
||||
}
|
||||
|
||||
// The sort order is also implementation defined if obj is sparse and any of the following conditions are true:
|
||||
if (sparse) {
|
||||
// IsExtensible(obj) is false.
|
||||
if (!IsExtensible(realm, O))
|
||||
throw Error("Implementation defined behavior, Array is both sparse and extensible");
|
||||
if (!IsExtensible(realm, O)) throw Error("Implementation defined behavior, Array is both sparse and extensible");
|
||||
// Any integer index property of obj whose name is a nonnegative integer less than len
|
||||
for (let j = 0; j < len; j++){
|
||||
for (let j = 0; j < len; j++) {
|
||||
// is a data property whose [[Configurable]] attribute is false.
|
||||
let prop = O.$GetOwnProperty(j.toString());
|
||||
if (prop !== undefined && !prop.configurable) {
|
||||
ThrowIfMightHaveBeenDeleted(prop.value);
|
||||
throw Error("Implementation defined behavior : Array is sparse and it's prototype has some numbered properties");
|
||||
throw Error(
|
||||
"Implementation defined behavior : Array is sparse and it's prototype has some numbered properties"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1297,7 +1324,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
// is not the ordinary object implementation of these internal methods.
|
||||
|
||||
// Any integer index property of obj whose name is a nonnegative integer less than len
|
||||
for (let j = 0; j < len; j++){
|
||||
for (let j = 0; j < len; j++) {
|
||||
//is a data property whose [[writable]] attribute is false.
|
||||
let prop = O.$GetOwnProperty(j.toString());
|
||||
if (prop !== undefined && !prop.writable) {
|
||||
@ -1306,7 +1333,6 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO If comparefn is undefined and the application of ToString to any value passed as an argument to SortCompare modifies obj or any object on obj's prototype chain.
|
||||
// TODO If comparefn is undefined and all applications of ToString, to any specific value passed as an argument to SortCompare, do not produce the same result.
|
||||
|
||||
@ -1356,15 +1382,12 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
return realm.intrinsics.zero;
|
||||
};
|
||||
|
||||
|
||||
//1. Perform an implementation-dependent sequence of calls to the [[Get]] and [[Set]] internal methods of obj, to the DeletePropertyOrThrow and HasOwnProperty abstract operation with obj as the first argument, and to SortCompare (described below), such that:
|
||||
// The property key argument for each call to [[Get]], [[Set]], HasOwnProperty, or DeletePropertyOrThrow is the string representation of a nonnegative integer less than len.
|
||||
|
||||
|
||||
// We leverage the underlying implementation sort by copying the element in a temp. array, sorting it, and
|
||||
// transfering back the value inside the our array.
|
||||
|
||||
|
||||
let arr = [];
|
||||
|
||||
// We need to adapt the comparefn function to match the expected types
|
||||
@ -1379,8 +1402,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
|
||||
for (let j = 0; j < len; j++) {
|
||||
// The property key argument for each call to [[Get]], [[Set]], HasOwnProperty, or DeletePropertyOrThrow is the string representation of a nonnegative integer less than len.
|
||||
if (!(HasOwnProperty(realm, O, j.toString())))
|
||||
continue;
|
||||
if (!HasOwnProperty(realm, O, j.toString())) continue;
|
||||
// The arguments for calls to SortCompare are values returned by a previous call to the [[Get]] internal method,
|
||||
// unless the properties accessed by those previous calls did not exist according to HasOwnProperty.
|
||||
|
||||
@ -1395,13 +1417,11 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
arr.sort(comparefn_);
|
||||
|
||||
//Apply the permutation back to the original array.
|
||||
for (let j = 0; j < len; j++){
|
||||
if (arr.hasOwnProperty(j.toString())){
|
||||
for (let j = 0; j < len; j++) {
|
||||
if (arr.hasOwnProperty(j.toString())) {
|
||||
let ok = O.$Set(j.toString(), arr[j], O);
|
||||
// If any [[Set]] call returns false a TypeError exception is thrown.
|
||||
if (!ok)
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "[[Set]] returned false");
|
||||
|
||||
if (!ok) throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "[[Set]] returned false");
|
||||
} else {
|
||||
// If obj is not sparse then DeletePropertyOrThrow must not be called.
|
||||
invariant(sparse);
|
||||
@ -1438,13 +1458,15 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
|
||||
// b. Let actualDeleteCount be 0.
|
||||
actualDeleteCount = 0;
|
||||
} else if (argLength === 1) { // 6. Else if the number of actual arguments is 1, then
|
||||
} else if (argLength === 1) {
|
||||
// 6. Else if the number of actual arguments is 1, then
|
||||
// a. Let insertCount be 0.
|
||||
insertCount = 0;
|
||||
|
||||
// b. Let actualDeleteCount be len - actualStart.
|
||||
actualDeleteCount = len - actualStart;
|
||||
} else { // 7. Else,
|
||||
} else {
|
||||
// 7. Else,
|
||||
// a. Let insertCount be the number of actual arguments minus 2.
|
||||
insertCount = argLength - 2;
|
||||
|
||||
@ -1469,7 +1491,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
// 11. Repeat, while k < actualDeleteCount
|
||||
while (k < actualDeleteCount) {
|
||||
// a. Let from be ! ToString(actualStart+k).
|
||||
let frm = new StringValue(realm, (actualStart + k) + "");
|
||||
let frm = new StringValue(realm, actualStart + k + "");
|
||||
|
||||
// b. Let fromPresent be ? HasProperty(O, from).
|
||||
let fromPresent = HasProperty(realm, O, frm);
|
||||
@ -1505,10 +1527,10 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
// b. Repeat, while k < (len - actualDeleteCount)
|
||||
while (k < len - actualDeleteCount) {
|
||||
// i. Let from be ! ToString(k+actualDeleteCount).
|
||||
let frm = new StringValue(realm, (k + actualDeleteCount) + "");
|
||||
let frm = new StringValue(realm, k + actualDeleteCount + "");
|
||||
|
||||
// ii. Let to be ! ToString(k+itemCount).
|
||||
let to = new StringValue(realm, (k + itemCount) + "");
|
||||
let to = new StringValue(realm, k + itemCount + "");
|
||||
|
||||
// iii. Let fromPresent be ? HasProperty(O, from).
|
||||
let fromPresent = HasProperty(realm, O, frm);
|
||||
@ -1520,7 +1542,8 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
|
||||
// 2. Perform ? Set(O, to, fromValue, true).
|
||||
Set(realm, O, to, fromValue, true);
|
||||
} else { // v. Else fromPresent is false,
|
||||
} else {
|
||||
// v. Else fromPresent is false,
|
||||
// 1. Perform ? DeletePropertyOrThrow(O, to).
|
||||
DeletePropertyOrThrow(realm, O, to);
|
||||
}
|
||||
@ -1535,22 +1558,23 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
// d. Repeat, while k > (len - actualDeleteCount + itemCount)
|
||||
while (k > len - actualDeleteCount + itemCount) {
|
||||
// i. Perform ? DeletePropertyOrThrow(O, ! ToString(k-1)).
|
||||
DeletePropertyOrThrow(realm, O, new StringValue(realm, (k - 1) + ""));
|
||||
DeletePropertyOrThrow(realm, O, new StringValue(realm, k - 1 + ""));
|
||||
|
||||
// ii. Decrease k by 1.
|
||||
k--;
|
||||
}
|
||||
} else if (itemCount > actualDeleteCount) { // 16. Else if itemCount > actualDeleteCount, then
|
||||
} else if (itemCount > actualDeleteCount) {
|
||||
// 16. Else if itemCount > actualDeleteCount, then
|
||||
// a. Let k be (len - actualDeleteCount).
|
||||
k = len - actualDeleteCount;
|
||||
|
||||
// b. Repeat, while k > actualStart
|
||||
while (k > actualStart) {
|
||||
// i. Let from be ! ToString(k + actualDeleteCount - 1).
|
||||
let frm = new StringValue(realm, (k + actualDeleteCount - 1) + "");
|
||||
let frm = new StringValue(realm, k + actualDeleteCount - 1 + "");
|
||||
|
||||
// ii. Let to be ! ToString(k + itemCount - 1).
|
||||
let to = new StringValue(realm, (k + itemCount - 1) + "");
|
||||
let to = new StringValue(realm, k + itemCount - 1 + "");
|
||||
|
||||
// iii. Let fromPresent be ? HasProperty(O, from).
|
||||
let fromPresent = HasProperty(realm, O, frm);
|
||||
@ -1562,7 +1586,8 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
|
||||
// 2. Perform ? Set(O, to, fromValue, true).
|
||||
Set(realm, O, to, fromValue, true);
|
||||
} else { // v. Else fromPresent is false,
|
||||
} else {
|
||||
// v. Else fromPresent is false,
|
||||
// 1. Perform ? DeletePropertyOrThrow(O, to).
|
||||
DeletePropertyOrThrow(realm, O, to);
|
||||
}
|
||||
@ -1595,7 +1620,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 22.1.3.27
|
||||
obj.defineNativeMethod("toLocaleString", 0, (context) => {
|
||||
obj.defineNativeMethod("toLocaleString", 0, context => {
|
||||
// 1. Let array be ? ToObject(this value).
|
||||
let array = ToObject(realm, context.throwIfNotConcrete());
|
||||
|
||||
@ -1617,7 +1642,8 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
if (HasSomeCompatibleType(firstElement, UndefinedValue, NullValue)) {
|
||||
// a. Let R be the empty String.
|
||||
R = "";
|
||||
} else { // 7. Else,
|
||||
} else {
|
||||
// 7. Else,
|
||||
// a. Let R be ? ToString(? Invoke(firstElement, "toLocaleString")).
|
||||
R = ToStringPartial(realm, Invoke(realm, firstElement, "toLocaleString"));
|
||||
}
|
||||
@ -1637,7 +1663,8 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
if (HasSomeCompatibleType(nextElement, UndefinedValue, NullValue)) {
|
||||
// i. Let R be the empty String.
|
||||
R = "";
|
||||
} else { // d. Else,
|
||||
} else {
|
||||
// d. Else,
|
||||
// i. Let R be ? ToString(? Invoke(nextElement, "toLocaleString")).
|
||||
R = ToStringPartial(realm, Invoke(realm, nextElement, "toLocaleString"));
|
||||
}
|
||||
@ -1680,10 +1707,10 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
// c. Repeat, while k > 0,
|
||||
while (k > 0) {
|
||||
// i. Let from be ! ToString(k-1).
|
||||
let frm = new StringValue(realm, (k - 1) + "");
|
||||
let frm = new StringValue(realm, k - 1 + "");
|
||||
|
||||
// ii. Let to be ! ToString(k+argCount-1).
|
||||
let to = new StringValue(realm, (k + argCount - 1) + "");
|
||||
let to = new StringValue(realm, k + argCount - 1 + "");
|
||||
|
||||
// iv. Let fromPresent be ? HasProperty(O, from).
|
||||
let fromPresent = HasProperty(realm, O, frm);
|
||||
@ -1695,7 +1722,8 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
|
||||
// 2. Perform ? Set(O, to, fromValue, true).
|
||||
Set(realm, O, to, fromValue, true);
|
||||
} else { // vi. Else fromPresent is false,
|
||||
} else {
|
||||
// vi. Else fromPresent is false,
|
||||
// 1. Perform ? DeletePropertyOrThrow(O, to).
|
||||
DeletePropertyOrThrow(realm, O, to);
|
||||
}
|
||||
@ -1767,7 +1795,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
|
||||
// 11. Return unscopableList.
|
||||
obj.defineNativeProperty(realm.intrinsics.SymbolUnscopables, unscopableList, {
|
||||
writable: false
|
||||
writable: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import { NativeFunctionValue, BooleanValue } from "../../values/index.js";
|
||||
import { OrdinaryCreateFromConstructor } from "../../methods/create.js";
|
||||
import { ToBooleanPartial } from "../../methods/to.js";
|
||||
|
||||
export default function (realm: Realm): NativeFunctionValue {
|
||||
export default function(realm: Realm): NativeFunctionValue {
|
||||
// ECMA262 19.3.1.1
|
||||
let func = new NativeFunctionValue(realm, "Boolean", "Boolean", 1, (context, [value], argCount, NewTarget) => {
|
||||
// 1. Let b be ToBoolean(value).
|
||||
|
@ -13,12 +13,12 @@ import type { Realm } from "../../realm.js";
|
||||
import { ObjectValue, StringValue } from "../../values/index.js";
|
||||
import { thisBooleanValue } from "../../methods/to.js";
|
||||
|
||||
export default function (realm: Realm, obj: ObjectValue): void {
|
||||
export default function(realm: Realm, obj: ObjectValue): void {
|
||||
// ECMA262 19.3.1
|
||||
obj.$BooleanData = realm.intrinsics.false;
|
||||
|
||||
// ECMA262 19.3.3.3
|
||||
obj.defineNativeMethod("toString", 0, (context) => {
|
||||
obj.defineNativeMethod("toString", 0, context => {
|
||||
// 1. Let b be ? thisBooleanValue(this value).
|
||||
let b = thisBooleanValue(realm, context);
|
||||
|
||||
@ -27,7 +27,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 19.3.3.4
|
||||
obj.defineNativeMethod("valueOf", 0, (context) => {
|
||||
obj.defineNativeMethod("valueOf", 0, context => {
|
||||
// 1. Return ? thisBooleanValue(this value).
|
||||
return thisBooleanValue(realm, context);
|
||||
});
|
||||
|
@ -10,88 +10,91 @@
|
||||
/* @flow */
|
||||
|
||||
import type { Realm } from "../../realm.js";
|
||||
import {
|
||||
ToIndexPartial,
|
||||
OrdinaryCreateFromConstructor,
|
||||
IsDetachedBuffer,
|
||||
} from "../../methods/index.js";
|
||||
import { ToIndexPartial, OrdinaryCreateFromConstructor, IsDetachedBuffer } from "../../methods/index.js";
|
||||
import { NativeFunctionValue, ObjectValue, UndefinedValue } from "../../values/index.js";
|
||||
import invariant from "../../invariant.js";
|
||||
|
||||
export default function (realm: Realm): NativeFunctionValue {
|
||||
export default function(realm: Realm): NativeFunctionValue {
|
||||
// ECMA262 24.2.2.1
|
||||
let func = new NativeFunctionValue(realm, "DataView", "DataView", 3, (context, [buffer, byteOffset, byteLength], argCount, NewTarget) => {
|
||||
// 1. If NewTarget is undefined, throw a TypeError exception.
|
||||
if (!NewTarget) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
|
||||
}
|
||||
let func = new NativeFunctionValue(
|
||||
realm,
|
||||
"DataView",
|
||||
"DataView",
|
||||
3,
|
||||
(context, [buffer, byteOffset, byteLength], argCount, NewTarget) => {
|
||||
// 1. If NewTarget is undefined, throw a TypeError exception.
|
||||
if (!NewTarget) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
|
||||
}
|
||||
|
||||
buffer = buffer.throwIfNotConcrete();
|
||||
// 2. If Type(buffer) is not Object, throw a TypeError exception.
|
||||
if (!(buffer instanceof ObjectValue)) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
|
||||
}
|
||||
buffer = buffer.throwIfNotConcrete();
|
||||
// 2. If Type(buffer) is not Object, throw a TypeError exception.
|
||||
if (!(buffer instanceof ObjectValue)) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
|
||||
}
|
||||
|
||||
// 3. If buffer does not have an [[ArrayBufferData]] internal slot, throw a TypeError exception.
|
||||
if (!('$ArrayBufferData' in buffer)) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
|
||||
}
|
||||
// 3. If buffer does not have an [[ArrayBufferData]] internal slot, throw a TypeError exception.
|
||||
if (!("$ArrayBufferData" in buffer)) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
|
||||
}
|
||||
|
||||
// 4. Let offset be ? ToIndex(byteOffset).
|
||||
let offset = ToIndexPartial(realm, byteOffset);
|
||||
// 4. Let offset be ? ToIndex(byteOffset).
|
||||
let offset = ToIndexPartial(realm, byteOffset);
|
||||
|
||||
// 5. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
|
||||
if (IsDetachedBuffer(realm, buffer)) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
|
||||
}
|
||||
// 5. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
|
||||
if (IsDetachedBuffer(realm, buffer)) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
|
||||
}
|
||||
|
||||
// 6. Let bufferByteLength be the value of buffer's [[ArrayBufferByteLength]] internal slot.
|
||||
let bufferByteLength = buffer.$ArrayBufferByteLength;
|
||||
invariant(typeof bufferByteLength === "number");
|
||||
// 6. Let bufferByteLength be the value of buffer's [[ArrayBufferByteLength]] internal slot.
|
||||
let bufferByteLength = buffer.$ArrayBufferByteLength;
|
||||
invariant(typeof bufferByteLength === "number");
|
||||
|
||||
// 7. If offset > bufferByteLength, throw a RangeError exception.
|
||||
if (offset > bufferByteLength) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.RangeError);
|
||||
}
|
||||
|
||||
// 8. If byteLength is undefined, then
|
||||
let viewByteLength;
|
||||
if (!byteLength || byteLength instanceof UndefinedValue) {
|
||||
// a. Let viewByteLength be bufferByteLength - offset.
|
||||
viewByteLength = bufferByteLength - offset;
|
||||
} else { // 9. Else,
|
||||
// a. Let viewByteLength be ? ToIndex(byteLength).
|
||||
viewByteLength = ToIndexPartial(realm, byteLength);
|
||||
|
||||
// b. If offset+viewByteLength > bufferByteLength, throw a RangeError exception.
|
||||
if (offset + viewByteLength > bufferByteLength) {
|
||||
// 7. If offset > bufferByteLength, throw a RangeError exception.
|
||||
if (offset > bufferByteLength) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.RangeError);
|
||||
}
|
||||
|
||||
// 8. If byteLength is undefined, then
|
||||
let viewByteLength;
|
||||
if (!byteLength || byteLength instanceof UndefinedValue) {
|
||||
// a. Let viewByteLength be bufferByteLength - offset.
|
||||
viewByteLength = bufferByteLength - offset;
|
||||
} else {
|
||||
// 9. Else,
|
||||
// a. Let viewByteLength be ? ToIndex(byteLength).
|
||||
viewByteLength = ToIndexPartial(realm, byteLength);
|
||||
|
||||
// b. If offset+viewByteLength > bufferByteLength, throw a RangeError exception.
|
||||
if (offset + viewByteLength > bufferByteLength) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.RangeError);
|
||||
}
|
||||
}
|
||||
|
||||
// 10. Let O be ? OrdinaryCreateFromConstructor(NewTarget, "%DataViewPrototype%", « [[DataView]], [[ViewedArrayBuffer]], [[ByteLength]], [[ByteOffset]] »).
|
||||
let O = OrdinaryCreateFromConstructor(realm, NewTarget, "DataViewPrototype", {
|
||||
$DataView: undefined,
|
||||
$ViewedArrayBuffer: undefined,
|
||||
$ByteLength: undefined,
|
||||
$ByteOffset: undefined,
|
||||
});
|
||||
|
||||
// 11. Set O's [[DataView]] internal slot to true.
|
||||
O.$DataView = true;
|
||||
|
||||
// 12. Set O's [[ViewedArrayBuffer]] internal slot to buffer.
|
||||
O.$ViewedArrayBuffer = buffer;
|
||||
|
||||
// 13. Set O's [[ByteLength]] internal slot to viewByteLength.
|
||||
O.$ByteLength = viewByteLength;
|
||||
|
||||
// 14. Set O's [[ByteOffset]] internal slot to offset.
|
||||
O.$ByteOffset = offset;
|
||||
|
||||
// 15. Return O.
|
||||
return O;
|
||||
}
|
||||
|
||||
// 10. Let O be ? OrdinaryCreateFromConstructor(NewTarget, "%DataViewPrototype%", « [[DataView]], [[ViewedArrayBuffer]], [[ByteLength]], [[ByteOffset]] »).
|
||||
let O = OrdinaryCreateFromConstructor(realm, NewTarget, "DataViewPrototype", {
|
||||
$DataView: undefined,
|
||||
$ViewedArrayBuffer: undefined,
|
||||
$ByteLength: undefined,
|
||||
$ByteOffset: undefined
|
||||
});
|
||||
|
||||
// 11. Set O's [[DataView]] internal slot to true.
|
||||
O.$DataView = true;
|
||||
|
||||
// 12. Set O's [[ViewedArrayBuffer]] internal slot to buffer.
|
||||
O.$ViewedArrayBuffer = buffer;
|
||||
|
||||
// 13. Set O's [[ByteLength]] internal slot to viewByteLength.
|
||||
O.$ByteLength = viewByteLength;
|
||||
|
||||
// 14. Set O's [[ByteOffset]] internal slot to offset.
|
||||
O.$ByteOffset = offset;
|
||||
|
||||
// 15. Return O.
|
||||
return O;
|
||||
});
|
||||
);
|
||||
|
||||
return func;
|
||||
}
|
||||
|
@ -15,9 +15,9 @@ import { IsDetachedBuffer } from "../../methods/is.js";
|
||||
import { GetViewValue, SetViewValue } from "../../methods/arraybuffer.js";
|
||||
import invariant from "../../invariant.js";
|
||||
|
||||
export default function (realm: Realm, obj: ObjectValue): void {
|
||||
export default function(realm: Realm, obj: ObjectValue): void {
|
||||
// ECMA262 24.2.4.1
|
||||
obj.defineNativeGetter("buffer", (context) => {
|
||||
obj.defineNativeGetter("buffer", context => {
|
||||
// 1. Let O be the this value.
|
||||
let O = context.throwIfNotConcrete();
|
||||
|
||||
@ -27,8 +27,11 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
}
|
||||
|
||||
// 3. If O does not have a [[DataView]] internal slot, throw a TypeError exception.
|
||||
if (!('$DataView' in O)) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "O does not have a [[DataView]] internal slot");
|
||||
if (!("$DataView" in O)) {
|
||||
throw realm.createErrorThrowCompletion(
|
||||
realm.intrinsics.TypeError,
|
||||
"O does not have a [[DataView]] internal slot"
|
||||
);
|
||||
}
|
||||
|
||||
// 4. Assert: O has a [[ViewedArrayBuffer]] internal slot.
|
||||
@ -42,7 +45,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 24.2.4.2
|
||||
obj.defineNativeGetter("byteLength", (context) => {
|
||||
obj.defineNativeGetter("byteLength", context => {
|
||||
// 1. Let O be the this value.
|
||||
let O = context.throwIfNotConcrete();
|
||||
|
||||
@ -52,8 +55,11 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
}
|
||||
|
||||
// 3. If O does not have a [[DataView]] internal slot, throw a TypeError exception.
|
||||
if (!('$DataView' in O)) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "O does not have a [[DataView]] internal slot");
|
||||
if (!("$DataView" in O)) {
|
||||
throw realm.createErrorThrowCompletion(
|
||||
realm.intrinsics.TypeError,
|
||||
"O does not have a [[DataView]] internal slot"
|
||||
);
|
||||
}
|
||||
|
||||
// 4. Assert: O has a [[ViewedArrayBuffer]] internal slot.
|
||||
@ -76,7 +82,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 24.2.4.3
|
||||
obj.defineNativeGetter("byteOffset", (context) => {
|
||||
obj.defineNativeGetter("byteOffset", context => {
|
||||
// 1. Let O be the this value.
|
||||
let O = context.throwIfNotConcrete();
|
||||
|
||||
@ -86,8 +92,11 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
}
|
||||
|
||||
// 3. If O does not have a [[DataView]] internal slot, throw a TypeError exception.
|
||||
if (!('$DataView' in O)) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "O does not have a [[DataView]] internal slot");
|
||||
if (!("$DataView" in O)) {
|
||||
throw realm.createErrorThrowCompletion(
|
||||
realm.intrinsics.TypeError,
|
||||
"O does not have a [[DataView]] internal slot"
|
||||
);
|
||||
}
|
||||
|
||||
// 4. Assert: O has a [[ViewedArrayBuffer]] internal slot.
|
||||
|
@ -21,13 +21,18 @@ import seedrandom from "seedrandom";
|
||||
|
||||
let buildDateNow = buildExpressionTemplate("global.Date.now()");
|
||||
|
||||
export default function (realm: Realm): NativeFunctionValue {
|
||||
export default function(realm: Realm): NativeFunctionValue {
|
||||
let lastNow;
|
||||
let offsetGenerator;
|
||||
function getCurrentTime(): AbstractValue | NumberValue {
|
||||
if (realm.useAbstractInterpretation) {
|
||||
let dummyArg = new StringValue(realm, "__Date.now()");
|
||||
let tmp = realm.deriveAbstract(new TypesDomain(NumberValue), ValuesDomain.topVal, [dummyArg], buildDateNow(realm.preludeGenerator));
|
||||
let tmp = realm.deriveAbstract(
|
||||
new TypesDomain(NumberValue),
|
||||
ValuesDomain.topVal,
|
||||
[dummyArg],
|
||||
buildDateNow(realm.preludeGenerator)
|
||||
);
|
||||
invariant(tmp instanceof AbstractValue, "getCurrentTime() should always return and abstract value");
|
||||
return tmp;
|
||||
} else {
|
||||
@ -97,7 +102,8 @@ export default function (realm: Realm): NativeFunctionValue {
|
||||
|
||||
// l. Return O.
|
||||
return O;
|
||||
} else { // 4. Else,
|
||||
} else {
|
||||
// 4. Else,
|
||||
// a. Let now be the Number that is the time value (UTC) identifying the current time.
|
||||
let now = getCurrentTime().throwIfNotConcreteNumber().value;
|
||||
|
||||
@ -123,7 +129,8 @@ export default function (realm: Realm): NativeFunctionValue {
|
||||
if (value instanceof ObjectValue && value.$DateValue !== undefined) {
|
||||
// i. Let tv be thisTimeValue(value).
|
||||
tv = thisTimeValue(realm, value);
|
||||
} else { // b. Else,
|
||||
} else {
|
||||
// b. Else,
|
||||
// i. Let v be ? ToPrimitive(value)
|
||||
let v = ToPrimitive(realm, value);
|
||||
|
||||
@ -131,10 +138,11 @@ export default function (realm: Realm): NativeFunctionValue {
|
||||
if (v instanceof StringValue) {
|
||||
// 1. Let tv be the result of parsing v as a date, in exactly the same manner as for the parse
|
||||
// method (20.3.3.2). If the parse resulted in an abrupt completion, tv is the Completion Record.
|
||||
tv = new NumberValue(realm, (new Date(v.value)).getTime());
|
||||
tv = new NumberValue(realm, new Date(v.value).getTime());
|
||||
|
||||
// 2. ReturnIfAbrupt(tv).
|
||||
} else { // iii. Else,
|
||||
} else {
|
||||
// iii. Else,
|
||||
// 1. Let tv be ? ToNumber(v).
|
||||
tv = new NumberValue(realm, ToNumber(realm, v));
|
||||
}
|
||||
@ -148,7 +156,8 @@ export default function (realm: Realm): NativeFunctionValue {
|
||||
|
||||
// e. Return O.
|
||||
return O;
|
||||
} else { // 4. Else,
|
||||
} else {
|
||||
// 4. Else,
|
||||
// a. Let now be the Number that is the time value (UTC) identifying the current time.
|
||||
let now = getCurrentTime().throwIfNotConcreteNumber().value;
|
||||
|
||||
@ -174,7 +183,8 @@ export default function (realm: Realm): NativeFunctionValue {
|
||||
|
||||
// c. Return O.
|
||||
return O;
|
||||
} else { // 4. Else,
|
||||
} else {
|
||||
// 4. Else,
|
||||
// a. Let now be the Number that is the time value (UTC) identifying the current time.
|
||||
let now = getCurrentTime().throwIfNotConcreteNumber().value;
|
||||
|
||||
@ -185,7 +195,7 @@ export default function (realm: Realm): NativeFunctionValue {
|
||||
});
|
||||
|
||||
// ECMA262 20.3.3.1
|
||||
func.defineNativeMethod("now", 0, (context) => {
|
||||
func.defineNativeMethod("now", 0, context => {
|
||||
return getCurrentTime();
|
||||
});
|
||||
|
||||
@ -223,7 +233,7 @@ export default function (realm: Realm): NativeFunctionValue {
|
||||
let milli = argCount >= 7 ? ToNumber(realm, ms) : 0;
|
||||
|
||||
// 8. If y is not NaN and 0 ≤ ToInteger(y) ≤ 99, let yr be 1900+ToInteger(y); otherwise, let yr be y.
|
||||
let yr = (!isNaN(y) && ToInteger(realm, y) >= 0 && ToInteger(realm, y) <= 99) ? 1900 + ToInteger(realm, y) : y;
|
||||
let yr = !isNaN(y) && ToInteger(realm, y) >= 0 && ToInteger(realm, y) <= 99 ? 1900 + ToInteger(realm, y) : y;
|
||||
|
||||
// 9. Return TimeClip(MakeDate(MakeDay(yr, m, dt), MakeTime(h, min, s, milli))).
|
||||
return TimeClip(realm, MakeDate(realm, MakeDay(realm, yr, m, dt), MakeTime(realm, h, min, s, milli)));
|
||||
|
@ -40,9 +40,9 @@ import {
|
||||
} from "../../methods/index.js";
|
||||
import invariant from "../../invariant.js";
|
||||
|
||||
export default function (realm: Realm, obj: ObjectValue): void {
|
||||
export default function(realm: Realm, obj: ObjectValue): void {
|
||||
// ECMA262 20.3.4.2
|
||||
obj.defineNativeMethod("getDate", 0, (context) => {
|
||||
obj.defineNativeMethod("getDate", 0, context => {
|
||||
// 1. Let t be ? thisTimeValue(this value).
|
||||
let t = thisTimeValue(realm, context).throwIfNotConcreteNumber().value;
|
||||
|
||||
@ -54,7 +54,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 20.3.4.3
|
||||
obj.defineNativeMethod("getDay", 0, (context) => {
|
||||
obj.defineNativeMethod("getDay", 0, context => {
|
||||
// 1. Let t be ? thisTimeValue(this value).
|
||||
let t = thisTimeValue(realm, context).throwIfNotConcreteNumber().value;
|
||||
|
||||
@ -66,7 +66,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 20.3.4.4
|
||||
obj.defineNativeMethod("getFullYear", 0, (context) => {
|
||||
obj.defineNativeMethod("getFullYear", 0, context => {
|
||||
// 1. Let t be ? thisTimeValue(this value).
|
||||
let t = thisTimeValue(realm, context).throwIfNotConcreteNumber().value;
|
||||
|
||||
@ -78,7 +78,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 20.3.4.5
|
||||
obj.defineNativeMethod("getHours", 0, (context) => {
|
||||
obj.defineNativeMethod("getHours", 0, context => {
|
||||
// 1. Let t be ? thisTimeValue(this value).
|
||||
let t = thisTimeValue(realm, context).throwIfNotConcreteNumber().value;
|
||||
|
||||
@ -90,7 +90,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 20.3.4.6
|
||||
obj.defineNativeMethod("getMilliseconds", 0, (context) => {
|
||||
obj.defineNativeMethod("getMilliseconds", 0, context => {
|
||||
// 1. Let t be ? thisTimeValue(this value).
|
||||
let t = thisTimeValue(realm, context).throwIfNotConcreteNumber().value;
|
||||
|
||||
@ -102,7 +102,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 20.3.4.7
|
||||
obj.defineNativeMethod("getMinutes", 0, (context) => {
|
||||
obj.defineNativeMethod("getMinutes", 0, context => {
|
||||
// 1. Let t be ? thisTimeValue(this value).
|
||||
let t = thisTimeValue(realm, context).throwIfNotConcreteNumber().value;
|
||||
|
||||
@ -114,7 +114,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 20.3.4.8
|
||||
obj.defineNativeMethod("getMonth", 0, (context) => {
|
||||
obj.defineNativeMethod("getMonth", 0, context => {
|
||||
// 1. Let t be ? thisTimeValue(this value).
|
||||
let t = thisTimeValue(realm, context).throwIfNotConcreteNumber().value;
|
||||
|
||||
@ -126,7 +126,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 20.3.4.9
|
||||
obj.defineNativeMethod("getSeconds", 0, (context) => {
|
||||
obj.defineNativeMethod("getSeconds", 0, context => {
|
||||
// 1. Let t be ? thisTimeValue(this value).
|
||||
let t = thisTimeValue(realm, context).throwIfNotConcreteNumber().value;
|
||||
|
||||
@ -138,13 +138,13 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 20.3.4.10
|
||||
obj.defineNativeMethod("getTime", 0, (context) => {
|
||||
obj.defineNativeMethod("getTime", 0, context => {
|
||||
// 1. Return ? thisTimeValue(this value).
|
||||
return thisTimeValue(realm, context);
|
||||
});
|
||||
|
||||
// ECMA262 20.3.4.11
|
||||
obj.defineNativeMethod("getTimezoneOffset", 0, (context) => {
|
||||
obj.defineNativeMethod("getTimezoneOffset", 0, context => {
|
||||
// 1. Let t be ? thisTimeValue(this value).
|
||||
let t = thisTimeValue(realm, context).throwIfNotConcreteNumber().value;
|
||||
|
||||
@ -156,7 +156,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 20.3.4.12
|
||||
obj.defineNativeMethod("getUTCDate", 0, (context) => {
|
||||
obj.defineNativeMethod("getUTCDate", 0, context => {
|
||||
// 1. Let t be ? thisTimeValue(this value).
|
||||
let t = thisTimeValue(realm, context).throwIfNotConcreteNumber().value;
|
||||
|
||||
@ -168,7 +168,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 20.3.4.13
|
||||
obj.defineNativeMethod("getUTCDay", 0, (context) => {
|
||||
obj.defineNativeMethod("getUTCDay", 0, context => {
|
||||
// 1. Let t be ? thisTimeValue(this value).
|
||||
let t = thisTimeValue(realm, context).throwIfNotConcreteNumber().value;
|
||||
|
||||
@ -180,7 +180,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 20.3.4.14
|
||||
obj.defineNativeMethod("getUTCFullYear", 0, (context) => {
|
||||
obj.defineNativeMethod("getUTCFullYear", 0, context => {
|
||||
// 1. Let t be ? thisTimeValue(this value).
|
||||
let t = thisTimeValue(realm, context).throwIfNotConcreteNumber().value;
|
||||
|
||||
@ -192,7 +192,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 20.3.4.15
|
||||
obj.defineNativeMethod("getUTCHours", 0, (context) => {
|
||||
obj.defineNativeMethod("getUTCHours", 0, context => {
|
||||
// 1. Let t be ? thisTimeValue(this value).
|
||||
let t = thisTimeValue(realm, context).throwIfNotConcreteNumber().value;
|
||||
|
||||
@ -204,7 +204,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 20.3.4.16
|
||||
obj.defineNativeMethod("getUTCMilliseconds", 0, (context) => {
|
||||
obj.defineNativeMethod("getUTCMilliseconds", 0, context => {
|
||||
// 1. Let t be ? thisTimeValue(this value).
|
||||
let t = thisTimeValue(realm, context).throwIfNotConcreteNumber().value;
|
||||
|
||||
@ -216,7 +216,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 20.3.4.17
|
||||
obj.defineNativeMethod("getUTCMinutes", 0, (context) => {
|
||||
obj.defineNativeMethod("getUTCMinutes", 0, context => {
|
||||
// 1. Let t be ? thisTimeValue(this value).
|
||||
let t = thisTimeValue(realm, context).throwIfNotConcreteNumber().value;
|
||||
|
||||
@ -228,7 +228,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 20.3.4.18
|
||||
obj.defineNativeMethod("getUTCMonth", 0, (context) => {
|
||||
obj.defineNativeMethod("getUTCMonth", 0, context => {
|
||||
// 1. Let t be ? thisTimeValue(this value).
|
||||
let t = thisTimeValue(realm, context).throwIfNotConcreteNumber().value;
|
||||
|
||||
@ -240,7 +240,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 20.3.4.19
|
||||
obj.defineNativeMethod("getUTCSeconds", 0, (context) => {
|
||||
obj.defineNativeMethod("getUTCSeconds", 0, context => {
|
||||
// 1. Let t be ? thisTimeValue(this value).
|
||||
let t = thisTimeValue(realm, context).throwIfNotConcreteNumber().value;
|
||||
invariant(context instanceof ObjectValue);
|
||||
@ -262,7 +262,11 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
let dt = ToNumber(realm, date);
|
||||
|
||||
// 3. Let newDate be MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), dt), TimeWithinDay(t)).
|
||||
let newDate = MakeDate(realm, MakeDay(realm, YearFromTime(realm, t), MonthFromTime(realm, t), dt), TimeWithinDay(realm, t));
|
||||
let newDate = MakeDate(
|
||||
realm,
|
||||
MakeDay(realm, YearFromTime(realm, t), MonthFromTime(realm, t), dt),
|
||||
TimeWithinDay(realm, t)
|
||||
);
|
||||
|
||||
// 4. Let u be TimeClip(UTC(newDate)).
|
||||
let u = TimeClip(realm, UTC(realm, newDate));
|
||||
@ -465,7 +469,11 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
let dt = ToNumber(realm, date);
|
||||
|
||||
// 3. Let newDate be MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), dt), TimeWithinDay(t)).
|
||||
let newDate = MakeDate(realm, MakeDay(realm, YearFromTime(realm, t), MonthFromTime(realm, t), dt), TimeWithinDay(realm, t));
|
||||
let newDate = MakeDate(
|
||||
realm,
|
||||
MakeDay(realm, YearFromTime(realm, t), MonthFromTime(realm, t), dt),
|
||||
TimeWithinDay(realm, t)
|
||||
);
|
||||
|
||||
// 4. Let v be TimeClip(newDate).
|
||||
let v = TimeClip(realm, newDate);
|
||||
@ -574,7 +582,8 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
let s;
|
||||
if (argCount < 2) {
|
||||
s = SecFromTime(realm, t);
|
||||
} else { // 4. Else,
|
||||
} else {
|
||||
// 4. Else,
|
||||
// a. Let s be ? ToNumber(sec).
|
||||
s = ToNumber(realm, sec);
|
||||
}
|
||||
@ -583,7 +592,8 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
let milli;
|
||||
if (argCount < 3) {
|
||||
milli = msFromTime(realm, t);
|
||||
} else { // 6. Else,
|
||||
} else {
|
||||
// 6. Else,
|
||||
// a. Let milli be ? ToNumber(ms).
|
||||
milli = ToNumber(realm, ms);
|
||||
}
|
||||
@ -614,7 +624,8 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
let dt;
|
||||
if (argCount < 2) {
|
||||
dt = DateFromTime(realm, t);
|
||||
} else { // 4. Else,
|
||||
} else {
|
||||
// 4. Else,
|
||||
// a. Let dt be ? ToNumber(date).
|
||||
dt = ToNumber(realm, date);
|
||||
}
|
||||
@ -645,7 +656,8 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
let milli;
|
||||
if (argCount < 2) {
|
||||
milli = msFromTime(realm, t);
|
||||
} else { // 4. Else,
|
||||
} else {
|
||||
// 4. Else,
|
||||
// a. Let milli be ? ToNumber(ms).
|
||||
milli = ToNumber(realm, ms);
|
||||
}
|
||||
@ -664,12 +676,12 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 20.3.4.35
|
||||
obj.defineNativeMethod("toDateString", 0, (context) => {
|
||||
obj.defineNativeMethod("toDateString", 0, context => {
|
||||
throw new Error("TODO: implement Date.prototype.toDateString");
|
||||
});
|
||||
|
||||
// ECMA262 20.3.4.36
|
||||
obj.defineNativeMethod("toISOString", 0, (context) => {
|
||||
obj.defineNativeMethod("toISOString", 0, context => {
|
||||
let t = thisTimeValue(realm, context).throwIfNotConcreteNumber().value;
|
||||
if (!isFinite(t)) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.RangeError);
|
||||
@ -696,22 +708,22 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 20.3.4.38
|
||||
obj.defineNativeMethod("toLocaleDateString", 0, (context) => {
|
||||
obj.defineNativeMethod("toLocaleDateString", 0, context => {
|
||||
throw new Error("TODO: implement Date.prototype.toLocaleDateString");
|
||||
});
|
||||
|
||||
// ECMA262 20.3.4.39
|
||||
obj.defineNativeMethod("toLocaleString", 0, (context) => {
|
||||
obj.defineNativeMethod("toLocaleString", 0, context => {
|
||||
throw new Error("TODO: implement Date.prototype.toLocaleString");
|
||||
});
|
||||
|
||||
// ECMA262 20.3.4.40
|
||||
obj.defineNativeMethod("toLocaleTimeString", 0, (context) => {
|
||||
obj.defineNativeMethod("toLocaleTimeString", 0, context => {
|
||||
throw new Error("TODO: implement Date.prototype.toLocaleTimeString");
|
||||
});
|
||||
|
||||
// ECMA262 20.3.4.41
|
||||
obj.defineNativeMethod("toString", 0, (context) => {
|
||||
obj.defineNativeMethod("toString", 0, context => {
|
||||
// 1. Let O be this Date object.
|
||||
let O = context;
|
||||
|
||||
@ -720,7 +732,8 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
if (O.$DateValue === undefined) {
|
||||
// a. Let tv be NaN.
|
||||
tv = NaN;
|
||||
} else { // 3. Else,
|
||||
} else {
|
||||
// 3. Else,
|
||||
// a. Let tv be thisTimeValue(O).
|
||||
tv = thisTimeValue(realm, O).throwIfNotConcreteNumber().value;
|
||||
}
|
||||
@ -730,50 +743,57 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 20.3.4.42
|
||||
obj.defineNativeMethod("toTimeString", 0, (context) => {
|
||||
obj.defineNativeMethod("toTimeString", 0, context => {
|
||||
throw new Error("TODO: implement Date.prototype.toTimeString");
|
||||
});
|
||||
|
||||
// ECMA262 20.3.4.43
|
||||
obj.defineNativeMethod("toUTCString", 0, (context) => {
|
||||
obj.defineNativeMethod("toUTCString", 0, context => {
|
||||
throw new Error("TODO: implement Date.prototype.toUTCString");
|
||||
});
|
||||
|
||||
// ECMA262 20.3.4.44
|
||||
obj.defineNativeMethod("valueOf", 0, (context) => {
|
||||
obj.defineNativeMethod("valueOf", 0, context => {
|
||||
// 1. Return ? thisTimeValue(this value).
|
||||
return thisTimeValue(realm, context);
|
||||
});
|
||||
|
||||
// ECMA262 20.3.4.45
|
||||
obj.defineNativeMethod(realm.intrinsics.SymbolToPrimitive, 1, (context, [hint]) => {
|
||||
// 1. Let O be the this value.
|
||||
let O = context.throwIfNotConcrete();
|
||||
obj.defineNativeMethod(
|
||||
realm.intrinsics.SymbolToPrimitive,
|
||||
1,
|
||||
(context, [hint]) => {
|
||||
// 1. Let O be the this value.
|
||||
let O = context.throwIfNotConcrete();
|
||||
|
||||
// 2. If Type(O) is not Object, throw a TypeError exception.
|
||||
if (!(O instanceof ObjectValue)) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "Type(O) is not Object");
|
||||
}
|
||||
// 2. If Type(O) is not Object, throw a TypeError exception.
|
||||
if (!(O instanceof ObjectValue)) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "Type(O) is not Object");
|
||||
}
|
||||
|
||||
let tryFirst;
|
||||
hint = hint.throwIfNotConcrete();
|
||||
// 3. If hint is the String value "string" or the String value "default", then
|
||||
if (hint instanceof StringValue && (hint.value === "string" || hint.value === "default")) {
|
||||
// a. Let tryFirst be "string".
|
||||
tryFirst = "string";
|
||||
} else if (hint instanceof StringValue && hint.value === "number") { // 4. Else if hint is the String value "number", then
|
||||
// a. Let tryFirst be "number".
|
||||
tryFirst = "number";
|
||||
} else { // 5. Else, throw a TypeError exception.
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "Type(O) is not Object");
|
||||
}
|
||||
let tryFirst;
|
||||
hint = hint.throwIfNotConcrete();
|
||||
// 3. If hint is the String value "string" or the String value "default", then
|
||||
if (hint instanceof StringValue && (hint.value === "string" || hint.value === "default")) {
|
||||
// a. Let tryFirst be "string".
|
||||
tryFirst = "string";
|
||||
} else if (hint instanceof StringValue && hint.value === "number") {
|
||||
// 4. Else if hint is the String value "number", then
|
||||
// a. Let tryFirst be "number".
|
||||
tryFirst = "number";
|
||||
} else {
|
||||
// 5. Else, throw a TypeError exception.
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "Type(O) is not Object");
|
||||
}
|
||||
|
||||
// 6. Return ? OrdinaryToPrimitive(O, tryFirst).
|
||||
return OrdinaryToPrimitive(realm, O, tryFirst);
|
||||
}, { writable: false });
|
||||
// 6. Return ? OrdinaryToPrimitive(O, tryFirst).
|
||||
return OrdinaryToPrimitive(realm, O, tryFirst);
|
||||
},
|
||||
{ writable: false }
|
||||
);
|
||||
|
||||
// B.2.4.1
|
||||
obj.defineNativeMethod("getYear", 0, (context) => {
|
||||
obj.defineNativeMethod("getYear", 0, context => {
|
||||
// 1. Let t be ? thisTimeValue(this value).
|
||||
let t = thisTimeValue(realm, context).throwIfNotConcreteNumber().value;
|
||||
|
||||
@ -806,7 +826,8 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
let yyyy;
|
||||
if (ToInteger(realm, y) < 99) {
|
||||
yyyy = ToInteger(realm, y) + 1900;
|
||||
} else { // 6. Else, let yyyy be y.
|
||||
} else {
|
||||
// 6. Else, let yyyy be y.
|
||||
yyyy = y;
|
||||
}
|
||||
|
||||
|
@ -16,11 +16,16 @@ import { OrdinaryCreateFromConstructor, ToStringPartial, Get, DefinePropertyOrTh
|
||||
import invariant from "../../invariant.js";
|
||||
import type { BabelNodeSourceLocation } from "babel-types";
|
||||
|
||||
export default function (realm: Realm): NativeFunctionValue {
|
||||
export default function(realm: Realm): NativeFunctionValue {
|
||||
return build("Error", realm, false);
|
||||
}
|
||||
|
||||
export function describeLocation(realm: Realm, callerFn: ?FunctionValue, env: ?LexicalEnvironment, loc: ?BabelNodeSourceLocation): void | string {
|
||||
export function describeLocation(
|
||||
realm: Realm,
|
||||
callerFn: ?FunctionValue,
|
||||
env: ?LexicalEnvironment,
|
||||
loc: ?BabelNodeSourceLocation
|
||||
): void | string {
|
||||
let locString = "";
|
||||
let displayName = "";
|
||||
|
||||
@ -30,10 +35,8 @@ export function describeLocation(realm: Realm, callerFn: ?FunctionValue, env: ?L
|
||||
}
|
||||
|
||||
let name = callerFn.$Get("name", callerFn);
|
||||
if (!name.mightBeUndefined())
|
||||
displayName = ToStringPartial(realm, name);
|
||||
else
|
||||
name.throwIfNotConcrete();
|
||||
if (!name.mightBeUndefined()) displayName = ToStringPartial(realm, name);
|
||||
else name.throwIfNotConcrete();
|
||||
|
||||
if (env && env.$NewTarget) displayName = `new ${displayName}`;
|
||||
}
|
||||
@ -76,7 +79,12 @@ function buildStack(realm: Realm, context: ObjectValue) {
|
||||
|
||||
for (let executionContext of stack.reverse()) {
|
||||
let caller = executionContext.caller;
|
||||
let locString = describeLocation(realm, caller ? caller.function : undefined, caller ? caller.lexicalEnvironment : undefined, executionContext.loc);
|
||||
let locString = describeLocation(
|
||||
realm,
|
||||
caller ? caller.function : undefined,
|
||||
caller ? caller.lexicalEnvironment : undefined,
|
||||
executionContext.loc
|
||||
);
|
||||
if (locString !== undefined) lines.push(locString);
|
||||
}
|
||||
|
||||
@ -92,7 +100,7 @@ export function build(name: string, realm: Realm, inheritError?: boolean = true)
|
||||
let O = OrdinaryCreateFromConstructor(realm, newTarget, `${name}Prototype`, { $ErrorData: undefined });
|
||||
O.$ErrorData = {
|
||||
contextStack: realm.contextStack.slice(1),
|
||||
locationData: undefined
|
||||
locationData: undefined,
|
||||
};
|
||||
|
||||
// Build a text description of the stack.
|
||||
@ -100,7 +108,7 @@ export function build(name: string, realm: Realm, inheritError?: boolean = true)
|
||||
value: buildStack(realm, O),
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true
|
||||
writable: true,
|
||||
};
|
||||
DefinePropertyOrThrow(realm, O, "stack", stackDesc);
|
||||
|
||||
@ -114,7 +122,7 @@ export function build(name: string, realm: Realm, inheritError?: boolean = true)
|
||||
value: new StringValue(realm, msg),
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
configurable: true,
|
||||
};
|
||||
|
||||
// c. Perform ! DefinePropertyOrThrow(O, "message", msgDesc).
|
||||
|
@ -13,7 +13,7 @@ import type { Realm } from "../../realm.js";
|
||||
import { ObjectValue, StringValue, UndefinedValue } from "../../values/index.js";
|
||||
import { ToStringPartial, Get } from "../../methods/index.js";
|
||||
|
||||
export default function (realm: Realm, obj: ObjectValue): void {
|
||||
export default function(realm: Realm, obj: ObjectValue): void {
|
||||
return build("Error", realm, obj);
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@ export function build(name: string, realm: Realm, obj: ObjectValue): void {
|
||||
obj.defineNativeProperty("name", new StringValue(realm, name));
|
||||
|
||||
// ECMA262 19.5.3.4
|
||||
obj.defineNativeMethod("toString", 0, (context) => {
|
||||
obj.defineNativeMethod("toString", 0, context => {
|
||||
// 1. Let O be the this value.
|
||||
let O = context.throwIfNotConcrete();
|
||||
|
||||
|
@ -13,6 +13,6 @@ import type { Realm } from "../../realm.js";
|
||||
import type { NativeFunctionValue } from "../../values/index.js";
|
||||
import { build } from "./Error.js";
|
||||
|
||||
export default function (realm: Realm): NativeFunctionValue {
|
||||
export default function(realm: Realm): NativeFunctionValue {
|
||||
return build("EvalError", realm);
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
import type { Realm } from "../../realm.js";
|
||||
import { ObjectValue, StringValue } from "../../values/index.js";
|
||||
|
||||
export default function (realm: Realm, obj: ObjectValue): void {
|
||||
export default function(realm: Realm, obj: ObjectValue): void {
|
||||
obj.defineNativeProperty("name", new StringValue(realm, "EvalError"));
|
||||
obj.defineNativeProperty("message", realm.intrinsics.emptyString);
|
||||
}
|
||||
|
@ -13,6 +13,6 @@ import type { Realm } from "../../realm.js";
|
||||
import { NativeFunctionValue } from "../../values/index.js";
|
||||
import { build } from "./TypedArray.js";
|
||||
|
||||
export default function (realm: Realm): NativeFunctionValue {
|
||||
export default function(realm: Realm): NativeFunctionValue {
|
||||
return build(realm, "Float32");
|
||||
}
|
||||
|
@ -13,6 +13,6 @@ import type { Realm } from "../../realm.js";
|
||||
import type { ObjectValue } from "../../values/index.js";
|
||||
import { build } from "./TypedArrayPrototype.js";
|
||||
|
||||
export default function (realm: Realm, obj: ObjectValue): void {
|
||||
export default function(realm: Realm, obj: ObjectValue): void {
|
||||
build(realm, obj, "Float32");
|
||||
}
|
||||
|
@ -13,6 +13,6 @@ import type { Realm } from "../../realm.js";
|
||||
import { NativeFunctionValue } from "../../values/index.js";
|
||||
import { build } from "./TypedArray.js";
|
||||
|
||||
export default function (realm: Realm): NativeFunctionValue {
|
||||
export default function(realm: Realm): NativeFunctionValue {
|
||||
return build(realm, "Float64");
|
||||
}
|
||||
|
@ -13,6 +13,6 @@ import type { Realm } from "../../realm.js";
|
||||
import type { ObjectValue } from "../../values/index.js";
|
||||
import { build } from "./TypedArrayPrototype.js";
|
||||
|
||||
export default function (realm: Realm, obj: ObjectValue): void {
|
||||
export default function(realm: Realm, obj: ObjectValue): void {
|
||||
build(realm, obj, "Float64");
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import type { Realm } from "../../realm.js";
|
||||
import { NativeFunctionValue } from "../../values/index.js";
|
||||
import { CreateDynamicFunction } from "../../methods/create.js";
|
||||
|
||||
export default function (realm: Realm): NativeFunctionValue {
|
||||
export default function(realm: Realm): NativeFunctionValue {
|
||||
// ECMA262 19.2.1
|
||||
let func = new NativeFunctionValue(realm, "Function", "Function", 1, (context, args, argCount, NewTarget) => {
|
||||
// 1. Let C be the active function object.
|
||||
|
@ -9,11 +9,19 @@
|
||||
|
||||
/* @flow */
|
||||
|
||||
|
||||
import type { Realm } from "../../realm.js";
|
||||
import { BoundFunctionCreate, SetFunctionName } from "../../methods/function.js";
|
||||
import { DefinePropertyOrThrow } from "../../methods/properties.js";
|
||||
import { BooleanValue, NullValue, UndefinedValue, NumberValue, StringValue, FunctionValue, NativeFunctionValue, ObjectValue } from "../../values/index.js";
|
||||
import {
|
||||
BooleanValue,
|
||||
NullValue,
|
||||
UndefinedValue,
|
||||
NumberValue,
|
||||
StringValue,
|
||||
FunctionValue,
|
||||
NativeFunctionValue,
|
||||
ObjectValue,
|
||||
} from "../../values/index.js";
|
||||
import { Call } from "../../methods/call.js";
|
||||
import { ToInteger } from "../../methods/to.js";
|
||||
import { CreateListFromArrayLike } from "../../methods/create.js";
|
||||
@ -24,7 +32,7 @@ import { OrdinaryHasInstance } from "../../methods/abstract.js";
|
||||
import { ThrowCompletion } from "../../completions.js";
|
||||
import invariant from "../../invariant.js";
|
||||
|
||||
export default function (realm: Realm, obj: ObjectValue): void {
|
||||
export default function(realm: Realm, obj: ObjectValue): void {
|
||||
// ECMA262 19.2.3
|
||||
obj.$Call = (thisArgument, argsList) => {
|
||||
return realm.intrinsics.undefined;
|
||||
@ -58,8 +66,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
obj.defineNativeMethod("apply", 2, (func, [thisArg, argArray]) => {
|
||||
// 1. If IsCallable(func) is false, throw a TypeError exception.
|
||||
if (IsCallable(realm, func) === false) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError,
|
||||
"not callable");
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "not callable");
|
||||
}
|
||||
|
||||
// 2. If argArray is null or undefined, then
|
||||
@ -109,7 +116,8 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
// b. If Type(targetLen) is not Number, let L be 0.
|
||||
if (!targetLen.mightBeNumber()) {
|
||||
L = 0;
|
||||
} else { // c. Else,
|
||||
} else {
|
||||
// c. Else,
|
||||
targetLen = targetLen.throwIfNotConcreteNumber();
|
||||
// i. Let targetLen be ToInteger(targetLen).
|
||||
targetLen = ToInteger(realm, targetLen);
|
||||
@ -117,7 +125,8 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
// ii. Let L be the larger of 0 and the result of targetLen minus the number of elements of args.
|
||||
L = Math.max(0, targetLen - args.length);
|
||||
}
|
||||
} else { // 7. Else let L be 0.
|
||||
} else {
|
||||
// 7. Else let L be 0.
|
||||
L = 0;
|
||||
}
|
||||
|
||||
@ -126,7 +135,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
value: new NumberValue(realm, L),
|
||||
writable: false,
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
// 9. Let targetName be ? Get(Target, "name").
|
||||
@ -143,15 +152,20 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// 19.2.3.6
|
||||
obj.defineNativeMethod(realm.intrinsics.SymbolHasInstance, 1, (context, [V]) => {
|
||||
// 1. Let F be the this value.
|
||||
let F = context;
|
||||
obj.defineNativeMethod(
|
||||
realm.intrinsics.SymbolHasInstance,
|
||||
1,
|
||||
(context, [V]) => {
|
||||
// 1. Let F be the this value.
|
||||
let F = context;
|
||||
|
||||
// 2. Return ? OrdinaryHasInstance(F, V).
|
||||
return new BooleanValue(realm, OrdinaryHasInstance(realm, F, V));
|
||||
}, { writable: false, configurable: false });
|
||||
// 2. Return ? OrdinaryHasInstance(F, V).
|
||||
return new BooleanValue(realm, OrdinaryHasInstance(realm, F, V));
|
||||
},
|
||||
{ writable: false, configurable: false }
|
||||
);
|
||||
|
||||
obj.defineNativeMethod("toString", 0, (context) => {
|
||||
obj.defineNativeMethod("toString", 0, context => {
|
||||
context = context.throwIfNotConcrete();
|
||||
if (context instanceof NativeFunctionValue) {
|
||||
return new StringValue(realm, `function ${context.name}() { [native code] }`);
|
||||
|
@ -12,7 +12,9 @@
|
||||
import type { Realm } from "../../realm.js";
|
||||
import { ObjectValue, StringValue } from "../../values/index.js";
|
||||
|
||||
export default function (realm: Realm, obj: ObjectValue): void {
|
||||
export default function(realm: Realm, obj: ObjectValue): void {
|
||||
// ECMA262 25.3.1.5
|
||||
obj.defineNativeProperty(realm.intrinsics.SymbolToStringTag, new StringValue(realm, "GeneratorFunction"), { writable: false });
|
||||
obj.defineNativeProperty(realm.intrinsics.SymbolToStringTag, new StringValue(realm, "GeneratorFunction"), {
|
||||
writable: false,
|
||||
});
|
||||
}
|
||||
|
@ -13,18 +13,24 @@ import type { Realm } from "../../realm.js";
|
||||
import { NativeFunctionValue } from "../../values/index.js";
|
||||
import { CreateDynamicFunction } from "../../methods/create.js";
|
||||
|
||||
export default function (realm: Realm): NativeFunctionValue {
|
||||
export default function(realm: Realm): NativeFunctionValue {
|
||||
// ECMA262 25.2.1
|
||||
let func = new NativeFunctionValue(realm, "GeneratorFunction", "GeneratorFunction", 1, (context, args, argCount, NewTarget) => {
|
||||
// 1. Let C be the active function object.
|
||||
let C = func;
|
||||
let func = new NativeFunctionValue(
|
||||
realm,
|
||||
"GeneratorFunction",
|
||||
"GeneratorFunction",
|
||||
1,
|
||||
(context, args, argCount, NewTarget) => {
|
||||
// 1. Let C be the active function object.
|
||||
let C = func;
|
||||
|
||||
// 2. Let args be the argumentsList that was passed to this function by [[Call]] or [[Construct]].
|
||||
args = argCount > 0 ? args : [];
|
||||
// 2. Let args be the argumentsList that was passed to this function by [[Call]] or [[Construct]].
|
||||
args = argCount > 0 ? args : [];
|
||||
|
||||
// 3. Return ? CreateDynamicFunction(C, NewTarget, "generator", args).
|
||||
return CreateDynamicFunction(realm, C, NewTarget, "generator", args);
|
||||
});
|
||||
// 3. Return ? CreateDynamicFunction(C, NewTarget, "generator", args).
|
||||
return CreateDynamicFunction(realm, C, NewTarget, "generator", args);
|
||||
}
|
||||
);
|
||||
|
||||
return func;
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import { ReturnCompletion } from "../../completions.js";
|
||||
import { ObjectValue, StringValue } from "../../values/index.js";
|
||||
import { GeneratorResume, GeneratorResumeAbrupt } from "../../methods/generator.js";
|
||||
|
||||
export default function (realm: Realm, obj: ObjectValue): void {
|
||||
export default function(realm: Realm, obj: ObjectValue): void {
|
||||
// ECMA262 25.3.1.2
|
||||
obj.defineNativeMethod("next", 1, (context, [value]) => {
|
||||
// 1. Let g be the this value.
|
||||
@ -49,5 +49,7 @@ export default function (realm: Realm, obj: ObjectValue): void {
|
||||
});
|
||||
|
||||
// ECMA262 25.3.1.5
|
||||
obj.defineNativeProperty(realm.intrinsics.SymbolToStringTag, new StringValue(realm, "Generator"), { writable: false });
|
||||
obj.defineNativeProperty(realm.intrinsics.SymbolToStringTag, new StringValue(realm, "Generator"), {
|
||||
writable: false,
|
||||
});
|
||||
}
|
||||
|
@ -13,6 +13,6 @@ import type { Realm } from "../../realm.js";
|
||||
import { NativeFunctionValue } from "../../values/index.js";
|
||||
import { build } from "./TypedArray.js";
|
||||
|
||||
export default function (realm: Realm): NativeFunctionValue {
|
||||
export default function(realm: Realm): NativeFunctionValue {
|
||||
return build(realm, "Int16");
|
||||
}
|
||||
|
@ -13,6 +13,6 @@ import type { Realm } from "../../realm.js";
|
||||
import type { ObjectValue } from "../../values/index.js";
|
||||
import { build } from "./TypedArrayPrototype.js";
|
||||
|
||||
export default function (realm: Realm, obj: ObjectValue): void {
|
||||
export default function(realm: Realm, obj: ObjectValue): void {
|
||||
build(realm, obj, "Int16");
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user