cpp_synom-0.12.0/Cargo.toml01006440000765000002400000001664130567074710013771 0ustar0000000000000000# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "cpp_synom" version = "0.12.0" authors = ["Michael Layzell ", "David Tolnay "] include = ["Cargo.toml", "src/**/*.rs"] description = "Stripped-down Nom parser used by cpp_syn" documentation = "https://docs.rs/cpp_syn" license = "MIT/Apache-2.0" repository = "https://github.com/mystor/cpp_syn" [lib] doctest = false [dependencies.unicode-xid] version = "0.0.4" cpp_synom-0.12.0/Cargo.toml.orig01006440000765000002400000001155130567074710014723 0ustar0000000000000000[package] name = "cpp_synom" version = "0.12.0" authors = ["Michael Layzell ", "David Tolnay "] license = "MIT/Apache-2.0" description = "Stripped-down Nom parser used by cpp_syn" repository = "https://github.com/mystor/cpp_syn" documentation = "https://docs.rs/cpp_syn" include = ["Cargo.toml", "src/**/*.rs"] [lib] # Temporarily disable doc tests as they no longer pass due to Span API changes. doctest = false [dependencies] unicode-xid = "0.0.4" # [dev-dependencies.cpp_syn] # version = "0.12.0" # path = ".." # features = ["parsing", "full"] # default-features = false cpp_synom-0.12.0/src/helper.rs01006440000765000002400000024773130567070770014465 0ustar0000000000000000use {IResult, ParseState}; use space::{skip_whitespace, word_break}; /// Parse a piece of punctuation like "+" or "+=". /// /// See also `keyword!` for parsing keywords, which are subtly different from /// punctuation. /// /// - **Syntax:** `punct!("...")` /// - **Output:** `&str` /// /// ```rust /// extern crate syn; /// #[macro_use] extern crate synom; /// /// // Parse zero or more bangs. /// named!(many_bangs -> Vec<&str>, /// many0!(punct!("!")) /// ); /// /// fn main() { /// let input = "!! !"; /// let parsed = many_bangs(input).expect("bangs"); /// assert_eq!(parsed, ["!", "!", "!"]); /// } /// ``` #[macro_export] macro_rules! punct { ($i:expr, $punct:expr) => { $crate::helper::punct($i, $punct) }; } // Not public API. #[doc(hidden)] pub fn punct<'a>(input: ParseState<'a>, token: &'static str) -> IResult, &'a str> { let input = skip_whitespace(input); if input.starts_with(token) { IResult::Done(input.advance(token.len()), token) } else { IResult::Error } } /// Parse a keyword like "fn" or "struct". /// /// See also `punct!` for parsing punctuation, which are subtly different from /// keywords. /// /// - **Syntax:** `keyword!("...")` /// - **Output:** `&str` /// /// ```rust /// extern crate syn; /// #[macro_use] extern crate synom; /// /// use synom::IResult; /// /// // Parse zero or more "bang" keywords. /// named!(many_bangs -> Vec<&str>, /// terminated!( /// many0!(keyword!("bang")), /// punct!(";") /// ) /// ); /// /// fn main() { /// let input = "bang bang bang;"; /// let parsed = many_bangs(input).expect("bangs"); /// assert_eq!(parsed, ["bang", "bang", "bang"]); /// /// let input = "bangbang;"; /// let err = many_bangs(input); /// assert_eq!(err, IResult::Error); /// } /// ``` #[macro_export] macro_rules! keyword { ($i:expr, $keyword:expr) => { $crate::helper::keyword($i, $keyword) }; } // Not public API. #[doc(hidden)] pub fn keyword<'a>(input: ParseState<'a>, token: &'static str) -> IResult, &'a str> { match punct(input, token) { IResult::Done(rest, _) => { match word_break(rest) { IResult::Done(_, _) => IResult::Done(rest, token), IResult::Error => IResult::Error, } } IResult::Error => IResult::Error, } } /// Turn a failed parse into `None` and a successful parse into `Some`. /// /// - **Syntax:** `option!(THING)` /// - **Output:** `Option` /// /// ```rust /// extern crate syn; /// #[macro_use] extern crate synom; /// /// named!(maybe_bang -> Option<&str>, option!(punct!("!"))); /// /// fn main() { /// let input = "!"; /// let parsed = maybe_bang(input).expect("maybe bang"); /// assert_eq!(parsed, Some("!")); /// /// let input = ""; /// let parsed = maybe_bang(input).expect("maybe bang"); /// assert_eq!(parsed, None); /// } /// ``` #[macro_export] macro_rules! option { ($i:expr, $submac:ident!( $($args:tt)* )) => { match $submac!($i, $($args)*) { $crate::IResult::Done(i, o) => $crate::IResult::Done(i, Some(o)), $crate::IResult::Error => $crate::IResult::Done($i, None), } }; ($i:expr, $f:expr) => { option!($i, call!($f)); }; } /// Turn a failed parse into an empty vector. The argument parser must itself /// return a vector. /// /// This is often more convenient than `option!(...)` when the argument produces /// a vector. /// /// - **Syntax:** `opt_vec!(THING)` /// - **Output:** `THING`, which must be `Vec` /// /// ```rust /// extern crate syn; /// #[macro_use] extern crate synom; /// /// use syn::{Lifetime, Ty}; /// use syn::parse::{lifetime, ty}; /// /// named!(bound_lifetimes -> (Vec, Ty), tuple!( /// opt_vec!(do_parse!( /// keyword!("for") >> /// punct!("<") >> /// lifetimes: terminated_list!(punct!(","), lifetime) >> /// punct!(">") >> /// (lifetimes) /// )), /// ty /// )); /// /// fn main() { /// let input = "for<'a, 'b> fn(&'a A) -> &'b B"; /// let parsed = bound_lifetimes(input).expect("bound lifetimes"); /// assert_eq!(parsed.0, [Lifetime::new("'a"), Lifetime::new("'b")]); /// println!("{:?}", parsed); /// /// let input = "From"; /// let parsed = bound_lifetimes(input).expect("bound lifetimes"); /// assert!(parsed.0.is_empty()); /// println!("{:?}", parsed); /// } /// ``` #[macro_export] macro_rules! opt_vec { ($i:expr, $submac:ident!( $($args:tt)* )) => { match $submac!($i, $($args)*) { $crate::IResult::Done(i, o) => $crate::IResult::Done(i, o), $crate::IResult::Error => $crate::IResult::Done($i, Vec::new()), } }; } /// Parses nothing and always succeeds. /// /// This can be useful as a fallthrough case in `alt!`. /// /// - **Syntax:** `epsilon!()` /// - **Output:** `()` /// /// ```rust /// extern crate syn; /// #[macro_use] extern crate synom; /// /// use syn::Mutability; /// /// named!(mutability -> Mutability, alt!( /// keyword!("mut") => { |_| Mutability::Mutable } /// | /// epsilon!() => { |_| Mutability::Immutable } /// )); /// /// fn main() { /// let input = "mut"; /// let parsed = mutability(input).expect("mutability"); /// assert_eq!(parsed, Mutability::Mutable); /// /// let input = ""; /// let parsed = mutability(input).expect("mutability"); /// assert_eq!(parsed, Mutability::Immutable); /// } /// ``` #[macro_export] macro_rules! epsilon { ($i:expr,) => { $crate::IResult::Done($i, ()) }; } /// Run a parser, binding the result to a name, and then evaluating an /// expression. /// /// Discards the result of the expression and parser. /// /// - **Syntax:** `tap!(NAME : THING => EXPR)` /// - **Output:** `()` /// /// ```rust /// extern crate syn; /// #[macro_use] extern crate synom; /// /// use syn::{Expr, ExprKind}; /// use syn::parse::expr; /// /// named!(expr_with_arrow_call -> Expr, do_parse!( /// mut e: expr >> /// many0!(tap!(arg: tuple!(punct!("=>"), expr) => { /// e = Expr { /// node: ExprKind::Call(Box::new(e), vec![arg.1]), /// attrs: Vec::new(), /// }; /// })) >> /// (e) /// )); /// /// fn main() { /// let input = "something => argument1 => argument2"; /// /// let parsed = expr_with_arrow_call(input).expect("expr with arrow call"); /// /// println!("{:?}", parsed); /// } /// ``` #[doc(hidden)] #[macro_export] macro_rules! tap { ($i:expr, $name:ident : $submac:ident!( $($args:tt)* ) => $e:expr) => { match $submac!($i, $($args)*) { $crate::IResult::Done(i, o) => { let $name = o; $e; $crate::IResult::Done(i, ()) } $crate::IResult::Error => $crate::IResult::Error, } }; ($i:expr, $name:ident : $f:expr => $e:expr) => { tap!($i, $name: call!($f) => $e); }; } /// Zero or more values separated by some separator. Does not allow a trailing /// seperator. /// /// The implementation requires that the first parameter is a `punct!` macro, /// and the second is a named parser. /// /// - **Syntax:** `separated_list!(punct!("..."), THING)` /// - **Output:** `Vec` /// /// You may also be looking for: /// /// - `separated_nonempty_list!` - one or more values /// - `terminated_list!` - zero or more, allows trailing separator /// - `many0!` - zero or more, no separator /// /// ```rust /// extern crate syn; /// #[macro_use] extern crate synom; /// /// use syn::Expr; /// use syn::parse::expr; /// /// named!(expr_list -> Vec, /// separated_list!(punct!(","), expr) /// ); /// /// fn main() { /// let input = "1 + 1, things, Construct { this: thing }"; /// /// let parsed = expr_list(input).expect("expr list"); /// assert_eq!(parsed.len(), 3); /// } /// ``` #[macro_export] macro_rules! separated_list { ($i:expr, punct!($sep:expr), $f:expr) => { $crate::helper::separated_list($i, $sep, $f, false) }; } /// Zero or more values separated by some separator. A trailing separator is /// allowed. /// /// The implementation requires that the first parameter is a `punct!` macro, /// and the second is a named parser. /// /// - **Syntax:** `terminated_list!(punct!("..."), THING)` /// - **Output:** `Vec` /// /// You may also be looking for: /// /// - `separated_list!` - zero or more, allows trailing separator /// - `separated_nonempty_list!` - one or more values /// - `many0!` - zero or more, no separator /// /// ```rust /// extern crate syn; /// #[macro_use] extern crate synom; /// /// use syn::Expr; /// use syn::parse::expr; /// /// named!(expr_list -> Vec, /// terminated_list!(punct!(","), expr) /// ); /// /// fn main() { /// let input = "1 + 1, things, Construct { this: thing },"; /// /// let parsed = expr_list(input).expect("expr list"); /// assert_eq!(parsed.len(), 3); /// } /// ``` #[macro_export] macro_rules! terminated_list { ($i:expr, punct!($sep:expr), $f:expr) => { $crate::helper::separated_list($i, $sep, $f, true) }; } // Not public API. #[doc(hidden)] pub fn separated_list<'a, T>(mut input: ParseState<'a>, sep: &'static str, f: fn(ParseState<'a>) -> IResult, T>, terminated: bool) -> IResult, Vec> { let mut res = Vec::new(); // get the first element match f(input) { IResult::Error => IResult::Done(input, Vec::new()), IResult::Done(i, o) => { if i.len() == input.len() { IResult::Error } else { res.push(o); input = i; // get the separator first while let IResult::Done(i2, _) = punct(input, sep) { if i2.len() == input.len() { break; } // get the element next if let IResult::Done(i3, o3) = f(i2) { if i3.len() == i2.len() { break; } res.push(o3); input = i3; } else { break; } } if terminated { if let IResult::Done(after, _) = punct(input, sep) { input = after; } } IResult::Done(input, res) } } } } cpp_synom-0.12.0/src/lib.rs01006440000765000002400000112076130567071330013737 0ustar0000000000000000//! Adapted from [`nom`](https://github.com/Geal/nom) by removing the //! `IResult::Incomplete` variant which: //! //! - we don't need, //! - is an unintuitive footgun when working with non-streaming use cases, and //! - more than doubles compilation time. //! //! ## Whitespace handling strategy //! //! As (sy)nom is a parser combinator library, the parsers provided here and //! that you implement yourself are all made up of successively more primitive //! parsers, eventually culminating in a small number of fundamental parsers //! that are implemented in Rust. Among these are `punct!` and `keyword!`. //! //! All synom fundamental parsers (those not combined out of other parsers) //! should be written to skip over leading whitespace in their input. This way, //! as long as every parser eventually boils down to some combination of //! fundamental parsers, we get correct whitespace handling at all levels for //! free. //! //! For our use case, this strategy is a huge improvement in usability, //! correctness, and compile time over nom's `ws!` strategy. extern crate unicode_xid; use std::str::{CharIndices, Chars, Bytes}; #[doc(hidden)] pub mod space; #[doc(hidden)] pub mod helper; /// A wrapper around a &'a str which keeps track of the current index into the /// source string. Provides a mechanism for determining source locations during /// the parse. #[derive(Debug, Copy, Clone)] pub struct ParseState<'a> { input: &'a str, index: usize, } impl<'a> ParseState<'a> { pub fn new(s: &'a str) -> ParseState<'a> { ParseState { input: s, index: 0, } } pub fn rest(self) -> &'a str { &self.input[self.index..] } pub fn is_empty(self) -> bool { self.rest().is_empty() } pub fn len(self) -> usize { self.rest().len() } pub fn starts_with(self, p: &str) -> bool { self.rest().starts_with(p) } pub fn until(self, i: usize) -> &'a str { &self.rest()[..i] } pub fn char_indices(self) -> CharIndices<'a> { self.rest().char_indices() } pub fn chars(self) -> Chars<'a> { self.rest().chars() } pub fn bytes(self) -> Bytes<'a> { self.rest().bytes() } pub fn advance(self, i: usize) -> ParseState<'a> { let index = i + self.index; assert!(index <= self.input.len()); ParseState { input: self.input, index: index, } } pub fn finish(self) -> ParseState<'a> { ParseState { input: self.input, index: self.input.len(), } } pub fn idx(self) -> usize { self.index } } /// The result of a parser. #[derive(Debug, PartialEq, Eq, Clone)] pub enum IResult { /// Parsing succeeded. The first field contains the rest of the unparsed /// data and the second field contains the parse result. Done(I, O), /// Parsing failed. Error, } impl<'a, O> IResult, O> { /// Unwraps the result, asserting the the parse is complete. Panics with a /// message based on the given string if the parse failed or is incomplete. /// /// ```rust /// extern crate syn; /// #[macro_use] extern crate synom; /// /// use syn::Ty; /// use syn::parse::ty; /// /// // One or more Rust types separated by commas. /// named!(comma_separated_types -> Vec, /// separated_nonempty_list!(punct!(","), ty) /// ); /// /// fn main() { /// let input = "&str, Map, String"; /// /// let parsed = comma_separated_types(input).expect("comma-separated types"); /// /// assert_eq!(parsed.len(), 3); /// println!("{:?}", parsed); /// } /// ``` pub fn expect(self, name: &str) -> O { match self { IResult::Done(mut rest, o) => { rest = space::skip_whitespace(rest); if rest.is_empty() { o } else { panic!("unparsed tokens after {}: {:?}", name, rest) } } IResult::Error => panic!("failed to parse {}", name), } } } impl<'a, O: Eq> IResult, O> { /// This function primarially exists for testing parsers. It returns `true` if the IResult /// "looks like" the passed in parameters. This means that the variant is IResult::Done, /// the `ParseState::rest()` of the input matches `rest` and the result matches. pub fn test_looks_like(&self, rest: &str, result: &O) -> bool { match *self { IResult::Done(input, ref o) => { input.rest() == rest && o == result } IResult::Error => false, } } } /// Define a function from a parser combination. /// /// - **Syntax:** `named!(NAME -> TYPE, PARSER)` or `named!(pub NAME -> TYPE, PARSER)` /// /// ```rust /// # extern crate syn; /// # #[macro_use] extern crate synom; /// # use syn::Ty; /// # use syn::parse::ty; /// // One or more Rust types separated by commas. /// named!(pub comma_separated_types -> Vec, /// separated_nonempty_list!(punct!(","), ty) /// ); /// # fn main() {} /// ``` #[macro_export] macro_rules! named { ($name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => { fn $name(i: $crate::ParseState) -> $crate::IResult<$crate::ParseState, $o> { $submac!(i, $($args)*) } }; (pub $name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => { pub fn $name(i: $crate::ParseState) -> $crate::IResult<$crate::ParseState, $o> { $submac!(i, $($args)*) } }; } /// Invoke the given parser function with the passed in arguments. /// /// - **Syntax:** `call!(FUNCTION, ARGS...)` /// /// where the signature of the function is `fn(&str, ARGS...) -> IResult<&str, T>` /// - **Output:** `T`, the result of invoking the function `FUNCTION` /// /// ```rust /// #[macro_use] extern crate synom; /// /// use synom::IResult; /// /// // Parses any string up to but not including the given character, returning /// // the content up to the given character. The given character is required to /// // be present in the input string. /// fn skip_until(input: &str, ch: char) -> IResult<&str, &str> { /// if let Some(pos) = input.find(ch) { /// IResult::Done(&input[pos..], &input[..pos]) /// } else { /// IResult::Error /// } /// } /// /// // Parses any string surrounded by tilde characters '~'. Returns the content /// // between the tilde characters. /// named!(surrounded_by_tilde -> &str, delimited!( /// punct!("~"), /// call!(skip_until, '~'), /// punct!("~") /// )); /// /// fn main() { /// let input = "~ abc def ~"; /// /// let inner = surrounded_by_tilde(input).expect("surrounded by tilde"); /// /// println!("{:?}", inner); /// } /// ``` #[macro_export] macro_rules! call { ($i:expr, $fun:expr $(, $args:expr)*) => { $fun($i $(, $args)*) }; } /// Transform the result of a parser by applying a function or closure. /// /// - **Syntax:** `map!(THING, FN)` /// - **Output:** the return type of function FN applied to THING /// /// ```rust /// extern crate syn; /// #[macro_use] extern crate synom; /// /// use syn::{Item, Ident}; /// use syn::parse::item; /// /// fn get_item_ident(item: Item) -> Ident { /// item.ident /// } /// /// // Parses an item and returns the name (identifier) of the item only. /// named!(item_ident -> Ident, /// map!(item, get_item_ident) /// ); /// /// // Or equivalently: /// named!(item_ident2 -> Ident, /// map!(item, |i: Item| i.ident) /// ); /// /// fn main() { /// let input = "fn foo() {}"; /// /// let parsed = item_ident(input).expect("item"); /// /// assert_eq!(parsed, "foo"); /// } /// ``` #[macro_export] macro_rules! map { ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => { match $submac!($i, $($args)*) { $crate::IResult::Error => $crate::IResult::Error, $crate::IResult::Done(i, o) => { $crate::IResult::Done(i, call!(o, $g)) } } }; ($i:expr, $f:expr, $g:expr) => { map!($i, call!($f), $g) }; } /// Parses successfully if the given parser fails to parse. Does not consume any /// of the input. /// /// - **Syntax:** `not!(THING)` /// - **Output:** `()` /// /// ```rust /// extern crate syn; /// #[macro_use] extern crate synom; /// use synom::IResult; /// /// // Parses a shebang line like `#!/bin/bash` and returns the part after `#!`. /// // Note that a line starting with `#![` is an inner attribute, not a /// // shebang. /// named!(shebang -> &str, preceded!( /// tuple!(tag!("#!"), not!(tag!("["))), /// take_until!("\n") /// )); /// /// fn main() { /// let bin_bash = "#!/bin/bash\n"; /// let parsed = shebang(bin_bash).expect("shebang"); /// assert_eq!(parsed, "/bin/bash"); /// /// let inner_attr = "#![feature(specialization)]\n"; /// let err = shebang(inner_attr); /// assert_eq!(err, IResult::Error); /// } /// ``` #[macro_export] macro_rules! not { ($i:expr, $submac:ident!( $($args:tt)* )) => { match $submac!($i, $($args)*) { $crate::IResult::Done(_, _) => $crate::IResult::Error, $crate::IResult::Error => $crate::IResult::Done($i, ()), } }; } /// Conditionally execute the given parser. /// /// If you are familiar with nom, this is nom's `cond_with_error` parser. /// /// - **Syntax:** `cond!(CONDITION, THING)` /// - **Output:** `Some(THING)` if the condition is true, else `None` /// /// ```rust /// extern crate syn; /// #[macro_use] extern crate synom; /// /// use syn::parse::boolean; /// /// // Parses a tuple of booleans like `(true, false, false)`, possibly with a /// // dotdot indicating omitted values like `(true, true, .., true)`. Returns /// // separate vectors for the booleans before and after the dotdot. The second /// // vector is None if there was no dotdot. /// named!(bools_with_dotdot -> (Vec, Option>), do_parse!( /// punct!("(") >> /// before: separated_list!(punct!(","), boolean) >> /// after: option!(do_parse!( /// // Only allow comma if there are elements before dotdot, i.e. cannot /// // be `(, .., true)`. /// cond!(!before.is_empty(), punct!(",")) >> /// punct!("..") >> /// after: many0!(preceded!(punct!(","), boolean)) >> /// // Only allow trailing comma if there are elements after dotdot, /// // i.e. cannot be `(true, .., )`. /// cond!(!after.is_empty(), option!(punct!(","))) >> /// (after) /// )) >> /// // Allow trailing comma if there is no dotdot but there are elements. /// cond!(!before.is_empty() && after.is_none(), option!(punct!(","))) >> /// punct!(")") >> /// (before, after) /// )); /// /// fn main() { /// let input = "(true, false, false)"; /// let parsed = bools_with_dotdot(input).expect("bools with dotdot"); /// assert_eq!(parsed, (vec![true, false, false], None)); /// /// let input = "(true, true, .., true)"; /// let parsed = bools_with_dotdot(input).expect("bools with dotdot"); /// assert_eq!(parsed, (vec![true, true], Some(vec![true]))); /// /// let input = "(.., true)"; /// let parsed = bools_with_dotdot(input).expect("bools with dotdot"); /// assert_eq!(parsed, (vec![], Some(vec![true]))); /// /// let input = "(true, true, ..)"; /// let parsed = bools_with_dotdot(input).expect("bools with dotdot"); /// assert_eq!(parsed, (vec![true, true], Some(vec![]))); /// /// let input = "(..)"; /// let parsed = bools_with_dotdot(input).expect("bools with dotdot"); /// assert_eq!(parsed, (vec![], Some(vec![]))); /// } /// ``` #[macro_export] macro_rules! cond { ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => { if $cond { match $submac!($i, $($args)*) { $crate::IResult::Done(i, o) => $crate::IResult::Done(i, ::std::option::Option::Some(o)), $crate::IResult::Error => $crate::IResult::Error, } } else { $crate::IResult::Done($i, ::std::option::Option::None) } }; ($i:expr, $cond:expr, $f:expr) => { cond!($i, $cond, call!($f)) }; } /// Fail to parse if condition is false, otherwise parse the given parser. /// /// This is typically used inside of `option!` or `alt!`. /// /// - **Syntax:** `cond_reduce!(CONDITION, THING)` /// - **Output:** `THING` /// /// ```rust /// extern crate syn; /// #[macro_use] extern crate synom; /// /// use syn::parse::boolean; /// /// #[derive(Debug, PartialEq)] /// struct VariadicBools { /// data: Vec, /// variadic: bool, /// } /// /// // Parse one or more comma-separated booleans, possibly ending in "..." to /// // indicate there may be more. /// named!(variadic_bools -> VariadicBools, do_parse!( /// data: separated_nonempty_list!(punct!(","), boolean) >> /// trailing_comma: option!(punct!(",")) >> /// // Only allow "..." if there is a comma after the last boolean. Using /// // `cond_reduce!` is more convenient here than using `cond!`. The /// // alternatives are: /// // /// // - `cond!(c, option!(p))` or `option!(cond!(c, p))` /// // Gives `Some(Some("..."))` for variadic and `Some(None)` or `None` /// // which both mean not variadic. /// // - `cond_reduce!(c, option!(p))` /// // Incorrect; would fail to parse if there is no trailing comma. /// // - `option!(cond_reduce!(c, p))` /// // Gives `Some("...")` for variadic and `None` otherwise. Perfect! /// variadic: option!(cond_reduce!(trailing_comma.is_some(), punct!("..."))) >> /// (VariadicBools { /// data: data, /// variadic: variadic.is_some(), /// }) /// )); /// /// fn main() { /// let input = "true, true"; /// let parsed = variadic_bools(input).expect("variadic bools"); /// assert_eq!(parsed, VariadicBools { /// data: vec![true, true], /// variadic: false, /// }); /// /// let input = "true, ..."; /// let parsed = variadic_bools(input).expect("variadic bools"); /// assert_eq!(parsed, VariadicBools { /// data: vec![true], /// variadic: true, /// }); /// } /// ``` #[macro_export] macro_rules! cond_reduce { ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => { if $cond { $submac!($i, $($args)*) } else { $crate::IResult::Error } }; ($i:expr, $cond:expr, $f:expr) => { cond_reduce!($i, $cond, call!($f)) }; } /// Parse two things, returning the value of the second. /// /// - **Syntax:** `preceded!(BEFORE, THING)` /// - **Output:** `THING` /// /// ```rust /// extern crate syn; /// #[macro_use] extern crate synom; /// /// use syn::Expr; /// use syn::parse::expr; /// /// // An expression preceded by ##. /// named!(pound_pound_expr -> Expr, /// preceded!(punct!("##"), expr) /// ); /// /// fn main() { /// let input = "## 1 + 1"; /// /// let parsed = pound_pound_expr(input).expect("pound pound expr"); /// /// println!("{:?}", parsed); /// } /// ``` #[macro_export] macro_rules! preceded { ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => { match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) { $crate::IResult::Done(remaining, (_, o)) => $crate::IResult::Done(remaining, o), $crate::IResult::Error => $crate::IResult::Error, } }; ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => { preceded!($i, $submac!($($args)*), call!($g)) }; ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => { preceded!($i, call!($f), $submac!($($args)*)) }; ($i:expr, $f:expr, $g:expr) => { preceded!($i, call!($f), call!($g)) }; } /// Parse two things, returning the value of the first. /// /// - **Syntax:** `terminated!(THING, AFTER)` /// - **Output:** `THING` /// /// ```rust /// extern crate syn; /// #[macro_use] extern crate synom; /// /// use syn::Expr; /// use syn::parse::expr; /// /// // An expression terminated by ##. /// named!(expr_pound_pound -> Expr, /// terminated!(expr, punct!("##")) /// ); /// /// fn main() { /// let input = "1 + 1 ##"; /// /// let parsed = expr_pound_pound(input).expect("expr pound pound"); /// /// println!("{:?}", parsed); /// } /// ``` #[macro_export] macro_rules! terminated { ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => { match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) { $crate::IResult::Done(remaining, (o, _)) => $crate::IResult::Done(remaining, o), $crate::IResult::Error => $crate::IResult::Error, } }; ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => { terminated!($i, $submac!($($args)*), call!($g)) }; ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => { terminated!($i, call!($f), $submac!($($args)*)) }; ($i:expr, $f:expr, $g:expr) => { terminated!($i, call!($f), call!($g)) }; } /// Parse zero or more values using the given parser. /// /// - **Syntax:** `many0!(THING)` /// - **Output:** `Vec` /// /// You may also be looking for: /// /// - `separated_list!` - zero or more values with separator /// - `separated_nonempty_list!` - one or more values /// - `terminated_list!` - zero or more, allows trailing separator /// /// ```rust /// extern crate syn; /// #[macro_use] extern crate synom; /// /// use syn::Item; /// use syn::parse::item; /// /// named!(items -> Vec, many0!(item)); /// /// fn main() { /// let input = " /// fn a() {} /// fn b() {} /// "; /// /// let parsed = items(input).expect("items"); /// /// assert_eq!(parsed.len(), 2); /// println!("{:?}", parsed); /// } /// ``` #[macro_export] macro_rules! many0 { ($i:expr, $submac:ident!( $($args:tt)* )) => {{ let ret; let mut res = ::std::vec::Vec::new(); let mut input = $i; loop { if input.is_empty() { ret = $crate::IResult::Done(input, res); break; } match $submac!(input, $($args)*) { $crate::IResult::Error => { ret = $crate::IResult::Done(input, res); break; } $crate::IResult::Done(i, o) => { // loop trip must always consume (otherwise infinite loops) if i.len() == input.len() { ret = $crate::IResult::Error; break; } res.push(o); input = i; } } } ret }}; ($i:expr, $f:expr) => { $crate::many0($i, $f) }; } // Improve compile time by compiling this loop only once per type it is used // with. // // Not public API. #[doc(hidden)] pub fn many0<'a, T>(mut input: ParseState<'a>, f: fn(ParseState<'a>) -> IResult, T>) -> IResult, Vec> { let mut res = Vec::new(); loop { if input.is_empty() { return IResult::Done(input, res); } match f(input) { IResult::Error => { return IResult::Done(input, res); } IResult::Done(i, o) => { // loop trip must always consume (otherwise infinite loops) if i.len() == input.len() { return IResult::Error; } res.push(o); input = i; } } } } /// Parse a value without consuming it from the input data. /// /// - **Syntax:** `peek!(THING)` /// - **Output:** `THING` /// /// ```rust /// extern crate syn; /// #[macro_use] extern crate synom; /// /// use syn::Expr; /// use syn::parse::{ident, expr}; /// use synom::IResult; /// /// // Parse an expression that begins with an identifier. /// named!(ident_expr -> Expr, /// preceded!(peek!(ident), expr) /// ); /// /// fn main() { /// // begins with an identifier /// let input = "banana + 1"; /// let parsed = ident_expr(input).expect("ident"); /// println!("{:?}", parsed); /// /// // does not begin with an identifier /// let input = "1 + banana"; /// let err = ident_expr(input); /// assert_eq!(err, IResult::Error); /// } /// ``` #[macro_export] macro_rules! peek { ($i:expr, $submac:ident!( $($args:tt)* )) => { match $submac!($i, $($args)*) { $crate::IResult::Done(_, o) => $crate::IResult::Done($i, o), $crate::IResult::Error => $crate::IResult::Error, } }; ($i:expr, $f:expr) => { peek!($i, call!($f)) }; } /// Parse the part of the input up to but not including the given string. Fail /// to parse if the given string is not present in the input. /// /// - **Syntax:** `take_until!("...")` /// - **Output:** `&str` /// /// ```rust /// extern crate syn; /// #[macro_use] extern crate synom; /// use synom::IResult; /// /// // Parse a single line doc comment: /// ... /// named!(single_line_doc -> &str, /// preceded!(punct!("///"), take_until!("\n")) /// ); /// /// fn main() { /// let comment = "/// comment\n"; /// let parsed = single_line_doc(comment).expect("single line doc comment"); /// assert_eq!(parsed, " comment"); /// } /// ``` #[macro_export] macro_rules! take_until { ($i:expr, $substr:expr) => {{ if $substr.len() > $i.len() { $crate::IResult::Error } else { let substr_vec: Vec = $substr.chars().collect(); let mut window: Vec = vec![]; let mut offset = $i.len(); let mut parsed = false; for (o, c) in $i.char_indices() { window.push(c); if window.len() > substr_vec.len() { window.remove(0); } if window == substr_vec { parsed = true; window.pop(); let window_len: usize = window.iter() .map(|x| x.len_utf8()) .fold(0, |x, y| x + y); offset = o - window_len; break; } } if parsed { $crate::IResult::Done($i.advance(offset), $i.until(offset)) } else { $crate::IResult::Error } } }}; } /// Parse the given string from exactly the current position in the input. You /// almost always want `punct!` or `keyword!` instead of this. /// /// The `tag!` parser is equivalent to `punct!` but does not ignore leading /// whitespace. Both `punct!` and `keyword!` skip over leading whitespace. See /// an explanation of synom's whitespace handling strategy in the top-level /// crate documentation. /// /// - **Syntax:** `tag!("...")` /// - **Output:** `"..."` /// /// ```rust /// extern crate syn; /// #[macro_use] extern crate synom; /// /// use syn::StrLit; /// use syn::parse::string; /// use synom::IResult; /// /// // Parse a proposed syntax for an owned string literal: "abc"s /// named!(owned_string -> String, /// map!( /// terminated!(string, tag!("s")), /// |lit: StrLit| lit.value /// ) /// ); /// /// fn main() { /// let input = r#" "abc"s "#; /// let parsed = owned_string(input).expect("owned string literal"); /// println!("{:?}", parsed); /// /// let input = r#" "abc" s "#; /// let err = owned_string(input); /// assert_eq!(err, IResult::Error); /// } /// ``` #[macro_export] macro_rules! tag { ($i:expr, $tag:expr) => { if $i.starts_with($tag) { $crate::IResult::Done($i.advance($tag.len()), $i.until($tag.len())) } else { $crate::IResult::Error } }; } /// Pattern-match the result of a parser to select which other parser to run. /// /// - **Syntax:** `switch!(TARGET, PAT1 => THEN1 | PAT2 => THEN2 | ...)` /// - **Output:** `T`, the return type of `THEN1` and `THEN2` and ... /// /// ```rust /// extern crate syn; /// #[macro_use] extern crate synom; /// /// use syn::{Ident, Ty}; /// use syn::parse::{ident, ty}; /// /// #[derive(Debug)] /// enum UnitType { /// Struct { /// name: Ident, /// }, /// Enum { /// name: Ident, /// variant: Ident, /// }, /// } /// /// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`. /// named!(unit_type -> UnitType, do_parse!( /// which: alt!(keyword!("struct") | keyword!("enum")) >> /// id: ident >> /// item: switch!(value!(which), /// "struct" => map!( /// punct!(";"), /// move |_| UnitType::Struct { /// name: id, /// } /// ) /// | /// "enum" => map!( /// delimited!(punct!("{"), ident, punct!("}")), /// move |variant| UnitType::Enum { /// name: id, /// variant: variant, /// } /// ) /// ) >> /// (item) /// )); /// /// fn main() { /// let input = "struct S;"; /// let parsed = unit_type(input).expect("unit struct or enum"); /// println!("{:?}", parsed); /// /// let input = "enum E { V }"; /// let parsed = unit_type(input).expect("unit struct or enum"); /// println!("{:?}", parsed); /// } /// ``` #[macro_export] macro_rules! switch { ($i:expr, $submac:ident!( $($args:tt)* ), $($p:pat => $subrule:ident!( $($args2:tt)* ))|* ) => { match $submac!($i, $($args)*) { $crate::IResult::Error => $crate::IResult::Error, $crate::IResult::Done(i, o) => match o { $( $p => $subrule!(i, $($args2)*), )* _ => $crate::IResult::Error, } } }; } /// Produce the given value without parsing anything. Useful as an argument to /// `switch!`. /// /// - **Syntax:** `value!(VALUE)` /// - **Output:** `VALUE` /// /// ```rust /// extern crate syn; /// #[macro_use] extern crate synom; /// /// use syn::{Ident, Ty}; /// use syn::parse::{ident, ty}; /// /// #[derive(Debug)] /// enum UnitType { /// Struct { /// name: Ident, /// }, /// Enum { /// name: Ident, /// variant: Ident, /// }, /// } /// /// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`. /// named!(unit_type -> UnitType, do_parse!( /// which: alt!(keyword!("struct") | keyword!("enum")) >> /// id: ident >> /// item: switch!(value!(which), /// "struct" => map!( /// punct!(";"), /// move |_| UnitType::Struct { /// name: id, /// } /// ) /// | /// "enum" => map!( /// delimited!(punct!("{"), ident, punct!("}")), /// move |variant| UnitType::Enum { /// name: id, /// variant: variant, /// } /// ) /// ) >> /// (item) /// )); /// /// fn main() { /// let input = "struct S;"; /// let parsed = unit_type(input).expect("unit struct or enum"); /// println!("{:?}", parsed); /// /// let input = "enum E { V }"; /// let parsed = unit_type(input).expect("unit struct or enum"); /// println!("{:?}", parsed); /// } /// ``` #[macro_export] macro_rules! value { ($i:expr, $res:expr) => { $crate::IResult::Done($i, $res) }; } /// Value surrounded by a pair of delimiters. /// /// - **Syntax:** `delimited!(OPEN, THING, CLOSE)` /// - **Output:** `THING` /// /// ```rust /// extern crate cpp_syn as syn; /// #[macro_use] extern crate cpp_synom as synom; /// /// use syn::Expr; /// use syn::parse::expr; /// /// // An expression surrounded by [[ ... ]]. /// named!(double_bracket_expr -> Expr, /// delimited!(punct!("[["), expr, punct!("]]")) /// ); /// /// fn main() { /// let input = "[[ 1 + 1 ]]"; /// /// let parsed = double_bracket_expr(input).expect("double bracket expr"); /// /// println!("{:?}", parsed); /// } /// ``` #[macro_export] macro_rules! delimited { ($i:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)+) => { match tuple_parser!($i, (), $submac!($($args)*), $($rest)*) { $crate::IResult::Error => $crate::IResult::Error, $crate::IResult::Done(i1, (_, o, _)) => $crate::IResult::Done(i1, o) } }; ($i:expr, $f:expr, $($rest:tt)+) => { delimited!($i, call!($f), $($rest)*) }; } /// One or more values separated by some separator. Does not allow a trailing /// separator. /// /// - **Syntax:** `separated_nonempty_list!(SEPARATOR, THING)` /// - **Output:** `Vec` /// /// You may also be looking for: /// /// - `separated_list!` - one or more values /// - `terminated_list!` - zero or more, allows trailing separator /// - `many0!` - zero or more, no separator /// /// ```rust /// extern crate cpp_syn as syn; /// #[macro_use] extern crate cpp_synom as synom; /// /// use syn::Ty; /// use syn::parse::ty; /// /// // One or more Rust types separated by commas. /// named!(comma_separated_types -> Vec, /// separated_nonempty_list!(punct!(","), ty) /// ); /// /// fn main() { /// let input = "&str, Map, String"; /// /// let parsed = comma_separated_types(input).expect("comma-separated types"); /// /// assert_eq!(parsed.len(), 3); /// println!("{:?}", parsed); /// } /// ``` #[macro_export] macro_rules! separated_nonempty_list { ($i:expr, $sep:ident!( $($args:tt)* ), $submac:ident!( $($args2:tt)* )) => {{ let mut res = ::std::vec::Vec::new(); let mut input = $i; // get the first element match $submac!(input, $($args2)*) { $crate::IResult::Error => $crate::IResult::Error, $crate::IResult::Done(i, o) => { if i.len() == input.len() { $crate::IResult::Error } else { res.push(o); input = i; while let $crate::IResult::Done(i2, _) = $sep!(input, $($args)*) { if i2.len() == input.len() { break; } if let $crate::IResult::Done(i3, o3) = $submac!(i2, $($args2)*) { if i3.len() == i2.len() { break; } res.push(o3); input = i3; } else { break; } } $crate::IResult::Done(input, res) } } } }}; ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => { separated_nonempty_list!($i, $submac!($($args)*), call!($g)) }; ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => { separated_nonempty_list!($i, call!($f), $submac!($($args)*)) }; ($i:expr, $f:expr, $g:expr) => { separated_nonempty_list!($i, call!($f), call!($g)) }; } /// Run a series of parsers and produce all of the results in a tuple. /// /// - **Syntax:** `tuple!(A, B, C, ...)` /// - **Output:** `(A, B, C, ...)` /// /// ```rust /// extern crate syn; /// #[macro_use] extern crate synom; /// /// use syn::Ty; /// use syn::parse::ty; /// /// named!(two_types -> (Ty, Ty), tuple!(ty, ty)); /// /// fn main() { /// let input = "&str Map"; /// /// let parsed = two_types(input).expect("two types"); /// /// println!("{:?}", parsed); /// } /// ``` #[macro_export] macro_rules! tuple { ($i:expr, $($rest:tt)*) => { tuple_parser!($i, (), $($rest)*) }; } /// Internal parser, do not use directly. #[doc(hidden)] #[macro_export] macro_rules! tuple_parser { ($i:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => { tuple_parser!($i, ($($parsed),*), call!($e), $($rest)*) }; ($i:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => { match $submac!($i, $($args)*) { $crate::IResult::Error => $crate::IResult::Error, $crate::IResult::Done(i, o) => tuple_parser!(i, (o), $($rest)*), } }; ($i:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => { match $submac!($i, $($args)*) { $crate::IResult::Error => $crate::IResult::Error, $crate::IResult::Done(i, o) => tuple_parser!(i, ($($parsed)* , o), $($rest)*), } }; ($i:expr, ($($parsed:tt),*), $e:ident) => { tuple_parser!($i, ($($parsed),*), call!($e)) }; ($i:expr, (), $submac:ident!( $($args:tt)* )) => { $submac!($i, $($args)*) }; ($i:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => { match $submac!($i, $($args)*) { $crate::IResult::Error => $crate::IResult::Error, $crate::IResult::Done(i, o) => $crate::IResult::Done(i, ($($parsed),*, o)) } }; ($i:expr, ($($parsed:expr),*)) => { $crate::IResult::Done($i, ($($parsed),*)) }; } /// Run a series of parsers, returning the result of the first one which /// succeeds. /// /// Optionally allows for the result to be transformed. /// /// - **Syntax:** `alt!(THING1 | THING2 => { FUNC } | ...)` /// - **Output:** `T`, the return type of `THING1` and `FUNC(THING2)` and ... /// /// ```rust /// extern crate syn; /// #[macro_use] extern crate synom; /// /// use syn::Ident; /// use syn::parse::ident; /// /// named!(ident_or_bang -> Ident, /// alt!( /// ident /// | /// punct!("!") => { |_| "BANG".into() } /// ) /// ); /// /// fn main() { /// let input = "foo"; /// let parsed = ident_or_bang(input).expect("identifier or `!`"); /// assert_eq!(parsed, "foo"); /// /// let input = "!"; /// let parsed = ident_or_bang(input).expect("identifier or `!`"); /// assert_eq!(parsed, "BANG"); /// } /// ``` #[macro_export] macro_rules! alt { ($i:expr, $e:ident | $($rest:tt)*) => { alt!($i, call!($e) | $($rest)*) }; ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => { match $subrule!($i, $($args)*) { res @ $crate::IResult::Done(_, _) => res, _ => alt!($i, $($rest)*) } }; ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => { match $subrule!($i, $($args)*) { $crate::IResult::Done(i, o) => $crate::IResult::Done(i, $gen(o)), $crate::IResult::Error => alt!($i, $($rest)*) } }; ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => { alt!($i, call!($e) => { $gen } | $($rest)*) }; ($i:expr, $e:ident => { $gen:expr }) => { alt!($i, call!($e) => { $gen }) }; ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => { match $subrule!($i, $($args)*) { $crate::IResult::Done(i, o) => $crate::IResult::Done(i, $gen(o)), $crate::IResult::Error => $crate::IResult::Error, } }; ($i:expr, $e:ident) => { alt!($i, call!($e)) }; ($i:expr, $subrule:ident!( $($args:tt)*)) => { $subrule!($i, $($args)*) }; } /// Run a series of parsers, one after another, optionally assigning the results /// a name. Fail if any of the parsers fails. /// /// Produces the result of evaluating the final expression in parentheses with /// all of the previously named results bound. /// /// - **Syntax:** `do_parse!(name: THING1 >> THING2 >> (RESULT))` /// - **Output:** `RESULT` /// /// ```rust /// extern crate syn; /// #[macro_use] extern crate synom; /// /// use syn::{Ident, TokenTree}; /// use syn::parse::{ident, tt}; /// /// // Parse a macro invocation like `stringify!($args)`. /// named!(simple_mac -> (Ident, TokenTree), do_parse!( /// name: ident >> /// punct!("!") >> /// body: tt >> /// (name, body) /// )); /// /// fn main() { /// let input = "stringify!($args)"; /// let (name, body) = simple_mac(input).expect("macro invocation"); /// println!("{:?}", name); /// println!("{:?}", body); /// } /// ``` #[macro_export] macro_rules! do_parse { ($i:expr, ( $($rest:expr),* )) => { $crate::IResult::Done($i, ( $($rest),* )) }; ($i:expr, $e:ident >> $($rest:tt)*) => { do_parse!($i, call!($e) >> $($rest)*) }; ($i:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => { match $submac!($i, $($args)*) { $crate::IResult::Error => $crate::IResult::Error, $crate::IResult::Done(i, _) => do_parse!(i, $($rest)*), } }; ($i:expr, $field:ident : $e:ident >> $($rest:tt)*) => { do_parse!($i, $field: call!($e) >> $($rest)*) }; ($i:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => { match $submac!($i, $($args)*) { $crate::IResult::Error => $crate::IResult::Error, $crate::IResult::Done(i, o) => { let $field = o; do_parse!(i, $($rest)*) }, } }; ($i:expr, mut $field:ident : $e:ident >> $($rest:tt)*) => { do_parse!($i, mut $field: call!($e) >> $($rest)*) }; ($i:expr, mut $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => { match $submac!($i, $($args)*) { $crate::IResult::Error => $crate::IResult::Error, $crate::IResult::Done(i, o) => { let mut $field = o; do_parse!(i, $($rest)*) }, } }; } cpp_synom-0.12.0/src/space.rs01006440000765000002400000005535130501226120014250 0ustar0000000000000000use {IResult, ParseState}; use unicode_xid::UnicodeXID; pub fn whitespace(input: ParseState) -> IResult { if input.is_empty() { return IResult::Error; } let bytes = input.rest().as_bytes(); let mut i = 0; while i < bytes.len() { let s = input.advance(i); if bytes[i] == b'/' { if s.starts_with("//") && (!s.starts_with("///") || s.starts_with("////")) && !s.starts_with("//!") { if let Some(len) = s.rest().find('\n') { i += len + 1; continue; } break; } else if s.starts_with("/*") && (!s.starts_with("/**") || s.starts_with("/***")) && !s.starts_with("/*!") { match block_comment(s) { IResult::Done(_, com) => { i += com.len(); continue; } IResult::Error => { return IResult::Error; } } } } match bytes[i] { b' ' | 0x09...0x0d => { i += 1; continue; } b if b <= 0x7f => {} _ => { let ch = s.chars().next().unwrap(); if is_whitespace(ch) { i += ch.len_utf8(); continue; } } } return if i > 0 { IResult::Done(s, ()) } else { IResult::Error }; } IResult::Done(input.finish(), ()) } pub fn block_comment(input: ParseState) -> IResult { if !input.starts_with("/*") { return IResult::Error; } let mut depth = 0; let bytes = input.rest().as_bytes(); let mut i = 0; let upper = bytes.len() - 1; while i < upper { if bytes[i] == b'/' && bytes[i + 1] == b'*' { depth += 1; i += 1; // eat '*' } else if bytes[i] == b'*' && bytes[i + 1] == b'/' { depth -= 1; if depth == 0 { return IResult::Done(input.advance(i + 2), input.until(i + 2)); } i += 1; // eat '/' } i += 1; } IResult::Error } pub fn word_break(input: ParseState) -> IResult { match input.chars().next() { Some(ch) if UnicodeXID::is_xid_continue(ch) => IResult::Error, Some(_) | None => IResult::Done(input, ()), } } pub fn skip_whitespace(input: ParseState) -> ParseState { match whitespace(input) { IResult::Done(rest, _) => rest, IResult::Error => input, } } fn is_whitespace(ch: char) -> bool { // Rust treats left-to-right mark and right-to-left mark as whitespace ch.is_whitespace() || ch == '\u{200e}' || ch == '\u{200f}' }