{"id":20111951,"url":"https://github.com/mezoni/parser_combinator","last_synced_at":"2026-06-09T17:31:18.333Z","repository":{"id":184840401,"uuid":"672578542","full_name":"mezoni/parser_combinator","owner":"mezoni","description":"Parser combinator is a collection of parsers that can be used to combine basic parsers to create parsers for more complex rules.","archived":false,"fork":false,"pushed_at":"2023-08-31T19:12:02.000Z","size":175,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-22T20:10:31.291Z","etag":null,"topics":["dart","dart3","parser","parser-combinators","parser-library","parsers","parsing"],"latest_commit_sha":null,"homepage":"","language":"Dart","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/mezoni.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":"2023-07-30T15:03:52.000Z","updated_at":"2023-07-30T15:05:17.000Z","dependencies_parsed_at":"2025-03-02T18:41:23.889Z","dependency_job_id":"92e0b2cf-bb90-43f5-b92a-a48b4d7b243d","html_url":"https://github.com/mezoni/parser_combinator","commit_stats":null,"previous_names":["mezoni/parser_combinator"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mezoni/parser_combinator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mezoni%2Fparser_combinator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mezoni%2Fparser_combinator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mezoni%2Fparser_combinator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mezoni%2Fparser_combinator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mezoni","download_url":"https://codeload.github.com/mezoni/parser_combinator/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mezoni%2Fparser_combinator/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34118751,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-09T02:00:06.510Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["dart","dart3","parser","parser-combinators","parser-library","parsers","parsing"],"created_at":"2024-11-13T18:18:18.222Z","updated_at":"2026-06-09T17:31:18.315Z","avatar_url":"https://github.com/mezoni.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# parser_combinator\n\nParser combinator is a collection of parsers that can be used to combine basic parsers to create parsers for more complex rules.\n\nVersion: 0.2.9\n\n## About\n\nParser combinator is intended for general purpose use.  \nIt can be used not only to implement parsers, but also to create validators.  \nCombined parser do not require building and can be used immediately.  \nThe combined parser can be compiled into static code.  \nParsers declared as constants are evaluated at compile time.  \nSimple and understandable localization of error messages.  \nFully customizable parsing error tracking system during development for maximum convenience.  \nVery handy ways to track down parsing errors when tracing during development.  \nParsing character data not only from strings, but also from any other sources.  \n\n## Parsing\n\nThe general rule is that complex parsers are made up of less complex parsers.  \nThe simpler some part of the parser, the easier it is to imagine how it should work.  \nFor certain purposes, you can write a custom parser that will parse more efficiently than a combined parser.  \nOr, for example, you can implement a basic set for parsing some data (binary or that is directly in the file) and use them to parse such data.  \n\nThe simplest parsing example:\n\n```dart\nvoid main(List\u003cString\u003e args) {\n  const id = Recognize2(Satisfy(isAlpha), SkipWhile(isAlphanumeric));\n  print(parseString(id.parse, 'Abc'));\n  print(parseString(id.parse, 'xyz123'));\n\n  print(parseString(calc.parse, '1 + 2 * 3'));\n  print(parseString(calc.parse, '(1 + 2) * 3'));\n}\n\nconst calc = _expr;\n\nconst _add = ChainL1(_mul, _addOps, _mul, _toBinary);\n\nconst _addOps = Terminated(Tags(['-', '+']), _ws);\n\nconst _closeParenthesis = Terminated(Tag(')'), _ws);\n\nconst _expr = Ref(_exprRef);\n\nconst _mul = ChainL1(_primary, _mulOps, _primary, _toBinary);\n\nconst _mulOps = Terminated(Tags(['*', '/']), _ws);\n\nconst _number = Terminated(_number_, _ws);\n\nconst _number_ = Map1(Recognize2(Opt(Tag('-')), Digit1()), num.parse);\n\nconst _openParenthesis = Terminated(Tag('('), _ws);\n\nconst _primary =\n    Choice2(_number, Delimited(_openParenthesis, _expr, _closeParenthesis));\n\nconst _ws = SkipWhile(isWhitespace);\n\nParser\u003cStringReader, num\u003e _exprRef() =\u003e _add;\n\nnum _toBinary(num left, String op, num right) {\n  return switch (op) {\n    '-' =\u003e left - right,\n    '+' =\u003e left + right,\n    '*' =\u003e left * right,\n    '/' =\u003e left * right,\n    _ =\u003e throw ArgumentError.value(op, 'op'),\n  };\n}\n\n```\n\n## Parsing from files\n\nAn example of parsing from a text file.  \n\n```dart\nfinal file = File('test/temp.json');\nfinal fileReader = FileReader(file.openSync(), bufferSize: 1024);\nfinal utf8Reader = Utf8Reader(fileReader);\ntry {\n  return parseInput(json_parser.parser.parse, utf8Reader);\n} finally {\n  fileReader.fp.closeSync();\n}\n\n```\n\n## Localization\n\nLocalization is implemented through the use of translation through hash tables.  \nLocalization is supported at the translation level of error messages and tags used in error messages.  \nThis approach uses two independent tables.  \nOne table for translating messages, the other for translating tags.  \nTranslation is performed only for data for which information for translation is provided.  \n\nA complete example of the simplest parse localization.\n\n```dart\nvoid main(List\u003cString\u003e args) {\n  parse(r'\"abc\\u123xyz\"');\n  parse('{\"abc\": `123}');\n  parse('1.');\n}\n\nvoid parse(String text) {\n  print(text);\n  try {\n    parseString(parser, text, messages: _messages, tags: _tags);\n  } catch (e) {\n    print(e);\n    print('-' * 40);\n  }\n}\n\nfinal _tags = {\n  'decimal digit': 'десятичная цифра',\n  'number': 'число',\n  'string': 'строка',\n};\n\nconst _messages = {\n  ParserErrorMessages.expected4DigitHexadecimalNumber:\n      MessageLocalization(other: 'Ожидается 4-значное шестнадцатеричное число'),\n  ErrorExpectedCharacter.message:\n      MessageLocalization(other: 'Ожидается символ {0}'),\n  ErrorExpectedEndOfInput.message:\n      MessageLocalization(other: 'Ожидается конец входных данных'),\n  ErrorExpectedIntegerValue.message:\n      MessageLocalization(other: 'Ожидается целочисленное значение {0}'),\n  ErrorExpectedTags.message: MessageLocalization(\n    other: 'Ожидаются: {0}',\n    one: 'Ожидается: {0}',\n  ),\n  ErrorUnexpectedCharacter.message:\n      MessageLocalization(other: 'Неожиданный символ {0}'),\n  ErrorUnexpectedEndOfInput.message:\n      MessageLocalization(other: 'Неожиданный конец входных данных'),\n  ErrorUnexpectedInput.message:\n      MessageLocalization(other: 'Неожиданные входные данные'),\n  ErrorUnknownError.message: MessageLocalization(other: 'Неизвестная ошибка'),\n};\n\n```\n\nExample of displayed localized error messages (in Russian):\n\n```\n\"abc\\u123xyz\"\nFormatException: line 1, column 10: Неожиданный символ 'x' (0x78)\n\"abc\\u123xyz\"\n         ^\n\nline 1, column 7: Ожидается 4-значное шестнадцатеричное число\n\"abc\\u123xyz\"\n      ^^^\n----------------------------------------\n{\"abc\": `123}\nFormatException: line 1, column 9: Ожидаются: '[', 'false', 'null', 'true', '{', 'строка', 'число'\n{\"abc\": `123}\n        ^\n----------------------------------------\n1.\nFormatException: line 1, column 3: Неожиданный конец входных данных\n1.\n  ^\n\nline 1, column 3: Ожидается: 'десятичная цифра'\n1.\n  ^\n----------------------------------------\n\n```\n\n## Tracing\n\nTracing parsers is very easy. All you have to do is build a traceable parser.  \nBuilding a traceable parser is also very easy.  \n\nAn example of how to build a traceable parser:\n\n```dart\nfinal builder = TracerBuilder(fastParse: fastParse, parse: parse);\nfinal tracer = builder.build(parser);\n```\n\nTracer is the same regular parser that will invoke the appropriate methods (`fastParse` and `parse`) of all traced parsers (that is, it will trace the entire parsing process).\n\nAn example of how to trace parsing:\n\n```dart\nResult\u003cO\u003e? parse\u003cI, O\u003e(Parser\u003cI, O\u003e parser, State\u003cI\u003e state) {\n  stack.add(parser);\n  if (bps.check(name: parser.name)) {\n    print('breakpoint');\n  }\n\n  final result = parser.parse(state);\n  stack.removeLast();\n  return result;\n}\n\n```\n\nA complete example of a simple parse trace:\n\n```dart\nvoid main(List\u003cString\u003e args) {\n  final bps = Breakpoints();\n  bps.add(name: 'fraction');\n  bps.add(name: 'integer');\n  final stack = \u003cObject?\u003e[];\n  bool fastParse\u003cI, O\u003e(Parser\u003cI, O\u003e parser, State\u003cI\u003e state) {\n    stack.add(parser);\n    if (bps.check(name: parser.name)) {\n      print('breakpoint');\n    }\n\n    final result = parser.fastParse(state);\n    stack.removeLast();\n    return result;\n  }\n\n  Result\u003cO\u003e? parse\u003cI, O\u003e(Parser\u003cI, O\u003e parser, State\u003cI\u003e state) {\n    stack.add(parser);\n    if (bps.check(name: parser.name)) {\n      print('breakpoint');\n    }\n\n    final result = parser.parse(state);\n    stack.removeLast();\n    return result;\n  }\n\n  final builder = TracerBuilder(fastParse: fastParse, parse: parse);\n  final tracer = builder.build(example.parser);\n  final result = tracer.parseString('1.');\n  print(result);\n}\n\n```\n\n## Generating source code from code\n\nIt is possible to generate valid code from most parsers.  \n\nAn example of generated code.  \n\n```dart\nbool _tag2(State\u003cStringReader\u003e state) {\n  const p = _i1.Tag.parseTag;\n  const tag = 'false';\n  return p(state, tag);\n}\n\nbool _terminated2(State\u003cStringReader\u003e state) {\n  final pos = state.pos;\n  final r1 = _tag2(state);\n  if (r1) {\n    final r2 = _ws(state);\n    if (r2) {\n      return true;\n    }\n\n    state.pos = pos;\n  }\n\n  return false;\n}\n\nResult\u003cbool\u003e? _false(State\u003cStringReader\u003e state) {\n  const value = false;\n  final r = _terminated2(state);\n  if (r) {\n    return Result(value);\n  }\n\n  return null;\n}\n\n```\n\nAn example of how the code can be generated can be found in the `tool` directory.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmezoni%2Fparser_combinator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmezoni%2Fparser_combinator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmezoni%2Fparser_combinator/lists"}