{"id":19758054,"url":"https://github.com/paurkedal/ppx_regexp","last_synced_at":"2025-10-01T06:31:30.380Z","repository":{"id":136457603,"uuid":"92623769","full_name":"paurkedal/ppx_regexp","owner":"paurkedal","description":"Matching Regular Expressions with OCaml Patterns","archived":false,"fork":false,"pushed_at":"2023-02-05T09:32:04.000Z","size":119,"stargazers_count":56,"open_issues_count":1,"forks_count":3,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-01-15T07:42:05.204Z","etag":null,"topics":["ocaml-patterns","ppx-rewriter","regular-expression"],"latest_commit_sha":null,"homepage":null,"language":"OCaml","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/paurkedal.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":null,"funding":null,"license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-05-27T20:58:10.000Z","updated_at":"2024-11-05T00:40:19.000Z","dependencies_parsed_at":null,"dependency_job_id":"592d9c3d-a35b-4dd3-ab6a-cbbe1b0e06b8","html_url":"https://github.com/paurkedal/ppx_regexp","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paurkedal%2Fppx_regexp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paurkedal%2Fppx_regexp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paurkedal%2Fppx_regexp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paurkedal%2Fppx_regexp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/paurkedal","download_url":"https://codeload.github.com/paurkedal/ppx_regexp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234835295,"owners_count":18894201,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ocaml-patterns","ppx-rewriter","regular-expression"],"created_at":"2024-11-12T03:22:45.334Z","updated_at":"2025-10-01T06:31:25.037Z","avatar_url":"https://github.com/paurkedal.png","language":"OCaml","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status][ci-build-status]][ci]\n\n# Two PPXes for Working with Regular Expressions\n\nThis repo provides two PPXes providing regular expression-based routing:\n\n- `ppx_regexp` maps to [re][] with the conventional last-match extraction\n  into `string` and `string option`.\n- `ppx_tyre` maps to [Tyre][tyre] providing typed extraction into options,\n  lists, tuples, objects, and polymorphic variants.\n\nAnother difference is that `ppx_regexp` works directly on strings\nessentially hiding the library calls, while `ppx_tyre` provides `Tyre.t` and\n`Tyre.route` which can be composed an applied using the Tyre library.\n\n## `ppx_regexp` - Regular Expression Matching with OCaml Patterns\n\nThis syntax extension turns\n```ocaml\nfunction%pcre\n| {|re1|} -\u003e e1\n...\n| {|reN|} -\u003e eN\n| _ -\u003e e0\n```\ninto suitable invocations of the [Re library][re], and similar for\n`match%pcre`.  The patterns are plain strings of the form accepted by\n`Re_pcre`, with the following additions:\n\n  - `(?\u003cvar\u003e...)` defines a group and binds whatever it matches as `var`.\n    The type of `var` will be `string` if the match is guaranteed given that\n    the whole pattern matches, and `string option` if the variable is bound\n    to or nested below an optionally matched group.\n\n  - `?\u003cvar\u003e` at the start of a pattern binds group 0 as `var : string`.\n    This may not be the full string if the pattern is unanchored.\n\nA variable is allowed for the universal case and is bound to the matched\nstring.  A regular alias is currently not allowed for patterns, since it is\nnot obvious whether is should bind the full string or group 0.\n\n### Example\n\nThe following prints out times and hosts for SMTP connections to the Postfix\ndaemon:\n```ocaml\n(* Link with re, re.pcre, lwt, lwt.unix.\n   Preprocess with ppx_regexp.\n   Adjust to your OS. *)\n\nopen Lwt.Infix\n\nlet check_line =\n  (function%pcre\n   | {|(?\u003ct\u003e.*:\\d\\d) .* postfix/smtpd\\[[0-9]+\\]: connect from (?\u003chost\u003e[a-z0-9.-]+)|} -\u003e\n      Lwt_io.printlf \"%s %s\" t host\n   | _ -\u003e\n      Lwt.return_unit)\n\nlet () = Lwt_main.run begin\n  Lwt_io.printl \"SMTP connections from:\" \u003e\u003e= fun () -\u003e\n  Lwt_stream.iter_s check_line (Lwt_io.lines_of_file \"/var/log/syslog\")\nend\n```\n\n## `ppx_tyre` - Syntax Support for Tyre Routes\n\n### Typed regular expressions\n\nThis PPX compiles\n```ocaml\n[%tyre {|re|}]\n```\ninto `'a Tyre.t`.\n\nFor instance, We can define a pattern that recognize strings of the form \"dim:3x5\" like so:\n\n```ocaml\n# open Tyre ;;\n# let dim = [%tyre \"dim:(?\u0026int)x(?\u0026int)\"] ;;\nval dim : (int * int) Tyre.t\n```\n\nThe syntax `(?\u0026id)` allows to call a typed regular expression named `id` of type `'a Tyre.t`, such as `Tyre.int`.\n\nFor convenience, you can also use *named* capture groups to name the captured elements.\n```ocaml\n# let dim = [%tyre \"dim:(?\u003cx\u003e(?\u0026int))x(?\u0026y:int)\"] ;;\nval dim : \u003c x : int; y : int \u003e Tyre.t\n```\n\nNames given using the syntax `(?\u003cfoo\u003ere)` will be used for the fields\nof the results. `(?\u0026y:int)` is a shortcut for `(?\u003cy\u003e(?\u0026int))`.\nThis can also be used for alternatives, for instance:\n\n```ocaml\n# let id_or_name = [%tyre \"id:(?\u0026id:int)|name:(?\u003cname\u003e[[:alnum:]]+)\"] ;;\nval id_or_name : [ `id of int | `name of string ] Tyre.t\n```\n\nExpressions of type `Tyre.t` can then be composed as part of bigger regular\nexpressions, or compiled with `Tyre.compile`. \nSee [tyre][]'s documentation for details.\n\n### Routes\n\n`ppx_tyre` can also be used for routing, in the style of `ppx_regexp`:\n\n```ocaml\n    function%tyre\n    | {|re1|} -\u003e e1\n    ...\n    | {|reN|} -\u003e eN\n```\n\nis turned into a `'a Type.route`, where `re`, `re1`, ... are regular expressions\nusing the same syntax as above. `\"re\" as v` is considered like `(?\u003cv\u003ere)` and\n`\"re1\" | \"re2\"` is turned into a regular expression alternative.\n\nOnce routes are defined, matching is done with `Tyre.exec`.\n\n### Details\n\nThe syntax follow Perl's syntax:\n\n- `re?` extracts an option of what `re` extracts.\n- `re+`, `re*`, `re{n,m}` extracts a list of what `re` extracts.\n- `(?\u0026qname)` refers to any identifier bound to a typed regular expression\n  of type `'a Tyre.t`.\n- Normal parens are *non-capturing*.\n- There are two ways to capture:\n  - Anonymous capture `(+re)`\n  - Named capture `(?\u003cv\u003ere)`\n- One or more `(?\u003cv\u003ere)` at the top level can be used to bind variables\n  instead of `as ...`.\n- One or more `(?\u003cv\u003ere)` in a sequence extracts an object where each method\n  `v` is bound to what `re` extracts.\n- An alternative with one `(?\u003cv\u003ere)` per branch extracts a polymorphic\n  variant where each constructor `` `v`` receives what `re` extracts as its\n  argument.\n- `(?\u0026v:qname)` is a shortcut for `(?\u003cv\u003e(?\u0026qname))`.\n\n## Limitations\n\n### No Pattern Guards\n\nPattern guards are not supported.  This is due to the fact that all match\ncases are combined into a single regular expression, so if one of the\npatterns succeed, the match is committed before we can check the guard\ncondition.\n\n### No Exhaustiveness Check\n\nThe syntax extension will always warn if no catch-all case is provided.  No\nexhaustiveness check is attempted.  Doing it right would require\nreimplementing full regular expression parsing and an algorithm which would\nideally produce a counter-example.\n\n## Bug Reports\n\nThe processor is currently new and not well tested.  Please break it and\nfile bug reports in the GitHub issue tracker.  Any exception raised by\ngenerated code except for `Match_failure` is a bug.\n\n\n[ci]: https://travis-ci.org/paurkedal/ppx_regexp\n[ci-build-status]: https://travis-ci.org/paurkedal/ppx_regexp.svg?branch=master\n[re]: https://github.com/ocaml/ocaml-re\n[tyre]: https://github.com/Drup/tyre\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaurkedal%2Fppx_regexp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpaurkedal%2Fppx_regexp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaurkedal%2Fppx_regexp/lists"}