Allow toplevel value to be used for preprocessing#386
Allow toplevel value to be used for preprocessing#386Kakadu wants to merge 8 commits intoocaml:trunkfrom
Conversation
|
cc @diml @whitequark @alainfrisch : what do you think? |
|
I acknowledge the usefulness of such a feature (even without js_of_ocaml!), but I have a few concerns. The main one is that we will have two distinct ways of adding a ppx. How do they interact with each other? This is especially important, given that I think I'd like to see ocamlfind activating extensions like this. The minor ones are that the messages are inconsistent with the behavior of I propose to rename |
a685a87 to
b15f556
Compare
At the moment toplevel applies all external ppx preprocessors and ad-hoc preprocessors after that. Demo output looks like this:
Maybe
I like that I am able to enable/disable source output when I want it. Also, |
That's completely uninformative.
Did you mean I still really dislike that we have two completely independent ways of applying ppx extensions. How about refactoring the codepath behind |
You can still do that if using |
|
Yeah,
I will take a look |
|
I share all @whitequark's comments. Having a single set of ppxs to be applied (with two different calling modes) seems much better. Cookies should be properly threaded between all of them (they can be used to pass information from one to the other). Instead of taking a Ast_mapper.mapper value, one could consider relying on the registration mechanism in Ast_mapper, i.e. simply load a .cmo/.cma file implementing the ppx logic and registering the mapper through Ast_mapper.register, and then use a toplevel directive with string argument(s) to refer to registered mapper (and pass them arguments). This would make it easier to reuse existing code of ppx that don't necessarily export the mapper value. |
|
Folks, do you think that changing type clflags.mli to will be bad idea? |
Yes, indeed. I'd find much better to keep using Clflags.all_ppx to represent command-line parameters and introduce another list (e.g. in Pparse) to represent the two possible kinds of ppx calling mode. There, instead of Obj.t, you could directly refer to the actual type of mapper (or just a local record of mapping functions). |
|
Note that it should be possible to give the two kinds of ppx the same type by using a GADT and existential packing. You should be able to reuse the type 'a ast_kind that I developped (not merged in trunk) for #351 (note: I'm interested in feedback on this PR): type ppx_transform = Ppx_val : 'a ast_kind * ('a -> 'a) -> ppx_transformHaving a single sequence of ppx transformers (even if some are skipped dynamically when processing a certain kind of ASTs) would make it easier to ensure that the pass ordering is preserved. |
|
I'm not sure to see what you mean with the existential. Registered PPXs all have to support both kinds of AST types (signatures/structures), not only one of them. (Well, technically, in the context of the toplevel, in-process mappers don't need to deal with signature, but let's be more general to allow linking special compiler drivers with built-in mappers.) The two kinds of PPXs are those implemented by an external command (which can be abstracted as "string -> string -> unit", the two strings representing the input and output files) and those implemented by an in-process mapper (of type Ast_mapper.mapper). |
|
I think the name should be |
acf5fab to
53698ed
Compare
|
Okay.
|
|
Looks good to me otherwise--though there are a few leftover changes from the rebase ( |
|
I probably should rebase everything after release of 4.03... |
Are you reading outdated diff, @whitequark ? Don't see anything like that. |
|
@Kakadu I was reading individual commits. |
|
It seems fine to me -- sorry for not replying earlier. In general, with GADT-based APIs, when the code type-checks then it is also reasonable code. (In the same way, patches over the new GADT-based format implementations are much easier to review because type-checking gives much stronger confidence in their correctness than before.) |
From now on Clflags.all_ppx only stores options after parsing command line arguments. Some values are exposed in pparse.mli to manage PPX preprocessors: val clear_ppx : unit -> unit (* disable all ppxs *) val add_external_ppx : path:string -> unit (* Add PPX specified by command line option *) val add_in_process_ppx : Ast_mapper.mapper -> unit (* Add ast mapper specified in the toplevel *)
Add directives to remove in-process ppxs by path.
1) External PPX don't cause any additional IO. 2) Tool name is set when applying in-process PPXs. Also slightly rewritten code related to applyign rewriters: function for applying on structures and signatures merged into single one.
|
Can we do one more iteration of review? |
|
I'm not making decisions on this PR (I'm not qualified), and would rather delegate to @alainfrisch and @whitequark that seems to have opinions about it. They seem rather "meh" on the proposal for now, and I don't think we would merge before a somewhat more enthusiastic consensus emerges. |
|
Not much has changed from my POV:
|
|
I haven't reviewed the new implementation, but I still need to be convinced about the usefulness of unloading a ppx. You'd typically set up your REPL environment (loading libraries, registering printers, and now installing in-process ppx) after startup and then use it for the current session. What would be a typical use case for unloading a ppx? |
|
Latest comments from @whitequark and me were left unaddressed for more than 1Y. I suspect the OP lost motivation to push the proposal forward, so I'm close this PR for now. |
Print aliases for debug. Various improvements * Use `Coercion.t` rather than `Coercion.t option` in many places * Use `Rec_info.t` again where sensible (in making inlining decisions, for instance), but redefine it as `unit` pending the next phase of `Rec_info` overhaul * Add simple `int` fields to `Coercion.t` for changing recursion depth; this is simpler than what we'll actually need but specific enough that we can test meaningfully (e.g., we can tell whether coercions are composed in the right order) Address a CR Update .depend Overhaul Aliases_of_canonical_element; add Alias_set Also return Bottom from more places (generally anything involved in a meet). Use Rec_info.unknown instead of unit Add comments; simplify `Aliases` API a bit Revert (most of) "Overhaul Aliases_of_canonical_element; add Alias_set" This reverts the parts of commit 9816841 that have been split off into PRs ocaml#383 and ocaml#386, as well as the Bottom stuff (likely to be unnecessary as we're considering making `Coercion.compose` a total function).
Print aliases for debug. Various improvements * Use `Coercion.t` rather than `Coercion.t option` in many places * Use `Rec_info.t` again where sensible (in making inlining decisions, for instance), but redefine it as `unit` pending the next phase of `Rec_info` overhaul * Add simple `int` fields to `Coercion.t` for changing recursion depth; this is simpler than what we'll actually need but specific enough that we can test meaningfully (e.g., we can tell whether coercions are composed in the right order) Address a CR Update .depend Overhaul Aliases_of_canonical_element; add Alias_set Also return Bottom from more places (generally anything involved in a meet). Use Rec_info.unknown instead of unit Add comments; simplify `Aliases` API a bit Revert (most of) "Overhaul Aliases_of_canonical_element; add Alias_set" This reverts the parts of commit 9816841 that have been split off into PRs ocaml#383 and ocaml#386, as well as the Bottom stuff (likely to be unnecessary as we're considering making `Coercion.compose` a total function).
Print aliases for debug. Various improvements * Use `Coercion.t` rather than `Coercion.t option` in many places * Use `Rec_info.t` again where sensible (in making inlining decisions, for instance), but redefine it as `unit` pending the next phase of `Rec_info` overhaul * Add simple `int` fields to `Coercion.t` for changing recursion depth; this is simpler than what we'll actually need but specific enough that we can test meaningfully (e.g., we can tell whether coercions are composed in the right order) Address a CR Update .depend Overhaul Aliases_of_canonical_element; add Alias_set Also return Bottom from more places (generally anything involved in a meet). Use Rec_info.unknown instead of unit Add comments; simplify `Aliases` API a bit Revert (most of) "Overhaul Aliases_of_canonical_element; add Alias_set" This reverts the parts of commit 9816841 that have been split off into PRs ocaml#383 and ocaml#386, as well as the Bottom stuff (likely to be unnecessary as we're considering making `Coercion.compose` a total function).
A `Name.Set.t` or `'a Name.Map.t` is a fine thing, but a `Simple.Set.t` or `'a Simple.Map.t` is much sketchier, since whether we want to treat two simples that differ only in `Rec_info.t` as equivalent depends on context. Fortunately, we usually just need a set or map of names. The one place where this gets tricky is in the uses of `Aliases.get_alias`, so there's now `Aliases.Alias_set.t` to encapsulate the needed operations.
Signed-off-by: Christine Rose <professor.rose@gmail.com>
I was building a custom js_of_ocaml toplevel recently and I needed to embed PPX syntax extension. By default it uses system call to invoke preprocessor which doesn't suite js_of_ocaml. The patch allows toplevel values of type
Ast_mapper.mapperto be used while preprocessing the source.P.S. Happy New Year :)