-
-
Notifications
You must be signed in to change notification settings - Fork 75
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
Add generic AstVisitor #370
base: main
Are you sure you want to change the base?
Add generic AstVisitor #370
Conversation
Although I've only got to take a quick look at the proposal yet, I have doubts because making virtual methods generic doesn't usually come without a cost: Esprima.Benchmark.VisitorBenchmark
I like the idea in general but don't like the idea of taking the perf. hit in cases where reference return values are enough (or returns are not needed at all). And to me, this seems the (much?) more frequent case. I can't really see too many use cases which need value type returns. But maybe it's just my ignorance as e.g. Roslyn probably doesn't provide a non-generic and a generic visitor implementation with parallel non-generic and generic Such a parallel solution would solve the perf. issue but would add to our maintenance burden significantly. Thinking of which, I don't really like this idea either... Adding a generic But it's also worth noting that there may be other viable ways to handle this problem, for example object pooling. These are my first thoughts. @lahma @jogibear9988 How about you? |
Huh, I didn't know that it would have this much of an impact on the performance. Good catch. I always thought that a generic method would "magically" create a new method with the generic types and having the same(ish) result. I tried to change to make the final class sealed, and change the abstract class to an interface but both had the same performance hit. I agree that the performance hit is too much for this to be merged, and having to maintain two methods (on every node) for both visitors isn't ideal either. Alternatively we could create a source generator which
But this is also more code to maintain which brings the question if it's worth it. |
What if there is a generic version and a non generic one that inherits from the |
Next time I will read the PR before commenting |
Thank you @adams85 for reviewing and checking the perf impact! I think we need to be very careful in this regard as a lot of the esprima 3 (vnext) effort has been around performance (and of course features and fixes). I'd say @adams85 is the best person to give feedback on design as he's been the driving for around AST visitors (thank you for that!). I'm trying to understand the use case here. If it's about crafting an interpreter, maybe that should be a separate part - just like Jint is built on top of the esprima AST and does the JavaScript interpretation. So in that way there's no need to "transform" return values. |
for me the perf hit does not matter, cause I only use esprima.net to parse and rewrite javascript files once during application startup. |
Thank you all, guys, for sharing your opinions. They certainly helped my thought process.
I can imagine a use case where you just want to evaluate some simple JS expressions (maybe only a very limited subset of what the language allows). I did something similar in my PO parser library. (Though that one doesn't evaluate the expression but transforms it into a compiled lambda expression.) Anyway, the point is that such simple transformations wouldn't really require more than a visitor. And when you evaluate e.g. numeric expressions, it'd be nice to be able to return a value type to avoid boxing.
This is a nice idea, definitely worth exploring! I haven't had the time to delve into it but I suspect that a bunch of visitor-related boilerplate code could be generated. I think of stuff like
There are a few special cases here and there but the whole thing follows a pretty solid pattern. We'd need to annotate our AST nodes to let the generator know which are the child properties, what is the default order of their visitation and probably a few other pieces of relevant information and we could generate about 90% of what I enumerated above. Handcrafting the remaining bits wouldn't be a big deal then. In that case adding a generic version of The main problem is that implementing such a generator is quite a task... But I'm sure it'd be pretty damn exciting as well. So I may be not able to resist to give it a try. :) Of course, if anyone else has intentions like this, just let me know. |
I know, took the idea of using PO for localization from Orchard (from the "original", not the Core version). 😄
Thanks for the tip. Looks like a nice lib, I'll take a closer look! |
FYI, this is possible now: #372 Do you feel like rewriting your PR based on this maybe? |
This PR adds a generic AstVisitor (
AstVisitor<T>
).This allows value types to be returned without boxing, for example a
double
to make a simple calculator:esprima-dotnet/test/Esprima.Tests/AstVisitorTests.cs
Lines 105 to 141 in 977356b
AstVisitor
extendsAstVisitor<object?>
so it's still possible to use inheritAstVisitor
without making a breaking change.