mirror of
https://github.com/facebookarchive/prepack.git
synced 2024-09-11 14:46:37 +03:00
Effects contain NormalCompletion not Value (#2110)
Summary: Release Notes: None In an effort to unify Completions and Effects (many completions are tied to effects whose result should be the completion), I change evaluateForEffects to return a `NormalCompletion` whereever it would otherwise return a `Value`. Now all `EvaluationResults` are `Completions` or `References`. Fairly mechanical refactor (except slightly tricky because PossiblyNormalCompletions are NormalCompletions, so instead of checking `instanceof Value` you should check `instanceof NormalCompletion && ! instanceof PossiblyNormalCompletion`). Closes https://github.com/facebook/prepack/pull/2110 Differential Revision: D8431970 Pulled By: cblappert fbshipit-source-id: d70d6c5d4100eec52f60b8e4328f2a0b4afabbed
This commit is contained in:
parent
03b7fd37ff
commit
b59e918fd6
@ -24,11 +24,19 @@ export class Completion {
|
||||
value: Value;
|
||||
target: ?string;
|
||||
location: ?BabelNodeSourceLocation;
|
||||
|
||||
toDisplayString(): string {
|
||||
return "[" + this.constructor.name + " value " + (this.value ? this.value.toDisplayString() : "undefined") + "]";
|
||||
}
|
||||
}
|
||||
|
||||
// Normal completions are returned just like spec completions
|
||||
export class NormalCompletion extends Completion {}
|
||||
|
||||
// SimpleNormalCompletions are returned just like spec completions. This class exists as the parallel for
|
||||
// PossiblyNormalCompletion to make comparisons easier.
|
||||
export class SimpleNormalCompletion extends NormalCompletion {}
|
||||
|
||||
// Abrupt completions are thrown as exeptions, to make it a easier
|
||||
// to quickly get to the matching high level construct.
|
||||
export class AbruptCompletion extends Completion {}
|
||||
@ -86,6 +94,13 @@ export class ForkedAbruptCompletion extends AbruptCompletion {
|
||||
alternate: AbruptCompletion;
|
||||
alternateEffects: Effects;
|
||||
|
||||
toDisplayString(): string {
|
||||
let superString = super.toDisplayString().slice(0, -1);
|
||||
return (
|
||||
superString + " c: [" + this.consequent.toDisplayString() + "] a: [" + this.alternate.toDisplayString() + "]]"
|
||||
);
|
||||
}
|
||||
|
||||
containsCompletion(CompletionType: typeof Completion): boolean {
|
||||
if (this.consequent instanceof CompletionType) return true;
|
||||
if (this.alternate instanceof CompletionType) return true;
|
||||
@ -130,31 +145,22 @@ export class PossiblyNormalCompletion extends NormalCompletion {
|
||||
constructor(
|
||||
value: Value,
|
||||
joinCondition: AbstractValue,
|
||||
consequent: Completion | Value,
|
||||
consequent: Completion,
|
||||
consequentEffects: Effects,
|
||||
alternate: Completion | Value,
|
||||
alternate: Completion,
|
||||
alternateEffects: Effects,
|
||||
savedPathConditions: Array<AbstractValue>,
|
||||
savedEffects: void | Effects = undefined
|
||||
) {
|
||||
invariant(consequent === consequentEffects.result);
|
||||
invariant(alternate === alternateEffects.result);
|
||||
invariant(
|
||||
consequent instanceof NormalCompletion ||
|
||||
consequent instanceof Value ||
|
||||
alternate instanceof NormalCompletion ||
|
||||
alternate instanceof Value
|
||||
);
|
||||
invariant(consequent instanceof NormalCompletion || alternate instanceof NormalCompletion);
|
||||
invariant(consequent instanceof AbruptCompletion || alternate instanceof AbruptCompletion);
|
||||
invariant(
|
||||
value === consequent ||
|
||||
consequent instanceof AbruptCompletion ||
|
||||
(consequent instanceof NormalCompletion && value === consequent.value)
|
||||
consequent instanceof AbruptCompletion || (consequent instanceof NormalCompletion && value === consequent.value)
|
||||
);
|
||||
invariant(
|
||||
value === alternate ||
|
||||
alternate instanceof AbruptCompletion ||
|
||||
(alternate instanceof NormalCompletion && value === alternate.value)
|
||||
alternate instanceof AbruptCompletion || (alternate instanceof NormalCompletion && value === alternate.value)
|
||||
);
|
||||
let loc =
|
||||
consequent instanceof AbruptCompletion
|
||||
@ -173,14 +179,39 @@ export class PossiblyNormalCompletion extends NormalCompletion {
|
||||
}
|
||||
|
||||
joinCondition: AbstractValue;
|
||||
consequent: Completion | Value;
|
||||
consequent: Completion;
|
||||
consequentEffects: Effects;
|
||||
alternate: Completion | Value;
|
||||
alternate: Completion;
|
||||
alternateEffects: Effects;
|
||||
savedEffects: void | Effects;
|
||||
// The path conditions that applied at the time of the oldest fork that caused this completion to arise.
|
||||
savedPathConditions: Array<AbstractValue>;
|
||||
|
||||
toDisplayString(): string {
|
||||
let superString = super.toDisplayString().slice(0, -1);
|
||||
return (
|
||||
superString + " c: [" + this.consequent.toDisplayString() + "] a: [" + this.alternate.toDisplayString() + "]]"
|
||||
);
|
||||
}
|
||||
|
||||
getNormalCompletion(): SimpleNormalCompletion {
|
||||
let result;
|
||||
if (this.alternate instanceof SimpleNormalCompletion) {
|
||||
result = this.alternate;
|
||||
} else if (this.consequent instanceof SimpleNormalCompletion) {
|
||||
result = this.consequent;
|
||||
} else {
|
||||
if (this.alternate instanceof PossiblyNormalCompletion) {
|
||||
result = this.alternate.getNormalCompletion();
|
||||
} else {
|
||||
invariant(this.consequent instanceof PossiblyNormalCompletion);
|
||||
result = this.consequent.getNormalCompletion();
|
||||
}
|
||||
}
|
||||
invariant(result.value === this.value);
|
||||
return result;
|
||||
}
|
||||
|
||||
containsCompletion(CompletionType: typeof Completion): boolean {
|
||||
if (this.consequent instanceof CompletionType) return true;
|
||||
if (this.alternate instanceof CompletionType) return true;
|
||||
|
@ -25,7 +25,7 @@ import {
|
||||
UndefinedValue,
|
||||
Value,
|
||||
} from "../values/index.js";
|
||||
import { AbruptCompletion, PossiblyNormalCompletion } from "../completions.js";
|
||||
import { AbruptCompletion, PossiblyNormalCompletion, SimpleNormalCompletion } from "../completions.js";
|
||||
import { Environment, Havoc, To } from "../singletons.js";
|
||||
import type {
|
||||
BabelBinaryOperator,
|
||||
@ -227,6 +227,8 @@ export function computeBinary(
|
||||
// Consequently we have to continue tracking changes until the point where
|
||||
// all the branches come together into one.
|
||||
completion = realm.composeWithSavedCompletion(completion);
|
||||
} else if (completion instanceof SimpleNormalCompletion) {
|
||||
completion = completion.value;
|
||||
}
|
||||
// return or throw completion
|
||||
if (completion instanceof AbruptCompletion) throw completion;
|
||||
|
@ -10,7 +10,7 @@
|
||||
/* @flow */
|
||||
|
||||
import { CompilerDiagnostic, FatalError } from "../errors.js";
|
||||
import { AbruptCompletion, PossiblyNormalCompletion } from "../completions.js";
|
||||
import { AbruptCompletion, PossiblyNormalCompletion, SimpleNormalCompletion } from "../completions.js";
|
||||
import type { Realm } from "../realm.js";
|
||||
import { Effects } from "../realm.js";
|
||||
import { type LexicalEnvironment, type BaseValue, mightBecomeAnObject } from "../environment.js";
|
||||
@ -182,6 +182,7 @@ function callBothFunctionsAndJoinTheirEffects(
|
||||
new Effects(e2.result, e2.generator, e2.modifiedBindings, e2.modifiedProperties, e2.createdObjects)
|
||||
);
|
||||
let completion = joinedEffects.result;
|
||||
if (completion instanceof SimpleNormalCompletion) completion = completion.value;
|
||||
if (completion instanceof PossiblyNormalCompletion) {
|
||||
// in this case one of the branches may complete abruptly, which means that
|
||||
// not all control flow branches join into one flow at this point.
|
||||
@ -290,6 +291,7 @@ function tryToEvaluateCallOrLeaveAsAbstract(
|
||||
}
|
||||
// return or throw completion
|
||||
if (completion instanceof AbruptCompletion) throw completion;
|
||||
if (completion instanceof SimpleNormalCompletion) completion = completion.value;
|
||||
invariant(completion instanceof Value);
|
||||
return completion;
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ import { Value } from "../values/index.js";
|
||||
import { EmptyValue } from "../values/index.js";
|
||||
import { UpdateEmpty } from "../methods/index.js";
|
||||
import { LoopContinues, InternalGetResultValue, TryToApplyEffectsOfJoiningBranches } from "./ForOfStatement.js";
|
||||
import { AbruptCompletion, BreakCompletion, ForkedAbruptCompletion } from "../completions.js";
|
||||
import { AbruptCompletion, BreakCompletion, ForkedAbruptCompletion, SimpleNormalCompletion } from "../completions.js";
|
||||
import { Environment, To } from "../singletons.js";
|
||||
import invariant from "../invariant.js";
|
||||
import type { BabelNodeDoWhileStatement } from "babel-types";
|
||||
@ -73,6 +73,7 @@ export default function(
|
||||
// so instead try to compute a fixpoint for it
|
||||
let iteration = () => {
|
||||
let bodyResult = env.evaluateCompletion(body, strictCode);
|
||||
if (bodyResult instanceof Value) bodyResult = new SimpleNormalCompletion(bodyResult);
|
||||
let exprRef = env.evaluate(test, strictCode);
|
||||
let testResult = Environment.GetConditionValue(realm, exprRef);
|
||||
return [testResult, bodyResult];
|
||||
@ -86,8 +87,8 @@ export default function(
|
||||
let generator = realm.generator;
|
||||
invariant(generator !== undefined);
|
||||
generator.emitDoWhileStatement(cond, bodyGenerator);
|
||||
invariant(rval instanceof Value, "todo: handle loops that throw exceptions or return");
|
||||
return rval;
|
||||
invariant(rval instanceof SimpleNormalCompletion, "todo: handle loops that throw exceptions or return");
|
||||
return rval.value;
|
||||
}
|
||||
|
||||
// If we get here the fixpoint computation failed as well. Report the diagnostic from the unrolling and throw.
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
import type { Realm } from "../realm.js";
|
||||
import type { LexicalEnvironment } from "../environment.js";
|
||||
import { BreakCompletion } from "../completions.js";
|
||||
import { BreakCompletion, SimpleNormalCompletion } from "../completions.js";
|
||||
import { DeclarativeEnvironmentRecord } from "../environment.js";
|
||||
import { CompilerDiagnostic, FatalError } from "../errors.js";
|
||||
import { ForInOfHeadEvaluation, ForInOfBodyEvaluation } from "./ForOfStatement.js";
|
||||
@ -142,7 +142,12 @@ function emitResidualLoopIfSafe(
|
||||
strictCode,
|
||||
blockEnv
|
||||
);
|
||||
if (result instanceof Value && gen.empty() && modifiedBindings.size === 0 && modifiedProperties.size === 1) {
|
||||
if (
|
||||
result instanceof SimpleNormalCompletion &&
|
||||
gen.empty() &&
|
||||
modifiedBindings.size === 0 &&
|
||||
modifiedProperties.size === 1
|
||||
) {
|
||||
invariant(createdObjects.size === 0); // or there will be more than one property
|
||||
let targetObject;
|
||||
let sourceObject;
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
import type { Realm } from "../realm.js";
|
||||
import { Effects } from "../realm.js";
|
||||
import { AbruptCompletion, PossiblyNormalCompletion } from "../completions.js";
|
||||
import { AbruptCompletion, PossiblyNormalCompletion, SimpleNormalCompletion } from "../completions.js";
|
||||
import { InfeasiblePathError } from "../errors.js";
|
||||
import { construct_empty_effects } from "../realm.js";
|
||||
import type { LexicalEnvironment } from "../environment.js";
|
||||
@ -93,13 +93,19 @@ export default function(
|
||||
realm,
|
||||
lval,
|
||||
new Effects(result2, generator2, modifiedBindings2, modifiedProperties2, createdObjects2),
|
||||
new Effects(lval, generator1, modifiedBindings1, modifiedProperties1, createdObjects1)
|
||||
new Effects(new SimpleNormalCompletion(lval), generator1, modifiedBindings1, modifiedProperties1, createdObjects1)
|
||||
);
|
||||
} else {
|
||||
joinedEffects = Join.joinForkOrChoose(
|
||||
realm,
|
||||
lval,
|
||||
new Effects(lval, generator1, modifiedBindings1, modifiedProperties1, createdObjects1),
|
||||
new Effects(
|
||||
new SimpleNormalCompletion(lval),
|
||||
generator1,
|
||||
modifiedBindings1,
|
||||
modifiedProperties1,
|
||||
createdObjects1
|
||||
),
|
||||
new Effects(result2, generator2, modifiedBindings2, modifiedProperties2, createdObjects2)
|
||||
);
|
||||
}
|
||||
@ -117,7 +123,9 @@ export default function(
|
||||
|
||||
// return or throw completion
|
||||
if (completion instanceof AbruptCompletion) throw completion;
|
||||
invariant(completion instanceof Value); // references do not survive join
|
||||
if (completion instanceof SimpleNormalCompletion) completion = completion.value;
|
||||
if (result2 instanceof SimpleNormalCompletion) result2 = result2.value;
|
||||
invariant(completion instanceof Value);
|
||||
if (lval instanceof Value && result2 instanceof Value) {
|
||||
// joinForkOrChoose does the right thing for the side effects of the second expression but for the result the join
|
||||
// produces a conditional expressions of the form (a ? b : a) for a && b and (a ? a : b) for a || b
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
import type { Realm } from "../realm.js";
|
||||
import type { LexicalEnvironment } from "../environment.js";
|
||||
import { AbruptCompletion, PossiblyNormalCompletion } from "../completions.js";
|
||||
import { AbruptCompletion, PossiblyNormalCompletion, SimpleNormalCompletion } from "../completions.js";
|
||||
import { TypesDomain, ValuesDomain } from "../domains/index.js";
|
||||
import { ObjectValue, Value, AbstractObjectValue, AbstractValue } from "../values/index.js";
|
||||
import { Environment, Havoc } from "../singletons.js";
|
||||
@ -125,6 +125,7 @@ function tryToEvaluateConstructOrLeaveAsAbstract(
|
||||
|
||||
// return or throw completion
|
||||
if (completion instanceof AbruptCompletion) throw completion;
|
||||
if (completion instanceof SimpleNormalCompletion) completion = completion.value;
|
||||
invariant(completion instanceof ObjectValue || completion instanceof AbstractObjectValue);
|
||||
return completion;
|
||||
}
|
||||
|
@ -14,7 +14,13 @@ import type { LexicalEnvironment } from "../environment.js";
|
||||
import { CompilerDiagnostic, InfeasiblePathError } from "../errors.js";
|
||||
import { Reference } from "../environment.js";
|
||||
import { computeBinary } from "./BinaryExpression.js";
|
||||
import { AbruptCompletion, BreakCompletion, PossiblyNormalCompletion, Completion } from "../completions.js";
|
||||
import {
|
||||
AbruptCompletion,
|
||||
BreakCompletion,
|
||||
SimpleNormalCompletion,
|
||||
PossiblyNormalCompletion,
|
||||
Completion,
|
||||
} from "../completions.js";
|
||||
import { InternalGetResultValue } from "./ForOfStatement.js";
|
||||
import { EmptyValue, AbstractValue, Value } from "../values/index.js";
|
||||
import { StrictEqualityComparisonPartial, UpdateEmpty } from "../methods/index.js";
|
||||
@ -186,6 +192,9 @@ function AbstractCaseBlockEvaluation(
|
||||
|
||||
// return or throw completion
|
||||
if (completion instanceof AbruptCompletion) throw completion;
|
||||
if (completion instanceof SimpleNormalCompletion) {
|
||||
completion = completion.value;
|
||||
}
|
||||
invariant(completion instanceof Value);
|
||||
return completion;
|
||||
}
|
||||
@ -369,6 +378,9 @@ export default function(
|
||||
// all the branches come together into one.
|
||||
result = realm.composeWithSavedCompletion(result);
|
||||
}
|
||||
if (result instanceof SimpleNormalCompletion) {
|
||||
result = result.value;
|
||||
}
|
||||
invariant(result instanceof Value); // since evaluationHelper returns a value in non abrupt cases
|
||||
return result;
|
||||
}
|
||||
|
@ -11,7 +11,14 @@
|
||||
|
||||
import type { Effects, Realm } from "../realm.js";
|
||||
import { type LexicalEnvironment } from "../environment.js";
|
||||
import { AbruptCompletion, ForkedAbruptCompletion, PossiblyNormalCompletion, ThrowCompletion } from "../completions.js";
|
||||
import {
|
||||
AbruptCompletion,
|
||||
ForkedAbruptCompletion,
|
||||
PossiblyNormalCompletion,
|
||||
ThrowCompletion,
|
||||
SimpleNormalCompletion,
|
||||
NormalCompletion,
|
||||
} from "../completions.js";
|
||||
import { UpdateEmpty } from "../methods/index.js";
|
||||
import { Functions, Join } from "../singletons.js";
|
||||
import { Value } from "../values/index.js";
|
||||
@ -69,7 +76,7 @@ export default function(ast: BabelNodeTryStatement, strictCode: boolean, env: Le
|
||||
let finalizerEffects = composeNestedEffectsWithFinalizer(blockRes);
|
||||
finalizerRes = finalizerEffects.result;
|
||||
// The result may become abrupt because of the finalizer, but it cannot become normal.
|
||||
invariant(!(finalizerRes instanceof Value));
|
||||
invariant(!(finalizerRes instanceof SimpleNormalCompletion));
|
||||
} else {
|
||||
// A single thread of control has produced a normal blockRes and the global state is up to date.
|
||||
finalizerRes = env.evaluateCompletion(ast.finalizer, strictCode);
|
||||
@ -78,7 +85,7 @@ export default function(ast: BabelNodeTryStatement, strictCode: boolean, env: Le
|
||||
|
||||
if (finalizerRes instanceof AbruptCompletion) throw finalizerRes;
|
||||
if (finalizerRes instanceof PossiblyNormalCompletion) realm.composeWithSavedCompletion(finalizerRes);
|
||||
if (handlerRes instanceof PossiblyNormalCompletion) handlerRes = handlerRes.value;
|
||||
if (handlerRes instanceof NormalCompletion) handlerRes = handlerRes.value;
|
||||
if (handlerRes instanceof Value) return (UpdateEmpty(realm, handlerRes, realm.intrinsics.undefined): any);
|
||||
throw handlerRes;
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
import type { Realm } from "../realm.js";
|
||||
import type { LexicalEnvironment } from "../environment.js";
|
||||
import { AbruptCompletion, PossiblyNormalCompletion } from "../completions.js";
|
||||
import { AbruptCompletion, PossiblyNormalCompletion, SimpleNormalCompletion } from "../completions.js";
|
||||
import { CompilerDiagnostic, FatalError } from "../errors.js";
|
||||
import { TypesDomain, ValuesDomain } from "../domains/index.js";
|
||||
import {
|
||||
@ -143,6 +143,7 @@ function tryToEvaluateOperationOrLeaveAsAbstract(
|
||||
|
||||
// return or throw completion
|
||||
if (completion instanceof AbruptCompletion) throw completion;
|
||||
if (completion instanceof SimpleNormalCompletion) completion = completion.value;
|
||||
invariant(completion instanceof Value);
|
||||
return completion;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import {
|
||||
ContinueCompletion,
|
||||
PossiblyNormalCompletion,
|
||||
ForkedAbruptCompletion,
|
||||
SimpleNormalCompletion,
|
||||
NormalCompletion,
|
||||
ReturnCompletion,
|
||||
ThrowCompletion,
|
||||
@ -152,7 +153,7 @@ export class JoinImplementation {
|
||||
invariant(c.savedEffects === undefined); // the caller should ensure this
|
||||
let savedPathConditions = pnc.savedPathConditions;
|
||||
if (pnc.consequent instanceof AbruptCompletion) {
|
||||
if (pnc.alternate instanceof Value) {
|
||||
if (pnc.alternate instanceof SimpleNormalCompletion) {
|
||||
let { generator, modifiedBindings, modifiedProperties, createdObjects } = pnc.alternateEffects;
|
||||
let newAlternateEffects = new Effects(c, generator, modifiedBindings, modifiedProperties, createdObjects);
|
||||
return new PossiblyNormalCompletion(
|
||||
@ -182,7 +183,7 @@ export class JoinImplementation {
|
||||
);
|
||||
} else {
|
||||
invariant(pnc.alternate instanceof AbruptCompletion);
|
||||
if (pnc.consequent instanceof Value) {
|
||||
if (pnc.consequent instanceof SimpleNormalCompletion) {
|
||||
let { generator, modifiedBindings, modifiedProperties, createdObjects } = pnc.consequentEffects;
|
||||
let newConsequentEffects = new Effects(c, generator, modifiedBindings, modifiedProperties, createdObjects);
|
||||
return new PossiblyNormalCompletion(
|
||||
@ -219,10 +220,10 @@ export class JoinImplementation {
|
||||
subsequentEffects: Effects
|
||||
) {
|
||||
let v = subsequentEffects.result;
|
||||
invariant(v instanceof Value);
|
||||
pnc.value = v;
|
||||
invariant(v instanceof SimpleNormalCompletion);
|
||||
pnc.value = v.value;
|
||||
if (pnc.consequent instanceof AbruptCompletion) {
|
||||
if (pnc.alternate instanceof Value) {
|
||||
if (pnc.alternate instanceof SimpleNormalCompletion) {
|
||||
pnc.alternate = v;
|
||||
pnc.alternateEffects.result = v;
|
||||
pnc.alternateEffects = realm.composeEffects(pnc.alternateEffects, subsequentEffects);
|
||||
@ -231,7 +232,7 @@ export class JoinImplementation {
|
||||
this.updatePossiblyNormalCompletionWithSubsequentEffects(realm, pnc.alternate, subsequentEffects);
|
||||
}
|
||||
} else {
|
||||
if (pnc.consequent instanceof Value) {
|
||||
if (pnc.consequent instanceof SimpleNormalCompletion) {
|
||||
pnc.consequent = v;
|
||||
pnc.consequentEffects.result = v;
|
||||
pnc.consequentEffects = realm.composeEffects(pnc.consequentEffects, subsequentEffects);
|
||||
@ -243,13 +244,15 @@ export class JoinImplementation {
|
||||
}
|
||||
|
||||
updatePossiblyNormalCompletionWithValue(realm: Realm, pnc: PossiblyNormalCompletion, v: Value) {
|
||||
let nc = new SimpleNormalCompletion(v);
|
||||
pnc.value = v;
|
||||
if (pnc.consequent instanceof AbruptCompletion) {
|
||||
Path.withInverseCondition(pnc.joinCondition, () => {
|
||||
if (v instanceof AbstractValue) v = realm.simplifyAndRefineAbstractValue(v);
|
||||
if (pnc.alternate instanceof Value) {
|
||||
pnc.alternate = v;
|
||||
pnc.alternateEffects.result = v;
|
||||
if (pnc.alternate instanceof SimpleNormalCompletion) {
|
||||
nc.value = v;
|
||||
pnc.alternate = nc;
|
||||
pnc.alternateEffects.result = nc;
|
||||
pnc.value = v;
|
||||
} else {
|
||||
invariant(pnc.alternate instanceof PossiblyNormalCompletion);
|
||||
@ -261,9 +264,10 @@ export class JoinImplementation {
|
||||
} else {
|
||||
Path.withCondition(pnc.joinCondition, () => {
|
||||
if (v instanceof AbstractValue) v = realm.simplifyAndRefineAbstractValue(v);
|
||||
if (pnc.consequent instanceof Value) {
|
||||
pnc.consequent = v;
|
||||
pnc.consequentEffects.result = v;
|
||||
if (pnc.consequent instanceof SimpleNormalCompletion) {
|
||||
nc.value = v;
|
||||
pnc.consequent = nc;
|
||||
pnc.consequentEffects.result = nc;
|
||||
pnc.value = v;
|
||||
} else {
|
||||
invariant(pnc.consequent instanceof PossiblyNormalCompletion);
|
||||
@ -289,7 +293,7 @@ export class JoinImplementation {
|
||||
let pncc = pnc.consequent;
|
||||
if (pncc instanceof AbruptCompletion) {
|
||||
e = realm.composeEffects(pnc.alternateEffects, e);
|
||||
if (pnc.alternate instanceof Value) {
|
||||
if (pnc.alternate instanceof SimpleNormalCompletion) {
|
||||
return new ForkedAbruptCompletion(realm, pnc.joinCondition, pncc, pnc.consequentEffects, ac, e);
|
||||
}
|
||||
invariant(pnc.alternate instanceof PossiblyNormalCompletion);
|
||||
@ -301,7 +305,7 @@ export class JoinImplementation {
|
||||
let pnca = pnc.alternate;
|
||||
invariant(pnca instanceof AbruptCompletion);
|
||||
e = realm.composeEffects(pnc.consequentEffects, e);
|
||||
if (pnc.consequent instanceof Value) {
|
||||
if (pnc.consequent instanceof SimpleNormalCompletion) {
|
||||
return new ForkedAbruptCompletion(realm, pnc.joinCondition, ac, e, pnca, pnc.alternateEffects);
|
||||
}
|
||||
invariant(pnc.consequent instanceof PossiblyNormalCompletion);
|
||||
@ -312,52 +316,78 @@ export class JoinImplementation {
|
||||
}
|
||||
}
|
||||
|
||||
updatePossiblyNormalCompletionWithConditionalValue(
|
||||
updatePossiblyNormalCompletionWithConditionalSimpleNormalCompletion(
|
||||
realm: Realm,
|
||||
joinCondition: AbstractValue,
|
||||
pnc: PossiblyNormalCompletion,
|
||||
v: Value
|
||||
nc: SimpleNormalCompletion
|
||||
) {
|
||||
let v = nc.value;
|
||||
if (pnc.consequent instanceof AbruptCompletion) {
|
||||
if (pnc.alternate instanceof Value) {
|
||||
pnc.alternate = AbstractValue.createFromConditionalOp(realm, joinCondition, pnc.alternate, v);
|
||||
if (pnc.alternate instanceof SimpleNormalCompletion) {
|
||||
nc.value = AbstractValue.createFromConditionalOp(realm, joinCondition, pnc.alternate.value, v);
|
||||
pnc.alternate = nc;
|
||||
pnc.alternateEffects.result = pnc.alternate;
|
||||
} else {
|
||||
invariant(pnc.alternate instanceof PossiblyNormalCompletion);
|
||||
this.updatePossiblyNormalCompletionWithConditionalValue(realm, joinCondition, pnc.alternate, v);
|
||||
this.updatePossiblyNormalCompletionWithConditionalSimpleNormalCompletion(
|
||||
realm,
|
||||
joinCondition,
|
||||
pnc.alternate,
|
||||
nc
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (pnc.consequent instanceof Value) {
|
||||
pnc.consequent = AbstractValue.createFromConditionalOp(realm, joinCondition, pnc.consequent, v);
|
||||
if (pnc.consequent instanceof SimpleNormalCompletion) {
|
||||
nc.value = AbstractValue.createFromConditionalOp(realm, joinCondition, pnc.consequent.value, v);
|
||||
pnc.consequent = nc;
|
||||
pnc.consequentEffects.result = pnc.consequent;
|
||||
} else {
|
||||
invariant(pnc.consequent instanceof PossiblyNormalCompletion);
|
||||
this.updatePossiblyNormalCompletionWithConditionalValue(realm, joinCondition, pnc.consequent, v);
|
||||
this.updatePossiblyNormalCompletionWithConditionalSimpleNormalCompletion(
|
||||
realm,
|
||||
joinCondition,
|
||||
pnc.consequent,
|
||||
nc
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updatePossiblyNormalCompletionWithInverseConditionalValue(
|
||||
updatePossiblyNormalCompletionWithInverseConditionalSimpleNormalCompletion(
|
||||
realm: Realm,
|
||||
joinCondition: AbstractValue,
|
||||
pnc: PossiblyNormalCompletion,
|
||||
v: Value
|
||||
nc: SimpleNormalCompletion
|
||||
) {
|
||||
let v = nc.value;
|
||||
if (pnc.consequent instanceof AbruptCompletion) {
|
||||
if (pnc.alternate instanceof Value) {
|
||||
pnc.alternate = AbstractValue.createFromConditionalOp(realm, joinCondition, v, pnc.alternate);
|
||||
if (pnc.alternate instanceof SimpleNormalCompletion) {
|
||||
nc.value = AbstractValue.createFromConditionalOp(realm, joinCondition, v, pnc.alternate.value);
|
||||
pnc.alternate = nc;
|
||||
pnc.alternateEffects.result = pnc.alternate;
|
||||
} else {
|
||||
invariant(pnc.alternate instanceof PossiblyNormalCompletion);
|
||||
this.updatePossiblyNormalCompletionWithInverseConditionalValue(realm, joinCondition, pnc.alternate, v);
|
||||
this.updatePossiblyNormalCompletionWithInverseConditionalSimpleNormalCompletion(
|
||||
realm,
|
||||
joinCondition,
|
||||
pnc.alternate,
|
||||
nc
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (pnc.consequent instanceof Value) {
|
||||
pnc.consequent = AbstractValue.createFromConditionalOp(realm, joinCondition, v, pnc.consequent);
|
||||
if (pnc.consequent instanceof SimpleNormalCompletion) {
|
||||
nc.value = AbstractValue.createFromConditionalOp(realm, joinCondition, v, pnc.consequent.value);
|
||||
pnc.consequent = nc;
|
||||
pnc.consequentEffects.result = pnc.consequent;
|
||||
} else {
|
||||
invariant(pnc.consequent instanceof PossiblyNormalCompletion);
|
||||
this.updatePossiblyNormalCompletionWithInverseConditionalValue(realm, joinCondition, pnc.consequent, v);
|
||||
this.updatePossiblyNormalCompletionWithInverseConditionalSimpleNormalCompletion(
|
||||
realm,
|
||||
joinCondition,
|
||||
pnc.consequent,
|
||||
nc
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -368,12 +398,17 @@ export class JoinImplementation {
|
||||
c: PossiblyNormalCompletion,
|
||||
a: PossiblyNormalCompletion
|
||||
): PossiblyNormalCompletion {
|
||||
let getAbstractValue = (v1: void | Value, v2: void | Value): Value => {
|
||||
if (v1 instanceof EmptyValue) return v2 || realm.intrinsics.undefined;
|
||||
if (v2 instanceof EmptyValue) return v1 || realm.intrinsics.undefined;
|
||||
return AbstractValue.createFromConditionalOp(realm, joinCondition, v1, v2);
|
||||
};
|
||||
let ac = new AbruptCompletion(realm.intrinsics.empty);
|
||||
let ee = construct_empty_effects(realm, ac);
|
||||
let fc = this.replacePossiblyNormalCompletionWithForkedAbruptCompletion(realm, c, ac, ee);
|
||||
let ce = construct_empty_effects(realm, fc);
|
||||
let ae = construct_empty_effects(realm, a);
|
||||
let rv = this.collapseResults(realm, joinCondition, c.value, a.value);
|
||||
let rv = this.joinValues(realm, c.value, a.value, getAbstractValue);
|
||||
invariant(rv instanceof Value);
|
||||
a.value = rv;
|
||||
return new PossiblyNormalCompletion(rv, joinCondition, fc, ce, a, ae, []);
|
||||
@ -409,7 +444,9 @@ export class JoinImplementation {
|
||||
if (ce.result instanceof CompletionType) {
|
||||
// Erase completions of type CompletionType and prepare for transformation of c to a possibly normal completion
|
||||
if (c.consequent instanceof CompletionType) {
|
||||
c.consequentEffects.result = c.consequent = convertToPNC ? (realm.intrinsics.empty: any) : dummyCompletion;
|
||||
c.consequentEffects.result = c.consequent = convertToPNC
|
||||
? new SimpleNormalCompletion(realm.intrinsics.empty)
|
||||
: dummyCompletion;
|
||||
convertToPNC = false;
|
||||
} else if (convertToPNC && c.consequent instanceof ForkedAbruptCompletion) {
|
||||
c.consequentEffects.result = c.consequent = (c.consequent.transferChildrenToPossiblyNormalCompletion(): any);
|
||||
@ -427,7 +464,9 @@ export class JoinImplementation {
|
||||
if (ae.result instanceof CompletionType) {
|
||||
// Erase completions of type CompletionType and prepare for transformation of c to a possibly normal completion
|
||||
if (c.alternate instanceof CompletionType) {
|
||||
c.alternateEffects.result = c.alternate = convertToPNC ? (realm.intrinsics.empty: any) : dummyCompletion;
|
||||
c.alternateEffects.result = c.alternate = convertToPNC
|
||||
? new SimpleNormalCompletion(realm.intrinsics.empty)
|
||||
: dummyCompletion;
|
||||
} else if (convertToPNC && c.alternate instanceof ForkedAbruptCompletion) {
|
||||
c.alternateEffects.result = c.alternate = (c.alternate.transferChildrenToPossiblyNormalCompletion(): any);
|
||||
}
|
||||
@ -498,7 +537,7 @@ export class JoinImplementation {
|
||||
return new Effects(result, generator, bindings, properties, createdObjects);
|
||||
}
|
||||
|
||||
joinNestedEffects(realm: Realm, c: Completion | Value, precedingEffects?: Effects): Effects {
|
||||
joinNestedEffects(realm: Realm, c: Completion, precedingEffects?: Effects): Effects {
|
||||
if (c instanceof PossiblyNormalCompletion || c instanceof ForkedAbruptCompletion) {
|
||||
let e1 = this.joinNestedEffects(realm, c.consequent, c.consequentEffects);
|
||||
let e2 = this.joinNestedEffects(realm, c.alternate, c.alternateEffects);
|
||||
@ -517,8 +556,8 @@ export class JoinImplementation {
|
||||
joinCondition: AbstractValue,
|
||||
result1: EvaluationResult,
|
||||
result2: EvaluationResult
|
||||
): AbruptCompletion | PossiblyNormalCompletion | Value {
|
||||
let getAbstractValue = (v1: void | Value, v2: void | Value) => {
|
||||
): Completion {
|
||||
let getAbstractValue = (v1: void | Value, v2: void | Value): Value => {
|
||||
if (v1 instanceof EmptyValue) return v2 || realm.intrinsics.undefined;
|
||||
if (v2 instanceof EmptyValue) return v1 || realm.intrinsics.undefined;
|
||||
return AbstractValue.createFromConditionalOp(realm, joinCondition, v1, v2);
|
||||
@ -548,8 +587,8 @@ export class JoinImplementation {
|
||||
invariant(val instanceof Value);
|
||||
return new ThrowCompletion(val, result1.location);
|
||||
}
|
||||
if (result1 instanceof Value && result2 instanceof Value) {
|
||||
return getAbstractValue(result1, result2);
|
||||
if (result1 instanceof SimpleNormalCompletion && result2 instanceof SimpleNormalCompletion) {
|
||||
return new SimpleNormalCompletion(getAbstractValue(result1.value, result2.value));
|
||||
}
|
||||
AbstractValue.reportIntrospectionError(joinCondition);
|
||||
throw new FatalError();
|
||||
@ -562,7 +601,7 @@ export class JoinImplementation {
|
||||
result2: EvaluationResult,
|
||||
e1: Effects,
|
||||
e2: Effects
|
||||
): AbruptCompletion | PossiblyNormalCompletion | Value {
|
||||
): Completion {
|
||||
let getAbstractValue = (v1: void | Value, v2: void | Value) => {
|
||||
return AbstractValue.createFromConditionalOp(realm, joinCondition, v1, v2);
|
||||
};
|
||||
@ -570,10 +609,10 @@ export class JoinImplementation {
|
||||
AbstractValue.reportIntrospectionError(joinCondition);
|
||||
throw new FatalError();
|
||||
}
|
||||
if (result1 instanceof Value && result2 instanceof Value) {
|
||||
let val = this.joinValues(realm, result1, result2, getAbstractValue);
|
||||
if (result1 instanceof SimpleNormalCompletion && result2 instanceof SimpleNormalCompletion) {
|
||||
let val = this.joinValues(realm, result1.value, result2.value, getAbstractValue);
|
||||
invariant(val instanceof Value);
|
||||
return val;
|
||||
return new SimpleNormalCompletion(val);
|
||||
}
|
||||
if (result1 instanceof AbruptCompletion && result2 instanceof AbruptCompletion) {
|
||||
return new ForkedAbruptCompletion(realm, joinCondition, result1, e1, result2, e2);
|
||||
@ -582,17 +621,17 @@ export class JoinImplementation {
|
||||
return this.joinPossiblyNormalCompletions(realm, joinCondition, result1, result2);
|
||||
}
|
||||
if (result1 instanceof AbruptCompletion) {
|
||||
let value = result2;
|
||||
let completion = result2;
|
||||
let savedEffects;
|
||||
let savedPathConditions = [];
|
||||
if (result2 instanceof PossiblyNormalCompletion) {
|
||||
value = result2.value;
|
||||
completion = result2.getNormalCompletion();
|
||||
savedEffects = result2.savedEffects;
|
||||
savedPathConditions = result2.savedPathConditions;
|
||||
}
|
||||
invariant(value instanceof Value);
|
||||
invariant(completion instanceof SimpleNormalCompletion);
|
||||
return new PossiblyNormalCompletion(
|
||||
value,
|
||||
completion.value,
|
||||
joinCondition,
|
||||
result1,
|
||||
e1,
|
||||
@ -603,17 +642,17 @@ export class JoinImplementation {
|
||||
);
|
||||
}
|
||||
if (result2 instanceof AbruptCompletion) {
|
||||
let value = result1;
|
||||
let completion = result1;
|
||||
let savedEffects;
|
||||
let savedPathConditions = [];
|
||||
if (result1 instanceof PossiblyNormalCompletion) {
|
||||
value = result1.value;
|
||||
completion = result1.value;
|
||||
savedEffects = result1.savedEffects;
|
||||
savedPathConditions = result1.savedPathConditions;
|
||||
}
|
||||
invariant(value instanceof Value);
|
||||
invariant(completion instanceof SimpleNormalCompletion);
|
||||
return new PossiblyNormalCompletion(
|
||||
value,
|
||||
completion.value,
|
||||
joinCondition,
|
||||
result1,
|
||||
e1,
|
||||
@ -624,13 +663,18 @@ export class JoinImplementation {
|
||||
);
|
||||
}
|
||||
if (result1 instanceof PossiblyNormalCompletion) {
|
||||
invariant(result2 instanceof Value);
|
||||
this.updatePossiblyNormalCompletionWithConditionalValue(realm, joinCondition, result1, result2);
|
||||
invariant(result2 instanceof SimpleNormalCompletion);
|
||||
this.updatePossiblyNormalCompletionWithConditionalSimpleNormalCompletion(realm, joinCondition, result1, result2);
|
||||
return result1;
|
||||
}
|
||||
if (result2 instanceof PossiblyNormalCompletion) {
|
||||
invariant(result1 instanceof Value);
|
||||
this.updatePossiblyNormalCompletionWithInverseConditionalValue(realm, joinCondition, result2, result1);
|
||||
invariant(result1 instanceof SimpleNormalCompletion);
|
||||
this.updatePossiblyNormalCompletionWithInverseConditionalSimpleNormalCompletion(
|
||||
realm,
|
||||
joinCondition,
|
||||
result2,
|
||||
result1
|
||||
);
|
||||
return result2;
|
||||
}
|
||||
invariant(false);
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
/* @flow */
|
||||
|
||||
import { AbruptCompletion, PossiblyNormalCompletion } from "../completions.js";
|
||||
import { AbruptCompletion, PossiblyNormalCompletion, SimpleNormalCompletion } from "../completions.js";
|
||||
import { construct_empty_effects, type Realm, Effects } from "../realm.js";
|
||||
import type { Descriptor, PropertyBinding, PropertyKeyValue } from "../types.js";
|
||||
import {
|
||||
@ -341,6 +341,7 @@ export class PropertiesImplementation {
|
||||
|
||||
// return or throw completion
|
||||
if (completion instanceof AbruptCompletion) throw completion;
|
||||
if (completion instanceof SimpleNormalCompletion) completion = completion.value;
|
||||
invariant(completion instanceof Value);
|
||||
return To.ToBooleanPartial(realm, completion);
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ import type { Bindings, BindingEntry, EvaluationResult, PropertyBindings, Create
|
||||
import { Effects } from "../realm.js";
|
||||
import type { Descriptor, PropertyBinding } from "../types.js";
|
||||
|
||||
import { AbruptCompletion, PossiblyNormalCompletion } from "../completions.js";
|
||||
import { AbruptCompletion, PossiblyNormalCompletion, SimpleNormalCompletion } from "../completions.js";
|
||||
import { Reference } from "../environment.js";
|
||||
import { cloneDescriptor, equalDescriptors, IsDataDescriptor, StrictEqualityComparison } from "../methods/index.js";
|
||||
import { Generator } from "../utils/generator.js";
|
||||
@ -100,16 +100,20 @@ export class WidenImplementation {
|
||||
return new Effects(result, generator, bindings, properties, createdObjects);
|
||||
}
|
||||
|
||||
widenResults(realm: Realm, result1: EvaluationResult, result2: EvaluationResult): PossiblyNormalCompletion | Value {
|
||||
widenResults(
|
||||
realm: Realm,
|
||||
result1: EvaluationResult,
|
||||
result2: EvaluationResult
|
||||
): PossiblyNormalCompletion | SimpleNormalCompletion {
|
||||
invariant(!(result1 instanceof Reference || result2 instanceof Reference), "loop bodies should not result in refs");
|
||||
invariant(
|
||||
!(result1 instanceof AbruptCompletion || result2 instanceof AbruptCompletion),
|
||||
"if a loop iteration ends abruptly, there is no need for fixed point computation"
|
||||
);
|
||||
if (result1 instanceof Value && result2 instanceof Value) {
|
||||
let val = this.widenValues(realm, result1, result2);
|
||||
if (result1 instanceof SimpleNormalCompletion && result2 instanceof SimpleNormalCompletion) {
|
||||
let val = this.widenValues(realm, result1.value, result2.value);
|
||||
invariant(val instanceof Value);
|
||||
return val;
|
||||
return new SimpleNormalCompletion(val);
|
||||
}
|
||||
if (result1 instanceof PossiblyNormalCompletion || result2 instanceof PossiblyNormalCompletion) {
|
||||
//todo: #1174 figure out how to deal with loops that have embedded conditional exits
|
||||
@ -348,7 +352,8 @@ export class WidenImplementation {
|
||||
}
|
||||
|
||||
containsResults(result1: EvaluationResult, result2: EvaluationResult): boolean {
|
||||
if (result1 instanceof Value && result2 instanceof Value) return this._containsValues(result1, result2);
|
||||
if (result1 instanceof SimpleNormalCompletion && result2 instanceof SimpleNormalCompletion)
|
||||
return this._containsValues(result1.value, result2.value);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ import type { Realm } from "../realm.js";
|
||||
import { Effects } from "../realm.js";
|
||||
import type { LexicalEnvironment } from "../environment.js";
|
||||
|
||||
import { AbruptCompletion, Completion, PossiblyNormalCompletion } from "../completions.js";
|
||||
import { AbruptCompletion, Completion, PossiblyNormalCompletion, SimpleNormalCompletion } from "../completions.js";
|
||||
import { EnvironmentRecord, Reference } from "../environment.js";
|
||||
import { EvaluateDirectCallWithArgList, GetThisValue, IsInTailPosition, SameValue } from "../methods/index.js";
|
||||
import { Environment, Functions, Join } from "../singletons.js";
|
||||
@ -134,6 +134,7 @@ function callBothFunctionsAndJoinTheirEffects(
|
||||
realm.applyEffects(joinedEffects);
|
||||
|
||||
// return or throw completion
|
||||
if (joinedCompletion instanceof SimpleNormalCompletion) joinedCompletion = joinedCompletion.value;
|
||||
invariant(joinedCompletion instanceof AbruptCompletion || joinedCompletion instanceof Value);
|
||||
return joinedCompletion;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
import type { Realm } from "../../realm.js";
|
||||
import { ReactStatistics } from "../../serializer/types.js";
|
||||
import { SimpleNormalCompletion } from "../../completions.js";
|
||||
import {
|
||||
AbstractObjectValue,
|
||||
AbstractValue,
|
||||
@ -456,8 +457,8 @@ function handleNestedOptimizedFunctions(realm: Realm, reconciler: Reconciler, st
|
||||
[closureEffects],
|
||||
() => {
|
||||
let serverRenderer = new ReactDOMServerRenderer(realm, staticMarkup);
|
||||
invariant(closureEffects.result instanceof Value);
|
||||
return serverRenderer.render(closureEffects.result);
|
||||
invariant(closureEffects.result instanceof SimpleNormalCompletion);
|
||||
return serverRenderer.render(closureEffects.result.value);
|
||||
},
|
||||
"handleNestedOptimizedFunctions"
|
||||
);
|
||||
@ -498,9 +499,9 @@ export function renderToString(
|
||||
);
|
||||
invariant(effects);
|
||||
realm.applyEffects(effects);
|
||||
invariant(effects.result instanceof Value);
|
||||
invariant(effects.result instanceof SimpleNormalCompletion);
|
||||
let serverRenderer = new ReactDOMServerRenderer(realm, staticMarkup);
|
||||
let renderValue = serverRenderer.render(effects.result);
|
||||
let renderValue = serverRenderer.render(effects.result.value);
|
||||
handleNestedOptimizedFunctions(realm, reconciler, staticMarkup);
|
||||
return renderValue;
|
||||
}
|
||||
|
28
src/realm.js
28
src/realm.js
@ -55,6 +55,7 @@ import { cloneDescriptor, Construct } from "./methods/index.js";
|
||||
import {
|
||||
AbruptCompletion,
|
||||
Completion,
|
||||
SimpleNormalCompletion,
|
||||
ForkedAbruptCompletion,
|
||||
PossiblyNormalCompletion,
|
||||
ThrowCompletion,
|
||||
@ -78,7 +79,7 @@ export type BindingEntry = {
|
||||
previousValue: void | Value,
|
||||
};
|
||||
export type Bindings = Map<Binding, BindingEntry>;
|
||||
export type EvaluationResult = Completion | Reference | Value;
|
||||
export type EvaluationResult = Completion | Reference;
|
||||
export type PropertyBindings = Map<PropertyBinding, void | Descriptor>;
|
||||
|
||||
export type CreatedObjects = Set<ObjectValue>;
|
||||
@ -191,7 +192,10 @@ export class ExecutionContext {
|
||||
}
|
||||
}
|
||||
|
||||
export function construct_empty_effects(realm: Realm, c: Completion | Value = realm.intrinsics.empty): Effects {
|
||||
export function construct_empty_effects(
|
||||
realm: Realm,
|
||||
c: Completion = new SimpleNormalCompletion(realm.intrinsics.empty)
|
||||
): Effects {
|
||||
return new Effects(c, new Generator(realm, "construct_empty_effects"), new Map(), new Map(), new Set());
|
||||
}
|
||||
|
||||
@ -827,6 +831,7 @@ export class Realm {
|
||||
*/
|
||||
|
||||
// Return the captured state changes and evaluation result
|
||||
if (c instanceof Value) c = new SimpleNormalCompletion(c);
|
||||
result = new Effects(c, astGenerator, astBindings, astProperties, astCreatedObjects);
|
||||
return result;
|
||||
} finally {
|
||||
@ -875,7 +880,7 @@ export class Realm {
|
||||
undefined,
|
||||
"evaluateWithUndo"
|
||||
);
|
||||
return effects.result instanceof Value ? effects.result : defaultValue;
|
||||
return effects.result instanceof SimpleNormalCompletion ? effects.result.value : defaultValue;
|
||||
} finally {
|
||||
this.errorHandler = oldErrorHandler;
|
||||
}
|
||||
@ -901,8 +906,8 @@ export class Realm {
|
||||
// all the branches come together into one.
|
||||
resultVal = this.composeWithSavedCompletion(resultVal);
|
||||
}
|
||||
invariant(resultVal instanceof Value);
|
||||
return resultVal;
|
||||
invariant(resultVal instanceof SimpleNormalCompletion);
|
||||
return resultVal.value;
|
||||
} catch (e) {
|
||||
if (diagnostic !== undefined) return diagnostic;
|
||||
throw e;
|
||||
@ -918,7 +923,7 @@ export class Realm {
|
||||
let result;
|
||||
[test, result] = iteration();
|
||||
if (!(test instanceof AbstractValue)) throw new FatalError("loop terminates before fixed point");
|
||||
invariant(result instanceof Completion || result instanceof Value);
|
||||
invariant(result instanceof Completion);
|
||||
return result;
|
||||
};
|
||||
let effects1 = this.evaluateForEffects(f, undefined, "evaluateForFixpointEffects/1");
|
||||
@ -999,6 +1004,7 @@ export class Realm {
|
||||
|
||||
// return or throw completion
|
||||
if (completion instanceof AbruptCompletion) throw completion;
|
||||
if (completion instanceof SimpleNormalCompletion) completion = completion.value;
|
||||
invariant(completion instanceof Value);
|
||||
return completion;
|
||||
}
|
||||
@ -1255,7 +1261,7 @@ export class Realm {
|
||||
captureEffects(completion: PossiblyNormalCompletion) {
|
||||
invariant(completion.savedEffects === undefined);
|
||||
completion.savedEffects = new Effects(
|
||||
this.intrinsics.undefined,
|
||||
new SimpleNormalCompletion(this.intrinsics.undefined),
|
||||
(this.generator: any),
|
||||
(this.modifiedBindings: any),
|
||||
(this.modifiedProperties: any),
|
||||
@ -1272,7 +1278,13 @@ export class Realm {
|
||||
invariant(this.modifiedBindings !== undefined);
|
||||
invariant(this.modifiedProperties !== undefined);
|
||||
invariant(this.createdObjects !== undefined);
|
||||
return new Effects(v, this.generator, this.modifiedBindings, this.modifiedProperties, this.createdObjects);
|
||||
return new Effects(
|
||||
new SimpleNormalCompletion(v),
|
||||
this.generator,
|
||||
this.modifiedBindings,
|
||||
this.modifiedProperties,
|
||||
this.createdObjects
|
||||
);
|
||||
}
|
||||
|
||||
stopEffectCaptureAndUndoEffects(completion: PossiblyNormalCompletion) {
|
||||
|
15
src/types.js
15
src/types.js
@ -32,8 +32,9 @@ import {
|
||||
AbruptCompletion,
|
||||
Completion,
|
||||
ForkedAbruptCompletion,
|
||||
NormalCompletion,
|
||||
SimpleNormalCompletion,
|
||||
PossiblyNormalCompletion,
|
||||
NormalCompletion,
|
||||
} from "./completions.js";
|
||||
import { EnvironmentRecord, LexicalEnvironment, Reference } from "./environment.js";
|
||||
import { Generator } from "./utils/generator.js";
|
||||
@ -739,18 +740,18 @@ export type JoinType = {
|
||||
e: Effects
|
||||
): ForkedAbruptCompletion,
|
||||
|
||||
updatePossiblyNormalCompletionWithConditionalValue(
|
||||
updatePossiblyNormalCompletionWithConditionalSimpleNormalCompletion(
|
||||
realm: Realm,
|
||||
joinCondition: AbstractValue,
|
||||
pnc: PossiblyNormalCompletion,
|
||||
v: Value
|
||||
nc: SimpleNormalCompletion
|
||||
): void,
|
||||
|
||||
updatePossiblyNormalCompletionWithInverseConditionalValue(
|
||||
updatePossiblyNormalCompletionWithInverseConditionalSimpleNormalCompletion(
|
||||
realm: Realm,
|
||||
joinCondition: AbstractValue,
|
||||
pnc: PossiblyNormalCompletion,
|
||||
v: Value
|
||||
nc: SimpleNormalCompletion
|
||||
): void,
|
||||
|
||||
extractAndJoinCompletionsOfType(
|
||||
@ -769,7 +770,7 @@ export type JoinType = {
|
||||
joinCondition: AbstractValue,
|
||||
result1: EvaluationResult,
|
||||
result2: EvaluationResult
|
||||
): AbruptCompletion | PossiblyNormalCompletion | Value,
|
||||
): Completion,
|
||||
|
||||
joinOrForkResults(
|
||||
realm: Realm,
|
||||
@ -778,7 +779,7 @@ export type JoinType = {
|
||||
result2: EvaluationResult,
|
||||
e1: Effects,
|
||||
e2: Effects
|
||||
): AbruptCompletion | PossiblyNormalCompletion | Value,
|
||||
): Completion,
|
||||
|
||||
composeGenerators(realm: Realm, generator1: Generator, generator2: Generator): Generator,
|
||||
|
||||
|
@ -41,6 +41,7 @@ import {
|
||||
ThrowCompletion,
|
||||
ReturnCompletion,
|
||||
PossiblyNormalCompletion,
|
||||
SimpleNormalCompletion,
|
||||
} from "../completions.js";
|
||||
import type {
|
||||
BabelNodeExpression,
|
||||
@ -436,9 +437,7 @@ export class Generator {
|
||||
}
|
||||
|
||||
if (result instanceof UndefinedValue) return output;
|
||||
if (result instanceof Value) {
|
||||
output.emitReturnValue(result);
|
||||
} else if (result instanceof ReturnCompletion) {
|
||||
if (result instanceof SimpleNormalCompletion || result instanceof ReturnCompletion) {
|
||||
output.emitReturnValue(result.value);
|
||||
} else if (result instanceof PossiblyNormalCompletion || result instanceof ForkedAbruptCompletion) {
|
||||
output.emitIfThenElse(result, realm);
|
||||
|
@ -64,7 +64,7 @@ export class Logger {
|
||||
undefined,
|
||||
"tryQuery"
|
||||
);
|
||||
invariant(effects.result === realm.intrinsics.undefined);
|
||||
invariant(effects.result.value === realm.intrinsics.undefined);
|
||||
return ((result: any): T);
|
||||
} finally {
|
||||
realm.errorHandler = oldErrorHandler;
|
||||
|
@ -14,7 +14,7 @@ import { CompilerDiagnostic, FatalError } from "../errors.js";
|
||||
import { Realm, Tracer } from "../realm.js";
|
||||
import type { Effects } from "../realm.js";
|
||||
import { Get } from "../methods/index.js";
|
||||
import { AbruptCompletion, PossiblyNormalCompletion } from "../completions.js";
|
||||
import { AbruptCompletion, PossiblyNormalCompletion, SimpleNormalCompletion } from "../completions.js";
|
||||
import { Environment } from "../singletons.js";
|
||||
import {
|
||||
AbstractValue,
|
||||
@ -251,9 +251,9 @@ export class ModuleTracer extends Tracer {
|
||||
);
|
||||
} else {
|
||||
result = effects.result;
|
||||
if (result instanceof Value) {
|
||||
if (result instanceof SimpleNormalCompletion) {
|
||||
realm.applyEffects(effects, `initialization of module ${moduleIdValue}`);
|
||||
this.modules.recordModuleInitialized(moduleIdValue, result);
|
||||
this.modules.recordModuleInitialized(moduleIdValue, result.value);
|
||||
} else if (result instanceof PossiblyNormalCompletion) {
|
||||
let warning = new CompilerDiagnostic(
|
||||
"Module import may fail with an exception",
|
||||
@ -273,6 +273,7 @@ export class ModuleTracer extends Tracer {
|
||||
invariant(popped === moduleIdValue);
|
||||
this.log(`<require(${moduleIdValue})`);
|
||||
}
|
||||
if (result instanceof SimpleNormalCompletion) result = result.value;
|
||||
invariant(result instanceof Value);
|
||||
return result;
|
||||
});
|
||||
@ -625,6 +626,7 @@ export class Modules {
|
||||
invariant(modifiedBindings);
|
||||
|
||||
if (result instanceof AbruptCompletion) return undefined;
|
||||
if (result instanceof SimpleNormalCompletion) result = result.value;
|
||||
invariant(result instanceof Value);
|
||||
|
||||
if (!generator.empty() || (result instanceof ObjectValue && createdObjects.has(result))) return undefined;
|
||||
|
@ -123,6 +123,10 @@ export default class AbstractValue extends Value {
|
||||
args: Array<Value>;
|
||||
_buildNode: void | AbstractValueBuildNodeFunction | BabelNodeExpression;
|
||||
|
||||
toDisplayString(): string {
|
||||
return "[Abstract " + this.hashValue.toString() + "]";
|
||||
}
|
||||
|
||||
addSourceLocationsTo(locations: Array<BabelNodeSourceLocation>, seenValues?: Set<AbstractValue> = new Set()) {
|
||||
if (seenValues.has(this)) return;
|
||||
seenValues.add(this);
|
||||
|
@ -34,6 +34,12 @@ export default class Value {
|
||||
// Name from original source if existant
|
||||
__originalName: void | string;
|
||||
|
||||
toDisplayString(): string {
|
||||
return (
|
||||
"[" + this.constructor.name + " originally; " + (this.__originalName ? this.__originalName : "undefined") + "]"
|
||||
);
|
||||
}
|
||||
|
||||
equals(x: Value): boolean {
|
||||
invariant(false, "abstract method; please override");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user