Skip to content

Add a new visitor: SyntaxTransformVisitor. #643

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 10 commits into from
Sep 7, 2022

Conversation

zoecarver
Copy link
Contributor

This visitor returns a transformed Syntax node rather than exposing a pre-post visitor. This will be helpful for ASTGen.

@zoecarver zoecarver requested a review from ahoppen as a code owner August 26, 2022 23:22
% end
% end

public func visit(_ data: SyntaxData) -> [ResultType] {
Copy link
Contributor

Choose a reason for hiding this comment

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

We don't want clients visiting SyntaxData directly.

Copy link
Member

Choose a reason for hiding this comment

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

I agree, SyntaxTransformVisitor should be a class and this should be private like we do in all the other initializers.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why do we want this to be a class? I think this should just take a Syntax.

Copy link
Member

@ahoppen ahoppen left a comment

Choose a reason for hiding this comment

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

I’m a little worried about this implementation because IIUC its default implementation discards any recursive transformations by default. My suggestion would be to have a visitAny method (similar to SyntaxAnyVisitor) that all the visit methods default to and have that visitAny method fatalError by default. This way you’ll trap at runtime rather than just dropping results.

Also, I’m not a huge fan of tying this to Array as the transformation result. What do you think about having two generic types: NodeTransformResult and TransformResult (feel free to come up with a better name) and then combining them using a func reduce(initialResult: TransformResult?, nextPartialResult: NodeTransformResult). That way you could also return strings testStringify instead of arrays of strings.

% end
% end

public func visit(_ data: SyntaxData) -> [ResultType] {
Copy link
Member

Choose a reason for hiding this comment

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

I agree, SyntaxTransformVisitor should be a class and this should be private like we do in all the other initializers.

}
}

public func visitChildren<SyntaxType: SyntaxProtocol>(_ node: SyntaxType) -> [ResultType] {
Copy link
Member

Choose a reason for hiding this comment

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

Similarly to visit(_ data: SyntaxData), this should be private.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why? It is useful to API consumers (see the FuncCounter test).

@@ -141,3 +141,75 @@ open class SyntaxVisitor {
}
}
}

public protocol SyntaxTransformVisitor {
Copy link
Member

Choose a reason for hiding this comment

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

Let’s put this in a different file. SyntaxRewriter also has its dedicated file.

@zoecarver
Copy link
Contributor Author

I’m a little worried about this implementation because IIUC its default implementation discards any recursive transformations by default. My suggestion would be to have a visitAny method (similar to SyntaxAnyVisitor) that all the visit methods default to and have that visitAny method fatalError by default. This way you’ll trap at runtime rather than just dropping results.

I'm not sure what you mean by this. The default implementation will visit all the children and flatMap them together. Nothing should be lost...

Also, I’m not a huge fan of tying this to Array as the transformation result. What do you think about having two generic types: NodeTransformResult and TransformResult (feel free to come up with a better name) and then combining them using a func reduce(initialResult: TransformResult?, nextPartialResult: NodeTransformResult). That way you could also return strings testStringify instead of arrays of strings.

As long as there can be N children, I think this implementation will be hard. For a generic implementation, the reducer will either have to drop something on the floor or be non-trivial. I like that with the array approach we can handle any input and pass it up to the client for processing/validation.

If performance is a concern, maybe we can introduce a SingleTransformVisitor that returns a T? instead of [T] and asserts that all nodes have one or no children. Otherwise, maybe we can work on your suggested implementation offline or commit it as a follow-up change?

@zoecarver
Copy link
Contributor Author

@swift-ci please test

@zoecarver
Copy link
Contributor Author

@swift-ci test

1 similar comment
@zoecarver
Copy link
Contributor Author

@swift-ci test

zoecarver added a commit to zoecarver/swift-syntax that referenced this pull request Sep 6, 2022
@zoecarver
Copy link
Contributor Author

The visitAny method was a great idea. The stringify test did not change, but the FuncCounter got a lot simpler :) Thanks, @ahoppen!

@zoecarver
Copy link
Contributor Author

@swift-ci please test

public func visit(_ data: ExprSyntax) -> ResultType {
switch data.raw.kind {
% for node in NON_BASE_SYNTAX_NODES:
% if node.base_kind == "Expr":
case .${node.swift_syntax_kind}:
let node = data.as(${node.name}.self)!
return visit(node)
% end
% end
default:
fatalError("Not expression?")
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need this method? I don’t think we should ever end up calling visit with a base node type. Same for the methods below.

@zoecarver
Copy link
Contributor Author

@swift-ci please test

@zoecarver
Copy link
Contributor Author

@swift-ci please test

@zoecarver zoecarver merged commit 6cd32e4 into swiftlang:main Sep 7, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants