Skip to content

expose Pprintast.longident#1996

Merged
gasche merged 5 commits intoocaml:trunkfrom
gasche:Pprintast.longident
Aug 25, 2018
Merged

expose Pprintast.longident#1996
gasche merged 5 commits intoocaml:trunkfrom
gasche:Pprintast.longident

Conversation

@gasche
Copy link
Copy Markdown
Member

@gasche gasche commented Aug 20, 2018

This is a continuation of #1918 (Longident.to_string) with a different implementation approach suggested by @Octachron and @jberdine.

(I haven't updated the Changes yet, but a review would still be welcome.)


type lid = Longident.t loc
type str = string loc
type 'a with_loc = 'a Location.loc
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this suggest that 'a Location.loc would be better named 'a Location.with_loc? (but changing that now may be not worth the hassle..)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes?

@Octachron
Copy link
Copy Markdown
Member

The hardening against empty identifiers in 360b867 makes me wonder if this should be an AST invariant. Except this point, I think that this the right minimal change.
(p.s. I am not sure if the inclusion of #1903 changes is intentional?)

val structure: Format.formatter -> Parsetree.structure -> unit
val string_of_structure: Parsetree.structure -> string

val longident : Format.formatter -> Longident.t -> unit
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that longident could be at the top rather than the bottom of the interface since it prints simpler items.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do -- the order in the other declarations is not the one you suggest, so I will reorder everything.

[@@@ocaml.doc{|
To print a longident, see {!Pprintast.longident}, using
{!Format.asprintf} to convert to a string.
|}]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was there a problem with a documentation comment here ((** ... *)) ?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't sure that I would get the right comment-by-itself behavior with just newlines, so I thought that this more explicit syntax would be better. Do you think I should change back?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so: I just realized that the right attribute was ocaml.text and not ocaml.doc. A newline should be fine (and checking with -dsource works well).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch... I just changed it.

[`A of & T1 & .. & Tn] ( true, [T1;...Tn] )

- The 2nd field is true if the tag contains a
- The 3rd field is true if the tag contains a
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now it is actually the 2nd field.

| Psig_extension (x, attrs) ->
sub.extension sub x; sub.attributes sub attrs
sub.attributes sub attrs;
sub.extension sub x
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if there are consequences to this order change, but it is more consistent with other cases after this change.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is to have .attributes come right after .location for all AST nodes, so that you can know when you process an attribute the location of its whole attached node (attribute included) by an ugly side-effect. See #1765. This is fragile of course, and would like a better long-term way to do it.

@gasche
Copy link
Copy Markdown
Member Author

gasche commented Aug 20, 2018

Sitting on top of #1903 is unintentional, sorry. @jberdine, I think that the bits you reviewed come from #1903. (Thanks! I will make the change there.)

@gasche gasche force-pushed the Pprintast.longident branch from 360b867 to 106b048 Compare August 20, 2018 17:46
@gasche gasche mentioned this pull request Aug 20, 2018
@gasche gasche force-pushed the Pprintast.longident branch from 106b048 to 256e6e3 Compare August 20, 2018 18:02
@gasche
Copy link
Copy Markdown
Member Author

gasche commented Aug 21, 2018

(I rebased the PR.)

Line 1, characters 25-33:
let last_ident = L.last (L.lident "foo")
^^^^^^^^
Error: Unbound value L.lident
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error does not seem intentional?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, sorry. I just reworked the tests and rebased.

@gasche gasche force-pushed the Pprintast.longident branch from 256e6e3 to a7a0abf Compare August 21, 2018 16:53
Copy link
Copy Markdown
Member

@Octachron Octachron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes look good to me.

let parse_complex = L.parse "M.F(M.N).N.foo"
[%%expect {|
val parse_complex : L.t =
L.Ldot (L.Ldot (L.Ldot (L.Ldot (L.Lident "M", "F(M"), "N)"), "N"), "foo")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"F(M"), "N)" really? Yirk.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missed that, but yes Longident.parse only parses the subset of Longident without application.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you (or @gasche) comment on what you think should be done then?
Should we change Longident.parse? Should we remove the test? Add a comment on the test?

Note that a few lines below we're converting back that broken Longident to a string, and everything looks "fine". I don't think we should do that.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I think that Longident.parse should be fixed to be complete. In fact I hadn't really looked at the test output (otherwise I would have said something here); this continuing experience of surprises makes me half-glad half-sorry that I insisted on writing unit tests for compiler-libs feature.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Going down this rabit's hole, making Longident.parse complete also means udapting the call in makedepend.ml and typemod.ml to reject applications in -open arguments .

Copy link
Copy Markdown
Member

@damiendoligez damiendoligez Nov 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An intermediate fix would be to make Longident.parse fail upon seeing a parenthesis.

[edit] better yet, make it check that the components are valid identifers.

Copy link
Copy Markdown
Member

@Octachron Octachron Nov 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think an option returning version might be better since in the two current use cases of Longident the error handling should be specialized:

  • In Typemod, the compiler should warns that -open F(X) is not valid (should the input be validated earlier?)
  • in toplevel/genprintval.ml, the extension printer should abort the search for extensions constructor to handle cases like
module F(X:sig end) = struct type t = .. type t+= A end
module E = struct end
let x : F(E).t = let module M = F(E) in M.A;;
val x : F(E).t = <extension>

( currently, the printer searches for a module Lident F(E) and fails)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Typemod, the compiler should warns that -open F(X) is not valid

That won't stay true for very long: I'm about to send a refreshed version of the "extended open" PR which allows this.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm about to send a refreshed version of the "extended open" PR which allows this.

I think that's only true for .mli files, for .ml files you probably still need a warning.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, would it not be simpler to expose the corresponding parser rule (module_expr?) from the parser and use constr_longident for the extension printer?

@gasche gasche force-pushed the Pprintast.longident branch 2 times, most recently from f9c67fe to eef31c5 Compare August 23, 2018 19:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants