use crate::parse::EntryRole;
use crate::parse::google::kind::GoogleSectionKind;
use crate::parse::text_block::TextBlock;
use crate::parse::text_block::find_text_block;
use crate::parse::token_ref::TokenRef;
use crate::parse::unified::DefaultMarker;
use crate::syntax::Parsed;
use crate::syntax::SyntaxKind;
use crate::syntax::SyntaxNode;
macro_rules! define_node {
($name:ident, $kind:ident) => {
#[doc = concat!("Typed wrapper for `", stringify!($kind), "` syntax nodes.")]
#[derive(Debug, Clone, Copy)]
pub struct $name<'a> {
pub(crate) parsed: &'a Parsed,
pub(crate) node: &'a SyntaxNode,
}
impl<'a> $name<'a> {
pub fn cast(parsed: &'a Parsed, node: &'a SyntaxNode) -> Option<Self> {
(node.kind() == SyntaxKind::$kind).then(|| Self { parsed, node })
}
pub fn syntax(&self) -> &'a SyntaxNode {
self.node
}
#[allow(dead_code)]
fn token_ref(&self, token: &'a crate::syntax::SyntaxToken) -> TokenRef<'a> {
TokenRef::new(self.parsed, token)
}
#[allow(dead_code)]
fn find_token_ref(&self, kind: SyntaxKind) -> Option<TokenRef<'a>> {
self.node.find_token(kind).map(|t| TokenRef::new(self.parsed, t))
}
}
};
}
define_node!(GoogleDocstring, DOCUMENT);
impl<'a> GoogleDocstring<'a> {
pub fn summary(&self) -> Option<TextBlock<'a>> {
find_text_block(self.parsed, self.node, SyntaxKind::SUMMARY)
}
pub fn extended_summary(&self) -> Option<TextBlock<'a>> {
find_text_block(self.parsed, self.node, SyntaxKind::EXTENDED_SUMMARY)
}
pub fn deprecation(&self) -> Option<GoogleDeprecation<'a>> {
let parsed = self.parsed;
self.node
.nodes(SyntaxKind::DIRECTIVE)
.find(|n| crate::parse::utils::directive_is_deprecated(parsed, n))
.map(|node| GoogleDeprecation { parsed, node })
}
pub fn sections(&self) -> impl Iterator<Item = GoogleSection<'a>> {
let parsed = self.parsed;
self.node
.nodes(SyntaxKind::SECTION)
.map(move |node| GoogleSection { parsed, node })
}
pub fn paragraphs(&self) -> impl Iterator<Item = TextBlock<'a>> {
let parsed = self.parsed;
self.node
.nodes(SyntaxKind::PARAGRAPH)
.filter_map(move |node| TextBlock::cast(parsed, node))
}
#[deprecated(
since = "0.3.0",
note = "use `paragraphs()`; stray lines are now PARAGRAPH text blocks"
)]
pub fn stray_lines(&self) -> impl Iterator<Item = TextBlock<'a>> {
self.paragraphs()
}
}
define_node!(GoogleDeprecation, DIRECTIVE);
impl<'a> GoogleDeprecation<'a> {
pub fn directive_marker(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::DIRECTIVE_MARKER)
}
pub fn keyword(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::DIRECTIVE_NAME)
}
pub fn double_colon(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::DOUBLE_COLON)
}
pub fn version(&self) -> TokenRef<'a> {
self.token_ref(self.node.required_token(SyntaxKind::ARGUMENT))
}
pub fn description(&self) -> Option<TextBlock<'a>> {
find_text_block(self.parsed, self.node, SyntaxKind::DESCRIPTION)
}
}
define_node!(GoogleDirective, DIRECTIVE);
impl<'a> GoogleDirective<'a> {
pub fn directive_marker(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::DIRECTIVE_MARKER)
}
pub fn name(&self) -> TokenRef<'a> {
self.token_ref(self.node.required_token(SyntaxKind::DIRECTIVE_NAME))
}
pub fn double_colon(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::DOUBLE_COLON)
}
pub fn argument(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::ARGUMENT)
}
pub fn description(&self) -> Option<TextBlock<'a>> {
find_text_block(self.parsed, self.node, SyntaxKind::DESCRIPTION)
}
}
define_node!(GoogleSection, SECTION);
impl<'a> GoogleSection<'a> {
pub fn header(&self) -> GoogleSectionHeader<'a> {
GoogleSectionHeader {
parsed: self.parsed,
node: self
.node
.find_node(SyntaxKind::SECTION_HEADER)
.expect("SECTION must have a SECTION_HEADER child"),
}
}
pub fn section_kind(&self) -> GoogleSectionKind {
let name_text = self.header().name().text();
GoogleSectionKind::from_name(&name_text.to_ascii_lowercase())
}
fn entries_with_role(&self, role: EntryRole) -> impl Iterator<Item = &'a SyntaxNode> {
let matches = self.section_kind().entry_role() == role;
self.node.nodes(SyntaxKind::ENTRY).filter(move |_| matches)
}
pub fn args(&self) -> impl Iterator<Item = GoogleArg<'a>> {
let parsed = self.parsed;
self.entries_with_role(EntryRole::Parameter)
.map(move |node| GoogleArg { parsed, node })
}
pub fn returns(&self) -> Option<GoogleReturn<'a>> {
let parsed = self.parsed;
self.entries_with_role(EntryRole::Return)
.next()
.map(|node| GoogleReturn { parsed, node })
}
pub fn yields(&self) -> Option<GoogleYield<'a>> {
let parsed = self.parsed;
self.entries_with_role(EntryRole::Yield)
.next()
.map(|node| GoogleYield { parsed, node })
}
pub fn exceptions(&self) -> impl Iterator<Item = GoogleException<'a>> {
let parsed = self.parsed;
self.entries_with_role(EntryRole::Exception)
.map(move |node| GoogleException { parsed, node })
}
pub fn warnings(&self) -> impl Iterator<Item = GoogleWarning<'a>> {
let parsed = self.parsed;
self.entries_with_role(EntryRole::Warning)
.map(move |node| GoogleWarning { parsed, node })
}
pub fn see_also_items(&self) -> impl Iterator<Item = GoogleSeeAlsoItem<'a>> {
let parsed = self.parsed;
self.entries_with_role(EntryRole::SeeAlsoItem)
.map(move |node| GoogleSeeAlsoItem { parsed, node })
}
pub fn references(&self) -> impl Iterator<Item = GoogleReference<'a>> {
let parsed = self.parsed;
self.node
.nodes(SyntaxKind::CITATION)
.map(move |node| GoogleReference { parsed, node })
}
pub fn attributes(&self) -> impl Iterator<Item = GoogleAttribute<'a>> {
let parsed = self.parsed;
self.entries_with_role(EntryRole::Attribute)
.map(move |node| GoogleAttribute { parsed, node })
}
pub fn methods(&self) -> impl Iterator<Item = GoogleMethod<'a>> {
let parsed = self.parsed;
self.entries_with_role(EntryRole::Method)
.map(move |node| GoogleMethod { parsed, node })
}
pub fn body_text(&self) -> Option<TextBlock<'a>> {
find_text_block(self.parsed, self.node, SyntaxKind::DESCRIPTION)
}
}
define_node!(GoogleSectionHeader, SECTION_HEADER);
impl<'a> GoogleSectionHeader<'a> {
pub fn name(&self) -> TokenRef<'a> {
self.token_ref(self.node.required_token(SyntaxKind::NAME))
}
pub fn colon(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::COLON)
}
}
define_node!(GoogleArg, ENTRY);
impl<'a> GoogleArg<'a> {
pub fn name(&self) -> TokenRef<'a> {
self.token_ref(self.node.required_token(SyntaxKind::NAME))
}
pub fn names(&self) -> impl Iterator<Item = TokenRef<'a>> {
let parsed = self.parsed;
self.node
.tokens(SyntaxKind::NAME)
.map(move |t| TokenRef::new(parsed, t))
}
pub fn open_bracket(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::OPEN_BRACKET)
}
pub fn type_annotation(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::TYPE)
}
#[deprecated(since = "0.3.0", note = "renamed to type_annotation")]
pub fn r#type(&self) -> Option<TokenRef<'a>> {
self.type_annotation()
}
pub fn close_bracket(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::CLOSE_BRACKET)
}
pub fn colon(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::COLON)
}
pub fn description(&self) -> Option<TextBlock<'a>> {
find_text_block(self.parsed, self.node, SyntaxKind::DESCRIPTION)
}
pub fn is_optional(&self) -> bool {
self.optionals().next().is_some()
}
pub fn optional_marker(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::OPTIONAL)
}
#[deprecated(since = "0.3.0", note = "renamed to optional_marker; see also is_optional")]
pub fn optional(&self) -> Option<TokenRef<'a>> {
self.optional_marker()
}
pub fn optionals(&self) -> impl Iterator<Item = TokenRef<'a>> {
let parsed = self.parsed;
self.node
.tokens(SyntaxKind::OPTIONAL)
.map(move |t| TokenRef::new(parsed, t))
}
pub fn defaults(&self) -> impl Iterator<Item = DefaultMarker<'a>> {
let parsed = self.parsed;
self.node
.nodes(SyntaxKind::DEFAULT)
.filter_map(move |node| DefaultMarker::cast(parsed, node))
}
pub fn default_keyword(&self) -> Option<TokenRef<'a>> {
self.defaults().next().map(|d| d.keyword())
}
pub fn default_separator(&self) -> Option<TokenRef<'a>> {
self.defaults().next().and_then(|d| d.separator())
}
pub fn default_value(&self) -> Option<TokenRef<'a>> {
self.defaults().next().and_then(|d| d.value())
}
}
define_node!(GoogleReturn, ENTRY);
impl<'a> GoogleReturn<'a> {
pub fn type_annotation(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::TYPE)
}
#[deprecated(since = "0.3.0", note = "renamed to type_annotation")]
pub fn return_type(&self) -> Option<TokenRef<'a>> {
self.type_annotation()
}
pub fn colon(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::COLON)
}
pub fn description(&self) -> Option<TextBlock<'a>> {
find_text_block(self.parsed, self.node, SyntaxKind::DESCRIPTION)
}
}
define_node!(GoogleYield, ENTRY);
impl<'a> GoogleYield<'a> {
pub fn type_annotation(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::TYPE)
}
#[deprecated(since = "0.3.0", note = "renamed to type_annotation")]
pub fn return_type(&self) -> Option<TokenRef<'a>> {
self.type_annotation()
}
pub fn colon(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::COLON)
}
pub fn description(&self) -> Option<TextBlock<'a>> {
find_text_block(self.parsed, self.node, SyntaxKind::DESCRIPTION)
}
}
define_node!(GoogleException, ENTRY);
impl<'a> GoogleException<'a> {
pub fn type_annotation(&self) -> TokenRef<'a> {
self.token_ref(self.node.required_token(SyntaxKind::TYPE))
}
#[deprecated(since = "0.3.0", note = "renamed to type_annotation")]
pub fn r#type(&self) -> TokenRef<'a> {
self.type_annotation()
}
pub fn colon(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::COLON)
}
pub fn description(&self) -> Option<TextBlock<'a>> {
find_text_block(self.parsed, self.node, SyntaxKind::DESCRIPTION)
}
}
define_node!(GoogleWarning, ENTRY);
impl<'a> GoogleWarning<'a> {
pub fn type_annotation(&self) -> TokenRef<'a> {
self.token_ref(self.node.required_token(SyntaxKind::TYPE))
}
#[deprecated(since = "0.3.0", note = "renamed to type_annotation")]
pub fn warning_type(&self) -> TokenRef<'a> {
self.type_annotation()
}
pub fn colon(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::COLON)
}
pub fn description(&self) -> Option<TextBlock<'a>> {
find_text_block(self.parsed, self.node, SyntaxKind::DESCRIPTION)
}
}
define_node!(GoogleSeeAlsoItem, ENTRY);
impl<'a> GoogleSeeAlsoItem<'a> {
pub fn names(&self) -> impl Iterator<Item = TokenRef<'a>> {
let parsed = self.parsed;
self.node
.tokens(SyntaxKind::NAME)
.map(move |t| TokenRef::new(parsed, t))
}
pub fn colon(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::COLON)
}
pub fn description(&self) -> Option<TextBlock<'a>> {
find_text_block(self.parsed, self.node, SyntaxKind::DESCRIPTION)
}
}
define_node!(GoogleReference, CITATION);
impl<'a> GoogleReference<'a> {
pub fn directive_marker(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::DIRECTIVE_MARKER)
}
pub fn open_bracket(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::OPEN_BRACKET)
}
pub fn label(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::LABEL)
}
#[deprecated(since = "0.3.0", note = "renamed to label")]
pub fn number(&self) -> Option<TokenRef<'a>> {
self.label()
}
pub fn close_bracket(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::CLOSE_BRACKET)
}
pub fn content(&self) -> Option<TextBlock<'a>> {
find_text_block(self.parsed, self.node, SyntaxKind::DESCRIPTION)
}
}
define_node!(GoogleAttribute, ENTRY);
impl<'a> GoogleAttribute<'a> {
pub fn name(&self) -> TokenRef<'a> {
self.token_ref(self.node.required_token(SyntaxKind::NAME))
}
pub fn names(&self) -> impl Iterator<Item = TokenRef<'a>> {
let parsed = self.parsed;
self.node
.tokens(SyntaxKind::NAME)
.map(move |t| TokenRef::new(parsed, t))
}
pub fn open_bracket(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::OPEN_BRACKET)
}
pub fn type_annotation(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::TYPE)
}
#[deprecated(since = "0.3.0", note = "renamed to type_annotation")]
pub fn r#type(&self) -> Option<TokenRef<'a>> {
self.type_annotation()
}
pub fn close_bracket(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::CLOSE_BRACKET)
}
pub fn colon(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::COLON)
}
pub fn description(&self) -> Option<TextBlock<'a>> {
find_text_block(self.parsed, self.node, SyntaxKind::DESCRIPTION)
}
}
define_node!(GoogleMethod, ENTRY);
impl<'a> GoogleMethod<'a> {
pub fn name(&self) -> TokenRef<'a> {
self.token_ref(self.node.required_token(SyntaxKind::NAME))
}
pub fn open_bracket(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::OPEN_BRACKET)
}
pub fn type_annotation(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::TYPE)
}
#[deprecated(since = "0.3.0", note = "renamed to type_annotation")]
pub fn r#type(&self) -> Option<TokenRef<'a>> {
self.type_annotation()
}
pub fn close_bracket(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::CLOSE_BRACKET)
}
pub fn colon(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::COLON)
}
pub fn description(&self) -> Option<TextBlock<'a>> {
find_text_block(self.parsed, self.node, SyntaxKind::DESCRIPTION)
}
}