diff options
| author | Greg Brown <gmb60@cam.ac.uk> | 2021-01-09 14:31:02 +0000 | 
|---|---|---|
| committer | Greg Brown <gmb60@cam.ac.uk> | 2021-01-09 14:31:02 +0000 | 
| commit | 0d01692c97ea8ca6fc4b229e5b9678cb252bceda (patch) | |
| tree | 6c5ed07740b814f50dddbc6afaefc21c11dc3440 /src | |
| parent | 487ce4fe0fa081f58d790d7d6417bf7d2659197c (diff) | |
Introduce chomp as a procedural macro.
Add a bunch of tests.
Fix chomp and chewed so autochomp compiles.
Diffstat (limited to 'src')
| -rw-r--r-- | src/chomp/check/inline.rs | 119 | ||||
| -rw-r--r-- | src/chomp/error.rs | 17 | ||||
| -rw-r--r-- | src/lower/rust.rs | 5 | 
3 files changed, 136 insertions, 5 deletions
| diff --git a/src/chomp/check/inline.rs b/src/chomp/check/inline.rs index 43a2eb8..da501f1 100644 --- a/src/chomp/check/inline.rs +++ b/src/chomp/check/inline.rs @@ -158,7 +158,7 @@ mod tests {                  None,              )              .into(), -            None +            None,          );          let inlined = expr.fold(&mut InlineCalls::new(function));          assert_eq!( @@ -208,7 +208,7 @@ mod tests {                  None,              )              .into(), -            None +            None,          );          let inlined = expr.fold(&mut InlineCalls::new(function));          assert_eq!( @@ -231,4 +231,119 @@ mod tests {              .into())          )      } + +    #[test] +    fn test_inline_double_subst() { +        let expr = Call::new( +            Name::Spanless("opt".to_string()), +            vec![Call::new( +                Name::Spanless("opt".to_string()), +                vec![Literal::Spanless("x".to_string()).into()], +                None, +            ) +            .into()], +            None, +        ); +        let inlined = expr.fold(&mut InlineCalls::new(opt())); +        assert_eq!( +            inlined, +            Ok(Alt::new( +                Epsilon::default().into(), +                None, +                Alt::new( +                    Epsilon::default().into(), +                    None, +                    Literal::Spanless("x".to_string()).into() +                ) +                .into() +            ) +            .into()) +        ) +    } + +    #[test] +    fn test_inline_call_args() { +        let expr = Fix::new( +            Name::Spanless("rec".to_string()), +            Cat::new( +                Literal::Spanless("a".to_string()).into(), +                None, +                Call::new( +                    Name::Spanless("opt".to_string()), +                    vec![Cat::new( +                        Cat::new( +                            Literal::Spanless("a".to_string()).into(), +                            None, +                            Fix::new( +                                Name::Spanless("star".to_string()), +                                Call::new( +                                    Name::Spanless("opt".to_string()), +                                    vec![Cat::new( +                                        Literal::Spanless(" ".to_string()).into(), +                                        None, +                                        Variable::new(Name::Spanless("star".to_string()), 0).into(), +                                    ) +                                    .into()], +                                    None, +                                ) +                                .into(), +                                None, +                            ) +                            .into(), +                        ) +                        .into(), +                        None, +                        Variable::new(Name::Spanless("rec".to_string()), 0).into(), +                    ) +                    .into()], +                    None, +                ) +                .into(), +            ) +            .into(), +            None, +        ); +        let inlined = expr.fold(&mut InlineCalls::new(opt())); +        assert_eq!(inlined, +        Ok(Fix::new( +            Name::Spanless("rec".to_string()), +            Cat::new( +                Literal::Spanless("a".to_string()).into(), +                None, +                Alt::new( +                    Epsilon::default().into(), +                    None, +                    Cat::new( +                        Cat::new( +                            Literal::Spanless("a".to_string()).into(), +                            None, +                            Fix::new( +                                Name::Spanless("star".to_string()), +                                Alt::new( +                                    Epsilon::default().into(), +                                    None, +                                    Cat::new( +                                        Literal::Spanless(" ".to_string()).into(), +                                        None, +                                        Variable::new(Name::Spanless("star".to_string()), 0).into(), +                                    ) +                                        .into() +                                ) +                                .into(), +                                None, +                            ) +                            .into(), +                        ) +                        .into(), +                        None, +                        Variable::new(Name::Spanless("rec".to_string()), 0).into(), +                    ) +                    .into(), +                ) +                .into(), +            ) +            .into(), +            None, +        ).into())) +    }  } diff --git a/src/chomp/error.rs b/src/chomp/error.rs index ffcbdd0..e7e4660 100644 --- a/src/chomp/error.rs +++ b/src/chomp/error.rs @@ -358,6 +358,19 @@ pub enum SubstituteError {      WrongArgCount { call: Call, expected: usize },  } +impl From<SubstituteError> for syn::Error { +    fn from(e: SubstituteError) -> Self { +        match e { +            SubstituteError::FreeParameter(param) => { +                Self::new(param.name().span().unwrap_or_else(Span::call_site), format!("undeclared variable `{}'", param.name())) +            } +            SubstituteError::WrongArgCount { call, expected } => { +                Self::new(call.span().unwrap_or_else(Span::call_site), format!("wrong number of arguments. Expected {}, got {}", expected, call.args().len())) +            } +        } +    } +} +  impl Display for SubstituteError {      fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {          match self { @@ -378,8 +391,8 @@ impl Display for SubstituteError {                      "{}:{}: wrong number of arguments. Expected {}, got {}",                      start.line,                      start.column, -                    call.args().len(), -                    expected +                    expected, +                    call.args().len()                  )              }          } diff --git a/src/lower/rust.rs b/src/lower/rust.rs index 74deb73..7931306 100644 --- a/src/lower/rust.rs +++ b/src/lower/rust.rs @@ -75,7 +75,7 @@ impl Backend for RustBackend {                  impl Parse for #name {                      fn take<P: Parser + ?Sized>(input: &mut P) -> Result<Self, TakeError> { -                        input.take_str(#lit).map(|()| #name) +                        input.consume_str(#lit).map(|()| #name)                      }                  }              }; @@ -206,8 +206,11 @@ impl Backend for RustBackend {                  TokenStream::new(),                  BTreeSet::new(),              )); +              self.context.push(id);              let inner = inner.gen(self); +            self.context.pop(); +              let inner_ty = self.data[inner].0.clone();              let tokens = quote! {                  #[derive(Clone, Debug, Eq, Hash, PartialEq)] | 
