pest::grammar! [] [src]

macro_rules! grammar {
    ( @assoc < $( $ts:tt )* ) => { ... };
    ( @assoc $( $ts:tt )* ) => { ... };
    ( @conv $atomic:tt $slf:ident [ < $( $ts:tt )* ] [] [] ) => { ... };
    ( @conv_prec $pos:ident ($_prec:expr) $_atomic:tt $slf:ident [] [] [] ) => { ... };
    ( @conv_prec $pos:ident ($prec:expr) $atomic:tt $slf:ident
      [ $name:ident = { $( $head:tt )* } $( $tail:tt )* ] [] [] ) => { ... };
    ( @conv_prec $pos:ident ($prec:expr) $atomic:tt $slf:ident
      [ $name:ident = @{ $( $head:tt )* } $( $tail:tt )* ] [] [] ) => { ... };
    ( @conv_prec $pos:ident ($prec:expr) $atomic:tt $slf:ident
      [ $name:ident = _{ $( $head:tt )* } $( $tail:tt )* ] [] [] ) => { ... };
    ( @conv $atomic:tt $slf:ident [ { $( $primary:tt )* } $( $ts:tt )* ] [] [] ) => { ... };
    ( @conv $atomic:tt $slf:ident [ ( $( $head:tt )* ) $( $tail:tt )* ] [ $( $optail:tt )* ]
      [ $( $output:tt )* ] ) => { ... };
    ( @conv $atomic:tt $slf:ident [ _rp $( $tail:tt )* ] [ _lp $( $optail:tt )* ]
      [ $( $output:tt )* ] ) => { ... };
    ( @conv $atomic:tt $slf:ident [ _rp $( $tail:tt )* ] [ $op:tt $( $optail:tt )* ]
      [ $( $output:tt )* ] ) => { ... };
    ( @conv $atomic:tt $slf:ident [ & $head:tt $( $tail:tt )* ] [ $( $optail:tt )* ]
      $output:tt ) => { ... };
    ( @conv $atomic:tt $slf:ident [ ! $head:tt $( $tail:tt )* ] [ $( $optail:tt )* ]
      $output:tt ) => { ... };
    ( @conv $atomic:tt $slf:ident [ ~ $( $tail:tt )* ] [ ~ $( $optail:tt )* ]
      [ $( $output:tt )* ] ) => { ... };
    ( @conv $atomic:tt $slf:ident [ ~ $( $tail:tt )* ] [ $( $optail:tt )* ] $output:tt) => { ... };
    ( @conv $atomic:tt $slf:ident [ | $( $tail:tt )* ] [ ~ $( $optail:tt )* ]
      [ $( $output:tt )* ] ) => { ... };
    ( @conv $atomic:tt $slf:ident [ | $( $tail:tt )* ] [ | $( $optail:tt )* ]
      [ $( $output:tt )* ] ) => { ... };
    ( @conv $atomic:tt $slf:ident [ | $( $tail:tt )* ] [ $( $optail:tt )* ] $output:tt) => { ... };
    ( @conv $atomic:tt $slf:ident [ $head:tt $( $tail:tt )* ] $ops:tt [ $( $output:tt )* ] ) => { ... };
    ( @conv $atomic:tt $slf:ident [] [] [ $( $output:tt )* ] ) => { ... };
    ( @conv $atomic:tt $slf:ident [] [ $op:tt $( $optail:tt )* ] [ $( $output:tt )* ] ) => { ... };
    ( @mtc $slf:ident (( $exp:expr )) ) => { ... };
    ( @mtc $slf:ident [ $left:tt .. $right:tt ]) => { ... };
    ( @mtc $slf:ident [ $left:expr, $right:expr ]) => { ... };
    ( @mtc $slf:ident [ $str:expr ]) => { ... };
    ( @mtc $slf:ident $rule:ident) => { ... };
    ( @process $_atomic:tt $_slf:ident [( $result:expr )] [] ) => { ... };
    ( @process false $slf:ident [ $b:tt $a:tt $( $tail:tt )* ] [ ~ $( $optail:tt )* ] ) => { ... };
    ( @process true $slf:ident [ $b:tt $a:tt $( $tail:tt )* ] [ ~ $( $optail:tt )* ] ) => { ... };
    ( @process $atomic:tt $slf:ident [ $b:tt $a:tt $( $tail:tt )* ] [ | $( $optail:tt )* ] ) => { ... };
    ( @process false $slf:ident [ $a:tt $( $tail:tt )* ] [ * $( $optail:tt )* ] ) => { ... };
    ( @process true $slf:ident [ $a:tt $( $tail:tt )* ] [ * $( $optail:tt )* ] ) => { ... };
    ( @process false $slf:ident [ $a:tt $( $tail:tt )* ] [ + $( $optail:tt )* ] ) => { ... };
    ( @process true $slf:ident [ $a:tt $( $tail:tt )* ] [ + $( $optail:tt )* ] ) => { ... };
    ( @process $atomic:tt $slf:ident [ $a:tt $( $tail:tt )* ] [ ? $( $optail:tt )* ] ) => { ... };
    ( @process $atomic:tt $slf:ident [ $a:tt $( $tail:tt )* ] [ _pres $( $optail:tt )* ] ) => { ... };
    ( @process $atomic:tt $slf:ident [ $a:tt $( $tail:tt )* ] [ _abs $( $optail:tt )* ] ) => { ... };
    ( @process $_atomic:tt $slf:ident [] [ $single:tt ] ) => { ... };
    ( @process $atomic:tt $slf:ident [ $( $optail:tt )* ] [ $head:tt $( $tail:tt )* ] ) => { ... };
    ( @skip whitespace $_slf:ident ) => { ... };
    ( @skip comment $slf:ident ) => { ... };
    ( @skip $_name:ident $slf:ident ) => { ... };
    ( @skip false $slf:ident ) => { ... };
    ( @skip true $slf:ident ) => { ... };
    ( @atomic whitespace $_atomic:tt $slf:ident $rules:tt ) => { ... };
    ( @atomic comment $_atomic:tt $slf:ident $rules:tt ) => { ... };
    ( @atomic $_name:ident $atomic:tt $slf:ident $rules:tt ) => { ... };
    () => { ... };
    ( $name:ident = { $( $ts:tt )* } $( $tail:tt )* ) => { ... };
    ( $name:ident = @{ $( $ts:tt )* } $( $tail:tt )* ) => { ... };
    ( $name:ident = _{ $( $ts:tt )* } $( $tail:tt )* ) => { ... };
}

