{"id":28538799,"url":"https://github.com/calcit-lang/lilac-parser","last_synced_at":"2026-02-07T07:33:10.408Z","repository":{"id":42458558,"uuid":"318993455","full_name":"calcit-lang/lilac-parser","owner":"calcit-lang","description":"A toy combinator parser inspired by Lilac, ported from CLJS version","archived":false,"fork":false,"pushed_at":"2024-03-27T16:10:44.000Z","size":474,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-08-03T17:55:33.295Z","etag":null,"topics":["calcit","parser"],"latest_commit_sha":null,"homepage":"http://repo.calcit-lang.org/lilac-parser/","language":"Cirru","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/calcit-lang.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2020-12-06T09:13:07.000Z","updated_at":"2022-04-03T18:31:42.000Z","dependencies_parsed_at":"2023-11-10T19:24:18.843Z","dependency_job_id":"9836a33c-0cdf-48b1-845a-4c467156e837","html_url":"https://github.com/calcit-lang/lilac-parser","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":"calcit-lang/calcit-workflow","purl":"pkg:github/calcit-lang/lilac-parser","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/calcit-lang%2Flilac-parser","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/calcit-lang%2Flilac-parser/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/calcit-lang%2Flilac-parser/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/calcit-lang%2Flilac-parser/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/calcit-lang","download_url":"https://codeload.github.com/calcit-lang/lilac-parser/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/calcit-lang%2Flilac-parser/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29189342,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-07T05:07:31.176Z","status":"ssl_error","status_checked_at":"2026-02-07T05:06:15.227Z","response_time":63,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["calcit","parser"],"created_at":"2025-06-09T18:13:23.435Z","updated_at":"2026-02-07T07:33:10.403Z","avatar_url":"https://github.com/calcit-lang.png","language":"Cirru","funding_links":[],"categories":[],"sub_categories":[],"readme":"\nLilac Parser\n----\n\n\u003e A toy DSL-based combinator parser with better failure reasons.\n\nOnline demo http://repo.calcit-lang.org/lilac-parser/\n\nTry with `(def a (add 1 2))` or `{\"json\": [1, 2]}`.\n\n### Usage\n\n```cirru\nns app\n  :require\n    lilac-parser.core :refer\n      parse-lilac defparser is+ many+ one-of+ other-than+\n        , some+ combine+ interleave+ label+ replace-lilac find-lilac\n\nparse-lilac (string/split |aaaa |) (many+ (is+ |a))\n```\n\nDemo of a stupid S-expression parser:\n\n```cirru\ndef number-parser $ many+ (one-of+ |1234567890)\n\ndef space-parser (is+ \"| \")\n\ndef word-parser $ many+ (one-of+ |qwertyuiopasdfghjklzxcvbnm)\n\ndefparser s-expr-parser+ ()\n  identity\n  combine+ $ []\n    is+ \"|(\"\n    some+ $ or+ $ [] number-parser word-parser space-parser (s-expr-parser+)\n    is+ \"|)\"\n\nparse-lilac (.split \"|(def a (add 1 2))\" |) (s-expr-parser+)\n```\n\n### Rules\n\n| Rule             | Example                                         | Description                                |\n| ---------------- | ----------------------------------------------- | ------------------------------------------ |\n| `is+`            | `(is+ \"a\")` or `(is+ \"abc\")`                    | matches a piece of string                  |\n| `one-of+`        | `(one-of+ \"abc\")` or `(one-of+ #{\"a\" \"b\" \"c\"})` | matches a character in one of candidates   |\n| `other-than+`    | `(other-than+ \"abc\")`                           | matches a character that is not listed     |\n| `optional+`      | `(optional+ (is+ \"a\"))`                         | matching or nothing                        |\n| `some+`          | `(some+ (is+ \"a\"))`                             | matches 0 or more items                    |\n| `many+`          | `(many+ (is+ \"a\"))`                             | matches 1 or more items                    |\n| `or+`            | `(or+ [(is+ \"a\") (is+ \"b\")])`                   | matches one among listed items             |\n| `combine+`       | `(combine+ [(is+ \"a\") (is+ \"b\")])`              | matches items in ecxact order              |\n| `interleave+`    | `(interleave+ (is+ \"a\") (is+ \",\"))`             | matches two interleaving items             |\n| `label+`         | `(label+ \"just a\" (is+ \"a\"))`                   | simpler rule for adding comments in result |\n| `unicode-range+` | `(unicode-range+ 97 122)`                       | matches a with unicode in between given    |\n\n### `defparser`\n\n`defparser` is a macro for defining parser that can be used recursively. The type is `:component`, which is like a more complicated version of `:label`. Notice that `s-expr-parser+` defined with `defparser` is different from a normal rule, it's a function so it need to be called before being used as a rule.\n\n### Visual DEMO\n\nlilac-parser would be pretter slow since it tries to store all information during parsing, which results in a piece of EDN data. The result can be rendered into a tree with GUI and that's what is [demonstrated in the demo](http://repo.calcit-lang.org/lilac-parser/).\n\nAn example for Cirru EDN data in parsing a JSON number.\n\n```cirru\n{} (:ok? true) (:value 112)\n  :rest $ []\n  :parser-node :component\n  :label :value-parser+\n  :result $ {} (:ok? true) (:value 112)\n    :rest $ []\n    :parser-node :or\n    :results $ []\n    :result $ {} (:ok? true) (:parser-node :label) (:label |number) (:value 112)\n      :rest $ []\n      :result $ {} (:ok? true) (:value 112)\n        :rest $ []\n        :parser-node :combine\n        :results $ []\n          {} (:ok? true) (:value nil)\n            :result $ {} (:ok? false) (:message \"|expects |- but got ([] |1)\") (:parser-node :is)\n              :rest $ [] |1 |1 |2\n            :parser-node :optional\n            :rest $ [] |1 |1 |2\n          {} (:ok? true) (:value |112)\n            :rest $ []\n            :parser-node :many\n            :results $ []\n              {} (:ok? true) (:value |1)\n                :rest $ [] |1 |2\n                :parser-node :one-of\n              {} (:ok? true) (:value |1)\n                :rest $ [] |2\n                :parser-node :one-of\n              {} (:ok? true) (:value |2)\n                :rest $ []\n                :parser-node :one-of\n            :peek-result $ {} (:ok? false) (:message \"|unexpected EOF\") (:parser-node :one-of)\n              :rest $ []\n          {} (:ok? true) (:value nil)\n            :result $ {} (:ok? false) (:parser-node :combine) (:message \"|failed to combine\")\n              :result $ {} (:ok? false) (:message \"|expects |. but got EOF\") (:parser-node :is)\n                :rest $ []\n              :previous-results $ []\n              :rest $ []\n            :parser-node :optional\n            :rest $ []\n```\n\n### Preset rules\n\nUnder `lilac-parser.preset`:\n\n- `lilac-digit` matches `\\d`\n- `lilac-alphabet` matches `[a-zA-Z]`\n- `lilac-chinese-char` matches `[\\u4e00-\\u9fa5]`\n- `lilac-comma-space` matches `\\s*\\,\\s*`\n\n### Custom Rule\n\nParser rules can be expected by injecting functions. It could be quite tricky and is not recommended:\n\n```cirru\nlilac-parser.core/resigter-custom-rule! :xyz\n  fn (xs rule)\n    ; TODO\n\ndefn xyz+ (xs transform)\n  ; TODO\n```\n\n### Replacer\n\nA function is also provided for replacing text pieces matching a given rule:\n\n```cirru\nreplace-lilac content rule $ fn (x) (str |\u003c\u003c\u003c x |\u003e\u003e\u003e)\n```\n\nwhich returns `:result` as well as parsing details in `:attempts`:\n\n```cirru\n{}\n  :result |\u003c\u003c\u003cMATCHED\u003e\u003e\u003e\n  :attempts $ []\n    ; parsing summaries in vector\n```\n\nThis is an experimental API serving jobs as a custom regular expression replacer.\n\nSimilarly matched pieces can be collected with `find-lilac`:\n\n```cirru\nfind-lilac content rule\n```\n\n### Workflow\n\nhttps://github.com/calcit-lang/respo-calcit-workflow\n\n### License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcalcit-lang%2Flilac-parser","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcalcit-lang%2Flilac-parser","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcalcit-lang%2Flilac-parser/lists"}