use alloc::{boxed::Box, vec, vec::Vec};
use nom::{
branch::alt,
bytes::complete::{tag, take_until, take_while},
character::complete::char,
combinator::opt,
multi::separated_list0,
sequence::{delimited, pair},
IResult, Parser,
};
use crate::types::{
TypeName, TypeNameArray, TypeNameReference, TypeNameSlice, TypeNameStruct, TypeNameTrait,
TypeNameTuple,
};
#[rustfmt::skip]
const PRIMITIVE_TYPES: &[&str] = &[
"bool",
"char",
"f32",
"f64",
"i128",
"i16",
"i32",
"i64",
"i8",
"isize",
"str",
"u128",
"u16",
"u32",
"u64",
"u8",
"usize",
];
pub fn is_alphanumeric_underscore(c: char) -> bool {
c == '_' || c.is_ascii_alphanumeric()
}
pub fn is_lowercase_alphanumeric_underscore(c: char) -> bool {
c == '_' || c.is_ascii_digit() || c.is_ascii_lowercase()
}
pub fn module_name(input: &str) -> IResult<&str, &str> {
if let Some(first_char) = input.chars().next() {
if first_char.is_ascii_alphabetic() && first_char.is_ascii_lowercase() {
take_while(is_lowercase_alphanumeric_underscore).parse(input)
} else {
Ok((input, ""))
}
} else {
Ok((input, ""))
}
}
pub fn module_path(input: &str) -> IResult<&str, Vec<&str>> {
separated_list0(tag("::"), module_name)
.parse(input)
.map(|(input, mut module_names)| {
module_names.retain(|module_name| !module_name.is_empty());
(input, module_names)
})
}
pub fn type_simple_name(input: &str) -> IResult<&str, &str> {
if let Some(first_char) = input.chars().next() {
if first_char.is_ascii_alphabetic() && first_char.is_ascii_uppercase() {
take_while(is_alphanumeric_underscore).parse(input)
} else {
Ok((input, ""))
}
} else {
Ok((input, ""))
}
}
pub fn type_parameters(input: &str) -> IResult<&str, Vec<TypeName>> {
opt(delimited(
char('<'),
separated_list0(tag(", "), type_name),
char('>'),
))
.parse(input)
.map(|(input, type_params)| (input, type_params.unwrap_or_default()))
}
pub fn array_length(input: &str) -> IResult<&str, Option<&str>> {
pair(tag("; "), take_until("]"))
.parse(input)
.map(|(input, (_, len))| (input, Some(len)))
.or_else(|e| {
if let nom::Err::Error(nom::error::Error { input, code: _ }) = e {
Ok((input, None))
} else {
Err(e)
}
})
}
pub fn array_or_slice_internal(input: &str) -> IResult<&str, TypeName> {
(type_name, array_length)
.parse(input)
.map(|(input, (type_param, len))| {
let type_param = Box::new(type_param);
if let Some(len) = len {
(input, TypeName::Array(TypeNameArray { type_param, len }))
} else {
(input, TypeName::Slice(TypeNameSlice { type_param }))
}
})
}
pub fn array_or_slice(input: &str) -> IResult<&str, TypeName> {
delimited(char('['), array_or_slice_internal, char(']')).parse(input)
}
pub fn parse_reference(input: &str) -> IResult<&str, TypeName> {
(char('&'), opt(tag("mut")), opt(char(' ')), type_name)
.parse(input)
.map(|(input, (_, mut_str, _, type_param))| {
let type_param = Box::new(type_param);
(
input,
TypeName::Reference(TypeNameReference {
mutable: mut_str.is_some(),
type_param,
}),
)
})
}
pub fn parse_unit(input: &str) -> IResult<&str, TypeName> {
tag("()")
.parse(input)
.map(|(input, _)| (input, TypeName::Unit))
}
pub fn parse_tuple(input: &str) -> IResult<&str, TypeName> {
delimited(
char('('),
separated_list0(tag(", "), type_name),
(opt(char(',')), char(')')),
)
.parse(input)
.map(|(input, type_params)| {
let type_name_tuple = TypeName::Tuple(TypeNameTuple { type_params });
(input, type_name_tuple)
})
}
pub fn parse_unit_or_tuple(input: &str) -> IResult<&str, TypeName> {
alt((parse_unit, parse_tuple)).parse(input)
}
pub fn named_primitive(input: &str) -> Option<IResult<&str, TypeName>> {
if let Some(prim_type) = PRIMITIVE_TYPES
.iter()
.find(|prim_type| input.starts_with(*prim_type))
{
let remainder = &input[prim_type.len()..];
let next_char = remainder.chars().next();
let mut is_primitive_type = false;
if next_char.is_none() {
is_primitive_type = true;
} else if let Some(c) = next_char {
is_primitive_type = !is_lowercase_alphanumeric_underscore(c);
}
if is_primitive_type {
Some(Ok((
remainder,
TypeName::Struct(TypeNameStruct {
module_path: vec![],
simple_name: prim_type,
type_params: vec![],
}),
)))
} else {
None
}
} else {
None
}
}
pub fn struct_type(input: &str) -> IResult<&str, TypeNameStruct> {
(module_path, type_simple_name, type_parameters)
.parse(input)
.map(|(s, (module_path, simple_name, type_params))| {
(
s,
TypeNameStruct {
module_path,
simple_name,
type_params,
},
)
})
}
pub fn named_primitive_or_struct(input: &str) -> IResult<&str, TypeName> {
if let Some(result) = named_primitive(input) {
result
} else {
struct_type(input)
.map(|(input, type_name_struct)| (input, TypeName::Struct(type_name_struct)))
}
}
pub fn trait_type(input: &str) -> IResult<&str, TypeName> {
struct_type(input).map(|(input, type_name_struct)| {
(
input,
TypeName::Trait(TypeNameTrait {
inner: type_name_struct,
}),
)
})
}
pub fn type_name(input: &str) -> IResult<&str, TypeName> {
let mut chars = input.chars();
if let Some(first_char) = chars.next() {
match first_char {
'[' => array_or_slice(input),
'*' => unimplemented!("`tynm` is not implemented for pointer types."),
'!' => nom::character::complete::char('!')
.parse(input)
.map(|(input, _)| (input, TypeName::Never)),
'&' => parse_reference(input),
'(' => parse_unit_or_tuple(input),
'd' => {
let mut split = input.splitn(2, ' ');
if let Some("dyn") = split.next() {
if let Some(remainder) = split.next() {
trait_type(remainder)
} else {
Ok((
"",
TypeName::Struct(TypeNameStruct {
module_path: vec![],
simple_name: "dyn",
type_params: vec![],
}),
))
}
} else {
named_primitive_or_struct(input)
}
}
_ => named_primitive_or_struct(input),
}
} else {
Ok((input, TypeName::None))
}
}