use std::borrow::Cow;
use super::ast::Expr;
grammar;
// Below implements a hierarchy of operator precedences. The lower-numbered
// `Expr`s bind less tightly than the higher-numbered `Expr`s.
pub Expr: Expr<'input> = {
<lhs:Expr> "|" <rhs:Expr2> => Expr::FunctionCall(Cow::Borrowed("union"), vec![lhs, rhs]),
<lhs:Expr> "+" <rhs:Expr2> => Expr::FunctionCall(Cow::Borrowed("union"), vec![lhs, rhs]),
<lhs:Expr> "or" <rhs:Expr2> => Expr::FunctionCall(Cow::Borrowed("union"), vec![lhs, rhs]),
<Expr2>,
}
Expr2: Expr<'input> = {
<lhs:Expr2> "&" <rhs:Expr3> => Expr::FunctionCall(Cow::Borrowed("intersection"), vec![lhs, rhs]),
<lhs:Expr2> "and" <rhs:Expr3> => Expr::FunctionCall(Cow::Borrowed("intersection"), vec![lhs, rhs]),
<lhs:Expr2> "-" <rhs:Expr3> => Expr::FunctionCall(Cow::Borrowed("difference"), vec![lhs, rhs]),
<lhs:Expr2> "%" <rhs:Expr3> => Expr::FunctionCall(Cow::Borrowed("only"), vec![lhs, rhs]),
<Expr3>
}
Expr3: Expr<'input> = {
<lhs:Expr3> ":" <rhs:Expr4> => Expr::FunctionCall(Cow::Borrowed("range"), vec![lhs, rhs]),
<lhs:Expr3> ":" => Expr::FunctionCall(Cow::Borrowed("descendants"), vec![lhs, ]),
":" <rhs:Expr4> => Expr::FunctionCall(Cow::Borrowed("ancestors"), vec![ rhs]),
// For Mercurial users' familiarity.
<lhs:Expr3> "::" <rhs:Expr4> => Expr::FunctionCall(Cow::Borrowed("range"), vec![lhs, rhs]),
<lhs:Expr3> "::" => Expr::FunctionCall(Cow::Borrowed("descendants"), vec![lhs, ]),
"::" <rhs:Expr4> => Expr::FunctionCall(Cow::Borrowed("ancestors"), vec![ rhs]),
// Note that the LHS and RHS are passed in opposite order to `only`.
<lhs:Expr3> ".." <rhs:Expr4> => Expr::FunctionCall(Cow::Borrowed("only"), vec![rhs, lhs]),
<lhs:Expr3> ".." => Expr::FunctionCall(Cow::Borrowed("only"), vec![Expr::Name(Cow::Borrowed(".")), lhs]),
".." <rhs:Expr4> => Expr::FunctionCall(Cow::Borrowed("only"), vec![rhs, Expr::Name(Cow::Borrowed("."))]),
<Expr4>
}
Expr4: Expr<'input> = {
<lhs:Expr4> "^" => Expr::FunctionCall(Cow::Borrowed("parents.nth"), vec![lhs, Expr::Name(Cow::Borrowed("1"))]),
<lhs:Expr4> "^" <rhs:Name> => Expr::FunctionCall(Cow::Borrowed("parents.nth"), vec![lhs, Expr::Name(rhs)]),
<lhs:Expr4> "~" => Expr::FunctionCall(Cow::Borrowed("ancestors.nth"), vec![lhs, Expr::Name(Cow::Borrowed("1"))]),
<lhs:Expr4> "~" <rhs:Name> => Expr::FunctionCall(Cow::Borrowed("ancestors.nth"), vec![lhs, Expr::Name(rhs)]),
<Expr5>
}
Expr5: Expr<'input> = {
"(" <Expr> ")",
<name:Name> "(" <args:FunctionArgs> ")" => Expr::FunctionCall(name, args),
<name:Name> => Expr::Name(name),
}
Name: Cow<'input, str> = {
// NOTE: `.` should be allowed in names, but not `..` (since that is an operator).
<s:r"([a-zA-Z0-9_$@/-]|\.[a-zA-Z0-9_$@/-])+|\."> => Cow::Borrowed(&s),
// Escaping is not supported in LALROP regex literals.
// \x22 = double-quote.
// \x27 = single-quote.
// \x5c = backslash
<s:r"\x22([^\x22]|\x5c.)*\x22|\x27([^\x27]|\x5c.)*\x27"> => {
assert!(s.len() >= 2, "There should be at least 2 quote characters in the string literal, got: {}", s);
let mut result = String::new();
let mut last_char_was_backslash = false;
for c in s.chars().skip(1) {
if last_char_was_backslash {
result.push(match c {
'n' => '\n',
'r' => '\r',
't' => '\t',
c => c,
});
} else if c == '\\' {
last_char_was_backslash = true;
} else {
result.push(c);
}
}
result.pop();
Cow::Owned(result)
},
}
FunctionArgs: Vec<Expr<'input>> = {
<exprs:(<Expr> ",")*> <last_expr:Expr?> => {
let mut exprs = exprs;
if let Some(last_expr) = last_expr {
exprs.push(last_expr);
}
exprs
}
}