use crate::{diagnostic::Diagnostic, doc_entry::FunctionType, span::Span};
use serde::Serialize;
use std::convert::TryFrom;
mod class;
mod custom;
mod error;
mod external;
mod field;
mod function;
mod index;
mod interface;
mod marker;
mod param;
mod property;
mod return_tag;
mod status;
mod type_tag;
mod validation;
mod within;
pub use class::ClassTag;
pub use custom::CustomTag;
pub use error::ErrorTag;
pub use external::ExternalTag;
pub use field::FieldTag;
pub use function::FunctionTag;
pub use index::IndexTag;
pub use interface::InterfaceTag;
pub use marker::{
ClientTag, IgnoreTag, PluginTag, PrivateTag, ReadOnlyTag, ServerTag, UnreleasedTag, YieldsTag,
};
pub use param::ParamTag;
pub use property::PropertyTag;
pub use return_tag::ReturnTag;
pub use status::{DeprecatedTag, SinceTag};
pub use type_tag::TypeTag;
pub use validation::{validate_global_tags, validate_tags};
pub use within::WithinTag;
macro_rules! define_tags {
( $( $variant_name:ident($struct_name:ident),)* ) => {
#[derive(Debug, PartialEq, Serialize, Clone)]
pub enum Tag<'a> {
$( $variant_name($struct_name<'a>), )*
}
impl<'a> Tag<'a> {
pub fn diagnostic(&self, text: &str) -> Diagnostic {
match self {
$( Tag::$variant_name(tag) => tag.source.diagnostic(text), )*
}
}
pub fn tag_type(&self) -> TagType {
match self {
$( Tag::$variant_name(_) => TagType::$variant_name, )*
}
}
pub fn blame(&mut self, span: Span<'a>) {
match self {
$( Tag::$variant_name(tag) => tag.source.replace(span), )*
}
}
}
#[allow(unused)]
#[derive(Debug, PartialEq, Hash, Eq, PartialOrd, Ord)]
pub enum TagType {
$( $variant_name, )*
}
};
}
define_tags! {
Param(ParamTag),
Function(FunctionTag),
Property(PropertyTag),
Class(ClassTag),
Within(WithinTag),
Type(TypeTag),
Interface(InterfaceTag),
Field(FieldTag),
Unreleased(UnreleasedTag),
Server(ServerTag),
Client(ClientTag),
Plugin(PluginTag),
Private(PrivateTag),
Ignore(IgnoreTag),
Yields(YieldsTag),
ReadOnly(ReadOnlyTag),
Return(ReturnTag),
Deprecated(DeprecatedTag),
Since(SinceTag),
Custom(CustomTag),
Error(ErrorTag),
Index(IndexTag),
External(ExternalTag),
}
impl<'a> TryFrom<Span<'a>> for Tag<'a> {
type Error = Diagnostic;
fn try_from(text: Span<'a>) -> Result<Self, Diagnostic> {
if text.starts_with('.') {
let mut parsed_tag = FieldTag::parse(text.slice(1, text.len() - 1)).map(Tag::Field)?;
parsed_tag.blame(text);
return Ok(parsed_tag);
}
let mut pieces = text.splitn(2, " ");
let tag_name = pieces.next().unwrap().trim();
let mut tag_text = || {
pieces
.next()
.map(Span::trim)
.ok_or_else(|| text.diagnostic("This tag requires text following it"))
};
let mut parsed_tag = match tag_name.as_str() {
"@server" => ServerTag::parse().map(Tag::Server),
"@client" => ClientTag::parse().map(Tag::Client),
"@plugin" => PluginTag::parse().map(Tag::Plugin),
"@private" => PrivateTag::parse().map(Tag::Private),
"@ignore" => IgnoreTag::parse().map(Tag::Ignore),
"@yields" => YieldsTag::parse().map(Tag::Yields),
"@readonly" => ReadOnlyTag::parse().map(Tag::ReadOnly),
"@unreleased" => UnreleasedTag::parse().map(Tag::Unreleased),
"@param" => ParamTag::parse(tag_text()?).map(Tag::Param),
"@return" => ReturnTag::parse(tag_text()?).map(Tag::Return),
"@within" => WithinTag::parse(tag_text()?).map(Tag::Within),
"@__index" => IndexTag::parse(tag_text()?).map(Tag::Index),
"@type" => TypeTag::parse(tag_text()?).map(Tag::Type),
"@interface" => InterfaceTag::parse(tag_text()?).map(Tag::Interface),
"@field" => FieldTag::parse(tag_text()?).map(Tag::Field),
"@prop" => PropertyTag::parse(tag_text()?).map(Tag::Property),
"@class" => ClassTag::parse(tag_text()?).map(Tag::Class),
"@external" => ExternalTag::parse(tag_text()?).map(Tag::External),
"@function" => FunctionTag::parse(tag_text()?, FunctionType::Static).map(Tag::Function),
"@method" => FunctionTag::parse(tag_text()?, FunctionType::Method).map(Tag::Function),
"@deprecated" => DeprecatedTag::parse(tag_text()?).map(Tag::Deprecated),
"@since" => SinceTag::parse(tag_text()?).map(Tag::Since),
"@tag" => CustomTag::parse(tag_text()?).map(Tag::Custom),
"@error" => ErrorTag::parse(tag_text()?).map(Tag::Error),
_ => Err(text.diagnostic("Unknown tag")),
}?;
parsed_tag.blame(text);
Ok(parsed_tag)
}
}