Partial evaluator for block (#695)

This commit is contained in:
Herman Venter 2017-06-02 10:25:07 -07:00 committed by GitHub
parent 4ac76366e9
commit 8a55a231af
3 changed files with 96 additions and 6 deletions

View File

@ -12,7 +12,7 @@
import type { LexicalEnvironment } from "../environment.js";
import type { PropertyKeyValue } from "../types.js";
import type { Realm } from "../realm.js";
import { ThrowCompletion, ReturnCompletion, AbruptCompletion, NormalCompletion, PossiblyNormalCompletion, IntrospectionThrowCompletion } from "../completions.js";
import { Completion, ThrowCompletion, ReturnCompletion, AbruptCompletion, NormalCompletion, PossiblyNormalCompletion, IntrospectionThrowCompletion } from "../completions.js";
import { ExecutionContext } from "../realm.js";
import { GlobalEnvironmentRecord, ObjectEnvironmentRecord, Reference } from "../environment.js";
import { Value, BoundFunctionValue, EmptyValue, FunctionValue, ObjectValue, StringValue, SymbolValue, NumberValue } from "../values/index.js";
@ -1060,6 +1060,62 @@ export function EvaluateStatements(
}
export function PartiallyEvaluateStatements(
body: Array<BabelNodeStatement>, blockValue: void | NormalCompletion | Value,
strictCode: boolean, blockEnv: LexicalEnvironment, realm: Realm
): [Completion | Value, Array<BabelNodeStatement>] {
let statementAsts = [];
for (let node of body) {
if (node.type !== "FunctionDeclaration") {
let [res, nast, nio] = blockEnv.partiallyEvaluateCompletionDeref(node, strictCode);
for (let ioAst of nio) statementAsts.push(ioAst);
statementAsts.push((nast: any));
if (!(res instanceof EmptyValue)) {
if (blockValue === undefined || blockValue instanceof Value) {
if (res instanceof AbruptCompletion)
return [UpdateEmpty(realm, res, blockValue || realm.intrinsics.empty), statementAsts];
invariant(res instanceof NormalCompletion || res instanceof Value);
blockValue = res;
} else {
invariant(blockValue instanceof PossiblyNormalCompletion);
if (res instanceof AbruptCompletion) {
let e = realm.getCapturedEffects();
invariant(e !== undefined);
realm.stopEffectCapture();
let [_c, _g, b, p, _o] = e;
_c; _g; _o;
realm.restoreBindings(b);
realm.restoreProperties(p);
if (res instanceof IntrospectionThrowCompletion) {
realm.applyEffects(e);
throw res;
}
invariant(blockValue instanceof PossiblyNormalCompletion);
e[0] = res;
let joined_effects = joinPossiblyNormalCompletionWithAbruptCompletion(realm, blockValue, res, e);
realm.applyEffects(joined_effects);
let jres = joined_effects[0];
invariant(jres instanceof Value || jres instanceof Completion);
return [jres, statementAsts];
} else {
if (res instanceof Value)
blockValue.value = res;
else {
invariant(blockValue instanceof PossiblyNormalCompletion);
invariant(res instanceof PossiblyNormalCompletion);
blockValue = composePossiblyNormalCompletions(realm, blockValue, res);
}
}
}
}
}
}
// 7. Return blockValue.
return [blockValue || realm.intrinsics.empty, statementAsts];
}
// ECMA262 9.2.5
export function FunctionCreate(realm: Realm, kind: "normal" | "arrow" | "method", ParameterList: Array<BabelNodeLVal>, Body: BabelNodeBlockStatement, Scope: LexicalEnvironment, Strict: boolean, prototype?: ObjectValue) {
// 1. If the prototype argument was not passed, then

View File

@ -13,13 +13,46 @@ import type { BabelNodeBlockStatement, BabelNodeStatement } from "babel-types";
import type { Realm } from "../realm.js";
import type { LexicalEnvironment } from "../environment.js";
import { AbruptCompletion } from "../completions.js";
import { Value } from "../values/index.js";
import { Completion, NormalCompletion } from "../completions.js";
import { EmptyValue, StringValue, Value } from "../values/index.js";
import { BlockDeclarationInstantiation, NewDeclarativeEnvironment, PartiallyEvaluateStatements } from "../methods/index.js";
import invariant from "../invariant.js";
import * as t from "babel-types";
// ECMA262 13.2.13
export default function (
ast: BabelNodeBlockStatement, strictCode: boolean, env: LexicalEnvironment, realm: Realm
): [AbruptCompletion | Value, BabelNodeBlockStatement, Array<BabelNodeStatement>] {
let result = env.evaluateCompletionDeref(ast, strictCode);
return [result, ast, []];
): [Completion | Value, BabelNodeStatement, Array<BabelNodeStatement>] {
// 1. Let oldEnv be the running execution context's LexicalEnvironment.
let oldEnv = realm.getRunningContext().lexicalEnvironment;
// 2. Let blockEnv be NewDeclarativeEnvironment(oldEnv).
let blockEnv = NewDeclarativeEnvironment(realm, oldEnv);
// 3. Perform BlockDeclarationInstantiation(StatementList, blockEnv).
BlockDeclarationInstantiation(realm, strictCode, ast.body, blockEnv);
// 4. Set the running execution context's LexicalEnvironment to blockEnv.
realm.getRunningContext().lexicalEnvironment = blockEnv;
try {
// 5. Let blockValue be the result of evaluating StatementList.
let blockValue: void | NormalCompletion | Value;
if (ast.directives) {
for (let directive of (ast.directives)) {
blockValue = new StringValue(realm, directive.value.value);
}
}
let [res, bAst] = PartiallyEvaluateStatements(ast.body, blockValue, strictCode, blockEnv, realm);
invariant(bAst.length > 0 || res instanceof EmptyValue);
if (bAst.length === 0) return [res, t.emptyStatement(), []];
let rAst = t.blockStatement(bAst, ast.directives);
return [res, rAst, []];
} finally {
// 6. Set the running execution context's LexicalEnvironment to oldEnv.
realm.getRunningContext().lexicalEnvironment = oldEnv;
}
}

1
test/residual/block.js Normal file
View File

@ -0,0 +1 @@
{let __result = 1;}