From f6fcd5c54a8d08328ae05eb864763fdba46f9ee1 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Mon, 14 Sep 2015 15:48:26 -0700 Subject: [PATCH] Added offset information when visiting an array of nodes. --- src/compiler/factory.ts | 11 ++- src/compiler/transform.ts | 7 +- src/compiler/transforms/es6.ts | 133 +++++++++++++-------------------- 3 files changed, 65 insertions(+), 86 deletions(-) diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index cdcb9be5fe1..fc9ea71a518 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -260,11 +260,14 @@ namespace ts { return createVariableStatement(undefined, undefined, declarationList, location, flags); } - export function createSimpleLetStatement(name: Identifier, initializer: Expression, location?: TextRange, exported?: boolean) { + export function createVariableStatement3(name: Identifier | BindingPattern, initializer?: Expression, location?: TextRange, flags?: NodeFlags) { let varDecl = createVariableDeclaration2(name, initializer); - let varDeclList = createVariableDeclarationList([varDecl], undefined, NodeFlags.Let); - let varStmt = createVariableStatement2(varDeclList, location, exported ? NodeFlags.Export : 0); - return varStmt; + let varDeclList = createVariableDeclarationList([varDecl], undefined, flags & (NodeFlags.Let | NodeFlags.Const)); + return createVariableStatement2(varDeclList, location, flags & ~(NodeFlags.Let | NodeFlags.Const)); + } + + export function createLetStatement(name: Identifier, initializer: Expression, location?: TextRange, exported?: boolean) { + return createVariableStatement3(name, initializer, location, exported ? NodeFlags.Let | NodeFlags.Export : NodeFlags.Let); } export function createExportDefaultStatement(expression: Expression): ExportAssignment { diff --git a/src/compiler/transform.ts b/src/compiler/transform.ts index 3097a324c60..593be59c8b9 100644 --- a/src/compiler/transform.ts +++ b/src/compiler/transform.ts @@ -7,7 +7,7 @@ namespace ts { export type Visitor = (input: Node, output: (node: Node) => void) => void; export type LexicalEnvironmentBody = ModuleDeclaration | ModuleBlock | Block | Expression; export type PipelineOutput = (node: TOut) => void; - export type Pipeline = (input: TIn, output: PipelineOutput) => void; + export type Pipeline = (input: TIn, output: PipelineOutput, offset?: number) => void; export type NodeTest = (node: Node) => node is T; /** @@ -724,7 +724,7 @@ namespace ts { * This function also manages when new lexical environments are introduced, and tracks temporary * variables and hoisted variable and function declarations. */ - function pipeOneOrMany(inputNode: TIn, inputNodes: TIn[], pipeline: Visitor, output: (node: TOut) => void, flags: PipelineFlags): void { + function pipeOneOrMany(inputNode: TIn, inputNodes: TIn[], pipeline: Pipeline, output: (node: TOut) => void, flags: PipelineFlags): void { if (!inputNode && !inputNodes) { return; } @@ -760,9 +760,10 @@ namespace ts { nodeStack.pushNode(/*node*/ undefined); // Visit each input node + let offset = 0; for (let node of inputNodes) { nodeStack.setNode(node); - pipeline(node, output); + pipeline(node, output, offset++); } // For the perf reasons mentioned above, we pop the current node at the end of the loop. diff --git a/src/compiler/transforms/es6.ts b/src/compiler/transforms/es6.ts index 548333f6b52..d7b1486fcfe 100644 --- a/src/compiler/transforms/es6.ts +++ b/src/compiler/transforms/es6.ts @@ -4,19 +4,19 @@ namespace ts.transform { let resolver: EmitResolver; let compilerOptions: CompilerOptions; let languageVersion: ScriptTarget; - let currentLexicalEnvironment: SourceFile | FunctionLikeDeclaration | ModuleDeclaration let currentModuleDeclaration: ModuleDeclaration; let currentClassLikeDeclaration: ClassLikeDeclaration; let currentBaseTypeNode: ExpressionWithTypeArguments; let currentConstructor: ConstructorDeclaration; let currentParametersWithPropertyAssignments: ParameterDeclaration[]; let currentInstancePropertyAssignments: PropertyDeclaration[]; + let currentEnumLocalName: Identifier; + let currentParameterIndex: number; export function toES6(statements: NodeArray) { resolver = getEmitResolver(); compilerOptions = getCompilerOptions(); languageVersion = compilerOptions.target || ScriptTarget.ES3; - currentLexicalEnvironment = getRootNode(); return visitNodes(statements, transformNode, PipelineFlags.LexicalEnvironment); } @@ -251,11 +251,11 @@ namespace ts.transform { // If the class has been decorated, we need to emit the class as part of a `let` declaration // to avoid the pitfalls of the doubly-bound class name. let classExpr = createClassExpression3(currentBaseTypeNode, classMembers); - let varStmt = createSimpleLetStatement(getDeclarationName(node), classExpr, /*location*/ node, isTopLevelNonDefaultExport(node)); + let varStmt = createLetStatement(getDeclarationName(node), classExpr, /*location*/ node, isTopLevelNonDefaultExport(node)); write(setOriginalNode(varStmt, node)); } else { - let exportFlags = isNamespaceLevelExport(node) ? undefined : node.flags & (NodeFlags.Export | NodeFlags.Default); + let exportFlags = isTopLevelExport(node) ? node.flags & (NodeFlags.Export | NodeFlags.Default) : undefined; let classDecl = createClassDeclaration2(getDeclarationName(node), currentBaseTypeNode, classMembers, /*location*/ node, exportFlags); write(setOriginalNode(classDecl, node)); } @@ -626,9 +626,7 @@ namespace ts.transform { return callExpr; } else { - let returnStmt = createReturnStatement(callExpr); - let newBody = createBlock([returnStmt], /*location*/ body); - return newBody; + return createBlock([createReturnStatement(callExpr)], /*location*/ body); } } @@ -655,6 +653,8 @@ namespace ts.transform { return; } + transformBindingElementToExpressionWithParenthesisIfNeeded(node, write, /*parenthesizeObjectLiteralAssignment*/ true); + let name = node.name; if (isBindingPattern(name)) { let expr = visitNode(name, transformBindingPatternToExpression); @@ -686,27 +686,22 @@ namespace ts.transform { write(createObjectLiteralExpression2(properties)); } - function transformBindingElementToObjectLiteralElement(node: BindingElement, write: (node: ObjectLiteralElement) => void) { - let propertyName = node.propertyName || node.name; - let name = node.name; - let expr = isBindingPattern(name) - ? visitNode(name, transformBindingPatternToExpression) - : getModuleMemberName(node); - - let initializer = visitNode(node.initializer, transformNode); - if (initializer) { - expr = createAssignmentExpression(expr, initializer); - } - - write(createPropertyAssignment(propertyName, expr)); - } - function transformArrayBindingPatternToExpression(node: ArrayBindingPattern, write: (node: Expression) => void) { let elements = visitNodes(node.elements, transformBindingElementToExpression); write(createArrayLiteralExpression(elements)); } + function transformBindingElementToObjectLiteralElement(node: BindingElement, write: (node: ObjectLiteralElement) => void) { + let propertyName = node.propertyName || node.name; + let expr = visitNode(node, transformBindingElementToExpression); + write(createPropertyAssignment(propertyName, expr)); + } + function transformBindingElementToExpression(node: BindingElement, write: (node: Expression) => void) { + transformBindingElementToExpressionWithParenthesisIfNeeded(node, write, /*parenthesizeObjectLiteralAssignment*/ false); + } + + function transformBindingElementToExpressionWithParenthesisIfNeeded(node: BindingElement, write: (node: Expression) => void, parenthesizeObjectLiteralAssignment?: boolean) { let name = node.name; let expr = isBindingPattern(name) ? visitNode(name, transformBindingPatternToExpression) @@ -717,7 +712,10 @@ namespace ts.transform { expr = createAssignmentExpression(expr, initializer); } - if (node.dotDotDotToken) { + if (parenthesizeObjectLiteralAssignment && isObjectBindingPattern(name)) { + expr = createParenthesizedExpression(expr); + } + else if (node.dotDotDotToken) { expr = createSpreadElementExpression(expr); } @@ -811,8 +809,6 @@ namespace ts.transform { } } - let currentEnumLocalName: Identifier; - function transformEnumDeclaration(node: EnumDeclaration, write: (node: Statement) => void) { if (!shouldEmitEnumDeclaration(node)) { // Const enum declarations may be elided. @@ -824,11 +820,7 @@ namespace ts.transform { let location: TextRange = node; if (!isNamespaceLevelExport(node)) { - let exportFlags = isTopLevelExport(node) ? NodeFlags.Export : undefined; - let varDecl = createVariableDeclaration2(node.name, /*initializer*/ undefined, /*location*/ undefined, exportFlags); - let varDecls = createVariableDeclarationList([varDecl]); - let varStmt = createVariableStatement2(varDecls, location); - write(varStmt); + write(createVariableStatement3(node.name, /*initializer*/ undefined, location, isTopLevelExport(node) ? NodeFlags.Export : undefined)); location = undefined; } @@ -844,14 +836,10 @@ namespace ts.transform { let enumStorageInitExpr = createAssignmentExpression(moduleMemberName, enumStorageObjectExpr); let enumStorageExpr = createLogicalOrExpression(moduleMemberName, enumStorageInitExpr); let callExpr = createCallExpression2(parenExpr, [enumStorageExpr]); - let callStmt = createExpressionStatement(callExpr, location); - write(callStmt); + write(createExpressionStatement(callExpr, location)); if (isNamespaceLevelExport(node)) { - let varDecl = createVariableDeclaration2(node.name, moduleMemberName); - let varDecls = createVariableDeclarationList([varDecl]); - let varStmt = createVariableStatement2(varDecls); - write(varStmt); + write(createVariableStatement3(node.name, moduleMemberName)); } currentEnumLocalName = savedCurrentEnumLocalName; @@ -864,8 +852,7 @@ namespace ts.transform { let enumValueAssignExpr = createAssignmentExpression(enumNameElemExpr, enumValueExpr); let enumValueElemExpr = createElementAccessExpression2(currentEnumLocalName, enumValueAssignExpr); let enumNameAssignExpr = createAssignmentExpression(enumValueElemExpr, enumNameExpr); - let enumMemberStmt = createExpressionStatement(enumNameAssignExpr, /*location*/ node); - write(enumMemberStmt); + write(createExpressionStatement(enumNameAssignExpr, /*location*/ node)); } function getEnumMemberDeclarationValue(member: EnumMember): Expression { @@ -947,18 +934,11 @@ namespace ts.transform { // let decoratorExpressions: Expression[] = []; - if (decorators) { - for (let decorator of decorators) { - decoratorExpressions.push(visitNode(decorator.expression, transformNode)) - } - } - - if (constructor) { - appendDecoratorsOfParameters(constructor.parameters, decoratorExpressions); - } + emitNodes(decorators, transformDecoratorToExpression, decoratorExpressions); + emitNode(constructor, emitDecoratorsOfParameters, decoratorExpressions); if (compilerOptions.emitDecoratorMetadata) { - appendSerializedTypeMetadata(node, decoratorExpressions); + emitNode(node, emitSerializedTypeMetadata, decoratorExpressions); } let name = getDeclarationName(node); @@ -967,6 +947,10 @@ namespace ts.transform { write(statement); } + function transformDecoratorToExpression(node: Decorator, write: (node: Expression) => void) { + return visitNode(node.expression, transformNode); + } + function transformDecoratorsOfMember(node: ClassLikeDeclaration, member: ClassElement, write: (node: Statement) => void) { let decorators: Decorator[]; let parameters: ParameterDeclaration[]; @@ -1032,20 +1016,10 @@ namespace ts.transform { // let decoratorExpressions: Expression[] = []; - if (decorators) { - for (let decorator of decorators) { - decoratorExpressions.push(visitNode(decorator.expression, transformNode)) - } - } - - if (parameters) { - // TODO(rbuckton): switch to emitNode to maintain node stack - appendDecoratorsOfParameters(parameters, decoratorExpressions); - } - + emitNodes(decorators, transformDecoratorToExpression, decoratorExpressions); + emitNodes(parameters, emitDecoratorsOfParameter, decoratorExpressions); if (compilerOptions.emitDecoratorMetadata) { - // TODO(rbuckton): switch to emitNode to maintain node stack - appendSerializedTypeMetadata(node, decoratorExpressions); + emitNode(node, emitSerializedTypeMetadata, decoratorExpressions); } let prefix = getClassMemberPrefix(node, member); @@ -1064,39 +1038,40 @@ namespace ts.transform { } } - function appendDecoratorsOfParameters(parameters: ParameterDeclaration[], expressions: Expression[]) { - // TODO(rbuckton): switch to emitNode to maintain node stack - for (let parameterIndex = 0; parameterIndex < parameters.length; parameterIndex++) { - let parameter = parameters[parameterIndex]; - if (nodeIsDecorated(parameter)) { - for (let decorator of parameter.decorators) { - let decoratorExpr = visitNode(decorator.expression, transformNode); - let paramExpr = createParamHelperCall(parameterIndex, decoratorExpr); - expressions.push(paramExpr); - } - } - } + function emitDecoratorsOfParameters(node: FunctionLikeDeclaration, write: (node: Expression) => void) { + pipeNodes(node.parameters, emitDecoratorsOfParameter, write); } - function appendSerializedTypeMetadata(node: Declaration, expressions: Expression[]) { - // TODO(rbuckton): switch to emitNode to maintain node stack + function emitDecoratorsOfParameter(node: ParameterDeclaration, write: (node: Expression) => void, offset?: number) { + let savedCurrentParameterIndex = currentParameterIndex; + currentParameterIndex = offset; + pipeNodes(node.decorators, emitDecoratorOfParameter, write); + currentParameterIndex = savedCurrentParameterIndex; + } + + function emitDecoratorOfParameter(node: Decorator, write: (node: Expression) => void) { + let decoratorExpr = visitNode(node.expression, transformNode); + write(createParamHelperCall(currentParameterIndex, decoratorExpr)); + } + + function emitSerializedTypeMetadata(node: Declaration, write: (node: Expression) => void) { if (shouldAppendTypeMetadata(node)) { let typeExpr = serializeTypeOfNode(node); let metadataExpr = createMetadataHelperCall("design:type", createArrowFunction2([], typeExpr)); - expressions.push(metadataExpr); + write(metadataExpr); } if (shouldAppendParamTypesMetadata(node)) { let paramTypesExpr = serializeParameterTypesOfNode(node); let metadataExpr = createMetadataHelperCall("design:paramtypes", createArrowFunction2([], paramTypesExpr)); - expressions.push(metadataExpr); + write(metadataExpr); } if (shouldAppendReturnTypeMetadata(node)) { let returnTypeExpr = serializeReturnTypeOfNode(node); let metadataExpr = createMetadataHelperCall("design:returntype", createArrowFunction2([], returnTypeExpr)); - expressions.push(metadataExpr); + write(metadataExpr); } } - + function shouldAppendTypeMetadata(node: Declaration): boolean { // 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