{"id":13508472,"url":"https://github.com/princemaple/abnf_parsec","last_synced_at":"2025-04-04T20:14:26.080Z","repository":{"id":41758846,"uuid":"235097784","full_name":"princemaple/abnf_parsec","owner":"princemaple","description":"ABNF in, parser out","archived":false,"fork":false,"pushed_at":"2025-04-02T08:42:43.000Z","size":186,"stargazers_count":53,"open_issues_count":4,"forks_count":3,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-04T14:49:48.933Z","etag":null,"topics":["abnf","elixir","parser-generator","parsing"],"latest_commit_sha":null,"homepage":"https://hexdocs.pm/abnf_parsec/AbnfParsec.html","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/princemaple.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","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":"2020-01-20T12:35:50.000Z","updated_at":"2025-04-02T08:42:57.000Z","dependencies_parsed_at":"2023-01-21T09:47:27.654Z","dependency_job_id":"4f383013-8b1a-4a34-ad61-b13d476d6805","html_url":"https://github.com/princemaple/abnf_parsec","commit_stats":{"total_commits":166,"total_committers":7,"mean_commits":"23.714285714285715","dds":"0.35542168674698793","last_synced_commit":"0b63964278453b13807c9cbccf26e852d5b8cb3e"},"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/princemaple%2Fabnf_parsec","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/princemaple%2Fabnf_parsec/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/princemaple%2Fabnf_parsec/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/princemaple%2Fabnf_parsec/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/princemaple","download_url":"https://codeload.github.com/princemaple/abnf_parsec/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247198435,"owners_count":20900079,"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":["abnf","elixir","parser-generator","parsing"],"created_at":"2024-08-01T02:00:53.489Z","updated_at":"2025-04-04T20:14:26.058Z","avatar_url":"https://github.com/princemaple.png","language":"Elixir","funding_links":[],"categories":["Lexical analysis"],"sub_categories":[],"readme":"# AbnfParsec\n\n[![hex.pm](https://img.shields.io/hexpm/v/abnf_parsec.svg)](https://hex.pm/packages/abnf_parsec)\n[![hex.pm](https://img.shields.io/hexpm/dt/abnf_parsec.svg)](https://hex.pm/packages/abnf_parsec)\n[![hex.pm](https://img.shields.io/hexpm/l/abnf_parsec.svg)](https://hex.pm/packages/abnf_parsec)\n[![github.com](https://img.shields.io/github/last-commit/princemaple/abnf_parsec.svg)](https://github.com/princemaple/abnf_parsec)\n\n### ABNF in and parser out.\n\nParses ABNF with a parser written with `nimble_parsec`, emits parser consists of `nimble_parsec` combinators.\n\n## Features\n\n- Brevity - flattens unnecessary nesting in parsed ABNF\n- Easy to config and customize\n- Full test coverage\n\n## Installation\n\nThe [package](https://hex.pm/packages/abnf_parsec) is available on [Hex](https://hex.pm)\nand can be installed by adding `abnf_parsec` to your list of dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:abnf_parsec, \"~\u003e 2.0\", runtime: false}\n  ]\nend\n```\n\nDocumentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)\nand published on [HexDocs](https://hexdocs.pm). Once published, the docs can\nbe found at [https://hexdocs.pm/abnf_parsec](https://hexdocs.pm/abnf_parsec).\n\n## Text / Byte mode\n\nIn some RFCs, literals in ABNF could be used to describe the byte representation instead of\nthe text codepoints. There is no clear distinction between them for us to detect automatically.\nHence a text / byte mode is added for the user to set.\n\n```elixir\ndefmodule TextParser do\n  use AbnfParsec,\n    mode: :text, # the default, can be omitted\n    abnf: \"\"\"\n    ucschar = %xA0-D7FF / %xF900-FDCF / %xFDF0-FFEF\n      / %x10000-1FFFD / %x20000-2FFFD / %x30000-3FFFD\n      / %x40000-4FFFD / %x50000-5FFFD / %x60000-6FFFD\n      / %x70000-7FFFD / %x80000-8FFFD / %x90000-9FFFD\n      / %xA0000-AFFFD / %xB0000-BFFFD / %xC0000-CFFFD\n      / %xD0000-DFFFD / %xE1000-EFFFD\n    \"\"\"\nend\n\ndefmodule ByteParser do\n  use AbnfParsec,\n    mode: :byte,\n    abnf: \"\"\"\n    ; from RFC 5322 + UTF8-non-ascii\n    atext = ALPHA / DIGIT / \"!\" / \"#\" / \"$\" / \"%\" / \"\u0026\" / \"'\" / \"*\" / \"+\" /\n      \"-\" / \"/\" / \"=\" / \"?\" / \"^\" / \"_\" / \"`\" / \"{\" / \"|\" / \"}\" / \"~\" / UTF8-non-ascii\n\n    ; from RFC 3629\n    UTF8-non-ascii  =   UTF8-2 / UTF8-3 / UTF8-4\n\n    UTF8-2      = %xC2-DF UTF8-tail\n    UTF8-3      = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /\n          %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )\n    UTF8-4      = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /\n          %xF4 %x80-8F 2( UTF8-tail )\n    UTF8-tail   = %x80-BF\n    \"\"\"\nend\n```\n\n## Usage\n\n```elixir\ndefmodule IPv4Parser do\n  use AbnfParsec,\n    abnf: \"\"\"\n    ip = first dot second dot third dot fourth\n    dot = \".\"\n    dec-octet =\n      \"25\" %x30-35      /   ; 250-255\n      \"2\" %x30-34 DIGIT /   ; 200-249\n      \"1\" 2DIGIT        /   ; 100-199\n      %x31-39 DIGIT     /   ; 10-99\n      DIGIT                 ; 0-9\n    first = dec-octet\n    second = dec-octet\n    third = dec-octet\n    fourth = dec-octet\n    \"\"\",\n    unbox: [\"dec-octet\"],\n    ignore: [\"dot\"],\n    parse: :ip\nend\n\n# IPv4Parser.ip(\"192.168.0.1\")\n# IPv4Parser.parse(\"127.0.0.1\")\n# IPv4Parser.parse!(\"10.0.0.1\")\n\niex\u003e IPv4Parser.parse! \"10.0.0.1\"\n[ip: [first: '10', second: '0', third: '0', fourth: '1']]\n```\n\n```elixir\ndefmodule JsonParser do\n  use AbnfParsec,\n    abnf_file: \"test/fixture/json.abnf\",\n    parse: :json_text,\n    transform: %{\n      \"string\" =\u003e {:reduce, {List, :to_string, []}},\n      \"int\" =\u003e [{:reduce, {List, :to_string, []}}, {:map, {String, :to_integer, []}}],\n      \"frac\" =\u003e {:reduce, {List, :to_string, []}},\n      \"null\" =\u003e {:replace, nil},\n      \"true\" =\u003e {:replace, true},\n      \"false\" =\u003e {:replace, false}\n    },\n    untag: [\"member\"],\n    unwrap: [\"int\", \"frac\"],\n    unbox: [\n      \"JSON-text\",\n      \"null\",\n      \"true\",\n      \"false\",\n      \"digit1-9\",\n      \"decimal-point\",\n      \"escape\",\n      \"unescaped\",\n      \"char\"\n    ],\n    ignore: [\n      \"name-separator\",\n      \"value-separator\",\n      \"quotation-mark\",\n      \"begin-object\",\n      \"end-object\",\n      \"begin-array\",\n      \"end-array\"\n    ]\nend\n\njson = \"\"\"\n  {\"a\": {\"b\": 1, \"c\": [true]}, \"d\": null, \"e\": \"e\\\\te\"}\n  \"\"\"\n\n# JsonParser.json_text(json)\n# JsonParser.parse(json)\n# JsonParser.parse!(json)\n\niex\u003e JsonParser.parse! \"\"\"\n...\u003e {\"a\": {\"b\": 1, \"c\": [true]}, \"d\": null, \"e\": \"e\\\\te\"}\n...\u003e \"\"\"\n[\n  object: [\n    [\n      string: [\"a\"],\n      value: [\n        object: [\n          [string: [\"b\"], value: [number: [int: 1]]],\n          [string: [\"c\"], value: [array: [value: [true]]]]\n        ]\n      ]\n    ],\n    [string: [\"d\"], value: [nil]],\n    [string: [\"e\"], value: [string: [\"e\\\\te\"]]]\n  ]\n]\n```\n\nFor more details of options for customization, see [abnf_parsec.ex](https://github.com/princemaple/abnf_parsec/blob/main/lib/abnf_parsec.ex)\n\n## What does it do, really?\n\nFor example, ABNF of ABNF 😉 is parsed\n\n```\nrulelist       =  1*( rule / (*c-wsp c-nl) )\n\nrule           =  rulename defined-as elements c-nl\n                      ; continues if next line starts\n                      ;  with white space\n\nrulename       =  ALPHA *(ALPHA / DIGIT / \"-\")\n\ndefined-as     =  *c-wsp (\"=\" / \"=/\") *c-wsp\n                      ; basic rules definition and\n                      ;  incremental alternatives\n\nelements       =  alternation *c-wsp\n\nc-wsp          =  WSP / (c-nl WSP)\n\nc-nl           =  comment / CRLF\n                      ; comment or newline\n\ncomment        =  \";\" *(WSP / VCHAR) CRLF\n\nalternation    =  concatenation\n                 *(*c-wsp \"/\" *c-wsp concatenation)\n\nconcatenation  =  repetition *(1*c-wsp repetition)\n\nrepetition     =  [repeat] element\n\nrepeat         =  1*DIGIT / (*DIGIT \"*\" *DIGIT)\n\nelement        =  rulename / group / option /\n                 char-val / num-val / prose-val\n\ngroup          =  \"(\" *c-wsp alternation *c-wsp \")\"\n\noption         =  \"[\" *c-wsp alternation *c-wsp \"]\"\n\nchar-val       =  DQUOTE *(%x20-21 / %x23-7E) DQUOTE\n                      ; quoted string of SP and VCHAR\n                      ;  without DQUOTE\n\nnum-val        =  \"%\" (bin-val / dec-val / hex-val)\n\nbin-val        =  \"b\" 1*BIT\n                 [ 1*(\".\" 1*BIT) / (\"-\" 1*BIT) ]\n                      ; series of concatenated bit values\n                      ;  or single ONEOF range\n\ndec-val        =  \"d\" 1*DIGIT\n                 [ 1*(\".\" 1*DIGIT) / (\"-\" 1*DIGIT) ]\n\nhex-val        =  \"x\" 1*HEXDIG\n                 [ 1*(\".\" 1*HEXDIG) / (\"-\" 1*HEXDIG) ]\n\nprose-val      =  \"\u003c\" *(%x20-3D / %x3F-7E) \"\u003e\"\n                      ; bracketed string of SP and VCHAR\n                      ;  without angles\n                      ; prose description, to be used as\n                      ;  last resort\n```\n\ninto\n\n```elixir\n[\n  rule: [\n    rulename: \"rulelist\",\n    repetition: [\n      repeat: [min: 1],\n      alternation: [\n        rulename: \"rule\",\n        concatenation: [\n          repetition: [repeat: [], rulename: \"c-wsp\"],\n          rulename: \"c-nl\"\n        ]\n      ]\n    ]\n  ],\n  rule: [\n    rulename: \"rule\",\n    concatenation: [\n      rulename: \"rulename\",\n      rulename: \"defined-as\",\n      rulename: \"elements\",\n      rulename: \"c-nl\"\n    ],\n    comment: \"continues if next line starts\",\n    comment: \"with white space\"\n  ],\n  rule: [\n    rulename: \"rulename\",\n    concatenation: [\n      rulename: \"ALPHA\",\n      repetition: [\n        repeat: [],\n        alternation: [{:rulename, \"ALPHA\"}, {:rulename, \"DIGIT\"}, \"-\"]\n      ]\n    ]\n  ],\n  rule: [\n    rulename: \"defined-as\",\n    concatenation: [\n      repetition: [repeat: [], rulename: \"c-wsp\"],\n      alternation: [\"=\", \"=/\"],\n      repetition: [repeat: [], rulename: \"c-wsp\"]\n    ],\n    comment: \"basic rules definition and\",\n    comment: \"incremental alternatives\"\n  ],\n  rule: [\n    rulename: \"elements\",\n    concatenation: [\n      rulename: \"alternation\",\n      repetition: [repeat: [], rulename: \"c-wsp\"]\n    ]\n  ],\n  rule: [\n    rulename: \"c-wsp\",\n    alternation: [\n      rulename: \"WSP\",\n      concatenation: [rulename: \"c-nl\", rulename: \"WSP\"]\n    ]\n  ],\n  rule: [\n    rulename: \"c-nl\",\n    alternation: [rulename: \"comment\", rulename: \"CRLF\"],\n    comment: \"comment or newline\"\n  ],\n  rule: [\n    rulename: \"comment\",\n    concatenation: [\n      \";\",\n      {:repetition,\n       [repeat: [], alternation: [rulename: \"WSP\", rulename: \"VCHAR\"]]},\n      {:rulename, \"CRLF\"}\n    ]\n  ],\n  rule: [\n    rulename: \"alternation\",\n    concatenation: [\n      rulename: \"concatenation\",\n      repetition: [\n        repeat: [],\n        concatenation: [\n          {:repetition, [repeat: [], rulename: \"c-wsp\"]},\n          \"/\",\n          {:repetition, [repeat: [], rulename: \"c-wsp\"]},\n          {:rulename, \"concatenation\"}\n        ]\n      ]\n    ]\n  ],\n  rule: [\n    rulename: \"concatenation\",\n    concatenation: [\n      rulename: \"repetition\",\n      repetition: [\n        repeat: [],\n        concatenation: [\n          repetition: [repeat: [min: 1], rulename: \"c-wsp\"],\n          rulename: \"repetition\"\n        ]\n      ]\n    ]\n  ],\n  rule: [\n    rulename: \"repetition\",\n    concatenation: [option: [rulename: \"repeat\"], rulename: \"element\"]\n  ],\n  rule: [\n    rulename: \"repeat\",\n    alternation: [\n      repetition: [repeat: [min: 1], rulename: \"DIGIT\"],\n      concatenation: [\n        {:repetition, [repeat: [], rulename: \"DIGIT\"]},\n        \"*\",\n        {:repetition, [repeat: [], rulename: \"DIGIT\"]}\n      ]\n    ]\n  ],\n  rule: [\n    rulename: \"element\",\n    alternation: [\n      rulename: \"rulename\",\n      rulename: \"group\",\n      rulename: \"option\",\n      rulename: \"char-val\",\n      rulename: \"num-val\",\n      rulename: \"prose-val\"\n    ]\n  ],\n  rule: [\n    rulename: \"group\",\n    concatenation: [\n      \"(\",\n      {:repetition, [repeat: [], rulename: \"c-wsp\"]},\n      {:rulename, \"alternation\"},\n      {:repetition, [repeat: [], rulename: \"c-wsp\"]},\n      \")\"\n    ]\n  ],\n  rule: [\n    rulename: \"option\",\n    concatenation: [\n      \"[\",\n      {:repetition, [repeat: [], rulename: \"c-wsp\"]},\n      {:rulename, \"alternation\"},\n      {:repetition, [repeat: [], rulename: \"c-wsp\"]},\n      \"]\"\n    ]\n  ],\n  rule: [\n    rulename: \"char-val\",\n    concatenation: [\n      rulename: \"DQUOTE\",\n      repetition: [\n        repeat: [],\n        alternation: [\n          num_range: [{:base, \"x\"}, \"20\", \"21\"],\n          num_range: [{:base, \"x\"}, \"23\", \"7E\"]\n        ]\n      ],\n      rulename: \"DQUOTE\"\n    ],\n    comment: \"quoted string of SP and VCHAR\",\n    comment: \"without DQUOTE\"\n  ],\n  rule: [\n    rulename: \"num-val\",\n    concatenation: [\n      \"%\",\n      {:alternation,\n       [rulename: \"bin-val\", rulename: \"dec-val\", rulename: \"hex-val\"]}\n    ]\n  ],\n  rule: [\n    rulename: \"bin-val\",\n    concatenation: [\n      \"b\",\n      {:repetition, [repeat: [min: 1], rulename: \"BIT\"]},\n      {:option,\n       [\n         alternation: [\n           repetition: [\n             repeat: [min: 1],\n             concatenation: [\n               \".\",\n               {:repetition, [repeat: [min: 1], rulename: \"BIT\"]}\n             ]\n           ],\n           concatenation: [\n             \"-\",\n             {:repetition, [repeat: [min: 1], rulename: \"BIT\"]}\n           ]\n         ]\n       ]}\n    ],\n    comment: \"series of concatenated bit values\",\n    comment: \"or single ONEOF range\"\n  ],\n  rule: [\n    rulename: \"dec-val\",\n    concatenation: [\n      \"d\",\n      {:repetition, [repeat: [min: 1], rulename: \"DIGIT\"]},\n      {:option,\n       [\n         alternation: [\n           repetition: [\n             repeat: [min: 1],\n             concatenation: [\n               \".\",\n               {:repetition, [repeat: [min: 1], rulename: \"DIGIT\"]}\n             ]\n           ],\n           concatenation: [\n             \"-\",\n             {:repetition, [repeat: [min: 1], rulename: \"DIGIT\"]}\n           ]\n         ]\n       ]}\n    ]\n  ],\n  rule: [\n    rulename: \"hex-val\",\n    concatenation: [\n      \"x\",\n      {:repetition, [repeat: [min: 1], rulename: \"HEXDIG\"]},\n      {:option,\n       [\n         alternation: [\n           repetition: [\n             repeat: [min: 1],\n             concatenation: [\n               \".\",\n               {:repetition, [repeat: [min: 1], rulename: \"HEXDIG\"]}\n             ]\n           ],\n           concatenation: [\n             \"-\",\n             {:repetition, [repeat: [min: 1], rulename: \"HEXDIG\"]}\n           ]\n         ]\n       ]}\n    ]\n  ],\n  rule: [\n    rulename: \"prose-val\",\n    concatenation: [\n      \"\u003c\",\n      {:repetition,\n       [\n         repeat: [],\n         alternation: [\n           num_range: [{:base, \"x\"}, \"20\", \"3D\"],\n           num_range: [{:base, \"x\"}, \"3F\", \"7E\"]\n         ]\n       ]},\n      \"\u003e\"\n    ],\n    comment: \"bracketed string of SP and VCHAR\",\n    comment: \"without angles\",\n    comment: \"prose description, to be used as\",\n    comment: \"last resort\"\n  ]\n]\n```\n\nAnd generated parser looks something like (outdated but close enough):\n\n```elixir\n[\n  defparsec(\n    :rulelist,\n    tag(\n      times(choice([parsec(:rule), repeat(parsec(:c_wsp)) |\u003e parsec(:c_nl)]), min: 1),\n      :rulelist\n    )\n  ),\n  defparsec(\n    :rule,\n    tag(parsec(:rulename) |\u003e parsec(:defined_as) |\u003e parsec(:elements) |\u003e parsec(:c_nl), :rule)\n  ),\n  defparsec(\n    :rulename,\n    tag(\n      parsec(:core_alpha)\n      |\u003e repeat(choice([parsec(:core_alpha), parsec(:core_digit), string(\"-\")])),\n      :rulename\n    )\n  ),\n  defparsec(\n    :defined_as,\n    tag(\n      repeat(parsec(:c_wsp)) |\u003e choice([string(\"=\"), string(\"=/\")]) |\u003e repeat(parsec(:c_wsp)),\n      :defined_as\n    )\n  ),\n  defparsec(:elements, tag(parsec(:alternation) |\u003e repeat(parsec(:c_wsp)), :elements)),\n  defparsec(:c_wsp, tag(choice([parsec(:core_wsp), parsec(:c_nl) |\u003e parsec(:core_wsp)]), :c_wsp)),\n  defparsec(:c_nl, tag(choice([parsec(:comment), parsec(:core_crlf)]), :c_nl)),\n  defparsec(\n    :comment,\n    tag(\n      string(\";\")\n      |\u003e repeat(choice([parsec(:core_wsp), parsec(:core_vchar)]))\n      |\u003e parsec(:core_crlf),\n      :comment\n    )\n  ),\n  defparsec(\n    :alternation,\n    tag(\n      parsec(:concatenation)\n      |\u003e repeat(\n        repeat(parsec(:c_wsp))\n        |\u003e string(\"/\")\n        |\u003e repeat(parsec(:c_wsp))\n        |\u003e parsec(:concatenation)\n      ),\n      :alternation\n    )\n  ),\n  defparsec(\n    :concatenation,\n    tag(\n      parsec(:repetition) |\u003e repeat(times(parsec(:c_wsp), min: 1) |\u003e parsec(:repetition)),\n      :concatenation\n    )\n  ),\n  defparsec(:repetition, tag(optional(parsec(:repeat)) |\u003e parsec(:element), :repetition)),\n  defparsec(\n    :repeat,\n    tag(\n      choice([\n        times(parsec(:core_digit), min: 1),\n        repeat(parsec(:core_digit)) |\u003e string(\"*\") |\u003e repeat(parsec(:core_digit))\n      ]),\n      :repeat\n    )\n  ),\n  defparsec(\n    :element,\n    tag(\n      choice([\n        parsec(:rulename),\n        parsec(:group),\n        parsec(:option),\n        parsec(:char_val),\n        parsec(:num_val),\n        parsec(:prose_val)\n      ]),\n      :element\n    )\n  ),\n  defparsec(\n    :group,\n    tag(\n      string(\"(\")\n      |\u003e repeat(parsec(:c_wsp))\n      |\u003e parsec(:alternation)\n      |\u003e repeat(parsec(:c_wsp))\n      |\u003e string(\")\"),\n      :group\n    )\n  ),\n  defparsec(\n    :option,\n    tag(\n      string(\"[\")\n      |\u003e repeat(parsec(:c_wsp))\n      |\u003e parsec(:alternation)\n      |\u003e repeat(parsec(:c_wsp))\n      |\u003e string(\"]\"),\n      :option\n    )\n  ),\n  defparsec(\n    :char_val,\n    tag(\n      parsec(:core_dquote)\n      |\u003e repeat(choice([ascii_char([32..33]), ascii_char([35..126])]))\n      |\u003e parsec(:core_dquote),\n      :char_val\n    )\n  ),\n  defparsec(\n    :num_val,\n    tag(string(\"%\") |\u003e choice([parsec(:bin_val), parsec(:dec_val), parsec(:hex_val)]), :num_val)\n  ),\n  defparsec(\n    :bin_val,\n    tag(\n      string(\"b\")\n      |\u003e times(parsec(:core_bit), min: 1)\n      |\u003e optional(\n        choice([\n          times(string(\".\") |\u003e times(parsec(:core_bit), min: 1), min: 1),\n          string(\"-\") |\u003e times(parsec(:core_bit), min: 1)\n        ])\n      ),\n      :bin_val\n    )\n  ),\n  defparsec(\n    :dec_val,\n    tag(\n      string(\"d\")\n      |\u003e times(parsec(:core_digit), min: 1)\n      |\u003e optional(\n        choice([\n          times(string(\".\") |\u003e times(parsec(:core_digit), min: 1), min: 1),\n          string(\"-\") |\u003e times(parsec(:core_digit), min: 1)\n        ])\n      ),\n      :dec_val\n    )\n  ),\n  defparsec(\n    :hex_val,\n    tag(\n      string(\"x\")\n      |\u003e times(parsec(:core_hexdig), min: 1)\n      |\u003e optional(\n        choice([\n          times(string(\".\") |\u003e times(parsec(:core_hexdig), min: 1), min: 1),\n          string(\"-\") |\u003e times(parsec(:core_hexdig), min: 1)\n        ])\n      ),\n      :hex_val\n    )\n  ),\n  defparsec(\n    :prose_val,\n    tag(\n      string(\"\u003c\") |\u003e repeat(choice([ascii_char([32..61]), ascii_char([63..126])])) |\u003e string(\"\u003e\"),\n      :prose_val\n    )\n  )\n]\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprincemaple%2Fabnf_parsec","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprincemaple%2Fabnf_parsec","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprincemaple%2Fabnf_parsec/lists"}