Skip to content
This repository has been archived by the owner on Feb 12, 2022. It is now read-only.

Move $ContextStack to $ErrorData, and append location data for syntax errors #461

Merged
merged 1 commit into from
Apr 27, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/intrinsics/ecma262/Error.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export function describeLocation(realm: Realm, callerFn: ?FunctionValue, env: ?L
function buildStack(realm: Realm, context: ObjectValue) {
invariant(context.$ErrorData);

let stack = context.$ContextStack;
let stack = context.$ErrorData.contextStack;
if (!stack) return realm.intrinsics.undefined;

let lines = [];
Expand Down Expand Up @@ -90,10 +90,12 @@ export function build(name: string, realm: Realm, inheritError?: boolean = true)

// 2. Let O be ? OrdinaryCreateFromConstructor(newTarget, "%ErrorPrototype%", « [[ErrorData]] »).
let O = OrdinaryCreateFromConstructor(realm, newTarget, `${name}Prototype`, { $ErrorData: undefined });
O.$ErrorData = O; // The value is never used, but allows us to use undefined as a way to say "not in"
O.$ErrorData = {
contextStack: realm.contextStack.slice(1),
locationData: undefined
};

// Build a text description of the stack.
O.$ContextStack = realm.contextStack.slice(1);
let stackDesc = {
value: buildStack(realm, O),
enumerable: false,
Expand Down
4 changes: 3 additions & 1 deletion src/serializer/logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ export class Logger {
let message = object.properties.get("message");
console.error((message && message.descriptor && message.descriptor.value instanceof StringValue) ? message.descriptor.value.value : "(no message available)");
console.error(err.stack);
console.error(object.$ContextStack);
if (object.$ErrorData) {
console.error(object.$ErrorData.contextStack);
}
}
} else {
try {
Expand Down
25 changes: 17 additions & 8 deletions src/utils/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

/* @flow */

import invariant from "../invariant.js";
import type { SourceType } from "../types.js";
import type { Realm } from "../realm.js";
import { ThrowCompletion } from "../completions.js";
Expand All @@ -18,9 +19,9 @@ import traverse from "babel-traverse";
import { parse } from "babylon";
import type { BabelNodeFile } from "babel-types";

export default function (realm: Realm, code: string, filename: string, sourceType: SourceType = "script"): BabelNodeFile {
export default function (realm: Realm, code: string, filename: string, sourceType: SourceType = "script", startLine: number = 1): BabelNodeFile {
Copy link
Contributor Author

@sebmarkbage sebmarkbage Apr 26, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also needed the startLine option to model contextify's ability to shift source location numbers. @kittens is there a way to do the same for columns in babylon?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should try to make sure that everything we add to the code base has test coverage, so it would be better if startLine can be added in a separate pull request that includes a use case and test for it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The goal of this string of PRs is to break out everything from #397 with changes existing code. To make it easier to review that one. I could just leave it in #397 as one big blob but that makes rebasing and reviewing harder. I could make up some artificial test case here but I'm not quite sure how to do a pure unit test since we don't really have any infra set up for unit tests. I'd have to wire up a lot of things just to test this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough. It is usually possible to do an integration test that exercises new code, but in this case we'd need a unit testing story.

try {
let ast = parse(code, { filename, sourceType });
let ast = parse(code, { filename, sourceType, startLine });
traverse.cheap(ast, (node) => {
node.loc.source = filename;
});
Expand All @@ -35,15 +36,23 @@ export default function (realm: Realm, code: string, filename: string, sourceTyp
'Invalid left-hand side in assignment expression',
];

let error;
if (referenceErrors.some((msg) => e.message.indexOf(msg) >= 0)) {
throw new ThrowCompletion(
Construct(realm, realm.intrinsics.ReferenceError, [new StringValue(realm, e.message)])
);
error = Construct(realm, realm.intrinsics.ReferenceError, [new StringValue(realm, e.message)]);
} else {
throw new ThrowCompletion(
Construct(realm, realm.intrinsics.SyntaxError, [new StringValue(realm, e.message)])
);
error = Construct(realm, realm.intrinsics.SyntaxError, [new StringValue(realm, e.message)]);
}
// These constructors are currently guaranteed to produce an object with
// built-in error data. Append location information about the syntax error
// and the source code to it so that we can use it to print nicer errors.
invariant(error.$ErrorData);
error.$ErrorData.locationData = {
filename: filename,
sourceCode: code,
loc: e.loc,
stackDecorated: false
};
throw new ThrowCompletion(error);
} else {
throw e;
}
Expand Down
12 changes: 9 additions & 3 deletions src/values/ObjectValue.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,15 @@ export default class ObjectValue extends ConcreteValue {
$BooleanData: void | BooleanValue;

// error
$ErrorData: void | ObjectValue; // undefined when the property is "missing"
$ContextStack: void | Array<ExecutionContext>;

$ErrorData: void | { // undefined when the property is "missing"
contextStack: Array<ExecutionContext>,
locationData: void | {
filename: string,
sourceCode: string,
loc: { line: number, column: number },
stackDecorated: boolean
}
};

// function
$Call: void | ((thisArgument: Value, argumentsList: Array<Value>) => Value);
Expand Down