pax_global_header00006660000000000000000000000064146770755120014530gustar00rootroot0000000000000052 comment=5586c575342ba9f068dd7b940fbf770820f57a28 ocaml-ocaml-re-5586c57/000077500000000000000000000000001467707551200146105ustar00rootroot00000000000000ocaml-ocaml-re-5586c57/.github/000077500000000000000000000000001467707551200161505ustar00rootroot00000000000000ocaml-ocaml-re-5586c57/.github/dependabot.yml000066400000000000000000000001601467707551200207750ustar00rootroot00000000000000version: 2 updates: - package-ecosystem: github-actions directory: / schedule: interval: weekly ocaml-ocaml-re-5586c57/.github/workflows/000077500000000000000000000000001467707551200202055ustar00rootroot00000000000000ocaml-ocaml-re-5586c57/.github/workflows/gh-pages.yml000066400000000000000000000020661467707551200224270ustar00rootroot00000000000000name: Deploy odoc to GitHub Pages on: push: branches: - master permissions: read-all concurrency: group: deploy-odoc cancel-in-progress: true jobs: deploy-odoc: name: Deploy odoc to GitHub Pages environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} permissions: contents: read id-token: write pages: write runs-on: ubuntu-latest steps: - name: Checkout tree uses: actions/checkout@v4 - name: Set-up OCaml uses: ocaml/setup-ocaml@v3 with: ocaml-compiler: "5.2" - name: Install dependencies run: opam install . --deps-only --with-doc - name: Build documentation run: opam exec -- dune build @doc - name: Set-up Pages uses: actions/configure-pages@v5 - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: path: _build/default/_doc/_html - name: Deploy odoc to GitHub Pages id: deployment uses: actions/deploy-pages@v4 ocaml-ocaml-re-5586c57/.github/workflows/main.yml000066400000000000000000000011341467707551200216530ustar00rootroot00000000000000name: build on: - push - pull_request jobs: run: name: Build strategy: matrix: os: - macos-latest - ubuntu-latest - windows-latest ocaml-compiler: - "4.14" - "5.2" runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - uses: ocaml/setup-ocaml@v3 with: ocaml-compiler: ${{ matrix.ocaml-compiler }} - run: opam install . --deps-only --with-test - run: opam install core_bench core_unix - run: opam exec -- dune build - run: opam exec -- dune runtest ocaml-ocaml-re-5586c57/.github/workflows/nix.yml000066400000000000000000000004771467707551200215360ustar00rootroot00000000000000name: Nix on: - push - pull_request jobs: tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: submodules: true - uses: cachix/install-nix-action@v29 with: nix_path: nixpkgs=channel:nixos-unstable - run: nix develop -c dune runtest ocaml-ocaml-re-5586c57/.gitignore000066400000000000000000000002121467707551200165730ustar00rootroot00000000000000.*.swp _build/ *.bak setup.data setup.log setup.exe *.native *.byte *.docdir .merlin *.install perf.data *.old *.ctf *.bench.sexp *.trace ocaml-ocaml-re-5586c57/.ocamlformat000066400000000000000000000000671467707551200171200ustar00rootroot00000000000000version=0.26.2 profile=janestreet ocaml-version=4.08.0 ocaml-ocaml-re-5586c57/.travis.yml000066400000000000000000000004641467707551200167250ustar00rootroot00000000000000language: c sudo: required install: wget https://raw.githubusercontent.com/ocaml/ocaml-ci-scripts/master/.travis-opam.sh script: bash -ex .travis-opam.sh env: global: - PACKAGE=re matrix: - OCAML_VERSION=4.03 - OCAML_VERSION=4.04 - OCAML_VERSION=4.05 - OCAML_VERSION=4.06 os: - linux - osx ocaml-ocaml-re-5586c57/CHANGES.md000066400000000000000000000133021467707551200162010ustar00rootroot000000000000001.13.1 (30-Sep-2024) -------------------- * Fix re on jsoo (#150) 1.13.0 (30-Sep-2024) -------------------- * Add non raising versions of all [Re.Group] functions (#414, fixes #150) * Add support for hex and octal of the form: `\o{...}` and `\x{...}` (#403) * Add support for octal characters using `\0dd` and `\ddd` (#402) * Add support for `\Q...\E` quoted expressions in Pcre and Perl syntax (#401) * Re.execp and related function raise [Invalid_argument "$function"] when [pos] or [len] arguments are out of bounds. In 1.12.0, a regerssion was introduced that raised [Invalid_argument _] from [String.get]. 1.12.0 (29-Aug-2024) -------------------- * Add `Re.split_delim` (#233) * Fix handling of empty matches in splitting and substitution functions (#233) * Add support for character classes in `Re.Posix` (#263) 1.11.0 (19-Aug-2023) -------------------- * Add `Re.group_count` to get the number of groups in a compiled regex (#218) * Add `Re.exec_partial_detailed` to allow resuming searches from partial inputs (#219) * Re-export `Re.Perl`'s `Parse_error` and `Not_supported` exceptions in Pcre (#222) * Add support for `DOTALL` flag in `Re.Pcre.regexp` (#225) * Add support for named groups (#223) * Add support for some control characters in `Re.Perl` (#227) 1.10.4 (27-Apr-2022) -------------------- * Improve handling of word boundaries (#179) 1.10.3 (13-Sep-2021) -------------------- * Glob: change optional argument `?backslash_escapes` to `?match_backslashes`. The interpretation of backslashes in the glob pattern remains unchanged with the new option, but forward slashes match backslashes when activated (#199) 1.10.2 (09-Sep-2021) -------------------- * Fix missing aliases introduced in 1.10.1 1.10.1 (08-Sep-2021) -------------------- * Glob: add optional argument `?backslash_escapes` to control interpretation of backslashes (useful under Windows) (#197, #198) * Restore accidentally deleted `*_seq` deprecated aliases. 1.10.0 (25-Aug-2021) -------------------- * Add the `[:alpha:]` character class in `Re.Perl` (#169) * Double asterisk (`**`) in `Re.Glob` (#172) Like `*` but also match `/` characters when `pathname` is set. * Double asterisk should match 0 or more directories unless in trailing position. (#192, fixes #185) 1.9.0 (05-Apr-2019) ------------------- * Fix regression in `Re.exec_partial` (#164) * Mov gen related functions to `Re.Gen` and deprecate the old names (#167) * Introduce `Re.View` that exposes the internal representation (#163) 1.8.0 (04-Aug-2018) ------------------- * Fix index-out-of-bounds exception in Re.Perl.re (#160) * Add seq based iterators (#170) 1.7.3 (05-Mar-2018) ------------------- * Remove dependency on bytes package (#155) 1.7.2 (01-Mar-2018) ------------------- * Deprecate all Re_* modules. Re_x is now available as Re.X * Deprecate all re.x sub libraries. Those are all available as Re.X * Make all function in Re.Str tail recursive. 1.7.1 (19-Oct-2016) ------------------- * Fix Re_str.global_replace (#132) 1.7.0 (18-Sep-2016) ------------------- * Fix stack overflow in Re_str.full_split * Use correct exceptions in Re_str group functions * Add experimental Re.witness * Add experimental Re.Group.nb_groups 1.6.1 (20-Jun-2016) ------------------- * Fix Re.pp (#101) * Add Re.Group.pp (#102) 1.6.0 (30-May-2016) ------------------- * Add Re.pp and Re.pp_re (#55) * Fix ocamldoc syntax (#87) 1.5.0 (04-Jan-2016) ------------------- * Add Re.exec_opt. Like exec but doesn't raise * Add Group module. Old group accessors are deprecated. * Add Mark module * Improve docs of Re.repn * Improve docs of Re_pcre * Fix doc of Re_pcre.match * Consolidate variants of Re.glob that takes options to modify its behavior (?period, ?expand_braces). Old variants are deprecated. * New option ?pathname added for Re_glob.glob. Controls how the `/` character is matched 1.4.1 (06-Jun-2015) ------------------- * Fix 4.00.1 compatibilty with tests. 1.4.0 (12-May-2015) ------------------- * Add Re.{mark,marked,mark_set}. Regexps can now be "marked" to query post execution if they matched. 1.3.2 (14-Apr-2015) ------------------- * Fix replacing 0 length matches (#55) 1.3.1 (13-Mar-2015) ------------------- * Rename {Cset, Automata} to {Re_cset, Re_automata} 1.3.0 (02-Feb-2015) ------------------- * Add Re.split{,_gen,_token,_full,_full_gen} * Add Re.replace{,_string} * Add Re.all{,_gen} * Add posix classes of the form [:xxx:] * Add complement suport for posix classes * Add Multiline and anchored flag to Re_pcre * Add Re_pcre.full_split 1.2.2 (05-May-2014) ------------------- * Add a Re.whole_string convenience function to only match whole strings * Add a ?anchored parameter to functions in Re_glob to specify whole string matching * Document Re_glob module * Fix compilation of submatches occurring inside a Kleen star * Fix word boundary matching * Fix definition of Re.xdigit * Fix Re.exec_partial function * Fix compilation of patterns of the shape r1r2|r1r3 * Fixed compilation of re.cmxs (Vincent Bernardoff) * Improved matching of anchored regular expressions: stop as soon as we know there cannot possibly be any match. * Updated to OASIS 0.4.x (Vincent Bernardoff) * Add the linking exception to the license 1.2.1 (07-Apr-2013) ------------------- * Correct OASIS metadata (Christophe Troestler). * Fix typo in Invalid_arg error message (Jeremy Yallop). 1.2.0 (15-Jan-2012) ------------------- * Rename Pcre module to `Re_pcre` to make it more suitable for upstream packaging (it currently conflicts with the `Pcre` package). (Mehdi Dogguy). 1.1.0 (05-Sep-2012) ------------------- * Add a basic Pcre wrapper around Re_perl for porting applications using that API (Thomas Gazagnaire). 1.0.0 (01-Aug-2012) ------------------- * Initial public release. ocaml-ocaml-re-5586c57/LICENSE.md000066400000000000000000000655121467707551200162250ustar00rootroot00000000000000This Software is distributed under the terms of the GNU Lesser General Public License version 2.1 (included below), or (at your option) any later version. As a special exception to the GNU Library General Public License, you may link, statically or dynamically, a "work that uses the Library" with a publicly distributed version of the Library to produce an executable file containing portions of the Library, and distribute that executable file under terms of your choice, without any of the additional requirements listed in clause 6 of the GNU Library General Public License. By "a publicly distributed version of the Library", we mean either the unmodified Library, or a modified version of the Library that is distributed under the conditions defined in clause 3 of the GNU Library General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU Library General Public License. ---------------------------------------------------------------------- GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! ocaml-ocaml-re-5586c57/Makefile000066400000000000000000000005041467707551200162470ustar00rootroot00000000000000DUNE ?= dune all: @$(DUNE) build test: @$(DUNE) runtest check: @$(DUNE) build @runtest @check .PHONY: check test all clean .PHONY: release release: ## Release on Opam dune-release distrib --skip-build --skip-lint --skip-tests dune-release publish distrib --verbose dune-release opam pkg dune-release opam submit ocaml-ocaml-re-5586c57/README.md000066400000000000000000000056021467707551200160720ustar00rootroot00000000000000Description =========== Re is a regular expression library for OCaml. [![Build status](https://github.com/ocaml/ocaml-re/actions/workflows/main.yml/badge.svg)](https://github.com/ocaml/ocaml-re/actions/workflows/main.yml) Contact ======= This library has been written by Jerome Vouillon (Jerome.Vouillon@pps.univ-paris-diderot.fr). It can be downloaded from Bug reports, suggestions and contributions are welcome. Features ======== The following styles of regular expressions are supported: - Perl-style regular expressions (module `Re.Perl`); - Posix extended regular expressions (module `Re.Posix`); - Emacs-style regular expressions (module `Re.Emacs`); - Shell-style file globbing (module `Re.Glob`). It is also possible to build regular expressions by combining simpler regular expressions (module `Re`). The most notable missing features are **back-references** and look-ahead/look-behind **assertions**. There is also a subset of the PCRE interface available in the `Re.Pcre` module. This makes it easier to port code from that library to Re with minimal changes. Performances ============ The matches are performed by lazily building a DFA (deterministic finite automaton) from the regular expression. As a consequence, matching takes linear time in the length of the matched string. The compilation of patterns is slower than with libraries using back-tracking, such as PCRE. But, once a large enough part of the DFA is built, matching is extremely fast. Of course, for some combinations of regular expression and string, the part of the DFA that needs to be build is so large that this point is never reached, and matching will be slow. This is not expected to happen often in practice, and actually a lot of expressions that behaves badly with a backtracking implementation are very efficient with this implementation. The library is at the moment entirely written in OCaml. As a consequence, regular expression matching is much slower when the library is compiled to bytecode than when it is compiled to native code. Here are some timing results (Pentium III 500Mhz): * Scanning a 1Mb string containing only `a`s, except for the last character which is a `b`, searching for the pattern `aa?b` (repeated 100 times): - RE: 2.6s - PCRE: 68s * Regular expression example from http://www.bagley.org/~doug/shootout/ [1] - RE: 0.43s - PCRE: 3.68s [1] this page is no longer up but is available via the Internet Archive http://web.archive.org/web/20010429190941/http://www.bagley.org/~doug/shootout/bench/regexmatch/ * The large regular expression (about 2000 characters long) that Unison uses with my preference file to decide whether a file should be ignored or not. This expression is matched against a filename about 20000 times. - RE: 0.31s - PCRE: 3.7s However, RE is only faster than PCRE when there are more than about 300 filenames. ocaml-ocaml-re-5586c57/TODO.txt000066400000000000000000000046531467707551200161260ustar00rootroot00000000000000* To compile r{i,j} we need a sequence that does not match epsilon (or a constructor around an expression telling that this expression does not match epsilon) * A subexpression repeated by an asterisk ( '*' ) or an interval expression shall not match a null expression unless this is the only match for the repetition or it is necessary to satisfy the exact or minimum number of occurrences for the interval expression. * There might be a typo in deriv_1/delta_1: should we generate 'TMatch mark' or 'TMatch mark'? (neither is correct!) POSIX: "(a?)*" "b" "" "(a?)*" "ab" "a" "((a)|(b))*" "ab" -> "b" none "b" Str "(a?)*" "b" no submatch "(a?)*" "ab" "a" "((a)|(b))*" "ab" -> "b" "a" "b" Javascript "(a?)*" "b" no submatch "(a?)*" "ab" "a" "((a)|(b))*" "ab" -> "b" none "b" PCRE "(a?)*" "b" "" "(a?)*" "ab" "" "(a?)*?" "b" "" "(a?)*?" "ab" "a" "((a)|(b))*" "ab" -> "b" "a" "b" Emacs "(a?)*" "b" "" "(a?)*" "ab" "" "(a?)*?" "b" "" "(a?)*?" "ab" "a" "((a)|(b))*" "ab" -> "b" "a" "b" r{0,0} = eps r{i+1,j+1} = r,r{i,j} r{0,j+1} = r,r{0,j} | eps PCRE/Emacs r{0,j+1} = (r-eps},r{0,j} | eps JavaScript * Rewrite sequences of sequences when possible... High priority ============= * Improve the Perl regular expressions parser * Character classes (in the three regular expression parsers) * Reduce memory usage - More compact representation of character sequences - Special notation for "anything but this set of characters" (more generally, optimize the compilation of regular expressions) * Simple optimisations - alt containing alt - epsilon elimination - Seq (Seq (x,y), z) => Seq (x, Seq (y, z)) under some circumstances (x or y has a fixed length) ... * Test suite Medium priority =============== * Implement back-references * Implement look-ahead and look-behind assertions Low priority ============ * Optimize the main loop for processor that are not register starved * Rewrite the main loops in C (but keep the option to compile a pure OCaml version) * Limit the size of the cached DFAs by removing states that have not been used recently * Documentation Other ideas =========== * It would be great to have a more generic interface (parameterized over some abstract tokens). * Compile checked printers parameterized over match groups (DRY for literal subexpressions) ocaml-ocaml-re-5586c57/benchmarks/000077500000000000000000000000001467707551200167255ustar00rootroot00000000000000ocaml-ocaml-re-5586c57/benchmarks/benchmark.ml000066400000000000000000000104161467707551200212130ustar00rootroot00000000000000open Core open Core_bench let str_20_zeroes = String.make 20 '0' let re_20_zeroes = Re.(str str_20_zeroes) let lots_of_a's = String.init 101 ~f:(function | 100 -> 'b' | _ -> 'a') ;; let lots_o_a's_re = Re.(seq [ char 'a'; opt (char 'a'); char 'b' ]) let media_type_re = let re = Re.Emacs.re ~case:true "[ \t]*\\([^ \t;]+\\)" in Re.(seq [ start; re ]) ;; (* Taken from https://github.com/rgrinberg/ocaml-uri/blob/903ef1010f9808d6f3f6d9c1fe4b4eabbd76082d/lib/uri.ml*) let uri_reference = Re.Posix.re "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?" ;; let uris = [ "https://google.com" ; "http://yahoo.com/xxx/yyy?query=param&one=two" ; "file:/random_crap" ] ;; let benchmarks = [ "20 zeroes", re_20_zeroes, [ str_20_zeroes ] ; "lots of a's", lots_o_a's_re, [ lots_of_a's ] ; "media type match", media_type_re, [ " foo/bar ; charset=UTF-8" ] ; "uri", uri_reference, uris ] ;; let test ~name re f = [ Bench.Test.create ~name (fun () -> f re) ; (let re () = let re = lazy (re ()) in Lazy.force re in Bench.Test.create ~name:(sprintf "%s (compiled)" name) (fun () -> f re)) ] ;; let exec_bench exec name (re : Re.t) cases = Bench.Test.create_group ~name (List.concat_map cases ~f:(fun data -> let name = let len = String.length data in if len > 70 then Printf.sprintf "%s .. (%d)" (String.sub data ~pos:0 ~len:10) len else data in let re () = Re.compile re in test ~name re (fun re -> ignore (exec (re ()) data)))) ;; let exec_bench_many exec name re cases = test ~name (fun () -> Re.compile re) (fun re -> let re = re () in List.iter cases ~f:(fun x -> ignore (exec re x))) ;; let string_traversal = let len = 1000 * 1000 in let s = String.make len 'a' in let re = let re = Re.Pcre.re "aaaaaaaaaaaaaaaaz" in fun () -> Re.compile re in test ~name:"string traversal from #210" re (fun re -> ignore (Re.execp (re ()) s ~pos:0)) ;; let compile_clean_star = let c = 'c' in let s = String.make 10_000 c in let re = Re.rep (Re.char 'c') in let re () = Re.compile re in test ~name:"kleene star compilation" re (fun re -> ignore (Re.execp (re ()) s)) ;; let benchmarks = let benches = List.map benchmarks ~f:(fun (name, re, cases) -> Bench.Test.create_group ~name [ exec_bench Re.exec "exec" re cases ; exec_bench Re.execp "execp" re cases ; exec_bench Re.exec_opt "exec_opt" re cases ]) in let http_benches = let open Http.Export in let manual = [ request, "no group"; request_g, "group" ] |> List.concat_map ~f:(fun (re, name) -> let re () = Re.compile re in test ~name re (fun re -> let re = re () in Http.read_all 0 re Http.requests)) |> Bench.Test.create_group ~name:"manual" in let many = [ test ~name:"execp no group" (fun () -> Re.compile requests) (fun re -> ignore (Re.execp (re ()) Http.requests)) ; test ~name:"all_gen" (fun () -> Re.compile requests_g) (fun re -> Http.requests |> Re.all (re ())) ] |> List.concat |> Bench.Test.create_group ~name:"auto" in Bench.Test.create_group ~name:"http" [ manual; many ] in benches @ [ [ exec_bench_many Re.execp "execp"; exec_bench_many Re.exec_opt "exec_opt" ] |> List.concat_map ~f:(fun f -> f Tex.ignore_re Tex.ignore_filesnames) |> Bench.Test.create_group ~name:"tex gitignore" ] @ [ http_benches ] @ string_traversal @ compile_clean_star @ Memory.benchmarks ;; let () = let benchmarks = match Sys.getenv "RE_BENCH_FILTER" with | None -> benchmarks | Some only -> let only = String.split ~on:',' only in let filtered = List.filter benchmarks ~f:(fun bench -> let name = Bench.Test.name bench in List.mem only name ~equal:String.equal) in (match filtered with | _ :: _ -> filtered | [] -> print_endline "No benchmarks to run. Your options are:"; List.iter benchmarks ~f:(fun bench -> let name = Bench.Test.name bench in Printf.printf "- %s\n" name); exit 1) in Command_unix.run (Bench.make_command benchmarks) ;; ocaml-ocaml-re-5586c57/benchmarks/dune000066400000000000000000000002311467707551200175770ustar00rootroot00000000000000(env (dev (flags (:standard -w -58)))) (executables (libraries re core base stdio threads core_bench core_unix.command_unix) (names benchmark)) ocaml-ocaml-re-5586c57/benchmarks/files000066400000000000000000001203641467707551200177600ustar00rootroot00000000000000./.merlin ./re_match.native ./lib ./lib/re-api.odocl ./lib/re_glob.mllib ./lib/re.mli ./lib/re_cset.ml ./lib/re_automata.ml ./lib/re.ml ./lib/re_emacs.mli ./lib/re_glob.mldylib ./lib/re_pcre.mli ./lib/re_perl.mldylib ./lib/re_posix.mli ./lib/re_perl.mli ./lib/re.mldylib ./lib/re_posix.mldylib ./lib/re_automata.mli ./lib/re_glob.ml ./lib/re_emacs.ml ./lib/re_pcre.mllib ./lib/re_glob.mli ./lib/re_str.mldylib ./lib/re.mllib ./lib/re_posix.mllib ./lib/re_pcre.ml ./lib/re_emacs.mldylib ./lib/META ./lib/re_pcre.mldylib ./lib/re_cset.mli ./lib/re_emacs.mllib ./lib/re_str.mli ./lib/re_perl.ml ./lib/re_fmt.ml ./lib/re_perl.mllib ./lib/re_posix.ml ./lib/re_str.ml ./lib/re_str.mllib ./lib_test ./lib_test/test_easy.ml ./lib_test/test_emacs.ml ./lib_test/re_match.ml ./lib_test/longest.c ./lib_test/pcre_match.ml ./lib_test/.cvsignore ./lib_test/test_glob.ml ./lib_test/fort_unit.mllib ./lib_test/test_perl.ml ./lib_test/fort_unit.ml ./lib_test/test_exec_iter.ml ./lib_test/perl_scan.pl ./lib_test/Input ./lib_test/scan.ml ./lib_test/fort_unit.mldylib ./lib_test/unison2.ml ./lib_test/META ./lib_test/unison.ml ./lib_test/test_pcre.ml ./lib_test/glob.ml ./lib_test/pcre_scan.ml ./lib_test/re_scan.ml ./lib_test/Makefile ./lib_test/test_str.ml ./lib_test/test_re.ml ./lib_test/unison3.ml ./setup.exe ./_oasis ./repl.ml ./test_perl.native ./setup.data ./test_re.native ./setup.ml ./benchmarks ./benchmarks/.merlin ./benchmarks/benchmark.ml ./benchmarks/.#files ./benchmarks/.#tex.gitignore ./.gitignore ./.git ./.git/COMMIT_EDITMSG ./.git/objects ./.git/objects/bd ./.git/objects/bd/7b4a58cc13ca497618e5f8eaa664727a489c14 ./.git/objects/04 ./.git/objects/04/a2c275e68174559191e1f03369472ab6cc79a6 ./.git/objects/04/266b2bfdc3cb6dd1557ddc6cca27dd1c2483de ./.git/objects/c3 ./.git/objects/c3/b0f3506b6efa82e7d8455a51c40f674e362019 ./.git/objects/ae ./.git/objects/ae/edba64f100def873a670083e7cc4dec013b461 ./.git/objects/ae/e951b55c41573ce87f3e1e9ed7af59cfd03465 ./.git/objects/ae/6fb476af3ed0c1c09bac3cca8825a1983f6baf ./.git/objects/80 ./.git/objects/80/c9e3062a7a04de5f4fac4e99402caa9b51a06a ./.git/objects/80/c8e9cfeb808e093b68db94016ed90c821111f7 ./.git/objects/pack ./.git/objects/pack/pack-866532c1406fa054e3eb4a18c69f02811d0d9218.pack ./.git/objects/pack/pack-866532c1406fa054e3eb4a18c69f02811d0d9218.idx ./.git/objects/ed ./.git/objects/ed/0f521c10cf8d6bff59836ec4ccbe7e5457833b ./.git/objects/7a ./.git/objects/7a/93d826a964cfcda511666ea90cae1c932fa420 ./.git/objects/7a/948d869ac1991341c6a809fff33fe6f7578176 ./.git/objects/7a/11dea700ff573997fa79ee6d720d8c36bb8c24 ./.git/objects/57 ./.git/objects/57/41501919c83c417773c4db93c40f064c01b9fa ./.git/objects/57/5df2075ef86ab5052cf3f640cfef0ade065079 ./.git/objects/c1 ./.git/objects/c1/b86cbaa2bc74068aa01996d5361165488ad90b ./.git/objects/d5 ./.git/objects/d5/fae05fd2c4e4319d1d8b72b47c5bf7c5c988bc ./.git/objects/d5/a493ad0448a01ef3b090cafa65e4052e3e3443 ./.git/objects/d5/18889bb8e29093ac8c151dbfb94ecdb55da37b ./.git/objects/c0 ./.git/objects/c0/3edfcb9c4d1ba4d5c714784719f2babc0d4bc2 ./.git/objects/ea ./.git/objects/ea/59fc8cae70bc30d4925b5d754d3eaa4c86fbe7 ./.git/objects/ea/96d0c79a09edde6fb5fdca45fad5eeb6b94a3b ./.git/objects/ea/d533485541976b0e8651823b48dd3b893fd7bf ./.git/objects/bf ./.git/objects/bf/9238d7470f96c20ef3b8ae9ae800c29a24b7d0 ./.git/objects/da ./.git/objects/da/5d5f8e2a5adf35ea1918972f87bae5ef20eba8 ./.git/objects/da/9d6c16f47466f0483a426802c81a4e2f105565 ./.git/objects/5d ./.git/objects/5d/68a2c24d022272086e02e201a34a7cc471a810 ./.git/objects/d1 ./.git/objects/d1/baa7c6cb5a197c2fa16d74d015cb65383befae ./.git/objects/d1/4a2f9a73098a607be995953a176a4c158eda31 ./.git/objects/a8 ./.git/objects/a8/385bd4963671a9f8e46367258ed74470230be8 ./.git/objects/a8/88411f7ae15f92b0a4f115b6a198bb9fca17eb ./.git/objects/a8/6354c21c4ea14488a7749ce9ca7319dfd7962d ./.git/objects/f8 ./.git/objects/f8/402f7182db519f40022913d9b7f545155e23da ./.git/objects/f8/fe27353f98e6449f9c140ed285c66111a83c8a ./.git/objects/32 ./.git/objects/32/7e89b0ce8c6c488a6052e2de5204ef89e2f507 ./.git/objects/32/46e88c270717153eee687e584c48c2b7611500 ./.git/objects/d3 ./.git/objects/d3/4bab001c846b49c144845ae06905122fc00d5b ./.git/objects/d3/14cca150738f34ec06d0a620746fa4b664d488 ./.git/objects/d3/c1b11ad75157f9b7976205c02c5017edbe91e5 ./.git/objects/7c ./.git/objects/7c/4fff7192504e558898de1a0a6a03f40b1ba383 ./.git/objects/7c/ca263ea8cf851ed5e6b620b1ac975a52cd1ab9 ./.git/objects/7c/c8bf775e67bee805e45e2c2de7292c060f31ce ./.git/objects/e3 ./.git/objects/e3/fee6d0fba12db992dab0c59f0c0af51e00f0cc ./.git/objects/73 ./.git/objects/73/e55a4522cb6094dbfa5259ea1246a80e3b8c40 ./.git/objects/73/7cc095a1c47d9895cf38d27633f8fde7024868 ./.git/objects/73/afa2a0065c795b73f8ac64879d85342765624a ./.git/objects/48 ./.git/objects/48/85f690a7e2bbf6c95ab017ebeddf13d4adbf01 ./.git/objects/48/a13cb1beef406dd4a4e2306e1e37f6836e4825 ./.git/objects/8c ./.git/objects/8c/a9e8d133eef4f47c05922233619de5a86ee4ab ./.git/objects/8c/df1c29071e45af80bf897cac73b4c1566e2d50 ./.git/objects/1b ./.git/objects/1b/9d5c43861498c1854465ac03e76a514d5cbaa8 ./.git/objects/50 ./.git/objects/50/ef8ba0f5817ad270ae921fea07bb8797b9c267 ./.git/objects/50/48505dcfbfd75f4bbad53bf5d71105215052c7 ./.git/objects/eb ./.git/objects/eb/31ab22a61ecfba506504fdf4b0f5cd28af2e11 ./.git/objects/eb/bf41561fdfffa8b973ad8c8d60c00907c59571 ./.git/objects/eb/dbd748cd4c6e3fcadd5087b9508a20a34c8125 ./.git/objects/ef ./.git/objects/ef/5f4e84fc1fb16d0e6a3b6402b2ef7b4ed4597f ./.git/objects/ca ./.git/objects/ca/67f392b19172f6bc90132ef568aeadff4c47e4 ./.git/objects/ca/9cd9a973452dcedfabe0bb1ee39eaa825856b7 ./.git/objects/ca/0249ae201624a0915b20a04f0bea1e88fbac12 ./.git/objects/c5 ./.git/objects/c5/531af344c2046d8887b5a8414fca0034be08c4 ./.git/objects/c5/c32cce665964562c01cb70dbd1d931d0fc9013 ./.git/objects/c5/dd991dc612c5cd22a26633a5ab5cb1e19065c3 ./.git/objects/75 ./.git/objects/75/c564016f8ebf5726272c3f624f8f607002bbda ./.git/objects/4e ./.git/objects/4e/f45ea3fd278fb84e61bb004f62beeb6e58a461 ./.git/objects/4e/af84d38158ff6aeab975f4b93bca267185ff75 ./.git/objects/cb ./.git/objects/cb/a0873bb0fb8cdd095efea7fc00d244d9f33dd6 ./.git/objects/6a ./.git/objects/6a/00cd81ccdbe607f9585878296c1e1e2c5b7cbd ./.git/objects/6a/93ab65f245de47a5a6c97f6b95e2b5ed93c6ce ./.git/objects/6a/521ac0a70a030b4570b17ce369ae7e0ccb5bcc ./.git/objects/6a/00c91ef0a06a2aa19cfb94ba06503cb1d0a2c5 ./.git/objects/e8 ./.git/objects/e8/4dc23cd8d2b83c0986002851ad228ca86f104b ./.git/objects/e8/ad3cd2087d55ff7928f7ad191a5c447a86a253 ./.git/objects/06 ./.git/objects/06/1a15896701e0696b9056e8c1f3ed0602b696c7 ./.git/objects/06/8886279674c32c6c0189ca0eb9ca3427b6a73f ./.git/objects/06/96d3afa20ddbad8c4e09ffc80da6a062ecca0f ./.git/objects/26 ./.git/objects/26/d94482417d0415bc3074d578ea15fa29bf61eb ./.git/objects/51 ./.git/objects/51/21ef81a3c018e7ece82b8fa53804f49b187e61 ./.git/objects/51/7475c493f88584541456158468830c728a385f ./.git/objects/f7 ./.git/objects/f7/e5d4ab3ab0b9b806b17f166db3de7cb83e16ba ./.git/objects/49 ./.git/objects/49/b13c62775b3f1ae207c1c7b937b8799d280a53 ./.git/objects/49/9613067efd80e477704c5752e2e24d16b685e5 ./.git/objects/e7 ./.git/objects/e7/71a89a26f22e59b14d4537f341206ae7e2dd59 ./.git/objects/5c ./.git/objects/5c/28f300f108705b0838519b16b64040e1753dac ./.git/objects/7d ./.git/objects/7d/24c5c18d327f576162279ec5c8d1040ae9f53a ./.git/objects/d0 ./.git/objects/d0/bdcf3a2e68cf891369b37c0bdafe5b3a8c3721 ./.git/objects/ad ./.git/objects/ad/dc2932430682c6f4aebf981bbdb60bd8650a46 ./.git/objects/5e ./.git/objects/5e/5a6c6e318cbcc56ac17c785e42512984a54ffe ./.git/objects/5e/65dfb3785145e3359094f2da9a9308ca89f95a ./.git/objects/5e/e61c21b52ad286753d76024e686ae2188f3d9c ./.git/objects/5e/7211f1f557ceea2922e95c9353344a7d8011eb ./.git/objects/60 ./.git/objects/60/825f155344cfac612ddb9aa4056cee1a3758fa ./.git/objects/60/df4d354a7d252d34d31d266064a498bae0c00e ./.git/objects/60/9434044eb5c63cfbe323346a76c37316f5d3cb ./.git/objects/68 ./.git/objects/68/7f8ea68a53e8a91694db6e8e19309c7aaff242 ./.git/objects/68/5de33ed341bc2e51a650f5c42f02a4cea86c74 ./.git/objects/68/ba3add2e2f20ff74ca504aa69a067269748796 ./.git/objects/68/54eba89564df3120ae33bd3905f70af0a9508e ./.git/objects/bb ./.git/objects/bb/26307254872961f81864ae695a2212da53e305 ./.git/objects/bb/0b632d318e1cc55446ab86264a943dc662dedf ./.git/objects/bb/04232d06b8b1b51d0313c76ecdf53fbb38b133 ./.git/objects/79 ./.git/objects/79/05fb61e4f1057e53188709c091739c2adabdce ./.git/objects/3b ./.git/objects/3b/6969415623e49b583fd9623a21269d16cf67d8 ./.git/objects/3b/a8e873cae0cd0d76051c8845a05ee7e5d6d2d1 ./.git/objects/24 ./.git/objects/24/18f0e1209770aeeb848a83fab8a87a5e9a3a86 ./.git/objects/24/4d94f9094fe4b391a781a7b5059d19233558c0 ./.git/objects/1a ./.git/objects/1a/a9a109bfb5e0100583062628741d37edbef198 ./.git/objects/cf ./.git/objects/cf/b4058d5efe88c7e11216de67c3ddecfaeb74c1 ./.git/objects/cf/ca9f3ec8ffd3a716e84a1816fd2f290aff45f3 ./.git/objects/cf/249dc6bf90a05272ea34a37c179695ec1679e8 ./.git/objects/41 ./.git/objects/41/7e9c7be145d7ce950e2634e24bdb7ead9eaf27 ./.git/objects/e0 ./.git/objects/e0/cf46969ea651e5939b9d5f048eaec3ec1de4c2 ./.git/objects/e0/56cae16e516031cd82e2190a7a021a95145026 ./.git/objects/e0/897837a3548051e45ac861ab417adf7c59829f ./.git/objects/e0/d97cc471e24acd66068a44308c7abff19b1925 ./.git/objects/91 ./.git/objects/91/a4117c6026321105e7a694173a05b2644d77c2 ./.git/objects/91/b1cee3be1539bb24a359d20d8a5e076a9cf30d ./.git/objects/fa ./.git/objects/fa/eb7cd164e1c586e7d45a09e0619cf9a74f54af ./.git/objects/fa/8e7262e1a26131ac68a1a911baca583f27dca4 ./.git/objects/fa/9de6a7c9f2dee85a1145e1fc4c5d1b570e964b ./.git/objects/2b ./.git/objects/2b/4c9ad40ba8fde41829a22e88bd26d38cd513f9 ./.git/objects/54 ./.git/objects/54/f717fa1d49e761b89e8f8097e8e3afde5cc6f7 ./.git/objects/54/f513d93e0e3263265c24591a7c874b53030436 ./.git/objects/b4 ./.git/objects/b4/6ae8881ee452f7a4ff0efb75bac923f36d14aa ./.git/objects/b4/8ffdfbe33be1dfd1783c8ff6b1e8fbe41db10d ./.git/objects/b4/e29997072acf52d882cfced7e85bb3b37460b5 ./.git/objects/b4/25a61759c2334ae65b46e56533f54804906c7a ./.git/objects/ac ./.git/objects/ac/1468dfa7da0b2fea46f17a3525c19feacdc1a1 ./.git/objects/ac/375885c60a0ea3a99d8bb439109c1fa895761d ./.git/objects/ac/fe49dc5da96f42f02493db63c143e2e2babad1 ./.git/objects/ac/6c0f696722f17907f137f4c7fad91e64f49dac ./.git/objects/e9 ./.git/objects/e9/cc98781f3762e4dd7e8be3b025723674999a31 ./.git/objects/1e ./.git/objects/1e/08112d5532b7b52a6d51270e73b5bf019ebd0a ./.git/objects/6c ./.git/objects/6c/e4e9093f07b21a48bb122f10a347e38eac84a3 ./.git/objects/03 ./.git/objects/03/fb2ad72c7a8427949a2bd42155098c7ba5292b ./.git/objects/b5 ./.git/objects/b5/3290a08b842bb02ec8b9a453ddcce593595285 ./.git/objects/1f ./.git/objects/1f/b018c263111f5612dff4a0714d133fa14b47d0 ./.git/objects/f5 ./.git/objects/f5/5fa50d15939fef068814d393f10c47d6c24df0 ./.git/objects/78 ./.git/objects/78/c2eef20df32f85b780af9ea5cda026a0c597ec ./.git/objects/05 ./.git/objects/05/c94e09c13c59b6b0313c670a3b2b05f104e9d5 ./.git/objects/05/6aa0e5511235422238f4944ab543c1339ba472 ./.git/objects/05/2233649e450bb03b929975139eeb624310852e ./.git/objects/05/0ac4c6759899cd6c1c48d74aaa8cdeb8802d67 ./.git/objects/05/5c86781ebb8d7466e996d2a953ffb2701160b7 ./.git/objects/3a ./.git/objects/3a/b09d8cd602c91f6b13418aedfc10c6dea50311 ./.git/objects/3a/0080d9bd9df6701481c73c108df8f8aba270d6 ./.git/objects/3f ./.git/objects/3f/121aca11150765ad412e552c38cb846cdf1b25 ./.git/objects/9d ./.git/objects/9d/c192d47b5c60f58ea01b6fbb3cac7f95355920 ./.git/objects/dc ./.git/objects/dc/81451f732d8886a46ba4be0eb8689c3ffa05ff ./.git/objects/dc/277721b85d2c24888d9b295d73e77dc0b56c47 ./.git/objects/11 ./.git/objects/11/f3056a841ad601f309f9bb45fd1e7a45bdc35a ./.git/objects/09 ./.git/objects/09/83adb85f1e3af304b3219d112d87868940bd34 ./.git/objects/09/9d1ab30c98206fe2cd21e5351e4e739ddca093 ./.git/objects/a6 ./.git/objects/a6/78884c9d14735ad62e6ffe8edeb237b153b31f ./.git/objects/90 ./.git/objects/90/d315297656082d1d3fa42398237e6fd7ca8b77 ./.git/objects/90/131c7cf785f05180b94d3fa03ea5a15bc3fc86 ./.git/objects/9c ./.git/objects/9c/5bef9eb738539b7ef600afb5e4a4daf520ecf3 ./.git/objects/9c/5e872385933c0748afbe0d04721d2d87fcef7a ./.git/objects/9e ./.git/objects/9e/967e175d46284466def0287af70684002ebc9b ./.git/objects/98 ./.git/objects/98/2ac64fcb212641da96dd4aeba1c4d3a2089c8d ./.git/objects/83 ./.git/objects/83/c7ca0b3a62936df5bdadf81866f2f42a60201d ./.git/objects/ee ./.git/objects/ee/905700bdc10dd27f0b9b5d3e8e7c63cdb003a8 ./.git/objects/ee/137eb490291da49905c526776f3240dd994bde ./.git/objects/8b ./.git/objects/8b/b979b870b98d1421703d3c5f9b4506b34da31b ./.git/objects/8b/94333973de20dc2f9f6fba276d77957a585f19 ./.git/objects/8b/49a1a69ac34a2a9133ff3cfb2b30d7ce21269c ./.git/objects/cd ./.git/objects/cd/149e97dcb42e9893f15b0908cc6e7be8c176ad ./.git/objects/f3 ./.git/objects/f3/ff42162b9ceaa17323e15da2fcae4455acdc94 ./.git/objects/df ./.git/objects/df/0cad1cb3e9fa09265d3f63deedc382639dd902 ./.git/objects/74 ./.git/objects/74/3d2df4b1818f0aa743f57a85a4a5fb41b01fa9 ./.git/objects/74/01fc63e34bb3750d5b16c5d151653c8d6cfbc0 ./.git/objects/01 ./.git/objects/01/2e7dc0ac588f0e708ee8a8d115dc7c064c12b7 ./.git/objects/01/b09c53d179d687bc0837662bc48601e928502e ./.git/objects/01/7b3e99b3434bfe6ef2edb0a75b080311844169 ./.git/objects/dd ./.git/objects/dd/ad7182883890236f925f3353f4873c0b75034a ./.git/objects/18 ./.git/objects/18/8fe3d25861b14cd4af1163410b61f73ca4a04e ./.git/objects/62 ./.git/objects/62/064f59de8e93a5664bf43829e477bd9985cef6 ./.git/objects/2f ./.git/objects/2f/cd5c7dea3df5fa12fcbb5f26c8582b2910c447 ./.git/objects/b6 ./.git/objects/b6/8cc01c492b43223b504821bfd73b4f583ef4e2 ./.git/objects/be ./.git/objects/be/6b86d77fbb51906eacba3df56274612f1c3029 ./.git/objects/be/0938c18155c11f355d0fdc81c489c599cde3a7 ./.git/objects/be/d2ef86152fa9a0aabd84027e317733f0dfbae7 ./.git/objects/be/f110dd4cfaa19684396aaf93b27a5fb3c0b945 ./.git/objects/f6 ./.git/objects/f6/354b6caad8336c77feff4de8509c274a27fb70 ./.git/objects/21 ./.git/objects/21/5eb4b90109c24b08014bba985aa654feb57c59 ./.git/objects/f2 ./.git/objects/f2/687c378697490c59291d1cec912fe66852453a ./.git/objects/f2/d72115d8389718be364c28fc13785e5277b180 ./.git/objects/3d ./.git/objects/3d/a02568239608f630e802f4dd777449d0913e03 ./.git/objects/1d ./.git/objects/1d/2143cfb7d3376ecd5486c18c779c9d144d384c ./.git/objects/6f ./.git/objects/6f/5fb29affd8ac04ecf3574d5e99a716b414f2ca ./.git/objects/6f/6df7bced1281095533e756c0d6b9e7373f1a8b ./.git/objects/6f/52a7ca4ac7a38e8705299c2d9473ca1058b627 ./.git/objects/45 ./.git/objects/45/f68c1233212098478ac83525e9e68e2df1fadb ./.git/objects/45/6f776946d4828283ba374a165742234590fcc9 ./.git/objects/45/7aca0b40cef66eacf359630f145a4ff26364f2 ./.git/objects/5a ./.git/objects/5a/de07472965b3a18ce368b40dc9c904278142b9 ./.git/objects/info ./.git/objects/af ./.git/objects/af/f436ea457490f0752d934983bf1bbba2e2197a ./.git/objects/af/45c22cb2b534b5698562b3080e747fefa1b981 ./.git/objects/d8 ./.git/objects/d8/f83208765b69ade21aa13ffcdd38648bc54f14 ./.git/objects/70 ./.git/objects/70/e2c3dfaef29f8c8a3fa5d714105d3f5c3cd10f ./.git/objects/70/d74188dd90fb7e09d2d163dfa874e7c9e434bd ./.git/objects/61 ./.git/objects/61/a4c4b922c4ef41400d990031f3ac12f6a0888c ./.git/objects/61/6f06980312fc46031d9f21f29beef5e17d46f1 ./.git/objects/61/21078331176aaee1238c0f059f7f94663690b3 ./.git/objects/61/b65d28779937e8010a8c9d5f7eeeddbc5e0294 ./.git/objects/84 ./.git/objects/84/6ed3f02af5b46751dc2b0ff84690a84abf8f52 ./.git/objects/84/4378673c7db10ddc3e8d22a8187ebbc8905030 ./.git/objects/23 ./.git/objects/23/f56c7122758ebed362f40e98d4f6030659abb4 ./.git/objects/23/52ab57fcf2e8a26f2bf625baf5b5bbfb831417 ./.git/objects/23/b7b897cff7f35ae6566ce97c6c7c2590df15f2 ./.git/objects/23/cb216300bc481ca8915b935e563f4d409199e1 ./.git/objects/db ./.git/objects/db/06339ac988ad5c24e59b1e72038c9bc8dcc4d7 ./.git/objects/db/1f143eeac8eeb55f3ef826718e1d6f915cc5f8 ./.git/objects/f4 ./.git/objects/f4/427b4d63bf1508f56f365c65e85280d1af5763 ./.git/objects/f4/a591498b21a52c805a11509178fa5d0915f526 ./.git/objects/f4/0c870089b85b6402c0a2243f740a1370c79286 ./.git/objects/0e ./.git/objects/0e/189b2485f4535994863ca52a6420ec623f819d ./.git/objects/0e/e9b8159d8b6e430b82845f790cb54669e833f3 ./.git/objects/0e/e16c90707c76e59789d809ab5fc41fc91f5f67 ./.git/objects/0e/9d4bcf8f359d586197ff7e48bfb2662c0c0935 ./.git/objects/d2 ./.git/objects/d2/00c42d909a31c17dea48da932202860b406cf9 ./.git/objects/d2/b9537b66981e8063b93ac516098a9ab07a531b ./.git/objects/2d ./.git/objects/2d/45d0f37ab6828e8531fbf86096bc9d8e895527 ./.git/objects/2d/99122bb3539025961f0fda6ae664b7342b6b83 ./.git/objects/2d/1e8b892f7ee580e10244ba83ac6cc89e7ba727 ./.git/objects/2d/4b717bf8427170e5906538104c6d0fa4d630f0 ./.git/objects/82 ./.git/objects/82/56665942d2d563c29a09c8e8dd633014b4514b ./.git/objects/82/08d67320a0aff6533a4b7fac917ddc79f95418 ./.git/objects/82/69e1621ff5621db953bb1e5c26ccc9141eb8b3 ./.git/objects/0d ./.git/objects/0d/6a0b5fe6a1bafad0544e22510df8a62335a609 ./.git/objects/0d/36a5901973e607b333be7b03ba47eea66dc403 ./.git/objects/0d/42bacc3191f370f0f4bc276cd908061f9ac828 ./.git/objects/0d/707ecbb8abf68b3ebfb525b63937f9c805cef1 ./.git/objects/10 ./.git/objects/10/48a1a8ae5742d323ae648c92a777d1d2d2015b ./.git/objects/59 ./.git/objects/59/151f39243bb30f51e9dc7595311d93103d6eb4 ./.git/objects/63 ./.git/objects/63/9f63c06b29f39840edd73ad04cd3b8309204f0 ./.git/objects/63/2775a8aa713d331205fa1d8c167e84ad9186cb ./.git/objects/5b ./.git/objects/5b/52231d17726d4ad4ea7994fe105eb81e9e9dd9 ./.git/objects/14 ./.git/objects/14/36d8a33498d27fa02e0f2e3c8862475bfacebd ./.git/objects/17 ./.git/objects/17/662c8875023c93144ae394f2c76c8c3cda38a0 ./.git/objects/17/54196f5997eef681179aedae446349ea1b8f95 ./.git/objects/3e ./.git/objects/3e/997e9b6647df287339fcde654c42aa30505be4 ./.git/objects/3e/cc46e96a32867bbe05b2290fc126ab93f85bcd ./.git/objects/56 ./.git/objects/56/fd5d33c9c2bfaa8805dc058d7fde9152723a33 ./.git/objects/56/f541e80ea129e6e064f8b43cacacb70e17953e ./.git/objects/bc ./.git/objects/bc/1bf84bbb65652f4b787dd7b446860a32c2e8ca ./.git/objects/bc/82b6b7fbd83ed55e18d675745ba2efb6239f5b ./.git/objects/8f ./.git/objects/8f/7dd0e6b24f8f93777152241f7891017c613e4e ./.git/objects/8f/a44135f287836c9c362922897cdf50c8abfb0a ./.git/objects/40 ./.git/objects/40/953ed78adacbd5e220aad3cec4ac5e30b90bd8 ./.git/objects/40/17069d256c4b4b46ace0a1d3a17ab474705571 ./.git/objects/40/59ef7942ff3505c5ce73ce59f4a7bfd82ba6b9 ./.git/objects/40/3ce1a8cdab4310a2e1867567be6e847f71efd9 ./.git/objects/b2 ./.git/objects/b2/6158a9e38f0450e55de2bcff275ceb5322c6ad ./.git/objects/b2/c32bc79af68feae3d4a621976396efe0820798 ./.git/objects/9b ./.git/objects/9b/5e363c1cdd23d5c116b74644713ebc7fe73af4 ./.git/objects/9b/e2d15472a28c004e57f8e223ed6d0141689f60 ./.git/objects/29 ./.git/objects/29/bc4dcda2ef8a866b6c44a8a86f06e38e3a486a ./.git/objects/29/e47e432042221c28bcf000f50ad6a08a75dbed ./.git/objects/29/2386fb0d6dca1127e6c05c2ecdba6e4a93cea7 ./.git/objects/58 ./.git/objects/58/ab0cfc01268a2ffd914ee9e62f9af1da78d178 ./.git/objects/58/491745d53e90b2f018604a67a00e301c9dfdfd ./.git/objects/19 ./.git/objects/19/1e9420d874de0715def8962f446e3aae2e05c7 ./.git/objects/67 ./.git/objects/67/96afd7d35321930d2c306f64c3ed4d72dfe482 ./.git/objects/1c ./.git/objects/1c/9d91b14661081b506e4dee4daf78b1567e3323 ./.git/objects/1c/3c0f6bc181c8c3904ad239102c183bfc5816d4 ./.git/objects/4c ./.git/objects/4c/5a7864dd9e018485e98f98f84b706a5510ae30 ./.git/objects/92 ./.git/objects/92/36c995e938d2c12a9a49714b6258db02ae39c3 ./.git/objects/92/7360fe2e74518ab716f01252c732a7269a7631 ./.git/objects/92/d9903d9e8f6dc0216f8644be14fd733977dd79 ./.git/objects/39 ./.git/objects/39/7b5ce17fe342555c16de630d19ba1b4773fefd ./.git/objects/39/41aa48e3029a96c11c0f12f9e94043ec655815 ./.git/objects/39/f544d4c59fd91822f5189ac7c70f6066bef54b ./.git/objects/6e ./.git/objects/6e/4bee91d25e88a35f0be2fc7a14552627915afe ./.git/objects/6e/2fab67530969884622b05d64c3d049465b5efa ./.git/objects/d7 ./.git/objects/d7/775f3198f4dbbb284ac1d2bfbe0789f95bef26 ./.git/objects/d7/b4d0ca5ca71281fdc77b49820272ddea245958 ./.git/objects/4f ./.git/objects/4f/f6719cf0d54eddb41be1f095ceb9d272a92aae ./.git/objects/b0 ./.git/objects/b0/4c7a44f9ab42e495553aa332bc80e3685021b8 ./.git/objects/b0/4eb2c9a981a3a7459b0053d7b8436471066730 ./.git/objects/fd ./.git/objects/fd/eb0e5a19478cca5377cb47fe41426975109205 ./.git/objects/fd/cdf055082dc71e0f30f962578f214e6812631e ./.git/objects/fd/ff1ae9862d61a9e117e56b3548078193cbd078 ./.git/objects/08 ./.git/objects/08/2e3a2cb843392a72074b65718bc672f56835cd ./.git/objects/ec ./.git/objects/ec/5efce500afb6393d66da480b2b529a4f4f348d ./.git/objects/ec/6fc32ccaa7ee6a6f3e732578eb4c98817deb83 ./.git/objects/16 ./.git/objects/16/252d2718003ea39fa83a16a84db4fc616d73d8 ./.git/objects/16/86d481b6ef09f351775a4dc1ce272c304df1ec ./.git/objects/2a ./.git/objects/2a/6f80a64c07b516b56c681e9d6e75598b43b207 ./.git/objects/27 ./.git/objects/27/045100d894b6044d1ae548948bdfa8b2b74874 ./.git/objects/31 ./.git/objects/31/9b57b742825237cdbd9b368d9cce7127be9775 ./.git/objects/28 ./.git/objects/28/77fdeda6264e50d9a6ec4cafa505de0507cbac ./.git/objects/28/7c7c56177b382323e8fb3b41db8e02d6b8bd1c ./.git/objects/28/bfeae2edb4cd27c3323cc44ada958aea2ec165 ./.git/objects/64 ./.git/objects/64/dbea3ab74738f8ee05cf874665a7c7181c5649 ./.git/objects/9a ./.git/objects/9a/03b54f19d91702674f804179c0d86dc8f763f2 ./.git/objects/34 ./.git/objects/34/139b81408463cd1ce871a3e954bf062e1c9711 ./.git/objects/34/912ecae4fdb5c0e898af5f0c5e2350dcad4cf0 ./.git/objects/34/d776502fcdc7f0ccc2bd972e390133526b91a0 ./.git/objects/7e ./.git/objects/7e/8a190738a7c9f6c5a6a520f817c85e41d02b46 ./.git/objects/7e/b3436415d6bb988d8c0a533f4b7fc2f66491aa ./.git/objects/7f ./.git/objects/7f/423a93c268c328b5e161d986d4476e2cf4f571 ./.git/objects/7f/c7ab857ad56796463f01c4f1cfc89e378ca221 ./.git/objects/7f/10d6e0684b637206d6919b5956a1ac6ed37e49 ./.git/objects/13 ./.git/objects/13/4908aac9fe7db898b18a0a7e154072c1a3d7a2 ./.git/objects/f9 ./.git/objects/f9/85215f4f91d9cc3b848e56f78aa519ae49b5fa ./.git/objects/89 ./.git/objects/89/abfc5bdc924ff5551bfaff18de67741966b15d ./.git/objects/89/1c6f722bff534ac88c0dde8e7e63454d199296 ./.git/objects/89/735db4f10c18709ada2dc788a9743565f55388 ./.git/objects/89/a9e26eeb0a3ffd689ab5e98e43a21a1c0a87ae ./.git/objects/89/855435ff72be41295f28ee57c2bee30202de47 ./.git/objects/b1 ./.git/objects/b1/c385a303bc2dd3b850b41a1ae0410af2c5786a ./.git/objects/b1/eefe4521c5ef85f8b779add575aecf58393ce5 ./.git/objects/b1/bacc7a0b15fb01e09e1a59ee6e5bdfc2925b54 ./.git/objects/b1/ec612772c1c2249e6af3e7ba77585ee5c13c58 ./.git/objects/ff ./.git/objects/ff/3defee152ceda6082a9dc5040cd433c61efcf9 ./.git/objects/ff/f440d7c7f9aad902701b385561ddc8b77f8fe3 ./.git/objects/e5 ./.git/objects/e5/3214c9e3cad529dc0d4dfb61b48f478bfbbd4c ./.git/objects/e5/f4ff38c22af8c8dc51a7c94b4f1fb83b6558e5 ./.git/objects/e1 ./.git/objects/e1/865c1c5fd94104ed9bacb4cd53adfcd83a9697 ./.git/objects/7b ./.git/objects/7b/a0dbd949f60a1559d96d911cc33efc6939d01c ./.git/objects/7b/ea82ee2c4c1021b2e20ad5276414d1b4246c47 ./.git/objects/3c ./.git/objects/3c/63515ea22b572d39b224cc508908853084b123 ./.git/objects/8e ./.git/objects/8e/272b49dc5f3be82d469086ca9d3bed7253e70f ./.git/objects/8e/749d82d91ba0123f0bb4ebf646857049b8ef0c ./.git/objects/c9 ./.git/objects/c9/df108c929b2e5a312cd86c704c090013039e69 ./.git/objects/c9/e2566ac9d03be1f74c0ffb437998644dd60e02 ./.git/objects/ab ./.git/objects/ab/52adec5fd340b834de7014d1f3471728801848 ./.git/objects/ab/22631c8807eda2cb9fa48606aa58cbdb7dd1f4 ./.git/objects/ab/0db94c4fba3033a1993b146fcb7d4e6fad191f ./.git/objects/6b ./.git/objects/6b/c97371f4936bd31bf71f37d410f67879d208fd ./.git/objects/6b/91cabb14b820197c4a396e195d6cf8dcc18eb3 ./.git/objects/52 ./.git/objects/52/9076f7a1acb9707376f59e0e1248c348867e34 ./.git/objects/f1 ./.git/objects/f1/84063fe783cae53b303f169c9af5bca7b0f82c ./.git/objects/f1/6282f7f2786e1f9f1130343dc8c94b0b6dbf9a ./.git/objects/77 ./.git/objects/77/f0dc81400956ade5be5598af329b46c0fdeab9 ./.git/objects/77/f3677d9db06f94d516209acdfc19569736cc9a ./.git/objects/77/b205d10b78dc1cc7b318d8ad3ef866f0b88435 ./.git/objects/77/11a20542d388d93aa990522a45a432c2e5b61b ./.git/objects/00 ./.git/objects/00/deef1c92d3b244f7392a54e2e0da3fcf73cccd ./.git/objects/aa ./.git/objects/aa/55b7f297a28c5663cb8051c5f4e5431150e36a ./.git/objects/aa/056834a4ab2e1d476b371a91206c396affa82b ./.git/objects/de ./.git/objects/de/11623e687555a843d60ecc3f0c70f550e98e3d ./.git/objects/de/19613e554cca5fab317d3605f5b0ad8a8f5711 ./.git/objects/de/3effaea36556b96c74d86abf327517b289e3b7 ./.git/objects/55 ./.git/objects/55/04a585b2d05749a197cc648d4948585b002aeb ./.git/objects/55/5671ae38e662bc02b3e4f84af337732c725c41 ./.git/objects/55/ac449d0e9a26a294d47152e964564bebf0cbb7 ./.git/objects/55/1b2391f3cec5b8a7c6971bb6a4043f273eee8e ./.git/objects/69 ./.git/objects/69/6bcb9994deb32a6198dbe7683bc43e33fa8a9f ./.git/objects/d6 ./.git/objects/d6/c954feb40f1ee75fdcf00ca57f5c0d3d2e0f99 ./.git/objects/d6/c49da67ff56cbfc86661c5dfffb3b144ed5eb0 ./.git/objects/d6/811902b9ad236aad771ce776e1332736f7d88f ./.git/objects/2c ./.git/objects/2c/33e2d59e07e20924a9b25c6c737ad228ca9b0f ./.git/objects/2c/7cf5ed16ae8e4d7333984cbebaff7962b4eaef ./.git/objects/2c/6a5f8dd2ccd70f29683915413d5a7afb0c38e0 ./.git/objects/2c/ea4a57dae3d943c974d35343fd14f857e4a537 ./.git/objects/2c/90b9d946389975380bd8b96ab03a5c325ca355 ./.git/objects/fb ./.git/objects/fb/143505c55d0b75752d2077621e7f6a057dbe0a ./.git/objects/0b ./.git/objects/0b/e9761371a503b2c6d83d8f7846543666377bab ./.git/objects/95 ./.git/objects/95/26ddc2f80b69eb676be5908b863e221cc55311 ./.git/objects/95/6fa5bf5ff46970f3646bb9d3a354587ce7a758 ./.git/objects/95/d981e795f5c2beb635a3e70f3ddbfede70fbb8 ./.git/objects/b8 ./.git/objects/b8/b07af1a1bc02d22ca70807a2e4604ed94bca68 ./.git/objects/65 ./.git/objects/65/2752f82065b53bd9e241d3b1ee260dd0dc7787 ./.git/objects/65/88c2c23bcac12f9692c2cd06480cee422c1c8d ./.git/objects/65/29f3b232b42e48a7ef1f935c765e60f34ef170 ./.git/objects/65/b10e153969f46f3d80b866741c0151876da8e7 ./.git/objects/65/964392595e262f0571912b5bacd9c999b002c4 ./.git/objects/c7 ./.git/objects/c7/7f3f64c1e9bfca7efb514ba08af74c9fae2885 ./.git/objects/94 ./.git/objects/94/87dd0b25009cbd8debaf3cb2edc383790677a5 ./.git/objects/42 ./.git/objects/42/f4ec8e259667b739c89b30684fa10b1dc8ea3d ./.git/objects/53 ./.git/objects/53/27fba844b2bc564d0aa3f1e3eb930bac3fb032 ./.git/objects/53/5ed8fc72b4b1e307dd19e89267438c4423db3a ./.git/objects/35 ./.git/objects/35/deb323feeaf3ca7e9bc101029176e11734d199 ./.git/objects/35/2afae96809d801c4b45997ee4431e5bb680ede ./.git/objects/35/fd399b11365e08ffbe39585abd3be44321c406 ./.git/objects/35/d2c09301c92eab37e03723c505065e494e10d1 ./.git/objects/35/cc754c3415cc8aad653e8b09af109fe391711a ./.git/objects/a1 ./.git/objects/a1/6cb5eafaef7a2354723f9c54d400f8ee743818 ./.git/objects/37 ./.git/objects/37/581301a02ffae12602a136cad472ea76cbdb8d ./.git/objects/97 ./.git/objects/97/26766d221f3303009799db3e7ea3bec6ed2cfe ./.git/objects/97/b4363d1844eda0f9979ff4734d54a160ea6064 ./.git/objects/97/e8f520105d1f196900c45665086a68b569b7e8 ./.git/objects/ba ./.git/objects/ba/cd1431be4d953a1388bbb2685601f8b66b6710 ./.git/objects/e6 ./.git/objects/e6/f4ae3427fdc975b344464f9437fd6e783cbc2d ./.git/objects/e6/1fa3ced7bb7e13d8ee87f4eac3d1f00cb30ccb ./.git/objects/e2 ./.git/objects/e2/c6fe08e2c69707b9817a09375f099e1a93efc1 ./.git/objects/b7 ./.git/objects/b7/eab6d5e5b62a0a594a2b52998cecb5ec993800 ./.git/objects/b7/306f863c71df9b62eb25319df5aa04de67d1ed ./.git/objects/b7/755aefc6109b0581f359cfef5050110780bdc5 ./.git/objects/b7/6d3f36ede46cd4e3868631cd56d2f89ca420c0 ./.git/objects/72 ./.git/objects/72/f7b77e29f727976e5cef2bbf573ff3ed2be79f ./.git/objects/25 ./.git/objects/25/0e21592a948efb3b81f3d325d5e6a92f7b57bb ./.git/objects/25/d7ba5250934e6ccf724f22997447dd929a992c ./.git/objects/93 ./.git/objects/93/0be3835b8225191fc3e25bac75b46f59f1e4ec ./.git/objects/93/468fafb296570203c5ea7f53f3b0ca969b781b ./.git/objects/a7 ./.git/objects/a7/665a4d00775a6736b3bf9251fd402ed5214b0a ./.git/objects/a7/eb3f631f1391d84d787c36d5d81f1db6d64ff4 ./.git/objects/5f ./.git/objects/5f/2e350ec9cc6ed80e7ec93285d796b50ded711b ./.git/objects/6d ./.git/objects/6d/a9005dd1a094e5fdd61f98d55552c8ed25b758 ./.git/objects/6d/d60283ba8de90e73c86a0a1b3a0262faa83ca9 ./.git/objects/6d/0ea5ad50c394ef01a3691451aa546d2ad7aa3a ./.git/objects/4a ./.git/objects/4a/254c4789f8b2cfcfb690215dd3bf16774b060f ./.git/objects/4a/97cd73b86af93d38715655b2922602bf5effd6 ./.git/objects/4a/91acf8a657f209e77074dea27f43dece276dd9 ./.git/objects/12 ./.git/objects/12/cd765ea7be32a73ea2ec12268ccc7a978dd975 ./.git/objects/12/848fa310de1e10eb83f41ef8359b148f3ed74a ./.git/objects/12/0d81b2e9e89ed11a8c86fcaac0f19f44b5f4eb ./.git/objects/0c ./.git/objects/0c/caecffa9374685010200f29c869dce83ed02be ./.git/objects/fc ./.git/objects/fc/8440f85ef023184513b2b606ee6e0b40e5c6e9 ./.git/objects/fc/986c42168c88cefaefd8a8201d4455b4205672 ./.git/objects/fc/0781a4dc652c45cdf8122833f5f1638fe087ca ./.git/objects/0f ./.git/objects/0f/1f15d28a517a5dee0e6d81a1804c02380c26f3 ./.git/objects/f0 ./.git/objects/f0/0a2246063ebd8671cafe9983de72bbc6e45f4c ./.git/objects/96 ./.git/objects/96/e4b97449ae85fad317880fe76a35207c9d419a ./.git/objects/96/67c6e2e8bfa8504c9af78bcfc698418349a3d1 ./.git/objects/96/005d21f7fc36c9c9a8767c7b457e51730aa953 ./.git/objects/4b ./.git/objects/4b/7bd2c810157b639d753ee04bafa89fd31d7c9e ./.git/objects/4b/7646b2252c04719e5b897e28f35510415a5a3a ./.git/description ./.git/config ./.git/index ./.git/ORIG_HEAD ./.git/refs ./.git/refs/remotes ./.git/refs/remotes/drup ./.git/refs/remotes/drup/master ./.git/refs/remotes/drup/rgrinberg-pp ./.git/refs/remotes/drup/no_exception ./.git/refs/remotes/origin ./.git/refs/remotes/origin/pp ./.git/refs/remotes/origin/master ./.git/refs/remotes/origin/re_automata-module-refactor ./.git/refs/remotes/origin/format-group ./.git/refs/remotes/origin/re_str-infinite-loop-fix ./.git/refs/remotes/origin/re_str-fixes ./.git/refs/remotes/origin/prepare-1.6.1 ./.git/refs/remotes/origin/travis-403 ./.git/refs/remotes/origin/benchmarks ./.git/refs/remotes/origin/HEAD ./.git/refs/remotes/origin/re-cleanups ./.git/refs/remotes/origin/exec-no-group ./.git/refs/remotes/origin/prepare-1.6.0 ./.git/refs/remotes/origin/4.00-compat ./.git/refs/remotes/origin/labelize-match-str ./.git/refs/remotes/origin/status-lazy ./.git/refs/remotes/origin/dead-code-deriv ./.git/refs/remotes/gt ./.git/refs/remotes/gt/master ./.git/refs/heads ./.git/refs/heads/master ./.git/refs/heads/re_automata-module-refactor ./.git/refs/heads/re_cset-abstract ./.git/refs/heads/re_str-infinite-loop-fix ./.git/refs/heads/re_str-fixes ./.git/refs/heads/infinite-loop-cleanup ./.git/refs/heads/dev ./.git/refs/heads/re-cleanups ./.git/refs/heads/status-lazy ./.git/refs/heads/exec-no-group-with-bench ./.git/refs/heads/dead-code-deriv ./.git/refs/tags ./.git/refs/tags/1.3.0 ./.git/refs/tags/1.1.0 ./.git/refs/tags/1.2.2 ./.git/refs/tags/1.6.1 ./.git/refs/tags/1.2.0 ./.git/refs/tags/1.6.0 ./.git/refs/tags/1.3.2 ./.git/refs/tags/1.3.1 ./.git/refs/tags/1.2.1 ./.git/refs/tags/1.5.0 ./.git/refs/tags/1.0.0 ./.git/refs/tags/1.4.1 ./.git/HEAD ./.git/branches ./.git/info ./.git/info/exclude ./.git/FETCH_HEAD ./.git/logs ./.git/logs/refs ./.git/logs/refs/remotes ./.git/logs/refs/remotes/drup ./.git/logs/refs/remotes/drup/master ./.git/logs/refs/remotes/drup/rgrinberg-pp ./.git/logs/refs/remotes/drup/no_exception ./.git/logs/refs/remotes/origin ./.git/logs/refs/remotes/origin/pp ./.git/logs/refs/remotes/origin/master ./.git/logs/refs/remotes/origin/re_automata-module-refactor ./.git/logs/refs/remotes/origin/format-group ./.git/logs/refs/remotes/origin/re_str-infinite-loop-fix ./.git/logs/refs/remotes/origin/re_str-fixes ./.git/logs/refs/remotes/origin/prepare-1.6.1 ./.git/logs/refs/remotes/origin/travis-403 ./.git/logs/refs/remotes/origin/benchmarks ./.git/logs/refs/remotes/origin/HEAD ./.git/logs/refs/remotes/origin/re-cleanups ./.git/logs/refs/remotes/origin/exec-no-group ./.git/logs/refs/remotes/origin/prepare-1.6.0 ./.git/logs/refs/remotes/origin/4.00-compat ./.git/logs/refs/remotes/origin/labelize-match-str ./.git/logs/refs/remotes/origin/status-lazy ./.git/logs/refs/remotes/origin/dead-code-deriv ./.git/logs/refs/remotes/gt ./.git/logs/refs/remotes/gt/master ./.git/logs/refs/heads ./.git/logs/refs/heads/master ./.git/logs/refs/heads/re_automata-module-refactor ./.git/logs/refs/heads/re_cset-abstract ./.git/logs/refs/heads/re_str-infinite-loop-fix ./.git/logs/refs/heads/re_str-fixes ./.git/logs/refs/heads/infinite-loop-cleanup ./.git/logs/refs/heads/dev ./.git/logs/refs/heads/re-cleanups ./.git/logs/refs/heads/status-lazy ./.git/logs/refs/heads/exec-no-group-with-bench ./.git/logs/refs/heads/dead-code-deriv ./.git/logs/HEAD ./.git/hooks ./.git/hooks/prepare-commit-msg.sample ./.git/hooks/pre-commit.sample ./.git/hooks/update.sample ./.git/hooks/pre-rebase.sample ./.git/hooks/pre-push.sample ./.git/hooks/pre-applypatch.sample ./.git/hooks/applypatch-msg.sample ./.git/hooks/post-update.sample ./.git/hooks/commit-msg.sample ./.git/packed-refs ./_build ./_build/oUnit-test_perl-rgcaml#02.log ./_build/oUnit-test_str.cache ./_build/lib ./_build/lib/re.a ./_build/lib/re_emacs.o ./_build/lib/re_glob.mllib ./_build/lib/re_posix.cmi ./_build/lib/re_str.cmi ./_build/lib/re_perl.cmx ./_build/lib/re_glob.cmi ./_build/lib/re.mli ./_build/lib/re_pcre.annot ./_build/lib/re_emacs.annot ./_build/lib/re_cset.ml ./_build/lib/re_fmt.o ./_build/lib/re_perl.mli.depends ./_build/lib/re_posix.cma ./_build/lib/re_perl.cmi ./_build/lib/re_glob.o ./_build/lib/re_str.cmti ./_build/lib/re_automata.ml ./_build/lib/re_str.mli.depends ./_build/lib/re.ml ./_build/lib/re_emacs.mli ./_build/lib/re_pcre.cmx ./_build/lib/re_perl.cmt ./_build/lib/re_posix.cmti ./_build/lib/re_glob.mldylib ./_build/lib/re_pcre.mli ./_build/lib/re.cmti ./_build/lib/re_emacs.mli.depends ./_build/lib/re_perl.a ./_build/lib/re_pcre.cmxa ./_build/lib/re_str.cmxa ./_build/lib/re_cset.ml.depends ./_build/lib/re_glob.cmxs ./_build/lib/re_pcre.a ./_build/lib/re_perl.mldylib ./_build/lib/re.cmxa ./_build/lib/re_pcre.cmo ./_build/lib/re_pcre.cmt ./_build/lib/re_str.annot ./_build/lib/re_posix.mli ./_build/lib/re_perl.mli ./_build/lib/re_cset.cmt ./_build/lib/re.mli.depends ./_build/lib/re.mldylib ./_build/lib/re_str.cmx ./_build/lib/re_pcre.o ./_build/lib/re_automata.cmo ./_build/lib/re_posix.mldylib ./_build/lib/re_automata.mli ./_build/lib/re_cset.annot ./_build/lib/re_fmt.cmt ./_build/lib/re_posix.a ./_build/lib/re_glob.ml ./_build/lib/re.cmxs ./_build/lib/re.cmi ./_build/lib/re_str.cmt ./_build/lib/re_pcre.cmxs ./_build/lib/re_pcre.mli.depends ./_build/lib/re_emacs.ml ./_build/lib/re_fmt.cmi ./_build/lib/re_perl.ml.depends ./_build/lib/re_emacs.cmxa ./_build/lib/re_pcre.mllib ./_build/lib/re.o ./_build/lib/re_pcre.cmi ./_build/lib/re_emacs.cmo ./_build/lib/re_glob.cma ./_build/lib/re_str.a ./_build/lib/re.cmt ./_build/lib/re_str.o ./_build/lib/re_cset.cmti ./_build/lib/re_posix.annot ./_build/lib/re.ml.depends ./_build/lib/re_posix.cmo ./_build/lib/re.annot ./_build/lib/re_automata.cmx ./_build/lib/re_perl.cma ./_build/lib/re_posix.cmx ./_build/lib/re_perl.annot ./_build/lib/re_glob.cmxa ./_build/lib/re_glob.mli ./_build/lib/re_cset.cmo ./_build/lib/re_cset.cmx ./_build/lib/re_glob.a ./_build/lib/re_cset.cmi ./_build/lib/re_str.mldylib ./_build/lib/re_pcre.cmti ./_build/lib/re_automata.mli.depends ./_build/lib/re.mllib ./_build/lib/re_posix.mllib ./_build/lib/re_emacs.cmxs ./_build/lib/re_fmt.annot ./_build/lib/re_emacs.cmt ./_build/lib/re_fmt.cmo ./_build/lib/re_pcre.ml ./_build/lib/re_glob.cmti ./_build/lib/re_glob.cmx ./_build/lib/re_posix.mli.depends ./_build/lib/re_emacs.cmti ./_build/lib/re_str.ml.depends ./_build/lib/re_automata.cmi ./_build/lib/re_emacs.mldylib ./_build/lib/re_pcre.cma ./_build/lib/re_glob.cmt ./_build/lib/re_pcre.ml.depends ./_build/lib/re_posix.cmxs ./_build/lib/re_automata.annot ./_build/lib/re_emacs.a ./_build/lib/re_posix.cmxa ./_build/lib/re_pcre.mldylib ./_build/lib/re_cset.mli ./_build/lib/re_str.cmxs ./_build/lib/re_posix.o ./_build/lib/re_emacs.mllib ./_build/lib/re_perl.cmo ./_build/lib/re_cset.mli.depends ./_build/lib/re_str.mli ./_build/lib/re_glob.ml.depends ./_build/lib/re_posix.cmt ./_build/lib/re_perl.o ./_build/lib/re_str.cma ./_build/lib/re.cma ./_build/lib/re_emacs.cmx ./_build/lib/re_fmt.cmx ./_build/lib/re_str.cmo ./_build/lib/re_glob.annot ./_build/lib/re_perl.cmti ./_build/lib/re_perl.ml ./_build/lib/re_perl.cmxs ./_build/lib/re.cmo ./_build/lib/re_fmt.ml.depends ./_build/lib/re_posix.ml.depends ./_build/lib/re_automata.ml.depends ./_build/lib/re_fmt.ml ./_build/lib/re_perl.mllib ./_build/lib/re_glob.mli.depends ./_build/lib/re_emacs.cmi ./_build/lib/re.cmx ./_build/lib/re_emacs.ml.depends ./_build/lib/re_automata.o ./_build/lib/re_posix.ml ./_build/lib/re_perl.cmxa ./_build/lib/re_str.ml ./_build/lib/re_cset.o ./_build/lib/re_glob.cmo ./_build/lib/re_str.mllib ./_build/lib/re_emacs.cma ./_build/lib/re_automata.cmt ./_build/lib/re_automata.cmti ./_build/oUnit-test_perl-rgcaml#01.log ./_build/lib_test ./_build/lib_test/test_glob.ml.depends ./_build/lib_test/test_emacs.cmo ./_build/lib_test/test_glob.cmt ./_build/lib_test/test_easy.ml ./_build/lib_test/test_str.cmi ./_build/lib_test/re_match.native ./_build/lib_test/test_emacs.ml ./_build/lib_test/test_glob.cmo ./_build/lib_test/test_pcre.cmt ./_build/lib_test/re_match.ml ./_build/lib_test/re_match.cmo ./_build/lib_test/test_pcre.cmi ./_build/lib_test/fort_unit.cmxa ./_build/lib_test/fort_unit.cmo ./_build/lib_test/re_match.o ./_build/lib_test/test_pcre.cmx ./_build/lib_test/re_match.ml.depends ./_build/lib_test/fort_unit.cmt ./_build/lib_test/test_glob.ml ./_build/lib_test/test_str.o ./_build/lib_test/test_perl.native ./_build/lib_test/re_match.cmx ./_build/lib_test/fort_unit.mllib ./_build/lib_test/test_perl.ml ./_build/lib_test/test_perl.annot ./_build/lib_test/fort_unit.ml ./_build/lib_test/test_re.native ./_build/lib_test/test_perl.cmt ./_build/lib_test/test_emacs.o ./_build/lib_test/test_easy.cmi ./_build/lib_test/test_pcre.o ./_build/lib_test/test_emacs.ml.depends ./_build/lib_test/test_emacs.cmx ./_build/lib_test/test_str.cmo ./_build/lib_test/test_perl.cmx ./_build/lib_test/fort_unit.mldylib ./_build/lib_test/re_match.cmt ./_build/lib_test/test_pcre.cmo ./_build/lib_test/test_easy.cmo ./_build/lib_test/fort_unit.cma ./_build/lib_test/test_str.cmx ./_build/lib_test/test_easy.cmx ./_build/lib_test/test_pcre.native ./_build/lib_test/test_emacs.cmt ./_build/lib_test/fort_unit.o ./_build/lib_test/fort_unit.cmx ./_build/lib_test/test_re.cmo ./_build/lib_test/test_glob.cmi ./_build/lib_test/fort_unit.a ./_build/lib_test/test_easy.annot ./_build/lib_test/re_match.annot ./_build/lib_test/test_emacs.native ./_build/lib_test/test_emacs.annot ./_build/lib_test/test_re.cmx ./_build/lib_test/fort_unit.annot ./_build/lib_test/test_re.cmi ./_build/lib_test/test_emacs.cmi ./_build/lib_test/test_perl.cmo ./_build/lib_test/test_re.annot ./_build/lib_test/test_easy.native ./_build/lib_test/test_pcre.annot ./_build/lib_test/test_glob.native ./_build/lib_test/test_glob.cmx ./_build/lib_test/test_str.cmt ./_build/lib_test/test_re.cmt ./_build/lib_test/test_re.ml.depends ./_build/lib_test/test_pcre.ml ./_build/lib_test/test_glob.o ./_build/lib_test/fort_unit.ml.depends ./_build/lib_test/test_easy.o ./_build/lib_test/test_perl.cmi ./_build/lib_test/fort_unit.cmi ./_build/lib_test/test_pcre.ml.depends ./_build/lib_test/test_perl.ml.depends ./_build/lib_test/re_match.cmi ./_build/lib_test/test_str.ml.depends ./_build/lib_test/fort_unit.cmxs ./_build/lib_test/test_re.o ./_build/lib_test/test_str.annot ./_build/lib_test/test_easy.ml.depends ./_build/lib_test/test_str.ml ./_build/lib_test/test_str.native ./_build/lib_test/test_re.ml ./_build/lib_test/test_glob.annot ./_build/lib_test/test_easy.cmt ./_build/lib_test/test_perl.o ./_build/_digests ./_build/oUnit-test_emacs-rgcaml#02.log ./_build/benchmarks ./_build/benchmarks/benchmark.cmt ./_build/benchmarks/benchmark.cmx ./_build/benchmarks/benchmark.ml ./_build/benchmarks/benchmark.cmi ./_build/benchmarks/benchmark.cmo ./_build/benchmarks/benchmark.ml.depends ./_build/benchmarks/benchmark.native ./_build/benchmarks/benchmark.annot ./_build/benchmarks/benchmark.o ./_build/myocamlbuild.cmi ./_build/oUnit-test_re.cache ./_build/oUnit-test_re-rgcaml#02.log ./_build/myocamlbuild.cmx ./_build/_log ./_build/ocamlc.where ./_build/oUnit-test_emacs-rgcaml#00.log ./_build/oUnit-test_emacs-rgcaml#01.log ./_build/oUnit-test_perl-rgcaml#00.log ./_build/oUnit-test_perl.cache ./_build/oUnit-test_str-rgcaml#01.log ./_build/oUnit-test_str-rgcaml#00.log ./_build/oUnit-test_re-rgcaml#00.log ./_build/oUnit-anon.cache ./_build/myocamlbuild.o ./_build/oUnit-test_emacs.cache ./_build/oUnit-test_str-rgcaml#02.log ./_build/myocamlbuild ./_build/oUnit-test_re-rgcaml#01.log ./_build/myocamlbuild.ml ./setup.log ./.travis.yml ./_tags ./test_pcre.native ./LICENSE ./test_emacs.native ./README.md ./TODO.txt ./test_easy.native ./benchmark.native ./test_glob.native ./tags ./dev.org ./INSTALL ./configure ./Makefile ./CHANGES ./opam ./test_str.native ./myocamlbuild.ml ./compare.pl ocaml-ocaml-re-5586c57/benchmarks/http-requests.txt000066400000000000000000000516021467707551200223220ustar00rootroot00000000000000GET / HTTP/1.1 Host: www.reddit.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive GET /reddit.v_EZwRzV-Ns.css HTTP/1.1 Host: www.redditstatic.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: text/css,*/*;q=0.1 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /reddit-init.en-us.O1zuMqOOQvY.js HTTP/1.1 Host: www.redditstatic.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: */* Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /reddit.en-us.31yAfSoTsfo.js HTTP/1.1 Host: www.redditstatic.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: */* Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /kill.png HTTP/1.1 Host: www.redditstatic.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /icon.png HTTP/1.1 Host: www.redditstatic.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive GET /favicon.ico HTTP/1.1 Host: www.redditstatic.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive GET /AMZM4CWd6zstSC8y.jpg HTTP/1.1 Host: b.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /jz1d5Nm0w97-YyNm.jpg HTTP/1.1 Host: b.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /aWGO99I6yOcNUKXB.jpg HTTP/1.1 Host: a.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /rZ_rD5TjrJM0E9Aj.css HTTP/1.1 Host: e.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: text/css,*/*;q=0.1 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /tmsPwagFzyTvrGRx.jpg HTTP/1.1 Host: a.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /KYgUaLvXCK3TCEJx.jpg HTTP/1.1 Host: a.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /81pzxT5x2ozuEaxX.jpg HTTP/1.1 Host: e.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /MFqCUiUVPO5V8t6x.jpg HTTP/1.1 Host: a.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /TFpYTiAO5aEowokv.jpg HTTP/1.1 Host: e.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /eMWMpmm9APNeNqcF.jpg HTTP/1.1 Host: e.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /S-IpsJrOKuaK9GZ8.jpg HTTP/1.1 Host: c.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /3V6dj9PDsNnheDXn.jpg HTTP/1.1 Host: c.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /wQ3-VmNXhv8sg4SJ.jpg HTTP/1.1 Host: c.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /ixd1C1njpczEWC22.jpg HTTP/1.1 Host: c.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /nGsQj15VyOHMwmq8.jpg HTTP/1.1 Host: c.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /zT4yQmDxQLbIxK1b.jpg HTTP/1.1 Host: c.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /L5e1HcZLv1iu4nrG.jpg HTTP/1.1 Host: f.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /WJFFPxD8X4JO_lIG.jpg HTTP/1.1 Host: f.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /hVMVTDdjuY3bQox5.jpg HTTP/1.1 Host: f.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /rnWf8CjBcyPQs5y_.jpg HTTP/1.1 Host: f.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /gZJL1jNylKbGV4d-.jpg HTTP/1.1 Host: d.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /aNd2zNRLXiMnKUFh.jpg HTTP/1.1 Host: c.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /droparrowgray.gif HTTP/1.1 Host: www.redditstatic.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.redditstatic.com/reddit.v_EZwRzV-Ns.css GET /sprite-reddit.an0Lnf61Ap4.png HTTP/1.1 Host: www.redditstatic.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.redditstatic.com/reddit.v_EZwRzV-Ns.css GET /ga.js HTTP/1.1 Host: www.google-analytics.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: */* Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ If-Modified-Since: Tue, 29 Oct 2013 19:33:51 GMT GET /reddit/ads.html?sr=-reddit.com&bust2 HTTP/1.1 Host: static.adzerk.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /pixel/of_destiny.png?v=hOlmDALJCWWdjzfBV4ZxJPmrdCLWB%2Ftq7Z%2Ffp4Q%2FxXbVPPREuMJMVGzKraTuhhNWxCCwi6yFEZg%3D&r=783333388 HTTP/1.1 Host: pixel.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /UNcO-h_QcS9PD-Gn.jpg HTTP/1.1 Host: c.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://e.thumbs.redditmedia.com/rZ_rD5TjrJM0E9Aj.css GET /welcome-lines.png HTTP/1.1 Host: www.redditstatic.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.redditstatic.com/reddit.v_EZwRzV-Ns.css GET /welcome-upvote.png HTTP/1.1 Host: www.redditstatic.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.redditstatic.com/reddit.v_EZwRzV-Ns.css GET /__utm.gif?utmwv=5.5.1&utms=1&utmn=720496082&utmhn=www.reddit.com&utme=8(site*srpath*usertype*uitype)9(%20reddit.com*%20reddit.com-GET_listing*guest*web)11(3!2)&utmcs=UTF-8&utmsr=2560x1600&utmvp=1288x792&utmsc=24-bit&utmul=en-us&utmje=1&utmfl=13.0%20r0&utmdt=reddit%3A%20the%20front%20page%20of%20the%20internet&utmhid=2129416330&utmr=-&utmp=%2F&utmht=1400862512705&utmac=UA-12131688-1&utmcc=__utma%3D55650728.585571751.1400862513.1400862513.1400862513.1%3B%2B__utmz%3D55650728.1400862513.1.1.utmcsr%3D(direct)%7Cutmccn%3D(direct)%7Cutmcmd%3D(none)%3B&utmu=qR~ HTTP/1.1 Host: www.google-analytics.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /ImnpOQhbXUPkwceN.png HTTP/1.1 Host: a.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /ajax/libs/jquery/1.7.1/jquery.min.js HTTP/1.1 Host: ajax.googleapis.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: */* Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://static.adzerk.net/reddit/ads.html?sr=-reddit.com&bust2 GET /__utm.gif?utmwv=5.5.1&utms=2&utmn=1493472678&utmhn=www.reddit.com&utmt=event&utme=5(AdBlock*enabled*false)(0)8(site*srpath*usertype*uitype)9(%20reddit.com*%20reddit.com-GET_listing*guest*web)11(3!2)&utmcs=UTF-8&utmsr=2560x1600&utmvp=1288x792&utmsc=24-bit&utmul=en-us&utmje=1&utmfl=13.0%20r0&utmdt=reddit%3A%20the%20front%20page%20of%20the%20internet&utmhid=2129416330&utmr=-&utmp=%2F&utmht=1400862512708&utmac=UA-12131688-1&utmni=1&utmcc=__utma%3D55650728.585571751.1400862513.1400862513.1400862513.1%3B%2B__utmz%3D55650728.1400862513.1.1.utmcsr%3D(direct)%7Cutmccn%3D(direct)%7Cutmcmd%3D(none)%3B&utmu=6R~ HTTP/1.1 Host: www.google-analytics.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /ados.js?q=43 HTTP/1.1 Host: secure.adzerk.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: */* Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://static.adzerk.net/reddit/ads.html?sr=-reddit.com&bust2 GET /fetch-trackers?callback=jQuery111005268222517967478_1400862512407&ids%5B%5D=t3_25jzeq-t8_k2ii&_=1400862512408 HTTP/1.1 Host: tracker.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: */* Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /ados?t=1400862512892&request={%22Placements%22:[{%22A%22:5146,%22S%22:24950,%22D%22:%22main%22,%22AT%22:5},{%22A%22:5146,%22S%22:24950,%22D%22:%22sponsorship%22,%22AT%22:8}],%22Keywords%22:%22-reddit.com%22,%22Referrer%22:%22http%3A%2F%2Fwww.reddit.com%2F%22,%22IsAsync%22:true,%22WriteResults%22:true} HTTP/1.1 Host: engine.adzerk.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: */* Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://static.adzerk.net/reddit/ads.html?sr=-reddit.com&bust2 GET /pixel/of_doom.png?id=t3_25jzeq-t8_k2ii&hash=da31d967485cdbd459ce1e9a5dde279fef7fc381&r=1738649500 HTTP/1.1 Host: pixel.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /Extensions/adFeedback.js HTTP/1.1 Host: static.adzrk.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: */* Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://static.adzerk.net/reddit/ads.html?sr=-reddit.com&bust2 GET /Extensions/adFeedback.css HTTP/1.1 Host: static.adzrk.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: text/css,*/*;q=0.1 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://static.adzerk.net/reddit/ads.html?sr=-reddit.com&bust2 GET /reddit/ads-load.html?bust2 HTTP/1.1 Host: static.adzerk.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /Advertisers/a774d7d6148046efa89403a8db635a81.jpg HTTP/1.1 Host: static.adzerk.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://static.adzerk.net/reddit/ads.html?sr=-reddit.com&bust2 GET /i.gif?e=eyJhdiI6NjIzNTcsImF0Ijo1LCJjbSI6MTE2MzUxLCJjaCI6Nzk4NCwiY3IiOjMzNzAxNSwiZGkiOiI4NmI2Y2UzYWM5NDM0MjhkOTk2ZTg4MjYwZDE5ZTE1YyIsImRtIjoxLCJmYyI6NDE2MTI4LCJmbCI6MjEwNDY0LCJrdyI6Ii1yZWRkaXQuY29tIiwibWsiOiItcmVkZGl0LmNvbSIsIm53Ijo1MTQ2LCJwYyI6MCwicHIiOjIwMzYyLCJydCI6MSwicmYiOiJodHRwOi8vd3d3LnJlZGRpdC5jb20vIiwic3QiOjI0OTUwLCJ1ayI6InVlMS01ZWIwOGFlZWQ5YTc0MDFjOTE5NWNiOTMzZWI3Yzk2NiIsInRzIjoxNDAwODYyNTkzNjQ1fQ&s=lwlbFf2Uywt7zVBFRj_qXXu7msY HTTP/1.1 Host: engine.adzerk.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://static.adzerk.net/reddit/ads.html?sr=-reddit.com&bust2 Cookie: azk=ue1-5eb08aeed9a7401c9195cb933eb7c966 GET /BurstingPipe/adServer.bs?cn=tf&c=19&mc=imp&pli=9994987&PluID=0&ord=1400862593644&rtu=-1 HTTP/1.1 Host: bs.serving-sys.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://static.adzerk.net/reddit/ads.html?sr=-reddit.com&bust2 GET /Advertisers/63cfd0044ffd49c0a71a6626f7a1d8f0.jpg HTTP/1.1 Host: static.adzerk.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://static.adzerk.net/reddit/ads-load.html?bust2 GET /BurstingPipe/adServer.bs?cn=tf&c=19&mc=imp&pli=9962555&PluID=0&ord=1400862593645&rtu=-1 HTTP/1.1 Host: bs.serving-sys.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://static.adzerk.net/reddit/ads-load.html?bust2 Cookie: S_9994987=6754579095859875029; A4=01fmFvgRnI09SF00000; u2=d1263d39-874b-4a89-86cd-a2ab0860ed4e3Zl040 GET /i.gif?e=eyJhdiI6NjIzNTcsImF0Ijo4LCJjbSI6MTE2MzUxLCJjaCI6Nzk4NCwiY3IiOjMzNzAxOCwiZGkiOiI3OTdlZjU3OWQ5NjE0ODdiODYyMGMyMGJkOTE4YzNiMSIsImRtIjoxLCJmYyI6NDE2MTMxLCJmbCI6MjEwNDY0LCJrdyI6Ii1yZWRkaXQuY29tIiwibWsiOiItcmVkZGl0LmNvbSIsIm53Ijo1MTQ2LCJwYyI6MCwicHIiOjIwMzYyLCJydCI6MSwicmYiOiJodHRwOi8vd3d3LnJlZGRpdC5jb20vIiwic3QiOjI0OTUwLCJ1ayI6InVlMS01ZWIwOGFlZWQ5YTc0MDFjOTE5NWNiOTMzZWI3Yzk2NiIsInRzIjoxNDAwODYyNTkzNjQ2fQ&s=OjzxzXAgQksbdQOHNm-bjZcnZPA HTTP/1.1 Host: engine.adzerk.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://static.adzerk.net/reddit/ads-load.html?bust2 Cookie: azk=ue1-5eb08aeed9a7401c9195cb933eb7c966 GET /subscribe?host_int=1042356184&ns_map=571794054_374233948806,464381511_13349283399&user_id=245722467&nid=1399334269710011966&ts=1400862514 HTTP/1.1 Host: notify8.dropbox.com Accept-Encoding: identity Connection: keep-alive X-Dropbox-Locale: en_US User-Agent: DropboxDesktopClient/2.7.54 (Macintosh; 10.8; ('i32',); en_US) ocaml-ocaml-re-5586c57/benchmarks/http.ml000066400000000000000000000021071467707551200202360ustar00rootroot00000000000000open Re let space = rep blank let crlf = str "\r\n" let token = rep1 @@ compl [ rg '\000' '\031'; set "\127)(<>@,;:\\/[]?={}" ] let meth = token let version = let digits = rep1 digit in let decimal = seq [ digits; opt (seq [ char '.'; digits ]) ] in seq [ str "HTTP/"; decimal ] ;; let uri = rep1 (compl [ char '\n' ]) let request_line = [ space; group meth; space; group uri; group version; space ] |> seq let header = let key = group (rep1 (Re.compl [ char ':' ])) in let value = group (rep1 (Re.compl [ char '\n' ])) in seq [ space; key; space; char ':'; space; value; space; crlf ] ;; let request' = seq [ request_line; crlf; rep header; crlf ] module Export = struct let request = request' let request_g = request' |> no_group let requests = request' |> rep1 let requests_g = request' |> no_group |> rep1 end let requests = Stdio.In_channel.read_all "benchmarks/http-requests.txt" let rec read_all pos re reqs = if pos < String.length reqs then ( let g = Re.exec ~pos re reqs in let _, pos = Re.Group.offset g 0 in read_all (pos + 1) re reqs) ;; ocaml-ocaml-re-5586c57/benchmarks/memory.ml000066400000000000000000000016121467707551200205670ustar00rootroot00000000000000open Core (* This set of benchmarks is designed for testing re's memory usage rather than speed. *) module Bench = Core_bench.Bench let size = 1_000 (* a pathological re that will consume a bunch of memory *) let re () = let open Re in compile @@ seq [ rep (set "01"); char '1'; repn (set "01") size (Some size) ] ;; (* Another pathological case that is a simplified version of the above *) let re2 () = let open Re in seq [ rep (set "01"); char '1'; repn (set "01") size (Some size); char 'x' ] |> compile ;; let str = "01" ^ String.make size '1' let benchmarks = [ "memory 1", re; "memory 2", re2 ] |> ListLabels.map ~f:(fun (name, re) -> Bench.Test.create_indexed ~name ~args:[ 10; 20; 40; 80; 100; size ] (fun len -> Staged.stage (fun () -> let re = re () in let len = Int.min (String.length str) len in ignore (Re.execp ~pos:0 ~len re str)))) ;; ocaml-ocaml-re-5586c57/benchmarks/memory.mli000066400000000000000000000000561467707551200207410ustar00rootroot00000000000000val benchmarks : Core_bench.Bench.Test.t list ocaml-ocaml-re-5586c57/benchmarks/tex.gitignore000066400000000000000000000035651467707551200214470ustar00rootroot00000000000000## Core latex/pdflatex auxiliary files: *.aux *.lof *.log *.lot *.fls *.out *.toc *.fmt *.fot *.cb *.cb2 ## Intermediate documents: *.dvi *-converted-to.* # these rules might exclude image files for figures etc. # *.ps # *.eps # *.pdf ## Generated if empty string is given at "Please type another file name for output:" .pdf ## Bibliography auxiliary files (bibtex/biblatex/biber): *.bbl *.bcf *.blg *-blx.aux *-blx.bib *.brf *.run.xml ## Build tool auxiliary files: *.fdb_latexmk *.synctex *.synctex(busy) *.synctex.gz *.synctex.gz(busy) *.pdfsync ## Auxiliary and intermediate files from other packages: # algorithms *.alg *.loa # achemso acs-*.bib # amsthm *.thm # beamer *.nav *.snm *.vrb # cprotect *.cpt # fixme *.lox #(r)(e)ledmac/(r)(e)ledpar *.end *.?end *.[1-9] *.[1-9][0-9] *.[1-9][0-9][0-9] *.[1-9]R *.[1-9][0-9]R *.[1-9][0-9][0-9]R *.eledsec[1-9] *.eledsec[1-9]R *.eledsec[1-9][0-9] *.eledsec[1-9][0-9]R *.eledsec[1-9][0-9][0-9] *.eledsec[1-9][0-9][0-9]R # glossaries *.acn *.acr *.glg *.glo *.gls *.glsdefs # gnuplottex *-gnuplottex-* # gregoriotex *.gaux *.gtex # hyperref *.brf # knitr *-concordance.tex # TODO Comment the next line if you want to keep your tikz graphics files *.tikz *-tikzDictionary # listings *.lol # makeidx *.idx *.ilg *.ind *.ist # minitoc *.maf *.mlf *.mlt *.mtc *.mtc[0-9] *.mtc[1-9][0-9] # minted _minted* *.pyg # morewrites *.mw # mylatexformat *.fmt # nomencl *.nlo # sagetex *.sagetex.sage *.sagetex.py *.sagetex.scmd # scrwfile *.wrt # sympy *.sout *.sympy sympy-plots-for-*.tex/ # pdfcomment *.upa *.upb # pythontex *.pytxcode pythontex-files-*/ # thmtools *.loe # TikZ & PGF *.dpth *.md5 *.auxlock # todonotes *.tdo # easy-todo *.lod # xindy *.xdy # xypic precompiled matrices *.xyc # endfloat *.ttt *.fff # Latexian TSWLatexianTemp* ## Editors: # WinEdt *.bak *.sav # Texpad .texpadtmp # Kile *.backup # KBibTeX *~[0-9]*ocaml-ocaml-re-5586c57/benchmarks/tex.ml000066400000000000000000000006651467707551200200660ustar00rootroot00000000000000open Core let ignore_re = Stdio.In_channel.read_lines "benchmarks/tex.gitignore" |> List.map ~f:(fun s -> match Base.String.lsplit2 s ~on:'#' with | Some (pattern, _comment) -> pattern | None -> s) |> List.filter_map ~f:(fun s -> match Base.String.strip s with | "" -> None | s -> Some s) |> List.map ~f:Re.Glob.glob |> Re.alt ;; let ignore_filesnames = Stdio.In_channel.read_lines "benchmarks/files" ocaml-ocaml-re-5586c57/deprecated/000077500000000000000000000000001467707551200167105ustar00rootroot00000000000000ocaml-ocaml-re-5586c57/deprecated/dune000066400000000000000000000015671467707551200175770ustar00rootroot00000000000000(env (_ (flags (:standard -w -53)))) (library (name re_str) (public_name re.str) (wrapped false) (modules re_str) (synopsis "Deprecated. Use Re.Str") (libraries re)) (library (name re_pcre) (public_name re.pcre) (wrapped false) (modules re_pcre) (synopsis "Deprecated. Use Re.Pcre") (libraries re)) (library (name re_perl) (public_name re.perl) (wrapped false) (modules re_perl) (synopsis "Deprecated. Use Re.Perl") (libraries re)) (library (name re_posix) (public_name re.posix) (wrapped false) (modules re_posix) (synopsis "Deprecated. Use Re.Posix") (libraries re)) (library (name re_emacs) (public_name re.emacs) (wrapped false) (modules re_emacs) (synopsis "Deprecated. Use Re.Emacs") (libraries re)) (library (name re_glob) (public_name re.glob) (wrapped false) (modules re_glob) (synopsis "Deprecated. Use Re.Glob") (libraries re)) ocaml-ocaml-re-5586c57/deprecated/re_emacs.ml000066400000000000000000000000611467707551200210150ustar00rootroot00000000000000[@@@deprecated "Use Re.Emacs"] include Re.Emacs ocaml-ocaml-re-5586c57/deprecated/re_glob.ml000066400000000000000000000000571467707551200206550ustar00rootroot00000000000000[@@@deprecated "Use Re.Glob"] include Re.Glob ocaml-ocaml-re-5586c57/deprecated/re_pcre.ml000066400000000000000000000000571467707551200206630ustar00rootroot00000000000000[@@@deprecated "Use Re.Pcre"] include Re.Pcre ocaml-ocaml-re-5586c57/deprecated/re_perl.ml000066400000000000000000000000571467707551200206740ustar00rootroot00000000000000[@@@deprecated "Use Re.Perl"] include Re.Perl ocaml-ocaml-re-5586c57/deprecated/re_posix.ml000066400000000000000000000000611467707551200210670ustar00rootroot00000000000000[@@@deprecated "Use Re.Posix"] include Re.Posix ocaml-ocaml-re-5586c57/deprecated/re_str.ml000066400000000000000000000000551467707551200205400ustar00rootroot00000000000000[@@@deprecated "Use Re.Str"] include Re.Str ocaml-ocaml-re-5586c57/dune000066400000000000000000000000531467707551200154640ustar00rootroot00000000000000(env (_ (flags (:standard -w -50)))) ocaml-ocaml-re-5586c57/dune-project000066400000000000000000000015161467707551200171350ustar00rootroot00000000000000(lang dune 3.12) (name re) (generate_opam_files true) (implicit_transitive_deps false) (license "LGPL-2.1-or-later WITH OCaml-LGPL-linking-exception") (maintainers "Rudi Grinberg ") (authors "Jerome Vouillon" "Thomas Gazagnaire" "Anil Madhavapeddy" "Rudi Grinberg" "Gabriel Radanne") (source (github ocaml/ocaml-re)) (package (name re) (synopsis "RE is a regular expression library for OCaml") (depends (ocaml (>= 4.12.0)) seq (ppx_expect :with-test) (ounit2 :with-test)) (description " Pure OCaml regular expressions with: * Perl-style regular expressions (module Re.Perl) * Posix extended regular expressions (module Re.Posix) * Emacs-style regular expressions (module Re.Emacs) * Shell-style file globbing (module Re.Glob) * Compatibility layer for OCaml's built-in Str module (module Re.Str) ")) ocaml-ocaml-re-5586c57/flake.lock000066400000000000000000000065041467707551200165510ustar00rootroot00000000000000{ "nodes": { "flake-utils": { "inputs": { "systems": "systems" }, "locked": { "lastModified": 1726560853, "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", "owner": "numtide", "repo": "flake-utils", "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", "type": "github" }, "original": { "owner": "numtide", "repo": "flake-utils", "type": "github" } }, "flake-utils_2": { "inputs": { "systems": "systems_2" }, "locked": { "lastModified": 1726560853, "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", "owner": "numtide", "repo": "flake-utils", "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", "type": "github" }, "original": { "owner": "numtide", "repo": "flake-utils", "type": "github" } }, "nix-filter": { "locked": { "lastModified": 1710156097, "narHash": "sha256-1Wvk8UP7PXdf8bCCaEoMnOT1qe5/Duqgj+rL8sRQsSM=", "owner": "numtide", "repo": "nix-filter", "rev": "3342559a24e85fc164b295c3444e8a139924675b", "type": "github" }, "original": { "owner": "numtide", "repo": "nix-filter", "type": "github" } }, "nixpkgs": { "inputs": { "flake-utils": "flake-utils_2", "nixpkgs": "nixpkgs_2" }, "locked": { "lastModified": 1727203675, "narHash": "sha256-ibsyYaGi8KfmxkbNsy8eR1L6zT4WCAQzIEP9EcOoXJo=", "owner": "nix-ocaml", "repo": "nix-overlays", "rev": "aaa9425cea232424d486f1123f5168f2a70346cc", "type": "github" }, "original": { "owner": "nix-ocaml", "repo": "nix-overlays", "type": "github" } }, "nixpkgs_2": { "locked": { "lastModified": 1727190658, "narHash": "sha256-hO8ullPTzvBvwd+o0dzH8SDbkNcTuUQQhex5LW45heY=", "owner": "NixOS", "repo": "nixpkgs", "rev": "5620491106cfe8c2db0628161b93830d66506ffc", "type": "github" }, "original": { "owner": "NixOS", "repo": "nixpkgs", "rev": "5620491106cfe8c2db0628161b93830d66506ffc", "type": "github" } }, "root": { "inputs": { "flake-utils": "flake-utils", "nix-filter": "nix-filter", "nixpkgs": "nixpkgs" } }, "systems": { "locked": { "lastModified": 1681028828, "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", "owner": "nix-systems", "repo": "default", "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", "type": "github" }, "original": { "owner": "nix-systems", "repo": "default", "type": "github" } }, "systems_2": { "locked": { "lastModified": 1681028828, "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", "owner": "nix-systems", "repo": "default", "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", "type": "github" }, "original": { "owner": "nix-systems", "repo": "default", "type": "github" } } }, "root": "root", "version": 7 } ocaml-ocaml-re-5586c57/flake.nix000066400000000000000000000021551467707551200164150ustar00rootroot00000000000000{ description = "ocaml-re flake"; inputs.nix-filter.url = "github:numtide/nix-filter"; inputs.flake-utils.url = "github:numtide/flake-utils"; inputs.nixpkgs.url = "github:nix-ocaml/nix-overlays"; outputs = { self, nixpkgs, flake-utils, nix-filter }: flake-utils.lib.eachDefaultSystem (system: let pkgs = nixpkgs.legacyPackages."${system}"; inherit (pkgs.ocamlPackages) buildDunePackage; in rec { packages = rec { default = re; re = buildDunePackage { pname = "re"; version = "n/a"; src = ./.; duneVersion = "3"; propagatedBuildInputs = with pkgs.ocamlPackages; [ seq ]; checkInputs = with pkgs.ocamlPackages; [ ounit ]; doCheck = true; }; }; devShells.default = pkgs.mkShell { inputsFrom = pkgs.lib.attrValues packages; buildInputs = with pkgs.ocamlPackages; [ ocaml-lsp core_bench pkgs.ocamlformat_0_26_2 js_of_ocaml pkgs.nodejs-slim ]; }; }); } ocaml-ocaml-re-5586c57/lib/000077500000000000000000000000001467707551200153565ustar00rootroot00000000000000ocaml-ocaml-re-5586c57/lib/ast.ml000066400000000000000000000253741467707551200165120ustar00rootroot00000000000000open Import type ('a, _) ast = | Alternative : 'a list -> ('a, [> `Uncased ]) ast | No_case : 'a -> ('a, [> `Cased ]) ast | Case : 'a -> ('a, [> `Cased ]) ast let empty_alternative : ('a, 'b) ast = Alternative [] let equal_ast (type a) eq (x : (a, [ `Uncased ]) ast) (y : (a, [ `Uncased ]) ast) = match x, y with | Alternative a, Alternative b -> List.equal ~eq a b ;; let pp_ast (type a b) f fmt (ast : (a, b) ast) = let open Fmt in let var s re = sexp fmt s f re in match ast with | Alternative alt -> sexp fmt "Alternative" (list f) alt | Case c -> var "Case" c | No_case c -> var "No_case" c ;; type cset = | Cset of Cset.t | Intersection of cset list | Complement of cset list | Difference of cset * cset | Cast of (cset, [ `Cased | `Uncased ]) ast type ('a, 'case) gen = | Set of 'a | Ast of (('a, 'case) gen, 'case) ast | Sequence of ('a, 'case) gen list | Repeat of ('a, 'case) gen * int * int option | Beg_of_line | End_of_line | Beg_of_word | End_of_word | Not_bound | Beg_of_str | End_of_str | Last_end_of_line | Start | Stop | Group of string option * ('a, 'case) gen | No_group of ('a, 'case) gen | Nest of ('a, 'case) gen | Pmark of Pmark.t * ('a, 'case) gen | Sem of Automata.Sem.t * ('a, 'case) gen | Sem_greedy of Automata.Rep_kind.t * ('a, 'case) gen let rec pp_gen pp_cset fmt t = let open Format in let open Fmt in let pp = pp_gen pp_cset in let var s re = sexp fmt s pp re in let seq s rel = sexp fmt s (list pp) rel in match t with | Set cset -> pp_cset fmt cset | Sequence sq -> seq "Sequence" sq | Repeat (re, start, stop) -> let pp' fmt () = fprintf fmt "%a@ %d%a" pp re start optint stop in sexp fmt "Repeat" pp' () | Beg_of_line -> str fmt "Beg_of_line" | End_of_line -> str fmt "End_of_line" | Beg_of_word -> str fmt "Beg_of_word" | End_of_word -> str fmt "End_of_word" | Not_bound -> str fmt "Not_bound" | Beg_of_str -> str fmt "Beg_of_str" | End_of_str -> str fmt "End_of_str" | Last_end_of_line -> str fmt "Last_end_of_line" | Start -> str fmt "Start" | Stop -> str fmt "Stop" | Group (None, c) -> var "Group" c | Group (Some n, c) -> sexp fmt "Named_group" (pair str pp) (n, c) | Nest c -> var "Nest" c | Pmark (m, r) -> sexp fmt "Pmark" (pair Pmark.pp pp) (m, r) | Ast a -> pp_ast pp fmt a | Sem (sem, a) -> sexp fmt "Sem" (pair Automata.Sem.pp pp) (sem, a) | Sem_greedy (k, re) -> sexp fmt "Sem_greedy" (pair Automata.Rep_kind.pp pp) (k, re) | No_group c -> var "No_group" c ;; let rec pp_cset fmt cset = let open Fmt in let seq s rel = sexp fmt s (list pp_cset) rel in match cset with | Cast s -> pp_ast pp_cset fmt s | Cset s -> sexp fmt "Set" Cset.pp s | Intersection c -> seq "Intersection" c | Complement c -> seq "Complement" c | Difference (a, b) -> sexp fmt "Difference" (pair pp_cset pp_cset) (a, b) ;; let rec equal cset x1 x2 = match x1, x2 with | Set s1, Set s2 -> cset s1 s2 | Sequence l1, Sequence l2 -> List.equal ~eq:(equal cset) l1 l2 | Repeat (x1', i1, j1), Repeat (x2', i2, j2) -> Int.equal i1 i2 && Option.equal Int.equal j1 j2 && equal cset x1' x2' | Beg_of_line, Beg_of_line | End_of_line, End_of_line | Beg_of_word, Beg_of_word | End_of_word, End_of_word | Not_bound, Not_bound | Beg_of_str, Beg_of_str | End_of_str, End_of_str | Last_end_of_line, Last_end_of_line | Start, Start | Stop, Stop -> true | Group _, Group _ -> (* Do not merge groups! *) false | Pmark (m1, r1), Pmark (m2, r2) -> Pmark.equal m1 m2 && equal cset r1 r2 | Nest x, Nest y -> equal cset x y | Ast x, Ast y -> equal_ast (equal cset) x y | Sem (sem, a), Sem (sem', a') -> Poly.equal sem sem' && equal cset a a' | Sem_greedy (rep, a), Sem_greedy (rep', a') -> Poly.equal rep rep' && equal cset a a' | _ -> false ;; type t = (cset, [ `Cased | `Uncased ]) gen type no_case = (Cset.t, [ `Uncased ]) gen let pp = pp_gen pp_cset let cset cset = Set (Cset cset) let rec handle_case_cset ign_case = function | Cset s -> if ign_case then Cset.case_insens s else s | Cast (Alternative l) -> List.map ~f:(handle_case_cset ign_case) l |> Cset.union_all | Complement l -> List.map ~f:(handle_case_cset ign_case) l |> Cset.union_all |> Cset.diff Cset.cany | Difference (r, r') -> Cset.inter (handle_case_cset ign_case r) (Cset.diff Cset.cany (handle_case_cset ign_case r')) | Intersection l -> List.map ~f:(handle_case_cset ign_case) l |> Cset.intersect_all | Cast (No_case a) -> handle_case_cset true a | Cast (Case a) -> handle_case_cset false a ;; let rec handle_case ign_case : t -> (Cset.t, [ `Uncased ]) gen = function | Set s -> Set (handle_case_cset ign_case s) | Sequence l -> Sequence (List.map ~f:(handle_case ign_case) l) | Ast (Alternative l) -> let l = List.map ~f:(handle_case ign_case) l in Ast (Alternative l) | Repeat (r, i, j) -> Repeat (handle_case ign_case r, i, j) | ( Beg_of_line | End_of_line | Beg_of_word | End_of_word | Not_bound | Beg_of_str | End_of_str | Last_end_of_line | Start | Stop ) as r -> r | Sem (k, r) -> Sem (k, handle_case ign_case r) | Sem_greedy (k, r) -> Sem_greedy (k, handle_case ign_case r) | Group (n, r) -> Group (n, handle_case ign_case r) | No_group r -> No_group (handle_case ign_case r) | Nest r -> Nest (handle_case ign_case r) | Ast (Case r) -> handle_case false r | Ast (No_case r) -> handle_case true r | Pmark (i, r) -> Pmark (i, handle_case ign_case r) ;; module Export = struct type nonrec t = t let pp = pp let seq = function | [ r ] -> r | l -> Sequence l ;; let char c : t = cset (Cset.csingle c) let any = cset Cset.cany let str s : t = let l = ref [] in for i = String.length s - 1 downto 0 do l := char s.[i] :: !l done; seq !l ;; let as_set_elems elems = match List.map elems ~f:(function | Set e -> e | _ -> raise_notrace Exit) with | exception Exit -> None | e -> Some e ;; let empty : t = Ast empty_alternative let alt (elems : t list) : t = match elems with | [] -> empty | [ x ] -> x | _ -> (match as_set_elems elems with | None -> Ast (Alternative elems) | Some elems -> Set (Cast (Alternative elems))) ;; let epsilon = seq [] let repn r i j = if i < 0 then invalid_arg "Re.repn"; match j, i with | Some j, _ when j < i -> invalid_arg "Re.repn" | Some 0, 0 -> epsilon | Some 1, 1 -> r | _ -> Repeat (r, i, j) ;; let rep r = repn r 0 None let rep1 r = repn r 1 None let opt r = repn r 0 (Some 1) let bol = Beg_of_line let eol = End_of_line let bow = Beg_of_word let eow = End_of_word let word r = seq [ bow; r; eow ] let not_boundary = Not_bound let bos = Beg_of_str let eos = End_of_str let whole_string r = seq [ bos; r; eos ] let leol = Last_end_of_line let start = Start let stop = Stop type 'b f = { f : 'a. 'a -> ('a, 'b) ast } let make_set f t = match t with | Set x -> Set (Cast (f.f x)) | _ -> Ast (f.f t) ;; let preserve_set f t = match t with | Set _ -> t | _ -> f t ;; let longest = preserve_set (fun t -> Sem (`Longest, t)) let shortest = preserve_set (fun t -> Sem (`Shortest, t)) let first = preserve_set (fun t -> Sem (`First, t)) let greedy = preserve_set (fun t -> Sem_greedy (`Greedy, t)) let non_greedy = preserve_set (fun t -> Sem_greedy (`Non_greedy, t)) let group ?name r = Group (name, r) let no_group = preserve_set (fun t -> No_group t) let nest r = Nest r let set str = cset (Cset.set str) let mark r = let i = Pmark.gen () in i, Pmark (i, r) ;; (**** Character sets ****) let as_set_or_error name elems = match as_set_elems elems with | None -> invalid_arg name | Some s -> s ;; let inter elems = Set (Intersection (as_set_or_error "Re.inter" elems)) let compl elems = Set (Complement (as_set_or_error "Re.compl" elems)) let diff r r' = match r, r' with | Set r, Set r' -> Set (Difference (r, r')) | _, _ -> invalid_arg "Re.diff" ;; let case = let f = { f = (fun r -> Case r) } in fun t -> make_set f t ;; let no_case = let f = { f = (fun r -> No_case r) } in fun t -> make_set f t ;; let witness t = let rec witness (t : no_case) = match t with | Set c -> String.make 1 (Cset.to_char (Cset.pick c)) | Sequence xs -> String.concat "" (List.map ~f:witness xs) | Ast (Alternative (x :: _)) -> witness x | Ast (Alternative []) -> assert false | Repeat (r, from, _to) -> let w = witness r in let b = Buffer.create (String.length w * from) in for _i = 1 to from do Buffer.add_string b w done; Buffer.contents b | No_group r -> witness r | Sem_greedy (_, r) | Sem (_, r) | Nest r | Pmark (_, r) | Group (_, r) -> witness r | Beg_of_line | End_of_line | Beg_of_word | End_of_word | Not_bound | Beg_of_str | Last_end_of_line | Start | Stop | End_of_str -> "" in witness (handle_case false t) ;; end open Export let rec merge_sequences = function | [] -> [] | Ast (Alternative l') :: r -> merge_sequences (l' @ r) | Sequence (x :: y) :: r -> (match merge_sequences r with | Sequence (x' :: y') :: r' when equal Cset.equal x x' -> Sequence [ x; Ast (Alternative [ seq y; seq y' ]) ] :: r' | r' -> Sequence (x :: y) :: r') | x :: r -> x :: merge_sequences r ;; (*XXX Use a better algorithm allowing non-contiguous regions? *) let colorize color_map (regexp : no_case) = let lnl = ref false in let rec colorize regexp = match (regexp : no_case) with | Set s -> Color_map.split color_map s | Sequence l -> List.iter ~f:colorize l | Ast (Alternative l) -> List.iter ~f:colorize l | Repeat (r, _, _) -> colorize r | Beg_of_line | End_of_line -> Color_map.split color_map Cset.nl | Beg_of_word | End_of_word | Not_bound -> Color_map.split color_map Cset.cword | Beg_of_str | End_of_str | Start | Stop -> () | Last_end_of_line -> lnl := true | No_group r | Group (_, r) | Nest r | Pmark (_, r) -> colorize r | Sem (_, r) | Sem_greedy (_, r) -> colorize r in colorize regexp; !lnl ;; let rec anchored_ast : (t, _) ast -> bool = function | Alternative als -> List.for_all ~f:anchored als | No_case r | Case r -> anchored r and anchored : t -> bool = function | Ast a -> anchored_ast a | Sequence l -> List.exists ~f:anchored l | Repeat (r, i, _) -> i > 0 && anchored r | No_group r | Sem (_, r) | Sem_greedy (_, r) | Group (_, r) | Nest r | Pmark (_, r) -> anchored r | Set _ | Beg_of_line | End_of_line | Beg_of_word | End_of_word | Not_bound | End_of_str | Last_end_of_line | Stop -> false | Beg_of_str | Start -> true ;; let t_of_cset x = Set x ocaml-ocaml-re-5586c57/lib/ast.mli000066400000000000000000000042251467707551200166530ustar00rootroot00000000000000type ('a, _) ast = private | Alternative : 'a list -> ('a, [> `Uncased ]) ast | No_case : 'a -> ('a, [> `Cased ]) ast | Case : 'a -> ('a, [> `Cased ]) ast type cset = private | Cset of Cset.t | Intersection of cset list | Complement of cset list | Difference of cset * cset | Cast of (cset, [ `Cased | `Uncased ]) ast type ('a, 'case) gen = private | Set of 'a | Ast of (('a, 'case) gen, 'case) ast | Sequence of ('a, 'case) gen list | Repeat of ('a, 'case) gen * int * int option | Beg_of_line | End_of_line | Beg_of_word | End_of_word | Not_bound | Beg_of_str | End_of_str | Last_end_of_line | Start | Stop | Group of string option * ('a, 'case) gen | No_group of ('a, 'case) gen | Nest of ('a, 'case) gen | Pmark of Pmark.t * ('a, 'case) gen | Sem of Automata.Sem.t * ('a, 'case) gen | Sem_greedy of Automata.Rep_kind.t * ('a, 'case) gen type t = (cset, [ `Cased | `Uncased ]) gen type no_case = (Cset.t, [ `Uncased ]) gen val pp : t Fmt.t val merge_sequences : (Cset.t, [ `Uncased ]) gen list -> (Cset.t, [ `Uncased ]) gen list val handle_case : bool -> t -> (Cset.t, [ `Uncased ]) gen val anchored : t -> bool val colorize : Color_map.t -> (Cset.t, [ `Uncased ]) gen -> bool module Export : sig type nonrec t = t val empty : t val epsilon : t val str : string -> t val no_case : t -> t val case : t -> t val diff : t -> t -> t val compl : t list -> t val repn : t -> int -> int option -> t val inter : t list -> t val char : char -> t val any : t val set : string -> t val mark : t -> Pmark.t * t val nest : t -> t val no_group : t -> t val whole_string : t -> t val leol : t val longest : t -> t val greedy : t -> t val non_greedy : t -> t val stop : t val not_boundary : t val group : ?name:string -> t -> t val word : t -> t val first : t -> t val bos : t val bow : t val eow : t val eos : t val bol : t val start : t val eol : t val opt : t -> t val rep : t -> t val rep1 : t -> t val alt : t list -> t val shortest : t -> t val seq : t list -> t val pp : t Fmt.t val witness : t -> string end val cset : Cset.t -> t val t_of_cset : cset -> t ocaml-ocaml-re-5586c57/lib/automata.ml000066400000000000000000000377311467707551200175360ustar00rootroot00000000000000open Import (* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr 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, with linking exception; 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 *) let hash_combine h accu = (accu * 65599) + h module Ids : sig module Id : sig type t val equal : t -> t -> bool val zero : t val hash : t -> int val pp : t Fmt.t module Hash_set : sig type id := t type t val create : unit -> t val mem : t -> id -> bool val add : t -> id -> unit val clear : t -> unit end end type t val create : unit -> t val next : t -> Id.t end = struct module Id = struct type t = int module Hash_set = Hash_set let equal = Int.equal let zero = 0 let hash x = x let pp = Fmt.int end type t = int ref let create () = ref 0 let next t = incr t; !t ;; end module Id = Ids.Id module Sem = struct type t = [ `Longest | `Shortest | `First ] let equal = Poly.equal let pp ch k = Format.pp_print_string ch (match k with | `Shortest -> "short" | `Longest -> "long" | `First -> "first") ;; end module Rep_kind = struct type t = [ `Greedy | `Non_greedy ] let pp fmt = function | `Greedy -> Format.pp_print_string fmt "Greedy" | `Non_greedy -> Format.pp_print_string fmt "Non_greedy" ;; end module Mark : sig type t = private int val compare : t -> t -> int val equal : t -> t -> bool val pp : t Fmt.t val start : t val prev : t -> t val next : t -> t val next2 : t -> t val group_count : t -> int val outside_range : t -> start_inclusive:t -> stop_inclusive:t -> bool end = struct type t = int let equal = Int.equal let compare = Int.compare let pp = Format.pp_print_int let start = 0 let prev x = pred x let next x = succ x let next2 x = x + 2 let group_count x = x / 2 let outside_range t ~start_inclusive ~stop_inclusive = t < start_inclusive || t > stop_inclusive ;; end module Idx : sig type t = private int val pp : t Fmt.t val to_int : t -> int val unknown : t val initial : t val used : t -> bool val make : int -> t val equal : t -> t -> bool end = struct type t = int let to_int x = x let pp = Format.pp_print_int let used t = t >= 0 let make x = x let equal = Int.equal let unknown = -1 let initial = 0 end module Expr = struct type t = { id : Id.t ; def : def } and def = | Cst of Cset.t | Alt of t list | Seq of Sem.t * t * t | Eps | Rep of Rep_kind.t * Sem.t * t | Mark of Mark.t | Erase of Mark.t * Mark.t | Before of Category.t | After of Category.t | Pmark of Pmark.t let rec pp ch e = let open Fmt in match e.def with | Cst l -> sexp ch "cst" Cset.pp l | Alt l -> sexp ch "alt" (list pp) l | Seq (k, e, e') -> sexp ch "seq" (triple Sem.pp pp pp) (k, e, e') | Eps -> str ch "eps" | Rep (_rk, k, e) -> sexp ch "rep" (pair Sem.pp pp) (k, e) | Mark i -> sexp ch "mark" Mark.pp i | Pmark i -> sexp ch "pmark" Pmark.pp i | Erase (b, e) -> sexp ch "erase" (pair Mark.pp Mark.pp) (b, e) | Before c -> sexp ch "before" Category.pp c | After c -> sexp ch "after" Category.pp c ;; let eps_expr = { id = Id.zero; def = Eps } let mk ids def = { id = Ids.next ids; def } let empty ids = mk ids (Alt []) let cst ids s = if Cset.is_empty s then empty ids else mk ids (Cst s) let eps ids = mk ids Eps let rep ids kind sem x = mk ids (Rep (kind, sem, x)) let mark ids m = mk ids (Mark m) let pmark ids i = mk ids (Pmark i) let erase ids m m' = mk ids (Erase (m, m')) let before ids c = mk ids (Before c) let after ids c = mk ids (After c) let alt ids = function | [] -> empty ids | [ c ] -> c | l -> mk ids (Alt l) ;; let seq ids (kind : Sem.t) x y = match x.def, y.def with | Alt [], _ -> x | _, Alt [] -> y | Eps, _ -> y | _, Eps when Sem.equal kind `First -> x | _ -> mk ids (Seq (kind, x, y)) ;; let is_eps expr = match expr.def with | Eps -> true | _ -> false ;; let rec rename ids x = match x.def with | Cst _ | Eps | Mark _ | Pmark _ | Erase _ | Before _ | After _ -> mk ids x.def | Alt l -> mk ids (Alt (List.map ~f:(rename ids) l)) | Seq (k, y, z) -> mk ids (Seq (k, rename ids y, rename ids z)) | Rep (g, k, y) -> mk ids (Rep (g, k, rename ids y)) ;; end type expr = Expr.t include Expr module Marks = struct type t = { marks : (Mark.t * Idx.t) list ; pmarks : Pmark.Set.t } let equal { marks; pmarks } t = List.equal ~eq:(fun (x, y) (x', y') -> Mark.equal x x' && Idx.equal y y') marks t.marks && Pmark.Set.equal pmarks t.pmarks ;; let empty = { marks = []; pmarks = Pmark.Set.empty } let hash_marks_offset = let f acc ((a : Mark.t), (i : Idx.t)) = hash_combine (a :> int) (hash_combine (i :> int) acc) in fun l init -> List.fold_left l ~init ~f ;; let hash m accu = hash_marks_offset m.marks (hash_combine (Hashtbl.hash m.pmarks) accu) let marks_set_idx = let rec marks_set_idx idx marks = match marks with | [] -> [] | (a, idx') :: rem -> if Idx.equal idx' Idx.unknown then (a, idx) :: marks_set_idx idx rem else marks in fun marks idx -> { marks with marks = marks_set_idx idx marks.marks } ;; let filter t (b : Mark.t) (e : Mark.t) = { t with marks = List.filter t.marks ~f:(fun ((i : Mark.t), _) -> Mark.outside_range i ~start_inclusive:b ~stop_inclusive:e) } ;; let set_mark t (i : Mark.t) = { t with marks = (i, Idx.unknown) :: List.remove_assq i t.marks } ;; let set_pmark t i = { t with pmarks = Pmark.Set.add i t.pmarks } let pp fmt { marks; pmarks } = Format.pp_open_box fmt 1; (match marks with | [] -> () | _ :: _ -> Format.fprintf fmt "@[<2>marks@ %a@]" (Format.pp_print_list (fun fmt (a, i) -> Format.fprintf fmt "%a-%a" Mark.pp a Idx.pp i)) marks); (match Pmark.Set.to_list pmarks with | [] -> () | pmarks -> Format.fprintf fmt "@[<2>pmarks %a@]" (Format.pp_print_list Pmark.pp) pmarks); Format.pp_close_box fmt () ;; end module Status = struct type t = | Failed | Match of Mark_infos.t * Pmark.Set.t | Running end module Desc : sig module E : sig type t = private | TSeq of Sem.t * t list * Expr.t | TExp of Marks.t * Expr.t | TMatch of Marks.t val tmatch : Marks.t -> t val tseq : Sem.t -> t list -> Expr.t -> t list -> t list val initial : Expr.t -> t val eps : Marks.t -> t end type t = E.t list val set_idx : Idx.t -> t -> t val hash : t -> int -> int val equal : t -> t -> bool val status : t -> Status.t val first_match : t -> Marks.t option val remove_matches : t -> t val split_at_match : t -> t * t end = struct module E = struct type t = | TSeq of Sem.t * t list * Expr.t | TExp of Marks.t * Expr.t | TMatch of Marks.t let tmatch marks = TMatch marks let initial expr = TExp (Marks.empty, expr) let eps marks = TExp (marks, eps_expr) let rec equal_list l1 l2 = List.equal ~eq:equal l1 l2 and equal x y = match x, y with | TSeq (_, l1, e1), TSeq (_, l2, e2) -> Id.equal e1.id e2.id && equal_list l1 l2 | TExp (marks1, e1), TExp (marks2, e2) -> Id.equal e1.id e2.id && Marks.equal marks1 marks2 | TMatch marks1, TMatch marks2 -> Marks.equal marks1 marks2 | _, _ -> false ;; let rec hash (t : t) accu = match t with | TSeq (_, l, e) -> hash_combine 0x172a1bce (hash_combine (Id.hash e.id) (hash_list l accu)) | TExp (marks, e) -> hash_combine 0x2b4c0d77 (hash_combine (Id.hash e.id) (Marks.hash marks accu)) | TMatch marks -> hash_combine 0x1c205ad5 (Marks.hash marks accu) and hash_list = let f acc x = hash x acc in fun l init -> List.fold_left l ~init ~f ;; let tseq' kind x y = match x with | [] -> [] | [ TExp (marks, { def = Eps; _ }) ] -> [ TExp (marks, y) ] | _ -> [ TSeq (kind, x, y) ] ;; let tseq kind x y rem = tseq' kind x y @ rem end type t = E.t list open E let equal = E.equal_list let hash = E.hash_list let rec print_state_rec ch e (y : Expr.t) = match e with | TMatch marks -> Format.fprintf ch "@[<2>(Match@ %a)@]" Marks.pp marks | TSeq (_kind, l', x) -> Format.fprintf ch "@[<2>(Seq@ "; print_state_lst ch l' x; Format.fprintf ch "@ %a)@]" Expr.pp x | TExp (marks, { def = Eps; _ }) -> Format.fprintf ch "@[<2>(Exp@ %a@ (%a)@ (eps))@]" Id.pp y.id Marks.pp marks | TExp (marks, x) -> Format.fprintf ch "@[<2>(Exp@ %a@ (%a)@ %a)@]" Id.pp x.id Marks.pp marks Expr.pp x and print_state_lst ch l y = match l with | [] -> Format.fprintf ch "()" | e :: rem -> print_state_rec ch e y; List.iter rem ~f:(fun e -> Format.fprintf ch "@ | "; print_state_rec ch e y) ;; let pp ch t = print_state_lst ch [ t ] { id = Id.zero; def = Eps } let rec first_match = function | [] -> None | TMatch marks :: _ -> Some marks | _ :: r -> first_match r ;; let remove_matches = List.filter ~f:(function | TMatch _ -> false | _ -> true) ;; let split_at_match = let rec split_at_match_rec l = function | [] -> assert false | TMatch _ :: r -> List.rev l, remove_matches r | x :: r -> split_at_match_rec (x :: l) r in fun l -> split_at_match_rec [] l ;; let status : _ -> Status.t = function | [] -> Failed | TMatch m :: _ -> Match (Mark_infos.make (m.marks :> (int * int) list), m.pmarks) | _ -> Running ;; let set_idx = let rec f idx = function | TMatch marks -> TMatch (Marks.marks_set_idx marks idx) | TSeq (kind, l, x) -> TSeq (kind, set_idx idx l, x) | TExp (marks, x) -> TExp (Marks.marks_set_idx marks idx, x) and set_idx idx xs = List.map xs ~f:(f idx) in set_idx ;; let[@ocaml.warning "-32"] pp fmt t = Format.fprintf fmt "[%a]" (Format.pp_print_list ~pp_sep:(Fmt.lit "; ") pp) t ;; end module E = Desc.E module State = struct type t = { idx : Idx.t ; category : Category.t ; desc : Desc.t ; mutable status : Status.t option ; hash : int } let[@inline] idx t = t.idx let dummy = { idx = Idx.unknown; category = Category.dummy; desc = []; status = None; hash = -1 } ;; let hash idx cat desc = Desc.hash desc (hash_combine idx (hash_combine (Category.to_int cat) 0)) land 0x3FFFFFFF ;; let mk idx cat desc = { idx; category = cat; desc; status = None; hash = hash (idx :> int) cat desc } ;; let create cat e = mk Idx.initial cat [ E.initial e ] let equal { idx; category; desc; status = _; hash } t = Int.equal hash t.hash && Idx.equal idx t.idx && Category.equal category t.category && Desc.equal desc t.desc ;; let status s = match s.status with | Some s -> s | None -> let st = Desc.status s.desc in s.status <- Some st; st ;; module Table = Hashtbl.Make (struct type nonrec t = t let equal = equal let hash t = t.hash end) end (**** Find a free index ****) module Working_area = struct type t = { mutable ids : Bit_vector.t ; seen : Id.Hash_set.t } let create () = { ids = Bit_vector.create_zero 1; seen = Id.Hash_set.create () } let index_count w = Bit_vector.length w.ids let rec mark_used_indices tbl = List.iter ~f:(fun (e : E.t) -> match e with | TSeq (_, l, _) -> mark_used_indices tbl l | TExp (marks, _) | TMatch marks -> List.iter marks.marks ~f:(fun (_, i) -> if Idx.used i then Bit_vector.set tbl (i :> int) true)) ;; let rec find_free tbl idx len = if idx = len || not (Bit_vector.get tbl idx) then idx else find_free tbl (idx + 1) len ;; let free_index t l = Bit_vector.reset_zero t.ids; mark_used_indices t.ids l; let len = Bit_vector.length t.ids in let idx = find_free t.ids 0 len in if idx = len then t.ids <- Bit_vector.create_zero (2 * len); Idx.make idx ;; end (**** Computation of the next state ****) let remove_duplicates = let rec loop seen (l : Desc.t) y = match l with | [] -> [] | (TMatch _ as x) :: _ -> (* Truncate after first match *) [ x ] | TSeq (kind, l, x) :: r -> let l = loop seen l x in let r = loop seen r y in E.tseq kind l x r | (TExp (_marks, { def = Eps; _ }) as e) :: r -> if Id.Hash_set.mem seen y.id then loop seen r y else ( Id.Hash_set.add seen y.id; e :: loop seen r y) | (TExp (_marks, x) as e) :: r -> if Id.Hash_set.mem seen x.id then loop seen r y else ( Id.Hash_set.add seen x.id; e :: loop seen r y) in fun seen l y -> Id.Hash_set.clear seen; loop seen l y ;; type ctx = { c : Cset.c ; prev_cat : Category.t ; next_cat : Category.t } let rec delta_expr ({ c; _ } as ctx) marks (x : Expr.t) rem = (*Format.eprintf "%d@." x.id;*) match x.def with | Cst s -> if Cset.mem c s then E.eps marks :: rem else rem | Alt l -> delta_alt ctx marks l rem | Seq (kind, y, z) -> let y = delta_expr ctx marks y [] in delta_seq ctx kind y z rem | Rep (rep_kind, kind, y) -> let y, marks' = let y = delta_expr ctx marks y [] in match Desc.first_match y with | None -> y, marks | Some marks -> Desc.remove_matches y, marks in (match rep_kind with | `Greedy -> E.tseq kind y x (E.tmatch marks' :: rem) | `Non_greedy -> E.tmatch marks :: E.tseq kind y x rem) | Eps -> E.tmatch marks :: rem | Mark i -> E.tmatch (Marks.set_mark marks i) :: rem | Pmark i -> E.tmatch (Marks.set_pmark marks i) :: rem | Erase (b, e) -> E.tmatch (Marks.filter marks b e) :: rem | Before cat -> if Category.intersect ctx.next_cat cat then E.tmatch marks :: rem else rem | After cat -> if Category.intersect ctx.prev_cat cat then E.tmatch marks :: rem else rem and delta_alt ctx marks l rem = match l with | [] -> rem | y :: r -> delta_expr ctx marks y (delta_alt ctx marks r rem) and delta_seq ctx (kind : Sem.t) y z rem = match Desc.first_match y with | None -> E.tseq kind y z rem | Some marks -> (match kind with | `Longest -> E.tseq kind (Desc.remove_matches y) z (delta_expr ctx marks z rem) | `Shortest -> delta_expr ctx marks z (E.tseq kind (Desc.remove_matches y) z rem) | `First -> let y, y' = Desc.split_at_match y in E.tseq kind y z (delta_expr ctx marks z (E.tseq kind y' z rem))) ;; let rec delta_e ctx marks (x : E.t) rem = match x with | TSeq (kind, y, z) -> let y = delta_desc ctx marks y [] in delta_seq ctx kind y z rem | TExp (marks, e) -> delta_expr ctx marks e rem | TMatch _ -> x :: rem and delta_desc ctx marks l rem = match l with | [] -> rem | y :: r -> delta_e ctx marks y (delta_desc ctx marks r rem) ;; let delta (tbl_ref : Working_area.t) next_cat char (st : State.t) = let expr = let prev_cat = st.category in let ctx = { c = char; next_cat; prev_cat } in remove_duplicates tbl_ref.seen (delta_desc ctx Marks.empty st.desc []) Expr.eps_expr in let idx = Working_area.free_index tbl_ref expr in let expr = Desc.set_idx idx expr in State.mk idx next_cat expr ;; ocaml-ocaml-re-5586c57/lib/automata.mli000066400000000000000000000046721467707551200177050ustar00rootroot00000000000000(* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr 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, with linking exception; 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 *) (* Regular expressions *) module Mark : sig type t [@@immediate] val compare : t -> t -> int val start : t val prev : t -> t val next : t -> t val next2 : t -> t val group_count : t -> int end module Sem : sig type t = [ `Longest | `Shortest | `First ] val pp : t Fmt.t end module Rep_kind : sig type t = [ `Greedy | `Non_greedy ] val pp : t Fmt.t end type expr val is_eps : expr -> bool val pp : expr Fmt.t module Ids : sig type t val create : unit -> t end val cst : Ids.t -> Cset.t -> expr val empty : Ids.t -> expr val alt : Ids.t -> expr list -> expr val seq : Ids.t -> Sem.t -> expr -> expr -> expr val eps : Ids.t -> expr val rep : Ids.t -> Rep_kind.t -> Sem.t -> expr -> expr val mark : Ids.t -> Mark.t -> expr val pmark : Ids.t -> Pmark.t -> expr val erase : Ids.t -> Mark.t -> Mark.t -> expr val before : Ids.t -> Category.t -> expr val after : Ids.t -> Category.t -> expr val rename : Ids.t -> expr -> expr (****) (* States of the automata *) module Idx : sig type t val to_int : t -> int end module Status : sig type t = | Failed | Match of Mark_infos.t * Pmark.Set.t | Running end module State : sig type t val dummy : t val create : Category.t -> expr -> t val idx : t -> Idx.t val status : t -> Status.t module Table : Hashtbl.S with type key = t end (****) (* Computation of the states following a given state *) module Working_area : sig type t val create : unit -> t val index_count : t -> int end val delta : Working_area.t -> Category.t -> Cset.c -> State.t -> State.t ocaml-ocaml-re-5586c57/lib/bit_vector.ml000066400000000000000000000020531467707551200200500ustar00rootroot00000000000000type t = { len : int ; bits : Bytes.t } let byte s i = Char.code (Bytes.unsafe_get s i) let set_byte s i x = Bytes.unsafe_set s i (Char.chr x) let length t = t.len let unsafe_set v n b = let i = n lsr 3 in let c = byte v.bits i in let mask = 1 lsl (n land 7) in set_byte v.bits i (if b then c lor mask else c land lnot mask) ;; let set v n b = if n < 0 || n >= v.len then invalid_arg "Bit_vector.set"; unsafe_set v n b ;; let unsafe_get v n = let i = n lsr 3 in byte v.bits i land (1 lsl (n land 7)) > 0 ;; let get v n = if n < 0 || n >= v.len then invalid_arg "Bit_vector.get"; unsafe_get v n ;; let reset_zero t = Bytes.fill t.bits 0 (Bytes.length t.bits) '\000' let create_zero len = let bits = let r = len land 7 in let q = len lsr 3 in let len = if r = 0 then q else q + 1 in Bytes.make len '\000' in { len; bits } ;; let pp fmt { len; bits } = let len fmt () = Fmt.sexp fmt "len" Fmt.int len in let bits fmt () = Fmt.sexp fmt "bits" Fmt.bytes bits in Format.fprintf fmt "%a@.%a@." len () bits () ;; ocaml-ocaml-re-5586c57/lib/bit_vector.mli000066400000000000000000000002431467707551200202200ustar00rootroot00000000000000type t val length : t -> int val set : t -> int -> bool -> unit val create_zero : int -> t val get : t -> int -> bool val reset_zero : t -> unit val pp : t Fmt.t ocaml-ocaml-re-5586c57/lib/category.ml000066400000000000000000000011411467707551200175220ustar00rootroot00000000000000type t = int let equal (x : int) (y : int) = x = y let compare (x : int) (y : int) = compare x y let to_int x = x let pp = Format.pp_print_int let intersect x y = x land y <> 0 let ( ++ ) x y = x lor y let dummy = -1 let inexistant = 1 let letter = 2 let not_letter = 4 let newline = 8 let lastnewline = 16 let search_boundary = 32 let from_char = function (* Should match [cword] definition *) | 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_' | '\170' | '\181' | '\186' | '\192' .. '\214' | '\216' .. '\246' | '\248' .. '\255' -> letter | '\n' -> not_letter ++ newline | _ -> not_letter ;; ocaml-ocaml-re-5586c57/lib/category.mli000066400000000000000000000007671467707551200177100ustar00rootroot00000000000000(** Categories represent the various kinds of characters that can be tested by look-ahead and look-behind operations. This is more restricted than Cset, but faster. *) type t [@@immediate] val ( ++ ) : t -> t -> t val from_char : char -> t val dummy : t val inexistant : t val letter : t val not_letter : t val newline : t val lastnewline : t val search_boundary : t val to_int : t -> int val equal : t -> t -> bool val compare : t -> t -> int val intersect : t -> t -> bool val pp : t Fmt.t ocaml-ocaml-re-5586c57/lib/color_map.ml000066400000000000000000000026401467707551200176650ustar00rootroot00000000000000(* In reality, this can really be represented as a bool array. The representation is best thought of as a list of all chars along with a flag: (a, 0), (b, 1), (c, 0), (d, 0), ... characters belonging to the same color are represented by sequnces of characters with the flag set to 0. *) type t = Bytes.t module Repr = struct type t = string let repr t color = t.[Cset.to_int color] let length = String.length end module Table = struct type t = string let get_char t c = t.[Cset.to_int c] let get t c = Cset.of_char (String.unsafe_get t (Char.code c)) let translate_colors (cm : t) cset = Cset.fold_right cset ~init:Cset.empty ~f:(fun i j l -> let start = get_char cm i in let stop = get_char cm j in Cset.union (Cset.cseq start stop) l) ;; end let make () = Bytes.make 257 '\000' let flatten cm = let c = Bytes.create 256 in let color_repr = Bytes.create 256 in let v = ref 0 in Bytes.set c 0 '\000'; Bytes.set color_repr 0 '\000'; for i = 1 to 255 do if Bytes.get cm i <> '\000' then incr v; Bytes.set c i (Char.chr !v); Bytes.set color_repr !v (Char.chr i) done; Bytes.unsafe_to_string c, Bytes.sub_string color_repr 0 (!v + 1) ;; (* mark all the endpoints of the intervals of the char set with the 1 byte *) let split t set = Cset.iter set ~f:(fun i j -> Bytes.set t (Cset.to_int i) '\001'; Bytes.set t (Cset.to_int j + 1) '\001') ;; ocaml-ocaml-re-5586c57/lib/color_map.mli000066400000000000000000000012651467707551200200400ustar00rootroot00000000000000(* Color maps exists to provide an optimization for the regex engine. The fact that some characters are entirely equivalent for some regexes means that we can use them interchangeably. A color map assigns a color to every character in our character set. Any two characters with the same color will be treated equivalently by the automaton. *) type t module Repr : sig type t val repr : t -> Cset.c -> char val length : t -> int end module Table : sig type t val get_char : t -> Cset.c -> char val get : t -> char -> Cset.c val translate_colors : t -> Cset.t -> Cset.t end val make : unit -> t val flatten : t -> Table.t * Repr.t val split : t -> Cset.t -> unit ocaml-ocaml-re-5586c57/lib/compile.ml000066400000000000000000000435771467707551200173600ustar00rootroot00000000000000open Import let rec iter n f v = if Int.equal n 0 then v else iter (n - 1) f (f v) module Idx : sig type t [@@immediate] val unknown : t val make_break : Automata.Idx.t -> t val of_idx : Automata.Idx.t -> t val is_idx : t -> bool val is_break : t -> bool val idx : t -> int val break_idx : t -> int end = struct type t = int let unknown = -2 let break = -3 let of_idx (x : Automata.Idx.t) = Automata.Idx.to_int x [@@inline always] let is_idx t = t >= 0 [@@inline always] let is_break x = x <= break [@@inline always] let idx t = t [@@inline always] let make_break (idx : Automata.Idx.t) = -5 - Automata.Idx.to_int idx [@@inline always] let break_idx t = (t + 5) * -1 [@@inline always] end type match_info = | Match of Group.t | Failed | Running of { no_match_starts_before : int } type state_info = { idx : Idx.t ; (* Index of the current position in the position table. Not yet computed transitions point to a dummy state where [idx] is set to [unknown]; If [idx] is set to [break] for states that either always succeed or always fail. *) mutable final : (Category.t * (Automata.Idx.t * Automata.Status.t)) list ; (* Mapping from the category of the next character to - the index where the next position should be saved - possibly, the list of marks (and the corresponding indices) corresponding to the best match *) desc : Automata.State.t (* Description of this state of the automata *) } (* A state [t] is a pair composed of some information about the state [state_info] and a transition table [t array], indexed by color. For performance reason, to avoid an indirection, we manually unbox the transition table: we allocate a single array, with the state information at index 0, followed by the transitions. *) module State : sig type t val make : ncol:int -> state_info -> t val make_break : state_info -> t val get_info : t -> state_info val follow_transition : t -> color:Cset.c -> t val set_transition : t -> color:Cset.c -> t -> unit end = struct type t = Table of t array [@@unboxed] let get_info (Table st) : state_info = Obj.magic (Array.unsafe_get st 0) [@@inline always] ;; let set_info (Table st) (info : state_info) = st.(0) <- Obj.magic info let follow_transition (Table st) ~color = Array.unsafe_get st (1 + Cset.to_int color) [@@inline always] ;; let set_transition (Table st) ~color st' = st.(1 + Cset.to_int color) <- st' let dummy (info : state_info) = Table [| Obj.magic info |] let unknown_state = dummy { idx = Idx.unknown; final = []; desc = Automata.State.dummy } let make ~ncol state = let st = Table (Array.make (ncol + 1) unknown_state) in set_info st state; st ;; let make_break state = Table [| Obj.magic state |] end (* Automata (compiled regular expression) *) type re = { initial : Automata.expr ; (* The whole regular expression *) mutable initial_states : (Category.t * State.t) list ; (* Initial states, indexed by initial category *) colors : Color_map.Table.t ; (* Color table *) color_repr : Color_map.Repr.t ; (* Table from colors to one character of this color *) ncolor : int ; (* Number of colors. *) lnl : Cset.c ; (* Color of the last newline. [Cset.null_char] if unnecessary *) tbl : Automata.Working_area.t ; (* Temporary table used to compute the first available index when computing a new state *) states : State.t Automata.State.Table.t ; (* States of the deterministic automata *) group_names : (string * int) list ; (* Named groups in the regular expression *) group_count : int (* Number of groups in the regular expression *) } let pp_re ch re = Automata.pp ch re.initial let group_count re = re.group_count let group_names re = re.group_names module Positions = struct (* Information used during matching *) type t = { mutable positions : int array (* Array of mark positions The mark are off by one for performance reasons *) } let empty = { positions = [||] } let length t = Array.length t.positions let set t idx pos = Array.unsafe_set t.positions idx pos let resize t = let len = Array.length t.positions in let pos = t.positions in t.positions <- Array.make (2 * len) 0; Array.blit pos 0 t.positions 0 len ;; let all t = t.positions let first t = t.positions.(0) let make ~groups re = if groups then { positions = (let n = Automata.Working_area.index_count re.tbl + 1 in if n <= 10 then [| 0; 0; 0; 0; 0; 0; 0; 0; 0; 0 |] else Array.make n 0) } else empty ;; end (****) let category re ~color = if Cset.equal_c color Cset.null_char then Category.inexistant (* Special category for the last newline *) else if Cset.equal_c color re.lnl then Category.(lastnewline ++ newline ++ not_letter) else Category.from_char (Color_map.Repr.repr re.color_repr color) ;; (****) let find_state re desc = try Automata.State.Table.find re.states desc with | Not_found -> let st = let break_state = match Automata.State.status desc with | Running -> false | Failed | Match _ -> true in let st = { idx = (let idx = Automata.State.idx desc in if break_state then Idx.make_break idx else Idx.of_idx idx) ; final = [] ; desc } in if break_state then State.make_break st else State.make ~ncol:re.ncolor st in Automata.State.Table.add re.states desc st; st ;; (**** Match with marks ****) let delta re positions cat ~color st = let desc = Automata.delta re.tbl cat color st.desc in let len = Positions.length positions in if len > 0 && Automata.State.idx desc |> Automata.Idx.to_int = len then Positions.resize positions; desc ;; let validate re positions (s : string) ~pos st = let color = Color_map.Table.get re.colors s.[pos] in let st' = let desc' = let cat = category re ~color in delta re positions cat ~color (State.get_info st) in find_state re desc' in State.set_transition st ~color st' ;; let next colors st s pos = State.follow_transition st ~color:(Color_map.Table.get colors (String.unsafe_get s pos)) ;; let rec loop re ~colors ~positions s ~pos ~last st0 st = if pos < last then ( let st' = next colors st s pos in let idx = (State.get_info st').idx in if Idx.is_idx idx then ( Positions.set positions (Idx.idx idx) pos; loop re ~colors ~positions s ~pos:(pos + 1) ~last st' st') else if Idx.is_break idx then ( Positions.set positions (Idx.break_idx idx) pos; st') else ( (* Unknown *) validate re positions s ~pos st0; loop re ~colors ~positions s ~pos ~last st0 st0)) else st ;; let rec loop_no_mark re ~colors s ~pos ~last st0 st = if pos < last then ( let st' = next colors st s pos in let idx = (State.get_info st').idx in if Idx.is_idx idx then loop_no_mark re ~colors s ~pos:(pos + 1) ~last st' st' else if Idx.is_break idx then st' else ( (* Unknown *) validate re Positions.empty s ~pos st0; loop_no_mark re ~colors s ~pos ~last st0 st0)) else st ;; let final re positions st cat = try List.assq cat st.final with | Not_found -> let st' = delta re positions cat ~color:Cset.null_char st in let res = Automata.State.idx st', Automata.State.status st' in st.final <- (cat, res) :: st.final; res ;; let find_initial_state re cat = try List.assq cat re.initial_states with | Not_found -> let st = find_state re (Automata.State.create cat re.initial) in re.initial_states <- (cat, st) :: re.initial_states; st ;; let get_color re (s : string) pos = if pos < 0 then Cset.null_char else ( let slen = String.length s in if pos >= slen then Cset.null_char else if pos = slen - 1 && (not (Cset.equal_c re.lnl Cset.null_char)) && Char.equal (String.unsafe_get s pos) '\n' then (* Special case for the last newline *) re.lnl else Color_map.Table.get re.colors (String.unsafe_get s pos)) ;; let rec handle_last_newline re positions ~pos st ~groups = let st' = State.follow_transition st ~color:re.lnl in let info = State.get_info st' in if Idx.is_idx info.idx then ( if groups then Positions.set positions (Idx.idx info.idx) pos; st') else if Idx.is_break info.idx then ( if groups then Positions.set positions (Idx.break_idx info.idx) pos; st') else ( (* Unknown *) let color = re.lnl in let st' = let desc = let cat = category re ~color in let real_c = Color_map.Table.get re.colors '\n' in delta re positions cat ~color:real_c (State.get_info st) in find_state re desc in State.set_transition st ~color st'; handle_last_newline re positions ~pos st ~groups) ;; let rec scan_str re positions (s : string) initial_state ~last ~pos ~groups = if last = String.length s && (not (Cset.equal_c re.lnl Cset.null_char)) && last > pos && Char.equal (String.get s (last - 1)) '\n' then ( let last = last - 1 in let st = scan_str re positions ~pos s initial_state ~last ~groups in if Idx.is_break (State.get_info st).idx then st else handle_last_newline re positions ~pos:last st ~groups) else if groups then loop re ~colors:re.colors ~positions s ~pos ~last initial_state initial_state else loop_no_mark re ~colors:re.colors s ~pos ~last initial_state initial_state ;; (* This function adds a final boundary check on the input. This is useful to indicate that the output failed because of insufficient input, or to verify that the output actually matches for regex that have boundary conditions with respect to the input string. *) let final_boundary_check re positions ~last ~slen s state_info ~groups = let idx, res = let final_cat = Category.( search_boundary ++ if last = slen then inexistant else category re ~color:(get_color re s last)) in final re positions state_info final_cat in (match groups, res with | true, Match _ -> Positions.set positions (Automata.Idx.to_int idx) last | _ -> ()); res ;; let make_match_str re positions ~len ~groups ~partial s ~pos = let slen = String.length s in let last = if len = -1 then slen else pos + len in let st = let initial_state = let initial_cat = Category.( search_boundary ++ if pos = 0 then inexistant else category re ~color:(get_color re s (pos - 1))) in find_initial_state re initial_cat in scan_str re positions s initial_state ~pos ~last ~groups in let state_info = State.get_info st in if Idx.is_break state_info.idx || (partial && not groups) then Automata.State.status state_info.desc else if partial && groups then ( match Automata.State.status state_info.desc with | (Match _ | Failed) as status -> status | Running -> (* This could be because it's still not fully matched, or it could be that because we need to run special end of input checks. *) (match final_boundary_check re positions ~last ~slen s state_info ~groups with | Match _ as status -> status | Failed | Running -> (* A failure here just means that we need more data, i.e. it's a partial match. *) Running)) else final_boundary_check re positions ~last ~slen s state_info ~groups ;; let match_str_no_bounds ~groups ~partial re s ~pos ~len = let positions = Positions.make ~groups re in match make_match_str re positions ~len ~groups ~partial s ~pos with | Match (marks, pmarks) -> Match (Group.create s marks pmarks ~gpos:(Positions.all positions) ~gcount:re.group_count) | Failed -> Failed | Running -> let no_match_starts_before = if groups then Positions.first positions else 0 in Running { no_match_starts_before } ;; let match_str_p re s ~pos ~len = if pos < 0 || len < -1 || pos + len > String.length s then invalid_arg "Re.exec: out of bounds"; match make_match_str re Positions.empty ~len ~groups:false ~partial:false s ~pos with | Match _ -> true | _ -> false ;; let match_str ~groups ~partial re s ~pos ~len = if pos < 0 || len < -1 || pos + len > String.length s then invalid_arg "Re.exec: out of bounds"; match_str_no_bounds ~groups ~partial re s ~pos ~len ;; let mk_re ~initial ~colors ~color_repr ~ncolor ~lnl ~group_names ~group_count = { initial ; initial_states = [] ; colors ; color_repr ; ncolor ; lnl ; tbl = Automata.Working_area.create () ; states = Automata.State.Table.create 97 ; group_names ; group_count } ;; (**** Compilation ****) module A = Automata let enforce_kind ids kind kind' cr = match kind, kind' with | `First, `First -> cr | `First, k -> A.seq ids k cr (A.eps ids) | _ -> cr ;; type context = { ids : A.Ids.t ; kind : A.Sem.t ; ign_group : bool ; greedy : A.Rep_kind.t ; pos : A.Mark.t ref ; names : (string * int) list ref ; cache : Cset.t Cset.CSetMap.t ref ; colors : Color_map.Table.t } let trans_set cache (cm : Color_map.Table.t) s = match Cset.one_char s with | Some i -> Cset.csingle (Color_map.Table.get_char cm i) | None -> let v = Cset.hash s, s in (try Cset.CSetMap.find v !cache with | Not_found -> let l = Color_map.Table.translate_colors cm s in cache := Cset.CSetMap.add v l !cache; l) ;; let make_repeater ids cr kind greedy = match greedy with | `Greedy -> fun rem -> A.alt ids [ A.seq ids kind (A.rename ids cr) rem; A.eps ids ] | `Non_greedy -> fun rem -> A.alt ids [ A.eps ids; A.seq ids kind (A.rename ids cr) rem ] ;; (* XXX should probably compute a category mask *) let rec translate ({ ids; kind; ign_group; greedy; pos; names; cache; colors } as ctx) (ast : Ast.no_case) = match ast with | Set s -> A.cst ids (trans_set cache colors s), kind | Sequence l -> trans_seq ctx l, kind | Ast (Alternative l) -> (match Ast.merge_sequences l with | [ r' ] -> let cr, kind' = translate ctx r' in enforce_kind ids kind kind' cr, kind | merged_sequences -> ( A.alt ids (List.map merged_sequences ~f:(fun r' -> let cr, kind' = translate ctx r' in enforce_kind ids kind kind' cr)) , kind )) | Repeat (r', i, j) -> let cr, kind' = translate ctx r' in let rem = match j with | None -> A.rep ids greedy kind' cr | Some j -> let f = make_repeater ids cr kind' greedy in iter (j - i) f (A.eps ids) in iter i (fun rem -> A.seq ids kind' (A.rename ids cr) rem) rem, kind | Beg_of_line -> A.after ids Category.(inexistant ++ newline), kind | End_of_line -> A.before ids Category.(inexistant ++ newline), kind | Beg_of_word -> ( A.seq ids `First (A.after ids Category.(inexistant ++ not_letter)) (A.before ids Category.letter) , kind ) | End_of_word -> ( A.seq ids `First (A.after ids Category.letter) (A.before ids Category.(inexistant ++ not_letter)) , kind ) | Not_bound -> ( A.alt ids [ A.seq ids `First (A.after ids Category.letter) (A.before ids Category.letter) ; (let cat = Category.(inexistant ++ not_letter) in A.seq ids `First (A.after ids cat) (A.before ids cat)) ] , kind ) | Beg_of_str -> A.after ids Category.inexistant, kind | End_of_str -> A.before ids Category.inexistant, kind | Last_end_of_line -> A.before ids Category.(inexistant ++ lastnewline), kind | Start -> A.after ids Category.search_boundary, kind | Stop -> A.before ids Category.search_boundary, kind | Sem (kind', r') -> let cr, kind'' = translate { ctx with kind = kind' } r' in enforce_kind ids kind' kind'' cr, kind' | Sem_greedy (greedy', r') -> translate { ctx with greedy = greedy' } r' | Group (n, r') -> if ign_group then translate ctx r' else ( let p = !pos in let () = match n with | Some name -> names := (name, A.Mark.group_count p) :: !names | None -> () in pos := A.Mark.next2 !pos; let cr, kind' = translate ctx r' in ( A.seq ids `First (A.mark ids p) (A.seq ids `First cr (A.mark ids (A.Mark.next p))) , kind' )) | No_group r' -> translate { ctx with ign_group = true } r' | Nest r' -> let b = !pos in let cr, kind' = translate ctx r' in let e = A.Mark.prev !pos in if A.Mark.compare e b = -1 then cr, kind' else A.seq ids `First (A.erase ids b e) cr, kind' | Pmark (i, r') -> let cr, kind' = translate ctx r' in A.seq ids `First (A.pmark ids i) cr, kind' and trans_seq ({ ids; kind; _ } as ctx) = function | [] -> A.eps ids | [ r ] -> let cr', kind' = translate ctx r in enforce_kind ids kind kind' cr' | r :: rem -> let cr', kind' = translate ctx r in let cr'' = trans_seq ctx rem in if A.is_eps cr'' then cr' else if A.is_eps cr' then cr'' else A.seq ids kind' cr' cr'' ;; let compile_1 regexp = let regexp = Ast.handle_case false regexp in let color_map = Color_map.make () in let need_lnl = Ast.colorize color_map regexp in let colors, color_repr = Color_map.flatten color_map in let ncolor = Color_map.Repr.length color_repr in let lnl = if need_lnl then Cset.of_int ncolor else Cset.null_char in let ncolor = if need_lnl then ncolor + 1 else ncolor in let ctx = { ids = A.Ids.create () ; kind = `First ; ign_group = false ; greedy = `Greedy ; pos = ref A.Mark.start ; names = ref [] ; cache = ref Cset.CSetMap.empty ; colors } in let r, kind = translate ctx regexp in let r = enforce_kind ctx.ids `First kind r in (*Format.eprintf "<%d %d>@." !ids ncol;*) mk_re ~initial:r ~colors ~color_repr ~ncolor ~lnl ~group_names:(List.rev !(ctx.names)) ~group_count:(A.Mark.group_count !(ctx.pos)) ;; let compile r = let open Ast.Export in compile_1 (if Ast.anchored r then group r else seq [ shortest (rep any); group r ]) ;; ocaml-ocaml-re-5586c57/lib/compile.mli000066400000000000000000000010121467707551200175030ustar00rootroot00000000000000type re type match_info = | Match of Group.t | Failed | Running of { no_match_starts_before : int } val match_str_no_bounds : groups:bool -> partial:bool -> re -> string -> pos:int -> len:int -> match_info val match_str : groups:bool -> partial:bool -> re -> string -> pos:int -> len:int -> match_info val match_str_p : re -> string -> pos:int -> len:int -> bool val compile : Ast.t -> re val group_count : re -> int val group_names : re -> (string * int) list val pp_re : re Fmt.t ocaml-ocaml-re-5586c57/lib/core.ml000066400000000000000000000107011467707551200166370ustar00rootroot00000000000000(* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr 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, with linking exception; 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 *) open Import include struct let cset = Ast.cset let rg c c' = cset (Cset.cseq c c') let notnl = cset Cset.notnl let lower = cset Cset.lower let upper = cset Cset.upper let alpha = cset Cset.alpha let digit = cset Cset.cdigit let alnum = cset Cset.alnum let wordc = cset Cset.wordc let ascii = cset Cset.ascii let blank = cset Cset.blank let cntrl = cset Cset.cntrl let graph = cset Cset.graph let print = cset Cset.print let punct = cset Cset.punct let space = cset Cset.space let xdigit = cset Cset.xdigit end include Ast.Export let exec_internal ?(pos = 0) ?(len = -1) ~partial ~groups re s = Compile.match_str ~groups ~partial re s ~pos ~len ;; let exec ?pos ?len re s = match exec_internal ?pos ?len ~groups:true ~partial:false re s with | Match substr -> substr | _ -> raise Not_found ;; let exec_opt ?pos ?len re s = match exec_internal ?pos ?len ~groups:true ~partial:false re s with | Match substr -> Some substr | _ -> None ;; let execp ?(pos = 0) ?(len = -1) re s = Compile.match_str_p ~pos ~len re s let exec_partial ?pos ?len re s = match exec_internal ~groups:false ~partial:true ?pos ?len re s with | Match _ -> `Full | Running _ -> `Partial | Failed -> `Mismatch ;; let exec_partial_detailed ?pos ?len re s = match exec_internal ~groups:true ~partial:true ?pos ?len re s with | Match group -> `Full group | Running { no_match_starts_before } -> `Partial no_match_starts_before | Failed -> `Mismatch ;; module Mark = struct type t = Pmark.t let test (g : Group.t) p = Pmark.Set.mem p (Group.pmarks g) let all (g : Group.t) = Group.pmarks g module Set = Pmark.Set let equal = Pmark.equal let compare = Pmark.compare end type split_token = [ `Text of string | `Delim of Group.t ] module Gen = struct type 'a gen = unit -> 'a option let gen_of_seq (s : 'a Seq.t) : 'a gen = let r = ref s in fun () -> match !r () with | Seq.Nil -> None | Seq.Cons (x, tl) -> r := tl; Some x ;; let split ?pos ?len re s : _ gen = Search.split ?pos ?len re s |> gen_of_seq let split_full ?pos ?len re s : _ gen = Search.split_full ?pos ?len re s |> gen_of_seq let all ?pos ?len re s = Search.all ?pos ?len re s |> gen_of_seq let matches ?pos ?len re s = Search.matches ?pos ?len re s |> gen_of_seq end module Group = Group (** {2 Deprecated functions} *) let split_full_seq = Search.split_full let split_seq = Search.split let matches_seq = Search.matches let all_seq = Search.all type 'a gen = 'a Gen.gen let all_gen = Gen.all let matches_gen = Gen.matches let split_gen = Gen.split let split_full_gen = Gen.split_full type substrings = Group.t let get = Group.get let get_ofs = Group.offset let get_all = Group.all let get_all_ofs = Group.all_offset let test = Group.test type markid = Mark.t let marked = Mark.test let mark_set = Mark.all type groups = Group.t module List = struct let list_of_seq (s : 'a Seq.t) : 'a list = Seq.fold_left (fun l x -> x :: l) [] s |> List.rev ;; let all ?pos ?len re s = Search.all ?pos ?len re s |> list_of_seq let matches ?pos ?len re s = Search.matches ?pos ?len re s |> list_of_seq let split_full ?pos ?len re s = Search.split_full ?pos ?len re s |> list_of_seq let split ?pos ?len re s = Search.split ?pos ?len re s |> list_of_seq let split_delim ?pos ?len re s = Search.split_delim ?pos ?len re s |> list_of_seq end include List include struct open Compile type nonrec re = re let compile = compile let pp_re = pp_re let print_re = pp_re let group_names = group_names let group_count = group_count end module Seq = Search ocaml-ocaml-re-5586c57/lib/core.mli000066400000000000000000000565261467707551200170270ustar00rootroot00000000000000(* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr 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, with linking exception; 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 *) (** Module [Re]: code for creating and using regular expressions, independently of regular expression syntax. *) (** Regular expression *) type t = Ast.t (** Compiled regular expression *) type re = Compile.re (** Manipulate matching groups. *) module Group : sig (** Information about groups in a match. As is conventional, every match implicitly has a group 0 that covers the whole match, and explicit groups are numbered from 1. *) type t = Group.t (** Raise [Not_found] if the group did not match *) val get : t -> int -> string (** Similar to {!get}, but returns an option instead of using an exception. *) val get_opt : t -> int -> string option (** Raise [Not_found] if the group did not match *) val offset : t -> int -> int * int (** Similar to {!offset}, but returns an option instead of using an exception. *) val offset_opt : t -> int -> (int * int) option (** Return the start of the match. Raise [Not_found] if the group did not match. *) val start : t -> int -> int (** Similar to {!start_opt}, but returns an option instead of using an exception. *) val start_opt : t -> int -> int option (** Return the end of the match. Raise [Not_found] if the group did not match. *) val stop : t -> int -> int (** Similar to {!stop_opt}, but returns an option instead of using an exception. *) val stop_opt : t -> int -> int option (** Return the empty string for each group which did not match *) val all : t -> string array (** Return [(-1,-1)] for each group which did not match *) val all_offset : t -> (int * int) array (** Test whether a group matched *) val test : t -> int -> bool (** Returns the total number of groups defined - matched or not. This function is experimental. *) val nb_groups : t -> int val pp : Format.formatter -> t -> unit end type groups = Group.t [@@ocaml.deprecated "Use Group.t"] (** {2 Compilation and execution of a regular expression} *) (** Compile a regular expression into an executable version that can be used to match strings, e.g. with {!exec}. *) val compile : t -> re (** Return the number of capture groups (including the one corresponding to the entire regexp). *) val group_count : re -> int (** Return named capture groups with their index. *) val group_names : re -> (string * int) list (** [exec re str] searches [str] for a match of the compiled expression [re], and returns the matched groups if any. More specifically, when a match exists, [exec] returns a match that starts at the earliest position possible. If multiple such matches are possible, the one specified by the match semantics described below is returned. {5 Examples:} {[ # let regex = Re.compile Re.(seq [str "//"; rep print ]);; val regex : re = # Re.exec regex "// a C comment";; - : Re.Group.t = # Re.exec regex "# a C comment?";; Exception: Not_found # Re.exec ~pos:1 regex "// a C comment";; Exception: Not_found ]} @param pos optional beginning of the string (default 0) @param len length of the substring of [str] that can be matched (default [-1], meaning to the end of the string) @raise Not_found if the regular expression can't be found in [str] *) val exec : ?pos:int (** Default: 0 *) -> ?len:int (** Default: -1 (until end of string) *) -> re -> string -> Group.t (** Similar to {!exec}, but returns an option instead of using an exception. {5 Examples:} {[ # let regex = Re.compile Re.(seq [str "//"; rep print ]);; val regex : re = # Re.exec_opt regex "// a C comment";; - : Re.Group.t option = Some # Re.exec_opt regex "# a C comment?";; - : Re.Group.t option = None # Re.exec_opt ~pos:1 regex "// a C comment";; - : Re.Group.t option = None ]} *) val exec_opt : ?pos:int (** Default: 0 *) -> ?len:int (** Default: -1 (until end of string) *) -> re -> string -> Group.t option (** Similar to {!exec}, but returns [true] if the expression matches, and [false] if it doesn't. This function is more efficient than calling {!exec} or {!exec_opt} and ignoring the returned group. {5 Examples:} {[ # let regex = Re.compile Re.(seq [str "//"; rep print ]);; val regex : re = # Re.execp regex "// a C comment";; - : bool = true # Re.execp ~pos:1 regex "// a C comment";; - : bool = false ]} *) val execp : ?pos:int (** Default: 0 *) -> ?len:int (** Default: -1 (until end of string) *) -> re -> string -> bool (** More detailed version of {!execp}. [`Full] is equivalent to [true], while [`Mismatch] and [`Partial] are equivalent to [false], but [`Partial] indicates the input string could be extended to create a match. {5 Examples:} {[ # let regex = Re.compile Re.(seq [bos; str "// a C comment"]);; val regex : re = # Re.exec_partial regex "// a C comment here.";; - : [ `Full | `Mismatch | `Partial ] = `Full # Re.exec_partial regex "// a C comment";; - : [ `Full | `Mismatch | `Partial ] = `Partial # Re.exec_partial regex "//";; - : [ `Full | `Mismatch | `Partial ] = `Partial # Re.exec_partial regex "# a C comment?";; - : [ `Full | `Mismatch | `Partial ] = `Mismatch ]} *) val exec_partial : ?pos:int (** Default: 0 *) -> ?len:int (** Default: -1 (until end of string) *) -> re -> string -> [ `Full | `Partial | `Mismatch ] (** More detailed version of {!exec_opt}. [`Full group] is equivalent to [Some group], while [`Mismatch] and [`Partial _] are equivalent to [None], but [`Partial position] indicates that the input string could be extended to create a match, and no match could start in the input string before the given position. This could be used to not have to search the entirety of the input if more becomes available, and use the given position as the [?pos] argument. *) val exec_partial_detailed : ?pos:int (** Default: 0 *) -> ?len:int (** Default: -1 (until end of string) *) -> re -> string -> [ `Full of Group.t | `Partial of int | `Mismatch ] (** Marks *) module Mark : sig (** Mark id *) type t (** Tell if a mark was matched. *) val test : Group.t -> t -> bool module Set : Set.S with type elt = t (** Return all the mark matched. *) val all : Group.t -> Set.t val equal : t -> t -> bool val compare : t -> t -> int end (** {2 High Level Operations} *) type split_token = [ `Text of string (** Text between delimiters *) | `Delim of Group.t (** Delimiter *) ] (** Repeatedly calls {!exec} on the given string, starting at given position and length. {5 Examples:} {[ # let regex = Re.compile Re.(seq [str "my"; blank; word(rep alpha)]);; val regex : re = # Re.all regex "my head, my shoulders, my knees, my toes ...";; - : Re.Group.t list = [; ; ; ] # Re.all regex "My head, My shoulders, My knees, My toes ...";; - : Re.Group.t list = [] ]} *) val all : ?pos:int -> ?len:int -> re -> string -> Group.t list type 'a gen = unit -> 'a option (** @deprecated Use {!module-Seq.all} instead. *) val all_gen : ?pos:int -> ?len:int -> re -> string -> Group.t gen [@@ocaml.deprecated "Use Seq.all"] (** @deprecated Use {!module-Seq.all} instead. *) val all_seq : ?pos:int -> ?len:int -> re -> string -> Group.t Seq.t [@@ocaml.deprecated "Use Seq.all"] (** Same as {!all}, but extracts the matched substring rather than returning the whole group. This basically iterates over matched strings. {5 Examples:} {[ # let regex = Re.compile Re.(seq [str "my"; blank; word(rep alpha)]);; val regex : re = # Re.matches regex "my head, my shoulders, my knees, my toes ...";; - : string list = ["my head"; "my shoulders"; "my knees"; "my toes"] # Re.matches regex "My head, My shoulders, My knees, My toes ...";; - : string list = [] # Re.matches regex "my my my my head my 1 toe my ...";; - : string list = ["my my"; "my my"] # Re.matches ~pos:2 regex "my my my my head my +1 toe my ...";; - : string list = ["my my"; "my head"] ]} *) val matches : ?pos:int -> ?len:int -> re -> string -> string list (** @deprecated Use {!module-Seq.matches} instead. *) val matches_gen : ?pos:int -> ?len:int -> re -> string -> string gen [@@ocaml.deprecated "Use Seq.matches"] (** @deprecated Use {!module-Seq.matches} instead. *) val matches_seq : ?pos:int -> ?len:int -> re -> string -> string Seq.t [@@ocaml.deprecated "Use Seq.matches"] (** [split re s] splits [s] into chunks separated by [re]. It yields the chunks themselves, not the separator. An occurence of the separator at the beginning or the end of the string is ignoring. {5 Examples:} {[ # let regex = Re.compile (Re.char ',');; val regex : re = # Re.split regex "Re,Ocaml,Jerome Vouillon";; - : string list = ["Re"; "Ocaml"; "Jerome Vouillon"] # Re.split regex "No commas in this sentence.";; - : string list = ["No commas in this sentence."] # Re.split regex ",1,2,";; - : string list = ["1"; "2"] # Re.split ~pos:3 regex "1,2,3,4. Commas go brrr.";; - : string list = ["3"; "4. Commas go brrr."] ]} {6 Zero-length patterns:} Be careful when using [split] with zero-length patterns like [eol], [bow], and [eow]. Because they don't have any width, they will still be present in the result. (Note the position of the [\n] and space characters in the output.) {[ # Re.split (Re.compile Re.eol) "a\nb";; - : string list = ["a"; "\nb"] # Re.split (Re.compile Re.bow) "a b";; - : string list = ["a "; "b"] # Re.split (Re.compile Re.eow) "a b";; - : string list = ["a"; " b"] ]} Compare this to the behavior of splitting on the char itself. (Note that the delimiters are not present in the output.) {[ # Re.split (Re.compile (Re.char '\n')) "a\nb";; - : string list = ["a"; "b"] # Re.split (Re.compile (Re.char ' ')) "a b";; - : string list = ["a"; "b"] ]} *) val split : ?pos:int -> ?len:int -> re -> string -> string list (** [split_delim re s] splits [s] into chunks separated by [re]. It yields the chunks themselves, not the separator. Occurences of the separator at the beginning or the end of the string will produce empty chunks. {5 Examples:} {[ # let regex = Re.compile (Re.char ',');; val regex : re = # Re.split regex "Re,Ocaml,Jerome Vouillon";; - : string list = ["Re"; "Ocaml"; "Jerome Vouillon"] # Re.split regex "No commas in this sentence.";; - : string list = ["No commas in this sentence."] # Re.split regex ",1,2,";; - : string list = [""; "1"; "2"; ""] # Re.split ~pos:3 regex "1,2,3,4. Commas go brrr.";; - : string list = ["3"; "4. Commas go brrr."] ]} {6 Zero-length patterns:} Be careful when using [split_delim] with zero-length patterns like [eol], [bow], and [eow]. Because they don't have any width, they will still be present in the result. (Note the position of the [\n] and space characters in the output.) {[ # Re.split_delim (Re.compile Re.eol) "a\nb";; - : string list = ["a"; "\nb"; ""] # Re.split_delim (Re.compile Re.bow) "a b";; - : string list = [""; "a "; "b"] # Re.split_delim (Re.compile Re.eow) "a b";; - : string list = ["a"; " b"; ""] ]} Compare this to the behavior of splitting on the char itself. (Note that the delimiters are not present in the output.) {[ # Re.split_delim (Re.compile (Re.char '\n')) "a\nb";; - : string list = ["a"; "b"] # Re.split_delim (Re.compile (Re.char ' ')) "a b";; - : string list = ["a"; "b"] ]} *) val split_delim : ?pos:int -> ?len:int -> re -> string -> string list (** @deprecated Use {!module-Seq.split} instead. *) val split_gen : ?pos:int -> ?len:int -> re -> string -> string gen [@@ocaml.deprecated "Use Seq.split"] (** @deprecated Use {!module-Seq.split} instead. *) val split_seq : ?pos:int -> ?len:int -> re -> string -> string Seq.t [@@ocaml.deprecated "Use Seq.split"] (** [split re s] splits [s] into chunks separated by [re]. It yields the chunks along with the separators. For instance this can be used with a whitespace-matching re such as ["[\t ]+"]. {5 Examples:} {[ # let regex = Re.compile (Re.char ',');; val regex : re = # Re.split_full regex "Re,Ocaml,Jerome Vouillon";; - : Re.split_token list = [`Text "Re"; `Delim ; `Text "Ocaml"; `Delim ; `Text "Jerome Vouillon"] # Re.split_full regex "No commas in this sentence.";; - : Re.split_token list = [`Text "No commas in this sentence."] # Re.split_full ~pos:3 regex "1,2,3,4. Commas go brrr.";; - : Re.split_token list = [`Delim ; `Text "3"; `Delim ; `Text "4. Commas go brrr."] ]} *) val split_full : ?pos:int -> ?len:int -> re -> string -> split_token list (** @deprecated Use {!module-Seq.split_full} instead. *) val split_full_gen : ?pos:int -> ?len:int -> re -> string -> split_token gen [@@ocaml.deprecated "Use Seq.split_full"] (** @deprecated Use {!module-Seq.split_full} instead. *) val split_full_seq : ?pos:int -> ?len:int -> re -> string -> split_token Seq.t [@@ocaml.deprecated "Use Seq.split_full"] module Seq : sig (** Same as {!module-Re.val-all} but returns an iterator. {5 Examples:} {[ # let regex = Re.compile Re.(seq [str "my"; blank; word(rep alpha)]);; val regex : re = # Re.Seq.all regex "my head, my shoulders, my knees, my toes ...";; - : Re.Group.t Seq.t = ]} @since 1.10.0 *) val all : ?pos:int (** Default: 0 *) -> ?len:int -> re -> string -> Group.t Seq.t (** Same as {!module-Re.val-matches}, but returns an iterator. {5 Example:} {[ # let regex = Re.compile Re.(seq [str "my"; blank; word(rep alpha)]);; val regex : re = # Re.Seq.matches regex "my head, my shoulders, my knees, my toes ...";; - : string Seq.t = ]} @since 1.10.0 *) val matches : ?pos:int (** Default: 0 *) -> ?len:int -> re -> string -> string Seq.t (** Same as {!module-Re.val-split} but returns an iterator. {5 Example:} {[ # let regex = Re.compile (Re.char ',');; val regex : re = # Re.Seq.split regex "Re,Ocaml,Jerome Vouillon";; - : string Seq.t = ]} @since 1.10.0 *) val split : ?pos:int (** Default: 0 *) -> ?len:int -> re -> string -> string Seq.t (** Same as {!module-Re.val-split_delim} but returns an iterator. {5 Example:} {[ # let regex = Re.compile (Re.char ',');; val regex : re = # Re.Seq.split regex "Re,Ocaml,Jerome Vouillon";; - : string Seq.t = ]} @since 1.11.1 *) val split_delim : ?pos:int (** Default: 0 *) -> ?len:int -> re -> string -> string Seq.t (** Same as {!module-Re.val-split_full} but returns an iterator. {5 Example:} {[ # let regex = Re.compile (Re.char ',');; val regex : re = # Re.Seq.split_full regex "Re,Ocaml,Jerome Vouillon";; - : Re.split_token Seq.t = ]} @since 1.10.0 *) val split_full : ?pos:int (** Default: 0 *) -> ?len:int -> re -> string -> split_token Seq.t end (** {2 String expressions (literal match)} *) val str : string -> t val char : char -> t (** {2 Basic operations on regular expressions} *) (** Alternative. [alt []] is equivalent to {!empty}. By default, the leftmost match is preferred (see match semantics below). *) val alt : t list -> t (** Sequence *) val seq : t list -> t (** Match nothing *) val empty : t (** Empty word *) val epsilon : t (** 0 or more matches *) val rep : t -> t (** 1 or more matches *) val rep1 : t -> t (** [repn re i j] matches [re] at least [i] times and at most [j] times, bounds included. [j = None] means no upper bound. *) val repn : t -> int -> int option -> t (** 0 or 1 matches *) val opt : t -> t (** {2 String, line, word} We define a word as a sequence of latin1 letters, digits and underscore. *) (** Beginning of line *) val bol : t (** End of line *) val eol : t (** Beginning of word *) val bow : t (** End of word *) val eow : t (** Beginning of string. This differs from {!start} because it matches the beginning of the input string even when using [~pos] arguments: {[ let b = execp (compile (seq [ bos; str "a" ])) "aa" ~pos:1 in assert (not b) ]} *) val bos : t (** End of string. This is different from {!stop} in the way described in {!bos}. *) val eos : t (** Last end of line or end of string *) val leol : t (** Initial position. This differs from {!bos} because it takes into account the [~pos] arguments: {[ let b = execp (compile (seq [ start; str "a" ])) "aa" ~pos:1 in assert b ]} *) val start : t (** Final position. This is different from {!eos} in the way described in {!start}. *) val stop : t (** Word *) val word : t -> t (** Not at a word boundary *) val not_boundary : t (** Only matches the whole string, i.e. [fun t -> seq [ bos; t; eos ]]. *) val whole_string : t -> t (** {2 Match semantics} A regular expression frequently matches a string in multiple ways. For instance [exec (compile (opt (str "a"))) "ab"] can match "" or "a". Match semantic can be modified with the functions below, allowing one to choose which of these is preferable. By default, the leftmost branch of alternations is preferred, and repetitions are greedy. Note that the existence of matches cannot be changed by specifying match semantics. [seq [ bos; str "a"; non_greedy (opt (str "b")); eos ]] will match when applied to "ab". However if [seq [ bos; str "a"; non_greedy (opt (str "b")) ]] is applied to "ab", it will match "a" rather than "ab". Also note that multiple match semantics can conflict. In this case, the one executed earlier takes precedence. For instance, any match of [shortest (seq [ bos; group (rep (str "a")); group (rep (str "a")); eos ])] will always have an empty first group. Conversely, if we use [longest] instead of [shortest], the second group will always be empty. *) (** Longest match semantics. That is, matches will match as many bytes as possible. If multiple choices match the maximum amount of bytes, the one respecting the inner match semantics is preferred. *) val longest : t -> t (** Same as {!longest}, but matching the least number of bytes. *) val shortest : t -> t (** First match semantics for alternations (not repetitions). That is, matches will prefer the leftmost branch of the alternation that matches the text. *) val first : t -> t (** Greedy matches for repetitions ({!opt}, {!rep}, {!rep1}, {!repn}): they will match as many times as possible. *) val greedy : t -> t (** Non-greedy matches for repetitions ({!opt}, {!rep}, {!rep1}, {!repn}): they will match as few times as possible. *) val non_greedy : t -> t (** {2 Groups (or submatches)} *) (** Delimit a group. The group is considered as matching if it is used at least once (it may be used multiple times if is nested inside {!rep} for instance). If it is used multiple times, the last match is what gets captured. *) val group : ?name:string -> t -> t (** Remove all groups *) val no_group : t -> t (** When matching against [nest e], only the group matching in the last match of e will be considered as matching. For instance: {[ let re = compile (rep1 (nest (alt [ group (str "a"); str "b" ]))) in let group = Re.exec re "ab" in assert (Group.get_opt group 1 = None); (* same thing but without [nest] *) let re = compile (rep1 (alt [ group (str "a"); str "b" ])) in let group = Re.exec re "ab" in assert (Group.get_opt group 1 = Some "a") ]} *) val nest : t -> t (** Mark a regexp. the markid can then be used to know if this regexp was used. *) val mark : t -> Mark.t * t (** {2 Character sets} *) (** Any character of the string *) val set : string -> t (** Character ranges *) val rg : char -> char -> t (** Intersection of character sets *) val inter : t list -> t (** Difference of character sets *) val diff : t -> t -> t (** Complement of union *) val compl : t list -> t (** {2 Predefined character sets} *) (** Any character *) val any : t (** Any character but a newline *) val notnl : t val alnum : t val wordc : t val alpha : t val ascii : t val blank : t val cntrl : t val digit : t val graph : t val lower : t val print : t val punct : t val space : t val upper : t val xdigit : t (** {2 Case modifiers} *) (** Case sensitive matching. Note that this works on latin1, not ascii and not utf8. *) val case : t -> t (** Case insensitive matching. Note that this works on latin1, not ascii and not utf8. *) val no_case : t -> t (****) (** {2 Internal debugging} *) val pp : Format.formatter -> t -> unit val pp_re : Format.formatter -> re -> unit (** Alias for {!pp_re}. Deprecated *) val print_re : Format.formatter -> re -> unit (** {2 Experimental functions} *) (** [witness r] generates a string [s] such that [execp (compile r) s] is true. Be warned that this function is buggy because it ignores zero-width assertions like beginning of words. As a result it can generate incorrect results. *) val witness : t -> string (** {2 Deprecated functions} *) (** Alias for {!Group.t}. Deprecated *) type substrings = Group.t [@@ocaml.deprecated "Use Group.t"] (** Same as {!Group.get}. Deprecated *) val get : Group.t -> int -> string [@@ocaml.deprecated "Use Group.get"] (** Same as {!Group.offset}. Deprecated *) val get_ofs : Group.t -> int -> int * int [@@ocaml.deprecated "Use Group.offset"] (** Same as {!Group.all}. Deprecated *) val get_all : Group.t -> string array [@@ocaml.deprecated "Use Group.all"] (** Same as {!Group.all_offset}. Deprecated *) val get_all_ofs : Group.t -> (int * int) array [@@ocaml.deprecated "Use Group.all_offset"] (** Same as {!Group.test}. Deprecated *) val test : Group.t -> int -> bool [@@ocaml.deprecated "Use Group.test"] (** Alias for {!Mark.t}. Deprecated *) type markid = Mark.t [@@ocaml.deprecated "Use Mark."] (** Same as {!Mark.test}. Deprecated *) val marked : Group.t -> Mark.t -> bool [@@ocaml.deprecated "Use Mark.test"] (** Same as {!Mark.all}. Deprecated *) val mark_set : Group.t -> Mark.Set.t [@@ocaml.deprecated "Use Mark.all"] ocaml-ocaml-re-5586c57/lib/cset.ml000066400000000000000000000135001467707551200166450ustar00rootroot00000000000000module List = struct end open Import (* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr 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, with linking exception; 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 *) type c = int let equal_c = Int.equal let to_int x = x let of_int x = x let to_char t = Char.chr t let of_char c = Char.code c let null_char = -1 type t = (c * c) list let compare_pair (x, y) (x', y') = match Int.compare x x' with | 0 -> Int.compare y y' | x -> x ;; let equal_pair (x, y) (x', y') = Int.equal x x' && Int.equal y y' let equal = List.equal ~eq:equal_pair let compare : t -> t -> int = List.compare ~cmp:compare_pair let rec union l l' = match l, l' with | _, [] -> l | [], _ -> l' | (c1, c2) :: r, (c1', c2') :: r' -> if c2 + 1 < c1' then (c1, c2) :: union r l' else if c2' + 1 < c1 then (c1', c2') :: union l r' else if c2 < c2' then union r ((min c1 c1', c2') :: r') else union ((min c1 c1', c2) :: r) r' ;; let rec inter l l' = match l, l' with | _, [] -> [] | [], _ -> [] | (c1, c2) :: r, (c1', c2') :: r' -> if c2 < c1' then inter r l' else if c2' < c1 then inter l r' else if c2 < c2' then (max c1 c1', c2) :: inter r l' else (max c1 c1', c2') :: inter l r' ;; let rec diff l l' = match l, l' with | _, [] -> l | [], _ -> [] | (c1, c2) :: r, (c1', c2') :: r' -> if c2 < c1' then (c1, c2) :: diff r l' else if c2' < c1 then diff l r' else ( let r'' = if c2' < c2 then (c2' + 1, c2) :: r else r in if c1 < c1' then (c1, c1' - 1) :: diff r'' r' else diff r'' r') ;; let single c = [ c, c ] let add c l = union (single c) l let seq c c' = if c <= c' then [ c, c' ] else [ c', c ] let rec offset o l = match l with | [] -> [] | (c1, c2) :: r -> (c1 + o, c2 + o) :: offset o r ;; let empty = [] let cany = [ 0, 255 ] let union_all : t list -> t = List.fold_left ~init:empty ~f:union let intersect_all : t list -> t = List.fold_left ~init:cany ~f:inter let rec mem (c : int) s = match s with | [] -> false | (c1, c2) :: rem -> if c <= c2 then c >= c1 else mem c rem ;; (****) let rec hash_rec = function | [] -> 0 | (i, j) :: r -> i + (13 * j) + (257 * hash_rec r) ;; let hash l = hash_rec l land 0x3FFFFFFF (****) let print_one ch (c1, c2) = if Int.equal c1 c2 then Format.fprintf ch "%d" c1 else Format.fprintf ch "%d-%d" c1 c2 ;; let pp = Fmt.list ~pp_sep:(Fmt.lit ", ") print_one let rec iter t ~f = match t with | [] -> () | (x, y) :: xs -> f x y; iter xs ~f ;; let one_char = function | [ (i, j) ] when Int.equal i j -> Some i | _ -> None ;; module CSetMap = Map.Make (struct type t = int * (int * int) list let compare (i, u) (j, v) = let c = Int.compare i j in if c <> 0 then c else compare u v ;; end) let fold_right t ~init ~f = List.fold_right ~f:(fun (x, y) acc -> f x y acc) t ~init let csingle c = single (Char.code c) let is_empty = function | [] -> true | _ -> false ;; let rec prepend s x l = match s, l with | [], _ -> l | _r, [] -> [] | (_c, c') :: r, ([ (d, _d') ], _x') :: _r' when c' < d -> prepend r x l | (c, c') :: r, ([ (d, d') ], x') :: r' -> if c <= d then if c' < d' then ([ d, c' ], x @ x') :: prepend r x (([ c' + 1, d' ], x') :: r') else ([ d, d' ], x @ x') :: prepend s x r' else if c > d' then ([ d, d' ], x') :: prepend s x r' else ([ d, c - 1 ], x') :: prepend s x (([ c, d' ], x') :: r') | _ -> assert false ;; let pick = function | [] -> invalid_arg "Re_cset.pick" | (x, _) :: _ -> x ;; let cseq c c' = seq (of_char c) (of_char c') let rg = cseq let char = csingle let upper = union_all [ cseq 'A' 'Z'; cseq '\192' '\214'; cseq '\216' '\222' ] let clower = offset 32 upper let cdigit = cseq '0' '9' let ascii = cseq '\000' '\127' let cadd c s = add (of_char c) s let space = add (of_char ' ') (cseq '\009' '\013') let xdigit = union_all [ cdigit; cseq 'a' 'f'; cseq 'A' 'F' ] let calpha = List.fold_right ~f:cadd [ '\170'; '\181'; '\186'; '\223'; '\255' ] ~init:(union clower upper) ;; let calnum = union calpha cdigit let case_insens s = union_all [ s; offset 32 (inter s upper); offset (-32) (inter s clower) ] ;; let cword = cadd '_' calnum let notnl = diff cany (csingle '\n') let nl = csingle '\n' let set str = let s = ref empty in for i = 0 to String.length str - 1 do s := union (csingle str.[i]) !s done; !s ;; let blank = set "\t " (* CR-someday rgrinberg: this [lower] doesn't match [clower] *) let lower = union_all [ rg 'a' 'z'; char '\181'; rg '\223' '\246'; rg '\248' '\255' ] let alpha = union_all [ lower; upper; char '\170'; char '\186' ] let alnum = union_all [ alpha; cdigit ] let wordc = union_all [ alnum; char '_' ] let cntrl = union_all [ rg '\000' '\031'; rg '\127' '\159' ] let graph = union_all [ rg '\033' '\126'; rg '\160' '\255' ] let print = union_all [ rg '\032' '\126'; rg '\160' '\255' ] let punct = union_all [ rg '\033' '\047' ; rg '\058' '\064' ; rg '\091' '\096' ; rg '\123' '\126' ; rg '\160' '\169' ; rg '\171' '\180' ; rg '\182' '\185' ; rg '\187' '\191' ; char '\215' ; char '\247' ] ;; ocaml-ocaml-re-5586c57/lib/cset.mli000066400000000000000000000042301467707551200170160ustar00rootroot00000000000000(* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr 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, with linking exception; 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 *) (* Character sets, represented as sorted list of intervals *) type c [@@immediate] val equal_c : c -> c -> bool val to_int : c -> int val of_int : int -> c val to_char : c -> char val of_char : char -> c type t (** special characters which isn't present in any set (not even in [cany]) *) val null_char : c val equal : t -> t -> bool val iter : t -> f:(c -> c -> unit) -> unit val union : t -> t -> t val union_all : t list -> t val intersect_all : t list -> t val inter : t -> t -> t val diff : t -> t -> t val empty : t val single : c -> t val add : c -> t -> t val mem : c -> t -> bool val case_insens : t -> t val cdigit : t val calpha : t val cword : t val notnl : t val ascii : t val nl : t val cseq : char -> char -> t val set : string -> t val blank : t val space : t val xdigit : t val lower : t val upper : t val alpha : t val alnum : t val wordc : t val cntrl : t val graph : t val print : t val punct : t val pp : t Fmt.t val one_char : t -> c option val fold_right : t -> init:'acc -> f:(c -> c -> 'acc -> 'acc) -> 'acc val hash : t -> int val compare : t -> t -> int module CSetMap : Map.S with type key = int * t val cany : t val csingle : char -> t val is_empty : t -> bool val prepend : t -> 'a list -> (t * 'a list) list -> (t * 'a list) list val pick : t -> c val offset : int -> t -> t ocaml-ocaml-re-5586c57/lib/dune000066400000000000000000000001541467707551200162340ustar00rootroot00000000000000(library (name re) (synopsis "Pure OCaml regular expression library") (libraries seq) (public_name re)) ocaml-ocaml-re-5586c57/lib/emacs.ml000066400000000000000000000067561467707551200170160ustar00rootroot00000000000000(* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr 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, with linking exception; 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 *) module Re = Core exception Parse_error exception Not_supported let parse s = let buf = Parse_buffer.create s in let accept = Parse_buffer.accept buf in let accept2 = Parse_buffer.accept2 buf in let eos () = Parse_buffer.eos buf in let test2 = Parse_buffer.test2 buf in let get () = Parse_buffer.get buf in let rec regexp () = regexp' (branch ()) and regexp' left = if accept2 '\\' '|' then regexp' (Re.alt [ left; branch () ]) else left and branch () = branch' [] and branch' left = if eos () || test2 '\\' '|' || test2 '\\' ')' then Re.seq (List.rev left) else branch' (piece () :: left) and piece () = let r = atom () in if accept '*' then Re.rep r else if accept '+' then Re.rep1 r else if accept '?' then Re.opt r else r and atom () = if accept '.' then Re.notnl else if accept '^' then Re.bol else if accept '$' then Re.eol else if accept '[' then if accept '^' then Re.compl (bracket []) else Re.alt (bracket []) else if accept '\\' then if accept '(' then ( let r = regexp () in if not (accept2 '\\' ')') then raise Parse_error; Re.group r) else if accept '`' then Re.bos else if accept '\'' then Re.eos else if accept '=' then Re.start else if accept 'b' then Re.alt [ Re.bow; Re.eow ] else if accept 'B' then Re.not_boundary else if accept '<' then Re.bow else if accept '>' then Re.eow else if accept 'w' then Re.alt [ Re.alnum; Re.char '_' ] else if accept 'W' then Re.compl [ Re.alnum; Re.char '_' ] else ( if eos () then raise Parse_error; match get () with | ('*' | '+' | '?' | '[' | ']' | '.' | '^' | '$' | '\\') as c -> Re.char c | '0' .. '9' -> raise Not_supported | _ -> raise Parse_error) else ( if eos () then raise Parse_error; match get () with | '*' | '+' | '?' -> raise Parse_error | c -> Re.char c) and bracket s = if s <> [] && accept ']' then s else ( let c = char () in if accept '-' then if accept ']' then Re.char c :: Re.char '-' :: s else ( let c' = char () in bracket (Re.rg c c' :: s)) else bracket (Re.char c :: s)) and char () = if eos () then raise Parse_error; get () in let res = regexp () in if not (eos ()) then raise Parse_error; res ;; let re ?(case = true) s = let r = parse s in if case then r else Re.no_case r ;; let compile = Re.compile let compile_pat ?(case = true) s = compile (re ~case s) ocaml-ocaml-re-5586c57/lib/emacs.mli000066400000000000000000000024211467707551200171500ustar00rootroot00000000000000(* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr 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, with linking exception; 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 *) (** Emacs-style regular expressions *) exception Parse_error (** Errors that can be raised during the parsing of the regular expression *) exception Not_supported (** Parsing of an Emacs-style regular expression *) val re : ?case:bool -> string -> Core.t (** Regular expression compilation *) val compile : Core.t -> Core.re (** Same as [Core.compile] *) val compile_pat : ?case:bool -> string -> Core.re ocaml-ocaml-re-5586c57/lib/fmt.ml000066400000000000000000000024551467707551200165040ustar00rootroot00000000000000(** Very small tooling for format printers. *) include Format type 'a t = Format.formatter -> 'a -> unit let list = pp_print_list let array ?pp_sep f fmt arr = list ?pp_sep f fmt (Array.to_list arr) let str = pp_print_string let sexp fmt s pp x = fprintf fmt "@[<3>(%s@ %a)@]" s pp x let bytes fmt t = Format.fprintf fmt "%S" (Bytes.to_string t) let pair pp1 pp2 fmt (v1, v2) = pp1 fmt v1; pp_print_space fmt (); pp2 fmt v2 ;; let triple pp1 pp2 pp3 fmt (v1, v2, v3) = pp1 fmt v1; pp_print_space fmt (); pp2 fmt v2; pp_print_space fmt (); pp3 fmt v3 ;; let opt f fmt x = match x with | None -> pp_print_string fmt "" | Some x -> fprintf fmt "%a" f x ;; let int = pp_print_int let optint fmt = function | None -> () | Some i -> fprintf fmt "@ %d" i ;; let quote fmt s = Format.fprintf fmt "\"%s\"" s let pp_olist pp_elem fmt = Format.fprintf fmt "@[<3>[@ %a@ ]@]" (pp_print_list ~pp_sep:(fun fmt () -> fprintf fmt ";@ ") pp_elem) ;; let char fmt c = Format.fprintf fmt "%c" c let bool = Format.pp_print_bool let pp_str_list = pp_olist quote let lit s fmt () = pp_print_string fmt s let to_to_string pp x = let b = Buffer.create 16 in let fmt = Format.formatter_of_buffer b in pp fmt x; Buffer.contents b ;; let quoted_string fmt s = Format.fprintf fmt "%S" s ocaml-ocaml-re-5586c57/lib/fmt.mli000066400000000000000000000011171467707551200166470ustar00rootroot00000000000000type formatter := Format.formatter type 'a t = formatter -> 'a -> unit val pp_str_list : string list t val sexp : formatter -> string -> 'a t -> 'a -> unit val str : string t val optint : int option t val opt : 'a t -> 'a option t val char : char t val bool : bool t val int : int t val pair : 'a t -> 'b t -> ('a * 'b) t val triple : 'a t -> 'b t -> 'c t -> ('a * 'b * 'c) t val list : ?pp_sep:unit t -> 'a t -> 'a list t val bytes : Bytes.t t val array : ?pp_sep:unit t -> 'a t -> 'a array t val lit : string -> unit t val to_to_string : 'a t -> 'a -> string val quoted_string : string t ocaml-ocaml-re-5586c57/lib/glob.ml000066400000000000000000000234061467707551200166400ustar00rootroot00000000000000(* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr 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, with linking exception; 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 *) module Re = Core exception Parse_error type enclosed = | Char of char | Range of char * char type piece = | Exactly of char | Any_of of enclosed list | Any_but of enclosed list | One | Many | ManyMany type t = piece list let of_string ~double_asterisk s : t = let buf = Parse_buffer.create s in let eos () = Parse_buffer.eos buf in let read c = Parse_buffer.accept buf c in let char () = ignore (read '\\' : bool); if eos () then raise Parse_error; Parse_buffer.get buf in let enclosed () : enclosed list = let rec loop s = (* This returns the list in reverse order, but order isn't important anyway *) if s <> [] && read ']' then s else ( let c = char () in if not (read '-') then loop (Char c :: s) else if read ']' then Char c :: Char '-' :: s else ( let c' = char () in loop (Range (c, c') :: s))) in loop [] in let piece acc = if double_asterisk && Parse_buffer.accept_s buf "/**" then ManyMany :: (if eos () then Exactly '/' :: acc else acc) else if read '*' then (if double_asterisk && read '*' then ManyMany else Many) :: acc else if read '?' then One :: acc else if not (read '[') then Exactly (char ()) :: acc else if read '^' || read '!' then Any_but (enclosed ()) :: acc else Any_of (enclosed ()) :: acc in let rec loop pieces = if eos () then List.rev pieces else loop (piece pieces) in loop [] ;; let mul l l' = List.flatten (List.map (fun s -> List.map (fun s' -> s ^ s') l') l) let explode str = let l = String.length str in let rec expl inner s i acc beg = if i >= l then ( if inner then raise Parse_error; mul beg [ String.sub str s (i - s) ], i) else ( match str.[i] with | '\\' -> expl inner s (i + 2) acc beg | '{' -> let t, i' = expl true (i + 1) (i + 1) [] [ "" ] in expl inner i' i' acc (mul beg (mul [ String.sub str s (i - s) ] t)) | ',' when inner -> expl inner (i + 1) (i + 1) (mul beg [ String.sub str s (i - s) ] @ acc) [ "" ] | '}' when inner -> mul beg [ String.sub str s (i - s) ] @ acc, i + 1 | _ -> expl inner s (i + 1) acc beg) in List.rev (fst (expl false 0 0 [] [ "" ])) ;; module State = struct type t = { re_pieces : Re.t list (* last piece at head of list. *) ; remaining : piece list (* last piece at tail of list. *) ; am_at_start_of_pattern : bool (* true at start of pattern *) ; am_at_start_of_component : bool (* true at start of pattern or immediately after '/' *) ; pathname : bool ; match_backslashes : bool ; period : bool } let create ~period ~pathname ~match_backslashes remaining = { re_pieces = [] ; am_at_start_of_pattern = true ; am_at_start_of_component = true ; pathname ; match_backslashes ; period ; remaining } ;; let explicit_period t = t.period && (t.am_at_start_of_pattern || (t.am_at_start_of_component && t.pathname)) ;; let explicit_slash t = t.pathname let slashes t = if t.match_backslashes then [ '/'; '\\' ] else [ '/' ] let append ?(am_at_start_of_component = false) t piece = { t with re_pieces = piece :: t.re_pieces ; am_at_start_of_pattern = false ; am_at_start_of_component } ;; let to_re t = Re.seq (List.rev t.re_pieces) let next t = match t.remaining with | [] -> None | piece :: remaining -> Some (piece, { t with remaining }) ;; end let one ~explicit_slash ~slashes ~explicit_period = Re.compl (List.concat [ (if explicit_slash then List.map Re.char slashes else []) ; (if explicit_period then [ Re.char '.' ] else []) ]) ;; let enclosed enclosed = match enclosed with | Char c -> Re.char c | Range (low, high) -> Re.rg low high ;; let enclosed_set ~explicit_slash ~slashes ~explicit_period kind set = let set = List.map enclosed set in let enclosure = match kind with | `Any_of -> Re.alt set | `Any_but -> Re.compl set in Re.inter [ enclosure; one ~explicit_slash ~slashes ~explicit_period ] ;; let exactly state c = let slashes = State.slashes state in let am_at_start_of_component = List.mem c slashes in let chars = if am_at_start_of_component then slashes else [ c ] in State.append state (Re.alt (List.map Re.char chars)) ~am_at_start_of_component ;; let many_many state = let explicit_period = state.State.period && state.State.pathname in let first_explicit_period = State.explicit_period state in let slashes = State.slashes state in let match_component ~explicit_period = Re.seq [ one ~explicit_slash:true ~slashes ~explicit_period ; Re.rep (one ~explicit_slash:true ~slashes ~explicit_period:false) ] in (* We must match components individually when [period] flag is set, making sure to not match ["foo/.bar"]. *) State.append state (Re.seq [ Re.opt (match_component ~explicit_period:first_explicit_period) ; Re.rep (Re.seq [ Re.alt (List.map Re.char slashes) ; Re.opt (match_component ~explicit_period) ]) ]) ;; let many (state : State.t) = let explicit_slash = State.explicit_slash state in let explicit_period = State.explicit_period state in let slashes = State.slashes state in (* Whether we must explicitly match period depends on the surrounding characters, but slashes are easy to explicit match. This conditional splits out some simple cases. *) if not explicit_period then State.append state (Re.rep (one ~explicit_slash ~slashes ~explicit_period)) else if not explicit_slash then (* In this state, we explicitly match periods only at the very beginning *) State.append state (Re.opt (Re.seq [ one ~explicit_slash:false ~slashes ~explicit_period ; Re.rep (one ~explicit_slash:false ~slashes ~explicit_period:false) ])) else ( let not_empty = Re.seq [ one ~explicit_slash:true ~slashes ~explicit_period:true ; Re.rep (one ~explicit_slash:true ~slashes ~explicit_period:false) ] in (* [maybe_empty] is the default translation of Many, except in some special cases. *) let maybe_empty = Re.opt not_empty in let enclosed_set state kind set = State.append state (Re.alt [ enclosed_set kind set ~explicit_slash:true ~slashes ~explicit_period:true ; Re.seq [ not_empty ; (* Since [not_empty] matched, subsequent dots are not leading. *) enclosed_set kind set ~explicit_slash:true ~slashes ~explicit_period:false ] ]) in let rec lookahead state = match State.next state with | None -> State.append state maybe_empty (* glob ** === glob * . *) | Some (Many, state) -> lookahead state | Some (Exactly c, state) -> let state = State.append state (if c = '.' then not_empty else maybe_empty) in exactly state c (* glob *? === glob ?* *) | Some (One, state) -> State.append state not_empty | Some (Any_of enclosed, state) -> enclosed_set state `Any_of enclosed | Some (Any_but enclosed, state) -> enclosed_set state `Any_but enclosed (* * then ** === ** *) | Some (ManyMany, state) -> many_many state in lookahead state) ;; let piece state piece = let explicit_slash = State.explicit_slash state in let explicit_period = State.explicit_period state in let slashes = State.slashes state in match piece with | One -> State.append state (one ~explicit_slash ~slashes ~explicit_period) | Many -> many state | Any_of enclosed -> State.append state (enclosed_set `Any_of ~explicit_slash ~slashes ~explicit_period enclosed) | Any_but enclosed -> State.append state (enclosed_set `Any_but ~explicit_slash ~slashes ~explicit_period enclosed) | Exactly c -> exactly state c | ManyMany -> many_many state ;; let glob ~pathname ~match_backslashes ~period glob = let rec loop state = match State.next state with | None -> State.to_re state | Some (p, state) -> loop (piece state p) in loop (State.create ~pathname ~match_backslashes ~period glob) ;; let glob ?(anchored = false) ?(pathname = true) ?(match_backslashes = false) ?(period = true) ?(expand_braces = false) ?(double_asterisk = true) s = let to_re s = let re = glob ~pathname ~match_backslashes ~period (of_string ~double_asterisk s) in if anchored then Re.whole_string re else re in if expand_braces then Re.alt (List.map to_re (explode s)) else to_re s ;; let glob' ?anchored period s = glob ?anchored ~period s let globx ?anchored s = glob ?anchored ~expand_braces:true s let globx' ?anchored period s = glob ?anchored ~expand_braces:true ~period s ocaml-ocaml-re-5586c57/lib/glob.mli000066400000000000000000000066541467707551200170170ustar00rootroot00000000000000(* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr 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, with linking exception; 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 *) (** Shell-style regular expressions *) exception Parse_error (** Implements the semantics of shells patterns. The returned regular expression is unanchored by default. Character '*' matches any sequence of characters and character '?' matches a single character. A sequence '[...]' matches any one of the enclosed characters. A sequence '[^...]' or '[!...]' matches any character *but* the enclosed characters. A backslash escapes the following character. The last character of the string cannot be a backslash. [anchored] controls whether the regular expression will only match entire strings. Defaults to false. [pathname]: If this flag is set, match a slash in string only with a slash in pattern and not by an asterisk ('*') or a question mark ('?') metacharacter, nor by a bracket expression ('[]') containing a slash. Defaults to true. [match_backslashes]: If this flag is set, a forward slash will also match a backslash (useful when globbing Windows paths). Note that a backslash in the pattern will continue to escape the following character. Defaults to [false]. [period]: If this flag is set, a leading period in string has to be matched exactly by a period in pattern. A period is considered to be leading if it is the first character in string, or if both [pathname] is set and the period immediately follows a slash. Defaults to true. If [expand_braces] is true, braced sets will expand into multiple globs, e.g. a\{x,y\}b\{1,2\} matches axb1, axb2, ayb1, ayb2. As specified for bash, brace expansion is purely textual and can be nested. Defaults to false. [double_asterisk]: If this flag is set, double asterisks ('**') will match slash characters, even if [pathname] is set. The [period] flag still applies. Default to true. *) val glob : ?anchored:bool -> ?pathname:bool -> ?match_backslashes:bool -> ?period:bool -> ?expand_braces:bool -> ?double_asterisk:bool -> string -> Core.t (** Same, but allows to choose whether dots at the beginning of a file name need to be explicitly matched (true) or not (false) @deprecated Use [glob ~period]. *) val glob' : ?anchored:bool -> bool -> string -> Core.t (** This version of [glob] also recognizes the pattern \{..,..\} @deprecated Prefer [glob ~expand_braces:true]. *) val globx : ?anchored:bool -> string -> Core.t (** This version of [glob'] also recognizes the pattern \{..,..\} @deprecated Prefer [glob ~expand_braces:true ~period]. *) val globx' : ?anchored:bool -> bool -> string -> Core.t ocaml-ocaml-re-5586c57/lib/group.ml000066400000000000000000000046771467707551200170620ustar00rootroot00000000000000(* Result of a successful match. *) type t = { (* Input string. Matched strings are substrings of s *) s : string (* Mapping from group indices to positions in gpos. group i has positions 2*i - 1, 2*i + 1 in gpos. If the group wasn't matched, then its corresponding values in marks will be -1,-1 *) ; marks : Mark_infos.t ; (* Marks positions. i.e. those marks created with Re.marks *) pmarks : Pmark.Set.t ; (* Group positions. Adjacent elements are (start, stop) of group match. indexed by the values in marks. So group i in an re would be the substring: start = t.gpos.(marks.(2*i)) - 1 stop = t.gpos.(marks.(2*i + 1)) - 1 *) gpos : int array ; (* Number of groups the regular expression contains. Matched or not *) gcount : int } let create s ~gcount ~gpos marks pmarks = { s; gcount; gpos; marks; pmarks } let offset_opt t i = Mark_infos.offset t.marks i |> Option.map (fun (start, stop) -> t.gpos.(start), t.gpos.(stop)) ;; let or_not_found = function | None -> raise Not_found | Some s -> s ;; let offset t i = offset_opt t i |> or_not_found let get_opt t i = offset_opt t i |> Option.map (fun (p1, p2) -> String.sub t.s p1 (p2 - p1)) ;; let pmarks t = t.pmarks let get t i = get_opt t i |> or_not_found let start_opt subs i = offset_opt subs i |> Option.map fst let start subs i = start_opt subs i |> or_not_found let stop_opt subs i = offset_opt subs i |> Option.map snd let stop subs i = stop_opt subs i |> or_not_found let test t i = Mark_infos.test t.marks i let get_opt t i = if test t i then Some (get t i) else None let dummy_offset = -1, -1 let all_offset t = let res = Array.make t.gcount dummy_offset in Mark_infos.iteri t.marks ~f:(fun i start stop -> let p1 = t.gpos.(start) in let p2 = t.gpos.(stop) in res.(i) <- p1, p2); res ;; let dummy_string = "" let all t = let res = Array.make t.gcount dummy_string in Mark_infos.iteri t.marks ~f:(fun i start stop -> let p1 = t.gpos.(start) in let p2 = t.gpos.(stop) in res.(i) <- String.sub t.s p1 (p2 - p1)); res ;; let pp fmt t = let matches = let offsets = all_offset t in let strs = all t in Array.to_list (Array.init (Array.length strs) (fun i -> strs.(i), offsets.(i))) in let open Format in let open Fmt in let pp_match fmt (str, (start, stop)) = fprintf fmt "@[(%s (%d %d))@]" str start stop in sexp fmt "Group" (list pp_match) matches ;; let nb_groups t = t.gcount ocaml-ocaml-re-5586c57/lib/group.mli000066400000000000000000000023511467707551200172160ustar00rootroot00000000000000(** Information about groups in a match. *) (** Result of a successful match. *) type t val create : string -> gcount:int -> gpos:int array -> Mark_infos.t -> Pmark.Set.t -> t (** Raise [Not_found] if the group did not match *) val get : t -> int -> string (** Similar to {!get}, but returns an option instead of using an exception. *) val get_opt : t -> int -> string option (** Raise [Not_found] if the group did not match *) val offset : t -> int -> int * int val offset_opt : t -> int -> (int * int) option (** Return the start of the match. Raise [Not_found] if the group did not match. *) val start : t -> int -> int val start_opt : t -> int -> int option (** Return the end of the match. Raise [Not_found] if the group did not match. *) val stop : t -> int -> int val stop_opt : t -> int -> int option (** Return the empty string for each group which did not match *) val all : t -> string array (** Return [(-1,-1)] for each group which did not match *) val all_offset : t -> (int * int) array (** Test whether a group matched *) val test : t -> int -> bool val pmarks : t -> Pmark.Set.t (** Returns the total number of groups defined - matched or not. This function is experimental. *) val nb_groups : t -> int val pp : t Fmt.t ocaml-ocaml-re-5586c57/lib/hash_set.ml000066400000000000000000000071161467707551200175130ustar00rootroot00000000000000open Import module Array = struct type nonrec t = Bytes.t let words = 8 let[@inline] length t = Bytes.length t / words let[@inline] unsafe_get t i = Int64.to_int (Bytes.get_int64_ne t (i * words)) let[@inline] unsafe_set t i x = Bytes.set_int64_ne t (i * words) (Int64.of_int x) let[@inline] make len x = let t = Bytes.create (len * words) in for i = 0 to length t - 1 do unsafe_set t i x done; t ;; let[@inline] make_absent len = Bytes.make (len * words) '\255' let clear t = Bytes.fill t 0 (Bytes.length t) '\255' let fold_left t ~init ~f = let init = ref init in for i = 0 to length t - 1 do init := f !init (unsafe_get t i) done; !init ;; end (* A specialized hash table that makes the following trade-offs: - Open addresing. Bucketing is quite memory intensive and dune is already a memory hog. - No boxing for empty slots. We make use of the fact that id's are never negative to achieve this. - No saving of the hash. Recomputing the hash for id's is a no-op. *) type nonrec table = { mutable table : Array.t ; mutable size : int } type t = table Option.t ref let init t = if Option.is_none !t then t := Option.some { size = 0; table = Array.make 0 (-1) }; Option.get !t ;; let[@inline] should_grow t = let slots = Array.length t.table in slots = 0 || (t.size > 0 && slots / t.size < 2) ;; let absent = -1 let () = let x = Array.make_absent 1 in assert (Array.unsafe_get x 0 = absent) ;; let create () = ref Option.none let[@inline] index_of_offset slots index i = let i = index + !i in if i >= slots then i - slots else i ;; let clear t = match !t with | None -> () | Some t -> t.size <- 0; Array.clear t.table ;; let add t x = let hash = Int.hash x in let slots = Array.length t.table in let index = hash land (slots - 1) in let inserting = ref true in let i = ref 0 in while !inserting do let idx = index_of_offset slots index i in let elem = Array.unsafe_get t.table idx in if elem = absent then ( Array.unsafe_set t.table idx x; inserting := false) else incr i done; t.size <- t.size + 1 ;; let resize t = let old_table = t.table in let slots = Array.length old_table in let table = Array.make_absent (if slots = 0 then 1 else slots lsl 1) in t.table <- table; for i = 0 to slots - 1 do let elem = Array.unsafe_get old_table i in if elem <> absent then add t elem done ;; let add t x = let t = init t in if should_grow t then resize t; add t x ;; let[@inline] is_empty t = let t = !t in if Option.is_none t then true else ( let t = Option.get t in t.size = 0) ;; let mem t x = let t = !t in if Option.is_none t || (Option.get t).size = 0 then false else ( let t = Option.get t in let hash = Int.hash x in let slots = Array.length t.table in let index = hash land (slots - 1) in let i = ref 0 in let found = ref false in while (not !found) && !i < slots do let idx = index_of_offset slots index i in let elem = Array.unsafe_get t.table idx in if Int.equal elem x then found := true else if Int.equal elem absent then i := slots else incr i done; !found) ;; let pp fmt t = let { table; size } = init t in let table = Array.fold_left table ~init:[] ~f:(fun acc i -> if i = absent then acc else i :: acc) |> List.rev |> Stdlib.Array.of_list in let table fmt () = Fmt.sexp fmt "table" Fmt.(array int) table in let size fmt () = Fmt.sexp fmt "size" Fmt.int size in Format.fprintf fmt "%a@.%a@." table () size () ;; ocaml-ocaml-re-5586c57/lib/hash_set.mli000066400000000000000000000002251467707551200176560ustar00rootroot00000000000000type t val create : unit -> t val is_empty : t -> bool val add : t -> int -> unit val mem : t -> int -> bool val clear : t -> unit val pp : t Fmt.t ocaml-ocaml-re-5586c57/lib/import.ml000066400000000000000000000006771467707551200172340ustar00rootroot00000000000000module List = Stdlib.ListLabels module Poly = struct let equal = ( = ) let compare = compare end module Phys_equal = struct let equal = ( == ) end let ( = ) = Int.equal let ( == ) = [ `Use_phys_equal ] let ( < ) x y = Int.compare x y = -1 let ( > ) x y = Int.compare x y = 1 let min = Int.min let max = Int.max let compare = Int.compare module Int = struct let[@warning "-32"] hash (x : int) = Hashtbl.hash x include Stdlib.Int end ocaml-ocaml-re-5586c57/lib/mark_infos.ml000066400000000000000000000013701467707551200200410ustar00rootroot00000000000000open Import type t = int array let make marks = let len = 1 + List.fold_left ~f:(fun ma (i, _) -> max ma i) ~init:(-1) marks in let t = Array.make len (-1) in List.iter ~f:(fun (i, v) -> t.(i) <- v) marks; t ;; let test t i = if 2 * i >= Array.length t then false else t.(2 * i) <> -1 let offset t i = let start_i = 2 * i in let stop_i = start_i + 1 in if stop_i >= Array.length t then None else ( let start = t.(start_i) in if start = -1 then None else ( let stop = t.(stop_i) in Some (start, stop))) ;; let iteri t ~f = for i = 0 to (Array.length t / 2) - 1 do let idx = 2 * i in let start = t.(idx) in if start <> -1 then ( let stop = t.(idx + 1) in f i start stop) done ;; ocaml-ocaml-re-5586c57/lib/mark_infos.mli000066400000000000000000000003351467707551200202120ustar00rootroot00000000000000(** store mark information for groups in an array *) type t val make : (int * int) list -> t val offset : t -> int -> (int * int) option val test : t -> int -> bool val iteri : t -> f:(int -> int -> int -> unit) -> unit ocaml-ocaml-re-5586c57/lib/parse_buffer.ml000066400000000000000000000024351467707551200203570ustar00rootroot00000000000000type t = { str : string ; mutable pos : int } exception Parse_error let create str = { str; pos = 0 } let unget t = t.pos <- t.pos - 1 let junk t = t.pos <- t.pos + 1 let eos t = t.pos = String.length t.str let test t c = (not (eos t)) && t.str.[t.pos] = c let test2 t c c' = t.pos + 1 < String.length t.str && t.str.[t.pos] = c && t.str.[t.pos + 1] = c' ;; let accept t c = let r = test t c in if r then t.pos <- t.pos + 1; r ;; let accept2 t c c' = let r = test2 t c c' in if r then t.pos <- t.pos + 2; r ;; let get t = let r = t.str.[t.pos] in t.pos <- t.pos + 1; r ;; let accept_s t s' = let len = String.length s' in try for j = 0 to len - 1 do try if s'.[j] <> t.str.[t.pos + j] then raise_notrace Exit with | _ -> raise_notrace Exit done; t.pos <- t.pos + len; true with | Exit -> false ;; let rec integer' t i = if eos t then Some i else ( match get t with | '0' .. '9' as d -> let i' = (10 * i) + (Char.code d - Char.code '0') in if i' < i then raise Parse_error; integer' t i' | _ -> unget t; Some i) ;; let integer t = if eos t then None else ( match get t with | '0' .. '9' as d -> integer' t (Char.code d - Char.code '0') | _ -> unget t; None) ;; ocaml-ocaml-re-5586c57/lib/parse_buffer.mli000066400000000000000000000005261467707551200205270ustar00rootroot00000000000000type t exception Parse_error val create : string -> t val junk : t -> unit val unget : t -> unit val eos : t -> bool val test : t -> char -> bool val test2 : t -> char -> char -> bool val get : t -> char val accept : t -> char -> bool val accept2 : t -> char -> char -> bool val accept_s : t -> string -> bool val integer : t -> int option ocaml-ocaml-re-5586c57/lib/pcre.ml000066400000000000000000000104641467707551200166460ustar00rootroot00000000000000module Re = Core exception Parse_error = Perl.Parse_error exception Not_supported = Perl.Not_supported type regexp = Re.re type flag = [ `CASELESS | `MULTILINE | `ANCHORED | `DOTALL ] type split_result = | Text of string | Delim of string | Group of int * string | NoGroup type groups = Core.Group.t let re ?(flags = []) pat = let opts = List.map (function | `CASELESS -> `Caseless | `MULTILINE -> `Multiline | `ANCHORED -> `Anchored | `DOTALL -> `Dotall) flags in Perl.re ~opts pat ;; let regexp ?flags pat = Re.compile (re ?flags pat) let extract ~rex s = Re.Group.all (Re.exec rex s) let exec ~rex ?pos s = Re.exec rex ?pos s let get_substring s i = Re.Group.get s i let names rex = Re.group_names rex |> List.map fst |> Array.of_list let get_named_substring rex name s = let rec loop = function | [] -> raise Not_found | (n, i) :: rem when n = name -> (try get_substring s i with | Not_found -> loop rem) | _ :: rem -> loop rem in loop (Re.group_names rex) ;; let get_substring_ofs s i = Re.Group.offset s i let pmatch ~rex s = Re.execp rex s let substitute ~rex ~subst str = let b = Buffer.create 1024 in let rec loop pos on_match = if Re.execp ~pos rex str then ( let ss = Re.exec ~pos rex str in let start, fin = Re.Group.offset ss 0 in if on_match && start = pos && start = fin then ( if (* Empty match following a match *) pos < String.length str then ( Buffer.add_char b str.[pos]; loop (pos + 1) false)) else ( let pat = Re.Group.get ss 0 in Buffer.add_substring b str pos (start - pos); Buffer.add_string b (subst pat); if start = fin then ( if (* Manually advance by one after an empty match *) fin < String.length str then ( Buffer.add_char b str.[fin]; loop (fin + 1) false)) else loop fin true)) else Buffer.add_substring b str pos (String.length str - pos) in loop 0 false; Buffer.contents b ;; let split ~rex str = let finish str last accu = let accu = String.sub str last (String.length str - last) :: accu in List.rev accu in let rec loop accu last pos on_match = if Re.execp ~pos rex str then ( let ss = Re.exec ~pos rex str in let start, fin = Re.Group.offset ss 0 in if on_match && start = pos && start = fin then if (* Empty match following a match *) pos = String.length str then finish str last accu else loop accu last (pos + 1) false else ( let accu = String.sub str last (start - last) :: accu in if start = fin then if (* Manually advance by one after an empty match *) fin = String.length str then finish str fin accu else loop accu fin (fin + 1) false else loop accu fin fin true)) else finish str last accu in loop [] 0 0 false ;; (* From PCRE *) let string_unsafe_sub s ofs len = let r = Bytes.create len in Bytes.unsafe_blit s ofs r 0 len; Bytes.unsafe_to_string r ;; let quote s = let len = String.length s in let buf = Bytes.create (len lsl 1) in let pos = ref 0 in for i = 0 to len - 1 do match String.unsafe_get s i with | ('\\' | '^' | '$' | '.' | '[' | '|' | '(' | ')' | '?' | '*' | '+' | '{') as c -> Bytes.unsafe_set buf !pos '\\'; incr pos; Bytes.unsafe_set buf !pos c; incr pos | c -> Bytes.unsafe_set buf !pos c; incr pos done; string_unsafe_sub buf 0 !pos ;; let full_split ?(max = 0) ~rex s = if String.length s = 0 then [] else if max = 1 then [ Text s ] else ( let results = Re.split_full rex s in let matches = List.map (function | `Text s -> [ Text s ] | `Delim d -> let matches = Re.Group.all_offset d in let delim = Re.Group.get d 0 in Delim delim :: (let l = ref [] in for i = 1 to Array.length matches - 1 do l := (if matches.(i) = (-1, -1) then NoGroup else Group (i, Re.Group.get d i)) :: !l done; List.rev !l)) results in List.concat matches) ;; type substrings = Group.t ocaml-ocaml-re-5586c57/lib/pcre.mli000066400000000000000000000033001467707551200170060ustar00rootroot00000000000000(** NOTE: Only a subset of the PCRE spec is supported *) exception Parse_error exception Not_supported type regexp = Core.re type flag = [ `CASELESS | `MULTILINE | `ANCHORED | `DOTALL ] type groups = Core.Group.t (** Result of a {!Pcre.full_split} *) type split_result = | Text of string (** Text part of splitted string *) | Delim of string (** Delimiter part of splitted string *) | Group of int * string (** Subgroup of matched delimiter (subgroup_nr, subgroup_str) *) | NoGroup (** Unmatched subgroup *) (** [re ~flags s] creates the regexp [s] using the pcre syntax. *) val re : ?flags:flag list -> string -> Core.t (** [re ~flags s] compiles the regexp [s] using the pcre syntax. *) val regexp : ?flags:flag list -> string -> regexp (** [extract ~rex s] executes [rex] on [s] and returns the matching groups. *) val extract : rex:regexp -> string -> string array (** Equivalent to {!Core.exec}. *) val exec : rex:regexp -> ?pos:int -> string -> groups (** Equivalent to {!Core.Group.get}. *) val get_substring : groups -> int -> string (** Return the names of named groups. *) val names : regexp -> string array (** Return the first matched named group, or raise [Not_found]. *) val get_named_substring : regexp -> string -> groups -> string (** Equivalent to {!Core.Group.offset}. *) val get_substring_ofs : groups -> int -> int * int (** Equivalent to {!Core.execp}. *) val pmatch : rex:regexp -> string -> bool val substitute : rex:Core.re -> subst:(string -> string) -> string -> string val full_split : ?max:int -> rex:regexp -> string -> split_result list val split : rex:regexp -> string -> string list val quote : string -> string (** {2 Deprecated} *) type substrings = Group.t ocaml-ocaml-re-5586c57/lib/perl.ml000066400000000000000000000227301467707551200166560ustar00rootroot00000000000000(* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr 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, with linking exception; 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 *) module Re = Core exception Parse_error = Parse_buffer.Parse_error exception Not_supported let acc_digits = let rec loop base digits acc i = match digits with | [] -> acc | d :: digits -> let acc = acc + (d * i) in let i = i * i in loop base digits acc i in fun ~base ~digits -> loop base digits 0 1 ;; let char_of_int x = match char_of_int x with | x -> x | exception _ -> raise Parse_error ;; let parse multiline dollar_endonly dotall ungreedy s = let buf = Parse_buffer.create s in let accept = Parse_buffer.accept buf in let eos () = Parse_buffer.eos buf in let test c = Parse_buffer.test buf c in let unget () = Parse_buffer.unget buf in let get () = Parse_buffer.get buf in let greedy_mod r = let gr = accept '?' in let gr = if ungreedy then not gr else gr in if gr then Re.non_greedy r else Re.greedy r in let rec regexp () = regexp' (branch ()) and regexp' left = if accept '|' then regexp' (Re.alt [ left; branch () ]) else left and branch () = branch' [] and branch' left = if eos () || test '|' || test ')' then Re.seq (List.rev left) else branch' (piece () :: left) and in_brace ~f ~init = match accept '{' with | false -> None | true -> let rec loop acc = if accept '}' then acc else ( let acc = f acc in loop acc) in Some (loop init) and piece () = let r = atom () in if accept '*' then greedy_mod (Re.rep r) else if accept '+' then greedy_mod (Re.rep1 r) else if accept '?' then greedy_mod (Re.opt r) else if accept '{' then ( match Parse_buffer.integer buf with | Some i -> let j = if accept ',' then Parse_buffer.integer buf else Some i in if not (accept '}') then raise Parse_error; (match j with | Some j when j < i -> raise Parse_error | _ -> ()); greedy_mod (Re.repn r i j) | None -> unget (); r) else r and atom () = if accept '.' then if dotall then Re.any else Re.notnl else if accept '(' then if accept '?' then if accept ':' then ( let r = regexp () in if not (accept ')') then raise Parse_error; r) else if accept '#' then comment () else if accept '<' then ( let name = name () in let r = regexp () in if not (accept ')') then raise Parse_error; Re.group ~name r) else raise Parse_error else ( let r = regexp () in if not (accept ')') then raise Parse_error; Re.group r) else if accept '^' then if multiline then Re.bol else Re.bos else if accept '$' then if multiline then Re.eol else if dollar_endonly then Re.leol else Re.eos else if accept '[' then if accept '^' then Re.compl (bracket []) else Re.alt (bracket []) else if accept '\\' then ( (* XXX - Back-references - \cx (control-x), \ddd *) if eos () then raise Parse_error; match get () with | 'w' -> Re.alt [ Re.alnum; Re.char '_' ] | 'W' -> Re.compl [ Re.alnum; Re.char '_' ] | 's' -> Re.space | 'S' -> Re.compl [ Re.space ] | 'd' -> Re.digit | 'D' -> Re.compl [ Re.digit ] | 'b' -> Re.alt [ Re.bow; Re.eow ] | 'B' -> Re.not_boundary | 'A' -> Re.bos | 'Z' -> Re.leol | 'z' -> Re.eos | 'G' -> Re.start | 'e' -> Re.char '\x1b' | 'f' -> Re.char '\x0c' | 'n' -> Re.char '\n' | 'r' -> Re.char '\r' | 't' -> Re.char '\t' | 'Q' -> quote (Buffer.create 12) | 'E' -> raise Parse_error | 'x' -> let c1, c2 = match in_brace ~init:[] ~f:(fun acc -> hexdigit () :: acc) with | Some [ c1; c2 ] -> c1, c2 | Some [ c2 ] -> 0, c2 | Some _ -> raise Parse_error | None -> let c1 = hexdigit () in let c2 = hexdigit () in c1, c2 in let code = (c1 * 16) + c2 in Re.char (char_of_int code) | 'o' -> (match in_brace ~init:[] ~f:(fun acc -> match maybe_octaldigit () with | None -> raise Parse_error | Some p -> p :: acc) with | None -> raise Parse_error | Some digits -> Re.char (char_of_int (acc_digits ~base:8 ~digits))) | 'a' .. 'z' | 'A' .. 'Z' -> raise Parse_error | '0' .. '7' as n1 -> let n2 = maybe_octaldigit () in let n3 = maybe_octaldigit () in (match n2, n3 with | Some n2, Some n3 -> let n1 = Char.code n1 - Char.code '0' in Re.char (char_of_int ((n1 * (8 * 8)) + (n2 * 8) + n3)) | _, _ -> raise Not_supported) | '8' .. '9' -> raise Not_supported | c -> Re.char c) else ( if eos () then raise Parse_error; match get () with | '*' | '+' | '?' | '{' | '\\' -> raise Parse_error | c -> Re.char c) and quote buf = if accept '\\' then ( if eos () then raise Parse_error; match get () with | 'E' -> Re.str (Buffer.contents buf) | c -> Buffer.add_char buf '\\'; Buffer.add_char buf c; quote buf) else ( if eos () then raise Parse_error; Buffer.add_char buf (get ()); quote buf) and hexdigit () = if eos () then raise Parse_error; match get () with | '0' .. '9' as d -> Char.code d - Char.code '0' | 'a' .. 'f' as d -> Char.code d - Char.code 'a' + 10 | 'A' .. 'F' as d -> Char.code d - Char.code 'A' + 10 | _ -> raise Parse_error and maybe_octaldigit () = if eos () then None else ( match get () with | '0' .. '7' as d -> Some (Char.code d - Char.code '0') | _ -> None) and name () = if eos () then raise Parse_error else ( match get () with | ('_' | 'a' .. 'z' | 'A' .. 'Z') as c -> let b = Buffer.create 32 in Buffer.add_char b c; name' b | _ -> raise Parse_error) and name' b = if eos () then raise Parse_error else ( match get () with | ('_' | 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9') as c -> Buffer.add_char b c; name' b | '>' -> Buffer.contents b | _ -> raise Parse_error) and bracket s = if s <> [] && accept ']' then s else ( match char () with | `Set st -> bracket (st :: s) | `Char c -> if accept '-' then if accept ']' then Re.char c :: Re.char '-' :: s else bracket (match char () with | `Char c' -> Re.rg c c' :: s | `Set st' -> Re.char c :: Re.char '-' :: st' :: s) else bracket (Re.char c :: s)) and char () = if eos () then raise Parse_error; let c = get () in if c = '[' then ( if accept '=' then raise Not_supported; match Posix_class.parse buf with | Some set -> `Set set | None -> if accept '.' then ( if eos () then raise Parse_error; let c = get () in if not (accept '.') then raise Not_supported; if not (accept ']') then raise Parse_error; `Char c) else `Char c) else if c = '\\' then ( if eos () then raise Parse_error; let c = get () in (* XXX \127, ... *) match c with | 'b' -> `Char '\008' | 'n' -> `Char '\n' (*XXX*) | 'r' -> `Char '\r' (*XXX*) | 't' -> `Char '\t' (*XXX*) | 'w' -> `Set (Re.alt [ Re.alnum; Re.char '_' ]) | 'W' -> `Set (Re.compl [ Re.alnum; Re.char '_' ]) | 's' -> `Set Re.space | 'S' -> `Set (Re.compl [ Re.space ]) | 'd' -> `Set Re.digit | 'D' -> `Set (Re.compl [ Re.digit ]) | 'a' .. 'z' | 'A' .. 'Z' -> raise Parse_error | '0' .. '9' -> raise Not_supported | _ -> `Char c) else `Char c and comment () = if eos () then raise Parse_error; if accept ')' then Re.epsilon else ( Parse_buffer.junk buf; comment ()) in let res = regexp () in if not (eos ()) then raise Parse_error; res ;; type opt = [ `Ungreedy | `Dotall | `Dollar_endonly | `Multiline | `Anchored | `Caseless ] let re ?(opts = []) s = let r = parse (List.memq `Multiline opts) (List.memq `Dollar_endonly opts) (List.memq `Dotall opts) (List.memq `Ungreedy opts) s in let r = if List.memq `Anchored opts then Re.seq [ Re.start; r ] else r in let r = if List.memq `Caseless opts then Re.no_case r else r in r ;; let compile = Re.compile let compile_pat ?(opts = []) s = compile (re ~opts s) ocaml-ocaml-re-5586c57/lib/perl.mli000066400000000000000000000025771467707551200170360ustar00rootroot00000000000000(* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr 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, with linking exception; 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 *) (** Perl-style regular expressions *) exception Parse_error (** Errors that can be raised during the parsing of the regular expression *) exception Not_supported type opt = [ `Ungreedy | `Dotall | `Dollar_endonly | `Multiline | `Anchored | `Caseless ] (** Parsing of a Perl-style regular expression *) val re : ?opts:opt list -> string -> Core.t (** (Same as [Re.compile]) *) val compile : Core.t -> Core.re (** Regular expression compilation *) val compile_pat : ?opts:opt list -> string -> Core.re ocaml-ocaml-re-5586c57/lib/pmark.ml000066400000000000000000000006111467707551200170200ustar00rootroot00000000000000module Pmark = struct type t = int let equal (x : int) (y : int) = x = y let compare (x : int) (y : int) = compare x y let r = ref 0 let gen () = incr r; !r ;; let pp = Format.pp_print_int end include Pmark module Set = struct module Set = Set.Make (Pmark) let[@warning "-32"] to_list x = let open Set in to_seq x |> List.of_seq ;; include Set end ocaml-ocaml-re-5586c57/lib/pmark.mli000066400000000000000000000003111467707551200171660ustar00rootroot00000000000000type t = private int val equal : t -> t -> bool val compare : t -> t -> int val gen : unit -> t val pp : t Fmt.t module Set : sig include Set.S with type elt = t val to_list : t -> elt list end ocaml-ocaml-re-5586c57/lib/posix.ml000066400000000000000000000110411467707551200170470ustar00rootroot00000000000000(* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr 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, with linking exception; 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 *) (* What we could (should?) do: - a* ==> longest ((shortest (no_group a)* ), a | ()) (!!!) - abc understood as (ab)c - "((a?)|b)" against "ab" should not bind the first subpattern to anything Note that it should be possible to handle "(((ab)c)d)e" efficiently *) module Re = Core exception Parse_error = Parse_buffer.Parse_error exception Not_supported let parse newline s = let buf = Parse_buffer.create s in let accept = Parse_buffer.accept buf in let eos () = Parse_buffer.eos buf in let test c = Parse_buffer.test buf c in let unget () = Parse_buffer.unget buf in let get () = Parse_buffer.get buf in let rec regexp () = regexp' (branch ()) and regexp' left = if accept '|' then regexp' (Re.alt [ left; branch () ]) else left and branch () = branch' [] and branch' left = if eos () || test '|' || test ')' then Re.seq (List.rev left) else branch' (piece () :: left) and piece () = let r = atom () in if accept '*' then Re.rep (Re.nest r) else if accept '+' then Re.rep1 (Re.nest r) else if accept '?' then Re.opt r else if accept '{' then ( match Parse_buffer.integer buf with | Some i -> let j = if accept ',' then Parse_buffer.integer buf else Some i in if not (accept '}') then raise Parse_error; (match j with | Some j when j < i -> raise Parse_error | _ -> ()); Re.repn (Re.nest r) i j | None -> unget (); r) else r and atom () = if accept '.' then if newline then Re.notnl else Re.any else if accept '(' then ( let r = regexp () in if not (accept ')') then raise Parse_error; Re.group r) else if accept '^' then if newline then Re.bol else Re.bos else if accept '$' then if newline then Re.eol else Re.eos else if accept '[' then if accept '^' then Re.diff (Re.compl (bracket [])) (Re.char '\n') else Re.alt (bracket []) else if accept '\\' then ( if eos () then raise Parse_error; match get () with | ('|' | '(' | ')' | '*' | '+' | '?' | '[' | '.' | '^' | '$' | '{' | '\\') as c -> Re.char c | _ -> raise Parse_error) else ( if eos () then raise Parse_error; match get () with | '*' | '+' | '?' | '{' | '\\' -> raise Parse_error | c -> Re.char c) and bracket s = if s <> [] && accept ']' then s else ( match char () with | `Set st -> bracket (st :: s) | `Char c -> if accept '-' then if accept ']' then Re.char c :: Re.char '-' :: s else bracket (match char () with | `Char c' -> Re.rg c c' :: s | `Set st' -> Re.char c :: Re.char '-' :: st' :: s) else bracket (Re.char c :: s)) and char () = if eos () then raise Parse_error; let c = get () in if c = '[' then ( match Posix_class.parse buf with | Some set -> `Set set | None -> if accept '.' then ( if eos () then raise Parse_error; let c = get () in if not (accept '.') then raise Not_supported; if not (accept ']') then raise Parse_error; `Char c) else `Char c) else `Char c in let res = regexp () in if not (eos ()) then raise Parse_error; res ;; type opt = [ `ICase | `NoSub | `Newline ] let re ?(opts = []) s = let r = parse (List.memq `Newline opts) s in let r = if List.memq `ICase opts then Re.no_case r else r in let r = if List.memq `NoSub opts then Re.no_group r else r in r ;; let compile re = Re.compile (Re.longest re) let compile_pat ?(opts = []) s = compile (re ~opts s) ocaml-ocaml-re-5586c57/lib/posix.mli000066400000000000000000000073171467707551200172330ustar00rootroot00000000000000(* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr 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, with linking exception; 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 *) (** References: - {{:http://www.opengroup.org/onlinepubs/007908799/xbd/re.html} re} - {{:http://www.opengroup.org/onlinepubs/007908799/xsh/regcomp.html} regcomp} Example of how to use this module (to parse some IRC logs): {[ type msg = { time : string ; author : string ; content : string } let re = Core.compile (Re_posix.re "([^:].*:[^:]*:[^:]{2})<.([^>]+)> (.+)$") (* parse a line *) let match_line line = try let substrings = Core.exec re line in let groups = Core.get_all substrings in (* groups can be obtained directly by index within [substrings] *) Some { time = groups.(1); author = groups.(2); content = groups.(3) } with | Not_found -> None (* regex didn't match *) ;; ]} *) (* XXX Character classes *) exception Parse_error (** Errors that can be raised during the parsing of the regular expression *) exception Not_supported type opt = [ `ICase | `NoSub | `Newline ] (** Parsing of a Posix extended regular expression *) val re : ?opts:opt list -> string -> Core.t (** [compile r] is defined as [Core.compile (Core.longest r)] *) val compile : Core.t -> Core.re (** [compile_pat ?opts regex] compiles the Posix extended regular expression [regexp] *) val compile_pat : ?opts:opt list -> string -> Core.re (* Deviation from the standard / ambiguities in the standard --------------------------------------------------------- We tested the behavior of the Linux library (glibc) and the Solaris library. (1) An expression [efg] should be parsed as [(ef)g]. All implementations parse it as [e(fg)]. (2) When matching the pattern "((a)|b)*" against the string "ab", the sub-expression "((a)|b)" should match "b", and the sub-expression "(a)" should not match anything. In both implementation, the sub-expression "(a)" matches "a". (3) When matching the pattern "(aa?)*" against the string "aaa", it is not clear whether the final match of the sub-expression "(aa?)" is the last "a" (all matches of the sub-expression are successively maximized), or "aa" (the final match is maximized). Both implementations implements the first case. (4) When matching the pattern "((a?)|b)*" against the string "ab", the sub-expression "((a?)|b)" should match the empty string at the end of the string (it is better to match the empty string than to match nothing). In both implementations, this sub-expression matches "b". (Strangely, in the Linux implementation, the sub-expression "(a?)" correctly matches the empty string at the end of the string) This library behaves the same way as the other libraries for all points, except for (2) and (4) where it follows the standard. The behavior of this library in theses four cases may change in future releases. *) ocaml-ocaml-re-5586c57/lib/posix_class.ml000066400000000000000000000021161467707551200202370ustar00rootroot00000000000000module Re = Core let of_name = function | "alpha" -> Re.alpha | "alnum" -> Re.alnum | "ascii" -> Re.ascii | "blank" -> Re.blank | "cntrl" -> Re.cntrl | "digit" -> Re.digit | "lower" -> Re.lower | "print" -> Re.print | "space" -> Re.space | "upper" -> Re.upper | "word" -> Re.wordc | "punct" -> Re.punct | "graph" -> Re.graph | "xdigit" -> Re.xdigit | class_ -> invalid_arg ("Invalid pcre class: " ^ class_) ;; let names = [ "alpha" ; "alnum" ; "ascii" ; "blank" ; "cntrl" ; "digit" ; "lower" ; "print" ; "space" ; "upper" ; "word" ; "punct" ; "graph" ; "xdigit" ] ;; let parse buf = let accept = Parse_buffer.accept buf in let accept_s = Parse_buffer.accept_s buf in match accept ':' with | false -> None | true -> let compl = accept '^' in let cls = try List.find accept_s names with | Not_found -> raise Parse_buffer.Parse_error in if not (accept_s ":]") then raise Parse_buffer.Parse_error; let posix_class = of_name cls in Some (if compl then Re.compl [ posix_class ] else posix_class) ;; ocaml-ocaml-re-5586c57/lib/posix_class.mli000066400000000000000000000001431467707551200204060ustar00rootroot00000000000000val names : string list val of_name : string -> Core.t val parse : Parse_buffer.t -> Core.t option ocaml-ocaml-re-5586c57/lib/re.ml000066400000000000000000000002441467707551200163160ustar00rootroot00000000000000include Core include Replace module View = View module Emacs = Emacs module Glob = Glob module Perl = Perl module Pcre = Pcre module Posix = Posix module Str = Str ocaml-ocaml-re-5586c57/lib/replace.ml000066400000000000000000000034701467707551200173270ustar00rootroot00000000000000let replace ?(pos = 0) ?len ?(all = true) re ~f s = if pos < 0 then invalid_arg "Re.replace"; let limit = match len with | None -> String.length s | Some l -> if l < 0 || pos + l > String.length s then invalid_arg "Re.replace"; pos + l in (* buffer into which we write the result *) let buf = Buffer.create (String.length s) in (* iterate on matched substrings. *) let rec iter pos on_match = if pos <= limit then ( match Compile.match_str ~groups:true ~partial:false re s ~pos ~len:(limit - pos) with | Match substr -> let p1, p2 = Group.offset substr 0 in if pos = p1 && p1 = p2 && on_match then ( (* if we matched an empty string right after a match, we must manually advance by 1 *) if p2 < limit then Buffer.add_char buf s.[p2]; iter (p2 + 1) false) else ( (* add string between previous match and current match *) Buffer.add_substring buf s pos (p1 - pos); (* what should we replace the matched group with? *) let replacing = f substr in Buffer.add_string buf replacing; if all then (* if we matched an empty string, we must manually advance by 1 *) iter (if p1 = p2 then ( (* a non char could be past the end of string. e.g. $ *) if p2 < limit then Buffer.add_char buf s.[p2]; p2 + 1) else p2) (p1 <> p2) else Buffer.add_substring buf s p2 (limit - p2)) | Running _ -> () | Failed -> Buffer.add_substring buf s pos (limit - pos)) in iter pos false; Buffer.contents buf ;; let replace_string ?pos ?len ?all re ~by s = replace ?pos ?len ?all re s ~f:(fun _ -> by) ocaml-ocaml-re-5586c57/lib/replace.mli000066400000000000000000000023661467707551200175030ustar00rootroot00000000000000(** [replace ~all re ~f s] iterates on [s], and replaces every occurrence of [re] with [f substring] where [substring] is the current match. If [all = false], then only the first occurrence of [re] is replaced. *) val replace : ?pos:int (** Default: 0 *) -> ?len:int -> ?all:bool (** Default: true. Otherwise only replace first occurrence *) -> Compile.re (** matched groups *) -> f:(Group.t -> string) (** how to replace *) -> string (** string to replace in *) -> string (** [replace_string ~all re ~by s] iterates on [s], and replaces every occurrence of [re] with [by]. If [all = false], then only the first occurrence of [re] is replaced. {5 Examples:} {[ # let regex = Re.compile (Re.char ',');; val regex : re = # Re.replace_string regex ~by:";" "[1,2,3,4,5,6,7]";; - : string = "[1;2;3;4;5;6;7]" # Re.replace_string regex ~all:false ~by:";" "[1,2,3,4,5,6,7]";; - : string = "[1;2,3,4,5,6,7]" ]} *) val replace_string : ?pos:int (** Default: 0 *) -> ?len:int -> ?all:bool (** Default: true. Otherwise only replace first occurrence *) -> Compile.re (** matched groups *) -> by:string (** replacement string *) -> string (** string to replace in *) -> string ocaml-ocaml-re-5586c57/lib/search.ml000066400000000000000000000067531467707551200171700ustar00rootroot00000000000000let all ?(pos = 0) ?len re s : _ Seq.t = if pos < 0 then invalid_arg "Re.all"; (* index of the first position we do not consider. !pos < limit is an invariant *) let limit = match len with | None -> String.length s | Some l -> if l < 0 || pos + l > String.length s then invalid_arg "Re.all"; pos + l in (* iterate on matches. When a match is found, search for the next one just after its end *) let rec aux pos on_match () = if pos > limit then Seq.Nil (* no more matches *) else ( match Compile.match_str ~groups:true ~partial:false re s ~pos ~len:(limit - pos) with | Match substr -> let p1, p2 = Group.offset substr 0 in if on_match && p1 = pos && p1 = p2 then (* skip empty match right after a match *) aux (pos + 1) false () else ( let pos = if p1 = p2 then p2 + 1 else p2 in Seq.Cons (substr, aux pos (p1 <> p2))) | Running _ | Failed -> Seq.Nil) in aux pos false ;; let matches ?pos ?len re s : _ Seq.t = all ?pos ?len re s |> Seq.map (fun sub -> Group.get sub 0) ;; let split_full ?(pos = 0) ?len re s : _ Seq.t = if pos < 0 then invalid_arg "Re.split"; let limit = match len with | None -> String.length s | Some l -> if l < 0 || pos + l > String.length s then invalid_arg "Re.split"; pos + l in (* i: start of delimited string pos: first position after last match of [re] limit: first index we ignore (!pos < limit is an invariant) *) let pos0 = pos in let rec aux state i pos () = match state with | `Idle when pos > limit -> (* We had an empty match at the end of the string *) assert (i = limit); Seq.Nil | `Idle -> (match Compile.match_str ~groups:true ~partial:false re s ~pos ~len:(limit - pos) with | Match substr -> let p1, p2 = Group.offset substr 0 in let pos = if p1 = p2 then p2 + 1 else p2 in let old_i = i in let i = p2 in if old_i = p1 && p1 = p2 && p1 > pos0 then (* Skip empty match right after a delimiter *) aux state i pos () else if p1 > pos0 then ( (* string does not start by a delimiter *) let text = String.sub s old_i (p1 - old_i) in let state = `Yield (`Delim substr) in Seq.Cons (`Text text, aux state i pos)) else Seq.Cons (`Delim substr, aux state i pos) | Running _ -> Seq.Nil | Failed -> if i < limit then ( let text = String.sub s i (limit - i) in (* yield last string *) Seq.Cons (`Text text, aux state limit pos)) else Seq.Nil) | `Yield x -> Seq.Cons (x, aux `Idle i pos) in aux `Idle pos pos ;; let split ?pos ?len re s : _ Seq.t = let seq = split_full ?pos ?len re s in let rec filter seq () = match seq () with | Seq.Nil -> Seq.Nil | Seq.Cons (`Delim _, tl) -> filter tl () | Seq.Cons (`Text s, tl) -> Seq.Cons (s, filter tl) in filter seq ;; let split_delim ?pos ?len re s : _ Seq.t = let seq = split_full ?pos ?len re s in let rec filter ~delim seq () = match seq () with | Seq.Nil -> if delim then Seq.Cons ("", fun () -> Seq.Nil) else Seq.Nil | Seq.Cons (`Delim _, tl) -> if delim then Seq.Cons ("", fun () -> filter ~delim:true tl ()) else filter ~delim:true tl () | Seq.Cons (`Text s, tl) -> Seq.Cons (s, filter ~delim:false tl) in filter ~delim:true seq ;; ocaml-ocaml-re-5586c57/lib/str.ml000066400000000000000000000203661467707551200165270ustar00rootroot00000000000000(***********************************************************************) (* *) (* Objective Caml *) (* *) (* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) (* *) (* Copyright 1996 Institut National de Recherche en Informatique et *) (* en Automatique. All rights reserved. This file is distributed *) (* under the terms of the GNU Library General Public License, with *) (* linking exception. *) (* *) (***********************************************************************) (* Modified by Jerome.Vouillon@pps.jussieu.fr for integration in RE *) (* $Id: re_str.ml,v 1.3 2002/07/03 15:47:54 vouillon Exp $ *) module Ast = Ast.Export include struct open Core let exec = exec let exec_partial = exec_partial end type regexp = { mtch : Compile.re Lazy.t ; srch : Compile.re Lazy.t } let compile_regexp s c = let re = Emacs.re ~case:(not c) s in { mtch = lazy (Compile.compile (Ast.seq [ Ast.start; re ])) ; srch = lazy (Compile.compile re) } ;; let state = ref None let string_match re s p = match exec ~pos:p (Lazy.force re.mtch) s with | res -> state := Some res; true | exception Not_found -> state := None; false ;; let string_partial_match re s p = match exec_partial ~pos:p (Lazy.force re.mtch) s with | `Full -> string_match re s p | `Partial -> true | `Mismatch -> false ;; let search_forward re s p = match exec ~pos:p (Lazy.force re.srch) s with | res -> state := Some res; fst (Group.offset res 0) | exception Not_found -> state := None; raise Not_found ;; let rec search_backward re s p = match exec ~pos:p (Lazy.force re.mtch) s with | res -> state := Some res; p | exception Not_found -> state := None; if p = 0 then raise Not_found else search_backward re s (p - 1) ;; let valid_group n = n >= 0 && n < 10 && match !state with | None -> false | Some m -> n < Group.nb_groups m ;; let offset_group i = match !state with | Some m -> Group.offset m i | None -> raise Not_found ;; let group_len i = match offset_group i with | b, e -> e - b | exception Not_found -> 0 ;; let rec repl_length repl p q len = if p < len then if repl.[p] <> '\\' then repl_length repl (p + 1) (q + 1) len else ( let p = p + 1 in if p = len then failwith "Str.replace: illegal backslash sequence"; let q = match repl.[p] with | '\\' -> q + 1 | '0' .. '9' as c -> q + group_len (Char.code c - Char.code '0') | _ -> q + 2 in repl_length repl (p + 1) q len) else q ;; let rec replace orig repl p res q len = if p < len then ( let c = repl.[p] in if c <> '\\' then ( Bytes.set res q c; replace orig repl (p + 1) res (q + 1) len) else ( match repl.[p + 1] with | '\\' -> Bytes.set res q '\\'; replace orig repl (p + 2) res (q + 1) len | '0' .. '9' as c -> let d = let group = Char.code c - Char.code '0' in match offset_group group with | exception Not_found -> 0 | b, e -> let d = e - b in if d > 0 then String.blit orig b res q d; d in replace orig repl (p + 2) res (q + d) len | c -> Bytes.set res q '\\'; Bytes.set res (q + 1) c; replace orig repl (p + 2) res (q + 2) len)) ;; let replacement_text repl orig = let len = String.length repl in let res = Bytes.create (repl_length repl 0 0 len) in replace orig repl 0 res 0 (String.length repl); Bytes.unsafe_to_string res ;; let quote s = let len = String.length s in let buf = Buffer.create (2 * len) in for i = 0 to len - 1 do match s.[i] with | ('[' | ']' | '*' | '.' | '\\' | '?' | '+' | '^' | '$') as c -> Buffer.add_char buf '\\'; Buffer.add_char buf c | c -> Buffer.add_char buf c done; Buffer.contents buf ;; let string_before s n = String.sub s 0 n let string_after s n = String.sub s n (String.length s - n) let first_chars s n = String.sub s 0 n let last_chars s n = String.sub s (String.length s - n) n let regexp e = compile_regexp e false let regexp_case_fold e = compile_regexp e true let regexp_string s = compile_regexp (quote s) false let regexp_string_case_fold s = compile_regexp (quote s) true let group_beginning n = if not (valid_group n) then invalid_arg "Str.group_beginning"; let pos = fst (offset_group n) in if pos = -1 then raise Not_found else pos ;; let group_end n = if not (valid_group n) then invalid_arg "Str.group_end"; let pos = snd (offset_group n) in if pos = -1 then raise Not_found else pos ;; let matched_group n txt = let b, e = offset_group n in String.sub txt b (e - b) ;; let replace_matched repl matched = replacement_text repl matched let match_beginning () = group_beginning 0 and match_end () = group_end 0 and matched_string txt = matched_group 0 txt let substitute_first expr repl_fun text = try let pos = search_forward expr text 0 in String.concat "" [ string_before text pos; repl_fun text; string_after text (match_end ()) ] with | Not_found -> text ;; let global_substitute expr repl_fun text = let rec replace accu start last_was_empty = let startpos = if last_was_empty then start + 1 else start in if startpos > String.length text then string_after text start :: accu else ( match search_forward expr text startpos with | pos -> let end_pos = match_end () in let repl_text = repl_fun text in replace (repl_text :: String.sub text start (pos - start) :: accu) end_pos (end_pos = pos) | exception Not_found -> string_after text start :: accu) in String.concat "" (List.rev (replace [] 0 false)) ;; let global_replace expr repl text = global_substitute expr (replacement_text repl) text and replace_first expr repl text = substitute_first expr (replacement_text repl) text let search_forward_progress re s p = let pos = search_forward re s p in if match_end () > p then pos else if p < String.length s then search_forward re s (p + 1) else raise Not_found ;; let bounded_split expr text num = let start = if string_match expr text 0 then match_end () else 0 in let rec split accu start n = if start >= String.length text then accu else if n = 1 then string_after text start :: accu else ( try let pos = search_forward_progress expr text start in split (String.sub text start (pos - start) :: accu) (match_end ()) (n - 1) with | Not_found -> string_after text start :: accu) in List.rev (split [] start num) ;; let split expr text = bounded_split expr text 0 let bounded_split_delim expr text num = let rec split accu start n = if start > String.length text then accu else if n = 1 then string_after text start :: accu else ( try let pos = search_forward_progress expr text start in split (String.sub text start (pos - start) :: accu) (match_end ()) (n - 1) with | Not_found -> string_after text start :: accu) in if text = "" then [] else List.rev (split [] 0 num) ;; let split_delim expr text = bounded_split_delim expr text 0 type split_result = | Text of string | Delim of string let bounded_full_split expr text num = let rec split accu start n = if start >= String.length text then accu else if n = 1 then Text (string_after text start) :: accu else ( try let pos = search_forward_progress expr text start in let s = matched_string text in if pos > start then split (Delim s :: Text (String.sub text start (pos - start)) :: accu) (match_end ()) (n - 1) else split (Delim s :: accu) (match_end ()) (n - 1) with | Not_found -> Text (string_after text start) :: accu) in List.rev (split [] 0 num) ;; let full_split expr text = bounded_full_split expr text 0 ocaml-ocaml-re-5586c57/lib/str.mli000066400000000000000000000241021467707551200166700ustar00rootroot00000000000000(***********************************************************************) (* *) (* Objective Caml *) (* *) (* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) (* *) (* Copyright 1996 Institut National de Recherche en Informatique et *) (* en Automatique. All rights reserved. This file is distributed *) (* under the terms of the GNU Library General Public License, with *) (* linking exception. *) (* *) (***********************************************************************) (* $Id: re_str.mli,v 1.1 2002/01/16 14:16:04 vouillon Exp $ *) (** Module [Str]: regular expressions and high-level string processing *) (** {2 Regular expressions} *) (** The type of compiled regular expressions. *) type regexp (** Compile a regular expression. The syntax for regular expressions is the same as in Gnu Emacs. The special characters are [$^.*+?[]]. The following constructs are recognized: - [. ] matches any character except newline - [* ] (postfix) matches the previous expression zero, one or several times - [+ ] (postfix) matches the previous expression one or several times - [? ] (postfix) matches the previous expression once or not at all - [[..] ] character set; ranges are denoted with [-], as in [[a-z]]; an initial [^], as in [[^0-9]], complements the set - [^ ] matches at beginning of line - [$ ] matches at end of line - [\| ] (infix) alternative between two expressions - [\(..\)] grouping and naming of the enclosed expression - [\1 ] the text matched by the first [\(...\)] expression ([\2] for the second expression, etc) - [\b ] matches word boundaries - [\ ] quotes special characters. *) val regexp : string -> regexp (** Same as [regexp], but the compiled expression will match text in a case-insensitive way: uppercase and lowercase letters will be considered equivalent. *) val regexp_case_fold : string -> regexp (** [Str.quote s] returns a regexp string that matches exactly [s] and nothing else. *) val quote : string -> string (** [Str.regexp_string s] returns a regular expression that matches exactly [s] and nothing else. *) val regexp_string : string -> regexp (** [Str.regexp_string_case_fold] is similar to [Str.regexp_string], but the regexp matches in a case-insensitive way. *) val regexp_string_case_fold : string -> regexp (** {2 String matching and searching} *) (** [string_match r s start] tests whether the characters in [s] starting at position [start] match the regular expression [r]. The first character of a string has position [0], as usual. *) val string_match : regexp -> string -> int -> bool (** [search_forward r s start] searches the string [s] for a substring matching the regular expression [r]. The search starts at position [start] and proceeds towards the end of the string. Return the position of the first character of the matched substring, or raise [Not_found] if no substring matches. *) val search_forward : regexp -> string -> int -> int (** Same as [search_forward], but the search proceeds towards the beginning of the string. *) val search_backward : regexp -> string -> int -> int (** Similar to [string_match], but succeeds whenever the argument string is a prefix of a string that matches. This includes the case of a true complete match. *) val string_partial_match : regexp -> string -> int -> bool (** [matched_string s] returns the substring of [s] that was matched by the latest [string_match], [search_forward] or [search_backward]. The user must make sure that the parameter [s] is the same string that was passed to the matching or searching function. *) val matched_string : string -> string (** [match_beginning ()] returns the position of the first character of the substring that was matched by [string_match], [search_forward] or [search_backward]. *) val match_beginning : unit -> int (** [match_end ()] returns the position of the character following the last character of the substring that was matched by [string_match], [search_forward] or [search_backward]. *) val match_end : unit -> int (** [matched_group n s] returns the substring of [s] that was matched by the [n]th group [\(...\)] of the regular expression during the latest [string_match], [search_forward] or [search_backward]. The user must make sure that the parameter [s] is the same string that was passed to the matching or searching function. [matched_group n s] raises [Not_found] if the [n]th group of the regular expression was not matched. This can happen with groups inside alternatives [\|], options [?] or repetitions [*]. For instance, the empty string will match [\(a\)*], but [matched_group 1 ""] will raise [Not_found] because the first group itself was not matched. *) val matched_group : int -> string -> string (** [group_beginning n] returns the position of the first character of the substring that was matched by the [n]th group of the regular expression. Raises [Not_found] if the [n]th group of the regular expression was not matched. *) val group_beginning : int -> int (** [group_end n] returns the position of the character following the last character of the matched substring. Raises [Not_found] if the [n]th group of the regular expression was not matched. *) val group_end : int -> int (** {2 Replacement} *) (** [global_replace regexp templ s] returns a string identical to [s], except that all substrings of [s] that match [regexp] have been replaced by [templ]. The replacement template [templ] can contain [\1], [\2], etc; these sequences will be replaced by the text matched by the corresponding group in the regular expression. [\0] stands for the text matched by the whole regular expression. *) val global_replace : regexp -> string -> string -> string (** Same as [global_replace], except that only the first substring matching the regular expression is replaced. *) val replace_first : regexp -> string -> string -> string (** [global_substitute regexp subst s] returns a string identical to [s], except that all substrings of [s] that match [regexp] have been replaced by the result of function [subst]. The function [subst] is called once for each matching substring, and receives [s] (the whole text) as argument. *) val global_substitute : regexp -> (string -> string) -> string -> string (** Same as [global_substitute], except that only the first substring matching the regular expression is replaced. *) val substitute_first : regexp -> (string -> string) -> string -> string (** [replace_matched repl s] returns the replacement text [repl] in which [\1], [\2], etc. have been replaced by the text matched by the corresponding groups in the most recent matching operation. [s] must be the same string that was matched during this matching operation. *) val replace_matched : string -> string -> string (** {2 Splitting} *) (** [split r s] splits [s] into substrings, taking as delimiters the substrings that match [r], and returns the list of substrings. For instance, [split (regexp "[ \t]+") s] splits [s] into blank-separated words. An occurrence of the delimiter at the beginning and at the end of the string is ignored. *) val split : regexp -> string -> string list (** Same as [split], but splits into at most [n] substrings, where [n] is the extra integer parameter. *) val bounded_split : regexp -> string -> int -> string list (** Same as [split], but occurrences of the delimiter at the beginning and at the end of the string are recognized and returned as empty strings in the result. For instance, [split_delim (regexp " ") " abc "] returns [[""; "abc"; ""]], while [split] with the same arguments returns [["abc"]]. *) val split_delim : regexp -> string -> string list (** Same as [bounded_split] and [split_delim], but occurrences of the delimiter at the beginning and at the end of the string are recognized and returned as empty strings in the result. For instance, [split_delim (regexp " ") " abc "] returns [[""; "abc"; ""]], while [split] with the same arguments returns [["abc"]]. *) val bounded_split_delim : regexp -> string -> int -> string list type split_result = | Text of string | Delim of string (** Same as [split_delim], but returns the delimiters as well as the substrings contained between delimiters. The former are tagged [Delim] in the result list; the latter are tagged [Text]. For instance, [full_split (regexp "[{}]") "{ab}"] returns [[Delim "{"; Text "ab"; Delim "}"]]. *) val full_split : regexp -> string -> split_result list (** Same as [split_delim] and [bounded_split_delim], but returns the delimiters as well as the substrings contained between delimiters. The former are tagged [Delim] in the result list; the latter are tagged [Text]. For instance, [full_split (regexp "[{}]") "{ab}"] returns [[Delim "{"; Text "ab"; Delim "}"]]. *) val bounded_full_split : regexp -> string -> int -> split_result list (** {2 Extracting substrings} *) (** [string_before s n] returns the substring of all characters of [s] that precede position [n] (excluding the character at position [n]). *) val string_before : string -> int -> string (** [string_after s n] returns the substring of all characters of [s] that follow position [n] (including the character at position [n]). *) val string_after : string -> int -> string (** [first_chars s n] returns the first [n] characters of [s]. This is the same function as [string_before]. *) val first_chars : string -> int -> string (** [last_chars s n] returns the last [n] characters of [s]. *) val last_chars : string -> int -> string ocaml-ocaml-re-5586c57/lib/view.ml000066400000000000000000000042141467707551200166630ustar00rootroot00000000000000open Import module Cset = struct include Cset module Range = struct type t = { first : Char.t ; last : Char.t } let first t = t.first let last t = t.last end let view t = fold_right t ~init:[] ~f:(fun first last acc -> let range = { Range.first = Cset.to_char first; last = Cset.to_char last } in range :: acc) ;; end module Sem = Automata.Sem module Rep_kind = Automata.Rep_kind type t = | Set of Cset.t | Sequence of Ast.t list | Alternative of Ast.t list | Repeat of Ast.t * int * int option | Beg_of_line | End_of_line | Beg_of_word | End_of_word | Not_bound | Beg_of_str | End_of_str | Last_end_of_line | Start | Stop | Sem of Automata.Sem.t * Ast.t | Sem_greedy of Automata.Rep_kind.t * Ast.t | Group of string option * Ast.t | No_group of Ast.t | Nest of Ast.t | Case of Ast.t | No_case of Ast.t | Intersection of Ast.t list | Complement of Ast.t list | Difference of Ast.t * Ast.t | Pmark of Pmark.t * Ast.t let view_ast f (t : _ Ast.ast) : t = match t with | Alternative a -> Alternative (List.map ~f a) | No_case a -> No_case (f a) | Case a -> Case (f a) ;; let view_set (cset : Ast.cset) : t = match cset with | Cset set -> Set set | Intersection sets -> Intersection (List.map sets ~f:Ast.t_of_cset) | Complement sets -> Complement (List.map sets ~f:Ast.t_of_cset) | Difference (x, y) -> Difference (Ast.t_of_cset x, Ast.t_of_cset y) | Cast ast -> view_ast Ast.t_of_cset ast ;; let view : Ast.t -> t = function | Set s -> view_set s | Ast s -> view_ast (fun x -> x) s | Sem (sem, a) -> Sem (sem, a) | Sem_greedy (sem, a) -> Sem_greedy (sem, a) | Sequence s -> Sequence s | Repeat (t, x, y) -> Repeat (t, x, y) | Beg_of_line -> Beg_of_line | End_of_line -> End_of_line | Beg_of_word -> Beg_of_word | End_of_word -> End_of_word | Not_bound -> Not_bound | Beg_of_str -> Beg_of_str | End_of_str -> End_of_str | Last_end_of_line -> Last_end_of_line | Start -> Start | Stop -> Stop | No_group a -> No_group a | Group (name, t) -> Group (name, t) | Nest t -> Nest t | Pmark (pmark, t) -> Pmark (pmark, t) ;; ocaml-ocaml-re-5586c57/lib/view.mli000066400000000000000000000017471467707551200170440ustar00rootroot00000000000000(** A view of the top-level of a regex. This type is unstable and may change *) module Cset : sig type t = Cset.t module Range : sig type t val first : t -> Char.t val last : t -> Char.t end val view : t -> Range.t list end module Sem : sig type t = [ `Longest | `Shortest | `First ] end module Rep_kind : sig type t = [ `Greedy | `Non_greedy ] end type t = | Set of Cset.t | Sequence of Ast.t list | Alternative of Ast.t list | Repeat of Ast.t * int * int option | Beg_of_line | End_of_line | Beg_of_word | End_of_word | Not_bound | Beg_of_str | End_of_str | Last_end_of_line | Start | Stop | Sem of Sem.t * Ast.t | Sem_greedy of Rep_kind.t * Ast.t | Group of string option * Ast.t | No_group of Ast.t | Nest of Ast.t | Case of Ast.t | No_case of Ast.t | Intersection of Ast.t list | Complement of Ast.t list | Difference of Ast.t * Ast.t | Pmark of Pmark.t * Ast.t val view : Ast.t -> t ocaml-ocaml-re-5586c57/lib_test/000077500000000000000000000000001467707551200164155ustar00rootroot00000000000000ocaml-ocaml-re-5586c57/lib_test/.cvsignore000066400000000000000000000001111467707551200204060ustar00rootroot00000000000000*.cmi *.cmx re_match pcre_match re_scan pcre_scan unison unison2 unison3 ocaml-ocaml-re-5586c57/lib_test/dune000066400000000000000000000000531467707551200172710ustar00rootroot00000000000000(env (_ (flags (:standard -w -58)))) ocaml-ocaml-re-5586c57/lib_test/expect/000077500000000000000000000000001467707551200177055ustar00rootroot00000000000000ocaml-ocaml-re-5586c57/lib_test/expect/dune000066400000000000000000000010111467707551200205540ustar00rootroot00000000000000(library (name re_tests) (libraries re_private ;; This is because of the (implicit_transitive_deps false) ;; in dune-project ppx_expect.config ppx_expect.config_types ppx_expect base ppx_inline_test.config) (inline_tests (modes native js)) (preprocess (pps ppx_expect))) ;; this hackery is needed because ppx_expect itself uses re, therefore we need to mangle ;; the library name (subdir private_re (library (name re_private) (libraries seq)) (copy_files %{project_root}/lib/*.{ml,mli})) ocaml-ocaml-re-5586c57/lib_test/expect/import.ml000066400000000000000000000032551467707551200215560ustar00rootroot00000000000000module Re = Re_private.Re include Re_private.Import module Fmt = Re_private.Fmt let printf = Printf.printf let t re s = let group = Re.exec_opt (Re.compile re) s in Format.printf "%a@." (Fmt.opt Re.Group.pp) group ;; let re_whitespace = Re.Pcre.regexp "[\t ]+" let re_eol = Re.compile Re.eol let re_bow = Re.compile Re.bow let re_eow = Re.compile Re.eow let strings = Format.printf "[%a]@." Fmt.(list ~pp_sep:(Fmt.lit "; ") Fmt.quoted_string) let re_empty = Re.Posix.compile_pat "" let invalid_argument f = match f () with | s -> ignore s | exception Invalid_argument s -> Format.printf "Invalid_argument %S@." s ;; let exec_partial_detailed ?pos re s = let re = Re.compile re in let res = Re.exec_partial_detailed ?pos re s in match res with | `Mismatch -> Format.printf "`Mismatch@." | `Partial position -> Format.printf "`Partial %d@." position | `Full groups -> Re.Group.all_offset groups |> Array.to_list |> List.map ~f:(fun (a, b) -> Printf.sprintf "%d,%d,%s" a b (match String.sub s a (b - a) with | exception Invalid_argument _ -> "" | s -> Printf.sprintf "%S" s)) |> String.concat ";" |> Format.printf "`Full [|%s|]@." ;; let or_not_found f fmt v = match v () with | exception Not_found -> Format.fprintf fmt "Not_found" | s -> f fmt s ;; let array f fmt v = Format.fprintf fmt "[| %a |]" (Fmt.list ~pp_sep:(Fmt.lit "; ") f) (Array.to_list v) ;; let offset fmt (x, y) = Format.fprintf fmt "(%d, %d)" x y let test_re ?pos ?len r s = let offsets () = Re.Group.all_offset (Re.exec ?pos ?len (Re.compile r) s) in Format.printf "%a@." (or_not_found (array offset)) offsets ;; ocaml-ocaml-re-5586c57/lib_test/expect/test_bit_vector.ml000066400000000000000000000010221467707551200234310ustar00rootroot00000000000000open! Import module Bit_vector = Re_private.Bit_vector let%expect_test "reset_zero" = let n = Bit_vector.create_zero 10 in let print () = Format.printf "%a@." Bit_vector.pp n in print (); [%expect {| (len 10) (bits "\000\000") |}]; Bit_vector.reset_zero n; print (); [%expect {| (len 10) (bits "\000\000") |}]; Bit_vector.set n 1 true; print (); [%expect {| (len 10) (bits "\002\000") |}]; Bit_vector.reset_zero n; print (); [%expect {| (len 10) (bits "\000\000") |}] ;; ocaml-ocaml-re-5586c57/lib_test/expect/test_category.ml000066400000000000000000000007121467707551200231130ustar00rootroot00000000000000module Category = Re_private.Category module Cset = Re_private.Cset let%expect_test "Category.from_char" = for i = 0 to 255 do let char = Char.chr i in let cat = Category.from_char char in if Cset.(mem (of_char char) cword) then assert (Category.(intersect letter cat)) done ;; let%expect_test "newline" = let cat = Category.from_char '\n' in assert (Category.(intersect cat newline)); assert (Category.(intersect cat not_letter)) ;; ocaml-ocaml-re-5586c57/lib_test/expect/test_csets.ml000066400000000000000000000070431467707551200224230ustar00rootroot00000000000000open! Import module Fmt = Re_private.Fmt module Cset = Re_private.Cset let%expect_test "empty" = Format.printf "%a@." Cset.pp Cset.empty; [%expect {| |}] ;; let%expect_test "ascii" = Format.printf "%a@." Cset.pp Cset.ascii; [%expect {| 0-127 |}] ;; let%expect_test "cdigit" = Format.printf "%a@." Cset.pp Cset.cdigit; [%expect {| 48-57 |}] ;; let%expect_test "calpha" = Format.printf "%a@." Cset.pp Cset.calpha; [%expect {| 65-90, 97-122, 170, 181, 186, 192-214, 216-246, 248-255 |}] ;; let%expect_test "cword" = Format.printf "%a@." Cset.pp Cset.cword; [%expect {| 48-57, 65-90, 95, 97-122, 170, 181, 186, 192-214, 216-246, 248-255 |}] ;; let%expect_test "notnl" = Format.printf "%a@." Cset.pp Cset.notnl; [%expect {| 0-9, 11-255 |}] ;; let%expect_test "nl" = Format.printf "%a@." Cset.pp Cset.nl; [%expect {| 10 |}] ;; let%expect_test "blank" = Format.printf "%a@." Cset.pp Cset.nl; [%expect {| 10 |}] ;; let%expect_test "space" = Format.printf "%a@." Cset.pp Cset.space; [%expect {| 9-13, 32 |}] ;; let%expect_test "xdigit" = Format.printf "%a@." Cset.pp Cset.xdigit; [%expect {| 48-57, 65-70, 97-102 |}] ;; let%expect_test "lower" = Format.printf "%a@." Cset.pp Cset.lower; [%expect {| 97-122, 181, 223-246, 248-255 |}] ;; let%expect_test "upper" = Format.printf "%a@." Cset.pp Cset.upper; [%expect {| 65-90, 192-214, 216-222 |}] ;; let%expect_test "alpha" = Format.printf "%a@." Cset.pp Cset.alpha; [%expect {| 65-90, 97-122, 170, 181, 186, 192-214, 216-246, 248-255 |}] ;; let%expect_test "alnum" = Format.printf "%a@." Cset.pp Cset.alnum; [%expect {| 48-57, 65-90, 97-122, 170, 181, 186, 192-214, 216-246, 248-255 |}] ;; let%expect_test "wordc" = Format.printf "%a@." Cset.pp Cset.wordc; [%expect {| 48-57, 65-90, 95, 97-122, 170, 181, 186, 192-214, 216-246, 248-255 |}] ;; let%expect_test "cntrl" = Format.printf "%a@." Cset.pp Cset.cntrl; [%expect {| 0-31, 127-159 |}] ;; let%expect_test "graph" = Format.printf "%a@." Cset.pp Cset.graph; [%expect {| 33-126, 160-255 |}] ;; let%expect_test "print" = Format.printf "%a@." Cset.pp Cset.print; [%expect {| 32-126, 160-255 |}] ;; let%expect_test "punct" = Format.printf "%a@." Cset.pp Cset.punct; [%expect {| 33-47, 58-64, 91-96, 123-126, 160-169, 171-180, 182-185, 187-191, 215, 247 |}] ;; let%expect_test "cany" = Format.printf "%a@." Cset.pp Cset.cany; [%expect {| 0-255 |}] ;; let%expect_test "case_insens" = let cset = Cset.diff (Cset.case_insens Cset.lower) (Cset.case_insens Cset.upper) in Format.printf "%a@." Cset.pp cset; [%expect {| 181, 223, 255 |}] ;; let%expect_test "one_char" = let test set = let pp fmt c = let c = Option.map Cset.to_char c in Fmt.(opt char) fmt c in Format.printf "%a@." pp (Cset.one_char set) in test Cset.empty; [%expect {| |}]; test (Cset.csingle 'c'); [%expect {| c |}]; test Cset.cany; [%expect {| |}] ;; let%expect_test "is_empty" = let test set = Format.printf "%a@." Fmt.bool (Cset.is_empty set) in test Cset.empty; [%expect {| true |}]; test (Cset.csingle 'c'); [%expect {| false |}]; test Cset.cany; [%expect {| false |}] ;; let%expect_test "Cset mem" = let test set c = Format.printf "%a@." Fmt.bool (Cset.mem c set) in test Cset.cany Cset.null_char; [%expect {| false |}]; test Cset.cany (Cset.of_char 'a'); [%expect {| true |}]; let c = Cset.csingle 'c' in test c (Cset.of_char 'c'); [%expect {| true |}]; test c (Cset.of_char '.'); [%expect {| false |}] ;; ocaml-ocaml-re-5586c57/lib_test/expect/test_emacs.ml000066400000000000000000000060321467707551200223670ustar00rootroot00000000000000open Import (* * Tests based on description of emacs regular expressions given at * http://www.gnu.org/manual/elisp-manual-20-2.5/html_chapter/elisp_34.html *) let re re = Format.printf "%a@." Re.pp (Re.Emacs.re re) let%expect_test "not supported" = let re s = try ignore (Re.Emacs.re s) with | Re.Emacs.Parse_error -> print_endline "Parse error" | Re.Emacs.Not_supported -> print_endline "Not supported" in re "*ab"; [%expect {| Parse error |}]; re "+ab"; [%expect {| Parse error |}]; re "?ab"; [%expect {| Parse error |}]; re "\\0"; [%expect {| Not supported |}] ;; let%expect_test "escaping special characters" = re "\\."; [%expect {| (Set 46) |}]; re "\\*"; [%expect {| (Set 42) |}]; re "\\+"; [%expect {| (Set 43) |}]; re "\\?"; [%expect {| (Set 63) |}]; re "\\["; [%expect {| (Set 91) |}]; re "\\]"; [%expect {| (Set 93) |}]; re "\\^"; [%expect {| (Set 94) |}]; re "\\$"; [%expect {| (Set 36) |}]; re "\\\\"; [%expect {| (Set 92) |}] ;; let%expect_test "special characeters" = re "."; [%expect {| (Set 0-9, 11-255) |}]; re "a*"; [%expect {| (Repeat (Set 97) 0) |}]; re "a+"; [%expect {| (Repeat (Set 97) 1) |}]; re "a?"; [%expect {| (Repeat (Set 97) 0 1) |}]; re "[ab]"; [%expect {| (Alternative (Set 98)(Set 97)) |}]; re "[a-z]"; [%expect {| (Set 97-122) |}]; re "[a-z$%.]"; [%expect {| (Alternative (Set 46)(Set 37)(Set 36)(Set 97-122)) |}]; re "[]a]"; [%expect {| (Alternative (Set 97)(Set 93)) |}]; re "[]-]"; [%expect {| (Alternative (Set 93)(Set 45)) |}]; re "[a^]"; [%expect {| (Alternative (Set 94)(Set 97)) |}]; re "[^a-z]"; [%expect {| (Complement (Set 97-122)) |}]; re "[^a-z$]"; [%expect {| (Complement (Set 36)(Set 97-122)) |}]; re "^"; [%expect {| Beg_of_line |}]; re "$"; [%expect {| End_of_line |}] ;; let%expect_test "alternatives" = re "a\\|b"; [%expect {| (Alternative (Set 97)(Set 98)) |}]; re "aa\\|bb"; [%expect {| (Alternative (Sequence (Set 97)(Set 97))(Sequence (Set 98)(Set 98))) |}] ;; let%expect_test "contexts" = re "\\`"; [%expect {| Beg_of_str |}]; re "\\'"; [%expect {| End_of_str |}]; re "\\="; [%expect {| Start |}]; re "\\b"; [%expect {| (Alternative Beg_of_wordEnd_of_word) |}]; re "\\B"; [%expect {| Not_bound |}]; re "\\<"; [%expect {| Beg_of_word |}]; re "\\>"; [%expect {| End_of_word |}] ;; let%expect_test "word-constituent" = re "\\w"; [%expect {| (Alternative (Set 48-57, 65-90, 97-122, 170, 181, 186, 192-214, 216-246, 248-255) (Set 95)) |}]; re "\\W"; [%expect {| (Complement (Set 48-57, 65-90, 97-122, 170, 181, 186, 192-214, 216-246, 248-255) (Set 95)) |}] ;; let%expect_test "grouping" = re "\\(a\\)"; [%expect {| (Group (Set 97)) |}]; re "\\(a\\|b\\)c"; [%expect {| (Sequence (Group (Alternative (Set 97)(Set 98)))(Set 99)) |}] ;; let%expect_test "concatenation" = re "ab"; [%expect {| (Sequence (Set 97)(Set 98)) |}] ;; let%expect_test "ordinary characters" = re "a"; [%expect {| (Set 97) |}] ;; ocaml-ocaml-re-5586c57/lib_test/expect/test_glob.ml000066400000000000000000000160211467707551200222210ustar00rootroot00000000000000open Import let glob ?match_backslashes ?expand_braces ?anchored ?pathname ?period re s = let re = Re.Glob.glob ?match_backslashes ?expand_braces ?anchored ?pathname ?period re |> Re.compile in Format.printf "%b@." (Re.execp re s) ;; let%expect_test "glob" = glob "foo*" "foobar"; [%expect {| true |}]; glob "fo?bar" "fobar"; [%expect {| false |}]; glob "fo?bar" "foobar"; [%expect {| true |}]; glob "fo?bar" "foo0bar"; [%expect {| false |}]; glob "?oobar" "foobar"; [%expect {| true |}]; glob "*bar" "foobar"; [%expect {| true |}]; glob "\\*bar" "foobar"; [%expect {| false |}]; glob "\\*bar" "*bar"; [%expect {| true |}]; glob "[ab]foo" "afoo"; [%expect {| true |}]; glob "[ab]foo" "bfoo"; [%expect {| true |}]; glob "[ab]foo" "cfoo"; [%expect {| false |}]; glob "c[ab]foo" "cabfoo"; [%expect {| false |}]; glob ".foo" ".foo"; [%expect {| true |}]; glob ".foo" "afoo"; [%expect {| false |}]; glob "*[.]foo" "a.foo"; [%expect {| true |}]; glob "*[.]foo" "ba.foo"; [%expect {| true |}]; glob "*.foo" ".foo"; [%expect {| false |}]; glob "*[.]foo" ".foo"; [%expect {| false |}]; glob ~anchored:true "*/foo" "/foo"; [%expect {| true |}]; glob ~anchored:true "foo/*" "foo/"; [%expect {| true |}]; glob "/[^f]" "/foo"; [%expect {| false |}]; glob "/[^f]" "/bar"; [%expect {| true |}]; glob ~anchored:true "/[^f]" "/bar"; [%expect {| false |}]; glob ~anchored:true "*" ".bar"; [%expect {| false |}]; glob "foo[.]bar" "foo.bar"; [%expect {| true |}]; glob "[.]foo" ".foo"; [%expect {| false |}]; glob "foo[/]bar" "foo/bar"; [%expect {| false |}]; glob ~anchored:true "*bar" "foobar"; [%expect {| true |}]; glob "foo" "foobar"; [%expect {| true |}]; glob "bar" "foobar"; [%expect {| true |}]; glob ~anchored:true "foo" "foobar"; [%expect {| false |}]; glob ~anchored:true "bar" "foobar"; [%expect {| false |}]; glob "{foo,bar}bar" "foobar"; [%expect {| false |}]; glob "{foo,bar}bar" "{foo,bar}bar"; [%expect {| true |}]; glob "foo?bar" "foo/bar"; [%expect {| false |}]; let pathname = true in let period = true in glob ~pathname ~period "?oobar" ".oobar"; [%expect {| false |}]; glob ~pathname ~period "?oobar" "/oobar"; [%expect {| false |}]; glob ~pathname ~period "f?obar" "f/obar"; [%expect {| false |}]; glob ~pathname ~period "f?obar" "f.obar"; [%expect {| true |}]; glob ~pathname ~period "f*.bar" "f.bar"; [%expect {| true |}]; glob ~pathname ~period "f?.bar" "fo.bar"; [%expect {| true |}]; glob ~pathname ~period "/.bar" "/.bar"; [%expect {| true |}]; glob ~pathname ~period "*.bar" ".bar"; [%expect {| false |}]; glob ~pathname ~period "?" "."; [%expect {| false |}]; glob ~pathname ~period "/*bar" "/.bar"; [%expect {| false |}]; glob "?oobar" ".oobar"; [%expect {| false |}]; glob "?oobar" "/oobar"; [%expect {| false |}]; let pathname = true in let period = false in glob ~pathname ~period "?oobar" "/oobar"; [%expect {| false |}]; glob ~pathname ~period "?oobar" ".oobar"; [%expect {| true |}]; glob ~pathname ~period "f?obar" "f/obar"; [%expect {| false |}]; glob ~pathname ~period "f?obar" "f.obar"; [%expect {| true |}]; let pathname = false in let period = false in glob ~pathname ~period "?oobar" ".oobar"; [%expect {| true |}]; glob ~pathname ~period "?oobar" "/oobar"; [%expect {| true |}]; glob ~expand_braces:true "{foo,far}bar" "foobar"; [%expect {| true |}]; glob ~expand_braces:true "{foo,far}bar" "farbar"; [%expect {| true |}]; glob ~expand_braces:true "{foo,far}bar" "{foo,far}bar"; [%expect {| false |}] ;; let%expect_test "double asterisk" = let glob = glob ~anchored:true in glob "**" "foobar"; [%expect {| true |}]; glob "**" "foo/bar"; [%expect {| true |}]; glob "**/bar" "foo/bar"; [%expect {| true |}]; glob "**/bar" "foo/far/bar"; [%expect {| true |}]; glob "foo/**" "foo"; [%expect {| false |}]; glob "foo/**" "foo/bar"; [%expect {| true |}]; glob "foo/**" "foo/far/bar"; [%expect {| true |}]; glob "foo/**/bar" "foo/far/bar"; [%expect {| true |}]; glob "foo/**/bar" "foo/far/oof/bar"; [%expect {| true |}]; glob "foo/**bar" "foo/far/oofbar"; [%expect {| true |}]; glob "foo/**bar" "foo/bar"; [%expect {| true |}]; glob "foo/**bar" "foo/foobar"; [%expect {| true |}]; glob "/**" "//foo"; [%expect {| true |}]; glob "/**" "/"; [%expect {| true |}]; glob "/**" "/x"; [%expect {| true |}]; glob "**" "foo//bar"; [%expect {| true |}]; glob "foo/bar/**/*.ml" "foo/bar/baz/foobar.ml"; [%expect {| true |}]; glob "foo/bar/**/*.ml" "foo/bar/foobar.ml"; [%expect {| true |}]; glob "foo/**/bar/**/baz" "foo/bar/baz"; [%expect {| true |}]; glob "foo/**/bar/**/baz" "foo/bar/x/y/z/baz"; [%expect {| true |}]; glob "foo/**/bar/**/baz" "foo/x/y/z/bar/baz"; [%expect {| true |}]; glob "foo/**/bar/**/baz" "foo/bar/x/bar/x/baz"; [%expect {| true |}]; glob "foo/**/bar/**/baz" "foo/bar/../x/baz"; [%expect {| false |}]; glob "foo/**/bar/**/baz" "foo/bar/./x/baz"; [%expect {| false |}]; ((* Interaction with [~period] *) let glob = glob ~period:true in glob "**" ".foobar"; [%expect {| false |}]; glob "**" ".foo/bar"; [%expect {| false |}]; glob "foo/**" "foo/.bar"; [%expect {| false |}]; glob "**" "foo/.bar/bat"; [%expect {| false |}]; glob "foo/**/bat" "foo/.bar/bat"; [%expect {| false |}]; glob "/**/bat" "/foo/.bar/bat"; [%expect {| false |}]; glob "/**/bat" "/.bar/bat"; [%expect {| false |}]; glob "/**bat" "/bar/.bat"; [%expect {| false |}]; glob ".**" ".foobar"; [%expect {| true |}]; glob ".**" ".foo/bar"; [%expect {| true |}]; glob "foo/.**" "foo/.bar"; [%expect {| true |}]); let glob = glob ~period:false in glob "**" ".foobar"; [%expect {| true |}]; glob "**" ".foo/bar"; [%expect {| true |}]; glob "foo/**" "foo/.bar"; [%expect {| true |}]; glob "**" "foo/.bar/bat"; [%expect {| true |}]; glob "foo/**/bat" "foo/.bar/bat"; [%expect {| true |}]; glob "/**/bat" "/foo/.bar/bat"; [%expect {| true |}]; glob "/**/bat" "/.bar/bat"; [%expect {| true |}]; glob "/**bat" "/bar/.bat"; [%expect {| true |}] ;; let%expect_test "backslash handling" = let anchored = true in let glob = glob ~anchored in (let glob = glob ~match_backslashes:false in glob "a/b/c" "a\\b/c"; [%expect {| false |}]; glob "a\\b" "ab"; [%expect {| true |}]; glob "a/*.ml" "a/b\\c.ml"; [%expect {| true |}]; glob "a/b/*.ml" "a\\b\\c.ml"; [%expect {| false |}]; glob "/" "\\"; [%expect {| false |}]; glob "/?" "\\a"; [%expect {| false |}]; glob "a/**.ml" "a\\c\\.b.ml"; [%expect {| true |}]); let glob = glob ~match_backslashes:true in glob "a/b/c" "a\\b/c"; [%expect {| true |}]; glob "a\\b" "ab"; [%expect {| true |}]; glob "a/*.ml" "a/b\\c.ml"; [%expect {| false |}]; glob "a/b/*.ml" "a\\b\\c.ml"; [%expect {| true |}]; glob "/" "\\"; [%expect {| true |}]; glob "/?" "\\a"; [%expect {| true |}]; glob "a/**.ml" "a\\c\\.b.ml"; [%expect {| false |}] ;; ocaml-ocaml-re-5586c57/lib_test/expect/test_group.ml000066400000000000000000000071161467707551200224370ustar00rootroot00000000000000open Import open Re let%expect_test "empty group" = let empty = group empty in t empty ""; [%expect {| |}]; t empty "x"; [%expect {| |}] ;; let%expect_test "zero length group" = let empty = group bos in t empty ""; [%expect {| (Group ( (0 0))( (0 0))) |}]; t empty "x"; [%expect {| (Group ( (0 0))( (0 0))) |}] ;; let%expect_test "no group" = let re = any in t re ""; [%expect {| |}]; t re "."; [%expect {| (Group (. (0 1))) |}] ;; let%expect_test "two groups" = let re = seq [ group any; group any ] in t re "a"; [%expect {| |}]; t re "ab"; [%expect {| (Group (ab (0 2))(a (0 1))(b (1 2))) |}]; t re "abc"; [%expect {| (Group (ab (0 2))(a (0 1))(b (1 2))) |}] ;; let%expect_test "maybe group" = let twoany = seq [ any; any ] in let re = alt [ twoany; group twoany ] in t re "aa"; [%expect {| (Group (aa (0 2))( (-1 -1))) |}]; t re "a"; [%expect {| |}] ;; let%expect_test "nesting of groups" = let re = group (seq [ group (char 'a'); char 'b' ]) in t re "ab"; [%expect {| (Group (ab (0 2))(ab (0 2))(a (0 1))) |}] ;; let%expect_test "group choice" = let t = Import.exec_partial_detailed in (* Alternation of character sets isn't flattened *) let lhs_group = let open Re in alt [ group (char 'a'); char 'b' ] in t lhs_group "a"; [%expect {| `Full [|0,1,"a";0,1,"a"|] |}]; t lhs_group "b"; [%expect {| `Full [|0,1,"b";-1,-1,|] |}]; t (let open Re in alt [ group (char 'a'); group (char 'b') ]) "b"; [%expect {| `Full [|0,1,"b";-1,-1,;0,1,"b"|] |}]; (* No_group inside char set: *) let no_group_charset = let a = Re.group (Re.char 'a') in let b = Re.char 'b' in Re.no_group (Re.alt [ a; b ]) in t no_group_charset "a"; [%expect {| `Full [|0,1,"a"|] |}]; t no_group_charset "b"; [%expect {| `Full [|0,1,"b"|] |}]; (* No_group outside char set *) let no_group_string = let aa = Re.group (Re.str "aa") in let bb = Re.str "bb" in Re.no_group (Re.alt [ aa; bb ]) in t no_group_string "aa"; [%expect {| `Full [|0,2,"aa"|] |}]; t no_group_string "bb"; [%expect {| `Full [|0,2,"bb"|] |}] ;; let%expect_test "Group.{get,get_opt,offset,test}" = let r = seq [ group (char 'a'); opt (group (char 'a')); group (char 'b') ] in let m = exec (compile r) "ab" in let test idx = Format.printf "get_opt = %a@." (Fmt.opt Fmt.str) (Group.get_opt m idx); Format.printf "get = %a@." (or_not_found Fmt.str) (fun () -> Group.get m idx); Format.printf "test = %b@." (Group.test m idx); Format.printf "offset = %a@." (or_not_found offset) (fun () -> Group.offset m idx) in test 0; [%expect {| get_opt = ab get = ab test = true offset = (0, 2) |}]; test 1; [%expect {| get_opt = a get = a test = true offset = (0, 1) |}]; test 2; [%expect {| get_opt = get = Not_found test = false offset = Not_found |}]; test 3; [%expect {| get_opt = b get = b test = true offset = (1, 2) |}]; Format.printf "%a@." (array offset) (Group.all_offset m); [%expect {| [| (0, 2); (0, 1); (-1, -1); (1, 2) |] |}] ;; let%expect_test "nest" = let r = rep (nest (alt [ group (char 'a'); char 'b' ])) in test_re r "ab"; [%expect {| [| (0, 2); (-1, -1) |] |}]; test_re r "ba"; [%expect {| [| (0, 2); (1, 2) |] |}] ;; let%expect_test "group/no_group" = let r = seq [ group (char 'a'); opt (group (char 'a')); group (char 'b') ] in test_re r "ab"; [%expect {| [| (0, 2); (0, 1); (-1, -1); (1, 2) |] |}]; test_re (no_group r) "ab"; [%expect {| [| (0, 2) |] |}] ;; ocaml-ocaml-re-5586c57/lib_test/expect/test_hashset.ml000066400000000000000000000021701467707551200227350ustar00rootroot00000000000000open Import let () = Printexc.record_backtrace true module Hash_set = Re_private.Hash_set let id1 = 1 let id2 = 2 let id3 = 3 let test table f = if f table then print_endline "[PASS]" else ( print_endline "[FAIL]"; Format.printf "%a@." Hash_set.pp table) ;; let%expect_test "basic set" = let set = Hash_set.create () in test set Hash_set.is_empty; [%expect {| [PASS] |}]; test set (fun set -> not (Hash_set.mem set id1)); [%expect {| [PASS] |}] ;; let%expect_test "add 1 element" = let set = Hash_set.create () in Hash_set.add set id1; test set (fun set -> not (Hash_set.is_empty set)); [%expect {| [PASS] |}]; test set (fun set -> Hash_set.mem set id1); [%expect {| [PASS] |}]; Hash_set.add set id1; test set (fun set -> Hash_set.mem set id1); [%expect {| [PASS] |}]; Hash_set.add set id2; test set (fun set -> Hash_set.mem set id2); [%expect {| [PASS] |}]; Hash_set.add set id3; test set (fun set -> Hash_set.mem set id3); [%expect {| [PASS] |}]; test set (fun set -> List.for_all [ id1; id2; id3 ] ~f:(fun id -> Hash_set.mem set id)); [%expect {| [PASS] |}] ;; ocaml-ocaml-re-5586c57/lib_test/expect/test_iter.ml000066400000000000000000000006551467707551200222470ustar00rootroot00000000000000open Import let%expect_test "iter" = let re = Re.Posix.compile_pat "(ab)+" in strings (Re.matches re "aabab aaabba dab "); [%expect {| ["abab"; "ab"; "ab"] |}]; strings (Re.matches ~pos:2 ~len:7 re "abab ababab"); [%expect {| ["ab"; "abab"] |}]; strings (Re.matches re_empty "ab"); [%expect {| [""; ""; ""] |}]; strings (Re.matches (Re.compile (Re.rep (Re.char 'a'))) "cat"); [%expect {| [""; "a"; ""] |}] ;; ocaml-ocaml-re-5586c57/lib_test/expect/test_mark.ml000066400000000000000000000022031467707551200222250ustar00rootroot00000000000000open Import open Re let test_mark ?pos ?len r s il1 il2 = let subs = exec ?pos ?len (compile r) s in Format.printf "%b@." (List.for_all ~f:(Mark.test subs) il1 && List.for_all ~f:(fun x -> not (Mark.test subs x)) il2) ;; let%expect_test "mark" = let i, r = mark digit in test_mark r "0" [ i ] []; [%expect {| true |}] ;; let%expect_test "mark seq" = let i, r = mark digit in let r = seq [ r; r ] in test_mark r "02" [ i ] []; [%expect {| true |}] ;; let%expect_test "mark rep" = let i, r = mark digit in let r = rep r in test_mark r "02" [ i ] []; [%expect {| true |}] ;; let%expect_test "mark alt" = let ia, ra = mark (char 'a') in let ib, rb = mark (char 'b') in let r = alt [ ra; rb ] in test_mark r "a" [ ia ] [ ib ]; test_mark r "b" [ ib ] [ ia ]; [%expect {| true true |}]; let r = rep r in test_mark r "ab" [ ia; ib ] []; [%expect {| true |}] ;; let%expect_test "mark prefers lhs" = let two_chars = seq [ any; any ] in let lhs, x = mark two_chars in let rhs, x' = mark two_chars in let r = alt [ x; x' ] in test_mark r "aa" [ lhs ] [ rhs ]; [%expect {| true |}] ;; ocaml-ocaml-re-5586c57/lib_test/expect/test_partial.ml000066400000000000000000000041761467707551200227420ustar00rootroot00000000000000open Import let t re s = let re = Re.compile re in let res = Re.exec_partial re s in Format.printf "`%s@." (match res with | `Partial -> "Partial" | `Full -> "Full" | `Mismatch -> "Mismatch") ;; let%expect_test "partial matches" = let open Re in t (str "hello") "he"; [%expect {| `Partial |}]; t (str "hello") "goodbye"; [%expect {| `Partial |}]; (* exec_partial 3 should be `Full *) t (str "hello") "hello"; [%expect {| `Partial |}]; t (whole_string (str "hello")) "hello"; [%expect {| `Partial |}]; t (whole_string (str "hello")) "goodbye"; [%expect {| `Mismatch |}]; t (str "hello") ""; [%expect {| `Partial |}]; t (str "") "hello"; [%expect {| `Full |}]; t (whole_string (str "hello")) ""; [%expect {| `Partial |}] ;; let t = exec_partial_detailed let%expect_test "partial detailed" = let open Re in t (str "hello") "he"; [%expect {| `Partial 0 |}]; (* Because of how the matching engine currently works, situations where the entirety of the input string cannot be a match like the test below actually return the last character as a potential start instead of just return `Partial (String.length input). This is still fine however as it still respects the mli contract, as no match could start before the given position, and is fine in practice as testing an extra character on extra input doesn't add much more in terms of workload. *) t (str "hello") "goodbye"; [%expect {| `Partial 6 |}]; t (str "hello") "hello"; [%expect {| `Full [|0,5,"hello"|] |}]; t (whole_string (str "hello")) "hello"; [%expect {| `Full [|0,5,"hello"|] |}]; t (whole_string (str "hello")) "goodbye"; [%expect {| `Mismatch |}]; t (str "hello") ""; [%expect {| `Partial 0 |}]; t (str "") "hello"; [%expect {| `Full [|0,0,""|] |}]; t (whole_string (str "hello")) ""; [%expect {| `Partial 0 |}]; t (str "abc") ".ab.ab"; [%expect {| `Partial 4 |}]; t ~pos:1 (seq [ not_boundary; str "b" ]) "ab"; [%expect {| `Full [|1,2,"b"|] |}]; t (seq [ group (str "a"); rep any; group (str "b") ]) ".acb."; [%expect {| `Full [|1,4,"acb";1,2,"a";3,4,"b"|] |}] ;; ocaml-ocaml-re-5586c57/lib_test/expect/test_pcre.ml000066400000000000000000000046731467707551200222410ustar00rootroot00000000000000open Import module Pcre = Re_private.Pcre let test re s = match Pcre.re re with | exception _ -> Format.printf "failed to parse@." | re -> t re s ;; let%expect_test "quoted strings" = test {|\Qfoo\E|} "foo"; [%expect {| (Group (foo (0 3))) |}]; test {|\Qbar|} ""; [%expect {| failed to parse |}]; test {|\Qbaz\|} ""; [%expect {| failed to parse |}]; test {|\Qba\Xz\E|} {|ba\Xz|}; [%expect {| (Group (ba\Xz (0 5))) |}] ;; let%expect_test "octal" = test {|\025|} (String.make 1 '\o025'); [%expect {| (Group ( (0 1))) |}]; test {|\999|} ""; [%expect {| failed to parse |}]; test {|\111|} (String.make 1 '\o111'); [%expect {| (Group (I (0 1))) |}] ;; let%expect_test "\\x and \\o form" = test {|\o{111}|} (String.make 1 '\o111'); [%expect {| |}]; test {|\o{111|} ""; [%expect {| failed to parse |}]; test {|\x{ff}|} (String.make 1 '\xff'); [%expect {| (Group (ÿ (0 1))) |}]; test {|\x{ff|} ""; [%expect {| failed to parse |}] ;; let%expect_test "substitute" = let open Pcre in let substitute ~rex ~subst s = substitute ~rex ~subst s |> print_endline in let rex = regexp "[a-zA-Z]+" in let subst = String.capitalize_ascii in substitute ~rex ~subst " hello world; I love chips!"; [%expect {| Hello World; I Love Chips! |}]; substitute ~rex:re_empty ~subst:(fun _ -> "a") ""; [%expect {| a |}]; substitute ~rex:(regexp "a*") ~subst:(fun _ -> "*") "cat"; [%expect {| *c*t* |}]; let rex = regexp "^ *" in substitute ~rex ~subst:(fun _ -> "A ") "test"; [%expect {| A test |}] ;; let%expect_test "test_blank_class" = let re = Re.Perl.compile_pat "\\d[[:blank:]]\\d[[:blank:]]+[a-z]" in let successes = [ "1 2 a"; "2\t3 z"; "9\t0 \t a" ] in let failures = [ ""; "123"; " "; "1 3z" ] in List.iter successes ~f:(fun s -> printf "String %S should match %b\n" s (Re.execp re s)); [%expect {| String "1 2 a" should match true String "2\t3 z" should match true String "9\t0 \t a" should match true |}]; List.iter failures ~f:(fun s -> printf "String %S should not match %b\n" s (Re.execp re s)); [%expect {| String "" should not match false String "123" should not match false String " " should not match false String "1 3z" should not match false |}] ;; let%expect_test "named groups" = let open Pcre in let rex = regexp "(?x+)" in let s = exec ~rex "testxxxyyy" in print_endline (get_named_substring rex "many_x" s); [%expect {| xxx |}] ;; ocaml-ocaml-re-5586c57/lib_test/expect/test_pcre_288.ml000066400000000000000000000004431467707551200226310ustar00rootroot00000000000000open Import module Pcre = Re_private.Pcre let whitespace_re = Pcre.regexp "\\s+" let%expect_test "split1" = strings (Pcre.split ~rex:whitespace_re ""); [%expect {| [""] |}] ;; let%expect_test "split2" = strings (Pcre.split ~rex:whitespace_re " "); [%expect {| [""; ""] |}] ;; ocaml-ocaml-re-5586c57/lib_test/expect/test_pcre_split.ml000066400000000000000000000030111467707551200234350ustar00rootroot00000000000000open Import let split ~rex s = Re.Pcre.split ~rex s |> strings let%expect_test "split" = split ~rex:re_whitespace "aa bb c d "; [%expect {| ["aa"; "bb"; "c"; "d"; ""] |}]; split ~rex:re_whitespace " a full_word bc "; [%expect {| [""; "a"; "full_word"; "bc"; ""] |}]; split ~rex:re_empty "abcd"; [%expect {| [""; "a"; "b"; "c"; "d"; ""] |}]; split ~rex:re_eol "a\nb"; [%expect {| ["a"; "\nb"; ""] |}]; split ~rex:re_bow "a b"; [%expect {| [""; "a "; "b"] |}]; split ~rex:re_eow "a b"; [%expect {| ["a"; " b"; ""] |}]; let rex = Re.Pcre.regexp "" in split ~rex "xx"; [%expect {| [""; "x"; "x"; ""] |}] ;; let full_split ?max ~rex s = let res = Re.Pcre.full_split ?max ~rex s in Format.printf "[%a]@." Fmt.( list ~pp_sep:(Fmt.lit "; ") (fun fmt what -> match (what : Re.Pcre.split_result) with | Text s -> Format.fprintf fmt "Text %S" s | Delim s -> Format.fprintf fmt "Delim %S" s | NoGroup -> Format.fprintf fmt "NoGroup" | Group (x, s) -> Format.fprintf fmt "Group (%d, %S)" x s)) res ;; let%expect_test "full split" = (let full_split = full_split ~rex:(Re.Pcre.regexp "x(x)?") in full_split "testxxyyy"; [%expect {| [Text "test"; Delim "xx"; Group (1, "x"); Text "yyy"] |}]; full_split "testxyyy"; [%expect {| [Text "test"; Delim "x"; NoGroup; Text "yyy"] |}]); let full_split = full_split ~rex:(Re.Pcre.regexp "[:_]") in full_split ""; [%expect {| [] |}]; full_split ~max:1 "xxx:yyy"; [%expect {| [Text "xxx:yyy"] |}] ;; ocaml-ocaml-re-5586c57/lib_test/expect/test_perl.ml000066400000000000000000000130651467707551200222450ustar00rootroot00000000000000open Import (* Tests based on description of Perl regular expressions given at http://www.perl.com/CPAN-local/doc/manual/html/pod/perlre.html *) let re ?opts s = Format.printf "%a@." Re.pp (Re.Perl.re ?opts s) let try_parse ?opts s = try ignore (Re.Perl.re ?opts s); print_endline "Prased successfully" with | Re.Perl.Parse_error -> print_endline "Parse error" | Re.Perl.Not_supported -> print_endline "Not supported" ;; let%expect_test "escaping meta characters" = re "\\^"; [%expect {| (Set 94) |}]; re "\\."; [%expect {| (Set 46) |}]; re "\\$"; [%expect {| (Set 36) |}]; re "\\|"; [%expect {| (Set 124) |}]; re "\\("; [%expect {| (Set 40) |}]; re "\\)"; [%expect {| (Set 41) |}]; re "\\["; [%expect {| (Set 91) |}]; re "\\]"; [%expect {| (Set 93) |}]; re "\\*"; [%expect {| (Set 42) |}]; re "\\+"; [%expect {| (Set 43) |}]; re "\\?"; [%expect {| (Set 63) |}]; re "\\\\"; [%expect {| (Set 92) |}] ;; let%expect_test "basic metacharacters" = re "^"; [%expect {| Beg_of_str |}]; re "."; [%expect {| (Set 0-9, 11-255) |}]; re "$"; [%expect {| End_of_str |}]; re "a|b"; [%expect {| (Alternative (Set 97)(Set 98)) |}]; re "aa|bb"; [%expect {| (Alternative (Sequence (Set 97)(Set 97))(Sequence (Set 98)(Set 98))) |}]; re "(a)"; [%expect {| (Group (Set 97)) |}]; re "(a|b)c"; [%expect {| (Sequence (Group (Alternative (Set 97)(Set 98)))(Set 99)) |}]; re "[ab]"; [%expect {| (Alternative (Set 98)(Set 97)) |}]; re "[a-z]"; [%expect {| (Set 97-122) |}]; re "[a-z$%.]"; [%expect {| (Alternative (Set 46)(Set 37)(Set 36)(Set 97-122)) |}]; re "[-az]"; [%expect {| (Alternative (Set 122)(Set 97)(Set 45)) |}]; re "[az-]"; [%expect {| (Alternative (Set 122)(Set 45)(Set 97)) |}]; re "[a\\-z]"; [%expect {| (Alternative (Set 122)(Set 45)(Set 97)) |}]; re "[]a]"; [%expect {| (Alternative (Set 97)(Set 93)) |}]; re "[]-]"; [%expect {| (Alternative (Set 93)(Set 45)) |}]; re "[a^]"; [%expect {| (Alternative (Set 94)(Set 97)) |}]; re "[^a-z]"; [%expect {| (Complement (Set 97-122)) |}]; re "[^a-z$]"; [%expect {| (Complement (Set 36)(Set 97-122)) |}]; re "[a-\\sz]"; [%expect {| (Alternative (Set 122)(Set 97)(Set 45)(Set 9-13, 32)) |}] ;; let%expect_test "greedy quantifiers" = re "a*"; [%expect {| (Sem_greedy Greedy (Repeat (Set 97) 0)) |}]; re "a+"; [%expect {| (Sem_greedy Greedy (Repeat (Set 97) 1)) |}]; re "a?"; [%expect {| (Sem_greedy Greedy (Repeat (Set 97) 0 1)) |}]; re "a{10}"; [%expect {| (Sem_greedy Greedy (Repeat (Set 97) 10 10)) |}]; re "a{10,}"; [%expect {| (Sem_greedy Greedy (Repeat (Set 97) 10)) |}]; re "a{10,12}"; [%expect {| (Sem_greedy Greedy (Repeat (Set 97) 10 12)) |}] ;; let%expect_test "non-greedy quantifiers" = re "a*?"; [%expect {| (Sem_greedy Non_greedy (Repeat (Set 97) 0)) |}]; re "a+?"; [%expect {| (Sem_greedy Non_greedy (Repeat (Set 97) 1)) |}]; re "a??"; [%expect {| (Sem_greedy Non_greedy (Repeat (Set 97) 0 1)) |}]; re "a{10}?"; [%expect {| (Sem_greedy Non_greedy (Repeat (Set 97) 10 10)) |}]; re "a{10,}?"; [%expect {| (Sem_greedy Non_greedy (Repeat (Set 97) 10)) |}]; re "a{10,12}?"; [%expect {| (Sem_greedy Non_greedy (Repeat (Set 97) 10 12)) |}] ;; let%expect_test "character sets" = re "\\w"; [%expect {| (Alternative (Set 48-57, 65-90, 97-122, 170, 181, 186, 192-214, 216-246, 248-255) (Set 95)) |}]; re "\\W"; [%expect {| (Complement (Set 48-57, 65-90, 97-122, 170, 181, 186, 192-214, 216-246, 248-255) (Set 95)) |}]; re "\\s"; [%expect {| (Set 9-13, 32) |}]; re "\\S"; [%expect {| (Complement (Set 9-13, 32)) |}]; re "\\d"; [%expect {| (Set 48-57) |}]; re "\\D"; [%expect {| (Complement (Set 48-57)) |}] ;; let%expect_test "zero-width assertions" = re "\\b"; [%expect {| (Alternative Beg_of_wordEnd_of_word) |}]; re "\\B"; [%expect {| Not_bound |}]; re "\\A"; [%expect {| Beg_of_str |}]; re "\\Z"; [%expect {| Last_end_of_line |}]; re "\\z"; [%expect {| End_of_str |}]; re "\\G"; [%expect {| Start |}] ;; let%expect_test "options" = re ~opts:[ `Anchored ] "a"; [%expect {| (Sequence Start(Set 97)) |}]; re ~opts:[ `Caseless ] "b"; [%expect {| (No_case (Set 98)) |}]; re ~opts:[ `Dollar_endonly ] "$"; [%expect {| Last_end_of_line |}]; re ~opts:[ `Dollar_endonly; `Multiline ] "$"; [%expect {| End_of_line |}]; re ~opts:[ `Dotall ] "."; [%expect {| (Set 0-255) |}]; re ~opts:[ `Multiline ] "^"; [%expect {| Beg_of_line |}]; re ~opts:[ `Multiline ] "$"; [%expect {| End_of_line |}]; re ~opts:[ `Ungreedy ] "a*"; [%expect {| (Sem_greedy Non_greedy (Repeat (Set 97) 0)) |}]; re ~opts:[ `Ungreedy ] "a*?"; [%expect {| (Sem_greedy Greedy (Repeat (Set 97) 0)) |}] ;; let%expect_test "clustering" = re "(?:a)"; [%expect {| (Set 97) |}]; re "(?:a|b)c"; [%expect {| (Sequence (Alternative (Set 97)(Set 98))(Set 99)) |}] ;; let%expect_test "comment" = re "a(?#comment)b"; [%expect {| (Sequence (Set 97)(Sequence )(Set 98)) |}]; try_parse "(?#"; [%expect {| Parse error |}] ;; let%expect_test "backrefs" = try_parse "\\0"; [%expect {| Not supported |}] ;; let%expect_test "ordinary characters" = re "a"; [%expect {| (Set 97) |}] ;; let%expect_test "concacentation" = re "ab"; [%expect {| (Sequence (Set 97)(Set 98)) |}] ;; let%expect_test "sets in classes" = re "[a\\s]"; [%expect {| (Alternative (Set 9-13, 32)(Set 97)) |}] ;; let%expect_test "fixed bug" = (try ignore (Re.compile (Re.Perl.re "(.*?)(\\WPl|\\Bpl)(.*)")) with | _ -> failwith "bug in Re.handle_case"); [%expect {||}] ;; ocaml-ocaml-re-5586c57/lib_test/expect/test_posix.ml000066400000000000000000000003421467707551200224370ustar00rootroot00000000000000open Import let%expect_test "class space" = let re = Re.Posix.compile_pat {|a[[:space:]]b|} in let exec = Re.execp re in assert (exec "a b"); assert (not (exec "ab")); assert (not (exec "a_b")); [%expect {||}] ;; ocaml-ocaml-re-5586c57/lib_test/expect/test_re.ml000066400000000000000000000257301467707551200217130ustar00rootroot00000000000000open Import let%expect_test "fixed repetition" = let re = Re.compile @@ Re.(repn (char 'a') 3 (Some 3)) in let test s = printf "%b\n" (Re.execp re s) in test ""; [%expect {| false |}]; test "aa"; [%expect {| false |}]; test "aaa"; [%expect {| true |}]; test "aaaa"; [%expect {| true |}] ;; open Re let%expect_test "str" = test_re (str "a") "a"; [%expect {| [| (0, 1) |] |}]; test_re (str "a") "b"; [%expect {| Not_found |}] ;; let%expect_test "char" = test_re (alt [ char 'a'; char 'b' ]) "a"; [%expect {| [| (0, 1) |] |}]; test_re (alt [ char 'a'; char 'b' ]) "b"; [%expect {| [| (0, 1) |] |}]; test_re (alt [ char 'a'; char 'b' ]) "c"; [%expect {| Not_found |}] ;; let%expect_test "alt" = test_re (alt [ char 'a'; char 'b' ]) "a"; [%expect {| [| (0, 1) |] |}]; test_re (alt [ char 'a'; char 'b' ]) "b"; [%expect {| [| (0, 1) |] |}]; test_re (alt [ char 'a'; char 'b' ]) "c"; [%expect {| Not_found |}] ;; let%expect_test "seq" = test_re (seq [ char 'a'; char 'b' ]) "ab"; [%expect {| [| (0, 2) |] |}]; test_re (seq [ char 'a'; char 'b' ]) "ac"; [%expect {| Not_found |}] ;; let%expect_test "empty" = test_re empty ""; [%expect {| Not_found |}]; test_re empty "a"; [%expect {| Not_found |}] ;; let%expect_test "epsilon" = test_re epsilon ""; [%expect {| [| (0, 0) |] |}]; test_re epsilon "a"; [%expect {| [| (0, 0) |] |}] ;; let%expect_test "rep" = test_re (rep (char 'a')) ""; [%expect {| [| (0, 0) |] |}]; test_re (rep (char 'a')) "a"; [%expect {| [| (0, 1) |] |}]; test_re (rep (char 'a')) "aa"; [%expect {| [| (0, 2) |] |}]; test_re (rep (char 'a')) "b"; [%expect {| [| (0, 0) |] |}] ;; let%expect_test "rep1" = test_re (rep1 (char 'a')) "a"; [%expect {| [| (0, 1) |] |}]; test_re (rep1 (char 'a')) "aa"; [%expect {| [| (0, 2) |] |}]; test_re (rep1 (char 'a')) ""; [%expect {| Not_found |}]; test_re (rep1 (char 'a')) "b"; [%expect {| Not_found |}] ;; let%expect_test "repn" = let a = char 'a' in test_re (repn a 0 None) ""; [%expect {| [| (0, 0) |] |}]; test_re (repn a 2 None) "a"; [%expect {| Not_found |}]; test_re (repn a 2 None) "aa"; [%expect {| [| (0, 2) |] |}]; test_re (repn a 0 (Some 0)) ""; [%expect {| [| (0, 0) |] |}]; test_re (repn a 1 (Some 2)) "a"; [%expect {| [| (0, 1) |] |}]; test_re (repn a 1 (Some 2)) "aa"; [%expect {| [| (0, 2) |] |}]; test_re (repn a 1 (Some 2)) ""; [%expect {| Not_found |}]; test_re (repn a 1 (Some 2)) "aaa"; [%expect {| [| (0, 2) |] |}]; invalid_argument (fun () -> repn empty (-1) None); [%expect {| Invalid_argument "Re.repn" |}]; invalid_argument (fun () -> repn empty 1 (Some 0)); [%expect {| Invalid_argument "Re.repn" |}]; invalid_argument (fun () -> repn empty 4 (Some 3)); [%expect {| Invalid_argument "Re.repn" |}] ;; let%expect_test "opt" = test_re (opt (char 'a')) ""; [%expect {| [| (0, 0) |] |}]; test_re (opt (char 'a')) "a"; [%expect {| [| (0, 1) |] |}] ;; let%expect_test "bol" = test_re (seq [ bol; char 'a' ]) "ab"; [%expect {| [| (0, 1) |] |}]; test_re (seq [ bol; char 'a' ]) "b\na"; [%expect {| [| (2, 3) |] |}]; test_re (seq [ bol; char 'a' ]) "ba"; [%expect {| Not_found |}] ;; let%expect_test "eol" = test_re (seq [ char 'a'; eol ]) "ba"; [%expect {| [| (1, 2) |] |}]; test_re (seq [ char 'a'; eol ]) "a\nb"; [%expect {| [| (0, 1) |] |}]; test_re (seq [ char 'a'; eol ]) "ba\n"; [%expect {| [| (1, 2) |] |}]; test_re (seq [ char 'a'; eol ]) "ab"; [%expect {| Not_found |}] ;; let%expect_test "bow" = test_re (seq [ bow; char 'a' ]) "a"; [%expect {| [| (0, 1) |] |}]; test_re (seq [ bow; char 'a' ]) "bb aa"; [%expect {| [| (3, 4) |] |}]; test_re (seq [ bow; char 'a' ]) "ba ba"; [%expect {| Not_found |}]; test_re bow ";"; [%expect {| Not_found |}]; test_re bow ""; [%expect {| Not_found |}] ;; let%expect_test "eow" = test_re (seq [ char 'a'; eow ]) "a"; [%expect {| [| (0, 1) |] |}]; test_re (seq [ char 'a'; eow ]) "bb aa"; [%expect {| [| (4, 5) |] |}]; test_re (seq [ char 'a'; eow ]) "ab ab"; [%expect {| Not_found |}]; test_re eow ";"; [%expect {| Not_found |}]; test_re eow ""; [%expect {| Not_found |}] ;; let%expect_test "bos" = test_re (seq [ bos; char 'a' ]) "ab"; [%expect {| [| (0, 1) |] |}]; test_re (seq [ bos; char 'a' ]) "b\na"; [%expect {| Not_found |}]; test_re (seq [ bos; char 'a' ]) "ba"; [%expect {| Not_found |}] ;; let%expect_test "eos" = test_re (seq [ char 'a'; eos ]) "ba"; [%expect {| [| (1, 2) |] |}]; test_re (seq [ char 'a'; eos ]) "a\nb"; [%expect {| Not_found |}]; test_re (seq [ char 'a'; eos ]) "ba\n"; [%expect {| Not_found |}]; test_re (seq [ char 'a'; eos ]) "ab"; [%expect {| Not_found |}] ;; let%expect_test "leol" = test_re (seq [ char 'a'; leol ]) "ba"; [%expect {| [| (1, 2) |] |}]; test_re (seq [ char 'a'; leol ]) "a\nb"; [%expect {| Not_found |}]; test_re (seq [ char 'a'; leol ]) "ba\n"; [%expect {| [| (1, 2) |] |}]; test_re (seq [ char 'a'; leol ]) "ab"; [%expect {| Not_found |}]; test_re (alt [ str "b\n"; seq [ char 'a'; leol ] ]) "ab\n"; [%expect {| [| (1, 3) |] |}] ;; let%expect_test "start" = test_re ~pos:1 (seq [ start; char 'a' ]) "xab"; [%expect {| [| (1, 2) |] |}]; test_re ~pos:1 (seq [ start; char 'a' ]) "xb\na"; [%expect {| Not_found |}]; test_re ~pos:1 (seq [ start; char 'a' ]) "xba"; [%expect {| Not_found |}] ;; let%expect_test "stop" = test_re ~len:2 (seq [ char 'a'; stop ]) "bax"; [%expect {| [| (1, 2) |] |}]; test_re ~len:3 (seq [ char 'a'; stop ]) "a\nbx"; [%expect {| Not_found |}]; test_re ~len:3 (seq [ char 'a'; stop ]) "ba\nx"; [%expect {| Not_found |}]; test_re ~len:2 (seq [ char 'a'; stop ]) "abx"; [%expect {| Not_found |}] ;; let%expect_test "word" = test_re (word (str "aa")) "aa"; [%expect {| [| (0, 2) |] |}]; test_re (word (str "aa")) "bb aa"; [%expect {| [| (3, 5) |] |}]; test_re (word (str "aa")) "aaa"; [%expect {| Not_found |}]; test_re (word (str "")) ""; [%expect {| Not_found |}] ;; let%expect_test "not_boundary" = test_re (seq [ not_boundary; char 'b'; not_boundary ]) "abc"; [%expect {| [| (1, 2) |] |}]; test_re (seq [ char ';'; not_boundary; char ';' ]) ";;"; [%expect {| [| (0, 2) |] |}]; test_re (seq [ not_boundary; char ';'; not_boundary ]) ";"; [%expect {| [| (0, 1) |] |}]; test_re (seq [ not_boundary; char 'a' ]) "abc"; [%expect {| Not_found |}]; test_re (seq [ char 'c'; not_boundary ]) "abc"; [%expect {| Not_found |}] ;; let%expect_test "default match semantics" = test_re (seq [ rep (alt [ char 'a'; char 'b' ]); char 'b' ]) "aabaab"; [%expect {| [| (0, 6) |] |}]; test_re (alt [ str "aa"; str "aaa" ]) "aaaa"; [%expect {| [| (0, 2) |] |}]; test_re (alt [ str "aaa"; str "aa" ]) "aaaa"; [%expect {| [| (0, 3) |] |}] ;; let%expect_test "shortest match" = test_re (shortest (seq [ rep (alt [ char 'a'; char 'b' ]); char 'b' ])) "aabaab"; [%expect {| [| (0, 3) |] |}]; test_re (shortest (alt [ str "aa"; str "aaa" ])) "aaaa"; [%expect {| [| (0, 2) |] |}]; test_re (shortest (alt [ str "aaa"; str "aa" ])) "aaaa"; [%expect {| [| (0, 2) |] |}] ;; let%expect_test "longest match" = test_re (longest (seq [ rep (alt [ char 'a'; char 'b' ]); char 'b' ])) "aabaab"; [%expect {| [| (0, 6) |] |}]; test_re (longest (alt [ str "aa"; str "aaa" ])) "aaaa"; [%expect {| [| (0, 3) |] |}]; test_re (longest (alt [ str "aaa"; str "aa" ])) "aaaa"; [%expect {| [| (0, 3) |] |}] ;; let%expect_test "first match" = test_re (first (seq [ rep (alt [ char 'a'; char 'b' ]); char 'b' ])) "aabaab"; [%expect {| [| (0, 6) |] |}]; test_re (first (alt [ str "aa"; str "aaa" ])) "aaaa"; [%expect {| [| (0, 2) |] |}]; test_re (first (alt [ str "aaa"; str "aa" ])) "aaaa"; [%expect {| [| (0, 3) |] |}] ;; let%expect_test "match_semantics" = let r = rep (group (alt [ str "aaa"; str "aa" ])) in test_re (longest r) "aaaaaaa"; [%expect {| [| (0, 7); (5, 7) |] |}]; test_re (first r) "aaaaaaa"; [%expect {| [| (0, 6); (3, 6) |] |}]; test_re (first (non_greedy r)) "aaaaaaa"; [%expect {| [| (0, 0); (-1, -1) |] |}]; test_re (shortest r) "aaaaaaa"; [%expect {| [| (0, 0); (-1, -1) |] |}]; let r' = rep (group (shortest (alt [ str "aaa"; str "aa" ]))) in test_re (longest r') "aaaaaaa"; [%expect {| [| (0, 7); (4, 7) |] |}]; test_re (first r') "aaaaaaa"; [%expect {| [| (0, 6); (4, 6) |] |}] ;; let%expect_test "greedy" = test_re (greedy (seq [ rep (alt [ char 'a'; char 'b' ]); char 'b' ])) "aabaab"; [%expect {| [| (0, 6) |] |}]; test_re (greedy (rep (group (opt (char 'a'))))) "aa"; [%expect {| [| (0, 2); (2, 2) |] |}] ;; let%expect_test "non_greedy" = test_re (non_greedy (longest (seq [ rep (alt [ char 'a'; char 'b' ]); char 'b' ]))) "aabaab"; [%expect {| [| (0, 6) |] |}]; test_re (non_greedy (first (seq [ rep (alt [ char 'a'; char 'b' ]); char 'b' ]))) "aabaab"; [%expect {| [| (0, 3) |] |}]; test_re (non_greedy (longest (rep (group (opt (char 'a')))))) "aa"; [%expect {| [| (0, 2); (1, 2) |] |}] ;; let%expect_test "set" = test_re (rep1 (set "abcd")) "bcbadbabcdba"; [%expect {| [| (0, 12) |] |}]; test_re (set "abcd") "e"; [%expect {| Not_found |}] ;; let%expect_test "rg" = test_re (rep1 (rg '0' '9')) "0123456789"; [%expect {| [| (0, 10) |] |}]; test_re (rep1 (rg '0' '9')) "a"; [%expect {| Not_found |}] ;; let%expect_test "inter" = test_re (rep1 (inter [ rg '0' '9'; rg '4' '6' ])) "456"; [%expect {| [| (0, 3) |] |}]; test_re (rep1 (inter [ rg '0' '9'; rg '4' '6' ])) "7"; [%expect {| Not_found |}]; test_re (inter [ alt [ char 'a'; char 'b' ]; char 'b' ]) "b"; [%expect {| [| (0, 1) |] |}] ;; let%expect_test "diff" = test_re (rep1 (diff (rg '0' '9') (rg '4' '6'))) "0123789"; [%expect {| [| (0, 7) |] |}]; test_re (rep1 (diff (rg '0' '9') (rg '4' '6'))) "4"; [%expect {| Not_found |}] ;; let%expect_test "compl" = test_re (rep1 (compl [ rg '0' '9'; rg 'a' 'z' ])) "A:Z+"; [%expect {| [| (0, 4) |] |}]; test_re (rep1 (compl [ rg '0' '9'; rg 'a' 'z' ])) "0"; [%expect {| Not_found |}]; test_re (rep1 (compl [ rg '0' '9'; rg 'a' 'z' ])) "a"; [%expect {| Not_found |}] ;; let%expect_test "case" = test_re (case (str "abc")) "abc"; [%expect {| [| (0, 3) |] |}]; test_re (no_case (case (str "abc"))) "abc"; [%expect {| [| (0, 3) |] |}]; test_re (case (str "abc")) "ABC"; [%expect {| Not_found |}]; test_re (no_case (case (str "abc"))) "ABC"; [%expect {| Not_found |}] ;; let%expect_test "no_case" = test_re (no_case (str "abc")) "abc"; [%expect {| [| (0, 3) |] |}]; test_re (no_case (str "abc")) "ABC"; [%expect {| [| (0, 3) |] |}]; test_re (case (no_case (str "abc"))) "abc"; [%expect {| [| (0, 3) |] |}]; test_re (case (no_case (str "abc"))) "ABC"; [%expect {| [| (0, 3) |] |}] ;; let%expect_test "witness" = let t re = print_endline (witness re) in t (set "ac"); [%expect {| a |}]; t (repn (str "foo") 3 None); [%expect {| foofoofoo |}]; t (alt [ char 'c'; char 'd' ]); [%expect {| c |}]; t (no_case (str "test")); [%expect {| TEST |}]; t eol; [%expect {| |}] ;; ocaml-ocaml-re-5586c57/lib_test/expect/test_replace.ml000066400000000000000000000022541467707551200227140ustar00rootroot00000000000000open Import let%expect_test "test_replace" = let re = Re.Posix.compile_pat "[a-zA-Z]+" in let f sub = String.capitalize_ascii (Re.Group.get sub 0) in print_endline (Re.replace re ~f " hello world; I love chips!"); [%expect {| Hello World; I Love Chips! |}]; print_endline (Re.replace ~all:false re ~f " allo maman, bobo"); [%expect {| Allo maman, bobo |}]; print_endline (Re.replace re_empty ~f:(fun _ -> "a") ""); [%expect {| a |}]; print_endline (Re.replace (Re.compile (Re.rep (Re.char 'a'))) ~f:(fun _ -> "*") "cat"); [%expect {| *c*t* |}] ;; let%expect_test "test_replace_string" = let re = Re.Posix.compile_pat "_[a-zA-Z]+_" in print_endline (Re.replace_string re ~by:"goodbye" "_hello_ world"); [%expect {| goodbye world |}]; print_endline (Re.replace_string ~all:false re ~by:"brown" "The quick _XXX_ fox"); [%expect {| The quick brown fox |}] ;; let%expect_test "test_bug_55" = let re = Re.(compile bol) in let res = Re.replace_string re ~by:"z" "abc" in print_endline res; [%expect {| zabc |}]; let re = Re.(compile eow) in let res = Re.replace_string re ~by:"X" "one two three" in print_endline res; [%expect {| oneX twoX threeX |}] ;; ocaml-ocaml-re-5586c57/lib_test/expect/test_split.ml000066400000000000000000000047501467707551200224370ustar00rootroot00000000000000open Import let re_whitespace = Re.Posix.compile_pat "[\t ]+" let re_eol = Re.compile Re.eol let re_bow = Re.compile Re.bow let re_eow = Re.compile Re.eow let%expect_test "split" = let split ?pos ?len re s = strings (Re.split ?pos ?len re s) in split re_whitespace "aa bb c d "; [%expect {| ["aa"; "bb"; "c"; "d"] |}]; split ~pos:1 ~len:4 re_whitespace "aa b c d"; [%expect {| ["a"; "b"] |}]; split re_whitespace " a full_word bc "; [%expect {| ["a"; "full_word"; "bc"] |}]; split re_empty "abcd"; [%expect {| ["a"; "b"; "c"; "d"] |}]; split re_eol "a\nb"; [%expect {| ["a"; "\nb"] |}]; split re_bow "a b"; [%expect {| ["a "; "b"] |}]; split re_eow "a b"; [%expect {| ["a"; " b"] |}]; split re_whitespace ""; [%expect {| [] |}]; split re_empty ""; [%expect {| [] |}] ;; let%expect_test "split_delim" = let split_delim ?pos ?len re s = strings (Re.split_delim ?pos ?len re s) in split_delim re_whitespace "aa bb c d "; [%expect {| ["aa"; "bb"; "c"; "d"; ""] |}]; split_delim ~pos:1 ~len:4 re_whitespace "aa b c d"; [%expect {| ["a"; "b"; ""] |}]; split_delim re_whitespace " a full_word bc "; [%expect {| [""; "a"; "full_word"; "bc"; ""] |}]; split_delim re_empty "abcd"; [%expect {| [""; "a"; "b"; "c"; "d"; ""] |}]; split_delim re_eol "a\nb"; [%expect {| ["a"; "\nb"; ""] |}]; split_delim re_bow "a b"; [%expect {| [""; "a "; "b"] |}]; split_delim re_eow "a b"; [%expect {| ["a"; " b"; ""] |}]; split_delim re_whitespace ""; [%expect {| [""] |}]; split_delim re_empty ""; [%expect {| [""; ""] |}] ;; let%expect_test "split_full" = let split_full ?pos ?len re s = let res = Re.split_full ?pos ?len re s in Format.printf "[%a]@." Fmt.( list ~pp_sep:(Fmt.lit "; ") (fun fmt what -> match what with | `Text s -> Format.fprintf fmt "`T %S" s | `Delim s -> Format.fprintf fmt "`D %S" (Re.Group.get s 0))) res in split_full re_whitespace "aa bb c d "; [%expect {| [`T "aa"; `D " "; `T "bb"; `D " "; `T "c"; `D " "; `T "d"; `D " "] |}]; split_full ~pos:1 ~len:5 re_whitespace "aa \tb c d"; [%expect {| [`T "a"; `D " \t"; `T "b"; `D " "] |}]; split_full re_whitespace " a full_word bc "; [%expect {| [`D " "; `T "a"; `D " "; `T "full_word"; `D " "; `T "bc"; `D " "] |}]; split_full re_empty "ab"; [%expect {| [`D ""; `T "a"; `D ""; `T "b"; `D ""] |}]; split_full Re.(compile (rep (char 'a'))) "cat"; [%expect {| [`D ""; `T "c"; `D "a"; `T "t"; `D ""] |}]; () ;; ocaml-ocaml-re-5586c57/lib_test/expect/test_validation.ml000066400000000000000000000005301467707551200234260ustar00rootroot00000000000000open Import let () = Printexc.record_backtrace false let any = Re.(compile (rep any)) let%expect_test "bound errors" = let (_ : bool) = Re.execp any ~pos:4 "foo" in [%expect {| |}]; let (_ : bool) = Re.execp any ~pos:1 ~len:3 "foo" in [%expect.unreachable] [@@expect.uncaught_exn {| (Invalid_argument "Re.exec: out of bounds") |}] ;; ocaml-ocaml-re-5586c57/lib_test/expect/test_view.ml000066400000000000000000000001431467707551200222460ustar00rootroot00000000000000open Import let%expect_test "view" = let view = Re.View.view (Re.str "foo") in ignore view ;; ocaml-ocaml-re-5586c57/lib_test/fort_unit/000077500000000000000000000000001467707551200204265ustar00rootroot00000000000000ocaml-ocaml-re-5586c57/lib_test/fort_unit/dune000066400000000000000000000001661467707551200213070ustar00rootroot00000000000000(rule (copy %{project_root}/lib/fmt.ml fmt.ml)) (library (name fort_unit) (wrapped false) (libraries re ounit2)) ocaml-ocaml-re-5586c57/lib_test/fort_unit/fort_unit.ml000066400000000000000000000041101467707551200227650ustar00rootroot00000000000000(* ounit compatibility layer for fort tests *) open OUnit2 type ('a, 'b) either = | Left of 'a | Right of 'b let str_of_either f g = function | Left a -> f a | Right b -> g b ;; let try_with f = try Right (f ()) with | exn -> Left exn ;; let expect_equal_app ?printer ?msg f x g y = let fx = try_with (fun () -> f x) in let gy = try_with (fun () -> g y) in let printer = let right x = match printer with | None -> "" | Some p -> p x in str_of_either Printexc.to_string right in assert_equal ~printer ?msg fx gy ;; let collected_tests = ref [] let id x = x let not_found () = raise Not_found let bool_printer i = Printf.sprintf "%b" i let int_printer i = Printf.sprintf "%d" i let str_printer s = "\"" ^ String.escaped s ^ "\"" let ofs_printer (i0, i1) = Printf.sprintf "(%d,%d)" i0 i1 let list_printer f l = "[" ^ String.concat "; " (List.map f l) ^ "]" let arr_printer f a = "[|" ^ String.concat "; " (List.map f (Array.to_list a)) ^ "|]" let opt_printer f = function | None -> "" | Some s -> "Some (" ^ f s ^ ")" ;; let arr_str_printer = arr_printer str_printer let arr_ofs_printer = arr_printer ofs_printer let list_ofs_printer = list_printer ofs_printer let fail = assert_failure let expect_eq_bool ?msg f x g y = expect_equal_app ?msg ~printer:string_of_bool f x g y let expect_eq_str ?msg f x g y = expect_equal_app ?msg ~printer:str_printer f x g y let expect_eq_str_opt ?msg f x g y = expect_equal_app ?msg ~printer:(opt_printer str_printer) f x g y ;; let expect_eq_ofs ?msg f x g y = expect_equal_app ?msg ~printer:ofs_printer f x g y let expect_eq_arr_str ?msg f x g y = expect_equal_app ?msg ~printer:arr_str_printer f x g y ;; let expect_eq_arr_ofs ?msg f x g y = expect_equal_app ?msg ~printer:arr_ofs_printer f x g y ;; let expect_eq_list_str ?msg f x g y = expect_equal_app ?msg ~printer:(list_printer str_printer) f x g y ;; let expect_pass name run = collected_tests := (name >:: fun _ -> run ()) :: !collected_tests ;; let run_test_suite suite_name = run_test_tt_main (suite_name >::: !collected_tests) ocaml-ocaml-re-5586c57/lib_test/str/000077500000000000000000000000001467707551200172255ustar00rootroot00000000000000ocaml-ocaml-re-5586c57/lib_test/str/dune000066400000000000000000000000751467707551200201050ustar00rootroot00000000000000(test (libraries re fort_unit str ounit2) (name test_str)) ocaml-ocaml-re-5586c57/lib_test/str/test_str.ml000066400000000000000000000147711467707551200214400ustar00rootroot00000000000000open Fort_unit open OUnit2 module type Str_intf = module type of Str module Test_matches (R : Str_intf) = struct let groups () = let group i = try `Found (R.group_beginning i) with | Not_found -> `Not_found | Invalid_argument _ -> `Not_exists in let rec loop acc i = match group i with | `Found p -> loop ((p, R.group_end i) :: acc) (i + 1) | `Not_found -> loop ((-1, -1) :: acc) (i + 1) | `Not_exists -> List.rev acc in loop [] 0 ;; let eq_match ?(pos = 0) ?(case = true) r s = let pat = if case then R.regexp r else R.regexp_case_fold r in try ignore (R.search_forward pat s pos); Some (groups ()) with | Not_found -> None ;; end module T_str = Test_matches (Str) module T_re = Test_matches (Re.Str) let eq_match ?pos ?case r s = expect_equal_app ~msg:(str_printer s) ~printer:(opt_printer (list_printer ofs_printer)) (fun () -> T_str.eq_match ?pos ?case r s) () (fun () -> T_re.eq_match ?pos ?case r s) () ;; let split_result_conv = List.map (function | Str.Delim x -> Re.Str.Delim x | Str.Text x -> Re.Str.Text x) ;; let pp_split_result_list = Fmt.pp_olist (fun fmt x -> let tag, arg = match x with | Re.Str.Delim x -> "Delim", x | Re.Str.Text x -> "Text", x in Fmt.fprintf fmt "%s@ (\"%s\")" tag arg) ;; let pp_fs pp_args pp_out fmt (name, re, args, ex, res) = let f fmt (mod_, r) = Fmt.fprintf fmt "%s.%s %a %a = %a" mod_ name Fmt.quote re pp_args args pp_out r in Fmt.fprintf fmt "@.%a@.%a" f ("Str", ex) f ("Re.Str", res) ;; type ('a, 'b) test = { name : string ; pp_args : 'a Fmt.t ; pp_out : 'b Fmt.t ; re_str : Re.Str.regexp -> 'a -> 'b ; str : Str.regexp -> 'a -> 'b } let bounded_split_t = { name = "bounded_split" ; pp_args = (fun fmt (s, n) -> Fmt.fprintf fmt "%a %d" Fmt.quote s n) ; pp_out = Fmt.pp_str_list ; re_str = (fun re (s, n) -> Re.Str.bounded_split re s n) ; str = (fun re (s, n) -> Str.bounded_split re s n) } ;; let bounded_full_split_t = { bounded_split_t with name = "bounded_full_split" ; pp_out = pp_split_result_list ; re_str = (fun re (s, n) -> Re.Str.bounded_full_split re s n) ; str = (fun re (s, n) -> split_result_conv (Str.bounded_full_split re s n)) } ;; let full_split_t = { bounded_full_split_t with name = "full_split" ; pp_args = (fun fmt s -> Fmt.fprintf fmt "%a" Fmt.quote s) ; re_str = (fun re s -> Re.Str.full_split re s) ; str = (fun re s -> split_result_conv (Str.full_split re s)) } ;; let split_delim_t = { full_split_t with name = "split_delim" ; pp_out = Fmt.pp_str_list ; re_str = (fun re s -> Re.Str.split_delim re s) ; str = (fun re s -> Str.split_delim re s) } ;; let split_t = { name = "split" ; pp_out = Fmt.pp_str_list ; pp_args = full_split_t.pp_args ; re_str = (fun re s -> Re.Str.split re s) ; str = (fun re s -> Str.split re s) } ;; let global_replace_t = { name = "global_replace" ; pp_out = Fmt.pp_print_string ; pp_args = (fun fmt (r, s) -> Fmt.fprintf fmt "%a %a" Fmt.quote r Fmt.quote s) ; re_str = (fun re (r, s) -> Re.Str.global_replace re r s) ; str = (fun re (r, s) -> Str.global_replace re r s) } ;; let test t re args = assert_equal ~pp_diff:(fun fmt (ex, act) -> pp_fs t.pp_args t.pp_out fmt (t.name, re, args, ex, act)) ~printer:(Fmt.to_to_string t.pp_out) (t.re_str (Re.Str.regexp re) args) (t.str (Str.regexp re) args) ;; let split_delim re s = test split_delim_t re s let split re s = test split_t re s let full_split re s = test full_split_t re s let bounded_split re s n = test bounded_split_t re (s, n) let bounded_full_split re s n = test bounded_full_split_t re (s, n) let global_replace re r s = test global_replace_t re (r, s) let _ = (* Literal Match *) expect_pass "str" (fun () -> eq_match "a" "a"; eq_match "a" "b"); (* Basic Operations *) expect_pass "alt" (fun () -> eq_match "a\\|b" "a"; eq_match "a\\|b" "b"; eq_match "a\\|b" "c"); expect_pass "seq" (fun () -> eq_match "ab" "ab"; eq_match "ab" "ac"); expect_pass "epsilon" (fun () -> eq_match "" ""; eq_match "" "a"); expect_pass "rep" (fun () -> eq_match "a*" ""; eq_match "a*" "a"; eq_match "a*" "aa"; eq_match "a*" "b"); expect_pass "rep1" (fun () -> eq_match "a+" "a"; eq_match "a+" "aa"; eq_match "a+" ""; eq_match "a+" "b"); expect_pass "opt" (fun () -> eq_match "a?" ""; eq_match "a?" "a"); (* String, line, word *) expect_pass "bol" (fun () -> eq_match "^a" "ab"; eq_match "^a" "b\na"; eq_match "^a" "ba"); expect_pass "eol" (fun () -> eq_match "a$" "ba"; eq_match "a$" "a\nb"; eq_match "a$" "ba\n"; eq_match "a$" "ab"); expect_pass "start" (fun () -> eq_match ~pos:1 "Za" "xab"; eq_match ~pos:1 "Za" "xb\na"; eq_match ~pos:1 "Za" "xba"); (* Match semantics *) expect_pass "match semantics" (fun () -> eq_match "\\(a\\|b\\)*b" "aabaab"; eq_match "aa\\|aaa" "aaaa"; eq_match "aaa\\|aa" "aaaa"); (* Group (or submatch) *) (* TODO: infinite loop *) expect_pass "group" (fun () -> eq_match "\\(a\\)\\(a\\)?\\(b\\)" "ab"); (* Character set *) expect_pass "rg" (fun () -> eq_match "[0-9]+" "0123456789"; eq_match "[0-9]+" "a"); expect_pass "compl" (fun () -> eq_match "[^0-9a-z]+" "A:Z+"; eq_match "[^0-9a-z]+" "0"; eq_match "[^0-9a-z]+" "a"); (* Case modifiers *) expect_pass "no_case" (fun () -> eq_match ~case:false "abc" "abc"; eq_match ~case:false "abc" "ABC"); expect_pass "global_replace" (fun () -> global_replace "needle" "test" "needlehaystack"; global_replace "needle" "" ""; global_replace "needle" "" "needle"; global_replace "xxx" "yyy" "zzz"; global_replace "test\\([0-9]*\\)" "\\1-foo-\\1" "test100 test200 test"; global_replace "test\\([0-9]*\\)" "'\\-0'" "test100 test200 test"; (* Regrssion test for #129 *) global_replace "\\(X+\\)" "A\\1YY" "XXXXXXZZZZ"); expect_pass "bounded_split, bounded_full_split" (fun () -> List.iter (fun (re, s, n) -> bounded_full_split re s n; bounded_split re s n) [ ",", "foo,bar,baz", 5 ; ",", "foo,bar,baz", 1 ; ",", "foo,bar,baz", 0 ; ",\\|", "foo,bar|baz", 4 ]); expect_pass "split, full_split, split_delim" (fun () -> List.iter (fun (re, s) -> split re s; full_split re s; split_delim re s) [ "re", ""; " ", "foo bar"; "\b", "one-two three"; "[0-9]", "One3TwoFive" ]); run_test_suite "test_str" ;; ocaml-ocaml-re-5586c57/re.opam000066400000000000000000000022021467707551200160700ustar00rootroot00000000000000# This file is generated by dune, edit dune-project instead opam-version: "2.0" synopsis: "RE is a regular expression library for OCaml" description: """ Pure OCaml regular expressions with: * Perl-style regular expressions (module Re.Perl) * Posix extended regular expressions (module Re.Posix) * Emacs-style regular expressions (module Re.Emacs) * Shell-style file globbing (module Re.Glob) * Compatibility layer for OCaml's built-in Str module (module Re.Str) """ maintainer: ["Rudi Grinberg "] authors: [ "Jerome Vouillon" "Thomas Gazagnaire" "Anil Madhavapeddy" "Rudi Grinberg" "Gabriel Radanne" ] license: "LGPL-2.1-or-later WITH OCaml-LGPL-linking-exception" homepage: "https://github.com/ocaml/ocaml-re" bug-reports: "https://github.com/ocaml/ocaml-re/issues" depends: [ "dune" {>= "3.12"} "ocaml" {>= "4.12.0"} "seq" "ppx_expect" {with-test} "ounit2" {with-test} "odoc" {with-doc} ] build: [ ["dune" "subst"] {dev} [ "dune" "build" "-p" name "-j" jobs "@install" "@runtest" {with-test} "@doc" {with-doc} ] ] dev-repo: "git+https://github.com/ocaml/ocaml-re.git"