pub enum Expr {
Show 18 variants
Str(String),
Insens(String),
Range(String, String),
Ident(String),
PeekSlice(i32, Option<i32>),
PosPred(Box<Expr>),
NegPred(Box<Expr>),
Seq(Box<Expr>, Box<Expr>),
Choice(Box<Expr>, Box<Expr>),
Opt(Box<Expr>),
Rep(Box<Expr>),
RepOnce(Box<Expr>),
RepExact(Box<Expr>, u32),
RepMin(Box<Expr>, u32),
RepMax(Box<Expr>, u32),
RepMinMax(Box<Expr>, u32, u32),
Skip(Vec<String>),
Push(Box<Expr>),
}
Expand description
All possible rule expressions
Variants§
Str(String)
Matches an exact string, e.g. "a"
Insens(String)
Matches an exact string, case insensitively (ASCII only), e.g. ^"a"
Range(String, String)
Matches one character in the range, e.g. 'a'..'z'
Ident(String)
Matches the rule with the given name, e.g. a
PeekSlice(i32, Option<i32>)
Matches a custom part of the stack, e.g. PEEK[..]
PosPred(Box<Expr>)
Positive lookahead; matches expression without making progress, e.g. &e
NegPred(Box<Expr>)
Negative lookahead; matches if expression doesn’t match, without making progress, e.g. !e
Seq(Box<Expr>, Box<Expr>)
Matches a sequence of two expressions, e.g. e1 ~ e2
Choice(Box<Expr>, Box<Expr>)
Matches either of two expressions, e.g. e1 | e2
Opt(Box<Expr>)
Optionally matches an expression, e.g. e?
Rep(Box<Expr>)
Matches an expression zero or more times, e.g. e*
RepOnce(Box<Expr>)
Matches an expression one or more times, e.g. e+
RepExact(Box<Expr>, u32)
Matches an expression an exact number of times, e.g. e{n}
RepMin(Box<Expr>, u32)
Matches an expression at least a number of times, e.g. e{n,}
RepMax(Box<Expr>, u32)
Matches an expression at most a number of times, e.g. e{,n}
RepMinMax(Box<Expr>, u32, u32)
Matches an expression a number of times within a range, e.g. e{m, n}
Skip(Vec<String>)
Continues to match expressions until one of the strings in the Vec
is found
Push(Box<Expr>)
Matches an expression and pushes it to the stack, e.g. push(e)
Implementations§
source§impl Expr
impl Expr
sourcepub fn iter_top_down(&self) -> ExprTopDownIterator ⓘ
pub fn iter_top_down(&self) -> ExprTopDownIterator ⓘ
Returns the iterator that steps the expression from top to bottom.
sourcepub fn map_top_down<F>(self, f: F) -> Exprwhere
F: FnMut(Expr) -> Expr,
pub fn map_top_down<F>(self, f: F) -> Exprwhere
F: FnMut(Expr) -> Expr,
Applies f
to the expression and all its children (top to bottom).
Examples found in repository?
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
pub fn rotate(rule: Rule) -> Rule {
fn rotate_internal(expr: Expr) -> Expr {
match expr {
// TODO: Use box syntax when it gets stabilized.
Expr::Seq(lhs, rhs) => {
let lhs = *lhs;
match lhs {
Expr::Seq(ll, lr) => {
rotate_internal(Expr::Seq(ll, Box::new(Expr::Seq(lr, rhs))))
}
lhs => Expr::Seq(Box::new(lhs), rhs),
}
}
Expr::Choice(lhs, rhs) => {
let lhs = *lhs;
match lhs {
Expr::Choice(ll, lr) => {
rotate_internal(Expr::Choice(ll, Box::new(Expr::Choice(lr, rhs))))
}
lhs => Expr::Choice(Box::new(lhs), rhs),
}
}
expr => expr,
}
}
let Rule { name, ty, expr } = rule;
Rule {
name,
ty,
expr: expr.map_top_down(rotate_internal),
}
}
More examples
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
pub fn skip(rule: Rule) -> Rule {
fn populate_choices(expr: Expr, mut choices: Vec<String>) -> Option<Expr> {
match expr {
Expr::Choice(lhs, rhs) => {
if let Expr::Str(string) = *lhs {
choices.push(string);
populate_choices(*rhs, choices)
} else {
None
}
}
Expr::Str(string) => {
choices.push(string);
Some(Expr::Skip(choices))
}
_ => None,
}
}
let Rule { name, ty, expr } = rule;
Rule {
name,
ty,
expr: if ty == RuleType::Atomic {
expr.map_top_down(|expr| {
// TODO: Use box syntax when it gets stabilized.
if let Expr::Rep(expr) = expr.clone() {
if let Expr::Seq(lhs, rhs) = *expr {
if let (Expr::NegPred(expr), Expr::Ident(ident)) = (*lhs, *rhs) {
if ident == "ANY" {
if let Some(expr) = populate_choices(*expr, vec![]) {
return expr;
}
}
}
}
};
expr
})
} else {
expr
},
}
}
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
pub fn factor(rule: Rule) -> Rule {
let Rule { name, ty, expr } = rule;
Rule {
name,
ty,
expr: expr.map_top_down(|expr| {
// TODO: Use box syntax when it gets stabilized.
match expr {
Expr::Choice(lhs, rhs) => match (*lhs, *rhs) {
(Expr::Seq(l1, r1), Expr::Seq(l2, r2)) => {
if l1 == l2 {
Expr::Seq(l1, Box::new(Expr::Choice(r1, r2)))
} else {
Expr::Choice(Box::new(Expr::Seq(l1, r1)), Box::new(Expr::Seq(l2, r2)))
}
}
// Converts `(rule ~ rest) | rule` to `rule ~ rest?`, avoiding trying to match `rule` twice.
(Expr::Seq(l1, l2), r) => {
if *l1 == r {
Expr::Seq(l1, Box::new(Expr::Opt(l2)))
} else {
Expr::Choice(Box::new(Expr::Seq(l1, l2)), Box::new(r))
}
}
// Converts `rule | (rule ~ rest)` to `rule` since `(rule ~ rest)`
// will never match if `rule` didn't.
(l, Expr::Seq(r1, r2)) => {
if l == *r1 {
l
} else {
Expr::Choice(Box::new(l), Box::new(Expr::Seq(r1, r2)))
}
}
(lhs, rhs) => Expr::Choice(Box::new(lhs), Box::new(rhs)),
},
expr => expr,
}
}),
}
}
sourcepub fn map_bottom_up<F>(self, f: F) -> Exprwhere
F: FnMut(Expr) -> Expr,
pub fn map_bottom_up<F>(self, f: F) -> Exprwhere
F: FnMut(Expr) -> Expr,
Applies f
to the expression and all its children (bottom up).
Examples found in repository?
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
pub fn concatenate(rule: Rule) -> Rule {
let Rule { name, ty, expr } = rule;
Rule {
name,
ty,
expr: expr.map_bottom_up(|expr| {
if ty == RuleType::Atomic {
// TODO: Use box syntax when it gets stabilized.
match expr {
Expr::Seq(lhs, rhs) => match (*lhs, *rhs) {
(Expr::Str(lhs), Expr::Str(rhs)) => Expr::Str(lhs + &rhs),
(Expr::Insens(lhs), Expr::Insens(rhs)) => Expr::Insens(lhs + &rhs),
(lhs, rhs) => Expr::Seq(Box::new(lhs), Box::new(rhs)),
},
expr => expr,
}
} else {
expr
}
}),
}
}
More examples
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
pub fn list(rule: Rule) -> Rule {
let Rule { name, ty, expr } = rule;
Rule {
name,
ty,
expr: expr.map_bottom_up(|expr| {
// TODO: Use box syntax when it gets stabilized.
match expr {
Expr::Seq(l, r) => match *l {
Expr::Rep(l) => {
let l = *l;
match l {
Expr::Seq(l1, l2) => {
// Converts `(rule ~ rest)* ~ rule` to `rule ~ (rest ~ rule)*`,
// avoiding matching the last `rule` twice.
if l1 == r {
Expr::Seq(l1, Box::new(Expr::Rep(Box::new(Expr::Seq(l2, r)))))
} else {
Expr::Seq(Box::new(Expr::Rep(Box::new(Expr::Seq(l1, l2)))), r)
}
}
expr => Expr::Seq(Box::new(Expr::Rep(Box::new(expr))), r),
}
}
expr => Expr::Seq(Box::new(expr), r),
},
expr => expr,
}
}),
}
}
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
pub fn unroll(rule: Rule) -> Rule {
let Rule { name, ty, expr } = rule;
Rule {
name,
ty,
expr: expr.map_bottom_up(|expr| match expr {
Expr::RepOnce(expr) => Expr::Seq(expr.clone(), Box::new(Expr::Rep(expr))),
Expr::RepExact(expr, num) => (1..num + 1)
.map(|_| *expr.clone())
.rev()
.fold(None, |rep, expr| match rep {
None => Some(expr),
Some(rep) => Some(Expr::Seq(Box::new(expr), Box::new(rep))),
})
.unwrap(),
Expr::RepMin(expr, min) => (1..min + 2)
.map(|i| {
if i <= min {
*expr.clone()
} else {
Expr::Rep(expr.clone())
}
})
.rev()
.fold(None, |rep, expr| match rep {
None => Some(expr),
Some(rep) => Some(Expr::Seq(Box::new(expr), Box::new(rep))),
})
.unwrap(),
Expr::RepMax(expr, max) => (1..max + 1)
.map(|_| Expr::Opt(expr.clone()))
.rev()
.fold(None, |rep, expr| match rep {
None => Some(expr),
Some(rep) => Some(Expr::Seq(Box::new(expr), Box::new(rep))),
})
.unwrap(),
Expr::RepMinMax(expr, min, max) => (1..max + 1)
.map(|i| {
if i <= min {
*expr.clone()
} else {
Expr::Opt(expr.clone())
}
})
.rev()
.fold(None, |rep, expr| match rep {
None => Some(expr),
Some(rep) => Some(Expr::Seq(Box::new(expr), Box::new(rep))),
})
.unwrap(),
expr => expr,
}),
}
}