use syn::{parse::{Parse, ParseStream, Result}, Token, spanned::Spanned};
use crate::{syntax::*, token::*};
use crate::syntax::{BIP39, DIGITS};
impl Parse for RepeatKind {
fn parse(content: ParseStream) -> Result<Self> {
if content.peek(syn::LitInt) {
let lit = content.parse::<syn::LitInt>()?;
let left = lit.base10_parse::<usize>()?;
if content.peek(Token![,]) {
content.parse::<Token![,]>()?;
if content.peek(syn::LitInt) {
let right_lit = content.parse::<syn::LitInt>()?;
let right = right_lit.base10_parse::<usize>()?;
return Ok(RepeatKind::Between(Some(left), Some(right)));
} else {
return Ok(RepeatKind::Between(Some(left), None));
}
} else {
return Ok(RepeatKind::Between(Some(left), Some(left)));
}
}
if content.peek(Token![,]) {
content.parse::<Token![,]>()?;
if content.peek(syn::LitInt) {
let right_lit = content.parse::<syn::LitInt>()?;
let right = right_lit.base10_parse::<usize>()?;
Ok(RepeatKind::Between(None, Some(right)))
} else {
Err(syn::Error::new(content.span(), "Expected integer after comma as repeated group"))
}
}
else if content.peek(MUL0) {
content.parse::<MUL0>()?;
Ok(RepeatKind::Between(None, None))
} else if content.peek(MUL1) {
content.parse::<MUL1>()?;
Ok(RepeatKind::Between(Some(1), None))
} else if content.peek(QST) {
content.parse::<QST>()?;
Ok(RepeatKind::Between(Some(0), Some(1)))
}
else {
Err(syn::Error::new(content.span(), "Expected integer or comma as repeated group"))
}
}
}
impl Parse for CustomToken {
fn parse(content: ParseStream) -> Result<Self> {
if let Ok(_) = content.parse::<BIP39>() {
Ok(CustomToken::BIP39)
} else if let Ok(_) = content.parse::<DIGITS>() {
Ok(CustomToken::DIGITS)
} else {
Err(syn::Error::new(content.span(), "Expected custom token"))
}
}
}
impl Parse for CurlyWrapped {
fn parse(content: ParseStream) -> Result<Self> {
let data;
let brace_token = syn::braced!(data in content);
let span = brace_token.span.span();
if data.peek(Token![,]) || data.peek(syn::LitInt) {
let repeat = data.parse::<RepeatKind>()?;
Ok(CurlyWrapped::Repeat(span, repeat))
} else {
let token = data.parse::<CustomToken>()?;
Ok(CurlyWrapped::Custom(span, token))
}
}
}
impl Parse for StructureToken {
fn parse(input: ParseStream) -> Result<Self> {
if input.peek(syn::Ident) {
let ident = input.parse::<syn::Ident>()?;
let span = ident.span();
Ok(StructureToken::Name(span, ident.to_string()))
} else if input.peek(syn::token::Paren) {
let content;
let _paren_token = syn::parenthesized!(content in input);
let group = content.parse::<FullStructure>()?;
Ok(StructureToken::Group(group))
} else if input.peek(syn::token::Brace) {
let curly = input.parse::<CurlyWrapped>()?;
let span = match &curly {
CurlyWrapped::Repeat(span, _) => *span,
CurlyWrapped::Custom(span, _) => *span,
};
Ok(StructureToken::Curly(span, curly))
} else if input.peek(Token![,]) || input.peek(MUL0) || input.peek(MUL1) || input.peek(QST) {
let repeat = input.parse::<RepeatKind>()?;
let span = input.span();
Ok(StructureToken::Repeat(span, repeat))
} else {
Err(syn::Error::new(input.span(), "Expected name, group, curly or repeat"))
}
}
}
impl Parse for FullStructure {
fn parse(input: ParseStream) -> Result<Self> {
let mut tokens = Vec::new();
while !input.is_empty() {
tokens.push(input.parse::<StructureToken>()?);
}
Ok(FullStructure { tokens })
}
}
pub fn parse(input: &str) -> Result<FullStructure> {
syn::parse_str::<FullStructure>(input)
}
pub fn translate(structure: &FullStructure) -> Result<IntermediateFullStructure> {
let mut out: Vec<IntermediateToken> = vec![];
for token in &structure.tokens {
match token {
StructureToken::Name(_, name) => out.push(IntermediateToken::Literal(name.clone())),
StructureToken::Group(group) => {
let group_tokens = translate(group)?;
out.push(IntermediateToken::Group(group_tokens));
},
StructureToken::Curly(_, curly) => match curly {
CurlyWrapped::Repeat(_, repeat) => {
if let Some(last) = out.pop() {
out.push(IntermediateToken::Repeat(Box::new(last), (*repeat).clone()));
} else {
}
},
CurlyWrapped::Custom(_, token) => out.push(IntermediateToken::Custom((*token).clone())),
},
StructureToken::Repeat(_, repeat) => {
if let Some(last) = out.pop() {
out.push(IntermediateToken::Repeat(Box::new(last), (*repeat).clone()));
} else {
}
},
}
}
Ok(IntermediateFullStructure { tokens: out })
}