From a3607dc926488659c7a2ae322dc6697a068f6f60 Mon Sep 17 00:00:00 2001 From: Ralf Treinen Date: Wed, 17 Jul 2019 22:52:52 +0200 Subject: Import ocaml-visitors_20190711-1.debian.tar.xz [dgit import tarball ocaml-visitors 20190711-1 ocaml-visitors_20190711-1.debian.tar.xz] --- changelog | 74 ++++++++++++++++++++++++++++++++++++++ control | 36 +++++++++++++++++++ copyright | 57 +++++++++++++++++++++++++++++ gbp.conf | 2 ++ libppx-visitors-ocaml-doc.doc-base | 8 +++++ libppx-visitors-ocaml-doc.docs | 1 + patches/series | 0 rules | 28 +++++++++++++++ source/format | 1 + tests/control | 2 ++ tests/weight | 17 +++++++++ tests/weight.ml | 27 ++++++++++++++ watch | 4 +++ 13 files changed, 257 insertions(+) create mode 100644 changelog create mode 100644 control create mode 100644 copyright create mode 100644 gbp.conf create mode 100644 libppx-visitors-ocaml-doc.doc-base create mode 100644 libppx-visitors-ocaml-doc.docs create mode 100644 patches/series create mode 100755 rules create mode 100644 source/format create mode 100644 tests/control create mode 100755 tests/weight create mode 100644 tests/weight.ml create mode 100644 watch diff --git a/changelog b/changelog new file mode 100644 index 0000000..ec7e1dd --- /dev/null +++ b/changelog @@ -0,0 +1,74 @@ +ocaml-visitors (20190711-1) unstable; urgency=medium + + * New upstream version. + * Standards-Version 4.4.0 (no change) + + -- Ralf Treinen Wed, 17 Jul 2019 22:52:52 +0200 + +ocaml-visitors (20180513-1) unstable; urgency=medium + + * New upstream version. This version allows projects using the -dev + package to build under dune. + * Build-depend on debhelper-compat (=12) + + -- Ralf Treinen Mon, 18 Feb 2019 20:38:44 +0100 + +ocaml-visitors (20180306-4) unstable; urgency=medium + + * Standards-Version 4.3.0 (no change) + * Debhelper compatibility level 12 (no change) + * -dev package Suggests ocaml-findlib since package has a META file + * Remove trailing white space in debian/{changelog,rules,control} + + -- Ralf Treinen Tue, 08 Jan 2019 21:26:16 +0100 + +ocaml-visitors (20180306-3) unstable; urgency=medium + + * autopkgtest: depends on ocamlbuild + * libppx-visitors-ocaml-dev: suggests -doc package. + + -- Ralf Treinen Wed, 11 Jul 2018 07:59:45 +0200 + +ocaml-visitors (20180306-2) unstable; urgency=medium + + * Vcs-{Browser,Git}: update to salsa. + * Standards-Version 4.1.5 (no change) + + -- Ralf Treinen Mon, 09 Jul 2018 21:07:17 +0200 + +ocaml-visitors (20180306-1) unstable; urgency=medium + + * New upstream version. + - dropped patch ocaml-4.05 since issue is solved upstream. + * Standards-Version 4.1.3: + - d/copyright: use https in format specifier + * debhelper compatibility level 11: + - fixed file location in libppx-visitors-ocaml-doc.doc-base since + dh_installdocs now installs into the /usr/share/doc of the main + package. + * Add minimal version of build-dependency libppx-deriving-ocaml-dev. + + -- Ralf Treinen Wed, 21 Mar 2018 20:43:06 +0100 + +ocaml-visitors (20170725-2) unstable; urgency=medium + + * Patch ocaml-4.05: migrate to ocaml 4.05, patch picked from upstream git + (closes: #880063) + * Standards-Version 4.1.1: + - replace Priority extra by optional. + + -- Ralf Treinen Mon, 30 Oct 2017 20:22:58 +0100 + +ocaml-visitors (20170725-1) unstable; urgency=medium + + * New upstream release. This release fixes compilation on bytecode + architectures (closes: #869207) + * Added build-dependency on ocamlbuild. + + -- Ralf Treinen Fri, 28 Jul 2017 22:32:00 +0200 + +ocaml-visitors (20170404-1) unstable; urgency=medium + + * Initial upload (closes: #862775) + + -- Ralf Treinen Thu, 06 Jul 2017 12:52:24 +0200 diff --git a/control b/control new file mode 100644 index 0000000..c5801b0 --- /dev/null +++ b/control @@ -0,0 +1,36 @@ +Source: ocaml-visitors +Section: ocaml +Priority: optional +Maintainer: Debian OCaml Maintainers +Uploaders: Ralf Treinen , +Build-Depends: debhelper-compat (= 12), dh-ocaml (>= 0.9~), + ocaml-nox (>= 4.02.2), libfindlib-ocaml, cppo, ocamlbuild, + libppx-deriving-ocaml-dev (>= 4.0) +Build-Depends-Indep: texlive-latex-base, latexmk, + lmodern, texlive-fonts-recommended, texlive-latex-extra, + ocp-indent +Standards-Version: 4.4.0 +Homepage: https://gitlab.inria.fr/fpottier/visitors +Vcs-Browser: https://salsa.debian.org/ocaml-team/ocaml-visitors +Vcs-Git: https://salsa.debian.org/ocaml-team/ocaml-visitors.git + +Package: libppx-visitors-ocaml-dev +Architecture: any +Depends: ${misc:Depends}, ${ocaml:Depends}, ${shlibs:Depends} +Provides: ${ocaml:Provides} +Suggests: libppx-visitors-ocaml-doc, ocaml-findlib +Description: OCaml syntax extension for object-oriented visitors + Visitors is a syntax extension for the OCaml programming language. It + allows you to annotate your type definitions, such that a visitor class + will be automatically generated. This visitor class contains methods + for the traversal of your data structure, like iter, map, fold, etc. It + is then easy to override these methods for your needs. This is very + convenient when programming with complex algebraic data structures. + +Package: libppx-visitors-ocaml-doc +Section: doc +Architecture: all +Depends: ${misc:Depends} +Description: Documentation of the visitors syntax extension for OCaml + This package contains the documentation of the visitors syntax extension + for the OCaml programming language. diff --git a/copyright b/copyright new file mode 100644 index 0000000..fa1ca82 --- /dev/null +++ b/copyright @@ -0,0 +1,57 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: visitors +Upstream-Contact: François Pottier +Source: https://gitlab.inria.fr/fpottier/visitors.git + +Files: * +Copyright: © 2016, 2017 INRIA +License: LGPL-2.1 +Comment: + the copyright holder has been confirmed in a personal mail by the author. + +Files: debian/* +Copyright: © 2017 Ralf Treinen +License: LGPL-2.1 + +Files: test/cil_types.ml test/cil_types.ml.orig test/cil_types_polymorphic.ml +Copyright: (C) 2001-2003 + George C. Necula + Scott McPeak + Wes Weimer + Ben Liblit +License: BSD-3-clause + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + . + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + . + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + . + 3. The names of the contributors may not be used to endorse or + promote products derived from this software without specific prior + written permission. + . + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +License: LGPL-2.1 + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License version 2.1 as published by the Free Software Foundation. + . + On Debian systems, the complete text of the latest GNU Lesser General + Public License can be found in `/usr/share/common-licenses/LGPL-2.1'. diff --git a/gbp.conf b/gbp.conf new file mode 100644 index 0000000..cec628c --- /dev/null +++ b/gbp.conf @@ -0,0 +1,2 @@ +[DEFAULT] +pristine-tar = True diff --git a/libppx-visitors-ocaml-doc.doc-base b/libppx-visitors-ocaml-doc.doc-base new file mode 100644 index 0000000..f475522 --- /dev/null +++ b/libppx-visitors-ocaml-doc.doc-base @@ -0,0 +1,8 @@ +Document: visitors-documentation +Title: Visitors +Author: François Pottier +Abstract: This document describes how to use the visitors syntax extension for OCaml +Section: Programming/OCaml + +Format: PDF +Files: /usr/share/doc/libppx-visitors-ocaml-dev/main.pdf.gz diff --git a/libppx-visitors-ocaml-doc.docs b/libppx-visitors-ocaml-doc.docs new file mode 100644 index 0000000..aa78ec2 --- /dev/null +++ b/libppx-visitors-ocaml-doc.docs @@ -0,0 +1 @@ +doc/main.pdf diff --git a/patches/series b/patches/series new file mode 100644 index 0000000..e69de29 diff --git a/rules b/rules new file mode 100755 index 0000000..71eacca --- /dev/null +++ b/rules @@ -0,0 +1,28 @@ +#!/usr/bin/make -f + +ODESTDIR = $(CURDIR)/debian/libppx-visitors-ocaml-dev/usr/lib/ocaml + +%: + dh $@ --with ocaml + +override_dh_auto_build: + # do nothing + +build-arch: + $(MAKE) + +build-indep: + cd doc && $(MAKE) + +override_dh_auto_install: + # do nothing + +override_dh_install-arch: + mkdir -p $(ODESTDIR) + OCAMLFIND_DESTDIR=$(ODESTDIR) make install + +override_dh_install-indep: + dh_installdocs -i + +override_dh_auto_test: + # do nothing diff --git a/source/format b/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/tests/control b/tests/control new file mode 100644 index 0000000..dceeccc --- /dev/null +++ b/tests/control @@ -0,0 +1,2 @@ +Tests: weight +Depends: @, ocaml-nox, libfindlib-ocaml, ocamlbuild diff --git a/tests/weight b/tests/weight new file mode 100755 index 0000000..92826d2 --- /dev/null +++ b/tests/weight @@ -0,0 +1,17 @@ +#!/bin/sh -e + +this=weight +indir=debian/tests +outdir=${ADT_ARTIFACTS:-/tmp}/${this} +mkdir -p ${outdir} + +ppx='visitors.ppx,visitors.runtime' +cp ${indir}/${this}.ml ${outdir} +cd ${outdir} +ocamlbuild -quiet -use-ocamlfind -pkgs ${ppx} weight.byte +[ $(./weight.byte) -eq '16' ] + +if [ -x /usr/bin/ocamlopt ] +then ocamlbuild -quiet -use-ocamlfind -pkgs ${ppx} weight.native; + [ $(./weight.native) -eq '16' ] +fi diff --git a/tests/weight.ml b/tests/weight.ml new file mode 100644 index 0000000..33eb9b1 --- /dev/null +++ b/tests/weight.ml @@ -0,0 +1,27 @@ +type expr = + | EConst of int + | EAdd of expr * expr + [@@deriving visitors { variety = "iter" }] + +let weight (e : expr) : int = +(* return the weight of an expr, where the weight of constants is its *) +(* value, and additions have weight 5. *) + let v = object + val mutable weight = 0 + method weight = weight + inherit [_] iter as super + method! visit_EAdd env e0 e1 = + weight <- weight + 5; + super#visit_EAdd env e0 e1 + method! visit_EConst env i = + weight <- weight + i; + super#visit_EConst env i + end in + v#visit_expr () e; + v#weight +;; + +let c = EConst 2 in + let e = EAdd(c,EAdd(c,c)) in + print_int (weight e) +;; diff --git a/watch b/watch new file mode 100644 index 0000000..581a47b --- /dev/null +++ b/watch @@ -0,0 +1,4 @@ +version=4 +opts="mode=git, pgpmode=none" \ + https://gitlab.inria.fr/fpottier/visitors.git \ + refs/tags/([\d]+) -- cgit v1.2.3 From f36c6e7064524903ca7b132b37b2924851958f49 Mon Sep 17 00:00:00 2001 From: Ralf Treinen Date: Wed, 17 Jul 2019 22:52:52 +0200 Subject: Import ocaml-visitors_20190711.orig.tar.xz [dgit import orig ocaml-visitors_20190711.orig.tar.xz] --- .gitignore | 12 + AUTHORS | 3 + CHANGES.md | 103 + GNUmakefile | 174 + LICENSE | 502 + Makefile | 4 + NOTES | 75 + README.md | 26 + TODO | 112 + doc/.gitignore | 26 + doc/Makefile | 25 + doc/OOinfererror.ml | 6 + doc/OOinfererroragain.ml | 6 + doc/convention.tex | 49 + doc/english.bib | 15090 +++++++++++++++++++++++++++++++ doc/from-visitors-to-iterators.md | 493 + doc/listings-ocaml.tex | 24 + doc/local.bib | 23 + doc/macros.tex | 123 + doc/main.tex | 2390 +++++ doc/plain.bst | 1106 +++ doc/types.tex | 38 + doc/version.tex | 1 + opam | 27 + src/.merlin | 2 + src/META | 32 + src/Makefile | 67 + src/Makefile.preprocess | 45 + src/Visitors.ml | 1287 +++ src/Visitors.mli | 1 + src/VisitorsAnalysis.ml | 387 + src/VisitorsCompatibility.cppo.ml | 171 + src/VisitorsGeneration.ml | 583 ++ src/VisitorsList.ml | 125 + src/VisitorsPlugin.ml | 4 + src/VisitorsRuntime.ml | 1139 +++ src/VisitorsSettings.ml | 370 + src/VisitorsString.ml | 70 + src/_tags | 13 + src/myocamlbuild.ml | 5 + src/ppx_deriving_visitors.mllib | 8 + test/.merlin | 6 + test/Makefile | 94 + test/OOinfer.ml | 5 + test/OOinfer.mllib | 6 + test/OOinferfixed.ml | 6 + test/OOinferfixedagain.ml | 6 + test/OOinferfixedagaincheck.ml | 6 + test/OOinferself.ml | 6 + test/OOinfervirtual.ml | 6 + test/VisitorsRuntimeBootstrap.ml | 26 + test/VisitorsRuntimeBootstrap.mllib | 1 + test/_tags | 24 + test/attic/expr07.ml | 23 + 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/bench.ml | 136 + test/bench.mllib | 1 + test/build.ml | 10 + test/cil_types.ml | 1811 ++++ test/cil_types.ml.orig | 1775 ++++ test/cil_types.mllib | 1 + test/cil_types_polymorphic.ml | 1780 ++++ test/cil_types_polymorphic.mllib | 1 + test/cloud.ml | 18 + test/delayed_tree.ml | 435 + test/dictionary.ml | 14 + test/expr.ml | 3 + test/expr.mllib | 42 + test/expr00.ml | 4 + test/expr00.mli | 9 + test/expr00endo.ml | 4 + test/expr00fold.ml | 4 + test/expr00fold2.ml | 4 + test/expr01.ml | 4 + test/expr01use.ml | 25 + test/expr01use_variant.ml | 20 + test/expr02.ml | 4 + test/expr03.ml | 4 + test/expr04.ml | 13 + test/expr05.ml | 4 + test/expr05lexico.ml | 20 + test/expr05lexico_test.ml | 11 + test/expr06.ml | 16 + test/expr08.ml | 18 + test/expr08double.ml | 10 + test/expr08extra.ml | 15 + test/expr11.ml | 4 + test/expr12.ml | 4 + test/expr13.ml | 10 + test/expr13double.ml | 10 + test/expr13extra.ml | 26 + test/expr14.ml | 20 + test/expr15.ml | 4 + test/expr15b.ml | 10 + test/expr15c.ml | 5 + test/expr16.ml | 4 + test/expr17.ml | 4 + test/expr_import.ml | 3 + test/expr_import_opaque.ml | 3 + test/expr_info.ml | 8 + test/expr_info_mapreduce.ml | 8 + test/expr_info_mapreduce_test.ml | 29 + test/expr_info_mapreduce_use.ml | 15 + test/expr_info_polymorphic.ml | 9 + test/expr_info_polymorphic_use.ml | 15 + test/expr_info_polymorphic_use_test.ml | 27 + test/expr_info_use.ml | 17 + test/expr_redef.ml | 4 + test/fold.ml | 18 + test/hexpr_polymorphic.ml | 52 + test/mapReduce.ml | 9 + test/map_from_fold.ml | 37 + test/map_from_fold.mli | 6 + test/misc.mllib | 22 + test/monomorphic.ml | 11 + test/monopoly.ml | 18 + test/oexpr_polymorphic.ml | 21 + test/opaque.ml | 21 + test/point.ml | 4 + test/point.mli | 2 + test/polyclass.ml | 8 + test/prefixes.ml | 23 + test/test00.ml | 11 + test/test01.ml | 11 + test/test02.ml | 31 + test/test03.ml | 63 + test/test04.ml | 16 + test/test05.ml | 16 + test/test06.ml | 38 + test/test07.ml | 49 + test/testallprims.ml | 28 + 137 files changed, 32066 insertions(+) create mode 100644 .gitignore create mode 100644 AUTHORS create mode 100644 CHANGES.md create mode 100644 GNUmakefile create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 NOTES create mode 100644 README.md create mode 100644 TODO create mode 100644 doc/.gitignore create mode 100644 doc/Makefile create mode 100644 doc/OOinfererror.ml create mode 100644 doc/OOinfererroragain.ml create mode 100644 doc/convention.tex create mode 100644 doc/english.bib create mode 100644 doc/from-visitors-to-iterators.md create mode 100644 doc/listings-ocaml.tex create mode 100644 doc/local.bib create mode 100644 doc/macros.tex create mode 100644 doc/main.tex create mode 100644 doc/plain.bst create mode 100644 doc/types.tex create mode 100644 doc/version.tex create mode 100644 opam create mode 100644 src/.merlin create mode 100644 src/META create mode 100644 src/Makefile create mode 100644 src/Makefile.preprocess create mode 100644 src/Visitors.ml create mode 100644 src/Visitors.mli create mode 100644 src/VisitorsAnalysis.ml create mode 100644 src/VisitorsCompatibility.cppo.ml create mode 100644 src/VisitorsGeneration.ml create mode 100644 src/VisitorsList.ml create mode 100644 src/VisitorsPlugin.ml create mode 100644 src/VisitorsRuntime.ml create mode 100644 src/VisitorsSettings.ml create mode 100644 src/VisitorsString.ml create mode 100644 src/_tags create mode 100644 src/myocamlbuild.ml create mode 100644 src/ppx_deriving_visitors.mllib create mode 100644 test/.merlin create mode 100644 test/Makefile create mode 100644 test/OOinfer.ml create mode 100644 test/OOinfer.mllib create mode 100644 test/OOinferfixed.ml create mode 100644 test/OOinferfixedagain.ml create mode 100644 test/OOinferfixedagaincheck.ml create mode 100644 test/OOinferself.ml create mode 100644 test/OOinfervirtual.ml create mode 100644 test/VisitorsRuntimeBootstrap.ml create mode 100644 test/VisitorsRuntimeBootstrap.mllib create mode 100644 test/_tags create mode 100644 test/attic/expr07.ml create mode 100644 test/bad/Makefile create mode 100644 test/bad/conflict.ml create mode 100644 test/bad/conflict_at_name.ml create mode 100644 test/bad/conflict_atat_name.ml create mode 100644 test/bad/datacon.ml create mode 100644 test/bad/datacon_at_name.ml create mode 100644 test/bad/visitors.t create mode 100644 test/bench.ml create mode 100644 test/bench.mllib create mode 100644 test/build.ml create mode 100644 test/cil_types.ml create mode 100644 test/cil_types.ml.orig create mode 100644 test/cil_types.mllib create mode 100644 test/cil_types_polymorphic.ml create mode 100644 test/cil_types_polymorphic.mllib create mode 100644 test/cloud.ml create mode 100644 test/delayed_tree.ml create mode 100644 test/dictionary.ml create mode 100644 test/expr.ml create mode 100644 test/expr.mllib create mode 100644 test/expr00.ml create mode 100644 test/expr00.mli create mode 100644 test/expr00endo.ml create mode 100644 test/expr00fold.ml create mode 100644 test/expr00fold2.ml create mode 100644 test/expr01.ml create mode 100644 test/expr01use.ml create mode 100644 test/expr01use_variant.ml create mode 100644 test/expr02.ml create mode 100644 test/expr03.ml create mode 100644 test/expr04.ml create mode 100644 test/expr05.ml create mode 100644 test/expr05lexico.ml create mode 100644 test/expr05lexico_test.ml create mode 100644 test/expr06.ml create mode 100644 test/expr08.ml create mode 100644 test/expr08double.ml create mode 100644 test/expr08extra.ml create mode 100644 test/expr11.ml create mode 100644 test/expr12.ml create mode 100644 test/expr13.ml create mode 100644 test/expr13double.ml create mode 100644 test/expr13extra.ml create mode 100644 test/expr14.ml create mode 100644 test/expr15.ml create mode 100644 test/expr15b.ml create mode 100644 test/expr15c.ml create mode 100644 test/expr16.ml create mode 100644 test/expr17.ml create mode 100644 test/expr_import.ml create mode 100644 test/expr_import_opaque.ml create mode 100644 test/expr_info.ml create mode 100644 test/expr_info_mapreduce.ml create mode 100644 test/expr_info_mapreduce_test.ml create mode 100644 test/expr_info_mapreduce_use.ml create mode 100644 test/expr_info_polymorphic.ml create mode 100644 test/expr_info_polymorphic_use.ml create mode 100644 test/expr_info_polymorphic_use_test.ml create mode 100644 test/expr_info_use.ml create mode 100644 test/expr_redef.ml create mode 100644 test/fold.ml create mode 100644 test/hexpr_polymorphic.ml create mode 100644 test/mapReduce.ml create mode 100644 test/map_from_fold.ml create mode 100644 test/map_from_fold.mli create mode 100644 test/misc.mllib create mode 100644 test/monomorphic.ml create mode 100644 test/monopoly.ml create mode 100644 test/oexpr_polymorphic.ml create mode 100644 test/opaque.ml create mode 100644 test/point.ml create mode 100644 test/point.mli create mode 100644 test/polyclass.ml create mode 100644 test/prefixes.ml create mode 100644 test/test00.ml create mode 100644 test/test01.ml create mode 100644 test/test02.ml create mode 100644 test/test03.ml create mode 100644 test/test04.ml create mode 100644 test/test05.ml create mode 100644 test/test06.ml create mode 100644 test/test07.ml create mode 100644 test/testallprims.ml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b3ae41b --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +# Editing: +*~ + +# Compilation: +*.native +_build* +*.processed.ml + +# MacOS: +.DS_Store + +doc/auto diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..dd8061e --- /dev/null +++ b/AUTHORS @@ -0,0 +1,3 @@ +François Pottier +Inria Paris +francois.pottier@inria.fr diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 0000000..3ffc3e4 --- /dev/null +++ b/CHANGES.md @@ -0,0 +1,103 @@ +# Changes + +## 2018/05/13 + +* Fixes in `_tags` and `META` so as to allow `visitors` + to be used in `jbuilder` (`dune`) projects. + (Contributed by Armaël Guéneau.) + +## 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 + missing. (Suggested by Ralf Treinen.) + +## 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.`. + +## 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. diff --git a/GNUmakefile b/GNUmakefile new file mode 100644 index 0000000..57885ea --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,174 @@ +# ------------------------------------------------------------------------- + +# This Makefile is not distributed. + +SHELL := bash +export CDPATH= + +.PHONY: package check export tag opam pin unpin versions + +# ------------------------------------------------------------------------- + +include Makefile + +# ------------------------------------------------------------------------- + +# Utilities. + +MD5SUM := $(shell if command -v md5 >/dev/null 2>/dev/null ; \ + then echo "md5 -r" ; else echo md5sum ; fi) + +# ------------------------------------------------------------------------- + +# Distribution. + +# The version number is automatically set to the current date, +# unless DATE is defined on the command line. +DATE := $(shell /bin/date +%Y%m%d) + +PACKAGE := visitors-$(DATE) +CURRENT := $(shell pwd) +TARBALL := $(CURRENT)/$(PACKAGE).tar.gz + +# ------------------------------------------------------------------------- + +# A list of files to copy without changes to the package. +# +# This does not include the src/ and doc/ directories, which require +# special treatment. + +DISTRIBUTED_FILES := AUTHORS CHANGES.md LICENSE Makefile + +# ------------------------------------------------------------------------- + +# Creating a tarball for distribution. + +package: +# Make sure the correct version is installed. + @ make -C src reinstall +# Create a directory to store the distributed files temporarily. + @ rm -rf $(PACKAGE) + @ mkdir -p $(PACKAGE)/src + @ cp $(DISTRIBUTED_FILES) $(PACKAGE) + @ cp src/*.ml{,i,lib} src/Makefile src/Makefile.preprocess src/META src/_tags $(PACKAGE)/src +# Set the version number into the files that mention it. +# These include version.tex, META. + @ echo "Setting version to $(DATE)." + @ echo version = \"$(DATE)\" >> $(PACKAGE)/src/META +# Copy and compile the documentation. +# This requires %.processed.ml files in the test/ directory, +# which in turn requires building (and installing) in src/. + @ echo "Generating the documentation." + @ cp -r doc test $(PACKAGE) + @ make -C $(PACKAGE)/test clean processed + @ echo '\gdef\visitorsversion{$(DATE)}' > $(PACKAGE)/doc/version.tex + @ make -C $(PACKAGE)/doc clean all + @ mv $(PACKAGE)/doc/main.pdf $(PACKAGE)/manual.pdf + @ rm -rf $(PACKAGE)/doc $(PACKAGE)/test + @ make -C $(PACKAGE)/src clean +# Create the tarball. + @ echo "Creating a tarball." + tar --exclude-from=.gitignore -cvz -f $(TARBALL) $(PACKAGE) + @ echo "The package $(PACKAGE).tar.gz is ready." + +# ------------------------------------------------------------------------- + +# Checking the tarball that was created above. + +check: + @ echo "Checking the package ..." +# Create a temporary directory; extract, build, and install. + @ TEMPDIR=`mktemp -d /tmp/visitors-test.XXXXXX` && { \ + echo " * Extracting. " && \ + (cd $$TEMPDIR && tar xfz $(TARBALL)) && \ + echo " * Compiling and installing." && \ + (cd $$TEMPDIR/$(PACKAGE) && make reinstall \ + ) > $$TEMPDIR/install.log 2>&1 \ + || (cat $$TEMPDIR/install.log; exit 1) && \ + echo " * Uninstalling." && \ + (cd $$TEMPDIR/$(PACKAGE) && make uninstall \ + ) > $$TEMPDIR/uninstall.log 2>&1 \ + || (cat $$TEMPDIR/uninstall.log; exit 1) && \ + rm -rf $$TEMPDIR ; } + @ echo "The package $(PACKAGE) seems ready for distribution!" + +# ------------------------------------------------------------------------- + +# Copying the tarball to my Web site. + +RSYNC := scp -p -C +TARGET := yquem.inria.fr:public_html/visitors/ + +export: +# Copier l'archive et la doc vers yquem. + $(RSYNC) $(TARBALL) $(TARGET) + $(RSYNC) $(PACKAGE)/manual.pdf $(TARGET) + +# ------------------------------------------------------------------------- + +# Creating a git tag. + +tag: + git tag -a $(DATE) -m "Release $(DATE)." + +# ------------------------------------------------------------------------- + +# Updating the opam package. + +# This entry assumes that "make package" and "make export" have been +# run on the same day. + +OPAM := $(HOME)/dev/opam-repository +CSUM = $(shell $(MD5SUM) visitors-$(DATE).tar.gz | cut -d ' ' -f 1) + +opam: +# Update my local copy of the opam repository. + @ echo "Updating local opam repository..." + @ cd $(OPAM) && \ + git fetch upstream && \ + git merge upstream/master +# Create a new package, based on the last one. + @ echo "Creating a new package description visitors-$(DATE)..." + @ cd $(OPAM)/packages/visitors && \ + cp -r `ls | grep visitors | tail -1` visitors.$(DATE) +# Update the file "url". + @ cd $(OPAM)/packages/visitors/visitors.$(DATE) && \ + rm url && \ + echo 'archive: "http://gallium.inria.fr/~fpottier/visitors/visitors-$(DATE).tar.gz"' >> url && \ + echo 'checksum: "$(CSUM)"' >> url +# Copy the file "opam" from Visitors's repository to opam's. + @ cp -f opam $(OPAM)/packages/visitors/visitors.$(DATE) +# Prepare a commit. + @ echo "Preparing a new commit..." + @ cd $(OPAM)/packages/visitors && \ + git add visitors.$(DATE) && \ + git status +# Ask for review. + @ echo "If happy, please run:" + @ echo " cd $(OPAM)/packages/visitors && git commit -a && git push && firefox https://github.com/" + @ echo "and issue a pull request." + +# ------------------------------------------------------------------------- + +# Pinning. + +pin: + opam pin add visitors `pwd` -k git + +unpin: + opam pin remove visitors + +# ------------------------------------------------------------------------- + +# Trying out compilation under multiple versions of OCaml. + +# TEMPORARY (ppx_import currently unavailable on 4.08) + +versions: + for i in 4.02.3 4.03.0 4.04.0 4.05.0 4.06.0 4.07.0 4.08.0 ; do \ + opam switch $$i && eval `opam config env` && ocamlc -v && \ + opam install hashcons ppx_deriving ocp-indent && \ + make clean && \ + make && \ + make reinstall ; \ + done diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..4362b49 --- /dev/null +++ b/LICENSE @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b70389d --- /dev/null +++ b/Makefile @@ -0,0 +1,4 @@ +.PHONY: all clean install uninstall reinstall + +all clean install uninstall reinstall: + $(MAKE) -C src $@ diff --git a/NOTES b/NOTES new file mode 100644 index 0000000..38c0cfc --- /dev/null +++ b/NOTES @@ -0,0 +1,75 @@ +------------------------------------------------------------------------------ + +On named method parameters + +When the arguments of a data constructor are arranged in an inline record, we +would ideally like the data constructor's descending method to receive named +arguments. E.g., it could receive a record as an argument. But that does not +work, because we would need to declare a record type, with the same fields. +Or, it could take labeled arguments. That would work, I think, but we prefer +to avoid labels. Our solution, for now, is to pass unnamed arguments to the +descending method. The arguments appear in the same order as in the data +constructor declaration. + +Similarly, the ascending methods for records and for inline records currently +receive anonymous arguments. + +------------------------------------------------------------------------------ + +On type variables + +Can we deal with parameterized type declarations? Yes, we can, but we should +distinguish two approaches. + +The "monomorphic" approach assumes (requires) that a local parameterized type +is always applied to the same actual arguments. So, it is just as if we have a +type \Lambda at the top level and, under that, we are dealing with ordinary +unparameterized types. This approach naturally leads to generated code where +every method has a monomorphic type, but our class declarations are +parameterized (they have a type \Lambda at the top level). In fact, the +quantification over 'self is probably sufficient to take care of this aspect; +no extra type parameters are required. In this approach, a type variable 'a is +traversed by invoking a virtual method, [visit_'a]. + +The "polymorphic" approach allows a type constructor (which could be local, +say 'a term, or nonlocal, say 'a list) to be instantiated in multiple sites +with distinct (vectors of) actual arguments. This approach requires +polymorphic methods. In the subclass [iter], for example, the visitor method +[visit_list] could have type: + + 'env 'a0. ('env -> 'a0 -> unit) -> 'env -> 'a0 list -> unit + +In the subclass [map], it could have type: + + 'env 'a0 'a1. ('env -> 'a0 -> 'a1) -> 'env -> 'a0 term -> 'a1 term + +In this approach, a type variable 'a is traversed by invoking a visitor +function which has been received as an argument. + +In the first release of visitors, only the monomorphic approach was supported. +However, the hand-written classes in VisitorsRuntime follow the polymorphic +approach, for greater generality. + +It should be noted that the polymorphic approach is not always preferable to +the monomorphic approach. Indeed, assigning to a method a more general type +makes this method easier to *use*, but more difficult to *override*. + +------------------------------------------------------------------------------ + +Base class, or no base class + +I initially thought that [iter] and [map] should be subclasses of a base class +[visitor], as they differ only in the ascending computation: to do nothing in +[iter], and to reconstruct a data structure in [map]. + +However, a difficulty with this approach is that this requires declaring +virtual methods in the base class [visitor], and these virtual methods must +have a monomorphic type, even if they are invoked in several places -- which +is typically the case for nonlocal (parameterized) types, such as tuples, +lists, options, and pre-existing user-defined type constructors. This leads to +an unacceptable lack of generality. + +A different approach is to generate [iter] and [map] directly, without a base +class. In the case of nonlocal types, we allow the user to provide (possibly +polymorphic) code. This solves the problem. (Furthermore, we probably gain +some speed by saving a few virtual method calls.) diff --git a/README.md b/README.md new file mode 100644 index 0000000..edd2567 --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +An OCaml syntax extension (technically, a ppx_deriving plugin) which generates +object-oriented visitors for traversing and transforming data structures. + +Here is the [documentation of the latest released version](http://gallium.inria.fr/~fpottier/visitors/manual.pdf). + +The easiest way of installing the latest released version of this package is +via `opam`, the OCaml package manager. +```bash +opam update +opam install visitors +``` + +To install the latest development version, also via `opam`, please proceed as follows: +```bash + git clone https://gitlab.inria.fr/fpottier/visitors.git + cd visitors + make pin +``` + +To install the latest development version, outside of `opam`, please proceed as follows: +```bash + git clone https://gitlab.inria.fr/fpottier/visitors.git + cd visitors + make install +``` +This requires `ocamlfind`, `ocamlbuild`, `ppx_tools`, and `ppx_deriving`. diff --git a/TODO b/TODO new file mode 100644 index 0000000..6ab2f4a --- /dev/null +++ b/TODO @@ -0,0 +1,112 @@ +------------------------------------------------------------------------------ + +TODO (REALLY) + +Better clean up & share code at the three call sites of [bulk]. + +Update the release scripts so that no .tar.gz archive is explicitly created +(i.e., installation takes place directly based on the repository contents) +and the release is hosted on gitlab.inria.fr. + +------------------------------------------------------------------------------ + +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, + because they are placed in the generated code. + Can we fix this? + e.g. type t = A of (int -> int)[@opaque] + +In fully [polymorphic] mode, perhaps one could allow [@@deriving visitors] + to be used in an .mli file, producing class types. + +In [polymorphic] mode, we could annotate every invocation + of an external visitor method with its expected (polymorphic) type, + so as to get better type error messages if this method does not have + the expected type. + +Ideally, a visitor method should be parameterized with visit_'a + only if 'a appears in the type of some component. +It would be good if a type parameter ['a] could be declared never-visited, + so the method or function [visit_'a] would be unneeded. + Could be useful for phantom type parameters, GADTs, 'bn, etc. + The problem is, when a nonlocal type constructor is applied, + we cannot know which parameters are phantom. + Unless we find a way of declaring that, too? + +Think about enabling [polymorphic] and [fold] together. +That would require letting the user specify the result type + associated with each type constructor. + +Implement and document endoreduce? + Share code by using "Map endo" internally where endo : bool. + +Maybe [fold] and [fold2] in VisitorsRuntime should just be aliases + for [map] and [map2]. The user can use [nude] if that it is not appropriate. + +Once we have that, can we deal with GADTs? + +In [fold], + the build_ methods could take not only the results of the recursive calls, + but also their arguments (for added expressive power). That would be a + true "recursor" (David Chemouil). + +Could we have visitors where a state is explicitly threaded from left to right? + (David Chemouil.) +For greater generality, maybe we should have monadic visitors. +Currently, the environment monad (a reader monad) is built-in. +Could we let the user choose which monad should be used, + without breaking compatibility? + +Develop a real test suite, with expected output. + Check for left-to-right traversal order. + Release the test suite, too? + Some tests have dependencies on other packages: hashcons, core_bench... + Run these tests only if these packages are installed, warn otherwise? + +Add [opaque] as an option, carrying a list of types. + That would be lighter than writing [@opaque] at every occurrence. + +Include an option [except t] to omit the definition of visitor methods for the type [t]. + That would allow the user to provide their own implementation, + (possibly inherited / polymorphic), + without having to satisfy the type constraints imposed by our implementation. + e.g. could generate a [map] visitor where one type (in a family) is rewritten to something completely different + +Detect and reject existential types and GADTs. + +Could define a fold visitor where the methods receive the names of the types, +data constructors, and record fields that are being visited. (As in +ppx_tools/genlifter.) + +Develop [@deriving zippers] to produce a type of zippers, + and add an option for the environment to be a zipper + that is extended at every recursive call. (Yann Régis-Gianas.) + Parameterize the type of zippers by the type of their root + and allow the constructor Nil only when the root type and + the current type coincide. (GADT.) + So that we get n zipper types out of n source types. + +Avoid generating beta-redexes. + (fun (x, y) -> ...) z should be let (x, y) = z in ... + See [visit_types]. + +Re-introduce hoisting of closure allocations of the form [self#visit_foo]? + If so, share them when they have several occurrences. + +Think about generating analyze_ methods + which perform a fixed point computation (use Fix) + based only on the type structure + so as to allow a static analysis of the type structure, + which could be exploited to optimize runtime traversals. + One would have to lose precision at parameterized types, or expand them away. diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 0000000..63bf318 --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1,26 @@ +# TeX. +main.pdf +talk.pdf +*.aux +*.aux.bak +*.bbl +*.blg +*.log +*.out +*.nav +*.snm +*.toc +*.vrb + +# WhizzyTeX. +._whizzy* +_whizzy* +*.raux +*.wdvi +*.dvi +*.waux +*.fmt + +# latexmk +*.fdb_latexmk +*.fls diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000..baaf713 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,25 @@ +export VISITORS_BUILDING_DOCUMENTATION=true + +include ../src/Makefile.preprocess + +export TEXINPUTS=.:../test: + +.PHONY: all loop clean + +all: main.pdf + +SOURCES := $(wildcard *.tex) $(wildcard *.bib) $(wildcard *.sty) +ML := $(shell ls ../test/*.ml | grep -v processed) +PROCESSED := $(patsubst %.ml,%.processed.ml,$(ML)) + +%.pdf: %.tex $(SOURCES) $(ML) $(PROCESSED) + pdflatex $* + bibtex $* + pdflatex $* + pdflatex $* + +loop: $(SOURCES) $(ML) $(PROCESSED) + latexmk -pdf -pvc main + +clean: + rm -f *.log *.aux *.bbl *.blg *.out *.toc *~ main.pdf diff --git a/doc/OOinfererror.ml b/doc/OOinfererror.ml new file mode 100644 index 0000000..38d0d65 --- /dev/null +++ b/doc/OOinfererror.ml @@ -0,0 +1,6 @@ +class virtual int_cell = object (self) + val mutable x = 0 + method get = x + method set y = x <- self#check y + method virtual check: _ +end diff --git a/doc/OOinfererroragain.ml b/doc/OOinfererroragain.ml new file mode 100644 index 0000000..ff90009 --- /dev/null +++ b/doc/OOinfererroragain.ml @@ -0,0 +1,6 @@ +class virtual ['a] cell (init) = object (self) + val mutable x = init + method get = x + method set y = x <- self#check y + method virtual check: 'a -> _ +end diff --git a/doc/convention.tex b/doc/convention.tex new file mode 100644 index 0000000..a01c0f3 --- /dev/null +++ b/doc/convention.tex @@ -0,0 +1,49 @@ +\begin{figure}[p] +\begin{mdframed}[backgroundcolor=green!10] +\begin{lstlisting} +class ['self] iter : object ('self) + method private visit_list: 'env 'a . + ('env -> 'a -> unit) -> 'env -> 'a list -> unit +end +class ['self] map : object ('self) + method private visit_list: 'env 'a 'b . + ('env -> 'a -> 'b) -> 'env -> 'a list -> 'b list +end +class ['self] endo : object ('self) + method private visit_list: 'env 'a . + ('env -> 'a -> 'a) -> 'env -> 'a list -> 'a list +end +class virtual ['self] reduce : object ('self) + inherit ['s] monoid + method private visit_list: 'env 'a . + ('env -> 'a -> 's) -> 'env -> 'a list -> 's +end +class virtual ['self] mapreduce : object ('self) + inherit ['s] monoid + method private visit_list: 'env 'a 'b . + ('env -> 'a -> 'b * 's) -> 'env -> 'a list -> 'b list * 's +end +class ['self] iter2 : object ('self) + method private visit_list: 'env 'a 'b . + ('env -> 'a -> 'b -> unit) -> 'env -> 'a list -> 'b list -> unit +end +class ['self] map2 : object ('self) + method private visit_list: 'env 'a 'b 'c . + ('env -> 'a -> 'b -> 'c) -> 'env -> 'a list -> 'b list -> 'c list +end +class virtual ['self] reduce2 : object ('self) + inherit ['s] monoid + method private visit_list: 'env 'a 'b . + ('env -> 'a -> 'b -> 's) -> 'env -> 'a list -> 'b list -> 's +end +class virtual ['self] mapreduce2 : object ('self) + inherit ['s] monoid + method private visit_list: 'env 'a 'b 'c . + ('env -> 'a -> 'b -> 'c * 's) -> + 'env -> 'a list -> 'b list -> 'c list * 's +end +\end{lstlisting} +\end{mdframed} +\caption{Conventional types of polymorphic visitor methods} +\label{fig:convention} +\end{figure} diff --git a/doc/english.bib b/doc/english.bib new file mode 100644 index 0000000..1d5f136 --- /dev/null +++ b/doc/english.bib @@ -0,0 +1,15090 @@ +@String{acmp = "ACM Press"} + +@String{acsac = "Annual Computer Security Applications Conference"} + +@String{acta = "Acta Informatica"} + +@String{afp = "Advanced Functional Programming"} + +@String{amast = "International Conference on Algebraic Methodology and + Software Technology (AMAST)"} + +@String{ams = "American Mathematical Society"} + +@String{ap = "Academic Press"} + +@String{apal = "Annals of Pure and Applied Logic"} + +@String{aplas = "Asian Symposium on Programming Languages and Systems + (APLAS)"} + +@String{asian = "Asian Computer Science Conference ({ASIAN})"} + +@String{aw = "Addison-Wesley"} + +@String{cacm = "Communications of the {ACM}"} + +@String{cade = "International Conference on Automated Deduction + (CADE)"} + +@String{carleton = "Carleton Scientific"} + +@String{cassis = "Construction and Analysis of Safe, Secure and + Interoperable Smart devices (CASSIS)"} + +@String{cav = "Computer Aided Verification (CAV)"} + +@String{cc = "Compiler Construction (CC)"} + +@String{cdcs = "International Conference on Distributed Computing + Systems (CDCS)"} + +@String{cj = "Computer Journal"} + +@String{computer = "Computer"} + +@String{concur = "International Conference on Concurrency Theory + (CONCUR)"} + +@String{cpp = "Certified Programs and Proofs (CPP)"} + +@String{csfw = "{IEEE} Computer Security Foundations Workshop"} + +@String{csl = "Computer Science Logic"} + +@String{cup = "Cambridge University Press"} + +@String{dac = "Design Automation Conference (DAC)"} + +@String{decsrc = "Digital Equipment Corporation, Systems Research + Center"} + +@String{dls = "Symposium on Dynamic Languages"} + +@String{dspg = "Domain-Specific Program Generation (DSPG)"} + +@String{ecoop = "European Conference on Object-Oriented Programming + (ECOOP)"} + +@String{ellis = "Ellis Horwood"} + +@String{elsevier = "Elsevier Science"} + +@String{entcs = "Electronic Notes in Theoretical Computer Science"} + +@String{esop = "European Symposium on Programming (ESOP)"} + +@String{esorics = "European Symposium on Research in Computer Security"} + +@String{eurosys = "EuroSys"} + +@String{fac = "Formal Aspects of Computing"} + +@String{fics = "International workshop on Fixed Points in Computer + Science (FICS)"} + +@String{flops = "Functional and Logic Programming"} + +@String{fm = "Formal Methods (FM)"} + +@String{fmco = "Formal Methods for Components and Objects"} + +@String{fmsd = "Formal Methods in System Design"} + +@String{fool = "Foundations of Object-Oriented Languages (FOOL)"} + +@String{fopara = "Foundational and Practical Aspects of Resource + Analysis"} + +@String{fosad = "Foundations of Security Analysis and Design"} + +@String{fossacs = "Foundations of Software Science and Computation + Structures ({FOSSACS})"} + +@String{fpca = "Functional Programming Languages and Computer + Architecture (FPCA)"} + +@String{fse = "Workshop on Foundations of Software Engineering"} + +@String{fsttcs = "Foundations of Software Technology and Theoretical + Computer Science (FSTTCS)"} + +@String{ftfjp = "Formal Techniques for {Java}-like Programs"} + +@String{fundamenta = "Fundamenta Informaticæ"} + +@String{gcse = "Generative and Component-Based Software Engineering"} + +@String{gpce = "Generative Programming and Component Engineering + (GPCE)"} + +@String{hav = "Heap Analysis and Verification (HAV)"} + +@String{hilt = "ACM SIGAda Annual Conference on High Integrity + Language Technology (HILT)"} + +@String{hlcl = "High-Level Concurrent Languages (HLCL)"} + +@String{hoots = "Higher Order Operational Techniques in Semantics + (HOOTS)"} + +@String{hopl = "History of Programming Languages"} + +@String{hosc = "Higher-Order and Symbolic Computation"} + +@String{hotpar = "USENIX Conference on Hot Topics in Parallelism + (HotPar)"} + +@String{hs = "Haskell symposium"} + +@String{hw = "Haskell workshop"} + +@String{ic = "Information and Computation"} + +@String{icalp = "International Colloquium on Automata, Languages and + Programming"} + +@String{icfem = "International Conference on Formal Engineering Methods + (ICFEM)"} + +@String{icfp = "International Conference on Functional Programming + (ICFP)"} + +@String{iclp = "International Conference on Logic Programming (ICLP)"} + +@String{icse = "International Conference on Software Engineering + ({ICSE})"} + +@String{ictl = "International Conference on Temporal Logic (ICTL)"} + +@String{ie = "InterEditions"} + +@String{ifiptcs = "IFIP International Conference on Theoretical Computer + Science (TCS)"} + +@String{ifl = "Implementation of Functional Languages (IFL)"} + +@String{ijcai = "International Joint Conferences on Artificial + Intelligence"} + +@String{ijfcs = "International Journal of Foundations of Computer + Science"} + +@String{ipl = "Information Processing Letters"} + +@String{issta = "International Symposium on Software Testing and + Analysis (ISSTA)"} + +@String{ist = "Information and Software Technology"} + +@String{ita = "Informatique théorique et applications"} + +@String{itp = "Interactive Theorem Proving (ITP)"} + +@String{itrs = "Workshop on Intersection Types and Related Systems + (ITRS)"} + +@String{jacm = "Journal of the {ACM}"} + +@String{jar = "Journal of Automated Reasoning"} + +@String{jfla = "Journées Françaises des Langages Applicatifs + (JFLA)"} + +@String{jfp = "Journal of Functional Programming"} + +@String{jfr = "Journal of Formalized Reasoning"} + +@String{jlap = "Journal of Logic and Algebraic Programming"} + +@String{jlc = "Journal of Logic and Computation"} + +@String{jlp = "Journal of Logic Programming"} + +@String{jot = "Journal of Object Technology"} + +@String{jsc = "Journal of Symbolic Computation"} + +@String{jucs = "Journal of Universal Computer Science"} + +@String{kluwer = "Kluwer"} + +@String{lfm = "Workshop on Logical Frameworks and Meta-Languages + (LFM)"} + +@String{lfp = "ACM Symposium on Lisp and Functional Programming + (LFP)"} + +@String{lics = "Logic in Computer Science (LICS)"} + +@String{lipics = "{Leibniz} International Proceedings in Informatics"} + +@String{lmcs = "Logical Methods in Computer Science"} + +@String{lnai = "Lecture Notes in Artificial Intelligence"} + +@String{lncs = "Lecture Notes in Computer Science"} + +@String{lola = "Workshop on Syntax and Semantics of Low Level + Languages"} + +@String{loplas = "ACM Letters on Programming Languages and Systems"} + +@String{lpar = "Logic for Programming Artificial Intelligence and + Reasoning (LPAR)"} + +@String{lsc = "Lisp and Symbolic Computation"} + +@String{merlin = "ACM Workshop on Mechanized Reasoning about Languages + with Variable Binding"} + +@String{mfcs = "International Symposium on Mathematical Foundations of + Computer Science"} + +@String{mfps = "Mathematical Foundations of Programming Semantics"} + +@String{mitp = "MIT Press"} + +@String{ml = "ACM Workshop on ML"} + +@String{mlapp = "ACM Workshop on ML and its Applications"} + +@String{mpc = "Mathematics of Program Construction (MPC)"} + +@String{mscs = "Mathematical Structures in Computer Science"} + +@String{msfp = "ACM SIGPLAN Workshop on Mathematically Structured + Functional Programming (MSFP)"} + +@String{ndss = "Internet Society Symposium on Network and Distributed + System Security"} + +@String{nfm = "{NASA} Formal Methods (NFM)"} + +@String{njc = "Nordic Journal of Computing"} + +@String{notices = "{ACM} {SIGPLAN} Notices"} + +@String{nspw = "New Security Paradigms Workshop"} + +@String{onward = "{ACM} Symposium on New Ideas in Programming and + Reflections on Software (Onward!)"} + +@String{oopsla = "Object-Oriented Programming, Systems, Languages, and + Applications (OOPSLA)"} + +@String{oopslacomp = "Companion to Object-Oriented Programming, Systems, + Languages, and Applications (OOPSLA)"} + +@String{padl = "Practical Aspects of Declarative Languages (PADL)"} + +@String{palgrave = "Palgrave Macmillan"} + +@String{pcc = "International Workshop on Proof-Carrying Code (PCC)"} + +@String{pepm = "{ACM} Workshop on Evaluation and Semantics-Based + Program Manipulation ({PEPM})"} + +@String{pi = "Proceedings in Informatics"} + +@String{pieee = "Proceedings of the IEEE"} + +@String{pldi = "{Programming Language Design and Implementation + (PLDI)}"} + +@String{plilp = "Programming Languages: Implementations, Logics, and + Programs (PLILP)"} + +@String{plpv = "Programming Languages Meets Program Verification + (PLPV)"} + +@String{popl = "Principles of Programming Languages ({POPL})"} + +@String{ppcp = "International Workshop on Principles and Practice of + Constraint Programming (PPCP)"} + +@String{ppdp = "Principles and Practice of Declarative Programming + (PPDP)"} + +@String{prentice = "Prentice Hall"} + +@String{rairo = "RAIRO Theoretical Informatics and Applications"} + +@String{rta = "Rewriting Techniques and Applications (RTA)"} + +@String{saig = "International Workshop on Semantics, Applications, and + Implementation of Program Generation (SAIG)"} + +@String{sas = "Static Analysis Symposium (SAS)"} + +@String{scp = "Science of Computer Programming"} + +@String{siamjc = "SIAM Journal on Computing"} + +@String{sigops = "ACM Operating Systems Review"} + +@String{sle = "Software Language Engineering"} + +@String{snapl = "Summit on Advances in Programming Languages (SNAPL)"} + +@String{soda = "Symposium on Discrete Algorithms (SODA)"} + +@String{sp = "{IEEE} Symposium on Security and Privacy (S\&P)"} + +@String{spe = "Software: Practice and Experience"} + +@String{springer = "Springer"} + +@String{stoc = "ACM Symposium on Theory of Computing"} + +@String{sttt = "Software Tools for Technology Transfer"} + +@String{surveys = "{ACM} Computing Surveys"} + +@String{tacas = "Tools and Algorithms for Construction and Analysis of + Systems (TACAS)"} + +@String{tacs = "International Symposium on Theoretical Aspects of + Computer Software (TACS)"} + +@String{tams = "Transactions of the American Mathematical Society"} + +@String{taoop = "Theoretical Aspects Of Object-Oriented Programming: + Types, Semantics and Language Design"} + +@String{tapos = "Theory and Practice of Object Systems"} + +@String{tapsoft = "Theory and Practice of Software Development + ({TAPSOFT})"} + +@String{tcs = "Theoretical Computer Science"} + +@String{tcsconf = "IFIP International Conference on Theoretical Computer + Science (TCS)"} + +@String{tfp = "Trends in Functional Programming (TFP)"} + +@String{tic = "Types in Compilation (TIC)"} + +@String{tissec = "ACM Transactions on Information and System Security"} + +@String{tlca = "Typed Lambda Calculi and Applications (TLCA)"} + +@String{tldi = "Types in Language Design and Implementation (TLDI)"} + +@String{tocl = "ACM Transactions on Computational Logic"} + +@String{tods = "ACM Transactions on Database Systems"} + +@String{toplas = "ACM Transactions on Programming Languages and + Systems"} + +@String{tose = "IEEE Transactions on Software Engineering"} + +@String{tosem = "ACM Transactions on Software Engineering and + Methodology"} + +@String{tphol = "Theorem Proving in Higher Order Logics (TPHOLs)"} + +@String{types = "Types for Proofs and Programs"} + +@String{vmcai = "Verification, Model Checking and Abstract + Interpretation (VMCAI)"} + +@String{vstte = "Verified Software: Theories, Tools and Experiments"} + +@String{wgp = "Workshop on Generic Programming"} + +@String{wollic = "Workshop on Logic, Language, Information and + Computation (WoLLIC)"} + +@String{wrla = "International Workshop on Rewriting Logic and its + Applications (WRLA)"} + +@String{wsa = "International Workshop on Static Analysis (WSA)"} + +@String{wwv = "Workshop on Automated Specification and Verification + of Web Systems"} + +@InProceedings{abadi-blanchet-01, + author = "Martín Abadi and Bruno Blanchet", + title = "Secrecy Types for Asymmetric Communication", + booktitle = fossacs, + year = "2001", + volume = "2030", + series = lncs, + publisher = springer, + pages = "25--41", + URL = "http://www.di.ens.fr/~blanchet/publications/AbadiBlanchetFOSSACS01.html", +} + +@Article{abadi-cardelli-94, + author = "Mart{\'\i}n Abadi and Luca Cardelli", + title = "A Theory of Primitive Objects: Untyped and First-Order + Systems", + journal = ic, + year = "1996", + volume = "125", + number = "2", + pages = "78--102", + URL = "http://research.microsoft.com/Users/luca/Papers/PrimObj1stOrder.pdf", +} + +@Article{abadi-cardelli-94b, + author = "Mart{\'\i}n Abadi and Luca Cardelli", + title = "A Theory of Primitive Objects: Second-Order Systems", + journal = scp, + year = "1995", + volume = "25", + number = "2--3", + pages = "81--116", + URL = "http://research.microsoft.com/Users/luca/Papers/PrimObj2ndOrder.pdf", +} + +@InProceedings{abadi-dcc-99, + title = "A Core Calculus of Dependency", + author = "Martín Abadi and Anindya Banerjee and Nevin Heintze + and Jon G. Riecke", + booktitle = popl, + year = "1999", + pages = "147--160", + URL = "http://www.soe.ucsc.edu/~abadi/Papers/flowpopl.ps", +} + +@InProceedings{abadi-fiore-96, + author = "Mart{\'\i}n Abadi and Marcelo P. Fiore", + title = "Syntactic Considerations on Recursive Types", + booktitle = lics, + pages = "242--252", + year = "1996", + URL = "http://www.soe.ucsc.edu/~abadi/Papers/rec.ps", +} + +@InProceedings{abadi-lampson-levy-96, + title = "Analysis and Caching of Dependencies", + author = "Martín Abadi and Butler Lampson and Jean-Jacques + Lévy", + pages = "83--91", + booktitle = icfp, + year = "1996", + URL = "http://www.soe.ucsc.edu/~abadi/Papers/make-preprint.ps", +} + +@Article{abadi-pierce-plotkin-91, + author = "Martín Abadi and Benjamin Pierce and Gordon Plotkin", + title = "Faithful Ideal Models for Recursive Polymorphic + Types", + journal = "International Journal of Foundations of Computer + Science", + volume = "2", + number = "1", + year = "1991", + pages = "1--21", + URL = "http://www.cis.upenn.edu/~bcpierce/papers/ideals.ps", +} + +@Article{abel-04, + author = "Andreas Abel", + title = "Termination Checking with Types", + journal = rairo, + year = "2004", + volume = "38", + number = "4", + pages = "277--319", + URL = "http://www2.tcs.ifi.lmu.de/~abel/rairo04.pdf", +} + +@InProceedings{abel-haskell-05, + author = "Andreas Abel and Marcin Benke and Ana Bove and John + Hughes and Ulf Norell", + title = "Verifying {Haskell} programs using constructive type + theory", + booktitle = hw, + year = "2005", + pages = "62--73", + URL = "http://www.tcs.informatik.uni-muenchen.de/~abel/haskell05.pdf", +} + +@InProceedings{abel-miniagda-10, + author = "Andreas Abel", + title = "{MiniAgda}: Integrating Sized and Dependent Types", + booktitle = "Workshop on Partiality And Recursion in Interactive + Theorem Provers (PAR)", + year = "2010", + URL = "http://www2.tcs.ifi.lmu.de/~abel/par10.pdf", +} + +@Article{abramsky-91, + author = "Samson Abramsky", + title = "Domain Theory in Logical Form", + journal = apal, + year = "1991", + volume = "51", + pages = "1--77", + URL = "http://web.comlab.ox.ac.uk/oucl/work/samson.abramsky/dtlf.ps.gz", +} + +@InProceedings{abramsky-honda-mccusker-98, + author = "Samson Abramsky and Kohei Honda and Guy McCusker", + title = "A fully abstract game semantics for general + references", + booktitle = lics, + pages = "334--344", + year = "1998", + URL = "http://web.comlab.ox.ac.uk/people/Samson.Abramsky/lics98.ps.gz", +} + +@Article{achten-plasmeijer-95, + author = "Peter Achten and Marinus J. Plasmeijer", + title = "The Ins and Outs of {Clean} {I/O}", + journal = jfp, + volume = "5", + number = "1", + year = "1995", + pages = "81--110", + URL = "http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.17.935", +} + +@TechReport{agerholm-examples-94, + author = "Sten Agerholm", + title = "{LCF} Examples in {HOL}", + institution = "BRICS", + year = "1994", + number = "RS-94-18", + URL = "http://www.brics.dk/RS/94/18/BRICS-RS-94-18.ps.gz", +} + +@TechReport{agerholm-holcpo-94, + author = "Sten Agerholm", + title = "A {HOL} Basis for Reasoning about Functional + Programs", + institution = "BRICS", + year = "1994", + number = "RS-94-44", + URL = "http://www.brics.dk/RS/94/44/BRICS-RS-94-44.ps.gz", +} + +@PhdThesis{ahmed-04, + author = "Amal Jamil Ahmed", + title = "Semantics of Types for Mutable State", + school = "Princeton University", + year = "2004", + URL = "http://www.cs.indiana.edu/~amal/ahmedsthesis.pdf", +} + +@InProceedings{ahmed-appel-virga-02, + author = "Amal J. Ahmed and Andrew W. Appel and Roberto Virga", + title = "A Stratified Semantics of General References + Embeddable in Higher-Order Logic", + booktitle = lics, + pages = "75--86", + year = "2002", + URL = "http://www.cs.princeton.edu/sip/pub/stratified-lics02.pdf", +} + +@InProceedings{ahmed-blume-08, + author = "Amal Ahmed and Matthias Blume", + title = "Typed closure conversion preserves observational + equivalence", + booktitle = icfp, + year = "2008", + pages = "157--168", + URL = "http://ttic.uchicago.edu/~amal/papers/tccpoe.pdf", +} + +@InProceedings{ahmed-dreyer-rossberg-09, + author = "Amal Ahmed and Derek Dreyer and Andreas Rossberg", + title = "State-dependent representation independence", + booktitle = popl, + year = "2009", + pages = "340--353", + URL = "http://ttic.uchicago.edu/~amal/papers/sdri.pdf", +} + +@InProceedings{ahmed-fluet-morrisett-05, + author = "Amal J. Ahmed and Matthew Fluet and Greg Morrisett", + title = "A step-indexed model of substructural state", + booktitle = icfp, + year = "2005", + pages = "78--91", + URL = "http://www.cs.rit.edu/~mtf/research/substruct-state/ICFP05/icfp05.pdf", +} + +@Article{ahmed-semantic-tal-10, + author = "Amal Ahmed and Andrew W. Appel and Christopher D. + Richards and Kedar N. Swadi and Gang Tan and Daniel C. + Wang", + title = "Semantic foundations for typed assembly languages", + journal = toplas, + volume = "32", + number = "3", + year = "2010", + URL = "http://www.cs.princeton.edu/~appel/papers/sftal.pdf", +} + +@Book{aho-86, + author = "Alfred V. Aho and Ravi Sethi and Jeffrey D. Ullman", + title = "Compilers: Principles, Techniques, and Tools", + publisher = aw, + year = "1986", +} + +@Book{aho-89, + author = "Alfred Aho and Ravi Sethi and Jeffrey Ullman", + title = "Compilateurs: principes, techniques et outils", + publisher = ie, + year = "1989", +} + +@Book{aho-hopcroft-ullman-74, + author = "Alfred V. Aho and John E. Hopcroft and Jeffrey D. + Ullman", + title = "The Design and Analysis of Computer Algorithms", + publisher = aw, + year = "1974", +} + +@Book{aho-hopcroft-ullman-83, + author = "Alfred V. Aho and John E. Hopcroft and Jeffrey D. + Ullman", + title = "Data Structures and Algorithms", + year = "1983", + publisher = aw, +} + +@Article{aho-optim-72, + author = "Alfred V. Aho and Jeffrey D. Ullman", + title = "Optimization of {LR(k)} parsers", + journal = "Journal of Computer and System Sciences", + volume = "6", + number = "6", + pages = "573--602", + year = "1972", + URL = "http://www.sciencedirect.com/science/article/pii/S002200007280031X", +} + +@Book{aho-ullman-72, + author = "Alfred V. Aho and Jeffrey D. Ullman", + title = "The theory of parsing, translation, and compiling", + year = "1972", + publisher = prentice, + URL = "http://portal.acm.org/citation.cfm?id=SERIES11430.578789", +} + +@Article{aho-ullman-73, + author = "Alfred V. Aho and Jeffrey D. Ullman", + title = "A Technique for Speeding up {LR(k)} Parsers", + journal = siamjc, + volume = "2", + number = "2", + pages = "106--127", + year = "1973", + URL = "http://dx.doi.org/10.1137/0202010", +} + +@Article{aiken-bane-98, + author = "Alexander Aiken and Manuel Fähndrich and Jeffrey S. + Foster and Zhendong Su", + title = "A Toolkit for Constructing Type- and Constraint-Based + Program Analyses", + journal = lncs, + volume = "1473", + pages = "76--96", + year = "1998", + URL = "http://theory.stanford.edu/~aiken/publications/papers/tic98.pdf", +} + +@Article{aiken-faehndrich-levien-95, + author = "Alexander Aiken and Manuel F{\"a}hndrich and Raph + Levien", + title = "Better static memory management: improving + region-based analysis of higher-order languages", + journal = notices, + volume = "30", + number = "6", + pages = "174--185", + year = "1995", + URL = "http://www.eecs.berkeley.edu/Pubs/TechRpts/1995/CSD-95-866.pdf", +} + +@InProceedings{aiken-faehndrich-mixed-97, + author = "Alexander S. Aiken and Manuel F{\"a}hndrich", + title = "Program Analysis Using Mixed Term and Set + Constraints", + pages = "114--126", + booktitle = sas, + year = "1997", + URL = "http://theory.stanford.edu/~aiken/publications/papers/sas97.pdf", +} + +@TechReport{aiken-faehndrich-scale-96, + number = "CSD-96-917", + institution = "University of California, Berkeley", + title = "Making Set-Constraint Based Program Analyses Scale", + year = "1996", + author = "Alexander S. Aiken and Manuel F{\"a}hndrich", + URL = "http://research.microsoft.com/pubs/67469/scw96.pdf", +} + +@TechReport{aiken-faehndrich-subtyping-96, + number = "CSD-96-898", + institution = "University of California, Berkeley", + title = "Subtyping Polymorphic Constrained Types", + year = "1996", + author = "Alexander S. Aiken and Manuel F{\"a}hndrich", +} + +@Misc{aiken-illyria, + author = "Alexander S. Aiken", + title = "The {Illyria} system", + year = "1994", + URL = "http://http.cs.berkeley.edu:80/~aiken/Illyria-demo.html", +} + +@Article{aiken-intro-99, + author = "Alexander Aiken", + title = "Introduction to Set Constraint-Based Program + Analysis", + journal = scp, + year = "1999", + volume = "35", + pages = "79--111", + URL = "http://theory.stanford.edu/~aiken/publications/papers/scp99.pdf", +} + +@TechReport{aiken-palsberg-wimmers-optimal-96, + number = "CSD-96-909", + institution = "University of California, Berkeley", + title = "Optimal Representations of Polymorphic Types with + Subtyping", + year = "1996", + pages = "31", + author = "Alexander S. Aiken and Edward L. Wimmers and Jens + Palsberg", + URL = "http://digitalassets.lib.berkeley.edu/techreports/ucb/text/CSD-96-909.pdf", +} + +@InProceedings{aiken-wimmers-92, + author = "Alexander S. Aiken and Edward L. Wimmers", + title = "Solving Systems of Set Constraints", + pages = "329--340", + booktitle = lics, + year = "1992", + URL = "http://theory.stanford.edu/~aiken/publications/papers/lics92.pdf", +} + +@InProceedings{aiken-wimmers-93, + author = "Alexander S. Aiken and Edward L. Wimmers", + booktitle = fpca, + publisher = acmp, + title = "Type Inclusion Constraints and Type Inference", + year = "1993", + pages = "31--41", + URL = "http://theory.stanford.edu/~aiken/publications/papers/fpca93.pdf", +} + +@InProceedings{aiken-wimmers-lakshman-94, + author = "Alexander S. Aiken and Edward L. Wimmers and T. K. + Lakshman", + booktitle = popl, + title = "Soft Typing with Conditional Types", + year = "1994", + pages = "163--173", + URL = "http://theory.stanford.edu/~aiken/publications/papers/popl94.pdf", +} + +@InProceedings{aldrich-borrowing-12, + title = "A type system for borrowing permissions", + author = "Karl Naden and Robert Bocchino and Jonathan Aldrich + and Kevin Bierhoff", + booktitle = popl, + year = "2012", + pages = "557--570", + URL = "http://cs.cmu.edu/afs/cs.cmu.edu/Web/People/kbn/pubs/poplBorrowing.pdf", +} + +@InProceedings{aldrich-objects-13, + author = "Jonathan Aldrich", + title = "The power of interoperability: why objects are + inevitable", + booktitle = onward, + year = "2013", + pages = "101--116", + URL = "http://www.cs.cmu.edu/~aldrich/papers/objects-essay.pdf", +} + +@Unpublished{aldrich-plaid-10, + author = "Jonathan Aldrich", + title = "Resource-Based Programming in {Plaid}", + note = "Fun Ideas and Thoughts", + year = "2010", + URL = "http://www.cs.cmu.edu/~aldrich/papers/pldi-fit10.pdf", +} + +@InProceedings{aldrich-typestate-09, + author = "Jonathan Aldrich and Joshua Sunshine and Darpan Saini + and {Zacha\-ry} Sparks", + title = "Typestate-Oriented Programming", + booktitle = oopslacomp, + pages = "1015--1022", + year = "2009", + URL = "http://www.cs.cmu.edu/~aldrich/papers/onward2009-state.pdf", +} + +@InProceedings{alias-types-00, + author = "Frederick Smith and David Walker and Greg Morrisett", + title = "Alias Types", + booktitle = esop, + pages = "366--381", + year = "2000", + volume = "1782", + series = lncs, + publisher = springer, + URL = "http://www.cs.cornell.edu/talc/papers/alias.pdf", +} + +@InProceedings{allais-cpp-17, + author = "Guillaume Allais and James Chapman and Conor McBride + and James McKinna", + title = "Type-and-scope Safe Programs and Their Proofs", + booktitle = cpp, + pages = "195--207", + year = "2017", + URL = "http://gallais.github.io/pdf/cpp2017.pdf", +} + +@InProceedings{almeida-97, + author = "Paulo S{\'e}rgio Almeida", + title = "Balloon Types: Controlling Sharing of State in Data + Types", + booktitle = ecoop, + year = "1997", + pages = "32--59", + publisher = springer, + series = lncs, + volume = "1241", + URL = "http://gsd.di.uminho.pt/publications/gsd-1997-04/file/at_download", +} + +@Article{alstrup-al-14, + author = "Stephen Alstrup and Mikkel Thorup and Inge Li G{\o}rtz + and Theis Rauhe and Uri Zwick", + title = "Union-Find with Constant Time Deletions", + journal = "{ACM} Transactions on Algorithms", + volume = "11", + number = "1", + pages = "6:1--6:28", + year = "2014", + URL = "http://doi.acm.org/10.1145/2636922", +} + +@InProceedings{altenkirch-pisigma-10, + author = "Thorsten Altenkirch and Nils Anders Danielsson and + Andres L{\"o}h and Nicolas Oury", + title = "{$\Pi$}{$\Sigma$}: Dependent Types Without the Sugar", + booktitle = flops, + pages = "40--55", + year = "2010", + publisher = springer, + series = lncs, + volume = "6009", + URL = "http://www.cs.nott.ac.uk/~txa/publ/pisigma-new.pdf", +} + +@InProceedings{altenkirch-reus-99, + author = "Thorsten Altenkirch and Bernhard Reus", + title = "Monadic Presentations of Lambda Terms Using + Generalized Inductive Types", + booktitle = csl, + year = "1999", + pages = "453--468", + publisher = springer, + series = lncs, + volume = "1683", + URL = "http://www.cs.nott.ac.uk/~txa/publ/csl99.pdf", +} + +@Article{amadio-cardelli-93, + author = "Roberto M. Amadio and Luca Cardelli", + title = "Subtyping Recursive Types", + journal = toplas, + volume = "15", + number = "4", + pages = "575--631", + year = "1993", + URL = "http://research.microsoft.com/Users/luca/Papers/SRT.pdf", +} + +@InProceedings{amadio-regis-gianas-11, + author = "Roberto Amadio and Yann R{\'{e}}gis{-}Gianas", + title = "Certifying and Reasoning on Cost Annotations of + Functional Programs", + booktitle = fopara, + pages = "72--89", + year = "2011", + series = lncs, + volume = "7177", + publisher = springer, + URL = "https://hal.inria.fr/inria-00629473v1", +} + +@Article{amadio-regis-gianas-13, + title = "Certifying and reasoning about cost annotations of + functional programs", + author = "Roberto Amadio and Yann R{\'e}gis-Gianas", + URL = "https://hal.inria.fr/inria-00629473", + journal = hosc, + year = "2013", +} + +@InProceedings{america-rutten-88, + author = "Pierre America and Jan Rutten", + title = "Solving reflexive domain equations in a category of + complete metric spaces", + booktitle = mfps, + pages = "254--288", + year = "1988", + volume = "298", + series = lncs, + publisher = springer, + URL = "http://dx.doi.org/10.1007/3-540-19020-1_13", +} + +@Article{amighi-15, + author = "Afshin Amighi and Christian Haack and Marieke Huisman + and Clément Hurlin", + title = "Permission-based separation logic for multithreaded + {Java} programs", + journal = lmcs, + year = "2015", + volume = "11", + number = "1", + pages = "1--66", + URL = "http://arxiv.org/abs/1411.0851", +} + +@InProceedings{amin-essence-16, + author = "Nada Amin and Samuel Gr{\"{u}}tter and Martin Odersky + and Tiark Rompf and Sandro Stucki", + title = "The Essence of Dependent Object Types", + booktitle = "A List of Successes That Can Change the World -- + Essays Dedicated to {Philip Wadler} on the Occasion of + His 60th Birthday", + series = lncs, + volume = "9600", + publisher = springer, + pages = "249--272", + year = "2016", + URL = "https://infoscience.epfl.ch/record/215280/files/paper_1.pdf", +} + +@InProceedings{amin-rompf-17, + author = "Nada Amin and Tiark Rompf", + title = "Type Soundness Proofs with Definitional Interpreters", + booktitle = popl, + year = "2017", + pages = "666--679", + URL = "http://lampwww.epfl.ch/~amin/pub/big-step.pdf", +} + +@Article{andersen-94, + author = "Henrik Reif Andersen", + title = "Model checking and {Boolean} graphs", + journal = tcs, + volume = "126", + number = "1", + year = "1994", + pages = "3--30", + URL = "http://dx.doi.org/10.1016/0304-3975(94)90266-6", +} + +@Article{anderson-eve-horning-73, + author = "T. Anderson and J. Eve and J. J. Horning", + title = "Efficient ${LR}(1)$ parsers", + journal = acta, + year = "1973", + volume = "2", + pages = "12--39", + URL = "http://dx.doi.org/10.1007/BF00571461", +} + +@Book{andrews-00, + author = "Gregory R. Andrews", + title = "Foundations of Multithreaded, Parallel, and + Distributed Programming", + publisher = aw, + year = "2000", +} + +@Book{andrews-86, + author = "Peter B. Andrews", + title = "An introduction to mathematical logic and type theory: + to truth through proof", + year = "1986", + publisher = ap, +} + +@Article{andrews-reitman-80, + author = "Gregory R. Andrews and Richard P. Reitman", + title = "An Axiomatic Approach to Information Flow in + Programs", + journal = toplas, + volume = "2", + number = "1", + pages = "56--76", + year = "1980", +} + +@Book{antlr, + author = "Terence Parr", + title = "The Definitive {ANTLR 4} Reference, 2nd edition", + year = "2013", + publisher = "Pragmatic Bookshelf", +} + +@InProceedings{antonopoulos-14, + author = "Timos Antonopoulos and Nikos Gorogiannis and Christoph + Haase and Max I. Kanovich and Jo{\"{e}}l Ouaknine", + title = "Foundations for Decision Problems in Separation Logic + with General Inductive Predicates", + booktitle = fossacs, + pages = "411--425", + year = "2014", + series = lncs, + volume = "8412", + publisher = springer, + URL = "http://www.lsv.ens-cachan.fr/Publis/PAPERS/PDF/AGHKO-fossacs14.pdf", +} + +@InProceedings{aponte-dicosmo-96, + author = "Maria-Virginia Aponte and Roberto {Di Cosmo}", + title = "Type isomorphisms for module signatures", + year = "1996", + booktitle = plilp, + publisher = springer, + series = lncs, + volume = "1140", + pages = "334--346", + URL = "http://dx.doi.org/10.1007/3-540-61756-6_95", +} + +@Book{appel-92, + author = "Andrew W. Appel", + title = "Compiling with Continuations", + publisher = cup, + year = "1992", + URL = "http://www.cambridge.org/9780521033114", +} + +@Article{appel-jim-97, + author = "Andrew W. Appel and Trevor Jim", + title = "Shrinking lambda expressions in linear time", + journal = jfp, + volume = "7", + number = "5", + year = "1997", + pages = "515--540", + URL = "http://www.research.att.com/~trevor/papers/shrinking.ps.gz", +} + +@InProceedings{appel-major-07, + author = "Andrew W. Appel and Paul-Andr\'{e} Melli\`{e}s and + Christopher D. Richards and J\'{e}r\^{o}me Vouillon", + title = "A very modal model of a modern, major, general type + system", + booktitle = popl, + year = "2007", + pages = "109--122", + URL = "http://www.cs.princeton.edu/~appel/papers/modalmodel.pdf", +} + +@Book{appel-tiger-98, + author = "Andrew Appel", + title = "Modern Compiler Implementation in {ML}", + publisher = cup, + year = "1998", + URL = "http://www.cs.princeton.edu/~appel/modern/ml/", +} + +@InProceedings{appel-verismall-11, + author = "Andrew W. Appel", + title = "{VeriSmall}: Verified {Smallfoot} Shape Analysis", + booktitle = cpp, + year = "2011", + pages = "231--246", + publisher = springer, + series = lncs, + volume = "7086", + URL = "http://www.cs.princeton.edu/~appel/papers/verismall.pdf", +} + +@InProceedings{appel-vst-11, + author = "Andrew W. Appel", + title = "Verified Software Toolchain", + booktitle = esop, + pages = "1--17", + year = "2011", + series = lncs, + volume = "6602", + publisher = springer, + URL = "https://www.cs.princeton.edu/~appel/papers/vst.pdf", +} + +@Article{apt-81, + author = "Krzysztof R. Apt", + title = "Ten Years of {Hoare's} Logic: {A} Survey---Part {I}", + journal = toplas, + volume = "3", + number = "4", + year = "1981", + pages = "431--483", + URL = "http://doi.acm.org/10.1145/357146.357150", +} + +@Article{ariola-klop-95, + author = "Zena M. Ariola and Jan Willem Klop", + title = "Equational term graph rewriting", + journal = fundamenta, + volume = "26", + number = "3--4", + year = "1996", + pages = "207--240", + URL = "http://www.cwi.nl/ftp/CWIreports/AP/CS-R9552.ps.Z", +} + +@Article{arnold-crubille-88, + author = "Andr{\'e} Arnold and Paul Crubillé", + title = "A Linear Algorithm to Solve Fixed-Point Equations on + Transition Systems", + journal = ipl, + volume = "29", + number = "2", + year = "1988", + pages = "57--66", + URL = "http://dx.doi.org/10.1016/0020-0190(88)90029-4", +} + +@Article{arnold-nivat-80, + author = "André Arnold and Maurice Nivat", + year = "1980", + journal = fundamenta, + volume = "3", + number = "4", + pages = "181--205", + title = "{T}he Metric Space of Infinite Trees. {A}lgebraic And + Topological Properties", +} + +@InProceedings{asai-kameyama-07, + author = "Kenichi Asai and Yukiyoshi Kameyama", + title = "Polymorphic Delimited Continuations", + booktitle = aplas, + pages = "239--254", + year = "2007", + series = lncs, + volume = "4807", + publisher = springer, + URL = "http://logic.cs.tsukuba.ac.jp/~kam/paper/aplas07.pdf", +} + +@Article{aspinall-07, + author = "David Aspinall and Lennart Beringer and Martin Hofmann + and Hans{-}Wolfgang Loidl and Alberto Momigliano", + title = "A program logic for resources", + journal = tcs, + volume = "389", + number = "3", + pages = "411--445", + year = "2007", + URL = "https://www.tcs.ifi.lmu.de/mitarbeiter/martin-hofmann/publikationen-pdfs/j25-ProgramLogisResources.pdf", +} + +@InProceedings{aspinall-hofmann-02, + author = "David Aspinall and Martin Hofmann", + title = "Another Type System for In-Place Update", + booktitle = esop, + pages = "36--52", + year = "2002", + series = lncs, + volume = "2305", + publisher = springer, + URL = "https://www.tcs.ifi.lmu.de/mitarbeiter/martin-hofmann/publikationen-pdfs/c22-anothertypesystem.pdf", +} + +@Article{aspinall-hofmann-konecky-08, + author = "David Aspinall and Martin Hofmann and Michal Kone{\v + c}n{\'{y}}", + title = "A type system with usage aspects", + journal = jfp, + volume = "18", + number = "2", + pages = "141--178", + year = "2008", + URL = "http://dx.doi.org/10.1017/S0956796807006399", +} + +@Misc{astree, + author = "Patrick Cousot and Radhia Cousot and Jérôme Feret + and Antoine Miné and Xavier Rival", + title = "The {Astrée} Static Analyzer", + year = "2011", + note = "\url{http://www.astree.ens.fr/}", + URL = "http://www.astree.ens.fr/", +} + +@Article{atkey-09, + author = "Robert Atkey", + title = "Parameterised Notions of Computation", + journal = jfp, + year = "2009", + volume = "19", + number = "3--4", + pages = "355--376", + URL = "http://homepages.inf.ed.ac.uk/ratkey/paramnotions-jfp.pdf", +} + +@Article{atkey-11, + title = "Amortised Resource Analysis with Separation Logic", + author = "Robert Atkey", + year = "2011", + journal = lmcs, + volume = "7", + number = "2:17", + URL = "http://bentnib.org/amortised-sep-logic-journal.pdf", +} + +@InProceedings{atkey-amortised-10, + author = "Robert Atkey", + title = "Amortised Resource Analysis with Separation Logic", + booktitle = esop, + pages = "85--103", + year = "2010", + volume = "6012", + series = lncs, + publisher = springer, + URL = "http://personal.cis.strath.ac.uk/~raa/amortised-sep-logic.pdf", +} + +@InProceedings{atkey-hoas-09, + author = "Robert Atkey", + title = "Syntax for free: representing syntax with binding + using parametricity", + booktitle = tlca, + pages = "35--49", + year = "2009", + volume = "5608", + series = lncs, + publisher = springer, + URL = "https://personal.cis.strath.ac.uk/~raa/syntaxforfree.pdf", +} + +@InProceedings{atkey-lindley-yallop-09, + author = "Robert Atkey and Sam Lindley and Jeremy Yallop", + title = "Unembedding Domain-Specific languages", + booktitle = hs, + pages = "37--48", + year = "2009", + URL = "http://personal.cis.strath.ac.uk/~raa/unembedding.pdf", +} + +@InProceedings{augustsson-93, + author = "Lennart Augustsson", + title = "Implementing {Haskell} Overloading", + booktitle = fpca, + pages = "65--73", + year = "1993", + URL = "http://dl.acm.org/citation.cfm?id=165191", +} + +@Book{autebert-94, + author = "Jean-Michel Autebert", + title = "Théorie des langages et des automates", + publisher = "Masson", + year = "1994", +} + +@InCollection{autebert-97, + author = "Jean-Michel Autebert and Jean Berstel and Luc + Boasson", + booktitle = "Handbook of Formal Languages", + title = "Context-Free Languages and Push-Down Automata", + publisher = springer, + year = "1997", + volume = "1", + pages = "111--174", + URL = "http://www-igm.univ-mlv.fr/~berstel/Articles/CFLPDA.ps.gz", +} + +@InProceedings{autosubst-15, + author = "Steven Sch{\"{a}}fer and Tobias Tebbi and Gert + Smolka", + title = "{Autosubst}: Reasoning with {de Bruijn} Terms and + Parallel Substitutions", + booktitle = itp, + pages = "359--374", + year = "2015", + series = lncs, + volume = "9236", + publisher = springer, + URL = "https://www.ps.uni-saarland.de/Publications/documents/SchaeferEtAl_2015_Autosubst_-Reasoning.pdf", +} + +@InProceedings{ayache-amadio-regis-gianas-12, + author = "Nicholas Ayache and Roberto M. Amadio and Yann + R{\'{e}}gis{-}Gianas", + title = "Certifying and Reasoning on Cost Annotations in {C} + Programs", + booktitle = "Formal Methods for Industrial Critical Systems", + pages = "32--46", + year = "2012", + series = lncs, + volume = "7437", + publisher = springer, + URL = "https://hal.inria.fr/hal-00702665", +} + +@InProceedings{aycock-horspool-00, + author = "John Aycock and Nigel Horspool", + title = "Simple Generation of Static Single-Assignment Form", + booktitle = cc, + year = "2000", + volume = "1781", + series = lncs, + publisher = springer, + URL = "http://pages.cpsc.ucalgary.ca/~aycock/papers/ssa.ps", +} + +@InProceedings{aydemir-08, + author = "Brian Aydemir and Arthur Chargu{\'e}raud and {Benjamin + C.} Pierce and Randy Pollack and Stephanie Weirich", + booktitle = popl, + title = "Engineering Formal Metatheory", + year = "2008", + pages = "3--15", + URL = "http://www.cis.upenn.edu/~bcpierce/papers/binders.pdf", +} + +@Article{baker-77, + author = "Henry G. Baker", + title = "List Processing in Real Time on a Serial Computer", + journal = cacm, + volume = "21", + number = "4", + year = "1978", + pages = "280--294", + URL = "http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.468.2631&rep=rep1&type=pdf", +} + +@InProceedings{baker-conquer-90, + author = "Henry G. Baker", + title = "Unify and conquer (Garbage, Updating, Aliasing, + \ldots) in Functional Languages", + booktitle = lfp, + year = "1990", + pages = "218--226", + URL = "http://home.pipeline.com/~hbaker1/Share-Unify.ps.gz", +} + +@InProceedings{balabonski-pottier-protzenko-mezzo-14, + author = "Thibaut Balabonski and François Pottier and Jonathan + Protzenko", + title = "Type Soundness and Race Freedom for {Mezzo}", + booktitle = "Proceedings of the 12th International Symposium on + Functional and Logic Programming (FLOPS 2014)", + year = "2014", + series = lncs, + publisher = springer, + volume = "8475", + pages = "253--269", + URL = "http://gallium.inria.fr/~fpottier/publis/bpp-mezzo.pdf", +} + +@Article{balabonski-pottier-protzenko-mezzo-journal-16, + author = "Thibaut Balabonski and François Pottier and Jonathan + Protzenko", + title = "The Design and Formalization of {Mezzo}, a + Permission-Based Programming Language", + journal = toplas, + volume = "38", + number = "4", + pages = "14:1--14:94", + year = "2016", + URL = "http://gallium.inria.fr/~fpottier/publis/bpp-mezzo-journal.pdf", +} + +@InProceedings{balat-dicosmo-fiore-02, + author = "Vincent Balat and Roberto {Di Cosmo} and Marcelo + Fiore", + title = "Remarks on Isomorphisms in Typed Lambda Calculi with + Empty and Sum Type", + booktitle = lics, + year = "2002", + URL = "http://www.cl.cam.ac.uk/~mpf23/papers/Types/remarks.ps.gz", +} + +@InProceedings{banatre-bryce-lemetayer-94, + author = "Jean-Pierre Banâtre and Ciarán Bryce and Daniel {Le + Métayer}", + title = "Compile-time detection of information flow in + sequential programs", + booktitle = esorics, + year = "1994", + publisher = springer, + pages = "55--74", + series = lncs, + volume = "875", + URL = "ftp://ftp.irisa.fr/local/lande/dlm-esorics94.ps.Z", +} + +@InProceedings{banerjee-heintze-riecke-01, + author = "Anindya Banerjee and Nevin Heintze and Jon G. Riecke", + title = "Design and Correctness of Program Transformations + based on Control-flow Analysis", + booktitle = tacs, + pages = "420--447", + year = "2001", + volume = "2215", + series = lncs, + publisher = springer, + URL = "http://www.cis.ksu.edu/~ab/Publications/pcfa.ps.gz", +} + +@InProceedings{banerjee-heintze-riecke-99, + author = "Anindya Banerjee and Nevin Heintze and Jon G. Riecke", + title = "Region Analysis and the Polymorphic Lambda Calculus", + booktitle = lics, + year = "1999", + pages = "88--97", + URL = "http://www.cs.ucla.edu/~palsberg/tba/papers/banerjee-heintze-riecke-lics99.pdf", +} + +@TechReport{banerjee-naumann-01, + author = "Anindya Banerjee and David A. Naumann", + title = "A Simple Semantics and Static Analysis for {Java} + Security", + institution = "Stevens Institute of Technology", + number = "2001-1", + year = "2001", + URL = "http://guinness.cs.stevens-tech.edu/~naumann/publications/tr2001.ps", +} + +@InProceedings{banerjee-naumann-05, + author = "Anindya Banerjee and David A. Naumann", + title = "State based ownership, reentrance, and encapsulation", + booktitle = ecoop, + pages = "387--411", + year = "2005", + volume = "3586", + series = lncs, + publisher = springer, + URL = "https://guinness.cs.stevens-tech.edu/~naumann/publications/ecoop.pdf", +} + +@InProceedings{banerjee-naumann-csfw-02, + author = "Anindya Banerjee and David Naumann", + title = "Secure Information Flow and Pointer Confinement in a + {Java}-like Language", + booktitle = csfw, + pages = "253--267", + year = "2002", + URL = "http://www.cs.stevens-tech.edu/~naumann/publications/csfw15.ps", +} + +@InProceedings{banerjee-naumann-popl-02, + author = "Anindya Banerjee and David A. Naumann", + title = "Representation Independence, Confinement, and Access + Control", + booktitle = popl, + year = "2002", + pages = "166--177", + URL = "http://guinness.cs.stevens-tech.edu/~naumann/publications/BanerjeeNaumann.ps", +} + +@TechReport{barber-dill-96, + author = "Andrew Barber", + title = "Dual Intuitionistic Linear Logic", + institution = "Laboratory for Foundations of Computer Science, School + of Informatics at the University of Edinburgh", + year = "1996", + number = "ECS-LFCS-96-347", + URL = "http://www.lfcs.inf.ed.ac.uk/reports/96/ECS-LFCS-96-347/", +} + +@Book{barendregt, + author = "Henk P. Barendregt", + title = "The Lambda Calculus, Its Syntax and Semantics", + publisher = elsevier, + year = "1984", + URL = "http://www.elsevier.com/wps/find/bookdescription.cws_home/501727/description", +} + +@InCollection{barendregt-90, + author = "Henk P. Barendregt", + title = "Functional Programming and Lambda Calculus", + booktitle = "Handbook of Theoretical Computer Science", + pages = "321--363", + publisher = elsevier, + year = "1990", + editor = "J. Van Leeuwen", +} + +@InProceedings{barendsen-smesters-95, + author = "Erik Barendsen and Sjaak Smetsers", + title = "Uniqueness Type Inference", + booktitle = plilp, + year = "1995", + pages = "189--206", + publisher = springer, + series = lncs, + volume = "982", + URL = "http://dx.doi.org/10.1007/BFb0026821", +} + +@InProceedings{barnett-pure-04, + author = "Mike Barnett and David A. Naumann and Wolfram Schulte + and Qi Sun", + title = "99.44\% pure: Useful Abstractions in Specifications", + booktitle = ftfjp, + year = "2004", + URL = "http://www.cs.ru.nl/ftfjp/2004/Purity.pdf", +} + +@InProceedings{barnett-spec-04, + author = "Mike Barnett and K. Rustan M. Leino and Wolfram + Schulte", + title = "The {Spec\#} programming system: An overview", + booktitle = cassis, + year = "2004", + volume = "3362", + pages = "49--69", + series = lncs, + publisher = springer, + URL = "http://research.microsoft.com/~leino/papers/krml136.pdf", +} + +@Article{barrett-00, + author = "Chris Barrett and Riko Jacob and Madhav Marathe", + title = "Formal Language Constrained Path Problems", + journal = siamjc, + year = "2000", + volume = "30", + number = "3", + pages = "809--837", + URL = "http://www.brics.dk/~rjacob/Publications/regpath.ps.gz", + alturl = "http://epubs.siam.org/sam-bin/getfile/SICOMP/articles/33771.pdf", +} + +@TechReport{bartels-96, + author = "Frank Bartels and Friedrich von Henke and Holger + Pfeifer and Harald Rue{\ss}", + title = "Mechanizing Domain Theory", + institution = "Universit{\"a}t Ulm, Fakult{\"a}t f{\"u}r Informatik", + year = "1996", + number = "96-10", + type = "Ulmer Informatik-Berichte", + URL = "http://www.csl.sri.com/users/ruess/papers/Fixpoints/fixpoints-domains3.ps.gz", +} + +@InProceedings{barthe-06, + author = "Gilles Barthe and Julien Forest and David Pichardie + and Vlad Rusu", + title = "Defining and Reasoning About Recursive Functions: A + Practical Tool for the {Coq} Proof Assistant", + booktitle = flops, + pages = "114--129", + year = "2006", + series = lncs, + volume = "3945", + publisher = springer, + URL = "http://people.irisa.fr/David.Pichardie/papers/flops06.pdf", +} + +@InProceedings{barthwal-norrish-09, + author = "Aditi Barthwal and Michael Norrish", + title = "Verified, Executable Parsing", + booktitle = esop, + year = "2009", + pages = "160--174", + series = lncs, + publisher = springer, + volume = "5502", + URL = "http://users.cecs.anu.edu.au/~aditi/esop09_submission_16.pdf", +} + +@InProceedings{bartoletti-al-01, + author = "Massimo Bartoletti and Pierpaolo Degano and GianLuigi + Ferrari", + title = "Static Analysis for Stack Inspection", + booktitle = "International Workshop on Concurrency and + Coordination", + series = entcs, + volume = "54", + publisher = elsevier, + year = "2001", +} + +@Article{bauer-pretnar-13, + author = "Andrej Bauer and Matija Pretnar", + title = "An Effect System for Algebraic Effects and Handlers", + journal = lmcs, + volume = "10", + number = "4", + year = "2014", + URL = "https://arxiv.org/pdf/1306.6316.pdf", +} + +@Article{beaven-stansifer-93, + author = "Mike Beaven and Ryan Stansifer", + title = "Explaining type errors in polymorphic languages", + journal = "ACM Letters on Programming Languages and Systems", + volume = "2", + number = "4", + pages = "17--30", + year = "1993", + URL = "http://www.cs.fit.edu/~ryan/papers/explain.ps.gz", +} + +@InProceedings{belanger-monnier-pientka-13, + author = "Olivier {Savary Belanger} and Stefan Monnier and + Brigitte Pientka", + title = "Programming Type-Safe Transformations Using + Higher-Order Abstract Syntax", + booktitle = cpp, + pages = "243--258", + year = "2013", + series = lncs, + volume = "8307", + publisher = springer, + URL = "https://link.springer.com/chapter/10.1007/978-3-319-03545-1_16", +} + +@Article{belanger-monnier-pientka-15, + author = "Olivier {Savary Belanger} and Stefan Monnier and + Brigitte Pientka", + title = "Programming Type-Safe Transformations Using + Higher-Order Abstract Syntax", + journal = jfr, + year = "2015", + volume = "8", + number = "1", + URL = "https://jfr.unibo.it/article/view/5122/5330", +} + +@InProceedings{bell-08, + author = "C. J. Bell and Robert Dockins and Aquinas Hobor and + Andrew W. Appel and David Walker", + title = "Comparing Semantic and Syntactic Methods in Mechanized + Proof Frameworks", + booktitle = pcc, + year = "2008", + URL = "http://www.cs.princeton.edu/~rdockins/pubs/semsyn.pdf", +} + +@InProceedings{bell-bellegarde-hook-97, + author = "Jeffrey M. Bell and Françoise Bellegarde and James + Hook", + title = "Type-driven Defunctionalization", + booktitle = icfp, + year = "1997", + URL = "http://doi.acm.org/10.1145/258949.258953", +} + +@TechReport{bell-lapadula-75, + author = "D. E. Bell and Leonard J. LaPadula", + title = "Secure Computer Systems: Unified Exposition and + {Multics} Interpretation", + year = "1975", + number = "MTR-2997", + institution = "The {MITRE} Corp.", + URL = "http://niatec.info/pdf/bell76.pdf", +} + +@InProceedings{bengtson-12, + author = "Jesper Bengtson and Jonas Braband Jensen and Lars + Birkedal", + title = "Charge! {A} Framework for Higher-Order Separation + Logic in {Coq}", + booktitle = itp, + pages = "315--331", + year = "2012", + URL = "http://cs.au.dk/~birke/papers/charge-conf.pdf", +} + +@InProceedings{berdine-calcagno-ohearn-05, + author = "Josh Berdine and Cristiano Calcagno and Peter W. + O'Hearn", + title = "Symbolic Execution with Separation Logic", + booktitle = aplas, + year = "2005", + publisher = springer, + series = lncs, + volume = "3780", + pages = "52--68", + URL = "http://www.dcs.qmul.ac.uk/~berdine/papers/execution.pdf", +} + +@InProceedings{berdine-decidable-fragment-04, + author = "Josh Berdine and Cristiano Calcagno and Peter W. + O'Hearn", + title = "A Decidable Fragment of Separation Logic", + booktitle = fsttcs, + year = "2004", + pages = "97--109", + publisher = springer, + series = lncs, + volume = "3328", + URL = "http://www.cs.ucl.ac.uk/staff/p.ohearn/papers/unroll_collapse.pdf", +} + +@Article{berdine-linear-continuations-02, + author = "Josh Berdine and Peter W. O'Hearn and Uday S. Reddy + and Hayo Thielecke", + title = "Linear Continuation-Passing", + journal = hosc, + year = "2002", + volume = "15", + number = "2--3", + pages = "181--208", + URL = "http://www.cs.bham.ac.uk/~hxt/research/LinCP.pdf", +} + +@InProceedings{berdine-ohearn-06, + author = "Josh Berdine and Peter W. O'Hearn", + title = "Strong Update, Disposal, and Encapsulation in Bunched + Typing", + booktitle = mfps, + series = entcs, + publisher = elsevier, + volume = "158", + year = "2006", + pages = "81--98", + URL = "http://research.microsoft.com/pubs/73584/bil.pdf", +} + +@InProceedings{berger-honda-yoshida-05, + author = "Martin Berger and Kohei Honda and Nobuko Yoshida", + title = "A logical analysis of aliasing in imperative + higher-order functions", + booktitle = icfp, + year = "2005", + pages = "280--293", + URL = "http://doi.acm.org/10.1145/1086365.1086401", +} + +@InProceedings{bergeron-al-00, + author = "M. Debbabi and E. Giasson and B. Ktari and F. Michaud + and N. Tawbi", + title = "Secure Self-Certified {COTS}", + booktitle = "IEEE International Workshop on Enterprise Security + (WETICE'00)", + year = "2000", + URL = "http://www.ift.ulaval.ca/~lsfm/lsfm_eng/Publications/wetice2000_2.pdf", +} + +@Unpublished{bernstein-stark-95, + author = "K. Bernstein and E. W. Stark", + title = "Debugging Type Errors", + year = "1995", + URL = "http://bsd7.starkhome.cs.sunysb.edu/~stark/REPORTS/debugtype.ps.gz", + note = "Unpublished", +} + +@InProceedings{berthomieu-sagazan-95, + author = "Bernard Berthomieu and Camille {le Moniès de + Sagazan}", + title = "A Calculus of Tagged Types, with applications to + process languages", + booktitle = "Workshop on Types for Program Analysis", + pages = "1--15", + year = "1995", + URL = "http://www.laas.fr/~bernard/lcs/papers/tpa95.ps.gz", +} + +@Article{besson-al-01, + author = "Frédéric Besson and Thomas P. Jensen and Daniel {Le + Métayer} and Tommy Thorn", + title = "Model Checking Security Properties of Control Flow + Graphs", + journal = "Journal of Computer Security", + volume = "9", + number = "3", + year = "2001", + pages = "217--250", + URL = "http://www.irisa.fr/lande/jensen/jcs.pdf", +} + +@InProceedings{besson-al-02, + author = "Frédéric Besson and Thomas {de Grenier de Latour} + and Thomas Jensen", + title = "Secure Calling Contexts for Stack Inspection", + pages = "76--87", + booktitle = ppdp, + year = "2002", + URL = "http://www.irisa.fr/lande/jensen/ppdp02.pdf", +} + +@Article{bhamidipaty-proebsting-98, + author = "Achyutram Bhamidipaty and Todd A. Proebsting", + title = "Very Fast {YACC}-Compatible Parsers (For Very Little + Effort)", + journal = spe, + year = "1998", + volume = "28", + number = "2", + pages = "181--190", + URL = "http://www.cs.arizona.edu/people/todd/papers/TR95-09.ps", +} + +@InProceedings{bhargavan-fournet-gordon-10, + author = "Karthik Bhargavan and Cédric Fournet and Andy + Gordon", + title = "Modular Verification of Security Protocol Code by + Typing", + booktitle = popl, + pages = "445--456", + year = "2010", + URL = "http://moscova.inria.fr/~karthik/pubs/modular-verification-of-security-protocols-by-typing-popl10.pdf", +} + +@InProceedings{bhat-cleaveland-96, + author = "Girish Bhat and Rance Cleaveland", + title = "Efficient Local Model-Checking for Fragments of the + Modal $\mu$-Calculus", + booktitle = tacas, + pages = "107--126", + year = "1996", + volume = "1055", + series = lncs, + publisher = springer, + URL = "http://www.cs.umd.edu/~rance/publications/papers/tacas96a.ps.gz", +} + +@InProceedings{biere-bmc-99, + author = "Armin Biere and Alessandro Cimatti and Edmund Clarke + and Yunshan Zhu", + title = "Symbolic Model Checking Without {BDDs}", + booktitle = tacas, + pages = "193--207", + year = "1999", + volume = "1579", + series = lncs, + publisher = springer, + URL = "http://www.inf.ethz.ch/personal/biere/papers/BiereCimattiClarkeZhu-TACAS99.pdf", +} + +@InProceedings{bierhoff-aldrich-07, + author = "Kevin Bierhoff and Jonathan Aldrich", + title = "Modular typestate checking of aliased objects", + booktitle = oopsla, + year = "2007", + pages = "301--320", + URL = "http://www.cs.cmu.edu/~kbierhof/papers/typestate-verification.pdf", +} + +@InProceedings{bierhoff-beckman-aldrich-09, + author = "Kevin Bierhoff and Nels E. Beckman and Jonathan + Aldrich", + title = "Practical {API} Protocol Checking with Access + Permissions", + booktitle = ecoop, + year = "2009", + pages = "195--219", + publisher = springer, + series = lncs, + volume = "5653", + URL = "http://www.cs.cmu.edu/~kbierhof/papers/permission-practice.pdf", +} + +@InProceedings{biering-05, + author = "Bodil Biering and Lars Birkedal and Noah Torp-Smith", + title = "{BI} Hyperdoctrines and Higher-Order Separation + Logic", + booktitle = esop, + year = "2005", + pages = "233--247", + publisher = springer, + series = lncs, + volume = "3444", + URL = "http://www.itu.dk/people/noah/papers/hyperdocs.pdf", +} + +@Article{bird-hughes-87, + author = "Richard S. Bird and John Hughes", + title = "The alpha-beta Algorithm: An Exercise in Program + Transformation", + journal = ipl, + volume = "24", + number = "1", + year = "1987", + pages = "53--57", + URL = "http://dx.doi.org/10.1016/0020-0190(87)90198-0", +} + +@InProceedings{bird-meertens-98, + author = "Richard Bird and Lambert Meertens", + title = "Nested Datatypes", + booktitle = mpc, + pages = "52--67", + year = "1998", + volume = "1422", + series = lncs, + publisher = springer, + URL = "http://www.cs.ox.ac.uk/richard.bird/online/BirdMeertens98Nested.pdf", +} + +@Article{bird-paterson-99, + title = "{de Bruijn} Notation as a Nested Datatype", + author = "Richard Bird and Ross Paterson", + URL = "http://dx.doi.org/10.1017/S0956796899003366", + journal = jfp, + volume = "9", + number = "1", + pages = "77--91", + year = "1999", +} + +@TechReport{birkedal-alii-93, + author = "Lars Birkedal and Nick Rothwell and Mads Tofte and + David N. Turner", + semno = "D-181", + title = "The {ML} Kit (Version 1)", + institution = "Department of Computer Science, University of + Copenhagen", + year = "1993", + number = "DIKU 93/14", + URL = "http://www.it-c.dk/research/mlkit/", +} + +@Article{birkedal-hoframe-06, + author = "Lars Birkedal and Noah Torp-Smith and Hongseok Yang", + title = "Semantics of separation-logic typing and higher-order + frame rules for {Algol}-like languages", + journal = lmcs, + year = "2006", + volume = "2", + number = "5", + URL = "http://arxiv.org/pdf/cs.LO/0610081", +} + +@Unpublished{birkedal-nakano-10, + author = "Lars Birkedal and Jan Schwinghammer and Kristian + Støvring", + title = "A Metric Model of Lambda Calculus with Guarded + Recursion", + note = "Presented at FICS 2010", + year = "2010", + URL = "http://www.itu.dk/~birkedal/papers/nakano-conf.pdf", +} + +@InProceedings{birkedal-popl-11, + author = "Lars Birkedal and Bernhard Reus and Jan Schwinghammer + and Kristian Støvring and Jacob Thamsborg and Hongseok + Yang", + title = "Step-indexed {Kripke} models over recursive worlds", + booktitle = popl, + pages = "119--132", + year = "2011", + URL = "http://www.eecs.qmul.ac.uk/~hyang/paper/popl11-long.pdf", +} + +@InProceedings{birkedal-stovring-thamsborg-09, + author = "Lars Birkedal and Kristian St{\o}vring and Jacob + Thamsborg", + title = "Realizability Semantics of Parametric Polymorphism, + General References, and Recursive Types", + booktitle = fossacs, + pages = "456--470", + year = "2009", + volume = "5504", + series = lncs, + publisher = springer, + URL = "http://www.itu.dk/~birkedal/papers/parametricity-state-metric-conf.pdf", +} + +@Article{birkedal-stovring-thamsborg-10, + author = "Lars Birkedal and Kristian St{\o}vring and Jacob + Thamsborg", + title = "Realisability Semantics of Parametric Polymorphism, + General References, and Recursive Types", + journal = mscs, + year = "2010", + volume = "20", + number = "4", + pages = "655--703", + URL = "http://www.itu.dk/~birkedal/papers/parametricity-state-metric-journal.pdf", +} + +@TechReport{birkedal-stovring-thamsborg-solution-09, + author = "Lars Birkedal and Kristian St{\o}vring and Jacob + Thamsborg", + title = "The category-theoretic solution of recursive + metric-space quations", + institution = "IT University of Copenhagen", + year = "2009", + number = "ITU-2009-119", + URL = "http://www.itu.dk/~birkedal/papers/ITU-TR-2009-119.pdf", +} + +@Article{birkedal-tofte-01, + author = "Lars Birkedal and Mads Tofte", + title = "A constraint-based region inference algorithm", + journal = tcs, + year = "2001", + volume = "258", + pages = "299--392", + URL = "http://www.itu.dk/people/birkedal/papers/conria.ps.gz", +} + +@Unpublished{birrell-03, + author = "Andrew D. Birrell", + title = "An Introduction to Programming with {C\#} Threads", + note = "Manuscript", + year = "2003", + URL = "http://birrell.org/andrew/papers/ThreadsCSharp.pdf", +} + +@Manual{bison, + title = "Bison", + author = "Charles Donnelly and Richard Stallman", + year = "2015", + URL = "http://www.gnu.org/software/bison/manual/", +} + +@PhdThesis{biswas-97, + school = "University of Pennsylvania", + title = "Dynamic Slicing in Higher-Order Programming + Languages", + year = "1997", + pages = "151", + author = "Sandip K. Biswas", +} + +@InProceedings{blelloch-greiner-95, + author = "Guy E. Blelloch and John Greiner", + title = "Parallelism in Sequential Functional Languages", + booktitle = fpca, + pages = "226--237", + year = "1995", + URL = "http://www.cs.cmu.edu/afs/cs.cmu.edu/project/scandal/public/papers/fpca-pal.ps.gz", +} + +@Article{bobot-why3-15, + author = "Fran{\c{c}}ois Bobot and Jean-Christophe + Filli{\^{a}}tre and Claude March{\'{e}} and Andrei + Paskevich", + title = "Let's verify this with {Why3}", + journal = sttt, + volume = "17", + number = "6", + pages = "709--727", + year = "2015", + URL = "https://hal.inria.fr/hal-00967132/", +} + +@InProceedings{bocchino-09, + author = "Robert L. {Bocchino Jr.} and Vikram S. Adve and Sarita + V. Adve and Marc Snir", + title = "Parallel Programming Must Be Deterministic by + Default", + booktitle = hotpar, + year = "2009", + pages = "1--6", + URL = "http://dpj.cs.illinois.edu/DPJ/Publications_files/DPJ-HotPar-2009.pdf", +} + +@InCollection{bocchino-13, + author = "Robert L. {Bocchino Jr.}", + title = "Alias Control for Deterministic Parallelism", + editor = "Dave Clarke and James Noble and Tobias Wrigstad", + booktitle = "Aliasing in Object-Oriented Programming. Types, + Analysis and Verification", + pages = "156--195", + year = "2013", + URL = "http://dx.doi.org/10.1007/978-3-642-36946-9_7", + series = lncs, + volume = "7850", + publisher = springer, +} + +@InProceedings{bocchino-adve-11, + author = "Robert L. {Bocchino Jr.} and Vikram S. Adve", + title = "Types, Regions, and Effects for Safe Programming with + Object-Oriented Parallel Frameworks", + booktitle = ecoop, + pages = "306--332", + year = "2011", + series = lncs, + volume = "6813", + publisher = springer, + URL = "http://rob-bocchino.net/Professional/Publications_files/DPJ-ECOOP-2011-Frameworks.pdf", +} + +@InProceedings{bocchino-dpj-09, + author = "Robert L. {Bocchino Jr.} and Vikram S. Adve and Danny + Dig and Sarita V. Adve and Stephen Heumann and Rakesh + Komuravelli and Jeffrey Overbey and Patrick Simmons and + Hyojin Sung and Mohsen Vakilian", + title = "A type and effect system for deterministic parallel + {Java}", + booktitle = oopsla, + pages = "97--116", + year = "2009", + URL = "http://rob-bocchino.net/Professional/Publications_files/Bocchino-OOPSLA-2009.pdf", +} + +@InProceedings{bocchino-safe-11, + author = "Robert L. {Bocchino Jr.} and Stephen Heumann and Nima + Honarmand and Sarita V. Adve and Vikram S. Adve and + Adam Welc and Tatiana Shpeisman", + title = "Safe nondeterminism in a deterministic-by-default + parallel language", + booktitle = popl, + pages = "535--548", + year = "2011", + URL = "http://rob-bocchino.net/Professional/Publications_files/Bocchino-POPL-2011.pdf", +} + +@InProceedings{bodei-al-99, + author = "Chiara Bodei and Pierpaolo Degano and Flemming Nielson + and Hanne Riis Nielson", + title = "Static Analysis of Processes for No Read-Up and No + Write-Down", + booktitle = fossacs, + year = "1999", + volume = "1578", + series = lncs, + publisher = springer, + pages = "120--134", + URL = "http://www.di.unipi.it/~chiara/publ-40/BDNN99.ps", +} + +@Article{boehm-adve-12, + author = "Hans-J. Boehm and Sarita V. Adve", + title = "You don't know jack about shared variables or memory + models", + journal = cacm, + volume = "55", + number = "2", + year = "2012", + pages = "48--54", + URL = "http://doi.acm.org/10.1145/2076450.2076465", +} + +@InProceedings{bonniot-02, + author = "Daniel Bonniot", + title = "Type-checking multi-methods in {ML} (a modular + approach)", + booktitle = fool, + year = "2002", + URL = "http://gallium.inria.fr/~bonniot/bonniot02.ps", +} + +@PhdThesis{boquist-99, + author = "Urban Boquist", + title = "Code Optimisation Techniques for Lazy Functional + Languages", + school = "Chalmers University of Technology", + year = "1999", + URL = "http://www.cs.uu.nl/docs/vakken/macc/boquist.pdf", +} + +@Article{boreale-sangiorgi-98, + author = "Michele Boreale and Davide Sangiorgi", + title = "A fully abstract semantics for causality in the + $\pi$-calculus", + journal = acta, + volume = "35", + number = "5", + pages = "353--400", + year = "1998", + URL = "http://link.springer.de/link/service/journals/00236/papers/8035005/80350353.pdf", +} + +@InProceedings{borgstrom-chen-swamy-11, + author = "Johannes Borgström and Juan Chen and and Nikhil + Swamy", + title = "Verified Stateful Programs with Substructural State + and {Hoare} Types", + booktitle = plpv, + year = "2011", + URL = "http://research.microsoft.com/pubs/135430/plpv11k-borgstrom.pdf", +} + +@InProceedings{bornat-00, + author = "Richard Bornat", + title = "Proving Pointer Programs in {Hoare} Logic", + booktitle = mpc, + year = "2000", + pages = "102--126", + publisher = springer, + series = lncs, + volume = "1837", + URL = "http://www.cs.mdx.ac.uk/staffpages/r_bornat/papers/MPC2000.pdf", +} + +@InProceedings{bornat-permission-accounting-05, + author = "Richard Bornat and Cristiano Calcagno and Peter + O'Hearn and Matthew Parkinson", + title = "Permission accounting in separation logic", + booktitle = popl, + year = "2005", + pages = "259--270", + URL = "http://www.cs.ucl.ac.uk/staff/p.ohearn/papers/permissions_paper.pdf", +} + +@InProceedings{bouajjani-esparza-maler-97, + author = "Ahmed Bouajjani and Javier Esparza and Oded Maler", + title = "Reachability Analysis of Pushdown Automata: + Application to Model-Checking", + booktitle = concur, + pages = "135--150", + year = "1997", + URL = "http://www-verimag.imag.fr/~maler/Papers/pda.pdf", + series = lncs, + volume = "1243", + publisher = springer, +} + +@Unpublished{boudol-castellani-01, + author = "Gérard Boudol and Ilaria Castellani", + title = "Non-interference for concurrent programs and thread + systems", + year = "2001", + note = "To appear", + URL = "ftp://ftp-sop.inria.fr/mimosa/personnel/gbo/non-interf-threads.ps.gz", +} + +@Article{boudol-stratified-regions, + author = "Gérard Boudol", + title = "Typing termination in a higher-order concurrent + imperative language", + journal = ic, + year = "2009", + note = "To appear", + URL = "ftp://ftp-sop.inria.fr/mimosa/personnel/gbo/ttiahocil.pdf", +} + +@InProceedings{boulme-07, + author = "Sylvain Boulmé", + title = "Intuitionistic Refinement Calculus", + booktitle = tlca, + year = "2007", + pages = "54--69", + volume = "4583", + series = lncs, + publisher = springer, + URL = "http://www-lsr.imag.fr/users/Sylvain.Boulme/horefinement/dsm.pdf", +} + +@Misc{bound, + author = "Edward Kmett", + title = "Bound", + howpublished = "Blog post", + year = "2014", + URL = "https://www.fpcomplete.com/user/edwardk/bound", +} + +@TechReport{bourdoncle-merz-96, + author = "François Bourdoncle and Stephan Merz", + title = "On the integration of functional programming, + class-based object-oriented programming, and + multi-methods", + institution = "Centre de Mathématiques Appliquées, Ecole des Mines + de Paris", + year = "1996", + type = "Research Report", + number = "26", + URL = "http://www.loria.fr/~merz/papers/mlsub.html", +} + +@InProceedings{bourdoncle-merz-97, + author = "François Bourdoncle and Stephan Merz", + title = "Type Checking Higher-Order Polymorphic Multi-Methods", + booktitle = popl, + year = "1997", + pages = "302--315", + URL = "http://www.exalead.com/Francois.Bourdoncle/popl97.html", +} + +@InProceedings{boyapati-lee-rinard-02, + author = "Chandrasekhar Boyapati and Robert Lee and Martin + Rinard", + title = "Ownership types for safe programming: preventing data + races and deadlocks", + booktitle = oopsla, + year = "2002", + pages = "211--230", + URL = "http://doi.acm.org/10.1145/582419.582440", +} + +@InProceedings{boyapati-liskov-shrira-03, + author = "Chandrasekhar Boyapati and Barbara Liskov and Liuba + Shrira", + title = "Ownership types for object encapsulation", + booktitle = popl, + year = "2003", + pages = "213--223", + URL = "http://www.pmg.lcs.mit.edu/~chandra/publications/popl03.pdf", +} + +@Article{boyland-burying-01, + author = "John Boyland", + title = "Alias burying: Unique variables without destructive + reads", + journal = scp, + year = "2001", + volume = "31", + number = "6", + pages = "533--553", + URL = "http://www.cs.uwm.edu/faculty/boyland/papers/unique-preprint.ps", +} + +@InProceedings{boyland-fractions-03, + author = "John Boyland", + title = "Checking Interference with Fractional Permissions", + booktitle = sas, + year = "2003", + series = lncs, + publisher = springer, + volume = "2694", + pages = "55--72", + URL = "http://www.cs.uwm.edu/~boyland/papers/permissions.pdf", +} + +@Article{boyland-nesting-10, + author = "John Tang Boyland", + title = "Semantics of fractional permissions with nesting", + journal = toplas, + volume = "32", + number = "6", + pages = "22:1--22:33", + year = "2010", + URL = "http://dx.doi.org/10.1145/1749608.1749611", +} + +@InProceedings{boyland-noble-retert-01, + author = "John Boyland and James Noble and William Retert", + title = "Capabilities for Sharing: {A} Generalisation of + Uniqueness and Read-Only", + booktitle = ecoop, + pages = "2--27", + year = "2001", + series = lncs, + volume = "2072", + publisher = springer, + URL = "http://www.cs.uwm.edu/~boyland/papers/capability.ps", +} + +@InProceedings{boyland-retert-05, + author = "John Tang Boyland and William Retert", + title = "Connecting Effects and Uniqueness with Adoption", + booktitle = popl, + year = "2005", + pages = "283--295", + URL = "http://www.cs.uwm.edu/~boyland/papers/connecting2.pdf", +} + +@InProceedings{bracha-cook-90, + author = "Gilad Bracha and William Cook", + title = "Mixin-based inheritance", + booktitle = oopsla, + pages = "303--311", + year = "1990", + URL = "http://www.bracha.org/oopsla90.ps", +} + +@TechReport{bracha-lindstrom-91, + author = "Gilad Bracha and Gary Lindstrom", + title = "Modularity Meets Inheritance", + institution = "University of Utah", + year = "1991", + number = "UUCS-91-017", + URL = "http://www.bracha.org/modularity-meets-inheritance.ps", +} + +@Book{bradley-manna-07, + author = "Aaron R. Bradley and Zohar Manna", + title = "The Calculus of Computation", + publisher = springer, + year = "2007", + URL = "http://www.springerlink.com/content/wv0127/?p=77473ec707e949ae8856c880fe4e7649&pi=0", +} + +@InProceedings{braibant-pous-11, + author = "Thomas Braibant and Damien Pous", + title = "Tactics for Reasoning Modulo {AC} in {Coq}", + booktitle = cpp, + year = "2011", + pages = "167--182", + publisher = springer, + series = lncs, + volume = "7086", + URL = "http://arxiv.org/abs/1106.4448", +} + +@Article{brandis-mossenbock-94, + author = "Marc M. Brandis and Hanspeter Mössenböck", + title = "Single-pass generation of static single-assignment + form for structured languages", + journal = toplas, + volume = "16", + number = "6", + year = "1994", + pages = "1684--1698", + URL = "ftp://ftp.ssw.uni-linz.ac.at/pub/Papers/Moe94.ps.gz", +} + +@Article{brandt-henglein-98, + author = "Michael Brandt and Fritz Henglein", + year = "1998", + title = "Coinductive axiomatization of recursive type equality + and subtyping", + journal = fundamenta, + pages = "309--338", + volume = "33", + URL = "ftp://ftp.diku.dk/diku/semantics/papers/D-353.ps.gz", +} + +@Article{breazu-tannen-91, + author = "Val Breazu-Tannen and Thierry Coquand and Carl A. + Gunter and Andre Scedrov", + title = "Inheritance as Implicit Coercion", + journal = ic, + year = "1991", + volume = "93", + number = "1", + pages = "172--221", + URL = "http://seclab.uiuc.edu/cgunter/publications/documents/Breazu-TannenCGS91.pdf", +} + +@InProceedings{brookes-04, + author = "Stephen D. Brookes", + title = "A Semantics for Concurrent Separation Logic", + booktitle = concur, + year = "2004", + pages = "16--34", + publisher = springer, + series = lncs, + volume = "3170", + URL = "http://dx.doi.org/10.1007/978-3-540-28644-8_2", +} + +@Article{brookes-ohearn-16, + author = "Stephen Brookes and Peter W. O'Hearn", + title = "Concurrent separation logic", + journal = "{SIGLOG} News", + volume = "3", + number = "3", + pages = "47--65", + year = "2016", + URL = "http://siglog.hosting.acm.org/wp-content/uploads/2016/07/siglog_news_9.pdf#page=49", +} + +@InProceedings{brotherston-cyclic-11, + author = "James Brotherston and Dino Distefano and Rasmus + Lerchedahl Petersen", + title = "Automated Cyclic Entailment Proofs in Separation + Logic", + booktitle = cade, + year = "2011", + pages = "131--146", + publisher = springer, + series = lncs, + volume = "6803", + URL = "http://www.eecs.qmul.ac.uk/~rusmus/articles/Cyclic.pdf", +} + +@TechReport{bruce-alii-binary-methods, + key = "Bruce, {\em et al.}", + author = "Kim Bruce and Luca Cardelli and Giuseppe Castagna and + The Hopkins Object Group and Gary T. Leavens and + Benjamin Pierce", + title = "On Binary Methods", + year = "1995", + institution = "Department of Computer Science, Iowa State + University", + number = "95-08a", + URL = "ftp://ftp.cs.iastate.edu/pub/techreports/TR95-08/TR.ps.Z", +} + +@Article{bruce-cardelli-pierce-99, + author = "Kim B. Bruce and Luca Cardelli and Benjamin C. + Pierce", + title = "Comparing Object Encodings", + journal = ic, + year = "1999", + volume = "155", + number = "1/2", + pages = "108--133", + URL = "http://www.cis.upenn.edu/~bcpierce/papers/compobj.ps", +} + +@Article{bruce-dicosmo-longo-92, + author = "Kim Bruce and Roberto {Di Cosmo} and Giuseppe Longo", + title = "Provable isomorphisms of types", + journal = mscs, + year = "1992", + volume = "2", + number = "2", + pages = "231--247", + URL = "http://www.dicosmo.org/Articles/MSCS.dvi", +} + +@Article{buchlovsky-thielecke-06, + author = "Peter Buchlovsky and Hayo Thielecke", + title = "A type-theoretic reconstruction of the Visitor + pattern", + journal = entcs, + volume = "155", + pages = "309--329", + year = "2006", + URL = "http://www.cs.bham.ac.uk/~hxt/research/mfps-visitors.pdf", +} + +@Unpublished{bugliesi-affine-15, + author = "Michele Bugliesi and Stefano Calzavara and Fabienne + Eigner and Matteo Maffei", + title = "Affine Refinement Types for Secure Distributed + Programming", + note = "To appear", + year = "2015", + URL = "http://www.sps.cs.uni-saarland.de/affine-rcf/resources/long.pdf", +} + +@InProceedings{bugliesi-crafa-dynamic-99, + author = "Michele Bugliesi and Silvia Crafa", + title = "Object Calculi for Dynamic Messages", + booktitle = fool, + year = "1999", +} + +@Article{bugliesi-pericas-02, + author = "Michele Bugliesi and Santiago M. + Peric{\'a}s-Geertsen", + title = "Type Inference for Variant Object Types", + journal = ic, + year = "2002", + volume = "177", + number = "1", + pages = "2--27", + URL = "http://www.dsi.unive.it/~michele/Papers/PS/SplitTypes-ic02.ps.gz", +} + +@Article{buisse-11, + author = "Alexandre Buisse and Lars Birkedal and Kristian + St{\o}vring", + title = "A Step-Indexed {Kripke} Model of Separation Logic for + Storable Locks", + journal = entcs, + volume = "276", + year = "2011", + pages = "121--143", + URL = "http://www.itu.dk/~birkedal/papers/locks.pdf", +} + +@InProceedings{bulwahn-08, + author = "Lukas Bulwahn and Alexander Krauss and Florian + Haftmann and Levent Erk{\"{o}}k and John Matthews", + title = "Imperative Functional Programming with + {Isabelle/HOL}", + booktitle = tphol, + pages = "134--149", + year = "2008", + series = lncs, + volume = "5170", + publisher = springer, + URL = "http://www21.in.tum.de/~krauss/imperative/imperative.pdf", +} + +@Article{buneman-ohori-96, + author = "Peter Buneman and Atsushi Ohori", + title = "Polymorphism and Type Inference in Database + Programming", + journal = tods, + year = "1996", + volume = "21", + number = "1", + pages = "30--76", + URL = "http://www.jaist.ac.jp/~ohori/research/tods96.pdf", +} + +@InProceedings{burstall-hope-80, + author = "R. M. Burstall and D. B. MacQueen and D. T. Sannella", + title = "{HOPE}: An experimental applicative language", + booktitle = lfp, + year = "1980", + pages = "136--143", + URL = "http://portal.acm.org/citation.cfm?id=802799", +} + +@Article{cai-paige-89, + author = "Jiazhen Cai and Robert Paige", + title = "Program derivation by fixed point computation", + journal = scp, + volume = "11", + number = "3", + year = "1989", + pages = "197--261", + URL = "http://cs.nyu.edu/paige/papers/fixpoint.ps", +} + +@InProceedings{caires-seco-13, + author = "Lu\'{\i}s Caires and Jo{\~a}o Costa Seco", + title = "The type discipline of behavioral separation", + booktitle = popl, + year = "2013", + pages = "275--286", + URL = "http://dx.doi.org/10.1145/2429069.2429103", +} + +@InProceedings{cakeml-new-16, + author = "Yong Kiam Tan and Magnus O. Myreen and Ramana Kumar + and Anthony C. J. Fox and Scott Owens and Michael + Norrish", + title = "A new verified compiler backend for {CakeML}", + booktitle = icfp, + pages = "60--73", + year = "2016", + URL = "https://cakeml.org/icfp16.pdf", +} + +@Article{calcagno-02, + author = "Cristiano Calcagno and Simon Helsen and Peter + Thiemann", + title = "Syntactic Type Soundness Results for the Region + Calculus", + journal = ic, + year = "2002", + volume = "173", + number = "2", + pages = "199--221", + URL = "http://www.dcs.qmw.ac.uk/~ccris/ftp/iac_calhelthi.pdf", +} + +@InProceedings{calcagno-11, + author = "Cristiano Calcagno and Dino Distefano", + title = "Infer: An Automatic Program Verifier for Memory Safety + of {C} Programs", + booktitle = nfm, + pages = "459--465", + year = "2011", + series = lncs, + volume = "6617", + publisher = springer, + URL = "http://www.eecs.qmul.ac.uk/~ddino/papers/nasa-infer.pdf", +} + +@InProceedings{calcagno-15, + author = "Cristiano Calcagno and Dino Distefano and + J{\'{e}}r{\'{e}}my Dubreil and Dominik Gabi and Pieter + Hooimeijer and Martino Luca and Peter W. O'Hearn and + Irene Papakonstantinou and Jim Purbrick and Dulma + Rodriguez", + title = "Moving Fast with Software Verification", + booktitle = nfm, + pages = "3--11", + year = "2015", + series = lncs, + volume = "9058", + publisher = springer, + URL = "https://research.facebook.com/publications/moving-fast-with-software-verification/", +} + +@Article{calcagno-closed-03, + author = "Cristiano Calcagno and Eugenio Moggi and Tim Sheard", + title = "Closed Types for a Safe Imperative {MetaML}", + journal = jfp, + year = "2003", + volume = "13", + number = "3", + pages = "545--571", + URL = "http://dx.doi.org/10.1017/S0956796802004598", +} + +@InProceedings{calcagno-distefano-ohearn-yang-09, + author = "Cristiano Calcagno and Dino Distefano and Peter W. + O'Hearn and Hongseok Yang", + title = "Compositional shape analysis by means of + bi-abduction", + booktitle = popl, + year = "2009", + pages = "289--300", + URL = "http://www.doc.ic.ac.uk/~ccris/ftp/popl09.pdf", +} + +@Article{calcagno-distefano-ohearn-yang-11, + author = "Cristiano Calcagno and Dino Distefano and Peter W. + O'Hearn and Hongseok Yang", + title = "Compositional Shape Analysis by Means of + Bi-Abduction", + journal = jacm, + volume = "58", + number = "6", + year = "2011", + URL = "http://www.doc.ic.ac.uk/~ccris/ftp/jacm-abduction.pdf", +} + +@InProceedings{calcagno-distefano-vafeiadis-09, + author = "Cristiano Calcagno and Dino Distefano and Viktor + Vafeiadis", + title = "Bi-abductive Resource Invariant Synthesis", + booktitle = aplas, + year = "2009", + pages = "259--274", + publisher = springer, + series = lncs, + volume = "5904", + URL = "http://www.eecs.qmul.ac.uk/~ddino/papers/resinvariant.pdf", +} + +@InProceedings{calcagno-inference-04, + author = "Cristiano Calcagno and Eugenio Moggi and Walid Taha", + title = "{ML}-Like Inference for Classifiers", + booktitle = esop, + year = "2004", + pages = "79--93", + series = lncs, + volume = "2986", + publisher = springer, + URL = "http://www.doc.ic.ac.uk/~ccris/ftp/esop04.pdf", +} + +@InProceedings{calcagno-local-07, + author = "Cristiano Calcagno and Peter W. O'Hearn and Hongseok + Yang", + title = "Local Action and Abstract Separation Logic", + booktitle = lics, + year = "2007", + pages = "366--378", + URL = "http://www.doc.ic.ac.uk/~ccris/ftp/asl-short.pdf", +} + +@InProceedings{calcagno-yang-ohearn-01, + author = "Cristiano Calcagno and Hongseok Yang and Peter W. + O'Hearn", + title = "Computability and Complexity Results for a Spatial + Assertion Language for Data Structures", + booktitle = aplas, + pages = "289--300", + year = "2001", + URL = "http://www.cs.ox.ac.uk/people/hongseok.yang/paper/decidability.ps", +} + +@Misc{caml-light, + author = "Xavier Leroy and Damien Doligez and Michel Mauny and + Pierre Weis", + title = "The {Caml} {Light} system, release 0.75", + year = "2002", + URL = "http://caml.inria.fr/", +} + +@InProceedings{carbonneaux-14, + author = "Quentin Carbonneaux and Jan Hoffmann and Tahina + Ramananandro and Zhong Shao", + title = "End-to-end verification of stack-space bounds for {C} + programs", + booktitle = pldi, + pages = "270--281", + year = "2014", + URL = "http://flint.cs.yale.edu/flint/publications/veristack.pdf", +} + +@InCollection{cardelli-97, + author = "Luca Cardelli", + title = "Type Systems", + booktitle = "The Computer Science and Engineering Handbook", + publisher = "CRC Press", + year = "1997", + editor = "Allen B. Tucker", + pages = "2208--2236", + URL = "http://research.microsoft.com/Users/luca/Papers/TypeSystems.pdf", +} + +@Article{cardelli-basic-87, + author = "Luca Cardelli", + title = "Basic polymorphic typechecking", + journal = scp, + year = "1987", + volume = "8", + number = "2", + pages = "147--172", + URL = "http://research.microsoft.com/Users/luca/Papers/BasicTypechecking.pdf", +} + +@TechReport{cardelli-extensible-94, + author = "Luca Cardelli and Florian Matthes and Martín Abadi", + title = "Extensible syntax with lexical scoping", + institution = decsrc, + year = "1994", + type = "Research Report", + number = "121", + URL = "http://gatekeeper.dec.com/pub/compaq/SRC/research-reports/SRC-121.ps.gz", +} + +@Article{cardelli-longo-91, + author = "Luca Cardelli and Giuseppe Longo", + title = "A semantic basis for {Quest}", + journal = jfp, + year = "1991", + volume = "1", + number = "4", + pages = "417--458", + URL = "http://research.microsoft.com/Users/luca/Papers/QuestSem.pdf", +} + +@InCollection{cardelli-mitchell-records-91, + author = "Luca Cardelli and John Mitchell", + title = "Operations on Records", + booktitle = taoop, + publisher = mitp, + editor = "Carl A. Gunter and John C. Mitchell", + year = "1994", + URL = "http://research.microsoft.com/Users/luca/Papers/Records.pdf", +} + +@Article{cardelli-multiple-88, + author = "Luca Cardelli", + title = "A Semantics of Multiple Inheritance", + journal = ic, + volume = "76", + number = "2/3", + year = "1988", + pages = "138--164", + URL = "http://research.microsoft.com/Users/luca/Papers/Inheritance.pdf", +} + +@Misc{cardelli-quest-91, + author = "Luca Cardelli", + title = "The {Quest} Language and System", + year = "1991", + URL = "http://research.microsoft.com/Users/luca/Notes/QuestManual.pdf", +} + +@InProceedings{cardelli-typeful-89, + author = "Luca Cardelli", + title = "Typeful programming", + booktitle = "Formal Description of Programming Concepts", + year = "1989", + series = "IFIP State of the Art Reports Series", + publisher = springer, + URL = "http://research.microsoft.com/Users/luca/Papers/TypefulProg.pdf", +} + +@Article{cardelli-wegner-85, + author = "Luca Cardelli and Peter Wegner", + title = "On Understanding Types, Data Abstraction, and + Polymorphism", + journal = surveys, + volume = "17", + number = "4", + pages = "471--522", + year = "1985", + URL = "http://research.microsoft.com/Users/luca/Papers/OnUnderstanding.pdf", +} + +@Article{cardone-02, + author = "Felice Cardone", + title = "A coinductive completeness proof for the equivalence + of recursive types", + journal = tcs, + volume = "275", + number = "1--2", + year = "2002", + pages = "575--587", + URL = "http://dx.doi.org/10.1016/S0304-3975(01)00298-5", + publisher = elsevier, +} + +@Article{cardone-coppo-91, + author = "Felice Cardone and Mario Coppo", + title = "Type inference with recursive types: syntax and + semantics", + journal = ic, + volume = "92", + number = "1", + year = "1991", + pages = "48--80", + URL = "http://dx.doi.org/10.1016/0890-5401(91)90020-3", +} + +@InProceedings{carette-finally-tagless-07, + author = "Jacques Carette and Oleg Kiselyov and Chung-chieh + Shan", + title = "Finally Tagless, Partially Evaluated", + booktitle = aplas, + year = "2007", + pages = "222--238", + publisher = springer, + series = lncs, + volume = "4807", + URL = "http://okmij.org/ftp/papers/tagless-final-APLAS.pdf", +} + +@Article{carette-gauss-05, + author = "Jacques Carette", + title = "{Gaussian} Elimination: a case study in efficient + genericity with {MetaOCaml}", + journal = scp, + year = "2005", + volume = "62", + number = "1", + pages = "3--24", + URL = "http://www.cas.mcmaster.ca/~carette/publications/ge.pdf", +} + +@InProceedings{carlier-04, + author = "Sébastien Carlier and Jeff Polakow and J. B. Wells + and A. J. Kfoury", + title = "{System E}: Expansion variables for flexible typing + with linear and non-linear types and intersection + types", + booktitle = esop, + year = "2004", + series = lncs, + publisher = springer, + URL = "http://www.macs.hw.ac.uk/~jbw/papers/Carlier+Polakow+Wells+Kfoury:System-E:ESOP-2004.pdf", +} + +@TechReport{carlier-wells-04, + author = "Sébastien Carlier and J. B. Wells", + title = "Type inference with expansion variables and + intersection types in {System E} and an exact + correspondence with $\beta$-reduction", + institution = "Heriot-Watt University", + year = "2004", + number = "HW-MACS-TR-0012", + URL = "http://www.macs.hw.ac.uk:8080/techreps/docs/files/HW-MACS-TR-0012.pdf", +} + +@Misc{cartwright-notes-00, + author = "Robert Cartwright", + title = "Notes on Object-Oriented Program Design", + URL = "http://www.cs.rice.edu/~cork/book/", + year = "2000", +} + +@InProceedings{castagna-ampersand-93, + author = "Giuseppe Castagna", + title = "${F}_{\leq}^{\&}$ : integrating parametric and ``ad + hoc'' second order polymorphism", + booktitle = "International Workshop on Database Programming + Languages", + year = "1993", + publisher = springer, + series = "Workshops in Computing", +} + +@Article{castagna-contravariance-95, + author = "Giuseppe Castagna", + title = "Covariance and Contravariance: Conflict without a + Cause", + journal = toplas, + volume = "17", + number = "3", + pages = "431--447", + year = "1995", + URL = "ftp://ftp.ens.fr/pub/di/users/castagna/covariance.ps.Z", +} + +@InProceedings{castagna-frisch-05, + author = "Giuseppe Castagna and Alain Frisch", + title = "A gentle introduction to semantic subtyping", + booktitle = ppdp, + year = "2005", + pages = "198--199", + URL = "http://www.pps.univ-paris-diderot.fr/~gc/papers/icalp-ppdp05.pdf", +} + +@InProceedings{cejtin-al-00, + author = "Henry Cejtin and Suresh Jagannathan and Stephen + Weeks", + title = "Flow-directed Closure Conversion for Typed Languages", + booktitle = esop, + publisher = springer, + series = lncs, + volume = "1782", + pages = "56--71", + year = "2000", + URL = "http://mlton.org/papers/00-esop.ps.gz", +} + +@InProceedings{cerco, + author = "Roberto M. Amadio and Nicholas Ayache and + Fran{\c{c}}ois Bobot and Jaap Boender and Brian + Campbell and Ilias Garnier and Antoine Madet and James + McKinna and Dominic P. Mulligan and Mauro Piccolo and + Randy Pollack and Yann R{\'{e}}gis{-}Gianas and Claudio + Sacerdoti Coen and Ian Stark and Paolo Tranquilli", + title = "Certified Complexity ({CerCo})", + booktitle = fopara, + pages = "1--18", + year = "2014", + series = lncs, + publisher = springer, + volume = "8552", + URL = "http://dx.doi.org/10.1007/978-3-319-12466-7_1", +} + +@Misc{cfml, + author = "Arthur Charguéraud", + title = "The {CFML} tool and library", + howpublished = "\url{http://www.chargueraud.org/softs/cfml/}", + year = "2016", +} + +@InProceedings{chakravarty-associated-05, + author = "Manuel M. T. Chakravarty and Gabriele Keller and Simon + L. {Peyton Jones} and Simon Marlow", + title = "Associated types with class", + booktitle = popl, + pages = "1--13", + year = "2005", + URL = "https://research.microsoft.com/en-us/um/people/simonpj/papers/assoc-types/assoc.pdf", +} + +@TechReport{chambers-leavens-96, + author = "Craig Chambers and Gary T. Leavens", + title = "{BeCecil}, a Core Object-Oriented Language with Block + Structure and Multimethods: Semantics and Typing", + institution = "University of Washington", + year = "1996", + number = "UW-CSE-96-12-02", + URL = "ftp://ftp.cs.washington.edu/pub/chambers/BeCecil.ps.gz", +} + +@Misc{chameleon, + author = "Andreas Rossberg and Peter J. Stuckey and Martin + Sulzmann and Jeremy Wazny", + title = "The {Chameleon} language", + URL = "http://taichi.ddns.comp.nus.edu.sg/taichiwiki/ChameleonHomePage", +} + +@InProceedings{chang-rival-08, + author = "Bor-Yuh Evan Chang and Xavier Rival", + title = "Relational inductive shape analysis", + booktitle = popl, + year = "2008", + pages = "247--260", + URL = "http://xisa.cs.colorado.edu/papers/popl08-relational.pdf", +} + +@PhdThesis{chargueraud-10, + author = "Arthur Charguéraud", + title = "Characteristic Formulae for Mechanized Program + Verification", + school = "Université Paris 7", + year = "2010", + URL = "http://www.chargueraud.org/research/2010/thesis/thesis_final.pdf", +} + +@InProceedings{chargueraud-10-cfml, + author = "Arthur Chargu{\'e}raud", + title = "Program Verification Through Characteristic Formulae", + booktitle = icfp, + year = "2010", + pages = "321--332", + URL = "http://www.chargueraud.org/research/2010/cfml/main.pdf", +} + +@InProceedings{chargueraud-11-cfml, + author = "Arthur Chargu{\'e}raud", + title = "Characteristic Formulae for the Verification of + Imperative Programs", + booktitle = icfp, + year = "2011", + pages = "418--430", + URL = "http://www.chargueraud.org/research/2011/cfml/main.pdf", +} + +@Misc{chargueraud-cfml, + author = "Arthur Charguéraud", + title = "Characteristic Formulae for the Verification of + Imperative Programs", + year = "2013", + note = "Unpublished. + \url{http://www.chargueraud.org/research/2013/cf/cf.pdf}", +} + +@Article{chargueraud-ln-11, + author = "Arthur Chargu{\'e}raud", + title = "The Locally Nameless Representation", + year = "2012", + journal = jar, + volume = "49", + number = "3", + pages = "363--408", + URL = "http://www.chargueraud.org/arthur/research/2009/ln/main.pdf", +} + +@InProceedings{chargueraud-pottier-08, + author = "Arthur Charguéraud and François Pottier", + title = "Functional Translation of a Calculus of Capabilities", + booktitle = icfp, + year = "2008", + pages = "213--224", + URL = "http://gallium.inria.fr/~fpottier/publis/chargueraud-pottier-capabilities.pdf", +} + +@InProceedings{chargueraud-pottier-15, + author = "Arthur Charguéraud and François Pottier", + title = "Machine-Checked Verification of the Correctness and + Amortized Complexity of an Efficient Union-Find + Implementation", + booktitle = itp, + year = "2015", + volume = "9236", + series = lncs, + publisher = springer, + pages = "137--153", + URL = "http://gallium.inria.fr/~fpottier/publis/chargueraud-pottier-uf.pdf", +} + +@TechReport{chen-al-99, + author = "Martin Odersky and Christoph Zenger and Matthias + Zenger and Gang Chen", + title = "A Functional View Of Join", + institution = "University of South Australia", + year = "1999", + number = "ACRC-99-016", + URL = "http://www.christoph-zenger.de/papers/tr-acrc-99-016.ps.gz", +} + +@InProceedings{chen-crash-16, + author = "Haogang Chen and Daniel Ziegler and Tej Chajed and + Adam Chlipala and M. Frans Kaashoek and Nickolai + Zeldovich", + title = "Using {Crash Hoare logic} for certifying the {FSCQ} + file system", + booktitle = sosp, + pages = "18--37", + year = "2015", + URL = "https://people.csail.mit.edu/nickolai/papers/chen-fscq.pdf", +} + +@InProceedings{chen-hudak-97, + author = "Chih-Ping Chen and Paul Hudak", + title = "Rolling your own mutable {ADT}---a connection between + linear types and monads", + booktitle = popl, + year = "1997", + pages = "54--66", + URL = "http://www.cs.yale.edu/homes/hudak-paul/hudak-dir/popl97.ps", +} + +@InProceedings{chen-shi-xi-04, + author = "Chiyan Chen and Rui Shi and Hongwei Xi", + title = "A Typeful Approach to Object-Oriented Programming with + Multiple Inheritance", + booktitle = padl, + publisher = springer, + series = lncs, + volume = "3057", + year = "2004", + URL = "http://www.cs.bu.edu/~hwxi/academic/papers/OBJwMI/OBJwMI.pdf", +} + +@InProceedings{chen-tarditi-05, + author = "Juan Chen and David Tarditi", + title = "A simple typed intermediate language for + object-oriented languages", + booktitle = popl, + year = "2005", + pages = "38--49", + URL = "http://research.microsoft.com/pubs/59934/lilc_popl05.pdf", +} + +@InProceedings{chen-xi-05, + author = "Chiyan Chen and Hongwei Xi", + title = "Combining Programming with Theorem Proving", + booktitle = icfp, + year = "2005", + pages = "66--77", + URL = "http://www.cs.bu.edu/~hwxi/academic/papers/icfp05.pdf", +} + +@InProceedings{chen-xi-icfp-03, + author = "Chiyan Chen and Hongwei Xi", + title = "Meta-Programming through Typeful Code Representation", + booktitle = icfp, + year = "2003", + pages = "275--286", + URL = "http://www.cs.bu.edu/~hwxi/academic/papers/icfp03.pdf", +} + +@InProceedings{chen-xi-pepm-03, + author = "Chiyan Chen and Hongwei Xi", + title = "Implementing Typeful Program Transformations", + booktitle = pepm, + year = "2003", + pages = "20--28", + URL = "http://www.cs.bu.edu/~hwxi/academic/papers/pepm03.pdf", +} + +@InProceedings{cheney-05, + author = "James Cheney", + title = "Scrap your nameplate", + booktitle = icfp, + year = "2005", + pages = "180--191", + URL = "http://homepages.inf.ed.ac.uk/jcheney/publications/cheney05icfp.pdf", +} + +@InProceedings{cheney-hinze-02, + author = "James Cheney and Ralf Hinze", + title = "A lightweight implementation of generics and + dynamics", + booktitle = hw, + year = "2002", + URL = "http://www.cs.cornell.edu/people/jcheney/papers/Dynamic-final.pdf", +} + +@TechReport{cheney-hinze-03, + author = "James Cheney and Ralf Hinze", + title = "First-Class Phantom Types", + institution = "Cornell University", + year = "2003", + number = "1901", + URL = "http://techreports.library.cornell.edu:8081/Dienst/UI/1.0/Display/cul.cis/TR2003-1901", +} + +@InProceedings{cheney-urban-04, + author = "James Cheney and Christian Urban", + title = "{$\alpha$Prolog}: {A} Logic Programming Language with + Names, Binding and $\alpha$-equivalence", + booktitle = iclp, + pages = "269--283", + year = "2004", + volume = "3132", + series = lncs, + publisher = springer, + URL = "http://www.cs.cornell.edu/people/jcheney/papers/alpnba.pdf", +} + +@InProceedings{cheng-blelloch-01, + author = "Perry Cheng and Guy E. Blelloch", + title = "A Parallel, Real-Time Garbage Collector", + booktitle = pldi, + pages = "125--136", + year = "2001", + URL = "https://www.cs.cmu.edu/~guyb/papers/gc2001.pdf", +} + +@Article{chin-khoo-01, + author = "Wei-Ngan Chin and Siau-Cheng Khoo", + title = "Calculating Sized Types", + journal = hosc, + volume = "14", + number = "2--3", + year = "2001", + pages = "261--300", + publisher = kluwer, + URL = "http://dx.doi.org/10.1023/A:1012996816178", +} + +@InProceedings{chitil-01, + author = "Olaf Chitil", + title = "Compositional Explanation of Types and Algorithmic + Debugging of Type Errors", + booktitle = icfp, + pages = "193--204", + year = "2001", + URL = "http://www-users.cs.york.ac.uk/~olaf/PUBLICATIONS/explainTypes.ps.gz", +} + +@InProceedings{chlipala-07, + author = "Adam Chlipala", + title = "A certified type-preserving compiler from lambda + calculus to assembly language", + booktitle = pldi, + year = "2007", + pages = "54--65", + URL = "http://www.cs.berkeley.edu/~adamc/papers/CtpcPLDI07/CtpcPLDI07.pdf", +} + +@InProceedings{chlipala-08, + author = "Adam Chlipala", + title = "Parametric higher-order abstract syntax for mechanized + semantics", + booktitle = icfp, + year = "2008", + pages = "143--156", + URL = "http://adam.chlipala.net/papers/PhoasICFP08/PhoasICFP08.pdf", +} + +@InProceedings{chlipala-15, + author = "Adam Chlipala", + title = "From Network Interface to Multithreaded Web + Applications: {A} Case Study in Modular Program + Verification", + booktitle = popl, + pages = "609--622", + year = "2015", + URL = "http://adam.chlipala.net/papers/BedrockPOPL15/BedrockPOPL15.pdf", +} + +@InProceedings{chlipala-bedrock-13, + author = "Adam Chlipala", + title = "The {Bedrock} structured programming system: combining + generative metaprogramming and {Hoare} logic in an + extensible program verifier", + booktitle = icfp, + pages = "391--402", + year = "2013", + URL = "http://adam.chlipala.net/papers/BedrockICFP13/BedrockICFP13.pdf", +} + +@Book{chlipala-cpdt-13, + author = "Adam Chlipala", + title = "Certified Programming and Dependent Types", + publisher = mitp, + year = "2013", + URL = "http://adam.chlipala.net/cpdt/", +} + +@InProceedings{chlipala-ynot-09, + author = "Adam Chlipala and Gregory Malecha and Greg Morrisett + and Avraham Shinnar and Ryan Wisnesky", + title = "Effective interactive proofs for higher-order + imperative programs", + booktitle = icfp, + year = "2009", + pages = "79--90", + URL = "http://ynot.cs.harvard.edu/papers/icfp09.pdf", +} + +@PhdThesis{choppella-02, + author = "Venkatesh Choppella", + title = "Unification Source-tracking with Application to + Diagnosis of Type Inference", + school = "Indiana University", + year = "2002", + URL = "http://www.cs.indiana.edu/cgi-bin/techreports/TRNNN.cgi?trnum=TR566", +} + +@InProceedings{chrzaszcz-98, + author = "Jacek Chrzaszcz", + title = "Polymorphic Subtyping Without Distributivity", + booktitle = mfcs, + pages = "346--355", + year = "1998", + series = lncs, + volume = "1450", + publisher = springer, + URL = "http://www.mimuw.edu.pl/~chrzaszc/papers/Chrzaszcz_Polymorphic-subtyping-without-distributivity.ps.gz", +} + +@Article{clarke-79, + author = "Edmund Clarke", + title = "Programming Language Constructs for Which It Is + Impossible To Obtain Good {Hoare} Axiom Systems", + journal = jacm, + volume = "26", + number = "1", + year = "1979", + pages = "129--147", + URL = "http://doi.acm.org/10.1145/322108.322121", +} + +@InProceedings{clarke-drossopoulou-02, + author = "Dave Clarke and Sophia Drossopoulou", + title = "Ownership, encapsulation and the disjointness of type + and effect", + booktitle = oopsla, + year = "2002", + pages = "292--310", + URL = "http://pubs.doc.ic.ac.uk/ownershipAndEffects/ownershipAndEffects.ps", +} + +@InProceedings{clarke-noble-potter-01, + author = "David G. Clarke and James Noble and John Potter", + title = "Simple Ownership Types for Object Containment", + booktitle = ecoop, + year = "2001", + pages = "53--76", + publisher = springer, + series = lncs, + volume = "2072", + URL = "http://www.cs.washington.edu/education/courses/cse590p/00wi/simple.pdf", +} + +@InProceedings{clarke-potter-noble-98, + author = "David G. Clarke and John M. Potter and James Noble", + title = "Ownership types for flexible alias protection", + booktitle = oopsla, + year = "1998", + pages = "48--64", + URL = "http://doi.acm.org/10.1145/286936.286947", +} + +@InCollection{clarke-survey-13, + author = "Dave Clarke and Johan {\"O}stlund and Ilya Sergey and + Tobias Wrigstad", + title = "Ownership Types: {A} Survey", + booktitle = "Aliasing in Object-Oriented Programming. Types, + Analysis and Verification", + year = "2013", + pages = "15--58", + publisher = springer, + series = lncs, + volume = "7850", + URL = "http://dx.doi.org/10.1007/978-3-642-36946-9_3", +} + +@InProceedings{clarke-wrigstad-03, + author = "Dave Clarke and Tobias Wrigstad", + title = "External Uniqueness Is Unique Enough", + booktitle = ecoop, + year = "2003", + pages = "176--200", + publisher = springer, + series = lncs, + volume = "2743", + URL = "https://lirias.kuleuven.be/bitstream/123456789/203436/1/euiue.pdf", +} + +@InProceedings{cleaveland-steffen-91, + author = "Rance Cleaveland and Bernhard Steffen", + title = "A linear-time model-checking algorithm for the + alternation-free modal mu-calculus", + booktitle = cav, + pages = "48--58", + year = "1991", + volume = "575", + series = lncs, + publisher = springer, + URL = "http://dx.doi.org/10.1007/3-540-55179-4_6", +} + +@InProceedings{clement-despeyroux-kahn-86, + author = "Dominique Cl{\'e}ment and Jo{\"e}lle Despeyroux and + Thierry Despeyroux and Gilles Kahn", + title = "A simple applicative language: Mini-{ML}", + booktitle = lfp, + year = "1986", + pages = "13--27", +} + +@InProceedings{clements-felleisen-03, + author = "John Clements and Matthias Felleisen", + title = "A Tail-Recursive Semantics for Stack Inspections", + booktitle = esop, + pages = "22--37", + year = "2003", + volume = "2618", + series = lncs, + publisher = springer, + URL = "http://www.ccs.neu.edu/scheme/pubs/esop2003-cf.ps.gz", +} + +@InProceedings{clochard-filliatre-paskevich-15, + title = "How to avoid proving the absence of integer + overflows", + author = "Martin Clochard and Jean-Christophe Filli{\^a}tre and + Andrei Paskevich", + URL = "https://hal.inria.fr/hal-01162661", + booktitle = vstte, + year = "2015", + pages = "94--109", + series = lncs, + volume = "9593", + publisher = springer, +} + +@InProceedings{clochard-marche-paskevich-14, + author = "Martin Clochard and Claude March{\'{e}} and Andrei + Paskevich", + title = "Verified programs with binders", + booktitle = plpv, + pages = "29--40", + year = "2014", + URL = "https://hal.inria.fr/hal-00913431", +} + +@InProceedings{coblenz-16, + author = "Michael J. Coblenz and Joshua Sunshine and Jonathan + Aldrich and Brad A. Myers and Sam Weber and Forrest + Shull", + title = "Exploring language support for immutability", + booktitle = icse, + pages = "736--747", + year = "2016", + URL = "http://www.cs.cmu.edu/~aldrich/papers/icse16-immutability.pdf", +} + +@Article{cohen-search-06, + author = "Albert Cohen and Sébastien Donadio and Maria-Jesus + Garzaran and Christoph Herrmann and Oleg Kiselyov and + David Padua", + title = "In search of a program generator to implement generic + transformations for high-performance computing", + journal = scp, + year = "2006", + volume = "62", + number = "1", + pages = "25--46", + URL = "http://www-rocq.inria.fr/~acohen/publications/CDGHKP06.ps.gz", +} + +@InProceedings{cohen-vcc-09, + author = "Ernie Cohen and Markus Dahlweid and Mark A. Hillebrand + and Dirk Leinenbach and Michal Moskal and Thomas Santen + and Wolfram Schulte and Stephan Tobies", + title = "{VCC}: {A} Practical System for Verifying Concurrent + {C}", + booktitle = tphol, + year = "2009", + pages = "23--42", + publisher = springer, + series = lncs, + volume = "5674", + URL = "http://research.microsoft.com/apps/pubs/default.aspx?id=117859", +} + +@InProceedings{colazzo-ghelli-99, + author = "Dario Colazzo and Giorgio Ghelli", + title = "Subtyping Recursive Types in {Kernel Fun}", + booktitle = lics, + pages = "137--146", + year = "1999", +} + +@TechReport{collins-shao-02, + author = "Gregory D. Collins and Zhong Shao", + title = "Intensional Analysis of Higher-Kinded Recursive + Types", + institution = "Yale University", + year = "2002", + number = "YALEU/DCS/TR-1240", + URL = "http://flint.cs.yale.edu/flint/publications/collins02-ita-tr.pdf", +} + +@InProceedings{colmerauer-84, + author = "Alain Colmerauer", + title = "Equations and Inequations on Finite and Infinite + Trees", + booktitle = "International Conference on Fifth Generation Computer + Systems (FGCS)", + pages = "85--99", + year = "1984", +} + +@Article{color, + author = "Frédéric Blanqui and Adam Koprowski", + title = "{CoLoR}: a Coq library on well-founded rewrite + relations and its application to the automated + verification of termination certificates", + journal = mscs, + year = "2011", + volume = "21", + number = "4", + pages = "827--859", + URL = "https://who.rocq.inria.fr/Frederic.Blanqui/papers/mscs11.pdf", +} + +@InProceedings{comon-93, + author = "Hubert Comon", + title = "Constraints in Term Algebras (Short Survey)", + booktitle = amast, + year = "1993", + publisher = springer, + series = "Workshops in Computing", + URL = "http://www.lsv.ens-cachan.fr/~comon/ftp.articles/amast93.ps", +} + +@Article{comon-lescanne-89, + author = "Hubert Comon and Pierre Lescanne", + title = "Equational Problems and Disunification", + journal = jsc, + year = "1989", + volume = "7", + pages = "371--425", + URL = "http://perso.ens-lyon.fr/pierre.lescanne/PUBLICATIONS/jsc-diseq.pdf", +} + +@Misc{compcert, + author = "Xavier Leroy", + title = "The {CompCert C} compiler", + year = "2015", + howpublished = "\url{http://compcert.inria.fr/}", +} + +@InProceedings{conchon-filliatre-07, + author = "Sylvain Conchon and Jean{-}Christophe + Filli{\^{a}}tre", + title = "A persistent union-find data structure", + booktitle = ml, + pages = "37--46", + year = "2007", + URL = "https://www.lri.fr/~filliatr/puf/", +} + +@Book{conchon-filliatre-ocaml-14, + author = "Sylvain Conchon et Jean-Christophe Filliâtre", + title = "Apprendre à programmer avec {OCaml}: Algorithmes et + structures de données", + publisher = "Eyrolles", + year = "2014", + URL = "http://programmer-avec-ocaml.lri.fr/", +} + +@InProceedings{conchon-kanig-lescuyer-08, + author = "Sylvain Conchon and Johannes Kanig and Stéphane + Lescuyer", + title = "\textsc{Sat-Micro}: petit mais costaud!", + booktitle = jfla, + year = "2008", + URL = "http://www.lri.fr/~conchon/publis/conchon-jfla08.ps", +} + +@InProceedings{conchon-le-fessant-99, + title = "Jocaml: Mobile Agents for {Objective-Caml}", + author = "Sylvain Conchon and Fabrice Le Fessant", + booktitle = "International Symposium on Agent Systems and + Applications and International Symposium on Mobile + Agents (ASA/MA)", + year = "1999", + pages = "22--29", + URL = "http://para.inria.fr/~conchon/publis/conchon-lefessant-asama99.ps.gz", +} + +@InProceedings{conchon-pottier-01, + author = "Sylvain Conchon and François Pottier", + title = "{JOIN(X)}: Constraint-Based Type Inference for the + Join-Calculus", + booktitle = esop, + publisher = springer, + series = lncs, + volume = "2028", + pages = "221--236", + year = "2001", + URL = "http://gallium.inria.fr/~fpottier/publis/conchon-fpottier-esop01.ps.gz", +} + +@TechReport{considine-00, + author = "Jeffrey Considine", + title = "Efficient Hash-Consing of Recursive Types", + institution = "Boston University", + year = "2000", + number = "2000-006", + URL = "http://www.cs.bu.edu/techreports/pdf/2000-006-hashconsing-recursive-types.pdf", +} + +@InProceedings{cook-09, + author = "William R. Cook", + title = "On understanding data abstraction, revisited", + booktitle = oopsla, + year = "2009", + pages = "557--572", + URL = "http://www.cs.utexas.edu/~wcook/Drafts/2009/essay.pdf", +} + +@InProceedings{cook-71, + author = "Stephen A. Cook", + title = "The Complexity of Theorem-Proving Procedures", + booktitle = stoc, + year = "1971", + pages = "151--158", + URL = "http://doi.acm.org/10.1145/800157.805047", +} + +@InProceedings{cook-tractable-11, + author = "Byron Cook and Christoph Haase and Jo{\"{e}}l Ouaknine + and Matthew J. Parkinson and James Worrell", + title = "Tractable Reasoning in a Fragment of Separation + Logic", + booktitle = concur, + pages = "235--249", + year = "2011", + series = lncs, + volume = "6901", + publisher = springer, + URL = "http://www.cs.ox.ac.uk/files/4048/sl.pdf", +} + +@TechReport{cooper-harvey-kennedy-04, + author = "Keith D. Cooper and Timothy J. Harvey and Ken + Kennedy", + title = "Iterative Data-flow Analysis, Revisited", + institution = "Rice University", + year = "2004", + number = "TR04-432", + URL = "http://www.cs.rice.edu/~harv/my_papers/worklist.pdf", +} + +@Article{coppo-dezani-80, + author = "Mario Coppo and Mariangiola Dezani-Ciancaglini", + title = "An extension of the basic functionality theory for the + $\lambda$-calculus", + journal = "Notre Dame J. Formal Logic", + year = "1980", + volume = "21", + number = "4", + pages = "685--693", +} + +@Manual{coq, + author = "{The {Coq} development team}", + title = "The {Coq} Proof Assistant", + year = "2016", + URL = "http://coq.inria.fr/", +} + +@Book{coqart, + author = "Yves Bertot and Pierre Cast{\'{e}}ran", + title = "Interactive Theorem Proving and Program Development -- + {Coq'Art}: The Calculus of Inductive Constructions", + series = "Texts in Theoretical Computer Science. An {EATCS} + Series", + publisher = springer, + year = "2004", + URL = "https://www.labri.fr/perso/casteran/CoqArt/coqartF.pdf", +} + +@InProceedings{coquand-86, + author = "Thierry Coquand", + title = "An analysis of {Girard}'s paradox", + booktitle = lics, + pages = "227--236", + year = "1986", + URL = "http://hal.inria.fr/docs/00/07/60/23/PDF/RR-0531.pdf", +} + +@Book{cormen-en, + author = "Thomas H. Cormen and Charles E. Leiserson and Ronald + L. Rivest and Clifford Stein", + title = "Introduction to Algorithms (Third Edition)", + publisher = "MIT Press", + year = "2009", + URL = "http://mitpress.mit.edu/catalog/item/ + default.asp?ttype=2&tid=11866", +} + +@Book{cormen-fr, + author = "Thomas H. Cormen and Charles E. Leiserson and Ronald + L. Rivest and Clifford Stein", + title = "Algorithmique (Troisième Édition)", + publisher = "Dunod", + year = "2010", + series = "Sciences Sup", + URL = "http://www.dunod.com/informatique-multimedia/fondements-de-linformatique/algorithmique/algorithmique", + note = "Traduction française", +} + +@Article{courcelle-fundamental-trees, + title = "Fundamental Properties of Infinite Trees", + author = "Bruno Courcelle", + pages = "95--169", + journal = tcs, + year = "1983", + volume = "25", + number = "2", +} + +@InCollection{cousot-90, + author = "Patrick Cousot", + title = "Methods and Logics for Proving Programs", + booktitle = "Formal Models and Semantics", + series = "Handbook of Theoretical Computer Science", + publisher = elsevier, + year = "1990", + pages = "841--993", + volume = "B", + chapter = "15", + URL = "http://www.di.ens.fr/~cousot/publications.www/Cousot-HTCS-vB-FMS-c15-p843--993-1990.pdf.gz", +} + +@InProceedings{cousot-cousot-77, + author = "Patrick Cousot and Radhia Cousot", + title = "Abstract interpretation: a unified lattice model for + static analysis of programs by construction or + approximation of fixpoints", + pages = "238--252", + booktitle = popl, + year = "1977", + URL = "http://www.di.ens.fr/~cousot/publications.www/CousotCousot-POPL-77-ACM-p238--252-1977.pdf", +} + +@Article{cousot-cousot-constructive-79, + author = "Patrick Cousot and Radhia Cousot", + title = "Constructive Versions of {Tarski}'s Fixed Point + Theorems", + journal = "Pacific Journal of Mathematics", + volume = "81", + number = "1", + pages = "43--57", + year = "1979", + URL = "http://www.di.ens.fr/~cousot/publications.www/CousotCousot-PacJMath-82-1-1979.pdf", +} + +@InProceedings{cousot-gentle-09, + author = "Patrick Cousot and Radhia Cousot", + title = "A gentle introduction to formal verification of + computer systems by abstract interpretation", + booktitle = "Logics and Languages for Reliability and Security", + series = "{NATO} Science Series {III}: Computer and Systems + Sciences", + editor = "J.~Esparza and O.~Grumberg and M.~Broy", + publisher = "IOS Press", + year = "2010", + pages = "1--29", + URL = "http://www.di.ens.fr/~cousot/COUSOTpapers/MARKTOBERDORF-09.shtml", +} + +@InProceedings{cousot-sba-95, + author = "Patrick Cousot and Radhia Cousot", + title = "Formal Language, Grammar and Set-Constraint-Based + Program Analysis by Abstract Interpretation", + pages = "170--181", + booktitle = fpca, + publisher = acmp, + year = "1995", +} + +@InProceedings{coutts-07, + author = "Duncan Coutts and Roman Leshchinskiy and Don Stewart", + title = "Stream fusion: from lists to streams to nothing at + all", + booktitle = icfp, + pages = "315--326", + year = "2007", + URL = "http://dx.doi.org/10.1145/1291151.1291199", +} + +@InProceedings{crank-felleisen-91, + author = "Erik Crank and Matthias Felleisen", + title = "Parameter-Passing and the Lambda Calculus", + booktitle = popl, + pages = "233--244", + year = "1991", + URL = "http://www.ccs.neu.edu/scheme/pubs/popl91-cf.ps.gz", +} + +@TechReport{crary-99, + author = "Karl Crary", + title = "Simple, Efficient Object Encoding using Intersection + Types", + institution = "Carnegie Mellon University", + year = "1999", + number = "CMU-CS-99-100", + URL = "http://www-2.cs.cmu.edu/~crary/papers/1999/orei/orei.ps.gz", +} + +@InProceedings{crary-cc-99, + author = "Karl Crary and David Walker and Greg Morrisett", + title = "Typed Memory Management in a Calculus of + Capabilities", + booktitle = popl, + pages = "262--275", + year = "1999", + URL = "http://www.cs.cornell.edu/talc/papers/capabilities.pdf", +} + +@Article{crary-intensional-02, + author = "Karl Crary and Stephanie Weirich and Greg Morrisett", + title = "Intensional Polymorphism in Type Erasure Semantics", + journal = jfp, + year = "2002", + volume = "12", + number = "6", + pages = "567--600", + URL = "http://www-2.cs.cmu.edu/~crary/papers/2002/typepass/typepass.ps", +} + +@InProceedings{crary-intensional-98, + author = "Karl Crary and Stephanie Weirich and Greg Morrisett", + title = "Intensional Polymorphism in Type-Erasure Semantics", + booktitle = icfp, + pages = "301--313", + year = "1998", + URL = "http://www.cis.upenn.edu/~sweirich/papers/typepass/typepass.ps", +} + +@PhdThesis{crary-phd-98, + author = "Karl Crary", + title = "Type-Theoretic Methodology for Practical Programming + Languages", + school = "Cornell University", + year = "1998", + URL = "http://www.cs.cmu.edu/~crary/papers/1998/thesis/thesis.ps.gz", +} + +@TechReport{crary-standard-09, + author = "Karl Crary", + title = "A Simple Proof of Call-by-Value Standardization", + institution = "Carnegie Mellon University", + year = "2009", + type = "Technical Report", + number = "CMU-CS-09-137", + URL = "https://www.cs.cmu.edu/~crary/papers/2009/standard.pdf", +} + +@InProceedings{crary-weirich-00, + author = "Karl Crary and Stephanie Weirich", + title = "Resource bound certification", + booktitle = popl, + year = "2000", + pages = "184--198", + URL = "http://www.cs.cornell.edu/talc/papers/resource_bound/res.pdf", +} + +@InProceedings{crary-weirich-99, + author = "Karl Crary and Stephanie Weirich", + title = "Flexible Type Analysis", + booktitle = icfp, + pages = "233--248", + year = "1999", + URL = "http://www-2.cs.cmu.edu/~crary/papers/1999/lx/lx.ps.gz", +} + +@PhdThesis{cretin-14, + author = "Julien Cretin", + title = "Erasable coercions: a unified approach to type + systems", + school = "Université Paris Diderot", + year = "2014", + URL = "http://tel.archives-ouvertes.fr/tel-00940511", +} + +@InProceedings{cretin-remy-12, + author = "Julien Cretin and Didier R{\'e}my", + title = "On the power of coercion abstraction", + booktitle = popl, + year = "2012", + pages = "361--372", + URL = "http://gallium.inria.fr/~remy/coercions/Cretin-Remy:coercions@popl2012.pdf", +} + +@PhdThesis{curtis-90, + author = "Pavel Curtis", + title = "Constrained Quantification in Polymorphic Type + Analysis", + school = "Cornell University", + year = "1990", + URL = "http://www.parc.xerox.com/company/history/publications/bw-ps-gz/csl90-1.ps.gz", +} + +@InProceedings{cyclone-regions-02, + author = "Dan Grossman and Greg Morrisett and Trevor Jim and + Michael Hicks and Yanling Wang and James Cheney", + title = "Region-Based Memory Management in {Cyclone}", + booktitle = pldi, + pages = "282--293", + year = "2002", + URL = "http://www.cs.cornell.edu/projects/cyclone/papers/cyclone-regions.pdf", +} + +@InProceedings{dafny, + author = "K. Rustan M. Leino", + title = "{Dafny}: An Automatic Program Verifier for Functional + Correctness", + booktitle = lpar, + pages = "348--370", + year = "2010", + volume = "6355", + series = lncs, + publisher = springer, + URL = "http://research.microsoft.com/en-us/um/people/leino/papers/krml203.pdf", +} + +@PhdThesis{damas-85, + author = "Luis Damas", + title = "Type Assignment in Programming Languages", + school = "University of Edinburgh", + year = "1985", +} + +@InProceedings{damas-milner-82, + author = "Luis Damas and Robin Milner", + title = "Principal type-schemes for functional programs", + booktitle = popl, + year = "1982", + pages = "207--212", + URL = "http://doi.acm.org/10.1145/582153.582176", +} + +@InProceedings{damm-josko-83, + author = "Werner Damm and Bernhard Josko", + title = "A Sound and Relatively$^*$ Complete Axiomatization of + {Clarke's} Language {L4}", + booktitle = "Logic of Programs", + pages = "161--175", + year = "1983", + volume = "164", + series = lncs, + publisher = springer, + URL = "http://dx.doi.org/10.1007/3-540-12896-4_362", +} + +@InProceedings{danielsson-06, + author = "Nils Anders Danielsson and John Hughes and Patrik + Jansson and Jeremy Gibbons", + title = "Fast and loose reasoning is morally correct", + booktitle = popl, + year = "2006", + pages = "206--217", + URL = "http://web.comlab.ox.ac.uk/oucl/work/jeremy.gibbons/publications/fast+loose.pdf", +} + +@InProceedings{danielsson-08, + author = "Nils Anders Danielsson", + title = "Lightweight Semiformal Time Complexity Analysis for + Purely Functional Data Structures", + booktitle = popl, + year = "2008", + URL = "http://www.cse.chalmers.se/~nad/publications/danielsson-popl2008.pdf", +} + +@InProceedings{danielsson-altenkirch-10, + author = "Nils Anders Danielsson and Thorsten Altenkirch", + title = "Subtyping, Declaratively", + booktitle = mpc, + year = "2010", + pages = "100--118", + publisher = springer, + series = lncs, + volume = "6120", + URL = "http://www.cse.chalmers.se/~nad/publications/danielsson-altenkirch-subtyping.pdf", +} + +@InProceedings{danner-13, + author = "Norman Danner and Jennifer Paykin and James S. Royer", + title = "A static cost analysis for a higher-order language", + booktitle = plpv, + pages = "25--34", + year = "2013", + URL = "http://cis.upenn.edu/~jpaykin/papers/danner_PLPV_2013.pdf", +} + +@TechReport{danvy-98, + author = "Olivier Danvy", + title = "Functional Unparsing", + institution = "BRICS", + year = "1998", + number = "RS-98-12", + URL = "http://www.brics.dk/RS/98/12/", +} + +@TechReport{danvy-nielsen-01, + author = "Olivier Danvy and Lasse R. Nielsen", + title = "Defunctionalization at Work", + year = "2001", + institution = "BRICS", + number = "RS-01-23", + URL = "http://www.brics.dk/RS/01/23/", +} + +@Article{danvy-nielsen-03, + author = "Olivier Danvy and Lasse R. Nielsen", + title = "A first-order one-pass {CPS} transformation", + journal = tcs, + volume = "308", + number = "1--3", + pages = "239--257", + year = "2003", + URL = "http://dx.doi.org/10.1016/S0304-3975(02)00733-8", +} + +@InProceedings{danvy-nielsen-ppdp-01, + author = "Olivier Danvy and Lasse R. Nielsen", + title = "Defunctionalization at Work", + pages = "162--174", + booktitle = ppdp, + year = "2001", + URL = "http://doi.acm.org/10.1145/773184.773202", +} + +@Article{danvy-pearl-98, + author = "Olivier Danvy", + title = "Functional Unparsing", + journal = jfp, + year = "1998", + volume = "8", + number = "6", + pages = "621--625", + URL = "http://dx.doi.org/10.1017/S0956796898003104", +} + +@PhdThesis{dao-00, + author = "Thi Bich Hanh Dao", + title = "{R}ésolution de contraintes du premier ordre dans la + théorie des arbres finis ou infinis", + school = "Université de la Méditerranée", + year = "2000", + URL = "http://www.univ-orleans.fr/SCIENCES/LIFO/Members/dao/papers/ts4dec.ps.gz", +} + +@InProceedings{dargaye-leroy-cps-07, + author = "Zaynah Dargaye and Xavier Leroy", + title = "Mechanized verification of {CPS} transformations", + booktitle = lpar, + year = "2007", + series = lnai, + volume = "4790", + publisher = springer, + pages = "211--225", + URL = "http://gallium.inria.fr/~xleroy/publi/cps-dargaye-leroy.pdf", +} + +@TechReport{davies-05, + author = "Rowan Davies", + title = "Practical Refinement-Type Checking", + institution = "School of Computer Science, Carnegie Mellon + University", + year = "2005", + number = "CMU-CS-05-110", + URL = "http://reports-archive.adm.cs.cmu.edu/anon/2005/CMU-CS-05-110.pdf", +} + +@InProceedings{davies-pfenning-00, + author = "Rowan Davies and Frank Pfenning", + title = "Intersection types and computational effects", + booktitle = icfp, + year = "2000", + pages = "198--208", + URL = "http://www.cs.cmu.edu/~fp/papers/icfp00.pdf", +} + +@Article{davis-logemann-loveland-62, + author = "Martin Davis and George Logemann and Donald Loveland", + title = "A machine program for theorem-proving", + journal = cacm, + volume = "5", + number = "7", + year = "1962", + pages = "394--397", + URL = "http://doi.acm.org/10.1145/368273.368557", +} + +@Article{davis-putnam-60, + author = "Martin Davis and Hilary Putnam", + title = "A Computing Procedure for Quantification Theory", + journal = jacm, + volume = "7", + number = "3", + year = "1960", + pages = "201--215", + URL = "http://doi.acm.org/10.1145/321033.321034", +} + +@Article{de-bruijn-72, + author = "Nicolaas G. de Bruijn", + title = "Lambda-Calculus Notation with Nameless Dummies: a Tool + for Automatic Formula Manipulation with Application to + the {Church-Rosser} Theorem", + journal = "Indag. Math.", + volume = "34", + number = "5", + year = "1972", + pages = "381--392", +} + +@InProceedings{delaware-3mt-13, + author = "Benjamin Delaware and Steven Keuchel and Tom + Schrijvers and Bruno C. d. S. Oliveira", + title = "Modular monadic meta-theory", + booktitle = icfp, + year = "2013", + pages = "319--330", + URL = "http://ropas.snu.ac.kr/~bruno/papers/3MT.pdf", +} + +@InProceedings{delaware-mtc-13, + author = "Benjamin Delaware and Bruno C. d. S. Oliveira and Tom + Schrijvers", + title = "Meta-theory à La Carte", + booktitle = popl, + year = "2013", + pages = "207--218", + URL = "http://people.csail.mit.edu/bendy/MTC/MTC.pdf", +} + +@InProceedings{delbianco-nanevski-13, + author = "Germ{\'{a}}n Andr{\'{e}}s Delbianco and Aleksandar + Nanevski", + title = "{Hoare}-style reasoning with (algebraic) + continuations", + booktitle = icfp, + pages = "363--376", + year = "2013", + URL = "http://software.imdea.org/~aleks/papers/callcc/icfp2013.pdf", +} + +@InProceedings{deline-faehndrich-01, + author = "Robert DeLine and Manuel Fähndrich", + title = "Enforcing High-Level Protocols in Low-Level Software", + booktitle = pldi, + pages = "59--69", + year = "2001", + URL = "http://research.microsoft.com/apps/pubs/default.aspx?id=67457", +} + +@InProceedings{deline-faehndrich-04, + author = "Robert DeLine and Manuel Fähndrich", + title = "Typestates for objects", + booktitle = ecoop, + pages = "465--490", + year = "2004", + volume = "3086", + series = lncs, + publisher = springer, + URL = "http://research.microsoft.com/apps/pubs/default.aspx?id=67463", +} + +@TechReport{deline-faehndrich-fugue-04, + author = "Robert DeLine and Manuel Fähndrich", + title = "The {Fugue} Protocol Checker: Is Your Software + Baroque?", + institution = "Microsoft Research", + year = "2004", + number = "MSR-TR-2004-07", + URL = "http://research.microsoft.com/apps/pubs/default.aspx?id=67458", +} + +@InProceedings{delphin-08, + author = "Adam Poswolsky and Carsten Schürmann", + title = "Practical Programming with Higher-Order Encodings and + Dependent Types", + booktitle = esop, + pages = "93--107", + year = "2008", + volume = "4960", + series = lncs, + publisher = springer, + URL = "http://cs-www.cs.yale.edu/homes/delphin/files/delphinESOP08.pdf", +} + +@Article{delphin-09, + author = "Adam Poswolsky and Carsten Schürmann", + title = "System Description: {Delphin} -- {A} Functional + Programming Language for Deductive Systems", + journal = entcs, + volume = "228", + year = "2009", + pages = "113--120", + URL = "http://www.itu.dk/~carsten/papers/lfmtp-08.pdf", +} + +@Article{dencker-84, + author = "Peter Dencker and Karl Dürre and Johannes Heuft", + title = "Optimization of parser tables for portable compilers", + journal = toplas, + volume = "6", + number = "4", + year = "1984", + pages = "546--572", + URL = "http://doi.acm.org/10.1145/1780.1802", +} + +@Article{denning-77, + author = "Dorothy E. Denning and Peter J. Denning", + title = "Certification of Programs for Secure Information + Flow", + journal = cacm, + volume = "20", + number = "7", + pages = "504--513", + year = "1977", +} + +@Book{denning-82, + author = "Dorothy E. Denning", + title = "Cryptography and Data Security", + publisher = aw, + year = "1982", +} + +@InProceedings{dennis-sat-06, + author = "Greg Dennis and Felix Change and Daniel Jackson", + title = "Modular Verification of Code with {SAT}", + booktitle = issta, + year = "2006", + URL = "http://sdg.csail.mit.edu/pubs/2006/dennis_modular.pdf", +} + +@Article{denny-malloy-10, + author = "Joel E. Denny and Brian A. Malloy", + title = "The {IELR(1)} algorithm for generating minimal {LR(1)} + parser tables for non-{LR(1)} grammars with conflict + resolution", + journal = scp, + volume = "75", + number = "11", + pages = "943--979", + year = "2010", + URL = "http://dx.doi.org/10.1016/j.scico.2009.08.001", +} + +@Article{deremer-pennello-82, + author = "Frank DeRemer and Thomas Pennello", + title = "Efficient Computation of ${LALR}(1)$ Look-Ahead Sets", + journal = toplas, + volume = "4", + number = "4", + year = "1982", + pages = "615--649", + URL = "http://doi.acm.org/10.1145/69622.357187", +} + +@TechReport{deremer-phd-69, + author = "Franklin Lewis DeRemer", + title = "Practical Translators for {LR(k)} Languages", + institution = "Massachusetts Institute of Technology", + year = "1969", + type = "Technical Report", + number = "MIT-LCS-TR-065", + URL = "http://publications.csail.mit.edu/lcs/pubs/pdf/MIT-LCS-TR-065.pdf", +} + +@Article{deremer-slr-71, + author = "Franklin L. DeRemer", + title = "Simple ${LR}(k)$ grammars", + journal = cacm, + year = "1971", + volume = "14", + number = "7", + pages = "453--460", + URL = "http://dx.doi.org/10.1145/362619.362625", +} + +@Book{design-patterns, + author = "Erich Gamma and Richard Helm and Ralph Johnson and + John Vlissides", + title = "Design Patterns: Elements of Reusable Object-oriented + Software", + year = "1995", + publisher = aw, +} + +@TechReport{detlefs-98, + author = "David L. Detlefs and K. Rustan M. Leino and Greg + Nelson and James B. Saxe", + title = "Extended static checking", + institution = "Compaq SRC", + year = "1998", + type = "Research Report", + number = "159", + URL = "ftp://gatekeeper.research.compaq.com/pub/DEC/SRC/research-reports/SRC-159.pdf", +} + +@TechReport{detlefs-wrestling-98, + author = "David L. Detlefs and K. Rustan M. Leino and Greg + Nelson", + title = "Wrestling with rep exposure", + institution = "SRC", + year = "1998", + type = "Research Report", + number = "156", + URL = "http://www.hpl.hp.com/techreports/Compaq-DEC/SRC-RR-156.pdf", +} + +@Book{dicosmo-95, + author = "Roberto {Di Cosmo}", + title = "Isomorphisms of types: from $\lambda$-calculus to + information retrieval and language design", + series = "Progress in Theoretical Computer Science", + publisher = "Birkhauser", + year = "1995", + URL = "http://www.pps.jussieu.fr/~dicosmo/Publications/ISObook.html", +} + +@Article{dicosmo-jfp-93, + author = "Roberto {Di Cosmo}", + title = "Deciding Type isomorphisms in a type assignment + framework", + journal = jfp, + year = "1993", + volume = "3", + number = "3", + pages = "485--525", + URL = "http://www.dicosmo.org/Articles/JFP94.dvi", +} + +@Article{dietl-drossopoulou-mueller-11, + author = "Werner Dietl and Sophia Drossopoulou and Peter + M{\"u}ller", + title = "Separating ownership topology and encapsulation with + generic universe types", + journal = toplas, + volume = "33", + number = "6", + year = "2011", + pages = "20", + URL = "http://pm.inf.ethz.ch/publications/getpdf.php?bibname=Own&id=DietlDrossopoulouMueller11.pdf", +} + +@Article{dietl-mueller-05, + author = "Werner Dietl and Peter M{\"u}ller", + title = "Universes: Lightweight Ownership for {JML}", + journal = jot, + year = "2005", + volume = "4", + number = "8", + pages = "5--32", + URL = "http://www.jot.fm/issues/issue_2005_10/article1.pdf", +} + +@Article{dijkstra-59, + author = "E. W. Dijkstra", + title = "A Note on Two Problems in Connection with Graphs", + journal = "Numerische Mathematik", + year = "1959", + volume = "1", + pages = "269--271", +} + +@Article{dijkstra-75, + author = "Edsger W. Dijkstra", + title = "Guarded commands, nondeterminacy and formal derivation + of programs", + journal = "Communications of the ACM", + volume = "18", + number = "8", + year = "1975", + pages = "453--457", + URL = "http://doi.acm.org/10.1145/360933.360975", +} + +@PhdThesis{dimock-02, + author = "Allyn Dimock", + title = "Type- and Flow-Directed Compilation for Specialized + Data Representations", + school = "Harvard University", + year = "2002", + URL = "http://www.cs.uml.edu/~dimock/thesis.ps.gz", +} + +@InProceedings{dimock-al-01, + author = "Allyn Dimock and Ian Westmacott and Robert Muller and + Franklyn Turbak and J. B. Wells", + title = "Functioning without closure: type-safe customized + function representations for {Standard ML}", + booktitle = icfp, + year = "2001", + URL = "http://puma.wellesley.edu/~fturbak/pubs/icfp01.ps", +} + +@InProceedings{dinsdale-young-views-13, + author = "Thomas Dinsdale-Young and Lars Birkedal and Philippa + Gardner and Matthew J. Parkinson and Hongseok Yang", + title = "Views: compositional reasoning for concurrent + programs", + booktitle = popl, + year = "2013", + pages = "287--300", + URL = "http://cs.au.dk/~birke/papers/views.pdf", +} + +@InProceedings{dinsdaleyoung-cap-10, + author = "Thomas Dinsdale-Young and Mike Dodds and Philippa + Gardner and Matthew J. Parkinson and Viktor Vafeiadis", + booktitle = ecoop, + publisher = springer, + title = "Concurrent Abstract Predicates", + series = lncs, + volume = "6183", + year = "2010", + pages = "504--528", + URL = "http://www.cl.cam.ac.uk/~md466/publications/ECOOP.10.concurrent_abstract_predicates.pdf", +} + +@TechReport{dinsdaleyoung-cap-tr-10, + author = "Thomas Dinsdale-Young and Mike Dodds and Philippa + Gardner and Matthew Parkinson and Viktor Vafeiadis", + title = "Concurrent Abstract Predicates", + institution = "University of Cambridge, Computer Laboratory", + year = "2010", + URL = "http://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-777.pdf", +} + +@InProceedings{distefano-parkinson-08, + author = "Dino Distefano and Matthew J. Parkinson", + title = "{jStar}: towards practical verification for {Java}", + booktitle = oopsla, + year = "2008", + pages = "213--226", + URL = "http://www.eecs.qmul.ac.uk/~ddino/papers/oopsla2008.pdf", +} + +@InProceedings{dockins-algebras-09, + author = "Robert Dockins and Aquinas Hobor and Andrew W. Appel", + title = "A Fresh Look at Separation Algebras and Share + Accounting", + booktitle = aplas, + year = "2009", + pages = "161--177", + publisher = springer, + series = lncs, + volume = "5904", + URL = "http://www.cs.princeton.edu/~appel/papers/fresh-sa.pdf", +} + +@InProceedings{dodds-11, + author = "Mike Dodds and Suresh Jagannathan and Matthew J. + Parkinson", + title = "Modular reasoning for deterministic parallelism", + booktitle = popl, + year = "2011", + pages = "259--270", + URL = "http://www.cl.cam.ac.uk/~md466/publications/POPL.11.deterministic_parallelism.pdf", +} + +@InProceedings{dodds-deny-guarantee-09, + author = "Mike Dodds and Xinyu Feng and Matthew J. Parkinson and + Viktor Vafeiadis", + title = "Deny-Guarantee Reasoning", + booktitle = esop, + year = "2009", + pages = "363--377", + publisher = springer, + series = lncs, + volume = "5502", + URL = "http://ttic.uchicago.edu/~feng/research/publications/DG.pdf", +} + +@Article{dodds-sync-16, + author = "Mike Dodds and Suresh Jagannathan and Matthew J. + Parkinson and Kasper Svendsen and Lars Birkedal", + title = "Verifying custom synchronization constructs using + higher-order separation logic", + journal = toplas, + year = "2016", + volume = "28", + number = "2", + URL = "http://dx.doi.org/10.1145/2818638", +} + +@InProceedings{donnelly-xi-05, + author = "Kevin Donnelly and Hongwei Xi", + title = "Combining higher-order abstract syntax with + first-order abstract syntax in {ATS}", + booktitle = merlin, + year = "2005", + pages = "58--63", + URL = "http://www.cs.bu.edu/~hwxi/academic/papers/merlin05.pdf", +} + +@Article{dornic-jouvelot-gifford-92, + author = "Vincent Dornic and Pierre Jouvelot and David K. + Gifford", + title = "Polymorphic time systems for estimating program + complexity", + journal = loplas, + volume = "1", + number = "1", + year = "1992", + pages = "33--45", + URL = "http://ropas.snu.ac.kr/lib/dock/DoJoGi1992.pdf", +} + +@InCollection{dowek-01, + author = "Gilles Dowek", + title = "Higher-order unification and matching", + booktitle = "Handbook of Automated Reasoning", + pages = "1009--1062", + publisher = elsevier, + year = "2001", + editor = "J. Alan Robinson and Andrei Voronkov", + URL = "http://www.lix.polytechnique.fr/~dowek/Publi/unification.ps", +} + +@TechReport{dowek-al-95, + author = "Gilles Dowek and Thérèse Hardin and Claude + Kirchner", + title = "Higher Order Unification via Explicit Substitutions", + institution = "INRIA", + number = "2709", + year = "1995", + pages = "42", + type = "Research Report", + URL = "http://www.inria.fr/rrrt/rr-2709.html", +} + +@TechReport{dowek-al-98, + author = "Gilles Dowek and Thérèse Hardin and Claude Kirchner + and Frank Pfenning", + title = "Unification via Explicit Substitutions: the Case of + Higher-Order Patterns", + institution = "INRIA", + number = "3591", + year = "1998", + pages = "33", + type = "Research Report", + URL = "http://www.inria.fr/rrrt/rr-3591.html", +} + +@Article{dowling-gallier-84, + author = "William F. Dowling and Jean H. Gallier", + title = "Linear-Time Algorithms for Testing the Satisfiability + of Propositional {Horn} Formulae", + journal = jlp, + volume = "1", + number = "3", + year = "1984", + pages = "267--284", +} + +@Article{downey-sethi-tarjan-80, + author = "Peter J. Downey and Ravi Sethi and Robert Endre + Tarjan", + title = "Variations on the Common Subexpression Problem", + journal = jacm, + year = "1980", + volume = "27", + number = "4", + pages = "758--771", + URL = "http://doi.acm.org/10.1145/322217.322228", +} + +@InProceedings{dreyer-neis-birkedal-10, + author = "Derek Dreyer and Georg Neis and Lars Birkedal", + title = "The impact of higher-order state and control effects + on local relational reasoning", + booktitle = icfp, + pages = "143--156", + year = "2010", + URL = "https://www.mpi-sws.org/~dreyer/papers/stslr/icfp.pdf", +} + +@InProceedings{dubois-menissier-97, + author = "Catherine Dubois and Valérie Ménissier-Morain", + title = "Typage de {ML}: Spécification et preuve en {Coq}", + booktitle = "Actes du GDR Programmation", + year = "1997", + URL = "http://www.irisa.fr/lande/ridoux/GDR_annexe/dubois.ps.gz", +} + +@Article{dubois-menissier-99, + author = "Catherine Dubois and Valérie Ménissier-Morain", + title = "Certification of a Type Inference Tool for {ML}: + {Damas-Milner} within {Coq}", + journal = jar, + year = "1999", + volume = "23", + number = "3--4", + pages = "319--346", + URL = "http://www.ensiie.fr/~dubois/jar_final.pdf", +} + +@Article{duggan-bent-96, + author = "Dominic Duggan and Frederick Bent", + title = "Explaining type inference", + journal = scp, + year = "1996", + volume = "27", + number = "1", +} + +@InProceedings{dussart-henglein-mossin-95, + author = "Dirk Dussart and Fritz Henglein and Christian Mossin", + year = "1995", + title = "Polymorphic Recursion and Subtype Qualifications: + Polymorphic Binding-Time Analysis in Polynomial Time", + booktitle = sas, + publisher = springer, + series = lncs, + volume = "983", + pages = "118--135", + URL = "ftp://ftp.diku.dk/diku/semantics/papers/D-243.dvi.gz", +} + +@Article{dybvig-93, + author = "Kent Dybvig and Robert Hieb and Carl Bruggeman", + title = "Syntactic abstraction in {Scheme}", + journal = lsc, + year = "1993", + volume = "5", + number = "4", + pages = "295--326", + URL = "http://www.cs.indiana.edu/~dyb/pubs/LaSC-5-4-pp295-326.pdf", +} + +@Article{eberl-17, + author = "Manuel Eberl", + title = "Proving Divide and Conquer Complexities in + {Isabelle/HOL}", + journal = jar, + volume = "58", + number = "4", + pages = "483--508", + year = "2017", + URL = "https://www21.in.tum.de/~eberlm/divide_and_conquer_isabelle.pdf", +} + +@InProceedings{eifrig-smith-trifonov-94, + author = "Jonathan Eifrig and Scott Smith and Valery Trifonov", + title = "Type Inference for Recursively Constrained Types and + its Application to {OOP}", + booktitle = mfps, + series = entcs, + publisher = elsevier, + volume = "1", + year = "1995", + URL = "http://www.cs.jhu.edu/~scott/ftp/ooinfer.ps.gz", +} + +@Article{eifrig-smith-trifonov-95, + author = "Jonathan Eifrig and Scott Smith and Valery Trifonov", + title = "Sound polymorphic type inference for objects", + journal = notices, + volume = "30", + number = "10", + year = "1995", + pages = "169--184", + URL = "http://www.cs.jhu.edu/~scott/ftp/sptio.ps.gz", +} + +@TechReport{elphin-04, + author = "Carsten Schürmann and Adam Poswolsky and Jeffrey + Sarnat", + title = "The $\nabla$-Calculus: Functional programming with + higher-order encodings", + institution = "Yale University", + number = "YALEU/DCS/TR-1272", + year = "2004", + URL = "http://www.cs.yale.edu/~delphin/files/nablaTR.pdf", +} + +@InProceedings{elphin-05, + author = "Carsten Schürmann and Adam Poswolsky and Jeffrey + Sarnat", + title = "The $\nabla$-Calculus: Functional programming with + higher-order encodings", + booktitle = tlca, + pages = "339--353", + year = "2005", + volume = "3461", + series = lncs, + publisher = springer, + URL = "http://www.itu.dk/~carsten/papers/nabla.pdf", +} + +@InProceedings{emerson-lei-86, + author = "E. Allen Emerson and Chin-Laung Lei", + title = "Efficient Model Checking in Fragments of the + Propositional Mu-Calculus", + booktitle = lics, + year = "1986", + pages = "267--278", +} + +@TechReport{emms-leiss-96, + author = "Martin Emms and Hans Lei{\ss}", + title = "Extending the Type Checker for {SML} by Polymorphic + Recursion --- {A} Correctness Proof", + institution = "Centrum f{\"{u}}r Informations- und + Sprachverarbeitung, Universit{\"{a}}t M{\"{u}}nchen", + year = "1996", + number = "96-101", + URL = "http://www.cis.uni-muenchen.de/~leiss/polyrec/polyrec.cisbericht.96-101.ps.gz", +} + +@Book{eopl, + author = "Daniel P. Friedman and Mitchell Wand", + title = "Essentials of Programming Languages, 3rd Edition", + publisher = mitp, + year = "2008", + URL = "http://www.eopl3.com/", +} + +@Unpublished{epigram-05, + author = "Thorsten Altenkirch and Conor McBride and James + McKinna", + title = "Why Dependent Types Matter", + note = "Unpublished", + year = "2005", + URL = "http://www.e-pig.org/downloads/ydtm.pdf", +} + +@Misc{ergo, + author = "Sylvain Conchon and Evelyne Contejean", + title = "The {Alt-Ergo} Automatic Theorem Prover", + note = "\url{http://alt-ergo.lri.fr/}", + year = "2011", + URL = "http://alt-ergo.lri.fr/", +} + +@InProceedings{erlingsson-schneider-00, + author = "{\'U}lfar Erlingsson and Fred B. Schneider", + title = "{IRM} Enforcement of {Java} Stack Inspection", + booktitle = sp, + year = "2000", + pages = "246--255", + URL = "http://csdl.computer.org/comp/proceedings/sp/2000/0665/00/06650246abs.htm", +} + +@InProceedings{erlingsson-schneider-99, + author = "{\'U}lfar Erlingsson and Fred B. Schneider", + title = "{SASI} Enforcement of Security Policies: a + Retrospective", + booktitle = nspw, + pages = "87--95", + year = "1999", + URL = "http://www.cs.cornell.edu/fbs/publications/sasiNSPW.ps", +} + +@InProceedings{esparza-13, + author = "Javier Esparza and Peter Lammich and Ren{\'e} Neumann + and Tobias Nipkow and Alexander Schimpf and Jan-Georg + Smaus", + title = "A Fully Verified Executable {LTL} Model Checker", + booktitle = cav, + pages = "463--478", + year = "2013", + series = lncs, + volume = "8044", + publisher = springer, + URL = "https://www21.in.tum.de/~nipkow/pubs/cav13.pdf", +} + +@InProceedings{esparza-efficient-00, + author = "Javier Esparza and David Hansel and Peter Rossmanith + and Stefan Schwoon", + title = "Efficient Algorithms for Model Checking Pushdown + Systems", + booktitle = cav, + pages = "232--247", + year = "2000", + series = lncs, + volume = "1855", + publisher = springer, + URL = "https://www7.in.tum.de/um/bibdb/esparza/cav00.pdf", +} + +@Misc{f7, + author = "Karthik Bhargavan and Cédric Fournet and Andy Gordon + and Sergio Maffeis and Jesper Bengtson", + title = "The {F7} Typechecker", + note = "\url{http://research.microsoft.com/en-us/projects/f7/}", + year = "2011", + URL = "http://research.microsoft.com/en-us/projects/f7/", +} + +@Misc{facebook-infer, + author = "Cristiano Calcagno and Dino Distefano and Peter + O'Hearn", + title = "Open-sourcing {Facebook Infer}: Identify bugs before + you ship", + howpublished = "\url{https://code.facebook.com/posts/1648953042007882/open-sourcing-facebook-infer-identify-bugs-before-you-ship/}", + year = "2015", +} + +@InProceedings{faehndrich-al-00, + author = "Manuel Fähndrich and Jakob Rehof and Manuvir Das", + title = "Scalable Context-Sensitive Flow Analysis Using + Instantiation Constraints", + booktitle = pldi, + year = "2000", + URL = "http://research.microsoft.com/pubs/67468/pldi00.ps", +} + +@InProceedings{faehndrich-cycles-98, + author = "Manuel Fähndrich and Jeffrey S. Foster and Zhendong + Su and Alexander S. Aiken", + title = "Partial Online Cycle Elimination in Inclusion + Constraint Graphs", + booktitle = pldi, + year = "1998", + pages = "85--96", + URL = "http://research.microsoft.com/pubs/67475/pldi98.pdf", +} + +@InProceedings{faehndrich-deline-02, + author = "Manuel Fähndrich and Robert DeLine", + title = "Adoption and focus: practical linear types for + imperative programming", + booktitle = pldi, + year = "2002", + pages = "13--24", + URL = "http://research.microsoft.com/pubs/67459/pldi02.pdf", +} + +@InProceedings{faehndrich-leino-03, + author = "Manuel Fähndrich and Rustan Leino", + title = "Heap Monotonic Typestates", + booktitle = "International Workshop on Alias Confinement and + Ownership (IWACO)", + year = "2003", + URL = "http://research.microsoft.com/en-us/um/people/leino/papers/krml123.pdf", +} + +@PhdThesis{faehndrich-phd-99, + school = "University of California at Berkeley", + title = "Bane: {A} Library for Scalable Constraint-Based + Program Analysis", + year = "1999", + author = "Manuel Fähndrich", + URL = "http://research.microsoft.com/pubs/67479/thesis-compact.pdf", +} + +@InProceedings{faehndrich-singularity-06, + author = "Manuel Fähndrich and Mark Aiken and Chris Hawblitzel + and Orion Hodson and Galen Hunt and James R. Larus and + Steven Levi", + title = "Language support for fast and reliable message-based + communication in {Singularity OS}", + booktitle = eurosys, + year = "2006", + pages = "177--190", + URL = "http://www.cs.kuleuven.ac.be/conference/EuroSys2006/papers/p177-fahndrich.pdf", +} + +@Unpublished{fan, + author = "Hongbo Zhang and Steve Zdancewic", + title = "{Fan}: compile-time metaprogramming for {OCaml}", + note = "Unpublished", + year = "2013", + URL = "http://zhanghongbo.me/fan/_downloads/metaprogramming_for_ocaml.pdf", +} + +@Article{faxen-02, + author = "Karl-Filip Fax\'{e}n", + title = "A Static Semantics for {Haskell}", + pages = "295--357", + year = "2002", + journal = jfp, + volume = "12", + number = "4--5", + URL = "http://www.it.kth.se/~kff/semantics.ps.gz", +} + +@Article{fecht-seidl-99, + author = "Christian Fecht and Helmut Seidl", + title = "A Faster Solver for General Systems of Equations", + journal = scp, + year = "1999", + volume = "35", + number = "2--3", + pages = "137--162", + URL = "http://www2.in.tum.de/~seidl/papers/final-solver.ps.gz", +} + +@InProceedings{felleisen-flanagan-componential-97, + author = "Cormac Flanagan and Matthias Felleisen", + title = "Componential Set-Based Analysis", + booktitle = pldi, + year = "1997", + pages = "235--248", + URL = "http://www.cs.rice.edu/CS/PLT/Publications/Scheme/pldi97-ff.ps.gz", +} + +@TechReport{felleisen-flanagan-theory-practice-96, + number = "TR96-266", + institution = "Rice University", + title = "Modular and Polymorphic Set-Based Analysis: Theory and + Practice", + year = "1996", + pages = "48", + author = "Cormac Flanagan and Matthias Felleisen", + URL = "http://www.cs.rice.edu/CS/PLT/Publications/Scheme/tr96-266.ps.gz", +} + +@PhdThesis{fenton-73, + school = "University of Cambridge", + title = "Information Protection Systems", + year = "1973", + author = "J. S. Fenton", +} + +@Article{fenton-74, + author = "J. S. Fenton", + title = "Memoryless Subsystems", + journal = cj, + volume = "17", + number = "2", + pages = "143--147", + year = "1974", +} + +@InProceedings{ferreira-pientka-17, + author = "Francisco Ferreira and Brigitte Pientka", + title = "Programs Using Syntax with First-Class Binders", + booktitle = esop, + year = "2017", + series = lncs, + volume = "10201", + publisher = springer, + URL = "http://www.cs.mcgill.ca/~bpientka/papers/esop17_ferreira.pdf", +} + +@Article{fftw-05, + author = "Matteo Frigo and Steven G. Johnson", + title = "The Design and Implementation of {FFTW3}", + journal = pieee, + year = "2005", + volume = "93", + number = "2", + pages = "216--231", + URL = "http://www.fftw.org/fftw-paper-ieee.pdf", +} + +@InProceedings{field-teitelbaum-90, + author = "John Field and Tim Teitelbaum", + title = "Incremental Reduction in the Lambda Calculus", + booktitle = lfp, + year = "1990", + pages = "307--322", +} + +@InProceedings{filinski-99, + author = "Andrzej Filinski", + title = "Representing Layered Monads", + booktitle = popl, + year = "1999", + pages = "175--188", + URL = "http://www.diku.dk/~andrzej/papers/RLM.ps.gz", +} + +@Article{filliatre-00, + author = "Jean-Christophe Filliâtre", + title = "Verification of Non-Functional Programs using + Interpretations in Type Theory", + journal = jfp, + volume = "13", + number = "4", + pages = "709--745", + year = "2003", + URL = "http://www.lri.fr/~filliatr/ftp/publis/jphd.ps.gz", +} + +@InProceedings{filliatre-06, + author = "Jean-Christophe Filli\^atre", + title = "Backtracking iterators", + booktitle = ml, + year = "2006", + pages = "55--62", + URL = "http://www.lri.fr/~filliatr/publis/enum2.ps.gz", +} + +@InProceedings{filliatre-conchon-06, + author = "Jean-Christophe Filli{\^a}tre and Sylvain Conchon", + title = "Type-safe modular hash-consing", + booktitle = ml, + pages = "12--19", + year = "2006", + URL = "https://www.lri.fr/~filliatr/ftp/publis/hash-consing2.pdf", +} + +@Article{filliatre-find-06, + author = "Jean-Christophe Filliâtre", + title = "Formal Proof of a Program: {Find}", + journal = scp, + year = "2006", + volume = "64", + pages = "332--240", + URL = "http://www.lri.fr/~filliatr/ftp/publis/find.ps.gz", +} + +@InProceedings{filliatre-ghost-14, + author = "Jean{-}Christophe Filli{\^{a}}tre and L{\'{e}}on + Gondelman and Andrei Paskevich", + title = "The Spirit of Ghost Code", + booktitle = cav, + pages = "1--16", + year = "2014", + series = lncs, + volume = "8559", + publisher = springer, + URL = "https://hal.archives-ouvertes.fr/hal-00873187/PDF/main.pdf", +} + +@InProceedings{filliatre-letouzey-04, + author = "Jean-Christophe Filliâtre and Pierre Letouzey", + title = "Functors for Proofs and Programs", + booktitle = esop, + pages = "370--384", + year = "2004", + volume = "2986", + series = lncs, + publisher = springer, + URL = "http://www.lri.fr/~filliatr/ftp/publis/fpp.ps.gz", +} + +@InProceedings{filliatre-marche-04, + author = "Jean-Christophe Filliâtre and Claude Marché", + title = "Multi-Prover Verification of {C} Programs", + booktitle = icfem, + year = "2004", + publisher = springer, + series = lncs, + volume = "3308", + pages = "15--29", + URL = "http://www.lri.fr/~filliatr/ftp/publis/caduceus.ps.gz", +} + +@InProceedings{filliatre-pereira-16, + author = "Jean{-}Christophe Filli{\^{a}}tre and M{\'{a}}rio + Pereira", + title = "A Modular Way to Reason About Iteration", + booktitle = nfm, + pages = "322--336", + year = "2016", + series = lncs, + volume = "9690", + publisher = springer, + URL = "https://hal.inria.fr/hal-01281759", +} + +@InProceedings{findler-felleisen-02, + author = "Robert Bruce Findler and Matthias Felleisen", + title = "Contracts for higher-order functions", + booktitle = icfp, + year = "2002", + pages = "48--59", + URL = "http://people.cs.uchicago.edu/~robby/pubs/papers/ho-contracts-icfp2002.pdf", +} + +@Article{fischbach-hannan-02, + author = "Adam Fischbach and John Hannan", + title = "Specification and Correctness of Lambda Lifting", + journal = jfp, + year = "2003", + volume = "13", + number = "3", + pages = "509--543", + URL = "http://dx.doi.org/10.1017/S0956796802004604", +} + +@Article{fisher-mitchell-98, + author = "Kathleen Fisher and John C. Mitchell", + title = "On the Relationship between Classes, Objects and Data + Abstraction", + journal = tapos, + year = "1998", + volume = "4", + number = "1", + pages = "3--25", + URL = "http://www.research.att.com/~kfisher/files/tapos98.ps", +} + +@InProceedings{flanagan-abadi-99, + author = "Cormac Flanagan and Mart\'{\i}n Abadi", + title = "Types for Safe Locking", + booktitle = esop, + year = "1999", + pages = "91--108", + publisher = springer, + series = lncs, + volume = "1576", + URL = "http://users.soe.ucsc.edu/~cormac/papers/esop99.pdf", +} + +@InProceedings{flanagan-al-93, + author = "Cormac Flanagan and Amr Sabry and Bruce F. Duba and + Matthias Felleisen", + title = "The Essence of Compiling with Continuations", + booktitle = pldi, + year = "1993", + pages = "237--247", + URL = "http://www.cs.rice.edu/CS/PLT/Publications/Scheme/pldi93-fsdf.ps.gz", +} + +@InProceedings{flanagan-al-96, + author = "Cormac Flanagan and Matthew Flatt and Shriram + Krishnamurthi and Stephanie Weirich and Matthias + Felleisen", + year = "1996", + booktitle = pldi, + title = "Catching Bugs in the Web of Program Invariants", + URL = "http://www.cs.rice.edu/CS/PLT/Publications/Scheme/pldi96-ffkwf.ps.gz", +} + +@PhdThesis{flanagan-effective-97, + school = "Rice University", + title = "Effective Static Debugging via Componential Set-Based + Analysis", + year = "1997", + pages = "164", + author = "Cormac Flanagan", + URL = "http://www.cs.rice.edu/CS/PLT/Publications/Scheme/thesis-flanagan.ps.gz", +} + +@InProceedings{flanagan-esc-02, + author = "Cormac Flanagan and K. Rustan M. Leino and Mark + Lillibridge and Greg Nelson and James B. Saxe and + Raymie Stata", + title = "Extended Static Checking for {Java}", + booktitle = pldi, + pages = "234--245", + year = "2002", + URL = "http://www.soe.ucsc.edu/~cormac/papers/pldi02.ps", +} + +@InProceedings{flanagan-saxe-01, + author = "Cormac Flanagan and James B. Saxe", + title = "Avoiding exponential explosion: generating compact + verification conditions", + booktitle = popl, + year = "2001", + pages = "193--205", + URL = "http://www.soe.ucsc.edu/~cormac/papers/popl01.ps", +} + +@InProceedings{floyd-67, + author = "R. W. Floyd", + title = "Assigning meanings to programs", + booktitle = "Mathematical Aspects of Computer Science", + series = "Proceedings of Symposia in Applied Mathematics", + volume = "19", + year = "1967", + organization = ams, + pages = "19--32", + URL = "https://people.eecs.berkeley.edu/~necula/Papers/FloydMeaning.pdf", +} + +@InProceedings{fluet-02, + author = "Matthew Fluet and Riccardo Pucella", + title = "Phantom types and subtyping", + booktitle = tcsconf, + pages = "448--460", + year = "2002", + URL = "http://arXiv.org/abs/cs.PL/0403034", +} + +@InProceedings{fluet-al-06, + author = "Matthew Fluet and Greg Morrisett and Amal Ahmed", + title = "Linear Regions Are All You Need", + booktitle = esop, + pages = "7--21", + year = "2006", + volume = "3924", + series = lncs, + publisher = springer, + URL = "http://ttic.uchicago.edu/~fluet/research/substruct-regions/ESOP06/esop06.pdf", +} + +@PhdThesis{fluet-phd-07, + author = "Matthew Fluet", + title = "Monadic and Substructural Type Systems for + Region-Based Memory Management", + school = "Cornell University", + year = "2007", + URL = "http://ttic.uchicago.edu/~fluet/research/thesis/fluet-thesis.single.pdf", +} + +@InProceedings{fluet-pucella-02, + author = "Matthew Fluet and Riccardo Pucella", + title = "Phantom Types and Subtyping", + booktitle = ifiptcs, + pages = "448--460", + year = "2002", + volume = "223", + series = "IFIP Conference Proceedings", + publisher = kluwer, + URL = "http://www.cs.cornell.edu/people/fluet/phantom-subtyping/TCS02/tcs02.ps", +} + +@InProceedings{fluet-pucella-05, + author = "Matthew Fluet and Riccardo Pucella", + title = "Practical Datatype Specializations with Phantom Types + and Recursion Schemes", + booktitle = ml, + year = "2005", + series = entcs, + URL = "http://www.cs.cornell.edu/people/fluet/specializations/MLWRK05/mlwrk05.pdf", +} + +@Article{focardi-gorrieri-95, + author = "Riccardo Focardi and Roberto Gorrieri", + title = "A classification of security properties for process + algebras", + journal = "Journal of Computer Security", + volume = "3", + number = "1", + pages = "5--33", + year = "1995", + URL = "http://www.cs.unibo.it/~gorrieri/Papers/jcsfinal.ps.gz", +} + +@InProceedings{ford-02, + author = "Bryan Ford", + title = "Packrat parsing: simple, powerful, lazy, linear time", + booktitle = icfp, + year = "2002", + pages = "36--47", + URL = "http://www.brynosaurus.com/pub/lang/packrat-icfp02.pdf", +} + +@InProceedings{ford-04, + author = "Bryan Ford", + title = "Parsing expression grammars: a recognition-based + syntactic foundation", + booktitle = popl, + year = "2004", + pages = "111--122", + URL = "http://pdos.csail.mit.edu/~baford/packrat/popl04/peg-popl04.pdf", +} + +@TechReport{foster-aiken-restrict-01, + author = "Jeffrey S. Foster and Alex Aiken", + institution = "University of California, Berkeley", + title = "Checking Programmer-Specified Non-Aliasing", + year = "2001", + number = "UCB//CSD-01-1160", + URL = "http://www.cs.umd.edu/~jfoster/papers/tr01-restrict.pdf", +} + +@InProceedings{foster-flow-sensitive-qualifiers-02, + author = "Jeffrey S. Foster and Tachio Terauchi and Alex Aiken", + title = "Flow-Sensitive Type Qualifiers", + booktitle = pldi, + year = "2002", + pages = "1--12", + URL = "http://www.cs.umd.edu/~jfoster/papers/pldi02.pdf", +} + +@Article{fournet-al-join-03, + author = "Cédric Fournet and Cosimo Laneve and Luc Maranget and + Didier Rémy", + journal = jlap, + title = "Inheritance in the Join Calculus", + volume = "57", + number = "2", + pages = "23--69", + year = "2003", + URL = "http://gallium.inria.fr/~remy/work/ojoin/jojoin.pdf", +} + +@InProceedings{fournet-al-join-97, + author = "Cédric Fournet and Luc Maranget and Cosimo Laneve and + Didier Rémy", + title = "Implicit typing à la {ML} for the join-calculus", + booktitle = concur, + series = lncs, + publisher = springer, + volume = "1243", + pages = "196--212", + year = "1997", + URL = "http://gallium.inria.fr/~remy/ftp/typing-join.pdf", +} + +@InProceedings{fournet-gonthier-96, + author = "Cédric Fournet and Georges Gonthier", + title = "The Reflexive Chemical Abstract Machine and the + Join-Calculus", + booktitle = popl, + pages = "372--385", + year = "1996", + URL = "https://doi.org/10.1145/237721.237805", +} + +@InProceedings{fournet-gordon-02, + author = "Cédric Fournet and Andrew D. Gordon", + title = "Stack Inspection: Theory and Variants", + booktitle = popl, + pages = "307--318", + year = "2002", + URL = "http://research.microsoft.com/~fournet/papers/stack-inspection-theory-and-variants-popl-02.ps", +} + +@Article{fournet-gordon-03, + author = "Cédric Fournet and Andrew D. Gordon", + title = "Stack Inspection: Theory and Variants", + journal = toplas, + year = "2003", + volume = "25", + number = "3", + pages = "360--399", + URL = "http://doi.acm.org/10.1145/641909.641912", +} + +@Article{francalanza-rathke-sassone-2011, + author = "Adrian Francalanza and Julian Rathke and Vladimiro + Sassone", + title = "Permission-Based Separation Logic for Message-Passing + Concurrency", + journal = lmcs, + volume = "7", + number = "3", + year = "2011", + URL = "http://arxiv.org/abs/1106.5128", +} + +@InProceedings{fredman-saks-89, + author = "Michael Fredman and Michael Saks", + title = "The Cell Probe Complexity of Dynamic Data Structures", + pages = "345--354", + booktitle = "Annual Symposium on Theory of Computing ({STOC})", + publisher = "ACM", + year = "1989", + URL = "http://dx.doi.org/10.1145/73007.73040", +} + +@Article{fredman-tarjan-87, + author = "Michael L. Fredman and Robert Endre Tarjan", + title = "Fibonacci heaps and their uses in improved network + optimization algorithms", + journal = jacm, + volume = "34", + number = "3", + year = "1987", + pages = "596--615", + URL = "http://doi.acm.org/10.1145/28869.28874", +} + +@InProceedings{freeman-91, + author = "Tim Freeman and Frank Pfenning", + title = "Refinement types for {ML}", + booktitle = pldi, + pages = "268--277", + year = "1991", + URL = "http://www.cs.cmu.edu/~fp/papers/pldi91.pdf", +} + +@TechReport{fresh-ocaml, + author = "Mark R. Shinwell and Andrew M. Pitts", + year = "2005", + title = "{Fresh Objective Caml} user manual", + institution = "University of Cambridge", + number = "621", + URL = "http://www.cl.cam.ac.uk/TechReports/UCAM-CL-TR-621.pdf", +} + +@PhdThesis{frey-04, + author = "Alexandre Frey", + title = "Approche algébrique du typage d'un langage à la {ML} + avec objets, sous-typage et multi-méthodes", + school = "École des Mines de Paris", + year = "2004", + URL = "http://gallium.inria.fr/~remy/students/alexandre.frey.pdf", +} + +@InProceedings{frey-97, + author = "Alexandre Frey", + title = "Satisfying Subtype Inequalities in Polynomial Space", + booktitle = sas, + series = lncs, + number = "1302", + year = "1997", + pages = "265--277", + publisher = springer, + URL = "http://citeseer.ist.psu.edu/frey97satisfying.html", + alturl = "http://dx.doi.org/10.1016/S0304-3975(00)00314-5", +} + +@InProceedings{frisch-castagna-benzaken-02, + author = "Alain Frisch and Giuseppe Castagna and V{\'e}ronique + Benzaken", + title = "Semantic Subtyping", + booktitle = lics, + year = "2002", + pages = "137--146", + URL = "http://www.cduce.org/papers/lics02.ps.gz", +} + +@Article{frisch-castagna-benzaken-08, + author = "Alain Frisch and Giuseppe Castagna and V{\'e}ronique + Benzaken", + title = "Semantic subtyping: Dealing set-theoretically with + function, union, intersection, and negation types", + journal = jacm, + volume = "55", + number = "4", + year = "2008", + URL = "http://www.pps.univ-paris-diderot.fr/~gc/papers/semantic_subtyping.pdf", +} + +@InProceedings{fstar, + author = "Nikhil Swamy and Juan Chen and C{\'e}dric Fournet and + Pierre-Yves Strub and Karthik Bhargavan and Jean Yang", + title = "Secure distributed programming with value-dependent + types", + booktitle = icfp, + year = "2011", + pages = "266--278", + URL = "http://research.microsoft.com/pubs/150012/icfp-camera-ready.pdf", +} + +@InProceedings{fuh-mishra-88, + author = "You-Chin Fuh and Prateek Mishra", + title = "Type inference with subtypes", + booktitle = esop, + publisher = springer, + series = lncs, + volume = "300", + year = "1988", + pages = "94--114", + URL = "http://dx.doi.org/10.1007/3-540-19027-9_7", +} + +@InProceedings{fuh-mishra-gap-89, + author = "You-Chin Fuh and Prateek Mishra", + title = "Polymorphic Subtype Inference: Closing the + Theory-Practice Gap", + pages = "167--183", + booktitle = tapsoft, + series = lncs, + volume = "352", + publisher = springer, + year = "1989", + URL = "http://dx.doi.org/10.1007/3-540-50940-2_35", +} + +@InProceedings{furuse-03, + author = "Jun Furuse", + title = "Extensional Polymorphism by Flow Graph Dispatching", + booktitle = aplas, + publisher = springer, + series = lncs, + volume = "2895", + year = "2003", + URL = "http://gallium.inria.fr/~furuse/publications/flowgraph.ps.gz", +} + +@PhdThesis{gabbay-01, + author = "Murdoch J. Gabbay", + title = "A Theory of Inductive Definitions with + $\alpha$-Equivalence", + school = "Cambridge University", + year = "2001", + URL = "http://www.macs.hw.ac.uk/~gabbay/papers/thesis.pdf", +} + +@Unpublished{gabbay-04, + author = "Murdoch J. Gabbay", + title = "A General Mathematics of Names in Syntax", + year = "2004", + note = "Submitted for publication", + URL = "http://www.macs.hw.ac.uk/~gabbay/papers/genmns.pdf", +} + +@Article{gabbay-pitts-02, + author = "Murdoch J. Gabbay and Andrew M. Pitts", + title = "A New Approach to Abstract Syntax with Variable + Binding", + journal = fac, + year = "2002", + volume = "13", + number = "3--5", + pages = "341--363", + URL = "http://www.cl.cam.ac.uk/~amp12/papers/newaas/newaas-jv.pdf", + alturl = "http://www.springerlink.com/link.asp?id=epn028x83rqw00qv", +} + +@Article{galil-italiano-91, + author = "Zvi Galil and Giuseppe F. Italiano", + title = "Data Structures and Algorithms for Disjoint Set Union + Problems", + journal = surveys, + volume = "23", + number = "3", + pages = "319--344", + year = "1991", + URL = "http://doi.acm.org/10.1145/116873.116878", +} + +@Article{galler-fischer-64, + author = "Bernard A. Galler and Michael J. Fischer", + title = "An improved equivalence algorithm", + journal = cacm, + volume = "7", + number = "5", + pages = "301--303", + year = "1964", + URL = "http://doi.acm.org/10.1145/364099.364331", +} + +@Article{gapeyev-levin-pierce-00, + author = "Vladimir Gapeyev and Michael Levin and Benjamin + Pierce", + title = "Recursive Subtyping Revealed", + journal = jfp, + volume = "12", + number = "6", + pages = "511--548", + year = "2002", + URL = "http://dx.doi.org/10.1017/S0956796802004318", +} + +@InProceedings{gardner-ntizk-wright-14, + author = "Philippa Gardner and Gian Ntzik and Adam Wright", + title = "Local Reasoning for the {POSIX} File System", + booktitle = esop, + pages = "169--188", + year = "2014", + series = lncs, + volume = "8410", + publisher = springer, + URL = "https://www.doc.ic.ac.uk/~gn408/POSIXFS/esop2014.pdf", +} + +@Book{garey-johnson-79, + author = "Michael R. Garey and David S. Johnson", + title = "Computers and Intractability: {A} Guide to the Theory + of {NP}-Completeness", + year = "1979", + publisher = "W. H. Freeman and Company", +} + +@InProceedings{garrigue-00, + author = "Jacques Garrigue", + title = "Code reuse through polymorphic variants", + booktitle = fse, + year = "2000", + URL = "http://www.math.nagoya-u.ac.jp/~garrigue/papers/variant-reuse.ps.gz", +} + +@InProceedings{garrigue-02, + author = "Jacques Garrigue", + title = "Simple Type Inference for Structural Polymorphism", + booktitle = fool, + year = "2002", + URL = "http://www.math.nagoya-u.ac.jp/~garrigue/papers/structural-inf.ps.gz", +} + +@InProceedings{garrigue-98, + author = "Jacques Garrigue", + title = "Programming with polymorphic variants", + booktitle = ml, + year = "1998", + URL = "http://www.math.nagoya-u.ac.jp/~garrigue/papers/variants.ps.gz", +} + +@TechReport{garrigue-furuse-95, + author = "Jun P. Furuse and Jacques Garrigue", + title = "A label-selective lambda-calculus with optional + arguments and its compilation method", + institution = "Kyoto University", + year = "1995", + type = "RIMS Preprint", + number = "1041", + URL = "http://wwwfun.kurims.kyoto-u.ac.jp/~garrigue/papers/rims-1041.pdf", +} + +@InProceedings{garrigue-relax-04, + author = "Jacques Garrigue", + title = "Relaxing the Value Restriction", + booktitle = flops, + pages = "196--213", + year = "2004", + volume = "2998", + series = lncs, + publisher = springer, + URL = "http://www.math.nagoya-u.ac.jp/~garrigue/papers/morepoly-long.pdf", +} + +@Article{garrigue-remy-99, + author = "Jacques Garrigue and Didier R{\'e}my", + title = "Extending {ML} with Semi-Explicit Higher-Order + Polymorphism", + journal = ic, + year = "1999", + volume = "155", + number = "1", + pages = "134--169", + URL = "http://gallium.inria.fr/~remy/ftp/iandc.pdf", +} + +@InProceedings{garrigue-remy-gadts-13, + author = "Jacques Garrigue and Didier R{\'e}my", + title = "Ambivalent types for principal type inference with + {GADT}s", + booktitle = aplas, + year = "2013", + URL = "http://gallium.inria.fr/~remy/gadts/Garrigue-Remy:gadts@aplas2013.pdf", +} + +@PhdThesis{gaster-98, + author = "Benedict R. Gaster", + title = "Records, variants and qualified types", + school = "University of Nottingham", + year = "1998", + URL = "http://www.cs.nott.ac.uk/Research/fop/gaster-thesis.ps", +} + +@TechReport{gaster-jones-96, + author = "Benedict R. Gaster and Mark P. Jones", + title = "A Polymorphic Type System for Extensible Records and + Variants", + institution = "Department of Computer Science, University of + Nottingham", + year = "1996", + number = "NOTTCS-TR-96-3", + URL = "http://web.cecs.pdx.edu/~mpj/pubs/polyrec.html", +} + +@InProceedings{gauthier-pottier-04, + author = "Nadji Gauthier and François Pottier", + title = "Numbering Matters: First-Order Canonical Forms for + Second-Order Recursive Types", + booktitle = icfp, + URL = "http://gallium.inria.fr/~fpottier/publis/gauthier-fpottier-icfp04.pdf", + year = "2004", + pages = "150--161", +} + +@InProceedings{gay-modular-session-types-10, + author = "Simon J. Gay and Vasco Thudichum Vasconcelos and + Ant{\'o}nio Ravara and Nils Gesbert and Alexandre Z. + Caldeira", + title = "Modular session types for distributed object-oriented + programming", + booktitle = popl, + year = "2010", + pages = "299--312", + URL = "http://www.dcs.gla.ac.uk/~simon/publications/ModularSessionTypes.pdf", +} + +@InProceedings{german-clarke-halpern-83, + author = "Steven German and Edmund Clarke and Joseph Halpern", + title = "Reasoning About Procedures as Parameters", + booktitle = "Logic of Programs", + pages = "206--220", + year = "1983", + volume = "164", + series = lncs, + publisher = springer, + URL = "http://dx.doi.org/10.1007/3-540-12896-4_365", +} + +@TechReport{geser-chaotic-94, + author = "Alfons Geser and Jens Knoop and Gerald Lüttgen and + Oliver Rüthing and Bernhard Steffen", + title = "Chaotic fixed point iterations", + institution = "Fakultät für Mathematik und Informatik, Universität + Passau", + year = "1994", + type = "MIP-Bericht", + number = "9403", + URL = "http://citeseer.ist.psu.edu/190778.html", +} + +@Manual{ghc, + author = "The GHC team", + title = "The {Glasgow Haskell} compiler", + year = "2005", + URL = "http://www.haskell.org/ghc/", +} + +@Article{ghelli-divergence-95, + title = "Divergence of {$F_\leq$} type checking", + author = "Giorgio Ghelli", + journal = tcs, + pages = "131--162", + year = "1995", + volume = "139", + number = "1--2", + URL = "ftp://ftp.di.unipi.it/pub/Papers/ghelli/DivergenceFsubTCS95.ps.gz", +} + +@InProceedings{gherghina-structured-11, + author = "Cristian Gherghina and Cristina David and Shengchao + Qin and Wei-Ngan Chin", + title = "Structured Specifications for Better Verification of + Heap-Manipulating Programs", + year = "2011", + pages = "386--401", + booktitle = fm, + publisher = springer, + series = lncs, + volume = "6664", + URL = "http://loris-7.ddns.comp.nus.edu.sg/~project/hip/publications/FM_2011_Case.pdf", +} + +@InProceedings{gibbons-dgp-06, + author = "Jeremy Gibbons", + title = "Datatype-generic programming", + booktitle = "International Spring School on Datatype-Generic + Programming", + pages = "1--71", + year = "2006", + series = lncs, + publisher = springer, + volume = "4719", + URL = "http://www.cs.ox.ac.uk/jeremy.gibbons/publications/dgp.pdf", +} + +@TechReport{gifford-fx-87, + author = "David K. Gifford and Pierre Jouvelot and John M. + Lucassen and Mark A. Sheldon", + title = "{FX-87} Reference Manual", + institution = "Massachusetts Institute of Technology", + year = "1987", + number = "MIT/LCS/TR-407", +} + +@TechReport{gifford-fx-91, + author = "David K. Gifford and Pierre Jouvelot and Mark A. + Sheldon and James W. O'Toole", + title = "Report on the {FX-91} Programming Language", + institution = "Massachusetts Institute of Technology", + year = "1992", + number = "MIT/LCS/TR-531", + URL = "http://www.psrg.lcs.mit.edu/history/publications.html#fxps", +} + +@PhdThesis{girard-72, + author = "Jean-Yves Girard", + title = "Interprétation fonctionnelle et élimination des + coupures de l'arith\-mé\-ti\-que d'ordre supérieur", + school = "Universit{\'e} Paris 7", + type = "Th\`ese d'\'Etat", + year = "1972", +} + +@Article{girard-87, + author = "Jean-Yves Girard", + title = "Linear logic", + journal = tcs, + year = "1987", + volume = "50", + number = "1", + pages = "1--102", + URL = "http://iml.univ-mrs.fr/~girard/linear.pdf", +} + +@InProceedings{glew-00, + author = "Neal Glew", + title = "An Efficient Class and Object Encoding", + booktitle = oopsla, + pages = "311--324", + year = "2000", + URL = "http://glew.org/nglew/papers/oce-oopsla.ps.gz", +} + +@InProceedings{glew-02, + author = "Neal Glew", + title = "A Theory of Second-Order Trees", + booktitle = esop, + pages = "147--161", + year = "2002", + volume = "2305", + series = lncs, + publisher = springer, + URL = "http://glew.org/nglew/papers/tsot-esop.pdf", +} + +@InProceedings{glew-99, + author = "Neal Glew", + title = "Object Closure Conversion", + booktitle = hoots, + year = "1999", + series = entcs, + volume = "26", + pages = "52--68", + URL = "http://glew.org/nglew/papers/occ-hoots.ps.gz", +} + +@InProceedings{gmeta-12, + author = "Gyesik Lee and Bruno C. d. S. Oliveira and Sungkeun + Cho and Kwangkeun Yi", + title = "{GMeta}: {A} Generic Formal Metatheory Framework for + First-Order Representations", + booktitle = esop, + pages = "436--455", + year = "2012", + series = lncs, + volume = "7211", + publisher = springer, + URL = "http://ropas.snu.ac.kr/gmeta/gmeta.pdf", +} + +@InProceedings{goerdt-85, + author = "Andreas Goerdt", + title = "A {Hoare} Calculus for Functions Defined by Recursion + on Higher Types", + booktitle = "Logic of Programs", + year = "1985", + pages = "106--117", + publisher = springer, + series = lncs, + volume = "193", + URL = "http://dx.doi.org/10.1007/3-540-15648-8_9", +} + +@InProceedings{goguen-meseguer-82, + author = "Joseph Goguen and José Meseguer", + title = "Security policies and security models", + booktitle = sp, + year = "1982", + pages = "11--20", +} + +@InProceedings{gong-97, + author = "Li Gong and Marianne Mueller and Hemma Prafullchandra + and Roland Schemers", + title = "Going Beyond the Sandbox: An Overview of the New + Security Architecture in the {Java Development Kit + 1.2}", + booktitle = "{USENIX} Symposium on Internet Technologies and + Systems", + year = "1997", + pages = "103--112", + URL = "http://secinf.net/uplarticle/10/jdk12arch.ps", +} + +@InProceedings{gong-schemers-98, + author = "Li Gong and Roland Schemers", + title = "Implementing Protection Domains in the {Java} + Development Kit 1.2", + booktitle = ndss, + year = "1998", + URL = "http://www.isoc.org/isoc/conferences/ndss/98/gong.pdf", +} + +@InProceedings{gordon-12, + author = "Colin S. Gordon and Matthew J. Parkinson and Jared + Parsons and Aleks Bromfield and Joe Duffy", + title = "Uniqueness and reference immutability for safe + parallelism", + booktitle = oopsla, + year = "2012", + pages = "21--40", + URL = "http://homes.cs.washington.edu/~csgordon/papers/oopsla12.pdf", +} + +@InProceedings{gordon-melham-96, + author = "Andrew D. Gordon and Tom Melham", + title = "Five Axioms of Alpha-Conversion", + booktitle = tphol, + pages = "173--191", + year = "1996", + volume = "1125", + series = lncs, + publisher = springer, + URL = "http://www.ftp.cl.cam.ac.uk/ftp/papers/adg/hug96.ps.gz", +} + +@InProceedings{gordon-noble-07, + author = "Donald Gordon and James Noble", + title = "Dynamic ownership in a dynamic language", + booktitle = dls, + year = "2007", + pages = "41--52", + URL = "http://doi.acm.org/10.1145/1297081.1297090", +} + +@InProceedings{gotsman-aplas-07, + author = "Alexey Gotsman and Josh Berdine and Byron Cook and + Noam Rinetzky and Mooly Sagiv", + title = "Local Reasoning for Storable Locks and Threads", + booktitle = aplas, + pages = "19--37", + year = "2007", + series = lncs, + volume = "4807", + publisher = springer, + URL = "http://dx.doi.org/10.1007/978-3-540-76637-7_3", +} + +@TechReport{gotsman-storable-07, + author = "Alexey Gotsman and Josh Berdine and Byron Cook and + Noam Rinetzky and Mooly Sagiv", + title = "Local Reasoning for Storable Locks and Threads", + institution = "Microsoft Research", + year = "2007", + number = "MSR-TR-2007-39", + URL = "http://research.microsoft.com/pubs/70427/tr-2007-39.pdf", +} + +@InProceedings{goubault-dim-94, + author = "Jean Goubault", + title = "Inférence d'unités physiques en {ML}", + booktitle = jfla, + pages = "3--20", + year = "1994", +} + +@Article{gries-73, + author = "David Gries", + title = "Describing an Algorithm by {Hopcroft}", + journal = acta, + volume = "2", + pages = "97--109", + year = "1973", + URL = "http://dx.doi.org/10.1007/BF00264025", +} + +@Article{grosch-90, + author = "Josef Grosch", + title = "Efficient and Comfortable Error Recovery in Recursive + Descent Parsers", + journal = "Structured Programming", + volume = "11", + number = "3", + pages = "129--140", + year = "1990", + URL = "http://www.cocolab.com/products/cocktail/doc.pdf/ell.pdf", +} + +@Article{grossman-06, + author = "Dan Grossman", + title = "Quantified Types in an Imperative Language", + journal = toplas, + year = "2006", + volume = "28", + number = "3", + pages = "429--475", + URL = "http://www.cs.washington.edu/homes/djg/papers/qtil.pdf", +} + +@Book{grune-jacobs-08, + author = "Dick Grune and Ceriel J. H. Jacobs", + title = "Parsing techniques: a practical guide, second + edition", + year = "2008", + publisher = springer, + series = "Monographs in computer science", + URL = "http://www.cs.vu.nl/~dick/PT2Ed.html", +} + +@Book{grune-jacobs-90, + author = "Dick Grune and Ceriel J. H. Jacobs", + title = "Parsing techniques: a practical guide", + year = "1990", + publisher = ellis, + URL = "http://www.cs.vu.nl/~dick/PTAPG.html", +} + +@Unpublished{gueneau-cakeml-16, + author = "Arma{\"e}l Gu{\'e}neau and Magnus O. Myreen and Ramana + Kumar and Michael Norrish", + title = "Verified Characteristic Formulae for {CakeML}", + note = "Submitted", + year = "2016", +} + +@Misc{gueneau-pottier-protzenko-13, + author = "Armaël Guéneau and François Pottier and Jonathan + Protzenko", + title = "The ins and outs of iteration in {Mezzo}", + note = "\url{http://goo.gl/NrgKc4}", + year = "2013", + howpublished = "Higher-Order Programming and Effects (HOPE)", +} + +@InProceedings{guillemette-monnier-07, + author = "Louis-Julien Guillemette and Stefan Monnier", + title = "A Type-Preserving Closure Conversion in {Haskell}", + booktitle = hw, + pages = "83--92", + year = "2007", + URL = "http://www.iro.umontreal.ca/~monnier/tcm.pdf", +} + +@InProceedings{guillemette-monnier-08, + author = "Louis-Julien Guillemette and Stefan Monnier", + title = "A Type-Preserving Compiler in {Haskell}", + booktitle = icfp, + year = "2008", + pages = "75--86", + URL = "http://www-etud.iro.umontreal.ca/~guillelj/icfp08.pdf", +} + +@InProceedings{guillemette-vote-08, + author = "Louis-Julien Guillemette and Stefan Monnier", + title = "One Vote for Type Families in {Haskell}!", + booktitle = tfp, + year = "2008", + URL = "http://www-etud.iro.umontreal.ca/~guillelj/tfp08.pdf", +} + +@InProceedings{gundry-10, + author = "Adam Gundry and Conor McBride and James McKinna", + title = "Type inference in context", + booktitle = msfp, + pages = "43--54", + year = "2010", + URL = "https://personal.cis.strath.ac.uk/adam.gundry/type-inference/type-inference-final.pdf", +} + +@PhdThesis{gundry-13, + author = "Adam Gundry", + title = "Type Inference, {Haskell} and Dependent Types", + school = "University of Strathclyde", + year = "2013", + URL = "https://personal.cis.strath.ac.uk/adam.gundry/thesis/thesis-2013-12-03.pdf", +} + +@Article{gupta-nandivada-15, + author = "Kartik Gupta and V. Krishna Nandivada", + title = "Lexical state analyzer for {JavaCC} grammars", + journal = spe, + URL = "http://dx.doi.org/10.1002/spe.2322", + year = "2015", +} + +@InProceedings{gustavsson-svenningsson-01, + author = "Jörgen Gustavsson and Josef Svenningsson", + title = "Constraint Abstractions", + booktitle = "Symposium on Programs as Data Objects", + year = "2001", + volume = "2053", + series = lncs, + publisher = springer, + URL = "http://www.cse.chalmers.se/~josefs/publications/ca.pdf", +} + +@InProceedings{guzman-suarez-94, + author = "Juan Carlos Guzm{\'a}n and Asc{\'a}nder Su{\'a}rez", + title = "An Extended Type System for Exceptions", + booktitle = mlapp, + series = "INRIA Research Reports", + publisher = "INRIA", + number = "2265", + year = "1994", + pages = "127--135", +} + +@InProceedings{haack-huisman-hurlin-08, + author = "Christian Haack and Marieke Huisman and Cl{\'{e}}ment + Hurlin", + title = "Reasoning about {Java's} Reentrant Locks", + booktitle = aplas, + pages = "171--187", + year = "2008", + series = lncs, + volume = "5356", + publisher = springer, + URL = "http://www.cs.ru.nl/~chaack/papers/papers/reentrant.pdf", +} + +@Article{haack-hurlin-09, + author = "Christian Haack and Cl{\'{e}}ment Hurlin", + title = "Resource Usage Protocols for Iterators", + journal = jot, + volume = "8", + number = "4", + pages = "55--83", + year = "2009", + URL = "http://www.jot.fm/issues/issue_2009_06/article3.pdf", +} + +@InProceedings{haack-wells-03, + author = "Christian Haack and J. B. Wells", + title = "Type error slicing in implicitly typed, higher-order + languages", + booktitle = esop, + year = "2003", + series = lncs, + publisher = springer, + volume = "2618", + URL = "http://www.macs.hw.ac.uk/~jbw/papers/Haack+Wells:Type-Error-Slicing-in-Implicitly-Typed-Higher-Order-Languages:ESOP-2003.pdf", +} + +@InProceedings{hall-94, + author = "Cordelia Hall and Kevin Hammond and Simon {Peyton + Jones} and Philip Wadler", + title = "Type classes in {Haskell}", + booktitle = esop, + pages = "241--256", + year = "1994", + volume = "788", + series = lncs, + publisher = springer, + URL = "http://research.microsoft.com/Users/simonpj/Papers/classhask.ps.gz", +} + +@Article{hall-96, + author = "Cordelia Hall and Kevin Hammond and Simon {Peyton + Jones} and Philip Wadler", + title = "Type classes in {Haskell}", + journal = toplas, + year = "1996", + volume = "18", + number = "2", + pages = "109--138", + URL = "http://doi.acm.org/10.1145/227699.227700", +} + +@InProceedings{haller-odersky-10, + author = "Philipp Haller and Martin Odersky", + title = "Capabilities for Uniqueness and Borrowing", + booktitle = ecoop, + year = "2010", + pages = "354--378", + publisher = springer, + series = lncs, + volume = "6183", + URL = "http://lampwww.epfl.ch/~phaller/doc/haller-odersky10-Capabilities_for_uniqueness_and_borrowing.pdf", +} + +@TechReport{hallett-kfoury-04, + author = "Joseph J. Hallett and Assaf J. Kfoury", + title = "Programming Examples Needing Polymorphic Recursion", + institution = "Department of Computer Science, Boston University", + year = "2004", + number = "BUCS-TR-2004-004", + URL = "http://www.church-project.org/reports/electronic/Hal+Kfo:BUCS-TR-2004-004.pdf", +} + +@PhdThesis{hanus-88, + author = "Michael Hanus", + title = "Horn Clause Specifications with Polymorphic Types", + year = "1988", + school = "Fachbereich Informatik, Universität Dortmund", + URL = "http://www.informatik.uni-kiel.de/~mh/publications/various/Dissertation.dvi.Z", +} + +@InProceedings{hanus-89, + author = "Michael Hanus", + title = "Horn Clause Programs with Polymorphic Types: Semantics + and Resolution", + booktitle = tapsoft, + publisher = springer, + series = lncs, + volume = "352", + pages = "225--240", + year = "1989", + URL = "http://www.informatik.uni-kiel.de/~mh/publications/papers/TAPSOFT89.ps", +} + +@Manual{happy, + author = "Simon Marlow and Andy Gill", + title = "Happy: the parser generator for {Haskell}", + year = "2004", + URL = "http://www.haskell.org/happy/", +} + +@Article{hardy-88, + author = "Norm Hardy", + title = "The Confused Deputy (or why capabilities might have + been invented)", + journal = sigops, + year = "1988", + volume = "22", + number = "4", + pages = "36--38", + URL = "http://www.cis.upenn.edu/~KeyKOS/ConfusedDeputy.html", +} + +@Article{harfst-reingold-00, + author = "Gregory C. Harfst and Edward M. Reingold", + title = "A potential-based amortized analysis of the union-find + data structure", + journal = "{SIGACT} News", + volume = "31", + number = "3", + pages = "86--95", + year = "2000", + URL = "http://doi.acm.org/10.1145/356458.356463", +} + +@Article{harper-94, + author = "Robert Harper", + title = "A simplified account of polymorphic references", + journal = ipl, + volume = "51", + number = "4", + year = "1994", + pages = "201--206", + URL = "http://www.cs.cmu.edu/~rwh/papers/refs/ipl94.pdf", +} + +@Article{harper-99, + author = "Robert Harper", + title = "Proof-Directed Debugging", + journal = jfp, + volume = "9", + number = "4", + year = "1999", + pages = "463--469", + URL = "http://dx.doi.org/10.1017/S0956796808007119", +} + +@Article{harper-honsell-plotkin-93, + author = "Robert Harper and Furio Honsell and Gordon D. + Plotkin", + title = "A Framework for Defining Logics", + journal = jacm, + volume = "40", + number = "1", + pages = "143--184", + year = "1993", + URL = "http://homepages.inf.ed.ac.uk/gdp/publications/Framework_Def_Log.pdf", +} + +@Article{harper-licata-07, + author = "Robert Harper and Daniel R. Licata", + title = "Mechanizing metatheory in a logical framework", + journal = jfp, + volume = "17", + number = "4--5", + year = "2007", + pages = "613--673", + URL = "http://www.cs.cmu.edu/~rwh/papers/mech/jfp07.pdf", +} + +@Misc{harper-lillibridge-91, + author = "Bob Harper and Mark Lillibridge", + title = "{ML} with callcc is unsound", + howpublished = "Message to the {TYPES} mailing list", + year = "1991", + URL = "http://www.cis.upenn.edu/~bcpierce/types/archives/1991/msg00034.html", +} + +@InProceedings{harper-pierce-91, + author = "Robert Harper and Benjamin Pierce", + title = "A Record Calculus Based on symmetric Concatenation", + pages = "131--142", + booktitle = popl, + year = "1991", + URL = "http://www.cis.upenn.edu/~bcpierce/papers/merge.ps", +} + +@InCollection{harper-pierce-attapl, + author = "Robert Harper and Benjamin C. Pierce", + title = "Design Considerations for {ML}-Style Module Systems", + booktitle = "Advanced Topics in Types and Programming Languages", + pages = "293--345", + publisher = mitp, + year = "2005", + editor = "Benjamin C. Pierce", + chapter = "8", +} + +@Book{harrison-09, + author = "John Harrison", + title = "Handbook of Practical Logic and Automated Reasoning", + publisher = cup, + year = "2009", + URL = "http://www.cl.cam.ac.uk/~jrh13/atp/", +} + +@Book{haskell-98, + editor = "Simon {Peyton Jones}", + title = "{Haskell} 98 Language and Libraries: The Revised + Report", + publisher = cup, + year = "2003", + URL = "http://www.haskell.org/onlinereport/", +} + +@InProceedings{haskell-history-07, + author = "Paul Hudak and John Hughes and Simon {Peyton Jones} + and Philip Wadler", + title = "A History of {Haskell}: being lazy with class", + booktitle = hopl, + year = "2007", + URL = "https://www.microsoft.com/en-us/research/wp-content/uploads/2016/07/history.pdf", +} + +@TechReport{hawblitzel-05, + author = "Chris Hawblitzel", + title = "Linear Types for Aliased Resources", + institution = "Microsoft Research", + year = "2005", + number = "MSR-TR-2005-141", + URL = "http://research.microsoft.com/pubs/70228/tr-2005-141.pdf", +} + +@InProceedings{hecht-ullman-73, + author = "Matthew S. Hecht and Jeffrey D. Ullman", + title = "Analysis of a simple algorithm for global data flow + problems", + booktitle = popl, + pages = "207--217", + year = "1973", + URL = "http://doi.acm.org/10.1145/512927.512946", +} + +@TechReport{heeren-improving-02, + title = "Improving type-error messages in functional + languages", + author = "Bastiaan Heeren and Johan Jeuring and Doaitse + Swierstra and Pablo Azero Alcocer", + year = "2002", + institution = "University of Utrecht, Institute of Information and + Computing Science", + number = "UU-CS-2002-009", + URL = "http://archive.cs.uu.nl/pub/RUU/CS/techreps/CS-2002/2002-009.pdf", +} + +@TechReport{heeren2002generalizing, + title = "Generalizing {Hindley-Milner} Type Inference + Algorithms", + author = "Bastiaan Heeren and Jurriaan Hage and Doaitse + Swierstra", + year = "2002", + institution = "University of Utrecht, Institute of Information and + Computing Science", + number = "UU-CS-2002-031", + URL = "http://archive.cs.uu.nl/pub/RUU/CS/techreps/CS-2002/2002-031.pdf", +} + +@TechReport{heeren2002parametric, + title = "Parametric Type Inferencing for {Helium}", + author = "Bastiaan Heeren and Jurriaan Hage", + year = "2002", + institution = "University of Utrecht, Institute of Information and + Computing Science", + number = "UU-CS-2002-035", + URL = "http://archive.cs.uu.nl/pub/RUU/CS/techreps/CS-2002/2002-035.pdf", +} + +@InBook{hehner-96, + author = "Eric C. R. Hehner", + booktitle = "A classical mind", + title = "Abstractions of Time", + publisher = prentice, + year = "1994", + pages = "191--210", + URL = "http://www.cs.toronto.edu/~hehner/AoT.pdf", +} + +@Article{hehner-98, + author = "Eric C. R. Hehner", + title = "Formalization of Time and Space", + journal = fac, + year = "1998", + volume = "10", + pages = "290--206", + URL = "http://www.cs.toronto.edu/~hehner/FTS.pdf", +} + +@TechReport{heintze-93, + author = "Nevin Heintze", + institution = "Carnegie Mellon University, School of Computer + Science", + title = "Set Based Analysis of {ML} Programs", + year = "1993", + number = "CMU-CS-93-193", + URL = "http://reports-archive.adm.cs.cmu.edu/anon/1993/CMU-CS-93-193.ps", +} + +@InProceedings{heintze-mcallester-97, + author = "Nevin Heintze and David McAllester", + title = "Linear-Time Subtransitive Control Flow Analysis", + pages = "261--272", + booktitle = pldi, + year = "1997", + URL = "http://www.autoreason.com/PLDI97.ps", +} + +@InProceedings{heintze-riecke-slam-98, + author = "Nevin Heintze and Jon G. Riecke", + title = "The {SL}am Calculus: Programming with Secrecy and + Integrity", + booktitle = popl, + year = "1998", + pages = "365--377", + URL = "http://cm.bell-labs.com/cm/cs/who/nch/slam.ps", +} + +@InProceedings{heintze-tardieu-01, + author = "Nevin Heintze and Olivier Tardieu", + title = "Ultra-fast Aliasing Analysis using {CLA}: {A} Million + Lines of {C} Code in a Second", + pages = "254--263", + booktitle = pldi, + year = "2001", + URL = "http://cm.bell-labs.com/cm/cs/who/nch/pldi01-1m.ps", +} + +@InProceedings{helsen-thiemann-00, + author = "Simon Helsen and Peter Thiemann", + title = "Syntactic Type Soundness for the Region Calculus", + booktitle = hoots, + pages = "1--19", + year = "2000", + volume = "41", + number = "3", + series = entcs, + URL = "http://www.swen.uwaterloo.ca/~shelsen/papers/helsen-thiemann-hoots-00.pdf", +} + +@TechReport{henderson-modes-92, + author = "Fergus Henderson", + title = "Strong modes can change the world!", + institution = "Department of Computer Science, University of + Melbourne", + year = "1992", + number = "96/11", + URL = "http://www.cs.mu.oz.au/~fjh/papers/hons_thesis.ps.gz", +} + +@InProceedings{hendriks-oostrom-03, + author = "Dimitri Hendriks and Vincent van Oostrom", + title = "Adbmal", + booktitle = cade, + pages = "136--150", + year = "2003", + volume = "2741", + series = lncs, + publisher = springer, + URL = "http://www.phil.uu.nl/~oostrom/publication/ps/adbmal_jfpsv.ps", +} + +@InProceedings{henglein-91, + author = "Fritz Henglein", + booktitle = fpca, + title = "Efficient Type Inference for Higher-Order Binding-Time + Analysis", + year = "1991", + pages = "448--472", + series = lncs, + volume = "523", + publisher = springer, + URL = "ftp://ftp.diku.dk/pub/diku/users/henglein/binding-time-analysis.dvi.gz", +} + +@Article{henglein-93, + author = "Fritz Henglein", + title = "Type Inference with Polymorphic Recursion", + journal = toplas, + year = "1993", + volume = "15", + number = "2", + pages = "253--289", + URL = "http://doi.acm.org/10.1145/169701.169692", +} + +@InProceedings{henglein-breaking-97, + author = "Fritz Henglein", + title = "Breaking through the $n^3$ barrier: Faster object type + inference", + booktitle = fool, + year = "1997", +} + +@Article{henglein-breaking-99, + author = "Fritz Henglein", + title = "Breaking through the $n^3$ barrier: Faster Object Type + Inference", + journal = "Theory and Practice of Object Systems", + year = "1999", + volume = "5", + number = "1", + pages = "57--72", + URL = "ftp://ftp.diku.dk/diku/semantics/papers/D-396.ps.gz", +} + +@Article{henglein-paige-87, + author = "Robert Paige and Fritz Henglein", + title = "Mechanical translation of set theoretic problem + specifications into efficient {RAM} code -- {A} case + study", + journal = jsc, + volume = "4", + number = "2", + year = "1987", + pages = "207--232", + URL = "http://dx.doi.org/10.1016/S0747-7171(87)80066-4", +} + +@PhdThesis{henglein-phd-89, + author = "Fritz Henglein", + school = "Rutgers University", + title = "Polymorphic Type Inference and Semi-Unification", + year = "1989", + URL = "ftp://ftp.diku.dk/diku/users/henglein/poly-typ-inf-and-semi-unif.ps.gz", +} + +@InProceedings{henglein-rehof-97, + author = "Fritz Henglein and Jakob Rehof", + title = "The Complexity of Subtype Entailment for Simple + Types", + pages = "352--361", + booktitle = lics, + year = "1997", + URL = "http://research.microsoft.com/~rehof/lics97.ps", +} + +@InProceedings{henglein-rehof-98, + author = "Fritz Henglein and Jakob Rehof", + title = "Constraint Automata and the Complexity of Recursive + Subtype Entailment", + booktitle = icalp, + year = "1998", + URL = "http://research.microsoft.com/~rehof/icalp98.ps", +} + +@TechReport{hennessy-2000, + author = "Matthew Hennessy", + title = "The security picalculus and non-interference", + year = "2000", + institution = "University of Sussex", + number = "2000:05", + URL = "ftp://ftp.cogs.susx.ac.uk/pub/reports/compsci/cs052000.ps.Z", +} + +@InProceedings{hennessy-riely-00, + author = "Matthew Hennessy and James Riely", + title = "Information Flow vs. Resource Access in the + Asynchronous Pi-Calculus", + booktitle = icalp, + series = lncs, + publisher = springer, + year = "2000", + URL = "http://www.depaul.edu/~jriely/papers/00icalp.ps.gz", +} + +@InProceedings{hepburn-wright-01, + author = "Mark Hepburn and David Wright", + title = "Trust in the Pi-Calculus", + booktitle = ppdp, + year = "2001", +} + +@Article{herlihy-schachte-sondergaard-07, + author = "Brian Herlihy and Peter Schachte and Harald + Søndergaard", + title = "Un-{Kleene} {Boolean} Equation Solving", + journal = ijfcs, + year = "2007", + volume = "18", + number = "2", + pages = "227--250", + URL = "http://dx.doi.org/10.1142/S0129054107004668", +} + +@InProceedings{heule-13, + author = "Stefan Heule and K. Rustan M. Leino and Peter + M{\"u}ller and Alexander J. Summers", + title = "Abstract Read Permissions: Fractional Permissions + without the Fractions", + booktitle = vmcai, + year = "2013", + pages = "315--334", + publisher = springer, + series = lncs, + volume = "7737", + URL = "http://research.microsoft.com/en-us/um/people/leino/papers/krml225.pdf", +} + +@InProceedings{higuchi-ohori-03, + author = "Tomoyuki Higuchi and Atsushi Ohori", + title = "A Static Type System for {JVM} Access Control", + booktitle = icfp, + pages = "227--237", + year = "2003", + URL = "http://doi.acm.org/10.1145/944726", +} + +@InProceedings{hillerstrom-lindley-16, + author = "Daniel Hillerstr{\"{o}}m and Sam Lindley", + title = "Liberating effects with rows and handlers", + booktitle = "International Workshop on Type-Driven Development + (TyDe@ICFP)", + pages = "15--27", + year = "2016", + URL = "http://homepages.inf.ed.ac.uk/slindley/papers/links-effect.pdf", +} + +@Article{hindley-69, + author = "J. Roger Hindley", + title = "The Principal Type-scheme of an Object in Combinatory + Logic", + journal = tams, + volume = "146", + pages = "29--60", + year = "1969", + URL = "http://dx.doi.org/10.2307/1995158", +} + +@InCollection{hinze-03, + author = "Ralf Hinze", + editor = "Jeremy Gibbons and Oege de Moor", + booktitle = "The Fun of Programming", + title = "Fun with Phantom Types", + publisher = palgrave, + year = "2003", + pages = "245--262", + URL = "http://www.informatik.uni-bonn.de/~ralf/publications/With.pdf", +} + +@TechReport{hinze-comparing-generic-06, + author = "Ralf Hinze and Johan Jeuring and Andres Löh", + year = "2006", + title = "Comparing approaches to generic programming in + {Haskell}", + number = "UU-CS-2006-022", + institution = "Department of Information and Computing Sciences, + Utrecht University", + URL = "http://www.cs.uu.nl/research/techreps/repo/CS-2006/2006-022.pdf", +} + +@InProceedings{hinze-derivable-00, + author = "Ralf Hinze and Simon {Peyton Jones}", + title = "Derivable type classes", + booktitle = hw, + year = "2000", + URL = "https://www.microsoft.com/en-us/research/wp-content/uploads/2000/09/derive.pdf", +} + +@Unpublished{hinze-paterson-05, + author = "Ralf Hinze and Ross Paterson", + title = "Derivation of a Typed Functional {LR} Parser", + note = "Unpublished", + year = "2005", + URL = "http://www.cs.ox.ac.uk/ralf.hinze/publications/TypedLR.pdf", +} + +@Article{hinze-paterson-06, + title = "Finger trees: a simple general-purpose data + structure", + author = "Ralf Hinze and Ross Paterson", + journal = jfp, + year = "2006", + number = "2", + volume = "16", + pages = "197--217", + URL = "http://www.cs.ox.ac.uk/ralf.hinze/publications/FingerTrees.pdf", +} + +@InProceedings{hirschowitz-cbv-04, + author = "Tom Hirschowitz and Xavier Leroy and J. B. Wells", + title = "Call-by-value mixin modules: Reduction semantics, side + effects, types", + booktitle = esop, + pages = "64--78", + year = "2004", + volume = "2986", + series = lncs, + publisher = springer, + URL = "http://gallium.inria.fr/~xleroy/publi/mixins-mm-esop2004.ps.gz", +} + +@Article{hirschowitz-leroy-04, + author = "Tom Hirschowitz and Xavier Leroy", + title = "Mixin Modules in a Call-by-Value Setting", + journal = toplas, + year = "2004", + note = "To appear", + URL = "http://gallium.inria.fr/~hirschow/papers/toplas-cmsv.ps.gz", +} + +@InProceedings{hoang-mitchell-lower-95, + author = "My Hoang and John C. Mitchell", + title = "Lower Bounds on Type Inference with Subtypes", + pages = "176--185", + booktitle = popl, + year = "1995", + URL = "http://doi.acm.org/10.1145/199448.199481", +} + +@Article{hoare-61, + author = "C. A. R. Hoare", + title = "Algorithm 65: find", + journal = cacm, + volume = "4", + number = "7", + year = "1961", + pages = "321--322", + URL = "http://doi.acm.org/10.1145/366622.366647", +} + +@Article{hoare-69, + author = "C. A. R. Hoare", + title = "An axiomatic basis for computer programming", + journal = cacm, + volume = "12", + number = "10", + year = "1969", + pages = "576--580", + URL = "http://doi.acm.org/10.1145/363235.363259", +} + +@Article{hoare-71, + author = "C. A. R. Hoare", + title = "Proof of a program: {FIND}", + journal = cacm, + year = "1971", + volume = "14", + number = "1", + pages = "39--45", + URL = "http://doi.acm.org/10.1145/362452.362489", +} + +@Article{hoare-data-72, + author = "C. A. R. Hoare", + title = "Proof of correctness of data representations", + journal = acta, + year = "1972", + volume = "4", + pages = "271--281", + URL = "http://dx.doi.org/10.1007/BF00289507", +} + +@InProceedings{hobor-gherghina-11, + author = "Aquinas Hobor and Cristian Gherghina", + title = "Barriers in Concurrent Separation Logic", + booktitle = esop, + year = "2011", + series = lncs, + publisher = springer, + URL = "http://www.comp.nus.edu.sg/~hobor/Publications/barrier.pdf", +} + +@InProceedings{hobor-indirection-10, + author = "Aquinas Hobor and Robert Dockins and Andrew W. Appel", + title = "A Theory of Indirection via Approximation", + booktitle = popl, + year = "2010", + URL = "http://www.comp.nus.edu.sg/~hobor/Publications/indirection.pdf", +} + +@InProceedings{hobor-oracle-08, + author = "Aquinas Hobor and Andrew W. Appel and Francesco {Zappa + Nardelli}", + title = "Oracle Semantics for Concurrent Separation Logic", + booktitle = esop, + pages = "353--367", + year = "2008", + volume = "4960", + series = lncs, + publisher = springer, + URL = "http://www.cs.princeton.edu/~appel/papers/concurrent.pdf", +} + +@Article{hoffmann-aehlig-hofmann-multivariate-12, + author = "Jan Hoffmann and Klaus Aehlig and Martin Hofmann", + title = "Multivariate amortized resource analysis", + journal = toplas, + volume = "34", + number = "3", + pages = "14:1--14:62", + year = "2012", + URL = "http://doi.acm.org/10.1145/2362389.2362393", +} + +@InProceedings{hoffmann-aehlig-hofmann-raml-12, + author = "Jan Hoffmann and Klaus Aehlig and Martin Hofmann", + title = "Resource Aware {ML}", + booktitle = cav, + pages = "781--786", + year = "2012", + URL = "http://dx.doi.org/10.1007/978-3-642-31424-7_64", + series = lncs, + volume = "7358", + publisher = springer, +} + +@InProceedings{hoffmann-das-weng-17, + author = "Jan Hoffmann and Ankush Das and Shu{-}Chun Weng", + title = "Towards automatic resource bound analysis for + {OCaml}", + booktitle = popl, + pages = "359--373", + year = "2017", + URL = "http://www.cs.cmu.edu/~janh/papers/HoffmannDW17.pdf", +} + +@InProceedings{hoffmann-hofmann-10, + author = "Jan Hoffmann and Martin Hofmann", + title = "Amortized Resource Analysis with Polynomial + Potential", + booktitle = esop, + pages = "287--306", + year = "2010", + volume = "6012", + series = lncs, + publisher = springer, + URL = "http://www.cs.yale.edu/homes/hoffmann/papers/aapoly_conference.pdf", +} + +@InProceedings{hoffmann-marmar-shao-13, + author = "Jan Hoffmann and Michael Marmar and Zhong Shao", + title = "Quantitative Reasoning for Proving Lock-Freedom", + booktitle = lics, + year = "2013", + pages = "124--133", + URL = "http://www.cs.cmu.edu/~janh/papers/lockfree2013.pdf", +} + +@Article{hofmann-00, + author = "Martin Hofmann", + title = "A type system for bounded space and functional + in-place update", + journal = njc, + year = "2000", + volume = "7", + number = "4", + pages = "258--289", + URL = "http://www.tcs.informatik.uni-muenchen.de/~mhofmann/nordic.ps.gz", +} + +@InProceedings{hofmann-jost-03, + author = "Martin Hofmann and Steffen Jost", + title = "Static prediction of heap space usage for first-order + functional programs", + booktitle = popl, + year = "2003", + pages = "185--197", + URL = "http://www2.tcs.ifi.lmu.de/~jost/research/POPL_2003_Jost_Hofmann.pdf", +} + +@InProceedings{hofmann-moser-14, + author = "Martin Hofmann and Georg Moser", + title = "Amortised Resource Analysis and Typed Polynomial + Interpretations", + booktitle = tlca, + pages = "272--286", + year = "2014", + volume = "8560", + series = lncs, + publisher = springer, + URL = "http://arxiv.org/pdf/1402.1922.pdf", +} + +@InProceedings{hofmann-pavlova-08, + author = "Martin Hofmann and Mariela Pavlova", + title = "Elimination of ghost variables in program logics", + booktitle = "Trustworthy Global Computing", + pages = "1--20", + year = "2008", + volume = "4912", + series = lncs, + publisher = springer, + URL = "http://www-sop.inria.fr/everest/personnel/Mariela.Pavlova/ghost.pdf", +} + +@Article{hofmann-pierce-94, + author = "Martin Hofmann and Benjamin Pierce", + title = "A Unifying Type-Theoretic Framework for Objects", + journal = jfp, + volume = "5", + number = "4", + pages = "593--635", + note = "Previous versions appeared in the Symposium on + Theoretical Aspects of Computer Science, 1994, (pages + 251--262) and, under the title ``An Abstract View of + Objects and Subtyping (Preliminary Report),'' as + University of Edinburgh, LFCS technical report + ECS-LFCS-92-226, 1992", + year = "1995", + URL = "http://www.cis.upenn.edu/~bcpierce/papers/abstroop.ps", +} + +@InProceedings{hogg-91, + author = "John Hogg", + title = "Islands: Aliasing Protection in Object-Oriented + Languages", + booktitle = oopsla, + year = "1991", + pages = "271--285", + URL = "http://dx.doi.org/10.1145/118014.117975", +} + +@InProceedings{honda-al-00, + author = "Kohei Honda and Vasco Vasconcelos and Nobuko Yoshida", + title = "Secure information flow as typed process behaviour", + booktitle = esop, + publisher = springer, + series = lncs, + volume = "1782", + pages = "180--199", + year = "2000", + URL = "ftp://ftp.dcs.qmw.ac.uk/lfp/kohei/siftp-esop00.ps.gz", +} + +@TechReport{honda-al-00-long, + author = "Kohei Honda and Vasco Vasconcelos and Nobuko Yoshida", + title = "Secure information flow as typed process behaviour", + institution = "Queen Mary and Westfield College, University of + London", + year = "1999", + number = "QMW-DCS-1999-767", + URL = "ftp://ftp.dcs.qmw.ac.uk/lfp/kohei/siftp-qmwrep.ps.gz", +} + +@InProceedings{honda-yoshida-02, + author = "Kohei Honda and Nobuko Yoshida", + title = "A Uniform Type Structure for Secure Information Flow", + booktitle = popl, + year = "2002", + pages = "81--92", + URL = "http://www.mcs.le.ac.uk/~nyoshida/paper/ifa_long.ps.gz", +} + +@InProceedings{honda-yoshida-04, + author = "Kohei Honda and Nobuko Yoshida", + title = "A compositional logic for polymorphic higher-order + functions", + booktitle = ppdp, + year = "2004", + pages = "191--202", + URL = "http://www.dcs.qmul.ac.uk/~kohei/logics/polyrec.pdf.gz", +} + +@InProceedings{honsell-01, + author = "Furio Honsell and Marino Miculan and Ivan Scagnetto", + title = "An axiomatic approach to metareasoning on nominal + algebras in {HOAS}", + booktitle = icalp, + pages = "963--978", + year = "2001", + volume = "2076", + series = lncs, + publisher = springer, + URL = "https://users.dimi.uniud.it/~marino.miculan/Papers/ICALP01.pdf", +} + +@InCollection{hopcroft-minimizing-71, + author = "John~E. Hopcroft", + title = "An $n\log n$ algorithm for minimizing states in a + finite automaton", + booktitle = "Theory of Machines and Computations", + editor = "Z. Kohavi", + publisher = ap, + year = "1971", + pages = "189--196", +} + +@Book{hopcroft-motwani-ullman-00, + author = "John E. Hopcroft and Rajeev Motwani and Jeffrey D. + Ullman", + title = "Introduction to Automata Theory, Languages, and + Computation", + publisher = aw, + year = "2000", + URL = "http://www-db.stanford.edu/~ullman/ialc.html", +} + +@Article{hopcroft-ullman-73, + author = "John E. Hopcroft and Jeffrey D. Ullman", + title = "Set Merging Algorithms", + journal = siamjc, + volume = "2", + number = "4", + pages = "294--303", + year = "1973", + URL = "http://dx.doi.org/10.1137/0202024", +} + +@InProceedings{horning-74, + author = "James J. Horning", + title = "What the Compiler Should Tell the User", + booktitle = cc, + year = "1974", + pages = "525--548", + volume = "21", + series = lncs, + publisher = springer, + URL = "http://dx.doi.org/10.1007/3540069585_64", +} + +@Article{horspool-faster-90, + author = "R. Nigel Horspool and Michael Whitney", + title = "Even Faster {LR} Parsing", + journal = spe, + year = "1990", + volume = "20", + number = "6", + pages = "515--535", + URL = "http://www.cs.uvic.ca/~nigelh/Publications/fastparse.pdf", +} + +@InProceedings{horwitz-95, + author = "Susan Horwitz and Thomas Reps and Mooly Sagiv", + title = "Demand interprocedural dataflow analysis", + booktitle = "ACM Symposium on the Foundations of Software + Engineering (FSE)", + year = "1995", + URL = "http://www.cs.wisc.edu/wpis/papers/fse95a.ps", +} + +@Article{horwitz-demers-teitelbaum-87, + author = "Alan Demers and Susan Horwitz and Tim Teitelbaum", + title = "An efficient general algorithm for dataflow analysis", + journal = acta, + year = "1987", + volume = "24", + number = "6", + pages = "679--694", + URL = "http://dx.doi.org/10.1007/BF00282621", +} + +@Article{hosoya-pierce-02, + author = "Haruo Hosoya and Benjamin C. Pierce", + title = "Regular expression pattern matching for {XML}", + journal = jfp, + volume = "13", + number = "6", + year = "2003", + pages = "961--1004", + URL = "http://dx.doi.org/10.1017/S0956796802004410", +} + +@TechReport{howell-08, + author = "Rodney R. Howell", + title = "On Asymptotic Notation with Multiple Variables", + institution = "Kansas State University", + year = "2008", + number = "2007-4", + URL = "http://people.cs.ksu.edu/~rhowell/asymptotic.pdf", +} + +@Misc{howell-book, + author = "Rodney R. Howell", + title = "Algorithms: {A} Top-Down Approach", + year = "2012", + note = "Draft", + URL = "http://people.cs.ksu.edu/~rhowell/algorithms-text/text/", +} + +@Article{hru-76, + author = "Michael A. Harrison and Walter L. Ruzzo and Jeffrey D. + Ullman", + title = "Protection in Operating Systems", + journal = cacm, + year = "1976", + volume = "19", + number = "8", + pages = "461--471", + URL = "http://doi.acm.org/10.1145/360303.360333", +} + +@InProceedings{hubert-marche-07, + author = "Thierry Hubert and Claude Marché", + title = "Separation Analysis for Deductive Verification", + booktitle = hav, + year = "2007", + URL = "http://www.lri.fr/~marche/hubert07hav.pdf", +} + +@PhdThesis{huet-76, + author = "G{\'e}rard Huet", + title = "{R}{\'e}solution d'{\'e}quations dans des langages + d'ordre $1$, $2$, $\ldots$, $\omega$", + school = "Universit{\'e} Paris 7", + year = "1976", +} + +@Article{huet-98, + author = "Gérard Huet", + title = "Regular {Böhm} Trees", + journal = mscs, + year = "1998", + volume = "8", + pages = "671--680", + URL = "http://yquem.inria.fr/~huet/PUBLIC/RBT2.pdf", +} + +@Article{huet-zipper-97, + author = "G{\'e}rard Huet", + title = "The Zipper", + journal = jfp, + volume = "7", + number = "5", + year = "1997", + pages = "549--554", + URL = "http://yquem.inria.fr/~huet/PUBLIC/zip.pdf", +} + +@InProceedings{huffman-urban-10, + author = "Brian Huffman and Christian Urban", + title = "A New Foundation for {Nominal Isabelle}", + booktitle = itp, + pages = "35--50", + year = "2010", + series = lncs, + volume = "6172", + publisher = springer, + URL = "http://nms.kcl.ac.uk/christian.urban/Publications/nominal-atoms.pdf", +} + +@Article{hughes-arrows-00, + author = "John Hughes", + title = "Generalising monads to arrows", + journal = scp, + volume = "37", + number = "1--3", + year = "2000", + pages = "67--111", + URL = "http://www.cse.chalmers.se/~rjmh/Papers/arrows.pdf", +} + +@Article{hughes-matters-89, + author = "John Hughes", + title = "Why Functional Programming Matters", + journal = cj, + volume = "32", + number = "2", + pages = "98--107", + year = "1989", + URL = "http://www.cse.chalmers.se/~rjmh/Papers/whyfp.pdf", +} + +@InProceedings{hughes-pareto-sabry-96, + author = "John Hughes and Lars Pareto and Amr Sabry", + title = "Proving the correctness of reactive systems using + sized types", + booktitle = popl, + year = "1996", + pages = "410--423", + URL = "http://doi.acm.org/10.1145/237721.240882", +} + +@Article{hutton-fold-99, + author = "Graham Hutton", + title = "A Tutorial on the Universality and Expressiveness of + Fold", + journal = jfp, + volume = "9", + number = "4", + pages = "355--372", + year = "1999", + URL = "http://www.cs.nott.ac.uk/~pszgmh/fold.pdf", +} + +@Article{igarashi-kobayashi-00, + author = "Atsushi Igarashi and Naoki Kobayashi", + title = "Type Reconstruction for Linear $\pi$-Calculus with + {I}/{O} Subtyping", + journal = ic, + volume = "161", + pages = "1--44", + year = "2000", + URL = "http://www.sato.kuis.kyoto-u.ac.jp/~igarashi/papers/psgz/linear-pi.IC.ps.gz", +} + +@InProceedings{ishtiaq-ohearn-01, + author = "Samin S. Ishtiaq and Peter W. O'Hearn", + title = "{BI} as an assertion language for mutable data + structures", + booktitle = popl, + year = "2001", + pages = "14--26", + URL = "http://www.cs.ucl.ac.uk/staff/p.ohearn/papers/bi-assertion-lan.pdf", +} + +@InCollection{iwaco-03, + author = "Dave Clarke and Sophia Drossopoulou and James Noble", + title = "Aliasing, Confinement, and Ownership in + Object-Oriented Programming", + booktitle = "Object-Oriented Technology. {ECOOP 2003} Workshop + Reader", + year = "2004", + publisher = springer, + series = lncs, + volume = "3013", + pages = "197--207", + URL = "http://dx.doi.org/10.1007/978-3-540-25934-3_19", +} + +@Manual{jacc, + title = "jacc: Just Another Compiler Compiler for {Java}", + author = "Mark P. Jones", + year = "2004", + URL = "http://web.cecs.pdx.edu/~mpj/jacc/jacc.pdf", +} + +@InProceedings{jackson-vaziri-00, + author = "Daniel Jackson and Mandana Vaziri", + title = "Finding Bugs with a Constraint Solver", + booktitle = issta, + year = "2000", + URL = "http://sdg.csail.mit.edu/pubs/2000/issta00.pdf", +} + +@InProceedings{jacobs-termination-15, + author = "Bart Jacobs and Dragan Bosnacki and Ruurd Kuipe", + title = "Modular Termination Verification", + booktitle = ecoop, + pages = "99--1023", + year = "2015", + series = lipics, + URL = "http://people.cs.kuleuven.be/~bart.jacobs/ecoop2015.pdf", +} + +@InProceedings{jagannathan-wright-95, + author = "Suresh Jagannathan and Andrew Wright", + title = "Effective Flow Analysis for Avoiding Run-Time Checks", + year = "1995", + booktitle = sas, + publisher = springer, + series = lncs, + volume = "983", + URL = "http://www.cs.purdue.edu/homes/suresh/papers/sas95.ps.gz", +} + +@PhdThesis{jansson-00, + author = "Patrik Jansson", + title = "Functional Polytypic Programming", + school = "Chalmers University of Technology", + year = "2000", + URL = "http://www.cse.chalmers.se/~patrikj/poly/polythesis/Jansson2000_PhD_thesis.pdf", +} + +@Book{java, + author = "James Gosling and Bill Joy and Guy Steele and Gilad + Bracha", + title = "The {Java} Language Specification, Second Edition", + publisher = aw, + year = "2000", + URL = "http://java.sun.com/docs/books/jls/", +} + +@Book{javasec, + author = "Li Gong and Gary Ellison and Mary Dageforde", + title = "Inside {Java 2} Platform Security, Second Edition", + publisher = aw, + year = "2003", + URL = "http://java.sun.com/docs/books/security/", +} + +@Article{jay-04, + author = "C. Barry Jay", + title = "The Pattern Calculus", + journal = toplas, + volume = "26", + number = "6", + pages = "911--937", + year = "2004", + URL = "http://www-staff.it.uts.edu.au/~cbj/Publications/pattern_calculus.pdf", + alturl = "http://doi.acm.org/10.1145/1034774.1034775", +} + +@Article{jeffery-03, + author = "Clinton L. Jeffery", + title = "Generating {LR} syntax error messages from examples", + journal = toplas, + volume = "25", + number = "5", + year = "2003", + pages = "631--640", + URL = "http://doi.acm.org/10.1145/937563.937566", +} + +@InProceedings{jensen-13, + author = "Jonas Braband Jensen and Nick Benton and Andrew + Kennedy", + title = "High-level separation logic for low-level code", + booktitle = popl, + pages = "301--314", + year = "2013", + URL = "http://research.microsoft.com/en-us/um/people/nick/hlsl.pdf", +} + +@InProceedings{jensen-98, + author = "Thomas Jensen", + title = "Inference of polymorphic and conditional strictness + properties", + booktitle = popl, + year = "1998", + pages = "209--221", + publisher = acmp, + URL = "http://www.irisa.fr/lande/jensen/papers/popl98.ps", +} + +@InProceedings{jensen-al-99, + author = "Thomas Jensen and Daniel {Le Métayer} and Tommy + Thorn", + title = "Verifying security properties of control-flow graphs", + booktitle = sp, + pages = "89--105", + year = "1999", + URL = "http://www.irisa.fr/lande/jensen/papers/SP99.ps", +} + +@InProceedings{jensen-birkedal-fictional-12, + author = "Jonas Braband Jensen and Lars Birkedal", + title = "Fictional Separation Logic", + booktitle = esop, + year = "2012", + pages = "377--396", + publisher = springer, + series = lncs, + volume = "7211", + URL = "http://cs.au.dk/~birke/papers/sharing-conf.pdf", +} + +@InProceedings{jensen-ployette-ridoux-02, + title = "Iteration schemes for fixed point computation", + author = "Thomas Jensen and Florimond Ployette and Olivier + Ridoux", + year = "2002", + booktitle = fics, + pages = "69--76", + URL = "http://www.irisa.fr/lande/REQS/fics02.ps", +} + +@InProceedings{jha-al-02, + author = "Somesh Jha and Jens Palsberg and Tian Zhao", + title = "Efficient Type Matching", + booktitle = fossacs, + pages = "187--204", + year = "2002", + publisher = springer, + series = lncs, + volume = "2303", + URL = "http://www.cs.ucla.edu/~palsberg/paper/fossacs02.pdf", +} + +@InProceedings{jia-05, + author = "Limin Jia and Frances Spalding and David Walker and + Neal Glew", + title = "Certifying Compilation for a Language with Stack + Allocation", + booktitle = lics, + year = "2005", + URL = "http://www.cs.princeton.edu/~dpw/papers/stackcert-lics05.pdf", + pages = "407--416", +} + +@InProceedings{jia-walker-06, + author = "Limin Jia and David Walker", + title = "{ILC}: {A} Foundation for Automated Reasoning About + Pointer Programs", + booktitle = esop, + year = "2006", + pages = "131--145", + publisher = springer, + series = lncs, + volume = "3924", + URL = "http://sip.cs.princeton.edu/pub/ilc-esop06.pdf", +} + +@InProceedings{jim-00, + author = "Trevor Jim", + title = "A Polar Type System", + booktitle = itrs, + year = "2000", + volume = "8", + series = pi, + publisher = carleton, + URL = "http://www.cee.hw.ac.uk/~jbw/itrs/itrs00/papers/Jim:ITRS-2000.ps.gz", +} + +@TechReport{jim-95, + author = "Trevor Jim", + title = "What are principal typings and what are they good + for?", + institution = "Massachusetts Institute of Technology", + year = "1995", + number = "MIT/LCS TM-532", + URL = "http://www.research.att.com/~trevor/papers/principal-typings.ps.gz", +} + +@Unpublished{jim-palsberg-99, + author = "Trevor Jim and Jens Palsberg", + title = "Type inference in systems of recursive types with + subtyping", + year = "1999", + note = "Manuscript", + URL = "http://www.cs.ucla.edu/~palsberg/draft/jim-palsberg99.pdf", +} + +@Manual{jml, + title = "{JML} Reference Manual", + author = "Gary T. Leavens and Erik Poll and Curtis Clifton and + Yoonsik Cheon and Clyde Ruby and David Cok and Peter + Müller and Joseph Kiniry and Patrice Chalin and Daniel + M. Zimmerman", + year = "2008", + URL = "http://www.jmlspecs.org/OldReleases/jmlrefman.pdf", +} + +@Article{jml-05, + author = "Lilian Burdy and Yoonsik Cheon and David Cok and + Michael Ernst and Joe Kiniry and Gary T. Leavens and K. + Rustan M. Leino and Erik Poll", + title = "An overview of {JML} tools and applications", + journal = sttt, + year = "2005", + volume = "7", + number = "3", + pages = "212--232", + URL = "http://research.microsoft.com/en-us/um/people/leino/papers/jml-sttt.pdf", +} + +@TechReport{johnson-75, + author = "Stephen C. Johnson", + title = "Yacc: Yet Another Compiler-Compiler", + institution = "Bell Laboratories", + year = "1975", + type = "Computing Science Technical Report", + number = "32", + URL = "http://dinosaur.compilertools.net/yacc/yacc.ps", +} + +@InProceedings{johnson-walz-86, + author = "Gregory F. Johnson and Janet A. Walz", + title = "A maximum-flow approach to anomaly isolation in + unification-based incremental type inference", + booktitle = popl, + pages = "44--57", + year = "1986", +} + +@InCollection{johnson-yacc-79, + author = "Steven C. Johnson", + title = "{Yacc}: Yet Another Compiler Compiler", + booktitle = "{UNIX} Programmer's Manual", + volume = "2", + publisher = "Holt, Rinehart, and Winston", + pages = "353--387", + year = "1979", + URL = "http://dinosaur.compilertools.net/", +} + +@InCollection{johnsson-85, + author = "Thomas Johnsson", + editor = "Jean-Pierre Jouannaud", + title = "Lambda Lifting: Transforming Programs to Recursive + Equations", + booktitle = fpca, + series = lncs, + volume = "201", + pages = "190--203", + publisher = springer, + year = "1985", + URL = "http://dx.doi.org/10.1007/3-540-15975-4_37", +} + +@InProceedings{jones-92, + author = "Mark P. Jones", + title = "A theory of qualified types", + booktitle = esop, + year = "1992", + volume = "582", + series = lncs, + publisher = springer, + URL = "http://web.cecs.pdx.edu/~mpj/pubs/esop92.html", +} + +@Book{jones-94, + author = "Mark P. Jones", + title = "Qualified Types: Theory and Practice", + publisher = cup, + year = "1994", +} + +@TechReport{jones-95, + author = "Mark P. Jones", + title = "From {Hindley-Milner} Types to First-Class + Structures", + institution = "Yale University", + year = "1995", + type = "Research Report", + number = "YALEU/DCS/RR-1075", + URL = "http://web.cecs.pdx.edu/~mpj/pubs/haskwork95.html", +} + +@InProceedings{jones-96, + author = "Mark P. Jones", + title = "Using Parameterized Signatures to Express Modular + Structure", + booktitle = popl, + year = "1996", + URL = "http://web.cecs.pdx.edu/~mpj/pubs/paramsig.html", +} + +@InProceedings{jones-dictionary-94, + author = "Mark P. Jones", + title = "Dictionary-free Overloading by Partial Evaluation", + booktitle = pepm, + year = "1994", + URL = "http://web.cecs.pdx.edu/~mpj/pubs/pepm94.ps", +} + +@InProceedings{jones-peyton-jones-99, + author = "Mark P. Jones and Simon {Peyton Jones}", + title = "Lightweight Extensible Records for {Haskell}", + booktitle = hw, + year = "1999", + URL = "http://web.cecs.pdx.edu/~mpj/pubs/recpro.ps.gz", +} + +@TechReport{jones-qualified-94, + author = "Mark P. Jones", + institution = "Yale University", + title = "Simplifying and Improving Qualified Types", + year = "1994", + number = "YALEU/DCS/RR-1040", + URL = "ftp://nebula.cs.yale.edu/pub/yale-fp/reports/RR-1040.ps.Z", +} + +@InProceedings{jones-thih-99, + author = "Mark P. Jones", + title = "Typing {Haskell} in {Haskell}", + booktitle = hw, + year = "1999", + URL = "http://web.cecs.pdx.edu/~mpj/thih/", +} + +@InProceedings{jorgensen-93, + author = "Niels Jørgensen", + title = "Chaotic Fixpoint Iteration Guided by Dynamic + Dependency", + booktitle = wsa, + year = "1993", + pages = "27--44", + series = lncs, + volume = "724", + publisher = springer, + URL = "http://webhotel2.ruc.dk/nielsj/research/publications/wsa93.ps", +} + +@InProceedings{jost-hammond-loidl-hofmann-10, + author = "Steffen Jost and Kevin Hammond and Hans{-}Wolfgang + Loidl and Martin Hofmann", + title = "Static determination of quantitative resource usage + for higher-order programs", + booktitle = popl, + pages = "223--236", + year = "2010", + URL = "http://www2.tcs.ifi.lmu.de/~jost/research/POPL_2010__Higher-Order_AA__Jost_etAl.pdf", +} + +@InProceedings{jost-loidl-hammond-scaife-hofmann-09, + author = "Steffen Jost and Hans{-}Wolfgang Loidl and Kevin + Hammond and Norman Scaife and Martin Hofmann", + title = "{"}Carbon Credits{"} for Resource-Bounded Computations + Using Amortised Analysis", + booktitle = fm, + pages = "354--369", + year = "2009", + series = lncs, + volume = "5850", + publisher = springer, + URL = "http://www2.tcs.ifi.lmu.de/~jost/research/FM09_AmortisedAnalysis__Jost_etAl.pdf", +} + +@TechReport{jouannaud-kirchner-90, + author = "Jean-Pierre Jouannaud and Claude Kirchner", + title = "Solving equations in abstract algebras: a rule-based + survey of unification", + institution = "Université Paris-Sud", + number = "561", + year = "1990", +} + +@InCollection{jouannaud-kirchner-91, + author = "Jean-Pierre Jouannaud and Claude Kirchner", + title = "Solving equations in abstract algebras: a rule-based + survey of unification", + booktitle = "Computational Logic. Essays in honor of Alan + Robinson", + publisher = mitp, + year = "1991", + editor = "Jean-Louis Lassez and Gordon Plotkin", + chapter = "8", + pages = "257--321", +} + +@InProceedings{jourdan-leroy-pottier-12, + author = "Jacques-Henri Jourdan and François Pottier and Xavier + Leroy", + title = "Validating ${LR}(1)$ Parsers", + year = "2012", + booktitle = esop, + publisher = springer, + series = lncs, + volume = "7211", + pages = "397--416", + URL = "http://gallium.inria.fr/~fpottier/publis/jourdan-leroy-pottier-validating-parsers.pdf", +} + +@InProceedings{jourdan-verasco-15, + author = "Jacques{-}Henri Jourdan and Vincent Laporte and + Sandrine Blazy and Xavier Leroy and David Pichardie", + title = "A Formally-Verified {C} Static Analyzer", + booktitle = popl, + pages = "247--259", + year = "2015", + URL = "http://gallium.inria.fr/~xleroy/publi/verasco-popl2015.pdf", +} + +@InProceedings{jung-15, + author = "Ralf Jung and David Swasey and Filip Sieczkowski and + Kasper Svendsen and Aaron Turon and Lars Birkedal and + Derek Dreyer", + title = "Iris: Monoids and Invariants as an Orthogonal Basis + for Concurrent Reasoning", + booktitle = popl, + pages = "637--650", + year = "2015", + URL = "http://plv.mpi-sws.org/iris/paper.pdf", +} + +@Article{kam-ullman-76, + author = "John B. Kam and Jeffrey D. Ullman", + title = "Global Data Flow Analysis and Iterative Algorithms", + journal = jacm, + year = "1976", + volume = "23", + number = "1", + pages = "158--171", + URL = "http://doi.acm.org/10.1145/321921.321938", +} + +@Article{kam-ullman-77, + author = "John B. Kam and Jeffrey D. Ullman", + title = "Monotone Data Flow Analysis Frameworks", + journal = acta, + year = "1977", + volume = "7", + number = "3", + pages = "305--317", + URL = "http://dx.doi.org/10.1007/BF00290339", +} + +@InProceedings{kammar-lindley-oury-13, + author = "Ohad Kammar and Sam Lindley and Nicolas Oury", + title = "Handlers in action", + booktitle = icfp, + pages = "145--158", + year = "2013", + URL = "http://homepages.inf.ed.ac.uk/slindley/papers/handlers.pdf", +} + +@PhdThesis{kanig-10, + author = "Johannes Kanig", + title = "Specification and Proof of Higher-Order Programs", + school = "Université Paris-Sud", + year = "2010", + URL = "http://www.lri.fr/~kanig/files/thesis-kanig-15112010.pdf", +} + +@Article{kantorowitz-laor-86, + author = "E. Kantorowitz and H. Laor", + title = "Automatic generation of useful syntax error messages", + journal = spe, + volume = "16", + number = "7", + publisher = "John Wiley \& Sons", + URL = "http://dx.doi.org/10.1002/spe.4380160703", + pages = "627--640", + year = "1986", +} + +@InProceedings{kaplan-shafrir-tarjan-02, + author = "Haim Kaplan and Nira Shafrir and Robert E. Tarjan", + title = "Union-find with deletions", + booktitle = soda, + pages = "19--28", + year = "2002", + URL = "http://dl.acm.org/citation.cfm?id=545381.545384", +} + +@Article{kaplan-tarjan-99, + author = "Haim Kaplan and Robert E. Tarjan", + title = "Purely functional, real-time deques with catenation", + journal = jacm, + volume = "46", + number = "5", + year = "1999", + pages = "577--603", + URL = "http://www.math.tau.ac.il/~haimk/bob.ps", +} + +@Article{kapur-zhang-rrl, + author = "Deepak Kapur and Hantao Zhang", + title = "An overview of {Rewrite Rule Laboratory (RRL)}", + journal = "J. Comput. Appl. Math.", + year = "1995", + volume = "29", + number = "2", + pages = "91--114", + URL = "ftp://ftp.cs.albany.edu/pub/ipl/papers/overview.rrl.ps.gz", +} + +@TechReport{kashiwagi-wise-91, + author = "Yugo Kashiwagi and David S. Wise", + title = "Graph Algorithms in a Lazy Functional Programming + Language", + institution = "Indiana University", + year = "1991", + type = "Technical Report", + number = "330", + URL = "http://www.cs.indiana.edu/pub/techreports/TR330.pdf", +} + +@InProceedings{kassios-06, + author = "Ioannis T. Kassios", + title = "Dynamic Frames: Support for Framing, Dependencies and + Sharing Without Restrictions", + booktitle = fm, + year = "2006", + pages = "268--283", + publisher = springer, + series = lncs, + volume = "4085", + URL = "http://n.ethz.ch/~kassiosi/papers/fm06.pdf", +} + +@PhdThesis{keinanen-06, + author = "Misa Keinänen", + title = "Techniques For Solving {Boolean} Equation Systems", + school = "Helsinki University of Technology", + year = "2006", + note = "Research Report HUT-TCS-A105", + URL = "http://www.tcs.hut.fi/Publications/bibdb/HUT-TCS-A105.pdf", +} + +@Article{keisu-94, + author = "Torbjörn Keisu", + title = "Finite and Rational Tree Constraints", + journal = "Bulletin of the {IGPL}", + year = "1994", + volume = "2", + number = "2", + pages = "167--204", + URL = "http://www.dcs.kcl.ac.uk/journals/igpl/IGPL/V2-2/Keisu.ps.gz", +} + +@PhdThesis{keisu-phd-94, + author = "Torbjörn Keisu", + title = "Tree Constraints", + school = "The Royal Institute of Technology (KTH)", + year = "1994", + URL = "ftp://ftp.sics.se/pub/ps/papers/torbjorn-keisu-thesis.ps.gz", +} + +@InProceedings{kennedy-07, + author = "Andrew Kennedy", + title = "Compiling with continuations, continued", + booktitle = icfp, + year = "2007", + pages = "177--190", + URL = "http://research.microsoft.com/~akenn/sml/CompilingWithContinuationsContinued.pdf", +} + +@InProceedings{kennedy-75, + author = "Ken W. Kennedy", + title = "Node listings applied to data flow analysis", + booktitle = popl, + year = "1975", + pages = "10--21", + URL = "http://doi.acm.org/10.1145/512976.512978", +} + +@InProceedings{kennedy-94, + author = "Andrew Kennedy", + title = "Dimension Types", + booktitle = esop, + year = "1994", + volume = "788", + series = lncs, + publisher = springer, + URL = "http://research.microsoft.com/~akenn/units/DimensionTypes.pdf", +} + +@TechReport{kennedy-96, + author = "Andrew Kennedy", + title = "Type Inference and Equational Theories", + institution = "École Polytechnique", + year = "1996", + number = "LIX/RR/96/09", +} + +@InProceedings{kerber-91, + author = "Manfred Kerber", + title = "How to Prove Higher Order Theorems in First Order + Logic", + booktitle = ijcai, + year = "1991", + pages = "137--142", + URL = "ftp://ftp.cs.bham.ac.uk/pub/authors/M.Kerber/91-IJCAI.pdf", +} + +@Book{kernighan-ritchie-88, + author = "Brian W. Kernighan and Dennis Ritchie", + title = "The {C} Programming Language, Second Edition", + publisher = prentice, + year = "1988", +} + +@Unpublished{keuchel-schrijvers-inbound-15, + author = "Steven Keuchel and Tom Schrijvers", + title = "\textsc{InBound}: simple yet powerful specification of + syntax with binders", + note = "Unpublished", + year = "2015", + URL = "http://users.ugent.be/~skeuchel/publications/inbound.pdf", +} + +@InProceedings{kfoury-ml-90, + author = "Assaf J. Kfoury and Jerzy Tiuryn and Pawel Urzyczyn", + title = "{ML} Typability is {DEXPTIME}-Complete", + booktitle = "Colloquium on Trees in Algebra and Programming", + publisher = springer, + series = lncs, + volume = "431", + pages = "206--220", + year = "1990", + URL = "http://dx.doi.org/10.1007/3-540-52590-4_50", +} + +@Article{kfoury-recursion-93, + author = "A. J. Kfoury and J. Tiuryn and P. Urzyczyn", + title = "Type reconstruction in the presence of polymorphic + recursion", + journal = toplas, + volume = "15", + number = "2", + year = "1993", + pages = "290--311", + URL = "http://doi.acm.org/10.1145/169701.169687", +} + +@Article{kfoury-wells-2004, + author = "Assaf J. Kfoury and J. B. Wells", + title = "Principality and Type Inference for Intersection Types + Using Expansion Variables", + journal = tcs, + volume = "311", + number = "1--3", + pages = "1--70", + year = "2004", + URL = "http://www.church-project.org/reports/Kfo+Wel:TCSB-2004-v311n1-3.html", +} + +@Unpublished{kieburtz-02, + author = "Richard B. Kieburtz", + title = "${P}$-logic: Property verification for {Haskell} + programs", + note = "Draft", + year = "2002", + URL = "http://www.cse.ogi.edu/PacSoft/projects/programatica/plogic.pdf", +} + +@InProceedings{kieburtz-98, + author = "Richard B. Kieburtz", + title = "Taming effects with monadic typing", + booktitle = icfp, + year = "1998", + pages = "51--62", + URL = "http://doi.acm.org/10.1145/289423.289428", +} + +@InProceedings{kildall-73, + author = "Gary A. Kildall", + title = "A unified approach to global program optimization", + booktitle = popl, + year = "1973", + pages = "194--206", + URL = "http://doi.acm.org/10.1145/512927.512945", +} + +@InProceedings{kim-yi-calcagno-06, + author = "Ik-Soon Kim and Kwangkeun Yi and Cristiano Calcagno", + title = "A polymorphic modal type system for {Lisp}-like + multi-staged languages", + booktitle = popl, + year = "2006", + pages = "257--268", + URL = "http://www.doc.ic.ac.uk/~ccris/ftp/06-popl-kiyicr.pdf", +} + +@InProceedings{king-wadler-92, + author = "David King and Philip Wadler", + title = "Combining Monads", + booktitle = "Workshop on Functional Programming", + publisher = springer, + year = "1992", + URL = "http://homepages.inf.ed.ac.uk/wadler/papers/monadscomb/monadscomb.ps.gz", +} + +@InProceedings{kiselyov-shan-07, + author = "Oleg Kiselyov and Chung{-}chieh Shan", + title = "A Substructural Type System for Delimited + Continuations", + booktitle = tlca, + pages = "223--239", + year = "2007", + series = lncs, + volume = "4583", + publisher = springer, + URL = "http://homes.soic.indiana.edu/ccshan/binding/context.pdf", +} + +@Article{klein-seL4-2010, + author = "Gerwin Klein and June Andronick and Kevin Elphinstone + and Gernot Heiser and David Cock and Philip Derrin and + Dhammika Elkaduwe and Kai Engelhardt and Rafal Kolanski + and Michael Norrish and Thomas Sewell and Harvey Tuch + and Simon Winwood", + title = "{seL4}: formal verification of an operating-system + kernel", + journal = cacm, + volume = "53", + number = "6", + year = "2010", + pages = "107--115", + URL = "http://ertos.nicta.com.au/publications/papers/Klein_EHACDEEKNSTW_10.pdf", +} + +@Article{klint-laemmel-verhoef-05, + author = "Paul Klint and Ralf L{\"a}mmel and Chris Verhoef", + title = "{Toward an engineering discipline for grammarware}", + journal = tosem, + volume = "14", + number = "3", + year = "2005", + pages = "331--380", + URL = "http://www.few.vu.nl/~x/gw/gw.pdf", +} + +@InProceedings{kloos-majumdar-vafeiadis-15, + author = "Johannes Kloos and Rupak Majumdar and Viktor + Vafeiadis", + title = "Asynchronous Liquid Separation Types", + booktitle = ecoop, + pages = "396--420", + year = "2015", + URL = "https://www.mpi-sws.org/~viktor/papers/ecoop2015-alstypes.pdf", +} + +@Article{kmp-77, + author = "James H. Morris and Donald E. Knuth and Vaughan R. + Pratt", + title = "Fast Pattern Matching in Strings", + journal = siamjc, + year = "1977", + volume = "6", + number = "2", + pages = "323--350", + URL = "http://locus.siam.org/fulltext/SICOMP/volume-06/0206024.pdf", +} + +@Article{knight-89, + author = "Kevin Knight", + title = "Unification: a multidisciplinary survey", + journal = surveys, + year = "1989", + volume = "21", + number = "1", + pages = "93--124", + URL = "http://doi.acm.org/10.1145/62029.62030", +} + +@Article{knuth-77, + author = "Donald E. Knuth", + title = "A Generalization of {Dijkstra}'s Algorithm", + journal = ipl, + year = "1977", + volume = "6", + number = "1", + pages = "1--5", +} + +@Article{knuth-lr-65, + author = "Donald E. Knuth", + title = "On the translation of languages from left to right", + journal = "Information \& Control", + year = "1965", + volume = "8", + number = "6", + pages = "607--639", + URL = "http://www.sciencedirect.com/science/article/pii/S0019995865904262", +} + +@InProceedings{kobayashi-implicit-00, + author = "Naoki Kobayashi and Shin Saito and Eijiro Sumii", + title = "An Implicitly-Typed Deadlock-Free Process Calculus", + booktitle = concur, + publisher = springer, + series = lncs, + volume = "1877", + year = "2000", + pages = "489--503", + URL = "http://www.yl.is.s.u-tokyo.ac.jp/members/koba/papers/deadlock-inference-concur.ps.gz", +} + +@Article{kobayashi-linearity-99, + author = "Naoki Kobayashi and Benjamin C. Pierce and David N. + Turner", + title = "Linearity and the {Pi-Calculus}", + journal = toplas, + volume = "21", + number = "5", + pages = "914--947", + year = "1999", + URL = "http://doi.acm.org/10.1145/330249.330251", +} + +@Article{kobayashi-partial-98, + author = "Naoki Kobayashi", + title = "A Partially Deadlock-Free Typed Process Calculus", + journal = toplas, + volume = "20", + number = "2", + pages = "436--482", + year = "1998", + URL = "http://doi.acm.org/10.1145/276393.278524", +} + +@InProceedings{kobayashi-sumii-98, + author = "Eijiro Sumii and Naoki Kobayashi", + title = "A Generalized Deadlock-Free Process Calculus", + booktitle = hlcl, + year = "1998", + volume = "16", + series = entcs, + publisher = elsevier, + pages = "55--77", + URL = "http://www1.elsevier.com/gej-ng/31/29/23/40/26/39/tcs16.3.006.ps", +} + +@InProceedings{kobayashi-useless-00, + author = "Naoki Kobayashi", + title = "Type-based useless variable elimination", + pages = "84--93", + booktitle = pepm, + year = "2000", + URL = "http://www.yl.is.s.u-tokyo.ac.jp/members/koba/papers/PEPM00.ps.gz", +} + +@Article{koda-ruskey-93, + author = "Yasunori Koda and Frank Ruskey", + title = "A {Gray} Code for the Ideals of a Forest Poset", + journal = "Journal of Algorithms", + volume = "15", + number = "2", + year = "1993", + pages = "324--340", + URL = "http://www.cs.uvic.ca/~ruskey/Publications/ForestIdeals.ps", +} + +@InProceedings{kohlbecker-hygienic-86, + author = "Eugene Kohlbecker and Daniel P. Friedman and Matthias + Felleisen and Bruce Duba", + title = "Hygienic macro expansion", + booktitle = lfp, + year = "1986", + pages = "151--161", + URL = "http://doi.acm.org/10.1145/319838.319859", +} + +@InProceedings{kohlbecker-wand-87, + author = "Eugene E. Kohlbecker and Mitchell Wand", + title = "Macro-by-example: Deriving syntactic transformations + from their specifications", + booktitle = popl, + year = "1987", + pages = "77--84", + URL = "http://doi.acm.org/10.1145/41625.41632", +} + +@InProceedings{konat-13, + author = "Gabri{\"e}l Konat and Lennart Kats and Guido Wachsmuth + and Eelco Visser", + title = "Declarative Name Binding and Scope Rules", + booktitle = sle, + year = "2013", + publisher = springer, + volume = "7745", + series = lncs, + pages = "311--331", + URL = "http://swerl.tudelft.nl/twiki/pub/Main/TechnicalReports/TUD-SERG-2012-015.pdf", +} + +@InProceedings{koprowski-binsztok-10, + author = "Adam Koprowski and Henri Binsztok", + title = "{TRX}: {A} Formally Verified Parser Interpreter", + booktitle = esop, + year = "2010", + pages = "345--365", + publisher = "Springer", + series = lncs, + volume = "6012", + URL = "http://adam-koprowski.net/papers/trx-ESOP-10.pdf", +} + +@Article{koprowski-binsztok-11, + author = "Adam Koprowski and Henri Binsztok", + title = "{TRX}: {A} Formally Verified Parser Interpreter", + journal = lmcs, + year = "2011", + volume = "7", + number = "2", + URL = "http://arxiv.org/pdf/1105.2576", +} + +@InProceedings{koved-al-02, + author = "Larry Koved and Marco Pistoia and Aaron Kershenbaum", + title = "Access rights analysis for {Java}", + pages = "359--372", + booktitle = oopsla, + year = "2002", + URL = "http://www.research.ibm.com/javasec/OOPSLA2002preprint.pdf", +} + +@Book{kozen-91, + author = "Dexter C. Kozen", + title = "The design and analysis of algorithms", + year = "1992", + series = "Texts and Monographs in Computer Science", + publisher = springer, + URL = "http://www.cs.cornell.edu/~kozen/papers/daa.pdf", +} + +@Article{kozen-palsberg-schwartzbach-95, + author = "Dexter Kozen and Jens Palsberg and Michael I. + Schwartzbach", + title = "Efficient Recursive Subtyping", + journal = mscs, + volume = "5", + number = "1", + pages = "113--125", + year = "1995", + URL = "http://www.cs.ucla.edu/~palsberg/paper/mscs95-kps.pdf", +} + +@InProceedings{krebbers-17, + author = "Robert Krebbers and Amin Timany and Lars Birkedal", + title = "Interactive proofs in higher-order concurrent + separation logic", + booktitle = popl, + year = "2017", + URL = "http://cs.au.dk/~birke/papers/ipm-conf.pdf", +} + +@InProceedings{krishnamurthi-99, + author = "Shriram Krishnamurthi and Matthias Felleisen and Bruce + F. Duba", + title = "From Macros to Reusable Generative Programming", + booktitle = gcse, + pages = "105--120", + year = "1999", + volume = "1799", + series = lncs, + publisher = springer, + URL = "http://www.cs.brown.edu/~sk/Publications/Papers/Published/kfd-macro-to-gen-prog/paper.ps", +} + +@PhdThesis{krishnaswami-12, + author = "Neelakantan R. Krishnaswami", + title = "Verifying Higher-Order Imperative Programs with + Higher-Order Separation Logic", + school = "School of Computer Science, Carnegie Mellon + University", + year = "2012", + URL = "http://www.cs.cmu.edu/~neelk/thesis.pdf", +} + +@InProceedings{krishnaswami-design-patterns-09, + author = "Neelakantan R. Krishnaswami and Jonathan Aldrich and + Lars {Bir\-ke\-dal} and Kasper Svendsen and Alexandre + Buisse", + title = "Design Patterns in Separation Logic", + booktitle = tldi, + pages = "105--116", + year = "2009", + URL = "http://www.cs.cmu.edu/~neelk/design-patterns-tldi09.pdf", +} + +@InProceedings{krishnaswami-sharing-12, + author = "Neelakantan R. Krishnaswami and Aaron Turon and Derek + Dreyer and Deepak Garg", + title = "Superficially substructural types", + booktitle = icfp, + year = "2012", + pages = "41--54", + URL = "http://www.mpi-sws.org/~neelk/icfp12-superficial-krishnaswami-turon-dreyer-garg.pdf", +} + +@Book{kroening-strichman-08, + author = "Daniel Kroening and Ofer Strichman", + title = "Decision procedures -- An algorithmic point of view", + publisher = springer, + year = "2008", + URL = "http://www.decision-procedures.org/", +} + +@InProceedings{kuan-07, + author = "George Kuan and David MacQueen", + title = "Efficient type inference using ranked type variables", + booktitle = ml, + year = "2007", + pages = "3--14", + URL = "http://people.cs.uchicago.edu/~gkuan/pubs/ml07-km.pdf", +} + +@InProceedings{kuncak-rinard-03, + author = "Viktor Kuncak and Martin Rinard", + title = "Structural Subtyping of Non-Recursive Types is + Decidable", + booktitle = lics, + year = "2003", + URL = "http://www.cag.lcs.mit.edu/~rinard/paper/lics03.pdf", +} + +@TechReport{kuncak-rinard-tr-03, + author = "Viktor Kuncak and Martin Rinard", + title = "On the Theory of Structural Subtyping", + institution = "MIT Laboratory for Computer Science", + year = "2003", + number = "879", + URL = "http://www.mit.edu/people/vkuncak/papers/TheoryStructuralSubtyping.ps", +} + +@InProceedings{laemmel-00, + author = "Ralf Lämmel and Joost Visser and Jan Kort", + title = "Dealing with Large Bananas", + pages = "46--59", + booktitle = wgp, + year = "2000", + URL = "http://homepages.cwi.nl/~ralf/wgp00.ps", +} + +@Unpublished{laemmel-scrap-05, + author = "Ralf Lämmel and Simon {Peyton Jones}", + title = "Scrap your boilerplate with class: extensible generic + functions", + note = "Submitted", + year = "2005", + URL = "http://research.microsoft.com/Users/simonpj/papers/hmap/gmap3.ps", +} + +@InProceedings{lai-user-99, + author = "Charlie Lai and Li Gong and Larry Koved and Anthony J. + Nadalin and Roland Schemers", + title = "User Authentication and Authorization in the {Java} + Platform", + booktitle = acsac, + pages = "285--290", + year = "1999", + URL = "http://www.acsac.org/1999/papers/thu-b-1500-lai.pdf", +} + +@InProceedings{lammich-13, + author = "Peter Lammich", + title = "Automatic Data Refinement", + booktitle = itp, + pages = "84--99", + year = "2013", + volume = "7998", + series = lncs, + publisher = springer, + URL = "http://www21.in.tum.de/~lammich/pub/autoref.pdf", +} + +@InProceedings{lammich-14, + author = "Peter Lammich", + title = "Verified Efficient Implementation of {Gabow}'s + Strongly Connected Component Algorithm", + booktitle = itp, + year = "2014", + pages = "325--340", + publisher = springer, + series = lncs, + volume = "8558", + URL = "http://www21.in.tum.de/~lammich/pub/gabow_scc.pdf", +} + +@InProceedings{lammich-15, + author = "Peter Lammich", + title = "Refinement to {Imperative/HOL}", + booktitle = itp, + pages = "253--269", + year = "2015", + series = lncs, + volume = "9236", + publisher = springer, + URL = "https://www21.in.tum.de/~lammich/pub/itp15_sepref.pdf", +} + +@InProceedings{lammich-16, + author = "Peter Lammich", + title = "Refinement Based Verification of Imperative Data + Structures", + booktitle = cpp, + year = "2016", + pages = "27--36", + URL = "https://www21.in.tum.de/~lammich/pub/cpp2016_impds.pdf", +} + +@InProceedings{lammich-lochbihler-10, + author = "Peter Lammich and Andreas Lochbihler", + title = "The {Isabelle} Collections Framework", + booktitle = itp, + pages = "339--354", + year = "2010", + series = lncs, + volume = "6172", + publisher = springer, + URL = "http://cs.uni-muenster.de/sev/publications/itp10.pdf", +} + +@Article{lammich-meis-12, + author = "Peter Lammich and Rene Meis", + title = "A Separation Logic Framework for {Imperative HOL}", + journal = "Archive of Formal Proofs", + year = "2012", + URL = "http://afp.sourceforge.net/entries/Separation_Logic_Imperative_HOL.shtml", +} + +@Article{lampson-73, + author = "Butler W. Lampson", + title = "A Note on the Confinement Problem", + journal = cacm, + volume = "16", + number = "10", + pages = "613--615", + year = "1973", + URL = "http://research.microsoft.com/lampson/11-Confinement/WebPage.html", +} + +@Article{landin-64, + author = "Peter J. Landin", + title = "The Mechanical Evaluation of Expressions", + journal = cj, + volume = "6", + number = "4", + year = "1964", + pages = "308--320", +} + +@Article{landin-65, + author = "Peter J. Landin", + title = "Correspondence between {ALGOL} 60 and {Church's} + Lambda-notation: part {I}", + journal = cacm, + volume = "8", + number = "2", + year = "1965", + pages = "89--101", + URL = "http://doi.acm.org/10.1145/363744.363749", +} + +@PhdThesis{larus-89, + author = "James Richard Larus", + title = "Restructuring Symbolic Programs for Concurrent + Execution on Multiprocessors", + school = "EECS Department, University of California, Berkeley", + year = "1989", + note = "Technical Report UCB/CSD-89-502", + URL = "http://www.eecs.berkeley.edu/Pubs/TechRpts/1989/CSD-89-502.pdf", +} + +@InProceedings{lassen-06, + author = "Soren B. Lassen", + title = "Head Normal Form Bisimulation for Pairs and the + $\lambda\mu$-Calculus", + booktitle = lics, + year = "2006", + pages = "297--306", + URL = "http://www.blassen.dk/soren/papers/2006lics.pdf", +} + +@InProceedings{lassen-99, + author = "Soren B. Lassen", + title = "Bisimulation in untyped lambda calculus: {Böhm} trees + and bisimulation up to context", + booktitle = mfps, + pages = "346--374", + year = "1999", + volume = "20", + series = entcs, + publisher = elsevier, + URL = "http://www.blassen.dk/soren/papers/1999mfps15.ps", +} + +@InCollection{lassez-al-88, + author = "Jean-Louis Lassez and Michael J. Maher and Kim G. + Marriott", + editor = "Jack Minker", + booktitle = "Foundations of Deductive Databases and Logic + Programming", + title = "Unification Revisited", + chapter = "15", + publisher = "Morgan Kaufmann", + year = "1988", + pages = "587--625", +} + +@Article{lassez-nguyen-sonenberg-82, + author = "Jean-Louis Lassez and V. L. Nguyen and Liz Sonenberg", + title = "Fixed point theorems and semantics: a folk tale", + journal = ipl, + year = "1982", + volume = "14", + number = "3", + pages = "112--116", + URL = "http://dx.doi.org/10.1016/0020-0190(82)90065-5", +} + +@InProceedings{laufer-odersky-92, + author = "Martin Odersky and Konstantin Läufer", + title = "An Extension of {ML} with First-Class Abstract Types", + year = "1992", + booktitle = mlapp, + pages = "78--91", + URL = "http://www.cs.luc.edu/laufer/papers/ml92.pdf", +} + +@Article{laufer-odersky-94, + author = "Konstantin L{\"a}ufer and Martin Odersky", + title = "Polymorphic Type Inference and Abstract Data Types", + journal = toplas, + year = "1994", + pages = "1411--1430", + volume = "16", + number = "5", + URL = "http://www.cs.luc.edu/laufer/papers/toplas94.pdf", +} + +@Article{launchbury-peyton-jones-95, + author = "John Launchbury and Simon {Peyton Jones}", + title = "State in {Haskell}", + journal = "{LISP} and Symbolic Computation", + publisher = springer, + pages = "293--341", + year = "1995", + volume = "8", + number = "4", + URL = "http://dx.doi.org/10.1007/BF01018827", +} + +@InProceedings{laviron-chang-rival-10, + author = "Vincent Laviron and Bor-Yuh Evan Chang and Xavier + Rival", + title = "Separating Shape Graphs", + booktitle = esop, + year = "2010", + pages = "387--406", + publisher = springer, + series = lncs, + volume = "6012", + URL = "http://xisa.cs.colorado.edu/papers/esop10-sepshapegraph.pdf", +} + +@TechReport{le-charlier-van-hentenryck-92, + author = "Baudouin {Le Charlier} and Pascal {Van Hentenryck}", + title = "A Universal Top-Down Fixpoint Algorithm", + institution = "Brown University", + year = "1992", + type = "Technical Report", + number = "CS-92-25", + URL = "ftp://ftp.cs.brown.edu/pub/techreports/92/cs92-25.ps.gz", +} + +@Article{le-metayer-88, + author = "Daniel {Le Métayer}", + title = "{ACE:} An Automatic Complexity Evaluator", + journal = toplas, + volume = "10", + number = "2", + pages = "248--266", + year = "1988", + URL = "http://doi.acm.org/10.1145/42190.42347", +} + +@Article{league-02, + author = "Christopher League and Zhong Shao and Valery + Trifonov", + title = "Type-Preserving Compilation of {Featherweight} + {Java}", + journal = toplas, + year = "2002", + volume = "24", + number = "2", + pages = "112--152", + URL = "http://flint.cs.yale.edu/flint/publications/fj-toplas.html", +} + +@InProceedings{league-03, + author = "Christopher League and Zhong Shao and Valery + Trifonov", + title = "Precision in Practice: a Type-Preserving {Java} + Compiler", + booktitle = cc, + pages = "106--120", + year = "2003", + volume = "2622", + series = lncs, + publisher = springer, + URL = "http://flint.cs.yale.edu/flint/publications/piptr.html", +} + +@InProceedings{league-99, + author = "Christopher League and Zhong Shao and Valery + Trifonov", + title = "Representing {Java} Classes in a Typed Intermediate + Language", + booktitle = icfp, + pages = "183--196", + year = "1999", + URL = "http://flint.cs.yale.edu/flint/publications/javaflint2.html", +} + +@InProceedings{leavens-baker-99, + author = "Gary T. Leavens and Albert L. Baker", + title = "Enhancing the Pre- and Postcondition Technique for + More Expressive Specifications", + booktitle = fm, + volume = "1709", + series = lncs, + year = "1999", + pages = "1087--1106", + publisher = springer, + URL = "http://dx.doi.org/10.1007/3-540-48118-4_8", +} + +@InProceedings{lebotlan-remy-03, + author = "Didier {Le Botlan} and Didier R{\'e}my", + title = "{MLF}: Raising {ML} to the power of System ${F}$", + booktitle = icfp, + pages = "27--38", + year = "2003", + URL = "http://gallium.inria.fr/~remy/work/mlf/icfp.pdf", +} + +@InProceedings{lebresne-08, + author = "Sylvain Lebresne", + title = "A System ${F}$ with Call-by-Name Exceptions", + booktitle = icalp, + year = "2008", + pages = "323--335", + publisher = springer, + series = lncs, + volume = "5126", + URL = "http://www.pps.jussieu.fr/~lebresne/papers/SystemFWithExceptions.pdf", +} + +@Article{lee-yi-98, + author = "Oukseh Lee and Kwangkeun Yi", + title = "Proofs about a folklore let-polymorphic type inference + algorithm", + journal = toplas, + volume = "20", + number = "4", + year = "1998", + pages = "707--723", + URL = "http://doi.acm.org/10.1145/291891.291892", +} + +@InProceedings{lefessant-maranget-01, + author = "Fabrice {Le Fessant} and Luc Maranget", + title = "Optimizing Pattern Matching", + booktitle = icfp, + year = "2001", + URL = "http://gallium.inria.fr/~maranget/papers/opt-pat.ps.gz", +} + +@TechReport{leijen-algebraic-effects-16, + author = "Daan Leijen", + title = "Algebraic Effects for Functional Programming", + institution = "Microsoft Research", + number = "MSR-TR-2016-29", + year = "2016", + URL = "https://www.microsoft.com/en-us/research/publication/algebraic-effects-for-functional-programming/", +} + +@Article{leino-05, + author = "K. Rustan M. Leino", + title = "Efficient Weakest Preconditions", + journal = ipl, + year = "2005", + volume = "93", + number = "6", + pages = "281--288", + URL = "http://research.microsoft.com/pubs/70052/tr-2004-34.pdf", +} + +@InProceedings{leino-mueller-chalice-09, + author = "K. Rustan M. Leino and Peter M{\"u}ller", + title = "A Basis for Verifying Multi-threaded Programs", + booktitle = esop, + year = "2009", + pages = "378--393", + series = lncs, + volume = "5502", + publisher = springer, + URL = "http://research.microsoft.com/en-us/um/people/leino/papers/krml191.pdf", +} + +@InProceedings{leino-mueller-smans-09, + author = "K. Rustan M. Leino and Peter Müller and Jan Smans", + title = "Verification of Concurrent Programs with {Chalice}", + booktitle = fosad, + year = "2009", + pages = "195--222", + publisher = springer, + series = lncs, + volume = "5705", + URL = "http://research.microsoft.com/en-us/um/people/leino/papers/krml197.pdf", +} + +@InProceedings{leino-mueller-smans-10, + author = "K. Rustan M. Leino and Peter Müller and Jan Smans", + title = "Deadlock-Free Channels and Locks", + booktitle = esop, + year = "2010", + pages = "407--426", + publisher = springer, + series = lncs, + volume = "6012", + URL = "http://research.microsoft.com/en-us/um/people/leino/papers/krml200ext.pdf", +} + +@Article{leino-nelson-02, + author = "K. Rustan M. Leino and Greg Nelson", + title = "Data abstraction and information hiding", + journal = toplas, + volume = "24", + number = "5", + year = "2002", + pages = "491--553", + URL = "http://research.microsoft.com/~leino/papers/krml71.pdf", +} + +@InProceedings{leino-schulte-07, + author = "K. Rustan M. Leino and Wolfram Schulte", + title = "Using History Invariants to Verify Observers", + booktitle = esop, + year = "2007", + pages = "80--94", + publisher = springer, + series = lncs, + volume = "4421", + URL = "http://research.microsoft.com/en-us/um/people/leino/papers/krml166.pdf", +} + +@PhdThesis{leroy-92, + author = "Xavier Leroy", + title = "Typage polymorphe d'un langage algorithmique", + school = "Université Paris 7", + year = "1992", + pages = "196", + URL = "http://gallium.inria.fr/~xleroy/publi/these-doctorat.ps.gz", +} + +@InProceedings{leroy-compcert-06, + author = "Xavier Leroy", + title = "Formal certification of a compiler back-end or: + programming a compiler with a proof assistant", + booktitle = popl, + year = "2006", + pages = "42--54", + URL = "http://gallium.inria.fr/~xleroy/publi/compiler-certif.pdf", +} + +@TechReport{leroy-phd-92, + author = "Xavier Leroy", + title = "Polymorphic typing of an algorithmic language", + institution = "INRIA", + year = "1992", + type = "Research Report", + number = "1778", + URL = "http://gallium.inria.fr/~xleroy/publi/phd-thesis.ps.gz", +} + +@MastersThesis{lescuyer-06, + author = "Stéphane Lescuyer", + title = "Codage de la logique du premier ordre polymorphe + multi-sortée dans la logique sans sortes", + school = "Master Parisien de Recherche en Informatique", + year = "2006", + URL = "http://www.seas.upenn.edu/~lescuyer/pdf/RapportDEA.pdf", +} + +@Article{lescuyer-11, + author = "St{\'{e}}phane Lescuyer", + title = "First-Class Containers in {Coq}", + journal = "Studia Informatica Universalis", + volume = "9", + number = "1", + pages = "87--127", + year = "2011", + URL = "http://studia.complexica.net/Art/RI090103.pdf", +} + +@PhdThesis{letouzey-04, + author = "Pierre Letouzey", + title = "Programmation fonctionnelle certifiée -- l'extraction + de programmes dans l'assistant {Coq}", + school = "Université Paris 11", + year = "2004", + URL = "http://www.lri.fr/~letouzey/download/these_letouzey.ps.gz", +} + +@InProceedings{levy-02, + author = "Paul Blain Levy", + title = "Possible World Semantics for General Storage in + Call-By-Value", + booktitle = csl, + series = lncs, + volume = "2471", + publisher = springer, + year = "2002", + URL = "http://www.cs.bham.ac.uk/~pbl/papers/storagecbv.ps", +} + +@InProceedings{lewis-al-00, + author = "Jeffrey Lewis and Mark Shields and Erik Meijer and + John Launchbury", + title = "Implicit Parameters: Dynamic Scoping with Static + Types", + booktitle = popl, + year = "2000", + pages = "108--118", + URL = "http://www.cse.ogi.edu/~mbs/pub/implicit_parameters/implicit.ps", +} + +@InProceedings{ley-wild-nanevski-subjective-13, + author = "Ruy Ley-Wild and Aleksandar Nanevski", + title = "Subjective auxiliary state for coarse-grained + concurrency", + booktitle = popl, + year = "2013", + pages = "561--574", + URL = "http://software.imdea.org/~aleks/papers/concur/scsl4.pdf", +} + +@InProceedings{lgph-08, + author = "Johan Jeuring and Sean Leather and Jos{\'{e}} Pedro + Magalh{\~{a}}es and Alexey Rodriguez Yakushev", + title = "Libraries for Generic Programming in {Haskell}", + booktitle = afp, + pages = "165--229", + year = "2008", + series = lncs, + volume = "5832", + publisher = springer, + URL = "http://dreixel.net/research/pdf/lgph.pdf", +} + +@InProceedings{licata-harper-09, + author = "Daniel R. Licata and Robert Harper", + title = "A universe of binding and computation", + booktitle = icfp, + year = "2009", + pages = "123--134", + URL = "http://www.cs.cmu.edu/~drl/pubs/lh09unibind/lh09unibind.pdf", +} + +@InProceedings{licata-zeilberger-harper-08, + author = "Daniel R. Licata and Noam Zeilberger and Robert + Harper", + title = "Focusing on Binding and Computation", + booktitle = lics, + year = "2008", + pages = "241--252", + URL = "http://www.cs.cmu.edu/~rwh/papers/focusing/paper.pdf", +} + +@TechReport{licata-zeilberger-harper-08-tr, + author = "Daniel R. Licata and Noam Zeilberger and Robert + Harper", + title = "Focusing on Binding and Computation", + institution = "Carnegie Mellon University", + year = "2008", + number = "CMU-CS-08-101", + URL = "http://www.cs.cmu.edu/~noam/research/lzh08focbind-tr.pdf", +} + +@InProceedings{lindley-mcbride-mclaughlin-17, + author = "Sam Lindley and Conor McBride and Craig McLaughlin", + title = "Do Be Do Be Do", + booktitle = popl, + year = "2017", + URL = "http://homepages.inf.ed.ac.uk/slindley/papers/frankly-draft-july2016.pdf", +} + +@Book{liskov-guttag-01, + author = "Barbara Liskov and John V. Guttag", + title = "Program Development in {Java} -- Abstraction, + Specification, and Object-Oriented Design", + year = "2001", + publisher = aw, + URL = "http://dl.acm.org/citation.cfm?id=556707", +} + +@Article{liskov-wing-94, + author = "Barbara Liskov and Jeannette M. Wing", + title = "A Behavioral Notion of Subtyping", + journal = toplas, + volume = "16", + number = "6", + year = "1994", + pages = "1811--1841", + URL = "http://www.cs.cmu.edu/~wing/publications/LiskovWing94.pdf", +} + +@InProceedings{liu-smolka-98, + author = "Xinxin Liu and Scott A. Smolka", + title = "Simple Linear-Time Algorithms for Minimal Fixed + Points", + booktitle = icalp, + year = "1998", + pages = "53--66", + series = lncs, + volume = "1443", + publisher = springer, + URL = "http://dx.doi.org/10.1007/BFb0055040", +} + +@TechReport{lngen-10, + author = "Brian Aydemir and Stephanie Weirich", + title = "{LNgen}: Tool Support for Locally Nameless + Representations", + institution = "University of Pennsylvania Department of Computer and + Information Science", + year = "2010", + type = "Technical Report", + number = "MS-CIS-10-24", + URL = "http://repository.upenn.edu/cis_reports/933/", +} + +@InProceedings{lochbihler-13, + author = "Andreas Lochbihler", + title = "Light-weight containers for {Isabelle}: efficient, + extensible, nestable", + booktitle = itp, + pages = "116--132", + year = "2013", + series = lncs, + volume = "7998", + publisher = springer, + URL = "https://pp.ipd.kit.edu/uploads/publikationen/lochbihler13itp.pdf", +} + +@InProceedings{longley-99, + author = "John Longley", + title = "When is a Functional Program Not a Functional + Program?", + booktitle = icfp, + year = "1999", + pages = "1--7", + URL = "http://doi.acm.org/10.1145/317636.317775", +} + +@InProceedings{longley-pollack-04, + author = "John Longley and Randy Pollack", + title = "Reasoning About {CBV} Functional Programs in + {Isabelle/HOL}", + booktitle = tphol, + year = "2004", + pages = "201--216", + URL = "http://homepages.inf.ed.ac.uk/rpollack/export/LongleyPollack04.pdf", + publisher = springer, + series = lncs, + volume = "3223", +} + +@InProceedings{lucassen-gifford-88, + author = "John M. Lucassen and David K. Gifford", + title = "Polymorphic effect systems", + booktitle = popl, + year = "1988", + pages = "47--57", + URL = "http://pag.lcs.mit.edu/reading-group/lucassen88effects.pdf", +} + +@InProceedings{mackenzie-wolverson-03, + author = "Kenneth MacKenzie and Nicholas Wolverson", + title = "{Camelot} and {Grail}: resource-aware functional + programming for the {JVM}", + booktitle = tfp, + pages = "29--46", + year = "2003", + volume = "4", + URL = "http://groups.inf.ed.ac.uk/mrg/publications/mrg/camelot.ps", +} + +@Article{macqueen-plotkin-sethi-86, + author = "David B. MacQueen and Gordon D. Plotkin and Ravi + Sethi", + title = "An Ideal Model for Recursive Polymorphic Types", + journal = "Information and Control", + volume = "71", + number = "1--2", + year = "1986", + pages = "95--130", +} + +@PhdThesis{mader-97, + school = "Technische Universität München", + author = "Angelika Mader", + title = "Verification of Modal Properties Using {Boolean} + Equation Systems", + year = "1997", + URL = "http://eprints.eemcs.utwente.nl/1078/02/diss.pdf", +} + +@InProceedings{madhavan-kulal-kuncak-17, + author = "Ravichandhran Madhavan and Sumith Kulal and Viktor + Kuncak", + title = "Contract-based resource verification for higher-order + functions with memoization", + booktitle = popl, + pages = "330--343", + year = "2017", + URL = "http://lara.epfl.ch/~kandhada/orb-popl17.pdf", +} + +@InProceedings{maeda-11, + author = "Toshiyuki Maeda and Haruki Sato and Akinori Yonezawa", + title = "Extended Alias Type System using Separating + Implication", + booktitle = tldi, + year = "2011", + pages = "29--42", + URL = "http://dx.doi.org/10.1145/1929553.1929559", +} + +@InProceedings{maher-88, + author = "Michael J. Maher", + title = "Complete Axiomatizations of the Algebras of Finite, + Rational and Infinite Trees", + booktitle = lics, + pages = "348--357", + year = "1988", +} + +@InProceedings{mairson-90, + author = "Harry G. Mairson", + title = "Deciding {ML} typability is complete for deterministic + exponential time", + booktitle = popl, + year = "1990", + pages = "382--401", + URL = "http://doi.acm.org/10.1145/96709.96748", +} + +@InCollection{mairson-kanellakis-mitchell-91, + author = "Harry G. Mairson and Paris C. Kanellakis and John C. + Mitchell", + title = "Unification and {ML} type reconstruction", + booktitle = "Computational Logic: Essays in Honor of Alan + Robinson", + publisher = mitp, + year = "1991", + editor = "J.-L. Lassez and G. Plotkin", + pages = "444--478", +} + +@Article{marche-krakatoa-04, + author = "Claude Marché and Christine Paulin-Mohring and Xavier + Urbain", + title = "The {Krakatoa} tool for certification of + {Java}/{JavaCard} programs annotated in {JML}", + journal = jlap, + year = "2004", + volume = "58", + number = "1--2", + pages = "89--106", + URL = "http://www3.ensiie.fr/~urbain/textes/jlap.ps.gz", +} + +@Article{maric-09, + author = "Filip Mari\'c", + title = "Formalization and Implementation of Modern {SAT} + Solvers", + journal = jar, + year = "2009", + volume = "43", + pages = "81--119", + URL = "http://poincare.matf.bg.ac.rs/~filip//phd/sat-tutorial.pdf", +} + +@Unpublished{maric-10, + author = "Filip Mari\'c", + title = "Formal Verification of a Modern {SAT} Solver", + note = "Unpublished", + year = "2010", + URL = "http://poincare.matf.bg.ac.rs/~filip//phd/sat-verification-shallow.pdf", +} + +@InProceedings{marlow-wadler-erlang-97, + title = "A Practical Subtyping System for {Erlang}", + author = "Simon Marlow and Philip Wadler", + pages = "136--149", + booktitle = icfp, + year = "1997", +} + +@TechReport{marriott-odersky-boolean-94, + author = "Kim Marriott and Martin Odersky", + title = "Negative {Boolean} Constraints", + institution = "Monash University", + year = "1994", + number = "94/203", + URL = "http://lampwww.epfl.ch/~odersky/papers/negative-tr.ps.gz", +} + +@Article{martelli-montanari-82, + author = "Alberto Martelli and Ugo Montanari", + title = "An Efficient Unification Algorithm", + journal = toplas, + volume = "4", + number = "2", + pages = "258--282", + year = "1982", + URL = "http://doi.acm.org/10.1145/357162.357169", +} + +@Article{mateescu-sighireanu-03, + author = "Radu Mateescu and Mihaela Sighireanu", + title = "Efficient on-the-fly model-checking for regular + alternation-free mu-calculus", + journal = scp, + volume = "46", + number = "3", + year = "2003", + pages = "255--281", + URL = "ftp://ftp.inrialpes.fr/pub/vasy/publications/cadp/Mateescu-Sighireanu-03.pdf", +} + +@TechReport{mauny-pottier-93, + author = "Michel Mauny and François Pottier", + title = "An implementation of {Caml Light} with existential + types", + number = "2183", + institution = "INRIA", + year = "1993", + URL = "http://gallium.inria.fr/~fpottier/publis/rapport-maitrise.ps.gz", +} + +@InProceedings{mazurak-10, + author = "Karl Mazurak and Jianzhou Zhao and Steve Zdancewic", + title = "Lightweight linear types in system ${F}^\circ$", + booktitle = tldi, + year = "2010", + pages = "77--88", + URL = "http://www.cis.upenn.edu/~stevez/papers/MZZ10.pdf", +} + +@InProceedings{mcadam-98, + title = "{On the Unification of Substitutions in Type + Inference}", + author = "Bruce J. McAdam", + publisher = springer, + booktitle = ifl, + series = lncs, + volume = "1595", + year = "1998", + pages = "139--154", + URL = "http://www.scms.rgu.ac.uk/staff/bjm/doc/IFL_98.ps", +} + +@Article{mcallester-02, + author = "David McAllester", + title = "On the Complexity Analysis of Static Analyses", + year = "2002", + pages = "512--537", + journal = jacm, + volume = "49", + number = "4", + URL = "http://doi.acm.org/10.1145/581771.581774", +} + +@InProceedings{mcallester-03, + author = "David McAllester", + title = "A Logical Algorithm for {ML} Type Inference", + booktitle = rta, + year = "2003", + pages = "436--451", + series = lncs, + publisher = springer, + volume = "2706", + URL = "http://ttic.uchicago.edu/~dmcallester/rta03.ps", +} + +@Unpublished{mcbride-derivative, + author = "Conor McBride", + title = "The Derivative of a Regular Type is its Type of + One-Hole Contexts", + note = "Unpublished", + URL = "http://strictlypositive.org/diff.pdf", +} + +@InProceedings{mcbride-mckinna-04, + author = "Conor McBride and James McKinna", + title = "{I} am not a number: {I} am a free variable", + booktitle = hw, + year = "2004", + URL = "http://www.cs.ru.nl/~james/RESEARCH/haskell2004.pdf", +} + +@Article{mcbride-paterson-08, + author = "Conor McBride and Ross Paterson", + title = "Applicative Programming with Effects", + journal = jfp, + year = "2008", + volume = "18", + number = "1", + pages = "1--13", + URL = "http://www.soi.city.ac.uk/~ross/papers/Applicative.pdf", +} + +@Article{mcbride-unif-03, + author = "Conor McBride", + title = "First-order unification by structural recursion", + journal = jfp, + volume = "13", + number = "6", + year = "2003", + pages = "1061--1075", + URL = "http://strictlypositive.org/unify.ps.gz", +} + +@InProceedings{mccarthy-16, + author = "Jay A. McCarthy and Burke Fetscher and Max S. New and + Daniel Feltey and Robert Bruce Findler", + title = "A {Coq} Library for Internal Verification of + Running-Times", + booktitle = flops, + pages = "144--162", + year = "2016", + series = lncs, + volume = "9613", + publisher = springer, + URL = "https://www.eecs.northwestern.edu/~robby/pubs/papers/flops2016-mfnff.pdf", +} + +@InProceedings{mckinna-pollack-93, + author = "James McKinna and Randy Pollack", + title = "Pure Type Systems Formalized", + booktitle = tlca, + year = "1993", + pages = "289--305", + publisher = springer, + series = lncs, + number = "664", + URL = "http://www.dcs.ed.ac.uk/home/rap/export/formalPTS.ps.gz", +} + +@Article{mckinna-pollack-99, + author = "James McKinna and Randy Pollack", + title = "Some Lambda Calculus and Type Theory Formalized", + journal = jar, + year = "1999", + volume = "23", + number = "3--4", + pages = "373--409", +} + +@InCollection{mclean-94, + author = "John {McLean}", + title = "Security Models", + year = "1994", + booktitle = "Encyclopedia of Software Engineering", + editor = "John Marciniak", + publisher = "John Wiley \& Sons", + URL = "http://chacs.nrl.navy.mil/publications/CHACS/1994/1994mclean-ency.ps", +} + +@InProceedings{mclean-composition-94, + author = "John {McLean}", + title = "A General Theory of Composition for Trace Sets Closed + Under Selective Interleaving Functions", + year = "1994", + booktitle = sp, + URL = "http://chacs.nrl.navy.mil/publications/CHACS/1994/1994mclean-sp.ps", +} + +@InProceedings{meadows-94, + author = "Catherine Meadows", + title = "Formal Verification of Cryptographic Protocols: {A} + Survey", + booktitle = "Advances in Cryptology -- {ASIA\-CRYPT}'94", + year = "1995", + publisher = springer, + series = lncs, + volume = "917", + pages = "133--150", + URL = "http://chacs.nrl.navy.mil/publications/CHACS/1995/1995meadows-asiacrypt94.ps", +} + +@Article{mehta-nipkow-05, + author = "Farhad Mehta and Tobias Nipkow", + title = "Proving pointer programs in higher-order logic", + journal = ic, + volume = "199", + number = "1--2", + year = "2005", + pages = "200--227", + URL = "http://www4.informatik.tu-muenchen.de/~nipkow/pubs/ic05.ps.gz", +} + +@Article{melham-hol-93, + author = "Thomas F. Melham", + title = "The {HOL} Logic Extended with Quantification over Type + Variables", + journal = fmsd, + year = "1993", + volume = "3", + number = "1--2", + pages = "7--24", + URL = "http://web.comlab.ox.ac.uk/oucl/work/tom.melham/pub/Melham-1994-HLE.pdf", +} + +} + +@Article{melski-reps-00, + author = "David Melski and Thomas Reps", + title = "Interconvertibility of a class of set constraints and + context-free language reachability", + journal = tcs, + year = "2000", + volume = "248", + number = "1--2", + URL = "http://www.cs.wisc.edu/wpis/papers/tcs_submission98r2.ps", +} + +@Misc{menhir, + author = "François Pottier and Yann Régis-Gianas", + title = "The {Menhir} parser generator", + note = "\url{http://gallium.inria.fr/~fpottier/menhir/}", +} + +@Manual{merr, + title = "{Merr} User's Guide", + author = "Clinton L. Jeffery", + year = "2002", + URL = "http://unicon.sourceforge.net/merr/merrguid.pdf", +} + +@InProceedings{merz-00, + author = "Stephan Merz", + title = "Model Checking: {A} Tutorial Overview", + booktitle = "Fourth Summer School on Modeling and Verification of + Parallel Processes", + pages = "3--38", + publisher = springer, + series = lncs, + volume = "2067", + year = "2001", + URL = "http://www.loria.fr/~merz/papers/mc-tutorial.pdf", +} + +@InProceedings{merz-08, + author = "Stephan Merz", + editor = "N. Navet and S. Merz", + booktitle = "Modeling and Verification of Real-Time Systems: + Formalisms and Software Tools", + title = "An Introduction to Model Checking", + publisher = "ISTE Publishing", + year = "2008", + pages = "77--109", + URL = "http://www.loria.fr/~merz/papers/mc-iste2008.pdf", +} + +@InProceedings{miller-00, + author = "Dale Miller", + title = "Abstract Syntax for Variable Binders: An Overview", + booktitle = "Computational Logic", + pages = "239--253", + year = "2000", + series = lncs, + volume = "1861", + publisher = springer, + URL = "http://www.lix.polytechnique.fr/~dale/papers/cl2000.pdf", +} + +@InProceedings{miller-90, + author = "Dale Miller", + title = "An Extension to {ML} to Handle Bound Variables in Data + Structures", + booktitle = "Logical Frameworks BRA Workshop", + year = "1990", + URL = "http://www.lix.polytechnique.fr/Labo/Dale.Miller/papers/mll.pdf", +} + +@Article{miller-92, + author = "Dale Miller", + title = "Unification Under a Mixed Prefix", + journal = jsc, + volume = "14", + number = "4", + year = "1992", + pages = "321--358", + URL = "http://www.lix.polytechnique.fr/~dale/papers/jsc92.pdf", +} + +@Article{millstein-chambers-02, + author = "Todd Millstein and Craig Chambers", + title = "Modular statically typed multimethods", + journal = ic, + year = "2002", + volume = "175", + number = "1", + pages = "76--118", + URL = "http://www.cs.ucla.edu/~todd/research/iandc.ps", +} + +@InProceedings{millstein-chambers-99, + author = "Todd Millstein and Craig Chambers", + title = "Modular statically typed multimethods", + booktitle = ecoop, + pages = "279--303", + year = "1999", + volume = "1628", + series = lncs, + publisher = springer, + URL = "http://www.cs.ucla.edu/~todd/research/ecoop99.ps", +} + +@Article{milner-78, + title = "A Theory of Type Polymorphism in Programming", + author = "Robin Milner", + pages = "348--375", + journal = "Journal of Computer and System Sciences", + year = "1978", + volume = "17", + number = "3", + URL = "http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.67.5276", +} + +@TechReport{milner-91, + author = "Robin Milner", + institution = "Laboratory for Foundations of Computer Science, + Department of Computer Science, University of + Edinburgh", + number = "{ECS--LFCS--91--180}", + title = "The Polyadic $\pi$-Calculus: a Tutorial", + year = "1991", + URL = "ftp://ftp.cl.cam.ac.uk/users/rm135/ppi.ps.Z", +} + +@InProceedings{milner-lcf-72, + author = "Robin Milner", + title = "Implementation and applications of {Scott's} logic for + computable functions", + booktitle = "Proceedings of the {ACM} conference on proving + assertions about programs", + year = "1972", + pages = "1--6", + URL = "http://doi.acm.org/10.1145/800235.807067", +} + +@TechReport{milner-lcf-tr-72, + author = "Robin Milner", + title = "Logic for Computable Functions -- Description of a + Machine Implementation", + institution = "Stanford University, Department of Computer Science", + year = "1972", + number = "CS-TR-72-288", + URL = "ftp://reports.stanford.edu/pub/cstr/reports/cs/tr/72/288/CS-TR-72-288.pdf", +} + +@TechReport{milner-lcf-tr-73, + author = "Robin Milner", + title = "Models of {LCF}", + institution = "Stanford University, Department of Computer Science", + year = "1973", + number = "CS-TR-73-332", + URL = "ftp://reports.stanford.edu/pub/cstr/reports/cs/tr/73/332/CS-TR-73-332.pdf", +} + +@TechReport{milner-parrow-walker-89b, + author = "Robin Milner and Joachim Parrow and David Walker", + title = "A Calculus of Mobile Processes, part 2", + institution = "Laboratory for Foundations of Computer Science, School + of Informatics at the University of Edinburgh", + year = "1989", + number = "ECS-LFCS-89-86", + URL = "http://www.lfcs.inf.ed.ac.uk/reports/89/ECS-LFCS-89-86/ECS-LFCS-89-86.ps", +} + +@InProceedings{milner-sangiorgi-92, + title = "Barbed Bisimulation", + author = "Robin Milner and Davide Sangiorgi", + booktitle = icalp, + year = "1992", + series = lncs, + volume = "623", + publisher = springer, + pages = "685--695", + URL = "ftp://ftp-sop.inria.fr/meije/theorie-par/davides/bn.ps.gz", +} + +@InProceedings{minamide-98, + author = "Yasuhiko Minamide", + title = "A functional representation of data structures with a + hole", + booktitle = popl, + year = "1998", + pages = "75--84", + URL = "http://www.score.cs.tsukuba.ac.jp/~minamide/papers/hole.popl98.pdf", +} + +@InProceedings{minamide-al-96, + author = "Yasuhiko Minamide and Greg Morrisett and Robert + Harper", + title = "Typed closure conversion", + booktitle = popl, + year = "1996", + pages = "271--283", + URL = "http://www.cs.cornell.edu/Info/People/jgm/papers/closure-summary.ps", +} + +@InProceedings{minamide-okuma-03, + author = "Yasuhiko Minamide and Koji Okuma", + title = "Verifying {CPS} transformations in {Isabelle/HOL}", + booktitle = merlin, + year = "2003", + URL = "http://doi.acm.org/10.1145/976571.976576", +} + +@Article{mitchell-05, + author = "David G. Mitchell", + title = "A {SAT} Solver Primer", + journal = "Bulletin of the EATCS", + volume = "85", + year = "2005", + pages = "112--133", + URL = "http://www.cs.sfu.ca/~mitchell/papers/colLogCS85.pdf", +} + +@InProceedings{mitchell-84, + author = "John C. Mitchell", + title = "Coercion and type inference", + booktitle = popl, + pages = "175--185", + year = "1984", + URL = "http://portal.acm.org/citation.cfm?id=800529&dl=ACM&coll=portal", +} + +@InProceedings{mitchell-86, + author = "John C. Mitchell", + title = "Representation Independence and Data Abstraction", + booktitle = popl, + year = "1986", + pages = "263--276", + URL = "http://dx.doi.org/10.1145/512644.512669", +} + +@Article{mitchell-88, + author = "John C. Mitchell", + title = "Polymorphic type inference and containment", + journal = ic, + year = "1988", + volume = "76", + number = "2--3", + pages = "211--249", + URL = "http://dx.doi.org/10.1016/0890-5401(88)90009-0", +} + +@Article{mitchell-91, + author = "John C. Mitchell", + title = "Type Inference with Simple Subtypes", + journal = jfp, + year = "1991", + volume = "1", + number = "3", + pages = "245--286", +} + +@Book{mitchell-96, + author = "John C. Mitchell", + title = "Foundations for Programming Languages", + publisher = mitp, + year = "1996", +} + +@Article{mitchell-plotkin-88, + author = "John C. Mitchell and Gordon D. Plotkin", + title = "Abstract types have existential type", + journal = toplas, + volume = "10", + number = "3", + year = "1988", + pages = "470--502", + URL = "http://theory.stanford.edu/people/jcm/papers/mitch-plotkin-88.pdf", +} + +@InProceedings{mitls-13, + author = "Karthikeyan Bhargavan and C{\'{e}}dric Fournet and + Markulf Kohlweiss and Alfredo Pironti and Pierre{-}Yves + Strub", + title = "Implementing {TLS} with Verified Cryptographic + Security", + booktitle = sp, + pages = "445--459", + year = "2013", + URL = "http://prosecco.gforge.inria.fr/personal/karthik/pubs/implementing-tls-with-verified-cryptographic-security-sp13.pdf", +} + +@Article{mizuno-schmidt-92, + author = "Masaaki Mizuno and David A. Schmidt", + journal = fac, + title = "A Security Flow Control Algorithm and Its Denotational + Semantics Correctness Proof", + year = "1992", + volume = "4", + number = "6A", + pages = "727--754", + URL = "ftp://ftp.cis.ksu.edu/pub/CIS/Schmidt/papers/security.ps.Z", +} + +@Misc{mlton, + author = "Henry Cejtin and Matthew Fluet and Suresh Jagannathan + and Stephen Weeks", + title = "The {MLton} compiler", + year = "2007", + URL = "http://mlton.org/", +} + +@InProceedings{mogelberg-staton-10, + author = "Rasmus Ejlers Møgelberg and Sam Staton", + title = "Full abstraction in a metalanguage for state", + booktitle = lola, + year = "2010", +} + +@InProceedings{moggi-89, + author = "Eugenio Moggi", + title = "Computational $\lambda$-Calculus and Monads", + booktitle = lics, + year = "1989", + pages = "14--23", + URL = "http://www.disi.unige.it/person/MoggiE/ftp/lics89.ps.gz", +} + +@TechReport{moggi-89b, + author = "Eugenio Moggi", + title = "An abstract view of programming languages", + institution = "University of Edinburgh", + number = "ECS-LFCS-90-113", + year = "1989", + URL = "http://www.disi.unige.it/person/MoggiE/ftp/abs-view.ps.gz", +} + +@Article{moggi-91, + author = "Eugenio Moggi", + title = "Notions of computation and monads", + journal = ic, + year = "1991", + volume = "93", + number = "1", + URL = "http://www.disi.unige.it/person/MoggiE/ftp/ic91.pdf", +} + +@Article{moggi-sabry-04, + author = "Eugenio Moggi and Amr Sabry", + title = "An Abstract Monadic Semantics for Value Recursion", + journal = ita, + year = "2004", + volume = "38", + number = "4", + pages = "377--400", + URL = "http://www.disi.unige.it/person/MoggiE/ftp/ita04.pdf", +} + +@Article{monadic-regions-06, + author = "Matthew Fluet and Greg Morrisett", + title = "Monadic Regions", + journal = jfp, + year = "2006", + volume = "16", + number = "4--5", + pages = "485--545", + URL = "http://dx.doi.org/10.1017/S095679680600596X", +} + +@Unpublished{monnier-08, + author = "Stefan Monnier", + title = "Statically tracking state with Typed Regions", + note = "Unpublished", + year = "2008", + URL = "http://www.iro.umontreal.ca/~monnier/tr.pdf", +} + +@InProceedings{montagu-remy-09, + author = "Beno{\^\i}t Montagu and Didier R{\'e}my", + title = "Modeling Abstract Types in Modules with Open + Existential Types", + booktitle = popl, + year = "2009", + URL = "http://gallium.inria.fr/~remy/modules/Montagu-Remy@popl09:fzip.pdf", + pages = "63--74", +} + +@Article{morrisett-al-07, + title = "${L}^3$: {A} Linear Language with Locations", + author = "Amal Ahmed and Matthew Fluet and Greg Morrisett", + journal = fundamenta, + year = "2007", + number = "4", + volume = "77", + pages = "397--449", + URL = "http://ttic.uchicago.edu/~amal/papers/linloc-fi07.pdf", +} + +@Article{morrisett-ftal-99, + author = "Greg Morrisett and David Walker and Karl Crary and + Neal Glew", + title = "From System {F} to Typed Assembly Language", + journal = toplas, + year = "1999", + volume = "21", + number = "3", + pages = "528--569", + URL = "http://www.cs.cornell.edu/talc/papers/tal-toplas.pdf", +} + +@InProceedings{morrisett-rec-98, + author = "Greg Morrisett and Robert Harper", + title = "Typed Closure Conversion for Recursively-Defined + Functions (Extended Abstract)", + booktitle = hoots, + year = "1998", + series = entcs, + volume = "10", + publisher = elsevier, + URL = "http://www.cs.cornell.edu/home/jgm/papers/hootsclosure.ps", +} + +@InProceedings{moskewicz-chaff-01, + author = "Matthew W. Moskewicz and Conor F. Madigan and Ying + Zhao and Lintao Zhang and Sharad Malik", + title = "Chaff: Engineering an efficient {SAT} solver", + booktitle = dac, + year = "2001", + URL = "http://research.microsoft.com/users/lintaoz/papers/dac_2001.pdf", +} + +@Article{mosses-04, + author = "Peter D. Mosses", + title = "Modular structural operational semantics", + journal = jlap, + volume = "60--61", + year = "2004", + pages = "195--228", + URL = "http://www.brics.dk/RS/05/7/BRICS-RS-05-7.pdf", +} + +@InProceedings{mueller-94, + author = "Martin M{\"u}ller", + title = "A Constraint-Based Recast of {ML}-Polymorphism", + booktitle = "International Workshop on Unification", + year = "1994", + note = "Technical Report 94-R-243, CRIN, Nancy, France", + URL = "http://www.ps.uni-sb.de/Papers/abstracts/UNIF94.ps", +} + +@Unpublished{mueller-98, + author = "Martin M{\"u}ller", + title = "Notes on {HM}$({X})$", + year = "1998", + URL = "http://www.ps.uni-sb.de/~mmueller/papers/HMX.ps.gz", + note = "Unpublished", +} + +@Article{mueller-feature-01, + title = "The First-Order Theory of Ordering Constraints over + Feature Trees", + year = "2001", + author = "Martin M{\"u}ller and Joachim Niehren and Ralf + Treinen", + journal = "Discrete Mathematics and Theoretical Computer + Science", + pages = "193--234", + number = "2", + volume = "4", + URL = "http://www.ps.uni-sb.de/Papers/abstracts/FTSubTheory-Long:99.ps", +} + +@Article{mueller-holcf-99, + author = "Olaf Müller and Tobias Nipkow and David von Oheimb + and Oskar Slotosch", + title = "{HOLCF = HOL + LCF}", + journal = jfp, + volume = "9", + pages = "191--223", + year = "1999", + URL = "http://www4.informatik.tu-muenchen.de/~nipkow/pubs/jfp99.ps.gz", +} + +@Article{mueller-niehren-podelski-feature-99, + author = "Martin Müller and Joachim Niehren and Andreas + Podelski", + journal = "Constraints, an International Journal", + volume = "5", + number = "1--2", + title = "Ordering Constraints over Feature Trees", + mon = jan, + year = "2000", + pages = "7--42", + URL = "ftp://ftp.ps.uni-sb.de/pub/papers/ProgrammingSysLab/ftsub-constraints-99.ps.gz", +} + +@InProceedings{mueller-niehren-podelski-ines-97, + author = "Joachim Niehren and Martin M{\"u}ller and Andreas + Podelski", + booktitle = tapsoft, + title = "Inclusion Constraints over Non-Empty Sets of Trees", + series = lncs, + publisher = springer, + volume = "1214", + year = "1997", + pages = "217--231", + URL = "http://www.ps.uni-sb.de/Papers/abstracts/ines97.ps", +} + +@Article{mueller-nishimura-00, + author = "Martin M{\"u}ller and Susumu Nishimura", + title = "Type Inference for First-Class Messages with Feature + Constraints", + journal = ijfcs, + year = "2000", + volume = "11", + number = "1", + pages = "29--63", +} + +@InProceedings{mueller-nishimura-98, + author = "Martin M{\"u}ller and Susumu Nishimura", + title = "Type Inference for First-Class Messages with Feature + Constraints", + booktitle = asian, + pages = "169--187", + year = "1998", + volume = "1538", + series = lncs, + publisher = springer, + URL = "http://www.ps.uni-sb.de/Papers/abstracts/FirstClass98.ps", +} + +@TechReport{mueller-poetzsch-heffter-01, + author = "Peter M{\"u}ller and Arnd Poetzsch-Heffter", + title = "Universes: {A} Type System for Alias and Dependency + Control", + year = "2001", + institution = "Fernuniversit{\"a}t Hagen", + number = "279", + URL = "http://people.inf.ethz.ch/lehnerh/pm/publications/getpdf.php?bibname=Own&id=MuellerPoetzsch-Heffter01a.pdf", +} + +@InProceedings{mueller-rudich-07, + author = "Peter M{\"u}ller and Arsenii Rudich", + title = "Ownership transfer in universe types", + booktitle = oopsla, + year = "2007", + pages = "461--478", + URL = "http://dx.doi.org/10.1145/1297027.1297061", +} + +@InProceedings{mueller-schwerhoff-summers-16, + author = "Peter M{\"{u}}ller and Malte Schwerhoff and Alexander + J. Summers", + title = "Automatic Verification of Iterated Separating + Conjunctions Using Symbolic Execution", + booktitle = cav, + pages = "405--425", + year = "2016", + volume = "9779", + publisher = springer, + series = lncs, + URL = "https://arxiv.org/abs/1603.00649", +} + +@InProceedings{muller-rpc-98, + title = "Fast, optimized {Sun} {RPC} using automatic program + specialization", + author = "Gilles Muller and Renaud Marlet and Eugen-Nicolae + Volanschi and Charles Consel and Calton Pu and Ashvin + Goel", + booktitle = cdcs, + pages = "240--249", + year = "1998", + URL = "http://www.cc.gatech.edu/~calton/publications/dcs-98.pdf", +} + +@InProceedings{mycroft-84, + author = "Alan Mycroft", + title = "Polymorphic Type Schemes and Recursive Definitions", + booktitle = "International Symposium on Programming", + series = lncs, + volume = "167", + pages = "217--228", + year = "1984", + publisher = springer, + URL = "http://dx.doi.org/10.1007/3-540-12925-1_41", +} + +@PhdThesis{myers-99, + author = "Andrew C. Myers", + title = "Mostly-Static Decentralized Information Flow Control", + school = "Massachusetts Institute of Technology", + year = "1999", + pages = "171", + note = "Technical Report MIT/LCS/TR-783", + URL = "http://www.cs.cornell.edu/andru/release/tr783.ps.gz", +} + +@Article{myers-liskov-00, + author = "Andrew C. Myers and Barbara Liskov", + title = "Protecting Privacy using the Decentralized Label + Model", + journal = tosem, + volume = "9", + number = "4", + year = "2000", + pages = "410--442", + URL = "http://www.cs.cornell.edu/andru/papers/iflow-tosem.ps.gz", +} + +@Article{myers-liskov-97, + author = "Andrew C. Myers and Barbara Liskov", + title = "A Decentralized Model for Information Flow Control", + year = "1997", + number = "5", + volume = "31", + pages = "129--142", + journal = "{ACM} Operating Systems Review", + URL = "http://www.cs.cornell.edu/andru/papers/iflow-sosp97/paper.html", +} + +@InProceedings{myers-liskov-98, + author = "Andrew C. Myers and Barbara Liskov", + title = "Complete, Safe Information Flow with Decentralized + Labels", + year = "1998", + pages = "186--197", + booktitle = sp, + URL = "http://www.cs.cornell.edu/andru/papers/sp98/top.html", +} + +@InProceedings{myers-popl-99, + author = "Andrew C. Myers", + title = "{JFlow}: practical mostly-static information flow + control", + booktitle = popl, + year = "1999", + pages = "228--241", + URL = "http://www.cs.cornell.edu/andru/papers/popl99/myers-popl99.ps.gz", +} + +@Article{myers-sabelfeld-03, + author = "Andrew C. Myers and Andrei Sabelfeld", + title = "Language-Based Information-Flow Security", + journal = "IEEE Journal on Selected Areas in Communications", + year = "2003", + volume = "21", + number = "1", + pages = "5--19", + URL = "http://www.cs.cornell.edu/andru/papers/jsac/sm-jsac03.pdf", +} + +@InProceedings{nadathur-miller-88, + author = "Gopalan Nadathur and Dale Miller", + title = "An Overview of Lambda-Prolog", + booktitle = "Logic Programming", + pages = "810--827", + year = "1988", + URL = "http://repository.upenn.edu/cis_reports/595/", +} + +@InProceedings{nadathur-qi-03, + author = "Gopalan Nadathur and Xiaochu Qi", + title = "Explicit Substitutions in the Reduction of Lambda + Terms", + booktitle = ppdp, + pages = "195--206", + year = "2003", + URL = "http://www-users.cs.umn.edu/~gopalan/papers/reduction.ps", + alturl = "http://doi.acm.org/10.1145/888270", +} + +@Book{naftalin-wadler-06, + author = "Maurice Naftalin and Philip Wadler", + title = "{Java} generics and collections", + publisher = "O'Reilly", + year = "2006", + URL = "http://shop.oreilly.com/product/9780596527754.do", +} + +@InProceedings{nakano-00, + author = "Hiroshi Nakano", + title = "A Modality for Recursion", + booktitle = lics, + pages = "255--266", + year = "2000", + URL = "http://www602.math.ryukoku.ac.jp/~nakano/papers/modality-lics00.ps.gz", +} + +@InProceedings{nakano-01, + author = "Hiroshi Nakano", + title = "Fixed-point Logic with the Approximation Modality and + Its {Kripke} Completeness", + booktitle = tacs, + pages = "165--182", + year = "2001", + volume = "2215", + series = lncs, + publisher = springer, + URL = "http://www602.math.ryukoku.ac.jp/~nakano/papers/modality-tacs01.pdf", +} + +@TechReport{nanevski-02, + author = "Aleksandar Nanevski", + title = "Meta-Programming with Names and Necessity", + institution = "School of Computer Science, Carnegie Mellon + University", + year = "2002", + number = "CMU-CS-02-123R", + URL = "http://www.eecs.harvard.edu/~aleks/papers/necessity/techrep2.ps", +} + +@InProceedings{nanevski-htt-06, + author = "Aleksandar Nanevski and Greg Morrisett and Lars + Birkedal", + title = "Polymorphism and Separation in {Hoare} Type Theory", + booktitle = icfp, + pages = "62--73", + year = "2006", + URL = "http://www.eecs.harvard.edu/~aleks/papers/hoarelogic/icfp06.pdf", +} + +@InProceedings{nanevski-htt-07, + author = "Aleksandar Nanevski and Amal Ahmed and Greg Morrisett + and Lars Birkedal", + title = "Abstract Predicates and Mutable {ADTs} in {Hoare} Type + Theory", + booktitle = esop, + year = "2007", + series = lncs, + volume = "4421", + pages = "189--204", + publisher = springer, + URL = "http://ynot.cs.harvard.edu/papers/esop07.pdf", +} + +@Article{nanevski-htt-08, + author = "Aleksandar Nanevski and Greg Morrisett and Lars + Birkedal", + title = "{Hoare} Type Theory, Polymorphism and Separation", + journal = jfp, + year = "2008", + volume = "18", + number = "5--6", + pages = "865--911", + URL = "http://ynot.cs.harvard.edu/papers/jfpsep07.pdf", +} + +@InProceedings{nanevski-structuring-10, + author = "Aleksandar Nanevski and Viktor Vafeiadis and Josh + Berdine", + title = "Structuring the verification of heap-manipulating + programs", + booktitle = popl, + year = "2010", + pages = "261--274", + URL = "http://software.imdea.org/~aleks/papers/reflect/reflect.pdf", +} + +@InProceedings{nanevski-ynot-08, + author = "Aleksandar Nanevski and Greg Morrisett and Avraham + Shinnar and Paul Govereau and Lars Birkedal", + title = "Ynot: dependent types for imperative programs", + booktitle = icfp, + year = "2008", + pages = "229--240", + URL = "http://software.imdea.org/~aleks/htt/ynot08.pdf", +} + +@Article{naraschewski-nipkow-99, + author = "Wolfgang Naraschewski and Tobias Nipkow", + title = "Type Inference Verified: Algorithm {W} in + {Isabelle/HOL}", + journal = jar, + year = "1999", + volume = "23", + pages = "299--318", + URL = "http://www4.informatik.tu-muenchen.de/~nipkow/pubs/W.ps.gz", +} + +@Article{naumann-survey-07, + author = "David A. Naumann", + title = "On assertion-based encapsulation for object invariants + and simulations", + journal = fac, + volume = "19", + number = "2", + year = "2007", + pages = "205--224", + publisher = springer, + URL = "https://guinness.cs.stevens-tech.edu/~naumann/publications/fmcoFinal.pdf", +} + +@InProceedings{navarro-perez-rybalchenko-11, + author = "Juan Antonio {Navarro P{\'e}rez} and Andrey + Rybalchenko", + title = "Separation logic + superposition calculus = heap + theorem prover", + booktitle = pldi, + year = "2011", + pages = "556--566", + URL = "http://www7.informatik.tu-muenchen.de/um/bibdb/navarro/pldi2011.pdf", +} + +@InProceedings{needle-knot-16, + author = "Steven Keuchel and Stephanie Weirich and Tom + Schrijvers", + title = "Needle {\&} Knot: Binder Boilerplate Tied Up", + booktitle = esop, + pages = "419--445", + year = "2016", + series = lncs, + volume = "9632", + publisher = springer, + URL = "https://users.ugent.be/~skeuchel/publications/knot.pdf", +} + +@InProceedings{neron-tolmach-visser-wachsmuth-15, + author = "Pierre Neron and Andrew P. Tolmach and Eelco Visser + and Guido Wachsmuth", + title = "A Theory of name resolution", + booktitle = esop, + pages = "205--231", + year = "2015", + series = lncs, + volume = "9032", + publisher = springer, + URL = "http://web.cecs.pdx.edu/~apt/esop15.pdf", +} + +@InProceedings{neumann-12, + author = "René Neumann", + booktitle = "ATx/WInG: Joint Proceedings of the Workshops on + Automated Theory eXploration and on Invariant + Generation", + pages = "36--45", + title = "A Framework for Verified Depth-First Algorithms", + publisher = "EasyChair", + series = "EPiC Series", + volume = "17", + year = "2012", + URL = "http://www.easychair.org/publications/?page=722211206", +} + +@InProceedings{nguyen-07, + author = "Huu Hai Nguyen and Cristina David and Shengchao Qin + and Wei-Ngan Chin", + title = "Automated Verification of Shape and Size Properties + Via Separation Logic", + booktitle = vmcai, + year = "2007", + pages = "251--266", + publisher = springer, + series = lncs, + volume = "4349", + URL = "http://www.scm.tees.ac.uk/s.qin/papers/vmcai07.pdf", +} + +@InProceedings{nicklisch-peyton-jones-96, + author = "Jan Nicklisch and Simon {Peyton Jones}", + title = "An exploration of modular programs", + booktitle = "Functional Programming Workshop", + year = "1996", + URL = "http://www.dcs.gla.ac.uk/fp/workshops/fpw96/Nicklisch.ps.gz", +} + +@InProceedings{niehren-priesnitz-01, + author = "Joachim Niehren and Tim Priesnitz", + title = "Non-Structural Subtype Entailment in Automata Theory", + booktitle = tacs, + publisher = springer, + year = "2001", + URL = "ftp://ftp.ps.uni-sb.de/pub/papers/ProgrammingSysLab/pauto.ps.gz", +} + +@Article{niehren-priesnitz-03, + author = "Joachim Niehren and Tim Priesnitz", + title = "Non-Structural Subtype Entailment in Automata Theory", + journal = ic, + year = "2003", + volume = "186", + number = "2", + pages = "319--354", + URL = "http://www.ps.uni-sb.de/Papers/abstracts/subtype.pdf", +} + +@TechReport{nielsen-00, + author = "Lasse R. Nielsen", + title = "A denotational investigation of defunctionalization", + year = "2000", + institution = "BRICS", + number = "RS-00-47", + URL = "http://www.brics.dk/RS/00/47/", +} + +@Article{nielson-02, + author = "Flemming Nielson and Hanne Riis Nielson and Helmut + Seidl", + title = "A Succinct Solver for {ALFP}", + journal = njc, + year = "2002", + volume = "9", + number = "4", + pages = "335--372", + URL = "http://www.informatik.uni-trier.de/~seidl/papers/succinct.pdf", +} + +@Article{nielson-88, + author = "Flemming Nielson and Hanne Riis Nielson", + title = "Two-Level Semantics and Code Generation", + year = "1988", + pages = "59--133", + journal = tcs, + volume = "56", + number = "1", + URL = "http://dx.doi.org/10.1016/0304-3975(86)90006-X", +} + +@Article{nieuwenhuis-oliveras-tinelli-06, + author = "Robert Nieuwenhuis and Albert Oliveras and Cesare + Tinelli", + title = "Solving {SAT} and {SAT Modulo Theories}: From an + abstract {Davis--Putnam--Logemann--Loveland} procedure + to {DPLL(T)}", + journal = jacm, + volume = "53", + number = "6", + year = "2006", + pages = "937--977", + URL = "ftp://ftp.cs.uiowa.edu/pub/tinelli/papers/NieOT-JACM-06.pdf", +} + +@InProceedings{nipkow-15, + author = "Tobias Nipkow", + title = "Amortized Complexity Verified", + year = "2015", + booktitle = itp, + pages = "310--324", + volume = "9236", + series = lncs, + publisher = springer, + URL = "http://www21.in.tum.de/~nipkow/pubs/itp15.pdf", +} + +@InProceedings{nishimura-98, + title = "Static Typing for Dynamic Messages", + author = "Susumu Nishimura", + pages = "266--278", + booktitle = popl, + year = "1998", + URL = "ftp://ftp.kurims.kyoto-u.ac.jp/pub/paper/member/nisimura/dmesg-popl98.ps.gz", +} + +@InProceedings{ntzik-gardner-15, + author = "Gian Ntzik and Philippa Gardner", + title = "Reasoning about the {POSIX} file system: local update + and global pathnames", + booktitle = oopsla, + pages = "201--220", + year = "2015", + URL = "https://www.doc.ic.ac.uk/~pg/papers/oopsla2015.pdf", +} + +@Article{o'hearn-03, + author = "Peter O'Hearn", + title = "On Bunched Typing", + journal = jfp, + year = "2003", + volume = "13", + number = "4", + pages = "747--796", + URL = "http://www.cs.ucl.ac.uk/staff/p.ohearn/papers/BunchedTyping.pdf", +} + +@Manual{objective-caml, + author = "Xavier Leroy and Damien Doligez and Jacques Garrigue + and Didier Rémy and Jérôme Vouillon", + title = "The {Objective Caml} system", + year = "2005", + URL = "http://caml.inria.fr/", +} + +@Misc{ocaml, + author = "Xavier Leroy and Damien Doligez and Alain Frisch and + Jacques Garrigue and Didier Rémy and Jérôme + Vouillon", + title = "The {OCaml} system: documentation and user's manual", + year = "2016", + URL = "http://caml.inria.fr/pub/docs/manual-ocaml-4.04/index.html", +} + +@Article{oconnor-07, + author = "Russell O'Connor", + title = "Assembly: Circular Programming with Recursive do", + journal = "The Monad.Reader", + year = "2007", + volume = "6", + URL = "http://www.haskell.org/sitewiki/images/1/14/TMR-Issue6.pdf", +} + +@InProceedings{odersky-laufer-96, + author = "Martin Odersky and Konstantin Läufer", + title = "Putting Type Annotations To Work", + booktitle = popl, + year = "1996", + pages = "54--67", + URL = "http://lamp.epfl.ch/~odersky/papers/popl96.ps.gz", +} + +@InProceedings{odersky-local-94, + author = "Martin Odersky", + title = "A Functional Theory of Local Names", + pages = "48--59", + booktitle = popl, + year = "1994", + URL = "http://lampwww.epfl.ch/~odersky/papers/popl94.ps.gz", +} + +@InProceedings{odersky-observers-92, + author = "Martin Odersky", + title = "Observers for Linear Types", + booktitle = esop, + pages = "390--407", + year = "1992", + volume = "582", + series = lncs, + publisher = springer, + URL = "http://lamp.epfl.ch/~odersky/papers/esop92.ps.gz", +} + +@Article{odersky-sulzmann-wehr-99, + author = "Martin Odersky and Martin Sulzmann and Martin Wehr", + title = "Type Inference with Constrained Types", + journal = tapos, + year = "1999", + volume = "5", + number = "1", + pages = "35--55", + URL = "http://eprints.kfupm.edu.sa/73647/1/73647.pdf", +} + +@InProceedings{odersky-wadler-wehr-95, + author = "Martin Odersky and Philip Wadler and Martin Wehr", + title = "A Second Look at Overloading", + booktitle = fpca, + pages = "135--146", + year = "1995", + URL = "http://lampwww.epfl.ch/~odersky/papers/fpca95.ps.gz", +} + +@InProceedings{odersky-zenger-zenger-01, + author = "Martin Odersky and Matthias Zenger and Christoph + Zenger", + title = "Colored Local Type Inference", + booktitle = popl, + year = "2001", + pages = "41--53", + URL = "http://lampwww.epfl.ch/papers/clti-colored.ps.gz", +} + +@Article{ohearn-07, + author = "Peter W. O'Hearn", + title = "Resources, Concurrency and Local Reasoning", + journal = tcs, + year = "2007", + volume = "375", + number = "1--3", + pages = "271--307", + URL = "http://www.cs.ucl.ac.uk/staff/p.ohearn/papers/concurrency.pdf", +} + +@InProceedings{ohearn-hiding-04, + author = "Peter W. O'Hearn and Hongseok Yang and John C. + Reynolds", + title = "Separation and information hiding", + booktitle = popl, + pages = "268--280", + year = "2004", + URL = "http://www.cs.ucl.ac.uk/staff/p.ohearn/papers/separation-and-hiding.pdf", +} + +@Article{ohearn-hiding-09, + author = "Peter W. O'Hearn and Hongseok Yang and John C. + Reynolds", + title = "Separation and information hiding", + journal = toplas, + volume = "31", + number = "3", + year = "2009", + URL = "http://www.cs.ucl.ac.uk/staff/p.ohearn/papers/toplas09.pdf", +} + +@Article{ohearn-reynolds-00, + author = "Peter W. O'Hearn and John C. Reynolds", + title = "From {Algol} to polymorphic linear lambda-calculus", + journal = jacm, + volume = "47", + number = "1", + year = "2000", + pages = "167--223", + URL = "http://www.cs.ucl.ac.uk/staff/p.ohearn/papers/AlgolToPolyLin.ps", +} + +@Article{ohearn-scir-99, + author = "Peter W. O'Hearn and John Power and Makoto Takeyama + and Robert D. Tennent", + title = "Syntactic Control of Interference Revisited", + journal = tcs, + volume = "228", + number = "1-2", + pages = "211--252", + year = "1999", + URL = "http://surface.syr.edu/cgi/viewcontent.cgi?article=1011&context=lcsmith_other", +} + +@Article{ohori-95, + author = "Atsushi Ohori", + title = "A Polymorphic Record Calculus and Its Compilation", + journal = toplas, + volume = "17", + number = "6", + pages = "844--895", + year = "1995", + URL = "http://doi.acm.org/10.1145/218570.218572", +} + +@InProceedings{ohori-buneman-88, + author = "Atsushi Ohori and Peter Buneman", + title = "Type Inference in a Database Programming Language", + booktitle = lfp, + pages = "174--183", + year = "1988", + URL = "http://www.jaist.ac.jp/~ohori/research/lfp88.pdf", +} + +@InProceedings{okasaki-96, + author = "Chris Okasaki", + title = "The role of lazy evaluation in amortized data + structures", + booktitle = icfp, + year = "1996", + pages = "62--72", + URL = "http://www.eecs.usma.edu/webs/people/okasaki/icfp96.ps", +} + +@InProceedings{okasaki-98, + author = "Chris Okasaki and Andy Gill", + title = "Fast Mergeable Integer Maps", + booktitle = ml, + pages = "77--86", + year = "1998", + URL = "http://www.cse.ogi.edu/~andy/papers/ml98maps.ps", +} + +@Book{okasaki-book-99, + author = "Chris Okasaki", + title = "Purely Functional Data Structures", + publisher = cup, + year = "1999", + URL = "http://www.cambridge.org/us/catalogue/catalogue.asp?isbn=0521663504", +} + +@TechReport{okasaki-phd-96, + author = "Chris Okasaki", + title = "Purely Functional Data Structures", + institution = "School of Computer Science, Carnegie Mellon + University", + year = "1996", + number = "CMU-CS-96-177", + URL = "http://www.cs.cmu.edu/~rwh/theses/okasaki.pdf", +} + +@InProceedings{okasaki-views-98, + author = "Chris Okasaki", + title = "Views for {Standard ML}", + booktitle = ml, + pages = "14--23", + year = "1998", + URL = "http://www.eecs.usma.edu/Personnel/okasaki/ml98views.ps", +} + +@InProceedings{olderog-83, + author = "Ernst-Rüdiger Olderog", + title = "A characterization of {Hoare's} logic for programs + with {Pascal}-like procedures", + booktitle = stoc, + year = "1983", + pages = "320--329", + URL = "http://doi.acm.org/10.1145/800061.808761", +} + +@Manual{omega, + title = "{${\Omega}$}mega", + author = "Tim Sheard", + year = "2005", + URL = "http://www.cs.pdx.edu/~sheard/Omega/", +} + +@Article{oostrom-94, + author = "Vincent van Oostrom", + title = "Confluence by decreasing diagrams", + journal = tcs, + volume = "126", + number = "2", + pages = "259--280", + year = "1994", + URL = "ftp://ftp.cs.vu.nl/pub/papers/theory/IR-298.ps.Z", +} + +@Book{orourke-98, + author = "Joseph O'Rourke", + title = "Computational Geometry in {C}, Second Edition", + publisher = cup, + year = "1998", + URL = "http://maven.smith.edu/~orourke/books/compgeom.html", +} + +@InProceedings{otoole-gifford-89, + author = "James William {O'Toole, Jr.} and David K. Gifford", + title = "Type reconstruction with first-class polymorphic + values", + booktitle = pldi, + year = "1989", + pages = "207--217", + URL = "http://www.psrg.lcs.mit.edu/history/publications/Papers/pldi89-otoole.ps", +} + +@Article{ott-10, + author = "Peter Sewell and Francesco {Zappa Nardelli} and Scott + Owens and Gilles Peskine and Thomas Ridge and Susmit + Sarkar and Rok Strnisa", + title = "{Ott}: Effective tool support for the working + semanticist", + journal = jfp, + volume = "20", + number = "1", + pages = "71--122", + year = "2010", + URL = "http://www.cl.cam.ac.uk/~pes20/ott/ott-jfp.pdf", +} + +@Article{owens-reppy-turon-09, + author = "Scott Owens and John H. Reppy and Aaron Turon", + title = "Regular-expression derivatives re-examined", + journal = jfp, + volume = "19", + number = "2", + year = "2009", + pages = "173--190", + URL = "http://www.cl.cam.ac.uk/~so294/documents/jfp09.pdf", +} + +@Article{pager-77, + author = "David Pager", + title = "A Practical General Method for Constructing ${LR}(k)$ + Parsers", + journal = acta, + year = "1977", + volume = "7", + pages = "249--268", + URL = "http://dx.doi.org/10.1007/BF00290336", +} + +@Article{paige-tarjan-87, + author = "Robert Paige and Robert E. Tarjan", + title = "Three partition refinement algorithms", + journal = siamjc, + volume = "16", + number = "6", + pages = "973--989", + year = "1987", + URL = "http://locus.siam.org/fulltext/SICOMP/volume-16/0216062.pdf", +} + +@InProceedings{pale-01, + author = "Anders M{\o}ller and Michael I. Schwartzbach", + title = "The Pointer Assertion Logic Engine", + booktitle = pldi, + year = "2001", + pages = "221--231", + URL = "http://www.brics.dk/~amoeller/papers/pale/pale.pdf", +} + +@Article{palsberg-efficient-object-95, + author = "Jens Palsberg", + title = "Efficient inference of object types", + journal = ic, + volume = "123", + number = "2", + pages = "198--209", + year = "1995", + URL = "http://www.cs.ucla.edu/~palsberg/paper/ic95-p.pdf", +} + +@Article{palsberg-okeefe-flow-95, + author = "Jens Palsberg and Patrick M. O'Keefe", + title = "A Type System Equivalent to Flow Analysis", + journal = toplas, + year = "1995", + volume = "17", + number = "4", + pages = "576--599", + URL = "http://www.cs.ucla.edu/~palsberg/paper/toplas95-po.pdf", +} + +@InProceedings{palsberg-orbaek-95, + author = "Jens Palsberg and Peter {\O}rb{\ae}k", + booktitle = sas, + title = "Trust in the {$\lambda$}-calculus", + series = "Lecture Notes in Computer Science", + volume = "983", + pages = "314--330", + year = "1995", + URL = "ftp://ftp.daimi.au.dk/pub/empl/poe/lambda-trust.dvi.gz", +} + +@Article{palsberg-orbaek-97, + title = "Trust in the {$\lambda$}-calculus", + author = "Peter {\O}rb{\ae}k and Jens Palsberg", + pages = "557--591", + journal = jfp, + year = "1997", + volume = "7", + number = "6", + URL = "http://www.cs.ucla.edu/~palsberg/paper/jfp97.pdf", +} + +@Article{palsberg-smith-96, + author = "Jens Palsberg and Scott Smith", + title = "Constrained types and their expressiveness", + journal = toplas, + volume = "18", + number = "5", + pages = "519--527", + year = "1996", + URL = "http://www.cs.ucla.edu/~palsberg/paper/toplas96-ps.pdf", +} + +@Article{palsberg-wand-okeefe-97, + title = "Type inference with non-structural subtyping", + author = "Jens Palsberg and Mitchell Wand and Patrick M. + O'Keefe", + journal = fac, + year = "1997", + pages = "49--67", + volume = "9", + URL = "http://www.cs.ucla.edu/~palsberg/paper/fac97.pdf", +} + +@Article{palsberg-zhao-01, + author = "Jens Palsberg and Tian Zhao", + title = "Efficient and Flexible Matching of Recursive Types", + journal = ic, + volume = "171", + pages = "364--387", + year = "2001", + URL = "http://www.cs.ucla.edu/~palsberg/paper/ic01.pdf", +} + +@InProceedings{palsberg-zhao-02, + author = "Jens Palsberg and Tian Zhao", + title = "Efficient Type Inference for Record Concatenation and + Subtyping", + pages = "125--136", + booktitle = lics, + year = "2002", +} + +@Article{palsberg-zhao-04, + author = "Jens Palsberg and Tian Zhao", + title = "Type Inference for Record Concatenation and + Subtyping", + journal = ic, + year = "2004", + volume = "189", + pages = "54--86", + URL = "http://www.cs.ucla.edu/~palsberg/paper/ic04.pdf", +} + +@Misc{pangolin, + author = "Yann Régis-Gianas", + title = "The {Pangolin} programming language", + note = "\url{http://code.google.com/p/pangolin-programming-language/}", + year = "2008", + URL = "http://code.google.com/p/pangolin-programming-language/", +} + +@InProceedings{parkinson-bierman-05, + author = "Matthew Parkinson and Gavin Bierman", + title = "Separation logic and abstraction", + booktitle = popl, + year = "2005", + pages = "247--258", + URL = "http://dx.doi.org/10.1145/1040305.1040326", +} + +@InProceedings{parkinson-bierman-08, + author = "Matthew Parkinson and Gavin Bierman", + title = "Separation logic, abstraction and inheritance", + booktitle = popl, + year = "2008", + pages = "75--86", + URL = "http://dx.doi.org/10.1145/1328438.1328451", +} + +@InProceedings{parnas-71, + author = "David Lorge Parnas", + title = "Information distribution aspects of design + methodology", + booktitle = "Information Processing 71", + pages = "339--344", + volume = "1", + year = "1971", + URL = "http://cseweb.ucsd.edu/~wgg/CSE218/Parnas-IFIP71-information-distribution.PDF", +} + +@Article{parnas-72, + author = "David Lorge Parnas", + title = "On the criteria to be used in decomposing systems into + modules", + journal = cacm, + volume = "15", + number = "12", + year = "1972", + pages = "1053--1058", + URL = "http://doi.acm.org/10.1145/361598.361623", +} + +@TechReport{pasalic-dali-00, + author = "Emir Pa{\v s}ali{\'c} and Tim Sheard and Walid Taha", + title = "{DALI}: An Untyped, {CBV} Functional Language + Supporting First-Order Datatypes with Binders + (Technical Development)", + institution = "Oregon Graduate Institute", + year = "2000", + number = "00-007", + URL = "http://www.cse.ogi.edu/PacSoft/publications/phaseiiiq13papers/dali.pdf", +} + +@InProceedings{pasalic-linger-04, + author = "Pa{\v s}ali{\'c} and Nathan Linger", + title = "Meta-programming with Typed Object-Language + Representations", + booktitle = gpce, + pages = "136--167", + year = "2004", + URL = "http://web.cecs.pdx.edu/~sheard/papers/MetaProgTypObjLangReps.ps", +} + +@InProceedings{pasalic-tagless-02, + author = "Emir Pa{\v s}ali{\'c} and Walid Taha and Tim Sheard", + title = "Tagless staged interpreters for typed languages", + booktitle = icfp, + year = "2002", + pages = "218--229", + URL = "http://www.cs.rice.edu/~taha/teaching/02F/511/papers/pts02.pdf", +} + +@InProceedings{paterson-wegman-76, + author = "M. S. Paterson and M. N. Wegman", + title = "Linear Unification", + booktitle = "Annual {ACM} Symposium on Theory of Computing", + pages = "181--186", + year = "1976", +} + +@InProceedings{patwary-10, + author = "Md. Mostofa Ali Patwary and Jean Blair and Fredrik + Manne", + title = "Experiments on Union-Find Algorithms for the + Disjoint-Set Data Structure", + booktitle = "International Symposium on Experimental Algorithms + (SEA)", + pages = "411--423", + year = "2010", + series = lncs, + volume = "6049", + publisher = springer, + URL = "http://www.ii.uib.no/~fredrikm/fredrik/papers/SEA2010.pdf", +} + +@InProceedings{paulin-89, + author = "Christine Paulin-Mohring", + title = "Extracting ${F}_{\omega}$'s programs from proofs in + the Calculus of Constructions", + year = "1989", + booktitle = popl, + pages = "89--104", + URL = "http://doi.acm.org/10.1145/75277.75285", +} + +@TechReport{paulin-92, + author = "Christine Paulin-Mohring", + title = "Inductive Definitions in the system {Coq}: rules and + Properties", + institution = "ENS Lyon", + year = "1992", + type = "Research Report", + number = "RR1992-49", + URL = "ftp://ftp.ens-lyon.fr/pub/LIP/Rapports/RR/RR1992/RR1992-49.ps.Z", +} + +@InProceedings{pennello-86, + author = "Thomas J. Pennello", + title = "Very fast {LR} parsing", + booktitle = "Symposium on Compiler Construction", + pages = "145--151", + year = "1986", + URL = "http://doi.acm.org/10.1145/12276.13326", +} + +@Article{pessaux-leroy-00, + author = "Fran\c{c}ois Pessaux and Xavier Leroy", + title = "Type-based analysis of uncaught exceptions", + journal = toplas, + pages = "340--377", + volume = "22", + number = "2", + year = "2000", + URL = "http://gallium.inria.fr/~xleroy/publi/exceptions-toplas.ps.gz", +} + +@InProceedings{peterson-jones-93, + author = "John Peterson and Mark P. Jones", + title = "Implementing Type Classes", + booktitle = pldi, + pages = "227--236", + year = "1993", + URL = "http://web.cecs.pdx.edu/~mpj/pubs/pldi93.ps", +} + +@Book{peyton-jones-ifl-87, + author = "Simon {Peyton Jones}", + title = "The Implementation of Functional Programming + Languages", + publisher = prentice, + year = "1987", + URL = "http://research.microsoft.com/Users/simonpj/papers/slpj-book-1987/", +} + +@Article{peyton-jones-marlow-ghc-inliner-02, + author = "Simon {Peyton Jones} and Simon Marlow", + title = "Secrets of the {Glasgow Haskell Compiler} inliner", + journal = jfp, + volume = "12", + number = "4{\&}5", + pages = "393--433", + year = "2002", + URL = "http://research.microsoft.com/en-us/um/people/simonpj/Papers/inlining/inline-jfp.ps.gz", +} + +@Article{peyton-jones-rank-07, + author = "Simon {Peyton Jones} and Dimitrios Vytiniotis and + Stephanie Weirich and Mark Shields", + title = "Practical type inference for arbitrary-rank types", + journal = jfp, + volume = "17", + number = "1", + pages = "1--82", + year = "2007", + URL = "http://research.microsoft.com/en-us/um/people/simonpj/papers/higher-rank/putting.pdf", +} + +@Unpublished{peyton-jones-shields-04, + author = "Simon {Peyton Jones} and Mark Shields", + title = "Lexically-Scoped Type Variables", + year = "2004", + note = "Manuscript", + URL = "http://www.cse.ogi.edu/~mbs/pub/scoped/", +} + +@InProceedings{peyton-jones-simple-gadts-06, + author = "Simon {Peyton Jones} and Dimitrios Vytiniotis and + Stephanie Weirich and Geoffrey Washburn", + title = "Simple unification-based type inference for {GADTs}", + booktitle = icfp, + year = "2006", + pages = "50--61", + URL = "https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/gadt-pldi.pdf", +} + +@Misc{peyton-jones-tackling-09, + author = "Simon {Peyton Jones}", + title = "Tackling the Awkward Squad: monadic input/output, + concurrency, exceptions, and foreign-language calls in + {Haskell}", + howpublished = "Online lecture notes", + year = "2009", + URL = "http://research.microsoft.com/en-us/um/people/simonpj/papers/marktoberdorf/mark.pdf", +} + +@InProceedings{peyton-jones-wadler-93, + author = "Simon {Peyton Jones} and Philip Wadler", + title = "Imperative functional programming", + booktitle = popl, + year = "1993", + pages = "71--84", + URL = "http://homepages.inf.ed.ac.uk/wadler/papers/imperative/imperative.ps.gz", +} + +@TechReport{peyton-jones-wobbly-04, + author = "Simon {Peyton Jones} and Geoffrey Washburn and + Stephanie Weirich", + title = "Wobbly types: type inference for generalised algebraic + data types", + institution = "University of Pennsylvania", + year = "2004", + number = "MS-CIS-05-26", + URL = "http://www.cis.upenn.edu/~geoffw/research/papers/MS-CIS-05-26.pdf", +} + +@InProceedings{pfenning-elliott-88, + author = "Frank Pfenning and Conal Elliott", + title = "Higher-Order Abstract Syntax", + pages = "199--208", + booktitle = pldi, + year = "1988", + URL = "http://doi.acm.org/10.1145/53990.54010", +} + +@InProceedings{pfenning-lee-89, + author = "Frank Pfenning and Peter Lee", + title = "{LEAP}: {A} Language with Eval And Polymorphism", + booktitle = tapsoft, + year = "1989", + publisher = springer, + series = lncs, + volume = "352", + pages = "345--359", + URL = "http://dx.doi.org/10.1007/3-540-50940-2_46", +} + +@InProceedings{pientka-08, + author = "Brigitte Pientka", + title = "A type-theoretic foundation for programming with + higher-order abstract syntax and first-class + substitutions", + booktitle = popl, + year = "2008", + pages = "371--382", + URL = "http://www.cs.mcgill.ca/~bpientka/papers/hoasfun-short.pdf", +} + +@InProceedings{pientka-dunfield-08, + author = "Brigitte Pientka and Joshua Dunfield", + title = "Programming with Proofs and Explicit Contexts", + booktitle = ppdp, + pages = "163--173", + year = "2008", + URL = "http://www.cs.mcgill.ca/~bpientka/papers/ppdp-pientka.pdf", +} + +@InProceedings{pientka-pearl-07, + author = "Brigitte Pientka", + title = "Proof Pearl: The power of higher-order encodings in + the logical framework {LF}", + booktitle = tphol, + pages = "246--261", + year = "2007", + volume = "4732", + series = lncs, + publisher = springer, + URL = "http://www.cs.mcgill.ca/~bpientka/papers/pearl.pdf", +} + +@InProceedings{pierce-sangiorgi-93, + author = "Benjamin Pierce and Davide Sangiorgi", + title = "Typing and Subtyping for Mobile Processes", + pages = "376--385", + booktitle = lics, + year = "1993", + URL = "http://www.cis.upenn.edu/~bcpierce/papers/pi-lics.ps", +} + +@Book{pierce-tapl, + author = "Benjamin C. Pierce", + title = "Types and Programming Languages", + publisher = mitp, + year = "2002", + URL = "http://www.cis.upenn.edu/~bcpierce/tapl/", +} + +@Article{pierce-turner-00, + author = "Benjamin C. Pierce and David N. Turner", + title = "Local Type Inference", + journal = toplas, + year = "2000", + volume = "22", + number = "1", + pages = "1--44", + URL = "http://doi.acm.org/10.1145/345099.345100", +} + +@TechReport{pierce-turner-92, + author = "Benjamin C. Pierce and David N. Turner", + title = "Statically Typed Friendly Functions via Partially + Abstract Types", + institution = "University of Edinburgh, LFCS", + type = "Technical Report", + number = "ECS-LFCS-93-256", + year = "1993", + note = "Also available as INRIA Research Report 1899", + URL = "http://www.cis.upenn.edu/~bcpierce/papers/friendly.ps", +} + +@Article{pierce-turner-94, + author = "Benjamin C. Pierce and David N. Turner", + title = "Simple Type-Theoretic Foundations for Object-Oriented + Programming", + journal = jfp, + volume = "4", + number = "2", + pages = "207--247", + year = "1994", + URL = "http://www.cis.upenn.edu/~bcpierce/papers/oop.ps", +} + +@Article{pierce-undecidable-92, + author = "Benjamin C. Pierce", + title = "Bounded Quantification is Undecidable", + journal = ic, + year = "1994", + volume = "112", + number = "1", + pages = "131--165", + URL = "http://www.cis.upenn.edu/~bcpierce/papers/fsubpopl.ps", +} + +@InProceedings{pilkiewicz-pottier-monotonicity-11, + author = "Alexandre Pilkiewicz and François Pottier", + title = "The essence of monotonic state", + booktitle = tldi, + year = "2011", + URL = "http://gallium.inria.fr/~fpottier/publis/pilkiewicz-pottier-monotonicity.pdf", +} + +@InProceedings{piskac-13, + author = "Ruzica Piskac and Thomas Wies and Damien Zufferey", + title = "Automating Separation Logic Using {SMT}", + booktitle = cav, + pages = "773--789", + year = "2013", + series = lncs, + volume = "8044", + publisher = springer, + URL = "https://www.mpi-sws.org/~piskac/publications/PiskacWiesZuffrey13SepLog.pdf", +} + +@InProceedings{piskac-14, + author = "Ruzica Piskac and Thomas Wies and Damien Zufferey", + title = "Automating Separation Logic with Trees and Data", + booktitle = cav, + pages = "711--728", + year = "2014", + series = lncs, + volume = "8559", + publisher = springer, + URL = "http://cs.nyu.edu/wies/publ/automating_separation_logic_with_trees_and_data.pdf", +} + +@Article{pitts-03, + author = "Andrew M. Pitts", + title = "Nominal Logic, {A} First Order Theory of Names and + Binding", + journal = ic, + year = "2003", + volume = "186", + pages = "165--193", + URL = "http://www.cl.cam.ac.uk/~amp12/papers/nomlfo/nomlfo-jv.pdf", +} + +@InProceedings{pitts-05, + author = "Andrew M. Pitts", + title = "Alpha-Structural Recursion and Induction", + booktitle = tphol, + year = "2005", + series = lncs, + publisher = springer, + URL = "http://www.cl.cam.ac.uk/~amp12/papers/alpsri/alpsri-ea.pdf", +} + +@Article{pitts-06, + author = "Andrew M. Pitts", + title = "Alpha-Structural Recursion and Induction", + journal = jacm, + year = "2006", + volume = "53", + pages = "459--506", + URL = "http://www.cl.cam.ac.uk/~amp12/papers/alpsri/alpsri.pdf", +} + +@InProceedings{pitts-10, + author = "Andrew M. Pitts", + title = "Nominal {System} ${T}$", + booktitle = popl, + pages = "159--170", + year = "2010", + URL = "http://www.cl.cam.ac.uk/~amp12/papers/nomst/nomst-popl.pdf", +} + +@InProceedings{pitts-gabbay-00, + author = "Andrew M. Pitts and Murdoch J. Gabbay", + title = "A Metalanguage for Programming with Bound Names Modulo + Renaming", + booktitle = mpc, + pages = "230--255", + year = "2000", + volume = "1837", + series = lncs, + publisher = springer, + URL = "http://www.cl.cam.ac.uk/~amp12/papers/metpbn/metpbn.pdf", +} + +@Article{pitts-parametric-00, + author = "Andrew M. Pitts", + title = "Parametric Polymorphism and Operational Equivalence", + journal = mscs, + year = "2000", + volume = "10", + pages = "321--359", + URL = "http://www.cl.cam.ac.uk/~amp12/papers/parpoe/parpoe.pdf", +} + +@InProceedings{plaid-permissions-11, + author = "Jonathan Aldrich and Ronald Garcia and Mark Hahnenberg + and Manuel Mohr and Karl Naden and Darpan Saini and + Sven Stork and Joshua Sunshine and {\'E}ric Tanter and + Roger Wolff", + title = "Permission-based programming languages", + booktitle = icse, + year = "2011", + pages = "828--831", + URL = "http://www.cs.cmu.edu/~aldrich/papers/plaid-NIER2010.pdf", +} + +@Article{plotkin-75, + author = "Gordon D. Plotkin", + title = "Call-by-name, call-by-value and the + $\lambda$-calculus", + journal = tcs, + volume = "1", + number = "2", + pages = "125--159", + year = "1975", + URL = "http://homepages.inf.ed.ac.uk/gdp/publications/cbn_cbv_lambda.pdf", +} + +@InCollection{plotkin-90, + author = "Gordon Plotkin", + title = "An illative theory of relations", + booktitle = "Situation Theory and its Applications", + pages = "133--146", + publisher = "Stanford University", + year = "1990", + number = "22", + series = "CSLI Lecture Notes", + URL = "http://homepages.inf.ed.ac.uk/gdp/publications/illative.pdf", +} + +@Article{plotkin-lcf-77, + author = "Gordon D. Plotkin", + title = "{LCF} Considered as a Programming Language", + journal = tcs, + volume = "5", + number = "3", + year = "1977", + pages = "225--255", + URL = "http://homepages.inf.ed.ac.uk/gdp/publications/LCF.pdf", +} + +@InCollection{plural-11, + author = "Kevin Bierhoff and Nels E. Beckman and Jonathan + Aldrich", + title = "Checking Concurrent Typestate with Access Permissions + in {Plural}: {A} Retrospective", + booktitle = "Engineering of Software", + pages = "35--48", + publisher = springer, + year = "2011", + editor = "Peri L. Tarr and Alexander L. Wolf", + URL = "http://www.cs.cmu.edu/~aldrich/papers/bierhoff-plural-festschrift11.pdf", +} + +@InProceedings{polikarpova-15, + author = "Nadia Polikarpova and Julian Tschannen and Carlo A. + Furia", + title = "A Fully Verified Container Library", + booktitle = fm, + pages = "414--434", + year = "2015", + series = lncs, + volume = "9109", + publisher = springer, + URL = "http://se.inf.ethz.ch/people/tschannen/publications/ptf-fm15.pdf", +} + +@Article{pollack-sato-ricciotti-11, + author = "Randy Pollack and Masahiko Sato and Wilmer Ricciotti", + title = "A Canonical Locally Named Representation of Binding", + year = "2012", + journal = jar, + volume = "49", + number = "2", + pages = "185--207", + URL = "http://homepages.inf.ed.ac.uk/rpollack/export/PollackSatoRicciottiJAR.pdf", +} + +@InProceedings{poplmark, + author = "Brian E. Aydemir and Aaron Bohannon and Matthew + Fairbairn and J. Nathan Foster and Benjamin C. Pierce + and Peter Sewell and Dimitrios Vytiniotis and Geoffrey + Washburn and Stephanie Weirich and Steve Zdancewic", + title = "Mechanized Metatheory for the Masses: The + \textsc{PoplMark} Challenge", + booktitle = tphol, + year = "2005", + series = lncs, + volume = "3603", + pages = "50--65", + publisher = springer, + URL = "http://research.microsoft.com/en-us/people/dimitris/poplmark.pdf", +} + +@Misc{popuri-bison-06, + author = "Satya Kiran Popuri", + title = "Understanding {C} parsers generated by {GNU Bison}", + year = "2006", + URL = "http://www.cs.uic.edu/~spopuri/cparser.html", +} + +@InCollection{potanin-13, + author = "Alex Potanin and Johan {\"{O}}stlund and Yoav Zibin + and Michael D. Ernst", + title = "Immutability", + booktitle = "Aliasing in Object-Oriented Programming. Types, + Analysis and Verification", + pages = "233--269", + year = "2013", + series = lncs, + volume = "7850", + publisher = springer, + URL = "https://homes.cs.washington.edu/~mernst/pubs/immutability-aliasing-2013-lncs7850.pdf", +} + +@InProceedings{pottier-alphacaml, + author = "François Pottier", + title = "An overview of {C$\alpha$ml}", + year = "2006", + booktitle = "ACM Workshop on ML", + pages = "27--52", + volume = "148", + number = "2", + series = entcs, + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-alphacaml.pdf", +} + +@Misc{pottier-alphacaml-software, + author = "François Pottier", + title = "{C$\alpha$ml}", + year = "2005", + URL = "http://gallium.inria.fr/~fpottier/alphaCaml/", +} + +@InProceedings{pottier-antiframe-08, + author = "François Pottier", + title = "Hiding local state in direct style: a higher-order + anti-frame rule", + year = "2008", + booktitle = lics, + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-antiframe-2008.pdf", + pages = "331--340", +} + +@Unpublished{pottier-caf, + author = "François Pottier", + title = "Three comments on the anti-frame rule", + note = "Unpublished", + year = "2009", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-caf-2009.pdf", +} + +@InProceedings{pottier-conchon-icfp-00, + author = "François Pottier and Sylvain Conchon", + title = "Information Flow Inference for Free", + booktitle = icfp, + year = "2000", + pages = "46--57", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-conchon-icfp00.ps.gz", +} + +@InProceedings{pottier-cpp-17, + author = "François Pottier", + title = "Verifying a hash table and its iterators in + higher-order separation logic", + booktitle = cpp, + year = "2017", + pages = "3--16", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-hashtable.pdf", +} + +@InProceedings{pottier-csfw-02, + author = "François Pottier", + title = "A Simple View of Type-Secure Information Flow in the + $\pi$-Calculus", + year = "2002", + booktitle = csfw, + pages = "320--330", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-csfw15.ps.gz", +} + +@TechReport{pottier-dea-95, + author = "François Pottier", + title = "Implémentation d'un système de modules évolué en + {Caml-Light}", + institution = "INRIA", + number = "2449", + type = "Research Report", + year = "1995", + URL = "http://gallium.inria.fr/~fpottier/publis/memoire-dea.ps.gz", +} + +@Unpublished{pottier-dfs-scc-15, + author = "François Pottier", + title = "Depth-First Search and Strong Connectivity in {Coq}", + year = "2014", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-dfs-scc.pdf", + note = "Submitted for publication", +} + +@InProceedings{pottier-esop-00, + author = "François Pottier", + title = "A 3-part type inference engine", + booktitle = esop, + publisher = springer, + series = lncs, + volume = "1782", + pages = "320--335", + year = "2000", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-esop-2000.ps.gz", +} + +@Unpublished{pottier-gaf, + author = "François Pottier", + title = "Generalizing the higher-order frame and anti-frame + rules", + note = "Unpublished", + year = "2009", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-gaf-2009.pdf", +} + +@InProceedings{pottier-gauthier-04, + author = "François Pottier and Nadji Gauthier", + title = "Polymorphic Typed Defunctionalization", + booktitle = popl, + year = "2004", + pages = "89--98", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-gauthier-popl04.pdf", +} + +@Article{pottier-gauthier-hosc, + author = "François Pottier and Nadji Gauthier", + title = "Polymorphic Typed Defunctionalization and + Concretization", + journal = hosc, + year = "2006", + volume = "19", + pages = "125--162", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-gauthier-hosc.pdf", +} + +@InProceedings{pottier-gdr-95, + author = "François Pottier", + title = "Type inference and simplification for recursively + constrained types", + booktitle = "Actes du {GDR} Programmation 1995 (journée du pôle + Programmation Fonctionnelle)", + year = "1995", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-gdr-95.ps.gz", +} + +@TechReport{pottier-hmx-01, + author = "François Pottier", + title = "A semi-syntactic soundness proof for {HM$(X)$}", + institution = "INRIA", + number = "4150", + type = "Research Report", + year = "2001", + URL = "http://hal.inria.fr/docs/00/07/24/75/PDF/RR-4150.pdf", +} + +@Article{pottier-ic-01, + author = "François Pottier", + title = "Simplifying subtyping constraints: a theory", + journal = ic, + year = "2001", + volume = "170", + number = "2", + pages = "153--183", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-ic01.ps.gz", +} + +@InProceedings{pottier-icfp-96, + author = "François Pottier", + title = "Simplifying subtyping constraints", + booktitle = icfp, + year = "1996", + pages = "122--133", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-icfp96.ps.gz", +} + +@InProceedings{pottier-icfp-98, + author = "François Pottier", + title = "A Framework for Type Inference with Subtyping", + booktitle = icfp, + year = "1998", + pages = "228--238", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-icfp98.ps.gz", +} + +@InProceedings{pottier-lics-03, + author = "François Pottier", + title = "A Constraint-Based Presentation and Generalization of + Rows", + year = "2003", + booktitle = lics, + pages = "331--340", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-lics03.ps.gz", +} + +@InProceedings{pottier-lics-07, + author = "François Pottier", + title = "Static name control for {FreshML}", + booktitle = lics, + year = "2007", + pages = "356--365", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-pure-freshml.pdf", +} + +@Article{pottier-njc-00, + author = "François Pottier", + title = "A Versatile Constraint-Based Type Inference System", + journal = njc, + year = "2000", + volume = "7", + number = "4", + pages = "312--347", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-njc-2000.ps.gz", +} + +@Misc{pottier-notes-dea, + author = "Xavier Leroy and François Pottier", + title = "Notes du cours de {DEA} «~Typage et + programmation~»", + year = "2002", + URL = "http://gallium.inria.fr/~fpottier/dea/dea-typage.ps.gz", +} + +@TechReport{pottier-phd-english-98, + author = "François Pottier", + title = "Type inference in the presence of subtyping: from + theory to practice", + institution = "INRIA", + number = "3483", + type = "Research Report", + year = "1998", + URL = "http://hal.inria.fr/docs/00/07/32/05/PDF/RR-3483.pdf", +} + +@PhdThesis{pottier-phd-french-98, + author = "François Pottier", + title = "Synthèse de types en présence de sous-typage: de la + théorie à la pratique", + school = "Université Paris 7", + year = "1998", + URL = "http://gallium.inria.fr/~fpottier/publis/these-fpottier.ps.gz", +} + +@InProceedings{pottier-protzenko-13, + author = "François Pottier and Jonathan Protzenko", + title = "Programming with permissions in {Mezzo}", + booktitle = icfp, + year = "2013", + pages = "173--184", + URL = "http://gallium.inria.fr/~fpottier/publis/pottier-protzenko-mezzo.pdf", +} + +@InProceedings{pottier-protzenko-lessons-mezzo-15, + author = "François Pottier and Jonathan Protzenko", + title = "A few lessons from the {Mezzo} project", + booktitle = snapl, + year = "2015", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-protzenko-lessons-mezzo.pdf", +} + +@InProceedings{pottier-reachability-cc-2016, + author = "François Pottier", + title = "Reachability and error diagnosis in {LR}(1) parsers", + booktitle = cc, + year = "2016", + pages = "88--98", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-reachability-cc2016.pdf", +} + +@InProceedings{pottier-reachability-jfla-2016, + author = "François Pottier", + title = "Reachability and error diagnosis in {LR}(1) automata", + booktitle = jfla, + year = "2016", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-reachability-jfla2016.pdf", +} + +@InProceedings{pottier-regis-gianas-06, + author = "François Pottier and Yann Régis-Gianas", + title = "Stratified type inference for generalized algebraic + data types", + booktitle = popl, + year = "2006", + pages = "232--244", + URL = "http://gallium.inria.fr/~fpottier/publis/pottier-regis-gianas-popl06.pdf", +} + +@Article{pottier-regis-gianas-typed-lr, + author = "François Pottier and Yann {Régis-Gianas}", + title = "Towards efficient, typed {LR} parsers", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-regis-gianas-typed-lr.pdf", + year = "2006", + pages = "155--180", + journal = entcs, + volume = "148", + number = "2", +} + +@InCollection{pottier-remy-emlti, + author = "François Pottier and Didier Rémy", + title = "The Essence of {ML} Type Inference", + booktitle = "Advanced Topics in Types and Programming Languages", + pages = "389--489", + publisher = mitp, + year = "2005", + editor = "Benjamin C. Pierce", + chapter = "10", + URL = "http://gallium.inria.fr/~fpottier/publis/emlti-final.pdf", +} + +@Unpublished{pottier-remy-emlti-long, + author = "François Pottier and Didier Rémy", + title = "The Essence of {ML} Type Inference", + note = "Draft of an extended version. Unpublished", + year = "2003", + URL = "http://cristal.inria.fr/attapl/emlti-long.pdf", +} + +@InProceedings{pottier-simonet-02, + author = "François Pottier and Vincent Simonet", + title = "Information Flow Inference for {ML}", + booktitle = popl, + year = "2002", + pages = "319--330", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-simonet-popl02.ps.gz", +} + +@Article{pottier-simonet-toplas-03, + author = "François Pottier and Vincent Simonet", + title = "Information Flow Inference for {ML}", + year = "2003", + volume = "25", + number = "1", + pages = "117--158", + journal = toplas, + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-simonet-toplas.ps.gz", +} + +@InProceedings{pottier-skalka-smith-01, + author = "François Pottier and Christian Skalka and Scott + Smith", + title = "A Systematic Approach to Static Access Control", + booktitle = esop, + publisher = springer, + series = lncs, + volume = "2028", + pages = "30--45", + year = "2001", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-skalka-smith-esop01.ps.gz", +} + +@Article{pottier-skalka-smith-05, + author = "François Pottier and Christian Skalka and Scott + Smith", + title = "A Systematic Approach to Static Access Control", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-skalka-smith-toplas.ps.gz", + volume = "27", + number = "2", + pages = "344--382", + journal = toplas, + year = "2005", +} + +@Article{pottier-ssphs-13, + author = "François Pottier", + title = "Syntactic soundness proof of a type-and-capability + system with hidden state", + journal = jfp, + volume = "23", + number = "1", + pages = "38--144", + year = "2013", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-ssphs.pdf", +} + +@Misc{pottier-wallace, + author = "François Pottier", + title = "Wallace: an efficient implementation of type inference + with subtyping", + year = "2000", + URL = "http://gallium.inria.fr/~fpottier/wallace/", +} + +@InCollection{pottinger-80, + author = "Garrel Pottinger", + title = "A type assignment for the strongly normalizable + $\lambda$-terms", + booktitle = "To H. B. Curry: Essays on Combinatory Logic, Lambda + Calculus, and Formalism", + pages = "561--577", + publisher = ap, + year = "1980", + editor = "J. Roger Hindley and Jonathan P. Seldin", +} + +@InProceedings{pouillard-11, + author = "Nicolas Pouillard", + title = "Nameless, painless", + booktitle = icfp, + year = "2011", + pages = "320--332", + URL = "http://nicolaspouillard.fr/publis/nameless-painless.pdf", +} + +@InProceedings{pouillard-pottier-10, + author = "Nicolas Pouillard and François Pottier", + title = "A fresh look at programming with names and binders", + booktitle = icfp, + year = "2010", + pages = "217--228", + URL = "http://gallium.inria.fr/~fpottier/publis/pouillard-pottier-fresh-look.pdf", +} + +@Article{pouillard-pottier-12, + author = "Nicolas Pouillard and François Pottier", + title = "A unified treatment of syntax with binders", + journal = jfp, + volume = "22", + number = "4--5", + pages = "614--704", + year = "2012", + URL = "http://gallium.inria.fr/~fpottier/publis/pouillard-pottier-unified.pdf", +} + +@Article{pratt-tiuryn-96, + author = "Vaughan Pratt and Jerzy Tiuryn", + title = "Satisfiability of Inequalities in a Poset", + journal = fundamenta, + year = "1996", + volume = "28", + number = "1--2", + pages = "165--182", + URL = "ftp://ftp.mimuw.edu.pl/pub/users/tiuryn/sat-ineq.ps.gz", +} + +@Article{pretnar-15, + author = "Matija Pretnar", + title = "An Introduction to Algebraic Effects and Handlers", + journal = entcs, + volume = "319", + pages = "19--35", + year = "2015", + URL = "http://www.eff-lang.org/handlers-tutorial.pdf", +} + +@Misc{programatica-04, + author = "Thomas Hallgren and James Hook and Mark P. Jones and + Richard Kieburtz", + title = "An overview of the {Programatica} ToolSet", + howpublished = "High Confidence Software and Systems Conference + (HCSS)", + year = "2004", + URL = "http://ogi.altocumulus.org/~hallgren/Programatica/HCSS04/hcss04-tools.pdf", +} + +@Book{proofs-and-types, + author = "Jean-Yves Girard and Yves Lafont and Paul Taylor", + title = "Proofs and Types", + publisher = cup, + year = "1990", + URL = "http://www.paultaylor.eu/stable/prot.pdf", +} + +@PhdThesis{protzenko-phd-14, + author = "Jonathan Protzenko", + title = "{Mezzo}: a typed language for safe effectful + concurrent programs", + year = "2014", + school = "Université Paris Diderot", + URL = "https://hal.inria.fr/tel-01086106/document", +} + +@InProceedings{pugh-weddell-90, + author = "William Pugh and Grant Weddell", + title = "Two-directional record layout for multiple + inheritance", + booktitle = pldi, + pages = "85--91", + year = "1990", + URL = "http://doi.acm.org/10.1145/93542.93556", +} + +@Article{purdom-74, + author = "Paul Purdom", + title = "The size of {LALR(1)} parsers", + year = "1974", + journal = "BIT Numerical Mathematics", + volume = "14", + number = "3", + URL = "http://dx.doi.org/10.1007/BF01933232", + publisher = kluwer, + pages = "326--337", +} + +@Article{qian-96, + author = "Zhenyu Qian", + title = "Unification of higher-order patterns in linear time + and space", + journal = jlc, + year = "1996", + volume = "6", + number = "3", + pages = "315--341", +} + +@TechReport{raffalli-98, + author = "Christophe Raffalli", + title = "Type checking in system ${F}^\eta$", + institution = "LAMA, Université de Savoie", + year = "1998", + type = "Prépublication", + number = "98-05a", + URL = "ftp://www.lama.univ-savoie.fr/pub/users/RAFFALLI/Papers/Feta-partial.ps", +} + +@Unpublished{raffalli-99, + author = "Christophe Raffalli", + title = "An optimized complete semi-algorithm for system + ${F}^\eta$", + note = "Unpublished", + year = "1999", + URL = "ftp://www.lama.univ-savoie.fr/pub/users/RAFFALLI/Papers/Feta-total.ps", +} + +@InProceedings{ramachandran-93, + author = "Viswanath Ramachandran and Pascal Van Hentenryck", + title = "Incremental Algorithms for Constraint Solving and + Entailment over Rational Trees", + booktitle = fsttcs, + pages = "205--217", + year = "1993", +} + +@InProceedings{ramalingam-02, + author = "G. Ramalingam and Alex Varshavsky and John Field and + Deepak Goyal and Shmuel Sagiv", + title = "Deriving Specialized Program Analyses for Certifying + Component-Client Conformance", + booktitle = pldi, + pages = "83--94", + year = "2002", + URL = "http://pages.cs.wisc.edu/~ramali/Papers/pldi02.pdf", +} + +@Book{real-world-ocaml, + author = "Yaron Minsky and Anil Madhavapeddy and Jason Hickey", + title = "Real World {OCaml}: Functional programming for the + masses", + publisher = "O'Reilly", + year = "2013", + URL = "https://realworldocaml.org/", +} + +@InProceedings{recursive-alias-types-00, + author = "David Walker and Greg Morrisett", + title = "Alias Types for Recursive Data Structures", + booktitle = tic, + year = "2000", + series = lncs, + volume = "2071", + pages = "177--206", + publisher = springer, + URL = "http://www.cs.cornell.edu/talc/papers/alias-recursion.pdf", +} + +@TechReport{reed-15, + author = "Eric Reed", + title = "Patina: {A} Formalization of the {Rust} Programming + Language", + institution = "University of Washington", + year = "2015", + number = "UW-CSE-15-03-02", + URL = "ftp://ftp.cs.washington.edu/tr/2015/03/UW-CSE-15-03-02.pdf", +} + +@InProceedings{regensburger-holcf-95, + author = "Franz Regensburger", + title = "{HOLCF}: Higher Order Logic of Computable Functions", + booktitle = tphol, + year = "1995", + pages = "293--307", + publisher = springer, + series = lncs, + volume = "971", + URL = "http://www4.informatik.tu-muenchen.de/publ/papers/Regensburger_HOLT1995.pdf", +} + +@PhdThesis{regis-gianas-07, + author = "Yann Régis-Gianas", + title = "Des types aux assertions logiques : preuve automatique + ou assistée de propriétés sur les programmes + fonctionnels", + school = "Université Paris 7", + year = "2007", + URL = "http://gallium.inria.fr/~regisgia/these-yann.regis-gianas.pdf", +} + +@InProceedings{regis-gianas-pottier-08, + author = "Yann Régis-Gianas and François Pottier", + title = "A {Hoare} Logic for Call-by-Value Functional + Programs", + booktitle = mpc, + year = "2008", + series = lncs, + volume = "5133", + publisher = springer, + URL = "http://gallium.inria.fr/~fpottier/publis/regis-gianas-pottier-hoarefp.pdf", + pages = "305--335", +} + +@InProceedings{rehof-faehndrich-01, + author = "Jakob Rehof and Manuel Fähndrich", + title = "Type-Based Flow Analysis: From Polymorphic Subtyping + to {CFL}-Reachability", + booktitle = popl, + pages = "54--66", + year = "2001", + URL = "http://research.microsoft.com/~rehof/popl01.ps", +} + +@TechReport{rehof-minimality-96, + author = "Jakob Rehof", + year = "1996", + title = "Minimal Typings in Atomic Subtyping", + institution = "Department of Computer Science, University of + Copenhagen", + number = "D-278", + URL = "ftp://ftp.diku.dk/diku/semantics/papers/D-278.ps.gz", +} + +@InProceedings{rehof-minimality-97, + author = "Jakob Rehof", + title = "Minimal Typings in Atomic Subtyping", + booktitle = popl, + year = "1997", + pages = "278--291", + URL = "http://research.microsoft.com/~rehof/popl97.ps", +} + +@InProceedings{reistad-gifford-94, + author = "Brian Reistad and David K. Gifford", + title = "Static dependent costs for estimating execution time", + booktitle = lfp, + year = "1994", + pages = "65--78", + URL = "https://groups.csail.mit.edu/cgs/pubs/lfp94.pdf", +} + +@InProceedings{remy-89, + author = "Didier Rémy", + title = "Type checking records and variants in a natural + extension of {ML}", + booktitle = popl, + pages = "77--88", + year = "1989", + URL = "http://doi.acm.org/10.1145/75277.75284", +} + +@InProceedings{remy-efficient-records-92, + author = "Didier Rémy", + title = "Efficient Representation of Extensible Records", + booktitle = mlapp, + year = "1992", + URL = "http://gallium.inria.fr/~remy/ftp/eff-repr-of-ext-records.pdf", +} + +@TechReport{remy-equational-92, + author = "Didier R{\'e}my", + title = "Extending {ML} Type System with a Sorted Equational + Theory", + institution = "INRIA", + number = "1766", + year = "1992", + URL = "http://gallium.inria.fr/~remy/ftp/eq-theory-on-types.pdf", +} + +@InProceedings{remy-esop-98, + author = "Didier R{\'e}my", + title = "From Classes to Objects via Subtyping", + booktitle = esop, + year = "1998", + series = lncs, + publisher = springer, + volume = "1381", + pages = "200--220", + URL = "http://gallium.inria.fr/~remy/ftp/classes-to-objects.pdf", +} + +@InCollection{remy-for-free-94, + author = "Didier R{\'e}my", + title = "Typing Record Concatenation for Free", + booktitle = "Theoretical Aspects Of Object-Oriented Programming. + Types, Semantics and Language Design", + publisher = mitp, + year = "1994", + editor = "Carl A. Gunter and John C. Mitchell", + URL = "http://gallium.inria.fr/~remy/ftp/taoop2.pdf", +} + +@InProceedings{remy-icfp-05, + author = "Didier Rémy", + title = "Simple, partial type inference for System ${F}$ based + on type containment", + booktitle = icfp, + year = "2005", + URL = "http://gallium.inria.fr/~remy/work/fml/fml-icfp.pdf", +} + +@InProceedings{remy-icfp05, + author = "Didier Rémy", + title = "Simple, partial type inference for System ${F}$ based + on type containment", + booktitle = icfp, + year = "2005", + URL = "http://gallium.inria.fr/~remy/work/fml/fml-icfp.pdf", +} + +@InProceedings{remy-lfp-92, + author = "Didier R{\'e}my", + title = "Projective {ML}", + booktitle = lfp, + pages = "66--75", + year = "1992", + URL = "http://gallium.inria.fr/~remy/ftp/lfp92.pdf", +} + +@InProceedings{remy-mlart-94, + author = "Didier R{\'e}my", + title = "Programming Objects with {ML-ART}: An extension to + {ML} with Abstract and Record Types", + booktitle = tacs, + year = "1994", + pages = "321--346", + publisher = springer, + URL = "http://gallium.inria.fr/~remy/ftp/tacs94.pdf", +} + +@Misc{remy-newton-95, + author = "Didier R{\'e}my", + title = "A case study of typechecking with constrained types: + Typing record concatenation", + howpublished = "Workshop on Advances in Types for Computer Science", + year = "1995", + URL = "http://gallium.inria.fr/~remy/work/sub-concat.dvi.gz", +} + +@InCollection{remy-records-94, + author = "Didier R{\'e}my", + title = "Type Inference for Records in a Natural Extension of + {ML}", + booktitle = "Theoretical Aspects Of Object-Oriented Programming: + Types, Semantics and Language Design", + publisher = mitp, + year = "1994", + editor = "Carl A. Gunter and John C. Mitchell", + URL = "http://gallium.inria.fr/~remy/ftp/taoop1.pdf", +} + +@TechReport{remy-start-93, + author = "Didier R{\'e}my", + title = "Syntactic Theories and the Algebra of Record Terms", + institution = "INRIA", + number = "1869", + year = "1993", + type = "Research Report", + URL = "http://gallium.inria.fr/~remy/ftp/record-algebras.pdf", +} + +@InProceedings{remy-vouillon-objective-ml-97, + author = "Didier R{\'e}my and J{\'e}r{\^o}me Vouillon", + title = "{Objective} {ML}: {A} simple object-oriented extension + of {ML}", + booktitle = popl, + year = "1997", + pages = "40--53", + URL = "http://gallium.inria.fr/~remy/ftp/objective-ml!popl97.pdf", +} + +@Article{remy-vouillon-objective-ml-98, + author = "Didier R{\'e}my and J{\'e}r{\^o}me Vouillon", + title = "{Objective} {ML}: {An} effective object-oriented + extension to {ML}", + journal = tapos, + year = "1998", + pages = "27--50", + volume = "4", + number = "1", + URL = "http://gallium.inria.fr/~remy/ftp/objective-ml!tapos98.pdf", +} + +@Article{remy-yakobowski-11, + author = "Didier R{\'e}my and Boris Yakobowski", + title = "A {Church}-Style Intermediate Language for {MLF}", + journal = tcs, + year = "2012", + volume = "435", + number = "1", + pages = "77--105", + URL = "http://gallium.inria.fr/~remy/mlf/Remy-Yakobowski:xmlf@tcs2011.pdf", +} + +@Article{reps-98, + author = "Thomas Reps", + title = "Program analysis via graph reachability", + journal = ist, + year = "1998", + volume = "40", + number = "11--12", + pages = "701--726", + URL = "http://www.cs.wisc.edu/wpis/papers/tr1386.pdf", +} + +@PhdThesis{retert-09, + author = "William S. Retert", + title = "Implementing Permission Analysis", + school = "University of Wisconsin-Milwaukee", + year = "2009", +} + +@InProceedings{reus-schwinghammer-06, + title = "Separation Logic for Higher-order Store", + year = "2006", + author = "Bernhard Reus and Jan Schwinghammer", + booktitle = csl, + series = lncs, + volume = "4207", + publisher = springer, + pages = "575--590", + URL = "http://www.ps.uni-sb.de/Papers/abstracts/seplogic-hos.pdf", +} + +@Article{revuz-92, + author = "Dominique Revuz", + title = "Minimization of acyclic deterministic automata in + linear time", + journal = tcs, + volume = "92", + number = "1", + year = "1992", + pages = "181--189", +} + +@InProceedings{reynolds-02, + author = "John C. Reynolds", + title = "Separation Logic: {A} Logic for Shared Mutable Data + Structures", + booktitle = lics, + pages = "55--74", + year = "2002", + URL = "http://www.cs.cmu.edu/~jcr/seplogic.pdf", +} + +@InProceedings{reynolds-69, + author = "John C. Reynolds", + title = "Automatic Computation of Data Set Definitions", + booktitle = "Information Processing 68", + volume = "1", + publisher = "North Holland", + year = "1969", + pages = "456--461", +} + +@InProceedings{reynolds-74, + author = "John C. Reynolds", + title = "Towards a theory of type structure", + booktitle = "Colloque sur la Programmation", + pages = "408--425", + year = "1974", + volume = "19", + series = lncs, + publisher = springer, + URL = "http://www.springerlink.com/content/p5801737k78207p7/", +} + +@TechReport{reynolds-75, + author = "John C. Reynolds", + title = "User-defined Types and Procedural Data Structures as + Complementary Approaches to Data Abstraction", + institution = "Carnegie Mellon University", + year = "1975", + number = "1278", + URL = "http://repository.cmu.edu/compsci/1278/", +} + +@InProceedings{reynolds-78, + author = "John C. Reynolds", + title = "Syntactic control of interference", + booktitle = popl, + year = "1978", + pages = "39--46", + URL = "http://doi.acm.org/10.1145/512760.512766", +} + +@InProceedings{reynolds-83, + author = "John C. Reynolds", + title = "Types, Abstraction and Parametric Polymorphism", + booktitle = "Information Processing 83", + publisher = elsevier, + year = "1983", + pages = "513--523", + URL = "http://www.cse.chalmers.se/edu/year/2010/course/DAT140_Types/Reynolds_typesabpara.pdf", +} + +@InProceedings{reynolds-85, + author = "John C. Reynolds", + title = "Three Approaches to Type Structure", + booktitle = tapsoft, + series = lncs, + volume = "185", + publisher = springer, + year = "1985", + pages = "97--138", + URL = "http://dx.doi.org/10.1007/3-540-15198-2_7", +} + +@Article{reynolds-98a, + author = "John C. Reynolds", + title = "Definitional Interpreters for Higher-Order Programming + Languages", + journal = "Higher-Order and Symbolic Computation", + volume = "11", + number = "4", + pages = "363--397", + year = "1998", + URL = "https://cs.au.dk/~hosc/local/HOSC-11-4-pp363-397.pdf", +} + +@Article{reynolds-98b, + author = "John C. Reynolds", + title = "Definitional Interpreters Revisited", + journal = "Higher-Order and Symbolic Computation", + volume = "11", + number = "4", + pages = "355--361", + year = "1998", + URL = "https://cs.au.dk/~hosc/local/HOSC-11-4-pp355-361.pdf", +} + +@InCollection{reynolds-abstraction-94, + author = "John C. Reynolds", + title = "User Defined Types and Procedural Data Structures as + Complementary Approaches to Data Abstraction", + booktitle = taoop, + publisher = mitp, + year = "1994", + pages = "13--23", + editor = "Carl A. Gunter and John C. Mitchell", +} + +@InCollection{reynolds-intro-90, + author = "John C. Reynolds", + title = "An Introduction to the Polymorphic Lambda Calculus", + booktitle = "Logical Foundations of Functional Programming", + editor = "G{\'e}rard Huet", + publisher = aw, + year = "1990", + pages = "77--86", + URL = "http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.7.9916", +} + +@Article{rhiger-03, + author = "Morten Rhiger", + title = "A Foundation for Embedded Languages", + journal = toplas, + year = "2003", + volume = "25", + number = "3", + pages = "291--315", + URL = "http://doi.acm.org/10.1145/641909.641910", +} + +@InProceedings{riba-09, + author = "Colin Riba", + title = "On the Values of Reducibility Candidates", + booktitle = tlca, + year = "2009", + pages = "264--278", + publisher = springer, + series = lncs, + volume = "5608", + URL = "http://perso.ens-lyon.fr/colin.riba/papers/values.pdf", +} + +@InProceedings{ringenburg-grossman-05, + author = "Michael F. Ringenburg and Dan Grossman", + title = "Types for Describing Coordinated Data Structures", + booktitle = tldi, + pages = "25--36", + year = "2005", + URL = "http://www.cs.washington.edu/homes/miker/coord/coordinated_tldi05.pdf", +} + +@Article{rittri-89, + author = "Mikael Rittri", + title = "Using types as Search Keys in Function Libraries", + journal = jfp, + volume = "1", + number = "1", + pages = "71--89", + year = "1991", +} + +@Article{rittri-93, + author = "Mikael Rittri", + title = "Retrieving library functions by unifying types modulo + linear isomorphism", + journal = rairo, + year = "1993", + volume = "27", + number = "6", + pages = "523--540", +} + +@PhdThesis{rival-hdr, + author = "Xavier Rival", + title = "Abstract Domains for the Static Analysis of Programs + Manipulating Complex Data Structures", + school = "École Normale Supérieure", + year = "2011", + type = "Habilitation à diriger des recherches", + URL = "http://www.di.ens.fr/~rival/hdr.pdf", +} + +@Article{robinson-65, + author = "J. Alan Robinson", + title = "A Machine-Oriented Logic Based on the Resolution + Principle", + journal = jacm, + year = "1965", + volume = "12", + number = "1", + pages = "23--41", + URL = "http://doi.acm.org/10.1145/321250.321253", +} + +@InProceedings{rompf-amin-16, + author = "Tiark Rompf and Nada Amin", + title = "Type soundness for dependent object types {(DOT)}", + booktitle = oopsla, + pages = "624--641", + year = "2016", + URL = "http://lampwww.epfl.ch/~amin/dot/soundness_oopsla16.pdf", +} + +@Article{ross-sagiv-98, + author = "John L. Ross and Mooly Sagiv", + title = "Building a Bridge between Pointer Aliases and Program + Dependences", + journal = njc, + volume = "5", + number = "4", + year = "1998", + mon = "Winter", + pages = "361--386", + URL = "http://www.math.tau.ac.il/~msagiv/njc98.ps", +} + +@InProceedings{rossberg-15, + author = "Andreas Rossberg", + title = "{1ML} -- core and modules united ({F}-ing first-class + modules)", + booktitle = icfp, + pages = "35--47", + year = "2015", + URL = "https://people.mpi-sws.org/~rossberg/papers/Rossberg%20-%201ML%20--%20Core%20and%20modules%20united.pdf", +} + +@Article{rossberg-russo-dreyer-14, + author = "Andreas Rossberg and Claudio V. Russo and Derek + Dreyer", + title = "{F}-ing modules", + journal = jfp, + volume = "24", + number = "5", + pages = "529--607", + year = "2014", + URL = "https://people.mpi-sws.org/~rossberg/papers/Rossberg,%20Russo,%20Dreyer%20-%20F-ing%20Modules%20[JFP].pdf", +} + +@Article{runciman-toyn-91, + author = "Colin Runciman and Ian Toyn", + title = "Retrieving re-usable software components by + polymorphic type", + journal = jfp, + year = "1991", + pages = "191--211", + volume = "1", + number = "2", +} + +@Book{russell-norvig-09, + author = "Stuart Russell and Peter Norvig", + title = "Artificial Intelligence: {A} Modern Approach", + publisher = prentice, + year = "2009", + URL = "http://aima.cs.berkeley.edu/", +} + +@PhdThesis{russo-98, + school = "University of Edinburgh", + title = "Types For Modules", + year = "1998", + pages = "360", + author = "Claudio V. Russo", + URL = "http://www.dcs.ed.ac.uk/home/cvr/ECS-LFCS-98-389.html", +} + +@Misc{rust, + title = "The {Rust} programming language", + author = "{The Mozilla foundation}", + year = "2014", + URL = "https://doc.rust-lang.org/book/", +} + +@InProceedings{rust-14, + author = "Nicholas D. Matsakis and Felix S. {Klock,II}", + title = "The {Rust} Language", + booktitle = hilt, + year = "2014", + pages = "103--104", + URL = "http://doi.acm.org/10.1145/2663171.2663188", +} + +@Unpublished{rust-servo-15, + author = "Brian Anderson and Lars Bergstrom and David Herman and + Josh Matthews and Keegan McAllister and Manish + Goregaokar and Jack Moffitt and Simon Sapin", + title = "Experience Report: Developing the {Servo} Web Browser + Engine using {Rust}", + year = "2015", + URL = "http://arxiv.org/abs/1505.07383", +} + +@InProceedings{sabelfeld-sands-99, + author = "Andrei Sabelfeld and David Sands", + title = "A {PER} Model of Secure Information Flow in Sequential + Programs", + booktitle = esop, + volume = "1575", + series = lncs, + year = "1999", + publisher = springer, + pages = "40--58", + URL = "http://www.cse.chalmers.se/~andrei/esop99.ps", +} + +@InProceedings{sabin-freuder-94, + author = "Daniel Sabin and Eugene C. Freuder", + title = "Contradicting Conventional Wisdom in Constraint + Satisfaction", + booktitle = ppcp, + publisher = springer, + series = lncs, + volume = "874", + year = "1994", + pages = "10--20", + URL = "http://4c.ucc.ie/web/upload/publications/inProc/sabin94contradicting.pdf", +} + +@Article{sabry-98, + author = "Amr Sabry", + title = "What is a Purely Functional Language?", + journal = jfp, + year = "1998", + volume = "8", + number = "1", + pages = "1--22", + URL = "http://dx.doi.org/10.1017/S0956796897002943", +} + +@InProceedings{sage-06, + author = "Jessica Gronski and Kenneth Knowles and Aaron Tomb and + Stephen N. Freund and Cormac Flanagan", + title = "{Sage}: Hybrid Checking for Flexible Specifications", + booktitle = "Scheme and Functional Programming", + year = "2006", + pages = "93--104", + URL = "http://www.cs.williams.edu/~freund/papers/06-sfp.pdf", +} + +@TechReport{saha-al-98, + author = "Bratin Saha and Nevin Heintze and Dino Oliva", + title = "Subtransitive {CFA} using Types", + institution = "Yale University", + year = "1998", + number = "YALEU/DCS/TR-1166", + URL = "http://flint.cs.yale.edu/flint/publications/cfa.ps.gz", +} + +@InProceedings{sands-90, + author = "David Sands", + title = "Complexity Analysis for a Lazy Higher-Order Language", + booktitle = esop, + pages = "361--376", + year = "1990", + series = lncs, + volume = "432", + publisher = springer, + URL = "http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.42.9125", +} + +@InProceedings{sands-gustavsson-moran-02, + author = "David Sands and J{\"{o}}rgen Gustavsson and Andrew + Moran", + title = "Lambda Calculi and Linear Speedups", + booktitle = "The Essence of Computation, Complexity, Analysis, + Transformation. Essays Dedicated to Neil D. Jones", + pages = "60--84", + year = "2002", + volume = "2566", + publisher = springer, + series = lncs, + URL = "http://www.cse.chalmers.se/~dave/papers/Sands-Gustavsson-Moran.pdf", +} + +@Article{sangiorgi-98, + author = "Davide Sangiorgi", + title = "On the bisimulation proof method", + journal = mscs, + volume = "8", + number = "5", + pages = "447--479", + year = "1998", + URL = "http://www.cs.unibo.it/~sangio/DOC_public/bis-proof.ps.gz", +} + +@InProceedings{sansom-93, + author = "Patrick M. Sansom", + title = "Time profiling a lazy functional compiler", + booktitle = "Functional Programming, Workshops in Computing", + year = "1993", + publisher = springer, + URL = "ftp://ftp.dcs.glasgow.ac.uk/pub/glasgow-fp/authors/Patrick_Sansom/1993_profiling-compiler_GLASGOWFP.ps.gz", +} + +@Book{scala, + author = "Martin Odersky and Lex Spoon and Bill Venners", + title = "Programming in {Scala}, Third Edition: {A} + Comprehensive Step-by-step Guide", + year = "2016", + publisher = "Artima Incorporation", + URL = "http://www.artima.com/shop/programming_in_scala_3ed", +} + +@InProceedings{scala-05, + author = "Martin Odersky and Matthias Zenger", + title = "Scalable Component Abstractions", + booktitle = oopsla, + pages = "41--57", + year = "2005", + URL = "http://lamp.epfl.ch/~odersky/papers/ScalableComponent.pdf", +} + +@PhdThesis{schimpf-81, + author = "Karl Max Schimpf", + title = "Construction Methods of {LR} Parsers", + school = "University of Pennsylvania", + year = "1981", + URL = "http://repository.upenn.edu/cis_reports/725/", +} + +@Article{schneider-00, + author = "Fred B. Schneider", + title = "Enforceable security policies", + year = "2000", + journal = tissec, + volume = "3", + number = "1", + pages = "1--50", + URL = "http://www.cs.cornell.edu/fbs/publications/EnfSecPols.pdf", +} + +@Book{schneider-97, + author = "Fred B. Schneider", + title = "On Concurrent Programming", + publisher = springer, + year = "1997", +} + +@InProceedings{schroeder-mossakowski-02, + author = "Lutz Schr{\"o}der and Till Mossakowski", + title = "{HasCASL}: Towards Integrated Specification and + Development of Functional Programs", + booktitle = amast, + year = "2002", + pages = "99--116", + publisher = springer, + series = lncs, + volume = "2422", + URL = "http://www.informatik.uni-bremen.de/~lschrode/hascasl/recursion.ps", +} + +@Article{schubert-83, + author = "Lenhart K. Schubert and Mary Angela Papalaskaris and + Jay Taugher", + title = "Determining Type, Part, Color, and Time + Relationships", + journal = computer, + volume = "16", + number = "10", + pages = "53--60", + year = "1983", +} + +@TechReport{schwartzbach-95, + author = "Michael I. Schwartzbach", + title = "Polymorphic Type Inference", + institution = "BRICS", + year = "1995", + number = "BRICS-LS-95-3", + URL = "http://www.brics.dk/LS/95/3/BRICS-LS-95-3.ps.gz", +} + +@InProceedings{schwinghammer-birkedal-stovring-11, + author = "Jan Schwinghammer and Lars Birkedal and Kristian + Støvring", + title = "A step-indexed {Kripke} model of hidden state via + recursive properties on recursively defined metric + spaces", + booktitle = fossacs, + year = "2011", + number = "6604", + pages = "305--319", + series = lncs, + publisher = springer, + URL = "http://www.itu.dk/~birkedal/papers/relpoms-antiframe-conf.pdf", +} + +@InProceedings{schwinghammer-csl-09, + author = "Jan Schwinghammer and Lars Birkedal and Bernhard Reus + and Hongseok Yang", + title = "Nested {Hoare} triples and frame rules for + higher-order store", + booktitle = csl, + pages = "440--454", + year = "2009", + volume = "5771", + series = lncs, + publisher = springer, + URL = "http://www.itu.dk/~birkedal/papers/nested-triples-conf.pdf", +} + +@InProceedings{schwinghammer-sfhs-10, + author = "Jan Schwinghammer and Hongseok Yang and Lars Birkedal + and François Pottier and Bernhard Reus", + title = "A Semantic Foundation for Hidden State", + booktitle = fossacs, + year = "2010", + pages = "2--17", + publisher = springer, + series = lncs, + volume = "6014", + URL = "http://gallium.inria.fr/~fpottier/publis/sfhs.pdf", +} + +@PhdThesis{schwoon-02, + author = "Stefan Schwoon", + title = "Model-Checking Pushdown Systems", + school = "Technische Universit{\"a}t M{\"u}nchen", + year = "2002", + URL = "http://www.lsv.ens-cachan.fr/Publis/PAPERS/PDF/schwoon-phd02.pdf", +} + +@Article{scott-lcf-93, + author = "Dana S. Scott", + title = "A Type-Theoretical Alternative to {ISWIM}, {CUCH}, + {OWHY}", + journal = tcs, + volume = "121", + number = "1--2", + year = "1993", + pages = "411--440", + URL = "http://dx.doi.org/10.1016/0304-3975(93)90095-B", +} + +@Book{sedgewick-graphs-java, + author = "Robert Sedgewick and Michael Schidlowsky", + title = "Algorithms in {Java}: Graph Algorithms", + publisher = aw, + year = "2003", +} + +@Article{seidel-sharir-05, + author = "Raimund Seidel and Micha Sharir", + title = "Top-Down Analysis of Path Compression", + journal = siamjc, + volume = "34", + number = "3", + pages = "515--525", + year = "2005", + URL = "http://dx.doi.org/10.1137/S0097539703439088", +} + +@Article{sekar-al-95, + title = "Adaptive Pattern Matching", + author = "R. C. Sekar and R. Ramesh and I. V. Ramakrishnan", + pages = "1207--1234", + journal = siamjc, + year = "1995", + volume = "24", + number = "6", + URL = "http://seclab.cs.sunysb.edu/sekar/papers/adaptive.ps", + alturl = "http://locus.siam.org/fulltext/SICOMP/volume-24/0224073.pdf", +} + +@Article{sethi-ullman-70, + author = "Ravi Sethi and J. D. Ullman", + title = "The Generation of Optimal Code for Arithmetic + Expressions", + journal = jacm, + volume = "17", + number = "4", + year = "1970", + pages = "715--728", + URL = "http://doi.acm.org/10.1145/321607.321620", +} + +@InProceedings{sewell-vitek-00, + author = "Peter Sewell and Jan Vitek", + title = "Secure Composition of Untrusted Code: Wrappers and + Causality Types", + year = "2000", + booktitle = csfw, + URL = "http://www.cl.cam.ac.uk/users/pes20/wraptypes.ps", +} + +@TechReport{sewell-vitek-99, + author = "Peter Sewell and Jan Vitek", + title = "Secure Composition of Untrusted Code: Wrappers and + Causality Types", + number = "478", + institution = "Computer Laboratory, University of Cambridge", + year = "1999", + URL = "http://www.cl.cam.ac.uk/users/pes20/wraptypes-tr.ps", +} + +@Article{sha-steiglitz-93, + author = "Edwin Hsing-Mean Sha and Kenneth Steiglitz", + title = "Maintaining Bipartite Matchings in the Presence of + Failures", + journal = "Networks", + year = "1993", + volume = "23", + number = "5", + pages = "459--471", + URL = "http://www.nd.edu/~esha/papers/oldsha/alg.ps", +} + +@Article{shao-certified-05, + author = "Zhong Shao and Valery Trifonov and Bratin Saha and + Nikolaos Papaspyrou", + title = "A type system for certified binaries", + journal = toplas, + volume = "27", + number = "1", + year = "2005", + pages = "1--45", + URL = "http://flint.cs.yale.edu/flint/publications/tscb-toplas.pdf", +} + +@InProceedings{sheard-04, + author = "Tim Sheard", + title = "Languages of the Future", + booktitle = oopsla, + year = "2004", + pages = "116--119", + URL = "http://doi.acm.org/10.1145/1028664.1028711", +} + +@InProceedings{sheard-05, + author = "Tim Sheard", + title = "Putting {Curry-Howard} To Work", + booktitle = hw, + year = "2005", + pages = "74--85", + URL = "http://web.cecs.pdx.edu/~sheard/papers/PutCurryHoward2WorkFinalVersion.ps", +} + +@InProceedings{sheard-challenges-01, + author = "Tim Sheard", + title = "Accomplishments and Research Challenges in + Meta-Programming", + booktitle = saig, + pages = "2--44", + year = "2001", + volume = "2196", + series = lncs, + publisher = springer, + URL = "http://www.cse.ogi.edu/PacSoft/publications/2001/challeges_sheard.pdf", +} + +@InProceedings{sheard-metaml-98, + author = "Tim Sheard", + title = "Using {MetaML}: {A} staged Programming Language", + booktitle = afp, + pages = "207--239", + year = "1998", + volume = "1608", + series = lncs, + publisher = springer, + URL = "http://web.cecs.pdx.edu/~sheard/papers/summerschool.ps", +} + +@InProceedings{sheard-pasalic-04, + author = "Tim Sheard and Emir Pa{\v s}ali{\'c}", + title = "Meta-Programming with Built-in Type Equality", + booktitle = lfm, + year = "2004", + URL = "http://cs-www.cs.yale.edu/homes/carsten/lfm04/proceedings/pasalic.pdf", +} + +@InProceedings{shields-peyton-jones-02, + author = "Mark B. Shields and Simon {Peyton Jones}", + title = "First class modules for {Haskell}", + booktitle = fool, + year = "2002", + pages = "28--40", + URL = "http://www.cse.ogi.edu/~mbs/pub/first_class_modules/first_class_modules.pdf", +} + +@InProceedings{shinwell-03, + author = "Mark R. Shinwell and Andrew M. Pitts and Murdoch J. + Gabbay", + title = "{FreshML}: Programming with Binders Made Simple", + booktitle = icfp, + pages = "263--274", + year = "2003", + URL = "http://www.cl.cam.ac.uk/~amp12/papers/frepbm/frepbm.pdf", +} + +@Article{shinwell-05, + author = "Mark R. Shinwell", + title = "{Fresh O'Caml}: nominal abstract syntax for the + masses", + journal = entcs, + year = "2006", + volume = "148", + number = "2", + pages = "53--77", + URL = "http://dx.doi.org/10.1016/j.entcs.2005.11.040", +} + +@PhdThesis{shinwell-phd, + author = "Mark R. Shinwell", + title = "The Fresh Approach: functional programming with names + and binders", + school = "University of Cambridge", + year = "2005", + URL = "http://www.cl.cam.ac.uk/users/mrs30/papers/thesis.pdf", +} + +@Article{shinwell-pitts-05, + author = "Mark R. Shinwell and Andrew M. Pitts", + title = "On a Monadic Semantics for Freshness", + journal = tcs, + year = "2005", + volume = "342", + pages = "28--55", + URL = "http://www.cl.cam.ac.uk/users/amp12/papers/monsf/monsf-jv.pdf", +} + +@InProceedings{shivers-96, + author = "Olin Shivers", + title = "A universal scripting framework or, {Lambda}: the + ultimate ``little language''", + booktitle = "Concurrency and Parallelism: Programming, Networking + and Security", + pages = "254--265", + year = "1996", + volume = "1179", + series = lncs, + publisher = springer, + URL = "http://www.ai.mit.edu/people/shivers/ll.ps", +} + +@Article{sikmhs-12, + author = "Jan Schwinghammer and Lars Birkedal and François + Pottier and Bernhard Reus and Kristian St{\o}vring and + Hongseok Yang", + title = "A step-indexed {Kripke} Model of Hidden State", + journal = mscs, + note = "To appear", + year = "2012", + URL = "http://gallium.inria.fr/~fpottier/publis/sikmhs.pdf", +} + +@InProceedings{simonet-02, + author = "Vincent Simonet", + title = "Fine-grained Information Flow Analysis for a + $\lambda$-calculus with Sum Types", + booktitle = csfw, + pages = "223--237", + year = "2002", + URL = "http://gallium.inria.fr/~simonet/publis/simonet-csfw-02.ps.gz", +} + +@InProceedings{simonet-03, + author = "Vincent Simonet", + title = "An Extension of {HM(X)} with Bounded Existential and + Universal Data-Types", + year = "2003", + booktitle = icfp, + URL = "http://gallium.inria.fr/~simonet/publis/simonet-icfp03.ps.gz", +} + +@TechReport{simonet-flowcaml-manual, + author = "Vincent Simonet", + title = "The {Flow Caml} system: documentation and user's + manual", + institution = "INRIA", + number = "0282", + year = "2003", + URL = "http://gallium.inria.fr/~simonet/soft/flowcaml/manual/", +} + +@TechReport{simonet-pottier-hmg, + author = "Vincent Simonet and François Pottier", + title = "Constraint-Based Type Inference for Guarded Algebraic + Data Types", + year = "2005", + institution = "INRIA", + type = "Research Report", + number = "5462", + URL = "http://www.inria.fr/rrrt/rr-5462.html", +} + +@InProceedings{simonet-solver-03, + author = "Vincent Simonet", + title = "Type inference with structural subtyping: a faithful + formalization of an efficient constraint solver", + booktitle = aplas, + publisher = springer, + series = lncs, + volume = "2895", + year = "2003", + URL = "http://gallium.inria.fr/~simonet/publis/simonet-aplas03.pdf", +} + +@PhdThesis{simonet-these, + author = "Vincent Simonet", + title = "Inférence de flots d'information pour {ML}: + formalisation et implantation", + school = "Université Paris 7", + year = "2004", + URL = "http://gallium.inria.fr/~simonet/publis/simonet-these.pdf", +} + +@Article{simplify, + author = "David Detlefs and Greg Nelson and James B. Saxe", + title = "{Simplify}: a theorem prover for program checking", + journal = jacm, + volume = "52", + number = "3", + year = "2005", + pages = "365--473", + URL = "http://doi.acm.org/10.1145/1066100.1066102", +} + +@PhdThesis{skalka-phd-02, + author = "Christian Skalka", + title = "Types for Programming Language-Based Security", + school = "The Johns Hopkins University", + year = "2002", + URL = "http://www.cs.uvm.edu/~skalka/skalka-pubs/skalka-phd-thesis.ps", +} + +@InProceedings{skalka-pottier-tip-02, + author = "Christian Skalka and François Pottier", + title = "Syntactic Type Soundness for {HM}{$(X)$}", + year = "2002", + booktitle = "Workshop on Types in Programming (TIP)", + series = entcs, + volume = "75", + URL = "http://gallium.inria.fr/~fpottier/publis/skalka-fpottier-tip-02.ps.gz", +} + +@InProceedings{skalka-smith-00, + author = "Christian Skalka and Scott Smith", + title = "Static Enforcement of Security with Types", + booktitle = icfp, + year = "2000", + pages = "34--45", + URL = "http://www.cs.uvm.edu/~skalka/skalka-pubs/skalka-smith-icfp00.ps", +} + +@InProceedings{smallfoot-05, + author = "Josh Berdine and Cristiano Calcagno and Peter W. + O'Hearn", + title = "Smallfoot: Modular Automatic Assertion Checking with + Separation Logic", + booktitle = fmco, + pages = "115--137", + year = "2005", + volume = "4111", + series = lncs, + publisher = springer, + URL = "http://research.microsoft.com/pubs/67598/smallfoot.pdf", +} + +@InProceedings{smans-implicit-09, + title = "Implicit Dynamic Frames: Combining Dynamic Frames and + Separation Logic", + year = "2009", + author = "Jan Smans and Bart Jacobs and Frank Piessens", + booktitle = ecoop, + pages = "148--172", + volume = "5653", + series = lncs, + publisher = springer, + URL = "http://people.cs.kuleuven.be/~jan.smans/ecoop09.pdf", +} + +@InProceedings{smetsers-94, + author = "Sjaak Smetsers and Erik Barendsen and Marko C. J. D. + van Eekelen and Marinus J. Plasmeijer", + title = "Guaranteeing Safe Destructive Updates Through a Type + System with Uniqueness Information for Graphs", + booktitle = "Dagstuhl Seminar on Graph Transformations in Computer + Science", + year = "1994", + pages = "358--379", + publisher = springer, + series = lncs, + volume = "776", + URL = "http://www.mbsd.cs.ru.nl/publications/papers/1994/smes94-guaranteeing.pdf", +} + +@InProceedings{smith-01, + author = "Geoffrey S. Smith", + title = "A New Type System for Secure Information Flow", + booktitle = csfw, + pages = "115--125", + year = "2001", + URL = "http://www.cs.fiu.edu/~smithg/papers/csfw01.pdf", +} + +@InProceedings{smith-93, + author = "Geoffrey S. Smith", + title = "Polymorphic type Inference with Overloading and + Subtyping", + booktitle = tapsoft, + series = lncs, + volume = "668", + publisher = springer, + year = "1993", + pages = "671--685", + URL = "http://dx.doi.org/10.1007/3-540-56610-4_97", +} + +@Article{smith-94, + author = "Geoffrey S. Smith", + title = "Principal Type Schemes for Functional Programs with + Overloading and Subtyping", + journal = scp, + year = "1994", + volume = "23", + number = "2--3", + pages = "197--226", + URL = "http://www.cs.fiu.edu/~smithg/papers/scp94.pdf", +} + +@PhdThesis{smith-phd-89, + author = "Scott Fraser Smith", + title = "Partial Objects in Type Theory", + school = "Cornell University", + year = "1989", + URL = "http://www.cs.jhu.edu/~scott/pll/older-papers/thesis.pdf", +} + +@InProceedings{smith-volpano-98, + title = "Secure Information Flow in a Multi-Threaded Imperative + Language", + booktitle = popl, + author = "Geoffrey Smith and Dennis Volpano", + year = "1998", + pages = "355--364", + URL = "http://www.cs.nps.navy.mil/people/faculty/volpano/papers/popl98.ps.Z", +} + +@InProceedings{smith-wang-00, + author = "Scott Smith and Tiejun Wang", + title = "Polyvariant Flow Analysis with Constrained Types", + booktitle = esop, + publisher = springer, + series = lncs, + volume = "1782", + pages = "382--396", + year = "2000", + URL = "http://link.springer.de/link/service/series/0558/papers/1782/17820382.pdf", +} + +@Book{sml-97, + author = "Robin Milner and Mads Tofte and Robert Harper and + David MacQueen", + title = "The Definition of {Standard ML} -- Revised", + publisher = mitp, + year = "1997", +} + +@Article{smolka-treinen-94, + title = "Records for Logic Programming", + year = "1994", + author = "Gert Smolka and Ralf Treinen", + volume = "18", + journal = jlp, + number = "3", + pages = "229--258", + URL = "http://www.ps.uni-sb.de/Papers/abstracts/RecordsLogProg.ps", +} + +@Article{smyth-plotkin-82, + author = "Michael B. Smyth and Gordon D. Plotkin", + title = "The Category-Theoretic Solution of Recursive Domain + Equations", + journal = siamjc, + volume = "11", + number = "4", + year = "1982", + pages = "761--783", + URL = "http://homepages.inf.ed.ac.uk/gdp/publications/Category_Theoretic_Solution.pdf", +} + +@InProceedings{snyder-86, + author = "Alan Snyder", + title = "Encapsulation and inheritance in object-oriented + programming languages", + booktitle = oopsla, + year = "1986", + pages = "38--45", + URL = "http://doi.acm.org/10.1145/28697.28702", +} + +@InProceedings{sobel-friedman-98, + author = "Jonathan Sobel and Daniel P. Friedman", + title = "Recycling continuations", + booktitle = icfp, + year = "1998", + pages = "251--260", + URL = "http://www.cs.indiana.edu/hyplan/dfried/rc.ps", +} + +@Article{soisalon-soininen-82, + author = "Eljas Soisalon-Soininen", + title = "Inessential Error Entries and Their Use in {LR} Parser + Optimization", + journal = toplas, + volume = "4", + number = "2", + year = "1982", + pages = "179--195", + URL = "http://doi.acm.org/10.1145/357162.357165", +} + +@InProceedings{solomon-78, + author = "Marvin H. Solomon", + title = "Type Definitions with Parameters", + booktitle = popl, + year = "1978", + pages = "31--38", + URL = "http://doi.acm.org/10.1145/512760.512765", +} + +@Article{soloviev-83, + author = "Sergei V. Soloviev", + title = "The category of finite sets and Cartesian Closed + Categories", + journal = "Journal of Soviet Mathematics", + year = "1983", + volume = "22", + number = "3", + pages = "1387--1400", +} + +@InProceedings{sozeau-06, + author = "Matthieu Sozeau", + title = "Subset Coercions in {Coq}", + booktitle = types, + year = "2006", + volume = "4502", + pages = "237--252", + URL = "http://www.lri.fr/~sozeau/research/russell/article.pdf", +} + +@InProceedings{sozeau-finger-07, + author = "Matthieu Sozeau", + booktitle = icfp, + pages = "13--24", + URL = "http://mattam.org/research/publications/Program-ing_Finger_Trees_in_Coq.pdf", + title = "Program-ing Finger Trees in {Coq}", + year = "2007", +} + +@Article{spec-sharp-04, + author = "Mike Barnett and Rob DeLine and Manuel Fähndrich and + K. Rustan M. Leino and Wolfram Schulte", + title = "Verification of object-oriented programs with + invariants", + journal = jot, + year = "2004", + volume = "3", + number = "6", + URL = "http://research.microsoft.com/research/pubs/view.aspx?type=article&id=1161", +} + +@Article{spivey-90, + year = "1990", + volume = "14", + title = "A Functional Theory of Exceptions", + pages = "25--42", + journal = scp, + author = "Mike Spivey", +} + +@InProceedings{stata-abadi-98, + author = "R. Stata and M. Abadi", + title = "A Type System for {Java} Bytecode Subroutines", + year = "1998", + pages = "149--160", + booktitle = popl, + URL = "http://gatekeeper.dec.com/pub/DEC/SRC/research-reports/abstracts/src-rr-158.html", +} + +@Article{steckler-wand-97, + author = "Paul A. Steckler and Mitchell Wand", + title = "Lightweight closure conversion", + journal = toplas, + volume = "19", + number = "1", + year = "1997", + pages = "48--86", + URL = "ftp://ftp.ccs.neu.edu/pub/people/wand/papers/steckler-wand-97.ps", +} + +@InProceedings{steensgaard-96, + author = "Bjarne Steensgaard", + booktitle = popl, + title = "Points-to Analysis in Almost Linear Time", + year = "1996", + pages = "32--41", + URL = "ftp://ftp.research.microsoft.com/users/rusa/popl96.ps", +} + +@InProceedings{steffen-fix-machine-95, + author = "Bernhard Steffen and Andreas Cla{\ss}en and Marion + Klein and Jens Knoop and Tiziana Margaria", + title = "The Fixpoint-Analysis Machine", + booktitle = concur, + year = "1995", + pages = "72--87", + publisher = springer, + series = lncs, + volume = "962", + URL = "http://dx.doi.org/10.1007/3-540-60218-6_6", +} + +@InProceedings{stehr-00, + author = "Mark-Oliver Stehr", + title = "{CINNI} -- {A} Generic Calculus of Explicit + Substitutions and its Application to $\lambda$-, + $\sigma$- and $\pi$-calculi", + booktitle = wrla, + year = "2000", + volume = "36", + series = entcs, + publisher = elsevier, + URL = "http://formal.cs.uiuc.edu/stehr/extcinni.ps", +} + +@InProceedings{stewart-veristar-12, + author = "Gordon Stewart and Lennart Beringer and Andrew W. + Appel", + title = "Verified heap theorem prover by paramodulation", + booktitle = icfp, + year = "2012", + pages = "3--14", + URL = "http://www.cs.princeton.edu/~appel/papers/veristar.pdf", +} + +@InProceedings{stoughton-81, + author = "Allen Stoughton", + title = "Access Flow: {A} Protection Model Which Integrates + Access Control and Information Flow", + pages = "9--18", + booktitle = sp, + year = "1981", +} + +@Article{strachey-fundamental, + author = "Christopher Strachey", + title = "Fundamental Concepts in Programming Languages", + journal = hosc, + year = "2000", + volume = "13", + number = "1--2", + pages = "11--49", + URL = "http://dx.doi.org/10.1023/A:1010000313106", +} + +@Article{strom-yemini-86, + author = "Robert E. Strom and Shaula Yemini", + title = "Typestate: {A} programming language concept for + enhancing software reliability", + journal = tose, + volume = "12", + number = "1", + year = "1986", + pages = "157--171", + URL = "http://www.cs.cmu.edu/~aldrich/papers/classic/tse12-typestate.pdf", +} + +@InProceedings{stuckey-sulzmann-02, + author = "Peter J. Stuckey and Martin Sulzmann", + title = "A Theory of Overloading", + booktitle = icfp, + pages = "167--178", + year = "2002", + URL = "http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.62.8605", +} + +@InProceedings{stuckey-sulzmann-wazny-03, + author = "Peter J. Stuckey and Martin Sulzmann and Jeremy + Wazny", + title = "Interactive type debugging in {Haskell}", + booktitle = hw, + pages = "72--83", + year = "2003", + URL = "http://www.cs.mu.oz.au/~pjs/papers/p316-stuckey.pdf", +} + +@InProceedings{su-aiken-01, + author = "Zhendong Su and Alexander Aiken", + title = "Entailment with Conditional Equality Constraints", + booktitle = esop, + year = "2001", + pages = "170--189", + series = lncs, + volume = "2028", + URL = "http://www.cs.ucdavis.edu/~su/publications/esop01.pdf", +} + +@InProceedings{su-al-02, + author = "Zhendong Su and Alexander Aiken and Joachim Niehren + and Tim Priesnitz and Ralf Treinen", + title = "The First-Order Theory of Subtyping Constraints", + booktitle = popl, + pages = "203--216", + year = "2002", + URL = "http://theory.stanford.edu/~aiken/publications/papers/popl02.pdf", +} + +@PhdThesis{sulzmann-00, + author = "Martin Sulzmann", + title = "A general framework for {Hindley/Milner} type systems + with constraints", + school = "Yale University, Department of Computer Science", + year = "2000", + URL = "http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.7.7745", +} + +@InProceedings{sulzmann-01, + author = "Martin Sulzmann", + title = "A General Type Inference Framework for + {Hindley/Milner} Style Systems", + booktitle = "International Symposium on Functional and Logic + Programming", + series = lncs, + volume = "2024", + pages = "246--263", + publisher = springer, + year = "2001", + URL = "http://link.springer.de/link/service/series/0558/papers/2024/20240248.pdf", +} + +@TechReport{sulzmann-mueller-zenger-99, + author = "Martin Sulzmann and Martin Müller and Christoph + Zenger", + title = "{Hindley/Milner} style type systems in constraint + form", + institution = "University of South Australia, School of Computer and + Information Science", + type = "Research Report", + year = "1999", + number = "ACRC--99--009", + URL = "http://www.ps.uni-sb.de/~mmueller/papers/hm-constraints.ps.gz", +} + +@InProceedings{sulzmann-odersky-wehr-97, + author = "Martin Sulzmann and Martin Odersky and Martin Wehr", + title = "Type Inference with Constrained Types", + booktitle = fool, + year = "1997", + URL = "ftp://ftp.ira.uka.de/pub/uni-karlsruhe/papers/techreports/1996/1996-28.ps.gz", +} + +@TechReport{sulzmann-records-97, + author = "Martin Sulzmann", + title = "Designing Record Systems", + institution = "Yale University", + year = "1997", + type = "Research Report", + number = "YALEU/DCS/RR-1128", + URL = "http://www.cs.mu.oz.au/~sulzmann/publications/tr-1128.ps.gz", +} + +@TechReport{sulzmann-wang-04, + author = "Martin Sulzmann and Meng Wang", + title = "A Systematic Translation of Guarded Recursive Data + Types to Existential Types", + institution = "National University of Singapore", + number = "TR22/04", + year = "2004", + ps = "http://www.cs.mu.oz.au/~sulzmann/publications/translate-grdts.ps.gz", +} + +@InProceedings{sumii-09, + author = "Eijiro Sumii", + title = "A Complete Characterization of Observational + Equivalence in Polymorphic lambda-Calculus with General + References", + booktitle = csl, + series = lncs, + publisher = springer, + volume = "5771", + pages = "455--469", + year = "2009", + URL = "http://www.kb.ecei.tohoku.ac.jp/~sumii/pub/poly-ref.pdf", +} + +@InProceedings{svendsen-birkedal-icap-14, + author = "Kasper Svendsen and Lars Birkedal", + title = "Impredicative Concurrent Abstract Predicates", + booktitle = esop, + year = "2014", + pages = "149--168", + volume = "8410", + publisher = springer, + series = lncs, + URL = "http://cs.au.dk/~birke/papers/icap-conf.pdf", +} + +@InProceedings{svendsen-birkedal-parkinson-hocap-13, + author = "Kasper Svendsen and Lars Birkedal and Matthew J. + Parkinson", + booktitle = esop, + pages = "169--188", + publisher = springer, + series = lncs, + title = "Modular Reasoning about Separation of Concurrent Data + Structures", + volume = "7792", + year = "2013", + URL = "http://cs.au.dk/~birke/papers/hocap-conf.pdf", +} + +@InProceedings{svendsen-birkedal-parkinson-joins-13, + author = "Kasper Svendsen and Lars Birkedal and Matthew J. + Parkinson", + title = "Joins: {A} Case Study in Modular Specification of a + Concurrent Reentrant Higher-Order Library", + booktitle = ecoop, + year = "2013", + pages = "327--351", + publisher = springer, + series = lncs, + volume = "7920", + URL = "http://cs.au.dk/~birke/papers/joins-conf.pdf", +} + +@Article{swamy-06, + author = "Nikhil Swamy and Michael Hicks and Greg Morrisett and + Dan Grossman and Trevor Jim", + title = "Safe Manual Memory Management in {Cyclone}", + journal = scp, + year = "2006", + volume = "62", + number = "2", + pages = "122--144", + URL = "http://www.cs.umd.edu/~mwh/papers/cyc-mm-scp.pdf", +} + +@InProceedings{swierstra-duponcheel-96, + author = "S. Doaitse Swierstra and Luc Duponcheel", + title = "Deterministic, Error-Correcting Combinator Parsers", + booktitle = "Advanced Functional Programming", + year = "1996", + publisher = "Springer", + series = "Lecture Notes in Computer Science", + volume = "1129", + pages = "184--207", + URL = "http://www.staff.science.uu.nl/~swier101/Papers/1996/DetErrCorrComPars.pdf", +} + +@InProceedings{syb, + author = "Ralf L{\"{a}}mmel and Simon {Peyton Jones}", + title = "Scrap your boilerplate: a practical design pattern for + generic programming", + booktitle = tldi, + pages = "26--37", + year = "2003", + URL = "https://www.microsoft.com/en-us/research/wp-content/uploads/2003/01/hmap.pdf", +} + +@InProceedings{syb-reloaded, + author = "Ralf Hinze and Andres L{\"{o}}h and Bruno C. d. S. + Oliveira", + title = "``Scrap Your Boilerplate'' Reloaded", + booktitle = flops, + pages = "13--29", + year = "2006", + series = lncs, + volume = "3945", + publisher = springer, + URL = "http://www.cs.ox.ac.uk/bruno.oliveira/SYB0.pdf", +} + +@InProceedings{syb-revolutions, + author = "Ralf Hinze and Andres L{\"{o}}h", + title = "``Scrap Your Boilerplate'' Revolutions", + booktitle = mpc, + pages = "180--208", + year = "2006", + series = lncs, + volume = "4014", + publisher = springer, + URL = "https://www.andres-loeh.de/SYB1.pdf", +} + +@InProceedings{syb2, + author = "Ralf L{\"{a}}mmel and Simon {Peyton Jones}", + title = "Scrap more boilerplate: reflection, zips, and + generalised casts", + booktitle = icfp, + pages = "244--255", + year = "2004", + URL = "https://doi.org/10.1145/1016848.1016883", +} + +@InProceedings{syb3, + author = "Ralf L{\"{a}}mmel and Simon {Peyton Jones}", + title = "Scrap your boilerplate with class: extensible generic + functions", + booktitle = icfp, + pages = "204--215", + year = "2005", + URL = "https://www.microsoft.com/en-us/research/wp-content/uploads/2016/07/gmap3.pdf", +} + +@PhdThesis{taha-99, + author = "Walid Taha", + title = "Multi-stage Programming: Its Theory and Applications", + school = "Oregon Graduate Institute", + year = "1999", + URL = "http://www.cs.rice.edu/~taha/publications/thesis/thesis.pdf", +} + +@InProceedings{taha-gentle-04, + author = "Walid Taha", + title = "A Gentle Introduction to Multi-stage Programming", + booktitle = dspg, + pages = "30--50", + year = "2004", + volume = "3016", + series = lncs, + publisher = springer, + URL = "http://www.cs.rice.edu/~taha/publications/journal/dspg04a.pdf", +} + +@InProceedings{taha-nielsen-03, + author = "Walid Taha and Michael Florentin Nielsen", + title = "Environment classifiers", + booktitle = popl, + year = "2003", + pages = "26--37", + URL = "http://www.cs.rice.edu/~taha/publications/conference/popl03.pdf", +} + +@Article{takahashi-95, + author = "Masako Takahashi", + title = "Parallel Reductions in $\lambda$-Calculus", + journal = ic, + year = "1995", + volume = "118", + number = "1", + pages = "120--127", + URL = "http://dx.doi.org/10.1006/inco.1995.1057", +} + +@Article{talcott-93, + author = "Carolyn Talcott", + title = "A Theory of Binding Structures and Applications to + Rewriting", + journal = tcs, + year = "1993", + volume = "112", + number = "1", + pages = "99--143", + URL = "http://dx.doi.org/10.1016/0304-3975(93)90240-T", +} + +@Article{talpin-jouvelot-94, + author = "Jean-Pierre Talpin and Pierre Jouvelot", + title = "The type and effect discipline", + journal = ic, + year = "1994", + volume = "11", + number = "2", + pages = "245--296", + URL = "http://www.irisa.fr/prive/talpin/papers/ic94.pdf", +} + +@InProceedings{tan-wusl-09, + author = "Gang Tan and Zhong Shao and Xinyu Feng and Hongxu + Cai", + title = "Weak Updates and Separation Logic", + booktitle = aplas, + pages = "178--193", + year = "2009", + volume = "5904", + series = lncs, + publisher = springer, + URL = "http://flint.cs.yale.edu/flint/publications/wusl.pdf", +} + +@Book{tapl, + author = "Benjamin C. Pierce", + title = "Types and Programming Languages", + publisher = mitp, + year = "2002", +} + +@Manual{tarditi-appel-00, + title = "{ML-Yacc} User's Manual", + author = "David R. Tarditi and Andrew W. Appel", + year = "2000", + URL = "http://www.smlnj.org/doc/ML-Yacc/", +} + +@Article{tarjan-72, + author = "Robert Tarjan", + title = "Depth-First Search and Linear Graph Algorithms", + journal = siamjc, + year = "1972", + volume = "1", + number = "2", + pages = "146--160", + URL = "http://epubs.siam.org/doi/abs/10.1137/0201010", +} + +@Article{tarjan-75, + author = "Robert Endre Tarjan", + title = "Efficiency of a Good But Not Linear Set Union + Algorithm", + journal = jacm, + year = "1975", + volume = "22", + number = "2", + pages = "215--225", + URL = "http://www.csd.uwo.ca/~eschost/Teaching/07-08/CS445a/p215-tarjan.pdf", +} + +@Article{tarjan-79, + author = "Robert Endre Tarjan", + title = "Applications of Path Compression on Balanced Trees", + journal = jacm, + year = "1979", + volume = "26", + number = "4", + pages = "690--715", + URL = "http://doi.acm.org/10.1145/322154.322161", +} + +@Unpublished{tarjan-99-notes, + title = "Class notes: Disjoint Set Union", + author = "Robert E. Tarjan", + year = "1999", + URL = "http://www.cs.princeton.edu/courses/archive/spr00/cs423/handout3.pdf", +} + +@Article{tarjan-amortized-85, + author = "Robert Endre Tarjan", + title = "Amortized Computational Complexity", + year = "1985", + journal = "SIAM Journal on Algebraic and Discrete Methods", + volume = "6", + number = "2", + pages = "306--318", + URL = "http://dx.doi.org/10.1137/0606031", +} + +@Article{tarjan-leeuwen-84, + author = "Robert E. Tarjan and Jan {van Leeuwen}", + title = "Worst-Case Analysis of Set Union Algorithms", + journal = jacm, + volume = "31", + number = "2", + pages = "245--281", + year = "1984", + URL = "http://dx.doi.org/10.1145/62.2160", +} + +@Article{tarjan-yannakakis-84, + author = "Robert E. Tarjan and Mihalis Yannakakis", + title = "Simple Linear-Time Algorithms to Test Chordality of + Graphs, Test Acyclicity of Hypergraphs, and Selectively + Reduce Acyclic Hypergraphs", + journal = siamjc, + year = "1984", + volume = "13", + number = "3", + pages = "566--579", + URL = "http://dx.doi.org/10.1137/0213035", +} + +@Article{tarjan-yao-79, + author = "Robert Endre Tarjan and Andrew Chi-Chih Yao", + title = "Storing a sparse table", + journal = cacm, + volume = "22", + number = "11", + year = "1979", + pages = "606--611", + URL = "http://doi.acm.org/10.1145/359168.359175", +} + +@InProceedings{template-haskell-02, + author = "Tim Sheard and Simon {Peyton Jones}", + title = "Template metaprogramming for {Haskell}", + booktitle = hw, + year = "2002", + pages = "1--16", + URL = "https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/meta-haskell.pdf", +} + +@Article{tennent-ghica-00, + author = "Robert D. Tennent and Dan Ghica", + title = "Abstract models of storage", + journal = hosc, + year = "2000", + volume = "13", + pages = "119--129", + URL = "http://dx.doi.org/10.1023/A:1010022312623", +} + +@InProceedings{thatte-94, + author = "Satish R. Thatt{\'e}", + title = "Automated synthesis of interface adapters for reusable + classes", + booktitle = popl, + year = "1994", + pages = "174--187", + URL = "http://doi.acm.org/10.1145/174675.177850", +} + +@InProceedings{thielecke-03, + author = "Hayo Thielecke", + title = "From control effects to typed continuation passing", + booktitle = popl, + year = "2003", + pages = "139--149", + URL = "http://www.cs.bham.ac.uk/~hxt/research/effects.pdf", +} + +@InProceedings{thielecke-06, + author = "Hayo Thielecke", + title = "Frame rules from answer types for code pointers", + booktitle = popl, + year = "2006", + pages = "309--319", + URL = "http://www.cs.bham.ac.uk/~hxt/research/popl06thielecke.pdf", +} + +@Article{thielecke-barrel-02, + author = "Hayo Thielecke", + title = "Comparing Control Constructs by Double-barrelled + {CPS}", + journal = hosc, + year = "2002", + volume = "15", + number = "2--3", + pages = "141--160", + URL = "http://www.cs.bham.ac.uk/~hxt/research/HOSC-double-barrel.pdf", +} + +@InProceedings{thiemann-01, + author = "Peter Thiemann", + title = "Enforcing Security Properties Using Type + Specialization", + booktitle = esop, + publisher = springer, + series = lncs, + year = "2001", + URL = "http://www.informatik.uni-freiburg.de/~thiemann/papers/espps-het.ps.gz", +} + +@InProceedings{thiemann-99, + author = "Peter Thiemann", + title = "{ML}-Style Typing, Lambda Lifting, and Partial + Evaluation", + booktitle = "Latin American Conference on Functional Programming", + year = "1999", + URL = "http://www.informatik.uni-freiburg.de/~thiemann/papers/clapf99.ps.gz", +} + +@InProceedings{tian-06, + author = "Ye Henry Tian", + title = "Mechanically Verifying Correctness of {CPS} + Compilation", + booktitle = "Computing: The Australasian Theory Symposium (CATS)", + pages = "41--51", + year = "2006", + URL = "http://crpit.com/confpapers/CRPITV51Tian.pdf", + series = "{CRPIT}", + volume = "51", + publisher = "Australian Computer Society", +} + +@InProceedings{tiuryn-92, + author = "Jerzy Tiuryn", + title = "Subtype inequalities", + pages = "308--317", + booktitle = lics, + year = "1992", +} + +@Article{tiuryn-urzyczyn-02, + author = "Jerzy Tiuryn and Pawel Urzyczyn", + title = "The subtyping problem for second-order types is + undecidable", + journal = ic, + volume = "179", + number = "1", + year = "2002", + pages = "1--18", + URL = "http://dx.doi.org/10.1006/inco.2001.2950", +} + +@InProceedings{tiuryn-wand-93, + author = "Jerzy Tiuryn and Mitchell Wand", + title = "Type Reconstruction with Recursive Types and Atomic + Subtyping", + pages = "686--701", + year = "1993", + booktitle = tapsoft, + series = lncs, + volume = "668", + publisher = springer, + URL = "ftp://ftp.ccs.neu.edu/pub/people/wand/papers/caap-93.dvi", +} + +@PhdThesis{tofte-88, + author = "Mads Tofte", + title = "Operational Semantics and Polymorphic Type Inference", + school = "University of Edinburgh", + year = "1988", + URL = "http://www.itu.dk/people/tofte/publ/phdthesis/thesis-part1and2.ps", +} + +@Article{tofte-retro-04, + author = "Mads Tofte and Lars Birkedal and Martin Elsman and + Niels Hallenberg", + title = "A Retrospective on Region-Based Memory Management", + journal = hosc, + year = "2004", + volume = "17", + number = "3", + pages = "245--265", + URL = "http://www.itu.dk/people/birkedal/papers/regmmp.ps.gz", +} + +@InProceedings{tofte-talpin-94, + author = "Mads Tofte and Jean-Pierre Talpin", + title = "Implementation of the Typed Call-by-Value + $\lambda$-Calculus using a Stack of Regions", + booktitle = popl, + year = "1994", + pages = "188--201", + URL = "http://www.irisa.fr/prive/talpin/papers/popl94.pdf", +} + +@Article{tofte-talpin-97, + author = "Mads Tofte and Jean-Pierre Talpin", + title = "Region-based memory management", + journal = ic, + volume = "132", + number = "2", + year = "1997", + pages = "109--176", + URL = "http://www.irisa.fr/prive/talpin/papers/ic97.pdf", +} + +@InProceedings{tolmach-97, + author = "Andrew Tolmach", + title = "Combining Closure Conversion with Closure Analysis + using Algebraic Types", + booktitle = tic, + year = "1997", + URL = "http://www.cs.pdx.edu/~apt/tic97.ps", +} + +@Article{tolmach-oliva-98, + author = "Andrew Tolmach and Dino P. Oliva", + title = "From {ML} to {Ada}: Strongly-typed Language + Interoperability via Source Translation", + journal = jfp, + year = "1998", + volume = "8", + number = "4", + pages = "367--412", + URL = "http://dx.doi.org/10.1017/S0956796898003086", +} + +@Article{topor-82, + author = "Rodney W. Topor", + title = "A Note on Error Recovery in Recursive Descent + Parsers", + journal = notices, + volume = "17", + number = "2", + year = "1982", + pages = "37--40", + URL = "http://doi.acm.org/10.1145/947902.947905", +} + +@InProceedings{tov-pucella-10, + author = "Jesse A. Tov and Riccardo Pucella", + title = "Stateful Contracts for Affine Types", + booktitle = esop, + year = "2010", + pages = "550--569", + publisher = springer, + series = lncs, + volume = "6012", + URL = "http://www.eecs.harvard.edu/~tov/pubs/affine-contracts/affinecontracts10-bw.pdf", +} + +@InProceedings{tov-pucella-11, + author = "Jesse A. Tov and Riccardo Pucella", + title = "Practical Affine Types", + booktitle = popl, + year = "2011", + pages = "447--458", + URL = "http://www.eecs.harvard.edu/~tov/pubs/alms/", +} + +@InProceedings{trifonov-smith-96, + author = "Valery Trifonov and Scott Smith", + title = "Subtyping Constrained Types", + booktitle = sas, + series = lncs, + volume = "1145", + pages = "349--365", + year = "1996", + publisher = springer, + URL = "http://flint.cs.yale.edu/trifonov/papers/subcon.pdf", +} + +@InProceedings{tschantz-ernst-05, + author = "Matthew S. Tschantz and Michael D. Ernst", + title = "Javari: adding reference immutability to {Java}", + booktitle = oopsla, + year = "2005", + pages = "211--230", + URL = "https://homes.cs.washington.edu/~mernst/pubs/ref-immutability-oopsla2005.pdf", +} + +@InProceedings{tse-zdancewic-04, + author = "Stephen Tse and Steve Zdancewic", + title = "Run-time Principals in Information-flow Type Systems", + booktitle = sp, + year = "2004", + URL = "http://www.cis.upenn.edu/~stevez/papers/TZ04a.pdf", +} + +@InProceedings{tsuiki-94, + author = "Hideki Tsuiki", + title = "On Typed Calculi with a Merge Operator", + booktitle = fsttcs, + pages = "101--112", + year = "1994", + volume = "880", + series = lncs, + publisher = springer, + URL = "http://www.i.h.kyoto-u.ac.jp/~tsuiki/papers/fsttcs.ps.gz", +} + +@Unpublished{tuerk-10, + author = "Thomas Tuerk", + title = "Local reasoning about while-loops", + year = "2010", + note = "Unpublished", + URL = "http://www.cl.cam.ac.uk/~tt291/talks/vstte10.pdf", +} + +@PhdThesis{turner-95, + author = "David N. Turner", + title = "The Polymorphic Pi-Calculus: Theory and + Implementation", + school = "University of Edinburgh", + year = "1995", + URL = "http://www.lfcs.inf.ed.ac.uk/reports/96/ECS-LFCS-96-345/", +} + +@InProceedings{turner-wadler-mossin-95, + author = "David N. Turner and Philip Wadler and Christian + Mossin", + year = "1995", + title = "Once upon a type", + booktitle = fpca, + publisher = acmp, + pages = "1--11", + URL = "ftp://ftp.dcs.gla.ac.uk/pub/glasgow-fp/authors/Philip_Wadler/once.dvi", +} + +@InProceedings{turon-caresl-13, + author = "Aaron Turon and Derek Dreyer and Lars Birkedal", + title = "Unifying refinement and {Hoare}-style reasoning in a + logic for higher-order concurrency", + booktitle = icfp, + year = "2013", + pages = "377--390", + URL = "http://www.mpi-sws.org/~turon/caresl/caresl.pdf", +} + +@Misc{unicon, + title = "Unicon", + note = "\url{http://unicon.sourceforge.net/}", + URL = "http://unicon.sourceforge.net/", +} + +@Article{urban-04, + author = "Christian Urban and Andrew Pitts and Murdoch Gabbay", + title = "Nominal Unification", + journal = tcs, + year = "2004", + URL = "http://gabbay.org.uk/papers/nomu-jv.pdf", + volume = "323", + pages = "473--497", +} + +@Article{urban-08, + author = "Christian Urban", + title = "Nominal Techniques in {Isabelle/HOL}", + journal = jar, + volume = "40", + number = "4", + pages = "327--356", + year = "2008", + URL = "https://nms.kcl.ac.uk/christian.urban/Publications/nom-tech.pdf", +} + +@Unpublished{urban-nipkow-08, + author = "Christian Urban and Tobias Nipkow", + title = "Nominal Verification of Algorithm {W}", + year = "2008", + note = "Unpublished", + URL = "http://www4.in.tum.de/~urbanc/Publications/w-07.pdf", +} + +@InProceedings{urban-tasson-05, + author = "Christian Urban and Christine Tasson", + title = "Nominal Techniques in {Isabelle/HOL}", + booktitle = cade, + year = "2005", + series = lncs, + publisher = springer, + volume = "3632", + pages = "38--53", + URL = "http://www4.in.tum.de/~urbanc/Publications/nom-cade-05.ps", +} + +@Unpublished{vacid, + author = "K. Rustan M. Leino and Michal Moskal", + title = "{VACID}-0: Verification of Ample Correctness of + Invariants of Data-structures, Edition 0", + note = "Manuscript KRML 209", + year = "2010", + URL = "http://research.microsoft.com/en-us/um/people/moskal/pdf/vacid0.pdf", +} + +@Article{vafeiadis-11, + author = "Viktor Vafeiadis", + title = "Concurrent Separation Logic and Operational + Semantics", + journal = entcs, + volume = "276", + year = "2011", + pages = "335--351", + URL = "http://www.mpi-sws.org/~viktor/papers/mfps2011-cslsound.pdf", +} + +@InProceedings{vaziri-jackson-03, + author = "Mandana Vaziri and Daniel Jackson", + title = "Checking Heap-Manipulating Procedures with a + Constraint Solver", + booktitle = tacas, + year = "2003", + publisher = springer, + series = lncs, + volume = "2619", + URL = "http://sdg.lcs.mit.edu/pubs/2003/checkingHMPs.pdf", +} + +@InProceedings{vdw-mckinna-08, + author = "Eelis {van der Weegen} and James McKinna", + title = "A Machine-Checked Proof of the Average-Case Complexity + of {Quicksort} in {Coq}", + booktitle = types, + year = "2008", + pages = "256--271", + publisher = springer, + series = lncs, + volume = "5497", + URL = "http://www.xs4all.nl/~weegen/eelis/research/quicksort/", +} + +@InProceedings{vergauwen-lewi-94, + author = "Bart Vergauwen and Johan Lewi", + title = "Efficient Local Correctness Checking for Single and + Alternating {Boolean} Equation Systems", + booktitle = icalp, + year = "1994", + pages = "304--315", + publisher = springer, + series = lncs, + volume = "820", + URL = "http://dx.doi.org/10.1007/3-540-58201-0_77", +} + +@InProceedings{vergauwen-nested-94, + author = "Bart Vergauwen and Johan Lewi and I. Avau and A. + Poté", + title = "Efficient computation of nested fix-points, with + applications to model checking", + booktitle = ictl, + pages = "165--179", + year = "1994", + volume = "827", + series = lncs, + publisher = springer, + URL = "http://dx.doi.org/10.1007/BFb0013987", +} + +@InProceedings{vergauwen-wauman-lewi-94, + author = "Bart Vergauwen and J. Wauman and Johan Lewi", + title = "Efficient fixpoint computation", + booktitle = sas, + pages = "314--328", + year = "1994", + volume = "864", + series = lncs, + publisher = springer, + URL = "http://dx.doi.org/10.1007/3-540-58485-4_49", +} + +@TechReport{verifast, + author = "Bart Jacobs and Frank Piessens", + title = "The {VeriFast} Program Verifier", + institution = "Department of Computer Science, Katholieke + Universiteit Leuven", + year = "2008", + number = "CW-520", + URL = "http://people.cs.kuleuven.be/~bart.jacobs/verifast/verifast.pdf", +} + +@InProceedings{villard-lozes-calcagno-09, + author = "Jules Villard and Étienne Lozes and Cristiano + Calcagno", + booktitle = aplas, + pages = "194--209", + publisher = springer, + series = lncs, + title = "Proving Copyless Message Passing", + URL = "http://www.lsv.ens-cachan.fr/Publis/PAPERS/PDF/VLC-aplas09.pdf", + volume = "5904", + year = "2009", +} + +@InProceedings{villard-lozes-calcagno-10, + author = "Jules Villard and Étienne Lozes and Cristiano + Calcagno", + booktitle = tacas, + pages = "275--279", + publisher = springer, + series = lncs, + title = "Tracking Heaps that Hop with {Heap-Hop}", + URL = "http://www.lsv.ens-cachan.fr/Publis/PAPERS/PDF/VLC-tacas10.pdf", + volume = "6015", + year = "2010", +} + +@Article{vitek-bokowski-01, + author = "Jan Vitek and Boris Bokowski", + title = "Confined types in {Java}", + journal = spe, + volume = "31", + number = "6", + pages = "507--532", + year = "2001", + URL = "https://www.cerias.purdue.edu/assets/pdf/bibtex_archive/2001-63.pdf", +} + +@Article{volpano-97, + author = "Dennis Volpano", + title = "Provably-Secure Programming Languages for Remote + Evaluation", + journal = notices, + volume = "32", + number = "1", + pages = "117--119", + year = "1997", +} + +@Article{volpano-smith-97, + author = "Dennis Volpano and Geoffrey Smith", + title = "A Type-Based Approach to Program Security", + journal = lncs, + volume = "1214", + pages = "607--621", + year = "1997", + URL = "http://www.cs.nps.navy.mil/people/faculty/volpano/papers/tapsoft97.ps.Z", +} + +@InProceedings{volpano-smith-csfw-97, + author = "Dennis Volpano and Geoffrey Smith", + year = "1997", + title = "Eliminating Covert Flows with Minimum Typings", + booktitle = csfw, + pages = "156--168", + URL = "http://www.cs.nps.navy.mil/people/faculty/volpano/papers/csfw97.ps.Z", +} + +@Article{volpano-smith-irvine-96, + author = "Dennis Volpano and Geoffrey Smith and Cynthia Irvine", + title = "A Sound Type System for Secure Flow Analysis", + journal = "Journal of Computer Security", + volume = "4", + number = "3", + pages = "167--187", + year = "1996", + URL = "http://www.cs.nps.navy.mil/people/faculty/volpano/papers/jcs96.ps.Z", +} + +@InProceedings{vorobyov-96, + author = "Sergei G. Vorobyov", + title = "An Improved Lower Bound for the Elementary Theories of + Trees", + booktitle = cade, + pages = "275--287", + year = "1996", + volume = "1104", + series = lncs, + publisher = springer, + URL = "http://www.mpi-sb.mpg.de/~sv/publications/complexity/2ILB.ps.Z", +} + +@InProceedings{vouillon-mellies-04, + author = "Jérôme Vouillon and Paul-André Melliès", + title = "Semantic types: a fresh look at the ideal model for + types", + booktitle = popl, + year = "2004", + pages = "52--63", + URL = "http://www.pps.jussieu.fr/~vouillon/publi/cbv.ps.gz", +} + +@InProceedings{vries-06, + author = "Edsko de Vries and Rinus Plasmeijer and David + Abrahamson", + title = "Uniqueness Typing Redefined", + booktitle = ifl, + pages = "181--198", + year = "2006", + volume = "4449", + series = lncs, + publisher = springer, + URL = "https://www.cs.tcd.ie/~devriese/pub/ifl06-paper.pdf", +} + +@InProceedings{vries-07, + author = "Edsko de Vries and Rinus Plasmeijer and David + Abrahamson", + title = "Equality Based Uniqueness Typing", + booktitle = tfp, + year = "2007", + URL = "https://www.cs.tcd.ie/~devriese/pub/tfp07-paper.pdf", +} + +@Unpublished{vytiniotis-boxy-05, + author = "Dimitrios Vytiniotis and Stephanie Weirich and Simon + {Peyton Jones}", + title = "Boxy types: type inference for higher-rank types and + impredicativity", + note = "Manuscript", + year = "2005", + URL = "http://research.microsoft.com/Users/simonpj/papers/boxy/", +} + +@Article{vytiniotis-outsidein-11, + author = "Dimitrios Vytiniotis and Simon {Peyton Jones} and Tom + Schrijvers and Martin Sulzmann", + title = "{OutsideIn(X)}: Modular type inference with local + assumptions", + journal = jfp, + volume = "21", + number = "4--5", + year = "2011", + pages = "333--412", + URL = "http://research.microsoft.com/en-us/um/people/simonpj/papers/constraints/jfp-outsidein.pdf", +} + +@InProceedings{vytiniotis-pie-07, + author = "Dimitrios Vytiniotis and Stephanie Weirich", + title = "Dependent Types: Easy as {PIE}", + booktitle = tfp, + year = "2007", + URL = "http://www.seas.upenn.edu/~sweirich/papers/tfp07.pdf", +} + +@InProceedings{wadler-85, + author = "Philip L. Wadler", + title = "How to replace failure by a list of successes", + booktitle = fpca, + publisher = springer, + series = lncs, + volume = "201", + year = "1985", + pages = "113--128", + URL = "http://dx.doi.org/10.1007/3-540-15975-4_33", +} + +@InProceedings{wadler-blott-89, + author = "Philip Wadler and Stephen Blott", + title = "How to make ad-hoc polymorphism less ad-hoc", + pages = "60--76", + booktitle = popl, + year = "1989", + URL = "http://homepages.inf.ed.ac.uk/wadler/papers/class/class.ps.gz", +} + +@Article{wadler-comprehending-92, + author = "Philip Wadler", + title = "Comprehending monads", + journal = mscs, + year = "1992", + volume = "2", + pages = "461--493", + URL = "http://homepages.inf.ed.ac.uk/wadler/papers/monads/monads.ps.gz", +} + +@InProceedings{wadler-essence-92, + author = "Philip Wadler", + title = "The essence of functional programming", + booktitle = popl, + year = "1992", + pages = "1--14", + note = "Invited talk", + URL = "http://homepages.inf.ed.ac.uk/wadler/papers/essence/essence.ps", +} + +@InProceedings{wadler-free-89, + author = "Philip Wadler", + title = "Theorems for free!", + booktitle = fpca, + year = "1989", + pages = "347--359", + URL = "http://homepages.inf.ed.ac.uk/wadler/papers/free/free.ps.gz", +} + +@Article{wadler-isomorphism-07, + author = "Philip Wadler", + title = "The {Girard}-{Reynolds} isomorphism (second edition)", + journal = tcs, + year = "2007", + volume = "375", + number = "1--3", + pages = "201--226", + URL = "http://homepages.inf.ed.ac.uk/wadler/papers/gr2/gr2.pdf", +} + +@InCollection{wadler-linear-90, + author = "Philip Wadler", + title = "Linear types can change the world!", + booktitle = "Programming Concepts and Methods", + publisher = "North Holland", + year = "1990", + editor = "M. Broy and C. Jones", + URL = "http://homepages.inf.ed.ac.uk/wadler/papers/linear/linear.ps", +} + +@Article{wadler-thiemann-03, + author = "Philip Wadler and Peter Thiemann", + title = "The marriage of effects and monads", + journal = tocl, + volume = "4", + number = "1", + pages = "1--32", + year = "2003", + URL = "http://homepages.inf.ed.ac.uk/wadler/papers/effectstocl/effectstocl.ps.gz", +} + +@InProceedings{walker-00, + author = "David Walker", + title = "A Type System for Expressive Security Policies", + booktitle = popl, + year = "2000", + pages = "254--267", + URL = "http://www.cs.cornell.edu/home/walker/papers/sa-popl00_ps.gz", +} + +@InCollection{walker-attapl-05, + author = "David Walker", + title = "Substructural Type Systems", + booktitle = "Advanced Topics in Types and Programming Languages", + pages = "3--43", + publisher = mitp, + year = "2005", + editor = "Benjamin C. Pierce", + chapter = "1", +} + +@Article{walker-capabilities-00, + author = "David Walker and Karl Crary and Greg Morrisett", + title = "Typed memory management via static capabilities", + journal = toplas, + volume = "22", + number = "4", + year = "2000", + pages = "701--771", + URL = "http://www.cs.princeton.edu/~dpw/papers/capabilities-toplas.pdf", +} + +@PhdThesis{wallach-99, + author = "Dan S. Wallach", + title = "A New Approach to Mobile Code Security", + school = "Princeton University", + year = "1999", + URL = "http://www.cs.princeton.edu/sip/pub/dwallach-dissertation.html", +} + +@Article{wallach-appel-felten-00, + author = "Dan S. Wallach and Andrew W. Appel and Edward W. + Felten", + title = "Safkasi: {A} Security Mechanism for Language-based + Systems", + journal = tosem, + year = "2000", + volume = "9", + number = "4", + pages = "341--378", + URL = "http://www.cs.rice.edu/~dwallach/pub/tosem2000.ps", +} + +@InProceedings{wallach-felten-stack-98, + author = "Dan S. Wallach and Edward Felten", + title = "Understanding {Java} Stack Inspection", + booktitle = sp, + year = "1998", + URL = "http://www.cs.princeton.edu/sip/pub/oakland98.php3", +} + +@Article{wand-80, + author = "Mitchell Wand", + title = "Continuation-Based Program Transformation Strategies", + journal = jacm, + volume = "27", + number = "1", + year = "1980", + pages = "164--180", + URL = "http://dx.doi.org/10.1145/322169.322183", +} + +@InProceedings{wand-85, + author = "Mitchell Wand", + title = "Embedding type structure in semantics", + booktitle = popl, + year = "1985", + pages = "1--6", + URL = "http://doi.acm.org/10.1145/318593.318602", +} + +@InProceedings{wand-86, + author = "Mitchell Wand", + title = "Finding the Source of Type Errors", + booktitle = popl, + pages = "38--43", + year = "1986", + URL = "http://doi.acm.org/10.1145/512644.512648", +} + +@Article{wand-87, + author = "Mitchell Wand", + title = "A Simple Algorithm and Proof for Type Inference", + journal = fundamenta, + volume = "10", + pages = "115--122", + year = "1987", + URL = "http://www.cs.ucla.edu/~palsberg/course/cs239/reading/wand87.pdf", +} + +@Article{wand-concat, + author = "Mitchell Wand", + title = "Type Inference for Record Concatenation and Multiple + Inheritance", + year = "1991", + volume = "93", + number = "1", + pages = "1--15", + journal = ic, + URL = "ftp://ftp.ccs.neu.edu/pub/people/wand/papers/ic-91.dvi", +} + +@InCollection{wand-objects, + author = "Mitchell Wand", + title = "Type Inference for Objects with Instance Variables and + Inheritance", + booktitle = taoop, + editor = "Carl A. Gunter and John C. Mitchell", + publisher = mitp, + pages = "97--120", + year = "1994", + URL = "ftp://ftp.ccs.neu.edu/pub/people/wand/papers/gunter-mitchell-94.dvi", +} + +@InProceedings{wand-steckler-94, + author = "Mitchell Wand and Paul A. Steckler", + title = "Selective and lightweight closure conversion", + booktitle = popl, + year = "1994", + pages = "435--445", + URL = "http://doi.acm.org/10.1145/174675.178044", +} + +@Article{ward-96, + author = "Martin Ward", + title = "Derivation of Data Intensive Algorithms by Formal + Transformation -- The {Schorr-Waite} Graph Marking + Algorithm", + journal = tose, + year = "1996", + volume = "22", + number = "9", + pages = "665--686", + URL = "http://www.cse.dmu.ac.uk/~mward/martin/papers/sw-alg-t.pdf", +} + +@InCollection{warren-82, + author = "D. H. D. Warren", + title = "Higher-order extensions to {PROLOG}: are they + needed?", + booktitle = "Machine Intelligence 10", + pages = "441--454", + publisher = ellis, + year = "1982", + editor = "J. E. Hayes and D. Michie and Y-H. Pao", +} + +@InProceedings{warth-douglass-millstein-08, + author = "Alessandro Warth and James R. Douglass and Todd D. + Millstein", + title = "Packrat parsers can support left recursion", + booktitle = pepm, + year = "2008", + pages = "103--110", + URL = "http://www.cs.ucla.edu/~todd/research/pepm08.pdf", +} + +@Article{wegbreit-75, + author = "Ben Wegbreit", + title = "Mechanical Program Analysis", + journal = cacm, + volume = "18", + number = "9", + year = "1975", + pages = "528--539", + URL = "http://doi.acm.org/10.1145/361002.361016", +} + +@Article{wegener-02, + author = "Ingo Wegener", + title = "A simplified correctness proof for a well-known + algorithm computing strongly connected components", + journal = "Information Processing Letters", + year = "2002", + volume = "83", + number = "1", + pages = "17--19", + URL = "http://ls2-www.cs.uni-dortmund.de/~wegener/papers/connected.pdf", +} + +@InProceedings{weirich-00, + author = "Stephanie Weirich", + title = "Type-Safe Cast: Functional Pearl", + booktitle = icfp, + year = "2000", + pages = "58--67", + URL = "http://www.cis.upenn.edu/~sweirich/papers/cast/cast.pdf", +} + +@Article{weirich-polytypic-06, + author = "Stephanie Weirich", + title = "Type-Safe Run-time Polytypic Programming", + journal = jfp, + year = "2006", + volume = "16", + number = "10", + pages = "681--710", + URL = "http://www.seas.upenn.edu/~sweirich/papers/erasure/erasure-jfp.pdf", +} + +@InProceedings{weirich-replib-06, + author = "Stephanie Weirich", + title = "{RepLib}: a library for derivable type classes", + booktitle = hw, + pages = "1--12", + year = "2006", + URL = "http://www.seas.upenn.edu/~sweirich/RepLib/haskell08-weirich.pdf", +} + +@Misc{weirich-tc-04, + author = "Stephanie Weirich", + title = "A typechecker that produces a typed term from an + untyped source", + howpublished = "Part of the Glasgow Haskell compiler's test suite", + year = "2004", + URL = "http://cvs.haskell.org/cgi-bin/cvsweb.cgi/fptools/testsuite/tests/ghc-regress/gadt/tc.hs?rev=1.1", +} + +@InProceedings{weirich-yorgey-sheard-11, + author = "Stephanie Weirich and Brent A. Yorgey and Tim Sheard", + title = "Binders unbound", + booktitle = icfp, + pages = "333--345", + year = "2011", + URL = "http://www.seas.upenn.edu/~sweirich/papers/icfp11.pdf", +} + +@InProceedings{wells-02, + author = "J. B. Wells", + title = "The Essence of Principal Typings", + booktitle = icalp, + pages = "913--925", + publisher = springer, + volume = "2380", + series = lncs, + year = "2002", + URL = "http://www.macs.hw.ac.uk/~jbw/papers/Wells:The-Essence-of-Principal-Typings:ICALP-2002.pdf", +} + +@TechReport{wells-95, + author = "J. B. Wells", + title = "The Undecidability of {Mitchell's} Subtyping + Relation", + institution = "Computer Science Department, Boston University", + year = "1995", + URL = "http://www.cs.bu.edu/ftp/pub/jbw/types/subtyping-undecidable.ps.gz", + type = "Technical Report", + number = "95-019", +} + +@Article{wells-99, + author = "J. B. Wells", + title = "Typability and type checking in System {F} are + equivalent and undecidable", + journal = apal, + year = "1999", + volume = "98", + number = "1--3", + pages = "111--156", + URL = "http://www.macs.hw.ac.uk/~jbw/papers/f-undecidable-APAL.ps.gz", +} + +@PhdThesis{werner-94, + author = "Benjamin Werner", + title = "Une Théorie des Constructions Inductives", + school = "Université Paris 7", + year = "1994", +} + +@InProceedings{westbrook-05, + author = "Edwin Westbrook and Aaron Stump and Ian Wehrman", + title = "A language-based approach to functionally correct + imperative programming", + booktitle = icfp, + year = "2005", + pages = "268--279", + URL = "http://cl.cse.wustl.edu/papers/rsp1-icfp05.pdf", +} + +@PhdThesis{westbrook-08, + author = "Edwin M. Westbrook", + title = "Higher-Order Encodings with Constructors", + school = "Washington University", + year = "2008", + URL = "http://www.cs.rice.edu/~emw4/thesis-westbrook.pdf", +} + +@TechReport{why, + author = "Jean-Christophe Filliâtre", + title = "{Why}: a multi-language multi-prover verification + tool", + institution = "LRI, Université Paris Sud", + type = "Research Report", + number = "1366", + year = "2003", + URL = "http://www.lri.fr/~filliatr/ftp/publis/why-tool.ps.gz", +} + +@InProceedings{why-07, + author = "Jean-Christophe Filliâtre and Claude Marché", + title = "The {Why}/{Kra\-ka\-toa}/{Ca\-du\-ceus} Platform for + Deductive Program Verification", + booktitle = cav, + year = "2007", + pages = "173--177", + volume = "4590", + series = lncs, + publisher = springer, + URL = "http://www.lri.fr/~filliatr/ftp/publis/cav07.pdf", +} + +@Article{williams-64, + author = "J. W. J. Williams", + title = "Algorithm 232: Heapsort", + journal = cacm, + year = "1964", + volume = "7", + number = "6", + pages = "347--348", + URL = "http://doi.acm.org/10.1145/512274.512284", +} + +@InProceedings{wing-rollins-zaremsky-92, + author = "Jeannette M. Wing and Eugene Rollins and Amy Moormann + Zaremski", + title = "Thoughts on a {Larch/ML} and a New Application for + {LP}", + booktitle = "First International Workshop on Larch", + year = "1992", + URL = "http://reports-archive.adm.cs.cmu.edu/anon/usr0/ftp/home/ftp/1992/CMU-CS-92-135.ps", + pages = "297--312", +} + +@Book{wirth-78, + author = "Niklaus Wirth", + title = "Algorithms + Data Structures = Programs", + year = "1978", + publisher = prentice, +} + +@InProceedings{wisnesky-malecha-morrisett-09, + author = "Ryan Wisnesky and Gregory Malecha and Greg Morrisett", + title = "Certified Web Services in {Ynot}", + booktitle = wwv, + year = "2009", + URL = "http://wisnesky.net/wwv09.pdf", +} + +@InProceedings{wolff-11, + author = "Roger Wolff and Ronald Garcia and \'{E}ric Tanter and + Jonathan Aldrich", + title = "Gradual typestate", + booktitle = ecoop, + year = "2011", + pages = "459--483", + publisher = springer, + series = lncs, + volume = "6813", + URL = "http://www.cs.cmu.edu/~aldrich/papers/aldrich-gradual-ecoop11.pdf", +} + +@InProceedings{woodward-79, + author = "J. P. L. Woodward", + title = "Applications for Multilevel Secure Operating Systems", + booktitle = "Proceedings NCC", + year = "1979", + pages = "319--328", + volume = "48", + publisher = "{AFIPS} Press", +} + +@Article{wright-cartwright-97, + author = "Andrew K. Wright and Robert Cartwright", + title = "A Practical Soft Type System for {Scheme}", + journal = toplas, + volume = "19", + number = "1", + pages = "87--152", + year = "1997", + URL = "http://doi.acm.org/10.1145/239912.239917", +} + +@Article{wright-felleisen-94, + title = "A Syntactic Approach to Type Soundness", + author = "Andrew K. Wright and Matthias Felleisen", + pages = "38--94", + journal = ic, + year = "1994", + volume = "115", + number = "1", + URL = "http://www.cs.rice.edu/CS/PLT/Publications/Scheme/ic94-wf.ps.gz", +} + +@TechReport{wright-restriction-93, + author = "Andrew K. Wright", + institution = "Rice University", + title = "Polymorphism for Imperative Languages without + Imperative Types", + year = "1993", + number = "93-200", +} + +@Article{wright-restriction-95, + author = "Andrew K. Wright", + title = "Simple Imperative Polymorphism", + journal = lsc, + volume = "8", + number = "4", + year = "1995", + pages = "343--356", + URL = "http://www.cs.rice.edu/CS/PLT/Publications/Scheme/lasc95-w.ps.gz", +} + +@InProceedings{wyk-99, + author = "Eric van Wyk and Oege de Moor and Simon {Peyton + Jones}", + title = "Aspect-oriented compilers", + booktitle = gcse, + pages = "121--133", + year = "1999", + volume = "1799", + series = lncs, + publisher = springer, + URL = "https://www.microsoft.com/en-us/research/wp-content/uploads/2016/07/aspects.pdf", +} + +@PhdThesis{xi-98, + author = "Hongwei Xi", + title = "Dependent Types in Practical Programming", + school = "Carnegie Mellon University", + year = "1998", + URL = "http://www.cs.bu.edu/~hwxi/academic/papers/thesis.ps", +} + +@InProceedings{xi-ats, + author = "Hongwei Xi", + title = "Applied Type System", + year = "2004", + booktitle = "{TYPES} 2003", + publisher = springer, + series = lncs, + volume = "3085", + pages = "394--408", + URL = "http://www.cs.bu.edu/~hwxi/academic/papers/types03.pdf", +} + +@InProceedings{xi-chen-chen-03, + author = "Hongwei Xi and Chiyan Chen and Gang Chen", + title = "Guarded Recursive Datatype Constructors", + booktitle = popl, + year = "2003", + pages = "224--235", + URL = "http://www.cs.bu.edu/fac/hwxi/academic/papers/popl03.ps", +} + +@InProceedings{xi-cps-01, + author = "Hongwei Xi and Carsten Schürmann", + title = "{CPS} Transform for {Dependent ML}", + booktitle = wollic, + year = "2001", + URL = "http://www.cs.bu.edu/~hwxi/academic/papers/DMLcps.pdf", +} + +@InProceedings{xi-dead-99, + author = "Hongwei Xi", + title = "Dead Code Elimination through Dependent Types", + booktitle = padl, + pages = "228--242", + year = "1999", + volume = "1551", + series = lncs, + publisher = springer, + URL = "http://www.cs.bu.edu/~hwxi/academic/papers/padl99.ps", +} + +@Misc{xi-dml, + author = "Hongwei Xi", + title = "Dependent {ML}", + year = "2001", + URL = "http://www.cs.bu.edu/~hwxi/DML/DML.html", +} + +@Article{xi-dml-07, + author = "Hongwei Xi", + title = "Dependent {ML}: an approach to practical programming + with dependent types", + journal = jfp, + year = "2007", + volume = "17", + number = "2", + pages = "215--286", + URL = "http://www.cs.bu.edu/~hwxi/academic/papers/JFPdml.pdf", +} + +@Article{xi-patterns-03, + author = "Hongwei Xi", + title = "{Dependently Typed Pattern Matching}", + journal = jucs, + volume = "9", + number = "8", + year = "2003", + pages = "851--872", + URL = "http://www.cs.bu.edu/~hwxi/academic/papers/jucs03.pdf", +} + +@InProceedings{xi-pfenning-99, + author = "Hongwei Xi and Frank Pfenning", + title = "Dependent Types in Practical Programming", + booktitle = popl, + year = "1999", + pages = "214--227", + URL = "http://www.ececs.uc.edu/~hwxi/academic/papers/popl99.ps", +} + +@InProceedings{xi-views-05, + author = "Dengping Zhu and Hongwei Xi", + title = "Safe Programming with Pointers through Stateful + Views", + booktitle = padl, + publisher = springer, + series = lncs, + volume = "3350", + year = "2005", + pages = "83--97", + URL = "http://www.cs.bu.edu/~hwxi/academic/papers/padl05.pdf", +} + +@InProceedings{xie-aiken-05, + author = "Yichen Xie and Alex Aiken", + title = "Scalable error detection using {Boolean} + satisfiability", + booktitle = popl, + year = "2005", + pages = "351--363", + URL = "http://glide.stanford.edu/saturn/papers/popl05.pdf", +} + +@InProceedings{xu-06, + author = "Dana N. Xu", + title = "Extended static checking for {Haskell}", + booktitle = hw, + year = "2006", + pages = "48--59", + publisher = acmp, + URL = "http://www.cl.cam.ac.uk/~nx200/research/escH-hw.ps", +} + +@InProceedings{xu-09, + author = "Dana N. Xu and Simon {Peyton Jones} and Koen + Claessen", + title = "Static contract checking for {Haskell}", + booktitle = popl, + year = "2009", + pages = "41--52", + URL = "http://research.microsoft.com/en-us/um/people/simonpj/papers/verify/HaskellContract.ps", +} + +@InProceedings{yang-join-08, + author = "Hongseok Yang and Oukseh Lee and Josh Berdine and + Cristiano Calcagno and Byron Cook and Dino Distefano + and Peter W. O'Hearn", + title = "Scalable Shape Analysis for Systems Code", + year = "2008", + pages = "385--398", + booktitle = cav, + publisher = springer, + series = lncs, + volume = "5123", + URL = "http://research.microsoft.com/en-us/um/cambridge/projects/terminator/cav08b.pdf", +} + +@Article{yi-06, + author = "Kwangkeun Yi", + title = "Educational Pearl: 'Proof-directed debugging' + revisited for a first-order version", + journal = jfp, + volume = "16", + number = "6", + year = "2006", + pages = "663--670", + URL = "http://ropas.snu.ac.kr/~kwang/paper/06-jfp-yi.pdf", +} + +@InProceedings{yoshida-96, + author = "Nobuko Yoshida", + title = "Graph Types for Monadic Mobile Processes", + booktitle = fsttcs, + mon = dec, + year = "1996", + publisher = springer, + series = lncs, + volume = "1180", + pages = "371--386", + URL = "http://www.mcs.le.ac.uk/~nyoshida/paper/graph1_short.ps.gz", +} + +@TechReport{yoshida-96-full, + author = "Nobuko Yoshida", + title = "Graph Types for Monadic Mobile Processes", + number = "ECS-LFCS-96-350", + institution = "University of Edinburgh", + year = "1996", + URL = "http://www.lfcs.inf.ed.ac.uk/reports/96/ECS-LFCS-96-350/", +} + +@InProceedings{yoshida-al-02, + author = "Nobuko Yoshida and Kohei Honda and Martin Berger", + title = "Linearity and Bisimulation", + booktitle = fossacs, + publisher = springer, + series = lncs, + year = "2002", + URL = "http://www.mcs.le.ac.uk/~nyoshida/paper/fossacs_ca_final.ps.gz", +} + +@TechReport{yoshida-al-02-long, + author = "Nobuko Yoshida and Kohei Honda and Martin Berger", + title = "Linearity and Bisimulation", + institution = "University of Leicester", + year = "2001", + number = "MSC-2001/48", + URL = "http://www.mcs.le.ac.uk/~nyoshida/paper/lb.ps.gz", +} + +@InProceedings{yoshida-honda-berger-07, + author = "Nobuko Yoshida and Kohei Honda and Martin Berger", + title = "Logical Reasoning for Higher-Order Functions with + Local State", + booktitle = fossacs, + pages = "361--377", + year = "2007", + volume = "4423", + series = lncs, + publisher = springer, + URL = "http://www.doc.ic.ac.uk/~mberger/publications/fossacs07/fossacs07.pdf", +} + +@InProceedings{zdancewic-myers-01, + author = "Steve Zdancewic and Andrew C. Myers", + title = "Secure Information Flow and {CPS}", + booktitle = esop, + publisher = springer, + series = lncs, + year = "2001", + URL = "http://www.cs.cornell.edu/zdance/lincont.ps", +} + +@Article{zdancewic-myers-02, + author = "Steve Zdancewic and Andrew C. Myers", + title = "Secure Information Flow via Linear Continuations", + journal = "Higher Order and Symbolic Computation", + year = "2002", + volume = "15", + number = "2--3", + pages = "209--234", + URL = "http://www.cis.upenn.edu/~stevez/papers/ZM02.pdf", +} + +@InProceedings{zendra-97, + author = "Olivier Zendra and Dominique Colnet and Suzanne + Collin", + title = "Efficient Dynamic Dispatch without Virtual Function + Tables. The {SmallEiffel} Compiler", + booktitle = oopsla, + pages = "125--141", + year = "1997", + URL = "http://www.loria.fr/~colnet/publis/oopsla97.ps.gz", +} + +@Article{zenger-97, + author = "Christoph Zenger", + title = "Indexed Types", + journal = tcs, + year = "1997", + volume = "187", + number = "1--2", + pages = "147--165", + URL = "http://dx.doi.org/10.1016/S0304-3975(97)00062-5", +} + +@PhdThesis{zenger-98, + author = "Christoph Zenger", + title = "Indizierte Typen", + school = "Universität Karlsruhe", + year = "1998", + URL = "http://www.christoph-zenger.de/papers/thesis.ps.gz", +} + +@PhdThesis{zhao-07, + author = "Yang Zhao", + title = "Concurrency Analysis Based on Fractional Permission + System", + school = "University of Wisconsin", + year = "2007", + URL = "http://www.cs.uwm.edu/~boyland/papers/yangzhao-thesis.pdf", +} + +@TechReport{zheng-myers-04, + author = "Lantian Zheng and Andrew C. Myers", + title = "Dynamic Security Labels and Noninterference", + institution = "Cornell University", + year = "2004", + number = "2004-1924", + URL = "http://www.cs.cornell.edu/andru/papers/dynl-tr.pdf", +} + +@InProceedings{zhu-xi-03, + author = "Dengping Zhu and Hongwei Xi", + title = "A Typeful and Tagless Representation for {XML} + Documents", + booktitle = aplas, + publisher = springer, + series = lncs, + volume = "2895", + year = "2003", + pages = "89--104", + URL = "http://www.cs.bu.edu/~hwxi/academic/papers/aplas03.pdf", +} + +@Misc{zibin-gil-01, + author = "Yoav Zibin and Yossi Gil", + title = "Theory and Practice of Incremental Subtyping Tests and + Message Dispatching", + year = "2001", + URL = "http://www.cs.technion.ac.il/~yogi/incremental-dispatching.ps.gz", +} + +@InProceedings{zibin-gil-02, + author = "Yoav Zibin and Yossi Gil", + title = "Fast Algorithm for Creating Space Efficient + Dispatching Tables with Application to + Multi-Dispatching", + booktitle = oopsla, + pages = "142--160", + year = "2002", + URL = "http://www.cs.technion.ac.il/~zyoav/publications/OOPSLA02-dispatching-TS.pdf", +} + +@InProceedings{zibin-gil-03, + author = "Yoav Zibin and Yossi Gil", + title = "Incremental Algorithms for Dispatching in Dynamically + Typed Languages", + booktitle = popl, + year = "2003", + URL = "http://www.cs.technion.ac.il/~zyoav/publications/POPL03-dispatching-CT.pdf", +} + +@TechReport{zwanenburg-97, + author = "Jan Zwanenburg", + title = "A Type System for Record Concatenation and Subtyping", + year = "1997", + institution = "Eindhoven University of Technology", + URL = "http://www.cs.ru.nl/~janz/publications/type_check.ps", +} diff --git a/doc/from-visitors-to-iterators.md b/doc/from-visitors-to-iterators.md new file mode 100644 index 0000000..fd1733e --- /dev/null +++ b/doc/from-visitors-to-iterators.md @@ -0,0 +1,493 @@ +I have been asked whether +an automatically-generated visitor, +as produced by the [visitors](https://gitlab.inria.fr/fpottier/visitors) +syntax extension for OCaml, +can be used to construct an iterator. + +It turns out that this can be done +in a simple and efficient manner. +(Up to a constant factor, the time complexity of this solution is optimal.) +As the problem is interesting and +its solution is somewhat nonobvious, +I am describing them here. + +To play with this code in an OCaml toplevel, +first install `visitors` via the command `opam install visitors`. +Then, launch `ocaml` and type this: + +``` +#use "topfind";; +#require "visitors.ppx";; +#require "visitors.runtime";; +``` + +## Problem Statement + +Suppose we have an arbitrary data structure that contains elements +of type `'a`. Here, it is a binary tree, but it could be anything: + +``` +type 'a sometree = + | Leaf + | Node of 'a sometree * 'a * 'a sometree +``` + +We would like to enumerate the elements of this data structure. +More precisely, we would like to construct an iterator, that is, +an on-demand producer of elements. Here is a simple definition +of a stateful iterator: + +``` +type 'a iterator = + unit -> 'a option +``` + +The question is, can we construct an iterator for the type `'a sometree`, +based on an automatically-generated visitor, so that the construction is +entirely independent of the type `'a sometree`? + +## Cascades + +For starters, let us define cascades, which are a more pleasant kind of +iterators. A cascade is a persistent (stateless) iterator. It can be thought +of as a delayed list, that is, a list whose elements are computed only on +demand. + +Cascades could (should) be part of a separate library. +As the time of writing (March, 2017), there is in fact +[a proposal](https://github.com/ocaml/ocaml/pull/1002) +to add them to OCaml's standard library. + +``` +type 'a cascade = + unit -> 'a head + +and 'a head = + | Nil + | Cons of 'a * 'a cascade +``` + +A delayed computation is represented as a function of type `unit -> _`. + +The cascade constructors are as follows: + +``` +let nil : 'a cascade = + fun () -> Nil + +let cons (x : 'a) (xs : 'a cascade) : 'a cascade = + fun () -> Cons (x, xs) +``` + +Forcing a cascade reveals its head: + +``` +let force xs = + xs() +``` + +A cascade can be easily converted to a stateful iterator: + +``` +let cascade_to_iterator (xs : 'a cascade) : 'a iterator = + let s = ref xs in + fun () -> + match force !s with + | Nil -> + s := nil; + None + | Cons (x, xs) -> + s := xs; + Some x +``` + +In the above code, writing `nil` into `s` may seem superfluous, but is in fact +necessary to guarantee that the computation that led to a `Nil` outcome is not +repeated in the future. + +Because cascades are close cousins of lists, they are easy to work with. +Constructing a cascade for a tree-like data structure is straightforward, +whereas directly constructing a stateful iterator would be more involved. + +## Back to the problem + +Now, can we use some kind of visitor to turn a tree of type `'a sometree` +into a cascade of type `'a cascade`? + +At first sight, this does not seem very easy, because of two issues: + + * a visitor usually traverses a tree in an eager manner, whereas we need the + traversal to make progress only as cascade elements are demanded; + + * a visitor performs a bottom-up computation, without a left-to-right bias + (assuming mutable state is not used), whereas a cascade enumerates elements + in a left-to-right manner. (Or in a right-to-left manner. As will be + apparent below, both directions are possible.) + +The trick is to use another intermediate step. Instead of turning a tree +directly into a cascade, we first transform it into a generic tree-like +structure: a *delayed tree*. The first issue above is solved because, by +introducing delays into the new tree, we allow its construction to be carried +out on demand. The second issue is solved because this tree-to-tree +transformation can be carried out in a purely bottom-up manner by a `reduce` +visitor. Then, finally, it is straightforward to transform a delayed tree into +a cascade. + +## From Delayed Trees to Cascades and Iterators + +A delayed tree contains ordinary nodes of arity 0, 1, and 2. Furthermore, +it contains `DTDelay` nodes, of arity 1, whose child is delayed, that is, +computed only on demand. + +``` +type 'a delayed_tree = + | DTZero + | DTOne of 'a + | DTTwo of 'a delayed_tree * 'a delayed_tree + | DTDelay of (unit -> 'a delayed_tree) +``` + +A delayed tree is converted to a cascade as follows. As is often the case, +when building a cascade, one must take a continuation `k` as an argument, so +as to avoid naive and costly cascade concatenation operations. Thus, the +specification of the function call `delayed_tree_to_cascade dt k` is to +construct a cascade whose elements are the elements of the delayed tree `dt` +(listed from left to right), followed with the elements of the cascade `k`. + +``` +let rec delayed_tree_to_cascade (dt : 'a delayed_tree) (k : 'a cascade) +: 'a cascade = + fun () -> delayed_tree_to_head dt k + +and delayed_tree_to_head (dt : 'a delayed_tree) (k : 'a cascade) : 'a head = + match dt with + | DTZero -> + force k + | DTOne x -> + Cons (x, k) + | DTTwo (dt1, dt2) -> + delayed_tree_to_head dt1 (delayed_tree_to_cascade dt2 k) + | DTDelay dt -> + delayed_tree_to_head (force dt) k + +let delayed_tree_to_cascade (dt : 'a delayed_tree) : 'a cascade = + delayed_tree_to_cascade dt nil + +let delayed_tree_to_iterator (dt : 'a delayed_tree) : 'a iterator = + cascade_to_iterator (delayed_tree_to_cascade dt) +``` + +In the above code, we have chosen to perform a left-to-right traversal of +the delayed tree, but could just as well have chosen a right-to-left traversal. + +It is possible to make the delayed tree data structure implicit in the code; +this is explained [further on](#variant-getting-rid-of-explicit-delayed-trees). + +## Constructing Delayed Trees + +The type `'a delay` is a synonym for `'a`. We will use it as a decoration, in +a type definition, to indicate that a call to the method `visit_delay` is +desired. + +``` +type 'a delay = 'a +``` + +We now set up four constructor functions or constructor methods, which +construct delayed trees, and which we will use in a `reduce` visitor. + +Delayed trees form a monoid, in the sense that we concatenate them using +`DTTwo`, and the neutral element is `DTZero`. We package these two data +constructors in the methods `zero` and `plus`, which are automatically called +in an automatically-generated `reduce` visitor. + +The visitor method `visit_delay` delays the visit of a subtree by constructing +and returning a `DTDelay` node, which carries a delayed recursive call to a +visitor. + +The visitor function `yield` will be invoked at elements of type `'a`. It +constructs a one-element delayed tree. + +``` +class ['self] delayed_tree_monoid = object (_ : 'self) + + method zero = + DTZero + + method plus s1 s2 = + match s1, s2 with + | DTZero, s + | s, DTZero -> + s + | _, _ -> + DTTwo (s1, s2) + + method visit_delay: 'env 'a . + ('env -> 'a -> 'b delayed_tree) -> + 'env -> 'a delay -> 'b delayed_tree + = fun visit_'a env x -> + DTDelay (fun () -> visit_'a env x) + +end + +let yield _env x = + DTOne x +``` + +In the method `plus`, above, treating `DTZero` specially is not mandatory. It +is an optimization, which helps allocate fewer nodes. + +## Generating a Visitor + +It is now time to generate a `reduce` visitor for the type `'a sometree`. +This is the only part of the code which is specific of `sometree`. +Everything else is generic. + +We must insert *delays* into the structure of the type `'a sometree` so as to +indicate where `visit_delay` should be called and (therefore) where `DTDelay` +nodes should be allocated. To do this, we write a copy of the definition of +the type `'a sometree`, with extra uses of `delay` in it. The new type is +actually considered equal to `'a sometree` by OCaml. Its role is purely to +carry a `@@deriving visitors` annotation. + +In the data constructor `Node`, the left-hand `delay` is in fact superfluous. +With or without it, our iterators will eagerly descend along the leftmost +branch of a tree, anyway. + +``` +type 'a mytree = 'a sometree = + | Leaf + | Node of 'a mytree delay * 'a * 'a mytree delay + +and 'a mytree_delay = + 'a mytree delay + +[@@deriving visitors { variety = "reduce"; polymorphic = true; + concrete = true; ancestors = ["delayed_tree_monoid"] }] +``` + +This approach is pleasant insofar as one controls exactly where delays are +inserted. However, it requires copying the type definition, which may be +unpleasant. Another approach is described +[further on](#variant-avoiding-duplication-of-the-type-definition). + +## Using the Generated Visitor + +For demonstration purposes, let us make our visitor verbose. In production, +one should remove `verbose_reduce` and use `reduce` instead. + +``` +class ['self] verbose_reduce = object (_ : 'self) + inherit [_] reduce as super + method! visit_Leaf visit_'a env = + Printf.printf "Visiting a leaf.\n%!"; + super#visit_Leaf visit_'a env + method! visit_Node visit_'a env t1 x t2 = + Printf.printf "Visiting a node.\n%!"; + super#visit_Node visit_'a env t1 x t2 +end +``` + +The problem is solved! There remains to write a couple lines of glue code: + +``` +let sometree_to_delayed_tree (t : 'a sometree) = + new verbose_reduce # visit_mytree_delay yield () t + +let sometree_to_iterator (t : 'a sometree) : 'a iterator = + delayed_tree_to_iterator (sometree_to_delayed_tree t) +``` + +We use `visit_mytree_delay` above, even though `visit_mytree` would work just +as well, so as to ensure that we get a delayed tree whose root is a `DTDelay` +node. Thus, absolutely no work is performed when the iterator is created; +iteration begins only when the first element is demanded. + +## Demo + +A little demo helps see what is going on. + +``` +let t : int sometree = + Node (Node (Leaf, 1, Leaf), 2, Node (Leaf, 3, Leaf)) + +let i : int iterator = + sometree_to_iterator t +``` + +Here is a transcript of an OCaml toplevel session: + +``` + # i();; + Visiting a node. + Visiting a node. + Visiting a leaf. + - : int option = Some 1 + # i();; + Visiting a leaf. + - : int option = Some 2 + # i();; + Visiting a node. + Visiting a leaf. + - : int option = Some 3 + # i();; + Visiting a leaf. + - : int option = None + # i();; + - : int option = None +``` + +## Variant: Avoiding Duplication of the Type Definition + +Earlier, we have generated a visitor for the existing type `'a sometree` in *a +posteriori* style. We have manually created an isomorphic copy of the type `'a +sometree`, which we have named `'a mytree`, and have annotated this copy with +`[@@deriving visitors { ... }]`. Furthermore, we have taken this opportunity +to insert `delay` type constructors into the type, so as to influence the +generated visitor. + +This style is relatively pleasant because it is declarative and lets us +control exactly where delays are inserted. However, it requires duplicating +the definition of the type `'a sometree`, which may be unpleasant (if the +definition is large) or impossible (if the definition is hidden behind an +abstraction barrier). + +Another approach is to generate a visitor in *a priori* style. When the type +`'a sometree` is first defined, a `reduce` visitor can be immediately +generated for it, as follows: + +``` +type 'a sometree = + | Leaf + | Node of 'a sometree * 'a * 'a sometree + +[@@deriving visitors { variety = "reduce"; polymorphic = true; + name = "sometree_reduce" }] +``` + +At this point, we pretend that we do not know yet what this visitor will be +used for, so we do not annotate the type definition with `delay`, and do not +use `delayed_tree_monoid` as a base class. We get a visitor class, named +`sometree_reduce`. This class has two virtual methods, `zero` and `plus`. + +Then, we create a subclass, named `reduce`, which we tailor to our needs. +We mix the generated class `sometree_reduce` with the class `delayed_tree_monoid`, +and insert a delay at every tree node by overriding the method `visit_sometree`: + +``` +class ['self] reduce = object (self : 'self) + inherit [_] sometree_reduce as super + inherit [_] delayed_tree_monoid + method! visit_sometree visit_'a env t = + self#visit_delay (super#visit_sometree visit_'a) env t +end +``` + +The rest of the code is unchanged (except the method `visit_mytree_delay` no +longer exists; one calls `visit_sometree` instead). + +## Variant: Getting Rid of Explicit Delayed Trees + +I like to present delayed trees as an explicit data structure, because this +helps understand what is going on. However, if desired, it is possible to +hide them by *refunctionalization* (the opposite of *defunctionalization*). + +Above, the function `delayed_tree_to_cascade` was written with the help of an +auxiliary function, `delayed_tree_to_head`. We could also have written it +directly, as follows: + +``` +let rec delayed_tree_to_cascade (dt : 'a delayed_tree) (k : 'a cascade) +: 'a cascade = + match dt with + | DTZero -> + k + | DTOne x -> + cons x k + | DTTwo (dt1, dt2) -> + delayed_tree_to_cascade dt1 (delayed_tree_to_cascade dt2 k) + | DTDelay dt -> + fun () -> delayed_tree_to_cascade (force dt) k () +``` + +In this form, the only function that is ever applied to a delayed tree is +`delayed_tree_to_cascade`. Therefore, wherever we construct a delayed tree +`t`, we could instead directly build a closure whose behavior is equivalent to +`delayed_tree_to_cascade t`. This is *refunctionalization*. + +The data structure of delayed trees seems to disappears. +The type `'a delayed_tree` can be defined as a synonym +for a `'a cascade -> 'a cascade`. I usually refer to +this type as `'a producer`: it is the type of a function +that concatenates elements in front of the cascade that it +receives as an argument. + +``` +type 'a producer = + 'a cascade -> 'a cascade + +type 'a delayed_tree = + 'a producer +``` + +The four data constructors are defined as follows: + +``` +let _DTZero k = + k + +let _DTOne x k = + cons x k + +let _DTTwo dt1 dt2 k = + dt1 (dt2 k) + +let _DTDelay dt k = + fun () -> force dt k () +``` + +The reader can check that the types of these data constructors are the +same as in the previous version of the code. For instance, `_DTDelay` +has type `(unit -> 'a delayed_tree) -> 'a delayed_tree`. + +The root function `delayed_tree_to_cascade` (without a continuation argument) +is defined as follows: + +``` +let delayed_tree_to_cascade (dt : 'a delayed_tree) : 'a cascade = + dt nil +``` + +The delayed tree monoid uses the new versions of the four data constructors: + +``` +class ['self] delayed_tree_monoid = object (_ : 'self) + + method zero = + _DTZero + + method plus = + _DTTwo + + method visit_delay: 'env 'a . + ('env -> 'a -> 'b delayed_tree) -> + 'env -> 'a delay -> 'b delayed_tree + = fun visit_'a env x -> + _DTDelay (fun () -> visit_'a env x) + +end + +let yield _env x = + _DTOne x +``` + +The four functions `_DTZero`, `_DTOne`, `_DTTwo`, and `_DTDelay` could be +inlined, if desired, so as to make the above code seem even more concise. + +The rest of the code is unchanged. + +## Acknowledgements + +KC Sivaramakrishnan asked whether a visitor can be used to construct an +iterator. Gabriel Scherer pointed out that the delayed tree data structure can +be hidden by refunctionalization. diff --git a/doc/listings-ocaml.tex b/doc/listings-ocaml.tex new file mode 100644 index 0000000..4ab8be0 --- /dev/null +++ b/doc/listings-ocaml.tex @@ -0,0 +1,24 @@ +% Configuring listings for OCaml. + +% Comments in blue. +\newcommand{\ocamlcommentstyle}{\color{blue}} + +\lstdefinelanguage{ocaml}[Objective]{Caml}{ + % Fix errors in the default definition of ocaml. + deletekeywords={closed,ref}, + morekeywords={initializer}, + % General settings. + flexiblecolumns=false, + showstringspaces=false, + framesep=5pt, + commentstyle=\ocamlcommentstyle, + % By default, we use a small font. + basicstyle=\tt\small, + numberstyle=\footnotesize, + % LaTeX escape. + escapeinside={$}{$}, +} + +% An abbreviation for \lstinline, with a normal font size. +% To be used in the text of the paper. +\def\oc{\lstinline[language=ocaml,basicstyle=\tt,flexiblecolumns=true]} diff --git a/doc/local.bib b/doc/local.bib new file mode 100644 index 0000000..9d71c5b --- /dev/null +++ b/doc/local.bib @@ -0,0 +1,23 @@ +@Misc{ocaml7465, + author = {Fran{\c c}ois Pottier}, + title = {OCaml issue 7465}, + month = jan, + year = 2017, + URL = "https://caml.inria.fr/mantis/view.php?id=7465", +} + +@Misc{milewski-13, + author = {Bartosz Milewski}, + title = {Understanding {$F$-algebras}}, + month = oct, + year = 2013, + URL = {https://www.schoolofhaskell.com/user/bartosz/understanding-algebras} +} + +@Misc{iterators, + author = {Fran{\c c}ois Pottier}, + title = {From visitors to iterators}, + month = mar, + year = 2017, + URL = {http://gallium.inria.fr/blog/from-visitors-to-iterators/}, +} diff --git a/doc/macros.tex b/doc/macros.tex new file mode 100644 index 0000000..b1c0118 --- /dev/null +++ b/doc/macros.tex @@ -0,0 +1,123 @@ +% ------------------------------------------------------------------------------ +% Including a source code file foo.ml: +% \orig{foo} + +\mdfsetup{% + linewidth=0pt,% + skipabove=\baselineskip,% + skipbelow=.4\baselineskip,% + innertopmargin=0pt,% + innerbottommargin=0pt,% +} + +\newenvironment{origenv}{% + \begin{mdframed}[backgroundcolor=gray!10]% +}{% + \end{mdframed}% +} + +\newcommand{\orig}[1]{% +\begin{origenv} +\lstinputlisting{#1.ml} +\end{origenv} +} + +\newcommand{\origfirstline}[2]{% +\begin{origenv} +\lstinputlisting[firstline=#2]{#1.ml} +\end{origenv} +} + +%% \newcommand{\codefollowupgeneral}[1]{% +%% \begin{center} +%% (This code fragment follows up on #1.) +%% \end{center} +%% \vspace{-\baselineskip} +%% } + +\newcommand{\codefollowupgeneral}[1]{% +\marginnote{\footnotesize This follows #1.}[5mm]% +} + +\newcommand{\codefollowup}[1]{% + \codefollowupgeneral{\fref{fig:#1}}% +} + +% ------------------------------------------------------------------------------ +% Including the corresponding auto-generated code: +% \processed{foo} + +\newenvironment{processedenv}{% + \begin{mdframed}[backgroundcolor=yellow!40]% +}{% + \end{mdframed}% +} + +\newcommand{\processed}[1]{% +\begin{processedenv} +\lstinputlisting{#1.processed.ml} +\end{processedenv} +} + +% ------------------------------------------------------------------------------ +% Various macros. + +\newcommand{\fref}[1]{Figure~\ref{#1}} +\newcommand{\sref}[1]{\S\ref{#1}} +\newcommand{\email}[1]{\href{mailto:#1}{\texttt{#1}}} + +% ------------------------------------------------------------------------------ +% Abbreviations. + +\newcommand{\merlin}{\href{https://github.com/ocaml/merlin}{Merlin}\xspace} +\newcommand{\ocamlbuild}{\href{https://github.com/ocaml/ocamlbuild/blob/master/manual/manual.adoc}{\texttt{ocamlbuild}}\xspace} +\newcommand{\ocamlfind}{\texttt{ocamlfind}\xspace} +\newcommand{\opam}{\href{https://opam.ocaml.org/}{\texttt{opam}}\xspace} +\newcommand{\ppxderiving}{\href{https://github.com/whitequark/ppx_deriving}{\texttt{ppx\_deriving}}\xspace} +\newcommand{\ppximport}{\href{https://github.com/whitequark/ppx_import}{\texttt{ppx\_import}}\xspace} + +\newcommand{\hashconsRepoURL}{https://github.com/backtracking/ocaml-hashcons} +\newcommand{\hashcons}{\href{\hashconsRepoURL}{\texttt{hashcons}}\xspace} +\newcommand{\hashconsRepoFile}[1]{\href{\hashconsRepoURL/blob/master/#1}{\texttt{#1}}} + +\newcommand{\repoURL}{https://gitlab.inria.fr/fpottier/visitors} +\newcommand{\srcFile}[1]{\href{\repoURL/blob/master/src/#1}{\texttt{#1}}} + +\newcommand{\iter}{\texttt{iter}\xspace} +\newcommand{\map}{\texttt{map}\xspace} +\newcommand{\mapendo}{\texttt{endo}\xspace} +\newcommand{\reduce}{\texttt{reduce}\xspace} +\newcommand{\mapreduce}{\texttt{mapreduce}\xspace} +\newcommand{\fold}{\texttt{fold}\xspace} +\newcommand{\itertwo}{\texttt{iter2}\xspace} +\newcommand{\maptwo}{\texttt{map2}\xspace} +\newcommand{\reducetwo}{\texttt{reduce2}\xspace} +\newcommand{\mapreducetwo}{\texttt{mapreduce2}\xspace} +\newcommand{\foldtwo}{\texttt{fold2}\xspace} +\newcommand{\unit}{\texttt{unit}\xspace} +\newcommand{\visitors}{\texttt{visitors}\xspace} +\newcommand{\derivingvisitors}{\texttt{[@@deriving visitors \{ ...\ \}]}\xspace} +\newcommand{\runtime}[1]{\oc|VisitorsRuntime.#1|} + +\newcommand{\tyconvisitor}[1]{\texttt{visit\_#1}} +\newcommand{\dataconvisitor}[1]{\texttt{visit\_#1}} +\newcommand{\tyconfail}[1]{\texttt{fail\_#1}} +\newcommand{\dataconascendingmethod}[1]{\texttt{build\_#1}} +\newcommand{\tyconascendingmethod}[1]{\texttt{build\_#1}} + +\newcommand{\refconvention}{\sref{sec:intro:parameterized:poly}, \sref{sec:intro:nonlocal}, +\fref{fig:convention}} + +% Options. +\newcommand{\ancestors}{\texttt{ancestors}\xspace} +\newcommand{\concrete}{\texttt{concrete}\xspace} +\newcommand{\irregular}{\texttt{irregular}\xspace} +\newcommand{\name}{\texttt{name}\xspace} +\newcommand{\public}{\texttt{public}\xspace} +\newcommand{\variety}{\texttt{variety}\xspace} +\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} diff --git a/doc/main.tex b/doc/main.tex new file mode 100644 index 0000000..6b9cf3f --- /dev/null +++ b/doc/main.tex @@ -0,0 +1,2390 @@ +\documentclass[11pt,a4paper,twoside]{article} +\usepackage[left=25mm,right=25mm,top=25mm,bottom=25mm,marginparwidth=50pt]{geometry} +\setlength\abovecaptionskip{0pt} % Reduce space above figure captions. +\usepackage{lmodern} % This gives us a bold monospace font. +\renewcommand{\rmdefault}{ptm} % Times. +\usepackage[T1]{fontenc} +\usepackage[utf8]{inputenc} +\usepackage{enumitem} +\usepackage[bookmarks=true,bookmarksopen=true,colorlinks=true,% + linkcolor=blue,citecolor=blue,urlcolor=blue]{hyperref} +\usepackage{marginnote} +\usepackage{listings} +\input{listings-ocaml} +\lstset{language=ocaml} +\usepackage{moreverb} +\usepackage{tabularx} +\usepackage{xcolor} +\usepackage{mdframed} +\usepackage{xspace} +\input{macros} +% Style. +\renewcommand{\emph}[1]{\textbf{#1}} +\input{version} + +% ------------------------------------------------------------------------------ +% Headings. + +\title{Visitors\\\normalsize version \visitorsversion} +\date{} +\begin{document} +\author{François Pottier\\ Inria Paris\\ \email{francois.pottier@inria.fr}} +\maketitle + +% ------------------------------------------------------------------------------ + +\clearpage +\tableofcontents +\clearpage + +% ------------------------------------------------------------------------------ + +\begin{flushright} + Les visites font toujours plaisir, si ce n'est en arrivant, du moins en + partant. \\ --- \textit{Jean de La Bruyère} +\end{flushright} + +\vspace{8mm} + +% ------------------------------------------------------------------------------ +% ------------------------------------------------------------------------------ + +\section{Introduction} +\label{sec:intro} + +% ------------------------------------------------------------------------------ + +\subsection{What is a visitor?} + +A visitor class for a data structure is a class whose methods implement a +traversal of this data structure. By default, the visitor methods do not have +interesting behavior: they just cause control to go down into the data +structure and come back up, without performing any actual computation. +Nevertheless, by defining subclasses where one method or a few methods are +overridden, nontrivial behavior can be obtained. Therefore, visitors allow +many operations on this data structure to be defined with little effort. + +Visitor classes come in several varieties. An \iter visitor traverses a data +structure and returns no result. It can nevertheless have side effects, +including updating a piece of mutable state, raising an exception, and +performing input/output. A \map visitor traverses a data structure and returns +another data structure: typically, a copy of its argument that has been +transformed in some way. An \mapendo visitor is a variant of a \map visitor +that preserves physical sharing when possible. A \reduce visitor traverses a +data structure and returns a value that somehow summarizes it: computing the +size of a data structure is a typical example. A \mapreduce visitor performs +the tasks of a \map visitor and a \reduce visitor at the same time, +possibly allowing symbiosis between them. All of these can be viewed as +special cases of the \fold visitor, which performs a bottom-up computation +over a data structure. The class \fold is equipped with virtual methods +% (the ``\tyconascendingmethod{}'' methods) +that can be overridden (in a subclass) so as to specify what computation is +desired. + +Visitors also come in several arities. The visitors mentioned above have arity +one: they traverse one data structure. However, it is sometimes necessary to +simultaneously traverse two data structures of identical shape. For this +purpose, there are visitors of arity two: here, they are known as \itertwo, +\maptwo, \reducetwo, \mapreducetwo, and \foldtwo visitors. + +% \mapendotwo does not exist. + +% ------------------------------------------------------------------------------ + +\subsection{What does this package offer?} + +Visitors have extremely regular structure. As a result, whereas implementing +them by hand is boring and error-prone, generating them automatically is often +possible. The \visitors package extends the syntax of OCaml% +% +\footnote{Technically, \visitors is a plugin for \ppxderiving, which itself is + a preprocessor extension for the OCaml compiler.} +% +so as to make it easy for the programmer to request the automatic generation +of visitor classes. Visitor classes for many forms of user-defined data types +can be generated and, if necessary, combined (via multiple inheritance) with +hand-written visitor classes, making the framework quite powerful. + +% ------------------------------------------------------------------------------ +% ------------------------------------------------------------------------------ + +\section{Walkthrough} + +% ------------------------------------------------------------------------------ + +\subsection{Setup} +\label{sec:intro:setup} + +In order to install the \visitors package, an \opam user should issue the +following commands: +\begin{lstlisting}[keywords={}] + opam update + opam install visitors +\end{lstlisting} +To use the package, an \ocamlbuild user should add the +following line in her project's \texttt{\_tags} file: +\begin{lstlisting}[keywords={}] + true: package(visitors.ppx), package(visitors.runtime) +\end{lstlisting} +Finally, a user of \merlin should add the following lines in her project's +\texttt{.merlin} file: +\begin{lstlisting}[keywords={}] + 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} + +% ------------------------------------------------------------------------------ + +\begin{figure}[t] +% In an OCaml source file, a type definition can be annotated with +% \derivingvisitors: +\orig{expr00} +% This causes the following code to be (invisibly) generated: +\vspace{-\baselineskip} +\processed{expr00} +\caption{A visitor of the \iter variety} +\label{fig:expr00} +\end{figure} + +\subsection{Defining an \iter visitor} +\label{sec:intro:iter:def} + +Suppose we need to manipulate arithmetic expressions built out of integer +literals and binary additions. The abstract syntax of these expressions can be +described by an algebraic data type \oc|expr|, shown in the first part of +\fref{fig:expr00}. +% +By annotating this type definition with \derivingvisitors, we request the +automated generation of a visitor for expressions. The annotation +\derivingvisitors must carry at least one parameter, \variety, which indicates +what variety of visitor is desired. + +The code of the visitor class, which is automatically generated and in normal +use remains invisible, is shown in the second part of \fref{fig:expr00}. The +name of this class is by default the value of the \variety parameter. It can +be changed, if desired, by explicitly supplying a \name parameter. + +A visitor takes the form of an OCaml class, whose methods are named after the +types and data constructors that appear in the type definition. In +\fref{fig:expr00}, for instance, the method \tyconvisitor{expr} is named after +the type \oc|expr|, while the methods \dataconvisitor{EConst} and +\dataconvisitor{EAdd} are named after the data constructors \oc|EConst| and +\oc|EAdd|. + +Different varieties of visitors differ in the computation that is performed +``on the way up'', after the recursive calls have finished, therefore differ +in the return types of the visitor methods. \iter is the simplest variety. An +\iter visitor performs no computation on the way up, so its methods have +return type \oc|unit|. + +In an \iter visitor, the generated visitor methods do nothing. In +\fref{fig:expr00}, for instance, the method \tyconvisitor{expr} inspects its +argument \oc|this| and recursively invokes either \dataconvisitor{EConst} or +\dataconvisitor{EAdd}, as appropriate. The method \dataconvisitor{EConst} does +nothing.\footnote{More precisely, it calls the method \tyconvisitor{int}, + which is inherited from the class \runtime{iter}, and does + nothing. This call to \tyconvisitor{int} can be avoided, if desired, by using + \oc|(int[@opaque])| instead of \oc|int|; see \sref{sec:opaque}.} The method +\dataconvisitor{EAdd} performs two recursive calls to \tyconvisitor{expr}, +which does nothing, so \dataconvisitor{EAdd} itself does nothing. + +Every method is parameterized with an environment \oc|env|, which is carried +down into every recursive call and is otherwise unused. The type of this +environment is undetermined: it is up to the (user-defined) subclasses of the +visitor class to decide what the type of \oc|env| should be and (possibly) +where and how this environment should be enriched. + +% One could note that the visitor class is parameterized over 'self, +% but it is perhaps a bit early for such a remark. + +The fields of a data constructor or record are traversed left to right, in the +order they are declared. In a list-like data structure, the field that holds a +pointer to the list tail should be declared last, so as to ensure that the +traversal requires constant stack space. + +% ------------------------------------------------------------------------------ + +\begin{figure}[t] +\codefollowup{expr00} +\origfirstline{expr04}{3} +\caption{Counting the number of addition nodes in an expression} +\label{fig:expr04} +\end{figure} + +\subsection{Using an \iter visitor} +\label{sec:intro:iter:usage} + +Naturally, traversing a data structure without actually computing anything is +not a very sensible thing to do. Things become interesting when at least one +visitor method is overridden so as to give rise to nontrivial behavior. +Suppose, for instance, that we wish to count the number of addition nodes in +an expression. This can be done as shown in \fref{fig:expr04}. We create an +object~\oc|v| that is both a counter (that is, an object equipped with a +mutable field~\oc|count|) and a visitor, and we override its method +\dataconvisitor{EAdd} so that the counter is incremented every time this +method is invoked. There remains to run the visitor, by invoking its +\tyconvisitor{expr} method, and to return the final value of the counter. The +environment, in this example, is unused; we let it have type \unit. + +This may seem a rather complicated way of counting the addition nodes in an +expression. Of course, one could give a direct recursive definition of the +function \oc|count|, in a few lines of code, without using a visitor at all. +The point of employing a visitor, as done in Figures~\ref{fig:expr00} +and~\ref{fig:expr04}, is that no changes to the code are required when the +type of expressions is extended with new cases. + +% ------------------------------------------------------------------------------ + +\subsection{What is the type of a visitor?} +\label{sec:intro:type} + +In this document, most of the time, we prefer to show the code of a visitor +class and omit its type. There are two reasons for this. First, this type is +often verbose, as the class has many methods, and complex, as several type +variables are often involved. Second, although we can explain the type of a +generated visitor on a case-by-case basis, we cannot in the general case +predict the type of a generated visitor. +The reason is, the type of a generated visitor depends upon the +types of the classes that are inherited via the \ancestors parameter +(\sref{sec:ancestors}). Because a \texttt{ppx} syntax extension transforms +untyped syntax trees to untyped syntax trees, the \visitors syntax extension +does not have access to this information. + +For this reason, the \visitors syntax extension cannot generate any type +declarations. Thus, the annotation \derivingvisitors can be used only in an +\texttt{\%.ml} file, not in an \texttt{\%.mli} file. When it is used in an +\texttt{\%.ml} file, the corresponding \texttt{\%.mli} file should either be +omitted altogether or be written by hand. + +\input{types} + +Nevertheless, the type of the generated code can be inspected, if desired, by +requesting the OCaml compiler to infer and display it. For this purpose, one +can use a command of the following form: +\begin{quote} +\verb|ocamlbuild -use-ocamlfind %.inferred.mli| +\end{quote} + +\fref{fig:inferred} shows the type that is inferred via such a command for the +\iter visitor of \fref{fig:expr00}. This type is rather verbose, for two +reasons. First, an explicit type equation, introduced by the \oc|constraint| +keyword, relates the type parameter \oc|'self| with an OCaml object type that +lists the public methods with their types. Second, the class \iter has many more +methods than one might think. This is because it inherits a large number of +private methods from the class \runtime{iter}. In the present case, all of +these methods except \tyconvisitor{int} are in fact unused. + +Fortunately, this complicated type can be manually simplified. This is done in +\fref{fig:simplified}. Two main simplifications have been performed. First, we +have omitted all private methods. Indeed, the most important property of +private methods in OCaml is precisely the fact that it is permitted to hide +their existence. Second, we have omitted the type constraint that bears on +the type variable \oc|'self|, as it is in fact redundant: it is implicit in OCaml +that the type of ``self'' must be an object type that lists the public methods. +The bizarre-looking ``\oc|'monomorphic.|'' annotations indicate that the methods have +monomorphic types. (This notational trick is explained in \sref{sec:oo:monomorphic}.) +This means that the type variable~\oc|'env| is not quantified at the level of each +method\footnote{That would be undesirable, as it would force each method to +treat the environment as an argument of unknown type!}, but at the level of the class. +This means that the three methods must agree on the type of the environment, and +that this type is presently undetermined, but can be determined in a subclass. + +The class type shown in \fref{fig:simplified} cannot be further simplified. +The methods \tyconvisitor{EConst} and \tyconvisitor{EAdd} cannot be hidden, as +they are public. That said, if one wished to hide them, one could add the parameter % +\oc|public = ["visit_expr"]| to the annotation \derivingvisitors in \fref{fig:expr00}. +These two methods would then be declared private in the generated code, +so it would be permitted to hide their existence. + +Although we have claimed earlier that one cannot in the general case predict +the type of a generated visitor method, or even predict whether a generated +method will be well-typed, it is possible to define a convention which in many +cases can be adhered to. This convention is presented later on +(\refconvention). + +% ------------------------------------------------------------------------------ + +\begin{figure}[t] +\orig{expr01} +\vspace{-\baselineskip} +\processed{expr01} +\caption{A visitor of the \map variety} +\label{fig:expr01} +\end{figure} + +\subsection{\map visitors} +\label{sec:intro:map} + +An \iter visitor returns no result. Although, as illustrated previously +(\sref{sec:intro:iter:usage}), it can use private mutable state to accumulate +information, there are applications for which such a visitor is not suitable. +One class of such applications is tree transformations. To transform an +expression into an expression, one should use a visitor of another variety, +namely \map. + +A \map visitor is shown in \fref{fig:expr01}. In comparison with the \iter +visitor of \fref{fig:expr00}, the generated code is identical, except that, +instead of returning the unit value \oc|()|, the method +\dataconvisitor{EConst} reconstructs an \oc|EConst| expression, while the +method \dataconvisitor{EAdd} reconstructs an \oc|EAdd| expression. + +A \map visitor behaves (by default) as an identity function: it constructs a +copy of the data structure that it visits. If the data structure is immutable, +this is rather pointless: in order to obtain nontrivial behavior, at least one +method should be overridden. If the data structure is mutable, though, even +the default behavior is potentially of interest: it constructs a deep copy of +its argument. + +% ------------------------------------------------------------------------------ + +\begin{figure}[p] +\orig{expr00endo} +\vspace{-\baselineskip} +\processed{expr00endo} +\caption{A visitor of the \mapendo variety} +\label{fig:expr00endo} +\end{figure} + +\subsection{\mapendo visitors} +\label{sec:intro:endo} + +\mapendo visitors are a slight variation of \map visitors. Whereas a \map +visitor systematically allocates a copy of the memory block that it receives +as an argument, an \mapendo visitor (\fref{fig:expr00endo}) first tests if the +newly allocated block would have exactly the same contents as the original +block, and if so, re-uses the original block instead. +% Didier attributes this idea to Gérard Huet, +% at least in the case of a dictionary insertion operation, +% where Gérard would raise an exception so as to go back to +% the toplevel and avoid re-allocating a path. +% +This trick allows saving memory: for instance, when a performing a +substitution operation on a term, the subterms that are unaffected +by the substitution are not copied. + +One potential disadvantage of \mapendo visitors, in comparison with \map +visitors, is that these runtime tests have a runtime cost. A more serious +disadvantage is that \mapendo visitors have less general types: in an \mapendo +visitor, the argument type and return type of every method must coincide, +whence the name ``\mapendo''. +% +(An endomorphism is a function of a set into itself.) +% +\map visitors are not subject to this restriction: for an illustration, see +\sref{sec:advanced:hashconsed} and \fref{fig:expr14}. + +In principle, \mapendo visitors should be created only for immutable data +structures. Although the tool can produce an \mapendo visitor for a mutable +data structure, this is discouraged, as it may lead to unexpected behavior. + +% ------------------------------------------------------------------------------ + +\begin{figure}[p] +\orig{expr15} +\vspace{-\baselineskip} +\processed{expr15} +\caption{A visitor of the \reduce variety} +\label{fig:expr15} +\end{figure} + +\begin{figure}[t] +\codefollowup{expr15} +\origfirstline{expr15b}{3} +\caption{Computing the size of an expression using a \reduce visitor} +\label{fig:reduce} +\end{figure} + +\subsection{\reduce visitors} +\label{sec:intro:reduce} + +Whereas an \iter visitor returns no result and a \map visitor returns a data +structure, a \reduce visitor returns a ``summary'' of a data structure, so to +speak. The summary of a term is computed by combining the summaries of its +subterms. This requires summaries to inhabit a monoid, that is, a type +equipped with a binary operation \oc|plus| and its neutral element \oc|zero|. + +\fref{fig:expr15} shows a \reduce visitor for arithmetic expressions. In +\dataconvisitor{EAdd}, the summaries produced by the two recursive calls are +combined using a call to \oc|self#plus|. In \dataconvisitor{EConst}, there are +no recursive calls, so there is nothing to combine: the result is +\oc|self#zero|. + +The virtual methods \oc|zero| and \oc|plus| are declared in the class +\runtime{reduce}, which is automatically inherited. The type of the +monoid elements, at this point, is undetermined: it is up to the +(user-defined) subclasses of the class \reduce to decide what this type should +be and what the monoid operations should be. + +As an example application, \fref{fig:reduce} shows how to compute the size of +an expression using a \reduce visitor. We inherit the class \reduce. We also +inherit the class \runtime{addition_monoid}, which defines the +methods \oc|zero| and \oc|plus| as the integer \oc|0| and integer addition, +respectively. There remains to override the method \tyconvisitor{expr} so as +to indicate that every node contributes 1 to the size of an expression. + +Incidentally, this code is written in such a manner that a single visitor +object is created initially and serves in every call to the function +\oc|size|. This style can be used when the visitor object is immutable and +when the function that one wishes to define is monomorphic. When it cannot be +used, one begins with \oc|let size (e : expr) : int = ...| and ends with % +\oc|v # visit_expr () e|. That style causes a new visitor object to be created +every time \oc|size| is called. +% On pourrait ré-utiliser le même objet à chaque fois en remettant son champ à +% zéro... Mais ce serait sale et pas ré-entrant. + +The size of an expression can also be computed using an \iter visitor equipped +with mutable state, in the style of \fref{fig:expr04}. It is mostly a matter +of style whether such a computation should be performed using \iter or +\reduce. +% TEMPORARY comparer les perfs, pour voir + +An \iter visitor is in fact a special case of a \reduce visitor, instantiated +with the \oc|unit| monoid. Thus, in principle, one could forget \iter and +always work with \reduce. Nevertheless, it is preferable to work with \iter +when it is applicable, for reasons of clarity and efficiency. +% e.g. an \iter visitor can traverse a list-like data structure in constant +% stack space; a \reduce visitor cannot, because it does not have an accu. + +% One might wonder whether a reduce visitor should have an accumulator... +% ...but then it would be left-to-right-from-the-start, instead of bottom-up. +% I am not sure what we want. Maybe we do not need reduce visitors at all! + +% ------------------------------------------------------------------------------ + +\begin{figure}[p] +\orig{expr_info_mapreduce} +\vspace{-\baselineskip} +\processed{expr_info_mapreduce} +\caption{A visitor of the \mapreduce variety} +\label{fig:mapreduce} +\end{figure} + +\begin{figure}[p] +\codefollowup{mapreduce} +\origfirstline{expr_info_mapreduce_use}{3} +\caption{Decorating every subexpression with its size} +\label{fig:expr_info_mapreduce_use} +\end{figure} + +\subsection{\mapreduce visitors} +\label{sec:intro:mapreduce} + +A \mapreduce visitor performs the tasks of a \map visitor and a \reduce +visitor at once. An example appears in \fref{fig:mapreduce}. Every visitor +method returns a pair of a transformed term and a summary. In other words, +it returns a pair of the results that would be returned by a \map visitor +method and by a \reduce visitor method. + +Like a \reduce visitor, a \mapreduce visitor performs a bottom-up computation. +Like a \map visitor, it constructs a new tree. By default, these two tasks are +independent of one another. However, by overriding one or more methods, it is +easy to establish a connection between them: typically, one wishes to exploit +the information that was computed about a subtree in the construction of the +corresponding new subtree. As an example, \fref{fig:expr_info_mapreduce_use} +shows how to transform an arithmetic expression into an arithmetic expression +where every subexpression is annotated with its size. (This example uses a +parameterized type of decorated expressions, which is explained in +\sref{sec:intro:parameterized:mono}. We suggest reading the explanations there +first.) The transformation is carried out in one pass and in linear time. As +in \fref{fig:reduce}, we use the addition monoid to compute integer sizes. +This time, however, the visitor methods return not just a size, but a pair of +a new expression and a size. The method \tyconvisitor{expr} is overridden so +as to store the size of the subexpression, \oc|size|, in the \oc|info| field +of the new expression. Because the overridden method \tyconvisitor{expr} does +not call \tyconvisitor{'info}, the latter method is never called: we provide a +dummy definition of it. + +Other example applications of \mapreduce visitors include: +\begin{itemize}[nosep] +\item decorating every subterm of a $\lambda$-term with the set of its free + variables; +\item decorating every internal node of abstract syntax tree with a region in + the source code (assuming that every leaf carries such a region already). +\end{itemize} + +% ------------------------------------------------------------------------------ + +\begin{figure}[p] +\orig{expr00fold} +\vspace{-\baselineskip} +\processed{expr00fold} +\caption{A visitor of the \fold variety} +\label{fig:expr00fold} +\end{figure} + +\begin{figure}[p] +\orig{fold} +\caption{Converting towards unrelated types using a \fold visitor} +\label{fig:fold} +\end{figure} + +\subsection{\fold visitors} +\label{sec:intro:fold} + +The varities of visitors presented up to this point differ in the computation +that they perform on the way up, after the recursive calls. As we have seen, +\iter visitors perform no computation at all; \map and \mapendo visitors +reconstruct a term; \reduce visitors perform a series of monoid operations. +Each variety follows a baked-in pattern, which has been programmed ahead of +time, and cannot be changed. What if a different form of computation, which +has not been envisioned by the author of the \visitors syntax extension, is +needed? + +This is where \fold visitors come in. A \fold visitor declares virtual methods +that are called on the way up and can be overridden by the user (in a +subclass) so as to implement the desired computation. \fref{fig:expr00fold} +shows a \fold visitor. Two virtual methods, \dataconascendingmethod{EConst} +and \dataconascendingmethod{EAdd}, are declared. They are invoked by +\tyconvisitor{EConst} and \tyconvisitor{EAdd}, respectively. + +In a \fold visitor, the return type of the visitor methods is not fixed ahead +of time. It is up to the (user-defined) subclasses of the visitor class to +decide what this type should be. + +As an example application, \fref{fig:fold} shows how a \fold visitor can be +used to convert the visited data structure to an entirely different format. In +this example, the type \oc|person| is a record type, whose fields are +\oc|firstname| and \oc|surname|. The type \oc|crowd| is isomorphic to a list +of persons, but, for some reason, it is declared as an algebraic data type +equipped with its own data constructors, \oc|Nobody| and \oc|Someone|. Suppose +we wish to convert a \oc|crowd| to a list of pairs of strings. We can do so by +creating a visitor object that inherits the class \fold and provides concrete +implementations of the methods \tyconascendingmethod{person}, +\dataconascendingmethod{Nobody}, and \dataconascendingmethod{Someone}. +Our implementation of \tyconascendingmethod{person} simply allocates +a pair, while our implementations of +\dataconascendingmethod{Nobody} and \dataconascendingmethod{Someone} +respectively build an empty list and a nonempty list. +Thus, the return type of the methods \tyconascendingmethod{person} +and \tyconvisitor{person} is \oc|string * string|, +while the return type of the methods \dataconascendingmethod{Nobody}, +\dataconascendingmethod{Someone}, and \dataconvisitor{crowd} is +\oc|(string * string) list|. In a \fold visitor, not all methods +need have the same return type! + +If we had chosen to return \oc|f ^ s| instead of \oc|(f, s)| in +\tyconascendingmethod{person}, then a crowd would be converted to +a \oc|string list|. A \fold visitor offers great flexibility. + +All previous varieties of visitors are special cases of \fold visitors. The +specialized varieties of visitors are more convenient to use, when they can be +used, because they do not require the user to provide \tyconascendingmethod{} +methods. Yet, \fold visitors are in principle more versatile.% +% +\footnote{This would be true in an untyped setting, but is not quite true in OCaml, +due to restrictions imposed by OCaml's type discipline (\sref{sec:map_from_fold}).} + +% ppx_tools/genlifter is analogous, with a few differences: +% - it is a command line tool, not as ppx extension; +% - it has only one return type 'res for all methods; +% - the visitor methods receive (as extra arguments) +% the names of the types, data constructors, and record fields +% that are being visited. +% - and there are fewer visitor methods, basically one per type, +% plus one primitive type, plus this#record, this#constr. + +% TEMPORARY show how to do a fold in the presence of primitive types, e.g., list +% writing ancestors = ["VisitorsRuntime.map"] may be necessary + +% ------------------------------------------------------------------------------ + +\begin{figure}[p] +\orig{expr02} +\vspace{-\baselineskip} +\processed{expr02} +\caption{A visitor of the \itertwo variety} +\label{fig:expr02} +\end{figure} + +\begin{comment} +\begin{figure}[p] +\orig{expr03} +\vspace{-\baselineskip} +\processed{expr03} +\caption{A visitor of the \maptwo variety} +\label{fig:expr03} +\end{figure} +\end{comment} + +\subsection{Visitors of arity two} +\label{sec:intro:aritytwo} + +The visitors introduced so far traverse one tree at a time. There are +situations where one wishes to simultaneously traverse two trees, which one +expects have the same structure. For this purpose, one can use a visitor of +arity 2. Every variety except \mapendo is available at arity 2. + +As an illustration, \fref{fig:expr02} shows an \itertwo visitor. There, the +method \tyconvisitor{expr} expects an environment and two expressions. These +expressions must have identical structure: indeed, if \tyconvisitor{expr} +finds that they exhibit different tags at the root, say \oc|EConst| versus +\oc|EAdd|, then it invokes the method \tyconfail{expr}, whose default +implementation calls the function \runtime{fail}. This function +throws the exception \runtime{StructuralMismatch}. + +In \fref{fig:expr02}, we have added the optional parameter +% +\oc|concrete = true| +% +to indicate that the generated class should not be virtual. (By default, +every generated class is declared \oc|virtual|.) We do this because, in +the illustration that follows, we wish to instantiate this class. + +\begin{figure}[p] +\codefollowup{expr02} +\origfirstline{expr05}{3} +\caption{Determining whether two expressions are syntactically equal} +\label{fig:expr05} +\end{figure} + +\begin{figure}[p] +\codefollowup{expr02} +\origfirstline{expr05lexico}{3} +\caption{Determining which way two expressions are ordered} +\label{fig:expr05lexico} +\end{figure} + +As an illustration, in \fref{fig:expr05}, we use an \itertwo visitor to write +a function that tests whether two expressions are syntactically equal. This is +just a matter of performing a synchronous traversal of the two expressions and +detecting a \oc|StructuralMismatch| exception: if this exception is raised, +one must return \oc|false|, otherwise one must return \oc|true|. We rely on +the fact that the method \tyconvisitor{int}, which is inherited from the class +\runtime{iter2}, fails when its two integer arguments are +unequal. + +The convenience functions \runtime{wrap} and +\runtime{wrap2} run a user-supplied function (of arity 1 or 2, +respectively) within an exception handler and return a Boolean result, which +is \oc|true| if no exception was raised. Here, we run the function +% +\oc|new iter2 # visit_expr ()|, whose type is \oc|expr -> expr -> unit|, +in the scope of such a handler. + +Naturally, to test whether two expressions are syntactically equal, one could +also use the primitive equality operator \oc|=|. Alternatively, one could +exploit \ppxderiving and annotate the type definition with +% +\oc|[@@deriving eq]|. Visitors offer greater flexibility: for instance, if our +arithmetic expressions contained variables and binders, we could easily define +an operation that tests whether two expressions are $\alpha$-equivalent. + +As a second illustration, in \fref{fig:expr05lexico}, we use an \itertwo +visitor to write a lexicographic ordering function for expressions. Again, +this involves a synchronous traversal of the two expressions. When a mismatch +is detected, however, one must not raise a \oc|StructuralMismatch| exception: +instead, one must raise an exception that carries one bit of information, +namely, which of the two expressions is strictly ``smaller'' in the ordering. +The exception \oc|Different| is introduced for this purpose; it carries an +integer return code, which by convention is either -1 or +1. Two visitor methods +must be overridden, namely \tyconvisitor{int}, which is in charge of detecting +a mismatch between two integer constants, and \tyconfail{expr}, which is invoked +when a mismatch between (the head constructors of) two expressions is detected. +The auxiliary function \oc|tag| returns an integer code for the head constructor +of an expression. It must be hand-written. One could in principle write such a +function once and for all by using the undocumented operations in OCaml's +\href{https://caml.inria.fr/pub/docs/manual-ocaml/libref/Obj.html}{\oc|Obj|} +module, but that is discouraged. + +% Il faut au minimum distinguer les constructeurs constants des autres, +% en utilisant is_int. Il y a peut-être d'autres pièges. De plus, on ne +% peut pas (je crois?) garantir que l'ordre des constructeurs sera bien +% celui de la déclaration de types, parce que les constructeurs constants +% et les autres sont codés indépendamment. + +% ------------------------------------------------------------------------------ + +\begin{figure}[t] +\orig{expr06} +\caption{Visitors for a family of types} +\label{fig:expr06} +\end{figure} + +\subsection{Visitors for a family of types} +\label{sec:intro:family} + +Visitors can be generated not just for one type definition, but for a family +of type definitions. In \fref{fig:expr06}, we propose a definition of +arithmetic expressions that involves three algebraic data types, namely +\oc|unop|, \oc|binop|, and \oc|expr|. We request the generation of two +visitors, namely an \iter visitor and a \map visitor. This causes the +generation of just two classes, named \iter and \map, respectively. Each of +these classes has visitor methods for every type (namely \tyconvisitor{unop}, +\tyconvisitor{binop}, \tyconvisitor{expr}) and for every data constructor +(namely \dataconvisitor{UnaryMinus}, \dataconvisitor{BinaryMinus}, and so on). + +Note that, for the \derivingvisitors annotation to apply to the entire family, +as opposed to just the type \oc|expr|, the types \oc|unop|, \oc|binop|, and +\oc|expr| in \fref{fig:expr06} are declared simultaneously: that is, their +declarations are separated with the keyword \oc|and|. + +% ------------------------------------------------------------------------------ + +\subsection{Visitors for parameterized types} +\label{sec:intro:parameterized} + +% ------------------------------------------------------------------------------ + +Visitors can be generated for parameterized types, too. However, there are two +ways in which this can be done. Here is why. + +To visit a data type where some type variable~\oc|'a| occurs, one must know +how to visit a value of type~\oc|'a|. +% +% That is not quite true, in reality: perhaps there is no component of +% type~\oc|'a|, perhaps because \oc|'a| is a phantom type parameter or a GADT index, +% or perhaps because \oc|'a| occurs only under a type constructor that performs +% special treatment and does not recursively descend its own components. +% +There are two ways in which this information can be provided. One way is to +assume that there is a \emph{virtual visitor method} \oc|visit_'a| in charge +of visiting a value of type~\oc|'a|. Another way is to pass a \emph{visitor + function} \oc|visit_'a| as an argument to every visitor method. + +% J'allais écrire que dans un cadre non typé, ces deux approches ont la +% même expressivité. Mais c'est faux: seule la seconde approche permet +% de gérer les types de données non réguliers (qui existent aussi dans +% un cadre non typé, même s'ils ne sont pas explicitement décrits par +% une déclaration). + +These two approaches differ in their expressive power. The +virtual-visitor-method approach implies that the visitor methods must have +monomorphic types: roughly speaking, the type variable~\oc|'a| +% (or variants of it) +appears free in the type of every visitor method. +The visitor-function approach implies that the visitor methods can have +polymorphic types: roughly speaking, each method independently +can be polymorphic in \oc|'a|. +For this reason, we refer to these two approaches as the \emph{monomorphic} +approach and the \emph{polymorphic} approach, respectively. + +The monomorphic approach offers the advantage that the type of every method is +inferred by OCaml. Indeed, in this mode, the generated code need not contain +any type annotations. This allows correct, most general (monomorphic) types to +be obtained even in the case where certain hand-written visitor methods +(provided via the \ancestors parameter) have unconventional types. +% +% The downside of this approach is that it does not allow taking several +% distinct instances of a parameterized type. In particular, it is restricted +% to regular algebraic data types (\sref{sec:regularity}). + +The polymorphic approach offers the advantage that visitor methods can receive +polymorphic types. If the type \oc|container| is parameterized with a type +variable~\oc|'a|, then the method \tyconvisitor{container} can be assigned a +type that is universally quantified in~\oc|'a|, of the following form: +% +\begin{mdframed}[backgroundcolor=green!10] +\begin{lstlisting} +method visit_container: + 'env 'a . + ('env -> 'a -> ...) -> + 'env -> 'a container -> ... +\end{lstlisting} +\end{mdframed} +% +The types of the \tyconvisitor{list} methods, shown later on +(\sref{sec:intro:nonlocal}, \fref{fig:convention}), follow this pattern. +% +Because \tyconvisitor{container} is polymorphic, taking multiple instances of +the type \oc|container|, such as \oc|apple| \oc|container| and \oc|orange| +\oc|container|, and attempting to generate visitor methods for these types, +poses no difficulty. This works even if the definition of \oc|'a container| +mentions other instances of this type, such as \oc|('a * 'a)| \oc|container|. +In other words, in the polymorphic approach, irregular algebraic data types +(\sref{sec:regularity}) are supported. + +One downside of the polymorphic approach is that, because polymorphic types +cannot be inferred by OCaml, the \visitors syntax extension must generate +polymorphic type annotations. Therefore, it must be able to predict +the type of every visitor method. +% +% Actually, not the full type, but at least the polymorphic skeleton. +% +This requires that any visitor methods inherited via \ancestors adhere to a +certain convention (\refconvention). + +In summary, both the monomorphic approach and the polymorphic approach are +currently supported (\sref{sec:intro:parameterized:mono}, +\sref{sec:intro:parameterized:poly}). The parameter \polymorphic allows +choosing between them. As a rule of thumb, we suggest setting +% +\oc|polymorphic = true|, as this produces visitors that compose better. + +% TEMPORARY give an explanation why monomorphic mode can be useful? + +% In my ICFP paper, I believe monomorphic mode is necessary to deal with ['bn] +% and ['env]. Indeed, we cannot expect [visit_abs] to be polymorphic in ['bn] +% and ['env], as it needs to be told how to [extend] an environment with a +% bound name. + +% Other examples? + +% ------------------------------------------------------------------------------ + +\begin{figure}[p] +\orig{expr_info} +\vspace{-\baselineskip} +\processed{expr_info} +\caption{A ``monomorphic-method'' visitor for a parameterized type of decorated expressions} +\label{fig:expr_info} +\end{figure} + +\begin{figure}[p] +\codefollowup{expr_info} +\origfirstline{expr_info_use}{3} +\caption{Working with different types of decorations} +\label{fig:expr_info_use} +\end{figure} + +\subsubsection{Monomorphic visitor methods for parameterized types} +\label{sec:intro:parameterized:mono} + +We begin with an example of the \emph{monomorphic} mode. This mode can be +explicitly requested by writing \oc|polymorphic = false| as part of the +\derivingvisitors annotation. It is the default mode. + +In \fref{fig:expr_info}, we define a variant of arithmetic +expressions where every tree node is decorated with a value of type +\oc|'info|. We request the generation of a \map visitor, whose code is shown +in the second part of \fref{fig:expr_info}. The generated code has exactly the +same structure as in the previous sections. The only new feature is that the +class \map now has a virtual method, \tyconvisitor{'info}. The general rule +is, for each type parameter, there is one virtual method, named after it. + +The visitor methods are \emph{not} declared polymorphic in a type +variable~\oc|'info|, or in two type variables \oc|'info1|~and~\oc|'info2|, as +one might perhaps expect. In fact, they must not be declared polymorphic: +indeed, the user who implements \tyconvisitor{'info} in a subclass of \map may +wish to provide an implementation that expects and/or produces specific types +of information. + +As a result, a visitor \emph{object} is monomorphic: its method +\tyconvisitor{'info} must have type \oc|info1 ->| \oc|info2| for certain +specific types \oc|info1| and \oc|info2|. Fortunately, because it is +parameterized over \oc|'self|,\footnote{We explain in \sref{sec:oo:self} why + all visitor classes are parameterized over \oc|'self|.} the visitor +\emph{class} is polymorphic: two distinct visitor objects can have distinct +types. + +Although every \emph{automatically generated} method +is monomorphic, a visitor class can nevertheless \emph{inherit} polymorphic +methods from a parent class, whose name is specified via the \ancestors parameter +(\sref{sec:ancestors}). For instance, the \tyconvisitor{list} methods provided by +the classes \runtime{iter}, \runtime{map}, and so on, are +polymorphic in the types of the list elements. (See \sref{sec:intro:nonlocal} +for more information on the treatment of preexisting types.) + +\fref{fig:expr_info_use} presents two example uses of the class \map defined in +\fref{fig:expr_info}. In the first example, we define a function \oc|strip|, of +type \oc|'info expr -> unit expr|, which strips off the decorations in an +arithmetic expression, replacing them with unit values. In the second example, +we define a function \oc|number|, of type \oc|'info expr -> int expr|, which +decorates each node in an arithmetic expression with a unique integer number.% +\footnote{Because the \oc|info| field appears before the \oc|node| field in + the definition of the type \oc|expr|, and because fields are visited + left-to-right, we get a prefix numbering scheme. By exchanging these fields, + we would get postfix numbering.} % + +% ------------------------------------------------------------------------------ + +\subsubsection{Polymorphic visitor methods for parameterized types} +\label{sec:intro:parameterized:poly} + +\begin{figure}[p] +\orig{expr_info_polymorphic} +\vspace{-\baselineskip} +\processed{expr_info_polymorphic} +\caption{A ``polymorphic-method'' visitor for a parameterized type of decorated expressions} +\label{fig:expr_info_polymorphic} +\end{figure} + +\begin{figure}[p] +\codefollowup{expr_info_polymorphic} +\origfirstline{expr_info_polymorphic_use}{3} +\caption{Working with different types of decorations} +\label{fig:expr_info_polymorphic_use} +\end{figure} + +We continue with an example of the \emph{polymorphic} mode. This mode can be +explicitly requested by writing \oc|polymorphic = true| as part of the +\derivingvisitors annotation. It is available for all varieties of visitors +except \fold and \foldtwo. The reason why it seems difficult to come up with +a satisfactory polymorphic type for \fold visitor methods is explained later +on (\sref{sec:map_from_fold}). + +In \fref{fig:expr_info_polymorphic}, we again have arithmetic expressions +where every tree node is decorated with a value of type \oc|'info|. We again +request a \map visitor but, this time, we specify \oc|polymorphic = true|. +% +In order to make the generated code shorter, we specify \oc|data = false| +(\sref{sec:params}), which causes the methods \dataconvisitor{EConst} and +\dataconvisitor{EAdd} to disappear. (They are inlined at their call sites.) + +The generated code is the same as in the previous section, +% except the methods \dataconvisitor{EConst} and \dataconvisitor{EAdd} have +% disappeared, as explained above, and +except that \tyconvisitor{'info} is not a method any more. Instead, it is +a function, which is passed as an argument to every visitor method. + +% Because \tyconvisitor{'info} is a function, as opposed to a virtual method, +The class \map does not have any virtual methods. It can thus be declared as +concrete class: to this end, we specify +% +\oc|concrete = true| (\sref{sec:params}). Without this indication, it would be +declared \oc|virtual|. + +Because \tyconvisitor{'info} is an argument of every visitor method, +every visitor method can be declared polymorphic in the type variables~\oc|'env|, +\oc|'info_0| and \oc|'info_1|, +where the function \tyconvisitor{'info} has type \oc|'env -> 'info_0 -> 'info_1|. +% +The fact that we would like every method to have a polymorphic type cannot +be inferred by OCaml. For this reason, the generated code contains explicit +polymorphic type annotations. + +\fref{fig:expr_info_polymorphic_use} presents two example uses of the class +\map defined in \fref{fig:expr_info_polymorphic}. As in +\fref{fig:expr_info_use}, we define two functions \oc|strip| and \oc|number|. +A striking feature of this code is that a single visitor object~\oc|v| is now +allocated, once and for all, and is used in every subsequent call to \oc|strip| +and \oc|number|. The two \tyconvisitor{'info} functions are also defined once +and for all.% +% +\footnote{Although we have nested these functions inside the definitions of + \oc|strip| and \oc|number|, they are closed, so they could be hoisted out to + the top level, if desired.} + +In the definition of \oc|number|, we choose to store the current count in a +reference, \oc|count|, and to let \oc|count| play the role of the +``environment''. Thus, we initially pass \oc|count| to \tyconvisitor{expr}, +and \tyconvisitor{'info} receives \oc|count| as its ``environment'' argument. + +%% + +The polymorphic type annotations that are automatically generated +(\fref{fig:expr_info_polymorphic}) follow a certain fixed convention. If the +user throws in hand-written visitor methods via the \ancestors parameter, then +those hand-written methods must adhere to the same convention (or the +generated code would be ill-typed). This convention is illustrated in the next +section (\sref{sec:intro:nonlocal}) with the example of the +\tyconvisitor{list} methods. + +A type variable is not allowed to occur under an \oc|[@opaque]| annotation +(\sref{sec:opaque}). Indeed, annotating a type variable~\oc|'a| with +\oc|[@opaque]| would cause special-purpose visit code to be generated, whose +type is not as polymorphic as required by the above convention. + +%% + +% We might wish to document that the type variable names \oc|'s| and \oc|'env| +% are reserved. + +% ------------------------------------------------------------------------------ + +% At the moment, the following feature is considered experimental and +% undocumented: + +\begin{comment} + +\subsubsection{Mixing the monomorphic and polymorphic modes} +\label{sec:intro:parameterized:fine} + +It is possible to mix the monomorphic and polymorphic modes +(\sref{sec:intro:parameterized:mono}, \sref{sec:intro:parameterized:poly}) in +a single generated visitor class. Suppose we wish to generate a visitor class +for the type \oc|('a, 'b) dictionary|. Suppose, for some reason, that we would +like \tyconvisitor{'a} to be a virtual visitor method and \tyconvisitor{'b} to +be a visitor function, which is passed as an argument to +\tyconvisitor{dictionary}. This can be achieved by declaring +% +\oc|polymorphic = ["'b"]| as part of the \derivingvisitors annotation. + +% The user can control whether the visitor methods are polymorphic in \oc|'env|. +% This is done by including (or not including) \oc|'env| in the list. +% (The type variable \oc|'env| is reserved.) + +\end{comment} + +% ------------------------------------------------------------------------------ + +\begin{figure}[t] +\orig{expr11} +\vspace{-\baselineskip} +\processed{expr11} +\caption{Using preexisting (parameterized) types, such as \oc|int| and \oc|list|} +\label{fig:expr11} +\end{figure} + +\input{convention} + +\subsection{Dealing with references to preexisting types} +\label{sec:intro:nonlocal} + +A type definition can contain references to the types that are being defined, +also known as \emph{local} types. For instance, in \fref{fig:expr00}, the +definition of \oc|EAdd| contains two references to a local type, namely +\oc|expr|. + +A type definition can also contain references to preexisting types, also +known as \emph{nonlocal} types. For instance, in \fref{fig:expr00}, the +definition of \oc|EConst| contains a reference to a nonlocal type, namely +\oc|int|, which happens to be one of OCaml's primitive types. In +\fref{fig:expr11}, the definition of \oc|EAdd| contains a reference to a +parameterized nonlocal type, namely \oc|list|, which happens to be defined in +OCaml's standard library. + +The treatment of local types has been illustrated in the previous sections. In +short, for every local type, a visitor method is called, and is defined: +for instance, for the local type \oc|expr|, we define the (concrete) method +\tyconvisitor{expr}. + +The treatment of nonlocal types is the same, except the visitor method is not +defined, nor declared. That is, it is called, but is neither defined (as a +concrete method) or declared (as a virtual method). Therefore, its definition +must be provided by an ancestor class. + +For most of OCaml primitive or built-in types, support is provided by the +module \oc|VisitorsRuntime|. This module contains several classes named +\oc|iter|, \oc|map|, and so on; each of them supplies methods named +\tyconvisitor{int}, \tyconvisitor{list}, and so on.% +% +\footnote{As an exception to this rule, the classes \runtime{fold} + and \runtime{fold2} do not supply any methods, because we do not + wish to prematurely fix the types of the visitor methods. Please consult + \srcFile{VisitorsRuntime.ml} to check which methods exist and what they + do.} % +% +As is evident in Figures~\ref{fig:expr00}, \ref{fig:expr01}, and so on, the +generated visitor automatically inherits from the appropriate class in +\oc|VisitorsRuntime|, so it receives default implementations of the methods +\tyconvisitor{int}, \tyconvisitor{list}, and so on. + +The visitor methods for parameterized data types (\oc|array|, \oc|Lazy.t|, +\oc|list|, \oc|option|, \oc|ref|, \oc|result|) are polymorphic, so it is not a +problem if both lists of apples and lists of oranges need to be traversed. +The types of these methods follow a strict \emph{convention}, +illustrated in \fref{fig:convention} with the example of \tyconvisitor{list}. + +The \tyconvisitor{list} methods in the classes \runtime{iter}, \runtime{map}, +and so on, have been hand-written, but could equally well have been generated, +with \oc|polymorphic = true|: their types would be the same. +% +% The code would not be the same. At the moment, we are using List.fold_left +% instead of a natural fold. +% +This illustrates the fact that, with \oc|polymorphic = true|, +\emph{visitors are compositional}. +% +% With \oc|polymorphic = false|, visitors are compositional, too, +% but only for non-parameterized types. +% +That is, if the definition of the type \oc|'b bar| refers to the type \oc|'a foo|, +then one can \emph{separately} generate a visitor class for \oc|'a foo| +and generate a visitor class for \oc|'b bar|, which inherits the previous class. +% There is no need to generate a single visitor class for \oc|'a foo| and +% \oc|'b bar| at once. + +At a primitive type, it is advisable to carefully consider what +behavior is desired. On the one hand, perhaps the inherited method +\tyconvisitor{int} need not be invoked in the first place; this behavior can +be obtained by using \oc|(int[@opaque])| instead of \oc|int|. (See +\sref{sec:opaque} for details.) This is done, for instance, in +\fref{fig:expr15}, where one can check that no call to \tyconvisitor{int} is +generated. On the other hand, when one decides to use an inherited method, one +should make sure that one understands its behavior. The methods +\tyconvisitor{array} and \tyconvisitor{ref} in the class +\runtime{map}, for instance, perform a copy of a mutable memory +block: one should be aware that such a copy is taking place. If this behavior +is undesirable, it can be overridden. + +It is possible to inherit as many classes as one wishes, beyond those defined +in \oc|VisitorsRuntime|. This is done via the \ancestors parameter +(\sref{sec:ancestors}). It is also possible to \emph{not} inherit any methods +from \oc|VisitorsRuntime|. This is done via the \nude parameter +(\sref{sec:ancestors}). + +% ------------------------------------------------------------------------------ + +\subsection{Generating visitors for preexisting types} +\label{sec:import} + +Because the \derivingvisitors annotation must be attached to the type +definition, it may seem as if it is impossible to generate a visitor for a +type whose definition is out of reach. Suppose, for instance, that the type +\oc|expr| of arithmetic expressions is defined in a module \oc|Expr|, which, +for some reason, we cannot modify. Can we generate a visitor for this type? + +Fortunately, the answer is positive. The basic trick, documented in the +\href{https://github.com/whitequark/ppx_deriving/#working-with-existing-types} +{\texttt{ppx\_deriving} \textsc{readme}}, +consists in defining a new type \oc|expr| of arithmetic expressions and to +explicitly declare that it is equal to the preexisting type \oc|Expr.expr|, +as follows. + +\orig{expr_redef} + +As can be seen above, the new definition of \oc|expr| can be annotated with +\derivingvisitors, yielding a visitor for the new type \oc|expr|, which by +definition, is equal to the preexisting type \oc|Expr.expr|. Thus, this +visitor class be used to traverse expressions of type \oc|Expr.expr|. + +This approach works, but requires repeating the definition of the type \oc|expr|. +This duplication can be eliminated thanks to the \ppximport syntax extension, +as follows: + +\orig{expr_import} + +This expands to the code shown previously. (To use this syntax extension, +assuming you are using \ocamlbuild and \ocamlfind, just add the line +\texttt{true: package(ppx\_import)} to your \texttt{\_tags} file.) As icing on +the cake, \ppximport allows decorating the type definition, on the fly, with +new attributes. In the following examples, we replace all occurrences of +\oc|int| with \oc|int[@opaque]| (\sref{sec:opaque}), so as to ensure that the +generated visitor does not invoke the method \tyconvisitor{int}: + +\orig{expr_import_opaque} + +% ------------------------------------------------------------------------------ +% ------------------------------------------------------------------------------ + +\section{Advanced examples} +\label{sec:advanced} + +% ------------------------------------------------------------------------------ + +\begin{figure}[p] +\orig{expr12} +\vspace{-\baselineskip} +\processed{expr12} +\caption{An open type of arithmetic expressions} % and a visitor for it +\label{fig:expr12} +\end{figure} + +\begin{figure}[p] +\codefollowup{expr12} +\origfirstline{expr13}{3} +\caption{A closed type of arithmetic expressions} +\label{fig:expr13} +\end{figure} + +\begin{figure}[p] +\codefollowup{expr12} +\origfirstline{expr08}{3} +\caption{A closed type of hash-consed arithmetic expressions} +\label{fig:expr08} +\end{figure} + +\subsection{Visitors for open and closed data types} +\label{sec:advanced:openclosed} + +The algebraic data types of arithmetic expressions shown in the previous +section (\sref{sec:intro}) are \emph{closed}. That is, the type \oc|expr| +is recursive: an expression of type \oc|expr| has subexpressions of type +\oc|expr|. + +It is often desirable, for greater flexibility, to first define an \emph{open} +type of arithmetic expressions. Such a type, say \oc|oexpr|, is parameterized +over a type variable~\oc|'expr|. It is not recursive: an expression of type +\oc|'expr oexpr| has subexpressions of type \oc|'expr|. It is shown in +\fref{fig:expr12}. Naturally, we may request the generation of visitors for +the type \oc|oexpr|. In \fref{fig:expr12}, we generate a class of \map +visitors, which we name \oc|omap|. (This is an example of using an explicit +\name parameter.) As explained earlier (\sref{sec:intro:parameterized:mono}), +because the type \oc|oexpr| is parameterized over the type variable +\oc|'expr|, the visitor class has a virtual method, \tyconvisitor{'expr}. +% +In this example, we use the monomorphic mode (\sref{sec:intro:parameterized:mono}), +but could just as well use the polymorphic mode (\sref{sec:intro:parameterized:poly}): +this is left as an exercise for the reader. + +A closed (recursive) type of expressions, \oc|expr|, can then be defined in +terms of \oc|expr|. This is done in \fref{fig:expr13}. In type-theoretical +terms, one would like to define \oc|expr| as the fixed point of the functor +\oc|oexpr|~\cite{milewski-13}. +% +That is, roughly speaking, one would like to define \oc|type expr = expr oexpr|. +This is not accepted by OCaml, though;% +% +\footnote{It would be accepted by OCaml with the command line switch + \texttt{-rectypes}, which instructs the typechecker to tolerate + equirecursive types. However, this is not a good idea, as it causes + the typechecker to suddenly accept many meaningless programs and infer + bizarre types for them.} +% +we work around this limitation by making \oc|expr| an algebraic data type +whose single data constructor is named~\oc|E|.% +% +\footnote{We mark this algebraic data type \oc|[@@unboxed]|, which (as of + OCaml 4.04) guarantees that there is no runtime cost associated with the + data constructor~\oc|E|. Although \oc|expr| and \oc|expr oexpr| are + considered distinct types by the OCaml typechecker, they have the same + runtime representation.} + +Let us now construct a visitor class for the type \oc|expr|. It is easy to +do so, by hand, in a few lines of code.% +% +% \footnote{We could request the generation of a visitor class via a +% \oc|[@@deriving]| annotation. However, the type \oc|oexpr| would then be +% viewed as nonlocal; therefore, in the generated code, the method +% \tyconvisitor{oexpr} would be applied to \oc|self#visit_expr|, a +% parameter which it does not expect.} +% +% Also, we would have to inherit from \oc|omap|, but that would cause us +% to inherit twice from \runtime{map}, causing warnings. +% +We define a class \oc|map|, a subclass of \oc|omap|, and provide a concrete +implementation of the virtual method \tyconvisitor{'expr}. In the definition +of the type \oc|expr|, the type variable \oc|'expr| is instantiated with +\oc|expr|, so the method \tyconvisitor{'expr} expects an argument of type +\oc|expr| and must return a result of type \oc|expr|. We deconstruct the +argument using the pattern \oc|E e|. Therefore, the variable \oc|e| has type +\oc|expr oexpr| and is a suitable argument to the method \tyconvisitor{oexpr}. +After this call, we perform the same step in reverse: the result of the call +has type \oc|expr oexpr|, so we wrap it in an application of the data +constructor~\oc|E| and obtain a result of type \oc|expr|. + +The visitor class \oc|map| can now be used to implement transformations of +arithmetic expressions, that is, functions of type \oc|expr -> expr|. As an +example, let us implement a transformation whose effect is to double every +integer constant in an arithmetic expression. This is done in +\fref{fig:expr13double}. As expected, it suffices to construct a visitor +object that inherits \oc|map| and overrides the method +\dataconvisitor{EConst}. + +% ------------------------------------------------------------------------------ + +\begin{figure}[p] +\codefollowupgeneral{Figures~\ref{fig:expr12} and \ref{fig:expr13}} +\origfirstline{expr13double}{4} +\caption{A transformation of ordinary arithmetic expressions} +\label{fig:expr13double} +\end{figure} + +\begin{figure}[p] +\codefollowupgeneral{Figures~\ref{fig:expr12} and \ref{fig:expr08}} +\origfirstline{expr08double}{4} +\caption{A transformation of hash-consed arithmetic expressions} +\label{fig:expr08double} +\end{figure} + +\begin{figure}[p] +\codefollowupgeneral{Figures~\ref{fig:expr12}, \ref{fig:expr13}, and~\ref{fig:expr08}} +\origfirstline{expr14}{6} +\caption{Conversions between ordinary and hash-consed arithmetic expressions} +\label{fig:expr14} +\end{figure} + +\subsection{Visitors for hash-consed abstract syntax trees} +\label{sec:advanced:hashconsed} + +On top of the open data type \oc|oexpr| of the previous section +(\sref{sec:advanced:openclosed}), one can define not just the closed data type +\oc|expr| of ordinary arithmetic expressions, but also other closed data types +of expressions where every node is annotated with information. + +As an example, let us define a type \oc|hexpr| of hash-consed (that is, +maximally-shared) arithmetic expressions. We use Filliâtre and Conchon's +library~\cite{filliatre-conchon-06}, which can be found in \opam under the +name \hashcons. + +The definition of the type \oc|hexpr| appears in \fref{fig:expr08}. It is +analogous to the definition of the type \oc|expr| (\fref{fig:expr13}), with an +added twist: instead of taking the fixed point of the functor \oc|_ oexpr|, we +take the fixed point of the functor \oc|_ oexpr hash_consed|. By looking up +the definition of the type \oc|hash_consed| in \hashconsRepoFile{hashcons.mli}, +one finds that this means that every node in an arithmetic expression carries +certain information (namely a unique tag and a hash) that are used to enforce +maximal sharing. + +Enforcing maximal sharing requires maintaining a mutable table where all +arithmetic expressions ever constructed are stored. (This is in fact a weak +hash table.) We initialize such a table by calling the function +\oc|Hashcons.create|. This table is then populated by the function \oc|h|, a smart +constructor. +% of type \oc|hexpr oexpr -> hexpr|. +This function takes a candidate expression of type \oc|hexpr oexpr| and +returns an expression of type \oc|hexpr|, which is either allocated anew +or found in the table (should an identical expression already exist). + +We can now construct a visitor class for the type \oc|hexpr|. As in the previous +section (\sref{sec:advanced:openclosed}), we do so by hand in a few lines of code. +% +% Our reasons for writing this code by hand are the same as in the previous +% section. Furthermore, we note that the code of the visitor refers to the +% function~\oc|h|, thus depends on \oc|table|. The definition of \oc|table| +% itself must come after the definition of the type \oc|hexpr|, since the +% type of \oc|table| is \oc|hexpr oexpr Hashcons.t|. For this reason, we +% cannot use [@@deriving] to generate the visitor just after the type +% definition. +% +% That said, since the visitor depends on \oc|h| and not directly on \oc|table|, +% we could cut the dependency by going through the store. Create a reference to +% a function of type \oc|hexpr oexpr -> hexpr|. Initialize it with a dummy +% function. Generate the visitor. Then, create the table, define \oc|h| and +% update the reference. Ugh. +% +The overall structure of this code is the same as in \fref{fig:expr13}. The +only difference is that the method \tyconvisitor{'expr} must now traverse +two levels of type structure, corresponding to \oc|_ oexpr hash_consed|. +It deconstructs this structure by using the pattern \oc|H { node = e ; _ }|,% +% +\footnote{The \oc|node| field is part of the record type \oc|hash_consed|; +see \hashconsRepoFile{hashcons.mli}.} +% +and reconstructs it by applying the smart constructor~\oc|h|. + +A function \oc|double| can be defined for hash-consed arithmetic expressions +in exactly the same manner as we defined \oc|double| for ordinary arithmetic +expressions: compare \fref{fig:expr13double} and \fref{fig:expr08double}. +% +% In fact, although we did not attempt to share the code of the method +% \dataconvisitor{EConst} between these two figures, one could do so if +% desired, by exploiting multiple inheritance. +% + +The visitor class \oc|omap| for open arithmetic expressions +(\fref{fig:expr12}) can be exploited to define conversions +between different types of arithmetic expressions. +This is illustrated in \fref{fig:expr14}. +There, the function \oc|import| converts an ordinary expression +to a hash-consed expression, thereby imposing maximal sharing. +Conversely, the function \oc|export| converts a hash-consed +expression into an ordinary expression, thereby abandoning +all sharing (and possibly causing an exponential explosion). +The implementation of these functions is simple: it is just +a matter of overriding \tyconvisitor{'expr} so as to deconstruct +one kind of expression and reconstruct the other kind. + +% ------------------------------------------------------------------------------ + +\subsection{From visitors to iterators} +\label{sec:iterators} + +It is possible to use a visitor to implement an iterator, that is, an object +that traverses a container data structure and produces its elements on demand. +The story is told in a blog post~\cite{iterators}. + +% ------------------------------------------------------------------------------ +% ------------------------------------------------------------------------------ + +\section{Little-known aspects of OCaml objects} +\label{sec:oo} + +In this section, we document a few relatively little-known aspects of OCaml's +class and object system that play an essential role in our visitors. + +% ------------------------------------------------------------------------------ + +\subsection{Type inference for concrete and virtual methods} +\label{sec:oo:infer} + +It is well-known that OCaml can infer the type of a concrete method. In the +following simple example, it infers that the field \oc|x| has type \oc|int| +and that (therefore) the methods \oc|get| and \oc|set| must have types +\oc|int| and \oc|int -> unit|, respectively: +% +\orig{OOinfer} + +It is perhaps lesser known that \emph{OCaml can also infer the type of a + virtual method}, based on the manner in which this method is used. In the +following variant of the previous example, it infers that the method +\oc|check| must have type \oc|int -> int|, as it receives an integer argument +and produces a result that is stored in the field \oc|x|. +% +\orig{OOinfervirtual} + +The type annotation \oc|_| that appears in the declaration of the method +\oc|check| stands for an unconstrained type variable. It lets the OCaml +typechecker infer a most general monomorphic type for this method. +A~polymorphic type cannot be inferred. If we wished for the method \oc|check| +to have type \oc|'a . 'a -> 'a|, then we would have to explicitly annotate the +declaration with this polymorphic type. + +% ------------------------------------------------------------------------------ + +\subsection{Virtues of self-parameterized classes} +\label{sec:oo:self} + +Popular belief holds that inferring a method's type fails if ``some type +variables are unbound in this type''. For instance, in the following variant +of the previous example, OCaml infers that the method \oc|check| has type +\oc|'a -> int|, where the type variable \oc|'a| is unconstrained: +% +\orig{OOinfererror} + +At that point, it fails with a type error message: +% +\begin{mdframed}[backgroundcolor=red!10] +\begin{lstlisting}[keywords={}] +Error: Some type variables are unbound in this type: + class virtual int_cell : + object + val mutable x : int + method virtual check : 'a -> int + method get : int + method set : 'a -> unit + end +The method check has type 'a -> int where 'a is unbound +\end{lstlisting} +\end{mdframed} + +In this case, the OCaml manual says, ``the class should be parametric'', and +``the type parameters must be [subject] somewhere in the class body to a type +constraint''. In the above example, one might choose to parameterize the class +over a type variable~\oc|'a| and to add a type annotation that requires +\oc|'a| to be the domain of the virtual method \oc|check|: +% +\orig{OOinferfixed} + +This eliminates the type error: this code is well-typed. One problem with this +approach, though, is that further changes to the code might require +introducing further type parameters. Suppose for instance that, instead of +initializing the field~\oc|x| with the value \oc|0|, we wish to parameterize +the class over an initial value~\oc|init|. We modify the code as follows: +% +\orig{OOinfererroragain} + +Unfortunately, this modification makes the code ill-typed again: +% +\begin{mdframed}[backgroundcolor=red!10] +\begin{lstlisting}[keywords={}] +Error: Some type variables are unbound in this type: + class virtual ['a] cell : + 'b -> + object + val mutable x : 'b + method virtual check : 'a -> 'b + method get : 'b + method set : 'a -> unit + end +The method check has type 'a -> 'b where 'b is unbound +\end{lstlisting} +\end{mdframed} + +A natural reaction to this type error message might be to parameterize the +class over both \oc|'a| and \oc|'b|, as follows: +% +\orig{OOinferfixedagain} + +This eliminates the type error: this code is well-typed. However, it seems +unfortunate that one cannot depend on the typechecker to infer the types of +all methods. Instead, it seems that one must introduce an unpredictable number +of type parameters, as well as an unpredictable amount of explicit type +annotations, for the code to be accepted. + +Fortunately, there is a solution to this problem. + +Let us first note that, in the above example, even though both the argument +type and result type of the method \oc|check| are undetermined, \emph{it is + not necessary to introduce two type parameters} \oc|'a| and~\oc|'b|. Indeed, +one type parameter suffices, provided this parameter determines both the +argument type and result type of \oc|check|. To illustrate this, let us +parameterize the class over a type variable \oc|'check|, and provide a type +annotation that equates \oc|'check| with the type of the method \oc|check|: +% +\orig{OOinferfixedagaincheck} + +This code is well-typed, too. Its inferred type is as follows: +% +\begin{mdframed}[backgroundcolor=green!10] +\begin{lstlisting} +class virtual ['check] cell : + 'b -> + object + constraint 'check = 'a -> 'b (* a type equation *) + val mutable x : 'b + method virtual check : 'check + method get : 'b + method set : 'a -> unit + end +\end{lstlisting} +\end{mdframed} + +Because the typechecker infers and records the type equation % +\oc|'check = 'a -> 'b|, instantiating the type variable~\oc|'check| with a +concrete type suffices to determine the values of both~\oc|'a| and~\oc|'b|. +For instance, if~\oc|'check| is instantiated with \oc|float -> int|, then +\oc|'a| must be \oc|float| and \oc|'b| must be \oc|int|. For this reason, +there is no need to parameterize the class over \oc|'a| and~\oc|'b|. +Parameterizing it over \oc|'check| suffices. + +This remark alone does not quite solve our problem yet. It still seems as if, +for a class definition to be accepted, one must introduce an unpredictable +number of type parameters, as well as an unpredictable amount of explicit type +annotations and/or type equations. + +Fortunately, there is a general way out of this problem. In fact, \emph{one + type parameter always suffices}. The trick is to constrain this type +parameter to be the type of ``self''. Indeed, in OCaml, the type of ``self'' +is an OCaml object type that lists the names and types of all (public) +methods. Therefore, fixing the type of ``self'' is enough to determine the +type of every method. + +% A curious remark: even though the private methods do not appear in the type +% of self, OCaml still allows their types to contain unconstrained type +% variables. For instance, the following is allowed, with and without +% self-parameterization: +% +% class virtual foo = object +% method private virtual f: _ +% end +% +% class virtual ['self] foo = object (_ : 'self) +% method private virtual f: _ +% end + +We modify the example as follows. We parameterize the class over a single type +variable, named \oc|'self|, which we constrain to be the type of ``self'', via +the type annotation \oc|self : 'self|. +% +\orig{OOinferself} + +Even though, this time, we have not given the type of the method \oc|check|, +this code is well-typed. \emph{In~a self-parameterized OCaml class, a + monomorphic type can be inferred for every method}, be it concrete or +virtual. In other words, in~a self-parameterized class, the OCaml typechecker +never complains that ``some type variables are unbound''. + +In the \visitors package, this remark solves several problems. First, we never +need to wonder how many type parameters a class should have, and what they +should be: the answer is always one, namely \oc|'self|. Second, we never need +to annotate a method with its type: every virtual method can be annotated with +the wildcard \oc|_|. These properties are of utmost importance, as we cannot +in general predict the types of the generated methods. + +Since self-parameterized classes seem so great, one may wonder whether, in +everyday life, it would be a good idea to parameterize every class over +\oc|'self| in this manner. The answer is, it probably would not. Such an +approach leads to verbose class types, as the type of ``self'' contains a list +of all (public) methods. It also gives rise to recursive object types, of the +form \oc|'self c as 'self|, where \oc|c| is a class. + +% ------------------------------------------------------------------------------ + +\subsection{Simplifying the type of a self-parameterized class} +\label{sec:oo:monomorphic} + +We have used in \sref{sec:intro:type} a few rules that allow an inferred class +type to be manually simplified. In going from \fref{fig:inferred} to +\fref{fig:simplified}, we have used the well-known property that private +methods can be omitted in a class type. We have also exploited the perhaps +lesser-known fact that, in a self-parameterized class, the constraint that +bears on the type parameter \oc|'self| can be omitted, as it is implicit in +OCaml that the type of ``self'' must be an object type that lists the public +methods. + +There remains to explain the surprising use of the ``\oc|'monomorphic.|'' prefix +in \fref{fig:simplified}. On the face of it, this is a universal +quantification over a type variable, named \oc|'monomorphic|, which does +\emph{not} appear in the type of the method. From a purely logical standpoint, +such a universal quantification should be superfluous. Yet, here, it is +required, due to the following peculiarity of OCaml~\cite{ocaml7465}: +\begin{quote} + In a class type, + if the type of a method exhibits a free variable~\oc|'a|, + if this method type has no explicit universal quantifiers, + and if the type variable~\oc|'a| does not appear in an explicit type constraint, + then, by convention, + OCaml considers that the method type is universally quantified in \oc|'a|. + % Personal communication with Jacques Garrigue. + % https://caml.inria.fr/mantis/view.php?id=7465 +\end{quote} +We must work around this syntactic convention: in \fref{fig:inferred}, for +instance, the method \tyconvisitor{expr} has monomorphic type % +\oc|'env -> expr -> unit|, where the type variable \oc|'env| is connected with +\oc|'self| via an implicit constraint and (like \oc|'self|) is quantified at +the level of the class. This method does \emph{not} have polymorphic type % +\oc|'env. 'env -> expr -> unit|. The logically redundant quantification over +\oc|'monomorphic| serves as a syntactic mark that we really intend the type +variable~\oc|'env| to appear free in the method type. + +% ------------------------------------------------------------------------------ + +\subsection{Monomorphic methods, polymorphic classes} + +Even if a method is monomorphic, the class that contains this method can be +polymorphic. In the following example, the \oc|identity| method is annotated +with a monomorphic type, which implies that, if \oc|o| is an object of +class~\oc|c|, then the method \oc|o#identity| cannot be applied both to apples +and to oranges. However, the class~\oc|c| is polymorphic, which means that two +distinct instances of this class can be used (separately) with apples and with +oranges. +\begin{origenv} +\lstinputlisting{polyclass.ml} +\end{origenv} +This (well-known) property of classes is exploited in the \visitors package. +Although (in monomorphic mode, \sref{sec:intro:parameterized:mono}) every +generated visitor method is monomorphic, the visitor classes are +polymorphic, so (distinct) visitor objects can be used at many different +types. + +% ------------------------------------------------------------------------------ + +% This subsection is mostly obsolete now that we have [polymorphic] mode, +% so I am removing it. + +\begin{comment} + +\subsection{Customization from above and from below} + +In the object-oriented world, a traditional way of ensuring that a piece of +code has customizable behavior is to write it in the form of a class with many +(concrete or virtual) methods. These methods can later be overridden in a +subclass: this is ``customization from below''. + +When the class is automatically generated, as is the case of our visitor +classes, another approach to customization is to let the user choose which +classes should be inherited: this is done via the \ancestors parameter +(\sref{sec:params}). This is ``customization from above''. It is a somewhat +more unusual customization mechanism. + +As the (concrete and virtual) methods that we generate must be monomorphic, +customization from below is restricted, in our situation, to providing +monomorphic code fragments. Fortunately, no such restriction bears on +customization from above: a parent class can provide (hand-written) +polymorphic methods. + +For this reason, customization from above plays a key role in our setting. For +instance, the methods \oc|visit_array|, \oc|visit_list|, and so on, which must +be polymorphic, must be hand-written, and must be inherited from a parent +class. The asymmetry between hand-written methods (which may be polymorphic) +and generated methods (which must be monomorphic) is admittedly unfortunate, +but this is the best that we offer, at present. + +\end{comment} + +% ------------------------------------------------------------------------------ + +\subsection{Where the expressiveness of OCaml's type system falls short} +\label{sec:map_from_fold} + +\begin{figure}[p] +\orig{map_from_fold} +\caption{An unsatisfactory definition of \oc|map| as a subclass of \oc|fold|} +\label{fig:map_from_fold} +\end{figure} + +\begin{figure}[p] +\begin{mdframed}[backgroundcolor=green!10] +\lstinputlisting{map_from_fold.mli} +\end{mdframed} +\caption{The type of the class \oc|map_from_fold| (\fref{fig:map_from_fold})} +\label{fig:map_from_fold:type} +\end{figure} + +We have noted earlier (\sref{sec:intro:fold}) that, among the varieties of +visitors that we have presented, \fold visitors are in principle the most +general. This raises the question: is it possible to define \map and \reduce +as subclasses of \fold, equipped with appropriate \tyconascendingmethod{} +methods? + +Doing so would be more economical: that is, it would significantly reduce the +redundancy between the classes \map, \reduce, and \fold. When these classes +are automatically generated, code duplication is not so much of a problem. +However, there are situations where (parts of) visitor classes must be +hand-written, and where duplication becomes painful. + +Furthermore, defining \map and \reduce as subclasses of \fold would give rise +to new patterns of customization. It would become possible to define a +subclass of \map or \reduce and override just one \tyconascendingmethod{} +method so as to obtain custom behavior.% +% +\footnote{At present, this must be done by overriding a + \tyconvisitor{} method, thereby causing more code duplication than + necessary.} + +In an untyped setting, the question can be answered positively: \map and +\reduce can be defined in terms of \fold. Unfortunately, in the setting +of OCaml's type system, the answer is negative: although \reduce can be +defined in terms of \fold, \map cannot. +% (or cannot always). + +The situation is illustrated in \fref{fig:map_from_fold}. As an example, we +define visitor methods, by hand, for the type \oc|'a option|. + +The methods \tyconvisitor{option} in the classes \reduce and \map are +identical to those found in the classes \runtime{reduce} and \runtime{map}. We +note that the method \tyconvisitor{option} in the class \reduce is polymorphic +in \oc|'a|, whereas \tyconvisitor{option} in the class \map is polymorphic +in~\oc|'a| and~\oc|'b|. + +There is some similarity between these methods, which is why we define a class +\fold, whose method \tyconvisitor{option} contains calls to the virtual +methods \dataconascendingmethod{None} and \dataconascendingmethod{Some}. We +assign to this method the most general type that is expressible in OCaml's +type system. It is polymorphic in \oc|'a|. The type variable~\oc|'r|, which +represents the result of the function~\oc|f|, and the type variable~\oc|'s|, +which represents the result of the methods \tyconvisitor{option}, +\dataconascendingmethod{None}, and \dataconascendingmethod{Some}, +cannot be universally quantified at the level of a method, +since they appear in the types of several methods. +They must be (implicitly) quantified at the level of the class. + +Is this definition of \fold satisfactory? To test this, let us now attempt to +propose new definitions of \reduce and \map as subclasses of \fold. We define +two more classes, \oc|reduce_from_fold| and \oc|map_from_fold|, which both +inherit \oc|fold| and provide suitable definitions of the methods +\dataconascendingmethod{None} and \dataconascendingmethod{Some}. + +In \oc|reduce_from_fold|, everything works fine. The type parameters \oc|'r| +and \oc|'s| in \fold are both instantiated with \oc|'z|. As a result, the +method \tyconvisitor{option} in the class \oc|reduce_from_fold| has type +% +\oc|'a. ('c -> 'a -> 'z) -> 'c -> 'a option -> 'z|, +% +just as in the class \reduce. + +In \oc|map_from_fold|, a problem arises. The code is well-typed, but its type +is less general than desired. The OCaml typechecker infers that the type +parameters \oc|'r| and \oc|'s| in \fold must be respectively instantiated with +\oc|'b| and \oc|'b option|, where the type variable \oc|'b| must be quantified +at the level of the class. Therefore, the type of \oc|map_from_fold| is as +shown in \fref{fig:map_from_fold:type}. This type is \emph{not} polymorphic +in~\oc|'b|, thus strictly less general than the type of the method +\tyconvisitor{option} in the class \map (\fref{fig:map_from_fold}). + +What would it take to repair this problem? Apparently, the type of the method +\tyconvisitor{option} in the class \fold is not general enough. Whereas the +type variables \oc|'r| and \oc|'s| currently have kind \oc|*|, it seems that +they should have kind \oc|* -> *|. The type of the class \fold should be as +follows: +% +\begin{mdframed}[backgroundcolor=green!10] +\begin{lstlisting} +class ['self] fold : object ('self) + method private visit_option: 'a 'b . + ('env -> 'a -> 'r['b]) -> 'env -> 'a option -> 's['b] + method private virtual build_None: 'b . 'env -> 's['b] + method private virtual build_Some: 'b . 'env -> 'r['b] -> 's['b] +end +\end{lstlisting} +\end{mdframed} + +This is not valid OCaml: we write \oc|'r[b]| for the type-level application of +\oc|'r| to \oc|'b|. The type of each method is universally quantified in +\oc|'b|, as desired. The type of \tyconvisitor{option} seems to have the +desired generality. By instantiating both~\oc|'r| and~\oc|'s| with the +type-level function \oc|fun 'b -> 'z|, we obtain the type of +\tyconvisitor{option} in the class \reduce. By instantiating \oc|'r| and +\oc|'s| with the type-level functions +% +\oc|fun 'b -> 'b| and \oc|fun 'b -> 'b option|, respectively, we obtain the +type of \tyconvisitor{option} in the class \map. + +This suggests that higher kinds, type-level functions, and type-level +$\beta$-reduction might be valuable features, not just in functional +programming languages, but also in an object-oriented programming setting. + +% ------------------------------------------------------------------------------ +% ------------------------------------------------------------------------------ + +\section{Reference} + +% ------------------------------------------------------------------------------ +% Parameters. + +\begin{figure}[p] +\renewcommand{\arraystretch}{1.5} +\begin{tabular}{@{}r@{\qquad}l@{\quad}p{.64\textwidth}@{}} + \ancestors & (list of strings) & + A list of classes that the generated class should inherit. + This is an optional parameter; its default value is the empty list. + The class \runtime{} is implicitly prepended to this list + 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 + concrete; otherwise, it is declared virtual. + This is an optional parameter; its default value is \texttt{false}. +\\ + \data & (Boolean) & + 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; + otherwise, it is enabled. + This is an optional parameter; its default value is \texttt{false}. +\\ + \name & (string) & + The name of the generated class. + This is an optional parameter; its default value is \oc||. +\\ + \nude & (Boolean) & + If \texttt{true}, the class \runtime{} is \emph{not} implicitly prepended to + the list \ancestors. + This is an optional parameter; its default value is \texttt{false}. +\\ + \polymorphic & (Boolean) & + If \texttt{true}, type variables are handled by virtual visitor methods, + and generated methods are monomorphic + (\sref{sec:intro:parameterized:mono}); + if \texttt{false}, type variables are handled by visitor functions, + and generated methods are polymorphic + (\sref{sec:intro:parameterized:poly}). + This is an optional parameter, whose default value is \texttt{false}. +\\ + \public & (list of strings) & + This is an optional parameter. + If absent, then every method in the generated class is declared public. + If present, then every method in the generated class is declared + private, except those whose name appears in the list: those are declared public. +\\ + \variety & (string) & + The variety of visitor that should be generated. + The supported varieties are + \iter (\sref{sec:intro:iter:def}), + \map (\sref{sec:intro:map}) and + \mapendo (\sref{sec:intro:endo}), + \reduce (\sref{sec:intro:reduce}), + \mapreduce (\sref{sec:intro:mapreduce}), + \fold (\sref{sec:intro:fold}), + \itertwo, + \maptwo, + \reducetwo, + \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 +\vspace{2.5mm} +\caption{Parameters of \derivingvisitors} +\label{fig:params} +\end{figure} + +\subsection{Parameters} +\label{sec:params} +\label{sec:ancestors} + +The parameters that can be passed as part of the \derivingvisitors annotation, +inside the curly braces, are described in \fref{fig:params}. + +% ------------------------------------------------------------------------------ + +\subsection{How to examine the generated code} + +The generated code is conceptually inserted into the user's source code just +after the type definition that is decorated with \derivingvisitors. + +It can be useful to inspect the generated code, so as to understand how it +works, what are the arguments and result of each method, and so on. This can +be especially useful when the generated code is ill-typed (which can happen, +for instance, when arbitrary user code is inherited via the \ancestors +parameter). + +The file \srcFile{Makefile.preprocess} offers a recipe that builds a file +named \verb|%.processed.ml| out of the source file \verb|%.ml|. This file contains +just the generated code. The recipe relies on \oc|sed|, \oc|perl|, and +\oc|ocp-indent| to extract and beautify the code. This file is installed +with the \visitors package; it can be found at the computed path +\verb+`ocamlfind query visitors`/Makefile.preprocess+. In a \texttt{Makefile}, +use the following directive: +\begin{verbatim} + include $(shell ocamlfind query visitors)/Makefile.preprocess +\end{verbatim} + +% ------------------------------------------------------------------------------ + +\subsection{Structure of the generated code} +\label{sec:structure} + +The \derivingvisitors annotation applies to a type definition. A type +definition may define several types, and these types may be parameterized. A +local type is one that is defined as part of this type definition, whereas a +nonlocal type is one that preexists (\sref{sec:intro:nonlocal}). + +The generated code consists of \emph{a single class}, whose name is \oc||, +that is, the value of the \variety parameter (\sref{sec:params}). This class +has \emph{one type parameter}, namely \oc|'self|, the type of ``self'' +(\sref{sec:oo:self}). It has no fields. It \emph{inherits} from the class +\runtime{} (unless the parameter \nude is \texttt{true}, \sref{sec:params}) +and from the classes listed via the \ancestors parameter (\sref{sec:params}), +in that order. To find out which methods exist in the class +\runtime{}, please consult \srcFile{VisitorsRuntime.ml}. + +In the following, the index~\oc|i| ranges from 0 (included) to \oc|| +(excluded), where \oc|| is the arity of the generated visitor (thus, +either 1 or 2). + +The following \emph{concrete methods} are \emph{defined}: +% +\begin{itemize} +\item for every local type \oc|??? foo|, a visitor method. + + \begin{tabular}{@{\qquad}rp{35mm}@{\quad}p{7cm}} + method name: & \tyconvisitor{foo} \\ + arguments: & \tyconvisitor{'a}, \ldots & a visitor function for each type param.\ of \oc|foo| \\ + & & (only if \oc|polymorphic = true|) \\ + & \oc|env| & an environment of type \oc|'env| \\ + & \oc|this_0|, \oc|this_1|, \ldots & for each \oc|i|, a value of type \oc|??? foo| \\ + invoked: & on the way down \\ + example: & \fref{fig:expr00} + \end{tabular} + +\item for every data constructor \oc|Foo| of a local sum type \oc|??? foo|, a visitor method. + + \begin{tabular}{@{\qquad}rp{35mm}@{\quad}p{7cm}} + method name: & \dataconvisitor{Foo} \\ + arguments: & \tyconvisitor{'a}, \ldots & a visitor function for each type param.\ of \oc|foo| \\ + & & (only if \oc|polymorphic = true|) \\ + & \oc|env| & an environment of type \oc|'env| \\ + & \oc|this| & a data structure of type \oc|??? foo| \\ + & & (only in an \mapendo visitor) \\ + & \oc|c0_0|, \oc|c0_1|, \ldots & for each \oc|i|, the first component of a \oc|Foo| value \\ + & \oc|c1_0|, \oc|c1_1|, \ldots & for each \oc|i|, the next component of a \oc|Foo| value \\ + & \ldots & \ldots and so on \\ + invoked: & on the way down \\ + example: & \fref{fig:expr00} + \end{tabular} + + If the parameter \data is \texttt{false}, then + this method is \emph{not} generated (\sref{sec:params}). + It is inlined instead. The behavior is the same, but cannot be overridden on + a per-data-constructor basis. + +\item if the visitor has arity two (\sref{sec:intro:aritytwo}), + for every local type \oc|foo|, + a failure method. + + \begin{tabular}{@{\qquad}rp{35mm}@{\quad}p{7cm}} + method name: & \tyconfail{foo} \\ + arguments: & \oc|env| & an environment of type \oc|'env| \\ + & \oc|this_0|, \oc|this_1|, \ldots & for each \oc|i|, a value of type \oc|??? foo| \\ + invoked: & \multicolumn{2}{l}{when two distinct data constructors \oc|Foo| and \oc|Bar| are found} \\ + example: & \fref{fig:expr02} + \end{tabular} + +\end{itemize} +% + +The following \emph{virtual methods} are \emph{declared}: +% +\begin{itemize} +\item for every type parameter \oc|'foo| of a local type, + a visitor method. (Only if \oc|polymorphic = true|.) + + \begin{tabular}{@{\qquad}rp{35mm}@{\quad}p{7cm}} + method name: & \tyconvisitor{'foo} \\ + arguments: & \oc|env| & an environment of type \oc|'env| \\ + & \oc|this_0|, \oc|this_1|, \ldots & for each \oc|i|, a value of type \oc|'foo| \\ + invoked: & on the way down \\ + example: & \fref{fig:expr_info} + \end{tabular} + +\item if this is a \reduce visitor (\sref{sec:intro:reduce}) + or a \mapreduce visitor (\sref{sec:intro:mapreduce}), + the monoid methods. + + \begin{tabular}{@{\qquad}rp{35mm}@{\quad}p{7cm}} + method name: & \oc|zero| \\ + arguments: & none \\ + result: & a summary \\ + example: & \fref{fig:expr15} + \end{tabular} + + \begin{tabular}{@{\qquad}rp{35mm}@{\quad}p{7cm}} + method name: & \oc|plus| \\ + arguments: & two summaries \\ + result: & a summary \\ + example: & \fref{fig:expr15} + \end{tabular} + +\item if this is a \fold visitor (\sref{sec:intro:fold}), + for every local record type \oc|foo|, + a build method. + + \begin{tabular}{@{\qquad}rp{35mm}@{\quad}p{7cm}} + method name: & \tyconascendingmethod{foo} \\ + arguments: & \oc|env| & an environment of type \oc|'env| \\ + & \oc|r_0| & the result of the first recursive call \\ + & \oc|r_1| & the result of the next recursive call \\ + & & \ldots and so on \\ + invoked: & on the way up \\ + example: & none in this document + \end{tabular} + +\item if this is a \fold visitor (\sref{sec:intro:fold}), + for every data constructor \oc|Foo| of a local sum type, + a build method. + + \begin{tabular}{@{\qquad}rp{35mm}@{\quad}p{7cm}} + method name: & \dataconascendingmethod{Foo} \\ + arguments: & \oc|env| & an environment of type \oc|'env| \\ + & \oc|r_0| & the result of the first recursive call \\ + & \oc|r_1| & the result of the next recursive call \\ + & & \ldots and so on \\ + invoked: & on the way up \\ + example: & \fref{fig:expr00fold} + \end{tabular} + +\end{itemize} + +The following methods are \emph{called}, therefore are expected to exist. +These methods are neither defined nor declared: their definition or +declaration must be inherited from a parent class. These methods can have a +polymorphic type. +% +\begin{itemize} +\item for every nonlocal type \oc|??? foo|, a visitor method. + + \begin{tabular}{@{\qquad}rp{35mm}@{\quad}p{7cm}} + method name: & \tyconvisitor{foo} \\ + arguments: & \oc|visit_0|, \ldots & for each actual type parameter in \oc|??? foo|, \\ + & & a visitor function for this type \\ + & \oc|env| & an environment of type \oc|'env| \\ + & \oc|this_0|, \oc|this_1|, \ldots & for each \oc|i|, a value of type \oc|??? foo| \\ + invoked: & on the way down \\ + example: & \fref{fig:expr11} + \end{tabular} + +\end{itemize} + +All of the above methods are parameterized with an environment \oc|env|, which +is propagated in a top-down manner, that is, into the recursive calls. The +environment is not returned out of the recursive calls, therefore not +propagated bottom-up or left-to-right. The type of this environment is +undetermined: it is a type variable. +% (which is implicitly related with \oc|'self|) +There is no a priori constraint that the type of the environment should be +the same in every method: it is possible for unrelated visitor methods to +expect environments of unrelated types. + +The result types of the visitor methods, build methods, and failure methods +depend on the parameter \variety (\sref{sec:params}). In an \iter visitor, +every method has result type \oc|unit|. In a \map or \mapendo visitor, the +visitor method associated with the type \oc|foo| has result type \oc|??? foo|.% +% +\footnote{The question marks \oc|???| stand for the type parameters of \oc|foo|, +which can be a parameterized type. In a \map visitor, the type parameters that +appear in the method's argument type and in the method's result type can differ. +In an \mapendo visitor, they must be the same.} +% +In a \reduce visitor, every method has result type \oc|'s|, if \oc|'s| is the +monoid, that is, if the methods \oc|zero| and \oc|plus| respectively have type \oc|'s| +and \oc|'s -> 's -> 's|. +% +In a \mapreduce visitor, the visitor method associated with the type \oc|foo| +has result type \oc|??? foo * 's|, if \oc|'s| is the monoid. +% +In a \fold visitor, it is up to the user to decide what the result types of +the visitor methods should be (subject to certain consistency constraints, +naturally). In particular, two visitor methods \tyconvisitor{foo} and +\tyconvisitor{bar} can have distinct result types; this is illustrated +in \fref{fig:fold}. + +% ------------------------------------------------------------------------------ + +\subsection{Supported forms of types} + +The following forms of type definitions are supported: +\begin{itemize} +\item Definitions of \emph{type abbreviations} (also known as type synonyms). +\item Definitions of \emph{record types}. \\ Mutable fields are supported. +\item Definitions of \emph{sum types} (also known as variant types and as algebraic + data types). \\ Data constructors whose arguments form an ``inline record'' are + supported. +\end{itemize} + +Definitions of abstract types and of extensible sum types are not supported. + +\label{sec:regularity} +% The regularity restriction. + +Definitions of \emph{parameterized types} are supported. In monomorphic mode +(\sref{sec:intro:parameterized:mono}), only \emph{\hbox{regular}} +parameterized types are permitted, whereas in polymorphic mode +(\sref{sec:intro:parameterized:poly}), arbitrary parameterized types are +permitted. +% +A parameterized type is regular if, within its own definition, it is applied +only to its formal parameters. For instance, the well-known definition of +lists is regular: + +\begin{origenv} +\begin{lstlisting} +type 'a list = +| [] +| (::) of 'a * 'a list +\end{lstlisting} +\end{origenv} +% +whereas the following definition of a random access +list~\cite[\S10.1.2]{okasaki-book-99} is not: +% +\begin{origenv} +\begin{lstlisting} +type 'a seq = +| Nil +| Zero of ('a * 'a) seq +| One of 'a * ('a * 'a) seq +\end{lstlisting} +\end{origenv} + +Irregular data types are also known as +``nonuniform''~\cite[\S10.1]{okasaki-book-99} or ``nested'' data +types~\cite{bird-meertens-98}. + +% The regularity check performed by the \visitors package in monomorphic mode +% can be disabled via the \irregular parameter (\sref{sec:params}). + +Existential types and generalized algebraic data types (GADTs) are currently +not supported. + +% Visiting an existential type seems problematic anyway, since we do not know +% how to descend into a value of unknkown type. Perhaps we could generate a +% default visitor method which treats the value as opaque, and allow the user +% to override this behavior if desired. + +% Visiting a GADT seems possible if the type parameters are used purely as +% indices (i.e., they are phantom parameters). In that case, we actually do +% not need visitor functions for the type parameters. + +In the right-hand side of a type definition, the following forms of types are +supported: +\begin{itemize} +\item Type constructors, possibly applied to a number of types, such as + \oc|foo| and \oc|('a * 'b) bar|. +\item Type variables, such as \oc|'foo|. +\item Tuple types, such as \oc|int * expr|. +\end{itemize} +The unsupported forms of types include +anonymous type variables (\oc|_|), +function types (\oc|int -> unit|), +object types (\oc|| and \oc|#point|), +recursive types (\oc|int -> 'a as 'a|), +polymorphic variant types (\oc+[ `A| `B ]+), +universal types (\oc|'a. 'a -> 'a|), +and +packaged module types (\oc|(module S)|). +If these forms appear in a type definition, +they must be marked \oc|@opaque| (\sref{sec:opaque}). + +In theory, at each arity, the tuple type constructor could be viewed as a +parameterized nonlocal type constructor. At arity 2, for instance, the pair +type \oc|'a * 'b| could be treated as a nonlocal type \oc|('a, 'b) tuple2|. +Then, to traverse a value of this type, one would invoke a method +\tyconvisitor{tuple2}, which necessarily would be inherited from a parent +class. That would be somewhat inconvenient, as these (polymorphic) methods +would have to be manually written, at each arity. Instead, special treatment +for tuple types is built-in. There are no visitor methods or build methods for +tuples; instead, ad hoc code is generated. This means that the behavior of a +visitor at a tuple type is fixed: it cannot be overridden in a subclass. The +behavior of a \fold visitor at a tuple type is to rebuild a tuple, just like a +\map visitor would do. + +% ------------------------------------------------------------------------------ + +\subsection{Opaque components} +\label{sec:opaque} + +One sometimes wishes for a component of a data structure \emph{not} to be +visited, either for efficiency reasons, or because this component is of an +unsupported type. This can be requested by annotating the type of this +component with the attribute \oc|[@opaque]|. This is done, for instance, if +\fref{fig:expr15}, where the integer argument of the data constructor +\oc|EConst| is marked opaque. (Note the parentheses, which are required.) The +effect of this annotation is that this component is not visited: in the method +\dataconvisitor{EConst}, instead of a call to \oc|self#visit_int|, we find a +call to \oc|self#zero|, as this is a \reduce visitor. + +Generating a visitor of arity two for a data structure with \oc|@opaque| +components requires some care. The methods \tyconvisitor{int} defined in the +classes \runtime{iter2}, \runtime{map2}, and so on, raise a +\oc|StructuralMismatch| exception when their two integer arguments differ. If +\oc|int| is replaced with \oc|(int[@opaque])|, then these methods are not +invoked, so no exception is raised. It is up to the user to decide which +behavior is desired. Furthermore, it should be noted that \maptwo and \foldtwo +visitors follow an arbitrary convention at \oc|@opaque| components: they +return the first of their two arguments. Again, it is up to the user to decide +whether this behavior is appropriate. + +In \polymorphic mode (\sref{sec:intro:parameterized:poly}), a type variable +must not occur under an \oc|[@opaque]| annotation. + +If desired, instead of \oc|[@opaque]|, one can use the more verbose forms +\oc|[@visitors.opaque]| and \oc|[@deriving.visitors.opaque]|. + +% ------------------------------------------------------------------------------ + +\subsection{Alternate method names} +\label{sec:name} + +The methods associated with the type \oc|foo| are normally named after this +type: this includes the visitor method \tyconvisitor{foo}, the build method +\tyconascendingmethod{foo}, +% (in \oc|fold| visitors) +and the failure method \tyconfail{foo}. +% (when the arity is 2) +This base name can be altered via an attribute. If \oc|foo| is a local type, +then a \oc|[@@name]| attribute must be attached to the declaration of this +type. If \oc|foo| is a nonlocal type, then a \oc|[@name]| attribute must be +attached to every reference to this type. For instance, in the following +example, +the visitor method associated with the type \oc|cloud| is named +\oc|visit_nuage| instead of \oc|visit_cloud|: +% +\begin{origenv} +\begin{lstlisting} +type cloud = + | Point of (float[@name "real"]) * (float[@name "real"]) + | Clouds of cloud list + [@@name "nuage"] + [@@deriving visitors { variety = "map"; ancestors = ["base"] }] +\end{lstlisting} +\end{origenv} +% +Furthermore, the visitor method associated with the type \oc|float| +(which is not generated, and should be inherited from the class \oc|base|) +is assumed to be named \oc|visit_real| instead of \oc|visit_float|. + +The methods associated with the data constructor \oc|Foo| are normally named +after it: this includes the visitor method \dataconvisitor{Foo} and the build +method \dataconascendingmethod{Foo}. +% +This base name can be altered via a \oc|[@name]| attribute, which must be +attached to the data constructor. For instance, in the following example, +the visitor methods associated with the data constructors \oc|[]| and \oc|::| +are named \dataconvisitor{nil} and \dataconvisitor{cons}: +% instead of \dataconvisitor{[]} and \dataconvisitor{::}, +% which would be invalid names: +% +\begin{origenv} +\begin{lstlisting} +type 'a mylist = 'a list = + | [] [@name "nil"] + | (::) of 'a * 'a mylist [@name "cons"] + [@@deriving visitors { variety = "map" }] +\end{lstlisting} +\end{origenv} +% +If desired, instead of \oc|[@name]|, one can use +\oc|[@visitors.name]| or \oc|[@deriving.visitors.name]|. + +% ------------------------------------------------------------------------------ + +\subsection{Alternate construction code in \map visitors} +\label{sec:build} + +By default, a \map visitor for an algebraic data type constructs a new data +structure, by applying a data constructor or by allocating a new record. +Sometimes, though, it is illegal to do so: this is the case, for instance, if +the type has been declared \oc|private|. +% +% Sometimes, the default behavior is well-typed, but is not the desired +% behavior. In that case, it can be customized by overriding a method. Using +% [@build] offers a little extra conciseness and efficiency in that case, but +% this need not be advertised. +% +% Another solution would be to just write the visitor by hand for a private +% type, but that would require more work from the user. +% +In such a situation, an alternate constructor can be provided via a +\oc|[@build]| attribute (which must be attached to a data constructor) or via a +\oc|[@@build]| attribute (which must be attached to a record type declaration). +% +Such an attribute carries an OCaml expression, which should represent a +constructor function. + +For instance, suppose that the module \oc|Point| has the following signature: +\begin{mdframed}[backgroundcolor=green!10] +\lstinputlisting{point.mli} +\end{mdframed} + +Suppose that, outside of this module, one wishes to generate a \map visitor +for the type \oc|Point.point|. One would like to do this in the style that was +presented earlier (\sref{sec:import}), but a naïve attempt fails: the +generated visitor is illegal, because allocating a record of type +\oc|Point.point| is forbidden. To circumvent this problem, one should +indicate, via a \oc|[@@build]| attribute, that the constructor function +\oc|Point.make| should be used: +% +\begin{origenv} +\begin{lstlisting} +type point = Point.point = private { x: int; y: int } + [@@build Point.make] + [@@deriving visitors { variety = "map" }] +\end{lstlisting} +\end{origenv} +% + +The OCaml expression carried by a \oc|[@build]| attribute can refer to the +local variable \oc|self|, which represents the visitor object, and to the +local variable \oc|env|, which represents the environment received by the +visitor method. + +\oc|[@build]| attributes influence not only \map visitors, +but also \mapendo and \mapreduce visitors. + +Instead of \oc|[@build]|, one can use +\oc|[@visitors.build]| or \oc|[@deriving.visitors.build]|. + +% Be careful not to misspell the attribute name, +% as the attribute would then be silently ignored. + +% ------------------------------------------------------------------------------ + +\bibliographystyle{plain} +\bibliography{english,local} + +\end{document} + +% TEMPORARY to do: + +add a use case that shows an environment in use + e.g. expressions with let bindings, + and if a variable is bound to a constant, replace it with its value + +document the speed overhead compared to a native recursive function + +document the lazy-initializer trick, if used + +référence: + avoid shadowing the following names: VisitorsRuntime, Lazy, Pervasives + +related work, for OCaml: + ppx_deriving (generates monolithic code) (fixed number of templates) + ppx_deriving_morphism + janestreet/ppx_traverse + Hongbo Zhang has `deriving at a distance' in Fan + https://github.com/bobzhang/fan + http://zhanghongbo.me/fan/ + http://zhanghongbo.me/fan/_downloads/metaprogramming_for_ocaml.pdf + alphaCaml + +related work, for other programming languages: + Bound (Edward Kmett) + Unbound (Weirich) + RedPerl + Francisco Ferreira et Brigitte Pientka, ESOP 2017 (Babybel) + +related work, for proof assistants: + Steven Keuchel + Autosubst (voir Kaiser et al., CPP 2017) + voir Guillaume Allais (CPP 2017, Agda et Haskell) et Goguen & McKinna diff --git a/doc/plain.bst b/doc/plain.bst new file mode 100644 index 0000000..2071152 --- /dev/null +++ b/doc/plain.bst @@ -0,0 +1,1106 @@ +% BibTeX standard bibliography style `plain' + % version 0.99a for BibTeX versions 0.99a or later, LaTeX version 2.09. + % Copyright (C) 1985, all rights reserved. + % Copying of this file is authorized only if either + % (1) you make absolutely no changes to your copy, including name, or + % (2) if you do make changes, you name it something other than + % btxbst.doc, plain.bst, unsrt.bst, alpha.bst, and abbrv.bst. + % This restriction helps ensure that all standard styles are identical. + % The file btxbst.doc has the documentation for this style. + +% Modified by Francois.Pottier@inria.fr with support for url field. + +ENTRY + { address + author + booktitle + chapter + edition + editor + howpublished + institution + journal + key + month + note + number + organization + pages + publisher + school + series + title + type + url + volume + year + } + {} + { label } + +INTEGERS { output.state before.all mid.sentence after.sentence after.block } + +FUNCTION {init.state.consts} +{ #0 'before.all := + #1 'mid.sentence := + #2 'after.sentence := + #3 'after.block := +} + +STRINGS { s t } + +FUNCTION {output.nonnull} +{ 's := + output.state mid.sentence = + { ", " * write$ } + { output.state after.block = + { add.period$ write$ + newline$ + "\newblock " write$ + } + { output.state before.all = + 'write$ + { add.period$ " " * write$ } + if$ + } + if$ + mid.sentence 'output.state := + } + if$ + s +} + +FUNCTION {output} +{ duplicate$ empty$ + 'pop$ + 'output.nonnull + if$ +} + +FUNCTION {output.check} +{ 't := + duplicate$ empty$ + { pop$ "empty " t * " in " * cite$ * warning$ } + 'output.nonnull + if$ +} + +FUNCTION {output.bibitem} +{ newline$ + "\bibitem{" write$ + cite$ write$ + "}" write$ + newline$ + "" + before.all 'output.state := +} + +FUNCTION {fin.entry} +{ add.period$ + write$ + newline$ +} + +FUNCTION {new.block} +{ output.state before.all = + 'skip$ + { after.block 'output.state := } + if$ +} + +FUNCTION {new.sentence} +{ output.state after.block = + 'skip$ + { output.state before.all = + 'skip$ + { after.sentence 'output.state := } + if$ + } + if$ +} + +FUNCTION {not} +{ { #0 } + { #1 } + if$ +} + +FUNCTION {and} +{ 'skip$ + { pop$ #0 } + if$ +} + +FUNCTION {or} +{ { pop$ #1 } + 'skip$ + if$ +} + +FUNCTION {new.block.checka} +{ empty$ + 'skip$ + 'new.block + if$ +} + +FUNCTION {new.block.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.block + if$ +} + +FUNCTION {new.sentence.checka} +{ empty$ + 'skip$ + 'new.sentence + if$ +} + +FUNCTION {new.sentence.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.sentence + if$ +} + +FUNCTION {field.or.null} +{ duplicate$ empty$ + { pop$ "" } + 'skip$ + if$ +} + +FUNCTION {emphasize} +{ duplicate$ empty$ + { pop$ "" } + { "{\em " swap$ * "}" * } + if$ +} + +INTEGERS { nameptr namesleft numnames } + +FUNCTION {format.names} +{ 's := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr "{ff~}{vv~}{ll}{, jj}" format.name$ 't := + nameptr #1 > + { namesleft #1 > + { ", " * t * } + { numnames #2 > + { "," * } + 'skip$ + if$ + t "others" = + { " et~al." * } + { " and " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {format.authors} +{ author empty$ + { "" } + { author format.names } + if$ +} + +FUNCTION {format.editors} +{ editor empty$ + { "" } + { editor format.names + editor num.names$ #1 > + { ", editors" * } + { ", editor" * } + if$ + } + if$ +} + +FUNCTION {format.title} +{ title empty$ + { "" } + { url empty$ + { title "t" change.case$ } + { "\href{" url "}{" title "t" change.case$ "}" * * * * } + if$ } + if$ +} + +FUNCTION {n.dashify} +{ 't := + "" + { t empty$ not } + { t #1 #1 substring$ "-" = + { t #1 #2 substring$ "--" = not + { "--" * + t #2 global.max$ substring$ 't := + } + { { t #1 #1 substring$ "-" = } + { "-" * + t #2 global.max$ substring$ 't := + } + while$ + } + if$ + } + { t #1 #1 substring$ * + t #2 global.max$ substring$ 't := + } + if$ + } + while$ +} + +FUNCTION {format.date} +{ year empty$ + { month empty$ + { "" } + { "there's a month but no year in " cite$ * warning$ + month + } + if$ + } + { month empty$ + 'year + { month " " * year * } + if$ + } + if$ +} + +FUNCTION {format.btitle} +{ url empty$ + { title emphasize } + { "\href{" url "}{" title emphasize "}" * * * * } + if$ +} + +FUNCTION {tie.or.space.connect} +{ duplicate$ text.length$ #3 < + { "~" } + { " " } + if$ + swap$ * * +} + +FUNCTION {either.or.check} +{ empty$ + 'pop$ + { "can't use both " swap$ * " fields in " * cite$ * warning$ } + if$ +} + +FUNCTION {format.bvolume} +{ volume empty$ + { "" } + { "volume" volume tie.or.space.connect + series empty$ + 'skip$ + { " of " * series emphasize * } + if$ + "volume and number" number either.or.check + } + if$ +} + +FUNCTION {format.number.series} +{ volume empty$ + { number empty$ + { series field.or.null } + { output.state mid.sentence = + { "number" } + { "Number" } + if$ + number tie.or.space.connect + series empty$ + { "there's a number but no series in " cite$ * warning$ } + { " in " * series * } + if$ + } + if$ + } + { "" } + if$ +} + +FUNCTION {format.edition} +{ edition empty$ + { "" } + { output.state mid.sentence = + { edition "l" change.case$ " edition" * } + { edition "t" change.case$ " edition" * } + if$ + } + if$ +} + +INTEGERS { multiresult } + +FUNCTION {multi.page.check} +{ 't := + #0 'multiresult := + { multiresult not + t empty$ not + and + } + { t #1 #1 substring$ + duplicate$ "-" = + swap$ duplicate$ "," = + swap$ "+" = + or or + { #1 'multiresult := } + { t #2 global.max$ substring$ 't := } + if$ + } + while$ + multiresult +} + +FUNCTION {format.pages} +{ pages empty$ + { "" } + { pages multi.page.check + { "pages" pages n.dashify tie.or.space.connect } + { "page" pages tie.or.space.connect } + if$ + } + if$ +} + +FUNCTION {format.vol.num.pages} +{ volume field.or.null + number empty$ + 'skip$ + { "(" number * ")" * * + volume empty$ + { "there's a number but no volume in " cite$ * warning$ } + 'skip$ + if$ + } + if$ + pages empty$ + 'skip$ + { duplicate$ empty$ + { pop$ format.pages } + { ":" * pages n.dashify * } + if$ + } + if$ +} + +FUNCTION {format.chapter.pages} +{ chapter empty$ + 'format.pages + { type empty$ + { "chapter" } + { type "l" change.case$ } + if$ + chapter tie.or.space.connect + pages empty$ + 'skip$ + { ", " * format.pages * } + if$ + } + if$ +} + +FUNCTION {format.in.ed.booktitle} +{ booktitle empty$ + { "" } + { editor empty$ + { "In " booktitle emphasize * } + { "In " format.editors * ", " * booktitle emphasize * } + if$ + } + if$ +} + +FUNCTION {empty.misc.check} +{ author empty$ title empty$ howpublished empty$ + month empty$ year empty$ note empty$ + and and and and and + key empty$ not and + { "all relevant fields are empty in " cite$ * warning$ } + 'skip$ + if$ +} + +FUNCTION {format.thesis.type} +{ type empty$ + 'skip$ + { pop$ + type "t" change.case$ + } + if$ +} + +FUNCTION {format.tr.number} +{ type empty$ + { "Technical Report" } + 'type + if$ + number empty$ + { "t" change.case$ } + { number tie.or.space.connect } + if$ +} + +FUNCTION {format.article.crossref} +{ key empty$ + { journal empty$ + { "need key or journal for " cite$ * " to crossref " * crossref * + warning$ + "" + } + { "In {\em " journal * "\/}" * } + if$ + } + { "In " key * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {format.crossref.editor} +{ editor #1 "{vv~}{ll}" format.name$ + editor num.names$ duplicate$ + #2 > + { pop$ " et~al." * } + { #2 < + 'skip$ + { editor #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" = + { " et~al." * } + { " and " * editor #2 "{vv~}{ll}" format.name$ * } + if$ + } + if$ + } + if$ +} + +FUNCTION {format.book.crossref} +{ volume empty$ + { "empty volume in " cite$ * "'s crossref of " * crossref * warning$ + "In " + } + { "Volume" volume tie.or.space.connect + " of " * + } + if$ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { series empty$ + { "need editor, key, or series for " cite$ * " to crossref " * + crossref * warning$ + "" * + } + { "{\em " * series * "\/}" * } + if$ + } + { key * } + if$ + } + { format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {format.incoll.inproc.crossref} +{ editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { booktitle empty$ + { "need editor, key, or booktitle for " cite$ * " to crossref " * + crossref * warning$ + "" + } + { "In {\em " booktitle * "\/}" * } + if$ + } + { "In " key * } + if$ + } + { "In " format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {article} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { journal emphasize "journal" output.check + format.vol.num.pages output + format.date "year" output.check + } + { format.article.crossref output.nonnull + format.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {book} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + new.block + format.number.series output + new.sentence + publisher "publisher" output.check + address output + } + { new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {booklet} +{ output.bibitem + format.authors output + new.block + format.title "title" output.check + howpublished address new.block.checkb + howpublished output + address output + format.date output + new.block + note output + fin.entry +} + +FUNCTION {inbook} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + format.chapter.pages "chapter and pages" output.check + new.block + format.number.series output + new.sentence + publisher "publisher" output.check + address output + } + { format.chapter.pages "chapter and pages" output.check + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {incollection} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.number.series output + format.chapter.pages output + new.sentence + publisher "publisher" output.check + address output + format.edition output + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.chapter.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {inproceedings} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.number.series output + format.pages output + address empty$ + { organization publisher new.sentence.checkb + organization output + publisher output + format.date "year" output.check + } + { address output.nonnull + format.date "year" output.check + new.sentence + organization output + publisher output + } + if$ + } + { format.incoll.inproc.crossref output.nonnull + format.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {conference} { inproceedings } + +FUNCTION {manual} +{ output.bibitem + author empty$ + { organization empty$ + 'skip$ + { organization output.nonnull + address output + } + if$ + } + { format.authors output.nonnull } + if$ + new.block + format.btitle "title" output.check + author empty$ + { organization empty$ + { address new.block.checka + address output + } + 'skip$ + if$ + } + { organization address new.block.checkb + organization output + address output + } + if$ + format.edition output + format.date output + new.block + note output + fin.entry +} + +FUNCTION {mastersthesis} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + "Master's thesis" format.thesis.type output.nonnull + school "school" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {misc} +{ output.bibitem + format.authors output + title howpublished new.block.checkb + format.title output + howpublished new.block.checka + howpublished output + format.date output + new.block + note output + fin.entry + empty.misc.check +} + +FUNCTION {phdthesis} +{ output.bibitem + format.authors "author" output.check + new.block + format.btitle "title" output.check + new.block + "PhD thesis" format.thesis.type output.nonnull + school "school" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {proceedings} +{ output.bibitem + editor empty$ + { organization output } + { format.editors output.nonnull } + if$ + new.block + format.btitle "title" output.check + format.bvolume output + format.number.series output + address empty$ + { editor empty$ + { publisher new.sentence.checka } + { organization publisher new.sentence.checkb + organization output + } + if$ + publisher output + format.date "year" output.check + } + { address output.nonnull + format.date "year" output.check + new.sentence + editor empty$ + 'skip$ + { organization output } + if$ + publisher output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {techreport} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + format.tr.number output.nonnull + institution "institution" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {unpublished} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + note "note" output.check + format.date output + fin.entry +} + +FUNCTION {default.type} { misc } + +MACRO {jan} {"January"} + +MACRO {feb} {"February"} + +MACRO {mar} {"March"} + +MACRO {apr} {"April"} + +MACRO {may} {"May"} + +MACRO {jun} {"June"} + +MACRO {jul} {"July"} + +MACRO {aug} {"August"} + +MACRO {sep} {"September"} + +MACRO {oct} {"October"} + +MACRO {nov} {"November"} + +MACRO {dec} {"December"} + +MACRO {acmcs} {"ACM Computing Surveys"} + +MACRO {acta} {"Acta Informatica"} + +MACRO {cacm} {"Communications of the ACM"} + +MACRO {ibmjrd} {"IBM Journal of Research and Development"} + +MACRO {ibmsj} {"IBM Systems Journal"} + +MACRO {ieeese} {"IEEE Transactions on Software Engineering"} + +MACRO {ieeetc} {"IEEE Transactions on Computers"} + +MACRO {ieeetcad} + {"IEEE Transactions on Computer-Aided Design of Integrated Circuits"} + +MACRO {ipl} {"Information Processing Letters"} + +MACRO {jacm} {"Journal of the ACM"} + +MACRO {jcss} {"Journal of Computer and System Sciences"} + +MACRO {scp} {"Science of Computer Programming"} + +MACRO {sicomp} {"SIAM Journal on Computing"} + +MACRO {tocs} {"ACM Transactions on Computer Systems"} + +MACRO {tods} {"ACM Transactions on Database Systems"} + +MACRO {tog} {"ACM Transactions on Graphics"} + +MACRO {toms} {"ACM Transactions on Mathematical Software"} + +MACRO {toois} {"ACM Transactions on Office Information Systems"} + +MACRO {toplas} {"ACM Transactions on Programming Languages and Systems"} + +MACRO {tcs} {"Theoretical Computer Science"} + +READ + +FUNCTION {sortify} +{ purify$ + "l" change.case$ +} + +INTEGERS { len } + +FUNCTION {chop.word} +{ 's := + 'len := + s #1 len substring$ = + { s len #1 + global.max$ substring$ } + 's + if$ +} + +FUNCTION {sort.format.names} +{ 's := + #1 'nameptr := + "" + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { nameptr #1 > + { " " * } + 'skip$ + if$ + s nameptr "{vv{ } }{ll{ }}{ ff{ }}{ jj{ }}" format.name$ 't := + nameptr numnames = t "others" = and + { "et al" * } + { t sortify * } + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {sort.format.title} +{ 't := + "A " #2 + "An " #3 + "The " #4 t chop.word + chop.word + chop.word + sortify + #1 global.max$ substring$ +} + +FUNCTION {author.sort} +{ author empty$ + { key empty$ + { "to sort, need author or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {author.editor.sort} +{ author empty$ + { editor empty$ + { key empty$ + { "to sort, need author, editor, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { editor sort.format.names } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {author.organization.sort} +{ author empty$ + { organization empty$ + { key empty$ + { "to sort, need author, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {editor.organization.sort} +{ editor empty$ + { organization empty$ + { key empty$ + { "to sort, need editor, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { editor sort.format.names } + if$ +} + +FUNCTION {presort} +{ type$ "book" = + type$ "inbook" = + or + 'author.editor.sort + { type$ "proceedings" = + 'editor.organization.sort + { type$ "manual" = + 'author.organization.sort + 'author.sort + if$ + } + if$ + } + if$ + " " + * + year field.or.null sortify + * + " " + * + title field.or.null + sort.format.title + * + #1 entry.max$ substring$ + 'sort.key$ := +} + +ITERATE {presort} + +SORT + +STRINGS { longest.label } + +INTEGERS { number.label longest.label.width } + +FUNCTION {initialize.longest.label} +{ "" 'longest.label := + #1 'number.label := + #0 'longest.label.width := +} + +FUNCTION {longest.label.pass} +{ number.label int.to.str$ 'label := + number.label #1 + 'number.label := + label width$ longest.label.width > + { label 'longest.label := + label width$ 'longest.label.width := + } + 'skip$ + if$ +} + +EXECUTE {initialize.longest.label} + +ITERATE {longest.label.pass} + +FUNCTION {begin.bib} +{ preamble$ empty$ + 'skip$ + { preamble$ write$ newline$ } + if$ + "\begin{thebibliography}{" longest.label * "}" * write$ newline$ +} + +EXECUTE {begin.bib} + +EXECUTE {init.state.consts} + +ITERATE {call.type$} + +FUNCTION {end.bib} +{ newline$ + "\end{thebibliography}" write$ newline$ +} + +EXECUTE {end.bib} diff --git a/doc/types.tex b/doc/types.tex new file mode 100644 index 0000000..8a66dcc --- /dev/null +++ b/doc/types.tex @@ -0,0 +1,38 @@ +\begin{figure}[t] +\begin{mdframed}[backgroundcolor=green!10] +\begin{lstlisting} +class virtual ['self] iter : object ('self) + constraint 'self = + < visit_EAdd : 'env -> expr -> expr -> unit; + visit_EConst : 'env -> int -> unit; + visit_expr : 'env -> expr -> unit; + .. > + method visit_EAdd : 'env -> expr -> expr -> unit + method visit_EConst : 'env -> int -> unit + method visit_expr : 'env -> expr -> unit + (* These methods are inherited from [VisitorsRuntime.iter]: *) + method private visit_array : + 'env 'a. ('env -> 'a -> unit) -> 'env -> 'a array -> unit + method private visit_bool : 'env. 'env -> bool -> unit + method private visit_bytes : 'env. 'env -> bytes -> unit + (* ... and many more ... *) +end +\end{lstlisting} +\end{mdframed} +\caption{An inferred type for the \iter visitor of \fref{fig:expr00}} +\label{fig:inferred} +\end{figure} + +\begin{figure}[t] +\begin{mdframed}[backgroundcolor=green!10] +\begin{lstlisting} +class virtual ['self] iter : object ('self) + method visit_EAdd : 'monomorphic. 'env -> expr -> expr -> unit + method visit_EConst : 'monomorphic. 'env -> int -> unit + method visit_expr : 'monomorphic. 'env -> expr -> unit +end +\end{lstlisting} +\end{mdframed} +\caption{A simplified type for the \iter visitor of \fref{fig:expr00}} +\label{fig:simplified} +\end{figure} diff --git a/doc/version.tex b/doc/version.tex new file mode 100644 index 0000000..0745576 --- /dev/null +++ b/doc/version.tex @@ -0,0 +1 @@ +\gdef\visitorsversion{(unreleased)} % To be overridden. diff --git a/opam b/opam new file mode 100644 index 0000000..e81ae85 --- /dev/null +++ b/opam @@ -0,0 +1,27 @@ +opam-version: "1.2" +maintainer: "francois.pottier@inria.fr" +authors: [ + "François Pottier " +] +homepage: "https://gitlab.inria.fr/fpottier/visitors" +dev-repo: "https://gitlab.inria.fr/fpottier/visitors.git" +bug-reports: "francois.pottier@inria.fr" +build: [ + [make] +] +install: [ + [make "install"] +] +remove: [ + [make "uninstall"] +] +depends: [ + "ocamlfind" {build} + "ocamlbuild" {build} + "cppo" {build} + "cppo_ocamlbuild" {build} + "ppx_tools" + "ppx_deriving" {>= "4.0"} + "result" +] +available: [ ocaml-version >= "4.02.2" ] diff --git a/src/.merlin b/src/.merlin new file mode 100644 index 0000000..f54631e --- /dev/null +++ b/src/.merlin @@ -0,0 +1,2 @@ +PKG compiler-libs.common ppx_tools ppx_deriving.api +B _build diff --git a/src/META b/src/META new file mode 100644 index 0000000..be5dd5b --- /dev/null +++ b/src/META @@ -0,0 +1,32 @@ +description = "A visitor generation facility" +requires = "compiler-libs ppx_tools ppx_deriving" + +# I don't really understand any of the following. +# See https://github.com/whitequark/ppx_deriving + +package "ppx" ( + description = "Compile-time support for generating visitors" + requires(-ppx_driver) = "ppx_deriving" + ppxopt(-ppx_driver) = "ppx_deriving,./ppx_deriving_visitors.cma" + +# It seems OK to let this package exist unconditionally. +# exists_if = "ppx_deriving_visitors.cma" + +# Apparently the following part could be omitted too. +# It affects ppx driver compilation, whatever that means. + requires(ppx_driver) = "ppx_deriving.api" + archive(ppx_driver, byte) = "ppx_deriving_visitors.cma" + archive(ppx_driver, native) = "ppx_deriving_visitors.cmxa" + +# This is what jbuilder uses to find out the runtime dependencies of +# a preprocessor + ppx_runtime_deps = "visitors.runtime" +) + +# The runtime support library. + +package "runtime" ( + description = "Runtime support for the generated visitors" + archive(byte) = "VisitorsRuntime.cma" + archive(native) = "VisitorsRuntime.cmxa" +) diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..3b20dc2 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,67 @@ +# ------------------------------------------------------------------------------ + +# Variables. + +PACKAGE := \ + visitors + +PLUGIN := \ + ppx_deriving_$(PACKAGE) + +RUNTIME := \ + VisitorsRuntime + +OCAMLBUILD := \ + ocamlbuild \ + -use-ocamlfind \ + -classic-display \ + -plugin-tag 'package(cppo_ocamlbuild)' \ + +# Detect whether ocamlopt is available. +NATIVE := $(shell if env ocamlopt >/dev/null 2>/dev/null ; then \ + echo yes ; else echo no ; fi) + +# The targets that should be built (using ocamlbuild). +# Not sure whether all of the following files are really required. +ifeq ($(NATIVE),yes) + MSG := "Compiling for byte code and native code." + TARGETS := \ + $(patsubst %,$(PLUGIN).%,cma a cmxa cmxs) \ + $(patsubst %,$(RUNTIME).%,cmi cmo cma a cmx cmxa o) +else + MSG := "Compiling for byte code only." + TARGETS := \ + $(patsubst %,$(PLUGIN).%,cma) \ + $(patsubst %,$(RUNTIME).%,cmi cmo cma) +endif + +# The files that should be installed (using ocamlfind). +FILES := \ + META \ + Makefile.preprocess \ + $(patsubst %,_build/%,$(TARGETS)) \ + +# ------------------------------------------------------------------------------ + +# Rules. + +.PHONY: all clean install uninstall reinstall + +all: + @ echo $(MSG) + $(OCAMLBUILD) $(TARGETS) + +clean: + rm -f *~ + $(OCAMLBUILD) -clean + +install: all + ocamlfind install $(PACKAGE) $(FILES) + +# [make uninstall] attempts to uninstall, but succeeds even if uninstallation +# fails (probably because the package was not installed in the first place). +uninstall: + ocamlfind remove $(PACKAGE) || true + +reinstall: uninstall + @ $(MAKE) install diff --git a/src/Makefile.preprocess b/src/Makefile.preprocess new file mode 100644 index 0000000..f6dd49a --- /dev/null +++ b/src/Makefile.preprocess @@ -0,0 +1,45 @@ +# This Makefile allows running visitors as a preprocessor, +# so as to inspect the generated code and possibly include +# it in a TeX document. + +# This assumes the visitors package is installed. + +# The rewriting command. +PPX := `ocamlfind query ppx_deriving`/ppx_deriving \ + `ocamlfind query visitors`/ppx_deriving_visitors.cma +REWRITE := ocamlfind ppx_tools/rewriter -ppx '$(PPX)' + +# Use GNU sed to extract the generated code. +# This requires GNU sed 3.95 or above, I am told. +SED := $(shell if command -v gsed >/dev/null ; then echo gsed ; else echo sed ; fi) +EXTRACT := $(SED) -e '/VISITORS.BEGIN/,/VISITORS.END/!d;//d' + +# Fix some deficiencies of OCaml's code printer. +# -- Force a space after a comma. +# -- Force a space after an ordinary letter and before [=]. +# -- Replace multiple consecutive spaces with a single space. +# This destroys indentation; we restore it afterwards. +# -- Remove a space before a comma or closing parenthesis. +# -- Force a line break after [in], unless there is one already. +# -- Force a line break after [| ... ->] on a line by itself, unless there is one already. +# -- Force a line break after [method ... =], unless there is one already. +# -- Remove the line break between [=] and [object]. +# -- Replace [fun x y -> fun ] with [fun x y ], so multiple-argument functions are prettier. +# Do this twice, so we can handle functions of arity up to 3. (Yes, this is very ad hoc.) +BEAUTIFY := \ + | $(SED) -e 's/,/, /g' \ + | $(SED) -e 's/\([a-zA-Z_)]\)=/\1 =/g' \ + | $(SED) -e 's/ / /g' \ + | $(SED) -e 's/ \([,)]\)/\1/g' \ + | $(SED) -e 's/ in / in\n/g' \ + | $(SED) -e 's/^\( *|.* ->\) /\1\n/g' \ + | $(SED) -e 's/\(method[^=]*=\) /\1\n/g' \ + | perl -0777 -pe 's/=\n *object/= object/gs' \ + | perl -0777 -pe "s/fun ([a-zA-Z0-9_' ]+) ->\n *fun /fun \1 /gs" \ + | perl -0777 -pe "s/fun ([a-zA-Z0-9_' ]+) ->\n *fun /fun \1 /gs" \ + +# Use ocp-indent to beautify the generated code. +INDENT := ocp-indent --config=JaneStreet,match_clause=4 + +%.processed.ml: %.ml + $(REWRITE) $< | $(EXTRACT) $(BEAUTIFY) | $(INDENT) > $@ diff --git a/src/Visitors.ml b/src/Visitors.ml new file mode 100644 index 0000000..b459b78 --- /dev/null +++ b/src/Visitors.ml @@ -0,0 +1,1287 @@ +open VisitorsString +open VisitorsList +open Longident +open List +open Asttypes +open Parsetree +open Ast_helper +open Ast_convenience +open Ppx_deriving +open VisitorsPlugin +open VisitorsCompatibility +open VisitorsAnalysis +open VisitorsGeneration +open VisitorsSettings + +(* -------------------------------------------------------------------------- *) + +(* Per-run global state. *) + +module Setup (X : SETTINGS) = struct + +let arity = + X.arity + +(* -------------------------------------------------------------------------- *) + +(* If the [public] option is absent, then every method is public. If it is + present, then every method is private, unless its name occurs in the list + [X.public]. *) + +let visibility m = + match X.public with + | None -> + Public + | Some ms -> + if List.mem m ms then Public else Private + +(* The following brings [generate] and [dump] into scope. *) + +include ClassFieldStore(struct end) + +let annotation (ty : core_type) : core_type option = + (* A type annotation is generated only in [polymorphic] mode. *) + if X.polymorphic then Some ty else None + +let generate_concrete_method m e ty = + generate (concrete_method (visibility m) m e (annotation ty)) + +let generate_virtual_method m ty = + generate (virtual_method (visibility m) m (annotation ty)) + +(* -------------------------------------------------------------------------- *) + +(* The following brings [warning] and [warnings] into scope. *) + +include WarningStore(struct end) + +(* [datacon_opacity_warning cd] emits a warning (if necessary) about the + following issue. One should not write "A of int[@opaque]". Instead, one + should write "A of (int[@opaque])". In the case of records fields, we fix + this silently, by moving the attribute from the record field to the type, + but in the case of data constructors with multiple fields, it is preferable + to be strict. *) + +let datacon_opacity_warning (cd : constructor_declaration) : unit = + if opacity cd.pcd_attributes = Opaque then + warning cd.pcd_loc + "%s: @opaque, attached to a data constructor, is ignored.\n\ + It should be attached to a type. Please use parentheses." + plugin + +(* [sum_build_warning decl] emits emits a warning (if necessary) about the + following issue. One should not attach a [@@build] attribute to a sum type. + Instead, one should attach a [@build] attribute to every data constructor. + Note that one can attach a [@@build] attribute to a record type. *) + +let sum_build_warning (decl : type_declaration) : unit = + if build decl.ptype_attributes <> None then + warning decl.ptype_loc + "%s: @@build, attached to a sum type, is ignored.\n\ + Instead, @build should be attached to each data constructor." + plugin + +(* -------------------------------------------------------------------------- *) + +(* 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, + [int term] or [('a * 'a) term]. *) + +(* To enforce this, we check that, in every use of a local type constructor, + the actual type parameters coincide with the formal type parameters. *) + +(* This check is imposed only on [mono] type variables. For [poly] type + variables, irregularity is allowed. *) + +(* The purpose of this check is to avoid an incomprehensible type error in + the generated code. *) + +let check_regularity loc tycon (formals : tyvars) (actuals : core_types) = + (* Check that the numbers of parameters match. *) + if length formals <> length actuals then + raise_errorf ~loc + "%s: the type constructor %s expects %s,\n\ + but is applied to %s." + plugin tycon + (number (length formals) "type parameter") + (number (length actuals) "type parameter"); + (* Check that the parameters match. *) + if not X.irregular && not ( + fold_left2 (fun ok formal actual -> + ok && (X.poly formal || actual.ptyp_desc = Ptyp_var formal) + ) true formals actuals + ) then + raise_errorf ~loc "%s: the type constructor %s is irregular." plugin tycon + +(* -------------------------------------------------------------------------- *) + +(* 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. + + 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]. *) + +let tycon_modified_name (attrs : attributes) (tycon : tycon) : tycon = + maybe (name attrs) tycon + +(* Similarly, the base name of the methods associated with a data constructor + can be altered via a [@name] attribute, which must be attached to the data + constructor declaration. *) + +let datacon_modified_name (cd : constructor_declaration) : datacon = + maybe (name cd.pcd_attributes) cd.pcd_name.txt + +(* For every type constructor [tycon], there is a visitor method, also called + a descending method, as it is invoked when going down into the tree. *) + +(* 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.) *) + +(* 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_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_loc, ty.ptyp_attributes, tycon.txt) + | _ -> + assert false + +(* For every local record type constructor [tycon], there is an ascending + 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]. *) + +(* The name of this method is normally [build_foo] if the type is named [foo]. *) + +let tycon_ascending_method (decl : type_declaration) : methode = + 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 = + 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. *) + +(* The name of this method is normally [visit_Foo] if the data constructor is + named [Foo]. *) + +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]. *) + +let datacon_ascending_method (cd : constructor_declaration) : methode = + 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 + left-hand and right-hand arguments do not exhibit the same tags. *) + +(* The name of this method is normally [fail_foo] if the type is named [foo]. *) + +let failure_method (decl : type_declaration) : methode = + 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 + that there exist virtual methods by these names. It is up to the user to + provide these methods via inheritance, that is, via the [ancestors] + option. *) + +let zero = + "zero" + +let plus = + "plus" + +(* -------------------------------------------------------------------------- *) + +(* Private naming conventions. *) + +(* These conventions must be set up so as to avoid collisions within each name + space separately: e.g., variables, methods, type variables, and so on. *) + +(* We use improbable variable names, because it is possible for user code to + be placed in the scope of these variables. (This is the case when the user + provides [@build] annotations.) As a couple exceptions, the names [self] + and [env] are not made improbable, and we document the existence of these + variables, which can be used in [@build] annotations. *) + +(* In a class, the variable [self] refers to self. + The type variable [ty_self] denotes its type. *) + +let self : variable = + "self" + +let ty_self : core_type = + Typ.var "self" + +let pself : pattern = + Pat.constraint_ (pvar self) ty_self + +(* The variable [env] refers to the environment that is carried down into + recursive calls. *) + +let env : variable = + "env" + +(* We sometimes need two (or more) copies of a variable: one copy for each + index [j] ranging in the interval [0..arity). *) + +let copy (j : int) (x : string) : string = + assert (0 <= j && j < arity); + if arity = 1 then + (* No alteration required. *) + x + else + sprintf "%s_%d" x j + +(* The variables [component i j] denote tuple components. The index [i] + ranges over tuple components; the index [j] ranges in [0..arity). *) + +let component (i : int) (j : int) : variable = + improbable (copy j (sprintf "c%d" i)) + +let components (i : int) : variables = + map (component i) (interval 0 arity) + +let componentss (xs : _ list) : variables list = + mapi (fun i _ -> components i) xs + +(* The variable [thing j] denotes an input value. *) + +let thing (j : int) : variable = + improbable (copy j "this") + +let things : variables = + map thing (interval 0 arity) + +(* The variable [this] is used only in the generation of [endo] visitors. *) + +let this = + thing 0 + +(* The variables [field label j] denote record fields. *) + +let field (label : label) (j : int) : variable = + improbable (copy j (sprintf "f%s" label)) + +let fields (label : label) : variables = + map (field label) (interval 0 arity) + +let fieldss (labels : label list) : variables list = + map fields labels + +(* The variables [result i] denote results of recursive calls. *) + +let result (i : int) : variable = + improbable (sprintf "r%d" i) + +let results (xs : _ list) : variables = + mapi (fun i _ -> result i) xs + +(* The variables [summary i] denote results of recursive calls. + When the scheme is [MapReduce], each recursive call produces + a pair; we use [result i] and [summary i] as the names of the + pair components. *) + +let summary (i : int) : variable = + improbable (sprintf "s%d" i) + +let summaries (xs : _ list) : variables = + mapi (fun i _ -> summary i) xs + +(* Reserved names of type variables. We forbid the user from using these + names, and do not let them be renamed by the function [variant] below. *) + +let reserved : tyvars = + [ "s"; "env" ] + +let reserved_ty_var (alpha : tyvar) : core_type = + assert (mem alpha reserved); + ty_var alpha + +(* Naming conventions for type variables in type annotations. If ['a] + is a type variable named by the user, we use ['a_i], where [i] is + in [0..arity]. Indices [i] in the interval [0..arity) are used for + the arguments of a visitor method. The index [arity] is used for + the result of a visitor method. *) + +(* If [scheme] is [Endo], then the argument and result must have the + same type, so we do not introduce a variation in the type variables. *) + +let variant (i : int) (alpha : tyvar) : tyvar = + assert (0 <= i && i <= arity); + if X.scheme = Endo || mem alpha reserved then + alpha + else + sprintf "%s_%d" alpha i + +let vary_type (i : int) (ty : core_type) : core_type = + rename_type (variant i) ty + +(* [ty_monoid] is the type of monoid elements. *) + +let ty_monoid = + reserved_ty_var "s" + +(* [ty_env] is the type of the environment. *) + +(* What IS the type of the environment? This is a tricky question. Two + possibilities arise: + + 1. One might wish for every visitor method to be polymorphic in the type + ['env] of the environment. This makes the method more widely applicable, + but means that the environment effectively cannot be used by the method + (except by passing it on to its callees). Thus, the method cannot be + overridden by a custom implementation that actually uses the environment. + + 2. One might wish for the environment to have monomorphic type. In that + case, one should note that there is a priori no reason why the type of + the environment should be the same in every method. So, we must be + careful not to use a single type variable ['env]. We must use a distinct + type variable every time, or (easier but equivalent) use a wildcard. + + How do we let the user specify which behavior is desired? And with what + granularity? We choose a simple approach: we treat ['env] as polymorphic + if and only if this (reserved) type variable is declared polymorphic by + the user. *) + +let ty_env = + if X.poly "env" then + reserved_ty_var "env" + else + ty_any + +(* What is the type of a virtual visitor method [visit_'a] in charge of + dealing with a [mono] type variable ['a]? + + One might think that it must be a monomorphic type, so we can just + issue a wildcard [_] and let OCaml infer this type. + + Yet, if the user has requested that every method be polymorphic in + the type ['env] of the environment, then [visit_'a], too must be + polymorphic in ['env]. (Otherwise, the generated code would be ill-typed.) + In that case, we must generate ['env . 'env -> _]. + + This implies that [visit_'a] cannot use the environment. + So, it seems somewhat doubtful that this feature is useful. + Perhaps we could allow the environment to consist of two components + and to quantify universally over only one of them? *) + +let tyvar_visitor_method_type = + if X.poly "env" then + typ_poly ["env"] (ty_arrow ty_env ty_any) + else + ty_any + +(* [poly] type variables have a visitor function. *) + +let tyvar_visitor_function (alpha : tyvar) : variable = + tyvar_visitor_method alpha + +(* -------------------------------------------------------------------------- *) + +(* Construction of type annotations. *) + +(* [result_type scheme ty] is the result type of a visitor method associated + with the type [ty]. *) + +(* If [ty] is of the form [decl_type decl] -- that is, if [ty] is a local type + constructor -- then this is the result type of the visitor method associated + with [ty]. *) + +let rec result_type scheme (ty : core_type) : core_type = + match scheme with + | Iter -> + (* An [iter] visitor method returns nothing. *) + ty_unit + | Map | Endo -> + (* A [map] or [endo] visitor method for the type [ty] returns a + value of type [ty]. Note that [ty] can contain type variables. *) + ty + | Reduce -> + (* A [reduce] visitor method returns a monoid element. *) + ty_monoid + | MapReduce -> + (* A [mapreduce] visitor method returns a pair of the results produced + by a [map] visitor method and by a [reduce] visitor method. *) + Typ.tuple [ result_type Map ty; result_type Reduce ty ] + | Fold -> + (* This is where we have a problem. We would really like to allow the + user to specify which skeleton should be used here, as we cannot + guess it. We might allow it in the future. For now, we impose the + monomorphic skeleton [_], which is not as general as we would like, + since it requires the method to have monomorphic result type. *) + ty_any + +let result_type = + result_type X.scheme + +(* [decl_result_type decl] is the result type of a visitor method associated + with the type declaration [decl]. *) + +let decl_result_type decl = + result_type (decl_type decl) + +(* A visitor function takes an environment, followed with [arity] arguments, + and produces a result. Thus, if [argument] and [result] are types, then the + type of a visitor function has the following shape: + + ty_env -> + argument_0 -> ... -> argument_{arity-1} -> + result_{arity} + + where [ty_{i}] denotes a copy of the type [ty] whose type variables have + been renamed by the renaming [variant i]. *) + +(* We generalize the above definition to allow for multiple [arguments]. This + is used in the visitor methods associated with data constructors. Thus, + each argument in succession is extended to [arity] arguments. *) + +(* We specialize the above definition to the case where the result type + is [result_type ty]. *) + +let visitor_fun_type (arguments : core_types) (ty : core_type) : core_type = + ty_arrows + (ty_env :: flatten (hextend arguments arity vary_type)) + (vary_type arity (result_type ty)) + +(* This special case of [visitor_fun_type] is the normal form of a visitor + function type: there is one argument of type [ty] (extended to [arity]) + and one result of type [result_type ty]. *) + +let simple_visitor_fun_type (ty : core_type) : core_type = + visitor_fun_type [ty] ty + +(* [visitor_method_type decl] is the type of the visitor method associated + with the type [decl]. This does not account for the visitor parameters + in charge of dealing with type variables. *) + +let visitor_method_type (decl : type_declaration) : core_type = + simple_visitor_fun_type (decl_type decl) + +(* [visitor_param_type alpha] is the type of the visitor function associated + with the type variable [alpha]. *) + +let visitor_param_type (alpha : tyvar) : core_type = + simple_visitor_fun_type (ty_var alpha) + +(* [fold_result_type ty] is the result type of the visitor code generated + by [visit_type ... ty], when [scheme] is [Fold]. *) + +let fold_result_type _ty = + (* This function is currently unimplemented and unused, because we + do not allow [polymorphic] to be [true] when [scheme] is [Fold]. + Thus, we do not generate any type annotations for ascending methods. *) + ty_any + +(* [poly_params decl] is the subset of the formal type parameters of [decl] + which are marked [poly]. For each of these parameters, a visitor function + should be passed. *) + +let poly_params (decl : type_declaration) : tyvars = + filter X.poly (decl_params decl) + +(* [quantify alphas ty] quantifies an appropriate set of type variables in the + method type [ty]. The parameter [alphas] is usually [poly_params decl], + although it could in principle be a subset of it, if we can prove that + some visitor functions are unneeded. We introduce universal quantifiers + on (suitable variants of) the type variables [alphas] and also possibly + on the type variable ['env]. *) + +let quantify (alphas : tyvars) (ty : core_type) : core_type = + (* Find out which variants of the type variables [alphas] we should quantify + over. For the arguments, we need to quantify over the variants in the + interval [0..arity). For the result, we may need to quantify over the + variant [arity]. We try and avoid superfluous quantifiers, as that would + decrease readability. *) + let alphas = + match X.scheme with + | Iter + | Reduce -> + (* Just the arguments. The result contains no type variables. *) + flatten (hextend alphas arity variant) + | Map + | MapReduce -> + (* Arguments and result. *) + flatten (hextend alphas (arity+1) variant) + | Endo -> + (* In this special case, there is just one variant, as the argument + and result must have the same type. *) + alphas + | Fold -> + (* Polymorphism currently not supported with [Fold]. *) + [] + in + (* Then, decide whether ['env] should be universally quantified. *) + let alphas = + if X.poly "env" then + "env" :: alphas + else + alphas + in + (* Done. *) + typ_poly alphas ty + +(* -------------------------------------------------------------------------- *) + +(* [bind rs ss] is a binding construct which, depending on the scheme, binds + either the variables [rs], or the variables [ss], or both, using pair + patterns. It is used to bind the results of recursive calls to visitor + methods. *) + +let bind (rs : variables) (ss : variables) + : expressions -> expression -> expression = + match X.scheme with + | Iter + | Map + | Endo + | Fold -> + letn rs + | Reduce -> + letn ss + | MapReduce -> + letnp rs ss + +(* -------------------------------------------------------------------------- *) + +(* [call m es] emits a method call of the form [self#m es]. *) + +let call (m : methode) (es : expressions) : expression = + send self m es + +(* -------------------------------------------------------------------------- *) + +(* Access to the monoid operations. *) + +let monoid_unit () : expression = + assert (X.scheme = Reduce || X.scheme = MapReduce); + call zero [] + +let monoid_law () : expression = + assert (X.scheme = Reduce || X.scheme = MapReduce); + call plus [] + +(* -------------------------------------------------------------------------- *) + +(* [reduce es] reduces the expressions [es], that is, it combines them, using + a monoid, which provides a unit and a binary operation. The reduction is + performed left-to-right. This could be of importance if the monoid is not + associative-commutative. *) + +let reduce es = + let unit = monoid_unit() + and law = monoid_law() in + fold_left1 (fun e1 e2 -> app law [e1; e2]) unit es + +(* -------------------------------------------------------------------------- *) + +(* [alias x ps] requires the pattern list [ps] to have length [arity]. If + [scheme] is [Endo], then it further requires [arity] to be 1. It adds a + binding of the variable [x], using an [as] pattern, at the top level of the + pattern. The result is again packaged as a pattern list of length [arity]. + If scheme is not [Endo], then [alias x ps] is just [ps]. *) + +let alias (x : variable) (ps : patterns) : patterns = + assert (length ps = arity); + match X.scheme with + | Endo -> + assert (arity = 1); + map (fun p -> + Pat.alias p (Location.mknoloc x) + ) ps + | _ -> + ps + +(* If [scheme] is [Endo], then [transmit x xs] is [x :: xs]. Otherwise, it is + just [xs]. *) + +let transmit x xs = + match X.scheme with + | Endo -> + x :: xs + | _ -> + xs + +(* -------------------------------------------------------------------------- *) + +(* [hook m xs ty e] constructs a call of the form [self#m xs], and (as a side + effect) generates a method [method m xs = e]. The free variables of the + expression [e] must be (a subset of) [xs]. The type [ty] is the type of + the method. It is always computed internally, but the type annotation is + actually printed only in [polymorphic] mode. *) + +(* Thus, by default, the expression [hook m xs ty e] behaves in the same way + as the expression [e]. But a hook, named [m], allows this default to be + overridden. *) + +let hook (m : methode) (xs : variables) (ty : core_type) (e : expression) : expression = + (* Generate a method. *) + generate_concrete_method m (lambdas xs e) ty; + (* Construct a method call. *) + call m (evars xs) + +(* The additional parameter [b] makes hook insertion optional. If [b] is [true], + a hook is created; otherwise, no hook is created. *) + +let hook b m xs ty e = + if b then hook m xs ty e else e + +(* -------------------------------------------------------------------------- *) + +(* [vhook m xs ty] constructs a call of the form [self#m xs], and (as a side + effect) generates a virtual method [method m: ty]. The type [ty] is the type + of the method. It is always computed internally, but the type annotation is + actually printed only in [polymorphic] mode. *) + +let vhook (m : methode) (xs : variables) (ty : core_type) : expression = + generate_virtual_method m ty; + call m (evars xs) + +(* -------------------------------------------------------------------------- *) + +(* If a data constructor or record carries a [@build] attribute, then the + OCaml expression carried by this attribute should be used instead of the + default [builder] function, which rebuilds a data constructor or record. + This concerns [map], [endo], and [mapreduce] visitors. *) + +type builder = + variables -> expression + +let ifbuild (attrs : attributes) (builder : builder) : builder = + match build attrs with + | None -> + builder + | Some e -> + fun rs -> app e (evars rs) + +(* -------------------------------------------------------------------------- *) + +(* The following classes help build the code that forms the ascending part of + a visitor method, that is, the code found after the recursive calls. *) + +(* There are four variants of this code, used in visitor methods for data + constructors, in visitor methods for records, in visitor functions for + tuples, and in visitor functions for @opaque types. *) + +(* The base class, [ascend], provides as much shared behavior as possible. *) + +class virtual ascend (ss : variables) = object (self) + + (* An [iter] visitor returns a unit value. *) + method ascend_Iter = + unit() + + (* The behavior of a [map] visitor is defined in subclasses. *) + method virtual ascend_Map : expression + + (* By default, an [endo] visitor behaves like a [map] visitor. This behavior + is appropriate at @opaque types. *) + method ascend_Endo = + self#ascend_Map + + (* A [reduce] visitor uses [zero] and [plus] to combine the results + of the recursive calls, which are bound to the variables [ss]. *) + method ascend_Reduce = + reduce (evars ss) + + (* A [mapreduce] visitor returns a pair of the results that would be + returned by a [map] visitor and by a [reduce] visitor. *) + method ascend_MapReduce = + tuple [ self#ascend_Map; self#ascend_Reduce ] + + (* By default, a [fold] visitor behaves like a [map] visitor, because we + have no better choice. This behavior is used at tuples and at @opaque + types. *) + method ascend_Fold = + self#ascend_Map + + (* Dispatch. *) + method ascend = + match X.scheme with + | Iter -> self#ascend_Iter + | Map -> self#ascend_Map + | Endo -> self#ascend_Endo + | Reduce -> self#ascend_Reduce + | MapReduce -> self#ascend_MapReduce + | Fold -> self#ascend_Fold + +end + +(* The subclass [ascend_opaque] defines the desired behavior at @opaque types. *) + +(* In an [iter] visitor, we return a unit value, as always. This means that, + even if [arity] is greater than 1, NO EQUALITY TEST takes place. This + differs from the behavior of the methods [visit_int], [visit_bool], etc., + which perform an equality test. *) + +(* In a [map] visitor, we return THE FIRST ARGUMENT of the visitor. At arity + greater than 1, this is an ARBITRARY choice. It is not clear what else we + could do. *) + +(* In a [reduce] visitor, we return the neutral element, [self#zero]. *) + +(* In a [fold] visitor, we keep the default behavior, which is to behave like + a [map] visitor. *) + +class ascend_opaque (xs : variables) = object + + inherit ascend [] + + method ascend_Map = + evar (hd xs) (* [xs] is the vector of arguments; pick the first one *) + +end + +(* The subclass [ascend_endo] defines the standard behavior of an [endo] + visitor, which is to perform physical equality tests. *) + +(* Its parameters are as follows: + + [this] (a variable for) the data structure that is visited + [subjects] the matrix of arguments to the recursive calls + [rs], [ss] (vectors of variables for) the results of the recursive calls *) + +class virtual ascend_endo + (this : variable) + (subjects : expressions list) + (rs : variables) + (ss : variables) += object (self) + + inherit ascend ss + + (* An [endo] visitor first tests if the arguments of the recursive calls, + [subjects], are physically equal to the results of these calls, [rs]. If + that is the case, then it returns the original data structure, [this]. + Otherwise, it reconstructs a new data structure, like a [map] visitor. *) + method! ascend_Endo = + (* [subjects] is a matrix of width [arity], and [arity] is [1]. The first + column of [subjects] is [map hd subjects]. *) + assert (for_all (fun es -> length es = arity) subjects); + assert (arity = 1); + Exp.ifthenelse + (eqphys (map hd subjects) (evars rs)) + (evar this) + (Some self#ascend_Map) + +end + +(* The subclass [ascend_tuple] defines the desired behavior at tuple types. *) + +class ascend_tuple this subjects rs ss = object + + inherit ascend_endo this subjects rs ss + + (* A [map] visitor reconstructs a tuple. *) + method ascend_Map = + tuple (evars rs) + +end + +(* The subclass [ascend_algebraic] defines the desired behavior at a sum type + or record type. Its extra parameters are as follows: + + [builder] how to reconstruct a data constructor or record + [decl] the type declaration under which we are working + [m] the name of the virtual ascending method + [tys] the types of the components of this data constructor or record *) + +class ascend_algebraic this subjects rs ss + (builder : builder) + (decl : type_declaration) + (m : methode) + (tys : core_types) += object + + inherit ascend_endo this subjects rs ss + + (* A [map] visitor reconstructs a data structure using the results [rs] of + the recursive calls. *) + method ascend_Map = + builder rs + + (* A [fold] visitor invokes the virtual ascending method [m], with [env] and + [rs] as arguments. As a side effect, [ascend_Fold] declares this virtual + method. *) + method! ascend_Fold = + vhook m + (env :: rs) + (ty_arrows + (ty_env :: map fold_result_type tys) + (decl_result_type decl) + ) + +end + +(* -------------------------------------------------------------------------- *) + +(* [visit_type env_in_scope ty] builds a small expression that represents the + visiting code associated with the OCaml type [ty]. For instance, if [ty] is + a local type constructor, this could be a call to the visitor method + associated with this type constructor. *) + +(* This expression may refer to the variable [self]. *) + +(* If [env_in_scope] is true, then this expression may refer to the variable + [env]. If [env_in_scope] is false, then this expression should denote a + function of [env]. The use of [env_in_scope] complicates things slightly, + but allows us to avoid the production of certain eta-redexes. *) + +(* If [ty] carries the attribute [@opaque], then we act as if there is nothing + to visit. The nature of the type [ty], in that case, plays no role. *) + +let rec visit_type (env_in_scope : bool) (ty : core_type) : expression = + match env_in_scope, opacity ty.ptyp_attributes, ty.ptyp_desc with + + (* A type constructor [tycon] applied to type parameters [tys]. We handle + the case where [env_in_scope] is false, so we construct a function of + [env]. *) + | false, + NonOpaque, + Ptyp_constr ({ txt = tycon; _ }, tys) -> + (* [tycon] is a type constructor, applied to certain types [tys]. *) + (* We must call the visitor method associated with [tycon], + applied to the visitor functions associated with SOME of the [tys]. *) + let m, tys = + match is_local X.decls tycon with + | Some decl -> + let formals = decl_params decl in + (* [tycon] is a local type constructor, whose formal type parameters + are [formals]. Among these formal type parameters, some should be + treated in a monomorphic manner, and some should be treated in a + polymorphic manner. The function [X.poly], applied to a type + variable [formal], tells how it should be treated. *) + (* The regularity check is applied only to [mono] parameters. *) + check_regularity ty.ptyp_loc (last tycon) formals tys; + (* The visitor method should be applied to the visitor functions + associated with the subset of [tys] that corresponds to [poly] + variables. *) + local_tycon_visitor_method decl, + filter2 X.poly formals tys + | None -> + (* [tycon] is a nonlocal type constructor. *) + (* The visitor method should be applied to visitor functions for all + of the types [tys]. *) + (* This visitor method is NOT generated by us, so it MUST be + inherited from an ancestor class; it is up to the user to + ensure that this method exists. (It may be virtual.) This + method may be polymorphic, so multiple call sites do not + pollute one another. *) + nonlocal_tycon_visitor_method ty, + tys + in + app + (call m []) + (map (visit_type false) tys) + + (* A type variable [alpha] must be a formal parameter of the current + declaration. (Indeed, we do not handle GADTs yet.) Now, two cases + arise. If [alpha] is [mono], then it is handled by a virtual visitor + method. If [alpha] is [poly], then it is handled by a visitor function + which we must have received as an argument. *) + | false, + NonOpaque, + Ptyp_var alpha -> + if X.poly alpha then + evar (tyvar_visitor_function alpha) + else + vhook (tyvar_visitor_method alpha) [] tyvar_visitor_method_type + + (* A tuple type. We handle the case where [env_in_scope] is true, as it + is easier. *) + | true, + NonOpaque, + Ptyp_tuple tys -> + (* Construct a function that takes [arity] tuples as arguments. *) + (* See [constructor_declaration] for comments. *) + let xss = componentss tys in + let subjects = evarss xss in + let rs = results xss + and ss = summaries xss in + let ascend = new ascend_tuple this subjects rs ss in + plambdas + (alias this (ptuples (transpose arity (pvarss xss)))) + (bulk rs ss tys subjects ascend) + + (* If [env_in_scope] does not have the desired value, wrap a recursive call + within an application or abstraction. At most one recursive call takes + place, so we never produce an eta-redex. *) + | true, NonOpaque, (Ptyp_constr _ | Ptyp_var _) -> + app (visit_type false ty) [evar env] + | false, _, _ -> + lambda env (visit_type true ty) + + (* If [ty] is marked opaque, then we ignore the structure of [ty] and carry + out appropriate action, based on the current scheme. *) + | true, Opaque, _ -> + (* Construct a function that takes [arity] arguments. *) + lambdas things ( + let ascend = new ascend_opaque things in + ascend#ascend + ) + + (* An unsupported construct. *) + | _, _, Ptyp_any + | _, _, Ptyp_arrow _ + | _, _, Ptyp_object _ + | _, _, Ptyp_class _ + | _, _, Ptyp_alias _ + | _, _, Ptyp_variant _ + | _, _, Ptyp_poly _ + | _, _, Ptyp_package _ + | _, _, Ptyp_extension _ -> + unsupported ty + +and visit_types tys (ess : expressions list) : expressions = + (* The matrix [ess] is indexed first by component, then by index [j]. + Thus, to each type [ty], corresponds a row [es] of expressions, + whose length is [arity]. *) + assert (is_matrix (length tys) arity ess); + map2 (fun ty es -> + app (visit_type true ty) es + ) tys ess + +(* -------------------------------------------------------------------------- *) + +(* The expression [bulk rs ss tys subjects ascend] represents the bulk of a + visitor method or visitor function. It performs the recursive calls, binds + their results to [rs] and/or [ss], then runs the ascending code. *) + +and bulk + (rs : variables) (ss : variables) + (tys : core_types) + (subjects : expressions list) + (ascend : < ascend: expression; .. >) += + bind rs ss + (visit_types tys subjects) + (ascend#ascend) + +(* -------------------------------------------------------------------------- *) + +(* [constructor_declaration] turns a constructor declaration (as found in a + declaration of a sum type) into a case, that is, a branch in the case + analysis construct that forms the body of the visitor method for this sum + type. At the same time, it generates several auxiliary method declarations + and definitions. *) + +let constructor_declaration decl (cd : constructor_declaration) : case = + datacon_opacity_warning cd; + let datacon = cd.pcd_name.txt in + + (* This is either a traditional data constructor, whose components are + anonymous, or a data constructor whose components form an ``inline + record''. This is a new feature of OCaml 4.03. *) + + (* In order to treat these two cases uniformly, we extract the following + information. + [xss] the names under which the components are known. + this matrix has [length tys] rows -- one per component -- + and [arity] columns. + [tys] the types of the components. + [pss] the patterns that bind [xss], on the way down. + this matrix has [arity] rows. + it has [length tys] columns in the case of tuples, + and 1 column in the case of inline records. + [builder] a function which, applied to the results [rs] of the + recursive calls, rebuilds a data constructor, on the way up. + *) + + let xss, tys, pss, (builder : builder) = + match data_constructor_variety cd with + (* A traditional data constructor. *) + | DataTraditional tys -> + let xss = componentss tys in + let pss = transpose arity (pvarss xss) in + xss, tys, pss, fun rs -> constr datacon (evars rs) + (* An ``inline record'' data constructor. *) + | DataInlineRecord (labels, tys) -> + let xss = fieldss labels in + let pss = transpose arity (pvarss xss) in + xss, tys, + map (fun ps -> [precord ~closed:Closed (combine labels ps)]) pss, + fun rs -> constr datacon [record (combine labels (evars rs))] + in + assert (is_matrix (length tys) arity xss); + assert (length pss = arity); + let subjects = evarss xss in + + (* Take a [@build] attribute into account. *) + let builder = ifbuild cd.pcd_attributes builder in + + (* Find out which type variables [alphas] are formal parameters of this + declaration and are marked [poly]. We have to universally quantify over + (variants of) these type variables in the type of the hook, below. + Furthermore, we forbid these type variables from appearing under [@opaque], + as that would cause us to generate code whose actual type is less general + than its expected type. *) + let alphas = poly_params decl in + check_poly_under_opaque alphas tys; + + (* Create new names [rs] and [ss] for the results of the recursive calls of + visitor methods. *) + let rs = results xss + and ss = summaries xss in + + (* Construct a case for this data constructor in the visitor method associated + with this sum type. This case analyzes a tuple of width [arity]. After + binding the components [xss], we call the descending method associated with + this data constructor. The arguments of this method are: + 1. visitor functions for [poly] type variables; + 2. [env]; + 3. [this] (see below); + 4. [xss]. + In this method, we bind the variables [rs] and/or [ss] to the results of + the recursive calls to visitor methods, then produce a result (whose nature + depends on [scheme]). *) + + (* If the variety is [endo] (which implies that [arity] is 1), then we bind + the variable [this] to the whole memory block. This variable is transmitted + to the descending method. When the time comes to allocate a new memory + block, if the components of the new block are physically equal to the + components of the existing block, then the address of the existing block is + returned; otherwise a new block is allocated, as in [map]. *) + + let ascend = + new ascend_algebraic + this subjects rs ss + builder decl (datacon_ascending_method cd) tys + in + + Exp.case + (ptuple (alias this (map (pconstr datacon) pss))) + (hook X.data + (datacon_descending_method cd) + (map tyvar_visitor_function alphas @ env :: transmit this (flatten xss)) + (quantify alphas (ty_arrows + (map visitor_param_type alphas) + (visitor_fun_type (transmit (decl_type decl) tys) (decl_type decl)))) + (bulk rs ss tys subjects ascend) + ) + +(* -------------------------------------------------------------------------- *) + +(* [visit_decl decl] constructs an expression that represents the visiting + code associated with the type declaration [decl]. In other words, it is + the body of the visitor method associated with [decl]. *) + +let visit_decl (decl : type_declaration) : expression = + + (* Check that the user does not use a reserved type variable name. *) + decl_params decl |> iter (fun alpha -> + if mem alpha reserved then + let loc = decl.ptype_loc in + raise_errorf ~loc "%s: the type variable name '%s is reserved." + plugin alpha + ); + + (* Bind the values to a vector of variables [xs]. *) + let xs = things in + assert (length xs = arity); + + match decl.ptype_kind, decl.ptype_manifest with + + (* A type abbreviation. *) + | Ptype_abstract, Some ty -> + visit_type true ty + + (* A record type. *) + | Ptype_record (lds : label_declaration list), _ -> + let labels, tys = ld_labels lds, ld_tys (fix lds) in + (* See [constructor_declaration] for comments. *) + check_poly_under_opaque (poly_params decl) tys; + let builder rs = record (combine labels (evars rs)) in + let builder = ifbuild decl.ptype_attributes builder in + let subjects = accesses xs labels in + let rs = results labels + and ss = summaries labels in + let ascend = + new ascend_algebraic + (hd xs) subjects rs ss + builder decl (tycon_ascending_method decl) tys + in + lambdas xs (bulk rs ss tys subjects ascend) + + (* A sum type. *) + | Ptype_variant (cds : constructor_declaration list), _ -> + sum_build_warning decl; + (* Generate one case per data constructor. Place these cases in a + [match] construct, which itself is placed in a function body. *) + (* If [arity] is greater than 1 and if there is more than one data + constructor, then generate also a default case. In this default + case, invoke the failure method, which raises an exception. The + failure method receives [env] and [xs] as arguments. *) + let default() : case = + Exp.case + (ptuple (pvars xs)) + (hook true + (failure_method decl) + (env :: xs) + (quantify (poly_params decl) (visitor_method_type decl)) + (efail (local_tycon_visitor_method decl)) + ) + in + let complete (cs : case list) : case list = + if arity = 1 || length cs <= 1 then cs else cs @ [ default() ] + in + lambdas xs ( + Exp.match_ + (tuple (evars xs)) + (complete (map (constructor_declaration decl) cds)) + ) + + (* Unsupported constructs. *) + | Ptype_abstract, None -> + let loc = decl.ptype_loc in + raise_errorf ~loc "%s: cannot deal with abstract types." plugin + + | Ptype_open, _ -> + let loc = decl.ptype_loc in + raise_errorf ~loc "%s: cannot deal with open types." plugin + +(* -------------------------------------------------------------------------- *) + +(* [type_decl decl] generates the main visitor method associated with the type + declaration [decl], as well as the necessary auxiliary methods. It returns + no result. *) + +let type_decl (decl : type_declaration) : unit = + let alphas = poly_params decl in + generate_concrete_method + (local_tycon_visitor_method decl) + (lambdas (map tyvar_visitor_function alphas @ [env]) (visit_decl decl)) + (quantify alphas (ty_arrows (map visitor_param_type alphas) (visitor_method_type decl))) + +(* -------------------------------------------------------------------------- *) + +(* [type_decls decls] processes the type declarations [decl] and produces a + list of structure items. It is the main entry point inside the body of + the functor [Setup]. *) + +let type_decls (decls : type_declaration list) : structure = + (* Analyze the type definitions, and populate our classes with methods. *) + iter type_decl decls; + (* Emit our preprocessor warnings (if any). *) + warnings() @ + (* In the generated code, disable certain warnings, so that the user sees + no warnings, even if she explicitly enables them. We disable warnings + 26, 27 (unused variables) and 4 (fragile pattern matching; a feature + intentionally exploited by [iter2] and [map2]). *) + [ with_warnings "-4-26-27" ( + (* Surround the generated code with floating attributes, which can be + used as markers to find and review the generated code. We use this + mechanism to show the generated code in the documentation. *) + floating "VISITORS.BEGIN" [] :: + (* Produce a class definition. *) + (* Our classes are parameterized over the type variable ['env]. They are + also parameterized over the type variable ['self], with a constraint + that this is the type of [self]. This trick allows us to omit the types + of the virtual methods, even if these types include type variables. *) + dump X.concrete X.ancestors [ ty_self, Invariant ] pself X.name :: + floating "VISITORS.END" [] :: + [] + )] + +end + +(* -------------------------------------------------------------------------- *) + +(* [type_decls decls] produces a list of structure items (that is, toplevel + definitions) associated with the type declarations [decls]. It is the + main entry point outside of the functor [Setup]. *) + +let type_decls ~options ~path:_ (decls : type_declaration list) : structure = + assert (decls <> []); + let module Process = Setup(Parse(struct + let loc = (VisitorsList.last decls).ptype_loc (* an approximation *) + let options = options + let decls = decls + end)) in + Process.type_decls decls + +(* -------------------------------------------------------------------------- *) + +(* Register our plugin with [ppx_deriving]. *) + +let () = + register (create plugin ~type_decl_str:type_decls ()) diff --git a/src/Visitors.mli b/src/Visitors.mli new file mode 100644 index 0000000..d3e496f --- /dev/null +++ b/src/Visitors.mli @@ -0,0 +1 @@ +(* This file intentionally empty. *) diff --git a/src/VisitorsAnalysis.ml b/src/VisitorsAnalysis.ml new file mode 100644 index 0000000..6f5dbdf --- /dev/null +++ b/src/VisitorsAnalysis.ml @@ -0,0 +1,387 @@ +open Result +open Longident +open Asttypes +open Parsetree +open Ast_helper +open Ppx_deriving +open VisitorsPlugin + +(* This module offers helper functions for abstract syntax tree analysis. *) + +(* -------------------------------------------------------------------------- *) + +type tycon = string +type tyvar = string +type tyvars = tyvar list + +(* -------------------------------------------------------------------------- *) + +(* Testing whether an identifier is valid. *) + +(* We use OCaml's lexer to analyze the string and check if it is a valid + identifier. This method is slightly unorthodox, as the lexer can have + undesired side effects, such as raising an [Error] exception or printing + warnings. We do our best to hide these effects. The strength of this + approach is to give us (at little cost) a correct criterion for deciding if + an identifier is valid. *) + +(* Note: [Location.formatter_for_warnings] appeared in OCaml 4.02.2. *) + +type classification = + | LIDENT + | UIDENT + | OTHER + +let classify (s : string) : classification = + let lexbuf = Lexing.from_string s in + let backup = !Location.formatter_for_warnings in + let null = Format.formatter_of_buffer (Buffer.create 0) in + Location.formatter_for_warnings := null; + let result = try + let token1 = Lexer.token lexbuf in + let token2 = Lexer.token lexbuf in + match token1, token2 with + | Parser.LIDENT _, Parser.EOF -> + LIDENT + | Parser.UIDENT _, Parser.EOF -> + UIDENT + | _, _ -> + OTHER + with Lexer.Error _ -> + OTHER + in + Location.formatter_for_warnings := backup; + result + +(* -------------------------------------------------------------------------- *) + +(* Testing if a string is a valid [mod_longident], i.e., a possibly-qualified + module identifier. *) + +(* We might wish to use OCaml's parser for this purpose, but [mod_longident] is + not declared as a start symbol. Furthermore, that would be perhaps slightly + too lenient, e.g., allowing whitespace and comments inside. Our solution is + to split at the dots using [Longident.parse], then check that every piece + is a valid module name. *) + +let is_valid_mod_longident (m : string) : bool = + String.length m > 0 && + let ms = Longident.flatten (Longident.parse m) in + List.for_all (fun m -> classify m = UIDENT) ms + +(* -------------------------------------------------------------------------- *) + +(* Testing if a string is a valid [class_longident], i.e., a possibly-qualified + class identifier. *) + +let is_valid_class_longident (m : string) : bool = + String.length m > 0 && + match Longident.parse m with + | Lident c -> + classify c = LIDENT + | Ldot (m, c) -> + List.for_all (fun m -> classify m = UIDENT) (Longident.flatten m) && + classify c = LIDENT + | Lapply _ -> + assert false (* this cannot happen *) + +(* -------------------------------------------------------------------------- *) + +(* 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 + list. By convention, an attribute named [foo] can also be referred to as + [visitors.foo] or as [deriving.visitors.foo]. *) + +(* [select foo attrs] extracts the attribute named [foo] from the attribute + list [attrs]. *) + +let select (foo : string) (attrs : attributes) : attribute option = + attr ~deriver:plugin foo attrs + +(* [present foo attrs] tests whether an attribute named [foo] is present + (with no argument) in the list [attrs]. *) + +let present (foo : string) (attrs : attributes) : bool = + Arg.get_flag ~deriver:plugin (select foo attrs) + +(* [opacity attrs] tests for the presence of an [@opaque] attribute. *) + +type opacity = + | Opaque + | NonOpaque + +let opacity (attrs : attributes) : opacity = + if present "opaque" attrs then Opaque else NonOpaque + +(* [name attrs] tests for the presence of a [@name] attribute, carrying a + payload of type [string]. We check that the payload is a valid (lowercase + or uppercase) identifier, because we intend to use it as the basis of a + method name. *) + +let identifier : string Arg.conv = + fun e -> + match Arg.string e with + | Error msg -> + Error msg + | Ok s -> + match classify s with + | LIDENT | UIDENT -> + Ok s + | OTHER -> + Error "identifier" + +let name (attrs : attributes) : string option = + Arg.get_attr ~deriver:plugin identifier (select "name" attrs) + +(* [build attrs] tests for the presence of a [@build] attribute, + carrying a payload that is an arbitrary OCaml expression. *) + +let build (attrs : attributes) : expression option = + Arg.get_attr ~deriver:plugin Arg.expr (select "build" attrs) + +(* [maybe ox y] returns [x] if present, otherwise [y]. *) + +let maybe (ox : 'a option) (y : 'a) : 'a = + match ox with Some x -> x | None -> y + +(* -------------------------------------------------------------------------- *) + +(* When parsing a record declaration, the OCaml parser attaches attributes + with field labels, whereas the user might naturally expect them to be + attached with the type. We rectify this situation by copying all attributes + from the label to the type. This might seem dangerous, but we use it only + to test for the presence of an [@opaque] attribute. *) + +let paste (ty : core_type) (attrs : attributes) : core_type = + { ty with ptyp_attributes = attrs @ ty.ptyp_attributes } + +let fix (ld : label_declaration) : label_declaration = + { ld with pld_type = paste ld.pld_type ld.pld_attributes } + +let fix = + List.map fix + +(* -------------------------------------------------------------------------- *) + +(* [type_param_to_tyvar] expects a type parameter as found in the field + [ptype_params] of a type definition, and returns the underlying type + variable. *) + +let type_param_to_tyvar ((ty, _) : core_type * variance) : tyvar = + match ty.ptyp_desc with + | Ptyp_var tv -> + tv + | Ptyp_any -> + (* This error occurs if a formal type parameter is a wildcard [_]. + We could support this form, but it makes life slightly simpler + to disallow it. It is usually used only in GADTs anyway. *) + raise_errorf ~loc:ty.ptyp_loc + "%s: every formal type parameter should be named." plugin + | _ -> + assert false + +let type_params_to_tyvars = + List.map type_param_to_tyvar + +(* [decl_params decl] returns the type parameters of the declaration [decl]. *) + +let decl_params (decl : type_declaration) : tyvars = + type_params_to_tyvars decl.ptype_params + +(* [is_local decls tycon] tests whether the type constructor [tycon] is + declared by the type declarations [decls]. If so, it returns the + corresponding declaration. *) + +let rec is_local (decls : type_declaration list) (tycon : tycon) +: type_declaration option = + match decls with + | [] -> + None + | decl :: decls -> + if decl.ptype_name.txt = tycon then + Some decl + else + is_local decls tycon + +let is_local (decls : type_declaration list) (tycon : Longident.t) +: type_declaration option = + match tycon with + | Lident tycon -> + is_local decls tycon + | Ldot _ + | Lapply _ -> + None + +(* -------------------------------------------------------------------------- *) + +(* [occurs_type alpha ty] tests whether the type variable [alpha] occurs in + the type [ty]. This function goes down into all OCaml types, even those + that are not supported by [visitors]. *) + +exception Occurs of loc + +let rec occurs_type (alpha : tyvar) (ty : core_type) : unit = + match ty.ptyp_desc with + | Ptyp_any -> + () + | Ptyp_var beta -> + if alpha = beta then + raise (Occurs ty.ptyp_loc) + | Ptyp_alias (ty, _) -> + (* This is not a binder; just go down into it. *) + occurs_type alpha ty + | Ptyp_arrow (_, ty1, ty2) -> + occurs_types alpha [ ty1; ty2 ] + | Ptyp_tuple tys + | Ptyp_constr (_, tys) + | Ptyp_class (_, tys) -> + occurs_types alpha tys + | Ptyp_object (fields, _) -> + fields + |> List.map VisitorsCompatibility.object_field_to_core_type + |> occurs_types alpha + | Ptyp_variant (fields, _, _) -> + List.iter (occurs_row_field alpha) fields + | Ptyp_poly (qs, ty) -> + let qs : string list = VisitorsCompatibility.quantifiers qs in + (* The type variables in [qs] are bound. *) + 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) -> + occurs_payload alpha payload + +and occurs_types alpha tys = + List.iter (occurs_type alpha) tys + +and occurs_row_field alpha field = + field + |> VisitorsCompatibility.row_field_to_core_types + |> occurs_types alpha + +and occurs_quantifiers alpha (qs : string list) = + List.mem alpha qs + +and occurs_payload alpha = function + | PTyp ty -> + occurs_type alpha ty + (* | PStr _ | PPat _ *) + (* | PSig _ (* >= 4.03 *) *) + | _ -> + (* We assume that these cases won't arise or won't have any free type + variables in them. *) + () + +(* -------------------------------------------------------------------------- *) + +(* An error message about an unsupported type. *) + +let unsupported ty = + let loc = ty.ptyp_loc in + raise_errorf ~loc + "%s: cannot deal with the type %s.\n\ + Consider annotating it with [@opaque]." + plugin + (string_of_core_type ty) + +(* -------------------------------------------------------------------------- *) + +(* [at_opaque f ty] applies the function [f] to every [@opaque] component of + the type [ty]. *) + +let rec at_opaque (f : core_type -> unit) (ty : core_type) : unit = + match opacity ty.ptyp_attributes, ty.ptyp_desc with + | NonOpaque, Ptyp_any + | NonOpaque, Ptyp_var _ -> + () + | NonOpaque, Ptyp_tuple tys + | NonOpaque, Ptyp_constr (_, tys) -> + List.iter (at_opaque f) tys + | Opaque, _ -> + f ty + | NonOpaque, Ptyp_arrow _ + | NonOpaque, Ptyp_object _ + | NonOpaque, Ptyp_class _ + | NonOpaque, Ptyp_alias _ + | NonOpaque, Ptyp_variant _ + | NonOpaque, Ptyp_poly _ + | NonOpaque, Ptyp_package _ + | NonOpaque, Ptyp_extension _ -> + unsupported ty + +(* -------------------------------------------------------------------------- *) + +(* [check_poly_under_opaque alphas tys] checks that none of the type variables + [alphas] appears under [@opaque] in the types [tys]. *) + +let check_poly_under_opaque alphas tys = + List.iter (fun alpha -> + List.iter (fun ty -> + at_opaque (fun ty -> + try + occurs_type alpha ty + with Occurs loc -> + raise_errorf ~loc + "%s: a [polymorphic] type variable must not appear under @opaque." + plugin + ) ty + ) tys + ) alphas + +(* -------------------------------------------------------------------------- *) + +(* [subst_type sigma ty] applies [sigma], a substitution of types for type + variables, to the type [ty]. + + [rename_type rho ty] applies [rho], a renaming of type variables, to the + type [ty]. *) + +(* We do not go down into [@opaque] types. We replace every opaque type with a + wildcard [_]. Because we have checked that [poly] variables do not appear + under [@opaque], this is good enough: there is never a need for an + explicitly named/quantified type variable to describe an opaque + component. *) + +type substitution = + tyvar -> core_type + +type renaming = + tyvar -> tyvar + +let rec subst_type (sigma : substitution) (ty : core_type) : core_type = + match opacity ty.ptyp_attributes, ty.ptyp_desc with + | NonOpaque, Ptyp_any -> + ty + | NonOpaque, Ptyp_var alpha -> + sigma alpha + | NonOpaque, Ptyp_tuple tys -> + { ty with ptyp_desc = Ptyp_tuple (subst_types sigma tys) } + | NonOpaque, Ptyp_constr (tycon, tys) -> + { ty with ptyp_desc = Ptyp_constr (tycon, subst_types sigma tys) } + | Opaque, _ -> + Typ.any() + | NonOpaque, Ptyp_arrow _ + | NonOpaque, Ptyp_object _ + | NonOpaque, Ptyp_class _ + | NonOpaque, Ptyp_alias _ + | NonOpaque, Ptyp_variant _ + | NonOpaque, Ptyp_poly _ + | NonOpaque, Ptyp_package _ + | NonOpaque, Ptyp_extension _ -> + unsupported ty + +and subst_types sigma tys = + List.map (subst_type sigma) tys + +let rename_type (rho : renaming) (ty : core_type) : core_type = + subst_type (fun alpha -> Typ.var (rho alpha)) ty diff --git a/src/VisitorsCompatibility.cppo.ml b/src/VisitorsCompatibility.cppo.ml new file mode 100644 index 0000000..de1c705 --- /dev/null +++ b/src/VisitorsCompatibility.cppo.ml @@ -0,0 +1,171 @@ +let mknoloc = Location.mknoloc +open Asttypes +open Parsetree +open Ast_helper + +(* OCaml's abstract syntax tree evolves with time. We depend on this tree + because we analyze it (that is, we analyze type definitions) and because we + construct it (that is, we generate code). This module gathers the ugly bits + whose definition varies depending on the version of OCaml that we are + working with. *) + +#if OCAML_VERSION < (4, 03, 0) +#define Nolabel "" +#endif + +(* Constructing an arrow type. *) + +let ty_arrow (a : core_type) (b : core_type) : core_type = + Typ.arrow Nolabel a b + +(* Constructing a function. *) + +let plambda (p : pattern) (e : expression) : expression = + Exp.fun_ Nolabel None p e + +(* Constructing a string literal. *) + +let const_string (w : string) = +#if OCAML_VERSION < (4, 03, 0) + Const_string (w, None) +#else + Const.string w +#endif + +(* [ld_label] and [ld_ty] extract a label and type out of an OCaml record label + declaration. *) + +let ld_label (ld : label_declaration) : label = + ld.pld_name.txt + +let ld_labels = + List.map ld_label + +let ld_ty (ld : label_declaration) : core_type = + ld.pld_type + +let ld_tys = + List.map ld_ty + +(* Analyzing the definition of a data constructor. *) + +(* A data constructor is either a traditional data constructor, whose + components are anonymous, or a data constructor whose components + form an ``inline record''. This is a new feature of OCaml 4.03. *) + +type data_constructor_variety = + | DataTraditional of core_type list + | DataInlineRecord of label list * core_type list + +let data_constructor_variety (cd : constructor_declaration) = + #if OCAML_VERSION < (4, 03, 0) + DataTraditional cd.pcd_args + #else + match cd.pcd_args with + (* A traditional data constructor. *) + | Pcstr_tuple tys -> + DataTraditional tys + (* An ``inline record'' data constructor. *) + | 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 (field : object_field) : core_type = + #if OCAML_VERSION < (4, 06, 0) + match field with + | (_, _, ty) -> ty + #elif OCAML_VERSION < (4, 08, 0) + match field with + | 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 *) + #else + match field.pof_desc with + | Otag (_, ty) -> ty + | Oinherit ty -> ty + #endif + +let row_field_to_core_types (field : row_field) : core_type list = + #if OCAML_VERSION < (4, 08, 0) + match field with + | Rtag (_, _, _, tys) -> + tys + | Rinherit ty -> + [ ty ] + #else + match field.prf_desc with + | Rtag (_, _, tys) -> + tys + | Rinherit ty -> + [ ty ] + #endif + +(* -------------------------------------------------------------------------- *) + +(* [floating s items] produces a floating attribute whose name is [s] and + whose payload is the list of structure items [items]. *) + +(* The type [attribute] is defined in 4.07 as [string loc * payload], but in + 4.08 its definition changes to a record type and the function [Attr.mk] + appears. *) + +let floating (s : string) (items : structure) : structure_item = + let name = mknoloc s + and payload = PStr items in + #if OCAML_VERSION < (4, 08, 0) + Str.attribute (name, payload) + #else + Str.attribute (Attr.mk name payload) + #endif diff --git a/src/VisitorsGeneration.ml b/src/VisitorsGeneration.ml new file mode 100644 index 0000000..5ca3606 --- /dev/null +++ b/src/VisitorsGeneration.ml @@ -0,0 +1,583 @@ +open Longident +let mknoloc = Location.mknoloc +open Asttypes +open Parsetree +open Ast_helper +open Ast_convenience +open VisitorsList +open VisitorsAnalysis +open VisitorsCompatibility + +(* This module offers helper functions for code generation. *) + +(* -------------------------------------------------------------------------- *) + +(* Type abbreviations. *) + +type variable = string +type datacon = string +type label = string +type classe = string +type methode = string +type tyvar = string + +type variables = variable list +type tyvars = tyvar list +type core_types = core_type list +type patterns = pattern list +type expressions = expression list + +(* -------------------------------------------------------------------------- *) + +(* We normally place a [Pervasives] prefix in front of OCaml's operators, so as + to ensure that our code makes sense even if these operators are shadowed by + the user. (That said, we still run into trouble if the user shadows the name + [Pervasives] itself.) *) + +(* When producing code for inclusion in the documentation, we remove the + [Pervasives] prefix, just so that things look pretty. We rely on an + undocumented environment variable to toggle this behavior. *) + +let pervasive (x : string) : Longident.t = + try + let _ = Sys.getenv "VISITORS_BUILDING_DOCUMENTATION" in + Lident x + (* danger: the name [x] must not be shadowed. *) + with Not_found -> + Ldot (Lident "Pervasives", x) + (* danger: the name [Pervasives] must not be shadowed. *) + +(* We normally place an improbable prefix in front of our private (local) + variables, so as to make sure that we do not shadow user variables that + are used in [@build] code fragments. *) + +(* When producing code for inclusion in the documentation, we remove this + prefix. *) + +let improbable (x : string) : string = + try + let _ = Sys.getenv "VISITORS_BUILDING_DOCUMENTATION" in + x + with Not_found -> + "_visitors_" ^ x + +(* -------------------------------------------------------------------------- *) + +(* Types. *) + +let ty_var (alpha : tyvar) : core_type = + Typ.var alpha + +let ty_vars (alphas : tyvars) : core_types = + List.map ty_var alphas + +let ty_any = + Typ.any() + +let ty_unit = + tconstr "unit" [] + +(* For [ty_arrow], see [VisitorsCompatibility]. *) + +let ty_arrows : core_types -> core_type -> core_type = + List.fold_right ty_arrow + +(* [decl_type decl] turns a declaration of the type ['a foo] into a the type + ['a foo]. *) + +let decl_type (decl : type_declaration) : core_type = + tconstr decl.ptype_name.txt (ty_vars (decl_params decl)) + +(* -------------------------------------------------------------------------- *) + +(* [unit] produces a unit constant. [tuple] produces a tuple. [record] + produces a record. These functions already exist; we redefine them without + any optional arguments so as avoid OCaml's warning 48 (implicit elimination + of optional arguments). *) + +let unit() = + unit() + +let tuple es = + tuple es + +let record les = + record les + +(* -------------------------------------------------------------------------- *) + +(* [number i thing] constructs an English description of "[i] thing(s)". *) + +let number i s = + match i with + | 0 -> + Printf.sprintf "zero %s" s + | 1 -> + Printf.sprintf "one %s" s + | _ -> + Printf.sprintf "%d %ss" i s + +(* -------------------------------------------------------------------------- *) + +(* [eident] converts a (possibly-qualified) identifier to an expression. *) + +let eident (id : Longident.t) : expression = + Exp.ident (mknoloc id) + +(* -------------------------------------------------------------------------- *) + +(* [pvars] converts a list of variables to a list of patterns. *) + +let pvars (xs : variables) : patterns = + List.map (fun x -> pvar x) xs + +(* [evars] converts a list of variables to a list of expressions. *) + +let evars (xs : variables) : expressions = + List.map (fun x -> evar x) xs + +(* [pvarss] converts a matrix of variables to a matrix of patterns. *) + +let pvarss (xss : variables list) : patterns list = + List.map pvars xss + +(* [evarss] converts a matrix of variables to a matrix of expressions. *) + +let evarss (xss : variables list) : expressions list = + List.map evars xss + +(* -------------------------------------------------------------------------- *) + +(* [wildcards] converts a list of anything to a list of wildcard patterns. *) + +let wildcards xs = + List.map (fun _ -> Pat.any()) xs + +(* -------------------------------------------------------------------------- *) + +(* [plambda p e] constructs a function [fun p -> e]. *) + +(* For [plambda], see [VisitorsCompatibility]. *) + +(* [lambda x e] constructs a function [fun x -> e]. *) + +let lambda (x : variable) (e : expression) : expression = + plambda (pvar x) e + +(* [plambdas ps e] constructs a multi-argument function [fun ps -> e]. *) + +let plambdas (ps : patterns) (e : expression) : expression = + List.fold_right plambda ps e + +(* [lambdas xs e] constructs a multi-argument function [fun xs -> e]. *) + +let lambdas (xs : variables) (e : expression) : expression = + List.fold_right lambda xs e + +(* -------------------------------------------------------------------------- *) + +(* [app] works like [Ast_convenience.app] (which it shadows), except it avoids + constructing nested applications of the form [(f x) y], transforming them + instead into a single application [f x y]. The difference is probably just + cosmetic. *) + +let app (e : expression) (es2 : expressions) : expression = + match e.pexp_desc with + | Pexp_apply (e1, les1) -> + let les2 = List.map (fun e -> Label.nolabel, e) es2 in + { e with pexp_desc = Pexp_apply (e1, les1 @ les2) } + | _ -> + app e es2 + +(* -------------------------------------------------------------------------- *) + +(* [sequence es] constructs a sequence of the expressions [es]. *) + +let sequence (es : expressions) : expression = + (* Using [fold_right1] instead of [List.fold_right] allows us to get + rid of a final [()] constant at the end of the sequence. Cosmetic. *) + fold_right1 + (fun e accu -> Exp.sequence e accu) + es + (unit()) + +(* -------------------------------------------------------------------------- *) + +(* [vblet1 vb e] constructs a single [let] binding. *) + +let vblet1 (vb : value_binding) (e : expression) : expression = + Exp.let_ Nonrecursive [vb] e + +(* [let1 x e1 e2] constructs a single [let] binding. *) + +let let1 (x : variable) (e1 : expression) (e2 : expression) : expression = + vblet1 (Vb.mk (pvar x) e1) e2 + +(* [let1p x y e1 e2] constructs a single [let] binding of a pair. *) + +let let1p (x, y : variable * variable) (e1 : expression) (e2 : expression) : expression = + vblet1 (Vb.mk (ptuple [pvar x; pvar y]) e1) e2 + +(* [vbletn vbs e] constructs a series of nested [let] bindings. *) + +let vbletn (vbs : value_binding list) (e : expression) : expression = + List.fold_right vblet1 vbs e + +(* [letn xs es e] constructs a series of nested [let] bindings. *) + +let letn (xs : variables) (es : expressions) (e : expression) = + List.fold_right2 let1 xs es e + +(* [letnp xs ys es e] constructs a series of nested [let] bindings of pairs. *) + +let letnp (xs : variables) (ys : variables) (es : expressions) (e : expression) = + List.fold_right2 let1p (List.combine xs ys) es e + +(* -------------------------------------------------------------------------- *) + +(* [access x label] constructs a record access expression [x.label]. *) + +let access (x : variable) (label : label) : expression = + Exp.field (evar x) (mknoloc (Lident label)) + +(* [accesses labels xs] constructs a matrix of record access expressions of + the form [x.label]. There is a row for every [label] and a column for every + [x]. *) + +let accesses (xs : variables) (labels : label list) : expressions list = + List.map (fun label -> List.map (fun x -> access x label) xs) labels + +(* -------------------------------------------------------------------------- *) + +(* [ptuple] is [Ast_convenience.ptuple], deprived of its optional arguments. *) + +let ptuple (ps : patterns) : pattern = + ptuple ps + +(* [ptuples] is [map ptuple]. *) + +let ptuples (pss : patterns list) : patterns = + List.map ptuple pss + +(* -------------------------------------------------------------------------- *) + +(* The Boolean expressions [false] and [true]. *) + +let efalse : expression = + Exp.construct (mknoloc (Lident "false")) None + +let etrue : expression = + Exp.construct (mknoloc (Lident "true")) None + +(* -------------------------------------------------------------------------- *) + +(* [conjunction es] constructs a Boolean conjunction of the expressions [es]. *) + +let conjunction : expression = + eident (pervasive "&&") + +let conjunction e1 e2 = + app conjunction [e1; e2] + +let conjunction (es : expressions) : expression = + fold_right1 conjunction es etrue + +(* -------------------------------------------------------------------------- *) + +(* [eassertfalse] is the expression [assert false]. *) + +let eassertfalse : expression = + Exp.assert_ efalse + +(* -------------------------------------------------------------------------- *) + +(* [eforce e] is the expression [Lazy.force e]. *) + +let eforce : expression = + eident (Longident.parse "Lazy.force") + (* danger: the module name [Lazy] must not be shadowed. *) + +let eforce (e : expression) : expression = + app eforce [e] + +(* -------------------------------------------------------------------------- *) + +(* [eqphy e1 e2] is the expression [e1 == e2]. *) + +let eqphy : expression = + eident (pervasive "==") + +let eqphy (e1 : expression) (e2 : expression) : expression = + app eqphy [e1; e2] + +(* [eqphys es1 es2] is the conjunction of the expressions [e1 == e2]. *) + +let eqphys (es1 : expressions) (es2 : expressions) : expression = + assert (List.length es1 = List.length es2); + conjunction (List.map2 eqphy es1 es2) + +(* -------------------------------------------------------------------------- *) + +(* [efail s] generates a call to [VisitorsRuntime.fail]. The parameter [s] is + a string, which could represent the place where a failure occurred, or the + reason why a failure occurred. As of now, it is unused. *) + +let efail : expression = + eident (Ldot (Lident "VisitorsRuntime", "fail")) + (* danger: the module name [VisitorsRuntime] must not be shadowed. *) + +let efail (_ : string) : expression = + app efail [ unit() ] + +(* -------------------------------------------------------------------------- *) + +(* [include_ e] constructs an [include] declaration. *) + +let include_ (e : module_expr) : structure_item = + Str.include_ { + pincl_mod = e; + pincl_loc = Location.none; + pincl_attributes = []; + } + +(* -------------------------------------------------------------------------- *) + +(* [with_warnings w items] wraps the structure items [items] in such a way + that the warning directive [w] is applied to these items. Technically, this + is done by emitting [include struct [@@@ocaml.warning ] end]. *) + +let with_warnings (w : string) (items : structure_item list) : structure_item = + include_ (Mod.structure ( + floating "ocaml.warning" [ Str.eval (Exp.constant (const_string w)) ] + :: items + )) + +(* -------------------------------------------------------------------------- *) + +(* [class1 concrete ancestors params name self fields] builds a class + declaration and packages it as a structure item. (This implies that it + cannot be recursive with other class declarations). *) + +let class1 + (concrete : bool) + (params : (core_type * variance) list) + (name : classe) + (self : pattern) + (fields : class_field list) + : structure_item = + Str.class_ [{ + pci_virt = if concrete then Concrete else Virtual; + pci_params = params; + pci_name = mknoloc name; + pci_expr = Cl.structure (Cstr.mk self fields); + pci_loc = !default_loc; + pci_attributes = []; + }] + +(* -------------------------------------------------------------------------- *) + +(* [inherit_ c tys] builds an [inherit] clause, where the superclass is [c] + and its actual type parameters are [tys]. No [super] identifier is bound. *) + +let inherit_ (c : Longident.t) (tys : core_types) : class_field = + Cf.inherit_ Fresh (Cl.constr (mknoloc c) tys) None + +(* -------------------------------------------------------------------------- *) + +(* An algebraic data type of the methods that we generate. These include + concrete methods (with code) and virtual methods (without code). They may + be public or private. The method type is optional. If omitted, then + it is inferred by OCaml. If present, it can be a polymorphic type. *) + +type meth = + Meth of private_flag * methode * expression option * core_type option + +let concrete_method p m e oty = + Meth (p, m, Some e, oty) + +let virtual_method p m oty = + Meth (p, m, None, oty) + +(* -------------------------------------------------------------------------- *) + +(* Converting a method description to OCaml abstract syntax. *) + +let oe2cfk (oe : expression option) (oty : core_type option) : class_field_kind = + match oe, oty with + | Some e, Some _ -> + Cf.concrete Fresh (Exp.poly e oty) + | Some e, None -> + Cf.concrete Fresh e + | None, Some ty -> + Cf.virtual_ ty + | None, None -> + Cf.virtual_ ty_any + +let meth2cf (Meth (p, m, oe, oty)) : class_field = + Cf.method_ (mknoloc m) p (oe2cfk oe oty) + +(* -------------------------------------------------------------------------- *) + +(* [method_name] extracts a method name out of a method description. *) + +let method_name (Meth (_, m, _, _)) : string = + m + +(* -------------------------------------------------------------------------- *) + +(* [is_virtual] tests whether a method description represents a virtual + method. *) + +let is_virtual (Meth (_, _, oe, _)) : bool = + oe = None + +(* -------------------------------------------------------------------------- *) + +(* [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 + +(* -------------------------------------------------------------------------- *) + +(* An algebraic data type of the ``hoisted expressions'' that we generate. *) + +(* A ``hoisted expression'' is evaluated at most once after the object is + allocated. Its value is stored in an instance field. We allow such an + expression to reference [self], as long as it does not actually invoke any + methods. *) + +type hoisted = + Hoisted of string (* the name of the instance field *) + * expression (* the hoisted expression *) + +(* -------------------------------------------------------------------------- *) + +(* Converting a hoisted field description to OCaml abstract syntax. *) + +(* We generate a mutable field declaration, followed with an initialization: + + val mutable x = lazy (assert false) + initializer x <- lazy e + + We must do this in two steps because the expression [e] might contain + references to [self], which are invalid in a field declaration, whereas + they are allowed in an initializer. + + The potential danger in this idiom lies in forcing [x] before the + initializer has finished running, leading to an assertion failure. + This should not happen if [e] does not perform any method calls + or read any fields. *) + +let hoisted2cf (Hoisted (x, e)) : class_field list = + [ + Cf.val_ (mknoloc x) (Mutable) (Cf.concrete Fresh (Exp.lazy_ eassertfalse)); + Cf.initializer_ (Exp.setinstvar (mknoloc x) (Exp.lazy_ e)) + ] + +(* -------------------------------------------------------------------------- *) + +(* A facility for generating a class. *) + +module ClassFieldStore (X : sig end) : sig + + (* [generate meth] adds [meth] to the list of methods. *) + val generate: meth -> unit + + (* [hoist e] causes the expression [e] to be hoisted, that is, computed + once after the object is allocated. The result of evaluating [e] is + stored in a field. The call [hoist e] returns an expression which + reads this field. *) + val hoist: expression -> expression + + (* [dump concrete ancestors params self c] returns a class definition. *) + val dump: + bool -> + Longident.t list -> + (core_type * variance) list -> + pattern -> + classe -> + structure_item + +end = struct + + let meths : meth list ref = + ref [] + + let generate meth = + meths := meth :: !meths + + let dump () : class_field list = + let methods = List.rev !meths in + (* Move all of the virtual methods up front. If two virtual methods have + the same name, keep only one of them. This is useful because we allow + a virtual method declaration to be generated several times. In fact, + OCaml supports this, but it looks tidier if we remove duplicates. *) + let virtual_methods, concrete_methods = List.partition is_virtual methods in + let cmp meth1 meth2 = compare (method_name meth1) (method_name meth2) in + let virtual_methods = VisitorsList.weed cmp virtual_methods in + let methods = virtual_methods @ concrete_methods in + List.map meth2cf methods + + let hoisted : hoisted list ref = + ref [] + + let fresh : unit -> int = + let c = ref 0 in + fun () -> + let x = !c in + c := x + 1; + x + + let hoist (e : expression) : expression = + let x = Printf.sprintf "h%d" (fresh()) in + hoisted := Hoisted (x, e) :: !hoisted; + eforce (evar x) + + let dump concrete ancestors params self c : structure_item = + class1 concrete params c self ( + (* [inherit] clauses. *) + (* We ARBITRARILY assume that every ancestor class is parameterized + with ONE type parameter. *) + List.map (fun c -> inherit_ c [ ty_any ]) ancestors @ + (* Hoisted expressions. *) + List.flatten (List.map hoisted2cf (List.rev !hoisted)) @ + (* Methods. *) + dump() + ) + +end + +(* -------------------------------------------------------------------------- *) + +(* A facility for emitting preprocessor warnings. *) + +(* Warnings must be emitted under the form of [ppwarning] attributes, placed + in the generated code. This is not very convenient; we must store these + warnings, waiting for a convenient time to emit them. *) + +module WarningStore (X : sig end) : sig + + (* [warning loc format ...] emits a warning. *) + val warning: loc -> ('a, unit, string, unit) format4 -> 'a + + (* [warnings()] returns a list of all warnings emitted so far. *) + val warnings: unit -> structure + +end = struct + + let warnings : attribute list ref = + ref [] + + let warning loc msg = + warnings := Ast_mapper.attribute_of_warning loc msg :: !warnings + + let warning loc format = + Printf.ksprintf (warning loc) format + + let warnings () = + let ws = !warnings in + warnings := []; + List.map (fun a -> Str.attribute a) (List.rev ws) + +end diff --git a/src/VisitorsList.ml b/src/VisitorsList.ml new file mode 100644 index 0000000..0455540 --- /dev/null +++ b/src/VisitorsList.ml @@ -0,0 +1,125 @@ +open List + +(* [last xs] returns the last element of the nonempty list [xs]. *) + +let rec last1 x xs = + match xs with + | [] -> + x + | x :: xs -> + last1 x xs + +let last xs = + match xs with + | [] -> + assert false + | x :: xs -> + last1 x xs + +(* [interval i j] constructs a list representation of the semi-open interval + [i..j). *) + +let rec interval i j : int list = + if i < j then + i :: interval (i + 1) j + else + [] + +(* [init i j f] constructs a list of the values [f i] up to [f (j - 1)]. *) + +let init i j (f : int -> 'a) : 'a list = + map f (interval i j) + +(* [is_matrix m n xss] checks that [xss] is an [m]-by-[n] matrix, represented + as a list of lists. *) + +let is_matrix m n (xss : _ list list) = + length xss = m && for_all (fun xs -> length xs = n) xss + +(* [transpose n xss] transposes a matrix, represented as a list of lists. + The parameter [n] is the width of the matrix, and is really useful only + in the case where the matrix has zero height, in which case [transpose] + constructs a matrix of height [n] and zero width. *) + +let transpose (n : int) (xss : 'a list list) : 'a list list = + let m = length xss in + assert (is_matrix m n xss); + (* Convert [xss] to an array, for speed. *) + let xss : 'a array array = + Array.(map of_list (of_list xss)) + in + (* We have an [m]-by-[n] matrix, and construct an [n]-by-[m] matrix. *) + init 0 n (fun j -> + init 0 m (fun i -> + xss.(i).(j) + ) + ) + +(* [hextend xs n f] extends the vertical vector [xs] to a matrix of width [n]. + A vector element [x] is turned into [f j x] in the [j]-th row. *) + +let hextend (xs : 'a list) (n : int) (f : int -> 'a -> 'a) : 'a list list = + map (fun x -> init 0 n (fun j -> f j x)) xs + +(* [uniq cmp xs] assumes that the list [xs] is sorted according to the + ordering [cmp] and returns the list [xs] deprived of any duplicate + elements. *) + +let rec uniq1 cmp x ys = + match ys with + | [] -> + [] + | y :: ys -> + if cmp x y = 0 then + uniq1 compare x ys + else + y :: uniq1 cmp y ys + +let uniq cmp xs = + match xs with + | [] -> + [] + | x :: xs -> + x :: uniq1 cmp x xs + +(* [weed cmp xs] returns the list [xs] deprived of any duplicate elements. *) + +let weed cmp xs = + uniq cmp (List.sort cmp xs) + +(* [fold_right1] is like [fold_right], but uses the last element of the list + (if the list is nonempty) as the initial accumulator, saving one call to + the binary operation [f]. This is equivalent to [fold_right] if [accu] is + a right unit for [f]. *) + +let fold_right1 f xs accu = + match List.rev xs with + | [] -> + accu + | x :: xs -> + let xs = List.rev xs in + (* We have decomposed [xs] as [xs] followed with [x]. We can now + ignore [accu] and use [x] as the initial accumulator in our + right-to-left sweep of the list. *) + List.fold_right f xs x + +(* [fold_left1] is like [fold_left], but uses the first element of the list + (if the list is nonempty) as the initial accumulator, saving one call to + the binary operation [f]. This is equivalent to [fold_left] if [accu] is + a left unit for [f]. *) + +let fold_left1 f accu xs = + match xs with + | [] -> + accu + | x :: xs -> + (* We can ignore [accu] and use [x] as the initial accumulator in + our left-to-right sweep of the list. *) + List.fold_left f x xs + +(* [filter2 f xs ys] returns the list of elements [y] in [ys] such that + the corresponding element [x] in [xs] satisfies [f]. *) + +let filter2 f xs ys = + assert (length xs = length ys); + map snd (filter (fun (x, _y) -> f x) (combine xs ys)) diff --git a/src/VisitorsPlugin.ml b/src/VisitorsPlugin.ml new file mode 100644 index 0000000..113488e --- /dev/null +++ b/src/VisitorsPlugin.ml @@ -0,0 +1,4 @@ +(* The name of our [ppx_deriving] plugin. *) + +let plugin = + "visitors" diff --git a/src/VisitorsRuntime.ml b/src/VisitorsRuntime.ml new file mode 100644 index 0000000..04d2ba5 --- /dev/null +++ b/src/VisitorsRuntime.ml @@ -0,0 +1,1139 @@ +(* This file provides useful / reasonable visitor methods for many of the + built-in types of OCaml. *) + +(* The classes defined in this file are automatically inherited by + auto-generated visitors. If this is not desired, this behavior can be + turned off at generation time by specifying [nude = true]. *) + +(* Some of the code in this file can be (or has been) auto-generated by + the [visitors] package itself: see [test/VisitorsRuntimeBootstrap]. + To avoid a complicated process and to facilitate code review, we + keep this code under manual control in this file. *) + +(* -------------------------------------------------------------------------- *) + +(* For compatibility with OCaml 4.02, we take the type [('a, 'b) result] from + the package [result]. This type appeared in the standard library in OCaml + 4.03. *) + +open Result + +(* -------------------------------------------------------------------------- *) + +(* [array_equal eq xs1 xs2] tests whether the arrays [xs1] and [xs2] have the + same components. The arrays must have the same length. The components are + compared using [eq]. *) + +let rec array_equal eq i n xs1 xs2 = + i = n || + let x1 = Array.unsafe_get xs1 i + and x2 = Array.unsafe_get xs2 i in + eq x1 x2 && array_equal eq (i + 1) n xs1 xs2 + +let array_equal eq xs1 xs2 = + let n = Array.length xs1 in + assert (Array.length xs2 = n); + array_equal eq 0 n xs1 xs2 + +(* -------------------------------------------------------------------------- *) + +(* An exception used at arity 2 and above. *) + +exception StructuralMismatch + +let fail () = + raise StructuralMismatch + +let wrap f t = + try + f t; + true + with StructuralMismatch -> + false + +let wrap2 f t1 t2 = + try + f t1 t2; + true + with StructuralMismatch -> + false + +(* -------------------------------------------------------------------------- *) + +(* A virtual base class for monoids. *) + +class virtual ['s] monoid = object + method private virtual zero: 's + method private virtual plus: 's -> 's -> 's +end + +(* -------------------------------------------------------------------------- *) + +(* Common monoids. *) + +class ['s] addition_monoid = object + inherit ['s] monoid + method private zero = 0 + method private plus = (+) +end + +class ['s] unit_monoid = object + inherit ['s] monoid + method private zero = () + method private plus () () = () +end + +(* -------------------------------------------------------------------------- *) + +(* Visitor methods for the primitive types. *) + +(* Must the methods below be declared polymorphic in ['env]? The fact is, they + ARE polymorphic in ['env], because they do not extend it or look it up. + + By declaring them polymorphic, we gain in generality: e.g., [visit_list] + can be called by two visitor methods which happen to have different types + of environments. (This happens in alphaLib, where visitor methods for terms + and patterns manipulate different types of environments.) + + However, by declaring them polymorphic, we also lose some generality, as we + PREVENT users from overriding these methods with code that extends or looks + up the environment. + + Here, it seems reasonable to take both the gain and the loss, and declare + these methods polymorphic. + + We could give the user a choice by providing multiple base classes, but that + would messy. Note that, when using [@@deriving visitors { ... }], the user + does have a choice whether the generated methods should be polymorphic in + ['env]. *) + +(* -------------------------------------------------------------------------- *) + +(* [iter] *) + +class ['self] iter = object (self) + + method private visit_array: 'env 'a . + ('env -> 'a -> unit) -> 'env -> 'a array -> unit + = fun f env xs -> + (* For speed, we inline [Array.iter]. Chances are, we save a closure + allocation, as using [Array.iter] would require us to build [f env]. *) + for i = 0 to Array.length xs - 1 do + f env (Array.unsafe_get xs i) + done + + method private visit_bool: 'env . + 'env -> bool -> unit + = fun _ _ -> () + + method private visit_bytes: 'env . + 'env -> bytes -> unit + = fun _ _ -> () + + method private visit_char: 'env . + 'env -> char -> unit + = fun _ _ -> () + + method private visit_float: 'env . + 'env -> float -> unit + = fun _ _ -> () + + method private visit_int: 'env . + 'env -> int -> unit + = fun _ _ -> () + + method private visit_int32: 'env . + 'env -> int32 -> unit + = fun _ _ -> () + + method private visit_int64: 'env . + 'env -> int64 -> unit + = fun _ _ -> () + + method private visit_lazy_t: 'env 'a . + ('env -> 'a -> unit) -> 'env -> 'a Lazy.t -> unit + = fun f env (lazy x) -> + f env x + + method private visit_list: 'env 'a . + ('env -> 'a -> unit) -> 'env -> 'a list -> unit + = fun f env xs -> + match xs with + | [] -> + () + | x :: xs -> + f env x; + self # visit_list f env xs + + method private visit_nativeint: 'env . + 'env -> nativeint -> unit + = fun _ _ -> () + + method private visit_option: 'env 'a . + ('env -> 'a -> unit) -> 'env -> 'a option -> unit + = fun f env ox -> + match ox with + | None -> + () + | Some x -> + f env x + + method private visit_ref: 'env 'a . + ('env -> 'a -> unit) -> 'env -> 'a ref -> unit + = fun f env rx -> + f env !rx + + method private visit_result: 'env 'a 'e. + ('env -> 'a -> unit) -> + ('env -> 'e -> unit) -> + 'env -> ('a, 'e) result -> unit + = fun f g env r -> + match r with + | Ok a -> f env a + | Error b -> g env b + + method private visit_string: 'env . + 'env -> string -> unit + = fun _ _ -> () + + method private visit_unit: 'env . + 'env -> unit -> unit + = fun _ _ -> () + +end + +(* -------------------------------------------------------------------------- *) + +(* [map] *) + +class ['self] map = object (self) + + method private visit_array: 'env 'a 'b . + ('env -> 'a -> 'b) -> 'env -> 'a array -> 'b array + = fun f env xs -> + Array.map (f env) xs + (* We could in principle inline [Array.map] so as to avoid allocating + the closure [f env]. That would be a bit painful, though. Anyway, + in [flambda] mode, the compiler might be able to do that for us. *) + + method private visit_bool: 'env . + 'env -> bool -> bool + = fun _ x -> x + + method private visit_bytes: 'env . + 'env -> bytes -> bytes + = fun _ x -> x + + method private visit_char: 'env . + 'env -> char -> char + = fun _ x -> x + + method private visit_float: 'env . + 'env -> float -> float + = fun _ x -> x + + method private visit_int: 'env . + 'env -> int -> int + = fun _ x -> x + + method private visit_int32: 'env . + 'env -> int32 -> int32 + = fun _ x -> x + + method private visit_int64: 'env . + 'env -> int64 -> int64 + = fun _ x -> x + + method private visit_lazy_t: 'env 'a 'b . + ('env -> 'a -> 'b) -> 'env -> 'a Lazy.t -> 'b Lazy.t + = fun f env thx -> + (* We seem to have two options: either force the suspension now + and rebuild a trivial suspension, or build now a suspension + that will perform the traversal when forced. We choose the + latter, which seems more interesting. If this is not the + desired behavior, it can of course be overridden. *) + lazy (f env (Lazy.force thx)) + + method private visit_list: 'env 'a 'b . + ('env -> 'a -> 'b) -> 'env -> 'a list -> 'b list + = fun f env xs -> + match xs with + | [] -> + [] + | x :: xs -> + let x = f env x in + x :: self # visit_list f env xs + + method private visit_nativeint: 'env . + 'env -> nativeint -> nativeint + = fun _ x -> x + + method private visit_option: 'env 'a 'b . + ('env -> 'a -> 'b) -> 'env -> 'a option -> 'b option + = fun f env ox -> + match ox with + | None -> + None + | Some x -> + Some (f env x) + + method private visit_ref: 'env 'a 'b . + ('env -> 'a -> 'b) -> 'env -> 'a ref -> 'b ref + = fun f env rx -> + ref (f env !rx) + + method private visit_result: 'env 'a 'b 'e 'f . + ('env -> 'a -> 'b) -> + ('env -> 'e -> 'f) -> + 'env -> ('a, 'e) result -> ('b, 'f) result + = fun f g env r -> + match r with + | Ok a -> Ok (f env a) + | Error b -> Error (g env b) + + method private visit_string: 'env . + 'env -> string -> string + = fun _ x -> x + + method private visit_unit: 'env . + 'env -> unit -> unit + = fun _ x -> x + +end + +(* -------------------------------------------------------------------------- *) + +(* [endo] *) + +class ['self] endo = object (self) + + (* We might wish to inherit from [map] and override only those methods where + a physical equality check is needed. Yet, we cannot do that, because some + methods, like [visit_list], have more restrictive types in this class than + in the class [map]. *) + + (* It may seem fishy to use an [endo] visitor at type [array], but one never + knows -- maybe the user wants this. Maybe she is using an array as an + immutable data structure. *) + + method private visit_array: 'env 'a . + ('env -> 'a -> 'a) -> 'env -> 'a array -> 'a array + = fun f env xs -> + let xs' = Array.map (f env) xs in + if array_equal (==) xs xs' then xs else xs' + + method private visit_bool: 'env . + 'env -> bool -> bool + = fun _ x -> x + + method private visit_bytes: 'env . + 'env -> bytes -> bytes + = fun _ x -> x + + method private visit_char:'env . + 'env -> char -> char + = fun _ x -> x + + method private visit_float: 'env . + 'env -> float -> float + = fun _ x -> x + + method private visit_int: 'env . + 'env -> int -> int + = fun _ x -> x + + method private visit_int32: 'env . + 'env -> int32 -> int32 + = fun _ x -> x + + method private visit_int64: 'env . + 'env -> int64 -> int64 + = fun _ x -> x + + method private visit_lazy_t : 'env 'a . + ('env -> 'a -> 'a) -> 'env -> 'a Lazy.t -> 'a Lazy.t + = fun f env thx -> + (* We could use the same code as in [map], which does not preserve sharing. + Or, we can force the suspension now, compute [x'], and if [x] and + [x'] coincide, then we can return the original suspension (now + forced), so as to preserve sharing. We choose the latter behavior. If + this is not the desired behavior, it can of course be overridden. *) + let x = Lazy.force thx in + let x' = f env x in + if x == x' then thx else lazy x' + + method private visit_list: 'env 'a . + ('env -> 'a -> 'a) -> 'env -> 'a list -> 'a list + = fun f env this -> + match this with + | [] -> + [] + | x :: xs -> + let x' = f env x in + let xs' = self # visit_list f env xs in + if x == x' && xs == xs' then + this + else + x' :: xs' + + method private visit_nativeint: 'env . + 'env -> nativeint -> nativeint + = fun _ x -> x + + method private visit_option: 'env 'a . + ('env -> 'a -> 'a) -> 'env -> 'a option -> 'a option + = fun f env ox -> + match ox with + | None -> + None + | Some x -> + let x' = f env x in + if x == x' then + ox + else + Some x' + + (* It probably does not make sense to use an [endo] visitor at type + [ref], but one never knows -- maybe the user wants this. Anyway, + it is consistent with the behavior of [endo] visitors at mutable + record types. *) + + method private visit_ref: 'env 'a . + ('env -> 'a -> 'a) -> 'env -> 'a ref -> 'a ref + = fun f env rx -> + let x = !rx in + let x' = f env x in + if x == x' then + rx + else + ref x' + + method private visit_result: 'env 'a 'e . + ('env -> 'a -> 'a) -> + ('env -> 'e -> 'e) -> + 'env -> ('a, 'e) result -> ('a, 'e) result + = fun f g env r -> + match r with + | Ok a -> + let a' = f env a in + if a == a' then r else Ok a' + | Error b -> + let b' = g env b in + if b == b' then r else Error b' + + method private visit_string: 'env . + 'env -> string -> string + = fun _ x -> x + + method private visit_unit: 'env . + 'env -> unit -> unit + = fun _ x -> x + +end + +(* -------------------------------------------------------------------------- *) + +(* [reduce] *) + +(* For arrays and lists, we use [fold_left] instead of a natural (bottom-up) + fold. The order in which the elements are traversed is the same either way + (namely, left-to-right) but the manner in which the [plus] operations are + associated is not the same, so the [plus] operator should be associative. + + We could go back to a natural fold, but we would lose tail recursion. *) + +class virtual ['self] reduce = object (self : 'self) + + inherit ['s] monoid + + method private visit_array: 'env 'a . + ('env -> 'a -> 's) -> 'env -> 'a array -> 's + = fun f env xs -> + Array.fold_left (fun s x -> self#plus s (f env x)) self#zero xs + (* We might wish to inline [Array.fold_left] and save a closure + allocation. That said, in flambda mode, the compiler might be + able to do that automatically. *) + + method private visit_bool: 'env . + 'env -> bool -> 's + = fun _env _ -> self#zero + + method private visit_bytes: 'env . + 'env -> bytes -> 's + = fun _env _ -> self#zero + + method private visit_char: 'env . + 'env -> char -> 's + = fun _env _ -> self#zero + + method private visit_float: 'env . + 'env -> float -> 's + = fun _env _ -> self#zero + + method private visit_int: 'env . + 'env -> int -> 's + = fun _env _ -> self#zero + + method private visit_int32: 'env . + 'env -> int32 -> 's + = fun _env _ -> self#zero + + method private visit_int64: 'env . + 'env -> int64 -> 's + = fun _env _ -> self#zero + + method private visit_lazy_t: 'env 'a . + ('env -> 'a -> 's) -> 'env -> 'a Lazy.t -> 's + = fun f env (lazy x) -> + f env x + + method private visit_list: 'env 'a . + ('env -> 'a -> 's) -> 'env -> 'a list -> 's + = fun f env xs -> + self # list_fold_left f env self#zero xs + (* The above line is equivalent to the following: *) + (* List.fold_left (fun s x -> self#plus s (f env x)) self#zero xs *) + (* By using the auxiliary method [list_fold_left] instead of calling + the library function [List.fold_left], we save a closure allocation, + at least in non-flambda mode. A micro-benchmark shows no performance + impact, either way. *) + + method private list_fold_left: 'env 'a . + ('env -> 'a -> 's) -> 'env -> 's -> 'a list -> 's + = fun f env s xs -> + match xs with + | [] -> + s + | x :: xs -> + let s = self#plus s (f env x) in + self # list_fold_left f env s xs + + method private visit_nativeint: 'env . + 'env -> nativeint -> 's + = fun _env _ -> self#zero + + method private visit_option: 'env 'a . + ('env -> 'a -> 's) -> 'env -> 'a option -> 's + = fun f env ox -> + match ox with + | Some x -> + f env x + | None -> + self#zero + + method private visit_ref: 'env 'a . + ('env -> 'a -> 's) -> 'env -> 'a ref -> 's + = fun f env rx -> + f env !rx + + method private visit_result: 'env 'a 'e . + ('env -> 'a -> 's) -> + ('env -> 'e -> 's) -> + 'env -> ('a, 'e) result -> 's + = fun f g env r -> + match r with + | Ok a -> + f env a + | Error b -> + g env b + + method private visit_string: 'env . + 'env -> string -> 's + = fun _env _ -> self#zero + + method private visit_unit: 'env . + 'env -> unit -> 's + = fun _env _ -> self#zero + +end + +(* -------------------------------------------------------------------------- *) + +(* [mapreduce] *) + +class virtual ['self] mapreduce = object (self : 'self) + + inherit ['s] monoid + + method private visit_array: 'env 'a 'b . + ('env -> 'a -> 'b * 's) -> 'env -> 'a array -> 'b array * 's + = fun f env xs -> + let s = ref self#zero in + let xs = + Array.map (fun x -> + let x, sx = f env x in + s := self#plus !s sx; + x + ) xs + in + xs, !s + + method private visit_bool: 'env . + 'env -> bool -> bool * 's + = fun _ x -> x, self#zero + + method private visit_bytes: 'env . + 'env -> bytes -> bytes * 's + = fun _ x -> x, self#zero + + method private visit_char: 'env . + 'env -> char -> char * 's + = fun _ x -> x, self#zero + + method private visit_float: 'env . + 'env -> float -> float * 's + = fun _ x -> x, self#zero + + method private visit_int: 'env . + 'env -> int -> int * 's + = fun _ x -> x, self#zero + + method private visit_int32: 'env . + 'env -> int32 -> int32 * 's + = fun _ x -> x, self#zero + + method private visit_int64: 'env . + 'env -> int64 -> int64 * 's + = fun _ x -> x, self#zero + + method private visit_lazy_t: 'env 'a 'b . + ('env -> 'a -> 'b * 's) -> 'env -> 'a Lazy.t -> 'b Lazy.t * 's + = fun f env (lazy x) -> + (* Because we must compute a summary now, it seems that we have to + force the suspension now. One should be aware that this is not + the same behavior as the one we chose in the class [map]. *) + let y, s = f env x in + lazy y, s + + method private visit_list: 'env 'a 'b . + ('env -> 'a -> 'b * 's) -> 'env -> 'a list -> 'b list * 's + = fun f env xs -> + match xs with + | [] -> + [], self#zero + | x :: xs -> + let x, sx = f env x in + let xs, sxs = self # visit_list f env xs in + x :: xs, self#plus sx sxs + (* This is not the same strategy as in the class [reduce], where we + used an accumulator and a tail-recursive left fold. Here, we are + using a right fold. The order in which list elements are visited + is left-to-right in both cases, but the tree of [self#plus] ops + is not balanced the same way. *) + + method private visit_nativeint: 'env . + 'env -> nativeint -> nativeint * 's + = fun _ x -> x, self#zero + + method private visit_option: 'env 'a_0 'a_1 . + ('env -> 'a_0 -> 'a_1 * 's) -> + 'env -> 'a_0 option -> 'a_1 option * 's + = fun visit_'a env this -> + match this with + | None -> + None, self#zero + | Some c0 -> + let r0, s0 = visit_'a env c0 in + Some r0, s0 + + method private visit_ref: 'env 'a_0 'a_1 . + ('env -> 'a_0 -> 'a_1 * 's) -> + 'env -> 'a_0 ref -> 'a_1 ref * 's + = fun visit_'a env this -> + let r0, s0 = visit_'a env !this in + ref r0, s0 + + method private visit_result: 'env 'a_0 'a_1 'b_0 'b_1 . + ('env -> 'a_0 -> 'a_1 * 's) -> + ('env -> 'b_0 -> 'b_1 * 's) -> + 'env -> ('a_0, 'b_0) result -> ('a_1, 'b_1) result * 's + = fun visit_'a visit_'b env this -> + match this with + | Ok c0 -> + let r0, s0 = visit_'a env c0 in + Ok r0, s0 + | Error c0 -> + let r0, s0 = visit_'b env c0 in + Error r0, s0 + + method private visit_string: 'env . + 'env -> string -> string * 's + = fun _ x -> x, self#zero + + method private visit_unit: 'env . + 'env -> unit -> unit * 's + = fun _ x -> x, self#zero + +end + +(* -------------------------------------------------------------------------- *) + +(* [fold] *) + +class ['self] fold = object (_self) + + (* No methods are provided, as we do not wish to fix the types of these + methods. It is up to the user to inherit from a class that defines + appropriate methods. Note that [VisitorsRuntime.map] is likely to be + appropriate in many situations. *) + +end + +(* -------------------------------------------------------------------------- *) + +(* [iter2] *) + +class ['self] iter2 = object (self) + + method private visit_array: 'env 'a 'b . + ('env -> 'a -> 'b -> unit) -> 'env -> 'a array -> 'b array -> unit + = fun f env xs1 xs2 -> + (* We inline [Array.iter2]. *) + if Array.length xs1 = Array.length xs2 then + for i = 0 to Array.length xs1 - 1 do + f env (Array.unsafe_get xs1 i) (Array.unsafe_get xs2 i) + done + else + fail() + + method private visit_bool: 'env . + 'env -> bool -> bool -> unit + = fun _ x1 x2 -> if x1 = x2 then () else fail() + + method private visit_bytes: 'env . + 'env -> bytes -> bytes -> unit + = fun _ x1 x2 -> if x1 = x2 then () else fail() + + method private visit_char: 'env . + 'env -> char -> char -> unit + = fun _ x1 x2 -> if x1 = x2 then () else fail() + + method private visit_float: 'env . + 'env -> float -> float -> unit + = fun _ x1 x2 -> if x1 = x2 then () else fail() + + method private visit_int: 'env . + 'env -> int -> int -> unit + = fun _ x1 x2 -> if x1 = x2 then () else fail() + + method private visit_int32: 'env . + 'env -> int32 -> int32 -> unit + = fun _ x1 x2 -> if x1 = x2 then () else fail() + + method private visit_int64: 'env . + 'env -> int64 -> int64 -> unit + = fun _ x1 x2 -> if x1 = x2 then () else fail() + + method private visit_lazy_t: 'env 'a 'b . + ('env -> 'a -> 'b -> unit) -> 'env -> 'a Lazy.t -> 'b Lazy.t -> unit + = fun f env (lazy x1) (lazy x2) -> + f env x1 x2 + + method private visit_list: 'env 'a 'b . + ('env -> 'a -> 'b -> unit) -> 'env -> 'a list -> 'b list -> unit + = fun f env xs1 xs2 -> + match xs1, xs2 with + | [], [] -> + () + | x1 :: xs1, x2 :: xs2 -> + f env x1 x2; + self # visit_list f env xs1 xs2 + | _, _ -> + fail() + + method private visit_nativeint: 'env . + 'env -> nativeint -> nativeint -> unit + = fun _ x1 x2 -> if x1 = x2 then () else fail() + + method private visit_option: 'env 'a 'b . + ('env -> 'a -> 'b -> unit) -> 'env -> 'a option -> 'b option -> unit + = fun f env ox1 ox2 -> + match ox1, ox2 with + | None, None -> + () + | Some x1, Some x2 -> + f env x1 x2 + | _, _ -> + fail() + + method private visit_ref: 'env 'a 'b . + ('env -> 'a -> 'b -> unit) -> 'env -> 'a ref -> 'b ref -> unit + = fun f env rx1 rx2 -> + f env !rx1 !rx2 + + method private visit_result: 'env 'a 'b 'e 'f . + ('env -> 'a -> 'b -> unit) -> + ('env -> 'e -> 'f -> unit) -> + 'env -> ('a, 'e) result -> ('b, 'f) result -> unit + = fun f g env r1 r2 -> + match r1, r2 with + | Ok a1, Ok a2 -> f env a1 a2 + | Error b1, Error b2 -> g env b1 b2 + | _, _ -> fail() + + method private visit_string: 'env . + 'env -> string -> string -> unit + = fun _ x1 x2 -> if x1 = x2 then () else fail() + + method private visit_unit: 'env . + 'env -> unit -> unit -> unit + = fun _ _x1 _x2 -> () + +end + +(* -------------------------------------------------------------------------- *) + +(* [map2] *) + +class ['self] map2 = object (self) + + method private visit_array: 'env 'a 'b 'c . + ('env -> 'a -> 'b -> 'c) -> 'env -> 'a array -> 'b array -> 'c array + = fun f env xs1 xs2 -> + if Array.length xs1 = Array.length xs2 then + Array.mapi (fun i x1 -> f env x1 xs2.(i)) xs1 + (* Array.map2 (f env) xs1 xs2 *) + (* We avoid [Array.map2] because it does not exist in OCaml 4.02. *) + else + fail() + + method private visit_bool: 'env . + 'env -> bool -> bool -> bool + = fun _ x1 x2 -> if x1 = x2 then x1 else fail() + + method private visit_bytes: 'env . + 'env -> bytes -> bytes -> bytes + = fun _ x1 x2 -> if x1 = x2 then x1 else fail() + + method private visit_char: 'env . + 'env -> char -> char -> char + = fun _ x1 x2 -> if x1 = x2 then x1 else fail() + + method private visit_float: 'env . + 'env -> float -> float -> float + = fun _ x1 x2 -> if x1 = x2 then x1 else fail() + + method private visit_int: 'env . + 'env -> int -> int -> int + = fun _ x1 x2 -> if x1 = x2 then x1 else fail() + + method private visit_int32: 'env . + 'env -> int32 -> int32 -> int32 + = fun _ x1 x2 -> if x1 = x2 then x1 else fail() + + method private visit_int64: 'env . + 'env -> int64 -> int64 -> int64 + = fun _ x1 x2 -> if x1 = x2 then x1 else fail() + + method private visit_lazy_t: 'env 'a 'b 'c . + ('env -> 'a -> 'b -> 'c) -> 'env -> 'a Lazy.t -> 'b Lazy.t -> 'c Lazy.t + = fun f env thx1 thx2 -> + (* As in [map]. *) + lazy (f env (Lazy.force thx1) (Lazy.force thx2)) + + method private visit_list: 'env 'a 'b 'c . + ('env -> 'a -> 'b -> 'c) -> 'env -> 'a list -> 'b list -> 'c list + = fun f env xs1 xs2 -> + match xs1, xs2 with + | [], [] -> + [] + | x1 :: xs1, x2 :: xs2 -> + let x = f env x1 x2 in + x :: self # visit_list f env xs1 xs2 + | _, _ -> + fail() + + method private visit_nativeint: 'env . + 'env -> nativeint -> nativeint -> nativeint + = fun _ x1 x2 -> if x1 = x2 then x1 else fail() + + method private visit_option: 'env 'a 'b 'c . + ('env -> 'a -> 'b -> 'c) -> 'env -> 'a option -> 'b option -> 'c option + = fun f env ox1 ox2 -> + match ox1, ox2 with + | None, None -> + None + | Some x1, Some x2 -> + let x = f env x1 x2 in + Some x + | _, _ -> + fail() + + method private visit_ref: 'env 'a 'b 'c . + ('env -> 'a -> 'b -> 'c) -> 'env -> 'a ref -> 'b ref -> 'c ref + = fun f env rx1 rx2 -> + ref (f env !rx1 !rx2) + + method private visit_result: 'env 'a 'b 'c 'e 'f 'g . + ('env -> 'a -> 'b -> 'c) -> + ('env -> 'e -> 'f -> 'g) -> + 'env -> ('a, 'e) result -> ('b, 'f) result -> ('c, 'g) result + = fun f g env r1 r2 -> + match r1, r2 with + | Ok a1, Ok a2 -> Ok (f env a1 a2) + | Error b1, Error b2 -> Error (g env b1 b2) + | _, _ -> fail() + + method private visit_string: 'env . + 'env -> string -> string -> string + = fun _ x1 x2 -> if x1 = x2 then x1 else fail() + + method private visit_unit: 'env . + 'env -> unit -> unit -> unit + = fun _ _x1 _x2 -> () + +end + +(* -------------------------------------------------------------------------- *) + +(* [reduce2] *) + +class virtual ['self] reduce2 = object (self : 'self) + + inherit ['s] monoid + + method private visit_array: 'env 'a 'b . + ('env -> 'a -> 'b -> 's) -> 'env -> 'a array -> 'b array -> 's + = fun f env xs1 xs2 -> + (* OCaml does not offer [Array.fold_left2], so we use [Array.iter2], + which we inline. *) + if Array.length xs1 = Array.length xs2 then + let s = ref self#zero in + for i = 0 to Array.length xs1 - 1 do + let x1 = Array.unsafe_get xs1 i + and x2 = Array.unsafe_get xs2 i in + s := self#plus !s (f env x1 x2) + done; + !s + else + fail() + + method private visit_bool: 'env . + 'env -> bool -> bool -> 's + = fun _env x1 x2 -> + if x1 = x2 then self#zero else fail() + + method private visit_bytes: 'env . + 'env -> bytes -> bytes -> 's + = fun _env x1 x2 -> + if x1 = x2 then self#zero else fail() + + method private visit_char: 'env . + 'env -> char -> char -> 's + = fun _env x1 x2 -> + if x1 = x2 then self#zero else fail() + + method private visit_float: 'env . + 'env -> float -> float -> 's + = fun _env x1 x2 -> + if x1 = x2 then self#zero else fail() + + method private visit_int: 'env . + 'env -> int -> int -> 's + = fun _env x1 x2 -> + if x1 = x2 then self#zero else fail() + + method private visit_int32: 'env . + 'env -> int32 -> int32 -> 's + = fun _env x1 x2 -> + if x1 = x2 then self#zero else fail() + + method private visit_int64: 'env . + 'env -> int64 -> int64 -> 's + = fun _env x1 x2 -> + if x1 = x2 then self#zero else fail() + + method private visit_lazy_t: 'env 'a 'b . + ('env -> 'a -> 'b -> 's) -> 'env -> 'a Lazy.t -> 'b Lazy.t -> 's + = fun f env (lazy x1) (lazy x2) -> + f env x1 x2 + + method private visit_list: 'env 'a 'b . + ('env -> 'a -> 'b -> 's) -> 'env -> 'a list -> 'b list -> 's + = fun f env xs1 xs2 -> + if List.length xs1 = List.length xs2 then + List.fold_left2 (fun s x1 x2 -> self#plus s (f env x1 x2)) self#zero xs1 xs2 + else + fail() + + method private visit_nativeint: 'env . + 'env -> nativeint -> nativeint -> 's + = fun _env x1 x2 -> + if x1 = x2 then self#zero else fail() + + method private visit_option: 'env 'a 'b . + ('env -> 'a -> 'b -> 's) -> 'env -> 'a option -> 'b option -> 's + = fun f env ox1 ox2 -> + match ox1, ox2 with + | Some x1, Some x2 -> + f env x1 x2 + | None, None -> + self#zero + | Some _, None + | None, Some _ -> + fail() + + method private visit_ref: 'env 'a 'b . + ('env -> 'a -> 'b -> 's) -> 'env -> 'a ref -> 'b ref -> 's + = fun f env rx1 rx2 -> + f env !rx1 !rx2 + + method private visit_result: 'env 'a 'b 'e 'f . + ('env -> 'a -> 'b -> 's) -> + ('env -> 'e -> 'f -> 's) -> + 'env -> ('a, 'e) result -> ('b, 'f) result -> 's + = fun f g env r1 r2 -> + match r1, r2 with + | Ok a1, Ok a2 -> + f env a1 a2 + | Error b1, Error b2 -> + g env b1 b2 + | Ok _, Error _ + | Error _, Ok _ -> + fail() + + method private visit_string: 'env . + 'env -> string -> string -> 's + = fun _env x1 x2 -> + if x1 = x2 then self#zero else fail() + + method private visit_unit: 'env . + 'env -> unit -> unit -> 's + = fun _env () () -> + self#zero + +end + +(* -------------------------------------------------------------------------- *) + +(* [mapreduce2] *) + +class virtual ['self] mapreduce2 = object (self) + + inherit ['s] monoid + + method private visit_array: 'env 'a 'b 'c . + ('env -> 'a -> 'b -> 'c * 's) -> 'env -> 'a array -> 'b array -> 'c array * 's + = fun f env xs1 xs2 -> + let n1 = Array.length xs1 + and n2 = Array.length xs2 in + if n1 = n2 then + let s = ref self#zero in + let xs = Array.init n1 (fun i -> + let x1 = Array.unsafe_get xs1 i + and x2 = Array.unsafe_get xs2 i in + let x, sx = f env x1 x2 in + s := self#plus !s sx; + x + ) in + xs, !s + else + fail() + + method private visit_bool: 'env . + 'env -> bool -> bool -> bool * 's + = fun _ x1 x2 -> if x1 = x2 then x1, self#zero else fail() + + method private visit_bytes: 'env . + 'env -> bytes -> bytes -> bytes * 's + = fun _ x1 x2 -> if x1 = x2 then x1, self#zero else fail() + + method private visit_char: 'env . + 'env -> char -> char -> char * 's + = fun _ x1 x2 -> if x1 = x2 then x1, self#zero else fail() + + method private visit_float: 'env . + 'env -> float -> float -> float * 's + = fun _ x1 x2 -> if x1 = x2 then x1, self#zero else fail() + + method private visit_int: 'env . + 'env -> int -> int -> int * 's + = fun _ x1 x2 -> if x1 = x2 then x1, self#zero else fail() + + method private visit_int32: 'env . + 'env -> int32 -> int32 -> int32 * 's + = fun _ x1 x2 -> if x1 = x2 then x1, self#zero else fail() + + method private visit_int64: 'env . + 'env -> int64 -> int64 -> int64 * 's + = fun _ x1 x2 -> if x1 = x2 then x1, self#zero else fail() + + method private visit_lazy_t: 'env 'a 'b 'c . + ('env -> 'a -> 'b -> 'c * 's) -> 'env -> 'a Lazy.t -> 'b Lazy.t -> 'c Lazy.t * 's + = fun f env (lazy x1) (lazy x2) -> + (* As in [mapreduce]. *) + let y, s = f env x1 x2 in + lazy y, s + + method private visit_list: 'env 'a_0 'a_1 'a_2 . + ('env -> 'a_0 -> 'a_1 -> 'a_2 * 's) -> + 'env -> 'a_0 list -> 'a_1 list -> 'a_2 list * 's + = fun visit_'a env this_0 this_1 -> + match this_0, this_1 with + | [], [] -> + [], self#zero + | c0_0 :: c1_0, c0_1 :: c1_1 -> + let r0, s0 = visit_'a env c0_0 c0_1 in + let r1, s1 = self#visit_list visit_'a env c1_0 c1_1 in + r0 :: r1, self#plus s0 s1 + | _, _ -> + fail() + + method private visit_nativeint: 'env . + 'env -> nativeint -> nativeint -> nativeint * 's + = fun _ x1 x2 -> if x1 = x2 then x1, self#zero else fail() + + method private visit_option: 'env 'a_0 'a_1 'a_2 . + ('env -> 'a_0 -> 'a_1 -> 'a_2 * 's) -> + 'env -> 'a_0 option -> 'a_1 option -> 'a_2 option * 's + = fun visit_'a env this_0 this_1 -> + match this_0, this_1 with + | None, None -> + None, self#zero + | Some c0_0, Some c0_1 -> + let r0, s0 = visit_'a env c0_0 c0_1 in + Some r0, s0 + | _, _ -> + fail() + + method private visit_ref: 'env 'a_0 'a_1 'a_2 . + ('env -> 'a_0 -> 'a_1 -> 'a_2 * 's) -> + 'env -> 'a_0 ref -> 'a_1 ref -> 'a_2 ref * 's + = fun visit_'a env this_0 this_1 -> + let r0, s0 = visit_'a env !this_0 !this_1 in + ref r0, s0 + + method private visit_result: 'env 'a_0 'a_1 'a_2 'b_0 'b_1 'b_2 . + ('env -> 'a_0 -> 'a_1 -> 'a_2 * 's) -> + ('env -> 'b_0 -> 'b_1 -> 'b_2 * 's) -> + 'env -> ('a_0, 'b_0) result -> ('a_1, 'b_1) result -> ('a_2, 'b_2) result * 's + = fun visit_'a visit_'b env this_0 this_1 -> + match this_0, this_1 with + | Ok c0_0, Ok c0_1 -> + let r0, s0 = visit_'a env c0_0 c0_1 in + Ok r0, s0 + | Error c0_0, Error c0_1 -> + let r0, s0 = visit_'b env c0_0 c0_1 in + Error r0, s0 + | _, _ -> + fail() + + method private visit_string: 'env . + 'env -> string -> string -> string * 's + = fun _ x1 x2 -> if x1 = x2 then x1, self#zero else fail() + + method private visit_unit: 'env . + 'env -> unit -> unit -> unit * 's + = fun _ () () -> (), self#zero + +end + +(* -------------------------------------------------------------------------- *) + +(* [fold2] *) + +class ['self] fold2 = object (_self) + + (* See the comment in the class [fold] above. *) + +end diff --git a/src/VisitorsSettings.ml b/src/VisitorsSettings.ml new file mode 100644 index 0000000..d10b221 --- /dev/null +++ b/src/VisitorsSettings.ml @@ -0,0 +1,370 @@ +open Result +open VisitorsString +open List +let sprintf = Printf.sprintf +open Parsetree +open Ppx_deriving +open VisitorsPlugin +open VisitorsAnalysis +open VisitorsGeneration + +(* -------------------------------------------------------------------------- *) + +(* We can generate classes that adhere to several distinct schemes, listed + below. These schemes differ only in the re-building code that is executed + after the recursive calls. In [iter], this code does nothing. In [map], it + reconstructs a data structure. In [endo], it also reconstructs a data + structure, but attempts to preserve sharing. In [reduce], it combines the + results of the recursive calls using a monoid operation. In [fold], this + code is missing; it is represented by a virtual method. *) + +type scheme = + | Iter + | Map + | Endo + | Reduce + | MapReduce + | Fold + +(* -------------------------------------------------------------------------- *) + +(* The parameters that can be set by the user. *) + +module type SETTINGS = sig + + (* The type declarations that we are processing. *) + val decls: type_declaration list + + (* The name of the generated class. *) + val name: classe + + (* The arity of the generated code, e.g., 1 if one wishes to generate [iter] + and [map], 2 if one wishes to generate [iter2] and [map2], and so on. *) + val arity: int + + (* The scheme of visitor that we wish to generate (see the definition of + the type [scheme] above). *) + val scheme: scheme + + (* [variety] combines the information in [scheme] and [arity]. It is just + 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.] is implicitly prepended to this list. + If [nude] is [true], it is not. *) + val ancestors: Longident.t list + + (* [concrete] controls whether the generated class should be concrete or + virtual. By default, it is virtual. *) + val concrete: bool + + (* If [irregular] is [true], the regularity check is suppressed; this allows + a local parameterized type to be instantiated. The definition of ['a t] + can then refer to [int t]. However, in most situations, this will lead to + ill-typed generated code. The generated code should be well-typed if [t] + is always instantiated in the same manner, e.g., if there are references + to [int t] but not to other instances of [t]. *) + val irregular: bool + + (* If [public] is present, then every method is declared private, except + the methods whose name appears in the list [public]. *) + val public: string list option + + (* If [polymorphic] is [true], then (possibly polymorphic) type annotations + for methods are generated. The function [poly], applied to the name of a + type variable (without its quote), tells whether this type variable + should receive monomorphic or polymorphic treatment. In the former case, + this type variable is dealt with via a visitor method; in the latter + case, it is dealt with via a visitor function. *) + val polymorphic: bool + val poly: tyvar -> bool + + (* If [data] is [true], then descending visitor methods for data constructors + are generated. This allows the user to request per-data-constructor custom + behavior by overriding these methods. If [data] is [false], then these + methods are not generated. This yields simpler and faster code with + fewer customization opportunities. *) + val data: bool + +end + +(* -------------------------------------------------------------------------- *) + +(* The supported varieties. *) + +(* Note that [mapreduce] must appear in this list before [map], as shorter + prefixes must be tested last. *) + +let supported = [ + "mapreduce", MapReduce; + "map", Map; + "iter", Iter; + "endo", Endo; + "reduce", Reduce; + "fold", Fold; + ] + +let valid_varieties = + "iter, map, endo, reduce, mapreduce, fold,\n\ + iter2, map2, reduce2, mapreduce2, fold2" + +let invalid_variety loc = + raise_errorf ~loc + "%s: invalid variety. The valid varieties are\n\ + %s." + plugin valid_varieties + +(* [parse_variety] takes a variety, which could be "iter", "map2", etc. and + returns a pair of a scheme and an arity. *) + +let parse_variety loc (s : string) : scheme * int = + (* A loop over [supported] tries each supported variety in turn. *) + let rec loop supported s = + match supported with + | (p, scheme) :: supported -> + if prefix p s then + let s = remainder p s in + let i = if s = "" then 1 else int_of_string s in + if i <= 0 then failwith "negative integer" + else scheme, i + else + loop supported s + | [] -> + failwith "unexpected prefix" + in + (* Start the loop and handle errors. *) + try + loop supported s + with Failure _ -> + invalid_variety loc + +(* -------------------------------------------------------------------------- *) + +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 + +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 + +(* -------------------------------------------------------------------------- *) + +type bool_or_strings = + | Bool of bool + | Strings of string list + +let bool_or_strings : bool_or_strings Arg.conv = + fun e -> + match Arg.bool e, Arg.list Arg.string e with + | Ok b, Error _ -> + Ok (Bool b) + | Error _, Ok alphas -> + Ok (Strings alphas) + | Error _, Error _ -> + Error "Boolean or string list" + | Ok _, Ok _ -> + assert false + +(* -------------------------------------------------------------------------- *) + +(* The option processing code constructs a module of type [SETTINGS]. *) + +module Parse (O : sig + val loc: Location.t + val decls: type_declaration list + val options: (string * expression) list +end) +: SETTINGS += struct + open O + + (* Set up a few parsers. *) + + let bool = Arg.get_expr ~deriver:plugin Arg.bool + let string = Arg.get_expr ~deriver:plugin Arg.string + let strings = Arg.get_expr ~deriver:plugin (Arg.list Arg.string) + let bool_or_strings = Arg.get_expr ~deriver:plugin bool_or_strings + + (* Default values. *) + + let name = ref None + 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 + let irregular = ref false + let nude = ref false + let polymorphic = ref false + let poly = ref (fun _ -> false) + let public = ref None + + (* Parse every option. *) + + let () = + 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" -> + concrete := bool e + | "data" -> + data := bool e + | "irregular" -> + irregular := bool e + | "name" -> + name := Some (string e) + | "nude" -> + nude := bool e + | "polymorphic" -> + (* The [polymorphic] parameter can be a Boolean constant or a list + of type variable names. If [true], then all type variables are + considered polymorphic. If a list of type variables, then only + the variables in the list are considered polymorphic. *) + begin match bool_or_strings e with + | Bool b -> + polymorphic := b; + poly := (fun _ -> b) + | Strings alphas -> + let alphas = List.map unquote alphas in + polymorphic := true; + poly := (fun alpha -> List.mem alpha alphas) + end + | "monomorphic" -> + (* The [monomorphic] parameter is provided as a facility for the user. + It means the reverse of [polymorphic]. This is particularly useful + when the parameter is a list of type variables: then, only the + variables *not* in the list are considered polymorphic. *) + begin match bool_or_strings e with + | Bool b -> + polymorphic := not b; + poly := (fun _ -> not b) + | Strings alphas -> + let alphas = List.map unquote alphas in + polymorphic := true; (* yes, [true] *) + poly := (fun alpha -> not (List.mem alpha alphas)) + end + | "public" -> + public := Some (strings e) + | "variety" -> + let v = string e in + variety := Some v; + let s, a = parse_variety loc v in + scheme := s; + arity := a; + (* [endo] is supported only at arity 1. *) + if s = Endo && a > 1 then + invalid_variety loc + | _ -> + (* We could emit a warning, instead of an error, if we find an + unsupported option. That might be preferable for forward + compatibility. That said, I am not sure that ignoring unknown + options is a good idea; it might cause us to generate code + that does not work as expected by the user. *) + raise_errorf ~loc "%s: option %s is not supported." plugin o + ) options + + (* Export the results. *) + + 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 + let irregular = !irregular + let nude = !nude + let polymorphic = !polymorphic + let poly = !poly + let public = !public + + (* Perform sanity checking. *) + + (* The parameter [variety] is not optional. *) + let variety = + match !variety with + | None -> + raise_errorf ~loc + "%s: please specify the variety of the generated class.\n\ + e.g. [@@deriving visitors { variety = \"iter\" }]" plugin + | Some variety -> + variety + + (* The parameter [name] is optional. If it is absent, then [variety] + is used as its default value. *) + let name = + match !name with + | Some name -> + (* We expect [name] to be a valid class name. *) + if classify name <> LIDENT then + raise_errorf ~loc + "%s: %s is not a valid class name." + plugin name; + name + | None -> + variety + + (* Every string in the list [ancestors] must be a valid (long) class + identifier. *) + let () = + iter (must_be_valid_class_longident loc) ancestors + + (* When the variety is [iter], the class [VisitorsRuntime.iter] is an + implicit ancestor, and similarly for every variety. *) + let ancestors = + if nude then ancestors else ("VisitorsRuntime." ^ variety) :: ancestors + let ancestors = + map Longident.parse ancestors + + (* If [scheme] is [Fold], then [polymorphic] must be [false]. Indeed, + we currently cannot generate polymorphic type annotations in that + case, as we cannot guess the return types of the visitor methods. *) + let () = + if scheme = Fold && polymorphic then + raise_errorf ~loc + "%s: cannot generate polymorphic\n\ + type annotations for fold visitors." + plugin + +end diff --git a/src/VisitorsString.ml b/src/VisitorsString.ml new file mode 100644 index 0000000..bf0d4a1 --- /dev/null +++ b/src/VisitorsString.ml @@ -0,0 +1,70 @@ +open String + +(* [prefix s1 s2] tests whether [s1] is a prefix of [s2], i.e. whether + [s2] begins with [s1]. *) + +let prefix s1 s2 = + let n1 = length s1 in + n1 <= length s2 && s1 = sub s2 0 n1 + +(* [remainder s1 s2] assumes that [s1] is a prefix of [s2], and chops + [s1] off [s2], returning the remainder. *) + +let remainder s1 s2 = + assert (prefix s1 s2); + let n1 = length s1 in + let n2 = length s2 in + sub s2 n1 (n2 - n1) + +(* [unquote alpha] removes a leading quote in the string [alpha], if + there is one. *) + +let unquote alpha = + let n = String.length alpha in + if n > 0 && alpha.[0] = '\'' then + 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/src/_tags b/src/_tags new file mode 100644 index 0000000..c46c343 --- /dev/null +++ b/src/_tags @@ -0,0 +1,13 @@ +true: \ + debug, \ + safe_string, \ + warn(A-4-44), \ + linkall, \ + package(result), \ + cppo_V_OCAML + +not : \ + package(compiler-libs.common), \ + package(ppx_deriving.api) + +# If you wish to use quotations and antiquotations, add package(ppx_tools.metaquot). diff --git a/src/myocamlbuild.ml b/src/myocamlbuild.ml new file mode 100644 index 0000000..09e7d3e --- /dev/null +++ b/src/myocamlbuild.ml @@ -0,0 +1,5 @@ +(* This means: please use [cppo] to generate [%.ml] from [%.cppo.ml]. *) +let () = + Ocamlbuild_plugin.dispatch (fun phase -> + Ocamlbuild_cppo.dispatcher phase + ) diff --git a/src/ppx_deriving_visitors.mllib b/src/ppx_deriving_visitors.mllib new file mode 100644 index 0000000..fddb98b --- /dev/null +++ b/src/ppx_deriving_visitors.mllib @@ -0,0 +1,8 @@ +VisitorsCompatibility +VisitorsList +VisitorsString +VisitorsPlugin +VisitorsAnalysis +VisitorsGeneration +VisitorsSettings +Visitors diff --git a/test/.merlin b/test/.merlin new file mode 100644 index 0000000..7b418a1 --- /dev/null +++ b/test/.merlin @@ -0,0 +1,6 @@ +PKG ppx_import +PKG visitors.ppx +PKG visitors.runtime +PKG hashcons +PKG core_bench +B _build diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 0000000..bfc8946 --- /dev/null +++ b/test/Makefile @@ -0,0 +1,94 @@ +# ocamlbuild options. +OCAMLBUILD := ocamlbuild -use-ocamlfind -classic-display + +# For consistency with doc/Makefile, which relies on the same set of +# %.processed.ml files, we set this variable to true. +export VISITORS_BUILDING_DOCUMENTATION=true + +# The source files. +TESTS := $(shell ls *.ml | grep -v processed) + +# ------------------------------------------------------------------------------ + +.PHONY: test reinstall coverage bench mli processed clean + +# Because ocamlbuild is not good at parallel builds, we have broken up the set +# of test sources into several subsets, each of which is described by an +# [.mllib] file. For each such file, we make a separate ocamlbuild invocation, +# and we let [make] run these invocations in parallel. (Each of them must use +# a distinct build directory, and ignore everyone else's build directory.) + +test: reinstall + @ echo Compiling... + @ make -j4 $(patsubst %.mllib,%.cma,$(shell ls *.mllib)) + +%.cma: + @ $(OCAMLBUILD) -build-dir _build_$* $@ + +# To ensure that we always have the current version of [visitors], we +# reinstall it before compiling. + +reinstall: + @ echo Re-installing... + @ make -C ../src reinstall >/dev/null 2>/dev/null + +# Checking that every .ml file is covered by one .mllib file. + +coverage: + @ for i in $(TESTS) ; do \ + if ! grep -iw `basename $$i .ml` *.mllib >/dev/null ; then \ + echo [ERROR] $$i is not covered by any .mllib file. ; \ + fi \ + done + +# ------------------------------------------------------------------------------ + +# A tiny speed benchmark. + +bench: reinstall + @ $(OCAMLBUILD) -build-dir _build_bench bench.native + @ echo Running... + @ _build_bench/bench.native + +# Building an executable. + +%.native: + @ $(OCAMLBUILD) -build-dir \ + _build_$(shell grep -iw $* *.mllib | sed -e 's/\([^.]*\).mllib:.*/\1/') \ + $@ + +# ------------------------------------------------------------------------------ + +# Building inferred .mli files. + +mli: reinstall + make -j4 $(patsubst %.ml,%.inferred.mli,$(TESTS)) + +# This one is a bit tricky, as we must specify the right build directory. +# We grep to find out which .mllib file covers the desired .mli file, +# then construct the name of the build directory from the name of the +# .mllib file. + +%.inferred.mli: + @ $(OCAMLBUILD) -build-dir \ + _build_$(shell grep -iw $* *.mllib | sed -e 's/\([^.]*\).mllib:.*/\1/') \ + $@ + +# ------------------------------------------------------------------------------ + +# Preprocessing all source files. + +processed: reinstall + make -j4 -f ../src/Makefile.preprocess \ + $(patsubst %.ml,%.processed.ml,$(TESTS)) + +# ------------------------------------------------------------------------------ + +# Cleaning up. + +clean: + @ rm -f *~ + @ rm -f *.processed.ml + @ rm -rf _build* + +# ------------------------------------------------------------------------------ diff --git a/test/OOinfer.ml b/test/OOinfer.ml new file mode 100644 index 0000000..83d178c --- /dev/null +++ b/test/OOinfer.ml @@ -0,0 +1,5 @@ +class int_cell = object + val mutable x = 0 + method get = x + method incr y = x <- x + y +end diff --git a/test/OOinfer.mllib b/test/OOinfer.mllib new file mode 100644 index 0000000..54d315f --- /dev/null +++ b/test/OOinfer.mllib @@ -0,0 +1,6 @@ +OOinfer +OOinferfixed +OOinferfixedagain +OOinferfixedagaincheck +OOinferself +OOinfervirtual diff --git a/test/OOinferfixed.ml b/test/OOinferfixed.ml new file mode 100644 index 0000000..098dccf --- /dev/null +++ b/test/OOinferfixed.ml @@ -0,0 +1,6 @@ +class virtual ['a] int_cell = object (self) + val mutable x = 0 + method get = x + method set y = x <- self#check y + method virtual check: 'a -> _ +end diff --git a/test/OOinferfixedagain.ml b/test/OOinferfixedagain.ml new file mode 100644 index 0000000..cf78a1c --- /dev/null +++ b/test/OOinferfixedagain.ml @@ -0,0 +1,6 @@ +class virtual ['a, 'b] cell (init) = object (self) + val mutable x = init + method get = x + method set y = x <- self#check y + method virtual check: 'a -> 'b +end diff --git a/test/OOinferfixedagaincheck.ml b/test/OOinferfixedagaincheck.ml new file mode 100644 index 0000000..3c79f03 --- /dev/null +++ b/test/OOinferfixedagaincheck.ml @@ -0,0 +1,6 @@ +class virtual ['check] cell (init) = object (self) + val mutable x = init + method get = x + method set y = x <- self#check y + method virtual check: 'check +end diff --git a/test/OOinferself.ml b/test/OOinferself.ml new file mode 100644 index 0000000..2564efd --- /dev/null +++ b/test/OOinferself.ml @@ -0,0 +1,6 @@ +class virtual ['self] cell (init) = object (self : 'self) + val mutable x = init + method get = x + method set y = x <- self#check y + method virtual check: _ +end diff --git a/test/OOinfervirtual.ml b/test/OOinfervirtual.ml new file mode 100644 index 0000000..189d8d8 --- /dev/null +++ b/test/OOinfervirtual.ml @@ -0,0 +1,6 @@ +class virtual int_cell = object (self) + val mutable x = 0 + method get = x + method incr y = x <- self#check (x + y) + method virtual check: _ +end diff --git a/test/VisitorsRuntimeBootstrap.ml b/test/VisitorsRuntimeBootstrap.ml new file mode 100644 index 0000000..b1a0f1c --- /dev/null +++ b/test/VisitorsRuntimeBootstrap.ml @@ -0,0 +1,26 @@ +type 'a list = + | [] + | (::) of 'a * 'a list + +and 'a option = + | None + | Some of 'a + +and 'a ref = + { mutable contents: 'a } + +and ('a, 'b) result = + | Ok of 'a + | Error of 'b + +[@@deriving +visitors { variety = "iter"; public = []; polymorphic = true; data = false; nude = true }, +visitors { variety = "map"; public = []; polymorphic = true; data = false; nude = true }, +visitors { variety = "endo"; public = []; polymorphic = true; data = false; nude = true }, +visitors { variety = "reduce"; public = []; polymorphic = true; data = false; nude = true; ancestors = ["VisitorsRuntime.monoid"] }, +visitors { variety = "mapreduce"; public = []; polymorphic = true; data = false; nude = true; ancestors = ["VisitorsRuntime.monoid"] }, +visitors { variety = "iter2"; public = []; polymorphic = true; data = false; nude = true }, +visitors { variety = "map2"; public = []; polymorphic = true; data = false; nude = true }, +visitors { variety = "reduce2"; public = []; polymorphic = true; data = false; nude = true; ancestors = ["VisitorsRuntime.monoid"] }, +visitors { variety = "mapreduce2"; public = []; polymorphic = true; data = false; nude = true; ancestors = ["VisitorsRuntime.monoid"] } +] diff --git a/test/VisitorsRuntimeBootstrap.mllib b/test/VisitorsRuntimeBootstrap.mllib new file mode 100644 index 0000000..1270cb8 --- /dev/null +++ b/test/VisitorsRuntimeBootstrap.mllib @@ -0,0 +1 @@ +VisitorsRuntimeBootstrap diff --git a/test/_tags b/test/_tags new file mode 100644 index 0000000..c68877c --- /dev/null +++ b/test/_tags @@ -0,0 +1,24 @@ +# Declare that the build directories should not be traversed. +<_build*>: -traverse + +true: \ + debug, \ + safe_string, \ + package(visitors.ppx), \ + package(visitors.runtime) + + or or or : \ + package(hashcons) + +: \ + thread, \ + package(core_bench) + +: \ + package(ppx_import) + +: \ + warn(A-34) + +true: \ + warn(A-44) diff --git a/test/attic/expr07.ml b/test/attic/expr07.ml new file mode 100644 index 0000000..e17c000 --- /dev/null +++ b/test/attic/expr07.ml @@ -0,0 +1,23 @@ +open Hashcons + +module Hash_consed = struct + + let table = + create 128 + + let iter f env hcx = + f env hcx.node + + let map f env hcx = + hashcons table (f env hcx.node) + +end + +type expr = + expr_node hash_consed + +and expr_node = + | EConst of int + | EAdd of expr * expr + [@@deriving visitors { name = "iter"; variety = "iter" }, + visitors { name = "map" ; variety = "map" }] 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/bench.ml b/test/bench.ml new file mode 100644 index 0000000..51c1996 --- /dev/null +++ b/test/bench.ml @@ -0,0 +1,136 @@ +module Bench = Core_bench.Std.Bench +module Command = Core.Std.Command + +let run tests = + let tests = + List.map (fun (name, test) -> Bench.Test.create ~name test) tests + in + Command.run (Bench.make_command tests) + +type expr = + | EConst of (int[@opaque]) + | EAdd of expr * expr + | EList of expr list + [@@deriving visitors { variety = "iter"; concrete = true }, + visitors { variety = "map"; concrete = true }, + visitors { variety = "reduce"; ancestors = ["VisitorsRuntime.addition_monoid"]; concrete = true }] + +let iter : expr -> unit = + new iter # visit_expr () + +let rec native_iter env e = + match e with + | EConst _ -> + () + | EAdd (e1, e2) -> + native_iter env e1; + native_iter env e2 + | EList es -> + List.iter (native_iter env) es + +class size = object + inherit [_] reduce as super + method! visit_expr () e = + 1 + super # visit_expr () e +end + +let size : expr -> int = + new size # visit_expr () + +let rec native_size env e = + match e with + | EConst _ -> + 1 + | EAdd (e1, e2) -> + native_size env e1 + + native_size env e2 + | EList es -> + List.fold_left (fun accu e -> accu + native_size env e) 0 es + +let rec native_size_noenv e = + match e with + | EConst _ -> + 1 + | EAdd (e1, e2) -> + native_size_noenv e1 + + native_size_noenv e2 + | EList es -> + List.fold_left (fun accu e -> accu + native_size_noenv e) 0 es + +let rec native_size_noenv_accu accu e = + match e with + | EConst _ -> + accu + 1 + | EAdd (e1, e2) -> + let accu = native_size_noenv_accu accu e1 in + native_size_noenv_accu accu e2 + | EList es -> + List.fold_left native_size_noenv_accu accu es + +let split n = + assert (n >= 0); + let n1 = Random.int (n + 1) in + let n2 = n - n1 in + assert (0 <= n1 && n1 <= n); + assert (0 <= n2 && n2 <= n); + n1, n2 + +let rec generate n = + assert (n >= 0); + if n = 0 then + EConst (Random.int 100) + else + match Random.int 2 with + | 0 -> + let n1, n2 = split (n - 1) in + EAdd (generate n1, generate n2) + | 1 -> + let n1, n2 = split (n - 1) in + EList [ generate n1; generate n2 ] + | _ -> + assert false + +let rec list_init i n f = + if i = n then + [] + else + let x = f i in + x :: list_init (i + 1) n f + +let list_init n f = + list_init 0 n f + +let samples = + list_init 100 (fun _ -> generate 100) + +let test f () = + List.iter (fun e -> ignore (f e)) samples + +let () = + run [ + "iter", test iter; + "native_iter", test (native_iter ()); + ] + +let () = + run [ + "size", test size; + "native_size", test (native_size ()); +(* + "native_size_noenv", test native_size_noenv; + "native_size_noenv_accu", test (native_size_noenv_accu 0); + *) + ] + +(* with hoisting, applied to self#visit_expr: + iter allocates no memory, and is 46% slower than native_iter (which allocates). + without hoisting: + iter allocates memory and is 65% slower than native_iter + So, in this case, hoisting helps a little. + + with hoisting, applied to self#visit_expr: + size allocates no memory, and is 105% slower than native_size (which allocates). + without hoisting: + size allocates memory (same amount as native_size) and is 86% slower than native_size + So, in this case, hoisting seems counter-productive. + *) diff --git a/test/bench.mllib b/test/bench.mllib new file mode 100644 index 0000000..7efcd5c --- /dev/null +++ b/test/bench.mllib @@ -0,0 +1 @@ +Bench diff --git a/test/build.ml b/test/build.ml new file mode 100644 index 0000000..6c3c400 --- /dev/null +++ b/test/build.ml @@ -0,0 +1,10 @@ +(* Testing @build attributes. *) + +type foo = + | A + | B of int + | C of foo * foo [@build fun x y -> C (x, y)] + +and point = Point.point = private { x: int; y: int } + [@@build Point.make] + [@@deriving visitors { variety = "map" }] diff --git a/test/cil_types.ml b/test/cil_types.ml new file mode 100644 index 0000000..cdf228a --- /dev/null +++ b/test/cil_types.ml @@ -0,0 +1,1811 @@ +module Integer = struct type t = int end (* fpottier/visitors *) +(****************************************************************************) +(* *) +(* Copyright (C) 2001-2003 *) +(* George C. Necula *) +(* Scott McPeak *) +(* Wes Weimer *) +(* Ben Liblit *) +(* All rights reserved. *) +(* *) +(* Redistribution and use in source and binary forms, with or without *) +(* modification, are permitted provided that the following conditions *) +(* are met: *) +(* *) +(* 1. Redistributions of source code must retain the above copyright *) +(* notice, this list of conditions and the following disclaimer. *) +(* *) +(* 2. Redistributions in binary form must reproduce the above copyright *) +(* notice, this list of conditions and the following disclaimer in the *) +(* documentation and/or other materials provided with the distribution. *) +(* *) +(* 3. The names of the contributors may not be used to endorse or *) +(* promote products derived from this software without specific prior *) +(* written permission. *) +(* *) +(* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *) +(* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *) +(* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *) +(* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *) +(* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, *) +(* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, *) +(* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; *) +(* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *) +(* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *) +(* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN *) +(* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE *) +(* POSSIBILITY OF SUCH DAMAGE. *) +(* *) +(* File modified by CEA (Commissariat à l'énergie atomique et aux *) +(* énergies alternatives) *) +(* and INRIA (Institut National de Recherche en Informatique *) +(* et Automatique). *) +(****************************************************************************) + +(** The Abstract Syntax of CIL. + @plugin development guide *) + +(**************************** WARNING ***************************************) +(* Remember to reflect any change here into the visitor and pretty-printer *) +(* in cil.ml. In particular, if a type becomes mutable, it is necessary to *) +(* adapt the Cil.behavior type and the copy_behavior accordingly. *) +(* A first test to see if something has been broken by a change is to launch*) +(* ptests.byte -add-options '-files-debug "-check -copy"' *) +(* In addition, it is a good idea to add some invariant checks in the *) +(* check_file class in frama-c/src/file.ml (before lauching the tests) *) +(****************************************************************************) + +(* ************************************************************************* *) +(** {2 Root of the AST} *) +(* ************************************************************************* *) + +(** In Frama-C, the whole AST is accessible through {!Ast.get}. *) + +(** The top-level representation of a CIL source file (and the result of the + parsing and elaboration). Its main contents is the list of global + declarations and definitions. You can iterate over the globals in a + {!Cil_types.file} using the following iterators: {!Cil.mapGlobals}, + {!Cil.iterGlobals} and {!Cil.foldGlobals}. You can also use the + {!Cil.dummyFile} when you need a {!Cil_types.file} as a placeholder. For + each global item CIL stores the source location where it appears (using the + type {!Cil_types.location}) + @plugin development guide *) +type file = { + mutable fileName: string; (** The complete file name *) + + mutable globals: global list; + (** List of globals as they will appear in the printed file *) + + mutable globinit: fundec option; + (** An optional global initializer function. This is a function where you + can put stuff that must be executed before the program is + started. This function, is conceptually at the end of the file, + although it is not part of the globals list. Use {!Cil.getGlobInit} to + create/get one. *) + + mutable globinitcalled: bool; +(** Whether the global initialization function is called in main. This + should always be false if there is no global initializer. When you + create a global initialization CIL will try to insert code in main to + call it. *) +} + +(** The main type for representing global declarations and definitions. A list + of these form a CIL file. The order of globals in the file is generally + important. + @plugin development guide *) +and global = + | GType of typeinfo * location + (** A typedef. All uses of type names (through the [TNamed] constructor) + must be preceeded in the file by a definition of the name. The string + is the defined name and always not-empty. *) + + | GCompTag of compinfo * location + (** Defines a struct/union tag with some fields. There must be one of + these for each struct/union tag that you use (through the [TComp] + constructor) since this is the only context in which the fields are + printed. Consequently nested structure tag definitions must be + broken into individual definitions with the innermost structure + defined first. *) + + | GCompTagDecl of compinfo * location + (** Declares a struct/union tag. Use as a forward declaration. This is + printed without the fields. *) + + | GEnumTag of enuminfo * location + (** Declares an enumeration tag with some fields. There must be one of + these for each enumeration tag that you use (through the [TEnum] + constructor) since this is the only context in which the items are + printed. *) + + | GEnumTagDecl of enuminfo * location + (** Declares an enumeration tag. Use as a forward declaration. This is + printed without the items. *) + + | GVarDecl of varinfo * location + (** A variable declaration (not a definition) for a variable with object + type. There can be several declarations and at most one definition for + a given variable. If both forms appear then they must share the same + varinfo structure. Either has storage Extern or there must be a + definition in this file *) + + | GFunDecl of funspec * varinfo * location + (** A variable declaration (not a definition) for a function, i.e. a + prototype. There can be several declarations and at most one definition + for a given function. If both forms appear then they must share the same + varinfo structure. A prototype shares the varinfo with the fundec of the + definition. Either has storage Extern or there must be a definition in + this file. *) + + | GVar of varinfo * initinfo * location + (** A variable definition. Can have an initializer. The initializer is + updateable so that you can change it without requiring to recreate the + list of globals. There can be at most one definition for a variable in an + entire program. Cannot have storage Extern or function type. *) + + | GFun of fundec * location + (** A function definition. *) + + | GAsm of string * location + (** Global asm statement. These ones can contain only a template *) + + | GPragma of attribute * location + (** Pragmas at top level. Use the same syntax as attributes *) + + | GText of string + (** Some text (printed verbatim) at top level. E.g., this way you can put + comments in the output. *) + + | GAnnot of global_annotation * location +(** a global annotation. Can be + - an axiom or a lemma + - a predicate declaration or definition + - a global type invariant + - a global invariant + - a logic function declaration or definition. *) + +(* ************************************************************************* *) +(** {2 Types} *) +(* ************************************************************************* *) + +(** A C type is represented in CIL using the type {!Cil_types.typ}. Among types + we differentiate the integral types (with different kinds denoting the sign + and precision), floating point types, enumeration types, array and pointer + types, and function types. Every type is associated with a list of + attributes, which are always kept in sorted order. Use {!Cil.addAttribute} + and {!Cil.addAttributes} to construct list of attributes. If you want to + inspect a type, you should use {!Cil.unrollType} or {!Cil.unrollTypeDeep} to + see through the uses of named types. + + CIL is configured at build-time with the sizes and alignments of the + underlying compiler (GCC or MSVC). CIL contains functions that can compute + the size of a type (in bits) {!Cil.bitsSizeOf}, the alignment of a type (in + bytes) {!Cil.alignOf_int}, and can convert an offset into a start and width + (both in bits) using the function {!Cil.bitsOffset}. At the moment these + functions do not take into account the [packed] attributes and pragmas. *) + +and typ = + | TVoid of attributes (** Void type. Also predefined as {!Cil.voidType} *) + + | TInt of ikind * attributes + (** An integer type. The kind specifies the sign and width. Several useful + variants are predefined as {!Cil.intType}, {!Cil.uintType}, + {!Cil.longType}, {!Cil.charType}. *) + + | TFloat of fkind * attributes + (** A floating-point type. The kind specifies the precision. You can also use + the predefined constant {!Cil.doubleType}. *) + + | TPtr of typ * attributes + (** Pointer type. Several useful variants are predefined as + {!Cil.charPtrType}, {!Cil.charConstPtrType} (pointer to a constant + character), {!Cil.voidPtrType}, {!Cil.intPtrType} *) + + | TArray of typ * exp option * bitsSizeofTypCache * attributes + (** Array type. It indicates the base type and the array length. *) + + | TFun of typ * (string * typ * attributes) list option * bool * attributes + (** Function type. Indicates the type of the result, the name, type + and name attributes of the formal arguments ([None] if no arguments + were specified, as in a function whose definition or prototype we + have not seen; [Some \[\]] means void). Use {!Cil.argsToList} to + obtain a list of arguments. The boolean indicates if it is a + variable-argument function. If this is the type of a varinfo for + which we have a function declaration then the information for the + formals must match that in the function's sformals. Use + {!Cil.setFormals}, or {!Cil.setFunctionType}, or + {!Cil.makeFormalVar} for this purpose. *) + + | TNamed of typeinfo * attributes + (** The use of a named type. All uses of the same type name must share the + typeinfo. Each such type name must be preceeded in the file by a [GType] + global. This is printed as just the type name. The actual referred type + is not printed here and is carried only to simplify processing. To see + through a sequence of named type references, use {!Cil.unrollType}. The + attributes are in addition to those given when the type name was + defined. *) + + | TComp of compinfo * bitsSizeofTypCache * attributes + (** A reference to a struct or a union type. All references to the + same struct or union must share the same compinfo among them and + with a [GCompTag] global that preceeds all uses (except maybe + those that are pointers to the composite type). The attributes + given are those pertaining to this use of the type and are in + addition to the attributes that were given at the definition of + the type and which are stored in the compinfo. *) + + | TEnum of enuminfo * attributes + (** A reference to an enumeration type. All such references must + share the enuminfo among them and with a [GEnumTag] global that + preceeds all uses. The attributes refer to this use of the + enumeration and are in addition to the attributes of the + enumeration itself, which are stored inside the enuminfo *) + + | TBuiltin_va_list of attributes +(** This is the same as the gcc's type with the same name *) + +(** Various kinds of integers *) +and ikind = + IBool (** [_Bool] *) + | IChar (** [char] *) + | ISChar (** [signed char] *) + | IUChar (** [unsigned char] *) + | IInt (** [int] *) + | IUInt (** [unsigned int] *) + | IShort (** [short] *) + | IUShort (** [unsigned short] *) + | ILong (** [long] *) + | IULong (** [unsigned long] *) + | ILongLong (** [long long] (or [_int64] on Microsoft Visual C) *) + | IULongLong (** [unsigned long long] (or [unsigned _int64] on Microsoft + Visual C) *) + +(** Various kinds of floating-point numbers*) +and fkind = + FFloat (** [float] *) + | FDouble (** [double] *) + | FLongDouble (** [long double] *) + +(** This is used to cache the computation of the size of types in bits. *) +and bitsSizeofTyp = + | Not_Computed + | Computed of int + | Not_Computable of (string * typ) (** Explanation of the error *) + +and bitsSizeofTypCache = { mutable scache : bitsSizeofTyp} + +(* ************************************************************************* *) +(** {2 Attributes} *) +(* ************************************************************************* *) + +and attribute = + | Attr of string * attrparam list + (** An attribute has a name and some optional parameters. The name should not + start or end with underscore. When CIL parses attribute names it will + strip leading and ending underscores (to ensure that the multitude of GCC + attributes such as const, __const and __const__ all mean the same + thing.) *) + + | AttrAnnot of string + +(** Attributes are lists sorted by the attribute name. Use the functions + {!Cil.addAttribute} and {!Cil.addAttributes} to insert attributes in an + attribute list and maintain the sortedness. *) +and attributes = attribute list + +(** The type of parameters of attributes *) +and attrparam = + | AInt of (Integer.t[@opaque]) (** An integer constant *) + | AStr of string (** A string constant *) + | ACons of string * attrparam list + (** Constructed attributes. These are printed [foo(a1,a2,...,an)]. The list + of parameters can be empty and in that case the parentheses are not + printed. *) + | ASizeOf of typ (** A way to talk about types *) + | ASizeOfE of attrparam + | AAlignOf of typ + | AAlignOfE of attrparam + | AUnOp of unop * attrparam + | ABinOp of binop * attrparam * attrparam + | ADot of attrparam * string (** a.foo **) + | AStar of attrparam (** * a *) + | AAddrOf of attrparam (** & a **) + | AIndex of attrparam * attrparam (** a1[a2] *) + | AQuestion of attrparam * attrparam * attrparam (** a1 ? a2 : a3 **) + +(* ************************************************************************* *) +(** {2 Structures} *) +(* ************************************************************************* *) + +(** The {!Cil_types.compinfo} describes the definition of a structure or union + type. Each such {!Cil_types.compinfo} must be defined at the top-level using + the [GCompTag] constructor and must be shared by all references to this type + (using either the [TComp] type constructor or from the definition of the + fields. + + If all you need is to scan the definition of each composite type once, you + can do that by scanning all top-level [GCompTag]. + + Constructing a {!Cil_types.compinfo} can be tricky since it must contain + fields that might refer to the host {!Cil_types.compinfo} and furthermore + the type of the field might need to refer to the {!Cil_types.compinfo} for + recursive types. Use the {!Cil.mkCompInfo} function to create a + {!Cil_types.compinfo}. You can easily fetch the {!Cil_types.fieldinfo} for a + given field in a structure with {!Cil.getCompField}. *) + +(** The definition of a structure or union type. Use {!Cil.mkCompInfo} to make + one and use {!Cil.copyCompInfo} to copy one (this ensures that a new key is + assigned and that the fields have the right pointers to parents.). + @plugin development guide *) +and compinfo = { + mutable cstruct: bool; + (** [true] if struct, [false] if union *) + + corig_name: string; + (** Original name as found in C file. Will never be changed *) + + mutable cname: string; + (** The name. Always non-empty. Use {!Cil.compFullName} to get the full name + of a comp (along with the struct or union) *) + + mutable ckey: int; + (** A unique integer. This is assigned by {!Cil.mkCompInfo} using a global + variable in the Cil module. Thus two identical structs in two different + files might have different keys. Use {!Cil.copyCompInfo} to copy + structures so that a new key is assigned. *) + + mutable cfields: fieldinfo list; + (** Information about the fields. Notice that each fieldinfo has a pointer + back to the host compinfo. This means that you should not share + fieldinfo's between two compinfo's *) + + mutable cattr: attributes; + (** The attributes that are defined at the same time as the composite + type. These attributes can be supplemented individually at each + reference to this [compinfo] using the [TComp] type constructor. *) + + mutable cdefined: bool; + (** This boolean flag can be used to distinguish between structures + that have not been defined and those that have been defined but have + no fields (such things are allowed in gcc). *) + + mutable creferenced: bool; +(** [true] if used. Initially set to [false]. *) +} + +(* ************************************************************************* *) +(** {2 Structure fields} *) +(* ************************************************************************* *) + +(** The {!Cil_types.fieldinfo} structure is used to describe a structure or + union field. Fields, just like variables, can have attributes associated + with the field itself or associated with the type of the field (stored along + with the type of the field). *) + +(** Information about a struct/union field. + @plugin development guide *) +and fieldinfo = { + mutable fcomp: compinfo; + (** The host structure that contains this field. There can be only one + [compinfo] that contains the field. *) + + forig_name: string; + (** original name as found in C file. *) + + mutable fname: string; + (** The name of the field. Might be the value of {!Cil.missingFieldName} in + which case it must be a bitfield and is not printed and it does not + participate in initialization *) + + mutable ftype: typ; + (** The type. If the field is a bitfield, a special attribute + [FRAMA_C_BITFIELD_SIZE] indicating the width of the bitfield is added. *) + + mutable fbitfield: int option; + (** If a bitfield then ftype should be an integer type and the width of the + bitfield must be 0 or a positive integer smaller or equal to the width of + the integer type. A field of width 0 is used in C to control the alignment + of fields. *) + + mutable fattr: attributes; + (** The attributes for this field (not for its type) *) + + mutable floc: location; + (** The location where this field is defined *) + + mutable faddrof: bool; + (** Adapted from CIL [vaddrof] field for variables. Only set for non-array + fields. Variable whose field address is taken is not marked anymore as + having its own address taken. True if the address of this field is + taken. CIL will set these flags when it parses C, but you should make + sure to set the flag whenever your transformation create [AddrOf] + expression. *) + + mutable fsize_in_bits: int option; + (** (Deprecated. Use {!Cil.bitsOffset} instead.) Similar to [fbitfield] for + all types of fields. + @deprecated only Jessie uses this *) + + mutable foffset_in_bits: int option; + (** Offset at which the field starts in the structure. Do not read directly, + but use {!Cil.bitsOffset} instead. *) + + mutable fpadding_in_bits: int option; +(** (Deprecated.) Store the size of the padding that follows the field, if any. + @deprecated only Jessie uses this *) +} + +(* ************************************************************************* *) +(** {2 Enumerations} *) +(* ************************************************************************* *) + +(** Information about an enumeration. This is shared by all references to an + enumeration. Make sure you have a [GEnumTag] for each of these. *) + +(** Information about an enumeration. + @plugin development guide *) +and enuminfo = { + eorig_name: string; (** original name as found in C file. *) + + mutable ename: string; (** The name. Always non-empty. *) + + mutable eitems: enumitem list; (** Items. The list must be non-empty *) + + mutable eattr: attributes; + (** The attributes that are defined at the same time as the enumeration + type. These attributes can be supplemented individually at each + reference to this [enuminfo] using the [TEnum] type constructor. *) + + mutable ereferenced: bool; (** [true] if used. Initially set to [false]. *) + mutable ekind: ikind (** The integer kind used to represent this enum. MSVC + always assumes IInt but this is not the case + for gcc. See ISO C 6.7.2.2 *) +} + +and enumitem = { + eiorig_name: string; (** original name as found in C file. *) + mutable einame: string; (** the name, always non-empty. *) + mutable eival: exp; (** value of the item. Must be a compile-time constant *) + mutable eihost: enuminfo; (** the host enumeration in which the item is + declared. *) + eiloc: location; +} + +(** Information about a defined type. + @plugin development guide *) +and typeinfo = { + torig_name: string; (** original name as found in C file. *) + + mutable tname: string; + (** The name. Can be empty only in a [GType] when introducing a composite or + enumeration tag. If empty cannot be refered to from the file *) + + mutable ttype: typ; + (** The actual type. This includes the attributes that were present in the + typedef *) + + mutable treferenced: bool; (** [true] if used. Initially set to [false]. *) +} + +(* ************************************************************************* *) +(** {2 Variables} *) +(* ************************************************************************* *) + +(** Each local or global variable is represented by a unique + {!Cil_types.varinfo} structure. A global {!Cil_types.varinfo} can be + introduced with the [GVarDecl] or [GVar], [GFunDecl] or [GFun] globals. + A local varinfo can be introduced as part of a function definition + {!Cil_types.fundec}. + + All references to a given global or local variable must refer to the same + copy of the [varinfo]. Each [varinfo] has a globally unique identifier that + can be used to index maps and hashtables (the name can also be used for this + purpose, except for locals from different functions). This identifier is + constructor using a global counter. + + It is very important that you construct [varinfo] structures using only one + of the following functions: + - {!Cil.makeGlobalVar} : to make a global variable + - {!Cil.makeTempVar} : to make a temporary local variable whose name + will be generated so that to avoid conflict with other locals. + - {!Cil.makeLocalVar} : like {!Cil.makeTempVar} but you can specify the + exact name to be used. + - {!Cil.copyVarinfo}: make a shallow copy of a varinfo assigning a new name + and a new unique identifier + + A [varinfo] is also used in a function type to denote the list of + formals. *) + +(** Information about a variable. + @plugin development guide *) +and varinfo = { + mutable vname: string; + (** The name of the variable. Cannot be empty. It is primarily your + responsibility to ensure the uniqueness of a variable name. For local + variables {!Cil.makeTempVar} helps you ensure that the name is + unique. *) + + vorig_name: string; + (** the original name of the variable. Need not be unique. *) + + mutable vtype: typ; + (** The declared type of the variable. *) + + mutable vattr: attributes; + (** A list of attributes associated with the variable.*) + + mutable vstorage: storage; + (** The storage-class *) + + mutable vglob: bool; + (** True if this is a global variable*) + + mutable vdefined: bool; + (** True if the variable or function is defined in the file. Only relevant + for functions and global variables. Not used in particular for local + variables and logic variables. *) + + mutable vformal: bool; + (** True if the variable is a formal parameter of a function. *) + + mutable vinline: bool; + (** Whether this varinfo is for an inline function. *) + + mutable vdecl: location; + (** Location of variable declaration. *) + + mutable vid: int; + (** A unique integer identifier. This field will be set for you if you use + one of the {!Cil.makeFormalVar}, {!Cil.makeLocalVar}, + {!Cil.makeTempVar}, {!Cil.makeGlobalVar}, or {!Cil.copyVarinfo}. *) + + mutable vaddrof: bool; + (** [true] if the address of this variable is taken. CIL will set these + flags when it parses C, but you should make sure to set the flag + whenever your transformation create [AddrOf] expression. *) + + mutable vreferenced: bool; + (** [true] if this variable is ever referenced. This is computed by + [removeUnusedVars]. It is safe to just initialize this to [false]. *) + + vtemp: bool; + (** [true] for temporary variables generated by CIL normalization. [false] + for all the other variables. *) + + mutable vdescr: string option; + (** For most temporary variables, a description of what the var holds. + (e.g. for temporaries used for function call results, this string is a + representation of the function call.) *) + + mutable vdescrpure: bool; + (** Indicates whether the vdescr above is a pure expression or call. True + for all CIL expressions and Lvals, but false for e.g. function calls. + Printing a non-pure vdescr more than once may yield incorrect + results. *) + + mutable vghost: bool; + (** Indicates if the variable is declared in ghost code *) + + vsource: bool; + (** [true] iff this variable appears in the source of the program, which is + the case of all the variables in the initial AST. Plugins may create + variables with [vsource=false], for example to handle dynamic allocation. + Those variables do *not* have an associated {!GVar} or {!GVarDecl}. *) + + mutable vlogic_var_assoc: logic_var option + (** Logic variable representing this variable in the logic world. Do not + access this field directly. Instead, call {!Cil.cvar_to_lvar}. *) +} + +(** Storage-class information *) +and storage = + NoStorage (** The default storage. Nothing is printed *) + | Static + | Register + | Extern + +(* ************************************************************************* *) +(** {2 Expressions} *) +(* ************************************************************************* *) + +(** The CIL expression language contains only the side-effect free expressions + of C. They are represented as the type {!Cil_types.exp}. There are several + interesting aspects of CIL expressions: + + Integer and floating point constants can carry their textual representation. + This way the integer 15 can be printed as 0xF if that is how it occurred in + the source. + + CIL uses arbitrary precision integers + to represent the integer constants and also stores the + width of the integer type. Care must be taken to ensure that the constant is + representable with the given width. Use the functions {!Cil.kinteger}, + {!Cil.kinteger64} and {!Cil.integer} to construct constant expressions. CIL + predefines the constants {!Cil.zero}, {!Cil.one} and {!Cil.mone} (for -1). + + Use the functions {!Cil.isConstant} and {!Cil.isInteger} to test if an + expression is a constant and a constant integer respectively. + + CIL keeps the type of all unary and binary expressions. You can think of + that type qualifying the operator. Furthermore there are different operators + for arithmetic and comparisons on arithmetic types and on pointers. + + Another unusual aspect of CIL is that the implicit conversion between an + expression of array type and one of pointer type is made explicit, using the + [StartOf] expression constructor (which is not printed). If you apply the + [AddrOf]constructor to an lvalue of type [T] then you will be getting an + expression of type [TPtr(T)]. + + You can find the type of an expression with {!Cil.typeOf}. + + You can perform constant folding on expressions using the function + {!Cil.constFold}. *) + +(** Expressions (Side-effect free)*) +and exp = { + eid: int; (** unique identifier *) + enode: exp_node; (** the expression itself *) + eloc: location; (** location of the expression. *) +} + +and exp_node = + | Const of constant (** Constant *) + | Lval of lval (** Lvalue *) + | SizeOf of typ + (** sizeof(). Has [unsigned int] type (ISO 6.5.3.4). This is not + turned into a constant because some transformations might want to change + types *) + + | SizeOfE of exp (** sizeof() *) + + | SizeOfStr of string + (** sizeof(string_literal). We separate this case out because this is the + only instance in which a string literal should not be treated as having + type pointer to character. *) + + | AlignOf of typ + (** This corresponds to the GCC __alignof_. Has [unsigned int] type *) + + | AlignOfE of exp + + | UnOp of unop * exp * typ + (** Unary operation. Includes the type of the result. *) + + | BinOp of binop * exp * exp * typ + (** Binary operation. Includes the type of the result. The arithmetic + conversions are made explicit for the arguments. + @plugin development guide *) + + | CastE of typ * exp + (** Use {!Cil.mkCast} to make casts. *) + + | AddrOf of lval + (** Always use {!Cil.mkAddrOf} to construct one of these. Apply to an lvalue + of type [T] yields an expression of type [TPtr(T)] *) + + | StartOf of lval + (** Conversion from an array to a pointer to the beginning of the array. + Given an lval of type [TArray(T)] produces an expression of type + [TPtr(T)]. In C this operation is implicit, the [StartOf] operator is not + printed. We have it in CIL because it makes the typing rules simpler. *) + + | Info of exp * exp_info +(** Additional information on the underlying expression *) + +(** Additional information on an expression *) +and exp_info = { + exp_type : logic_type; (** when used as placeholder for a term *) + exp_name: string list; +} + +(* ************************************************************************* *) +(** {2 Constants} *) +(* ************************************************************************* *) + +(** Literal constants *) +and constant = + | CInt64 of (Integer.t[@opaque]) * ikind * string option + (** Integer constant. Give the ikind (see ISO9899 6.1.3.2) and the + textual representation. Textual representation is always set to Some s + when it comes from user code. This allows us to print a + constant as it was represented in the code, for example, + 0xF instead of 15. It is usually None for constant generated by Cil + itself. Use {!Cil.integer} or {!Cil.kinteger} to create these. *) + + | CStr of string + (** String constant. The escape characters inside the string have been already + interpreted. This constant has pointer to character type! The only case + when you would like a string literal to have an array type is when it is + an argument to sizeof. In that case you should use SizeOfStr. *) + + | CWStr of int64 list + (** Wide character string constant. Note that the local interpretation of such + a literal depends on {!Cil.theMachine.wcharType} and + {!Cil.theMachine.wcharKind}. Such a constant has type pointer to + {!Cil.theMachine.wcharType}. The escape characters in the string have not + been "interpreted" in the sense that L"A\xabcd" remains "A\xabcd" rather + than being represented as the wide character list with two elements: 65 + and 43981. That "interpretation" depends on the underlying wide character + type. *) + + | CChr of char + (** Character constant. This has type int, so use charConstToInt to read the + value in case sign-extension is needed. *) + + | CReal of float * fkind * string option + (** Floating point constant. Give the fkind (see ISO 6.4.4.2) and also the + textual representation, if available. *) + + | CEnum of enumitem +(** An enumeration constant. Use [Cillower.lowerEnumVisitor] to replace these + with integer constants. *) + +(** Unary operators *) +and unop = + Neg (** Unary minus *) + | BNot (** Bitwise complement (~) *) + | LNot (** Logical Not (!) *) + +(** Binary operations *) +and binop = + PlusA (** arithmetic + *) + | PlusPI (** pointer + integer *) + | IndexPI (** pointer + integer but only when it arises from an expression + [e\[i\]] when [e] is a pointer and + not an array. This is semantically + the same as PlusPI but CCured uses + this as a hint that the integer is + probably positive. *) + | MinusA (** arithmetic - *) + | MinusPI (** pointer - integer *) + | MinusPP (** pointer - pointer *) + | Mult (** * *) + | Div (** / + @plugin development guide *) + | Mod (** % + @plugin development guide *) + | Shiftlt (** shift left *) + | Shiftrt (** shift right *) + + | Lt (** < (arithmetic comparison) *) + | Gt (** > (arithmetic comparison) *) + | Le (** <= (arithmetic comparison) *) + | Ge (** >= (arithmetic comparison) *) + | Eq (** == (arithmetic comparison) *) + | Ne (** != (arithmetic comparison) *) + | BAnd (** bitwise and *) + | BXor (** exclusive-or *) + | BOr (** inclusive-or *) + + | LAnd (** logical and. Unlike other expressions this one does not always + evaluate both operands. If you want + to use these, you must set + {!Cil.useLogicalOperators}. *) + | LOr (** logical or. Unlike other expressions this one does not always + evaluate both operands. If you + want to use these, you must set + {!Cil.useLogicalOperators}. *) + +(* ************************************************************************* *) +(** {2 Left values} *) +(* ************************************************************************* *) + +(** Left values (aka Lvalues) are the sublanguage of expressions that can appear + at the left of an assignment or as operand to the address-of operator. In C + the syntax for lvalues is not always a good indication of the meaning of the + lvalue. For example the C value {v a[0][1][2] v} might involve 1, 2 or 3 + memory reads when used in an expression context, depending on the declared + type of the variable [a]. If [a] has type [int \[4\]\[4\]\[4\]] then we have + one memory read from somewhere inside the area that stores the array [a]. On + the other hand if [a] has type [int ***] then the expression really means [* + ( * ( * (a + 0) + 1) + 2)], in which case it is clear that it involves three + separate memory operations. + + An lvalue denotes the contents of a range of memory addresses. This range is + denoted as a host object along with an offset within the object. The host + object can be of two kinds: a local or global variable, or an object whose + address is in a pointer expression. We distinguish the two cases so that we + can tell quickly whether we are accessing some component of a variable + directly or we are accessing a memory location through a pointer. To make + it easy to tell what an lvalue means CIL represents lvalues as a host object + and an offset (see {!Cil_types.lval}). The host object (represented as + {!Cil_types.lhost}) can be a local or global variable or can be the object + pointed-to by a pointer expression. The offset (represented as + {!Cil_types.offset}) is a sequence of field or array index designators. + + Both the typing rules and the meaning of an lvalue is very precisely + specified in CIL. + + The following are a few useful function for operating on lvalues: + - {!Cil.mkMem} - makes an lvalue of [Mem] kind. Use this to ensure + that certain equivalent forms of lvalues are canonized. + For example, [*&x = x]. + - {!Cil.typeOfLval} - the type of an lvalue + - {!Cil.typeOffset} - the type of an offset, given the type of the + host. + - {!Cil.addOffset} and {!Cil.addOffsetLval} - extend sequences + of offsets. + - {!Cil.removeOffset} and {!Cil.removeOffsetLval} - shrink sequences + of offsets. + + The following equivalences hold {v + Mem(AddrOf(Mem a, aoff)), off = Mem a, aoff + off + Mem(AddrOf(Var v, aoff)), off = Var v, aoff + off + AddrOf (Mem a, NoOffset) = a + v} *) + +and lval = lhost * offset + +(** The host part of an {!Cil_types.lval}. *) +and lhost = + | Var of varinfo + (** The host is a variable. *) + + | Mem of exp +(** The host is an object of type [T] when the expression has pointer + [TPtr(T)]. *) + + +(** The offset part of an {!Cil_types.lval}. Each offset can be applied to + certain kinds of lvalues and its effect is that it advances the starting + address of the lvalue and changes the denoted type, essentially focussing + to some smaller lvalue that is contained in the original one. + @plugin development guide *) +and offset = + | NoOffset + (** No offset. Can be applied to any lvalue and does not change either the + starting address or the type. This is used when the lval consists of just + a host or as a terminator in a list of other kinds of offsets. *) + + | Field of fieldinfo * offset + (** A field offset. Can be applied only to an lvalue that denotes a structure + or a union that contains the mentioned field. This advances the offset to + the beginning of the mentioned field and changes the type to the type of + the mentioned field. *) + + | Index of exp * offset +(** An array index offset. Can be applied only to an lvalue that denotes an + array. This advances the starting address of the lval to the beginning of + the mentioned array element and changes the denoted type to be the type of + the array element *) + +(* ************************************************************************* *) +(** {2 Initializers} *) +(* ************************************************************************* *) + +(** A special kind of expressions are those that can appear as initializers for + global variables (initialization of local variables is turned into + assignments). The initializers are represented as type + {!Cil_types.init}. You can create initializers with {!Cil.makeZeroInit} and + you can conveniently scan compound initializers them with + {!Cil.foldLeftCompound}. *) + +(** Initializers for global variables. *) +and init = + | SingleInit of exp (** A single initializer *) + | CompoundInit of typ * (offset * init) list +(** Used only for initializers of structures, unions and arrays. The offsets + are all of the form [Field(f, NoOffset)] or [Index(i, NoOffset)] and + specify the field or the index being initialized. For structures all fields + must have an initializer (except the unnamed bitfields), in the proper + order. This is necessary since the offsets are not printed. For arrays the + list must contain a prefix of the initializers; the rest are 0-initialized. + For unions there must be exactly one initializer. If the initializer is not + for the first field then a field designator is printed, so you better be on + GCC since MSVC does not understand this. You can scan an initializer list + with {!Cil.foldLeftCompound}. *) + +(** We want to be able to update an initializer in a global variable, so we + define it as a mutable field *) +and initinfo = { mutable init : init option } + +(* ************************************************************************* *) +(** {2 Function definitions} *) +(* ************************************************************************* *) + +(** A function definition is always introduced with a [GFun] constructor at the + top level. All the information about the function is stored into a + {!Cil_types.fundec}. Some of the information (e.g. its name, type, storage, + attributes) is stored as a {!Cil_types.varinfo} that is a field of the + [fundec]. To refer to the function from the expression language you must use + the [varinfo]. + + The function definition contains, in addition to the body, a list of all the + local variables and separately a list of the formals. Both kind of variables + can be referred to in the body of the function. The formals must also be + shared with the formals that appear in the function type. For that reason, + to manipulate formals you should use the provided functions + {!Cil.makeFormalVar} and {!Cil.setFormals}. *) + +(** Function definitions. + @plugin development guide *) +and fundec = { + mutable svar: varinfo; + (** Holds the name and type as a variable, so we can refer to it easily + from the program. All references to this function either in a function + call or in a prototype must point to the same [varinfo]. *) + + mutable sformals: varinfo list; + (** Formals. These must be in the same order and with the same information + as the formal information in the type of the function. Use + {!Cil.setFormals} or {!Cil.setFunctionType} to set these formals and + ensure that they are reflected in the function type. Do not make + copies of these because the body refers to them. *) + + mutable slocals: varinfo list; + (** Locals. Does NOT include the sformals. Do not make copies of these + because the body refers to them. *) + + mutable smaxid: int; + (** Max local id. Starts at 0. Used for creating the names of new + temporary variables. Updated by {!Cil.makeLocalVar} and + {!Cil.makeTempVar}. You can also use {!Cil.setMaxId} to set it after + you have added the formals and locals. *) + + mutable sbody: block; (** The function body. *) + + mutable smaxstmtid: int option; + (** max id of a (reachable) statement in this function, if we have + computed it. range = 0 ... (smaxstmtid-1). This is computed by + {!Cfg.computeCFGInfo}. *) + + mutable sallstmts: stmt list; + (** After you call {!Cfg.computeCFGInfo} this field is set to contain all + statements in the function. *) + + mutable sspec: funspec; +} + +(** A block is a sequence of statements with the control falling through from + one element to the next *) +and block = { + mutable battrs: attributes; (** Attributes for the block *) + + mutable blocals: varinfo list; + (** variables that are local to the block. It is a subset of the slocals of + the enclosing function. *) + + mutable bstmts: stmt list; (** The statements comprising the block. *) +} + +(* ************************************************************************* *) +(** {2 Statements} *) +(* ************************************************************************* *) + +(** CIL statements are the structural elements that make the CFG. They are + represented using the type {!Cil_types.stmt}. Every statement has a + (possibly empty) list of labels. The {!Cil_types.stmtkind} field of a + statement indicates what kind of statement it is. + + Use {!Cil.mkStmt} to make a statement and the fill-in the fields. + + CIL also comes with support for control-flow graphs. The [sid] field in + [stmt] can be used to give unique numbers to statements, and the [succs] and + [preds] fields can be used to maintain a list of successors and predecessors + for every statement. The CFG information is not computed by default. Instead + you must explicitly use the functions {!Cfg.prepareCFG} and + {!Cfg.computeCFGInfo} to do it. *) + +(** Statements. + @plugin development guide *) +and stmt = { + mutable labels: label list; + (** Whether the statement starts with some labels, case statements or + default statements. *) + + mutable skind: stmtkind; + (** The kind of statement *) + + mutable sid: int; + (** A number (>= 0) that is unique in a function. Filled in only after the + CFG is computed. *) + + mutable succs: stmt list; + (** The successor statements. They can always be computed from the skind and + the context in which this statement appears. Filled in only after the CFG + is computed. *) + + mutable preds: stmt list; + (** The inverse of the succs function. *) + + mutable ghost : bool +} + +(** Labels *) +and label = + | Label of string * location * bool + (** A real label. If the bool is "true", the label is from the input source + program. If the bool is "false", the label was created by CIL or some + other transformation *) + + | Case of exp * location + (** A case statement. This expression is lowered into a constant if + {!Cil.lowerConstants} is set to [true]. *) + + | Default of location (** A default statement *) + +(* The various kinds of statements *) +and stmtkind = + | Instr of instr + (** An instruction that does not contain control flow. Control implicitly + falls through. + @plugin development guide *) + + | Return of exp option * location + (** The return statement. This is a leaf in the CFG. + @plugin development guide *) + + | Goto of stmt ref * location + (** A goto statement. Appears from actual goto's in the code or from goto's + that have been inserted during elaboration. The reference points to the + statement that is the target of the Goto. This means that you have to + update the reference whenever you replace the target statement. The + target statement MUST have at least a label. + @plugin development guide *) + + | Break of location + (** A break to the end of the nearest enclosing Loop or Switch. + @plugin development guide *) + + | Continue of location + (** A continue to the start of the nearest enclosing [Loop]. + @plugin development guide *) + + | If of exp * block * block * location + (** A conditional. Two successors, the "then" and the "else" branches (in + this order). + Both branches fall-through to the successor of the If statement. + @plugin development guide *) + + | Switch of exp * block * (stmt list) * location + (** A switch statement. [exp] is the index of the switch. [block] is + the body of the switch. [stmt list] contains the set of + statements whose [labels] are cases of the switch (i.e. for each + case, the corresponding statement is in [stmt list], a statement + cannot appear more than once in the list, and statements in + [stmt list] can have several labels corresponding to several + cases. + @plugin development guide *) + + | Loop of + code_annotation list * block * location * (stmt option) * (stmt option) + (** A [while(1)] loop. The termination test is implemented in the body of a + loop using a [Break] statement. If {!Cfg.prepareCFG} has been called, the + first stmt option will point to the stmt containing the continue label + for this loop and the second will point to the stmt containing the break + label for this loop. + @plugin development guide *) + + | Block of block + (** Just a block of statements. Use it as a way to keep some block attributes + local. + @plugin development guide *) + + | UnspecifiedSequence of (stmt * lval list + * lval list * lval list * stmt ref list) list + (** statements whose order of execution is not specified by + ISO/C. This is important for the order of side effects + during evaluation of expressions. Each statement comes + together with three list of lval, in this order. + - lvals that are written during the sequence and whose future + value depends upon the statement (it is legal to read from them, but + not to write to them) + - lvals that are written during the evaluation of the statement itself + - lval that are read. + - Function calls in the corresponding statement + Note that this include only a subset of the affectations + of the statement. Namely, the + temporary variables generated by cil are excluded (i.e. it + is assumed that the "compilation" is correct). In addition, + side effects caused by function applications are not taken + into account in the list. For a single statement, the written lvals + are supposed to be ordered (or their order of evaluation doesn't + matter), so that an alarm should be emitted only if the lvals read by + a statement overlap with the lvals written (or read) by another + statement of the sequence. + + At this time this feature is + experimental and may miss some unspecified sequences. + + In case you do not care about this feature just handle it + like a block (see {!Cil.block_from_unspecified_sequence}). + @plugin development guide *) + + | Throw of (exp * typ) option * location + (** Throws an exception, C++ style. + We keep the type of the expression, to match + it against the appropriate catch clause. A Throw node has + no successor, even if it is in try-catch block that will catch + the exception: we keep normal and exceptional control-flow + completely separate, as in Jo and Chang, ICSSA 2004. + *) + + | TryCatch of block * (catch_binder * block) list * location + + | TryFinally of block * block * location + (** On MSVC we support structured exception handling. This is what you might + expect. Control can get into the finally block either from the end of the + body block, or if an exception is thrown. + @plugin development guide *) + + | TryExcept of block * (instr list * exp) * block * location +(** On MSVC we support structured exception handling. The try/except + statement is a bit tricky: + {v __try \{ blk \} + __except (e) \{ + handler + \} + v} + + The argument to __except must be an expression. However, we keep a + list of instructions AND an expression in case you need to make + function calls. We'll print those as a comma expression. The control + can get to the __except expression only if an exception is thrown. + After that, depending on the value of the expression the control + goes to the handler, propagates the exception, or retries the + exception. The location corresponds to the try keyword. + @plugin development guide *) + +(** Kind of exceptions that are caught by a given clause. *) +and catch_binder = + | Catch_exn of varinfo * (varinfo * block) list + (** catch exception of given type(s). + If the list is empty, only exceptions with the same type as the + varinfo can be caught. If the list is non-empty, only exceptions + matching one of the type of a varinfo in the list are caught. + The associated block contains the operations necessary to transform + the matched varinfo into the principal one. + Semantics is by value (i.e. the varinfo is bound to a copy of the + caught object). + + This clause is a declaration point for the varinfo(s) + mentioned in it. More precisely, for + [Catch_exn(v_0,[(v_1, b_1),..., (v_n, b_n)])], + the [v_i] must be referenced in the [slocals] of the + enclosing [fundec], and _must not_ appear in any [blocals] + of some block. The scope of v_0 is all the [b_i] and + the corresponding block in the [catch_binder * block list] of the + [TryCatch] node the binder belongs to. The scope of the other [v_i] + is the corresponding [b_i]. + *) + | Catch_all (** default catch clause: all exceptions are caught. *) + +(** Instructions. They may cause effects directly but may not have control + flow.*) +and instr = + | Set of lval * exp * location + (** An assignment. A cast is present if the exp has different type from + lval *) + + | Call of lval option * exp * exp list * location + (** optional: result is an lval. A cast might be necessary if the declared + result type of the function is not the same as that of the destination. + Actual arguments must have a type equivalent (i.e. {!Cil.need_cast} must + return [false]) to the one of the formals of the function. + If the type of the result variable is not the same as the declared type of + the function result then an implicit cast exists. + *) + + (* See the GCC specification for the meaning of ASM. + If the source is MS VC then only the templates + are used. + + [sm] I've added a notes.txt file which contains more + information on interpreting Asm instructions *) + | Asm of + attributes (* Really only const and volatile can appear here *) + * string list (* templates (CR-separated) *) + * extended_asm option + * location + (** An inline assembly instruction. The arguments are + (1) a list of attributes (only const and volatile can appear here and only + for GCC) + (2) templates (CR-separated) + (3) GCC extended asm information if any + (4) location information *) + + | Skip of location + + | Code_annot of code_annotation * location + + +(** GNU extended-asm information: + - a list of outputs, each of which is an lvalue with optional names and + constraints. + - a list of input expressions along with constraints + - clobbered registers + - Possible destinations statements *) +and extended_asm = + { + asm_outputs: (string option * string * lval) list + (** outputs must be lvals with optional names and constraints. I would + like these to be actually variables, but I run into some trouble with + ASMs in the Linux sources *); + asm_inputs: (string option * string * exp) list + (** inputs with optional names and constraints *); + asm_clobbers: string list (** register clobbers *); + asm_gotos: (stmt ref) list + (** list of statements this asm section may jump to. Destination + must have a label. *); + } + +(** Describes a location in a source file *) +and location = Lexing.position * Lexing.position [@opaque] + +(** {1 Abstract syntax trees for annotations} *) + +and logic_constant = + | Integer of (Integer.t[@opaque]) * string option + (** Integer constant with a textual representation. *) + | LStr of string (** String constant. *) + | LWStr of int64 list (** Wide character string constant. *) + | LChr of char (** Character constant. *) + | LReal of logic_real + | LEnum of enumitem (** An enumeration constant.*) + +(** Real constants. *) +and logic_real = { + r_literal : string ; (** Initial string representation [s]. *) + r_nearest : float ; (** Nearest approximation of [s] in double precision. *) + r_upper : float ; (** Smallest double [u] such that [s <= u]. *) + r_lower : float ; (** Greatest double [l] such that [l <= s]. *) +} + +(** Types of logic terms. *) +and logic_type = + | Ctype of typ (** a C type *) + | Ltype of logic_type_info * logic_type list + (** an user-defined logic type with its parameters *) + | Lvar of string (** a type variable. *) + | Linteger (** mathematical integers, {i i.e.} Z *) + | Lreal (** mathematical reals, {i i.e.} R *) + | Larrow of logic_type list * logic_type (** (n-ary) function type *) + +(** tsets with an unique identifier. + Use [Logic_const.new_location] to generate a new id. *) +and identified_term = { + it_id: int; (** the identifier. *) + it_content: term (** the term *) +} + +(** logic label referring to a particular program point. *) +and logic_label = + | StmtLabel of stmt ref (** label of a C statement. *) + | LogicLabel of (stmt option * string) (* [JS 2011/05/13] why a tuple here? *) +(** builtin logic label ({t Here, Pre}, ...) *) + +(* ************************************************************************* *) +(** {2 Terms} *) +(* ************************************************************************* *) + +(** C Expressions as logic terms follow C constructs (with prefix T) *) + +(** Logic terms. *) +and term = { + term_node : term_node; (** kind of term. *) + term_loc : Lexing.position * Lexing.position [@opaque]; + (** position in the source file. *) + term_type : logic_type; (** type of the term. *) + term_name: string list; + (** names of the term if any. A name can be an arbitrary string, where + '"' and '\'' are escaped by a \, and which does not end with a \. + Hence, "name" and 'name' should be recognized as a unique label by most + tools. *) +} + +(** the various kind of terms. *) +and term_node = + (* same constructs as exp *) + | TConst of logic_constant (** a constant. *) + | TLval of term_lval (** an L-value *) + | TSizeOf of typ (** size of a given C type. *) + | TSizeOfE of term (** size of the type of an expression. *) + | TSizeOfStr of string (** size of a string constant. *) + | TAlignOf of typ (** alignment of a type. *) + | TAlignOfE of term (** alignment of the type of an expression. *) + | TUnOp of unop * term (** unary operator. *) + | TBinOp of binop * term * term (** binary operators. *) + | TCastE of typ * term (** cast to a C type. *) + | TAddrOf of term_lval (** address of a term. *) + | TStartOf of term_lval (** beginning of an array. *) + + (* additional constructs *) + | Tapp of logic_info * (logic_label * logic_label) list * term list + (** application of a logic function. *) + | Tlambda of quantifiers * term (** lambda abstraction. *) + | TDataCons of logic_ctor_info * term list + (** constructor of logic sum-type. *) + | Tif of term * term * term + (** conditional operator*) + | Tat of term * logic_label + (** term refers to a particular program point. *) + | Tbase_addr of logic_label * term (** base address of a pointer. *) + | Toffset of logic_label * term (** offset from the base address of a pointer. *) + | Tblock_length of logic_label * term (** length of the block pointed to by the term. *) + | Tnull (** the null pointer. *) + | TLogic_coerce of logic_type * term + (** implicit conversion from a C type to a logic type. + The logic type must not be a Ctype. In particular, used to denote + lifting to Linteger and Lreal. + *) + | TCoerce of term * typ (** coercion to a given C type. *) + | TCoerceE of term * term (** coercion to the type of a given term. *) + | TUpdate of term * term_offset * term + (** functional update of a field. *) + | Ttypeof of term (** type tag for a term. *) + | Ttype of typ (** type tag for a C type. *) + | Tempty_set (** the empty set. *) + | Tunion of term list (** union of terms. *) + | Tinter of term list (** intersection of terms. *) + | Tcomprehension of + term * quantifiers * predicate option + (** set defined in comprehension ({t \{ t[i] | integer i; 0 <= i < 5\}}) *) + | Trange of term option * term option (** range of integers. *) + | Tlet of logic_info * term (** local binding *) + +(** lvalue: base address and offset. *) +and term_lval = + term_lhost * term_offset + +(** base address of an lvalue. *) +and term_lhost = + | TVar of logic_var (** a variable. *) + | TResult of typ (** value returned by a C function. + Only used in post-conditions or assigns + *) + | TMem of term (** memory access. *) + +(** model field. *) +and model_info = { + mi_name: string; (** name *) + mi_field_type: logic_type; (** type of the field *) + mi_base_type: typ; (** type to which the field is associated. *) + mi_decl: location; (** where the field has been declared. *) +} + +(** offset of an lvalue. *) +and term_offset = + | TNoOffset (** no further offset. *) + | TField of fieldinfo * term_offset + (** access to the field of a compound type. *) + | TModel of model_info * term_offset (** access to a model field. *) + | TIndex of term * term_offset + (** index. Note that a range is denoted by [TIndex(Trange(i1,i2),ofs)] *) + +(** description of a logic function or predicate. +@plugin development guide *) +and logic_info = { +(* + mutable l_name : string; (** name of the function. *) +*) + mutable l_var_info : logic_var; + (** we use only fields lv_name and lv_id of l_var_info + we should factorize lv_type and l_type+l_profile below *) + mutable l_labels : logic_label list; (** label arguments of the function. *) + mutable l_tparams : string list; (** type parameters *) + mutable l_type : logic_type option; (** return type. None for predicates *) + mutable l_profile : logic_var list; (** type of the arguments. *) + mutable l_body : logic_body; (** body of the function. *) +} + +and builtin_logic_info = { + mutable bl_name: string; + mutable bl_labels: logic_label list; + mutable bl_params: string list; + mutable bl_type: logic_type option; + mutable bl_profile: (string * logic_type) list; +} + +and logic_body = + | LBnone (** no definition and no reads clause *) + | LBreads of identified_term list + (** read accesses performed by a function. *) + | LBterm of term (** direct definition of a function. *) + | LBpred of predicate (** direct definition of a predicate. *) + | LBinductive of + (string * logic_label list * string list * predicate) list + (** inductive definition *) + +(** Description of a logic type. + @plugin development guide *) +and logic_type_info = { + lt_name: string; + lt_params : string list; (** type parameters*) + mutable lt_def: logic_type_def option + (** definition of the type. None for abstract types. *) +} +(* will be expanded when dealing with concrete types *) + +and logic_type_def = + | LTsum of logic_ctor_info list (** sum type with its constructors. *) + | LTsyn of logic_type (** Synonym of another type. *) + +(** origin of a logic variable. *) +and logic_var_kind = + | LVGlobal (** global logic function or predicate. *) + | LVC (** Logic counterpart of a C variable. *) + | LVFormal (** formal parameter of a logic function / predicate + or \lambda abstraction *) + | LVQuant (** Bound by a quantifier (\exists or \forall) *) + | LVLocal (** local \let *) + +(** description of a logic variable +@plugin development guide *) +and logic_var = { + mutable lv_name : string; (** name of the variable. *) + mutable lv_id : int; (** unique identifier *) + mutable lv_type : logic_type; (** type of the variable. *) + mutable lv_kind: logic_var_kind; (** kind of the variable *) + mutable lv_origin : varinfo option +(** when the logic variable stems from a C variable, set to the original C + variable. *) +} + +(** Description of a constructor of a logic sum-type. + @plugin development guide *) +and logic_ctor_info = + { ctor_name: string; (** name of the constructor. *) + ctor_type: logic_type_info; (** type to which the constructor belongs. *) + ctor_params: logic_type list + (** types of the parameters of the constructor. *) + } + +(* ************************************************************************* *) +(** {2 Predicates} *) +(* ************************************************************************* *) + +(** variables bound by a quantifier. *) +and quantifiers = logic_var list + +(** comparison relations*) +and relation = + | Rlt + | Rgt + | Rle + | Rge + | Req + | Rneq (** @plugin development guide *) + + +(** predicates *) +and predicate_node = + | Pfalse (** always-false predicate. *) + | Ptrue (** always-true predicate. *) + | Papp of logic_info * (logic_label * logic_label) list * term list + (** application of a predicate. *) + | Pseparated of term list + | Prel of relation * term * term (** comparison of two terms. *) + | Pand of predicate * predicate (** conjunction *) + | Por of predicate * predicate (** disjunction. *) + | Pxor of predicate * predicate (** logical xor. *) + | Pimplies of predicate * predicate (** implication. *) + | Piff of predicate * predicate (** equivalence. *) + | Pnot of predicate (** negation. *) + | Pif of term * predicate * predicate (** conditional *) + | Plet of logic_info * predicate (** definition of a local variable *) + | Pforall of quantifiers * predicate (** universal quantification. *) + | Pexists of quantifiers * predicate (** existential quantification. *) + | Pat of predicate * logic_label + (** predicate refers to a particular program point. *) + | Pvalid_read of logic_label * term (** the given locations are valid for reading. *) + | Pvalid of logic_label * term (** the given locations are valid. *) + | Pvalid_function of term + (** the pointed function has a type compatible with the one of pointer. *) + | Pinitialized of logic_label * term (** the given locations are initialized. *) + | Pdangling of logic_label * term (** the given locations contain dangling + adresses. *) + | Pallocable of logic_label * term (** the given locations can be allocated. *) + | Pfreeable of logic_label * term (** the given locations can be free. *) + | Pfresh of logic_label * logic_label * term * term + (** \fresh(pointer, n) + A memory block of n bytes is newly allocated to the pointer.*) + | Psubtype of term * term + (** First term is a type tag that is a subtype of the second. *) + +(** predicate with an unique identifier. Use [Logic_const.new_predicate] to + create fresh predicates *) +and identified_predicate = { + ip_id: int; (** identifier *) + ip_content: predicate; (** the predicate itself*) +} + +(** predicates with a location and an optional list of names *) +and predicate = { + pred_name : string list; (** list of given names *) + pred_loc : location; (** position in the source code. *) + pred_content : predicate_node;(** content *) +} + +(* Polymorphic types shared with parsed trees (Logic_ptree) *) +(** variant of a loop or a recursive function. Type shared with Logic_ptree. *) +and 'term variant = 'term * string option + +(** allocates and frees. + @since Oxygen-20120901 *) +and 'locs allocation = + | FreeAlloc of 'locs list * 'locs list (** tsets. Empty list means \nothing. *) + | FreeAllocAny (** Nothing specified. Semantics depends on where it + is written. *) + +(** dependencies of an assigned location. Shared with Logic_ptree. *) +and 'locs deps = + | From of 'locs list (** tsets. Empty list means \nothing. *) + | FromAny (** Nothing specified. Any location can be involved. *) + +and 'locs from = ('locs * 'locs deps) + +(** zone assigned with its dependencies. Type shared with Logic_ptree. *) +and 'locs assigns = + | WritesAny (** Nothing specified. Anything can be written. *) + | Writes of 'locs from list + (** list of locations that can be written. Empty list means \nothing. *) + +(** Function or statement contract. This type shares the name of its + constructors with {!Logic_ptree.spec}. *) +and spec = { + mutable spec_behavior : behavior list; + (** behaviors *) + + mutable spec_variant : term variant option; + (** variant for recursive functions. *) + + mutable spec_terminates: identified_predicate option; + (** termination condition. *) + + mutable spec_complete_behaviors: string list list; + (** list of complete behaviors. + It is possible to have more than one set of complete behaviors *) + + mutable spec_disjoint_behaviors: string list list; + (** list of disjoint behaviors. + It is possible to have more than one set of disjoint behaviors *) +} + + +(** extension to standard ACSL clause. + Each extension is associated to a keyword. An extension + can be registered through the following functions: + - {!Logic_typing.register_behavior_extension} for parsing and type-checking + - {!Cil_printer.register_behavior_extension} for pretty-printing an + extended clause + - {!Cil.register_behavior_extension} for visiting an extended clause + + @plugin development guide *) +and acsl_extension = string * acsl_extension_kind + +and acsl_extension_kind = + | Ext_id of int (** id used internally by the extension itself. *) + | Ext_terms of term list + | Ext_preds of predicate list + (** a list of predicates, the most common case of for extensions *) + +(** Behavior of a function or statement. This type shares the name of its + constructors with {!Logic_ptree.behavior}. + @since Oxygen-20120901 [b_allocation] has been added. + @since Carbon-20101201 [b_requires] has been added. + @modify Boron-20100401 [b_ensures] is replaced by [b_post_cond]. + Old [b_ensures] represent the [Normal] case of [b_post_cond]. *) +and behavior = { + mutable b_name : string; (** name of the behavior. *) + mutable b_requires : identified_predicate list; (** require clauses. *) + mutable b_assumes : identified_predicate list; (** assume clauses. *) + mutable b_post_cond : (termination_kind * identified_predicate) list + (** post-condition. *); + mutable b_assigns : identified_term assigns; (** assignments. *) + mutable b_allocation : identified_term allocation; (** frees, allocates. *) + mutable b_extended : acsl_extension list (** extensions *) +} + +(** kind of termination a post-condition applies to. See ACSL manual. *) +and termination_kind = Normal | Exits | Breaks | Continues | Returns + +(** Pragmas for the value analysis plugin of Frama-C. + Type shared with Logic_ptree.*) +and 'term loop_pragma = + | Unroll_specs of 'term list + | Widen_hints of 'term list + | Widen_variables of 'term list + +(** Pragmas for the slicing plugin of Frama-C. Type shared with Logic_ptree.*) +and 'term slice_pragma = + | SPexpr of 'term + | SPctrl + | SPstmt + +(** Pragmas for the impact plugin of Frama-C. Type shared with Logic_ptree.*) +and 'term impact_pragma = + | IPexpr of 'term + | IPstmt + +(** The various kinds of pragmas. Type shared with Logic_ptree. *) +and 'term pragma = + | Loop_pragma of 'term loop_pragma + | Slice_pragma of 'term slice_pragma + | Impact_pragma of 'term impact_pragma + +(** all annotations that can be found in the code. + This type shares the name of its constructors with + {!Logic_ptree.code_annot}. *) +and code_annotation_node = + | AAssert of string list * predicate + (** assertion to be checked. The list of strings is the list of + behaviors to which this assertion applies. *) + + | AStmtSpec of string list * spec + (** statement contract + (potentially restricted to some enclosing behaviors). *) + + | AInvariant of string list * bool * predicate + (** loop/code invariant. The list of strings is the list of behaviors to which + this invariant applies. The boolean flag is true for normal loop + invariants and false for invariant-as-assertions. *) + + | AVariant of term variant + (** loop variant. Note that there can be at most one variant associated to a + given statement *) + + | AAssigns of string list * identified_term assigns + (** loop assigns. (see [b_assigns] in the behaviors for other assigns). At + most one clause associated to a given (statement, behavior) couple. *) + + | AAllocation of string list * identified_term allocation + (** loop allocation clause. (see [b_allocation] in the behaviors for other + allocation clauses). + At most one clause associated to a given (statement, behavior) couple. + @since Oxygen-20120901 when [b_allocation] has been added. *) + + | APragma of term pragma (** pragma. *) + | AExtended of string list * acsl_extension + (** extension in a loop annotation. + @since Silicon-20161101 *) + +(** function contract. *) + +and funspec = spec + +(** code annotation with an unique identifier. + Use [Logic_const.new_code_annotation] to create new code annotations with + a fresh id. *) +and code_annotation = { + annot_id: int; (** identifier. *) + annot_content : code_annotation_node; (** content of the annotation. *) +} + +(** behavior of a function. *) +and funbehavior = behavior + +(** global annotations, not attached to a statement or a function. *) +and global_annotation = + | Dfun_or_pred of logic_info * location + | Dvolatile of + identified_term list * varinfo option * varinfo option * location + (** associated terms, reading function, writing function *) + | Daxiomatic of string * global_annotation list * location + | Dtype of logic_type_info * location (** declaration of a logic type. *) + | Dlemma of + string * bool * logic_label list * string list * + predicate * location + (** definition of a lemma. The boolean flag is [true] if the property should + be taken as an axiom and [false] if it must be proved. *) + | Dinvariant of logic_info * location + (** global invariant. The predicate does not have any argument. *) + | Dtype_annot of logic_info * location + (** type invariant. The predicate has exactly one argument. *) + | Dmodel_annot of model_info * location + (** Model field for a type t, seen as a logic function with one + argument of type t *) + | Dcustom_annot of custom_tree * string* location + (*Custom declaration*) + +and custom_tree = CustomDummy +(* + | CustomType of logic_type + | CustomLexpr of lexpr + | CustomOther of string * (custom_tree list) +*) +[@@deriving visitors { variety = "iter"; irregular = true }, + visitors { variety = "map"; irregular = true }, + visitors { variety = "endo"; irregular = true }, + visitors { variety = "reduce"; irregular = true }, + visitors { variety = "mapreduce"; irregular = true }, + visitors { variety = "fold"; irregular = true; ancestors = ["VisitorsRuntime.map"] }, + visitors { variety = "iter2"; irregular = true }, + visitors { variety = "map2"; irregular = true }, + visitors { variety = "reduce2"; irregular = true }, + visitors { variety = "mapreduce2"; irregular = true }, + visitors { variety = "fold2"; irregular = true; ancestors = ["VisitorsRuntime.map2"] } +] + +(* Provide the missing methods so as to obtain concrete classes. *) +class ['self] iter_ = object (self : 'self) + inherit [_] iter + method visit_'locs env (t : identified_term) = self#visit_identified_term env t + method visit_'term env (t : term) = self#visit_term env t +end +class ['self] map_ = object (self : 'self) + inherit [_] map + method visit_'locs env (t : identified_term) = self#visit_identified_term env t + method visit_'term env (t : term) = self#visit_term env t +end +class ['self] endo_ = object (self : 'self) + inherit [_] endo + method visit_'locs env (t : identified_term) = self#visit_identified_term env t + method visit_'term env (t : term) = self#visit_term env t +end +class ['self] reduce_ = object (self : 'self) + inherit [_] VisitorsRuntime.addition_monoid + inherit [_] reduce + method visit_'locs env (t : identified_term) = self#visit_identified_term env t + method visit_'term env (t : term) = self#visit_term env t +end +class ['self] mapreduce_ = object (self : 'self) + inherit [_] VisitorsRuntime.addition_monoid + inherit [_] mapreduce + method visit_'locs env (t : identified_term) = self#visit_identified_term env t + method visit_'term env (t : term) = self#visit_term env t +end + +type kinstr = + | Kstmt of stmt + | Kglobal + +(** Internal representation of decorated C functions *) +type cil_function = + | Definition of (fundec * location) (** defined function *) + | Declaration of (funspec * varinfo * varinfo list option * location) + (** Declaration(spec,f,args,loc) represents a leaf function [f] with + specification [spec] and arguments [args], at location [loc]. As + with the [TFun] constructor of {!Cil_types.typ}, the arg list is + optional, to distinguish [void f()] ([None]) from + [void f(void)] ([Some []]). *) + +(** Only field [fundec] can be used directly. Use {!Annotations.funspec}, + [Annotations.add_*] and [Annotations.remove_*] to query or modify field + [spec]. *) +type kernel_function = { + mutable fundec : cil_function; + mutable spec : funspec; +} + +(* [VP] TODO: VLocal should be attached to a particular block, not a whole + function. *) +type localisation = + | VGlobal + | VLocal of kernel_function + | VFormal of kernel_function + +type mach = { + sizeof_short: int; (* Size of "short" *) + sizeof_int: int; (* Size of "int" *) + sizeof_long: int ; (* Size of "long" *) + sizeof_longlong: int; (* Size of "long long" *) + sizeof_ptr: int; (* Size of pointers *) + sizeof_float: int; (* Size of "float" *) + sizeof_double: int; (* Size of "double" *) + sizeof_longdouble: int; (* Size of "long double" *) + sizeof_void: int; (* Size of "void" *) + sizeof_fun: int; (* Size of function *) + size_t: string; (* Type of "sizeof(T)" *) + wchar_t: string; (* Type of "wchar_t" *) + ptrdiff_t: string; (* Type of "ptrdiff_t" *) + alignof_short: int; (* Alignment of "short" *) + alignof_int: int; (* Alignment of "int" *) + alignof_long: int; (* Alignment of "long" *) + alignof_longlong: int; (* Alignment of "long long" *) + alignof_ptr: int; (* Alignment of pointers *) + alignof_float: int; (* Alignment of "float" *) + alignof_double: int; (* Alignment of "double" *) + alignof_longdouble: int; (* Alignment of "long double" *) + alignof_str: int; (* Alignment of strings *) + alignof_fun: int; (* Alignment of function *) + char_is_unsigned: bool; (* Whether "char" is unsigned *) + underscore_name: bool; (* If assembly names have leading underscore *) + const_string_literals: bool; (* Whether string literals have const chars *) + little_endian: bool; (* whether the machine is little endian *) + alignof_aligned: int (* Alignment of a type with aligned attribute *); + has__builtin_va_list: bool (* Whether [__builtin_va_list] is a known type *); + __thread_is_keyword: bool (* Whether [__thread] is a keyword *); + compiler: string; (* Compiler being used. Currently recognized names + are 'gcc', 'msvc' and 'generic'. *) + version: string; (* Information on this machdep *) +} diff --git a/test/cil_types.ml.orig b/test/cil_types.ml.orig new file mode 100644 index 0000000..d5558eb --- /dev/null +++ b/test/cil_types.ml.orig @@ -0,0 +1,1775 @@ +(****************************************************************************) +(* *) +(* Copyright (C) 2001-2003 *) +(* George C. Necula *) +(* Scott McPeak *) +(* Wes Weimer *) +(* Ben Liblit *) +(* All rights reserved. *) +(* *) +(* Redistribution and use in source and binary forms, with or without *) +(* modification, are permitted provided that the following conditions *) +(* are met: *) +(* *) +(* 1. Redistributions of source code must retain the above copyright *) +(* notice, this list of conditions and the following disclaimer. *) +(* *) +(* 2. Redistributions in binary form must reproduce the above copyright *) +(* notice, this list of conditions and the following disclaimer in the *) +(* documentation and/or other materials provided with the distribution. *) +(* *) +(* 3. The names of the contributors may not be used to endorse or *) +(* promote products derived from this software without specific prior *) +(* written permission. *) +(* *) +(* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *) +(* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *) +(* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *) +(* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *) +(* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, *) +(* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, *) +(* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; *) +(* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *) +(* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *) +(* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN *) +(* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE *) +(* POSSIBILITY OF SUCH DAMAGE. *) +(* *) +(* File modified by CEA (Commissariat à l'énergie atomique et aux *) +(* énergies alternatives) *) +(* and INRIA (Institut National de Recherche en Informatique *) +(* et Automatique). *) +(****************************************************************************) + +(** The Abstract Syntax of CIL. + @plugin development guide *) + +(**************************** WARNING ***************************************) +(* Remember to reflect any change here into the visitor and pretty-printer *) +(* in cil.ml. In particular, if a type becomes mutable, it is necessary to *) +(* adapt the Cil.behavior type and the copy_behavior accordingly. *) +(* A first test to see if something has been broken by a change is to launch*) +(* ptests.byte -add-options '-files-debug "-check -copy"' *) +(* In addition, it is a good idea to add some invariant checks in the *) +(* check_file class in frama-c/src/file.ml (before lauching the tests) *) +(****************************************************************************) + +(* ************************************************************************* *) +(** {2 Root of the AST} *) +(* ************************************************************************* *) + +(** In Frama-C, the whole AST is accessible through {!Ast.get}. *) + +(** The top-level representation of a CIL source file (and the result of the + parsing and elaboration). Its main contents is the list of global + declarations and definitions. You can iterate over the globals in a + {!Cil_types.file} using the following iterators: {!Cil.mapGlobals}, + {!Cil.iterGlobals} and {!Cil.foldGlobals}. You can also use the + {!Cil.dummyFile} when you need a {!Cil_types.file} as a placeholder. For + each global item CIL stores the source location where it appears (using the + type {!Cil_types.location}) + @plugin development guide *) +type file = { + mutable fileName: string; (** The complete file name *) + + mutable globals: global list; + (** List of globals as they will appear in the printed file *) + + mutable globinit: fundec option; + (** An optional global initializer function. This is a function where you + can put stuff that must be executed before the program is + started. This function, is conceptually at the end of the file, + although it is not part of the globals list. Use {!Cil.getGlobInit} to + create/get one. *) + + mutable globinitcalled: bool; +(** Whether the global initialization function is called in main. This + should always be false if there is no global initializer. When you + create a global initialization CIL will try to insert code in main to + call it. *) +} + +(** The main type for representing global declarations and definitions. A list + of these form a CIL file. The order of globals in the file is generally + important. + @plugin development guide *) +and global = + | GType of typeinfo * location + (** A typedef. All uses of type names (through the [TNamed] constructor) + must be preceeded in the file by a definition of the name. The string + is the defined name and always not-empty. *) + + | GCompTag of compinfo * location + (** Defines a struct/union tag with some fields. There must be one of + these for each struct/union tag that you use (through the [TComp] + constructor) since this is the only context in which the fields are + printed. Consequently nested structure tag definitions must be + broken into individual definitions with the innermost structure + defined first. *) + + | GCompTagDecl of compinfo * location + (** Declares a struct/union tag. Use as a forward declaration. This is + printed without the fields. *) + + | GEnumTag of enuminfo * location + (** Declares an enumeration tag with some fields. There must be one of + these for each enumeration tag that you use (through the [TEnum] + constructor) since this is the only context in which the items are + printed. *) + + | GEnumTagDecl of enuminfo * location + (** Declares an enumeration tag. Use as a forward declaration. This is + printed without the items. *) + + | GVarDecl of varinfo * location + (** A variable declaration (not a definition) for a variable with object + type. There can be several declarations and at most one definition for + a given variable. If both forms appear then they must share the same + varinfo structure. Either has storage Extern or there must be a + definition in this file *) + + | GFunDecl of funspec * varinfo * location + (** A variable declaration (not a definition) for a function, i.e. a + prototype. There can be several declarations and at most one definition + for a given function. If both forms appear then they must share the same + varinfo structure. A prototype shares the varinfo with the fundec of the + definition. Either has storage Extern or there must be a definition in + this file. *) + + | GVar of varinfo * initinfo * location + (** A variable definition. Can have an initializer. The initializer is + updateable so that you can change it without requiring to recreate the + list of globals. There can be at most one definition for a variable in an + entire program. Cannot have storage Extern or function type. *) + + | GFun of fundec * location + (** A function definition. *) + + | GAsm of string * location + (** Global asm statement. These ones can contain only a template *) + + | GPragma of attribute * location + (** Pragmas at top level. Use the same syntax as attributes *) + + | GText of string + (** Some text (printed verbatim) at top level. E.g., this way you can put + comments in the output. *) + + | GAnnot of global_annotation * location +(** a global annotation. Can be + - an axiom or a lemma + - a predicate declaration or definition + - a global type invariant + - a global invariant + - a logic function declaration or definition. *) + +(* ************************************************************************* *) +(** {2 Types} *) +(* ************************************************************************* *) + +(** A C type is represented in CIL using the type {!Cil_types.typ}. Among types + we differentiate the integral types (with different kinds denoting the sign + and precision), floating point types, enumeration types, array and pointer + types, and function types. Every type is associated with a list of + attributes, which are always kept in sorted order. Use {!Cil.addAttribute} + and {!Cil.addAttributes} to construct list of attributes. If you want to + inspect a type, you should use {!Cil.unrollType} or {!Cil.unrollTypeDeep} to + see through the uses of named types. + + CIL is configured at build-time with the sizes and alignments of the + underlying compiler (GCC or MSVC). CIL contains functions that can compute + the size of a type (in bits) {!Cil.bitsSizeOf}, the alignment of a type (in + bytes) {!Cil.alignOf_int}, and can convert an offset into a start and width + (both in bits) using the function {!Cil.bitsOffset}. At the moment these + functions do not take into account the [packed] attributes and pragmas. *) + +and typ = + | TVoid of attributes (** Void type. Also predefined as {!Cil.voidType} *) + + | TInt of ikind * attributes + (** An integer type. The kind specifies the sign and width. Several useful + variants are predefined as {!Cil.intType}, {!Cil.uintType}, + {!Cil.longType}, {!Cil.charType}. *) + + | TFloat of fkind * attributes + (** A floating-point type. The kind specifies the precision. You can also use + the predefined constant {!Cil.doubleType}. *) + + | TPtr of typ * attributes + (** Pointer type. Several useful variants are predefined as + {!Cil.charPtrType}, {!Cil.charConstPtrType} (pointer to a constant + character), {!Cil.voidPtrType}, {!Cil.intPtrType} *) + + | TArray of typ * exp option * bitsSizeofTypCache * attributes + (** Array type. It indicates the base type and the array length. *) + + | TFun of typ * (string * typ * attributes) list option * bool * attributes + (** Function type. Indicates the type of the result, the name, type + and name attributes of the formal arguments ([None] if no arguments + were specified, as in a function whose definition or prototype we + have not seen; [Some \[\]] means void). Use {!Cil.argsToList} to + obtain a list of arguments. The boolean indicates if it is a + variable-argument function. If this is the type of a varinfo for + which we have a function declaration then the information for the + formals must match that in the function's sformals. Use + {!Cil.setFormals}, or {!Cil.setFunctionType}, or + {!Cil.makeFormalVar} for this purpose. *) + + | TNamed of typeinfo * attributes + (** The use of a named type. All uses of the same type name must share the + typeinfo. Each such type name must be preceeded in the file by a [GType] + global. This is printed as just the type name. The actual referred type + is not printed here and is carried only to simplify processing. To see + through a sequence of named type references, use {!Cil.unrollType}. The + attributes are in addition to those given when the type name was + defined. *) + + | TComp of compinfo * bitsSizeofTypCache * attributes + (** A reference to a struct or a union type. All references to the + same struct or union must share the same compinfo among them and + with a [GCompTag] global that preceeds all uses (except maybe + those that are pointers to the composite type). The attributes + given are those pertaining to this use of the type and are in + addition to the attributes that were given at the definition of + the type and which are stored in the compinfo. *) + + | TEnum of enuminfo * attributes + (** A reference to an enumeration type. All such references must + share the enuminfo among them and with a [GEnumTag] global that + preceeds all uses. The attributes refer to this use of the + enumeration and are in addition to the attributes of the + enumeration itself, which are stored inside the enuminfo *) + + | TBuiltin_va_list of attributes +(** This is the same as the gcc's type with the same name *) + +(** Various kinds of integers *) +and ikind = + IBool (** [_Bool] *) + | IChar (** [char] *) + | ISChar (** [signed char] *) + | IUChar (** [unsigned char] *) + | IInt (** [int] *) + | IUInt (** [unsigned int] *) + | IShort (** [short] *) + | IUShort (** [unsigned short] *) + | ILong (** [long] *) + | IULong (** [unsigned long] *) + | ILongLong (** [long long] (or [_int64] on Microsoft Visual C) *) + | IULongLong (** [unsigned long long] (or [unsigned _int64] on Microsoft + Visual C) *) + +(** Various kinds of floating-point numbers*) +and fkind = + FFloat (** [float] *) + | FDouble (** [double] *) + | FLongDouble (** [long double] *) + +(** This is used to cache the computation of the size of types in bits. *) +and bitsSizeofTyp = + | Not_Computed + | Computed of int + | Not_Computable of (string * typ) (** Explanation of the error *) + +and bitsSizeofTypCache = { mutable scache : bitsSizeofTyp} + +(* ************************************************************************* *) +(** {2 Attributes} *) +(* ************************************************************************* *) + +and attribute = + | Attr of string * attrparam list + (** An attribute has a name and some optional parameters. The name should not + start or end with underscore. When CIL parses attribute names it will + strip leading and ending underscores (to ensure that the multitude of GCC + attributes such as const, __const and __const__ all mean the same + thing.) *) + + | AttrAnnot of string + +(** Attributes are lists sorted by the attribute name. Use the functions + {!Cil.addAttribute} and {!Cil.addAttributes} to insert attributes in an + attribute list and maintain the sortedness. *) +and attributes = attribute list + +(** The type of parameters of attributes *) +and attrparam = + | AInt of Integer.t (** An integer constant *) + | AStr of string (** A string constant *) + | ACons of string * attrparam list + (** Constructed attributes. These are printed [foo(a1,a2,...,an)]. The list + of parameters can be empty and in that case the parentheses are not + printed. *) + | ASizeOf of typ (** A way to talk about types *) + | ASizeOfE of attrparam + | AAlignOf of typ + | AAlignOfE of attrparam + | AUnOp of unop * attrparam + | ABinOp of binop * attrparam * attrparam + | ADot of attrparam * string (** a.foo **) + | AStar of attrparam (** * a *) + | AAddrOf of attrparam (** & a **) + | AIndex of attrparam * attrparam (** a1[a2] *) + | AQuestion of attrparam * attrparam * attrparam (** a1 ? a2 : a3 **) + +(* ************************************************************************* *) +(** {2 Structures} *) +(* ************************************************************************* *) + +(** The {!Cil_types.compinfo} describes the definition of a structure or union + type. Each such {!Cil_types.compinfo} must be defined at the top-level using + the [GCompTag] constructor and must be shared by all references to this type + (using either the [TComp] type constructor or from the definition of the + fields. + + If all you need is to scan the definition of each composite type once, you + can do that by scanning all top-level [GCompTag]. + + Constructing a {!Cil_types.compinfo} can be tricky since it must contain + fields that might refer to the host {!Cil_types.compinfo} and furthermore + the type of the field might need to refer to the {!Cil_types.compinfo} for + recursive types. Use the {!Cil.mkCompInfo} function to create a + {!Cil_types.compinfo}. You can easily fetch the {!Cil_types.fieldinfo} for a + given field in a structure with {!Cil.getCompField}. *) + +(** The definition of a structure or union type. Use {!Cil.mkCompInfo} to make + one and use {!Cil.copyCompInfo} to copy one (this ensures that a new key is + assigned and that the fields have the right pointers to parents.). + @plugin development guide *) +and compinfo = { + mutable cstruct: bool; + (** [true] if struct, [false] if union *) + + corig_name: string; + (** Original name as found in C file. Will never be changed *) + + mutable cname: string; + (** The name. Always non-empty. Use {!Cil.compFullName} to get the full name + of a comp (along with the struct or union) *) + + mutable ckey: int; + (** A unique integer. This is assigned by {!Cil.mkCompInfo} using a global + variable in the Cil module. Thus two identical structs in two different + files might have different keys. Use {!Cil.copyCompInfo} to copy + structures so that a new key is assigned. *) + + mutable cfields: fieldinfo list; + (** Information about the fields. Notice that each fieldinfo has a pointer + back to the host compinfo. This means that you should not share + fieldinfo's between two compinfo's *) + + mutable cattr: attributes; + (** The attributes that are defined at the same time as the composite + type. These attributes can be supplemented individually at each + reference to this [compinfo] using the [TComp] type constructor. *) + + mutable cdefined: bool; + (** This boolean flag can be used to distinguish between structures + that have not been defined and those that have been defined but have + no fields (such things are allowed in gcc). *) + + mutable creferenced: bool; +(** [true] if used. Initially set to [false]. *) +} + +(* ************************************************************************* *) +(** {2 Structure fields} *) +(* ************************************************************************* *) + +(** The {!Cil_types.fieldinfo} structure is used to describe a structure or + union field. Fields, just like variables, can have attributes associated + with the field itself or associated with the type of the field (stored along + with the type of the field). *) + +(** Information about a struct/union field. + @plugin development guide *) +and fieldinfo = { + mutable fcomp: compinfo; + (** The host structure that contains this field. There can be only one + [compinfo] that contains the field. *) + + forig_name: string; + (** original name as found in C file. *) + + mutable fname: string; + (** The name of the field. Might be the value of {!Cil.missingFieldName} in + which case it must be a bitfield and is not printed and it does not + participate in initialization *) + + mutable ftype: typ; + (** The type. If the field is a bitfield, a special attribute + [FRAMA_C_BITFIELD_SIZE] indicating the width of the bitfield is added. *) + + mutable fbitfield: int option; + (** If a bitfield then ftype should be an integer type and the width of the + bitfield must be 0 or a positive integer smaller or equal to the width of + the integer type. A field of width 0 is used in C to control the alignment + of fields. *) + + mutable fattr: attributes; + (** The attributes for this field (not for its type) *) + + mutable floc: location; + (** The location where this field is defined *) + + mutable faddrof: bool; + (** Adapted from CIL [vaddrof] field for variables. Only set for non-array + fields. Variable whose field address is taken is not marked anymore as + having its own address taken. True if the address of this field is + taken. CIL will set these flags when it parses C, but you should make + sure to set the flag whenever your transformation create [AddrOf] + expression. *) + + mutable fsize_in_bits: int option; + (** (Deprecated. Use {!Cil.bitsOffset} instead.) Similar to [fbitfield] for + all types of fields. + @deprecated only Jessie uses this *) + + mutable foffset_in_bits: int option; + (** Offset at which the field starts in the structure. Do not read directly, + but use {!Cil.bitsOffset} instead. *) + + mutable fpadding_in_bits: int option; +(** (Deprecated.) Store the size of the padding that follows the field, if any. + @deprecated only Jessie uses this *) +} + +(* ************************************************************************* *) +(** {2 Enumerations} *) +(* ************************************************************************* *) + +(** Information about an enumeration. This is shared by all references to an + enumeration. Make sure you have a [GEnumTag] for each of these. *) + +(** Information about an enumeration. + @plugin development guide *) +and enuminfo = { + eorig_name: string; (** original name as found in C file. *) + + mutable ename: string; (** The name. Always non-empty. *) + + mutable eitems: enumitem list; (** Items. The list must be non-empty *) + + mutable eattr: attributes; + (** The attributes that are defined at the same time as the enumeration + type. These attributes can be supplemented individually at each + reference to this [enuminfo] using the [TEnum] type constructor. *) + + mutable ereferenced: bool; (** [true] if used. Initially set to [false]. *) + mutable ekind: ikind (** The integer kind used to represent this enum. MSVC + always assumes IInt but this is not the case + for gcc. See ISO C 6.7.2.2 *) +} + +and enumitem = { + eiorig_name: string; (** original name as found in C file. *) + mutable einame: string; (** the name, always non-empty. *) + mutable eival: exp; (** value of the item. Must be a compile-time constant *) + mutable eihost: enuminfo; (** the host enumeration in which the item is + declared. *) + eiloc: location; +} + +(** Information about a defined type. + @plugin development guide *) +and typeinfo = { + torig_name: string; (** original name as found in C file. *) + + mutable tname: string; + (** The name. Can be empty only in a [GType] when introducing a composite or + enumeration tag. If empty cannot be refered to from the file *) + + mutable ttype: typ; + (** The actual type. This includes the attributes that were present in the + typedef *) + + mutable treferenced: bool; (** [true] if used. Initially set to [false]. *) +} + +(* ************************************************************************* *) +(** {2 Variables} *) +(* ************************************************************************* *) + +(** Each local or global variable is represented by a unique + {!Cil_types.varinfo} structure. A global {!Cil_types.varinfo} can be + introduced with the [GVarDecl] or [GVar], [GFunDecl] or [GFun] globals. + A local varinfo can be introduced as part of a function definition + {!Cil_types.fundec}. + + All references to a given global or local variable must refer to the same + copy of the [varinfo]. Each [varinfo] has a globally unique identifier that + can be used to index maps and hashtables (the name can also be used for this + purpose, except for locals from different functions). This identifier is + constructor using a global counter. + + It is very important that you construct [varinfo] structures using only one + of the following functions: + - {!Cil.makeGlobalVar} : to make a global variable + - {!Cil.makeTempVar} : to make a temporary local variable whose name + will be generated so that to avoid conflict with other locals. + - {!Cil.makeLocalVar} : like {!Cil.makeTempVar} but you can specify the + exact name to be used. + - {!Cil.copyVarinfo}: make a shallow copy of a varinfo assigning a new name + and a new unique identifier + + A [varinfo] is also used in a function type to denote the list of + formals. *) + +(** Information about a variable. + @plugin development guide *) +and varinfo = { + mutable vname: string; + (** The name of the variable. Cannot be empty. It is primarily your + responsibility to ensure the uniqueness of a variable name. For local + variables {!Cil.makeTempVar} helps you ensure that the name is + unique. *) + + vorig_name: string; + (** the original name of the variable. Need not be unique. *) + + mutable vtype: typ; + (** The declared type of the variable. *) + + mutable vattr: attributes; + (** A list of attributes associated with the variable.*) + + mutable vstorage: storage; + (** The storage-class *) + + mutable vglob: bool; + (** True if this is a global variable*) + + mutable vdefined: bool; + (** True if the variable or function is defined in the file. Only relevant + for functions and global variables. Not used in particular for local + variables and logic variables. *) + + mutable vformal: bool; + (** True if the variable is a formal parameter of a function. *) + + mutable vinline: bool; + (** Whether this varinfo is for an inline function. *) + + mutable vdecl: location; + (** Location of variable declaration. *) + + mutable vid: int; + (** A unique integer identifier. This field will be set for you if you use + one of the {!Cil.makeFormalVar}, {!Cil.makeLocalVar}, + {!Cil.makeTempVar}, {!Cil.makeGlobalVar}, or {!Cil.copyVarinfo}. *) + + mutable vaddrof: bool; + (** [true] if the address of this variable is taken. CIL will set these + flags when it parses C, but you should make sure to set the flag + whenever your transformation create [AddrOf] expression. *) + + mutable vreferenced: bool; + (** [true] if this variable is ever referenced. This is computed by + [removeUnusedVars]. It is safe to just initialize this to [false]. *) + + vtemp: bool; + (** [true] for temporary variables generated by CIL normalization. [false] + for all the other variables. *) + + mutable vdescr: string option; + (** For most temporary variables, a description of what the var holds. + (e.g. for temporaries used for function call results, this string is a + representation of the function call.) *) + + mutable vdescrpure: bool; + (** Indicates whether the vdescr above is a pure expression or call. True + for all CIL expressions and Lvals, but false for e.g. function calls. + Printing a non-pure vdescr more than once may yield incorrect + results. *) + + mutable vghost: bool; + (** Indicates if the variable is declared in ghost code *) + + vsource: bool; + (** [true] iff this variable appears in the source of the program, which is + the case of all the variables in the initial AST. Plugins may create + variables with [vsource=false], for example to handle dynamic allocation. + Those variables do *not* have an associated {!GVar} or {!GVarDecl}. *) + + mutable vlogic_var_assoc: logic_var option + (** Logic variable representing this variable in the logic world. Do not + access this field directly. Instead, call {!Cil.cvar_to_lvar}. *) +} + +(** Storage-class information *) +and storage = + NoStorage (** The default storage. Nothing is printed *) + | Static + | Register + | Extern + +(* ************************************************************************* *) +(** {2 Expressions} *) +(* ************************************************************************* *) + +(** The CIL expression language contains only the side-effect free expressions + of C. They are represented as the type {!Cil_types.exp}. There are several + interesting aspects of CIL expressions: + + Integer and floating point constants can carry their textual representation. + This way the integer 15 can be printed as 0xF if that is how it occurred in + the source. + + CIL uses arbitrary precision integers + to represent the integer constants and also stores the + width of the integer type. Care must be taken to ensure that the constant is + representable with the given width. Use the functions {!Cil.kinteger}, + {!Cil.kinteger64} and {!Cil.integer} to construct constant expressions. CIL + predefines the constants {!Cil.zero}, {!Cil.one} and {!Cil.mone} (for -1). + + Use the functions {!Cil.isConstant} and {!Cil.isInteger} to test if an + expression is a constant and a constant integer respectively. + + CIL keeps the type of all unary and binary expressions. You can think of + that type qualifying the operator. Furthermore there are different operators + for arithmetic and comparisons on arithmetic types and on pointers. + + Another unusual aspect of CIL is that the implicit conversion between an + expression of array type and one of pointer type is made explicit, using the + [StartOf] expression constructor (which is not printed). If you apply the + [AddrOf]constructor to an lvalue of type [T] then you will be getting an + expression of type [TPtr(T)]. + + You can find the type of an expression with {!Cil.typeOf}. + + You can perform constant folding on expressions using the function + {!Cil.constFold}. *) + +(** Expressions (Side-effect free)*) +and exp = { + eid: int; (** unique identifier *) + enode: exp_node; (** the expression itself *) + eloc: location; (** location of the expression. *) +} + +and exp_node = + | Const of constant (** Constant *) + | Lval of lval (** Lvalue *) + | SizeOf of typ + (** sizeof(). Has [unsigned int] type (ISO 6.5.3.4). This is not + turned into a constant because some transformations might want to change + types *) + + | SizeOfE of exp (** sizeof() *) + + | SizeOfStr of string + (** sizeof(string_literal). We separate this case out because this is the + only instance in which a string literal should not be treated as having + type pointer to character. *) + + | AlignOf of typ + (** This corresponds to the GCC __alignof_. Has [unsigned int] type *) + + | AlignOfE of exp + + | UnOp of unop * exp * typ + (** Unary operation. Includes the type of the result. *) + + | BinOp of binop * exp * exp * typ + (** Binary operation. Includes the type of the result. The arithmetic + conversions are made explicit for the arguments. + @plugin development guide *) + + | CastE of typ * exp + (** Use {!Cil.mkCast} to make casts. *) + + | AddrOf of lval + (** Always use {!Cil.mkAddrOf} to construct one of these. Apply to an lvalue + of type [T] yields an expression of type [TPtr(T)] *) + + | StartOf of lval + (** Conversion from an array to a pointer to the beginning of the array. + Given an lval of type [TArray(T)] produces an expression of type + [TPtr(T)]. In C this operation is implicit, the [StartOf] operator is not + printed. We have it in CIL because it makes the typing rules simpler. *) + + | Info of exp * exp_info +(** Additional information on the underlying expression *) + +(** Additional information on an expression *) +and exp_info = { + exp_type : logic_type; (** when used as placeholder for a term *) + exp_name: string list; +} + +(* ************************************************************************* *) +(** {2 Constants} *) +(* ************************************************************************* *) + +(** Literal constants *) +and constant = + | CInt64 of Integer.t * ikind * string option + (** Integer constant. Give the ikind (see ISO9899 6.1.3.2) and the + textual representation. Textual representation is always set to Some s + when it comes from user code. This allows us to print a + constant as it was represented in the code, for example, + 0xF instead of 15. It is usually None for constant generated by Cil + itself. Use {!Cil.integer} or {!Cil.kinteger} to create these. *) + + | CStr of string + (** String constant. The escape characters inside the string have been already + interpreted. This constant has pointer to character type! The only case + when you would like a string literal to have an array type is when it is + an argument to sizeof. In that case you should use SizeOfStr. *) + + | CWStr of int64 list + (** Wide character string constant. Note that the local interpretation of such + a literal depends on {!Cil.theMachine.wcharType} and + {!Cil.theMachine.wcharKind}. Such a constant has type pointer to + {!Cil.theMachine.wcharType}. The escape characters in the string have not + been "interpreted" in the sense that L"A\xabcd" remains "A\xabcd" rather + than being represented as the wide character list with two elements: 65 + and 43981. That "interpretation" depends on the underlying wide character + type. *) + + | CChr of char + (** Character constant. This has type int, so use charConstToInt to read the + value in case sign-extension is needed. *) + + | CReal of float * fkind * string option + (** Floating point constant. Give the fkind (see ISO 6.4.4.2) and also the + textual representation, if available. *) + + | CEnum of enumitem +(** An enumeration constant. Use [Cillower.lowerEnumVisitor] to replace these + with integer constants. *) + +(** Unary operators *) +and unop = + Neg (** Unary minus *) + | BNot (** Bitwise complement (~) *) + | LNot (** Logical Not (!) *) + +(** Binary operations *) +and binop = + PlusA (** arithmetic + *) + | PlusPI (** pointer + integer *) + | IndexPI (** pointer + integer but only when it arises from an expression + [e\[i\]] when [e] is a pointer and + not an array. This is semantically + the same as PlusPI but CCured uses + this as a hint that the integer is + probably positive. *) + | MinusA (** arithmetic - *) + | MinusPI (** pointer - integer *) + | MinusPP (** pointer - pointer *) + | Mult (** * *) + | Div (** / + @plugin development guide *) + | Mod (** % + @plugin development guide *) + | Shiftlt (** shift left *) + | Shiftrt (** shift right *) + + | Lt (** < (arithmetic comparison) *) + | Gt (** > (arithmetic comparison) *) + | Le (** <= (arithmetic comparison) *) + | Ge (** >= (arithmetic comparison) *) + | Eq (** == (arithmetic comparison) *) + | Ne (** != (arithmetic comparison) *) + | BAnd (** bitwise and *) + | BXor (** exclusive-or *) + | BOr (** inclusive-or *) + + | LAnd (** logical and. Unlike other expressions this one does not always + evaluate both operands. If you want + to use these, you must set + {!Cil.useLogicalOperators}. *) + | LOr (** logical or. Unlike other expressions this one does not always + evaluate both operands. If you + want to use these, you must set + {!Cil.useLogicalOperators}. *) + +(* ************************************************************************* *) +(** {2 Left values} *) +(* ************************************************************************* *) + +(** Left values (aka Lvalues) are the sublanguage of expressions that can appear + at the left of an assignment or as operand to the address-of operator. In C + the syntax for lvalues is not always a good indication of the meaning of the + lvalue. For example the C value {v a[0][1][2] v} might involve 1, 2 or 3 + memory reads when used in an expression context, depending on the declared + type of the variable [a]. If [a] has type [int \[4\]\[4\]\[4\]] then we have + one memory read from somewhere inside the area that stores the array [a]. On + the other hand if [a] has type [int ***] then the expression really means [* + ( * ( * (a + 0) + 1) + 2)], in which case it is clear that it involves three + separate memory operations. + + An lvalue denotes the contents of a range of memory addresses. This range is + denoted as a host object along with an offset within the object. The host + object can be of two kinds: a local or global variable, or an object whose + address is in a pointer expression. We distinguish the two cases so that we + can tell quickly whether we are accessing some component of a variable + directly or we are accessing a memory location through a pointer. To make + it easy to tell what an lvalue means CIL represents lvalues as a host object + and an offset (see {!Cil_types.lval}). The host object (represented as + {!Cil_types.lhost}) can be a local or global variable or can be the object + pointed-to by a pointer expression. The offset (represented as + {!Cil_types.offset}) is a sequence of field or array index designators. + + Both the typing rules and the meaning of an lvalue is very precisely + specified in CIL. + + The following are a few useful function for operating on lvalues: + - {!Cil.mkMem} - makes an lvalue of [Mem] kind. Use this to ensure + that certain equivalent forms of lvalues are canonized. + For example, [*&x = x]. + - {!Cil.typeOfLval} - the type of an lvalue + - {!Cil.typeOffset} - the type of an offset, given the type of the + host. + - {!Cil.addOffset} and {!Cil.addOffsetLval} - extend sequences + of offsets. + - {!Cil.removeOffset} and {!Cil.removeOffsetLval} - shrink sequences + of offsets. + + The following equivalences hold {v + Mem(AddrOf(Mem a, aoff)), off = Mem a, aoff + off + Mem(AddrOf(Var v, aoff)), off = Var v, aoff + off + AddrOf (Mem a, NoOffset) = a + v} *) + +and lval = lhost * offset + +(** The host part of an {!Cil_types.lval}. *) +and lhost = + | Var of varinfo + (** The host is a variable. *) + + | Mem of exp +(** The host is an object of type [T] when the expression has pointer + [TPtr(T)]. *) + + +(** The offset part of an {!Cil_types.lval}. Each offset can be applied to + certain kinds of lvalues and its effect is that it advances the starting + address of the lvalue and changes the denoted type, essentially focussing + to some smaller lvalue that is contained in the original one. + @plugin development guide *) +and offset = + | NoOffset + (** No offset. Can be applied to any lvalue and does not change either the + starting address or the type. This is used when the lval consists of just + a host or as a terminator in a list of other kinds of offsets. *) + + | Field of fieldinfo * offset + (** A field offset. Can be applied only to an lvalue that denotes a structure + or a union that contains the mentioned field. This advances the offset to + the beginning of the mentioned field and changes the type to the type of + the mentioned field. *) + + | Index of exp * offset +(** An array index offset. Can be applied only to an lvalue that denotes an + array. This advances the starting address of the lval to the beginning of + the mentioned array element and changes the denoted type to be the type of + the array element *) + +(* ************************************************************************* *) +(** {2 Initializers} *) +(* ************************************************************************* *) + +(** A special kind of expressions are those that can appear as initializers for + global variables (initialization of local variables is turned into + assignments). The initializers are represented as type + {!Cil_types.init}. You can create initializers with {!Cil.makeZeroInit} and + you can conveniently scan compound initializers them with + {!Cil.foldLeftCompound}. *) + +(** Initializers for global variables. *) +and init = + | SingleInit of exp (** A single initializer *) + | CompoundInit of typ * (offset * init) list +(** Used only for initializers of structures, unions and arrays. The offsets + are all of the form [Field(f, NoOffset)] or [Index(i, NoOffset)] and + specify the field or the index being initialized. For structures all fields + must have an initializer (except the unnamed bitfields), in the proper + order. This is necessary since the offsets are not printed. For arrays the + list must contain a prefix of the initializers; the rest are 0-initialized. + For unions there must be exactly one initializer. If the initializer is not + for the first field then a field designator is printed, so you better be on + GCC since MSVC does not understand this. You can scan an initializer list + with {!Cil.foldLeftCompound}. *) + +(** We want to be able to update an initializer in a global variable, so we + define it as a mutable field *) +and initinfo = { mutable init : init option } + +(* ************************************************************************* *) +(** {2 Function definitions} *) +(* ************************************************************************* *) + +(** A function definition is always introduced with a [GFun] constructor at the + top level. All the information about the function is stored into a + {!Cil_types.fundec}. Some of the information (e.g. its name, type, storage, + attributes) is stored as a {!Cil_types.varinfo} that is a field of the + [fundec]. To refer to the function from the expression language you must use + the [varinfo]. + + The function definition contains, in addition to the body, a list of all the + local variables and separately a list of the formals. Both kind of variables + can be referred to in the body of the function. The formals must also be + shared with the formals that appear in the function type. For that reason, + to manipulate formals you should use the provided functions + {!Cil.makeFormalVar} and {!Cil.setFormals}. *) + +(** Function definitions. + @plugin development guide *) +and fundec = { + mutable svar: varinfo; + (** Holds the name and type as a variable, so we can refer to it easily + from the program. All references to this function either in a function + call or in a prototype must point to the same [varinfo]. *) + + mutable sformals: varinfo list; + (** Formals. These must be in the same order and with the same information + as the formal information in the type of the function. Use + {!Cil.setFormals} or {!Cil.setFunctionType} to set these formals and + ensure that they are reflected in the function type. Do not make + copies of these because the body refers to them. *) + + mutable slocals: varinfo list; + (** Locals. Does NOT include the sformals. Do not make copies of these + because the body refers to them. *) + + mutable smaxid: int; + (** Max local id. Starts at 0. Used for creating the names of new + temporary variables. Updated by {!Cil.makeLocalVar} and + {!Cil.makeTempVar}. You can also use {!Cil.setMaxId} to set it after + you have added the formals and locals. *) + + mutable sbody: block; (** The function body. *) + + mutable smaxstmtid: int option; + (** max id of a (reachable) statement in this function, if we have + computed it. range = 0 ... (smaxstmtid-1). This is computed by + {!Cfg.computeCFGInfo}. *) + + mutable sallstmts: stmt list; + (** After you call {!Cfg.computeCFGInfo} this field is set to contain all + statements in the function. *) + + mutable sspec: funspec; +} + +(** A block is a sequence of statements with the control falling through from + one element to the next *) +and block = { + mutable battrs: attributes; (** Attributes for the block *) + + mutable blocals: varinfo list; + (** variables that are local to the block. It is a subset of the slocals of + the enclosing function. *) + + mutable bstmts: stmt list; (** The statements comprising the block. *) +} + +(* ************************************************************************* *) +(** {2 Statements} *) +(* ************************************************************************* *) + +(** CIL statements are the structural elements that make the CFG. They are + represented using the type {!Cil_types.stmt}. Every statement has a + (possibly empty) list of labels. The {!Cil_types.stmtkind} field of a + statement indicates what kind of statement it is. + + Use {!Cil.mkStmt} to make a statement and the fill-in the fields. + + CIL also comes with support for control-flow graphs. The [sid] field in + [stmt] can be used to give unique numbers to statements, and the [succs] and + [preds] fields can be used to maintain a list of successors and predecessors + for every statement. The CFG information is not computed by default. Instead + you must explicitly use the functions {!Cfg.prepareCFG} and + {!Cfg.computeCFGInfo} to do it. *) + +(** Statements. + @plugin development guide *) +and stmt = { + mutable labels: label list; + (** Whether the statement starts with some labels, case statements or + default statements. *) + + mutable skind: stmtkind; + (** The kind of statement *) + + mutable sid: int; + (** A number (>= 0) that is unique in a function. Filled in only after the + CFG is computed. *) + + mutable succs: stmt list; + (** The successor statements. They can always be computed from the skind and + the context in which this statement appears. Filled in only after the CFG + is computed. *) + + mutable preds: stmt list; + (** The inverse of the succs function. *) + + mutable ghost : bool +} + +(** Labels *) +and label = + | Label of string * location * bool + (** A real label. If the bool is "true", the label is from the input source + program. If the bool is "false", the label was created by CIL or some + other transformation *) + + | Case of exp * location + (** A case statement. This expression is lowered into a constant if + {!Cil.lowerConstants} is set to [true]. *) + + | Default of location (** A default statement *) + +(* The various kinds of statements *) +and stmtkind = + | Instr of instr + (** An instruction that does not contain control flow. Control implicitly + falls through. + @plugin development guide *) + + | Return of exp option * location + (** The return statement. This is a leaf in the CFG. + @plugin development guide *) + + | Goto of stmt ref * location + (** A goto statement. Appears from actual goto's in the code or from goto's + that have been inserted during elaboration. The reference points to the + statement that is the target of the Goto. This means that you have to + update the reference whenever you replace the target statement. The + target statement MUST have at least a label. + @plugin development guide *) + + | Break of location + (** A break to the end of the nearest enclosing Loop or Switch. + @plugin development guide *) + + | Continue of location + (** A continue to the start of the nearest enclosing [Loop]. + @plugin development guide *) + + | If of exp * block * block * location + (** A conditional. Two successors, the "then" and the "else" branches (in + this order). + Both branches fall-through to the successor of the If statement. + @plugin development guide *) + + | Switch of exp * block * (stmt list) * location + (** A switch statement. [exp] is the index of the switch. [block] is + the body of the switch. [stmt list] contains the set of + statements whose [labels] are cases of the switch (i.e. for each + case, the corresponding statement is in [stmt list], a statement + cannot appear more than once in the list, and statements in + [stmt list] can have several labels corresponding to several + cases. + @plugin development guide *) + + | Loop of + code_annotation list * block * location * (stmt option) * (stmt option) + (** A [while(1)] loop. The termination test is implemented in the body of a + loop using a [Break] statement. If {!Cfg.prepareCFG} has been called, the + first stmt option will point to the stmt containing the continue label + for this loop and the second will point to the stmt containing the break + label for this loop. + @plugin development guide *) + + | Block of block + (** Just a block of statements. Use it as a way to keep some block attributes + local. + @plugin development guide *) + + | UnspecifiedSequence of (stmt * lval list + * lval list * lval list * stmt ref list) list + (** statements whose order of execution is not specified by + ISO/C. This is important for the order of side effects + during evaluation of expressions. Each statement comes + together with three list of lval, in this order. + - lvals that are written during the sequence and whose future + value depends upon the statement (it is legal to read from them, but + not to write to them) + - lvals that are written during the evaluation of the statement itself + - lval that are read. + - Function calls in the corresponding statement + Note that this include only a subset of the affectations + of the statement. Namely, the + temporary variables generated by cil are excluded (i.e. it + is assumed that the "compilation" is correct). In addition, + side effects caused by function applications are not taken + into account in the list. For a single statement, the written lvals + are supposed to be ordered (or their order of evaluation doesn't + matter), so that an alarm should be emitted only if the lvals read by + a statement overlap with the lvals written (or read) by another + statement of the sequence. + + At this time this feature is + experimental and may miss some unspecified sequences. + + In case you do not care about this feature just handle it + like a block (see {!Cil.block_from_unspecified_sequence}). + @plugin development guide *) + + | Throw of (exp * typ) option * location + (** Throws an exception, C++ style. + We keep the type of the expression, to match + it against the appropriate catch clause. A Throw node has + no successor, even if it is in try-catch block that will catch + the exception: we keep normal and exceptional control-flow + completely separate, as in Jo and Chang, ICSSA 2004. + *) + + | TryCatch of block * (catch_binder * block) list * location + + | TryFinally of block * block * location + (** On MSVC we support structured exception handling. This is what you might + expect. Control can get into the finally block either from the end of the + body block, or if an exception is thrown. + @plugin development guide *) + + | TryExcept of block * (instr list * exp) * block * location +(** On MSVC we support structured exception handling. The try/except + statement is a bit tricky: + {v __try \{ blk \} + __except (e) \{ + handler + \} + v} + + The argument to __except must be an expression. However, we keep a + list of instructions AND an expression in case you need to make + function calls. We'll print those as a comma expression. The control + can get to the __except expression only if an exception is thrown. + After that, depending on the value of the expression the control + goes to the handler, propagates the exception, or retries the + exception. The location corresponds to the try keyword. + @plugin development guide *) + +(** Kind of exceptions that are caught by a given clause. *) +and catch_binder = + | Catch_exn of varinfo * (varinfo * block) list + (** catch exception of given type(s). + If the list is empty, only exceptions with the same type as the + varinfo can be caught. If the list is non-empty, only exceptions + matching one of the type of a varinfo in the list are caught. + The associated block contains the operations necessary to transform + the matched varinfo into the principal one. + Semantics is by value (i.e. the varinfo is bound to a copy of the + caught object). + + This clause is a declaration point for the varinfo(s) + mentioned in it. More precisely, for + [Catch_exn(v_0,[(v_1, b_1),..., (v_n, b_n)])], + the [v_i] must be referenced in the [slocals] of the + enclosing [fundec], and _must not_ appear in any [blocals] + of some block. The scope of v_0 is all the [b_i] and + the corresponding block in the [catch_binder * block list] of the + [TryCatch] node the binder belongs to. The scope of the other [v_i] + is the corresponding [b_i]. + *) + | Catch_all (** default catch clause: all exceptions are caught. *) + +(** Instructions. They may cause effects directly but may not have control + flow.*) +and instr = + | Set of lval * exp * location + (** An assignment. A cast is present if the exp has different type from + lval *) + + | Call of lval option * exp * exp list * location + (** optional: result is an lval. A cast might be necessary if the declared + result type of the function is not the same as that of the destination. + Actual arguments must have a type equivalent (i.e. {!Cil.need_cast} must + return [false]) to the one of the formals of the function. + If the type of the result variable is not the same as the declared type of + the function result then an implicit cast exists. + *) + + (* See the GCC specification for the meaning of ASM. + If the source is MS VC then only the templates + are used. + + [sm] I've added a notes.txt file which contains more + information on interpreting Asm instructions *) + | Asm of + attributes (* Really only const and volatile can appear here *) + * string list (* templates (CR-separated) *) + * extended_asm option + * location + (** An inline assembly instruction. The arguments are + (1) a list of attributes (only const and volatile can appear here and only + for GCC) + (2) templates (CR-separated) + (3) GCC extended asm information if any + (4) location information *) + + | Skip of location + + | Code_annot of code_annotation * location + + +(** GNU extended-asm information: + - a list of outputs, each of which is an lvalue with optional names and + constraints. + - a list of input expressions along with constraints + - clobbered registers + - Possible destinations statements *) +and extended_asm = + { + asm_outputs: (string option * string * lval) list + (** outputs must be lvals with optional names and constraints. I would + like these to be actually variables, but I run into some trouble with + ASMs in the Linux sources *); + asm_inputs: (string option * string * exp) list + (** inputs with optional names and constraints *); + asm_clobbers: string list (** register clobbers *); + asm_gotos: (stmt ref) list + (** list of statements this asm section may jump to. Destination + must have a label. *); + } + +(** Describes a location in a source file *) +and location = Lexing.position * Lexing.position + +(** {1 Abstract syntax trees for annotations} *) + +and logic_constant = + | Integer of Integer.t * string option + (** Integer constant with a textual representation. *) + | LStr of string (** String constant. *) + | LWStr of int64 list (** Wide character string constant. *) + | LChr of char (** Character constant. *) + | LReal of logic_real + | LEnum of enumitem (** An enumeration constant.*) + +(** Real constants. *) +and logic_real = { + r_literal : string ; (** Initial string representation [s]. *) + r_nearest : float ; (** Nearest approximation of [s] in double precision. *) + r_upper : float ; (** Smallest double [u] such that [s <= u]. *) + r_lower : float ; (** Greatest double [l] such that [l <= s]. *) +} + +(** Types of logic terms. *) +and logic_type = + | Ctype of typ (** a C type *) + | Ltype of logic_type_info * logic_type list + (** an user-defined logic type with its parameters *) + | Lvar of string (** a type variable. *) + | Linteger (** mathematical integers, {i i.e.} Z *) + | Lreal (** mathematical reals, {i i.e.} R *) + | Larrow of logic_type list * logic_type (** (n-ary) function type *) + +(** tsets with an unique identifier. + Use [Logic_const.new_location] to generate a new id. *) +and identified_term = { + it_id: int; (** the identifier. *) + it_content: term (** the term *) +} + +(** logic label referring to a particular program point. *) +and logic_label = + | StmtLabel of stmt ref (** label of a C statement. *) + | LogicLabel of (stmt option * string) (* [JS 2011/05/13] why a tuple here? *) +(** builtin logic label ({t Here, Pre}, ...) *) + +(* ************************************************************************* *) +(** {2 Terms} *) +(* ************************************************************************* *) + +(** C Expressions as logic terms follow C constructs (with prefix T) *) + +(** Logic terms. *) +and term = { + term_node : term_node; (** kind of term. *) + term_loc : Lexing.position * Lexing.position; + (** position in the source file. *) + term_type : logic_type; (** type of the term. *) + term_name: string list; + (** names of the term if any. A name can be an arbitrary string, where + '"' and '\'' are escaped by a \, and which does not end with a \. + Hence, "name" and 'name' should be recognized as a unique label by most + tools. *) +} + +(** the various kind of terms. *) +and term_node = + (* same constructs as exp *) + | TConst of logic_constant (** a constant. *) + | TLval of term_lval (** an L-value *) + | TSizeOf of typ (** size of a given C type. *) + | TSizeOfE of term (** size of the type of an expression. *) + | TSizeOfStr of string (** size of a string constant. *) + | TAlignOf of typ (** alignment of a type. *) + | TAlignOfE of term (** alignment of the type of an expression. *) + | TUnOp of unop * term (** unary operator. *) + | TBinOp of binop * term * term (** binary operators. *) + | TCastE of typ * term (** cast to a C type. *) + | TAddrOf of term_lval (** address of a term. *) + | TStartOf of term_lval (** beginning of an array. *) + + (* additional constructs *) + | Tapp of logic_info * (logic_label * logic_label) list * term list + (** application of a logic function. *) + | Tlambda of quantifiers * term (** lambda abstraction. *) + | TDataCons of logic_ctor_info * term list + (** constructor of logic sum-type. *) + | Tif of term * term * term + (** conditional operator*) + | Tat of term * logic_label + (** term refers to a particular program point. *) + | Tbase_addr of logic_label * term (** base address of a pointer. *) + | Toffset of logic_label * term (** offset from the base address of a pointer. *) + | Tblock_length of logic_label * term (** length of the block pointed to by the term. *) + | Tnull (** the null pointer. *) + | TLogic_coerce of logic_type * term + (** implicit conversion from a C type to a logic type. + The logic type must not be a Ctype. In particular, used to denote + lifting to Linteger and Lreal. + *) + | TCoerce of term * typ (** coercion to a given C type. *) + | TCoerceE of term * term (** coercion to the type of a given term. *) + | TUpdate of term * term_offset * term + (** functional update of a field. *) + | Ttypeof of term (** type tag for a term. *) + | Ttype of typ (** type tag for a C type. *) + | Tempty_set (** the empty set. *) + | Tunion of term list (** union of terms. *) + | Tinter of term list (** intersection of terms. *) + | Tcomprehension of + term * quantifiers * predicate option + (** set defined in comprehension ({t \{ t[i] | integer i; 0 <= i < 5\}}) *) + | Trange of term option * term option (** range of integers. *) + | Tlet of logic_info * term (** local binding *) + +(** lvalue: base address and offset. *) +and term_lval = + term_lhost * term_offset + +(** base address of an lvalue. *) +and term_lhost = + | TVar of logic_var (** a variable. *) + | TResult of typ (** value returned by a C function. + Only used in post-conditions or assigns + *) + | TMem of term (** memory access. *) + +(** model field. *) +and model_info = { + mi_name: string; (** name *) + mi_field_type: logic_type; (** type of the field *) + mi_base_type: typ; (** type to which the field is associated. *) + mi_decl: location; (** where the field has been declared. *) +} + +(** offset of an lvalue. *) +and term_offset = + | TNoOffset (** no further offset. *) + | TField of fieldinfo * term_offset + (** access to the field of a compound type. *) + | TModel of model_info * term_offset (** access to a model field. *) + | TIndex of term * term_offset + (** index. Note that a range is denoted by [TIndex(Trange(i1,i2),ofs)] *) + +(** description of a logic function or predicate. +@plugin development guide *) +and logic_info = { +(* + mutable l_name : string; (** name of the function. *) +*) + mutable l_var_info : logic_var; + (** we use only fields lv_name and lv_id of l_var_info + we should factorize lv_type and l_type+l_profile below *) + mutable l_labels : logic_label list; (** label arguments of the function. *) + mutable l_tparams : string list; (** type parameters *) + mutable l_type : logic_type option; (** return type. None for predicates *) + mutable l_profile : logic_var list; (** type of the arguments. *) + mutable l_body : logic_body; (** body of the function. *) +} + +and builtin_logic_info = { + mutable bl_name: string; + mutable bl_labels: logic_label list; + mutable bl_params: string list; + mutable bl_type: logic_type option; + mutable bl_profile: (string * logic_type) list; +} + +and logic_body = + | LBnone (** no definition and no reads clause *) + | LBreads of identified_term list + (** read accesses performed by a function. *) + | LBterm of term (** direct definition of a function. *) + | LBpred of predicate (** direct definition of a predicate. *) + | LBinductive of + (string * logic_label list * string list * predicate) list + (** inductive definition *) + +(** Description of a logic type. + @plugin development guide *) +and logic_type_info = { + lt_name: string; + lt_params : string list; (** type parameters*) + mutable lt_def: logic_type_def option + (** definition of the type. None for abstract types. *) +} +(* will be expanded when dealing with concrete types *) + +and logic_type_def = + | LTsum of logic_ctor_info list (** sum type with its constructors. *) + | LTsyn of logic_type (** Synonym of another type. *) + +(** origin of a logic variable. *) +and logic_var_kind = + | LVGlobal (** global logic function or predicate. *) + | LVC (** Logic counterpart of a C variable. *) + | LVFormal (** formal parameter of a logic function / predicate + or \lambda abstraction *) + | LVQuant (** Bound by a quantifier (\exists or \forall) *) + | LVLocal (** local \let *) + +(** description of a logic variable +@plugin development guide *) +and logic_var = { + mutable lv_name : string; (** name of the variable. *) + mutable lv_id : int; (** unique identifier *) + mutable lv_type : logic_type; (** type of the variable. *) + mutable lv_kind: logic_var_kind; (** kind of the variable *) + mutable lv_origin : varinfo option +(** when the logic variable stems from a C variable, set to the original C + variable. *) +} + +(** Description of a constructor of a logic sum-type. + @plugin development guide *) +and logic_ctor_info = + { ctor_name: string; (** name of the constructor. *) + ctor_type: logic_type_info; (** type to which the constructor belongs. *) + ctor_params: logic_type list + (** types of the parameters of the constructor. *) + } + +(* ************************************************************************* *) +(** {2 Predicates} *) +(* ************************************************************************* *) + +(** variables bound by a quantifier. *) +and quantifiers = logic_var list + +(** comparison relations*) +and relation = + | Rlt + | Rgt + | Rle + | Rge + | Req + | Rneq (** @plugin development guide *) + + +(** predicates *) +and predicate_node = + | Pfalse (** always-false predicate. *) + | Ptrue (** always-true predicate. *) + | Papp of logic_info * (logic_label * logic_label) list * term list + (** application of a predicate. *) + | Pseparated of term list + | Prel of relation * term * term (** comparison of two terms. *) + | Pand of predicate * predicate (** conjunction *) + | Por of predicate * predicate (** disjunction. *) + | Pxor of predicate * predicate (** logical xor. *) + | Pimplies of predicate * predicate (** implication. *) + | Piff of predicate * predicate (** equivalence. *) + | Pnot of predicate (** negation. *) + | Pif of term * predicate * predicate (** conditional *) + | Plet of logic_info * predicate (** definition of a local variable *) + | Pforall of quantifiers * predicate (** universal quantification. *) + | Pexists of quantifiers * predicate (** existential quantification. *) + | Pat of predicate * logic_label + (** predicate refers to a particular program point. *) + | Pvalid_read of logic_label * term (** the given locations are valid for reading. *) + | Pvalid of logic_label * term (** the given locations are valid. *) + | Pvalid_function of term + (** the pointed function has a type compatible with the one of pointer. *) + | Pinitialized of logic_label * term (** the given locations are initialized. *) + | Pdangling of logic_label * term (** the given locations contain dangling + adresses. *) + | Pallocable of logic_label * term (** the given locations can be allocated. *) + | Pfreeable of logic_label * term (** the given locations can be free. *) + | Pfresh of logic_label * logic_label * term * term + (** \fresh(pointer, n) + A memory block of n bytes is newly allocated to the pointer.*) + | Psubtype of term * term + (** First term is a type tag that is a subtype of the second. *) + +(** predicate with an unique identifier. Use [Logic_const.new_predicate] to + create fresh predicates *) +and identified_predicate = { + ip_id: int; (** identifier *) + ip_content: predicate; (** the predicate itself*) +} + +(** predicates with a location and an optional list of names *) +and predicate = { + pred_name : string list; (** list of given names *) + pred_loc : location; (** position in the source code. *) + pred_content : predicate_node;(** content *) +} + +(* Polymorphic types shared with parsed trees (Logic_ptree) *) +(** variant of a loop or a recursive function. Type shared with Logic_ptree. *) +and 'term variant = 'term * string option + +(** allocates and frees. + @since Oxygen-20120901 *) +and 'locs allocation = + | FreeAlloc of 'locs list * 'locs list (** tsets. Empty list means \nothing. *) + | FreeAllocAny (** Nothing specified. Semantics depends on where it + is written. *) + +(** dependencies of an assigned location. Shared with Logic_ptree. *) +and 'locs deps = + | From of 'locs list (** tsets. Empty list means \nothing. *) + | FromAny (** Nothing specified. Any location can be involved. *) + +and 'locs from = ('locs * 'locs deps) + +(** zone assigned with its dependencies. Type shared with Logic_ptree. *) +and 'locs assigns = + | WritesAny (** Nothing specified. Anything can be written. *) + | Writes of 'locs from list + (** list of locations that can be written. Empty list means \nothing. *) + +(** Function or statement contract. This type shares the name of its + constructors with {!Logic_ptree.spec}. *) +and spec = { + mutable spec_behavior : behavior list; + (** behaviors *) + + mutable spec_variant : term variant option; + (** variant for recursive functions. *) + + mutable spec_terminates: identified_predicate option; + (** termination condition. *) + + mutable spec_complete_behaviors: string list list; + (** list of complete behaviors. + It is possible to have more than one set of complete behaviors *) + + mutable spec_disjoint_behaviors: string list list; + (** list of disjoint behaviors. + It is possible to have more than one set of disjoint behaviors *) +} + + +(** extension to standard ACSL clause. + Each extension is associated to a keyword. An extension + can be registered through the following functions: + - {!Logic_typing.register_behavior_extension} for parsing and type-checking + - {!Cil_printer.register_behavior_extension} for pretty-printing an + extended clause + - {!Cil.register_behavior_extension} for visiting an extended clause + + @plugin development guide *) +and acsl_extension = string * acsl_extension_kind + +and acsl_extension_kind = + | Ext_id of int (** id used internally by the extension itself. *) + | Ext_terms of term list + | Ext_preds of predicate list + (** a list of predicates, the most common case of for extensions *) + +(** Behavior of a function or statement. This type shares the name of its + constructors with {!Logic_ptree.behavior}. + @since Oxygen-20120901 [b_allocation] has been added. + @since Carbon-20101201 [b_requires] has been added. + @modify Boron-20100401 [b_ensures] is replaced by [b_post_cond]. + Old [b_ensures] represent the [Normal] case of [b_post_cond]. *) +and behavior = { + mutable b_name : string; (** name of the behavior. *) + mutable b_requires : identified_predicate list; (** require clauses. *) + mutable b_assumes : identified_predicate list; (** assume clauses. *) + mutable b_post_cond : (termination_kind * identified_predicate) list + (** post-condition. *); + mutable b_assigns : identified_term assigns; (** assignments. *) + mutable b_allocation : identified_term allocation; (** frees, allocates. *) + mutable b_extended : acsl_extension list (** extensions *) +} + +(** kind of termination a post-condition applies to. See ACSL manual. *) +and termination_kind = Normal | Exits | Breaks | Continues | Returns + +(** Pragmas for the value analysis plugin of Frama-C. + Type shared with Logic_ptree.*) +and 'term loop_pragma = + | Unroll_specs of 'term list + | Widen_hints of 'term list + | Widen_variables of 'term list + +(** Pragmas for the slicing plugin of Frama-C. Type shared with Logic_ptree.*) +and 'term slice_pragma = + | SPexpr of 'term + | SPctrl + | SPstmt + +(** Pragmas for the impact plugin of Frama-C. Type shared with Logic_ptree.*) +and 'term impact_pragma = + | IPexpr of 'term + | IPstmt + +(** The various kinds of pragmas. Type shared with Logic_ptree. *) +and 'term pragma = + | Loop_pragma of 'term loop_pragma + | Slice_pragma of 'term slice_pragma + | Impact_pragma of 'term impact_pragma + +(** all annotations that can be found in the code. + This type shares the name of its constructors with + {!Logic_ptree.code_annot}. *) +and code_annotation_node = + | AAssert of string list * predicate + (** assertion to be checked. The list of strings is the list of + behaviors to which this assertion applies. *) + + | AStmtSpec of string list * spec + (** statement contract + (potentially restricted to some enclosing behaviors). *) + + | AInvariant of string list * bool * predicate + (** loop/code invariant. The list of strings is the list of behaviors to which + this invariant applies. The boolean flag is true for normal loop + invariants and false for invariant-as-assertions. *) + + | AVariant of term variant + (** loop variant. Note that there can be at most one variant associated to a + given statement *) + + | AAssigns of string list * identified_term assigns + (** loop assigns. (see [b_assigns] in the behaviors for other assigns). At + most one clause associated to a given (statement, behavior) couple. *) + + | AAllocation of string list * identified_term allocation + (** loop allocation clause. (see [b_allocation] in the behaviors for other + allocation clauses). + At most one clause associated to a given (statement, behavior) couple. + @since Oxygen-20120901 when [b_allocation] has been added. *) + + | APragma of term pragma (** pragma. *) + | AExtended of string list * acsl_extension + (** extension in a loop annotation. + @since Silicon-20161101 *) + +(** function contract. *) + +and funspec = spec + +(** code annotation with an unique identifier. + Use [Logic_const.new_code_annotation] to create new code annotations with + a fresh id. *) +and code_annotation = { + annot_id: int; (** identifier. *) + annot_content : code_annotation_node; (** content of the annotation. *) +} + +(** behavior of a function. *) +and funbehavior = behavior + +(** global annotations, not attached to a statement or a function. *) +and global_annotation = + | Dfun_or_pred of logic_info * location + | Dvolatile of + identified_term list * varinfo option * varinfo option * location + (** associated terms, reading function, writing function *) + | Daxiomatic of string * global_annotation list * location + | Dtype of logic_type_info * location (** declaration of a logic type. *) + | Dlemma of + string * bool * logic_label list * string list * + predicate * location + (** definition of a lemma. The boolean flag is [true] if the property should + be taken as an axiom and [false] if it must be proved. *) + | Dinvariant of logic_info * location + (** global invariant. The predicate does not have any argument. *) + | Dtype_annot of logic_info * location + (** type invariant. The predicate has exactly one argument. *) + | Dmodel_annot of model_info * location + (** Model field for a type t, seen as a logic function with one + argument of type t *) + | Dcustom_annot of custom_tree * string* location + (*Custom declaration*) + +and custom_tree = CustomDummy +(* + | CustomType of logic_type + | CustomLexpr of lexpr + | CustomOther of string * (custom_tree list) +*) + +type kinstr = + | Kstmt of stmt + | Kglobal + +(** Internal representation of decorated C functions *) +type cil_function = + | Definition of (fundec * location) (** defined function *) + | Declaration of (funspec * varinfo * varinfo list option * location) + (** Declaration(spec,f,args,loc) represents a leaf function [f] with + specification [spec] and arguments [args], at location [loc]. As + with the [TFun] constructor of {!Cil_types.typ}, the arg list is + optional, to distinguish [void f()] ([None]) from + [void f(void)] ([Some []]). *) + +(** Only field [fundec] can be used directly. Use {!Annotations.funspec}, + [Annotations.add_*] and [Annotations.remove_*] to query or modify field + [spec]. *) +type kernel_function = { + mutable fundec : cil_function; + mutable spec : funspec; +} + +(* [VP] TODO: VLocal should be attached to a particular block, not a whole + function. *) +type localisation = + | VGlobal + | VLocal of kernel_function + | VFormal of kernel_function + +type mach = { + sizeof_short: int; (* Size of "short" *) + sizeof_int: int; (* Size of "int" *) + sizeof_long: int ; (* Size of "long" *) + sizeof_longlong: int; (* Size of "long long" *) + sizeof_ptr: int; (* Size of pointers *) + sizeof_float: int; (* Size of "float" *) + sizeof_double: int; (* Size of "double" *) + sizeof_longdouble: int; (* Size of "long double" *) + sizeof_void: int; (* Size of "void" *) + sizeof_fun: int; (* Size of function *) + size_t: string; (* Type of "sizeof(T)" *) + wchar_t: string; (* Type of "wchar_t" *) + ptrdiff_t: string; (* Type of "ptrdiff_t" *) + alignof_short: int; (* Alignment of "short" *) + alignof_int: int; (* Alignment of "int" *) + alignof_long: int; (* Alignment of "long" *) + alignof_longlong: int; (* Alignment of "long long" *) + alignof_ptr: int; (* Alignment of pointers *) + alignof_float: int; (* Alignment of "float" *) + alignof_double: int; (* Alignment of "double" *) + alignof_longdouble: int; (* Alignment of "long double" *) + alignof_str: int; (* Alignment of strings *) + alignof_fun: int; (* Alignment of function *) + char_is_unsigned: bool; (* Whether "char" is unsigned *) + underscore_name: bool; (* If assembly names have leading underscore *) + const_string_literals: bool; (* Whether string literals have const chars *) + little_endian: bool; (* whether the machine is little endian *) + alignof_aligned: int (* Alignment of a type with aligned attribute *); + has__builtin_va_list: bool (* Whether [__builtin_va_list] is a known type *); + __thread_is_keyword: bool (* Whether [__thread] is a keyword *); + compiler: string; (* Compiler being used. Currently recognized names + are 'gcc', 'msvc' and 'generic'. *) + version: string; (* Information on this machdep *) +} + +(* +Local Variables: +compile-command: "make -C ../../.." +End: +*) diff --git a/test/cil_types.mllib b/test/cil_types.mllib new file mode 100644 index 0000000..7ee3e27 --- /dev/null +++ b/test/cil_types.mllib @@ -0,0 +1 @@ +cil_types diff --git a/test/cil_types_polymorphic.ml b/test/cil_types_polymorphic.ml new file mode 100644 index 0000000..514ba4c --- /dev/null +++ b/test/cil_types_polymorphic.ml @@ -0,0 +1,1780 @@ +module Integer = struct type t = int end (* fpottier/visitors *) +(****************************************************************************) +(* *) +(* Copyright (C) 2001-2003 *) +(* George C. Necula *) +(* Scott McPeak *) +(* Wes Weimer *) +(* Ben Liblit *) +(* All rights reserved. *) +(* *) +(* Redistribution and use in source and binary forms, with or without *) +(* modification, are permitted provided that the following conditions *) +(* are met: *) +(* *) +(* 1. Redistributions of source code must retain the above copyright *) +(* notice, this list of conditions and the following disclaimer. *) +(* *) +(* 2. Redistributions in binary form must reproduce the above copyright *) +(* notice, this list of conditions and the following disclaimer in the *) +(* documentation and/or other materials provided with the distribution. *) +(* *) +(* 3. The names of the contributors may not be used to endorse or *) +(* promote products derived from this software without specific prior *) +(* written permission. *) +(* *) +(* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *) +(* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *) +(* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *) +(* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *) +(* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, *) +(* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, *) +(* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; *) +(* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *) +(* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *) +(* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN *) +(* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE *) +(* POSSIBILITY OF SUCH DAMAGE. *) +(* *) +(* File modified by CEA (Commissariat à l'énergie atomique et aux *) +(* énergies alternatives) *) +(* and INRIA (Institut National de Recherche en Informatique *) +(* et Automatique). *) +(****************************************************************************) + +(** The Abstract Syntax of CIL. + @plugin development guide *) + +(**************************** WARNING ***************************************) +(* Remember to reflect any change here into the visitor and pretty-printer *) +(* in cil.ml. In particular, if a type becomes mutable, it is necessary to *) +(* adapt the Cil.behavior type and the copy_behavior accordingly. *) +(* A first test to see if something has been broken by a change is to launch*) +(* ptests.byte -add-options '-files-debug "-check -copy"' *) +(* In addition, it is a good idea to add some invariant checks in the *) +(* check_file class in frama-c/src/file.ml (before lauching the tests) *) +(****************************************************************************) + +(* ************************************************************************* *) +(** {2 Root of the AST} *) +(* ************************************************************************* *) + +(** In Frama-C, the whole AST is accessible through {!Ast.get}. *) + +(** The top-level representation of a CIL source file (and the result of the + parsing and elaboration). Its main contents is the list of global + declarations and definitions. You can iterate over the globals in a + {!Cil_types.file} using the following iterators: {!Cil.mapGlobals}, + {!Cil.iterGlobals} and {!Cil.foldGlobals}. You can also use the + {!Cil.dummyFile} when you need a {!Cil_types.file} as a placeholder. For + each global item CIL stores the source location where it appears (using the + type {!Cil_types.location}) + @plugin development guide *) +type file = { + mutable fileName: string; (** The complete file name *) + + mutable globals: global list; + (** List of globals as they will appear in the printed file *) + + mutable globinit: fundec option; + (** An optional global initializer function. This is a function where you + can put stuff that must be executed before the program is + started. This function, is conceptually at the end of the file, + although it is not part of the globals list. Use {!Cil.getGlobInit} to + create/get one. *) + + mutable globinitcalled: bool; +(** Whether the global initialization function is called in main. This + should always be false if there is no global initializer. When you + create a global initialization CIL will try to insert code in main to + call it. *) +} + +(** The main type for representing global declarations and definitions. A list + of these form a CIL file. The order of globals in the file is generally + important. + @plugin development guide *) +and global = + | GType of typeinfo * location + (** A typedef. All uses of type names (through the [TNamed] constructor) + must be preceeded in the file by a definition of the name. The string + is the defined name and always not-empty. *) + + | GCompTag of compinfo * location + (** Defines a struct/union tag with some fields. There must be one of + these for each struct/union tag that you use (through the [TComp] + constructor) since this is the only context in which the fields are + printed. Consequently nested structure tag definitions must be + broken into individual definitions with the innermost structure + defined first. *) + + | GCompTagDecl of compinfo * location + (** Declares a struct/union tag. Use as a forward declaration. This is + printed without the fields. *) + + | GEnumTag of enuminfo * location + (** Declares an enumeration tag with some fields. There must be one of + these for each enumeration tag that you use (through the [TEnum] + constructor) since this is the only context in which the items are + printed. *) + + | GEnumTagDecl of enuminfo * location + (** Declares an enumeration tag. Use as a forward declaration. This is + printed without the items. *) + + | GVarDecl of varinfo * location + (** A variable declaration (not a definition) for a variable with object + type. There can be several declarations and at most one definition for + a given variable. If both forms appear then they must share the same + varinfo structure. Either has storage Extern or there must be a + definition in this file *) + + | GFunDecl of funspec * varinfo * location + (** A variable declaration (not a definition) for a function, i.e. a + prototype. There can be several declarations and at most one definition + for a given function. If both forms appear then they must share the same + varinfo structure. A prototype shares the varinfo with the fundec of the + definition. Either has storage Extern or there must be a definition in + this file. *) + + | GVar of varinfo * initinfo * location + (** A variable definition. Can have an initializer. The initializer is + updateable so that you can change it without requiring to recreate the + list of globals. There can be at most one definition for a variable in an + entire program. Cannot have storage Extern or function type. *) + + | GFun of fundec * location + (** A function definition. *) + + | GAsm of string * location + (** Global asm statement. These ones can contain only a template *) + + | GPragma of attribute * location + (** Pragmas at top level. Use the same syntax as attributes *) + + | GText of string + (** Some text (printed verbatim) at top level. E.g., this way you can put + comments in the output. *) + + | GAnnot of global_annotation * location +(** a global annotation. Can be + - an axiom or a lemma + - a predicate declaration or definition + - a global type invariant + - a global invariant + - a logic function declaration or definition. *) + +(* ************************************************************************* *) +(** {2 Types} *) +(* ************************************************************************* *) + +(** A C type is represented in CIL using the type {!Cil_types.typ}. Among types + we differentiate the integral types (with different kinds denoting the sign + and precision), floating point types, enumeration types, array and pointer + types, and function types. Every type is associated with a list of + attributes, which are always kept in sorted order. Use {!Cil.addAttribute} + and {!Cil.addAttributes} to construct list of attributes. If you want to + inspect a type, you should use {!Cil.unrollType} or {!Cil.unrollTypeDeep} to + see through the uses of named types. + + CIL is configured at build-time with the sizes and alignments of the + underlying compiler (GCC or MSVC). CIL contains functions that can compute + the size of a type (in bits) {!Cil.bitsSizeOf}, the alignment of a type (in + bytes) {!Cil.alignOf_int}, and can convert an offset into a start and width + (both in bits) using the function {!Cil.bitsOffset}. At the moment these + functions do not take into account the [packed] attributes and pragmas. *) + +and typ = + | TVoid of attributes (** Void type. Also predefined as {!Cil.voidType} *) + + | TInt of ikind * attributes + (** An integer type. The kind specifies the sign and width. Several useful + variants are predefined as {!Cil.intType}, {!Cil.uintType}, + {!Cil.longType}, {!Cil.charType}. *) + + | TFloat of fkind * attributes + (** A floating-point type. The kind specifies the precision. You can also use + the predefined constant {!Cil.doubleType}. *) + + | TPtr of typ * attributes + (** Pointer type. Several useful variants are predefined as + {!Cil.charPtrType}, {!Cil.charConstPtrType} (pointer to a constant + character), {!Cil.voidPtrType}, {!Cil.intPtrType} *) + + | TArray of typ * exp option * bitsSizeofTypCache * attributes + (** Array type. It indicates the base type and the array length. *) + + | TFun of typ * (string * typ * attributes) list option * bool * attributes + (** Function type. Indicates the type of the result, the name, type + and name attributes of the formal arguments ([None] if no arguments + were specified, as in a function whose definition or prototype we + have not seen; [Some \[\]] means void). Use {!Cil.argsToList} to + obtain a list of arguments. The boolean indicates if it is a + variable-argument function. If this is the type of a varinfo for + which we have a function declaration then the information for the + formals must match that in the function's sformals. Use + {!Cil.setFormals}, or {!Cil.setFunctionType}, or + {!Cil.makeFormalVar} for this purpose. *) + + | TNamed of typeinfo * attributes + (** The use of a named type. All uses of the same type name must share the + typeinfo. Each such type name must be preceeded in the file by a [GType] + global. This is printed as just the type name. The actual referred type + is not printed here and is carried only to simplify processing. To see + through a sequence of named type references, use {!Cil.unrollType}. The + attributes are in addition to those given when the type name was + defined. *) + + | TComp of compinfo * bitsSizeofTypCache * attributes + (** A reference to a struct or a union type. All references to the + same struct or union must share the same compinfo among them and + with a [GCompTag] global that preceeds all uses (except maybe + those that are pointers to the composite type). The attributes + given are those pertaining to this use of the type and are in + addition to the attributes that were given at the definition of + the type and which are stored in the compinfo. *) + + | TEnum of enuminfo * attributes + (** A reference to an enumeration type. All such references must + share the enuminfo among them and with a [GEnumTag] global that + preceeds all uses. The attributes refer to this use of the + enumeration and are in addition to the attributes of the + enumeration itself, which are stored inside the enuminfo *) + + | TBuiltin_va_list of attributes +(** This is the same as the gcc's type with the same name *) + +(** Various kinds of integers *) +and ikind = + IBool (** [_Bool] *) + | IChar (** [char] *) + | ISChar (** [signed char] *) + | IUChar (** [unsigned char] *) + | IInt (** [int] *) + | IUInt (** [unsigned int] *) + | IShort (** [short] *) + | IUShort (** [unsigned short] *) + | ILong (** [long] *) + | IULong (** [unsigned long] *) + | ILongLong (** [long long] (or [_int64] on Microsoft Visual C) *) + | IULongLong (** [unsigned long long] (or [unsigned _int64] on Microsoft + Visual C) *) + +(** Various kinds of floating-point numbers*) +and fkind = + FFloat (** [float] *) + | FDouble (** [double] *) + | FLongDouble (** [long double] *) + +(** This is used to cache the computation of the size of types in bits. *) +and bitsSizeofTyp = + | Not_Computed + | Computed of int + | Not_Computable of (string * typ) (** Explanation of the error *) + +and bitsSizeofTypCache = { mutable scache : bitsSizeofTyp} + +(* ************************************************************************* *) +(** {2 Attributes} *) +(* ************************************************************************* *) + +and attribute = + | Attr of string * attrparam list + (** An attribute has a name and some optional parameters. The name should not + start or end with underscore. When CIL parses attribute names it will + strip leading and ending underscores (to ensure that the multitude of GCC + attributes such as const, __const and __const__ all mean the same + thing.) *) + + | AttrAnnot of string + +(** Attributes are lists sorted by the attribute name. Use the functions + {!Cil.addAttribute} and {!Cil.addAttributes} to insert attributes in an + attribute list and maintain the sortedness. *) +and attributes = attribute list + +(** The type of parameters of attributes *) +and attrparam = + | AInt of (Integer.t[@opaque]) (** An integer constant *) + | AStr of string (** A string constant *) + | ACons of string * attrparam list + (** Constructed attributes. These are printed [foo(a1,a2,...,an)]. The list + of parameters can be empty and in that case the parentheses are not + printed. *) + | ASizeOf of typ (** A way to talk about types *) + | ASizeOfE of attrparam + | AAlignOf of typ + | AAlignOfE of attrparam + | AUnOp of unop * attrparam + | ABinOp of binop * attrparam * attrparam + | ADot of attrparam * string (** a.foo **) + | AStar of attrparam (** * a *) + | AAddrOf of attrparam (** & a **) + | AIndex of attrparam * attrparam (** a1[a2] *) + | AQuestion of attrparam * attrparam * attrparam (** a1 ? a2 : a3 **) + +(* ************************************************************************* *) +(** {2 Structures} *) +(* ************************************************************************* *) + +(** The {!Cil_types.compinfo} describes the definition of a structure or union + type. Each such {!Cil_types.compinfo} must be defined at the top-level using + the [GCompTag] constructor and must be shared by all references to this type + (using either the [TComp] type constructor or from the definition of the + fields. + + If all you need is to scan the definition of each composite type once, you + can do that by scanning all top-level [GCompTag]. + + Constructing a {!Cil_types.compinfo} can be tricky since it must contain + fields that might refer to the host {!Cil_types.compinfo} and furthermore + the type of the field might need to refer to the {!Cil_types.compinfo} for + recursive types. Use the {!Cil.mkCompInfo} function to create a + {!Cil_types.compinfo}. You can easily fetch the {!Cil_types.fieldinfo} for a + given field in a structure with {!Cil.getCompField}. *) + +(** The definition of a structure or union type. Use {!Cil.mkCompInfo} to make + one and use {!Cil.copyCompInfo} to copy one (this ensures that a new key is + assigned and that the fields have the right pointers to parents.). + @plugin development guide *) +and compinfo = { + mutable cstruct: bool; + (** [true] if struct, [false] if union *) + + corig_name: string; + (** Original name as found in C file. Will never be changed *) + + mutable cname: string; + (** The name. Always non-empty. Use {!Cil.compFullName} to get the full name + of a comp (along with the struct or union) *) + + mutable ckey: int; + (** A unique integer. This is assigned by {!Cil.mkCompInfo} using a global + variable in the Cil module. Thus two identical structs in two different + files might have different keys. Use {!Cil.copyCompInfo} to copy + structures so that a new key is assigned. *) + + mutable cfields: fieldinfo list; + (** Information about the fields. Notice that each fieldinfo has a pointer + back to the host compinfo. This means that you should not share + fieldinfo's between two compinfo's *) + + mutable cattr: attributes; + (** The attributes that are defined at the same time as the composite + type. These attributes can be supplemented individually at each + reference to this [compinfo] using the [TComp] type constructor. *) + + mutable cdefined: bool; + (** This boolean flag can be used to distinguish between structures + that have not been defined and those that have been defined but have + no fields (such things are allowed in gcc). *) + + mutable creferenced: bool; +(** [true] if used. Initially set to [false]. *) +} + +(* ************************************************************************* *) +(** {2 Structure fields} *) +(* ************************************************************************* *) + +(** The {!Cil_types.fieldinfo} structure is used to describe a structure or + union field. Fields, just like variables, can have attributes associated + with the field itself or associated with the type of the field (stored along + with the type of the field). *) + +(** Information about a struct/union field. + @plugin development guide *) +and fieldinfo = { + mutable fcomp: compinfo; + (** The host structure that contains this field. There can be only one + [compinfo] that contains the field. *) + + forig_name: string; + (** original name as found in C file. *) + + mutable fname: string; + (** The name of the field. Might be the value of {!Cil.missingFieldName} in + which case it must be a bitfield and is not printed and it does not + participate in initialization *) + + mutable ftype: typ; + (** The type. If the field is a bitfield, a special attribute + [FRAMA_C_BITFIELD_SIZE] indicating the width of the bitfield is added. *) + + mutable fbitfield: int option; + (** If a bitfield then ftype should be an integer type and the width of the + bitfield must be 0 or a positive integer smaller or equal to the width of + the integer type. A field of width 0 is used in C to control the alignment + of fields. *) + + mutable fattr: attributes; + (** The attributes for this field (not for its type) *) + + mutable floc: location; + (** The location where this field is defined *) + + mutable faddrof: bool; + (** Adapted from CIL [vaddrof] field for variables. Only set for non-array + fields. Variable whose field address is taken is not marked anymore as + having its own address taken. True if the address of this field is + taken. CIL will set these flags when it parses C, but you should make + sure to set the flag whenever your transformation create [AddrOf] + expression. *) + + mutable fsize_in_bits: int option; + (** (Deprecated. Use {!Cil.bitsOffset} instead.) Similar to [fbitfield] for + all types of fields. + @deprecated only Jessie uses this *) + + mutable foffset_in_bits: int option; + (** Offset at which the field starts in the structure. Do not read directly, + but use {!Cil.bitsOffset} instead. *) + + mutable fpadding_in_bits: int option; +(** (Deprecated.) Store the size of the padding that follows the field, if any. + @deprecated only Jessie uses this *) +} + +(* ************************************************************************* *) +(** {2 Enumerations} *) +(* ************************************************************************* *) + +(** Information about an enumeration. This is shared by all references to an + enumeration. Make sure you have a [GEnumTag] for each of these. *) + +(** Information about an enumeration. + @plugin development guide *) +and enuminfo = { + eorig_name: string; (** original name as found in C file. *) + + mutable ename: string; (** The name. Always non-empty. *) + + mutable eitems: enumitem list; (** Items. The list must be non-empty *) + + mutable eattr: attributes; + (** The attributes that are defined at the same time as the enumeration + type. These attributes can be supplemented individually at each + reference to this [enuminfo] using the [TEnum] type constructor. *) + + mutable ereferenced: bool; (** [true] if used. Initially set to [false]. *) + mutable ekind: ikind (** The integer kind used to represent this enum. MSVC + always assumes IInt but this is not the case + for gcc. See ISO C 6.7.2.2 *) +} + +and enumitem = { + eiorig_name: string; (** original name as found in C file. *) + mutable einame: string; (** the name, always non-empty. *) + mutable eival: exp; (** value of the item. Must be a compile-time constant *) + mutable eihost: enuminfo; (** the host enumeration in which the item is + declared. *) + eiloc: location; +} + +(** Information about a defined type. + @plugin development guide *) +and typeinfo = { + torig_name: string; (** original name as found in C file. *) + + mutable tname: string; + (** The name. Can be empty only in a [GType] when introducing a composite or + enumeration tag. If empty cannot be refered to from the file *) + + mutable ttype: typ; + (** The actual type. This includes the attributes that were present in the + typedef *) + + mutable treferenced: bool; (** [true] if used. Initially set to [false]. *) +} + +(* ************************************************************************* *) +(** {2 Variables} *) +(* ************************************************************************* *) + +(** Each local or global variable is represented by a unique + {!Cil_types.varinfo} structure. A global {!Cil_types.varinfo} can be + introduced with the [GVarDecl] or [GVar], [GFunDecl] or [GFun] globals. + A local varinfo can be introduced as part of a function definition + {!Cil_types.fundec}. + + All references to a given global or local variable must refer to the same + copy of the [varinfo]. Each [varinfo] has a globally unique identifier that + can be used to index maps and hashtables (the name can also be used for this + purpose, except for locals from different functions). This identifier is + constructor using a global counter. + + It is very important that you construct [varinfo] structures using only one + of the following functions: + - {!Cil.makeGlobalVar} : to make a global variable + - {!Cil.makeTempVar} : to make a temporary local variable whose name + will be generated so that to avoid conflict with other locals. + - {!Cil.makeLocalVar} : like {!Cil.makeTempVar} but you can specify the + exact name to be used. + - {!Cil.copyVarinfo}: make a shallow copy of a varinfo assigning a new name + and a new unique identifier + + A [varinfo] is also used in a function type to denote the list of + formals. *) + +(** Information about a variable. + @plugin development guide *) +and varinfo = { + mutable vname: string; + (** The name of the variable. Cannot be empty. It is primarily your + responsibility to ensure the uniqueness of a variable name. For local + variables {!Cil.makeTempVar} helps you ensure that the name is + unique. *) + + vorig_name: string; + (** the original name of the variable. Need not be unique. *) + + mutable vtype: typ; + (** The declared type of the variable. *) + + mutable vattr: attributes; + (** A list of attributes associated with the variable.*) + + mutable vstorage: storage; + (** The storage-class *) + + mutable vglob: bool; + (** True if this is a global variable*) + + mutable vdefined: bool; + (** True if the variable or function is defined in the file. Only relevant + for functions and global variables. Not used in particular for local + variables and logic variables. *) + + mutable vformal: bool; + (** True if the variable is a formal parameter of a function. *) + + mutable vinline: bool; + (** Whether this varinfo is for an inline function. *) + + mutable vdecl: location; + (** Location of variable declaration. *) + + mutable vid: int; + (** A unique integer identifier. This field will be set for you if you use + one of the {!Cil.makeFormalVar}, {!Cil.makeLocalVar}, + {!Cil.makeTempVar}, {!Cil.makeGlobalVar}, or {!Cil.copyVarinfo}. *) + + mutable vaddrof: bool; + (** [true] if the address of this variable is taken. CIL will set these + flags when it parses C, but you should make sure to set the flag + whenever your transformation create [AddrOf] expression. *) + + mutable vreferenced: bool; + (** [true] if this variable is ever referenced. This is computed by + [removeUnusedVars]. It is safe to just initialize this to [false]. *) + + vtemp: bool; + (** [true] for temporary variables generated by CIL normalization. [false] + for all the other variables. *) + + mutable vdescr: string option; + (** For most temporary variables, a description of what the var holds. + (e.g. for temporaries used for function call results, this string is a + representation of the function call.) *) + + mutable vdescrpure: bool; + (** Indicates whether the vdescr above is a pure expression or call. True + for all CIL expressions and Lvals, but false for e.g. function calls. + Printing a non-pure vdescr more than once may yield incorrect + results. *) + + mutable vghost: bool; + (** Indicates if the variable is declared in ghost code *) + + vsource: bool; + (** [true] iff this variable appears in the source of the program, which is + the case of all the variables in the initial AST. Plugins may create + variables with [vsource=false], for example to handle dynamic allocation. + Those variables do *not* have an associated {!GVar} or {!GVarDecl}. *) + + mutable vlogic_var_assoc: logic_var option + (** Logic variable representing this variable in the logic world. Do not + access this field directly. Instead, call {!Cil.cvar_to_lvar}. *) +} + +(** Storage-class information *) +and storage = + NoStorage (** The default storage. Nothing is printed *) + | Static + | Register + | Extern + +(* ************************************************************************* *) +(** {2 Expressions} *) +(* ************************************************************************* *) + +(** The CIL expression language contains only the side-effect free expressions + of C. They are represented as the type {!Cil_types.exp}. There are several + interesting aspects of CIL expressions: + + Integer and floating point constants can carry their textual representation. + This way the integer 15 can be printed as 0xF if that is how it occurred in + the source. + + CIL uses arbitrary precision integers + to represent the integer constants and also stores the + width of the integer type. Care must be taken to ensure that the constant is + representable with the given width. Use the functions {!Cil.kinteger}, + {!Cil.kinteger64} and {!Cil.integer} to construct constant expressions. CIL + predefines the constants {!Cil.zero}, {!Cil.one} and {!Cil.mone} (for -1). + + Use the functions {!Cil.isConstant} and {!Cil.isInteger} to test if an + expression is a constant and a constant integer respectively. + + CIL keeps the type of all unary and binary expressions. You can think of + that type qualifying the operator. Furthermore there are different operators + for arithmetic and comparisons on arithmetic types and on pointers. + + Another unusual aspect of CIL is that the implicit conversion between an + expression of array type and one of pointer type is made explicit, using the + [StartOf] expression constructor (which is not printed). If you apply the + [AddrOf]constructor to an lvalue of type [T] then you will be getting an + expression of type [TPtr(T)]. + + You can find the type of an expression with {!Cil.typeOf}. + + You can perform constant folding on expressions using the function + {!Cil.constFold}. *) + +(** Expressions (Side-effect free)*) +and exp = { + eid: int; (** unique identifier *) + enode: exp_node; (** the expression itself *) + eloc: location; (** location of the expression. *) +} + +and exp_node = + | Const of constant (** Constant *) + | Lval of lval (** Lvalue *) + | SizeOf of typ + (** sizeof(). Has [unsigned int] type (ISO 6.5.3.4). This is not + turned into a constant because some transformations might want to change + types *) + + | SizeOfE of exp (** sizeof() *) + + | SizeOfStr of string + (** sizeof(string_literal). We separate this case out because this is the + only instance in which a string literal should not be treated as having + type pointer to character. *) + + | AlignOf of typ + (** This corresponds to the GCC __alignof_. Has [unsigned int] type *) + + | AlignOfE of exp + + | UnOp of unop * exp * typ + (** Unary operation. Includes the type of the result. *) + + | BinOp of binop * exp * exp * typ + (** Binary operation. Includes the type of the result. The arithmetic + conversions are made explicit for the arguments. + @plugin development guide *) + + | CastE of typ * exp + (** Use {!Cil.mkCast} to make casts. *) + + | AddrOf of lval + (** Always use {!Cil.mkAddrOf} to construct one of these. Apply to an lvalue + of type [T] yields an expression of type [TPtr(T)] *) + + | StartOf of lval + (** Conversion from an array to a pointer to the beginning of the array. + Given an lval of type [TArray(T)] produces an expression of type + [TPtr(T)]. In C this operation is implicit, the [StartOf] operator is not + printed. We have it in CIL because it makes the typing rules simpler. *) + + | Info of exp * exp_info +(** Additional information on the underlying expression *) + +(** Additional information on an expression *) +and exp_info = { + exp_type : logic_type; (** when used as placeholder for a term *) + exp_name: string list; +} + +(* ************************************************************************* *) +(** {2 Constants} *) +(* ************************************************************************* *) + +(** Literal constants *) +and constant = + | CInt64 of (Integer.t[@opaque]) * ikind * string option + (** Integer constant. Give the ikind (see ISO9899 6.1.3.2) and the + textual representation. Textual representation is always set to Some s + when it comes from user code. This allows us to print a + constant as it was represented in the code, for example, + 0xF instead of 15. It is usually None for constant generated by Cil + itself. Use {!Cil.integer} or {!Cil.kinteger} to create these. *) + + | CStr of string + (** String constant. The escape characters inside the string have been already + interpreted. This constant has pointer to character type! The only case + when you would like a string literal to have an array type is when it is + an argument to sizeof. In that case you should use SizeOfStr. *) + + | CWStr of int64 list + (** Wide character string constant. Note that the local interpretation of such + a literal depends on {!Cil.theMachine.wcharType} and + {!Cil.theMachine.wcharKind}. Such a constant has type pointer to + {!Cil.theMachine.wcharType}. The escape characters in the string have not + been "interpreted" in the sense that L"A\xabcd" remains "A\xabcd" rather + than being represented as the wide character list with two elements: 65 + and 43981. That "interpretation" depends on the underlying wide character + type. *) + + | CChr of char + (** Character constant. This has type int, so use charConstToInt to read the + value in case sign-extension is needed. *) + + | CReal of float * fkind * string option + (** Floating point constant. Give the fkind (see ISO 6.4.4.2) and also the + textual representation, if available. *) + + | CEnum of enumitem +(** An enumeration constant. Use [Cillower.lowerEnumVisitor] to replace these + with integer constants. *) + +(** Unary operators *) +and unop = + Neg (** Unary minus *) + | BNot (** Bitwise complement (~) *) + | LNot (** Logical Not (!) *) + +(** Binary operations *) +and binop = + PlusA (** arithmetic + *) + | PlusPI (** pointer + integer *) + | IndexPI (** pointer + integer but only when it arises from an expression + [e\[i\]] when [e] is a pointer and + not an array. This is semantically + the same as PlusPI but CCured uses + this as a hint that the integer is + probably positive. *) + | MinusA (** arithmetic - *) + | MinusPI (** pointer - integer *) + | MinusPP (** pointer - pointer *) + | Mult (** * *) + | Div (** / + @plugin development guide *) + | Mod (** % + @plugin development guide *) + | Shiftlt (** shift left *) + | Shiftrt (** shift right *) + + | Lt (** < (arithmetic comparison) *) + | Gt (** > (arithmetic comparison) *) + | Le (** <= (arithmetic comparison) *) + | Ge (** >= (arithmetic comparison) *) + | Eq (** == (arithmetic comparison) *) + | Ne (** != (arithmetic comparison) *) + | BAnd (** bitwise and *) + | BXor (** exclusive-or *) + | BOr (** inclusive-or *) + + | LAnd (** logical and. Unlike other expressions this one does not always + evaluate both operands. If you want + to use these, you must set + {!Cil.useLogicalOperators}. *) + | LOr (** logical or. Unlike other expressions this one does not always + evaluate both operands. If you + want to use these, you must set + {!Cil.useLogicalOperators}. *) + +(* ************************************************************************* *) +(** {2 Left values} *) +(* ************************************************************************* *) + +(** Left values (aka Lvalues) are the sublanguage of expressions that can appear + at the left of an assignment or as operand to the address-of operator. In C + the syntax for lvalues is not always a good indication of the meaning of the + lvalue. For example the C value {v a[0][1][2] v} might involve 1, 2 or 3 + memory reads when used in an expression context, depending on the declared + type of the variable [a]. If [a] has type [int \[4\]\[4\]\[4\]] then we have + one memory read from somewhere inside the area that stores the array [a]. On + the other hand if [a] has type [int ***] then the expression really means [* + ( * ( * (a + 0) + 1) + 2)], in which case it is clear that it involves three + separate memory operations. + + An lvalue denotes the contents of a range of memory addresses. This range is + denoted as a host object along with an offset within the object. The host + object can be of two kinds: a local or global variable, or an object whose + address is in a pointer expression. We distinguish the two cases so that we + can tell quickly whether we are accessing some component of a variable + directly or we are accessing a memory location through a pointer. To make + it easy to tell what an lvalue means CIL represents lvalues as a host object + and an offset (see {!Cil_types.lval}). The host object (represented as + {!Cil_types.lhost}) can be a local or global variable or can be the object + pointed-to by a pointer expression. The offset (represented as + {!Cil_types.offset}) is a sequence of field or array index designators. + + Both the typing rules and the meaning of an lvalue is very precisely + specified in CIL. + + The following are a few useful function for operating on lvalues: + - {!Cil.mkMem} - makes an lvalue of [Mem] kind. Use this to ensure + that certain equivalent forms of lvalues are canonized. + For example, [*&x = x]. + - {!Cil.typeOfLval} - the type of an lvalue + - {!Cil.typeOffset} - the type of an offset, given the type of the + host. + - {!Cil.addOffset} and {!Cil.addOffsetLval} - extend sequences + of offsets. + - {!Cil.removeOffset} and {!Cil.removeOffsetLval} - shrink sequences + of offsets. + + The following equivalences hold {v + Mem(AddrOf(Mem a, aoff)), off = Mem a, aoff + off + Mem(AddrOf(Var v, aoff)), off = Var v, aoff + off + AddrOf (Mem a, NoOffset) = a + v} *) + +and lval = lhost * offset + +(** The host part of an {!Cil_types.lval}. *) +and lhost = + | Var of varinfo + (** The host is a variable. *) + + | Mem of exp +(** The host is an object of type [T] when the expression has pointer + [TPtr(T)]. *) + + +(** The offset part of an {!Cil_types.lval}. Each offset can be applied to + certain kinds of lvalues and its effect is that it advances the starting + address of the lvalue and changes the denoted type, essentially focussing + to some smaller lvalue that is contained in the original one. + @plugin development guide *) +and offset = + | NoOffset + (** No offset. Can be applied to any lvalue and does not change either the + starting address or the type. This is used when the lval consists of just + a host or as a terminator in a list of other kinds of offsets. *) + + | Field of fieldinfo * offset + (** A field offset. Can be applied only to an lvalue that denotes a structure + or a union that contains the mentioned field. This advances the offset to + the beginning of the mentioned field and changes the type to the type of + the mentioned field. *) + + | Index of exp * offset +(** An array index offset. Can be applied only to an lvalue that denotes an + array. This advances the starting address of the lval to the beginning of + the mentioned array element and changes the denoted type to be the type of + the array element *) + +(* ************************************************************************* *) +(** {2 Initializers} *) +(* ************************************************************************* *) + +(** A special kind of expressions are those that can appear as initializers for + global variables (initialization of local variables is turned into + assignments). The initializers are represented as type + {!Cil_types.init}. You can create initializers with {!Cil.makeZeroInit} and + you can conveniently scan compound initializers them with + {!Cil.foldLeftCompound}. *) + +(** Initializers for global variables. *) +and init = + | SingleInit of exp (** A single initializer *) + | CompoundInit of typ * (offset * init) list +(** Used only for initializers of structures, unions and arrays. The offsets + are all of the form [Field(f, NoOffset)] or [Index(i, NoOffset)] and + specify the field or the index being initialized. For structures all fields + must have an initializer (except the unnamed bitfields), in the proper + order. This is necessary since the offsets are not printed. For arrays the + list must contain a prefix of the initializers; the rest are 0-initialized. + For unions there must be exactly one initializer. If the initializer is not + for the first field then a field designator is printed, so you better be on + GCC since MSVC does not understand this. You can scan an initializer list + with {!Cil.foldLeftCompound}. *) + +(** We want to be able to update an initializer in a global variable, so we + define it as a mutable field *) +and initinfo = { mutable init : init option } + +(* ************************************************************************* *) +(** {2 Function definitions} *) +(* ************************************************************************* *) + +(** A function definition is always introduced with a [GFun] constructor at the + top level. All the information about the function is stored into a + {!Cil_types.fundec}. Some of the information (e.g. its name, type, storage, + attributes) is stored as a {!Cil_types.varinfo} that is a field of the + [fundec]. To refer to the function from the expression language you must use + the [varinfo]. + + The function definition contains, in addition to the body, a list of all the + local variables and separately a list of the formals. Both kind of variables + can be referred to in the body of the function. The formals must also be + shared with the formals that appear in the function type. For that reason, + to manipulate formals you should use the provided functions + {!Cil.makeFormalVar} and {!Cil.setFormals}. *) + +(** Function definitions. + @plugin development guide *) +and fundec = { + mutable svar: varinfo; + (** Holds the name and type as a variable, so we can refer to it easily + from the program. All references to this function either in a function + call or in a prototype must point to the same [varinfo]. *) + + mutable sformals: varinfo list; + (** Formals. These must be in the same order and with the same information + as the formal information in the type of the function. Use + {!Cil.setFormals} or {!Cil.setFunctionType} to set these formals and + ensure that they are reflected in the function type. Do not make + copies of these because the body refers to them. *) + + mutable slocals: varinfo list; + (** Locals. Does NOT include the sformals. Do not make copies of these + because the body refers to them. *) + + mutable smaxid: int; + (** Max local id. Starts at 0. Used for creating the names of new + temporary variables. Updated by {!Cil.makeLocalVar} and + {!Cil.makeTempVar}. You can also use {!Cil.setMaxId} to set it after + you have added the formals and locals. *) + + mutable sbody: block; (** The function body. *) + + mutable smaxstmtid: int option; + (** max id of a (reachable) statement in this function, if we have + computed it. range = 0 ... (smaxstmtid-1). This is computed by + {!Cfg.computeCFGInfo}. *) + + mutable sallstmts: stmt list; + (** After you call {!Cfg.computeCFGInfo} this field is set to contain all + statements in the function. *) + + mutable sspec: funspec; +} + +(** A block is a sequence of statements with the control falling through from + one element to the next *) +and block = { + mutable battrs: attributes; (** Attributes for the block *) + + mutable blocals: varinfo list; + (** variables that are local to the block. It is a subset of the slocals of + the enclosing function. *) + + mutable bstmts: stmt list; (** The statements comprising the block. *) +} + +(* ************************************************************************* *) +(** {2 Statements} *) +(* ************************************************************************* *) + +(** CIL statements are the structural elements that make the CFG. They are + represented using the type {!Cil_types.stmt}. Every statement has a + (possibly empty) list of labels. The {!Cil_types.stmtkind} field of a + statement indicates what kind of statement it is. + + Use {!Cil.mkStmt} to make a statement and the fill-in the fields. + + CIL also comes with support for control-flow graphs. The [sid] field in + [stmt] can be used to give unique numbers to statements, and the [succs] and + [preds] fields can be used to maintain a list of successors and predecessors + for every statement. The CFG information is not computed by default. Instead + you must explicitly use the functions {!Cfg.prepareCFG} and + {!Cfg.computeCFGInfo} to do it. *) + +(** Statements. + @plugin development guide *) +and stmt = { + mutable labels: label list; + (** Whether the statement starts with some labels, case statements or + default statements. *) + + mutable skind: stmtkind; + (** The kind of statement *) + + mutable sid: int; + (** A number (>= 0) that is unique in a function. Filled in only after the + CFG is computed. *) + + mutable succs: stmt list; + (** The successor statements. They can always be computed from the skind and + the context in which this statement appears. Filled in only after the CFG + is computed. *) + + mutable preds: stmt list; + (** The inverse of the succs function. *) + + mutable ghost : bool +} + +(** Labels *) +and label = + | Label of string * location * bool + (** A real label. If the bool is "true", the label is from the input source + program. If the bool is "false", the label was created by CIL or some + other transformation *) + + | Case of exp * location + (** A case statement. This expression is lowered into a constant if + {!Cil.lowerConstants} is set to [true]. *) + + | Default of location (** A default statement *) + +(* The various kinds of statements *) +and stmtkind = + | Instr of instr + (** An instruction that does not contain control flow. Control implicitly + falls through. + @plugin development guide *) + + | Return of exp option * location + (** The return statement. This is a leaf in the CFG. + @plugin development guide *) + + | Goto of stmt ref * location + (** A goto statement. Appears from actual goto's in the code or from goto's + that have been inserted during elaboration. The reference points to the + statement that is the target of the Goto. This means that you have to + update the reference whenever you replace the target statement. The + target statement MUST have at least a label. + @plugin development guide *) + + | Break of location + (** A break to the end of the nearest enclosing Loop or Switch. + @plugin development guide *) + + | Continue of location + (** A continue to the start of the nearest enclosing [Loop]. + @plugin development guide *) + + | If of exp * block * block * location + (** A conditional. Two successors, the "then" and the "else" branches (in + this order). + Both branches fall-through to the successor of the If statement. + @plugin development guide *) + + | Switch of exp * block * (stmt list) * location + (** A switch statement. [exp] is the index of the switch. [block] is + the body of the switch. [stmt list] contains the set of + statements whose [labels] are cases of the switch (i.e. for each + case, the corresponding statement is in [stmt list], a statement + cannot appear more than once in the list, and statements in + [stmt list] can have several labels corresponding to several + cases. + @plugin development guide *) + + | Loop of + code_annotation list * block * location * (stmt option) * (stmt option) + (** A [while(1)] loop. The termination test is implemented in the body of a + loop using a [Break] statement. If {!Cfg.prepareCFG} has been called, the + first stmt option will point to the stmt containing the continue label + for this loop and the second will point to the stmt containing the break + label for this loop. + @plugin development guide *) + + | Block of block + (** Just a block of statements. Use it as a way to keep some block attributes + local. + @plugin development guide *) + + | UnspecifiedSequence of (stmt * lval list + * lval list * lval list * stmt ref list) list + (** statements whose order of execution is not specified by + ISO/C. This is important for the order of side effects + during evaluation of expressions. Each statement comes + together with three list of lval, in this order. + - lvals that are written during the sequence and whose future + value depends upon the statement (it is legal to read from them, but + not to write to them) + - lvals that are written during the evaluation of the statement itself + - lval that are read. + - Function calls in the corresponding statement + Note that this include only a subset of the affectations + of the statement. Namely, the + temporary variables generated by cil are excluded (i.e. it + is assumed that the "compilation" is correct). In addition, + side effects caused by function applications are not taken + into account in the list. For a single statement, the written lvals + are supposed to be ordered (or their order of evaluation doesn't + matter), so that an alarm should be emitted only if the lvals read by + a statement overlap with the lvals written (or read) by another + statement of the sequence. + + At this time this feature is + experimental and may miss some unspecified sequences. + + In case you do not care about this feature just handle it + like a block (see {!Cil.block_from_unspecified_sequence}). + @plugin development guide *) + + | Throw of (exp * typ) option * location + (** Throws an exception, C++ style. + We keep the type of the expression, to match + it against the appropriate catch clause. A Throw node has + no successor, even if it is in try-catch block that will catch + the exception: we keep normal and exceptional control-flow + completely separate, as in Jo and Chang, ICSSA 2004. + *) + + | TryCatch of block * (catch_binder * block) list * location + + | TryFinally of block * block * location + (** On MSVC we support structured exception handling. This is what you might + expect. Control can get into the finally block either from the end of the + body block, or if an exception is thrown. + @plugin development guide *) + + | TryExcept of block * (instr list * exp) * block * location +(** On MSVC we support structured exception handling. The try/except + statement is a bit tricky: + {v __try \{ blk \} + __except (e) \{ + handler + \} + v} + + The argument to __except must be an expression. However, we keep a + list of instructions AND an expression in case you need to make + function calls. We'll print those as a comma expression. The control + can get to the __except expression only if an exception is thrown. + After that, depending on the value of the expression the control + goes to the handler, propagates the exception, or retries the + exception. The location corresponds to the try keyword. + @plugin development guide *) + +(** Kind of exceptions that are caught by a given clause. *) +and catch_binder = + | Catch_exn of varinfo * (varinfo * block) list + (** catch exception of given type(s). + If the list is empty, only exceptions with the same type as the + varinfo can be caught. If the list is non-empty, only exceptions + matching one of the type of a varinfo in the list are caught. + The associated block contains the operations necessary to transform + the matched varinfo into the principal one. + Semantics is by value (i.e. the varinfo is bound to a copy of the + caught object). + + This clause is a declaration point for the varinfo(s) + mentioned in it. More precisely, for + [Catch_exn(v_0,[(v_1, b_1),..., (v_n, b_n)])], + the [v_i] must be referenced in the [slocals] of the + enclosing [fundec], and _must not_ appear in any [blocals] + of some block. The scope of v_0 is all the [b_i] and + the corresponding block in the [catch_binder * block list] of the + [TryCatch] node the binder belongs to. The scope of the other [v_i] + is the corresponding [b_i]. + *) + | Catch_all (** default catch clause: all exceptions are caught. *) + +(** Instructions. They may cause effects directly but may not have control + flow.*) +and instr = + | Set of lval * exp * location + (** An assignment. A cast is present if the exp has different type from + lval *) + + | Call of lval option * exp * exp list * location + (** optional: result is an lval. A cast might be necessary if the declared + result type of the function is not the same as that of the destination. + Actual arguments must have a type equivalent (i.e. {!Cil.need_cast} must + return [false]) to the one of the formals of the function. + If the type of the result variable is not the same as the declared type of + the function result then an implicit cast exists. + *) + + (* See the GCC specification for the meaning of ASM. + If the source is MS VC then only the templates + are used. + + [sm] I've added a notes.txt file which contains more + information on interpreting Asm instructions *) + | Asm of + attributes (* Really only const and volatile can appear here *) + * string list (* templates (CR-separated) *) + * extended_asm option + * location + (** An inline assembly instruction. The arguments are + (1) a list of attributes (only const and volatile can appear here and only + for GCC) + (2) templates (CR-separated) + (3) GCC extended asm information if any + (4) location information *) + + | Skip of location + + | Code_annot of code_annotation * location + + +(** GNU extended-asm information: + - a list of outputs, each of which is an lvalue with optional names and + constraints. + - a list of input expressions along with constraints + - clobbered registers + - Possible destinations statements *) +and extended_asm = + { + asm_outputs: (string option * string * lval) list + (** outputs must be lvals with optional names and constraints. I would + like these to be actually variables, but I run into some trouble with + ASMs in the Linux sources *); + asm_inputs: (string option * string * exp) list + (** inputs with optional names and constraints *); + asm_clobbers: string list (** register clobbers *); + asm_gotos: (stmt ref) list + (** list of statements this asm section may jump to. Destination + must have a label. *); + } + +(** Describes a location in a source file *) +and location = Lexing.position * Lexing.position [@opaque] + +(** {1 Abstract syntax trees for annotations} *) + +and logic_constant = + | Integer of (Integer.t[@opaque]) * string option + (** Integer constant with a textual representation. *) + | LStr of string (** String constant. *) + | LWStr of int64 list (** Wide character string constant. *) + | LChr of char (** Character constant. *) + | LReal of logic_real + | LEnum of enumitem (** An enumeration constant.*) + +(** Real constants. *) +and logic_real = { + r_literal : string ; (** Initial string representation [s]. *) + r_nearest : float ; (** Nearest approximation of [s] in double precision. *) + r_upper : float ; (** Smallest double [u] such that [s <= u]. *) + r_lower : float ; (** Greatest double [l] such that [l <= s]. *) +} + +(** Types of logic terms. *) +and logic_type = + | Ctype of typ (** a C type *) + | Ltype of logic_type_info * logic_type list + (** an user-defined logic type with its parameters *) + | Lvar of string (** a type variable. *) + | Linteger (** mathematical integers, {i i.e.} Z *) + | Lreal (** mathematical reals, {i i.e.} R *) + | Larrow of logic_type list * logic_type (** (n-ary) function type *) + +(** tsets with an unique identifier. + Use [Logic_const.new_location] to generate a new id. *) +and identified_term = { + it_id: int; (** the identifier. *) + it_content: term (** the term *) +} + +(** logic label referring to a particular program point. *) +and logic_label = + | StmtLabel of stmt ref (** label of a C statement. *) + | LogicLabel of (stmt option * string) (* [JS 2011/05/13] why a tuple here? *) +(** builtin logic label ({t Here, Pre}, ...) *) + +(* ************************************************************************* *) +(** {2 Terms} *) +(* ************************************************************************* *) + +(** C Expressions as logic terms follow C constructs (with prefix T) *) + +(** Logic terms. *) +and term = { + term_node : term_node; (** kind of term. *) + term_loc : Lexing.position * Lexing.position [@opaque]; + (** position in the source file. *) + term_type : logic_type; (** type of the term. *) + term_name: string list; + (** names of the term if any. A name can be an arbitrary string, where + '"' and '\'' are escaped by a \, and which does not end with a \. + Hence, "name" and 'name' should be recognized as a unique label by most + tools. *) +} + +(** the various kind of terms. *) +and term_node = + (* same constructs as exp *) + | TConst of logic_constant (** a constant. *) + | TLval of term_lval (** an L-value *) + | TSizeOf of typ (** size of a given C type. *) + | TSizeOfE of term (** size of the type of an expression. *) + | TSizeOfStr of string (** size of a string constant. *) + | TAlignOf of typ (** alignment of a type. *) + | TAlignOfE of term (** alignment of the type of an expression. *) + | TUnOp of unop * term (** unary operator. *) + | TBinOp of binop * term * term (** binary operators. *) + | TCastE of typ * term (** cast to a C type. *) + | TAddrOf of term_lval (** address of a term. *) + | TStartOf of term_lval (** beginning of an array. *) + + (* additional constructs *) + | Tapp of logic_info * (logic_label * logic_label) list * term list + (** application of a logic function. *) + | Tlambda of quantifiers * term (** lambda abstraction. *) + | TDataCons of logic_ctor_info * term list + (** constructor of logic sum-type. *) + | Tif of term * term * term + (** conditional operator*) + | Tat of term * logic_label + (** term refers to a particular program point. *) + | Tbase_addr of logic_label * term (** base address of a pointer. *) + | Toffset of logic_label * term (** offset from the base address of a pointer. *) + | Tblock_length of logic_label * term (** length of the block pointed to by the term. *) + | Tnull (** the null pointer. *) + | TLogic_coerce of logic_type * term + (** implicit conversion from a C type to a logic type. + The logic type must not be a Ctype. In particular, used to denote + lifting to Linteger and Lreal. + *) + | TCoerce of term * typ (** coercion to a given C type. *) + | TCoerceE of term * term (** coercion to the type of a given term. *) + | TUpdate of term * term_offset * term + (** functional update of a field. *) + | Ttypeof of term (** type tag for a term. *) + | Ttype of typ (** type tag for a C type. *) + | Tempty_set (** the empty set. *) + | Tunion of term list (** union of terms. *) + | Tinter of term list (** intersection of terms. *) + | Tcomprehension of + term * quantifiers * predicate option + (** set defined in comprehension ({t \{ t[i] | integer i; 0 <= i < 5\}}) *) + | Trange of term option * term option (** range of integers. *) + | Tlet of logic_info * term (** local binding *) + +(** lvalue: base address and offset. *) +and term_lval = + term_lhost * term_offset + +(** base address of an lvalue. *) +and term_lhost = + | TVar of logic_var (** a variable. *) + | TResult of typ (** value returned by a C function. + Only used in post-conditions or assigns + *) + | TMem of term (** memory access. *) + +(** model field. *) +and model_info = { + mi_name: string; (** name *) + mi_field_type: logic_type; (** type of the field *) + mi_base_type: typ; (** type to which the field is associated. *) + mi_decl: location; (** where the field has been declared. *) +} + +(** offset of an lvalue. *) +and term_offset = + | TNoOffset (** no further offset. *) + | TField of fieldinfo * term_offset + (** access to the field of a compound type. *) + | TModel of model_info * term_offset (** access to a model field. *) + | TIndex of term * term_offset + (** index. Note that a range is denoted by [TIndex(Trange(i1,i2),ofs)] *) + +(** description of a logic function or predicate. +@plugin development guide *) +and logic_info = { +(* + mutable l_name : string; (** name of the function. *) +*) + mutable l_var_info : logic_var; + (** we use only fields lv_name and lv_id of l_var_info + we should factorize lv_type and l_type+l_profile below *) + mutable l_labels : logic_label list; (** label arguments of the function. *) + mutable l_tparams : string list; (** type parameters *) + mutable l_type : logic_type option; (** return type. None for predicates *) + mutable l_profile : logic_var list; (** type of the arguments. *) + mutable l_body : logic_body; (** body of the function. *) +} + +and builtin_logic_info = { + mutable bl_name: string; + mutable bl_labels: logic_label list; + mutable bl_params: string list; + mutable bl_type: logic_type option; + mutable bl_profile: (string * logic_type) list; +} + +and logic_body = + | LBnone (** no definition and no reads clause *) + | LBreads of identified_term list + (** read accesses performed by a function. *) + | LBterm of term (** direct definition of a function. *) + | LBpred of predicate (** direct definition of a predicate. *) + | LBinductive of + (string * logic_label list * string list * predicate) list + (** inductive definition *) + +(** Description of a logic type. + @plugin development guide *) +and logic_type_info = { + lt_name: string; + lt_params : string list; (** type parameters*) + mutable lt_def: logic_type_def option + (** definition of the type. None for abstract types. *) +} +(* will be expanded when dealing with concrete types *) + +and logic_type_def = + | LTsum of logic_ctor_info list (** sum type with its constructors. *) + | LTsyn of logic_type (** Synonym of another type. *) + +(** origin of a logic variable. *) +and logic_var_kind = + | LVGlobal (** global logic function or predicate. *) + | LVC (** Logic counterpart of a C variable. *) + | LVFormal (** formal parameter of a logic function / predicate + or \lambda abstraction *) + | LVQuant (** Bound by a quantifier (\exists or \forall) *) + | LVLocal (** local \let *) + +(** description of a logic variable +@plugin development guide *) +and logic_var = { + mutable lv_name : string; (** name of the variable. *) + mutable lv_id : int; (** unique identifier *) + mutable lv_type : logic_type; (** type of the variable. *) + mutable lv_kind: logic_var_kind; (** kind of the variable *) + mutable lv_origin : varinfo option +(** when the logic variable stems from a C variable, set to the original C + variable. *) +} + +(** Description of a constructor of a logic sum-type. + @plugin development guide *) +and logic_ctor_info = + { ctor_name: string; (** name of the constructor. *) + ctor_type: logic_type_info; (** type to which the constructor belongs. *) + ctor_params: logic_type list + (** types of the parameters of the constructor. *) + } + +(* ************************************************************************* *) +(** {2 Predicates} *) +(* ************************************************************************* *) + +(** variables bound by a quantifier. *) +and quantifiers = logic_var list + +(** comparison relations*) +and relation = + | Rlt + | Rgt + | Rle + | Rge + | Req + | Rneq (** @plugin development guide *) + + +(** predicates *) +and predicate_node = + | Pfalse (** always-false predicate. *) + | Ptrue (** always-true predicate. *) + | Papp of logic_info * (logic_label * logic_label) list * term list + (** application of a predicate. *) + | Pseparated of term list + | Prel of relation * term * term (** comparison of two terms. *) + | Pand of predicate * predicate (** conjunction *) + | Por of predicate * predicate (** disjunction. *) + | Pxor of predicate * predicate (** logical xor. *) + | Pimplies of predicate * predicate (** implication. *) + | Piff of predicate * predicate (** equivalence. *) + | Pnot of predicate (** negation. *) + | Pif of term * predicate * predicate (** conditional *) + | Plet of logic_info * predicate (** definition of a local variable *) + | Pforall of quantifiers * predicate (** universal quantification. *) + | Pexists of quantifiers * predicate (** existential quantification. *) + | Pat of predicate * logic_label + (** predicate refers to a particular program point. *) + | Pvalid_read of logic_label * term (** the given locations are valid for reading. *) + | Pvalid of logic_label * term (** the given locations are valid. *) + | Pvalid_function of term + (** the pointed function has a type compatible with the one of pointer. *) + | Pinitialized of logic_label * term (** the given locations are initialized. *) + | Pdangling of logic_label * term (** the given locations contain dangling + adresses. *) + | Pallocable of logic_label * term (** the given locations can be allocated. *) + | Pfreeable of logic_label * term (** the given locations can be free. *) + | Pfresh of logic_label * logic_label * term * term + (** \fresh(pointer, n) + A memory block of n bytes is newly allocated to the pointer.*) + | Psubtype of term * term + (** First term is a type tag that is a subtype of the second. *) + +(** predicate with an unique identifier. Use [Logic_const.new_predicate] to + create fresh predicates *) +and identified_predicate = { + ip_id: int; (** identifier *) + ip_content: predicate; (** the predicate itself*) +} + +(** predicates with a location and an optional list of names *) +and predicate = { + pred_name : string list; (** list of given names *) + pred_loc : location; (** position in the source code. *) + pred_content : predicate_node;(** content *) +} + +(* Polymorphic types shared with parsed trees (Logic_ptree) *) +(** variant of a loop or a recursive function. Type shared with Logic_ptree. *) +and 'term variant = 'term * string option + +(** allocates and frees. + @since Oxygen-20120901 *) +and 'locs allocation = + | FreeAlloc of 'locs list * 'locs list (** tsets. Empty list means \nothing. *) + | FreeAllocAny (** Nothing specified. Semantics depends on where it + is written. *) + +(** dependencies of an assigned location. Shared with Logic_ptree. *) +and 'locs deps = + | From of 'locs list (** tsets. Empty list means \nothing. *) + | FromAny (** Nothing specified. Any location can be involved. *) + +and 'locs from = ('locs * 'locs deps) + +(** zone assigned with its dependencies. Type shared with Logic_ptree. *) +and 'locs assigns = + | WritesAny (** Nothing specified. Anything can be written. *) + | Writes of 'locs from list + (** list of locations that can be written. Empty list means \nothing. *) + +(** Function or statement contract. This type shares the name of its + constructors with {!Logic_ptree.spec}. *) +and spec = { + mutable spec_behavior : behavior list; + (** behaviors *) + + mutable spec_variant : term variant option; + (** variant for recursive functions. *) + + mutable spec_terminates: identified_predicate option; + (** termination condition. *) + + mutable spec_complete_behaviors: string list list; + (** list of complete behaviors. + It is possible to have more than one set of complete behaviors *) + + mutable spec_disjoint_behaviors: string list list; + (** list of disjoint behaviors. + It is possible to have more than one set of disjoint behaviors *) +} + + +(** extension to standard ACSL clause. + Each extension is associated to a keyword. An extension + can be registered through the following functions: + - {!Logic_typing.register_behavior_extension} for parsing and type-checking + - {!Cil_printer.register_behavior_extension} for pretty-printing an + extended clause + - {!Cil.register_behavior_extension} for visiting an extended clause + + @plugin development guide *) +and acsl_extension = string * acsl_extension_kind + +and acsl_extension_kind = + | Ext_id of int (** id used internally by the extension itself. *) + | Ext_terms of term list + | Ext_preds of predicate list + (** a list of predicates, the most common case of for extensions *) + +(** Behavior of a function or statement. This type shares the name of its + constructors with {!Logic_ptree.behavior}. + @since Oxygen-20120901 [b_allocation] has been added. + @since Carbon-20101201 [b_requires] has been added. + @modify Boron-20100401 [b_ensures] is replaced by [b_post_cond]. + Old [b_ensures] represent the [Normal] case of [b_post_cond]. *) +and behavior = { + mutable b_name : string; (** name of the behavior. *) + mutable b_requires : identified_predicate list; (** require clauses. *) + mutable b_assumes : identified_predicate list; (** assume clauses. *) + mutable b_post_cond : (termination_kind * identified_predicate) list + (** post-condition. *); + mutable b_assigns : identified_term assigns; (** assignments. *) + mutable b_allocation : identified_term allocation; (** frees, allocates. *) + mutable b_extended : acsl_extension list (** extensions *) +} + +(** kind of termination a post-condition applies to. See ACSL manual. *) +and termination_kind = Normal | Exits | Breaks | Continues | Returns + +(** Pragmas for the value analysis plugin of Frama-C. + Type shared with Logic_ptree.*) +and 'term loop_pragma = + | Unroll_specs of 'term list + | Widen_hints of 'term list + | Widen_variables of 'term list + +(** Pragmas for the slicing plugin of Frama-C. Type shared with Logic_ptree.*) +and 'term slice_pragma = + | SPexpr of 'term + | SPctrl + | SPstmt + +(** Pragmas for the impact plugin of Frama-C. Type shared with Logic_ptree.*) +and 'term impact_pragma = + | IPexpr of 'term + | IPstmt + +(** The various kinds of pragmas. Type shared with Logic_ptree. *) +and 'term pragma = + | Loop_pragma of 'term loop_pragma + | Slice_pragma of 'term slice_pragma + | Impact_pragma of 'term impact_pragma + +(** all annotations that can be found in the code. + This type shares the name of its constructors with + {!Logic_ptree.code_annot}. *) +and code_annotation_node = + | AAssert of string list * predicate + (** assertion to be checked. The list of strings is the list of + behaviors to which this assertion applies. *) + + | AStmtSpec of string list * spec + (** statement contract + (potentially restricted to some enclosing behaviors). *) + + | AInvariant of string list * bool * predicate + (** loop/code invariant. The list of strings is the list of behaviors to which + this invariant applies. The boolean flag is true for normal loop + invariants and false for invariant-as-assertions. *) + + | AVariant of term variant + (** loop variant. Note that there can be at most one variant associated to a + given statement *) + + | AAssigns of string list * identified_term assigns + (** loop assigns. (see [b_assigns] in the behaviors for other assigns). At + most one clause associated to a given (statement, behavior) couple. *) + + | AAllocation of string list * identified_term allocation + (** loop allocation clause. (see [b_allocation] in the behaviors for other + allocation clauses). + At most one clause associated to a given (statement, behavior) couple. + @since Oxygen-20120901 when [b_allocation] has been added. *) + + | APragma of term pragma (** pragma. *) + | AExtended of string list * acsl_extension + (** extension in a loop annotation. + @since Silicon-20161101 *) + +(** function contract. *) + +and funspec = spec + +(** code annotation with an unique identifier. + Use [Logic_const.new_code_annotation] to create new code annotations with + a fresh id. *) +and code_annotation = { + annot_id: int; (** identifier. *) + annot_content : code_annotation_node; (** content of the annotation. *) +} + +(** behavior of a function. *) +and funbehavior = behavior + +(** global annotations, not attached to a statement or a function. *) +and global_annotation = + | Dfun_or_pred of logic_info * location + | Dvolatile of + identified_term list * varinfo option * varinfo option * location + (** associated terms, reading function, writing function *) + | Daxiomatic of string * global_annotation list * location + | Dtype of logic_type_info * location (** declaration of a logic type. *) + | Dlemma of + string * bool * logic_label list * string list * + predicate * location + (** definition of a lemma. The boolean flag is [true] if the property should + be taken as an axiom and [false] if it must be proved. *) + | Dinvariant of logic_info * location + (** global invariant. The predicate does not have any argument. *) + | Dtype_annot of logic_info * location + (** type invariant. The predicate has exactly one argument. *) + | Dmodel_annot of model_info * location + (** Model field for a type t, seen as a logic function with one + argument of type t *) + | Dcustom_annot of custom_tree * string* location + (*Custom declaration*) + +and custom_tree = CustomDummy +(* + | CustomType of logic_type + | CustomLexpr of lexpr + | CustomOther of string * (custom_tree list) +*) +[@@deriving visitors { variety = "iter"; polymorphic = true; concrete = true }, + visitors { variety = "map"; polymorphic = true; concrete = true }, + visitors { variety = "endo"; polymorphic = true; concrete = true }, + visitors { variety = "reduce"; polymorphic = true; concrete = true; ancestors = ["VisitorsRuntime.addition_monoid"] }, + visitors { variety = "mapreduce"; polymorphic = true; concrete = true; ancestors = ["VisitorsRuntime.addition_monoid"] }, + visitors { variety = "iter2"; polymorphic = true; concrete = true }, + visitors { variety = "map2"; polymorphic = true; concrete = true }, + visitors { variety = "reduce2"; polymorphic = true; concrete = true; ancestors = ["VisitorsRuntime.addition_monoid"] }, + visitors { variety = "mapreduce2"; polymorphic = true; concrete = true; ancestors = ["VisitorsRuntime.addition_monoid"] } +] + +type kinstr = + | Kstmt of stmt + | Kglobal + +(** Internal representation of decorated C functions *) +type cil_function = + | Definition of (fundec * location) (** defined function *) + | Declaration of (funspec * varinfo * varinfo list option * location) + (** Declaration(spec,f,args,loc) represents a leaf function [f] with + specification [spec] and arguments [args], at location [loc]. As + with the [TFun] constructor of {!Cil_types.typ}, the arg list is + optional, to distinguish [void f()] ([None]) from + [void f(void)] ([Some []]). *) + +(** Only field [fundec] can be used directly. Use {!Annotations.funspec}, + [Annotations.add_*] and [Annotations.remove_*] to query or modify field + [spec]. *) +type kernel_function = { + mutable fundec : cil_function; + mutable spec : funspec; +} + +(* [VP] TODO: VLocal should be attached to a particular block, not a whole + function. *) +type localisation = + | VGlobal + | VLocal of kernel_function + | VFormal of kernel_function + +type mach = { + sizeof_short: int; (* Size of "short" *) + sizeof_int: int; (* Size of "int" *) + sizeof_long: int ; (* Size of "long" *) + sizeof_longlong: int; (* Size of "long long" *) + sizeof_ptr: int; (* Size of pointers *) + sizeof_float: int; (* Size of "float" *) + sizeof_double: int; (* Size of "double" *) + sizeof_longdouble: int; (* Size of "long double" *) + sizeof_void: int; (* Size of "void" *) + sizeof_fun: int; (* Size of function *) + size_t: string; (* Type of "sizeof(T)" *) + wchar_t: string; (* Type of "wchar_t" *) + ptrdiff_t: string; (* Type of "ptrdiff_t" *) + alignof_short: int; (* Alignment of "short" *) + alignof_int: int; (* Alignment of "int" *) + alignof_long: int; (* Alignment of "long" *) + alignof_longlong: int; (* Alignment of "long long" *) + alignof_ptr: int; (* Alignment of pointers *) + alignof_float: int; (* Alignment of "float" *) + alignof_double: int; (* Alignment of "double" *) + alignof_longdouble: int; (* Alignment of "long double" *) + alignof_str: int; (* Alignment of strings *) + alignof_fun: int; (* Alignment of function *) + char_is_unsigned: bool; (* Whether "char" is unsigned *) + underscore_name: bool; (* If assembly names have leading underscore *) + const_string_literals: bool; (* Whether string literals have const chars *) + little_endian: bool; (* whether the machine is little endian *) + alignof_aligned: int (* Alignment of a type with aligned attribute *); + has__builtin_va_list: bool (* Whether [__builtin_va_list] is a known type *); + __thread_is_keyword: bool (* Whether [__thread] is a keyword *); + compiler: string; (* Compiler being used. Currently recognized names + are 'gcc', 'msvc' and 'generic'. *) + version: string; (* Information on this machdep *) +} diff --git a/test/cil_types_polymorphic.mllib b/test/cil_types_polymorphic.mllib new file mode 100644 index 0000000..7f40270 --- /dev/null +++ b/test/cil_types_polymorphic.mllib @@ -0,0 +1 @@ +cil_types_polymorphic diff --git a/test/cloud.ml b/test/cloud.ml new file mode 100644 index 0000000..53e50e9 --- /dev/null +++ b/test/cloud.ml @@ -0,0 +1,18 @@ +class ['self] base = object (_ : 'self) + method visit_real _env x = x +end + +type cloud = + | Point of (float[@name "real"]) * (float[@name "real"]) + | Clouds of cloud list + [@@name "nuage"] + [@@deriving visitors { variety = "map"; ancestors = ["base"] }] + +module List = struct + + type 'a mylist = 'a list = + | [] [@name "nil"] + | (::) of 'a * 'a mylist [@name "cons"] + [@@deriving visitors { variety = "map" }] + +end diff --git a/test/delayed_tree.ml b/test/delayed_tree.ml new file mode 100644 index 0000000..3093e8f --- /dev/null +++ b/test/delayed_tree.ml @@ -0,0 +1,435 @@ +(* To play with this code in an OCaml toplevel, launch [ocaml] and type this: + #use "topfind";; + #require "visitors.ppx";; + #require "visitors.runtime";; + *) + +(* -------------------------------------------------------------------------- *) + +(* Suppose we have an arbitrary data structure that contains elements + of type ['a]. Here, it is a binary tree, but it could be anything: *) + +type 'a sometree = + | Leaf + | Node of 'a sometree * 'a * 'a sometree + +(* This annotation is used only at the very end and can be ignored upon + first reading: *) + +[@@deriving visitors { variety = "reduce"; polymorphic = true; + name = "sometree_reduce" }] + +(* We would like to enumerate the elements of this data structure. + More precisely, we would like to construct an iterator, that is, + an on-demand producer of elements. Here is a simple definition + of a stateful iterator: *) + +type 'a iterator = + unit -> 'a option + +(* The question is, can we construct an iterator for the type ['a sometree], + based on an automatically-generated visitor, so that the construction is + entirely independent of the type ['a sometree]? *) + +(* -------------------------------------------------------------------------- *) + +(* For starters, let us define cascades, which are a more pleasant kind of + iterators. A cascade is a persistent (stateless) iterator. It can be + thought of as a delayed list, that is, a list whose elements are computed + only on demand. *) + +(* Cascades could (should) be part of a separate library. There is in fact a + proposal to add them to OCaml's standard library: see the discussion at + https://github.com/ocaml/ocaml/pull/1002 *) + +type 'a cascade = + unit -> 'a head + +and 'a head = + | Nil + | Cons of 'a * 'a cascade + +(* A delayed computation is represented as a function of type [unit -> _]. + Thus, no memoization takes place. It is easy to implement a function + [memo: 'a cascade -> 'a cascade] that turns a nonmemoizing cascade into + a memoizing one, so memoization can be requested a posteriori, if + desired. *) + +(* The empty cascade. *) + +let nil : 'a cascade = + fun () -> Nil + +let cons (x : 'a) (xs : 'a cascade) : 'a cascade = + fun () -> Cons (x, xs) + +(* Forcing a cascade reveals its head. *) + +let force xs = + xs() + +(* A cascade can be easily converted to a stateful iterator. *) + +let cascade_to_iterator (xs : 'a cascade) : 'a iterator = + let s = ref xs in + fun () -> + match force !s with + | Nil -> + (* Writing [nil] into [s] may seem superfluous, but is in fact + necessary to guarantee that the computation that just led to + a [Nil] outcome is not repeated in the future. *) + s := nil; + None + | Cons (x, xs) -> + s := xs; + Some x + +(* Because cascades are close cousins of lists, they are easy to work with. + Constructing a cascade for a tree-like data structure is straightforward, + whereas directly constructing a stateful iterator would be more involved. *) + +(* -------------------------------------------------------------------------- *) + +(* Now, can we use some kind of visitor to turn a tree of type ['a sometree] + into a cascade of type ['a cascade]? *) + +(* At first sight, this does not seem very easy, for two reasons: 1- a visitor + usually traverses a tree in an eager manner, whereas we need the traversal + to make progress only as cascade elements are demanded; and 2- a visitor + performs a bottom-up computation, without a left-to-right bias (assuming + mutable state is not used), whereas a cascade enumerates elements in a + left-to-right manner. (Or in a right-to-left manner. As will be apparent + below, both directions are possible.) *) + +(* The trick is to use another intermediate step. Instead of turning a tree + directly into a cascade, we first transform it into a generic tree-like + structure: a *delayed tree*. Problem 1 is solved because, by introducing + delays into the new tree, we allow its construction to be carried out on + demand. Problem 2 is solved because this tree-to-tree transformation can be + carried out in a purely bottom-up manner by a [reduce] visitor. Then, + finally, it is straightforward to transform a delayed tree into a + cascade. *) + +(* -------------------------------------------------------------------------- *) + +(* A delayed tree contains ordinary nodes of arity 0, 1, and 2. Furthermore, + it contains [DTDelay] nodes, of arity 1, whose child is delayed, that is, + computed only on demand. *) + +type 'a delayed_tree = + | DTZero + | DTOne of 'a + | DTTwo of 'a delayed_tree * 'a delayed_tree + | DTDelay of (unit -> 'a delayed_tree) + +(* A delayed tree is converted to a cascade as follows. We may choose, at this + point, between left-to-right and right-to-left traversals. As usual, when + building a cascade, one must take a continuation [k] as an argument, so as + to avoid naive and costly cascade concatenation operations. *) + +let rec delayed_tree_to_cascade (dt : 'a delayed_tree) (k : 'a cascade) +: 'a cascade = + fun () -> delayed_tree_to_head dt k + +and delayed_tree_to_head (dt : 'a delayed_tree) (k : 'a cascade) : 'a head = + match dt with + | DTZero -> + force k + | DTOne x -> + Cons (x, k) + | DTTwo (dt1, dt2) -> + delayed_tree_to_head dt1 (delayed_tree_to_cascade dt2 k) + | DTDelay dt -> + delayed_tree_to_head (force dt) k + +let delayed_tree_to_cascade (dt : 'a delayed_tree) : 'a cascade = + delayed_tree_to_cascade dt nil + +let delayed_tree_to_iterator (dt : 'a delayed_tree) : 'a iterator = + cascade_to_iterator (delayed_tree_to_cascade dt) + +(* -------------------------------------------------------------------------- *) + +(* We now set up four constructor functions and constructor methods, which + construct delayed trees, and which we will use in a [reduce] visitor. *) + +(* The type ['a delay] is a synonym for ['a]. It is used as a decoration, in a + type definition, to indicate that a call to the method [visit_delay] is + desired. *) + +type 'a delay = 'a + +class ['self] delayed_tree_monoid = object (_ : 'self) + + (* Delayed trees form a monoid, in the sense that we concatenate them using + [DTTwo], and the neutral element is [DTZero]. We package these two data + constructors in the methods [zero] and [plus], which are automatically + called in an automatically-generated [reduce] visitor. *) + + method zero = + DTZero + + method plus s1 s2 = + match s1, s2 with + | DTZero, s + | s, DTZero -> + (* This optimization is not mandatory. It helps allocate fewer nodes. *) + s + | (DTOne _ | DTTwo _ | DTDelay _), _ -> + DTTwo (s1, s2) + + (* The visitor method [visit_delay] delays the visit of a subtree by + constructing and returning a [DTDelay] node, which carries a delayed + recursive call to a visitor. *) + + method visit_delay: 'env 'a . + ('env -> 'a -> 'b delayed_tree) -> + 'env -> 'a delay -> 'b delayed_tree + = fun visit_'a env x -> + DTDelay (fun () -> visit_'a env x) + +end + +(* The visitor function [yield] will be invoked at elements of type ['a]. + It constructs a one-element delayed tree. *) + +let yield _env x = + DTOne x + +(* -------------------------------------------------------------------------- *) + +(* It is now time to generate a [reduce] visitor for the type ['a sometree]. + This is the only part of the code which is specific of [sometree]. + Everything else is generic. *) + +(* We must insert [delay]s into the structure of the type ['a sometree] so as + to indicate where [visit_delay] should be called and (therefore) where + [DTDelay] nodes should be allocated. To do this, we write a copy of the + definition of the type ['a sometree], with extra delays in it. The new type + is actually considered equal to ['a sometree] by OCaml. Its role is purely + to carry a [@@deriving visitors] annotation. *) + +(* In the data constructor [Node], the left-hand [delay] is in fact + superfluous. With or without it, our iterators will eagerly descend along + the leftmost branch of a tree, anyway. *) + +type 'a mytree = 'a sometree = + | Leaf + | Node of 'a mytree delay * 'a * 'a mytree delay + +and 'a mytree_delay = + 'a mytree delay + +[@@deriving visitors { variety = "reduce"; polymorphic = true; + concrete = true; ancestors = ["delayed_tree_monoid"] }] + +(* -------------------------------------------------------------------------- *) + +(* For demonstration purposes, let us make our visitor verbose. *) + +class ['self] verbose_reduce = object (_ : 'self) + inherit [_] reduce as super + method! visit_Leaf visit_'a env = + Printf.printf "Visiting a leaf.\n%!"; + super#visit_Leaf visit_'a env + method! visit_Node visit_'a env t1 x t2 = + Printf.printf "Visiting a node.\n%!"; + super#visit_Node visit_'a env t1 x t2 +end + +(* In production, one should remove [verbose_reduce] and use [reduce] + instead. *) + +let sometree_to_delayed_tree (t : 'a sometree) = + new verbose_reduce # visit_mytree_delay yield () t + (* We use [visit_mytree_delay], even though [visit_mytree] would work + just as well, so as to ensure that we get a delayed tree whose root + is a [DTDelay] node. *) + +(* Problem solved! *) + +let sometree_to_iterator (t : 'a sometree) : 'a iterator = + delayed_tree_to_iterator (sometree_to_delayed_tree t) + +(* -------------------------------------------------------------------------- *) + +(* Demo. *) + +let t : int sometree = + Node (Node (Leaf, 1, Leaf), 2, Node (Leaf, 3, Leaf)) + +let i : int iterator = + sometree_to_iterator t + +(* Transcript of an OCaml toplevel session: + + # i();; + Visiting a node. + Visiting a node. + Visiting a leaf. + - : int option = Some 1 + # i();; + Visiting a leaf. + - : int option = Some 2 + # i();; + Visiting a node. + Visiting a leaf. + - : int option = Some 3 + # i();; + Visiting a leaf. + - : int option = None + # i();; + - : int option = None + + *) + +(* -------------------------------------------------------------------------- *) + +(* Variant: it is possible to use the visitor [sometree_reduce] which was + generated at the very beginning. This removes the need for defining the + type [mytree]. The trick is to override the method [visit_sometree] so as + to insert a delay at every tree node. *) + +module Variant1 = struct + + class ['self] reduce = object (self : 'self) + inherit [_] sometree_reduce as super + inherit [_] delayed_tree_monoid + method! visit_sometree visit_'a env t = + self#visit_delay (super#visit_sometree visit_'a) env t + end + + (* The rest of the code is unchanged. It is reproduced here for testing. *) + + class ['self] verbose_reduce = object (_ : 'self) + inherit [_] reduce as super + method! visit_Leaf visit_'a env = + Printf.printf "Visiting a leaf.\n%!"; + super#visit_Leaf visit_'a env + method! visit_Node visit_'a env t1 x t2 = + Printf.printf "Visiting a node.\n%!"; + super#visit_Node visit_'a env t1 x t2 + end + + let sometree_to_delayed_tree (t : 'a sometree) = + new verbose_reduce # visit_sometree yield () t + + let sometree_to_iterator (t : 'a sometree) : 'a iterator = + delayed_tree_to_iterator (sometree_to_delayed_tree t) + + let t : int sometree = + Node (Node (Leaf, 1, Leaf), 2, Node (Leaf, 3, Leaf)) + + let i : int iterator = + sometree_to_iterator t + +end + +(* -------------------------------------------------------------------------- *) + +module Variant2 = struct + + (* The function [delayed_tree_to_cascade] could have been written directly + as follows, without the auxiliary function [delayed_tree_to_head]: *) + + let rec _delayed_tree_to_cascade (dt : 'a delayed_tree) (k : 'a cascade) + : 'a cascade = + match dt with + | DTZero -> + k + | DTOne x -> + cons x k + | DTTwo (dt1, dt2) -> + _delayed_tree_to_cascade dt1 (_delayed_tree_to_cascade dt2 k) + | DTDelay dt -> + fun () -> _delayed_tree_to_cascade (force dt) k () + + (* In this form, [delayed_tree_to_cascade] is the only operation that is + ever applied to a delayed tree, so we can refunctionalize delayed trees, + that is, wherever we used to build a delayed tree [t], we now directly + build a closure that is equivalent to [delayed_tree_to_cascade t]. *) + + type 'a producer = + 'a cascade -> 'a cascade + + type 'a delayed_tree = + 'a producer + + let _DTZero k = + k + + let _DTOne x k = + cons x k + + let _DTTwo dt1 dt2 k = + dt1 (dt2 k) + + let _DTDelay dt k = + fun () -> force dt k () + + let (_ : 'a delayed_tree) = _DTZero + let (_ : 'a -> 'a delayed_tree) = _DTOne + let (_ : 'a delayed_tree -> 'a delayed_tree -> 'a delayed_tree) = _DTTwo + let (_ : (unit -> 'a delayed_tree) -> 'a delayed_tree) = _DTDelay + + let delayed_tree_to_cascade (dt : 'a delayed_tree) : 'a cascade = + dt nil + + let delayed_tree_to_iterator (dt : 'a delayed_tree) : 'a iterator = + cascade_to_iterator (delayed_tree_to_cascade dt) + + (* The delayed monoid uses the new constructors. In [plus], we lose the + little optimization whereby [DTZero] were recognized and eliminated on + the fly. *) + + class ['self] delayed_tree_monoid = object (_ : 'self) + + method zero = + _DTZero + + method plus = + _DTTwo + + method visit_delay: 'env 'a . + ('env -> 'a -> 'b delayed_tree) -> + 'env -> 'a delay -> 'b delayed_tree + = fun visit_'a env x -> + _DTDelay (fun () -> visit_'a env x) + + end + + let yield _env x = + _DTOne x + + (* The rest of the code is as before. It is reproduced here for testing. *) + + class ['self] reduce = object (self : 'self) + inherit [_] sometree_reduce as super + inherit [_] delayed_tree_monoid + method! visit_sometree visit_'a env t = + self#visit_delay (super#visit_sometree visit_'a) env t + end + + class ['self] verbose_reduce = object (_ : 'self) + inherit [_] reduce as super + method! visit_Leaf visit_'a env = + Printf.printf "Visiting a leaf.\n%!"; + super#visit_Leaf visit_'a env + method! visit_Node visit_'a env t1 x t2 = + Printf.printf "Visiting a node.\n%!"; + super#visit_Node visit_'a env t1 x t2 + end + + let sometree_to_delayed_tree (t : 'a sometree) = + new verbose_reduce # visit_sometree yield () t + + let sometree_to_iterator (t : 'a sometree) : 'a iterator = + delayed_tree_to_iterator (sometree_to_delayed_tree t) + + let t : int sometree = + Node (Node (Leaf, 1, Leaf), 2, Node (Leaf, 3, Leaf)) + + let i : int iterator = + sometree_to_iterator t + +end diff --git a/test/dictionary.ml b/test/dictionary.ml new file mode 100644 index 0000000..afd4fd7 --- /dev/null +++ b/test/dictionary.ml @@ -0,0 +1,14 @@ +(* Examples of mixing the monomorphic and polymorphic modes. *) + +(* with a monomorphic 'env : *) +type ('a, 'b) dictionary = + | Empty + | NonEmpty of 'a * 'b * ('a, 'b) dictionary +[@@deriving visitors { variety = "map"; polymorphic = ["'b"] }] + +(* with a polymorphic 'env : *) +(* dubious though, since the method [visit_'a] cannot use [env] *) +type ('a, 'b) dictionary2 = + | Empty + | NonEmpty of 'a * 'b * ('a, 'b) dictionary2 +[@@deriving visitors { name = "map2"; variety = "map"; polymorphic = ["'b"; "'env"] }] diff --git a/test/expr.ml b/test/expr.ml new file mode 100644 index 0000000..3d11133 --- /dev/null +++ b/test/expr.ml @@ -0,0 +1,3 @@ +type expr = + | EConst of int + | EAdd of expr * expr diff --git a/test/expr.mllib b/test/expr.mllib new file mode 100644 index 0000000..b2f394d --- /dev/null +++ b/test/expr.mllib @@ -0,0 +1,42 @@ +expr +expr00 +expr00endo +expr00fold +expr00fold2 +expr01 +expr01use +expr01use_variant +expr02 +expr03 +expr04 +expr05 +expr05lexico +expr05lexico_test +expr06 +expr08 +expr08double +expr08extra +expr11 +expr12 +expr13 +expr13double +expr13extra +expr14 +expr15 +expr15b +expr15c +expr16 +expr17 +expr_import +expr_import_opaque +expr_info +expr_info_mapreduce +expr_info_mapreduce_test +expr_info_mapreduce_use +expr_info_polymorphic +expr_info_polymorphic_use +expr_info_polymorphic_use_test +expr_info_use +expr_redef +hexpr_polymorphic +oexpr_polymorphic diff --git a/test/expr00.ml b/test/expr00.ml new file mode 100644 index 0000000..0867bcd --- /dev/null +++ b/test/expr00.ml @@ -0,0 +1,4 @@ +type expr = + | EConst of int + | EAdd of expr * expr + [@@deriving visitors { variety = "iter" }] diff --git a/test/expr00.mli b/test/expr00.mli new file mode 100644 index 0000000..2c5c2ed --- /dev/null +++ b/test/expr00.mli @@ -0,0 +1,9 @@ +type expr = + | EConst of int + | EAdd of expr * expr + +class virtual ['self] iter : object ('self) + method visit_EAdd : 'monomorphic. 'env -> expr -> expr -> unit + method visit_EConst : 'monomorphic. 'env -> int -> unit + method visit_expr : 'monomorphic. 'env -> expr -> unit +end diff --git a/test/expr00endo.ml b/test/expr00endo.ml new file mode 100644 index 0000000..6b8ecde --- /dev/null +++ b/test/expr00endo.ml @@ -0,0 +1,4 @@ +type expr = + | EConst of int + | EAdd of expr * expr + [@@deriving visitors { variety = "endo" }] diff --git a/test/expr00fold.ml b/test/expr00fold.ml new file mode 100644 index 0000000..0d87d9f --- /dev/null +++ b/test/expr00fold.ml @@ -0,0 +1,4 @@ +type expr = + | EConst of (int[@opaque]) + | EAdd of expr * expr + [@@deriving visitors { variety = "fold" }] diff --git a/test/expr00fold2.ml b/test/expr00fold2.ml new file mode 100644 index 0000000..7a01203 --- /dev/null +++ b/test/expr00fold2.ml @@ -0,0 +1,4 @@ +type expr = + | EConst of (int[@opaque]) + | EAdd of expr * expr + [@@deriving visitors { variety = "fold2" }] diff --git a/test/expr01.ml b/test/expr01.ml new file mode 100644 index 0000000..7c6fec0 --- /dev/null +++ b/test/expr01.ml @@ -0,0 +1,4 @@ +type expr = + | EConst of int + | EAdd of expr * expr + [@@deriving visitors { variety = "map" }] diff --git a/test/expr01use.ml b/test/expr01use.ml new file mode 100644 index 0000000..557e19c --- /dev/null +++ b/test/expr01use.ml @@ -0,0 +1,25 @@ +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) + inherit [_] map + method! visit_EAdd env e1 e2 = + add + (self#visit_expr env e1) + (self#visit_expr env e2) + end in + o # visit_expr () + +let z e = EAdd (e, EConst 0) + +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_variant.ml b/test/expr01use_variant.ml new file mode 100644 index 0000000..42561f0 --- /dev/null +++ b/test/expr01use_variant.ml @@ -0,0 +1,20 @@ +open Expr01 + +let optimize : expr -> expr = + let o = object(self) + inherit [_] map + method! visit_EAdd env e1 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 () + +let z e = EAdd (e, EConst 0) + +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/expr02.ml b/test/expr02.ml new file mode 100644 index 0000000..05270da --- /dev/null +++ b/test/expr02.ml @@ -0,0 +1,4 @@ +type expr = + | EConst of int + | EAdd of expr * expr + [@@deriving visitors { variety = "iter2"; concrete = true }] diff --git a/test/expr03.ml b/test/expr03.ml new file mode 100644 index 0000000..a20f164 --- /dev/null +++ b/test/expr03.ml @@ -0,0 +1,4 @@ +type expr = + | EConst of int + | EAdd of expr * expr + [@@deriving visitors { variety = "map2" }] diff --git a/test/expr04.ml b/test/expr04.ml new file mode 100644 index 0000000..b1815cb --- /dev/null +++ b/test/expr04.ml @@ -0,0 +1,13 @@ +open Expr00 + +let count (e : expr) : int = + let v = object + val mutable count = 0 + method count = count + inherit [_] iter as super + method! visit_EAdd env e0 e1 = + count <- count + 1; + super#visit_EAdd env e0 e1 + end in + v#visit_expr () e; + v#count diff --git a/test/expr05.ml b/test/expr05.ml new file mode 100644 index 0000000..e0d7e2e --- /dev/null +++ b/test/expr05.ml @@ -0,0 +1,4 @@ +open Expr02 + +let equal : expr -> expr -> bool = + VisitorsRuntime.wrap2 (new iter2 # visit_expr ()) diff --git a/test/expr05lexico.ml b/test/expr05lexico.ml new file mode 100644 index 0000000..bb8c3cc --- /dev/null +++ b/test/expr05lexico.ml @@ -0,0 +1,20 @@ +open Expr02 + +let tag : expr -> int = function + | EConst _ -> 0 + | EAdd _ -> 1 + +exception Different of int + +let compare (i1 : int) (i2 : int) : unit = + if i1 <> i2 then + raise (Different (if i1 < i2 then -1 else 1)) + +class compare = object + inherit [_] iter2 + method! visit_int _ i1 i2 = compare i1 i2 + method! fail_expr () e1 e2 = compare (tag e1) (tag e2) +end + +let compare (e1 : expr) (e2 : expr) : int = + try new compare # visit_expr () e1 e2; 0 with Different c -> c diff --git a/test/expr05lexico_test.ml b/test/expr05lexico_test.ml new file mode 100644 index 0000000..3ed4385 --- /dev/null +++ b/test/expr05lexico_test.ml @@ -0,0 +1,11 @@ +open Expr02 +open Expr05lexico + +let () = + assert (compare (EConst 1) (EConst 2) = -1); + assert (compare (EConst 1) (EAdd (EConst 0, EConst 0)) = -1); + assert (compare (EAdd (EConst 0, EConst 0)) (EConst 1) = +1); + assert (compare (EAdd (EConst 0, EConst 0)) (EAdd (EConst 0, EConst 0)) = 0); + assert (compare (EAdd (EConst 0, EConst 0)) (EAdd (EConst 0, EConst 1)) = -1); + assert (compare (EAdd (EConst 1, EConst 0)) (EAdd (EConst 0, EConst 1)) = +1); + () diff --git a/test/expr06.ml b/test/expr06.ml new file mode 100644 index 0000000..966079f --- /dev/null +++ b/test/expr06.ml @@ -0,0 +1,16 @@ +type unop = + | UnaryMinus + +and binop = + | BinaryMinus + | BinaryAdd + | BinaryMul + | BinaryDiv + +and expr = + | EConst of int + | EUnOp of unop * expr + | EBinOp of expr * binop * expr + +[@@deriving visitors { variety = "iter" }, + visitors { variety = "map" }] diff --git a/test/expr08.ml b/test/expr08.ml new file mode 100644 index 0000000..ea885f0 --- /dev/null +++ b/test/expr08.ml @@ -0,0 +1,18 @@ +open Expr12 (* oexpr *) + +open Hashcons + +type hexpr = + H of hexpr oexpr hash_consed [@@unboxed] + +let table = + create 128 + +let h (e : hexpr oexpr) : hexpr = + H (hashcons table e) + +class ['self] hmap = object (self : 'self) + inherit [_] omap + method visit_'expr env (H { node = e; _ }) = + h (self#visit_oexpr env e) +end diff --git a/test/expr08double.ml b/test/expr08double.ml new file mode 100644 index 0000000..35ec2b3 --- /dev/null +++ b/test/expr08double.ml @@ -0,0 +1,10 @@ +open Expr12 (* [oexpr] *) +open Expr08 (* [hexpr] *) + +let double : hexpr -> hexpr = + let v = object + inherit [_] hmap + method! visit_EConst _env k = + EConst (2 * k) + end in + v # visit_'expr () diff --git a/test/expr08extra.ml b/test/expr08extra.ml new file mode 100644 index 0000000..4890675 --- /dev/null +++ b/test/expr08extra.ml @@ -0,0 +1,15 @@ +open Expr12 +open Expr08 +open Expr08double + +let econst e = h (EConst e) +let eadd e1 e2 = h (EAdd (e1, e2)) + +let e1 : hexpr = eadd (econst 0) (econst 1) +let e2 : hexpr = new hmap # visit_'expr () e1 (* identity *) +let () = + Printf.printf "%b\n%!" (e1 == e2) (* should print true *) +let e3 : hexpr = eadd (econst 0) (econst 2) +let e4 : hexpr = double e1 (* should produce [e3] *) +let () = + Printf.printf "%b\n%!" (e3 == e4) (* should print true *) diff --git a/test/expr11.ml b/test/expr11.ml new file mode 100644 index 0000000..3794b68 --- /dev/null +++ b/test/expr11.ml @@ -0,0 +1,4 @@ +type expr = + | EConst of int + | EAdd of expr list + [@@deriving visitors { variety = "iter" }] diff --git a/test/expr12.ml b/test/expr12.ml new file mode 100644 index 0000000..9c56040 --- /dev/null +++ b/test/expr12.ml @@ -0,0 +1,4 @@ +type 'expr oexpr = + | EConst of int + | EAdd of 'expr * 'expr + [@@deriving visitors { name = "omap"; variety = "map" }] diff --git a/test/expr13.ml b/test/expr13.ml new file mode 100644 index 0000000..cd8e3ba --- /dev/null +++ b/test/expr13.ml @@ -0,0 +1,10 @@ +open Expr12 + +type expr = + E of expr oexpr [@@unboxed] + +class ['self] map = object (self : 'self) + inherit [_] omap + method visit_'expr env (E e) = + E (self#visit_oexpr env e) +end diff --git a/test/expr13double.ml b/test/expr13double.ml new file mode 100644 index 0000000..17fa976 --- /dev/null +++ b/test/expr13double.ml @@ -0,0 +1,10 @@ +open Expr12 +open Expr13 + +let double : expr -> expr = + let v = object + inherit [_] map + method! visit_EConst _env k = + EConst (2 * k) + end in + v # visit_'expr () diff --git a/test/expr13extra.ml b/test/expr13extra.ml new file mode 100644 index 0000000..05304c5 --- /dev/null +++ b/test/expr13extra.ml @@ -0,0 +1,26 @@ +open Expr12 +open Expr13 +open Expr13double + +let const k = E (EConst k) +let add e1 e2 = E (EAdd (e1, e2)) + +let rec eval (E e) = + match e with + | EConst k -> k + | EAdd (e1, e2) -> eval e1 + eval e2 + +let e : expr = + add (const 1) (const 2) + +let () = + (* should print: 3 then 6 *) + Printf.printf "%d\n%d\n%!" (eval e) (eval (double e)) + +let omap : 'expr1 'expr2 . ('expr1 -> 'expr2) -> 'expr1 oexpr -> 'expr2 oexpr = + fun f e -> + let v = object + inherit [_] omap + method visit_'expr _env e = f e + end in + v # visit_oexpr () e diff --git a/test/expr14.ml b/test/expr14.ml new file mode 100644 index 0000000..e5700b0 --- /dev/null +++ b/test/expr14.ml @@ -0,0 +1,20 @@ +open Hashcons +open Expr12 (* [oexpr] *) +open Expr13 (* [expr] *) +open Expr08 (* [hexpr] *) + +let import : expr -> hexpr = + let v = object (self) + inherit [_] omap + method visit_'expr _env (E e) = + h (self#visit_oexpr _env e) + end in + v # visit_'expr () + +let export : hexpr -> expr = + let v = object (self) + inherit [_] omap + method visit_'expr _env (H { node = e; _ }) = + E (self#visit_oexpr _env e) + end in + v # visit_'expr () diff --git a/test/expr15.ml b/test/expr15.ml new file mode 100644 index 0000000..a20c709 --- /dev/null +++ b/test/expr15.ml @@ -0,0 +1,4 @@ +type expr = + | EConst of (int[@opaque]) + | EAdd of expr * expr + [@@deriving visitors { variety = "reduce" }] diff --git a/test/expr15b.ml b/test/expr15b.ml new file mode 100644 index 0000000..b4adcc1 --- /dev/null +++ b/test/expr15b.ml @@ -0,0 +1,10 @@ +open Expr15 + +let size : expr -> int = + let v = object + inherit [_] reduce as super + inherit [_] VisitorsRuntime.addition_monoid + method! visit_expr env e = + 1 + super # visit_expr env e + end in + v # visit_expr () diff --git a/test/expr15c.ml b/test/expr15c.ml new file mode 100644 index 0000000..18204a5 --- /dev/null +++ b/test/expr15c.ml @@ -0,0 +1,5 @@ +open Expr15 +open Expr15b + +let () = + Printf.printf "%d\n" (size (EAdd (EConst 22, EConst 11))) diff --git a/test/expr16.ml b/test/expr16.ml new file mode 100644 index 0000000..bba189c --- /dev/null +++ b/test/expr16.ml @@ -0,0 +1,4 @@ +type expr = + | EConst of int + | EAdd of expr * expr + [@@deriving visitors { variety = "iter"; public = ["visit_expr"] }] diff --git a/test/expr17.ml b/test/expr17.ml new file mode 100644 index 0000000..8dcb51f --- /dev/null +++ b/test/expr17.ml @@ -0,0 +1,4 @@ +type expr = + | EConst of (int[@opaque]) + | EAdd of expr * expr +[@@deriving visitors { variety = "mapreduce" }] diff --git a/test/expr_import.ml b/test/expr_import.ml new file mode 100644 index 0000000..ef3acc8 --- /dev/null +++ b/test/expr_import.ml @@ -0,0 +1,3 @@ +type expr = + [%import: Expr.expr] + [@@deriving visitors { variety = "iter" }] diff --git a/test/expr_import_opaque.ml b/test/expr_import_opaque.ml new file mode 100644 index 0000000..966949a --- /dev/null +++ b/test/expr_import_opaque.ml @@ -0,0 +1,3 @@ +type expr = + [%import: Expr.expr [@with int := int[@opaque]]] + [@@deriving visitors { variety = "iter" }] diff --git a/test/expr_info.ml b/test/expr_info.ml new file mode 100644 index 0000000..a07d126 --- /dev/null +++ b/test/expr_info.ml @@ -0,0 +1,8 @@ +type 'info expr_node = + | EConst of int + | EAdd of 'info expr * 'info expr + +and 'info expr = + { info: 'info; node: 'info expr_node } + +[@@deriving visitors { variety = "map" }] diff --git a/test/expr_info_mapreduce.ml b/test/expr_info_mapreduce.ml new file mode 100644 index 0000000..05ee19e --- /dev/null +++ b/test/expr_info_mapreduce.ml @@ -0,0 +1,8 @@ +type 'info expr_node = + | EConst of int + | EAdd of 'info expr * 'info expr + +and 'info expr = + { info: 'info; node: 'info expr_node } + +[@@deriving visitors { variety = "mapreduce" }] diff --git a/test/expr_info_mapreduce_test.ml b/test/expr_info_mapreduce_test.ml new file mode 100644 index 0000000..e92f521 --- /dev/null +++ b/test/expr_info_mapreduce_test.ml @@ -0,0 +1,29 @@ +open Expr_info_mapreduce +open Expr_info_mapreduce_use + +let mk node = { info = (); node } + +let const i = + mk (EConst i) + +let add e1 e2 = + mk (EAdd (e1, e2)) + +let e = + add (const 1) (add (const 0) (const 3)) + +let (e : int expr) = + annotate e + +let () = + assert (e.info = 5); + begin match e.node with + | EAdd (e1, e2) -> + assert (e1.info = 1); + assert (e2.info = 3); + () + | EConst _ -> + assert false + end; + Printf.printf "OK\n%!"; + () diff --git a/test/expr_info_mapreduce_use.ml b/test/expr_info_mapreduce_use.ml new file mode 100644 index 0000000..8442b88 --- /dev/null +++ b/test/expr_info_mapreduce_use.ml @@ -0,0 +1,15 @@ +open Expr_info_mapreduce + +let annotate (e : _ expr) : int expr = + let v = object + inherit [_] mapreduce as super + inherit [_] VisitorsRuntime.addition_monoid + method! visit_expr env { info = _; node } = + let node, size = super#visit_expr_node env node in + let size = size + 1 in + { info = size; node }, size + method visit_'info _env _info = + assert false (* never called *) + end in + let e, _ = v # visit_expr () e in + e diff --git a/test/expr_info_polymorphic.ml b/test/expr_info_polymorphic.ml new file mode 100644 index 0000000..22d3167 --- /dev/null +++ b/test/expr_info_polymorphic.ml @@ -0,0 +1,9 @@ +type 'info expr_node = + | EConst of int + | EAdd of 'info expr * 'info expr + +and 'info expr = + { info: 'info; node: 'info expr_node } + +[@@deriving visitors { variety = "map"; polymorphic = true; + concrete = true; data = false }] diff --git a/test/expr_info_polymorphic_use.ml b/test/expr_info_polymorphic_use.ml new file mode 100644 index 0000000..8680910 --- /dev/null +++ b/test/expr_info_polymorphic_use.ml @@ -0,0 +1,15 @@ +open Expr_info_polymorphic + +let v = new map + +let strip : _ expr -> unit expr = + let visit_'info _env _info = () in + fun e -> + v # visit_expr visit_'info () e + +let number : _ expr -> int expr = + let visit_'info count _info = + let c = !count in count := c + 1; c in + fun e -> + let count = ref 0 in + v # visit_expr visit_'info count e diff --git a/test/expr_info_polymorphic_use_test.ml b/test/expr_info_polymorphic_use_test.ml new file mode 100644 index 0000000..a415811 --- /dev/null +++ b/test/expr_info_polymorphic_use_test.ml @@ -0,0 +1,27 @@ +open Expr_info_polymorphic +open Expr_info_polymorphic_use + +let strip : 'a . 'a expr -> unit expr = strip +let number : 'a . 'a expr -> int expr = number + +let mk node = { info = (); node } + +let const i = + mk (EConst i) + +let add e1 e2 = + mk (EAdd (e1, e2)) + +let e = + add (const 1) (add (const 0) (const 3)) + +let e = number (strip e) + +let () = + assert (e.info = 0); + match e.node with + | EAdd (e1, e2) -> + assert (e1.info = 1); + assert (e2.info = 2) + | _ -> + assert false diff --git a/test/expr_info_use.ml b/test/expr_info_use.ml new file mode 100644 index 0000000..c82d224 --- /dev/null +++ b/test/expr_info_use.ml @@ -0,0 +1,17 @@ +open Expr_info + +let strip (e : _ expr) : unit expr = + let v = object + inherit [_] map + method visit_'info _env _info = () + end in + v # visit_expr () e + +let number (e : _ expr) : int expr = + let v = object + inherit [_] map + val mutable count = 0 + method visit_'info _env _info = + let c = count in count <- c + 1; c + end in + v # visit_expr () e diff --git a/test/expr_redef.ml b/test/expr_redef.ml new file mode 100644 index 0000000..aef646f --- /dev/null +++ b/test/expr_redef.ml @@ -0,0 +1,4 @@ +type expr = Expr.expr = + | EConst of int + | EAdd of expr * expr + [@@deriving visitors { variety = "iter" }] diff --git a/test/fold.ml b/test/fold.ml new file mode 100644 index 0000000..713c312 --- /dev/null +++ b/test/fold.ml @@ -0,0 +1,18 @@ +type person = { + firstname: string[@opaque]; + surname: string[@opaque] +} + +and crowd = + | Nobody + | Someone of person * crowd +[@@deriving visitors { variety = "fold" }] + +let convert : crowd -> (string * string) list = + let v = object + inherit [_] fold + method build_person () f s = (f, s) + method build_Nobody () = [] + method build_Someone () p c = p :: c + end + in v # visit_crowd () diff --git a/test/hexpr_polymorphic.ml b/test/hexpr_polymorphic.ml new file mode 100644 index 0000000..74e2531 --- /dev/null +++ b/test/hexpr_polymorphic.ml @@ -0,0 +1,52 @@ +open Hashcons + +module VisitorsHashcons = struct + + (* We CAN implement the method [visit_hash_consed], but this method requires + a hash-consing table. We assume that this table is stored in the field + [_table], which we declare virtual. *) + + (* A key subtlety is that the method [visit_hash_consed] must be monomorphic + in ['b]. Indeed, we cannot hope to build values of type ['b hash_consed] + for every ['b]. We can only hope to build values of type ['b hash_consed] + for a fixed ['b], where the hash-consing table has type ['b Hashcons.t]. + For now, the type ['b] is undetermined. It will be fixed in a subclass, + where the field [_table] is initialized. *) + + class virtual ['self] map = object (_ : 'self) + val virtual _table: 'b Hashcons.t + method visit_hash_consed: 'env 'a . + ('env -> 'a -> 'b) -> + 'env -> 'a hash_consed -> 'b hash_consed + = fun visit_'a env { node = e; _ } -> + hashcons _table (visit_'a env e) + end + +end + +(* This allows us to define the types [expr] and [hexpr] and generate a + visitor class for them. *) + +type 'expr oexpr = + | EConst of int + | EAdd of 'expr * 'expr + +and hexpr = + H of hexpr oexpr hash_consed [@@unboxed] + +[@@deriving visitors { variety = "map"; polymorphic = ["'expr"]; + ancestors = ["VisitorsHashcons.map"] }] + +(* Once the type [hexpr] is defined, we can allocate a table. *) + +let table : hexpr oexpr Hashcons.t = + Hashcons.create 128 + +(* Inheriting [map] and defining [_table] yields a working visitor. *) + +let id : hexpr -> hexpr = + let o = object + inherit [_] map + val _table = table + end in + o # visit_hexpr () diff --git a/test/mapReduce.ml b/test/mapReduce.ml new file mode 100644 index 0000000..fc59730 --- /dev/null +++ b/test/mapReduce.ml @@ -0,0 +1,9 @@ +type t = int * bool + +and u = { x: t; y: t } + +and expr = + | A + | B of t +[@@deriving visitors { variety = "mapreduce" }, + visitors { variety = "mapreduce2" }] diff --git a/test/map_from_fold.ml b/test/map_from_fold.ml new file mode 100644 index 0000000..dab99ad --- /dev/null +++ b/test/map_from_fold.ml @@ -0,0 +1,37 @@ +(* Direct definitions of [map], [reduce], and [fold]. *) +class virtual ['self] reduce = object (self: 'self) + method private visit_option: 'a . + ('env -> 'a -> 'z) -> 'env -> 'a option -> 'z + = fun f env ox -> + match ox with None -> self#zero | Some x -> f env x + method private virtual zero: 'z +end +class ['self] map = object (_ : 'self) + method private visit_option: 'a 'b . + ('env -> 'a -> 'b) -> 'env -> 'a option -> 'b option + = fun f env ox -> + match ox with None -> None | Some x -> Some (f env x) +end +class virtual ['self] fold = object (self : 'self) + method private visit_option: 'a . + ('env -> 'a -> 'r) -> 'env -> 'a option -> 's + = fun f env ox -> + match ox with + | None -> self#build_None env + | Some x -> self#build_Some env (f env x) + method private virtual build_None: 'env -> 's + method private virtual build_Some: 'env -> 'r -> 's +end +(* A successful definition of [reduce] in terms of [fold]. *) +class virtual ['self] reduce_from_fold = object (self : 'self) + inherit [_] fold + method private build_None _env = self#zero + method private build_Some _env z = z + method private virtual zero: 'z +end +(* An unsatisfactory definition of [map] in terms of [fold]. *) +class ['self] map_from_fold = object (_ : 'self) + inherit [_] fold + method private build_None _env = None + method private build_Some _env x = Some x +end diff --git a/test/map_from_fold.mli b/test/map_from_fold.mli new file mode 100644 index 0000000..9c6263d --- /dev/null +++ b/test/map_from_fold.mli @@ -0,0 +1,6 @@ +class ['self] map_from_fold : object ('self) + method private visit_option : 'a . + ('env -> 'a -> 'b) -> 'env -> 'a option -> 'b option + method private build_None : 'env -> 'b option + method private build_Some : 'env -> 'b -> 'b option +end diff --git a/test/misc.mllib b/test/misc.mllib new file mode 100644 index 0000000..3e96dad --- /dev/null +++ b/test/misc.mllib @@ -0,0 +1,22 @@ +build +cloud +delayed_tree +dictionary +fold +mapReduce +map_from_fold +monomorphic +monopoly +opaque +point +polyclass +prefixes +test00 +test01 +test02 +test03 +test04 +test05 +test06 +test07 +testallprims diff --git a/test/monomorphic.ml b/test/monomorphic.ml new file mode 100644 index 0000000..553a0f1 --- /dev/null +++ b/test/monomorphic.ml @@ -0,0 +1,11 @@ +type 'a t = + | Leaf of 'a + | Node of 'a t * ('a * 'a) t +[@@deriving visitors { variety = "map"; monomorphic = ["'env"] }] + +let o = object + inherit [_] map + method! visit_Leaf visit_'a env x = + let env = (env : int) in (* check that ['env] is not quantified *) + Leaf (visit_'a env x) +end diff --git a/test/monopoly.ml b/test/monopoly.ml new file mode 100644 index 0000000..67fd9f1 --- /dev/null +++ b/test/monopoly.ml @@ -0,0 +1,18 @@ +type ('a, 'b) data = + | DataNil + | DataCons of 'a * 'b * ('a, 'b) data + +and 'a seq = +| Nil +| Zero of ('a * 'a) seq +| One of 'a * ('a * 'a) seq + +[@@deriving visitors { variety = "iter"; polymorphic = ["a"] }, + visitors { variety = "map"; polymorphic = ["a"] }, + visitors { variety = "endo"; polymorphic = ["a"] }, + visitors { variety = "reduce"; polymorphic = ["a"] }, + visitors { variety = "mapreduce"; polymorphic = ["a"] }, + visitors { variety = "iter2"; polymorphic = ["a"] }, + visitors { variety = "map2"; polymorphic = ["a"] }, + visitors { variety = "reduce2"; polymorphic = ["a"] }, + visitors { variety = "mapreduce2"; polymorphic = ["a"] }] diff --git a/test/oexpr_polymorphic.ml b/test/oexpr_polymorphic.ml new file mode 100644 index 0000000..585ed4d --- /dev/null +++ b/test/oexpr_polymorphic.ml @@ -0,0 +1,21 @@ +(* Defining open expressions + and closing them, + in one go, + in [polymorphic] mode. *) + +type 'expr oexpr = + | EConst of int + | EAdd of 'expr * 'expr + +and expr = + E of expr oexpr [@@unboxed] + +[@@deriving visitors { variety = "map"; polymorphic = true; concrete = true }] + +let double : expr -> expr = + let v = object + inherit [_] map + method! visit_EConst _ _env k = + EConst (2 * k) + end in + v # visit_expr () diff --git a/test/opaque.ml b/test/opaque.ml new file mode 100644 index 0000000..d59f499 --- /dev/null +++ b/test/opaque.ml @@ -0,0 +1,21 @@ +type hop = position[@opaque] + +and position = { + pos_fname : string[@opaque]; + pos_lnum : int * (int[@opaque]); + pos_bol : int; + pos_cnum : int; + foo: (int[@opaque]) list; + } +and foo = + | A of (int[@opaque]) * int + | B of bool +[@@deriving + visitors { variety = "iter" }, + visitors { variety = "map" }, + visitors { variety = "reduce" }, + visitors { variety = "endo" }, + visitors { variety = "iter2" }, + visitors { variety = "map2" }, + visitors { variety = "reduce2" } +] diff --git a/test/point.ml b/test/point.ml new file mode 100644 index 0000000..151ac5d --- /dev/null +++ b/test/point.ml @@ -0,0 +1,4 @@ +type point = + { x: int; y: int } + +let make x y = { x; y } diff --git a/test/point.mli b/test/point.mli new file mode 100644 index 0000000..dca6c3e --- /dev/null +++ b/test/point.mli @@ -0,0 +1,2 @@ +type point = private { x: int; y: int } +val make: int -> int -> point diff --git a/test/polyclass.ml b/test/polyclass.ml new file mode 100644 index 0000000..4f7772e --- /dev/null +++ b/test/polyclass.ml @@ -0,0 +1,8 @@ +class ['self] c = object (_ : 'self) + method identity (x : 'a) : 'a = x +end + +let b : bool = + new c # identity true +let i : int = + new c # identity 0 diff --git a/test/prefixes.ml b/test/prefixes.ml new file mode 100644 index 0000000..5705855 --- /dev/null +++ b/test/prefixes.ml @@ -0,0 +1,23 @@ +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 diff --git a/test/test00.ml b/test/test00.ml new file mode 100644 index 0000000..f2a84c1 --- /dev/null +++ b/test/test00.ml @@ -0,0 +1,11 @@ +type u = Uber + and point = u * u +[@@deriving + visitors { variety = "iter" }, + visitors { variety = "map" }, + visitors { variety = "reduce" }, + visitors { variety = "endo" }, + visitors { variety = "iter2" }, + visitors { variety = "map2" }, + visitors { variety = "reduce2" } +] diff --git a/test/test01.ml b/test/test01.ml new file mode 100644 index 0000000..dba7ac0 --- /dev/null +++ b/test/test01.ml @@ -0,0 +1,11 @@ +type point = + { x: int; y: int; mutable color: bool } +[@@deriving + visitors { variety = "iter" }, + visitors { variety = "map" }, + visitors { variety = "reduce" }, + visitors { variety = "endo" }, + visitors { variety = "iter2" }, + visitors { variety = "map2" }, + visitors { variety = "reduce2" } +] diff --git a/test/test02.ml b/test/test02.ml new file mode 100644 index 0000000..b9ff25e --- /dev/null +++ b/test/test02.ml @@ -0,0 +1,31 @@ +type term = + | TUnit + | TIntLiteral of int + | TVar of string + | TLambda of string * term + | TApp of term * term + | TPair of { fst: term; snd: term } + | TTuple of term_list + +and term_list = + | TLNil + | TLCons of (term * term_list) + +[@@deriving + visitors { variety = "iter"; concrete = true }, + visitors { variety = "map"; concrete = true }, + visitors { variety = "reduce"; concrete = true; ancestors = ["VisitorsRuntime.addition_monoid"] }, + visitors { variety = "endo"; concrete = true }, + visitors { variety = "iter2"; concrete = true }, + visitors { variety = "map2"; concrete = true }, + visitors { variety = "reduce2"; concrete = true; ancestors = ["VisitorsRuntime.addition_monoid"] } +] + +let identity : term = + TLambda ("x", TVar "x") + +let () = + new iter#visit_term 33 identity + +let () = + new iter#visit_term 33 (new map#visit_term () identity) diff --git a/test/test03.ml b/test/test03.ml new file mode 100644 index 0000000..064f627 --- /dev/null +++ b/test/test03.ml @@ -0,0 +1,63 @@ +type ('var, 'binder) term = + | TVar of 'var + | TAbs of 'binder * ('var, 'binder) term + | TApp of ('var, 'binder) term * ('var, 'binder) term +[@@deriving + visitors { variety = "iter" }, + visitors { variety = "map" }, + visitors { variety = "reduce" }, + visitors { variety = "endo" }, + visitors { variety = "iter2" }, + visitors { variety = "map2" }, + visitors { variety = "reduce2" } +] + +(* Nominal. *) + +module StringSet = Set.Make(String) + +let iter = object(self) + inherit [_] iter + (* Descending methods for local types. *) + method! visit_TAbs env x t = + let env = StringSet.add x env in + self#visit_term env t + (* Descending methods for nonlocal types. *) + method visit_'binder _env _x = () + method visit_'var env x = + if StringSet.mem x env then + Printf.printf "%s is a bound variable.\n%!" x + else + Printf.printf "%s is a free variable.\n%!" x + +end + +let t : (_, _) term = + TAbs ("x", TApp (TVar "x", TVar "y")) + +let () = + iter#visit_term StringSet.empty t + +(* De Bruijn. *) + +let iter = object(self) + inherit [_] iter + (* Descending methods for local types. *) + method! visit_TAbs env _x t = + let env = 1 + env in + self#visit_term env t + (* Descending methods for nonlocal types. *) + method visit_'binder _env _x = () + method visit_'var env x = + if x < env then + Printf.printf "%d is a bound variable.\n%!" x + else + Printf.printf "%d is a free variable.\n%!" x + +end + +let t : (_, _) term = + TAbs ((), TApp (TVar 0, TVar 1)) + +let () = + iter#visit_term 0 t diff --git a/test/test04.ml b/test/test04.ml new file mode 100644 index 0000000..9f64099 --- /dev/null +++ b/test/test04.ml @@ -0,0 +1,16 @@ +type 'info expr_node = + | EConst of int + | EAdd of 'info expr * 'info expr + +and 'info expr = + { info: 'info; node: 'info expr_node } + +[@@deriving visitors { variety = "iter"; polymorphic = true }, + visitors { variety = "map"; polymorphic = true }, + visitors { variety = "endo"; polymorphic = true }, + visitors { variety = "reduce"; polymorphic = true }, + visitors { variety = "mapreduce"; polymorphic = true }, + visitors { variety = "iter2"; polymorphic = true }, + visitors { variety = "map2"; polymorphic = true }, + visitors { variety = "reduce2"; polymorphic = true }, + visitors { variety = "mapreduce2"; polymorphic = true }] diff --git a/test/test05.ml b/test/test05.ml new file mode 100644 index 0000000..baf60ae --- /dev/null +++ b/test/test05.ml @@ -0,0 +1,16 @@ +(* Testing that @opaque is properly detected. *) + +module T = struct + type t = A of ((int -> int)[@deriving.visitors.opaque]) + [@@deriving visitors { variety = "map" }] +end + +module U = struct + type u = B of ((int -> int)[@visitors.opaque]) + [@@deriving visitors { variety = "map" }] +end + +module V = struct + type w = C of ((int -> int)[@opaque]) + [@@deriving visitors { variety = "map" }] +end diff --git a/test/test06.ml b/test/test06.ml new file mode 100644 index 0000000..21d4424 --- /dev/null +++ b/test/test06.ml @@ -0,0 +1,38 @@ +(* Testing @name attributes on data constructors. *) + +type foo = + | A [@name "TA"] + | B of int [@name "TB"] + | C of int * int [@name "TC"] +[@@deriving visitors { variety = "map"; concrete = true }, + visitors { variety = "fold"; ancestors = ["VisitorsRuntime.map"] }] + +let f (x : foo) = + let o = object + inherit [_] map + method! visit_TA _env = B 0 + method! visit_TB _env x = B (x + 1) + method! visit_TC _env x y = C (x, x + y) + end in + o # visit_foo () x + +let () = + assert (f A = B 0); + assert (f (B 0) = B 1); + assert (f (C (1, 1)) = C (1, 2)); + () + +let g (x : foo) : int = + let o = object + inherit [_] fold + method build_TA _env = 42 + method build_TB _env x = x + method build_TC _env x y = x + y + end in + o # visit_foo () x + +let () = + assert (g A = 42); + assert (g (B 12) = 12); + assert (g (C (1, 1)) = 2); + () diff --git a/test/test07.ml b/test/test07.ml new file mode 100644 index 0000000..5e9f109 --- /dev/null +++ b/test/test07.ml @@ -0,0 +1,49 @@ +(* Testing @name attributes on data types. *) + +(* Testing local types decorated with [@@name]. *) + +module Point = struct + + type point = { x : coordinate; y : coordinate } [@@name "foo"] + + and coordinate = float [@@name "coord"] + + [@@deriving visitors { variety = "map"; concrete = true }, + visitors { variety = "fold"; ancestors = ["VisitorsRuntime.map"]}] + + let f (p : point) = + let o = new map in + o # visit_foo () p + + let () = + assert (f { x = 0.; y = 0. } = { x = 0.; y = 0. }); + () + + let g (p : point) : float = + let o = object + inherit [_] fold + method build_coord _env x = x + method build_foo _env x y = x +. y + end in + o # visit_foo () p + + let () = + assert (g { x = 1.; y = 2. } = 3.); + () + +end + +type boolean = Vrai | Faux [@@name "condition"] +[@@deriving visitors { variety = "iter2"; concrete = true }] + +let () = + try + new iter2 # fail_condition () Vrai Faux; + assert false + with VisitorsRuntime.StructuralMismatch -> + () + +(* Testing nonlocal types decorated with [@name]. *) + +type segment = { source: Point.point[@name "foo"]; destination: Point.point[@name "foo"] } +[@@deriving visitors { variety = "map"; concrete = true; nude = true; ancestors = ["Point.map"] }] diff --git a/test/testallprims.ml b/test/testallprims.ml new file mode 100644 index 0000000..bc0b0de --- /dev/null +++ b/test/testallprims.ml @@ -0,0 +1,28 @@ +type t = + | Array of t array + | Bool of bool + | Bytes of bytes + | Char of char + | Float of float + | Int of int + | Int32 of int32 + | Int64 of int64 + | Lazy of t lazy_t + | List of t list + | Nativeint of nativeint + | Option of t option + | Ref of t ref + | Result of (t, t) result + | String of string + | Unit of unit + | Tuple2 of (t * t) + | Tuple3 of (t * t * t) +[@@deriving + visitors { variety = "iter"; concrete = true }, + visitors { variety = "map"; concrete = true }, + visitors { variety = "reduce"; ancestors=["VisitorsRuntime.addition_monoid"]; concrete = true }, + visitors { variety = "endo"; concrete = true }, + visitors { variety = "iter2"; concrete = true }, + visitors { variety = "map2"; concrete = true }, + visitors { variety = "reduce2"; ancestors=["VisitorsRuntime.addition_monoid"]; concrete = true } +] -- cgit v1.2.3 From 487317160ed7d57171543136d4837cf04fbd1d23 Mon Sep 17 00:00:00 2001 From: Ralf Treinen Date: Tue, 11 Feb 2020 20:54:22 +0100 Subject: Import ocaml-visitors_20200210-1.debian.tar.xz [dgit import tarball ocaml-visitors 20200210-1 ocaml-visitors_20200210-1.debian.tar.xz] --- changelog | 100 +++++++++++++++++++++++++++++++++++++ control | 40 +++++++++++++++ copyright | 57 +++++++++++++++++++++ gbp.conf | 2 + libppx-visitors-ocaml-doc.doc-base | 8 +++ libppx-visitors-ocaml-doc.docs | 1 + patches/series | 0 rules | 30 +++++++++++ source/format | 1 + tests/control | 2 + tests/weight | 22 ++++++++ tests/weight.ml | 27 ++++++++++ watch | 4 ++ 13 files changed, 294 insertions(+) create mode 100644 changelog create mode 100644 control create mode 100644 copyright create mode 100644 gbp.conf create mode 100644 libppx-visitors-ocaml-doc.doc-base create mode 100644 libppx-visitors-ocaml-doc.docs create mode 100644 patches/series create mode 100755 rules create mode 100644 source/format create mode 100644 tests/control create mode 100755 tests/weight create mode 100644 tests/weight.ml create mode 100644 watch diff --git a/changelog b/changelog new file mode 100644 index 0000000..dada9bd --- /dev/null +++ b/changelog @@ -0,0 +1,100 @@ +ocaml-visitors (20200210-1) unstable; urgency=medium + + * New upstream release + * Build-dependencies: + - bump version of ocaml-nox + - drop ocamlbuild and ocamlfind + - add dune + - add libppx-tools-ocaml-dev + - bump version of libppx-deriving-ocaml-dev + - add libresult-ocaml-dev + * debian/rules: use dune to build and install + * installation: update filename of the manual + * override dh_missing to use the --fail-missing option + * Standards-version 4.5.0 (no change) + * Fix addresses in Vcs-{Git,Browser} + * As-installed test: be more verbose + + -- Ralf Treinen Tue, 11 Feb 2020 20:54:22 +0100 + +ocaml-visitors (20190711-2) unstable; urgency=medium + + * Team upload + * Fix overrides in debian/rules + + -- Stéphane Glondu Thu, 12 Sep 2019 13:22:35 +0200 + +ocaml-visitors (20190711-1) unstable; urgency=medium + + * New upstream version. + * Standards-Version 4.4.0 (no change) + + -- Ralf Treinen Wed, 17 Jul 2019 22:52:52 +0200 + +ocaml-visitors (20180513-1) unstable; urgency=medium + + * New upstream version. This version allows projects using the -dev + package to build under dune. + * Build-depend on debhelper-compat (=12) + + -- Ralf Treinen Mon, 18 Feb 2019 20:38:44 +0100 + +ocaml-visitors (20180306-4) unstable; urgency=medium + + * Standards-Version 4.3.0 (no change) + * Debhelper compatibility level 12 (no change) + * -dev package Suggests ocaml-findlib since package has a META file + * Remove trailing white space in debian/{changelog,rules,control} + + -- Ralf Treinen Tue, 08 Jan 2019 21:26:16 +0100 + +ocaml-visitors (20180306-3) unstable; urgency=medium + + * autopkgtest: depends on ocamlbuild + * libppx-visitors-ocaml-dev: suggests -doc package. + + -- Ralf Treinen Wed, 11 Jul 2018 07:59:45 +0200 + +ocaml-visitors (20180306-2) unstable; urgency=medium + + * Vcs-{Browser,Git}: update to salsa. + * Standards-Version 4.1.5 (no change) + + -- Ralf Treinen Mon, 09 Jul 2018 21:07:17 +0200 + +ocaml-visitors (20180306-1) unstable; urgency=medium + + * New upstream version. + - dropped patch ocaml-4.05 since issue is solved upstream. + * Standards-Version 4.1.3: + - d/copyright: use https in format specifier + * debhelper compatibility level 11: + - fixed file location in libppx-visitors-ocaml-doc.doc-base since + dh_installdocs now installs into the /usr/share/doc of the main + package. + * Add minimal version of build-dependency libppx-deriving-ocaml-dev. + + -- Ralf Treinen Wed, 21 Mar 2018 20:43:06 +0100 + +ocaml-visitors (20170725-2) unstable; urgency=medium + + * Patch ocaml-4.05: migrate to ocaml 4.05, patch picked from upstream git + (closes: #880063) + * Standards-Version 4.1.1: + - replace Priority extra by optional. + + -- Ralf Treinen Mon, 30 Oct 2017 20:22:58 +0100 + +ocaml-visitors (20170725-1) unstable; urgency=medium + + * New upstream release. This release fixes compilation on bytecode + architectures (closes: #869207) + * Added build-dependency on ocamlbuild. + + -- Ralf Treinen Fri, 28 Jul 2017 22:32:00 +0200 + +ocaml-visitors (20170404-1) unstable; urgency=medium + + * Initial upload (closes: #862775) + + -- Ralf Treinen Thu, 06 Jul 2017 12:52:24 +0200 diff --git a/control b/control new file mode 100644 index 0000000..3911316 --- /dev/null +++ b/control @@ -0,0 +1,40 @@ +Source: ocaml-visitors +Section: ocaml +Priority: optional +Maintainer: Debian OCaml Maintainers +Uploaders: Ralf Treinen , +Build-Depends: debhelper-compat (= 12), + dh-ocaml (>= 0.9~), + ocaml-nox (>= 4.02.3), + cppo, + libppx-tools-ocaml-dev, + libppx-deriving-ocaml-dev (>= 4.4), + ocaml-dune (>= 2.0) +Build-Depends-Indep: texlive-latex-base, latexmk, + lmodern, texlive-fonts-recommended, texlive-latex-extra, + ocp-indent +Standards-Version: 4.5.0 +Homepage: https://gitlab.inria.fr/fpottier/visitors +Vcs-Browser: https://salsa.debian.org:ocaml-team/ocaml-visitors +Vcs-Git: https://salsa.debian.org:ocaml-team/ocaml-visitors.git + +Package: libppx-visitors-ocaml-dev +Architecture: any +Depends: ${misc:Depends}, ${ocaml:Depends}, ${shlibs:Depends} +Provides: ${ocaml:Provides} +Suggests: libppx-visitors-ocaml-doc, ocaml-findlib +Description: OCaml syntax extension for object-oriented visitors + Visitors is a syntax extension for the OCaml programming language. It + allows you to annotate your type definitions, such that a visitor class + will be automatically generated. This visitor class contains methods + for the traversal of your data structure, like iter, map, fold, etc. It + is then easy to override these methods for your needs. This is very + convenient when programming with complex algebraic data structures. + +Package: libppx-visitors-ocaml-doc +Section: doc +Architecture: all +Depends: ${misc:Depends} +Description: Documentation of the visitors syntax extension for OCaml + This package contains the documentation of the visitors syntax extension + for the OCaml programming language. diff --git a/copyright b/copyright new file mode 100644 index 0000000..fa1ca82 --- /dev/null +++ b/copyright @@ -0,0 +1,57 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: visitors +Upstream-Contact: François Pottier +Source: https://gitlab.inria.fr/fpottier/visitors.git + +Files: * +Copyright: © 2016, 2017 INRIA +License: LGPL-2.1 +Comment: + the copyright holder has been confirmed in a personal mail by the author. + +Files: debian/* +Copyright: © 2017 Ralf Treinen +License: LGPL-2.1 + +Files: test/cil_types.ml test/cil_types.ml.orig test/cil_types_polymorphic.ml +Copyright: (C) 2001-2003 + George C. Necula + Scott McPeak + Wes Weimer + Ben Liblit +License: BSD-3-clause + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + . + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + . + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + . + 3. The names of the contributors may not be used to endorse or + promote products derived from this software without specific prior + written permission. + . + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +License: LGPL-2.1 + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License version 2.1 as published by the Free Software Foundation. + . + On Debian systems, the complete text of the latest GNU Lesser General + Public License can be found in `/usr/share/common-licenses/LGPL-2.1'. diff --git a/gbp.conf b/gbp.conf new file mode 100644 index 0000000..cec628c --- /dev/null +++ b/gbp.conf @@ -0,0 +1,2 @@ +[DEFAULT] +pristine-tar = True diff --git a/libppx-visitors-ocaml-doc.doc-base b/libppx-visitors-ocaml-doc.doc-base new file mode 100644 index 0000000..1931a08 --- /dev/null +++ b/libppx-visitors-ocaml-doc.doc-base @@ -0,0 +1,8 @@ +Document: visitors-documentation +Title: Visitors +Author: François Pottier +Abstract: This document describes how to use the visitors syntax extension for OCaml +Section: Programming/OCaml + +Format: PDF +Files: /usr/share/doc/libppx-visitors-ocaml-dev/manual.pdf.gz diff --git a/libppx-visitors-ocaml-doc.docs b/libppx-visitors-ocaml-doc.docs new file mode 100644 index 0000000..56a14e1 --- /dev/null +++ b/libppx-visitors-ocaml-doc.docs @@ -0,0 +1 @@ +doc/manual.pdf diff --git a/patches/series b/patches/series new file mode 100644 index 0000000..e69de29 diff --git a/rules b/rules new file mode 100755 index 0000000..a914b3d --- /dev/null +++ b/rules @@ -0,0 +1,30 @@ +#!/usr/bin/make -f + +DESTDIR = $(CURDIR)/debian/libppx-visitors-ocaml-dev/ + +%: + dh $@ --with ocaml + +override_dh_auto_build-arch: + dune build @install + +override_dh_auto_build-indep: + cd doc && $(MAKE) + +override_dh_auto_install: + # do nothing + +override_dh_install-arch: + mkdir -p $(DESTDIR) + DESTDIR=$(DESTDIR) dune install + # all useful docs are directly installed into the -doc package + rm -r $(DESTDIR)/usr/doc + +override_dh_install-indep: + dh_installdocs -i + +override_dh_auto_test: + # do nothing + +override_dh_missing: + dh_missing --fail-missing diff --git a/source/format b/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/tests/control b/tests/control new file mode 100644 index 0000000..dceeccc --- /dev/null +++ b/tests/control @@ -0,0 +1,2 @@ +Tests: weight +Depends: @, ocaml-nox, libfindlib-ocaml, ocamlbuild diff --git a/tests/weight b/tests/weight new file mode 100755 index 0000000..b5b614b --- /dev/null +++ b/tests/weight @@ -0,0 +1,22 @@ +#!/bin/sh -e + +this=weight +indir=debian/tests +outdir=${ADT_ARTIFACTS:-/tmp}/${this} +mkdir -p ${outdir} + +ppx='visitors.ppx,visitors.runtime' +cp ${indir}/${this}.ml ${outdir} +cd ${outdir} +echo "* Compile to bytecode." +ocamlbuild -use-ocamlfind -pkgs ${ppx} weight.byte +echo "* Run bytecode" +[ $(./weight.byte) -eq '16' ] + +if [ -x /usr/bin/ocamlopt ] +then + echo "* Compile to native code" + ocamlbuild -use-ocamlfind -pkgs ${ppx} weight.native; + echo "* Run native code" + [ $(./weight.native) -eq '16' ] +fi diff --git a/tests/weight.ml b/tests/weight.ml new file mode 100644 index 0000000..33eb9b1 --- /dev/null +++ b/tests/weight.ml @@ -0,0 +1,27 @@ +type expr = + | EConst of int + | EAdd of expr * expr + [@@deriving visitors { variety = "iter" }] + +let weight (e : expr) : int = +(* return the weight of an expr, where the weight of constants is its *) +(* value, and additions have weight 5. *) + let v = object + val mutable weight = 0 + method weight = weight + inherit [_] iter as super + method! visit_EAdd env e0 e1 = + weight <- weight + 5; + super#visit_EAdd env e0 e1 + method! visit_EConst env i = + weight <- weight + i; + super#visit_EConst env i + end in + v#visit_expr () e; + v#weight +;; + +let c = EConst 2 in + let e = EAdd(c,EAdd(c,c)) in + print_int (weight e) +;; diff --git a/watch b/watch new file mode 100644 index 0000000..581a47b --- /dev/null +++ b/watch @@ -0,0 +1,4 @@ +version=4 +opts="mode=git, pgpmode=none" \ + https://gitlab.inria.fr/fpottier/visitors.git \ + refs/tags/([\d]+) -- cgit v1.2.3 From 8fc16842102d02556ab98f168c9b7bf28aebb271 Mon Sep 17 00:00:00 2001 From: Ralf Treinen Date: Tue, 11 Feb 2020 20:54:22 +0100 Subject: Import ocaml-visitors_20200210.orig.tar.xz [dgit import orig ocaml-visitors_20200210.orig.tar.xz] --- .gitignore | 5 + AUTHORS | 3 + CHANGES.md | 109 + LICENSE | 502 + Makefile.preprocess | 45 + README.md | 26 + doc/.gitignore | 26 + doc/Makefile | 25 + doc/OOinfererror.ml | 6 + doc/OOinfererroragain.ml | 6 + doc/convention.tex | 49 + doc/dune | 1 + doc/dune.manual | 14 + doc/english.bib | 15090 +++++++++++++++++++++++++++++++ doc/from-visitors-to-iterators.md | 493 + doc/listings-ocaml.tex | 24 + doc/local.bib | 23 + doc/macros.tex | 126 + doc/manual.pdf | Bin 0 -> 304695 bytes doc/manual.tex | 2401 +++++ doc/plain.bst | 1106 +++ doc/types.tex | 38 + doc/version.tex | 1 + dune | 5 + dune-project | 12 + runtime/Makefile | 3 + runtime/VisitorsRuntime.ml | 1139 +++ runtime/dune | 7 + src/Makefile | 3 + src/Visitors.ml | 1287 +++ src/Visitors.mli | 1 + src/VisitorsAnalysis.ml | 387 + src/VisitorsCompatibility.cppo.ml | 171 + src/VisitorsGeneration.ml | 586 ++ src/VisitorsList.ml | 125 + src/VisitorsPlugin.ml | 4 + src/VisitorsSettings.ml | 370 + src/VisitorsString.ml | 70 + src/dune | 27 + test/Makefile | 3 + test/OOinfer.ml | 5 + test/OOinferfixed.ml | 6 + test/OOinferfixedagain.ml | 6 + test/OOinferfixedagaincheck.ml | 6 + test/OOinferself.ml | 6 + test/OOinfervirtual.ml | 6 + test/VisitorsRuntimeBootstrap.cppo.ml | 30 + test/attic/expr07.ml | 23 + 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/bench.ml | 136 + test/build.ml | 10 + test/cil_types.ml | 1811 ++++ test/cil_types.ml.orig | 1775 ++++ test/cil_types_polymorphic.ml | 1780 ++++ test/cloud.cppo.ml | 22 + test/delayed_tree.ml | 435 + test/dictionary.ml | 14 + test/dune | 126 + test/expr.ml | 3 + test/expr00.ml | 4 + test/expr00.mli | 9 + test/expr00endo.ml | 4 + test/expr00fold.ml | 4 + test/expr00fold2.ml | 4 + test/expr01.ml | 4 + test/expr01use.ml | 25 + test/expr01use_variant.ml | 20 + test/expr02.ml | 4 + test/expr03.ml | 4 + test/expr04.ml | 13 + test/expr05.ml | 4 + test/expr05lexico.ml | 20 + test/expr05lexico_test.ml | 11 + test/expr06.ml | 16 + test/expr08.ml | 18 + test/expr08double.ml | 10 + test/expr08extra.ml | 15 + test/expr11.ml | 4 + test/expr12.ml | 4 + test/expr13.ml | 10 + test/expr13double.ml | 10 + test/expr13extra.ml | 26 + test/expr14.ml | 20 + test/expr15.ml | 4 + test/expr15b.ml | 10 + test/expr15c.ml | 5 + test/expr16.ml | 4 + test/expr17.ml | 4 + test/expr_import.ml | 3 + test/expr_import_opaque.ml | 3 + test/expr_info.ml | 8 + test/expr_info_mapreduce.ml | 8 + test/expr_info_mapreduce_test.ml | 29 + test/expr_info_mapreduce_use.ml | 15 + test/expr_info_polymorphic.ml | 9 + test/expr_info_polymorphic_use.ml | 15 + test/expr_info_polymorphic_use_test.ml | 27 + test/expr_info_use.ml | 17 + test/expr_redef.ml | 4 + test/fold.ml | 18 + test/hexpr_polymorphic.ml | 52 + test/mapReduce.ml | 9 + test/map_from_fold.ml | 37 + test/map_from_fold.mli | 6 + test/monomorphic.ml | 11 + test/monopoly.ml | 18 + test/oexpr_polymorphic.ml | 21 + test/opaque.ml | 21 + test/point.ml | 4 + test/point.mli | 2 + test/polyclass.ml | 8 + test/prefixes.ml | 23 + test/test00.ml | 11 + test/test01.ml | 11 + test/test02.cppo.ml | 33 + test/test03.ml | 63 + test/test04.ml | 16 + test/test05.ml | 16 + test/test06.ml | 38 + test/test07.ml | 49 + test/testallprims.cppo.ml | 30 + visitors.opam | 24 + 128 files changed, 31602 insertions(+) create mode 100644 .gitignore create mode 100644 AUTHORS create mode 100644 CHANGES.md create mode 100644 LICENSE create mode 100644 Makefile.preprocess create mode 100644 README.md create mode 100644 doc/.gitignore create mode 100644 doc/Makefile create mode 100644 doc/OOinfererror.ml create mode 100644 doc/OOinfererroragain.ml create mode 100644 doc/convention.tex create mode 100644 doc/dune create mode 100644 doc/dune.manual create mode 100644 doc/english.bib create mode 100644 doc/from-visitors-to-iterators.md create mode 100644 doc/listings-ocaml.tex create mode 100644 doc/local.bib create mode 100644 doc/macros.tex create mode 100644 doc/manual.pdf create mode 100644 doc/manual.tex create mode 100644 doc/plain.bst create mode 100644 doc/types.tex create mode 100644 doc/version.tex create mode 100644 dune create mode 100644 dune-project create mode 100644 runtime/Makefile create mode 100644 runtime/VisitorsRuntime.ml create mode 100644 runtime/dune create mode 100644 src/Makefile create mode 100644 src/Visitors.ml create mode 100644 src/Visitors.mli create mode 100644 src/VisitorsAnalysis.ml create mode 100644 src/VisitorsCompatibility.cppo.ml create mode 100644 src/VisitorsGeneration.ml create mode 100644 src/VisitorsList.ml create mode 100644 src/VisitorsPlugin.ml create mode 100644 src/VisitorsSettings.ml create mode 100644 src/VisitorsString.ml create mode 100644 src/dune create mode 100644 test/Makefile create mode 100644 test/OOinfer.ml create mode 100644 test/OOinferfixed.ml create mode 100644 test/OOinferfixedagain.ml create mode 100644 test/OOinferfixedagaincheck.ml create mode 100644 test/OOinferself.ml create mode 100644 test/OOinfervirtual.ml create mode 100644 test/VisitorsRuntimeBootstrap.cppo.ml create mode 100644 test/attic/expr07.ml create mode 100644 test/bad/Makefile create mode 100644 test/bad/conflict.ml create mode 100644 test/bad/conflict_at_name.ml create mode 100644 test/bad/conflict_atat_name.ml create mode 100644 test/bad/datacon.ml create mode 100644 test/bad/datacon_at_name.ml create mode 100644 test/bad/visitors.t create mode 100644 test/bench.ml create mode 100644 test/build.ml create mode 100644 test/cil_types.ml create mode 100644 test/cil_types.ml.orig create mode 100644 test/cil_types_polymorphic.ml create mode 100644 test/cloud.cppo.ml create mode 100644 test/delayed_tree.ml create mode 100644 test/dictionary.ml create mode 100644 test/dune create mode 100644 test/expr.ml create mode 100644 test/expr00.ml create mode 100644 test/expr00.mli create mode 100644 test/expr00endo.ml create mode 100644 test/expr00fold.ml create mode 100644 test/expr00fold2.ml create mode 100644 test/expr01.ml create mode 100644 test/expr01use.ml create mode 100644 test/expr01use_variant.ml create mode 100644 test/expr02.ml create mode 100644 test/expr03.ml create mode 100644 test/expr04.ml create mode 100644 test/expr05.ml create mode 100644 test/expr05lexico.ml create mode 100644 test/expr05lexico_test.ml create mode 100644 test/expr06.ml create mode 100644 test/expr08.ml create mode 100644 test/expr08double.ml create mode 100644 test/expr08extra.ml create mode 100644 test/expr11.ml create mode 100644 test/expr12.ml create mode 100644 test/expr13.ml create mode 100644 test/expr13double.ml create mode 100644 test/expr13extra.ml create mode 100644 test/expr14.ml create mode 100644 test/expr15.ml create mode 100644 test/expr15b.ml create mode 100644 test/expr15c.ml create mode 100644 test/expr16.ml create mode 100644 test/expr17.ml create mode 100644 test/expr_import.ml create mode 100644 test/expr_import_opaque.ml create mode 100644 test/expr_info.ml create mode 100644 test/expr_info_mapreduce.ml create mode 100644 test/expr_info_mapreduce_test.ml create mode 100644 test/expr_info_mapreduce_use.ml create mode 100644 test/expr_info_polymorphic.ml create mode 100644 test/expr_info_polymorphic_use.ml create mode 100644 test/expr_info_polymorphic_use_test.ml create mode 100644 test/expr_info_use.ml create mode 100644 test/expr_redef.ml create mode 100644 test/fold.ml create mode 100644 test/hexpr_polymorphic.ml create mode 100644 test/mapReduce.ml create mode 100644 test/map_from_fold.ml create mode 100644 test/map_from_fold.mli create mode 100644 test/monomorphic.ml create mode 100644 test/monopoly.ml create mode 100644 test/oexpr_polymorphic.ml create mode 100644 test/opaque.ml create mode 100644 test/point.ml create mode 100644 test/point.mli create mode 100644 test/polyclass.ml create mode 100644 test/prefixes.ml create mode 100644 test/test00.ml create mode 100644 test/test01.ml create mode 100644 test/test02.cppo.ml create mode 100644 test/test03.ml create mode 100644 test/test04.ml create mode 100644 test/test05.ml create mode 100644 test/test06.ml create mode 100644 test/test07.ml create mode 100644 test/testallprims.cppo.ml create mode 100644 visitors.opam diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0ecfada --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*~ +_build +.merlin +test/*.processed.ml +doc/manual.pdf diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..dd8061e --- /dev/null +++ b/AUTHORS @@ -0,0 +1,3 @@ +François Pottier +Inria Paris +francois.pottier@inria.fr diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 0000000..5261d49 --- /dev/null +++ b/CHANGES.md @@ -0,0 +1,109 @@ +# Changes + +## 2020/02/07 + +* Avoid references to `Pervasives` in the generated code. + +* Switch from `ocamlbuild` to `dune` to compile `visitors`. + +## 2018/05/13 + +* Fixes in `_tags` and `META` so as to allow `visitors` + to be used in `jbuilder` (`dune`) projects. + (Contributed by Armaël Guéneau.) + +## 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 + missing. (Suggested by Ralf Treinen.) + +## 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.`. + +## 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. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..4362b49 --- /dev/null +++ b/LICENSE @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/Makefile.preprocess b/Makefile.preprocess new file mode 100644 index 0000000..06a238f --- /dev/null +++ b/Makefile.preprocess @@ -0,0 +1,45 @@ +# This Makefile allows running visitors as a preprocessor, +# so as to inspect the generated code and possibly include +# it in a TeX document. + +# This assumes the visitors package is installed. + +# The rewriting command. +PPX := `ocamlfind query ppx_deriving`/ppx_deriving \ + `ocamlfind query visitors`/ppx/ppx_deriving_visitors.cma +REWRITE := ocamlfind ppx_tools/rewriter -ppx '$(PPX)' + +# Use GNU sed to extract the generated code. +# This requires GNU sed 3.95 or above, I am told. +SED := $(shell if command -v gsed >/dev/null ; then echo gsed ; else echo sed ; fi) +EXTRACT := $(SED) -e '/VISITORS.BEGIN/,/VISITORS.END/!d;//d' + +# Fix some deficiencies of OCaml's code printer. +# -- Force a space after a comma. +# -- Force a space after an ordinary letter and before [=]. +# -- Replace multiple consecutive spaces with a single space. +# This destroys indentation; we restore it afterwards. +# -- Remove a space before a comma or closing parenthesis. +# -- Force a line break after [in], unless there is one already. +# -- Force a line break after [| ... ->] on a line by itself, unless there is one already. +# -- Force a line break after [method ... =], unless there is one already. +# -- Remove the line break between [=] and [object]. +# -- Replace [fun x y -> fun ] with [fun x y ], so multiple-argument functions are prettier. +# Do this twice, so we can handle functions of arity up to 3. (Yes, this is very ad hoc.) +BEAUTIFY := \ + | $(SED) -e 's/,/, /g' \ + | $(SED) -e 's/\([a-zA-Z_)]\)=/\1 =/g' \ + | $(SED) -e 's/ / /g' \ + | $(SED) -e 's/ \([,)]\)/\1/g' \ + | $(SED) -e 's/ in / in\n/g' \ + | $(SED) -e 's/^\( *|.* ->\) /\1\n/g' \ + | $(SED) -e 's/\(method[^=]*=\) /\1\n/g' \ + | perl -0777 -pe 's/=\n *object/= object/gs' \ + | perl -0777 -pe "s/fun ([a-zA-Z0-9_' ]+) ->\n *fun /fun \1 /gs" \ + | perl -0777 -pe "s/fun ([a-zA-Z0-9_' ]+) ->\n *fun /fun \1 /gs" \ + +# Use ocp-indent to beautify the generated code. +INDENT := ocp-indent --config=JaneStreet,match_clause=4 + +%.processed.ml: %.ml + $(REWRITE) $< | $(EXTRACT) $(BEAUTIFY) | $(INDENT) > $@ diff --git a/README.md b/README.md new file mode 100644 index 0000000..0fa8da4 --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +An OCaml syntax extension (technically, a ppx_deriving plugin) which generates +object-oriented visitors for traversing and transforming data structures. + +Here is the [documentation of the latest released version](http://gallium.inria.fr/~fpottier/visitors/manual.pdf). + +The easiest way of installing the latest released version of this package is +via `opam`, the OCaml package manager. +```bash +opam update +opam install visitors +``` + +To install the latest development version, also via `opam`, please proceed as follows: +```bash + git clone https://gitlab.inria.fr/fpottier/visitors.git + cd visitors + make pin +``` + +To install the latest development version, outside of `opam`, please proceed as follows: +```bash + git clone https://gitlab.inria.fr/fpottier/visitors.git + cd visitors + opam install . --deps-only + make install +``` diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 0000000..63bf318 --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1,26 @@ +# TeX. +main.pdf +talk.pdf +*.aux +*.aux.bak +*.bbl +*.blg +*.log +*.out +*.nav +*.snm +*.toc +*.vrb + +# WhizzyTeX. +._whizzy* +_whizzy* +*.raux +*.wdvi +*.dvi +*.waux +*.fmt + +# latexmk +*.fdb_latexmk +*.fls diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000..2fc8e37 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,25 @@ +export VISITORS_BUILDING_DOCUMENTATION=true + +include ../Makefile.preprocess + +export TEXINPUTS=.:../test: + +.PHONY: all loop clean + +all: manual.pdf + +SOURCES := $(wildcard *.tex) $(wildcard *.bib) $(wildcard *.sty) +ML := $(shell ls ../test/*.ml | grep -v cppo | grep -v processed) +PROCESSED := $(patsubst %.ml,%.processed.ml,$(ML)) + +%.pdf: %.tex $(SOURCES) $(ML) $(PROCESSED) + pdflatex $* + bibtex $* + pdflatex $* + pdflatex $* + +loop: $(SOURCES) $(ML) $(PROCESSED) + latexmk -pdf -pvc manual + +clean: + rm -f *.log *.aux *.bbl *.blg *.out *.toc *~ manual.pdf diff --git a/doc/OOinfererror.ml b/doc/OOinfererror.ml new file mode 100644 index 0000000..38d0d65 --- /dev/null +++ b/doc/OOinfererror.ml @@ -0,0 +1,6 @@ +class virtual int_cell = object (self) + val mutable x = 0 + method get = x + method set y = x <- self#check y + method virtual check: _ +end diff --git a/doc/OOinfererroragain.ml b/doc/OOinfererroragain.ml new file mode 100644 index 0000000..ff90009 --- /dev/null +++ b/doc/OOinfererroragain.ml @@ -0,0 +1,6 @@ +class virtual ['a] cell (init) = object (self) + val mutable x = init + method get = x + method set y = x <- self#check y + method virtual check: 'a -> _ +end diff --git a/doc/convention.tex b/doc/convention.tex new file mode 100644 index 0000000..a01c0f3 --- /dev/null +++ b/doc/convention.tex @@ -0,0 +1,49 @@ +\begin{figure}[p] +\begin{mdframed}[backgroundcolor=green!10] +\begin{lstlisting} +class ['self] iter : object ('self) + method private visit_list: 'env 'a . + ('env -> 'a -> unit) -> 'env -> 'a list -> unit +end +class ['self] map : object ('self) + method private visit_list: 'env 'a 'b . + ('env -> 'a -> 'b) -> 'env -> 'a list -> 'b list +end +class ['self] endo : object ('self) + method private visit_list: 'env 'a . + ('env -> 'a -> 'a) -> 'env -> 'a list -> 'a list +end +class virtual ['self] reduce : object ('self) + inherit ['s] monoid + method private visit_list: 'env 'a . + ('env -> 'a -> 's) -> 'env -> 'a list -> 's +end +class virtual ['self] mapreduce : object ('self) + inherit ['s] monoid + method private visit_list: 'env 'a 'b . + ('env -> 'a -> 'b * 's) -> 'env -> 'a list -> 'b list * 's +end +class ['self] iter2 : object ('self) + method private visit_list: 'env 'a 'b . + ('env -> 'a -> 'b -> unit) -> 'env -> 'a list -> 'b list -> unit +end +class ['self] map2 : object ('self) + method private visit_list: 'env 'a 'b 'c . + ('env -> 'a -> 'b -> 'c) -> 'env -> 'a list -> 'b list -> 'c list +end +class virtual ['self] reduce2 : object ('self) + inherit ['s] monoid + method private visit_list: 'env 'a 'b . + ('env -> 'a -> 'b -> 's) -> 'env -> 'a list -> 'b list -> 's +end +class virtual ['self] mapreduce2 : object ('self) + inherit ['s] monoid + method private visit_list: 'env 'a 'b 'c . + ('env -> 'a -> 'b -> 'c * 's) -> + 'env -> 'a list -> 'b list -> 'c list * 's +end +\end{lstlisting} +\end{mdframed} +\caption{Conventional types of polymorphic visitor methods} +\label{fig:convention} +\end{figure} diff --git a/doc/dune b/doc/dune new file mode 100644 index 0000000..a62d561 --- /dev/null +++ b/doc/dune @@ -0,0 +1 @@ +(include dune.manual) diff --git a/doc/dune.manual b/doc/dune.manual new file mode 100644 index 0000000..b52ddb9 --- /dev/null +++ b/doc/dune.manual @@ -0,0 +1,14 @@ +;; This file is concatenated at the end of the file "dune" +;; by the release script, so the documentation is installed +;; only on release branches. + +;; The documentation is currently built outside of dune's control +;; by doc/Makefile. + +(install + (section doc) + (files + manual.pdf + ) + (package visitors) +) diff --git a/doc/english.bib b/doc/english.bib new file mode 100644 index 0000000..1d5f136 --- /dev/null +++ b/doc/english.bib @@ -0,0 +1,15090 @@ +@String{acmp = "ACM Press"} + +@String{acsac = "Annual Computer Security Applications Conference"} + +@String{acta = "Acta Informatica"} + +@String{afp = "Advanced Functional Programming"} + +@String{amast = "International Conference on Algebraic Methodology and + Software Technology (AMAST)"} + +@String{ams = "American Mathematical Society"} + +@String{ap = "Academic Press"} + +@String{apal = "Annals of Pure and Applied Logic"} + +@String{aplas = "Asian Symposium on Programming Languages and Systems + (APLAS)"} + +@String{asian = "Asian Computer Science Conference ({ASIAN})"} + +@String{aw = "Addison-Wesley"} + +@String{cacm = "Communications of the {ACM}"} + +@String{cade = "International Conference on Automated Deduction + (CADE)"} + +@String{carleton = "Carleton Scientific"} + +@String{cassis = "Construction and Analysis of Safe, Secure and + Interoperable Smart devices (CASSIS)"} + +@String{cav = "Computer Aided Verification (CAV)"} + +@String{cc = "Compiler Construction (CC)"} + +@String{cdcs = "International Conference on Distributed Computing + Systems (CDCS)"} + +@String{cj = "Computer Journal"} + +@String{computer = "Computer"} + +@String{concur = "International Conference on Concurrency Theory + (CONCUR)"} + +@String{cpp = "Certified Programs and Proofs (CPP)"} + +@String{csfw = "{IEEE} Computer Security Foundations Workshop"} + +@String{csl = "Computer Science Logic"} + +@String{cup = "Cambridge University Press"} + +@String{dac = "Design Automation Conference (DAC)"} + +@String{decsrc = "Digital Equipment Corporation, Systems Research + Center"} + +@String{dls = "Symposium on Dynamic Languages"} + +@String{dspg = "Domain-Specific Program Generation (DSPG)"} + +@String{ecoop = "European Conference on Object-Oriented Programming + (ECOOP)"} + +@String{ellis = "Ellis Horwood"} + +@String{elsevier = "Elsevier Science"} + +@String{entcs = "Electronic Notes in Theoretical Computer Science"} + +@String{esop = "European Symposium on Programming (ESOP)"} + +@String{esorics = "European Symposium on Research in Computer Security"} + +@String{eurosys = "EuroSys"} + +@String{fac = "Formal Aspects of Computing"} + +@String{fics = "International workshop on Fixed Points in Computer + Science (FICS)"} + +@String{flops = "Functional and Logic Programming"} + +@String{fm = "Formal Methods (FM)"} + +@String{fmco = "Formal Methods for Components and Objects"} + +@String{fmsd = "Formal Methods in System Design"} + +@String{fool = "Foundations of Object-Oriented Languages (FOOL)"} + +@String{fopara = "Foundational and Practical Aspects of Resource + Analysis"} + +@String{fosad = "Foundations of Security Analysis and Design"} + +@String{fossacs = "Foundations of Software Science and Computation + Structures ({FOSSACS})"} + +@String{fpca = "Functional Programming Languages and Computer + Architecture (FPCA)"} + +@String{fse = "Workshop on Foundations of Software Engineering"} + +@String{fsttcs = "Foundations of Software Technology and Theoretical + Computer Science (FSTTCS)"} + +@String{ftfjp = "Formal Techniques for {Java}-like Programs"} + +@String{fundamenta = "Fundamenta Informaticæ"} + +@String{gcse = "Generative and Component-Based Software Engineering"} + +@String{gpce = "Generative Programming and Component Engineering + (GPCE)"} + +@String{hav = "Heap Analysis and Verification (HAV)"} + +@String{hilt = "ACM SIGAda Annual Conference on High Integrity + Language Technology (HILT)"} + +@String{hlcl = "High-Level Concurrent Languages (HLCL)"} + +@String{hoots = "Higher Order Operational Techniques in Semantics + (HOOTS)"} + +@String{hopl = "History of Programming Languages"} + +@String{hosc = "Higher-Order and Symbolic Computation"} + +@String{hotpar = "USENIX Conference on Hot Topics in Parallelism + (HotPar)"} + +@String{hs = "Haskell symposium"} + +@String{hw = "Haskell workshop"} + +@String{ic = "Information and Computation"} + +@String{icalp = "International Colloquium on Automata, Languages and + Programming"} + +@String{icfem = "International Conference on Formal Engineering Methods + (ICFEM)"} + +@String{icfp = "International Conference on Functional Programming + (ICFP)"} + +@String{iclp = "International Conference on Logic Programming (ICLP)"} + +@String{icse = "International Conference on Software Engineering + ({ICSE})"} + +@String{ictl = "International Conference on Temporal Logic (ICTL)"} + +@String{ie = "InterEditions"} + +@String{ifiptcs = "IFIP International Conference on Theoretical Computer + Science (TCS)"} + +@String{ifl = "Implementation of Functional Languages (IFL)"} + +@String{ijcai = "International Joint Conferences on Artificial + Intelligence"} + +@String{ijfcs = "International Journal of Foundations of Computer + Science"} + +@String{ipl = "Information Processing Letters"} + +@String{issta = "International Symposium on Software Testing and + Analysis (ISSTA)"} + +@String{ist = "Information and Software Technology"} + +@String{ita = "Informatique théorique et applications"} + +@String{itp = "Interactive Theorem Proving (ITP)"} + +@String{itrs = "Workshop on Intersection Types and Related Systems + (ITRS)"} + +@String{jacm = "Journal of the {ACM}"} + +@String{jar = "Journal of Automated Reasoning"} + +@String{jfla = "Journées Françaises des Langages Applicatifs + (JFLA)"} + +@String{jfp = "Journal of Functional Programming"} + +@String{jfr = "Journal of Formalized Reasoning"} + +@String{jlap = "Journal of Logic and Algebraic Programming"} + +@String{jlc = "Journal of Logic and Computation"} + +@String{jlp = "Journal of Logic Programming"} + +@String{jot = "Journal of Object Technology"} + +@String{jsc = "Journal of Symbolic Computation"} + +@String{jucs = "Journal of Universal Computer Science"} + +@String{kluwer = "Kluwer"} + +@String{lfm = "Workshop on Logical Frameworks and Meta-Languages + (LFM)"} + +@String{lfp = "ACM Symposium on Lisp and Functional Programming + (LFP)"} + +@String{lics = "Logic in Computer Science (LICS)"} + +@String{lipics = "{Leibniz} International Proceedings in Informatics"} + +@String{lmcs = "Logical Methods in Computer Science"} + +@String{lnai = "Lecture Notes in Artificial Intelligence"} + +@String{lncs = "Lecture Notes in Computer Science"} + +@String{lola = "Workshop on Syntax and Semantics of Low Level + Languages"} + +@String{loplas = "ACM Letters on Programming Languages and Systems"} + +@String{lpar = "Logic for Programming Artificial Intelligence and + Reasoning (LPAR)"} + +@String{lsc = "Lisp and Symbolic Computation"} + +@String{merlin = "ACM Workshop on Mechanized Reasoning about Languages + with Variable Binding"} + +@String{mfcs = "International Symposium on Mathematical Foundations of + Computer Science"} + +@String{mfps = "Mathematical Foundations of Programming Semantics"} + +@String{mitp = "MIT Press"} + +@String{ml = "ACM Workshop on ML"} + +@String{mlapp = "ACM Workshop on ML and its Applications"} + +@String{mpc = "Mathematics of Program Construction (MPC)"} + +@String{mscs = "Mathematical Structures in Computer Science"} + +@String{msfp = "ACM SIGPLAN Workshop on Mathematically Structured + Functional Programming (MSFP)"} + +@String{ndss = "Internet Society Symposium on Network and Distributed + System Security"} + +@String{nfm = "{NASA} Formal Methods (NFM)"} + +@String{njc = "Nordic Journal of Computing"} + +@String{notices = "{ACM} {SIGPLAN} Notices"} + +@String{nspw = "New Security Paradigms Workshop"} + +@String{onward = "{ACM} Symposium on New Ideas in Programming and + Reflections on Software (Onward!)"} + +@String{oopsla = "Object-Oriented Programming, Systems, Languages, and + Applications (OOPSLA)"} + +@String{oopslacomp = "Companion to Object-Oriented Programming, Systems, + Languages, and Applications (OOPSLA)"} + +@String{padl = "Practical Aspects of Declarative Languages (PADL)"} + +@String{palgrave = "Palgrave Macmillan"} + +@String{pcc = "International Workshop on Proof-Carrying Code (PCC)"} + +@String{pepm = "{ACM} Workshop on Evaluation and Semantics-Based + Program Manipulation ({PEPM})"} + +@String{pi = "Proceedings in Informatics"} + +@String{pieee = "Proceedings of the IEEE"} + +@String{pldi = "{Programming Language Design and Implementation + (PLDI)}"} + +@String{plilp = "Programming Languages: Implementations, Logics, and + Programs (PLILP)"} + +@String{plpv = "Programming Languages Meets Program Verification + (PLPV)"} + +@String{popl = "Principles of Programming Languages ({POPL})"} + +@String{ppcp = "International Workshop on Principles and Practice of + Constraint Programming (PPCP)"} + +@String{ppdp = "Principles and Practice of Declarative Programming + (PPDP)"} + +@String{prentice = "Prentice Hall"} + +@String{rairo = "RAIRO Theoretical Informatics and Applications"} + +@String{rta = "Rewriting Techniques and Applications (RTA)"} + +@String{saig = "International Workshop on Semantics, Applications, and + Implementation of Program Generation (SAIG)"} + +@String{sas = "Static Analysis Symposium (SAS)"} + +@String{scp = "Science of Computer Programming"} + +@String{siamjc = "SIAM Journal on Computing"} + +@String{sigops = "ACM Operating Systems Review"} + +@String{sle = "Software Language Engineering"} + +@String{snapl = "Summit on Advances in Programming Languages (SNAPL)"} + +@String{soda = "Symposium on Discrete Algorithms (SODA)"} + +@String{sp = "{IEEE} Symposium on Security and Privacy (S\&P)"} + +@String{spe = "Software: Practice and Experience"} + +@String{springer = "Springer"} + +@String{stoc = "ACM Symposium on Theory of Computing"} + +@String{sttt = "Software Tools for Technology Transfer"} + +@String{surveys = "{ACM} Computing Surveys"} + +@String{tacas = "Tools and Algorithms for Construction and Analysis of + Systems (TACAS)"} + +@String{tacs = "International Symposium on Theoretical Aspects of + Computer Software (TACS)"} + +@String{tams = "Transactions of the American Mathematical Society"} + +@String{taoop = "Theoretical Aspects Of Object-Oriented Programming: + Types, Semantics and Language Design"} + +@String{tapos = "Theory and Practice of Object Systems"} + +@String{tapsoft = "Theory and Practice of Software Development + ({TAPSOFT})"} + +@String{tcs = "Theoretical Computer Science"} + +@String{tcsconf = "IFIP International Conference on Theoretical Computer + Science (TCS)"} + +@String{tfp = "Trends in Functional Programming (TFP)"} + +@String{tic = "Types in Compilation (TIC)"} + +@String{tissec = "ACM Transactions on Information and System Security"} + +@String{tlca = "Typed Lambda Calculi and Applications (TLCA)"} + +@String{tldi = "Types in Language Design and Implementation (TLDI)"} + +@String{tocl = "ACM Transactions on Computational Logic"} + +@String{tods = "ACM Transactions on Database Systems"} + +@String{toplas = "ACM Transactions on Programming Languages and + Systems"} + +@String{tose = "IEEE Transactions on Software Engineering"} + +@String{tosem = "ACM Transactions on Software Engineering and + Methodology"} + +@String{tphol = "Theorem Proving in Higher Order Logics (TPHOLs)"} + +@String{types = "Types for Proofs and Programs"} + +@String{vmcai = "Verification, Model Checking and Abstract + Interpretation (VMCAI)"} + +@String{vstte = "Verified Software: Theories, Tools and Experiments"} + +@String{wgp = "Workshop on Generic Programming"} + +@String{wollic = "Workshop on Logic, Language, Information and + Computation (WoLLIC)"} + +@String{wrla = "International Workshop on Rewriting Logic and its + Applications (WRLA)"} + +@String{wsa = "International Workshop on Static Analysis (WSA)"} + +@String{wwv = "Workshop on Automated Specification and Verification + of Web Systems"} + +@InProceedings{abadi-blanchet-01, + author = "Martín Abadi and Bruno Blanchet", + title = "Secrecy Types for Asymmetric Communication", + booktitle = fossacs, + year = "2001", + volume = "2030", + series = lncs, + publisher = springer, + pages = "25--41", + URL = "http://www.di.ens.fr/~blanchet/publications/AbadiBlanchetFOSSACS01.html", +} + +@Article{abadi-cardelli-94, + author = "Mart{\'\i}n Abadi and Luca Cardelli", + title = "A Theory of Primitive Objects: Untyped and First-Order + Systems", + journal = ic, + year = "1996", + volume = "125", + number = "2", + pages = "78--102", + URL = "http://research.microsoft.com/Users/luca/Papers/PrimObj1stOrder.pdf", +} + +@Article{abadi-cardelli-94b, + author = "Mart{\'\i}n Abadi and Luca Cardelli", + title = "A Theory of Primitive Objects: Second-Order Systems", + journal = scp, + year = "1995", + volume = "25", + number = "2--3", + pages = "81--116", + URL = "http://research.microsoft.com/Users/luca/Papers/PrimObj2ndOrder.pdf", +} + +@InProceedings{abadi-dcc-99, + title = "A Core Calculus of Dependency", + author = "Martín Abadi and Anindya Banerjee and Nevin Heintze + and Jon G. Riecke", + booktitle = popl, + year = "1999", + pages = "147--160", + URL = "http://www.soe.ucsc.edu/~abadi/Papers/flowpopl.ps", +} + +@InProceedings{abadi-fiore-96, + author = "Mart{\'\i}n Abadi and Marcelo P. Fiore", + title = "Syntactic Considerations on Recursive Types", + booktitle = lics, + pages = "242--252", + year = "1996", + URL = "http://www.soe.ucsc.edu/~abadi/Papers/rec.ps", +} + +@InProceedings{abadi-lampson-levy-96, + title = "Analysis and Caching of Dependencies", + author = "Martín Abadi and Butler Lampson and Jean-Jacques + Lévy", + pages = "83--91", + booktitle = icfp, + year = "1996", + URL = "http://www.soe.ucsc.edu/~abadi/Papers/make-preprint.ps", +} + +@Article{abadi-pierce-plotkin-91, + author = "Martín Abadi and Benjamin Pierce and Gordon Plotkin", + title = "Faithful Ideal Models for Recursive Polymorphic + Types", + journal = "International Journal of Foundations of Computer + Science", + volume = "2", + number = "1", + year = "1991", + pages = "1--21", + URL = "http://www.cis.upenn.edu/~bcpierce/papers/ideals.ps", +} + +@Article{abel-04, + author = "Andreas Abel", + title = "Termination Checking with Types", + journal = rairo, + year = "2004", + volume = "38", + number = "4", + pages = "277--319", + URL = "http://www2.tcs.ifi.lmu.de/~abel/rairo04.pdf", +} + +@InProceedings{abel-haskell-05, + author = "Andreas Abel and Marcin Benke and Ana Bove and John + Hughes and Ulf Norell", + title = "Verifying {Haskell} programs using constructive type + theory", + booktitle = hw, + year = "2005", + pages = "62--73", + URL = "http://www.tcs.informatik.uni-muenchen.de/~abel/haskell05.pdf", +} + +@InProceedings{abel-miniagda-10, + author = "Andreas Abel", + title = "{MiniAgda}: Integrating Sized and Dependent Types", + booktitle = "Workshop on Partiality And Recursion in Interactive + Theorem Provers (PAR)", + year = "2010", + URL = "http://www2.tcs.ifi.lmu.de/~abel/par10.pdf", +} + +@Article{abramsky-91, + author = "Samson Abramsky", + title = "Domain Theory in Logical Form", + journal = apal, + year = "1991", + volume = "51", + pages = "1--77", + URL = "http://web.comlab.ox.ac.uk/oucl/work/samson.abramsky/dtlf.ps.gz", +} + +@InProceedings{abramsky-honda-mccusker-98, + author = "Samson Abramsky and Kohei Honda and Guy McCusker", + title = "A fully abstract game semantics for general + references", + booktitle = lics, + pages = "334--344", + year = "1998", + URL = "http://web.comlab.ox.ac.uk/people/Samson.Abramsky/lics98.ps.gz", +} + +@Article{achten-plasmeijer-95, + author = "Peter Achten and Marinus J. Plasmeijer", + title = "The Ins and Outs of {Clean} {I/O}", + journal = jfp, + volume = "5", + number = "1", + year = "1995", + pages = "81--110", + URL = "http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.17.935", +} + +@TechReport{agerholm-examples-94, + author = "Sten Agerholm", + title = "{LCF} Examples in {HOL}", + institution = "BRICS", + year = "1994", + number = "RS-94-18", + URL = "http://www.brics.dk/RS/94/18/BRICS-RS-94-18.ps.gz", +} + +@TechReport{agerholm-holcpo-94, + author = "Sten Agerholm", + title = "A {HOL} Basis for Reasoning about Functional + Programs", + institution = "BRICS", + year = "1994", + number = "RS-94-44", + URL = "http://www.brics.dk/RS/94/44/BRICS-RS-94-44.ps.gz", +} + +@PhdThesis{ahmed-04, + author = "Amal Jamil Ahmed", + title = "Semantics of Types for Mutable State", + school = "Princeton University", + year = "2004", + URL = "http://www.cs.indiana.edu/~amal/ahmedsthesis.pdf", +} + +@InProceedings{ahmed-appel-virga-02, + author = "Amal J. Ahmed and Andrew W. Appel and Roberto Virga", + title = "A Stratified Semantics of General References + Embeddable in Higher-Order Logic", + booktitle = lics, + pages = "75--86", + year = "2002", + URL = "http://www.cs.princeton.edu/sip/pub/stratified-lics02.pdf", +} + +@InProceedings{ahmed-blume-08, + author = "Amal Ahmed and Matthias Blume", + title = "Typed closure conversion preserves observational + equivalence", + booktitle = icfp, + year = "2008", + pages = "157--168", + URL = "http://ttic.uchicago.edu/~amal/papers/tccpoe.pdf", +} + +@InProceedings{ahmed-dreyer-rossberg-09, + author = "Amal Ahmed and Derek Dreyer and Andreas Rossberg", + title = "State-dependent representation independence", + booktitle = popl, + year = "2009", + pages = "340--353", + URL = "http://ttic.uchicago.edu/~amal/papers/sdri.pdf", +} + +@InProceedings{ahmed-fluet-morrisett-05, + author = "Amal J. Ahmed and Matthew Fluet and Greg Morrisett", + title = "A step-indexed model of substructural state", + booktitle = icfp, + year = "2005", + pages = "78--91", + URL = "http://www.cs.rit.edu/~mtf/research/substruct-state/ICFP05/icfp05.pdf", +} + +@Article{ahmed-semantic-tal-10, + author = "Amal Ahmed and Andrew W. Appel and Christopher D. + Richards and Kedar N. Swadi and Gang Tan and Daniel C. + Wang", + title = "Semantic foundations for typed assembly languages", + journal = toplas, + volume = "32", + number = "3", + year = "2010", + URL = "http://www.cs.princeton.edu/~appel/papers/sftal.pdf", +} + +@Book{aho-86, + author = "Alfred V. Aho and Ravi Sethi and Jeffrey D. Ullman", + title = "Compilers: Principles, Techniques, and Tools", + publisher = aw, + year = "1986", +} + +@Book{aho-89, + author = "Alfred Aho and Ravi Sethi and Jeffrey Ullman", + title = "Compilateurs: principes, techniques et outils", + publisher = ie, + year = "1989", +} + +@Book{aho-hopcroft-ullman-74, + author = "Alfred V. Aho and John E. Hopcroft and Jeffrey D. + Ullman", + title = "The Design and Analysis of Computer Algorithms", + publisher = aw, + year = "1974", +} + +@Book{aho-hopcroft-ullman-83, + author = "Alfred V. Aho and John E. Hopcroft and Jeffrey D. + Ullman", + title = "Data Structures and Algorithms", + year = "1983", + publisher = aw, +} + +@Article{aho-optim-72, + author = "Alfred V. Aho and Jeffrey D. Ullman", + title = "Optimization of {LR(k)} parsers", + journal = "Journal of Computer and System Sciences", + volume = "6", + number = "6", + pages = "573--602", + year = "1972", + URL = "http://www.sciencedirect.com/science/article/pii/S002200007280031X", +} + +@Book{aho-ullman-72, + author = "Alfred V. Aho and Jeffrey D. Ullman", + title = "The theory of parsing, translation, and compiling", + year = "1972", + publisher = prentice, + URL = "http://portal.acm.org/citation.cfm?id=SERIES11430.578789", +} + +@Article{aho-ullman-73, + author = "Alfred V. Aho and Jeffrey D. Ullman", + title = "A Technique for Speeding up {LR(k)} Parsers", + journal = siamjc, + volume = "2", + number = "2", + pages = "106--127", + year = "1973", + URL = "http://dx.doi.org/10.1137/0202010", +} + +@Article{aiken-bane-98, + author = "Alexander Aiken and Manuel Fähndrich and Jeffrey S. + Foster and Zhendong Su", + title = "A Toolkit for Constructing Type- and Constraint-Based + Program Analyses", + journal = lncs, + volume = "1473", + pages = "76--96", + year = "1998", + URL = "http://theory.stanford.edu/~aiken/publications/papers/tic98.pdf", +} + +@Article{aiken-faehndrich-levien-95, + author = "Alexander Aiken and Manuel F{\"a}hndrich and Raph + Levien", + title = "Better static memory management: improving + region-based analysis of higher-order languages", + journal = notices, + volume = "30", + number = "6", + pages = "174--185", + year = "1995", + URL = "http://www.eecs.berkeley.edu/Pubs/TechRpts/1995/CSD-95-866.pdf", +} + +@InProceedings{aiken-faehndrich-mixed-97, + author = "Alexander S. Aiken and Manuel F{\"a}hndrich", + title = "Program Analysis Using Mixed Term and Set + Constraints", + pages = "114--126", + booktitle = sas, + year = "1997", + URL = "http://theory.stanford.edu/~aiken/publications/papers/sas97.pdf", +} + +@TechReport{aiken-faehndrich-scale-96, + number = "CSD-96-917", + institution = "University of California, Berkeley", + title = "Making Set-Constraint Based Program Analyses Scale", + year = "1996", + author = "Alexander S. Aiken and Manuel F{\"a}hndrich", + URL = "http://research.microsoft.com/pubs/67469/scw96.pdf", +} + +@TechReport{aiken-faehndrich-subtyping-96, + number = "CSD-96-898", + institution = "University of California, Berkeley", + title = "Subtyping Polymorphic Constrained Types", + year = "1996", + author = "Alexander S. Aiken and Manuel F{\"a}hndrich", +} + +@Misc{aiken-illyria, + author = "Alexander S. Aiken", + title = "The {Illyria} system", + year = "1994", + URL = "http://http.cs.berkeley.edu:80/~aiken/Illyria-demo.html", +} + +@Article{aiken-intro-99, + author = "Alexander Aiken", + title = "Introduction to Set Constraint-Based Program + Analysis", + journal = scp, + year = "1999", + volume = "35", + pages = "79--111", + URL = "http://theory.stanford.edu/~aiken/publications/papers/scp99.pdf", +} + +@TechReport{aiken-palsberg-wimmers-optimal-96, + number = "CSD-96-909", + institution = "University of California, Berkeley", + title = "Optimal Representations of Polymorphic Types with + Subtyping", + year = "1996", + pages = "31", + author = "Alexander S. Aiken and Edward L. Wimmers and Jens + Palsberg", + URL = "http://digitalassets.lib.berkeley.edu/techreports/ucb/text/CSD-96-909.pdf", +} + +@InProceedings{aiken-wimmers-92, + author = "Alexander S. Aiken and Edward L. Wimmers", + title = "Solving Systems of Set Constraints", + pages = "329--340", + booktitle = lics, + year = "1992", + URL = "http://theory.stanford.edu/~aiken/publications/papers/lics92.pdf", +} + +@InProceedings{aiken-wimmers-93, + author = "Alexander S. Aiken and Edward L. Wimmers", + booktitle = fpca, + publisher = acmp, + title = "Type Inclusion Constraints and Type Inference", + year = "1993", + pages = "31--41", + URL = "http://theory.stanford.edu/~aiken/publications/papers/fpca93.pdf", +} + +@InProceedings{aiken-wimmers-lakshman-94, + author = "Alexander S. Aiken and Edward L. Wimmers and T. K. + Lakshman", + booktitle = popl, + title = "Soft Typing with Conditional Types", + year = "1994", + pages = "163--173", + URL = "http://theory.stanford.edu/~aiken/publications/papers/popl94.pdf", +} + +@InProceedings{aldrich-borrowing-12, + title = "A type system for borrowing permissions", + author = "Karl Naden and Robert Bocchino and Jonathan Aldrich + and Kevin Bierhoff", + booktitle = popl, + year = "2012", + pages = "557--570", + URL = "http://cs.cmu.edu/afs/cs.cmu.edu/Web/People/kbn/pubs/poplBorrowing.pdf", +} + +@InProceedings{aldrich-objects-13, + author = "Jonathan Aldrich", + title = "The power of interoperability: why objects are + inevitable", + booktitle = onward, + year = "2013", + pages = "101--116", + URL = "http://www.cs.cmu.edu/~aldrich/papers/objects-essay.pdf", +} + +@Unpublished{aldrich-plaid-10, + author = "Jonathan Aldrich", + title = "Resource-Based Programming in {Plaid}", + note = "Fun Ideas and Thoughts", + year = "2010", + URL = "http://www.cs.cmu.edu/~aldrich/papers/pldi-fit10.pdf", +} + +@InProceedings{aldrich-typestate-09, + author = "Jonathan Aldrich and Joshua Sunshine and Darpan Saini + and {Zacha\-ry} Sparks", + title = "Typestate-Oriented Programming", + booktitle = oopslacomp, + pages = "1015--1022", + year = "2009", + URL = "http://www.cs.cmu.edu/~aldrich/papers/onward2009-state.pdf", +} + +@InProceedings{alias-types-00, + author = "Frederick Smith and David Walker and Greg Morrisett", + title = "Alias Types", + booktitle = esop, + pages = "366--381", + year = "2000", + volume = "1782", + series = lncs, + publisher = springer, + URL = "http://www.cs.cornell.edu/talc/papers/alias.pdf", +} + +@InProceedings{allais-cpp-17, + author = "Guillaume Allais and James Chapman and Conor McBride + and James McKinna", + title = "Type-and-scope Safe Programs and Their Proofs", + booktitle = cpp, + pages = "195--207", + year = "2017", + URL = "http://gallais.github.io/pdf/cpp2017.pdf", +} + +@InProceedings{almeida-97, + author = "Paulo S{\'e}rgio Almeida", + title = "Balloon Types: Controlling Sharing of State in Data + Types", + booktitle = ecoop, + year = "1997", + pages = "32--59", + publisher = springer, + series = lncs, + volume = "1241", + URL = "http://gsd.di.uminho.pt/publications/gsd-1997-04/file/at_download", +} + +@Article{alstrup-al-14, + author = "Stephen Alstrup and Mikkel Thorup and Inge Li G{\o}rtz + and Theis Rauhe and Uri Zwick", + title = "Union-Find with Constant Time Deletions", + journal = "{ACM} Transactions on Algorithms", + volume = "11", + number = "1", + pages = "6:1--6:28", + year = "2014", + URL = "http://doi.acm.org/10.1145/2636922", +} + +@InProceedings{altenkirch-pisigma-10, + author = "Thorsten Altenkirch and Nils Anders Danielsson and + Andres L{\"o}h and Nicolas Oury", + title = "{$\Pi$}{$\Sigma$}: Dependent Types Without the Sugar", + booktitle = flops, + pages = "40--55", + year = "2010", + publisher = springer, + series = lncs, + volume = "6009", + URL = "http://www.cs.nott.ac.uk/~txa/publ/pisigma-new.pdf", +} + +@InProceedings{altenkirch-reus-99, + author = "Thorsten Altenkirch and Bernhard Reus", + title = "Monadic Presentations of Lambda Terms Using + Generalized Inductive Types", + booktitle = csl, + year = "1999", + pages = "453--468", + publisher = springer, + series = lncs, + volume = "1683", + URL = "http://www.cs.nott.ac.uk/~txa/publ/csl99.pdf", +} + +@Article{amadio-cardelli-93, + author = "Roberto M. Amadio and Luca Cardelli", + title = "Subtyping Recursive Types", + journal = toplas, + volume = "15", + number = "4", + pages = "575--631", + year = "1993", + URL = "http://research.microsoft.com/Users/luca/Papers/SRT.pdf", +} + +@InProceedings{amadio-regis-gianas-11, + author = "Roberto Amadio and Yann R{\'{e}}gis{-}Gianas", + title = "Certifying and Reasoning on Cost Annotations of + Functional Programs", + booktitle = fopara, + pages = "72--89", + year = "2011", + series = lncs, + volume = "7177", + publisher = springer, + URL = "https://hal.inria.fr/inria-00629473v1", +} + +@Article{amadio-regis-gianas-13, + title = "Certifying and reasoning about cost annotations of + functional programs", + author = "Roberto Amadio and Yann R{\'e}gis-Gianas", + URL = "https://hal.inria.fr/inria-00629473", + journal = hosc, + year = "2013", +} + +@InProceedings{america-rutten-88, + author = "Pierre America and Jan Rutten", + title = "Solving reflexive domain equations in a category of + complete metric spaces", + booktitle = mfps, + pages = "254--288", + year = "1988", + volume = "298", + series = lncs, + publisher = springer, + URL = "http://dx.doi.org/10.1007/3-540-19020-1_13", +} + +@Article{amighi-15, + author = "Afshin Amighi and Christian Haack and Marieke Huisman + and Clément Hurlin", + title = "Permission-based separation logic for multithreaded + {Java} programs", + journal = lmcs, + year = "2015", + volume = "11", + number = "1", + pages = "1--66", + URL = "http://arxiv.org/abs/1411.0851", +} + +@InProceedings{amin-essence-16, + author = "Nada Amin and Samuel Gr{\"{u}}tter and Martin Odersky + and Tiark Rompf and Sandro Stucki", + title = "The Essence of Dependent Object Types", + booktitle = "A List of Successes That Can Change the World -- + Essays Dedicated to {Philip Wadler} on the Occasion of + His 60th Birthday", + series = lncs, + volume = "9600", + publisher = springer, + pages = "249--272", + year = "2016", + URL = "https://infoscience.epfl.ch/record/215280/files/paper_1.pdf", +} + +@InProceedings{amin-rompf-17, + author = "Nada Amin and Tiark Rompf", + title = "Type Soundness Proofs with Definitional Interpreters", + booktitle = popl, + year = "2017", + pages = "666--679", + URL = "http://lampwww.epfl.ch/~amin/pub/big-step.pdf", +} + +@Article{andersen-94, + author = "Henrik Reif Andersen", + title = "Model checking and {Boolean} graphs", + journal = tcs, + volume = "126", + number = "1", + year = "1994", + pages = "3--30", + URL = "http://dx.doi.org/10.1016/0304-3975(94)90266-6", +} + +@Article{anderson-eve-horning-73, + author = "T. Anderson and J. Eve and J. J. Horning", + title = "Efficient ${LR}(1)$ parsers", + journal = acta, + year = "1973", + volume = "2", + pages = "12--39", + URL = "http://dx.doi.org/10.1007/BF00571461", +} + +@Book{andrews-00, + author = "Gregory R. Andrews", + title = "Foundations of Multithreaded, Parallel, and + Distributed Programming", + publisher = aw, + year = "2000", +} + +@Book{andrews-86, + author = "Peter B. Andrews", + title = "An introduction to mathematical logic and type theory: + to truth through proof", + year = "1986", + publisher = ap, +} + +@Article{andrews-reitman-80, + author = "Gregory R. Andrews and Richard P. Reitman", + title = "An Axiomatic Approach to Information Flow in + Programs", + journal = toplas, + volume = "2", + number = "1", + pages = "56--76", + year = "1980", +} + +@Book{antlr, + author = "Terence Parr", + title = "The Definitive {ANTLR 4} Reference, 2nd edition", + year = "2013", + publisher = "Pragmatic Bookshelf", +} + +@InProceedings{antonopoulos-14, + author = "Timos Antonopoulos and Nikos Gorogiannis and Christoph + Haase and Max I. Kanovich and Jo{\"{e}}l Ouaknine", + title = "Foundations for Decision Problems in Separation Logic + with General Inductive Predicates", + booktitle = fossacs, + pages = "411--425", + year = "2014", + series = lncs, + volume = "8412", + publisher = springer, + URL = "http://www.lsv.ens-cachan.fr/Publis/PAPERS/PDF/AGHKO-fossacs14.pdf", +} + +@InProceedings{aponte-dicosmo-96, + author = "Maria-Virginia Aponte and Roberto {Di Cosmo}", + title = "Type isomorphisms for module signatures", + year = "1996", + booktitle = plilp, + publisher = springer, + series = lncs, + volume = "1140", + pages = "334--346", + URL = "http://dx.doi.org/10.1007/3-540-61756-6_95", +} + +@Book{appel-92, + author = "Andrew W. Appel", + title = "Compiling with Continuations", + publisher = cup, + year = "1992", + URL = "http://www.cambridge.org/9780521033114", +} + +@Article{appel-jim-97, + author = "Andrew W. Appel and Trevor Jim", + title = "Shrinking lambda expressions in linear time", + journal = jfp, + volume = "7", + number = "5", + year = "1997", + pages = "515--540", + URL = "http://www.research.att.com/~trevor/papers/shrinking.ps.gz", +} + +@InProceedings{appel-major-07, + author = "Andrew W. Appel and Paul-Andr\'{e} Melli\`{e}s and + Christopher D. Richards and J\'{e}r\^{o}me Vouillon", + title = "A very modal model of a modern, major, general type + system", + booktitle = popl, + year = "2007", + pages = "109--122", + URL = "http://www.cs.princeton.edu/~appel/papers/modalmodel.pdf", +} + +@Book{appel-tiger-98, + author = "Andrew Appel", + title = "Modern Compiler Implementation in {ML}", + publisher = cup, + year = "1998", + URL = "http://www.cs.princeton.edu/~appel/modern/ml/", +} + +@InProceedings{appel-verismall-11, + author = "Andrew W. Appel", + title = "{VeriSmall}: Verified {Smallfoot} Shape Analysis", + booktitle = cpp, + year = "2011", + pages = "231--246", + publisher = springer, + series = lncs, + volume = "7086", + URL = "http://www.cs.princeton.edu/~appel/papers/verismall.pdf", +} + +@InProceedings{appel-vst-11, + author = "Andrew W. Appel", + title = "Verified Software Toolchain", + booktitle = esop, + pages = "1--17", + year = "2011", + series = lncs, + volume = "6602", + publisher = springer, + URL = "https://www.cs.princeton.edu/~appel/papers/vst.pdf", +} + +@Article{apt-81, + author = "Krzysztof R. Apt", + title = "Ten Years of {Hoare's} Logic: {A} Survey---Part {I}", + journal = toplas, + volume = "3", + number = "4", + year = "1981", + pages = "431--483", + URL = "http://doi.acm.org/10.1145/357146.357150", +} + +@Article{ariola-klop-95, + author = "Zena M. Ariola and Jan Willem Klop", + title = "Equational term graph rewriting", + journal = fundamenta, + volume = "26", + number = "3--4", + year = "1996", + pages = "207--240", + URL = "http://www.cwi.nl/ftp/CWIreports/AP/CS-R9552.ps.Z", +} + +@Article{arnold-crubille-88, + author = "Andr{\'e} Arnold and Paul Crubillé", + title = "A Linear Algorithm to Solve Fixed-Point Equations on + Transition Systems", + journal = ipl, + volume = "29", + number = "2", + year = "1988", + pages = "57--66", + URL = "http://dx.doi.org/10.1016/0020-0190(88)90029-4", +} + +@Article{arnold-nivat-80, + author = "André Arnold and Maurice Nivat", + year = "1980", + journal = fundamenta, + volume = "3", + number = "4", + pages = "181--205", + title = "{T}he Metric Space of Infinite Trees. {A}lgebraic And + Topological Properties", +} + +@InProceedings{asai-kameyama-07, + author = "Kenichi Asai and Yukiyoshi Kameyama", + title = "Polymorphic Delimited Continuations", + booktitle = aplas, + pages = "239--254", + year = "2007", + series = lncs, + volume = "4807", + publisher = springer, + URL = "http://logic.cs.tsukuba.ac.jp/~kam/paper/aplas07.pdf", +} + +@Article{aspinall-07, + author = "David Aspinall and Lennart Beringer and Martin Hofmann + and Hans{-}Wolfgang Loidl and Alberto Momigliano", + title = "A program logic for resources", + journal = tcs, + volume = "389", + number = "3", + pages = "411--445", + year = "2007", + URL = "https://www.tcs.ifi.lmu.de/mitarbeiter/martin-hofmann/publikationen-pdfs/j25-ProgramLogisResources.pdf", +} + +@InProceedings{aspinall-hofmann-02, + author = "David Aspinall and Martin Hofmann", + title = "Another Type System for In-Place Update", + booktitle = esop, + pages = "36--52", + year = "2002", + series = lncs, + volume = "2305", + publisher = springer, + URL = "https://www.tcs.ifi.lmu.de/mitarbeiter/martin-hofmann/publikationen-pdfs/c22-anothertypesystem.pdf", +} + +@Article{aspinall-hofmann-konecky-08, + author = "David Aspinall and Martin Hofmann and Michal Kone{\v + c}n{\'{y}}", + title = "A type system with usage aspects", + journal = jfp, + volume = "18", + number = "2", + pages = "141--178", + year = "2008", + URL = "http://dx.doi.org/10.1017/S0956796807006399", +} + +@Misc{astree, + author = "Patrick Cousot and Radhia Cousot and Jérôme Feret + and Antoine Miné and Xavier Rival", + title = "The {Astrée} Static Analyzer", + year = "2011", + note = "\url{http://www.astree.ens.fr/}", + URL = "http://www.astree.ens.fr/", +} + +@Article{atkey-09, + author = "Robert Atkey", + title = "Parameterised Notions of Computation", + journal = jfp, + year = "2009", + volume = "19", + number = "3--4", + pages = "355--376", + URL = "http://homepages.inf.ed.ac.uk/ratkey/paramnotions-jfp.pdf", +} + +@Article{atkey-11, + title = "Amortised Resource Analysis with Separation Logic", + author = "Robert Atkey", + year = "2011", + journal = lmcs, + volume = "7", + number = "2:17", + URL = "http://bentnib.org/amortised-sep-logic-journal.pdf", +} + +@InProceedings{atkey-amortised-10, + author = "Robert Atkey", + title = "Amortised Resource Analysis with Separation Logic", + booktitle = esop, + pages = "85--103", + year = "2010", + volume = "6012", + series = lncs, + publisher = springer, + URL = "http://personal.cis.strath.ac.uk/~raa/amortised-sep-logic.pdf", +} + +@InProceedings{atkey-hoas-09, + author = "Robert Atkey", + title = "Syntax for free: representing syntax with binding + using parametricity", + booktitle = tlca, + pages = "35--49", + year = "2009", + volume = "5608", + series = lncs, + publisher = springer, + URL = "https://personal.cis.strath.ac.uk/~raa/syntaxforfree.pdf", +} + +@InProceedings{atkey-lindley-yallop-09, + author = "Robert Atkey and Sam Lindley and Jeremy Yallop", + title = "Unembedding Domain-Specific languages", + booktitle = hs, + pages = "37--48", + year = "2009", + URL = "http://personal.cis.strath.ac.uk/~raa/unembedding.pdf", +} + +@InProceedings{augustsson-93, + author = "Lennart Augustsson", + title = "Implementing {Haskell} Overloading", + booktitle = fpca, + pages = "65--73", + year = "1993", + URL = "http://dl.acm.org/citation.cfm?id=165191", +} + +@Book{autebert-94, + author = "Jean-Michel Autebert", + title = "Théorie des langages et des automates", + publisher = "Masson", + year = "1994", +} + +@InCollection{autebert-97, + author = "Jean-Michel Autebert and Jean Berstel and Luc + Boasson", + booktitle = "Handbook of Formal Languages", + title = "Context-Free Languages and Push-Down Automata", + publisher = springer, + year = "1997", + volume = "1", + pages = "111--174", + URL = "http://www-igm.univ-mlv.fr/~berstel/Articles/CFLPDA.ps.gz", +} + +@InProceedings{autosubst-15, + author = "Steven Sch{\"{a}}fer and Tobias Tebbi and Gert + Smolka", + title = "{Autosubst}: Reasoning with {de Bruijn} Terms and + Parallel Substitutions", + booktitle = itp, + pages = "359--374", + year = "2015", + series = lncs, + volume = "9236", + publisher = springer, + URL = "https://www.ps.uni-saarland.de/Publications/documents/SchaeferEtAl_2015_Autosubst_-Reasoning.pdf", +} + +@InProceedings{ayache-amadio-regis-gianas-12, + author = "Nicholas Ayache and Roberto M. Amadio and Yann + R{\'{e}}gis{-}Gianas", + title = "Certifying and Reasoning on Cost Annotations in {C} + Programs", + booktitle = "Formal Methods for Industrial Critical Systems", + pages = "32--46", + year = "2012", + series = lncs, + volume = "7437", + publisher = springer, + URL = "https://hal.inria.fr/hal-00702665", +} + +@InProceedings{aycock-horspool-00, + author = "John Aycock and Nigel Horspool", + title = "Simple Generation of Static Single-Assignment Form", + booktitle = cc, + year = "2000", + volume = "1781", + series = lncs, + publisher = springer, + URL = "http://pages.cpsc.ucalgary.ca/~aycock/papers/ssa.ps", +} + +@InProceedings{aydemir-08, + author = "Brian Aydemir and Arthur Chargu{\'e}raud and {Benjamin + C.} Pierce and Randy Pollack and Stephanie Weirich", + booktitle = popl, + title = "Engineering Formal Metatheory", + year = "2008", + pages = "3--15", + URL = "http://www.cis.upenn.edu/~bcpierce/papers/binders.pdf", +} + +@Article{baker-77, + author = "Henry G. Baker", + title = "List Processing in Real Time on a Serial Computer", + journal = cacm, + volume = "21", + number = "4", + year = "1978", + pages = "280--294", + URL = "http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.468.2631&rep=rep1&type=pdf", +} + +@InProceedings{baker-conquer-90, + author = "Henry G. Baker", + title = "Unify and conquer (Garbage, Updating, Aliasing, + \ldots) in Functional Languages", + booktitle = lfp, + year = "1990", + pages = "218--226", + URL = "http://home.pipeline.com/~hbaker1/Share-Unify.ps.gz", +} + +@InProceedings{balabonski-pottier-protzenko-mezzo-14, + author = "Thibaut Balabonski and François Pottier and Jonathan + Protzenko", + title = "Type Soundness and Race Freedom for {Mezzo}", + booktitle = "Proceedings of the 12th International Symposium on + Functional and Logic Programming (FLOPS 2014)", + year = "2014", + series = lncs, + publisher = springer, + volume = "8475", + pages = "253--269", + URL = "http://gallium.inria.fr/~fpottier/publis/bpp-mezzo.pdf", +} + +@Article{balabonski-pottier-protzenko-mezzo-journal-16, + author = "Thibaut Balabonski and François Pottier and Jonathan + Protzenko", + title = "The Design and Formalization of {Mezzo}, a + Permission-Based Programming Language", + journal = toplas, + volume = "38", + number = "4", + pages = "14:1--14:94", + year = "2016", + URL = "http://gallium.inria.fr/~fpottier/publis/bpp-mezzo-journal.pdf", +} + +@InProceedings{balat-dicosmo-fiore-02, + author = "Vincent Balat and Roberto {Di Cosmo} and Marcelo + Fiore", + title = "Remarks on Isomorphisms in Typed Lambda Calculi with + Empty and Sum Type", + booktitle = lics, + year = "2002", + URL = "http://www.cl.cam.ac.uk/~mpf23/papers/Types/remarks.ps.gz", +} + +@InProceedings{banatre-bryce-lemetayer-94, + author = "Jean-Pierre Banâtre and Ciarán Bryce and Daniel {Le + Métayer}", + title = "Compile-time detection of information flow in + sequential programs", + booktitle = esorics, + year = "1994", + publisher = springer, + pages = "55--74", + series = lncs, + volume = "875", + URL = "ftp://ftp.irisa.fr/local/lande/dlm-esorics94.ps.Z", +} + +@InProceedings{banerjee-heintze-riecke-01, + author = "Anindya Banerjee and Nevin Heintze and Jon G. Riecke", + title = "Design and Correctness of Program Transformations + based on Control-flow Analysis", + booktitle = tacs, + pages = "420--447", + year = "2001", + volume = "2215", + series = lncs, + publisher = springer, + URL = "http://www.cis.ksu.edu/~ab/Publications/pcfa.ps.gz", +} + +@InProceedings{banerjee-heintze-riecke-99, + author = "Anindya Banerjee and Nevin Heintze and Jon G. Riecke", + title = "Region Analysis and the Polymorphic Lambda Calculus", + booktitle = lics, + year = "1999", + pages = "88--97", + URL = "http://www.cs.ucla.edu/~palsberg/tba/papers/banerjee-heintze-riecke-lics99.pdf", +} + +@TechReport{banerjee-naumann-01, + author = "Anindya Banerjee and David A. Naumann", + title = "A Simple Semantics and Static Analysis for {Java} + Security", + institution = "Stevens Institute of Technology", + number = "2001-1", + year = "2001", + URL = "http://guinness.cs.stevens-tech.edu/~naumann/publications/tr2001.ps", +} + +@InProceedings{banerjee-naumann-05, + author = "Anindya Banerjee and David A. Naumann", + title = "State based ownership, reentrance, and encapsulation", + booktitle = ecoop, + pages = "387--411", + year = "2005", + volume = "3586", + series = lncs, + publisher = springer, + URL = "https://guinness.cs.stevens-tech.edu/~naumann/publications/ecoop.pdf", +} + +@InProceedings{banerjee-naumann-csfw-02, + author = "Anindya Banerjee and David Naumann", + title = "Secure Information Flow and Pointer Confinement in a + {Java}-like Language", + booktitle = csfw, + pages = "253--267", + year = "2002", + URL = "http://www.cs.stevens-tech.edu/~naumann/publications/csfw15.ps", +} + +@InProceedings{banerjee-naumann-popl-02, + author = "Anindya Banerjee and David A. Naumann", + title = "Representation Independence, Confinement, and Access + Control", + booktitle = popl, + year = "2002", + pages = "166--177", + URL = "http://guinness.cs.stevens-tech.edu/~naumann/publications/BanerjeeNaumann.ps", +} + +@TechReport{barber-dill-96, + author = "Andrew Barber", + title = "Dual Intuitionistic Linear Logic", + institution = "Laboratory for Foundations of Computer Science, School + of Informatics at the University of Edinburgh", + year = "1996", + number = "ECS-LFCS-96-347", + URL = "http://www.lfcs.inf.ed.ac.uk/reports/96/ECS-LFCS-96-347/", +} + +@Book{barendregt, + author = "Henk P. Barendregt", + title = "The Lambda Calculus, Its Syntax and Semantics", + publisher = elsevier, + year = "1984", + URL = "http://www.elsevier.com/wps/find/bookdescription.cws_home/501727/description", +} + +@InCollection{barendregt-90, + author = "Henk P. Barendregt", + title = "Functional Programming and Lambda Calculus", + booktitle = "Handbook of Theoretical Computer Science", + pages = "321--363", + publisher = elsevier, + year = "1990", + editor = "J. Van Leeuwen", +} + +@InProceedings{barendsen-smesters-95, + author = "Erik Barendsen and Sjaak Smetsers", + title = "Uniqueness Type Inference", + booktitle = plilp, + year = "1995", + pages = "189--206", + publisher = springer, + series = lncs, + volume = "982", + URL = "http://dx.doi.org/10.1007/BFb0026821", +} + +@InProceedings{barnett-pure-04, + author = "Mike Barnett and David A. Naumann and Wolfram Schulte + and Qi Sun", + title = "99.44\% pure: Useful Abstractions in Specifications", + booktitle = ftfjp, + year = "2004", + URL = "http://www.cs.ru.nl/ftfjp/2004/Purity.pdf", +} + +@InProceedings{barnett-spec-04, + author = "Mike Barnett and K. Rustan M. Leino and Wolfram + Schulte", + title = "The {Spec\#} programming system: An overview", + booktitle = cassis, + year = "2004", + volume = "3362", + pages = "49--69", + series = lncs, + publisher = springer, + URL = "http://research.microsoft.com/~leino/papers/krml136.pdf", +} + +@Article{barrett-00, + author = "Chris Barrett and Riko Jacob and Madhav Marathe", + title = "Formal Language Constrained Path Problems", + journal = siamjc, + year = "2000", + volume = "30", + number = "3", + pages = "809--837", + URL = "http://www.brics.dk/~rjacob/Publications/regpath.ps.gz", + alturl = "http://epubs.siam.org/sam-bin/getfile/SICOMP/articles/33771.pdf", +} + +@TechReport{bartels-96, + author = "Frank Bartels and Friedrich von Henke and Holger + Pfeifer and Harald Rue{\ss}", + title = "Mechanizing Domain Theory", + institution = "Universit{\"a}t Ulm, Fakult{\"a}t f{\"u}r Informatik", + year = "1996", + number = "96-10", + type = "Ulmer Informatik-Berichte", + URL = "http://www.csl.sri.com/users/ruess/papers/Fixpoints/fixpoints-domains3.ps.gz", +} + +@InProceedings{barthe-06, + author = "Gilles Barthe and Julien Forest and David Pichardie + and Vlad Rusu", + title = "Defining and Reasoning About Recursive Functions: A + Practical Tool for the {Coq} Proof Assistant", + booktitle = flops, + pages = "114--129", + year = "2006", + series = lncs, + volume = "3945", + publisher = springer, + URL = "http://people.irisa.fr/David.Pichardie/papers/flops06.pdf", +} + +@InProceedings{barthwal-norrish-09, + author = "Aditi Barthwal and Michael Norrish", + title = "Verified, Executable Parsing", + booktitle = esop, + year = "2009", + pages = "160--174", + series = lncs, + publisher = springer, + volume = "5502", + URL = "http://users.cecs.anu.edu.au/~aditi/esop09_submission_16.pdf", +} + +@InProceedings{bartoletti-al-01, + author = "Massimo Bartoletti and Pierpaolo Degano and GianLuigi + Ferrari", + title = "Static Analysis for Stack Inspection", + booktitle = "International Workshop on Concurrency and + Coordination", + series = entcs, + volume = "54", + publisher = elsevier, + year = "2001", +} + +@Article{bauer-pretnar-13, + author = "Andrej Bauer and Matija Pretnar", + title = "An Effect System for Algebraic Effects and Handlers", + journal = lmcs, + volume = "10", + number = "4", + year = "2014", + URL = "https://arxiv.org/pdf/1306.6316.pdf", +} + +@Article{beaven-stansifer-93, + author = "Mike Beaven and Ryan Stansifer", + title = "Explaining type errors in polymorphic languages", + journal = "ACM Letters on Programming Languages and Systems", + volume = "2", + number = "4", + pages = "17--30", + year = "1993", + URL = "http://www.cs.fit.edu/~ryan/papers/explain.ps.gz", +} + +@InProceedings{belanger-monnier-pientka-13, + author = "Olivier {Savary Belanger} and Stefan Monnier and + Brigitte Pientka", + title = "Programming Type-Safe Transformations Using + Higher-Order Abstract Syntax", + booktitle = cpp, + pages = "243--258", + year = "2013", + series = lncs, + volume = "8307", + publisher = springer, + URL = "https://link.springer.com/chapter/10.1007/978-3-319-03545-1_16", +} + +@Article{belanger-monnier-pientka-15, + author = "Olivier {Savary Belanger} and Stefan Monnier and + Brigitte Pientka", + title = "Programming Type-Safe Transformations Using + Higher-Order Abstract Syntax", + journal = jfr, + year = "2015", + volume = "8", + number = "1", + URL = "https://jfr.unibo.it/article/view/5122/5330", +} + +@InProceedings{bell-08, + author = "C. J. Bell and Robert Dockins and Aquinas Hobor and + Andrew W. Appel and David Walker", + title = "Comparing Semantic and Syntactic Methods in Mechanized + Proof Frameworks", + booktitle = pcc, + year = "2008", + URL = "http://www.cs.princeton.edu/~rdockins/pubs/semsyn.pdf", +} + +@InProceedings{bell-bellegarde-hook-97, + author = "Jeffrey M. Bell and Françoise Bellegarde and James + Hook", + title = "Type-driven Defunctionalization", + booktitle = icfp, + year = "1997", + URL = "http://doi.acm.org/10.1145/258949.258953", +} + +@TechReport{bell-lapadula-75, + author = "D. E. Bell and Leonard J. LaPadula", + title = "Secure Computer Systems: Unified Exposition and + {Multics} Interpretation", + year = "1975", + number = "MTR-2997", + institution = "The {MITRE} Corp.", + URL = "http://niatec.info/pdf/bell76.pdf", +} + +@InProceedings{bengtson-12, + author = "Jesper Bengtson and Jonas Braband Jensen and Lars + Birkedal", + title = "Charge! {A} Framework for Higher-Order Separation + Logic in {Coq}", + booktitle = itp, + pages = "315--331", + year = "2012", + URL = "http://cs.au.dk/~birke/papers/charge-conf.pdf", +} + +@InProceedings{berdine-calcagno-ohearn-05, + author = "Josh Berdine and Cristiano Calcagno and Peter W. + O'Hearn", + title = "Symbolic Execution with Separation Logic", + booktitle = aplas, + year = "2005", + publisher = springer, + series = lncs, + volume = "3780", + pages = "52--68", + URL = "http://www.dcs.qmul.ac.uk/~berdine/papers/execution.pdf", +} + +@InProceedings{berdine-decidable-fragment-04, + author = "Josh Berdine and Cristiano Calcagno and Peter W. + O'Hearn", + title = "A Decidable Fragment of Separation Logic", + booktitle = fsttcs, + year = "2004", + pages = "97--109", + publisher = springer, + series = lncs, + volume = "3328", + URL = "http://www.cs.ucl.ac.uk/staff/p.ohearn/papers/unroll_collapse.pdf", +} + +@Article{berdine-linear-continuations-02, + author = "Josh Berdine and Peter W. O'Hearn and Uday S. Reddy + and Hayo Thielecke", + title = "Linear Continuation-Passing", + journal = hosc, + year = "2002", + volume = "15", + number = "2--3", + pages = "181--208", + URL = "http://www.cs.bham.ac.uk/~hxt/research/LinCP.pdf", +} + +@InProceedings{berdine-ohearn-06, + author = "Josh Berdine and Peter W. O'Hearn", + title = "Strong Update, Disposal, and Encapsulation in Bunched + Typing", + booktitle = mfps, + series = entcs, + publisher = elsevier, + volume = "158", + year = "2006", + pages = "81--98", + URL = "http://research.microsoft.com/pubs/73584/bil.pdf", +} + +@InProceedings{berger-honda-yoshida-05, + author = "Martin Berger and Kohei Honda and Nobuko Yoshida", + title = "A logical analysis of aliasing in imperative + higher-order functions", + booktitle = icfp, + year = "2005", + pages = "280--293", + URL = "http://doi.acm.org/10.1145/1086365.1086401", +} + +@InProceedings{bergeron-al-00, + author = "M. Debbabi and E. Giasson and B. Ktari and F. Michaud + and N. Tawbi", + title = "Secure Self-Certified {COTS}", + booktitle = "IEEE International Workshop on Enterprise Security + (WETICE'00)", + year = "2000", + URL = "http://www.ift.ulaval.ca/~lsfm/lsfm_eng/Publications/wetice2000_2.pdf", +} + +@Unpublished{bernstein-stark-95, + author = "K. Bernstein and E. W. Stark", + title = "Debugging Type Errors", + year = "1995", + URL = "http://bsd7.starkhome.cs.sunysb.edu/~stark/REPORTS/debugtype.ps.gz", + note = "Unpublished", +} + +@InProceedings{berthomieu-sagazan-95, + author = "Bernard Berthomieu and Camille {le Moniès de + Sagazan}", + title = "A Calculus of Tagged Types, with applications to + process languages", + booktitle = "Workshop on Types for Program Analysis", + pages = "1--15", + year = "1995", + URL = "http://www.laas.fr/~bernard/lcs/papers/tpa95.ps.gz", +} + +@Article{besson-al-01, + author = "Frédéric Besson and Thomas P. Jensen and Daniel {Le + Métayer} and Tommy Thorn", + title = "Model Checking Security Properties of Control Flow + Graphs", + journal = "Journal of Computer Security", + volume = "9", + number = "3", + year = "2001", + pages = "217--250", + URL = "http://www.irisa.fr/lande/jensen/jcs.pdf", +} + +@InProceedings{besson-al-02, + author = "Frédéric Besson and Thomas {de Grenier de Latour} + and Thomas Jensen", + title = "Secure Calling Contexts for Stack Inspection", + pages = "76--87", + booktitle = ppdp, + year = "2002", + URL = "http://www.irisa.fr/lande/jensen/ppdp02.pdf", +} + +@Article{bhamidipaty-proebsting-98, + author = "Achyutram Bhamidipaty and Todd A. Proebsting", + title = "Very Fast {YACC}-Compatible Parsers (For Very Little + Effort)", + journal = spe, + year = "1998", + volume = "28", + number = "2", + pages = "181--190", + URL = "http://www.cs.arizona.edu/people/todd/papers/TR95-09.ps", +} + +@InProceedings{bhargavan-fournet-gordon-10, + author = "Karthik Bhargavan and Cédric Fournet and Andy + Gordon", + title = "Modular Verification of Security Protocol Code by + Typing", + booktitle = popl, + pages = "445--456", + year = "2010", + URL = "http://moscova.inria.fr/~karthik/pubs/modular-verification-of-security-protocols-by-typing-popl10.pdf", +} + +@InProceedings{bhat-cleaveland-96, + author = "Girish Bhat and Rance Cleaveland", + title = "Efficient Local Model-Checking for Fragments of the + Modal $\mu$-Calculus", + booktitle = tacas, + pages = "107--126", + year = "1996", + volume = "1055", + series = lncs, + publisher = springer, + URL = "http://www.cs.umd.edu/~rance/publications/papers/tacas96a.ps.gz", +} + +@InProceedings{biere-bmc-99, + author = "Armin Biere and Alessandro Cimatti and Edmund Clarke + and Yunshan Zhu", + title = "Symbolic Model Checking Without {BDDs}", + booktitle = tacas, + pages = "193--207", + year = "1999", + volume = "1579", + series = lncs, + publisher = springer, + URL = "http://www.inf.ethz.ch/personal/biere/papers/BiereCimattiClarkeZhu-TACAS99.pdf", +} + +@InProceedings{bierhoff-aldrich-07, + author = "Kevin Bierhoff and Jonathan Aldrich", + title = "Modular typestate checking of aliased objects", + booktitle = oopsla, + year = "2007", + pages = "301--320", + URL = "http://www.cs.cmu.edu/~kbierhof/papers/typestate-verification.pdf", +} + +@InProceedings{bierhoff-beckman-aldrich-09, + author = "Kevin Bierhoff and Nels E. Beckman and Jonathan + Aldrich", + title = "Practical {API} Protocol Checking with Access + Permissions", + booktitle = ecoop, + year = "2009", + pages = "195--219", + publisher = springer, + series = lncs, + volume = "5653", + URL = "http://www.cs.cmu.edu/~kbierhof/papers/permission-practice.pdf", +} + +@InProceedings{biering-05, + author = "Bodil Biering and Lars Birkedal and Noah Torp-Smith", + title = "{BI} Hyperdoctrines and Higher-Order Separation + Logic", + booktitle = esop, + year = "2005", + pages = "233--247", + publisher = springer, + series = lncs, + volume = "3444", + URL = "http://www.itu.dk/people/noah/papers/hyperdocs.pdf", +} + +@Article{bird-hughes-87, + author = "Richard S. Bird and John Hughes", + title = "The alpha-beta Algorithm: An Exercise in Program + Transformation", + journal = ipl, + volume = "24", + number = "1", + year = "1987", + pages = "53--57", + URL = "http://dx.doi.org/10.1016/0020-0190(87)90198-0", +} + +@InProceedings{bird-meertens-98, + author = "Richard Bird and Lambert Meertens", + title = "Nested Datatypes", + booktitle = mpc, + pages = "52--67", + year = "1998", + volume = "1422", + series = lncs, + publisher = springer, + URL = "http://www.cs.ox.ac.uk/richard.bird/online/BirdMeertens98Nested.pdf", +} + +@Article{bird-paterson-99, + title = "{de Bruijn} Notation as a Nested Datatype", + author = "Richard Bird and Ross Paterson", + URL = "http://dx.doi.org/10.1017/S0956796899003366", + journal = jfp, + volume = "9", + number = "1", + pages = "77--91", + year = "1999", +} + +@TechReport{birkedal-alii-93, + author = "Lars Birkedal and Nick Rothwell and Mads Tofte and + David N. Turner", + semno = "D-181", + title = "The {ML} Kit (Version 1)", + institution = "Department of Computer Science, University of + Copenhagen", + year = "1993", + number = "DIKU 93/14", + URL = "http://www.it-c.dk/research/mlkit/", +} + +@Article{birkedal-hoframe-06, + author = "Lars Birkedal and Noah Torp-Smith and Hongseok Yang", + title = "Semantics of separation-logic typing and higher-order + frame rules for {Algol}-like languages", + journal = lmcs, + year = "2006", + volume = "2", + number = "5", + URL = "http://arxiv.org/pdf/cs.LO/0610081", +} + +@Unpublished{birkedal-nakano-10, + author = "Lars Birkedal and Jan Schwinghammer and Kristian + Støvring", + title = "A Metric Model of Lambda Calculus with Guarded + Recursion", + note = "Presented at FICS 2010", + year = "2010", + URL = "http://www.itu.dk/~birkedal/papers/nakano-conf.pdf", +} + +@InProceedings{birkedal-popl-11, + author = "Lars Birkedal and Bernhard Reus and Jan Schwinghammer + and Kristian Støvring and Jacob Thamsborg and Hongseok + Yang", + title = "Step-indexed {Kripke} models over recursive worlds", + booktitle = popl, + pages = "119--132", + year = "2011", + URL = "http://www.eecs.qmul.ac.uk/~hyang/paper/popl11-long.pdf", +} + +@InProceedings{birkedal-stovring-thamsborg-09, + author = "Lars Birkedal and Kristian St{\o}vring and Jacob + Thamsborg", + title = "Realizability Semantics of Parametric Polymorphism, + General References, and Recursive Types", + booktitle = fossacs, + pages = "456--470", + year = "2009", + volume = "5504", + series = lncs, + publisher = springer, + URL = "http://www.itu.dk/~birkedal/papers/parametricity-state-metric-conf.pdf", +} + +@Article{birkedal-stovring-thamsborg-10, + author = "Lars Birkedal and Kristian St{\o}vring and Jacob + Thamsborg", + title = "Realisability Semantics of Parametric Polymorphism, + General References, and Recursive Types", + journal = mscs, + year = "2010", + volume = "20", + number = "4", + pages = "655--703", + URL = "http://www.itu.dk/~birkedal/papers/parametricity-state-metric-journal.pdf", +} + +@TechReport{birkedal-stovring-thamsborg-solution-09, + author = "Lars Birkedal and Kristian St{\o}vring and Jacob + Thamsborg", + title = "The category-theoretic solution of recursive + metric-space quations", + institution = "IT University of Copenhagen", + year = "2009", + number = "ITU-2009-119", + URL = "http://www.itu.dk/~birkedal/papers/ITU-TR-2009-119.pdf", +} + +@Article{birkedal-tofte-01, + author = "Lars Birkedal and Mads Tofte", + title = "A constraint-based region inference algorithm", + journal = tcs, + year = "2001", + volume = "258", + pages = "299--392", + URL = "http://www.itu.dk/people/birkedal/papers/conria.ps.gz", +} + +@Unpublished{birrell-03, + author = "Andrew D. Birrell", + title = "An Introduction to Programming with {C\#} Threads", + note = "Manuscript", + year = "2003", + URL = "http://birrell.org/andrew/papers/ThreadsCSharp.pdf", +} + +@Manual{bison, + title = "Bison", + author = "Charles Donnelly and Richard Stallman", + year = "2015", + URL = "http://www.gnu.org/software/bison/manual/", +} + +@PhdThesis{biswas-97, + school = "University of Pennsylvania", + title = "Dynamic Slicing in Higher-Order Programming + Languages", + year = "1997", + pages = "151", + author = "Sandip K. Biswas", +} + +@InProceedings{blelloch-greiner-95, + author = "Guy E. Blelloch and John Greiner", + title = "Parallelism in Sequential Functional Languages", + booktitle = fpca, + pages = "226--237", + year = "1995", + URL = "http://www.cs.cmu.edu/afs/cs.cmu.edu/project/scandal/public/papers/fpca-pal.ps.gz", +} + +@Article{bobot-why3-15, + author = "Fran{\c{c}}ois Bobot and Jean-Christophe + Filli{\^{a}}tre and Claude March{\'{e}} and Andrei + Paskevich", + title = "Let's verify this with {Why3}", + journal = sttt, + volume = "17", + number = "6", + pages = "709--727", + year = "2015", + URL = "https://hal.inria.fr/hal-00967132/", +} + +@InProceedings{bocchino-09, + author = "Robert L. {Bocchino Jr.} and Vikram S. Adve and Sarita + V. Adve and Marc Snir", + title = "Parallel Programming Must Be Deterministic by + Default", + booktitle = hotpar, + year = "2009", + pages = "1--6", + URL = "http://dpj.cs.illinois.edu/DPJ/Publications_files/DPJ-HotPar-2009.pdf", +} + +@InCollection{bocchino-13, + author = "Robert L. {Bocchino Jr.}", + title = "Alias Control for Deterministic Parallelism", + editor = "Dave Clarke and James Noble and Tobias Wrigstad", + booktitle = "Aliasing in Object-Oriented Programming. Types, + Analysis and Verification", + pages = "156--195", + year = "2013", + URL = "http://dx.doi.org/10.1007/978-3-642-36946-9_7", + series = lncs, + volume = "7850", + publisher = springer, +} + +@InProceedings{bocchino-adve-11, + author = "Robert L. {Bocchino Jr.} and Vikram S. Adve", + title = "Types, Regions, and Effects for Safe Programming with + Object-Oriented Parallel Frameworks", + booktitle = ecoop, + pages = "306--332", + year = "2011", + series = lncs, + volume = "6813", + publisher = springer, + URL = "http://rob-bocchino.net/Professional/Publications_files/DPJ-ECOOP-2011-Frameworks.pdf", +} + +@InProceedings{bocchino-dpj-09, + author = "Robert L. {Bocchino Jr.} and Vikram S. Adve and Danny + Dig and Sarita V. Adve and Stephen Heumann and Rakesh + Komuravelli and Jeffrey Overbey and Patrick Simmons and + Hyojin Sung and Mohsen Vakilian", + title = "A type and effect system for deterministic parallel + {Java}", + booktitle = oopsla, + pages = "97--116", + year = "2009", + URL = "http://rob-bocchino.net/Professional/Publications_files/Bocchino-OOPSLA-2009.pdf", +} + +@InProceedings{bocchino-safe-11, + author = "Robert L. {Bocchino Jr.} and Stephen Heumann and Nima + Honarmand and Sarita V. Adve and Vikram S. Adve and + Adam Welc and Tatiana Shpeisman", + title = "Safe nondeterminism in a deterministic-by-default + parallel language", + booktitle = popl, + pages = "535--548", + year = "2011", + URL = "http://rob-bocchino.net/Professional/Publications_files/Bocchino-POPL-2011.pdf", +} + +@InProceedings{bodei-al-99, + author = "Chiara Bodei and Pierpaolo Degano and Flemming Nielson + and Hanne Riis Nielson", + title = "Static Analysis of Processes for No Read-Up and No + Write-Down", + booktitle = fossacs, + year = "1999", + volume = "1578", + series = lncs, + publisher = springer, + pages = "120--134", + URL = "http://www.di.unipi.it/~chiara/publ-40/BDNN99.ps", +} + +@Article{boehm-adve-12, + author = "Hans-J. Boehm and Sarita V. Adve", + title = "You don't know jack about shared variables or memory + models", + journal = cacm, + volume = "55", + number = "2", + year = "2012", + pages = "48--54", + URL = "http://doi.acm.org/10.1145/2076450.2076465", +} + +@InProceedings{bonniot-02, + author = "Daniel Bonniot", + title = "Type-checking multi-methods in {ML} (a modular + approach)", + booktitle = fool, + year = "2002", + URL = "http://gallium.inria.fr/~bonniot/bonniot02.ps", +} + +@PhdThesis{boquist-99, + author = "Urban Boquist", + title = "Code Optimisation Techniques for Lazy Functional + Languages", + school = "Chalmers University of Technology", + year = "1999", + URL = "http://www.cs.uu.nl/docs/vakken/macc/boquist.pdf", +} + +@Article{boreale-sangiorgi-98, + author = "Michele Boreale and Davide Sangiorgi", + title = "A fully abstract semantics for causality in the + $\pi$-calculus", + journal = acta, + volume = "35", + number = "5", + pages = "353--400", + year = "1998", + URL = "http://link.springer.de/link/service/journals/00236/papers/8035005/80350353.pdf", +} + +@InProceedings{borgstrom-chen-swamy-11, + author = "Johannes Borgström and Juan Chen and and Nikhil + Swamy", + title = "Verified Stateful Programs with Substructural State + and {Hoare} Types", + booktitle = plpv, + year = "2011", + URL = "http://research.microsoft.com/pubs/135430/plpv11k-borgstrom.pdf", +} + +@InProceedings{bornat-00, + author = "Richard Bornat", + title = "Proving Pointer Programs in {Hoare} Logic", + booktitle = mpc, + year = "2000", + pages = "102--126", + publisher = springer, + series = lncs, + volume = "1837", + URL = "http://www.cs.mdx.ac.uk/staffpages/r_bornat/papers/MPC2000.pdf", +} + +@InProceedings{bornat-permission-accounting-05, + author = "Richard Bornat and Cristiano Calcagno and Peter + O'Hearn and Matthew Parkinson", + title = "Permission accounting in separation logic", + booktitle = popl, + year = "2005", + pages = "259--270", + URL = "http://www.cs.ucl.ac.uk/staff/p.ohearn/papers/permissions_paper.pdf", +} + +@InProceedings{bouajjani-esparza-maler-97, + author = "Ahmed Bouajjani and Javier Esparza and Oded Maler", + title = "Reachability Analysis of Pushdown Automata: + Application to Model-Checking", + booktitle = concur, + pages = "135--150", + year = "1997", + URL = "http://www-verimag.imag.fr/~maler/Papers/pda.pdf", + series = lncs, + volume = "1243", + publisher = springer, +} + +@Unpublished{boudol-castellani-01, + author = "Gérard Boudol and Ilaria Castellani", + title = "Non-interference for concurrent programs and thread + systems", + year = "2001", + note = "To appear", + URL = "ftp://ftp-sop.inria.fr/mimosa/personnel/gbo/non-interf-threads.ps.gz", +} + +@Article{boudol-stratified-regions, + author = "Gérard Boudol", + title = "Typing termination in a higher-order concurrent + imperative language", + journal = ic, + year = "2009", + note = "To appear", + URL = "ftp://ftp-sop.inria.fr/mimosa/personnel/gbo/ttiahocil.pdf", +} + +@InProceedings{boulme-07, + author = "Sylvain Boulmé", + title = "Intuitionistic Refinement Calculus", + booktitle = tlca, + year = "2007", + pages = "54--69", + volume = "4583", + series = lncs, + publisher = springer, + URL = "http://www-lsr.imag.fr/users/Sylvain.Boulme/horefinement/dsm.pdf", +} + +@Misc{bound, + author = "Edward Kmett", + title = "Bound", + howpublished = "Blog post", + year = "2014", + URL = "https://www.fpcomplete.com/user/edwardk/bound", +} + +@TechReport{bourdoncle-merz-96, + author = "François Bourdoncle and Stephan Merz", + title = "On the integration of functional programming, + class-based object-oriented programming, and + multi-methods", + institution = "Centre de Mathématiques Appliquées, Ecole des Mines + de Paris", + year = "1996", + type = "Research Report", + number = "26", + URL = "http://www.loria.fr/~merz/papers/mlsub.html", +} + +@InProceedings{bourdoncle-merz-97, + author = "François Bourdoncle and Stephan Merz", + title = "Type Checking Higher-Order Polymorphic Multi-Methods", + booktitle = popl, + year = "1997", + pages = "302--315", + URL = "http://www.exalead.com/Francois.Bourdoncle/popl97.html", +} + +@InProceedings{boyapati-lee-rinard-02, + author = "Chandrasekhar Boyapati and Robert Lee and Martin + Rinard", + title = "Ownership types for safe programming: preventing data + races and deadlocks", + booktitle = oopsla, + year = "2002", + pages = "211--230", + URL = "http://doi.acm.org/10.1145/582419.582440", +} + +@InProceedings{boyapati-liskov-shrira-03, + author = "Chandrasekhar Boyapati and Barbara Liskov and Liuba + Shrira", + title = "Ownership types for object encapsulation", + booktitle = popl, + year = "2003", + pages = "213--223", + URL = "http://www.pmg.lcs.mit.edu/~chandra/publications/popl03.pdf", +} + +@Article{boyland-burying-01, + author = "John Boyland", + title = "Alias burying: Unique variables without destructive + reads", + journal = scp, + year = "2001", + volume = "31", + number = "6", + pages = "533--553", + URL = "http://www.cs.uwm.edu/faculty/boyland/papers/unique-preprint.ps", +} + +@InProceedings{boyland-fractions-03, + author = "John Boyland", + title = "Checking Interference with Fractional Permissions", + booktitle = sas, + year = "2003", + series = lncs, + publisher = springer, + volume = "2694", + pages = "55--72", + URL = "http://www.cs.uwm.edu/~boyland/papers/permissions.pdf", +} + +@Article{boyland-nesting-10, + author = "John Tang Boyland", + title = "Semantics of fractional permissions with nesting", + journal = toplas, + volume = "32", + number = "6", + pages = "22:1--22:33", + year = "2010", + URL = "http://dx.doi.org/10.1145/1749608.1749611", +} + +@InProceedings{boyland-noble-retert-01, + author = "John Boyland and James Noble and William Retert", + title = "Capabilities for Sharing: {A} Generalisation of + Uniqueness and Read-Only", + booktitle = ecoop, + pages = "2--27", + year = "2001", + series = lncs, + volume = "2072", + publisher = springer, + URL = "http://www.cs.uwm.edu/~boyland/papers/capability.ps", +} + +@InProceedings{boyland-retert-05, + author = "John Tang Boyland and William Retert", + title = "Connecting Effects and Uniqueness with Adoption", + booktitle = popl, + year = "2005", + pages = "283--295", + URL = "http://www.cs.uwm.edu/~boyland/papers/connecting2.pdf", +} + +@InProceedings{bracha-cook-90, + author = "Gilad Bracha and William Cook", + title = "Mixin-based inheritance", + booktitle = oopsla, + pages = "303--311", + year = "1990", + URL = "http://www.bracha.org/oopsla90.ps", +} + +@TechReport{bracha-lindstrom-91, + author = "Gilad Bracha and Gary Lindstrom", + title = "Modularity Meets Inheritance", + institution = "University of Utah", + year = "1991", + number = "UUCS-91-017", + URL = "http://www.bracha.org/modularity-meets-inheritance.ps", +} + +@Book{bradley-manna-07, + author = "Aaron R. Bradley and Zohar Manna", + title = "The Calculus of Computation", + publisher = springer, + year = "2007", + URL = "http://www.springerlink.com/content/wv0127/?p=77473ec707e949ae8856c880fe4e7649&pi=0", +} + +@InProceedings{braibant-pous-11, + author = "Thomas Braibant and Damien Pous", + title = "Tactics for Reasoning Modulo {AC} in {Coq}", + booktitle = cpp, + year = "2011", + pages = "167--182", + publisher = springer, + series = lncs, + volume = "7086", + URL = "http://arxiv.org/abs/1106.4448", +} + +@Article{brandis-mossenbock-94, + author = "Marc M. Brandis and Hanspeter Mössenböck", + title = "Single-pass generation of static single-assignment + form for structured languages", + journal = toplas, + volume = "16", + number = "6", + year = "1994", + pages = "1684--1698", + URL = "ftp://ftp.ssw.uni-linz.ac.at/pub/Papers/Moe94.ps.gz", +} + +@Article{brandt-henglein-98, + author = "Michael Brandt and Fritz Henglein", + year = "1998", + title = "Coinductive axiomatization of recursive type equality + and subtyping", + journal = fundamenta, + pages = "309--338", + volume = "33", + URL = "ftp://ftp.diku.dk/diku/semantics/papers/D-353.ps.gz", +} + +@Article{breazu-tannen-91, + author = "Val Breazu-Tannen and Thierry Coquand and Carl A. + Gunter and Andre Scedrov", + title = "Inheritance as Implicit Coercion", + journal = ic, + year = "1991", + volume = "93", + number = "1", + pages = "172--221", + URL = "http://seclab.uiuc.edu/cgunter/publications/documents/Breazu-TannenCGS91.pdf", +} + +@InProceedings{brookes-04, + author = "Stephen D. Brookes", + title = "A Semantics for Concurrent Separation Logic", + booktitle = concur, + year = "2004", + pages = "16--34", + publisher = springer, + series = lncs, + volume = "3170", + URL = "http://dx.doi.org/10.1007/978-3-540-28644-8_2", +} + +@Article{brookes-ohearn-16, + author = "Stephen Brookes and Peter W. O'Hearn", + title = "Concurrent separation logic", + journal = "{SIGLOG} News", + volume = "3", + number = "3", + pages = "47--65", + year = "2016", + URL = "http://siglog.hosting.acm.org/wp-content/uploads/2016/07/siglog_news_9.pdf#page=49", +} + +@InProceedings{brotherston-cyclic-11, + author = "James Brotherston and Dino Distefano and Rasmus + Lerchedahl Petersen", + title = "Automated Cyclic Entailment Proofs in Separation + Logic", + booktitle = cade, + year = "2011", + pages = "131--146", + publisher = springer, + series = lncs, + volume = "6803", + URL = "http://www.eecs.qmul.ac.uk/~rusmus/articles/Cyclic.pdf", +} + +@TechReport{bruce-alii-binary-methods, + key = "Bruce, {\em et al.}", + author = "Kim Bruce and Luca Cardelli and Giuseppe Castagna and + The Hopkins Object Group and Gary T. Leavens and + Benjamin Pierce", + title = "On Binary Methods", + year = "1995", + institution = "Department of Computer Science, Iowa State + University", + number = "95-08a", + URL = "ftp://ftp.cs.iastate.edu/pub/techreports/TR95-08/TR.ps.Z", +} + +@Article{bruce-cardelli-pierce-99, + author = "Kim B. Bruce and Luca Cardelli and Benjamin C. + Pierce", + title = "Comparing Object Encodings", + journal = ic, + year = "1999", + volume = "155", + number = "1/2", + pages = "108--133", + URL = "http://www.cis.upenn.edu/~bcpierce/papers/compobj.ps", +} + +@Article{bruce-dicosmo-longo-92, + author = "Kim Bruce and Roberto {Di Cosmo} and Giuseppe Longo", + title = "Provable isomorphisms of types", + journal = mscs, + year = "1992", + volume = "2", + number = "2", + pages = "231--247", + URL = "http://www.dicosmo.org/Articles/MSCS.dvi", +} + +@Article{buchlovsky-thielecke-06, + author = "Peter Buchlovsky and Hayo Thielecke", + title = "A type-theoretic reconstruction of the Visitor + pattern", + journal = entcs, + volume = "155", + pages = "309--329", + year = "2006", + URL = "http://www.cs.bham.ac.uk/~hxt/research/mfps-visitors.pdf", +} + +@Unpublished{bugliesi-affine-15, + author = "Michele Bugliesi and Stefano Calzavara and Fabienne + Eigner and Matteo Maffei", + title = "Affine Refinement Types for Secure Distributed + Programming", + note = "To appear", + year = "2015", + URL = "http://www.sps.cs.uni-saarland.de/affine-rcf/resources/long.pdf", +} + +@InProceedings{bugliesi-crafa-dynamic-99, + author = "Michele Bugliesi and Silvia Crafa", + title = "Object Calculi for Dynamic Messages", + booktitle = fool, + year = "1999", +} + +@Article{bugliesi-pericas-02, + author = "Michele Bugliesi and Santiago M. + Peric{\'a}s-Geertsen", + title = "Type Inference for Variant Object Types", + journal = ic, + year = "2002", + volume = "177", + number = "1", + pages = "2--27", + URL = "http://www.dsi.unive.it/~michele/Papers/PS/SplitTypes-ic02.ps.gz", +} + +@Article{buisse-11, + author = "Alexandre Buisse and Lars Birkedal and Kristian + St{\o}vring", + title = "A Step-Indexed {Kripke} Model of Separation Logic for + Storable Locks", + journal = entcs, + volume = "276", + year = "2011", + pages = "121--143", + URL = "http://www.itu.dk/~birkedal/papers/locks.pdf", +} + +@InProceedings{bulwahn-08, + author = "Lukas Bulwahn and Alexander Krauss and Florian + Haftmann and Levent Erk{\"{o}}k and John Matthews", + title = "Imperative Functional Programming with + {Isabelle/HOL}", + booktitle = tphol, + pages = "134--149", + year = "2008", + series = lncs, + volume = "5170", + publisher = springer, + URL = "http://www21.in.tum.de/~krauss/imperative/imperative.pdf", +} + +@Article{buneman-ohori-96, + author = "Peter Buneman and Atsushi Ohori", + title = "Polymorphism and Type Inference in Database + Programming", + journal = tods, + year = "1996", + volume = "21", + number = "1", + pages = "30--76", + URL = "http://www.jaist.ac.jp/~ohori/research/tods96.pdf", +} + +@InProceedings{burstall-hope-80, + author = "R. M. Burstall and D. B. MacQueen and D. T. Sannella", + title = "{HOPE}: An experimental applicative language", + booktitle = lfp, + year = "1980", + pages = "136--143", + URL = "http://portal.acm.org/citation.cfm?id=802799", +} + +@Article{cai-paige-89, + author = "Jiazhen Cai and Robert Paige", + title = "Program derivation by fixed point computation", + journal = scp, + volume = "11", + number = "3", + year = "1989", + pages = "197--261", + URL = "http://cs.nyu.edu/paige/papers/fixpoint.ps", +} + +@InProceedings{caires-seco-13, + author = "Lu\'{\i}s Caires and Jo{\~a}o Costa Seco", + title = "The type discipline of behavioral separation", + booktitle = popl, + year = "2013", + pages = "275--286", + URL = "http://dx.doi.org/10.1145/2429069.2429103", +} + +@InProceedings{cakeml-new-16, + author = "Yong Kiam Tan and Magnus O. Myreen and Ramana Kumar + and Anthony C. J. Fox and Scott Owens and Michael + Norrish", + title = "A new verified compiler backend for {CakeML}", + booktitle = icfp, + pages = "60--73", + year = "2016", + URL = "https://cakeml.org/icfp16.pdf", +} + +@Article{calcagno-02, + author = "Cristiano Calcagno and Simon Helsen and Peter + Thiemann", + title = "Syntactic Type Soundness Results for the Region + Calculus", + journal = ic, + year = "2002", + volume = "173", + number = "2", + pages = "199--221", + URL = "http://www.dcs.qmw.ac.uk/~ccris/ftp/iac_calhelthi.pdf", +} + +@InProceedings{calcagno-11, + author = "Cristiano Calcagno and Dino Distefano", + title = "Infer: An Automatic Program Verifier for Memory Safety + of {C} Programs", + booktitle = nfm, + pages = "459--465", + year = "2011", + series = lncs, + volume = "6617", + publisher = springer, + URL = "http://www.eecs.qmul.ac.uk/~ddino/papers/nasa-infer.pdf", +} + +@InProceedings{calcagno-15, + author = "Cristiano Calcagno and Dino Distefano and + J{\'{e}}r{\'{e}}my Dubreil and Dominik Gabi and Pieter + Hooimeijer and Martino Luca and Peter W. O'Hearn and + Irene Papakonstantinou and Jim Purbrick and Dulma + Rodriguez", + title = "Moving Fast with Software Verification", + booktitle = nfm, + pages = "3--11", + year = "2015", + series = lncs, + volume = "9058", + publisher = springer, + URL = "https://research.facebook.com/publications/moving-fast-with-software-verification/", +} + +@Article{calcagno-closed-03, + author = "Cristiano Calcagno and Eugenio Moggi and Tim Sheard", + title = "Closed Types for a Safe Imperative {MetaML}", + journal = jfp, + year = "2003", + volume = "13", + number = "3", + pages = "545--571", + URL = "http://dx.doi.org/10.1017/S0956796802004598", +} + +@InProceedings{calcagno-distefano-ohearn-yang-09, + author = "Cristiano Calcagno and Dino Distefano and Peter W. + O'Hearn and Hongseok Yang", + title = "Compositional shape analysis by means of + bi-abduction", + booktitle = popl, + year = "2009", + pages = "289--300", + URL = "http://www.doc.ic.ac.uk/~ccris/ftp/popl09.pdf", +} + +@Article{calcagno-distefano-ohearn-yang-11, + author = "Cristiano Calcagno and Dino Distefano and Peter W. + O'Hearn and Hongseok Yang", + title = "Compositional Shape Analysis by Means of + Bi-Abduction", + journal = jacm, + volume = "58", + number = "6", + year = "2011", + URL = "http://www.doc.ic.ac.uk/~ccris/ftp/jacm-abduction.pdf", +} + +@InProceedings{calcagno-distefano-vafeiadis-09, + author = "Cristiano Calcagno and Dino Distefano and Viktor + Vafeiadis", + title = "Bi-abductive Resource Invariant Synthesis", + booktitle = aplas, + year = "2009", + pages = "259--274", + publisher = springer, + series = lncs, + volume = "5904", + URL = "http://www.eecs.qmul.ac.uk/~ddino/papers/resinvariant.pdf", +} + +@InProceedings{calcagno-inference-04, + author = "Cristiano Calcagno and Eugenio Moggi and Walid Taha", + title = "{ML}-Like Inference for Classifiers", + booktitle = esop, + year = "2004", + pages = "79--93", + series = lncs, + volume = "2986", + publisher = springer, + URL = "http://www.doc.ic.ac.uk/~ccris/ftp/esop04.pdf", +} + +@InProceedings{calcagno-local-07, + author = "Cristiano Calcagno and Peter W. O'Hearn and Hongseok + Yang", + title = "Local Action and Abstract Separation Logic", + booktitle = lics, + year = "2007", + pages = "366--378", + URL = "http://www.doc.ic.ac.uk/~ccris/ftp/asl-short.pdf", +} + +@InProceedings{calcagno-yang-ohearn-01, + author = "Cristiano Calcagno and Hongseok Yang and Peter W. + O'Hearn", + title = "Computability and Complexity Results for a Spatial + Assertion Language for Data Structures", + booktitle = aplas, + pages = "289--300", + year = "2001", + URL = "http://www.cs.ox.ac.uk/people/hongseok.yang/paper/decidability.ps", +} + +@Misc{caml-light, + author = "Xavier Leroy and Damien Doligez and Michel Mauny and + Pierre Weis", + title = "The {Caml} {Light} system, release 0.75", + year = "2002", + URL = "http://caml.inria.fr/", +} + +@InProceedings{carbonneaux-14, + author = "Quentin Carbonneaux and Jan Hoffmann and Tahina + Ramananandro and Zhong Shao", + title = "End-to-end verification of stack-space bounds for {C} + programs", + booktitle = pldi, + pages = "270--281", + year = "2014", + URL = "http://flint.cs.yale.edu/flint/publications/veristack.pdf", +} + +@InCollection{cardelli-97, + author = "Luca Cardelli", + title = "Type Systems", + booktitle = "The Computer Science and Engineering Handbook", + publisher = "CRC Press", + year = "1997", + editor = "Allen B. Tucker", + pages = "2208--2236", + URL = "http://research.microsoft.com/Users/luca/Papers/TypeSystems.pdf", +} + +@Article{cardelli-basic-87, + author = "Luca Cardelli", + title = "Basic polymorphic typechecking", + journal = scp, + year = "1987", + volume = "8", + number = "2", + pages = "147--172", + URL = "http://research.microsoft.com/Users/luca/Papers/BasicTypechecking.pdf", +} + +@TechReport{cardelli-extensible-94, + author = "Luca Cardelli and Florian Matthes and Martín Abadi", + title = "Extensible syntax with lexical scoping", + institution = decsrc, + year = "1994", + type = "Research Report", + number = "121", + URL = "http://gatekeeper.dec.com/pub/compaq/SRC/research-reports/SRC-121.ps.gz", +} + +@Article{cardelli-longo-91, + author = "Luca Cardelli and Giuseppe Longo", + title = "A semantic basis for {Quest}", + journal = jfp, + year = "1991", + volume = "1", + number = "4", + pages = "417--458", + URL = "http://research.microsoft.com/Users/luca/Papers/QuestSem.pdf", +} + +@InCollection{cardelli-mitchell-records-91, + author = "Luca Cardelli and John Mitchell", + title = "Operations on Records", + booktitle = taoop, + publisher = mitp, + editor = "Carl A. Gunter and John C. Mitchell", + year = "1994", + URL = "http://research.microsoft.com/Users/luca/Papers/Records.pdf", +} + +@Article{cardelli-multiple-88, + author = "Luca Cardelli", + title = "A Semantics of Multiple Inheritance", + journal = ic, + volume = "76", + number = "2/3", + year = "1988", + pages = "138--164", + URL = "http://research.microsoft.com/Users/luca/Papers/Inheritance.pdf", +} + +@Misc{cardelli-quest-91, + author = "Luca Cardelli", + title = "The {Quest} Language and System", + year = "1991", + URL = "http://research.microsoft.com/Users/luca/Notes/QuestManual.pdf", +} + +@InProceedings{cardelli-typeful-89, + author = "Luca Cardelli", + title = "Typeful programming", + booktitle = "Formal Description of Programming Concepts", + year = "1989", + series = "IFIP State of the Art Reports Series", + publisher = springer, + URL = "http://research.microsoft.com/Users/luca/Papers/TypefulProg.pdf", +} + +@Article{cardelli-wegner-85, + author = "Luca Cardelli and Peter Wegner", + title = "On Understanding Types, Data Abstraction, and + Polymorphism", + journal = surveys, + volume = "17", + number = "4", + pages = "471--522", + year = "1985", + URL = "http://research.microsoft.com/Users/luca/Papers/OnUnderstanding.pdf", +} + +@Article{cardone-02, + author = "Felice Cardone", + title = "A coinductive completeness proof for the equivalence + of recursive types", + journal = tcs, + volume = "275", + number = "1--2", + year = "2002", + pages = "575--587", + URL = "http://dx.doi.org/10.1016/S0304-3975(01)00298-5", + publisher = elsevier, +} + +@Article{cardone-coppo-91, + author = "Felice Cardone and Mario Coppo", + title = "Type inference with recursive types: syntax and + semantics", + journal = ic, + volume = "92", + number = "1", + year = "1991", + pages = "48--80", + URL = "http://dx.doi.org/10.1016/0890-5401(91)90020-3", +} + +@InProceedings{carette-finally-tagless-07, + author = "Jacques Carette and Oleg Kiselyov and Chung-chieh + Shan", + title = "Finally Tagless, Partially Evaluated", + booktitle = aplas, + year = "2007", + pages = "222--238", + publisher = springer, + series = lncs, + volume = "4807", + URL = "http://okmij.org/ftp/papers/tagless-final-APLAS.pdf", +} + +@Article{carette-gauss-05, + author = "Jacques Carette", + title = "{Gaussian} Elimination: a case study in efficient + genericity with {MetaOCaml}", + journal = scp, + year = "2005", + volume = "62", + number = "1", + pages = "3--24", + URL = "http://www.cas.mcmaster.ca/~carette/publications/ge.pdf", +} + +@InProceedings{carlier-04, + author = "Sébastien Carlier and Jeff Polakow and J. B. Wells + and A. J. Kfoury", + title = "{System E}: Expansion variables for flexible typing + with linear and non-linear types and intersection + types", + booktitle = esop, + year = "2004", + series = lncs, + publisher = springer, + URL = "http://www.macs.hw.ac.uk/~jbw/papers/Carlier+Polakow+Wells+Kfoury:System-E:ESOP-2004.pdf", +} + +@TechReport{carlier-wells-04, + author = "Sébastien Carlier and J. B. Wells", + title = "Type inference with expansion variables and + intersection types in {System E} and an exact + correspondence with $\beta$-reduction", + institution = "Heriot-Watt University", + year = "2004", + number = "HW-MACS-TR-0012", + URL = "http://www.macs.hw.ac.uk:8080/techreps/docs/files/HW-MACS-TR-0012.pdf", +} + +@Misc{cartwright-notes-00, + author = "Robert Cartwright", + title = "Notes on Object-Oriented Program Design", + URL = "http://www.cs.rice.edu/~cork/book/", + year = "2000", +} + +@InProceedings{castagna-ampersand-93, + author = "Giuseppe Castagna", + title = "${F}_{\leq}^{\&}$ : integrating parametric and ``ad + hoc'' second order polymorphism", + booktitle = "International Workshop on Database Programming + Languages", + year = "1993", + publisher = springer, + series = "Workshops in Computing", +} + +@Article{castagna-contravariance-95, + author = "Giuseppe Castagna", + title = "Covariance and Contravariance: Conflict without a + Cause", + journal = toplas, + volume = "17", + number = "3", + pages = "431--447", + year = "1995", + URL = "ftp://ftp.ens.fr/pub/di/users/castagna/covariance.ps.Z", +} + +@InProceedings{castagna-frisch-05, + author = "Giuseppe Castagna and Alain Frisch", + title = "A gentle introduction to semantic subtyping", + booktitle = ppdp, + year = "2005", + pages = "198--199", + URL = "http://www.pps.univ-paris-diderot.fr/~gc/papers/icalp-ppdp05.pdf", +} + +@InProceedings{cejtin-al-00, + author = "Henry Cejtin and Suresh Jagannathan and Stephen + Weeks", + title = "Flow-directed Closure Conversion for Typed Languages", + booktitle = esop, + publisher = springer, + series = lncs, + volume = "1782", + pages = "56--71", + year = "2000", + URL = "http://mlton.org/papers/00-esop.ps.gz", +} + +@InProceedings{cerco, + author = "Roberto M. Amadio and Nicholas Ayache and + Fran{\c{c}}ois Bobot and Jaap Boender and Brian + Campbell and Ilias Garnier and Antoine Madet and James + McKinna and Dominic P. Mulligan and Mauro Piccolo and + Randy Pollack and Yann R{\'{e}}gis{-}Gianas and Claudio + Sacerdoti Coen and Ian Stark and Paolo Tranquilli", + title = "Certified Complexity ({CerCo})", + booktitle = fopara, + pages = "1--18", + year = "2014", + series = lncs, + publisher = springer, + volume = "8552", + URL = "http://dx.doi.org/10.1007/978-3-319-12466-7_1", +} + +@Misc{cfml, + author = "Arthur Charguéraud", + title = "The {CFML} tool and library", + howpublished = "\url{http://www.chargueraud.org/softs/cfml/}", + year = "2016", +} + +@InProceedings{chakravarty-associated-05, + author = "Manuel M. T. Chakravarty and Gabriele Keller and Simon + L. {Peyton Jones} and Simon Marlow", + title = "Associated types with class", + booktitle = popl, + pages = "1--13", + year = "2005", + URL = "https://research.microsoft.com/en-us/um/people/simonpj/papers/assoc-types/assoc.pdf", +} + +@TechReport{chambers-leavens-96, + author = "Craig Chambers and Gary T. Leavens", + title = "{BeCecil}, a Core Object-Oriented Language with Block + Structure and Multimethods: Semantics and Typing", + institution = "University of Washington", + year = "1996", + number = "UW-CSE-96-12-02", + URL = "ftp://ftp.cs.washington.edu/pub/chambers/BeCecil.ps.gz", +} + +@Misc{chameleon, + author = "Andreas Rossberg and Peter J. Stuckey and Martin + Sulzmann and Jeremy Wazny", + title = "The {Chameleon} language", + URL = "http://taichi.ddns.comp.nus.edu.sg/taichiwiki/ChameleonHomePage", +} + +@InProceedings{chang-rival-08, + author = "Bor-Yuh Evan Chang and Xavier Rival", + title = "Relational inductive shape analysis", + booktitle = popl, + year = "2008", + pages = "247--260", + URL = "http://xisa.cs.colorado.edu/papers/popl08-relational.pdf", +} + +@PhdThesis{chargueraud-10, + author = "Arthur Charguéraud", + title = "Characteristic Formulae for Mechanized Program + Verification", + school = "Université Paris 7", + year = "2010", + URL = "http://www.chargueraud.org/research/2010/thesis/thesis_final.pdf", +} + +@InProceedings{chargueraud-10-cfml, + author = "Arthur Chargu{\'e}raud", + title = "Program Verification Through Characteristic Formulae", + booktitle = icfp, + year = "2010", + pages = "321--332", + URL = "http://www.chargueraud.org/research/2010/cfml/main.pdf", +} + +@InProceedings{chargueraud-11-cfml, + author = "Arthur Chargu{\'e}raud", + title = "Characteristic Formulae for the Verification of + Imperative Programs", + booktitle = icfp, + year = "2011", + pages = "418--430", + URL = "http://www.chargueraud.org/research/2011/cfml/main.pdf", +} + +@Misc{chargueraud-cfml, + author = "Arthur Charguéraud", + title = "Characteristic Formulae for the Verification of + Imperative Programs", + year = "2013", + note = "Unpublished. + \url{http://www.chargueraud.org/research/2013/cf/cf.pdf}", +} + +@Article{chargueraud-ln-11, + author = "Arthur Chargu{\'e}raud", + title = "The Locally Nameless Representation", + year = "2012", + journal = jar, + volume = "49", + number = "3", + pages = "363--408", + URL = "http://www.chargueraud.org/arthur/research/2009/ln/main.pdf", +} + +@InProceedings{chargueraud-pottier-08, + author = "Arthur Charguéraud and François Pottier", + title = "Functional Translation of a Calculus of Capabilities", + booktitle = icfp, + year = "2008", + pages = "213--224", + URL = "http://gallium.inria.fr/~fpottier/publis/chargueraud-pottier-capabilities.pdf", +} + +@InProceedings{chargueraud-pottier-15, + author = "Arthur Charguéraud and François Pottier", + title = "Machine-Checked Verification of the Correctness and + Amortized Complexity of an Efficient Union-Find + Implementation", + booktitle = itp, + year = "2015", + volume = "9236", + series = lncs, + publisher = springer, + pages = "137--153", + URL = "http://gallium.inria.fr/~fpottier/publis/chargueraud-pottier-uf.pdf", +} + +@TechReport{chen-al-99, + author = "Martin Odersky and Christoph Zenger and Matthias + Zenger and Gang Chen", + title = "A Functional View Of Join", + institution = "University of South Australia", + year = "1999", + number = "ACRC-99-016", + URL = "http://www.christoph-zenger.de/papers/tr-acrc-99-016.ps.gz", +} + +@InProceedings{chen-crash-16, + author = "Haogang Chen and Daniel Ziegler and Tej Chajed and + Adam Chlipala and M. Frans Kaashoek and Nickolai + Zeldovich", + title = "Using {Crash Hoare logic} for certifying the {FSCQ} + file system", + booktitle = sosp, + pages = "18--37", + year = "2015", + URL = "https://people.csail.mit.edu/nickolai/papers/chen-fscq.pdf", +} + +@InProceedings{chen-hudak-97, + author = "Chih-Ping Chen and Paul Hudak", + title = "Rolling your own mutable {ADT}---a connection between + linear types and monads", + booktitle = popl, + year = "1997", + pages = "54--66", + URL = "http://www.cs.yale.edu/homes/hudak-paul/hudak-dir/popl97.ps", +} + +@InProceedings{chen-shi-xi-04, + author = "Chiyan Chen and Rui Shi and Hongwei Xi", + title = "A Typeful Approach to Object-Oriented Programming with + Multiple Inheritance", + booktitle = padl, + publisher = springer, + series = lncs, + volume = "3057", + year = "2004", + URL = "http://www.cs.bu.edu/~hwxi/academic/papers/OBJwMI/OBJwMI.pdf", +} + +@InProceedings{chen-tarditi-05, + author = "Juan Chen and David Tarditi", + title = "A simple typed intermediate language for + object-oriented languages", + booktitle = popl, + year = "2005", + pages = "38--49", + URL = "http://research.microsoft.com/pubs/59934/lilc_popl05.pdf", +} + +@InProceedings{chen-xi-05, + author = "Chiyan Chen and Hongwei Xi", + title = "Combining Programming with Theorem Proving", + booktitle = icfp, + year = "2005", + pages = "66--77", + URL = "http://www.cs.bu.edu/~hwxi/academic/papers/icfp05.pdf", +} + +@InProceedings{chen-xi-icfp-03, + author = "Chiyan Chen and Hongwei Xi", + title = "Meta-Programming through Typeful Code Representation", + booktitle = icfp, + year = "2003", + pages = "275--286", + URL = "http://www.cs.bu.edu/~hwxi/academic/papers/icfp03.pdf", +} + +@InProceedings{chen-xi-pepm-03, + author = "Chiyan Chen and Hongwei Xi", + title = "Implementing Typeful Program Transformations", + booktitle = pepm, + year = "2003", + pages = "20--28", + URL = "http://www.cs.bu.edu/~hwxi/academic/papers/pepm03.pdf", +} + +@InProceedings{cheney-05, + author = "James Cheney", + title = "Scrap your nameplate", + booktitle = icfp, + year = "2005", + pages = "180--191", + URL = "http://homepages.inf.ed.ac.uk/jcheney/publications/cheney05icfp.pdf", +} + +@InProceedings{cheney-hinze-02, + author = "James Cheney and Ralf Hinze", + title = "A lightweight implementation of generics and + dynamics", + booktitle = hw, + year = "2002", + URL = "http://www.cs.cornell.edu/people/jcheney/papers/Dynamic-final.pdf", +} + +@TechReport{cheney-hinze-03, + author = "James Cheney and Ralf Hinze", + title = "First-Class Phantom Types", + institution = "Cornell University", + year = "2003", + number = "1901", + URL = "http://techreports.library.cornell.edu:8081/Dienst/UI/1.0/Display/cul.cis/TR2003-1901", +} + +@InProceedings{cheney-urban-04, + author = "James Cheney and Christian Urban", + title = "{$\alpha$Prolog}: {A} Logic Programming Language with + Names, Binding and $\alpha$-equivalence", + booktitle = iclp, + pages = "269--283", + year = "2004", + volume = "3132", + series = lncs, + publisher = springer, + URL = "http://www.cs.cornell.edu/people/jcheney/papers/alpnba.pdf", +} + +@InProceedings{cheng-blelloch-01, + author = "Perry Cheng and Guy E. Blelloch", + title = "A Parallel, Real-Time Garbage Collector", + booktitle = pldi, + pages = "125--136", + year = "2001", + URL = "https://www.cs.cmu.edu/~guyb/papers/gc2001.pdf", +} + +@Article{chin-khoo-01, + author = "Wei-Ngan Chin and Siau-Cheng Khoo", + title = "Calculating Sized Types", + journal = hosc, + volume = "14", + number = "2--3", + year = "2001", + pages = "261--300", + publisher = kluwer, + URL = "http://dx.doi.org/10.1023/A:1012996816178", +} + +@InProceedings{chitil-01, + author = "Olaf Chitil", + title = "Compositional Explanation of Types and Algorithmic + Debugging of Type Errors", + booktitle = icfp, + pages = "193--204", + year = "2001", + URL = "http://www-users.cs.york.ac.uk/~olaf/PUBLICATIONS/explainTypes.ps.gz", +} + +@InProceedings{chlipala-07, + author = "Adam Chlipala", + title = "A certified type-preserving compiler from lambda + calculus to assembly language", + booktitle = pldi, + year = "2007", + pages = "54--65", + URL = "http://www.cs.berkeley.edu/~adamc/papers/CtpcPLDI07/CtpcPLDI07.pdf", +} + +@InProceedings{chlipala-08, + author = "Adam Chlipala", + title = "Parametric higher-order abstract syntax for mechanized + semantics", + booktitle = icfp, + year = "2008", + pages = "143--156", + URL = "http://adam.chlipala.net/papers/PhoasICFP08/PhoasICFP08.pdf", +} + +@InProceedings{chlipala-15, + author = "Adam Chlipala", + title = "From Network Interface to Multithreaded Web + Applications: {A} Case Study in Modular Program + Verification", + booktitle = popl, + pages = "609--622", + year = "2015", + URL = "http://adam.chlipala.net/papers/BedrockPOPL15/BedrockPOPL15.pdf", +} + +@InProceedings{chlipala-bedrock-13, + author = "Adam Chlipala", + title = "The {Bedrock} structured programming system: combining + generative metaprogramming and {Hoare} logic in an + extensible program verifier", + booktitle = icfp, + pages = "391--402", + year = "2013", + URL = "http://adam.chlipala.net/papers/BedrockICFP13/BedrockICFP13.pdf", +} + +@Book{chlipala-cpdt-13, + author = "Adam Chlipala", + title = "Certified Programming and Dependent Types", + publisher = mitp, + year = "2013", + URL = "http://adam.chlipala.net/cpdt/", +} + +@InProceedings{chlipala-ynot-09, + author = "Adam Chlipala and Gregory Malecha and Greg Morrisett + and Avraham Shinnar and Ryan Wisnesky", + title = "Effective interactive proofs for higher-order + imperative programs", + booktitle = icfp, + year = "2009", + pages = "79--90", + URL = "http://ynot.cs.harvard.edu/papers/icfp09.pdf", +} + +@PhdThesis{choppella-02, + author = "Venkatesh Choppella", + title = "Unification Source-tracking with Application to + Diagnosis of Type Inference", + school = "Indiana University", + year = "2002", + URL = "http://www.cs.indiana.edu/cgi-bin/techreports/TRNNN.cgi?trnum=TR566", +} + +@InProceedings{chrzaszcz-98, + author = "Jacek Chrzaszcz", + title = "Polymorphic Subtyping Without Distributivity", + booktitle = mfcs, + pages = "346--355", + year = "1998", + series = lncs, + volume = "1450", + publisher = springer, + URL = "http://www.mimuw.edu.pl/~chrzaszc/papers/Chrzaszcz_Polymorphic-subtyping-without-distributivity.ps.gz", +} + +@Article{clarke-79, + author = "Edmund Clarke", + title = "Programming Language Constructs for Which It Is + Impossible To Obtain Good {Hoare} Axiom Systems", + journal = jacm, + volume = "26", + number = "1", + year = "1979", + pages = "129--147", + URL = "http://doi.acm.org/10.1145/322108.322121", +} + +@InProceedings{clarke-drossopoulou-02, + author = "Dave Clarke and Sophia Drossopoulou", + title = "Ownership, encapsulation and the disjointness of type + and effect", + booktitle = oopsla, + year = "2002", + pages = "292--310", + URL = "http://pubs.doc.ic.ac.uk/ownershipAndEffects/ownershipAndEffects.ps", +} + +@InProceedings{clarke-noble-potter-01, + author = "David G. Clarke and James Noble and John Potter", + title = "Simple Ownership Types for Object Containment", + booktitle = ecoop, + year = "2001", + pages = "53--76", + publisher = springer, + series = lncs, + volume = "2072", + URL = "http://www.cs.washington.edu/education/courses/cse590p/00wi/simple.pdf", +} + +@InProceedings{clarke-potter-noble-98, + author = "David G. Clarke and John M. Potter and James Noble", + title = "Ownership types for flexible alias protection", + booktitle = oopsla, + year = "1998", + pages = "48--64", + URL = "http://doi.acm.org/10.1145/286936.286947", +} + +@InCollection{clarke-survey-13, + author = "Dave Clarke and Johan {\"O}stlund and Ilya Sergey and + Tobias Wrigstad", + title = "Ownership Types: {A} Survey", + booktitle = "Aliasing in Object-Oriented Programming. Types, + Analysis and Verification", + year = "2013", + pages = "15--58", + publisher = springer, + series = lncs, + volume = "7850", + URL = "http://dx.doi.org/10.1007/978-3-642-36946-9_3", +} + +@InProceedings{clarke-wrigstad-03, + author = "Dave Clarke and Tobias Wrigstad", + title = "External Uniqueness Is Unique Enough", + booktitle = ecoop, + year = "2003", + pages = "176--200", + publisher = springer, + series = lncs, + volume = "2743", + URL = "https://lirias.kuleuven.be/bitstream/123456789/203436/1/euiue.pdf", +} + +@InProceedings{cleaveland-steffen-91, + author = "Rance Cleaveland and Bernhard Steffen", + title = "A linear-time model-checking algorithm for the + alternation-free modal mu-calculus", + booktitle = cav, + pages = "48--58", + year = "1991", + volume = "575", + series = lncs, + publisher = springer, + URL = "http://dx.doi.org/10.1007/3-540-55179-4_6", +} + +@InProceedings{clement-despeyroux-kahn-86, + author = "Dominique Cl{\'e}ment and Jo{\"e}lle Despeyroux and + Thierry Despeyroux and Gilles Kahn", + title = "A simple applicative language: Mini-{ML}", + booktitle = lfp, + year = "1986", + pages = "13--27", +} + +@InProceedings{clements-felleisen-03, + author = "John Clements and Matthias Felleisen", + title = "A Tail-Recursive Semantics for Stack Inspections", + booktitle = esop, + pages = "22--37", + year = "2003", + volume = "2618", + series = lncs, + publisher = springer, + URL = "http://www.ccs.neu.edu/scheme/pubs/esop2003-cf.ps.gz", +} + +@InProceedings{clochard-filliatre-paskevich-15, + title = "How to avoid proving the absence of integer + overflows", + author = "Martin Clochard and Jean-Christophe Filli{\^a}tre and + Andrei Paskevich", + URL = "https://hal.inria.fr/hal-01162661", + booktitle = vstte, + year = "2015", + pages = "94--109", + series = lncs, + volume = "9593", + publisher = springer, +} + +@InProceedings{clochard-marche-paskevich-14, + author = "Martin Clochard and Claude March{\'{e}} and Andrei + Paskevich", + title = "Verified programs with binders", + booktitle = plpv, + pages = "29--40", + year = "2014", + URL = "https://hal.inria.fr/hal-00913431", +} + +@InProceedings{coblenz-16, + author = "Michael J. Coblenz and Joshua Sunshine and Jonathan + Aldrich and Brad A. Myers and Sam Weber and Forrest + Shull", + title = "Exploring language support for immutability", + booktitle = icse, + pages = "736--747", + year = "2016", + URL = "http://www.cs.cmu.edu/~aldrich/papers/icse16-immutability.pdf", +} + +@Article{cohen-search-06, + author = "Albert Cohen and Sébastien Donadio and Maria-Jesus + Garzaran and Christoph Herrmann and Oleg Kiselyov and + David Padua", + title = "In search of a program generator to implement generic + transformations for high-performance computing", + journal = scp, + year = "2006", + volume = "62", + number = "1", + pages = "25--46", + URL = "http://www-rocq.inria.fr/~acohen/publications/CDGHKP06.ps.gz", +} + +@InProceedings{cohen-vcc-09, + author = "Ernie Cohen and Markus Dahlweid and Mark A. Hillebrand + and Dirk Leinenbach and Michal Moskal and Thomas Santen + and Wolfram Schulte and Stephan Tobies", + title = "{VCC}: {A} Practical System for Verifying Concurrent + {C}", + booktitle = tphol, + year = "2009", + pages = "23--42", + publisher = springer, + series = lncs, + volume = "5674", + URL = "http://research.microsoft.com/apps/pubs/default.aspx?id=117859", +} + +@InProceedings{colazzo-ghelli-99, + author = "Dario Colazzo and Giorgio Ghelli", + title = "Subtyping Recursive Types in {Kernel Fun}", + booktitle = lics, + pages = "137--146", + year = "1999", +} + +@TechReport{collins-shao-02, + author = "Gregory D. Collins and Zhong Shao", + title = "Intensional Analysis of Higher-Kinded Recursive + Types", + institution = "Yale University", + year = "2002", + number = "YALEU/DCS/TR-1240", + URL = "http://flint.cs.yale.edu/flint/publications/collins02-ita-tr.pdf", +} + +@InProceedings{colmerauer-84, + author = "Alain Colmerauer", + title = "Equations and Inequations on Finite and Infinite + Trees", + booktitle = "International Conference on Fifth Generation Computer + Systems (FGCS)", + pages = "85--99", + year = "1984", +} + +@Article{color, + author = "Frédéric Blanqui and Adam Koprowski", + title = "{CoLoR}: a Coq library on well-founded rewrite + relations and its application to the automated + verification of termination certificates", + journal = mscs, + year = "2011", + volume = "21", + number = "4", + pages = "827--859", + URL = "https://who.rocq.inria.fr/Frederic.Blanqui/papers/mscs11.pdf", +} + +@InProceedings{comon-93, + author = "Hubert Comon", + title = "Constraints in Term Algebras (Short Survey)", + booktitle = amast, + year = "1993", + publisher = springer, + series = "Workshops in Computing", + URL = "http://www.lsv.ens-cachan.fr/~comon/ftp.articles/amast93.ps", +} + +@Article{comon-lescanne-89, + author = "Hubert Comon and Pierre Lescanne", + title = "Equational Problems and Disunification", + journal = jsc, + year = "1989", + volume = "7", + pages = "371--425", + URL = "http://perso.ens-lyon.fr/pierre.lescanne/PUBLICATIONS/jsc-diseq.pdf", +} + +@Misc{compcert, + author = "Xavier Leroy", + title = "The {CompCert C} compiler", + year = "2015", + howpublished = "\url{http://compcert.inria.fr/}", +} + +@InProceedings{conchon-filliatre-07, + author = "Sylvain Conchon and Jean{-}Christophe + Filli{\^{a}}tre", + title = "A persistent union-find data structure", + booktitle = ml, + pages = "37--46", + year = "2007", + URL = "https://www.lri.fr/~filliatr/puf/", +} + +@Book{conchon-filliatre-ocaml-14, + author = "Sylvain Conchon et Jean-Christophe Filliâtre", + title = "Apprendre à programmer avec {OCaml}: Algorithmes et + structures de données", + publisher = "Eyrolles", + year = "2014", + URL = "http://programmer-avec-ocaml.lri.fr/", +} + +@InProceedings{conchon-kanig-lescuyer-08, + author = "Sylvain Conchon and Johannes Kanig and Stéphane + Lescuyer", + title = "\textsc{Sat-Micro}: petit mais costaud!", + booktitle = jfla, + year = "2008", + URL = "http://www.lri.fr/~conchon/publis/conchon-jfla08.ps", +} + +@InProceedings{conchon-le-fessant-99, + title = "Jocaml: Mobile Agents for {Objective-Caml}", + author = "Sylvain Conchon and Fabrice Le Fessant", + booktitle = "International Symposium on Agent Systems and + Applications and International Symposium on Mobile + Agents (ASA/MA)", + year = "1999", + pages = "22--29", + URL = "http://para.inria.fr/~conchon/publis/conchon-lefessant-asama99.ps.gz", +} + +@InProceedings{conchon-pottier-01, + author = "Sylvain Conchon and François Pottier", + title = "{JOIN(X)}: Constraint-Based Type Inference for the + Join-Calculus", + booktitle = esop, + publisher = springer, + series = lncs, + volume = "2028", + pages = "221--236", + year = "2001", + URL = "http://gallium.inria.fr/~fpottier/publis/conchon-fpottier-esop01.ps.gz", +} + +@TechReport{considine-00, + author = "Jeffrey Considine", + title = "Efficient Hash-Consing of Recursive Types", + institution = "Boston University", + year = "2000", + number = "2000-006", + URL = "http://www.cs.bu.edu/techreports/pdf/2000-006-hashconsing-recursive-types.pdf", +} + +@InProceedings{cook-09, + author = "William R. Cook", + title = "On understanding data abstraction, revisited", + booktitle = oopsla, + year = "2009", + pages = "557--572", + URL = "http://www.cs.utexas.edu/~wcook/Drafts/2009/essay.pdf", +} + +@InProceedings{cook-71, + author = "Stephen A. Cook", + title = "The Complexity of Theorem-Proving Procedures", + booktitle = stoc, + year = "1971", + pages = "151--158", + URL = "http://doi.acm.org/10.1145/800157.805047", +} + +@InProceedings{cook-tractable-11, + author = "Byron Cook and Christoph Haase and Jo{\"{e}}l Ouaknine + and Matthew J. Parkinson and James Worrell", + title = "Tractable Reasoning in a Fragment of Separation + Logic", + booktitle = concur, + pages = "235--249", + year = "2011", + series = lncs, + volume = "6901", + publisher = springer, + URL = "http://www.cs.ox.ac.uk/files/4048/sl.pdf", +} + +@TechReport{cooper-harvey-kennedy-04, + author = "Keith D. Cooper and Timothy J. Harvey and Ken + Kennedy", + title = "Iterative Data-flow Analysis, Revisited", + institution = "Rice University", + year = "2004", + number = "TR04-432", + URL = "http://www.cs.rice.edu/~harv/my_papers/worklist.pdf", +} + +@Article{coppo-dezani-80, + author = "Mario Coppo and Mariangiola Dezani-Ciancaglini", + title = "An extension of the basic functionality theory for the + $\lambda$-calculus", + journal = "Notre Dame J. Formal Logic", + year = "1980", + volume = "21", + number = "4", + pages = "685--693", +} + +@Manual{coq, + author = "{The {Coq} development team}", + title = "The {Coq} Proof Assistant", + year = "2016", + URL = "http://coq.inria.fr/", +} + +@Book{coqart, + author = "Yves Bertot and Pierre Cast{\'{e}}ran", + title = "Interactive Theorem Proving and Program Development -- + {Coq'Art}: The Calculus of Inductive Constructions", + series = "Texts in Theoretical Computer Science. An {EATCS} + Series", + publisher = springer, + year = "2004", + URL = "https://www.labri.fr/perso/casteran/CoqArt/coqartF.pdf", +} + +@InProceedings{coquand-86, + author = "Thierry Coquand", + title = "An analysis of {Girard}'s paradox", + booktitle = lics, + pages = "227--236", + year = "1986", + URL = "http://hal.inria.fr/docs/00/07/60/23/PDF/RR-0531.pdf", +} + +@Book{cormen-en, + author = "Thomas H. Cormen and Charles E. Leiserson and Ronald + L. Rivest and Clifford Stein", + title = "Introduction to Algorithms (Third Edition)", + publisher = "MIT Press", + year = "2009", + URL = "http://mitpress.mit.edu/catalog/item/ + default.asp?ttype=2&tid=11866", +} + +@Book{cormen-fr, + author = "Thomas H. Cormen and Charles E. Leiserson and Ronald + L. Rivest and Clifford Stein", + title = "Algorithmique (Troisième Édition)", + publisher = "Dunod", + year = "2010", + series = "Sciences Sup", + URL = "http://www.dunod.com/informatique-multimedia/fondements-de-linformatique/algorithmique/algorithmique", + note = "Traduction française", +} + +@Article{courcelle-fundamental-trees, + title = "Fundamental Properties of Infinite Trees", + author = "Bruno Courcelle", + pages = "95--169", + journal = tcs, + year = "1983", + volume = "25", + number = "2", +} + +@InCollection{cousot-90, + author = "Patrick Cousot", + title = "Methods and Logics for Proving Programs", + booktitle = "Formal Models and Semantics", + series = "Handbook of Theoretical Computer Science", + publisher = elsevier, + year = "1990", + pages = "841--993", + volume = "B", + chapter = "15", + URL = "http://www.di.ens.fr/~cousot/publications.www/Cousot-HTCS-vB-FMS-c15-p843--993-1990.pdf.gz", +} + +@InProceedings{cousot-cousot-77, + author = "Patrick Cousot and Radhia Cousot", + title = "Abstract interpretation: a unified lattice model for + static analysis of programs by construction or + approximation of fixpoints", + pages = "238--252", + booktitle = popl, + year = "1977", + URL = "http://www.di.ens.fr/~cousot/publications.www/CousotCousot-POPL-77-ACM-p238--252-1977.pdf", +} + +@Article{cousot-cousot-constructive-79, + author = "Patrick Cousot and Radhia Cousot", + title = "Constructive Versions of {Tarski}'s Fixed Point + Theorems", + journal = "Pacific Journal of Mathematics", + volume = "81", + number = "1", + pages = "43--57", + year = "1979", + URL = "http://www.di.ens.fr/~cousot/publications.www/CousotCousot-PacJMath-82-1-1979.pdf", +} + +@InProceedings{cousot-gentle-09, + author = "Patrick Cousot and Radhia Cousot", + title = "A gentle introduction to formal verification of + computer systems by abstract interpretation", + booktitle = "Logics and Languages for Reliability and Security", + series = "{NATO} Science Series {III}: Computer and Systems + Sciences", + editor = "J.~Esparza and O.~Grumberg and M.~Broy", + publisher = "IOS Press", + year = "2010", + pages = "1--29", + URL = "http://www.di.ens.fr/~cousot/COUSOTpapers/MARKTOBERDORF-09.shtml", +} + +@InProceedings{cousot-sba-95, + author = "Patrick Cousot and Radhia Cousot", + title = "Formal Language, Grammar and Set-Constraint-Based + Program Analysis by Abstract Interpretation", + pages = "170--181", + booktitle = fpca, + publisher = acmp, + year = "1995", +} + +@InProceedings{coutts-07, + author = "Duncan Coutts and Roman Leshchinskiy and Don Stewart", + title = "Stream fusion: from lists to streams to nothing at + all", + booktitle = icfp, + pages = "315--326", + year = "2007", + URL = "http://dx.doi.org/10.1145/1291151.1291199", +} + +@InProceedings{crank-felleisen-91, + author = "Erik Crank and Matthias Felleisen", + title = "Parameter-Passing and the Lambda Calculus", + booktitle = popl, + pages = "233--244", + year = "1991", + URL = "http://www.ccs.neu.edu/scheme/pubs/popl91-cf.ps.gz", +} + +@TechReport{crary-99, + author = "Karl Crary", + title = "Simple, Efficient Object Encoding using Intersection + Types", + institution = "Carnegie Mellon University", + year = "1999", + number = "CMU-CS-99-100", + URL = "http://www-2.cs.cmu.edu/~crary/papers/1999/orei/orei.ps.gz", +} + +@InProceedings{crary-cc-99, + author = "Karl Crary and David Walker and Greg Morrisett", + title = "Typed Memory Management in a Calculus of + Capabilities", + booktitle = popl, + pages = "262--275", + year = "1999", + URL = "http://www.cs.cornell.edu/talc/papers/capabilities.pdf", +} + +@Article{crary-intensional-02, + author = "Karl Crary and Stephanie Weirich and Greg Morrisett", + title = "Intensional Polymorphism in Type Erasure Semantics", + journal = jfp, + year = "2002", + volume = "12", + number = "6", + pages = "567--600", + URL = "http://www-2.cs.cmu.edu/~crary/papers/2002/typepass/typepass.ps", +} + +@InProceedings{crary-intensional-98, + author = "Karl Crary and Stephanie Weirich and Greg Morrisett", + title = "Intensional Polymorphism in Type-Erasure Semantics", + booktitle = icfp, + pages = "301--313", + year = "1998", + URL = "http://www.cis.upenn.edu/~sweirich/papers/typepass/typepass.ps", +} + +@PhdThesis{crary-phd-98, + author = "Karl Crary", + title = "Type-Theoretic Methodology for Practical Programming + Languages", + school = "Cornell University", + year = "1998", + URL = "http://www.cs.cmu.edu/~crary/papers/1998/thesis/thesis.ps.gz", +} + +@TechReport{crary-standard-09, + author = "Karl Crary", + title = "A Simple Proof of Call-by-Value Standardization", + institution = "Carnegie Mellon University", + year = "2009", + type = "Technical Report", + number = "CMU-CS-09-137", + URL = "https://www.cs.cmu.edu/~crary/papers/2009/standard.pdf", +} + +@InProceedings{crary-weirich-00, + author = "Karl Crary and Stephanie Weirich", + title = "Resource bound certification", + booktitle = popl, + year = "2000", + pages = "184--198", + URL = "http://www.cs.cornell.edu/talc/papers/resource_bound/res.pdf", +} + +@InProceedings{crary-weirich-99, + author = "Karl Crary and Stephanie Weirich", + title = "Flexible Type Analysis", + booktitle = icfp, + pages = "233--248", + year = "1999", + URL = "http://www-2.cs.cmu.edu/~crary/papers/1999/lx/lx.ps.gz", +} + +@PhdThesis{cretin-14, + author = "Julien Cretin", + title = "Erasable coercions: a unified approach to type + systems", + school = "Université Paris Diderot", + year = "2014", + URL = "http://tel.archives-ouvertes.fr/tel-00940511", +} + +@InProceedings{cretin-remy-12, + author = "Julien Cretin and Didier R{\'e}my", + title = "On the power of coercion abstraction", + booktitle = popl, + year = "2012", + pages = "361--372", + URL = "http://gallium.inria.fr/~remy/coercions/Cretin-Remy:coercions@popl2012.pdf", +} + +@PhdThesis{curtis-90, + author = "Pavel Curtis", + title = "Constrained Quantification in Polymorphic Type + Analysis", + school = "Cornell University", + year = "1990", + URL = "http://www.parc.xerox.com/company/history/publications/bw-ps-gz/csl90-1.ps.gz", +} + +@InProceedings{cyclone-regions-02, + author = "Dan Grossman and Greg Morrisett and Trevor Jim and + Michael Hicks and Yanling Wang and James Cheney", + title = "Region-Based Memory Management in {Cyclone}", + booktitle = pldi, + pages = "282--293", + year = "2002", + URL = "http://www.cs.cornell.edu/projects/cyclone/papers/cyclone-regions.pdf", +} + +@InProceedings{dafny, + author = "K. Rustan M. Leino", + title = "{Dafny}: An Automatic Program Verifier for Functional + Correctness", + booktitle = lpar, + pages = "348--370", + year = "2010", + volume = "6355", + series = lncs, + publisher = springer, + URL = "http://research.microsoft.com/en-us/um/people/leino/papers/krml203.pdf", +} + +@PhdThesis{damas-85, + author = "Luis Damas", + title = "Type Assignment in Programming Languages", + school = "University of Edinburgh", + year = "1985", +} + +@InProceedings{damas-milner-82, + author = "Luis Damas and Robin Milner", + title = "Principal type-schemes for functional programs", + booktitle = popl, + year = "1982", + pages = "207--212", + URL = "http://doi.acm.org/10.1145/582153.582176", +} + +@InProceedings{damm-josko-83, + author = "Werner Damm and Bernhard Josko", + title = "A Sound and Relatively$^*$ Complete Axiomatization of + {Clarke's} Language {L4}", + booktitle = "Logic of Programs", + pages = "161--175", + year = "1983", + volume = "164", + series = lncs, + publisher = springer, + URL = "http://dx.doi.org/10.1007/3-540-12896-4_362", +} + +@InProceedings{danielsson-06, + author = "Nils Anders Danielsson and John Hughes and Patrik + Jansson and Jeremy Gibbons", + title = "Fast and loose reasoning is morally correct", + booktitle = popl, + year = "2006", + pages = "206--217", + URL = "http://web.comlab.ox.ac.uk/oucl/work/jeremy.gibbons/publications/fast+loose.pdf", +} + +@InProceedings{danielsson-08, + author = "Nils Anders Danielsson", + title = "Lightweight Semiformal Time Complexity Analysis for + Purely Functional Data Structures", + booktitle = popl, + year = "2008", + URL = "http://www.cse.chalmers.se/~nad/publications/danielsson-popl2008.pdf", +} + +@InProceedings{danielsson-altenkirch-10, + author = "Nils Anders Danielsson and Thorsten Altenkirch", + title = "Subtyping, Declaratively", + booktitle = mpc, + year = "2010", + pages = "100--118", + publisher = springer, + series = lncs, + volume = "6120", + URL = "http://www.cse.chalmers.se/~nad/publications/danielsson-altenkirch-subtyping.pdf", +} + +@InProceedings{danner-13, + author = "Norman Danner and Jennifer Paykin and James S. Royer", + title = "A static cost analysis for a higher-order language", + booktitle = plpv, + pages = "25--34", + year = "2013", + URL = "http://cis.upenn.edu/~jpaykin/papers/danner_PLPV_2013.pdf", +} + +@TechReport{danvy-98, + author = "Olivier Danvy", + title = "Functional Unparsing", + institution = "BRICS", + year = "1998", + number = "RS-98-12", + URL = "http://www.brics.dk/RS/98/12/", +} + +@TechReport{danvy-nielsen-01, + author = "Olivier Danvy and Lasse R. Nielsen", + title = "Defunctionalization at Work", + year = "2001", + institution = "BRICS", + number = "RS-01-23", + URL = "http://www.brics.dk/RS/01/23/", +} + +@Article{danvy-nielsen-03, + author = "Olivier Danvy and Lasse R. Nielsen", + title = "A first-order one-pass {CPS} transformation", + journal = tcs, + volume = "308", + number = "1--3", + pages = "239--257", + year = "2003", + URL = "http://dx.doi.org/10.1016/S0304-3975(02)00733-8", +} + +@InProceedings{danvy-nielsen-ppdp-01, + author = "Olivier Danvy and Lasse R. Nielsen", + title = "Defunctionalization at Work", + pages = "162--174", + booktitle = ppdp, + year = "2001", + URL = "http://doi.acm.org/10.1145/773184.773202", +} + +@Article{danvy-pearl-98, + author = "Olivier Danvy", + title = "Functional Unparsing", + journal = jfp, + year = "1998", + volume = "8", + number = "6", + pages = "621--625", + URL = "http://dx.doi.org/10.1017/S0956796898003104", +} + +@PhdThesis{dao-00, + author = "Thi Bich Hanh Dao", + title = "{R}ésolution de contraintes du premier ordre dans la + théorie des arbres finis ou infinis", + school = "Université de la Méditerranée", + year = "2000", + URL = "http://www.univ-orleans.fr/SCIENCES/LIFO/Members/dao/papers/ts4dec.ps.gz", +} + +@InProceedings{dargaye-leroy-cps-07, + author = "Zaynah Dargaye and Xavier Leroy", + title = "Mechanized verification of {CPS} transformations", + booktitle = lpar, + year = "2007", + series = lnai, + volume = "4790", + publisher = springer, + pages = "211--225", + URL = "http://gallium.inria.fr/~xleroy/publi/cps-dargaye-leroy.pdf", +} + +@TechReport{davies-05, + author = "Rowan Davies", + title = "Practical Refinement-Type Checking", + institution = "School of Computer Science, Carnegie Mellon + University", + year = "2005", + number = "CMU-CS-05-110", + URL = "http://reports-archive.adm.cs.cmu.edu/anon/2005/CMU-CS-05-110.pdf", +} + +@InProceedings{davies-pfenning-00, + author = "Rowan Davies and Frank Pfenning", + title = "Intersection types and computational effects", + booktitle = icfp, + year = "2000", + pages = "198--208", + URL = "http://www.cs.cmu.edu/~fp/papers/icfp00.pdf", +} + +@Article{davis-logemann-loveland-62, + author = "Martin Davis and George Logemann and Donald Loveland", + title = "A machine program for theorem-proving", + journal = cacm, + volume = "5", + number = "7", + year = "1962", + pages = "394--397", + URL = "http://doi.acm.org/10.1145/368273.368557", +} + +@Article{davis-putnam-60, + author = "Martin Davis and Hilary Putnam", + title = "A Computing Procedure for Quantification Theory", + journal = jacm, + volume = "7", + number = "3", + year = "1960", + pages = "201--215", + URL = "http://doi.acm.org/10.1145/321033.321034", +} + +@Article{de-bruijn-72, + author = "Nicolaas G. de Bruijn", + title = "Lambda-Calculus Notation with Nameless Dummies: a Tool + for Automatic Formula Manipulation with Application to + the {Church-Rosser} Theorem", + journal = "Indag. Math.", + volume = "34", + number = "5", + year = "1972", + pages = "381--392", +} + +@InProceedings{delaware-3mt-13, + author = "Benjamin Delaware and Steven Keuchel and Tom + Schrijvers and Bruno C. d. S. Oliveira", + title = "Modular monadic meta-theory", + booktitle = icfp, + year = "2013", + pages = "319--330", + URL = "http://ropas.snu.ac.kr/~bruno/papers/3MT.pdf", +} + +@InProceedings{delaware-mtc-13, + author = "Benjamin Delaware and Bruno C. d. S. Oliveira and Tom + Schrijvers", + title = "Meta-theory à La Carte", + booktitle = popl, + year = "2013", + pages = "207--218", + URL = "http://people.csail.mit.edu/bendy/MTC/MTC.pdf", +} + +@InProceedings{delbianco-nanevski-13, + author = "Germ{\'{a}}n Andr{\'{e}}s Delbianco and Aleksandar + Nanevski", + title = "{Hoare}-style reasoning with (algebraic) + continuations", + booktitle = icfp, + pages = "363--376", + year = "2013", + URL = "http://software.imdea.org/~aleks/papers/callcc/icfp2013.pdf", +} + +@InProceedings{deline-faehndrich-01, + author = "Robert DeLine and Manuel Fähndrich", + title = "Enforcing High-Level Protocols in Low-Level Software", + booktitle = pldi, + pages = "59--69", + year = "2001", + URL = "http://research.microsoft.com/apps/pubs/default.aspx?id=67457", +} + +@InProceedings{deline-faehndrich-04, + author = "Robert DeLine and Manuel Fähndrich", + title = "Typestates for objects", + booktitle = ecoop, + pages = "465--490", + year = "2004", + volume = "3086", + series = lncs, + publisher = springer, + URL = "http://research.microsoft.com/apps/pubs/default.aspx?id=67463", +} + +@TechReport{deline-faehndrich-fugue-04, + author = "Robert DeLine and Manuel Fähndrich", + title = "The {Fugue} Protocol Checker: Is Your Software + Baroque?", + institution = "Microsoft Research", + year = "2004", + number = "MSR-TR-2004-07", + URL = "http://research.microsoft.com/apps/pubs/default.aspx?id=67458", +} + +@InProceedings{delphin-08, + author = "Adam Poswolsky and Carsten Schürmann", + title = "Practical Programming with Higher-Order Encodings and + Dependent Types", + booktitle = esop, + pages = "93--107", + year = "2008", + volume = "4960", + series = lncs, + publisher = springer, + URL = "http://cs-www.cs.yale.edu/homes/delphin/files/delphinESOP08.pdf", +} + +@Article{delphin-09, + author = "Adam Poswolsky and Carsten Schürmann", + title = "System Description: {Delphin} -- {A} Functional + Programming Language for Deductive Systems", + journal = entcs, + volume = "228", + year = "2009", + pages = "113--120", + URL = "http://www.itu.dk/~carsten/papers/lfmtp-08.pdf", +} + +@Article{dencker-84, + author = "Peter Dencker and Karl Dürre and Johannes Heuft", + title = "Optimization of parser tables for portable compilers", + journal = toplas, + volume = "6", + number = "4", + year = "1984", + pages = "546--572", + URL = "http://doi.acm.org/10.1145/1780.1802", +} + +@Article{denning-77, + author = "Dorothy E. Denning and Peter J. Denning", + title = "Certification of Programs for Secure Information + Flow", + journal = cacm, + volume = "20", + number = "7", + pages = "504--513", + year = "1977", +} + +@Book{denning-82, + author = "Dorothy E. Denning", + title = "Cryptography and Data Security", + publisher = aw, + year = "1982", +} + +@InProceedings{dennis-sat-06, + author = "Greg Dennis and Felix Change and Daniel Jackson", + title = "Modular Verification of Code with {SAT}", + booktitle = issta, + year = "2006", + URL = "http://sdg.csail.mit.edu/pubs/2006/dennis_modular.pdf", +} + +@Article{denny-malloy-10, + author = "Joel E. Denny and Brian A. Malloy", + title = "The {IELR(1)} algorithm for generating minimal {LR(1)} + parser tables for non-{LR(1)} grammars with conflict + resolution", + journal = scp, + volume = "75", + number = "11", + pages = "943--979", + year = "2010", + URL = "http://dx.doi.org/10.1016/j.scico.2009.08.001", +} + +@Article{deremer-pennello-82, + author = "Frank DeRemer and Thomas Pennello", + title = "Efficient Computation of ${LALR}(1)$ Look-Ahead Sets", + journal = toplas, + volume = "4", + number = "4", + year = "1982", + pages = "615--649", + URL = "http://doi.acm.org/10.1145/69622.357187", +} + +@TechReport{deremer-phd-69, + author = "Franklin Lewis DeRemer", + title = "Practical Translators for {LR(k)} Languages", + institution = "Massachusetts Institute of Technology", + year = "1969", + type = "Technical Report", + number = "MIT-LCS-TR-065", + URL = "http://publications.csail.mit.edu/lcs/pubs/pdf/MIT-LCS-TR-065.pdf", +} + +@Article{deremer-slr-71, + author = "Franklin L. DeRemer", + title = "Simple ${LR}(k)$ grammars", + journal = cacm, + year = "1971", + volume = "14", + number = "7", + pages = "453--460", + URL = "http://dx.doi.org/10.1145/362619.362625", +} + +@Book{design-patterns, + author = "Erich Gamma and Richard Helm and Ralph Johnson and + John Vlissides", + title = "Design Patterns: Elements of Reusable Object-oriented + Software", + year = "1995", + publisher = aw, +} + +@TechReport{detlefs-98, + author = "David L. Detlefs and K. Rustan M. Leino and Greg + Nelson and James B. Saxe", + title = "Extended static checking", + institution = "Compaq SRC", + year = "1998", + type = "Research Report", + number = "159", + URL = "ftp://gatekeeper.research.compaq.com/pub/DEC/SRC/research-reports/SRC-159.pdf", +} + +@TechReport{detlefs-wrestling-98, + author = "David L. Detlefs and K. Rustan M. Leino and Greg + Nelson", + title = "Wrestling with rep exposure", + institution = "SRC", + year = "1998", + type = "Research Report", + number = "156", + URL = "http://www.hpl.hp.com/techreports/Compaq-DEC/SRC-RR-156.pdf", +} + +@Book{dicosmo-95, + author = "Roberto {Di Cosmo}", + title = "Isomorphisms of types: from $\lambda$-calculus to + information retrieval and language design", + series = "Progress in Theoretical Computer Science", + publisher = "Birkhauser", + year = "1995", + URL = "http://www.pps.jussieu.fr/~dicosmo/Publications/ISObook.html", +} + +@Article{dicosmo-jfp-93, + author = "Roberto {Di Cosmo}", + title = "Deciding Type isomorphisms in a type assignment + framework", + journal = jfp, + year = "1993", + volume = "3", + number = "3", + pages = "485--525", + URL = "http://www.dicosmo.org/Articles/JFP94.dvi", +} + +@Article{dietl-drossopoulou-mueller-11, + author = "Werner Dietl and Sophia Drossopoulou and Peter + M{\"u}ller", + title = "Separating ownership topology and encapsulation with + generic universe types", + journal = toplas, + volume = "33", + number = "6", + year = "2011", + pages = "20", + URL = "http://pm.inf.ethz.ch/publications/getpdf.php?bibname=Own&id=DietlDrossopoulouMueller11.pdf", +} + +@Article{dietl-mueller-05, + author = "Werner Dietl and Peter M{\"u}ller", + title = "Universes: Lightweight Ownership for {JML}", + journal = jot, + year = "2005", + volume = "4", + number = "8", + pages = "5--32", + URL = "http://www.jot.fm/issues/issue_2005_10/article1.pdf", +} + +@Article{dijkstra-59, + author = "E. W. Dijkstra", + title = "A Note on Two Problems in Connection with Graphs", + journal = "Numerische Mathematik", + year = "1959", + volume = "1", + pages = "269--271", +} + +@Article{dijkstra-75, + author = "Edsger W. Dijkstra", + title = "Guarded commands, nondeterminacy and formal derivation + of programs", + journal = "Communications of the ACM", + volume = "18", + number = "8", + year = "1975", + pages = "453--457", + URL = "http://doi.acm.org/10.1145/360933.360975", +} + +@PhdThesis{dimock-02, + author = "Allyn Dimock", + title = "Type- and Flow-Directed Compilation for Specialized + Data Representations", + school = "Harvard University", + year = "2002", + URL = "http://www.cs.uml.edu/~dimock/thesis.ps.gz", +} + +@InProceedings{dimock-al-01, + author = "Allyn Dimock and Ian Westmacott and Robert Muller and + Franklyn Turbak and J. B. Wells", + title = "Functioning without closure: type-safe customized + function representations for {Standard ML}", + booktitle = icfp, + year = "2001", + URL = "http://puma.wellesley.edu/~fturbak/pubs/icfp01.ps", +} + +@InProceedings{dinsdale-young-views-13, + author = "Thomas Dinsdale-Young and Lars Birkedal and Philippa + Gardner and Matthew J. Parkinson and Hongseok Yang", + title = "Views: compositional reasoning for concurrent + programs", + booktitle = popl, + year = "2013", + pages = "287--300", + URL = "http://cs.au.dk/~birke/papers/views.pdf", +} + +@InProceedings{dinsdaleyoung-cap-10, + author = "Thomas Dinsdale-Young and Mike Dodds and Philippa + Gardner and Matthew J. Parkinson and Viktor Vafeiadis", + booktitle = ecoop, + publisher = springer, + title = "Concurrent Abstract Predicates", + series = lncs, + volume = "6183", + year = "2010", + pages = "504--528", + URL = "http://www.cl.cam.ac.uk/~md466/publications/ECOOP.10.concurrent_abstract_predicates.pdf", +} + +@TechReport{dinsdaleyoung-cap-tr-10, + author = "Thomas Dinsdale-Young and Mike Dodds and Philippa + Gardner and Matthew Parkinson and Viktor Vafeiadis", + title = "Concurrent Abstract Predicates", + institution = "University of Cambridge, Computer Laboratory", + year = "2010", + URL = "http://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-777.pdf", +} + +@InProceedings{distefano-parkinson-08, + author = "Dino Distefano and Matthew J. Parkinson", + title = "{jStar}: towards practical verification for {Java}", + booktitle = oopsla, + year = "2008", + pages = "213--226", + URL = "http://www.eecs.qmul.ac.uk/~ddino/papers/oopsla2008.pdf", +} + +@InProceedings{dockins-algebras-09, + author = "Robert Dockins and Aquinas Hobor and Andrew W. Appel", + title = "A Fresh Look at Separation Algebras and Share + Accounting", + booktitle = aplas, + year = "2009", + pages = "161--177", + publisher = springer, + series = lncs, + volume = "5904", + URL = "http://www.cs.princeton.edu/~appel/papers/fresh-sa.pdf", +} + +@InProceedings{dodds-11, + author = "Mike Dodds and Suresh Jagannathan and Matthew J. + Parkinson", + title = "Modular reasoning for deterministic parallelism", + booktitle = popl, + year = "2011", + pages = "259--270", + URL = "http://www.cl.cam.ac.uk/~md466/publications/POPL.11.deterministic_parallelism.pdf", +} + +@InProceedings{dodds-deny-guarantee-09, + author = "Mike Dodds and Xinyu Feng and Matthew J. Parkinson and + Viktor Vafeiadis", + title = "Deny-Guarantee Reasoning", + booktitle = esop, + year = "2009", + pages = "363--377", + publisher = springer, + series = lncs, + volume = "5502", + URL = "http://ttic.uchicago.edu/~feng/research/publications/DG.pdf", +} + +@Article{dodds-sync-16, + author = "Mike Dodds and Suresh Jagannathan and Matthew J. + Parkinson and Kasper Svendsen and Lars Birkedal", + title = "Verifying custom synchronization constructs using + higher-order separation logic", + journal = toplas, + year = "2016", + volume = "28", + number = "2", + URL = "http://dx.doi.org/10.1145/2818638", +} + +@InProceedings{donnelly-xi-05, + author = "Kevin Donnelly and Hongwei Xi", + title = "Combining higher-order abstract syntax with + first-order abstract syntax in {ATS}", + booktitle = merlin, + year = "2005", + pages = "58--63", + URL = "http://www.cs.bu.edu/~hwxi/academic/papers/merlin05.pdf", +} + +@Article{dornic-jouvelot-gifford-92, + author = "Vincent Dornic and Pierre Jouvelot and David K. + Gifford", + title = "Polymorphic time systems for estimating program + complexity", + journal = loplas, + volume = "1", + number = "1", + year = "1992", + pages = "33--45", + URL = "http://ropas.snu.ac.kr/lib/dock/DoJoGi1992.pdf", +} + +@InCollection{dowek-01, + author = "Gilles Dowek", + title = "Higher-order unification and matching", + booktitle = "Handbook of Automated Reasoning", + pages = "1009--1062", + publisher = elsevier, + year = "2001", + editor = "J. Alan Robinson and Andrei Voronkov", + URL = "http://www.lix.polytechnique.fr/~dowek/Publi/unification.ps", +} + +@TechReport{dowek-al-95, + author = "Gilles Dowek and Thérèse Hardin and Claude + Kirchner", + title = "Higher Order Unification via Explicit Substitutions", + institution = "INRIA", + number = "2709", + year = "1995", + pages = "42", + type = "Research Report", + URL = "http://www.inria.fr/rrrt/rr-2709.html", +} + +@TechReport{dowek-al-98, + author = "Gilles Dowek and Thérèse Hardin and Claude Kirchner + and Frank Pfenning", + title = "Unification via Explicit Substitutions: the Case of + Higher-Order Patterns", + institution = "INRIA", + number = "3591", + year = "1998", + pages = "33", + type = "Research Report", + URL = "http://www.inria.fr/rrrt/rr-3591.html", +} + +@Article{dowling-gallier-84, + author = "William F. Dowling and Jean H. Gallier", + title = "Linear-Time Algorithms for Testing the Satisfiability + of Propositional {Horn} Formulae", + journal = jlp, + volume = "1", + number = "3", + year = "1984", + pages = "267--284", +} + +@Article{downey-sethi-tarjan-80, + author = "Peter J. Downey and Ravi Sethi and Robert Endre + Tarjan", + title = "Variations on the Common Subexpression Problem", + journal = jacm, + year = "1980", + volume = "27", + number = "4", + pages = "758--771", + URL = "http://doi.acm.org/10.1145/322217.322228", +} + +@InProceedings{dreyer-neis-birkedal-10, + author = "Derek Dreyer and Georg Neis and Lars Birkedal", + title = "The impact of higher-order state and control effects + on local relational reasoning", + booktitle = icfp, + pages = "143--156", + year = "2010", + URL = "https://www.mpi-sws.org/~dreyer/papers/stslr/icfp.pdf", +} + +@InProceedings{dubois-menissier-97, + author = "Catherine Dubois and Valérie Ménissier-Morain", + title = "Typage de {ML}: Spécification et preuve en {Coq}", + booktitle = "Actes du GDR Programmation", + year = "1997", + URL = "http://www.irisa.fr/lande/ridoux/GDR_annexe/dubois.ps.gz", +} + +@Article{dubois-menissier-99, + author = "Catherine Dubois and Valérie Ménissier-Morain", + title = "Certification of a Type Inference Tool for {ML}: + {Damas-Milner} within {Coq}", + journal = jar, + year = "1999", + volume = "23", + number = "3--4", + pages = "319--346", + URL = "http://www.ensiie.fr/~dubois/jar_final.pdf", +} + +@Article{duggan-bent-96, + author = "Dominic Duggan and Frederick Bent", + title = "Explaining type inference", + journal = scp, + year = "1996", + volume = "27", + number = "1", +} + +@InProceedings{dussart-henglein-mossin-95, + author = "Dirk Dussart and Fritz Henglein and Christian Mossin", + year = "1995", + title = "Polymorphic Recursion and Subtype Qualifications: + Polymorphic Binding-Time Analysis in Polynomial Time", + booktitle = sas, + publisher = springer, + series = lncs, + volume = "983", + pages = "118--135", + URL = "ftp://ftp.diku.dk/diku/semantics/papers/D-243.dvi.gz", +} + +@Article{dybvig-93, + author = "Kent Dybvig and Robert Hieb and Carl Bruggeman", + title = "Syntactic abstraction in {Scheme}", + journal = lsc, + year = "1993", + volume = "5", + number = "4", + pages = "295--326", + URL = "http://www.cs.indiana.edu/~dyb/pubs/LaSC-5-4-pp295-326.pdf", +} + +@Article{eberl-17, + author = "Manuel Eberl", + title = "Proving Divide and Conquer Complexities in + {Isabelle/HOL}", + journal = jar, + volume = "58", + number = "4", + pages = "483--508", + year = "2017", + URL = "https://www21.in.tum.de/~eberlm/divide_and_conquer_isabelle.pdf", +} + +@InProceedings{eifrig-smith-trifonov-94, + author = "Jonathan Eifrig and Scott Smith and Valery Trifonov", + title = "Type Inference for Recursively Constrained Types and + its Application to {OOP}", + booktitle = mfps, + series = entcs, + publisher = elsevier, + volume = "1", + year = "1995", + URL = "http://www.cs.jhu.edu/~scott/ftp/ooinfer.ps.gz", +} + +@Article{eifrig-smith-trifonov-95, + author = "Jonathan Eifrig and Scott Smith and Valery Trifonov", + title = "Sound polymorphic type inference for objects", + journal = notices, + volume = "30", + number = "10", + year = "1995", + pages = "169--184", + URL = "http://www.cs.jhu.edu/~scott/ftp/sptio.ps.gz", +} + +@TechReport{elphin-04, + author = "Carsten Schürmann and Adam Poswolsky and Jeffrey + Sarnat", + title = "The $\nabla$-Calculus: Functional programming with + higher-order encodings", + institution = "Yale University", + number = "YALEU/DCS/TR-1272", + year = "2004", + URL = "http://www.cs.yale.edu/~delphin/files/nablaTR.pdf", +} + +@InProceedings{elphin-05, + author = "Carsten Schürmann and Adam Poswolsky and Jeffrey + Sarnat", + title = "The $\nabla$-Calculus: Functional programming with + higher-order encodings", + booktitle = tlca, + pages = "339--353", + year = "2005", + volume = "3461", + series = lncs, + publisher = springer, + URL = "http://www.itu.dk/~carsten/papers/nabla.pdf", +} + +@InProceedings{emerson-lei-86, + author = "E. Allen Emerson and Chin-Laung Lei", + title = "Efficient Model Checking in Fragments of the + Propositional Mu-Calculus", + booktitle = lics, + year = "1986", + pages = "267--278", +} + +@TechReport{emms-leiss-96, + author = "Martin Emms and Hans Lei{\ss}", + title = "Extending the Type Checker for {SML} by Polymorphic + Recursion --- {A} Correctness Proof", + institution = "Centrum f{\"{u}}r Informations- und + Sprachverarbeitung, Universit{\"{a}}t M{\"{u}}nchen", + year = "1996", + number = "96-101", + URL = "http://www.cis.uni-muenchen.de/~leiss/polyrec/polyrec.cisbericht.96-101.ps.gz", +} + +@Book{eopl, + author = "Daniel P. Friedman and Mitchell Wand", + title = "Essentials of Programming Languages, 3rd Edition", + publisher = mitp, + year = "2008", + URL = "http://www.eopl3.com/", +} + +@Unpublished{epigram-05, + author = "Thorsten Altenkirch and Conor McBride and James + McKinna", + title = "Why Dependent Types Matter", + note = "Unpublished", + year = "2005", + URL = "http://www.e-pig.org/downloads/ydtm.pdf", +} + +@Misc{ergo, + author = "Sylvain Conchon and Evelyne Contejean", + title = "The {Alt-Ergo} Automatic Theorem Prover", + note = "\url{http://alt-ergo.lri.fr/}", + year = "2011", + URL = "http://alt-ergo.lri.fr/", +} + +@InProceedings{erlingsson-schneider-00, + author = "{\'U}lfar Erlingsson and Fred B. Schneider", + title = "{IRM} Enforcement of {Java} Stack Inspection", + booktitle = sp, + year = "2000", + pages = "246--255", + URL = "http://csdl.computer.org/comp/proceedings/sp/2000/0665/00/06650246abs.htm", +} + +@InProceedings{erlingsson-schneider-99, + author = "{\'U}lfar Erlingsson and Fred B. Schneider", + title = "{SASI} Enforcement of Security Policies: a + Retrospective", + booktitle = nspw, + pages = "87--95", + year = "1999", + URL = "http://www.cs.cornell.edu/fbs/publications/sasiNSPW.ps", +} + +@InProceedings{esparza-13, + author = "Javier Esparza and Peter Lammich and Ren{\'e} Neumann + and Tobias Nipkow and Alexander Schimpf and Jan-Georg + Smaus", + title = "A Fully Verified Executable {LTL} Model Checker", + booktitle = cav, + pages = "463--478", + year = "2013", + series = lncs, + volume = "8044", + publisher = springer, + URL = "https://www21.in.tum.de/~nipkow/pubs/cav13.pdf", +} + +@InProceedings{esparza-efficient-00, + author = "Javier Esparza and David Hansel and Peter Rossmanith + and Stefan Schwoon", + title = "Efficient Algorithms for Model Checking Pushdown + Systems", + booktitle = cav, + pages = "232--247", + year = "2000", + series = lncs, + volume = "1855", + publisher = springer, + URL = "https://www7.in.tum.de/um/bibdb/esparza/cav00.pdf", +} + +@Misc{f7, + author = "Karthik Bhargavan and Cédric Fournet and Andy Gordon + and Sergio Maffeis and Jesper Bengtson", + title = "The {F7} Typechecker", + note = "\url{http://research.microsoft.com/en-us/projects/f7/}", + year = "2011", + URL = "http://research.microsoft.com/en-us/projects/f7/", +} + +@Misc{facebook-infer, + author = "Cristiano Calcagno and Dino Distefano and Peter + O'Hearn", + title = "Open-sourcing {Facebook Infer}: Identify bugs before + you ship", + howpublished = "\url{https://code.facebook.com/posts/1648953042007882/open-sourcing-facebook-infer-identify-bugs-before-you-ship/}", + year = "2015", +} + +@InProceedings{faehndrich-al-00, + author = "Manuel Fähndrich and Jakob Rehof and Manuvir Das", + title = "Scalable Context-Sensitive Flow Analysis Using + Instantiation Constraints", + booktitle = pldi, + year = "2000", + URL = "http://research.microsoft.com/pubs/67468/pldi00.ps", +} + +@InProceedings{faehndrich-cycles-98, + author = "Manuel Fähndrich and Jeffrey S. Foster and Zhendong + Su and Alexander S. Aiken", + title = "Partial Online Cycle Elimination in Inclusion + Constraint Graphs", + booktitle = pldi, + year = "1998", + pages = "85--96", + URL = "http://research.microsoft.com/pubs/67475/pldi98.pdf", +} + +@InProceedings{faehndrich-deline-02, + author = "Manuel Fähndrich and Robert DeLine", + title = "Adoption and focus: practical linear types for + imperative programming", + booktitle = pldi, + year = "2002", + pages = "13--24", + URL = "http://research.microsoft.com/pubs/67459/pldi02.pdf", +} + +@InProceedings{faehndrich-leino-03, + author = "Manuel Fähndrich and Rustan Leino", + title = "Heap Monotonic Typestates", + booktitle = "International Workshop on Alias Confinement and + Ownership (IWACO)", + year = "2003", + URL = "http://research.microsoft.com/en-us/um/people/leino/papers/krml123.pdf", +} + +@PhdThesis{faehndrich-phd-99, + school = "University of California at Berkeley", + title = "Bane: {A} Library for Scalable Constraint-Based + Program Analysis", + year = "1999", + author = "Manuel Fähndrich", + URL = "http://research.microsoft.com/pubs/67479/thesis-compact.pdf", +} + +@InProceedings{faehndrich-singularity-06, + author = "Manuel Fähndrich and Mark Aiken and Chris Hawblitzel + and Orion Hodson and Galen Hunt and James R. Larus and + Steven Levi", + title = "Language support for fast and reliable message-based + communication in {Singularity OS}", + booktitle = eurosys, + year = "2006", + pages = "177--190", + URL = "http://www.cs.kuleuven.ac.be/conference/EuroSys2006/papers/p177-fahndrich.pdf", +} + +@Unpublished{fan, + author = "Hongbo Zhang and Steve Zdancewic", + title = "{Fan}: compile-time metaprogramming for {OCaml}", + note = "Unpublished", + year = "2013", + URL = "http://zhanghongbo.me/fan/_downloads/metaprogramming_for_ocaml.pdf", +} + +@Article{faxen-02, + author = "Karl-Filip Fax\'{e}n", + title = "A Static Semantics for {Haskell}", + pages = "295--357", + year = "2002", + journal = jfp, + volume = "12", + number = "4--5", + URL = "http://www.it.kth.se/~kff/semantics.ps.gz", +} + +@Article{fecht-seidl-99, + author = "Christian Fecht and Helmut Seidl", + title = "A Faster Solver for General Systems of Equations", + journal = scp, + year = "1999", + volume = "35", + number = "2--3", + pages = "137--162", + URL = "http://www2.in.tum.de/~seidl/papers/final-solver.ps.gz", +} + +@InProceedings{felleisen-flanagan-componential-97, + author = "Cormac Flanagan and Matthias Felleisen", + title = "Componential Set-Based Analysis", + booktitle = pldi, + year = "1997", + pages = "235--248", + URL = "http://www.cs.rice.edu/CS/PLT/Publications/Scheme/pldi97-ff.ps.gz", +} + +@TechReport{felleisen-flanagan-theory-practice-96, + number = "TR96-266", + institution = "Rice University", + title = "Modular and Polymorphic Set-Based Analysis: Theory and + Practice", + year = "1996", + pages = "48", + author = "Cormac Flanagan and Matthias Felleisen", + URL = "http://www.cs.rice.edu/CS/PLT/Publications/Scheme/tr96-266.ps.gz", +} + +@PhdThesis{fenton-73, + school = "University of Cambridge", + title = "Information Protection Systems", + year = "1973", + author = "J. S. Fenton", +} + +@Article{fenton-74, + author = "J. S. Fenton", + title = "Memoryless Subsystems", + journal = cj, + volume = "17", + number = "2", + pages = "143--147", + year = "1974", +} + +@InProceedings{ferreira-pientka-17, + author = "Francisco Ferreira and Brigitte Pientka", + title = "Programs Using Syntax with First-Class Binders", + booktitle = esop, + year = "2017", + series = lncs, + volume = "10201", + publisher = springer, + URL = "http://www.cs.mcgill.ca/~bpientka/papers/esop17_ferreira.pdf", +} + +@Article{fftw-05, + author = "Matteo Frigo and Steven G. Johnson", + title = "The Design and Implementation of {FFTW3}", + journal = pieee, + year = "2005", + volume = "93", + number = "2", + pages = "216--231", + URL = "http://www.fftw.org/fftw-paper-ieee.pdf", +} + +@InProceedings{field-teitelbaum-90, + author = "John Field and Tim Teitelbaum", + title = "Incremental Reduction in the Lambda Calculus", + booktitle = lfp, + year = "1990", + pages = "307--322", +} + +@InProceedings{filinski-99, + author = "Andrzej Filinski", + title = "Representing Layered Monads", + booktitle = popl, + year = "1999", + pages = "175--188", + URL = "http://www.diku.dk/~andrzej/papers/RLM.ps.gz", +} + +@Article{filliatre-00, + author = "Jean-Christophe Filliâtre", + title = "Verification of Non-Functional Programs using + Interpretations in Type Theory", + journal = jfp, + volume = "13", + number = "4", + pages = "709--745", + year = "2003", + URL = "http://www.lri.fr/~filliatr/ftp/publis/jphd.ps.gz", +} + +@InProceedings{filliatre-06, + author = "Jean-Christophe Filli\^atre", + title = "Backtracking iterators", + booktitle = ml, + year = "2006", + pages = "55--62", + URL = "http://www.lri.fr/~filliatr/publis/enum2.ps.gz", +} + +@InProceedings{filliatre-conchon-06, + author = "Jean-Christophe Filli{\^a}tre and Sylvain Conchon", + title = "Type-safe modular hash-consing", + booktitle = ml, + pages = "12--19", + year = "2006", + URL = "https://www.lri.fr/~filliatr/ftp/publis/hash-consing2.pdf", +} + +@Article{filliatre-find-06, + author = "Jean-Christophe Filliâtre", + title = "Formal Proof of a Program: {Find}", + journal = scp, + year = "2006", + volume = "64", + pages = "332--240", + URL = "http://www.lri.fr/~filliatr/ftp/publis/find.ps.gz", +} + +@InProceedings{filliatre-ghost-14, + author = "Jean{-}Christophe Filli{\^{a}}tre and L{\'{e}}on + Gondelman and Andrei Paskevich", + title = "The Spirit of Ghost Code", + booktitle = cav, + pages = "1--16", + year = "2014", + series = lncs, + volume = "8559", + publisher = springer, + URL = "https://hal.archives-ouvertes.fr/hal-00873187/PDF/main.pdf", +} + +@InProceedings{filliatre-letouzey-04, + author = "Jean-Christophe Filliâtre and Pierre Letouzey", + title = "Functors for Proofs and Programs", + booktitle = esop, + pages = "370--384", + year = "2004", + volume = "2986", + series = lncs, + publisher = springer, + URL = "http://www.lri.fr/~filliatr/ftp/publis/fpp.ps.gz", +} + +@InProceedings{filliatre-marche-04, + author = "Jean-Christophe Filliâtre and Claude Marché", + title = "Multi-Prover Verification of {C} Programs", + booktitle = icfem, + year = "2004", + publisher = springer, + series = lncs, + volume = "3308", + pages = "15--29", + URL = "http://www.lri.fr/~filliatr/ftp/publis/caduceus.ps.gz", +} + +@InProceedings{filliatre-pereira-16, + author = "Jean{-}Christophe Filli{\^{a}}tre and M{\'{a}}rio + Pereira", + title = "A Modular Way to Reason About Iteration", + booktitle = nfm, + pages = "322--336", + year = "2016", + series = lncs, + volume = "9690", + publisher = springer, + URL = "https://hal.inria.fr/hal-01281759", +} + +@InProceedings{findler-felleisen-02, + author = "Robert Bruce Findler and Matthias Felleisen", + title = "Contracts for higher-order functions", + booktitle = icfp, + year = "2002", + pages = "48--59", + URL = "http://people.cs.uchicago.edu/~robby/pubs/papers/ho-contracts-icfp2002.pdf", +} + +@Article{fischbach-hannan-02, + author = "Adam Fischbach and John Hannan", + title = "Specification and Correctness of Lambda Lifting", + journal = jfp, + year = "2003", + volume = "13", + number = "3", + pages = "509--543", + URL = "http://dx.doi.org/10.1017/S0956796802004604", +} + +@Article{fisher-mitchell-98, + author = "Kathleen Fisher and John C. Mitchell", + title = "On the Relationship between Classes, Objects and Data + Abstraction", + journal = tapos, + year = "1998", + volume = "4", + number = "1", + pages = "3--25", + URL = "http://www.research.att.com/~kfisher/files/tapos98.ps", +} + +@InProceedings{flanagan-abadi-99, + author = "Cormac Flanagan and Mart\'{\i}n Abadi", + title = "Types for Safe Locking", + booktitle = esop, + year = "1999", + pages = "91--108", + publisher = springer, + series = lncs, + volume = "1576", + URL = "http://users.soe.ucsc.edu/~cormac/papers/esop99.pdf", +} + +@InProceedings{flanagan-al-93, + author = "Cormac Flanagan and Amr Sabry and Bruce F. Duba and + Matthias Felleisen", + title = "The Essence of Compiling with Continuations", + booktitle = pldi, + year = "1993", + pages = "237--247", + URL = "http://www.cs.rice.edu/CS/PLT/Publications/Scheme/pldi93-fsdf.ps.gz", +} + +@InProceedings{flanagan-al-96, + author = "Cormac Flanagan and Matthew Flatt and Shriram + Krishnamurthi and Stephanie Weirich and Matthias + Felleisen", + year = "1996", + booktitle = pldi, + title = "Catching Bugs in the Web of Program Invariants", + URL = "http://www.cs.rice.edu/CS/PLT/Publications/Scheme/pldi96-ffkwf.ps.gz", +} + +@PhdThesis{flanagan-effective-97, + school = "Rice University", + title = "Effective Static Debugging via Componential Set-Based + Analysis", + year = "1997", + pages = "164", + author = "Cormac Flanagan", + URL = "http://www.cs.rice.edu/CS/PLT/Publications/Scheme/thesis-flanagan.ps.gz", +} + +@InProceedings{flanagan-esc-02, + author = "Cormac Flanagan and K. Rustan M. Leino and Mark + Lillibridge and Greg Nelson and James B. Saxe and + Raymie Stata", + title = "Extended Static Checking for {Java}", + booktitle = pldi, + pages = "234--245", + year = "2002", + URL = "http://www.soe.ucsc.edu/~cormac/papers/pldi02.ps", +} + +@InProceedings{flanagan-saxe-01, + author = "Cormac Flanagan and James B. Saxe", + title = "Avoiding exponential explosion: generating compact + verification conditions", + booktitle = popl, + year = "2001", + pages = "193--205", + URL = "http://www.soe.ucsc.edu/~cormac/papers/popl01.ps", +} + +@InProceedings{floyd-67, + author = "R. W. Floyd", + title = "Assigning meanings to programs", + booktitle = "Mathematical Aspects of Computer Science", + series = "Proceedings of Symposia in Applied Mathematics", + volume = "19", + year = "1967", + organization = ams, + pages = "19--32", + URL = "https://people.eecs.berkeley.edu/~necula/Papers/FloydMeaning.pdf", +} + +@InProceedings{fluet-02, + author = "Matthew Fluet and Riccardo Pucella", + title = "Phantom types and subtyping", + booktitle = tcsconf, + pages = "448--460", + year = "2002", + URL = "http://arXiv.org/abs/cs.PL/0403034", +} + +@InProceedings{fluet-al-06, + author = "Matthew Fluet and Greg Morrisett and Amal Ahmed", + title = "Linear Regions Are All You Need", + booktitle = esop, + pages = "7--21", + year = "2006", + volume = "3924", + series = lncs, + publisher = springer, + URL = "http://ttic.uchicago.edu/~fluet/research/substruct-regions/ESOP06/esop06.pdf", +} + +@PhdThesis{fluet-phd-07, + author = "Matthew Fluet", + title = "Monadic and Substructural Type Systems for + Region-Based Memory Management", + school = "Cornell University", + year = "2007", + URL = "http://ttic.uchicago.edu/~fluet/research/thesis/fluet-thesis.single.pdf", +} + +@InProceedings{fluet-pucella-02, + author = "Matthew Fluet and Riccardo Pucella", + title = "Phantom Types and Subtyping", + booktitle = ifiptcs, + pages = "448--460", + year = "2002", + volume = "223", + series = "IFIP Conference Proceedings", + publisher = kluwer, + URL = "http://www.cs.cornell.edu/people/fluet/phantom-subtyping/TCS02/tcs02.ps", +} + +@InProceedings{fluet-pucella-05, + author = "Matthew Fluet and Riccardo Pucella", + title = "Practical Datatype Specializations with Phantom Types + and Recursion Schemes", + booktitle = ml, + year = "2005", + series = entcs, + URL = "http://www.cs.cornell.edu/people/fluet/specializations/MLWRK05/mlwrk05.pdf", +} + +@Article{focardi-gorrieri-95, + author = "Riccardo Focardi and Roberto Gorrieri", + title = "A classification of security properties for process + algebras", + journal = "Journal of Computer Security", + volume = "3", + number = "1", + pages = "5--33", + year = "1995", + URL = "http://www.cs.unibo.it/~gorrieri/Papers/jcsfinal.ps.gz", +} + +@InProceedings{ford-02, + author = "Bryan Ford", + title = "Packrat parsing: simple, powerful, lazy, linear time", + booktitle = icfp, + year = "2002", + pages = "36--47", + URL = "http://www.brynosaurus.com/pub/lang/packrat-icfp02.pdf", +} + +@InProceedings{ford-04, + author = "Bryan Ford", + title = "Parsing expression grammars: a recognition-based + syntactic foundation", + booktitle = popl, + year = "2004", + pages = "111--122", + URL = "http://pdos.csail.mit.edu/~baford/packrat/popl04/peg-popl04.pdf", +} + +@TechReport{foster-aiken-restrict-01, + author = "Jeffrey S. Foster and Alex Aiken", + institution = "University of California, Berkeley", + title = "Checking Programmer-Specified Non-Aliasing", + year = "2001", + number = "UCB//CSD-01-1160", + URL = "http://www.cs.umd.edu/~jfoster/papers/tr01-restrict.pdf", +} + +@InProceedings{foster-flow-sensitive-qualifiers-02, + author = "Jeffrey S. Foster and Tachio Terauchi and Alex Aiken", + title = "Flow-Sensitive Type Qualifiers", + booktitle = pldi, + year = "2002", + pages = "1--12", + URL = "http://www.cs.umd.edu/~jfoster/papers/pldi02.pdf", +} + +@Article{fournet-al-join-03, + author = "Cédric Fournet and Cosimo Laneve and Luc Maranget and + Didier Rémy", + journal = jlap, + title = "Inheritance in the Join Calculus", + volume = "57", + number = "2", + pages = "23--69", + year = "2003", + URL = "http://gallium.inria.fr/~remy/work/ojoin/jojoin.pdf", +} + +@InProceedings{fournet-al-join-97, + author = "Cédric Fournet and Luc Maranget and Cosimo Laneve and + Didier Rémy", + title = "Implicit typing à la {ML} for the join-calculus", + booktitle = concur, + series = lncs, + publisher = springer, + volume = "1243", + pages = "196--212", + year = "1997", + URL = "http://gallium.inria.fr/~remy/ftp/typing-join.pdf", +} + +@InProceedings{fournet-gonthier-96, + author = "Cédric Fournet and Georges Gonthier", + title = "The Reflexive Chemical Abstract Machine and the + Join-Calculus", + booktitle = popl, + pages = "372--385", + year = "1996", + URL = "https://doi.org/10.1145/237721.237805", +} + +@InProceedings{fournet-gordon-02, + author = "Cédric Fournet and Andrew D. Gordon", + title = "Stack Inspection: Theory and Variants", + booktitle = popl, + pages = "307--318", + year = "2002", + URL = "http://research.microsoft.com/~fournet/papers/stack-inspection-theory-and-variants-popl-02.ps", +} + +@Article{fournet-gordon-03, + author = "Cédric Fournet and Andrew D. Gordon", + title = "Stack Inspection: Theory and Variants", + journal = toplas, + year = "2003", + volume = "25", + number = "3", + pages = "360--399", + URL = "http://doi.acm.org/10.1145/641909.641912", +} + +@Article{francalanza-rathke-sassone-2011, + author = "Adrian Francalanza and Julian Rathke and Vladimiro + Sassone", + title = "Permission-Based Separation Logic for Message-Passing + Concurrency", + journal = lmcs, + volume = "7", + number = "3", + year = "2011", + URL = "http://arxiv.org/abs/1106.5128", +} + +@InProceedings{fredman-saks-89, + author = "Michael Fredman and Michael Saks", + title = "The Cell Probe Complexity of Dynamic Data Structures", + pages = "345--354", + booktitle = "Annual Symposium on Theory of Computing ({STOC})", + publisher = "ACM", + year = "1989", + URL = "http://dx.doi.org/10.1145/73007.73040", +} + +@Article{fredman-tarjan-87, + author = "Michael L. Fredman and Robert Endre Tarjan", + title = "Fibonacci heaps and their uses in improved network + optimization algorithms", + journal = jacm, + volume = "34", + number = "3", + year = "1987", + pages = "596--615", + URL = "http://doi.acm.org/10.1145/28869.28874", +} + +@InProceedings{freeman-91, + author = "Tim Freeman and Frank Pfenning", + title = "Refinement types for {ML}", + booktitle = pldi, + pages = "268--277", + year = "1991", + URL = "http://www.cs.cmu.edu/~fp/papers/pldi91.pdf", +} + +@TechReport{fresh-ocaml, + author = "Mark R. Shinwell and Andrew M. Pitts", + year = "2005", + title = "{Fresh Objective Caml} user manual", + institution = "University of Cambridge", + number = "621", + URL = "http://www.cl.cam.ac.uk/TechReports/UCAM-CL-TR-621.pdf", +} + +@PhdThesis{frey-04, + author = "Alexandre Frey", + title = "Approche algébrique du typage d'un langage à la {ML} + avec objets, sous-typage et multi-méthodes", + school = "École des Mines de Paris", + year = "2004", + URL = "http://gallium.inria.fr/~remy/students/alexandre.frey.pdf", +} + +@InProceedings{frey-97, + author = "Alexandre Frey", + title = "Satisfying Subtype Inequalities in Polynomial Space", + booktitle = sas, + series = lncs, + number = "1302", + year = "1997", + pages = "265--277", + publisher = springer, + URL = "http://citeseer.ist.psu.edu/frey97satisfying.html", + alturl = "http://dx.doi.org/10.1016/S0304-3975(00)00314-5", +} + +@InProceedings{frisch-castagna-benzaken-02, + author = "Alain Frisch and Giuseppe Castagna and V{\'e}ronique + Benzaken", + title = "Semantic Subtyping", + booktitle = lics, + year = "2002", + pages = "137--146", + URL = "http://www.cduce.org/papers/lics02.ps.gz", +} + +@Article{frisch-castagna-benzaken-08, + author = "Alain Frisch and Giuseppe Castagna and V{\'e}ronique + Benzaken", + title = "Semantic subtyping: Dealing set-theoretically with + function, union, intersection, and negation types", + journal = jacm, + volume = "55", + number = "4", + year = "2008", + URL = "http://www.pps.univ-paris-diderot.fr/~gc/papers/semantic_subtyping.pdf", +} + +@InProceedings{fstar, + author = "Nikhil Swamy and Juan Chen and C{\'e}dric Fournet and + Pierre-Yves Strub and Karthik Bhargavan and Jean Yang", + title = "Secure distributed programming with value-dependent + types", + booktitle = icfp, + year = "2011", + pages = "266--278", + URL = "http://research.microsoft.com/pubs/150012/icfp-camera-ready.pdf", +} + +@InProceedings{fuh-mishra-88, + author = "You-Chin Fuh and Prateek Mishra", + title = "Type inference with subtypes", + booktitle = esop, + publisher = springer, + series = lncs, + volume = "300", + year = "1988", + pages = "94--114", + URL = "http://dx.doi.org/10.1007/3-540-19027-9_7", +} + +@InProceedings{fuh-mishra-gap-89, + author = "You-Chin Fuh and Prateek Mishra", + title = "Polymorphic Subtype Inference: Closing the + Theory-Practice Gap", + pages = "167--183", + booktitle = tapsoft, + series = lncs, + volume = "352", + publisher = springer, + year = "1989", + URL = "http://dx.doi.org/10.1007/3-540-50940-2_35", +} + +@InProceedings{furuse-03, + author = "Jun Furuse", + title = "Extensional Polymorphism by Flow Graph Dispatching", + booktitle = aplas, + publisher = springer, + series = lncs, + volume = "2895", + year = "2003", + URL = "http://gallium.inria.fr/~furuse/publications/flowgraph.ps.gz", +} + +@PhdThesis{gabbay-01, + author = "Murdoch J. Gabbay", + title = "A Theory of Inductive Definitions with + $\alpha$-Equivalence", + school = "Cambridge University", + year = "2001", + URL = "http://www.macs.hw.ac.uk/~gabbay/papers/thesis.pdf", +} + +@Unpublished{gabbay-04, + author = "Murdoch J. Gabbay", + title = "A General Mathematics of Names in Syntax", + year = "2004", + note = "Submitted for publication", + URL = "http://www.macs.hw.ac.uk/~gabbay/papers/genmns.pdf", +} + +@Article{gabbay-pitts-02, + author = "Murdoch J. Gabbay and Andrew M. Pitts", + title = "A New Approach to Abstract Syntax with Variable + Binding", + journal = fac, + year = "2002", + volume = "13", + number = "3--5", + pages = "341--363", + URL = "http://www.cl.cam.ac.uk/~amp12/papers/newaas/newaas-jv.pdf", + alturl = "http://www.springerlink.com/link.asp?id=epn028x83rqw00qv", +} + +@Article{galil-italiano-91, + author = "Zvi Galil and Giuseppe F. Italiano", + title = "Data Structures and Algorithms for Disjoint Set Union + Problems", + journal = surveys, + volume = "23", + number = "3", + pages = "319--344", + year = "1991", + URL = "http://doi.acm.org/10.1145/116873.116878", +} + +@Article{galler-fischer-64, + author = "Bernard A. Galler and Michael J. Fischer", + title = "An improved equivalence algorithm", + journal = cacm, + volume = "7", + number = "5", + pages = "301--303", + year = "1964", + URL = "http://doi.acm.org/10.1145/364099.364331", +} + +@Article{gapeyev-levin-pierce-00, + author = "Vladimir Gapeyev and Michael Levin and Benjamin + Pierce", + title = "Recursive Subtyping Revealed", + journal = jfp, + volume = "12", + number = "6", + pages = "511--548", + year = "2002", + URL = "http://dx.doi.org/10.1017/S0956796802004318", +} + +@InProceedings{gardner-ntizk-wright-14, + author = "Philippa Gardner and Gian Ntzik and Adam Wright", + title = "Local Reasoning for the {POSIX} File System", + booktitle = esop, + pages = "169--188", + year = "2014", + series = lncs, + volume = "8410", + publisher = springer, + URL = "https://www.doc.ic.ac.uk/~gn408/POSIXFS/esop2014.pdf", +} + +@Book{garey-johnson-79, + author = "Michael R. Garey and David S. Johnson", + title = "Computers and Intractability: {A} Guide to the Theory + of {NP}-Completeness", + year = "1979", + publisher = "W. H. Freeman and Company", +} + +@InProceedings{garrigue-00, + author = "Jacques Garrigue", + title = "Code reuse through polymorphic variants", + booktitle = fse, + year = "2000", + URL = "http://www.math.nagoya-u.ac.jp/~garrigue/papers/variant-reuse.ps.gz", +} + +@InProceedings{garrigue-02, + author = "Jacques Garrigue", + title = "Simple Type Inference for Structural Polymorphism", + booktitle = fool, + year = "2002", + URL = "http://www.math.nagoya-u.ac.jp/~garrigue/papers/structural-inf.ps.gz", +} + +@InProceedings{garrigue-98, + author = "Jacques Garrigue", + title = "Programming with polymorphic variants", + booktitle = ml, + year = "1998", + URL = "http://www.math.nagoya-u.ac.jp/~garrigue/papers/variants.ps.gz", +} + +@TechReport{garrigue-furuse-95, + author = "Jun P. Furuse and Jacques Garrigue", + title = "A label-selective lambda-calculus with optional + arguments and its compilation method", + institution = "Kyoto University", + year = "1995", + type = "RIMS Preprint", + number = "1041", + URL = "http://wwwfun.kurims.kyoto-u.ac.jp/~garrigue/papers/rims-1041.pdf", +} + +@InProceedings{garrigue-relax-04, + author = "Jacques Garrigue", + title = "Relaxing the Value Restriction", + booktitle = flops, + pages = "196--213", + year = "2004", + volume = "2998", + series = lncs, + publisher = springer, + URL = "http://www.math.nagoya-u.ac.jp/~garrigue/papers/morepoly-long.pdf", +} + +@Article{garrigue-remy-99, + author = "Jacques Garrigue and Didier R{\'e}my", + title = "Extending {ML} with Semi-Explicit Higher-Order + Polymorphism", + journal = ic, + year = "1999", + volume = "155", + number = "1", + pages = "134--169", + URL = "http://gallium.inria.fr/~remy/ftp/iandc.pdf", +} + +@InProceedings{garrigue-remy-gadts-13, + author = "Jacques Garrigue and Didier R{\'e}my", + title = "Ambivalent types for principal type inference with + {GADT}s", + booktitle = aplas, + year = "2013", + URL = "http://gallium.inria.fr/~remy/gadts/Garrigue-Remy:gadts@aplas2013.pdf", +} + +@PhdThesis{gaster-98, + author = "Benedict R. Gaster", + title = "Records, variants and qualified types", + school = "University of Nottingham", + year = "1998", + URL = "http://www.cs.nott.ac.uk/Research/fop/gaster-thesis.ps", +} + +@TechReport{gaster-jones-96, + author = "Benedict R. Gaster and Mark P. Jones", + title = "A Polymorphic Type System for Extensible Records and + Variants", + institution = "Department of Computer Science, University of + Nottingham", + year = "1996", + number = "NOTTCS-TR-96-3", + URL = "http://web.cecs.pdx.edu/~mpj/pubs/polyrec.html", +} + +@InProceedings{gauthier-pottier-04, + author = "Nadji Gauthier and François Pottier", + title = "Numbering Matters: First-Order Canonical Forms for + Second-Order Recursive Types", + booktitle = icfp, + URL = "http://gallium.inria.fr/~fpottier/publis/gauthier-fpottier-icfp04.pdf", + year = "2004", + pages = "150--161", +} + +@InProceedings{gay-modular-session-types-10, + author = "Simon J. Gay and Vasco Thudichum Vasconcelos and + Ant{\'o}nio Ravara and Nils Gesbert and Alexandre Z. + Caldeira", + title = "Modular session types for distributed object-oriented + programming", + booktitle = popl, + year = "2010", + pages = "299--312", + URL = "http://www.dcs.gla.ac.uk/~simon/publications/ModularSessionTypes.pdf", +} + +@InProceedings{german-clarke-halpern-83, + author = "Steven German and Edmund Clarke and Joseph Halpern", + title = "Reasoning About Procedures as Parameters", + booktitle = "Logic of Programs", + pages = "206--220", + year = "1983", + volume = "164", + series = lncs, + publisher = springer, + URL = "http://dx.doi.org/10.1007/3-540-12896-4_365", +} + +@TechReport{geser-chaotic-94, + author = "Alfons Geser and Jens Knoop and Gerald Lüttgen and + Oliver Rüthing and Bernhard Steffen", + title = "Chaotic fixed point iterations", + institution = "Fakultät für Mathematik und Informatik, Universität + Passau", + year = "1994", + type = "MIP-Bericht", + number = "9403", + URL = "http://citeseer.ist.psu.edu/190778.html", +} + +@Manual{ghc, + author = "The GHC team", + title = "The {Glasgow Haskell} compiler", + year = "2005", + URL = "http://www.haskell.org/ghc/", +} + +@Article{ghelli-divergence-95, + title = "Divergence of {$F_\leq$} type checking", + author = "Giorgio Ghelli", + journal = tcs, + pages = "131--162", + year = "1995", + volume = "139", + number = "1--2", + URL = "ftp://ftp.di.unipi.it/pub/Papers/ghelli/DivergenceFsubTCS95.ps.gz", +} + +@InProceedings{gherghina-structured-11, + author = "Cristian Gherghina and Cristina David and Shengchao + Qin and Wei-Ngan Chin", + title = "Structured Specifications for Better Verification of + Heap-Manipulating Programs", + year = "2011", + pages = "386--401", + booktitle = fm, + publisher = springer, + series = lncs, + volume = "6664", + URL = "http://loris-7.ddns.comp.nus.edu.sg/~project/hip/publications/FM_2011_Case.pdf", +} + +@InProceedings{gibbons-dgp-06, + author = "Jeremy Gibbons", + title = "Datatype-generic programming", + booktitle = "International Spring School on Datatype-Generic + Programming", + pages = "1--71", + year = "2006", + series = lncs, + publisher = springer, + volume = "4719", + URL = "http://www.cs.ox.ac.uk/jeremy.gibbons/publications/dgp.pdf", +} + +@TechReport{gifford-fx-87, + author = "David K. Gifford and Pierre Jouvelot and John M. + Lucassen and Mark A. Sheldon", + title = "{FX-87} Reference Manual", + institution = "Massachusetts Institute of Technology", + year = "1987", + number = "MIT/LCS/TR-407", +} + +@TechReport{gifford-fx-91, + author = "David K. Gifford and Pierre Jouvelot and Mark A. + Sheldon and James W. O'Toole", + title = "Report on the {FX-91} Programming Language", + institution = "Massachusetts Institute of Technology", + year = "1992", + number = "MIT/LCS/TR-531", + URL = "http://www.psrg.lcs.mit.edu/history/publications.html#fxps", +} + +@PhdThesis{girard-72, + author = "Jean-Yves Girard", + title = "Interprétation fonctionnelle et élimination des + coupures de l'arith\-mé\-ti\-que d'ordre supérieur", + school = "Universit{\'e} Paris 7", + type = "Th\`ese d'\'Etat", + year = "1972", +} + +@Article{girard-87, + author = "Jean-Yves Girard", + title = "Linear logic", + journal = tcs, + year = "1987", + volume = "50", + number = "1", + pages = "1--102", + URL = "http://iml.univ-mrs.fr/~girard/linear.pdf", +} + +@InProceedings{glew-00, + author = "Neal Glew", + title = "An Efficient Class and Object Encoding", + booktitle = oopsla, + pages = "311--324", + year = "2000", + URL = "http://glew.org/nglew/papers/oce-oopsla.ps.gz", +} + +@InProceedings{glew-02, + author = "Neal Glew", + title = "A Theory of Second-Order Trees", + booktitle = esop, + pages = "147--161", + year = "2002", + volume = "2305", + series = lncs, + publisher = springer, + URL = "http://glew.org/nglew/papers/tsot-esop.pdf", +} + +@InProceedings{glew-99, + author = "Neal Glew", + title = "Object Closure Conversion", + booktitle = hoots, + year = "1999", + series = entcs, + volume = "26", + pages = "52--68", + URL = "http://glew.org/nglew/papers/occ-hoots.ps.gz", +} + +@InProceedings{gmeta-12, + author = "Gyesik Lee and Bruno C. d. S. Oliveira and Sungkeun + Cho and Kwangkeun Yi", + title = "{GMeta}: {A} Generic Formal Metatheory Framework for + First-Order Representations", + booktitle = esop, + pages = "436--455", + year = "2012", + series = lncs, + volume = "7211", + publisher = springer, + URL = "http://ropas.snu.ac.kr/gmeta/gmeta.pdf", +} + +@InProceedings{goerdt-85, + author = "Andreas Goerdt", + title = "A {Hoare} Calculus for Functions Defined by Recursion + on Higher Types", + booktitle = "Logic of Programs", + year = "1985", + pages = "106--117", + publisher = springer, + series = lncs, + volume = "193", + URL = "http://dx.doi.org/10.1007/3-540-15648-8_9", +} + +@InProceedings{goguen-meseguer-82, + author = "Joseph Goguen and José Meseguer", + title = "Security policies and security models", + booktitle = sp, + year = "1982", + pages = "11--20", +} + +@InProceedings{gong-97, + author = "Li Gong and Marianne Mueller and Hemma Prafullchandra + and Roland Schemers", + title = "Going Beyond the Sandbox: An Overview of the New + Security Architecture in the {Java Development Kit + 1.2}", + booktitle = "{USENIX} Symposium on Internet Technologies and + Systems", + year = "1997", + pages = "103--112", + URL = "http://secinf.net/uplarticle/10/jdk12arch.ps", +} + +@InProceedings{gong-schemers-98, + author = "Li Gong and Roland Schemers", + title = "Implementing Protection Domains in the {Java} + Development Kit 1.2", + booktitle = ndss, + year = "1998", + URL = "http://www.isoc.org/isoc/conferences/ndss/98/gong.pdf", +} + +@InProceedings{gordon-12, + author = "Colin S. Gordon and Matthew J. Parkinson and Jared + Parsons and Aleks Bromfield and Joe Duffy", + title = "Uniqueness and reference immutability for safe + parallelism", + booktitle = oopsla, + year = "2012", + pages = "21--40", + URL = "http://homes.cs.washington.edu/~csgordon/papers/oopsla12.pdf", +} + +@InProceedings{gordon-melham-96, + author = "Andrew D. Gordon and Tom Melham", + title = "Five Axioms of Alpha-Conversion", + booktitle = tphol, + pages = "173--191", + year = "1996", + volume = "1125", + series = lncs, + publisher = springer, + URL = "http://www.ftp.cl.cam.ac.uk/ftp/papers/adg/hug96.ps.gz", +} + +@InProceedings{gordon-noble-07, + author = "Donald Gordon and James Noble", + title = "Dynamic ownership in a dynamic language", + booktitle = dls, + year = "2007", + pages = "41--52", + URL = "http://doi.acm.org/10.1145/1297081.1297090", +} + +@InProceedings{gotsman-aplas-07, + author = "Alexey Gotsman and Josh Berdine and Byron Cook and + Noam Rinetzky and Mooly Sagiv", + title = "Local Reasoning for Storable Locks and Threads", + booktitle = aplas, + pages = "19--37", + year = "2007", + series = lncs, + volume = "4807", + publisher = springer, + URL = "http://dx.doi.org/10.1007/978-3-540-76637-7_3", +} + +@TechReport{gotsman-storable-07, + author = "Alexey Gotsman and Josh Berdine and Byron Cook and + Noam Rinetzky and Mooly Sagiv", + title = "Local Reasoning for Storable Locks and Threads", + institution = "Microsoft Research", + year = "2007", + number = "MSR-TR-2007-39", + URL = "http://research.microsoft.com/pubs/70427/tr-2007-39.pdf", +} + +@InProceedings{goubault-dim-94, + author = "Jean Goubault", + title = "Inférence d'unités physiques en {ML}", + booktitle = jfla, + pages = "3--20", + year = "1994", +} + +@Article{gries-73, + author = "David Gries", + title = "Describing an Algorithm by {Hopcroft}", + journal = acta, + volume = "2", + pages = "97--109", + year = "1973", + URL = "http://dx.doi.org/10.1007/BF00264025", +} + +@Article{grosch-90, + author = "Josef Grosch", + title = "Efficient and Comfortable Error Recovery in Recursive + Descent Parsers", + journal = "Structured Programming", + volume = "11", + number = "3", + pages = "129--140", + year = "1990", + URL = "http://www.cocolab.com/products/cocktail/doc.pdf/ell.pdf", +} + +@Article{grossman-06, + author = "Dan Grossman", + title = "Quantified Types in an Imperative Language", + journal = toplas, + year = "2006", + volume = "28", + number = "3", + pages = "429--475", + URL = "http://www.cs.washington.edu/homes/djg/papers/qtil.pdf", +} + +@Book{grune-jacobs-08, + author = "Dick Grune and Ceriel J. H. Jacobs", + title = "Parsing techniques: a practical guide, second + edition", + year = "2008", + publisher = springer, + series = "Monographs in computer science", + URL = "http://www.cs.vu.nl/~dick/PT2Ed.html", +} + +@Book{grune-jacobs-90, + author = "Dick Grune and Ceriel J. H. Jacobs", + title = "Parsing techniques: a practical guide", + year = "1990", + publisher = ellis, + URL = "http://www.cs.vu.nl/~dick/PTAPG.html", +} + +@Unpublished{gueneau-cakeml-16, + author = "Arma{\"e}l Gu{\'e}neau and Magnus O. Myreen and Ramana + Kumar and Michael Norrish", + title = "Verified Characteristic Formulae for {CakeML}", + note = "Submitted", + year = "2016", +} + +@Misc{gueneau-pottier-protzenko-13, + author = "Armaël Guéneau and François Pottier and Jonathan + Protzenko", + title = "The ins and outs of iteration in {Mezzo}", + note = "\url{http://goo.gl/NrgKc4}", + year = "2013", + howpublished = "Higher-Order Programming and Effects (HOPE)", +} + +@InProceedings{guillemette-monnier-07, + author = "Louis-Julien Guillemette and Stefan Monnier", + title = "A Type-Preserving Closure Conversion in {Haskell}", + booktitle = hw, + pages = "83--92", + year = "2007", + URL = "http://www.iro.umontreal.ca/~monnier/tcm.pdf", +} + +@InProceedings{guillemette-monnier-08, + author = "Louis-Julien Guillemette and Stefan Monnier", + title = "A Type-Preserving Compiler in {Haskell}", + booktitle = icfp, + year = "2008", + pages = "75--86", + URL = "http://www-etud.iro.umontreal.ca/~guillelj/icfp08.pdf", +} + +@InProceedings{guillemette-vote-08, + author = "Louis-Julien Guillemette and Stefan Monnier", + title = "One Vote for Type Families in {Haskell}!", + booktitle = tfp, + year = "2008", + URL = "http://www-etud.iro.umontreal.ca/~guillelj/tfp08.pdf", +} + +@InProceedings{gundry-10, + author = "Adam Gundry and Conor McBride and James McKinna", + title = "Type inference in context", + booktitle = msfp, + pages = "43--54", + year = "2010", + URL = "https://personal.cis.strath.ac.uk/adam.gundry/type-inference/type-inference-final.pdf", +} + +@PhdThesis{gundry-13, + author = "Adam Gundry", + title = "Type Inference, {Haskell} and Dependent Types", + school = "University of Strathclyde", + year = "2013", + URL = "https://personal.cis.strath.ac.uk/adam.gundry/thesis/thesis-2013-12-03.pdf", +} + +@Article{gupta-nandivada-15, + author = "Kartik Gupta and V. Krishna Nandivada", + title = "Lexical state analyzer for {JavaCC} grammars", + journal = spe, + URL = "http://dx.doi.org/10.1002/spe.2322", + year = "2015", +} + +@InProceedings{gustavsson-svenningsson-01, + author = "Jörgen Gustavsson and Josef Svenningsson", + title = "Constraint Abstractions", + booktitle = "Symposium on Programs as Data Objects", + year = "2001", + volume = "2053", + series = lncs, + publisher = springer, + URL = "http://www.cse.chalmers.se/~josefs/publications/ca.pdf", +} + +@InProceedings{guzman-suarez-94, + author = "Juan Carlos Guzm{\'a}n and Asc{\'a}nder Su{\'a}rez", + title = "An Extended Type System for Exceptions", + booktitle = mlapp, + series = "INRIA Research Reports", + publisher = "INRIA", + number = "2265", + year = "1994", + pages = "127--135", +} + +@InProceedings{haack-huisman-hurlin-08, + author = "Christian Haack and Marieke Huisman and Cl{\'{e}}ment + Hurlin", + title = "Reasoning about {Java's} Reentrant Locks", + booktitle = aplas, + pages = "171--187", + year = "2008", + series = lncs, + volume = "5356", + publisher = springer, + URL = "http://www.cs.ru.nl/~chaack/papers/papers/reentrant.pdf", +} + +@Article{haack-hurlin-09, + author = "Christian Haack and Cl{\'{e}}ment Hurlin", + title = "Resource Usage Protocols for Iterators", + journal = jot, + volume = "8", + number = "4", + pages = "55--83", + year = "2009", + URL = "http://www.jot.fm/issues/issue_2009_06/article3.pdf", +} + +@InProceedings{haack-wells-03, + author = "Christian Haack and J. B. Wells", + title = "Type error slicing in implicitly typed, higher-order + languages", + booktitle = esop, + year = "2003", + series = lncs, + publisher = springer, + volume = "2618", + URL = "http://www.macs.hw.ac.uk/~jbw/papers/Haack+Wells:Type-Error-Slicing-in-Implicitly-Typed-Higher-Order-Languages:ESOP-2003.pdf", +} + +@InProceedings{hall-94, + author = "Cordelia Hall and Kevin Hammond and Simon {Peyton + Jones} and Philip Wadler", + title = "Type classes in {Haskell}", + booktitle = esop, + pages = "241--256", + year = "1994", + volume = "788", + series = lncs, + publisher = springer, + URL = "http://research.microsoft.com/Users/simonpj/Papers/classhask.ps.gz", +} + +@Article{hall-96, + author = "Cordelia Hall and Kevin Hammond and Simon {Peyton + Jones} and Philip Wadler", + title = "Type classes in {Haskell}", + journal = toplas, + year = "1996", + volume = "18", + number = "2", + pages = "109--138", + URL = "http://doi.acm.org/10.1145/227699.227700", +} + +@InProceedings{haller-odersky-10, + author = "Philipp Haller and Martin Odersky", + title = "Capabilities for Uniqueness and Borrowing", + booktitle = ecoop, + year = "2010", + pages = "354--378", + publisher = springer, + series = lncs, + volume = "6183", + URL = "http://lampwww.epfl.ch/~phaller/doc/haller-odersky10-Capabilities_for_uniqueness_and_borrowing.pdf", +} + +@TechReport{hallett-kfoury-04, + author = "Joseph J. Hallett and Assaf J. Kfoury", + title = "Programming Examples Needing Polymorphic Recursion", + institution = "Department of Computer Science, Boston University", + year = "2004", + number = "BUCS-TR-2004-004", + URL = "http://www.church-project.org/reports/electronic/Hal+Kfo:BUCS-TR-2004-004.pdf", +} + +@PhdThesis{hanus-88, + author = "Michael Hanus", + title = "Horn Clause Specifications with Polymorphic Types", + year = "1988", + school = "Fachbereich Informatik, Universität Dortmund", + URL = "http://www.informatik.uni-kiel.de/~mh/publications/various/Dissertation.dvi.Z", +} + +@InProceedings{hanus-89, + author = "Michael Hanus", + title = "Horn Clause Programs with Polymorphic Types: Semantics + and Resolution", + booktitle = tapsoft, + publisher = springer, + series = lncs, + volume = "352", + pages = "225--240", + year = "1989", + URL = "http://www.informatik.uni-kiel.de/~mh/publications/papers/TAPSOFT89.ps", +} + +@Manual{happy, + author = "Simon Marlow and Andy Gill", + title = "Happy: the parser generator for {Haskell}", + year = "2004", + URL = "http://www.haskell.org/happy/", +} + +@Article{hardy-88, + author = "Norm Hardy", + title = "The Confused Deputy (or why capabilities might have + been invented)", + journal = sigops, + year = "1988", + volume = "22", + number = "4", + pages = "36--38", + URL = "http://www.cis.upenn.edu/~KeyKOS/ConfusedDeputy.html", +} + +@Article{harfst-reingold-00, + author = "Gregory C. Harfst and Edward M. Reingold", + title = "A potential-based amortized analysis of the union-find + data structure", + journal = "{SIGACT} News", + volume = "31", + number = "3", + pages = "86--95", + year = "2000", + URL = "http://doi.acm.org/10.1145/356458.356463", +} + +@Article{harper-94, + author = "Robert Harper", + title = "A simplified account of polymorphic references", + journal = ipl, + volume = "51", + number = "4", + year = "1994", + pages = "201--206", + URL = "http://www.cs.cmu.edu/~rwh/papers/refs/ipl94.pdf", +} + +@Article{harper-99, + author = "Robert Harper", + title = "Proof-Directed Debugging", + journal = jfp, + volume = "9", + number = "4", + year = "1999", + pages = "463--469", + URL = "http://dx.doi.org/10.1017/S0956796808007119", +} + +@Article{harper-honsell-plotkin-93, + author = "Robert Harper and Furio Honsell and Gordon D. + Plotkin", + title = "A Framework for Defining Logics", + journal = jacm, + volume = "40", + number = "1", + pages = "143--184", + year = "1993", + URL = "http://homepages.inf.ed.ac.uk/gdp/publications/Framework_Def_Log.pdf", +} + +@Article{harper-licata-07, + author = "Robert Harper and Daniel R. Licata", + title = "Mechanizing metatheory in a logical framework", + journal = jfp, + volume = "17", + number = "4--5", + year = "2007", + pages = "613--673", + URL = "http://www.cs.cmu.edu/~rwh/papers/mech/jfp07.pdf", +} + +@Misc{harper-lillibridge-91, + author = "Bob Harper and Mark Lillibridge", + title = "{ML} with callcc is unsound", + howpublished = "Message to the {TYPES} mailing list", + year = "1991", + URL = "http://www.cis.upenn.edu/~bcpierce/types/archives/1991/msg00034.html", +} + +@InProceedings{harper-pierce-91, + author = "Robert Harper and Benjamin Pierce", + title = "A Record Calculus Based on symmetric Concatenation", + pages = "131--142", + booktitle = popl, + year = "1991", + URL = "http://www.cis.upenn.edu/~bcpierce/papers/merge.ps", +} + +@InCollection{harper-pierce-attapl, + author = "Robert Harper and Benjamin C. Pierce", + title = "Design Considerations for {ML}-Style Module Systems", + booktitle = "Advanced Topics in Types and Programming Languages", + pages = "293--345", + publisher = mitp, + year = "2005", + editor = "Benjamin C. Pierce", + chapter = "8", +} + +@Book{harrison-09, + author = "John Harrison", + title = "Handbook of Practical Logic and Automated Reasoning", + publisher = cup, + year = "2009", + URL = "http://www.cl.cam.ac.uk/~jrh13/atp/", +} + +@Book{haskell-98, + editor = "Simon {Peyton Jones}", + title = "{Haskell} 98 Language and Libraries: The Revised + Report", + publisher = cup, + year = "2003", + URL = "http://www.haskell.org/onlinereport/", +} + +@InProceedings{haskell-history-07, + author = "Paul Hudak and John Hughes and Simon {Peyton Jones} + and Philip Wadler", + title = "A History of {Haskell}: being lazy with class", + booktitle = hopl, + year = "2007", + URL = "https://www.microsoft.com/en-us/research/wp-content/uploads/2016/07/history.pdf", +} + +@TechReport{hawblitzel-05, + author = "Chris Hawblitzel", + title = "Linear Types for Aliased Resources", + institution = "Microsoft Research", + year = "2005", + number = "MSR-TR-2005-141", + URL = "http://research.microsoft.com/pubs/70228/tr-2005-141.pdf", +} + +@InProceedings{hecht-ullman-73, + author = "Matthew S. Hecht and Jeffrey D. Ullman", + title = "Analysis of a simple algorithm for global data flow + problems", + booktitle = popl, + pages = "207--217", + year = "1973", + URL = "http://doi.acm.org/10.1145/512927.512946", +} + +@TechReport{heeren-improving-02, + title = "Improving type-error messages in functional + languages", + author = "Bastiaan Heeren and Johan Jeuring and Doaitse + Swierstra and Pablo Azero Alcocer", + year = "2002", + institution = "University of Utrecht, Institute of Information and + Computing Science", + number = "UU-CS-2002-009", + URL = "http://archive.cs.uu.nl/pub/RUU/CS/techreps/CS-2002/2002-009.pdf", +} + +@TechReport{heeren2002generalizing, + title = "Generalizing {Hindley-Milner} Type Inference + Algorithms", + author = "Bastiaan Heeren and Jurriaan Hage and Doaitse + Swierstra", + year = "2002", + institution = "University of Utrecht, Institute of Information and + Computing Science", + number = "UU-CS-2002-031", + URL = "http://archive.cs.uu.nl/pub/RUU/CS/techreps/CS-2002/2002-031.pdf", +} + +@TechReport{heeren2002parametric, + title = "Parametric Type Inferencing for {Helium}", + author = "Bastiaan Heeren and Jurriaan Hage", + year = "2002", + institution = "University of Utrecht, Institute of Information and + Computing Science", + number = "UU-CS-2002-035", + URL = "http://archive.cs.uu.nl/pub/RUU/CS/techreps/CS-2002/2002-035.pdf", +} + +@InBook{hehner-96, + author = "Eric C. R. Hehner", + booktitle = "A classical mind", + title = "Abstractions of Time", + publisher = prentice, + year = "1994", + pages = "191--210", + URL = "http://www.cs.toronto.edu/~hehner/AoT.pdf", +} + +@Article{hehner-98, + author = "Eric C. R. Hehner", + title = "Formalization of Time and Space", + journal = fac, + year = "1998", + volume = "10", + pages = "290--206", + URL = "http://www.cs.toronto.edu/~hehner/FTS.pdf", +} + +@TechReport{heintze-93, + author = "Nevin Heintze", + institution = "Carnegie Mellon University, School of Computer + Science", + title = "Set Based Analysis of {ML} Programs", + year = "1993", + number = "CMU-CS-93-193", + URL = "http://reports-archive.adm.cs.cmu.edu/anon/1993/CMU-CS-93-193.ps", +} + +@InProceedings{heintze-mcallester-97, + author = "Nevin Heintze and David McAllester", + title = "Linear-Time Subtransitive Control Flow Analysis", + pages = "261--272", + booktitle = pldi, + year = "1997", + URL = "http://www.autoreason.com/PLDI97.ps", +} + +@InProceedings{heintze-riecke-slam-98, + author = "Nevin Heintze and Jon G. Riecke", + title = "The {SL}am Calculus: Programming with Secrecy and + Integrity", + booktitle = popl, + year = "1998", + pages = "365--377", + URL = "http://cm.bell-labs.com/cm/cs/who/nch/slam.ps", +} + +@InProceedings{heintze-tardieu-01, + author = "Nevin Heintze and Olivier Tardieu", + title = "Ultra-fast Aliasing Analysis using {CLA}: {A} Million + Lines of {C} Code in a Second", + pages = "254--263", + booktitle = pldi, + year = "2001", + URL = "http://cm.bell-labs.com/cm/cs/who/nch/pldi01-1m.ps", +} + +@InProceedings{helsen-thiemann-00, + author = "Simon Helsen and Peter Thiemann", + title = "Syntactic Type Soundness for the Region Calculus", + booktitle = hoots, + pages = "1--19", + year = "2000", + volume = "41", + number = "3", + series = entcs, + URL = "http://www.swen.uwaterloo.ca/~shelsen/papers/helsen-thiemann-hoots-00.pdf", +} + +@TechReport{henderson-modes-92, + author = "Fergus Henderson", + title = "Strong modes can change the world!", + institution = "Department of Computer Science, University of + Melbourne", + year = "1992", + number = "96/11", + URL = "http://www.cs.mu.oz.au/~fjh/papers/hons_thesis.ps.gz", +} + +@InProceedings{hendriks-oostrom-03, + author = "Dimitri Hendriks and Vincent van Oostrom", + title = "Adbmal", + booktitle = cade, + pages = "136--150", + year = "2003", + volume = "2741", + series = lncs, + publisher = springer, + URL = "http://www.phil.uu.nl/~oostrom/publication/ps/adbmal_jfpsv.ps", +} + +@InProceedings{henglein-91, + author = "Fritz Henglein", + booktitle = fpca, + title = "Efficient Type Inference for Higher-Order Binding-Time + Analysis", + year = "1991", + pages = "448--472", + series = lncs, + volume = "523", + publisher = springer, + URL = "ftp://ftp.diku.dk/pub/diku/users/henglein/binding-time-analysis.dvi.gz", +} + +@Article{henglein-93, + author = "Fritz Henglein", + title = "Type Inference with Polymorphic Recursion", + journal = toplas, + year = "1993", + volume = "15", + number = "2", + pages = "253--289", + URL = "http://doi.acm.org/10.1145/169701.169692", +} + +@InProceedings{henglein-breaking-97, + author = "Fritz Henglein", + title = "Breaking through the $n^3$ barrier: Faster object type + inference", + booktitle = fool, + year = "1997", +} + +@Article{henglein-breaking-99, + author = "Fritz Henglein", + title = "Breaking through the $n^3$ barrier: Faster Object Type + Inference", + journal = "Theory and Practice of Object Systems", + year = "1999", + volume = "5", + number = "1", + pages = "57--72", + URL = "ftp://ftp.diku.dk/diku/semantics/papers/D-396.ps.gz", +} + +@Article{henglein-paige-87, + author = "Robert Paige and Fritz Henglein", + title = "Mechanical translation of set theoretic problem + specifications into efficient {RAM} code -- {A} case + study", + journal = jsc, + volume = "4", + number = "2", + year = "1987", + pages = "207--232", + URL = "http://dx.doi.org/10.1016/S0747-7171(87)80066-4", +} + +@PhdThesis{henglein-phd-89, + author = "Fritz Henglein", + school = "Rutgers University", + title = "Polymorphic Type Inference and Semi-Unification", + year = "1989", + URL = "ftp://ftp.diku.dk/diku/users/henglein/poly-typ-inf-and-semi-unif.ps.gz", +} + +@InProceedings{henglein-rehof-97, + author = "Fritz Henglein and Jakob Rehof", + title = "The Complexity of Subtype Entailment for Simple + Types", + pages = "352--361", + booktitle = lics, + year = "1997", + URL = "http://research.microsoft.com/~rehof/lics97.ps", +} + +@InProceedings{henglein-rehof-98, + author = "Fritz Henglein and Jakob Rehof", + title = "Constraint Automata and the Complexity of Recursive + Subtype Entailment", + booktitle = icalp, + year = "1998", + URL = "http://research.microsoft.com/~rehof/icalp98.ps", +} + +@TechReport{hennessy-2000, + author = "Matthew Hennessy", + title = "The security picalculus and non-interference", + year = "2000", + institution = "University of Sussex", + number = "2000:05", + URL = "ftp://ftp.cogs.susx.ac.uk/pub/reports/compsci/cs052000.ps.Z", +} + +@InProceedings{hennessy-riely-00, + author = "Matthew Hennessy and James Riely", + title = "Information Flow vs. Resource Access in the + Asynchronous Pi-Calculus", + booktitle = icalp, + series = lncs, + publisher = springer, + year = "2000", + URL = "http://www.depaul.edu/~jriely/papers/00icalp.ps.gz", +} + +@InProceedings{hepburn-wright-01, + author = "Mark Hepburn and David Wright", + title = "Trust in the Pi-Calculus", + booktitle = ppdp, + year = "2001", +} + +@Article{herlihy-schachte-sondergaard-07, + author = "Brian Herlihy and Peter Schachte and Harald + Søndergaard", + title = "Un-{Kleene} {Boolean} Equation Solving", + journal = ijfcs, + year = "2007", + volume = "18", + number = "2", + pages = "227--250", + URL = "http://dx.doi.org/10.1142/S0129054107004668", +} + +@InProceedings{heule-13, + author = "Stefan Heule and K. Rustan M. Leino and Peter + M{\"u}ller and Alexander J. Summers", + title = "Abstract Read Permissions: Fractional Permissions + without the Fractions", + booktitle = vmcai, + year = "2013", + pages = "315--334", + publisher = springer, + series = lncs, + volume = "7737", + URL = "http://research.microsoft.com/en-us/um/people/leino/papers/krml225.pdf", +} + +@InProceedings{higuchi-ohori-03, + author = "Tomoyuki Higuchi and Atsushi Ohori", + title = "A Static Type System for {JVM} Access Control", + booktitle = icfp, + pages = "227--237", + year = "2003", + URL = "http://doi.acm.org/10.1145/944726", +} + +@InProceedings{hillerstrom-lindley-16, + author = "Daniel Hillerstr{\"{o}}m and Sam Lindley", + title = "Liberating effects with rows and handlers", + booktitle = "International Workshop on Type-Driven Development + (TyDe@ICFP)", + pages = "15--27", + year = "2016", + URL = "http://homepages.inf.ed.ac.uk/slindley/papers/links-effect.pdf", +} + +@Article{hindley-69, + author = "J. Roger Hindley", + title = "The Principal Type-scheme of an Object in Combinatory + Logic", + journal = tams, + volume = "146", + pages = "29--60", + year = "1969", + URL = "http://dx.doi.org/10.2307/1995158", +} + +@InCollection{hinze-03, + author = "Ralf Hinze", + editor = "Jeremy Gibbons and Oege de Moor", + booktitle = "The Fun of Programming", + title = "Fun with Phantom Types", + publisher = palgrave, + year = "2003", + pages = "245--262", + URL = "http://www.informatik.uni-bonn.de/~ralf/publications/With.pdf", +} + +@TechReport{hinze-comparing-generic-06, + author = "Ralf Hinze and Johan Jeuring and Andres Löh", + year = "2006", + title = "Comparing approaches to generic programming in + {Haskell}", + number = "UU-CS-2006-022", + institution = "Department of Information and Computing Sciences, + Utrecht University", + URL = "http://www.cs.uu.nl/research/techreps/repo/CS-2006/2006-022.pdf", +} + +@InProceedings{hinze-derivable-00, + author = "Ralf Hinze and Simon {Peyton Jones}", + title = "Derivable type classes", + booktitle = hw, + year = "2000", + URL = "https://www.microsoft.com/en-us/research/wp-content/uploads/2000/09/derive.pdf", +} + +@Unpublished{hinze-paterson-05, + author = "Ralf Hinze and Ross Paterson", + title = "Derivation of a Typed Functional {LR} Parser", + note = "Unpublished", + year = "2005", + URL = "http://www.cs.ox.ac.uk/ralf.hinze/publications/TypedLR.pdf", +} + +@Article{hinze-paterson-06, + title = "Finger trees: a simple general-purpose data + structure", + author = "Ralf Hinze and Ross Paterson", + journal = jfp, + year = "2006", + number = "2", + volume = "16", + pages = "197--217", + URL = "http://www.cs.ox.ac.uk/ralf.hinze/publications/FingerTrees.pdf", +} + +@InProceedings{hirschowitz-cbv-04, + author = "Tom Hirschowitz and Xavier Leroy and J. B. Wells", + title = "Call-by-value mixin modules: Reduction semantics, side + effects, types", + booktitle = esop, + pages = "64--78", + year = "2004", + volume = "2986", + series = lncs, + publisher = springer, + URL = "http://gallium.inria.fr/~xleroy/publi/mixins-mm-esop2004.ps.gz", +} + +@Article{hirschowitz-leroy-04, + author = "Tom Hirschowitz and Xavier Leroy", + title = "Mixin Modules in a Call-by-Value Setting", + journal = toplas, + year = "2004", + note = "To appear", + URL = "http://gallium.inria.fr/~hirschow/papers/toplas-cmsv.ps.gz", +} + +@InProceedings{hoang-mitchell-lower-95, + author = "My Hoang and John C. Mitchell", + title = "Lower Bounds on Type Inference with Subtypes", + pages = "176--185", + booktitle = popl, + year = "1995", + URL = "http://doi.acm.org/10.1145/199448.199481", +} + +@Article{hoare-61, + author = "C. A. R. Hoare", + title = "Algorithm 65: find", + journal = cacm, + volume = "4", + number = "7", + year = "1961", + pages = "321--322", + URL = "http://doi.acm.org/10.1145/366622.366647", +} + +@Article{hoare-69, + author = "C. A. R. Hoare", + title = "An axiomatic basis for computer programming", + journal = cacm, + volume = "12", + number = "10", + year = "1969", + pages = "576--580", + URL = "http://doi.acm.org/10.1145/363235.363259", +} + +@Article{hoare-71, + author = "C. A. R. Hoare", + title = "Proof of a program: {FIND}", + journal = cacm, + year = "1971", + volume = "14", + number = "1", + pages = "39--45", + URL = "http://doi.acm.org/10.1145/362452.362489", +} + +@Article{hoare-data-72, + author = "C. A. R. Hoare", + title = "Proof of correctness of data representations", + journal = acta, + year = "1972", + volume = "4", + pages = "271--281", + URL = "http://dx.doi.org/10.1007/BF00289507", +} + +@InProceedings{hobor-gherghina-11, + author = "Aquinas Hobor and Cristian Gherghina", + title = "Barriers in Concurrent Separation Logic", + booktitle = esop, + year = "2011", + series = lncs, + publisher = springer, + URL = "http://www.comp.nus.edu.sg/~hobor/Publications/barrier.pdf", +} + +@InProceedings{hobor-indirection-10, + author = "Aquinas Hobor and Robert Dockins and Andrew W. Appel", + title = "A Theory of Indirection via Approximation", + booktitle = popl, + year = "2010", + URL = "http://www.comp.nus.edu.sg/~hobor/Publications/indirection.pdf", +} + +@InProceedings{hobor-oracle-08, + author = "Aquinas Hobor and Andrew W. Appel and Francesco {Zappa + Nardelli}", + title = "Oracle Semantics for Concurrent Separation Logic", + booktitle = esop, + pages = "353--367", + year = "2008", + volume = "4960", + series = lncs, + publisher = springer, + URL = "http://www.cs.princeton.edu/~appel/papers/concurrent.pdf", +} + +@Article{hoffmann-aehlig-hofmann-multivariate-12, + author = "Jan Hoffmann and Klaus Aehlig and Martin Hofmann", + title = "Multivariate amortized resource analysis", + journal = toplas, + volume = "34", + number = "3", + pages = "14:1--14:62", + year = "2012", + URL = "http://doi.acm.org/10.1145/2362389.2362393", +} + +@InProceedings{hoffmann-aehlig-hofmann-raml-12, + author = "Jan Hoffmann and Klaus Aehlig and Martin Hofmann", + title = "Resource Aware {ML}", + booktitle = cav, + pages = "781--786", + year = "2012", + URL = "http://dx.doi.org/10.1007/978-3-642-31424-7_64", + series = lncs, + volume = "7358", + publisher = springer, +} + +@InProceedings{hoffmann-das-weng-17, + author = "Jan Hoffmann and Ankush Das and Shu{-}Chun Weng", + title = "Towards automatic resource bound analysis for + {OCaml}", + booktitle = popl, + pages = "359--373", + year = "2017", + URL = "http://www.cs.cmu.edu/~janh/papers/HoffmannDW17.pdf", +} + +@InProceedings{hoffmann-hofmann-10, + author = "Jan Hoffmann and Martin Hofmann", + title = "Amortized Resource Analysis with Polynomial + Potential", + booktitle = esop, + pages = "287--306", + year = "2010", + volume = "6012", + series = lncs, + publisher = springer, + URL = "http://www.cs.yale.edu/homes/hoffmann/papers/aapoly_conference.pdf", +} + +@InProceedings{hoffmann-marmar-shao-13, + author = "Jan Hoffmann and Michael Marmar and Zhong Shao", + title = "Quantitative Reasoning for Proving Lock-Freedom", + booktitle = lics, + year = "2013", + pages = "124--133", + URL = "http://www.cs.cmu.edu/~janh/papers/lockfree2013.pdf", +} + +@Article{hofmann-00, + author = "Martin Hofmann", + title = "A type system for bounded space and functional + in-place update", + journal = njc, + year = "2000", + volume = "7", + number = "4", + pages = "258--289", + URL = "http://www.tcs.informatik.uni-muenchen.de/~mhofmann/nordic.ps.gz", +} + +@InProceedings{hofmann-jost-03, + author = "Martin Hofmann and Steffen Jost", + title = "Static prediction of heap space usage for first-order + functional programs", + booktitle = popl, + year = "2003", + pages = "185--197", + URL = "http://www2.tcs.ifi.lmu.de/~jost/research/POPL_2003_Jost_Hofmann.pdf", +} + +@InProceedings{hofmann-moser-14, + author = "Martin Hofmann and Georg Moser", + title = "Amortised Resource Analysis and Typed Polynomial + Interpretations", + booktitle = tlca, + pages = "272--286", + year = "2014", + volume = "8560", + series = lncs, + publisher = springer, + URL = "http://arxiv.org/pdf/1402.1922.pdf", +} + +@InProceedings{hofmann-pavlova-08, + author = "Martin Hofmann and Mariela Pavlova", + title = "Elimination of ghost variables in program logics", + booktitle = "Trustworthy Global Computing", + pages = "1--20", + year = "2008", + volume = "4912", + series = lncs, + publisher = springer, + URL = "http://www-sop.inria.fr/everest/personnel/Mariela.Pavlova/ghost.pdf", +} + +@Article{hofmann-pierce-94, + author = "Martin Hofmann and Benjamin Pierce", + title = "A Unifying Type-Theoretic Framework for Objects", + journal = jfp, + volume = "5", + number = "4", + pages = "593--635", + note = "Previous versions appeared in the Symposium on + Theoretical Aspects of Computer Science, 1994, (pages + 251--262) and, under the title ``An Abstract View of + Objects and Subtyping (Preliminary Report),'' as + University of Edinburgh, LFCS technical report + ECS-LFCS-92-226, 1992", + year = "1995", + URL = "http://www.cis.upenn.edu/~bcpierce/papers/abstroop.ps", +} + +@InProceedings{hogg-91, + author = "John Hogg", + title = "Islands: Aliasing Protection in Object-Oriented + Languages", + booktitle = oopsla, + year = "1991", + pages = "271--285", + URL = "http://dx.doi.org/10.1145/118014.117975", +} + +@InProceedings{honda-al-00, + author = "Kohei Honda and Vasco Vasconcelos and Nobuko Yoshida", + title = "Secure information flow as typed process behaviour", + booktitle = esop, + publisher = springer, + series = lncs, + volume = "1782", + pages = "180--199", + year = "2000", + URL = "ftp://ftp.dcs.qmw.ac.uk/lfp/kohei/siftp-esop00.ps.gz", +} + +@TechReport{honda-al-00-long, + author = "Kohei Honda and Vasco Vasconcelos and Nobuko Yoshida", + title = "Secure information flow as typed process behaviour", + institution = "Queen Mary and Westfield College, University of + London", + year = "1999", + number = "QMW-DCS-1999-767", + URL = "ftp://ftp.dcs.qmw.ac.uk/lfp/kohei/siftp-qmwrep.ps.gz", +} + +@InProceedings{honda-yoshida-02, + author = "Kohei Honda and Nobuko Yoshida", + title = "A Uniform Type Structure for Secure Information Flow", + booktitle = popl, + year = "2002", + pages = "81--92", + URL = "http://www.mcs.le.ac.uk/~nyoshida/paper/ifa_long.ps.gz", +} + +@InProceedings{honda-yoshida-04, + author = "Kohei Honda and Nobuko Yoshida", + title = "A compositional logic for polymorphic higher-order + functions", + booktitle = ppdp, + year = "2004", + pages = "191--202", + URL = "http://www.dcs.qmul.ac.uk/~kohei/logics/polyrec.pdf.gz", +} + +@InProceedings{honsell-01, + author = "Furio Honsell and Marino Miculan and Ivan Scagnetto", + title = "An axiomatic approach to metareasoning on nominal + algebras in {HOAS}", + booktitle = icalp, + pages = "963--978", + year = "2001", + volume = "2076", + series = lncs, + publisher = springer, + URL = "https://users.dimi.uniud.it/~marino.miculan/Papers/ICALP01.pdf", +} + +@InCollection{hopcroft-minimizing-71, + author = "John~E. Hopcroft", + title = "An $n\log n$ algorithm for minimizing states in a + finite automaton", + booktitle = "Theory of Machines and Computations", + editor = "Z. Kohavi", + publisher = ap, + year = "1971", + pages = "189--196", +} + +@Book{hopcroft-motwani-ullman-00, + author = "John E. Hopcroft and Rajeev Motwani and Jeffrey D. + Ullman", + title = "Introduction to Automata Theory, Languages, and + Computation", + publisher = aw, + year = "2000", + URL = "http://www-db.stanford.edu/~ullman/ialc.html", +} + +@Article{hopcroft-ullman-73, + author = "John E. Hopcroft and Jeffrey D. Ullman", + title = "Set Merging Algorithms", + journal = siamjc, + volume = "2", + number = "4", + pages = "294--303", + year = "1973", + URL = "http://dx.doi.org/10.1137/0202024", +} + +@InProceedings{horning-74, + author = "James J. Horning", + title = "What the Compiler Should Tell the User", + booktitle = cc, + year = "1974", + pages = "525--548", + volume = "21", + series = lncs, + publisher = springer, + URL = "http://dx.doi.org/10.1007/3540069585_64", +} + +@Article{horspool-faster-90, + author = "R. Nigel Horspool and Michael Whitney", + title = "Even Faster {LR} Parsing", + journal = spe, + year = "1990", + volume = "20", + number = "6", + pages = "515--535", + URL = "http://www.cs.uvic.ca/~nigelh/Publications/fastparse.pdf", +} + +@InProceedings{horwitz-95, + author = "Susan Horwitz and Thomas Reps and Mooly Sagiv", + title = "Demand interprocedural dataflow analysis", + booktitle = "ACM Symposium on the Foundations of Software + Engineering (FSE)", + year = "1995", + URL = "http://www.cs.wisc.edu/wpis/papers/fse95a.ps", +} + +@Article{horwitz-demers-teitelbaum-87, + author = "Alan Demers and Susan Horwitz and Tim Teitelbaum", + title = "An efficient general algorithm for dataflow analysis", + journal = acta, + year = "1987", + volume = "24", + number = "6", + pages = "679--694", + URL = "http://dx.doi.org/10.1007/BF00282621", +} + +@Article{hosoya-pierce-02, + author = "Haruo Hosoya and Benjamin C. Pierce", + title = "Regular expression pattern matching for {XML}", + journal = jfp, + volume = "13", + number = "6", + year = "2003", + pages = "961--1004", + URL = "http://dx.doi.org/10.1017/S0956796802004410", +} + +@TechReport{howell-08, + author = "Rodney R. Howell", + title = "On Asymptotic Notation with Multiple Variables", + institution = "Kansas State University", + year = "2008", + number = "2007-4", + URL = "http://people.cs.ksu.edu/~rhowell/asymptotic.pdf", +} + +@Misc{howell-book, + author = "Rodney R. Howell", + title = "Algorithms: {A} Top-Down Approach", + year = "2012", + note = "Draft", + URL = "http://people.cs.ksu.edu/~rhowell/algorithms-text/text/", +} + +@Article{hru-76, + author = "Michael A. Harrison and Walter L. Ruzzo and Jeffrey D. + Ullman", + title = "Protection in Operating Systems", + journal = cacm, + year = "1976", + volume = "19", + number = "8", + pages = "461--471", + URL = "http://doi.acm.org/10.1145/360303.360333", +} + +@InProceedings{hubert-marche-07, + author = "Thierry Hubert and Claude Marché", + title = "Separation Analysis for Deductive Verification", + booktitle = hav, + year = "2007", + URL = "http://www.lri.fr/~marche/hubert07hav.pdf", +} + +@PhdThesis{huet-76, + author = "G{\'e}rard Huet", + title = "{R}{\'e}solution d'{\'e}quations dans des langages + d'ordre $1$, $2$, $\ldots$, $\omega$", + school = "Universit{\'e} Paris 7", + year = "1976", +} + +@Article{huet-98, + author = "Gérard Huet", + title = "Regular {Böhm} Trees", + journal = mscs, + year = "1998", + volume = "8", + pages = "671--680", + URL = "http://yquem.inria.fr/~huet/PUBLIC/RBT2.pdf", +} + +@Article{huet-zipper-97, + author = "G{\'e}rard Huet", + title = "The Zipper", + journal = jfp, + volume = "7", + number = "5", + year = "1997", + pages = "549--554", + URL = "http://yquem.inria.fr/~huet/PUBLIC/zip.pdf", +} + +@InProceedings{huffman-urban-10, + author = "Brian Huffman and Christian Urban", + title = "A New Foundation for {Nominal Isabelle}", + booktitle = itp, + pages = "35--50", + year = "2010", + series = lncs, + volume = "6172", + publisher = springer, + URL = "http://nms.kcl.ac.uk/christian.urban/Publications/nominal-atoms.pdf", +} + +@Article{hughes-arrows-00, + author = "John Hughes", + title = "Generalising monads to arrows", + journal = scp, + volume = "37", + number = "1--3", + year = "2000", + pages = "67--111", + URL = "http://www.cse.chalmers.se/~rjmh/Papers/arrows.pdf", +} + +@Article{hughes-matters-89, + author = "John Hughes", + title = "Why Functional Programming Matters", + journal = cj, + volume = "32", + number = "2", + pages = "98--107", + year = "1989", + URL = "http://www.cse.chalmers.se/~rjmh/Papers/whyfp.pdf", +} + +@InProceedings{hughes-pareto-sabry-96, + author = "John Hughes and Lars Pareto and Amr Sabry", + title = "Proving the correctness of reactive systems using + sized types", + booktitle = popl, + year = "1996", + pages = "410--423", + URL = "http://doi.acm.org/10.1145/237721.240882", +} + +@Article{hutton-fold-99, + author = "Graham Hutton", + title = "A Tutorial on the Universality and Expressiveness of + Fold", + journal = jfp, + volume = "9", + number = "4", + pages = "355--372", + year = "1999", + URL = "http://www.cs.nott.ac.uk/~pszgmh/fold.pdf", +} + +@Article{igarashi-kobayashi-00, + author = "Atsushi Igarashi and Naoki Kobayashi", + title = "Type Reconstruction for Linear $\pi$-Calculus with + {I}/{O} Subtyping", + journal = ic, + volume = "161", + pages = "1--44", + year = "2000", + URL = "http://www.sato.kuis.kyoto-u.ac.jp/~igarashi/papers/psgz/linear-pi.IC.ps.gz", +} + +@InProceedings{ishtiaq-ohearn-01, + author = "Samin S. Ishtiaq and Peter W. O'Hearn", + title = "{BI} as an assertion language for mutable data + structures", + booktitle = popl, + year = "2001", + pages = "14--26", + URL = "http://www.cs.ucl.ac.uk/staff/p.ohearn/papers/bi-assertion-lan.pdf", +} + +@InCollection{iwaco-03, + author = "Dave Clarke and Sophia Drossopoulou and James Noble", + title = "Aliasing, Confinement, and Ownership in + Object-Oriented Programming", + booktitle = "Object-Oriented Technology. {ECOOP 2003} Workshop + Reader", + year = "2004", + publisher = springer, + series = lncs, + volume = "3013", + pages = "197--207", + URL = "http://dx.doi.org/10.1007/978-3-540-25934-3_19", +} + +@Manual{jacc, + title = "jacc: Just Another Compiler Compiler for {Java}", + author = "Mark P. Jones", + year = "2004", + URL = "http://web.cecs.pdx.edu/~mpj/jacc/jacc.pdf", +} + +@InProceedings{jackson-vaziri-00, + author = "Daniel Jackson and Mandana Vaziri", + title = "Finding Bugs with a Constraint Solver", + booktitle = issta, + year = "2000", + URL = "http://sdg.csail.mit.edu/pubs/2000/issta00.pdf", +} + +@InProceedings{jacobs-termination-15, + author = "Bart Jacobs and Dragan Bosnacki and Ruurd Kuipe", + title = "Modular Termination Verification", + booktitle = ecoop, + pages = "99--1023", + year = "2015", + series = lipics, + URL = "http://people.cs.kuleuven.be/~bart.jacobs/ecoop2015.pdf", +} + +@InProceedings{jagannathan-wright-95, + author = "Suresh Jagannathan and Andrew Wright", + title = "Effective Flow Analysis for Avoiding Run-Time Checks", + year = "1995", + booktitle = sas, + publisher = springer, + series = lncs, + volume = "983", + URL = "http://www.cs.purdue.edu/homes/suresh/papers/sas95.ps.gz", +} + +@PhdThesis{jansson-00, + author = "Patrik Jansson", + title = "Functional Polytypic Programming", + school = "Chalmers University of Technology", + year = "2000", + URL = "http://www.cse.chalmers.se/~patrikj/poly/polythesis/Jansson2000_PhD_thesis.pdf", +} + +@Book{java, + author = "James Gosling and Bill Joy and Guy Steele and Gilad + Bracha", + title = "The {Java} Language Specification, Second Edition", + publisher = aw, + year = "2000", + URL = "http://java.sun.com/docs/books/jls/", +} + +@Book{javasec, + author = "Li Gong and Gary Ellison and Mary Dageforde", + title = "Inside {Java 2} Platform Security, Second Edition", + publisher = aw, + year = "2003", + URL = "http://java.sun.com/docs/books/security/", +} + +@Article{jay-04, + author = "C. Barry Jay", + title = "The Pattern Calculus", + journal = toplas, + volume = "26", + number = "6", + pages = "911--937", + year = "2004", + URL = "http://www-staff.it.uts.edu.au/~cbj/Publications/pattern_calculus.pdf", + alturl = "http://doi.acm.org/10.1145/1034774.1034775", +} + +@Article{jeffery-03, + author = "Clinton L. Jeffery", + title = "Generating {LR} syntax error messages from examples", + journal = toplas, + volume = "25", + number = "5", + year = "2003", + pages = "631--640", + URL = "http://doi.acm.org/10.1145/937563.937566", +} + +@InProceedings{jensen-13, + author = "Jonas Braband Jensen and Nick Benton and Andrew + Kennedy", + title = "High-level separation logic for low-level code", + booktitle = popl, + pages = "301--314", + year = "2013", + URL = "http://research.microsoft.com/en-us/um/people/nick/hlsl.pdf", +} + +@InProceedings{jensen-98, + author = "Thomas Jensen", + title = "Inference of polymorphic and conditional strictness + properties", + booktitle = popl, + year = "1998", + pages = "209--221", + publisher = acmp, + URL = "http://www.irisa.fr/lande/jensen/papers/popl98.ps", +} + +@InProceedings{jensen-al-99, + author = "Thomas Jensen and Daniel {Le Métayer} and Tommy + Thorn", + title = "Verifying security properties of control-flow graphs", + booktitle = sp, + pages = "89--105", + year = "1999", + URL = "http://www.irisa.fr/lande/jensen/papers/SP99.ps", +} + +@InProceedings{jensen-birkedal-fictional-12, + author = "Jonas Braband Jensen and Lars Birkedal", + title = "Fictional Separation Logic", + booktitle = esop, + year = "2012", + pages = "377--396", + publisher = springer, + series = lncs, + volume = "7211", + URL = "http://cs.au.dk/~birke/papers/sharing-conf.pdf", +} + +@InProceedings{jensen-ployette-ridoux-02, + title = "Iteration schemes for fixed point computation", + author = "Thomas Jensen and Florimond Ployette and Olivier + Ridoux", + year = "2002", + booktitle = fics, + pages = "69--76", + URL = "http://www.irisa.fr/lande/REQS/fics02.ps", +} + +@InProceedings{jha-al-02, + author = "Somesh Jha and Jens Palsberg and Tian Zhao", + title = "Efficient Type Matching", + booktitle = fossacs, + pages = "187--204", + year = "2002", + publisher = springer, + series = lncs, + volume = "2303", + URL = "http://www.cs.ucla.edu/~palsberg/paper/fossacs02.pdf", +} + +@InProceedings{jia-05, + author = "Limin Jia and Frances Spalding and David Walker and + Neal Glew", + title = "Certifying Compilation for a Language with Stack + Allocation", + booktitle = lics, + year = "2005", + URL = "http://www.cs.princeton.edu/~dpw/papers/stackcert-lics05.pdf", + pages = "407--416", +} + +@InProceedings{jia-walker-06, + author = "Limin Jia and David Walker", + title = "{ILC}: {A} Foundation for Automated Reasoning About + Pointer Programs", + booktitle = esop, + year = "2006", + pages = "131--145", + publisher = springer, + series = lncs, + volume = "3924", + URL = "http://sip.cs.princeton.edu/pub/ilc-esop06.pdf", +} + +@InProceedings{jim-00, + author = "Trevor Jim", + title = "A Polar Type System", + booktitle = itrs, + year = "2000", + volume = "8", + series = pi, + publisher = carleton, + URL = "http://www.cee.hw.ac.uk/~jbw/itrs/itrs00/papers/Jim:ITRS-2000.ps.gz", +} + +@TechReport{jim-95, + author = "Trevor Jim", + title = "What are principal typings and what are they good + for?", + institution = "Massachusetts Institute of Technology", + year = "1995", + number = "MIT/LCS TM-532", + URL = "http://www.research.att.com/~trevor/papers/principal-typings.ps.gz", +} + +@Unpublished{jim-palsberg-99, + author = "Trevor Jim and Jens Palsberg", + title = "Type inference in systems of recursive types with + subtyping", + year = "1999", + note = "Manuscript", + URL = "http://www.cs.ucla.edu/~palsberg/draft/jim-palsberg99.pdf", +} + +@Manual{jml, + title = "{JML} Reference Manual", + author = "Gary T. Leavens and Erik Poll and Curtis Clifton and + Yoonsik Cheon and Clyde Ruby and David Cok and Peter + Müller and Joseph Kiniry and Patrice Chalin and Daniel + M. Zimmerman", + year = "2008", + URL = "http://www.jmlspecs.org/OldReleases/jmlrefman.pdf", +} + +@Article{jml-05, + author = "Lilian Burdy and Yoonsik Cheon and David Cok and + Michael Ernst and Joe Kiniry and Gary T. Leavens and K. + Rustan M. Leino and Erik Poll", + title = "An overview of {JML} tools and applications", + journal = sttt, + year = "2005", + volume = "7", + number = "3", + pages = "212--232", + URL = "http://research.microsoft.com/en-us/um/people/leino/papers/jml-sttt.pdf", +} + +@TechReport{johnson-75, + author = "Stephen C. Johnson", + title = "Yacc: Yet Another Compiler-Compiler", + institution = "Bell Laboratories", + year = "1975", + type = "Computing Science Technical Report", + number = "32", + URL = "http://dinosaur.compilertools.net/yacc/yacc.ps", +} + +@InProceedings{johnson-walz-86, + author = "Gregory F. Johnson and Janet A. Walz", + title = "A maximum-flow approach to anomaly isolation in + unification-based incremental type inference", + booktitle = popl, + pages = "44--57", + year = "1986", +} + +@InCollection{johnson-yacc-79, + author = "Steven C. Johnson", + title = "{Yacc}: Yet Another Compiler Compiler", + booktitle = "{UNIX} Programmer's Manual", + volume = "2", + publisher = "Holt, Rinehart, and Winston", + pages = "353--387", + year = "1979", + URL = "http://dinosaur.compilertools.net/", +} + +@InCollection{johnsson-85, + author = "Thomas Johnsson", + editor = "Jean-Pierre Jouannaud", + title = "Lambda Lifting: Transforming Programs to Recursive + Equations", + booktitle = fpca, + series = lncs, + volume = "201", + pages = "190--203", + publisher = springer, + year = "1985", + URL = "http://dx.doi.org/10.1007/3-540-15975-4_37", +} + +@InProceedings{jones-92, + author = "Mark P. Jones", + title = "A theory of qualified types", + booktitle = esop, + year = "1992", + volume = "582", + series = lncs, + publisher = springer, + URL = "http://web.cecs.pdx.edu/~mpj/pubs/esop92.html", +} + +@Book{jones-94, + author = "Mark P. Jones", + title = "Qualified Types: Theory and Practice", + publisher = cup, + year = "1994", +} + +@TechReport{jones-95, + author = "Mark P. Jones", + title = "From {Hindley-Milner} Types to First-Class + Structures", + institution = "Yale University", + year = "1995", + type = "Research Report", + number = "YALEU/DCS/RR-1075", + URL = "http://web.cecs.pdx.edu/~mpj/pubs/haskwork95.html", +} + +@InProceedings{jones-96, + author = "Mark P. Jones", + title = "Using Parameterized Signatures to Express Modular + Structure", + booktitle = popl, + year = "1996", + URL = "http://web.cecs.pdx.edu/~mpj/pubs/paramsig.html", +} + +@InProceedings{jones-dictionary-94, + author = "Mark P. Jones", + title = "Dictionary-free Overloading by Partial Evaluation", + booktitle = pepm, + year = "1994", + URL = "http://web.cecs.pdx.edu/~mpj/pubs/pepm94.ps", +} + +@InProceedings{jones-peyton-jones-99, + author = "Mark P. Jones and Simon {Peyton Jones}", + title = "Lightweight Extensible Records for {Haskell}", + booktitle = hw, + year = "1999", + URL = "http://web.cecs.pdx.edu/~mpj/pubs/recpro.ps.gz", +} + +@TechReport{jones-qualified-94, + author = "Mark P. Jones", + institution = "Yale University", + title = "Simplifying and Improving Qualified Types", + year = "1994", + number = "YALEU/DCS/RR-1040", + URL = "ftp://nebula.cs.yale.edu/pub/yale-fp/reports/RR-1040.ps.Z", +} + +@InProceedings{jones-thih-99, + author = "Mark P. Jones", + title = "Typing {Haskell} in {Haskell}", + booktitle = hw, + year = "1999", + URL = "http://web.cecs.pdx.edu/~mpj/thih/", +} + +@InProceedings{jorgensen-93, + author = "Niels Jørgensen", + title = "Chaotic Fixpoint Iteration Guided by Dynamic + Dependency", + booktitle = wsa, + year = "1993", + pages = "27--44", + series = lncs, + volume = "724", + publisher = springer, + URL = "http://webhotel2.ruc.dk/nielsj/research/publications/wsa93.ps", +} + +@InProceedings{jost-hammond-loidl-hofmann-10, + author = "Steffen Jost and Kevin Hammond and Hans{-}Wolfgang + Loidl and Martin Hofmann", + title = "Static determination of quantitative resource usage + for higher-order programs", + booktitle = popl, + pages = "223--236", + year = "2010", + URL = "http://www2.tcs.ifi.lmu.de/~jost/research/POPL_2010__Higher-Order_AA__Jost_etAl.pdf", +} + +@InProceedings{jost-loidl-hammond-scaife-hofmann-09, + author = "Steffen Jost and Hans{-}Wolfgang Loidl and Kevin + Hammond and Norman Scaife and Martin Hofmann", + title = "{"}Carbon Credits{"} for Resource-Bounded Computations + Using Amortised Analysis", + booktitle = fm, + pages = "354--369", + year = "2009", + series = lncs, + volume = "5850", + publisher = springer, + URL = "http://www2.tcs.ifi.lmu.de/~jost/research/FM09_AmortisedAnalysis__Jost_etAl.pdf", +} + +@TechReport{jouannaud-kirchner-90, + author = "Jean-Pierre Jouannaud and Claude Kirchner", + title = "Solving equations in abstract algebras: a rule-based + survey of unification", + institution = "Université Paris-Sud", + number = "561", + year = "1990", +} + +@InCollection{jouannaud-kirchner-91, + author = "Jean-Pierre Jouannaud and Claude Kirchner", + title = "Solving equations in abstract algebras: a rule-based + survey of unification", + booktitle = "Computational Logic. Essays in honor of Alan + Robinson", + publisher = mitp, + year = "1991", + editor = "Jean-Louis Lassez and Gordon Plotkin", + chapter = "8", + pages = "257--321", +} + +@InProceedings{jourdan-leroy-pottier-12, + author = "Jacques-Henri Jourdan and François Pottier and Xavier + Leroy", + title = "Validating ${LR}(1)$ Parsers", + year = "2012", + booktitle = esop, + publisher = springer, + series = lncs, + volume = "7211", + pages = "397--416", + URL = "http://gallium.inria.fr/~fpottier/publis/jourdan-leroy-pottier-validating-parsers.pdf", +} + +@InProceedings{jourdan-verasco-15, + author = "Jacques{-}Henri Jourdan and Vincent Laporte and + Sandrine Blazy and Xavier Leroy and David Pichardie", + title = "A Formally-Verified {C} Static Analyzer", + booktitle = popl, + pages = "247--259", + year = "2015", + URL = "http://gallium.inria.fr/~xleroy/publi/verasco-popl2015.pdf", +} + +@InProceedings{jung-15, + author = "Ralf Jung and David Swasey and Filip Sieczkowski and + Kasper Svendsen and Aaron Turon and Lars Birkedal and + Derek Dreyer", + title = "Iris: Monoids and Invariants as an Orthogonal Basis + for Concurrent Reasoning", + booktitle = popl, + pages = "637--650", + year = "2015", + URL = "http://plv.mpi-sws.org/iris/paper.pdf", +} + +@Article{kam-ullman-76, + author = "John B. Kam and Jeffrey D. Ullman", + title = "Global Data Flow Analysis and Iterative Algorithms", + journal = jacm, + year = "1976", + volume = "23", + number = "1", + pages = "158--171", + URL = "http://doi.acm.org/10.1145/321921.321938", +} + +@Article{kam-ullman-77, + author = "John B. Kam and Jeffrey D. Ullman", + title = "Monotone Data Flow Analysis Frameworks", + journal = acta, + year = "1977", + volume = "7", + number = "3", + pages = "305--317", + URL = "http://dx.doi.org/10.1007/BF00290339", +} + +@InProceedings{kammar-lindley-oury-13, + author = "Ohad Kammar and Sam Lindley and Nicolas Oury", + title = "Handlers in action", + booktitle = icfp, + pages = "145--158", + year = "2013", + URL = "http://homepages.inf.ed.ac.uk/slindley/papers/handlers.pdf", +} + +@PhdThesis{kanig-10, + author = "Johannes Kanig", + title = "Specification and Proof of Higher-Order Programs", + school = "Université Paris-Sud", + year = "2010", + URL = "http://www.lri.fr/~kanig/files/thesis-kanig-15112010.pdf", +} + +@Article{kantorowitz-laor-86, + author = "E. Kantorowitz and H. Laor", + title = "Automatic generation of useful syntax error messages", + journal = spe, + volume = "16", + number = "7", + publisher = "John Wiley \& Sons", + URL = "http://dx.doi.org/10.1002/spe.4380160703", + pages = "627--640", + year = "1986", +} + +@InProceedings{kaplan-shafrir-tarjan-02, + author = "Haim Kaplan and Nira Shafrir and Robert E. Tarjan", + title = "Union-find with deletions", + booktitle = soda, + pages = "19--28", + year = "2002", + URL = "http://dl.acm.org/citation.cfm?id=545381.545384", +} + +@Article{kaplan-tarjan-99, + author = "Haim Kaplan and Robert E. Tarjan", + title = "Purely functional, real-time deques with catenation", + journal = jacm, + volume = "46", + number = "5", + year = "1999", + pages = "577--603", + URL = "http://www.math.tau.ac.il/~haimk/bob.ps", +} + +@Article{kapur-zhang-rrl, + author = "Deepak Kapur and Hantao Zhang", + title = "An overview of {Rewrite Rule Laboratory (RRL)}", + journal = "J. Comput. Appl. Math.", + year = "1995", + volume = "29", + number = "2", + pages = "91--114", + URL = "ftp://ftp.cs.albany.edu/pub/ipl/papers/overview.rrl.ps.gz", +} + +@TechReport{kashiwagi-wise-91, + author = "Yugo Kashiwagi and David S. Wise", + title = "Graph Algorithms in a Lazy Functional Programming + Language", + institution = "Indiana University", + year = "1991", + type = "Technical Report", + number = "330", + URL = "http://www.cs.indiana.edu/pub/techreports/TR330.pdf", +} + +@InProceedings{kassios-06, + author = "Ioannis T. Kassios", + title = "Dynamic Frames: Support for Framing, Dependencies and + Sharing Without Restrictions", + booktitle = fm, + year = "2006", + pages = "268--283", + publisher = springer, + series = lncs, + volume = "4085", + URL = "http://n.ethz.ch/~kassiosi/papers/fm06.pdf", +} + +@PhdThesis{keinanen-06, + author = "Misa Keinänen", + title = "Techniques For Solving {Boolean} Equation Systems", + school = "Helsinki University of Technology", + year = "2006", + note = "Research Report HUT-TCS-A105", + URL = "http://www.tcs.hut.fi/Publications/bibdb/HUT-TCS-A105.pdf", +} + +@Article{keisu-94, + author = "Torbjörn Keisu", + title = "Finite and Rational Tree Constraints", + journal = "Bulletin of the {IGPL}", + year = "1994", + volume = "2", + number = "2", + pages = "167--204", + URL = "http://www.dcs.kcl.ac.uk/journals/igpl/IGPL/V2-2/Keisu.ps.gz", +} + +@PhdThesis{keisu-phd-94, + author = "Torbjörn Keisu", + title = "Tree Constraints", + school = "The Royal Institute of Technology (KTH)", + year = "1994", + URL = "ftp://ftp.sics.se/pub/ps/papers/torbjorn-keisu-thesis.ps.gz", +} + +@InProceedings{kennedy-07, + author = "Andrew Kennedy", + title = "Compiling with continuations, continued", + booktitle = icfp, + year = "2007", + pages = "177--190", + URL = "http://research.microsoft.com/~akenn/sml/CompilingWithContinuationsContinued.pdf", +} + +@InProceedings{kennedy-75, + author = "Ken W. Kennedy", + title = "Node listings applied to data flow analysis", + booktitle = popl, + year = "1975", + pages = "10--21", + URL = "http://doi.acm.org/10.1145/512976.512978", +} + +@InProceedings{kennedy-94, + author = "Andrew Kennedy", + title = "Dimension Types", + booktitle = esop, + year = "1994", + volume = "788", + series = lncs, + publisher = springer, + URL = "http://research.microsoft.com/~akenn/units/DimensionTypes.pdf", +} + +@TechReport{kennedy-96, + author = "Andrew Kennedy", + title = "Type Inference and Equational Theories", + institution = "École Polytechnique", + year = "1996", + number = "LIX/RR/96/09", +} + +@InProceedings{kerber-91, + author = "Manfred Kerber", + title = "How to Prove Higher Order Theorems in First Order + Logic", + booktitle = ijcai, + year = "1991", + pages = "137--142", + URL = "ftp://ftp.cs.bham.ac.uk/pub/authors/M.Kerber/91-IJCAI.pdf", +} + +@Book{kernighan-ritchie-88, + author = "Brian W. Kernighan and Dennis Ritchie", + title = "The {C} Programming Language, Second Edition", + publisher = prentice, + year = "1988", +} + +@Unpublished{keuchel-schrijvers-inbound-15, + author = "Steven Keuchel and Tom Schrijvers", + title = "\textsc{InBound}: simple yet powerful specification of + syntax with binders", + note = "Unpublished", + year = "2015", + URL = "http://users.ugent.be/~skeuchel/publications/inbound.pdf", +} + +@InProceedings{kfoury-ml-90, + author = "Assaf J. Kfoury and Jerzy Tiuryn and Pawel Urzyczyn", + title = "{ML} Typability is {DEXPTIME}-Complete", + booktitle = "Colloquium on Trees in Algebra and Programming", + publisher = springer, + series = lncs, + volume = "431", + pages = "206--220", + year = "1990", + URL = "http://dx.doi.org/10.1007/3-540-52590-4_50", +} + +@Article{kfoury-recursion-93, + author = "A. J. Kfoury and J. Tiuryn and P. Urzyczyn", + title = "Type reconstruction in the presence of polymorphic + recursion", + journal = toplas, + volume = "15", + number = "2", + year = "1993", + pages = "290--311", + URL = "http://doi.acm.org/10.1145/169701.169687", +} + +@Article{kfoury-wells-2004, + author = "Assaf J. Kfoury and J. B. Wells", + title = "Principality and Type Inference for Intersection Types + Using Expansion Variables", + journal = tcs, + volume = "311", + number = "1--3", + pages = "1--70", + year = "2004", + URL = "http://www.church-project.org/reports/Kfo+Wel:TCSB-2004-v311n1-3.html", +} + +@Unpublished{kieburtz-02, + author = "Richard B. Kieburtz", + title = "${P}$-logic: Property verification for {Haskell} + programs", + note = "Draft", + year = "2002", + URL = "http://www.cse.ogi.edu/PacSoft/projects/programatica/plogic.pdf", +} + +@InProceedings{kieburtz-98, + author = "Richard B. Kieburtz", + title = "Taming effects with monadic typing", + booktitle = icfp, + year = "1998", + pages = "51--62", + URL = "http://doi.acm.org/10.1145/289423.289428", +} + +@InProceedings{kildall-73, + author = "Gary A. Kildall", + title = "A unified approach to global program optimization", + booktitle = popl, + year = "1973", + pages = "194--206", + URL = "http://doi.acm.org/10.1145/512927.512945", +} + +@InProceedings{kim-yi-calcagno-06, + author = "Ik-Soon Kim and Kwangkeun Yi and Cristiano Calcagno", + title = "A polymorphic modal type system for {Lisp}-like + multi-staged languages", + booktitle = popl, + year = "2006", + pages = "257--268", + URL = "http://www.doc.ic.ac.uk/~ccris/ftp/06-popl-kiyicr.pdf", +} + +@InProceedings{king-wadler-92, + author = "David King and Philip Wadler", + title = "Combining Monads", + booktitle = "Workshop on Functional Programming", + publisher = springer, + year = "1992", + URL = "http://homepages.inf.ed.ac.uk/wadler/papers/monadscomb/monadscomb.ps.gz", +} + +@InProceedings{kiselyov-shan-07, + author = "Oleg Kiselyov and Chung{-}chieh Shan", + title = "A Substructural Type System for Delimited + Continuations", + booktitle = tlca, + pages = "223--239", + year = "2007", + series = lncs, + volume = "4583", + publisher = springer, + URL = "http://homes.soic.indiana.edu/ccshan/binding/context.pdf", +} + +@Article{klein-seL4-2010, + author = "Gerwin Klein and June Andronick and Kevin Elphinstone + and Gernot Heiser and David Cock and Philip Derrin and + Dhammika Elkaduwe and Kai Engelhardt and Rafal Kolanski + and Michael Norrish and Thomas Sewell and Harvey Tuch + and Simon Winwood", + title = "{seL4}: formal verification of an operating-system + kernel", + journal = cacm, + volume = "53", + number = "6", + year = "2010", + pages = "107--115", + URL = "http://ertos.nicta.com.au/publications/papers/Klein_EHACDEEKNSTW_10.pdf", +} + +@Article{klint-laemmel-verhoef-05, + author = "Paul Klint and Ralf L{\"a}mmel and Chris Verhoef", + title = "{Toward an engineering discipline for grammarware}", + journal = tosem, + volume = "14", + number = "3", + year = "2005", + pages = "331--380", + URL = "http://www.few.vu.nl/~x/gw/gw.pdf", +} + +@InProceedings{kloos-majumdar-vafeiadis-15, + author = "Johannes Kloos and Rupak Majumdar and Viktor + Vafeiadis", + title = "Asynchronous Liquid Separation Types", + booktitle = ecoop, + pages = "396--420", + year = "2015", + URL = "https://www.mpi-sws.org/~viktor/papers/ecoop2015-alstypes.pdf", +} + +@Article{kmp-77, + author = "James H. Morris and Donald E. Knuth and Vaughan R. + Pratt", + title = "Fast Pattern Matching in Strings", + journal = siamjc, + year = "1977", + volume = "6", + number = "2", + pages = "323--350", + URL = "http://locus.siam.org/fulltext/SICOMP/volume-06/0206024.pdf", +} + +@Article{knight-89, + author = "Kevin Knight", + title = "Unification: a multidisciplinary survey", + journal = surveys, + year = "1989", + volume = "21", + number = "1", + pages = "93--124", + URL = "http://doi.acm.org/10.1145/62029.62030", +} + +@Article{knuth-77, + author = "Donald E. Knuth", + title = "A Generalization of {Dijkstra}'s Algorithm", + journal = ipl, + year = "1977", + volume = "6", + number = "1", + pages = "1--5", +} + +@Article{knuth-lr-65, + author = "Donald E. Knuth", + title = "On the translation of languages from left to right", + journal = "Information \& Control", + year = "1965", + volume = "8", + number = "6", + pages = "607--639", + URL = "http://www.sciencedirect.com/science/article/pii/S0019995865904262", +} + +@InProceedings{kobayashi-implicit-00, + author = "Naoki Kobayashi and Shin Saito and Eijiro Sumii", + title = "An Implicitly-Typed Deadlock-Free Process Calculus", + booktitle = concur, + publisher = springer, + series = lncs, + volume = "1877", + year = "2000", + pages = "489--503", + URL = "http://www.yl.is.s.u-tokyo.ac.jp/members/koba/papers/deadlock-inference-concur.ps.gz", +} + +@Article{kobayashi-linearity-99, + author = "Naoki Kobayashi and Benjamin C. Pierce and David N. + Turner", + title = "Linearity and the {Pi-Calculus}", + journal = toplas, + volume = "21", + number = "5", + pages = "914--947", + year = "1999", + URL = "http://doi.acm.org/10.1145/330249.330251", +} + +@Article{kobayashi-partial-98, + author = "Naoki Kobayashi", + title = "A Partially Deadlock-Free Typed Process Calculus", + journal = toplas, + volume = "20", + number = "2", + pages = "436--482", + year = "1998", + URL = "http://doi.acm.org/10.1145/276393.278524", +} + +@InProceedings{kobayashi-sumii-98, + author = "Eijiro Sumii and Naoki Kobayashi", + title = "A Generalized Deadlock-Free Process Calculus", + booktitle = hlcl, + year = "1998", + volume = "16", + series = entcs, + publisher = elsevier, + pages = "55--77", + URL = "http://www1.elsevier.com/gej-ng/31/29/23/40/26/39/tcs16.3.006.ps", +} + +@InProceedings{kobayashi-useless-00, + author = "Naoki Kobayashi", + title = "Type-based useless variable elimination", + pages = "84--93", + booktitle = pepm, + year = "2000", + URL = "http://www.yl.is.s.u-tokyo.ac.jp/members/koba/papers/PEPM00.ps.gz", +} + +@Article{koda-ruskey-93, + author = "Yasunori Koda and Frank Ruskey", + title = "A {Gray} Code for the Ideals of a Forest Poset", + journal = "Journal of Algorithms", + volume = "15", + number = "2", + year = "1993", + pages = "324--340", + URL = "http://www.cs.uvic.ca/~ruskey/Publications/ForestIdeals.ps", +} + +@InProceedings{kohlbecker-hygienic-86, + author = "Eugene Kohlbecker and Daniel P. Friedman and Matthias + Felleisen and Bruce Duba", + title = "Hygienic macro expansion", + booktitle = lfp, + year = "1986", + pages = "151--161", + URL = "http://doi.acm.org/10.1145/319838.319859", +} + +@InProceedings{kohlbecker-wand-87, + author = "Eugene E. Kohlbecker and Mitchell Wand", + title = "Macro-by-example: Deriving syntactic transformations + from their specifications", + booktitle = popl, + year = "1987", + pages = "77--84", + URL = "http://doi.acm.org/10.1145/41625.41632", +} + +@InProceedings{konat-13, + author = "Gabri{\"e}l Konat and Lennart Kats and Guido Wachsmuth + and Eelco Visser", + title = "Declarative Name Binding and Scope Rules", + booktitle = sle, + year = "2013", + publisher = springer, + volume = "7745", + series = lncs, + pages = "311--331", + URL = "http://swerl.tudelft.nl/twiki/pub/Main/TechnicalReports/TUD-SERG-2012-015.pdf", +} + +@InProceedings{koprowski-binsztok-10, + author = "Adam Koprowski and Henri Binsztok", + title = "{TRX}: {A} Formally Verified Parser Interpreter", + booktitle = esop, + year = "2010", + pages = "345--365", + publisher = "Springer", + series = lncs, + volume = "6012", + URL = "http://adam-koprowski.net/papers/trx-ESOP-10.pdf", +} + +@Article{koprowski-binsztok-11, + author = "Adam Koprowski and Henri Binsztok", + title = "{TRX}: {A} Formally Verified Parser Interpreter", + journal = lmcs, + year = "2011", + volume = "7", + number = "2", + URL = "http://arxiv.org/pdf/1105.2576", +} + +@InProceedings{koved-al-02, + author = "Larry Koved and Marco Pistoia and Aaron Kershenbaum", + title = "Access rights analysis for {Java}", + pages = "359--372", + booktitle = oopsla, + year = "2002", + URL = "http://www.research.ibm.com/javasec/OOPSLA2002preprint.pdf", +} + +@Book{kozen-91, + author = "Dexter C. Kozen", + title = "The design and analysis of algorithms", + year = "1992", + series = "Texts and Monographs in Computer Science", + publisher = springer, + URL = "http://www.cs.cornell.edu/~kozen/papers/daa.pdf", +} + +@Article{kozen-palsberg-schwartzbach-95, + author = "Dexter Kozen and Jens Palsberg and Michael I. + Schwartzbach", + title = "Efficient Recursive Subtyping", + journal = mscs, + volume = "5", + number = "1", + pages = "113--125", + year = "1995", + URL = "http://www.cs.ucla.edu/~palsberg/paper/mscs95-kps.pdf", +} + +@InProceedings{krebbers-17, + author = "Robert Krebbers and Amin Timany and Lars Birkedal", + title = "Interactive proofs in higher-order concurrent + separation logic", + booktitle = popl, + year = "2017", + URL = "http://cs.au.dk/~birke/papers/ipm-conf.pdf", +} + +@InProceedings{krishnamurthi-99, + author = "Shriram Krishnamurthi and Matthias Felleisen and Bruce + F. Duba", + title = "From Macros to Reusable Generative Programming", + booktitle = gcse, + pages = "105--120", + year = "1999", + volume = "1799", + series = lncs, + publisher = springer, + URL = "http://www.cs.brown.edu/~sk/Publications/Papers/Published/kfd-macro-to-gen-prog/paper.ps", +} + +@PhdThesis{krishnaswami-12, + author = "Neelakantan R. Krishnaswami", + title = "Verifying Higher-Order Imperative Programs with + Higher-Order Separation Logic", + school = "School of Computer Science, Carnegie Mellon + University", + year = "2012", + URL = "http://www.cs.cmu.edu/~neelk/thesis.pdf", +} + +@InProceedings{krishnaswami-design-patterns-09, + author = "Neelakantan R. Krishnaswami and Jonathan Aldrich and + Lars {Bir\-ke\-dal} and Kasper Svendsen and Alexandre + Buisse", + title = "Design Patterns in Separation Logic", + booktitle = tldi, + pages = "105--116", + year = "2009", + URL = "http://www.cs.cmu.edu/~neelk/design-patterns-tldi09.pdf", +} + +@InProceedings{krishnaswami-sharing-12, + author = "Neelakantan R. Krishnaswami and Aaron Turon and Derek + Dreyer and Deepak Garg", + title = "Superficially substructural types", + booktitle = icfp, + year = "2012", + pages = "41--54", + URL = "http://www.mpi-sws.org/~neelk/icfp12-superficial-krishnaswami-turon-dreyer-garg.pdf", +} + +@Book{kroening-strichman-08, + author = "Daniel Kroening and Ofer Strichman", + title = "Decision procedures -- An algorithmic point of view", + publisher = springer, + year = "2008", + URL = "http://www.decision-procedures.org/", +} + +@InProceedings{kuan-07, + author = "George Kuan and David MacQueen", + title = "Efficient type inference using ranked type variables", + booktitle = ml, + year = "2007", + pages = "3--14", + URL = "http://people.cs.uchicago.edu/~gkuan/pubs/ml07-km.pdf", +} + +@InProceedings{kuncak-rinard-03, + author = "Viktor Kuncak and Martin Rinard", + title = "Structural Subtyping of Non-Recursive Types is + Decidable", + booktitle = lics, + year = "2003", + URL = "http://www.cag.lcs.mit.edu/~rinard/paper/lics03.pdf", +} + +@TechReport{kuncak-rinard-tr-03, + author = "Viktor Kuncak and Martin Rinard", + title = "On the Theory of Structural Subtyping", + institution = "MIT Laboratory for Computer Science", + year = "2003", + number = "879", + URL = "http://www.mit.edu/people/vkuncak/papers/TheoryStructuralSubtyping.ps", +} + +@InProceedings{laemmel-00, + author = "Ralf Lämmel and Joost Visser and Jan Kort", + title = "Dealing with Large Bananas", + pages = "46--59", + booktitle = wgp, + year = "2000", + URL = "http://homepages.cwi.nl/~ralf/wgp00.ps", +} + +@Unpublished{laemmel-scrap-05, + author = "Ralf Lämmel and Simon {Peyton Jones}", + title = "Scrap your boilerplate with class: extensible generic + functions", + note = "Submitted", + year = "2005", + URL = "http://research.microsoft.com/Users/simonpj/papers/hmap/gmap3.ps", +} + +@InProceedings{lai-user-99, + author = "Charlie Lai and Li Gong and Larry Koved and Anthony J. + Nadalin and Roland Schemers", + title = "User Authentication and Authorization in the {Java} + Platform", + booktitle = acsac, + pages = "285--290", + year = "1999", + URL = "http://www.acsac.org/1999/papers/thu-b-1500-lai.pdf", +} + +@InProceedings{lammich-13, + author = "Peter Lammich", + title = "Automatic Data Refinement", + booktitle = itp, + pages = "84--99", + year = "2013", + volume = "7998", + series = lncs, + publisher = springer, + URL = "http://www21.in.tum.de/~lammich/pub/autoref.pdf", +} + +@InProceedings{lammich-14, + author = "Peter Lammich", + title = "Verified Efficient Implementation of {Gabow}'s + Strongly Connected Component Algorithm", + booktitle = itp, + year = "2014", + pages = "325--340", + publisher = springer, + series = lncs, + volume = "8558", + URL = "http://www21.in.tum.de/~lammich/pub/gabow_scc.pdf", +} + +@InProceedings{lammich-15, + author = "Peter Lammich", + title = "Refinement to {Imperative/HOL}", + booktitle = itp, + pages = "253--269", + year = "2015", + series = lncs, + volume = "9236", + publisher = springer, + URL = "https://www21.in.tum.de/~lammich/pub/itp15_sepref.pdf", +} + +@InProceedings{lammich-16, + author = "Peter Lammich", + title = "Refinement Based Verification of Imperative Data + Structures", + booktitle = cpp, + year = "2016", + pages = "27--36", + URL = "https://www21.in.tum.de/~lammich/pub/cpp2016_impds.pdf", +} + +@InProceedings{lammich-lochbihler-10, + author = "Peter Lammich and Andreas Lochbihler", + title = "The {Isabelle} Collections Framework", + booktitle = itp, + pages = "339--354", + year = "2010", + series = lncs, + volume = "6172", + publisher = springer, + URL = "http://cs.uni-muenster.de/sev/publications/itp10.pdf", +} + +@Article{lammich-meis-12, + author = "Peter Lammich and Rene Meis", + title = "A Separation Logic Framework for {Imperative HOL}", + journal = "Archive of Formal Proofs", + year = "2012", + URL = "http://afp.sourceforge.net/entries/Separation_Logic_Imperative_HOL.shtml", +} + +@Article{lampson-73, + author = "Butler W. Lampson", + title = "A Note on the Confinement Problem", + journal = cacm, + volume = "16", + number = "10", + pages = "613--615", + year = "1973", + URL = "http://research.microsoft.com/lampson/11-Confinement/WebPage.html", +} + +@Article{landin-64, + author = "Peter J. Landin", + title = "The Mechanical Evaluation of Expressions", + journal = cj, + volume = "6", + number = "4", + year = "1964", + pages = "308--320", +} + +@Article{landin-65, + author = "Peter J. Landin", + title = "Correspondence between {ALGOL} 60 and {Church's} + Lambda-notation: part {I}", + journal = cacm, + volume = "8", + number = "2", + year = "1965", + pages = "89--101", + URL = "http://doi.acm.org/10.1145/363744.363749", +} + +@PhdThesis{larus-89, + author = "James Richard Larus", + title = "Restructuring Symbolic Programs for Concurrent + Execution on Multiprocessors", + school = "EECS Department, University of California, Berkeley", + year = "1989", + note = "Technical Report UCB/CSD-89-502", + URL = "http://www.eecs.berkeley.edu/Pubs/TechRpts/1989/CSD-89-502.pdf", +} + +@InProceedings{lassen-06, + author = "Soren B. Lassen", + title = "Head Normal Form Bisimulation for Pairs and the + $\lambda\mu$-Calculus", + booktitle = lics, + year = "2006", + pages = "297--306", + URL = "http://www.blassen.dk/soren/papers/2006lics.pdf", +} + +@InProceedings{lassen-99, + author = "Soren B. Lassen", + title = "Bisimulation in untyped lambda calculus: {Böhm} trees + and bisimulation up to context", + booktitle = mfps, + pages = "346--374", + year = "1999", + volume = "20", + series = entcs, + publisher = elsevier, + URL = "http://www.blassen.dk/soren/papers/1999mfps15.ps", +} + +@InCollection{lassez-al-88, + author = "Jean-Louis Lassez and Michael J. Maher and Kim G. + Marriott", + editor = "Jack Minker", + booktitle = "Foundations of Deductive Databases and Logic + Programming", + title = "Unification Revisited", + chapter = "15", + publisher = "Morgan Kaufmann", + year = "1988", + pages = "587--625", +} + +@Article{lassez-nguyen-sonenberg-82, + author = "Jean-Louis Lassez and V. L. Nguyen and Liz Sonenberg", + title = "Fixed point theorems and semantics: a folk tale", + journal = ipl, + year = "1982", + volume = "14", + number = "3", + pages = "112--116", + URL = "http://dx.doi.org/10.1016/0020-0190(82)90065-5", +} + +@InProceedings{laufer-odersky-92, + author = "Martin Odersky and Konstantin Läufer", + title = "An Extension of {ML} with First-Class Abstract Types", + year = "1992", + booktitle = mlapp, + pages = "78--91", + URL = "http://www.cs.luc.edu/laufer/papers/ml92.pdf", +} + +@Article{laufer-odersky-94, + author = "Konstantin L{\"a}ufer and Martin Odersky", + title = "Polymorphic Type Inference and Abstract Data Types", + journal = toplas, + year = "1994", + pages = "1411--1430", + volume = "16", + number = "5", + URL = "http://www.cs.luc.edu/laufer/papers/toplas94.pdf", +} + +@Article{launchbury-peyton-jones-95, + author = "John Launchbury and Simon {Peyton Jones}", + title = "State in {Haskell}", + journal = "{LISP} and Symbolic Computation", + publisher = springer, + pages = "293--341", + year = "1995", + volume = "8", + number = "4", + URL = "http://dx.doi.org/10.1007/BF01018827", +} + +@InProceedings{laviron-chang-rival-10, + author = "Vincent Laviron and Bor-Yuh Evan Chang and Xavier + Rival", + title = "Separating Shape Graphs", + booktitle = esop, + year = "2010", + pages = "387--406", + publisher = springer, + series = lncs, + volume = "6012", + URL = "http://xisa.cs.colorado.edu/papers/esop10-sepshapegraph.pdf", +} + +@TechReport{le-charlier-van-hentenryck-92, + author = "Baudouin {Le Charlier} and Pascal {Van Hentenryck}", + title = "A Universal Top-Down Fixpoint Algorithm", + institution = "Brown University", + year = "1992", + type = "Technical Report", + number = "CS-92-25", + URL = "ftp://ftp.cs.brown.edu/pub/techreports/92/cs92-25.ps.gz", +} + +@Article{le-metayer-88, + author = "Daniel {Le Métayer}", + title = "{ACE:} An Automatic Complexity Evaluator", + journal = toplas, + volume = "10", + number = "2", + pages = "248--266", + year = "1988", + URL = "http://doi.acm.org/10.1145/42190.42347", +} + +@Article{league-02, + author = "Christopher League and Zhong Shao and Valery + Trifonov", + title = "Type-Preserving Compilation of {Featherweight} + {Java}", + journal = toplas, + year = "2002", + volume = "24", + number = "2", + pages = "112--152", + URL = "http://flint.cs.yale.edu/flint/publications/fj-toplas.html", +} + +@InProceedings{league-03, + author = "Christopher League and Zhong Shao and Valery + Trifonov", + title = "Precision in Practice: a Type-Preserving {Java} + Compiler", + booktitle = cc, + pages = "106--120", + year = "2003", + volume = "2622", + series = lncs, + publisher = springer, + URL = "http://flint.cs.yale.edu/flint/publications/piptr.html", +} + +@InProceedings{league-99, + author = "Christopher League and Zhong Shao and Valery + Trifonov", + title = "Representing {Java} Classes in a Typed Intermediate + Language", + booktitle = icfp, + pages = "183--196", + year = "1999", + URL = "http://flint.cs.yale.edu/flint/publications/javaflint2.html", +} + +@InProceedings{leavens-baker-99, + author = "Gary T. Leavens and Albert L. Baker", + title = "Enhancing the Pre- and Postcondition Technique for + More Expressive Specifications", + booktitle = fm, + volume = "1709", + series = lncs, + year = "1999", + pages = "1087--1106", + publisher = springer, + URL = "http://dx.doi.org/10.1007/3-540-48118-4_8", +} + +@InProceedings{lebotlan-remy-03, + author = "Didier {Le Botlan} and Didier R{\'e}my", + title = "{MLF}: Raising {ML} to the power of System ${F}$", + booktitle = icfp, + pages = "27--38", + year = "2003", + URL = "http://gallium.inria.fr/~remy/work/mlf/icfp.pdf", +} + +@InProceedings{lebresne-08, + author = "Sylvain Lebresne", + title = "A System ${F}$ with Call-by-Name Exceptions", + booktitle = icalp, + year = "2008", + pages = "323--335", + publisher = springer, + series = lncs, + volume = "5126", + URL = "http://www.pps.jussieu.fr/~lebresne/papers/SystemFWithExceptions.pdf", +} + +@Article{lee-yi-98, + author = "Oukseh Lee and Kwangkeun Yi", + title = "Proofs about a folklore let-polymorphic type inference + algorithm", + journal = toplas, + volume = "20", + number = "4", + year = "1998", + pages = "707--723", + URL = "http://doi.acm.org/10.1145/291891.291892", +} + +@InProceedings{lefessant-maranget-01, + author = "Fabrice {Le Fessant} and Luc Maranget", + title = "Optimizing Pattern Matching", + booktitle = icfp, + year = "2001", + URL = "http://gallium.inria.fr/~maranget/papers/opt-pat.ps.gz", +} + +@TechReport{leijen-algebraic-effects-16, + author = "Daan Leijen", + title = "Algebraic Effects for Functional Programming", + institution = "Microsoft Research", + number = "MSR-TR-2016-29", + year = "2016", + URL = "https://www.microsoft.com/en-us/research/publication/algebraic-effects-for-functional-programming/", +} + +@Article{leino-05, + author = "K. Rustan M. Leino", + title = "Efficient Weakest Preconditions", + journal = ipl, + year = "2005", + volume = "93", + number = "6", + pages = "281--288", + URL = "http://research.microsoft.com/pubs/70052/tr-2004-34.pdf", +} + +@InProceedings{leino-mueller-chalice-09, + author = "K. Rustan M. Leino and Peter M{\"u}ller", + title = "A Basis for Verifying Multi-threaded Programs", + booktitle = esop, + year = "2009", + pages = "378--393", + series = lncs, + volume = "5502", + publisher = springer, + URL = "http://research.microsoft.com/en-us/um/people/leino/papers/krml191.pdf", +} + +@InProceedings{leino-mueller-smans-09, + author = "K. Rustan M. Leino and Peter Müller and Jan Smans", + title = "Verification of Concurrent Programs with {Chalice}", + booktitle = fosad, + year = "2009", + pages = "195--222", + publisher = springer, + series = lncs, + volume = "5705", + URL = "http://research.microsoft.com/en-us/um/people/leino/papers/krml197.pdf", +} + +@InProceedings{leino-mueller-smans-10, + author = "K. Rustan M. Leino and Peter Müller and Jan Smans", + title = "Deadlock-Free Channels and Locks", + booktitle = esop, + year = "2010", + pages = "407--426", + publisher = springer, + series = lncs, + volume = "6012", + URL = "http://research.microsoft.com/en-us/um/people/leino/papers/krml200ext.pdf", +} + +@Article{leino-nelson-02, + author = "K. Rustan M. Leino and Greg Nelson", + title = "Data abstraction and information hiding", + journal = toplas, + volume = "24", + number = "5", + year = "2002", + pages = "491--553", + URL = "http://research.microsoft.com/~leino/papers/krml71.pdf", +} + +@InProceedings{leino-schulte-07, + author = "K. Rustan M. Leino and Wolfram Schulte", + title = "Using History Invariants to Verify Observers", + booktitle = esop, + year = "2007", + pages = "80--94", + publisher = springer, + series = lncs, + volume = "4421", + URL = "http://research.microsoft.com/en-us/um/people/leino/papers/krml166.pdf", +} + +@PhdThesis{leroy-92, + author = "Xavier Leroy", + title = "Typage polymorphe d'un langage algorithmique", + school = "Université Paris 7", + year = "1992", + pages = "196", + URL = "http://gallium.inria.fr/~xleroy/publi/these-doctorat.ps.gz", +} + +@InProceedings{leroy-compcert-06, + author = "Xavier Leroy", + title = "Formal certification of a compiler back-end or: + programming a compiler with a proof assistant", + booktitle = popl, + year = "2006", + pages = "42--54", + URL = "http://gallium.inria.fr/~xleroy/publi/compiler-certif.pdf", +} + +@TechReport{leroy-phd-92, + author = "Xavier Leroy", + title = "Polymorphic typing of an algorithmic language", + institution = "INRIA", + year = "1992", + type = "Research Report", + number = "1778", + URL = "http://gallium.inria.fr/~xleroy/publi/phd-thesis.ps.gz", +} + +@MastersThesis{lescuyer-06, + author = "Stéphane Lescuyer", + title = "Codage de la logique du premier ordre polymorphe + multi-sortée dans la logique sans sortes", + school = "Master Parisien de Recherche en Informatique", + year = "2006", + URL = "http://www.seas.upenn.edu/~lescuyer/pdf/RapportDEA.pdf", +} + +@Article{lescuyer-11, + author = "St{\'{e}}phane Lescuyer", + title = "First-Class Containers in {Coq}", + journal = "Studia Informatica Universalis", + volume = "9", + number = "1", + pages = "87--127", + year = "2011", + URL = "http://studia.complexica.net/Art/RI090103.pdf", +} + +@PhdThesis{letouzey-04, + author = "Pierre Letouzey", + title = "Programmation fonctionnelle certifiée -- l'extraction + de programmes dans l'assistant {Coq}", + school = "Université Paris 11", + year = "2004", + URL = "http://www.lri.fr/~letouzey/download/these_letouzey.ps.gz", +} + +@InProceedings{levy-02, + author = "Paul Blain Levy", + title = "Possible World Semantics for General Storage in + Call-By-Value", + booktitle = csl, + series = lncs, + volume = "2471", + publisher = springer, + year = "2002", + URL = "http://www.cs.bham.ac.uk/~pbl/papers/storagecbv.ps", +} + +@InProceedings{lewis-al-00, + author = "Jeffrey Lewis and Mark Shields and Erik Meijer and + John Launchbury", + title = "Implicit Parameters: Dynamic Scoping with Static + Types", + booktitle = popl, + year = "2000", + pages = "108--118", + URL = "http://www.cse.ogi.edu/~mbs/pub/implicit_parameters/implicit.ps", +} + +@InProceedings{ley-wild-nanevski-subjective-13, + author = "Ruy Ley-Wild and Aleksandar Nanevski", + title = "Subjective auxiliary state for coarse-grained + concurrency", + booktitle = popl, + year = "2013", + pages = "561--574", + URL = "http://software.imdea.org/~aleks/papers/concur/scsl4.pdf", +} + +@InProceedings{lgph-08, + author = "Johan Jeuring and Sean Leather and Jos{\'{e}} Pedro + Magalh{\~{a}}es and Alexey Rodriguez Yakushev", + title = "Libraries for Generic Programming in {Haskell}", + booktitle = afp, + pages = "165--229", + year = "2008", + series = lncs, + volume = "5832", + publisher = springer, + URL = "http://dreixel.net/research/pdf/lgph.pdf", +} + +@InProceedings{licata-harper-09, + author = "Daniel R. Licata and Robert Harper", + title = "A universe of binding and computation", + booktitle = icfp, + year = "2009", + pages = "123--134", + URL = "http://www.cs.cmu.edu/~drl/pubs/lh09unibind/lh09unibind.pdf", +} + +@InProceedings{licata-zeilberger-harper-08, + author = "Daniel R. Licata and Noam Zeilberger and Robert + Harper", + title = "Focusing on Binding and Computation", + booktitle = lics, + year = "2008", + pages = "241--252", + URL = "http://www.cs.cmu.edu/~rwh/papers/focusing/paper.pdf", +} + +@TechReport{licata-zeilberger-harper-08-tr, + author = "Daniel R. Licata and Noam Zeilberger and Robert + Harper", + title = "Focusing on Binding and Computation", + institution = "Carnegie Mellon University", + year = "2008", + number = "CMU-CS-08-101", + URL = "http://www.cs.cmu.edu/~noam/research/lzh08focbind-tr.pdf", +} + +@InProceedings{lindley-mcbride-mclaughlin-17, + author = "Sam Lindley and Conor McBride and Craig McLaughlin", + title = "Do Be Do Be Do", + booktitle = popl, + year = "2017", + URL = "http://homepages.inf.ed.ac.uk/slindley/papers/frankly-draft-july2016.pdf", +} + +@Book{liskov-guttag-01, + author = "Barbara Liskov and John V. Guttag", + title = "Program Development in {Java} -- Abstraction, + Specification, and Object-Oriented Design", + year = "2001", + publisher = aw, + URL = "http://dl.acm.org/citation.cfm?id=556707", +} + +@Article{liskov-wing-94, + author = "Barbara Liskov and Jeannette M. Wing", + title = "A Behavioral Notion of Subtyping", + journal = toplas, + volume = "16", + number = "6", + year = "1994", + pages = "1811--1841", + URL = "http://www.cs.cmu.edu/~wing/publications/LiskovWing94.pdf", +} + +@InProceedings{liu-smolka-98, + author = "Xinxin Liu and Scott A. Smolka", + title = "Simple Linear-Time Algorithms for Minimal Fixed + Points", + booktitle = icalp, + year = "1998", + pages = "53--66", + series = lncs, + volume = "1443", + publisher = springer, + URL = "http://dx.doi.org/10.1007/BFb0055040", +} + +@TechReport{lngen-10, + author = "Brian Aydemir and Stephanie Weirich", + title = "{LNgen}: Tool Support for Locally Nameless + Representations", + institution = "University of Pennsylvania Department of Computer and + Information Science", + year = "2010", + type = "Technical Report", + number = "MS-CIS-10-24", + URL = "http://repository.upenn.edu/cis_reports/933/", +} + +@InProceedings{lochbihler-13, + author = "Andreas Lochbihler", + title = "Light-weight containers for {Isabelle}: efficient, + extensible, nestable", + booktitle = itp, + pages = "116--132", + year = "2013", + series = lncs, + volume = "7998", + publisher = springer, + URL = "https://pp.ipd.kit.edu/uploads/publikationen/lochbihler13itp.pdf", +} + +@InProceedings{longley-99, + author = "John Longley", + title = "When is a Functional Program Not a Functional + Program?", + booktitle = icfp, + year = "1999", + pages = "1--7", + URL = "http://doi.acm.org/10.1145/317636.317775", +} + +@InProceedings{longley-pollack-04, + author = "John Longley and Randy Pollack", + title = "Reasoning About {CBV} Functional Programs in + {Isabelle/HOL}", + booktitle = tphol, + year = "2004", + pages = "201--216", + URL = "http://homepages.inf.ed.ac.uk/rpollack/export/LongleyPollack04.pdf", + publisher = springer, + series = lncs, + volume = "3223", +} + +@InProceedings{lucassen-gifford-88, + author = "John M. Lucassen and David K. Gifford", + title = "Polymorphic effect systems", + booktitle = popl, + year = "1988", + pages = "47--57", + URL = "http://pag.lcs.mit.edu/reading-group/lucassen88effects.pdf", +} + +@InProceedings{mackenzie-wolverson-03, + author = "Kenneth MacKenzie and Nicholas Wolverson", + title = "{Camelot} and {Grail}: resource-aware functional + programming for the {JVM}", + booktitle = tfp, + pages = "29--46", + year = "2003", + volume = "4", + URL = "http://groups.inf.ed.ac.uk/mrg/publications/mrg/camelot.ps", +} + +@Article{macqueen-plotkin-sethi-86, + author = "David B. MacQueen and Gordon D. Plotkin and Ravi + Sethi", + title = "An Ideal Model for Recursive Polymorphic Types", + journal = "Information and Control", + volume = "71", + number = "1--2", + year = "1986", + pages = "95--130", +} + +@PhdThesis{mader-97, + school = "Technische Universität München", + author = "Angelika Mader", + title = "Verification of Modal Properties Using {Boolean} + Equation Systems", + year = "1997", + URL = "http://eprints.eemcs.utwente.nl/1078/02/diss.pdf", +} + +@InProceedings{madhavan-kulal-kuncak-17, + author = "Ravichandhran Madhavan and Sumith Kulal and Viktor + Kuncak", + title = "Contract-based resource verification for higher-order + functions with memoization", + booktitle = popl, + pages = "330--343", + year = "2017", + URL = "http://lara.epfl.ch/~kandhada/orb-popl17.pdf", +} + +@InProceedings{maeda-11, + author = "Toshiyuki Maeda and Haruki Sato and Akinori Yonezawa", + title = "Extended Alias Type System using Separating + Implication", + booktitle = tldi, + year = "2011", + pages = "29--42", + URL = "http://dx.doi.org/10.1145/1929553.1929559", +} + +@InProceedings{maher-88, + author = "Michael J. Maher", + title = "Complete Axiomatizations of the Algebras of Finite, + Rational and Infinite Trees", + booktitle = lics, + pages = "348--357", + year = "1988", +} + +@InProceedings{mairson-90, + author = "Harry G. Mairson", + title = "Deciding {ML} typability is complete for deterministic + exponential time", + booktitle = popl, + year = "1990", + pages = "382--401", + URL = "http://doi.acm.org/10.1145/96709.96748", +} + +@InCollection{mairson-kanellakis-mitchell-91, + author = "Harry G. Mairson and Paris C. Kanellakis and John C. + Mitchell", + title = "Unification and {ML} type reconstruction", + booktitle = "Computational Logic: Essays in Honor of Alan + Robinson", + publisher = mitp, + year = "1991", + editor = "J.-L. Lassez and G. Plotkin", + pages = "444--478", +} + +@Article{marche-krakatoa-04, + author = "Claude Marché and Christine Paulin-Mohring and Xavier + Urbain", + title = "The {Krakatoa} tool for certification of + {Java}/{JavaCard} programs annotated in {JML}", + journal = jlap, + year = "2004", + volume = "58", + number = "1--2", + pages = "89--106", + URL = "http://www3.ensiie.fr/~urbain/textes/jlap.ps.gz", +} + +@Article{maric-09, + author = "Filip Mari\'c", + title = "Formalization and Implementation of Modern {SAT} + Solvers", + journal = jar, + year = "2009", + volume = "43", + pages = "81--119", + URL = "http://poincare.matf.bg.ac.rs/~filip//phd/sat-tutorial.pdf", +} + +@Unpublished{maric-10, + author = "Filip Mari\'c", + title = "Formal Verification of a Modern {SAT} Solver", + note = "Unpublished", + year = "2010", + URL = "http://poincare.matf.bg.ac.rs/~filip//phd/sat-verification-shallow.pdf", +} + +@InProceedings{marlow-wadler-erlang-97, + title = "A Practical Subtyping System for {Erlang}", + author = "Simon Marlow and Philip Wadler", + pages = "136--149", + booktitle = icfp, + year = "1997", +} + +@TechReport{marriott-odersky-boolean-94, + author = "Kim Marriott and Martin Odersky", + title = "Negative {Boolean} Constraints", + institution = "Monash University", + year = "1994", + number = "94/203", + URL = "http://lampwww.epfl.ch/~odersky/papers/negative-tr.ps.gz", +} + +@Article{martelli-montanari-82, + author = "Alberto Martelli and Ugo Montanari", + title = "An Efficient Unification Algorithm", + journal = toplas, + volume = "4", + number = "2", + pages = "258--282", + year = "1982", + URL = "http://doi.acm.org/10.1145/357162.357169", +} + +@Article{mateescu-sighireanu-03, + author = "Radu Mateescu and Mihaela Sighireanu", + title = "Efficient on-the-fly model-checking for regular + alternation-free mu-calculus", + journal = scp, + volume = "46", + number = "3", + year = "2003", + pages = "255--281", + URL = "ftp://ftp.inrialpes.fr/pub/vasy/publications/cadp/Mateescu-Sighireanu-03.pdf", +} + +@TechReport{mauny-pottier-93, + author = "Michel Mauny and François Pottier", + title = "An implementation of {Caml Light} with existential + types", + number = "2183", + institution = "INRIA", + year = "1993", + URL = "http://gallium.inria.fr/~fpottier/publis/rapport-maitrise.ps.gz", +} + +@InProceedings{mazurak-10, + author = "Karl Mazurak and Jianzhou Zhao and Steve Zdancewic", + title = "Lightweight linear types in system ${F}^\circ$", + booktitle = tldi, + year = "2010", + pages = "77--88", + URL = "http://www.cis.upenn.edu/~stevez/papers/MZZ10.pdf", +} + +@InProceedings{mcadam-98, + title = "{On the Unification of Substitutions in Type + Inference}", + author = "Bruce J. McAdam", + publisher = springer, + booktitle = ifl, + series = lncs, + volume = "1595", + year = "1998", + pages = "139--154", + URL = "http://www.scms.rgu.ac.uk/staff/bjm/doc/IFL_98.ps", +} + +@Article{mcallester-02, + author = "David McAllester", + title = "On the Complexity Analysis of Static Analyses", + year = "2002", + pages = "512--537", + journal = jacm, + volume = "49", + number = "4", + URL = "http://doi.acm.org/10.1145/581771.581774", +} + +@InProceedings{mcallester-03, + author = "David McAllester", + title = "A Logical Algorithm for {ML} Type Inference", + booktitle = rta, + year = "2003", + pages = "436--451", + series = lncs, + publisher = springer, + volume = "2706", + URL = "http://ttic.uchicago.edu/~dmcallester/rta03.ps", +} + +@Unpublished{mcbride-derivative, + author = "Conor McBride", + title = "The Derivative of a Regular Type is its Type of + One-Hole Contexts", + note = "Unpublished", + URL = "http://strictlypositive.org/diff.pdf", +} + +@InProceedings{mcbride-mckinna-04, + author = "Conor McBride and James McKinna", + title = "{I} am not a number: {I} am a free variable", + booktitle = hw, + year = "2004", + URL = "http://www.cs.ru.nl/~james/RESEARCH/haskell2004.pdf", +} + +@Article{mcbride-paterson-08, + author = "Conor McBride and Ross Paterson", + title = "Applicative Programming with Effects", + journal = jfp, + year = "2008", + volume = "18", + number = "1", + pages = "1--13", + URL = "http://www.soi.city.ac.uk/~ross/papers/Applicative.pdf", +} + +@Article{mcbride-unif-03, + author = "Conor McBride", + title = "First-order unification by structural recursion", + journal = jfp, + volume = "13", + number = "6", + year = "2003", + pages = "1061--1075", + URL = "http://strictlypositive.org/unify.ps.gz", +} + +@InProceedings{mccarthy-16, + author = "Jay A. McCarthy and Burke Fetscher and Max S. New and + Daniel Feltey and Robert Bruce Findler", + title = "A {Coq} Library for Internal Verification of + Running-Times", + booktitle = flops, + pages = "144--162", + year = "2016", + series = lncs, + volume = "9613", + publisher = springer, + URL = "https://www.eecs.northwestern.edu/~robby/pubs/papers/flops2016-mfnff.pdf", +} + +@InProceedings{mckinna-pollack-93, + author = "James McKinna and Randy Pollack", + title = "Pure Type Systems Formalized", + booktitle = tlca, + year = "1993", + pages = "289--305", + publisher = springer, + series = lncs, + number = "664", + URL = "http://www.dcs.ed.ac.uk/home/rap/export/formalPTS.ps.gz", +} + +@Article{mckinna-pollack-99, + author = "James McKinna and Randy Pollack", + title = "Some Lambda Calculus and Type Theory Formalized", + journal = jar, + year = "1999", + volume = "23", + number = "3--4", + pages = "373--409", +} + +@InCollection{mclean-94, + author = "John {McLean}", + title = "Security Models", + year = "1994", + booktitle = "Encyclopedia of Software Engineering", + editor = "John Marciniak", + publisher = "John Wiley \& Sons", + URL = "http://chacs.nrl.navy.mil/publications/CHACS/1994/1994mclean-ency.ps", +} + +@InProceedings{mclean-composition-94, + author = "John {McLean}", + title = "A General Theory of Composition for Trace Sets Closed + Under Selective Interleaving Functions", + year = "1994", + booktitle = sp, + URL = "http://chacs.nrl.navy.mil/publications/CHACS/1994/1994mclean-sp.ps", +} + +@InProceedings{meadows-94, + author = "Catherine Meadows", + title = "Formal Verification of Cryptographic Protocols: {A} + Survey", + booktitle = "Advances in Cryptology -- {ASIA\-CRYPT}'94", + year = "1995", + publisher = springer, + series = lncs, + volume = "917", + pages = "133--150", + URL = "http://chacs.nrl.navy.mil/publications/CHACS/1995/1995meadows-asiacrypt94.ps", +} + +@Article{mehta-nipkow-05, + author = "Farhad Mehta and Tobias Nipkow", + title = "Proving pointer programs in higher-order logic", + journal = ic, + volume = "199", + number = "1--2", + year = "2005", + pages = "200--227", + URL = "http://www4.informatik.tu-muenchen.de/~nipkow/pubs/ic05.ps.gz", +} + +@Article{melham-hol-93, + author = "Thomas F. Melham", + title = "The {HOL} Logic Extended with Quantification over Type + Variables", + journal = fmsd, + year = "1993", + volume = "3", + number = "1--2", + pages = "7--24", + URL = "http://web.comlab.ox.ac.uk/oucl/work/tom.melham/pub/Melham-1994-HLE.pdf", +} + +} + +@Article{melski-reps-00, + author = "David Melski and Thomas Reps", + title = "Interconvertibility of a class of set constraints and + context-free language reachability", + journal = tcs, + year = "2000", + volume = "248", + number = "1--2", + URL = "http://www.cs.wisc.edu/wpis/papers/tcs_submission98r2.ps", +} + +@Misc{menhir, + author = "François Pottier and Yann Régis-Gianas", + title = "The {Menhir} parser generator", + note = "\url{http://gallium.inria.fr/~fpottier/menhir/}", +} + +@Manual{merr, + title = "{Merr} User's Guide", + author = "Clinton L. Jeffery", + year = "2002", + URL = "http://unicon.sourceforge.net/merr/merrguid.pdf", +} + +@InProceedings{merz-00, + author = "Stephan Merz", + title = "Model Checking: {A} Tutorial Overview", + booktitle = "Fourth Summer School on Modeling and Verification of + Parallel Processes", + pages = "3--38", + publisher = springer, + series = lncs, + volume = "2067", + year = "2001", + URL = "http://www.loria.fr/~merz/papers/mc-tutorial.pdf", +} + +@InProceedings{merz-08, + author = "Stephan Merz", + editor = "N. Navet and S. Merz", + booktitle = "Modeling and Verification of Real-Time Systems: + Formalisms and Software Tools", + title = "An Introduction to Model Checking", + publisher = "ISTE Publishing", + year = "2008", + pages = "77--109", + URL = "http://www.loria.fr/~merz/papers/mc-iste2008.pdf", +} + +@InProceedings{miller-00, + author = "Dale Miller", + title = "Abstract Syntax for Variable Binders: An Overview", + booktitle = "Computational Logic", + pages = "239--253", + year = "2000", + series = lncs, + volume = "1861", + publisher = springer, + URL = "http://www.lix.polytechnique.fr/~dale/papers/cl2000.pdf", +} + +@InProceedings{miller-90, + author = "Dale Miller", + title = "An Extension to {ML} to Handle Bound Variables in Data + Structures", + booktitle = "Logical Frameworks BRA Workshop", + year = "1990", + URL = "http://www.lix.polytechnique.fr/Labo/Dale.Miller/papers/mll.pdf", +} + +@Article{miller-92, + author = "Dale Miller", + title = "Unification Under a Mixed Prefix", + journal = jsc, + volume = "14", + number = "4", + year = "1992", + pages = "321--358", + URL = "http://www.lix.polytechnique.fr/~dale/papers/jsc92.pdf", +} + +@Article{millstein-chambers-02, + author = "Todd Millstein and Craig Chambers", + title = "Modular statically typed multimethods", + journal = ic, + year = "2002", + volume = "175", + number = "1", + pages = "76--118", + URL = "http://www.cs.ucla.edu/~todd/research/iandc.ps", +} + +@InProceedings{millstein-chambers-99, + author = "Todd Millstein and Craig Chambers", + title = "Modular statically typed multimethods", + booktitle = ecoop, + pages = "279--303", + year = "1999", + volume = "1628", + series = lncs, + publisher = springer, + URL = "http://www.cs.ucla.edu/~todd/research/ecoop99.ps", +} + +@Article{milner-78, + title = "A Theory of Type Polymorphism in Programming", + author = "Robin Milner", + pages = "348--375", + journal = "Journal of Computer and System Sciences", + year = "1978", + volume = "17", + number = "3", + URL = "http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.67.5276", +} + +@TechReport{milner-91, + author = "Robin Milner", + institution = "Laboratory for Foundations of Computer Science, + Department of Computer Science, University of + Edinburgh", + number = "{ECS--LFCS--91--180}", + title = "The Polyadic $\pi$-Calculus: a Tutorial", + year = "1991", + URL = "ftp://ftp.cl.cam.ac.uk/users/rm135/ppi.ps.Z", +} + +@InProceedings{milner-lcf-72, + author = "Robin Milner", + title = "Implementation and applications of {Scott's} logic for + computable functions", + booktitle = "Proceedings of the {ACM} conference on proving + assertions about programs", + year = "1972", + pages = "1--6", + URL = "http://doi.acm.org/10.1145/800235.807067", +} + +@TechReport{milner-lcf-tr-72, + author = "Robin Milner", + title = "Logic for Computable Functions -- Description of a + Machine Implementation", + institution = "Stanford University, Department of Computer Science", + year = "1972", + number = "CS-TR-72-288", + URL = "ftp://reports.stanford.edu/pub/cstr/reports/cs/tr/72/288/CS-TR-72-288.pdf", +} + +@TechReport{milner-lcf-tr-73, + author = "Robin Milner", + title = "Models of {LCF}", + institution = "Stanford University, Department of Computer Science", + year = "1973", + number = "CS-TR-73-332", + URL = "ftp://reports.stanford.edu/pub/cstr/reports/cs/tr/73/332/CS-TR-73-332.pdf", +} + +@TechReport{milner-parrow-walker-89b, + author = "Robin Milner and Joachim Parrow and David Walker", + title = "A Calculus of Mobile Processes, part 2", + institution = "Laboratory for Foundations of Computer Science, School + of Informatics at the University of Edinburgh", + year = "1989", + number = "ECS-LFCS-89-86", + URL = "http://www.lfcs.inf.ed.ac.uk/reports/89/ECS-LFCS-89-86/ECS-LFCS-89-86.ps", +} + +@InProceedings{milner-sangiorgi-92, + title = "Barbed Bisimulation", + author = "Robin Milner and Davide Sangiorgi", + booktitle = icalp, + year = "1992", + series = lncs, + volume = "623", + publisher = springer, + pages = "685--695", + URL = "ftp://ftp-sop.inria.fr/meije/theorie-par/davides/bn.ps.gz", +} + +@InProceedings{minamide-98, + author = "Yasuhiko Minamide", + title = "A functional representation of data structures with a + hole", + booktitle = popl, + year = "1998", + pages = "75--84", + URL = "http://www.score.cs.tsukuba.ac.jp/~minamide/papers/hole.popl98.pdf", +} + +@InProceedings{minamide-al-96, + author = "Yasuhiko Minamide and Greg Morrisett and Robert + Harper", + title = "Typed closure conversion", + booktitle = popl, + year = "1996", + pages = "271--283", + URL = "http://www.cs.cornell.edu/Info/People/jgm/papers/closure-summary.ps", +} + +@InProceedings{minamide-okuma-03, + author = "Yasuhiko Minamide and Koji Okuma", + title = "Verifying {CPS} transformations in {Isabelle/HOL}", + booktitle = merlin, + year = "2003", + URL = "http://doi.acm.org/10.1145/976571.976576", +} + +@Article{mitchell-05, + author = "David G. Mitchell", + title = "A {SAT} Solver Primer", + journal = "Bulletin of the EATCS", + volume = "85", + year = "2005", + pages = "112--133", + URL = "http://www.cs.sfu.ca/~mitchell/papers/colLogCS85.pdf", +} + +@InProceedings{mitchell-84, + author = "John C. Mitchell", + title = "Coercion and type inference", + booktitle = popl, + pages = "175--185", + year = "1984", + URL = "http://portal.acm.org/citation.cfm?id=800529&dl=ACM&coll=portal", +} + +@InProceedings{mitchell-86, + author = "John C. Mitchell", + title = "Representation Independence and Data Abstraction", + booktitle = popl, + year = "1986", + pages = "263--276", + URL = "http://dx.doi.org/10.1145/512644.512669", +} + +@Article{mitchell-88, + author = "John C. Mitchell", + title = "Polymorphic type inference and containment", + journal = ic, + year = "1988", + volume = "76", + number = "2--3", + pages = "211--249", + URL = "http://dx.doi.org/10.1016/0890-5401(88)90009-0", +} + +@Article{mitchell-91, + author = "John C. Mitchell", + title = "Type Inference with Simple Subtypes", + journal = jfp, + year = "1991", + volume = "1", + number = "3", + pages = "245--286", +} + +@Book{mitchell-96, + author = "John C. Mitchell", + title = "Foundations for Programming Languages", + publisher = mitp, + year = "1996", +} + +@Article{mitchell-plotkin-88, + author = "John C. Mitchell and Gordon D. Plotkin", + title = "Abstract types have existential type", + journal = toplas, + volume = "10", + number = "3", + year = "1988", + pages = "470--502", + URL = "http://theory.stanford.edu/people/jcm/papers/mitch-plotkin-88.pdf", +} + +@InProceedings{mitls-13, + author = "Karthikeyan Bhargavan and C{\'{e}}dric Fournet and + Markulf Kohlweiss and Alfredo Pironti and Pierre{-}Yves + Strub", + title = "Implementing {TLS} with Verified Cryptographic + Security", + booktitle = sp, + pages = "445--459", + year = "2013", + URL = "http://prosecco.gforge.inria.fr/personal/karthik/pubs/implementing-tls-with-verified-cryptographic-security-sp13.pdf", +} + +@Article{mizuno-schmidt-92, + author = "Masaaki Mizuno and David A. Schmidt", + journal = fac, + title = "A Security Flow Control Algorithm and Its Denotational + Semantics Correctness Proof", + year = "1992", + volume = "4", + number = "6A", + pages = "727--754", + URL = "ftp://ftp.cis.ksu.edu/pub/CIS/Schmidt/papers/security.ps.Z", +} + +@Misc{mlton, + author = "Henry Cejtin and Matthew Fluet and Suresh Jagannathan + and Stephen Weeks", + title = "The {MLton} compiler", + year = "2007", + URL = "http://mlton.org/", +} + +@InProceedings{mogelberg-staton-10, + author = "Rasmus Ejlers Møgelberg and Sam Staton", + title = "Full abstraction in a metalanguage for state", + booktitle = lola, + year = "2010", +} + +@InProceedings{moggi-89, + author = "Eugenio Moggi", + title = "Computational $\lambda$-Calculus and Monads", + booktitle = lics, + year = "1989", + pages = "14--23", + URL = "http://www.disi.unige.it/person/MoggiE/ftp/lics89.ps.gz", +} + +@TechReport{moggi-89b, + author = "Eugenio Moggi", + title = "An abstract view of programming languages", + institution = "University of Edinburgh", + number = "ECS-LFCS-90-113", + year = "1989", + URL = "http://www.disi.unige.it/person/MoggiE/ftp/abs-view.ps.gz", +} + +@Article{moggi-91, + author = "Eugenio Moggi", + title = "Notions of computation and monads", + journal = ic, + year = "1991", + volume = "93", + number = "1", + URL = "http://www.disi.unige.it/person/MoggiE/ftp/ic91.pdf", +} + +@Article{moggi-sabry-04, + author = "Eugenio Moggi and Amr Sabry", + title = "An Abstract Monadic Semantics for Value Recursion", + journal = ita, + year = "2004", + volume = "38", + number = "4", + pages = "377--400", + URL = "http://www.disi.unige.it/person/MoggiE/ftp/ita04.pdf", +} + +@Article{monadic-regions-06, + author = "Matthew Fluet and Greg Morrisett", + title = "Monadic Regions", + journal = jfp, + year = "2006", + volume = "16", + number = "4--5", + pages = "485--545", + URL = "http://dx.doi.org/10.1017/S095679680600596X", +} + +@Unpublished{monnier-08, + author = "Stefan Monnier", + title = "Statically tracking state with Typed Regions", + note = "Unpublished", + year = "2008", + URL = "http://www.iro.umontreal.ca/~monnier/tr.pdf", +} + +@InProceedings{montagu-remy-09, + author = "Beno{\^\i}t Montagu and Didier R{\'e}my", + title = "Modeling Abstract Types in Modules with Open + Existential Types", + booktitle = popl, + year = "2009", + URL = "http://gallium.inria.fr/~remy/modules/Montagu-Remy@popl09:fzip.pdf", + pages = "63--74", +} + +@Article{morrisett-al-07, + title = "${L}^3$: {A} Linear Language with Locations", + author = "Amal Ahmed and Matthew Fluet and Greg Morrisett", + journal = fundamenta, + year = "2007", + number = "4", + volume = "77", + pages = "397--449", + URL = "http://ttic.uchicago.edu/~amal/papers/linloc-fi07.pdf", +} + +@Article{morrisett-ftal-99, + author = "Greg Morrisett and David Walker and Karl Crary and + Neal Glew", + title = "From System {F} to Typed Assembly Language", + journal = toplas, + year = "1999", + volume = "21", + number = "3", + pages = "528--569", + URL = "http://www.cs.cornell.edu/talc/papers/tal-toplas.pdf", +} + +@InProceedings{morrisett-rec-98, + author = "Greg Morrisett and Robert Harper", + title = "Typed Closure Conversion for Recursively-Defined + Functions (Extended Abstract)", + booktitle = hoots, + year = "1998", + series = entcs, + volume = "10", + publisher = elsevier, + URL = "http://www.cs.cornell.edu/home/jgm/papers/hootsclosure.ps", +} + +@InProceedings{moskewicz-chaff-01, + author = "Matthew W. Moskewicz and Conor F. Madigan and Ying + Zhao and Lintao Zhang and Sharad Malik", + title = "Chaff: Engineering an efficient {SAT} solver", + booktitle = dac, + year = "2001", + URL = "http://research.microsoft.com/users/lintaoz/papers/dac_2001.pdf", +} + +@Article{mosses-04, + author = "Peter D. Mosses", + title = "Modular structural operational semantics", + journal = jlap, + volume = "60--61", + year = "2004", + pages = "195--228", + URL = "http://www.brics.dk/RS/05/7/BRICS-RS-05-7.pdf", +} + +@InProceedings{mueller-94, + author = "Martin M{\"u}ller", + title = "A Constraint-Based Recast of {ML}-Polymorphism", + booktitle = "International Workshop on Unification", + year = "1994", + note = "Technical Report 94-R-243, CRIN, Nancy, France", + URL = "http://www.ps.uni-sb.de/Papers/abstracts/UNIF94.ps", +} + +@Unpublished{mueller-98, + author = "Martin M{\"u}ller", + title = "Notes on {HM}$({X})$", + year = "1998", + URL = "http://www.ps.uni-sb.de/~mmueller/papers/HMX.ps.gz", + note = "Unpublished", +} + +@Article{mueller-feature-01, + title = "The First-Order Theory of Ordering Constraints over + Feature Trees", + year = "2001", + author = "Martin M{\"u}ller and Joachim Niehren and Ralf + Treinen", + journal = "Discrete Mathematics and Theoretical Computer + Science", + pages = "193--234", + number = "2", + volume = "4", + URL = "http://www.ps.uni-sb.de/Papers/abstracts/FTSubTheory-Long:99.ps", +} + +@Article{mueller-holcf-99, + author = "Olaf Müller and Tobias Nipkow and David von Oheimb + and Oskar Slotosch", + title = "{HOLCF = HOL + LCF}", + journal = jfp, + volume = "9", + pages = "191--223", + year = "1999", + URL = "http://www4.informatik.tu-muenchen.de/~nipkow/pubs/jfp99.ps.gz", +} + +@Article{mueller-niehren-podelski-feature-99, + author = "Martin Müller and Joachim Niehren and Andreas + Podelski", + journal = "Constraints, an International Journal", + volume = "5", + number = "1--2", + title = "Ordering Constraints over Feature Trees", + mon = jan, + year = "2000", + pages = "7--42", + URL = "ftp://ftp.ps.uni-sb.de/pub/papers/ProgrammingSysLab/ftsub-constraints-99.ps.gz", +} + +@InProceedings{mueller-niehren-podelski-ines-97, + author = "Joachim Niehren and Martin M{\"u}ller and Andreas + Podelski", + booktitle = tapsoft, + title = "Inclusion Constraints over Non-Empty Sets of Trees", + series = lncs, + publisher = springer, + volume = "1214", + year = "1997", + pages = "217--231", + URL = "http://www.ps.uni-sb.de/Papers/abstracts/ines97.ps", +} + +@Article{mueller-nishimura-00, + author = "Martin M{\"u}ller and Susumu Nishimura", + title = "Type Inference for First-Class Messages with Feature + Constraints", + journal = ijfcs, + year = "2000", + volume = "11", + number = "1", + pages = "29--63", +} + +@InProceedings{mueller-nishimura-98, + author = "Martin M{\"u}ller and Susumu Nishimura", + title = "Type Inference for First-Class Messages with Feature + Constraints", + booktitle = asian, + pages = "169--187", + year = "1998", + volume = "1538", + series = lncs, + publisher = springer, + URL = "http://www.ps.uni-sb.de/Papers/abstracts/FirstClass98.ps", +} + +@TechReport{mueller-poetzsch-heffter-01, + author = "Peter M{\"u}ller and Arnd Poetzsch-Heffter", + title = "Universes: {A} Type System for Alias and Dependency + Control", + year = "2001", + institution = "Fernuniversit{\"a}t Hagen", + number = "279", + URL = "http://people.inf.ethz.ch/lehnerh/pm/publications/getpdf.php?bibname=Own&id=MuellerPoetzsch-Heffter01a.pdf", +} + +@InProceedings{mueller-rudich-07, + author = "Peter M{\"u}ller and Arsenii Rudich", + title = "Ownership transfer in universe types", + booktitle = oopsla, + year = "2007", + pages = "461--478", + URL = "http://dx.doi.org/10.1145/1297027.1297061", +} + +@InProceedings{mueller-schwerhoff-summers-16, + author = "Peter M{\"{u}}ller and Malte Schwerhoff and Alexander + J. Summers", + title = "Automatic Verification of Iterated Separating + Conjunctions Using Symbolic Execution", + booktitle = cav, + pages = "405--425", + year = "2016", + volume = "9779", + publisher = springer, + series = lncs, + URL = "https://arxiv.org/abs/1603.00649", +} + +@InProceedings{muller-rpc-98, + title = "Fast, optimized {Sun} {RPC} using automatic program + specialization", + author = "Gilles Muller and Renaud Marlet and Eugen-Nicolae + Volanschi and Charles Consel and Calton Pu and Ashvin + Goel", + booktitle = cdcs, + pages = "240--249", + year = "1998", + URL = "http://www.cc.gatech.edu/~calton/publications/dcs-98.pdf", +} + +@InProceedings{mycroft-84, + author = "Alan Mycroft", + title = "Polymorphic Type Schemes and Recursive Definitions", + booktitle = "International Symposium on Programming", + series = lncs, + volume = "167", + pages = "217--228", + year = "1984", + publisher = springer, + URL = "http://dx.doi.org/10.1007/3-540-12925-1_41", +} + +@PhdThesis{myers-99, + author = "Andrew C. Myers", + title = "Mostly-Static Decentralized Information Flow Control", + school = "Massachusetts Institute of Technology", + year = "1999", + pages = "171", + note = "Technical Report MIT/LCS/TR-783", + URL = "http://www.cs.cornell.edu/andru/release/tr783.ps.gz", +} + +@Article{myers-liskov-00, + author = "Andrew C. Myers and Barbara Liskov", + title = "Protecting Privacy using the Decentralized Label + Model", + journal = tosem, + volume = "9", + number = "4", + year = "2000", + pages = "410--442", + URL = "http://www.cs.cornell.edu/andru/papers/iflow-tosem.ps.gz", +} + +@Article{myers-liskov-97, + author = "Andrew C. Myers and Barbara Liskov", + title = "A Decentralized Model for Information Flow Control", + year = "1997", + number = "5", + volume = "31", + pages = "129--142", + journal = "{ACM} Operating Systems Review", + URL = "http://www.cs.cornell.edu/andru/papers/iflow-sosp97/paper.html", +} + +@InProceedings{myers-liskov-98, + author = "Andrew C. Myers and Barbara Liskov", + title = "Complete, Safe Information Flow with Decentralized + Labels", + year = "1998", + pages = "186--197", + booktitle = sp, + URL = "http://www.cs.cornell.edu/andru/papers/sp98/top.html", +} + +@InProceedings{myers-popl-99, + author = "Andrew C. Myers", + title = "{JFlow}: practical mostly-static information flow + control", + booktitle = popl, + year = "1999", + pages = "228--241", + URL = "http://www.cs.cornell.edu/andru/papers/popl99/myers-popl99.ps.gz", +} + +@Article{myers-sabelfeld-03, + author = "Andrew C. Myers and Andrei Sabelfeld", + title = "Language-Based Information-Flow Security", + journal = "IEEE Journal on Selected Areas in Communications", + year = "2003", + volume = "21", + number = "1", + pages = "5--19", + URL = "http://www.cs.cornell.edu/andru/papers/jsac/sm-jsac03.pdf", +} + +@InProceedings{nadathur-miller-88, + author = "Gopalan Nadathur and Dale Miller", + title = "An Overview of Lambda-Prolog", + booktitle = "Logic Programming", + pages = "810--827", + year = "1988", + URL = "http://repository.upenn.edu/cis_reports/595/", +} + +@InProceedings{nadathur-qi-03, + author = "Gopalan Nadathur and Xiaochu Qi", + title = "Explicit Substitutions in the Reduction of Lambda + Terms", + booktitle = ppdp, + pages = "195--206", + year = "2003", + URL = "http://www-users.cs.umn.edu/~gopalan/papers/reduction.ps", + alturl = "http://doi.acm.org/10.1145/888270", +} + +@Book{naftalin-wadler-06, + author = "Maurice Naftalin and Philip Wadler", + title = "{Java} generics and collections", + publisher = "O'Reilly", + year = "2006", + URL = "http://shop.oreilly.com/product/9780596527754.do", +} + +@InProceedings{nakano-00, + author = "Hiroshi Nakano", + title = "A Modality for Recursion", + booktitle = lics, + pages = "255--266", + year = "2000", + URL = "http://www602.math.ryukoku.ac.jp/~nakano/papers/modality-lics00.ps.gz", +} + +@InProceedings{nakano-01, + author = "Hiroshi Nakano", + title = "Fixed-point Logic with the Approximation Modality and + Its {Kripke} Completeness", + booktitle = tacs, + pages = "165--182", + year = "2001", + volume = "2215", + series = lncs, + publisher = springer, + URL = "http://www602.math.ryukoku.ac.jp/~nakano/papers/modality-tacs01.pdf", +} + +@TechReport{nanevski-02, + author = "Aleksandar Nanevski", + title = "Meta-Programming with Names and Necessity", + institution = "School of Computer Science, Carnegie Mellon + University", + year = "2002", + number = "CMU-CS-02-123R", + URL = "http://www.eecs.harvard.edu/~aleks/papers/necessity/techrep2.ps", +} + +@InProceedings{nanevski-htt-06, + author = "Aleksandar Nanevski and Greg Morrisett and Lars + Birkedal", + title = "Polymorphism and Separation in {Hoare} Type Theory", + booktitle = icfp, + pages = "62--73", + year = "2006", + URL = "http://www.eecs.harvard.edu/~aleks/papers/hoarelogic/icfp06.pdf", +} + +@InProceedings{nanevski-htt-07, + author = "Aleksandar Nanevski and Amal Ahmed and Greg Morrisett + and Lars Birkedal", + title = "Abstract Predicates and Mutable {ADTs} in {Hoare} Type + Theory", + booktitle = esop, + year = "2007", + series = lncs, + volume = "4421", + pages = "189--204", + publisher = springer, + URL = "http://ynot.cs.harvard.edu/papers/esop07.pdf", +} + +@Article{nanevski-htt-08, + author = "Aleksandar Nanevski and Greg Morrisett and Lars + Birkedal", + title = "{Hoare} Type Theory, Polymorphism and Separation", + journal = jfp, + year = "2008", + volume = "18", + number = "5--6", + pages = "865--911", + URL = "http://ynot.cs.harvard.edu/papers/jfpsep07.pdf", +} + +@InProceedings{nanevski-structuring-10, + author = "Aleksandar Nanevski and Viktor Vafeiadis and Josh + Berdine", + title = "Structuring the verification of heap-manipulating + programs", + booktitle = popl, + year = "2010", + pages = "261--274", + URL = "http://software.imdea.org/~aleks/papers/reflect/reflect.pdf", +} + +@InProceedings{nanevski-ynot-08, + author = "Aleksandar Nanevski and Greg Morrisett and Avraham + Shinnar and Paul Govereau and Lars Birkedal", + title = "Ynot: dependent types for imperative programs", + booktitle = icfp, + year = "2008", + pages = "229--240", + URL = "http://software.imdea.org/~aleks/htt/ynot08.pdf", +} + +@Article{naraschewski-nipkow-99, + author = "Wolfgang Naraschewski and Tobias Nipkow", + title = "Type Inference Verified: Algorithm {W} in + {Isabelle/HOL}", + journal = jar, + year = "1999", + volume = "23", + pages = "299--318", + URL = "http://www4.informatik.tu-muenchen.de/~nipkow/pubs/W.ps.gz", +} + +@Article{naumann-survey-07, + author = "David A. Naumann", + title = "On assertion-based encapsulation for object invariants + and simulations", + journal = fac, + volume = "19", + number = "2", + year = "2007", + pages = "205--224", + publisher = springer, + URL = "https://guinness.cs.stevens-tech.edu/~naumann/publications/fmcoFinal.pdf", +} + +@InProceedings{navarro-perez-rybalchenko-11, + author = "Juan Antonio {Navarro P{\'e}rez} and Andrey + Rybalchenko", + title = "Separation logic + superposition calculus = heap + theorem prover", + booktitle = pldi, + year = "2011", + pages = "556--566", + URL = "http://www7.informatik.tu-muenchen.de/um/bibdb/navarro/pldi2011.pdf", +} + +@InProceedings{needle-knot-16, + author = "Steven Keuchel and Stephanie Weirich and Tom + Schrijvers", + title = "Needle {\&} Knot: Binder Boilerplate Tied Up", + booktitle = esop, + pages = "419--445", + year = "2016", + series = lncs, + volume = "9632", + publisher = springer, + URL = "https://users.ugent.be/~skeuchel/publications/knot.pdf", +} + +@InProceedings{neron-tolmach-visser-wachsmuth-15, + author = "Pierre Neron and Andrew P. Tolmach and Eelco Visser + and Guido Wachsmuth", + title = "A Theory of name resolution", + booktitle = esop, + pages = "205--231", + year = "2015", + series = lncs, + volume = "9032", + publisher = springer, + URL = "http://web.cecs.pdx.edu/~apt/esop15.pdf", +} + +@InProceedings{neumann-12, + author = "René Neumann", + booktitle = "ATx/WInG: Joint Proceedings of the Workshops on + Automated Theory eXploration and on Invariant + Generation", + pages = "36--45", + title = "A Framework for Verified Depth-First Algorithms", + publisher = "EasyChair", + series = "EPiC Series", + volume = "17", + year = "2012", + URL = "http://www.easychair.org/publications/?page=722211206", +} + +@InProceedings{nguyen-07, + author = "Huu Hai Nguyen and Cristina David and Shengchao Qin + and Wei-Ngan Chin", + title = "Automated Verification of Shape and Size Properties + Via Separation Logic", + booktitle = vmcai, + year = "2007", + pages = "251--266", + publisher = springer, + series = lncs, + volume = "4349", + URL = "http://www.scm.tees.ac.uk/s.qin/papers/vmcai07.pdf", +} + +@InProceedings{nicklisch-peyton-jones-96, + author = "Jan Nicklisch and Simon {Peyton Jones}", + title = "An exploration of modular programs", + booktitle = "Functional Programming Workshop", + year = "1996", + URL = "http://www.dcs.gla.ac.uk/fp/workshops/fpw96/Nicklisch.ps.gz", +} + +@InProceedings{niehren-priesnitz-01, + author = "Joachim Niehren and Tim Priesnitz", + title = "Non-Structural Subtype Entailment in Automata Theory", + booktitle = tacs, + publisher = springer, + year = "2001", + URL = "ftp://ftp.ps.uni-sb.de/pub/papers/ProgrammingSysLab/pauto.ps.gz", +} + +@Article{niehren-priesnitz-03, + author = "Joachim Niehren and Tim Priesnitz", + title = "Non-Structural Subtype Entailment in Automata Theory", + journal = ic, + year = "2003", + volume = "186", + number = "2", + pages = "319--354", + URL = "http://www.ps.uni-sb.de/Papers/abstracts/subtype.pdf", +} + +@TechReport{nielsen-00, + author = "Lasse R. Nielsen", + title = "A denotational investigation of defunctionalization", + year = "2000", + institution = "BRICS", + number = "RS-00-47", + URL = "http://www.brics.dk/RS/00/47/", +} + +@Article{nielson-02, + author = "Flemming Nielson and Hanne Riis Nielson and Helmut + Seidl", + title = "A Succinct Solver for {ALFP}", + journal = njc, + year = "2002", + volume = "9", + number = "4", + pages = "335--372", + URL = "http://www.informatik.uni-trier.de/~seidl/papers/succinct.pdf", +} + +@Article{nielson-88, + author = "Flemming Nielson and Hanne Riis Nielson", + title = "Two-Level Semantics and Code Generation", + year = "1988", + pages = "59--133", + journal = tcs, + volume = "56", + number = "1", + URL = "http://dx.doi.org/10.1016/0304-3975(86)90006-X", +} + +@Article{nieuwenhuis-oliveras-tinelli-06, + author = "Robert Nieuwenhuis and Albert Oliveras and Cesare + Tinelli", + title = "Solving {SAT} and {SAT Modulo Theories}: From an + abstract {Davis--Putnam--Logemann--Loveland} procedure + to {DPLL(T)}", + journal = jacm, + volume = "53", + number = "6", + year = "2006", + pages = "937--977", + URL = "ftp://ftp.cs.uiowa.edu/pub/tinelli/papers/NieOT-JACM-06.pdf", +} + +@InProceedings{nipkow-15, + author = "Tobias Nipkow", + title = "Amortized Complexity Verified", + year = "2015", + booktitle = itp, + pages = "310--324", + volume = "9236", + series = lncs, + publisher = springer, + URL = "http://www21.in.tum.de/~nipkow/pubs/itp15.pdf", +} + +@InProceedings{nishimura-98, + title = "Static Typing for Dynamic Messages", + author = "Susumu Nishimura", + pages = "266--278", + booktitle = popl, + year = "1998", + URL = "ftp://ftp.kurims.kyoto-u.ac.jp/pub/paper/member/nisimura/dmesg-popl98.ps.gz", +} + +@InProceedings{ntzik-gardner-15, + author = "Gian Ntzik and Philippa Gardner", + title = "Reasoning about the {POSIX} file system: local update + and global pathnames", + booktitle = oopsla, + pages = "201--220", + year = "2015", + URL = "https://www.doc.ic.ac.uk/~pg/papers/oopsla2015.pdf", +} + +@Article{o'hearn-03, + author = "Peter O'Hearn", + title = "On Bunched Typing", + journal = jfp, + year = "2003", + volume = "13", + number = "4", + pages = "747--796", + URL = "http://www.cs.ucl.ac.uk/staff/p.ohearn/papers/BunchedTyping.pdf", +} + +@Manual{objective-caml, + author = "Xavier Leroy and Damien Doligez and Jacques Garrigue + and Didier Rémy and Jérôme Vouillon", + title = "The {Objective Caml} system", + year = "2005", + URL = "http://caml.inria.fr/", +} + +@Misc{ocaml, + author = "Xavier Leroy and Damien Doligez and Alain Frisch and + Jacques Garrigue and Didier Rémy and Jérôme + Vouillon", + title = "The {OCaml} system: documentation and user's manual", + year = "2016", + URL = "http://caml.inria.fr/pub/docs/manual-ocaml-4.04/index.html", +} + +@Article{oconnor-07, + author = "Russell O'Connor", + title = "Assembly: Circular Programming with Recursive do", + journal = "The Monad.Reader", + year = "2007", + volume = "6", + URL = "http://www.haskell.org/sitewiki/images/1/14/TMR-Issue6.pdf", +} + +@InProceedings{odersky-laufer-96, + author = "Martin Odersky and Konstantin Läufer", + title = "Putting Type Annotations To Work", + booktitle = popl, + year = "1996", + pages = "54--67", + URL = "http://lamp.epfl.ch/~odersky/papers/popl96.ps.gz", +} + +@InProceedings{odersky-local-94, + author = "Martin Odersky", + title = "A Functional Theory of Local Names", + pages = "48--59", + booktitle = popl, + year = "1994", + URL = "http://lampwww.epfl.ch/~odersky/papers/popl94.ps.gz", +} + +@InProceedings{odersky-observers-92, + author = "Martin Odersky", + title = "Observers for Linear Types", + booktitle = esop, + pages = "390--407", + year = "1992", + volume = "582", + series = lncs, + publisher = springer, + URL = "http://lamp.epfl.ch/~odersky/papers/esop92.ps.gz", +} + +@Article{odersky-sulzmann-wehr-99, + author = "Martin Odersky and Martin Sulzmann and Martin Wehr", + title = "Type Inference with Constrained Types", + journal = tapos, + year = "1999", + volume = "5", + number = "1", + pages = "35--55", + URL = "http://eprints.kfupm.edu.sa/73647/1/73647.pdf", +} + +@InProceedings{odersky-wadler-wehr-95, + author = "Martin Odersky and Philip Wadler and Martin Wehr", + title = "A Second Look at Overloading", + booktitle = fpca, + pages = "135--146", + year = "1995", + URL = "http://lampwww.epfl.ch/~odersky/papers/fpca95.ps.gz", +} + +@InProceedings{odersky-zenger-zenger-01, + author = "Martin Odersky and Matthias Zenger and Christoph + Zenger", + title = "Colored Local Type Inference", + booktitle = popl, + year = "2001", + pages = "41--53", + URL = "http://lampwww.epfl.ch/papers/clti-colored.ps.gz", +} + +@Article{ohearn-07, + author = "Peter W. O'Hearn", + title = "Resources, Concurrency and Local Reasoning", + journal = tcs, + year = "2007", + volume = "375", + number = "1--3", + pages = "271--307", + URL = "http://www.cs.ucl.ac.uk/staff/p.ohearn/papers/concurrency.pdf", +} + +@InProceedings{ohearn-hiding-04, + author = "Peter W. O'Hearn and Hongseok Yang and John C. + Reynolds", + title = "Separation and information hiding", + booktitle = popl, + pages = "268--280", + year = "2004", + URL = "http://www.cs.ucl.ac.uk/staff/p.ohearn/papers/separation-and-hiding.pdf", +} + +@Article{ohearn-hiding-09, + author = "Peter W. O'Hearn and Hongseok Yang and John C. + Reynolds", + title = "Separation and information hiding", + journal = toplas, + volume = "31", + number = "3", + year = "2009", + URL = "http://www.cs.ucl.ac.uk/staff/p.ohearn/papers/toplas09.pdf", +} + +@Article{ohearn-reynolds-00, + author = "Peter W. O'Hearn and John C. Reynolds", + title = "From {Algol} to polymorphic linear lambda-calculus", + journal = jacm, + volume = "47", + number = "1", + year = "2000", + pages = "167--223", + URL = "http://www.cs.ucl.ac.uk/staff/p.ohearn/papers/AlgolToPolyLin.ps", +} + +@Article{ohearn-scir-99, + author = "Peter W. O'Hearn and John Power and Makoto Takeyama + and Robert D. Tennent", + title = "Syntactic Control of Interference Revisited", + journal = tcs, + volume = "228", + number = "1-2", + pages = "211--252", + year = "1999", + URL = "http://surface.syr.edu/cgi/viewcontent.cgi?article=1011&context=lcsmith_other", +} + +@Article{ohori-95, + author = "Atsushi Ohori", + title = "A Polymorphic Record Calculus and Its Compilation", + journal = toplas, + volume = "17", + number = "6", + pages = "844--895", + year = "1995", + URL = "http://doi.acm.org/10.1145/218570.218572", +} + +@InProceedings{ohori-buneman-88, + author = "Atsushi Ohori and Peter Buneman", + title = "Type Inference in a Database Programming Language", + booktitle = lfp, + pages = "174--183", + year = "1988", + URL = "http://www.jaist.ac.jp/~ohori/research/lfp88.pdf", +} + +@InProceedings{okasaki-96, + author = "Chris Okasaki", + title = "The role of lazy evaluation in amortized data + structures", + booktitle = icfp, + year = "1996", + pages = "62--72", + URL = "http://www.eecs.usma.edu/webs/people/okasaki/icfp96.ps", +} + +@InProceedings{okasaki-98, + author = "Chris Okasaki and Andy Gill", + title = "Fast Mergeable Integer Maps", + booktitle = ml, + pages = "77--86", + year = "1998", + URL = "http://www.cse.ogi.edu/~andy/papers/ml98maps.ps", +} + +@Book{okasaki-book-99, + author = "Chris Okasaki", + title = "Purely Functional Data Structures", + publisher = cup, + year = "1999", + URL = "http://www.cambridge.org/us/catalogue/catalogue.asp?isbn=0521663504", +} + +@TechReport{okasaki-phd-96, + author = "Chris Okasaki", + title = "Purely Functional Data Structures", + institution = "School of Computer Science, Carnegie Mellon + University", + year = "1996", + number = "CMU-CS-96-177", + URL = "http://www.cs.cmu.edu/~rwh/theses/okasaki.pdf", +} + +@InProceedings{okasaki-views-98, + author = "Chris Okasaki", + title = "Views for {Standard ML}", + booktitle = ml, + pages = "14--23", + year = "1998", + URL = "http://www.eecs.usma.edu/Personnel/okasaki/ml98views.ps", +} + +@InProceedings{olderog-83, + author = "Ernst-Rüdiger Olderog", + title = "A characterization of {Hoare's} logic for programs + with {Pascal}-like procedures", + booktitle = stoc, + year = "1983", + pages = "320--329", + URL = "http://doi.acm.org/10.1145/800061.808761", +} + +@Manual{omega, + title = "{${\Omega}$}mega", + author = "Tim Sheard", + year = "2005", + URL = "http://www.cs.pdx.edu/~sheard/Omega/", +} + +@Article{oostrom-94, + author = "Vincent van Oostrom", + title = "Confluence by decreasing diagrams", + journal = tcs, + volume = "126", + number = "2", + pages = "259--280", + year = "1994", + URL = "ftp://ftp.cs.vu.nl/pub/papers/theory/IR-298.ps.Z", +} + +@Book{orourke-98, + author = "Joseph O'Rourke", + title = "Computational Geometry in {C}, Second Edition", + publisher = cup, + year = "1998", + URL = "http://maven.smith.edu/~orourke/books/compgeom.html", +} + +@InProceedings{otoole-gifford-89, + author = "James William {O'Toole, Jr.} and David K. Gifford", + title = "Type reconstruction with first-class polymorphic + values", + booktitle = pldi, + year = "1989", + pages = "207--217", + URL = "http://www.psrg.lcs.mit.edu/history/publications/Papers/pldi89-otoole.ps", +} + +@Article{ott-10, + author = "Peter Sewell and Francesco {Zappa Nardelli} and Scott + Owens and Gilles Peskine and Thomas Ridge and Susmit + Sarkar and Rok Strnisa", + title = "{Ott}: Effective tool support for the working + semanticist", + journal = jfp, + volume = "20", + number = "1", + pages = "71--122", + year = "2010", + URL = "http://www.cl.cam.ac.uk/~pes20/ott/ott-jfp.pdf", +} + +@Article{owens-reppy-turon-09, + author = "Scott Owens and John H. Reppy and Aaron Turon", + title = "Regular-expression derivatives re-examined", + journal = jfp, + volume = "19", + number = "2", + year = "2009", + pages = "173--190", + URL = "http://www.cl.cam.ac.uk/~so294/documents/jfp09.pdf", +} + +@Article{pager-77, + author = "David Pager", + title = "A Practical General Method for Constructing ${LR}(k)$ + Parsers", + journal = acta, + year = "1977", + volume = "7", + pages = "249--268", + URL = "http://dx.doi.org/10.1007/BF00290336", +} + +@Article{paige-tarjan-87, + author = "Robert Paige and Robert E. Tarjan", + title = "Three partition refinement algorithms", + journal = siamjc, + volume = "16", + number = "6", + pages = "973--989", + year = "1987", + URL = "http://locus.siam.org/fulltext/SICOMP/volume-16/0216062.pdf", +} + +@InProceedings{pale-01, + author = "Anders M{\o}ller and Michael I. Schwartzbach", + title = "The Pointer Assertion Logic Engine", + booktitle = pldi, + year = "2001", + pages = "221--231", + URL = "http://www.brics.dk/~amoeller/papers/pale/pale.pdf", +} + +@Article{palsberg-efficient-object-95, + author = "Jens Palsberg", + title = "Efficient inference of object types", + journal = ic, + volume = "123", + number = "2", + pages = "198--209", + year = "1995", + URL = "http://www.cs.ucla.edu/~palsberg/paper/ic95-p.pdf", +} + +@Article{palsberg-okeefe-flow-95, + author = "Jens Palsberg and Patrick M. O'Keefe", + title = "A Type System Equivalent to Flow Analysis", + journal = toplas, + year = "1995", + volume = "17", + number = "4", + pages = "576--599", + URL = "http://www.cs.ucla.edu/~palsberg/paper/toplas95-po.pdf", +} + +@InProceedings{palsberg-orbaek-95, + author = "Jens Palsberg and Peter {\O}rb{\ae}k", + booktitle = sas, + title = "Trust in the {$\lambda$}-calculus", + series = "Lecture Notes in Computer Science", + volume = "983", + pages = "314--330", + year = "1995", + URL = "ftp://ftp.daimi.au.dk/pub/empl/poe/lambda-trust.dvi.gz", +} + +@Article{palsberg-orbaek-97, + title = "Trust in the {$\lambda$}-calculus", + author = "Peter {\O}rb{\ae}k and Jens Palsberg", + pages = "557--591", + journal = jfp, + year = "1997", + volume = "7", + number = "6", + URL = "http://www.cs.ucla.edu/~palsberg/paper/jfp97.pdf", +} + +@Article{palsberg-smith-96, + author = "Jens Palsberg and Scott Smith", + title = "Constrained types and their expressiveness", + journal = toplas, + volume = "18", + number = "5", + pages = "519--527", + year = "1996", + URL = "http://www.cs.ucla.edu/~palsberg/paper/toplas96-ps.pdf", +} + +@Article{palsberg-wand-okeefe-97, + title = "Type inference with non-structural subtyping", + author = "Jens Palsberg and Mitchell Wand and Patrick M. + O'Keefe", + journal = fac, + year = "1997", + pages = "49--67", + volume = "9", + URL = "http://www.cs.ucla.edu/~palsberg/paper/fac97.pdf", +} + +@Article{palsberg-zhao-01, + author = "Jens Palsberg and Tian Zhao", + title = "Efficient and Flexible Matching of Recursive Types", + journal = ic, + volume = "171", + pages = "364--387", + year = "2001", + URL = "http://www.cs.ucla.edu/~palsberg/paper/ic01.pdf", +} + +@InProceedings{palsberg-zhao-02, + author = "Jens Palsberg and Tian Zhao", + title = "Efficient Type Inference for Record Concatenation and + Subtyping", + pages = "125--136", + booktitle = lics, + year = "2002", +} + +@Article{palsberg-zhao-04, + author = "Jens Palsberg and Tian Zhao", + title = "Type Inference for Record Concatenation and + Subtyping", + journal = ic, + year = "2004", + volume = "189", + pages = "54--86", + URL = "http://www.cs.ucla.edu/~palsberg/paper/ic04.pdf", +} + +@Misc{pangolin, + author = "Yann Régis-Gianas", + title = "The {Pangolin} programming language", + note = "\url{http://code.google.com/p/pangolin-programming-language/}", + year = "2008", + URL = "http://code.google.com/p/pangolin-programming-language/", +} + +@InProceedings{parkinson-bierman-05, + author = "Matthew Parkinson and Gavin Bierman", + title = "Separation logic and abstraction", + booktitle = popl, + year = "2005", + pages = "247--258", + URL = "http://dx.doi.org/10.1145/1040305.1040326", +} + +@InProceedings{parkinson-bierman-08, + author = "Matthew Parkinson and Gavin Bierman", + title = "Separation logic, abstraction and inheritance", + booktitle = popl, + year = "2008", + pages = "75--86", + URL = "http://dx.doi.org/10.1145/1328438.1328451", +} + +@InProceedings{parnas-71, + author = "David Lorge Parnas", + title = "Information distribution aspects of design + methodology", + booktitle = "Information Processing 71", + pages = "339--344", + volume = "1", + year = "1971", + URL = "http://cseweb.ucsd.edu/~wgg/CSE218/Parnas-IFIP71-information-distribution.PDF", +} + +@Article{parnas-72, + author = "David Lorge Parnas", + title = "On the criteria to be used in decomposing systems into + modules", + journal = cacm, + volume = "15", + number = "12", + year = "1972", + pages = "1053--1058", + URL = "http://doi.acm.org/10.1145/361598.361623", +} + +@TechReport{pasalic-dali-00, + author = "Emir Pa{\v s}ali{\'c} and Tim Sheard and Walid Taha", + title = "{DALI}: An Untyped, {CBV} Functional Language + Supporting First-Order Datatypes with Binders + (Technical Development)", + institution = "Oregon Graduate Institute", + year = "2000", + number = "00-007", + URL = "http://www.cse.ogi.edu/PacSoft/publications/phaseiiiq13papers/dali.pdf", +} + +@InProceedings{pasalic-linger-04, + author = "Pa{\v s}ali{\'c} and Nathan Linger", + title = "Meta-programming with Typed Object-Language + Representations", + booktitle = gpce, + pages = "136--167", + year = "2004", + URL = "http://web.cecs.pdx.edu/~sheard/papers/MetaProgTypObjLangReps.ps", +} + +@InProceedings{pasalic-tagless-02, + author = "Emir Pa{\v s}ali{\'c} and Walid Taha and Tim Sheard", + title = "Tagless staged interpreters for typed languages", + booktitle = icfp, + year = "2002", + pages = "218--229", + URL = "http://www.cs.rice.edu/~taha/teaching/02F/511/papers/pts02.pdf", +} + +@InProceedings{paterson-wegman-76, + author = "M. S. Paterson and M. N. Wegman", + title = "Linear Unification", + booktitle = "Annual {ACM} Symposium on Theory of Computing", + pages = "181--186", + year = "1976", +} + +@InProceedings{patwary-10, + author = "Md. Mostofa Ali Patwary and Jean Blair and Fredrik + Manne", + title = "Experiments on Union-Find Algorithms for the + Disjoint-Set Data Structure", + booktitle = "International Symposium on Experimental Algorithms + (SEA)", + pages = "411--423", + year = "2010", + series = lncs, + volume = "6049", + publisher = springer, + URL = "http://www.ii.uib.no/~fredrikm/fredrik/papers/SEA2010.pdf", +} + +@InProceedings{paulin-89, + author = "Christine Paulin-Mohring", + title = "Extracting ${F}_{\omega}$'s programs from proofs in + the Calculus of Constructions", + year = "1989", + booktitle = popl, + pages = "89--104", + URL = "http://doi.acm.org/10.1145/75277.75285", +} + +@TechReport{paulin-92, + author = "Christine Paulin-Mohring", + title = "Inductive Definitions in the system {Coq}: rules and + Properties", + institution = "ENS Lyon", + year = "1992", + type = "Research Report", + number = "RR1992-49", + URL = "ftp://ftp.ens-lyon.fr/pub/LIP/Rapports/RR/RR1992/RR1992-49.ps.Z", +} + +@InProceedings{pennello-86, + author = "Thomas J. Pennello", + title = "Very fast {LR} parsing", + booktitle = "Symposium on Compiler Construction", + pages = "145--151", + year = "1986", + URL = "http://doi.acm.org/10.1145/12276.13326", +} + +@Article{pessaux-leroy-00, + author = "Fran\c{c}ois Pessaux and Xavier Leroy", + title = "Type-based analysis of uncaught exceptions", + journal = toplas, + pages = "340--377", + volume = "22", + number = "2", + year = "2000", + URL = "http://gallium.inria.fr/~xleroy/publi/exceptions-toplas.ps.gz", +} + +@InProceedings{peterson-jones-93, + author = "John Peterson and Mark P. Jones", + title = "Implementing Type Classes", + booktitle = pldi, + pages = "227--236", + year = "1993", + URL = "http://web.cecs.pdx.edu/~mpj/pubs/pldi93.ps", +} + +@Book{peyton-jones-ifl-87, + author = "Simon {Peyton Jones}", + title = "The Implementation of Functional Programming + Languages", + publisher = prentice, + year = "1987", + URL = "http://research.microsoft.com/Users/simonpj/papers/slpj-book-1987/", +} + +@Article{peyton-jones-marlow-ghc-inliner-02, + author = "Simon {Peyton Jones} and Simon Marlow", + title = "Secrets of the {Glasgow Haskell Compiler} inliner", + journal = jfp, + volume = "12", + number = "4{\&}5", + pages = "393--433", + year = "2002", + URL = "http://research.microsoft.com/en-us/um/people/simonpj/Papers/inlining/inline-jfp.ps.gz", +} + +@Article{peyton-jones-rank-07, + author = "Simon {Peyton Jones} and Dimitrios Vytiniotis and + Stephanie Weirich and Mark Shields", + title = "Practical type inference for arbitrary-rank types", + journal = jfp, + volume = "17", + number = "1", + pages = "1--82", + year = "2007", + URL = "http://research.microsoft.com/en-us/um/people/simonpj/papers/higher-rank/putting.pdf", +} + +@Unpublished{peyton-jones-shields-04, + author = "Simon {Peyton Jones} and Mark Shields", + title = "Lexically-Scoped Type Variables", + year = "2004", + note = "Manuscript", + URL = "http://www.cse.ogi.edu/~mbs/pub/scoped/", +} + +@InProceedings{peyton-jones-simple-gadts-06, + author = "Simon {Peyton Jones} and Dimitrios Vytiniotis and + Stephanie Weirich and Geoffrey Washburn", + title = "Simple unification-based type inference for {GADTs}", + booktitle = icfp, + year = "2006", + pages = "50--61", + URL = "https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/gadt-pldi.pdf", +} + +@Misc{peyton-jones-tackling-09, + author = "Simon {Peyton Jones}", + title = "Tackling the Awkward Squad: monadic input/output, + concurrency, exceptions, and foreign-language calls in + {Haskell}", + howpublished = "Online lecture notes", + year = "2009", + URL = "http://research.microsoft.com/en-us/um/people/simonpj/papers/marktoberdorf/mark.pdf", +} + +@InProceedings{peyton-jones-wadler-93, + author = "Simon {Peyton Jones} and Philip Wadler", + title = "Imperative functional programming", + booktitle = popl, + year = "1993", + pages = "71--84", + URL = "http://homepages.inf.ed.ac.uk/wadler/papers/imperative/imperative.ps.gz", +} + +@TechReport{peyton-jones-wobbly-04, + author = "Simon {Peyton Jones} and Geoffrey Washburn and + Stephanie Weirich", + title = "Wobbly types: type inference for generalised algebraic + data types", + institution = "University of Pennsylvania", + year = "2004", + number = "MS-CIS-05-26", + URL = "http://www.cis.upenn.edu/~geoffw/research/papers/MS-CIS-05-26.pdf", +} + +@InProceedings{pfenning-elliott-88, + author = "Frank Pfenning and Conal Elliott", + title = "Higher-Order Abstract Syntax", + pages = "199--208", + booktitle = pldi, + year = "1988", + URL = "http://doi.acm.org/10.1145/53990.54010", +} + +@InProceedings{pfenning-lee-89, + author = "Frank Pfenning and Peter Lee", + title = "{LEAP}: {A} Language with Eval And Polymorphism", + booktitle = tapsoft, + year = "1989", + publisher = springer, + series = lncs, + volume = "352", + pages = "345--359", + URL = "http://dx.doi.org/10.1007/3-540-50940-2_46", +} + +@InProceedings{pientka-08, + author = "Brigitte Pientka", + title = "A type-theoretic foundation for programming with + higher-order abstract syntax and first-class + substitutions", + booktitle = popl, + year = "2008", + pages = "371--382", + URL = "http://www.cs.mcgill.ca/~bpientka/papers/hoasfun-short.pdf", +} + +@InProceedings{pientka-dunfield-08, + author = "Brigitte Pientka and Joshua Dunfield", + title = "Programming with Proofs and Explicit Contexts", + booktitle = ppdp, + pages = "163--173", + year = "2008", + URL = "http://www.cs.mcgill.ca/~bpientka/papers/ppdp-pientka.pdf", +} + +@InProceedings{pientka-pearl-07, + author = "Brigitte Pientka", + title = "Proof Pearl: The power of higher-order encodings in + the logical framework {LF}", + booktitle = tphol, + pages = "246--261", + year = "2007", + volume = "4732", + series = lncs, + publisher = springer, + URL = "http://www.cs.mcgill.ca/~bpientka/papers/pearl.pdf", +} + +@InProceedings{pierce-sangiorgi-93, + author = "Benjamin Pierce and Davide Sangiorgi", + title = "Typing and Subtyping for Mobile Processes", + pages = "376--385", + booktitle = lics, + year = "1993", + URL = "http://www.cis.upenn.edu/~bcpierce/papers/pi-lics.ps", +} + +@Book{pierce-tapl, + author = "Benjamin C. Pierce", + title = "Types and Programming Languages", + publisher = mitp, + year = "2002", + URL = "http://www.cis.upenn.edu/~bcpierce/tapl/", +} + +@Article{pierce-turner-00, + author = "Benjamin C. Pierce and David N. Turner", + title = "Local Type Inference", + journal = toplas, + year = "2000", + volume = "22", + number = "1", + pages = "1--44", + URL = "http://doi.acm.org/10.1145/345099.345100", +} + +@TechReport{pierce-turner-92, + author = "Benjamin C. Pierce and David N. Turner", + title = "Statically Typed Friendly Functions via Partially + Abstract Types", + institution = "University of Edinburgh, LFCS", + type = "Technical Report", + number = "ECS-LFCS-93-256", + year = "1993", + note = "Also available as INRIA Research Report 1899", + URL = "http://www.cis.upenn.edu/~bcpierce/papers/friendly.ps", +} + +@Article{pierce-turner-94, + author = "Benjamin C. Pierce and David N. Turner", + title = "Simple Type-Theoretic Foundations for Object-Oriented + Programming", + journal = jfp, + volume = "4", + number = "2", + pages = "207--247", + year = "1994", + URL = "http://www.cis.upenn.edu/~bcpierce/papers/oop.ps", +} + +@Article{pierce-undecidable-92, + author = "Benjamin C. Pierce", + title = "Bounded Quantification is Undecidable", + journal = ic, + year = "1994", + volume = "112", + number = "1", + pages = "131--165", + URL = "http://www.cis.upenn.edu/~bcpierce/papers/fsubpopl.ps", +} + +@InProceedings{pilkiewicz-pottier-monotonicity-11, + author = "Alexandre Pilkiewicz and François Pottier", + title = "The essence of monotonic state", + booktitle = tldi, + year = "2011", + URL = "http://gallium.inria.fr/~fpottier/publis/pilkiewicz-pottier-monotonicity.pdf", +} + +@InProceedings{piskac-13, + author = "Ruzica Piskac and Thomas Wies and Damien Zufferey", + title = "Automating Separation Logic Using {SMT}", + booktitle = cav, + pages = "773--789", + year = "2013", + series = lncs, + volume = "8044", + publisher = springer, + URL = "https://www.mpi-sws.org/~piskac/publications/PiskacWiesZuffrey13SepLog.pdf", +} + +@InProceedings{piskac-14, + author = "Ruzica Piskac and Thomas Wies and Damien Zufferey", + title = "Automating Separation Logic with Trees and Data", + booktitle = cav, + pages = "711--728", + year = "2014", + series = lncs, + volume = "8559", + publisher = springer, + URL = "http://cs.nyu.edu/wies/publ/automating_separation_logic_with_trees_and_data.pdf", +} + +@Article{pitts-03, + author = "Andrew M. Pitts", + title = "Nominal Logic, {A} First Order Theory of Names and + Binding", + journal = ic, + year = "2003", + volume = "186", + pages = "165--193", + URL = "http://www.cl.cam.ac.uk/~amp12/papers/nomlfo/nomlfo-jv.pdf", +} + +@InProceedings{pitts-05, + author = "Andrew M. Pitts", + title = "Alpha-Structural Recursion and Induction", + booktitle = tphol, + year = "2005", + series = lncs, + publisher = springer, + URL = "http://www.cl.cam.ac.uk/~amp12/papers/alpsri/alpsri-ea.pdf", +} + +@Article{pitts-06, + author = "Andrew M. Pitts", + title = "Alpha-Structural Recursion and Induction", + journal = jacm, + year = "2006", + volume = "53", + pages = "459--506", + URL = "http://www.cl.cam.ac.uk/~amp12/papers/alpsri/alpsri.pdf", +} + +@InProceedings{pitts-10, + author = "Andrew M. Pitts", + title = "Nominal {System} ${T}$", + booktitle = popl, + pages = "159--170", + year = "2010", + URL = "http://www.cl.cam.ac.uk/~amp12/papers/nomst/nomst-popl.pdf", +} + +@InProceedings{pitts-gabbay-00, + author = "Andrew M. Pitts and Murdoch J. Gabbay", + title = "A Metalanguage for Programming with Bound Names Modulo + Renaming", + booktitle = mpc, + pages = "230--255", + year = "2000", + volume = "1837", + series = lncs, + publisher = springer, + URL = "http://www.cl.cam.ac.uk/~amp12/papers/metpbn/metpbn.pdf", +} + +@Article{pitts-parametric-00, + author = "Andrew M. Pitts", + title = "Parametric Polymorphism and Operational Equivalence", + journal = mscs, + year = "2000", + volume = "10", + pages = "321--359", + URL = "http://www.cl.cam.ac.uk/~amp12/papers/parpoe/parpoe.pdf", +} + +@InProceedings{plaid-permissions-11, + author = "Jonathan Aldrich and Ronald Garcia and Mark Hahnenberg + and Manuel Mohr and Karl Naden and Darpan Saini and + Sven Stork and Joshua Sunshine and {\'E}ric Tanter and + Roger Wolff", + title = "Permission-based programming languages", + booktitle = icse, + year = "2011", + pages = "828--831", + URL = "http://www.cs.cmu.edu/~aldrich/papers/plaid-NIER2010.pdf", +} + +@Article{plotkin-75, + author = "Gordon D. Plotkin", + title = "Call-by-name, call-by-value and the + $\lambda$-calculus", + journal = tcs, + volume = "1", + number = "2", + pages = "125--159", + year = "1975", + URL = "http://homepages.inf.ed.ac.uk/gdp/publications/cbn_cbv_lambda.pdf", +} + +@InCollection{plotkin-90, + author = "Gordon Plotkin", + title = "An illative theory of relations", + booktitle = "Situation Theory and its Applications", + pages = "133--146", + publisher = "Stanford University", + year = "1990", + number = "22", + series = "CSLI Lecture Notes", + URL = "http://homepages.inf.ed.ac.uk/gdp/publications/illative.pdf", +} + +@Article{plotkin-lcf-77, + author = "Gordon D. Plotkin", + title = "{LCF} Considered as a Programming Language", + journal = tcs, + volume = "5", + number = "3", + year = "1977", + pages = "225--255", + URL = "http://homepages.inf.ed.ac.uk/gdp/publications/LCF.pdf", +} + +@InCollection{plural-11, + author = "Kevin Bierhoff and Nels E. Beckman and Jonathan + Aldrich", + title = "Checking Concurrent Typestate with Access Permissions + in {Plural}: {A} Retrospective", + booktitle = "Engineering of Software", + pages = "35--48", + publisher = springer, + year = "2011", + editor = "Peri L. Tarr and Alexander L. Wolf", + URL = "http://www.cs.cmu.edu/~aldrich/papers/bierhoff-plural-festschrift11.pdf", +} + +@InProceedings{polikarpova-15, + author = "Nadia Polikarpova and Julian Tschannen and Carlo A. + Furia", + title = "A Fully Verified Container Library", + booktitle = fm, + pages = "414--434", + year = "2015", + series = lncs, + volume = "9109", + publisher = springer, + URL = "http://se.inf.ethz.ch/people/tschannen/publications/ptf-fm15.pdf", +} + +@Article{pollack-sato-ricciotti-11, + author = "Randy Pollack and Masahiko Sato and Wilmer Ricciotti", + title = "A Canonical Locally Named Representation of Binding", + year = "2012", + journal = jar, + volume = "49", + number = "2", + pages = "185--207", + URL = "http://homepages.inf.ed.ac.uk/rpollack/export/PollackSatoRicciottiJAR.pdf", +} + +@InProceedings{poplmark, + author = "Brian E. Aydemir and Aaron Bohannon and Matthew + Fairbairn and J. Nathan Foster and Benjamin C. Pierce + and Peter Sewell and Dimitrios Vytiniotis and Geoffrey + Washburn and Stephanie Weirich and Steve Zdancewic", + title = "Mechanized Metatheory for the Masses: The + \textsc{PoplMark} Challenge", + booktitle = tphol, + year = "2005", + series = lncs, + volume = "3603", + pages = "50--65", + publisher = springer, + URL = "http://research.microsoft.com/en-us/people/dimitris/poplmark.pdf", +} + +@Misc{popuri-bison-06, + author = "Satya Kiran Popuri", + title = "Understanding {C} parsers generated by {GNU Bison}", + year = "2006", + URL = "http://www.cs.uic.edu/~spopuri/cparser.html", +} + +@InCollection{potanin-13, + author = "Alex Potanin and Johan {\"{O}}stlund and Yoav Zibin + and Michael D. Ernst", + title = "Immutability", + booktitle = "Aliasing in Object-Oriented Programming. Types, + Analysis and Verification", + pages = "233--269", + year = "2013", + series = lncs, + volume = "7850", + publisher = springer, + URL = "https://homes.cs.washington.edu/~mernst/pubs/immutability-aliasing-2013-lncs7850.pdf", +} + +@InProceedings{pottier-alphacaml, + author = "François Pottier", + title = "An overview of {C$\alpha$ml}", + year = "2006", + booktitle = "ACM Workshop on ML", + pages = "27--52", + volume = "148", + number = "2", + series = entcs, + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-alphacaml.pdf", +} + +@Misc{pottier-alphacaml-software, + author = "François Pottier", + title = "{C$\alpha$ml}", + year = "2005", + URL = "http://gallium.inria.fr/~fpottier/alphaCaml/", +} + +@InProceedings{pottier-antiframe-08, + author = "François Pottier", + title = "Hiding local state in direct style: a higher-order + anti-frame rule", + year = "2008", + booktitle = lics, + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-antiframe-2008.pdf", + pages = "331--340", +} + +@Unpublished{pottier-caf, + author = "François Pottier", + title = "Three comments on the anti-frame rule", + note = "Unpublished", + year = "2009", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-caf-2009.pdf", +} + +@InProceedings{pottier-conchon-icfp-00, + author = "François Pottier and Sylvain Conchon", + title = "Information Flow Inference for Free", + booktitle = icfp, + year = "2000", + pages = "46--57", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-conchon-icfp00.ps.gz", +} + +@InProceedings{pottier-cpp-17, + author = "François Pottier", + title = "Verifying a hash table and its iterators in + higher-order separation logic", + booktitle = cpp, + year = "2017", + pages = "3--16", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-hashtable.pdf", +} + +@InProceedings{pottier-csfw-02, + author = "François Pottier", + title = "A Simple View of Type-Secure Information Flow in the + $\pi$-Calculus", + year = "2002", + booktitle = csfw, + pages = "320--330", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-csfw15.ps.gz", +} + +@TechReport{pottier-dea-95, + author = "François Pottier", + title = "Implémentation d'un système de modules évolué en + {Caml-Light}", + institution = "INRIA", + number = "2449", + type = "Research Report", + year = "1995", + URL = "http://gallium.inria.fr/~fpottier/publis/memoire-dea.ps.gz", +} + +@Unpublished{pottier-dfs-scc-15, + author = "François Pottier", + title = "Depth-First Search and Strong Connectivity in {Coq}", + year = "2014", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-dfs-scc.pdf", + note = "Submitted for publication", +} + +@InProceedings{pottier-esop-00, + author = "François Pottier", + title = "A 3-part type inference engine", + booktitle = esop, + publisher = springer, + series = lncs, + volume = "1782", + pages = "320--335", + year = "2000", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-esop-2000.ps.gz", +} + +@Unpublished{pottier-gaf, + author = "François Pottier", + title = "Generalizing the higher-order frame and anti-frame + rules", + note = "Unpublished", + year = "2009", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-gaf-2009.pdf", +} + +@InProceedings{pottier-gauthier-04, + author = "François Pottier and Nadji Gauthier", + title = "Polymorphic Typed Defunctionalization", + booktitle = popl, + year = "2004", + pages = "89--98", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-gauthier-popl04.pdf", +} + +@Article{pottier-gauthier-hosc, + author = "François Pottier and Nadji Gauthier", + title = "Polymorphic Typed Defunctionalization and + Concretization", + journal = hosc, + year = "2006", + volume = "19", + pages = "125--162", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-gauthier-hosc.pdf", +} + +@InProceedings{pottier-gdr-95, + author = "François Pottier", + title = "Type inference and simplification for recursively + constrained types", + booktitle = "Actes du {GDR} Programmation 1995 (journée du pôle + Programmation Fonctionnelle)", + year = "1995", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-gdr-95.ps.gz", +} + +@TechReport{pottier-hmx-01, + author = "François Pottier", + title = "A semi-syntactic soundness proof for {HM$(X)$}", + institution = "INRIA", + number = "4150", + type = "Research Report", + year = "2001", + URL = "http://hal.inria.fr/docs/00/07/24/75/PDF/RR-4150.pdf", +} + +@Article{pottier-ic-01, + author = "François Pottier", + title = "Simplifying subtyping constraints: a theory", + journal = ic, + year = "2001", + volume = "170", + number = "2", + pages = "153--183", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-ic01.ps.gz", +} + +@InProceedings{pottier-icfp-96, + author = "François Pottier", + title = "Simplifying subtyping constraints", + booktitle = icfp, + year = "1996", + pages = "122--133", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-icfp96.ps.gz", +} + +@InProceedings{pottier-icfp-98, + author = "François Pottier", + title = "A Framework for Type Inference with Subtyping", + booktitle = icfp, + year = "1998", + pages = "228--238", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-icfp98.ps.gz", +} + +@InProceedings{pottier-lics-03, + author = "François Pottier", + title = "A Constraint-Based Presentation and Generalization of + Rows", + year = "2003", + booktitle = lics, + pages = "331--340", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-lics03.ps.gz", +} + +@InProceedings{pottier-lics-07, + author = "François Pottier", + title = "Static name control for {FreshML}", + booktitle = lics, + year = "2007", + pages = "356--365", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-pure-freshml.pdf", +} + +@Article{pottier-njc-00, + author = "François Pottier", + title = "A Versatile Constraint-Based Type Inference System", + journal = njc, + year = "2000", + volume = "7", + number = "4", + pages = "312--347", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-njc-2000.ps.gz", +} + +@Misc{pottier-notes-dea, + author = "Xavier Leroy and François Pottier", + title = "Notes du cours de {DEA} «~Typage et + programmation~»", + year = "2002", + URL = "http://gallium.inria.fr/~fpottier/dea/dea-typage.ps.gz", +} + +@TechReport{pottier-phd-english-98, + author = "François Pottier", + title = "Type inference in the presence of subtyping: from + theory to practice", + institution = "INRIA", + number = "3483", + type = "Research Report", + year = "1998", + URL = "http://hal.inria.fr/docs/00/07/32/05/PDF/RR-3483.pdf", +} + +@PhdThesis{pottier-phd-french-98, + author = "François Pottier", + title = "Synthèse de types en présence de sous-typage: de la + théorie à la pratique", + school = "Université Paris 7", + year = "1998", + URL = "http://gallium.inria.fr/~fpottier/publis/these-fpottier.ps.gz", +} + +@InProceedings{pottier-protzenko-13, + author = "François Pottier and Jonathan Protzenko", + title = "Programming with permissions in {Mezzo}", + booktitle = icfp, + year = "2013", + pages = "173--184", + URL = "http://gallium.inria.fr/~fpottier/publis/pottier-protzenko-mezzo.pdf", +} + +@InProceedings{pottier-protzenko-lessons-mezzo-15, + author = "François Pottier and Jonathan Protzenko", + title = "A few lessons from the {Mezzo} project", + booktitle = snapl, + year = "2015", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-protzenko-lessons-mezzo.pdf", +} + +@InProceedings{pottier-reachability-cc-2016, + author = "François Pottier", + title = "Reachability and error diagnosis in {LR}(1) parsers", + booktitle = cc, + year = "2016", + pages = "88--98", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-reachability-cc2016.pdf", +} + +@InProceedings{pottier-reachability-jfla-2016, + author = "François Pottier", + title = "Reachability and error diagnosis in {LR}(1) automata", + booktitle = jfla, + year = "2016", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-reachability-jfla2016.pdf", +} + +@InProceedings{pottier-regis-gianas-06, + author = "François Pottier and Yann Régis-Gianas", + title = "Stratified type inference for generalized algebraic + data types", + booktitle = popl, + year = "2006", + pages = "232--244", + URL = "http://gallium.inria.fr/~fpottier/publis/pottier-regis-gianas-popl06.pdf", +} + +@Article{pottier-regis-gianas-typed-lr, + author = "François Pottier and Yann {Régis-Gianas}", + title = "Towards efficient, typed {LR} parsers", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-regis-gianas-typed-lr.pdf", + year = "2006", + pages = "155--180", + journal = entcs, + volume = "148", + number = "2", +} + +@InCollection{pottier-remy-emlti, + author = "François Pottier and Didier Rémy", + title = "The Essence of {ML} Type Inference", + booktitle = "Advanced Topics in Types and Programming Languages", + pages = "389--489", + publisher = mitp, + year = "2005", + editor = "Benjamin C. Pierce", + chapter = "10", + URL = "http://gallium.inria.fr/~fpottier/publis/emlti-final.pdf", +} + +@Unpublished{pottier-remy-emlti-long, + author = "François Pottier and Didier Rémy", + title = "The Essence of {ML} Type Inference", + note = "Draft of an extended version. Unpublished", + year = "2003", + URL = "http://cristal.inria.fr/attapl/emlti-long.pdf", +} + +@InProceedings{pottier-simonet-02, + author = "François Pottier and Vincent Simonet", + title = "Information Flow Inference for {ML}", + booktitle = popl, + year = "2002", + pages = "319--330", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-simonet-popl02.ps.gz", +} + +@Article{pottier-simonet-toplas-03, + author = "François Pottier and Vincent Simonet", + title = "Information Flow Inference for {ML}", + year = "2003", + volume = "25", + number = "1", + pages = "117--158", + journal = toplas, + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-simonet-toplas.ps.gz", +} + +@InProceedings{pottier-skalka-smith-01, + author = "François Pottier and Christian Skalka and Scott + Smith", + title = "A Systematic Approach to Static Access Control", + booktitle = esop, + publisher = springer, + series = lncs, + volume = "2028", + pages = "30--45", + year = "2001", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-skalka-smith-esop01.ps.gz", +} + +@Article{pottier-skalka-smith-05, + author = "François Pottier and Christian Skalka and Scott + Smith", + title = "A Systematic Approach to Static Access Control", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-skalka-smith-toplas.ps.gz", + volume = "27", + number = "2", + pages = "344--382", + journal = toplas, + year = "2005", +} + +@Article{pottier-ssphs-13, + author = "François Pottier", + title = "Syntactic soundness proof of a type-and-capability + system with hidden state", + journal = jfp, + volume = "23", + number = "1", + pages = "38--144", + year = "2013", + URL = "http://gallium.inria.fr/~fpottier/publis/fpottier-ssphs.pdf", +} + +@Misc{pottier-wallace, + author = "François Pottier", + title = "Wallace: an efficient implementation of type inference + with subtyping", + year = "2000", + URL = "http://gallium.inria.fr/~fpottier/wallace/", +} + +@InCollection{pottinger-80, + author = "Garrel Pottinger", + title = "A type assignment for the strongly normalizable + $\lambda$-terms", + booktitle = "To H. B. Curry: Essays on Combinatory Logic, Lambda + Calculus, and Formalism", + pages = "561--577", + publisher = ap, + year = "1980", + editor = "J. Roger Hindley and Jonathan P. Seldin", +} + +@InProceedings{pouillard-11, + author = "Nicolas Pouillard", + title = "Nameless, painless", + booktitle = icfp, + year = "2011", + pages = "320--332", + URL = "http://nicolaspouillard.fr/publis/nameless-painless.pdf", +} + +@InProceedings{pouillard-pottier-10, + author = "Nicolas Pouillard and François Pottier", + title = "A fresh look at programming with names and binders", + booktitle = icfp, + year = "2010", + pages = "217--228", + URL = "http://gallium.inria.fr/~fpottier/publis/pouillard-pottier-fresh-look.pdf", +} + +@Article{pouillard-pottier-12, + author = "Nicolas Pouillard and François Pottier", + title = "A unified treatment of syntax with binders", + journal = jfp, + volume = "22", + number = "4--5", + pages = "614--704", + year = "2012", + URL = "http://gallium.inria.fr/~fpottier/publis/pouillard-pottier-unified.pdf", +} + +@Article{pratt-tiuryn-96, + author = "Vaughan Pratt and Jerzy Tiuryn", + title = "Satisfiability of Inequalities in a Poset", + journal = fundamenta, + year = "1996", + volume = "28", + number = "1--2", + pages = "165--182", + URL = "ftp://ftp.mimuw.edu.pl/pub/users/tiuryn/sat-ineq.ps.gz", +} + +@Article{pretnar-15, + author = "Matija Pretnar", + title = "An Introduction to Algebraic Effects and Handlers", + journal = entcs, + volume = "319", + pages = "19--35", + year = "2015", + URL = "http://www.eff-lang.org/handlers-tutorial.pdf", +} + +@Misc{programatica-04, + author = "Thomas Hallgren and James Hook and Mark P. Jones and + Richard Kieburtz", + title = "An overview of the {Programatica} ToolSet", + howpublished = "High Confidence Software and Systems Conference + (HCSS)", + year = "2004", + URL = "http://ogi.altocumulus.org/~hallgren/Programatica/HCSS04/hcss04-tools.pdf", +} + +@Book{proofs-and-types, + author = "Jean-Yves Girard and Yves Lafont and Paul Taylor", + title = "Proofs and Types", + publisher = cup, + year = "1990", + URL = "http://www.paultaylor.eu/stable/prot.pdf", +} + +@PhdThesis{protzenko-phd-14, + author = "Jonathan Protzenko", + title = "{Mezzo}: a typed language for safe effectful + concurrent programs", + year = "2014", + school = "Université Paris Diderot", + URL = "https://hal.inria.fr/tel-01086106/document", +} + +@InProceedings{pugh-weddell-90, + author = "William Pugh and Grant Weddell", + title = "Two-directional record layout for multiple + inheritance", + booktitle = pldi, + pages = "85--91", + year = "1990", + URL = "http://doi.acm.org/10.1145/93542.93556", +} + +@Article{purdom-74, + author = "Paul Purdom", + title = "The size of {LALR(1)} parsers", + year = "1974", + journal = "BIT Numerical Mathematics", + volume = "14", + number = "3", + URL = "http://dx.doi.org/10.1007/BF01933232", + publisher = kluwer, + pages = "326--337", +} + +@Article{qian-96, + author = "Zhenyu Qian", + title = "Unification of higher-order patterns in linear time + and space", + journal = jlc, + year = "1996", + volume = "6", + number = "3", + pages = "315--341", +} + +@TechReport{raffalli-98, + author = "Christophe Raffalli", + title = "Type checking in system ${F}^\eta$", + institution = "LAMA, Université de Savoie", + year = "1998", + type = "Prépublication", + number = "98-05a", + URL = "ftp://www.lama.univ-savoie.fr/pub/users/RAFFALLI/Papers/Feta-partial.ps", +} + +@Unpublished{raffalli-99, + author = "Christophe Raffalli", + title = "An optimized complete semi-algorithm for system + ${F}^\eta$", + note = "Unpublished", + year = "1999", + URL = "ftp://www.lama.univ-savoie.fr/pub/users/RAFFALLI/Papers/Feta-total.ps", +} + +@InProceedings{ramachandran-93, + author = "Viswanath Ramachandran and Pascal Van Hentenryck", + title = "Incremental Algorithms for Constraint Solving and + Entailment over Rational Trees", + booktitle = fsttcs, + pages = "205--217", + year = "1993", +} + +@InProceedings{ramalingam-02, + author = "G. Ramalingam and Alex Varshavsky and John Field and + Deepak Goyal and Shmuel Sagiv", + title = "Deriving Specialized Program Analyses for Certifying + Component-Client Conformance", + booktitle = pldi, + pages = "83--94", + year = "2002", + URL = "http://pages.cs.wisc.edu/~ramali/Papers/pldi02.pdf", +} + +@Book{real-world-ocaml, + author = "Yaron Minsky and Anil Madhavapeddy and Jason Hickey", + title = "Real World {OCaml}: Functional programming for the + masses", + publisher = "O'Reilly", + year = "2013", + URL = "https://realworldocaml.org/", +} + +@InProceedings{recursive-alias-types-00, + author = "David Walker and Greg Morrisett", + title = "Alias Types for Recursive Data Structures", + booktitle = tic, + year = "2000", + series = lncs, + volume = "2071", + pages = "177--206", + publisher = springer, + URL = "http://www.cs.cornell.edu/talc/papers/alias-recursion.pdf", +} + +@TechReport{reed-15, + author = "Eric Reed", + title = "Patina: {A} Formalization of the {Rust} Programming + Language", + institution = "University of Washington", + year = "2015", + number = "UW-CSE-15-03-02", + URL = "ftp://ftp.cs.washington.edu/tr/2015/03/UW-CSE-15-03-02.pdf", +} + +@InProceedings{regensburger-holcf-95, + author = "Franz Regensburger", + title = "{HOLCF}: Higher Order Logic of Computable Functions", + booktitle = tphol, + year = "1995", + pages = "293--307", + publisher = springer, + series = lncs, + volume = "971", + URL = "http://www4.informatik.tu-muenchen.de/publ/papers/Regensburger_HOLT1995.pdf", +} + +@PhdThesis{regis-gianas-07, + author = "Yann Régis-Gianas", + title = "Des types aux assertions logiques : preuve automatique + ou assistée de propriétés sur les programmes + fonctionnels", + school = "Université Paris 7", + year = "2007", + URL = "http://gallium.inria.fr/~regisgia/these-yann.regis-gianas.pdf", +} + +@InProceedings{regis-gianas-pottier-08, + author = "Yann Régis-Gianas and François Pottier", + title = "A {Hoare} Logic for Call-by-Value Functional + Programs", + booktitle = mpc, + year = "2008", + series = lncs, + volume = "5133", + publisher = springer, + URL = "http://gallium.inria.fr/~fpottier/publis/regis-gianas-pottier-hoarefp.pdf", + pages = "305--335", +} + +@InProceedings{rehof-faehndrich-01, + author = "Jakob Rehof and Manuel Fähndrich", + title = "Type-Based Flow Analysis: From Polymorphic Subtyping + to {CFL}-Reachability", + booktitle = popl, + pages = "54--66", + year = "2001", + URL = "http://research.microsoft.com/~rehof/popl01.ps", +} + +@TechReport{rehof-minimality-96, + author = "Jakob Rehof", + year = "1996", + title = "Minimal Typings in Atomic Subtyping", + institution = "Department of Computer Science, University of + Copenhagen", + number = "D-278", + URL = "ftp://ftp.diku.dk/diku/semantics/papers/D-278.ps.gz", +} + +@InProceedings{rehof-minimality-97, + author = "Jakob Rehof", + title = "Minimal Typings in Atomic Subtyping", + booktitle = popl, + year = "1997", + pages = "278--291", + URL = "http://research.microsoft.com/~rehof/popl97.ps", +} + +@InProceedings{reistad-gifford-94, + author = "Brian Reistad and David K. Gifford", + title = "Static dependent costs for estimating execution time", + booktitle = lfp, + year = "1994", + pages = "65--78", + URL = "https://groups.csail.mit.edu/cgs/pubs/lfp94.pdf", +} + +@InProceedings{remy-89, + author = "Didier Rémy", + title = "Type checking records and variants in a natural + extension of {ML}", + booktitle = popl, + pages = "77--88", + year = "1989", + URL = "http://doi.acm.org/10.1145/75277.75284", +} + +@InProceedings{remy-efficient-records-92, + author = "Didier Rémy", + title = "Efficient Representation of Extensible Records", + booktitle = mlapp, + year = "1992", + URL = "http://gallium.inria.fr/~remy/ftp/eff-repr-of-ext-records.pdf", +} + +@TechReport{remy-equational-92, + author = "Didier R{\'e}my", + title = "Extending {ML} Type System with a Sorted Equational + Theory", + institution = "INRIA", + number = "1766", + year = "1992", + URL = "http://gallium.inria.fr/~remy/ftp/eq-theory-on-types.pdf", +} + +@InProceedings{remy-esop-98, + author = "Didier R{\'e}my", + title = "From Classes to Objects via Subtyping", + booktitle = esop, + year = "1998", + series = lncs, + publisher = springer, + volume = "1381", + pages = "200--220", + URL = "http://gallium.inria.fr/~remy/ftp/classes-to-objects.pdf", +} + +@InCollection{remy-for-free-94, + author = "Didier R{\'e}my", + title = "Typing Record Concatenation for Free", + booktitle = "Theoretical Aspects Of Object-Oriented Programming. + Types, Semantics and Language Design", + publisher = mitp, + year = "1994", + editor = "Carl A. Gunter and John C. Mitchell", + URL = "http://gallium.inria.fr/~remy/ftp/taoop2.pdf", +} + +@InProceedings{remy-icfp-05, + author = "Didier Rémy", + title = "Simple, partial type inference for System ${F}$ based + on type containment", + booktitle = icfp, + year = "2005", + URL = "http://gallium.inria.fr/~remy/work/fml/fml-icfp.pdf", +} + +@InProceedings{remy-icfp05, + author = "Didier Rémy", + title = "Simple, partial type inference for System ${F}$ based + on type containment", + booktitle = icfp, + year = "2005", + URL = "http://gallium.inria.fr/~remy/work/fml/fml-icfp.pdf", +} + +@InProceedings{remy-lfp-92, + author = "Didier R{\'e}my", + title = "Projective {ML}", + booktitle = lfp, + pages = "66--75", + year = "1992", + URL = "http://gallium.inria.fr/~remy/ftp/lfp92.pdf", +} + +@InProceedings{remy-mlart-94, + author = "Didier R{\'e}my", + title = "Programming Objects with {ML-ART}: An extension to + {ML} with Abstract and Record Types", + booktitle = tacs, + year = "1994", + pages = "321--346", + publisher = springer, + URL = "http://gallium.inria.fr/~remy/ftp/tacs94.pdf", +} + +@Misc{remy-newton-95, + author = "Didier R{\'e}my", + title = "A case study of typechecking with constrained types: + Typing record concatenation", + howpublished = "Workshop on Advances in Types for Computer Science", + year = "1995", + URL = "http://gallium.inria.fr/~remy/work/sub-concat.dvi.gz", +} + +@InCollection{remy-records-94, + author = "Didier R{\'e}my", + title = "Type Inference for Records in a Natural Extension of + {ML}", + booktitle = "Theoretical Aspects Of Object-Oriented Programming: + Types, Semantics and Language Design", + publisher = mitp, + year = "1994", + editor = "Carl A. Gunter and John C. Mitchell", + URL = "http://gallium.inria.fr/~remy/ftp/taoop1.pdf", +} + +@TechReport{remy-start-93, + author = "Didier R{\'e}my", + title = "Syntactic Theories and the Algebra of Record Terms", + institution = "INRIA", + number = "1869", + year = "1993", + type = "Research Report", + URL = "http://gallium.inria.fr/~remy/ftp/record-algebras.pdf", +} + +@InProceedings{remy-vouillon-objective-ml-97, + author = "Didier R{\'e}my and J{\'e}r{\^o}me Vouillon", + title = "{Objective} {ML}: {A} simple object-oriented extension + of {ML}", + booktitle = popl, + year = "1997", + pages = "40--53", + URL = "http://gallium.inria.fr/~remy/ftp/objective-ml!popl97.pdf", +} + +@Article{remy-vouillon-objective-ml-98, + author = "Didier R{\'e}my and J{\'e}r{\^o}me Vouillon", + title = "{Objective} {ML}: {An} effective object-oriented + extension to {ML}", + journal = tapos, + year = "1998", + pages = "27--50", + volume = "4", + number = "1", + URL = "http://gallium.inria.fr/~remy/ftp/objective-ml!tapos98.pdf", +} + +@Article{remy-yakobowski-11, + author = "Didier R{\'e}my and Boris Yakobowski", + title = "A {Church}-Style Intermediate Language for {MLF}", + journal = tcs, + year = "2012", + volume = "435", + number = "1", + pages = "77--105", + URL = "http://gallium.inria.fr/~remy/mlf/Remy-Yakobowski:xmlf@tcs2011.pdf", +} + +@Article{reps-98, + author = "Thomas Reps", + title = "Program analysis via graph reachability", + journal = ist, + year = "1998", + volume = "40", + number = "11--12", + pages = "701--726", + URL = "http://www.cs.wisc.edu/wpis/papers/tr1386.pdf", +} + +@PhdThesis{retert-09, + author = "William S. Retert", + title = "Implementing Permission Analysis", + school = "University of Wisconsin-Milwaukee", + year = "2009", +} + +@InProceedings{reus-schwinghammer-06, + title = "Separation Logic for Higher-order Store", + year = "2006", + author = "Bernhard Reus and Jan Schwinghammer", + booktitle = csl, + series = lncs, + volume = "4207", + publisher = springer, + pages = "575--590", + URL = "http://www.ps.uni-sb.de/Papers/abstracts/seplogic-hos.pdf", +} + +@Article{revuz-92, + author = "Dominique Revuz", + title = "Minimization of acyclic deterministic automata in + linear time", + journal = tcs, + volume = "92", + number = "1", + year = "1992", + pages = "181--189", +} + +@InProceedings{reynolds-02, + author = "John C. Reynolds", + title = "Separation Logic: {A} Logic for Shared Mutable Data + Structures", + booktitle = lics, + pages = "55--74", + year = "2002", + URL = "http://www.cs.cmu.edu/~jcr/seplogic.pdf", +} + +@InProceedings{reynolds-69, + author = "John C. Reynolds", + title = "Automatic Computation of Data Set Definitions", + booktitle = "Information Processing 68", + volume = "1", + publisher = "North Holland", + year = "1969", + pages = "456--461", +} + +@InProceedings{reynolds-74, + author = "John C. Reynolds", + title = "Towards a theory of type structure", + booktitle = "Colloque sur la Programmation", + pages = "408--425", + year = "1974", + volume = "19", + series = lncs, + publisher = springer, + URL = "http://www.springerlink.com/content/p5801737k78207p7/", +} + +@TechReport{reynolds-75, + author = "John C. Reynolds", + title = "User-defined Types and Procedural Data Structures as + Complementary Approaches to Data Abstraction", + institution = "Carnegie Mellon University", + year = "1975", + number = "1278", + URL = "http://repository.cmu.edu/compsci/1278/", +} + +@InProceedings{reynolds-78, + author = "John C. Reynolds", + title = "Syntactic control of interference", + booktitle = popl, + year = "1978", + pages = "39--46", + URL = "http://doi.acm.org/10.1145/512760.512766", +} + +@InProceedings{reynolds-83, + author = "John C. Reynolds", + title = "Types, Abstraction and Parametric Polymorphism", + booktitle = "Information Processing 83", + publisher = elsevier, + year = "1983", + pages = "513--523", + URL = "http://www.cse.chalmers.se/edu/year/2010/course/DAT140_Types/Reynolds_typesabpara.pdf", +} + +@InProceedings{reynolds-85, + author = "John C. Reynolds", + title = "Three Approaches to Type Structure", + booktitle = tapsoft, + series = lncs, + volume = "185", + publisher = springer, + year = "1985", + pages = "97--138", + URL = "http://dx.doi.org/10.1007/3-540-15198-2_7", +} + +@Article{reynolds-98a, + author = "John C. Reynolds", + title = "Definitional Interpreters for Higher-Order Programming + Languages", + journal = "Higher-Order and Symbolic Computation", + volume = "11", + number = "4", + pages = "363--397", + year = "1998", + URL = "https://cs.au.dk/~hosc/local/HOSC-11-4-pp363-397.pdf", +} + +@Article{reynolds-98b, + author = "John C. Reynolds", + title = "Definitional Interpreters Revisited", + journal = "Higher-Order and Symbolic Computation", + volume = "11", + number = "4", + pages = "355--361", + year = "1998", + URL = "https://cs.au.dk/~hosc/local/HOSC-11-4-pp355-361.pdf", +} + +@InCollection{reynolds-abstraction-94, + author = "John C. Reynolds", + title = "User Defined Types and Procedural Data Structures as + Complementary Approaches to Data Abstraction", + booktitle = taoop, + publisher = mitp, + year = "1994", + pages = "13--23", + editor = "Carl A. Gunter and John C. Mitchell", +} + +@InCollection{reynolds-intro-90, + author = "John C. Reynolds", + title = "An Introduction to the Polymorphic Lambda Calculus", + booktitle = "Logical Foundations of Functional Programming", + editor = "G{\'e}rard Huet", + publisher = aw, + year = "1990", + pages = "77--86", + URL = "http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.7.9916", +} + +@Article{rhiger-03, + author = "Morten Rhiger", + title = "A Foundation for Embedded Languages", + journal = toplas, + year = "2003", + volume = "25", + number = "3", + pages = "291--315", + URL = "http://doi.acm.org/10.1145/641909.641910", +} + +@InProceedings{riba-09, + author = "Colin Riba", + title = "On the Values of Reducibility Candidates", + booktitle = tlca, + year = "2009", + pages = "264--278", + publisher = springer, + series = lncs, + volume = "5608", + URL = "http://perso.ens-lyon.fr/colin.riba/papers/values.pdf", +} + +@InProceedings{ringenburg-grossman-05, + author = "Michael F. Ringenburg and Dan Grossman", + title = "Types for Describing Coordinated Data Structures", + booktitle = tldi, + pages = "25--36", + year = "2005", + URL = "http://www.cs.washington.edu/homes/miker/coord/coordinated_tldi05.pdf", +} + +@Article{rittri-89, + author = "Mikael Rittri", + title = "Using types as Search Keys in Function Libraries", + journal = jfp, + volume = "1", + number = "1", + pages = "71--89", + year = "1991", +} + +@Article{rittri-93, + author = "Mikael Rittri", + title = "Retrieving library functions by unifying types modulo + linear isomorphism", + journal = rairo, + year = "1993", + volume = "27", + number = "6", + pages = "523--540", +} + +@PhdThesis{rival-hdr, + author = "Xavier Rival", + title = "Abstract Domains for the Static Analysis of Programs + Manipulating Complex Data Structures", + school = "École Normale Supérieure", + year = "2011", + type = "Habilitation à diriger des recherches", + URL = "http://www.di.ens.fr/~rival/hdr.pdf", +} + +@Article{robinson-65, + author = "J. Alan Robinson", + title = "A Machine-Oriented Logic Based on the Resolution + Principle", + journal = jacm, + year = "1965", + volume = "12", + number = "1", + pages = "23--41", + URL = "http://doi.acm.org/10.1145/321250.321253", +} + +@InProceedings{rompf-amin-16, + author = "Tiark Rompf and Nada Amin", + title = "Type soundness for dependent object types {(DOT)}", + booktitle = oopsla, + pages = "624--641", + year = "2016", + URL = "http://lampwww.epfl.ch/~amin/dot/soundness_oopsla16.pdf", +} + +@Article{ross-sagiv-98, + author = "John L. Ross and Mooly Sagiv", + title = "Building a Bridge between Pointer Aliases and Program + Dependences", + journal = njc, + volume = "5", + number = "4", + year = "1998", + mon = "Winter", + pages = "361--386", + URL = "http://www.math.tau.ac.il/~msagiv/njc98.ps", +} + +@InProceedings{rossberg-15, + author = "Andreas Rossberg", + title = "{1ML} -- core and modules united ({F}-ing first-class + modules)", + booktitle = icfp, + pages = "35--47", + year = "2015", + URL = "https://people.mpi-sws.org/~rossberg/papers/Rossberg%20-%201ML%20--%20Core%20and%20modules%20united.pdf", +} + +@Article{rossberg-russo-dreyer-14, + author = "Andreas Rossberg and Claudio V. Russo and Derek + Dreyer", + title = "{F}-ing modules", + journal = jfp, + volume = "24", + number = "5", + pages = "529--607", + year = "2014", + URL = "https://people.mpi-sws.org/~rossberg/papers/Rossberg,%20Russo,%20Dreyer%20-%20F-ing%20Modules%20[JFP].pdf", +} + +@Article{runciman-toyn-91, + author = "Colin Runciman and Ian Toyn", + title = "Retrieving re-usable software components by + polymorphic type", + journal = jfp, + year = "1991", + pages = "191--211", + volume = "1", + number = "2", +} + +@Book{russell-norvig-09, + author = "Stuart Russell and Peter Norvig", + title = "Artificial Intelligence: {A} Modern Approach", + publisher = prentice, + year = "2009", + URL = "http://aima.cs.berkeley.edu/", +} + +@PhdThesis{russo-98, + school = "University of Edinburgh", + title = "Types For Modules", + year = "1998", + pages = "360", + author = "Claudio V. Russo", + URL = "http://www.dcs.ed.ac.uk/home/cvr/ECS-LFCS-98-389.html", +} + +@Misc{rust, + title = "The {Rust} programming language", + author = "{The Mozilla foundation}", + year = "2014", + URL = "https://doc.rust-lang.org/book/", +} + +@InProceedings{rust-14, + author = "Nicholas D. Matsakis and Felix S. {Klock,II}", + title = "The {Rust} Language", + booktitle = hilt, + year = "2014", + pages = "103--104", + URL = "http://doi.acm.org/10.1145/2663171.2663188", +} + +@Unpublished{rust-servo-15, + author = "Brian Anderson and Lars Bergstrom and David Herman and + Josh Matthews and Keegan McAllister and Manish + Goregaokar and Jack Moffitt and Simon Sapin", + title = "Experience Report: Developing the {Servo} Web Browser + Engine using {Rust}", + year = "2015", + URL = "http://arxiv.org/abs/1505.07383", +} + +@InProceedings{sabelfeld-sands-99, + author = "Andrei Sabelfeld and David Sands", + title = "A {PER} Model of Secure Information Flow in Sequential + Programs", + booktitle = esop, + volume = "1575", + series = lncs, + year = "1999", + publisher = springer, + pages = "40--58", + URL = "http://www.cse.chalmers.se/~andrei/esop99.ps", +} + +@InProceedings{sabin-freuder-94, + author = "Daniel Sabin and Eugene C. Freuder", + title = "Contradicting Conventional Wisdom in Constraint + Satisfaction", + booktitle = ppcp, + publisher = springer, + series = lncs, + volume = "874", + year = "1994", + pages = "10--20", + URL = "http://4c.ucc.ie/web/upload/publications/inProc/sabin94contradicting.pdf", +} + +@Article{sabry-98, + author = "Amr Sabry", + title = "What is a Purely Functional Language?", + journal = jfp, + year = "1998", + volume = "8", + number = "1", + pages = "1--22", + URL = "http://dx.doi.org/10.1017/S0956796897002943", +} + +@InProceedings{sage-06, + author = "Jessica Gronski and Kenneth Knowles and Aaron Tomb and + Stephen N. Freund and Cormac Flanagan", + title = "{Sage}: Hybrid Checking for Flexible Specifications", + booktitle = "Scheme and Functional Programming", + year = "2006", + pages = "93--104", + URL = "http://www.cs.williams.edu/~freund/papers/06-sfp.pdf", +} + +@TechReport{saha-al-98, + author = "Bratin Saha and Nevin Heintze and Dino Oliva", + title = "Subtransitive {CFA} using Types", + institution = "Yale University", + year = "1998", + number = "YALEU/DCS/TR-1166", + URL = "http://flint.cs.yale.edu/flint/publications/cfa.ps.gz", +} + +@InProceedings{sands-90, + author = "David Sands", + title = "Complexity Analysis for a Lazy Higher-Order Language", + booktitle = esop, + pages = "361--376", + year = "1990", + series = lncs, + volume = "432", + publisher = springer, + URL = "http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.42.9125", +} + +@InProceedings{sands-gustavsson-moran-02, + author = "David Sands and J{\"{o}}rgen Gustavsson and Andrew + Moran", + title = "Lambda Calculi and Linear Speedups", + booktitle = "The Essence of Computation, Complexity, Analysis, + Transformation. Essays Dedicated to Neil D. Jones", + pages = "60--84", + year = "2002", + volume = "2566", + publisher = springer, + series = lncs, + URL = "http://www.cse.chalmers.se/~dave/papers/Sands-Gustavsson-Moran.pdf", +} + +@Article{sangiorgi-98, + author = "Davide Sangiorgi", + title = "On the bisimulation proof method", + journal = mscs, + volume = "8", + number = "5", + pages = "447--479", + year = "1998", + URL = "http://www.cs.unibo.it/~sangio/DOC_public/bis-proof.ps.gz", +} + +@InProceedings{sansom-93, + author = "Patrick M. Sansom", + title = "Time profiling a lazy functional compiler", + booktitle = "Functional Programming, Workshops in Computing", + year = "1993", + publisher = springer, + URL = "ftp://ftp.dcs.glasgow.ac.uk/pub/glasgow-fp/authors/Patrick_Sansom/1993_profiling-compiler_GLASGOWFP.ps.gz", +} + +@Book{scala, + author = "Martin Odersky and Lex Spoon and Bill Venners", + title = "Programming in {Scala}, Third Edition: {A} + Comprehensive Step-by-step Guide", + year = "2016", + publisher = "Artima Incorporation", + URL = "http://www.artima.com/shop/programming_in_scala_3ed", +} + +@InProceedings{scala-05, + author = "Martin Odersky and Matthias Zenger", + title = "Scalable Component Abstractions", + booktitle = oopsla, + pages = "41--57", + year = "2005", + URL = "http://lamp.epfl.ch/~odersky/papers/ScalableComponent.pdf", +} + +@PhdThesis{schimpf-81, + author = "Karl Max Schimpf", + title = "Construction Methods of {LR} Parsers", + school = "University of Pennsylvania", + year = "1981", + URL = "http://repository.upenn.edu/cis_reports/725/", +} + +@Article{schneider-00, + author = "Fred B. Schneider", + title = "Enforceable security policies", + year = "2000", + journal = tissec, + volume = "3", + number = "1", + pages = "1--50", + URL = "http://www.cs.cornell.edu/fbs/publications/EnfSecPols.pdf", +} + +@Book{schneider-97, + author = "Fred B. Schneider", + title = "On Concurrent Programming", + publisher = springer, + year = "1997", +} + +@InProceedings{schroeder-mossakowski-02, + author = "Lutz Schr{\"o}der and Till Mossakowski", + title = "{HasCASL}: Towards Integrated Specification and + Development of Functional Programs", + booktitle = amast, + year = "2002", + pages = "99--116", + publisher = springer, + series = lncs, + volume = "2422", + URL = "http://www.informatik.uni-bremen.de/~lschrode/hascasl/recursion.ps", +} + +@Article{schubert-83, + author = "Lenhart K. Schubert and Mary Angela Papalaskaris and + Jay Taugher", + title = "Determining Type, Part, Color, and Time + Relationships", + journal = computer, + volume = "16", + number = "10", + pages = "53--60", + year = "1983", +} + +@TechReport{schwartzbach-95, + author = "Michael I. Schwartzbach", + title = "Polymorphic Type Inference", + institution = "BRICS", + year = "1995", + number = "BRICS-LS-95-3", + URL = "http://www.brics.dk/LS/95/3/BRICS-LS-95-3.ps.gz", +} + +@InProceedings{schwinghammer-birkedal-stovring-11, + author = "Jan Schwinghammer and Lars Birkedal and Kristian + Støvring", + title = "A step-indexed {Kripke} model of hidden state via + recursive properties on recursively defined metric + spaces", + booktitle = fossacs, + year = "2011", + number = "6604", + pages = "305--319", + series = lncs, + publisher = springer, + URL = "http://www.itu.dk/~birkedal/papers/relpoms-antiframe-conf.pdf", +} + +@InProceedings{schwinghammer-csl-09, + author = "Jan Schwinghammer and Lars Birkedal and Bernhard Reus + and Hongseok Yang", + title = "Nested {Hoare} triples and frame rules for + higher-order store", + booktitle = csl, + pages = "440--454", + year = "2009", + volume = "5771", + series = lncs, + publisher = springer, + URL = "http://www.itu.dk/~birkedal/papers/nested-triples-conf.pdf", +} + +@InProceedings{schwinghammer-sfhs-10, + author = "Jan Schwinghammer and Hongseok Yang and Lars Birkedal + and François Pottier and Bernhard Reus", + title = "A Semantic Foundation for Hidden State", + booktitle = fossacs, + year = "2010", + pages = "2--17", + publisher = springer, + series = lncs, + volume = "6014", + URL = "http://gallium.inria.fr/~fpottier/publis/sfhs.pdf", +} + +@PhdThesis{schwoon-02, + author = "Stefan Schwoon", + title = "Model-Checking Pushdown Systems", + school = "Technische Universit{\"a}t M{\"u}nchen", + year = "2002", + URL = "http://www.lsv.ens-cachan.fr/Publis/PAPERS/PDF/schwoon-phd02.pdf", +} + +@Article{scott-lcf-93, + author = "Dana S. Scott", + title = "A Type-Theoretical Alternative to {ISWIM}, {CUCH}, + {OWHY}", + journal = tcs, + volume = "121", + number = "1--2", + year = "1993", + pages = "411--440", + URL = "http://dx.doi.org/10.1016/0304-3975(93)90095-B", +} + +@Book{sedgewick-graphs-java, + author = "Robert Sedgewick and Michael Schidlowsky", + title = "Algorithms in {Java}: Graph Algorithms", + publisher = aw, + year = "2003", +} + +@Article{seidel-sharir-05, + author = "Raimund Seidel and Micha Sharir", + title = "Top-Down Analysis of Path Compression", + journal = siamjc, + volume = "34", + number = "3", + pages = "515--525", + year = "2005", + URL = "http://dx.doi.org/10.1137/S0097539703439088", +} + +@Article{sekar-al-95, + title = "Adaptive Pattern Matching", + author = "R. C. Sekar and R. Ramesh and I. V. Ramakrishnan", + pages = "1207--1234", + journal = siamjc, + year = "1995", + volume = "24", + number = "6", + URL = "http://seclab.cs.sunysb.edu/sekar/papers/adaptive.ps", + alturl = "http://locus.siam.org/fulltext/SICOMP/volume-24/0224073.pdf", +} + +@Article{sethi-ullman-70, + author = "Ravi Sethi and J. D. Ullman", + title = "The Generation of Optimal Code for Arithmetic + Expressions", + journal = jacm, + volume = "17", + number = "4", + year = "1970", + pages = "715--728", + URL = "http://doi.acm.org/10.1145/321607.321620", +} + +@InProceedings{sewell-vitek-00, + author = "Peter Sewell and Jan Vitek", + title = "Secure Composition of Untrusted Code: Wrappers and + Causality Types", + year = "2000", + booktitle = csfw, + URL = "http://www.cl.cam.ac.uk/users/pes20/wraptypes.ps", +} + +@TechReport{sewell-vitek-99, + author = "Peter Sewell and Jan Vitek", + title = "Secure Composition of Untrusted Code: Wrappers and + Causality Types", + number = "478", + institution = "Computer Laboratory, University of Cambridge", + year = "1999", + URL = "http://www.cl.cam.ac.uk/users/pes20/wraptypes-tr.ps", +} + +@Article{sha-steiglitz-93, + author = "Edwin Hsing-Mean Sha and Kenneth Steiglitz", + title = "Maintaining Bipartite Matchings in the Presence of + Failures", + journal = "Networks", + year = "1993", + volume = "23", + number = "5", + pages = "459--471", + URL = "http://www.nd.edu/~esha/papers/oldsha/alg.ps", +} + +@Article{shao-certified-05, + author = "Zhong Shao and Valery Trifonov and Bratin Saha and + Nikolaos Papaspyrou", + title = "A type system for certified binaries", + journal = toplas, + volume = "27", + number = "1", + year = "2005", + pages = "1--45", + URL = "http://flint.cs.yale.edu/flint/publications/tscb-toplas.pdf", +} + +@InProceedings{sheard-04, + author = "Tim Sheard", + title = "Languages of the Future", + booktitle = oopsla, + year = "2004", + pages = "116--119", + URL = "http://doi.acm.org/10.1145/1028664.1028711", +} + +@InProceedings{sheard-05, + author = "Tim Sheard", + title = "Putting {Curry-Howard} To Work", + booktitle = hw, + year = "2005", + pages = "74--85", + URL = "http://web.cecs.pdx.edu/~sheard/papers/PutCurryHoward2WorkFinalVersion.ps", +} + +@InProceedings{sheard-challenges-01, + author = "Tim Sheard", + title = "Accomplishments and Research Challenges in + Meta-Programming", + booktitle = saig, + pages = "2--44", + year = "2001", + volume = "2196", + series = lncs, + publisher = springer, + URL = "http://www.cse.ogi.edu/PacSoft/publications/2001/challeges_sheard.pdf", +} + +@InProceedings{sheard-metaml-98, + author = "Tim Sheard", + title = "Using {MetaML}: {A} staged Programming Language", + booktitle = afp, + pages = "207--239", + year = "1998", + volume = "1608", + series = lncs, + publisher = springer, + URL = "http://web.cecs.pdx.edu/~sheard/papers/summerschool.ps", +} + +@InProceedings{sheard-pasalic-04, + author = "Tim Sheard and Emir Pa{\v s}ali{\'c}", + title = "Meta-Programming with Built-in Type Equality", + booktitle = lfm, + year = "2004", + URL = "http://cs-www.cs.yale.edu/homes/carsten/lfm04/proceedings/pasalic.pdf", +} + +@InProceedings{shields-peyton-jones-02, + author = "Mark B. Shields and Simon {Peyton Jones}", + title = "First class modules for {Haskell}", + booktitle = fool, + year = "2002", + pages = "28--40", + URL = "http://www.cse.ogi.edu/~mbs/pub/first_class_modules/first_class_modules.pdf", +} + +@InProceedings{shinwell-03, + author = "Mark R. Shinwell and Andrew M. Pitts and Murdoch J. + Gabbay", + title = "{FreshML}: Programming with Binders Made Simple", + booktitle = icfp, + pages = "263--274", + year = "2003", + URL = "http://www.cl.cam.ac.uk/~amp12/papers/frepbm/frepbm.pdf", +} + +@Article{shinwell-05, + author = "Mark R. Shinwell", + title = "{Fresh O'Caml}: nominal abstract syntax for the + masses", + journal = entcs, + year = "2006", + volume = "148", + number = "2", + pages = "53--77", + URL = "http://dx.doi.org/10.1016/j.entcs.2005.11.040", +} + +@PhdThesis{shinwell-phd, + author = "Mark R. Shinwell", + title = "The Fresh Approach: functional programming with names + and binders", + school = "University of Cambridge", + year = "2005", + URL = "http://www.cl.cam.ac.uk/users/mrs30/papers/thesis.pdf", +} + +@Article{shinwell-pitts-05, + author = "Mark R. Shinwell and Andrew M. Pitts", + title = "On a Monadic Semantics for Freshness", + journal = tcs, + year = "2005", + volume = "342", + pages = "28--55", + URL = "http://www.cl.cam.ac.uk/users/amp12/papers/monsf/monsf-jv.pdf", +} + +@InProceedings{shivers-96, + author = "Olin Shivers", + title = "A universal scripting framework or, {Lambda}: the + ultimate ``little language''", + booktitle = "Concurrency and Parallelism: Programming, Networking + and Security", + pages = "254--265", + year = "1996", + volume = "1179", + series = lncs, + publisher = springer, + URL = "http://www.ai.mit.edu/people/shivers/ll.ps", +} + +@Article{sikmhs-12, + author = "Jan Schwinghammer and Lars Birkedal and François + Pottier and Bernhard Reus and Kristian St{\o}vring and + Hongseok Yang", + title = "A step-indexed {Kripke} Model of Hidden State", + journal = mscs, + note = "To appear", + year = "2012", + URL = "http://gallium.inria.fr/~fpottier/publis/sikmhs.pdf", +} + +@InProceedings{simonet-02, + author = "Vincent Simonet", + title = "Fine-grained Information Flow Analysis for a + $\lambda$-calculus with Sum Types", + booktitle = csfw, + pages = "223--237", + year = "2002", + URL = "http://gallium.inria.fr/~simonet/publis/simonet-csfw-02.ps.gz", +} + +@InProceedings{simonet-03, + author = "Vincent Simonet", + title = "An Extension of {HM(X)} with Bounded Existential and + Universal Data-Types", + year = "2003", + booktitle = icfp, + URL = "http://gallium.inria.fr/~simonet/publis/simonet-icfp03.ps.gz", +} + +@TechReport{simonet-flowcaml-manual, + author = "Vincent Simonet", + title = "The {Flow Caml} system: documentation and user's + manual", + institution = "INRIA", + number = "0282", + year = "2003", + URL = "http://gallium.inria.fr/~simonet/soft/flowcaml/manual/", +} + +@TechReport{simonet-pottier-hmg, + author = "Vincent Simonet and François Pottier", + title = "Constraint-Based Type Inference for Guarded Algebraic + Data Types", + year = "2005", + institution = "INRIA", + type = "Research Report", + number = "5462", + URL = "http://www.inria.fr/rrrt/rr-5462.html", +} + +@InProceedings{simonet-solver-03, + author = "Vincent Simonet", + title = "Type inference with structural subtyping: a faithful + formalization of an efficient constraint solver", + booktitle = aplas, + publisher = springer, + series = lncs, + volume = "2895", + year = "2003", + URL = "http://gallium.inria.fr/~simonet/publis/simonet-aplas03.pdf", +} + +@PhdThesis{simonet-these, + author = "Vincent Simonet", + title = "Inférence de flots d'information pour {ML}: + formalisation et implantation", + school = "Université Paris 7", + year = "2004", + URL = "http://gallium.inria.fr/~simonet/publis/simonet-these.pdf", +} + +@Article{simplify, + author = "David Detlefs and Greg Nelson and James B. Saxe", + title = "{Simplify}: a theorem prover for program checking", + journal = jacm, + volume = "52", + number = "3", + year = "2005", + pages = "365--473", + URL = "http://doi.acm.org/10.1145/1066100.1066102", +} + +@PhdThesis{skalka-phd-02, + author = "Christian Skalka", + title = "Types for Programming Language-Based Security", + school = "The Johns Hopkins University", + year = "2002", + URL = "http://www.cs.uvm.edu/~skalka/skalka-pubs/skalka-phd-thesis.ps", +} + +@InProceedings{skalka-pottier-tip-02, + author = "Christian Skalka and François Pottier", + title = "Syntactic Type Soundness for {HM}{$(X)$}", + year = "2002", + booktitle = "Workshop on Types in Programming (TIP)", + series = entcs, + volume = "75", + URL = "http://gallium.inria.fr/~fpottier/publis/skalka-fpottier-tip-02.ps.gz", +} + +@InProceedings{skalka-smith-00, + author = "Christian Skalka and Scott Smith", + title = "Static Enforcement of Security with Types", + booktitle = icfp, + year = "2000", + pages = "34--45", + URL = "http://www.cs.uvm.edu/~skalka/skalka-pubs/skalka-smith-icfp00.ps", +} + +@InProceedings{smallfoot-05, + author = "Josh Berdine and Cristiano Calcagno and Peter W. + O'Hearn", + title = "Smallfoot: Modular Automatic Assertion Checking with + Separation Logic", + booktitle = fmco, + pages = "115--137", + year = "2005", + volume = "4111", + series = lncs, + publisher = springer, + URL = "http://research.microsoft.com/pubs/67598/smallfoot.pdf", +} + +@InProceedings{smans-implicit-09, + title = "Implicit Dynamic Frames: Combining Dynamic Frames and + Separation Logic", + year = "2009", + author = "Jan Smans and Bart Jacobs and Frank Piessens", + booktitle = ecoop, + pages = "148--172", + volume = "5653", + series = lncs, + publisher = springer, + URL = "http://people.cs.kuleuven.be/~jan.smans/ecoop09.pdf", +} + +@InProceedings{smetsers-94, + author = "Sjaak Smetsers and Erik Barendsen and Marko C. J. D. + van Eekelen and Marinus J. Plasmeijer", + title = "Guaranteeing Safe Destructive Updates Through a Type + System with Uniqueness Information for Graphs", + booktitle = "Dagstuhl Seminar on Graph Transformations in Computer + Science", + year = "1994", + pages = "358--379", + publisher = springer, + series = lncs, + volume = "776", + URL = "http://www.mbsd.cs.ru.nl/publications/papers/1994/smes94-guaranteeing.pdf", +} + +@InProceedings{smith-01, + author = "Geoffrey S. Smith", + title = "A New Type System for Secure Information Flow", + booktitle = csfw, + pages = "115--125", + year = "2001", + URL = "http://www.cs.fiu.edu/~smithg/papers/csfw01.pdf", +} + +@InProceedings{smith-93, + author = "Geoffrey S. Smith", + title = "Polymorphic type Inference with Overloading and + Subtyping", + booktitle = tapsoft, + series = lncs, + volume = "668", + publisher = springer, + year = "1993", + pages = "671--685", + URL = "http://dx.doi.org/10.1007/3-540-56610-4_97", +} + +@Article{smith-94, + author = "Geoffrey S. Smith", + title = "Principal Type Schemes for Functional Programs with + Overloading and Subtyping", + journal = scp, + year = "1994", + volume = "23", + number = "2--3", + pages = "197--226", + URL = "http://www.cs.fiu.edu/~smithg/papers/scp94.pdf", +} + +@PhdThesis{smith-phd-89, + author = "Scott Fraser Smith", + title = "Partial Objects in Type Theory", + school = "Cornell University", + year = "1989", + URL = "http://www.cs.jhu.edu/~scott/pll/older-papers/thesis.pdf", +} + +@InProceedings{smith-volpano-98, + title = "Secure Information Flow in a Multi-Threaded Imperative + Language", + booktitle = popl, + author = "Geoffrey Smith and Dennis Volpano", + year = "1998", + pages = "355--364", + URL = "http://www.cs.nps.navy.mil/people/faculty/volpano/papers/popl98.ps.Z", +} + +@InProceedings{smith-wang-00, + author = "Scott Smith and Tiejun Wang", + title = "Polyvariant Flow Analysis with Constrained Types", + booktitle = esop, + publisher = springer, + series = lncs, + volume = "1782", + pages = "382--396", + year = "2000", + URL = "http://link.springer.de/link/service/series/0558/papers/1782/17820382.pdf", +} + +@Book{sml-97, + author = "Robin Milner and Mads Tofte and Robert Harper and + David MacQueen", + title = "The Definition of {Standard ML} -- Revised", + publisher = mitp, + year = "1997", +} + +@Article{smolka-treinen-94, + title = "Records for Logic Programming", + year = "1994", + author = "Gert Smolka and Ralf Treinen", + volume = "18", + journal = jlp, + number = "3", + pages = "229--258", + URL = "http://www.ps.uni-sb.de/Papers/abstracts/RecordsLogProg.ps", +} + +@Article{smyth-plotkin-82, + author = "Michael B. Smyth and Gordon D. Plotkin", + title = "The Category-Theoretic Solution of Recursive Domain + Equations", + journal = siamjc, + volume = "11", + number = "4", + year = "1982", + pages = "761--783", + URL = "http://homepages.inf.ed.ac.uk/gdp/publications/Category_Theoretic_Solution.pdf", +} + +@InProceedings{snyder-86, + author = "Alan Snyder", + title = "Encapsulation and inheritance in object-oriented + programming languages", + booktitle = oopsla, + year = "1986", + pages = "38--45", + URL = "http://doi.acm.org/10.1145/28697.28702", +} + +@InProceedings{sobel-friedman-98, + author = "Jonathan Sobel and Daniel P. Friedman", + title = "Recycling continuations", + booktitle = icfp, + year = "1998", + pages = "251--260", + URL = "http://www.cs.indiana.edu/hyplan/dfried/rc.ps", +} + +@Article{soisalon-soininen-82, + author = "Eljas Soisalon-Soininen", + title = "Inessential Error Entries and Their Use in {LR} Parser + Optimization", + journal = toplas, + volume = "4", + number = "2", + year = "1982", + pages = "179--195", + URL = "http://doi.acm.org/10.1145/357162.357165", +} + +@InProceedings{solomon-78, + author = "Marvin H. Solomon", + title = "Type Definitions with Parameters", + booktitle = popl, + year = "1978", + pages = "31--38", + URL = "http://doi.acm.org/10.1145/512760.512765", +} + +@Article{soloviev-83, + author = "Sergei V. Soloviev", + title = "The category of finite sets and Cartesian Closed + Categories", + journal = "Journal of Soviet Mathematics", + year = "1983", + volume = "22", + number = "3", + pages = "1387--1400", +} + +@InProceedings{sozeau-06, + author = "Matthieu Sozeau", + title = "Subset Coercions in {Coq}", + booktitle = types, + year = "2006", + volume = "4502", + pages = "237--252", + URL = "http://www.lri.fr/~sozeau/research/russell/article.pdf", +} + +@InProceedings{sozeau-finger-07, + author = "Matthieu Sozeau", + booktitle = icfp, + pages = "13--24", + URL = "http://mattam.org/research/publications/Program-ing_Finger_Trees_in_Coq.pdf", + title = "Program-ing Finger Trees in {Coq}", + year = "2007", +} + +@Article{spec-sharp-04, + author = "Mike Barnett and Rob DeLine and Manuel Fähndrich and + K. Rustan M. Leino and Wolfram Schulte", + title = "Verification of object-oriented programs with + invariants", + journal = jot, + year = "2004", + volume = "3", + number = "6", + URL = "http://research.microsoft.com/research/pubs/view.aspx?type=article&id=1161", +} + +@Article{spivey-90, + year = "1990", + volume = "14", + title = "A Functional Theory of Exceptions", + pages = "25--42", + journal = scp, + author = "Mike Spivey", +} + +@InProceedings{stata-abadi-98, + author = "R. Stata and M. Abadi", + title = "A Type System for {Java} Bytecode Subroutines", + year = "1998", + pages = "149--160", + booktitle = popl, + URL = "http://gatekeeper.dec.com/pub/DEC/SRC/research-reports/abstracts/src-rr-158.html", +} + +@Article{steckler-wand-97, + author = "Paul A. Steckler and Mitchell Wand", + title = "Lightweight closure conversion", + journal = toplas, + volume = "19", + number = "1", + year = "1997", + pages = "48--86", + URL = "ftp://ftp.ccs.neu.edu/pub/people/wand/papers/steckler-wand-97.ps", +} + +@InProceedings{steensgaard-96, + author = "Bjarne Steensgaard", + booktitle = popl, + title = "Points-to Analysis in Almost Linear Time", + year = "1996", + pages = "32--41", + URL = "ftp://ftp.research.microsoft.com/users/rusa/popl96.ps", +} + +@InProceedings{steffen-fix-machine-95, + author = "Bernhard Steffen and Andreas Cla{\ss}en and Marion + Klein and Jens Knoop and Tiziana Margaria", + title = "The Fixpoint-Analysis Machine", + booktitle = concur, + year = "1995", + pages = "72--87", + publisher = springer, + series = lncs, + volume = "962", + URL = "http://dx.doi.org/10.1007/3-540-60218-6_6", +} + +@InProceedings{stehr-00, + author = "Mark-Oliver Stehr", + title = "{CINNI} -- {A} Generic Calculus of Explicit + Substitutions and its Application to $\lambda$-, + $\sigma$- and $\pi$-calculi", + booktitle = wrla, + year = "2000", + volume = "36", + series = entcs, + publisher = elsevier, + URL = "http://formal.cs.uiuc.edu/stehr/extcinni.ps", +} + +@InProceedings{stewart-veristar-12, + author = "Gordon Stewart and Lennart Beringer and Andrew W. + Appel", + title = "Verified heap theorem prover by paramodulation", + booktitle = icfp, + year = "2012", + pages = "3--14", + URL = "http://www.cs.princeton.edu/~appel/papers/veristar.pdf", +} + +@InProceedings{stoughton-81, + author = "Allen Stoughton", + title = "Access Flow: {A} Protection Model Which Integrates + Access Control and Information Flow", + pages = "9--18", + booktitle = sp, + year = "1981", +} + +@Article{strachey-fundamental, + author = "Christopher Strachey", + title = "Fundamental Concepts in Programming Languages", + journal = hosc, + year = "2000", + volume = "13", + number = "1--2", + pages = "11--49", + URL = "http://dx.doi.org/10.1023/A:1010000313106", +} + +@Article{strom-yemini-86, + author = "Robert E. Strom and Shaula Yemini", + title = "Typestate: {A} programming language concept for + enhancing software reliability", + journal = tose, + volume = "12", + number = "1", + year = "1986", + pages = "157--171", + URL = "http://www.cs.cmu.edu/~aldrich/papers/classic/tse12-typestate.pdf", +} + +@InProceedings{stuckey-sulzmann-02, + author = "Peter J. Stuckey and Martin Sulzmann", + title = "A Theory of Overloading", + booktitle = icfp, + pages = "167--178", + year = "2002", + URL = "http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.62.8605", +} + +@InProceedings{stuckey-sulzmann-wazny-03, + author = "Peter J. Stuckey and Martin Sulzmann and Jeremy + Wazny", + title = "Interactive type debugging in {Haskell}", + booktitle = hw, + pages = "72--83", + year = "2003", + URL = "http://www.cs.mu.oz.au/~pjs/papers/p316-stuckey.pdf", +} + +@InProceedings{su-aiken-01, + author = "Zhendong Su and Alexander Aiken", + title = "Entailment with Conditional Equality Constraints", + booktitle = esop, + year = "2001", + pages = "170--189", + series = lncs, + volume = "2028", + URL = "http://www.cs.ucdavis.edu/~su/publications/esop01.pdf", +} + +@InProceedings{su-al-02, + author = "Zhendong Su and Alexander Aiken and Joachim Niehren + and Tim Priesnitz and Ralf Treinen", + title = "The First-Order Theory of Subtyping Constraints", + booktitle = popl, + pages = "203--216", + year = "2002", + URL = "http://theory.stanford.edu/~aiken/publications/papers/popl02.pdf", +} + +@PhdThesis{sulzmann-00, + author = "Martin Sulzmann", + title = "A general framework for {Hindley/Milner} type systems + with constraints", + school = "Yale University, Department of Computer Science", + year = "2000", + URL = "http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.7.7745", +} + +@InProceedings{sulzmann-01, + author = "Martin Sulzmann", + title = "A General Type Inference Framework for + {Hindley/Milner} Style Systems", + booktitle = "International Symposium on Functional and Logic + Programming", + series = lncs, + volume = "2024", + pages = "246--263", + publisher = springer, + year = "2001", + URL = "http://link.springer.de/link/service/series/0558/papers/2024/20240248.pdf", +} + +@TechReport{sulzmann-mueller-zenger-99, + author = "Martin Sulzmann and Martin Müller and Christoph + Zenger", + title = "{Hindley/Milner} style type systems in constraint + form", + institution = "University of South Australia, School of Computer and + Information Science", + type = "Research Report", + year = "1999", + number = "ACRC--99--009", + URL = "http://www.ps.uni-sb.de/~mmueller/papers/hm-constraints.ps.gz", +} + +@InProceedings{sulzmann-odersky-wehr-97, + author = "Martin Sulzmann and Martin Odersky and Martin Wehr", + title = "Type Inference with Constrained Types", + booktitle = fool, + year = "1997", + URL = "ftp://ftp.ira.uka.de/pub/uni-karlsruhe/papers/techreports/1996/1996-28.ps.gz", +} + +@TechReport{sulzmann-records-97, + author = "Martin Sulzmann", + title = "Designing Record Systems", + institution = "Yale University", + year = "1997", + type = "Research Report", + number = "YALEU/DCS/RR-1128", + URL = "http://www.cs.mu.oz.au/~sulzmann/publications/tr-1128.ps.gz", +} + +@TechReport{sulzmann-wang-04, + author = "Martin Sulzmann and Meng Wang", + title = "A Systematic Translation of Guarded Recursive Data + Types to Existential Types", + institution = "National University of Singapore", + number = "TR22/04", + year = "2004", + ps = "http://www.cs.mu.oz.au/~sulzmann/publications/translate-grdts.ps.gz", +} + +@InProceedings{sumii-09, + author = "Eijiro Sumii", + title = "A Complete Characterization of Observational + Equivalence in Polymorphic lambda-Calculus with General + References", + booktitle = csl, + series = lncs, + publisher = springer, + volume = "5771", + pages = "455--469", + year = "2009", + URL = "http://www.kb.ecei.tohoku.ac.jp/~sumii/pub/poly-ref.pdf", +} + +@InProceedings{svendsen-birkedal-icap-14, + author = "Kasper Svendsen and Lars Birkedal", + title = "Impredicative Concurrent Abstract Predicates", + booktitle = esop, + year = "2014", + pages = "149--168", + volume = "8410", + publisher = springer, + series = lncs, + URL = "http://cs.au.dk/~birke/papers/icap-conf.pdf", +} + +@InProceedings{svendsen-birkedal-parkinson-hocap-13, + author = "Kasper Svendsen and Lars Birkedal and Matthew J. + Parkinson", + booktitle = esop, + pages = "169--188", + publisher = springer, + series = lncs, + title = "Modular Reasoning about Separation of Concurrent Data + Structures", + volume = "7792", + year = "2013", + URL = "http://cs.au.dk/~birke/papers/hocap-conf.pdf", +} + +@InProceedings{svendsen-birkedal-parkinson-joins-13, + author = "Kasper Svendsen and Lars Birkedal and Matthew J. + Parkinson", + title = "Joins: {A} Case Study in Modular Specification of a + Concurrent Reentrant Higher-Order Library", + booktitle = ecoop, + year = "2013", + pages = "327--351", + publisher = springer, + series = lncs, + volume = "7920", + URL = "http://cs.au.dk/~birke/papers/joins-conf.pdf", +} + +@Article{swamy-06, + author = "Nikhil Swamy and Michael Hicks and Greg Morrisett and + Dan Grossman and Trevor Jim", + title = "Safe Manual Memory Management in {Cyclone}", + journal = scp, + year = "2006", + volume = "62", + number = "2", + pages = "122--144", + URL = "http://www.cs.umd.edu/~mwh/papers/cyc-mm-scp.pdf", +} + +@InProceedings{swierstra-duponcheel-96, + author = "S. Doaitse Swierstra and Luc Duponcheel", + title = "Deterministic, Error-Correcting Combinator Parsers", + booktitle = "Advanced Functional Programming", + year = "1996", + publisher = "Springer", + series = "Lecture Notes in Computer Science", + volume = "1129", + pages = "184--207", + URL = "http://www.staff.science.uu.nl/~swier101/Papers/1996/DetErrCorrComPars.pdf", +} + +@InProceedings{syb, + author = "Ralf L{\"{a}}mmel and Simon {Peyton Jones}", + title = "Scrap your boilerplate: a practical design pattern for + generic programming", + booktitle = tldi, + pages = "26--37", + year = "2003", + URL = "https://www.microsoft.com/en-us/research/wp-content/uploads/2003/01/hmap.pdf", +} + +@InProceedings{syb-reloaded, + author = "Ralf Hinze and Andres L{\"{o}}h and Bruno C. d. S. + Oliveira", + title = "``Scrap Your Boilerplate'' Reloaded", + booktitle = flops, + pages = "13--29", + year = "2006", + series = lncs, + volume = "3945", + publisher = springer, + URL = "http://www.cs.ox.ac.uk/bruno.oliveira/SYB0.pdf", +} + +@InProceedings{syb-revolutions, + author = "Ralf Hinze and Andres L{\"{o}}h", + title = "``Scrap Your Boilerplate'' Revolutions", + booktitle = mpc, + pages = "180--208", + year = "2006", + series = lncs, + volume = "4014", + publisher = springer, + URL = "https://www.andres-loeh.de/SYB1.pdf", +} + +@InProceedings{syb2, + author = "Ralf L{\"{a}}mmel and Simon {Peyton Jones}", + title = "Scrap more boilerplate: reflection, zips, and + generalised casts", + booktitle = icfp, + pages = "244--255", + year = "2004", + URL = "https://doi.org/10.1145/1016848.1016883", +} + +@InProceedings{syb3, + author = "Ralf L{\"{a}}mmel and Simon {Peyton Jones}", + title = "Scrap your boilerplate with class: extensible generic + functions", + booktitle = icfp, + pages = "204--215", + year = "2005", + URL = "https://www.microsoft.com/en-us/research/wp-content/uploads/2016/07/gmap3.pdf", +} + +@PhdThesis{taha-99, + author = "Walid Taha", + title = "Multi-stage Programming: Its Theory and Applications", + school = "Oregon Graduate Institute", + year = "1999", + URL = "http://www.cs.rice.edu/~taha/publications/thesis/thesis.pdf", +} + +@InProceedings{taha-gentle-04, + author = "Walid Taha", + title = "A Gentle Introduction to Multi-stage Programming", + booktitle = dspg, + pages = "30--50", + year = "2004", + volume = "3016", + series = lncs, + publisher = springer, + URL = "http://www.cs.rice.edu/~taha/publications/journal/dspg04a.pdf", +} + +@InProceedings{taha-nielsen-03, + author = "Walid Taha and Michael Florentin Nielsen", + title = "Environment classifiers", + booktitle = popl, + year = "2003", + pages = "26--37", + URL = "http://www.cs.rice.edu/~taha/publications/conference/popl03.pdf", +} + +@Article{takahashi-95, + author = "Masako Takahashi", + title = "Parallel Reductions in $\lambda$-Calculus", + journal = ic, + year = "1995", + volume = "118", + number = "1", + pages = "120--127", + URL = "http://dx.doi.org/10.1006/inco.1995.1057", +} + +@Article{talcott-93, + author = "Carolyn Talcott", + title = "A Theory of Binding Structures and Applications to + Rewriting", + journal = tcs, + year = "1993", + volume = "112", + number = "1", + pages = "99--143", + URL = "http://dx.doi.org/10.1016/0304-3975(93)90240-T", +} + +@Article{talpin-jouvelot-94, + author = "Jean-Pierre Talpin and Pierre Jouvelot", + title = "The type and effect discipline", + journal = ic, + year = "1994", + volume = "11", + number = "2", + pages = "245--296", + URL = "http://www.irisa.fr/prive/talpin/papers/ic94.pdf", +} + +@InProceedings{tan-wusl-09, + author = "Gang Tan and Zhong Shao and Xinyu Feng and Hongxu + Cai", + title = "Weak Updates and Separation Logic", + booktitle = aplas, + pages = "178--193", + year = "2009", + volume = "5904", + series = lncs, + publisher = springer, + URL = "http://flint.cs.yale.edu/flint/publications/wusl.pdf", +} + +@Book{tapl, + author = "Benjamin C. Pierce", + title = "Types and Programming Languages", + publisher = mitp, + year = "2002", +} + +@Manual{tarditi-appel-00, + title = "{ML-Yacc} User's Manual", + author = "David R. Tarditi and Andrew W. Appel", + year = "2000", + URL = "http://www.smlnj.org/doc/ML-Yacc/", +} + +@Article{tarjan-72, + author = "Robert Tarjan", + title = "Depth-First Search and Linear Graph Algorithms", + journal = siamjc, + year = "1972", + volume = "1", + number = "2", + pages = "146--160", + URL = "http://epubs.siam.org/doi/abs/10.1137/0201010", +} + +@Article{tarjan-75, + author = "Robert Endre Tarjan", + title = "Efficiency of a Good But Not Linear Set Union + Algorithm", + journal = jacm, + year = "1975", + volume = "22", + number = "2", + pages = "215--225", + URL = "http://www.csd.uwo.ca/~eschost/Teaching/07-08/CS445a/p215-tarjan.pdf", +} + +@Article{tarjan-79, + author = "Robert Endre Tarjan", + title = "Applications of Path Compression on Balanced Trees", + journal = jacm, + year = "1979", + volume = "26", + number = "4", + pages = "690--715", + URL = "http://doi.acm.org/10.1145/322154.322161", +} + +@Unpublished{tarjan-99-notes, + title = "Class notes: Disjoint Set Union", + author = "Robert E. Tarjan", + year = "1999", + URL = "http://www.cs.princeton.edu/courses/archive/spr00/cs423/handout3.pdf", +} + +@Article{tarjan-amortized-85, + author = "Robert Endre Tarjan", + title = "Amortized Computational Complexity", + year = "1985", + journal = "SIAM Journal on Algebraic and Discrete Methods", + volume = "6", + number = "2", + pages = "306--318", + URL = "http://dx.doi.org/10.1137/0606031", +} + +@Article{tarjan-leeuwen-84, + author = "Robert E. Tarjan and Jan {van Leeuwen}", + title = "Worst-Case Analysis of Set Union Algorithms", + journal = jacm, + volume = "31", + number = "2", + pages = "245--281", + year = "1984", + URL = "http://dx.doi.org/10.1145/62.2160", +} + +@Article{tarjan-yannakakis-84, + author = "Robert E. Tarjan and Mihalis Yannakakis", + title = "Simple Linear-Time Algorithms to Test Chordality of + Graphs, Test Acyclicity of Hypergraphs, and Selectively + Reduce Acyclic Hypergraphs", + journal = siamjc, + year = "1984", + volume = "13", + number = "3", + pages = "566--579", + URL = "http://dx.doi.org/10.1137/0213035", +} + +@Article{tarjan-yao-79, + author = "Robert Endre Tarjan and Andrew Chi-Chih Yao", + title = "Storing a sparse table", + journal = cacm, + volume = "22", + number = "11", + year = "1979", + pages = "606--611", + URL = "http://doi.acm.org/10.1145/359168.359175", +} + +@InProceedings{template-haskell-02, + author = "Tim Sheard and Simon {Peyton Jones}", + title = "Template metaprogramming for {Haskell}", + booktitle = hw, + year = "2002", + pages = "1--16", + URL = "https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/meta-haskell.pdf", +} + +@Article{tennent-ghica-00, + author = "Robert D. Tennent and Dan Ghica", + title = "Abstract models of storage", + journal = hosc, + year = "2000", + volume = "13", + pages = "119--129", + URL = "http://dx.doi.org/10.1023/A:1010022312623", +} + +@InProceedings{thatte-94, + author = "Satish R. Thatt{\'e}", + title = "Automated synthesis of interface adapters for reusable + classes", + booktitle = popl, + year = "1994", + pages = "174--187", + URL = "http://doi.acm.org/10.1145/174675.177850", +} + +@InProceedings{thielecke-03, + author = "Hayo Thielecke", + title = "From control effects to typed continuation passing", + booktitle = popl, + year = "2003", + pages = "139--149", + URL = "http://www.cs.bham.ac.uk/~hxt/research/effects.pdf", +} + +@InProceedings{thielecke-06, + author = "Hayo Thielecke", + title = "Frame rules from answer types for code pointers", + booktitle = popl, + year = "2006", + pages = "309--319", + URL = "http://www.cs.bham.ac.uk/~hxt/research/popl06thielecke.pdf", +} + +@Article{thielecke-barrel-02, + author = "Hayo Thielecke", + title = "Comparing Control Constructs by Double-barrelled + {CPS}", + journal = hosc, + year = "2002", + volume = "15", + number = "2--3", + pages = "141--160", + URL = "http://www.cs.bham.ac.uk/~hxt/research/HOSC-double-barrel.pdf", +} + +@InProceedings{thiemann-01, + author = "Peter Thiemann", + title = "Enforcing Security Properties Using Type + Specialization", + booktitle = esop, + publisher = springer, + series = lncs, + year = "2001", + URL = "http://www.informatik.uni-freiburg.de/~thiemann/papers/espps-het.ps.gz", +} + +@InProceedings{thiemann-99, + author = "Peter Thiemann", + title = "{ML}-Style Typing, Lambda Lifting, and Partial + Evaluation", + booktitle = "Latin American Conference on Functional Programming", + year = "1999", + URL = "http://www.informatik.uni-freiburg.de/~thiemann/papers/clapf99.ps.gz", +} + +@InProceedings{tian-06, + author = "Ye Henry Tian", + title = "Mechanically Verifying Correctness of {CPS} + Compilation", + booktitle = "Computing: The Australasian Theory Symposium (CATS)", + pages = "41--51", + year = "2006", + URL = "http://crpit.com/confpapers/CRPITV51Tian.pdf", + series = "{CRPIT}", + volume = "51", + publisher = "Australian Computer Society", +} + +@InProceedings{tiuryn-92, + author = "Jerzy Tiuryn", + title = "Subtype inequalities", + pages = "308--317", + booktitle = lics, + year = "1992", +} + +@Article{tiuryn-urzyczyn-02, + author = "Jerzy Tiuryn and Pawel Urzyczyn", + title = "The subtyping problem for second-order types is + undecidable", + journal = ic, + volume = "179", + number = "1", + year = "2002", + pages = "1--18", + URL = "http://dx.doi.org/10.1006/inco.2001.2950", +} + +@InProceedings{tiuryn-wand-93, + author = "Jerzy Tiuryn and Mitchell Wand", + title = "Type Reconstruction with Recursive Types and Atomic + Subtyping", + pages = "686--701", + year = "1993", + booktitle = tapsoft, + series = lncs, + volume = "668", + publisher = springer, + URL = "ftp://ftp.ccs.neu.edu/pub/people/wand/papers/caap-93.dvi", +} + +@PhdThesis{tofte-88, + author = "Mads Tofte", + title = "Operational Semantics and Polymorphic Type Inference", + school = "University of Edinburgh", + year = "1988", + URL = "http://www.itu.dk/people/tofte/publ/phdthesis/thesis-part1and2.ps", +} + +@Article{tofte-retro-04, + author = "Mads Tofte and Lars Birkedal and Martin Elsman and + Niels Hallenberg", + title = "A Retrospective on Region-Based Memory Management", + journal = hosc, + year = "2004", + volume = "17", + number = "3", + pages = "245--265", + URL = "http://www.itu.dk/people/birkedal/papers/regmmp.ps.gz", +} + +@InProceedings{tofte-talpin-94, + author = "Mads Tofte and Jean-Pierre Talpin", + title = "Implementation of the Typed Call-by-Value + $\lambda$-Calculus using a Stack of Regions", + booktitle = popl, + year = "1994", + pages = "188--201", + URL = "http://www.irisa.fr/prive/talpin/papers/popl94.pdf", +} + +@Article{tofte-talpin-97, + author = "Mads Tofte and Jean-Pierre Talpin", + title = "Region-based memory management", + journal = ic, + volume = "132", + number = "2", + year = "1997", + pages = "109--176", + URL = "http://www.irisa.fr/prive/talpin/papers/ic97.pdf", +} + +@InProceedings{tolmach-97, + author = "Andrew Tolmach", + title = "Combining Closure Conversion with Closure Analysis + using Algebraic Types", + booktitle = tic, + year = "1997", + URL = "http://www.cs.pdx.edu/~apt/tic97.ps", +} + +@Article{tolmach-oliva-98, + author = "Andrew Tolmach and Dino P. Oliva", + title = "From {ML} to {Ada}: Strongly-typed Language + Interoperability via Source Translation", + journal = jfp, + year = "1998", + volume = "8", + number = "4", + pages = "367--412", + URL = "http://dx.doi.org/10.1017/S0956796898003086", +} + +@Article{topor-82, + author = "Rodney W. Topor", + title = "A Note on Error Recovery in Recursive Descent + Parsers", + journal = notices, + volume = "17", + number = "2", + year = "1982", + pages = "37--40", + URL = "http://doi.acm.org/10.1145/947902.947905", +} + +@InProceedings{tov-pucella-10, + author = "Jesse A. Tov and Riccardo Pucella", + title = "Stateful Contracts for Affine Types", + booktitle = esop, + year = "2010", + pages = "550--569", + publisher = springer, + series = lncs, + volume = "6012", + URL = "http://www.eecs.harvard.edu/~tov/pubs/affine-contracts/affinecontracts10-bw.pdf", +} + +@InProceedings{tov-pucella-11, + author = "Jesse A. Tov and Riccardo Pucella", + title = "Practical Affine Types", + booktitle = popl, + year = "2011", + pages = "447--458", + URL = "http://www.eecs.harvard.edu/~tov/pubs/alms/", +} + +@InProceedings{trifonov-smith-96, + author = "Valery Trifonov and Scott Smith", + title = "Subtyping Constrained Types", + booktitle = sas, + series = lncs, + volume = "1145", + pages = "349--365", + year = "1996", + publisher = springer, + URL = "http://flint.cs.yale.edu/trifonov/papers/subcon.pdf", +} + +@InProceedings{tschantz-ernst-05, + author = "Matthew S. Tschantz and Michael D. Ernst", + title = "Javari: adding reference immutability to {Java}", + booktitle = oopsla, + year = "2005", + pages = "211--230", + URL = "https://homes.cs.washington.edu/~mernst/pubs/ref-immutability-oopsla2005.pdf", +} + +@InProceedings{tse-zdancewic-04, + author = "Stephen Tse and Steve Zdancewic", + title = "Run-time Principals in Information-flow Type Systems", + booktitle = sp, + year = "2004", + URL = "http://www.cis.upenn.edu/~stevez/papers/TZ04a.pdf", +} + +@InProceedings{tsuiki-94, + author = "Hideki Tsuiki", + title = "On Typed Calculi with a Merge Operator", + booktitle = fsttcs, + pages = "101--112", + year = "1994", + volume = "880", + series = lncs, + publisher = springer, + URL = "http://www.i.h.kyoto-u.ac.jp/~tsuiki/papers/fsttcs.ps.gz", +} + +@Unpublished{tuerk-10, + author = "Thomas Tuerk", + title = "Local reasoning about while-loops", + year = "2010", + note = "Unpublished", + URL = "http://www.cl.cam.ac.uk/~tt291/talks/vstte10.pdf", +} + +@PhdThesis{turner-95, + author = "David N. Turner", + title = "The Polymorphic Pi-Calculus: Theory and + Implementation", + school = "University of Edinburgh", + year = "1995", + URL = "http://www.lfcs.inf.ed.ac.uk/reports/96/ECS-LFCS-96-345/", +} + +@InProceedings{turner-wadler-mossin-95, + author = "David N. Turner and Philip Wadler and Christian + Mossin", + year = "1995", + title = "Once upon a type", + booktitle = fpca, + publisher = acmp, + pages = "1--11", + URL = "ftp://ftp.dcs.gla.ac.uk/pub/glasgow-fp/authors/Philip_Wadler/once.dvi", +} + +@InProceedings{turon-caresl-13, + author = "Aaron Turon and Derek Dreyer and Lars Birkedal", + title = "Unifying refinement and {Hoare}-style reasoning in a + logic for higher-order concurrency", + booktitle = icfp, + year = "2013", + pages = "377--390", + URL = "http://www.mpi-sws.org/~turon/caresl/caresl.pdf", +} + +@Misc{unicon, + title = "Unicon", + note = "\url{http://unicon.sourceforge.net/}", + URL = "http://unicon.sourceforge.net/", +} + +@Article{urban-04, + author = "Christian Urban and Andrew Pitts and Murdoch Gabbay", + title = "Nominal Unification", + journal = tcs, + year = "2004", + URL = "http://gabbay.org.uk/papers/nomu-jv.pdf", + volume = "323", + pages = "473--497", +} + +@Article{urban-08, + author = "Christian Urban", + title = "Nominal Techniques in {Isabelle/HOL}", + journal = jar, + volume = "40", + number = "4", + pages = "327--356", + year = "2008", + URL = "https://nms.kcl.ac.uk/christian.urban/Publications/nom-tech.pdf", +} + +@Unpublished{urban-nipkow-08, + author = "Christian Urban and Tobias Nipkow", + title = "Nominal Verification of Algorithm {W}", + year = "2008", + note = "Unpublished", + URL = "http://www4.in.tum.de/~urbanc/Publications/w-07.pdf", +} + +@InProceedings{urban-tasson-05, + author = "Christian Urban and Christine Tasson", + title = "Nominal Techniques in {Isabelle/HOL}", + booktitle = cade, + year = "2005", + series = lncs, + publisher = springer, + volume = "3632", + pages = "38--53", + URL = "http://www4.in.tum.de/~urbanc/Publications/nom-cade-05.ps", +} + +@Unpublished{vacid, + author = "K. Rustan M. Leino and Michal Moskal", + title = "{VACID}-0: Verification of Ample Correctness of + Invariants of Data-structures, Edition 0", + note = "Manuscript KRML 209", + year = "2010", + URL = "http://research.microsoft.com/en-us/um/people/moskal/pdf/vacid0.pdf", +} + +@Article{vafeiadis-11, + author = "Viktor Vafeiadis", + title = "Concurrent Separation Logic and Operational + Semantics", + journal = entcs, + volume = "276", + year = "2011", + pages = "335--351", + URL = "http://www.mpi-sws.org/~viktor/papers/mfps2011-cslsound.pdf", +} + +@InProceedings{vaziri-jackson-03, + author = "Mandana Vaziri and Daniel Jackson", + title = "Checking Heap-Manipulating Procedures with a + Constraint Solver", + booktitle = tacas, + year = "2003", + publisher = springer, + series = lncs, + volume = "2619", + URL = "http://sdg.lcs.mit.edu/pubs/2003/checkingHMPs.pdf", +} + +@InProceedings{vdw-mckinna-08, + author = "Eelis {van der Weegen} and James McKinna", + title = "A Machine-Checked Proof of the Average-Case Complexity + of {Quicksort} in {Coq}", + booktitle = types, + year = "2008", + pages = "256--271", + publisher = springer, + series = lncs, + volume = "5497", + URL = "http://www.xs4all.nl/~weegen/eelis/research/quicksort/", +} + +@InProceedings{vergauwen-lewi-94, + author = "Bart Vergauwen and Johan Lewi", + title = "Efficient Local Correctness Checking for Single and + Alternating {Boolean} Equation Systems", + booktitle = icalp, + year = "1994", + pages = "304--315", + publisher = springer, + series = lncs, + volume = "820", + URL = "http://dx.doi.org/10.1007/3-540-58201-0_77", +} + +@InProceedings{vergauwen-nested-94, + author = "Bart Vergauwen and Johan Lewi and I. Avau and A. + Poté", + title = "Efficient computation of nested fix-points, with + applications to model checking", + booktitle = ictl, + pages = "165--179", + year = "1994", + volume = "827", + series = lncs, + publisher = springer, + URL = "http://dx.doi.org/10.1007/BFb0013987", +} + +@InProceedings{vergauwen-wauman-lewi-94, + author = "Bart Vergauwen and J. Wauman and Johan Lewi", + title = "Efficient fixpoint computation", + booktitle = sas, + pages = "314--328", + year = "1994", + volume = "864", + series = lncs, + publisher = springer, + URL = "http://dx.doi.org/10.1007/3-540-58485-4_49", +} + +@TechReport{verifast, + author = "Bart Jacobs and Frank Piessens", + title = "The {VeriFast} Program Verifier", + institution = "Department of Computer Science, Katholieke + Universiteit Leuven", + year = "2008", + number = "CW-520", + URL = "http://people.cs.kuleuven.be/~bart.jacobs/verifast/verifast.pdf", +} + +@InProceedings{villard-lozes-calcagno-09, + author = "Jules Villard and Étienne Lozes and Cristiano + Calcagno", + booktitle = aplas, + pages = "194--209", + publisher = springer, + series = lncs, + title = "Proving Copyless Message Passing", + URL = "http://www.lsv.ens-cachan.fr/Publis/PAPERS/PDF/VLC-aplas09.pdf", + volume = "5904", + year = "2009", +} + +@InProceedings{villard-lozes-calcagno-10, + author = "Jules Villard and Étienne Lozes and Cristiano + Calcagno", + booktitle = tacas, + pages = "275--279", + publisher = springer, + series = lncs, + title = "Tracking Heaps that Hop with {Heap-Hop}", + URL = "http://www.lsv.ens-cachan.fr/Publis/PAPERS/PDF/VLC-tacas10.pdf", + volume = "6015", + year = "2010", +} + +@Article{vitek-bokowski-01, + author = "Jan Vitek and Boris Bokowski", + title = "Confined types in {Java}", + journal = spe, + volume = "31", + number = "6", + pages = "507--532", + year = "2001", + URL = "https://www.cerias.purdue.edu/assets/pdf/bibtex_archive/2001-63.pdf", +} + +@Article{volpano-97, + author = "Dennis Volpano", + title = "Provably-Secure Programming Languages for Remote + Evaluation", + journal = notices, + volume = "32", + number = "1", + pages = "117--119", + year = "1997", +} + +@Article{volpano-smith-97, + author = "Dennis Volpano and Geoffrey Smith", + title = "A Type-Based Approach to Program Security", + journal = lncs, + volume = "1214", + pages = "607--621", + year = "1997", + URL = "http://www.cs.nps.navy.mil/people/faculty/volpano/papers/tapsoft97.ps.Z", +} + +@InProceedings{volpano-smith-csfw-97, + author = "Dennis Volpano and Geoffrey Smith", + year = "1997", + title = "Eliminating Covert Flows with Minimum Typings", + booktitle = csfw, + pages = "156--168", + URL = "http://www.cs.nps.navy.mil/people/faculty/volpano/papers/csfw97.ps.Z", +} + +@Article{volpano-smith-irvine-96, + author = "Dennis Volpano and Geoffrey Smith and Cynthia Irvine", + title = "A Sound Type System for Secure Flow Analysis", + journal = "Journal of Computer Security", + volume = "4", + number = "3", + pages = "167--187", + year = "1996", + URL = "http://www.cs.nps.navy.mil/people/faculty/volpano/papers/jcs96.ps.Z", +} + +@InProceedings{vorobyov-96, + author = "Sergei G. Vorobyov", + title = "An Improved Lower Bound for the Elementary Theories of + Trees", + booktitle = cade, + pages = "275--287", + year = "1996", + volume = "1104", + series = lncs, + publisher = springer, + URL = "http://www.mpi-sb.mpg.de/~sv/publications/complexity/2ILB.ps.Z", +} + +@InProceedings{vouillon-mellies-04, + author = "Jérôme Vouillon and Paul-André Melliès", + title = "Semantic types: a fresh look at the ideal model for + types", + booktitle = popl, + year = "2004", + pages = "52--63", + URL = "http://www.pps.jussieu.fr/~vouillon/publi/cbv.ps.gz", +} + +@InProceedings{vries-06, + author = "Edsko de Vries and Rinus Plasmeijer and David + Abrahamson", + title = "Uniqueness Typing Redefined", + booktitle = ifl, + pages = "181--198", + year = "2006", + volume = "4449", + series = lncs, + publisher = springer, + URL = "https://www.cs.tcd.ie/~devriese/pub/ifl06-paper.pdf", +} + +@InProceedings{vries-07, + author = "Edsko de Vries and Rinus Plasmeijer and David + Abrahamson", + title = "Equality Based Uniqueness Typing", + booktitle = tfp, + year = "2007", + URL = "https://www.cs.tcd.ie/~devriese/pub/tfp07-paper.pdf", +} + +@Unpublished{vytiniotis-boxy-05, + author = "Dimitrios Vytiniotis and Stephanie Weirich and Simon + {Peyton Jones}", + title = "Boxy types: type inference for higher-rank types and + impredicativity", + note = "Manuscript", + year = "2005", + URL = "http://research.microsoft.com/Users/simonpj/papers/boxy/", +} + +@Article{vytiniotis-outsidein-11, + author = "Dimitrios Vytiniotis and Simon {Peyton Jones} and Tom + Schrijvers and Martin Sulzmann", + title = "{OutsideIn(X)}: Modular type inference with local + assumptions", + journal = jfp, + volume = "21", + number = "4--5", + year = "2011", + pages = "333--412", + URL = "http://research.microsoft.com/en-us/um/people/simonpj/papers/constraints/jfp-outsidein.pdf", +} + +@InProceedings{vytiniotis-pie-07, + author = "Dimitrios Vytiniotis and Stephanie Weirich", + title = "Dependent Types: Easy as {PIE}", + booktitle = tfp, + year = "2007", + URL = "http://www.seas.upenn.edu/~sweirich/papers/tfp07.pdf", +} + +@InProceedings{wadler-85, + author = "Philip L. Wadler", + title = "How to replace failure by a list of successes", + booktitle = fpca, + publisher = springer, + series = lncs, + volume = "201", + year = "1985", + pages = "113--128", + URL = "http://dx.doi.org/10.1007/3-540-15975-4_33", +} + +@InProceedings{wadler-blott-89, + author = "Philip Wadler and Stephen Blott", + title = "How to make ad-hoc polymorphism less ad-hoc", + pages = "60--76", + booktitle = popl, + year = "1989", + URL = "http://homepages.inf.ed.ac.uk/wadler/papers/class/class.ps.gz", +} + +@Article{wadler-comprehending-92, + author = "Philip Wadler", + title = "Comprehending monads", + journal = mscs, + year = "1992", + volume = "2", + pages = "461--493", + URL = "http://homepages.inf.ed.ac.uk/wadler/papers/monads/monads.ps.gz", +} + +@InProceedings{wadler-essence-92, + author = "Philip Wadler", + title = "The essence of functional programming", + booktitle = popl, + year = "1992", + pages = "1--14", + note = "Invited talk", + URL = "http://homepages.inf.ed.ac.uk/wadler/papers/essence/essence.ps", +} + +@InProceedings{wadler-free-89, + author = "Philip Wadler", + title = "Theorems for free!", + booktitle = fpca, + year = "1989", + pages = "347--359", + URL = "http://homepages.inf.ed.ac.uk/wadler/papers/free/free.ps.gz", +} + +@Article{wadler-isomorphism-07, + author = "Philip Wadler", + title = "The {Girard}-{Reynolds} isomorphism (second edition)", + journal = tcs, + year = "2007", + volume = "375", + number = "1--3", + pages = "201--226", + URL = "http://homepages.inf.ed.ac.uk/wadler/papers/gr2/gr2.pdf", +} + +@InCollection{wadler-linear-90, + author = "Philip Wadler", + title = "Linear types can change the world!", + booktitle = "Programming Concepts and Methods", + publisher = "North Holland", + year = "1990", + editor = "M. Broy and C. Jones", + URL = "http://homepages.inf.ed.ac.uk/wadler/papers/linear/linear.ps", +} + +@Article{wadler-thiemann-03, + author = "Philip Wadler and Peter Thiemann", + title = "The marriage of effects and monads", + journal = tocl, + volume = "4", + number = "1", + pages = "1--32", + year = "2003", + URL = "http://homepages.inf.ed.ac.uk/wadler/papers/effectstocl/effectstocl.ps.gz", +} + +@InProceedings{walker-00, + author = "David Walker", + title = "A Type System for Expressive Security Policies", + booktitle = popl, + year = "2000", + pages = "254--267", + URL = "http://www.cs.cornell.edu/home/walker/papers/sa-popl00_ps.gz", +} + +@InCollection{walker-attapl-05, + author = "David Walker", + title = "Substructural Type Systems", + booktitle = "Advanced Topics in Types and Programming Languages", + pages = "3--43", + publisher = mitp, + year = "2005", + editor = "Benjamin C. Pierce", + chapter = "1", +} + +@Article{walker-capabilities-00, + author = "David Walker and Karl Crary and Greg Morrisett", + title = "Typed memory management via static capabilities", + journal = toplas, + volume = "22", + number = "4", + year = "2000", + pages = "701--771", + URL = "http://www.cs.princeton.edu/~dpw/papers/capabilities-toplas.pdf", +} + +@PhdThesis{wallach-99, + author = "Dan S. Wallach", + title = "A New Approach to Mobile Code Security", + school = "Princeton University", + year = "1999", + URL = "http://www.cs.princeton.edu/sip/pub/dwallach-dissertation.html", +} + +@Article{wallach-appel-felten-00, + author = "Dan S. Wallach and Andrew W. Appel and Edward W. + Felten", + title = "Safkasi: {A} Security Mechanism for Language-based + Systems", + journal = tosem, + year = "2000", + volume = "9", + number = "4", + pages = "341--378", + URL = "http://www.cs.rice.edu/~dwallach/pub/tosem2000.ps", +} + +@InProceedings{wallach-felten-stack-98, + author = "Dan S. Wallach and Edward Felten", + title = "Understanding {Java} Stack Inspection", + booktitle = sp, + year = "1998", + URL = "http://www.cs.princeton.edu/sip/pub/oakland98.php3", +} + +@Article{wand-80, + author = "Mitchell Wand", + title = "Continuation-Based Program Transformation Strategies", + journal = jacm, + volume = "27", + number = "1", + year = "1980", + pages = "164--180", + URL = "http://dx.doi.org/10.1145/322169.322183", +} + +@InProceedings{wand-85, + author = "Mitchell Wand", + title = "Embedding type structure in semantics", + booktitle = popl, + year = "1985", + pages = "1--6", + URL = "http://doi.acm.org/10.1145/318593.318602", +} + +@InProceedings{wand-86, + author = "Mitchell Wand", + title = "Finding the Source of Type Errors", + booktitle = popl, + pages = "38--43", + year = "1986", + URL = "http://doi.acm.org/10.1145/512644.512648", +} + +@Article{wand-87, + author = "Mitchell Wand", + title = "A Simple Algorithm and Proof for Type Inference", + journal = fundamenta, + volume = "10", + pages = "115--122", + year = "1987", + URL = "http://www.cs.ucla.edu/~palsberg/course/cs239/reading/wand87.pdf", +} + +@Article{wand-concat, + author = "Mitchell Wand", + title = "Type Inference for Record Concatenation and Multiple + Inheritance", + year = "1991", + volume = "93", + number = "1", + pages = "1--15", + journal = ic, + URL = "ftp://ftp.ccs.neu.edu/pub/people/wand/papers/ic-91.dvi", +} + +@InCollection{wand-objects, + author = "Mitchell Wand", + title = "Type Inference for Objects with Instance Variables and + Inheritance", + booktitle = taoop, + editor = "Carl A. Gunter and John C. Mitchell", + publisher = mitp, + pages = "97--120", + year = "1994", + URL = "ftp://ftp.ccs.neu.edu/pub/people/wand/papers/gunter-mitchell-94.dvi", +} + +@InProceedings{wand-steckler-94, + author = "Mitchell Wand and Paul A. Steckler", + title = "Selective and lightweight closure conversion", + booktitle = popl, + year = "1994", + pages = "435--445", + URL = "http://doi.acm.org/10.1145/174675.178044", +} + +@Article{ward-96, + author = "Martin Ward", + title = "Derivation of Data Intensive Algorithms by Formal + Transformation -- The {Schorr-Waite} Graph Marking + Algorithm", + journal = tose, + year = "1996", + volume = "22", + number = "9", + pages = "665--686", + URL = "http://www.cse.dmu.ac.uk/~mward/martin/papers/sw-alg-t.pdf", +} + +@InCollection{warren-82, + author = "D. H. D. Warren", + title = "Higher-order extensions to {PROLOG}: are they + needed?", + booktitle = "Machine Intelligence 10", + pages = "441--454", + publisher = ellis, + year = "1982", + editor = "J. E. Hayes and D. Michie and Y-H. Pao", +} + +@InProceedings{warth-douglass-millstein-08, + author = "Alessandro Warth and James R. Douglass and Todd D. + Millstein", + title = "Packrat parsers can support left recursion", + booktitle = pepm, + year = "2008", + pages = "103--110", + URL = "http://www.cs.ucla.edu/~todd/research/pepm08.pdf", +} + +@Article{wegbreit-75, + author = "Ben Wegbreit", + title = "Mechanical Program Analysis", + journal = cacm, + volume = "18", + number = "9", + year = "1975", + pages = "528--539", + URL = "http://doi.acm.org/10.1145/361002.361016", +} + +@Article{wegener-02, + author = "Ingo Wegener", + title = "A simplified correctness proof for a well-known + algorithm computing strongly connected components", + journal = "Information Processing Letters", + year = "2002", + volume = "83", + number = "1", + pages = "17--19", + URL = "http://ls2-www.cs.uni-dortmund.de/~wegener/papers/connected.pdf", +} + +@InProceedings{weirich-00, + author = "Stephanie Weirich", + title = "Type-Safe Cast: Functional Pearl", + booktitle = icfp, + year = "2000", + pages = "58--67", + URL = "http://www.cis.upenn.edu/~sweirich/papers/cast/cast.pdf", +} + +@Article{weirich-polytypic-06, + author = "Stephanie Weirich", + title = "Type-Safe Run-time Polytypic Programming", + journal = jfp, + year = "2006", + volume = "16", + number = "10", + pages = "681--710", + URL = "http://www.seas.upenn.edu/~sweirich/papers/erasure/erasure-jfp.pdf", +} + +@InProceedings{weirich-replib-06, + author = "Stephanie Weirich", + title = "{RepLib}: a library for derivable type classes", + booktitle = hw, + pages = "1--12", + year = "2006", + URL = "http://www.seas.upenn.edu/~sweirich/RepLib/haskell08-weirich.pdf", +} + +@Misc{weirich-tc-04, + author = "Stephanie Weirich", + title = "A typechecker that produces a typed term from an + untyped source", + howpublished = "Part of the Glasgow Haskell compiler's test suite", + year = "2004", + URL = "http://cvs.haskell.org/cgi-bin/cvsweb.cgi/fptools/testsuite/tests/ghc-regress/gadt/tc.hs?rev=1.1", +} + +@InProceedings{weirich-yorgey-sheard-11, + author = "Stephanie Weirich and Brent A. Yorgey and Tim Sheard", + title = "Binders unbound", + booktitle = icfp, + pages = "333--345", + year = "2011", + URL = "http://www.seas.upenn.edu/~sweirich/papers/icfp11.pdf", +} + +@InProceedings{wells-02, + author = "J. B. Wells", + title = "The Essence of Principal Typings", + booktitle = icalp, + pages = "913--925", + publisher = springer, + volume = "2380", + series = lncs, + year = "2002", + URL = "http://www.macs.hw.ac.uk/~jbw/papers/Wells:The-Essence-of-Principal-Typings:ICALP-2002.pdf", +} + +@TechReport{wells-95, + author = "J. B. Wells", + title = "The Undecidability of {Mitchell's} Subtyping + Relation", + institution = "Computer Science Department, Boston University", + year = "1995", + URL = "http://www.cs.bu.edu/ftp/pub/jbw/types/subtyping-undecidable.ps.gz", + type = "Technical Report", + number = "95-019", +} + +@Article{wells-99, + author = "J. B. Wells", + title = "Typability and type checking in System {F} are + equivalent and undecidable", + journal = apal, + year = "1999", + volume = "98", + number = "1--3", + pages = "111--156", + URL = "http://www.macs.hw.ac.uk/~jbw/papers/f-undecidable-APAL.ps.gz", +} + +@PhdThesis{werner-94, + author = "Benjamin Werner", + title = "Une Théorie des Constructions Inductives", + school = "Université Paris 7", + year = "1994", +} + +@InProceedings{westbrook-05, + author = "Edwin Westbrook and Aaron Stump and Ian Wehrman", + title = "A language-based approach to functionally correct + imperative programming", + booktitle = icfp, + year = "2005", + pages = "268--279", + URL = "http://cl.cse.wustl.edu/papers/rsp1-icfp05.pdf", +} + +@PhdThesis{westbrook-08, + author = "Edwin M. Westbrook", + title = "Higher-Order Encodings with Constructors", + school = "Washington University", + year = "2008", + URL = "http://www.cs.rice.edu/~emw4/thesis-westbrook.pdf", +} + +@TechReport{why, + author = "Jean-Christophe Filliâtre", + title = "{Why}: a multi-language multi-prover verification + tool", + institution = "LRI, Université Paris Sud", + type = "Research Report", + number = "1366", + year = "2003", + URL = "http://www.lri.fr/~filliatr/ftp/publis/why-tool.ps.gz", +} + +@InProceedings{why-07, + author = "Jean-Christophe Filliâtre and Claude Marché", + title = "The {Why}/{Kra\-ka\-toa}/{Ca\-du\-ceus} Platform for + Deductive Program Verification", + booktitle = cav, + year = "2007", + pages = "173--177", + volume = "4590", + series = lncs, + publisher = springer, + URL = "http://www.lri.fr/~filliatr/ftp/publis/cav07.pdf", +} + +@Article{williams-64, + author = "J. W. J. Williams", + title = "Algorithm 232: Heapsort", + journal = cacm, + year = "1964", + volume = "7", + number = "6", + pages = "347--348", + URL = "http://doi.acm.org/10.1145/512274.512284", +} + +@InProceedings{wing-rollins-zaremsky-92, + author = "Jeannette M. Wing and Eugene Rollins and Amy Moormann + Zaremski", + title = "Thoughts on a {Larch/ML} and a New Application for + {LP}", + booktitle = "First International Workshop on Larch", + year = "1992", + URL = "http://reports-archive.adm.cs.cmu.edu/anon/usr0/ftp/home/ftp/1992/CMU-CS-92-135.ps", + pages = "297--312", +} + +@Book{wirth-78, + author = "Niklaus Wirth", + title = "Algorithms + Data Structures = Programs", + year = "1978", + publisher = prentice, +} + +@InProceedings{wisnesky-malecha-morrisett-09, + author = "Ryan Wisnesky and Gregory Malecha and Greg Morrisett", + title = "Certified Web Services in {Ynot}", + booktitle = wwv, + year = "2009", + URL = "http://wisnesky.net/wwv09.pdf", +} + +@InProceedings{wolff-11, + author = "Roger Wolff and Ronald Garcia and \'{E}ric Tanter and + Jonathan Aldrich", + title = "Gradual typestate", + booktitle = ecoop, + year = "2011", + pages = "459--483", + publisher = springer, + series = lncs, + volume = "6813", + URL = "http://www.cs.cmu.edu/~aldrich/papers/aldrich-gradual-ecoop11.pdf", +} + +@InProceedings{woodward-79, + author = "J. P. L. Woodward", + title = "Applications for Multilevel Secure Operating Systems", + booktitle = "Proceedings NCC", + year = "1979", + pages = "319--328", + volume = "48", + publisher = "{AFIPS} Press", +} + +@Article{wright-cartwright-97, + author = "Andrew K. Wright and Robert Cartwright", + title = "A Practical Soft Type System for {Scheme}", + journal = toplas, + volume = "19", + number = "1", + pages = "87--152", + year = "1997", + URL = "http://doi.acm.org/10.1145/239912.239917", +} + +@Article{wright-felleisen-94, + title = "A Syntactic Approach to Type Soundness", + author = "Andrew K. Wright and Matthias Felleisen", + pages = "38--94", + journal = ic, + year = "1994", + volume = "115", + number = "1", + URL = "http://www.cs.rice.edu/CS/PLT/Publications/Scheme/ic94-wf.ps.gz", +} + +@TechReport{wright-restriction-93, + author = "Andrew K. Wright", + institution = "Rice University", + title = "Polymorphism for Imperative Languages without + Imperative Types", + year = "1993", + number = "93-200", +} + +@Article{wright-restriction-95, + author = "Andrew K. Wright", + title = "Simple Imperative Polymorphism", + journal = lsc, + volume = "8", + number = "4", + year = "1995", + pages = "343--356", + URL = "http://www.cs.rice.edu/CS/PLT/Publications/Scheme/lasc95-w.ps.gz", +} + +@InProceedings{wyk-99, + author = "Eric van Wyk and Oege de Moor and Simon {Peyton + Jones}", + title = "Aspect-oriented compilers", + booktitle = gcse, + pages = "121--133", + year = "1999", + volume = "1799", + series = lncs, + publisher = springer, + URL = "https://www.microsoft.com/en-us/research/wp-content/uploads/2016/07/aspects.pdf", +} + +@PhdThesis{xi-98, + author = "Hongwei Xi", + title = "Dependent Types in Practical Programming", + school = "Carnegie Mellon University", + year = "1998", + URL = "http://www.cs.bu.edu/~hwxi/academic/papers/thesis.ps", +} + +@InProceedings{xi-ats, + author = "Hongwei Xi", + title = "Applied Type System", + year = "2004", + booktitle = "{TYPES} 2003", + publisher = springer, + series = lncs, + volume = "3085", + pages = "394--408", + URL = "http://www.cs.bu.edu/~hwxi/academic/papers/types03.pdf", +} + +@InProceedings{xi-chen-chen-03, + author = "Hongwei Xi and Chiyan Chen and Gang Chen", + title = "Guarded Recursive Datatype Constructors", + booktitle = popl, + year = "2003", + pages = "224--235", + URL = "http://www.cs.bu.edu/fac/hwxi/academic/papers/popl03.ps", +} + +@InProceedings{xi-cps-01, + author = "Hongwei Xi and Carsten Schürmann", + title = "{CPS} Transform for {Dependent ML}", + booktitle = wollic, + year = "2001", + URL = "http://www.cs.bu.edu/~hwxi/academic/papers/DMLcps.pdf", +} + +@InProceedings{xi-dead-99, + author = "Hongwei Xi", + title = "Dead Code Elimination through Dependent Types", + booktitle = padl, + pages = "228--242", + year = "1999", + volume = "1551", + series = lncs, + publisher = springer, + URL = "http://www.cs.bu.edu/~hwxi/academic/papers/padl99.ps", +} + +@Misc{xi-dml, + author = "Hongwei Xi", + title = "Dependent {ML}", + year = "2001", + URL = "http://www.cs.bu.edu/~hwxi/DML/DML.html", +} + +@Article{xi-dml-07, + author = "Hongwei Xi", + title = "Dependent {ML}: an approach to practical programming + with dependent types", + journal = jfp, + year = "2007", + volume = "17", + number = "2", + pages = "215--286", + URL = "http://www.cs.bu.edu/~hwxi/academic/papers/JFPdml.pdf", +} + +@Article{xi-patterns-03, + author = "Hongwei Xi", + title = "{Dependently Typed Pattern Matching}", + journal = jucs, + volume = "9", + number = "8", + year = "2003", + pages = "851--872", + URL = "http://www.cs.bu.edu/~hwxi/academic/papers/jucs03.pdf", +} + +@InProceedings{xi-pfenning-99, + author = "Hongwei Xi and Frank Pfenning", + title = "Dependent Types in Practical Programming", + booktitle = popl, + year = "1999", + pages = "214--227", + URL = "http://www.ececs.uc.edu/~hwxi/academic/papers/popl99.ps", +} + +@InProceedings{xi-views-05, + author = "Dengping Zhu and Hongwei Xi", + title = "Safe Programming with Pointers through Stateful + Views", + booktitle = padl, + publisher = springer, + series = lncs, + volume = "3350", + year = "2005", + pages = "83--97", + URL = "http://www.cs.bu.edu/~hwxi/academic/papers/padl05.pdf", +} + +@InProceedings{xie-aiken-05, + author = "Yichen Xie and Alex Aiken", + title = "Scalable error detection using {Boolean} + satisfiability", + booktitle = popl, + year = "2005", + pages = "351--363", + URL = "http://glide.stanford.edu/saturn/papers/popl05.pdf", +} + +@InProceedings{xu-06, + author = "Dana N. Xu", + title = "Extended static checking for {Haskell}", + booktitle = hw, + year = "2006", + pages = "48--59", + publisher = acmp, + URL = "http://www.cl.cam.ac.uk/~nx200/research/escH-hw.ps", +} + +@InProceedings{xu-09, + author = "Dana N. Xu and Simon {Peyton Jones} and Koen + Claessen", + title = "Static contract checking for {Haskell}", + booktitle = popl, + year = "2009", + pages = "41--52", + URL = "http://research.microsoft.com/en-us/um/people/simonpj/papers/verify/HaskellContract.ps", +} + +@InProceedings{yang-join-08, + author = "Hongseok Yang and Oukseh Lee and Josh Berdine and + Cristiano Calcagno and Byron Cook and Dino Distefano + and Peter W. O'Hearn", + title = "Scalable Shape Analysis for Systems Code", + year = "2008", + pages = "385--398", + booktitle = cav, + publisher = springer, + series = lncs, + volume = "5123", + URL = "http://research.microsoft.com/en-us/um/cambridge/projects/terminator/cav08b.pdf", +} + +@Article{yi-06, + author = "Kwangkeun Yi", + title = "Educational Pearl: 'Proof-directed debugging' + revisited for a first-order version", + journal = jfp, + volume = "16", + number = "6", + year = "2006", + pages = "663--670", + URL = "http://ropas.snu.ac.kr/~kwang/paper/06-jfp-yi.pdf", +} + +@InProceedings{yoshida-96, + author = "Nobuko Yoshida", + title = "Graph Types for Monadic Mobile Processes", + booktitle = fsttcs, + mon = dec, + year = "1996", + publisher = springer, + series = lncs, + volume = "1180", + pages = "371--386", + URL = "http://www.mcs.le.ac.uk/~nyoshida/paper/graph1_short.ps.gz", +} + +@TechReport{yoshida-96-full, + author = "Nobuko Yoshida", + title = "Graph Types for Monadic Mobile Processes", + number = "ECS-LFCS-96-350", + institution = "University of Edinburgh", + year = "1996", + URL = "http://www.lfcs.inf.ed.ac.uk/reports/96/ECS-LFCS-96-350/", +} + +@InProceedings{yoshida-al-02, + author = "Nobuko Yoshida and Kohei Honda and Martin Berger", + title = "Linearity and Bisimulation", + booktitle = fossacs, + publisher = springer, + series = lncs, + year = "2002", + URL = "http://www.mcs.le.ac.uk/~nyoshida/paper/fossacs_ca_final.ps.gz", +} + +@TechReport{yoshida-al-02-long, + author = "Nobuko Yoshida and Kohei Honda and Martin Berger", + title = "Linearity and Bisimulation", + institution = "University of Leicester", + year = "2001", + number = "MSC-2001/48", + URL = "http://www.mcs.le.ac.uk/~nyoshida/paper/lb.ps.gz", +} + +@InProceedings{yoshida-honda-berger-07, + author = "Nobuko Yoshida and Kohei Honda and Martin Berger", + title = "Logical Reasoning for Higher-Order Functions with + Local State", + booktitle = fossacs, + pages = "361--377", + year = "2007", + volume = "4423", + series = lncs, + publisher = springer, + URL = "http://www.doc.ic.ac.uk/~mberger/publications/fossacs07/fossacs07.pdf", +} + +@InProceedings{zdancewic-myers-01, + author = "Steve Zdancewic and Andrew C. Myers", + title = "Secure Information Flow and {CPS}", + booktitle = esop, + publisher = springer, + series = lncs, + year = "2001", + URL = "http://www.cs.cornell.edu/zdance/lincont.ps", +} + +@Article{zdancewic-myers-02, + author = "Steve Zdancewic and Andrew C. Myers", + title = "Secure Information Flow via Linear Continuations", + journal = "Higher Order and Symbolic Computation", + year = "2002", + volume = "15", + number = "2--3", + pages = "209--234", + URL = "http://www.cis.upenn.edu/~stevez/papers/ZM02.pdf", +} + +@InProceedings{zendra-97, + author = "Olivier Zendra and Dominique Colnet and Suzanne + Collin", + title = "Efficient Dynamic Dispatch without Virtual Function + Tables. The {SmallEiffel} Compiler", + booktitle = oopsla, + pages = "125--141", + year = "1997", + URL = "http://www.loria.fr/~colnet/publis/oopsla97.ps.gz", +} + +@Article{zenger-97, + author = "Christoph Zenger", + title = "Indexed Types", + journal = tcs, + year = "1997", + volume = "187", + number = "1--2", + pages = "147--165", + URL = "http://dx.doi.org/10.1016/S0304-3975(97)00062-5", +} + +@PhdThesis{zenger-98, + author = "Christoph Zenger", + title = "Indizierte Typen", + school = "Universität Karlsruhe", + year = "1998", + URL = "http://www.christoph-zenger.de/papers/thesis.ps.gz", +} + +@PhdThesis{zhao-07, + author = "Yang Zhao", + title = "Concurrency Analysis Based on Fractional Permission + System", + school = "University of Wisconsin", + year = "2007", + URL = "http://www.cs.uwm.edu/~boyland/papers/yangzhao-thesis.pdf", +} + +@TechReport{zheng-myers-04, + author = "Lantian Zheng and Andrew C. Myers", + title = "Dynamic Security Labels and Noninterference", + institution = "Cornell University", + year = "2004", + number = "2004-1924", + URL = "http://www.cs.cornell.edu/andru/papers/dynl-tr.pdf", +} + +@InProceedings{zhu-xi-03, + author = "Dengping Zhu and Hongwei Xi", + title = "A Typeful and Tagless Representation for {XML} + Documents", + booktitle = aplas, + publisher = springer, + series = lncs, + volume = "2895", + year = "2003", + pages = "89--104", + URL = "http://www.cs.bu.edu/~hwxi/academic/papers/aplas03.pdf", +} + +@Misc{zibin-gil-01, + author = "Yoav Zibin and Yossi Gil", + title = "Theory and Practice of Incremental Subtyping Tests and + Message Dispatching", + year = "2001", + URL = "http://www.cs.technion.ac.il/~yogi/incremental-dispatching.ps.gz", +} + +@InProceedings{zibin-gil-02, + author = "Yoav Zibin and Yossi Gil", + title = "Fast Algorithm for Creating Space Efficient + Dispatching Tables with Application to + Multi-Dispatching", + booktitle = oopsla, + pages = "142--160", + year = "2002", + URL = "http://www.cs.technion.ac.il/~zyoav/publications/OOPSLA02-dispatching-TS.pdf", +} + +@InProceedings{zibin-gil-03, + author = "Yoav Zibin and Yossi Gil", + title = "Incremental Algorithms for Dispatching in Dynamically + Typed Languages", + booktitle = popl, + year = "2003", + URL = "http://www.cs.technion.ac.il/~zyoav/publications/POPL03-dispatching-CT.pdf", +} + +@TechReport{zwanenburg-97, + author = "Jan Zwanenburg", + title = "A Type System for Record Concatenation and Subtyping", + year = "1997", + institution = "Eindhoven University of Technology", + URL = "http://www.cs.ru.nl/~janz/publications/type_check.ps", +} diff --git a/doc/from-visitors-to-iterators.md b/doc/from-visitors-to-iterators.md new file mode 100644 index 0000000..fd1733e --- /dev/null +++ b/doc/from-visitors-to-iterators.md @@ -0,0 +1,493 @@ +I have been asked whether +an automatically-generated visitor, +as produced by the [visitors](https://gitlab.inria.fr/fpottier/visitors) +syntax extension for OCaml, +can be used to construct an iterator. + +It turns out that this can be done +in a simple and efficient manner. +(Up to a constant factor, the time complexity of this solution is optimal.) +As the problem is interesting and +its solution is somewhat nonobvious, +I am describing them here. + +To play with this code in an OCaml toplevel, +first install `visitors` via the command `opam install visitors`. +Then, launch `ocaml` and type this: + +``` +#use "topfind";; +#require "visitors.ppx";; +#require "visitors.runtime";; +``` + +## Problem Statement + +Suppose we have an arbitrary data structure that contains elements +of type `'a`. Here, it is a binary tree, but it could be anything: + +``` +type 'a sometree = + | Leaf + | Node of 'a sometree * 'a * 'a sometree +``` + +We would like to enumerate the elements of this data structure. +More precisely, we would like to construct an iterator, that is, +an on-demand producer of elements. Here is a simple definition +of a stateful iterator: + +``` +type 'a iterator = + unit -> 'a option +``` + +The question is, can we construct an iterator for the type `'a sometree`, +based on an automatically-generated visitor, so that the construction is +entirely independent of the type `'a sometree`? + +## Cascades + +For starters, let us define cascades, which are a more pleasant kind of +iterators. A cascade is a persistent (stateless) iterator. It can be thought +of as a delayed list, that is, a list whose elements are computed only on +demand. + +Cascades could (should) be part of a separate library. +As the time of writing (March, 2017), there is in fact +[a proposal](https://github.com/ocaml/ocaml/pull/1002) +to add them to OCaml's standard library. + +``` +type 'a cascade = + unit -> 'a head + +and 'a head = + | Nil + | Cons of 'a * 'a cascade +``` + +A delayed computation is represented as a function of type `unit -> _`. + +The cascade constructors are as follows: + +``` +let nil : 'a cascade = + fun () -> Nil + +let cons (x : 'a) (xs : 'a cascade) : 'a cascade = + fun () -> Cons (x, xs) +``` + +Forcing a cascade reveals its head: + +``` +let force xs = + xs() +``` + +A cascade can be easily converted to a stateful iterator: + +``` +let cascade_to_iterator (xs : 'a cascade) : 'a iterator = + let s = ref xs in + fun () -> + match force !s with + | Nil -> + s := nil; + None + | Cons (x, xs) -> + s := xs; + Some x +``` + +In the above code, writing `nil` into `s` may seem superfluous, but is in fact +necessary to guarantee that the computation that led to a `Nil` outcome is not +repeated in the future. + +Because cascades are close cousins of lists, they are easy to work with. +Constructing a cascade for a tree-like data structure is straightforward, +whereas directly constructing a stateful iterator would be more involved. + +## Back to the problem + +Now, can we use some kind of visitor to turn a tree of type `'a sometree` +into a cascade of type `'a cascade`? + +At first sight, this does not seem very easy, because of two issues: + + * a visitor usually traverses a tree in an eager manner, whereas we need the + traversal to make progress only as cascade elements are demanded; + + * a visitor performs a bottom-up computation, without a left-to-right bias + (assuming mutable state is not used), whereas a cascade enumerates elements + in a left-to-right manner. (Or in a right-to-left manner. As will be + apparent below, both directions are possible.) + +The trick is to use another intermediate step. Instead of turning a tree +directly into a cascade, we first transform it into a generic tree-like +structure: a *delayed tree*. The first issue above is solved because, by +introducing delays into the new tree, we allow its construction to be carried +out on demand. The second issue is solved because this tree-to-tree +transformation can be carried out in a purely bottom-up manner by a `reduce` +visitor. Then, finally, it is straightforward to transform a delayed tree into +a cascade. + +## From Delayed Trees to Cascades and Iterators + +A delayed tree contains ordinary nodes of arity 0, 1, and 2. Furthermore, +it contains `DTDelay` nodes, of arity 1, whose child is delayed, that is, +computed only on demand. + +``` +type 'a delayed_tree = + | DTZero + | DTOne of 'a + | DTTwo of 'a delayed_tree * 'a delayed_tree + | DTDelay of (unit -> 'a delayed_tree) +``` + +A delayed tree is converted to a cascade as follows. As is often the case, +when building a cascade, one must take a continuation `k` as an argument, so +as to avoid naive and costly cascade concatenation operations. Thus, the +specification of the function call `delayed_tree_to_cascade dt k` is to +construct a cascade whose elements are the elements of the delayed tree `dt` +(listed from left to right), followed with the elements of the cascade `k`. + +``` +let rec delayed_tree_to_cascade (dt : 'a delayed_tree) (k : 'a cascade) +: 'a cascade = + fun () -> delayed_tree_to_head dt k + +and delayed_tree_to_head (dt : 'a delayed_tree) (k : 'a cascade) : 'a head = + match dt with + | DTZero -> + force k + | DTOne x -> + Cons (x, k) + | DTTwo (dt1, dt2) -> + delayed_tree_to_head dt1 (delayed_tree_to_cascade dt2 k) + | DTDelay dt -> + delayed_tree_to_head (force dt) k + +let delayed_tree_to_cascade (dt : 'a delayed_tree) : 'a cascade = + delayed_tree_to_cascade dt nil + +let delayed_tree_to_iterator (dt : 'a delayed_tree) : 'a iterator = + cascade_to_iterator (delayed_tree_to_cascade dt) +``` + +In the above code, we have chosen to perform a left-to-right traversal of +the delayed tree, but could just as well have chosen a right-to-left traversal. + +It is possible to make the delayed tree data structure implicit in the code; +this is explained [further on](#variant-getting-rid-of-explicit-delayed-trees). + +## Constructing Delayed Trees + +The type `'a delay` is a synonym for `'a`. We will use it as a decoration, in +a type definition, to indicate that a call to the method `visit_delay` is +desired. + +``` +type 'a delay = 'a +``` + +We now set up four constructor functions or constructor methods, which +construct delayed trees, and which we will use in a `reduce` visitor. + +Delayed trees form a monoid, in the sense that we concatenate them using +`DTTwo`, and the neutral element is `DTZero`. We package these two data +constructors in the methods `zero` and `plus`, which are automatically called +in an automatically-generated `reduce` visitor. + +The visitor method `visit_delay` delays the visit of a subtree by constructing +and returning a `DTDelay` node, which carries a delayed recursive call to a +visitor. + +The visitor function `yield` will be invoked at elements of type `'a`. It +constructs a one-element delayed tree. + +``` +class ['self] delayed_tree_monoid = object (_ : 'self) + + method zero = + DTZero + + method plus s1 s2 = + match s1, s2 with + | DTZero, s + | s, DTZero -> + s + | _, _ -> + DTTwo (s1, s2) + + method visit_delay: 'env 'a . + ('env -> 'a -> 'b delayed_tree) -> + 'env -> 'a delay -> 'b delayed_tree + = fun visit_'a env x -> + DTDelay (fun () -> visit_'a env x) + +end + +let yield _env x = + DTOne x +``` + +In the method `plus`, above, treating `DTZero` specially is not mandatory. It +is an optimization, which helps allocate fewer nodes. + +## Generating a Visitor + +It is now time to generate a `reduce` visitor for the type `'a sometree`. +This is the only part of the code which is specific of `sometree`. +Everything else is generic. + +We must insert *delays* into the structure of the type `'a sometree` so as to +indicate where `visit_delay` should be called and (therefore) where `DTDelay` +nodes should be allocated. To do this, we write a copy of the definition of +the type `'a sometree`, with extra uses of `delay` in it. The new type is +actually considered equal to `'a sometree` by OCaml. Its role is purely to +carry a `@@deriving visitors` annotation. + +In the data constructor `Node`, the left-hand `delay` is in fact superfluous. +With or without it, our iterators will eagerly descend along the leftmost +branch of a tree, anyway. + +``` +type 'a mytree = 'a sometree = + | Leaf + | Node of 'a mytree delay * 'a * 'a mytree delay + +and 'a mytree_delay = + 'a mytree delay + +[@@deriving visitors { variety = "reduce"; polymorphic = true; + concrete = true; ancestors = ["delayed_tree_monoid"] }] +``` + +This approach is pleasant insofar as one controls exactly where delays are +inserted. However, it requires copying the type definition, which may be +unpleasant. Another approach is described +[further on](#variant-avoiding-duplication-of-the-type-definition). + +## Using the Generated Visitor + +For demonstration purposes, let us make our visitor verbose. In production, +one should remove `verbose_reduce` and use `reduce` instead. + +``` +class ['self] verbose_reduce = object (_ : 'self) + inherit [_] reduce as super + method! visit_Leaf visit_'a env = + Printf.printf "Visiting a leaf.\n%!"; + super#visit_Leaf visit_'a env + method! visit_Node visit_'a env t1 x t2 = + Printf.printf "Visiting a node.\n%!"; + super#visit_Node visit_'a env t1 x t2 +end +``` + +The problem is solved! There remains to write a couple lines of glue code: + +``` +let sometree_to_delayed_tree (t : 'a sometree) = + new verbose_reduce # visit_mytree_delay yield () t + +let sometree_to_iterator (t : 'a sometree) : 'a iterator = + delayed_tree_to_iterator (sometree_to_delayed_tree t) +``` + +We use `visit_mytree_delay` above, even though `visit_mytree` would work just +as well, so as to ensure that we get a delayed tree whose root is a `DTDelay` +node. Thus, absolutely no work is performed when the iterator is created; +iteration begins only when the first element is demanded. + +## Demo + +A little demo helps see what is going on. + +``` +let t : int sometree = + Node (Node (Leaf, 1, Leaf), 2, Node (Leaf, 3, Leaf)) + +let i : int iterator = + sometree_to_iterator t +``` + +Here is a transcript of an OCaml toplevel session: + +``` + # i();; + Visiting a node. + Visiting a node. + Visiting a leaf. + - : int option = Some 1 + # i();; + Visiting a leaf. + - : int option = Some 2 + # i();; + Visiting a node. + Visiting a leaf. + - : int option = Some 3 + # i();; + Visiting a leaf. + - : int option = None + # i();; + - : int option = None +``` + +## Variant: Avoiding Duplication of the Type Definition + +Earlier, we have generated a visitor for the existing type `'a sometree` in *a +posteriori* style. We have manually created an isomorphic copy of the type `'a +sometree`, which we have named `'a mytree`, and have annotated this copy with +`[@@deriving visitors { ... }]`. Furthermore, we have taken this opportunity +to insert `delay` type constructors into the type, so as to influence the +generated visitor. + +This style is relatively pleasant because it is declarative and lets us +control exactly where delays are inserted. However, it requires duplicating +the definition of the type `'a sometree`, which may be unpleasant (if the +definition is large) or impossible (if the definition is hidden behind an +abstraction barrier). + +Another approach is to generate a visitor in *a priori* style. When the type +`'a sometree` is first defined, a `reduce` visitor can be immediately +generated for it, as follows: + +``` +type 'a sometree = + | Leaf + | Node of 'a sometree * 'a * 'a sometree + +[@@deriving visitors { variety = "reduce"; polymorphic = true; + name = "sometree_reduce" }] +``` + +At this point, we pretend that we do not know yet what this visitor will be +used for, so we do not annotate the type definition with `delay`, and do not +use `delayed_tree_monoid` as a base class. We get a visitor class, named +`sometree_reduce`. This class has two virtual methods, `zero` and `plus`. + +Then, we create a subclass, named `reduce`, which we tailor to our needs. +We mix the generated class `sometree_reduce` with the class `delayed_tree_monoid`, +and insert a delay at every tree node by overriding the method `visit_sometree`: + +``` +class ['self] reduce = object (self : 'self) + inherit [_] sometree_reduce as super + inherit [_] delayed_tree_monoid + method! visit_sometree visit_'a env t = + self#visit_delay (super#visit_sometree visit_'a) env t +end +``` + +The rest of the code is unchanged (except the method `visit_mytree_delay` no +longer exists; one calls `visit_sometree` instead). + +## Variant: Getting Rid of Explicit Delayed Trees + +I like to present delayed trees as an explicit data structure, because this +helps understand what is going on. However, if desired, it is possible to +hide them by *refunctionalization* (the opposite of *defunctionalization*). + +Above, the function `delayed_tree_to_cascade` was written with the help of an +auxiliary function, `delayed_tree_to_head`. We could also have written it +directly, as follows: + +``` +let rec delayed_tree_to_cascade (dt : 'a delayed_tree) (k : 'a cascade) +: 'a cascade = + match dt with + | DTZero -> + k + | DTOne x -> + cons x k + | DTTwo (dt1, dt2) -> + delayed_tree_to_cascade dt1 (delayed_tree_to_cascade dt2 k) + | DTDelay dt -> + fun () -> delayed_tree_to_cascade (force dt) k () +``` + +In this form, the only function that is ever applied to a delayed tree is +`delayed_tree_to_cascade`. Therefore, wherever we construct a delayed tree +`t`, we could instead directly build a closure whose behavior is equivalent to +`delayed_tree_to_cascade t`. This is *refunctionalization*. + +The data structure of delayed trees seems to disappears. +The type `'a delayed_tree` can be defined as a synonym +for a `'a cascade -> 'a cascade`. I usually refer to +this type as `'a producer`: it is the type of a function +that concatenates elements in front of the cascade that it +receives as an argument. + +``` +type 'a producer = + 'a cascade -> 'a cascade + +type 'a delayed_tree = + 'a producer +``` + +The four data constructors are defined as follows: + +``` +let _DTZero k = + k + +let _DTOne x k = + cons x k + +let _DTTwo dt1 dt2 k = + dt1 (dt2 k) + +let _DTDelay dt k = + fun () -> force dt k () +``` + +The reader can check that the types of these data constructors are the +same as in the previous version of the code. For instance, `_DTDelay` +has type `(unit -> 'a delayed_tree) -> 'a delayed_tree`. + +The root function `delayed_tree_to_cascade` (without a continuation argument) +is defined as follows: + +``` +let delayed_tree_to_cascade (dt : 'a delayed_tree) : 'a cascade = + dt nil +``` + +The delayed tree monoid uses the new versions of the four data constructors: + +``` +class ['self] delayed_tree_monoid = object (_ : 'self) + + method zero = + _DTZero + + method plus = + _DTTwo + + method visit_delay: 'env 'a . + ('env -> 'a -> 'b delayed_tree) -> + 'env -> 'a delay -> 'b delayed_tree + = fun visit_'a env x -> + _DTDelay (fun () -> visit_'a env x) + +end + +let yield _env x = + _DTOne x +``` + +The four functions `_DTZero`, `_DTOne`, `_DTTwo`, and `_DTDelay` could be +inlined, if desired, so as to make the above code seem even more concise. + +The rest of the code is unchanged. + +## Acknowledgements + +KC Sivaramakrishnan asked whether a visitor can be used to construct an +iterator. Gabriel Scherer pointed out that the delayed tree data structure can +be hidden by refunctionalization. diff --git a/doc/listings-ocaml.tex b/doc/listings-ocaml.tex new file mode 100644 index 0000000..4ab8be0 --- /dev/null +++ b/doc/listings-ocaml.tex @@ -0,0 +1,24 @@ +% Configuring listings for OCaml. + +% Comments in blue. +\newcommand{\ocamlcommentstyle}{\color{blue}} + +\lstdefinelanguage{ocaml}[Objective]{Caml}{ + % Fix errors in the default definition of ocaml. + deletekeywords={closed,ref}, + morekeywords={initializer}, + % General settings. + flexiblecolumns=false, + showstringspaces=false, + framesep=5pt, + commentstyle=\ocamlcommentstyle, + % By default, we use a small font. + basicstyle=\tt\small, + numberstyle=\footnotesize, + % LaTeX escape. + escapeinside={$}{$}, +} + +% An abbreviation for \lstinline, with a normal font size. +% To be used in the text of the paper. +\def\oc{\lstinline[language=ocaml,basicstyle=\tt,flexiblecolumns=true]} diff --git a/doc/local.bib b/doc/local.bib new file mode 100644 index 0000000..9d71c5b --- /dev/null +++ b/doc/local.bib @@ -0,0 +1,23 @@ +@Misc{ocaml7465, + author = {Fran{\c c}ois Pottier}, + title = {OCaml issue 7465}, + month = jan, + year = 2017, + URL = "https://caml.inria.fr/mantis/view.php?id=7465", +} + +@Misc{milewski-13, + author = {Bartosz Milewski}, + title = {Understanding {$F$-algebras}}, + month = oct, + year = 2013, + URL = {https://www.schoolofhaskell.com/user/bartosz/understanding-algebras} +} + +@Misc{iterators, + author = {Fran{\c c}ois Pottier}, + title = {From visitors to iterators}, + month = mar, + year = 2017, + URL = {http://gallium.inria.fr/blog/from-visitors-to-iterators/}, +} diff --git a/doc/macros.tex b/doc/macros.tex new file mode 100644 index 0000000..1b698b8 --- /dev/null +++ b/doc/macros.tex @@ -0,0 +1,126 @@ +% ------------------------------------------------------------------------------ +% Including a source code file foo.ml: +% \orig{foo} + +\mdfsetup{% + linewidth=0pt,% + skipabove=\baselineskip,% + skipbelow=.4\baselineskip,% + innertopmargin=0pt,% + innerbottommargin=0pt,% +} + +\newenvironment{origenv}{% + \begin{mdframed}[backgroundcolor=gray!10]% +}{% + \end{mdframed}% +} + +\newcommand{\orig}[1]{% +\begin{origenv} +\lstinputlisting{#1.ml} +\end{origenv} +} + +\newcommand{\origfirstline}[2]{% +\begin{origenv} +\lstinputlisting[firstline=#2]{#1.ml} +\end{origenv} +} + +%% \newcommand{\codefollowupgeneral}[1]{% +%% \begin{center} +%% (This code fragment follows up on #1.) +%% \end{center} +%% \vspace{-\baselineskip} +%% } + +\newcommand{\codefollowupgeneral}[1]{% +\marginnote{\footnotesize This follows #1.}[5mm]% +} + +\newcommand{\codefollowup}[1]{% + \codefollowupgeneral{\fref{fig:#1}}% +} + +% ------------------------------------------------------------------------------ +% Including the corresponding auto-generated code: +% \processed{foo} + +\newenvironment{processedenv}{% + \begin{mdframed}[backgroundcolor=yellow!40]% +}{% + \end{mdframed}% +} + +\newcommand{\processed}[1]{% +\begin{processedenv} +\lstinputlisting{#1.processed.ml} +\end{processedenv} +} + +% ------------------------------------------------------------------------------ +% Various macros. + +\newcommand{\fref}[1]{Figure~\ref{#1}} +\newcommand{\sref}[1]{\S\ref{#1}} +\newcommand{\email}[1]{\href{mailto:#1}{\texttt{#1}}} + +% ------------------------------------------------------------------------------ +% Abbreviations. + +\newcommand{\merlin}{\href{https://github.com/ocaml/merlin}{Merlin}\xspace} +\newcommand{\ocamlbuild}{\href{https://github.com/ocaml/ocamlbuild/blob/master/manual/manual.adoc}{\texttt{ocamlbuild}}\xspace} +\newcommand{\ocamlfind}{\texttt{ocamlfind}\xspace} +\newcommand{\opam}{\href{https://opam.ocaml.org/}{\texttt{opam}}\xspace} +\newcommand{\ppxderiving}{\href{https://github.com/whitequark/ppx_deriving}{\texttt{ppx\_deriving}}\xspace} +\newcommand{\ppximport}{\href{https://github.com/whitequark/ppx_import}{\texttt{ppx\_import}}\xspace} +\newcommand{\dune}{\href{https://github.com/ocaml/dune}{Dune}\xspace} + +\newcommand{\hashconsRepoURL}{https://github.com/backtracking/ocaml-hashcons} +\newcommand{\hashcons}{\href{\hashconsRepoURL}{\texttt{hashcons}}\xspace} +\newcommand{\hashconsRepoFile}[1]{\href{\hashconsRepoURL/blob/master/#1}{\texttt{#1}}} + +\newcommand{\repoURL}{https://gitlab.inria.fr/fpottier/visitors} +\newcommand{\repoFile}[1]{\href{\repoURL/blob/master/#1}{\texttt{#1}}} +% \newcommand{\srcFile}[1]{\href{\repoURL/blob/master/src/#1}{\texttt{#1}}} +\newcommand{\runtimeFile}[1]{\href{\repoURL/blob/master/runtime/#1}{\texttt{#1}}} + +\newcommand{\iter}{\texttt{iter}\xspace} +\newcommand{\map}{\texttt{map}\xspace} +\newcommand{\mapendo}{\texttt{endo}\xspace} +\newcommand{\reduce}{\texttt{reduce}\xspace} +\newcommand{\mapreduce}{\texttt{mapreduce}\xspace} +\newcommand{\fold}{\texttt{fold}\xspace} +\newcommand{\itertwo}{\texttt{iter2}\xspace} +\newcommand{\maptwo}{\texttt{map2}\xspace} +\newcommand{\reducetwo}{\texttt{reduce2}\xspace} +\newcommand{\mapreducetwo}{\texttt{mapreduce2}\xspace} +\newcommand{\foldtwo}{\texttt{fold2}\xspace} +\newcommand{\unit}{\texttt{unit}\xspace} +\newcommand{\visitors}{\texttt{visitors}\xspace} +\newcommand{\derivingvisitors}{\texttt{[@@deriving visitors \{ ...\ \}]}\xspace} +\newcommand{\runtime}[1]{\oc|VisitorsRuntime.#1|} + +\newcommand{\tyconvisitor}[1]{\texttt{visit\_#1}} +\newcommand{\dataconvisitor}[1]{\texttt{visit\_#1}} +\newcommand{\tyconfail}[1]{\texttt{fail\_#1}} +\newcommand{\dataconascendingmethod}[1]{\texttt{build\_#1}} +\newcommand{\tyconascendingmethod}[1]{\texttt{build\_#1}} + +\newcommand{\refconvention}{\sref{sec:intro:parameterized:poly}, \sref{sec:intro:nonlocal}, +\fref{fig:convention}} + +% Options. +\newcommand{\ancestors}{\texttt{ancestors}\xspace} +\newcommand{\concrete}{\texttt{concrete}\xspace} +\newcommand{\irregular}{\texttt{irregular}\xspace} +\newcommand{\name}{\texttt{name}\xspace} +\newcommand{\public}{\texttt{public}\xspace} +\newcommand{\variety}{\texttt{variety}\xspace} +\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} diff --git a/doc/manual.pdf b/doc/manual.pdf new file mode 100644 index 0000000..9552d1a Binary files /dev/null and b/doc/manual.pdf differ diff --git a/doc/manual.tex b/doc/manual.tex new file mode 100644 index 0000000..4374a84 --- /dev/null +++ b/doc/manual.tex @@ -0,0 +1,2401 @@ +\documentclass[11pt,a4paper,twoside]{article} +\usepackage[left=25mm,right=25mm,top=25mm,bottom=25mm,marginparwidth=50pt]{geometry} +\setlength\abovecaptionskip{0pt} % Reduce space above figure captions. +\usepackage{lmodern} % This gives us a bold monospace font. +\renewcommand{\rmdefault}{ptm} % Times. +\usepackage[T1]{fontenc} +\usepackage[utf8]{inputenc} +\usepackage{enumitem} +\usepackage[bookmarks=true,bookmarksopen=true,colorlinks=true,% + linkcolor=blue,citecolor=blue,urlcolor=blue]{hyperref} +\usepackage{marginnote} +\usepackage{listings} +\input{listings-ocaml} +\lstset{language=ocaml} +\usepackage{moreverb} +\usepackage{tabularx} +\usepackage{xcolor} +\usepackage{mdframed} +\usepackage{xspace} +\input{macros} +% Style. +\renewcommand{\emph}[1]{\textbf{#1}} +\input{version} + +% ------------------------------------------------------------------------------ +% Headings. + +\title{Visitors\\\normalsize version \visitorsversion} +\date{} +\begin{document} +\author{François Pottier\\ Inria Paris\\ \email{francois.pottier@inria.fr}} +\maketitle + +% ------------------------------------------------------------------------------ + +\clearpage +\tableofcontents +\clearpage + +% ------------------------------------------------------------------------------ + +\begin{flushright} + Les visites font toujours plaisir, si ce n'est en arrivant, du moins en + partant. \\ --- \textit{Jean de La Bruyère} +\end{flushright} + +\vspace{8mm} + +% ------------------------------------------------------------------------------ +% ------------------------------------------------------------------------------ + +\section{Introduction} +\label{sec:intro} + +% ------------------------------------------------------------------------------ + +\subsection{What is a visitor?} + +A visitor class for a data structure is a class whose methods implement a +traversal of this data structure. By default, the visitor methods do not have +interesting behavior: they just cause control to go down into the data +structure and come back up, without performing any actual computation. +Nevertheless, by defining subclasses where one method or a few methods are +overridden, nontrivial behavior can be obtained. Therefore, visitors allow +many operations on this data structure to be defined with little effort. + +Visitor classes come in several varieties. An \iter visitor traverses a data +structure and returns no result. It can nevertheless have side effects, +including updating a piece of mutable state, raising an exception, and +performing input/output. A \map visitor traverses a data structure and returns +another data structure: typically, a copy of its argument that has been +transformed in some way. An \mapendo visitor is a variant of a \map visitor +that preserves physical sharing when possible. A \reduce visitor traverses a +data structure and returns a value that somehow summarizes it: computing the +size of a data structure is a typical example. A \mapreduce visitor performs +the tasks of a \map visitor and a \reduce visitor at the same time, +possibly allowing symbiosis between them. All of these can be viewed as +special cases of the \fold visitor, which performs a bottom-up computation +over a data structure. The class \fold is equipped with virtual methods +% (the ``\tyconascendingmethod{}'' methods) +that can be overridden (in a subclass) so as to specify what computation is +desired. + +Visitors also come in several arities. The visitors mentioned above have arity +one: they traverse one data structure. However, it is sometimes necessary to +simultaneously traverse two data structures of identical shape. For this +purpose, there are visitors of arity two: here, they are known as \itertwo, +\maptwo, \reducetwo, \mapreducetwo, and \foldtwo visitors. + +% \mapendotwo does not exist. + +% ------------------------------------------------------------------------------ + +\subsection{What does this package offer?} + +Visitors have extremely regular structure. As a result, whereas implementing +them by hand is boring and error-prone, generating them automatically is often +possible. The \visitors package extends the syntax of OCaml% +% +\footnote{Technically, \visitors is a plugin for \ppxderiving, which itself is + a preprocessor extension for the OCaml compiler.} +% +so as to make it easy for the programmer to request the automatic generation +of visitor classes. Visitor classes for many forms of user-defined data types +can be generated and, if necessary, combined (via multiple inheritance) with +hand-written visitor classes, making the framework quite powerful. + +% ------------------------------------------------------------------------------ +% ------------------------------------------------------------------------------ + +\section{Walkthrough} + +% ------------------------------------------------------------------------------ + +\subsection{Setup} +\label{sec:intro:setup} + +\enlargethispage{\baselineskip} + +In order to install the \visitors package, an \opam user should issue the +following commands: +\begin{lstlisting}[keywords={}] + opam update + opam install visitors +\end{lstlisting} +To use the package, an \ocamlbuild user should add the +following line in her project's \texttt{\_tags} file: +\begin{lstlisting}[keywords={}] + true: package(visitors.ppx) +\end{lstlisting} +while a user of \dune should add the following incantation +to her project's \texttt{dune} file, +inside a \texttt{library} or \texttt{executable} stanza: +\begin{lstlisting}[keywords={}] + (preprocess (pps visitors.ppx)) +\end{lstlisting} +%% A user of \merlin should add the following lines in her project's +%% \texttt{.merlin} file: +%% \begin{lstlisting}[keywords={}] +%% PKG visitors.ppx +%% \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";; +\end{lstlisting} + +% ------------------------------------------------------------------------------ + +\begin{figure}[t] +% In an OCaml source file, a type definition can be annotated with +% \derivingvisitors: +\orig{expr00} +% This causes the following code to be (invisibly) generated: +\vspace{-\baselineskip} +\processed{expr00} +\caption{A visitor of the \iter variety} +\label{fig:expr00} +\end{figure} + +\subsection{Defining an \iter visitor} +\label{sec:intro:iter:def} + +Suppose we need to manipulate arithmetic expressions built out of integer +literals and binary additions. The abstract syntax of these expressions can be +described by an algebraic data type \oc|expr|, shown in the first part of +\fref{fig:expr00}. +% +By annotating this type definition with \derivingvisitors, we request the +automated generation of a visitor for expressions. The annotation +\derivingvisitors must carry at least one parameter, \variety, which indicates +what variety of visitor is desired. + +The code of the visitor class, which is automatically generated and in normal +use remains invisible, is shown in the second part of \fref{fig:expr00}. The +name of this class is by default the value of the \variety parameter. It can +be changed, if desired, by explicitly supplying a \name parameter. + +A visitor takes the form of an OCaml class, whose methods are named after the +types and data constructors that appear in the type definition. In +\fref{fig:expr00}, for instance, the method \tyconvisitor{expr} is named after +the type \oc|expr|, while the methods \dataconvisitor{EConst} and +\dataconvisitor{EAdd} are named after the data constructors \oc|EConst| and +\oc|EAdd|. + +Different varieties of visitors differ in the computation that is performed +``on the way up'', after the recursive calls have finished, therefore differ +in the return types of the visitor methods. \iter is the simplest variety. An +\iter visitor performs no computation on the way up, so its methods have +return type \oc|unit|. + +In an \iter visitor, the generated visitor methods do nothing. In +\fref{fig:expr00}, for instance, the method \tyconvisitor{expr} inspects its +argument \oc|this| and recursively invokes either \dataconvisitor{EConst} or +\dataconvisitor{EAdd}, as appropriate. The method \dataconvisitor{EConst} does +nothing.\footnote{More precisely, it calls the method \tyconvisitor{int}, + which is inherited from the class \runtime{iter}, and does + nothing. This call to \tyconvisitor{int} can be avoided, if desired, by using + \oc|(int[@opaque])| instead of \oc|int|; see \sref{sec:opaque}.} The method +\dataconvisitor{EAdd} performs two recursive calls to \tyconvisitor{expr}, +which does nothing, so \dataconvisitor{EAdd} itself does nothing. + +Every method is parameterized with an environment \oc|env|, which is carried +down into every recursive call and is otherwise unused. The type of this +environment is undetermined: it is up to the (user-defined) subclasses of the +visitor class to decide what the type of \oc|env| should be and (possibly) +where and how this environment should be enriched. + +% One could note that the visitor class is parameterized over 'self, +% but it is perhaps a bit early for such a remark. + +The fields of a data constructor or record are traversed left to right, in the +order they are declared. In a list-like data structure, the field that holds a +pointer to the list tail should be declared last, so as to ensure that the +traversal requires constant stack space. + +% ------------------------------------------------------------------------------ + +\begin{figure}[t] +\codefollowup{expr00} +\origfirstline{expr04}{3} +\caption{Counting the number of addition nodes in an expression} +\label{fig:expr04} +\end{figure} + +\subsection{Using an \iter visitor} +\label{sec:intro:iter:usage} + +Naturally, traversing a data structure without actually computing anything is +not a very sensible thing to do. Things become interesting when at least one +visitor method is overridden so as to give rise to nontrivial behavior. +Suppose, for instance, that we wish to count the number of addition nodes in +an expression. This can be done as shown in \fref{fig:expr04}. We create an +object~\oc|v| that is both a counter (that is, an object equipped with a +mutable field~\oc|count|) and a visitor, and we override its method +\dataconvisitor{EAdd} so that the counter is incremented every time this +method is invoked. There remains to run the visitor, by invoking its +\tyconvisitor{expr} method, and to return the final value of the counter. The +environment, in this example, is unused; we let it have type \unit. + +This may seem a rather complicated way of counting the addition nodes in an +expression. Of course, one could give a direct recursive definition of the +function \oc|count|, in a few lines of code, without using a visitor at all. +The point of employing a visitor, as done in Figures~\ref{fig:expr00} +and~\ref{fig:expr04}, is that no changes to the code are required when the +type of expressions is extended with new cases. + +% ------------------------------------------------------------------------------ + +\subsection{What is the type of a visitor?} +\label{sec:intro:type} + +In this document, most of the time, we prefer to show the code of a visitor +class and omit its type. There are two reasons for this. First, this type is +often verbose, as the class has many methods, and complex, as several type +variables are often involved. Second, although we can explain the type of a +generated visitor on a case-by-case basis, we cannot in the general case +predict the type of a generated visitor. +The reason is, the type of a generated visitor depends upon the +types of the classes that are inherited via the \ancestors parameter +(\sref{sec:ancestors}). Because a \texttt{ppx} syntax extension transforms +untyped syntax trees to untyped syntax trees, the \visitors syntax extension +does not have access to this information. + +For this reason, the \visitors syntax extension cannot generate any type +declarations. Thus, the annotation \derivingvisitors can be used only in an +\texttt{\%.ml} file, not in an \texttt{\%.mli} file. When it is used in an +\texttt{\%.ml} file, the corresponding \texttt{\%.mli} file should either be +omitted altogether or be written by hand. + +\input{types} + +Nevertheless, the type of the generated code can be inspected, if desired, by +requesting the OCaml compiler to infer and display it. For this purpose, one +can use a command of the following form: +\begin{quote} +\verb|ocamlbuild -use-ocamlfind %.inferred.mli| +\end{quote} + +\fref{fig:inferred} shows the type that is inferred via such a command for the +\iter visitor of \fref{fig:expr00}. This type is rather verbose, for two +reasons. First, an explicit type equation, introduced by the \oc|constraint| +keyword, relates the type parameter \oc|'self| with an OCaml object type that +lists the public methods with their types. Second, the class \iter has many more +methods than one might think. This is because it inherits a large number of +private methods from the class \runtime{iter}. In the present case, all of +these methods except \tyconvisitor{int} are in fact unused. + +Fortunately, this complicated type can be manually simplified. This is done in +\fref{fig:simplified}. Two main simplifications have been performed. First, we +have omitted all private methods. Indeed, the most important property of +private methods in OCaml is precisely the fact that it is permitted to hide +their existence. Second, we have omitted the type constraint that bears on +the type variable \oc|'self|, as it is in fact redundant: it is implicit in OCaml +that the type of ``self'' must be an object type that lists the public methods. +The bizarre-looking ``\oc|'monomorphic.|'' annotations indicate that the methods have +monomorphic types. (This notational trick is explained in \sref{sec:oo:monomorphic}.) +This means that the type variable~\oc|'env| is not quantified at the level of each +method\footnote{That would be undesirable, as it would force each method to +treat the environment as an argument of unknown type!}, but at the level of the class. +This means that the three methods must agree on the type of the environment, and +that this type is presently undetermined, but can be determined in a subclass. + +The class type shown in \fref{fig:simplified} cannot be further simplified. +The methods \tyconvisitor{EConst} and \tyconvisitor{EAdd} cannot be hidden, as +they are public. That said, if one wished to hide them, one could add the parameter % +\oc|public = ["visit_expr"]| to the annotation \derivingvisitors in \fref{fig:expr00}. +These two methods would then be declared private in the generated code, +so it would be permitted to hide their existence. + +Although we have claimed earlier that one cannot in the general case predict +the type of a generated visitor method, or even predict whether a generated +method will be well-typed, it is possible to define a convention which in many +cases can be adhered to. This convention is presented later on +(\refconvention). + +% ------------------------------------------------------------------------------ + +\begin{figure}[t] +\orig{expr01} +\vspace{-\baselineskip} +\processed{expr01} +\caption{A visitor of the \map variety} +\label{fig:expr01} +\end{figure} + +\subsection{\map visitors} +\label{sec:intro:map} + +An \iter visitor returns no result. Although, as illustrated previously +(\sref{sec:intro:iter:usage}), it can use private mutable state to accumulate +information, there are applications for which such a visitor is not suitable. +One class of such applications is tree transformations. To transform an +expression into an expression, one should use a visitor of another variety, +namely \map. + +A \map visitor is shown in \fref{fig:expr01}. In comparison with the \iter +visitor of \fref{fig:expr00}, the generated code is identical, except that, +instead of returning the unit value \oc|()|, the method +\dataconvisitor{EConst} reconstructs an \oc|EConst| expression, while the +method \dataconvisitor{EAdd} reconstructs an \oc|EAdd| expression. + +A \map visitor behaves (by default) as an identity function: it constructs a +copy of the data structure that it visits. If the data structure is immutable, +this is rather pointless: in order to obtain nontrivial behavior, at least one +method should be overridden. If the data structure is mutable, though, even +the default behavior is potentially of interest: it constructs a deep copy of +its argument. + +% ------------------------------------------------------------------------------ + +\begin{figure}[p] +\orig{expr00endo} +\vspace{-\baselineskip} +\processed{expr00endo} +\caption{A visitor of the \mapendo variety} +\label{fig:expr00endo} +\end{figure} + +\subsection{\mapendo visitors} +\label{sec:intro:endo} + +\mapendo visitors are a slight variation of \map visitors. Whereas a \map +visitor systematically allocates a copy of the memory block that it receives +as an argument, an \mapendo visitor (\fref{fig:expr00endo}) first tests if the +newly allocated block would have exactly the same contents as the original +block, and if so, re-uses the original block instead. +% Didier attributes this idea to Gérard Huet, +% at least in the case of a dictionary insertion operation, +% where Gérard would raise an exception so as to go back to +% the toplevel and avoid re-allocating a path. +% +This trick allows saving memory: for instance, when a performing a +substitution operation on a term, the subterms that are unaffected +by the substitution are not copied. + +One potential disadvantage of \mapendo visitors, in comparison with \map +visitors, is that these runtime tests have a runtime cost. A more serious +disadvantage is that \mapendo visitors have less general types: in an \mapendo +visitor, the argument type and return type of every method must coincide, +whence the name ``\mapendo''. +% +(An endomorphism is a function of a set into itself.) +% +\map visitors are not subject to this restriction: for an illustration, see +\sref{sec:advanced:hashconsed} and \fref{fig:expr14}. + +In principle, \mapendo visitors should be created only for immutable data +structures. Although the tool can produce an \mapendo visitor for a mutable +data structure, this is discouraged, as it may lead to unexpected behavior. + +% ------------------------------------------------------------------------------ + +\begin{figure}[p] +\orig{expr15} +\vspace{-\baselineskip} +\processed{expr15} +\caption{A visitor of the \reduce variety} +\label{fig:expr15} +\end{figure} + +\begin{figure}[t] +\codefollowup{expr15} +\origfirstline{expr15b}{3} +\caption{Computing the size of an expression using a \reduce visitor} +\label{fig:reduce} +\end{figure} + +\subsection{\reduce visitors} +\label{sec:intro:reduce} + +Whereas an \iter visitor returns no result and a \map visitor returns a data +structure, a \reduce visitor returns a ``summary'' of a data structure, so to +speak. The summary of a term is computed by combining the summaries of its +subterms. This requires summaries to inhabit a monoid, that is, a type +equipped with a binary operation \oc|plus| and its neutral element \oc|zero|. + +\fref{fig:expr15} shows a \reduce visitor for arithmetic expressions. In +\dataconvisitor{EAdd}, the summaries produced by the two recursive calls are +combined using a call to \oc|self#plus|. In \dataconvisitor{EConst}, there are +no recursive calls, so there is nothing to combine: the result is +\oc|self#zero|. + +The virtual methods \oc|zero| and \oc|plus| are declared in the class +\runtime{reduce}, which is automatically inherited. The type of the +monoid elements, at this point, is undetermined: it is up to the +(user-defined) subclasses of the class \reduce to decide what this type should +be and what the monoid operations should be. + +As an example application, \fref{fig:reduce} shows how to compute the size of +an expression using a \reduce visitor. We inherit the class \reduce. We also +inherit the class \runtime{addition_monoid}, which defines the +methods \oc|zero| and \oc|plus| as the integer \oc|0| and integer addition, +respectively. There remains to override the method \tyconvisitor{expr} so as +to indicate that every node contributes 1 to the size of an expression. + +Incidentally, this code is written in such a manner that a single visitor +object is created initially and serves in every call to the function +\oc|size|. This style can be used when the visitor object is immutable and +when the function that one wishes to define is monomorphic. When it cannot be +used, one begins with \oc|let size (e : expr) : int = ...| and ends with % +\oc|v # visit_expr () e|. That style causes a new visitor object to be created +every time \oc|size| is called. +% On pourrait ré-utiliser le même objet à chaque fois en remettant son champ à +% zéro... Mais ce serait sale et pas ré-entrant. + +The size of an expression can also be computed using an \iter visitor equipped +with mutable state, in the style of \fref{fig:expr04}. It is mostly a matter +of style whether such a computation should be performed using \iter or +\reduce. +% TEMPORARY comparer les perfs, pour voir + +An \iter visitor is in fact a special case of a \reduce visitor, instantiated +with the \oc|unit| monoid. Thus, in principle, one could forget \iter and +always work with \reduce. Nevertheless, it is preferable to work with \iter +when it is applicable, for reasons of clarity and efficiency. +% e.g. an \iter visitor can traverse a list-like data structure in constant +% stack space; a \reduce visitor cannot, because it does not have an accu. + +% One might wonder whether a reduce visitor should have an accumulator... +% ...but then it would be left-to-right-from-the-start, instead of bottom-up. +% I am not sure what we want. Maybe we do not need reduce visitors at all! + +% ------------------------------------------------------------------------------ + +\begin{figure}[p] +\orig{expr_info_mapreduce} +\vspace{-\baselineskip} +\processed{expr_info_mapreduce} +\caption{A visitor of the \mapreduce variety} +\label{fig:mapreduce} +\end{figure} + +\begin{figure}[p] +\codefollowup{mapreduce} +\origfirstline{expr_info_mapreduce_use}{3} +\caption{Decorating every subexpression with its size} +\label{fig:expr_info_mapreduce_use} +\end{figure} + +\subsection{\mapreduce visitors} +\label{sec:intro:mapreduce} + +A \mapreduce visitor performs the tasks of a \map visitor and a \reduce +visitor at once. An example appears in \fref{fig:mapreduce}. Every visitor +method returns a pair of a transformed term and a summary. In other words, +it returns a pair of the results that would be returned by a \map visitor +method and by a \reduce visitor method. + +Like a \reduce visitor, a \mapreduce visitor performs a bottom-up computation. +Like a \map visitor, it constructs a new tree. By default, these two tasks are +independent of one another. However, by overriding one or more methods, it is +easy to establish a connection between them: typically, one wishes to exploit +the information that was computed about a subtree in the construction of the +corresponding new subtree. As an example, \fref{fig:expr_info_mapreduce_use} +shows how to transform an arithmetic expression into an arithmetic expression +where every subexpression is annotated with its size. (This example uses a +parameterized type of decorated expressions, which is explained in +\sref{sec:intro:parameterized:mono}. We suggest reading the explanations there +first.) The transformation is carried out in one pass and in linear time. As +in \fref{fig:reduce}, we use the addition monoid to compute integer sizes. +This time, however, the visitor methods return not just a size, but a pair of +a new expression and a size. The method \tyconvisitor{expr} is overridden so +as to store the size of the subexpression, \oc|size|, in the \oc|info| field +of the new expression. Because the overridden method \tyconvisitor{expr} does +not call \tyconvisitor{'info}, the latter method is never called: we provide a +dummy definition of it. + +Other example applications of \mapreduce visitors include: +\begin{itemize}[nosep] +\item decorating every subterm of a $\lambda$-term with the set of its free + variables; +\item decorating every internal node of abstract syntax tree with a region in + the source code (assuming that every leaf carries such a region already). +\end{itemize} + +% ------------------------------------------------------------------------------ + +\begin{figure}[p] +\orig{expr00fold} +\vspace{-\baselineskip} +\processed{expr00fold} +\caption{A visitor of the \fold variety} +\label{fig:expr00fold} +\end{figure} + +\begin{figure}[p] +\orig{fold} +\caption{Converting towards unrelated types using a \fold visitor} +\label{fig:fold} +\end{figure} + +\subsection{\fold visitors} +\label{sec:intro:fold} + +The varities of visitors presented up to this point differ in the computation +that they perform on the way up, after the recursive calls. As we have seen, +\iter visitors perform no computation at all; \map and \mapendo visitors +reconstruct a term; \reduce visitors perform a series of monoid operations. +Each variety follows a baked-in pattern, which has been programmed ahead of +time, and cannot be changed. What if a different form of computation, which +has not been envisioned by the author of the \visitors syntax extension, is +needed? + +This is where \fold visitors come in. A \fold visitor declares virtual methods +that are called on the way up and can be overridden by the user (in a +subclass) so as to implement the desired computation. \fref{fig:expr00fold} +shows a \fold visitor. Two virtual methods, \dataconascendingmethod{EConst} +and \dataconascendingmethod{EAdd}, are declared. They are invoked by +\tyconvisitor{EConst} and \tyconvisitor{EAdd}, respectively. + +In a \fold visitor, the return type of the visitor methods is not fixed ahead +of time. It is up to the (user-defined) subclasses of the visitor class to +decide what this type should be. + +As an example application, \fref{fig:fold} shows how a \fold visitor can be +used to convert the visited data structure to an entirely different format. In +this example, the type \oc|person| is a record type, whose fields are +\oc|firstname| and \oc|surname|. The type \oc|crowd| is isomorphic to a list +of persons, but, for some reason, it is declared as an algebraic data type +equipped with its own data constructors, \oc|Nobody| and \oc|Someone|. Suppose +we wish to convert a \oc|crowd| to a list of pairs of strings. We can do so by +creating a visitor object that inherits the class \fold and provides concrete +implementations of the methods \tyconascendingmethod{person}, +\dataconascendingmethod{Nobody}, and \dataconascendingmethod{Someone}. +Our implementation of \tyconascendingmethod{person} simply allocates +a pair, while our implementations of +\dataconascendingmethod{Nobody} and \dataconascendingmethod{Someone} +respectively build an empty list and a nonempty list. +Thus, the return type of the methods \tyconascendingmethod{person} +and \tyconvisitor{person} is \oc|string * string|, +while the return type of the methods \dataconascendingmethod{Nobody}, +\dataconascendingmethod{Someone}, and \dataconvisitor{crowd} is +\oc|(string * string) list|. In a \fold visitor, not all methods +need have the same return type! + +If we had chosen to return \oc|f ^ s| instead of \oc|(f, s)| in +\tyconascendingmethod{person}, then a crowd would be converted to +a \oc|string list|. A \fold visitor offers great flexibility. + +All previous varieties of visitors are special cases of \fold visitors. The +specialized varieties of visitors are more convenient to use, when they can be +used, because they do not require the user to provide \tyconascendingmethod{} +methods. Yet, \fold visitors are in principle more versatile.% +% +\footnote{This would be true in an untyped setting, but is not quite true in OCaml, +due to restrictions imposed by OCaml's type discipline (\sref{sec:map_from_fold}).} + +% ppx_tools/genlifter is analogous, with a few differences: +% - it is a command line tool, not as ppx extension; +% - it has only one return type 'res for all methods; +% - the visitor methods receive (as extra arguments) +% the names of the types, data constructors, and record fields +% that are being visited. +% - and there are fewer visitor methods, basically one per type, +% plus one primitive type, plus this#record, this#constr. + +% TEMPORARY show how to do a fold in the presence of primitive types, e.g., list +% writing ancestors = ["VisitorsRuntime.map"] may be necessary + +% ------------------------------------------------------------------------------ + +\begin{figure}[p] +\orig{expr02} +\vspace{-\baselineskip} +\processed{expr02} +\caption{A visitor of the \itertwo variety} +\label{fig:expr02} +\end{figure} + +\begin{comment} +\begin{figure}[p] +\orig{expr03} +\vspace{-\baselineskip} +\processed{expr03} +\caption{A visitor of the \maptwo variety} +\label{fig:expr03} +\end{figure} +\end{comment} + +\subsection{Visitors of arity two} +\label{sec:intro:aritytwo} + +The visitors introduced so far traverse one tree at a time. There are +situations where one wishes to simultaneously traverse two trees, which one +expects have the same structure. For this purpose, one can use a visitor of +arity 2. Every variety except \mapendo is available at arity 2. + +As an illustration, \fref{fig:expr02} shows an \itertwo visitor. There, the +method \tyconvisitor{expr} expects an environment and two expressions. These +expressions must have identical structure: indeed, if \tyconvisitor{expr} +finds that they exhibit different tags at the root, say \oc|EConst| versus +\oc|EAdd|, then it invokes the method \tyconfail{expr}, whose default +implementation calls the function \runtime{fail}. This function +throws the exception \runtime{StructuralMismatch}. + +In \fref{fig:expr02}, we have added the optional parameter +% +\oc|concrete = true| +% +to indicate that the generated class should not be virtual. (By default, +every generated class is declared \oc|virtual|.) We do this because, in +the illustration that follows, we wish to instantiate this class. + +\begin{figure}[p] +\codefollowup{expr02} +\origfirstline{expr05}{3} +\caption{Determining whether two expressions are syntactically equal} +\label{fig:expr05} +\end{figure} + +\begin{figure}[p] +\codefollowup{expr02} +\origfirstline{expr05lexico}{3} +\caption{Determining which way two expressions are ordered} +\label{fig:expr05lexico} +\end{figure} + +As an illustration, in \fref{fig:expr05}, we use an \itertwo visitor to write +a function that tests whether two expressions are syntactically equal. This is +just a matter of performing a synchronous traversal of the two expressions and +detecting a \oc|StructuralMismatch| exception: if this exception is raised, +one must return \oc|false|, otherwise one must return \oc|true|. We rely on +the fact that the method \tyconvisitor{int}, which is inherited from the class +\runtime{iter2}, fails when its two integer arguments are +unequal. + +The convenience functions \runtime{wrap} and +\runtime{wrap2} run a user-supplied function (of arity 1 or 2, +respectively) within an exception handler and return a Boolean result, which +is \oc|true| if no exception was raised. Here, we run the function +% +\oc|new iter2 # visit_expr ()|, whose type is \oc|expr -> expr -> unit|, +in the scope of such a handler. + +Naturally, to test whether two expressions are syntactically equal, one could +also use the primitive equality operator \oc|=|. Alternatively, one could +exploit \ppxderiving and annotate the type definition with +% +\oc|[@@deriving eq]|. Visitors offer greater flexibility: for instance, if our +arithmetic expressions contained variables and binders, we could easily define +an operation that tests whether two expressions are $\alpha$-equivalent. + +As a second illustration, in \fref{fig:expr05lexico}, we use an \itertwo +visitor to write a lexicographic ordering function for expressions. Again, +this involves a synchronous traversal of the two expressions. When a mismatch +is detected, however, one must not raise a \oc|StructuralMismatch| exception: +instead, one must raise an exception that carries one bit of information, +namely, which of the two expressions is strictly ``smaller'' in the ordering. +The exception \oc|Different| is introduced for this purpose; it carries an +integer return code, which by convention is either -1 or +1. Two visitor methods +must be overridden, namely \tyconvisitor{int}, which is in charge of detecting +a mismatch between two integer constants, and \tyconfail{expr}, which is invoked +when a mismatch between (the head constructors of) two expressions is detected. +The auxiliary function \oc|tag| returns an integer code for the head constructor +of an expression. It must be hand-written. One could in principle write such a +function once and for all by using the undocumented operations in OCaml's +\href{https://caml.inria.fr/pub/docs/manual-ocaml/libref/Obj.html}{\oc|Obj|} +module, but that is discouraged. + +% Il faut au minimum distinguer les constructeurs constants des autres, +% en utilisant is_int. Il y a peut-être d'autres pièges. De plus, on ne +% peut pas (je crois?) garantir que l'ordre des constructeurs sera bien +% celui de la déclaration de types, parce que les constructeurs constants +% et les autres sont codés indépendamment. + +% ------------------------------------------------------------------------------ + +\begin{figure}[t] +\orig{expr06} +\caption{Visitors for a family of types} +\label{fig:expr06} +\end{figure} + +\subsection{Visitors for a family of types} +\label{sec:intro:family} + +Visitors can be generated not just for one type definition, but for a family +of type definitions. In \fref{fig:expr06}, we propose a definition of +arithmetic expressions that involves three algebraic data types, namely +\oc|unop|, \oc|binop|, and \oc|expr|. We request the generation of two +visitors, namely an \iter visitor and a \map visitor. This causes the +generation of just two classes, named \iter and \map, respectively. Each of +these classes has visitor methods for every type (namely \tyconvisitor{unop}, +\tyconvisitor{binop}, \tyconvisitor{expr}) and for every data constructor +(namely \dataconvisitor{UnaryMinus}, \dataconvisitor{BinaryMinus}, and so on). + +Note that, for the \derivingvisitors annotation to apply to the entire family, +as opposed to just the type \oc|expr|, the types \oc|unop|, \oc|binop|, and +\oc|expr| in \fref{fig:expr06} are declared simultaneously: that is, their +declarations are separated with the keyword \oc|and|. + +% ------------------------------------------------------------------------------ + +\subsection{Visitors for parameterized types} +\label{sec:intro:parameterized} + +% ------------------------------------------------------------------------------ + +Visitors can be generated for parameterized types, too. However, there are two +ways in which this can be done. Here is why. + +To visit a data type where some type variable~\oc|'a| occurs, one must know +how to visit a value of type~\oc|'a|. +% +% That is not quite true, in reality: perhaps there is no component of +% type~\oc|'a|, perhaps because \oc|'a| is a phantom type parameter or a GADT index, +% or perhaps because \oc|'a| occurs only under a type constructor that performs +% special treatment and does not recursively descend its own components. +% +There are two ways in which this information can be provided. One way is to +assume that there is a \emph{virtual visitor method} \oc|visit_'a| in charge +of visiting a value of type~\oc|'a|. Another way is to pass a \emph{visitor + function} \oc|visit_'a| as an argument to every visitor method. + +% J'allais écrire que dans un cadre non typé, ces deux approches ont la +% même expressivité. Mais c'est faux: seule la seconde approche permet +% de gérer les types de données non réguliers (qui existent aussi dans +% un cadre non typé, même s'ils ne sont pas explicitement décrits par +% une déclaration). + +These two approaches differ in their expressive power. The +virtual-visitor-method approach implies that the visitor methods must have +monomorphic types: roughly speaking, the type variable~\oc|'a| +% (or variants of it) +appears free in the type of every visitor method. +The visitor-function approach implies that the visitor methods can have +polymorphic types: roughly speaking, each method independently +can be polymorphic in \oc|'a|. +For this reason, we refer to these two approaches as the \emph{monomorphic} +approach and the \emph{polymorphic} approach, respectively. + +The monomorphic approach offers the advantage that the type of every method is +inferred by OCaml. Indeed, in this mode, the generated code need not contain +any type annotations. This allows correct, most general (monomorphic) types to +be obtained even in the case where certain hand-written visitor methods +(provided via the \ancestors parameter) have unconventional types. +% +% The downside of this approach is that it does not allow taking several +% distinct instances of a parameterized type. In particular, it is restricted +% to regular algebraic data types (\sref{sec:regularity}). + +The polymorphic approach offers the advantage that visitor methods can receive +polymorphic types. If the type \oc|container| is parameterized with a type +variable~\oc|'a|, then the method \tyconvisitor{container} can be assigned a +type that is universally quantified in~\oc|'a|, of the following form: +% +\begin{mdframed}[backgroundcolor=green!10] +\begin{lstlisting} +method visit_container: + 'env 'a . + ('env -> 'a -> ...) -> + 'env -> 'a container -> ... +\end{lstlisting} +\end{mdframed} +% +The types of the \tyconvisitor{list} methods, shown later on +(\sref{sec:intro:nonlocal}, \fref{fig:convention}), follow this pattern. +% +Because \tyconvisitor{container} is polymorphic, taking multiple instances of +the type \oc|container|, such as \oc|apple| \oc|container| and \oc|orange| +\oc|container|, and attempting to generate visitor methods for these types, +poses no difficulty. This works even if the definition of \oc|'a container| +mentions other instances of this type, such as \oc|('a * 'a)| \oc|container|. +In other words, in the polymorphic approach, irregular algebraic data types +(\sref{sec:regularity}) are supported. + +One downside of the polymorphic approach is that, because polymorphic types +cannot be inferred by OCaml, the \visitors syntax extension must generate +polymorphic type annotations. Therefore, it must be able to predict +the type of every visitor method. +% +% Actually, not the full type, but at least the polymorphic skeleton. +% +This requires that any visitor methods inherited via \ancestors adhere to a +certain convention (\refconvention). + +In summary, both the monomorphic approach and the polymorphic approach are +currently supported (\sref{sec:intro:parameterized:mono}, +\sref{sec:intro:parameterized:poly}). The parameter \polymorphic allows +choosing between them. As a rule of thumb, we suggest setting +% +\oc|polymorphic = true|, as this produces visitors that compose better. + +% TEMPORARY give an explanation why monomorphic mode can be useful? + +% In my ICFP paper, I believe monomorphic mode is necessary to deal with ['bn] +% and ['env]. Indeed, we cannot expect [visit_abs] to be polymorphic in ['bn] +% and ['env], as it needs to be told how to [extend] an environment with a +% bound name. + +% Other examples? + +% ------------------------------------------------------------------------------ + +\begin{figure}[p] +\orig{expr_info} +\vspace{-\baselineskip} +\processed{expr_info} +\caption{A ``monomorphic-method'' visitor for a parameterized type of decorated expressions} +\label{fig:expr_info} +\end{figure} + +\begin{figure}[p] +\codefollowup{expr_info} +\origfirstline{expr_info_use}{3} +\caption{Working with different types of decorations} +\label{fig:expr_info_use} +\end{figure} + +\subsubsection{Monomorphic visitor methods for parameterized types} +\label{sec:intro:parameterized:mono} + +We begin with an example of the \emph{monomorphic} mode. This mode can be +explicitly requested by writing \oc|polymorphic = false| as part of the +\derivingvisitors annotation. It is the default mode. + +In \fref{fig:expr_info}, we define a variant of arithmetic +expressions where every tree node is decorated with a value of type +\oc|'info|. We request the generation of a \map visitor, whose code is shown +in the second part of \fref{fig:expr_info}. The generated code has exactly the +same structure as in the previous sections. The only new feature is that the +class \map now has a virtual method, \tyconvisitor{'info}. The general rule +is, for each type parameter, there is one virtual method, named after it. + +The visitor methods are \emph{not} declared polymorphic in a type +variable~\oc|'info|, or in two type variables \oc|'info1|~and~\oc|'info2|, as +one might perhaps expect. In fact, they must not be declared polymorphic: +indeed, the user who implements \tyconvisitor{'info} in a subclass of \map may +wish to provide an implementation that expects and/or produces specific types +of information. + +As a result, a visitor \emph{object} is monomorphic: its method +\tyconvisitor{'info} must have type \oc|info1 ->| \oc|info2| for certain +specific types \oc|info1| and \oc|info2|. Fortunately, because it is +parameterized over \oc|'self|,\footnote{We explain in \sref{sec:oo:self} why + all visitor classes are parameterized over \oc|'self|.} the visitor +\emph{class} is polymorphic: two distinct visitor objects can have distinct +types. + +Although every \emph{automatically generated} method +is monomorphic, a visitor class can nevertheless \emph{inherit} polymorphic +methods from a parent class, whose name is specified via the \ancestors parameter +(\sref{sec:ancestors}). For instance, the \tyconvisitor{list} methods provided by +the classes \runtime{iter}, \runtime{map}, and so on, are +polymorphic in the types of the list elements. (See \sref{sec:intro:nonlocal} +for more information on the treatment of preexisting types.) + +\fref{fig:expr_info_use} presents two example uses of the class \map defined in +\fref{fig:expr_info}. In the first example, we define a function \oc|strip|, of +type \oc|'info expr -> unit expr|, which strips off the decorations in an +arithmetic expression, replacing them with unit values. In the second example, +we define a function \oc|number|, of type \oc|'info expr -> int expr|, which +decorates each node in an arithmetic expression with a unique integer number.% +\footnote{Because the \oc|info| field appears before the \oc|node| field in + the definition of the type \oc|expr|, and because fields are visited + left-to-right, we get a prefix numbering scheme. By exchanging these fields, + we would get postfix numbering.} % + +% ------------------------------------------------------------------------------ + +\subsubsection{Polymorphic visitor methods for parameterized types} +\label{sec:intro:parameterized:poly} + +\begin{figure}[p] +\orig{expr_info_polymorphic} +\vspace{-\baselineskip} +\processed{expr_info_polymorphic} +\caption{A ``polymorphic-method'' visitor for a parameterized type of decorated expressions} +\label{fig:expr_info_polymorphic} +\end{figure} + +\begin{figure}[p] +\codefollowup{expr_info_polymorphic} +\origfirstline{expr_info_polymorphic_use}{3} +\caption{Working with different types of decorations} +\label{fig:expr_info_polymorphic_use} +\end{figure} + +We continue with an example of the \emph{polymorphic} mode. This mode can be +explicitly requested by writing \oc|polymorphic = true| as part of the +\derivingvisitors annotation. It is available for all varieties of visitors +except \fold and \foldtwo. The reason why it seems difficult to come up with +a satisfactory polymorphic type for \fold visitor methods is explained later +on (\sref{sec:map_from_fold}). + +In \fref{fig:expr_info_polymorphic}, we again have arithmetic expressions +where every tree node is decorated with a value of type \oc|'info|. We again +request a \map visitor but, this time, we specify \oc|polymorphic = true|. +% +In order to make the generated code shorter, we specify \oc|data = false| +(\sref{sec:params}), which causes the methods \dataconvisitor{EConst} and +\dataconvisitor{EAdd} to disappear. (They are inlined at their call sites.) + +The generated code is the same as in the previous section, +% except the methods \dataconvisitor{EConst} and \dataconvisitor{EAdd} have +% disappeared, as explained above, and +except that \tyconvisitor{'info} is not a method any more. Instead, it is +a function, which is passed as an argument to every visitor method. + +% Because \tyconvisitor{'info} is a function, as opposed to a virtual method, +The class \map does not have any virtual methods. It can thus be declared as +concrete class: to this end, we specify +% +\oc|concrete = true| (\sref{sec:params}). Without this indication, it would be +declared \oc|virtual|. + +Because \tyconvisitor{'info} is an argument of every visitor method, +every visitor method can be declared polymorphic in the type variables~\oc|'env|, +\oc|'info_0| and \oc|'info_1|, +where the function \tyconvisitor{'info} has type \oc|'env -> 'info_0 -> 'info_1|. +% +The fact that we would like every method to have a polymorphic type cannot +be inferred by OCaml. For this reason, the generated code contains explicit +polymorphic type annotations. + +\fref{fig:expr_info_polymorphic_use} presents two example uses of the class +\map defined in \fref{fig:expr_info_polymorphic}. As in +\fref{fig:expr_info_use}, we define two functions \oc|strip| and \oc|number|. +A striking feature of this code is that a single visitor object~\oc|v| is now +allocated, once and for all, and is used in every subsequent call to \oc|strip| +and \oc|number|. The two \tyconvisitor{'info} functions are also defined once +and for all.% +% +\footnote{Although we have nested these functions inside the definitions of + \oc|strip| and \oc|number|, they are closed, so they could be hoisted out to + the top level, if desired.} + +In the definition of \oc|number|, we choose to store the current count in a +reference, \oc|count|, and to let \oc|count| play the role of the +``environment''. Thus, we initially pass \oc|count| to \tyconvisitor{expr}, +and \tyconvisitor{'info} receives \oc|count| as its ``environment'' argument. + +%% + +The polymorphic type annotations that are automatically generated +(\fref{fig:expr_info_polymorphic}) follow a certain fixed convention. If the +user throws in hand-written visitor methods via the \ancestors parameter, then +those hand-written methods must adhere to the same convention (or the +generated code would be ill-typed). This convention is illustrated in the next +section (\sref{sec:intro:nonlocal}) with the example of the +\tyconvisitor{list} methods. + +A type variable is not allowed to occur under an \oc|[@opaque]| annotation +(\sref{sec:opaque}). Indeed, annotating a type variable~\oc|'a| with +\oc|[@opaque]| would cause special-purpose visit code to be generated, whose +type is not as polymorphic as required by the above convention. + +%% + +% We might wish to document that the type variable names \oc|'s| and \oc|'env| +% are reserved. + +% ------------------------------------------------------------------------------ + +% At the moment, the following feature is considered experimental and +% undocumented: + +\begin{comment} + +\subsubsection{Mixing the monomorphic and polymorphic modes} +\label{sec:intro:parameterized:fine} + +It is possible to mix the monomorphic and polymorphic modes +(\sref{sec:intro:parameterized:mono}, \sref{sec:intro:parameterized:poly}) in +a single generated visitor class. Suppose we wish to generate a visitor class +for the type \oc|('a, 'b) dictionary|. Suppose, for some reason, that we would +like \tyconvisitor{'a} to be a virtual visitor method and \tyconvisitor{'b} to +be a visitor function, which is passed as an argument to +\tyconvisitor{dictionary}. This can be achieved by declaring +% +\oc|polymorphic = ["'b"]| as part of the \derivingvisitors annotation. + +% The user can control whether the visitor methods are polymorphic in \oc|'env|. +% This is done by including (or not including) \oc|'env| in the list. +% (The type variable \oc|'env| is reserved.) + +\end{comment} + +% ------------------------------------------------------------------------------ + +\begin{figure}[t] +\orig{expr11} +\vspace{-\baselineskip} +\processed{expr11} +\caption{Using preexisting (parameterized) types, such as \oc|int| and \oc|list|} +\label{fig:expr11} +\end{figure} + +\input{convention} + +\subsection{Dealing with references to preexisting types} +\label{sec:intro:nonlocal} + +A type definition can contain references to the types that are being defined, +also known as \emph{local} types. For instance, in \fref{fig:expr00}, the +definition of \oc|EAdd| contains two references to a local type, namely +\oc|expr|. + +A type definition can also contain references to preexisting types, also +known as \emph{nonlocal} types. For instance, in \fref{fig:expr00}, the +definition of \oc|EConst| contains a reference to a nonlocal type, namely +\oc|int|, which happens to be one of OCaml's primitive types. In +\fref{fig:expr11}, the definition of \oc|EAdd| contains a reference to a +parameterized nonlocal type, namely \oc|list|, which happens to be defined in +OCaml's standard library. + +The treatment of local types has been illustrated in the previous sections. In +short, for every local type, a visitor method is called, and is defined: +for instance, for the local type \oc|expr|, we define the (concrete) method +\tyconvisitor{expr}. + +The treatment of nonlocal types is the same, except the visitor method is not +defined, nor declared. That is, it is called, but is neither defined (as a +concrete method) or declared (as a virtual method). Therefore, its definition +must be provided by an ancestor class. + +For most of OCaml primitive or built-in types, support is provided by the +module \oc|VisitorsRuntime|. This module contains several classes named +\oc|iter|, \oc|map|, and so on; each of them supplies methods named +\tyconvisitor{int}, \tyconvisitor{list}, and so on.% +% +\footnote{As an exception to this rule, the classes \runtime{fold} + and \runtime{fold2} do not supply any methods, because we do not + wish to prematurely fix the types of the visitor methods. Please consult + \runtimeFile{VisitorsRuntime.ml} to check which methods exist and what they + do.} % +% +As is evident in Figures~\ref{fig:expr00}, \ref{fig:expr01}, and so on, the +generated visitor automatically inherits from the appropriate class in +\oc|VisitorsRuntime|, so it receives default implementations of the methods +\tyconvisitor{int}, \tyconvisitor{list}, and so on. + +The visitor methods for parameterized data types (\oc|array|, \oc|Lazy.t|, +\oc|list|, \oc|option|, \oc|ref|, \oc|result|) are polymorphic, so it is not a +problem if both lists of apples and lists of oranges need to be traversed. +The types of these methods follow a strict \emph{convention}, +illustrated in \fref{fig:convention} with the example of \tyconvisitor{list}. + +The \tyconvisitor{list} methods in the classes \runtime{iter}, \runtime{map}, +and so on, have been hand-written, but could equally well have been generated, +with \oc|polymorphic = true|: their types would be the same. +% +% The code would not be the same. At the moment, we are using List.fold_left +% instead of a natural fold. +% +This illustrates the fact that, with \oc|polymorphic = true|, +\emph{visitors are compositional}. +% +% With \oc|polymorphic = false|, visitors are compositional, too, +% but only for non-parameterized types. +% +That is, if the definition of the type \oc|'b bar| refers to the type \oc|'a foo|, +then one can \emph{separately} generate a visitor class for \oc|'a foo| +and generate a visitor class for \oc|'b bar|, which inherits the previous class. +% There is no need to generate a single visitor class for \oc|'a foo| and +% \oc|'b bar| at once. + +At a primitive type, it is advisable to carefully consider what +behavior is desired. On the one hand, perhaps the inherited method +\tyconvisitor{int} need not be invoked in the first place; this behavior can +be obtained by using \oc|(int[@opaque])| instead of \oc|int|. (See +\sref{sec:opaque} for details.) This is done, for instance, in +\fref{fig:expr15}, where one can check that no call to \tyconvisitor{int} is +generated. On the other hand, when one decides to use an inherited method, one +should make sure that one understands its behavior. The methods +\tyconvisitor{array} and \tyconvisitor{ref} in the class +\runtime{map}, for instance, perform a copy of a mutable memory +block: one should be aware that such a copy is taking place. If this behavior +is undesirable, it can be overridden. + +It is possible to inherit as many classes as one wishes, beyond those defined +in \oc|VisitorsRuntime|. This is done via the \ancestors parameter +(\sref{sec:ancestors}). It is also possible to \emph{not} inherit any methods +from \oc|VisitorsRuntime|. This is done via the \nude parameter +(\sref{sec:ancestors}). + +% ------------------------------------------------------------------------------ + +\subsection{Generating visitors for preexisting types} +\label{sec:import} + +Because the \derivingvisitors annotation must be attached to the type +definition, it may seem as if it is impossible to generate a visitor for a +type whose definition is out of reach. Suppose, for instance, that the type +\oc|expr| of arithmetic expressions is defined in a module \oc|Expr|, which, +for some reason, we cannot modify. Can we generate a visitor for this type? + +Fortunately, the answer is positive. The basic trick, documented in the +\href{https://github.com/whitequark/ppx_deriving/#working-with-existing-types} +{\texttt{ppx\_deriving} \textsc{readme}}, +consists in defining a new type \oc|expr| of arithmetic expressions and to +explicitly declare that it is equal to the preexisting type \oc|Expr.expr|, +as follows. + +\orig{expr_redef} + +As can be seen above, the new definition of \oc|expr| can be annotated with +\derivingvisitors, yielding a visitor for the new type \oc|expr|, which by +definition, is equal to the preexisting type \oc|Expr.expr|. Thus, this +visitor class be used to traverse expressions of type \oc|Expr.expr|. + +This approach works, but requires repeating the definition of the type \oc|expr|. +This duplication can be eliminated thanks to the \ppximport syntax extension, +as follows: + +\orig{expr_import} + +This expands to the code shown previously. (To use this syntax extension, +assuming you are using \ocamlbuild and \ocamlfind, just add the line +\texttt{true: package(ppx\_import)} to your \texttt{\_tags} file.) As icing on +the cake, \ppximport allows decorating the type definition, on the fly, with +new attributes. In the following examples, we replace all occurrences of +\oc|int| with \oc|int[@opaque]| (\sref{sec:opaque}), so as to ensure that the +generated visitor does not invoke the method \tyconvisitor{int}: + +\orig{expr_import_opaque} + +% ------------------------------------------------------------------------------ +% ------------------------------------------------------------------------------ + +\section{Advanced examples} +\label{sec:advanced} + +% ------------------------------------------------------------------------------ + +\begin{figure}[p] +\orig{expr12} +\vspace{-\baselineskip} +\processed{expr12} +\caption{An open type of arithmetic expressions} % and a visitor for it +\label{fig:expr12} +\end{figure} + +\begin{figure}[p] +\codefollowup{expr12} +\origfirstline{expr13}{3} +\caption{A closed type of arithmetic expressions} +\label{fig:expr13} +\end{figure} + +\begin{figure}[p] +\codefollowup{expr12} +\origfirstline{expr08}{3} +\caption{A closed type of hash-consed arithmetic expressions} +\label{fig:expr08} +\end{figure} + +\subsection{Visitors for open and closed data types} +\label{sec:advanced:openclosed} + +The algebraic data types of arithmetic expressions shown in the previous +section (\sref{sec:intro}) are \emph{closed}. That is, the type \oc|expr| +is recursive: an expression of type \oc|expr| has subexpressions of type +\oc|expr|. + +It is often desirable, for greater flexibility, to first define an \emph{open} +type of arithmetic expressions. Such a type, say \oc|oexpr|, is parameterized +over a type variable~\oc|'expr|. It is not recursive: an expression of type +\oc|'expr oexpr| has subexpressions of type \oc|'expr|. It is shown in +\fref{fig:expr12}. Naturally, we may request the generation of visitors for +the type \oc|oexpr|. In \fref{fig:expr12}, we generate a class of \map +visitors, which we name \oc|omap|. (This is an example of using an explicit +\name parameter.) As explained earlier (\sref{sec:intro:parameterized:mono}), +because the type \oc|oexpr| is parameterized over the type variable +\oc|'expr|, the visitor class has a virtual method, \tyconvisitor{'expr}. +% +In this example, we use the monomorphic mode (\sref{sec:intro:parameterized:mono}), +but could just as well use the polymorphic mode (\sref{sec:intro:parameterized:poly}): +this is left as an exercise for the reader. + +A closed (recursive) type of expressions, \oc|expr|, can then be defined in +terms of \oc|expr|. This is done in \fref{fig:expr13}. In type-theoretical +terms, one would like to define \oc|expr| as the fixed point of the functor +\oc|oexpr|~\cite{milewski-13}. +% +That is, roughly speaking, one would like to define \oc|type expr = expr oexpr|. +This is not accepted by OCaml, though;% +% +\footnote{It would be accepted by OCaml with the command line switch + \texttt{-rectypes}, which instructs the typechecker to tolerate + equirecursive types. However, this is not a good idea, as it causes + the typechecker to suddenly accept many meaningless programs and infer + bizarre types for them.} +% +we work around this limitation by making \oc|expr| an algebraic data type +whose single data constructor is named~\oc|E|.% +% +\footnote{We mark this algebraic data type \oc|[@@unboxed]|, which (as of + OCaml 4.04) guarantees that there is no runtime cost associated with the + data constructor~\oc|E|. Although \oc|expr| and \oc|expr oexpr| are + considered distinct types by the OCaml typechecker, they have the same + runtime representation.} + +Let us now construct a visitor class for the type \oc|expr|. It is easy to +do so, by hand, in a few lines of code.% +% +% \footnote{We could request the generation of a visitor class via a +% \oc|[@@deriving]| annotation. However, the type \oc|oexpr| would then be +% viewed as nonlocal; therefore, in the generated code, the method +% \tyconvisitor{oexpr} would be applied to \oc|self#visit_expr|, a +% parameter which it does not expect.} +% +% Also, we would have to inherit from \oc|omap|, but that would cause us +% to inherit twice from \runtime{map}, causing warnings. +% +We define a class \oc|map|, a subclass of \oc|omap|, and provide a concrete +implementation of the virtual method \tyconvisitor{'expr}. In the definition +of the type \oc|expr|, the type variable \oc|'expr| is instantiated with +\oc|expr|, so the method \tyconvisitor{'expr} expects an argument of type +\oc|expr| and must return a result of type \oc|expr|. We deconstruct the +argument using the pattern \oc|E e|. Therefore, the variable \oc|e| has type +\oc|expr oexpr| and is a suitable argument to the method \tyconvisitor{oexpr}. +After this call, we perform the same step in reverse: the result of the call +has type \oc|expr oexpr|, so we wrap it in an application of the data +constructor~\oc|E| and obtain a result of type \oc|expr|. + +The visitor class \oc|map| can now be used to implement transformations of +arithmetic expressions, that is, functions of type \oc|expr -> expr|. As an +example, let us implement a transformation whose effect is to double every +integer constant in an arithmetic expression. This is done in +\fref{fig:expr13double}. As expected, it suffices to construct a visitor +object that inherits \oc|map| and overrides the method +\dataconvisitor{EConst}. + +% ------------------------------------------------------------------------------ + +\begin{figure}[p] +\codefollowupgeneral{Figures~\ref{fig:expr12} and \ref{fig:expr13}} +\origfirstline{expr13double}{4} +\caption{A transformation of ordinary arithmetic expressions} +\label{fig:expr13double} +\end{figure} + +\begin{figure}[p] +\codefollowupgeneral{Figures~\ref{fig:expr12} and \ref{fig:expr08}} +\origfirstline{expr08double}{4} +\caption{A transformation of hash-consed arithmetic expressions} +\label{fig:expr08double} +\end{figure} + +\begin{figure}[p] +\codefollowupgeneral{Figures~\ref{fig:expr12}, \ref{fig:expr13}, and~\ref{fig:expr08}} +\origfirstline{expr14}{6} +\caption{Conversions between ordinary and hash-consed arithmetic expressions} +\label{fig:expr14} +\end{figure} + +\subsection{Visitors for hash-consed abstract syntax trees} +\label{sec:advanced:hashconsed} + +On top of the open data type \oc|oexpr| of the previous section +(\sref{sec:advanced:openclosed}), one can define not just the closed data type +\oc|expr| of ordinary arithmetic expressions, but also other closed data types +of expressions where every node is annotated with information. + +As an example, let us define a type \oc|hexpr| of hash-consed (that is, +maximally-shared) arithmetic expressions. We use Filliâtre and Conchon's +library~\cite{filliatre-conchon-06}, which can be found in \opam under the +name \hashcons. + +The definition of the type \oc|hexpr| appears in \fref{fig:expr08}. It is +analogous to the definition of the type \oc|expr| (\fref{fig:expr13}), with an +added twist: instead of taking the fixed point of the functor \oc|_ oexpr|, we +take the fixed point of the functor \oc|_ oexpr hash_consed|. By looking up +the definition of the type \oc|hash_consed| in \hashconsRepoFile{hashcons.mli}, +one finds that this means that every node in an arithmetic expression carries +certain information (namely a unique tag and a hash) that are used to enforce +maximal sharing. + +Enforcing maximal sharing requires maintaining a mutable table where all +arithmetic expressions ever constructed are stored. (This is in fact a weak +hash table.) We initialize such a table by calling the function +\oc|Hashcons.create|. This table is then populated by the function \oc|h|, a smart +constructor. +% of type \oc|hexpr oexpr -> hexpr|. +This function takes a candidate expression of type \oc|hexpr oexpr| and +returns an expression of type \oc|hexpr|, which is either allocated anew +or found in the table (should an identical expression already exist). + +We can now construct a visitor class for the type \oc|hexpr|. As in the previous +section (\sref{sec:advanced:openclosed}), we do so by hand in a few lines of code. +% +% Our reasons for writing this code by hand are the same as in the previous +% section. Furthermore, we note that the code of the visitor refers to the +% function~\oc|h|, thus depends on \oc|table|. The definition of \oc|table| +% itself must come after the definition of the type \oc|hexpr|, since the +% type of \oc|table| is \oc|hexpr oexpr Hashcons.t|. For this reason, we +% cannot use [@@deriving] to generate the visitor just after the type +% definition. +% +% That said, since the visitor depends on \oc|h| and not directly on \oc|table|, +% we could cut the dependency by going through the store. Create a reference to +% a function of type \oc|hexpr oexpr -> hexpr|. Initialize it with a dummy +% function. Generate the visitor. Then, create the table, define \oc|h| and +% update the reference. Ugh. +% +The overall structure of this code is the same as in \fref{fig:expr13}. The +only difference is that the method \tyconvisitor{'expr} must now traverse +two levels of type structure, corresponding to \oc|_ oexpr hash_consed|. +It deconstructs this structure by using the pattern \oc|H { node = e ; _ }|,% +% +\footnote{The \oc|node| field is part of the record type \oc|hash_consed|; +see \hashconsRepoFile{hashcons.mli}.} +% +and reconstructs it by applying the smart constructor~\oc|h|. + +A function \oc|double| can be defined for hash-consed arithmetic expressions +in exactly the same manner as we defined \oc|double| for ordinary arithmetic +expressions: compare \fref{fig:expr13double} and \fref{fig:expr08double}. +% +% In fact, although we did not attempt to share the code of the method +% \dataconvisitor{EConst} between these two figures, one could do so if +% desired, by exploiting multiple inheritance. +% + +The visitor class \oc|omap| for open arithmetic expressions +(\fref{fig:expr12}) can be exploited to define conversions +between different types of arithmetic expressions. +This is illustrated in \fref{fig:expr14}. +There, the function \oc|import| converts an ordinary expression +to a hash-consed expression, thereby imposing maximal sharing. +Conversely, the function \oc|export| converts a hash-consed +expression into an ordinary expression, thereby abandoning +all sharing (and possibly causing an exponential explosion). +The implementation of these functions is simple: it is just +a matter of overriding \tyconvisitor{'expr} so as to deconstruct +one kind of expression and reconstruct the other kind. + +% ------------------------------------------------------------------------------ + +\subsection{From visitors to iterators} +\label{sec:iterators} + +It is possible to use a visitor to implement an iterator, that is, an object +that traverses a container data structure and produces its elements on demand. +The story is told in a blog post~\cite{iterators}. + +% ------------------------------------------------------------------------------ +% ------------------------------------------------------------------------------ + +\section{Little-known aspects of OCaml objects} +\label{sec:oo} + +In this section, we document a few relatively little-known aspects of OCaml's +class and object system that play an essential role in our visitors. + +% ------------------------------------------------------------------------------ + +\subsection{Type inference for concrete and virtual methods} +\label{sec:oo:infer} + +It is well-known that OCaml can infer the type of a concrete method. In the +following simple example, it infers that the field \oc|x| has type \oc|int| +and that (therefore) the methods \oc|get| and \oc|set| must have types +\oc|int| and \oc|int -> unit|, respectively: +% +\orig{OOinfer} + +It is perhaps lesser known that \emph{OCaml can also infer the type of a + virtual method}, based on the manner in which this method is used. In the +following variant of the previous example, it infers that the method +\oc|check| must have type \oc|int -> int|, as it receives an integer argument +and produces a result that is stored in the field \oc|x|. +% +\orig{OOinfervirtual} + +The type annotation \oc|_| that appears in the declaration of the method +\oc|check| stands for an unconstrained type variable. It lets the OCaml +typechecker infer a most general monomorphic type for this method. +A~polymorphic type cannot be inferred. If we wished for the method \oc|check| +to have type \oc|'a . 'a -> 'a|, then we would have to explicitly annotate the +declaration with this polymorphic type. + +% ------------------------------------------------------------------------------ + +\subsection{Virtues of self-parameterized classes} +\label{sec:oo:self} + +Popular belief holds that inferring a method's type fails if ``some type +variables are unbound in this type''. For instance, in the following variant +of the previous example, OCaml infers that the method \oc|check| has type +\oc|'a -> int|, where the type variable \oc|'a| is unconstrained: +% +\orig{OOinfererror} + +At that point, it fails with a type error message: +% +\begin{mdframed}[backgroundcolor=red!10] +\begin{lstlisting}[keywords={}] +Error: Some type variables are unbound in this type: + class virtual int_cell : + object + val mutable x : int + method virtual check : 'a -> int + method get : int + method set : 'a -> unit + end +The method check has type 'a -> int where 'a is unbound +\end{lstlisting} +\end{mdframed} + +In this case, the OCaml manual says, ``the class should be parametric'', and +``the type parameters must be [subject] somewhere in the class body to a type +constraint''. In the above example, one might choose to parameterize the class +over a type variable~\oc|'a| and to add a type annotation that requires +\oc|'a| to be the domain of the virtual method \oc|check|: +% +\orig{OOinferfixed} + +This eliminates the type error: this code is well-typed. One problem with this +approach, though, is that further changes to the code might require +introducing further type parameters. Suppose for instance that, instead of +initializing the field~\oc|x| with the value \oc|0|, we wish to parameterize +the class over an initial value~\oc|init|. We modify the code as follows: +% +\orig{OOinfererroragain} + +Unfortunately, this modification makes the code ill-typed again: +% +\begin{mdframed}[backgroundcolor=red!10] +\begin{lstlisting}[keywords={}] +Error: Some type variables are unbound in this type: + class virtual ['a] cell : + 'b -> + object + val mutable x : 'b + method virtual check : 'a -> 'b + method get : 'b + method set : 'a -> unit + end +The method check has type 'a -> 'b where 'b is unbound +\end{lstlisting} +\end{mdframed} + +A natural reaction to this type error message might be to parameterize the +class over both \oc|'a| and \oc|'b|, as follows: +% +\orig{OOinferfixedagain} + +This eliminates the type error: this code is well-typed. However, it seems +unfortunate that one cannot depend on the typechecker to infer the types of +all methods. Instead, it seems that one must introduce an unpredictable number +of type parameters, as well as an unpredictable amount of explicit type +annotations, for the code to be accepted. + +Fortunately, there is a solution to this problem. + +Let us first note that, in the above example, even though both the argument +type and result type of the method \oc|check| are undetermined, \emph{it is + not necessary to introduce two type parameters} \oc|'a| and~\oc|'b|. Indeed, +one type parameter suffices, provided this parameter determines both the +argument type and result type of \oc|check|. To illustrate this, let us +parameterize the class over a type variable \oc|'check|, and provide a type +annotation that equates \oc|'check| with the type of the method \oc|check|: +% +\orig{OOinferfixedagaincheck} + +This code is well-typed, too. Its inferred type is as follows: +% +\begin{mdframed}[backgroundcolor=green!10] +\begin{lstlisting} +class virtual ['check] cell : + 'b -> + object + constraint 'check = 'a -> 'b (* a type equation *) + val mutable x : 'b + method virtual check : 'check + method get : 'b + method set : 'a -> unit + end +\end{lstlisting} +\end{mdframed} + +Because the typechecker infers and records the type equation % +\oc|'check = 'a -> 'b|, instantiating the type variable~\oc|'check| with a +concrete type suffices to determine the values of both~\oc|'a| and~\oc|'b|. +For instance, if~\oc|'check| is instantiated with \oc|float -> int|, then +\oc|'a| must be \oc|float| and \oc|'b| must be \oc|int|. For this reason, +there is no need to parameterize the class over \oc|'a| and~\oc|'b|. +Parameterizing it over \oc|'check| suffices. + +This remark alone does not quite solve our problem yet. It still seems as if, +for a class definition to be accepted, one must introduce an unpredictable +number of type parameters, as well as an unpredictable amount of explicit type +annotations and/or type equations. + +Fortunately, there is a general way out of this problem. In fact, \emph{one + type parameter always suffices}. The trick is to constrain this type +parameter to be the type of ``self''. Indeed, in OCaml, the type of ``self'' +is an OCaml object type that lists the names and types of all (public) +methods. Therefore, fixing the type of ``self'' is enough to determine the +type of every method. + +% A curious remark: even though the private methods do not appear in the type +% of self, OCaml still allows their types to contain unconstrained type +% variables. For instance, the following is allowed, with and without +% self-parameterization: +% +% class virtual foo = object +% method private virtual f: _ +% end +% +% class virtual ['self] foo = object (_ : 'self) +% method private virtual f: _ +% end + +We modify the example as follows. We parameterize the class over a single type +variable, named \oc|'self|, which we constrain to be the type of ``self'', via +the type annotation \oc|self : 'self|. +% +\orig{OOinferself} + +Even though, this time, we have not given the type of the method \oc|check|, +this code is well-typed. \emph{In~a self-parameterized OCaml class, a + monomorphic type can be inferred for every method}, be it concrete or +virtual. In other words, in~a self-parameterized class, the OCaml typechecker +never complains that ``some type variables are unbound''. + +In the \visitors package, this remark solves several problems. First, we never +need to wonder how many type parameters a class should have, and what they +should be: the answer is always one, namely \oc|'self|. Second, we never need +to annotate a method with its type: every virtual method can be annotated with +the wildcard \oc|_|. These properties are of utmost importance, as we cannot +in general predict the types of the generated methods. + +Since self-parameterized classes seem so great, one may wonder whether, in +everyday life, it would be a good idea to parameterize every class over +\oc|'self| in this manner. The answer is, it probably would not. Such an +approach leads to verbose class types, as the type of ``self'' contains a list +of all (public) methods. It also gives rise to recursive object types, of the +form \oc|'self c as 'self|, where \oc|c| is a class. + +% ------------------------------------------------------------------------------ + +\subsection{Simplifying the type of a self-parameterized class} +\label{sec:oo:monomorphic} + +We have used in \sref{sec:intro:type} a few rules that allow an inferred class +type to be manually simplified. In going from \fref{fig:inferred} to +\fref{fig:simplified}, we have used the well-known property that private +methods can be omitted in a class type. We have also exploited the perhaps +lesser-known fact that, in a self-parameterized class, the constraint that +bears on the type parameter \oc|'self| can be omitted, as it is implicit in +OCaml that the type of ``self'' must be an object type that lists the public +methods. + +There remains to explain the surprising use of the ``\oc|'monomorphic.|'' prefix +in \fref{fig:simplified}. On the face of it, this is a universal +quantification over a type variable, named \oc|'monomorphic|, which does +\emph{not} appear in the type of the method. From a purely logical standpoint, +such a universal quantification should be superfluous. Yet, here, it is +required, due to the following peculiarity of OCaml~\cite{ocaml7465}: +\begin{quote} + In a class type, + if the type of a method exhibits a free variable~\oc|'a|, + if this method type has no explicit universal quantifiers, + and if the type variable~\oc|'a| does not appear in an explicit type constraint, + then, by convention, + OCaml considers that the method type is universally quantified in \oc|'a|. + % Personal communication with Jacques Garrigue. + % https://caml.inria.fr/mantis/view.php?id=7465 +\end{quote} +We must work around this syntactic convention: in \fref{fig:inferred}, for +instance, the method \tyconvisitor{expr} has monomorphic type % +\oc|'env -> expr -> unit|, where the type variable \oc|'env| is connected with +\oc|'self| via an implicit constraint and (like \oc|'self|) is quantified at +the level of the class. This method does \emph{not} have polymorphic type % +\oc|'env. 'env -> expr -> unit|. The logically redundant quantification over +\oc|'monomorphic| serves as a syntactic mark that we really intend the type +variable~\oc|'env| to appear free in the method type. + +% ------------------------------------------------------------------------------ + +\subsection{Monomorphic methods, polymorphic classes} + +Even if a method is monomorphic, the class that contains this method can be +polymorphic. In the following example, the \oc|identity| method is annotated +with a monomorphic type, which implies that, if \oc|o| is an object of +class~\oc|c|, then the method \oc|o#identity| cannot be applied both to apples +and to oranges. However, the class~\oc|c| is polymorphic, which means that two +distinct instances of this class can be used (separately) with apples and with +oranges. +\begin{origenv} +\lstinputlisting{polyclass.ml} +\end{origenv} +This (well-known) property of classes is exploited in the \visitors package. +Although (in monomorphic mode, \sref{sec:intro:parameterized:mono}) every +generated visitor method is monomorphic, the visitor classes are +polymorphic, so (distinct) visitor objects can be used at many different +types. + +% ------------------------------------------------------------------------------ + +% This subsection is mostly obsolete now that we have [polymorphic] mode, +% so I am removing it. + +\begin{comment} + +\subsection{Customization from above and from below} + +In the object-oriented world, a traditional way of ensuring that a piece of +code has customizable behavior is to write it in the form of a class with many +(concrete or virtual) methods. These methods can later be overridden in a +subclass: this is ``customization from below''. + +When the class is automatically generated, as is the case of our visitor +classes, another approach to customization is to let the user choose which +classes should be inherited: this is done via the \ancestors parameter +(\sref{sec:params}). This is ``customization from above''. It is a somewhat +more unusual customization mechanism. + +As the (concrete and virtual) methods that we generate must be monomorphic, +customization from below is restricted, in our situation, to providing +monomorphic code fragments. Fortunately, no such restriction bears on +customization from above: a parent class can provide (hand-written) +polymorphic methods. + +For this reason, customization from above plays a key role in our setting. For +instance, the methods \oc|visit_array|, \oc|visit_list|, and so on, which must +be polymorphic, must be hand-written, and must be inherited from a parent +class. The asymmetry between hand-written methods (which may be polymorphic) +and generated methods (which must be monomorphic) is admittedly unfortunate, +but this is the best that we offer, at present. + +\end{comment} + +% ------------------------------------------------------------------------------ + +\subsection{Where the expressiveness of OCaml's type system falls short} +\label{sec:map_from_fold} + +\begin{figure}[p] +\orig{map_from_fold} +\caption{An unsatisfactory definition of \oc|map| as a subclass of \oc|fold|} +\label{fig:map_from_fold} +\end{figure} + +\begin{figure}[p] +\begin{mdframed}[backgroundcolor=green!10] +\lstinputlisting{map_from_fold.mli} +\end{mdframed} +\caption{The type of the class \oc|map_from_fold| (\fref{fig:map_from_fold})} +\label{fig:map_from_fold:type} +\end{figure} + +We have noted earlier (\sref{sec:intro:fold}) that, among the varieties of +visitors that we have presented, \fold visitors are in principle the most +general. This raises the question: is it possible to define \map and \reduce +as subclasses of \fold, equipped with appropriate \tyconascendingmethod{} +methods? + +Doing so would be more economical: that is, it would significantly reduce the +redundancy between the classes \map, \reduce, and \fold. When these classes +are automatically generated, code duplication is not so much of a problem. +However, there are situations where (parts of) visitor classes must be +hand-written, and where duplication becomes painful. + +Furthermore, defining \map and \reduce as subclasses of \fold would give rise +to new patterns of customization. It would become possible to define a +subclass of \map or \reduce and override just one \tyconascendingmethod{} +method so as to obtain custom behavior.% +% +\footnote{At present, this must be done by overriding a + \tyconvisitor{} method, thereby causing more code duplication than + necessary.} + +In an untyped setting, the question can be answered positively: \map and +\reduce can be defined in terms of \fold. Unfortunately, in the setting +of OCaml's type system, the answer is negative: although \reduce can be +defined in terms of \fold, \map cannot. +% (or cannot always). + +The situation is illustrated in \fref{fig:map_from_fold}. As an example, we +define visitor methods, by hand, for the type \oc|'a option|. + +The methods \tyconvisitor{option} in the classes \reduce and \map are +identical to those found in the classes \runtime{reduce} and \runtime{map}. We +note that the method \tyconvisitor{option} in the class \reduce is polymorphic +in \oc|'a|, whereas \tyconvisitor{option} in the class \map is polymorphic +in~\oc|'a| and~\oc|'b|. + +There is some similarity between these methods, which is why we define a class +\fold, whose method \tyconvisitor{option} contains calls to the virtual +methods \dataconascendingmethod{None} and \dataconascendingmethod{Some}. We +assign to this method the most general type that is expressible in OCaml's +type system. It is polymorphic in \oc|'a|. The type variable~\oc|'r|, which +represents the result of the function~\oc|f|, and the type variable~\oc|'s|, +which represents the result of the methods \tyconvisitor{option}, +\dataconascendingmethod{None}, and \dataconascendingmethod{Some}, +cannot be universally quantified at the level of a method, +since they appear in the types of several methods. +They must be (implicitly) quantified at the level of the class. + +Is this definition of \fold satisfactory? To test this, let us now attempt to +propose new definitions of \reduce and \map as subclasses of \fold. We define +two more classes, \oc|reduce_from_fold| and \oc|map_from_fold|, which both +inherit \oc|fold| and provide suitable definitions of the methods +\dataconascendingmethod{None} and \dataconascendingmethod{Some}. + +In \oc|reduce_from_fold|, everything works fine. The type parameters \oc|'r| +and \oc|'s| in \fold are both instantiated with \oc|'z|. As a result, the +method \tyconvisitor{option} in the class \oc|reduce_from_fold| has type +% +\oc|'a. ('c -> 'a -> 'z) -> 'c -> 'a option -> 'z|, +% +just as in the class \reduce. + +In \oc|map_from_fold|, a problem arises. The code is well-typed, but its type +is less general than desired. The OCaml typechecker infers that the type +parameters \oc|'r| and \oc|'s| in \fold must be respectively instantiated with +\oc|'b| and \oc|'b option|, where the type variable \oc|'b| must be quantified +at the level of the class. Therefore, the type of \oc|map_from_fold| is as +shown in \fref{fig:map_from_fold:type}. This type is \emph{not} polymorphic +in~\oc|'b|, thus strictly less general than the type of the method +\tyconvisitor{option} in the class \map (\fref{fig:map_from_fold}). + +What would it take to repair this problem? Apparently, the type of the method +\tyconvisitor{option} in the class \fold is not general enough. Whereas the +type variables \oc|'r| and \oc|'s| currently have kind \oc|*|, it seems that +they should have kind \oc|* -> *|. The type of the class \fold should be as +follows: +% +\begin{mdframed}[backgroundcolor=green!10] +\begin{lstlisting} +class ['self] fold : object ('self) + method private visit_option: 'a 'b . + ('env -> 'a -> 'r['b]) -> 'env -> 'a option -> 's['b] + method private virtual build_None: 'b . 'env -> 's['b] + method private virtual build_Some: 'b . 'env -> 'r['b] -> 's['b] +end +\end{lstlisting} +\end{mdframed} + +This is not valid OCaml: we write \oc|'r[b]| for the type-level application of +\oc|'r| to \oc|'b|. The type of each method is universally quantified in +\oc|'b|, as desired. The type of \tyconvisitor{option} seems to have the +desired generality. By instantiating both~\oc|'r| and~\oc|'s| with the +type-level function \oc|fun 'b -> 'z|, we obtain the type of +\tyconvisitor{option} in the class \reduce. By instantiating \oc|'r| and +\oc|'s| with the type-level functions +% +\oc|fun 'b -> 'b| and \oc|fun 'b -> 'b option|, respectively, we obtain the +type of \tyconvisitor{option} in the class \map. + +This suggests that higher kinds, type-level functions, and type-level +$\beta$-reduction might be valuable features, not just in functional +programming languages, but also in an object-oriented programming setting. + +% ------------------------------------------------------------------------------ +% ------------------------------------------------------------------------------ + +\section{Reference} + +% ------------------------------------------------------------------------------ +% Parameters. + +\begin{figure}[p] +\renewcommand{\arraystretch}{1.5} +\begin{tabular}{@{}r@{\qquad}l@{\quad}p{.64\textwidth}@{}} + \ancestors & (list of strings) & + A list of classes that the generated class should inherit. + This is an optional parameter; its default value is the empty list. + The class \runtime{} is implicitly prepended to this list + 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 + concrete; otherwise, it is declared virtual. + This is an optional parameter; its default value is \texttt{false}. +\\ + \data & (Boolean) & + 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; + otherwise, it is enabled. + This is an optional parameter; its default value is \texttt{false}. +\\ + \name & (string) & + The name of the generated class. + This is an optional parameter; its default value is \oc||. +\\ + \nude & (Boolean) & + If \texttt{true}, the class \runtime{} is \emph{not} implicitly prepended to + the list \ancestors. + This is an optional parameter; its default value is \texttt{false}. +\\ + \polymorphic & (Boolean) & + If \texttt{true}, type variables are handled by virtual visitor methods, + and generated methods are monomorphic + (\sref{sec:intro:parameterized:mono}); + if \texttt{false}, type variables are handled by visitor functions, + and generated methods are polymorphic + (\sref{sec:intro:parameterized:poly}). + This is an optional parameter, whose default value is \texttt{false}. +\\ + \public & (list of strings) & + This is an optional parameter. + If absent, then every method in the generated class is declared public. + If present, then every method in the generated class is declared + private, except those whose name appears in the list: those are declared public. +\\ + \variety & (string) & + The variety of visitor that should be generated. + The supported varieties are + \iter (\sref{sec:intro:iter:def}), + \map (\sref{sec:intro:map}) and + \mapendo (\sref{sec:intro:endo}), + \reduce (\sref{sec:intro:reduce}), + \mapreduce (\sref{sec:intro:mapreduce}), + \fold (\sref{sec:intro:fold}), + \itertwo, + \maptwo, + \reducetwo, + \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 +\vspace{2.5mm} +\caption{Parameters of \derivingvisitors} +\label{fig:params} +\end{figure} + +\subsection{Parameters} +\label{sec:params} +\label{sec:ancestors} + +The parameters that can be passed as part of the \derivingvisitors annotation, +inside the curly braces, are described in \fref{fig:params}. + +% ------------------------------------------------------------------------------ + +\subsection{How to examine the generated code} + +The generated code is conceptually inserted into the user's source code just +after the type definition that is decorated with \derivingvisitors. + +It can be useful to inspect the generated code, so as to understand how it +works, what are the arguments and result of each method, and so on. This can +be especially useful when the generated code is ill-typed (which can happen, +for instance, when arbitrary user code is inherited via the \ancestors +parameter). + +The file \repoFile{Makefile.preprocess} offers a recipe that builds a file +named \verb|%.processed.ml| out of the source file \verb|%.ml|. This file contains +just the generated code. The recipe relies on \oc|sed|, \oc|perl|, and +\oc|ocp-indent| to extract and beautify the code. This file is installed +with the \visitors package; it can be found at the computed path +\verb+`ocamlfind query visitors`/Makefile.preprocess+. In a \texttt{Makefile}, +use the following directive: +\begin{verbatim} + include $(shell ocamlfind query visitors)/Makefile.preprocess +\end{verbatim} + +% ------------------------------------------------------------------------------ + +\subsection{Structure of the generated code} +\label{sec:structure} + +The \derivingvisitors annotation applies to a type definition. A type +definition may define several types, and these types may be parameterized. A +local type is one that is defined as part of this type definition, whereas a +nonlocal type is one that preexists (\sref{sec:intro:nonlocal}). + +The generated code consists of \emph{a single class}, whose name is \oc||, +that is, the value of the \variety parameter (\sref{sec:params}). This class +has \emph{one type parameter}, namely \oc|'self|, the type of ``self'' +(\sref{sec:oo:self}). It has no fields. It \emph{inherits} from the class +\runtime{} (unless the parameter \nude is \texttt{true}, \sref{sec:params}) +and from the classes listed via the \ancestors parameter (\sref{sec:params}), +in that order. To find out which methods exist in the class +\runtime{}, please consult \runtimeFile{VisitorsRuntime.ml}. + +In the following, the index~\oc|i| ranges from 0 (included) to \oc|| +(excluded), where \oc|| is the arity of the generated visitor (thus, +either 1 or 2). + +The following \emph{concrete methods} are \emph{defined}: +% +\begin{itemize} +\item for every local type \oc|??? foo|, a visitor method. + + \begin{tabular}{@{\qquad}rp{35mm}@{\quad}p{7cm}} + method name: & \tyconvisitor{foo} \\ + arguments: & \tyconvisitor{'a}, \ldots & a visitor function for each type param.\ of \oc|foo| \\ + & & (only if \oc|polymorphic = true|) \\ + & \oc|env| & an environment of type \oc|'env| \\ + & \oc|this_0|, \oc|this_1|, \ldots & for each \oc|i|, a value of type \oc|??? foo| \\ + invoked: & on the way down \\ + example: & \fref{fig:expr00} + \end{tabular} + +\item for every data constructor \oc|Foo| of a local sum type \oc|??? foo|, a visitor method. + + \begin{tabular}{@{\qquad}rp{35mm}@{\quad}p{7cm}} + method name: & \dataconvisitor{Foo} \\ + arguments: & \tyconvisitor{'a}, \ldots & a visitor function for each type param.\ of \oc|foo| \\ + & & (only if \oc|polymorphic = true|) \\ + & \oc|env| & an environment of type \oc|'env| \\ + & \oc|this| & a data structure of type \oc|??? foo| \\ + & & (only in an \mapendo visitor) \\ + & \oc|c0_0|, \oc|c0_1|, \ldots & for each \oc|i|, the first component of a \oc|Foo| value \\ + & \oc|c1_0|, \oc|c1_1|, \ldots & for each \oc|i|, the next component of a \oc|Foo| value \\ + & \ldots & \ldots and so on \\ + invoked: & on the way down \\ + example: & \fref{fig:expr00} + \end{tabular} + + If the parameter \data is \texttt{false}, then + this method is \emph{not} generated (\sref{sec:params}). + It is inlined instead. The behavior is the same, but cannot be overridden on + a per-data-constructor basis. + +\item if the visitor has arity two (\sref{sec:intro:aritytwo}), + for every local type \oc|foo|, + a failure method. + + \begin{tabular}{@{\qquad}rp{35mm}@{\quad}p{7cm}} + method name: & \tyconfail{foo} \\ + arguments: & \oc|env| & an environment of type \oc|'env| \\ + & \oc|this_0|, \oc|this_1|, \ldots & for each \oc|i|, a value of type \oc|??? foo| \\ + invoked: & \multicolumn{2}{l}{when two distinct data constructors \oc|Foo| and \oc|Bar| are found} \\ + example: & \fref{fig:expr02} + \end{tabular} + +\end{itemize} +% + +The following \emph{virtual methods} are \emph{declared}: +% +\begin{itemize} +\item for every type parameter \oc|'foo| of a local type, + a visitor method. (Only if \oc|polymorphic = true|.) + + \begin{tabular}{@{\qquad}rp{35mm}@{\quad}p{7cm}} + method name: & \tyconvisitor{'foo} \\ + arguments: & \oc|env| & an environment of type \oc|'env| \\ + & \oc|this_0|, \oc|this_1|, \ldots & for each \oc|i|, a value of type \oc|'foo| \\ + invoked: & on the way down \\ + example: & \fref{fig:expr_info} + \end{tabular} + +\item if this is a \reduce visitor (\sref{sec:intro:reduce}) + or a \mapreduce visitor (\sref{sec:intro:mapreduce}), + the monoid methods. + + \begin{tabular}{@{\qquad}rp{35mm}@{\quad}p{7cm}} + method name: & \oc|zero| \\ + arguments: & none \\ + result: & a summary \\ + example: & \fref{fig:expr15} + \end{tabular} + + \begin{tabular}{@{\qquad}rp{35mm}@{\quad}p{7cm}} + method name: & \oc|plus| \\ + arguments: & two summaries \\ + result: & a summary \\ + example: & \fref{fig:expr15} + \end{tabular} + +\item if this is a \fold visitor (\sref{sec:intro:fold}), + for every local record type \oc|foo|, + a build method. + + \begin{tabular}{@{\qquad}rp{35mm}@{\quad}p{7cm}} + method name: & \tyconascendingmethod{foo} \\ + arguments: & \oc|env| & an environment of type \oc|'env| \\ + & \oc|r_0| & the result of the first recursive call \\ + & \oc|r_1| & the result of the next recursive call \\ + & & \ldots and so on \\ + invoked: & on the way up \\ + example: & none in this document + \end{tabular} + +\item if this is a \fold visitor (\sref{sec:intro:fold}), + for every data constructor \oc|Foo| of a local sum type, + a build method. + + \begin{tabular}{@{\qquad}rp{35mm}@{\quad}p{7cm}} + method name: & \dataconascendingmethod{Foo} \\ + arguments: & \oc|env| & an environment of type \oc|'env| \\ + & \oc|r_0| & the result of the first recursive call \\ + & \oc|r_1| & the result of the next recursive call \\ + & & \ldots and so on \\ + invoked: & on the way up \\ + example: & \fref{fig:expr00fold} + \end{tabular} + +\end{itemize} + +The following methods are \emph{called}, therefore are expected to exist. +These methods are neither defined nor declared: their definition or +declaration must be inherited from a parent class. These methods can have a +polymorphic type. +% +\begin{itemize} +\item for every nonlocal type \oc|??? foo|, a visitor method. + + \begin{tabular}{@{\qquad}rp{35mm}@{\quad}p{7cm}} + method name: & \tyconvisitor{foo} \\ + arguments: & \oc|visit_0|, \ldots & for each actual type parameter in \oc|??? foo|, \\ + & & a visitor function for this type \\ + & \oc|env| & an environment of type \oc|'env| \\ + & \oc|this_0|, \oc|this_1|, \ldots & for each \oc|i|, a value of type \oc|??? foo| \\ + invoked: & on the way down \\ + example: & \fref{fig:expr11} + \end{tabular} + +\end{itemize} + +All of the above methods are parameterized with an environment \oc|env|, which +is propagated in a top-down manner, that is, into the recursive calls. The +environment is not returned out of the recursive calls, therefore not +propagated bottom-up or left-to-right. The type of this environment is +undetermined: it is a type variable. +% (which is implicitly related with \oc|'self|) +There is no a priori constraint that the type of the environment should be +the same in every method: it is possible for unrelated visitor methods to +expect environments of unrelated types. + +The result types of the visitor methods, build methods, and failure methods +depend on the parameter \variety (\sref{sec:params}). In an \iter visitor, +every method has result type \oc|unit|. In a \map or \mapendo visitor, the +visitor method associated with the type \oc|foo| has result type \oc|??? foo|.% +% +\footnote{The question marks \oc|???| stand for the type parameters of \oc|foo|, +which can be a parameterized type. In a \map visitor, the type parameters that +appear in the method's argument type and in the method's result type can differ. +In an \mapendo visitor, they must be the same.} +% +In a \reduce visitor, every method has result type \oc|'s|, if \oc|'s| is the +monoid, that is, if the methods \oc|zero| and \oc|plus| respectively have type \oc|'s| +and \oc|'s -> 's -> 's|. +% +In a \mapreduce visitor, the visitor method associated with the type \oc|foo| +has result type \oc|??? foo * 's|, if \oc|'s| is the monoid. +% +In a \fold visitor, it is up to the user to decide what the result types of +the visitor methods should be (subject to certain consistency constraints, +naturally). In particular, two visitor methods \tyconvisitor{foo} and +\tyconvisitor{bar} can have distinct result types; this is illustrated +in \fref{fig:fold}. + +% ------------------------------------------------------------------------------ + +\subsection{Supported forms of types} + +The following forms of type definitions are supported: +\begin{itemize} +\item Definitions of \emph{type abbreviations} (also known as type synonyms). +\item Definitions of \emph{record types}. \\ Mutable fields are supported. +\item Definitions of \emph{sum types} (also known as variant types and as algebraic + data types). \\ Data constructors whose arguments form an ``inline record'' are + supported. +\end{itemize} + +Definitions of abstract types and of extensible sum types are not supported. + +\label{sec:regularity} +% The regularity restriction. + +Definitions of \emph{parameterized types} are supported. In monomorphic mode +(\sref{sec:intro:parameterized:mono}), only \emph{\hbox{regular}} +parameterized types are permitted, whereas in polymorphic mode +(\sref{sec:intro:parameterized:poly}), arbitrary parameterized types are +permitted. +% +A parameterized type is regular if, within its own definition, it is applied +only to its formal parameters. For instance, the well-known definition of +lists is regular: + +\begin{origenv} +\begin{lstlisting} +type 'a list = +| [] +| (::) of 'a * 'a list +\end{lstlisting} +\end{origenv} +% +whereas the following definition of a random access +list~\cite[\S10.1.2]{okasaki-book-99} is not: +% +\begin{origenv} +\begin{lstlisting} +type 'a seq = +| Nil +| Zero of ('a * 'a) seq +| One of 'a * ('a * 'a) seq +\end{lstlisting} +\end{origenv} + +Irregular data types are also known as +``nonuniform''~\cite[\S10.1]{okasaki-book-99} or ``nested'' data +types~\cite{bird-meertens-98}. + +% The regularity check performed by the \visitors package in monomorphic mode +% can be disabled via the \irregular parameter (\sref{sec:params}). + +Existential types and generalized algebraic data types (GADTs) are currently +not supported. + +% Visiting an existential type seems problematic anyway, since we do not know +% how to descend into a value of unknkown type. Perhaps we could generate a +% default visitor method which treats the value as opaque, and allow the user +% to override this behavior if desired. + +% Visiting a GADT seems possible if the type parameters are used purely as +% indices (i.e., they are phantom parameters). In that case, we actually do +% not need visitor functions for the type parameters. + +In the right-hand side of a type definition, the following forms of types are +supported: +\begin{itemize} +\item Type constructors, possibly applied to a number of types, such as + \oc|foo| and \oc|('a * 'b) bar|. +\item Type variables, such as \oc|'foo|. +\item Tuple types, such as \oc|int * expr|. +\end{itemize} +The unsupported forms of types include +anonymous type variables (\oc|_|), +function types (\oc|int -> unit|), +object types (\oc|| and \oc|#point|), +recursive types (\oc|int -> 'a as 'a|), +polymorphic variant types (\oc+[ `A| `B ]+), +universal types (\oc|'a. 'a -> 'a|), +and +packaged module types (\oc|(module S)|). +If these forms appear in a type definition, +they must be marked \oc|@opaque| (\sref{sec:opaque}). + +In theory, at each arity, the tuple type constructor could be viewed as a +parameterized nonlocal type constructor. At arity 2, for instance, the pair +type \oc|'a * 'b| could be treated as a nonlocal type \oc|('a, 'b) tuple2|. +Then, to traverse a value of this type, one would invoke a method +\tyconvisitor{tuple2}, which necessarily would be inherited from a parent +class. That would be somewhat inconvenient, as these (polymorphic) methods +would have to be manually written, at each arity. Instead, special treatment +for tuple types is built-in. There are no visitor methods or build methods for +tuples; instead, ad hoc code is generated. This means that the behavior of a +visitor at a tuple type is fixed: it cannot be overridden in a subclass. The +behavior of a \fold visitor at a tuple type is to rebuild a tuple, just like a +\map visitor would do. + +% ------------------------------------------------------------------------------ + +\subsection{Opaque components} +\label{sec:opaque} + +One sometimes wishes for a component of a data structure \emph{not} to be +visited, either for efficiency reasons, or because this component is of an +unsupported type. This can be requested by annotating the type of this +component with the attribute \oc|[@opaque]|. This is done, for instance, if +\fref{fig:expr15}, where the integer argument of the data constructor +\oc|EConst| is marked opaque. (Note the parentheses, which are required.) The +effect of this annotation is that this component is not visited: in the method +\dataconvisitor{EConst}, instead of a call to \oc|self#visit_int|, we find a +call to \oc|self#zero|, as this is a \reduce visitor. + +Generating a visitor of arity two for a data structure with \oc|@opaque| +components requires some care. The methods \tyconvisitor{int} defined in the +classes \runtime{iter2}, \runtime{map2}, and so on, raise a +\oc|StructuralMismatch| exception when their two integer arguments differ. If +\oc|int| is replaced with \oc|(int[@opaque])|, then these methods are not +invoked, so no exception is raised. It is up to the user to decide which +behavior is desired. Furthermore, it should be noted that \maptwo and \foldtwo +visitors follow an arbitrary convention at \oc|@opaque| components: they +return the first of their two arguments. Again, it is up to the user to decide +whether this behavior is appropriate. + +In \polymorphic mode (\sref{sec:intro:parameterized:poly}), a type variable +must not occur under an \oc|[@opaque]| annotation. + +If desired, instead of \oc|[@opaque]|, one can use the more verbose forms +\oc|[@visitors.opaque]| and \oc|[@deriving.visitors.opaque]|. + +% ------------------------------------------------------------------------------ + +\subsection{Alternate method names} +\label{sec:name} + +The methods associated with the type \oc|foo| are normally named after this +type: this includes the visitor method \tyconvisitor{foo}, the build method +\tyconascendingmethod{foo}, +% (in \oc|fold| visitors) +and the failure method \tyconfail{foo}. +% (when the arity is 2) +This base name can be altered via an attribute. If \oc|foo| is a local type, +then a \oc|[@@name]| attribute must be attached to the declaration of this +type. If \oc|foo| is a nonlocal type, then a \oc|[@name]| attribute must be +attached to every reference to this type. For instance, in the following +example, +the visitor method associated with the type \oc|cloud| is named +\oc|visit_nuage| instead of \oc|visit_cloud|: +% +\begin{origenv} +\begin{lstlisting} +type cloud = + | Point of (float[@name "real"]) * (float[@name "real"]) + | Clouds of cloud list + [@@name "nuage"] + [@@deriving visitors { variety = "map"; ancestors = ["base"] }] +\end{lstlisting} +\end{origenv} +% +Furthermore, the visitor method associated with the type \oc|float| +(which is not generated, and should be inherited from the class \oc|base|) +is assumed to be named \oc|visit_real| instead of \oc|visit_float|. + +The methods associated with the data constructor \oc|Foo| are normally named +after it: this includes the visitor method \dataconvisitor{Foo} and the build +method \dataconascendingmethod{Foo}. +% +This base name can be altered via a \oc|[@name]| attribute, which must be +attached to the data constructor. For instance, in the following example, +the visitor methods associated with the data constructors \oc|[]| and \oc|::| +are named \dataconvisitor{nil} and \dataconvisitor{cons}: +% instead of \dataconvisitor{[]} and \dataconvisitor{::}, +% which would be invalid names: +% +\begin{origenv} +\begin{lstlisting} +type 'a mylist = 'a list = + | [] [@name "nil"] + | (::) of 'a * 'a mylist [@name "cons"] + [@@deriving visitors { variety = "map" }] +\end{lstlisting} +\end{origenv} +% +If desired, instead of \oc|[@name]|, one can use +\oc|[@visitors.name]| or \oc|[@deriving.visitors.name]|. + +% ------------------------------------------------------------------------------ + +\subsection{Alternate construction code in \map visitors} +\label{sec:build} + +By default, a \map visitor for an algebraic data type constructs a new data +structure, by applying a data constructor or by allocating a new record. +Sometimes, though, it is illegal to do so: this is the case, for instance, if +the type has been declared \oc|private|. +% +% Sometimes, the default behavior is well-typed, but is not the desired +% behavior. In that case, it can be customized by overriding a method. Using +% [@build] offers a little extra conciseness and efficiency in that case, but +% this need not be advertised. +% +% Another solution would be to just write the visitor by hand for a private +% type, but that would require more work from the user. +% +In such a situation, an alternate constructor can be provided via a +\oc|[@build]| attribute (which must be attached to a data constructor) or via a +\oc|[@@build]| attribute (which must be attached to a record type declaration). +% +Such an attribute carries an OCaml expression, which should represent a +constructor function. + +For instance, suppose that the module \oc|Point| has the following signature: +\begin{mdframed}[backgroundcolor=green!10] +\lstinputlisting{point.mli} +\end{mdframed} + +Suppose that, outside of this module, one wishes to generate a \map visitor +for the type \oc|Point.point|. One would like to do this in the style that was +presented earlier (\sref{sec:import}), but a naïve attempt fails: the +generated visitor is illegal, because allocating a record of type +\oc|Point.point| is forbidden. To circumvent this problem, one should +indicate, via a \oc|[@@build]| attribute, that the constructor function +\oc|Point.make| should be used: +% +\begin{origenv} +\begin{lstlisting} +type point = Point.point = private { x: int; y: int } + [@@build Point.make] + [@@deriving visitors { variety = "map" }] +\end{lstlisting} +\end{origenv} +% + +The OCaml expression carried by a \oc|[@build]| attribute can refer to the +local variable \oc|self|, which represents the visitor object, and to the +local variable \oc|env|, which represents the environment received by the +visitor method. + +\oc|[@build]| attributes influence not only \map visitors, +but also \mapendo and \mapreduce visitors. + +Instead of \oc|[@build]|, one can use +\oc|[@visitors.build]| or \oc|[@deriving.visitors.build]|. + +% Be careful not to misspell the attribute name, +% as the attribute would then be silently ignored. + +% ------------------------------------------------------------------------------ + +\bibliographystyle{plain} +\bibliography{english,local} + +\end{document} + +% TEMPORARY to do: + +explain how to use visitors to obtain + an equality function {fig:expr05} + an ordering function {fig:expr05lexico} + a hash function ?? -- use a reduce visitor + +add a use case that shows an environment in use + e.g. expressions with let bindings, + and if a variable is bound to a constant, replace it with its value + +document the speed overhead compared to a native recursive function + +document the lazy-initializer trick, if used + +référence: + avoid shadowing the following names: VisitorsRuntime, Lazy, Pervasives + +related work, for OCaml: + ppx_deriving (generates monolithic code) (fixed number of templates) + ppx_deriving_morphism + janestreet/ppx_traverse + Hongbo Zhang has `deriving at a distance' in Fan + https://github.com/bobzhang/fan + http://zhanghongbo.me/fan/ + http://zhanghongbo.me/fan/_downloads/metaprogramming_for_ocaml.pdf + alphaCaml + +related work, for other programming languages: + Bound (Edward Kmett) + Unbound (Weirich) + RedPerl + Francisco Ferreira et Brigitte Pientka, ESOP 2017 (Babybel) + +related work, for proof assistants: + Steven Keuchel + Autosubst (voir Kaiser et al., CPP 2017) + voir Guillaume Allais (CPP 2017, Agda et Haskell) et Goguen & McKinna diff --git a/doc/plain.bst b/doc/plain.bst new file mode 100644 index 0000000..2071152 --- /dev/null +++ b/doc/plain.bst @@ -0,0 +1,1106 @@ +% BibTeX standard bibliography style `plain' + % version 0.99a for BibTeX versions 0.99a or later, LaTeX version 2.09. + % Copyright (C) 1985, all rights reserved. + % Copying of this file is authorized only if either + % (1) you make absolutely no changes to your copy, including name, or + % (2) if you do make changes, you name it something other than + % btxbst.doc, plain.bst, unsrt.bst, alpha.bst, and abbrv.bst. + % This restriction helps ensure that all standard styles are identical. + % The file btxbst.doc has the documentation for this style. + +% Modified by Francois.Pottier@inria.fr with support for url field. + +ENTRY + { address + author + booktitle + chapter + edition + editor + howpublished + institution + journal + key + month + note + number + organization + pages + publisher + school + series + title + type + url + volume + year + } + {} + { label } + +INTEGERS { output.state before.all mid.sentence after.sentence after.block } + +FUNCTION {init.state.consts} +{ #0 'before.all := + #1 'mid.sentence := + #2 'after.sentence := + #3 'after.block := +} + +STRINGS { s t } + +FUNCTION {output.nonnull} +{ 's := + output.state mid.sentence = + { ", " * write$ } + { output.state after.block = + { add.period$ write$ + newline$ + "\newblock " write$ + } + { output.state before.all = + 'write$ + { add.period$ " " * write$ } + if$ + } + if$ + mid.sentence 'output.state := + } + if$ + s +} + +FUNCTION {output} +{ duplicate$ empty$ + 'pop$ + 'output.nonnull + if$ +} + +FUNCTION {output.check} +{ 't := + duplicate$ empty$ + { pop$ "empty " t * " in " * cite$ * warning$ } + 'output.nonnull + if$ +} + +FUNCTION {output.bibitem} +{ newline$ + "\bibitem{" write$ + cite$ write$ + "}" write$ + newline$ + "" + before.all 'output.state := +} + +FUNCTION {fin.entry} +{ add.period$ + write$ + newline$ +} + +FUNCTION {new.block} +{ output.state before.all = + 'skip$ + { after.block 'output.state := } + if$ +} + +FUNCTION {new.sentence} +{ output.state after.block = + 'skip$ + { output.state before.all = + 'skip$ + { after.sentence 'output.state := } + if$ + } + if$ +} + +FUNCTION {not} +{ { #0 } + { #1 } + if$ +} + +FUNCTION {and} +{ 'skip$ + { pop$ #0 } + if$ +} + +FUNCTION {or} +{ { pop$ #1 } + 'skip$ + if$ +} + +FUNCTION {new.block.checka} +{ empty$ + 'skip$ + 'new.block + if$ +} + +FUNCTION {new.block.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.block + if$ +} + +FUNCTION {new.sentence.checka} +{ empty$ + 'skip$ + 'new.sentence + if$ +} + +FUNCTION {new.sentence.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.sentence + if$ +} + +FUNCTION {field.or.null} +{ duplicate$ empty$ + { pop$ "" } + 'skip$ + if$ +} + +FUNCTION {emphasize} +{ duplicate$ empty$ + { pop$ "" } + { "{\em " swap$ * "}" * } + if$ +} + +INTEGERS { nameptr namesleft numnames } + +FUNCTION {format.names} +{ 's := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr "{ff~}{vv~}{ll}{, jj}" format.name$ 't := + nameptr #1 > + { namesleft #1 > + { ", " * t * } + { numnames #2 > + { "," * } + 'skip$ + if$ + t "others" = + { " et~al." * } + { " and " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {format.authors} +{ author empty$ + { "" } + { author format.names } + if$ +} + +FUNCTION {format.editors} +{ editor empty$ + { "" } + { editor format.names + editor num.names$ #1 > + { ", editors" * } + { ", editor" * } + if$ + } + if$ +} + +FUNCTION {format.title} +{ title empty$ + { "" } + { url empty$ + { title "t" change.case$ } + { "\href{" url "}{" title "t" change.case$ "}" * * * * } + if$ } + if$ +} + +FUNCTION {n.dashify} +{ 't := + "" + { t empty$ not } + { t #1 #1 substring$ "-" = + { t #1 #2 substring$ "--" = not + { "--" * + t #2 global.max$ substring$ 't := + } + { { t #1 #1 substring$ "-" = } + { "-" * + t #2 global.max$ substring$ 't := + } + while$ + } + if$ + } + { t #1 #1 substring$ * + t #2 global.max$ substring$ 't := + } + if$ + } + while$ +} + +FUNCTION {format.date} +{ year empty$ + { month empty$ + { "" } + { "there's a month but no year in " cite$ * warning$ + month + } + if$ + } + { month empty$ + 'year + { month " " * year * } + if$ + } + if$ +} + +FUNCTION {format.btitle} +{ url empty$ + { title emphasize } + { "\href{" url "}{" title emphasize "}" * * * * } + if$ +} + +FUNCTION {tie.or.space.connect} +{ duplicate$ text.length$ #3 < + { "~" } + { " " } + if$ + swap$ * * +} + +FUNCTION {either.or.check} +{ empty$ + 'pop$ + { "can't use both " swap$ * " fields in " * cite$ * warning$ } + if$ +} + +FUNCTION {format.bvolume} +{ volume empty$ + { "" } + { "volume" volume tie.or.space.connect + series empty$ + 'skip$ + { " of " * series emphasize * } + if$ + "volume and number" number either.or.check + } + if$ +} + +FUNCTION {format.number.series} +{ volume empty$ + { number empty$ + { series field.or.null } + { output.state mid.sentence = + { "number" } + { "Number" } + if$ + number tie.or.space.connect + series empty$ + { "there's a number but no series in " cite$ * warning$ } + { " in " * series * } + if$ + } + if$ + } + { "" } + if$ +} + +FUNCTION {format.edition} +{ edition empty$ + { "" } + { output.state mid.sentence = + { edition "l" change.case$ " edition" * } + { edition "t" change.case$ " edition" * } + if$ + } + if$ +} + +INTEGERS { multiresult } + +FUNCTION {multi.page.check} +{ 't := + #0 'multiresult := + { multiresult not + t empty$ not + and + } + { t #1 #1 substring$ + duplicate$ "-" = + swap$ duplicate$ "," = + swap$ "+" = + or or + { #1 'multiresult := } + { t #2 global.max$ substring$ 't := } + if$ + } + while$ + multiresult +} + +FUNCTION {format.pages} +{ pages empty$ + { "" } + { pages multi.page.check + { "pages" pages n.dashify tie.or.space.connect } + { "page" pages tie.or.space.connect } + if$ + } + if$ +} + +FUNCTION {format.vol.num.pages} +{ volume field.or.null + number empty$ + 'skip$ + { "(" number * ")" * * + volume empty$ + { "there's a number but no volume in " cite$ * warning$ } + 'skip$ + if$ + } + if$ + pages empty$ + 'skip$ + { duplicate$ empty$ + { pop$ format.pages } + { ":" * pages n.dashify * } + if$ + } + if$ +} + +FUNCTION {format.chapter.pages} +{ chapter empty$ + 'format.pages + { type empty$ + { "chapter" } + { type "l" change.case$ } + if$ + chapter tie.or.space.connect + pages empty$ + 'skip$ + { ", " * format.pages * } + if$ + } + if$ +} + +FUNCTION {format.in.ed.booktitle} +{ booktitle empty$ + { "" } + { editor empty$ + { "In " booktitle emphasize * } + { "In " format.editors * ", " * booktitle emphasize * } + if$ + } + if$ +} + +FUNCTION {empty.misc.check} +{ author empty$ title empty$ howpublished empty$ + month empty$ year empty$ note empty$ + and and and and and + key empty$ not and + { "all relevant fields are empty in " cite$ * warning$ } + 'skip$ + if$ +} + +FUNCTION {format.thesis.type} +{ type empty$ + 'skip$ + { pop$ + type "t" change.case$ + } + if$ +} + +FUNCTION {format.tr.number} +{ type empty$ + { "Technical Report" } + 'type + if$ + number empty$ + { "t" change.case$ } + { number tie.or.space.connect } + if$ +} + +FUNCTION {format.article.crossref} +{ key empty$ + { journal empty$ + { "need key or journal for " cite$ * " to crossref " * crossref * + warning$ + "" + } + { "In {\em " journal * "\/}" * } + if$ + } + { "In " key * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {format.crossref.editor} +{ editor #1 "{vv~}{ll}" format.name$ + editor num.names$ duplicate$ + #2 > + { pop$ " et~al." * } + { #2 < + 'skip$ + { editor #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" = + { " et~al." * } + { " and " * editor #2 "{vv~}{ll}" format.name$ * } + if$ + } + if$ + } + if$ +} + +FUNCTION {format.book.crossref} +{ volume empty$ + { "empty volume in " cite$ * "'s crossref of " * crossref * warning$ + "In " + } + { "Volume" volume tie.or.space.connect + " of " * + } + if$ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { series empty$ + { "need editor, key, or series for " cite$ * " to crossref " * + crossref * warning$ + "" * + } + { "{\em " * series * "\/}" * } + if$ + } + { key * } + if$ + } + { format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {format.incoll.inproc.crossref} +{ editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { booktitle empty$ + { "need editor, key, or booktitle for " cite$ * " to crossref " * + crossref * warning$ + "" + } + { "In {\em " booktitle * "\/}" * } + if$ + } + { "In " key * } + if$ + } + { "In " format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {article} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { journal emphasize "journal" output.check + format.vol.num.pages output + format.date "year" output.check + } + { format.article.crossref output.nonnull + format.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {book} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + new.block + format.number.series output + new.sentence + publisher "publisher" output.check + address output + } + { new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {booklet} +{ output.bibitem + format.authors output + new.block + format.title "title" output.check + howpublished address new.block.checkb + howpublished output + address output + format.date output + new.block + note output + fin.entry +} + +FUNCTION {inbook} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + format.chapter.pages "chapter and pages" output.check + new.block + format.number.series output + new.sentence + publisher "publisher" output.check + address output + } + { format.chapter.pages "chapter and pages" output.check + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {incollection} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.number.series output + format.chapter.pages output + new.sentence + publisher "publisher" output.check + address output + format.edition output + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.chapter.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {inproceedings} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.number.series output + format.pages output + address empty$ + { organization publisher new.sentence.checkb + organization output + publisher output + format.date "year" output.check + } + { address output.nonnull + format.date "year" output.check + new.sentence + organization output + publisher output + } + if$ + } + { format.incoll.inproc.crossref output.nonnull + format.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {conference} { inproceedings } + +FUNCTION {manual} +{ output.bibitem + author empty$ + { organization empty$ + 'skip$ + { organization output.nonnull + address output + } + if$ + } + { format.authors output.nonnull } + if$ + new.block + format.btitle "title" output.check + author empty$ + { organization empty$ + { address new.block.checka + address output + } + 'skip$ + if$ + } + { organization address new.block.checkb + organization output + address output + } + if$ + format.edition output + format.date output + new.block + note output + fin.entry +} + +FUNCTION {mastersthesis} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + "Master's thesis" format.thesis.type output.nonnull + school "school" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {misc} +{ output.bibitem + format.authors output + title howpublished new.block.checkb + format.title output + howpublished new.block.checka + howpublished output + format.date output + new.block + note output + fin.entry + empty.misc.check +} + +FUNCTION {phdthesis} +{ output.bibitem + format.authors "author" output.check + new.block + format.btitle "title" output.check + new.block + "PhD thesis" format.thesis.type output.nonnull + school "school" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {proceedings} +{ output.bibitem + editor empty$ + { organization output } + { format.editors output.nonnull } + if$ + new.block + format.btitle "title" output.check + format.bvolume output + format.number.series output + address empty$ + { editor empty$ + { publisher new.sentence.checka } + { organization publisher new.sentence.checkb + organization output + } + if$ + publisher output + format.date "year" output.check + } + { address output.nonnull + format.date "year" output.check + new.sentence + editor empty$ + 'skip$ + { organization output } + if$ + publisher output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {techreport} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + format.tr.number output.nonnull + institution "institution" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {unpublished} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + note "note" output.check + format.date output + fin.entry +} + +FUNCTION {default.type} { misc } + +MACRO {jan} {"January"} + +MACRO {feb} {"February"} + +MACRO {mar} {"March"} + +MACRO {apr} {"April"} + +MACRO {may} {"May"} + +MACRO {jun} {"June"} + +MACRO {jul} {"July"} + +MACRO {aug} {"August"} + +MACRO {sep} {"September"} + +MACRO {oct} {"October"} + +MACRO {nov} {"November"} + +MACRO {dec} {"December"} + +MACRO {acmcs} {"ACM Computing Surveys"} + +MACRO {acta} {"Acta Informatica"} + +MACRO {cacm} {"Communications of the ACM"} + +MACRO {ibmjrd} {"IBM Journal of Research and Development"} + +MACRO {ibmsj} {"IBM Systems Journal"} + +MACRO {ieeese} {"IEEE Transactions on Software Engineering"} + +MACRO {ieeetc} {"IEEE Transactions on Computers"} + +MACRO {ieeetcad} + {"IEEE Transactions on Computer-Aided Design of Integrated Circuits"} + +MACRO {ipl} {"Information Processing Letters"} + +MACRO {jacm} {"Journal of the ACM"} + +MACRO {jcss} {"Journal of Computer and System Sciences"} + +MACRO {scp} {"Science of Computer Programming"} + +MACRO {sicomp} {"SIAM Journal on Computing"} + +MACRO {tocs} {"ACM Transactions on Computer Systems"} + +MACRO {tods} {"ACM Transactions on Database Systems"} + +MACRO {tog} {"ACM Transactions on Graphics"} + +MACRO {toms} {"ACM Transactions on Mathematical Software"} + +MACRO {toois} {"ACM Transactions on Office Information Systems"} + +MACRO {toplas} {"ACM Transactions on Programming Languages and Systems"} + +MACRO {tcs} {"Theoretical Computer Science"} + +READ + +FUNCTION {sortify} +{ purify$ + "l" change.case$ +} + +INTEGERS { len } + +FUNCTION {chop.word} +{ 's := + 'len := + s #1 len substring$ = + { s len #1 + global.max$ substring$ } + 's + if$ +} + +FUNCTION {sort.format.names} +{ 's := + #1 'nameptr := + "" + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { nameptr #1 > + { " " * } + 'skip$ + if$ + s nameptr "{vv{ } }{ll{ }}{ ff{ }}{ jj{ }}" format.name$ 't := + nameptr numnames = t "others" = and + { "et al" * } + { t sortify * } + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {sort.format.title} +{ 't := + "A " #2 + "An " #3 + "The " #4 t chop.word + chop.word + chop.word + sortify + #1 global.max$ substring$ +} + +FUNCTION {author.sort} +{ author empty$ + { key empty$ + { "to sort, need author or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {author.editor.sort} +{ author empty$ + { editor empty$ + { key empty$ + { "to sort, need author, editor, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { editor sort.format.names } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {author.organization.sort} +{ author empty$ + { organization empty$ + { key empty$ + { "to sort, need author, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {editor.organization.sort} +{ editor empty$ + { organization empty$ + { key empty$ + { "to sort, need editor, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { editor sort.format.names } + if$ +} + +FUNCTION {presort} +{ type$ "book" = + type$ "inbook" = + or + 'author.editor.sort + { type$ "proceedings" = + 'editor.organization.sort + { type$ "manual" = + 'author.organization.sort + 'author.sort + if$ + } + if$ + } + if$ + " " + * + year field.or.null sortify + * + " " + * + title field.or.null + sort.format.title + * + #1 entry.max$ substring$ + 'sort.key$ := +} + +ITERATE {presort} + +SORT + +STRINGS { longest.label } + +INTEGERS { number.label longest.label.width } + +FUNCTION {initialize.longest.label} +{ "" 'longest.label := + #1 'number.label := + #0 'longest.label.width := +} + +FUNCTION {longest.label.pass} +{ number.label int.to.str$ 'label := + number.label #1 + 'number.label := + label width$ longest.label.width > + { label 'longest.label := + label width$ 'longest.label.width := + } + 'skip$ + if$ +} + +EXECUTE {initialize.longest.label} + +ITERATE {longest.label.pass} + +FUNCTION {begin.bib} +{ preamble$ empty$ + 'skip$ + { preamble$ write$ newline$ } + if$ + "\begin{thebibliography}{" longest.label * "}" * write$ newline$ +} + +EXECUTE {begin.bib} + +EXECUTE {init.state.consts} + +ITERATE {call.type$} + +FUNCTION {end.bib} +{ newline$ + "\end{thebibliography}" write$ newline$ +} + +EXECUTE {end.bib} diff --git a/doc/types.tex b/doc/types.tex new file mode 100644 index 0000000..8a66dcc --- /dev/null +++ b/doc/types.tex @@ -0,0 +1,38 @@ +\begin{figure}[t] +\begin{mdframed}[backgroundcolor=green!10] +\begin{lstlisting} +class virtual ['self] iter : object ('self) + constraint 'self = + < visit_EAdd : 'env -> expr -> expr -> unit; + visit_EConst : 'env -> int -> unit; + visit_expr : 'env -> expr -> unit; + .. > + method visit_EAdd : 'env -> expr -> expr -> unit + method visit_EConst : 'env -> int -> unit + method visit_expr : 'env -> expr -> unit + (* These methods are inherited from [VisitorsRuntime.iter]: *) + method private visit_array : + 'env 'a. ('env -> 'a -> unit) -> 'env -> 'a array -> unit + method private visit_bool : 'env. 'env -> bool -> unit + method private visit_bytes : 'env. 'env -> bytes -> unit + (* ... and many more ... *) +end +\end{lstlisting} +\end{mdframed} +\caption{An inferred type for the \iter visitor of \fref{fig:expr00}} +\label{fig:inferred} +\end{figure} + +\begin{figure}[t] +\begin{mdframed}[backgroundcolor=green!10] +\begin{lstlisting} +class virtual ['self] iter : object ('self) + method visit_EAdd : 'monomorphic. 'env -> expr -> expr -> unit + method visit_EConst : 'monomorphic. 'env -> int -> unit + method visit_expr : 'monomorphic. 'env -> expr -> unit +end +\end{lstlisting} +\end{mdframed} +\caption{A simplified type for the \iter visitor of \fref{fig:expr00}} +\label{fig:simplified} +\end{figure} diff --git a/doc/version.tex b/doc/version.tex new file mode 100644 index 0000000..db24732 --- /dev/null +++ b/doc/version.tex @@ -0,0 +1 @@ +\gdef\visitorsversion{20200210} diff --git a/dune b/dune new file mode 100644 index 0000000..e0d7b7d --- /dev/null +++ b/dune @@ -0,0 +1,5 @@ +(install + (files Makefile.preprocess) + (section lib) + (package visitors) +) diff --git a/dune-project b/dune-project new file mode 100644 index 0000000..f5d6cc3 --- /dev/null +++ b/dune-project @@ -0,0 +1,12 @@ +(lang dune 2.0) +(name visitors) +(version 20200210) +(package + (name visitors) +) +(package + (name visitors.runtime) +) +(package + (name visitors.ppx) +) diff --git a/runtime/Makefile b/runtime/Makefile new file mode 100644 index 0000000..441cb57 --- /dev/null +++ b/runtime/Makefile @@ -0,0 +1,3 @@ +.PHONY: all +all: + @ make -C .. $@ diff --git a/runtime/VisitorsRuntime.ml b/runtime/VisitorsRuntime.ml new file mode 100644 index 0000000..04d2ba5 --- /dev/null +++ b/runtime/VisitorsRuntime.ml @@ -0,0 +1,1139 @@ +(* This file provides useful / reasonable visitor methods for many of the + built-in types of OCaml. *) + +(* The classes defined in this file are automatically inherited by + auto-generated visitors. If this is not desired, this behavior can be + turned off at generation time by specifying [nude = true]. *) + +(* Some of the code in this file can be (or has been) auto-generated by + the [visitors] package itself: see [test/VisitorsRuntimeBootstrap]. + To avoid a complicated process and to facilitate code review, we + keep this code under manual control in this file. *) + +(* -------------------------------------------------------------------------- *) + +(* For compatibility with OCaml 4.02, we take the type [('a, 'b) result] from + the package [result]. This type appeared in the standard library in OCaml + 4.03. *) + +open Result + +(* -------------------------------------------------------------------------- *) + +(* [array_equal eq xs1 xs2] tests whether the arrays [xs1] and [xs2] have the + same components. The arrays must have the same length. The components are + compared using [eq]. *) + +let rec array_equal eq i n xs1 xs2 = + i = n || + let x1 = Array.unsafe_get xs1 i + and x2 = Array.unsafe_get xs2 i in + eq x1 x2 && array_equal eq (i + 1) n xs1 xs2 + +let array_equal eq xs1 xs2 = + let n = Array.length xs1 in + assert (Array.length xs2 = n); + array_equal eq 0 n xs1 xs2 + +(* -------------------------------------------------------------------------- *) + +(* An exception used at arity 2 and above. *) + +exception StructuralMismatch + +let fail () = + raise StructuralMismatch + +let wrap f t = + try + f t; + true + with StructuralMismatch -> + false + +let wrap2 f t1 t2 = + try + f t1 t2; + true + with StructuralMismatch -> + false + +(* -------------------------------------------------------------------------- *) + +(* A virtual base class for monoids. *) + +class virtual ['s] monoid = object + method private virtual zero: 's + method private virtual plus: 's -> 's -> 's +end + +(* -------------------------------------------------------------------------- *) + +(* Common monoids. *) + +class ['s] addition_monoid = object + inherit ['s] monoid + method private zero = 0 + method private plus = (+) +end + +class ['s] unit_monoid = object + inherit ['s] monoid + method private zero = () + method private plus () () = () +end + +(* -------------------------------------------------------------------------- *) + +(* Visitor methods for the primitive types. *) + +(* Must the methods below be declared polymorphic in ['env]? The fact is, they + ARE polymorphic in ['env], because they do not extend it or look it up. + + By declaring them polymorphic, we gain in generality: e.g., [visit_list] + can be called by two visitor methods which happen to have different types + of environments. (This happens in alphaLib, where visitor methods for terms + and patterns manipulate different types of environments.) + + However, by declaring them polymorphic, we also lose some generality, as we + PREVENT users from overriding these methods with code that extends or looks + up the environment. + + Here, it seems reasonable to take both the gain and the loss, and declare + these methods polymorphic. + + We could give the user a choice by providing multiple base classes, but that + would messy. Note that, when using [@@deriving visitors { ... }], the user + does have a choice whether the generated methods should be polymorphic in + ['env]. *) + +(* -------------------------------------------------------------------------- *) + +(* [iter] *) + +class ['self] iter = object (self) + + method private visit_array: 'env 'a . + ('env -> 'a -> unit) -> 'env -> 'a array -> unit + = fun f env xs -> + (* For speed, we inline [Array.iter]. Chances are, we save a closure + allocation, as using [Array.iter] would require us to build [f env]. *) + for i = 0 to Array.length xs - 1 do + f env (Array.unsafe_get xs i) + done + + method private visit_bool: 'env . + 'env -> bool -> unit + = fun _ _ -> () + + method private visit_bytes: 'env . + 'env -> bytes -> unit + = fun _ _ -> () + + method private visit_char: 'env . + 'env -> char -> unit + = fun _ _ -> () + + method private visit_float: 'env . + 'env -> float -> unit + = fun _ _ -> () + + method private visit_int: 'env . + 'env -> int -> unit + = fun _ _ -> () + + method private visit_int32: 'env . + 'env -> int32 -> unit + = fun _ _ -> () + + method private visit_int64: 'env . + 'env -> int64 -> unit + = fun _ _ -> () + + method private visit_lazy_t: 'env 'a . + ('env -> 'a -> unit) -> 'env -> 'a Lazy.t -> unit + = fun f env (lazy x) -> + f env x + + method private visit_list: 'env 'a . + ('env -> 'a -> unit) -> 'env -> 'a list -> unit + = fun f env xs -> + match xs with + | [] -> + () + | x :: xs -> + f env x; + self # visit_list f env xs + + method private visit_nativeint: 'env . + 'env -> nativeint -> unit + = fun _ _ -> () + + method private visit_option: 'env 'a . + ('env -> 'a -> unit) -> 'env -> 'a option -> unit + = fun f env ox -> + match ox with + | None -> + () + | Some x -> + f env x + + method private visit_ref: 'env 'a . + ('env -> 'a -> unit) -> 'env -> 'a ref -> unit + = fun f env rx -> + f env !rx + + method private visit_result: 'env 'a 'e. + ('env -> 'a -> unit) -> + ('env -> 'e -> unit) -> + 'env -> ('a, 'e) result -> unit + = fun f g env r -> + match r with + | Ok a -> f env a + | Error b -> g env b + + method private visit_string: 'env . + 'env -> string -> unit + = fun _ _ -> () + + method private visit_unit: 'env . + 'env -> unit -> unit + = fun _ _ -> () + +end + +(* -------------------------------------------------------------------------- *) + +(* [map] *) + +class ['self] map = object (self) + + method private visit_array: 'env 'a 'b . + ('env -> 'a -> 'b) -> 'env -> 'a array -> 'b array + = fun f env xs -> + Array.map (f env) xs + (* We could in principle inline [Array.map] so as to avoid allocating + the closure [f env]. That would be a bit painful, though. Anyway, + in [flambda] mode, the compiler might be able to do that for us. *) + + method private visit_bool: 'env . + 'env -> bool -> bool + = fun _ x -> x + + method private visit_bytes: 'env . + 'env -> bytes -> bytes + = fun _ x -> x + + method private visit_char: 'env . + 'env -> char -> char + = fun _ x -> x + + method private visit_float: 'env . + 'env -> float -> float + = fun _ x -> x + + method private visit_int: 'env . + 'env -> int -> int + = fun _ x -> x + + method private visit_int32: 'env . + 'env -> int32 -> int32 + = fun _ x -> x + + method private visit_int64: 'env . + 'env -> int64 -> int64 + = fun _ x -> x + + method private visit_lazy_t: 'env 'a 'b . + ('env -> 'a -> 'b) -> 'env -> 'a Lazy.t -> 'b Lazy.t + = fun f env thx -> + (* We seem to have two options: either force the suspension now + and rebuild a trivial suspension, or build now a suspension + that will perform the traversal when forced. We choose the + latter, which seems more interesting. If this is not the + desired behavior, it can of course be overridden. *) + lazy (f env (Lazy.force thx)) + + method private visit_list: 'env 'a 'b . + ('env -> 'a -> 'b) -> 'env -> 'a list -> 'b list + = fun f env xs -> + match xs with + | [] -> + [] + | x :: xs -> + let x = f env x in + x :: self # visit_list f env xs + + method private visit_nativeint: 'env . + 'env -> nativeint -> nativeint + = fun _ x -> x + + method private visit_option: 'env 'a 'b . + ('env -> 'a -> 'b) -> 'env -> 'a option -> 'b option + = fun f env ox -> + match ox with + | None -> + None + | Some x -> + Some (f env x) + + method private visit_ref: 'env 'a 'b . + ('env -> 'a -> 'b) -> 'env -> 'a ref -> 'b ref + = fun f env rx -> + ref (f env !rx) + + method private visit_result: 'env 'a 'b 'e 'f . + ('env -> 'a -> 'b) -> + ('env -> 'e -> 'f) -> + 'env -> ('a, 'e) result -> ('b, 'f) result + = fun f g env r -> + match r with + | Ok a -> Ok (f env a) + | Error b -> Error (g env b) + + method private visit_string: 'env . + 'env -> string -> string + = fun _ x -> x + + method private visit_unit: 'env . + 'env -> unit -> unit + = fun _ x -> x + +end + +(* -------------------------------------------------------------------------- *) + +(* [endo] *) + +class ['self] endo = object (self) + + (* We might wish to inherit from [map] and override only those methods where + a physical equality check is needed. Yet, we cannot do that, because some + methods, like [visit_list], have more restrictive types in this class than + in the class [map]. *) + + (* It may seem fishy to use an [endo] visitor at type [array], but one never + knows -- maybe the user wants this. Maybe she is using an array as an + immutable data structure. *) + + method private visit_array: 'env 'a . + ('env -> 'a -> 'a) -> 'env -> 'a array -> 'a array + = fun f env xs -> + let xs' = Array.map (f env) xs in + if array_equal (==) xs xs' then xs else xs' + + method private visit_bool: 'env . + 'env -> bool -> bool + = fun _ x -> x + + method private visit_bytes: 'env . + 'env -> bytes -> bytes + = fun _ x -> x + + method private visit_char:'env . + 'env -> char -> char + = fun _ x -> x + + method private visit_float: 'env . + 'env -> float -> float + = fun _ x -> x + + method private visit_int: 'env . + 'env -> int -> int + = fun _ x -> x + + method private visit_int32: 'env . + 'env -> int32 -> int32 + = fun _ x -> x + + method private visit_int64: 'env . + 'env -> int64 -> int64 + = fun _ x -> x + + method private visit_lazy_t : 'env 'a . + ('env -> 'a -> 'a) -> 'env -> 'a Lazy.t -> 'a Lazy.t + = fun f env thx -> + (* We could use the same code as in [map], which does not preserve sharing. + Or, we can force the suspension now, compute [x'], and if [x] and + [x'] coincide, then we can return the original suspension (now + forced), so as to preserve sharing. We choose the latter behavior. If + this is not the desired behavior, it can of course be overridden. *) + let x = Lazy.force thx in + let x' = f env x in + if x == x' then thx else lazy x' + + method private visit_list: 'env 'a . + ('env -> 'a -> 'a) -> 'env -> 'a list -> 'a list + = fun f env this -> + match this with + | [] -> + [] + | x :: xs -> + let x' = f env x in + let xs' = self # visit_list f env xs in + if x == x' && xs == xs' then + this + else + x' :: xs' + + method private visit_nativeint: 'env . + 'env -> nativeint -> nativeint + = fun _ x -> x + + method private visit_option: 'env 'a . + ('env -> 'a -> 'a) -> 'env -> 'a option -> 'a option + = fun f env ox -> + match ox with + | None -> + None + | Some x -> + let x' = f env x in + if x == x' then + ox + else + Some x' + + (* It probably does not make sense to use an [endo] visitor at type + [ref], but one never knows -- maybe the user wants this. Anyway, + it is consistent with the behavior of [endo] visitors at mutable + record types. *) + + method private visit_ref: 'env 'a . + ('env -> 'a -> 'a) -> 'env -> 'a ref -> 'a ref + = fun f env rx -> + let x = !rx in + let x' = f env x in + if x == x' then + rx + else + ref x' + + method private visit_result: 'env 'a 'e . + ('env -> 'a -> 'a) -> + ('env -> 'e -> 'e) -> + 'env -> ('a, 'e) result -> ('a, 'e) result + = fun f g env r -> + match r with + | Ok a -> + let a' = f env a in + if a == a' then r else Ok a' + | Error b -> + let b' = g env b in + if b == b' then r else Error b' + + method private visit_string: 'env . + 'env -> string -> string + = fun _ x -> x + + method private visit_unit: 'env . + 'env -> unit -> unit + = fun _ x -> x + +end + +(* -------------------------------------------------------------------------- *) + +(* [reduce] *) + +(* For arrays and lists, we use [fold_left] instead of a natural (bottom-up) + fold. The order in which the elements are traversed is the same either way + (namely, left-to-right) but the manner in which the [plus] operations are + associated is not the same, so the [plus] operator should be associative. + + We could go back to a natural fold, but we would lose tail recursion. *) + +class virtual ['self] reduce = object (self : 'self) + + inherit ['s] monoid + + method private visit_array: 'env 'a . + ('env -> 'a -> 's) -> 'env -> 'a array -> 's + = fun f env xs -> + Array.fold_left (fun s x -> self#plus s (f env x)) self#zero xs + (* We might wish to inline [Array.fold_left] and save a closure + allocation. That said, in flambda mode, the compiler might be + able to do that automatically. *) + + method private visit_bool: 'env . + 'env -> bool -> 's + = fun _env _ -> self#zero + + method private visit_bytes: 'env . + 'env -> bytes -> 's + = fun _env _ -> self#zero + + method private visit_char: 'env . + 'env -> char -> 's + = fun _env _ -> self#zero + + method private visit_float: 'env . + 'env -> float -> 's + = fun _env _ -> self#zero + + method private visit_int: 'env . + 'env -> int -> 's + = fun _env _ -> self#zero + + method private visit_int32: 'env . + 'env -> int32 -> 's + = fun _env _ -> self#zero + + method private visit_int64: 'env . + 'env -> int64 -> 's + = fun _env _ -> self#zero + + method private visit_lazy_t: 'env 'a . + ('env -> 'a -> 's) -> 'env -> 'a Lazy.t -> 's + = fun f env (lazy x) -> + f env x + + method private visit_list: 'env 'a . + ('env -> 'a -> 's) -> 'env -> 'a list -> 's + = fun f env xs -> + self # list_fold_left f env self#zero xs + (* The above line is equivalent to the following: *) + (* List.fold_left (fun s x -> self#plus s (f env x)) self#zero xs *) + (* By using the auxiliary method [list_fold_left] instead of calling + the library function [List.fold_left], we save a closure allocation, + at least in non-flambda mode. A micro-benchmark shows no performance + impact, either way. *) + + method private list_fold_left: 'env 'a . + ('env -> 'a -> 's) -> 'env -> 's -> 'a list -> 's + = fun f env s xs -> + match xs with + | [] -> + s + | x :: xs -> + let s = self#plus s (f env x) in + self # list_fold_left f env s xs + + method private visit_nativeint: 'env . + 'env -> nativeint -> 's + = fun _env _ -> self#zero + + method private visit_option: 'env 'a . + ('env -> 'a -> 's) -> 'env -> 'a option -> 's + = fun f env ox -> + match ox with + | Some x -> + f env x + | None -> + self#zero + + method private visit_ref: 'env 'a . + ('env -> 'a -> 's) -> 'env -> 'a ref -> 's + = fun f env rx -> + f env !rx + + method private visit_result: 'env 'a 'e . + ('env -> 'a -> 's) -> + ('env -> 'e -> 's) -> + 'env -> ('a, 'e) result -> 's + = fun f g env r -> + match r with + | Ok a -> + f env a + | Error b -> + g env b + + method private visit_string: 'env . + 'env -> string -> 's + = fun _env _ -> self#zero + + method private visit_unit: 'env . + 'env -> unit -> 's + = fun _env _ -> self#zero + +end + +(* -------------------------------------------------------------------------- *) + +(* [mapreduce] *) + +class virtual ['self] mapreduce = object (self : 'self) + + inherit ['s] monoid + + method private visit_array: 'env 'a 'b . + ('env -> 'a -> 'b * 's) -> 'env -> 'a array -> 'b array * 's + = fun f env xs -> + let s = ref self#zero in + let xs = + Array.map (fun x -> + let x, sx = f env x in + s := self#plus !s sx; + x + ) xs + in + xs, !s + + method private visit_bool: 'env . + 'env -> bool -> bool * 's + = fun _ x -> x, self#zero + + method private visit_bytes: 'env . + 'env -> bytes -> bytes * 's + = fun _ x -> x, self#zero + + method private visit_char: 'env . + 'env -> char -> char * 's + = fun _ x -> x, self#zero + + method private visit_float: 'env . + 'env -> float -> float * 's + = fun _ x -> x, self#zero + + method private visit_int: 'env . + 'env -> int -> int * 's + = fun _ x -> x, self#zero + + method private visit_int32: 'env . + 'env -> int32 -> int32 * 's + = fun _ x -> x, self#zero + + method private visit_int64: 'env . + 'env -> int64 -> int64 * 's + = fun _ x -> x, self#zero + + method private visit_lazy_t: 'env 'a 'b . + ('env -> 'a -> 'b * 's) -> 'env -> 'a Lazy.t -> 'b Lazy.t * 's + = fun f env (lazy x) -> + (* Because we must compute a summary now, it seems that we have to + force the suspension now. One should be aware that this is not + the same behavior as the one we chose in the class [map]. *) + let y, s = f env x in + lazy y, s + + method private visit_list: 'env 'a 'b . + ('env -> 'a -> 'b * 's) -> 'env -> 'a list -> 'b list * 's + = fun f env xs -> + match xs with + | [] -> + [], self#zero + | x :: xs -> + let x, sx = f env x in + let xs, sxs = self # visit_list f env xs in + x :: xs, self#plus sx sxs + (* This is not the same strategy as in the class [reduce], where we + used an accumulator and a tail-recursive left fold. Here, we are + using a right fold. The order in which list elements are visited + is left-to-right in both cases, but the tree of [self#plus] ops + is not balanced the same way. *) + + method private visit_nativeint: 'env . + 'env -> nativeint -> nativeint * 's + = fun _ x -> x, self#zero + + method private visit_option: 'env 'a_0 'a_1 . + ('env -> 'a_0 -> 'a_1 * 's) -> + 'env -> 'a_0 option -> 'a_1 option * 's + = fun visit_'a env this -> + match this with + | None -> + None, self#zero + | Some c0 -> + let r0, s0 = visit_'a env c0 in + Some r0, s0 + + method private visit_ref: 'env 'a_0 'a_1 . + ('env -> 'a_0 -> 'a_1 * 's) -> + 'env -> 'a_0 ref -> 'a_1 ref * 's + = fun visit_'a env this -> + let r0, s0 = visit_'a env !this in + ref r0, s0 + + method private visit_result: 'env 'a_0 'a_1 'b_0 'b_1 . + ('env -> 'a_0 -> 'a_1 * 's) -> + ('env -> 'b_0 -> 'b_1 * 's) -> + 'env -> ('a_0, 'b_0) result -> ('a_1, 'b_1) result * 's + = fun visit_'a visit_'b env this -> + match this with + | Ok c0 -> + let r0, s0 = visit_'a env c0 in + Ok r0, s0 + | Error c0 -> + let r0, s0 = visit_'b env c0 in + Error r0, s0 + + method private visit_string: 'env . + 'env -> string -> string * 's + = fun _ x -> x, self#zero + + method private visit_unit: 'env . + 'env -> unit -> unit * 's + = fun _ x -> x, self#zero + +end + +(* -------------------------------------------------------------------------- *) + +(* [fold] *) + +class ['self] fold = object (_self) + + (* No methods are provided, as we do not wish to fix the types of these + methods. It is up to the user to inherit from a class that defines + appropriate methods. Note that [VisitorsRuntime.map] is likely to be + appropriate in many situations. *) + +end + +(* -------------------------------------------------------------------------- *) + +(* [iter2] *) + +class ['self] iter2 = object (self) + + method private visit_array: 'env 'a 'b . + ('env -> 'a -> 'b -> unit) -> 'env -> 'a array -> 'b array -> unit + = fun f env xs1 xs2 -> + (* We inline [Array.iter2]. *) + if Array.length xs1 = Array.length xs2 then + for i = 0 to Array.length xs1 - 1 do + f env (Array.unsafe_get xs1 i) (Array.unsafe_get xs2 i) + done + else + fail() + + method private visit_bool: 'env . + 'env -> bool -> bool -> unit + = fun _ x1 x2 -> if x1 = x2 then () else fail() + + method private visit_bytes: 'env . + 'env -> bytes -> bytes -> unit + = fun _ x1 x2 -> if x1 = x2 then () else fail() + + method private visit_char: 'env . + 'env -> char -> char -> unit + = fun _ x1 x2 -> if x1 = x2 then () else fail() + + method private visit_float: 'env . + 'env -> float -> float -> unit + = fun _ x1 x2 -> if x1 = x2 then () else fail() + + method private visit_int: 'env . + 'env -> int -> int -> unit + = fun _ x1 x2 -> if x1 = x2 then () else fail() + + method private visit_int32: 'env . + 'env -> int32 -> int32 -> unit + = fun _ x1 x2 -> if x1 = x2 then () else fail() + + method private visit_int64: 'env . + 'env -> int64 -> int64 -> unit + = fun _ x1 x2 -> if x1 = x2 then () else fail() + + method private visit_lazy_t: 'env 'a 'b . + ('env -> 'a -> 'b -> unit) -> 'env -> 'a Lazy.t -> 'b Lazy.t -> unit + = fun f env (lazy x1) (lazy x2) -> + f env x1 x2 + + method private visit_list: 'env 'a 'b . + ('env -> 'a -> 'b -> unit) -> 'env -> 'a list -> 'b list -> unit + = fun f env xs1 xs2 -> + match xs1, xs2 with + | [], [] -> + () + | x1 :: xs1, x2 :: xs2 -> + f env x1 x2; + self # visit_list f env xs1 xs2 + | _, _ -> + fail() + + method private visit_nativeint: 'env . + 'env -> nativeint -> nativeint -> unit + = fun _ x1 x2 -> if x1 = x2 then () else fail() + + method private visit_option: 'env 'a 'b . + ('env -> 'a -> 'b -> unit) -> 'env -> 'a option -> 'b option -> unit + = fun f env ox1 ox2 -> + match ox1, ox2 with + | None, None -> + () + | Some x1, Some x2 -> + f env x1 x2 + | _, _ -> + fail() + + method private visit_ref: 'env 'a 'b . + ('env -> 'a -> 'b -> unit) -> 'env -> 'a ref -> 'b ref -> unit + = fun f env rx1 rx2 -> + f env !rx1 !rx2 + + method private visit_result: 'env 'a 'b 'e 'f . + ('env -> 'a -> 'b -> unit) -> + ('env -> 'e -> 'f -> unit) -> + 'env -> ('a, 'e) result -> ('b, 'f) result -> unit + = fun f g env r1 r2 -> + match r1, r2 with + | Ok a1, Ok a2 -> f env a1 a2 + | Error b1, Error b2 -> g env b1 b2 + | _, _ -> fail() + + method private visit_string: 'env . + 'env -> string -> string -> unit + = fun _ x1 x2 -> if x1 = x2 then () else fail() + + method private visit_unit: 'env . + 'env -> unit -> unit -> unit + = fun _ _x1 _x2 -> () + +end + +(* -------------------------------------------------------------------------- *) + +(* [map2] *) + +class ['self] map2 = object (self) + + method private visit_array: 'env 'a 'b 'c . + ('env -> 'a -> 'b -> 'c) -> 'env -> 'a array -> 'b array -> 'c array + = fun f env xs1 xs2 -> + if Array.length xs1 = Array.length xs2 then + Array.mapi (fun i x1 -> f env x1 xs2.(i)) xs1 + (* Array.map2 (f env) xs1 xs2 *) + (* We avoid [Array.map2] because it does not exist in OCaml 4.02. *) + else + fail() + + method private visit_bool: 'env . + 'env -> bool -> bool -> bool + = fun _ x1 x2 -> if x1 = x2 then x1 else fail() + + method private visit_bytes: 'env . + 'env -> bytes -> bytes -> bytes + = fun _ x1 x2 -> if x1 = x2 then x1 else fail() + + method private visit_char: 'env . + 'env -> char -> char -> char + = fun _ x1 x2 -> if x1 = x2 then x1 else fail() + + method private visit_float: 'env . + 'env -> float -> float -> float + = fun _ x1 x2 -> if x1 = x2 then x1 else fail() + + method private visit_int: 'env . + 'env -> int -> int -> int + = fun _ x1 x2 -> if x1 = x2 then x1 else fail() + + method private visit_int32: 'env . + 'env -> int32 -> int32 -> int32 + = fun _ x1 x2 -> if x1 = x2 then x1 else fail() + + method private visit_int64: 'env . + 'env -> int64 -> int64 -> int64 + = fun _ x1 x2 -> if x1 = x2 then x1 else fail() + + method private visit_lazy_t: 'env 'a 'b 'c . + ('env -> 'a -> 'b -> 'c) -> 'env -> 'a Lazy.t -> 'b Lazy.t -> 'c Lazy.t + = fun f env thx1 thx2 -> + (* As in [map]. *) + lazy (f env (Lazy.force thx1) (Lazy.force thx2)) + + method private visit_list: 'env 'a 'b 'c . + ('env -> 'a -> 'b -> 'c) -> 'env -> 'a list -> 'b list -> 'c list + = fun f env xs1 xs2 -> + match xs1, xs2 with + | [], [] -> + [] + | x1 :: xs1, x2 :: xs2 -> + let x = f env x1 x2 in + x :: self # visit_list f env xs1 xs2 + | _, _ -> + fail() + + method private visit_nativeint: 'env . + 'env -> nativeint -> nativeint -> nativeint + = fun _ x1 x2 -> if x1 = x2 then x1 else fail() + + method private visit_option: 'env 'a 'b 'c . + ('env -> 'a -> 'b -> 'c) -> 'env -> 'a option -> 'b option -> 'c option + = fun f env ox1 ox2 -> + match ox1, ox2 with + | None, None -> + None + | Some x1, Some x2 -> + let x = f env x1 x2 in + Some x + | _, _ -> + fail() + + method private visit_ref: 'env 'a 'b 'c . + ('env -> 'a -> 'b -> 'c) -> 'env -> 'a ref -> 'b ref -> 'c ref + = fun f env rx1 rx2 -> + ref (f env !rx1 !rx2) + + method private visit_result: 'env 'a 'b 'c 'e 'f 'g . + ('env -> 'a -> 'b -> 'c) -> + ('env -> 'e -> 'f -> 'g) -> + 'env -> ('a, 'e) result -> ('b, 'f) result -> ('c, 'g) result + = fun f g env r1 r2 -> + match r1, r2 with + | Ok a1, Ok a2 -> Ok (f env a1 a2) + | Error b1, Error b2 -> Error (g env b1 b2) + | _, _ -> fail() + + method private visit_string: 'env . + 'env -> string -> string -> string + = fun _ x1 x2 -> if x1 = x2 then x1 else fail() + + method private visit_unit: 'env . + 'env -> unit -> unit -> unit + = fun _ _x1 _x2 -> () + +end + +(* -------------------------------------------------------------------------- *) + +(* [reduce2] *) + +class virtual ['self] reduce2 = object (self : 'self) + + inherit ['s] monoid + + method private visit_array: 'env 'a 'b . + ('env -> 'a -> 'b -> 's) -> 'env -> 'a array -> 'b array -> 's + = fun f env xs1 xs2 -> + (* OCaml does not offer [Array.fold_left2], so we use [Array.iter2], + which we inline. *) + if Array.length xs1 = Array.length xs2 then + let s = ref self#zero in + for i = 0 to Array.length xs1 - 1 do + let x1 = Array.unsafe_get xs1 i + and x2 = Array.unsafe_get xs2 i in + s := self#plus !s (f env x1 x2) + done; + !s + else + fail() + + method private visit_bool: 'env . + 'env -> bool -> bool -> 's + = fun _env x1 x2 -> + if x1 = x2 then self#zero else fail() + + method private visit_bytes: 'env . + 'env -> bytes -> bytes -> 's + = fun _env x1 x2 -> + if x1 = x2 then self#zero else fail() + + method private visit_char: 'env . + 'env -> char -> char -> 's + = fun _env x1 x2 -> + if x1 = x2 then self#zero else fail() + + method private visit_float: 'env . + 'env -> float -> float -> 's + = fun _env x1 x2 -> + if x1 = x2 then self#zero else fail() + + method private visit_int: 'env . + 'env -> int -> int -> 's + = fun _env x1 x2 -> + if x1 = x2 then self#zero else fail() + + method private visit_int32: 'env . + 'env -> int32 -> int32 -> 's + = fun _env x1 x2 -> + if x1 = x2 then self#zero else fail() + + method private visit_int64: 'env . + 'env -> int64 -> int64 -> 's + = fun _env x1 x2 -> + if x1 = x2 then self#zero else fail() + + method private visit_lazy_t: 'env 'a 'b . + ('env -> 'a -> 'b -> 's) -> 'env -> 'a Lazy.t -> 'b Lazy.t -> 's + = fun f env (lazy x1) (lazy x2) -> + f env x1 x2 + + method private visit_list: 'env 'a 'b . + ('env -> 'a -> 'b -> 's) -> 'env -> 'a list -> 'b list -> 's + = fun f env xs1 xs2 -> + if List.length xs1 = List.length xs2 then + List.fold_left2 (fun s x1 x2 -> self#plus s (f env x1 x2)) self#zero xs1 xs2 + else + fail() + + method private visit_nativeint: 'env . + 'env -> nativeint -> nativeint -> 's + = fun _env x1 x2 -> + if x1 = x2 then self#zero else fail() + + method private visit_option: 'env 'a 'b . + ('env -> 'a -> 'b -> 's) -> 'env -> 'a option -> 'b option -> 's + = fun f env ox1 ox2 -> + match ox1, ox2 with + | Some x1, Some x2 -> + f env x1 x2 + | None, None -> + self#zero + | Some _, None + | None, Some _ -> + fail() + + method private visit_ref: 'env 'a 'b . + ('env -> 'a -> 'b -> 's) -> 'env -> 'a ref -> 'b ref -> 's + = fun f env rx1 rx2 -> + f env !rx1 !rx2 + + method private visit_result: 'env 'a 'b 'e 'f . + ('env -> 'a -> 'b -> 's) -> + ('env -> 'e -> 'f -> 's) -> + 'env -> ('a, 'e) result -> ('b, 'f) result -> 's + = fun f g env r1 r2 -> + match r1, r2 with + | Ok a1, Ok a2 -> + f env a1 a2 + | Error b1, Error b2 -> + g env b1 b2 + | Ok _, Error _ + | Error _, Ok _ -> + fail() + + method private visit_string: 'env . + 'env -> string -> string -> 's + = fun _env x1 x2 -> + if x1 = x2 then self#zero else fail() + + method private visit_unit: 'env . + 'env -> unit -> unit -> 's + = fun _env () () -> + self#zero + +end + +(* -------------------------------------------------------------------------- *) + +(* [mapreduce2] *) + +class virtual ['self] mapreduce2 = object (self) + + inherit ['s] monoid + + method private visit_array: 'env 'a 'b 'c . + ('env -> 'a -> 'b -> 'c * 's) -> 'env -> 'a array -> 'b array -> 'c array * 's + = fun f env xs1 xs2 -> + let n1 = Array.length xs1 + and n2 = Array.length xs2 in + if n1 = n2 then + let s = ref self#zero in + let xs = Array.init n1 (fun i -> + let x1 = Array.unsafe_get xs1 i + and x2 = Array.unsafe_get xs2 i in + let x, sx = f env x1 x2 in + s := self#plus !s sx; + x + ) in + xs, !s + else + fail() + + method private visit_bool: 'env . + 'env -> bool -> bool -> bool * 's + = fun _ x1 x2 -> if x1 = x2 then x1, self#zero else fail() + + method private visit_bytes: 'env . + 'env -> bytes -> bytes -> bytes * 's + = fun _ x1 x2 -> if x1 = x2 then x1, self#zero else fail() + + method private visit_char: 'env . + 'env -> char -> char -> char * 's + = fun _ x1 x2 -> if x1 = x2 then x1, self#zero else fail() + + method private visit_float: 'env . + 'env -> float -> float -> float * 's + = fun _ x1 x2 -> if x1 = x2 then x1, self#zero else fail() + + method private visit_int: 'env . + 'env -> int -> int -> int * 's + = fun _ x1 x2 -> if x1 = x2 then x1, self#zero else fail() + + method private visit_int32: 'env . + 'env -> int32 -> int32 -> int32 * 's + = fun _ x1 x2 -> if x1 = x2 then x1, self#zero else fail() + + method private visit_int64: 'env . + 'env -> int64 -> int64 -> int64 * 's + = fun _ x1 x2 -> if x1 = x2 then x1, self#zero else fail() + + method private visit_lazy_t: 'env 'a 'b 'c . + ('env -> 'a -> 'b -> 'c * 's) -> 'env -> 'a Lazy.t -> 'b Lazy.t -> 'c Lazy.t * 's + = fun f env (lazy x1) (lazy x2) -> + (* As in [mapreduce]. *) + let y, s = f env x1 x2 in + lazy y, s + + method private visit_list: 'env 'a_0 'a_1 'a_2 . + ('env -> 'a_0 -> 'a_1 -> 'a_2 * 's) -> + 'env -> 'a_0 list -> 'a_1 list -> 'a_2 list * 's + = fun visit_'a env this_0 this_1 -> + match this_0, this_1 with + | [], [] -> + [], self#zero + | c0_0 :: c1_0, c0_1 :: c1_1 -> + let r0, s0 = visit_'a env c0_0 c0_1 in + let r1, s1 = self#visit_list visit_'a env c1_0 c1_1 in + r0 :: r1, self#plus s0 s1 + | _, _ -> + fail() + + method private visit_nativeint: 'env . + 'env -> nativeint -> nativeint -> nativeint * 's + = fun _ x1 x2 -> if x1 = x2 then x1, self#zero else fail() + + method private visit_option: 'env 'a_0 'a_1 'a_2 . + ('env -> 'a_0 -> 'a_1 -> 'a_2 * 's) -> + 'env -> 'a_0 option -> 'a_1 option -> 'a_2 option * 's + = fun visit_'a env this_0 this_1 -> + match this_0, this_1 with + | None, None -> + None, self#zero + | Some c0_0, Some c0_1 -> + let r0, s0 = visit_'a env c0_0 c0_1 in + Some r0, s0 + | _, _ -> + fail() + + method private visit_ref: 'env 'a_0 'a_1 'a_2 . + ('env -> 'a_0 -> 'a_1 -> 'a_2 * 's) -> + 'env -> 'a_0 ref -> 'a_1 ref -> 'a_2 ref * 's + = fun visit_'a env this_0 this_1 -> + let r0, s0 = visit_'a env !this_0 !this_1 in + ref r0, s0 + + method private visit_result: 'env 'a_0 'a_1 'a_2 'b_0 'b_1 'b_2 . + ('env -> 'a_0 -> 'a_1 -> 'a_2 * 's) -> + ('env -> 'b_0 -> 'b_1 -> 'b_2 * 's) -> + 'env -> ('a_0, 'b_0) result -> ('a_1, 'b_1) result -> ('a_2, 'b_2) result * 's + = fun visit_'a visit_'b env this_0 this_1 -> + match this_0, this_1 with + | Ok c0_0, Ok c0_1 -> + let r0, s0 = visit_'a env c0_0 c0_1 in + Ok r0, s0 + | Error c0_0, Error c0_1 -> + let r0, s0 = visit_'b env c0_0 c0_1 in + Error r0, s0 + | _, _ -> + fail() + + method private visit_string: 'env . + 'env -> string -> string -> string * 's + = fun _ x1 x2 -> if x1 = x2 then x1, self#zero else fail() + + method private visit_unit: 'env . + 'env -> unit -> unit -> unit * 's + = fun _ () () -> (), self#zero + +end + +(* -------------------------------------------------------------------------- *) + +(* [fold2] *) + +class ['self] fold2 = object (_self) + + (* See the comment in the class [fold] above. *) + +end diff --git a/runtime/dune b/runtime/dune new file mode 100644 index 0000000..75112ef --- /dev/null +++ b/runtime/dune @@ -0,0 +1,7 @@ +(library + (name VisitorsRuntime) + (public_name visitors.runtime) + (synopsis "Runtime support for the generated visitors") + (libraries result) + (wrapped false) +) diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..441cb57 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,3 @@ +.PHONY: all +all: + @ make -C .. $@ diff --git a/src/Visitors.ml b/src/Visitors.ml new file mode 100644 index 0000000..b459b78 --- /dev/null +++ b/src/Visitors.ml @@ -0,0 +1,1287 @@ +open VisitorsString +open VisitorsList +open Longident +open List +open Asttypes +open Parsetree +open Ast_helper +open Ast_convenience +open Ppx_deriving +open VisitorsPlugin +open VisitorsCompatibility +open VisitorsAnalysis +open VisitorsGeneration +open VisitorsSettings + +(* -------------------------------------------------------------------------- *) + +(* Per-run global state. *) + +module Setup (X : SETTINGS) = struct + +let arity = + X.arity + +(* -------------------------------------------------------------------------- *) + +(* If the [public] option is absent, then every method is public. If it is + present, then every method is private, unless its name occurs in the list + [X.public]. *) + +let visibility m = + match X.public with + | None -> + Public + | Some ms -> + if List.mem m ms then Public else Private + +(* The following brings [generate] and [dump] into scope. *) + +include ClassFieldStore(struct end) + +let annotation (ty : core_type) : core_type option = + (* A type annotation is generated only in [polymorphic] mode. *) + if X.polymorphic then Some ty else None + +let generate_concrete_method m e ty = + generate (concrete_method (visibility m) m e (annotation ty)) + +let generate_virtual_method m ty = + generate (virtual_method (visibility m) m (annotation ty)) + +(* -------------------------------------------------------------------------- *) + +(* The following brings [warning] and [warnings] into scope. *) + +include WarningStore(struct end) + +(* [datacon_opacity_warning cd] emits a warning (if necessary) about the + following issue. One should not write "A of int[@opaque]". Instead, one + should write "A of (int[@opaque])". In the case of records fields, we fix + this silently, by moving the attribute from the record field to the type, + but in the case of data constructors with multiple fields, it is preferable + to be strict. *) + +let datacon_opacity_warning (cd : constructor_declaration) : unit = + if opacity cd.pcd_attributes = Opaque then + warning cd.pcd_loc + "%s: @opaque, attached to a data constructor, is ignored.\n\ + It should be attached to a type. Please use parentheses." + plugin + +(* [sum_build_warning decl] emits emits a warning (if necessary) about the + following issue. One should not attach a [@@build] attribute to a sum type. + Instead, one should attach a [@build] attribute to every data constructor. + Note that one can attach a [@@build] attribute to a record type. *) + +let sum_build_warning (decl : type_declaration) : unit = + if build decl.ptype_attributes <> None then + warning decl.ptype_loc + "%s: @@build, attached to a sum type, is ignored.\n\ + Instead, @build should be attached to each data constructor." + plugin + +(* -------------------------------------------------------------------------- *) + +(* 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, + [int term] or [('a * 'a) term]. *) + +(* To enforce this, we check that, in every use of a local type constructor, + the actual type parameters coincide with the formal type parameters. *) + +(* This check is imposed only on [mono] type variables. For [poly] type + variables, irregularity is allowed. *) + +(* The purpose of this check is to avoid an incomprehensible type error in + the generated code. *) + +let check_regularity loc tycon (formals : tyvars) (actuals : core_types) = + (* Check that the numbers of parameters match. *) + if length formals <> length actuals then + raise_errorf ~loc + "%s: the type constructor %s expects %s,\n\ + but is applied to %s." + plugin tycon + (number (length formals) "type parameter") + (number (length actuals) "type parameter"); + (* Check that the parameters match. *) + if not X.irregular && not ( + fold_left2 (fun ok formal actual -> + ok && (X.poly formal || actual.ptyp_desc = Ptyp_var formal) + ) true formals actuals + ) then + raise_errorf ~loc "%s: the type constructor %s is irregular." plugin tycon + +(* -------------------------------------------------------------------------- *) + +(* 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. + + 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]. *) + +let tycon_modified_name (attrs : attributes) (tycon : tycon) : tycon = + maybe (name attrs) tycon + +(* Similarly, the base name of the methods associated with a data constructor + can be altered via a [@name] attribute, which must be attached to the data + constructor declaration. *) + +let datacon_modified_name (cd : constructor_declaration) : datacon = + maybe (name cd.pcd_attributes) cd.pcd_name.txt + +(* For every type constructor [tycon], there is a visitor method, also called + a descending method, as it is invoked when going down into the tree. *) + +(* 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.) *) + +(* 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_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_loc, ty.ptyp_attributes, tycon.txt) + | _ -> + assert false + +(* For every local record type constructor [tycon], there is an ascending + 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]. *) + +(* The name of this method is normally [build_foo] if the type is named [foo]. *) + +let tycon_ascending_method (decl : type_declaration) : methode = + 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 = + 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. *) + +(* The name of this method is normally [visit_Foo] if the data constructor is + named [Foo]. *) + +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]. *) + +let datacon_ascending_method (cd : constructor_declaration) : methode = + 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 + left-hand and right-hand arguments do not exhibit the same tags. *) + +(* The name of this method is normally [fail_foo] if the type is named [foo]. *) + +let failure_method (decl : type_declaration) : methode = + 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 + that there exist virtual methods by these names. It is up to the user to + provide these methods via inheritance, that is, via the [ancestors] + option. *) + +let zero = + "zero" + +let plus = + "plus" + +(* -------------------------------------------------------------------------- *) + +(* Private naming conventions. *) + +(* These conventions must be set up so as to avoid collisions within each name + space separately: e.g., variables, methods, type variables, and so on. *) + +(* We use improbable variable names, because it is possible for user code to + be placed in the scope of these variables. (This is the case when the user + provides [@build] annotations.) As a couple exceptions, the names [self] + and [env] are not made improbable, and we document the existence of these + variables, which can be used in [@build] annotations. *) + +(* In a class, the variable [self] refers to self. + The type variable [ty_self] denotes its type. *) + +let self : variable = + "self" + +let ty_self : core_type = + Typ.var "self" + +let pself : pattern = + Pat.constraint_ (pvar self) ty_self + +(* The variable [env] refers to the environment that is carried down into + recursive calls. *) + +let env : variable = + "env" + +(* We sometimes need two (or more) copies of a variable: one copy for each + index [j] ranging in the interval [0..arity). *) + +let copy (j : int) (x : string) : string = + assert (0 <= j && j < arity); + if arity = 1 then + (* No alteration required. *) + x + else + sprintf "%s_%d" x j + +(* The variables [component i j] denote tuple components. The index [i] + ranges over tuple components; the index [j] ranges in [0..arity). *) + +let component (i : int) (j : int) : variable = + improbable (copy j (sprintf "c%d" i)) + +let components (i : int) : variables = + map (component i) (interval 0 arity) + +let componentss (xs : _ list) : variables list = + mapi (fun i _ -> components i) xs + +(* The variable [thing j] denotes an input value. *) + +let thing (j : int) : variable = + improbable (copy j "this") + +let things : variables = + map thing (interval 0 arity) + +(* The variable [this] is used only in the generation of [endo] visitors. *) + +let this = + thing 0 + +(* The variables [field label j] denote record fields. *) + +let field (label : label) (j : int) : variable = + improbable (copy j (sprintf "f%s" label)) + +let fields (label : label) : variables = + map (field label) (interval 0 arity) + +let fieldss (labels : label list) : variables list = + map fields labels + +(* The variables [result i] denote results of recursive calls. *) + +let result (i : int) : variable = + improbable (sprintf "r%d" i) + +let results (xs : _ list) : variables = + mapi (fun i _ -> result i) xs + +(* The variables [summary i] denote results of recursive calls. + When the scheme is [MapReduce], each recursive call produces + a pair; we use [result i] and [summary i] as the names of the + pair components. *) + +let summary (i : int) : variable = + improbable (sprintf "s%d" i) + +let summaries (xs : _ list) : variables = + mapi (fun i _ -> summary i) xs + +(* Reserved names of type variables. We forbid the user from using these + names, and do not let them be renamed by the function [variant] below. *) + +let reserved : tyvars = + [ "s"; "env" ] + +let reserved_ty_var (alpha : tyvar) : core_type = + assert (mem alpha reserved); + ty_var alpha + +(* Naming conventions for type variables in type annotations. If ['a] + is a type variable named by the user, we use ['a_i], where [i] is + in [0..arity]. Indices [i] in the interval [0..arity) are used for + the arguments of a visitor method. The index [arity] is used for + the result of a visitor method. *) + +(* If [scheme] is [Endo], then the argument and result must have the + same type, so we do not introduce a variation in the type variables. *) + +let variant (i : int) (alpha : tyvar) : tyvar = + assert (0 <= i && i <= arity); + if X.scheme = Endo || mem alpha reserved then + alpha + else + sprintf "%s_%d" alpha i + +let vary_type (i : int) (ty : core_type) : core_type = + rename_type (variant i) ty + +(* [ty_monoid] is the type of monoid elements. *) + +let ty_monoid = + reserved_ty_var "s" + +(* [ty_env] is the type of the environment. *) + +(* What IS the type of the environment? This is a tricky question. Two + possibilities arise: + + 1. One might wish for every visitor method to be polymorphic in the type + ['env] of the environment. This makes the method more widely applicable, + but means that the environment effectively cannot be used by the method + (except by passing it on to its callees). Thus, the method cannot be + overridden by a custom implementation that actually uses the environment. + + 2. One might wish for the environment to have monomorphic type. In that + case, one should note that there is a priori no reason why the type of + the environment should be the same in every method. So, we must be + careful not to use a single type variable ['env]. We must use a distinct + type variable every time, or (easier but equivalent) use a wildcard. + + How do we let the user specify which behavior is desired? And with what + granularity? We choose a simple approach: we treat ['env] as polymorphic + if and only if this (reserved) type variable is declared polymorphic by + the user. *) + +let ty_env = + if X.poly "env" then + reserved_ty_var "env" + else + ty_any + +(* What is the type of a virtual visitor method [visit_'a] in charge of + dealing with a [mono] type variable ['a]? + + One might think that it must be a monomorphic type, so we can just + issue a wildcard [_] and let OCaml infer this type. + + Yet, if the user has requested that every method be polymorphic in + the type ['env] of the environment, then [visit_'a], too must be + polymorphic in ['env]. (Otherwise, the generated code would be ill-typed.) + In that case, we must generate ['env . 'env -> _]. + + This implies that [visit_'a] cannot use the environment. + So, it seems somewhat doubtful that this feature is useful. + Perhaps we could allow the environment to consist of two components + and to quantify universally over only one of them? *) + +let tyvar_visitor_method_type = + if X.poly "env" then + typ_poly ["env"] (ty_arrow ty_env ty_any) + else + ty_any + +(* [poly] type variables have a visitor function. *) + +let tyvar_visitor_function (alpha : tyvar) : variable = + tyvar_visitor_method alpha + +(* -------------------------------------------------------------------------- *) + +(* Construction of type annotations. *) + +(* [result_type scheme ty] is the result type of a visitor method associated + with the type [ty]. *) + +(* If [ty] is of the form [decl_type decl] -- that is, if [ty] is a local type + constructor -- then this is the result type of the visitor method associated + with [ty]. *) + +let rec result_type scheme (ty : core_type) : core_type = + match scheme with + | Iter -> + (* An [iter] visitor method returns nothing. *) + ty_unit + | Map | Endo -> + (* A [map] or [endo] visitor method for the type [ty] returns a + value of type [ty]. Note that [ty] can contain type variables. *) + ty + | Reduce -> + (* A [reduce] visitor method returns a monoid element. *) + ty_monoid + | MapReduce -> + (* A [mapreduce] visitor method returns a pair of the results produced + by a [map] visitor method and by a [reduce] visitor method. *) + Typ.tuple [ result_type Map ty; result_type Reduce ty ] + | Fold -> + (* This is where we have a problem. We would really like to allow the + user to specify which skeleton should be used here, as we cannot + guess it. We might allow it in the future. For now, we impose the + monomorphic skeleton [_], which is not as general as we would like, + since it requires the method to have monomorphic result type. *) + ty_any + +let result_type = + result_type X.scheme + +(* [decl_result_type decl] is the result type of a visitor method associated + with the type declaration [decl]. *) + +let decl_result_type decl = + result_type (decl_type decl) + +(* A visitor function takes an environment, followed with [arity] arguments, + and produces a result. Thus, if [argument] and [result] are types, then the + type of a visitor function has the following shape: + + ty_env -> + argument_0 -> ... -> argument_{arity-1} -> + result_{arity} + + where [ty_{i}] denotes a copy of the type [ty] whose type variables have + been renamed by the renaming [variant i]. *) + +(* We generalize the above definition to allow for multiple [arguments]. This + is used in the visitor methods associated with data constructors. Thus, + each argument in succession is extended to [arity] arguments. *) + +(* We specialize the above definition to the case where the result type + is [result_type ty]. *) + +let visitor_fun_type (arguments : core_types) (ty : core_type) : core_type = + ty_arrows + (ty_env :: flatten (hextend arguments arity vary_type)) + (vary_type arity (result_type ty)) + +(* This special case of [visitor_fun_type] is the normal form of a visitor + function type: there is one argument of type [ty] (extended to [arity]) + and one result of type [result_type ty]. *) + +let simple_visitor_fun_type (ty : core_type) : core_type = + visitor_fun_type [ty] ty + +(* [visitor_method_type decl] is the type of the visitor method associated + with the type [decl]. This does not account for the visitor parameters + in charge of dealing with type variables. *) + +let visitor_method_type (decl : type_declaration) : core_type = + simple_visitor_fun_type (decl_type decl) + +(* [visitor_param_type alpha] is the type of the visitor function associated + with the type variable [alpha]. *) + +let visitor_param_type (alpha : tyvar) : core_type = + simple_visitor_fun_type (ty_var alpha) + +(* [fold_result_type ty] is the result type of the visitor code generated + by [visit_type ... ty], when [scheme] is [Fold]. *) + +let fold_result_type _ty = + (* This function is currently unimplemented and unused, because we + do not allow [polymorphic] to be [true] when [scheme] is [Fold]. + Thus, we do not generate any type annotations for ascending methods. *) + ty_any + +(* [poly_params decl] is the subset of the formal type parameters of [decl] + which are marked [poly]. For each of these parameters, a visitor function + should be passed. *) + +let poly_params (decl : type_declaration) : tyvars = + filter X.poly (decl_params decl) + +(* [quantify alphas ty] quantifies an appropriate set of type variables in the + method type [ty]. The parameter [alphas] is usually [poly_params decl], + although it could in principle be a subset of it, if we can prove that + some visitor functions are unneeded. We introduce universal quantifiers + on (suitable variants of) the type variables [alphas] and also possibly + on the type variable ['env]. *) + +let quantify (alphas : tyvars) (ty : core_type) : core_type = + (* Find out which variants of the type variables [alphas] we should quantify + over. For the arguments, we need to quantify over the variants in the + interval [0..arity). For the result, we may need to quantify over the + variant [arity]. We try and avoid superfluous quantifiers, as that would + decrease readability. *) + let alphas = + match X.scheme with + | Iter + | Reduce -> + (* Just the arguments. The result contains no type variables. *) + flatten (hextend alphas arity variant) + | Map + | MapReduce -> + (* Arguments and result. *) + flatten (hextend alphas (arity+1) variant) + | Endo -> + (* In this special case, there is just one variant, as the argument + and result must have the same type. *) + alphas + | Fold -> + (* Polymorphism currently not supported with [Fold]. *) + [] + in + (* Then, decide whether ['env] should be universally quantified. *) + let alphas = + if X.poly "env" then + "env" :: alphas + else + alphas + in + (* Done. *) + typ_poly alphas ty + +(* -------------------------------------------------------------------------- *) + +(* [bind rs ss] is a binding construct which, depending on the scheme, binds + either the variables [rs], or the variables [ss], or both, using pair + patterns. It is used to bind the results of recursive calls to visitor + methods. *) + +let bind (rs : variables) (ss : variables) + : expressions -> expression -> expression = + match X.scheme with + | Iter + | Map + | Endo + | Fold -> + letn rs + | Reduce -> + letn ss + | MapReduce -> + letnp rs ss + +(* -------------------------------------------------------------------------- *) + +(* [call m es] emits a method call of the form [self#m es]. *) + +let call (m : methode) (es : expressions) : expression = + send self m es + +(* -------------------------------------------------------------------------- *) + +(* Access to the monoid operations. *) + +let monoid_unit () : expression = + assert (X.scheme = Reduce || X.scheme = MapReduce); + call zero [] + +let monoid_law () : expression = + assert (X.scheme = Reduce || X.scheme = MapReduce); + call plus [] + +(* -------------------------------------------------------------------------- *) + +(* [reduce es] reduces the expressions [es], that is, it combines them, using + a monoid, which provides a unit and a binary operation. The reduction is + performed left-to-right. This could be of importance if the monoid is not + associative-commutative. *) + +let reduce es = + let unit = monoid_unit() + and law = monoid_law() in + fold_left1 (fun e1 e2 -> app law [e1; e2]) unit es + +(* -------------------------------------------------------------------------- *) + +(* [alias x ps] requires the pattern list [ps] to have length [arity]. If + [scheme] is [Endo], then it further requires [arity] to be 1. It adds a + binding of the variable [x], using an [as] pattern, at the top level of the + pattern. The result is again packaged as a pattern list of length [arity]. + If scheme is not [Endo], then [alias x ps] is just [ps]. *) + +let alias (x : variable) (ps : patterns) : patterns = + assert (length ps = arity); + match X.scheme with + | Endo -> + assert (arity = 1); + map (fun p -> + Pat.alias p (Location.mknoloc x) + ) ps + | _ -> + ps + +(* If [scheme] is [Endo], then [transmit x xs] is [x :: xs]. Otherwise, it is + just [xs]. *) + +let transmit x xs = + match X.scheme with + | Endo -> + x :: xs + | _ -> + xs + +(* -------------------------------------------------------------------------- *) + +(* [hook m xs ty e] constructs a call of the form [self#m xs], and (as a side + effect) generates a method [method m xs = e]. The free variables of the + expression [e] must be (a subset of) [xs]. The type [ty] is the type of + the method. It is always computed internally, but the type annotation is + actually printed only in [polymorphic] mode. *) + +(* Thus, by default, the expression [hook m xs ty e] behaves in the same way + as the expression [e]. But a hook, named [m], allows this default to be + overridden. *) + +let hook (m : methode) (xs : variables) (ty : core_type) (e : expression) : expression = + (* Generate a method. *) + generate_concrete_method m (lambdas xs e) ty; + (* Construct a method call. *) + call m (evars xs) + +(* The additional parameter [b] makes hook insertion optional. If [b] is [true], + a hook is created; otherwise, no hook is created. *) + +let hook b m xs ty e = + if b then hook m xs ty e else e + +(* -------------------------------------------------------------------------- *) + +(* [vhook m xs ty] constructs a call of the form [self#m xs], and (as a side + effect) generates a virtual method [method m: ty]. The type [ty] is the type + of the method. It is always computed internally, but the type annotation is + actually printed only in [polymorphic] mode. *) + +let vhook (m : methode) (xs : variables) (ty : core_type) : expression = + generate_virtual_method m ty; + call m (evars xs) + +(* -------------------------------------------------------------------------- *) + +(* If a data constructor or record carries a [@build] attribute, then the + OCaml expression carried by this attribute should be used instead of the + default [builder] function, which rebuilds a data constructor or record. + This concerns [map], [endo], and [mapreduce] visitors. *) + +type builder = + variables -> expression + +let ifbuild (attrs : attributes) (builder : builder) : builder = + match build attrs with + | None -> + builder + | Some e -> + fun rs -> app e (evars rs) + +(* -------------------------------------------------------------------------- *) + +(* The following classes help build the code that forms the ascending part of + a visitor method, that is, the code found after the recursive calls. *) + +(* There are four variants of this code, used in visitor methods for data + constructors, in visitor methods for records, in visitor functions for + tuples, and in visitor functions for @opaque types. *) + +(* The base class, [ascend], provides as much shared behavior as possible. *) + +class virtual ascend (ss : variables) = object (self) + + (* An [iter] visitor returns a unit value. *) + method ascend_Iter = + unit() + + (* The behavior of a [map] visitor is defined in subclasses. *) + method virtual ascend_Map : expression + + (* By default, an [endo] visitor behaves like a [map] visitor. This behavior + is appropriate at @opaque types. *) + method ascend_Endo = + self#ascend_Map + + (* A [reduce] visitor uses [zero] and [plus] to combine the results + of the recursive calls, which are bound to the variables [ss]. *) + method ascend_Reduce = + reduce (evars ss) + + (* A [mapreduce] visitor returns a pair of the results that would be + returned by a [map] visitor and by a [reduce] visitor. *) + method ascend_MapReduce = + tuple [ self#ascend_Map; self#ascend_Reduce ] + + (* By default, a [fold] visitor behaves like a [map] visitor, because we + have no better choice. This behavior is used at tuples and at @opaque + types. *) + method ascend_Fold = + self#ascend_Map + + (* Dispatch. *) + method ascend = + match X.scheme with + | Iter -> self#ascend_Iter + | Map -> self#ascend_Map + | Endo -> self#ascend_Endo + | Reduce -> self#ascend_Reduce + | MapReduce -> self#ascend_MapReduce + | Fold -> self#ascend_Fold + +end + +(* The subclass [ascend_opaque] defines the desired behavior at @opaque types. *) + +(* In an [iter] visitor, we return a unit value, as always. This means that, + even if [arity] is greater than 1, NO EQUALITY TEST takes place. This + differs from the behavior of the methods [visit_int], [visit_bool], etc., + which perform an equality test. *) + +(* In a [map] visitor, we return THE FIRST ARGUMENT of the visitor. At arity + greater than 1, this is an ARBITRARY choice. It is not clear what else we + could do. *) + +(* In a [reduce] visitor, we return the neutral element, [self#zero]. *) + +(* In a [fold] visitor, we keep the default behavior, which is to behave like + a [map] visitor. *) + +class ascend_opaque (xs : variables) = object + + inherit ascend [] + + method ascend_Map = + evar (hd xs) (* [xs] is the vector of arguments; pick the first one *) + +end + +(* The subclass [ascend_endo] defines the standard behavior of an [endo] + visitor, which is to perform physical equality tests. *) + +(* Its parameters are as follows: + + [this] (a variable for) the data structure that is visited + [subjects] the matrix of arguments to the recursive calls + [rs], [ss] (vectors of variables for) the results of the recursive calls *) + +class virtual ascend_endo + (this : variable) + (subjects : expressions list) + (rs : variables) + (ss : variables) += object (self) + + inherit ascend ss + + (* An [endo] visitor first tests if the arguments of the recursive calls, + [subjects], are physically equal to the results of these calls, [rs]. If + that is the case, then it returns the original data structure, [this]. + Otherwise, it reconstructs a new data structure, like a [map] visitor. *) + method! ascend_Endo = + (* [subjects] is a matrix of width [arity], and [arity] is [1]. The first + column of [subjects] is [map hd subjects]. *) + assert (for_all (fun es -> length es = arity) subjects); + assert (arity = 1); + Exp.ifthenelse + (eqphys (map hd subjects) (evars rs)) + (evar this) + (Some self#ascend_Map) + +end + +(* The subclass [ascend_tuple] defines the desired behavior at tuple types. *) + +class ascend_tuple this subjects rs ss = object + + inherit ascend_endo this subjects rs ss + + (* A [map] visitor reconstructs a tuple. *) + method ascend_Map = + tuple (evars rs) + +end + +(* The subclass [ascend_algebraic] defines the desired behavior at a sum type + or record type. Its extra parameters are as follows: + + [builder] how to reconstruct a data constructor or record + [decl] the type declaration under which we are working + [m] the name of the virtual ascending method + [tys] the types of the components of this data constructor or record *) + +class ascend_algebraic this subjects rs ss + (builder : builder) + (decl : type_declaration) + (m : methode) + (tys : core_types) += object + + inherit ascend_endo this subjects rs ss + + (* A [map] visitor reconstructs a data structure using the results [rs] of + the recursive calls. *) + method ascend_Map = + builder rs + + (* A [fold] visitor invokes the virtual ascending method [m], with [env] and + [rs] as arguments. As a side effect, [ascend_Fold] declares this virtual + method. *) + method! ascend_Fold = + vhook m + (env :: rs) + (ty_arrows + (ty_env :: map fold_result_type tys) + (decl_result_type decl) + ) + +end + +(* -------------------------------------------------------------------------- *) + +(* [visit_type env_in_scope ty] builds a small expression that represents the + visiting code associated with the OCaml type [ty]. For instance, if [ty] is + a local type constructor, this could be a call to the visitor method + associated with this type constructor. *) + +(* This expression may refer to the variable [self]. *) + +(* If [env_in_scope] is true, then this expression may refer to the variable + [env]. If [env_in_scope] is false, then this expression should denote a + function of [env]. The use of [env_in_scope] complicates things slightly, + but allows us to avoid the production of certain eta-redexes. *) + +(* If [ty] carries the attribute [@opaque], then we act as if there is nothing + to visit. The nature of the type [ty], in that case, plays no role. *) + +let rec visit_type (env_in_scope : bool) (ty : core_type) : expression = + match env_in_scope, opacity ty.ptyp_attributes, ty.ptyp_desc with + + (* A type constructor [tycon] applied to type parameters [tys]. We handle + the case where [env_in_scope] is false, so we construct a function of + [env]. *) + | false, + NonOpaque, + Ptyp_constr ({ txt = tycon; _ }, tys) -> + (* [tycon] is a type constructor, applied to certain types [tys]. *) + (* We must call the visitor method associated with [tycon], + applied to the visitor functions associated with SOME of the [tys]. *) + let m, tys = + match is_local X.decls tycon with + | Some decl -> + let formals = decl_params decl in + (* [tycon] is a local type constructor, whose formal type parameters + are [formals]. Among these formal type parameters, some should be + treated in a monomorphic manner, and some should be treated in a + polymorphic manner. The function [X.poly], applied to a type + variable [formal], tells how it should be treated. *) + (* The regularity check is applied only to [mono] parameters. *) + check_regularity ty.ptyp_loc (last tycon) formals tys; + (* The visitor method should be applied to the visitor functions + associated with the subset of [tys] that corresponds to [poly] + variables. *) + local_tycon_visitor_method decl, + filter2 X.poly formals tys + | None -> + (* [tycon] is a nonlocal type constructor. *) + (* The visitor method should be applied to visitor functions for all + of the types [tys]. *) + (* This visitor method is NOT generated by us, so it MUST be + inherited from an ancestor class; it is up to the user to + ensure that this method exists. (It may be virtual.) This + method may be polymorphic, so multiple call sites do not + pollute one another. *) + nonlocal_tycon_visitor_method ty, + tys + in + app + (call m []) + (map (visit_type false) tys) + + (* A type variable [alpha] must be a formal parameter of the current + declaration. (Indeed, we do not handle GADTs yet.) Now, two cases + arise. If [alpha] is [mono], then it is handled by a virtual visitor + method. If [alpha] is [poly], then it is handled by a visitor function + which we must have received as an argument. *) + | false, + NonOpaque, + Ptyp_var alpha -> + if X.poly alpha then + evar (tyvar_visitor_function alpha) + else + vhook (tyvar_visitor_method alpha) [] tyvar_visitor_method_type + + (* A tuple type. We handle the case where [env_in_scope] is true, as it + is easier. *) + | true, + NonOpaque, + Ptyp_tuple tys -> + (* Construct a function that takes [arity] tuples as arguments. *) + (* See [constructor_declaration] for comments. *) + let xss = componentss tys in + let subjects = evarss xss in + let rs = results xss + and ss = summaries xss in + let ascend = new ascend_tuple this subjects rs ss in + plambdas + (alias this (ptuples (transpose arity (pvarss xss)))) + (bulk rs ss tys subjects ascend) + + (* If [env_in_scope] does not have the desired value, wrap a recursive call + within an application or abstraction. At most one recursive call takes + place, so we never produce an eta-redex. *) + | true, NonOpaque, (Ptyp_constr _ | Ptyp_var _) -> + app (visit_type false ty) [evar env] + | false, _, _ -> + lambda env (visit_type true ty) + + (* If [ty] is marked opaque, then we ignore the structure of [ty] and carry + out appropriate action, based on the current scheme. *) + | true, Opaque, _ -> + (* Construct a function that takes [arity] arguments. *) + lambdas things ( + let ascend = new ascend_opaque things in + ascend#ascend + ) + + (* An unsupported construct. *) + | _, _, Ptyp_any + | _, _, Ptyp_arrow _ + | _, _, Ptyp_object _ + | _, _, Ptyp_class _ + | _, _, Ptyp_alias _ + | _, _, Ptyp_variant _ + | _, _, Ptyp_poly _ + | _, _, Ptyp_package _ + | _, _, Ptyp_extension _ -> + unsupported ty + +and visit_types tys (ess : expressions list) : expressions = + (* The matrix [ess] is indexed first by component, then by index [j]. + Thus, to each type [ty], corresponds a row [es] of expressions, + whose length is [arity]. *) + assert (is_matrix (length tys) arity ess); + map2 (fun ty es -> + app (visit_type true ty) es + ) tys ess + +(* -------------------------------------------------------------------------- *) + +(* The expression [bulk rs ss tys subjects ascend] represents the bulk of a + visitor method or visitor function. It performs the recursive calls, binds + their results to [rs] and/or [ss], then runs the ascending code. *) + +and bulk + (rs : variables) (ss : variables) + (tys : core_types) + (subjects : expressions list) + (ascend : < ascend: expression; .. >) += + bind rs ss + (visit_types tys subjects) + (ascend#ascend) + +(* -------------------------------------------------------------------------- *) + +(* [constructor_declaration] turns a constructor declaration (as found in a + declaration of a sum type) into a case, that is, a branch in the case + analysis construct that forms the body of the visitor method for this sum + type. At the same time, it generates several auxiliary method declarations + and definitions. *) + +let constructor_declaration decl (cd : constructor_declaration) : case = + datacon_opacity_warning cd; + let datacon = cd.pcd_name.txt in + + (* This is either a traditional data constructor, whose components are + anonymous, or a data constructor whose components form an ``inline + record''. This is a new feature of OCaml 4.03. *) + + (* In order to treat these two cases uniformly, we extract the following + information. + [xss] the names under which the components are known. + this matrix has [length tys] rows -- one per component -- + and [arity] columns. + [tys] the types of the components. + [pss] the patterns that bind [xss], on the way down. + this matrix has [arity] rows. + it has [length tys] columns in the case of tuples, + and 1 column in the case of inline records. + [builder] a function which, applied to the results [rs] of the + recursive calls, rebuilds a data constructor, on the way up. + *) + + let xss, tys, pss, (builder : builder) = + match data_constructor_variety cd with + (* A traditional data constructor. *) + | DataTraditional tys -> + let xss = componentss tys in + let pss = transpose arity (pvarss xss) in + xss, tys, pss, fun rs -> constr datacon (evars rs) + (* An ``inline record'' data constructor. *) + | DataInlineRecord (labels, tys) -> + let xss = fieldss labels in + let pss = transpose arity (pvarss xss) in + xss, tys, + map (fun ps -> [precord ~closed:Closed (combine labels ps)]) pss, + fun rs -> constr datacon [record (combine labels (evars rs))] + in + assert (is_matrix (length tys) arity xss); + assert (length pss = arity); + let subjects = evarss xss in + + (* Take a [@build] attribute into account. *) + let builder = ifbuild cd.pcd_attributes builder in + + (* Find out which type variables [alphas] are formal parameters of this + declaration and are marked [poly]. We have to universally quantify over + (variants of) these type variables in the type of the hook, below. + Furthermore, we forbid these type variables from appearing under [@opaque], + as that would cause us to generate code whose actual type is less general + than its expected type. *) + let alphas = poly_params decl in + check_poly_under_opaque alphas tys; + + (* Create new names [rs] and [ss] for the results of the recursive calls of + visitor methods. *) + let rs = results xss + and ss = summaries xss in + + (* Construct a case for this data constructor in the visitor method associated + with this sum type. This case analyzes a tuple of width [arity]. After + binding the components [xss], we call the descending method associated with + this data constructor. The arguments of this method are: + 1. visitor functions for [poly] type variables; + 2. [env]; + 3. [this] (see below); + 4. [xss]. + In this method, we bind the variables [rs] and/or [ss] to the results of + the recursive calls to visitor methods, then produce a result (whose nature + depends on [scheme]). *) + + (* If the variety is [endo] (which implies that [arity] is 1), then we bind + the variable [this] to the whole memory block. This variable is transmitted + to the descending method. When the time comes to allocate a new memory + block, if the components of the new block are physically equal to the + components of the existing block, then the address of the existing block is + returned; otherwise a new block is allocated, as in [map]. *) + + let ascend = + new ascend_algebraic + this subjects rs ss + builder decl (datacon_ascending_method cd) tys + in + + Exp.case + (ptuple (alias this (map (pconstr datacon) pss))) + (hook X.data + (datacon_descending_method cd) + (map tyvar_visitor_function alphas @ env :: transmit this (flatten xss)) + (quantify alphas (ty_arrows + (map visitor_param_type alphas) + (visitor_fun_type (transmit (decl_type decl) tys) (decl_type decl)))) + (bulk rs ss tys subjects ascend) + ) + +(* -------------------------------------------------------------------------- *) + +(* [visit_decl decl] constructs an expression that represents the visiting + code associated with the type declaration [decl]. In other words, it is + the body of the visitor method associated with [decl]. *) + +let visit_decl (decl : type_declaration) : expression = + + (* Check that the user does not use a reserved type variable name. *) + decl_params decl |> iter (fun alpha -> + if mem alpha reserved then + let loc = decl.ptype_loc in + raise_errorf ~loc "%s: the type variable name '%s is reserved." + plugin alpha + ); + + (* Bind the values to a vector of variables [xs]. *) + let xs = things in + assert (length xs = arity); + + match decl.ptype_kind, decl.ptype_manifest with + + (* A type abbreviation. *) + | Ptype_abstract, Some ty -> + visit_type true ty + + (* A record type. *) + | Ptype_record (lds : label_declaration list), _ -> + let labels, tys = ld_labels lds, ld_tys (fix lds) in + (* See [constructor_declaration] for comments. *) + check_poly_under_opaque (poly_params decl) tys; + let builder rs = record (combine labels (evars rs)) in + let builder = ifbuild decl.ptype_attributes builder in + let subjects = accesses xs labels in + let rs = results labels + and ss = summaries labels in + let ascend = + new ascend_algebraic + (hd xs) subjects rs ss + builder decl (tycon_ascending_method decl) tys + in + lambdas xs (bulk rs ss tys subjects ascend) + + (* A sum type. *) + | Ptype_variant (cds : constructor_declaration list), _ -> + sum_build_warning decl; + (* Generate one case per data constructor. Place these cases in a + [match] construct, which itself is placed in a function body. *) + (* If [arity] is greater than 1 and if there is more than one data + constructor, then generate also a default case. In this default + case, invoke the failure method, which raises an exception. The + failure method receives [env] and [xs] as arguments. *) + let default() : case = + Exp.case + (ptuple (pvars xs)) + (hook true + (failure_method decl) + (env :: xs) + (quantify (poly_params decl) (visitor_method_type decl)) + (efail (local_tycon_visitor_method decl)) + ) + in + let complete (cs : case list) : case list = + if arity = 1 || length cs <= 1 then cs else cs @ [ default() ] + in + lambdas xs ( + Exp.match_ + (tuple (evars xs)) + (complete (map (constructor_declaration decl) cds)) + ) + + (* Unsupported constructs. *) + | Ptype_abstract, None -> + let loc = decl.ptype_loc in + raise_errorf ~loc "%s: cannot deal with abstract types." plugin + + | Ptype_open, _ -> + let loc = decl.ptype_loc in + raise_errorf ~loc "%s: cannot deal with open types." plugin + +(* -------------------------------------------------------------------------- *) + +(* [type_decl decl] generates the main visitor method associated with the type + declaration [decl], as well as the necessary auxiliary methods. It returns + no result. *) + +let type_decl (decl : type_declaration) : unit = + let alphas = poly_params decl in + generate_concrete_method + (local_tycon_visitor_method decl) + (lambdas (map tyvar_visitor_function alphas @ [env]) (visit_decl decl)) + (quantify alphas (ty_arrows (map visitor_param_type alphas) (visitor_method_type decl))) + +(* -------------------------------------------------------------------------- *) + +(* [type_decls decls] processes the type declarations [decl] and produces a + list of structure items. It is the main entry point inside the body of + the functor [Setup]. *) + +let type_decls (decls : type_declaration list) : structure = + (* Analyze the type definitions, and populate our classes with methods. *) + iter type_decl decls; + (* Emit our preprocessor warnings (if any). *) + warnings() @ + (* In the generated code, disable certain warnings, so that the user sees + no warnings, even if she explicitly enables them. We disable warnings + 26, 27 (unused variables) and 4 (fragile pattern matching; a feature + intentionally exploited by [iter2] and [map2]). *) + [ with_warnings "-4-26-27" ( + (* Surround the generated code with floating attributes, which can be + used as markers to find and review the generated code. We use this + mechanism to show the generated code in the documentation. *) + floating "VISITORS.BEGIN" [] :: + (* Produce a class definition. *) + (* Our classes are parameterized over the type variable ['env]. They are + also parameterized over the type variable ['self], with a constraint + that this is the type of [self]. This trick allows us to omit the types + of the virtual methods, even if these types include type variables. *) + dump X.concrete X.ancestors [ ty_self, Invariant ] pself X.name :: + floating "VISITORS.END" [] :: + [] + )] + +end + +(* -------------------------------------------------------------------------- *) + +(* [type_decls decls] produces a list of structure items (that is, toplevel + definitions) associated with the type declarations [decls]. It is the + main entry point outside of the functor [Setup]. *) + +let type_decls ~options ~path:_ (decls : type_declaration list) : structure = + assert (decls <> []); + let module Process = Setup(Parse(struct + let loc = (VisitorsList.last decls).ptype_loc (* an approximation *) + let options = options + let decls = decls + end)) in + Process.type_decls decls + +(* -------------------------------------------------------------------------- *) + +(* Register our plugin with [ppx_deriving]. *) + +let () = + register (create plugin ~type_decl_str:type_decls ()) diff --git a/src/Visitors.mli b/src/Visitors.mli new file mode 100644 index 0000000..d3e496f --- /dev/null +++ b/src/Visitors.mli @@ -0,0 +1 @@ +(* This file intentionally empty. *) diff --git a/src/VisitorsAnalysis.ml b/src/VisitorsAnalysis.ml new file mode 100644 index 0000000..6f5dbdf --- /dev/null +++ b/src/VisitorsAnalysis.ml @@ -0,0 +1,387 @@ +open Result +open Longident +open Asttypes +open Parsetree +open Ast_helper +open Ppx_deriving +open VisitorsPlugin + +(* This module offers helper functions for abstract syntax tree analysis. *) + +(* -------------------------------------------------------------------------- *) + +type tycon = string +type tyvar = string +type tyvars = tyvar list + +(* -------------------------------------------------------------------------- *) + +(* Testing whether an identifier is valid. *) + +(* We use OCaml's lexer to analyze the string and check if it is a valid + identifier. This method is slightly unorthodox, as the lexer can have + undesired side effects, such as raising an [Error] exception or printing + warnings. We do our best to hide these effects. The strength of this + approach is to give us (at little cost) a correct criterion for deciding if + an identifier is valid. *) + +(* Note: [Location.formatter_for_warnings] appeared in OCaml 4.02.2. *) + +type classification = + | LIDENT + | UIDENT + | OTHER + +let classify (s : string) : classification = + let lexbuf = Lexing.from_string s in + let backup = !Location.formatter_for_warnings in + let null = Format.formatter_of_buffer (Buffer.create 0) in + Location.formatter_for_warnings := null; + let result = try + let token1 = Lexer.token lexbuf in + let token2 = Lexer.token lexbuf in + match token1, token2 with + | Parser.LIDENT _, Parser.EOF -> + LIDENT + | Parser.UIDENT _, Parser.EOF -> + UIDENT + | _, _ -> + OTHER + with Lexer.Error _ -> + OTHER + in + Location.formatter_for_warnings := backup; + result + +(* -------------------------------------------------------------------------- *) + +(* Testing if a string is a valid [mod_longident], i.e., a possibly-qualified + module identifier. *) + +(* We might wish to use OCaml's parser for this purpose, but [mod_longident] is + not declared as a start symbol. Furthermore, that would be perhaps slightly + too lenient, e.g., allowing whitespace and comments inside. Our solution is + to split at the dots using [Longident.parse], then check that every piece + is a valid module name. *) + +let is_valid_mod_longident (m : string) : bool = + String.length m > 0 && + let ms = Longident.flatten (Longident.parse m) in + List.for_all (fun m -> classify m = UIDENT) ms + +(* -------------------------------------------------------------------------- *) + +(* Testing if a string is a valid [class_longident], i.e., a possibly-qualified + class identifier. *) + +let is_valid_class_longident (m : string) : bool = + String.length m > 0 && + match Longident.parse m with + | Lident c -> + classify c = LIDENT + | Ldot (m, c) -> + List.for_all (fun m -> classify m = UIDENT) (Longident.flatten m) && + classify c = LIDENT + | Lapply _ -> + assert false (* this cannot happen *) + +(* -------------------------------------------------------------------------- *) + +(* 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 + list. By convention, an attribute named [foo] can also be referred to as + [visitors.foo] or as [deriving.visitors.foo]. *) + +(* [select foo attrs] extracts the attribute named [foo] from the attribute + list [attrs]. *) + +let select (foo : string) (attrs : attributes) : attribute option = + attr ~deriver:plugin foo attrs + +(* [present foo attrs] tests whether an attribute named [foo] is present + (with no argument) in the list [attrs]. *) + +let present (foo : string) (attrs : attributes) : bool = + Arg.get_flag ~deriver:plugin (select foo attrs) + +(* [opacity attrs] tests for the presence of an [@opaque] attribute. *) + +type opacity = + | Opaque + | NonOpaque + +let opacity (attrs : attributes) : opacity = + if present "opaque" attrs then Opaque else NonOpaque + +(* [name attrs] tests for the presence of a [@name] attribute, carrying a + payload of type [string]. We check that the payload is a valid (lowercase + or uppercase) identifier, because we intend to use it as the basis of a + method name. *) + +let identifier : string Arg.conv = + fun e -> + match Arg.string e with + | Error msg -> + Error msg + | Ok s -> + match classify s with + | LIDENT | UIDENT -> + Ok s + | OTHER -> + Error "identifier" + +let name (attrs : attributes) : string option = + Arg.get_attr ~deriver:plugin identifier (select "name" attrs) + +(* [build attrs] tests for the presence of a [@build] attribute, + carrying a payload that is an arbitrary OCaml expression. *) + +let build (attrs : attributes) : expression option = + Arg.get_attr ~deriver:plugin Arg.expr (select "build" attrs) + +(* [maybe ox y] returns [x] if present, otherwise [y]. *) + +let maybe (ox : 'a option) (y : 'a) : 'a = + match ox with Some x -> x | None -> y + +(* -------------------------------------------------------------------------- *) + +(* When parsing a record declaration, the OCaml parser attaches attributes + with field labels, whereas the user might naturally expect them to be + attached with the type. We rectify this situation by copying all attributes + from the label to the type. This might seem dangerous, but we use it only + to test for the presence of an [@opaque] attribute. *) + +let paste (ty : core_type) (attrs : attributes) : core_type = + { ty with ptyp_attributes = attrs @ ty.ptyp_attributes } + +let fix (ld : label_declaration) : label_declaration = + { ld with pld_type = paste ld.pld_type ld.pld_attributes } + +let fix = + List.map fix + +(* -------------------------------------------------------------------------- *) + +(* [type_param_to_tyvar] expects a type parameter as found in the field + [ptype_params] of a type definition, and returns the underlying type + variable. *) + +let type_param_to_tyvar ((ty, _) : core_type * variance) : tyvar = + match ty.ptyp_desc with + | Ptyp_var tv -> + tv + | Ptyp_any -> + (* This error occurs if a formal type parameter is a wildcard [_]. + We could support this form, but it makes life slightly simpler + to disallow it. It is usually used only in GADTs anyway. *) + raise_errorf ~loc:ty.ptyp_loc + "%s: every formal type parameter should be named." plugin + | _ -> + assert false + +let type_params_to_tyvars = + List.map type_param_to_tyvar + +(* [decl_params decl] returns the type parameters of the declaration [decl]. *) + +let decl_params (decl : type_declaration) : tyvars = + type_params_to_tyvars decl.ptype_params + +(* [is_local decls tycon] tests whether the type constructor [tycon] is + declared by the type declarations [decls]. If so, it returns the + corresponding declaration. *) + +let rec is_local (decls : type_declaration list) (tycon : tycon) +: type_declaration option = + match decls with + | [] -> + None + | decl :: decls -> + if decl.ptype_name.txt = tycon then + Some decl + else + is_local decls tycon + +let is_local (decls : type_declaration list) (tycon : Longident.t) +: type_declaration option = + match tycon with + | Lident tycon -> + is_local decls tycon + | Ldot _ + | Lapply _ -> + None + +(* -------------------------------------------------------------------------- *) + +(* [occurs_type alpha ty] tests whether the type variable [alpha] occurs in + the type [ty]. This function goes down into all OCaml types, even those + that are not supported by [visitors]. *) + +exception Occurs of loc + +let rec occurs_type (alpha : tyvar) (ty : core_type) : unit = + match ty.ptyp_desc with + | Ptyp_any -> + () + | Ptyp_var beta -> + if alpha = beta then + raise (Occurs ty.ptyp_loc) + | Ptyp_alias (ty, _) -> + (* This is not a binder; just go down into it. *) + occurs_type alpha ty + | Ptyp_arrow (_, ty1, ty2) -> + occurs_types alpha [ ty1; ty2 ] + | Ptyp_tuple tys + | Ptyp_constr (_, tys) + | Ptyp_class (_, tys) -> + occurs_types alpha tys + | Ptyp_object (fields, _) -> + fields + |> List.map VisitorsCompatibility.object_field_to_core_type + |> occurs_types alpha + | Ptyp_variant (fields, _, _) -> + List.iter (occurs_row_field alpha) fields + | Ptyp_poly (qs, ty) -> + let qs : string list = VisitorsCompatibility.quantifiers qs in + (* The type variables in [qs] are bound. *) + 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) -> + occurs_payload alpha payload + +and occurs_types alpha tys = + List.iter (occurs_type alpha) tys + +and occurs_row_field alpha field = + field + |> VisitorsCompatibility.row_field_to_core_types + |> occurs_types alpha + +and occurs_quantifiers alpha (qs : string list) = + List.mem alpha qs + +and occurs_payload alpha = function + | PTyp ty -> + occurs_type alpha ty + (* | PStr _ | PPat _ *) + (* | PSig _ (* >= 4.03 *) *) + | _ -> + (* We assume that these cases won't arise or won't have any free type + variables in them. *) + () + +(* -------------------------------------------------------------------------- *) + +(* An error message about an unsupported type. *) + +let unsupported ty = + let loc = ty.ptyp_loc in + raise_errorf ~loc + "%s: cannot deal with the type %s.\n\ + Consider annotating it with [@opaque]." + plugin + (string_of_core_type ty) + +(* -------------------------------------------------------------------------- *) + +(* [at_opaque f ty] applies the function [f] to every [@opaque] component of + the type [ty]. *) + +let rec at_opaque (f : core_type -> unit) (ty : core_type) : unit = + match opacity ty.ptyp_attributes, ty.ptyp_desc with + | NonOpaque, Ptyp_any + | NonOpaque, Ptyp_var _ -> + () + | NonOpaque, Ptyp_tuple tys + | NonOpaque, Ptyp_constr (_, tys) -> + List.iter (at_opaque f) tys + | Opaque, _ -> + f ty + | NonOpaque, Ptyp_arrow _ + | NonOpaque, Ptyp_object _ + | NonOpaque, Ptyp_class _ + | NonOpaque, Ptyp_alias _ + | NonOpaque, Ptyp_variant _ + | NonOpaque, Ptyp_poly _ + | NonOpaque, Ptyp_package _ + | NonOpaque, Ptyp_extension _ -> + unsupported ty + +(* -------------------------------------------------------------------------- *) + +(* [check_poly_under_opaque alphas tys] checks that none of the type variables + [alphas] appears under [@opaque] in the types [tys]. *) + +let check_poly_under_opaque alphas tys = + List.iter (fun alpha -> + List.iter (fun ty -> + at_opaque (fun ty -> + try + occurs_type alpha ty + with Occurs loc -> + raise_errorf ~loc + "%s: a [polymorphic] type variable must not appear under @opaque." + plugin + ) ty + ) tys + ) alphas + +(* -------------------------------------------------------------------------- *) + +(* [subst_type sigma ty] applies [sigma], a substitution of types for type + variables, to the type [ty]. + + [rename_type rho ty] applies [rho], a renaming of type variables, to the + type [ty]. *) + +(* We do not go down into [@opaque] types. We replace every opaque type with a + wildcard [_]. Because we have checked that [poly] variables do not appear + under [@opaque], this is good enough: there is never a need for an + explicitly named/quantified type variable to describe an opaque + component. *) + +type substitution = + tyvar -> core_type + +type renaming = + tyvar -> tyvar + +let rec subst_type (sigma : substitution) (ty : core_type) : core_type = + match opacity ty.ptyp_attributes, ty.ptyp_desc with + | NonOpaque, Ptyp_any -> + ty + | NonOpaque, Ptyp_var alpha -> + sigma alpha + | NonOpaque, Ptyp_tuple tys -> + { ty with ptyp_desc = Ptyp_tuple (subst_types sigma tys) } + | NonOpaque, Ptyp_constr (tycon, tys) -> + { ty with ptyp_desc = Ptyp_constr (tycon, subst_types sigma tys) } + | Opaque, _ -> + Typ.any() + | NonOpaque, Ptyp_arrow _ + | NonOpaque, Ptyp_object _ + | NonOpaque, Ptyp_class _ + | NonOpaque, Ptyp_alias _ + | NonOpaque, Ptyp_variant _ + | NonOpaque, Ptyp_poly _ + | NonOpaque, Ptyp_package _ + | NonOpaque, Ptyp_extension _ -> + unsupported ty + +and subst_types sigma tys = + List.map (subst_type sigma) tys + +let rename_type (rho : renaming) (ty : core_type) : core_type = + subst_type (fun alpha -> Typ.var (rho alpha)) ty diff --git a/src/VisitorsCompatibility.cppo.ml b/src/VisitorsCompatibility.cppo.ml new file mode 100644 index 0000000..de1c705 --- /dev/null +++ b/src/VisitorsCompatibility.cppo.ml @@ -0,0 +1,171 @@ +let mknoloc = Location.mknoloc +open Asttypes +open Parsetree +open Ast_helper + +(* OCaml's abstract syntax tree evolves with time. We depend on this tree + because we analyze it (that is, we analyze type definitions) and because we + construct it (that is, we generate code). This module gathers the ugly bits + whose definition varies depending on the version of OCaml that we are + working with. *) + +#if OCAML_VERSION < (4, 03, 0) +#define Nolabel "" +#endif + +(* Constructing an arrow type. *) + +let ty_arrow (a : core_type) (b : core_type) : core_type = + Typ.arrow Nolabel a b + +(* Constructing a function. *) + +let plambda (p : pattern) (e : expression) : expression = + Exp.fun_ Nolabel None p e + +(* Constructing a string literal. *) + +let const_string (w : string) = +#if OCAML_VERSION < (4, 03, 0) + Const_string (w, None) +#else + Const.string w +#endif + +(* [ld_label] and [ld_ty] extract a label and type out of an OCaml record label + declaration. *) + +let ld_label (ld : label_declaration) : label = + ld.pld_name.txt + +let ld_labels = + List.map ld_label + +let ld_ty (ld : label_declaration) : core_type = + ld.pld_type + +let ld_tys = + List.map ld_ty + +(* Analyzing the definition of a data constructor. *) + +(* A data constructor is either a traditional data constructor, whose + components are anonymous, or a data constructor whose components + form an ``inline record''. This is a new feature of OCaml 4.03. *) + +type data_constructor_variety = + | DataTraditional of core_type list + | DataInlineRecord of label list * core_type list + +let data_constructor_variety (cd : constructor_declaration) = + #if OCAML_VERSION < (4, 03, 0) + DataTraditional cd.pcd_args + #else + match cd.pcd_args with + (* A traditional data constructor. *) + | Pcstr_tuple tys -> + DataTraditional tys + (* An ``inline record'' data constructor. *) + | 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 (field : object_field) : core_type = + #if OCAML_VERSION < (4, 06, 0) + match field with + | (_, _, ty) -> ty + #elif OCAML_VERSION < (4, 08, 0) + match field with + | 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 *) + #else + match field.pof_desc with + | Otag (_, ty) -> ty + | Oinherit ty -> ty + #endif + +let row_field_to_core_types (field : row_field) : core_type list = + #if OCAML_VERSION < (4, 08, 0) + match field with + | Rtag (_, _, _, tys) -> + tys + | Rinherit ty -> + [ ty ] + #else + match field.prf_desc with + | Rtag (_, _, tys) -> + tys + | Rinherit ty -> + [ ty ] + #endif + +(* -------------------------------------------------------------------------- *) + +(* [floating s items] produces a floating attribute whose name is [s] and + whose payload is the list of structure items [items]. *) + +(* The type [attribute] is defined in 4.07 as [string loc * payload], but in + 4.08 its definition changes to a record type and the function [Attr.mk] + appears. *) + +let floating (s : string) (items : structure) : structure_item = + let name = mknoloc s + and payload = PStr items in + #if OCAML_VERSION < (4, 08, 0) + Str.attribute (name, payload) + #else + Str.attribute (Attr.mk name payload) + #endif diff --git a/src/VisitorsGeneration.ml b/src/VisitorsGeneration.ml new file mode 100644 index 0000000..15a0b84 --- /dev/null +++ b/src/VisitorsGeneration.ml @@ -0,0 +1,586 @@ +open Longident +let mknoloc = Location.mknoloc +open Asttypes +open Parsetree +open Ast_helper +open Ast_convenience +open VisitorsList +open VisitorsAnalysis +open VisitorsCompatibility + +(* This module offers helper functions for code generation. *) + +(* -------------------------------------------------------------------------- *) + +(* Type abbreviations. *) + +type variable = string +type datacon = string +type label = string +type classe = string +type methode = string +type tyvar = string + +type variables = variable list +type tyvars = tyvar list +type core_types = core_type list +type patterns = pattern list +type expressions = expression list + +(* -------------------------------------------------------------------------- *) + +(* We should in principle ensure that our code makes sense even if the + standard names that we rely upon are shadowed by the user. *) + +(* This is made slightly difficult by the fact that the name [Pervasives] + has been deprecated in favor of [Stdlib] in OCaml 4.07. *) + +(* One viable approach would be to define the names that we need in the + library [VisitorsRuntime], then refer to this library in the generated + code. *) + +(* One problem is that defining an alias for the standard operator (&&) + causes it to become strict instead of lazy! So we cannot define an + alias for it. *) + +(* Let's just cross our fingers and assume that the user won't shadow + the standard names that we need. *) + +let pervasive (x : string) : Longident.t = + Lident x + +(* We normally place an improbable prefix in front of our private (local) + variables, so as to make sure that we do not shadow user variables that + are used in [@build] code fragments. *) + +(* When producing code for inclusion in the documentation, we remove this + prefix, just so that things look pretty. We rely on an undocumented + environment variable to toggle this behavior. *) + +let improbable (x : string) : string = + try + let _ = Sys.getenv "VISITORS_BUILDING_DOCUMENTATION" in + x + with Not_found -> + "_visitors_" ^ x + +(* -------------------------------------------------------------------------- *) + +(* Types. *) + +let ty_var (alpha : tyvar) : core_type = + Typ.var alpha + +let ty_vars (alphas : tyvars) : core_types = + List.map ty_var alphas + +let ty_any = + Typ.any() + +let ty_unit = + tconstr "unit" [] + +(* For [ty_arrow], see [VisitorsCompatibility]. *) + +let ty_arrows : core_types -> core_type -> core_type = + List.fold_right ty_arrow + +(* [decl_type decl] turns a declaration of the type ['a foo] into a the type + ['a foo]. *) + +let decl_type (decl : type_declaration) : core_type = + tconstr decl.ptype_name.txt (ty_vars (decl_params decl)) + +(* -------------------------------------------------------------------------- *) + +(* [unit] produces a unit constant. [tuple] produces a tuple. [record] + produces a record. These functions already exist; we redefine them without + any optional arguments so as avoid OCaml's warning 48 (implicit elimination + of optional arguments). *) + +let unit() = + unit() + +let tuple es = + tuple es + +let record les = + record les + +(* -------------------------------------------------------------------------- *) + +(* [number i thing] constructs an English description of "[i] thing(s)". *) + +let number i s = + match i with + | 0 -> + Printf.sprintf "zero %s" s + | 1 -> + Printf.sprintf "one %s" s + | _ -> + Printf.sprintf "%d %ss" i s + +(* -------------------------------------------------------------------------- *) + +(* [eident] converts a (possibly-qualified) identifier to an expression. *) + +let eident (id : Longident.t) : expression = + Exp.ident (mknoloc id) + +(* -------------------------------------------------------------------------- *) + +(* [pvars] converts a list of variables to a list of patterns. *) + +let pvars (xs : variables) : patterns = + List.map (fun x -> pvar x) xs + +(* [evars] converts a list of variables to a list of expressions. *) + +let evars (xs : variables) : expressions = + List.map (fun x -> evar x) xs + +(* [pvarss] converts a matrix of variables to a matrix of patterns. *) + +let pvarss (xss : variables list) : patterns list = + List.map pvars xss + +(* [evarss] converts a matrix of variables to a matrix of expressions. *) + +let evarss (xss : variables list) : expressions list = + List.map evars xss + +(* -------------------------------------------------------------------------- *) + +(* [wildcards] converts a list of anything to a list of wildcard patterns. *) + +let wildcards xs = + List.map (fun _ -> Pat.any()) xs + +(* -------------------------------------------------------------------------- *) + +(* [plambda p e] constructs a function [fun p -> e]. *) + +(* For [plambda], see [VisitorsCompatibility]. *) + +(* [lambda x e] constructs a function [fun x -> e]. *) + +let lambda (x : variable) (e : expression) : expression = + plambda (pvar x) e + +(* [plambdas ps e] constructs a multi-argument function [fun ps -> e]. *) + +let plambdas (ps : patterns) (e : expression) : expression = + List.fold_right plambda ps e + +(* [lambdas xs e] constructs a multi-argument function [fun xs -> e]. *) + +let lambdas (xs : variables) (e : expression) : expression = + List.fold_right lambda xs e + +(* -------------------------------------------------------------------------- *) + +(* [app] works like [Ast_convenience.app] (which it shadows), except it avoids + constructing nested applications of the form [(f x) y], transforming them + instead into a single application [f x y]. The difference is probably just + cosmetic. *) + +let app (e : expression) (es2 : expressions) : expression = + match e.pexp_desc with + | Pexp_apply (e1, les1) -> + let les2 = List.map (fun e -> Label.nolabel, e) es2 in + { e with pexp_desc = Pexp_apply (e1, les1 @ les2) } + | _ -> + app e es2 + +(* -------------------------------------------------------------------------- *) + +(* [sequence es] constructs a sequence of the expressions [es]. *) + +let sequence (es : expressions) : expression = + (* Using [fold_right1] instead of [List.fold_right] allows us to get + rid of a final [()] constant at the end of the sequence. Cosmetic. *) + fold_right1 + (fun e accu -> Exp.sequence e accu) + es + (unit()) + +(* -------------------------------------------------------------------------- *) + +(* [vblet1 vb e] constructs a single [let] binding. *) + +let vblet1 (vb : value_binding) (e : expression) : expression = + Exp.let_ Nonrecursive [vb] e + +(* [let1 x e1 e2] constructs a single [let] binding. *) + +let let1 (x : variable) (e1 : expression) (e2 : expression) : expression = + vblet1 (Vb.mk (pvar x) e1) e2 + +(* [let1p x y e1 e2] constructs a single [let] binding of a pair. *) + +let let1p (x, y : variable * variable) (e1 : expression) (e2 : expression) : expression = + vblet1 (Vb.mk (ptuple [pvar x; pvar y]) e1) e2 + +(* [vbletn vbs e] constructs a series of nested [let] bindings. *) + +let vbletn (vbs : value_binding list) (e : expression) : expression = + List.fold_right vblet1 vbs e + +(* [letn xs es e] constructs a series of nested [let] bindings. *) + +let letn (xs : variables) (es : expressions) (e : expression) = + List.fold_right2 let1 xs es e + +(* [letnp xs ys es e] constructs a series of nested [let] bindings of pairs. *) + +let letnp (xs : variables) (ys : variables) (es : expressions) (e : expression) = + List.fold_right2 let1p (List.combine xs ys) es e + +(* -------------------------------------------------------------------------- *) + +(* [access x label] constructs a record access expression [x.label]. *) + +let access (x : variable) (label : label) : expression = + Exp.field (evar x) (mknoloc (Lident label)) + +(* [accesses labels xs] constructs a matrix of record access expressions of + the form [x.label]. There is a row for every [label] and a column for every + [x]. *) + +let accesses (xs : variables) (labels : label list) : expressions list = + List.map (fun label -> List.map (fun x -> access x label) xs) labels + +(* -------------------------------------------------------------------------- *) + +(* [ptuple] is [Ast_convenience.ptuple], deprived of its optional arguments. *) + +let ptuple (ps : patterns) : pattern = + ptuple ps + +(* [ptuples] is [map ptuple]. *) + +let ptuples (pss : patterns list) : patterns = + List.map ptuple pss + +(* -------------------------------------------------------------------------- *) + +(* The Boolean expressions [false] and [true]. *) + +let efalse : expression = + Exp.construct (mknoloc (Lident "false")) None + +let etrue : expression = + Exp.construct (mknoloc (Lident "true")) None + +(* -------------------------------------------------------------------------- *) + +(* [conjunction es] constructs a Boolean conjunction of the expressions [es]. *) + +let conjunction : expression = + eident (pervasive "&&") + +let conjunction e1 e2 = + app conjunction [e1; e2] + +let conjunction (es : expressions) : expression = + fold_right1 conjunction es etrue + +(* -------------------------------------------------------------------------- *) + +(* [eassertfalse] is the expression [assert false]. *) + +let eassertfalse : expression = + Exp.assert_ efalse + +(* -------------------------------------------------------------------------- *) + +(* [eforce e] is the expression [Lazy.force e]. *) + +let eforce : expression = + eident (Longident.parse "Lazy.force") + (* danger: the module name [Lazy] must not be shadowed. *) + +let eforce (e : expression) : expression = + app eforce [e] + +(* -------------------------------------------------------------------------- *) + +(* [eqphy e1 e2] is the expression [e1 == e2]. *) + +let eqphy : expression = + eident (pervasive "==") + +let eqphy (e1 : expression) (e2 : expression) : expression = + app eqphy [e1; e2] + +(* [eqphys es1 es2] is the conjunction of the expressions [e1 == e2]. *) + +let eqphys (es1 : expressions) (es2 : expressions) : expression = + assert (List.length es1 = List.length es2); + conjunction (List.map2 eqphy es1 es2) + +(* -------------------------------------------------------------------------- *) + +(* [efail s] generates a call to [VisitorsRuntime.fail]. The parameter [s] is + a string, which could represent the place where a failure occurred, or the + reason why a failure occurred. As of now, it is unused. *) + +let efail : expression = + eident (Ldot (Lident "VisitorsRuntime", "fail")) + (* danger: the module name [VisitorsRuntime] must not be shadowed. *) + +let efail (_ : string) : expression = + app efail [ unit() ] + +(* -------------------------------------------------------------------------- *) + +(* [include_ e] constructs an [include] declaration. *) + +let include_ (e : module_expr) : structure_item = + Str.include_ { + pincl_mod = e; + pincl_loc = Location.none; + pincl_attributes = []; + } + +(* -------------------------------------------------------------------------- *) + +(* [with_warnings w items] wraps the structure items [items] in such a way + that the warning directive [w] is applied to these items. Technically, this + is done by emitting [include struct [@@@ocaml.warning ] end]. *) + +let with_warnings (w : string) (items : structure_item list) : structure_item = + include_ (Mod.structure ( + floating "ocaml.warning" [ Str.eval (Exp.constant (const_string w)) ] + :: items + )) + +(* -------------------------------------------------------------------------- *) + +(* [class1 concrete ancestors params name self fields] builds a class + declaration and packages it as a structure item. (This implies that it + cannot be recursive with other class declarations). *) + +let class1 + (concrete : bool) + (params : (core_type * variance) list) + (name : classe) + (self : pattern) + (fields : class_field list) + : structure_item = + Str.class_ [{ + pci_virt = if concrete then Concrete else Virtual; + pci_params = params; + pci_name = mknoloc name; + pci_expr = Cl.structure (Cstr.mk self fields); + pci_loc = !default_loc; + pci_attributes = []; + }] + +(* -------------------------------------------------------------------------- *) + +(* [inherit_ c tys] builds an [inherit] clause, where the superclass is [c] + and its actual type parameters are [tys]. No [super] identifier is bound. *) + +let inherit_ (c : Longident.t) (tys : core_types) : class_field = + Cf.inherit_ Fresh (Cl.constr (mknoloc c) tys) None + +(* -------------------------------------------------------------------------- *) + +(* An algebraic data type of the methods that we generate. These include + concrete methods (with code) and virtual methods (without code). They may + be public or private. The method type is optional. If omitted, then + it is inferred by OCaml. If present, it can be a polymorphic type. *) + +type meth = + Meth of private_flag * methode * expression option * core_type option + +let concrete_method p m e oty = + Meth (p, m, Some e, oty) + +let virtual_method p m oty = + Meth (p, m, None, oty) + +(* -------------------------------------------------------------------------- *) + +(* Converting a method description to OCaml abstract syntax. *) + +let oe2cfk (oe : expression option) (oty : core_type option) : class_field_kind = + match oe, oty with + | Some e, Some _ -> + Cf.concrete Fresh (Exp.poly e oty) + | Some e, None -> + Cf.concrete Fresh e + | None, Some ty -> + Cf.virtual_ ty + | None, None -> + Cf.virtual_ ty_any + +let meth2cf (Meth (p, m, oe, oty)) : class_field = + Cf.method_ (mknoloc m) p (oe2cfk oe oty) + +(* -------------------------------------------------------------------------- *) + +(* [method_name] extracts a method name out of a method description. *) + +let method_name (Meth (_, m, _, _)) : string = + m + +(* -------------------------------------------------------------------------- *) + +(* [is_virtual] tests whether a method description represents a virtual + method. *) + +let is_virtual (Meth (_, _, oe, _)) : bool = + oe = None + +(* -------------------------------------------------------------------------- *) + +(* [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 + +(* -------------------------------------------------------------------------- *) + +(* An algebraic data type of the ``hoisted expressions'' that we generate. *) + +(* A ``hoisted expression'' is evaluated at most once after the object is + allocated. Its value is stored in an instance field. We allow such an + expression to reference [self], as long as it does not actually invoke any + methods. *) + +type hoisted = + Hoisted of string (* the name of the instance field *) + * expression (* the hoisted expression *) + +(* -------------------------------------------------------------------------- *) + +(* Converting a hoisted field description to OCaml abstract syntax. *) + +(* We generate a mutable field declaration, followed with an initialization: + + val mutable x = lazy (assert false) + initializer x <- lazy e + + We must do this in two steps because the expression [e] might contain + references to [self], which are invalid in a field declaration, whereas + they are allowed in an initializer. + + The potential danger in this idiom lies in forcing [x] before the + initializer has finished running, leading to an assertion failure. + This should not happen if [e] does not perform any method calls + or read any fields. *) + +let hoisted2cf (Hoisted (x, e)) : class_field list = + [ + Cf.val_ (mknoloc x) (Mutable) (Cf.concrete Fresh (Exp.lazy_ eassertfalse)); + Cf.initializer_ (Exp.setinstvar (mknoloc x) (Exp.lazy_ e)) + ] + +(* -------------------------------------------------------------------------- *) + +(* A facility for generating a class. *) + +module ClassFieldStore (X : sig end) : sig + + (* [generate meth] adds [meth] to the list of methods. *) + val generate: meth -> unit + + (* [hoist e] causes the expression [e] to be hoisted, that is, computed + once after the object is allocated. The result of evaluating [e] is + stored in a field. The call [hoist e] returns an expression which + reads this field. *) + val hoist: expression -> expression + + (* [dump concrete ancestors params self c] returns a class definition. *) + val dump: + bool -> + Longident.t list -> + (core_type * variance) list -> + pattern -> + classe -> + structure_item + +end = struct + + let meths : meth list ref = + ref [] + + let generate meth = + meths := meth :: !meths + + let dump () : class_field list = + let methods = List.rev !meths in + (* Move all of the virtual methods up front. If two virtual methods have + the same name, keep only one of them. This is useful because we allow + a virtual method declaration to be generated several times. In fact, + OCaml supports this, but it looks tidier if we remove duplicates. *) + let virtual_methods, concrete_methods = List.partition is_virtual methods in + let cmp meth1 meth2 = compare (method_name meth1) (method_name meth2) in + let virtual_methods = VisitorsList.weed cmp virtual_methods in + let methods = virtual_methods @ concrete_methods in + List.map meth2cf methods + + let hoisted : hoisted list ref = + ref [] + + let fresh : unit -> int = + let c = ref 0 in + fun () -> + let x = !c in + c := x + 1; + x + + let hoist (e : expression) : expression = + let x = Printf.sprintf "h%d" (fresh()) in + hoisted := Hoisted (x, e) :: !hoisted; + eforce (evar x) + + let dump concrete ancestors params self c : structure_item = + class1 concrete params c self ( + (* [inherit] clauses. *) + (* We ARBITRARILY assume that every ancestor class is parameterized + with ONE type parameter. *) + List.map (fun c -> inherit_ c [ ty_any ]) ancestors @ + (* Hoisted expressions. *) + List.flatten (List.map hoisted2cf (List.rev !hoisted)) @ + (* Methods. *) + dump() + ) + +end + +(* -------------------------------------------------------------------------- *) + +(* A facility for emitting preprocessor warnings. *) + +(* Warnings must be emitted under the form of [ppwarning] attributes, placed + in the generated code. This is not very convenient; we must store these + warnings, waiting for a convenient time to emit them. *) + +module WarningStore (X : sig end) : sig + + (* [warning loc format ...] emits a warning. *) + val warning: loc -> ('a, unit, string, unit) format4 -> 'a + + (* [warnings()] returns a list of all warnings emitted so far. *) + val warnings: unit -> structure + +end = struct + + let warnings : attribute list ref = + ref [] + + let warning loc msg = + warnings := Ast_mapper.attribute_of_warning loc msg :: !warnings + + let warning loc format = + Printf.ksprintf (warning loc) format + + let warnings () = + let ws = !warnings in + warnings := []; + List.map (fun a -> Str.attribute a) (List.rev ws) + +end diff --git a/src/VisitorsList.ml b/src/VisitorsList.ml new file mode 100644 index 0000000..0455540 --- /dev/null +++ b/src/VisitorsList.ml @@ -0,0 +1,125 @@ +open List + +(* [last xs] returns the last element of the nonempty list [xs]. *) + +let rec last1 x xs = + match xs with + | [] -> + x + | x :: xs -> + last1 x xs + +let last xs = + match xs with + | [] -> + assert false + | x :: xs -> + last1 x xs + +(* [interval i j] constructs a list representation of the semi-open interval + [i..j). *) + +let rec interval i j : int list = + if i < j then + i :: interval (i + 1) j + else + [] + +(* [init i j f] constructs a list of the values [f i] up to [f (j - 1)]. *) + +let init i j (f : int -> 'a) : 'a list = + map f (interval i j) + +(* [is_matrix m n xss] checks that [xss] is an [m]-by-[n] matrix, represented + as a list of lists. *) + +let is_matrix m n (xss : _ list list) = + length xss = m && for_all (fun xs -> length xs = n) xss + +(* [transpose n xss] transposes a matrix, represented as a list of lists. + The parameter [n] is the width of the matrix, and is really useful only + in the case where the matrix has zero height, in which case [transpose] + constructs a matrix of height [n] and zero width. *) + +let transpose (n : int) (xss : 'a list list) : 'a list list = + let m = length xss in + assert (is_matrix m n xss); + (* Convert [xss] to an array, for speed. *) + let xss : 'a array array = + Array.(map of_list (of_list xss)) + in + (* We have an [m]-by-[n] matrix, and construct an [n]-by-[m] matrix. *) + init 0 n (fun j -> + init 0 m (fun i -> + xss.(i).(j) + ) + ) + +(* [hextend xs n f] extends the vertical vector [xs] to a matrix of width [n]. + A vector element [x] is turned into [f j x] in the [j]-th row. *) + +let hextend (xs : 'a list) (n : int) (f : int -> 'a -> 'a) : 'a list list = + map (fun x -> init 0 n (fun j -> f j x)) xs + +(* [uniq cmp xs] assumes that the list [xs] is sorted according to the + ordering [cmp] and returns the list [xs] deprived of any duplicate + elements. *) + +let rec uniq1 cmp x ys = + match ys with + | [] -> + [] + | y :: ys -> + if cmp x y = 0 then + uniq1 compare x ys + else + y :: uniq1 cmp y ys + +let uniq cmp xs = + match xs with + | [] -> + [] + | x :: xs -> + x :: uniq1 cmp x xs + +(* [weed cmp xs] returns the list [xs] deprived of any duplicate elements. *) + +let weed cmp xs = + uniq cmp (List.sort cmp xs) + +(* [fold_right1] is like [fold_right], but uses the last element of the list + (if the list is nonempty) as the initial accumulator, saving one call to + the binary operation [f]. This is equivalent to [fold_right] if [accu] is + a right unit for [f]. *) + +let fold_right1 f xs accu = + match List.rev xs with + | [] -> + accu + | x :: xs -> + let xs = List.rev xs in + (* We have decomposed [xs] as [xs] followed with [x]. We can now + ignore [accu] and use [x] as the initial accumulator in our + right-to-left sweep of the list. *) + List.fold_right f xs x + +(* [fold_left1] is like [fold_left], but uses the first element of the list + (if the list is nonempty) as the initial accumulator, saving one call to + the binary operation [f]. This is equivalent to [fold_left] if [accu] is + a left unit for [f]. *) + +let fold_left1 f accu xs = + match xs with + | [] -> + accu + | x :: xs -> + (* We can ignore [accu] and use [x] as the initial accumulator in + our left-to-right sweep of the list. *) + List.fold_left f x xs + +(* [filter2 f xs ys] returns the list of elements [y] in [ys] such that + the corresponding element [x] in [xs] satisfies [f]. *) + +let filter2 f xs ys = + assert (length xs = length ys); + map snd (filter (fun (x, _y) -> f x) (combine xs ys)) diff --git a/src/VisitorsPlugin.ml b/src/VisitorsPlugin.ml new file mode 100644 index 0000000..113488e --- /dev/null +++ b/src/VisitorsPlugin.ml @@ -0,0 +1,4 @@ +(* The name of our [ppx_deriving] plugin. *) + +let plugin = + "visitors" diff --git a/src/VisitorsSettings.ml b/src/VisitorsSettings.ml new file mode 100644 index 0000000..d10b221 --- /dev/null +++ b/src/VisitorsSettings.ml @@ -0,0 +1,370 @@ +open Result +open VisitorsString +open List +let sprintf = Printf.sprintf +open Parsetree +open Ppx_deriving +open VisitorsPlugin +open VisitorsAnalysis +open VisitorsGeneration + +(* -------------------------------------------------------------------------- *) + +(* We can generate classes that adhere to several distinct schemes, listed + below. These schemes differ only in the re-building code that is executed + after the recursive calls. In [iter], this code does nothing. In [map], it + reconstructs a data structure. In [endo], it also reconstructs a data + structure, but attempts to preserve sharing. In [reduce], it combines the + results of the recursive calls using a monoid operation. In [fold], this + code is missing; it is represented by a virtual method. *) + +type scheme = + | Iter + | Map + | Endo + | Reduce + | MapReduce + | Fold + +(* -------------------------------------------------------------------------- *) + +(* The parameters that can be set by the user. *) + +module type SETTINGS = sig + + (* The type declarations that we are processing. *) + val decls: type_declaration list + + (* The name of the generated class. *) + val name: classe + + (* The arity of the generated code, e.g., 1 if one wishes to generate [iter] + and [map], 2 if one wishes to generate [iter2] and [map2], and so on. *) + val arity: int + + (* The scheme of visitor that we wish to generate (see the definition of + the type [scheme] above). *) + val scheme: scheme + + (* [variety] combines the information in [scheme] and [arity]. It is just + 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.] is implicitly prepended to this list. + If [nude] is [true], it is not. *) + val ancestors: Longident.t list + + (* [concrete] controls whether the generated class should be concrete or + virtual. By default, it is virtual. *) + val concrete: bool + + (* If [irregular] is [true], the regularity check is suppressed; this allows + a local parameterized type to be instantiated. The definition of ['a t] + can then refer to [int t]. However, in most situations, this will lead to + ill-typed generated code. The generated code should be well-typed if [t] + is always instantiated in the same manner, e.g., if there are references + to [int t] but not to other instances of [t]. *) + val irregular: bool + + (* If [public] is present, then every method is declared private, except + the methods whose name appears in the list [public]. *) + val public: string list option + + (* If [polymorphic] is [true], then (possibly polymorphic) type annotations + for methods are generated. The function [poly], applied to the name of a + type variable (without its quote), tells whether this type variable + should receive monomorphic or polymorphic treatment. In the former case, + this type variable is dealt with via a visitor method; in the latter + case, it is dealt with via a visitor function. *) + val polymorphic: bool + val poly: tyvar -> bool + + (* If [data] is [true], then descending visitor methods for data constructors + are generated. This allows the user to request per-data-constructor custom + behavior by overriding these methods. If [data] is [false], then these + methods are not generated. This yields simpler and faster code with + fewer customization opportunities. *) + val data: bool + +end + +(* -------------------------------------------------------------------------- *) + +(* The supported varieties. *) + +(* Note that [mapreduce] must appear in this list before [map], as shorter + prefixes must be tested last. *) + +let supported = [ + "mapreduce", MapReduce; + "map", Map; + "iter", Iter; + "endo", Endo; + "reduce", Reduce; + "fold", Fold; + ] + +let valid_varieties = + "iter, map, endo, reduce, mapreduce, fold,\n\ + iter2, map2, reduce2, mapreduce2, fold2" + +let invalid_variety loc = + raise_errorf ~loc + "%s: invalid variety. The valid varieties are\n\ + %s." + plugin valid_varieties + +(* [parse_variety] takes a variety, which could be "iter", "map2", etc. and + returns a pair of a scheme and an arity. *) + +let parse_variety loc (s : string) : scheme * int = + (* A loop over [supported] tries each supported variety in turn. *) + let rec loop supported s = + match supported with + | (p, scheme) :: supported -> + if prefix p s then + let s = remainder p s in + let i = if s = "" then 1 else int_of_string s in + if i <= 0 then failwith "negative integer" + else scheme, i + else + loop supported s + | [] -> + failwith "unexpected prefix" + in + (* Start the loop and handle errors. *) + try + loop supported s + with Failure _ -> + invalid_variety loc + +(* -------------------------------------------------------------------------- *) + +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 + +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 + +(* -------------------------------------------------------------------------- *) + +type bool_or_strings = + | Bool of bool + | Strings of string list + +let bool_or_strings : bool_or_strings Arg.conv = + fun e -> + match Arg.bool e, Arg.list Arg.string e with + | Ok b, Error _ -> + Ok (Bool b) + | Error _, Ok alphas -> + Ok (Strings alphas) + | Error _, Error _ -> + Error "Boolean or string list" + | Ok _, Ok _ -> + assert false + +(* -------------------------------------------------------------------------- *) + +(* The option processing code constructs a module of type [SETTINGS]. *) + +module Parse (O : sig + val loc: Location.t + val decls: type_declaration list + val options: (string * expression) list +end) +: SETTINGS += struct + open O + + (* Set up a few parsers. *) + + let bool = Arg.get_expr ~deriver:plugin Arg.bool + let string = Arg.get_expr ~deriver:plugin Arg.string + let strings = Arg.get_expr ~deriver:plugin (Arg.list Arg.string) + let bool_or_strings = Arg.get_expr ~deriver:plugin bool_or_strings + + (* Default values. *) + + let name = ref None + 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 + let irregular = ref false + let nude = ref false + let polymorphic = ref false + let poly = ref (fun _ -> false) + let public = ref None + + (* Parse every option. *) + + let () = + 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" -> + concrete := bool e + | "data" -> + data := bool e + | "irregular" -> + irregular := bool e + | "name" -> + name := Some (string e) + | "nude" -> + nude := bool e + | "polymorphic" -> + (* The [polymorphic] parameter can be a Boolean constant or a list + of type variable names. If [true], then all type variables are + considered polymorphic. If a list of type variables, then only + the variables in the list are considered polymorphic. *) + begin match bool_or_strings e with + | Bool b -> + polymorphic := b; + poly := (fun _ -> b) + | Strings alphas -> + let alphas = List.map unquote alphas in + polymorphic := true; + poly := (fun alpha -> List.mem alpha alphas) + end + | "monomorphic" -> + (* The [monomorphic] parameter is provided as a facility for the user. + It means the reverse of [polymorphic]. This is particularly useful + when the parameter is a list of type variables: then, only the + variables *not* in the list are considered polymorphic. *) + begin match bool_or_strings e with + | Bool b -> + polymorphic := not b; + poly := (fun _ -> not b) + | Strings alphas -> + let alphas = List.map unquote alphas in + polymorphic := true; (* yes, [true] *) + poly := (fun alpha -> not (List.mem alpha alphas)) + end + | "public" -> + public := Some (strings e) + | "variety" -> + let v = string e in + variety := Some v; + let s, a = parse_variety loc v in + scheme := s; + arity := a; + (* [endo] is supported only at arity 1. *) + if s = Endo && a > 1 then + invalid_variety loc + | _ -> + (* We could emit a warning, instead of an error, if we find an + unsupported option. That might be preferable for forward + compatibility. That said, I am not sure that ignoring unknown + options is a good idea; it might cause us to generate code + that does not work as expected by the user. *) + raise_errorf ~loc "%s: option %s is not supported." plugin o + ) options + + (* Export the results. *) + + 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 + let irregular = !irregular + let nude = !nude + let polymorphic = !polymorphic + let poly = !poly + let public = !public + + (* Perform sanity checking. *) + + (* The parameter [variety] is not optional. *) + let variety = + match !variety with + | None -> + raise_errorf ~loc + "%s: please specify the variety of the generated class.\n\ + e.g. [@@deriving visitors { variety = \"iter\" }]" plugin + | Some variety -> + variety + + (* The parameter [name] is optional. If it is absent, then [variety] + is used as its default value. *) + let name = + match !name with + | Some name -> + (* We expect [name] to be a valid class name. *) + if classify name <> LIDENT then + raise_errorf ~loc + "%s: %s is not a valid class name." + plugin name; + name + | None -> + variety + + (* Every string in the list [ancestors] must be a valid (long) class + identifier. *) + let () = + iter (must_be_valid_class_longident loc) ancestors + + (* When the variety is [iter], the class [VisitorsRuntime.iter] is an + implicit ancestor, and similarly for every variety. *) + let ancestors = + if nude then ancestors else ("VisitorsRuntime." ^ variety) :: ancestors + let ancestors = + map Longident.parse ancestors + + (* If [scheme] is [Fold], then [polymorphic] must be [false]. Indeed, + we currently cannot generate polymorphic type annotations in that + case, as we cannot guess the return types of the visitor methods. *) + let () = + if scheme = Fold && polymorphic then + raise_errorf ~loc + "%s: cannot generate polymorphic\n\ + type annotations for fold visitors." + plugin + +end diff --git a/src/VisitorsString.ml b/src/VisitorsString.ml new file mode 100644 index 0000000..bf0d4a1 --- /dev/null +++ b/src/VisitorsString.ml @@ -0,0 +1,70 @@ +open String + +(* [prefix s1 s2] tests whether [s1] is a prefix of [s2], i.e. whether + [s2] begins with [s1]. *) + +let prefix s1 s2 = + let n1 = length s1 in + n1 <= length s2 && s1 = sub s2 0 n1 + +(* [remainder s1 s2] assumes that [s1] is a prefix of [s2], and chops + [s1] off [s2], returning the remainder. *) + +let remainder s1 s2 = + assert (prefix s1 s2); + let n1 = length s1 in + let n2 = length s2 in + sub s2 n1 (n2 - n1) + +(* [unquote alpha] removes a leading quote in the string [alpha], if + there is one. *) + +let unquote alpha = + let n = String.length alpha in + if n > 0 && alpha.[0] = '\'' then + 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/src/dune b/src/dune new file mode 100644 index 0000000..d4cb797 --- /dev/null +++ b/src/dune @@ -0,0 +1,27 @@ +(library + (name ppx_deriving_visitors) + (public_name visitors.ppx) + (synopsis "Compile-time support for generating visitors") + (kind ppx_deriver) + (libraries result compiler-libs.common ppx_tools ppx_deriving.api) + (ppx_runtime_libraries visitors.runtime) +) + +(rule + (targets VisitorsCompatibility.ml) + (deps VisitorsCompatibility.cppo.ml) + (action (run %{bin:cppo} -V OCAML:%{ocaml_version} %{deps} -o %{targets}))) + +(env + (dev (flags + :standard + -safe-string + -g + -w @A-4-44 + )) + (release (flags + :standard + -safe-string + -g + )) +) diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 0000000..46c444f --- /dev/null +++ b/test/Makefile @@ -0,0 +1,3 @@ +.PHONY: test +test: + @ make -C .. $@ diff --git a/test/OOinfer.ml b/test/OOinfer.ml new file mode 100644 index 0000000..83d178c --- /dev/null +++ b/test/OOinfer.ml @@ -0,0 +1,5 @@ +class int_cell = object + val mutable x = 0 + method get = x + method incr y = x <- x + y +end diff --git a/test/OOinferfixed.ml b/test/OOinferfixed.ml new file mode 100644 index 0000000..098dccf --- /dev/null +++ b/test/OOinferfixed.ml @@ -0,0 +1,6 @@ +class virtual ['a] int_cell = object (self) + val mutable x = 0 + method get = x + method set y = x <- self#check y + method virtual check: 'a -> _ +end diff --git a/test/OOinferfixedagain.ml b/test/OOinferfixedagain.ml new file mode 100644 index 0000000..cf78a1c --- /dev/null +++ b/test/OOinferfixedagain.ml @@ -0,0 +1,6 @@ +class virtual ['a, 'b] cell (init) = object (self) + val mutable x = init + method get = x + method set y = x <- self#check y + method virtual check: 'a -> 'b +end diff --git a/test/OOinferfixedagaincheck.ml b/test/OOinferfixedagaincheck.ml new file mode 100644 index 0000000..3c79f03 --- /dev/null +++ b/test/OOinferfixedagaincheck.ml @@ -0,0 +1,6 @@ +class virtual ['check] cell (init) = object (self) + val mutable x = init + method get = x + method set y = x <- self#check y + method virtual check: 'check +end diff --git a/test/OOinferself.ml b/test/OOinferself.ml new file mode 100644 index 0000000..2564efd --- /dev/null +++ b/test/OOinferself.ml @@ -0,0 +1,6 @@ +class virtual ['self] cell (init) = object (self : 'self) + val mutable x = init + method get = x + method set y = x <- self#check y + method virtual check: _ +end diff --git a/test/OOinfervirtual.ml b/test/OOinfervirtual.ml new file mode 100644 index 0000000..189d8d8 --- /dev/null +++ b/test/OOinfervirtual.ml @@ -0,0 +1,6 @@ +class virtual int_cell = object (self) + val mutable x = 0 + method get = x + method incr y = x <- self#check (x + y) + method virtual check: _ +end diff --git a/test/VisitorsRuntimeBootstrap.cppo.ml b/test/VisitorsRuntimeBootstrap.cppo.ml new file mode 100644 index 0000000..81dc1f9 --- /dev/null +++ b/test/VisitorsRuntimeBootstrap.cppo.ml @@ -0,0 +1,30 @@ +type 'a option = + | None + | Some of 'a + +and 'a ref = + { mutable contents: 'a } + +#if OCAML_VERSION >= (4, 03, 0) + +and 'a list = + | Nil + | Cons of 'a * 'a list + +and ('a, 'b) result = + | Ok of 'a + | Error of 'b + +#endif + +[@@deriving +visitors { variety = "iter"; public = []; polymorphic = true; data = false; nude = true }, +visitors { variety = "map"; public = []; polymorphic = true; data = false; nude = true }, +visitors { variety = "endo"; public = []; polymorphic = true; data = false; nude = true }, +visitors { variety = "reduce"; public = []; polymorphic = true; data = false; nude = true; ancestors = ["VisitorsRuntime.monoid"] }, +visitors { variety = "mapreduce"; public = []; polymorphic = true; data = false; nude = true; ancestors = ["VisitorsRuntime.monoid"] }, +visitors { variety = "iter2"; public = []; polymorphic = true; data = false; nude = true }, +visitors { variety = "map2"; public = []; polymorphic = true; data = false; nude = true }, +visitors { variety = "reduce2"; public = []; polymorphic = true; data = false; nude = true; ancestors = ["VisitorsRuntime.monoid"] }, +visitors { variety = "mapreduce2"; public = []; polymorphic = true; data = false; nude = true; ancestors = ["VisitorsRuntime.monoid"] } +] diff --git a/test/attic/expr07.ml b/test/attic/expr07.ml new file mode 100644 index 0000000..e17c000 --- /dev/null +++ b/test/attic/expr07.ml @@ -0,0 +1,23 @@ +open Hashcons + +module Hash_consed = struct + + let table = + create 128 + + let iter f env hcx = + f env hcx.node + + let map f env hcx = + hashcons table (f env hcx.node) + +end + +type expr = + expr_node hash_consed + +and expr_node = + | EConst of int + | EAdd of expr * expr + [@@deriving visitors { name = "iter"; variety = "iter" }, + visitors { name = "map" ; variety = "map" }] 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/bench.ml b/test/bench.ml new file mode 100644 index 0000000..43cd6d1 --- /dev/null +++ b/test/bench.ml @@ -0,0 +1,136 @@ +module Bench = Core_bench.Bench +module Command = Core.Command + +let run tests = + let tests = + List.map (fun (name, test) -> Bench.Test.create ~name test) tests + in + Command.run (Bench.make_command tests) + +type expr = + | EConst of (int[@opaque]) + | EAdd of expr * expr + | EList of expr list + [@@deriving visitors { variety = "iter"; concrete = true }, + visitors { variety = "map"; concrete = true }, + visitors { variety = "reduce"; ancestors = ["VisitorsRuntime.addition_monoid"]; concrete = true }] + +let iter : expr -> unit = + new iter # visit_expr () + +let rec native_iter env e = + match e with + | EConst _ -> + () + | EAdd (e1, e2) -> + native_iter env e1; + native_iter env e2 + | EList es -> + List.iter (native_iter env) es + +class size = object + inherit [_] reduce as super + method! visit_expr () e = + 1 + super # visit_expr () e +end + +let size : expr -> int = + new size # visit_expr () + +let rec native_size env e = + match e with + | EConst _ -> + 1 + | EAdd (e1, e2) -> + native_size env e1 + + native_size env e2 + | EList es -> + List.fold_left (fun accu e -> accu + native_size env e) 0 es + +let rec native_size_noenv e = + match e with + | EConst _ -> + 1 + | EAdd (e1, e2) -> + native_size_noenv e1 + + native_size_noenv e2 + | EList es -> + List.fold_left (fun accu e -> accu + native_size_noenv e) 0 es + +let rec native_size_noenv_accu accu e = + match e with + | EConst _ -> + accu + 1 + | EAdd (e1, e2) -> + let accu = native_size_noenv_accu accu e1 in + native_size_noenv_accu accu e2 + | EList es -> + List.fold_left native_size_noenv_accu accu es + +let split n = + assert (n >= 0); + let n1 = Random.int (n + 1) in + let n2 = n - n1 in + assert (0 <= n1 && n1 <= n); + assert (0 <= n2 && n2 <= n); + n1, n2 + +let rec generate n = + assert (n >= 0); + if n = 0 then + EConst (Random.int 100) + else + match Random.int 2 with + | 0 -> + let n1, n2 = split (n - 1) in + EAdd (generate n1, generate n2) + | 1 -> + let n1, n2 = split (n - 1) in + EList [ generate n1; generate n2 ] + | _ -> + assert false + +let rec list_init i n f = + if i = n then + [] + else + let x = f i in + x :: list_init (i + 1) n f + +let list_init n f = + list_init 0 n f + +let samples = + list_init 100 (fun _ -> generate 100) + +let test f () = + List.iter (fun e -> ignore (f e)) samples + +let () = + run [ + "iter", test iter; + "native_iter", test (native_iter ()); + ] + +let () = + run [ + "size", test size; + "native_size", test (native_size ()); +(* + "native_size_noenv", test native_size_noenv; + "native_size_noenv_accu", test (native_size_noenv_accu 0); + *) + ] + +(* with hoisting, applied to self#visit_expr: + iter allocates no memory, and is 46% slower than native_iter (which allocates). + without hoisting: + iter allocates memory and is 65% slower than native_iter + So, in this case, hoisting helps a little. + + with hoisting, applied to self#visit_expr: + size allocates no memory, and is 105% slower than native_size (which allocates). + without hoisting: + size allocates memory (same amount as native_size) and is 86% slower than native_size + So, in this case, hoisting seems counter-productive. + *) diff --git a/test/build.ml b/test/build.ml new file mode 100644 index 0000000..6c3c400 --- /dev/null +++ b/test/build.ml @@ -0,0 +1,10 @@ +(* Testing @build attributes. *) + +type foo = + | A + | B of int + | C of foo * foo [@build fun x y -> C (x, y)] + +and point = Point.point = private { x: int; y: int } + [@@build Point.make] + [@@deriving visitors { variety = "map" }] diff --git a/test/cil_types.ml b/test/cil_types.ml new file mode 100644 index 0000000..cdf228a --- /dev/null +++ b/test/cil_types.ml @@ -0,0 +1,1811 @@ +module Integer = struct type t = int end (* fpottier/visitors *) +(****************************************************************************) +(* *) +(* Copyright (C) 2001-2003 *) +(* George C. Necula *) +(* Scott McPeak *) +(* Wes Weimer *) +(* Ben Liblit *) +(* All rights reserved. *) +(* *) +(* Redistribution and use in source and binary forms, with or without *) +(* modification, are permitted provided that the following conditions *) +(* are met: *) +(* *) +(* 1. Redistributions of source code must retain the above copyright *) +(* notice, this list of conditions and the following disclaimer. *) +(* *) +(* 2. Redistributions in binary form must reproduce the above copyright *) +(* notice, this list of conditions and the following disclaimer in the *) +(* documentation and/or other materials provided with the distribution. *) +(* *) +(* 3. The names of the contributors may not be used to endorse or *) +(* promote products derived from this software without specific prior *) +(* written permission. *) +(* *) +(* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *) +(* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *) +(* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *) +(* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *) +(* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, *) +(* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, *) +(* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; *) +(* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *) +(* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *) +(* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN *) +(* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE *) +(* POSSIBILITY OF SUCH DAMAGE. *) +(* *) +(* File modified by CEA (Commissariat à l'énergie atomique et aux *) +(* énergies alternatives) *) +(* and INRIA (Institut National de Recherche en Informatique *) +(* et Automatique). *) +(****************************************************************************) + +(** The Abstract Syntax of CIL. + @plugin development guide *) + +(**************************** WARNING ***************************************) +(* Remember to reflect any change here into the visitor and pretty-printer *) +(* in cil.ml. In particular, if a type becomes mutable, it is necessary to *) +(* adapt the Cil.behavior type and the copy_behavior accordingly. *) +(* A first test to see if something has been broken by a change is to launch*) +(* ptests.byte -add-options '-files-debug "-check -copy"' *) +(* In addition, it is a good idea to add some invariant checks in the *) +(* check_file class in frama-c/src/file.ml (before lauching the tests) *) +(****************************************************************************) + +(* ************************************************************************* *) +(** {2 Root of the AST} *) +(* ************************************************************************* *) + +(** In Frama-C, the whole AST is accessible through {!Ast.get}. *) + +(** The top-level representation of a CIL source file (and the result of the + parsing and elaboration). Its main contents is the list of global + declarations and definitions. You can iterate over the globals in a + {!Cil_types.file} using the following iterators: {!Cil.mapGlobals}, + {!Cil.iterGlobals} and {!Cil.foldGlobals}. You can also use the + {!Cil.dummyFile} when you need a {!Cil_types.file} as a placeholder. For + each global item CIL stores the source location where it appears (using the + type {!Cil_types.location}) + @plugin development guide *) +type file = { + mutable fileName: string; (** The complete file name *) + + mutable globals: global list; + (** List of globals as they will appear in the printed file *) + + mutable globinit: fundec option; + (** An optional global initializer function. This is a function where you + can put stuff that must be executed before the program is + started. This function, is conceptually at the end of the file, + although it is not part of the globals list. Use {!Cil.getGlobInit} to + create/get one. *) + + mutable globinitcalled: bool; +(** Whether the global initialization function is called in main. This + should always be false if there is no global initializer. When you + create a global initialization CIL will try to insert code in main to + call it. *) +} + +(** The main type for representing global declarations and definitions. A list + of these form a CIL file. The order of globals in the file is generally + important. + @plugin development guide *) +and global = + | GType of typeinfo * location + (** A typedef. All uses of type names (through the [TNamed] constructor) + must be preceeded in the file by a definition of the name. The string + is the defined name and always not-empty. *) + + | GCompTag of compinfo * location + (** Defines a struct/union tag with some fields. There must be one of + these for each struct/union tag that you use (through the [TComp] + constructor) since this is the only context in which the fields are + printed. Consequently nested structure tag definitions must be + broken into individual definitions with the innermost structure + defined first. *) + + | GCompTagDecl of compinfo * location + (** Declares a struct/union tag. Use as a forward declaration. This is + printed without the fields. *) + + | GEnumTag of enuminfo * location + (** Declares an enumeration tag with some fields. There must be one of + these for each enumeration tag that you use (through the [TEnum] + constructor) since this is the only context in which the items are + printed. *) + + | GEnumTagDecl of enuminfo * location + (** Declares an enumeration tag. Use as a forward declaration. This is + printed without the items. *) + + | GVarDecl of varinfo * location + (** A variable declaration (not a definition) for a variable with object + type. There can be several declarations and at most one definition for + a given variable. If both forms appear then they must share the same + varinfo structure. Either has storage Extern or there must be a + definition in this file *) + + | GFunDecl of funspec * varinfo * location + (** A variable declaration (not a definition) for a function, i.e. a + prototype. There can be several declarations and at most one definition + for a given function. If both forms appear then they must share the same + varinfo structure. A prototype shares the varinfo with the fundec of the + definition. Either has storage Extern or there must be a definition in + this file. *) + + | GVar of varinfo * initinfo * location + (** A variable definition. Can have an initializer. The initializer is + updateable so that you can change it without requiring to recreate the + list of globals. There can be at most one definition for a variable in an + entire program. Cannot have storage Extern or function type. *) + + | GFun of fundec * location + (** A function definition. *) + + | GAsm of string * location + (** Global asm statement. These ones can contain only a template *) + + | GPragma of attribute * location + (** Pragmas at top level. Use the same syntax as attributes *) + + | GText of string + (** Some text (printed verbatim) at top level. E.g., this way you can put + comments in the output. *) + + | GAnnot of global_annotation * location +(** a global annotation. Can be + - an axiom or a lemma + - a predicate declaration or definition + - a global type invariant + - a global invariant + - a logic function declaration or definition. *) + +(* ************************************************************************* *) +(** {2 Types} *) +(* ************************************************************************* *) + +(** A C type is represented in CIL using the type {!Cil_types.typ}. Among types + we differentiate the integral types (with different kinds denoting the sign + and precision), floating point types, enumeration types, array and pointer + types, and function types. Every type is associated with a list of + attributes, which are always kept in sorted order. Use {!Cil.addAttribute} + and {!Cil.addAttributes} to construct list of attributes. If you want to + inspect a type, you should use {!Cil.unrollType} or {!Cil.unrollTypeDeep} to + see through the uses of named types. + + CIL is configured at build-time with the sizes and alignments of the + underlying compiler (GCC or MSVC). CIL contains functions that can compute + the size of a type (in bits) {!Cil.bitsSizeOf}, the alignment of a type (in + bytes) {!Cil.alignOf_int}, and can convert an offset into a start and width + (both in bits) using the function {!Cil.bitsOffset}. At the moment these + functions do not take into account the [packed] attributes and pragmas. *) + +and typ = + | TVoid of attributes (** Void type. Also predefined as {!Cil.voidType} *) + + | TInt of ikind * attributes + (** An integer type. The kind specifies the sign and width. Several useful + variants are predefined as {!Cil.intType}, {!Cil.uintType}, + {!Cil.longType}, {!Cil.charType}. *) + + | TFloat of fkind * attributes + (** A floating-point type. The kind specifies the precision. You can also use + the predefined constant {!Cil.doubleType}. *) + + | TPtr of typ * attributes + (** Pointer type. Several useful variants are predefined as + {!Cil.charPtrType}, {!Cil.charConstPtrType} (pointer to a constant + character), {!Cil.voidPtrType}, {!Cil.intPtrType} *) + + | TArray of typ * exp option * bitsSizeofTypCache * attributes + (** Array type. It indicates the base type and the array length. *) + + | TFun of typ * (string * typ * attributes) list option * bool * attributes + (** Function type. Indicates the type of the result, the name, type + and name attributes of the formal arguments ([None] if no arguments + were specified, as in a function whose definition or prototype we + have not seen; [Some \[\]] means void). Use {!Cil.argsToList} to + obtain a list of arguments. The boolean indicates if it is a + variable-argument function. If this is the type of a varinfo for + which we have a function declaration then the information for the + formals must match that in the function's sformals. Use + {!Cil.setFormals}, or {!Cil.setFunctionType}, or + {!Cil.makeFormalVar} for this purpose. *) + + | TNamed of typeinfo * attributes + (** The use of a named type. All uses of the same type name must share the + typeinfo. Each such type name must be preceeded in the file by a [GType] + global. This is printed as just the type name. The actual referred type + is not printed here and is carried only to simplify processing. To see + through a sequence of named type references, use {!Cil.unrollType}. The + attributes are in addition to those given when the type name was + defined. *) + + | TComp of compinfo * bitsSizeofTypCache * attributes + (** A reference to a struct or a union type. All references to the + same struct or union must share the same compinfo among them and + with a [GCompTag] global that preceeds all uses (except maybe + those that are pointers to the composite type). The attributes + given are those pertaining to this use of the type and are in + addition to the attributes that were given at the definition of + the type and which are stored in the compinfo. *) + + | TEnum of enuminfo * attributes + (** A reference to an enumeration type. All such references must + share the enuminfo among them and with a [GEnumTag] global that + preceeds all uses. The attributes refer to this use of the + enumeration and are in addition to the attributes of the + enumeration itself, which are stored inside the enuminfo *) + + | TBuiltin_va_list of attributes +(** This is the same as the gcc's type with the same name *) + +(** Various kinds of integers *) +and ikind = + IBool (** [_Bool] *) + | IChar (** [char] *) + | ISChar (** [signed char] *) + | IUChar (** [unsigned char] *) + | IInt (** [int] *) + | IUInt (** [unsigned int] *) + | IShort (** [short] *) + | IUShort (** [unsigned short] *) + | ILong (** [long] *) + | IULong (** [unsigned long] *) + | ILongLong (** [long long] (or [_int64] on Microsoft Visual C) *) + | IULongLong (** [unsigned long long] (or [unsigned _int64] on Microsoft + Visual C) *) + +(** Various kinds of floating-point numbers*) +and fkind = + FFloat (** [float] *) + | FDouble (** [double] *) + | FLongDouble (** [long double] *) + +(** This is used to cache the computation of the size of types in bits. *) +and bitsSizeofTyp = + | Not_Computed + | Computed of int + | Not_Computable of (string * typ) (** Explanation of the error *) + +and bitsSizeofTypCache = { mutable scache : bitsSizeofTyp} + +(* ************************************************************************* *) +(** {2 Attributes} *) +(* ************************************************************************* *) + +and attribute = + | Attr of string * attrparam list + (** An attribute has a name and some optional parameters. The name should not + start or end with underscore. When CIL parses attribute names it will + strip leading and ending underscores (to ensure that the multitude of GCC + attributes such as const, __const and __const__ all mean the same + thing.) *) + + | AttrAnnot of string + +(** Attributes are lists sorted by the attribute name. Use the functions + {!Cil.addAttribute} and {!Cil.addAttributes} to insert attributes in an + attribute list and maintain the sortedness. *) +and attributes = attribute list + +(** The type of parameters of attributes *) +and attrparam = + | AInt of (Integer.t[@opaque]) (** An integer constant *) + | AStr of string (** A string constant *) + | ACons of string * attrparam list + (** Constructed attributes. These are printed [foo(a1,a2,...,an)]. The list + of parameters can be empty and in that case the parentheses are not + printed. *) + | ASizeOf of typ (** A way to talk about types *) + | ASizeOfE of attrparam + | AAlignOf of typ + | AAlignOfE of attrparam + | AUnOp of unop * attrparam + | ABinOp of binop * attrparam * attrparam + | ADot of attrparam * string (** a.foo **) + | AStar of attrparam (** * a *) + | AAddrOf of attrparam (** & a **) + | AIndex of attrparam * attrparam (** a1[a2] *) + | AQuestion of attrparam * attrparam * attrparam (** a1 ? a2 : a3 **) + +(* ************************************************************************* *) +(** {2 Structures} *) +(* ************************************************************************* *) + +(** The {!Cil_types.compinfo} describes the definition of a structure or union + type. Each such {!Cil_types.compinfo} must be defined at the top-level using + the [GCompTag] constructor and must be shared by all references to this type + (using either the [TComp] type constructor or from the definition of the + fields. + + If all you need is to scan the definition of each composite type once, you + can do that by scanning all top-level [GCompTag]. + + Constructing a {!Cil_types.compinfo} can be tricky since it must contain + fields that might refer to the host {!Cil_types.compinfo} and furthermore + the type of the field might need to refer to the {!Cil_types.compinfo} for + recursive types. Use the {!Cil.mkCompInfo} function to create a + {!Cil_types.compinfo}. You can easily fetch the {!Cil_types.fieldinfo} for a + given field in a structure with {!Cil.getCompField}. *) + +(** The definition of a structure or union type. Use {!Cil.mkCompInfo} to make + one and use {!Cil.copyCompInfo} to copy one (this ensures that a new key is + assigned and that the fields have the right pointers to parents.). + @plugin development guide *) +and compinfo = { + mutable cstruct: bool; + (** [true] if struct, [false] if union *) + + corig_name: string; + (** Original name as found in C file. Will never be changed *) + + mutable cname: string; + (** The name. Always non-empty. Use {!Cil.compFullName} to get the full name + of a comp (along with the struct or union) *) + + mutable ckey: int; + (** A unique integer. This is assigned by {!Cil.mkCompInfo} using a global + variable in the Cil module. Thus two identical structs in two different + files might have different keys. Use {!Cil.copyCompInfo} to copy + structures so that a new key is assigned. *) + + mutable cfields: fieldinfo list; + (** Information about the fields. Notice that each fieldinfo has a pointer + back to the host compinfo. This means that you should not share + fieldinfo's between two compinfo's *) + + mutable cattr: attributes; + (** The attributes that are defined at the same time as the composite + type. These attributes can be supplemented individually at each + reference to this [compinfo] using the [TComp] type constructor. *) + + mutable cdefined: bool; + (** This boolean flag can be used to distinguish between structures + that have not been defined and those that have been defined but have + no fields (such things are allowed in gcc). *) + + mutable creferenced: bool; +(** [true] if used. Initially set to [false]. *) +} + +(* ************************************************************************* *) +(** {2 Structure fields} *) +(* ************************************************************************* *) + +(** The {!Cil_types.fieldinfo} structure is used to describe a structure or + union field. Fields, just like variables, can have attributes associated + with the field itself or associated with the type of the field (stored along + with the type of the field). *) + +(** Information about a struct/union field. + @plugin development guide *) +and fieldinfo = { + mutable fcomp: compinfo; + (** The host structure that contains this field. There can be only one + [compinfo] that contains the field. *) + + forig_name: string; + (** original name as found in C file. *) + + mutable fname: string; + (** The name of the field. Might be the value of {!Cil.missingFieldName} in + which case it must be a bitfield and is not printed and it does not + participate in initialization *) + + mutable ftype: typ; + (** The type. If the field is a bitfield, a special attribute + [FRAMA_C_BITFIELD_SIZE] indicating the width of the bitfield is added. *) + + mutable fbitfield: int option; + (** If a bitfield then ftype should be an integer type and the width of the + bitfield must be 0 or a positive integer smaller or equal to the width of + the integer type. A field of width 0 is used in C to control the alignment + of fields. *) + + mutable fattr: attributes; + (** The attributes for this field (not for its type) *) + + mutable floc: location; + (** The location where this field is defined *) + + mutable faddrof: bool; + (** Adapted from CIL [vaddrof] field for variables. Only set for non-array + fields. Variable whose field address is taken is not marked anymore as + having its own address taken. True if the address of this field is + taken. CIL will set these flags when it parses C, but you should make + sure to set the flag whenever your transformation create [AddrOf] + expression. *) + + mutable fsize_in_bits: int option; + (** (Deprecated. Use {!Cil.bitsOffset} instead.) Similar to [fbitfield] for + all types of fields. + @deprecated only Jessie uses this *) + + mutable foffset_in_bits: int option; + (** Offset at which the field starts in the structure. Do not read directly, + but use {!Cil.bitsOffset} instead. *) + + mutable fpadding_in_bits: int option; +(** (Deprecated.) Store the size of the padding that follows the field, if any. + @deprecated only Jessie uses this *) +} + +(* ************************************************************************* *) +(** {2 Enumerations} *) +(* ************************************************************************* *) + +(** Information about an enumeration. This is shared by all references to an + enumeration. Make sure you have a [GEnumTag] for each of these. *) + +(** Information about an enumeration. + @plugin development guide *) +and enuminfo = { + eorig_name: string; (** original name as found in C file. *) + + mutable ename: string; (** The name. Always non-empty. *) + + mutable eitems: enumitem list; (** Items. The list must be non-empty *) + + mutable eattr: attributes; + (** The attributes that are defined at the same time as the enumeration + type. These attributes can be supplemented individually at each + reference to this [enuminfo] using the [TEnum] type constructor. *) + + mutable ereferenced: bool; (** [true] if used. Initially set to [false]. *) + mutable ekind: ikind (** The integer kind used to represent this enum. MSVC + always assumes IInt but this is not the case + for gcc. See ISO C 6.7.2.2 *) +} + +and enumitem = { + eiorig_name: string; (** original name as found in C file. *) + mutable einame: string; (** the name, always non-empty. *) + mutable eival: exp; (** value of the item. Must be a compile-time constant *) + mutable eihost: enuminfo; (** the host enumeration in which the item is + declared. *) + eiloc: location; +} + +(** Information about a defined type. + @plugin development guide *) +and typeinfo = { + torig_name: string; (** original name as found in C file. *) + + mutable tname: string; + (** The name. Can be empty only in a [GType] when introducing a composite or + enumeration tag. If empty cannot be refered to from the file *) + + mutable ttype: typ; + (** The actual type. This includes the attributes that were present in the + typedef *) + + mutable treferenced: bool; (** [true] if used. Initially set to [false]. *) +} + +(* ************************************************************************* *) +(** {2 Variables} *) +(* ************************************************************************* *) + +(** Each local or global variable is represented by a unique + {!Cil_types.varinfo} structure. A global {!Cil_types.varinfo} can be + introduced with the [GVarDecl] or [GVar], [GFunDecl] or [GFun] globals. + A local varinfo can be introduced as part of a function definition + {!Cil_types.fundec}. + + All references to a given global or local variable must refer to the same + copy of the [varinfo]. Each [varinfo] has a globally unique identifier that + can be used to index maps and hashtables (the name can also be used for this + purpose, except for locals from different functions). This identifier is + constructor using a global counter. + + It is very important that you construct [varinfo] structures using only one + of the following functions: + - {!Cil.makeGlobalVar} : to make a global variable + - {!Cil.makeTempVar} : to make a temporary local variable whose name + will be generated so that to avoid conflict with other locals. + - {!Cil.makeLocalVar} : like {!Cil.makeTempVar} but you can specify the + exact name to be used. + - {!Cil.copyVarinfo}: make a shallow copy of a varinfo assigning a new name + and a new unique identifier + + A [varinfo] is also used in a function type to denote the list of + formals. *) + +(** Information about a variable. + @plugin development guide *) +and varinfo = { + mutable vname: string; + (** The name of the variable. Cannot be empty. It is primarily your + responsibility to ensure the uniqueness of a variable name. For local + variables {!Cil.makeTempVar} helps you ensure that the name is + unique. *) + + vorig_name: string; + (** the original name of the variable. Need not be unique. *) + + mutable vtype: typ; + (** The declared type of the variable. *) + + mutable vattr: attributes; + (** A list of attributes associated with the variable.*) + + mutable vstorage: storage; + (** The storage-class *) + + mutable vglob: bool; + (** True if this is a global variable*) + + mutable vdefined: bool; + (** True if the variable or function is defined in the file. Only relevant + for functions and global variables. Not used in particular for local + variables and logic variables. *) + + mutable vformal: bool; + (** True if the variable is a formal parameter of a function. *) + + mutable vinline: bool; + (** Whether this varinfo is for an inline function. *) + + mutable vdecl: location; + (** Location of variable declaration. *) + + mutable vid: int; + (** A unique integer identifier. This field will be set for you if you use + one of the {!Cil.makeFormalVar}, {!Cil.makeLocalVar}, + {!Cil.makeTempVar}, {!Cil.makeGlobalVar}, or {!Cil.copyVarinfo}. *) + + mutable vaddrof: bool; + (** [true] if the address of this variable is taken. CIL will set these + flags when it parses C, but you should make sure to set the flag + whenever your transformation create [AddrOf] expression. *) + + mutable vreferenced: bool; + (** [true] if this variable is ever referenced. This is computed by + [removeUnusedVars]. It is safe to just initialize this to [false]. *) + + vtemp: bool; + (** [true] for temporary variables generated by CIL normalization. [false] + for all the other variables. *) + + mutable vdescr: string option; + (** For most temporary variables, a description of what the var holds. + (e.g. for temporaries used for function call results, this string is a + representation of the function call.) *) + + mutable vdescrpure: bool; + (** Indicates whether the vdescr above is a pure expression or call. True + for all CIL expressions and Lvals, but false for e.g. function calls. + Printing a non-pure vdescr more than once may yield incorrect + results. *) + + mutable vghost: bool; + (** Indicates if the variable is declared in ghost code *) + + vsource: bool; + (** [true] iff this variable appears in the source of the program, which is + the case of all the variables in the initial AST. Plugins may create + variables with [vsource=false], for example to handle dynamic allocation. + Those variables do *not* have an associated {!GVar} or {!GVarDecl}. *) + + mutable vlogic_var_assoc: logic_var option + (** Logic variable representing this variable in the logic world. Do not + access this field directly. Instead, call {!Cil.cvar_to_lvar}. *) +} + +(** Storage-class information *) +and storage = + NoStorage (** The default storage. Nothing is printed *) + | Static + | Register + | Extern + +(* ************************************************************************* *) +(** {2 Expressions} *) +(* ************************************************************************* *) + +(** The CIL expression language contains only the side-effect free expressions + of C. They are represented as the type {!Cil_types.exp}. There are several + interesting aspects of CIL expressions: + + Integer and floating point constants can carry their textual representation. + This way the integer 15 can be printed as 0xF if that is how it occurred in + the source. + + CIL uses arbitrary precision integers + to represent the integer constants and also stores the + width of the integer type. Care must be taken to ensure that the constant is + representable with the given width. Use the functions {!Cil.kinteger}, + {!Cil.kinteger64} and {!Cil.integer} to construct constant expressions. CIL + predefines the constants {!Cil.zero}, {!Cil.one} and {!Cil.mone} (for -1). + + Use the functions {!Cil.isConstant} and {!Cil.isInteger} to test if an + expression is a constant and a constant integer respectively. + + CIL keeps the type of all unary and binary expressions. You can think of + that type qualifying the operator. Furthermore there are different operators + for arithmetic and comparisons on arithmetic types and on pointers. + + Another unusual aspect of CIL is that the implicit conversion between an + expression of array type and one of pointer type is made explicit, using the + [StartOf] expression constructor (which is not printed). If you apply the + [AddrOf]constructor to an lvalue of type [T] then you will be getting an + expression of type [TPtr(T)]. + + You can find the type of an expression with {!Cil.typeOf}. + + You can perform constant folding on expressions using the function + {!Cil.constFold}. *) + +(** Expressions (Side-effect free)*) +and exp = { + eid: int; (** unique identifier *) + enode: exp_node; (** the expression itself *) + eloc: location; (** location of the expression. *) +} + +and exp_node = + | Const of constant (** Constant *) + | Lval of lval (** Lvalue *) + | SizeOf of typ + (** sizeof(). Has [unsigned int] type (ISO 6.5.3.4). This is not + turned into a constant because some transformations might want to change + types *) + + | SizeOfE of exp (** sizeof() *) + + | SizeOfStr of string + (** sizeof(string_literal). We separate this case out because this is the + only instance in which a string literal should not be treated as having + type pointer to character. *) + + | AlignOf of typ + (** This corresponds to the GCC __alignof_. Has [unsigned int] type *) + + | AlignOfE of exp + + | UnOp of unop * exp * typ + (** Unary operation. Includes the type of the result. *) + + | BinOp of binop * exp * exp * typ + (** Binary operation. Includes the type of the result. The arithmetic + conversions are made explicit for the arguments. + @plugin development guide *) + + | CastE of typ * exp + (** Use {!Cil.mkCast} to make casts. *) + + | AddrOf of lval + (** Always use {!Cil.mkAddrOf} to construct one of these. Apply to an lvalue + of type [T] yields an expression of type [TPtr(T)] *) + + | StartOf of lval + (** Conversion from an array to a pointer to the beginning of the array. + Given an lval of type [TArray(T)] produces an expression of type + [TPtr(T)]. In C this operation is implicit, the [StartOf] operator is not + printed. We have it in CIL because it makes the typing rules simpler. *) + + | Info of exp * exp_info +(** Additional information on the underlying expression *) + +(** Additional information on an expression *) +and exp_info = { + exp_type : logic_type; (** when used as placeholder for a term *) + exp_name: string list; +} + +(* ************************************************************************* *) +(** {2 Constants} *) +(* ************************************************************************* *) + +(** Literal constants *) +and constant = + | CInt64 of (Integer.t[@opaque]) * ikind * string option + (** Integer constant. Give the ikind (see ISO9899 6.1.3.2) and the + textual representation. Textual representation is always set to Some s + when it comes from user code. This allows us to print a + constant as it was represented in the code, for example, + 0xF instead of 15. It is usually None for constant generated by Cil + itself. Use {!Cil.integer} or {!Cil.kinteger} to create these. *) + + | CStr of string + (** String constant. The escape characters inside the string have been already + interpreted. This constant has pointer to character type! The only case + when you would like a string literal to have an array type is when it is + an argument to sizeof. In that case you should use SizeOfStr. *) + + | CWStr of int64 list + (** Wide character string constant. Note that the local interpretation of such + a literal depends on {!Cil.theMachine.wcharType} and + {!Cil.theMachine.wcharKind}. Such a constant has type pointer to + {!Cil.theMachine.wcharType}. The escape characters in the string have not + been "interpreted" in the sense that L"A\xabcd" remains "A\xabcd" rather + than being represented as the wide character list with two elements: 65 + and 43981. That "interpretation" depends on the underlying wide character + type. *) + + | CChr of char + (** Character constant. This has type int, so use charConstToInt to read the + value in case sign-extension is needed. *) + + | CReal of float * fkind * string option + (** Floating point constant. Give the fkind (see ISO 6.4.4.2) and also the + textual representation, if available. *) + + | CEnum of enumitem +(** An enumeration constant. Use [Cillower.lowerEnumVisitor] to replace these + with integer constants. *) + +(** Unary operators *) +and unop = + Neg (** Unary minus *) + | BNot (** Bitwise complement (~) *) + | LNot (** Logical Not (!) *) + +(** Binary operations *) +and binop = + PlusA (** arithmetic + *) + | PlusPI (** pointer + integer *) + | IndexPI (** pointer + integer but only when it arises from an expression + [e\[i\]] when [e] is a pointer and + not an array. This is semantically + the same as PlusPI but CCured uses + this as a hint that the integer is + probably positive. *) + | MinusA (** arithmetic - *) + | MinusPI (** pointer - integer *) + | MinusPP (** pointer - pointer *) + | Mult (** * *) + | Div (** / + @plugin development guide *) + | Mod (** % + @plugin development guide *) + | Shiftlt (** shift left *) + | Shiftrt (** shift right *) + + | Lt (** < (arithmetic comparison) *) + | Gt (** > (arithmetic comparison) *) + | Le (** <= (arithmetic comparison) *) + | Ge (** >= (arithmetic comparison) *) + | Eq (** == (arithmetic comparison) *) + | Ne (** != (arithmetic comparison) *) + | BAnd (** bitwise and *) + | BXor (** exclusive-or *) + | BOr (** inclusive-or *) + + | LAnd (** logical and. Unlike other expressions this one does not always + evaluate both operands. If you want + to use these, you must set + {!Cil.useLogicalOperators}. *) + | LOr (** logical or. Unlike other expressions this one does not always + evaluate both operands. If you + want to use these, you must set + {!Cil.useLogicalOperators}. *) + +(* ************************************************************************* *) +(** {2 Left values} *) +(* ************************************************************************* *) + +(** Left values (aka Lvalues) are the sublanguage of expressions that can appear + at the left of an assignment or as operand to the address-of operator. In C + the syntax for lvalues is not always a good indication of the meaning of the + lvalue. For example the C value {v a[0][1][2] v} might involve 1, 2 or 3 + memory reads when used in an expression context, depending on the declared + type of the variable [a]. If [a] has type [int \[4\]\[4\]\[4\]] then we have + one memory read from somewhere inside the area that stores the array [a]. On + the other hand if [a] has type [int ***] then the expression really means [* + ( * ( * (a + 0) + 1) + 2)], in which case it is clear that it involves three + separate memory operations. + + An lvalue denotes the contents of a range of memory addresses. This range is + denoted as a host object along with an offset within the object. The host + object can be of two kinds: a local or global variable, or an object whose + address is in a pointer expression. We distinguish the two cases so that we + can tell quickly whether we are accessing some component of a variable + directly or we are accessing a memory location through a pointer. To make + it easy to tell what an lvalue means CIL represents lvalues as a host object + and an offset (see {!Cil_types.lval}). The host object (represented as + {!Cil_types.lhost}) can be a local or global variable or can be the object + pointed-to by a pointer expression. The offset (represented as + {!Cil_types.offset}) is a sequence of field or array index designators. + + Both the typing rules and the meaning of an lvalue is very precisely + specified in CIL. + + The following are a few useful function for operating on lvalues: + - {!Cil.mkMem} - makes an lvalue of [Mem] kind. Use this to ensure + that certain equivalent forms of lvalues are canonized. + For example, [*&x = x]. + - {!Cil.typeOfLval} - the type of an lvalue + - {!Cil.typeOffset} - the type of an offset, given the type of the + host. + - {!Cil.addOffset} and {!Cil.addOffsetLval} - extend sequences + of offsets. + - {!Cil.removeOffset} and {!Cil.removeOffsetLval} - shrink sequences + of offsets. + + The following equivalences hold {v + Mem(AddrOf(Mem a, aoff)), off = Mem a, aoff + off + Mem(AddrOf(Var v, aoff)), off = Var v, aoff + off + AddrOf (Mem a, NoOffset) = a + v} *) + +and lval = lhost * offset + +(** The host part of an {!Cil_types.lval}. *) +and lhost = + | Var of varinfo + (** The host is a variable. *) + + | Mem of exp +(** The host is an object of type [T] when the expression has pointer + [TPtr(T)]. *) + + +(** The offset part of an {!Cil_types.lval}. Each offset can be applied to + certain kinds of lvalues and its effect is that it advances the starting + address of the lvalue and changes the denoted type, essentially focussing + to some smaller lvalue that is contained in the original one. + @plugin development guide *) +and offset = + | NoOffset + (** No offset. Can be applied to any lvalue and does not change either the + starting address or the type. This is used when the lval consists of just + a host or as a terminator in a list of other kinds of offsets. *) + + | Field of fieldinfo * offset + (** A field offset. Can be applied only to an lvalue that denotes a structure + or a union that contains the mentioned field. This advances the offset to + the beginning of the mentioned field and changes the type to the type of + the mentioned field. *) + + | Index of exp * offset +(** An array index offset. Can be applied only to an lvalue that denotes an + array. This advances the starting address of the lval to the beginning of + the mentioned array element and changes the denoted type to be the type of + the array element *) + +(* ************************************************************************* *) +(** {2 Initializers} *) +(* ************************************************************************* *) + +(** A special kind of expressions are those that can appear as initializers for + global variables (initialization of local variables is turned into + assignments). The initializers are represented as type + {!Cil_types.init}. You can create initializers with {!Cil.makeZeroInit} and + you can conveniently scan compound initializers them with + {!Cil.foldLeftCompound}. *) + +(** Initializers for global variables. *) +and init = + | SingleInit of exp (** A single initializer *) + | CompoundInit of typ * (offset * init) list +(** Used only for initializers of structures, unions and arrays. The offsets + are all of the form [Field(f, NoOffset)] or [Index(i, NoOffset)] and + specify the field or the index being initialized. For structures all fields + must have an initializer (except the unnamed bitfields), in the proper + order. This is necessary since the offsets are not printed. For arrays the + list must contain a prefix of the initializers; the rest are 0-initialized. + For unions there must be exactly one initializer. If the initializer is not + for the first field then a field designator is printed, so you better be on + GCC since MSVC does not understand this. You can scan an initializer list + with {!Cil.foldLeftCompound}. *) + +(** We want to be able to update an initializer in a global variable, so we + define it as a mutable field *) +and initinfo = { mutable init : init option } + +(* ************************************************************************* *) +(** {2 Function definitions} *) +(* ************************************************************************* *) + +(** A function definition is always introduced with a [GFun] constructor at the + top level. All the information about the function is stored into a + {!Cil_types.fundec}. Some of the information (e.g. its name, type, storage, + attributes) is stored as a {!Cil_types.varinfo} that is a field of the + [fundec]. To refer to the function from the expression language you must use + the [varinfo]. + + The function definition contains, in addition to the body, a list of all the + local variables and separately a list of the formals. Both kind of variables + can be referred to in the body of the function. The formals must also be + shared with the formals that appear in the function type. For that reason, + to manipulate formals you should use the provided functions + {!Cil.makeFormalVar} and {!Cil.setFormals}. *) + +(** Function definitions. + @plugin development guide *) +and fundec = { + mutable svar: varinfo; + (** Holds the name and type as a variable, so we can refer to it easily + from the program. All references to this function either in a function + call or in a prototype must point to the same [varinfo]. *) + + mutable sformals: varinfo list; + (** Formals. These must be in the same order and with the same information + as the formal information in the type of the function. Use + {!Cil.setFormals} or {!Cil.setFunctionType} to set these formals and + ensure that they are reflected in the function type. Do not make + copies of these because the body refers to them. *) + + mutable slocals: varinfo list; + (** Locals. Does NOT include the sformals. Do not make copies of these + because the body refers to them. *) + + mutable smaxid: int; + (** Max local id. Starts at 0. Used for creating the names of new + temporary variables. Updated by {!Cil.makeLocalVar} and + {!Cil.makeTempVar}. You can also use {!Cil.setMaxId} to set it after + you have added the formals and locals. *) + + mutable sbody: block; (** The function body. *) + + mutable smaxstmtid: int option; + (** max id of a (reachable) statement in this function, if we have + computed it. range = 0 ... (smaxstmtid-1). This is computed by + {!Cfg.computeCFGInfo}. *) + + mutable sallstmts: stmt list; + (** After you call {!Cfg.computeCFGInfo} this field is set to contain all + statements in the function. *) + + mutable sspec: funspec; +} + +(** A block is a sequence of statements with the control falling through from + one element to the next *) +and block = { + mutable battrs: attributes; (** Attributes for the block *) + + mutable blocals: varinfo list; + (** variables that are local to the block. It is a subset of the slocals of + the enclosing function. *) + + mutable bstmts: stmt list; (** The statements comprising the block. *) +} + +(* ************************************************************************* *) +(** {2 Statements} *) +(* ************************************************************************* *) + +(** CIL statements are the structural elements that make the CFG. They are + represented using the type {!Cil_types.stmt}. Every statement has a + (possibly empty) list of labels. The {!Cil_types.stmtkind} field of a + statement indicates what kind of statement it is. + + Use {!Cil.mkStmt} to make a statement and the fill-in the fields. + + CIL also comes with support for control-flow graphs. The [sid] field in + [stmt] can be used to give unique numbers to statements, and the [succs] and + [preds] fields can be used to maintain a list of successors and predecessors + for every statement. The CFG information is not computed by default. Instead + you must explicitly use the functions {!Cfg.prepareCFG} and + {!Cfg.computeCFGInfo} to do it. *) + +(** Statements. + @plugin development guide *) +and stmt = { + mutable labels: label list; + (** Whether the statement starts with some labels, case statements or + default statements. *) + + mutable skind: stmtkind; + (** The kind of statement *) + + mutable sid: int; + (** A number (>= 0) that is unique in a function. Filled in only after the + CFG is computed. *) + + mutable succs: stmt list; + (** The successor statements. They can always be computed from the skind and + the context in which this statement appears. Filled in only after the CFG + is computed. *) + + mutable preds: stmt list; + (** The inverse of the succs function. *) + + mutable ghost : bool +} + +(** Labels *) +and label = + | Label of string * location * bool + (** A real label. If the bool is "true", the label is from the input source + program. If the bool is "false", the label was created by CIL or some + other transformation *) + + | Case of exp * location + (** A case statement. This expression is lowered into a constant if + {!Cil.lowerConstants} is set to [true]. *) + + | Default of location (** A default statement *) + +(* The various kinds of statements *) +and stmtkind = + | Instr of instr + (** An instruction that does not contain control flow. Control implicitly + falls through. + @plugin development guide *) + + | Return of exp option * location + (** The return statement. This is a leaf in the CFG. + @plugin development guide *) + + | Goto of stmt ref * location + (** A goto statement. Appears from actual goto's in the code or from goto's + that have been inserted during elaboration. The reference points to the + statement that is the target of the Goto. This means that you have to + update the reference whenever you replace the target statement. The + target statement MUST have at least a label. + @plugin development guide *) + + | Break of location + (** A break to the end of the nearest enclosing Loop or Switch. + @plugin development guide *) + + | Continue of location + (** A continue to the start of the nearest enclosing [Loop]. + @plugin development guide *) + + | If of exp * block * block * location + (** A conditional. Two successors, the "then" and the "else" branches (in + this order). + Both branches fall-through to the successor of the If statement. + @plugin development guide *) + + | Switch of exp * block * (stmt list) * location + (** A switch statement. [exp] is the index of the switch. [block] is + the body of the switch. [stmt list] contains the set of + statements whose [labels] are cases of the switch (i.e. for each + case, the corresponding statement is in [stmt list], a statement + cannot appear more than once in the list, and statements in + [stmt list] can have several labels corresponding to several + cases. + @plugin development guide *) + + | Loop of + code_annotation list * block * location * (stmt option) * (stmt option) + (** A [while(1)] loop. The termination test is implemented in the body of a + loop using a [Break] statement. If {!Cfg.prepareCFG} has been called, the + first stmt option will point to the stmt containing the continue label + for this loop and the second will point to the stmt containing the break + label for this loop. + @plugin development guide *) + + | Block of block + (** Just a block of statements. Use it as a way to keep some block attributes + local. + @plugin development guide *) + + | UnspecifiedSequence of (stmt * lval list + * lval list * lval list * stmt ref list) list + (** statements whose order of execution is not specified by + ISO/C. This is important for the order of side effects + during evaluation of expressions. Each statement comes + together with three list of lval, in this order. + - lvals that are written during the sequence and whose future + value depends upon the statement (it is legal to read from them, but + not to write to them) + - lvals that are written during the evaluation of the statement itself + - lval that are read. + - Function calls in the corresponding statement + Note that this include only a subset of the affectations + of the statement. Namely, the + temporary variables generated by cil are excluded (i.e. it + is assumed that the "compilation" is correct). In addition, + side effects caused by function applications are not taken + into account in the list. For a single statement, the written lvals + are supposed to be ordered (or their order of evaluation doesn't + matter), so that an alarm should be emitted only if the lvals read by + a statement overlap with the lvals written (or read) by another + statement of the sequence. + + At this time this feature is + experimental and may miss some unspecified sequences. + + In case you do not care about this feature just handle it + like a block (see {!Cil.block_from_unspecified_sequence}). + @plugin development guide *) + + | Throw of (exp * typ) option * location + (** Throws an exception, C++ style. + We keep the type of the expression, to match + it against the appropriate catch clause. A Throw node has + no successor, even if it is in try-catch block that will catch + the exception: we keep normal and exceptional control-flow + completely separate, as in Jo and Chang, ICSSA 2004. + *) + + | TryCatch of block * (catch_binder * block) list * location + + | TryFinally of block * block * location + (** On MSVC we support structured exception handling. This is what you might + expect. Control can get into the finally block either from the end of the + body block, or if an exception is thrown. + @plugin development guide *) + + | TryExcept of block * (instr list * exp) * block * location +(** On MSVC we support structured exception handling. The try/except + statement is a bit tricky: + {v __try \{ blk \} + __except (e) \{ + handler + \} + v} + + The argument to __except must be an expression. However, we keep a + list of instructions AND an expression in case you need to make + function calls. We'll print those as a comma expression. The control + can get to the __except expression only if an exception is thrown. + After that, depending on the value of the expression the control + goes to the handler, propagates the exception, or retries the + exception. The location corresponds to the try keyword. + @plugin development guide *) + +(** Kind of exceptions that are caught by a given clause. *) +and catch_binder = + | Catch_exn of varinfo * (varinfo * block) list + (** catch exception of given type(s). + If the list is empty, only exceptions with the same type as the + varinfo can be caught. If the list is non-empty, only exceptions + matching one of the type of a varinfo in the list are caught. + The associated block contains the operations necessary to transform + the matched varinfo into the principal one. + Semantics is by value (i.e. the varinfo is bound to a copy of the + caught object). + + This clause is a declaration point for the varinfo(s) + mentioned in it. More precisely, for + [Catch_exn(v_0,[(v_1, b_1),..., (v_n, b_n)])], + the [v_i] must be referenced in the [slocals] of the + enclosing [fundec], and _must not_ appear in any [blocals] + of some block. The scope of v_0 is all the [b_i] and + the corresponding block in the [catch_binder * block list] of the + [TryCatch] node the binder belongs to. The scope of the other [v_i] + is the corresponding [b_i]. + *) + | Catch_all (** default catch clause: all exceptions are caught. *) + +(** Instructions. They may cause effects directly but may not have control + flow.*) +and instr = + | Set of lval * exp * location + (** An assignment. A cast is present if the exp has different type from + lval *) + + | Call of lval option * exp * exp list * location + (** optional: result is an lval. A cast might be necessary if the declared + result type of the function is not the same as that of the destination. + Actual arguments must have a type equivalent (i.e. {!Cil.need_cast} must + return [false]) to the one of the formals of the function. + If the type of the result variable is not the same as the declared type of + the function result then an implicit cast exists. + *) + + (* See the GCC specification for the meaning of ASM. + If the source is MS VC then only the templates + are used. + + [sm] I've added a notes.txt file which contains more + information on interpreting Asm instructions *) + | Asm of + attributes (* Really only const and volatile can appear here *) + * string list (* templates (CR-separated) *) + * extended_asm option + * location + (** An inline assembly instruction. The arguments are + (1) a list of attributes (only const and volatile can appear here and only + for GCC) + (2) templates (CR-separated) + (3) GCC extended asm information if any + (4) location information *) + + | Skip of location + + | Code_annot of code_annotation * location + + +(** GNU extended-asm information: + - a list of outputs, each of which is an lvalue with optional names and + constraints. + - a list of input expressions along with constraints + - clobbered registers + - Possible destinations statements *) +and extended_asm = + { + asm_outputs: (string option * string * lval) list + (** outputs must be lvals with optional names and constraints. I would + like these to be actually variables, but I run into some trouble with + ASMs in the Linux sources *); + asm_inputs: (string option * string * exp) list + (** inputs with optional names and constraints *); + asm_clobbers: string list (** register clobbers *); + asm_gotos: (stmt ref) list + (** list of statements this asm section may jump to. Destination + must have a label. *); + } + +(** Describes a location in a source file *) +and location = Lexing.position * Lexing.position [@opaque] + +(** {1 Abstract syntax trees for annotations} *) + +and logic_constant = + | Integer of (Integer.t[@opaque]) * string option + (** Integer constant with a textual representation. *) + | LStr of string (** String constant. *) + | LWStr of int64 list (** Wide character string constant. *) + | LChr of char (** Character constant. *) + | LReal of logic_real + | LEnum of enumitem (** An enumeration constant.*) + +(** Real constants. *) +and logic_real = { + r_literal : string ; (** Initial string representation [s]. *) + r_nearest : float ; (** Nearest approximation of [s] in double precision. *) + r_upper : float ; (** Smallest double [u] such that [s <= u]. *) + r_lower : float ; (** Greatest double [l] such that [l <= s]. *) +} + +(** Types of logic terms. *) +and logic_type = + | Ctype of typ (** a C type *) + | Ltype of logic_type_info * logic_type list + (** an user-defined logic type with its parameters *) + | Lvar of string (** a type variable. *) + | Linteger (** mathematical integers, {i i.e.} Z *) + | Lreal (** mathematical reals, {i i.e.} R *) + | Larrow of logic_type list * logic_type (** (n-ary) function type *) + +(** tsets with an unique identifier. + Use [Logic_const.new_location] to generate a new id. *) +and identified_term = { + it_id: int; (** the identifier. *) + it_content: term (** the term *) +} + +(** logic label referring to a particular program point. *) +and logic_label = + | StmtLabel of stmt ref (** label of a C statement. *) + | LogicLabel of (stmt option * string) (* [JS 2011/05/13] why a tuple here? *) +(** builtin logic label ({t Here, Pre}, ...) *) + +(* ************************************************************************* *) +(** {2 Terms} *) +(* ************************************************************************* *) + +(** C Expressions as logic terms follow C constructs (with prefix T) *) + +(** Logic terms. *) +and term = { + term_node : term_node; (** kind of term. *) + term_loc : Lexing.position * Lexing.position [@opaque]; + (** position in the source file. *) + term_type : logic_type; (** type of the term. *) + term_name: string list; + (** names of the term if any. A name can be an arbitrary string, where + '"' and '\'' are escaped by a \, and which does not end with a \. + Hence, "name" and 'name' should be recognized as a unique label by most + tools. *) +} + +(** the various kind of terms. *) +and term_node = + (* same constructs as exp *) + | TConst of logic_constant (** a constant. *) + | TLval of term_lval (** an L-value *) + | TSizeOf of typ (** size of a given C type. *) + | TSizeOfE of term (** size of the type of an expression. *) + | TSizeOfStr of string (** size of a string constant. *) + | TAlignOf of typ (** alignment of a type. *) + | TAlignOfE of term (** alignment of the type of an expression. *) + | TUnOp of unop * term (** unary operator. *) + | TBinOp of binop * term * term (** binary operators. *) + | TCastE of typ * term (** cast to a C type. *) + | TAddrOf of term_lval (** address of a term. *) + | TStartOf of term_lval (** beginning of an array. *) + + (* additional constructs *) + | Tapp of logic_info * (logic_label * logic_label) list * term list + (** application of a logic function. *) + | Tlambda of quantifiers * term (** lambda abstraction. *) + | TDataCons of logic_ctor_info * term list + (** constructor of logic sum-type. *) + | Tif of term * term * term + (** conditional operator*) + | Tat of term * logic_label + (** term refers to a particular program point. *) + | Tbase_addr of logic_label * term (** base address of a pointer. *) + | Toffset of logic_label * term (** offset from the base address of a pointer. *) + | Tblock_length of logic_label * term (** length of the block pointed to by the term. *) + | Tnull (** the null pointer. *) + | TLogic_coerce of logic_type * term + (** implicit conversion from a C type to a logic type. + The logic type must not be a Ctype. In particular, used to denote + lifting to Linteger and Lreal. + *) + | TCoerce of term * typ (** coercion to a given C type. *) + | TCoerceE of term * term (** coercion to the type of a given term. *) + | TUpdate of term * term_offset * term + (** functional update of a field. *) + | Ttypeof of term (** type tag for a term. *) + | Ttype of typ (** type tag for a C type. *) + | Tempty_set (** the empty set. *) + | Tunion of term list (** union of terms. *) + | Tinter of term list (** intersection of terms. *) + | Tcomprehension of + term * quantifiers * predicate option + (** set defined in comprehension ({t \{ t[i] | integer i; 0 <= i < 5\}}) *) + | Trange of term option * term option (** range of integers. *) + | Tlet of logic_info * term (** local binding *) + +(** lvalue: base address and offset. *) +and term_lval = + term_lhost * term_offset + +(** base address of an lvalue. *) +and term_lhost = + | TVar of logic_var (** a variable. *) + | TResult of typ (** value returned by a C function. + Only used in post-conditions or assigns + *) + | TMem of term (** memory access. *) + +(** model field. *) +and model_info = { + mi_name: string; (** name *) + mi_field_type: logic_type; (** type of the field *) + mi_base_type: typ; (** type to which the field is associated. *) + mi_decl: location; (** where the field has been declared. *) +} + +(** offset of an lvalue. *) +and term_offset = + | TNoOffset (** no further offset. *) + | TField of fieldinfo * term_offset + (** access to the field of a compound type. *) + | TModel of model_info * term_offset (** access to a model field. *) + | TIndex of term * term_offset + (** index. Note that a range is denoted by [TIndex(Trange(i1,i2),ofs)] *) + +(** description of a logic function or predicate. +@plugin development guide *) +and logic_info = { +(* + mutable l_name : string; (** name of the function. *) +*) + mutable l_var_info : logic_var; + (** we use only fields lv_name and lv_id of l_var_info + we should factorize lv_type and l_type+l_profile below *) + mutable l_labels : logic_label list; (** label arguments of the function. *) + mutable l_tparams : string list; (** type parameters *) + mutable l_type : logic_type option; (** return type. None for predicates *) + mutable l_profile : logic_var list; (** type of the arguments. *) + mutable l_body : logic_body; (** body of the function. *) +} + +and builtin_logic_info = { + mutable bl_name: string; + mutable bl_labels: logic_label list; + mutable bl_params: string list; + mutable bl_type: logic_type option; + mutable bl_profile: (string * logic_type) list; +} + +and logic_body = + | LBnone (** no definition and no reads clause *) + | LBreads of identified_term list + (** read accesses performed by a function. *) + | LBterm of term (** direct definition of a function. *) + | LBpred of predicate (** direct definition of a predicate. *) + | LBinductive of + (string * logic_label list * string list * predicate) list + (** inductive definition *) + +(** Description of a logic type. + @plugin development guide *) +and logic_type_info = { + lt_name: string; + lt_params : string list; (** type parameters*) + mutable lt_def: logic_type_def option + (** definition of the type. None for abstract types. *) +} +(* will be expanded when dealing with concrete types *) + +and logic_type_def = + | LTsum of logic_ctor_info list (** sum type with its constructors. *) + | LTsyn of logic_type (** Synonym of another type. *) + +(** origin of a logic variable. *) +and logic_var_kind = + | LVGlobal (** global logic function or predicate. *) + | LVC (** Logic counterpart of a C variable. *) + | LVFormal (** formal parameter of a logic function / predicate + or \lambda abstraction *) + | LVQuant (** Bound by a quantifier (\exists or \forall) *) + | LVLocal (** local \let *) + +(** description of a logic variable +@plugin development guide *) +and logic_var = { + mutable lv_name : string; (** name of the variable. *) + mutable lv_id : int; (** unique identifier *) + mutable lv_type : logic_type; (** type of the variable. *) + mutable lv_kind: logic_var_kind; (** kind of the variable *) + mutable lv_origin : varinfo option +(** when the logic variable stems from a C variable, set to the original C + variable. *) +} + +(** Description of a constructor of a logic sum-type. + @plugin development guide *) +and logic_ctor_info = + { ctor_name: string; (** name of the constructor. *) + ctor_type: logic_type_info; (** type to which the constructor belongs. *) + ctor_params: logic_type list + (** types of the parameters of the constructor. *) + } + +(* ************************************************************************* *) +(** {2 Predicates} *) +(* ************************************************************************* *) + +(** variables bound by a quantifier. *) +and quantifiers = logic_var list + +(** comparison relations*) +and relation = + | Rlt + | Rgt + | Rle + | Rge + | Req + | Rneq (** @plugin development guide *) + + +(** predicates *) +and predicate_node = + | Pfalse (** always-false predicate. *) + | Ptrue (** always-true predicate. *) + | Papp of logic_info * (logic_label * logic_label) list * term list + (** application of a predicate. *) + | Pseparated of term list + | Prel of relation * term * term (** comparison of two terms. *) + | Pand of predicate * predicate (** conjunction *) + | Por of predicate * predicate (** disjunction. *) + | Pxor of predicate * predicate (** logical xor. *) + | Pimplies of predicate * predicate (** implication. *) + | Piff of predicate * predicate (** equivalence. *) + | Pnot of predicate (** negation. *) + | Pif of term * predicate * predicate (** conditional *) + | Plet of logic_info * predicate (** definition of a local variable *) + | Pforall of quantifiers * predicate (** universal quantification. *) + | Pexists of quantifiers * predicate (** existential quantification. *) + | Pat of predicate * logic_label + (** predicate refers to a particular program point. *) + | Pvalid_read of logic_label * term (** the given locations are valid for reading. *) + | Pvalid of logic_label * term (** the given locations are valid. *) + | Pvalid_function of term + (** the pointed function has a type compatible with the one of pointer. *) + | Pinitialized of logic_label * term (** the given locations are initialized. *) + | Pdangling of logic_label * term (** the given locations contain dangling + adresses. *) + | Pallocable of logic_label * term (** the given locations can be allocated. *) + | Pfreeable of logic_label * term (** the given locations can be free. *) + | Pfresh of logic_label * logic_label * term * term + (** \fresh(pointer, n) + A memory block of n bytes is newly allocated to the pointer.*) + | Psubtype of term * term + (** First term is a type tag that is a subtype of the second. *) + +(** predicate with an unique identifier. Use [Logic_const.new_predicate] to + create fresh predicates *) +and identified_predicate = { + ip_id: int; (** identifier *) + ip_content: predicate; (** the predicate itself*) +} + +(** predicates with a location and an optional list of names *) +and predicate = { + pred_name : string list; (** list of given names *) + pred_loc : location; (** position in the source code. *) + pred_content : predicate_node;(** content *) +} + +(* Polymorphic types shared with parsed trees (Logic_ptree) *) +(** variant of a loop or a recursive function. Type shared with Logic_ptree. *) +and 'term variant = 'term * string option + +(** allocates and frees. + @since Oxygen-20120901 *) +and 'locs allocation = + | FreeAlloc of 'locs list * 'locs list (** tsets. Empty list means \nothing. *) + | FreeAllocAny (** Nothing specified. Semantics depends on where it + is written. *) + +(** dependencies of an assigned location. Shared with Logic_ptree. *) +and 'locs deps = + | From of 'locs list (** tsets. Empty list means \nothing. *) + | FromAny (** Nothing specified. Any location can be involved. *) + +and 'locs from = ('locs * 'locs deps) + +(** zone assigned with its dependencies. Type shared with Logic_ptree. *) +and 'locs assigns = + | WritesAny (** Nothing specified. Anything can be written. *) + | Writes of 'locs from list + (** list of locations that can be written. Empty list means \nothing. *) + +(** Function or statement contract. This type shares the name of its + constructors with {!Logic_ptree.spec}. *) +and spec = { + mutable spec_behavior : behavior list; + (** behaviors *) + + mutable spec_variant : term variant option; + (** variant for recursive functions. *) + + mutable spec_terminates: identified_predicate option; + (** termination condition. *) + + mutable spec_complete_behaviors: string list list; + (** list of complete behaviors. + It is possible to have more than one set of complete behaviors *) + + mutable spec_disjoint_behaviors: string list list; + (** list of disjoint behaviors. + It is possible to have more than one set of disjoint behaviors *) +} + + +(** extension to standard ACSL clause. + Each extension is associated to a keyword. An extension + can be registered through the following functions: + - {!Logic_typing.register_behavior_extension} for parsing and type-checking + - {!Cil_printer.register_behavior_extension} for pretty-printing an + extended clause + - {!Cil.register_behavior_extension} for visiting an extended clause + + @plugin development guide *) +and acsl_extension = string * acsl_extension_kind + +and acsl_extension_kind = + | Ext_id of int (** id used internally by the extension itself. *) + | Ext_terms of term list + | Ext_preds of predicate list + (** a list of predicates, the most common case of for extensions *) + +(** Behavior of a function or statement. This type shares the name of its + constructors with {!Logic_ptree.behavior}. + @since Oxygen-20120901 [b_allocation] has been added. + @since Carbon-20101201 [b_requires] has been added. + @modify Boron-20100401 [b_ensures] is replaced by [b_post_cond]. + Old [b_ensures] represent the [Normal] case of [b_post_cond]. *) +and behavior = { + mutable b_name : string; (** name of the behavior. *) + mutable b_requires : identified_predicate list; (** require clauses. *) + mutable b_assumes : identified_predicate list; (** assume clauses. *) + mutable b_post_cond : (termination_kind * identified_predicate) list + (** post-condition. *); + mutable b_assigns : identified_term assigns; (** assignments. *) + mutable b_allocation : identified_term allocation; (** frees, allocates. *) + mutable b_extended : acsl_extension list (** extensions *) +} + +(** kind of termination a post-condition applies to. See ACSL manual. *) +and termination_kind = Normal | Exits | Breaks | Continues | Returns + +(** Pragmas for the value analysis plugin of Frama-C. + Type shared with Logic_ptree.*) +and 'term loop_pragma = + | Unroll_specs of 'term list + | Widen_hints of 'term list + | Widen_variables of 'term list + +(** Pragmas for the slicing plugin of Frama-C. Type shared with Logic_ptree.*) +and 'term slice_pragma = + | SPexpr of 'term + | SPctrl + | SPstmt + +(** Pragmas for the impact plugin of Frama-C. Type shared with Logic_ptree.*) +and 'term impact_pragma = + | IPexpr of 'term + | IPstmt + +(** The various kinds of pragmas. Type shared with Logic_ptree. *) +and 'term pragma = + | Loop_pragma of 'term loop_pragma + | Slice_pragma of 'term slice_pragma + | Impact_pragma of 'term impact_pragma + +(** all annotations that can be found in the code. + This type shares the name of its constructors with + {!Logic_ptree.code_annot}. *) +and code_annotation_node = + | AAssert of string list * predicate + (** assertion to be checked. The list of strings is the list of + behaviors to which this assertion applies. *) + + | AStmtSpec of string list * spec + (** statement contract + (potentially restricted to some enclosing behaviors). *) + + | AInvariant of string list * bool * predicate + (** loop/code invariant. The list of strings is the list of behaviors to which + this invariant applies. The boolean flag is true for normal loop + invariants and false for invariant-as-assertions. *) + + | AVariant of term variant + (** loop variant. Note that there can be at most one variant associated to a + given statement *) + + | AAssigns of string list * identified_term assigns + (** loop assigns. (see [b_assigns] in the behaviors for other assigns). At + most one clause associated to a given (statement, behavior) couple. *) + + | AAllocation of string list * identified_term allocation + (** loop allocation clause. (see [b_allocation] in the behaviors for other + allocation clauses). + At most one clause associated to a given (statement, behavior) couple. + @since Oxygen-20120901 when [b_allocation] has been added. *) + + | APragma of term pragma (** pragma. *) + | AExtended of string list * acsl_extension + (** extension in a loop annotation. + @since Silicon-20161101 *) + +(** function contract. *) + +and funspec = spec + +(** code annotation with an unique identifier. + Use [Logic_const.new_code_annotation] to create new code annotations with + a fresh id. *) +and code_annotation = { + annot_id: int; (** identifier. *) + annot_content : code_annotation_node; (** content of the annotation. *) +} + +(** behavior of a function. *) +and funbehavior = behavior + +(** global annotations, not attached to a statement or a function. *) +and global_annotation = + | Dfun_or_pred of logic_info * location + | Dvolatile of + identified_term list * varinfo option * varinfo option * location + (** associated terms, reading function, writing function *) + | Daxiomatic of string * global_annotation list * location + | Dtype of logic_type_info * location (** declaration of a logic type. *) + | Dlemma of + string * bool * logic_label list * string list * + predicate * location + (** definition of a lemma. The boolean flag is [true] if the property should + be taken as an axiom and [false] if it must be proved. *) + | Dinvariant of logic_info * location + (** global invariant. The predicate does not have any argument. *) + | Dtype_annot of logic_info * location + (** type invariant. The predicate has exactly one argument. *) + | Dmodel_annot of model_info * location + (** Model field for a type t, seen as a logic function with one + argument of type t *) + | Dcustom_annot of custom_tree * string* location + (*Custom declaration*) + +and custom_tree = CustomDummy +(* + | CustomType of logic_type + | CustomLexpr of lexpr + | CustomOther of string * (custom_tree list) +*) +[@@deriving visitors { variety = "iter"; irregular = true }, + visitors { variety = "map"; irregular = true }, + visitors { variety = "endo"; irregular = true }, + visitors { variety = "reduce"; irregular = true }, + visitors { variety = "mapreduce"; irregular = true }, + visitors { variety = "fold"; irregular = true; ancestors = ["VisitorsRuntime.map"] }, + visitors { variety = "iter2"; irregular = true }, + visitors { variety = "map2"; irregular = true }, + visitors { variety = "reduce2"; irregular = true }, + visitors { variety = "mapreduce2"; irregular = true }, + visitors { variety = "fold2"; irregular = true; ancestors = ["VisitorsRuntime.map2"] } +] + +(* Provide the missing methods so as to obtain concrete classes. *) +class ['self] iter_ = object (self : 'self) + inherit [_] iter + method visit_'locs env (t : identified_term) = self#visit_identified_term env t + method visit_'term env (t : term) = self#visit_term env t +end +class ['self] map_ = object (self : 'self) + inherit [_] map + method visit_'locs env (t : identified_term) = self#visit_identified_term env t + method visit_'term env (t : term) = self#visit_term env t +end +class ['self] endo_ = object (self : 'self) + inherit [_] endo + method visit_'locs env (t : identified_term) = self#visit_identified_term env t + method visit_'term env (t : term) = self#visit_term env t +end +class ['self] reduce_ = object (self : 'self) + inherit [_] VisitorsRuntime.addition_monoid + inherit [_] reduce + method visit_'locs env (t : identified_term) = self#visit_identified_term env t + method visit_'term env (t : term) = self#visit_term env t +end +class ['self] mapreduce_ = object (self : 'self) + inherit [_] VisitorsRuntime.addition_monoid + inherit [_] mapreduce + method visit_'locs env (t : identified_term) = self#visit_identified_term env t + method visit_'term env (t : term) = self#visit_term env t +end + +type kinstr = + | Kstmt of stmt + | Kglobal + +(** Internal representation of decorated C functions *) +type cil_function = + | Definition of (fundec * location) (** defined function *) + | Declaration of (funspec * varinfo * varinfo list option * location) + (** Declaration(spec,f,args,loc) represents a leaf function [f] with + specification [spec] and arguments [args], at location [loc]. As + with the [TFun] constructor of {!Cil_types.typ}, the arg list is + optional, to distinguish [void f()] ([None]) from + [void f(void)] ([Some []]). *) + +(** Only field [fundec] can be used directly. Use {!Annotations.funspec}, + [Annotations.add_*] and [Annotations.remove_*] to query or modify field + [spec]. *) +type kernel_function = { + mutable fundec : cil_function; + mutable spec : funspec; +} + +(* [VP] TODO: VLocal should be attached to a particular block, not a whole + function. *) +type localisation = + | VGlobal + | VLocal of kernel_function + | VFormal of kernel_function + +type mach = { + sizeof_short: int; (* Size of "short" *) + sizeof_int: int; (* Size of "int" *) + sizeof_long: int ; (* Size of "long" *) + sizeof_longlong: int; (* Size of "long long" *) + sizeof_ptr: int; (* Size of pointers *) + sizeof_float: int; (* Size of "float" *) + sizeof_double: int; (* Size of "double" *) + sizeof_longdouble: int; (* Size of "long double" *) + sizeof_void: int; (* Size of "void" *) + sizeof_fun: int; (* Size of function *) + size_t: string; (* Type of "sizeof(T)" *) + wchar_t: string; (* Type of "wchar_t" *) + ptrdiff_t: string; (* Type of "ptrdiff_t" *) + alignof_short: int; (* Alignment of "short" *) + alignof_int: int; (* Alignment of "int" *) + alignof_long: int; (* Alignment of "long" *) + alignof_longlong: int; (* Alignment of "long long" *) + alignof_ptr: int; (* Alignment of pointers *) + alignof_float: int; (* Alignment of "float" *) + alignof_double: int; (* Alignment of "double" *) + alignof_longdouble: int; (* Alignment of "long double" *) + alignof_str: int; (* Alignment of strings *) + alignof_fun: int; (* Alignment of function *) + char_is_unsigned: bool; (* Whether "char" is unsigned *) + underscore_name: bool; (* If assembly names have leading underscore *) + const_string_literals: bool; (* Whether string literals have const chars *) + little_endian: bool; (* whether the machine is little endian *) + alignof_aligned: int (* Alignment of a type with aligned attribute *); + has__builtin_va_list: bool (* Whether [__builtin_va_list] is a known type *); + __thread_is_keyword: bool (* Whether [__thread] is a keyword *); + compiler: string; (* Compiler being used. Currently recognized names + are 'gcc', 'msvc' and 'generic'. *) + version: string; (* Information on this machdep *) +} diff --git a/test/cil_types.ml.orig b/test/cil_types.ml.orig new file mode 100644 index 0000000..d5558eb --- /dev/null +++ b/test/cil_types.ml.orig @@ -0,0 +1,1775 @@ +(****************************************************************************) +(* *) +(* Copyright (C) 2001-2003 *) +(* George C. Necula *) +(* Scott McPeak *) +(* Wes Weimer *) +(* Ben Liblit *) +(* All rights reserved. *) +(* *) +(* Redistribution and use in source and binary forms, with or without *) +(* modification, are permitted provided that the following conditions *) +(* are met: *) +(* *) +(* 1. Redistributions of source code must retain the above copyright *) +(* notice, this list of conditions and the following disclaimer. *) +(* *) +(* 2. Redistributions in binary form must reproduce the above copyright *) +(* notice, this list of conditions and the following disclaimer in the *) +(* documentation and/or other materials provided with the distribution. *) +(* *) +(* 3. The names of the contributors may not be used to endorse or *) +(* promote products derived from this software without specific prior *) +(* written permission. *) +(* *) +(* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *) +(* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *) +(* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *) +(* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *) +(* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, *) +(* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, *) +(* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; *) +(* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *) +(* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *) +(* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN *) +(* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE *) +(* POSSIBILITY OF SUCH DAMAGE. *) +(* *) +(* File modified by CEA (Commissariat à l'énergie atomique et aux *) +(* énergies alternatives) *) +(* and INRIA (Institut National de Recherche en Informatique *) +(* et Automatique). *) +(****************************************************************************) + +(** The Abstract Syntax of CIL. + @plugin development guide *) + +(**************************** WARNING ***************************************) +(* Remember to reflect any change here into the visitor and pretty-printer *) +(* in cil.ml. In particular, if a type becomes mutable, it is necessary to *) +(* adapt the Cil.behavior type and the copy_behavior accordingly. *) +(* A first test to see if something has been broken by a change is to launch*) +(* ptests.byte -add-options '-files-debug "-check -copy"' *) +(* In addition, it is a good idea to add some invariant checks in the *) +(* check_file class in frama-c/src/file.ml (before lauching the tests) *) +(****************************************************************************) + +(* ************************************************************************* *) +(** {2 Root of the AST} *) +(* ************************************************************************* *) + +(** In Frama-C, the whole AST is accessible through {!Ast.get}. *) + +(** The top-level representation of a CIL source file (and the result of the + parsing and elaboration). Its main contents is the list of global + declarations and definitions. You can iterate over the globals in a + {!Cil_types.file} using the following iterators: {!Cil.mapGlobals}, + {!Cil.iterGlobals} and {!Cil.foldGlobals}. You can also use the + {!Cil.dummyFile} when you need a {!Cil_types.file} as a placeholder. For + each global item CIL stores the source location where it appears (using the + type {!Cil_types.location}) + @plugin development guide *) +type file = { + mutable fileName: string; (** The complete file name *) + + mutable globals: global list; + (** List of globals as they will appear in the printed file *) + + mutable globinit: fundec option; + (** An optional global initializer function. This is a function where you + can put stuff that must be executed before the program is + started. This function, is conceptually at the end of the file, + although it is not part of the globals list. Use {!Cil.getGlobInit} to + create/get one. *) + + mutable globinitcalled: bool; +(** Whether the global initialization function is called in main. This + should always be false if there is no global initializer. When you + create a global initialization CIL will try to insert code in main to + call it. *) +} + +(** The main type for representing global declarations and definitions. A list + of these form a CIL file. The order of globals in the file is generally + important. + @plugin development guide *) +and global = + | GType of typeinfo * location + (** A typedef. All uses of type names (through the [TNamed] constructor) + must be preceeded in the file by a definition of the name. The string + is the defined name and always not-empty. *) + + | GCompTag of compinfo * location + (** Defines a struct/union tag with some fields. There must be one of + these for each struct/union tag that you use (through the [TComp] + constructor) since this is the only context in which the fields are + printed. Consequently nested structure tag definitions must be + broken into individual definitions with the innermost structure + defined first. *) + + | GCompTagDecl of compinfo * location + (** Declares a struct/union tag. Use as a forward declaration. This is + printed without the fields. *) + + | GEnumTag of enuminfo * location + (** Declares an enumeration tag with some fields. There must be one of + these for each enumeration tag that you use (through the [TEnum] + constructor) since this is the only context in which the items are + printed. *) + + | GEnumTagDecl of enuminfo * location + (** Declares an enumeration tag. Use as a forward declaration. This is + printed without the items. *) + + | GVarDecl of varinfo * location + (** A variable declaration (not a definition) for a variable with object + type. There can be several declarations and at most one definition for + a given variable. If both forms appear then they must share the same + varinfo structure. Either has storage Extern or there must be a + definition in this file *) + + | GFunDecl of funspec * varinfo * location + (** A variable declaration (not a definition) for a function, i.e. a + prototype. There can be several declarations and at most one definition + for a given function. If both forms appear then they must share the same + varinfo structure. A prototype shares the varinfo with the fundec of the + definition. Either has storage Extern or there must be a definition in + this file. *) + + | GVar of varinfo * initinfo * location + (** A variable definition. Can have an initializer. The initializer is + updateable so that you can change it without requiring to recreate the + list of globals. There can be at most one definition for a variable in an + entire program. Cannot have storage Extern or function type. *) + + | GFun of fundec * location + (** A function definition. *) + + | GAsm of string * location + (** Global asm statement. These ones can contain only a template *) + + | GPragma of attribute * location + (** Pragmas at top level. Use the same syntax as attributes *) + + | GText of string + (** Some text (printed verbatim) at top level. E.g., this way you can put + comments in the output. *) + + | GAnnot of global_annotation * location +(** a global annotation. Can be + - an axiom or a lemma + - a predicate declaration or definition + - a global type invariant + - a global invariant + - a logic function declaration or definition. *) + +(* ************************************************************************* *) +(** {2 Types} *) +(* ************************************************************************* *) + +(** A C type is represented in CIL using the type {!Cil_types.typ}. Among types + we differentiate the integral types (with different kinds denoting the sign + and precision), floating point types, enumeration types, array and pointer + types, and function types. Every type is associated with a list of + attributes, which are always kept in sorted order. Use {!Cil.addAttribute} + and {!Cil.addAttributes} to construct list of attributes. If you want to + inspect a type, you should use {!Cil.unrollType} or {!Cil.unrollTypeDeep} to + see through the uses of named types. + + CIL is configured at build-time with the sizes and alignments of the + underlying compiler (GCC or MSVC). CIL contains functions that can compute + the size of a type (in bits) {!Cil.bitsSizeOf}, the alignment of a type (in + bytes) {!Cil.alignOf_int}, and can convert an offset into a start and width + (both in bits) using the function {!Cil.bitsOffset}. At the moment these + functions do not take into account the [packed] attributes and pragmas. *) + +and typ = + | TVoid of attributes (** Void type. Also predefined as {!Cil.voidType} *) + + | TInt of ikind * attributes + (** An integer type. The kind specifies the sign and width. Several useful + variants are predefined as {!Cil.intType}, {!Cil.uintType}, + {!Cil.longType}, {!Cil.charType}. *) + + | TFloat of fkind * attributes + (** A floating-point type. The kind specifies the precision. You can also use + the predefined constant {!Cil.doubleType}. *) + + | TPtr of typ * attributes + (** Pointer type. Several useful variants are predefined as + {!Cil.charPtrType}, {!Cil.charConstPtrType} (pointer to a constant + character), {!Cil.voidPtrType}, {!Cil.intPtrType} *) + + | TArray of typ * exp option * bitsSizeofTypCache * attributes + (** Array type. It indicates the base type and the array length. *) + + | TFun of typ * (string * typ * attributes) list option * bool * attributes + (** Function type. Indicates the type of the result, the name, type + and name attributes of the formal arguments ([None] if no arguments + were specified, as in a function whose definition or prototype we + have not seen; [Some \[\]] means void). Use {!Cil.argsToList} to + obtain a list of arguments. The boolean indicates if it is a + variable-argument function. If this is the type of a varinfo for + which we have a function declaration then the information for the + formals must match that in the function's sformals. Use + {!Cil.setFormals}, or {!Cil.setFunctionType}, or + {!Cil.makeFormalVar} for this purpose. *) + + | TNamed of typeinfo * attributes + (** The use of a named type. All uses of the same type name must share the + typeinfo. Each such type name must be preceeded in the file by a [GType] + global. This is printed as just the type name. The actual referred type + is not printed here and is carried only to simplify processing. To see + through a sequence of named type references, use {!Cil.unrollType}. The + attributes are in addition to those given when the type name was + defined. *) + + | TComp of compinfo * bitsSizeofTypCache * attributes + (** A reference to a struct or a union type. All references to the + same struct or union must share the same compinfo among them and + with a [GCompTag] global that preceeds all uses (except maybe + those that are pointers to the composite type). The attributes + given are those pertaining to this use of the type and are in + addition to the attributes that were given at the definition of + the type and which are stored in the compinfo. *) + + | TEnum of enuminfo * attributes + (** A reference to an enumeration type. All such references must + share the enuminfo among them and with a [GEnumTag] global that + preceeds all uses. The attributes refer to this use of the + enumeration and are in addition to the attributes of the + enumeration itself, which are stored inside the enuminfo *) + + | TBuiltin_va_list of attributes +(** This is the same as the gcc's type with the same name *) + +(** Various kinds of integers *) +and ikind = + IBool (** [_Bool] *) + | IChar (** [char] *) + | ISChar (** [signed char] *) + | IUChar (** [unsigned char] *) + | IInt (** [int] *) + | IUInt (** [unsigned int] *) + | IShort (** [short] *) + | IUShort (** [unsigned short] *) + | ILong (** [long] *) + | IULong (** [unsigned long] *) + | ILongLong (** [long long] (or [_int64] on Microsoft Visual C) *) + | IULongLong (** [unsigned long long] (or [unsigned _int64] on Microsoft + Visual C) *) + +(** Various kinds of floating-point numbers*) +and fkind = + FFloat (** [float] *) + | FDouble (** [double] *) + | FLongDouble (** [long double] *) + +(** This is used to cache the computation of the size of types in bits. *) +and bitsSizeofTyp = + | Not_Computed + | Computed of int + | Not_Computable of (string * typ) (** Explanation of the error *) + +and bitsSizeofTypCache = { mutable scache : bitsSizeofTyp} + +(* ************************************************************************* *) +(** {2 Attributes} *) +(* ************************************************************************* *) + +and attribute = + | Attr of string * attrparam list + (** An attribute has a name and some optional parameters. The name should not + start or end with underscore. When CIL parses attribute names it will + strip leading and ending underscores (to ensure that the multitude of GCC + attributes such as const, __const and __const__ all mean the same + thing.) *) + + | AttrAnnot of string + +(** Attributes are lists sorted by the attribute name. Use the functions + {!Cil.addAttribute} and {!Cil.addAttributes} to insert attributes in an + attribute list and maintain the sortedness. *) +and attributes = attribute list + +(** The type of parameters of attributes *) +and attrparam = + | AInt of Integer.t (** An integer constant *) + | AStr of string (** A string constant *) + | ACons of string * attrparam list + (** Constructed attributes. These are printed [foo(a1,a2,...,an)]. The list + of parameters can be empty and in that case the parentheses are not + printed. *) + | ASizeOf of typ (** A way to talk about types *) + | ASizeOfE of attrparam + | AAlignOf of typ + | AAlignOfE of attrparam + | AUnOp of unop * attrparam + | ABinOp of binop * attrparam * attrparam + | ADot of attrparam * string (** a.foo **) + | AStar of attrparam (** * a *) + | AAddrOf of attrparam (** & a **) + | AIndex of attrparam * attrparam (** a1[a2] *) + | AQuestion of attrparam * attrparam * attrparam (** a1 ? a2 : a3 **) + +(* ************************************************************************* *) +(** {2 Structures} *) +(* ************************************************************************* *) + +(** The {!Cil_types.compinfo} describes the definition of a structure or union + type. Each such {!Cil_types.compinfo} must be defined at the top-level using + the [GCompTag] constructor and must be shared by all references to this type + (using either the [TComp] type constructor or from the definition of the + fields. + + If all you need is to scan the definition of each composite type once, you + can do that by scanning all top-level [GCompTag]. + + Constructing a {!Cil_types.compinfo} can be tricky since it must contain + fields that might refer to the host {!Cil_types.compinfo} and furthermore + the type of the field might need to refer to the {!Cil_types.compinfo} for + recursive types. Use the {!Cil.mkCompInfo} function to create a + {!Cil_types.compinfo}. You can easily fetch the {!Cil_types.fieldinfo} for a + given field in a structure with {!Cil.getCompField}. *) + +(** The definition of a structure or union type. Use {!Cil.mkCompInfo} to make + one and use {!Cil.copyCompInfo} to copy one (this ensures that a new key is + assigned and that the fields have the right pointers to parents.). + @plugin development guide *) +and compinfo = { + mutable cstruct: bool; + (** [true] if struct, [false] if union *) + + corig_name: string; + (** Original name as found in C file. Will never be changed *) + + mutable cname: string; + (** The name. Always non-empty. Use {!Cil.compFullName} to get the full name + of a comp (along with the struct or union) *) + + mutable ckey: int; + (** A unique integer. This is assigned by {!Cil.mkCompInfo} using a global + variable in the Cil module. Thus two identical structs in two different + files might have different keys. Use {!Cil.copyCompInfo} to copy + structures so that a new key is assigned. *) + + mutable cfields: fieldinfo list; + (** Information about the fields. Notice that each fieldinfo has a pointer + back to the host compinfo. This means that you should not share + fieldinfo's between two compinfo's *) + + mutable cattr: attributes; + (** The attributes that are defined at the same time as the composite + type. These attributes can be supplemented individually at each + reference to this [compinfo] using the [TComp] type constructor. *) + + mutable cdefined: bool; + (** This boolean flag can be used to distinguish between structures + that have not been defined and those that have been defined but have + no fields (such things are allowed in gcc). *) + + mutable creferenced: bool; +(** [true] if used. Initially set to [false]. *) +} + +(* ************************************************************************* *) +(** {2 Structure fields} *) +(* ************************************************************************* *) + +(** The {!Cil_types.fieldinfo} structure is used to describe a structure or + union field. Fields, just like variables, can have attributes associated + with the field itself or associated with the type of the field (stored along + with the type of the field). *) + +(** Information about a struct/union field. + @plugin development guide *) +and fieldinfo = { + mutable fcomp: compinfo; + (** The host structure that contains this field. There can be only one + [compinfo] that contains the field. *) + + forig_name: string; + (** original name as found in C file. *) + + mutable fname: string; + (** The name of the field. Might be the value of {!Cil.missingFieldName} in + which case it must be a bitfield and is not printed and it does not + participate in initialization *) + + mutable ftype: typ; + (** The type. If the field is a bitfield, a special attribute + [FRAMA_C_BITFIELD_SIZE] indicating the width of the bitfield is added. *) + + mutable fbitfield: int option; + (** If a bitfield then ftype should be an integer type and the width of the + bitfield must be 0 or a positive integer smaller or equal to the width of + the integer type. A field of width 0 is used in C to control the alignment + of fields. *) + + mutable fattr: attributes; + (** The attributes for this field (not for its type) *) + + mutable floc: location; + (** The location where this field is defined *) + + mutable faddrof: bool; + (** Adapted from CIL [vaddrof] field for variables. Only set for non-array + fields. Variable whose field address is taken is not marked anymore as + having its own address taken. True if the address of this field is + taken. CIL will set these flags when it parses C, but you should make + sure to set the flag whenever your transformation create [AddrOf] + expression. *) + + mutable fsize_in_bits: int option; + (** (Deprecated. Use {!Cil.bitsOffset} instead.) Similar to [fbitfield] for + all types of fields. + @deprecated only Jessie uses this *) + + mutable foffset_in_bits: int option; + (** Offset at which the field starts in the structure. Do not read directly, + but use {!Cil.bitsOffset} instead. *) + + mutable fpadding_in_bits: int option; +(** (Deprecated.) Store the size of the padding that follows the field, if any. + @deprecated only Jessie uses this *) +} + +(* ************************************************************************* *) +(** {2 Enumerations} *) +(* ************************************************************************* *) + +(** Information about an enumeration. This is shared by all references to an + enumeration. Make sure you have a [GEnumTag] for each of these. *) + +(** Information about an enumeration. + @plugin development guide *) +and enuminfo = { + eorig_name: string; (** original name as found in C file. *) + + mutable ename: string; (** The name. Always non-empty. *) + + mutable eitems: enumitem list; (** Items. The list must be non-empty *) + + mutable eattr: attributes; + (** The attributes that are defined at the same time as the enumeration + type. These attributes can be supplemented individually at each + reference to this [enuminfo] using the [TEnum] type constructor. *) + + mutable ereferenced: bool; (** [true] if used. Initially set to [false]. *) + mutable ekind: ikind (** The integer kind used to represent this enum. MSVC + always assumes IInt but this is not the case + for gcc. See ISO C 6.7.2.2 *) +} + +and enumitem = { + eiorig_name: string; (** original name as found in C file. *) + mutable einame: string; (** the name, always non-empty. *) + mutable eival: exp; (** value of the item. Must be a compile-time constant *) + mutable eihost: enuminfo; (** the host enumeration in which the item is + declared. *) + eiloc: location; +} + +(** Information about a defined type. + @plugin development guide *) +and typeinfo = { + torig_name: string; (** original name as found in C file. *) + + mutable tname: string; + (** The name. Can be empty only in a [GType] when introducing a composite or + enumeration tag. If empty cannot be refered to from the file *) + + mutable ttype: typ; + (** The actual type. This includes the attributes that were present in the + typedef *) + + mutable treferenced: bool; (** [true] if used. Initially set to [false]. *) +} + +(* ************************************************************************* *) +(** {2 Variables} *) +(* ************************************************************************* *) + +(** Each local or global variable is represented by a unique + {!Cil_types.varinfo} structure. A global {!Cil_types.varinfo} can be + introduced with the [GVarDecl] or [GVar], [GFunDecl] or [GFun] globals. + A local varinfo can be introduced as part of a function definition + {!Cil_types.fundec}. + + All references to a given global or local variable must refer to the same + copy of the [varinfo]. Each [varinfo] has a globally unique identifier that + can be used to index maps and hashtables (the name can also be used for this + purpose, except for locals from different functions). This identifier is + constructor using a global counter. + + It is very important that you construct [varinfo] structures using only one + of the following functions: + - {!Cil.makeGlobalVar} : to make a global variable + - {!Cil.makeTempVar} : to make a temporary local variable whose name + will be generated so that to avoid conflict with other locals. + - {!Cil.makeLocalVar} : like {!Cil.makeTempVar} but you can specify the + exact name to be used. + - {!Cil.copyVarinfo}: make a shallow copy of a varinfo assigning a new name + and a new unique identifier + + A [varinfo] is also used in a function type to denote the list of + formals. *) + +(** Information about a variable. + @plugin development guide *) +and varinfo = { + mutable vname: string; + (** The name of the variable. Cannot be empty. It is primarily your + responsibility to ensure the uniqueness of a variable name. For local + variables {!Cil.makeTempVar} helps you ensure that the name is + unique. *) + + vorig_name: string; + (** the original name of the variable. Need not be unique. *) + + mutable vtype: typ; + (** The declared type of the variable. *) + + mutable vattr: attributes; + (** A list of attributes associated with the variable.*) + + mutable vstorage: storage; + (** The storage-class *) + + mutable vglob: bool; + (** True if this is a global variable*) + + mutable vdefined: bool; + (** True if the variable or function is defined in the file. Only relevant + for functions and global variables. Not used in particular for local + variables and logic variables. *) + + mutable vformal: bool; + (** True if the variable is a formal parameter of a function. *) + + mutable vinline: bool; + (** Whether this varinfo is for an inline function. *) + + mutable vdecl: location; + (** Location of variable declaration. *) + + mutable vid: int; + (** A unique integer identifier. This field will be set for you if you use + one of the {!Cil.makeFormalVar}, {!Cil.makeLocalVar}, + {!Cil.makeTempVar}, {!Cil.makeGlobalVar}, or {!Cil.copyVarinfo}. *) + + mutable vaddrof: bool; + (** [true] if the address of this variable is taken. CIL will set these + flags when it parses C, but you should make sure to set the flag + whenever your transformation create [AddrOf] expression. *) + + mutable vreferenced: bool; + (** [true] if this variable is ever referenced. This is computed by + [removeUnusedVars]. It is safe to just initialize this to [false]. *) + + vtemp: bool; + (** [true] for temporary variables generated by CIL normalization. [false] + for all the other variables. *) + + mutable vdescr: string option; + (** For most temporary variables, a description of what the var holds. + (e.g. for temporaries used for function call results, this string is a + representation of the function call.) *) + + mutable vdescrpure: bool; + (** Indicates whether the vdescr above is a pure expression or call. True + for all CIL expressions and Lvals, but false for e.g. function calls. + Printing a non-pure vdescr more than once may yield incorrect + results. *) + + mutable vghost: bool; + (** Indicates if the variable is declared in ghost code *) + + vsource: bool; + (** [true] iff this variable appears in the source of the program, which is + the case of all the variables in the initial AST. Plugins may create + variables with [vsource=false], for example to handle dynamic allocation. + Those variables do *not* have an associated {!GVar} or {!GVarDecl}. *) + + mutable vlogic_var_assoc: logic_var option + (** Logic variable representing this variable in the logic world. Do not + access this field directly. Instead, call {!Cil.cvar_to_lvar}. *) +} + +(** Storage-class information *) +and storage = + NoStorage (** The default storage. Nothing is printed *) + | Static + | Register + | Extern + +(* ************************************************************************* *) +(** {2 Expressions} *) +(* ************************************************************************* *) + +(** The CIL expression language contains only the side-effect free expressions + of C. They are represented as the type {!Cil_types.exp}. There are several + interesting aspects of CIL expressions: + + Integer and floating point constants can carry their textual representation. + This way the integer 15 can be printed as 0xF if that is how it occurred in + the source. + + CIL uses arbitrary precision integers + to represent the integer constants and also stores the + width of the integer type. Care must be taken to ensure that the constant is + representable with the given width. Use the functions {!Cil.kinteger}, + {!Cil.kinteger64} and {!Cil.integer} to construct constant expressions. CIL + predefines the constants {!Cil.zero}, {!Cil.one} and {!Cil.mone} (for -1). + + Use the functions {!Cil.isConstant} and {!Cil.isInteger} to test if an + expression is a constant and a constant integer respectively. + + CIL keeps the type of all unary and binary expressions. You can think of + that type qualifying the operator. Furthermore there are different operators + for arithmetic and comparisons on arithmetic types and on pointers. + + Another unusual aspect of CIL is that the implicit conversion between an + expression of array type and one of pointer type is made explicit, using the + [StartOf] expression constructor (which is not printed). If you apply the + [AddrOf]constructor to an lvalue of type [T] then you will be getting an + expression of type [TPtr(T)]. + + You can find the type of an expression with {!Cil.typeOf}. + + You can perform constant folding on expressions using the function + {!Cil.constFold}. *) + +(** Expressions (Side-effect free)*) +and exp = { + eid: int; (** unique identifier *) + enode: exp_node; (** the expression itself *) + eloc: location; (** location of the expression. *) +} + +and exp_node = + | Const of constant (** Constant *) + | Lval of lval (** Lvalue *) + | SizeOf of typ + (** sizeof(). Has [unsigned int] type (ISO 6.5.3.4). This is not + turned into a constant because some transformations might want to change + types *) + + | SizeOfE of exp (** sizeof() *) + + | SizeOfStr of string + (** sizeof(string_literal). We separate this case out because this is the + only instance in which a string literal should not be treated as having + type pointer to character. *) + + | AlignOf of typ + (** This corresponds to the GCC __alignof_. Has [unsigned int] type *) + + | AlignOfE of exp + + | UnOp of unop * exp * typ + (** Unary operation. Includes the type of the result. *) + + | BinOp of binop * exp * exp * typ + (** Binary operation. Includes the type of the result. The arithmetic + conversions are made explicit for the arguments. + @plugin development guide *) + + | CastE of typ * exp + (** Use {!Cil.mkCast} to make casts. *) + + | AddrOf of lval + (** Always use {!Cil.mkAddrOf} to construct one of these. Apply to an lvalue + of type [T] yields an expression of type [TPtr(T)] *) + + | StartOf of lval + (** Conversion from an array to a pointer to the beginning of the array. + Given an lval of type [TArray(T)] produces an expression of type + [TPtr(T)]. In C this operation is implicit, the [StartOf] operator is not + printed. We have it in CIL because it makes the typing rules simpler. *) + + | Info of exp * exp_info +(** Additional information on the underlying expression *) + +(** Additional information on an expression *) +and exp_info = { + exp_type : logic_type; (** when used as placeholder for a term *) + exp_name: string list; +} + +(* ************************************************************************* *) +(** {2 Constants} *) +(* ************************************************************************* *) + +(** Literal constants *) +and constant = + | CInt64 of Integer.t * ikind * string option + (** Integer constant. Give the ikind (see ISO9899 6.1.3.2) and the + textual representation. Textual representation is always set to Some s + when it comes from user code. This allows us to print a + constant as it was represented in the code, for example, + 0xF instead of 15. It is usually None for constant generated by Cil + itself. Use {!Cil.integer} or {!Cil.kinteger} to create these. *) + + | CStr of string + (** String constant. The escape characters inside the string have been already + interpreted. This constant has pointer to character type! The only case + when you would like a string literal to have an array type is when it is + an argument to sizeof. In that case you should use SizeOfStr. *) + + | CWStr of int64 list + (** Wide character string constant. Note that the local interpretation of such + a literal depends on {!Cil.theMachine.wcharType} and + {!Cil.theMachine.wcharKind}. Such a constant has type pointer to + {!Cil.theMachine.wcharType}. The escape characters in the string have not + been "interpreted" in the sense that L"A\xabcd" remains "A\xabcd" rather + than being represented as the wide character list with two elements: 65 + and 43981. That "interpretation" depends on the underlying wide character + type. *) + + | CChr of char + (** Character constant. This has type int, so use charConstToInt to read the + value in case sign-extension is needed. *) + + | CReal of float * fkind * string option + (** Floating point constant. Give the fkind (see ISO 6.4.4.2) and also the + textual representation, if available. *) + + | CEnum of enumitem +(** An enumeration constant. Use [Cillower.lowerEnumVisitor] to replace these + with integer constants. *) + +(** Unary operators *) +and unop = + Neg (** Unary minus *) + | BNot (** Bitwise complement (~) *) + | LNot (** Logical Not (!) *) + +(** Binary operations *) +and binop = + PlusA (** arithmetic + *) + | PlusPI (** pointer + integer *) + | IndexPI (** pointer + integer but only when it arises from an expression + [e\[i\]] when [e] is a pointer and + not an array. This is semantically + the same as PlusPI but CCured uses + this as a hint that the integer is + probably positive. *) + | MinusA (** arithmetic - *) + | MinusPI (** pointer - integer *) + | MinusPP (** pointer - pointer *) + | Mult (** * *) + | Div (** / + @plugin development guide *) + | Mod (** % + @plugin development guide *) + | Shiftlt (** shift left *) + | Shiftrt (** shift right *) + + | Lt (** < (arithmetic comparison) *) + | Gt (** > (arithmetic comparison) *) + | Le (** <= (arithmetic comparison) *) + | Ge (** >= (arithmetic comparison) *) + | Eq (** == (arithmetic comparison) *) + | Ne (** != (arithmetic comparison) *) + | BAnd (** bitwise and *) + | BXor (** exclusive-or *) + | BOr (** inclusive-or *) + + | LAnd (** logical and. Unlike other expressions this one does not always + evaluate both operands. If you want + to use these, you must set + {!Cil.useLogicalOperators}. *) + | LOr (** logical or. Unlike other expressions this one does not always + evaluate both operands. If you + want to use these, you must set + {!Cil.useLogicalOperators}. *) + +(* ************************************************************************* *) +(** {2 Left values} *) +(* ************************************************************************* *) + +(** Left values (aka Lvalues) are the sublanguage of expressions that can appear + at the left of an assignment or as operand to the address-of operator. In C + the syntax for lvalues is not always a good indication of the meaning of the + lvalue. For example the C value {v a[0][1][2] v} might involve 1, 2 or 3 + memory reads when used in an expression context, depending on the declared + type of the variable [a]. If [a] has type [int \[4\]\[4\]\[4\]] then we have + one memory read from somewhere inside the area that stores the array [a]. On + the other hand if [a] has type [int ***] then the expression really means [* + ( * ( * (a + 0) + 1) + 2)], in which case it is clear that it involves three + separate memory operations. + + An lvalue denotes the contents of a range of memory addresses. This range is + denoted as a host object along with an offset within the object. The host + object can be of two kinds: a local or global variable, or an object whose + address is in a pointer expression. We distinguish the two cases so that we + can tell quickly whether we are accessing some component of a variable + directly or we are accessing a memory location through a pointer. To make + it easy to tell what an lvalue means CIL represents lvalues as a host object + and an offset (see {!Cil_types.lval}). The host object (represented as + {!Cil_types.lhost}) can be a local or global variable or can be the object + pointed-to by a pointer expression. The offset (represented as + {!Cil_types.offset}) is a sequence of field or array index designators. + + Both the typing rules and the meaning of an lvalue is very precisely + specified in CIL. + + The following are a few useful function for operating on lvalues: + - {!Cil.mkMem} - makes an lvalue of [Mem] kind. Use this to ensure + that certain equivalent forms of lvalues are canonized. + For example, [*&x = x]. + - {!Cil.typeOfLval} - the type of an lvalue + - {!Cil.typeOffset} - the type of an offset, given the type of the + host. + - {!Cil.addOffset} and {!Cil.addOffsetLval} - extend sequences + of offsets. + - {!Cil.removeOffset} and {!Cil.removeOffsetLval} - shrink sequences + of offsets. + + The following equivalences hold {v + Mem(AddrOf(Mem a, aoff)), off = Mem a, aoff + off + Mem(AddrOf(Var v, aoff)), off = Var v, aoff + off + AddrOf (Mem a, NoOffset) = a + v} *) + +and lval = lhost * offset + +(** The host part of an {!Cil_types.lval}. *) +and lhost = + | Var of varinfo + (** The host is a variable. *) + + | Mem of exp +(** The host is an object of type [T] when the expression has pointer + [TPtr(T)]. *) + + +(** The offset part of an {!Cil_types.lval}. Each offset can be applied to + certain kinds of lvalues and its effect is that it advances the starting + address of the lvalue and changes the denoted type, essentially focussing + to some smaller lvalue that is contained in the original one. + @plugin development guide *) +and offset = + | NoOffset + (** No offset. Can be applied to any lvalue and does not change either the + starting address or the type. This is used when the lval consists of just + a host or as a terminator in a list of other kinds of offsets. *) + + | Field of fieldinfo * offset + (** A field offset. Can be applied only to an lvalue that denotes a structure + or a union that contains the mentioned field. This advances the offset to + the beginning of the mentioned field and changes the type to the type of + the mentioned field. *) + + | Index of exp * offset +(** An array index offset. Can be applied only to an lvalue that denotes an + array. This advances the starting address of the lval to the beginning of + the mentioned array element and changes the denoted type to be the type of + the array element *) + +(* ************************************************************************* *) +(** {2 Initializers} *) +(* ************************************************************************* *) + +(** A special kind of expressions are those that can appear as initializers for + global variables (initialization of local variables is turned into + assignments). The initializers are represented as type + {!Cil_types.init}. You can create initializers with {!Cil.makeZeroInit} and + you can conveniently scan compound initializers them with + {!Cil.foldLeftCompound}. *) + +(** Initializers for global variables. *) +and init = + | SingleInit of exp (** A single initializer *) + | CompoundInit of typ * (offset * init) list +(** Used only for initializers of structures, unions and arrays. The offsets + are all of the form [Field(f, NoOffset)] or [Index(i, NoOffset)] and + specify the field or the index being initialized. For structures all fields + must have an initializer (except the unnamed bitfields), in the proper + order. This is necessary since the offsets are not printed. For arrays the + list must contain a prefix of the initializers; the rest are 0-initialized. + For unions there must be exactly one initializer. If the initializer is not + for the first field then a field designator is printed, so you better be on + GCC since MSVC does not understand this. You can scan an initializer list + with {!Cil.foldLeftCompound}. *) + +(** We want to be able to update an initializer in a global variable, so we + define it as a mutable field *) +and initinfo = { mutable init : init option } + +(* ************************************************************************* *) +(** {2 Function definitions} *) +(* ************************************************************************* *) + +(** A function definition is always introduced with a [GFun] constructor at the + top level. All the information about the function is stored into a + {!Cil_types.fundec}. Some of the information (e.g. its name, type, storage, + attributes) is stored as a {!Cil_types.varinfo} that is a field of the + [fundec]. To refer to the function from the expression language you must use + the [varinfo]. + + The function definition contains, in addition to the body, a list of all the + local variables and separately a list of the formals. Both kind of variables + can be referred to in the body of the function. The formals must also be + shared with the formals that appear in the function type. For that reason, + to manipulate formals you should use the provided functions + {!Cil.makeFormalVar} and {!Cil.setFormals}. *) + +(** Function definitions. + @plugin development guide *) +and fundec = { + mutable svar: varinfo; + (** Holds the name and type as a variable, so we can refer to it easily + from the program. All references to this function either in a function + call or in a prototype must point to the same [varinfo]. *) + + mutable sformals: varinfo list; + (** Formals. These must be in the same order and with the same information + as the formal information in the type of the function. Use + {!Cil.setFormals} or {!Cil.setFunctionType} to set these formals and + ensure that they are reflected in the function type. Do not make + copies of these because the body refers to them. *) + + mutable slocals: varinfo list; + (** Locals. Does NOT include the sformals. Do not make copies of these + because the body refers to them. *) + + mutable smaxid: int; + (** Max local id. Starts at 0. Used for creating the names of new + temporary variables. Updated by {!Cil.makeLocalVar} and + {!Cil.makeTempVar}. You can also use {!Cil.setMaxId} to set it after + you have added the formals and locals. *) + + mutable sbody: block; (** The function body. *) + + mutable smaxstmtid: int option; + (** max id of a (reachable) statement in this function, if we have + computed it. range = 0 ... (smaxstmtid-1). This is computed by + {!Cfg.computeCFGInfo}. *) + + mutable sallstmts: stmt list; + (** After you call {!Cfg.computeCFGInfo} this field is set to contain all + statements in the function. *) + + mutable sspec: funspec; +} + +(** A block is a sequence of statements with the control falling through from + one element to the next *) +and block = { + mutable battrs: attributes; (** Attributes for the block *) + + mutable blocals: varinfo list; + (** variables that are local to the block. It is a subset of the slocals of + the enclosing function. *) + + mutable bstmts: stmt list; (** The statements comprising the block. *) +} + +(* ************************************************************************* *) +(** {2 Statements} *) +(* ************************************************************************* *) + +(** CIL statements are the structural elements that make the CFG. They are + represented using the type {!Cil_types.stmt}. Every statement has a + (possibly empty) list of labels. The {!Cil_types.stmtkind} field of a + statement indicates what kind of statement it is. + + Use {!Cil.mkStmt} to make a statement and the fill-in the fields. + + CIL also comes with support for control-flow graphs. The [sid] field in + [stmt] can be used to give unique numbers to statements, and the [succs] and + [preds] fields can be used to maintain a list of successors and predecessors + for every statement. The CFG information is not computed by default. Instead + you must explicitly use the functions {!Cfg.prepareCFG} and + {!Cfg.computeCFGInfo} to do it. *) + +(** Statements. + @plugin development guide *) +and stmt = { + mutable labels: label list; + (** Whether the statement starts with some labels, case statements or + default statements. *) + + mutable skind: stmtkind; + (** The kind of statement *) + + mutable sid: int; + (** A number (>= 0) that is unique in a function. Filled in only after the + CFG is computed. *) + + mutable succs: stmt list; + (** The successor statements. They can always be computed from the skind and + the context in which this statement appears. Filled in only after the CFG + is computed. *) + + mutable preds: stmt list; + (** The inverse of the succs function. *) + + mutable ghost : bool +} + +(** Labels *) +and label = + | Label of string * location * bool + (** A real label. If the bool is "true", the label is from the input source + program. If the bool is "false", the label was created by CIL or some + other transformation *) + + | Case of exp * location + (** A case statement. This expression is lowered into a constant if + {!Cil.lowerConstants} is set to [true]. *) + + | Default of location (** A default statement *) + +(* The various kinds of statements *) +and stmtkind = + | Instr of instr + (** An instruction that does not contain control flow. Control implicitly + falls through. + @plugin development guide *) + + | Return of exp option * location + (** The return statement. This is a leaf in the CFG. + @plugin development guide *) + + | Goto of stmt ref * location + (** A goto statement. Appears from actual goto's in the code or from goto's + that have been inserted during elaboration. The reference points to the + statement that is the target of the Goto. This means that you have to + update the reference whenever you replace the target statement. The + target statement MUST have at least a label. + @plugin development guide *) + + | Break of location + (** A break to the end of the nearest enclosing Loop or Switch. + @plugin development guide *) + + | Continue of location + (** A continue to the start of the nearest enclosing [Loop]. + @plugin development guide *) + + | If of exp * block * block * location + (** A conditional. Two successors, the "then" and the "else" branches (in + this order). + Both branches fall-through to the successor of the If statement. + @plugin development guide *) + + | Switch of exp * block * (stmt list) * location + (** A switch statement. [exp] is the index of the switch. [block] is + the body of the switch. [stmt list] contains the set of + statements whose [labels] are cases of the switch (i.e. for each + case, the corresponding statement is in [stmt list], a statement + cannot appear more than once in the list, and statements in + [stmt list] can have several labels corresponding to several + cases. + @plugin development guide *) + + | Loop of + code_annotation list * block * location * (stmt option) * (stmt option) + (** A [while(1)] loop. The termination test is implemented in the body of a + loop using a [Break] statement. If {!Cfg.prepareCFG} has been called, the + first stmt option will point to the stmt containing the continue label + for this loop and the second will point to the stmt containing the break + label for this loop. + @plugin development guide *) + + | Block of block + (** Just a block of statements. Use it as a way to keep some block attributes + local. + @plugin development guide *) + + | UnspecifiedSequence of (stmt * lval list + * lval list * lval list * stmt ref list) list + (** statements whose order of execution is not specified by + ISO/C. This is important for the order of side effects + during evaluation of expressions. Each statement comes + together with three list of lval, in this order. + - lvals that are written during the sequence and whose future + value depends upon the statement (it is legal to read from them, but + not to write to them) + - lvals that are written during the evaluation of the statement itself + - lval that are read. + - Function calls in the corresponding statement + Note that this include only a subset of the affectations + of the statement. Namely, the + temporary variables generated by cil are excluded (i.e. it + is assumed that the "compilation" is correct). In addition, + side effects caused by function applications are not taken + into account in the list. For a single statement, the written lvals + are supposed to be ordered (or their order of evaluation doesn't + matter), so that an alarm should be emitted only if the lvals read by + a statement overlap with the lvals written (or read) by another + statement of the sequence. + + At this time this feature is + experimental and may miss some unspecified sequences. + + In case you do not care about this feature just handle it + like a block (see {!Cil.block_from_unspecified_sequence}). + @plugin development guide *) + + | Throw of (exp * typ) option * location + (** Throws an exception, C++ style. + We keep the type of the expression, to match + it against the appropriate catch clause. A Throw node has + no successor, even if it is in try-catch block that will catch + the exception: we keep normal and exceptional control-flow + completely separate, as in Jo and Chang, ICSSA 2004. + *) + + | TryCatch of block * (catch_binder * block) list * location + + | TryFinally of block * block * location + (** On MSVC we support structured exception handling. This is what you might + expect. Control can get into the finally block either from the end of the + body block, or if an exception is thrown. + @plugin development guide *) + + | TryExcept of block * (instr list * exp) * block * location +(** On MSVC we support structured exception handling. The try/except + statement is a bit tricky: + {v __try \{ blk \} + __except (e) \{ + handler + \} + v} + + The argument to __except must be an expression. However, we keep a + list of instructions AND an expression in case you need to make + function calls. We'll print those as a comma expression. The control + can get to the __except expression only if an exception is thrown. + After that, depending on the value of the expression the control + goes to the handler, propagates the exception, or retries the + exception. The location corresponds to the try keyword. + @plugin development guide *) + +(** Kind of exceptions that are caught by a given clause. *) +and catch_binder = + | Catch_exn of varinfo * (varinfo * block) list + (** catch exception of given type(s). + If the list is empty, only exceptions with the same type as the + varinfo can be caught. If the list is non-empty, only exceptions + matching one of the type of a varinfo in the list are caught. + The associated block contains the operations necessary to transform + the matched varinfo into the principal one. + Semantics is by value (i.e. the varinfo is bound to a copy of the + caught object). + + This clause is a declaration point for the varinfo(s) + mentioned in it. More precisely, for + [Catch_exn(v_0,[(v_1, b_1),..., (v_n, b_n)])], + the [v_i] must be referenced in the [slocals] of the + enclosing [fundec], and _must not_ appear in any [blocals] + of some block. The scope of v_0 is all the [b_i] and + the corresponding block in the [catch_binder * block list] of the + [TryCatch] node the binder belongs to. The scope of the other [v_i] + is the corresponding [b_i]. + *) + | Catch_all (** default catch clause: all exceptions are caught. *) + +(** Instructions. They may cause effects directly but may not have control + flow.*) +and instr = + | Set of lval * exp * location + (** An assignment. A cast is present if the exp has different type from + lval *) + + | Call of lval option * exp * exp list * location + (** optional: result is an lval. A cast might be necessary if the declared + result type of the function is not the same as that of the destination. + Actual arguments must have a type equivalent (i.e. {!Cil.need_cast} must + return [false]) to the one of the formals of the function. + If the type of the result variable is not the same as the declared type of + the function result then an implicit cast exists. + *) + + (* See the GCC specification for the meaning of ASM. + If the source is MS VC then only the templates + are used. + + [sm] I've added a notes.txt file which contains more + information on interpreting Asm instructions *) + | Asm of + attributes (* Really only const and volatile can appear here *) + * string list (* templates (CR-separated) *) + * extended_asm option + * location + (** An inline assembly instruction. The arguments are + (1) a list of attributes (only const and volatile can appear here and only + for GCC) + (2) templates (CR-separated) + (3) GCC extended asm information if any + (4) location information *) + + | Skip of location + + | Code_annot of code_annotation * location + + +(** GNU extended-asm information: + - a list of outputs, each of which is an lvalue with optional names and + constraints. + - a list of input expressions along with constraints + - clobbered registers + - Possible destinations statements *) +and extended_asm = + { + asm_outputs: (string option * string * lval) list + (** outputs must be lvals with optional names and constraints. I would + like these to be actually variables, but I run into some trouble with + ASMs in the Linux sources *); + asm_inputs: (string option * string * exp) list + (** inputs with optional names and constraints *); + asm_clobbers: string list (** register clobbers *); + asm_gotos: (stmt ref) list + (** list of statements this asm section may jump to. Destination + must have a label. *); + } + +(** Describes a location in a source file *) +and location = Lexing.position * Lexing.position + +(** {1 Abstract syntax trees for annotations} *) + +and logic_constant = + | Integer of Integer.t * string option + (** Integer constant with a textual representation. *) + | LStr of string (** String constant. *) + | LWStr of int64 list (** Wide character string constant. *) + | LChr of char (** Character constant. *) + | LReal of logic_real + | LEnum of enumitem (** An enumeration constant.*) + +(** Real constants. *) +and logic_real = { + r_literal : string ; (** Initial string representation [s]. *) + r_nearest : float ; (** Nearest approximation of [s] in double precision. *) + r_upper : float ; (** Smallest double [u] such that [s <= u]. *) + r_lower : float ; (** Greatest double [l] such that [l <= s]. *) +} + +(** Types of logic terms. *) +and logic_type = + | Ctype of typ (** a C type *) + | Ltype of logic_type_info * logic_type list + (** an user-defined logic type with its parameters *) + | Lvar of string (** a type variable. *) + | Linteger (** mathematical integers, {i i.e.} Z *) + | Lreal (** mathematical reals, {i i.e.} R *) + | Larrow of logic_type list * logic_type (** (n-ary) function type *) + +(** tsets with an unique identifier. + Use [Logic_const.new_location] to generate a new id. *) +and identified_term = { + it_id: int; (** the identifier. *) + it_content: term (** the term *) +} + +(** logic label referring to a particular program point. *) +and logic_label = + | StmtLabel of stmt ref (** label of a C statement. *) + | LogicLabel of (stmt option * string) (* [JS 2011/05/13] why a tuple here? *) +(** builtin logic label ({t Here, Pre}, ...) *) + +(* ************************************************************************* *) +(** {2 Terms} *) +(* ************************************************************************* *) + +(** C Expressions as logic terms follow C constructs (with prefix T) *) + +(** Logic terms. *) +and term = { + term_node : term_node; (** kind of term. *) + term_loc : Lexing.position * Lexing.position; + (** position in the source file. *) + term_type : logic_type; (** type of the term. *) + term_name: string list; + (** names of the term if any. A name can be an arbitrary string, where + '"' and '\'' are escaped by a \, and which does not end with a \. + Hence, "name" and 'name' should be recognized as a unique label by most + tools. *) +} + +(** the various kind of terms. *) +and term_node = + (* same constructs as exp *) + | TConst of logic_constant (** a constant. *) + | TLval of term_lval (** an L-value *) + | TSizeOf of typ (** size of a given C type. *) + | TSizeOfE of term (** size of the type of an expression. *) + | TSizeOfStr of string (** size of a string constant. *) + | TAlignOf of typ (** alignment of a type. *) + | TAlignOfE of term (** alignment of the type of an expression. *) + | TUnOp of unop * term (** unary operator. *) + | TBinOp of binop * term * term (** binary operators. *) + | TCastE of typ * term (** cast to a C type. *) + | TAddrOf of term_lval (** address of a term. *) + | TStartOf of term_lval (** beginning of an array. *) + + (* additional constructs *) + | Tapp of logic_info * (logic_label * logic_label) list * term list + (** application of a logic function. *) + | Tlambda of quantifiers * term (** lambda abstraction. *) + | TDataCons of logic_ctor_info * term list + (** constructor of logic sum-type. *) + | Tif of term * term * term + (** conditional operator*) + | Tat of term * logic_label + (** term refers to a particular program point. *) + | Tbase_addr of logic_label * term (** base address of a pointer. *) + | Toffset of logic_label * term (** offset from the base address of a pointer. *) + | Tblock_length of logic_label * term (** length of the block pointed to by the term. *) + | Tnull (** the null pointer. *) + | TLogic_coerce of logic_type * term + (** implicit conversion from a C type to a logic type. + The logic type must not be a Ctype. In particular, used to denote + lifting to Linteger and Lreal. + *) + | TCoerce of term * typ (** coercion to a given C type. *) + | TCoerceE of term * term (** coercion to the type of a given term. *) + | TUpdate of term * term_offset * term + (** functional update of a field. *) + | Ttypeof of term (** type tag for a term. *) + | Ttype of typ (** type tag for a C type. *) + | Tempty_set (** the empty set. *) + | Tunion of term list (** union of terms. *) + | Tinter of term list (** intersection of terms. *) + | Tcomprehension of + term * quantifiers * predicate option + (** set defined in comprehension ({t \{ t[i] | integer i; 0 <= i < 5\}}) *) + | Trange of term option * term option (** range of integers. *) + | Tlet of logic_info * term (** local binding *) + +(** lvalue: base address and offset. *) +and term_lval = + term_lhost * term_offset + +(** base address of an lvalue. *) +and term_lhost = + | TVar of logic_var (** a variable. *) + | TResult of typ (** value returned by a C function. + Only used in post-conditions or assigns + *) + | TMem of term (** memory access. *) + +(** model field. *) +and model_info = { + mi_name: string; (** name *) + mi_field_type: logic_type; (** type of the field *) + mi_base_type: typ; (** type to which the field is associated. *) + mi_decl: location; (** where the field has been declared. *) +} + +(** offset of an lvalue. *) +and term_offset = + | TNoOffset (** no further offset. *) + | TField of fieldinfo * term_offset + (** access to the field of a compound type. *) + | TModel of model_info * term_offset (** access to a model field. *) + | TIndex of term * term_offset + (** index. Note that a range is denoted by [TIndex(Trange(i1,i2),ofs)] *) + +(** description of a logic function or predicate. +@plugin development guide *) +and logic_info = { +(* + mutable l_name : string; (** name of the function. *) +*) + mutable l_var_info : logic_var; + (** we use only fields lv_name and lv_id of l_var_info + we should factorize lv_type and l_type+l_profile below *) + mutable l_labels : logic_label list; (** label arguments of the function. *) + mutable l_tparams : string list; (** type parameters *) + mutable l_type : logic_type option; (** return type. None for predicates *) + mutable l_profile : logic_var list; (** type of the arguments. *) + mutable l_body : logic_body; (** body of the function. *) +} + +and builtin_logic_info = { + mutable bl_name: string; + mutable bl_labels: logic_label list; + mutable bl_params: string list; + mutable bl_type: logic_type option; + mutable bl_profile: (string * logic_type) list; +} + +and logic_body = + | LBnone (** no definition and no reads clause *) + | LBreads of identified_term list + (** read accesses performed by a function. *) + | LBterm of term (** direct definition of a function. *) + | LBpred of predicate (** direct definition of a predicate. *) + | LBinductive of + (string * logic_label list * string list * predicate) list + (** inductive definition *) + +(** Description of a logic type. + @plugin development guide *) +and logic_type_info = { + lt_name: string; + lt_params : string list; (** type parameters*) + mutable lt_def: logic_type_def option + (** definition of the type. None for abstract types. *) +} +(* will be expanded when dealing with concrete types *) + +and logic_type_def = + | LTsum of logic_ctor_info list (** sum type with its constructors. *) + | LTsyn of logic_type (** Synonym of another type. *) + +(** origin of a logic variable. *) +and logic_var_kind = + | LVGlobal (** global logic function or predicate. *) + | LVC (** Logic counterpart of a C variable. *) + | LVFormal (** formal parameter of a logic function / predicate + or \lambda abstraction *) + | LVQuant (** Bound by a quantifier (\exists or \forall) *) + | LVLocal (** local \let *) + +(** description of a logic variable +@plugin development guide *) +and logic_var = { + mutable lv_name : string; (** name of the variable. *) + mutable lv_id : int; (** unique identifier *) + mutable lv_type : logic_type; (** type of the variable. *) + mutable lv_kind: logic_var_kind; (** kind of the variable *) + mutable lv_origin : varinfo option +(** when the logic variable stems from a C variable, set to the original C + variable. *) +} + +(** Description of a constructor of a logic sum-type. + @plugin development guide *) +and logic_ctor_info = + { ctor_name: string; (** name of the constructor. *) + ctor_type: logic_type_info; (** type to which the constructor belongs. *) + ctor_params: logic_type list + (** types of the parameters of the constructor. *) + } + +(* ************************************************************************* *) +(** {2 Predicates} *) +(* ************************************************************************* *) + +(** variables bound by a quantifier. *) +and quantifiers = logic_var list + +(** comparison relations*) +and relation = + | Rlt + | Rgt + | Rle + | Rge + | Req + | Rneq (** @plugin development guide *) + + +(** predicates *) +and predicate_node = + | Pfalse (** always-false predicate. *) + | Ptrue (** always-true predicate. *) + | Papp of logic_info * (logic_label * logic_label) list * term list + (** application of a predicate. *) + | Pseparated of term list + | Prel of relation * term * term (** comparison of two terms. *) + | Pand of predicate * predicate (** conjunction *) + | Por of predicate * predicate (** disjunction. *) + | Pxor of predicate * predicate (** logical xor. *) + | Pimplies of predicate * predicate (** implication. *) + | Piff of predicate * predicate (** equivalence. *) + | Pnot of predicate (** negation. *) + | Pif of term * predicate * predicate (** conditional *) + | Plet of logic_info * predicate (** definition of a local variable *) + | Pforall of quantifiers * predicate (** universal quantification. *) + | Pexists of quantifiers * predicate (** existential quantification. *) + | Pat of predicate * logic_label + (** predicate refers to a particular program point. *) + | Pvalid_read of logic_label * term (** the given locations are valid for reading. *) + | Pvalid of logic_label * term (** the given locations are valid. *) + | Pvalid_function of term + (** the pointed function has a type compatible with the one of pointer. *) + | Pinitialized of logic_label * term (** the given locations are initialized. *) + | Pdangling of logic_label * term (** the given locations contain dangling + adresses. *) + | Pallocable of logic_label * term (** the given locations can be allocated. *) + | Pfreeable of logic_label * term (** the given locations can be free. *) + | Pfresh of logic_label * logic_label * term * term + (** \fresh(pointer, n) + A memory block of n bytes is newly allocated to the pointer.*) + | Psubtype of term * term + (** First term is a type tag that is a subtype of the second. *) + +(** predicate with an unique identifier. Use [Logic_const.new_predicate] to + create fresh predicates *) +and identified_predicate = { + ip_id: int; (** identifier *) + ip_content: predicate; (** the predicate itself*) +} + +(** predicates with a location and an optional list of names *) +and predicate = { + pred_name : string list; (** list of given names *) + pred_loc : location; (** position in the source code. *) + pred_content : predicate_node;(** content *) +} + +(* Polymorphic types shared with parsed trees (Logic_ptree) *) +(** variant of a loop or a recursive function. Type shared with Logic_ptree. *) +and 'term variant = 'term * string option + +(** allocates and frees. + @since Oxygen-20120901 *) +and 'locs allocation = + | FreeAlloc of 'locs list * 'locs list (** tsets. Empty list means \nothing. *) + | FreeAllocAny (** Nothing specified. Semantics depends on where it + is written. *) + +(** dependencies of an assigned location. Shared with Logic_ptree. *) +and 'locs deps = + | From of 'locs list (** tsets. Empty list means \nothing. *) + | FromAny (** Nothing specified. Any location can be involved. *) + +and 'locs from = ('locs * 'locs deps) + +(** zone assigned with its dependencies. Type shared with Logic_ptree. *) +and 'locs assigns = + | WritesAny (** Nothing specified. Anything can be written. *) + | Writes of 'locs from list + (** list of locations that can be written. Empty list means \nothing. *) + +(** Function or statement contract. This type shares the name of its + constructors with {!Logic_ptree.spec}. *) +and spec = { + mutable spec_behavior : behavior list; + (** behaviors *) + + mutable spec_variant : term variant option; + (** variant for recursive functions. *) + + mutable spec_terminates: identified_predicate option; + (** termination condition. *) + + mutable spec_complete_behaviors: string list list; + (** list of complete behaviors. + It is possible to have more than one set of complete behaviors *) + + mutable spec_disjoint_behaviors: string list list; + (** list of disjoint behaviors. + It is possible to have more than one set of disjoint behaviors *) +} + + +(** extension to standard ACSL clause. + Each extension is associated to a keyword. An extension + can be registered through the following functions: + - {!Logic_typing.register_behavior_extension} for parsing and type-checking + - {!Cil_printer.register_behavior_extension} for pretty-printing an + extended clause + - {!Cil.register_behavior_extension} for visiting an extended clause + + @plugin development guide *) +and acsl_extension = string * acsl_extension_kind + +and acsl_extension_kind = + | Ext_id of int (** id used internally by the extension itself. *) + | Ext_terms of term list + | Ext_preds of predicate list + (** a list of predicates, the most common case of for extensions *) + +(** Behavior of a function or statement. This type shares the name of its + constructors with {!Logic_ptree.behavior}. + @since Oxygen-20120901 [b_allocation] has been added. + @since Carbon-20101201 [b_requires] has been added. + @modify Boron-20100401 [b_ensures] is replaced by [b_post_cond]. + Old [b_ensures] represent the [Normal] case of [b_post_cond]. *) +and behavior = { + mutable b_name : string; (** name of the behavior. *) + mutable b_requires : identified_predicate list; (** require clauses. *) + mutable b_assumes : identified_predicate list; (** assume clauses. *) + mutable b_post_cond : (termination_kind * identified_predicate) list + (** post-condition. *); + mutable b_assigns : identified_term assigns; (** assignments. *) + mutable b_allocation : identified_term allocation; (** frees, allocates. *) + mutable b_extended : acsl_extension list (** extensions *) +} + +(** kind of termination a post-condition applies to. See ACSL manual. *) +and termination_kind = Normal | Exits | Breaks | Continues | Returns + +(** Pragmas for the value analysis plugin of Frama-C. + Type shared with Logic_ptree.*) +and 'term loop_pragma = + | Unroll_specs of 'term list + | Widen_hints of 'term list + | Widen_variables of 'term list + +(** Pragmas for the slicing plugin of Frama-C. Type shared with Logic_ptree.*) +and 'term slice_pragma = + | SPexpr of 'term + | SPctrl + | SPstmt + +(** Pragmas for the impact plugin of Frama-C. Type shared with Logic_ptree.*) +and 'term impact_pragma = + | IPexpr of 'term + | IPstmt + +(** The various kinds of pragmas. Type shared with Logic_ptree. *) +and 'term pragma = + | Loop_pragma of 'term loop_pragma + | Slice_pragma of 'term slice_pragma + | Impact_pragma of 'term impact_pragma + +(** all annotations that can be found in the code. + This type shares the name of its constructors with + {!Logic_ptree.code_annot}. *) +and code_annotation_node = + | AAssert of string list * predicate + (** assertion to be checked. The list of strings is the list of + behaviors to which this assertion applies. *) + + | AStmtSpec of string list * spec + (** statement contract + (potentially restricted to some enclosing behaviors). *) + + | AInvariant of string list * bool * predicate + (** loop/code invariant. The list of strings is the list of behaviors to which + this invariant applies. The boolean flag is true for normal loop + invariants and false for invariant-as-assertions. *) + + | AVariant of term variant + (** loop variant. Note that there can be at most one variant associated to a + given statement *) + + | AAssigns of string list * identified_term assigns + (** loop assigns. (see [b_assigns] in the behaviors for other assigns). At + most one clause associated to a given (statement, behavior) couple. *) + + | AAllocation of string list * identified_term allocation + (** loop allocation clause. (see [b_allocation] in the behaviors for other + allocation clauses). + At most one clause associated to a given (statement, behavior) couple. + @since Oxygen-20120901 when [b_allocation] has been added. *) + + | APragma of term pragma (** pragma. *) + | AExtended of string list * acsl_extension + (** extension in a loop annotation. + @since Silicon-20161101 *) + +(** function contract. *) + +and funspec = spec + +(** code annotation with an unique identifier. + Use [Logic_const.new_code_annotation] to create new code annotations with + a fresh id. *) +and code_annotation = { + annot_id: int; (** identifier. *) + annot_content : code_annotation_node; (** content of the annotation. *) +} + +(** behavior of a function. *) +and funbehavior = behavior + +(** global annotations, not attached to a statement or a function. *) +and global_annotation = + | Dfun_or_pred of logic_info * location + | Dvolatile of + identified_term list * varinfo option * varinfo option * location + (** associated terms, reading function, writing function *) + | Daxiomatic of string * global_annotation list * location + | Dtype of logic_type_info * location (** declaration of a logic type. *) + | Dlemma of + string * bool * logic_label list * string list * + predicate * location + (** definition of a lemma. The boolean flag is [true] if the property should + be taken as an axiom and [false] if it must be proved. *) + | Dinvariant of logic_info * location + (** global invariant. The predicate does not have any argument. *) + | Dtype_annot of logic_info * location + (** type invariant. The predicate has exactly one argument. *) + | Dmodel_annot of model_info * location + (** Model field for a type t, seen as a logic function with one + argument of type t *) + | Dcustom_annot of custom_tree * string* location + (*Custom declaration*) + +and custom_tree = CustomDummy +(* + | CustomType of logic_type + | CustomLexpr of lexpr + | CustomOther of string * (custom_tree list) +*) + +type kinstr = + | Kstmt of stmt + | Kglobal + +(** Internal representation of decorated C functions *) +type cil_function = + | Definition of (fundec * location) (** defined function *) + | Declaration of (funspec * varinfo * varinfo list option * location) + (** Declaration(spec,f,args,loc) represents a leaf function [f] with + specification [spec] and arguments [args], at location [loc]. As + with the [TFun] constructor of {!Cil_types.typ}, the arg list is + optional, to distinguish [void f()] ([None]) from + [void f(void)] ([Some []]). *) + +(** Only field [fundec] can be used directly. Use {!Annotations.funspec}, + [Annotations.add_*] and [Annotations.remove_*] to query or modify field + [spec]. *) +type kernel_function = { + mutable fundec : cil_function; + mutable spec : funspec; +} + +(* [VP] TODO: VLocal should be attached to a particular block, not a whole + function. *) +type localisation = + | VGlobal + | VLocal of kernel_function + | VFormal of kernel_function + +type mach = { + sizeof_short: int; (* Size of "short" *) + sizeof_int: int; (* Size of "int" *) + sizeof_long: int ; (* Size of "long" *) + sizeof_longlong: int; (* Size of "long long" *) + sizeof_ptr: int; (* Size of pointers *) + sizeof_float: int; (* Size of "float" *) + sizeof_double: int; (* Size of "double" *) + sizeof_longdouble: int; (* Size of "long double" *) + sizeof_void: int; (* Size of "void" *) + sizeof_fun: int; (* Size of function *) + size_t: string; (* Type of "sizeof(T)" *) + wchar_t: string; (* Type of "wchar_t" *) + ptrdiff_t: string; (* Type of "ptrdiff_t" *) + alignof_short: int; (* Alignment of "short" *) + alignof_int: int; (* Alignment of "int" *) + alignof_long: int; (* Alignment of "long" *) + alignof_longlong: int; (* Alignment of "long long" *) + alignof_ptr: int; (* Alignment of pointers *) + alignof_float: int; (* Alignment of "float" *) + alignof_double: int; (* Alignment of "double" *) + alignof_longdouble: int; (* Alignment of "long double" *) + alignof_str: int; (* Alignment of strings *) + alignof_fun: int; (* Alignment of function *) + char_is_unsigned: bool; (* Whether "char" is unsigned *) + underscore_name: bool; (* If assembly names have leading underscore *) + const_string_literals: bool; (* Whether string literals have const chars *) + little_endian: bool; (* whether the machine is little endian *) + alignof_aligned: int (* Alignment of a type with aligned attribute *); + has__builtin_va_list: bool (* Whether [__builtin_va_list] is a known type *); + __thread_is_keyword: bool (* Whether [__thread] is a keyword *); + compiler: string; (* Compiler being used. Currently recognized names + are 'gcc', 'msvc' and 'generic'. *) + version: string; (* Information on this machdep *) +} + +(* +Local Variables: +compile-command: "make -C ../../.." +End: +*) diff --git a/test/cil_types_polymorphic.ml b/test/cil_types_polymorphic.ml new file mode 100644 index 0000000..514ba4c --- /dev/null +++ b/test/cil_types_polymorphic.ml @@ -0,0 +1,1780 @@ +module Integer = struct type t = int end (* fpottier/visitors *) +(****************************************************************************) +(* *) +(* Copyright (C) 2001-2003 *) +(* George C. Necula *) +(* Scott McPeak *) +(* Wes Weimer *) +(* Ben Liblit *) +(* All rights reserved. *) +(* *) +(* Redistribution and use in source and binary forms, with or without *) +(* modification, are permitted provided that the following conditions *) +(* are met: *) +(* *) +(* 1. Redistributions of source code must retain the above copyright *) +(* notice, this list of conditions and the following disclaimer. *) +(* *) +(* 2. Redistributions in binary form must reproduce the above copyright *) +(* notice, this list of conditions and the following disclaimer in the *) +(* documentation and/or other materials provided with the distribution. *) +(* *) +(* 3. The names of the contributors may not be used to endorse or *) +(* promote products derived from this software without specific prior *) +(* written permission. *) +(* *) +(* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *) +(* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *) +(* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *) +(* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *) +(* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, *) +(* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, *) +(* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; *) +(* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *) +(* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *) +(* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN *) +(* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE *) +(* POSSIBILITY OF SUCH DAMAGE. *) +(* *) +(* File modified by CEA (Commissariat à l'énergie atomique et aux *) +(* énergies alternatives) *) +(* and INRIA (Institut National de Recherche en Informatique *) +(* et Automatique). *) +(****************************************************************************) + +(** The Abstract Syntax of CIL. + @plugin development guide *) + +(**************************** WARNING ***************************************) +(* Remember to reflect any change here into the visitor and pretty-printer *) +(* in cil.ml. In particular, if a type becomes mutable, it is necessary to *) +(* adapt the Cil.behavior type and the copy_behavior accordingly. *) +(* A first test to see if something has been broken by a change is to launch*) +(* ptests.byte -add-options '-files-debug "-check -copy"' *) +(* In addition, it is a good idea to add some invariant checks in the *) +(* check_file class in frama-c/src/file.ml (before lauching the tests) *) +(****************************************************************************) + +(* ************************************************************************* *) +(** {2 Root of the AST} *) +(* ************************************************************************* *) + +(** In Frama-C, the whole AST is accessible through {!Ast.get}. *) + +(** The top-level representation of a CIL source file (and the result of the + parsing and elaboration). Its main contents is the list of global + declarations and definitions. You can iterate over the globals in a + {!Cil_types.file} using the following iterators: {!Cil.mapGlobals}, + {!Cil.iterGlobals} and {!Cil.foldGlobals}. You can also use the + {!Cil.dummyFile} when you need a {!Cil_types.file} as a placeholder. For + each global item CIL stores the source location where it appears (using the + type {!Cil_types.location}) + @plugin development guide *) +type file = { + mutable fileName: string; (** The complete file name *) + + mutable globals: global list; + (** List of globals as they will appear in the printed file *) + + mutable globinit: fundec option; + (** An optional global initializer function. This is a function where you + can put stuff that must be executed before the program is + started. This function, is conceptually at the end of the file, + although it is not part of the globals list. Use {!Cil.getGlobInit} to + create/get one. *) + + mutable globinitcalled: bool; +(** Whether the global initialization function is called in main. This + should always be false if there is no global initializer. When you + create a global initialization CIL will try to insert code in main to + call it. *) +} + +(** The main type for representing global declarations and definitions. A list + of these form a CIL file. The order of globals in the file is generally + important. + @plugin development guide *) +and global = + | GType of typeinfo * location + (** A typedef. All uses of type names (through the [TNamed] constructor) + must be preceeded in the file by a definition of the name. The string + is the defined name and always not-empty. *) + + | GCompTag of compinfo * location + (** Defines a struct/union tag with some fields. There must be one of + these for each struct/union tag that you use (through the [TComp] + constructor) since this is the only context in which the fields are + printed. Consequently nested structure tag definitions must be + broken into individual definitions with the innermost structure + defined first. *) + + | GCompTagDecl of compinfo * location + (** Declares a struct/union tag. Use as a forward declaration. This is + printed without the fields. *) + + | GEnumTag of enuminfo * location + (** Declares an enumeration tag with some fields. There must be one of + these for each enumeration tag that you use (through the [TEnum] + constructor) since this is the only context in which the items are + printed. *) + + | GEnumTagDecl of enuminfo * location + (** Declares an enumeration tag. Use as a forward declaration. This is + printed without the items. *) + + | GVarDecl of varinfo * location + (** A variable declaration (not a definition) for a variable with object + type. There can be several declarations and at most one definition for + a given variable. If both forms appear then they must share the same + varinfo structure. Either has storage Extern or there must be a + definition in this file *) + + | GFunDecl of funspec * varinfo * location + (** A variable declaration (not a definition) for a function, i.e. a + prototype. There can be several declarations and at most one definition + for a given function. If both forms appear then they must share the same + varinfo structure. A prototype shares the varinfo with the fundec of the + definition. Either has storage Extern or there must be a definition in + this file. *) + + | GVar of varinfo * initinfo * location + (** A variable definition. Can have an initializer. The initializer is + updateable so that you can change it without requiring to recreate the + list of globals. There can be at most one definition for a variable in an + entire program. Cannot have storage Extern or function type. *) + + | GFun of fundec * location + (** A function definition. *) + + | GAsm of string * location + (** Global asm statement. These ones can contain only a template *) + + | GPragma of attribute * location + (** Pragmas at top level. Use the same syntax as attributes *) + + | GText of string + (** Some text (printed verbatim) at top level. E.g., this way you can put + comments in the output. *) + + | GAnnot of global_annotation * location +(** a global annotation. Can be + - an axiom or a lemma + - a predicate declaration or definition + - a global type invariant + - a global invariant + - a logic function declaration or definition. *) + +(* ************************************************************************* *) +(** {2 Types} *) +(* ************************************************************************* *) + +(** A C type is represented in CIL using the type {!Cil_types.typ}. Among types + we differentiate the integral types (with different kinds denoting the sign + and precision), floating point types, enumeration types, array and pointer + types, and function types. Every type is associated with a list of + attributes, which are always kept in sorted order. Use {!Cil.addAttribute} + and {!Cil.addAttributes} to construct list of attributes. If you want to + inspect a type, you should use {!Cil.unrollType} or {!Cil.unrollTypeDeep} to + see through the uses of named types. + + CIL is configured at build-time with the sizes and alignments of the + underlying compiler (GCC or MSVC). CIL contains functions that can compute + the size of a type (in bits) {!Cil.bitsSizeOf}, the alignment of a type (in + bytes) {!Cil.alignOf_int}, and can convert an offset into a start and width + (both in bits) using the function {!Cil.bitsOffset}. At the moment these + functions do not take into account the [packed] attributes and pragmas. *) + +and typ = + | TVoid of attributes (** Void type. Also predefined as {!Cil.voidType} *) + + | TInt of ikind * attributes + (** An integer type. The kind specifies the sign and width. Several useful + variants are predefined as {!Cil.intType}, {!Cil.uintType}, + {!Cil.longType}, {!Cil.charType}. *) + + | TFloat of fkind * attributes + (** A floating-point type. The kind specifies the precision. You can also use + the predefined constant {!Cil.doubleType}. *) + + | TPtr of typ * attributes + (** Pointer type. Several useful variants are predefined as + {!Cil.charPtrType}, {!Cil.charConstPtrType} (pointer to a constant + character), {!Cil.voidPtrType}, {!Cil.intPtrType} *) + + | TArray of typ * exp option * bitsSizeofTypCache * attributes + (** Array type. It indicates the base type and the array length. *) + + | TFun of typ * (string * typ * attributes) list option * bool * attributes + (** Function type. Indicates the type of the result, the name, type + and name attributes of the formal arguments ([None] if no arguments + were specified, as in a function whose definition or prototype we + have not seen; [Some \[\]] means void). Use {!Cil.argsToList} to + obtain a list of arguments. The boolean indicates if it is a + variable-argument function. If this is the type of a varinfo for + which we have a function declaration then the information for the + formals must match that in the function's sformals. Use + {!Cil.setFormals}, or {!Cil.setFunctionType}, or + {!Cil.makeFormalVar} for this purpose. *) + + | TNamed of typeinfo * attributes + (** The use of a named type. All uses of the same type name must share the + typeinfo. Each such type name must be preceeded in the file by a [GType] + global. This is printed as just the type name. The actual referred type + is not printed here and is carried only to simplify processing. To see + through a sequence of named type references, use {!Cil.unrollType}. The + attributes are in addition to those given when the type name was + defined. *) + + | TComp of compinfo * bitsSizeofTypCache * attributes + (** A reference to a struct or a union type. All references to the + same struct or union must share the same compinfo among them and + with a [GCompTag] global that preceeds all uses (except maybe + those that are pointers to the composite type). The attributes + given are those pertaining to this use of the type and are in + addition to the attributes that were given at the definition of + the type and which are stored in the compinfo. *) + + | TEnum of enuminfo * attributes + (** A reference to an enumeration type. All such references must + share the enuminfo among them and with a [GEnumTag] global that + preceeds all uses. The attributes refer to this use of the + enumeration and are in addition to the attributes of the + enumeration itself, which are stored inside the enuminfo *) + + | TBuiltin_va_list of attributes +(** This is the same as the gcc's type with the same name *) + +(** Various kinds of integers *) +and ikind = + IBool (** [_Bool] *) + | IChar (** [char] *) + | ISChar (** [signed char] *) + | IUChar (** [unsigned char] *) + | IInt (** [int] *) + | IUInt (** [unsigned int] *) + | IShort (** [short] *) + | IUShort (** [unsigned short] *) + | ILong (** [long] *) + | IULong (** [unsigned long] *) + | ILongLong (** [long long] (or [_int64] on Microsoft Visual C) *) + | IULongLong (** [unsigned long long] (or [unsigned _int64] on Microsoft + Visual C) *) + +(** Various kinds of floating-point numbers*) +and fkind = + FFloat (** [float] *) + | FDouble (** [double] *) + | FLongDouble (** [long double] *) + +(** This is used to cache the computation of the size of types in bits. *) +and bitsSizeofTyp = + | Not_Computed + | Computed of int + | Not_Computable of (string * typ) (** Explanation of the error *) + +and bitsSizeofTypCache = { mutable scache : bitsSizeofTyp} + +(* ************************************************************************* *) +(** {2 Attributes} *) +(* ************************************************************************* *) + +and attribute = + | Attr of string * attrparam list + (** An attribute has a name and some optional parameters. The name should not + start or end with underscore. When CIL parses attribute names it will + strip leading and ending underscores (to ensure that the multitude of GCC + attributes such as const, __const and __const__ all mean the same + thing.) *) + + | AttrAnnot of string + +(** Attributes are lists sorted by the attribute name. Use the functions + {!Cil.addAttribute} and {!Cil.addAttributes} to insert attributes in an + attribute list and maintain the sortedness. *) +and attributes = attribute list + +(** The type of parameters of attributes *) +and attrparam = + | AInt of (Integer.t[@opaque]) (** An integer constant *) + | AStr of string (** A string constant *) + | ACons of string * attrparam list + (** Constructed attributes. These are printed [foo(a1,a2,...,an)]. The list + of parameters can be empty and in that case the parentheses are not + printed. *) + | ASizeOf of typ (** A way to talk about types *) + | ASizeOfE of attrparam + | AAlignOf of typ + | AAlignOfE of attrparam + | AUnOp of unop * attrparam + | ABinOp of binop * attrparam * attrparam + | ADot of attrparam * string (** a.foo **) + | AStar of attrparam (** * a *) + | AAddrOf of attrparam (** & a **) + | AIndex of attrparam * attrparam (** a1[a2] *) + | AQuestion of attrparam * attrparam * attrparam (** a1 ? a2 : a3 **) + +(* ************************************************************************* *) +(** {2 Structures} *) +(* ************************************************************************* *) + +(** The {!Cil_types.compinfo} describes the definition of a structure or union + type. Each such {!Cil_types.compinfo} must be defined at the top-level using + the [GCompTag] constructor and must be shared by all references to this type + (using either the [TComp] type constructor or from the definition of the + fields. + + If all you need is to scan the definition of each composite type once, you + can do that by scanning all top-level [GCompTag]. + + Constructing a {!Cil_types.compinfo} can be tricky since it must contain + fields that might refer to the host {!Cil_types.compinfo} and furthermore + the type of the field might need to refer to the {!Cil_types.compinfo} for + recursive types. Use the {!Cil.mkCompInfo} function to create a + {!Cil_types.compinfo}. You can easily fetch the {!Cil_types.fieldinfo} for a + given field in a structure with {!Cil.getCompField}. *) + +(** The definition of a structure or union type. Use {!Cil.mkCompInfo} to make + one and use {!Cil.copyCompInfo} to copy one (this ensures that a new key is + assigned and that the fields have the right pointers to parents.). + @plugin development guide *) +and compinfo = { + mutable cstruct: bool; + (** [true] if struct, [false] if union *) + + corig_name: string; + (** Original name as found in C file. Will never be changed *) + + mutable cname: string; + (** The name. Always non-empty. Use {!Cil.compFullName} to get the full name + of a comp (along with the struct or union) *) + + mutable ckey: int; + (** A unique integer. This is assigned by {!Cil.mkCompInfo} using a global + variable in the Cil module. Thus two identical structs in two different + files might have different keys. Use {!Cil.copyCompInfo} to copy + structures so that a new key is assigned. *) + + mutable cfields: fieldinfo list; + (** Information about the fields. Notice that each fieldinfo has a pointer + back to the host compinfo. This means that you should not share + fieldinfo's between two compinfo's *) + + mutable cattr: attributes; + (** The attributes that are defined at the same time as the composite + type. These attributes can be supplemented individually at each + reference to this [compinfo] using the [TComp] type constructor. *) + + mutable cdefined: bool; + (** This boolean flag can be used to distinguish between structures + that have not been defined and those that have been defined but have + no fields (such things are allowed in gcc). *) + + mutable creferenced: bool; +(** [true] if used. Initially set to [false]. *) +} + +(* ************************************************************************* *) +(** {2 Structure fields} *) +(* ************************************************************************* *) + +(** The {!Cil_types.fieldinfo} structure is used to describe a structure or + union field. Fields, just like variables, can have attributes associated + with the field itself or associated with the type of the field (stored along + with the type of the field). *) + +(** Information about a struct/union field. + @plugin development guide *) +and fieldinfo = { + mutable fcomp: compinfo; + (** The host structure that contains this field. There can be only one + [compinfo] that contains the field. *) + + forig_name: string; + (** original name as found in C file. *) + + mutable fname: string; + (** The name of the field. Might be the value of {!Cil.missingFieldName} in + which case it must be a bitfield and is not printed and it does not + participate in initialization *) + + mutable ftype: typ; + (** The type. If the field is a bitfield, a special attribute + [FRAMA_C_BITFIELD_SIZE] indicating the width of the bitfield is added. *) + + mutable fbitfield: int option; + (** If a bitfield then ftype should be an integer type and the width of the + bitfield must be 0 or a positive integer smaller or equal to the width of + the integer type. A field of width 0 is used in C to control the alignment + of fields. *) + + mutable fattr: attributes; + (** The attributes for this field (not for its type) *) + + mutable floc: location; + (** The location where this field is defined *) + + mutable faddrof: bool; + (** Adapted from CIL [vaddrof] field for variables. Only set for non-array + fields. Variable whose field address is taken is not marked anymore as + having its own address taken. True if the address of this field is + taken. CIL will set these flags when it parses C, but you should make + sure to set the flag whenever your transformation create [AddrOf] + expression. *) + + mutable fsize_in_bits: int option; + (** (Deprecated. Use {!Cil.bitsOffset} instead.) Similar to [fbitfield] for + all types of fields. + @deprecated only Jessie uses this *) + + mutable foffset_in_bits: int option; + (** Offset at which the field starts in the structure. Do not read directly, + but use {!Cil.bitsOffset} instead. *) + + mutable fpadding_in_bits: int option; +(** (Deprecated.) Store the size of the padding that follows the field, if any. + @deprecated only Jessie uses this *) +} + +(* ************************************************************************* *) +(** {2 Enumerations} *) +(* ************************************************************************* *) + +(** Information about an enumeration. This is shared by all references to an + enumeration. Make sure you have a [GEnumTag] for each of these. *) + +(** Information about an enumeration. + @plugin development guide *) +and enuminfo = { + eorig_name: string; (** original name as found in C file. *) + + mutable ename: string; (** The name. Always non-empty. *) + + mutable eitems: enumitem list; (** Items. The list must be non-empty *) + + mutable eattr: attributes; + (** The attributes that are defined at the same time as the enumeration + type. These attributes can be supplemented individually at each + reference to this [enuminfo] using the [TEnum] type constructor. *) + + mutable ereferenced: bool; (** [true] if used. Initially set to [false]. *) + mutable ekind: ikind (** The integer kind used to represent this enum. MSVC + always assumes IInt but this is not the case + for gcc. See ISO C 6.7.2.2 *) +} + +and enumitem = { + eiorig_name: string; (** original name as found in C file. *) + mutable einame: string; (** the name, always non-empty. *) + mutable eival: exp; (** value of the item. Must be a compile-time constant *) + mutable eihost: enuminfo; (** the host enumeration in which the item is + declared. *) + eiloc: location; +} + +(** Information about a defined type. + @plugin development guide *) +and typeinfo = { + torig_name: string; (** original name as found in C file. *) + + mutable tname: string; + (** The name. Can be empty only in a [GType] when introducing a composite or + enumeration tag. If empty cannot be refered to from the file *) + + mutable ttype: typ; + (** The actual type. This includes the attributes that were present in the + typedef *) + + mutable treferenced: bool; (** [true] if used. Initially set to [false]. *) +} + +(* ************************************************************************* *) +(** {2 Variables} *) +(* ************************************************************************* *) + +(** Each local or global variable is represented by a unique + {!Cil_types.varinfo} structure. A global {!Cil_types.varinfo} can be + introduced with the [GVarDecl] or [GVar], [GFunDecl] or [GFun] globals. + A local varinfo can be introduced as part of a function definition + {!Cil_types.fundec}. + + All references to a given global or local variable must refer to the same + copy of the [varinfo]. Each [varinfo] has a globally unique identifier that + can be used to index maps and hashtables (the name can also be used for this + purpose, except for locals from different functions). This identifier is + constructor using a global counter. + + It is very important that you construct [varinfo] structures using only one + of the following functions: + - {!Cil.makeGlobalVar} : to make a global variable + - {!Cil.makeTempVar} : to make a temporary local variable whose name + will be generated so that to avoid conflict with other locals. + - {!Cil.makeLocalVar} : like {!Cil.makeTempVar} but you can specify the + exact name to be used. + - {!Cil.copyVarinfo}: make a shallow copy of a varinfo assigning a new name + and a new unique identifier + + A [varinfo] is also used in a function type to denote the list of + formals. *) + +(** Information about a variable. + @plugin development guide *) +and varinfo = { + mutable vname: string; + (** The name of the variable. Cannot be empty. It is primarily your + responsibility to ensure the uniqueness of a variable name. For local + variables {!Cil.makeTempVar} helps you ensure that the name is + unique. *) + + vorig_name: string; + (** the original name of the variable. Need not be unique. *) + + mutable vtype: typ; + (** The declared type of the variable. *) + + mutable vattr: attributes; + (** A list of attributes associated with the variable.*) + + mutable vstorage: storage; + (** The storage-class *) + + mutable vglob: bool; + (** True if this is a global variable*) + + mutable vdefined: bool; + (** True if the variable or function is defined in the file. Only relevant + for functions and global variables. Not used in particular for local + variables and logic variables. *) + + mutable vformal: bool; + (** True if the variable is a formal parameter of a function. *) + + mutable vinline: bool; + (** Whether this varinfo is for an inline function. *) + + mutable vdecl: location; + (** Location of variable declaration. *) + + mutable vid: int; + (** A unique integer identifier. This field will be set for you if you use + one of the {!Cil.makeFormalVar}, {!Cil.makeLocalVar}, + {!Cil.makeTempVar}, {!Cil.makeGlobalVar}, or {!Cil.copyVarinfo}. *) + + mutable vaddrof: bool; + (** [true] if the address of this variable is taken. CIL will set these + flags when it parses C, but you should make sure to set the flag + whenever your transformation create [AddrOf] expression. *) + + mutable vreferenced: bool; + (** [true] if this variable is ever referenced. This is computed by + [removeUnusedVars]. It is safe to just initialize this to [false]. *) + + vtemp: bool; + (** [true] for temporary variables generated by CIL normalization. [false] + for all the other variables. *) + + mutable vdescr: string option; + (** For most temporary variables, a description of what the var holds. + (e.g. for temporaries used for function call results, this string is a + representation of the function call.) *) + + mutable vdescrpure: bool; + (** Indicates whether the vdescr above is a pure expression or call. True + for all CIL expressions and Lvals, but false for e.g. function calls. + Printing a non-pure vdescr more than once may yield incorrect + results. *) + + mutable vghost: bool; + (** Indicates if the variable is declared in ghost code *) + + vsource: bool; + (** [true] iff this variable appears in the source of the program, which is + the case of all the variables in the initial AST. Plugins may create + variables with [vsource=false], for example to handle dynamic allocation. + Those variables do *not* have an associated {!GVar} or {!GVarDecl}. *) + + mutable vlogic_var_assoc: logic_var option + (** Logic variable representing this variable in the logic world. Do not + access this field directly. Instead, call {!Cil.cvar_to_lvar}. *) +} + +(** Storage-class information *) +and storage = + NoStorage (** The default storage. Nothing is printed *) + | Static + | Register + | Extern + +(* ************************************************************************* *) +(** {2 Expressions} *) +(* ************************************************************************* *) + +(** The CIL expression language contains only the side-effect free expressions + of C. They are represented as the type {!Cil_types.exp}. There are several + interesting aspects of CIL expressions: + + Integer and floating point constants can carry their textual representation. + This way the integer 15 can be printed as 0xF if that is how it occurred in + the source. + + CIL uses arbitrary precision integers + to represent the integer constants and also stores the + width of the integer type. Care must be taken to ensure that the constant is + representable with the given width. Use the functions {!Cil.kinteger}, + {!Cil.kinteger64} and {!Cil.integer} to construct constant expressions. CIL + predefines the constants {!Cil.zero}, {!Cil.one} and {!Cil.mone} (for -1). + + Use the functions {!Cil.isConstant} and {!Cil.isInteger} to test if an + expression is a constant and a constant integer respectively. + + CIL keeps the type of all unary and binary expressions. You can think of + that type qualifying the operator. Furthermore there are different operators + for arithmetic and comparisons on arithmetic types and on pointers. + + Another unusual aspect of CIL is that the implicit conversion between an + expression of array type and one of pointer type is made explicit, using the + [StartOf] expression constructor (which is not printed). If you apply the + [AddrOf]constructor to an lvalue of type [T] then you will be getting an + expression of type [TPtr(T)]. + + You can find the type of an expression with {!Cil.typeOf}. + + You can perform constant folding on expressions using the function + {!Cil.constFold}. *) + +(** Expressions (Side-effect free)*) +and exp = { + eid: int; (** unique identifier *) + enode: exp_node; (** the expression itself *) + eloc: location; (** location of the expression. *) +} + +and exp_node = + | Const of constant (** Constant *) + | Lval of lval (** Lvalue *) + | SizeOf of typ + (** sizeof(). Has [unsigned int] type (ISO 6.5.3.4). This is not + turned into a constant because some transformations might want to change + types *) + + | SizeOfE of exp (** sizeof() *) + + | SizeOfStr of string + (** sizeof(string_literal). We separate this case out because this is the + only instance in which a string literal should not be treated as having + type pointer to character. *) + + | AlignOf of typ + (** This corresponds to the GCC __alignof_. Has [unsigned int] type *) + + | AlignOfE of exp + + | UnOp of unop * exp * typ + (** Unary operation. Includes the type of the result. *) + + | BinOp of binop * exp * exp * typ + (** Binary operation. Includes the type of the result. The arithmetic + conversions are made explicit for the arguments. + @plugin development guide *) + + | CastE of typ * exp + (** Use {!Cil.mkCast} to make casts. *) + + | AddrOf of lval + (** Always use {!Cil.mkAddrOf} to construct one of these. Apply to an lvalue + of type [T] yields an expression of type [TPtr(T)] *) + + | StartOf of lval + (** Conversion from an array to a pointer to the beginning of the array. + Given an lval of type [TArray(T)] produces an expression of type + [TPtr(T)]. In C this operation is implicit, the [StartOf] operator is not + printed. We have it in CIL because it makes the typing rules simpler. *) + + | Info of exp * exp_info +(** Additional information on the underlying expression *) + +(** Additional information on an expression *) +and exp_info = { + exp_type : logic_type; (** when used as placeholder for a term *) + exp_name: string list; +} + +(* ************************************************************************* *) +(** {2 Constants} *) +(* ************************************************************************* *) + +(** Literal constants *) +and constant = + | CInt64 of (Integer.t[@opaque]) * ikind * string option + (** Integer constant. Give the ikind (see ISO9899 6.1.3.2) and the + textual representation. Textual representation is always set to Some s + when it comes from user code. This allows us to print a + constant as it was represented in the code, for example, + 0xF instead of 15. It is usually None for constant generated by Cil + itself. Use {!Cil.integer} or {!Cil.kinteger} to create these. *) + + | CStr of string + (** String constant. The escape characters inside the string have been already + interpreted. This constant has pointer to character type! The only case + when you would like a string literal to have an array type is when it is + an argument to sizeof. In that case you should use SizeOfStr. *) + + | CWStr of int64 list + (** Wide character string constant. Note that the local interpretation of such + a literal depends on {!Cil.theMachine.wcharType} and + {!Cil.theMachine.wcharKind}. Such a constant has type pointer to + {!Cil.theMachine.wcharType}. The escape characters in the string have not + been "interpreted" in the sense that L"A\xabcd" remains "A\xabcd" rather + than being represented as the wide character list with two elements: 65 + and 43981. That "interpretation" depends on the underlying wide character + type. *) + + | CChr of char + (** Character constant. This has type int, so use charConstToInt to read the + value in case sign-extension is needed. *) + + | CReal of float * fkind * string option + (** Floating point constant. Give the fkind (see ISO 6.4.4.2) and also the + textual representation, if available. *) + + | CEnum of enumitem +(** An enumeration constant. Use [Cillower.lowerEnumVisitor] to replace these + with integer constants. *) + +(** Unary operators *) +and unop = + Neg (** Unary minus *) + | BNot (** Bitwise complement (~) *) + | LNot (** Logical Not (!) *) + +(** Binary operations *) +and binop = + PlusA (** arithmetic + *) + | PlusPI (** pointer + integer *) + | IndexPI (** pointer + integer but only when it arises from an expression + [e\[i\]] when [e] is a pointer and + not an array. This is semantically + the same as PlusPI but CCured uses + this as a hint that the integer is + probably positive. *) + | MinusA (** arithmetic - *) + | MinusPI (** pointer - integer *) + | MinusPP (** pointer - pointer *) + | Mult (** * *) + | Div (** / + @plugin development guide *) + | Mod (** % + @plugin development guide *) + | Shiftlt (** shift left *) + | Shiftrt (** shift right *) + + | Lt (** < (arithmetic comparison) *) + | Gt (** > (arithmetic comparison) *) + | Le (** <= (arithmetic comparison) *) + | Ge (** >= (arithmetic comparison) *) + | Eq (** == (arithmetic comparison) *) + | Ne (** != (arithmetic comparison) *) + | BAnd (** bitwise and *) + | BXor (** exclusive-or *) + | BOr (** inclusive-or *) + + | LAnd (** logical and. Unlike other expressions this one does not always + evaluate both operands. If you want + to use these, you must set + {!Cil.useLogicalOperators}. *) + | LOr (** logical or. Unlike other expressions this one does not always + evaluate both operands. If you + want to use these, you must set + {!Cil.useLogicalOperators}. *) + +(* ************************************************************************* *) +(** {2 Left values} *) +(* ************************************************************************* *) + +(** Left values (aka Lvalues) are the sublanguage of expressions that can appear + at the left of an assignment or as operand to the address-of operator. In C + the syntax for lvalues is not always a good indication of the meaning of the + lvalue. For example the C value {v a[0][1][2] v} might involve 1, 2 or 3 + memory reads when used in an expression context, depending on the declared + type of the variable [a]. If [a] has type [int \[4\]\[4\]\[4\]] then we have + one memory read from somewhere inside the area that stores the array [a]. On + the other hand if [a] has type [int ***] then the expression really means [* + ( * ( * (a + 0) + 1) + 2)], in which case it is clear that it involves three + separate memory operations. + + An lvalue denotes the contents of a range of memory addresses. This range is + denoted as a host object along with an offset within the object. The host + object can be of two kinds: a local or global variable, or an object whose + address is in a pointer expression. We distinguish the two cases so that we + can tell quickly whether we are accessing some component of a variable + directly or we are accessing a memory location through a pointer. To make + it easy to tell what an lvalue means CIL represents lvalues as a host object + and an offset (see {!Cil_types.lval}). The host object (represented as + {!Cil_types.lhost}) can be a local or global variable or can be the object + pointed-to by a pointer expression. The offset (represented as + {!Cil_types.offset}) is a sequence of field or array index designators. + + Both the typing rules and the meaning of an lvalue is very precisely + specified in CIL. + + The following are a few useful function for operating on lvalues: + - {!Cil.mkMem} - makes an lvalue of [Mem] kind. Use this to ensure + that certain equivalent forms of lvalues are canonized. + For example, [*&x = x]. + - {!Cil.typeOfLval} - the type of an lvalue + - {!Cil.typeOffset} - the type of an offset, given the type of the + host. + - {!Cil.addOffset} and {!Cil.addOffsetLval} - extend sequences + of offsets. + - {!Cil.removeOffset} and {!Cil.removeOffsetLval} - shrink sequences + of offsets. + + The following equivalences hold {v + Mem(AddrOf(Mem a, aoff)), off = Mem a, aoff + off + Mem(AddrOf(Var v, aoff)), off = Var v, aoff + off + AddrOf (Mem a, NoOffset) = a + v} *) + +and lval = lhost * offset + +(** The host part of an {!Cil_types.lval}. *) +and lhost = + | Var of varinfo + (** The host is a variable. *) + + | Mem of exp +(** The host is an object of type [T] when the expression has pointer + [TPtr(T)]. *) + + +(** The offset part of an {!Cil_types.lval}. Each offset can be applied to + certain kinds of lvalues and its effect is that it advances the starting + address of the lvalue and changes the denoted type, essentially focussing + to some smaller lvalue that is contained in the original one. + @plugin development guide *) +and offset = + | NoOffset + (** No offset. Can be applied to any lvalue and does not change either the + starting address or the type. This is used when the lval consists of just + a host or as a terminator in a list of other kinds of offsets. *) + + | Field of fieldinfo * offset + (** A field offset. Can be applied only to an lvalue that denotes a structure + or a union that contains the mentioned field. This advances the offset to + the beginning of the mentioned field and changes the type to the type of + the mentioned field. *) + + | Index of exp * offset +(** An array index offset. Can be applied only to an lvalue that denotes an + array. This advances the starting address of the lval to the beginning of + the mentioned array element and changes the denoted type to be the type of + the array element *) + +(* ************************************************************************* *) +(** {2 Initializers} *) +(* ************************************************************************* *) + +(** A special kind of expressions are those that can appear as initializers for + global variables (initialization of local variables is turned into + assignments). The initializers are represented as type + {!Cil_types.init}. You can create initializers with {!Cil.makeZeroInit} and + you can conveniently scan compound initializers them with + {!Cil.foldLeftCompound}. *) + +(** Initializers for global variables. *) +and init = + | SingleInit of exp (** A single initializer *) + | CompoundInit of typ * (offset * init) list +(** Used only for initializers of structures, unions and arrays. The offsets + are all of the form [Field(f, NoOffset)] or [Index(i, NoOffset)] and + specify the field or the index being initialized. For structures all fields + must have an initializer (except the unnamed bitfields), in the proper + order. This is necessary since the offsets are not printed. For arrays the + list must contain a prefix of the initializers; the rest are 0-initialized. + For unions there must be exactly one initializer. If the initializer is not + for the first field then a field designator is printed, so you better be on + GCC since MSVC does not understand this. You can scan an initializer list + with {!Cil.foldLeftCompound}. *) + +(** We want to be able to update an initializer in a global variable, so we + define it as a mutable field *) +and initinfo = { mutable init : init option } + +(* ************************************************************************* *) +(** {2 Function definitions} *) +(* ************************************************************************* *) + +(** A function definition is always introduced with a [GFun] constructor at the + top level. All the information about the function is stored into a + {!Cil_types.fundec}. Some of the information (e.g. its name, type, storage, + attributes) is stored as a {!Cil_types.varinfo} that is a field of the + [fundec]. To refer to the function from the expression language you must use + the [varinfo]. + + The function definition contains, in addition to the body, a list of all the + local variables and separately a list of the formals. Both kind of variables + can be referred to in the body of the function. The formals must also be + shared with the formals that appear in the function type. For that reason, + to manipulate formals you should use the provided functions + {!Cil.makeFormalVar} and {!Cil.setFormals}. *) + +(** Function definitions. + @plugin development guide *) +and fundec = { + mutable svar: varinfo; + (** Holds the name and type as a variable, so we can refer to it easily + from the program. All references to this function either in a function + call or in a prototype must point to the same [varinfo]. *) + + mutable sformals: varinfo list; + (** Formals. These must be in the same order and with the same information + as the formal information in the type of the function. Use + {!Cil.setFormals} or {!Cil.setFunctionType} to set these formals and + ensure that they are reflected in the function type. Do not make + copies of these because the body refers to them. *) + + mutable slocals: varinfo list; + (** Locals. Does NOT include the sformals. Do not make copies of these + because the body refers to them. *) + + mutable smaxid: int; + (** Max local id. Starts at 0. Used for creating the names of new + temporary variables. Updated by {!Cil.makeLocalVar} and + {!Cil.makeTempVar}. You can also use {!Cil.setMaxId} to set it after + you have added the formals and locals. *) + + mutable sbody: block; (** The function body. *) + + mutable smaxstmtid: int option; + (** max id of a (reachable) statement in this function, if we have + computed it. range = 0 ... (smaxstmtid-1). This is computed by + {!Cfg.computeCFGInfo}. *) + + mutable sallstmts: stmt list; + (** After you call {!Cfg.computeCFGInfo} this field is set to contain all + statements in the function. *) + + mutable sspec: funspec; +} + +(** A block is a sequence of statements with the control falling through from + one element to the next *) +and block = { + mutable battrs: attributes; (** Attributes for the block *) + + mutable blocals: varinfo list; + (** variables that are local to the block. It is a subset of the slocals of + the enclosing function. *) + + mutable bstmts: stmt list; (** The statements comprising the block. *) +} + +(* ************************************************************************* *) +(** {2 Statements} *) +(* ************************************************************************* *) + +(** CIL statements are the structural elements that make the CFG. They are + represented using the type {!Cil_types.stmt}. Every statement has a + (possibly empty) list of labels. The {!Cil_types.stmtkind} field of a + statement indicates what kind of statement it is. + + Use {!Cil.mkStmt} to make a statement and the fill-in the fields. + + CIL also comes with support for control-flow graphs. The [sid] field in + [stmt] can be used to give unique numbers to statements, and the [succs] and + [preds] fields can be used to maintain a list of successors and predecessors + for every statement. The CFG information is not computed by default. Instead + you must explicitly use the functions {!Cfg.prepareCFG} and + {!Cfg.computeCFGInfo} to do it. *) + +(** Statements. + @plugin development guide *) +and stmt = { + mutable labels: label list; + (** Whether the statement starts with some labels, case statements or + default statements. *) + + mutable skind: stmtkind; + (** The kind of statement *) + + mutable sid: int; + (** A number (>= 0) that is unique in a function. Filled in only after the + CFG is computed. *) + + mutable succs: stmt list; + (** The successor statements. They can always be computed from the skind and + the context in which this statement appears. Filled in only after the CFG + is computed. *) + + mutable preds: stmt list; + (** The inverse of the succs function. *) + + mutable ghost : bool +} + +(** Labels *) +and label = + | Label of string * location * bool + (** A real label. If the bool is "true", the label is from the input source + program. If the bool is "false", the label was created by CIL or some + other transformation *) + + | Case of exp * location + (** A case statement. This expression is lowered into a constant if + {!Cil.lowerConstants} is set to [true]. *) + + | Default of location (** A default statement *) + +(* The various kinds of statements *) +and stmtkind = + | Instr of instr + (** An instruction that does not contain control flow. Control implicitly + falls through. + @plugin development guide *) + + | Return of exp option * location + (** The return statement. This is a leaf in the CFG. + @plugin development guide *) + + | Goto of stmt ref * location + (** A goto statement. Appears from actual goto's in the code or from goto's + that have been inserted during elaboration. The reference points to the + statement that is the target of the Goto. This means that you have to + update the reference whenever you replace the target statement. The + target statement MUST have at least a label. + @plugin development guide *) + + | Break of location + (** A break to the end of the nearest enclosing Loop or Switch. + @plugin development guide *) + + | Continue of location + (** A continue to the start of the nearest enclosing [Loop]. + @plugin development guide *) + + | If of exp * block * block * location + (** A conditional. Two successors, the "then" and the "else" branches (in + this order). + Both branches fall-through to the successor of the If statement. + @plugin development guide *) + + | Switch of exp * block * (stmt list) * location + (** A switch statement. [exp] is the index of the switch. [block] is + the body of the switch. [stmt list] contains the set of + statements whose [labels] are cases of the switch (i.e. for each + case, the corresponding statement is in [stmt list], a statement + cannot appear more than once in the list, and statements in + [stmt list] can have several labels corresponding to several + cases. + @plugin development guide *) + + | Loop of + code_annotation list * block * location * (stmt option) * (stmt option) + (** A [while(1)] loop. The termination test is implemented in the body of a + loop using a [Break] statement. If {!Cfg.prepareCFG} has been called, the + first stmt option will point to the stmt containing the continue label + for this loop and the second will point to the stmt containing the break + label for this loop. + @plugin development guide *) + + | Block of block + (** Just a block of statements. Use it as a way to keep some block attributes + local. + @plugin development guide *) + + | UnspecifiedSequence of (stmt * lval list + * lval list * lval list * stmt ref list) list + (** statements whose order of execution is not specified by + ISO/C. This is important for the order of side effects + during evaluation of expressions. Each statement comes + together with three list of lval, in this order. + - lvals that are written during the sequence and whose future + value depends upon the statement (it is legal to read from them, but + not to write to them) + - lvals that are written during the evaluation of the statement itself + - lval that are read. + - Function calls in the corresponding statement + Note that this include only a subset of the affectations + of the statement. Namely, the + temporary variables generated by cil are excluded (i.e. it + is assumed that the "compilation" is correct). In addition, + side effects caused by function applications are not taken + into account in the list. For a single statement, the written lvals + are supposed to be ordered (or their order of evaluation doesn't + matter), so that an alarm should be emitted only if the lvals read by + a statement overlap with the lvals written (or read) by another + statement of the sequence. + + At this time this feature is + experimental and may miss some unspecified sequences. + + In case you do not care about this feature just handle it + like a block (see {!Cil.block_from_unspecified_sequence}). + @plugin development guide *) + + | Throw of (exp * typ) option * location + (** Throws an exception, C++ style. + We keep the type of the expression, to match + it against the appropriate catch clause. A Throw node has + no successor, even if it is in try-catch block that will catch + the exception: we keep normal and exceptional control-flow + completely separate, as in Jo and Chang, ICSSA 2004. + *) + + | TryCatch of block * (catch_binder * block) list * location + + | TryFinally of block * block * location + (** On MSVC we support structured exception handling. This is what you might + expect. Control can get into the finally block either from the end of the + body block, or if an exception is thrown. + @plugin development guide *) + + | TryExcept of block * (instr list * exp) * block * location +(** On MSVC we support structured exception handling. The try/except + statement is a bit tricky: + {v __try \{ blk \} + __except (e) \{ + handler + \} + v} + + The argument to __except must be an expression. However, we keep a + list of instructions AND an expression in case you need to make + function calls. We'll print those as a comma expression. The control + can get to the __except expression only if an exception is thrown. + After that, depending on the value of the expression the control + goes to the handler, propagates the exception, or retries the + exception. The location corresponds to the try keyword. + @plugin development guide *) + +(** Kind of exceptions that are caught by a given clause. *) +and catch_binder = + | Catch_exn of varinfo * (varinfo * block) list + (** catch exception of given type(s). + If the list is empty, only exceptions with the same type as the + varinfo can be caught. If the list is non-empty, only exceptions + matching one of the type of a varinfo in the list are caught. + The associated block contains the operations necessary to transform + the matched varinfo into the principal one. + Semantics is by value (i.e. the varinfo is bound to a copy of the + caught object). + + This clause is a declaration point for the varinfo(s) + mentioned in it. More precisely, for + [Catch_exn(v_0,[(v_1, b_1),..., (v_n, b_n)])], + the [v_i] must be referenced in the [slocals] of the + enclosing [fundec], and _must not_ appear in any [blocals] + of some block. The scope of v_0 is all the [b_i] and + the corresponding block in the [catch_binder * block list] of the + [TryCatch] node the binder belongs to. The scope of the other [v_i] + is the corresponding [b_i]. + *) + | Catch_all (** default catch clause: all exceptions are caught. *) + +(** Instructions. They may cause effects directly but may not have control + flow.*) +and instr = + | Set of lval * exp * location + (** An assignment. A cast is present if the exp has different type from + lval *) + + | Call of lval option * exp * exp list * location + (** optional: result is an lval. A cast might be necessary if the declared + result type of the function is not the same as that of the destination. + Actual arguments must have a type equivalent (i.e. {!Cil.need_cast} must + return [false]) to the one of the formals of the function. + If the type of the result variable is not the same as the declared type of + the function result then an implicit cast exists. + *) + + (* See the GCC specification for the meaning of ASM. + If the source is MS VC then only the templates + are used. + + [sm] I've added a notes.txt file which contains more + information on interpreting Asm instructions *) + | Asm of + attributes (* Really only const and volatile can appear here *) + * string list (* templates (CR-separated) *) + * extended_asm option + * location + (** An inline assembly instruction. The arguments are + (1) a list of attributes (only const and volatile can appear here and only + for GCC) + (2) templates (CR-separated) + (3) GCC extended asm information if any + (4) location information *) + + | Skip of location + + | Code_annot of code_annotation * location + + +(** GNU extended-asm information: + - a list of outputs, each of which is an lvalue with optional names and + constraints. + - a list of input expressions along with constraints + - clobbered registers + - Possible destinations statements *) +and extended_asm = + { + asm_outputs: (string option * string * lval) list + (** outputs must be lvals with optional names and constraints. I would + like these to be actually variables, but I run into some trouble with + ASMs in the Linux sources *); + asm_inputs: (string option * string * exp) list + (** inputs with optional names and constraints *); + asm_clobbers: string list (** register clobbers *); + asm_gotos: (stmt ref) list + (** list of statements this asm section may jump to. Destination + must have a label. *); + } + +(** Describes a location in a source file *) +and location = Lexing.position * Lexing.position [@opaque] + +(** {1 Abstract syntax trees for annotations} *) + +and logic_constant = + | Integer of (Integer.t[@opaque]) * string option + (** Integer constant with a textual representation. *) + | LStr of string (** String constant. *) + | LWStr of int64 list (** Wide character string constant. *) + | LChr of char (** Character constant. *) + | LReal of logic_real + | LEnum of enumitem (** An enumeration constant.*) + +(** Real constants. *) +and logic_real = { + r_literal : string ; (** Initial string representation [s]. *) + r_nearest : float ; (** Nearest approximation of [s] in double precision. *) + r_upper : float ; (** Smallest double [u] such that [s <= u]. *) + r_lower : float ; (** Greatest double [l] such that [l <= s]. *) +} + +(** Types of logic terms. *) +and logic_type = + | Ctype of typ (** a C type *) + | Ltype of logic_type_info * logic_type list + (** an user-defined logic type with its parameters *) + | Lvar of string (** a type variable. *) + | Linteger (** mathematical integers, {i i.e.} Z *) + | Lreal (** mathematical reals, {i i.e.} R *) + | Larrow of logic_type list * logic_type (** (n-ary) function type *) + +(** tsets with an unique identifier. + Use [Logic_const.new_location] to generate a new id. *) +and identified_term = { + it_id: int; (** the identifier. *) + it_content: term (** the term *) +} + +(** logic label referring to a particular program point. *) +and logic_label = + | StmtLabel of stmt ref (** label of a C statement. *) + | LogicLabel of (stmt option * string) (* [JS 2011/05/13] why a tuple here? *) +(** builtin logic label ({t Here, Pre}, ...) *) + +(* ************************************************************************* *) +(** {2 Terms} *) +(* ************************************************************************* *) + +(** C Expressions as logic terms follow C constructs (with prefix T) *) + +(** Logic terms. *) +and term = { + term_node : term_node; (** kind of term. *) + term_loc : Lexing.position * Lexing.position [@opaque]; + (** position in the source file. *) + term_type : logic_type; (** type of the term. *) + term_name: string list; + (** names of the term if any. A name can be an arbitrary string, where + '"' and '\'' are escaped by a \, and which does not end with a \. + Hence, "name" and 'name' should be recognized as a unique label by most + tools. *) +} + +(** the various kind of terms. *) +and term_node = + (* same constructs as exp *) + | TConst of logic_constant (** a constant. *) + | TLval of term_lval (** an L-value *) + | TSizeOf of typ (** size of a given C type. *) + | TSizeOfE of term (** size of the type of an expression. *) + | TSizeOfStr of string (** size of a string constant. *) + | TAlignOf of typ (** alignment of a type. *) + | TAlignOfE of term (** alignment of the type of an expression. *) + | TUnOp of unop * term (** unary operator. *) + | TBinOp of binop * term * term (** binary operators. *) + | TCastE of typ * term (** cast to a C type. *) + | TAddrOf of term_lval (** address of a term. *) + | TStartOf of term_lval (** beginning of an array. *) + + (* additional constructs *) + | Tapp of logic_info * (logic_label * logic_label) list * term list + (** application of a logic function. *) + | Tlambda of quantifiers * term (** lambda abstraction. *) + | TDataCons of logic_ctor_info * term list + (** constructor of logic sum-type. *) + | Tif of term * term * term + (** conditional operator*) + | Tat of term * logic_label + (** term refers to a particular program point. *) + | Tbase_addr of logic_label * term (** base address of a pointer. *) + | Toffset of logic_label * term (** offset from the base address of a pointer. *) + | Tblock_length of logic_label * term (** length of the block pointed to by the term. *) + | Tnull (** the null pointer. *) + | TLogic_coerce of logic_type * term + (** implicit conversion from a C type to a logic type. + The logic type must not be a Ctype. In particular, used to denote + lifting to Linteger and Lreal. + *) + | TCoerce of term * typ (** coercion to a given C type. *) + | TCoerceE of term * term (** coercion to the type of a given term. *) + | TUpdate of term * term_offset * term + (** functional update of a field. *) + | Ttypeof of term (** type tag for a term. *) + | Ttype of typ (** type tag for a C type. *) + | Tempty_set (** the empty set. *) + | Tunion of term list (** union of terms. *) + | Tinter of term list (** intersection of terms. *) + | Tcomprehension of + term * quantifiers * predicate option + (** set defined in comprehension ({t \{ t[i] | integer i; 0 <= i < 5\}}) *) + | Trange of term option * term option (** range of integers. *) + | Tlet of logic_info * term (** local binding *) + +(** lvalue: base address and offset. *) +and term_lval = + term_lhost * term_offset + +(** base address of an lvalue. *) +and term_lhost = + | TVar of logic_var (** a variable. *) + | TResult of typ (** value returned by a C function. + Only used in post-conditions or assigns + *) + | TMem of term (** memory access. *) + +(** model field. *) +and model_info = { + mi_name: string; (** name *) + mi_field_type: logic_type; (** type of the field *) + mi_base_type: typ; (** type to which the field is associated. *) + mi_decl: location; (** where the field has been declared. *) +} + +(** offset of an lvalue. *) +and term_offset = + | TNoOffset (** no further offset. *) + | TField of fieldinfo * term_offset + (** access to the field of a compound type. *) + | TModel of model_info * term_offset (** access to a model field. *) + | TIndex of term * term_offset + (** index. Note that a range is denoted by [TIndex(Trange(i1,i2),ofs)] *) + +(** description of a logic function or predicate. +@plugin development guide *) +and logic_info = { +(* + mutable l_name : string; (** name of the function. *) +*) + mutable l_var_info : logic_var; + (** we use only fields lv_name and lv_id of l_var_info + we should factorize lv_type and l_type+l_profile below *) + mutable l_labels : logic_label list; (** label arguments of the function. *) + mutable l_tparams : string list; (** type parameters *) + mutable l_type : logic_type option; (** return type. None for predicates *) + mutable l_profile : logic_var list; (** type of the arguments. *) + mutable l_body : logic_body; (** body of the function. *) +} + +and builtin_logic_info = { + mutable bl_name: string; + mutable bl_labels: logic_label list; + mutable bl_params: string list; + mutable bl_type: logic_type option; + mutable bl_profile: (string * logic_type) list; +} + +and logic_body = + | LBnone (** no definition and no reads clause *) + | LBreads of identified_term list + (** read accesses performed by a function. *) + | LBterm of term (** direct definition of a function. *) + | LBpred of predicate (** direct definition of a predicate. *) + | LBinductive of + (string * logic_label list * string list * predicate) list + (** inductive definition *) + +(** Description of a logic type. + @plugin development guide *) +and logic_type_info = { + lt_name: string; + lt_params : string list; (** type parameters*) + mutable lt_def: logic_type_def option + (** definition of the type. None for abstract types. *) +} +(* will be expanded when dealing with concrete types *) + +and logic_type_def = + | LTsum of logic_ctor_info list (** sum type with its constructors. *) + | LTsyn of logic_type (** Synonym of another type. *) + +(** origin of a logic variable. *) +and logic_var_kind = + | LVGlobal (** global logic function or predicate. *) + | LVC (** Logic counterpart of a C variable. *) + | LVFormal (** formal parameter of a logic function / predicate + or \lambda abstraction *) + | LVQuant (** Bound by a quantifier (\exists or \forall) *) + | LVLocal (** local \let *) + +(** description of a logic variable +@plugin development guide *) +and logic_var = { + mutable lv_name : string; (** name of the variable. *) + mutable lv_id : int; (** unique identifier *) + mutable lv_type : logic_type; (** type of the variable. *) + mutable lv_kind: logic_var_kind; (** kind of the variable *) + mutable lv_origin : varinfo option +(** when the logic variable stems from a C variable, set to the original C + variable. *) +} + +(** Description of a constructor of a logic sum-type. + @plugin development guide *) +and logic_ctor_info = + { ctor_name: string; (** name of the constructor. *) + ctor_type: logic_type_info; (** type to which the constructor belongs. *) + ctor_params: logic_type list + (** types of the parameters of the constructor. *) + } + +(* ************************************************************************* *) +(** {2 Predicates} *) +(* ************************************************************************* *) + +(** variables bound by a quantifier. *) +and quantifiers = logic_var list + +(** comparison relations*) +and relation = + | Rlt + | Rgt + | Rle + | Rge + | Req + | Rneq (** @plugin development guide *) + + +(** predicates *) +and predicate_node = + | Pfalse (** always-false predicate. *) + | Ptrue (** always-true predicate. *) + | Papp of logic_info * (logic_label * logic_label) list * term list + (** application of a predicate. *) + | Pseparated of term list + | Prel of relation * term * term (** comparison of two terms. *) + | Pand of predicate * predicate (** conjunction *) + | Por of predicate * predicate (** disjunction. *) + | Pxor of predicate * predicate (** logical xor. *) + | Pimplies of predicate * predicate (** implication. *) + | Piff of predicate * predicate (** equivalence. *) + | Pnot of predicate (** negation. *) + | Pif of term * predicate * predicate (** conditional *) + | Plet of logic_info * predicate (** definition of a local variable *) + | Pforall of quantifiers * predicate (** universal quantification. *) + | Pexists of quantifiers * predicate (** existential quantification. *) + | Pat of predicate * logic_label + (** predicate refers to a particular program point. *) + | Pvalid_read of logic_label * term (** the given locations are valid for reading. *) + | Pvalid of logic_label * term (** the given locations are valid. *) + | Pvalid_function of term + (** the pointed function has a type compatible with the one of pointer. *) + | Pinitialized of logic_label * term (** the given locations are initialized. *) + | Pdangling of logic_label * term (** the given locations contain dangling + adresses. *) + | Pallocable of logic_label * term (** the given locations can be allocated. *) + | Pfreeable of logic_label * term (** the given locations can be free. *) + | Pfresh of logic_label * logic_label * term * term + (** \fresh(pointer, n) + A memory block of n bytes is newly allocated to the pointer.*) + | Psubtype of term * term + (** First term is a type tag that is a subtype of the second. *) + +(** predicate with an unique identifier. Use [Logic_const.new_predicate] to + create fresh predicates *) +and identified_predicate = { + ip_id: int; (** identifier *) + ip_content: predicate; (** the predicate itself*) +} + +(** predicates with a location and an optional list of names *) +and predicate = { + pred_name : string list; (** list of given names *) + pred_loc : location; (** position in the source code. *) + pred_content : predicate_node;(** content *) +} + +(* Polymorphic types shared with parsed trees (Logic_ptree) *) +(** variant of a loop or a recursive function. Type shared with Logic_ptree. *) +and 'term variant = 'term * string option + +(** allocates and frees. + @since Oxygen-20120901 *) +and 'locs allocation = + | FreeAlloc of 'locs list * 'locs list (** tsets. Empty list means \nothing. *) + | FreeAllocAny (** Nothing specified. Semantics depends on where it + is written. *) + +(** dependencies of an assigned location. Shared with Logic_ptree. *) +and 'locs deps = + | From of 'locs list (** tsets. Empty list means \nothing. *) + | FromAny (** Nothing specified. Any location can be involved. *) + +and 'locs from = ('locs * 'locs deps) + +(** zone assigned with its dependencies. Type shared with Logic_ptree. *) +and 'locs assigns = + | WritesAny (** Nothing specified. Anything can be written. *) + | Writes of 'locs from list + (** list of locations that can be written. Empty list means \nothing. *) + +(** Function or statement contract. This type shares the name of its + constructors with {!Logic_ptree.spec}. *) +and spec = { + mutable spec_behavior : behavior list; + (** behaviors *) + + mutable spec_variant : term variant option; + (** variant for recursive functions. *) + + mutable spec_terminates: identified_predicate option; + (** termination condition. *) + + mutable spec_complete_behaviors: string list list; + (** list of complete behaviors. + It is possible to have more than one set of complete behaviors *) + + mutable spec_disjoint_behaviors: string list list; + (** list of disjoint behaviors. + It is possible to have more than one set of disjoint behaviors *) +} + + +(** extension to standard ACSL clause. + Each extension is associated to a keyword. An extension + can be registered through the following functions: + - {!Logic_typing.register_behavior_extension} for parsing and type-checking + - {!Cil_printer.register_behavior_extension} for pretty-printing an + extended clause + - {!Cil.register_behavior_extension} for visiting an extended clause + + @plugin development guide *) +and acsl_extension = string * acsl_extension_kind + +and acsl_extension_kind = + | Ext_id of int (** id used internally by the extension itself. *) + | Ext_terms of term list + | Ext_preds of predicate list + (** a list of predicates, the most common case of for extensions *) + +(** Behavior of a function or statement. This type shares the name of its + constructors with {!Logic_ptree.behavior}. + @since Oxygen-20120901 [b_allocation] has been added. + @since Carbon-20101201 [b_requires] has been added. + @modify Boron-20100401 [b_ensures] is replaced by [b_post_cond]. + Old [b_ensures] represent the [Normal] case of [b_post_cond]. *) +and behavior = { + mutable b_name : string; (** name of the behavior. *) + mutable b_requires : identified_predicate list; (** require clauses. *) + mutable b_assumes : identified_predicate list; (** assume clauses. *) + mutable b_post_cond : (termination_kind * identified_predicate) list + (** post-condition. *); + mutable b_assigns : identified_term assigns; (** assignments. *) + mutable b_allocation : identified_term allocation; (** frees, allocates. *) + mutable b_extended : acsl_extension list (** extensions *) +} + +(** kind of termination a post-condition applies to. See ACSL manual. *) +and termination_kind = Normal | Exits | Breaks | Continues | Returns + +(** Pragmas for the value analysis plugin of Frama-C. + Type shared with Logic_ptree.*) +and 'term loop_pragma = + | Unroll_specs of 'term list + | Widen_hints of 'term list + | Widen_variables of 'term list + +(** Pragmas for the slicing plugin of Frama-C. Type shared with Logic_ptree.*) +and 'term slice_pragma = + | SPexpr of 'term + | SPctrl + | SPstmt + +(** Pragmas for the impact plugin of Frama-C. Type shared with Logic_ptree.*) +and 'term impact_pragma = + | IPexpr of 'term + | IPstmt + +(** The various kinds of pragmas. Type shared with Logic_ptree. *) +and 'term pragma = + | Loop_pragma of 'term loop_pragma + | Slice_pragma of 'term slice_pragma + | Impact_pragma of 'term impact_pragma + +(** all annotations that can be found in the code. + This type shares the name of its constructors with + {!Logic_ptree.code_annot}. *) +and code_annotation_node = + | AAssert of string list * predicate + (** assertion to be checked. The list of strings is the list of + behaviors to which this assertion applies. *) + + | AStmtSpec of string list * spec + (** statement contract + (potentially restricted to some enclosing behaviors). *) + + | AInvariant of string list * bool * predicate + (** loop/code invariant. The list of strings is the list of behaviors to which + this invariant applies. The boolean flag is true for normal loop + invariants and false for invariant-as-assertions. *) + + | AVariant of term variant + (** loop variant. Note that there can be at most one variant associated to a + given statement *) + + | AAssigns of string list * identified_term assigns + (** loop assigns. (see [b_assigns] in the behaviors for other assigns). At + most one clause associated to a given (statement, behavior) couple. *) + + | AAllocation of string list * identified_term allocation + (** loop allocation clause. (see [b_allocation] in the behaviors for other + allocation clauses). + At most one clause associated to a given (statement, behavior) couple. + @since Oxygen-20120901 when [b_allocation] has been added. *) + + | APragma of term pragma (** pragma. *) + | AExtended of string list * acsl_extension + (** extension in a loop annotation. + @since Silicon-20161101 *) + +(** function contract. *) + +and funspec = spec + +(** code annotation with an unique identifier. + Use [Logic_const.new_code_annotation] to create new code annotations with + a fresh id. *) +and code_annotation = { + annot_id: int; (** identifier. *) + annot_content : code_annotation_node; (** content of the annotation. *) +} + +(** behavior of a function. *) +and funbehavior = behavior + +(** global annotations, not attached to a statement or a function. *) +and global_annotation = + | Dfun_or_pred of logic_info * location + | Dvolatile of + identified_term list * varinfo option * varinfo option * location + (** associated terms, reading function, writing function *) + | Daxiomatic of string * global_annotation list * location + | Dtype of logic_type_info * location (** declaration of a logic type. *) + | Dlemma of + string * bool * logic_label list * string list * + predicate * location + (** definition of a lemma. The boolean flag is [true] if the property should + be taken as an axiom and [false] if it must be proved. *) + | Dinvariant of logic_info * location + (** global invariant. The predicate does not have any argument. *) + | Dtype_annot of logic_info * location + (** type invariant. The predicate has exactly one argument. *) + | Dmodel_annot of model_info * location + (** Model field for a type t, seen as a logic function with one + argument of type t *) + | Dcustom_annot of custom_tree * string* location + (*Custom declaration*) + +and custom_tree = CustomDummy +(* + | CustomType of logic_type + | CustomLexpr of lexpr + | CustomOther of string * (custom_tree list) +*) +[@@deriving visitors { variety = "iter"; polymorphic = true; concrete = true }, + visitors { variety = "map"; polymorphic = true; concrete = true }, + visitors { variety = "endo"; polymorphic = true; concrete = true }, + visitors { variety = "reduce"; polymorphic = true; concrete = true; ancestors = ["VisitorsRuntime.addition_monoid"] }, + visitors { variety = "mapreduce"; polymorphic = true; concrete = true; ancestors = ["VisitorsRuntime.addition_monoid"] }, + visitors { variety = "iter2"; polymorphic = true; concrete = true }, + visitors { variety = "map2"; polymorphic = true; concrete = true }, + visitors { variety = "reduce2"; polymorphic = true; concrete = true; ancestors = ["VisitorsRuntime.addition_monoid"] }, + visitors { variety = "mapreduce2"; polymorphic = true; concrete = true; ancestors = ["VisitorsRuntime.addition_monoid"] } +] + +type kinstr = + | Kstmt of stmt + | Kglobal + +(** Internal representation of decorated C functions *) +type cil_function = + | Definition of (fundec * location) (** defined function *) + | Declaration of (funspec * varinfo * varinfo list option * location) + (** Declaration(spec,f,args,loc) represents a leaf function [f] with + specification [spec] and arguments [args], at location [loc]. As + with the [TFun] constructor of {!Cil_types.typ}, the arg list is + optional, to distinguish [void f()] ([None]) from + [void f(void)] ([Some []]). *) + +(** Only field [fundec] can be used directly. Use {!Annotations.funspec}, + [Annotations.add_*] and [Annotations.remove_*] to query or modify field + [spec]. *) +type kernel_function = { + mutable fundec : cil_function; + mutable spec : funspec; +} + +(* [VP] TODO: VLocal should be attached to a particular block, not a whole + function. *) +type localisation = + | VGlobal + | VLocal of kernel_function + | VFormal of kernel_function + +type mach = { + sizeof_short: int; (* Size of "short" *) + sizeof_int: int; (* Size of "int" *) + sizeof_long: int ; (* Size of "long" *) + sizeof_longlong: int; (* Size of "long long" *) + sizeof_ptr: int; (* Size of pointers *) + sizeof_float: int; (* Size of "float" *) + sizeof_double: int; (* Size of "double" *) + sizeof_longdouble: int; (* Size of "long double" *) + sizeof_void: int; (* Size of "void" *) + sizeof_fun: int; (* Size of function *) + size_t: string; (* Type of "sizeof(T)" *) + wchar_t: string; (* Type of "wchar_t" *) + ptrdiff_t: string; (* Type of "ptrdiff_t" *) + alignof_short: int; (* Alignment of "short" *) + alignof_int: int; (* Alignment of "int" *) + alignof_long: int; (* Alignment of "long" *) + alignof_longlong: int; (* Alignment of "long long" *) + alignof_ptr: int; (* Alignment of pointers *) + alignof_float: int; (* Alignment of "float" *) + alignof_double: int; (* Alignment of "double" *) + alignof_longdouble: int; (* Alignment of "long double" *) + alignof_str: int; (* Alignment of strings *) + alignof_fun: int; (* Alignment of function *) + char_is_unsigned: bool; (* Whether "char" is unsigned *) + underscore_name: bool; (* If assembly names have leading underscore *) + const_string_literals: bool; (* Whether string literals have const chars *) + little_endian: bool; (* whether the machine is little endian *) + alignof_aligned: int (* Alignment of a type with aligned attribute *); + has__builtin_va_list: bool (* Whether [__builtin_va_list] is a known type *); + __thread_is_keyword: bool (* Whether [__thread] is a keyword *); + compiler: string; (* Compiler being used. Currently recognized names + are 'gcc', 'msvc' and 'generic'. *) + version: string; (* Information on this machdep *) +} diff --git a/test/cloud.cppo.ml b/test/cloud.cppo.ml new file mode 100644 index 0000000..d3ebc95 --- /dev/null +++ b/test/cloud.cppo.ml @@ -0,0 +1,22 @@ +class ['self] base = object (_ : 'self) + method visit_real _env x = x +end + +type cloud = + | Point of (float[@name "real"]) * (float[@name "real"]) + | Clouds of cloud list + [@@name "nuage"] + [@@deriving visitors { variety = "map"; ancestors = ["base"] }] + +#if OCAML_VERSION >= (4, 03, 0) + +module List = struct + + type 'a mylist = 'a list = + | [] [@name "nil"] + | (::) of 'a * 'a mylist [@name "cons"] + [@@deriving visitors { variety = "map" }] + +end + +#endif diff --git a/test/delayed_tree.ml b/test/delayed_tree.ml new file mode 100644 index 0000000..3093e8f --- /dev/null +++ b/test/delayed_tree.ml @@ -0,0 +1,435 @@ +(* To play with this code in an OCaml toplevel, launch [ocaml] and type this: + #use "topfind";; + #require "visitors.ppx";; + #require "visitors.runtime";; + *) + +(* -------------------------------------------------------------------------- *) + +(* Suppose we have an arbitrary data structure that contains elements + of type ['a]. Here, it is a binary tree, but it could be anything: *) + +type 'a sometree = + | Leaf + | Node of 'a sometree * 'a * 'a sometree + +(* This annotation is used only at the very end and can be ignored upon + first reading: *) + +[@@deriving visitors { variety = "reduce"; polymorphic = true; + name = "sometree_reduce" }] + +(* We would like to enumerate the elements of this data structure. + More precisely, we would like to construct an iterator, that is, + an on-demand producer of elements. Here is a simple definition + of a stateful iterator: *) + +type 'a iterator = + unit -> 'a option + +(* The question is, can we construct an iterator for the type ['a sometree], + based on an automatically-generated visitor, so that the construction is + entirely independent of the type ['a sometree]? *) + +(* -------------------------------------------------------------------------- *) + +(* For starters, let us define cascades, which are a more pleasant kind of + iterators. A cascade is a persistent (stateless) iterator. It can be + thought of as a delayed list, that is, a list whose elements are computed + only on demand. *) + +(* Cascades could (should) be part of a separate library. There is in fact a + proposal to add them to OCaml's standard library: see the discussion at + https://github.com/ocaml/ocaml/pull/1002 *) + +type 'a cascade = + unit -> 'a head + +and 'a head = + | Nil + | Cons of 'a * 'a cascade + +(* A delayed computation is represented as a function of type [unit -> _]. + Thus, no memoization takes place. It is easy to implement a function + [memo: 'a cascade -> 'a cascade] that turns a nonmemoizing cascade into + a memoizing one, so memoization can be requested a posteriori, if + desired. *) + +(* The empty cascade. *) + +let nil : 'a cascade = + fun () -> Nil + +let cons (x : 'a) (xs : 'a cascade) : 'a cascade = + fun () -> Cons (x, xs) + +(* Forcing a cascade reveals its head. *) + +let force xs = + xs() + +(* A cascade can be easily converted to a stateful iterator. *) + +let cascade_to_iterator (xs : 'a cascade) : 'a iterator = + let s = ref xs in + fun () -> + match force !s with + | Nil -> + (* Writing [nil] into [s] may seem superfluous, but is in fact + necessary to guarantee that the computation that just led to + a [Nil] outcome is not repeated in the future. *) + s := nil; + None + | Cons (x, xs) -> + s := xs; + Some x + +(* Because cascades are close cousins of lists, they are easy to work with. + Constructing a cascade for a tree-like data structure is straightforward, + whereas directly constructing a stateful iterator would be more involved. *) + +(* -------------------------------------------------------------------------- *) + +(* Now, can we use some kind of visitor to turn a tree of type ['a sometree] + into a cascade of type ['a cascade]? *) + +(* At first sight, this does not seem very easy, for two reasons: 1- a visitor + usually traverses a tree in an eager manner, whereas we need the traversal + to make progress only as cascade elements are demanded; and 2- a visitor + performs a bottom-up computation, without a left-to-right bias (assuming + mutable state is not used), whereas a cascade enumerates elements in a + left-to-right manner. (Or in a right-to-left manner. As will be apparent + below, both directions are possible.) *) + +(* The trick is to use another intermediate step. Instead of turning a tree + directly into a cascade, we first transform it into a generic tree-like + structure: a *delayed tree*. Problem 1 is solved because, by introducing + delays into the new tree, we allow its construction to be carried out on + demand. Problem 2 is solved because this tree-to-tree transformation can be + carried out in a purely bottom-up manner by a [reduce] visitor. Then, + finally, it is straightforward to transform a delayed tree into a + cascade. *) + +(* -------------------------------------------------------------------------- *) + +(* A delayed tree contains ordinary nodes of arity 0, 1, and 2. Furthermore, + it contains [DTDelay] nodes, of arity 1, whose child is delayed, that is, + computed only on demand. *) + +type 'a delayed_tree = + | DTZero + | DTOne of 'a + | DTTwo of 'a delayed_tree * 'a delayed_tree + | DTDelay of (unit -> 'a delayed_tree) + +(* A delayed tree is converted to a cascade as follows. We may choose, at this + point, between left-to-right and right-to-left traversals. As usual, when + building a cascade, one must take a continuation [k] as an argument, so as + to avoid naive and costly cascade concatenation operations. *) + +let rec delayed_tree_to_cascade (dt : 'a delayed_tree) (k : 'a cascade) +: 'a cascade = + fun () -> delayed_tree_to_head dt k + +and delayed_tree_to_head (dt : 'a delayed_tree) (k : 'a cascade) : 'a head = + match dt with + | DTZero -> + force k + | DTOne x -> + Cons (x, k) + | DTTwo (dt1, dt2) -> + delayed_tree_to_head dt1 (delayed_tree_to_cascade dt2 k) + | DTDelay dt -> + delayed_tree_to_head (force dt) k + +let delayed_tree_to_cascade (dt : 'a delayed_tree) : 'a cascade = + delayed_tree_to_cascade dt nil + +let delayed_tree_to_iterator (dt : 'a delayed_tree) : 'a iterator = + cascade_to_iterator (delayed_tree_to_cascade dt) + +(* -------------------------------------------------------------------------- *) + +(* We now set up four constructor functions and constructor methods, which + construct delayed trees, and which we will use in a [reduce] visitor. *) + +(* The type ['a delay] is a synonym for ['a]. It is used as a decoration, in a + type definition, to indicate that a call to the method [visit_delay] is + desired. *) + +type 'a delay = 'a + +class ['self] delayed_tree_monoid = object (_ : 'self) + + (* Delayed trees form a monoid, in the sense that we concatenate them using + [DTTwo], and the neutral element is [DTZero]. We package these two data + constructors in the methods [zero] and [plus], which are automatically + called in an automatically-generated [reduce] visitor. *) + + method zero = + DTZero + + method plus s1 s2 = + match s1, s2 with + | DTZero, s + | s, DTZero -> + (* This optimization is not mandatory. It helps allocate fewer nodes. *) + s + | (DTOne _ | DTTwo _ | DTDelay _), _ -> + DTTwo (s1, s2) + + (* The visitor method [visit_delay] delays the visit of a subtree by + constructing and returning a [DTDelay] node, which carries a delayed + recursive call to a visitor. *) + + method visit_delay: 'env 'a . + ('env -> 'a -> 'b delayed_tree) -> + 'env -> 'a delay -> 'b delayed_tree + = fun visit_'a env x -> + DTDelay (fun () -> visit_'a env x) + +end + +(* The visitor function [yield] will be invoked at elements of type ['a]. + It constructs a one-element delayed tree. *) + +let yield _env x = + DTOne x + +(* -------------------------------------------------------------------------- *) + +(* It is now time to generate a [reduce] visitor for the type ['a sometree]. + This is the only part of the code which is specific of [sometree]. + Everything else is generic. *) + +(* We must insert [delay]s into the structure of the type ['a sometree] so as + to indicate where [visit_delay] should be called and (therefore) where + [DTDelay] nodes should be allocated. To do this, we write a copy of the + definition of the type ['a sometree], with extra delays in it. The new type + is actually considered equal to ['a sometree] by OCaml. Its role is purely + to carry a [@@deriving visitors] annotation. *) + +(* In the data constructor [Node], the left-hand [delay] is in fact + superfluous. With or without it, our iterators will eagerly descend along + the leftmost branch of a tree, anyway. *) + +type 'a mytree = 'a sometree = + | Leaf + | Node of 'a mytree delay * 'a * 'a mytree delay + +and 'a mytree_delay = + 'a mytree delay + +[@@deriving visitors { variety = "reduce"; polymorphic = true; + concrete = true; ancestors = ["delayed_tree_monoid"] }] + +(* -------------------------------------------------------------------------- *) + +(* For demonstration purposes, let us make our visitor verbose. *) + +class ['self] verbose_reduce = object (_ : 'self) + inherit [_] reduce as super + method! visit_Leaf visit_'a env = + Printf.printf "Visiting a leaf.\n%!"; + super#visit_Leaf visit_'a env + method! visit_Node visit_'a env t1 x t2 = + Printf.printf "Visiting a node.\n%!"; + super#visit_Node visit_'a env t1 x t2 +end + +(* In production, one should remove [verbose_reduce] and use [reduce] + instead. *) + +let sometree_to_delayed_tree (t : 'a sometree) = + new verbose_reduce # visit_mytree_delay yield () t + (* We use [visit_mytree_delay], even though [visit_mytree] would work + just as well, so as to ensure that we get a delayed tree whose root + is a [DTDelay] node. *) + +(* Problem solved! *) + +let sometree_to_iterator (t : 'a sometree) : 'a iterator = + delayed_tree_to_iterator (sometree_to_delayed_tree t) + +(* -------------------------------------------------------------------------- *) + +(* Demo. *) + +let t : int sometree = + Node (Node (Leaf, 1, Leaf), 2, Node (Leaf, 3, Leaf)) + +let i : int iterator = + sometree_to_iterator t + +(* Transcript of an OCaml toplevel session: + + # i();; + Visiting a node. + Visiting a node. + Visiting a leaf. + - : int option = Some 1 + # i();; + Visiting a leaf. + - : int option = Some 2 + # i();; + Visiting a node. + Visiting a leaf. + - : int option = Some 3 + # i();; + Visiting a leaf. + - : int option = None + # i();; + - : int option = None + + *) + +(* -------------------------------------------------------------------------- *) + +(* Variant: it is possible to use the visitor [sometree_reduce] which was + generated at the very beginning. This removes the need for defining the + type [mytree]. The trick is to override the method [visit_sometree] so as + to insert a delay at every tree node. *) + +module Variant1 = struct + + class ['self] reduce = object (self : 'self) + inherit [_] sometree_reduce as super + inherit [_] delayed_tree_monoid + method! visit_sometree visit_'a env t = + self#visit_delay (super#visit_sometree visit_'a) env t + end + + (* The rest of the code is unchanged. It is reproduced here for testing. *) + + class ['self] verbose_reduce = object (_ : 'self) + inherit [_] reduce as super + method! visit_Leaf visit_'a env = + Printf.printf "Visiting a leaf.\n%!"; + super#visit_Leaf visit_'a env + method! visit_Node visit_'a env t1 x t2 = + Printf.printf "Visiting a node.\n%!"; + super#visit_Node visit_'a env t1 x t2 + end + + let sometree_to_delayed_tree (t : 'a sometree) = + new verbose_reduce # visit_sometree yield () t + + let sometree_to_iterator (t : 'a sometree) : 'a iterator = + delayed_tree_to_iterator (sometree_to_delayed_tree t) + + let t : int sometree = + Node (Node (Leaf, 1, Leaf), 2, Node (Leaf, 3, Leaf)) + + let i : int iterator = + sometree_to_iterator t + +end + +(* -------------------------------------------------------------------------- *) + +module Variant2 = struct + + (* The function [delayed_tree_to_cascade] could have been written directly + as follows, without the auxiliary function [delayed_tree_to_head]: *) + + let rec _delayed_tree_to_cascade (dt : 'a delayed_tree) (k : 'a cascade) + : 'a cascade = + match dt with + | DTZero -> + k + | DTOne x -> + cons x k + | DTTwo (dt1, dt2) -> + _delayed_tree_to_cascade dt1 (_delayed_tree_to_cascade dt2 k) + | DTDelay dt -> + fun () -> _delayed_tree_to_cascade (force dt) k () + + (* In this form, [delayed_tree_to_cascade] is the only operation that is + ever applied to a delayed tree, so we can refunctionalize delayed trees, + that is, wherever we used to build a delayed tree [t], we now directly + build a closure that is equivalent to [delayed_tree_to_cascade t]. *) + + type 'a producer = + 'a cascade -> 'a cascade + + type 'a delayed_tree = + 'a producer + + let _DTZero k = + k + + let _DTOne x k = + cons x k + + let _DTTwo dt1 dt2 k = + dt1 (dt2 k) + + let _DTDelay dt k = + fun () -> force dt k () + + let (_ : 'a delayed_tree) = _DTZero + let (_ : 'a -> 'a delayed_tree) = _DTOne + let (_ : 'a delayed_tree -> 'a delayed_tree -> 'a delayed_tree) = _DTTwo + let (_ : (unit -> 'a delayed_tree) -> 'a delayed_tree) = _DTDelay + + let delayed_tree_to_cascade (dt : 'a delayed_tree) : 'a cascade = + dt nil + + let delayed_tree_to_iterator (dt : 'a delayed_tree) : 'a iterator = + cascade_to_iterator (delayed_tree_to_cascade dt) + + (* The delayed monoid uses the new constructors. In [plus], we lose the + little optimization whereby [DTZero] were recognized and eliminated on + the fly. *) + + class ['self] delayed_tree_monoid = object (_ : 'self) + + method zero = + _DTZero + + method plus = + _DTTwo + + method visit_delay: 'env 'a . + ('env -> 'a -> 'b delayed_tree) -> + 'env -> 'a delay -> 'b delayed_tree + = fun visit_'a env x -> + _DTDelay (fun () -> visit_'a env x) + + end + + let yield _env x = + _DTOne x + + (* The rest of the code is as before. It is reproduced here for testing. *) + + class ['self] reduce = object (self : 'self) + inherit [_] sometree_reduce as super + inherit [_] delayed_tree_monoid + method! visit_sometree visit_'a env t = + self#visit_delay (super#visit_sometree visit_'a) env t + end + + class ['self] verbose_reduce = object (_ : 'self) + inherit [_] reduce as super + method! visit_Leaf visit_'a env = + Printf.printf "Visiting a leaf.\n%!"; + super#visit_Leaf visit_'a env + method! visit_Node visit_'a env t1 x t2 = + Printf.printf "Visiting a node.\n%!"; + super#visit_Node visit_'a env t1 x t2 + end + + let sometree_to_delayed_tree (t : 'a sometree) = + new verbose_reduce # visit_sometree yield () t + + let sometree_to_iterator (t : 'a sometree) : 'a iterator = + delayed_tree_to_iterator (sometree_to_delayed_tree t) + + let t : int sometree = + Node (Node (Leaf, 1, Leaf), 2, Node (Leaf, 3, Leaf)) + + let i : int iterator = + sometree_to_iterator t + +end diff --git a/test/dictionary.ml b/test/dictionary.ml new file mode 100644 index 0000000..afd4fd7 --- /dev/null +++ b/test/dictionary.ml @@ -0,0 +1,14 @@ +(* Examples of mixing the monomorphic and polymorphic modes. *) + +(* with a monomorphic 'env : *) +type ('a, 'b) dictionary = + | Empty + | NonEmpty of 'a * 'b * ('a, 'b) dictionary +[@@deriving visitors { variety = "map"; polymorphic = ["'b"] }] + +(* with a polymorphic 'env : *) +(* dubious though, since the method [visit_'a] cannot use [env] *) +type ('a, 'b) dictionary2 = + | Empty + | NonEmpty of 'a * 'b * ('a, 'b) dictionary2 +[@@deriving visitors { name = "map2"; variety = "map"; polymorphic = ["'b"; "'env"] }] diff --git a/test/dune b/test/dune new file mode 100644 index 0000000..37e2de0 --- /dev/null +++ b/test/dune @@ -0,0 +1,126 @@ +;; Some files must be preprocessed by cppo. +(rule + (targets cloud.ml) + (deps cloud.cppo.ml) + (action (run %{bin:cppo} -V OCAML:%{ocaml_version} %{deps} -o %{targets}))) +(rule + (targets test02.ml) + (deps test02.cppo.ml) + (action (run %{bin:cppo} -V OCAML:%{ocaml_version} %{deps} -o %{targets}))) +(rule + (targets testallprims.ml) + (deps testallprims.cppo.ml) + (action (run %{bin:cppo} -V OCAML:%{ocaml_version} %{deps} -o %{targets}))) +(rule + (targets VisitorsRuntimeBootstrap.ml) + (deps VisitorsRuntimeBootstrap.cppo.ml) + (action (run %{bin:cppo} -V OCAML:%{ocaml_version} %{deps} -o %{targets}))) + +(executable + (name bench) + (modules bench) + (preprocess (pps visitors.ppx)) + (libraries core_bench) +) + +(library + (name snippets_basic) + (preprocess (pps visitors.ppx)) + (flags -w A-4-34-44) + (modules + point build + cloud + delayed_tree + dictionary + expr00 + expr00endo + expr00fold + expr00fold2 + expr01 + expr01use + expr01use_variant + expr02 + expr03 + expr04 + expr05lexico + expr05lexico_test + expr05 + expr06 + expr11 + expr15b + expr15c + expr15 + expr16 + expr17 + expr_info_mapreduce + expr_info_mapreduce_test + expr_info_mapreduce_use + expr_info + expr_info_polymorphic + expr_info_polymorphic_use + expr_info_polymorphic_use_test + expr_info_use + expr + expr_redef + fold + map_from_fold + mapReduce + monomorphic + monopoly + oexpr_polymorphic + OOinferfixedagaincheck + OOinferfixedagain + OOinferfixed + OOinfer + OOinferself + OOinfervirtual + opaque + polyclass + prefixes + test00 + test01 + test02 + test03 + test04 + test05 + test06 + test07 + testallprims + VisitorsRuntimeBootstrap + ) +) + +(library + (name snippets_that_need_hashcons) + (preprocess (pps visitors.ppx)) + (flags -w A-4-34-44) + (libraries hashcons) + (modules + expr08 + expr08double + expr08extra + expr12 + expr13double + expr13extra + expr13 + expr14 + hexpr_polymorphic + ) +) + +;; (library +;; (name snippets_that_need_ppx_import) +;; (preprocess (pps visitors.ppx)) +;; (flags -w A-4-34-44) +;; (libraries ppx_import) +;; (modules +;; expr_import +;; expr_import_opaque +;; ) +;; ) + +(library + (name cil) + (modules cil_types cil_types_polymorphic) + (preprocess (pps visitors.ppx)) +) diff --git a/test/expr.ml b/test/expr.ml new file mode 100644 index 0000000..3d11133 --- /dev/null +++ b/test/expr.ml @@ -0,0 +1,3 @@ +type expr = + | EConst of int + | EAdd of expr * expr diff --git a/test/expr00.ml b/test/expr00.ml new file mode 100644 index 0000000..0867bcd --- /dev/null +++ b/test/expr00.ml @@ -0,0 +1,4 @@ +type expr = + | EConst of int + | EAdd of expr * expr + [@@deriving visitors { variety = "iter" }] diff --git a/test/expr00.mli b/test/expr00.mli new file mode 100644 index 0000000..2c5c2ed --- /dev/null +++ b/test/expr00.mli @@ -0,0 +1,9 @@ +type expr = + | EConst of int + | EAdd of expr * expr + +class virtual ['self] iter : object ('self) + method visit_EAdd : 'monomorphic. 'env -> expr -> expr -> unit + method visit_EConst : 'monomorphic. 'env -> int -> unit + method visit_expr : 'monomorphic. 'env -> expr -> unit +end diff --git a/test/expr00endo.ml b/test/expr00endo.ml new file mode 100644 index 0000000..6b8ecde --- /dev/null +++ b/test/expr00endo.ml @@ -0,0 +1,4 @@ +type expr = + | EConst of int + | EAdd of expr * expr + [@@deriving visitors { variety = "endo" }] diff --git a/test/expr00fold.ml b/test/expr00fold.ml new file mode 100644 index 0000000..0d87d9f --- /dev/null +++ b/test/expr00fold.ml @@ -0,0 +1,4 @@ +type expr = + | EConst of (int[@opaque]) + | EAdd of expr * expr + [@@deriving visitors { variety = "fold" }] diff --git a/test/expr00fold2.ml b/test/expr00fold2.ml new file mode 100644 index 0000000..7a01203 --- /dev/null +++ b/test/expr00fold2.ml @@ -0,0 +1,4 @@ +type expr = + | EConst of (int[@opaque]) + | EAdd of expr * expr + [@@deriving visitors { variety = "fold2" }] diff --git a/test/expr01.ml b/test/expr01.ml new file mode 100644 index 0000000..7c6fec0 --- /dev/null +++ b/test/expr01.ml @@ -0,0 +1,4 @@ +type expr = + | EConst of int + | EAdd of expr * expr + [@@deriving visitors { variety = "map" }] diff --git a/test/expr01use.ml b/test/expr01use.ml new file mode 100644 index 0000000..557e19c --- /dev/null +++ b/test/expr01use.ml @@ -0,0 +1,25 @@ +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) + inherit [_] map + method! visit_EAdd env e1 e2 = + add + (self#visit_expr env e1) + (self#visit_expr env e2) + end in + o # visit_expr () + +let z e = EAdd (e, EConst 0) + +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_variant.ml b/test/expr01use_variant.ml new file mode 100644 index 0000000..42561f0 --- /dev/null +++ b/test/expr01use_variant.ml @@ -0,0 +1,20 @@ +open Expr01 + +let optimize : expr -> expr = + let o = object(self) + inherit [_] map + method! visit_EAdd env e1 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 () + +let z e = EAdd (e, EConst 0) + +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/expr02.ml b/test/expr02.ml new file mode 100644 index 0000000..05270da --- /dev/null +++ b/test/expr02.ml @@ -0,0 +1,4 @@ +type expr = + | EConst of int + | EAdd of expr * expr + [@@deriving visitors { variety = "iter2"; concrete = true }] diff --git a/test/expr03.ml b/test/expr03.ml new file mode 100644 index 0000000..a20f164 --- /dev/null +++ b/test/expr03.ml @@ -0,0 +1,4 @@ +type expr = + | EConst of int + | EAdd of expr * expr + [@@deriving visitors { variety = "map2" }] diff --git a/test/expr04.ml b/test/expr04.ml new file mode 100644 index 0000000..b1815cb --- /dev/null +++ b/test/expr04.ml @@ -0,0 +1,13 @@ +open Expr00 + +let count (e : expr) : int = + let v = object + val mutable count = 0 + method count = count + inherit [_] iter as super + method! visit_EAdd env e0 e1 = + count <- count + 1; + super#visit_EAdd env e0 e1 + end in + v#visit_expr () e; + v#count diff --git a/test/expr05.ml b/test/expr05.ml new file mode 100644 index 0000000..e0d7e2e --- /dev/null +++ b/test/expr05.ml @@ -0,0 +1,4 @@ +open Expr02 + +let equal : expr -> expr -> bool = + VisitorsRuntime.wrap2 (new iter2 # visit_expr ()) diff --git a/test/expr05lexico.ml b/test/expr05lexico.ml new file mode 100644 index 0000000..bb8c3cc --- /dev/null +++ b/test/expr05lexico.ml @@ -0,0 +1,20 @@ +open Expr02 + +let tag : expr -> int = function + | EConst _ -> 0 + | EAdd _ -> 1 + +exception Different of int + +let compare (i1 : int) (i2 : int) : unit = + if i1 <> i2 then + raise (Different (if i1 < i2 then -1 else 1)) + +class compare = object + inherit [_] iter2 + method! visit_int _ i1 i2 = compare i1 i2 + method! fail_expr () e1 e2 = compare (tag e1) (tag e2) +end + +let compare (e1 : expr) (e2 : expr) : int = + try new compare # visit_expr () e1 e2; 0 with Different c -> c diff --git a/test/expr05lexico_test.ml b/test/expr05lexico_test.ml new file mode 100644 index 0000000..3ed4385 --- /dev/null +++ b/test/expr05lexico_test.ml @@ -0,0 +1,11 @@ +open Expr02 +open Expr05lexico + +let () = + assert (compare (EConst 1) (EConst 2) = -1); + assert (compare (EConst 1) (EAdd (EConst 0, EConst 0)) = -1); + assert (compare (EAdd (EConst 0, EConst 0)) (EConst 1) = +1); + assert (compare (EAdd (EConst 0, EConst 0)) (EAdd (EConst 0, EConst 0)) = 0); + assert (compare (EAdd (EConst 0, EConst 0)) (EAdd (EConst 0, EConst 1)) = -1); + assert (compare (EAdd (EConst 1, EConst 0)) (EAdd (EConst 0, EConst 1)) = +1); + () diff --git a/test/expr06.ml b/test/expr06.ml new file mode 100644 index 0000000..966079f --- /dev/null +++ b/test/expr06.ml @@ -0,0 +1,16 @@ +type unop = + | UnaryMinus + +and binop = + | BinaryMinus + | BinaryAdd + | BinaryMul + | BinaryDiv + +and expr = + | EConst of int + | EUnOp of unop * expr + | EBinOp of expr * binop * expr + +[@@deriving visitors { variety = "iter" }, + visitors { variety = "map" }] diff --git a/test/expr08.ml b/test/expr08.ml new file mode 100644 index 0000000..ea885f0 --- /dev/null +++ b/test/expr08.ml @@ -0,0 +1,18 @@ +open Expr12 (* oexpr *) + +open Hashcons + +type hexpr = + H of hexpr oexpr hash_consed [@@unboxed] + +let table = + create 128 + +let h (e : hexpr oexpr) : hexpr = + H (hashcons table e) + +class ['self] hmap = object (self : 'self) + inherit [_] omap + method visit_'expr env (H { node = e; _ }) = + h (self#visit_oexpr env e) +end diff --git a/test/expr08double.ml b/test/expr08double.ml new file mode 100644 index 0000000..35ec2b3 --- /dev/null +++ b/test/expr08double.ml @@ -0,0 +1,10 @@ +open Expr12 (* [oexpr] *) +open Expr08 (* [hexpr] *) + +let double : hexpr -> hexpr = + let v = object + inherit [_] hmap + method! visit_EConst _env k = + EConst (2 * k) + end in + v # visit_'expr () diff --git a/test/expr08extra.ml b/test/expr08extra.ml new file mode 100644 index 0000000..4890675 --- /dev/null +++ b/test/expr08extra.ml @@ -0,0 +1,15 @@ +open Expr12 +open Expr08 +open Expr08double + +let econst e = h (EConst e) +let eadd e1 e2 = h (EAdd (e1, e2)) + +let e1 : hexpr = eadd (econst 0) (econst 1) +let e2 : hexpr = new hmap # visit_'expr () e1 (* identity *) +let () = + Printf.printf "%b\n%!" (e1 == e2) (* should print true *) +let e3 : hexpr = eadd (econst 0) (econst 2) +let e4 : hexpr = double e1 (* should produce [e3] *) +let () = + Printf.printf "%b\n%!" (e3 == e4) (* should print true *) diff --git a/test/expr11.ml b/test/expr11.ml new file mode 100644 index 0000000..3794b68 --- /dev/null +++ b/test/expr11.ml @@ -0,0 +1,4 @@ +type expr = + | EConst of int + | EAdd of expr list + [@@deriving visitors { variety = "iter" }] diff --git a/test/expr12.ml b/test/expr12.ml new file mode 100644 index 0000000..9c56040 --- /dev/null +++ b/test/expr12.ml @@ -0,0 +1,4 @@ +type 'expr oexpr = + | EConst of int + | EAdd of 'expr * 'expr + [@@deriving visitors { name = "omap"; variety = "map" }] diff --git a/test/expr13.ml b/test/expr13.ml new file mode 100644 index 0000000..cd8e3ba --- /dev/null +++ b/test/expr13.ml @@ -0,0 +1,10 @@ +open Expr12 + +type expr = + E of expr oexpr [@@unboxed] + +class ['self] map = object (self : 'self) + inherit [_] omap + method visit_'expr env (E e) = + E (self#visit_oexpr env e) +end diff --git a/test/expr13double.ml b/test/expr13double.ml new file mode 100644 index 0000000..17fa976 --- /dev/null +++ b/test/expr13double.ml @@ -0,0 +1,10 @@ +open Expr12 +open Expr13 + +let double : expr -> expr = + let v = object + inherit [_] map + method! visit_EConst _env k = + EConst (2 * k) + end in + v # visit_'expr () diff --git a/test/expr13extra.ml b/test/expr13extra.ml new file mode 100644 index 0000000..05304c5 --- /dev/null +++ b/test/expr13extra.ml @@ -0,0 +1,26 @@ +open Expr12 +open Expr13 +open Expr13double + +let const k = E (EConst k) +let add e1 e2 = E (EAdd (e1, e2)) + +let rec eval (E e) = + match e with + | EConst k -> k + | EAdd (e1, e2) -> eval e1 + eval e2 + +let e : expr = + add (const 1) (const 2) + +let () = + (* should print: 3 then 6 *) + Printf.printf "%d\n%d\n%!" (eval e) (eval (double e)) + +let omap : 'expr1 'expr2 . ('expr1 -> 'expr2) -> 'expr1 oexpr -> 'expr2 oexpr = + fun f e -> + let v = object + inherit [_] omap + method visit_'expr _env e = f e + end in + v # visit_oexpr () e diff --git a/test/expr14.ml b/test/expr14.ml new file mode 100644 index 0000000..e5700b0 --- /dev/null +++ b/test/expr14.ml @@ -0,0 +1,20 @@ +open Hashcons +open Expr12 (* [oexpr] *) +open Expr13 (* [expr] *) +open Expr08 (* [hexpr] *) + +let import : expr -> hexpr = + let v = object (self) + inherit [_] omap + method visit_'expr _env (E e) = + h (self#visit_oexpr _env e) + end in + v # visit_'expr () + +let export : hexpr -> expr = + let v = object (self) + inherit [_] omap + method visit_'expr _env (H { node = e; _ }) = + E (self#visit_oexpr _env e) + end in + v # visit_'expr () diff --git a/test/expr15.ml b/test/expr15.ml new file mode 100644 index 0000000..a20c709 --- /dev/null +++ b/test/expr15.ml @@ -0,0 +1,4 @@ +type expr = + | EConst of (int[@opaque]) + | EAdd of expr * expr + [@@deriving visitors { variety = "reduce" }] diff --git a/test/expr15b.ml b/test/expr15b.ml new file mode 100644 index 0000000..b4adcc1 --- /dev/null +++ b/test/expr15b.ml @@ -0,0 +1,10 @@ +open Expr15 + +let size : expr -> int = + let v = object + inherit [_] reduce as super + inherit [_] VisitorsRuntime.addition_monoid + method! visit_expr env e = + 1 + super # visit_expr env e + end in + v # visit_expr () diff --git a/test/expr15c.ml b/test/expr15c.ml new file mode 100644 index 0000000..18204a5 --- /dev/null +++ b/test/expr15c.ml @@ -0,0 +1,5 @@ +open Expr15 +open Expr15b + +let () = + Printf.printf "%d\n" (size (EAdd (EConst 22, EConst 11))) diff --git a/test/expr16.ml b/test/expr16.ml new file mode 100644 index 0000000..bba189c --- /dev/null +++ b/test/expr16.ml @@ -0,0 +1,4 @@ +type expr = + | EConst of int + | EAdd of expr * expr + [@@deriving visitors { variety = "iter"; public = ["visit_expr"] }] diff --git a/test/expr17.ml b/test/expr17.ml new file mode 100644 index 0000000..8dcb51f --- /dev/null +++ b/test/expr17.ml @@ -0,0 +1,4 @@ +type expr = + | EConst of (int[@opaque]) + | EAdd of expr * expr +[@@deriving visitors { variety = "mapreduce" }] diff --git a/test/expr_import.ml b/test/expr_import.ml new file mode 100644 index 0000000..ef3acc8 --- /dev/null +++ b/test/expr_import.ml @@ -0,0 +1,3 @@ +type expr = + [%import: Expr.expr] + [@@deriving visitors { variety = "iter" }] diff --git a/test/expr_import_opaque.ml b/test/expr_import_opaque.ml new file mode 100644 index 0000000..966949a --- /dev/null +++ b/test/expr_import_opaque.ml @@ -0,0 +1,3 @@ +type expr = + [%import: Expr.expr [@with int := int[@opaque]]] + [@@deriving visitors { variety = "iter" }] diff --git a/test/expr_info.ml b/test/expr_info.ml new file mode 100644 index 0000000..a07d126 --- /dev/null +++ b/test/expr_info.ml @@ -0,0 +1,8 @@ +type 'info expr_node = + | EConst of int + | EAdd of 'info expr * 'info expr + +and 'info expr = + { info: 'info; node: 'info expr_node } + +[@@deriving visitors { variety = "map" }] diff --git a/test/expr_info_mapreduce.ml b/test/expr_info_mapreduce.ml new file mode 100644 index 0000000..05ee19e --- /dev/null +++ b/test/expr_info_mapreduce.ml @@ -0,0 +1,8 @@ +type 'info expr_node = + | EConst of int + | EAdd of 'info expr * 'info expr + +and 'info expr = + { info: 'info; node: 'info expr_node } + +[@@deriving visitors { variety = "mapreduce" }] diff --git a/test/expr_info_mapreduce_test.ml b/test/expr_info_mapreduce_test.ml new file mode 100644 index 0000000..e92f521 --- /dev/null +++ b/test/expr_info_mapreduce_test.ml @@ -0,0 +1,29 @@ +open Expr_info_mapreduce +open Expr_info_mapreduce_use + +let mk node = { info = (); node } + +let const i = + mk (EConst i) + +let add e1 e2 = + mk (EAdd (e1, e2)) + +let e = + add (const 1) (add (const 0) (const 3)) + +let (e : int expr) = + annotate e + +let () = + assert (e.info = 5); + begin match e.node with + | EAdd (e1, e2) -> + assert (e1.info = 1); + assert (e2.info = 3); + () + | EConst _ -> + assert false + end; + Printf.printf "OK\n%!"; + () diff --git a/test/expr_info_mapreduce_use.ml b/test/expr_info_mapreduce_use.ml new file mode 100644 index 0000000..8442b88 --- /dev/null +++ b/test/expr_info_mapreduce_use.ml @@ -0,0 +1,15 @@ +open Expr_info_mapreduce + +let annotate (e : _ expr) : int expr = + let v = object + inherit [_] mapreduce as super + inherit [_] VisitorsRuntime.addition_monoid + method! visit_expr env { info = _; node } = + let node, size = super#visit_expr_node env node in + let size = size + 1 in + { info = size; node }, size + method visit_'info _env _info = + assert false (* never called *) + end in + let e, _ = v # visit_expr () e in + e diff --git a/test/expr_info_polymorphic.ml b/test/expr_info_polymorphic.ml new file mode 100644 index 0000000..22d3167 --- /dev/null +++ b/test/expr_info_polymorphic.ml @@ -0,0 +1,9 @@ +type 'info expr_node = + | EConst of int + | EAdd of 'info expr * 'info expr + +and 'info expr = + { info: 'info; node: 'info expr_node } + +[@@deriving visitors { variety = "map"; polymorphic = true; + concrete = true; data = false }] diff --git a/test/expr_info_polymorphic_use.ml b/test/expr_info_polymorphic_use.ml new file mode 100644 index 0000000..8680910 --- /dev/null +++ b/test/expr_info_polymorphic_use.ml @@ -0,0 +1,15 @@ +open Expr_info_polymorphic + +let v = new map + +let strip : _ expr -> unit expr = + let visit_'info _env _info = () in + fun e -> + v # visit_expr visit_'info () e + +let number : _ expr -> int expr = + let visit_'info count _info = + let c = !count in count := c + 1; c in + fun e -> + let count = ref 0 in + v # visit_expr visit_'info count e diff --git a/test/expr_info_polymorphic_use_test.ml b/test/expr_info_polymorphic_use_test.ml new file mode 100644 index 0000000..a415811 --- /dev/null +++ b/test/expr_info_polymorphic_use_test.ml @@ -0,0 +1,27 @@ +open Expr_info_polymorphic +open Expr_info_polymorphic_use + +let strip : 'a . 'a expr -> unit expr = strip +let number : 'a . 'a expr -> int expr = number + +let mk node = { info = (); node } + +let const i = + mk (EConst i) + +let add e1 e2 = + mk (EAdd (e1, e2)) + +let e = + add (const 1) (add (const 0) (const 3)) + +let e = number (strip e) + +let () = + assert (e.info = 0); + match e.node with + | EAdd (e1, e2) -> + assert (e1.info = 1); + assert (e2.info = 2) + | _ -> + assert false diff --git a/test/expr_info_use.ml b/test/expr_info_use.ml new file mode 100644 index 0000000..c82d224 --- /dev/null +++ b/test/expr_info_use.ml @@ -0,0 +1,17 @@ +open Expr_info + +let strip (e : _ expr) : unit expr = + let v = object + inherit [_] map + method visit_'info _env _info = () + end in + v # visit_expr () e + +let number (e : _ expr) : int expr = + let v = object + inherit [_] map + val mutable count = 0 + method visit_'info _env _info = + let c = count in count <- c + 1; c + end in + v # visit_expr () e diff --git a/test/expr_redef.ml b/test/expr_redef.ml new file mode 100644 index 0000000..aef646f --- /dev/null +++ b/test/expr_redef.ml @@ -0,0 +1,4 @@ +type expr = Expr.expr = + | EConst of int + | EAdd of expr * expr + [@@deriving visitors { variety = "iter" }] diff --git a/test/fold.ml b/test/fold.ml new file mode 100644 index 0000000..713c312 --- /dev/null +++ b/test/fold.ml @@ -0,0 +1,18 @@ +type person = { + firstname: string[@opaque]; + surname: string[@opaque] +} + +and crowd = + | Nobody + | Someone of person * crowd +[@@deriving visitors { variety = "fold" }] + +let convert : crowd -> (string * string) list = + let v = object + inherit [_] fold + method build_person () f s = (f, s) + method build_Nobody () = [] + method build_Someone () p c = p :: c + end + in v # visit_crowd () diff --git a/test/hexpr_polymorphic.ml b/test/hexpr_polymorphic.ml new file mode 100644 index 0000000..74e2531 --- /dev/null +++ b/test/hexpr_polymorphic.ml @@ -0,0 +1,52 @@ +open Hashcons + +module VisitorsHashcons = struct + + (* We CAN implement the method [visit_hash_consed], but this method requires + a hash-consing table. We assume that this table is stored in the field + [_table], which we declare virtual. *) + + (* A key subtlety is that the method [visit_hash_consed] must be monomorphic + in ['b]. Indeed, we cannot hope to build values of type ['b hash_consed] + for every ['b]. We can only hope to build values of type ['b hash_consed] + for a fixed ['b], where the hash-consing table has type ['b Hashcons.t]. + For now, the type ['b] is undetermined. It will be fixed in a subclass, + where the field [_table] is initialized. *) + + class virtual ['self] map = object (_ : 'self) + val virtual _table: 'b Hashcons.t + method visit_hash_consed: 'env 'a . + ('env -> 'a -> 'b) -> + 'env -> 'a hash_consed -> 'b hash_consed + = fun visit_'a env { node = e; _ } -> + hashcons _table (visit_'a env e) + end + +end + +(* This allows us to define the types [expr] and [hexpr] and generate a + visitor class for them. *) + +type 'expr oexpr = + | EConst of int + | EAdd of 'expr * 'expr + +and hexpr = + H of hexpr oexpr hash_consed [@@unboxed] + +[@@deriving visitors { variety = "map"; polymorphic = ["'expr"]; + ancestors = ["VisitorsHashcons.map"] }] + +(* Once the type [hexpr] is defined, we can allocate a table. *) + +let table : hexpr oexpr Hashcons.t = + Hashcons.create 128 + +(* Inheriting [map] and defining [_table] yields a working visitor. *) + +let id : hexpr -> hexpr = + let o = object + inherit [_] map + val _table = table + end in + o # visit_hexpr () diff --git a/test/mapReduce.ml b/test/mapReduce.ml new file mode 100644 index 0000000..fc59730 --- /dev/null +++ b/test/mapReduce.ml @@ -0,0 +1,9 @@ +type t = int * bool + +and u = { x: t; y: t } + +and expr = + | A + | B of t +[@@deriving visitors { variety = "mapreduce" }, + visitors { variety = "mapreduce2" }] diff --git a/test/map_from_fold.ml b/test/map_from_fold.ml new file mode 100644 index 0000000..dab99ad --- /dev/null +++ b/test/map_from_fold.ml @@ -0,0 +1,37 @@ +(* Direct definitions of [map], [reduce], and [fold]. *) +class virtual ['self] reduce = object (self: 'self) + method private visit_option: 'a . + ('env -> 'a -> 'z) -> 'env -> 'a option -> 'z + = fun f env ox -> + match ox with None -> self#zero | Some x -> f env x + method private virtual zero: 'z +end +class ['self] map = object (_ : 'self) + method private visit_option: 'a 'b . + ('env -> 'a -> 'b) -> 'env -> 'a option -> 'b option + = fun f env ox -> + match ox with None -> None | Some x -> Some (f env x) +end +class virtual ['self] fold = object (self : 'self) + method private visit_option: 'a . + ('env -> 'a -> 'r) -> 'env -> 'a option -> 's + = fun f env ox -> + match ox with + | None -> self#build_None env + | Some x -> self#build_Some env (f env x) + method private virtual build_None: 'env -> 's + method private virtual build_Some: 'env -> 'r -> 's +end +(* A successful definition of [reduce] in terms of [fold]. *) +class virtual ['self] reduce_from_fold = object (self : 'self) + inherit [_] fold + method private build_None _env = self#zero + method private build_Some _env z = z + method private virtual zero: 'z +end +(* An unsatisfactory definition of [map] in terms of [fold]. *) +class ['self] map_from_fold = object (_ : 'self) + inherit [_] fold + method private build_None _env = None + method private build_Some _env x = Some x +end diff --git a/test/map_from_fold.mli b/test/map_from_fold.mli new file mode 100644 index 0000000..9c6263d --- /dev/null +++ b/test/map_from_fold.mli @@ -0,0 +1,6 @@ +class ['self] map_from_fold : object ('self) + method private visit_option : 'a . + ('env -> 'a -> 'b) -> 'env -> 'a option -> 'b option + method private build_None : 'env -> 'b option + method private build_Some : 'env -> 'b -> 'b option +end diff --git a/test/monomorphic.ml b/test/monomorphic.ml new file mode 100644 index 0000000..553a0f1 --- /dev/null +++ b/test/monomorphic.ml @@ -0,0 +1,11 @@ +type 'a t = + | Leaf of 'a + | Node of 'a t * ('a * 'a) t +[@@deriving visitors { variety = "map"; monomorphic = ["'env"] }] + +let o = object + inherit [_] map + method! visit_Leaf visit_'a env x = + let env = (env : int) in (* check that ['env] is not quantified *) + Leaf (visit_'a env x) +end diff --git a/test/monopoly.ml b/test/monopoly.ml new file mode 100644 index 0000000..67fd9f1 --- /dev/null +++ b/test/monopoly.ml @@ -0,0 +1,18 @@ +type ('a, 'b) data = + | DataNil + | DataCons of 'a * 'b * ('a, 'b) data + +and 'a seq = +| Nil +| Zero of ('a * 'a) seq +| One of 'a * ('a * 'a) seq + +[@@deriving visitors { variety = "iter"; polymorphic = ["a"] }, + visitors { variety = "map"; polymorphic = ["a"] }, + visitors { variety = "endo"; polymorphic = ["a"] }, + visitors { variety = "reduce"; polymorphic = ["a"] }, + visitors { variety = "mapreduce"; polymorphic = ["a"] }, + visitors { variety = "iter2"; polymorphic = ["a"] }, + visitors { variety = "map2"; polymorphic = ["a"] }, + visitors { variety = "reduce2"; polymorphic = ["a"] }, + visitors { variety = "mapreduce2"; polymorphic = ["a"] }] diff --git a/test/oexpr_polymorphic.ml b/test/oexpr_polymorphic.ml new file mode 100644 index 0000000..585ed4d --- /dev/null +++ b/test/oexpr_polymorphic.ml @@ -0,0 +1,21 @@ +(* Defining open expressions + and closing them, + in one go, + in [polymorphic] mode. *) + +type 'expr oexpr = + | EConst of int + | EAdd of 'expr * 'expr + +and expr = + E of expr oexpr [@@unboxed] + +[@@deriving visitors { variety = "map"; polymorphic = true; concrete = true }] + +let double : expr -> expr = + let v = object + inherit [_] map + method! visit_EConst _ _env k = + EConst (2 * k) + end in + v # visit_expr () diff --git a/test/opaque.ml b/test/opaque.ml new file mode 100644 index 0000000..d59f499 --- /dev/null +++ b/test/opaque.ml @@ -0,0 +1,21 @@ +type hop = position[@opaque] + +and position = { + pos_fname : string[@opaque]; + pos_lnum : int * (int[@opaque]); + pos_bol : int; + pos_cnum : int; + foo: (int[@opaque]) list; + } +and foo = + | A of (int[@opaque]) * int + | B of bool +[@@deriving + visitors { variety = "iter" }, + visitors { variety = "map" }, + visitors { variety = "reduce" }, + visitors { variety = "endo" }, + visitors { variety = "iter2" }, + visitors { variety = "map2" }, + visitors { variety = "reduce2" } +] diff --git a/test/point.ml b/test/point.ml new file mode 100644 index 0000000..151ac5d --- /dev/null +++ b/test/point.ml @@ -0,0 +1,4 @@ +type point = + { x: int; y: int } + +let make x y = { x; y } diff --git a/test/point.mli b/test/point.mli new file mode 100644 index 0000000..dca6c3e --- /dev/null +++ b/test/point.mli @@ -0,0 +1,2 @@ +type point = private { x: int; y: int } +val make: int -> int -> point diff --git a/test/polyclass.ml b/test/polyclass.ml new file mode 100644 index 0000000..4f7772e --- /dev/null +++ b/test/polyclass.ml @@ -0,0 +1,8 @@ +class ['self] c = object (_ : 'self) + method identity (x : 'a) : 'a = x +end + +let b : bool = + new c # identity true +let i : int = + new c # identity 0 diff --git a/test/prefixes.ml b/test/prefixes.ml new file mode 100644 index 0000000..5705855 --- /dev/null +++ b/test/prefixes.ml @@ -0,0 +1,23 @@ +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 diff --git a/test/test00.ml b/test/test00.ml new file mode 100644 index 0000000..f2a84c1 --- /dev/null +++ b/test/test00.ml @@ -0,0 +1,11 @@ +type u = Uber + and point = u * u +[@@deriving + visitors { variety = "iter" }, + visitors { variety = "map" }, + visitors { variety = "reduce" }, + visitors { variety = "endo" }, + visitors { variety = "iter2" }, + visitors { variety = "map2" }, + visitors { variety = "reduce2" } +] diff --git a/test/test01.ml b/test/test01.ml new file mode 100644 index 0000000..dba7ac0 --- /dev/null +++ b/test/test01.ml @@ -0,0 +1,11 @@ +type point = + { x: int; y: int; mutable color: bool } +[@@deriving + visitors { variety = "iter" }, + visitors { variety = "map" }, + visitors { variety = "reduce" }, + visitors { variety = "endo" }, + visitors { variety = "iter2" }, + visitors { variety = "map2" }, + visitors { variety = "reduce2" } +] diff --git a/test/test02.cppo.ml b/test/test02.cppo.ml new file mode 100644 index 0000000..d2e4605 --- /dev/null +++ b/test/test02.cppo.ml @@ -0,0 +1,33 @@ +type term = + | TUnit + | TIntLiteral of int + | TVar of string + | TLambda of string * term + | TApp of term * term +#if OCAML_VERSION >= (4, 03, 0) + | TPair of { fst: term; snd: term } +#endif + | TTuple of term_list + +and term_list = + | TLNil + | TLCons of (term * term_list) + +[@@deriving + visitors { variety = "iter"; concrete = true }, + visitors { variety = "map"; concrete = true }, + visitors { variety = "reduce"; concrete = true; ancestors = ["VisitorsRuntime.addition_monoid"] }, + visitors { variety = "endo"; concrete = true }, + visitors { variety = "iter2"; concrete = true }, + visitors { variety = "map2"; concrete = true }, + visitors { variety = "reduce2"; concrete = true; ancestors = ["VisitorsRuntime.addition_monoid"] } +] + +let identity : term = + TLambda ("x", TVar "x") + +let () = + new iter#visit_term 33 identity + +let () = + new iter#visit_term 33 (new map#visit_term () identity) diff --git a/test/test03.ml b/test/test03.ml new file mode 100644 index 0000000..064f627 --- /dev/null +++ b/test/test03.ml @@ -0,0 +1,63 @@ +type ('var, 'binder) term = + | TVar of 'var + | TAbs of 'binder * ('var, 'binder) term + | TApp of ('var, 'binder) term * ('var, 'binder) term +[@@deriving + visitors { variety = "iter" }, + visitors { variety = "map" }, + visitors { variety = "reduce" }, + visitors { variety = "endo" }, + visitors { variety = "iter2" }, + visitors { variety = "map2" }, + visitors { variety = "reduce2" } +] + +(* Nominal. *) + +module StringSet = Set.Make(String) + +let iter = object(self) + inherit [_] iter + (* Descending methods for local types. *) + method! visit_TAbs env x t = + let env = StringSet.add x env in + self#visit_term env t + (* Descending methods for nonlocal types. *) + method visit_'binder _env _x = () + method visit_'var env x = + if StringSet.mem x env then + Printf.printf "%s is a bound variable.\n%!" x + else + Printf.printf "%s is a free variable.\n%!" x + +end + +let t : (_, _) term = + TAbs ("x", TApp (TVar "x", TVar "y")) + +let () = + iter#visit_term StringSet.empty t + +(* De Bruijn. *) + +let iter = object(self) + inherit [_] iter + (* Descending methods for local types. *) + method! visit_TAbs env _x t = + let env = 1 + env in + self#visit_term env t + (* Descending methods for nonlocal types. *) + method visit_'binder _env _x = () + method visit_'var env x = + if x < env then + Printf.printf "%d is a bound variable.\n%!" x + else + Printf.printf "%d is a free variable.\n%!" x + +end + +let t : (_, _) term = + TAbs ((), TApp (TVar 0, TVar 1)) + +let () = + iter#visit_term 0 t diff --git a/test/test04.ml b/test/test04.ml new file mode 100644 index 0000000..9f64099 --- /dev/null +++ b/test/test04.ml @@ -0,0 +1,16 @@ +type 'info expr_node = + | EConst of int + | EAdd of 'info expr * 'info expr + +and 'info expr = + { info: 'info; node: 'info expr_node } + +[@@deriving visitors { variety = "iter"; polymorphic = true }, + visitors { variety = "map"; polymorphic = true }, + visitors { variety = "endo"; polymorphic = true }, + visitors { variety = "reduce"; polymorphic = true }, + visitors { variety = "mapreduce"; polymorphic = true }, + visitors { variety = "iter2"; polymorphic = true }, + visitors { variety = "map2"; polymorphic = true }, + visitors { variety = "reduce2"; polymorphic = true }, + visitors { variety = "mapreduce2"; polymorphic = true }] diff --git a/test/test05.ml b/test/test05.ml new file mode 100644 index 0000000..baf60ae --- /dev/null +++ b/test/test05.ml @@ -0,0 +1,16 @@ +(* Testing that @opaque is properly detected. *) + +module T = struct + type t = A of ((int -> int)[@deriving.visitors.opaque]) + [@@deriving visitors { variety = "map" }] +end + +module U = struct + type u = B of ((int -> int)[@visitors.opaque]) + [@@deriving visitors { variety = "map" }] +end + +module V = struct + type w = C of ((int -> int)[@opaque]) + [@@deriving visitors { variety = "map" }] +end diff --git a/test/test06.ml b/test/test06.ml new file mode 100644 index 0000000..21d4424 --- /dev/null +++ b/test/test06.ml @@ -0,0 +1,38 @@ +(* Testing @name attributes on data constructors. *) + +type foo = + | A [@name "TA"] + | B of int [@name "TB"] + | C of int * int [@name "TC"] +[@@deriving visitors { variety = "map"; concrete = true }, + visitors { variety = "fold"; ancestors = ["VisitorsRuntime.map"] }] + +let f (x : foo) = + let o = object + inherit [_] map + method! visit_TA _env = B 0 + method! visit_TB _env x = B (x + 1) + method! visit_TC _env x y = C (x, x + y) + end in + o # visit_foo () x + +let () = + assert (f A = B 0); + assert (f (B 0) = B 1); + assert (f (C (1, 1)) = C (1, 2)); + () + +let g (x : foo) : int = + let o = object + inherit [_] fold + method build_TA _env = 42 + method build_TB _env x = x + method build_TC _env x y = x + y + end in + o # visit_foo () x + +let () = + assert (g A = 42); + assert (g (B 12) = 12); + assert (g (C (1, 1)) = 2); + () diff --git a/test/test07.ml b/test/test07.ml new file mode 100644 index 0000000..5e9f109 --- /dev/null +++ b/test/test07.ml @@ -0,0 +1,49 @@ +(* Testing @name attributes on data types. *) + +(* Testing local types decorated with [@@name]. *) + +module Point = struct + + type point = { x : coordinate; y : coordinate } [@@name "foo"] + + and coordinate = float [@@name "coord"] + + [@@deriving visitors { variety = "map"; concrete = true }, + visitors { variety = "fold"; ancestors = ["VisitorsRuntime.map"]}] + + let f (p : point) = + let o = new map in + o # visit_foo () p + + let () = + assert (f { x = 0.; y = 0. } = { x = 0.; y = 0. }); + () + + let g (p : point) : float = + let o = object + inherit [_] fold + method build_coord _env x = x + method build_foo _env x y = x +. y + end in + o # visit_foo () p + + let () = + assert (g { x = 1.; y = 2. } = 3.); + () + +end + +type boolean = Vrai | Faux [@@name "condition"] +[@@deriving visitors { variety = "iter2"; concrete = true }] + +let () = + try + new iter2 # fail_condition () Vrai Faux; + assert false + with VisitorsRuntime.StructuralMismatch -> + () + +(* Testing nonlocal types decorated with [@name]. *) + +type segment = { source: Point.point[@name "foo"]; destination: Point.point[@name "foo"] } +[@@deriving visitors { variety = "map"; concrete = true; nude = true; ancestors = ["Point.map"] }] diff --git a/test/testallprims.cppo.ml b/test/testallprims.cppo.ml new file mode 100644 index 0000000..238c4b8 --- /dev/null +++ b/test/testallprims.cppo.ml @@ -0,0 +1,30 @@ +type t = + | Array of t array + | Bool of bool + | Bytes of bytes + | Char of char + | Float of float + | Int of int + | Int32 of int32 + | Int64 of int64 + | Lazy of t lazy_t + | List of t list + | Nativeint of nativeint + | Option of t option + | Ref of t ref +#if OCAML_VERSION >= (4, 08, 0) + | Result of (t, t) result +#endif + | String of string + | Unit of unit + | Tuple2 of (t * t) + | Tuple3 of (t * t * t) +[@@deriving + visitors { variety = "iter"; concrete = true }, + visitors { variety = "map"; concrete = true }, + visitors { variety = "reduce"; ancestors=["VisitorsRuntime.addition_monoid"]; concrete = true }, + visitors { variety = "endo"; concrete = true }, + visitors { variety = "iter2"; concrete = true }, + visitors { variety = "map2"; concrete = true }, + visitors { variety = "reduce2"; ancestors=["VisitorsRuntime.addition_monoid"]; concrete = true } +] diff --git a/visitors.opam b/visitors.opam new file mode 100644 index 0000000..f83fdd8 --- /dev/null +++ b/visitors.opam @@ -0,0 +1,24 @@ +opam-version: "2.0" +maintainer: "francois.pottier@inria.fr" +authors: [ + "François Pottier " +] +homepage: "https://gitlab.inria.fr/fpottier/visitors" +dev-repo: "git+https://gitlab.inria.fr/fpottier/visitors.git" +bug-reports: "francois.pottier@inria.fr" +build: [ + ["dune" "build" "-p" name "-j" jobs] +] +depends: [ + "ocaml" {>= "4.02.3" } + "cppo" {build} + "ppx_tools" + "ppx_deriving" {>= "4.4"} + "result" + "dune" {>= "2.0"} +] +synopsis: "An OCaml syntax extension for generating visitor classes" +description: """ +Annotating an algebraic data type definition with [@@deriving visitors { ... }] +causes visitor classes to be automatically generated. A visitor is an object +that knows how to traverse and transform a data structure.""" -- cgit v1.2.3