reggy 0.0.6

friendly, resumable regular expressions for text analytics
Documentation
use std::str::FromStr;

use crate::parser::{ParseError, lexer, ast, Error};
use lexer::Tok;
use ast::Ast;

grammar();

pub Ast: ast::Ast = {
    #[precedence(level="0")]
    Term,
    
    #[precedence(level="1")] #[assoc(side="right")]
    <t: Ast> "?" => Ast::optional(t),
    <t: Ast> "{" <n: Nat> "}" =>? {
        if let Some(n) = n {
            Ok(Ast::quantifier_exact(t, n))
        } else {
            Err(ParseError::User { error: Error::ParseError })
        }
    },
    <t: Ast> "{" <min: Nat> "," <max: Nat> "}" =>? {
        if let (Some(min), Some(max)) = (min, max) {
            Ok(Ast::quantifier_range(t, min, max))
        } else {
            Err(ParseError::User { error: Error::ParseError })
        }
    },
    #[precedence(level="2")] #[assoc(side="left")]
    <lhs: Ast> <rhs: Ast> => Ast::then(lhs, rhs),
    
    #[precedence(level="3")] #[assoc(side="left")]
    <lhs: Ast> "|" <rhs: Ast> => Ast::or(lhs, rhs),
}

Term: ast::Ast = {
    <c: "char"> => Ast::char(c),
    <"digit"> => Ast::digit(),
    <" "> => Ast::space(),
    "(" <p: Ast> ")" => p,
    "(" "!" <p: Ast> ")" => Ast::case_sensitive(p)
}

Nat: Option<u32> = <s: NatSeq> => s.as_deref().map(u32::from_str)?.ok();

NatSeq: Option<String> = {
    <c: "char"> => {
        if c.is_ascii_digit() {
            Some(String::from(c))
        } else {
            None
        }
    },
    <substr: NatSeq> <c: "char"> => {
        if let Some(mut substr) = substr {
            if c.is_ascii_digit() {
                substr.push(c);
                Some(substr)
            } else {
                None
            }
        } else {
            None
        }
    }
}

extern {
    type Location = usize;
    type Error = Error;

    enum Tok {
        "|" => lexer::Tok::Or,
        "?" => lexer::Tok::QMark,
        "(" => lexer::Tok::LParen,
        ")" => lexer::Tok::RParen,
        "{" => lexer::Tok::LCurly,
        "}" => lexer::Tok::RCurly,
        "!" => lexer::Tok::Exclam,
        "," => lexer::Tok::Comma,
        "char" => lexer::Tok::Char { c: <char>, .. },
        "digit" => lexer::Tok::Digit,
        " " => lexer::Tok::Space
    }
}