crabwise_antlr_parser/
ast.rs

1use combine_proc_macro::{Ident, Literal};
2
3#[derive(Debug)]
4pub struct Grammar {
5    pub name: Ident,
6    pub rules: Vec<Rule>,
7}
8
9#[derive(Debug)]
10pub struct Rule {
11    pub name: Ident,
12    pub pattern: Pattern,
13    pub attributes: Vec<Attribute>,
14}
15
16#[derive(Debug)]
17pub enum Attribute {
18    Word(Ident), // e.g. `syn::Word`
19    Group(Ident, Vec<Attribute>), // e.g. `syn::Meta::List`
20}
21
22#[derive(Debug)]
23pub enum Pattern {
24    Empty,
25
26    /// A rule or terminal (e.g. `L_PAREN`)
27    Ident(Ident),
28
29    /// A literal string (e.g. `"keyword"`)
30    Literal(Literal),
31
32    /// Multiple patterns matched in a row (e.g. `L_PAREN IDENT R_PAREN`)
33    Series(Vec<Pattern>),
34
35    /// A choice between multiple patterns (e.g. `"public" | "private"`)
36    Choice(Vec<Pattern>),
37
38    /// A repetition of a pattern group (e.g. `(IDENT COLON type_expr COMMA)+`)
39    Repeat { pattern: Box<Pattern>, repeat: Repeat },
40
41    /// A pre-condition to check before parsing a tree, typically
42    /// to resolve syntactic ambiguity; e.g. the `(...) => ...` in:
43    ///
44    /// >    lhs_expression:
45    /// >        ("new" expression) => newExpression
46    /// >        | expression
47    /// >        ;
48    ///
49    Predicate { pred: Box<Pattern>, expr: Box<Pattern> },
50}
51
52impl Pattern {
53    pub fn is_empty(&self) -> bool {
54        std::mem::discriminant(self) == std::mem::discriminant(&Pattern::Empty)
55    }
56
57    /// Unwraps the top-level of the pattern tree, if possible.
58    pub fn flatten_once(mut self) -> Pattern {
59        match self {
60            Pattern::Choice(ref mut p) if p.len() == 0 => Pattern::Empty,
61            Pattern::Choice(ref mut p) if p.len() == 1 => p.drain(0..1).next().unwrap(),
62            Pattern::Series(ref mut p) if p.len() == 0 => Pattern::Empty,
63            Pattern::Series(ref mut p) if p.len() == 1 => p.drain(0..1).next().unwrap(),
64            Pattern::Repeat { ref pattern, .. } if pattern.is_empty() => Pattern::Empty,
65            Pattern::Predicate { pred, expr } => {
66                if pred.is_empty() {
67                    *expr
68                } else {
69                    Pattern::Predicate { pred, expr }
70                }
71            }
72            _ => self,
73        }
74    }
75
76    // /// Flattens the entire pattern tree recursively
77    // pub fn flatten_all(self) -> Pattern { ... }
78}
79
80#[derive(Copy, Clone, Debug)]
81pub enum Repeat {
82    ZeroOrOne,
83    ZeroOrMore,
84    OneOrMore,
85}