-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Add hooks on some compilation phases #647
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
Conversation
I think this is a good direction to allow custom drivers (or later, perhaps, plugins) to register hooks in various places of the compiler. Some comments:
|
(In addition to the toplevel, syntactic hooks should probably be used for ocamldoc and ocamldep as well, no?) |
4c77951
to
21ac600
Compare
Thanks @alainfrisch for these comments.
In the new version, I moved the functor in
Actually, they were called rewriters in my former implementation, and I decided to rename them as most of them are not rewriters (they check something on the AST, and usually return directly their argument), in our current use cases.
Done.
In our current use-cases (for example, the
Actually, no, they are applied in the lexicographical order of their names... We usually use names such as
We have some analyses that checks some properties on the typedtrees (in SecurOCaml for example). As I said, they are not rewriters, but really hooks. Pierrick Couderc also has a type-checker for example, that verifies that inferred types are correct, that could be used that way. |
21ac600
to
c43c986
Compare
|
Concerning Parsetree rewriters, would this be subsumed by #386? |
IIUC this would require making a second About turning the |
utils/misc.ml
Outdated
let stop = loop 0 0 in | ||
Bytes.sub_string dst 0 stop | ||
|
||
exception HookExit of exn |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What the rationale for this HookExit, and the fact that any other exception terminates the compiler (or toplevel) immediately. I'd rather have fold_hooks
wrap the exception into another constructor that records the hook name, and let that new exception propagates as usual.
I see it the other way around. It's a coquetry to force code sharing (about 10 lines of code) when the various uses don't match exactly. The non-uniform API would document that we don't really support Typedtree rewriters (before someone come with a valid use case), only Typedtree "validators". In particular, ordering of validators doesn't really matter, contrary to rewriters. |
I don't see the point of adding extra lines to prevent a use, just because we don't have the idea yet. Often, the idea comes when the possibility is there. I will add the record if you think it is useful to document this parameter. |
Ok, I won't fight on that. |
I agree with @lefessan, I think it should be allowed. In particular, ppx annotations can allow to encode information in the typedtree that can be used by tools later on (documentation, etc). A typedtree rewriter would allow to do non-regular propagation of such annotations, without compromising the correctness of the typedtree. |
c43c986
to
6ef534c
Compare
utils/misc.mli
Outdated
lexicographical order of their names. | ||
*) | ||
|
||
exception HookExn of exn |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea is that a hook raising an exception is almost always an error, in which case it should be detected and caught immediately. However, in our experience, there are cases where you really want to raise an exception, that should go outside of the hook. Raising HookExn exn
is thus the correct way to raise an exception outside of the hook. For the error, I could indeed create an exception for that case, but in Misc
, there is currently no support for printing errors in the standard way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are designing a new API for external use, so let's make it as smooth as possible. One could simply register the wrapper constructor in Misc and record the printer somewhere else (e.g. in Location). I'd also use this wrapper, which would normally terminate the compiler, but not necessarily the toplevel.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I don't understand what you mean. Could you provide a patch for that ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
6ef534c
to
4504e48
Compare
Ping on that. There is a clear overlap between ppx registered in the process (originally designed for the toplevel) and Parsetree rewriters. Adding both APIs at the same time does not seem right. By the way, one should specify how ppx (provided on the command-line) and Parsetree rewriters are combined (which are applied first). |
Parsetree rewriters and ppx serve two different purposes, so there is no reason to link them. Ppx are for users, to extend the syntax of OCaml. Parsetree rewriters are for compiler devs, to easily extend the compiler (their own version of the compiler). Parsetree rewriters are applied once ppx have been applied and invariants checked. |
Especially with dynamically linked plugins, rewriters will certainly be used by "external" users. One can say they become de facto "compiler devs" if they inject code in the compiler, but the line between ppx and Parsetree rewriters is really not clear to me. Typically, one might want to link a custom compiler driver with built-in ppx. Should this be done with Parsetree rewriters or in-process ppx from the other PR? Also I don't see why Parsetree rewriters should be run after Parsetree invariants are checked. These invariants are assumptions made by the type-checker and the check could detect mistakes in the rewriter. I don't see a good reason for allowing Parsetree rewriters to break those invariants. |
The rationale for checking invariants before was that internal rewriters were supposed to work on a correct parsetree, but indeed, they could be applied before, so that they would be able to add syntax extensions as ppx do. |
If there is no more opposition, and as it was reviewed by Alain, I will merge by the end of the week. |
Just to clarify, this is like inserting an API at every compiler layer. Will this inhibit development of said layers? My thinking is that we cannot let considerations about plugins that chose to use unstable interfaces such as these slow down compiler development / refactoring, meaning that the policy should be that it's the plugin authors' problem, but I'd like to hear what others have to say about this point. |
@bluddy I think that there is a consensus on this, yes, using these hooks exposes your code to unstable interfaces, as using the compiler-libs in general. But that's the same thing for ppx, that work on the AST, that is changing all the time... |
It is worth noting that ppx has been a complete nightmare due to the absence of even a remotely stable interface. This has led to a proliferation of code that is costly to maintain. It hasn't directly slowed down compiler development, but it has indirectly: some people who would otherwise have been working on the compiler have been spending time fixing ppx rewriters. It would be nice not to get ourselves into that position again for something else. This is not to say that rewriters aren't a good idea, but if they become commonplace---which tends to be the case when things like this get into the wild---they might start imposing a burden. |
My understanding is that |
@mshinwell, do you have any insight into what the main required fixes were to your (I guess Jane Street's) ppx rewriters? The shape of the AST stays mostly the same from version to version, with only the minor details changing. Would smart constructors have helped? Is it mostly a destructing (matching) problem, where pattern views might have helped? |
I think Mark was talking about Pierre Chambart, who is spending a lot of time upgrading ppx to work with trunk, to be able to benchmark his modifications to flambda with a lot of opam packages. One of the problems is probably that, if you update version 1 of |
I wasn't talking about Pierre actually, but yes, I think he did in fact suffer from this too. We spent a lot of peoples' time at Jane Street over the past few months on various ppx-related changes due to changes in the parsetree, etc. Some form of smart constructors / a generally better interface for building the parsetree might help. The problems are not limited to destruction. It is possible we may work on that at some point, but we cannot commit to it at present. |
e9f7ac6
to
d9f43d7
Compare
…m instead of stopping the process.
I think I replied to all requests for modifications, and Appveyor has its own problems, so merging |
Add hooks on some compilation phases
Improving Multicore's issue template
This PR add hooks in the compiler that can be filled by custom drivers (or by a forthcoming PR adding plugins to ocamlc/ocamlopt):