use std::borrow::Cow;
#[allow(clippy::wildcard_imports)]
use unsynn::*;
unsynn! {
pub operator IndexOf = "$?";
pub operator LengthOf = "$#";
pub operator Directive = "$:";
pub operator ConcatIdent = "$+";
pub operator EscapedDollar = "$$";
pub enum XToken {
Scope(Dollar, BraceGroup),
Definition(Dollar, ParenthesisGroupContaining<DefinitionContent>),
DefinitionError(Dollar, Either<ParenthesisGroup, BracketGroup>),
IndexedSubstitution(Dollar, usize),
NamedSubstitution(Dollar, CachedIdent),
IndexOfIndexed(IndexOf, usize),
IndexOfNamed(IndexOf, CachedIdent),
LengthOfIndexed(LengthOf, usize),
LengthOfNamed(LengthOf, CachedIdent),
EscapedDollar(EscapedDollar),
Directive(Directive, CachedIdent),
ConcatIdent(ConcatIdent, CachedIdent, Dollar, Either<usize, CachedIdent>),
BreakSemicolon(Semicolon),
BreakPunct(Punct, Expect<Dollar>),
Group(Group),
TokenTree(TokenTree),
EndOfStream(EndOfStream),
TokenStream(TokenStream),
XGroup(GroupContaining<Vec<XToken>>),
}
pub(crate) struct Named {
pub inplace: Option<Dollar>,
pub name: CachedIdent,
pub matches: Option<Cons<At, TokenTree>>,
_colon: Colon,
}
}
#[derive(Debug)]
pub(crate) struct DefinitionContent {
pub names: Vec<Named>,
pub definitions: Vec<Cow<'static, [TokenStream]>>,
}
impl Parser for DefinitionContent {
fn parser(tokens: &mut TokenIter) -> Result<Self> {
let names = Vec::<Named>::parse(tokens)?;
let len = 1.max(names.len());
let mut definitions: Vec<Cow<'static, [TokenStream]>> = Vec::with_capacity(len);
definitions.resize(len, Cow::Owned(Vec::new()));
if Expect::<TokenTree>::parse(tokens).is_err() {
return Error::unexpected_end();
}
while Expect::<TokenTree>::parse(tokens).is_ok() {
for def in definitions.iter_mut().take(len) {
def.to_mut().push(
Either::<ParenthesisGroupContaining<TokenStream>, TokenTree>::parse(tokens)?
.fold2(|pcontent| pcontent.content, |tt| tt.to_token_stream()),
);
}
}
Ok(Self { names, definitions })
}
}
impl ToTokens for DefinitionContent {
fn to_tokens(&self, _tokens: &mut TokenStream) {
unimplemented!();
}
}
#[test]
fn test_xtoken_parse() {
let parsed = "${something}"
.to_token_iter()
.parse_all::<XToken>()
.unwrap();
assert!(matches!(parsed, XToken::Scope(..)));
assert_eq!(parsed.tokens_to_string(), "${something}".tokens_to_string());
let parsed = "$(foo: foo)".to_token_iter().parse_all::<XToken>().unwrap();
assert!(matches!(parsed, XToken::Definition(..)));
let parsed = "$123".to_token_iter().parse_all::<XToken>().unwrap();
assert!(matches!(parsed, XToken::IndexedSubstitution(..)));
assert_eq!(parsed.tokens_to_string(), "$123".tokens_to_string());
let parsed = "$name".to_token_iter().parse_all::<XToken>().unwrap();
assert!(matches!(parsed, XToken::NamedSubstitution(..)));
assert_eq!(parsed.tokens_to_string(), "$name".tokens_to_string());
let parsed = "$?1".to_token_iter().parse_all::<XToken>().unwrap();
assert!(matches!(parsed, XToken::IndexOfIndexed(..)));
assert_eq!(parsed.tokens_to_string(), "$?1".tokens_to_string());
let parsed = "$?foo".to_token_iter().parse_all::<XToken>().unwrap();
assert!(matches!(parsed, XToken::IndexOfNamed(..)));
assert_eq!(parsed.tokens_to_string(), "$?foo".tokens_to_string());
let parsed = "$#0".to_token_iter().parse_all::<XToken>().unwrap();
assert!(matches!(parsed, XToken::LengthOfIndexed(..)));
assert_eq!(parsed.tokens_to_string(), "$#0".tokens_to_string());
let parsed = "$#foo".to_token_iter().parse_all::<XToken>().unwrap();
assert!(matches!(parsed, XToken::LengthOfNamed(..)));
assert_eq!(parsed.tokens_to_string(), "$#foo".tokens_to_string());
let parsed = "$$".to_token_iter().parse_all::<XToken>().unwrap();
assert!(matches!(parsed, XToken::EscapedDollar(..)));
assert_eq!(parsed.tokens_to_string(), "$$".tokens_to_string());
let parsed = "$:directive".to_token_iter().parse_all::<XToken>().unwrap();
assert!(matches!(parsed, XToken::Directive(..)));
assert_eq!(parsed.tokens_to_string(), "$:directive".tokens_to_string());
let parsed = "+$".to_token_iter().parse::<XToken>().unwrap();
assert!(matches!(parsed, XToken::BreakPunct(..)));
assert_eq!(parsed.tokens_to_string(), "+".tokens_to_string());
let parsed = "[anything else]"
.to_token_iter()
.parse_all::<XToken>()
.unwrap();
assert!(matches!(parsed, XToken::Group(..)));
assert_eq!(
parsed.tokens_to_string(),
"[anything else]".tokens_to_string()
);
let parsed = "something".to_token_iter().parse_all::<XToken>().unwrap();
assert!(matches!(parsed, XToken::TokenTree(..)));
assert_eq!(parsed.tokens_to_string(), "something".tokens_to_string());
let parsed = "".to_token_iter().parse_all::<XToken>().unwrap();
assert!(matches!(parsed, XToken::EndOfStream(..)));
}