diff options
143 files changed, 31587 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..80a7f4c --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*~ +_build +.merlin +*.processed.ml +doc/manual.pdf +dune-workspace.versions @@ -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..83289db --- /dev/null +++ b/CHANGES.md @@ -0,0 +1,133 @@ +# Changes + +## 2021/06/08 + +* Replace a reference to the `Parser` module in `ppxlib` with a reference to + the `Parser` module in `compiler-libs`, so as to remain compatible with the + next version of `ppxlib` (> 0.22.0), where the type `token` is abstract. + (Contributed by Sonja Heinze.) + +## 2021/01/27 + +* Switch to version 0.22.0 of `ppxlib`, which internally uses the abstract + syntax tree of OCaml 4.12. + (Contributed by Sonja Heinze.) + +* Relax our requirement from OCaml 4.07 to OCaml 4.05. + +## 2021/01/27 + +* Switch to version 5.0 of `ppx_deriving`. + (At present, this implies requiring OCaml 4.07, but this may be relaxed + to OCaml 4.05 in the future, I am told.) + Depend on `ppxlib` instead of `ppx_tools`. + Remove the dependency on `cppo`. + (Contributed by Kate Deplaix.) + +## 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.<variety>`. + +## 2017/02/15 + +* `Makefile.preprocess` is now installed with the package, so users can rely on it + without needing to copy it. See the documentation for instructions. + +## 2017/02/13 + +* Added a new variety of visitors, `mapreduce`. This visitor computes a pair of a + data structure (like a `map` visitor) and a summary (like a `reduce` visitor). + This can be used to annotate every tree node with information about the + subtree that lies below it. See the documentation for an example. + +## 2017/02/09 + +* Documentation: added a new subsection on OCaml objects, + entitled "Where the expressiveness of OCaml's type system falls short". + This section explains why `map` cannot be a subclass of `fold`, + even though it should be. + +## 2017/01/31 + +* Documentation: added an example of constructing a lexicographic ordering. + +* Documentation: discussed generating visitors for existing types and `ppx_import`. + +## 2017/01/26 + +* Initial release. @@ -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. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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. + + <signature of Ty Coon>, 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..655c7aa --- /dev/null +++ b/Makefile.preprocess @@ -0,0 +1,46 @@ +# 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 + @ echo Preprocessing $<... + @ $(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/changelog b/debian/changelog index db45044..db45044 100644 --- a/changelog +++ b/debian/changelog diff --git a/copyright b/debian/copyright index fa1ca82..fa1ca82 100644 --- a/copyright +++ b/debian/copyright diff --git a/gbp.conf b/debian/gbp.conf index cec628c..cec628c 100644 --- a/gbp.conf +++ b/debian/gbp.conf diff --git a/libppx-visitors-ocaml-doc.doc-base b/debian/libppx-visitors-ocaml-doc.doc-base index 1931a08..1931a08 100644 --- a/libppx-visitors-ocaml-doc.doc-base +++ b/debian/libppx-visitors-ocaml-doc.doc-base diff --git a/libppx-visitors-ocaml-doc.docs b/debian/libppx-visitors-ocaml-doc.docs index 56a14e1..56a14e1 100644 --- a/libppx-visitors-ocaml-doc.docs +++ b/debian/libppx-visitors-ocaml-doc.docs diff --git a/patches/series b/debian/patches/series index e69de29..e69de29 100644 --- a/patches/series +++ b/debian/patches/series diff --git a/source/format b/debian/source/format index 163aaf8..163aaf8 100644 --- a/source/format +++ b/debian/source/format diff --git a/tests/control b/debian/tests/control index dceeccc..dceeccc 100644 --- a/tests/control +++ b/debian/tests/control diff --git a/tests/weight b/debian/tests/weight index b5b614b..b5b614b 100755 --- a/tests/weight +++ b/debian/tests/weight diff --git a/tests/weight.ml b/debian/tests/weight.ml index 33eb9b1..33eb9b1 100644 --- a/tests/weight.ml +++ b/debian/tests/weight.ml diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 0000000..4eb332a --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1,27 @@ +# 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 +*.synctex.gz diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000..e7eaa77 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,22 @@ +export VISITORS_BUILDING_DOCUMENTATION=true + +include ../Makefile.preprocess + +export TEXINPUTS=.:../test:../test/ppx_import: + +SOURCEDIRS := ../test,../test/ppx_import +ML := $(shell ls {$(SOURCEDIRS)}/*.ml | grep -v cppo | grep -v processed) +PROCESSED := $(patsubst %.ml,%.processed.ml,$(ML)) + +.PHONY: all loop clean sources + +all: sources + latexmk -g -pdf manual + +loop: sources + latexmk -pdf -pvc manual + +clean: + rm -f *.log *.aux *.bbl *.blg *.out *.toc *~ manual.pdf + +sources: $(wildcard *.tex) $(wildcard *.bib) $(wildcard *.sty) $(ML) $(PROCESSED) 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 Binary files differnew file mode 100644 index 0000000..26c55d7 --- /dev/null +++ b/doc/manual.pdf diff --git a/doc/manual.tex b/doc/manual.tex new file mode 100644 index 0000000..60b4e53 --- /dev/null +++ b/doc/manual.tex @@ -0,0 +1,2410 @@ +\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 <other-flags> %.inferred.mli| +\end{quote} +% TEMPORARY explain how to it using Dune + +\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 \ppximport and \visitors simultaneously, +if you are using \dune, +include +\verb+(preprocess (staged_pps ppx_import visitors.ppx))+ +in your \texttt{dune} file.) +% 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{<variety>} 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|<variety>|. +\\ + \nude & (Boolean) & + If \texttt{true}, the class \runtime{<variety>} 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|<variety>|, +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{<variety>} (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{<variety>}, please consult \runtimeFile{VisitorsRuntime.ml}. + +In the following, the index~\oc|i| ranges from 0 (included) to \oc|<arity>| +(excluded), where \oc|<arity>| 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|<get: int>| 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..32d6e86 --- /dev/null +++ b/doc/version.tex @@ -0,0 +1 @@ +\gdef\visitorsversion{20210608} @@ -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..5b5e1ff --- /dev/null +++ b/dune-project @@ -0,0 +1,12 @@ +(lang dune 2.0) +(name visitors) +(version 20210608) +(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..75c28e9 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,3 @@ +.PHONY: all +all: + @ dune build @check diff --git a/src/Visitors.ml b/src/Visitors.ml new file mode 100644 index 0000000..f28925f --- /dev/null +++ b/src/Visitors.ml @@ -0,0 +1,1288 @@ +open VisitorsString +open VisitorsList +open Ppxlib +open List +open Asttypes +open Parsetree +open Ast_helper +open Ppx_deriving.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_exn 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 (Ocaml_common.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 (Longident.last_exn 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 cd.pcd_args with + (* A traditional data constructor. *) + | Pcstr_tuple 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. *) + | Pcstr_record lds -> + let labels, tys = ld_labels lds, ld_tys lds in + 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, (NoVariance, NoInjectivity) ] 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..4e951a9 --- /dev/null +++ b/src/VisitorsAnalysis.ml @@ -0,0 +1,408 @@ +open Ppxlib +open Result +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. *) + +(* 2021/06/08 By default, [Parser] would be [Ppxlib.Parser], which exposes the + type [token] as an abstract type. Because we need the type [token] to be + concrete, we use [Ocaml_common.Parser] instead. [Ocaml_common] is part of + compiler-libs. *) + +type classification = + | LIDENT + | UIDENT + | OTHER + +let classify (s : string) : classification = + let lexbuf = Lexing.from_string s in + let backup = !Ocaml_common.Location.formatter_for_warnings in + let null = Format.formatter_of_buffer (Buffer.create 0) in + Ocaml_common.Location.formatter_for_warnings := null; + let result = try + let token1 = Lexer.token lexbuf in + let token2 = Lexer.token lexbuf in + let module Parser = Ocaml_common.Parser in + match token1, token2 with + | Parser.LIDENT _, Parser.EOF -> + LIDENT + | Parser.UIDENT _, Parser.EOF -> + UIDENT + | _, _ -> + OTHER + with Lexer.Error _ -> + OTHER + in + Ocaml_common.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 and check that every piece is a valid module name. *) + +(* We used to use [Longident.parse] to do the splitting, but this function has + been deprecated as of 4.11.0, and its suggested replacements do not go as + far back in time as we need. So, we use our own variant of this code. *) + +let rec parse s n = + (* Parse the substring that extends from offset 0 to offset [n] excluded. *) + try + let i = String.rindex_from s (n - 1) '.' in + let segment = String.sub s (i + 1) (n - (i + 1)) in + Ldot (parse s i, segment) + with Not_found -> + Lident (String.sub s 0 n) + +let parse s = + parse s (String.length s) + +let is_valid_mod_longident (m : string) : bool = + String.length m > 0 && + let ms = Longident.flatten_exn (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 parse m with + | Lident c -> + classify c = LIDENT + | Ldot (m, c) -> + List.for_all (fun m -> classify m = UIDENT) (Longident.flatten_exn 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 * injectivity)) : 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.ml b/src/VisitorsCompatibility.ml new file mode 100644 index 0000000..0e8450b --- /dev/null +++ b/src/VisitorsCompatibility.ml @@ -0,0 +1,103 @@ +let mknoloc = Location.mknoloc +open Ppxlib +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 was initially created + to gather the ugly bits whose definition varies depending on the version of + OCaml that we are working with. That said, since we have switched to using + ppxlib, my understanding is that we always work with the latest version of + the AST. More precisely, the version of the AST that we get no longer + depends on which OCaml compiler we are using; it depends on which version + of ppxlib we are using. At the time of writing, we depend on ppxlib 0.9.0 + or newer, which implies that we get an AST for OCaml 4.08 or newer. See + https://github.com/ocaml-ppx/ppxlib/blob/master/CHANGES.md *) + +(* 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 + +(* [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 + +(* 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 = + string Location.loc + +let string2str (s : string) : str = + mknoloc s + +let str2string (s : str) : string = + s.txt + +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. *) + +let object_field_to_core_type (field : object_field) : core_type = + match field.pof_desc 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 *) + +let row_field_to_core_types (field : row_field) : core_type list = + match field.prf_desc with + | Rtag (_, _, tys) -> + tys + | Rinherit ty -> + [ ty ] + +(* -------------------------------------------------------------------------- *) + +(* [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 + Str.attribute (Attr.mk name payload) diff --git a/src/VisitorsGeneration.ml b/src/VisitorsGeneration.ml new file mode 100644 index 0000000..a7f28ec --- /dev/null +++ b/src/VisitorsGeneration.ml @@ -0,0 +1,586 @@ +open Ppxlib +let mknoloc = Ocaml_common.Location.mknoloc +open Asttypes +open Parsetree +open Ast_helper +open Ppx_deriving.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 (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 <w>] <items> 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 * injectivity)) 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 () : 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 * injectivity)) 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 = Stdlib.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 () : 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 := 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..9910463 --- /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 Stdlib.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..f7b7d1d --- /dev/null +++ b/src/VisitorsSettings.ml @@ -0,0 +1,371 @@ +open Result +open VisitorsString +open List +let sprintf = Printf.sprintf +open Ppxlib +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.<scheme>] 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 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..89914ca --- /dev/null +++ b/src/dune @@ -0,0 +1,22 @@ +(library + (name ppx_deriving_visitors) + (public_name visitors.ppx) + (synopsis "Compile-time support for generating visitors") + (kind ppx_deriver) + (libraries result compiler-libs.common ppxlib ppx_deriving.api) + (ppx_runtime_libraries visitors.runtime) +) + +(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 <necula@cs.berkeley.edu> *) +(* Scott McPeak <smcpeak@cs.berkeley.edu> *) +(* Wes Weimer <weimer@cs.berkeley.edu> *) +(* Ben Liblit <liblit@cs.berkeley.edu> *) +(* 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(<type>). 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(<expression>) *) + + | 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 <necula@cs.berkeley.edu> *) +(* Scott McPeak <smcpeak@cs.berkeley.edu> *) +(* Wes Weimer <weimer@cs.berkeley.edu> *) +(* Ben Liblit <liblit@cs.berkeley.edu> *) +(* 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(<type>). 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(<expression>) *) + + | 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 <necula@cs.berkeley.edu> *) +(* Scott McPeak <smcpeak@cs.berkeley.edu> *) +(* Wes Weimer <weimer@cs.berkeley.edu> *) +(* Ben Liblit <liblit@cs.berkeley.edu> *) +(* 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(<type>). 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(<expression>) *) + + | 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..4778e54 --- /dev/null +++ b/test/dune @@ -0,0 +1,115 @@ +;; 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 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_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/ppx_import/dune b/test/ppx_import/dune new file mode 100644 index 0000000..22320bf --- /dev/null +++ b/test/ppx_import/dune @@ -0,0 +1,11 @@ +(library + (name snippets_that_need_ppx_import) + (preprocess (staged_pps ppx_import visitors.ppx)) + (flags -w A-4-34-44) + (libraries ppx_import) + (modules + expr + expr_import + expr_import_opaque + ) +) diff --git a/test/ppx_import/expr.ml b/test/ppx_import/expr.ml new file mode 100644 index 0000000..3d11133 --- /dev/null +++ b/test/ppx_import/expr.ml @@ -0,0 +1,3 @@ +type expr = + | EConst of int + | EAdd of expr * expr diff --git a/test/ppx_import/expr_import.ml b/test/ppx_import/expr_import.ml new file mode 100644 index 0000000..ef3acc8 --- /dev/null +++ b/test/ppx_import/expr_import.ml @@ -0,0 +1,3 @@ +type expr = + [%import: Expr.expr] + [@@deriving visitors { variety = "iter" }] diff --git a/test/ppx_import/expr_import_opaque.ml b/test/ppx_import/expr_import_opaque.ml new file mode 100644 index 0000000..966949a --- /dev/null +++ b/test/ppx_import/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/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..bf77582 --- /dev/null +++ b/visitors.opam @@ -0,0 +1,23 @@ +opam-version: "2.0" +maintainer: "francois.pottier@inria.fr" +authors: [ + "François Pottier <francois.pottier@inria.fr>" +] +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.05.0"} + "ppxlib" {>= "0.22.0"} + "ppx_deriving" {>= "5.0"} + "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.""" |