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:
Nikolai Tillmann 2017-07-03 16:19:43 -07:00 committed by Facebook Github Bot
parent d182dcda70
commit 4824b47038
287 changed files with 7535 additions and 4748 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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 ]");

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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());

View File

@ -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

View File

@ -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);

View File

@ -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)]);

View File

@ -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).

View File

@ -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");
}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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
);
}

View File

@ -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);

View File

@ -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 contexts 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 contexts 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);

View File

@ -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.

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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)
)
),
])
);
},
});

View File

@ -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();

View File

@ -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.

View File

@ -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).

View File

@ -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.

View File

@ -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);
}

View File

@ -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

View File

@ -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 = [];

View File

@ -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) {

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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.
}

View File

@ -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);

View File

@ -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
);
}

View File

@ -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));

View File

@ -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) {

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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 {

View File

@ -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);

View File

@ -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++) {

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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
);
}

View File

@ -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);

View File

@ -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");
}

View File

@ -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);

View File

@ -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) => {

View File

@ -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;

View File

@ -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,
});
}

View File

@ -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;
});

View File

@ -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;
});

View File

@ -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,
});
}

View File

@ -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,
});
}

View File

@ -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
);
}

View File

@ -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());

View File

@ -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,
});
}
}

View File

@ -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).

View File

@ -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);
});

View File

@ -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;
}

View File

@ -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.

View File

@ -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)));

View File

@ -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;
}

View File

@ -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).

View File

@ -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();

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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");
}

View File

@ -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");
}

View File

@ -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");
}

View File

@ -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");
}

View File

@ -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.

View File

@ -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] }`);

View File

@ -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,
});
}

View File

@ -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;
}

View File

@ -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,
});
}

View File

@ -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");
}

View File

@ -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