Added offset information when visiting an array of nodes.

This commit is contained in:
Ron Buckton 2015-09-14 15:48:26 -07:00
parent 8cb5f78af3
commit f6fcd5c54a
3 changed files with 65 additions and 86 deletions

View file

@ -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 {

View file

@ -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<TOut extends Node> = (node: TOut) => void;
export type Pipeline<TIn extends Node, TOut extends Node> = (input: TIn, output: PipelineOutput<TOut>) => void;
export type Pipeline<TIn extends Node, TOut extends Node> = (input: TIn, output: PipelineOutput<TOut>, offset?: number) => void;
export type NodeTest<T extends Node> = (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<TIn extends Node, TOut extends Node>(inputNode: TIn, inputNodes: TIn[], pipeline: Visitor, output: (node: TOut) => void, flags: PipelineFlags): void {
function pipeOneOrMany<TIn extends Node, TOut extends Node>(inputNode: TIn, inputNodes: TIn[], pipeline: Pipeline<TIn, TOut>, 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.

View file

@ -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<Statement>) {
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<BindingPattern, Expression>(name, transformBindingPatternToExpression);
@ -686,27 +686,22 @@ namespace ts.transform {
write(createObjectLiteralExpression2(properties));
}
function transformBindingElementToObjectLiteralElement(node: BindingElement, write: (node: ObjectLiteralElement) => void) {
let propertyName = node.propertyName || <Identifier>node.name;
let name = node.name;
let expr = isBindingPattern(name)
? visitNode<BindingPattern, Expression>(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<BindingElement, Expression>(node.elements, transformBindingElementToExpression);
write(createArrayLiteralExpression(elements));
}
function transformBindingElementToObjectLiteralElement(node: BindingElement, write: (node: ObjectLiteralElement) => void) {
let propertyName = node.propertyName || <Identifier>node.name;
let expr = visitNode<BindingElement, Expression>(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<BindingPattern, Expression>(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