Add .ignore() for convenience

This commit is contained in:
Garen Tyler 2020-12-02 11:43:23 -07:00
parent f03b303bdb
commit eadba42762
3 changed files with 44 additions and 38 deletions

View File

@ -1,5 +1,5 @@
fn main() {
let src = "log(2 + 4, variable)";
let src = "log(1, 2)";
let ast = pivot::parse(src);
println!("{}", ast);
}

View File

@ -8,7 +8,7 @@ pub enum ParserKind {
Regex(Regex),
Constant(String),
And,
Ignore(bool),
Ignore,
Or,
Repeat(usize),
RepeatRange(Range<usize>),
@ -29,7 +29,7 @@ impl std::fmt::Display for ParserKind {
Regex(r) => write!(f, "Regex /{}/", r.as_str()),
Constant(c) => write!(f, "Constant \"{}\"", c),
And => write!(f, "And"),
Ignore(b) => write!(f, "Ignore{}", if *b { "Before" } else { "After" }),
Ignore => write!(f, "Ignore"),
Or => write!(f, "Or"),
Repeat(num) => write!(f, "Repeat {}", num),
RepeatRange(range) => write!(f, "RepeatRange {:?}", range),
@ -47,7 +47,7 @@ impl Clone for ParserKind {
Regex(r) => Regex(r.clone()),
Constant(c) => Constant(c.clone()),
And => And,
Ignore(b) => Ignore(*b),
Ignore => Ignore,
Or => Or,
Repeat(num) => Repeat(num.clone()),
RepeatRange(range) => RepeatRange(range.clone()),
@ -57,6 +57,11 @@ impl Clone for ParserKind {
}
}
}
impl PartialEq for ParserKind {
fn eq(&self, other: &ParserKind) -> bool {
format!("{}", self) == format!("{}", other)
}
}
#[derive(Debug, Clone)]
pub struct Parser {
@ -96,6 +101,20 @@ impl Parser {
}
Constant(constant) => Ok((constant.clone(), s)),
And => {
if self.subparsers[0].kind == Ignore
&& self.subparsers[1].kind == Ignore {
Ok(("".into(), s))
} else if self.subparsers[0].kind == Ignore {
let (_, rest) = self.subparsers[0].parse(s)?;
self.subparsers[1].parse(rest)
} else if self.subparsers[1].kind == Ignore {
let (matched, lrest) = self.subparsers[0].parse(s.clone())?;
if let Ok((_, rest)) = self.subparsers[1].parse(lrest) {
Ok((matched, rest))
} else {
Err(s)
}
} else {
let (lmatched, lrest) = self.subparsers[0].parse(s)?;
let (rmatched, rrest) = self.subparsers[1].parse(lrest)?;
Ok((
@ -103,15 +122,9 @@ impl Parser {
rrest,
))
}
Ignore(before) => {
if *before {
let (_, rest) = self.subparsers[0].parse(s)?;
self.subparsers[1].parse(rest)
} else {
let (matched, rest) = self.subparsers[0].parse(s)?;
let (_, rest) = self.subparsers[1].parse(rest)?;
Ok((matched, rest))
}
Ignore => {
self.subparsers[0].parse(s)
}
Or => {
if let Ok(lresult) = self.subparsers[0].parse(s.clone()) {
@ -213,16 +226,10 @@ impl Parser {
subparsers: vec![self, r],
}
}
pub fn ignore_before(self, r: Parser) -> Parser {
pub fn ignore(self) -> Parser {
Parser {
kind: ParserKind::Ignore(true),
subparsers: vec![self, r],
}
}
pub fn ignore_after(self, r: Parser) -> Parser {
Parser {
kind: ParserKind::Ignore(false),
subparsers: vec![self, r],
kind: ParserKind::Ignore,
subparsers: vec![self],
}
}
pub fn or(self, r: Parser) -> Parser {

View File

@ -14,7 +14,7 @@ fn parse_expression(src: String) -> Result<(String, String), String> {
let ignored = whitespace.or(comments).repeat_range(0..usize::MAX);
// Token parser constructor.
let i = ignored.clone();
let token = move |pattern: &str| i.clone().ignore_before(Parser::regex(pattern));
let token = move |pattern: &str| i.clone().ignore().and(Parser::regex(pattern));
// Token helper parsers.
let FUNCTION = Parser::regex(r"function\b").or(ignored.clone());
let IF = token(r"if\b");
@ -73,11 +73,10 @@ fn parse_expression(src: String) -> Result<(String, String), String> {
// Expression parser.
let expression = Parser::custom(parse_expression);
// Call parser.
let args = expression
.clone()
let args = expression.clone()
.and(
COMMA
.ignore_before(expression.clone())
COMMA.clone().ignore()
.and(expression.clone())
.repeat_range(0..usize::MAX),
)
.map(|matched| {
@ -90,11 +89,10 @@ fn parse_expression(src: String) -> Result<(String, String), String> {
}
Ok(to_string(&args)?)
});
let call = IDENTIFIER
.clone()
.ignore_after(LEFT_PAREN.clone())
let call = IDENTIFIER.clone()
.and(LEFT_PAREN.clone().ignore())
.and(args.clone())
.ignore_after(RIGHT_PAREN.clone())
.and(RIGHT_PAREN.clone().ignore())
.map(|matched| {
let data = from_str::<Vec<String>>(&matched)?;
let callee = data[0].clone();
@ -112,10 +110,11 @@ fn parse_expression(src: String) -> Result<(String, String), String> {
.clone()
.or(IDENTIFIER.clone())
.or(NUMBER.clone())
.or(LEFT_PAREN
.clone()
.ignore_before(expression.clone())
.ignore_after(RIGHT_PAREN.clone()));
.or(
LEFT_PAREN.clone().ignore()
.and(expression.clone())
.and(RIGHT_PAREN.clone().ignore())
);
// Unary operator parsers.
let unary = NOT.clone().optional().and(atom.clone()).map(|matched| {
let data = from_str::<Vec<String>>(&matched)?;