{"id":22837807,"url":"https://github.com/j-mie6/parsley","last_synced_at":"2025-05-16T18:03:27.148Z","repository":{"id":37003829,"uuid":"133719798","full_name":"j-mie6/parsley","owner":"j-mie6","description":"A fast and modern parser combinator library for Scala","archived":false,"fork":false,"pushed_at":"2025-05-15T09:05:54.000Z","size":131941,"stargazers_count":193,"open_issues_count":21,"forks_count":21,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-15T09:36:40.504Z","etag":null,"topics":["parser","parser-combinators","performant-parser","scala"],"latest_commit_sha":null,"homepage":"https://j-mie6.github.io/parsley/","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/j-mie6.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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,"zenodo":null}},"created_at":"2018-05-16T20:30:50.000Z","updated_at":"2025-05-15T08:35:01.000Z","dependencies_parsed_at":"2024-01-16T11:37:27.121Z","dependency_job_id":"516281a4-0ba8-4526-8cfe-2a5b0d892cbe","html_url":"https://github.com/j-mie6/parsley","commit_stats":null,"previous_names":[],"tags_count":145,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/j-mie6%2Fparsley","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/j-mie6%2Fparsley/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/j-mie6%2Fparsley/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/j-mie6%2Fparsley/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/j-mie6","download_url":"https://codeload.github.com/j-mie6/parsley/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254582901,"owners_count":22095518,"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":["parser","parser-combinators","performant-parser","scala"],"created_at":"2024-12-12T23:19:54.333Z","updated_at":"2025-05-16T18:03:27.130Z","avatar_url":"https://github.com/j-mie6.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Parsley ![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/j-mie6/parsley/ci.yml?branch=master) ![GitHub release](https://img.shields.io/github/v/release/j-mie6/parsley?include_prereleases\u0026sort=semver) [![GitHub license](https://img.shields.io/github/license/j-mie6/parsley.svg)](https://github.com/j-mie6/parsley/blob/master/LICENSE) ![GitHub commits since latest release (by SemVer)](https://img.shields.io/github/commits-since/j-mie6/parsley/latest) [![Badge-Scaladoc]][Link-Scaladoc]\n\n## What is Parsley?\nParsley is a fast and modern parser combinator library for Scala based loosely on a Haskell-style `parsec` API.\n\n## How do I use it? [![parsley Scala version support](https://index.scala-lang.org/j-mie6/parsley/parsley/latest-by-scala-version.svg?platform=jvm)](https://index.scala-lang.org/j-mie6/parsley/parsley) [![parsley Scala version support](https://index.scala-lang.org/j-mie6/parsley/parsley/latest-by-scala-version.svg?platform=sjs1)](https://index.scala-lang.org/j-mie6/parsley/parsley) [![parsley Scala version support](https://index.scala-lang.org/j-mie6/parsley/parsley/latest-by-scala-version.svg?platform=native0.4)](https://index.scala-lang.org/j-mie6/parsley/parsley)\n\nParsley is distributed on Maven Central, and can be added to your project via:\n\n```scala\n// SBT\nlibraryDependencies += \"com.github.j-mie6\" %% \"parsley\" % \"4.6.0\"\n\n// scala-cli\n--dependency com.github.j-mie6::parsley:4.6.0\n// or in file\n//\u003e using dep com.github.j-mie6::parsley:4.6.0\n\n// mill\nivy\"com.github.j-mie6::parsley:4.6.0\"\n```\n\nDocumentation can be found [**here**](https://javadoc.io/doc/com.github.j-mie6/parsley-docs_2.13/latest/index.html)\n\nIf you're a `cats` user, you may also be interested in using [`parsley-cats`](https://github.com/j-mie6/parsley-cats)\u003ca href=\"https://typelevel.org/cats/\"\u003e\u003cimg src=\"https://typelevel.org/cats/img/cats-badge.svg\" height=\"40px\" align=\"right\" alt=\"Cats friendly\" /\u003e\u003c/a\u003e\nto augment `parsley` with instances for various `cats` typeclasses:\n\n```scala\nlibraryDependencies += \"com.github.j-mie6\" %% \"parsley-cats\" % \"1.5.0\"\n```\n\n### Examples\n\n```scala\nscala\u003e import parsley.Parsley\nscala\u003e import parsley.syntax.character.{charLift, stringLift}\n\nscala\u003e val hello: Parsley[Unit] = ('h' ~\u003e (\"ello\" | \"i\") ~\u003e \" world!\").void\nscala\u003e hello.parse(\"hello world!\")\nval res0: parsley.Result[String,Unit] = Success(())\nscala\u003e hello.parse(\"hi world!\")\nval res1: parsley.Result[String,Unit] = Success(())\nscala\u003e hello.parse(\"hey world!\")\nval res2: parsley.Result[String,Unit] =\nFailure((line 1, column 2):\n  unexpected \"ey\"\n  expected \"ello\"\n  \u003ehey world!\n    ^^)\n\nscala\u003e import parsley.character.digit\nscala\u003e val natural: Parsley[Int] = digit.foldLeft1(0)((n, d) =\u003e n * 10 + d.asDigit)\nscala\u003e natural.parse(\"0\")\nval res3: parsley.Result[String,Int] = Success(0)\nscala\u003e natural.parse(\"123\")\nval res4: parsley.Result[String,Int] = Success(123)\n```\n\nFor more see [the Wiki](https://github.com/j-mie6/Parsley/wiki)!\n\n### What are the differences to Haskell's `parsec`?\nMostly, this library is quite similar. However, due to Scala's differences in operator characters a few operators are changed:\n\n* `(\u003c$\u003e)` is known as `map`\n* `try` is known as `attempt`\n* `($\u003e)` is known as either `#\u003e` or `as`\n\nIn addition, `lift2` and `lift3` are uncurried in this library: this is to provide better performance and easier usage with\nScala's traditionally uncurried functions. There are also a few new operators in general to be found here!\n\n## Library Evolution ![Semantic Versioning: early-semver](https://img.shields.io/badge/version%20policy-early--semver-blue)\nParsley is a _modern_ parser combinator library, which strives to be on the\nbleeding-edge of parser combinator library design. This means that improvements\nwill come naturally over time. Feel free to suggest improvements for\nconsideration, as well as high-level problems you commonly encounter that we may\nbe able to find a way to mitigate (see the _Design Patterns for Parser\nCombinators_ paper for example!).\n\n### Frequency of Major Changes\nPart of innovation is being willing to admit\ndesign mistakes and rectify them: when a binary-breaking release is made, the\nopportunity may be taken to polish parts of the libary's API that are clunky, or\ncould be better organised or improved. For example, see the differences between\n`parsley-3.3.10` and `parsley-4.0.0`! However, constant breaking changes are\nnot a good way to encourage the use of a library as users often want stability:\nto that end, annoyances and bugbears with the API are only addressed\napproximately _yearly_, and the frequence of these will decrease over time.\nFor future major releases, care will be taken to, wherever possible, publish\nall patch-level changes in a final version to the previous `major.minor`\nversion, and then all minor-level changes as a final `major.(minor+1).0`\nversion before releasing the major-level changes as `(major+1).0.0`: this will\nallow users stuck on the old version to benefit as much as possible from the\nfixes and new functionality.\n\n### Versioning Policy\nAs of `4.0.0`, `parsley` is _strictly_ commited to `early-semver`, which means\nthat the version numbers are significant:\n\n* Two versions `x._._` and `y._._` with `x != y` are incompatible with\n  each other at a binary level: having `x._._` on the classpath with code\n  compiled with the `y._._` will most likely result in a linkage-error at\n  runtime.\n* Two versions `a.x._` and `a.y._` with `x \u003c= y` are binary compatible, which\n  means that code compiled against `a.x._` will still work with `a.y._` on\n  the classpath. A \"source\" component `y \u003e x` indicates that `a.y._` has\n  added or deprecated functionality since `a.x._`.\n* Two versions `a.b.x` and `a.b.y` are binary and source compatible, which\n  means there are no compatiblity concerns between the two versions. Code\n  compiled against `a.b.x` will run with `a.b.y` on the classpath and\n  vice-versa. A \"patch\" component `y \u003e x` indicates that `a.b.y` fixes\n  issues (bugs or poor performance) with `a.b.x`.\n\nIn short, if you are on version `a.x.y`, you can: feel free to upgrade to\nversion `a.x.z` if `z \u003e y` without worry; and upgrade to `a.z._` if `z \u003e x`,\nwith a _possible_ (but rare) need to update your code minorly. _Occasionally_,\na \"source\" component bump may deprecate functionality, but it will provide a\nmigration to tell you how to avoid the deprecation warning. Altered/deprecated\nfunctionality may be hidden from the public API in a **binary backwards\ncompatible way** in a \"source\" bump and therefore may require updating _when\nrecompiled_; this will be done sparingly and with minimal disruption as to not\ndiscourage updating the libary, and any immediate migration changes to user\ncode from `a.x._` to _any_ `a.y._` with `y \u003e x` **will** be documented in\n`a.y._`'s release.\n\n_Note: all functionality marked as `private [parsley]` or within\nthe `parsley.internal` package is _not_ adherent to `early-semver` and may be\nremoved or changed at will with no impact to_ regular/intended _use of the\nlibrary._\n\n### Release Candidates and Milestones\nOccasionally, a minor (source) release will contain either a significant body of\nnew work, or a significant rework of some internal machinery. In these cases\nadditional versioning may be employed:\n\n* Experimental (and volatile) new functionality may be iterated with `a.b.0-Mn`\n  versions: these are (hopefully) _working_ pre-release versions of the\n  functionality, subject to even binary incompatible changes between `M`\n  versions. When the new API and behaviour becomes stable, the release\n  graduates to the `a.b.0-RC1` release candidate.\n* Release candidates are used to iron-out any lingering issues with a minor\n  release and _potentially_ alter the finer-points of the new functionality's\n  behaviour. Binary compatiblity will be preserved between `RCx` and `RCy` with\n  `y \u003e x` except within truly exceptional circumstances.\n* Finally, the release makes it to `a.b.0` and is _hopefully_ truly stable.\n\n### Version EoL (End of Life) Policy\nOld versions of the library may still be given important bug-fixes after it\nhas be obsoleted by a new release. In exceptional circumstances, performance\nproblems may be addressed for old versions. The lifetime policy is as follows:\n\n* Major (binary) versions reach EoL a minimum of 6 months after its successor\n  was released, unless an extension to its life is requested by a issue.\n* Minor (source) versions reach EoL immediately on the release of its\n  successor, _unless_ deprecations were issued by its successor, in which case\n  it will reach EoL after a minimum of 3 months.\n\nSome more minor bugfixes may not be ported to previous versions if they (a) do\nnot appear in that version or (b) the code has changed too much internally to\nmake porting feasible.\n\n_An exception to this policy is made for any version `3.x.y`, which reaches EoL effective immediately (December 2022) excluding exceptional circumstances._\n\n| Version | Released On        | EoL Status                      |\n|:-------:|:-------------------|:--------------------------------|\n| `3.3.0` | 7th January 2022   | EoL reached (`3.3.10`)          |\n| `4.0.0` | 30th November 2022 | EoL reached (`4.0.4`)           |\n| `4.1.0` | 18th January 2023  | EoL reached (`4.1.8`)           |\n| `4.2.0` | 22nd January 2023  | EoL reached (`4.2.14`)          |\n| `4.3.0` | 8th July 2023      | EoL reached (`4.3.1`)           |\n| `4.4.0` | 6th October 2023   | EoL reached (`4.4.1`)           |\n| `4.5.0` | 6th January 2023   | EoL reached (`4.5.3`)           |\n| `4.6.0` | 15th February 2025 | Enjoying indefinite support     |\n\n## Bug Reports [![Percentage of issues still open](https://isitmaintained.com/badge/open/j-mie6/Parsley.svg)](https://isitmaintained.com/project/j-mie6/Parsley \"Percentage of issues still open\") [![Maintainability](https://img.shields.io/codeclimate/maintainability/j-mie6/parsley)](https://codeclimate.com/github/j-mie6/parsley) [![Test Coverage](https://img.shields.io/codeclimate/coverage-letter/j-mie6/parsley)](https://codeclimate.com/github/j-mie6/parsley)\n\nIf you encounter a bug when using Parsley, try and minimise the example of the parser (and the input) that triggers the bug.\nIf possible, make a self contained example: this will help to identify the issue without too much issue.\n\n## How does it work?\nParsley represents parsers as an abstract-syntax tree AST, which is constructed lazily. As a result, Parsley is able to\nperform analysis and optimisations on your parsers, which helps reduce the burden on you, the programmer. This representation\nis then compiled into a light-weight stack-based instruction set designed to run fast on the JVM. This is what offers Parsley\nits competitive performance, but for best effect a parser should be compiled once and used many times (so-called hot execution).\n\nTo make recursive parsers work in this AST format, you must ensure that recursion is done by knot-tying: you should define all\nrecursive parsers with `val` and introduce `lazy val` where necessary for the compiler to accept the definition.\n\n## References\n* This work is based on my Master's Thesis (2018) which can be found [**here**](https://github.com/J-mie6/Parsley/blob/master/parsley.pdf)\n* This work spawned a paper at the Scala Symposium at ICFP 2018: [**Garnishing Parsec with Parsley**](https://dl.acm.org/doi/abs/10.1145/3241653.3241656)\n* This work supports the patterns introduced at the Scala Symposium in 2022: [**Design Patterns for Parser Combinators in Scala**](https://dl.acm.org/doi/10.1145/3550198.3550427)\n\n\u003c!-- Badges and Links --\u003e\n\n\n[Link-Scaladoc]: https://javadoc.io/doc/com.github.j-mie6/parsley_2.13/latest/index.html\n\n[Badge-Scaladoc]: https://img.shields.io/badge/documentation-available-green\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fj-mie6%2Fparsley","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fj-mie6%2Fparsley","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fj-mie6%2Fparsley/lists"}