{"id":19596258,"url":"https://github.com/sirthias/parboiled2","last_synced_at":"2025-05-13T22:02:46.052Z","repository":{"id":8104332,"uuid":"9519438","full_name":"sirthias/parboiled2","owner":"sirthias","description":"A macro-based PEG parser generator for Scala 2.10+","archived":false,"fork":false,"pushed_at":"2025-05-05T21:21:32.000Z","size":1847,"stargazers_count":717,"open_issues_count":36,"forks_count":86,"subscribers_count":27,"default_branch":"master","last_synced_at":"2025-05-07T00:00:12.060Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sirthias.png","metadata":{"files":{"readme":"README.rst","changelog":"CHANGELOG","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2013-04-18T10:48:21.000Z","updated_at":"2025-05-05T21:21:36.000Z","dependencies_parsed_at":"2023-12-03T10:21:11.401Z","dependency_job_id":"238f4b8e-49ed-429f-80fc-9861b3d18b24","html_url":"https://github.com/sirthias/parboiled2","commit_stats":{"total_commits":916,"total_committers":38,"mean_commits":"24.105263157894736","dds":0.705240174672489,"last_synced_commit":"21f1d884c431a9b02d55d1e8ad23c9449d59549b"},"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sirthias%2Fparboiled2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sirthias%2Fparboiled2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sirthias%2Fparboiled2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sirthias%2Fparboiled2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sirthias","download_url":"https://codeload.github.com/sirthias/parboiled2/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254036808,"owners_count":22003652,"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":[],"created_at":"2024-11-11T08:52:34.830Z","updated_at":"2025-05-13T22:02:45.980Z","avatar_url":"https://github.com/sirthias.png","language":"Scala","funding_links":[],"categories":["Table of Contents","Parsing","语言篇"],"sub_categories":["Parsing","Scala"],"readme":"**parboiled2**  |--| A Macro-Based PEG Parser Generator for Scala 2.12+\n\n\n.. contents:: Contents of this Document\n\n\nIntroduction\n============\n\n*parboiled2* is a Scala 2.12+ library enabling lightweight and easy-to-use, yet powerful, fast and elegant parsing of\narbitrary input text. It implements a macro-based parser generator for `Parsing Expression Grammars`_ (PEGs), which\nruns at compile time and translates a grammar rule definition (written in an internal Scala DSL) into corresponding JVM\nbytecode.\n\nPEGs are an alternative to `Context-Free Grammars`_ (CFGs) for formally specifying syntax, they make a good replacement\nfor regular expressions and have some advantages over the \"traditional\" way of building parsers via CFGs (like not\nneeding a separate lexer/scanner phase).\n\n*parboiled2* is the successor of `parboiled 1.x`_ , which provides a similar capability (for Scala as well as Java) but\ndoes not actually *generate* a parser. Rather `parboiled 1.x`_ interprets a rule tree structure (which is also created\nvia an internal DSL) against the input, which results in a much lower parsing performance.\nFor more info on how `parboiled 1.x`_ and *parboiled2* compare see `parboiled2 vs. parboiled 1.x`_.\nYou might also be interested in reading about `parboiled2 vs. Scala Parser Combinators`_ and\n`parboiled2 vs. Regular Expressions`_.\n\n.. _PEG:\n.. _Parsing Expression Grammars: https://en.wikipedia.org/wiki/Parsing_expression_grammar\n.. _Context-Free Grammars: https://en.wikipedia.org/wiki/Context-free_grammar\n.. _parboiled 1.x: http://parboiled.org\n\n\nFeatures\n========\n\n* Concise, flexible and type-safe DSL for expressing parsing logic\n* Full expressive power of `Parsing Expression Grammars`_, for effectively dealing with most real-world parsing needs\n* Excellent reporting of parse errors\n* Parsing performance comparable to hand-written parsers\n* Easy to learn and use (just one parsing phase (no lexer code required), rather small API)\n* Light-weight enough to serve as a replacement for regular expressions (also strictly more powerful than regexes)\n\n\nInstallation\n============\n\nThe artifacts for *parboiled2* live on `Maven Central`_ and can be tied into your SBT-based Scala project like this:\n\n.. code:: Scala\n\n    libraryDependencies += \"org.parboiled\" %% \"parboiled\" % \"2.5.0\"\n\nThe latest released version is **2.5.1**. It is available for Scala 2.12, 2.13 and 3, Scala.js and Scala Native.\n\n*parboiled2* has no external dependencies. (It used to depend on shapeless_, but the few bits it was using have been\ninternalized at some point).\n\nOnce on your classpath you can use this single import to bring everything you need into scope:\n\n.. code:: Scala\n\n    import org.parboiled2._\n\n.. _Maven Central: https://search.maven.org/search?q=g:org.parboiled\n.. _shapeless: https://github.com/milessabin/shapeless\n\n\nExample\n=======\n\nThis is what a simple *parboiled2* parser looks like:\n\n.. code:: Scala\n\n    import org.parboiled2._\n\n    class Calculator(val input: ParserInput) extends Parser {\n      def InputLine = rule { Expression ~ EOI }\n\n      def Expression: Rule1[Int] = rule {\n        Term ~ zeroOrMore(\n          '+' ~ Term ~\u003e ((_: Int) + _)\n        | '-' ~ Term ~\u003e ((_: Int) - _))\n      }\n\n      def Term = rule {\n        Factor ~ zeroOrMore(\n          '*' ~ Factor ~\u003e ((_: Int) * _)\n        | '/' ~ Factor ~\u003e ((_: Int) / _))\n      }\n\n      def Factor = rule { Number | Parens }\n\n      def Parens = rule { '(' ~ Expression ~ ')' }\n\n      def Number = rule { capture(Digits) ~\u003e (_.toInt) }\n\n      def Digits = rule { oneOrMore(CharPredicate.Digit) }\n    }\n\n    new Calculator(\"1+1\").InputLine.run() // evaluates to `scala.util.Success(2)`\n\nThis implements a parser for simple integer expressions like ``1+(2-3*4)/5`` and runs the actual calculation in-phase\nwith the parser. If you'd like to see it run and try it out yourself check out `Running the Examples`_.\n\n\nQuick Start\n===========\n\nA *parboiled2* parser is a class deriving from ``org.parboiled2.Parser``, which defines one abstract member:\n\n.. code:: Scala\n\n    def input: ParserInput\n\nholding the input for the parsing run. Usually it is best implemented as a ``val`` parameter in the constructor\n(as shown in the Example_ above). As you can see from this design you need to (re-)create a new parser instance for\nevery parsing run (parser instances are very lightweight).\n\nThe \"productions\" (or \"rules\") of your grammar are then defined as simple methods, which in most cases consist of a\nsingle call to the ``rule`` macro whose argument is a `DSL expression`_ defining what input the rule is to match and\nwhat actions_ to perform.\n\nIn order to run your parser against a given input you create a new instance and call ``run()`` on the top-level rule,\ne.g:\n\n.. code:: Scala\n\n    val parser = new MyParser(input)\n    parser.topLevelRule.run() // by default returns a ``scala.util.Try``\n\nFor more info on what options you have with regard to accessing the results of a parsing run check out the section\non `Access to Parser Results`_.\n\n.. _DSL expression: `The Rule DSL`_\n.. _actions: `Parser Actions`_\n\n\nHow the Parser matches Input\n============================\n\nPEG_ parsers are quite easy to understand as they work just like most people without a lot of background in parsing\ntheory would build a parser \"by hand\": recursive-descent with backtracking. They have only one parsing phase (not two,\nlike most parsers produced by traditional parser generators like ANTLR_), do not require any look-ahead and perform\nquite well in most real-world scenarios (although they *can* exhibit exponential runtime for certain pathological\nlanguages and inputs).\n\nA PEG_ parser consists of a number of rules that logically form a \"tree\", with one \"root\" rule at the top calling zero\nor more lower-level rules, which can each call other rules and so on. Since rules can also call themselves or any of\ntheir parents the rule \"tree\" is not really a tree but rather a potentially cyclic directed graph, but in most cases the\ntree structure dominates, which is why its useful to think of it as a tree with potential cycles.\n\nWhen a rule is executed against the current position in an input buffer it applies its specific matching logic to the\ninput, which can either succeed or fail. In the success case the parser advances the input position (the *cursor*) and\npotentially executes the next rule. Otherwise, when the rule fails, the cursor is reset and the parser backtracks in\nsearch of another parsing alternative that might succeed.\n\nFor example consider this simple *parboiled2* rule:\n\n.. code:: Scala\n\n    def foo = rule { 'a' ~ ('b' ~ 'c' | 'b' ~ 'd') }\n\nWhen this rule is confronted with the input ``abd`` the parser matches the input in these steps:\n\n1. Rule ``foo`` starts executing, which calls its first sub-rule ``'a'``. The cursor is at position 0.\n2. Rule ``'a'`` is executed against input position 0, matches (succeeds) and the cursor is advanced to position 1.\n3. Rule ``'b' ~ 'c' | 'b' ~ 'd'`` starts executing, which calls its first sub-rule ``'b' ~ 'c'``.\n4. Rule ``'b' ~ 'c'`` starts executing, which calls its first sub-rule ``'b'``.\n5. Rule ``'b'`` is executed against input position 1, matches (succeeds) and the cursor is advanced to position 2.\n6. Rule ``'c'`` is executed against input position 2 and mismatches (fails).\n7. Rule ``'b' ~ 'c' | 'b' ~ 'd'`` notices that its first sub-rule has failed, resets the cursor to position 1 and\n   calls its 2nd sub-rule ``'b' ~ 'd'``.\n8. Rule ``'b' ~ 'd'`` starts executing, which calls its first sub-rule ``'b'``.\n9. Rule ``'b'`` is executed against input position 1, matches and the cursor is advanced to position 2.\n10. Rule ``'d'`` is executed against input position 2, matches and the cursor is advanced to position 3.\n11. Rule ``'b' ~ 'd'`` completes successfully, as its last sub-rule has succeeded.\n12. Rule ``'b' ~ 'c' | 'b' ~ 'd'`` completes successfully, as one of its sub-rules has succeeded.\n13. Rule ``foo`` completes execution successfully, as its last sub-rule has succeeded.\n    The whole input \"abd\" was matched and the cursor is left at position 3 (after the last-matched character).\n\n.. _ANTLR: https://www.antlr.org/\n\n\nThe Rule DSL\n============\n\nIn order to work with *parboiled2* effectively you should understand the core concepts behind its rule DSL, mainly\nthe \"Value Stack\" and how *parboiled2* encodes value stack operations in the Scala type system.\n\n\nRule Types and the Value Stack\n------------------------------\n\nApart from the input buffer and the cursor the parser manages another important structure: the \"Value Stack\".\nThe value stack is a simple stack construct that serves as temporary storage for your `Parser Actions`_. In many cases\nit is used for constructing an AST_ during the parsing run but it can also be used for \"in-phase\" computations\n(like in the Example_ above) or for any other purpose.\n\nWhen a rule of a *parboiled2* parser executes it performs any combination of the following three things:\n\n- match input, i.e. advance the input cursor\n- operate on the value stack, i.e. pop values off and/or push values to the value stack\n- perform side-effects\n\nMatching input is done by calling `Basic Character Matching`_ rules, which do nothing but match input and advance\nthe cursor. Value stack operations (and other potential side-effects) are performed by `Parser Actions`_.\n\nIt is important to understand that rules in *parboiled2* (i.e. the rule methods in your parser class) do not directly\nreturn some custom value as a method result. Instead, all their consuming and producing values happens as side-effects\nto the value stack. Thereby the way that a rule interacts with value stack is encoded in the rule's type.\n\nThis is the general definition of a *parboiled2* rule:\n\n.. code:: Scala\n\n    class Rule[-I \u003c: HList, +O \u003c: HList]\n\nThis can look scary at first but is really quite simple. An ``HList`` is defined by shapeless_ and is essentially a type\nof list whose element number and element types are statically known at compile time. The ``I`` type parameter on\n``Rule`` encodes what values (the number and types) the rule pops off the value stack and the ``O`` type parameter\nencodes what values (the number and types) the rule then pushes onto the value stack.\n\nLuckily, in most cases, you won't have to work with these types directly as they can either be inferred or you can use\none of these predefined aliases:\n\n.. code:: Scala\n\n    type Rule0 = RuleN[HNil]\n    type Rule1[+T] = RuleN[T :: HNil]\n    type Rule2[+A, +B] = RuleN[A :: B :: HNil]\n    type RuleN[+L \u003c: HList] = Rule[HNil, L]\n    type PopRule[-L \u003c: HList] = Rule[L, HNil]\n\nHere is what these type aliases denote:\n\nRule0\n    A rule that neither pops off nor pushes to the value stack, i.e. has no effect on the value stack whatsoever.\n    All `Basic Character Matching`_ rules are of this type.\n\nRule1[+T]\n    Pushes exactly one value of type ``T`` onto the value stack. After ``Rule0`` this is the second-most frequently\n    used rule type.\n\nRule2[+A, +B]\n    Pushes exactly two values of types ``A`` and ``B`` onto the value stack.\n\nRuleN[+L \u003c: HList]\n    Pushes a number of values onto the value stack, which correspond to the given ``L \u003c: HList`` type parameter.\n\nPopRule[-L \u003c: HList]\n    Pops a number of values off the value stack (corresponding to the given ``L \u003c: HList`` type parameter) and does\n    not produce any new value itself.\n\nThe rule DSL makes sure that the rule types are properly assembled and carried through your rule structure as you\ncombine `Basic Character Matching`_  with `Rule Combinators and Modifiers`_ and `Parser Actions`_, so\nas long as you don't write any logic that circumvents the value stack your parser will be completely type-safe and\nthe compiler will be able to catch you if you make mistakes by combining rules in an unsound way.\n\n.. _AST: https://en.wikipedia.org/wiki/Abstract_syntax_tree\n\n\nBasic Character Matching\n------------------------\n\nThe following basic character matching rules are the only way to cause the parser to match actual input and\n\"make progress\". They are the \"atomic\" elements of the rule DSL which are then used by the\n`Rule Combinators and Modifiers`_ to form higher-level rules.\n\n----\n\nimplicit def ch(c: Char): Rule0\n    ``Char`` values can be directly used in the rule DSL and match themselves. There is one notable case where you will\n    have to use the explicit ``ch`` wrapper: You cannot use the ``|`` operator directly on chars as it denotes the\n    built-in Scala binary \"or\" operator defined on numeric types (``Char`` is an unsigned 16-bit integer).\n    So rather than saying ``'a' | 'b'`` you will have to say ``ch('a') | 'b'``.\n\n----\n\nimplicit def str(s: String): Rule0\n    ``String`` values can be directly used in the rule DSL and match themselves.\n\n----\n\nimplicit def predicate(p: CharPredicate): Rule0\n    You can use ``org.parboiled2.CharPredicate`` values directly in the rule DSL. ``CharPredicate`` is an efficient\n    implementation of character sets and already comes with a number pre-defined character classes like\n    ``CharPredicate.Digit`` or ``CharPredicate.LowerHexLetter``.\n\n----\n\nimplicit def valueMap[T](m: Map[String, T]): R\n    Values of type ``Map[String, T]`` can be directly used in the rule DSL and match any of the given map's keys and\n    push the respective value upon a successful match. The resulting rule type depends on ``T``:\n\n    =================== =========================================\n    ``T``               ``R``\n    =================== =========================================\n    ``Unit``            ``Rule0``\n    ``L \u003c: HList``      ``RuleN[L]`` (pushes all values of ``L``)\n    ``T`` (otherwise)   ``Rule1[T]`` (pushes only one value)\n    =================== =========================================\n\n----\n\ndef anyOf(chars: String): Rule0\n    This constructs a ``Rule0`` which matches any of the given strings characters.\n\n----\n\ndef noneOf(chars: String): Rule0\n    This constructs a ``Rule0`` which matches any single character except the ones in the given string and except EOI.\n\n----\n\ndef ignoreCase(c: Char): Rule0\n    Matches the given single character case insensitively.\n    Note: **The given character must be specified in lower-case!** This requirement is currently NOT enforced!\n\n----\n\ndef ignoreCase(s: String): Rule0\n    Matches the given string of characters case insensitively.\n    Note: **The given string must be specified in all lower-case!** This requirement is currently NOT enforced!\n\n----\n\ndef ANY: Rule0\n    Matches any character except *EOI* (end-of-input).\n\n----\n\ndef EOI: Char\n    The *EOI* (end-of-input) character, which is a virtual character that the parser \"appends\" after the last\n    character of the actual input.\n\n----\n\ndef MATCH: Rule0\n    Matches no character (i.e. doesn't cause the parser to make any progress) but succeeds always. It's the \"empty\"\n    rule that is mostly used as a neutral element in rule composition.\n\n----\n\ndef MISMATCH[I \u003c: HList, O \u003c: HList]: Rule[I, O]\n    A rule that always fails. Fits any rule signature.\n\n----\n\ndef MISMATCH0: Rule0\n    Same as ``MISMATCH`` but with a clearly defined type. Use it (rather then ``MISMATCH``) if the call site doesn't\n    clearly \"dictate\" a certain rule type and using ``MISMATCH`` therefore gives you a compiler error.\n\n\nRule Combinators and Modifiers\n------------------------------\n\nRules can be freely combined/modified with these operations:\n\n----\n\na ~ b\n    Two rules ``a`` and ``b`` can be combined with the ``~`` operator resulting in a rule that only matches if first\n    ``a`` matches and then ``b`` matches. The computation of the resulting rule type is somewhat involved.\n    Here is an illustration (using an abbreviated HList notation):\n\n    ====================== ==================== =========================\n    a                      b                    a ~ b\n    ====================== ==================== =========================\n    ``Rule[, A]``          ``Rule[, B]``        ``Rule[, A:B]``\n    ``Rule[A:B:C, D:E:F]`` ``Rule[F, G:H]``     ``Rule[A:B:C, D:E:G:H]``\n    ``Rule[A, B:C]``       ``Rule[D:B:C, E:F]`` ``Rule[D:A, E:F]``\n    ``Rule[A, B:C]``       ``Rule[D:C, E:F]``   Illegal if ``D`` != ``B``\n    ====================== ==================== =========================\n\n----\n\na | b\n    Two rules ``a`` and ``b`` can be combined with the ``|`` operator to form an \"ordered choice\" in PEG_ speak.\n    The resulting rule tries to match ``a`` and succeeds if this succeeds. Otherwise the parser is reset and ``b``\n    is tried. This operator can only be used on compatible rules.\n\n----\n\n\u0026(a)\n    Creates a \"positive syntactic predicate\", i.e. a rule that tests if the underlying rule matches but doesn't cause\n    the parser to make any progress (i.e. match any input) itself. Also, all effects that the underlying rule might\n    have had on the value stack are cleared out, the resulting rule type is therefore always ``Rule0``,\n    independently of the type of the underlying rule.\n\n    Note that ``\u0026`` not itself consuming any input can have surprising implications in repeating constructs,\n    see `Non-Termination when using Syntactic Predicates`_ for more details.\n\n----\n\n!a\n    Creates a \"negative syntactic predicate\", i.e. a rule that matches only if the underlying one mismatches and vice\n    versa. A syntactic predicate doesn't cause the parser to make any progress (i.e. match any input) and also clears\n    out all effects that the underlying rule might have had on the value stack. The resulting rule type is therefore\n    always ``Rule0``, independently of the type of the underlying rule.\n\n    Note that ``!`` not itself consuming any input can have surprising implications in repeating constructs,\n    see `Non-Termination when using Syntactic Predicates`_ for more details.\n\n----\n\noptional(a)\n    Runs its inner rule and succeeds even if the inner rule doesn't. The resulting rule type depends on the type\n    of the inner rule:\n\n    =================== =======================\n    Type of ``a``       Type of ``optional(a)``\n    =================== =======================\n    ``Rule0``           ``Rule0``\n    ``Rule1[T]``        ``Rule1[Option[T]]``\n    ``Rule[I, O \u003c: I]`` ``Rule[I, O]``\n    =================== =======================\n\n    The last case is a so-called \"reduction rule\", which leaves the value stack unchanged on a type level.\n    This is an example of a reduction rule wrapped with ``optional``:\n\n    .. code:: Scala\n\n        capture(CharPredicate.Digit) ~ optional(ch('h') ~\u003e ((s: String) =\u003e s + \"hex\"))\n\n    The inner rule of ``optional`` here has type ``Rule[String :: HNil, String :: HNil]``, i.e. it pops one ``String``\n    off the stack and pushes another one onto it, which means that the number of elements on the value stack as well as\n    their types remain the same, even though the actual values might have changed.\n\n    As a shortcut you can also use ``a.?`` instead of ``optional(a)``.\n\n----\n\nzeroOrMore(a)\n    Runs its inner rule until it fails, always succeeds. The resulting rule type depends on the type of the inner rule:\n\n    =================== =======================\n    Type of ``a``       Type of ``zeroOrMore(a)``\n    =================== =======================\n    ``Rule0``           ``Rule0``\n    ``Rule1[T]``        ``Rule1[Seq[T]]``\n    ``Rule[I, O \u003c: I]`` ``Rule[I, O]``\n    =================== =======================\n\n    The last case is a so-called \"reduction rule\", which leaves the value stack unchanged on a type level.\n    This is an example of a reduction rule wrapped with ``zeroOrMore``:\n\n    .. code:: Scala\n\n        (factor :Rule1[Int]) ~ zeroOrMore('*' ~ factor ~\u003e ((a: Int, b) =\u003e a * b))\n\n    The inner rule of ``zeroOrMore`` here has type ``Rule[Int :: HNil, Int :: HNil]``, i.e. it pops one ``Int``\n    off the stack and pushes another one onto it, which means that the number of elements on the value stack as well as\n    their types remain the same, even though the actual values might have changed.\n\n    As a shortcut you can also use ``a.*`` instead of ``zeroOrMore(a)``.\n\n----\n\noneOrMore(a)\n    Runs its inner rule until it fails, succeeds if its inner rule succeeded at least once.\n    The resulting rule type depends on the type of the inner rule:\n\n    =================== =======================\n    Type of ``a``       Type of ``oneOrMore(a)``\n    =================== =======================\n    ``Rule0``           ``Rule0``\n    ``Rule1[T]``        ``Rule1[Seq[T]]``\n    ``Rule[I, O \u003c: I]`` ``Rule[I, I]``\n    =================== =======================\n\n    The last case is a so-called \"reduction rule\", which leaves the value stack unchanged on a type level.\n    This is an example of a reduction rule wrapped with ``oneOrMore``:\n\n    .. code:: Scala\n\n        (factor :Rule1[Int]) ~ oneOrMore('*' ~ factor ~\u003e ((a: Int, b) =\u003e a * b))\n\n    The inner rule of ``oneOrMore`` here has type ``Rule[Int :: HNil, Int :: HNil]``, i.e. it pops one ``Int``\n    off the stack and pushes another one onto it, which means that the number of elements on the value stack as well as\n    their types remain the same, even though the actual values might have changed.\n\n    As a shortcut you can also use ``a.+`` instead of ``oneOrMore(a)``.\n\n----\n\nxxx.times(a)\n    Repeats a rule a given number of times. ``xxx`` can be either a positive ``Int`` value or a range ``(\u003cx\u003e to \u003cy\u003e)``\n    whereby both ``\u003cx\u003e`` and ``\u003cy\u003e`` are positive ``Int`` values.\n    The resulting rule type depends on the type of the inner rule:\n\n    =================== =======================\n    Type of ``a``       Type of ``xxx.times(a)``\n    =================== =======================\n    ``Rule0``           ``Rule0``\n    ``Rule1[T]``        ``Rule1[Seq[T]]``\n    ``Rule[I, O \u003c: I]`` ``Rule[I, O]``\n    =================== =======================\n\n    The last case is a so-called \"reduction rule\", which leaves the value stack unchanged on a type level.\n    This is an example of a reduction rule wrapped with ``oneOrMore``:\n\n    .. code:: Scala\n\n        (factor :Rule1[Int]) ~ (1 to 5).times('*' ~ factor ~\u003e ((a: Int, b) =\u003e a * b))\n\n    The inner rule here has type ``Rule[Int :: HNil, Int :: HNil]``, i.e. it pops one ``Int`` off the stack and pushes\n    another one onto it, which means that the number of elements on the value stack as well as their types remain the\n    same, even though the actual values might have changed.\n\n----\n\na.separatedBy(separator: Rule0)\n    You can use ``a.separatedBy(b)`` to create a rule with efficient and automatic support for element separators if\n    ``a`` is a rule produced by the ``zeroOrMore``, ``oneOrMore`` or ``xxx.times`` modifier and ``b`` is a ``Rule0``.\n    The resulting rule has the same type as ``a`` but expects the individual repetition elements to be separated by\n    a successful match of the ``separator`` rule.\n\n    As a shortcut you can also use ``a.*(b)`` or ``(a * b)`` instead of ``zeroOrMore(a).separatedBy(b)``.\n    The same shortcut also works for ``+`` (``oneOrMore``).\n\n----\n\na ~!~ b\n    Same as `~` but with \"cut\" semantics, meaning that the parser will never backtrack across this boundary.\n    If the rule being concatenated doesn't match a parse error will be triggered immediately.\n    Usually you don't need to use this \"cut\" operator but in certain cases it can help in simplifying grammar\n    construction.\n\n\nParser Actions\n--------------\n\nThe `Basic Character Matching`_  rules and the `Rule Combinators and Modifiers`_ allow you to build *recognizers* for\npotentially complex languages, but usually your parser is supposed to do more than simply determine whether a given\ninput conforms to the defined grammar. In order to run custom logic during parser execution, e.g. for creating custom\nobjects (like an AST_), you will have to add some \"actions\" to your rules.\n\n----\n\npush(value)\n    ``push(value)`` creates a rule that matches no input (but always succeeds, as a rule) and pushes the given value\n    onto the value stack. Its rule type depends on the given value:\n\n    ================= =============================================\n    Type of ``value`` Type of ``push(value)``\n    ================= =============================================\n    ``Unit``          ``Rule0`` (identical to ``run`` in this case)\n    ``L \u003c: HList``    ``RuleN[L]`` (pushes all values of ``L``)\n    ``T`` (otherwise) ``Rule1[T]`` (pushes only one value)\n    ================= =============================================\n\n    Also note that, due to the macro expansion the *parboiled2* rule DSL is based on, the given value expression behaves\n    like a call-by-name parameter even though it is not marked as one! This means that the argument expression to\n    ``push`` is (re-)evaluated for every rule execution.\n\n----\n\ncapture(a)\n    Wrapping a rule ``a`` with ``capture`` turns that rule into one that pushes an additional ``String`` instance onto\n    the value stack (in addition to all values that ``a`` already pushes itself): the input text matched by ``a``.\n\n    For example ``capture(oneOrMore(CharPredicate.Digit))`` has type ``Rule1[String]`` and pushes one value onto the\n    value stack: the string of digit characters matched by ``oneOrMore(CharPredicate.Digit)``.\n\n    Another example: ``capture(\"foo\" ~ push(42))`` has type ``Rule2[Int, String]`` and will match input \"foo\". After\n    successful execution the value stack will have the String ``\"foo\"`` as its top element and ``42`` underneath.\n\n----\n\ntest(condition: Boolean): Rule0\n    ``test`` implements \"semantic predicates\". It creates a rule that matches no input and succeeds only if the given\n    condition expression evaluates to true. Note that, due to the macro expansion the *parboiled2* rule DSL is based on,\n    the given argument behaves like a call-by-name parameter even though it is not marked as one!\n    This means that the argument expression to ``test`` is (re-)evaluated for every rule execution, just as if ``test``\n    would have been defined as ``def test(condition: =\u003e Boolean): Rule0``.\n\n----\n\na ~\u003e (...)\n    The ``~\u003e`` operator is the \"action operator\" and as such the most frequently used way to add custom logic to a rule.\n    It can be applied to any rule and appends action logic to it. The argument to ``~\u003e`` is always a function, what\n    functions are allowed and what the resulting rule type is depends on the type of ``a``.\n\n    The basic idea is that the input of the function is popped off the value stack and the result of the function is\n    pushed back onto it. In its basic form the ``~\u003e`` operator therefore transforms the top elements of the value stack\n    into some other object(s).\n\n    Let's look at some examples:\n\n    .. code:: Scala\n\n        (foo: Rule1[Int]) ~\u003e (i =\u003e i * 2)\n\n    This results in a ``Rule1[Int]`` which multiplies the \"output\" of rule ``foo`` by 2.\n\n    .. code:: Scala\n\n        (foo: Rule2[Int, String]) ~\u003e ((i, s) =\u003e s + i.toString)\n\n    This results in a ``Rule1[String]`` which combines the two \"outputs\" of rule ``foo`` (an ``Int`` and a ``String``)\n    into one single ``String``.\n\n    .. code:: Scala\n\n        (foo: Rule2[Int, String]) ~\u003e (_.toDouble)\n\n    This results in a ``Rule2[Int, Double]``. As you can see the function argument to ``~\u003e`` doesn't always have to\n    \"take\" the complete output of the rule its applied to. It can also take fewer or even more elements. Its parameters\n    are simply matched left to right against the top of the value stack (the right-most parameter matching the top-level\n    element).\n\n    .. code:: Scala\n\n        (foo: Rule1[String]) ~\u003e ((i :Int, s) =\u003e s + i.toString)\n\n    This results in a ``Rule[Int :: HNil, String :: HNil]``, i.e. a rule that pops one ``Int`` value off the stack and\n    replaces it with a ``String``. Note that, while the parameter types to the action function can be inferred if they\n    can be matched against an \"output\" of the underlying rule, this is not the case for parameters that don't directly\n    correspond to an underlying output. In these cases you need to add an explicit type annotation to the respective\n    action function parameter(s).\n\n    If an action function returns ``Unit`` it doesn't push anything on the stack. So this rule\n\n    .. code:: Scala\n\n        (foo: Rule1[String]) ~\u003e (println(_))\n\n    has type ``Rule0``.\n\n    Also, an action function can also be a ``Function0``, i.e. a function without any parameters:\n\n    .. code:: Scala\n\n        (foo: Rule1[String]) ~\u003e (() =\u003e 42)\n\n    This rule has type ``Rule2[String, Int]`` and is equivalent to this:\n\n    .. code:: Scala\n\n        (foo: Rule1[String]) ~ push(42)\n\n    An action function can also produce more than one output by returning an ``HList`` instance:\n\n    .. code:: Scala\n\n        (foo: Rule1[String]) ~\u003e (s =\u003e s.toInt :: 3.14 :: HNil)\n\n    This has type ``Rule2[Int, Double]``.\n\n    One more very useful feature is special support for case class instance creation:\n\n    .. code:: Scala\n\n        case class Person(name: String, age: Int)\n\n        (foo: Rule2[String, Int]) ~\u003e Person\n\n    This has type ``Rule1[Person]``. The top elements of the value stack are popped off and replaced by an instance\n    of the case class if they match in number, order and types to the case class members. This is great for building\n    AST_-like structures! Check out the Calculator2__ example to see this form in action.\n\n    Note that there is one quirk: For some reason this notation stops working if you explicitly define a companion\n    object for your case class. You'll have to write ``~\u003e (Person(_, _))`` instead.\n\n    __ https://github.com/sirthias/parboiled2/blob/master/examples/src/main/scala/org/parboiled2/examples/Calculator2.scala\n\n    And finally, there is one more very powerful action type: the action function can itself return a rule!\n    If an action returns a rule this rule is immediately executed after the action application just as if it\n    had been concatenated to the underlying rule with the ``~`` operator. You can therefore do things like\n\n    .. code:: Scala\n\n        (foo: Rule1[Int]) ~\u003e (i =\u003e test(i % 2 == 0) ~ push(i))\n\n    which is a ``Rule1[Int]`` that only produces even integers and fails for all others. Or, somewhat unusual\n    but still perfectly legal:\n\n    .. code:: Scala\n\n        capture(\"x\") ~\u003e (str(_))\n\n    which is a ``Rule0`` that is identical to ``'x' ~ 'x'``.\n\n----\n\nrun(expression)\n    ``run`` is the most versatile parser action. It can have several shapes, depending on the type of its argument\n    expression. If the argument expression evaluates to\n\n    - a rule (i.e. has type ``R \u003c: Rule[_, _]``) the result type of ``run`` is this rule's type (i.e. ``R``) and the\n      produced rule is immediately executed.\n\n    - a function with 1 to 5 parameters these parameters are mapped against the top of the value stack, popped\n      and the function executed. Thereby the function behaves just like an action function for the ``~\u003e`` operator,\n      i.e. if it produces a ``Unit`` value this result is simply dropped. ``HList`` results are pushed onto the value\n      stack (all their elements individually), rule results are immediately executed and other result values are pushed\n      onto the value stack as a single element.\n      The difference between using ``run`` and attaching an action function with the ``~\u003e`` operator is that in the\n      latter case the compiler can usually infer the types of the function parameters (if they map to \"output\" values\n      of the base rule) while with ``run`` you *always* have to explicitly attach type annotation to the function\n      parameters.\n\n    - a function with one ``HList`` parameter the behavior is similar to the previous case with the difference that the\n      elements of this parameter ``HList`` are mapped against the value stack top. This allows for consumption of an\n      arbitrary number of value stack elements (Note: This feature of ``run`` is not yet currently implemented.)\n\n    - any other value the result type of ``run`` is an always succeeding ``Rule0``. Since in this case it doesn't\n      interact with the value stack and doesn't match any input all it can do is perform \"unchecked\" side effects.\n      Note that by using ``run`` in this way you are leaving the \"safety-net\" that the value stack and the rule type\n      system gives you! Make sure you understand what you are doing before using these kinds of ``run`` actions!\n\n    Also note that, due to the macro expansion the *parboiled2* rule DSL is based on, the given block behaves like a\n    call-by-name parameter even though it is not marked as one! This means that the argument expression to ``run`` is\n    (re-)evaluated for every rule execution.\n\n----\n\nrunSubParser(f: ParserInput =\u003e Rule[I, O]): Rule[I, O]\n    This action allows creation of a sub parser and running of one of its rules as part of the current parsing process.\n    The subparser will start parsing at the current input position and the outer parser (the one calling\n    ``runSubParser``) will continue where the sub-parser stopped.\n\n----\n\nThere are a few more members of the ``Parser`` class that are useful for writing efficient action logic:\n\ndef cursor: Int\n    The index of the next (yet unmatched) input character.\n    Note: Might be equal to ``input.length`` if the cursor is currently behind the last input character!\n\ndef cursorChar: Char\n    The next (yet unmatched) input character, i.e. the one at the ``cursor`` index.\n    Identical to ``if (cursor \u003c input.length) input.charAt(cursor) else EOI`` but more efficient.\n\ndef lastChar: Char\n    Returns the last character that was matched, i.e. the one at index ``cursor - 1`` and as such is equivalent\n    to ``charAt(-1)``. Note that for performance optimization this method does *not* do a range check, i.e. depending on\n    the ``ParserInput`` implementation you might get an exception when calling this method before any character was\n    matched by the parser.\n\ndef charAt(offset: Int): Char\n    Returns the character at the input index with the given delta to the cursor and as such is equivalent to\n    ``input.charAt(cursor + offset)``. Note that for performance optimization this method does *not* do a range check,\n    i.e. depending on the ``ParserInput`` implementation you might get an exception if the computed index is out of\n    bounds.\n\ndef charAtRC(offset: Int): Char\n    Same as ``charAt`` but range-checked. Returns the input character at the index with the given offset from the\n    cursor. If this index is out of range the method returns ``EOI``.\n\nYou can use these to write efficient character-level logic like this:\n\n.. code:: Scala\n\n    def hexDigit: Rule1[Int] = rule {\n      CharPredicate.HexAlpha ~ push(CharUtils.hexValue(lastChar))\n    }\n\n\nAdditional Helpers\n------------------\n\nBase64Parsing\n    For parsing RFC2045_ (Base64) encoded strings *parboiled* provides the ``Base64Parsing`` trait which you can\n    mix into your ``Parser`` class. See `its source`_ for more info on what exactly it provides.\n    *parboiled* also comes with the ``org.parboiled2.util.Base64`` class which provides an efficient Base64\n    encoder/decoder for the standard as well as custom alphabets.\n\n.. _RFC2045: https://datatracker.ietf.org/doc/html/rfc2045#section-6.8\n.. _its source: https://github.com/sirthias/parboiled2/blob/v2.0.0-RC1/parboiled/src/main/scala/org/parboiled2/Base64Parsing.scala\n\n----\n\nDynamicRuleDispatch\n    Sometimes an application cannot fully specify at compile-time which of a given set of rules is to be called at\n    runtime. For example, a parser for parsing HTTP header values might need to select the right parser rule for a\n    header name that is only known once the HTTP request has actually been read from the network.\n    To prevent you from having to write a large (and not really efficient) ``match`` against the header name for\n    separating out all the possible cases *parboiled* provides the ``DynamicRuleDispatch`` facility.\n    Check out `its test`_ for more info on how to use it.\n\n.. _its test: https://github.com/sirthias/parboiled2/blob/v2.0.0-RC1/parboiled/src/test/scala/org/parboiled2/DynamicRuleDispatchSpec.scala\n\n----\n\nStringBuilding\n    For certain high-performance use-cases it is sometimes better to construct Strings that the parser is to\n    produce/extract from the input in a char-by-char fashion. To support you in doing this *parboiled* provides\n    the ``StringBuilding`` trait which you can mix into your ``Parser`` class.\n    It provides convenient access to a **single** and **mutable** ``StringBuilder`` instance.\n    As such it operates outside of the value stack and therefore without the full \"safety net\" that parboiled's\n    DSL otherwise gives you. If you don't understand what this means you probably shouldn't be using\n    the ``StringBuilding`` trait but resort to ``capture`` and ordinary parser actions instead.\n\n\nError Reporting\n===============\n\nIn many applications, especially with grammars that are not too complex, *parboiled* provides good error reports right\nout of the box, without any additional requirements on your part.\nHowever, there are cases where you want to have more control over how parse errors are created and/or formatted.\nThis section gives an overview over how parse error reporting works in *parboiled* and how you can influence it.\n\nThe Error Collection Process\n----------------------------\n\nAs described in the section about `How the Parser matches Input`_ above the parser consumes input by applying\ngrammar rules and backtracking in the case of mismatches. As such rule mismatches are an integral part of the parsers\noperation and do not generally mean that there is something wrong with the input.\nOnly when the root rule itself mismatches and the parser has no backtracking options remaining does it become clear that\na parse error is present. At that point however, when the root rule mismatches, the information about where exactly\nthe problematic input was and which of the many rule mismatches that the parser experienced during the run\nwere the \"bad\" ones is already lost.\n\n*parboiled* overcomes this problem by simply re-running the failed parser, potentially many times, and \"watching\" it as\nit tries to consume the erroneous input. With every re-run *parboiled* learns a bit more about the position and nature\nof the error and when this analysis is complete a ``ParseError`` instance is constructed and handed to the application\nas the result of the parsing run, which can then use the error information on its level (e.g. for formatting it and\ndisplaying it to the user).\nNote that re-running the parser in the presence of parse errors does result in unsuccessful parsing runs being\npotentially much slower than successful ones. However, since in the vast majority of use cases failed runs constitute\nonly a small minority of all parsing runs and the normal flow of application logic is disrupted anyway, this slow-down\nis normally quite acceptable, especially if it results in better error messages. See the section on\n`Limiting Error Re-Runs`_ if this is not true for your application.\n\nIn principle the error reporting process looks like this:\n\n1. The grammar's root rule is run at maximum speed against the parser input.\n   If this succeeds then all is well and the parsing result is immediately dispatched to the user.\n\n2. If the root rule did not match we know that there we have a parsing error.\n   The parser is then run again to establish the \"principal error location\". The principal error location is the\n   first character in the input that could not be matched by any rule during the parsing run. In order words, it is\n   the maximum value that the parser's ``cursor`` member had during the parsing run.\n\n3. Once the error location is known the parser is run again. This time all rule mismatches against the input character\n   at error location are recorded. These rule mismatches are used to determine what input the grammar \"expects\" at the\n   error location but failed to see. For every such \"error rule mismatch\" the parser collects the \"rule trace\", i.e.\n   the stack of rules that led to it. Currently this is done by throwing a special exception that bubbles up through\n   the JVM call stack and records rule stack information on its way up. A consequence of this design is that the parser\n   needs to be re-run once per \"error rule mismatch\".\n\n4. When all error rule traces have been collected all the relevant information about the parse error has been extracted\n   and a ``ParseError`` instance can be constructed and dispatched to the user.\n\nNote: The real process contains a few more steps to properly deal with the ``atomic`` and ``quiet`` markers described\nbelow. However, knowledge of these additional steps is not important for understanding the basic approach for how\n``ParseError`` instances are constructed.\n\nFormatting Parse Errors\n-----------------------\n\nIf a parsing runs fails and you receive a ``ParseError`` instance you can call the ``formatError`` method on your\nparser instance to get the error rendered into an error message string:\n\n.. code:: Scala\n\n    val errorMsg = parser.formatError(error)\n\nThe ``formatError`` message can also take an explicit ``ErrorFormatter`` as a second argument, which allows you to\ninfluence how exactly the error is to be rendered. For example, in order to also render the rule traces you can do:\n\n.. code:: Scala\n\n    val errorMsg = parser.formatError(error, new ErrorFormatter(showTraces = true))\n\nLook at the signature of the ``ErrorFormatter`` constructor for more information on what rendering options exist.\n\nIf you want even more control over the error rendering process you can extend the ``ErrorFormatter`` and override\nits methods where you see fit.\n\n\nTweaking Error Reporting\n------------------------\n\nWhile the error collection process described above yields all information required for a basic \"this character\nwas not matched and these characters were expected instead\" information you sometimes want to have more control\nover what exactly is reported as \"found\" and as \"expected\".\n\nThe ``atomic`` Marker\n+++++++++++++++++++++\n\nSince PEG parsers are scanner-less (i.e. without an intermediate \"TOKEN-stream\") they operate directly on the input\nbuffer's character level. As such, by default, *parboiled* reports all errors on this character level.\n\nFor example, if you run the rule ``\"foo\" | \"fob\" | \"bar\"`` against input \"foxes\" you'll get this error message::\n\n    Invalid input 'x', expected 'o' or 'b' (line 1, column 3):\n    foxes\n      ^\n\nWhile this error message is certainly correct, it might not be what you want to show your users, e.g. because ``foo``,\n``fob`` and ``bar`` are regarded as \"atomic\" keywords of your language, that should either be matched completely or not\nat all. In this case you can use the ``atomic`` marker to signal this to the parser.\nFor example, running the rule ``atomic(\"foo\") | atomic(\"fob\") | atomic(\"bar\")`` against input \"foxes\" yields this error\nmessage::\n\n    Invalid input \"fox\", expected \"foo\", \"fob\" or \"bar\" (line 1, column 1):\n    foxes\n    ^\n\nOf course you can use the ``atomic`` marker on any type of rule, not just string rules. It essentially moves the\nreported error position forward from the principal error position and lifts the level at which errors are reported\nfrom the character level to a rule level of your choice.\n\nThe ``quiet`` Marker\n++++++++++++++++++++\n\nAnother problem that more frequently occurs with *parboiled*'s default error reporting is that the list of \"expected\"\nthings becomes too long. Often the reason for this are rules that deal match input which can appear pretty much anywhere,\nlike whitespace or comments.\n\nConsider this simple language:\n\n.. code:: Scala\n\n    def Expr    = rule { oneOrMore(Id ~ Keyword ~ Id).separatedBy(',' ~ WS) ~ EOI }\n    def Id      = rule { oneOrMore(CharPredicate.Alpha) ~ WS }\n    def Keyword = rule { atomic((\"has\" | \"is\") ~ WS) }\n    def WS      = rule { zeroOrMore(anyOf(\" \\t \\n\")) }\n\nWhen we run the ``Expr`` rule against input \"Tim has money, Tom Is poor\" we get this error::\n\n    Invalid input 'I', expected [ \\t \\n] or Keyword (line 1, column 20):\n    Tim has money, Tom Is poor\n                       ^\n\nAgain the list of \"expected\" things is technically correct but we don't want to bother the user with the information\nthat whitespace is also allowed at the error location. The ``quiet`` marker let's us suppress a certain rule from the\nexpected list if there are also non-quiet alternatives:\n\n.. code:: Scala\n\n    def WS = rule { quiet(zeroOrMore(anyOf(\" \\t \\n\"))) }\n\nWith that change the error message becomes::\n\n    Invalid input 'I', expected Keyword (line 1, column 20):\n    Tim has money, Tom Is poor\n                       ^\n\nwhich is what we want.\n\n\nNaming Rules\n++++++++++++\n\n*parboiled* uses a somewhat involved logic to determine what exactly to report as \"mismatched\" and \"expected\" for a\ngiven parse error. Essentially the process looks like this:\n\n1. Compare all rule trace for the error and drop a potentially existing common prefix. This is done because, if all\n   traces share a common prefix, this prefix can be regarded as the \"context\" of the error which is probably apparent\n   to the user and as such doesn't need to be reported.\n\n2. For each trace (suffix), find the first frame that tried to start its match at the reported error position.\n   The string representation of this frame (which might be an assigned name) is selected for \"expected\" reporting.\n\n3. Duplicate \"expected\" strings are removed.\n\nSo, apart from placing ``atomic`` and ``quiet`` markers you can also influence what gets reported as \"expected\" by\nexplicitly naming rules. One way to do this is to pick good names for the rule methods as they automatically attach\ntheir name to their rules. The names of ``val`` or ``def`` members that you use to reference ``CharPredicate``\ninstances also automatically name the respective rule.\n\nIf you don't want to split out rules into their own methods you can also use the ``named`` modifier.\nWith it you can attach an explicit name to any parser rule. For example, if you run the rule ``foo`` from this snippet:\n\n.. code:: Scala\n\n    def foo = rule { \"aa\" | atomic(\"aaa\").named(\"threeAs\") | 'b' | 'B'.named(\"bigB\") }\n\nagainst input ``x`` you'll get this error message::\n\n    Invalid input 'x', expected 'a', threeAs, 'b' or bigB (line 1, column 1):\n    x\n    ^\n\n\nManual Error Reporting\n++++++++++++++++++++++\n\nIf you want to completely bypass *parboiled*'s built-in error reporting logic you can do so by exclusively relying on\nthe ``fail`` helper, which causes the parser to immediately and fatally terminate the parsing run with a single\none-frame rule trace with a given \"expected\" message.\n\nFor example, the rule ``\"foo\" | fail(\"a true FOO\")`` will produce this error when run against ``x``::\n\n    Invalid input 'x', expected a true FOO (line 1, column 1):\n    x\n    ^\n\n\nLimiting Error Re-Runs\n----------------------\n\nReally large grammars, especially ones with bugs as they commonly appear during development, can exhibit a very large\nnumber of rule traces (potentially thousands) and thus cause the parser to take longer than convenient to terminate an\nerror parsing run.\nIn order to mitigate this *parboiled* has a configurable limit on the maximum number of rule traces the parser will\ncollect during a single error run. The default limit is 24, you can change it by overriding the\n``errorTraceCollectionLimit`` method of the ``Parser`` class.\n\n\nRecovering from Parse Errors\n----------------------------\n\nCurrently *parboiled* only ever parses up to the very first parse error in the input.\nWhile this is all that's required for a large number of use cases there are applications that do require the ability\nto somehow recover from parse errors and continue parsing.\nSyntax highlighting in an interactive IDE-like environment is one such example.\n\nFuture versions of *parboiled* might support parse error recovery.\nIf your application would benefit from this feature please let us know in `this github ticket`__.\n\n__ https://github.com/sirthias/parboiled2/issues/42\n\n\nAdvanced Techniques\n===================\n\nMeta-Rules\n----------\n\nSometimes you might find yourself in a situation where you'd like to DRY up your grammar definition by factoring out\ncommon constructs from several rule definitions in a \"meta-rule\" that modifies/decorates other rules.\nEssentially you'd like to write something like this (*illegal* code!):\n\n.. code:: Scala\n\n    def expression = rule { bracketed(ab) ~ bracketed(cd) }\n    def ab = rule { \"ab\" }\n    def cd = rule { \"cd\" }\n    def bracketed(inner: Rule0) = rule { '[' ~ inner ~ ']' }\n\nIn this hypothetical example ``bracketed`` is a meta-rule which takes another rule as parameter and calls it from within\nits own rule definition.\n\nUnfortunately enabling a syntax such as the one shown above it not directly possible with *parboiled*.\nWhen looking at how the parser generation in *parboiled* actually works the reason becomes clear.\n*parboiled* \"expands\" the rule definition that is passed as argument to the ``rule`` macro into actual Scala code.\nThe rule methods themselves however remain what they are: instance methods on the parser class.\nAnd since you cannot simply pass a method name as argument to another method the calls ``bracketed(ab)`` and\n``bracketed(cd)`` from above don't compile.\n\nHowever, there is a work-around which might be good enough for your meta-rule needs:\n\n.. code:: Scala\n\n    def expression = rule { bracketed(ab) ~ bracketed(cd) }\n    val ab = () =\u003e rule { \"ab\" }\n    val cd = () =\u003e rule { \"cd\" }\n    def bracketed(inner: () =\u003e Rule0) = rule { '[' ~ inner() ~ ']' }\n\nIf you model the rules that you want to pass as arguments to other rules as ``Function0`` instances you *can* pass\nthem around. Assigning those function instances to ``val`` members avoids re-allocation during *every* execution of\nthe ``expression`` rule which would come with a potentially significant performance cost.\n\n\nCommon Mistakes\n===============\n\nDisregarding Order Choice\n-------------------------\n\nThere is one mistake that new users frequently make when starting out with writing PEG_ grammars: disregarding the\n\"ordered choice\" logic of the ``|`` operator. This operator always tries all alternatives *in the order that they were\ndefined* and picks the first match.\n\nAs a consequence earlier alternatives that are a prefix of later alternatives will always \"shadow\" the later ones, the\nlater ones will never be able to match!\n\nFor example in this simple rule\n\n.. code:: Scala\n\n    def foo = rule { \"foo\" | \"foobar\" }\n\n\"foobar\" will never match. Reordering the alternatives to either \"factor out\" all common prefixes or putting the more\nspecific alternatives first are the canonical solutions.\n\nIf your parser is not behaving the way you expect it to watch out for this \"wrong ordering\" problem, which might be\nnot that easy to spot in more complicated rule structures.\n\n\nNon-Termination when using Syntactic Predicates\n-----------------------------------------------\n\nThe syntactic predicate operators, ``\u0026`` and ``!``, don't themselves consume any input, so directly wrapping them with a\nrepeating combinator (like ``zeroOrMore`` or ``oneOrMore``) will lead to an infinite loop as the parser continuously\nruns the syntactic predicate against the very same input position without making any progress.\n\nIf you use syntactic predicates in a loop make sure to actually consume input as well. For example:\n\n.. code:: Scala\n\n    def foo = rule { capture(zeroOrMore( !',' )) }\n\nwill never terminate, while\n\n.. code:: Scala\n\n   def foo = rule { capture(zeroOrMore( !',' ~ ANY )) }\n\nwill capture all input until it reaches a comma.\n\n\nUnchecked Mutable State\n-----------------------\n\n*parboiled2* parsers work with mutable state as a design choice for achieving good parsing performance. Matching input\nand operating on the value stack happen as side-effects to rule execution and mutate the parser state.\nHowever, as long as you confine yourself to the value stack and do not add parser actions that mutate custom parser\nmembers the rule DSL will protect you from making mistakes.\n\nIt is important to understand that, in case of rule mismatch, the parser state (cursor and value stack) is reset to\nwhat it was before the rule execution was started. However, if you write rules that have side-effects beyond matching\ninput and operating on the value stack than these side-effects *cannot* be automatically rolled-back!\nThis means that you will have to make sure that you action logic \"cleans up after itself\" in the case of rule mismatches\nor is only used in locations where you know that rule execution can never fail.\nThese techniques are considered advanced and are not recommended for beginners.\n\nThe rule DSL is powerful enough to support even very complex parsing logic without the need to resort to custom mutable\nstate, we consider the addition of mutable members as an optimization that should be well justified.\n\n\nHandling Whitespace\n-------------------\n\nOne disadvantage of PEGs over lexer-based parser can be the handling of white space. In a \"traditional\" parser with a\nseparate lexer (scanner) phase this lexer can simply skip all white space and only generate tokens for the actual\nparser to operate on. This can free the higher-level parser grammar from all white space treatment.\n\nSince PEGs do not have a lexer but directly operate on the raw input they have to deal with white space in the grammar\nitself. Language designers with little experience in PEGs can sometime be unsure of how to best handle white space in\ntheir grammar.\n\nThe common and highly recommended pattern is to\n**match white space always immediately after a terminal (a single character or string) but not in any other place**.\nThis helps with keeping your grammar rules properly structured and white space \"taken care of\" without it getting in the\nway.\n\n----\n\nIn order to reduce boilerplate in your grammar definition parboiled allows for cleanly factoring out whitespace matching\nlogic into a dedicated rule. By defining a custom implicit conversion from ``String`` to ``Rule0`` you can implicitly\nmatch whitespace after a string terminal:\n\n.. code:: Scala\n\n    class FooParser(val input: ParserInput) extends Parser {\n      implicit def wspStr(s: String): Rule0 = rule {\n        str(s) ~ zeroOrMore(' ')\n      }\n\n      def foo = rule { \"foobar\" | \"foo\" } // implicitly matches trailing blanks\n      def fooNoWSP = rule { str(\"foobar\") | str(\"foo\") } // doesn't match trailing blanks\n    }\n\nIn this example all usages of a plain string literals in the parser rules will implicitly match trailing space characters.\nIn order to *not* apply the implicit whitespace matching in this case simply say ``str(\"foo\")`` instead of just ``\"foo\"``.\n\n\nParsing the whole Input\n-----------------------\n\nIf you don't explicitly match ``EOI`` (the special end-of-input pseudo-character) in your grammar's root rule\nthe parser will not produce an error if, at the end of a parsing run, there is still unmatched input left.\nThis means that if the root rule matches only a prefix of the whole input the parser will report a successful parsing\nrun, which might not be what you want.\n\nAs an example, consider this very basic parser:\n\n.. code:: Scala\n\n    class MyParser(val input: ParserInput) extends Parser {\n      def InputLine = rule { \"foo\" | \"bar\" }\n    }\n\n    new MyParser(\"foo\").InputLine.run()  // Success\n    new MyParser(\"foot\").InputLine.run()  // also Success!!\n\nIn the second run of the parser, instead of failing with a ``ParseError`` as you might expect, it successfully parses\nthe matching input ``foo`` and ignores the rest of the input.\n\nIf this is not what you want you need to explicitly match ``EOI``, for example as follows:\n\n.. code:: Scala\n\n    def InputLine = rule { (\"foo\" | \"bar\") ~ EOI }\n\n\nGrammar Debugging\n=================\n\nTODO\n\n(e.g., use ``parse.formatError(error, showTraces = true)``)\n\n\nAccess to Parser Results\n========================\n\nIn order to run the top-level parser rule against a given input you create a new instance of your parser class and\ncall ``run()`` on it, e.g:\n\n.. code:: Scala\n\n    val parser = new MyParser(input)\n    val result = parser.rootRule.run()\n\nBy default the type of ``result`` in this snippet will be a ``Try[T]`` whereby ``T`` depends on the type\nof ``rootRule``:\n\n================================= ==========================\nType of ``rootRule``              Type of ``rootRule.run()``\n================================= ==========================\n``Rule0``                         ``Try[Unit]``\n``Rule1[T]``                      ``Try[T]``\n``RuleN[L \u003c: HList]`` (otherwise) ``Try[L]``\n================================= ==========================\n\nThe contents of the value stack at the end of the ``rootRule`` execution constitute the result of the parsing run.\nNote that ``run()`` is not available on rules that are not of type ``RuleN[L \u003c: HList]``.\n\nIf the parser is not able to match the input successfully it creates an instance of class ``ParseError`` , which is\ndefined like this\n\n.. code:: Scala\n\n    case class ParseError(position: Position, charCount: Int, traces: Seq[RuleTrace]) extends RuntimeException\n\nIn such cases the ``Try`` is completed with a ``scala.util.Failure`` holding the ``ParseError``.\nIf other exceptions occur during the parsing run (e.g. because some parser action failed) these will also end up as\na ``Try`` failure.\n\n*parboiled2* has quite powerful error reporting facilities, which should help you (and your users) to easily understand\nwhy a particular input does not conform to the defined grammar and how this can be fixed.\nThe ``formatError`` method available on the ``Parser`` class is of great utility here, as it can \"pretty print\"\na parse error instance, to display something like this (excerpt from the ErrorReportingSpec_)::\n\n    Invalid input 'x', expected 'f', Digit, hex or UpperAlpha (line 1, column 4):\n    abcx\n       ^\n\n    4 rules mismatched at error location:\n      targetRule / | / \"fgh\" / 'f'\n      targetRule / | / Digit\n      targetRule / | / hex\n      targetRule / | / UpperAlpha\n\n\nAlternative DeliverySchemes\n---------------------------\n\nApart from delivering your parser results as a ``Try[T]`` *parboiled2* allows you to select another one of the\npre-defined ``Parser.DeliveryScheme`` alternatives, or even define your own. They differ in how they wrap the three\npossible outcomes of a parsing run:\n\n- parsing completed successfully, deliver a result of type ``T``\n- parsing failed with a ``ParseError``\n- parsing failed due to another exception\n\nThis table compares the built-in ``Parser.DeliveryScheme`` alternatives (the first one being the default):\n\n=================================== ========================== ======= ========== ================\nImport                              Type of ``rootRule.run()`` Success ParseError Other Exceptions\n=================================== ========================== ======= ========== ================\nimport Parser.DeliveryScheme.Try    Try[T]                     Success Failure    Failure\nimport Parser.DeliveryScheme.Either Either[ParseError, T]      Right   Left       thrown\nimport Parser.DeliveryScheme.Throw  T                          T       thrown     thrown\n=================================== ========================== ======= ========== ================\n\n.. _\nec: https://github.com/sirthias/parboiled2/blob/master/parboiled-core/src/test/scala/org/parboiled2/ErrorReportingSpec.scala\n\n\nRunning the Examples\n====================\n\nFollow these steps to run the example parsers defined here__ on your own machine:\n\n1. Clone the *parboiled2* repository::\n\n    git clone git@github.com:sirthias/parboiled2.git\n\n2. Change into the base directory::\n\n    cd parboiled2\n\n3. Run SBT::\n\n    sbt \"project examples\" run\n\n__ https://github.com/sirthias/parboiled2/tree/master/examples/src/main/scala/org/parboiled2/examples\n\n\nAlternatives\n============\n\nparboiled2 vs. parboiled 1.x\n----------------------------\n\nTODO\n\n(about one order of magnitude faster, more powerful DSL, improved error reporting, fewer dependencies (more lightweight),\nbut Scala 2.10.3+ only, no error recovery (yet) and no Java version (ever))\n\n\nparboiled2 vs. Scala Parser Combinators\n---------------------------------------\n\nTODO\n\n(several hundred times (!) faster, better error reporting, more concise and elegant DSL, similarly powerful in terms of\nlanguage class capabilities, but Scala 2.10.3+ only, 2 added dependencies (parboiled2 + shapeless))\n\nparboiled2 vs. Regular Expressions\n----------------------------------\n\nTODO\n\n(much easier to read and maintain, more powerful (e.g. regexes do not support recursive structures), faster,\nbut Scala 2.10.3+ only, 2 added dependencies (parboiled2 + shapeless))\n\n\nRoadmap\n=======\n\nTODO\n\n\nContributing\n============\n\nTODO\n\n\nSupport\n=======\n\nIn most cases the `parboiled2 mailing list`__ is probably the best place for your needs with regard to\nsupport, feedback and general discussion.\n\n**Note:** Your first post after signup is going to be moderated (for spam protection), but we'll immediately\ngive you full posting privileges if your message doesn't unmask you as a spammer.\n\n__ https://groups.google.com/forum/#!forum/parboiled-user\n\nYou can also use the gitter.im chat channel for parboiled2:\n\n.. image:: https://badges.gitter.im/Join%20Chat.svg\n   :alt: Join the chat at https://gitter.im/sirthias/parboiled2\n   :target: https://gitter.im/sirthias/parboiled2?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge\n\n\nReferences\n==========\n\nTODO\n\n\nCredits\n=======\n\nMuch of *parboiled2* was developed by `Alexander Myltsev`__ during `GSoc 2013`__, a big thank you for his great work!\n\nAlso, without the `Macro Paradise`__ made available by `Eugene Burmako`__ *parboiled2* would probably still not be ready\nand its codebase would look a lot more messy.\n\n\n__ https://github.com/alexander-myltsev\n__ https://www.google-melange.com/archive/gsoc/2013\n__ https://docs.scala-lang.org/overviews/macros/paradise.html\n__ https://github.com/xeno-by\n\n\nLicense\n=======\n\n*parboiled2* is released under the `Apache License 2.0`__\n\n__ https://en.wikipedia.org/wiki/Apache_license\n\n.. |--| unicode:: U+2013\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsirthias%2Fparboiled2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsirthias%2Fparboiled2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsirthias%2Fparboiled2/lists"}