#########################################################################
#                                                                       #
#                                 OCaml                                 #
#                                                                       #
#       Nicolas Pouillard, projet Gallium, INRIA Rocquencourt           #
#                                                                       #
#   Copyright 2010 Institut National de Recherche en Informatique et    #
#   en Automatique.  All rights reserved.  This file is distributed     #
#   under the terms of the Q Public License version 1.0.                #
#                                                                       #
#########################################################################

=== Initial setup ===
  make clean
  ./build/distclean.sh
  ./configure -prefix `pwd`/_install
  (cd otherlibs/labltk/browser; make help.ml)
  ./build/fastworld.sh
  # Go to "Bootstrap camlp4"

=== Install the bootstrapping camlp4 processor ===
  ./build/install.sh

=== Build camlp4 ===
  # This step is not needed right after a "./build/world.sh byte"
  ./build/camlp4-byte-only.sh

=== Bootstrap camlp4 ===
  # First "Build camlp4"
  # Then "Install the bootstrapping camlp4 processor"
  # Indeed the following bootstrapping script
  # does use the installed version!
  ./build/camlp4-bootstrap.sh
  # If the fixpoint not is reached yet
    # Go to "Bootstrap camlp4"
  # Otherwise
    # Have a look at the changes in
    # camlp4/boot it may be a good idea to commit them

=== Generate Camlp4Ast.ml ===
  # First "Install the bootstrapping camlp4 processor"
  # Indeed the following bootstrapping script
  # does use the installed version!
  ./build/camlp4-mkCamlp4Ast.sh

=== Case study "let open M in e" ===

 Open the revised parser
 Camlp4Parsers/Camlp4OCamlRevisedParser.ml

 Look for similar constructs, indeed rules
 that start by the same prefix should in
 the same entry. It is simpler to stick
 them close to each other.

 [ "let"; r = opt_rec; ...
 | "let"; "module"; m = a_UIDENT; ...

 So we naturally add something like

 | "let"; "open"; ...

 Then have a look to the "open" construct:

 | "open"; i = module_longident ->

 So we need a module_longident, it becomes:

 | "let"; "open"; i = module_longident; "in"; e = SELF ->

 Then we leave a dummy action but very close to what we want
 in the end:

 | "let"; "open"; i = module_longident; "in"; e = SELF ->
   <:expr< open_in $id:i$ $e$ >>

 Here it is just calling a (non-existing) function called open_in.

 Check that there is no other place where we have to duplicate this
 rule (yuk!). In our case it is! The sequence entry have the "let"
 rules again.

 Then go into Camlp4Parsers/Camlp4OCamlParser.ml and look for other
 occurences.

 When copy/pasting the rule take care of SELF occurences, you may
 have to replace it by expr and expr LEVEL ";" in our case.

 The return type of the production might be different from expr in
 our case an action become <:str_item<...>> instead of <:expr<...>

 Watch the DELETE_RULE as well, in our case I'm searching for the
 literal string "let" in the source:

 DELETE_RULE Gram expr: "let"; "open"; module_longident; "in"; SELF END;

 Then build and bootstrap.

 Then you can at last extend the AST, go in:

 Camlp4/Camlp4Ast.partial.ml

 And add the "open in" constructor (at the end).

   (* let open i in e *)
 | ExOpI of loc and ident and expr

 Then "Generate Camlp4Ast.ml" and build.

 We get a single warning in Camlp4/Struct/Camlp4Ast2OCamlAst.ml but
 don't fix it now. Notice that you may need to disable '-warn-error'
 in order to be able to successfully compile, despite of the warning.

 Then I hacked the camlp4/boot/camlp4boot.ml to generate:
   Ast.ExOpI(_loc, i, e)
 instead of
   Ast.ExApp(_loc .... "open_in" ... i ... e ...)

 Build. Bootstrap once and build again.

 Then change the parsers again and replace the
   open_in $id:i$ $e$
 by
   let open $i$ in $e$

 Then change the Parsetree generation in
   Camlp4/Struct/Camlp4Ast2OCamlAst.ml

   | <:expr@loc< let open $i$ in $e$ >> ->
       mkexp loc (Pexp_open (long_uident i) (expr e))

 Change the pretty-printers as well (drawing inspiration in
   "let module" in this case):

 In Camlp4/Printers/OCaml.ml:
   | <:expr< let open $i$ in $e$ >> ->
       pp f "@[<2>let open %a@]@ @[<2>in@ %a@]"
             o#ident i o#reset_semi#expr e
 And at the end of #simple_expr:
   <:expr< let open $_$ in $_$ >>

 Have a look in Camlp4/Printers/OCamlr.ml as well.

=== Second case study "with t := ..." ===

1/ Change the revised parser first.
Add new parsing rules for := but keep the old actions for now.

2/ Change Camlp4Ast.partial.ml, add:
    (* type t := t *)
    | WcTyS of loc and ctyp and ctyp
    (* module i := i *)
    | WcMoS of loc and ident and ident

3/ "Generate Camlp4Ast.ml" and build.

4/ Change the generated camlp4/boot/camlp4boot.ml:
   Look for ":=" and change occurences of
   WcMod by WcMoS and WcTyp by WcTyS

5/ Build (DO NOT bootstrap)
   "Install the bootstrapping camlp4 processor"

6/ Change the required files:
   Camlp4/Printers/OCaml.ml:
     just copy/paste&adapt what is done for
       "... with type t = u" and
       "... with module M = N"
   Camlp4/Struct/Camlp4Ast2OCamlAst.ml:
       I've factored out a common part under
       another function and then copy/pasted.
   Camlp4Parsers/Camlp4OCamlRevisedParser.ml:
       Change the <:with_constr< type $...$ = $...$ >>
       we've introduced earlier by replacing the '='
       by ':='.
   Camlp4Parsers/Camlp4OCamlParser.ml:
       Copy paste what we have done in Camlp4OCamlRevisedParser
       and but we need to call opt_private_ctyp instead of
       ctyp (just like the "type =" construct).

7/ Build & Bootstrap
