summaryrefslogtreecommitdiffstats
path: root/third_party/rust/glsl/src/parsers/nom_helpers.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/glsl/src/parsers/nom_helpers.rs')
-rw-r--r--third_party/rust/glsl/src/parsers/nom_helpers.rs95
1 files changed, 95 insertions, 0 deletions
diff --git a/third_party/rust/glsl/src/parsers/nom_helpers.rs b/third_party/rust/glsl/src/parsers/nom_helpers.rs
new file mode 100644
index 0000000000..657468e9e3
--- /dev/null
+++ b/third_party/rust/glsl/src/parsers/nom_helpers.rs
@@ -0,0 +1,95 @@
+//! Various nom parser helpers.
+
+use nom::branch::alt;
+use nom::bytes::complete::tag;
+use nom::character::complete::{anychar, line_ending, multispace1};
+use nom::combinator::{map, recognize, value};
+use nom::error::{ErrorKind, VerboseError, VerboseErrorKind};
+use nom::multi::fold_many0;
+use nom::{Err as NomErr, IResult};
+
+pub type ParserResult<'a, O> = IResult<&'a str, O, VerboseError<&'a str>>;
+
+// A constant parser that just forwards the value it’s parametered with without reading anything
+// from the input. Especially useful as “fallback” in an alternative parser.
+pub fn cnst<'a, T, E>(t: T) -> impl FnMut(&'a str) -> Result<(&'a str, T), E>
+where
+ T: 'a + Clone,
+{
+ move |i| Ok((i, t.clone()))
+}
+
+// End-of-input parser.
+//
+// Yields `()` if the parser is at the end of the input; an error otherwise.
+pub fn eoi(i: &str) -> ParserResult<()> {
+ if i.is_empty() {
+ Ok((i, ()))
+ } else {
+ Err(NomErr::Error(VerboseError {
+ errors: vec![(i, VerboseErrorKind::Nom(ErrorKind::Eof))],
+ }))
+ }
+}
+
+// A newline parser that accepts:
+//
+// - A newline.
+// - The end of input.
+pub fn eol(i: &str) -> ParserResult<()> {
+ alt((
+ eoi, // this one goes first because it’s very cheap
+ value((), line_ending),
+ ))(i)
+}
+
+// Apply the `f` parser until `g` succeeds. Both parsers consume the input.
+pub fn till<'a, A, B, F, G>(mut f: F, mut g: G) -> impl FnMut(&'a str) -> ParserResult<'a, ()>
+where
+ F: FnMut(&'a str) -> ParserResult<'a, A>,
+ G: FnMut(&'a str) -> ParserResult<'a, B>,
+{
+ move |mut i| loop {
+ if let Ok((i2, _)) = g(i) {
+ break Ok((i2, ()));
+ }
+
+ let (i2, _) = f(i)?;
+ i = i2;
+ }
+}
+
+// A version of many0 that discards the result of the parser, preventing allocating.
+pub fn many0_<'a, A, F>(mut f: F) -> impl FnMut(&'a str) -> ParserResult<'a, ()>
+where
+ F: FnMut(&'a str) -> ParserResult<'a, A>,
+{
+ move |i| fold_many0(&mut f, || (), |_, _| ())(i)
+}
+
+/// Parse a string until the end of line.
+///
+/// This parser accepts the multiline annotation (\) to break the string on several lines.
+///
+/// Discard any leading newline.
+pub fn str_till_eol(i: &str) -> ParserResult<&str> {
+ map(
+ recognize(till(alt((value((), tag("\\\n")), value((), anychar))), eol)),
+ |i| {
+ if i.as_bytes().last() == Some(&b'\n') {
+ &i[0..i.len() - 1]
+ } else {
+ i
+ }
+ },
+ )(i)
+}
+
+// Blank base parser.
+//
+// This parser succeeds with multispaces and multiline annotation.
+//
+// Taylor Swift loves it.
+pub fn blank_space(i: &str) -> ParserResult<&str> {
+ recognize(many0_(alt((multispace1, tag("\\\n")))))(i)
+}