use crate::parse::EntryRole;
use crate::parse::numpy::kind::NumPySectionKind;
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!(NumPyDocstring, DOCUMENT);
impl<'a> NumPyDocstring<'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<NumPyDeprecation<'a>> {
let parsed = self.parsed;
self.node
.nodes(SyntaxKind::DIRECTIVE)
.find(|n| crate::parse::utils::directive_is_deprecated(parsed, n))
.map(|node| NumPyDeprecation { parsed, node })
}
pub fn sections(&self) -> impl Iterator<Item = NumPySection<'a>> {
let parsed = self.parsed;
self.node
.nodes(SyntaxKind::SECTION)
.map(move |node| NumPySection { 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!(NumPySection, SECTION);
impl<'a> NumPySection<'a> {
pub fn header(&self) -> NumPySectionHeader<'a> {
NumPySectionHeader {
parsed: self.parsed,
node: self
.node
.find_node(SyntaxKind::SECTION_HEADER)
.expect("SECTION must have a SECTION_HEADER child"),
}
}
pub fn section_kind(&self) -> NumPySectionKind {
let name_text = self.header().name().text();
NumPySectionKind::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 parameters(&self) -> impl Iterator<Item = NumPyParameter<'a>> {
let parsed = self.parsed;
self.entries_with_role(EntryRole::Parameter)
.map(move |node| NumPyParameter { parsed, node })
}
pub fn returns(&self) -> impl Iterator<Item = NumPyReturns<'a>> {
let parsed = self.parsed;
self.entries_with_role(EntryRole::Return)
.map(move |node| NumPyReturns { parsed, node })
}
pub fn yields(&self) -> impl Iterator<Item = NumPyYields<'a>> {
let parsed = self.parsed;
self.entries_with_role(EntryRole::Yield)
.map(move |node| NumPyYields { parsed, node })
}
pub fn exceptions(&self) -> impl Iterator<Item = NumPyException<'a>> {
let parsed = self.parsed;
self.entries_with_role(EntryRole::Exception)
.map(move |node| NumPyException { parsed, node })
}
pub fn warnings(&self) -> impl Iterator<Item = NumPyWarning<'a>> {
let parsed = self.parsed;
self.entries_with_role(EntryRole::Warning)
.map(move |node| NumPyWarning { parsed, node })
}
pub fn see_also_items(&self) -> impl Iterator<Item = NumPySeeAlsoItem<'a>> {
let parsed = self.parsed;
self.entries_with_role(EntryRole::SeeAlsoItem)
.map(move |node| NumPySeeAlsoItem { parsed, node })
}
pub fn references(&self) -> impl Iterator<Item = NumPyReference<'a>> {
let parsed = self.parsed;
self.node
.nodes(SyntaxKind::CITATION)
.map(move |node| NumPyReference { parsed, node })
}
pub fn attributes(&self) -> impl Iterator<Item = NumPyAttribute<'a>> {
let parsed = self.parsed;
self.entries_with_role(EntryRole::Attribute)
.map(move |node| NumPyAttribute { parsed, node })
}
pub fn methods(&self) -> impl Iterator<Item = NumPyMethod<'a>> {
let parsed = self.parsed;
self.entries_with_role(EntryRole::Method)
.map(move |node| NumPyMethod { parsed, node })
}
pub fn body_text(&self) -> Option<TextBlock<'a>> {
find_text_block(self.parsed, self.node, SyntaxKind::DESCRIPTION)
}
}
define_node!(NumPySectionHeader, SECTION_HEADER);
impl<'a> NumPySectionHeader<'a> {
pub fn name(&self) -> TokenRef<'a> {
self.token_ref(self.node.required_token(SyntaxKind::NAME))
}
pub fn underline(&self) -> TokenRef<'a> {
self.token_ref(self.node.required_token(SyntaxKind::UNDERLINE))
}
}
define_node!(NumPyDeprecation, DIRECTIVE);
impl<'a> NumPyDeprecation<'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!(NumPyDirective, DIRECTIVE);
impl<'a> NumPyDirective<'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!(NumPyParameter, ENTRY);
impl<'a> NumPyParameter<'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 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 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!(NumPyReturns, ENTRY);
impl<'a> NumPyReturns<'a> {
pub fn name(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::NAME)
}
pub fn colon(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::COLON)
}
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 description(&self) -> Option<TextBlock<'a>> {
find_text_block(self.parsed, self.node, SyntaxKind::DESCRIPTION)
}
}
define_node!(NumPyYields, ENTRY);
impl<'a> NumPyYields<'a> {
pub fn name(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::NAME)
}
pub fn colon(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::COLON)
}
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 description(&self) -> Option<TextBlock<'a>> {
find_text_block(self.parsed, self.node, SyntaxKind::DESCRIPTION)
}
}
define_node!(NumPyException, ENTRY);
impl<'a> NumPyException<'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!(NumPyWarning, ENTRY);
impl<'a> NumPyWarning<'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!(NumPySeeAlsoItem, ENTRY);
impl<'a> NumPySeeAlsoItem<'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!(NumPyReference, CITATION);
impl<'a> NumPyReference<'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!(NumPyAttribute, ENTRY);
impl<'a> NumPyAttribute<'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 colon(&self) -> Option<TokenRef<'a>> {
self.find_token_ref(SyntaxKind::COLON)
}
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 description(&self) -> Option<TextBlock<'a>> {
find_text_block(self.parsed, self.node, SyntaxKind::DESCRIPTION)
}
}
define_node!(NumPyMethod, ENTRY);
impl<'a> NumPyMethod<'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)
}
pub fn description(&self) -> Option<TextBlock<'a>> {
find_text_block(self.parsed, self.node, SyntaxKind::DESCRIPTION)
}
}