diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index efee518cc93..c6853edf9de 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -13,6 +13,12 @@ namespace ts { CountMask = 0x0FFFFFFF, // Temp variable counter _i = 0x10000000, // Use/preference flag for '_i' } + + const enum StackBehavior { + Unspecified, // No node stack behavior has been specified or should be necessary + NodeIsOnTopOfStack, // The specified node is on the top of the node stack + ParentIsOnTopOfStack, // The parent of the specified node is on the top of the node stack + } // targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile): EmitResult { @@ -103,6 +109,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi }; function isNodeDescendentOf(node: Node, ancestor: Node): boolean { + // node stack behavior: parent pointers are acceptable here as they refer to the original + // source tree while (node) { if (node === ancestor) return true; node = node.parent; @@ -111,6 +119,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function isUniqueLocalName(name: string, container: Node): boolean { + // node stack behavior: parent pointers are acceptable here as they refer to the original + // source tree for (let node = container; isNodeDescendentOf(node, container); node = node.nextContainer) { if (node.locals && hasProperty(node.locals, name)) { // We conservatively include alias symbols to cover cases where they're emitted as locals @@ -147,7 +157,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi // tree as we descend into the branch. It is used to derive the parent // node of any node without needing parent pointers, to help with // the emit of synthesized nodes that do not maintain parent pointers. - let nodeStack: Node[] = []; + let nodeStackSize: number = 0; + let ancestorStack: Node[] = []; let parentNode: Node; let currentNode: Node; @@ -213,7 +224,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } }); } - + writeLine(); writeEmittedFiles(writer.getText(), /*writeByteOrderMark*/ compilerOptions.emitBOM); return; @@ -221,28 +232,36 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi function emitSourceFile(sourceFile: SourceFile): void { currentSourceFile = sourceFile; exportFunctionForFile = undefined; - nodeStack.length = 0; + nodeStackSize = 0; + ancestorStack.length = 0; parentNode = undefined; currentNode = undefined; emit(sourceFile); } function pushNode(node: Node): void { - nodeStack.push(parentNode); + Debug.assert(node !== undefined, "Incorrect node stack behavior during push. Argument `node` is undefined.") + Debug.assert(currentNode !== node, "Incorrect node stack behavior during push. Argument `node` is already the current node."); + Debug.assert(parentNode !== node, "Incorrect node stack behavior during push. Argument `node` is already the parent node."); + nodeStackSize++; + if (nodeStackSize > 2) { + ancestorStack.push(parentNode); + } parentNode = currentNode; currentNode = node; } function popNode(): void { currentNode = parentNode; - parentNode = nodeStack.pop(); + parentNode = nodeStackSize > 2 ? ancestorStack.pop() : undefined; + nodeStackSize--; } function peekNode(offset: number): Node { switch (offset) { case 0: return currentNode; case 1: return parentNode; - default: return nodeStack[nodeStack.length - 1 - offset]; + default: return nodeStackSize > 2 ? ancestorStack[nodeStackSize - 1 - offset] : undefined; } } @@ -252,8 +271,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi if (parentNode && match(parentNode)) { return parentNode; } - for (let i = nodeStack.length; i >= 0; i--) { - let node = nodeStack[i]; + for (let i = ancestorStack.length; i >= 0; i--) { + let node = ancestorStack[i]; if (match(node)) { return node; } @@ -311,12 +330,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function generateNameForModuleOrEnum(node: ModuleDeclaration | EnumDeclaration) { + verifyStackBehavior(StackBehavior.Unspecified); + let name = node.name.text; // Use module/enum name itself if it is unique, otherwise make a unique variation return isUniqueLocalName(name, node) ? name : makeUniqueName(name); } function generateNameForImportOrExportDeclaration(node: ImportDeclaration | ExportDeclaration) { + verifyStackBehavior(StackBehavior.Unspecified); + let expr = getExternalModuleName(node); let baseName = expr.kind === SyntaxKind.StringLiteral ? escapeIdentifier(makeIdentifierFromModuleName((expr).text)) : "module"; @@ -324,14 +347,20 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function generateNameForExportDefault() { + verifyStackBehavior(StackBehavior.Unspecified); + return makeUniqueName("default"); } function generateNameForClassExpression() { + verifyStackBehavior(StackBehavior.Unspecified); + return makeUniqueName("class"); } function generateNameForNode(node: Node) { + verifyStackBehavior(StackBehavior.Unspecified); + switch (node.kind) { case SyntaxKind.Identifier: return makeUniqueName((node).text); @@ -351,6 +380,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function getGeneratedNameForNode(node: Node) { + verifyStackBehavior(StackBehavior.Unspecified); + let id = getNodeId(node); return nodeToGeneratedName[id] || (nodeToGeneratedName[id] = unescapeIdentifier(generateNameForNode(node))); } @@ -717,6 +748,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitNodeWithSourceMap(node: Node) { + // node stack behavior: parent of `node` is top of stack. + Debug.assert(currentNode !== node, "Incorrect node stack behavior."); + if (node) { if (nodeIsSynthesized(node)) { return emitNodeWithoutSourceMap(node); @@ -769,6 +803,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitTempDeclarations(newLine: boolean) { + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack); + if (tempVariables) { if (newLine) { writeLine(); @@ -783,6 +819,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitTokenText(tokenKind: SyntaxKind, startPos: number, emitFn?: () => void) { + verifyStackBehavior(StackBehavior.Unspecified); + let tokenString = tokenToString(tokenKind); if (emitFn) { emitFn(); @@ -794,6 +832,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitOptional(prefix: string, node: Node) { + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack, node); + if (node) { write(prefix); emit(node); @@ -801,6 +841,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitParenthesizedIf(node: Node, parenthesized: boolean) { + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack, node); + if (parenthesized) { write("("); } @@ -817,6 +859,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitLinePreservingList(parent: Node, nodes: NodeArray, allowTrailingComma: boolean, spacesBetweenBraces: boolean) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, parent); Debug.assert(nodes.length > 0); increaseIndent(); @@ -861,6 +904,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitList(nodes: TNode[], start: number, count: number, multiLine: boolean, trailingComma: boolean, leadingComma?: boolean, noTrailingNewLine?: boolean, emitNode?: (node: TNode) => void): number { + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack); + if (!emitNode) { emitNode = emit; } @@ -891,16 +936,22 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitCommaList(nodes: Node[]) { + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack); + if (nodes) { emitList(nodes, 0, nodes.length, /*multiline*/ false, /*trailingComma*/ false); } } function emitLines(nodes: Node[]) { + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack); + emitLinesStartingAt(nodes, /*startIndex*/ 0); } function emitLinesStartingAt(nodes: Node[], startIndex: number): void { + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack); + for (let i = startIndex; i < nodes.length; i++) { writeLine(); emit(nodes[i]); @@ -908,6 +959,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function isBinaryOrOctalIntegerLiteral(node: LiteralExpression, text: string): boolean { + verifyStackBehavior(StackBehavior.Unspecified); + if (node.kind === SyntaxKind.NumericLiteral && text.length > 1) { switch (text.charCodeAt(1)) { case CharacterCodes.b: @@ -922,7 +975,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitLiteral(node: LiteralExpression) { - // node stack behavior: `node` is not guaranteed to be on top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + let text = getLiteralText(node); if ((compilerOptions.sourceMap || compilerOptions.inlineSourceMap) && (node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind))) { @@ -938,6 +992,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function getLiteralText(node: LiteralExpression) { + verifyStackBehavior(StackBehavior.Unspecified); + // Any template literal or string literal with an extended escape // (e.g. "\u{0067}") will need to be downleveled as a escaped string literal. if (languageVersion < ScriptTarget.ES6 && (isTemplateLiteralKind(node.kind) || node.hasExtendedUnicodeEscape)) { @@ -975,7 +1031,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitDownlevelRawTemplateLiteral(node: LiteralExpression) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack, node); // Find original source text, since we need to emit the raw strings of the tagged template. // The raw strings contain the (escaped) strings of what the user wrote. @@ -999,27 +1055,27 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitDownlevelTaggedTemplateArray(node: TaggedTemplateExpression, literalEmitter: (literal: LiteralExpression) => void) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + write("["); - if (node.template.kind === SyntaxKind.NoSubstitutionTemplateLiteral) { - literalEmitter(node.template); + let template = node.template; + if (template.kind === SyntaxKind.NoSubstitutionTemplateLiteral) { + literalEmitter(template); } else { - pushNode(node.template); - literalEmitter((node.template).head); - forEach((node.template).templateSpans, (child) => { + let head = (template).head; + literalEmitter(head); + forEach((template).templateSpans, (child) => { write(", "); - pushNode(child); literalEmitter(child.literal); - popNode(); }); - popNode(); } write("]"); } function emitDownlevelTaggedTemplate(node: TaggedTemplateExpression) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + let tempVariable = createAndRecordTempVariable(TempFlags.Auto); write("("); emit(tempVariable); @@ -1053,7 +1109,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitTemplateExpression(node: TemplateExpression): void { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); // In ES6 mode and above, we can simply emit each portion of a template in order, but in // ES3 & ES5 we must convert the template expression into a series of string concatenations. @@ -1062,14 +1118,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi return; } - let emitOuterParens = isExpression(parentNode) && templateNeedsParens(node); + let emitOuterParens = isExpression(parentNode, peekNode, 1) && templateNeedsParens(node); if (emitOuterParens) { write("("); } let headEmitted = false; if (shouldEmitTemplateHead()) { + pushNode(node.head); emitLiteral(node.head); + popNode(); + headEmitted = true; } @@ -1103,7 +1162,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi // Emitting a '+ ""' has no semantic effect for middles and tails. if (templateSpan.literal.text.length !== 0) { write(" + "); + pushNode(templateSpan.literal); emitLiteral(templateSpan.literal); + popNode(); } popNode(); } @@ -1135,7 +1196,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function templateNeedsParens(template: TemplateExpression) { - // node stack behavior: `template` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, template); + switch (parentNode.kind) { case SyntaxKind.CallExpression: case SyntaxKind.NewExpression: @@ -1185,18 +1247,20 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitTemplateSpan(span: TemplateSpan) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, span); + emit(span.expression); emit(span.literal); } function jsxEmitReact(node: JsxElement|JsxSelfClosingElement) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); /// Emit a tag name, which is either '"div"' for lower-cased names, or /// 'Div' for upper-cased or dotted names function emitTagName(name: Identifier|QualifiedName) { - // node stack behavior: parent of `name` is top of stack + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack, name); + if (name.kind === SyntaxKind.Identifier && isIntrinsicJsxName((name).text)) { write('"'); emit(name); @@ -1211,7 +1275,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi /// these emit into an object literal property name, we don't need to be worried /// about keywords, just non-identifier characters function emitAttributeName(name: Identifier) { - // node stack behavior: parent of `name` is top of stack + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack, name); if (/[A-Za-z_]+[\w*]/.test(name.text)) { write('"'); @@ -1225,7 +1289,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi /// Emit an name/value pair for an attribute (e.g. "x: 3") function emitJsxAttribute(node: JsxAttribute) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); emitAttributeName(node.name); write(": "); @@ -1238,7 +1302,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitJsxElement(openingNode: JsxOpeningLikeElement, children?: JsxChild[]) { - // node stack behavior: `openingNode` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, openingNode); // Call React.createElement(tag, ... emitLeadingComments(openingNode); @@ -1320,23 +1384,21 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi continue; } - pushNode(children[i]); - // Don't emit empty strings if (children[i].kind === SyntaxKind.JsxText) { + pushNode(children[i]); let text = getTextToEmit(children[i]); if(text !== undefined) { write(', "'); write(text); write('"'); } + popNode(); } else { write(", "); emit(children[i]); } - - popNode(); } } @@ -1357,24 +1419,27 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function jsxEmitPreserve(node: JsxElement|JsxSelfClosingElement) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); function emitJsxAttribute(node: JsxAttribute) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + emit(node.name); write("="); emit(node.initializer); } function emitJsxSpreadAttribute(node: JsxSpreadAttribute) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + write("{..."); emit(node.expression); write("}"); } function emitAttributes(attribs: NodeArray) { - // node stack behavior: parent of `attribs` is top of stack + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack); + for (let i = 0, n = attribs.length; i < n; i++) { if (i > 0) { write(" "); @@ -1393,7 +1458,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitJsxOpeningOrSelfClosingElement(node: JsxOpeningElement|JsxSelfClosingElement) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + write("<"); emit(node.tagName); if (node.attributes.length > 0 || (node.kind === SyntaxKind.JsxSelfClosingElement)) { @@ -1411,14 +1477,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitJsxClosingElement(node: JsxClosingElement) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + write(""); } function emitJsxElement(node: JsxElement) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + pushNode(node.openingElement); emitJsxOpeningOrSelfClosingElement(node.openingElement); popNode(); @@ -1445,15 +1513,19 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi // In a sense, it does not actually emit identifiers as much as it declares a name for a specific property. // For example, this is utilized when feeding in a result to Object.defineProperty. function emitExpressionForPropertyName(node: Declaration) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + let name = node.name; Debug.assert(name.kind !== SyntaxKind.BindingElement); if (name.kind === SyntaxKind.StringLiteral) { + pushNode(name); emitLiteral(name); + popNode(); } else if (name.kind === SyntaxKind.ComputedPropertyName) { pushNode(name); - emitExpressionForComputedPropertyName(node, name); + emitExpressionForComputedPropertyName(name); popNode(); } else { @@ -1470,7 +1542,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } } - function emitExpressionForComputedPropertyName(parent: Node, name: ComputedPropertyName) { + function emitExpressionForComputedPropertyName(name: ComputedPropertyName) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, name); + // if this is a decorated computed property, we will need to capture the result // of the property expression so that we can apply decorators later. This is to ensure // we don't introduce unintended side effects: @@ -1483,7 +1557,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi // // Object.defineProperty(C.prototype, _a, __decorate([dec], C.prototype, _a, Object.getOwnPropertyDescriptor(C.prototype, _a))); // - if (parent && nodeIsDecorated(parent)) { + if (parentNode && nodeIsDecorated(parentNode)) { if (!computedPropertyNamesToGeneratedNames) { computedPropertyNamesToGeneratedNames = []; } @@ -1505,7 +1579,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function isExpressionIdentifier(node: Node): boolean { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + switch (parentNode.kind) { case SyntaxKind.ArrayLiteralExpression: case SyntaxKind.BinaryExpression: @@ -1611,7 +1686,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function isNameOfNestedRedeclaration(node: Identifier) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (languageVersion < ScriptTarget.ES6) { switch (parentNode.kind) { case SyntaxKind.BindingElement: @@ -1625,7 +1701,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitIdentifier(node: Identifier) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (nodeIsSynthesized(node) || !node.parent) { write(node.text); } @@ -1641,7 +1718,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitThis(node: Node) { - // node stack behavior: `node` is not guaranteed to be on top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.LexicalThis) { write("_this"); } @@ -1651,7 +1729,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitSuper(node: Node) { - // node stack behavior: `node` is not guaranteed to be on top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (languageVersion >= ScriptTarget.ES6) { write("super"); } @@ -1667,7 +1746,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitObjectBindingPattern(node: BindingPattern) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + write("{ "); let elements = node.elements; emitList(elements, 0, elements.length, /*multiLine*/ false, /*trailingComma*/ elements.hasTrailingComma); @@ -1675,7 +1755,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitArrayBindingPattern(node: BindingPattern) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + write("["); let elements = node.elements; emitList(elements, 0, elements.length, /*multiLine*/ false, /*trailingComma*/ elements.hasTrailingComma); @@ -1683,7 +1764,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitBindingElement(node: BindingElement) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (node.propertyName) { emit(node.propertyName); write(": "); @@ -1701,13 +1783,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitSpreadElementExpression(node: SpreadElementExpression) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + write("..."); emit((node).expression); } function emitYieldExpression(node: YieldExpression) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + write(tokenToString(SyntaxKind.YieldKeyword)); if (node.asteriskToken) { write("*"); @@ -1719,7 +1803,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitAwaitExpression(node: AwaitExpression) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + let needsParenthesis = needsParenthesisForAwaitExpressionAsYield(node); if (needsParenthesis) { write("("); @@ -1733,7 +1818,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function needsParenthesisForAwaitExpressionAsYield(node: AwaitExpression) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (parentNode.kind === SyntaxKind.BinaryExpression && !isAssignmentOperator((parentNode).operatorToken.kind)) { return true; } @@ -1745,6 +1831,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function needsParenthesisForPropertyAccessOrInvocation(node: Expression) { + verifyStackBehavior(StackBehavior.Unspecified, node); + switch (node.kind) { case SyntaxKind.Identifier: case SyntaxKind.ArrayLiteralExpression: @@ -1760,6 +1848,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitListWithSpread(elements: Expression[], needsUniqueCopy: boolean, multiLine: boolean, trailingComma: boolean, useConcat: boolean) { + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack); + let pos = 0; let group = 0; let length = elements.length; @@ -1806,11 +1896,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function isSpreadElementExpression(node: Node) { + verifyStackBehavior(StackBehavior.Unspecified, node); + return node.kind === SyntaxKind.SpreadElementExpression; } function emitArrayLiteral(node: ArrayLiteralExpression) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + let elements = node.elements; if (elements.length === 0) { write("[]"); @@ -1827,7 +1920,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitObjectLiteralBody(node: ObjectLiteralExpression, numElements: number): void { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (numElements === 0) { write("{}"); return; @@ -1868,7 +1962,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitDownlevelObjectLiteralWithComputedProperties(node: ObjectLiteralExpression, firstComputedPropertyIndex: number) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + let multiLine = (node.flags & NodeFlags.MultiLine) !== 0; let properties = node.properties; @@ -1925,7 +2020,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi popNode(); } if (accessors.setAccessor) { - pushNode(accessors.getAccessor); + pushNode(accessors.setAccessor); writeLine(); emitLeadingComments(accessors.setAccessor); write("set: "); @@ -1998,7 +2093,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitObjectLiteral(node: ObjectLiteralExpression): void { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + let properties = node.properties; if (languageVersion < ScriptTarget.ES6) { @@ -2027,6 +2123,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function createBinaryExpression(left: Expression, operator: SyntaxKind, right: Expression, startsOnNewLine?: boolean): BinaryExpression { + verifyStackBehavior(StackBehavior.Unspecified); + let result = createSynthesizedNode(SyntaxKind.BinaryExpression, startsOnNewLine); result.operatorToken = createSynthesizedNode(operator); result.left = left; @@ -2036,6 +2134,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function createPropertyAccessExpression(expression: Expression, name: Identifier): PropertyAccessExpression { + verifyStackBehavior(StackBehavior.Unspecified); + let result = createSynthesizedNode(SyntaxKind.PropertyAccessExpression); result.expression = parenthesizeForAccess(expression); result.dotToken = createSynthesizedNode(SyntaxKind.DotToken); @@ -2045,6 +2145,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function createElementAccessExpression(expression: Expression, argumentExpression: Expression): ElementAccessExpression { + verifyStackBehavior(StackBehavior.Unspecified); + let result = createSynthesizedNode(SyntaxKind.ElementAccessExpression); result.expression = parenthesizeForAccess(expression); result.argumentExpression = argumentExpression; @@ -2053,6 +2155,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function parenthesizeForAccess(expr: Expression): LeftHandSideExpression { + verifyStackBehavior(StackBehavior.Unspecified); + // When diagnosing whether the expression needs parentheses, the decision should be based // on the innermost expression in a chain of nested type assertions. while (expr.kind === SyntaxKind.TypeAssertionExpression || expr.kind === SyntaxKind.AsExpression) { @@ -2079,14 +2183,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitComputedPropertyName(node: ComputedPropertyName) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + write("["); - emitExpressionForComputedPropertyName(parentNode, node); + emitExpressionForComputedPropertyName(node); write("]"); } function emitMethod(node: MethodDeclaration) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (languageVersion >= ScriptTarget.ES6 && node.asteriskToken) { write("*"); } @@ -2099,7 +2205,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitPropertyAssignment(node: PropertyDeclaration) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + emit(node.name); write(": "); emit(node.initializer); @@ -2107,13 +2214,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi // Return true if identifier resolves to an exported member of a namespace function isNamespaceExportReference(node: Identifier) { - // node stack behavior: parent of `node` is top of stack + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack, node); + let container = resolver.getReferencedExportContainer(node); return container && container.kind !== SyntaxKind.SourceFile; } function emitShorthandPropertyAssignment(node: ShorthandPropertyAssignment) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); // The name property of a short-hand property assignment is considered an expression position, so here // we manually emit the identifier to avoid rewriting. @@ -2135,7 +2243,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function tryEmitConstantValue(node: PropertyAccessExpression | ElementAccessExpression): boolean { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); if (compilerOptions.isolatedModules) { // do not inline enum values in separate compilation mode @@ -2158,6 +2266,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi // If the code is not indented, an optional valueToWriteWhenNotIndenting will be // emitted instead. function indentIfOnDifferentLines(parent: Node, node1: Node, node2: Node, valueToWriteWhenNotIndenting?: string): boolean { + verifyStackBehavior(StackBehavior.Unspecified); + let realNodesAreOnDifferentLines = !nodeIsSynthesized(parent) && !nodeEndIsOnSameLineAsNodeStart(node1, node2); // Always use a newline for synthesized code if the synthesizer desires it. @@ -2177,7 +2287,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitPropertyAccess(node: PropertyAccessExpression) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (tryEmitConstantValue(node)) { return; } @@ -2205,13 +2316,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitQualifiedName(node: QualifiedName) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + emit(node.left); write("."); emit(node.right); } function emitQualifiedNameAsExpression(node: QualifiedName, useFallback: boolean) { + verifyStackBehavior(StackBehavior.Unspecified, node); + if (node.left.kind === SyntaxKind.Identifier) { emitEntityNameAsExpression(node.left, useFallback); } @@ -2232,7 +2346,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi emitNodeWithoutSourceMap(node.right); } - function emitEntityNameAsExpression(node: EntityName, useFallback: boolean) { + function emitEntityNameAsExpression(node: EntityName, useFallback: boolean) { + verifyStackBehavior(StackBehavior.Unspecified, node); + switch (node.kind) { case SyntaxKind.Identifier: if (useFallback) { @@ -2251,7 +2367,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitIndexedAccess(node: ElementAccessExpression) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (tryEmitConstantValue(node)) { return; } @@ -2262,10 +2379,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function hasSpreadElement(elements: Expression[]) { + verifyStackBehavior(StackBehavior.Unspecified); + return forEach(elements, e => e.kind === SyntaxKind.SpreadElementExpression); } function skipParentheses(node: Expression): Expression { + verifyStackBehavior(StackBehavior.Unspecified, node); + while (node.kind === SyntaxKind.ParenthesizedExpression || node.kind === SyntaxKind.TypeAssertionExpression || node.kind === SyntaxKind.AsExpression) { node = (node).expression; } @@ -2273,7 +2394,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitCallTarget(node: Expression): Expression { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack, node); + if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.ThisKeyword || node.kind === SyntaxKind.SuperKeyword) { emit(node); return node; @@ -2289,16 +2411,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitCallWithSpread(node: CallExpression) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); let target: Expression; let expr = skipParentheses(node.expression); if (expr.kind === SyntaxKind.PropertyAccessExpression) { // Target will be emitted as "this" argument pushNode(expr); - pushNode((expr).expression); target = emitCallTarget((expr).expression); - popNode(); write("."); emit((expr).name); popNode(); @@ -2306,9 +2426,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi else if (expr.kind === SyntaxKind.ElementAccessExpression) { // Target will be emitted as "this" argument pushNode(expr); - pushNode((expr).expression); target = emitCallTarget((expr).expression); - popNode(); write("["); emit((expr).argumentExpression); write("]"); @@ -2325,7 +2443,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi if (target) { if (target.kind === SyntaxKind.SuperKeyword) { // Calls of form super(...) and super.foo(...) + pushNode(target); emitThis(target); + popNode(); } else { // Calls of form obj.foo(...) @@ -2342,23 +2462,29 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitCallExpression(node: CallExpression) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (languageVersion < ScriptTarget.ES6 && hasSpreadElement(node.arguments)) { emitCallWithSpread(node); return; } let superCall = false; - if (node.expression.kind === SyntaxKind.SuperKeyword) { - emitSuper(node.expression); + let expression = node.expression; + if (expression.kind === SyntaxKind.SuperKeyword) { + pushNode(expression); + emitSuper(expression); + popNode(); superCall = true; } else { - emit(node.expression); + emit(expression); superCall = node.expression.kind === SyntaxKind.PropertyAccessExpression && (node.expression).expression.kind === SyntaxKind.SuperKeyword; } if (superCall && languageVersion < ScriptTarget.ES6) { write(".call("); - emitThis(node.expression); + pushNode(expression); + emitThis(expression); + popNode(); if (node.arguments.length) { write(", "); emitCommaList(node.arguments); @@ -2373,7 +2499,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitNewExpression(node: NewExpression) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + write("new "); // Spread operator logic is supported in new expressions in ES5 using a combination @@ -2396,9 +2523,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi hasSpreadElement(node.arguments)) { write("("); - pushNode(node.expression); let target = emitCallTarget(node.expression); - popNode(); write(".bind.apply("); emit(target); write(", [void 0].concat("); @@ -2417,7 +2542,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitTaggedTemplateExpression(node: TaggedTemplateExpression): void { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (languageVersion >= ScriptTarget.ES6) { emit(node.tag); write(" "); @@ -2429,7 +2555,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitParenExpression(node: ParenthesizedExpression) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + + let parent = parentNode; // If the node is synthesized, it means the emitter put the parentheses there, // not the user. If we didn't want them, the emitter would not have put them @@ -2458,8 +2586,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi operand.kind !== SyntaxKind.DeleteExpression && operand.kind !== SyntaxKind.PostfixUnaryExpression && operand.kind !== SyntaxKind.NewExpression && - !(operand.kind === SyntaxKind.CallExpression && parentNode.kind === SyntaxKind.NewExpression) && - !(operand.kind === SyntaxKind.FunctionExpression && parentNode.kind === SyntaxKind.CallExpression)) { + !(operand.kind === SyntaxKind.CallExpression && parent.kind === SyntaxKind.NewExpression) && + !(operand.kind === SyntaxKind.FunctionExpression && parent.kind === SyntaxKind.CallExpression)) { emit(operand); return; } @@ -2472,45 +2600,54 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitDeleteExpression(node: DeleteExpression) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + write(tokenToString(SyntaxKind.DeleteKeyword)); write(" "); emit(node.expression); } function emitVoidExpression(node: VoidExpression) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + write(tokenToString(SyntaxKind.VoidKeyword)); write(" "); emit(node.expression); } function emitTypeOfExpression(node: TypeOfExpression) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + write(tokenToString(SyntaxKind.TypeOfKeyword)); write(" "); emit(node.expression); } - function isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node: Node, parent: Node): boolean { + function isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node: Node): boolean { + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack, node); + if (!isCurrentFileSystemExternalModule() || node.kind !== SyntaxKind.Identifier || nodeIsSynthesized(node)) { return false; } - + + debugger; + + const parentNode = currentNode; const isVariableDeclarationOrBindingElement = - parent && (parent.kind === SyntaxKind.VariableDeclaration || parent.kind === SyntaxKind.BindingElement); + parentNode && (parentNode.kind === SyntaxKind.VariableDeclaration || parentNode.kind === SyntaxKind.BindingElement); const targetDeclaration = isVariableDeclarationOrBindingElement - ? parent + ? parentNode : resolver.getReferencedValueDeclaration(node); - + return isSourceFileLevelDeclarationInSystemJsModule(targetDeclaration, /*isExported*/ true); } function emitPrefixUnaryExpression(node: PrefixUnaryExpression) { - // node stack behavior: `node` is top of stack - const exportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.operand, node); + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + + const exportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.operand); if (exportChanged) { // emit @@ -2552,8 +2689,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitPostfixUnaryExpression(node: PostfixUnaryExpression) { - // node stack behavior: `node` is top of stack - const exportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.operand, node); + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + + const exportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.operand); if (exportChanged) { // export function returns the value that was passes as the second argument // however for postfix unary expressions result value should be the value before modification. @@ -2579,6 +2717,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function shouldHoistDeclarationInSystemJsModule(node: Node): boolean { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + return isSourceFileLevelDeclarationInSystemJsModule(node, /*isExported*/ false); } @@ -2593,26 +2733,40 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi * we we emit variable statement 'var' should be dropped. */ function isSourceFileLevelDeclarationInSystemJsModule(node: Node, isExported: boolean): boolean { + verifyStackBehavior(StackBehavior.Unspecified); + if (!node || languageVersion >= ScriptTarget.ES6 || !isCurrentFileSystemExternalModule()) { return false; } - + + // If `node` is not on top of the stack, then we get the combined node flags by + // walking parent references. This should be safe as we should have received this + // node from the checker, so we will be looking at the original source file. + // If `node` is not on top of the stack, then we can get the combined node flags + // by walking the node stack (preferred). + let followParentReferences = node !== currentNode; + let getCombinedNodeFlagsWorker = followParentReferences + ? ts.getCombinedNodeFlags + : getCombinedNodeFlags; + + let offset = 0; let current: Node = node; while (current) { if (current.kind === SyntaxKind.SourceFile) { - return !isExported || ((getCombinedNodeFlags(node) & NodeFlags.Export) !== 0); + return !isExported || ((getCombinedNodeFlagsWorker(node) & NodeFlags.Export) !== 0); } else if (isFunctionLike(current) || current.kind === SyntaxKind.ModuleBlock) { return false; } else { - current = current.parent; + current = followParentReferences ? current.parent : peekNode(++offset); } } } function emitBinaryExpression(node: BinaryExpression) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (languageVersion < ScriptTarget.ES6 && node.operatorToken.kind === SyntaxKind.EqualsToken && (node.left.kind === SyntaxKind.ObjectLiteralExpression || node.left.kind === SyntaxKind.ArrayLiteralExpression)) { emitDestructuring(node, parentNode.kind === SyntaxKind.ExpressionStatement); @@ -2621,7 +2775,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi const exportChanged = node.operatorToken.kind >= SyntaxKind.FirstAssignment && node.operatorToken.kind <= SyntaxKind.LastAssignment && - isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.left, node); + isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.left); if (exportChanged) { // emit assignment 'x y' as 'exports("x", x y)' @@ -2646,7 +2800,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitConditionalExpression(node: ConditionalExpression) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + emit(node.condition); let indentedBeforeQuestion = indentIfOnDifferentLines(node, node.condition, node.questionToken, " "); write("?"); @@ -2674,6 +2829,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function isSingleLineEmptyBlock(node: Node) { + verifyStackBehavior(StackBehavior.Unspecified, node); + if (node && node.kind === SyntaxKind.Block) { let block = node; return block.statements.length === 0 && nodeEndIsOnSameLineAsNodeStart(block, block); @@ -2681,7 +2838,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitBlock(node: Block) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (isSingleLineEmptyBlock(node)) { emitToken(SyntaxKind.OpenBraceToken, node.pos); write(" "); @@ -2689,13 +2847,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi return; } - let parent = parentNode; emitToken(SyntaxKind.OpenBraceToken, node.pos); increaseIndent(); - scopeEmitStart(parent); + scopeEmitStart(parentNode); if (node.kind === SyntaxKind.ModuleBlock) { - Debug.assert(parent.kind === SyntaxKind.ModuleDeclaration); - emitCaptureThisForNodeIfNecessary(parent); + Debug.assert(parentNode.kind === SyntaxKind.ModuleDeclaration); + emitCaptureThisForNodeIfNecessary(parentNode); } emitLines(node.statements); if (node.kind === SyntaxKind.ModuleBlock) { @@ -2708,6 +2865,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitEmbeddedStatement(node: Node) { + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack, node); + if (node.kind === SyntaxKind.Block) { write(" "); emit(node); @@ -2721,13 +2880,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitExpressionStatement(node: ExpressionStatement) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + emitParenthesizedIf(node.expression, /*parenthesized*/ node.expression.kind === SyntaxKind.ArrowFunction); write(";"); } function emitIfStatement(node: IfStatement) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + let endPos = emitToken(SyntaxKind.IfKeyword, node.pos); write(" "); endPos = emitToken(SyntaxKind.OpenParenToken, endPos); @@ -2748,7 +2909,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitDoStatement(node: DoStatement) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + write("do"); emitEmbeddedStatement(node.statement); if (node.statement.kind === SyntaxKind.Block) { @@ -2763,7 +2925,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitWhileStatement(node: WhileStatement) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + write("while ("); emit(node.expression); write(")"); @@ -2776,6 +2939,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi * in system modules where such variable declarations are hoisted. */ function tryEmitStartOfVariableDeclarationList(decl: VariableDeclarationList, startPos?: number): boolean { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, decl); + if (shouldHoistVariable(decl, /*checkIfSourceFileLevelDecl*/ true)) { // variables in variable declaration list were already hoisted return false; @@ -2813,6 +2978,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitVariableDeclarationListSkippingUninitializedEntries(list: VariableDeclarationList): boolean { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, list); + let started = false; for (let decl of list.declarations) { if (!decl.initializer) { @@ -2833,12 +3000,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitForStatement(node: ForStatement) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + let endPos = emitToken(SyntaxKind.ForKeyword, node.pos); write(" "); endPos = emitToken(SyntaxKind.OpenParenToken, endPos); if (node.initializer && node.initializer.kind === SyntaxKind.VariableDeclarationList) { let variableDeclarationList = node.initializer; + pushNode(variableDeclarationList); let startIsEmitted = tryEmitStartOfVariableDeclarationList(variableDeclarationList, endPos); if (startIsEmitted) { emitCommaList(variableDeclarationList.declarations); @@ -2846,6 +3015,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi else { emitVariableDeclarationListSkippingUninitializedEntries(variableDeclarationList); } + popNode(); } else if (node.initializer) { emit(node.initializer); @@ -2859,7 +3029,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitForInOrForOfStatement(node: ForInStatement | ForOfStatement) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (languageVersion < ScriptTarget.ES6 && node.kind === SyntaxKind.ForOfStatement) { return emitDownLevelForOfStatement(node); } @@ -2870,8 +3041,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi if (node.initializer.kind === SyntaxKind.VariableDeclarationList) { let variableDeclarationList = node.initializer; if (variableDeclarationList.declarations.length >= 1) { + pushNode(variableDeclarationList); tryEmitStartOfVariableDeclarationList(variableDeclarationList, endPos); emit(variableDeclarationList.declarations[0]); + popNode(); } } else { @@ -2890,7 +3063,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitDownLevelForOfStatement(node: ForOfStatement) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); // The following ES6 code: // @@ -3041,21 +3214,24 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitBreakOrContinueStatement(node: BreakOrContinueStatement) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + emitToken(node.kind === SyntaxKind.BreakStatement ? SyntaxKind.BreakKeyword : SyntaxKind.ContinueKeyword, node.pos); emitOptional(" ", node.label); write(";"); } function emitReturnStatement(node: ReturnStatement) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + emitToken(SyntaxKind.ReturnKeyword, node.pos); emitOptional(" ", node.expression); write(";"); } function emitWithStatement(node: WithStatement) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + write("with ("); emit(node.expression); write(")"); @@ -3063,17 +3239,22 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitSwitchStatement(node: SwitchStatement) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + let endPos = emitToken(SyntaxKind.SwitchKeyword, node.pos); write(" "); emitToken(SyntaxKind.OpenParenToken, endPos); emit(node.expression); endPos = emitToken(SyntaxKind.CloseParenToken, node.expression.end); write(" "); + pushNode(node.caseBlock); emitCaseBlock(node.caseBlock, endPos); + popNode(); } function emitCaseBlock(node: CaseBlock, startPos: number): void { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + emitToken(SyntaxKind.OpenBraceToken, startPos); increaseIndent(); emitLines(node.clauses); @@ -3098,7 +3279,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitCaseOrDefaultClause(node: CaseOrDefaultClause) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (node.kind === SyntaxKind.CaseClause) { write("case "); emit((node).expression); @@ -3120,14 +3302,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitThrowStatement(node: ThrowStatement) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + write("throw "); emit(node.expression); write(";"); } function emitTryStatement(node: TryStatement) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + write("try "); emit(node.tryBlock); emit(node.catchClause); @@ -3139,7 +3323,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitCatchClause(node: CatchClause) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + writeLine(); let endPos = emitToken(SyntaxKind.CatchKeyword, node.pos); write(" "); @@ -3151,13 +3336,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitDebuggerStatement(node: Node) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + emitToken(SyntaxKind.DebuggerKeyword, node.pos); write(";"); } function emitLabelledStatement(node: LabeledStatement) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + emit(node.label); write(": "); emit(node.statement); @@ -3169,8 +3356,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitModuleMemberName(node: Declaration) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + emitStart(node.name); - if (getCombinedNodeFlags(node) & NodeFlags.Export) { + if (getCombinedNodeFlags() & NodeFlags.Export) { let container = findAncestorNode(isModuleDeclaration); if (container) { write(getGeneratedNameForNode(container)); @@ -3193,7 +3382,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitExportMemberAssignment(node: FunctionLikeDeclaration | ClassDeclaration) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (node.flags & NodeFlags.Export) { writeLine(); emitStart(node); @@ -3233,13 +3423,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitExportMemberAssignments(name: Identifier) { + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack, name); + if (!exportEquals && exportSpecifiers && hasProperty(exportSpecifiers, name.text)) { for (let specifier of exportSpecifiers[name.text]) { writeLine(); if (compilerOptions.module === ModuleKind.System) { emitStart(specifier.name); write(`${exportFunctionForFile}("`); + pushNode(specifier); emitNodeWithoutSourceMap(specifier.name); + popNode(); write(`", `); emitExpressionIdentifier(name); write(")"); @@ -3249,7 +3443,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi emitStart(specifier.name); emitContainingModuleName(); write("."); + pushNode(specifier); emitNodeWithoutSourceMap(specifier.name); + popNode(); emitEnd(specifier.name); write(" = "); emitExpressionIdentifier(name); @@ -3260,7 +3456,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitDestructuring(root: BinaryExpression | VariableDeclaration | ParameterDeclaration, isAssignmentExpressionStatement: boolean, value?: Expression) { - // node stack behavior: `root` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, root); + let emitCount = 0; // An exported declaration is actually emitted as an assignment (to a property on the module object), so @@ -3269,7 +3466,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi // because actual variable declarations are hoisted let canDefineTempVariablesInPlace = false; if (root.kind === SyntaxKind.VariableDeclaration) { - let isExported = getCombinedNodeFlags(root) & NodeFlags.Export; + let isExported = getCombinedNodeFlags() & NodeFlags.Export; let isSourceLevelForSystemModuleKind = shouldHoistDeclarationInSystemJsModule(root); canDefineTempVariablesInPlace = !isExported && !isSourceLevelForSystemModuleKind; } @@ -3285,15 +3482,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi emitBindingElement(root, value); } - function emitAssignment(name: Identifier, value: Expression, parent: Node) { + function emitAssignment(name: Identifier, value: Expression, isTempVariable?: boolean) { + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack, name); + if (emitCount++) { write(", "); } const isVariableDeclarationOrBindingElement = - parent && (parent.kind === SyntaxKind.VariableDeclaration || parent.kind === SyntaxKind.BindingElement); + !isTempVariable && (currentNode.kind === SyntaxKind.VariableDeclaration || currentNode.kind === SyntaxKind.BindingElement); - let exportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(name, parent); + let exportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(name); if (exportChanged) { write(`${exportFunctionForFile}("`); @@ -3302,7 +3501,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } if (isVariableDeclarationOrBindingElement) { - emitModuleMemberName(parent); + emitModuleMemberName(currentNode); } else { emit(name); @@ -3310,25 +3509,29 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi write(" = "); emit(value); - + if (exportChanged) { write(")"); } } function ensureIdentifier(expr: Expression): Expression { + verifyStackBehavior(StackBehavior.Unspecified); + if (expr.kind !== SyntaxKind.Identifier) { let identifier = createTempVariable(TempFlags.Auto); if (!canDefineTempVariablesInPlace) { recordTempDeclaration(identifier); } - emitAssignment(identifier, expr, /*parent*/ undefined); + emitAssignment(identifier, expr, /*isTempVariable*/ true); expr = identifier; } return expr; } function createDefaultValueCheck(value: Expression, defaultValue: Expression): Expression { + verifyStackBehavior(StackBehavior.Unspecified); + // The value expression will be evaluated twice, so for anything but a simple identifier // we need to generate a temporary variable value = ensureIdentifier(value); @@ -3341,6 +3544,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function createConditionalExpression(condition: Expression, whenTrue: Expression, whenFalse: Expression) { + verifyStackBehavior(StackBehavior.Unspecified); + let cond = createSynthesizedNode(SyntaxKind.ConditionalExpression); cond.condition = condition; cond.questionToken = createSynthesizedNode(SyntaxKind.QuestionToken); @@ -3351,12 +3556,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function createNumericLiteral(value: number) { + verifyStackBehavior(StackBehavior.Unspecified); + let node = createSynthesizedNode(SyntaxKind.NumericLiteral); node.text = "" + value; return node; } function createPropertyAccessForDestructuringProperty(object: Expression, propName: Identifier | LiteralExpression): Expression { + verifyStackBehavior(StackBehavior.Unspecified); + // We create a synthetic copy of the identifier in order to avoid the rewriting that might // otherwise occur when the identifier is emitted. let syntheticName = createSynthesizedNode(propName.kind); @@ -3368,6 +3577,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function createSliceCall(value: Expression, sliceIndex: number): CallExpression { + verifyStackBehavior(StackBehavior.Unspecified); + let call = createSynthesizedNode(SyntaxKind.CallExpression); let sliceIdentifier = createSynthesizedNode(SyntaxKind.Identifier); sliceIdentifier.text = "slice"; @@ -3378,42 +3589,57 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitObjectLiteralAssignment(target: ObjectLiteralExpression, value: Expression) { + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack, target); + let properties = target.properties; if (properties.length !== 1) { // For anything but a single element destructuring we need to generate a temporary // to ensure value is evaluated exactly once. value = ensureIdentifier(value); } + + pushNode(target); for (let p of properties) { if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) { + pushNode(p); let propName = (p).name; - emitDestructuringAssignment((p).initializer || propName, createPropertyAccessForDestructuringProperty(value, propName), p); + emitDestructuringAssignment((p).initializer || propName, createPropertyAccessForDestructuringProperty(value, propName)); + popNode(); } } + popNode(); } function emitArrayLiteralAssignment(target: ArrayLiteralExpression, value: Expression) { + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack, target); + let elements = target.elements; if (elements.length !== 1) { // For anything but a single element destructuring we need to generate a temporary // to ensure value is evaluated exactly once. value = ensureIdentifier(value); } + + pushNode(target); for (let i = 0; i < elements.length; i++) { let e = elements[i]; if (e.kind !== SyntaxKind.OmittedExpression) { if (e.kind !== SyntaxKind.SpreadElementExpression) { - emitDestructuringAssignment(e, createElementAccessExpression(value, createNumericLiteral(i)), target); + emitDestructuringAssignment(e, createElementAccessExpression(value, createNumericLiteral(i))); } else if (i === elements.length - 1) { - emitDestructuringAssignment((e).expression, createSliceCall(value, i), target); + pushNode(e); + emitDestructuringAssignment((e).expression, createSliceCall(value, i)); + popNode(); } } } + popNode(); } - function emitDestructuringAssignment(target: Expression, value: Expression, parent: Node) { - // node stack behavior: parent of `target` and `value` is top of stack + function emitDestructuringAssignment(target: Expression, value: Expression) { + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack, target); + if (target.kind === SyntaxKind.BinaryExpression && (target).operatorToken.kind === SyntaxKind.EqualsToken) { value = createDefaultValueCheck(value, (target).right); target = (target).left; @@ -3425,24 +3651,24 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi emitArrayLiteralAssignment(target, value); } else { - emitAssignment(target, value, parent); + emitAssignment(target, value); } } - function emitAssignmentExpression(root: BinaryExpression) { - // node stack behavior: `root` is top of stack + function emitAssignmentExpression(node: BinaryExpression) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); - let target = root.left; - let value = root.right; + let target = node.left; + let value = node.right; if (isAssignmentExpressionStatement) { - emitDestructuringAssignment(target, value, root); + emitDestructuringAssignment(target, value); } else { if (parentNode.kind !== SyntaxKind.ParenthesizedExpression) { write("("); } value = ensureIdentifier(value); - emitDestructuringAssignment(target, value, root); + emitDestructuringAssignment(target, value); write(", "); emit(value); if (parentNode.kind !== SyntaxKind.ParenthesizedExpression) { @@ -3452,7 +3678,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitBindingElement(target: BindingElement, value: Expression) { - // node stack behavior: `target` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, target); if (target.initializer) { // Combine value and initializer @@ -3465,13 +3691,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi if (isBindingPattern(target.name)) { let pattern = target.name; - pushNode(pattern); let elements = pattern.elements; if (elements.length !== 1) { // For anything but a single element destructuring we need to generate a temporary // to ensure value is evaluated exactly once. value = ensureIdentifier(value); } + pushNode(pattern); for (let i = 0; i < elements.length; i++) { let element = elements[i]; pushNode(element); @@ -3494,13 +3720,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi popNode(); } else { - emitAssignment(target.name, value, target); + emitAssignment(target.name, value); } } } function emitVariableDeclaration(node: VariableDeclaration) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (isBindingPattern(node.name)) { if (languageVersion < ScriptTarget.ES6) { emitDestructuring(node, /*isAssignmentExpressionStatement*/ false); @@ -3525,14 +3752,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi (getCombinedFlagsForIdentifier(node.name) & NodeFlags.Let); // NOTE: default initialization should not be added to let bindings in for-in\for-of statements - if (isUninitializedLet && - node.parent.parent.kind !== SyntaxKind.ForInStatement && - node.parent.parent.kind !== SyntaxKind.ForOfStatement) { - initializer = createVoidZero(); + if (isUninitializedLet) { + let grandparent = peekNode(2); + if (grandparent.kind !== SyntaxKind.ForInStatement && + grandparent.kind !== SyntaxKind.ForOfStatement) { + initializer = createVoidZero(); + } } } - let exportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.name, node); + let exportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.name); if (exportChanged) { write(`${exportFunctionForFile}("`); @@ -3550,6 +3779,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitExportVariableAssignments(node: VariableDeclaration | BindingElement) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (node.kind === SyntaxKind.OmittedExpression) { return; } @@ -3558,79 +3789,86 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi emitExportMemberAssignments(name); } else if (isBindingPattern(name)) { - forEach((name).elements, emitExportVariableAssignments); + forEach((name).elements, emitExportVariableAssignmentsOfChild); } } + + function emitExportVariableAssignmentsOfChild(node: VariableDeclaration | BindingElement) { + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack, node); + pushNode(node); + emitExportVariableAssignments(node); + popNode(); + } - function getCombinedNodeFlagsFromNodeStack(): NodeFlags { - let offset = 0; - let node = peekNode(offset); - while (node && (node.kind === SyntaxKind.BindingElement || isBindingPattern(node))) { - node = peekNode(offset++); - } + function getCombinedNodeFlags(): NodeFlags { + return ts.getCombinedNodeFlags(currentNode, peekNode, 0); + } + + function getCombinedFlagsForIdentifier(name: Identifier): NodeFlags { + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack, name); - let flags = node.flags; - if (node && node.kind === SyntaxKind.VariableDeclaration) { - node = peekNode(offset++); - } - - if (node && node.kind === SyntaxKind.VariableDeclarationList) { - flags |= node.flags; - node = peekNode(offset++); - } - - if (node && node.kind === SyntaxKind.VariableStatement) { - flags |= node.flags; - } - - return flags; - } - - function getCombinedFlagsForIdentifier(node: Identifier): NodeFlags { - if (!node.parent || (node.parent.kind !== SyntaxKind.VariableDeclaration && node.parent.kind !== SyntaxKind.BindingElement)) { + let parent = currentNode; + if (!parent || (parent.kind !== SyntaxKind.VariableDeclaration && parent.kind !== SyntaxKind.BindingElement)) { return 0; } - return getCombinedNodeFlags(node.parent); + return getCombinedNodeFlags(); } function isES6ExportedDeclaration(node: Node) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + return !!(node.flags & NodeFlags.Export) && languageVersion >= ScriptTarget.ES6 && parentNode.kind === SyntaxKind.SourceFile; } function emitVariableStatement(node: VariableStatement) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + + let declarationList = node.declarationList; let startIsEmitted = false; - + if (node.flags & NodeFlags.Export) { if (isES6ExportedDeclaration(node)) { // Exported ES6 module member write("export "); - startIsEmitted = tryEmitStartOfVariableDeclarationList(node.declarationList); + pushNode(declarationList); + startIsEmitted = tryEmitStartOfVariableDeclarationList(declarationList); + popNode(); } } else { - startIsEmitted = tryEmitStartOfVariableDeclarationList(node.declarationList); + pushNode(declarationList); + startIsEmitted = tryEmitStartOfVariableDeclarationList(declarationList); + popNode(); } if (startIsEmitted) { - emitCommaList(node.declarationList.declarations); + pushNode(declarationList); + emitCommaList(declarationList.declarations); + popNode(); write(";"); } else { - let atLeastOneItem = emitVariableDeclarationListSkippingUninitializedEntries(node.declarationList); + pushNode(declarationList); + let atLeastOneItem = emitVariableDeclarationListSkippingUninitializedEntries(declarationList); + popNode(); if (atLeastOneItem) { write(";"); } } + if (languageVersion < ScriptTarget.ES6 && parentNode === currentSourceFile) { - forEach(node.declarationList.declarations, emitExportVariableAssignments); + pushNode(declarationList); + forEach(declarationList.declarations, emitExportVariableAssignmentsOfChild); + popNode(); } } function shouldEmitLeadingAndTrailingCommentsForVariableStatement(node: VariableStatement) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + // If we're not exporting the variables, there's nothing special here. // Always emit comments for these nodes. if (!(node.flags & NodeFlags.Export)) { @@ -3653,7 +3891,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitParameter(node: ParameterDeclaration) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (languageVersion < ScriptTarget.ES6) { if (isBindingPattern(node.name)) { let name = createTempVariable(TempFlags.Auto); @@ -3677,6 +3916,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitDefaultValueAssignments(node: FunctionLikeDeclaration) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (languageVersion < ScriptTarget.ES6) { let tempIndex = 0; forEach(node.parameters, parameter => { @@ -3731,6 +3972,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitRestParameter(node: FunctionLikeDeclaration) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (languageVersion < ScriptTarget.ES6 && hasRestParameter(node)) { let restIndex = node.parameters.length - 1; let restParam = node.parameters[restIndex]; @@ -3739,7 +3982,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi if (isBindingPattern(restParam.name)) { return; } - + + pushNode(restParam); let tempName = createTempVariable(TempFlags._i).text; writeLine(); emitLeadingComments(restParam); @@ -3772,21 +4016,27 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi decreaseIndent(); writeLine(); write("}"); + popNode(); } } function emitAccessor(node: AccessorDeclaration) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + write(node.kind === SyntaxKind.GetAccessor ? "get " : "set "); emit(node.name); emitSignatureAndBody(node); } function shouldEmitAsArrowFunction(node: FunctionLikeDeclaration): boolean { + verifyStackBehavior(StackBehavior.Unspecified, node); + return node.kind === SyntaxKind.ArrowFunction && languageVersion >= ScriptTarget.ES6; } function emitDeclarationName(node: Declaration) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (node.name) { emitNodeWithoutSourceMap(node.name); } @@ -3796,6 +4046,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function shouldEmitFunctionName(node: FunctionLikeDeclaration) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (node.kind === SyntaxKind.FunctionExpression) { // Emit name if one is present return !!node.name; @@ -3807,9 +4059,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitFunctionDeclaration(node: FunctionLikeDeclaration) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (nodeIsMissing(node.body)) { - return emitOnlyPinnedOrTripleSlashComments(node); + emitOnlyPinnedOrTripleSlashComments(node); + return; } if (node.kind !== SyntaxKind.MethodDeclaration && node.kind !== SyntaxKind.MethodSignature) { @@ -3848,6 +4102,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitCaptureThisForNodeIfNecessary(node: Node): void { + verifyStackBehavior(StackBehavior.Unspecified); + if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.CaptureThis) { writeLine(); emitStart(node); @@ -3857,7 +4113,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitSignatureParameters(node: FunctionLikeDeclaration) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + increaseIndent(); write("("); if (node) { @@ -3870,7 +4127,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitSignatureParametersForArrow(node: FunctionLikeDeclaration) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); // Check whether the parameter list needs parentheses and preserve no-parenthesis if (node.parameters.length === 1 && node.pos === node.parameters[0].pos) { @@ -3882,7 +4139,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitAsyncFunctionBodyForES6(node: FunctionLikeDeclaration) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + let promiseConstructor = getEntityNameFromTypeNode(node.type); let isArrowFunction = node.kind === SyntaxKind.ArrowFunction; let hasLexicalArguments = (resolver.getNodeCheckFlags(node) & NodeCheckFlags.CaptureArguments) !== 0; @@ -4007,7 +4265,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitFunctionBody(node: FunctionLikeDeclaration) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (!node.body) { // There can be no body when there are parse errors. Just emit an empty block // in that case. @@ -4024,7 +4283,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitSignatureAndBody(node: FunctionLikeDeclaration) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + let saveTempFlags = tempFlags; let saveTempVariables = tempVariables; let saveTempParameters = tempParameters; @@ -4060,14 +4320,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi // Returns true if any preamble code was emitted. function emitFunctionBodyPreamble(node: FunctionLikeDeclaration): void { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + emitCaptureThisForNodeIfNecessary(node); emitDefaultValueAssignments(node); emitRestParameter(node); } function emitExpressionFunctionBody(node: FunctionLikeDeclaration, body: Expression) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (languageVersion < ScriptTarget.ES6 || node.flags & NodeFlags.Async) { emitDownLevelExpressionFunctionBody(node, body); return; @@ -4089,7 +4351,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitDownLevelExpressionFunctionBody(node: FunctionLikeDeclaration, body: Expression) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + write(" {"); scopeEmitStart(node); @@ -4115,11 +4378,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi else { increaseIndent(); writeLine(); + pushNode(node.body); emitLeadingComments(node.body); + popNode(); write("return "); emit(body); write(";"); + pushNode(node.body); emitTrailingComments(node.body); + popNode(); emitTempDeclarations(/*newLine*/ true); decreaseIndent(); @@ -4134,7 +4401,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitBlockFunctionBody(node: FunctionLikeDeclaration, body: Block) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + write(" {"); scopeEmitStart(node); @@ -4176,7 +4444,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function findInitialSuperCall(ctor: ConstructorDeclaration): ExpressionStatement { - // node stack behavior: `ctor` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, ctor); + if (ctor.body) { let statement = (ctor.body).statements[0]; if (statement && statement.kind === SyntaxKind.ExpressionStatement) { @@ -4192,6 +4461,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitParameterPropertyAssignments(node: ConstructorDeclaration) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + forEach(node.parameters, param => { if (param.flags & NodeFlags.AccessibilityModifier) { writeLine(); @@ -4209,6 +4480,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitMemberAccessForPropertyName(member: Declaration) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, member); + let memberName = member.name; // TODO: (jfreeman,drosen): comment on why this is emitNodeWithoutSourceMap instead of emit here. if (memberName.kind === SyntaxKind.StringLiteral || memberName.kind === SyntaxKind.NumericLiteral) { @@ -4219,7 +4492,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi else if (memberName.kind === SyntaxKind.ComputedPropertyName) { write("["); pushNode(memberName); - emitExpressionForComputedPropertyName(member, memberName); + emitExpressionForComputedPropertyName(memberName); popNode(); write("]"); } @@ -4230,7 +4503,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function getInitializedProperties(node: ClassLikeDeclaration, isStatic: boolean) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + let properties: PropertyDeclaration[] = []; for (let member of node.members) { if (member.kind === SyntaxKind.PropertyDeclaration && isStatic === ((member.flags & NodeFlags.Static) !== 0) && (member).initializer) { @@ -4242,16 +4516,20 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitPropertyDeclarations(node: ClassLikeDeclaration, properties: PropertyDeclaration[]) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + for (let property of properties) { emitPropertyDeclaration(node, property); } } function emitPropertyDeclaration(node: ClassLikeDeclaration, property: PropertyDeclaration, receiver?: Identifier, isExpression?: boolean) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + writeLine(); + pushNode(property); emitLeadingComments(property); + popNode(); emitStart(property); emitStart(property.name); if (receiver) { @@ -4280,6 +4558,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitMemberFunctionsForES5AndLower(node: ClassLikeDeclaration) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + forEach(node.members, member => { if (member.kind === SyntaxKind.SemicolonClassElement) { writeLine(); @@ -4287,15 +4567,20 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } else if (member.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature) { if (!(member).body) { - return emitOnlyPinnedOrTripleSlashComments(member); + pushNode(member); + emitOnlyPinnedOrTripleSlashComments(member); + popNode(); + return; } - pushNode(member); writeLine(); + pushNode(member); emitLeadingComments(member); + popNode(); emitStart(member); emitStart((member).name); emitClassMemberPrefix(node, member); + pushNode(member); emitMemberAccessForPropertyName(member); emitEnd((member).name); write(" = "); @@ -4310,18 +4595,18 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi else if (member.kind === SyntaxKind.GetAccessor || member.kind === SyntaxKind.SetAccessor) { let accessors = getAllAccessorDeclarations(node.members, member); if (member === accessors.firstAccessor) { - pushNode(member); writeLine(); emitStart(member); write("Object.defineProperty("); emitStart((member).name); emitClassMemberPrefix(node, member); write(", "); + pushNode(member); emitExpressionForPropertyName(member); + popNode(); emitEnd((member).name); write(", {"); increaseIndent(); - popNode(); if (accessors.getAccessor) { pushNode(accessors.getAccessor); writeLine(); @@ -4348,7 +4633,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi write(","); popNode(); } - pushNode(member); writeLine(); write("enumerable: true,"); writeLine(); @@ -4357,14 +4641,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi writeLine(); write("});"); emitEnd(member); - popNode(); } } }); } function emitMemberFunctionsForES6AndHigher(node: ClassLikeDeclaration) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + for (let member of node.members) { pushNode(member); if ((member.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature) && !(member).body) { @@ -4403,7 +4687,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitConstructor(node: ClassLikeDeclaration, baseTypeElement: ExpressionWithTypeArguments) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); let saveTempFlags = tempFlags; let saveTempVariables = tempVariables; @@ -4420,7 +4704,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitConstructorWorker(node: ClassLikeDeclaration, baseTypeElement: ExpressionWithTypeArguments) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); // Check if we have property assignment inside class declaration. // If there is property assignment, we need to emit constructor whether users define it or not @@ -4429,6 +4713,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi // Emit the constructor overload pinned comments forEach(node.members, member => { + pushNode(member); if (member.kind === SyntaxKind.Constructor && !(member).body) { emitOnlyPinnedOrTripleSlashComments(member); } @@ -4436,6 +4721,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi if (member.kind === SyntaxKind.PropertyDeclaration && (member).initializer && (member.flags & NodeFlags.Static) === 0) { hasInstancePropertyWithInitializer = true; } + popNode(); }); let ctor = getFirstConstructorWithBody(node); @@ -4447,16 +4733,23 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } if (ctor) { + pushNode(ctor); emitLeadingComments(ctor); + popNode(); } emitStart(ctor || node); if (languageVersion < ScriptTarget.ES6) { write("function "); emitDeclarationName(node); - pushNode(ctor); - emitSignatureParameters(ctor); - popNode(); + if (ctor) { + pushNode(ctor); + emitSignatureParameters(ctor); + popNode(); + } + else { + write("()"); + } } else { write("constructor"); @@ -4541,22 +4834,27 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi scopeEmitEnd(); emitEnd(ctor || node); if (ctor) { + pushNode(ctor); emitTrailingComments(ctor); + popNode(); } } function emitClassExpression(node: ClassExpression) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + return emitClassLikeDeclaration(node); } function emitClassDeclaration(node: ClassDeclaration) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + return emitClassLikeDeclaration(node); } function emitClassLikeDeclaration(node: ClassLikeDeclaration) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (languageVersion < ScriptTarget.ES6) { emitClassLikeDeclarationBelowES6(node); } @@ -4566,7 +4864,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitClassLikeDeclarationForES6AndHigher(node: ClassLikeDeclaration) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + let thisNodeIsDecorated = nodeIsDecorated(node); if (node.kind === SyntaxKind.ClassDeclaration) { if (thisNodeIsDecorated) { @@ -4746,7 +5045,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitClassLikeDeclarationBelowES6(node: ClassLikeDeclaration) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (node.kind === SyntaxKind.ClassDeclaration) { // source file level classes in system modules are hoisted so 'var's for them are already defined if (!shouldHoistDeclarationInSystemJsModule(node)) { @@ -4824,6 +5124,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitClassMemberPrefix(node: ClassLikeDeclaration, member: Node) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + emitDeclarationName(node); if (!(member.flags & NodeFlags.Static)) { write(".prototype"); @@ -4831,12 +5133,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitDecoratorsOfClass(node: ClassLikeDeclaration) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + emitDecoratorsOfMembers(node, /*staticFlag*/ 0); emitDecoratorsOfMembers(node, NodeFlags.Static); emitDecoratorsOfConstructor(node); } function emitDecoratorsOfConstructor(node: ClassLikeDeclaration) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + let decorators = node.decorators; let constructor = getFirstConstructorWithBody(node); let hasDecoratedParameters = constructor && forEach(constructor.parameters, nodeIsDecorated); @@ -4866,12 +5172,23 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi let decoratorCount = decorators ? decorators.length : 0; let argumentsWritten = emitList(decorators, 0, decoratorCount, /*multiLine*/ true, /*trailingComma*/ false, /*leadingComma*/ false, /*noTrailingNewLine*/ true, decorator => { + pushNode(decorator); emitStart(decorator); emit(decorator.expression); emitEnd(decorator); + popNode(); }); + if (constructor) { + pushNode(constructor); + } + argumentsWritten += emitDecoratorsOfParameters(constructor, /*leadingComma*/ argumentsWritten > 0); + + if (constructor) { + popNode(); + } + emitSerializedTypeMetadata(node, /*leadingComma*/ argumentsWritten >= 0); decreaseIndent(); @@ -4884,6 +5201,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitDecoratorsOfMembers(node: ClassLikeDeclaration, staticFlag: NodeFlags) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + for (let member of node.members) { // only emit members in the correct group if ((member.flags & NodeFlags.Static) !== staticFlag) { @@ -4891,7 +5210,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } // skip members that cannot be decorated (such as the constructor) - if (!nodeCanBeDecorated(member)) { + if (member.kind !== SyntaxKind.PropertyDeclaration + && ((member.kind !== SyntaxKind.GetAccessor + && member.kind !== SyntaxKind.SetAccessor + && member.kind !== SyntaxKind.MethodDeclaration) + || !(member).body)) { continue; } @@ -4899,7 +5222,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi if (!nodeOrChildIsDecorated(member)) { continue; } - + // skip an accessor declaration if it is not the first accessor let decorators: NodeArray; let functionLikeMember: FunctionLikeDeclaration; @@ -4967,7 +5290,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi emitStart(member.name); emitClassMemberPrefix(node, member); write(", "); + pushNode(member); emitExpressionForPropertyName(member); + popNode(); emitEnd(member.name); write(","); increaseIndent(); @@ -4978,15 +5303,27 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi increaseIndent(); writeLine(); + pushNode(member); let decoratorCount = decorators ? decorators.length : 0; let argumentsWritten = emitList(decorators, 0, decoratorCount, /*multiLine*/ true, /*trailingComma*/ false, /*leadingComma*/ false, /*noTrailingNewLine*/ true, decorator => { + pushNode(decorator); emitStart(decorator); emit(decorator.expression); emitEnd(decorator); + popNode(); }); - - argumentsWritten += emitDecoratorsOfParameters(functionLikeMember, argumentsWritten > 0); + popNode(); + + + if (functionLikeMember) { + pushNode(functionLikeMember); + argumentsWritten += emitDecoratorsOfParameters(functionLikeMember, argumentsWritten > 0); + popNode(); + } + + pushNode(member); emitSerializedTypeMetadata(member, argumentsWritten > 0); + popNode(); decreaseIndent(); writeLine(); @@ -4994,7 +5331,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi emitStart(member.name); emitClassMemberPrefix(node, member); write(", "); + pushNode(member); emitExpressionForPropertyName(member); + popNode(); emitEnd(member.name); if (member.kind !== SyntaxKind.PropertyDeclaration) { @@ -5002,7 +5341,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi emitStart(member.name); emitClassMemberPrefix(node, member); write(", "); + pushNode(member); emitExpressionForPropertyName(member); + popNode(); emitEnd(member.name); write("))"); decreaseIndent(); @@ -5015,6 +5356,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitDecoratorsOfParameters(node: FunctionLikeDeclaration, leadingComma: boolean): number { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + let argumentsWritten = 0; if (node) { let parameterIndex = 0; @@ -5022,11 +5365,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi if (nodeIsDecorated(parameter)) { let decorators = parameter.decorators; argumentsWritten += emitList(decorators, 0, decorators.length, /*multiLine*/ true, /*trailingComma*/ false, /*leadingComma*/ leadingComma, /*noTrailingNewLine*/ true, decorator => { + pushNode(decorator); emitStart(decorator); write(`__param(${parameterIndex}, `); emit(decorator.expression); write(")"); emitEnd(decorator); + popNode(); }); leadingComma = true; } @@ -5037,6 +5382,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function shouldEmitTypeMetadata(node: Declaration): boolean { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + // This method determines whether to emit the "design:type" metadata based on the node's kind. // The caller should have already tested whether the node has decorators and whether the emitDecoratorMetadata // compiler option is set. @@ -5052,6 +5399,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function shouldEmitReturnTypeMetadata(node: Declaration): boolean { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + // This method determines whether to emit the "design:returntype" metadata based on the node's kind. // The caller should have already tested whether the node has decorators and whether the emitDecoratorMetadata // compiler option is set. @@ -5063,6 +5412,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function shouldEmitParamTypesMetadata(node: Declaration): boolean { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + // This method determines whether to emit the "design:paramtypes" metadata based on the node's kind. // The caller should have already tested whether the node has decorators and whether the emitDecoratorMetadata // compiler option is set. @@ -5077,6 +5428,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi /** Serializes the type of a declaration to an appropriate JS constructor value. Used by the __metadata decorator for a class member. */ function emitSerializedTypeOfNode(node: Node) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + // serialization of the type of a declaration uses the following rules: // // * The serialized type of a ClassDeclaration is "Function" @@ -5092,19 +5445,19 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi write("Function"); return; - case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertyDeclaration: emitSerializedTypeNode((node).type); return; - case SyntaxKind.Parameter: + case SyntaxKind.Parameter: emitSerializedTypeNode((node).type); return; - case SyntaxKind.GetAccessor: + case SyntaxKind.GetAccessor: emitSerializedTypeNode((node).type); return; - case SyntaxKind.SetAccessor: + case SyntaxKind.SetAccessor: emitSerializedTypeNode(getSetAccessorTypeAnnotationNode(node)); return; @@ -5119,13 +5472,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitSerializedTypeNode(node: TypeNode) { + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack, node); + switch (node.kind) { case SyntaxKind.VoidKeyword: write("void 0"); return; case SyntaxKind.ParenthesizedType: + pushNode(node); emitSerializedTypeNode((node).type); + popNode(); return; case SyntaxKind.FunctionType: @@ -5157,7 +5514,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi return; case SyntaxKind.TypeReference: + pushNode(node); emitSerializedTypeReferenceNode(node); + popNode(); return; case SyntaxKind.TypeQuery: @@ -5177,6 +5536,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi /** Serializes a TypeReferenceNode to an appropriate JS constructor value. Used by the __metadata decorator. */ function emitSerializedTypeReferenceNode(node: TypeReferenceNode) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + let typeName = node.typeName; let result = resolver.getTypeReferenceSerializationKind(node); switch (result) { @@ -5236,6 +5597,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi /** Serializes the parameter types of a function or the constructor of a class. Used by the __metadata decorator for a method or set accessor. */ function emitSerializedParameterTypesOfNode(node: Node) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + // serialization of parameter types uses the following rules: // // * If the declaration is a class, the parameters of the first constructor with a body are used. @@ -5254,30 +5617,31 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi if (valueDeclaration) { var parameters = valueDeclaration.parameters; var parameterCount = parameters.length; - if (parameterCount > 0) { - for (var i = 0; i < parameterCount; i++) { - if (i > 0) { - write(", "); + for (var i = 0; i < parameterCount; i++) { + if (i > 0) { + write(", "); + } + + let parameter = parameters[i]; + pushNode(parameter); + if (parameter.dotDotDotToken) { + var parameterType = parameter.type; + if (parameterType.kind === SyntaxKind.ArrayType) { + parameterType = (parameterType).elementType; } - - if (parameters[i].dotDotDotToken) { - var parameterType = parameters[i].type; - if (parameterType.kind === SyntaxKind.ArrayType) { - parameterType = (parameterType).elementType; - } - else if (parameterType.kind === SyntaxKind.TypeReference && (parameterType).typeArguments && (parameterType).typeArguments.length === 1) { - parameterType = (parameterType).typeArguments[0]; - } - else { - parameterType = undefined; - } - - emitSerializedTypeNode(parameterType); + else if (parameterType.kind === SyntaxKind.TypeReference && (parameterType).typeArguments && (parameterType).typeArguments.length === 1) { + parameterType = (parameterType).typeArguments[0]; } else { - emitSerializedTypeOfNode(parameters[i]); + parameterType = undefined; } + + emitSerializedTypeNode(parameterType); } + else { + emitSerializedTypeOfNode(parameter); + } + popNode(); } } } @@ -5285,6 +5649,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi /** Serializes the return type of function. Used by the __metadata decorator for a method. */ function emitSerializedReturnTypeOfNode(node: Node): string | string[] { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (node && isFunctionLike(node)) { emitSerializedTypeNode((node).type); return; @@ -5295,6 +5661,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi function emitSerializedTypeMetadata(node: Declaration, writeComma: boolean): number { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + // This method emits the serialized type metadata for a decorator target. // The caller should have already tested whether the node has decorators. let argumentsWritten = 0; @@ -5336,17 +5704,20 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitInterfaceDeclaration(node: InterfaceDeclaration) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + emitOnlyPinnedOrTripleSlashComments(node); } function shouldEmitEnumDeclaration(node: EnumDeclaration) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + let isConstEnum = isConst(node); return !isConstEnum || compilerOptions.preserveConstEnums || compilerOptions.isolatedModules; } function emitEnumDeclaration(node: EnumDeclaration) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); // const enums are completely erased during compilation. if (!shouldEmitEnumDeclaration(node)) { @@ -5412,7 +5783,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitEnumMember(node: EnumMember) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + let enumParent = parentNode; emitStart(node); write(getGeneratedNameForNode(enumParent)); @@ -5429,6 +5801,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function writeEnumMemberDeclarationValue(member: EnumMember) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, member); + let value = resolver.getConstantValue(member); if (value !== undefined) { write(value.toString()); @@ -5443,6 +5817,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function getInnerMostModuleDeclarationFromDottedModule(moduleDeclaration: ModuleDeclaration): ModuleDeclaration { + verifyStackBehavior(StackBehavior.Unspecified); + if (moduleDeclaration.body.kind === SyntaxKind.ModuleDeclaration) { let recursiveInnerModule = getInnerMostModuleDeclarationFromDottedModule(moduleDeclaration.body); return recursiveInnerModule || moduleDeclaration.body; @@ -5450,22 +5826,28 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function shouldEmitModuleDeclaration(node: ModuleDeclaration) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + return isInstantiatedModule(node, compilerOptions.preserveConstEnums || compilerOptions.isolatedModules); } function isModuleMergedWithES6Class(node: ModuleDeclaration) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + return languageVersion === ScriptTarget.ES6 && !!(resolver.getNodeCheckFlags(node) & NodeCheckFlags.LexicalModuleMergesWithClass); } function emitModuleDeclaration(node: ModuleDeclaration) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); // Emit only if this module is non-ambient. let shouldEmit = shouldEmitModuleDeclaration(node); if (!shouldEmit) { - return emitOnlyPinnedOrTripleSlashComments(node); + emitOnlyPinnedOrTripleSlashComments(node); + return; } + let hoistedInDeclarationScope = shouldHoistDeclarationInSystemJsModule(node); let emitVarForModule = !hoistedInDeclarationScope && !isModuleMergedWithES6Class(node); @@ -5536,10 +5918,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitRequire(moduleName: Expression) { + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack, moduleName); + if (moduleName.kind === SyntaxKind.StringLiteral) { write("require("); emitStart(moduleName); + pushNode(moduleName); emitLiteral(moduleName); + popNode(); emitEnd(moduleName); emitToken(SyntaxKind.CloseParenToken, moduleName.end); } @@ -5549,6 +5935,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function getNamespaceDeclarationNode(node: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (node.kind === SyntaxKind.ImportEqualsDeclaration) { return node; } @@ -5559,52 +5947,75 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function isDefaultImport(node: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + return node.kind === SyntaxKind.ImportDeclaration && (node).importClause && !!(node).importClause.name; } function emitExportImportAssignments(node: Node) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (isAliasSymbolDeclaration(node) && resolver.isValueAliasDeclaration(node)) { emitExportMemberAssignments((node).name); } - forEachChild(node, emitExportImportAssignments); + forEachChild(node, emitExportImportAssignmentsOfChild); + } + + function emitExportImportAssignmentsOfChild(node: Node) { + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack, node); + + pushNode(node); + emitExportImportAssignments(node); + popNode(); } function emitImportDeclaration(node: ImportDeclaration) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (languageVersion < ScriptTarget.ES6) { return emitExternalImportDeclaration(node); } // ES6 import - if (node.importClause) { - let shouldEmitDefaultBindings = resolver.isReferencedAliasDeclaration(node.importClause); - let shouldEmitNamedBindings = node.importClause.namedBindings && resolver.isReferencedAliasDeclaration(node.importClause.namedBindings, /* checkChildren */ true); + let importClause = node.importClause; + if (importClause) { + let shouldEmitDefaultBindings = resolver.isReferencedAliasDeclaration(importClause); + let shouldEmitNamedBindings = importClause.namedBindings && resolver.isReferencedAliasDeclaration(importClause.namedBindings, /* checkChildren */ true); if (shouldEmitDefaultBindings || shouldEmitNamedBindings) { write("import "); - emitStart(node.importClause); + + pushNode(importClause); + emitStart(importClause); + if (shouldEmitDefaultBindings) { - emit(node.importClause.name); + emit(importClause.name); if (shouldEmitNamedBindings) { write(", "); } } + if (shouldEmitNamedBindings) { - emitLeadingComments(node.importClause.namedBindings); - emitStart(node.importClause.namedBindings); - if (node.importClause.namedBindings.kind === SyntaxKind.NamespaceImport) { + let namedBindings = importClause.namedBindings; + pushNode(namedBindings); + emitLeadingComments(namedBindings); + emitStart(namedBindings); + if (namedBindings.kind === SyntaxKind.NamespaceImport) { write("* as "); - emit((node.importClause.namedBindings).name); + emit((namedBindings).name); } else { write("{ "); - emitExportOrImportSpecifierList((node.importClause.namedBindings).elements, resolver.isReferencedAliasDeclaration); + emitExportOrImportSpecifierList((namedBindings).elements, resolver.isReferencedAliasDeclaration); write(" }"); } - emitEnd(node.importClause.namedBindings); - emitTrailingComments(node.importClause.namedBindings); + emitEnd(namedBindings); + emitTrailingComments(namedBindings); + popNode(); } - emitEnd(node.importClause); + emitEnd(importClause); + popNode(); + write(" from "); emit(node.moduleSpecifier); write(";"); @@ -5618,10 +6029,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitExternalImportDeclaration(node: ImportDeclaration | ImportEqualsDeclaration) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (contains(externalImports, node)) { let isExportedImport = node.kind === SyntaxKind.ImportEqualsDeclaration && (node.flags & NodeFlags.Export) !== 0; let namespaceDeclaration = getNamespaceDeclarationNode(node); - + let namespaceDeclarationIsTopOfStack = namespaceDeclaration === node; if (compilerOptions.module !== ModuleKind.AMD) { emitLeadingComments(node); emitStart(node); @@ -5629,7 +6042,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi // import x = require("foo") // import * as x from "foo" if (!isExportedImport) write("var "); - emitModuleMemberName(namespaceDeclaration); + if (namespaceDeclarationIsTopOfStack) { + emitModuleMemberName(namespaceDeclaration); + } + else { + pushNode(namespaceDeclaration); + emitModuleMemberName(namespaceDeclaration); + popNode(); + } write(" = "); } else { @@ -5649,7 +6069,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi if (namespaceDeclaration && isDefaultImport(node)) { // import d, * as x from "foo" write(", "); - emitModuleMemberName(namespaceDeclaration); + if (namespaceDeclarationIsTopOfStack) { + emitModuleMemberName(namespaceDeclaration); + } + else { + pushNode(namespaceDeclaration); + emitModuleMemberName(namespaceDeclaration); + popNode(); + } write(" = "); write(getGeneratedNameForNode(node)); } @@ -5660,7 +6087,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } else { if (isExportedImport) { - emitModuleMemberName(namespaceDeclaration); + if (namespaceDeclarationIsTopOfStack) { + emitModuleMemberName(namespaceDeclaration); + } + else { + pushNode(namespaceDeclaration); + emitModuleMemberName(namespaceDeclaration); + popNode(); + } write(" = "); emit(namespaceDeclaration.name); write(";"); @@ -5668,7 +6102,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi else if (namespaceDeclaration && isDefaultImport(node)) { // import d, * as x from "foo" write("var "); - emitModuleMemberName(namespaceDeclaration); + if (namespaceDeclarationIsTopOfStack) { + emitModuleMemberName(namespaceDeclaration); + } + else { + pushNode(namespaceDeclaration); + emitModuleMemberName(namespaceDeclaration); + popNode(); + } write(" = "); write(getGeneratedNameForNode(node)); write(";"); @@ -5679,7 +6120,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitImportEqualsDeclaration(node: ImportEqualsDeclaration) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (isExternalModuleImportEqualsDeclaration(node)) { emitExternalImportDeclaration(node); return; @@ -5709,7 +6151,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitExportDeclaration(node: ExportDeclaration) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + Debug.assert(compilerOptions.module !== ModuleKind.System); if (languageVersion < ScriptTarget.ES6) { @@ -5763,7 +6206,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi if (node.exportClause) { // export { x, y, ... } write("{ "); + pushNode(node.exportClause); emitExportOrImportSpecifierList(node.exportClause.elements, resolver.isValueAliasDeclaration); + popNode(); write(" }"); } else { @@ -5780,6 +6225,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitExportOrImportSpecifierList(specifiers: ImportOrExportSpecifier[], shouldEmit: (node: Node) => boolean) { + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack); + Debug.assert(languageVersion >= ScriptTarget.ES6); let needsComma = false; @@ -5801,7 +6248,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitExportAssignment(node: ExportAssignment) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (!node.isExportEquals && resolver.isValueAliasDeclaration(node)) { if (languageVersion >= ScriptTarget.ES6) { writeLine(); @@ -5839,6 +6287,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function collectExternalModuleInfo(sourceFile: SourceFile) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, sourceFile); + externalImports = []; exportSpecifiers = {}; exportEquals = undefined; @@ -5892,6 +6342,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitExportStarHelper() { + verifyStackBehavior(StackBehavior.Unspecified); + if (hasExportStars) { writeLine(); write("function __export(m) {"); @@ -5905,6 +6357,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function getLocalNameForExternalImport(node: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration): string { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + let namespaceDeclaration = getNamespaceDeclarationNode(node); if (namespaceDeclaration && !isDefaultImport(node)) { return getSourceTextOfNodeFromSourceFile(currentSourceFile, namespaceDeclaration.name); @@ -5918,6 +6372,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function getExternalModuleNameText(importNode: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration): string { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, importNode); + let moduleName = getExternalModuleName(importNode); if (moduleName.kind === SyntaxKind.StringLiteral) { return getLiteralText(moduleName); @@ -5927,6 +6383,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitVariableDeclarationsForImports(): void { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack); + if (externalImports.length === 0) { return; } @@ -5951,7 +6409,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi write(", "); } + pushNode(importNode); write(getLocalNameForExternalImport(importNode)); + popNode(); } if (started) { @@ -5960,6 +6420,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitLocalStorageForExportedNamesIfNecessary(exportedDeclarations: Declaration[]): string { + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack); + // when resolving exports local exported entries/indirect exported entries in the module // should always win over entries with similar names that were added via star exports // to support this we store names of local/indirect exported entries in a set. @@ -6005,7 +6467,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi for (let n in exportSpecifiers) { for (let specifier of exportSpecifiers[n]) { // write name of export specified, i.e. 'export {x}' + pushNode(specifier); writeExportedName(specifier.name); + popNode(); } } } @@ -6014,17 +6478,24 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi if (externalImport.kind !== SyntaxKind.ExportDeclaration) { continue; } - + let exportDecl = externalImport; if (!exportDecl.exportClause) { // export * from ... continue; } + pushNode(externalImport); + pushNode(exportDecl.exportClause); for (let element of exportDecl.exportClause.elements) { // write name of indirectly exported entry, i.e. 'export {x} from ...' + pushNode(element); writeExportedName(element.name || element.propertyName); + popNode(); } + + popNode(); + popNode(); } decreaseIndent(); @@ -6034,6 +6505,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi return emitExportStarFunction(exportedNamesStorageRef); function emitExportStarFunction(localNames: string): string { + verifyStackBehavior(StackBehavior.Unspecified); + const exportStarFunction = makeUniqueName("exportStar"); writeLine(); @@ -6061,6 +6534,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function writeExportedName(node: Identifier | Declaration): void { + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack, node); + // do not record default exports // they are local to module and never overwritten (explicitly skipped) by star export if (node.kind !== SyntaxKind.Identifier && node.flags & NodeFlags.Default) { @@ -6080,7 +6555,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi emitNodeWithoutSourceMap(node); } else { + pushNode(node); emitDeclarationName(node); + popNode(); } write("': true"); @@ -6088,6 +6565,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function processTopLevelVariableAndFunctionDeclarations(node: SourceFile): Declaration[] { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + // per ES6 spec: // 15.2.1.16.4 ModuleDeclarationInstantiation() Concrete Method // - var declarations are initialized to undefined - 14.a.ii @@ -6097,8 +6576,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi // in theory we should hoist only exported functions and its dependencies // in practice to simplify things we'll hoist all source level functions and variable declaration // including variables declarations for module and class declarations - debugger; - let nodeStack: Node[] = []; let seen: Map = {}; let hasWrittenVar = false; let hoistedFunctionDeclarations: FunctionDeclaration[]; @@ -6125,8 +6602,18 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } return exportedDeclarations; + + function visitChild(node: Node): void { + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack, node); + + pushNode(node); + visit(node); + popNode(); + } function visit(node: Node): void { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (node.flags & NodeFlags.Ambient) { return; } @@ -6140,7 +6627,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi return; } - nodeStack.push(node); hoist: if (shouldHoistNode(node)) { let name = node.name; if (name && name.kind === SyntaxKind.Identifier) { @@ -6162,10 +6648,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi else { write(", "); } - + emitDeclarationName(node); - let flags = getCombinedNodeFlagsForNodeStack(nodeStack); + let flags = getCombinedNodeFlags(); if (flags & NodeFlags.Export) { if (!exportedDeclarations) { exportedDeclarations = []; @@ -6174,19 +6660,20 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } } else if (node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement) { - forEachChild((node).name, visit); + forEachChild((node).name, visitChild); } else if (isBindingPattern(node)) { - forEach((node).elements, visit); + forEach((node).elements, visitChild); } else if (!isDeclaration(node)) { - forEachChild(node, visit); + forEachChild(node, visitChild); } - nodeStack.pop(); } } function shouldHoistNode(node: Node): node is Declaration { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + switch (node.kind) { case SyntaxKind.ClassDeclaration: return true; @@ -6207,6 +6694,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function shouldHoistVariable(node: VariableDeclaration | VariableDeclarationList | BindingElement, checkIfSourceFileLevelDecl: boolean): boolean { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (checkIfSourceFileLevelDecl && !shouldHoistDeclarationInSystemJsModule(node)) { return false; } @@ -6215,8 +6704,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi // - it is top level block scoped // if block scoped variables are nested in some another block then // no other functions can use them except ones that are defined at least in the same block - return (getCombinedNodeFlags(node) & NodeFlags.BlockScoped) === 0 || - getEnclosingBlockScopeContainer(node).kind === SyntaxKind.SourceFile; + return (getCombinedNodeFlags() & NodeFlags.BlockScoped) === 0 || + getEnclosingBlockScopeContainer(node, peekNode, /*offset*/ 0).kind === SyntaxKind.SourceFile; } function isCurrentFileSystemExternalModule() { @@ -6224,6 +6713,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitSystemModuleBody(node: SourceFile, startIndex: number): void { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + // shape of the body in system modules: // function (exports) { // @@ -6278,6 +6769,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitSetters(exportStarFunction: string) { + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack); + write("setters:["); for (let i = 0; i < externalImports.length; ++i) { if (i !== 0) { @@ -6286,7 +6779,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi writeLine(); increaseIndent(); + let importNode = externalImports[i]; + pushNode(importNode); + let importVariableName = getLocalNameForExternalImport(importNode) || ""; let parameterName = "_" + importVariableName; write(`function (${parameterName}) {`); @@ -6298,6 +6794,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi // module is imported only for side-effects, setter body will be empty break; } + // fall-through case SyntaxKind.ImportEqualsDeclaration: Debug.assert(importVariableName !== ""); @@ -6319,14 +6816,23 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi // import n2 = require('foo2') // export {n1} // export {n2} + if (importNode.kind === SyntaxKind.ImportDeclaration) { + pushNode((importNode).importClause); + } + emitExportMemberAssignments(defaultName); writeLine(); + + if (importNode.kind === SyntaxKind.ImportDeclaration) { + popNode(); + } } if (importNode.kind === SyntaxKind.ImportDeclaration && (importNode).importClause.namedBindings) { - + pushNode((importNode).importClause); let namedBindings = (importNode).importClause.namedBindings; + pushNode(namedBindings); if (namedBindings.kind === SyntaxKind.NamespaceImport) { // emit re-export for namespace // import * as n from 'foo' @@ -6339,10 +6845,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi // import {a, b} from 'foo' // export {a, b as c} for (let element of (namedBindings).elements) { + pushNode(element); emitExportMemberAssignments(element.name || element.propertyName); writeLine(); + popNode(); } } + popNode(); + popNode(); } decreaseIndent(); @@ -6353,18 +6863,22 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi increaseIndent(); if ((importNode).exportClause) { + pushNode((importNode).exportClause); // export {a, b as c} from 'foo' // emit as: // exports('a', _foo["a"]) // exports('c', _foo["b"]) for (let e of (importNode).exportClause.elements) { + pushNode(e); writeLine(); write(`${exportFunctionForFile}("`); emitNodeWithoutSourceMap(e.name); write(`", ${parameterName}["`); emitNodeWithoutSourceMap(e.propertyName || e.name); write(`"]);`); + popNode(); } + popNode(); } else { writeLine(); @@ -6381,11 +6895,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi write("}"); decreaseIndent(); + popNode(); } write("],"); } function emitExecute(node: SourceFile, startIndex: number) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + write("execute: function() {"); increaseIndent(); writeLine(); @@ -6409,6 +6926,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitSystemModule(node: SourceFile, startIndex: number): void { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + collectExternalModuleInfo(node); // System modules has the following shape // System.register(['dep-1', ... 'dep-n'], function(exports) {/* module body function */}) @@ -6428,11 +6947,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } write("["); for (let i = 0; i < externalImports.length; ++i) { - let text = getExternalModuleNameText(externalImports[i]); + let externalImport = externalImports[i]; + pushNode(externalImport); + let text = getExternalModuleNameText(externalImport); if (i !== 0) { write(", "); } write(text); + popNode(); } write(`], function(${exportFunctionForFile}) {`); writeLine(); @@ -6445,6 +6967,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitAMDDependencies(node: SourceFile, includeNonAmdDependencies: boolean) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + // An AMD define function has the following shape: // define(id?, dependencies?, factory); // @@ -6477,6 +7001,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } for (let importNode of externalImports) { + pushNode(importNode); // Find the name of the external module let externalModuleName = getExternalModuleNameText(importNode); @@ -6489,6 +7014,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi else { unaliasedModuleNames.push(externalModuleName); } + popNode(); } write("[\"require\", \"exports\""); @@ -6508,6 +7034,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitAMDModule(node: SourceFile, startIndex: number) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + collectExternalModuleInfo(node); writeLine(); @@ -6529,6 +7057,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitCommonJSModule(node: SourceFile, startIndex: number) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + collectExternalModuleInfo(node); emitExportStarHelper(); emitCaptureThisForNodeIfNecessary(node); @@ -6538,6 +7068,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitUMDModule(node: SourceFile, startIndex: number) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + collectExternalModuleInfo(node); // Module is detected first to support Browserify users that load into a browser with an AMD loader @@ -6563,6 +7095,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitES6Module(node: SourceFile, startIndex: number) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + externalImports = undefined; exportSpecifiers = undefined; exportEquals = undefined; @@ -6575,18 +7109,22 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitExportEquals(emitAsReturn: boolean) { + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack, exportEquals); + if (exportEquals && resolver.isValueAliasDeclaration(exportEquals)) { + pushNode(exportEquals); writeLine(); emitStart(exportEquals); write(emitAsReturn ? "return " : "module.exports = "); emit((exportEquals).expression); write(";"); emitEnd(exportEquals); + popNode(); } } function emitJsxElement(node: JsxElement | JsxSelfClosingElement) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); switch (compilerOptions.jsx) { case JsxEmit.React: @@ -6601,7 +7139,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function trimReactWhitespace(node: JsxText): string { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); let result: string = undefined; let text = getTextOfNode(node); @@ -6636,7 +7174,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function getTextToEmit(node: JsxText) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + switch (compilerOptions.jsx) { case JsxEmit.React: let text = trimReactWhitespace(node); @@ -6653,7 +7192,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitJsxText(node: JsxText) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + switch (compilerOptions.jsx) { case JsxEmit.React: write('"'); @@ -6669,7 +7209,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitJsxExpression(node: JsxExpression) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + if (node.expression) { switch (compilerOptions.jsx) { case JsxEmit.Preserve: @@ -6686,6 +7227,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitDirectivePrologues(statements: Node[], startWithNewLine: boolean): number { + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack); + for (let i = 0; i < statements.length; ++i) { if (isPrologueDirective(statements[i])) { if (startWithNewLine || i > 0) { @@ -6702,6 +7245,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function writeLines(text: string): void { + verifyStackBehavior(StackBehavior.Unspecified); + let lines = text.split(/\r\n|\r|\n/g); for (let i = 0; i < lines.length; ++i) { let line = lines[i]; @@ -6713,7 +7258,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitSourceFileNode(node: SourceFile) { - // node stack behavior: `node` is top of stack + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); // Start new file on new line writeLine(); @@ -6777,35 +7322,67 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi emitTempDeclarations(/*newLine*/ true); } + pushNode(node.endOfFileToken); emitLeadingComments(node.endOfFileToken); + popNode(); + } + + function emitWithStackBehavior(node: T, emit: (node: T) => U, stackBehavior: StackBehavior): U { + let result: U; + if (stackBehavior === StackBehavior.NodeIsOnTopOfStack && currentNode !== node) { + pushNode(node); + result = emit(node); + popNode(); + } + else if (stackBehavior === StackBehavior.ParentIsOnTopOfStack && currentNode === node) { + popNode(); + result = emit(node); + pushNode(node); + } + else { + result = emit(node); + } + + return result; } function emitNodeWithoutSourceMap(node: Node): void { if (!node) { return; } - - if (node.flags & NodeFlags.Ambient) { - return emitOnlyPinnedOrTripleSlashComments(node); - } + + verifyStackBehavior(StackBehavior.ParentIsOnTopOfStack, node); + let debugStackSize = nodeStackSize; + let debugParentNode = parentNode; + let debugCurrentNode = currentNode; pushNode(node); - - let emitComments = shouldEmitLeadingAndTrailingComments(node); - if (emitComments) { - emitLeadingComments(node); + if (node.flags & NodeFlags.Ambient) { + emitOnlyPinnedOrTripleSlashComments(node); + } + else { + let emitComments = shouldEmitLeadingAndTrailingComments(node); + if (emitComments) { + emitLeadingComments(node); + } + + emitJavaScriptWorker(node); + + if (emitComments) { + emitTrailingComments(node); + } } - - emitJavaScriptWorker(node); popNode(); - - if (emitComments) { - emitTrailingComments(node); - } + + Debug.assert(debugStackSize === nodeStackSize + && debugParentNode === parentNode + && debugCurrentNode === currentNode, "Incorrect stack behavior. Node stack after emit does not match node stack before emit."); } function shouldEmitLeadingAndTrailingComments(node: Node) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + switch (node.kind) { // All of these entities are emitted in a specialized fashion. As such, we allow // the specialized methods for each to handle the comments on the nodes. @@ -6849,6 +7426,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitJavaScriptWorker(node: Node) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + // Check if the node can be emitted regardless of the ScriptTarget switch (node.kind) { case SyntaxKind.Identifier: @@ -7020,10 +7599,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function hasDetachedComments(pos: number) { + verifyStackBehavior(StackBehavior.Unspecified); + return detachedCommentsInfo !== undefined && lastOrUndefined(detachedCommentsInfo).nodePos === pos; } function getLeadingCommentsWithoutDetachedComments() { + verifyStackBehavior(StackBehavior.Unspecified); + // get the leading comments from detachedPos let leadingComments = getLeadingCommentRanges(currentSourceFile.text, lastOrUndefined(detachedCommentsInfo).detachedCommentEndPos); @@ -7038,6 +7621,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function filterComments(ranges: CommentRange[], onlyPinnedOrTripleSlashComments: boolean): CommentRange[] { + verifyStackBehavior(StackBehavior.Unspecified); + // If we're removing comments, then we want to strip out all but the pinned or // triple slash comments. if (ranges && onlyPinnedOrTripleSlashComments) { @@ -7051,9 +7636,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function getLeadingCommentsToEmit(node: Node) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + // Emit the leading comments only if the parent's pos doesn't match because parent should take care of emitting these comments - if (node.parent) { - if (node.parent.kind === SyntaxKind.SourceFile || node.pos !== node.parent.pos) { + if (parentNode) { + if (parentNode.kind === SyntaxKind.SourceFile || node.pos !== parentNode.pos) { if (hasDetachedComments(node.pos)) { // get comments without detached comments return getLeadingCommentsWithoutDetachedComments(); @@ -7067,23 +7654,31 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function getTrailingCommentsToEmit(node: Node) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + // Emit the trailing comments only if the parent's pos doesn't match because parent should take care of emitting these comments - if (node.parent) { - if (node.parent.kind === SyntaxKind.SourceFile || node.end !== node.parent.end) { + if (parentNode && !nodeIsSynthesized(parentNode)) { + if (parentNode.kind === SyntaxKind.SourceFile || node.end !== parentNode.end) { return getTrailingCommentRanges(currentSourceFile.text, node.end); } } } function emitOnlyPinnedOrTripleSlashComments(node: Node) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + emitLeadingCommentsWorker(node, /*onlyPinnedOrTripleSlashComments:*/ true); } function emitLeadingComments(node: Node) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + return emitLeadingCommentsWorker(node, /*onlyPinnedOrTripleSlashComments:*/ compilerOptions.removeComments); } function emitLeadingCommentsWorker(node: Node, onlyPinnedOrTripleSlashComments: boolean) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + // If the caller only wants pinned or triple slash comments, then always filter // down to that set. Otherwise, filter based on the current compiler options. let leadingComments = filterComments(getLeadingCommentsToEmit(node), onlyPinnedOrTripleSlashComments); @@ -7095,6 +7690,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitTrailingComments(node: Node) { + verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node); + // Emit the trailing comments only if the parent's end doesn't match let trailingComments = filterComments(getTrailingCommentsToEmit(node), /*onlyPinnedOrTripleSlashComments:*/ compilerOptions.removeComments); @@ -7103,6 +7700,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitLeadingCommentsOfPosition(pos: number) { + verifyStackBehavior(StackBehavior.Unspecified); + let leadingComments: CommentRange[]; if (hasDetachedComments(pos)) { // get comments without detached comments @@ -7121,6 +7720,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitDetachedComments(node: TextRange) { + verifyStackBehavior(StackBehavior.Unspecified); + let leadingComments = getLeadingCommentRanges(currentSourceFile.text, node.pos); if (leadingComments) { let detachedComments: CommentRange[] = []; @@ -7166,6 +7767,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function isPinnedOrTripleSlashComment(comment: CommentRange) { + verifyStackBehavior(StackBehavior.Unspecified); + if (currentSourceFile.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk) { return currentSourceFile.text.charCodeAt(comment.pos + 2) === CharacterCodes.exclamation; } @@ -7178,6 +7781,26 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi return true; } } + + function verifyStackBehavior(behavior: StackBehavior, node?: Node) { + switch (behavior) { + case StackBehavior.Unspecified: + return; + + case StackBehavior.NodeIsOnTopOfStack: + if (node) { + Debug.assert(currentNode === node, "Incorrect node stack behavior. Expected node to be on the top of the stack."); + } + else { + Debug.assert(currentNode !== undefined, "Incorrect node stack behavior. Expected node to be on the top of the stack."); + } + return; + + case StackBehavior.ParentIsOnTopOfStack: + Debug.assert(currentNode !== node, "Incorrect node stack behavior. Expected parent of node to be on the top of the stack."); + return; + } + } } function emitFile(jsFilePath: string, sourceFile?: SourceFile) { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index d4e421b73a8..8fb77e8aa20 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -215,8 +215,10 @@ namespace ts { // Gets the nearest enclosing block scope container that has the provided node // as a descendant, that is not the provided node. - export function getEnclosingBlockScopeContainer(node: Node): Node { - let current = node.parent; + export function getEnclosingBlockScopeContainer(node: Node): Node; + export function getEnclosingBlockScopeContainer(node: Node, getAncestorOrSelf: (offset: number) => Node, offset: number): Node; + export function getEnclosingBlockScopeContainer(node: Node, getAncestorOrSelf?: (offset: number) => Node, offset?: number): Node { + let current = getAncestorOrSelf ? getAncestorOrSelf(++offset) : node.parent; while (current) { if (isFunctionLike(current)) { return current; @@ -233,12 +235,12 @@ namespace ts { case SyntaxKind.Block: // function block is not considered block-scope container // see comment in binder.ts: bind(...), case for SyntaxKind.Block - if (!isFunctionLike(current.parent)) { + if (!isFunctionLike(getAncestorOrSelf ? getAncestorOrSelf(offset + 1) : current.parent)) { return current; } } - current = current.parent; + current = getAncestorOrSelf ? getAncestorOrSelf(++offset) : current.parent; } } @@ -333,14 +335,6 @@ namespace ts { return node.kind === SyntaxKind.EnumDeclaration && isConst(node); } - function walkUpBindingElementsAndPatterns(node: Node): Node { - while (node && (node.kind === SyntaxKind.BindingElement || isBindingPattern(node))) { - node = node.parent; - } - - return node; - } - // Returns the node flags for this node and all relevant parent nodes. This is done so that // nodes like variable declarations and binding elements can returned a view of their flags // that includes the modifiers from their container. i.e. flags like export/declare aren't @@ -348,41 +342,21 @@ namespace ts { // (if it has one). Similarly, flags for let/const are store on the variable declaration // list. By calling this function, all those flags are combined so that the client can treat // the node as if it actually had those flags. - export function getCombinedNodeFlags(node: Node): NodeFlags { - node = walkUpBindingElementsAndPatterns(node); + export function getCombinedNodeFlags(node: Node): NodeFlags; + export function getCombinedNodeFlags(node: Node, getAncestorOrSelf: (offset: number) => Node, offset: number): NodeFlags; + export function getCombinedNodeFlags(node: Node, getAncestorOrSelf?: (offset: number) => Node, offset?: number): NodeFlags { + while (node && (node.kind === SyntaxKind.BindingElement || isBindingPattern(node))) { + node = getAncestorOrSelf ? getAncestorOrSelf(++offset) : node.parent; + } let flags = node.flags; if (node.kind === SyntaxKind.VariableDeclaration) { - node = node.parent; + node = getAncestorOrSelf ? getAncestorOrSelf(++offset) : node.parent; } if (node && node.kind === SyntaxKind.VariableDeclarationList) { flags |= node.flags; - node = node.parent; - } - - if (node && node.kind === SyntaxKind.VariableStatement) { - flags |= node.flags; - } - - return flags; - } - - export function getCombinedNodeFlagsForNodeStack(nodeStack: Node[]): NodeFlags { - let i = nodeStack.length - 1; - let node = nodeStack[i--]; - while (node && (node.kind === SyntaxKind.BindingElement || isBindingPattern(node))) { - node = nodeStack[i--]; - } - - let flags = node.flags; - if (node && node.kind === SyntaxKind.VariableDeclaration) { - node = nodeStack[i--]; - } - - if (node && node.kind === SyntaxKind.VariableDeclarationList) { - flags |= node.flags; - node = nodeStack[i--]; + node = getAncestorOrSelf ? getAncestorOrSelf(++offset) : node.parent; } if (node && node.kind === SyntaxKind.VariableStatement) { @@ -875,7 +849,10 @@ namespace ts { return nodeIsDecorated(node) || childIsDecorated(node); } - export function isExpression(node: Node): boolean { + export function isExpression(node: Node): boolean; + export function isExpression(node: Node, getAncestorOrSelf: (offset: number) => Node, offset: number): boolean; + export function isExpression(node: Node, getAncestorOrSelf?: (offset: number) => Node, offset?: number): boolean { + let parent: Node; switch (node.kind) { case SyntaxKind.ThisKeyword: case SyntaxKind.SuperKeyword: @@ -912,18 +889,22 @@ namespace ts { case SyntaxKind.YieldExpression: return true; case SyntaxKind.QualifiedName: - while (node.parent.kind === SyntaxKind.QualifiedName) { - node = node.parent; + parent = getAncestorOrSelf ? getAncestorOrSelf(++offset) : node.parent; + while (parent.kind === SyntaxKind.QualifiedName) { + node = parent; + parent = getAncestorOrSelf ? getAncestorOrSelf(++offset) : node.parent; } - return node.parent.kind === SyntaxKind.TypeQuery; + return parent.kind === SyntaxKind.TypeQuery; + case SyntaxKind.Identifier: - if (node.parent.kind === SyntaxKind.TypeQuery) { + parent = getAncestorOrSelf ? getAncestorOrSelf(offset + 1) : node.parent; + if (parent.kind === SyntaxKind.TypeQuery) { return true; } // fall through case SyntaxKind.NumericLiteral: case SyntaxKind.StringLiteral: - let parent = node.parent; + parent = getAncestorOrSelf ? getAncestorOrSelf(offset + 1) : node.parent; switch (parent.kind) { case SyntaxKind.VariableDeclaration: case SyntaxKind.Parameter: @@ -964,9 +945,9 @@ namespace ts { case SyntaxKind.Decorator: return true; case SyntaxKind.ExpressionWithTypeArguments: - return (parent).expression === node && isExpressionWithTypeArgumentsInClassExtendsClause(parent); + return (parent).expression === node && isExpressionWithTypeArgumentsInClassExtendsClause(parent, getAncestorOrSelf, offset + 1); default: - if (isExpression(parent)) { + if (isExpression(parent, getAncestorOrSelf, offset)) { return true; } } @@ -1451,7 +1432,7 @@ namespace ts { export function nodeStartsNewLexicalEnvironment(n: Node): boolean { return isFunctionLike(n) || n.kind === SyntaxKind.ModuleDeclaration || n.kind === SyntaxKind.SourceFile; } - + export function nodeIsSynthesized(node: Node): boolean { return node.pos === -1; } @@ -1980,10 +1961,15 @@ namespace ts { return token >= SyntaxKind.FirstAssignment && token <= SyntaxKind.LastAssignment; } - export function isExpressionWithTypeArgumentsInClassExtendsClause(node: Node): boolean { - return node.kind === SyntaxKind.ExpressionWithTypeArguments && - (node.parent).token === SyntaxKind.ExtendsKeyword && - isClassLike(node.parent.parent); + export function isExpressionWithTypeArgumentsInClassExtendsClause(node: Node, getAncestorOrSelf?: (offset: number) => Node, offset?: number): boolean { + if (node.kind === SyntaxKind.ExpressionWithTypeArguments) { + let parent = getAncestorOrSelf ? getAncestorOrSelf(offset + 1) : node.parent; + if ((parent).token === SyntaxKind.ExtendsKeyword) { + let grandparent = getAncestorOrSelf ? getAncestorOrSelf(offset + 2) : parent.parent; + return isClassLike(grandparent); + } + } + return false; } // Returns false if this heritage clause element's expression contains something unsupported