prepack
Version:
Execute a JS bundle, serialize global state and side effects to a snapshot that can be quickly restored.
653 lines (496 loc) • 27.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.TextPrinter = void 0;
var _completions = require("../completions.js");
var _descriptors = require("../descriptors.js");
var _environment = require("../environment.js");
var _index = require("../values/index.js");
var _invariant = _interopRequireDefault(require("../invariant.js"));
var _generator = require("./generator.js");
var t = _interopRequireWildcard(require("@babel/types"));
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
const indent = " ";
class TextPrinter {
constructor(printLine, abstractValueIds = new Map(), symbolIds = new Map()) {
this._printLine = printLine;
this._abstractValueIds = abstractValueIds;
this._symbolIds = symbolIds;
this._indent = "";
this._objects = new Set();
this._propertyBindings = new Set();
this._environmentRecords = new Set();
this._bindings = new Set();
this._lexicalEnvironments = new Set();
this._symbols = new Set();
}
_nest() {
this._indent += indent;
}
_unnest() {
this._indent = this._indent.substring(0, this._indent.length - indent.length);
}
_print(text) {
this._printLine(this._indent + text);
}
_printDefinition(id, constructorName, args) {
this._print(`* ${id} = ${constructorName}(${args.join(", ")})`);
}
printGeneratorEntry(declared, type, args, data, metadata) {
switch (type) {
case "DO_WHILE":
(0, _invariant.default)(data.value !== undefined);
this._print(`do while ${this.describeValue(data.value)}`);
this._nest();
const generator = data.generator;
(0, _invariant.default)(generator !== undefined);
this.printGenerator(generator, "body");
this._unnest();
break;
case "JOIN_GENERATORS":
(0, _invariant.default)(args.length === 1);
this._print(`if ${this.describeValue(args[0])}`);
this._nest();
const generators = data.generators;
(0, _invariant.default)(generators !== undefined && generators.length === 2);
this.printGenerator(generators[0], "then");
this.printGenerator(generators[1], "else");
this._unnest();
break;
default:
let text;
if (declared !== undefined) {
(0, _invariant.default)(declared.intrinsicName !== undefined);
text = `${this.describeExpression(declared.intrinsicName)} := `;
} else {
text = "";
}
text += type;
const dataTexts = [];
if (data.unaryOperator !== undefined) dataTexts.push(`unary ${data.unaryOperator}`); // used by UNARY_EXPRESSION
if (data.binaryOperator !== undefined) dataTexts.push(`binary ${data.binaryOperator}`); // used by BINARY_EXPRESSION
if (data.logicalOperator !== undefined) dataTexts.push(`logical ${data.logicalOperator}`); // used by LOGICAL_EXPRESSION
if (data.incrementor !== undefined) dataTexts.push(`incrementor ${data.incrementor}`); // used by UPDATE_INCREMENTOR
if (data.prefix !== undefined) dataTexts.push("prefix"); // used by UNARY_EXPRESSION
if (data.binding !== undefined) dataTexts.push(`binding ${this.describeBinding(data.binding)}`); // used by GET_BINDING
if (data.propertyBinding !== undefined) dataTexts.push(`property binding ${this.describePropertyBinding(data.propertyBinding)}`); // used by LOGICAL_PROPERTY_ASSIGNMENT
if (data.object !== undefined) dataTexts.push(`object ${this.describeValue(data.object)}`); // used by DEFINE_PROPERTY
if (data.descriptor !== undefined) dataTexts.push(`desc ${this.describeDescriptor(data.descriptor)}`); // used by DEFINE_PROPERTY
if (data.value !== undefined) dataTexts.push(`value ${this.describeValue(data.value)}`); // used by DO_WHILE, CONDITIONAL_PROPERTY_ASSIGNMENT, LOGICAL_PROPERTY_ASSIGNMENT, LOCAL_ASSIGNMENT, CONDITIONAL_THROW, EMIT_PROPERTY_ASSIGNMENT
if (data.id !== undefined) dataTexts.push(`id ${this.describeExpression(data.id)}`); // used by IDENTIFIER
if (data.thisArg !== undefined) dataTexts.push(`this arg ${this.describeBaseValue(data.thisArg)}`); // used by CALL_BAILOUT
if (data.propRef !== undefined) dataTexts.push(`prop ref ${this.describeKey(data.propRef)}`); // used by CALL_BAILOUT, and then only if string
if (data.state !== undefined) dataTexts.push(`state ${data.state}`); // used by PROPERTY_INVARIANT
if (data.usesThis !== undefined) dataTexts.push(`usesThis`); // used by FOR_STATEMENT_FUNC
if (data.path !== undefined) dataTexts.push(`path ${this.describeValue(data.path)}`); // used by PROPERTY_ASSIGNMENT, CONDITIONAL_PROPERTY_ASSIGNMENT
if (data.callFunctionRef !== undefined) dataTexts.push(`call function ref ${this.describeExpression(data.callFunctionRef)}`); // used by EMIT_CALL and EMIT_CALL_AND_CAPTURE_RESULT
if (data.templateSource !== undefined) dataTexts.push(`template source ${this.describeExpression(data.templateSource)}`); // used by ABSTRACT_FROM_TEMPLATE
if (data.propertyGetter !== undefined) dataTexts.push(`property getter ${data.propertyGetter}`); // used by ABSTRACT_OBJECT_GET
// TODO:
// appendLastToInvariantOperationDescriptor?: OperationDescriptor, // used by INVARIANT
// concreteComparisons?: Array<Value>, // used by FULL_INVARIANT_ABSTRACT
// boundName?: BabelNodeIdentifier, // used by FOR_IN
// lh?: BabelNodeVariableDeclaration, // used by FOR_IN
// quasis?: Array<BabelNodeTemplateElement>, // used by REACT_SSR_TEMPLATE_LITERAL
// typeComparisons?: Set<typeof Value>, // used by FULL_INVARIANT_ABSTRACT
// violationConditionOperationDescriptor?: OperationDescriptor, // used by INVARIANT
if (dataTexts.length > 0) text += `<${dataTexts.join("; ")}>`;
if (args.length > 0) text += `(${this.describeValues(args)})`;
const metadataTexts = [];
if (metadata.isPure) metadataTexts.push("isPure");
if (metadata.mutatesOnly !== undefined && metadata.mutatesOnly.length > 0) metadataTexts.push(`mutates only: [${this.describeValues(metadata.mutatesOnly)}]`);
if (metadataTexts.length > 0) text += `[${metadataTexts.join("; ")}]`;
this._print(text);
break;
}
}
printGenerator(generator, label = "(entry point)") {
this._print(`${label}: ${JSON.stringify(generator.getName())}`);
this._nest();
if (generator.pathConditions.getLength() > 0) this._print(`path conditions ${this.describeValues(Array.from(generator.pathConditions.getAssumedConditions()))}`);
generator.print(this);
this._unnest();
}
print(realm, optimizedFunctions) {
const realmGenerator = realm.generator;
if (realmGenerator !== undefined) this.printGenerator(realmGenerator);
for (const [functionValue, generator] of optimizedFunctions) {
const effectsToApply = generator.effectsToApply;
(0, _invariant.default)(effectsToApply !== undefined);
this._print(`=== optimized function ${this.describeValue(functionValue)}`);
realm.withEffectsAppliedInGlobalEnv(effects => {
const nestedPrinter = new TextPrinter(this._printLine, this._abstractValueIds, this._symbolIds);
nestedPrinter.printEffects(effects, generator);
return nestedPrinter; // not needed, but withEffectsAppliedInGlobalEnv has an unmotivated invariant that the result must not be undefined
}, effectsToApply);
}
}
describeCompletion(result) {
const args = [];
if (result instanceof _completions.SimpleNormalCompletion) args.push(`value ${this.describeValue(result.value)}`);else if (result instanceof _completions.ThrowCompletion) args.push(`value ${this.describeValue(result.value)}`);else {
(0, _invariant.default)(result instanceof _completions.JoinedNormalAndAbruptCompletions);
args.push(`join condition ${this.describeValue(result.joinCondition)}`);
args.push(`consequent ${this.describeCompletion(result.consequent)}`);
args.push(`alternate ${this.describeCompletion(result.alternate)}`);
if (result.composedWith !== undefined) args.push(`composed with ${this.describeCompletion(result.composedWith)}`);
}
return `${result.constructor.name}(${args.join(", ")})`;
}
printEffects(effects, generator) {
this._nest();
this.printGenerator(generator || effects.generator); // skip effects.generator
if (effects.modifiedProperties.size > 0) this._print(`modified property bindings: [${Array.from(effects.modifiedProperties.keys()).map(propertyBinding => this.describePropertyBinding(propertyBinding)).join(", ")}]`);
if (effects.modifiedBindings.size > 0) this._print(`modified bindings: [${Array.from(effects.modifiedBindings.keys()).map(binding => this.describeBinding(binding)).join(", ")}]`);
if (effects.createdObjects.size > 0) this._print(`created objects: [${Array.from(effects.createdObjects).map(object => this.describeValue(object)).join(", ")}]`);
if (!(effects.result instanceof _index.UndefinedValue)) this._print(`result: ${this.describeCompletion(effects.result)}`);
this._unnest();
}
describeExpression(expression) {
if (t.isValidIdentifier(expression)) return expression;else return "@" + JSON.stringify(expression);
}
describeValues(values) {
return values.map(value => this.describeValue(value)).join(", ");
}
abstractValueName(value) {
const id = this._abstractValueIds.get(value);
(0, _invariant.default)(id !== undefined);
return `value#${id}`;
}
printAbstractValue(value) {
(0, _invariant.default)(value.intrinsicName === undefined);
let kind = value.kind; // TODO: I'd expect kind to be defined in this situation; however, it's not defined for test ForInStatement4.js
// invariant(kind !== undefined);
if (kind === undefined) kind = "(no kind)";
this._printDefinition(this.abstractValueName(value), this.describeExpression(kind), value.args.map(arg => this.describeValue(arg)));
}
objectValueName(value) {
(0, _invariant.default)(this._objects.has(value));
let name;
if (value instanceof _index.FunctionValue) name = "func";else if (value instanceof _index.ProxyValue) name = "proxy";else name = "object";
return `${name}#${value.getHash()}`;
}
printObjectValue(value) {
const args = [];
if (value.temporalAlias !== undefined) args.push(`temporalAlias ${this.describeValue(value.temporalAlias)}`);
if (value instanceof _index.FunctionValue) {
if (value instanceof _index.NativeFunctionValue) {// TODO: This shouldn't happen; all native function values should be intrinsics
} else if (value instanceof _index.BoundFunctionValue) {
args.push(`$BoundTargetFunction ${this.describeValue(value.$BoundTargetFunction)}`);
args.push(`$BoundThis ${this.describeValue(value.$BoundThis)}`);
args.push(`$BoundArguments [${this.describeValues(value.$BoundArguments)}]`);
} else {
(0, _invariant.default)(value instanceof _index.ECMAScriptSourceFunctionValue);
args.push(`$ConstructorKind ${value.$ConstructorKind}`);
args.push(`$ThisMode ${value.$ThisMode}`);
args.push(`$FunctionKind ${value.$FunctionKind}`);
if (value.$HomeObject !== undefined) args.push(`$HomeObject ${this.describeValue(value.$HomeObject)}`); // TODO: $Strict should always be defined according to its flow type signature, however, there are some tests where it's not
if (value.$Strict) args.push(`$Strict`);
args.push(`$FormalParameters ${value.$FormalParameters.length}`); // TODO: pretty-print $ECMAScriptCode
// TODO: $Environment should always be defined according to its flow type signature, however, it's not in test ConcreteModel2.js
if (value.$Environment) args.push(`$Environment ${this.describeLexicalEnvironment(value.$Environment)}`);
}
} else if (value instanceof _index.ProxyValue) {
args.push(`$ProxyTarget ${this.describeValue(value.$ProxyTarget)}`);
args.push(`$ProxyHandler ${this.describeValue(value.$ProxyHandler)}`);
} else {
const kind = value.getKind();
if (kind !== "Object") args.push(`kind ${kind}`);
switch (kind) {
case "RegExp":
const originalSource = value.$OriginalSource;
(0, _invariant.default)(originalSource !== undefined);
args.push(`$OriginalSource ${originalSource}`);
const originalFlags = value.$OriginalFlags;
(0, _invariant.default)(originalFlags !== undefined);
args.push(`$OriginalFlags ${originalFlags}`);
break;
case "Number":
const numberData = value.$NumberData;
(0, _invariant.default)(numberData !== undefined);
args.push(`$NumberData ${this.describeValue(numberData)}`);
break;
case "String":
const stringData = value.$StringData;
(0, _invariant.default)(stringData !== undefined);
args.push(`$StringData ${this.describeValue(stringData)}`);
break;
case "Boolean":
const booleanData = value.$BooleanData;
(0, _invariant.default)(booleanData !== undefined);
args.push(`$BooleanData ${this.describeValue(booleanData)}`);
break;
case "Date":
const dateValue = value.$DateValue;
(0, _invariant.default)(dateValue !== undefined);
args.push(`$DateValue ${this.describeValue(dateValue)}`);
break;
case "ArrayBuffer":
const len = value.$ArrayBufferByteLength;
(0, _invariant.default)(len !== undefined);
args.push(`$ArrayBufferByteLength ${len}`);
const db = value.$ArrayBufferData;
(0, _invariant.default)(db !== undefined);
if (db !== null) args.push(`$ArrayBufferData [${db.join(", ")}]`);
break;
case "Float32Array":
case "Float64Array":
case "Int8Array":
case "Int16Array":
case "Int32Array":
case "Uint8Array":
case "Uint16Array":
case "Uint32Array":
case "Uint8ClampedArray":
case "DataView":
const buf = value.$ViewedArrayBuffer;
(0, _invariant.default)(buf !== undefined);
args.push(`$ViewedArrayBuffer ${this.describeValue(buf)}`);
break;
case "Map":
const mapDataEntries = value.$MapData;
(0, _invariant.default)(mapDataEntries !== undefined);
args.push(`$MapData [${this.describeMapEntries(mapDataEntries)}]`);
break;
case "WeakMap":
const weakMapDataEntries = value.$WeakMapData;
(0, _invariant.default)(weakMapDataEntries !== undefined);
args.push(`$WeakMapData [${this.describeMapEntries(weakMapDataEntries)}]`);
break;
case "Set":
const setDataEntries = value.$SetData;
(0, _invariant.default)(setDataEntries !== undefined);
args.push(`$SetData [${this.describeSetEntries(setDataEntries)}]`);
break;
case "WeakSet":
const weakSetDataEntries = value.$WeakSetData;
(0, _invariant.default)(weakSetDataEntries !== undefined);
args.push(`$WeakSetData [${this.describeSetEntries(weakSetDataEntries)}]`);
break;
case "ReactElement":
case "Object":
case "Array":
break;
default:
(0, _invariant.default)(false);
}
} // properties
if (value.properties.size > 0) {
args.push(`properties [${Array.from(value.properties.keys()).map(key => this.describeKey(key)).join(", ")}]`);
} // symbols
if (value.symbols.size > 0) {
args.push(`symbols [${Array.from(value.symbols.keys()).map(key => this.describeKey(key)).join(", ")}]`);
}
const unknownProperty = value.unknownProperty;
if (unknownProperty !== undefined) args.push(`unknown property`);
if (value.$Prototype !== undefined) args.push(`$Prototype ${this.describeValue(value.$Prototype)}`);
this._printDefinition(this.objectValueName(value), value.constructor.name, args); // jull pull on property bindings to get them emitting
for (const propertyBinding of value.properties.values()) this.describePropertyBinding(propertyBinding);
for (const propertyBinding of value.symbols.values()) this.describePropertyBinding(propertyBinding);
if (unknownProperty !== undefined) this.describePropertyBinding(unknownProperty);
}
describeValue(value) {
if (value.intrinsicName !== undefined) return this.describeExpression(value.intrinsicName);
if (value instanceof _index.SymbolValue) return this.describeSymbol(value);
if (value instanceof _index.PrimitiveValue) return value.toDisplayString();
if (value instanceof _index.ObjectValue) {
if (!this._objects.has(value)) {
this._objects.add(value);
this.printObjectValue(value);
}
return this.objectValueName(value);
} else {
(0, _invariant.default)(value instanceof _index.AbstractValue, value.constructor.name);
if (!this._abstractValueIds.has(value)) {
this._abstractValueIds.set(value, this._abstractValueIds.size);
this.printAbstractValue(value);
}
return this.abstractValueName(value);
}
}
describeMapEntries(entries) {
return entries.map(entry => {
const args = [];
if (entry.$Key !== undefined) args.push(`$Key ${this.describeValue(entry.$Key)}`);
if (entry.$Value !== undefined) args.push(`$Value ${this.describeValue(entry.$Value)}`);
return `{${args.join(", ")}}`;
}).join(", ");
}
describeSetEntries(entries) {
return entries.map(entry => entry === undefined ? "(undefined)" : this.describeValue(entry)).join(", ");
}
describeDescriptor(desc) {
if (desc instanceof _descriptors.PropertyDescriptor) return this.describePropertyDescriptor(desc);else if (desc instanceof _descriptors.InternalSlotDescriptor) return this.describeInternalSlotDescriptor(desc);else {
(0, _invariant.default)(desc instanceof _descriptors.AbstractJoinedDescriptor, desc.constructor.name);
return this.describeAbstractJoinedDescriptor(desc);
}
}
describePropertyDescriptor(desc) {
const args = [];
if (desc.writable) args.push("writable");
if (desc.enumerable) args.push("enumerable");
if (desc.configurable) args.push("configurable");
if (desc.value !== undefined) args.push(`value ${this.describeValue(desc.value)}`);
if (desc.get !== undefined) args.push(`get ${this.describeValue(desc.get)}`);
if (desc.set !== undefined) args.push(`set ${this.describeValue(desc.set)}`);
return `PropertyDescriptor(${args.join(", ")})`;
}
describeInternalSlotDescriptor(desc) {
const args = [];
if (desc.value instanceof _index.Value) args.push(`value ${this.describeValue(desc.value)}`);else if (Array.isArray(desc.value)) args.push(`some array`); // TODO
return `InternalSlotDescriptor(${args.join(", ")})`;
}
describeAbstractJoinedDescriptor(desc) {
const args = [];
args.push(`join condition ${this.describeValue(desc.joinCondition)}`);
if (desc.descriptor1 !== undefined) args.push(`descriptor1 ${this.describeDescriptor(desc.descriptor1)}`);
if (desc.descriptor2 !== undefined) args.push(`descriptor2 ${this.describeDescriptor(desc.descriptor2)}`);
return `AbstractJoinedDescriptor(${args.join(", ")})`;
}
bindingName(binding) {
(0, _invariant.default)(this._bindings.has(binding));
return `${this.describeEnvironmentRecord(binding.environment)}.${this.describeExpression(binding.name)}`;
}
printBinding(binding) {
const args = [];
if (binding.isGlobal) args.push("is global");
if (binding.mightHaveBeenCaptured) args.push("might have been captured");
if (binding.initialized) args.push("initialized");
if (binding.mutable) args.push("mutable");
if (binding.deletable) args.push("deletable");
if (binding.strict) args.push("strict");
if (binding.hasLeaked) args.push("has leaked");
if (binding.value !== undefined) args.push(`value ${this.describeValue(binding.value)})`);
if (binding.phiNode !== undefined) args.push(`phi node ${this.describeValue(binding.phiNode)}`);
this._printDefinition(this.bindingName(binding), "Binding", args);
}
describeBinding(binding) {
if (!this._bindings.has(binding)) {
this._bindings.add(binding);
this.printBinding(binding);
}
return this.bindingName(binding);
}
describeKey(key) {
if (key === undefined) return "(undefined)";else if (typeof key === "string") return this.describeExpression(key);else {
(0, _invariant.default)(key instanceof _index.Value);
return this.describeValue(key);
}
}
propertyBindingName(propertyBinding) {
return `${this.describeValue(propertyBinding.object)}.${this.describeKey(propertyBinding.key)}`;
}
printPropertyBinding(propertyBinding) {
const args = [];
if (propertyBinding.internalSlot) args.push("internal slot");
if (propertyBinding.descriptor !== undefined) args.push(`descriptor ${this.describeDescriptor(propertyBinding.descriptor)}`);
if (propertyBinding.pathNode !== undefined) args.push(`path node ${this.describeValue(propertyBinding.pathNode)}`);
this._printDefinition(this.propertyBindingName(propertyBinding), "PropertyBinding", args);
}
describePropertyBinding(propertyBinding) {
if (!this._propertyBindings.has(propertyBinding)) {
this._propertyBindings.add(propertyBinding);
this.printPropertyBinding(propertyBinding);
}
return this.propertyBindingName(propertyBinding);
}
environmentRecordName(environment) {
(0, _invariant.default)(this._environmentRecords.has(environment));
let name;
if (environment instanceof _environment.DeclarativeEnvironmentRecord) {
name = environment instanceof _environment.FunctionEnvironmentRecord ? "funEnv" : "declEnv";
} else if (environment instanceof _environment.ObjectEnvironmentRecord) {
name = "objEnv";
} else {
(0, _invariant.default)(environment instanceof _environment.GlobalEnvironmentRecord);
name = "globEnv";
}
return `${name}#${environment.id}`;
}
printEnvironmentRecord(environment) {
const args = [];
if (environment instanceof _environment.DeclarativeEnvironmentRecord) {
if (environment instanceof _environment.FunctionEnvironmentRecord) {
args.push(`$ThisBindingStatus ${environment.$ThisBindingStatus}`); // TODO: $ThisValue should always be defined according to its flow type signature, however, it's not for test ObjectAssign9.js
if (environment.$ThisValue !== undefined) args.push(`$ThisValue ${this.describeValue(environment.$ThisValue)}`);
if (environment.$HomeObject !== undefined) args.push(`$HomeObject ${this.describeValue(environment.$HomeObject)}`);
args.push(`$FunctionObject ${this.describeValue(environment.$FunctionObject)}`);
}
if (environment.$NewTarget !== undefined) args.push(`$NewTarget ${this.describeValue(environment.$NewTarget)}`);
if (environment.frozen) args.push("frozen");
const bindings = Object.keys(environment.bindings);
if (bindings.length > 0) args.push(`bindings [${Object.keys(environment.bindings).map(key => this.describeKey(key)).join(", ")}]`);
} else if (environment instanceof _environment.ObjectEnvironmentRecord) {
args.push(`object ${this.describeValue(environment.object)}`);
if (environment.withEnvironment) args.push("with environment");
} else if (environment instanceof _environment.GlobalEnvironmentRecord) {
args.push(`$DeclarativeRecord ${this.describeEnvironmentRecord(environment.$DeclarativeRecord)}`);
args.push(`$ObjectRecord ${this.describeEnvironmentRecord(environment.$DeclarativeRecord)}`);
if (environment.$VarNames.length > 0) args.push(`$VarNames [${environment.$VarNames.map(varName => this.describeExpression(varName)).join(", ")}]`);
args.push(`$GlobalThisValue ${this.describeValue(environment.$GlobalThisValue)}`);
}
this._printDefinition(this.environmentRecordName(environment), environment.constructor.name, args); // pull on bindings to get them emitted
if (environment instanceof _environment.DeclarativeEnvironmentRecord) for (const bindingName in environment.bindings) this.describeBinding(environment.bindings[bindingName]);
}
describeEnvironmentRecord(environment) {
if (!this._environmentRecords.has(environment)) {
this._environmentRecords.add(environment);
this.printEnvironmentRecord(environment);
}
return this.environmentRecordName(environment);
}
describeBaseValue(value) {
if (value === undefined) return "(undefined)";else if (value instanceof _index.Value) return this.describeValue(value);
(0, _invariant.default)(value instanceof _environment.EnvironmentRecord);
return this.describeEnvironmentRecord(value);
}
lexicalEnvironmentName(environment) {
(0, _invariant.default)(this._lexicalEnvironments.has(environment));
return `lexEnv#${environment._uid}`;
}
printLexicalEnvironment(environment) {
const args = [];
if (environment.destroyed) args.push("destroyed");
if (environment.parent !== null) args.push(`parent ${this.describeLexicalEnvironment(environment.parent)}`);
args.push(`environment record ${this.describeEnvironmentRecord(environment.environmentRecord)}`);
this._printDefinition(this.lexicalEnvironmentName(environment), "LexicalEnvironment", args);
}
describeLexicalEnvironment(environment) {
if (!this._lexicalEnvironments.has(environment)) {
this._lexicalEnvironments.add(environment);
this.printLexicalEnvironment(environment);
}
return this.lexicalEnvironmentName(environment);
}
symbolName(symbol) {
const id = this._symbolIds.get(symbol);
(0, _invariant.default)(id !== undefined);
return `symbol#${id}`;
}
printSymbol(symbol) {
const args = [];
if (symbol.$Description) args.push(`$Description ${this.describeValue(symbol.$Description)}`);
this._printDefinition(this.symbolName(symbol), "Symbol", args);
}
describeSymbol(symbol) {
if (!this._symbolIds.has(symbol)) {
this._symbolIds.set(symbol, this._symbolIds.size);
}
if (!this._symbols.has(symbol)) {
this._symbols.add(symbol);
this.printSymbol(symbol);
}
return this.symbolName(symbol);
}
}
exports.TextPrinter = TextPrinter;
//# sourceMappingURL=TextPrinter.js.map