{"id":32186941,"url":"https://github.com/mvc-works/lilac-parser","last_synced_at":"2026-02-21T00:02:00.735Z","repository":{"id":62433725,"uuid":"246607703","full_name":"mvc-works/lilac-parser","owner":"mvc-works","description":"A toy combinator parser inspired by Lilac","archived":false,"fork":false,"pushed_at":"2020-08-10T08:05:44.000Z","size":380,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-11-27T14:42:49.686Z","etag":null,"topics":["clojure","parser"],"latest_commit_sha":null,"homepage":"https://r.tiye.me/mvc-works/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/mvc-works.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}},"created_at":"2020-03-11T15:25:29.000Z","updated_at":"2022-04-03T13:29:38.000Z","dependencies_parsed_at":"2022-11-01T21:15:46.337Z","dependency_job_id":null,"html_url":"https://github.com/mvc-works/lilac-parser","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":"mvc-works/calcit-nodejs-workflow","purl":"pkg:github/mvc-works/lilac-parser","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mvc-works%2Flilac-parser","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mvc-works%2Flilac-parser/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mvc-works%2Flilac-parser/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mvc-works%2Flilac-parser/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mvc-works","download_url":"https://codeload.github.com/mvc-works/lilac-parser/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mvc-works%2Flilac-parser/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29668627,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-20T23:24:07.480Z","status":"ssl_error","status_checked_at":"2026-02-20T23:24:06.202Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5: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":["clojure","parser"],"created_at":"2025-10-22T00:01:48.929Z","updated_at":"2026-02-21T00:02:00.727Z","avatar_url":"https://github.com/mvc-works.png","language":"Cirru","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Lilac parser\n\n\u003e A toy DSL-based combinator parser with better failure reasons.\n\nOnline demo http://repo.mvc-works.org/lilac-parser/\n\nTry with `(def a (add 1 2))` or `{\"json\": [1, 2]}`.\n\n### Usage\n\n[![Clojars Project](https://img.shields.io/clojars/v/mvc-works/lilac-parser.svg)](https://clojars.org/mvc-works/lilac-parser)\n\n```edn\n[mvc-works/lilac-parser \"0.0.3-a5\"]\n```\n\n```clojure\n(require '[lilac-parser.core :refer\n            [parse-lilac defparser is+ many+ one-of+ other-than+\n             some+ combine+ interleave+ label+\n             replace-lilac find-lilac]])\n\n(parse-lilac (string/split \"aaaa\" \"\") (many+ (is+ \"a\")))\n```\n\nDemo of a stupid S-expression parser:\n\n```clojure\n(def number-parser (many+ (one-of+ \"1234567890\")))\n\n(def space-parser (is+ \" \"))\n\n(def word-parser (many+ (one-of+ \"qwertyuiopasdfghjklzxcvbnm\")))\n\n(defparser\n s-expr-parser+\n ()\n identity\n (combine+\n  [(is+ \"(\")\n   (some+ (or+ [number-parser word-parser space-parser (s-expr-parser+)]))\n   (is+ \")\")]))\n\n(parse-lilac (string/split \"(def a (add 1 2))\" \"\") (s-expr-parser+))\n```\n\n[More demos](https://github.com/mvc-works/lilac-parser/tree/master/src/lilac_parser/demo).\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.mvc-works.org/lilac-parser/).\n\n\u003cdetails\u003e\n\u003csummary\u003eAn example for EDN data in parsing a JSON number.\u003c/summary\u003e\n\u003cpre\u003e\u003ccode\u003e\n{\n  :ok? true, :value 112, :parser-node :component, :label :value-parser+\n  :rest (\",\" \"1\")\n  :result {\n    :ok? true, :value 112, :parser-node :or\n    :rest (\",\" \"1\")\n    :result {\n      :ok? true, :parser-node :label, :label \"number\", :value 112\n      :rest (\",\" \"1\")\n      :result {\n        :ok? true, :value 112, :parser-node :combine\n        :rest (\",\" \"1\")\n        :results [\n          {\n            :ok? true, :value nil, :parser-node :optional\n            :result {\n              :ok? false, :message \"expects \\\"-\\\" but got \\\"1\\\"\", :parser-node :is\n              :rest [\"1\" \"1\" \"2\" \",\" \"1\"]\n            }\n            :rest [\"1\" \"1\" \"2\" \",\" \"1\"]\n          }\n          {\n            :ok? true, :parser-node :many\n            :value (\"1\" \"1\" \"2\")\n            :rest (\",\" \"1\")\n            :results [\n              {\n                :ok? true, :value \"1\", :parser-node :one-of\n                :rest (\"1\" \"2\" \",\" \"1\")\n              }\n              {\n                :ok? true, :value \"1\", :parser-node :one-of\n                :rest (\"2\" \",\" \"1\")\n              }\n              {\n                :ok? true, :value \"2\", :parser-node :one-of\n                :rest (\",\" \"1\")\n              }\n            ]\n            :peek-result {\n              :ok? false, :message \"\\\",\\\" is not in \\\"1234567890\\\"\", :parser-node :one-of\n              :rest (\",\" \"1\")\n            }\n          }\n          {\n            :ok? true, :value nil, :parser-node :optional\n            :result {\n              :ok? false, :parser-node :combine, :message \"failed to combine\"\n              :result {\n                :ok? false, :message \"expects \\\".\\\" but got \\\",\\\"\", :parser-node :is\n                :rest (\",\" \"1\")\n              }\n              :previous-results []\n              :rest (\",\" \"1\")\n            }\n            :rest (\",\" \"1\")\n          }\n        ]\n      }\n    }\n  }\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/details\u003e\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```clojure\n(lilac-parser.core/resigter-custom-rule! :xyz\n  (fn [xs rule]\n    ; TODO\n    ))\n\n(defn xyz+ [xs transform]\n  ; TODO\n  )\n```\n\n### Replacer\n\nA function is also provided for replacing text pieces matching a given rule:\n\n```clojure\n(replace-lilac content rule (fn [x] (str \"\u003c\u003c\u003c\" x \"\u003e\u003e\u003e\u003e\")))\n```\n\nwhich returns `:result` as well as parsing details in `:attempts`:\n\n```edn\n{\n  :result \"\u003c\u003c\u003cMATCHED\u003e\u003e\u003e\u003e\"\n  :attempts [\n    ; parsing summaries in vector\n  ]\n}\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```clojure\n(find-lilac content rule)\n```\n\n### Workflow\n\nWorkflow https://github.com/mvc-works/calcit-workflow\n\n### License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmvc-works%2Flilac-parser","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmvc-works%2Flilac-parser","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmvc-works%2Flilac-parser/lists"}