Commit ae456c12 authored by POTTIER Francois's avatar POTTIER Francois

Merge branch 'master' of gitlab.inria.fr:fpottier/visitors

parents 50b931ef 445e78b1
2017/04/04:
Extended backward compatibility to OCaml 4.02.2. (Thanks to Benjamin Farinier.)
2017/03/17:
New attributes [@build] and [@@build] can be attached to record type
declarations and data constructors, so as to alter the construction code that
is used in map, endo, and mapreduce visitors. See the documentation for
details. (This feature was suggested by Reuben Rowe.)
2017/03/15:
New attributes [@name] and [@@name] can be attached to types, type declarations,
and data constructors, so as to alter the names of the generated methods. See
the documentation for details. (This feature was suggested by Reuben Rowe.)
2017/03/08:
A new option [polymorphic = true] allows generating visitor methods with
polymorphic types. With [polymorphic = true], a type variable ['a] is
handled by a visitor *function* [visit_'a], which is passed as an argument
to every visitor method; whereas, with [polymorphic = false], a type
variable ['a] is handled by a virtual visitor *method* [visit_'a].
With [polymorphic = true], visitor classes compose better,
and irregular algebraic data types are supported.
See the documentation for more details.
(This feature was suggested by Reuben Rowe.)
2017/03/03:
A new option [data = false] allows suppressing the generation of visitor
methods for data constructors. This makes the generated visitor slightly
simpler and faster, but less customizable.
A new option [nude = true] allows *not* implicitly inheriting the class
VisitorsRuntime.<variety>.
2017/02/15:
Makefile.preprocess is now installed with the package, so users can rely on it
without needing to copy it. See the documentation for instructions.
2017/02/13:
Added a new variety of visitors, "mapreduce". This visitor computes a pair of a
data structure (like a "map" visitor) and a summary (like a "reduce" visitor).
This can be used to annotate every tree node with information about the
subtree that lies below it. See the documentation for an example.
2017/02/09:
Documentation: added a new subsection on OCaml objects,
entitled "Where the expressiveness of OCaml's type system falls short".
This section explains why "map" cannot be a subclass of "fold",
even though it should be.
2017/01/31:
Documentation: added an example of constructing a lexicographic ordering.
Documentation: discussed generating visitors for existing types and ppx_import.
2017/01/26:
Initial release.
# Changes
## 2017/04/20
* New settings `visit_prefix`, `build_prefix`, and `fail_prefix` can be used
to control which prefixes are used in generated method names. (This feature
was suggested by Philip Hölzenspies.)
## 2017/04/04
* Extended backward compatibility to OCaml 4.02.2. (Thanks to Benjamin Farinier.)
## 2017/03/17
* New attributes `@build` and `@@build` can be attached to record type
declarations and data constructors, so as to alter the construction code that
is used in `map`, `endo`, and `mapreduce` visitors. See the documentation for
details. (This feature was suggested by Reuben Rowe.)
## 2017/03/15
* New attributes `@name` and `@@name` can be attached to types, type declarations,
and data constructors, so as to alter the names of the generated methods. See
the documentation for details. (This feature was suggested by Reuben Rowe.)
## 2017/03/08
* A new option `polymorphic = true` allows generating visitor methods with
polymorphic types. With `polymorphic = true`, a type variable `'a` is
handled by a visitor *function* `visit_'a`, which is passed as an argument
to every visitor method; whereas, with `polymorphic = false`, a type
variable `'a` is handled by a virtual visitor *method* `visit_'a`.
With `polymorphic = true`, visitor classes compose better,
and irregular algebraic data types are supported.
See the documentation for more details.
(This feature was suggested by Reuben Rowe.)
## 2017/03/03
* A new option `data = false` allows suppressing the generation of visitor
methods for data constructors. This makes the generated visitor slightly
simpler and faster, but less customizable.
* A new option `nude = true` allows *not* implicitly inheriting the class
`VisitorsRuntime.<variety>`.
## 2017/02/15
* `Makefile.preprocess` is now installed with the package, so users can rely on it
without needing to copy it. See the documentation for instructions.
## 2017/02/13
* Added a new variety of visitors, `mapreduce`. This visitor computes a pair of a
data structure (like a `map` visitor) and a summary (like a `reduce` visitor).
This can be used to annotate every tree node with information about the
subtree that lies below it. See the documentation for an example.
## 2017/02/09
* Documentation: added a new subsection on OCaml objects,
entitled "Where the expressiveness of OCaml's type system falls short".
This section explains why `map` cannot be a subclass of `fold`,
even though it should be.
## 2017/01/31
* Documentation: added an example of constructing a lexicographic ordering.
* Documentation: discussed generating visitors for existing types and `ppx_import`.
## 2017/01/26
* Initial release.
......@@ -15,7 +15,8 @@ include Makefile
# Utilities.
MD5SUM := $(shell if command -v md5 2>/dev/null ; then echo "md5 -r" ; else echo md5sum ; fi)
MD5SUM := $(shell if command -v md5 >/dev/null 2>/dev/null ; \
then echo "md5 -r" ; else echo md5sum ; fi)
# -------------------------------------------------------------------------
......@@ -36,7 +37,7 @@ TARBALL := $(CURRENT)/$(PACKAGE).tar.gz
# This does not include the src/ and doc/ directories, which require
# special treatment.
DISTRIBUTED_FILES := AUTHORS CHANGES LICENSE Makefile
DISTRIBUTED_FILES := AUTHORS CHANGES.md LICENSE Makefile
# -------------------------------------------------------------------------
......
......@@ -118,3 +118,6 @@
\newcommand{\data}{\texttt{data}\xspace}
\newcommand{\nude}{\texttt{nude}\xspace}
\newcommand{\polymorphic}{\texttt{polymorphic}\xspace}
\newcommand{\visitprefix}{\texttt{visit\_prefix}\xspace}
\newcommand{\buildprefix}{\texttt{build\_prefix}\xspace}
\newcommand{\failprefix}{\texttt{fail\_prefix}\xspace}
......@@ -1790,6 +1790,11 @@ programming languages, but also in an object-oriented programming setting.
unless \nude is \texttt{true}.
Every ancestor class must have exactly \emph{one} type parameter,
which is typically (but not necessarily) the type of ``self''.
\\
\buildprefix & (string) &
The prefix that is used in the name of the build methods in \fold and
\foldtwo visitors (\sref{sec:intro:fold}).
This is an optional parameter, whose default value is ``\texttt{build\_}''.
\\
\concrete & (Boolean) &
If \texttt{true}, the generated class is declared
......@@ -1800,6 +1805,11 @@ programming languages, but also in an object-oriented programming setting.
If \texttt{true}, one visitor method is generated for every data constructor (\sref{sec:structure}).
If \texttt{false}, this method is not generated (it is inlined instead).
This is an optional parameter; its default value is \texttt{true}.
\\
\failprefix & (string) &
The prefix that is used in the name of the failure methods in
visitors of arity two (\sref{sec:intro:aritytwo}).
This is an optional parameter, whose default value is ``\texttt{fail\_}''.
\\
\irregular & (Boolean) &
If \texttt{true}, the regularity check (\sref{sec:regularity}) is disabled;
......@@ -1845,6 +1855,12 @@ programming languages, but also in an object-oriented programming setting.
\mapreducetwo,
\foldtwo (\sref{sec:intro:aritytwo}).
\\
\visitprefix & (string) &
The prefix that is used in the name of visitor methods.
This is an optional parameter, whose default value is ``\texttt{visit\_}''.
Be aware that, if this prefix is changed, then the classes provided by the
library \texttt{VisitorsRuntime} become useless: in that case, one might wish to
also specify \verb+nude = true+, so as to not inherit these classes.
\end{tabular}
\vspace{2.5mm}
\hrule
......
......@@ -118,10 +118,15 @@ let check_regularity loc tycon (formals : tyvars) (actuals : core_types) =
(* Public naming conventions. *)
(* The names of the methods associated with the type [foo] are normally based
on (derived from) the name [foo]. This base name can be overriden by the
user via an attribute. For a local type, a [@@name] attribute must be
attached to the type declaration. For a nonlocal type, a [@name] attribute
must be attached to every reference to this type. *)
on (derived from) the name [foo].
This base name can be overriden by the user via an attribute. For a local
type, a [@@name] attribute must be attached to the type declaration. For a
nonlocal type, a [@name] attribute must be attached to every reference to
this type.
The prefix that is prepended to the base name can be controlled via the
settings [visit_prefix], [build_prefix], and [fail_prefix]. *)
let tycon_modified_name (attrs : attributes) (tycon : tycon) : tycon =
maybe (name attrs) tycon
......@@ -140,7 +145,7 @@ let datacon_modified_name (cd : constructor_declaration) : datacon =
or [A.foo]. (A qualified name must denote a nonlocal type.) *)
let tycon_visitor_method (attrs : attributes) (tycon : tycon) : methode =
"visit_" ^ tycon_modified_name attrs tycon
X.visit_prefix ^ tycon_modified_name attrs tycon
let local_tycon_visitor_method (decl : type_declaration) : methode =
tycon_visitor_method decl.ptype_attributes decl.ptype_name.txt
......@@ -160,13 +165,13 @@ let nonlocal_tycon_visitor_method (ty : core_type) : methode =
(* The name of this method is normally [build_foo] if the type is named [foo]. *)
let tycon_ascending_method (decl : type_declaration) : methode =
"build_" ^ tycon_modified_name decl.ptype_attributes decl.ptype_name.txt
X.build_prefix ^ tycon_modified_name decl.ptype_attributes decl.ptype_name.txt
(* [mono] type variables have a virtual visitor method. We include a quote in
the method name so as to ensure the absence of collisions. *)
let tyvar_visitor_method (alpha : tyvar) : methode =
"visit_'" ^ alpha
sprintf "%s'%s" X.visit_prefix alpha
(* For every data constructor [datacon], there is a descending visitor method,
which is invoked on the way down, when this data constructor is discovered. *)
......@@ -175,14 +180,14 @@ let tyvar_visitor_method (alpha : tyvar) : methode =
named [Foo]. *)
let datacon_descending_method (cd : constructor_declaration) : methode =
"visit_" ^ datacon_modified_name cd
X.visit_prefix ^ datacon_modified_name cd
(* 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]. *)
let datacon_ascending_method (cd : constructor_declaration) : methode =
"build_" ^ datacon_modified_name cd
X.build_prefix ^ datacon_modified_name cd
(* At arity 2, for every sum type constructor [tycon] which has at least two
data constructors, there is a failure method, which is invoked when the
......@@ -191,7 +196,7 @@ let datacon_ascending_method (cd : constructor_declaration) : methode =
(* The name of this method is normally [fail_foo] if the type is named [foo]. *)
let failure_method (decl : type_declaration) : methode =
"fail_" ^ tycon_modified_name decl.ptype_attributes decl.ptype_name.txt
X.fail_prefix ^ tycon_modified_name decl.ptype_attributes decl.ptype_name.txt
(* When [scheme] is [Reduce], we need a monoid, that is, a unit [zero] and a
binary operation [plus]. The names [zero] and [plus] are fixed. We assume
......
......@@ -87,6 +87,14 @@ let is_valid_class_longident (m : string) : bool =
(* -------------------------------------------------------------------------- *)
(* Testing if a string is a valid method name prefix. *)
let is_valid_method_name_prefix (m : string) : bool =
String.length m > 0 &&
classify m = LIDENT
(* -------------------------------------------------------------------------- *)
(* Testing for the presence of attributes. *)
(* We use [ppx_deriving] to extract a specific attribute from an attribute
......
......@@ -50,6 +50,21 @@ module type SETTINGS = sig
the string provided by the user. *)
val variety: string
(* [visit_prefix] is the common prefix used to name the descending visitor
methods. It must be nonempty and a valid identifier by itself. Its
default value is "visit_". *)
val visit_prefix: string
(* [build_prefix] is the common prefix used to name the ascending visitor
methods. It must be nonempty and a valid identifier by itself. Its
default value is "build_". *)
val build_prefix: string
(* [fail_prefix] is the common prefix used to name the failure methods. It
must be nonempty and a valid identifier by itself. Its default value is
"fail_". *)
val fail_prefix: string
(* The classes that the visitor should inherit. If [nude] is [false], the
class [VisitorsRuntime.<scheme>] is implicitly prepended to this list.
If [nude] is [true], it is not. *)
......@@ -141,15 +156,20 @@ let parse_variety loc (s : string) : scheme * int =
(* -------------------------------------------------------------------------- *)
let must_be_valid_method_name_prefix loc p =
if not (is_valid_method_name_prefix p) then
raise_errorf ~loc
"%s: %S is not a valid method name prefix." plugin p
let must_be_valid_mod_longident loc m =
if not (is_valid_mod_longident m) then
raise_errorf ~loc
"%s: %s is not a valid module identifier." plugin m
"%s: %S is not a valid module identifier." plugin m
let must_be_valid_class_longident loc c =
if not (is_valid_class_longident c) then
raise_errorf ~loc
"%s: %s is not a valid class identifier." plugin c
"%s: %S is not a valid class identifier." plugin c
(* -------------------------------------------------------------------------- *)
......@@ -195,6 +215,9 @@ end)
let arity = ref 1 (* dummy: [variety] is mandatory; see below *)
let scheme = ref Iter (* dummy: [variety] is mandatory; see below *)
let variety = ref None
let visit_prefix = ref "visit_"
let build_prefix = ref "build_"
let fail_prefix = ref "fail_"
let ancestors = ref []
let concrete = ref false
let data = ref true
......@@ -210,6 +233,15 @@ end)
iter (fun (o, e) ->
let loc = e.pexp_loc in
match o with
| "visit_prefix" ->
visit_prefix := string e;
must_be_valid_method_name_prefix loc !visit_prefix
| "build_prefix" ->
build_prefix := string e;
must_be_valid_method_name_prefix loc !build_prefix
| "fail_prefix" ->
fail_prefix := string e;
must_be_valid_method_name_prefix loc !fail_prefix
| "ancestors" ->
ancestors := strings e
| "concrete" ->
......@@ -275,6 +307,9 @@ end)
let decls = decls
let arity = !arity
let scheme = !scheme
let visit_prefix = !visit_prefix
let build_prefix = !build_prefix
let fail_prefix = !fail_prefix
let ancestors = !ancestors
let concrete = !concrete
let data = !data
......
......@@ -10,6 +10,7 @@ monopoly
opaque
point
polyclass
prefixes
test00
test01
test02
......
class ['self] base = object(_ : 'self)
method on_int () i j = i + j
end
type inttree = Node of (int * inttree * inttree) | Leaf of int
[@@deriving visitors { variety = "fold2"; visit_prefix = "on_";
build_prefix = "mk_"; fail_prefix = "err_";
nude = true; ancestors = ["base"]}]
let add_inttree : inttree -> inttree -> int =
let v = object
inherit [_] fold2 as super
method mk_Node () (i, l, r) = i + l + r
method mk_Leaf () i = i
method! err_inttree () _l _r = 0
method! on_inttree = super # on_inttree
end
in v # on_inttree ()
let t = Node (1, Leaf 2, Leaf 3)
let (_i : int) =
add_inttree t t
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment