use syn::{
parenthesized, parse::Parse, parse::ParseStream, token::Paren, token, Block, Ident, Type,
LitStr, Token,
};
#[derive(Debug)]
pub enum ParseTree {
DefinitionList(Vec<ParseTree>),
ParserDefinition(Ident, Option<Type>, Box<ParseTree>),
Capture(Box<ParseTree>, Option<Ident>),
NonTerminal(Ident),
Call(Ident),
Sequence(Vec<ParseTree>, Option<Block>),
Empty,
Terminal(String),
Choice(Vec<ParseTree>),
Many0(Box<ParseTree>),
Many1(Box<ParseTree>),
Optional(Box<ParseTree>),
Peek(Box<ParseTree>),
Not(Box<ParseTree>),
}
enum Prefix {
Peek,
Not,
}
enum Postfix {
Optional,
Many0,
Many1,
}
fn parse_prefix(input: ParseStream) -> Option<Prefix> {
let lookahead = input.lookahead1();
if lookahead.peek(Token![&]) {
input.parse::<Token![&]>().unwrap(); Some(Prefix::Peek)
} else if lookahead.peek(Token![!]) {
input.parse::<Token![!]>().unwrap(); Some(Prefix::Not)
} else {
None
}
}
fn parse_postfix(input: ParseStream) -> Option<Postfix> {
let lookahead = input.lookahead1();
if lookahead.peek(Token![?]) {
input.parse::<Token![?]>().unwrap(); Some(Postfix::Optional)
} else if lookahead.peek(Token![*]) {
input.parse::<Token![*]>().unwrap(); Some(Postfix::Many0)
} else if lookahead.peek(Token![+]) {
input.parse::<Token![+]>().unwrap(); Some(Postfix::Many1)
} else {
None
}
}
fn parse_element(input: ParseStream) -> syn::Result<ParseTree> {
let prefix = parse_prefix(input);
let lookahead = input.lookahead1();
let mut parsed = if lookahead.peek(Ident) {
if parse_definition(&input.fork()).is_ok() {
Err(input.error("Reached start of new definition."))
} else {
Ok(ParseTree::NonTerminal(input.parse::<Ident>()?))
}
} else if lookahead.peek(Token![::]) {
input.parse::<Token![::]>()?;
Ok(ParseTree::Call(input.parse::<Ident>()?))
} else if lookahead.peek(LitStr) {
Ok(ParseTree::Terminal(input.parse::<LitStr>()?.value()))
} else if lookahead.peek(Paren) {
let content;
parenthesized!(content in input);
Ok(parse_expression(&content)?)
} else if lookahead.peek(Token![<]) {
input.parse::<token::Lt>()?;
let ident = if input.peek(Ident) && input.peek2(Token![:]) {
let i = Some(input.parse::<Ident>()?);
input.parse::<Token![:]>()?; i
} else {
None
};
let term = parse_element(&input)?;
input.parse::<token::Gt>()?;
Ok(ParseTree::Capture(Box::new(term), ident))
} else {
Err(lookahead.error())
};
let postfix = parse_postfix(input);
parsed = parsed.and_then(|p| {
Ok(match postfix {
Some(Postfix::Optional) => ParseTree::Optional(Box::new(p)),
Some(Postfix::Many0) => ParseTree::Many0(Box::new(p)),
Some(Postfix::Many1) => ParseTree::Many1(Box::new(p)),
None => p,
})
});
parsed.and_then(|p| {
Ok(match prefix {
Some(Prefix::Peek) => ParseTree::Peek(Box::new(p)),
Some(Prefix::Not) => ParseTree::Not(Box::new(p)),
None => p,
})
})
}
fn parse_sequence(input: ParseStream) -> syn::Result<ParseTree> {
let mut expressions: Vec<ParseTree> = Vec::with_capacity(4);
while !input.is_empty() {
match parse_element(input) {
Ok(e) => expressions.push(e),
Err(_) => break,
}
}
if expressions.len() == 0 {
return Err(input.error("Need at least one element in a sequence"))
}
let block = if input.peek(Token![=>]) {
input.parse::<Token![=>]>()?; Some(input.parse::<Block>()?)
} else {
None
};
Ok(ParseTree::Sequence(expressions, block))
}
fn parse_expression(input: ParseStream) -> syn::Result<ParseTree> {
let mut expressions: Vec<ParseTree> = Vec::with_capacity(4);
expressions.push(parse_sequence(input)?);
while !input.is_empty() && input.peek(Token![|]) {
input.parse::<Token![|]>()?; expressions.push(parse_sequence(input)?);
}
match expressions.len() {
0 => Ok(ParseTree::Empty),
1 => Ok(expressions.remove(0)),
_ => Ok(ParseTree::Choice(expressions)),
}
}
fn parse_definition(input: ParseStream) -> syn::Result<ParseTree> {
let name = input.parse::<Ident>()?;
let return_type = if input.peek(Token![:]) {
input.parse::<Token![:]>()?; Some(input.parse::<Type>()?)
} else {
None
};
input.parse::<Token![=]>()?;
let expression = parse_expression(input)?;
Ok(ParseTree::ParserDefinition(name, return_type, Box::new(expression)))
}
impl Parse for ParseTree {
fn parse(input: ParseStream) -> syn::Result<Self> {
let mut definitions: Vec<ParseTree> = Vec::with_capacity(4);
definitions.push(parse_definition(input)?);
while !input.is_empty() {
definitions.push(parse_definition(input)?);
}
Ok(ParseTree::DefinitionList(definitions))
}
}