Skip to content

Commit

Permalink
Forward deopt node path in NodePath#evaludate (#11832)
Browse files Browse the repository at this point in the history
* Forward deopt node path

* Move deopt evaluation tests

* Document evaluate deopt property
  • Loading branch information
johanholmerin committed Aug 20, 2020
1 parent bd07cda commit b9407d7
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 8 deletions.
21 changes: 13 additions & 8 deletions packages/babel-traverse/src/path/evaluation.js
Expand Up @@ -219,7 +219,7 @@ function _evaluate(path, state) {
if (elemValue.confident) {
arr.push(elemValue.value);
} else {
return deopt(elem, state);
return deopt(elemValue.deopt, state);
}
}
return arr;
Expand All @@ -237,7 +237,7 @@ function _evaluate(path, state) {
if (prop.node.computed) {
key = key.evaluate();
if (!key.confident) {
return deopt(keyPath, state);
return deopt(key.deopt, state);
}
key = key.value;
} else if (key.isIdentifier()) {
Expand All @@ -248,7 +248,7 @@ function _evaluate(path, state) {
const valuePath = prop.get("value");
let value = valuePath.evaluate();
if (!value.confident) {
return deopt(valuePath, state);
return deopt(value.deopt, state);
}
value = value.value;
obj[key] = value;
Expand Down Expand Up @@ -407,19 +407,24 @@ function evaluateQuasis(path, quasis: Array<Object>, state, raw = false) {
/**
* Walk the input `node` and statically evaluate it.
*
* Returns an object in the form `{ confident, value }`. `confident` indicates
* whether or not we had to drop out of evaluating the expression because of
* hitting an unknown node that we couldn't confidently find the value of.
* Returns an object in the form `{ confident, value, deopt }`. `confident`
* indicates whether or not we had to drop out of evaluating the expression
* because of hitting an unknown node that we couldn't confidently find the
* value of, in which case `deopt` is the path of said node.
*
* Example:
*
* t.evaluate(parse("5 + 5")) // { confident: true, value: 10 }
* t.evaluate(parse("!true")) // { confident: true, value: false }
* t.evaluate(parse("foo + foo")) // { confident: false, value: undefined }
* t.evaluate(parse("foo + foo")) // { confident: false, value: undefined, deopt: NodePath }
*
*/

export function evaluate(): { confident: boolean, value: any } {
export function evaluate(): {
confident: boolean,
value: any,
deopt?: NodePath,
} {
const state = {
confident: true,
deoptPath: null,
Expand Down
23 changes: 23 additions & 0 deletions packages/babel-traverse/test/evaluation.js
Expand Up @@ -13,6 +13,25 @@ function getPath(code) {
return path;
}

function addDeoptTest(code, type, expectedType) {
it(type + " deopt: " + code, function () {
const visitor = {};

visitor[type] = function (path) {
const evaluate = path.evaluate();
expect(evaluate.confident).toBeFalsy();
expect(evaluate.deopt.type).toEqual(expectedType);
};

traverse(
parse(code, {
plugins: ["*"],
}),
visitor,
);
});
}

describe("evaluation", function () {
describe("evaluateTruthy", function () {
it("it should work with null", function () {
Expand Down Expand Up @@ -228,4 +247,8 @@ describe("evaluation", function () {
expect(result.deopt).toBeNull();
expect(result.value).toEqual(["foo", "bar"]);
});

addDeoptTest("({a:{b}})", "ObjectExpression", "Identifier");
addDeoptTest("({[a + 'b']: 1})", "ObjectExpression", "Identifier");
addDeoptTest("[{a}]", "ArrayExpression", "Identifier");
});

0 comments on commit b9407d7

Please sign in to comment.