{"id":15293185,"url":"https://github.com/mezoni/parser_builder_lite","last_synced_at":"2025-03-24T12:40:29.974Z","repository":{"id":138227080,"uuid":"594657571","full_name":"mezoni/parser_builder_lite","owner":"mezoni","description":"Parser Builder Lite is a source code generator of high performance real-time parsers.","archived":false,"fork":false,"pushed_at":"2023-09-01T17:36:32.000Z","size":364,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-01T03:49:29.296Z","etag":null,"topics":["dart","dart3","dartlang","parser","parser-combinators","parser-generator","parsers","peg"],"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-01-29T08:21:09.000Z","updated_at":"2023-07-21T19:30:20.000Z","dependencies_parsed_at":"2024-10-14T21:41:33.170Z","dependency_job_id":"c971ff30-1cd5-425e-bbfe-f90682394fbe","html_url":"https://github.com/mezoni/parser_builder_lite","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mezoni%2Fparser_builder_lite","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mezoni%2Fparser_builder_lite/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mezoni%2Fparser_builder_lite/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mezoni%2Fparser_builder_lite/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mezoni","download_url":"https://codeload.github.com/mezoni/parser_builder_lite/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245273136,"owners_count":20588528,"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":["dart","dart3","dartlang","parser","parser-combinators","parser-generator","parsers","peg"],"created_at":"2024-09-30T16:40:11.184Z","updated_at":"2025-03-24T12:40:29.944Z","avatar_url":"https://github.com/mezoni.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# parser_builder_lite\n\nParser Builder Lite is a source code generator of high performance real-time parsers.\n\nVersion: 0.7.3\n\n## What is it and what is it for?\n\nParser Builder is intended to quickly implement (and test) parsers through source code templates.  \nThe main features and advantage:\n- A very simple builder is used to build parsers\n- Parsers are generated as source code\n- The generated parsers are very fast and efficient (as if they were written by hand)\n- The `SmartChoice` parser builder increases the performance of parsing by looking one character ahead\n- The `SequenceBase` can efficiently generate an unlimited number of combinations of parser sequences\n- On-demand memoization almost without delay in real-time\n- The error reporting system is very flexible and informative\n- Convenient and easy debugging of the parsing process\n- A simple and convenient test generator is included\n\n## Parser builder example\n\nA typical example of a parser builder (with static template).\n\n```dart\nimport '../helper.dart';\nimport '../parser_builder.dart';\n\nclass Many\u003cI, O\u003e extends ParserBuilder\u003cI, List\u003cO\u003e\u003e {\n  static const _template = '''\nfinal @list = \u003c@O\u003e[];\nwhile (true) {\n  @p1\n  if (!state.ok) {\n    break;\n  }\n  @list.add(@rv1);\n}\nif (state.ok = true) {\n  @r = @list;\n}''';\n\n  static const _templateNoResult = '''\nwhile (true) {\n  @p1\n  if (!state.ok) {\n    break;\n  }\n}\nstate.ok = true;''';\n\n  final ParserBuilder\u003cI, O\u003e p;\n\n  const Many(this.p);\n\n  @override\n  bool get isOptional =\u003e true;\n\n  @override\n  BuildBodyResult buildBody(BuildContext context, bool hasResult) {\n    checkIsNotOptional(p);\n    return renderBody(\n      this,\n      context,\n      hasResult,\n      _template,\n      _templateNoResult,\n      {'O': '$O'},\n    );\n  }\n\n  @override\n  Iterable\u003c(ParserBuilder\u003cI, Object?\u003e, bool?)\u003e getCombinedParsers() {\n    return [(p, null)];\n  }\n}\n\n```\n\n## Parser builder usage example\n\nA typical example of using a parser builder.\n\n```dart\nconst _object = Named(\n    '_object',\n    Mapped(\n      Tuple3(\n        _openBrace,\n        _keyValues,\n        _closeBrace,\n      ),\n      Expr\u003cMap\u003cString, Object?\u003e\u003e(r'Map.fromEntries({{0}}.$2)'),\n    ));\n\n```\n\nAn example of the generated source code.\n\n```dart\nMap\u003cString, Object?\u003e? _object(State\u003cString\u003e state) {\n  Map\u003cString, Object?\u003e? $0;\n  (String, List\u003cMapEntry\u003cString, Object?\u003e\u003e, String)? $1;\n  final pos$0 = state.pos;\n  String? $2;\n  // =\u003e _openBrace\n  final pos$1 = state.pos;\n  String? $3;\n  const tag$0 = '{';\n  if (state.ok = state.pos + 1 \u003c= state.input.length \u0026\u0026\n      state.input.codeUnitAt(state.pos) == 123) {\n    state.pos += 1;\n    $3 = tag$0;\n  } else {\n    state.fail(const ErrorExpectedTags([tag$0]));\n  }\n  if (state.ok) {\n    _ws(state);\n    if (state.ok) {\n      $2 = $3;\n    } else {\n      state.pos = pos$1;\n    }\n  }\n  // \u003c= _openBrace\n  if (state.ok) {\n    List\u003cMapEntry\u003cString, Object?\u003e\u003e? $5;\n    $5 = _keyValues(state);\n    if (state.ok) {\n      String? $32;\n      // =\u003e _closeBrace\n      final pos$12 = state.pos;\n      String? $33;\n      const tag$6 = '}';\n      if (state.ok = state.pos + 1 \u003c= state.input.length \u0026\u0026\n          state.input.codeUnitAt(state.pos) == 125) {\n        state.pos += 1;\n        $33 = tag$6;\n      } else {\n        state.fail(const ErrorExpectedTags([tag$6]));\n      }\n      if (state.ok) {\n        _ws(state);\n        if (state.ok) {\n          $32 = $33;\n        } else {\n          state.pos = pos$12;\n        }\n      }\n      // \u003c= _closeBrace\n      if (state.ok) {\n        $1 = ($2!, $5!, $32!);\n      }\n    }\n  }\n  if (!state.ok) {\n    state.pos = pos$0;\n  }\n  if (state.ok) {\n    final v = $1!;\n    $0 = Map.fromEntries(v.$2);\n  }\n  return $0;\n}\n\n```\n\n## Fast build example\n\nA typical example of a source code builder.\n\n```dart\nFuture\u003cvoid\u003e main(List\u003cString\u003e args) async {\n  await fastBuild(\n    context: BuildContext(\n      allocator: Allocator('_p'),\n      output: StringBuffer(),\n    ),\n    filename: 'example/json_parser.dart',\n    footer: __footer,\n    header: __header,\n    parsers: [json, _value_],\n  );\n}\n\n```\n\n## Error reporting\n\nAll errors are generated automatically.  \nBut if you need elegant error messages, then you can use the built-in parsers for this, which generate more informative error messages.  \nOr you can always write your own parser builder for this purpose.  \nMoreover, this parser builder will be the same as all the others, no different from any other.  \n\nError handling customization example:  \n\n```dart\nconst _hexValueChecked = Named(\n    '_hexValueChecked',\n    ReplaceErrors(\n      _hexValue,\n      Expr(\n          \"(true, [ErrorMessage({{1}} - {{0}}, 'Expected 4 digit hexadecimal number')])\"),\n    ));\n\n```\n\nData source (JSON):  \n\n```\n\"abc\\u123  \"\n```\n\nError report:  \n\n```\nline 1, column 7: Expected 4 digit hexadecimal number\n\"abc\\u123  \"\n      ^^^\n```\n\nAn example of standard error messages.  \nError messages will directly depend on the selected parsing algorithm.  \n\nData source (JSON):  \n\n```\n{\"rocket\": \"🚀 flies to the stars}\n```\n\nError report:  \n\n```\nline 1, column 35: Unexpected end of file\n{\"rocket\": \"🚀 flies to the stars}\n                                  ^\n\nline 1, column 35: Expected '\"'\n{\"rocket\": \"🚀 flies to the stars}\n                                  ^\n```\n\n## Parser test generator\n\nExample of usage:\n\n```dart\nimport 'package:parser_builder_lite/allocator.dart';\nimport 'package:parser_builder_lite/fast_build.dart';\nimport 'package:parser_builder_lite/parser/char.dart';\nimport 'package:parser_builder_lite/parser/many.dart';\nimport 'package:parser_builder_lite/parser/preceded.dart';\nimport 'package:parser_builder_lite/parser_builder.dart';\nimport 'package:parser_builder_lite/parser_tester.dart';\n\nvoid main(List\u003cString\u003e args) async {\n  await _generate();\n}\n\nconst _footer = '''\n''';\n\nconst _header = '''\n// ignore_for_file: non_constant_identifier_names\n// ignore_for_file: inference_failure_on_collection_literal\n// ignore_for_file: unnecessary_cast\n\nimport 'package:test/test.dart' hide escape;\n''';\n\nconst _prefix = '';\n\nFuture\u003cvoid\u003e _generate() async {\n  final context = BuildContext(\n    globalAllocator: Allocator('_'),\n    globalOutput: StringBuffer(),\n    localAllocator: Allocator(''),\n  );\n  final tester = ParserTester\u003cString\u003e(\n    context: context,\n    localOutput: StringBuffer(),\n  );\n  tester.addTest('Many', const Many(Char(0x31)), (\n    parserName,\n    parserNameNoResult,\n    parser,\n    parserNoResult,\n  ) {\n    final buffer = StringBuffer();\n    final t1 = ParserTest(\n      allocator: Allocator(_prefix),\n      context: context,\n      output: buffer,\n      parser: parser,\n      parserNameNoResult: parserNameNoResult,\n      parserName: parserName,\n      parserNoResult: parserNoResult,\n    );\n    t1.testSuccess(\n      input: '1112',\n      result: [0x31, 0x31, 0x31],\n      pos: 3,\n    );\n    t1.testSuccess(\n      input: '',\n      result: [],\n      pos: 0,\n    );\n    t1.testSuccess(\n      input: '2',\n      result: [],\n      pos: 0,\n    );\n    return buffer.toString();\n  });\n\n  tester.addTest('Preceded', const Preceded(Char(0x31), Char(0x32)), (\n    parserName,\n    parserNameNoResult,\n    parser,\n    parserNoResult,\n  ) {\n    final buffer = StringBuffer();\n    final t1 = ParserTest(\n      allocator: Allocator(_prefix),\n      context: context,\n      output: buffer,\n      parser: parser,\n      parserNameNoResult: parserNameNoResult,\n      parserName: parserName,\n      parserNoResult: parserNoResult,\n    );\n    t1.testSuccess(\n      input: '123',\n      result: 0x32,\n      pos: 2,\n    );\n    t1.testFailure(\n      input: '',\n      failPos: 0,\n      pos: 0,\n      errors: [errorExpectedChar],\n    );\n    t1.testFailure(\n      input: '1',\n      failPos: 1,\n      pos: 0,\n      errors: [errorExpectedChar],\n    );\n    t1.testFailure(\n      input: '2',\n      failPos: 0,\n      pos: 0,\n      errors: [errorExpectedChar],\n    );\n    return buffer.toString();\n  });\n\n  await fastBuild(\n    context: context,\n    parsers: [...tester.parsers],\n    filename: 'example/parser_test.dart',\n    addErrorMessageCode: false,\n    footer: _footer,\n    header: _header + tester.generate(),\n  );\n}\n\n```\n\nGenerated tests (part of this file):\n\n```dart\n// ignore_for_file: non_constant_identifier_names\n// ignore_for_file: inference_failure_on_collection_literal\n// ignore_for_file: unnecessary_cast\n\nimport 'package:test/test.dart' hide escape;\n\nvoid main() {\n  _test();\n}\n\nvoid _test() {\n  // Many\n  _test_Many$0();\n  // Preceded\n  _test_Preceded$0();\n}\n\nvoid _test_Many$0() {\n  // Many\n  test('Many', () {\n    final state$0 = State('1112');\n    final result$0 = _Many$0(state$0);\n    expect(state$0.ok, true,\n        reason: 'Testing \\'state.ok == true\\' failed, input: 1112');\n    final value$0 = result$0!;\n    expect(value$0, [49, 49, 49],\n        reason: 'Testing \\'result = value\\' failed, input: 1112');\n    expect(state$0.pos, 3, reason: 'Testing \\'state.pos\\' failed, input: 1112');\n    final state$1 = State('1112');\n    final result$1 = _Many_NoResult$0(state$1);\n    expect(state$1.ok, true,\n        reason: 'Testing \\'state.ok == true\\' failed, input: 1112');\n    final value$1 = result$1;\n    expect(value$1, null,\n        reason: 'Testing \\'result == null\\' failed, input: 1112');\n    expect(state$1.pos, 3, reason: 'Testing \\'state.pos\\' failed, input: 1112');\n    final state$2 = State('');\n    final result$2 = _Many$0(state$2);\n    expect(state$2.ok, true,\n        reason: 'Testing \\'state.ok == true\\' failed, input: ');\n    final value$2 = result$2!;\n    expect(value$2, [], reason: 'Testing \\'result = value\\' failed, input: ');\n    expect(state$2.pos, 0, reason: 'Testing \\'state.pos\\' failed, input: ');\n    final state$3 = State('');\n    final result$3 = _Many_NoResult$0(state$3);\n    expect(state$3.ok, true,\n        reason: 'Testing \\'state.ok == true\\' failed, input: ');\n    final value$3 = result$3;\n    expect(value$3, null, reason: 'Testing \\'result == null\\' failed, input: ');\n    expect(state$3.pos, 0, reason: 'Testing \\'state.pos\\' failed, input: ');\n    final state$4 = State('2');\n    final result$4 = _Many$0(state$4);\n    expect(state$4.ok, true,\n        reason: 'Testing \\'state.ok == true\\' failed, input: 2');\n    final value$4 = result$4!;\n    expect(value$4, [], reason: 'Testing \\'result = value\\' failed, input: 2');\n    expect(state$4.pos, 0, reason: 'Testing \\'state.pos\\' failed, input: 2');\n    final state$5 = State('2');\n    final result$5 = _Many_NoResult$0(state$5);\n    expect(state$5.ok, true,\n        reason: 'Testing \\'state.ok == true\\' failed, input: 2');\n    final value$5 = result$5;\n    expect(value$5, null,\n        reason: 'Testing \\'result == null\\' failed, input: 2');\n    expect(state$5.pos, 0, reason: 'Testing \\'state.pos\\' failed, input: 2');\n  });\n}\n\n```\n\n## Performance\n\nTest results based on data from this source https://github.com/miloyip/nativejson-benchmark.  \n\nJIT code execution.\n\n```\nParse 20 times: E:\\prj\\test_json_new\\bin\\data\\canada.json (2251.05 Kb)\nDart SDK JSON        : k: 3.05, 46.70 MB/s, 919.3990 ms (100.00%),\nJSON Parser          : k: 1.00, 142.49 MB/s, 301.3300 ms (32.77%),\n\nParse 20 times: E:\\prj\\test_json_new\\bin\\data\\citm_catalog.json (1727.03 Kb)\nDart SDK JSON        : k: 1.00, 100.64 MB/s, 327.3030 ms (89.28%),\nJSON Parser          : k: 1.12, 89.85 MB/s, 366.6040 ms (100.00%),\n\nParse 20 times: E:\\prj\\test_json_new\\bin\\data\\twitter.json (567.93 Kb)\nDart SDK JSON        : k: 1.00, 66.03 MB/s, 164.0480 ms (89.75%),\nJSON Parser          : k: 1.11, 59.26 MB/s, 182.7920 ms (100.00%),\n\nOS: Њ ©Єа®б®дв Windows 10 Pro 10.0.19045\nKernel: Windows_NT 10.0.19045\nProcessor (4 core) Intel(R) Core(TM) i5-3450 CPU @ 3.10GHz\n```\n\nAOT code execution.\n\n```\nParse 20 times: E:\\prj\\test_json_new\\bin\\data\\canada.json (2251.05 Kb)\nDart SDK JSON        : k: 1.70, 47.65 MB/s, 900.9720 ms (100.00%),\nJSON Parser          : k: 1.00, 81.03 MB/s, 529.8630 ms (58.81%),\n\nParse 20 times: E:\\prj\\test_json_new\\bin\\data\\citm_catalog.json (1727.03 Kb)\nDart SDK JSON        : k: 1.00, 89.48 MB/s, 368.1300 ms (87.84%),\nJSON Parser          : k: 1.14, 78.60 MB/s, 419.0910 ms (100.00%),\n\nParse 20 times: E:\\prj\\test_json_new\\bin\\data\\twitter.json (567.93 Kb)\nDart SDK JSON        : k: 1.00, 60.43 MB/s, 179.2560 ms (85.30%),\nJSON Parser          : k: 1.17, 51.55 MB/s, 210.1430 ms (100.00%),\n\nOS: Њ ©Єа®б®дв Windows 10 Pro 10.0.19045\nKernel: Windows_NT 10.0.19045\nProcessor (4 core) Intel(R) Core(TM) i5-3450 CPU @ 3.10GHz\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmezoni%2Fparser_builder_lite","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmezoni%2Fparser_builder_lite","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmezoni%2Fparser_builder_lite/lists"}