Skip to content

Adds the visitor API foundation for tree transformations. #6892

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 131 commits into from
Mar 18, 2016

Conversation

rbuckton
Copy link
Member

@rbuckton rbuckton commented Feb 4, 2016

This provides the basic foundation for tree transformations. The additions include:

  • factory.ts - Which will include a growing list of node factory functions used by various transformations.
  • visitor.ts - The various visitor functions used for visiting the tree.

The visitNode function is used to visit single-node branches of a tree. It also provides a facility for converting an array of nodes (in the form of a NodeArrayNode) into a single node, for cases such as converting a single-statement branch of an IterationStatement into a Block.

The visitNodes function is used to visit an array of nodes. If there are no changes to any node in the array (all visited nodes have the same reference and the same number of nodes were written), then the original array is returned. This allows for faster change detection in visitEachChild by way of reference equality checks.

The visitEachNode function is used as a fallback mechanism to recursively apply a visitor to each branch of the tree. This function leverages nodeEdgeTraversalMap, which is used to describe which properties should be traversed as well as how to verify the tree.

The LexicalEnvironment interface will be leveraged in a later revision to provide a mechanism for hoisting temporary variables and function declarations.

Examples

The following is an example of a visitor that could be used with these helpers:

function visitor(node: Node) {
  switch (node.kind) {
    case SyntaxKind.BinaryExpression:
      return visitBinaryExpression(<BinaryExpression>node);
    ...
    default:
      return visitEachChild(node, visitor);
  }
}
function visitBinaryExpression(node: BinaryExpression) {
  if (node.operatorToken.kind === SyntaxKind.AsteriskAsteriskToken) {
    return createCall(
      createPropertyAccess(createIdentifier("Math"), "pow"),
      [
        visitNode(node.left, visitor, isExpressionNode),
        visitNode(node.right, visitor, isExpressionNode)
      ]
    );
  }
  else {
    return visitEachChild(node, visitor);
  }
}

Related Pull Requests:

Review on Reviewable

@rbuckton
Copy link
Member Author

rbuckton commented Feb 4, 2016

@mhegazy, @ahejlsberg I will be publishing a series of pull requests targeting the transforms branch, which is a recent branch of master. This way I am able to break up this work into smaller, more easily reviewed chunks. I also will regularly merge from master into transforms to keep it in sync. Once the transformation work is fully integrated into transforms, there will be a single PR to merge transforms into master.

@rbuckton
Copy link
Member Author

rbuckton commented Feb 4, 2016

Another PR with the second layer of the transformations API will be published tomorrow.

@rbuckton
Copy link
Member Author

rbuckton commented Feb 4, 2016

CC: @yuit, @DanielRosenwasser, @RyanCavanaugh, @vladima

I want to make sure I have a lot of eyes on this implementation as we move forward.

}

export function createNodeArrayNode<T extends Node>(elements?: (T | NodeArrayNode<T>)[]): NodeArrayNode<T> {
const array = <NodeArrayNode<T>>createNodeArray(elements);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you feed NodeArrayNode<T> as a type argument instead?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would end up being createNodeArray<T | NodeArrayNode<T>, NodeArrayNode<T>>(elements)), which isn't as clear.

@rbuckton
Copy link
Member Author

rbuckton commented Feb 8, 2016

CC: @sandersn

/* @internal */
namespace ts {
let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any reason you need to do this again instead of leveraging ts.createNode?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is partly performance related, as the ts namespace is horribly deoptimized in v8, but also due to the fact I have a slightly different call signature.

rbuckton and others added 26 commits March 2, 2016 15:20
Adds a simplified pretty printer for tree transformations
Adds the transformFiles API for tree transformations
Adds the Transform Flags concept for tree transformations
rbuckton added a commit that referenced this pull request Mar 18, 2016
Adds the visitor API foundation for tree transformations.
@rbuckton rbuckton merged commit 5732a60 into transforms Mar 18, 2016
@rbuckton rbuckton deleted the transforms-visitor branch March 18, 2016 23:40
@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants