use crate::apply::{err_ty, err_ty_at};
use crate::ast::*;
use crate::parse::generic::{
empty, is_trait_base, parse_angle_bracket_contents, parse_generic,
parse_type_params, primitive,
};
use crate::parse::parse_atom::{
parse_attribute, parse_function, parse_group, parse_prefix, parse_range,
};
use crate::parse::parse_primitive;
use crate::parse::trailing::attach_wrapper;
use crate::parse::{parse_item, split_at_depth0};
use crate::util::Cursor;
use proc_macro2::{Delimiter, Ident, TokenTree};
pub(crate) fn parse_primary(tokens: &[TokenTree], trait_name: Option<&Ident>) -> Ty {
if let Some((attr, rest)) = parse_attribute(tokens) {
return attach_wrapper(
TyWithAttr(TyAttr(attr), None).into(),
rest,
trait_name,
);
}
if let Some(function) = parse_function(tokens, trait_name) {
return function;
}
if let [TokenTree::Ident(name)] = tokens
&& name == "fn"
{
return TyFn(None, None, false).into();
}
if let Some((prefix, rest)) = parse_prefix(tokens) {
if matches!(prefix, TyPrefix::Unsafe) && !rest.is_empty() {
if matches!(rest.first(), Some(TokenTree::Ident(f)) if f == "fn") {
let inner = parse_primitive(rest, trait_name);
return match inner.kind {
TyKind::Fn(mut f) => {
f.2 = true;
f.to_ty().with_span(inner.span)
}
other => Ty { span: inner.span, kind: other },
};
}
return err_ty(
"batch-impl: `unsafe` can only qualify a fn type (e.g. `unsafe fn(u32) -> u32`) \
or act as a bare impl marker (e.g. `unsafe^T`)",
);
}
let inner =
attach_wrapper(TyWithPrefix(prefix, None).into(), rest, trait_name);
return inner;
}
if let [TokenTree::Punct(star), TokenTree::Group(group), rest @ ..] = tokens
&& star.as_char() == '*'
&& matches!(
group.delimiter(),
Delimiter::Bracket | Delimiter::Parenthesis
)
{
let inner = group.stream().into_iter().collect::<Vec<TokenTree>>();
let elems = if inner.is_empty() {
Vec::new()
} else {
split_at_depth0(&inner, ',')
.iter()
.filter(|c| !c.is_empty())
.map(|c| {
parse_item(&mut Cursor::new(c), Op::Dash, trait_name)
.unwrap_or_else(empty)
})
.collect()
};
let splat = if matches!(group.delimiter(), Delimiter::Bracket) {
TySplat::Array(TyArray(elems)).to_ty()
} else {
TySplat::Tuple(TyTuple(elems)).to_ty()
}
.with_span(star.span());
return if rest.is_empty() {
splat
} else {
splat.apply(parse_primitive(rest, trait_name))
};
}
if let [TokenTree::Punct(star), ..] = tokens
&& star.as_char() == '*'
{
return err_ty_at(
"batch-impl: `*` must be a splat (`*[...]` / `*(...)`) or a raw \
pointer (`*const T` / `*mut T`)",
star.span(),
);
}
if let Some(range) = parse_range(tokens) {
return range;
}
if let [TokenTree::Literal(literal)] = tokens {
match literal.to_string().parse::<usize>() {
Ok(number) => return TyNum(number).into(),
Err(_) => {
return err_ty_at(
"batch-impl: a bare literal in a type position must be an integer (usize); float/string/char literals are not types",
literal.span(),
);
}
}
}
if let [TokenTree::Group(group)] = tokens
&& group.delimiter() != delimiter![<>]
{
return parse_group(group, trait_name);
}
if let Some((base, args, rest)) = parse_generic(tokens) {
let args_vec = args.into_iter().collect::<Vec<TokenTree>>();
let params = parse_angle_bracket_contents(
&args_vec,
trait_name,
is_trait_base(&base, trait_name),
);
let generic = if is_trait_base(&base, trait_name) {
TyTrait(base.iter().cloned().collect(), params).into()
} else {
if !rest.is_empty()
&& !matches!(rest.first(), Some(TokenTree::Group(g)) if g.delimiter() == delimiter![<>])
{
return primitive(tokens);
}
TyGeneric(primitive(&base).into(), params).into()
};
return if rest.is_empty() {
generic
} else {
generic.apply(parse_primitive(&rest, trait_name))
};
}
if let Some((args, rest)) = parse_type_params(tokens) {
let args_vec = args.into_iter().collect::<Vec<_>>();
let params = parse_angle_bracket_contents(&args_vec, trait_name, true);
let params = params.into();
return if rest.is_empty() {
params
} else {
params.apply(parse_primitive(&rest, trait_name))
};
}
primitive(tokens)
}