pub mod convert; use std::fmt; use proc_macro2::TokenStream; use quote::{ToTokens, TokenStreamExt}; use syn::{ ext::IdentExt, parenthesized, parse::{Parse, ParseStream}, punctuated::Punctuated, token::{Let, Match, Paren}, LitStr, Token, }; pub type Epsilon = Token![_]; pub type Ident = syn::Ident; pub type Literal = LitStr; #[derive(Clone)] pub struct Fix { bang_token: Token![!], pub expr: Box, } impl ToTokens for Fix { fn to_tokens(&self, tokens: &mut TokenStream) { self.bang_token.to_tokens(tokens); self.expr.to_tokens(tokens); } } impl Parse for Fix { fn parse(input: ParseStream<'_>) -> syn::Result { let bang_token = input.parse()?; let expr = input.parse()?; Ok(Self { bang_token, expr }) } } impl fmt::Debug for Fix { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Fix").field("expr", &self.expr).finish() } } #[derive(Clone)] pub struct ParenExpression { paren_token: Paren, pub expr: Expression, } impl ToTokens for ParenExpression { fn to_tokens(&self, tokens: &mut TokenStream) { self.paren_token.surround(tokens, |tokens| self.expr.to_tokens(tokens)) } } impl Parse for ParenExpression { fn parse(input: ParseStream<'_>) -> syn::Result { let expr; let paren_token = parenthesized!(expr in input); let expr = expr.parse()?; Ok(Self { paren_token, expr }) } } impl fmt::Debug for ParenExpression { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ParenExpression") .field("expr", &self.expr) .finish() } } #[derive(Clone)] pub enum Term { Epsilon(Epsilon), Ident(Ident), Literal(Literal), Fix(Fix), Parens(ParenExpression), } impl ToTokens for Term { fn to_tokens(&self, tokens: &mut TokenStream) { match self { Self::Epsilon(e) => e.to_tokens(tokens), Self::Ident(i) => i.to_tokens(tokens), Self::Literal(l) => l.to_tokens(tokens), Self::Fix(f) => f.to_tokens(tokens), Self::Parens(p) => p.to_tokens(tokens), } } } impl Parse for Term { fn parse(input: ParseStream<'_>) -> syn::Result { let lookahead = input.lookahead1(); if lookahead.peek(Token![_]) { input.parse().map(Self::Epsilon) } else if lookahead.peek(LitStr) { input.parse().map(Self::Literal) } else if lookahead.peek(Token![!]) { input.parse().map(Self::Fix) } else if lookahead.peek(Paren) { input.parse().map(Self::Parens) } else if lookahead.peek(Ident::peek_any) { input.call(Ident::parse_any).map(Self::Ident) } else { Err(lookahead.error()) } } } impl fmt::Debug for Term { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Term::Epsilon(_) => write!(f, "Term::Epsilon"), Term::Ident(i) => write!(f, "Term::Ident({:?})", i), Term::Literal(l) => write!(f, "Term::Literal({:?})", l.value()), Term::Fix(x) => write!(f, "Term::Fix({:?})", x), Term::Parens(p) => write!(f, "Term::Parens({:?})", p), } } } #[derive(Clone, Debug)] pub struct Call(pub Vec); impl ToTokens for Call { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append_all(&self.0) } } impl Parse for Call { fn parse(input: ParseStream<'_>) -> syn::Result { let mut out = vec![input.parse()?]; loop { let lookahead = input.lookahead1(); if lookahead.peek(Token![_]) || lookahead.peek(LitStr) || lookahead.peek(Token![!]) || lookahead.peek(Paren) || lookahead.peek(Ident::peek_any) { out.push(input.parse()?); } else { break; } } Ok(Self(out)) } } #[derive(Clone)] pub struct Cat(pub Punctuated); impl ToTokens for Cat { fn to_tokens(&self, tokens: &mut TokenStream) { self.0.to_tokens(tokens) } } impl Parse for Cat { fn parse(input: ParseStream<'_>) -> syn::Result { input.call(Punctuated::parse_separated_nonempty).map(Self) } } impl fmt::Debug for Cat { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Cat")?; f.debug_list().entries(&self.0).finish() } } #[derive(Clone)] pub struct Label { colon_tok: Token![:], pub label: Ident, } impl ToTokens for Label { fn to_tokens(&self, tokens: &mut TokenStream) { self.colon_tok.to_tokens(tokens); self.label.to_tokens(tokens); } } impl Parse for Label { fn parse(input: ParseStream<'_>) -> syn::Result { let colon_tok = input.parse()?; let label = input.call(Ident::parse_any)?; Ok(Self { colon_tok, label }) } } impl fmt::Debug for Label { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Label").field("label", &self.label).finish() } } #[derive(Clone, Debug)] pub struct Labelled { pub cat: Cat, pub label: Option