-
-
Notifications
You must be signed in to change notification settings - Fork 670
Add Visitor Pass #727
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 Visitor Pass #727
Conversation
Currently
can run tests with `npm run test:packages`
Now `packages/d` will output it's trace of resolving files.
Now just runs and validates compilations and two packages use the two other commands.
- changed listFiles to return null if error - add path if package found
Imports added to backlog also include which file imported, meaning search starts from that file's perspective.
It compiles and can be loaded dynamically.
The first thing that comes to my mind here is that there's a concrete AST visitor in |
I started with the visitor in This would be a good opportunity to split up the pipeline into separate passes of visitors. This way we can have a type checking phase that can be done before compiling to binaryen. Also we could create an internal IR that is closer to Binaryen so that the final compilation to it is simple, while also allowing for higher level abstractions like classes. This will make it easier to write the IR by hand, which I've experienced when trying to create the |
Can you elaborate why you think that this is better? On a first glimpse, this looks like a less performant and less portable approach to do the same basic thing.
Currently we are reusing Binaryen's IR, which is about as close and simple as it can get. Adding another intermediate layer between the AST and Binaryen IR seems unnecessary to me, since one could directly use the Binaryen API instead. In a sense, the two representations we have are a) Stuff in TS and b) Stuff in Wasm, with the program elements sitting in between to keep the necessary state for high-level structures.
Would say that we'd want to do either integration with Binaryen or roll our own, the latter strictly requiring additional IR, but not both. Adding more IR than necessary, that then might significantly slow-down compilation and increase memory footprint, doesn't appear worth it. |
I don't understand how it's less portable. Because it uses interfaces and abstract methods?
situations like, // expressions
case NodeKind.FALSE:
case NodeKind.NULL:
case NodeKind.SUPER:
case NodeKind.THIS:
case NodeKind.TRUE:
case NodeKind.CONSTRUCTOR:
case NodeKind.IDENTIFIER: {
this.visitIdentifierExpression(<IdentifierExpression>node);
break;
} becomes solved by having the IdentifierExpression have the visit method, which all the subclasses will inherit. Furthermore, throughout visitLiteralExpression(node: LiteralExpression): void {
switch (node.literalKind) {
case LiteralKind.FLOAT: {
this.visitFloatLiteralExpression(<FloatLiteralExpression>node);
break;
}
case LiteralKind.INTEGER: {
this.visitIntegerLiteralExpression(<IntegerLiteralExpression>node);
break;
}
...... Here each subclass of LiteralExpression would implement the visit function making this: visitLiteralExpression(node: LiteralExpression): void {
this.visit(node);
super.visitLiteralExpression(node);
// This allows us to keep traversing since the base class traverses the ast. My main reason for this switch is readability and a more standardized way of doing passes over the ast/program. So in that vain the only thing that really matters is that there is a base visitor that you can extend that allows you to overwrite just the methods you want and still have a way to call I also would be very shocked if this impacted performance significantly as it only adds a small constant cost. Again as long as everything hinges on the use of the base class we can swap out the implementation with another. As for adding a new IR before binaryen; currently it's difficult to hand write IR with both higher level and lower level abstractions. For example, I'm currently trying to write the virtual method. function virtual(methodID: usize, classID: usize): usize {
//switch
} I had trouble writing the switch statement in the current AST, because it needed to resolve |
Closing this PR as part of 2020 vacuum as it seems to be outdated. Iirc there was a new suggestion to add a visitor to extra/ast meanwhile, which seems good to do as long as we can keep it reasonably simple. |
An abstract visitor method is added to each of the base abstract classes for a node in the ast and program element.
For example,
Subclasses
BaseVisitor
can overwrite the implementation ofvisitIfStatement
and continue to visit member nodes past it in the tree withsuper.visitIfStatement(stmt)
.I also added an AbstractVisitor class, which defines a polymorphic visit function. This function expects an input of a type `Collection:
This means it handles iterating through different types of collections.
The default visit function ignores null. So we can pass it possibly null references. This way the previous function can be rewritten:
Visitor classes must export their class as the default export. It is then constructed after the module in binaryen and passed the current parser and compiler.
The ultimate goal is to use the pass to add the interface/virtual table support.
fixes #702