On 7/27/23 19:27, Eric Blake wrote:
> On Thu, Jul 27, 2023 at 01:54:25PM +0200, Laszlo Ersek wrote:
>> On 7/26/23 19:50, Eric Blake wrote:
>>> Use Go-preferred whitespace: TAB for indent, and no space before
>>> opening '(', better use of blank lines.  These changes reduce the size
>>> of a diff produced by gofmt, although there are still other places
>>> where we are not idiomatic in what we generate (mainly in lining up
>>> columns of = in const() blocks).
>>>
>>> Signed-off-by: Eric Blake <ebl...@redhat.com>
>>> ---
>>>  generator/GoLang.ml | 244 ++++++++++++++++++++++----------------------
>>>  1 file changed, 123 insertions(+), 121 deletions(-)
>>
>> Unfortunately:
>>
>> - This must have been an incredible amount of work for you.
> 
> Some automation involved (emacs macros are nice), but yeah, it's
> grunt-work.
> 
>>
>> - The many \t escape sequences make the generator source code harder to
>> read.
> 
> Agreed.  Maybe a better approach would be figuring out an optional
> argument to pr to insist on TAB instead of space indent?  Or, as
> mentioned elsewhere, not bothering with TAB at all in OCaml but
> instead figuring out how to run gofmt itself as part of the generation
> pipeline.
> 
>>
>> - This patch depends on patch#4 (minimally), so if you modify that one
>> like I've asked, it will create a conflict for this patch. :(
> 
> Yep, I've already encountered a number of conflicts as I shuffle
> around patches, trying to pick out which changes are more than just
> whitespace (such as the RBool change).  Not terribly difficult, but
> back in the grunt-work category.
> 
>>
>> Acked-by: Laszlo Ersek <ler...@redhat.com>
>>
>> Thanks
>> Laszlo
>>
>>>
>>> diff --git a/generator/GoLang.ml b/generator/GoLang.ml
>>> index 77dacadb..a38aa19f 100644
>>> --- a/generator/GoLang.ml
>>> +++ b/generator/GoLang.ml
>>> @@ -175,6 +175,7 @@ let
>>>  let print_binding (name, { args; optargs; ret; shortdesc }) =
>>>    let cname = camel_case name in
>>>
>>> +  pr "\n";
>>>    (* Tedious method of passing optional arguments in golang. *)
>>>    if optargs <> [] then (
>>>      pr "/* Struct carrying optional arguments for %s. */\n" cname;
>>> @@ -182,10 +183,10 @@ let
>>>      List.iter (
>>>        fun optarg ->
>>>          let fname = go_name_of_optarg optarg in
>>> -        pr "  /* %s field is ignored unless %sSet == true. */\n"
>>> +        pr "\t/* %s field is ignored unless %sSet == true. */\n"
>>>            fname fname;
> 
> I tried:
> 
>     +        pr "\t" ^ "/* %s field is ignored unless %sSet == true. */\n"
>                fname fname;
> 
> File "GoLang.ml", line 186, characters 8-15:
> 186 |         pr "\t" ^ "/* %s field is ignored unless %sSet == true. */\n"
>               ^^^^^^^
> Error: This expression has type unit but an expression was expected of type
>          string
> 
> and:
> 
> File "GoLang.ml", line 186, characters 11-71:
> 186 |         pr ("\t" ^ "/* %s field is ignored unless %sSet == true. */\n")
>                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> Error: This expression has type string but an expression was expected of type
>          ('weak2 -> 'weak3 -> 'weak4, unit, string, unit) format4 =
>            ('weak2 -> 'weak3 -> 'weak4, unit, string, string, string, unit)
>            CamlinternalFormatBasics.format6

Sigh. :/

"pr" is declared like this [generator/utils.mli]:

  val pr : ('a, unit, string, unit) format4 -> 'a

The format string would normally be converted to a "format4" type, which
is a polymorphic type, taking one type variable ('a).

It seems that this automatic conversion/construction, from string to
format4, is performed by a mechanism that is similar to
"Stdlib.format_of_string":

  https://v2.ocaml.org/api/Stdlib.html#1_Operationsonformatstrings

There are two catches however:

- Stdlib.format_of_string only works with string *literals*, according
to the documentation,

- Stdlib.format_of_string produces a format6, not a format4.

The documentation recommends "Scanf.format_from_string":

  https://v2.ocaml.org/api/Scanf.html#VALformat_from_string

so you could *theoretically* do something like

  printf (Scanf.format_from_string ("%d " ^ "%d\n")) 1 2

it still doesn't work though, because Scanf.format_from_string also
produces a format6 (like Stdlib.format_of_string does), but printf
expects a plain "format" (similarly to how "pr" expects "format4", i.e.,
*not* format6).

So this appears unsolvable. "Scanf.format_from_string" produces a
format6, which takes six type variables, but "pr" expects "format4",
which is much less generic:

  type ('a, 'b, 'c, 'd) format4 = ('a, 'b, 'c, 'c, 'c, 'd) format6

We'd have to find a way to "narrow" the format6 produced by
"Scanf.format_from_string" into a format4, and I don't think that's
possible (the parameters are not values but types). And I couldn't find
a Printf module function that took a format6.

Ultimately open-coding the \t escape sequences seems the least intrusive...

> 
> so those are non-starters.  We can get more verbose with:
> 
>     +        pr "\t";
>     +        pr "/* %s field is ignored unless %sSet == true. */\n"
>                fname fname;
> 
> but that may not scale as nicely.  Go's use of TAB does not specify
> what tabstop it prefers;

well that I find unfathomable; how can any coding style mandate TABs for
indentation if it doesn't explain how wide a TAB should be? For example,
that makes "maximum line width" mostly impossible to define.

> our .editorconfig suggests using a tabstop of
> 4 (instead of the usual 8) when reading a .go file for less visual
> distraction, and which matches with GoLang.ml currently using 4-space
> indentation.
> 
> Rich, do you have any ideas on any better approach to take here?
> 
>>> -        pr "  %sSet bool\n" fname;
>>> -        pr "  %s " fname;
>>> +        pr "\t%sSet bool\n" fname;
>>> +        pr "\t%s    " fname;
> 
> I also debated about splitting this patch into two (yes, more
> gruntwork): one to address space before '(', and the other to address
> leading indentation.  Lines like this would be touched by both
> patches if I split.
> 

I wouldn't insist on such a split. :)

Laszlo
_______________________________________________
Libguestfs mailing list
Libguestfs@redhat.com
https://listman.redhat.com/mailman/listinfo/libguestfs

Reply via email to