diff options
| author | Greg Brown <gmb60@cam.ac.uk> | 2021-01-06 16:36:46 +0000 | 
|---|---|---|
| committer | Greg Brown <gmb60@cam.ac.uk> | 2021-01-06 16:36:46 +0000 | 
| commit | eb280a903f8f20d0b0c0ef5acae955a20929d100 (patch) | |
| tree | 5e6f38fb41c8c630d3b1e3a1990249f8a98047b8 | |
| parent | dc10a278cca74d737e4af0fe034a1caa8abb291d (diff) | |
Create Chewed, the consumer crate.
| -rw-r--r-- | Cargo.toml | 6 | ||||
| -rw-r--r-- | chewed/Cargo.toml | 9 | ||||
| -rw-r--r-- | chewed/src/error.rs | 58 | ||||
| -rw-r--r-- | chewed/src/lib.rs | 5 | ||||
| -rw-r--r-- | chewed/src/parse.rs | 82 | ||||
| -rw-r--r-- | examples/autochomp/main.rs | 3 | ||||
| -rw-r--r-- | src/lower/rust.rs | 92 | 
7 files changed, 183 insertions, 72 deletions
| @@ -4,6 +4,9 @@ version = "0.1.0"  authors = ["Greg Brown <gmb60@cam.ac.uk>"]  edition = "2018" +[workspace] +members = ["chewed"] +  [dependencies]  quote = "1.0.7" @@ -14,3 +17,6 @@ features = ["span-locations"]  [dependencies.syn]  version = "1.0.48"  features = ["extra-traits"] + +[dev-dependencies] +chewed = {path = "chewed"} diff --git a/chewed/Cargo.toml b/chewed/Cargo.toml new file mode 100644 index 0000000..87053bc --- /dev/null +++ b/chewed/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "chewed" +version = "0.1.0" +authors = ["Greg Brown <gmb60@cam.ac.uk>"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/chewed/src/error.rs b/chewed/src/error.rs new file mode 100644 index 0000000..cb2cc4b --- /dev/null +++ b/chewed/src/error.rs @@ -0,0 +1,58 @@ +use std::{error::Error, fmt}; + +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub enum TakeError { +    BadBranch(char, &'static [char]), +    BadString(String, &'static str), +    EndOfStream, +} + +impl fmt::Display for TakeError { +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +        match self { +            Self::BadBranch(got, expected) => { +                write!(f, "Unexpected character {:?}.", got)?; + +                if expected.is_empty() { +                    write!(f, "Expected end of input.") +                } else if expected.len() == 1 { +                    write!(f, "Expected character {:?}.", expected[0]) +                } else { +                    let mut iter = expected.iter(); +                    write!(f, "Expected one of {:?}", iter.next().unwrap())?; + +                    for c in iter { +                        write!(f, ", {:?}", c)?; +                    } + +                    Ok(()) +                } +            } +            Self::BadString(got, expected) => write!(f, "Unexpected string {:?}. Expected {:?}", got, expected), +            Self::EndOfStream => write!(f, "Unexpected end of input"), +        } +    } +} + +impl Error for TakeError {} + +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub enum ParseError { +    TakeError(TakeError), +    InputContinues, +} + +impl fmt::Display for ParseError { +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +        match self { +            Self::TakeError(e) => e.fmt(f), +            Self::InputContinues => write!(f, "Expected end of input"), +        } +    } +} + +impl From<TakeError> for ParseError { +    fn from(e: TakeError) -> Self { +        Self::TakeError(e) +    } +} diff --git a/chewed/src/lib.rs b/chewed/src/lib.rs new file mode 100644 index 0000000..341af9d --- /dev/null +++ b/chewed/src/lib.rs @@ -0,0 +1,5 @@ +mod error; +mod parse; + +pub use error::*; +pub use parse::*; diff --git a/chewed/src/parse.rs b/chewed/src/parse.rs new file mode 100644 index 0000000..0687ea5 --- /dev/null +++ b/chewed/src/parse.rs @@ -0,0 +1,82 @@ +use super::error::{ParseError, TakeError}; + +pub trait Parser: Iterator<Item = char> { +    fn peek(&mut self) -> Option<char>; + +    fn take<P: Parse>(&mut self) -> Result<P, TakeError> { +        P::take(self) +    } + +    fn parse<P: Parse>(self) -> Result<P, ParseError> +    where +        Self: Sized, +    { +        P::parse(self) +    } + +    fn take_str(&mut self, s: &'static str) -> Result<(), TakeError> { +        let mut count = 0; + +        for exp in s.chars() { +            if let Some(got) = self.peek() { +                if got == exp { +                    self.next(); +                    count += 1 +                } else { +                    let mut out = String::from(&s[..count]); +                    out.push(got); + +                    return Err(TakeError::BadString(out, s)); +                } +            } else { +                return Err(TakeError::EndOfStream); +            } +        } + +        Ok(()) +    } +} + +pub trait Parse: Sized { +    fn take<P: Parser + ?Sized>(input: &mut P) -> Result<Self, TakeError>; + +    fn parse<P: Parser>(mut input: P) -> Result<Self, ParseError> { +        let res = Self::take(&mut input)?; + +        if input.peek().is_some() { +            Err(ParseError::InputContinues) +        } else { +            Ok(res) +        } +    } +} + +impl Parse for () { +    fn take<P: Parser + ?Sized>(_: &mut P) -> Result<Self, TakeError> { +        Ok(()) +    } +} + +impl<A: Parse, B: Parse> Parse for (A, B) { +    fn take<P: Parser + ?Sized>(input: &mut P) -> Result<Self, TakeError> { +        let a = input.take()?; +        let b = input.take()?; +        Ok((a, b)) +    } + +    fn parse<P: Parser>(mut input: P) -> Result<Self, ParseError> { +        let a = A::take(&mut input)?; +        let b = B::parse(input)?; +        Ok((a, b)) +    } +} + +impl<T: Parse + Sized> Parse for Box<T> { +    fn take<P: Parser + ?Sized>(input: &mut P) -> Result<Self, TakeError> { +        Ok(Box::new(input.take()?)) +    } + +    fn parse<P: Parser>(input: P) -> Result<Self, ParseError> { +        Ok(Box::new(input.parse()?)) +    } +} diff --git a/examples/autochomp/main.rs b/examples/autochomp/main.rs new file mode 100644 index 0000000..afa489f --- /dev/null +++ b/examples/autochomp/main.rs @@ -0,0 +1,3 @@ +pub fn main() { +    todo!("Create AutoChomp") +} diff --git a/src/lower/rust.rs b/src/lower/rust.rs index e47fa8a..c236bdd 100644 --- a/src/lower/rust.rs +++ b/src/lower/rust.rs @@ -46,13 +46,7 @@ impl Backend for RustBackend {              None => {                  let id = self.data.len();                  let ty = quote! { () }; -                let tokens = quote! { -                    impl Parse for () { -                        fn parse<P: Parser>(_input: &mut P) -> Result<Self> { -                            Ok(()) -                        } -                    } -                }; +                let tokens = TokenStream::new();                  self.data.push((ty, tokens, BTreeSet::new()));                  id              } @@ -75,7 +69,7 @@ impl Backend for RustBackend {                  pub struct #name;                  impl Parse for #name { -                    fn parse<P: Parser>(input: &mut P) -> Result<Self> { +                    fn take<P: Parser + ?Sized>(input: &mut P) -> Result<Self, TakeError> {                          input.take_str(#lit).map(|()| #name)                      }                  } @@ -145,10 +139,10 @@ impl Backend for RustBackend {                  quote! {                      impl Parse for #name { -                        fn parse<P: Parser>(input: &mut P) -> Result<Self> { +                        fn take<P: Parser + ?Sized>(input: &mut P) -> Result<Self, TakeError> {                              match input.peek() { -                                #(Some(#iter))|* => input.parse().map(Self::Right), -                                _ => input.parse().map(Self::Left), +                                #(Some(#iter))|* => input.take().map(Self::Right), +                                _ => input.take().map(Self::Left),                              }                          }                      } @@ -158,10 +152,10 @@ impl Backend for RustBackend {                  quote! {                      impl Parse for #name { -                        fn parse<P: Parser>(input: &mut P) -> Result<Self> { +                        fn take<P: Parser + ?Sized>(input: &mut P) -> Result<Self, TakeError> {                              match input.peek() { -                                #(Some(#iter))|* => input.parse().map(Self::Left), -                                _ => input.parse().map(Self::Right), +                                #(Some(#iter))|* => input.take().map(Self::Left), +                                _ => input.take().map(Self::Right),                              }                          }                      } @@ -172,11 +166,11 @@ impl Backend for RustBackend {                  quote! {                      impl Parse for #name { -                        fn parse<P: Parser>(input: &mut P) -> Result<Self> { -                            match input.peek().ok_or(Error::EndOfStream)? { -                                #(#iter_left)|* => input.parse().map(Self::Left), -                                #(#iter_right)|* => input.parse().map(Self::Right), -                                c => input.error(Error::BadBranch(c, &[#(#iter_first),*])) +                        fn take<P: Parser + ?Sized>(input: &mut P) -> Result<Self, TakeError> { +                            match input.peek().ok_or(TakeError::EndOfStream)? { +                                #(#iter_left)|* => input.take().map(Self::Left), +                                #(#iter_right)|* => input.take().map(Self::Right), +                                c => input.error(TakeError::BadBranch(c, &[#(#iter_first),*]))                              }                          }                      } @@ -213,7 +207,7 @@ impl Backend for RustBackend {                  pub struct #name(#inner_ty);                  impl Parse for #name { -                    fn parse<P: Parser>(input: &mut P) -> Result<Self> { +                    fn take<P: Parser + ?Sized>(input: &mut P) -> Result<Self, TakeError> {                          input.parse().map(Self)                      }                  } @@ -239,10 +233,13 @@ impl Backend for RustBackend {      }      fn emit_code(self, id: Self::Id) -> Self::Code { -        let root = self.data[id].clone(); -        let mut tokens = root.1; +        let mut tokens = quote! { +            use ::chewed::*; +        }; + +        let (root_ty, root_impl, mut todo) = self.data[id].clone(); +        tokens.extend(root_impl);          let mut completed = [id].iter().cloned().collect::<BTreeSet<_>>(); -        let mut todo = root.2;          while !todo.is_empty() {              let mut next = BTreeSet::new(); @@ -257,59 +254,10 @@ impl Backend for RustBackend {              todo = next;          } -        let root_ty = root.0;          tokens.extend(quote! {              pub type Ast = #root_ty; - -            pub enum Error { -                BadBranch(char, &'static [char]), -                EndOfStream, -            } - -            pub type Result<T> = std::result::Result<T, Error>; - -            pub trait Parser: Iterator<Item = char> { -                fn peek(&mut self) -> Option<char>; - -                fn parse<T: Parse>(&mut self) -> Result<T> where Self: Sized { -                    T::parse(self) -                } - -                fn take_str(&mut self, s: &str) -> Result<()>; - -                fn error<T>(&mut self, e: Error) -> Result<T>; -            } - -            pub trait Parse: Sized { -                fn parse<P: Parser>(input: &mut P) -> Result<Self>; -            } -          }); -        // Good enough guess of whether we need concatenation rules -        if !self.cat_map.is_empty() { -            tokens.extend(quote! { -                impl<A: Parse, B: Parse> Parse for (A, B) { -                    fn parse<P: Parser>(input: &mut P) -> Result<Self> { -                        let a = input.parse()?; -                        let b = input.parse()?; -                        Ok((a, b)) -                    } -                } -            }); -        } - -        // Good enough guess of whether we need variable rules -        if !self.fix_map.is_empty() { -            tokens.extend(quote! { -                impl<T: Parse + Sized> Parse for Box<T> { -                    fn parse<P: Parser>(input: &mut P) -> Result<Self> { -                        input.parse().map(Box::new) -                    } -                } -            }); -        } -          tokens      }  } | 