A macro that defines each rule as a method on a Parser which parses from the current position. Rules are always defined between braces, with an optional symbol marking the type of rule defined.

Note: grammar! may require you to increase the recursion limit of your create with #![recursion_limit = "*"] where * is the new limit.

pest has four special rules:

  • whitespace - gets run between rules and sub-rules
  • comment - gets run only between rules
  • any - matches exactly one char
  • eoi - (end-of-input) matches only when a Parser has reached its end

whitespace and comment should be overridden and are void otherwise, while any and eoi are predefined rules.

Normal rules

A normal rule will always create a Token and add it to the Parser::queue, along with any subsequent rules that its subrules may create.

one = { two }

If the above rule matches and two is a normal rule as well, the queue of Tokens will contain Token { rule: Rule::one, ... }, Token { rule: Rule::two, ... }.

Normal rules are also tracked for error reporting. Once a normal rule fails, its failure is automatically recorded and available in Parser::expected.

Atomic rules @

Atomic rules work as normal rules apart from the fact that they don't accept any whitespace or comment between rules and sub-rules, and any sub-rules of an atomic rule will not appear in Parser::expected.

ab = @{ a ~ b }

In the rule above, there cannot be anything between a and b for ab to match. This rule has a cascading effect, so any rules called from an atomic rule will also be atomic while being matched in an atomic context. In other words, a and b will also be atomic when being matched inside of ab.

Silent rules _

Silent rules work like normal rules without appearing in Parser::queue or Parser::expected.

whitespace = _{ [" "] }

Unlike atomic rules, silent rules are not cascading. A rule inside a silent rule will not be silent unless it's explicitly stated.

Syntax

Rule What it does
["a"] matches the exact string "a"
['a'..'z'] matches one character between 'a' and 'z'
a matches rule a
a ~ b matches the sequence a b
a | b matches either a or b
a* matches a zero or more times
a+ matches a one or more times
a? optionally matches a
&a matches a without making progress
!a matches if a doesn't match without making progress

Precedence climbing

pest supports a special type of rule that implements precedence climbing in the background.

expression = _{
    { ["("] ~ expression ~ [")"] | number }
    addition       = {  plus  | minus }
    multiplication = {  times | slash }
    power          = {< pow } // < for right-associativity
}

The first part of the precedence climbing rule is the primary expression that comes between braces. It's followed by any number of rules, each rule having a precedence higher than the previous one. The < denote right-associativity, the default being left-associativity.

Examples

impl_rdp! {
    grammar! {
        expression = _{ paren ~ expression? }
        paren      =  { ["("] ~ expression? ~ [")"] }
    }
}

let mut parser = Rdp::new(StringInput::new("(())((())())()"));

assert!(parser.expression());
assert!(parser.end());