-
Notifications
You must be signed in to change notification settings - Fork 67
Ffigen transformer refactor #1259
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
Comments
Some notes on the transformer pattern. |
I was planning to let the transformer support AST node deletion, but I don't think it really makes sense in practice. Most of the children of our AST nodes are not optional (eg fields in a struct or arguments in a function). So I found myself inserting loads of The only use case we have for node deletion is applying the user's filters to the AST. But we also bypass those filters for transitive dependencies. So the filtering isn't actually recursive. We apply the filters to the top level list of bindings, then everything transitively depended on by the bindings that pass the filters are included regardless of the filters. So the filters don't need any sort of recursive traversal of the tree, and would be better implemented outside of the transformer infrastructure. |
Ran into a fun DS&A problem. The transform is a DFS, so we need to track whether the nodes are visited. T transform<T extends AstNode>(T node) {
if (_seen.containsKey(node)) return _seen[node] as T;
final result = node.transform(_transformation) as T;
_seen[node] = result;
return result;
} Since there are cycles in the graph, we need to mark the node as visited before recursing into it (to avoid infinite loops). But the transformation is allowed to return a different node, so what do we put in the T transform<T extends AstNode>(T node) {
if (_seen.containsKey(node)) return _seen[node] as T;
_seen[node] = ???;
final result = node.transform(_transformation) as T;
_seen[node] = result;
return result;
} We could insert a sentinel value, but then anyone hitting the But we're still left with the issue of what do we actually return in the
|
This is a good refactor to do regardless of this issue.
I don't have a preference for how ffigen wants to internally do things, but if you want to expose these APIs to the user, I'm in favor of this option. I prototyped this back when I was working on jnigen transformations as well – I'm not sure if you remember our discussions from like a year ago! We want to expose a very limited set of things that the user can do, and a mutable data structure + visitor allows exactly that. |
For handling cycles you could "color" the node grey when you enter and black when you finish visiting. But maybe I don't understand the exact problem you're facing. So in your case you'd have both a |
Yeah, that'll let me detect the cycle and avoid infinite loops, and for visitors that's enough (actually for visitors I think I can just color the node black before I visit it). But if I'm going with a real transformer, where the transformation can produce a different node, it's not clear what the |
OK I read your comment again and got it now! It's 4 am here so my brain is not quite braining anymore. Makes sense, the AST we transform should be afterall a T! |
Remaining minor cleanups:
The important stuff is done, so I'll remove this issue from the v16 milestone. |
As ffigen has developed we've gradually added more and more complexity to the
addDependencies
andtoBindingString
methods of the bindings classes. We should add a transformation step to the pipeline, beforeaddDependencies
, and move any logic that modifies the AST into this step.It will probably be cleanest to have multiple separate transformations, rather than one big one. So we'll use a similar transformer pattern to the Dart CFE. This will also allow custom transformation steps in future. We'll probably also need to formalize/cleanup the AST representation a bit.
1: Clean up AST
2: Write transformer boilerplate
3 to N: Add a seperate transformer implementation for each of the AST modifying actions that currently happens in
addDependencies
andtoBindingString
. Could probably also port addDependencies to a transformer/visitor.The text was updated successfully, but these errors were encountered: