Skip to content
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

Sketch of a visitor pattern #719

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft

Conversation

glasser
Copy link
Member

@glasser glasser commented Nov 3, 2023

This visitor pattern is designed for doing normalizations on executable documents, so it assumes you will mutate the tree as it is walked. (Perhaps a better design would be to make each visitor return an object of the type it is visiting (which could be the same object it received), constructing a new tree (possibly sharing most of its data) immutably.)

This highlights some places where it would be helpful if the AST contained more explicit types where it currently only has variants, type aliases, or vecs. By having more little structs in the type system, it's easier to write a visitor like this that can easily target (say) every Name node. This includes:

  • It would be helpful if all enums (which actually contain data, so not OperationType) had a specific type for each variant, so that visitors can choose to visit that variant specifically. Definition and Selection work this way already; Type and Value do not. This is especially helpful for Value, as it would be nice to be able to write visitors that visit just string values or int values or whatever without needing to match against the Value.
  • Most uses of NodeStr in the AST are names or descriptions. It would be helpful if there were (non-alias) Name and Description types that could implement Walkable like the other AST types, and then you could implement visit_name, etc. (Sure, we could just call visit_name directly from each Walkable implementation for a type containing a name, but keeping the strict pattern of "each walk calls visit_* exactly once and then calls walk on its children" seems nice.)
  • It would be nice if some more of the Vec types were a struct like Directives, though I suppose implementing Walkable on Vec<Selection> isn't that much more awkward than implementing it on SelectionSet. I'm thinking SelectionSet and Arguments specifically.

It's possible I'm missing something and the status quo is pretty reasonable though.

It would be nice if apollo-compiler had some sort of built-in visitor API; maybe this one, maybe a more immutable one, maybe something else. Whether or not apollo-compiler adds such an API, this PR hopefully at least points out some potential improvements in the AST data types.

This visitor pattern is designed for doing normalizations on executable
documents, so it assumes you will mutate the tree as it is walked.
(Perhaps a better design would be to make each visitor return an object
of the type it is visiting (which could be the same object it received),
constructing a new tree (possibly sharing most of its data) immutably.)

This highlights some places where it would be helpful if the AST
contained more explicit types where it currently only has variants, type
aliases, or vecs. By having more little structs in the type system, it's
easier to write a visitor like this that can easily target (say) every
Name node. This includes:

- It would be helpful if all enums (which actually contain data, so not
  OperationType) had a specific type for each variant, so that visitors
  can choose to visit that variant specifically. Definition and
  Selection work this way already; Type and Value do not. This is
  especially helpful for Value, as it would be nice to be able to write
  visitors that visit just string values or int values or whatever
  without needing to match against the Value.
- Most uses of NodeStr in the AST are names or descriptions. It would be
  helpful if there were (non-alias) Name and Description types that
  could implement Walkable like the other AST types, and then you could
  implement `visit_name`, etc. (Sure, we could just call `visit_name`
  directly from each Walkable implementation for a type containing a
  name, but keeping the strict pattern of "each `walk` calls `visit_*`
  exactly once and then calls `walk` on its children" seems nice.)
- It would be nice if some more of the Vec types were a struct like
  Directives, though I suppose implementing Walkable on `Vec<Selection>`
  isn't that much more awkward than implementing it on `SelectionSet`.
  I'm thinking `SelectionSet` and `Arguments` specifically.

It's possible I'm missing something and the status quo is pretty
reasonable though.

It would be nice if apollo-compiler had some sort of built-in visitor
API; maybe this one, maybe a more immutable one, maybe something else.
Whether or not apollo-compiler adds such an API, this PR hopefully at
least points out some potential improvements in the AST data types.
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.

1 participant