{"id":23070175,"url":"https://github.com/strojure/parsesso","last_synced_at":"2025-12-12T01:24:55.515Z","repository":{"id":61160267,"uuid":"534141719","full_name":"strojure/parsesso","owner":"strojure","description":"Parser combinators for Clojure(Script).","archived":false,"fork":false,"pushed_at":"2023-06-06T13:55:56.000Z","size":374,"stargazers_count":55,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"default","last_synced_at":"2024-11-28T13:11:42.517Z","etag":null,"topics":["babashka","clojure","clojurescript","parser","parser-combinators"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/strojure.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-09-08T09:31:23.000Z","updated_at":"2024-10-05T23:58:50.000Z","dependencies_parsed_at":"2023-01-22T04:07:47.157Z","dependency_job_id":null,"html_url":"https://github.com/strojure/parsesso","commit_stats":null,"previous_names":["strojure/parsessor"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strojure%2Fparsesso","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strojure%2Fparsesso/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strojure%2Fparsesso/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strojure%2Fparsesso/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/strojure","download_url":"https://codeload.github.com/strojure/parsesso/tar.gz/refs/heads/default","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":229916373,"owners_count":18144130,"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":["babashka","clojure","clojurescript","parser","parser-combinators"],"created_at":"2024-12-16T06:20:02.370Z","updated_at":"2025-12-12T01:24:55.477Z","avatar_url":"https://github.com/strojure.png","language":"Clojure","readme":"# parsesso\n\n[Parser combinators](https://en.wikipedia.org/wiki/Parser_combinator) for\nClojure(Script).\n\n[![Clojars Project](https://img.shields.io/clojars/v/com.github.strojure/parsesso.svg)](https://clojars.org/com.github.strojure/parsesso)\n![ClojarsDownloads](https://img.shields.io/clojars/dt/com.github.strojure/parsesso)\n\n[![cljdoc badge](https://cljdoc.org/badge/com.github.strojure/parsesso)](https://cljdoc.org/d/com.github.strojure/parsesso)\n[![cljs compatible](https://img.shields.io/badge/cljs-compatible-green)](https://clojurescript.org/)\n[![bb compatible](https://raw.githubusercontent.com/babashka/babashka/master/logo/badge.svg)](https://book.babashka.org#badges)\n[![tests](https://github.com/strojure/parsesso/actions/workflows/tests.yml/badge.svg)](https://github.com/strojure/parsesso/actions/workflows/tests.yml)\n\n## Motivation\n\n* Idiomatic and convenient API for parser combinators in Clojure and\n  ClojureScript.\n\n## Inspiration\n\n* [haskell/parsec](https://github.com/haskell/parsec)\n* [blancas/kern](https://github.com/blancas/kern)\n* [youngnh/parsatron](https://github.com/youngnh/parsatron)\n* [rm-hull/jasentaa](https://github.com/rm-hull/jasentaa)\n\n## Documentation\n\nAs far as there is no comprehensive documentation how to use `parsesso` there\nare another resources to get familiar with idea of parser combinators in Clojure:\n\n- [Kern documentation wiki](https://github.com/blancas/kern/wiki).\n\n## Cheat sheet\n\n| Parsesso                              | Parsec\u003csup\u003e[1],[2],[3]\u003c/sup\u003e    | Kern\u003csup\u003e[4]\u003c/sup\u003e      | Parsatron\u003csup\u003e[5]\u003c/sup\u003e |\n|---------------------------------------|---------------------------------|-------------------------|-------------------------|\n| \u003ccode\u003e[p/do-parser]\u003c/code\u003e            |                                 | `fwd`                   | `defparser`             |\n| \u003ccode\u003e[p/result]\u003c/code\u003e               | `return`                        | `return`                | `always`                |\n| \u003ccode\u003e[p/fail]\u003c/code\u003e                 | `fail`                          | `fail`                  | `never`                 |\n| \u003ccode\u003e[p/fail-unexpected]\u003c/code\u003e      | `unexpected`                    | `unexpected`            |                         |\n| \u003ccode\u003e[p/expecting]\u003c/code\u003e            | `\u003c?\u003e`, `label`                  | `\u003c?\u003e`, `expect`         |                         |\n| \u003ccode\u003e[p/bind]\u003c/code\u003e                 | `\u003e\u003e=`                           | `\u003e\u003e=`                   | `bind`                  |\n| \u003ccode\u003e[p/for]\u003c/code\u003e                  | `do`                            | `bind`                  | `let-\u003e\u003e`                |\n| \u003ccode\u003e[p/after]\u003c/code\u003e                | `\u003e\u003e`                            | `\u003e\u003e`                    | `\u003e\u003e`, `nxt`             |\n| \u003ccode\u003e[p/value]\u003c/code\u003e                | `fmap`                          | `\u003c$\u003e`                   |                         |\n| \u003ccode\u003e[p/maybe]\u003c/code\u003e                | `try`                           | `\u003c:\u003e`                   | `attempt`               |\n| \u003ccode\u003e[p/look-ahead]\u003c/code\u003e           | `lookAhead`                     | `look-ahead`            | `lookahead`             |\n| \u003ccode\u003e[p/not-followed-by]\u003c/code\u003e      | `notFollowedBy`                 | `not-followed-by`       |                         |\n| \u003ccode\u003e[p/*many]\u003c/code\u003e                | `many`                          | `many`                  | `many`                  |\n| \u003ccode\u003e[p/+many]\u003c/code\u003e                | `many1`                         | `many1`                 | `many1`                 |\n| \u003ccode\u003e[p/*skip]\u003c/code\u003e                | `skipMany`                      | `skip-many`             |                         |\n| \u003ccode\u003e[p/+skip]\u003c/code\u003e                | `skipMany1`                     | `skip-many1`            |                         |\n| \u003ccode\u003e[p/token]\u003c/code\u003e                | `token`, `satisfy`              | `satisfy`               | `token`                 |\n| \u003ccode\u003e[p/token-not]\u003c/code\u003e            |                                 |                         |                         |\n| \u003ccode\u003e[p/word]\u003c/code\u003e                 | `tokens`, `string`              | `token*`                | `string`                |\n| \u003ccode\u003e[p/any-token]\u003c/code\u003e            | `anyToken`,`anyChar`            | `any-char`              | `any-char`              |\n| \u003ccode\u003e[p/eof]\u003c/code\u003e                  | `eof`                           | `eof`                   | `eof`                   |\n| \u003ccode\u003e[p/group]\u003c/code\u003e                | `\u003c*\u003e`                           | `\u003c*\u003e`                   |                         |\n| \u003ccode\u003e[p/alt]\u003c/code\u003e                  | \u003ccode\u003e\u003c\u0026#124;\u003e\u003c/code\u003e, `choice` | \u003ccode\u003e\u003c\u0026#124;\u003e\u003c/code\u003e   | `choice`                |\n| \u003ccode\u003e[p/option]\u003c/code\u003e               | `option`, `optional`            | `option`, `optional`    |                         |\n| \u003ccode\u003e[p/between]\u003c/code\u003e              | `between`                       | `between`               | `between`               |\n| \u003ccode\u003e[p/times]\u003c/code\u003e                | `count`                         | `times`                 | `times`                 |\n| \u003ccode\u003e[p/*many-till]\u003c/code\u003e           | `manyTill`                      | `many-till`             |                         |\n| \u003ccode\u003e[p/*sep-by]\u003c/code\u003e              | `sepBy`                         | `sep-by`                |                         |\n| \u003ccode\u003e[p/+sep-by]\u003c/code\u003e              | `sepBy1`                        | `sep-by1`               |                         |\n| \u003ccode\u003e[p/*sep-end-by]\u003c/code\u003e          | `endBy`                         | `end-by`                |                         |\n| \u003ccode\u003e[p/+sep-end-by]\u003c/code\u003e          | `endBy1`                        | `end-by1`               |                         |\n| \u003ccode\u003e[p/*sep-opt-by]\u003c/code\u003e          | `sepEndBy`                      | `sep-end-by`            |                         |\n| \u003ccode\u003e[p/+sep-opt-by]\u003c/code\u003e          | `sepEndBy1`                     | `sep-end-by1`           |                         |\n| \u003ccode\u003e[p/get-state]\u003c/code\u003e            | `getParserState`...             | input, pos, user state  |                         |\n| \u003ccode\u003e[p/set-state]\u003c/code\u003e            | `setParserState`...             | input, pos, user state  |                         |\n| \u003ccode\u003e[p/update-state]\u003c/code\u003e         | `updateParserState`...          | user state              |                         |\n| \u003ccode\u003e[p/trace]\u003c/code\u003e                | `parserTrace`, `parserTraced`   |                         |                         |\n| \u003ccode\u003e[expr/*chain-left]\u003c/code\u003e       | `chainl`                        | `chainl`                |                         |\n| \u003ccode\u003e[expr/+chain-left]\u003c/code\u003e       | `chainl1`                       | `chainl1`               |                         |\n| \u003ccode\u003e[expr/*chain-right]\u003c/code\u003e      | `chainr`                        | `chainr`                |                         |\n| \u003ccode\u003e[expr/+chain-right]\u003c/code\u003e      | `chainr1`                       | `chainr1`               |                         |\n| \u003ccode\u003e[char/is]\u003c/code\u003e                | `char`, `oneOf`                 | `sym*`, `one-of*`       | `char`                  |\n| \u003ccode\u003e[char/is-not]\u003c/code\u003e            | `noneOf`                        | `none-of*`              |                         |\n| \u003ccode\u003e[char/regex]\u003c/code\u003e             |                                 |                         |                         |\n| \u003ccode\u003e[char/upper?]\u003c/code\u003e            | `upper`                         | `upper` (unicode)       |                         |\n| \u003ccode\u003e[char/lower?]\u003c/code\u003e            | `lower`                         | `lower` (unicode)       |                         |\n| \u003ccode\u003e[char/letter?]\u003c/code\u003e           | `letter`                        | `letter` (unicode)      | `letter` (unicode)      |\n| \u003ccode\u003e[char/number?]\u003c/code\u003e           | `digit`                         | `digit` (unicode)       | `digit` (unicode)       |\n| \u003ccode\u003e[char/letter-or-number?]\u003c/code\u003e | `alphaNum`                      | `alpha-num` (unicode)   |                         |\n| \u003ccode\u003e[char/white?]\u003c/code\u003e            | `space`                         | `white-space` (unicode) |                         |\n| \u003ccode\u003e[char/newline]\u003c/code\u003e           | `endOfLine`                     | `new-line*`             |                         |\n| \u003ccode\u003e[char/str*]\u003c/code\u003e              |                                 | `\u003c+\u003e`                   |                         |\n\n[1]: https://github.com/haskell/parsec/blob/master/src/Text/Parsec/Prim.hs\n\n[2]: https://github.com/haskell/parsec/blob/master/src/Text/Parsec/Combinator.hs\n\n[3]: https://github.com/haskell/parsec/blob/master/src/Text/Parsec/Char.hs\n\n[4]: https://github.com/blancas/kern/blob/master/src/main/clojure/blancas/kern/core.clj\n\n[5]: https://github.com/youngnh/parsatron/blob/master/src/clj/the/parsatron.clj\n\n[p/do-parser]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#do-parser\n\n[p/result]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#result\n\n[p/fail]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#fail\n\n[p/fail-unexpected]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#fail-unexpected\n\n[p/expecting]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#expecting\n\n[p/bind]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#bind\n\n[p/for]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#for\n\n[p/after]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#after\n\n[p/value]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#value\n\n[p/maybe]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#maybe\n\n[p/look-ahead]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#look-ahead\n\n[p/not-followed-by]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#not-followed-by\n\n[p/*many]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#*many\n\n[p/+many]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#+many\n\n[p/*skip]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#*skip\n\n[p/+skip]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#+skip\n\n[p/token]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#token\n\n[p/token-not]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#token-not\n\n[p/word]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#word\n\n[p/any-token]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#any-token\n\n[p/eof]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#eof\n\n[p/group]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#group\n\n[p/alt]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#alt\n\n[p/option]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#option\n\n[p/between]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#between\n\n[p/times]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#times\n\n[p/*many-till]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#*many-till\n\n[p/*sep-by]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#*sep-by\n\n[p/+sep-by]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#+sep-by\n\n[p/*sep-end-by]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#*sep-end-by\n\n[p/+sep-end-by]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#+sep-end-by\n\n[p/*sep-opt-by]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#*sep-opt-by\n\n[p/+sep-opt-by]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#+sep-opt-by\n\n[p/get-state]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#get-state\n\n[p/set-state]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#set-state\n\n[p/update-state]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#update-state\n\n[p/trace]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.parser#trace\n\n[expr/*chain-left]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.expr#*chain-left\n\n[expr/+chain-left]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.expr#+chain-left\n\n[expr/*chain-right]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.expr#*chain-right\n\n[expr/+chain-right]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.expr#+chain-right\n\n[char/is]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.char#is\n\n[char/is-not]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.char#is-not\n\n[char/regex]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.char#regex\n\n[char/upper?]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.char#upper?\n\n[char/lower?]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.char#lower?\n\n[char/letter?]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.char#letter?\n\n[char/number?]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.char#number?\n\n[char/letter-or-number?]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.char#letter-or-number?\n\n[char/white?]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.char#white?\n\n[char/newline]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.char#newline\n\n[char/str*]: https://cljdoc.org/d/com.github.strojure/parsesso/CURRENT/api/strojure.parsesso.char#str*\n\n## Examples\n\n* [HoneySQL SELECT](doc/demo/honeysql_select.clj)\n\n## Performance\n\nSee some benchmarks [here](doc/benchmarks/compare.clj).\n\n## FAQ\n\n**What parser combinators are \u0026 are good for? How does it differ e.g. from\nInstaparse, which also parses text into data?**\n\nA parser combinator library is a library with functions that can be composed\ninto a parser. Instaparse takes a grammar specification, but in a parser\ncombinator library you build the specification from functions, rather than a\nDSL.\n\n**When should I pick parser combinators over EBNF? Do they offer the same,\nand it is only question of which one I prefer to learn or is there some distinct\nadvantage over a DSL such as EBNF? Perhaps it is easier to describe more complex\ngrammars b/c I can make my own helper functions, or something?**\n\nIn general, parser combinators such as `parsesso` are for creating top-down\n(i.e. LL) parsers, with the ability to reuse common code (this lib). Parser\nGenerators typically generate a finite state automaton for a bottom-up (LR)\nparser. Though nowadays there are also combinators for LR grammars and\ngenerators for LL ones (e.g. ANTLR). Which one you should use, depends on how\nhard your grammar is, and how fast the parser needs to be. Especially if the\ngrammar has lot of non-trivial ambiguities then it might be easier with the more\nflexible combinators approach.\n\n## Contributors\n\n- [Michiel Borkent](https://github.com/borkdude)\n    + Compatibility with babashka.\n    + Github CI configuration.\n    + Clj-kondo configuration tips.\n- [Jakub Holý](https://github.com/holyjak)\n    + Questions and answers in FAQ.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstrojure%2Fparsesso","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstrojure%2Fparsesso","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstrojure%2Fparsesso/lists"}