summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/_tags3
-rw-r--r--src/lexer.mll1
-rw-r--r--src/myocamlbuild.ml1
-rw-r--r--src/parser.mly29
-rw-r--r--src/pprint/AUTHORS3
-rw-r--r--src/pprint/CHANGES27
-rw-r--r--src/pprint/LICENSE517
-rw-r--r--src/pprint/README13
-rwxr-xr-xsrc/pprint/src/META5
-rw-r--r--src/pprint/src/Makefile35
-rw-r--r--src/pprint/src/PPrint.ml18
-rw-r--r--src/pprint/src/PPrintCombinators.ml311
-rw-r--r--src/pprint/src/PPrintCombinators.mli236
-rw-r--r--src/pprint/src/PPrintEngine.ml637
-rw-r--r--src/pprint/src/PPrintEngine.mli226
-rw-r--r--src/pprint/src/PPrintLib.mllib5
-rw-r--r--src/pprint/src/PPrintOCaml.ml158
-rw-r--r--src/pprint/src/PPrintOCaml.mli90
-rw-r--r--src/pprint/src/PPrintRenderer.ml37
-rw-r--r--src/pprint/src/PPrintTest.ml64
-rw-r--r--src/pretty_print.ml525
-rw-r--r--src/pretty_print.mli7
-rw-r--r--src/sail.ml2
-rw-r--r--src/type_check.ml16
24 files changed, 2947 insertions, 19 deletions
diff --git a/src/_tags b/src/_tags
index 0938900a..9088a3a2 100644
--- a/src/_tags
+++ b/src/_tags
@@ -1,7 +1,8 @@
true: -traverse, debug
<**/*.ml>: bin_annot, annot
<lem_interp> or <test>: include
+<sail.{byte,native}>: use_pprint
+<pprint> or <pprint/src>: include
# see http://caml.inria.fr/mantis/view.php?id=4943
<lem_interp/*> and not <lem_interp/*.cmxa>: use_nums, use_lem
<test/*> and not <test/*.cmxa>: use_nums, use_lem, use_str
-
diff --git a/src/lexer.mll b/src/lexer.mll
index 988ddb7c..ad6ea0d9 100644
--- a/src/lexer.mll
+++ b/src/lexer.mll
@@ -218,6 +218,7 @@ rule token = parse
| "*_u" { (StarUnderU(r"*_u")) }
| "*_ui" { (StarUnderUi(r"*_ui")) }
| "2^" { (TwoCarrot(r"2^")) }
+ | "2**" { TwoStarStar }
| "(*" { comment (Lexing.lexeme_start_p lexbuf) 0 lexbuf; token lexbuf }
diff --git a/src/myocamlbuild.ml b/src/myocamlbuild.ml
index 70e2b633..4c5505ee 100644
--- a/src/myocamlbuild.ml
+++ b/src/myocamlbuild.ml
@@ -36,6 +36,7 @@ dispatch begin function
| After_rules ->
(* ocaml_lib "lem_interp/interp"; *)
ocaml_lib ~extern:true ~dir:lem_libdir ~tag_name:"use_lem" lem_lib;
+ ocaml_lib ~extern:false ~dir:"pprint/src" ~tag_name:"use_pprint" "pprint/src/PPrintLib";
rule "lem -> ml"
~prod: "%.ml"
diff --git a/src/parser.mly b/src/parser.mly
index 3c3cf8e0..75cdcf7d 100644
--- a/src/parser.mly
+++ b/src/parser.mly
@@ -367,6 +367,7 @@ app_num_typ:
| Num
{ tloc (ATyp_constant $1) }
+/* XXX this part of the parser makes absolutely no sense to me */
star_typ_list:
| app_num_typ
{ [$1] }
@@ -378,6 +379,8 @@ star_typ:
{ match $1 with
| [] -> assert false
| [t] -> t
+ (* XXX why is ATyp_tup star-separated here, but comma-separated
+ below? *)
| ts -> tloc (ATyp_tup(ts)) }
exp_typ:
@@ -386,6 +389,7 @@ exp_typ:
| TwoStarStar nexp_typ
{ tloc (ATyp_exp($2)) }
+/* XXX this is wrong - for instance, 2** 3 + 5 is parsed as 2** (3+5) */
nexp_typ:
| exp_typ
{ $1 }
@@ -532,6 +536,9 @@ atomic_exp:
{ eloc (E_cast($2,$4)) }
| Lparen comma_exps Rparen
{ eloc (E_tuple($2)) }
+ /* XXX creates many conflicts
+ | Lcurly semi_exps Rcurly
+ { eloc (E_record($2)) } */
| Lcurly exp With semi_exps Rcurly
{ eloc (E_record_update($2,$4)) }
| Lsquare Rsquare
@@ -568,6 +575,7 @@ app_exp:
{ $1 }
| id Lparen Rparen
{ eloc (E_app($1, [eloc (E_lit (lloc L_unit))])) }
+ /* we wrap into a tuple here, but this is unwrapped in initial_check.ml */
| id Lparen exp Rparen
{ eloc (E_app($1,[ E_aux((E_tuple [$3]),locn 3 3)])) }
| id Lparen comma_exps Rparen
@@ -614,6 +622,9 @@ starstar_exp:
| starstar_exp StarStar app_exp
{ eloc (E_app_infix($1,Id_aux(Id($2), locn 2 2), $3)) }
+/* this is where we diverge from the non-right_atomic path;
+ here we go directly to right_atomic whereas the other one
+ goes through app_exp, vaccess_exp and field_exp too. */
starstar_right_atomic_exp:
| right_atomic_exp
{ $1 }
@@ -661,8 +672,12 @@ star_right_atomic_exp:
{ eloc (E_app_infix($1,Id_aux(Id("mod"), locn 2 2), $3)) }
| star_exp StarUnderS starstar_right_atomic_exp
{ eloc (E_app_infix($1,Id_aux(Id($2), locn 2 2), $3)) }
+ | star_exp StarUnderSi starstar_right_atomic_exp
+ { eloc (E_app_infix($1,Id_aux(Id($2), locn 2 2), $3)) }
| star_exp StarUnderU starstar_right_atomic_exp
{ eloc (E_app_infix($1,Id_aux(Id($2), locn 2 2), $3)) }
+ | star_exp StarUnderUi starstar_right_atomic_exp
+ { eloc (E_app_infix($1,Id_aux(Id($2), locn 2 2), $3)) }
plus_exp:
| star_exp
@@ -718,6 +733,8 @@ cons_right_atomic_exp:
{ $1 }
| shift_exp ColonColon cons_right_atomic_exp
{ eloc (E_cons($1,$3)) }
+ | shift_exp Colon cons_right_atomic_exp
+ { eloc (E_app_infix($1,Id_aux(Id(":"), locn 2 2), $3)) }
at_exp:
| cons_exp
@@ -740,10 +757,13 @@ at_right_atomic_exp:
{ eloc (E_app_infix($1,Id_aux(Id($2), locn 2 2), $3)) }
| cons_exp Carrot at_right_atomic_exp
{ eloc (E_app_infix($1,Id_aux(Id($2), locn 2 2), $3)) }
+ | cons_exp TildeCarrot at_right_atomic_exp
+ { eloc (E_app_infix($1,Id_aux(Id($2), locn 2 2), $3)) }
eq_exp:
| at_exp
{ $1 }
+ /* XXX check for consistency */
| eq_exp Eq at_exp
{ eloc (E_app_infix($1,Id_aux(Id($2), locn 2 2), $3)) }
| eq_exp EqEq at_exp
@@ -774,6 +794,8 @@ eq_exp:
{ eloc (E_app_infix ($1,Id_aux(Id($2), locn 2 2), $3)) }
| eq_exp LtUnderU at_exp
{ eloc (E_app_infix($1,Id_aux(Id($2), locn 2 2), $3)) }
+ /* XXX assignement should not have the same precedence as equal,
+ otherwise a := b > c requires extra parens... */
| eq_exp ColonEq at_exp
{ eloc (E_assign($1,$3)) }
@@ -918,7 +940,7 @@ fun_def:
{ funloc (FD_function(mk_rec 2,mk_tannot (mk_typqn ()) $3 3 3, mk_eannotn (), $4)) }
| Function_ Rec funcl_ands
{ funloc (FD_function(mk_rec 2, mk_tannotn (), mk_eannotn (), $3)) }
- | Function_ typquant atomic_typ Effect effect_typ funcl_ands
+ | Function_ typquant typ Effect effect_typ funcl_ands
{ funloc (FD_function(mk_recn (), mk_tannot $2 $3 2 3, mk_eannot $5 5, $6)) }
| Function_ typquant typ funcl_ands
{ funloc (FD_function(mk_recn (), mk_tannot $2 $3 2 2, mk_eannotn (), $4)) }
@@ -992,7 +1014,10 @@ typquant:
name_sect:
| Lsquare Id Eq String Rsquare
- { Name_sect_aux(Name_sect_some($4), loc ()) }
+ {
+ if $2 <> "name" then
+ raise (Parse_error_locn ((loc ()),"Unexpected id \""^$2^"\" in name_sect (should be \"name\")"));
+ Name_sect_aux(Name_sect_some($4), loc ()) }
c_def_body:
| typ id
diff --git a/src/pprint/AUTHORS b/src/pprint/AUTHORS
new file mode 100644
index 00000000..6060ac93
--- /dev/null
+++ b/src/pprint/AUTHORS
@@ -0,0 +1,3 @@
+PPrint was written by François Pottier and Nicolas Pouillard, with
+contributions by Yann Régis-Gianas, Gabriel Scherer, and Jonathan
+Protzenko.
diff --git a/src/pprint/CHANGES b/src/pprint/CHANGES
new file mode 100644
index 00000000..69747a41
--- /dev/null
+++ b/src/pprint/CHANGES
@@ -0,0 +1,27 @@
+2014/04/11
+Changed the behavior of [align], which was not consistent with its documentation.
+[align] now sets the indentation level to the current column. In particular, this
+means that [align (align d)] is equivalent to [align d], which was not the case
+previously. Thanks to Dmitry Grebeniuk for reporting this issue.
+
+2014/04/03
+The library is now extensible (in principle). A [custom] document constructor
+allows the user to define her own documents, as long as they fit the manner
+in which the current rendering engine works.
+
+The [compact] rendering engine is now tail-recursive too.
+
+2014/03/21
+Minor optimisation in the smart constructor [group].
+
+2014/03/13
+New (simpler) pretty-printing engine. The representation of documents in
+memory is slightly larger; document construction is perhaps slightly slower,
+while rendering is significantly faster. (Construction dominates rendering.)
+The rendering speed is now guaranteed to be independent of the width
+parameter. The price to pay for this simplification is that the primitive
+document constructors [column] and [nesting] are no longer supported. The
+API is otherwise unchanged.
+
+2013/01/31
+First official release of PPrint.
diff --git a/src/pprint/LICENSE b/src/pprint/LICENSE
new file mode 100644
index 00000000..d6eb151e
--- /dev/null
+++ b/src/pprint/LICENSE
@@ -0,0 +1,517 @@
+
+CeCILL-C FREE SOFTWARE LICENSE AGREEMENT
+
+
+ Notice
+
+This Agreement is a Free Software license agreement that is the result
+of discussions between its authors in order to ensure compliance with
+the two main principles guiding its drafting:
+
+ * firstly, compliance with the principles governing the distribution
+ of Free Software: access to source code, broad rights granted to
+ users,
+ * secondly, the election of a governing law, French law, with which
+ it is conformant, both as regards the law of torts and
+ intellectual property law, and the protection that it offers to
+ both authors and holders of the economic rights over software.
+
+The authors of the CeCILL-C (for Ce[a] C[nrs] I[nria] L[ogiciel] L[ibre])
+license are:
+
+Commissariat à l'Energie Atomique - CEA, a public scientific, technical
+and industrial research establishment, having its principal place of
+business at 25 rue Leblanc, immeuble Le Ponant D, 75015 Paris, France.
+
+Centre National de la Recherche Scientifique - CNRS, a public scientific
+and technological establishment, having its principal place of business
+at 3 rue Michel-Ange, 75794 Paris cedex 16, France.
+
+Institut National de Recherche en Informatique et en Automatique -
+INRIA, a public scientific and technological establishment, having its
+principal place of business at Domaine de Voluceau, Rocquencourt, BP
+105, 78153 Le Chesnay cedex, France.
+
+
+ Preamble
+
+The purpose of this Free Software license agreement is to grant users
+the right to modify and re-use the software governed by this license.
+
+The exercising of this right is conditional upon the obligation to make
+available to the community the modifications made to the source code of
+the software so as to contribute to its evolution.
+
+In consideration of access to the source code and the rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty and the software's author, the holder of the
+economic rights, and the successive licensors only have limited liability.
+
+In this respect, the risks associated with loading, using, modifying
+and/or developing or reproducing the software by the user are brought to
+the user's attention, given its Free Software status, which may make it
+complicated to use, with the result that its use is reserved for
+developers and experienced professionals having in-depth computer
+knowledge. Users are therefore encouraged to load and test the
+suitability of the software as regards their requirements in conditions
+enabling the security of their systems and/or data to be ensured and,
+more generally, to use and operate it in the same conditions of
+security. This Agreement may be freely reproduced and published,
+provided it is not altered, and that no provisions are either added or
+removed herefrom.
+
+This Agreement may apply to any or all software for which the holder of
+the economic rights decides to submit the use thereof to its provisions.
+
+
+ Article 1 - DEFINITIONS
+
+For the purpose of this Agreement, when the following expressions
+commence with a capital letter, they shall have the following meaning:
+
+Agreement: means this license agreement, and its possible subsequent
+versions and annexes.
+
+Software: means the software in its Object Code and/or Source Code form
+and, where applicable, its documentation, "as is" when the Licensee
+accepts the Agreement.
+
+Initial Software: means the Software in its Source Code and possibly its
+Object Code form and, where applicable, its documentation, "as is" when
+it is first distributed under the terms and conditions of the Agreement.
+
+Modified Software: means the Software modified by at least one
+Integrated Contribution.
+
+Source Code: means all the Software's instructions and program lines to
+which access is required so as to modify the Software.
+
+Object Code: means the binary files originating from the compilation of
+the Source Code.
+
+Holder: means the holder(s) of the economic rights over the Initial
+Software.
+
+Licensee: means the Software user(s) having accepted the Agreement.
+
+Contributor: means a Licensee having made at least one Integrated
+Contribution.
+
+Licensor: means the Holder, or any other individual or legal entity, who
+distributes the Software under the Agreement.
+
+Integrated Contribution: means any or all modifications, corrections,
+translations, adaptations and/or new functions integrated into the
+Source Code by any or all Contributors.
+
+Related Module: means a set of sources files including their
+documentation that, without modification to the Source Code, enables
+supplementary functions or services in addition to those offered by the
+Software.
+
+Derivative Software: means any combination of the Software, modified or
+not, and of a Related Module.
+
+Parties: mean both the Licensee and the Licensor.
+
+These expressions may be used both in singular and plural form.
+
+
+ Article 2 - PURPOSE
+
+The purpose of the Agreement is the grant by the Licensor to the
+Licensee of a non-exclusive, transferable and worldwide license for the
+Software as set forth in Article 5 hereinafter for the whole term of the
+protection granted by the rights over said Software.
+
+
+ Article 3 - ACCEPTANCE
+
+3.1 The Licensee shall be deemed as having accepted the terms and
+conditions of this Agreement upon the occurrence of the first of the
+following events:
+
+ * (i) loading the Software by any or all means, notably, by
+ downloading from a remote server, or by loading from a physical
+ medium;
+ * (ii) the first time the Licensee exercises any of the rights
+ granted hereunder.
+
+3.2 One copy of the Agreement, containing a notice relating to the
+characteristics of the Software, to the limited warranty, and to the
+fact that its use is restricted to experienced users has been provided
+to the Licensee prior to its acceptance as set forth in Article 3.1
+hereinabove, and the Licensee hereby acknowledges that it has read and
+understood it.
+
+
+ Article 4 - EFFECTIVE DATE AND TERM
+
+
+ 4.1 EFFECTIVE DATE
+
+The Agreement shall become effective on the date when it is accepted by
+the Licensee as set forth in Article 3.1.
+
+
+ 4.2 TERM
+
+The Agreement shall remain in force for the entire legal term of
+protection of the economic rights over the Software.
+
+
+ Article 5 - SCOPE OF RIGHTS GRANTED
+
+The Licensor hereby grants to the Licensee, who accepts, the following
+rights over the Software for any or all use, and for the term of the
+Agreement, on the basis of the terms and conditions set forth hereinafter.
+
+Besides, if the Licensor owns or comes to own one or more patents
+protecting all or part of the functions of the Software or of its
+components, the Licensor undertakes not to enforce the rights granted by
+these patents against successive Licensees using, exploiting or
+modifying the Software. If these patents are transferred, the Licensor
+undertakes to have the transferees subscribe to the obligations set
+forth in this paragraph.
+
+
+ 5.1 RIGHT OF USE
+
+The Licensee is authorized to use the Software, without any limitation
+as to its fields of application, with it being hereinafter specified
+that this comprises:
+
+ 1. permanent or temporary reproduction of all or part of the Software
+ by any or all means and in any or all form.
+
+ 2. loading, displaying, running, or storing the Software on any or
+ all medium.
+
+ 3. entitlement to observe, study or test its operation so as to
+ determine the ideas and principles behind any or all constituent
+ elements of said Software. This shall apply when the Licensee
+ carries out any or all loading, displaying, running, transmission
+ or storage operation as regards the Software, that it is entitled
+ to carry out hereunder.
+
+
+ 5.2 RIGHT OF MODIFICATION
+
+The right of modification includes the right to translate, adapt,
+arrange, or make any or all modifications to the Software, and the right
+to reproduce the resulting software. It includes, in particular, the
+right to create a Derivative Software.
+
+The Licensee is authorized to make any or all modification to the
+Software provided that it includes an explicit notice that it is the
+author of said modification and indicates the date of the creation thereof.
+
+
+ 5.3 RIGHT OF DISTRIBUTION
+
+In particular, the right of distribution includes the right to publish,
+transmit and communicate the Software to the general public on any or
+all medium, and by any or all means, and the right to market, either in
+consideration of a fee, or free of charge, one or more copies of the
+Software by any means.
+
+The Licensee is further authorized to distribute copies of the modified
+or unmodified Software to third parties according to the terms and
+conditions set forth hereinafter.
+
+
+ 5.3.1 DISTRIBUTION OF SOFTWARE WITHOUT MODIFICATION
+
+The Licensee is authorized to distribute true copies of the Software in
+Source Code or Object Code form, provided that said distribution
+complies with all the provisions of the Agreement and is accompanied by:
+
+ 1. a copy of the Agreement,
+
+ 2. a notice relating to the limitation of both the Licensor's
+ warranty and liability as set forth in Articles 8 and 9,
+
+and that, in the event that only the Object Code of the Software is
+redistributed, the Licensee allows effective access to the full Source
+Code of the Software at a minimum during the entire period of its
+distribution of the Software, it being understood that the additional
+cost of acquiring the Source Code shall not exceed the cost of
+transferring the data.
+
+
+ 5.3.2 DISTRIBUTION OF MODIFIED SOFTWARE
+
+When the Licensee makes an Integrated Contribution to the Software, the
+terms and conditions for the distribution of the resulting Modified
+Software become subject to all the provisions of this Agreement.
+
+The Licensee is authorized to distribute the Modified Software, in
+source code or object code form, provided that said distribution
+complies with all the provisions of the Agreement and is accompanied by:
+
+ 1. a copy of the Agreement,
+
+ 2. a notice relating to the limitation of both the Licensor's
+ warranty and liability as set forth in Articles 8 and 9,
+
+and that, in the event that only the object code of the Modified
+Software is redistributed, the Licensee allows effective access to the
+full source code of the Modified Software at a minimum during the entire
+period of its distribution of the Modified Software, it being understood
+that the additional cost of acquiring the source code shall not exceed
+the cost of transferring the data.
+
+
+ 5.3.3 DISTRIBUTION OF DERIVATIVE SOFTWARE
+
+When the Licensee creates Derivative Software, this Derivative Software
+may be distributed under a license agreement other than this Agreement,
+subject to compliance with the requirement to include a notice
+concerning the rights over the Software as defined in Article 6.4.
+In the event the creation of the Derivative Software required modification
+of the Source Code, the Licensee undertakes that:
+
+ 1. the resulting Modified Software will be governed by this Agreement,
+ 2. the Integrated Contributions in the resulting Modified Software
+ will be clearly identified and documented,
+ 3. the Licensee will allow effective access to the source code of the
+ Modified Software, at a minimum during the entire period of
+ distribution of the Derivative Software, such that such
+ modifications may be carried over in a subsequent version of the
+ Software; it being understood that the additional cost of
+ purchasing the source code of the Modified Software shall not
+ exceed the cost of transferring the data.
+
+
+ 5.3.4 COMPATIBILITY WITH THE CeCILL LICENSE
+
+When a Modified Software contains an Integrated Contribution subject to
+the CeCILL license agreement, or when a Derivative Software contains a
+Related Module subject to the CeCILL license agreement, the provisions
+set forth in the third item of Article 6.4 are optional.
+
+
+ Article 6 - INTELLECTUAL PROPERTY
+
+
+ 6.1 OVER THE INITIAL SOFTWARE
+
+The Holder owns the economic rights over the Initial Software. Any or
+all use of the Initial Software is subject to compliance with the terms
+and conditions under which the Holder has elected to distribute its work
+and no one shall be entitled to modify the terms and conditions for the
+distribution of said Initial Software.
+
+The Holder undertakes that the Initial Software will remain ruled at
+least by this Agreement, for the duration set forth in Article 4.2.
+
+
+ 6.2 OVER THE INTEGRATED CONTRIBUTIONS
+
+The Licensee who develops an Integrated Contribution is the owner of the
+intellectual property rights over this Contribution as defined by
+applicable law.
+
+
+ 6.3 OVER THE RELATED MODULES
+
+The Licensee who develops a Related Module is the owner of the
+intellectual property rights over this Related Module as defined by
+applicable law and is free to choose the type of agreement that shall
+govern its distribution under the conditions defined in Article 5.3.3.
+
+
+ 6.4 NOTICE OF RIGHTS
+
+The Licensee expressly undertakes:
+
+ 1. not to remove, or modify, in any manner, the intellectual property
+ notices attached to the Software;
+
+ 2. to reproduce said notices, in an identical manner, in the copies
+ of the Software modified or not;
+
+ 3. to ensure that use of the Software, its intellectual property
+ notices and the fact that it is governed by the Agreement is
+ indicated in a text that is easily accessible, specifically from
+ the interface of any Derivative Software.
+
+The Licensee undertakes not to directly or indirectly infringe the
+intellectual property rights of the Holder and/or Contributors on the
+Software and to take, where applicable, vis-à-vis its staff, any and all
+measures required to ensure respect of said intellectual property rights
+of the Holder and/or Contributors.
+
+
+ Article 7 - RELATED SERVICES
+
+7.1 Under no circumstances shall the Agreement oblige the Licensor to
+provide technical assistance or maintenance services for the Software.
+
+However, the Licensor is entitled to offer this type of services. The
+terms and conditions of such technical assistance, and/or such
+maintenance, shall be set forth in a separate instrument. Only the
+Licensor offering said maintenance and/or technical assistance services
+shall incur liability therefor.
+
+7.2 Similarly, any Licensor is entitled to offer to its licensees, under
+its sole responsibility, a warranty, that shall only be binding upon
+itself, for the redistribution of the Software and/or the Modified
+Software, under terms and conditions that it is free to decide. Said
+warranty, and the financial terms and conditions of its application,
+shall be subject of a separate instrument executed between the Licensor
+and the Licensee.
+
+
+ Article 8 - LIABILITY
+
+8.1 Subject to the provisions of Article 8.2, the Licensee shall be
+entitled to claim compensation for any direct loss it may have suffered
+from the Software as a result of a fault on the part of the relevant
+Licensor, subject to providing evidence thereof.
+
+8.2 The Licensor's liability is limited to the commitments made under
+this Agreement and shall not be incurred as a result of in particular:
+(i) loss due the Licensee's total or partial failure to fulfill its
+obligations, (ii) direct or consequential loss that is suffered by the
+Licensee due to the use or performance of the Software, and (iii) more
+generally, any consequential loss. In particular the Parties expressly
+agree that any or all pecuniary or business loss (i.e. loss of data,
+loss of profits, operating loss, loss of customers or orders,
+opportunity cost, any disturbance to business activities) or any or all
+legal proceedings instituted against the Licensee by a third party,
+shall constitute consequential loss and shall not provide entitlement to
+any or all compensation from the Licensor.
+
+
+ Article 9 - WARRANTY
+
+9.1 The Licensee acknowledges that the scientific and technical
+state-of-the-art when the Software was distributed did not enable all
+possible uses to be tested and verified, nor for the presence of
+possible defects to be detected. In this respect, the Licensee's
+attention has been drawn to the risks associated with loading, using,
+modifying and/or developing and reproducing the Software which are
+reserved for experienced users.
+
+The Licensee shall be responsible for verifying, by any or all means,
+the suitability of the product for its requirements, its good working
+order, and for ensuring that it shall not cause damage to either persons
+or properties.
+
+9.2 The Licensor hereby represents, in good faith, that it is entitled
+to grant all the rights over the Software (including in particular the
+rights set forth in Article 5).
+
+9.3 The Licensee acknowledges that the Software is supplied "as is" by
+the Licensor without any other express or tacit warranty, other than
+that provided for in Article 9.2 and, in particular, without any warranty
+as to its commercial value, its secured, safe, innovative or relevant
+nature.
+
+Specifically, the Licensor does not warrant that the Software is free
+from any error, that it will operate without interruption, that it will
+be compatible with the Licensee's own equipment and software
+configuration, nor that it will meet the Licensee's requirements.
+
+9.4 The Licensor does not either expressly or tacitly warrant that the
+Software does not infringe any third party intellectual property right
+relating to a patent, software or any other property right. Therefore,
+the Licensor disclaims any and all liability towards the Licensee
+arising out of any or all proceedings for infringement that may be
+instituted in respect of the use, modification and redistribution of the
+Software. Nevertheless, should such proceedings be instituted against
+the Licensee, the Licensor shall provide it with technical and legal
+assistance for its defense. Such technical and legal assistance shall be
+decided on a case-by-case basis between the relevant Licensor and the
+Licensee pursuant to a memorandum of understanding. The Licensor
+disclaims any and all liability as regards the Licensee's use of the
+name of the Software. No warranty is given as regards the existence of
+prior rights over the name of the Software or as regards the existence
+of a trademark.
+
+
+ Article 10 - TERMINATION
+
+10.1 In the event of a breach by the Licensee of its obligations
+hereunder, the Licensor may automatically terminate this Agreement
+thirty (30) days after notice has been sent to the Licensee and has
+remained ineffective.
+
+10.2 A Licensee whose Agreement is terminated shall no longer be
+authorized to use, modify or distribute the Software. However, any
+licenses that it may have granted prior to termination of the Agreement
+shall remain valid subject to their having been granted in compliance
+with the terms and conditions hereof.
+
+
+ Article 11 - MISCELLANEOUS
+
+
+ 11.1 EXCUSABLE EVENTS
+
+Neither Party shall be liable for any or all delay, or failure to
+perform the Agreement, that may be attributable to an event of force
+majeure, an act of God or an outside cause, such as defective
+functioning or interruptions of the electricity or telecommunications
+networks, network paralysis following a virus attack, intervention by
+government authorities, natural disasters, water damage, earthquakes,
+fire, explosions, strikes and labor unrest, war, etc.
+
+11.2 Any failure by either Party, on one or more occasions, to invoke
+one or more of the provisions hereof, shall under no circumstances be
+interpreted as being a waiver by the interested Party of its right to
+invoke said provision(s) subsequently.
+
+11.3 The Agreement cancels and replaces any or all previous agreements,
+whether written or oral, between the Parties and having the same
+purpose, and constitutes the entirety of the agreement between said
+Parties concerning said purpose. No supplement or modification to the
+terms and conditions hereof shall be effective as between the Parties
+unless it is made in writing and signed by their duly authorized
+representatives.
+
+11.4 In the event that one or more of the provisions hereof were to
+conflict with a current or future applicable act or legislative text,
+said act or legislative text shall prevail, and the Parties shall make
+the necessary amendments so as to comply with said act or legislative
+text. All other provisions shall remain effective. Similarly, invalidity
+of a provision of the Agreement, for any reason whatsoever, shall not
+cause the Agreement as a whole to be invalid.
+
+
+ 11.5 LANGUAGE
+
+The Agreement is drafted in both French and English and both versions
+are deemed authentic.
+
+
+ Article 12 - NEW VERSIONS OF THE AGREEMENT
+
+12.1 Any person is authorized to duplicate and distribute copies of this
+Agreement.
+
+12.2 So as to ensure coherence, the wording of this Agreement is
+protected and may only be modified by the authors of the License, who
+reserve the right to periodically publish updates or new versions of the
+Agreement, each with a separate number. These subsequent versions may
+address new issues encountered by Free Software.
+
+12.3 Any Software distributed under a given version of the Agreement may
+only be subsequently distributed under the same version of the Agreement
+or a subsequent version.
+
+
+ Article 13 - GOVERNING LAW AND JURISDICTION
+
+13.1 The Agreement is governed by French law. The Parties agree to
+endeavor to seek an amicable solution to any disagreements or disputes
+that may arise during the performance of the Agreement.
+
+13.2 Failing an amicable solution within two (2) months as from their
+occurrence, and unless emergency proceedings are necessary, the
+disagreements or disputes shall be referred to the Paris Courts having
+jurisdiction, by the more diligent Party.
+
+
+Version 1.0 dated 2006-09-05.
diff --git a/src/pprint/README b/src/pprint/README
new file mode 100644
index 00000000..7146250a
--- /dev/null
+++ b/src/pprint/README
@@ -0,0 +1,13 @@
+This is an adaptation of Daan Leijen's "PPrint" library, which itself is based
+on the ideas developed by Philip Wadler in "A Prettier Printer". For more
+information about Wadler's and Leijen's work, please consult the following
+references:
+
+ http://www.cs.uu.nl/~daan/pprint.html
+ http://homepages.inf.ed.ac.uk/wadler/papers/prettier/prettier.pdf
+
+To install PPrint, type "make -C src install". ocamlfind is required.
+
+The documentation for PPrint is built by "make doc" and is found in the
+file doc/index.html.
+
diff --git a/src/pprint/src/META b/src/pprint/src/META
new file mode 100755
index 00000000..b7d43d40
--- /dev/null
+++ b/src/pprint/src/META
@@ -0,0 +1,5 @@
+requires = ""
+description = "The PPrint pretty-printing library"
+archive(byte) = "PPrintLib.cma"
+archive(native) = "PPrintLib.cmxa"
+version = "20140424"
diff --git a/src/pprint/src/Makefile b/src/pprint/src/Makefile
new file mode 100644
index 00000000..f56f4d88
--- /dev/null
+++ b/src/pprint/src/Makefile
@@ -0,0 +1,35 @@
+.PHONY: all install clean doc test
+
+OCAMLBUILD := ocamlbuild -use-ocamlfind -cflags "-g" -lflags "-g" -classic-display
+OCAMLFIND := ocamlfind
+DOCDIR := doc
+MAIN := PPrintTest
+TO_BUILD := PPrintLib.cma PPrintLib.cmxa
+
+all:
+ $(OCAMLBUILD) $(TO_BUILD)
+
+install: all
+ $(OCAMLFIND) install pprint META \
+ $(patsubst %,_build/%,$(TO_BUILD)) \
+ _build/PPrintLib.a _build/*.cmx _build/*.cmi
+
+clean:
+ rm -f *~
+ rm -rf doc
+ $(OCAMLBUILD) -clean
+
+doc: all
+ @rm -rf $(DOCDIR)
+ @mkdir $(DOCDIR)
+ ocamlfind ocamldoc \
+ -html \
+ -I _build \
+ -d $(DOCDIR) \
+ -charset utf8 \
+ PPrintRenderer.ml PPrintEngine.mli PPrintCombinators.mli PPrintOCaml.mli PPrint.ml
+
+test: all
+ $(OCAMLBUILD) $(MAIN).native
+ ./$(MAIN).native
+
diff --git a/src/pprint/src/PPrint.ml b/src/pprint/src/PPrint.ml
new file mode 100644
index 00000000..ae1ff709
--- /dev/null
+++ b/src/pprint/src/PPrint.ml
@@ -0,0 +1,18 @@
+(**************************************************************************)
+(* *)
+(* PPrint *)
+(* *)
+(* Francois Pottier, INRIA Paris-Rocquencourt *)
+(* Nicolas Pouillard, IT University of Copenhagen *)
+(* *)
+(* Copyright 2007-2014 INRIA. All rights reserved. This file is *)
+(* distributed under the terms of the CeCILL-C license, as described *)
+(* in the file LICENSE. *)
+(* *)
+(**************************************************************************)
+
+(** A package of all of the above. *)
+
+include PPrintEngine
+include PPrintCombinators
+module OCaml = PPrintOCaml
diff --git a/src/pprint/src/PPrintCombinators.ml b/src/pprint/src/PPrintCombinators.ml
new file mode 100644
index 00000000..39b99b9c
--- /dev/null
+++ b/src/pprint/src/PPrintCombinators.ml
@@ -0,0 +1,311 @@
+(**************************************************************************)
+(* *)
+(* PPrint *)
+(* *)
+(* Francois Pottier, INRIA Paris-Rocquencourt *)
+(* Nicolas Pouillard, IT University of Copenhagen *)
+(* *)
+(* Copyright 2007-2014 INRIA. All rights reserved. This file is *)
+(* distributed under the terms of the CeCILL-C license, as described *)
+(* in the file LICENSE. *)
+(* *)
+(**************************************************************************)
+
+open PPrintEngine
+
+(* ------------------------------------------------------------------------- *)
+
+(* Predefined single-character documents. *)
+
+let lparen = char '('
+let rparen = char ')'
+let langle = char '<'
+let rangle = char '>'
+let lbrace = char '{'
+let rbrace = char '}'
+let lbracket = char '['
+let rbracket = char ']'
+let squote = char '\''
+let dquote = char '"'
+let bquote = char '`'
+let semi = char ';'
+let colon = char ':'
+let comma = char ','
+let space = char ' '
+let dot = char '.'
+let sharp = char '#'
+let slash = char '/'
+let backslash = char '\\'
+let equals = char '='
+let qmark = char '?'
+let tilde = char '~'
+let at = char '@'
+let percent = char '%'
+let dollar = char '$'
+let caret = char '^'
+let ampersand = char '&'
+let star = char '*'
+let plus = char '+'
+let minus = char '-'
+let underscore = char '_'
+let bang = char '!'
+let bar = char '|'
+
+(* ------------------------------------------------------------------------- *)
+
+(* Repetition. *)
+
+let twice doc =
+ doc ^^ doc
+
+let repeat n doc =
+ let rec loop n doc accu =
+ if n = 0 then
+ accu
+ else
+ loop (n - 1) doc (doc ^^ accu)
+ in
+ loop n doc empty
+
+(* ------------------------------------------------------------------------- *)
+
+(* Delimiters. *)
+
+let precede l x = l ^^ x
+let terminate r x = x ^^ r
+let enclose l r x = l ^^ x ^^ r
+
+let squotes = enclose squote squote
+let dquotes = enclose dquote dquote
+let bquotes = enclose bquote bquote
+let braces = enclose lbrace rbrace
+let parens = enclose lparen rparen
+let angles = enclose langle rangle
+let brackets = enclose lbracket rbracket
+
+(* ------------------------------------------------------------------------- *)
+
+(* Some functions on lists. *)
+
+(* A variant of [fold_left] that keeps track of the element index. *)
+
+let foldli (f : int -> 'b -> 'a -> 'b) (accu : 'b) (xs : 'a list) : 'b =
+ let r = ref 0 in
+ List.fold_left (fun accu x ->
+ let i = !r in
+ r := i + 1;
+ f i accu x
+ ) accu xs
+
+(* ------------------------------------------------------------------------- *)
+
+(* Working with lists of documents. *)
+
+let concat docs =
+ (* We take advantage of the fact that [^^] operates in constant
+ time, regardless of the size of its arguments. The document
+ that is constructed is essentially a reversed list (i.e., a
+ tree that is biased towards the left). This is not a problem;
+ when pretty-printing this document, the engine will descend
+ along the left branch, pushing the nodes onto its stack as
+ it goes down, effectively reversing the list again. *)
+ List.fold_left (^^) empty docs
+
+let separate sep docs =
+ foldli (fun i accu doc ->
+ if i = 0 then
+ doc
+ else
+ accu ^^ sep ^^ doc
+ ) empty docs
+
+let concat_map f xs =
+ List.fold_left (fun accu x ->
+ accu ^^ f x
+ ) empty xs
+
+let separate_map sep f xs =
+ foldli (fun i accu x ->
+ if i = 0 then
+ f x
+ else
+ accu ^^ sep ^^ f x
+ ) empty xs
+
+let separate2 sep last_sep docs =
+ let n = List.length docs in
+ foldli (fun i accu doc ->
+ if i = 0 then
+ doc
+ else
+ accu ^^ (if i < n - 1 then sep else last_sep) ^^ doc
+ ) empty docs
+
+let optional f = function
+ | None ->
+ empty
+ | Some x ->
+ f x
+
+(* ------------------------------------------------------------------------- *)
+
+(* Text. *)
+
+(* This variant of [String.index_from] returns an option. *)
+
+let index_from s i c =
+ try
+ Some (String.index_from s i c)
+ with Not_found ->
+ None
+
+(* [lines s] chops the string [s] into a list of lines, which are turned
+ into documents. *)
+
+let lines s =
+ let rec chop accu i =
+ match index_from s i '\n' with
+ | Some j ->
+ let accu = substring s i (j - i) :: accu in
+ chop accu (j + 1)
+ | None ->
+ substring s i (String.length s - i) :: accu
+ in
+ List.rev (chop [] 0)
+
+let arbitrary_string s =
+ separate (break 1) (lines s)
+
+(* [split ok s] splits the string [s] at every occurrence of a character
+ that satisfies the predicate [ok]. The substrings thus obtained are
+ turned into documents, and a list of documents is returned. No information
+ is lost: the concatenation of the documents yields the original string.
+ This code is not UTF-8 aware. *)
+
+let split ok s =
+ let n = String.length s in
+ let rec index_from i =
+ if i = n then
+ None
+ else if ok s.[i] then
+ Some i
+ else
+ index_from (i + 1)
+ in
+ let rec chop accu i =
+ match index_from i with
+ | Some j ->
+ let accu = substring s i (j - i) :: accu in
+ let accu = char s.[j] :: accu in
+ chop accu (j + 1)
+ | None ->
+ substring s i (String.length s - i) :: accu
+ in
+ List.rev (chop [] 0)
+
+(* [words s] chops the string [s] into a list of words, which are turned
+ into documents. *)
+
+let words s =
+ let n = String.length s in
+ (* A two-state finite automaton. *)
+ (* In this state, we have skipped at least one blank character. *)
+ let rec skipping accu i =
+ if i = n then
+ (* There was whitespace at the end. Drop it. *)
+ accu
+ else match s.[i] with
+ | ' '
+ | '\t'
+ | '\n'
+ | '\r' ->
+ (* Skip more whitespace. *)
+ skipping accu (i + 1)
+ | _ ->
+ (* Begin a new word. *)
+ word accu i (i + 1)
+ (* In this state, we have skipped at least one non-blank character. *)
+ and word accu i j =
+ if j = n then
+ (* Final word. *)
+ substring s i (j - i) :: accu
+ else match s.[j] with
+ | ' '
+ | '\t'
+ | '\n'
+ | '\r' ->
+ (* A new word has been identified. *)
+ let accu = substring s i (j - i) :: accu in
+ skipping accu (j + 1)
+ | _ ->
+ (* Continue inside the current word. *)
+ word accu i (j + 1)
+ in
+ List.rev (skipping [] 0)
+
+let flow_map sep f docs =
+ foldli (fun i accu doc ->
+ if i = 0 then
+ f doc
+ else
+ accu ^^
+ (* This idiom allows beginning a new line if [doc] does not
+ fit on the current line. *)
+ group (sep ^^ f doc)
+ ) empty docs
+
+let flow sep docs =
+ flow_map sep (fun x -> x) docs
+
+let url s =
+ flow (break 0) (split (function '/' | '.' -> true | _ -> false) s)
+
+(* ------------------------------------------------------------------------- *)
+
+(* Alignment and indentation. *)
+
+let hang i d =
+ align (nest i d)
+
+let ( !^ ) = string
+
+let ( ^/^ ) x y =
+ x ^^ break 1 ^^ y
+
+let prefix n b x y =
+ group (x ^^ nest n (break b ^^ y))
+
+let (^//^) =
+ prefix 2 1
+
+let jump n b y =
+ group (nest n (break b ^^ y))
+
+(* Deprecated.
+let ( ^@^ ) x y = group (x ^/^ y)
+let ( ^@@^ ) x y = group (nest 2 (x ^/^ y))
+*)
+
+let infix n b op x y =
+ prefix n b (x ^^ blank b ^^ op) y
+
+let surround n b opening contents closing =
+ group (opening ^^ nest n ( break b ^^ contents) ^^ break b ^^ closing )
+
+let soft_surround n b opening contents closing =
+ group (opening ^^ nest n (group (break b) ^^ contents) ^^ group (break b ^^ closing))
+
+let surround_separate n b void opening sep closing docs =
+ match docs with
+ | [] ->
+ void
+ | _ :: _ ->
+ surround n b opening (separate sep docs) closing
+
+let surround_separate_map n b void opening sep closing f xs =
+ match xs with
+ | [] ->
+ void
+ | _ :: _ ->
+ surround n b opening (separate_map sep f xs) closing
+
diff --git a/src/pprint/src/PPrintCombinators.mli b/src/pprint/src/PPrintCombinators.mli
new file mode 100644
index 00000000..ef2b44ea
--- /dev/null
+++ b/src/pprint/src/PPrintCombinators.mli
@@ -0,0 +1,236 @@
+(**************************************************************************)
+(* *)
+(* PPrint *)
+(* *)
+(* Francois Pottier, INRIA Paris-Rocquencourt *)
+(* Nicolas Pouillard, IT University of Copenhagen *)
+(* *)
+(* Copyright 2007-2014 INRIA. All rights reserved. This file is *)
+(* distributed under the terms of the CeCILL-C license, as described *)
+(* in the file LICENSE. *)
+(* *)
+(**************************************************************************)
+
+open PPrintEngine
+
+(** A set of high-level combinators for building documents. *)
+
+(** {1 Single characters} *)
+
+(** The following constant documents consist of a single character. *)
+
+val lparen: document
+val rparen: document
+val langle: document
+val rangle: document
+val lbrace: document
+val rbrace: document
+val lbracket: document
+val rbracket: document
+val squote: document
+val dquote: document
+val bquote: document
+val semi: document
+val colon: document
+val comma: document
+val space: document
+val dot: document
+val sharp: document
+val slash: document
+val backslash: document
+val equals: document
+val qmark: document
+val tilde: document
+val at: document
+val percent: document
+val dollar: document
+val caret: document
+val ampersand: document
+val star: document
+val plus: document
+val minus: document
+val underscore: document
+val bang: document
+val bar: document
+
+(** {1 Delimiters} *)
+
+(** [precede l x] is [l ^^ x]. *)
+val precede: document -> document -> document
+
+(** [terminate r x] is [x ^^ r]. *)
+val terminate: document -> document -> document
+
+(** [enclose l r x] is [l ^^ x ^^ r]. *)
+val enclose: document -> document -> document -> document
+
+(** The following combinators enclose a document within a pair of delimiters.
+ They are partial applications of [enclose]. No whitespace or line break is
+ introduced. *)
+
+val squotes: document -> document
+val dquotes: document -> document
+val bquotes: document -> document
+val braces: document -> document
+val parens: document -> document
+val angles: document -> document
+val brackets: document -> document
+
+(** {1 Repetition} *)
+
+(** [twice doc] is the document obtained by concatenating two copies of
+ the document [doc]. *)
+val twice: document -> document
+
+(** [repeat n doc] is the document obtained by concatenating [n] copies of
+ the document [doc]. *)
+val repeat: int -> document -> document
+
+(** {1 Lists and options} *)
+
+(** [concat docs] is the concatenation of the documents in the list [docs]. *)
+val concat: document list -> document
+
+(** [separate sep docs] is the concatenation of the documents in the list
+ [docs]. The separator [sep] is inserted between every two adjacent
+ documents. *)
+val separate: document -> document list -> document
+
+(** [concat_map f xs] is equivalent to [concat (List.map f xs)]. *)
+val concat_map: ('a -> document) -> 'a list -> document
+
+(** [separate_map sep f xs] is equivalent to [separate sep (List.map f xs)]. *)
+val separate_map: document -> ('a -> document) -> 'a list -> document
+
+(** [separate2 sep last_sep docs] is the concatenation of the documents in the
+ list [docs]. The separator [sep] is inserted between every two adjacent
+ documents, except between the last two documents, where the separator
+ [last_sep] is used instead. *)
+val separate2: document -> document -> document list -> document
+
+(** [optional f None] is the empty document. [optional f (Some x)] is
+ the document [f x]. *)
+val optional: ('a -> document) -> 'a option -> document
+
+(** {1 Text} *)
+
+(** [lines s] is the list of documents obtained by splitting [s] at newline
+ characters, and turning each line into a document via [substring]. This
+ code is not UTF-8 aware. *)
+val lines: string -> document list
+
+(** [arbitrary_string s] is equivalent to [separate (break 1) (lines s)].
+ It is analogous to [string s], but is valid even if the string [s]
+ contains newline characters. *)
+val arbitrary_string: string -> document
+
+(** [words s] is the list of documents obtained by splitting [s] at whitespace
+ characters, and turning each word into a document via [substring]. All
+ whitespace is discarded. This code is not UTF-8 aware. *)
+val words: string -> document list
+
+(** [split ok s] splits the string [s] before and after every occurrence of a
+ character that satisfies the predicate [ok]. The substrings thus obtained
+ are turned into documents, and a list of documents is returned. No
+ information is lost: the concatenation of the documents yields the
+ original string. This code is not UTF-8 aware. *)
+val split: (char -> bool) -> string -> document list
+
+(** [flow sep docs] separates the documents in the list [docs] with the
+ separator [sep] and arranges for a new line to begin whenever a document
+ does not fit on the current line. This is useful for typesetting
+ free-flowing, ragged-right text. A typical choice of [sep] is [break b],
+ where [b] is the number of spaces that must be inserted between two
+ consecutive words (when displayed on the same line). *)
+val flow: document -> document list -> document
+
+(** [flow_map sep f docs] is equivalent to [flow sep (List.map f docs)]. *)
+val flow_map: document -> ('a -> document) -> 'a list -> document
+
+(** [url s] is a possible way of displaying the URL [s]. A potential line
+ break is inserted immediately before and immediately after every slash
+ and dot character. *)
+val url: string -> document
+
+(** {1 Alignment and indentation} *)
+
+(* [hang n doc] is analogous to [align], but additionally indents
+ all lines, except the first one, by [n]. Thus, the text in the
+ box forms a hanging indent. *)
+val hang: int -> document -> document
+
+(** [prefix n b left right] has the following flat layout: {[
+left right
+]}
+and the following non-flat layout:
+{[
+left
+ right
+]}
+The parameter [n] controls the nesting of [right] (when not flat).
+The parameter [b] controls the number of spaces between [left] and [right]
+(when flat).
+ *)
+val prefix: int -> int -> document -> document -> document
+
+(** [jump n b right] is equivalent to [prefix n b empty right]. *)
+val jump: int -> int -> document -> document
+
+(** [infix n b middle left right] has the following flat layout: {[
+left middle right
+]}
+and the following non-flat layout: {[
+left middle
+ right
+]}
+The parameter [n] controls the nesting of [right] (when not flat).
+The parameter [b] controls the number of spaces between [left] and [middle]
+(always) and between [middle] and [right] (when flat).
+*)
+val infix: int -> int -> document -> document -> document -> document
+
+(** [surround n b opening contents closing] has the following flat layout: {[
+opening contents closing
+]}
+and the following non-flat layout: {[
+opening
+ contents
+closing
+]}
+The parameter [n] controls the nesting of [contents] (when not flat).
+The parameter [b] controls the number of spaces between [opening] and [contents]
+and between [contents] and [closing] (when flat).
+*)
+val surround: int -> int -> document -> document -> document -> document
+
+(** [soft_surround] is analogous to [surround], but involves more than one
+ group, so it offers possibilities other than the completely flat layout
+ (where [opening], [contents], and [closing] appear on a single line) and
+ the completely developed layout (where [opening], [contents], and
+ [closing] appear on separate lines). It tries to place the beginning of
+ [contents] on the same line as [opening], and to place [closing] on the
+ same line as the end of [contents], if possible.
+*)
+val soft_surround: int -> int -> document -> document -> document -> document
+
+(** [surround_separate n b void opening sep closing docs] is equivalent to
+ [surround n b opening (separate sep docs) closing], except when the
+ list [docs] is empty, in which case it reduces to [void]. *)
+val surround_separate: int -> int -> document -> document -> document -> document -> document list -> document
+
+(** [surround_separate_map n b void opening sep closing f xs] is equivalent to
+ [surround_separate n b void opening sep closing (List.map f xs)]. *)
+val surround_separate_map: int -> int -> document -> document -> document -> document -> ('a -> document) -> 'a list -> document
+
+(** {1 Short-hands} *)
+
+(** [!^s] is a short-hand for [string s]. *)
+val ( !^ ) : string -> document
+
+(** [x ^/^ y] separates [x] and [y] with a breakable space.
+ It is a short-hand for [x ^^ break 1 ^^ y]. *)
+val ( ^/^ ) : document -> document -> document
+
+(** [x ^//^ y] is a short-hand for [prefix 2 1 x y]. *)
+val ( ^//^ ) : document -> document -> document
+
diff --git a/src/pprint/src/PPrintEngine.ml b/src/pprint/src/PPrintEngine.ml
new file mode 100644
index 00000000..cfa8474a
--- /dev/null
+++ b/src/pprint/src/PPrintEngine.ml
@@ -0,0 +1,637 @@
+(**************************************************************************)
+(* *)
+(* PPrint *)
+(* *)
+(* Francois Pottier, INRIA Paris-Rocquencourt *)
+(* Nicolas Pouillard, IT University of Copenhagen *)
+(* *)
+(* Copyright 2007-2014 INRIA. All rights reserved. This file is *)
+(* distributed under the terms of the CeCILL-C license, as described *)
+(* in the file LICENSE. *)
+(* *)
+(**************************************************************************)
+
+(* ------------------------------------------------------------------------- *)
+
+(* A type of integers with infinity. *)
+
+type requirement =
+ int (* with infinity *)
+
+(* Infinity is encoded as [max_int]. *)
+
+let infinity : requirement =
+ max_int
+
+(* Addition of integers with infinity. *)
+
+let (++) (x : requirement) (y : requirement) : requirement =
+ if x = infinity || y = infinity then
+ infinity
+ else
+ x + y
+
+(* Comparison between an integer with infinity and a normal integer. *)
+
+let (<==) (x : requirement) (y : int) =
+ x <= y
+
+(* ------------------------------------------------------------------------- *)
+
+(* A uniform interface for output channels. *)
+
+class type output = object
+
+ (** [char c] sends the character [c] to the output channel. *)
+ method char: char -> unit
+
+ (** [substring s ofs len] sends the substring of [s] delimited by the
+ offset [ofs] and the length [len] to the output channel. *)
+ method substring: string -> int (* offset *) -> int (* length *) -> unit
+
+end
+
+(* Three kinds of output channels are wrapped so as to satisfy the above
+ interface: OCaml output channels, OCaml memory buffers, and OCaml
+ formatters. *)
+
+class channel_output channel = object
+ method char = output_char channel
+ method substring = output channel
+end
+
+class buffer_output buffer = object
+ method char = Buffer.add_char buffer
+ method substring = Buffer.add_substring buffer
+end
+
+class formatter_output fmt = object
+ method char = Format.pp_print_char fmt
+ method substring = fst (Format.pp_get_formatter_output_functions fmt ())
+end
+
+(* ------------------------------------------------------------------------- *)
+
+(** The rendering engine maintains the following internal state. Its structure
+ is subject to change in future versions of the library. Nevertheless, it is
+ exposed to the user who wishes to define custom documents. *)
+
+type state = {
+
+ width: int;
+ (** The line width. This parameter is fixed throughout the execution of
+ the renderer. *)
+
+ ribbon: int;
+ (** The ribbon width. This parameter is fixed throughout the execution of
+ the renderer. *)
+
+ mutable last_indent: int;
+ (** The number of blanks that were printed at the beginning of the current
+ line. This field is updated (only) by the function [emit_hardline]. It
+ is used (only) to determine whether the ribbon width constraint is
+ respected. *)
+
+ mutable column: int;
+ (** The current column. This field must be updated whenever something is
+ sent to the output channel. It is used (only) to determine whether the
+ width constraint is respected. *)
+
+ }
+
+(* ------------------------------------------------------------------------- *)
+
+(* [initial rfrac width] creates a fresh initial state. *)
+
+let initial rfrac width = {
+ width = width;
+ ribbon = max 0 (min width (truncate (float_of_int width *. rfrac)));
+ last_indent = 0;
+ column = 0
+}
+
+(* ------------------------------------------------------------------------- *)
+
+(** A custom document is defined by implementing the following methods. *)
+
+class type custom = object
+
+ (** A custom document must publish the width (i.e., the number of columns)
+ that it would like to occupy if it is printed on a single line (that is,
+ in flattening mode). The special value [infinity] means that this
+ document cannot be printed on a single line; this value causes any
+ groups that contain this document to be dissolved. This method should
+ in principle work in constant time. *)
+ method requirement: requirement
+
+ (** The method [pretty] is used by the main rendering algorithm. It has
+ access to the output channel and to the algorithm's internal state, as
+ described above. In addition, it receives the current indentation level
+ and the current flattening mode (on or off). If flattening mode is on,
+ then the document must be printed on a single line, in a manner that is
+ consistent with the requirement that was published ahead of time. If
+ flattening mode is off, then there is no such obligation. The state must
+ be updated in a manner that is consistent with what is sent to the
+ output channel. *)
+ method pretty: output -> state -> int -> bool -> unit
+
+ (** The method [compact] is used by the compact rendering algorithm. It has
+ access to the output channel only. *)
+ method compact: output -> unit
+
+end
+
+(* ------------------------------------------------------------------------- *)
+
+(* Here is the algebraic data type of documents. It is analogous to Daan
+ Leijen's version, but the binary constructor [Union] is replaced with
+ the unary constructor [Group], and the constant [Line] is replaced with
+ more general constructions, namely [IfFlat], which provides alternative
+ forms depending on the current flattening mode, and [HardLine], which
+ represents a newline character, and causes a failure in flattening mode. *)
+
+type document =
+
+ (* [Empty] is the empty document. *)
+
+ | Empty
+
+ (* [Char c] is a document that consists of the single character [c]. We
+ enforce the invariant that [c] is not a newline character. *)
+
+ | Char of char
+
+ (* [String (s, ofs, len)] is a document that consists of the portion of
+ the string [s] delimited by the offset [ofs] and the length [len]. We
+ assume, but do not check, that this portion does not contain a newline
+ character. *)
+
+ | String of string * int * int
+
+ (* [FancyString (s, ofs, len, apparent_length)] is a (portion of a) string
+ that may contain fancy characters: color escape characters, UTF-8 or
+ multi-byte characters, etc. Thus, the apparent length (which corresponds
+ to what will be visible on screen) differs from the length (which is a
+ number of bytes, and is reported by [String.length]). We assume, but do
+ not check, that fancystrings do not contain a newline character. *)
+
+ | FancyString of string * int * int * int
+
+ (* [Blank n] is a document that consists of [n] blank characters. *)
+
+ | Blank of int
+
+ (* When in flattening mode, [IfFlat (d1, d2)] turns into the document
+ [d1]. When not in flattening mode, it turns into the document [d2]. *)
+
+ | IfFlat of document * document
+
+ (* When in flattening mode, [HardLine] causes a failure, which requires
+ backtracking all the way until the stack is empty. When not in flattening
+ mode, it represents a newline character, followed with an appropriate
+ number of indentation. A common way of using [HardLine] is to only use it
+ directly within the right branch of an [IfFlat] construct. *)
+
+ | HardLine
+
+ (* The following constructors store their space requirement. This is the
+ document's apparent length, if printed in flattening mode. This
+ information is computed in a bottom-up manner when the document is
+ constructed. *)
+
+ (* In other words, the space requirement is the number of columns that the
+ document needs in order to fit on a single line. We express this value in
+ the set of `integers extended with infinity', and use the value
+ [infinity] to indicate that the document cannot be printed on a single
+ line. *)
+
+ (* Storing this information at [Group] nodes is crucial, as it allows us to
+ avoid backtracking and buffering. *)
+
+ (* Storing this information at other nodes allows the function [requirement]
+ to operate in constant time. This means that the bottom-up computation of
+ requirements takes linear time. *)
+
+ (* [Cat (req, doc1, doc2)] is the concatenation of the documents [doc1] and
+ [doc2]. The space requirement [req] is the sum of the requirements of
+ [doc1] and [doc2]. *)
+
+ | Cat of requirement * document * document
+
+ (* [Nest (req, j, doc)] is the document [doc], in which the indentation
+ level has been increased by [j], that is, in which [j] blanks have been
+ inserted after every newline character. The space requirement [req] is
+ the same as the requirement of [doc]. *)
+
+ | Nest of requirement * int * document
+
+ (* [Group (req, doc)] represents an alternative: it is either a flattened
+ form of [doc], in which occurrences of [Group] disappear and occurrences
+ of [IfFlat] resolve to their left branch, or [doc] itself. The space
+ requirement [req] is the same as the requirement of [doc]. *)
+
+ | Group of requirement * document
+
+ (* [Align (req, doc)] increases the indentation level to reach the current
+ column. Thus, the document [doc] is rendered within a box whose upper
+ left corner is the current position. The space requirement [req] is the
+ same as the requirement of [doc]. *)
+
+ | Align of requirement * document
+
+ (* [Custom (req, f)] is a document whose appearance is user-defined. *)
+
+ | Custom of custom
+
+(* ------------------------------------------------------------------------- *)
+
+(* Retrieving or computing the space requirement of a document. *)
+
+let rec requirement = function
+ | Empty ->
+ 0
+ | Char _ ->
+ 1
+ | String (_, _, len)
+ | FancyString (_, _, _, len)
+ | Blank len ->
+ len
+ | IfFlat (doc1, _) ->
+ (* In flattening mode, the requirement of [ifflat x y] is just the
+ requirement of its flat version, [x]. *)
+ (* The smart constructor [ifflat] ensures that [IfFlat] is never nested
+ in the left-hand side of [IfFlat], so this recursive call is not a
+ problem; the function [requirement] has constant time complexity. *)
+ requirement doc1
+ | HardLine ->
+ (* A hard line cannot be printed in flattening mode. *)
+ infinity
+ | Cat (req, _, _)
+ | Nest (req, _, _)
+ | Group (req, _)
+ | Align (req, _) ->
+ (* These nodes store their requirement -- which is computed when the
+ node is constructed -- so as to allow us to answer in constant time
+ here. *)
+ req
+ | Custom c ->
+ c#requirement
+
+(* ------------------------------------------------------------------------- *)
+
+(* The above algebraic data type is not exposed to the user. Instead, we
+ expose the following functions. These functions construct a raw document
+ and compute its requirement, so as to obtain a document. *)
+
+let empty =
+ Empty
+
+let char c =
+ assert (c <> '\n');
+ Char c
+
+let space =
+ char ' '
+
+let substring s ofs len =
+ if len = 0 then
+ empty
+ else
+ String (s, ofs, len)
+
+let string s =
+ substring s 0 (String.length s)
+
+let fancysubstring s ofs len apparent_length =
+ if len = 0 then
+ empty
+ else
+ FancyString (s, ofs, len, apparent_length)
+
+let fancystring s apparent_length =
+ fancysubstring s 0 (String.length s) apparent_length
+
+(* The following function was stolen from [Batteries]. *)
+let utf8_length s =
+ let rec length_aux s c i =
+ if i >= String.length s then c else
+ let n = Char.code (String.unsafe_get s i) in
+ let k =
+ if n < 0x80 then 1 else
+ if n < 0xe0 then 2 else
+ if n < 0xf0 then 3 else 4
+ in
+ length_aux s (c + 1) (i + k)
+ in
+ length_aux s 0 0
+
+let utf8string s =
+ fancystring s (utf8_length s)
+
+let hardline =
+ HardLine
+
+let blank n =
+ match n with
+ | 0 ->
+ empty
+ | 1 ->
+ space
+ | _ ->
+ Blank n
+
+let ifflat doc1 doc2 =
+ (* Avoid nesting [IfFlat] in the left-hand side of [IfFlat], as this
+ is redundant. *)
+ match doc1 with
+ | IfFlat (doc1, _)
+ | doc1 ->
+ IfFlat (doc1, doc2)
+
+let internal_break i =
+ ifflat (blank i) hardline
+
+let break0 =
+ internal_break 0
+
+let break1 =
+ internal_break 1
+
+let break i =
+ match i with
+ | 0 ->
+ break0
+ | 1 ->
+ break1
+ | _ ->
+ internal_break i
+
+let (^^) x y =
+ match x, y with
+ | Empty, _ ->
+ y
+ | _, Empty ->
+ x
+ | _, _ ->
+ Cat (requirement x ++ requirement y, x, y)
+
+let nest i x =
+ assert (i >= 0);
+ Nest (requirement x, i, x)
+
+let group x =
+ let req = requirement x in
+ (* Minor optimisation: an infinite requirement dissolves a group. *)
+ if req = infinity then
+ x
+ else
+ Group (req, x)
+
+let align x =
+ Align (requirement x, x)
+
+let custom c =
+ (* Sanity check. *)
+ assert (c#requirement >= 0);
+ Custom c
+
+(* ------------------------------------------------------------------------- *)
+
+(* Printing blank space (indentation characters). *)
+
+let blank_length =
+ 80
+
+let blank_buffer =
+ String.make blank_length ' '
+
+let rec blanks output n =
+ if n <= 0 then
+ ()
+ else if n <= blank_length then
+ output#substring blank_buffer 0 n
+ else begin
+ output#substring blank_buffer 0 blank_length;
+ blanks output (n - blank_length)
+ end
+
+(* ------------------------------------------------------------------------- *)
+
+(* This function expresses the following invariant: if we are in flattening
+ mode, then we must be within bounds, i.e. the width and ribbon width
+ constraints must be respected. *)
+
+let ok state flatten : bool =
+ not flatten ||
+ state.column <= state.width && state.column <= state.last_indent + state.ribbon
+
+(* ------------------------------------------------------------------------- *)
+
+(* The pretty rendering engine. *)
+
+(* The renderer is supposed to behave exactly like Daan Leijen's, although its
+ implementation is quite radically different, and simpler. Our documents are
+ constructed eagerly, as opposed to lazily. This means that we pay a large
+ space overhead, but in return, we get the ability of computing information
+ bottom-up, as described above, which allows to render documents without
+ backtracking or buffering. *)
+
+(* The [state] record is never copied; it is just threaded through. In
+ addition to it, the parameters [indent] and [flatten] influence the
+ manner in which the document is rendered. *)
+
+(* The code is written in tail-recursive style, so as to avoid running out of
+ stack space if the document is very deep. Its explicit continuation can be
+ viewed as a sequence of pending calls to [pretty]. *)
+
+type cont =
+ | KNil
+ | KCons of int * bool * document * cont
+
+let rec pretty
+ (output : output)
+ (state : state)
+ (indent : int)
+ (flatten : bool)
+ (doc : document)
+ (cont : cont)
+: unit =
+ match doc with
+
+ | Empty ->
+ continue output state cont
+
+ | Char c ->
+ output#char c;
+ state.column <- state.column + 1;
+ (* assert (ok state flatten); *)
+ continue output state cont
+
+ | String (s, ofs, len) ->
+ output#substring s ofs len;
+ state.column <- state.column + len;
+ (* assert (ok state flatten); *)
+ continue output state cont
+
+ | FancyString (s, ofs, len, apparent_length) ->
+ output#substring s ofs len;
+ state.column <- state.column + apparent_length;
+ (* assert (ok state flatten); *)
+ continue output state cont
+
+ | Blank n ->
+ blanks output n;
+ state.column <- state.column + n;
+ (* assert (ok state flatten); *)
+ continue output state cont
+
+ | HardLine ->
+ (* We cannot be in flattening mode, because a hard line has an [infinity]
+ requirement, and we attempt to render a group in flattening mode only
+ if this group's requirement is met. *)
+ assert (not flatten);
+ (* Emit a hardline. *)
+ output#char '\n';
+ blanks output indent;
+ state.column <- indent;
+ state.last_indent <- indent;
+ (* Continue. *)
+ continue output state cont
+
+ | IfFlat (doc1, doc2) ->
+ (* Pick an appropriate sub-document, based on the current flattening
+ mode. *)
+ pretty output state indent flatten (if flatten then doc1 else doc2) cont
+
+ | Cat (_, doc1, doc2) ->
+ (* Push the second document onto the continuation. *)
+ pretty output state indent flatten doc1 (KCons (indent, flatten, doc2, cont))
+
+ | Nest (_, j, doc) ->
+ pretty output state (indent + j) flatten doc cont
+
+ | Group (req, doc) ->
+ (* If we already are in flattening mode, stay in flattening mode; we
+ are committed to it. If we are not already in flattening mode, we
+ have a choice of entering flattening mode. We enter this mode only
+ if we know that this group fits on this line without violating the
+ width or ribbon width constraints. Thus, we never backtrack. *)
+ let flatten =
+ flatten ||
+ let column = state.column ++ req in
+ column <== state.width && column <== state.last_indent + state.ribbon
+ in
+ pretty output state indent flatten doc cont
+
+ | Align (_, doc) ->
+ (* The effect of this combinator is to set [indent] to [state.column].
+ Usually [indent] is equal to [state.last_indent], hence setting it
+ to [state.column] increases it. However, if [nest] has been used
+ since the current line began, then this could cause [indent] to
+ decrease. *)
+ (* assert (state.column > state.last_indent); *)
+ pretty output state state.column flatten doc cont
+
+ | Custom c ->
+ (* Invoke the document's custom rendering function. *)
+ c#pretty output state indent flatten;
+ (* Sanity check. *)
+ assert (ok state flatten);
+ (* Continue. *)
+ continue output state cont
+
+and continue output state = function
+ | KNil ->
+ ()
+ | KCons (indent, flatten, doc, cont) ->
+ pretty output state indent flatten doc cont
+
+(* Publish a version of [pretty] that does not take an explicit continuation.
+ This function may be used by authors of custom documents. We do not expose
+ the internal [pretty] -- the one that takes a continuation -- because we
+ wish to simplify the user's life. The price to pay is that calls that go
+ through a custom document cannot be tail calls. *)
+
+let pretty output state indent flatten doc =
+ pretty output state indent flatten doc KNil
+
+(* ------------------------------------------------------------------------- *)
+
+(* The compact rendering algorithm. *)
+
+let rec compact output doc cont =
+ match doc with
+ | Empty ->
+ continue output cont
+ | Char c ->
+ output#char c;
+ continue output cont
+ | String (s, ofs, len) ->
+ output#substring s ofs len;
+ continue output cont
+ | FancyString (s, ofs, len, apparent_length) ->
+ output#substring s ofs len;
+ continue output cont
+ | Blank n ->
+ blanks output n;
+ continue output cont
+ | HardLine ->
+ output#char '\n';
+ continue output cont
+ | Cat (_, doc1, doc2) ->
+ compact output doc1 (doc2 :: cont)
+ | IfFlat (doc, _)
+ | Nest (_, _, doc)
+ | Group (_, doc)
+ | Align (_, doc) ->
+ compact output doc cont
+ | Custom c ->
+ (* Invoke the document's custom rendering function. *)
+ c#compact output;
+ continue output cont
+
+and continue output cont =
+ match cont with
+ | [] ->
+ ()
+ | doc :: cont ->
+ compact output doc cont
+
+let compact output doc =
+ compact output doc []
+
+(* ------------------------------------------------------------------------- *)
+
+(* We now instantiate the renderers for the three kinds of output channels. *)
+
+(* This is just boilerplate. *)
+
+module MakeRenderer (X : sig
+ type channel
+ val output: channel -> output
+end) = struct
+ type channel = X.channel
+ type dummy = document
+ type document = dummy
+ let pretty rfrac width channel doc = pretty (X.output channel) (initial rfrac width) 0 false doc
+ let compact channel doc = compact (X.output channel) doc
+end
+
+module ToChannel =
+ MakeRenderer(struct
+ type channel = out_channel
+ let output = new channel_output
+ end)
+
+module ToBuffer =
+ MakeRenderer(struct
+ type channel = Buffer.t
+ let output = new buffer_output
+ end)
+
+module ToFormatter =
+ MakeRenderer(struct
+ type channel = Format.formatter
+ let output = new formatter_output
+ end)
+
diff --git a/src/pprint/src/PPrintEngine.mli b/src/pprint/src/PPrintEngine.mli
new file mode 100644
index 00000000..7f6fcf35
--- /dev/null
+++ b/src/pprint/src/PPrintEngine.mli
@@ -0,0 +1,226 @@
+(**************************************************************************)
+(* *)
+(* PPrint *)
+(* *)
+(* Francois Pottier, INRIA Paris-Rocquencourt *)
+(* Nicolas Pouillard, IT University of Copenhagen *)
+(* *)
+(* Copyright 2007-2014 INRIA. All rights reserved. This file is *)
+(* distributed under the terms of the CeCILL-C license, as described *)
+(* in the file LICENSE. *)
+(* *)
+(**************************************************************************)
+
+(** A pretty-printing engine and a set of basic document combinators. *)
+
+(** {1 Building documents} *)
+
+(** Documents must be built in memory before they are rendered. This may seem
+ costly, but it is a simple approach, and works well. *)
+
+(** The following operations form a set of basic (low-level) combinators for
+ building documents. On top of these combinators, higher-level combinators
+ can be defined: see {!PPrintCombinators}. *)
+
+(** This is the abstract type of documents. *)
+type document
+
+(** The following basic (low-level) combinators allow constructing documents. *)
+
+(** [empty] is the empty document. *)
+val empty: document
+
+(** [char c] is a document that consists of the single character [c]. This
+ character must not be a newline. *)
+val char: char -> document
+
+(** [string s] is a document that consists of the string [s]. This string must
+ not contain a newline. *)
+val string: string -> document
+
+(** [substring s ofs len] is a document that consists of the portion of the
+ string [s] delimited by the offset [ofs] and the length [len]. This
+ portion must not contain a newline. *)
+val substring: string -> int -> int -> document
+
+(** [fancystring s apparent_length] is a document that consists of the string
+ [s]. This string must not contain a newline. The string may contain fancy
+ characters: color escape characters, UTF-8 or multi-byte characters,
+ etc. Thus, its apparent length (which measures how many columns the text
+ will take up on screen) differs from its length in bytes. *)
+val fancystring: string -> int -> document
+
+(** [fancysubstring s ofs len apparent_length] is a document that consists of
+ the portion of the string [s] delimited by the offset [ofs] and the length
+ [len]. This portion must contain a newline. The string may contain fancy
+ characters. *)
+val fancysubstring : string -> int -> int -> int -> document
+
+(** [utf8string s] is a document that consists of the UTF-8-encoded string [s].
+ This string must not contain a newline. *)
+val utf8string: string -> document
+
+(** [hardline] is a forced newline document. This document forces all enclosing
+ groups to be printed in non-flattening mode. In other words, any enclosing
+ groups are dissolved. *)
+val hardline: document
+
+(** [blank n] is a document that consists of [n] blank characters. *)
+val blank: int -> document
+
+(** [break n] is a document which consists of either [n] blank characters,
+ when forced to display on a single line, or a single newline character,
+ otherwise. Note that there is no choice at this point: choices are encoded
+ by the [group] combinator. *)
+val break: int -> document
+
+(** [doc1 ^^ doc2] is the concatenation of the documents [doc1] and [doc2]. *)
+val (^^): document -> document -> document
+
+(** [nest j doc] is the document [doc], in which the indentation level has
+ been increased by [j], that is, in which [j] blanks have been inserted
+ after every newline character. Read this again: indentation is inserted
+ after every newline character. No indentation is inserted at the beginning
+ of the document. *)
+val nest: int -> document -> document
+
+(** [group doc] encodes a choice. If possible, then the entire document [group
+ doc] is rendered on a single line. Otherwise, the group is dissolved, and
+ [doc] is rendered. There might be further groups within [doc], whose
+ presence will lead to further choices being explored. *)
+val group: document -> document
+
+(** [ifflat doc1 doc2] is rendered as [doc1] if part of a group that can be
+ successfully flattened, and is rendered as [doc2] otherwise. Use this
+ operation with caution. Because the pretty-printer is free to choose
+ between [doc1] and [doc2], these documents should be semantically
+ equivalent. *)
+val ifflat: document -> document -> document
+
+(** [align doc] is the document [doc], in which the indentation level has been
+ set to the current column. Thus, [doc] is rendered within a box whose
+ upper left corner is the current position. *)
+val align: document -> document
+
+(** {1 Rendering documents} *)
+
+(** This renderer sends its output into an output channel. *)
+module ToChannel : PPrintRenderer.RENDERER
+ with type channel = out_channel
+ and type document = document
+
+(** This renderer sends its output into a memory buffer. *)
+module ToBuffer : PPrintRenderer.RENDERER
+ with type channel = Buffer.t
+ and type document = document
+
+(** This renderer sends its output into a formatter channel. *)
+module ToFormatter : PPrintRenderer.RENDERER
+ with type channel = Format.formatter
+ and type document = document
+
+(** {1 Defining custom documents} *)
+
+(** A width requirement is expressed as an integer, where the value [max_int]
+ is reserved and represents infinity. *)
+
+type requirement = int
+val infinity : requirement
+
+(** An output channel is represented abstractly as an object equipped with
+ methods for displaying one character and for displaying a substring. *)
+
+class type output = object
+
+ (** [char c] sends the character [c] to the output channel. *)
+ method char: char -> unit
+
+ (** [substring s ofs len] sends the substring of [s] delimited by the
+ offset [ofs] and the length [len] to the output channel. *)
+ method substring: string -> int (* offset *) -> int (* length *) -> unit
+
+end
+
+(** The rendering engine maintains the following internal state. Its structure
+ is subject to change in future versions of the library. Nevertheless, it is
+ exposed to the user who wishes to define custom documents. *)
+
+type state = {
+
+ width: int;
+ (** The line width. This parameter is fixed throughout the execution of
+ the renderer. *)
+
+ ribbon: int;
+ (** The ribbon width. This parameter is fixed throughout the execution of
+ the renderer. *)
+
+ mutable last_indent: int;
+ (** The number of blanks that were printed at the beginning of the current
+ line. This field is updated (only) by the function [emit_hardline]. It
+ is used (only) to determine whether the ribbon width constraint is
+ respected. *)
+
+ mutable column: int;
+ (** The current column. This field must be updated whenever something is
+ sent to the output channel. It is used (only) to determine whether the
+ width constraint is respected. *)
+
+ }
+
+(** A custom document is defined by implementing the following methods. *)
+
+class type custom = object
+
+ (** A custom document must publish the width (i.e., the number of columns)
+ that it would like to occupy if it is printed on a single line (that is,
+ in flattening mode). The special value [infinity] means that this
+ document cannot be printed on a single line; this value causes any
+ groups that contain this document to be dissolved. This method should
+ in principle work in constant time. *)
+ method requirement: requirement
+
+ (** The method [pretty] is used by the main rendering algorithm. It has
+ access to the output channel and to the algorithm's internal state, as
+ described above. In addition, it receives the current indentation level
+ and the current flattening mode (on or off). If flattening mode is on,
+ then the document must be printed on a single line, in a manner that is
+ consistent with the requirement that was published ahead of time. If
+ flattening mode is off, then there is no such obligation. The state must
+ be updated in a manner that is consistent with what is sent to the
+ output channel. *)
+ method pretty: output -> state -> int -> bool -> unit
+
+ (** The method [compact] is used by the compact rendering algorithm. It has
+ access to the output channel only. *)
+ method compact: output -> unit
+
+end
+
+(** The function [custom] constructs a custom document. In other words, it
+ converts an object of type [custom] to a document. *)
+val custom: custom -> document
+
+(** The key functions of the library are exposed, in the hope that they may be
+ useful to authors of custom (leaf and non-leaf) documents. In the case of
+ a leaf document, they can help perform certain basic functions; for
+ instance, applying the function [pretty] to the document [hardline] is a
+ simple way of printing a hardline, while respecting the indentation
+ parameters and updating the state in a correct manner. Similarly, applying
+ [pretty] to the document [blank n] is a simple way of printing [n] spaces.
+ In the case of a non-leaf document (i.e., one which contains
+ sub-documents), these functions are essential: they allow computing the
+ width requirement of a sub-document and displaying a sub-document. *)
+
+(** [requirement doc] computes the width requirement of the document [doc].
+ It works in constant time. *)
+val requirement: document -> requirement
+
+(** [pretty output state indent flatten doc] prints the document [doc]. See
+ the documentation of the method [pretty]. *)
+val pretty: output -> state -> int -> bool -> document -> unit
+
+(** [compact output doc] prints the document [doc]. See the documentation of
+ the method [compact]. *)
+val compact: output -> document -> unit
+
diff --git a/src/pprint/src/PPrintLib.mllib b/src/pprint/src/PPrintLib.mllib
new file mode 100644
index 00000000..e5de6978
--- /dev/null
+++ b/src/pprint/src/PPrintLib.mllib
@@ -0,0 +1,5 @@
+PPrint
+PPrintCombinators
+PPrintEngine
+PPrintOCaml
+PPrintRenderer
diff --git a/src/pprint/src/PPrintOCaml.ml b/src/pprint/src/PPrintOCaml.ml
new file mode 100644
index 00000000..88e039ce
--- /dev/null
+++ b/src/pprint/src/PPrintOCaml.ml
@@ -0,0 +1,158 @@
+(**************************************************************************)
+(* *)
+(* PPrint *)
+(* *)
+(* Francois Pottier, INRIA Paris-Rocquencourt *)
+(* Nicolas Pouillard, IT University of Copenhagen *)
+(* *)
+(* Copyright 2007-2014 INRIA. All rights reserved. This file is *)
+(* distributed under the terms of the CeCILL-C license, as described *)
+(* in the file LICENSE. *)
+(* *)
+(**************************************************************************)
+
+open Printf
+open PPrintEngine
+open PPrintCombinators
+
+type constructor = string
+type type_name = string
+type record_field = string
+type tag = int
+
+(* ------------------------------------------------------------------------- *)
+
+(* This internal [sprintf]-like function produces a document. We use [string],
+ as opposed to [arbitrary_string], because the strings that we produce will
+ never contain a newline character. *)
+
+let dsprintf format =
+ ksprintf string format
+
+(* ------------------------------------------------------------------------- *)
+
+(* Nicolas prefers using this code as opposed to just [sprintf "%g"] or
+ [sprintf "%f"]. The latter print [inf] and [-inf], whereas OCaml
+ understands [infinity] and [neg_infinity]. [sprintf "%g"] does not add a
+ trailing dot when the number happens to be an integral number. [sprintf
+ "%F"] seems to lose precision and ignores the precision modifier. *)
+
+let valid_float_lexeme (s : string) : string =
+ let l = String.length s in
+ let rec loop i =
+ if i >= l then
+ (* If we reach the end of the string and have found only characters in
+ the set '0' .. '9' and '-', then this string will be considered as an
+ integer literal by OCaml. Adding a trailing dot makes it a float
+ literal. *)
+ s ^ "."
+ else
+ match s.[i] with
+ | '0' .. '9' | '-' -> loop (i + 1)
+ | _ -> s
+ in loop 0
+
+(* This function constructs a string representation of a floating point
+ number. This representation is supposed to be accepted by OCaml as a
+ valid floating point literal. *)
+
+let float_representation (f : float) : string =
+ match classify_float f with
+ | FP_nan ->
+ "nan"
+ | FP_infinite ->
+ if f < 0.0 then "neg_infinity" else "infinity"
+ | _ ->
+ (* Try increasing precisions and validate. *)
+ let s = sprintf "%.12g" f in
+ if f = float_of_string s then valid_float_lexeme s else
+ let s = sprintf "%.15g" f in
+ if f = float_of_string s then valid_float_lexeme s else
+ sprintf "%.18g" f
+
+(* ------------------------------------------------------------------------- *)
+
+(* A few constants and combinators, used below. *)
+
+let some =
+ string "Some"
+
+let none =
+ string "None"
+
+let lbracketbar =
+ string "[|"
+
+let rbracketbar =
+ string "|]"
+
+let seq1 opening separator closing =
+ surround_separate 2 0 (opening ^^ closing) opening (separator ^^ break 1) closing
+
+let seq2 opening separator closing =
+ surround_separate_map 2 1 (opening ^^ closing) opening (separator ^^ break 1) closing
+
+(* ------------------------------------------------------------------------- *)
+
+(* The following functions are printers for many types of OCaml values. *)
+
+(* There is no protection against cyclic values. *)
+
+type representation =
+ document
+
+let tuple =
+ seq1 lparen comma rparen
+
+let variant _ cons _ args =
+ match args with
+ | [] ->
+ !^cons
+ | _ :: _ ->
+ !^cons ^^ tuple args
+
+let record _ fields =
+ seq2 lbrace semi rbrace (fun (k, v) -> infix 2 1 equals !^k v) fields
+
+let option f = function
+ | None ->
+ none
+ | Some x ->
+ some ^^ tuple [f x]
+
+let list f xs =
+ seq2 lbracket semi rbracket f xs
+
+let array f xs =
+ seq2 lbracketbar semi rbracketbar f (Array.to_list xs)
+
+let ref f x =
+ record "ref" ["contents", f !x]
+
+let float f =
+ string (float_representation f)
+
+let int =
+ dsprintf "%d"
+
+let int32 =
+ dsprintf "%ld"
+
+let int64 =
+ dsprintf "%Ld"
+
+let nativeint =
+ dsprintf "%nd"
+
+let char =
+ dsprintf "%C"
+
+let bool =
+ dsprintf "%B"
+
+let string =
+ dsprintf "%S"
+
+let unknown tyname _ =
+ dsprintf "<abstr:%s>" tyname
+
diff --git a/src/pprint/src/PPrintOCaml.mli b/src/pprint/src/PPrintOCaml.mli
new file mode 100644
index 00000000..e1395203
--- /dev/null
+++ b/src/pprint/src/PPrintOCaml.mli
@@ -0,0 +1,90 @@
+(**************************************************************************)
+(* *)
+(* PPrint *)
+(* *)
+(* Francois Pottier, INRIA Paris-Rocquencourt *)
+(* Nicolas Pouillard, IT University of Copenhagen *)
+(* *)
+(* Copyright 2007-2014 INRIA. All rights reserved. This file is *)
+(* distributed under the terms of the CeCILL-C license, as described *)
+(* in the file LICENSE. *)
+(* *)
+(**************************************************************************)
+
+(** A set of functions that construct representations of OCaml values. *)
+
+(** The string representations produced by these functions are supposed to be
+ accepted by the OCaml parser as valid values. *)
+
+(** The signature of this module is compatible with that expected by
+ the [camlp4] generator [Camlp4RepresentationGenerator]. *)
+
+(** These functions do {i not} distinguish between mutable and immutable
+ values. They do {i not} recognize sharing, and do {i not} incorporate a
+ protection against cyclic values. *)
+
+type constructor = string
+type type_name = string
+type record_field = string
+type tag = int
+
+(** A representation of a value is a [PPrint] document. *)
+type representation =
+ PPrintEngine.document
+
+(** [variant _ dc _ args] is a description of a constructed value whose data
+ constructor is [dc] and whose arguments are [args]. The other two
+ parameters are presently unused. *)
+val variant : type_name -> constructor -> tag -> representation list -> representation
+
+(** [record _ fields] is a description of a record value whose fields are
+ [fields]. The other parameter is presently unused. *)
+val record : type_name -> (record_field * representation) list -> representation
+
+(** [tuple args] is a description of a tuple value whose components are [args]. *)
+val tuple : representation list -> representation
+
+(** [string s] is a representation of the string [s]. *)
+val string : string -> representation
+
+(** [int i] is a representation of the integer [i]. *)
+val int : int -> representation
+
+(** [int32 i] is a representation of the 32-bit integer [i]. *)
+val int32 : int32 -> representation
+
+(** [int64 i] is a representation of the 64-bit integer [i]. *)
+val int64 : int64 -> representation
+
+(** [nativeint i] is a representation of the native integer [i]. *)
+val nativeint : nativeint -> representation
+
+(** [float f] is a representation of the floating-point number [f]. *)
+val float : float -> representation
+
+(** [char c] is a representation of the character [c]. *)
+val char : char -> representation
+
+(** [bool b] is a representation of the Boolenan value [b]. *)
+val bool : bool -> representation
+
+(** [option f o] is a representation of the option [o], where the
+ representation of the element, if present, is computed by the function
+ [f]. *)
+val option : ('a -> representation) -> 'a option -> representation
+
+(** [list f xs] is a representation of the list [xs], where the representation
+ of each element is computed by the function [f]. *)
+val list : ('a -> representation) -> 'a list -> representation
+
+(** [array f xs] is a representation of the array [xs], where the
+ representation of each element is computed by the function [f]. *)
+val array : ('a -> representation) -> 'a array -> representation
+
+(** [ref r] is a representation of the reference [r], where the
+ representation of the content is computed by the function [f]. *)
+val ref : ('a -> representation) -> 'a ref -> representation
+
+(** [unknown t _] is a representation of an unknown value of type [t]. *)
+val unknown : type_name -> 'a -> representation
+
diff --git a/src/pprint/src/PPrintRenderer.ml b/src/pprint/src/PPrintRenderer.ml
new file mode 100644
index 00000000..9096eada
--- /dev/null
+++ b/src/pprint/src/PPrintRenderer.ml
@@ -0,0 +1,37 @@
+(**************************************************************************)
+(* *)
+(* PPrint *)
+(* *)
+(* Francois Pottier, INRIA Paris-Rocquencourt *)
+(* Nicolas Pouillard, IT University of Copenhagen *)
+(* *)
+(* Copyright 2007-2014 INRIA. All rights reserved. This file is *)
+(* distributed under the terms of the CeCILL-C license, as described *)
+(* in the file LICENSE. *)
+(* *)
+(**************************************************************************)
+
+(** A common signature for the multiple document renderers proposed by {!PPrintEngine}. *)
+
+module type RENDERER = sig
+
+ (** Output channels. *)
+ type channel
+
+ (** Documents. *)
+ type document
+
+ (** [pretty rfrac width channel document] pretty-prints the document
+ [document] into the output channel [channel]. The parameter [width] is
+ the maximum number of characters per line. The parameter [rfrac] is the
+ ribbon width, a fraction relative to [width]. The ribbon width is the
+ maximum number of non-indentation characters per line. *)
+ val pretty: float -> int -> channel -> document -> unit
+
+ (** [compact channel document] prints the document [document] to the output
+ channel [channel]. No indentation is used. All newline instructions are
+ respected, that is, no groups are flattened. *)
+ val compact: channel -> document -> unit
+
+end
+
diff --git a/src/pprint/src/PPrintTest.ml b/src/pprint/src/PPrintTest.ml
new file mode 100644
index 00000000..3e4fb2c9
--- /dev/null
+++ b/src/pprint/src/PPrintTest.ml
@@ -0,0 +1,64 @@
+(**************************************************************************)
+(* *)
+(* PPrint *)
+(* *)
+(* Francois Pottier, INRIA Paris-Rocquencourt *)
+(* Nicolas Pouillard, IT University of Copenhagen *)
+(* *)
+(* Copyright 2007-2014 INRIA. All rights reserved. This file is *)
+(* distributed under the terms of the CeCILL-C license, as described *)
+(* in the file LICENSE. *)
+(* *)
+(**************************************************************************)
+
+open PPrint
+
+(* This is a test file. It is not, strictly speaking, part of the library. *)
+
+let paragraph (s : string) =
+ flow (break 1) (words s)
+
+let document =
+ prefix 2 1
+ (string "TITLE:")
+ (string "PPrint")
+ ^^
+ hardline
+ ^^
+ prefix 2 1
+ (string "AUTHORS:")
+ (utf8string "François Pottier and Nicolas Pouillard")
+ ^^
+ hardline
+ ^^
+ prefix 2 1
+ (string "ABSTRACT:")
+ (
+ paragraph "This is an adaptation of Daan Leijen's \"PPrint\" library,
+ which itself is based on the ideas developed by Philip Wadler in
+ \"A Prettier Printer\". For more information about Wadler's and Leijen's work,
+ please consult the following references:"
+ ^^
+ nest 2 (
+ twice (break 1)
+ ^^
+ separate_map (break 1) (fun s -> nest 2 (url s)) [
+ "http://www.cs.uu.nl/~daan/pprint.html";
+ "http://homepages.inf.ed.ac.uk/wadler/papers/prettier/prettier.pdf";
+ ]
+ )
+ ^^
+ twice (break 1)
+ ^^
+ paragraph "To install PPrint, type \"make -C src install\". ocamlfind is required."
+ ^^
+ twice (break 1)
+ ^^
+ paragraph "The documentation for PPrint is built by \"make doc\" and is found in the file doc/index.html."
+ )
+ ^^
+ hardline
+
+let () =
+ ToChannel.pretty 0.5 80 stdout document;
+ flush stdout
diff --git a/src/pretty_print.ml b/src/pretty_print.ml
index 759e2f4a..9f0382f5 100644
--- a/src/pretty_print.ml
+++ b/src/pretty_print.ml
@@ -133,7 +133,7 @@ let pp_format_nexp_constraint (NC_aux(nc,_)) =
| NC_bounded_le(n1,n2) -> pp_format_nexp n1 ^ " <= " ^ pp_format_nexp n2
| NC_nat_set_bounded(var,bounds) ->
pp_format_var var ^
- " In {" ^
+ " IN {" ^
list_format ", " string_of_int bounds ^
"}"
@@ -167,8 +167,8 @@ let pp_typscm ppf ts = base ppf (pp_format_typscm ts)
let pp_format_lit (L_aux(l,_)) =
match l with
| L_unit -> "()"
- | L_zero -> "0"
- | L_one -> "1"
+ | L_zero -> "bitzero"
+ | L_one -> "bitone"
| L_true -> "true"
| L_false -> "false"
| L_num(i) -> string_of_int i
@@ -255,6 +255,9 @@ and pp_exp ppf (E_aux(e,(_,annot))) =
| E_case(exp,pexps) -> fprintf ppf "@[<0>%a %a %a %a %a@]" kwd "switch " pp_exp exp kwd "{" (list_pp pp_case pp_case) pexps kwd "}"
| E_let(leb,exp) -> fprintf ppf "@[<0>%a@ %a@ %a@]" pp_let leb kwd "in" pp_exp exp
| E_assign(lexp,exp) -> fprintf ppf "@[<0>%a%a%a@]" pp_lexp lexp kwd " := " pp_exp exp
+ (* XXX missing cases *)
+ | E_internal_cast ((_, Overload (_, _)), _) | E_internal_exp _ -> assert false
+
and pp_semi_exp ppf e = fprintf ppf "@[<1>%a%a@]" pp_exp e kwd ";"
@@ -603,6 +606,8 @@ let pp_format_annot = function
| NoTyp -> "Nothing"
| Base((_,t),tag,nes,efct) ->
"(Just (" ^ pp_format_t t ^ ", " ^ pp_format_tag tag ^ ", " ^ pp_format_nes nes ^ ", " ^ pp_format_e efct ^ "))"
+ (* XXX missing case *)
+ | Overload _ -> assert false
let pp_annot ppf ant = base ppf (pp_format_annot ant)
@@ -689,6 +694,8 @@ and pp_lem_exp ppf (E_aux(e,(l,annot))) =
fprintf ppf "@[<0>(E_aux (%a %a [%a]) (%a, %a))@]" kwd "E_case" pp_lem_exp exp (list_pp pp_semi_lem_case pp_lem_case) pexps pp_lem_l l pp_annot annot
| E_let(leb,exp) -> fprintf ppf "@[<0>(E_aux (%a %a %a) (%a, %a))@]" kwd "E_let" pp_lem_let leb pp_lem_exp exp pp_lem_l l pp_annot annot
| E_assign(lexp,exp) -> fprintf ppf "@[<0>(E_aux (%a %a %a) (%a, %a))@]" kwd "E_assign" pp_lem_lexp lexp pp_lem_exp exp pp_lem_l l pp_annot annot
+ (* XXX missing cases *)
+ | E_internal_cast ((_, Overload (_, _)), _) | E_internal_exp _ -> assert false
in
print_e ppf e
@@ -814,3 +821,515 @@ let pp_lem_def ppf d =
let pp_lem_defs ppf (Defs(defs)) =
fprintf ppf "Defs [@[%a@]]@\n" (list_pp pp_lem_def pp_lem_def) defs
+
+
+(** PPrint based source-to-source pretty-printer *)
+
+open PPrint
+
+let doc_id (Id_aux(i,_)) =
+ match i with
+ | Id i -> string i
+ | DeIid x ->
+ (* add an extra space through empty to avoid a closing-comment
+ * token in case of x ending with star. *)
+ parens (separate space [string "deinfix"; string x; empty])
+
+let doc_var (Kid_aux(Var v,_)) = string v
+
+let doc_int i = string (string_of_int i)
+
+let doc_bkind (BK_aux(k,_)) =
+ string (match k with
+ | BK_type -> "Type"
+ | BK_nat -> "Nat"
+ | BK_order -> "Order"
+ | BK_effect -> "Effect")
+
+let doc_op symb a b = infix 2 1 symb a b
+let doc_unop symb a = prefix 2 1 symb a
+
+let arrow = string "->"
+let dotdot = string ".."
+let coloneq = string ":="
+let lsquarebarbar = string "[||"
+let rsquarebarbar = string "||]"
+let squarebarbars = enclose lsquarebarbar rsquarebarbar
+let spaces op = enclose space space op
+let semi_sp = semi ^^ space
+let comma_sp = comma ^^ space
+let colon_sp = spaces colon
+
+let doc_kind (K_aux(K_kind(klst),_)) =
+ separate_map (spaces arrow) doc_bkind klst
+
+let doc_effect (BE_aux (e,_)) =
+ string (match e with
+ | BE_rreg -> "rreg"
+ | BE_wreg -> "wreg"
+ | BE_rmem -> "rmem"
+ | BE_wmem -> "wmem"
+ | BE_undef -> "undef"
+ | BE_unspec -> "unspec"
+ | BE_nondet -> "nondet")
+
+let doc_effects (Effect_aux(e,_)) = match e with
+ | Effect_var v -> doc_var v
+ | Effect_set [] -> string "pure"
+ | Effect_set s -> braces (separate_map comma_sp doc_effect s)
+
+let doc_ord (Ord_aux(o,_)) = match o with
+ | Ord_var v -> doc_var v
+ | Ord_inc -> string "inc"
+ | Ord_dec -> string "dec"
+
+let doc_typ, doc_atomic_typ, doc_nexp =
+ (* following the structure of parser for precedence *)
+ let rec typ ty = fn_typ ty
+ and fn_typ ((Typ_aux (t, _)) as ty) = match t with
+ | Typ_fn(arg,ret,efct) ->
+ separate space [tup_typ arg; arrow; fn_typ ret; string "effect"; doc_effects efct]
+ | _ -> tup_typ ty
+ and tup_typ ((Typ_aux (t, _)) as ty) = match t with
+ | Typ_tup typs -> parens (separate_map comma_sp app_typ typs)
+ | _ -> app_typ ty
+ and app_typ ((Typ_aux (t, _)) as ty) = match t with
+ | Typ_app(id,args) ->
+ (* trailing space to avoid >> token in case of nested app types *)
+ (doc_id id) ^^ (angles (separate_map comma_sp doc_typ_arg args)) ^^ space
+ | _ -> atomic_typ ty (* for simplicity, skip vec_typ - which is only sugar *)
+ and atomic_typ ((Typ_aux (t, _)) as ty) = match t with
+ | Typ_id id -> doc_id id
+ | Typ_var v -> doc_var v
+ | Typ_wild -> underscore
+ | Typ_app _ | Typ_tup _ | Typ_fn _ ->
+ (* exhaustiveness matters here to avoid infinite loops
+ * if we add a new Typ constructor *)
+ group (parens (typ ty))
+ and doc_typ_arg (Typ_arg_aux(t,_)) = match t with
+ (* Be careful here because typ_arg is implemented as nexp in the
+ * parser - in practice falling through app_typ after all the proper nexp
+ * cases; so Typ_arg_typ has the same precedence as a Typ_app *)
+ | Typ_arg_typ t -> app_typ t
+ | Typ_arg_nexp n -> nexp n
+ | Typ_arg_order o -> doc_ord o
+ | Typ_arg_effect e -> doc_effects e
+
+ (* same trick to handle precedence of nexp *)
+ and nexp ne = sum_typ ne
+ and sum_typ ((Nexp_aux(n,_)) as ne) = match n with
+ | Nexp_sum(n1,n2) -> doc_op plus (sum_typ n1) (star_typ n2)
+ | _ -> star_typ ne
+ and star_typ ((Nexp_aux(n,_)) as ne) = match n with
+ | Nexp_times(n1,n2) -> doc_op star (star_typ n1) (exp_typ n2)
+ | _ -> exp_typ ne
+ and exp_typ ((Nexp_aux(n,_)) as ne) = match n with
+ | Nexp_exp n1 -> doc_unop (string "2**") (neg_typ n1)
+ | _ -> neg_typ ne
+ and neg_typ ((Nexp_aux(n,_)) as ne) = match n with
+ | Nexp_neg n1 ->
+ (* XXX this is not valid Sail, only an internal representation -
+ * work around by commenting it *)
+ let minus = concat [string "(*"; minus; string "*)"] in
+ minus ^^ (atomic_nexp_typ n1)
+ | _ -> atomic_nexp_typ ne
+ and atomic_nexp_typ ((Nexp_aux(n,_)) as ne) = match n with
+ | Nexp_var v -> doc_var v
+ | Nexp_constant i -> doc_int i
+ | Nexp_neg _ | Nexp_exp _ | Nexp_times _ | Nexp_sum _ ->
+ group (parens (nexp ne))
+
+ (* expose doc_typ, doc_atomic_typ and doc_nexp *)
+ in typ, atomic_typ, nexp
+
+let doc_nexp_constraint (NC_aux(nc,_)) = match nc with
+ | NC_fixed(n1,n2) -> doc_op equals (doc_nexp n1) (doc_nexp n2)
+ | NC_bounded_ge(n1,n2) -> doc_op (string ">=") (doc_nexp n1) (doc_nexp n2)
+ | NC_bounded_le(n1,n2) -> doc_op (string "<=") (doc_nexp n1) (doc_nexp n2)
+ | NC_nat_set_bounded(v,bounds) ->
+ doc_op (string "IN") (doc_var v)
+ (braces (separate_map comma_sp doc_int bounds))
+
+let doc_qi (QI_aux(qi,_)) = match qi with
+ | QI_const n_const -> doc_nexp_constraint n_const
+ | QI_id(KOpt_aux(ki,_)) ->
+ match ki with
+ | KOpt_none v -> doc_var v
+ | KOpt_kind(k,v) -> separate space [doc_kind k; doc_var v]
+
+(* typ_doc is the doc for the type being quantified *)
+let doc_typquant (TypQ_aux(tq,_)) typ_doc = match tq with
+ | TypQ_no_forall -> typ_doc
+ | TypQ_tq [] -> failwith "TypQ_tq with empty list"
+ | TypQ_tq qlist ->
+ (* include trailing break because the caller doesn't know if tq is empty *)
+ doc_op dot
+ (separate space [string "forall"; separate_map comma_sp doc_qi qlist])
+ typ_doc
+
+let doc_typscm (TypSchm_aux(TypSchm_ts(tq,t),_)) =
+ (doc_typquant tq (doc_typ t))
+
+let doc_typscm_atomic (TypSchm_aux(TypSchm_ts(tq,t),_)) =
+ (doc_typquant tq (doc_atomic_typ t))
+
+let doc_lit (L_aux(l,_)) =
+ utf8string (match l with
+ | L_unit -> "()"
+ | L_zero -> "bitzero"
+ | L_one -> "bitone"
+ | L_true -> "true"
+ | L_false -> "false"
+ | L_num i -> string_of_int i
+ | L_hex n -> "0x" ^ n
+ | L_bin n -> "0b" ^ n
+ | L_undef -> "undefined"
+ | L_string s -> "\"" ^ s ^ "\"")
+
+let doc_pat, doc_atomic_pat =
+ let rec pat pa = pat_colons pa
+ and pat_colons ((P_aux(p,l)) as pa) = match p with
+ | P_vector_concat pats -> separate_map colon_sp atomic_pat pats
+ | _ -> app_pat pa
+ and app_pat ((P_aux(p,l)) as pa) = match p with
+ | P_app(id, ((_ :: _) as pats)) -> doc_unop (doc_id id) (parens (separate_map comma_sp atomic_pat pats))
+ | _ -> atomic_pat pa
+ and atomic_pat ((P_aux(p,l)) as pa) = match p with
+ | P_lit lit -> doc_lit lit
+ | P_wild -> underscore
+ | P_id id -> doc_id id
+ | P_as(p,id) -> parens (separate space [pat p; string "as"; doc_id id])
+ | P_typ(typ,p) -> separate space [parens (doc_typ typ); atomic_pat p]
+ | P_app(id,[]) -> doc_id id
+ | P_record(fpats,_) -> braces (separate_map semi_sp fpat fpats)
+ | P_vector pats -> brackets (separate_map comma_sp atomic_pat pats)
+ | P_vector_indexed ipats -> brackets (separate_map comma_sp npat ipats)
+ | P_tup pats -> parens (separate_map comma_sp atomic_pat pats)
+ | P_list pats -> squarebarbars (separate_map semi_sp atomic_pat pats)
+ | P_app(_, _ :: _) | P_vector_concat _ ->
+ group (parens (pat pa))
+ and fpat (FP_aux(FP_Fpat(id,fpat),_)) = doc_op equals (doc_id id) (pat fpat)
+ and npat (i,p) = doc_op equals (doc_int i) (pat p)
+
+ (* expose doc_pat and doc_atomic_pat *)
+ in pat, atomic_pat
+
+let doc_exp, doc_let =
+ let rec exp e = group (or_exp e)
+ and or_exp ((E_aux(e,_)) as expr) = match e with
+ | E_app_infix(l,(Id_aux(Id ("|" | "||"),_) as op),r) ->
+ doc_op (doc_id op) (and_exp l) (or_exp r)
+ | _ -> and_exp expr
+ and and_exp ((E_aux(e,_)) as expr) = match e with
+ | E_app_infix(l,(Id_aux(Id ("&" | "&&"),_) as op),r) ->
+ doc_op (doc_id op) (eq_exp l) (and_exp r)
+ | _ -> eq_exp expr
+ and eq_exp ((E_aux(e,_)) as expr) = match e with
+ | E_app_infix(l,(Id_aux(Id (
+ (* XXX this is not very consistent - is the parser bogus here? *)
+ "=" | "==" | "!="
+ | ">=" | ">=_s" | ">=_u" | ">" | ">_s" | ">_u"
+ | "<=" | "<=_s" | "<" | "<_s" | "<_si" | "<_u"
+ ),_) as op),r) ->
+ doc_op (doc_id op) (eq_exp l) (at_exp r)
+ (* XXX assignment should not have the same precedence as equal etc. *)
+ | E_assign(le,exp) -> doc_op coloneq (doc_lexp le) (at_exp exp)
+ | _ -> at_exp expr
+ and at_exp ((E_aux(e,_)) as expr) = match e with
+ | E_app_infix(l,(Id_aux(Id ("@" | "^^" | "^" | "~^"),_) as op),r) ->
+ doc_op (doc_id op) (cons_exp l) (at_exp r)
+ | _ -> cons_exp expr
+ and cons_exp ((E_aux(e,_)) as expr) = match e with
+ | E_app_infix(l,(Id_aux(Id (":"),_) as op),r) ->
+ doc_op (doc_id op) (shift_exp l) (cons_exp r)
+ | E_cons(l,r) ->
+ doc_op colon (shift_exp l) (cons_exp r)
+ | _ -> shift_exp expr
+ and shift_exp ((E_aux(e,_)) as expr) = match e with
+ | E_app_infix(l,(Id_aux(Id (">>" | ">>>" | "<<" | "<<<"),_) as op),r) ->
+ doc_op (doc_id op) (shift_exp l) (plus_exp r)
+ | _ -> plus_exp expr
+ and plus_exp ((E_aux(e,_)) as expr) = match e with
+ | E_app_infix(l,(Id_aux(Id ("+" | "-"),_) as op),r) ->
+ doc_op (doc_id op) (plus_exp l) (star_exp r)
+ | _ -> star_exp expr
+ and star_exp ((E_aux(e,_)) as expr) = match e with
+ | E_app_infix(l,(Id_aux(Id (
+ "*" | "/"
+ | "div" | "quot" | "rem" | "mod"
+ | "*_s" | "*_si" | "*_u" | "*_ui"),_) as op),r) ->
+ doc_op (doc_id op) (star_exp l) (starstar_exp r)
+ | _ -> starstar_exp expr
+ and starstar_exp ((E_aux(e,_)) as expr) = match e with
+ | E_app_infix(l,(Id_aux(Id "**",_) as op),r) ->
+ doc_op (doc_id op) (starstar_exp l) (app_exp r)
+ | E_if _ | E_for _ | E_let _ -> right_atomic_exp expr
+ | _ -> app_exp expr
+ and right_atomic_exp ((E_aux(e,_)) as expr) = match e with
+ (* Special case: omit "else ()" when the else branch is empty. *)
+ | E_if(c,t,E_aux(E_block [], _)) ->
+ string "if" ^^ space ^^ group (exp c) ^/^
+ string "then" ^^ space ^^ group (exp t)
+ | E_if(c,t,e) ->
+ string "if" ^^ space ^^ group (exp c) ^/^
+ string "then" ^^ space ^^ group (exp t) ^/^
+ string "else" ^^ space ^^ group (exp e)
+ | E_for(id,exp1,exp2,exp3,order,exp4) ->
+ string "foreach" ^^ space ^^
+ group (parens (
+ separate (break 1) [
+ doc_id id;
+ string "from " ^^ atomic_exp exp1;
+ string "to " ^^ atomic_exp exp2;
+ string "by " ^^ atomic_exp exp3;
+ string "in " ^^ doc_ord order
+ ]
+ )) ^/^
+ exp exp4
+ | E_let(leb,e) -> doc_op (string "in") (let_exp leb) (exp e)
+ | _ -> group (parens (exp expr))
+ and app_exp ((E_aux(e,_)) as expr) = match e with
+ | E_app(f,args) ->
+ doc_unop (doc_id f) (parens (separate_map comma exp args))
+ | _ -> vaccess_exp expr
+ and vaccess_exp ((E_aux(e,_)) as expr) = match e with
+ | E_vector_access(v,e) ->
+ atomic_exp v ^^ brackets (exp e)
+ | E_vector_subrange(v,e1,e2) ->
+ atomic_exp v ^^ brackets (doc_op dotdot (exp e1) (exp e2))
+ | _ -> field_exp expr
+ and field_exp ((E_aux(e,_)) as expr) = match e with
+ | E_field(fexp,id) -> atomic_exp fexp ^^ dot ^^ doc_id id
+ | _ -> atomic_exp expr
+ and atomic_exp ((E_aux(e,_)) as expr) = match e with
+ (* Special case: an empty block is equivalent to unit, but { } would
+ * be parsed as a struct. *)
+ | E_block [] -> string "()"
+ | E_block exps ->
+ let exps_doc = separate_map (semi ^^ hardline) exp exps in
+ surround 2 1 lbrace exps_doc rbrace
+ | E_id id -> doc_id id
+ | E_lit lit -> doc_lit lit
+ | E_cast(typ,e) -> prefix 2 1 (parens (doc_typ typ)) (group (atomic_exp e))
+ | E_internal_cast((_,NoTyp),e) -> atomic_exp e
+ | E_internal_cast((_,Base((_,t),_,_,_)), (E_aux(_,(_,eannot)) as e)) ->
+ (match t.t,eannot with
+ (* XXX I don't understand why we can hide the internal cast here *)
+ | Tapp("vector",[TA_nexp n1;_;_;_]),Base((_,{t=Tapp("vector",[TA_nexp n2;_;_;_])}),_,_,_)
+ when nexp_eq n1 n2 -> atomic_exp e
+ | _ -> prefix 2 1 (parens (doc_typ (t_to_typ t))) (group (atomic_exp e)))
+ | E_tuple exps ->
+ parens (separate_map comma exp exps)
+ | E_record(FES_aux(FES_Fexps(fexps,_),_)) ->
+ (* XXX E_record is not handled by parser currently *)
+ braces (separate_map semi_sp doc_fexp fexps)
+ | E_record_update(e,(FES_aux(FES_Fexps(fexps,_),_))) ->
+ braces (doc_op (string "with") (exp e) (separate_map semi_sp doc_fexp fexps))
+ | E_vector exps ->
+ brackets (separate_map comma exp exps)
+ | E_vector_indexed (iexps, default) ->
+ (* XXX TODO print default when it is non-empty *)
+ let iexp (i,e) = doc_op equals (doc_int i) (exp e) in
+ brackets (separate_map comma iexp iexps)
+ | E_vector_update(v,e1,e2) ->
+ brackets (doc_op (string "with") (exp v) (doc_op equals (atomic_exp e1) (exp e2)))
+ | E_vector_update_subrange(v,e1,e2,e3) ->
+ brackets (
+ doc_op (string "with") (exp v)
+ (doc_op equals (atomic_exp e1 ^^ colon ^^ atomic_exp e2) (exp e3)))
+ | E_list exps ->
+ squarebarbars (separate_map comma exp exps)
+ | E_case(e,pexps) ->
+ let opening = separate space [string "switch"; exp e; lbrace] in
+ let cases = separate_map (break 1) doc_case pexps in
+ surround 2 1 opening cases rbrace
+ (* adding parens and loop for lower precedence *)
+ | E_app (_, _)|E_vector_access (_, _)|E_vector_subrange (_, _, _)
+ | E_cons (_, _)|E_field (_, _)|E_assign (_, _)
+ | E_app_infix (_,
+ (* for every app_infix operator caught at a higher precedence,
+ * we need to wrap around with parens *)
+ (Id_aux(Id("|" | "||"
+ | "&" | "&&"
+ | "=" | "==" | "!="
+ | ">=" | ">=_s" | ">=_u" | ">" | ">_s" | ">_u"
+ | "<=" | "<=_s" | "<" | "<_s" | "<_si" | "<_u"
+ | "@" | "^^" | "^" | "~^"
+ | ":"
+ | ">>" | ">>>" | "<<" | "<<<"
+ | "+" | "-"
+ | "*" | "/"
+ | "div" | "quot" | "rem" | "mod"
+ | "*_s" | "*_si" | "*_u" | "*_ui"
+ | "**"), _))
+ , _) ->
+ group (parens (exp expr))
+ (* XXX default precedence for app_infix? *)
+ | E_app_infix(l,op,r) ->
+ failwith ("unexpected app_infix operator " ^ (pp_format_id op))
+ (* doc_op (doc_id op) (exp l) (exp r) *)
+ (* XXX missing case *)
+ | E_internal_cast ((_, Overload (_, _)), _) | E_internal_exp _ -> assert false
+
+ and let_exp (LB_aux(lb,_)) = match lb with
+ | LB_val_explicit(ts,pat,e) ->
+ prefix 2 1
+ (separate space [string "let"; doc_typscm_atomic ts; doc_atomic_pat pat; equals])
+ (exp e)
+ | LB_val_implicit(pat,e) ->
+ prefix 2 1
+ (separate space [string "let"; doc_atomic_pat pat; equals])
+ (exp e)
+
+ and doc_fexp (FE_aux(FE_Fexp(id,e),_)) = doc_op equals (doc_id id) (exp e)
+
+ and doc_case (Pat_aux(Pat_exp(pat,e),_)) =
+ doc_op arrow (separate space [string "case"; doc_atomic_pat pat]) (group (exp e))
+
+ (* lexps are parsed as eq_exp - we need to duplicate the precedence
+ * structure for them *)
+ and doc_lexp le = app_lexp le
+ and app_lexp ((LEXP_aux(lexp,_)) as le) = match lexp with
+ | LEXP_memory(id,args) -> doc_id id ^^ parens (separate_map comma exp args)
+ | _ -> vaccess_lexp le
+ and vaccess_lexp ((LEXP_aux(lexp,_)) as le) = match lexp with
+ | LEXP_vector(v,e) -> atomic_lexp v ^^ brackets (exp e)
+ | LEXP_vector_range(v,e1,e2) ->
+ atomic_lexp v ^^ brackets (exp e1 ^^ dotdot ^^ exp e2)
+ | _ -> field_lexp le
+ and field_lexp ((LEXP_aux(lexp,_)) as le) = match lexp with
+ | LEXP_field(v,id) -> atomic_lexp v ^^ dot ^^ doc_id id
+ | _ -> atomic_lexp le
+ and atomic_lexp ((LEXP_aux(lexp,_)) as le) = match lexp with
+ | LEXP_id id -> doc_id id
+ | LEXP_cast(typ,id) -> prefix 2 1 (parens (doc_typ typ)) (doc_id id)
+ | LEXP_memory _ | LEXP_vector _ | LEXP_vector_range _
+ | LEXP_field _ -> group (parens (doc_lexp le))
+
+ (* expose doc_exp and doc_let *)
+ in exp, let_exp
+
+let doc_default (DT_aux(df,_)) = match df with
+ | DT_kind(bk,v) -> separate space [string "default"; doc_bkind bk; doc_var v]
+ | DT_typ(ts,id) -> separate space [string "default"; doc_typscm ts; doc_id id]
+
+let doc_spec (VS_aux(v,_)) = match v with
+ | VS_val_spec(ts,id) ->
+ separate space [string "val"; doc_typscm ts; doc_id id]
+ | VS_extern_no_rename(ts,id) ->
+ separate space [string "val"; string "extern"; doc_typscm ts; doc_id id]
+ | VS_extern_spec(ts,id,s) ->
+ separate space [string "val"; string "extern"; doc_typscm ts;
+ doc_op equals (doc_id id) (dquotes (string s))]
+
+let doc_namescm (Name_sect_aux(ns,_)) = match ns with
+ | Name_sect_none -> empty
+ (* include leading space because the caller doesn't know if ns is
+ * empty, and trailing break already added by the following equals *)
+ | Name_sect_some s -> space ^^ brackets (doc_op equals (string "name") (dquotes (string s)))
+
+let rec doc_range (BF_aux(r,_)) = match r with
+ | BF_single i -> doc_int i
+ | BF_range(i1,i2) -> doc_op dotdot (doc_int i1) (doc_int i2)
+ | BF_concat(ir1,ir2) -> (doc_range ir1) ^^ comma ^^ (doc_range ir2)
+
+let doc_type_union (Tu_aux(typ_u,_)) = match typ_u with
+ | Tu_ty_id(typ,id) -> concat [doc_typ typ; space; doc_id id; semi]
+ | Tu_id id -> doc_id id ^^ semi
+
+let doc_typdef (TD_aux(td,_)) = match td with
+ | TD_abbrev(id,nm,typschm) ->
+ doc_op equals (concat [string "typedef"; space; doc_id id; doc_namescm nm]) (doc_typscm typschm)
+ | TD_record(id,nm,typq,fs,_) ->
+ let f_pp (typ,id) = concat [doc_typ typ; space; doc_id id; semi] in
+ let fs_doc = group (separate_map (break 1) f_pp fs) in
+ doc_op equals
+ (concat [string "typedef"; space; doc_id id; doc_namescm nm])
+ (string "const struct" ^^ space ^^ doc_typquant typq (braces fs_doc))
+ | TD_variant(id,nm,typq,ar,_) ->
+ let ar_doc = group (separate_map (break 1) doc_type_union ar) in
+ doc_op equals
+ (concat [string "typedef"; space; doc_id id; doc_namescm nm])
+ (string "const union" ^^ space ^^ doc_typquant typq (braces ar_doc))
+ | TD_enum(id,nm,enums,_) ->
+ let enums_doc = group (separate_map (semi ^^ break 1) doc_id enums) in
+ doc_op equals
+ (concat [string "typedef"; space; doc_id id; doc_namescm nm])
+ (string "enumerate" ^^ space ^^ braces enums_doc)
+ | TD_register(id,n1,n2,rs) ->
+ let doc_rid (r,id) = separate space [doc_range r; colon; doc_id id] ^^ semi in
+ let doc_rids = group (separate_map (break 1) doc_rid rs) in
+ doc_op equals
+ (string "typedef" ^^ space ^^ doc_id id)
+ (separate space [
+ string "register bits";
+ brackets (doc_nexp n1 ^^ colon ^^ doc_nexp n2);
+ braces doc_rids;
+ ])
+
+let doc_rec (Rec_aux(r,_)) = match r with
+ | Rec_nonrec -> empty
+ (* include trailing space because caller doesn't know if we return
+ * empty *)
+ | Rec_rec -> string "rec" ^^ space
+
+let doc_tannot_opt (Typ_annot_opt_aux(t,_)) = match t with
+ | Typ_annot_opt_some(tq,typ) -> doc_typquant tq (doc_typ typ)
+
+let doc_effects_opt (Effect_opt_aux(e,_)) = match e with
+ | Effect_opt_pure -> string "pure"
+ | Effect_opt_effect e -> doc_effects e
+
+let doc_funcl (FCL_aux(FCL_Funcl(id,pat,exp),_)) =
+ group (doc_op equals (separate space [doc_id id; doc_atomic_pat pat]) (doc_exp exp))
+
+let doc_fundef (FD_aux(FD_function(r, typa, efa, fcls),_)) =
+ match fcls with
+ | [] -> failwith "FD_function with empty function list"
+ | _ ->
+ let sep = hardline ^^ string "and" ^^ space in
+ let clauses = separate_map sep doc_funcl fcls in
+ separate space [string "function";
+ doc_rec r ^^ doc_tannot_opt typa;
+ string "effect"; doc_effects_opt efa;
+ clauses]
+
+let doc_dec (DEC_aux(DEC_reg(typ,id),_)) =
+ separate space [string "register"; doc_atomic_typ typ; doc_id id]
+
+let doc_scattered (SD_aux (sdef, _)) = match sdef with
+ | SD_scattered_function (r, typa, efa, id) ->
+ separate space [
+ string "scattered function";
+ doc_rec r ^^ doc_tannot_opt typa;
+ string "effect"; doc_effects_opt efa;
+ doc_id id]
+ | SD_scattered_variant (id, ns, tq) ->
+ doc_op equals
+ (string "scattered typedef" ^^ space ^^ doc_id id ^^ doc_namescm ns)
+ (doc_typquant tq empty)
+ | SD_scattered_funcl funcl ->
+ string "function clause" ^^ space ^^ doc_funcl funcl
+ | SD_scattered_unioncl (id, tu) ->
+ separate space [string "union"; doc_id id;
+ string "member"; doc_type_union tu]
+ | SD_scattered_end id -> string "end" ^^ space ^^ doc_id id
+
+let doc_def def = group (match def with
+ | DEF_default df -> doc_default df
+ | DEF_spec v_spec -> doc_spec v_spec
+ | DEF_type t_def -> doc_typdef t_def
+ | DEF_fundef f_def -> doc_fundef f_def
+ | DEF_val lbind -> doc_let lbind
+ | DEF_reg_dec dec -> doc_dec dec
+ | DEF_scattered sdef -> doc_scattered sdef
+ ) ^^ hardline
+
+let doc_defs (Defs(defs)) =
+ separate_map hardline doc_def defs
+
+let print ?(len=80) channel doc = ToChannel.pretty 1. len channel doc
+let to_buf ?(len=80) buf doc = ToBuffer.pretty 1. len buf doc
+
+let pp_defs f d = print f (doc_defs d)
+let pp_exp b e = to_buf b (doc_exp e)
diff --git a/src/pretty_print.mli b/src/pretty_print.mli
index bf32a805..3fdf7841 100644
--- a/src/pretty_print.mli
+++ b/src/pretty_print.mli
@@ -1,10 +1,9 @@
open Ast
open Type_internal
-open Format
-(* Prints on formatter the defs following source syntax *)
-val pp_defs : Format.formatter -> tannot defs -> unit
-val pp_exp : Format.formatter -> exp -> unit
+(* Prints the defs following source syntax *)
+val pp_defs : out_channel -> tannot defs -> unit
+val pp_exp : Buffer.t -> exp -> unit
(* Prints on formatter the defs as Lem Ast nodes *)
val pp_lem_defs : Format.formatter -> tannot defs -> unit
diff --git a/src/sail.ml b/src/sail.ml
index b0957f91..a3a52c1b 100644
--- a/src/sail.ml
+++ b/src/sail.ml
@@ -399,7 +399,7 @@ let main() =
let chkedasts = (List.map (fun (f,(ast,kenv)) -> (f,check_ast ast kenv)) asts) in
begin
(if !(opt_print_verbose)
- then ((Pretty_print.pp_defs Format.std_formatter) (snd (List.hd chkedasts)))
+ then ((Pretty_print.pp_defs stdout) (snd (List.hd chkedasts)))
else ());
(if !(opt_print_lem)
then output "" Lem_ast_out chkedasts
diff --git a/src/type_check.ml b/src/type_check.ml
index 218efb84..5499c3e2 100644
--- a/src/type_check.ml
+++ b/src/type_check.ml
@@ -547,7 +547,7 @@ let rec check_exp envs expect_t (E_aux(e,(l,annot)) : tannot exp) : (tannot exp
(match (select_overload_variant d_env variants arg_t) with
| NoTyp -> typ_error l ("No matching function found with name " ^ i ^ " that expects parameters " ^ (t_to_string arg_t))
| Base((params,t),tag,cs,ef) ->
- let _ = Printf.printf "Selected an overloaded function for %s, variant with function type %s\n" i (t_to_string t) in
+ let _ = Printf.eprintf "Selected an overloaded function for %s, variant with function type %s\n" i (t_to_string t) in
(match t.t with
| Tfn(arg,ret,ef') ->
(match arg.t,arg_t.t with
@@ -660,7 +660,7 @@ let rec check_exp envs expect_t (E_aux(e,(l,annot)) : tannot exp) : (tannot exp
[GtEq((Expr l),base,min); LtEq((Expr l),{nexp=Nadd(min,m_rise)},{nexp=Nadd(base,{nexp=Nneg rise})})]
| _ -> typ_error l "A vector must be either increasing or decreasing to access a single element"
in
- (*let _ = Printf.printf "Type checking vector access. item_t is %s and expect_t is %s\n" (t_to_string item_t) (t_to_string expect_t) in*)
+ (*let _ = Printf.eprintf "Type checking vector access. item_t is %s and expect_t is %s\n" (t_to_string item_t) (t_to_string expect_t) in*)
let t',cs',e'=type_coerce (Expr l) d_env item_t (E_aux(E_vector_access(vec',i'),(l,Base(([],item_t),Emp_local,[],pure_e)))) expect_t in
(e',t',t_env,cs_loc@cs_i@cs@cs',union_effects ef ef_i)
| E_vector_subrange(vec,i1,i2) ->
@@ -907,12 +907,12 @@ let rec check_exp envs expect_t (E_aux(e,(l,annot)) : tannot exp) : (tannot exp
| E_case(exp,pexps) ->
(*let check_t = new_t() in*)
let (e',t',_,cs,ef) = check_exp envs (new_t()) exp in
- (*let _ = Printf.printf "Type of pattern after expression check %s\n" (t_to_string t') in*)
+ (*let _ = Printf.eprintf "Type of pattern after expression check %s\n" (t_to_string t') in*)
let t' =
match t'.t with
| Tapp("register",[TA_typ t]) -> t
| _ -> t' in
- (*let _ = Printf.printf "Type of pattern after register check %s\n" (t_to_string t') in*)
+ (*let _ = Printf.eprintf "Type of pattern after register check %s\n" (t_to_string t') in*)
let (pexps',t,cs',ef') = check_cases envs t' expect_t pexps in
(E_aux(E_case(e',pexps'),(l,Base(([],t),Emp_local,[],pure_e))),t,t_env,cs@cs',union_effects ef ef')
| E_let(lbind,body) ->
@@ -968,7 +968,7 @@ and check_lexp envs is_top (LEXP_aux(lexp,(l,annot))) : (tannot lexp * typ * tan
let t_actual = match t.t with
| Tabbrev(i,t) -> t
| _ -> t in
- (*let _ = Printf.printf "Assigning to %s, t is %s\n" i (t_to_string t_actual) in*)
+ (*let _ = Printf.eprintf "Assigning to %s, t is %s\n" i (t_to_string t_actual) in*)
(match t_actual.t,is_top with
| Tapp("register",[TA_typ u]),_ ->
let ef = {effect=Eset[BE_aux(BE_wreg,l)]} in
@@ -1304,15 +1304,15 @@ let check_fundef envs (FD_aux(FD_function(recopt,tannotopt,effectopt,funcls),(l,
List.split
(List.map (fun (FCL_aux((FCL_Funcl(id,pat,exp)),l)) ->
let (pat',t_env',cs_p,t') = check_pattern (Env(d_env,t_env)) Emp_local param_t pat in
- (*let _ = Printf.printf "about to check that %s and %s are consistent\n" (t_to_string t') (t_to_string param_t) in*)
+ (*let _ = Printf.eprintf "about to check that %s and %s are consistent\n" (t_to_string t') (t_to_string param_t) in*)
let exp',_,_,cs_e,ef = check_exp (Env(d_env,Envmap.union_merge (tannot_merge (Expr l) d_env) t_env t_env')) ret_t exp in
- (*let _ = Printf.printf "checked function %s : %s -> %s\n" (id_to_string id) (t_to_string param_t) (t_to_string ret_t) in*)
+ (*let _ = Printf.eprintf "checked function %s : %s -> %s\n" (id_to_string id) (t_to_string param_t) (t_to_string ret_t) in*)
(*let _ = (Pretty_print.pp_exp Format.std_formatter) exp' in*)
let cs = [CondCons(Fun l,cs_p,cs_e)] in
(FCL_aux((FCL_Funcl(id,pat',exp')),l),(cs,ef))) funcls) in
match (in_env,tannot) with
| Some(Base( (params,u),Spec,constraints,eft)), Base( (p',t),_,c',eft') ->
- (*let _ = Printf.printf "Function %s is in env\n" id in*)
+ (*let _ = Printf.eprintf "Function %s is in env\n" id in*)
let u,constraints,eft = subst params u constraints eft in
let t',cs = type_consistent (Specc l) d_env t u in
let t_env = if is_rec then t_env else Envmap.remove t_env id in