Skip to main content

Crate nom_rule

Crate nom_rule 

Source
Expand description

Compose nom parsers with grammar-shaped expressions.

rule! is a procedural macro. It does not tokenize input and does not introduce a new parsing runtime. It expands a rule into ordinary nom parser values, using terminal matcher functions supplied by the calling crate.

The generated code refers to nom::..., so crates using this macro must depend on nom directly.

§Quick Start

use nom::bytes::complete::tag;
use nom::character::complete::{alpha1, digit1};
use nom::combinator::map_res;
use nom::error::ParseError;
use nom::{IResult, Parser};
use nom_rule::rule;

fn match_text<'a, Error>(
    text: &'static str,
) -> impl Parser<&'a str, Output = &'a str, Error = Error>
where
    Error: ParseError<&'a str>,
{
    tag(text)
}

fn number(input: &str) -> IResult<&str, u32> {
    map_res(digit1, str::parse).parse(input)
}

fn assignment(input: &str) -> IResult<&str, (&str, u32)> {
    let mut parser = rule! {
        "let " ~ #alpha1 ~ " = " ~ #number ~ ";"
    };

    let (rest, (_, name, _, value, _)) = parser.parse(input)?;
    Ok((rest, (name, value)))
}

let (rest, (name, value)) = assignment("let answer = 42;").unwrap();

assert_eq!(rest, "");
assert_eq!(name, "answer");
assert_eq!(value, 42);

§Terminals

Terminals are the boundary between the grammar expression and your input representation.

Rule formExpanded call
"text"match_text("text")
TOKEN or path::TOKENmatch_token(TOKEN) or match_token(path::TOKEN)

The matcher signatures are not fixed. They only need to return values that implement nom::Parser for your input type.

Custom terminal matcher paths can be supplied before the rule:

let parser = rule! {
    crate::tokens::text, crate::tokens::kind,
    TokenKind::Create ~ #ident
};

§Rule Syntax

FormMeaningOutput shape
"text"Match text with match_textmatcher output
TOKENMatch a token with match_tokenmatcher output
#parserUse an existing parserparser output
#parser(args...)Call a parser factoryparser output
a ~ bRun parsers in sequence(A, B)
a | bTry alternatives with nom::branch::altbranch output
a?Optional parserOption<A>
a*Zero or more matchesVec<A>
a+One or more matchesVec<A>
&aPeek without consuming inputA
!aNegative lookahead()
^aCut on failureA
a : "context"Add nom::error::contextA

Use parentheses to group subrules.

Operator precedence, from low to high:

  1. choice: a | b
  2. context: a : "context"
  3. sequence: a ~ b
  4. postfix operators: ?, *, +
  5. prefix operators: &, !, ^

Choice branches must return compatible output shapes. An optional branch is rejected before later alternatives because it can succeed without consuming input.

Macros§

rule
Expands a grammar-shaped expression into a nom parser.