Conversation
gasche
left a comment
There was a problem hiding this comment.
Thanks!
The code looks very reasonable to me.
Do I correctly understand that the current handling of "transform intersection" forbids having a warning/error location that contains an ellipsis? Isn't that something that we could want to have in the future? If yes, and you see a way to enable it that is not too much work, maybe that could be nice.
(I regret not trying to merge #1209 earlier because we are giving ourselves more rebase work by having one giant PR instead of merging whatever is ready when it's ready.)
manual/manual/refman/exten.etex
Outdated
| \begin{verbatim} | ||
| module type DEVICE = sig ... end | ||
| \begin{caml_example*}{verbatim} | ||
| module type DEVICE = sig [@@@ellipsis.start][@@@ellipsis.stop] end |
There was a problem hiding this comment.
Couldn't just [@@@ellipsis] work here?
There was a problem hiding this comment.
Yes, I was too focused on having tests for [@ellipsis.start]...[@ellipsis.end].
manual/manual/refman/exten.etex
Outdated
| let module M = struct exception E of t end in | ||
| (fun x -> M.E x), (function M.E x -> Some x | _ -> None) | ||
| \end{verbatim} | ||
| \end{caml_example*} |
There was a problem hiding this comment.
This environment change and the one below look like they are likely to conflict with #1209 for no very good reason.
There was a problem hiding this comment.
True, I will remove them. (I could also remove all changes to exten.etex since they are more here as an example than anything else.).
| | "ellipsis" -> | ||
| transforms := | ||
| { Text_transform.kind=Ellipsis; start; stop= max attr_stop stop } | ||
| :: !transforms |
There was a problem hiding this comment.
Shouldn't you check that left_mark is not active to guarantee the absence of nested ellipses?
There was a problem hiding this comment.
Possibly. However, this case is already caught later by check_partition. I will think a bit about this independence problem.
There was a problem hiding this comment.
I have added a test in order to catch nested ellipsis early in all cases (which makes the the test for unmatched stop/start simpler).
I added the possibility of eliding strict subset of underlined interval. The complextity increase seems moderate. |
gasche
left a comment
There was a problem hiding this comment.
Good to go, but I think that a Changes entry could be nice. I plan to cherry-pick into 4.07 as well, to be able to use it in the 4.07 manual.
|
I added the change entry in the 4.07 section. |
manual: ellipses in examples (cherry picked from commit 7398fd2)
| let left_mark = ref None (* stored position of [@@@ellipsis.start]*) in | ||
| let location _this loc = | ||
| (* we rely on the fact that the default iterator call first | ||
| the location subiterator, then the attribute subiterator *) |
There was a problem hiding this comment.
On reviewing I didn't think much of this assertion, but upon usage I see bugs caused by the fact that it is wrong. For example the following does not behave correctly:
module type DEVICE = sig val draw : picture -> unit[@@ellipsis] endThe ellipsis should elide the whole signature item val draw ..., but it only elides the unit part, because location iterators are called in the wrong order.
The mismatch can be found in the sources of ast_iterator.ml:
module_type_declaration =
(fun this {pmtd_name; pmtd_type; pmtd_attributes; pmtd_loc} ->
iter_loc this pmtd_name;
iter_opt (this.module_type this) pmtd_type;
this.attributes this pmtd_attributes;
this.location this pmtd_loc
);(My first idea on how to fix it turned out not to work, so I'm not sure of what's the best fix. It may be to special-case the situations in which we support the ellipsis attribute as we can reliably extract locations, and fail on the others, for now.)
There was a problem hiding this comment.
I should have indeed checked more carefully this assertion. If you find the fix too time consuming, please do not hesitate to ping me.
There was a problem hiding this comment.
In fact I am currently under the impression that there is no nice fix that does not touch ast_iterator (which would be the condition to go into 4.07). I started writing the following
let located_attributed_iterator located_attribute =
let open Ast_iterator in
let super = default_iterator in
let rec this = {
super with
structure_item = (fun this ({pstr_loc = loc; pstr_desc = desc} as si) ->
begin match desc with
| Pstr_eval (_, attrs) -> located_attributes loc attrs
| Pstr_extension (_, attrs) -> located_attributes loc attrs
end;
super.structure_item this si;
);but the idea of having to extend with definition with all the cases under the sun is killing me, and I don't think this is the right approach.
I would be tempted to revert the ellipsis stuff from 4.07, because I don't like the idea of releasing something that we know is broken. Then for trunk we can discuss either:
- fixing the Ast_iterator control flow (but then I realized that some things have attributes but no locations, so we would probably need to change Parsetree as well if we want to enforce the invariant that all attributable things are located. This is the right thing to do, but it is bound to be long, painful, and break user code.)
- and/or using extension points instead of attributes (that was actually my very first interface idea).
There was a problem hiding this comment.
@Octachron I'll wait until you confirm that you agree there is no simple/easy fix here before reverting.
There was a problem hiding this comment.
Reading more carefully ast_iterator, I found only 7 exception to the location; attribute pattern:
- iter_type_extension
- iter_structure_item
- iter_signature_item
- value_description
- module_declaration
- module_type_declaration
- module_binding
My biased opinion is that writing a custom iterator rewriting those part would be ugly but acceptable.
There was a problem hiding this comment.
See this commit for some ugliness quantification.
Concerning your other points, extension nodes were my second idea after pseudo-latex macro; but I found that attribute were the right interface at the user level since there is nothing special going at the code level, and this is really a meta-information. I think it is worth it to try to support this interface.
In term of maintenability, would it be a bad idea to move (on trunk) the tuned iterator to parsing/ast_iterator.ml as another variant of ast iterator?
For the attributable items that need a more precise location, I noted attribute locations polymorphic variant and object tag, exceptions. This seems like a small set which could be fixed at an ulterior date.
At least, this my opinion on the spot, I would rethink the issue tomorrow.
|
I still think that using extension points would be better here. Even with we fix a handful of cases of the iterator, we still have the problem that some attributes are not located, so the technology cannot be correct without parsetree changes, and I don't really like that. (Although we can fix the attribute locability in trunk later.) |
|
Ok, I will write a PR that switch to extension nodes. |
|
Another point to put in the balance, that I forgot before starting the extension node implementation, is that some extension nodes do not have a corresponding payload: typically node extension can replace class expression, class field or module types; but payloads are either structure, signature or patterns. class c = object [%ellipsis method m = ( ) ] endis invalid due to the payload, and the closest valid option would be class c = object [%ellipsis object method m = ( ) end ] end |
As suggested in #1209, this PR proposes to add the ability to elide some of the content in the
caml_examplecode examples. More precisely, term annotated by[@ellipsis]or between[@ellipsis.start]and[ellipsis.stop]are replaced by\ldots(i.e.…):becomes
in the manual text.
As an illustration, I translated the locally abstract type section of the extension chapter to
caml_examplesand one of the verbatim examples in the section on first-class modules.This PR also adds a notion of textual transformation to
caml_tex2and checks that no transformation applies to intersecting text fragment. Consequently, it is not possible to elide a part of an example which raises a warning or an error.