use proc_macro2::TokenStream;
#[derive(Debug, Clone)]
pub(crate) struct Args {
pub(crate) cst_span: Option<proc_macro2::Span>,
pub(crate) ast_span: Option<proc_macro2::Span>,
pub(crate) error_span: Option<proc_macro2::Span>,
pub(crate) semantic_span: Option<proc_macro2::Span>,
}
impl Args {
pub(crate) fn parse(ts: TokenStream) -> Self {
let mut args = Args {
cst_span: None,
ast_span: None,
error_span: None,
semantic_span: None,
};
let tokens_iter = ts.clone().into_iter().peekable();
let mut collected_tokens = Vec::new();
let mut items = Vec::new();
for token in tokens_iter {
match &token {
| proc_macro2::TokenTree::Punct(punct) if punct.as_char() == ',' => {
if !collected_tokens.is_empty() {
items.push(collected_tokens.to_vec());
collected_tokens.clear();
}
},
| _ => {
collected_tokens.push(token);
},
}
}
if !collected_tokens.is_empty() {
items.push(collected_tokens.to_vec());
}
for item in items {
for tkn in item.iter() {
match tkn {
| proc_macro2::TokenTree::Ident(ident) => {
match ident.to_string().as_str() {
| "CST" => {
args.cst_span = Some(ident.span());
},
| "AST" => {
args.ast_span = Some(ident.span());
},
| "error" => {
args.error_span = Some(ident.span());
},
| "allow_semantic" => {
args.semantic_span = Some(ident.span());
},
| _ => (),
}
},
| _ => (),
}
}
}
args
}
pub(crate) fn is_cst(&self) -> bool {
self.cst_span.is_some()
}
pub(crate) fn is_ast(&self) -> bool {
self.ast_span.is_some()
}
pub(crate) fn is_error_node(&self) -> bool {
self.error_span.is_some()
}
pub(crate) fn has_semantic_tokens(&self) -> bool {
self.semantic_span.is_some()
}
pub(crate) fn conflicting_span(&self) -> proc_macro2::Span {
self
.ast_span
.or(self.cst_span)
.unwrap_or_else(proc_macro2::Span::call_site)
}
pub(crate) fn missing_type_span(&self) -> proc_macro2::Span {
self
.error_span
.or(self.semantic_span)
.unwrap_or_else(proc_macro2::Span::call_site)
}
#[cfg(test)]
#[allow(dead_code)]
pub(crate) fn ast() -> Self {
Self {
cst_span: None,
ast_span: Some(proc_macro2::Span::call_site()),
error_span: None,
semantic_span: None,
}
}
#[cfg(test)]
#[allow(dead_code)]
pub(crate) fn cst() -> Self {
Self {
cst_span: Some(proc_macro2::Span::call_site()),
ast_span: None,
error_span: None,
semantic_span: None,
}
}
#[cfg(test)]
#[allow(dead_code)]
pub(crate) fn ast_with_error() -> Self {
Self {
cst_span: None,
ast_span: Some(proc_macro2::Span::call_site()),
error_span: Some(proc_macro2::Span::call_site()),
semantic_span: None,
}
}
#[cfg(test)]
#[allow(dead_code)]
pub(crate) fn cst_with_error() -> Self {
Self {
cst_span: Some(proc_macro2::Span::call_site()),
ast_span: None,
error_span: Some(proc_macro2::Span::call_site()),
semantic_span: None,
}
}
#[cfg(test)]
#[allow(dead_code)]
pub(crate) fn ast_with_semantic() -> Self {
Self {
cst_span: None,
ast_span: Some(proc_macro2::Span::call_site()),
error_span: None,
semantic_span: Some(proc_macro2::Span::call_site()),
}
}
#[cfg(test)]
#[allow(dead_code)]
pub(crate) fn cst_with_semantic() -> Self {
Self {
cst_span: Some(proc_macro2::Span::call_site()),
ast_span: None,
error_span: None,
semantic_span: Some(proc_macro2::Span::call_site()),
}
}
#[cfg(test)]
#[allow(dead_code)]
pub(crate) fn ast_with_error_and_semantic() -> Self {
Self {
cst_span: None,
ast_span: Some(proc_macro2::Span::call_site()),
error_span: Some(proc_macro2::Span::call_site()),
semantic_span: Some(proc_macro2::Span::call_site()),
}
}
#[cfg(test)]
#[allow(dead_code)]
pub(crate) fn cst_with_error_and_semantic() -> Self {
Self {
cst_span: Some(proc_macro2::Span::call_site()),
ast_span: None,
error_span: Some(proc_macro2::Span::call_site()),
semantic_span: Some(proc_macro2::Span::call_site()),
}
}
}