[Pkg-ocaml-maint-commits] [ocaml-visitors] 01/07: New upstream version 20180306
Ralf Treinen
treinen at moszumanska.debian.org
Wed Mar 21 23:09:07 UTC 2018
This is an automated email from the git hooks/post-receive script.
treinen pushed a commit to branch master
in repository ocaml-visitors.
commit 024ae8b24a6d76a3424ba8dab98031807abaec26
Author: Ralf Treinen <treinen at free.fr>
Date: Wed Mar 21 08:26:58 2018 +0100
New upstream version 20180306
---
CHANGES.md | 18 +++++++
GNUmakefile | 15 +++++-
TODO | 8 ++++
doc/main.tex | 7 +++
src/Visitors.ml | 74 ++++++++++++++++++++++++++---
src/VisitorsAnalysis.ml | 25 +++++-----
src/VisitorsCompatibility.cppo.ml | 63 ++++++++++++++++++++++++
src/VisitorsGeneration.ml | 2 +-
src/VisitorsString.ml | 43 +++++++++++++++++
test/bad/Makefile | 7 +++
test/bad/conflict.ml | 25 ++++++++++
test/bad/conflict_at_name.ml | 17 +++++++
test/bad/conflict_atat_name.ml | 15 ++++++
test/bad/datacon.ml | 11 +++++
test/bad/datacon_at_name.ml | 10 ++++
test/bad/visitors.t | 49 +++++++++++++++++++
test/expr.mllib | 1 +
test/expr01use.ml | 1 +
test/{expr01use.ml => expr01use_variant.ml} | 16 +++----
19 files changed, 375 insertions(+), 32 deletions(-)
diff --git a/CHANGES.md b/CHANGES.md
index eea14f5..cae0e4c 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,5 +1,23 @@
# Changes
+## 2018/03/06
+
+* Warn when the visitor methods for two distinct types or two distinct data
+ constructors have the same name, as this results in an OCaml type error
+ or multiply-defined-method error. (Reported by Gabriel Radanne.)
+
+## 2017/11/24
+
+* Added compatibility with OCaml 4.06.0.
+
+* Fixed the internal function `occurs_type` in the case of polymorphic types.
+ This should make no observable difference, as this function is used only
+ to produce an error message in a corner case.
+
+## 2017/08/28
+
+* Added compatibility with OCaml 4.05.0.
+
## 2017/07/25
* Updated `src/Makefile` to allow compilation on systems where `ocamlopt` is
diff --git a/GNUmakefile b/GNUmakefile
index b2e3c38..8b4f543 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -5,7 +5,7 @@
SHELL := bash
export CDPATH=
-.PHONY: package check export tag opam pin unpin
+.PHONY: package check export tag opam pin unpin versions
# -------------------------------------------------------------------------
@@ -158,3 +158,16 @@ pin:
unpin:
opam pin remove visitors
+
+# -------------------------------------------------------------------------
+
+# Trying out compilation under multiple versions of OCaml.
+
+versions:
+ for i in 4.02.3 4.03.0 4.04.0 4.05.0 4.06.0 ; do \
+ opam switch $$i && eval `opam config env` && ocamlc -v && \
+ opam install hashcons ppx_deriving ppx_import ocp-indent && \
+ make clean && \
+ make && \
+ make reinstall ; \
+ done
diff --git a/TODO b/TODO
index e320c0b..42d6370 100644
--- a/TODO
+++ b/TODO
@@ -8,6 +8,14 @@ Better clean up & share code at the three call sites of [bulk].
TODO (PERHAPS)
+Philip's question: when you compose two transformations formulated as map
+visitors, can you deforest? (eliminate the allocation of the intermediate
+tree)
+
+Document Jonathan's example where every node in an "expression" carries a type
+and the visitor for expressions carries the type down (whereas the visitor for
+types doesn't). https://github.com/FStarLang/kremlin/blob/visitors/src/Ast.ml
+
Document hexpr_polymorphic. Make VisitorsHashcons available as a library.
If there is an error, then the warnings are never seen,
diff --git a/doc/main.tex b/doc/main.tex
index eaacde6..6b9cf3f 100644
--- a/doc/main.tex
+++ b/doc/main.tex
@@ -132,6 +132,13 @@ Finally, a user of \merlin should add the following lines in her project's
PKG visitors.ppx
PKG visitors.runtime
\end{lstlisting}
+To use the \visitors package in OCaml's interactive ``toplevel'' environment,
+launch \texttt{ocaml} and type the following commands:
+\begin{lstlisting}
+ #use "topfind";;
+ #require "visitors.ppx";;
+ #require "visitors.runtime";;
+\end{lstlisting}
% ------------------------------------------------------------------------------
diff --git a/src/Visitors.ml b/src/Visitors.ml
index 0ad37aa..b459b78 100644
--- a/src/Visitors.ml
+++ b/src/Visitors.ml
@@ -1,3 +1,4 @@
+open VisitorsString
open VisitorsList
open Longident
open List
@@ -82,6 +83,44 @@ let sum_build_warning (decl : type_declaration) : unit =
(* -------------------------------------------------------------------------- *)
+(* Shared glue code for detecting and warning against name clashes. *)
+
+type 'a wrapper =
+ 'a -> 'a
+
+type tycon_visitor_method =
+ Location.t * attributes * Longident.t -> methode
+
+let protect_tycon_visitor_method : tycon_visitor_method wrapper =
+ fun tycon_visitor_method ->
+ let format : (_, _, _, _) format4 =
+ "%s: name clash: the types %s and %s\n\
+ both have visitor methods named %s.\n\
+ Please consider using [@@name] at type declaration sites\n\
+ or [@name] at type reference sites."
+ in
+ let id = print_longident in
+ protect tycon_visitor_method
+ (fun (_, _, x) (_, _, y) -> x = y)
+ (fun (_, _, x) (loc, _, y) m -> warning loc format plugin (id x) (id y) m)
+
+type datacon_descending_method =
+ constructor_declaration -> methode
+
+let protect_datacon_descending_method : datacon_descending_method wrapper =
+ fun datacon_descending_method ->
+ let format : (_, _, _, _) format4 =
+ "%s: name clash: the data constructors %s and %s\n\
+ both have visitor methods named %s.\n\
+ Please consider using [@name] at data constructor declaration sites."
+ in
+ let id cd = cd.pcd_name.txt in
+ protect datacon_descending_method
+ (fun cd1 cd2 -> cd1 == cd2)
+ (fun cd1 cd2 m -> warning cd2.pcd_loc format plugin (id cd1) (id cd2) m)
+
+(* -------------------------------------------------------------------------- *)
+
(* We support parameterized type declarations. We require them to be regular.
That is, for instance, if a type ['a term] is being defined, then every
use of [_ term] in the definition should be ['a term]; it cannot be, say,
@@ -125,6 +164,10 @@ let check_regularity loc tycon (formals : tyvars) (actuals : core_types) =
nonlocal type, a [@name] attribute must be attached to every reference to
this type.
+ The [@name] attribute can be misused: e.g., one can mistakenly use
+ different visitor method names for different occurrences of a single type.
+ We currently do not attempt to detect this situation.
+
The prefix that is prepended to the base name can be controlled via the
settings [visit_prefix], [build_prefix], and [fail_prefix]. *)
@@ -144,16 +187,32 @@ let datacon_modified_name (cd : constructor_declaration) : datacon =
(* The name of this method is normally [visit_foo] if the type is named [foo]
or [A.foo]. (A qualified name must denote a nonlocal type.) *)
-let tycon_visitor_method (attrs : attributes) (tycon : tycon) : methode =
- X.visit_prefix ^ tycon_modified_name attrs tycon
+(* This convention can cause name clashes, as the types [foo] and [A.foo]
+ receive visitor methods by the same name. We warn if this happens.
+
+ A name clash can also be caused by incorrect use of the [@@name] or
+ [@name] attributes. We also warn if this happens. *)
+
+(* Step 1 -- the raw convention. *)
+
+let tycon_visitor_method : tycon_visitor_method =
+ fun (_, attrs, tycon) ->
+ X.visit_prefix ^ tycon_modified_name attrs (Longident.last tycon)
+
+(* Step 2 -- protect against name clashes. *)
+
+let tycon_visitor_method =
+ protect_tycon_visitor_method tycon_visitor_method
+
+(* Step 3 -- define auxiliary functions that are easier to use. *)
let local_tycon_visitor_method (decl : type_declaration) : methode =
- tycon_visitor_method decl.ptype_attributes decl.ptype_name.txt
+ tycon_visitor_method (decl.ptype_loc, decl.ptype_attributes, Lident decl.ptype_name.txt)
let nonlocal_tycon_visitor_method (ty : core_type) : methode =
match ty.ptyp_desc with
| Ptyp_constr (tycon, _) ->
- tycon_visitor_method ty.ptyp_attributes (Longident.last tycon.txt)
+ tycon_visitor_method (ty.ptyp_loc, ty.ptyp_attributes, tycon.txt)
| _ ->
assert false
@@ -182,6 +241,9 @@ let tyvar_visitor_method (alpha : tyvar) : methode =
let datacon_descending_method (cd : constructor_declaration) : methode =
X.visit_prefix ^ datacon_modified_name cd
+let datacon_descending_method =
+ protect_datacon_descending_method datacon_descending_method
+
(* For every data constructor [datacon], there is a ascending visitor method,
which is invoked on the way up, in order to re-build some data structure.
This method is virtual and exists only when the scheme is [fold]. *)
@@ -387,7 +449,7 @@ let ty_env =
let tyvar_visitor_method_type =
if X.poly "env" then
- Typ.poly ["env"] (ty_arrow ty_env ty_any)
+ typ_poly ["env"] (ty_arrow ty_env ty_any)
else
ty_any
@@ -538,7 +600,7 @@ let quantify (alphas : tyvars) (ty : core_type) : core_type =
alphas
in
(* Done. *)
- Typ.poly alphas ty
+ typ_poly alphas ty
(* -------------------------------------------------------------------------- *)
diff --git a/src/VisitorsAnalysis.ml b/src/VisitorsAnalysis.ml
index 7d55357..39307e0 100644
--- a/src/VisitorsAnalysis.ml
+++ b/src/VisitorsAnalysis.ml
@@ -245,21 +245,18 @@ let rec occurs_type (alpha : tyvar) (ty : core_type) : unit =
| Ptyp_constr (_, tys)
| Ptyp_class (_, tys) ->
occurs_types alpha tys
- | Ptyp_object (methods, _) ->
- List.iter (fun (_, _, ty) -> occurs_type alpha ty) methods
+ | Ptyp_object (fields, _) ->
+ let tys : core_type list =
+ List.map VisitorsCompatibility.object_field_to_core_type fields
+ in
+ List.iter (occurs_type alpha) tys
| Ptyp_variant (fields, _, _) ->
List.iter (occurs_row_field alpha) fields
- | Ptyp_poly (_qs, ty) ->
+ | Ptyp_poly (qs, ty) ->
+ let qs : string list = VisitorsCompatibility.quantifiers qs in
(* The type variables in [qs] are bound. *)
- (* Unfortunately, the type of [qs] has changed from [string list]
- to [string loc list] between OCaml 4.04 and 4.05.
- See commit b0e880c448c78ed0cedff28356fcaf88f1436eef.
- I do not want to do conditional compilation,
- nor do I want to require 4.05 (yet).
- So, for now, I just assume that [alpha] does not appear in [qs].
- This means that [occurs] can (on rare occasions) return [true]
- when it should return [false]. *)
- (* if not (occurs_quantifiers alpha qs) then *) occurs_type alpha ty
+ if not (occurs_quantifiers alpha qs) then
+ occurs_type alpha ty
| Ptyp_package (_, ltys) ->
List.iter (fun (_, ty) -> occurs_type alpha ty) ltys
| Ptyp_extension (_, payload) ->
@@ -275,8 +272,8 @@ and occurs_row_field alpha field =
| Rinherit ty ->
occurs_type alpha ty
-and occurs_quantifiers alpha qs =
- List.exists (fun q -> alpha = q.txt) qs
+and occurs_quantifiers alpha (qs : string list) =
+ List.mem alpha qs
and occurs_payload alpha = function
| PTyp ty ->
diff --git a/src/VisitorsCompatibility.cppo.ml b/src/VisitorsCompatibility.cppo.ml
index 71b6b0f..4a55fc0 100644
--- a/src/VisitorsCompatibility.cppo.ml
+++ b/src/VisitorsCompatibility.cppo.ml
@@ -1,3 +1,4 @@
+let mknoloc = Location.mknoloc
open Asttypes
open Parsetree
open Ast_helper
@@ -68,3 +69,65 @@ let data_constructor_variety (cd : constructor_declaration) =
| Pcstr_record lds ->
DataInlineRecord (ld_labels lds, ld_tys lds)
#endif
+
+(* Between OCaml 4.04 and OCaml 4.05, the types of several functions in [Ast_helper]
+ have changed. They used to take arguments of type [string], and now take arguments
+ of type [str], thus requiring a conversion. These functions include [Typ.object_],
+ [Typ.poly], [Exp.send], [Exp.newtype], [Ctf.val_], [Ctf.method_], [Cf.inherit_]. *)
+
+type str =
+ #if OCAML_VERSION < (4, 05, 0)
+ string
+ #else
+ string Location.loc
+ #endif
+
+let string2str (s : string) : str =
+ #if OCAML_VERSION < (4, 05, 0)
+ s
+ #else
+ mknoloc s
+ #endif
+
+let str2string (s : str) : string =
+ #if OCAML_VERSION < (4, 05, 0)
+ s
+ #else
+ s.txt
+ #endif
+
+let typ_poly (tyvars : string list) (cty : core_type) : core_type =
+ Typ.poly (List.map string2str tyvars) cty
+
+let exp_send (e : expression) (m : string) : expression =
+ Exp.send e (string2str m)
+
+(* In the data constructor [Ptyp_poly (qs, ty)], the type of [qs] has changed from
+ [string list] to [string loc list] between OCaml 4.04 and 4.05.
+ See commit b0e880c448c78ed0cedff28356fcaf88f1436eef.
+ The function [quantifiers] compensates for this. *)
+
+let quantifiers qs : string list =
+ List.map str2string qs
+
+(* In the data constructor [Ptyp_object (methods, _)], the type of [methods] has
+ changed from [(string loc * attributes * core_type) list] in OCaml 4.05 to
+ [object_field list] in OCaml 4.06. *)
+
+
+#if OCAML_VERSION < (4, 06, 0)
+type object_field =
+ str * attributes * core_type
+#endif
+
+let object_field_to_core_type : object_field -> core_type =
+ #if OCAML_VERSION < (4, 06, 0)
+ fun (_, _, ty) -> ty
+ #else
+ function
+ | Otag (_, _, ty) -> ty
+ | Oinherit ty -> ty
+ (* this may seem nonsensical, but (so far) is used only in the
+ function [occurs_type], where we do not care what the types
+ mean *)
+ #endif
diff --git a/src/VisitorsGeneration.ml b/src/VisitorsGeneration.ml
index 01fae98..2d656c2 100644
--- a/src/VisitorsGeneration.ml
+++ b/src/VisitorsGeneration.ml
@@ -467,7 +467,7 @@ let is_virtual (Meth (_, _, oe, _)) : bool =
(* [send o m es] produces a call to the method [o#m] with arguments [es]. *)
let send (o : variable) (m : methode) (es : expressions) : expression =
- app (Exp.send (evar o) m) es
+ app (exp_send (evar o) m) es
(* -------------------------------------------------------------------------- *)
diff --git a/src/VisitorsString.ml b/src/VisitorsString.ml
index 40e43e3..bf0d4a1 100644
--- a/src/VisitorsString.ml
+++ b/src/VisitorsString.ml
@@ -25,3 +25,46 @@ let unquote alpha =
String.sub alpha 1 (n-1)
else
alpha
+
+(* [print_longident] converts an OCaml long identifier to a string. *)
+
+let print_longident (x : Longident.t) : string =
+ String.concat "." (Longident.flatten x)
+
+(* Suppose the function [f] is a lossy (non-injective) mapping of ['a] to
+ [string]. Then, the function [protect f equal warn] is also a function of
+ ['a] to [string], which behaves like [f], except it warns if [f] is applied
+ to two values of type ['a] that have the same image of type [string]. *)
+
+(* [equal] must implement equality at type ['a]. *)
+
+(* [warn x1 x2 y] is invoked when [f] is applied at two distinct values [x1]
+ and [x2] that have the same image [y] through [f]. Precautions are taken
+ so that [f] is not invoked repeatedly if the same conflict is repeatedly
+ detected. *)
+
+module H = Hashtbl
+
+let protect
+ (f : 'a -> string)
+ (equal : 'a -> 'a -> bool)
+ (warn : 'a -> 'a -> string -> unit)
+: 'a -> string =
+ (* A hash table memoizes the inverse of [f]. *)
+ let table : (string, 'a list) H.t = H.create 127 in
+ fun (x : 'a) ->
+ let y = f x in
+ let xs = try H.find table y with Not_found -> [] in
+ H.add table y (x :: xs);
+ if List.exists (equal x) xs || xs = [] then
+ (* If the mapping of [x] to [y] is known already,
+ or if no pre-image of [y] was previously known,
+ then no warning is needed. *)
+ y
+ else
+ (* The list [xs] is nonempty and does not contain [x],
+ so its head [x'] is distinct from [x] and is also
+ a pre-image of [y]. Warn. *)
+ let x' = List.hd xs in
+ warn x' x y;
+ y
diff --git a/test/bad/Makefile b/test/bad/Makefile
new file mode 100644
index 0000000..6c8b7d4
--- /dev/null
+++ b/test/bad/Makefile
@@ -0,0 +1,7 @@
+.PHONY: test clean
+
+test:
+ cram -iv visitors.t
+
+clean:
+ rm -f visitors.t.err
diff --git a/test/bad/conflict.ml b/test/bad/conflict.ml
new file mode 100644
index 0000000..86b0186
--- /dev/null
+++ b/test/bad/conflict.ml
@@ -0,0 +1,25 @@
+module Elt = struct
+ type t = int
+end
+
+type t =
+ | Leaf
+ | Node of { left: t; value: Elt.t; right: t }
+ [@@deriving visitors { variety = "iter" } ]
+
+(*
+
+Issue 3, reported by Gabriel Radanne.
+
+https://gitlab.inria.fr/fpottier/visitors/issues/3
+
+File "conflict.ml", line 5, characters 0-111:
+Error: This expression has type Elt.t = int
+ but an expression was expected of type t
+
+The naming convention for visitor methods causes a name clash:
+the types [Elt.t] and [t] have visitor methods by the same name.
+
+A warning should be issued.
+
+*)
diff --git a/test/bad/conflict_at_name.ml b/test/bad/conflict_at_name.ml
new file mode 100644
index 0000000..ab67704
--- /dev/null
+++ b/test/bad/conflict_at_name.ml
@@ -0,0 +1,17 @@
+module Elt = struct
+ type elt = int
+end
+
+type t =
+ | Leaf
+ | Node of { left: t; value: (Elt.elt[@name "t"]); right: t }
+ [@@deriving visitors { variety = "iter" } ]
+
+(*
+
+In this example, a stupid [@name] attribute causes a name clash:
+the types [elt] and [t] have visitor methods by the same name.
+
+A warning should be issued.
+
+*)
diff --git a/test/bad/conflict_atat_name.ml b/test/bad/conflict_atat_name.ml
new file mode 100644
index 0000000..7acce5e
--- /dev/null
+++ b/test/bad/conflict_atat_name.ml
@@ -0,0 +1,15 @@
+type t =
+ | Leaf
+ | Node of { left: t; value: elt; right: t }
+ [@@deriving visitors { variety = "iter" } ]
+
+and elt = int[@@name "t"]
+
+(*
+
+In this example, a stupid [@name] attribute causes a name clash:
+the types [elt] and [t] have visitor methods by the same name.
+
+A warning should be issued.
+
+*)
diff --git a/test/bad/datacon.ml b/test/bad/datacon.ml
new file mode 100644
index 0000000..86c7c7f
--- /dev/null
+++ b/test/bad/datacon.ml
@@ -0,0 +1,11 @@
+type t =
+ | A
+ | B of u
+
+and u =
+ | A of t
+ [@@deriving visitors { variety = "iter" }]
+
+(* Another example where two distinct types have a data constructor
+ named [A] (which OCaml warns about, but allows). This causes a
+ name clash on the methods [visit_A]. *)
diff --git a/test/bad/datacon_at_name.ml b/test/bad/datacon_at_name.ml
new file mode 100644
index 0000000..be3ce4a
--- /dev/null
+++ b/test/bad/datacon_at_name.ml
@@ -0,0 +1,10 @@
+type t =
+ | A
+ | B of u
+
+and u =
+ | C of t [@name "A"]
+ [@@deriving visitors { variety = "iter" }]
+
+(* Another example where two distinct types have a data constructor
+ renamed [A]. This causes a name clash on the methods [visit_A]. *)
diff --git a/test/bad/visitors.t b/test/bad/visitors.t
new file mode 100644
index 0000000..9ffdba9
--- /dev/null
+++ b/test/bad/visitors.t
@@ -0,0 +1,49 @@
+
+ $ compile="ocamlfind ocamlc -c -package visitors.ppx -package visitors.runtime"
+
+ $ $compile $TESTDIR/conflict.ml 2>&1 | sed -e "s|$TESTDIR/||"
+ File "conflict.ml", line 7, characters 30-35:
+ Warning 22: visitors: name clash: the types t and Elt.t
+ both have visitor methods named visit_t.
+ Please consider using [@@name] at type declaration sites
+ or [@name] at type reference sites.
+ File "conflict.ml", line 5, characters 0-111:
+ Error: This expression has type Elt.t = int
+ but an expression was expected of type t
+
+ $ $compile $TESTDIR/conflict_at_name.ml 2>&1 | sed -e "s|$TESTDIR/||"
+ File "conflict_at_name.ml", line 7, characters 31-38:
+ Warning 22: visitors: name clash: the types t and Elt.elt
+ both have visitor methods named visit_t.
+ Please consider using [@@name] at type declaration sites
+ or [@name] at type reference sites.
+ File "conflict_at_name.ml", line 5, characters 0-126:
+ Error: This expression has type Elt.elt = int
+ but an expression was expected of type t
+
+ $ $compile $TESTDIR/conflict_atat_name.ml 2>&1 | sed -e "s|$TESTDIR/||"
+ File "conflict_atat_name.ml", line 6, characters 0-25:
+ Warning 22: visitors: name clash: the types t and elt
+ both have visitor methods named visit_t.
+ Please consider using [@@name] at type declaration sites
+ or [@name] at type reference sites.
+ File "conflict_atat_name.ml", line 1, characters 0-136:
+ Error: The method `visit_t' has multiple definitions in this object
+
+ $ $compile $TESTDIR/datacon.ml 2>&1 | sed -e "s|$TESTDIR/||"
+ File "datacon.ml", line 6, characters 2-10:
+ Warning 22: visitors: name clash: the data constructors A and A
+ both have visitor methods named visit_A.
+ Please consider using [@name] at data constructor declaration sites.
+ File "datacon.ml", line 6, characters 2-10:
+ Warning 30: the constructor A is defined in both types t and u.
+ File "datacon.ml", line 1, characters 0-90:
+ Error: The method `visit_A' has multiple definitions in this object
+
+ $ $compile $TESTDIR/datacon_at_name.ml 2>&1 | sed -e "s|$TESTDIR/||"
+ File "datacon_at_name.ml", line 6, characters 2-22:
+ Warning 22: visitors: name clash: the data constructors A and C
+ both have visitor methods named visit_A.
+ Please consider using [@name] at data constructor declaration sites.
+ File "datacon_at_name.ml", line 1, characters 0-102:
+ Error: The method `visit_A' has multiple definitions in this object
diff --git a/test/expr.mllib b/test/expr.mllib
index 14d9c3d..b2f394d 100644
--- a/test/expr.mllib
+++ b/test/expr.mllib
@@ -5,6 +5,7 @@ expr00fold
expr00fold2
expr01
expr01use
+expr01use_variant
expr02
expr03
expr04
diff --git a/test/expr01use.ml b/test/expr01use.ml
index dd387bd..557e19c 100644
--- a/test/expr01use.ml
+++ b/test/expr01use.ml
@@ -22,3 +22,4 @@ let () =
assert (optimize (z (EConst 1)) = EConst 1);
assert (optimize (z (z (EConst 1))) = EConst 1);
assert (optimize (EAdd (EConst 1, EConst 1)) = EAdd (EConst 1, EConst 1));
+ assert (optimize (EAdd (z (EConst 1), EConst 1)) = EAdd (EConst 1, EConst 1));
diff --git a/test/expr01use.ml b/test/expr01use_variant.ml
similarity index 57%
copy from test/expr01use.ml
copy to test/expr01use_variant.ml
index dd387bd..42561f0 100644
--- a/test/expr01use.ml
+++ b/test/expr01use_variant.ml
@@ -1,18 +1,13 @@
open Expr01
-let add e1 e2 =
- match e1, e2 with
- | EConst 0, e
- | e, EConst 0 -> e
- | _, _ -> EAdd (e1, e2)
-
let optimize : expr -> expr =
- let o = object (self)
+ let o = object(self)
inherit [_] map
method! visit_EAdd env e1 e2 =
- add
- (self#visit_expr env e1)
- (self#visit_expr env e2)
+ match self#visit_expr env e1, self#visit_expr env e2 with
+ | EConst 0, e
+ | e, EConst 0 -> e
+ | e1, e2 -> EAdd (e1, e2)
end in
o # visit_expr ()
@@ -22,3 +17,4 @@ let () =
assert (optimize (z (EConst 1)) = EConst 1);
assert (optimize (z (z (EConst 1))) = EConst 1);
assert (optimize (EAdd (EConst 1, EConst 1)) = EAdd (EConst 1, EConst 1));
+ assert (optimize (EAdd (z (EConst 1), EConst 1)) = EAdd (EConst 1, EConst 1));
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ocaml-maint/packages/ocaml-visitors.git
More information about the Pkg-ocaml-maint-commits
mailing list