Parse based on proc-macro2
diff --git a/synom/src/helper.rs b/synom/src/helper.rs
index a488359..800874a 100644
--- a/synom/src/helper.rs
+++ b/synom/src/helper.rs
@@ -1,5 +1,4 @@
-use IResult;
-use space::{skip_whitespace, word_break};
+use {IResult, TokenTree, TokenKind, OpKind, Delimiter, InputBuf};
/// Parse a piece of punctuation like "+" or "+=".
///
@@ -33,13 +32,33 @@
// Not public API.
#[doc(hidden)]
-pub fn punct<'a>(input: &'a str, token: &'static str) -> IResult<&'a str, &'a str> {
- let input = skip_whitespace(input);
- if input.starts_with(token) {
- IResult::Done(&input[token.len()..], token)
- } else {
- IResult::Error
+pub fn punct<'a>(input: &'a [TokenTree], token: &'static str) -> IResult<&'a [TokenTree], &'a str> {
+ // Extract the chars from token, so we know how many tokens to expect, check
+ // if we are running past EOF, then confirm that the tokens exist as
+ // requested.
+ let expected = token.chars().collect::<Vec<_>>();
+ if input.len() < expected.len() {
+ return IResult::Error;
}
+ for i in 0..expected.len() {
+ if let TokenKind::Op(c, ok) = input[i].kind {
+ if c != expected[i] {
+ return IResult::Error;
+ }
+
+ // The last token in the sequence does not have to be marked as
+ // OpKind::Joint. Unfortunately OpKind doesn't implement
+ // Eq/PartialEq right now.
+ match ok {
+ OpKind::Alone if i != expected.len() - 1 => return IResult::Error,
+ _ => {}
+ }
+ } else {
+ return IResult::Error;
+ }
+ }
+
+ IResult::Done(&input[expected.len()..], token)
}
/// Parse a keyword like "fn" or "struct".
@@ -83,15 +102,11 @@
// Not public API.
#[doc(hidden)]
-pub fn keyword<'a>(input: &'a str, token: &'static str) -> IResult<&'a str, &'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,
+pub fn keyword<'a>(input: &'a [TokenTree], token: &'static str) -> IResult<&'a [TokenTree], &'static str> {
+ match input.first() {
+ Some(&TokenTree{ kind: TokenKind::Word(ref symbol), .. }) if &**symbol == token =>
+ IResult::Done(&input[1..], token),
+ _ => IResult::Error,
}
}
@@ -497,11 +512,11 @@
// Not public API.
#[doc(hidden)]
-pub fn separated_list<'a, T>(mut input: &'a str,
+pub fn separated_list<'a, T>(mut input: &'a [TokenTree],
sep: &'static str,
- f: fn(&'a str) -> IResult<&'a str, T>,
+ f: fn(&'a [TokenTree]) -> IResult<&'a [TokenTree], T>,
terminated: bool)
- -> IResult<&'a str, Vec<T>> {
+ -> IResult<&'a [TokenTree], Vec<T>> {
let mut res = Vec::new();
// get the first element
@@ -541,3 +556,45 @@
}
}
}
+
+#[macro_export]
+macro_rules! delim {
+ ($i:expr, $delim:ident, $fmac:ident!( $($fargs:tt)* )) => {
+ match $crate::helper::delim_impl($i, $crate::Delimiter::$delim) {
+ Some((i, ib)) => {
+ match $fmac!(&*ib, $($fargs)*) {
+ $crate::IResult::Done(rest, val) => {
+ if rest.is_empty() {
+ $crate::IResult::Done(i, val)
+ } else {
+ $crate::IResult::Error
+ }
+ }
+ _ => $crate::IResult::Error,
+ }
+ }
+ _ => $crate::IResult::Error,
+ }
+ };
+ ($i:expr, $delim:ident, $f:expr) => {
+ delim!($i, $delim, call!($f))
+ };
+}
+
+// Not a public API
+#[doc(hidden)]
+pub fn delim_impl(input: &[TokenTree],
+ expected_delim: Delimiter)
+ -> Option<(&[TokenTree], InputBuf)> {
+ // NOTE: The `as u32` hack is being used as `Delimiter` doesn't implement
+ // `PartialEq` or `Eq` despite being a simple c-style enum.
+ match input.first() {
+ Some(&TokenTree {
+ kind: TokenKind::Sequence(delim, ref stream),
+ ..
+ }) if delim as u32 == expected_delim as u32 => {
+ Some((&input[1..], InputBuf::new(stream.clone())))
+ }
+ _ => None
+ }
+}