use sv_parser::{NodeEvent, RefNode, SyntaxTree};
pub struct RawDoc<'a> {
pub ast: &'a SyntaxTree,
pub root: Scope<'a>,
}
impl<'a> RawDoc<'a> {
pub fn new(ast: &'a SyntaxTree) -> Self {
let mut comments = vec![];
let mut stack = vec![];
#[derive(PartialEq)]
enum LastComment {
None,
Local,
Parent,
}
let mut last_comment = LastComment::None;
stack.push(Scope::default());
for event in ast.into_iter().event() {
match event {
NodeEvent::Enter(node) => match node {
RefNode::Comment(comment) => {
let s = ast.get_str(&comment.nodes.0).unwrap();
if s.starts_with("//!") {
let comments = &mut stack.last_mut().unwrap().comments;
if !comments.is_empty() && last_comment != LastComment::Parent {
comments.push("");
}
last_comment = LastComment::Parent;
comments.push(&s[3..]);
} else if s.starts_with("///") && !s.starts_with("////") {
if !comments.is_empty() && last_comment != LastComment::Local {
comments.push("");
}
last_comment = LastComment::Local;
comments.push(&s[3..]);
}
}
RefNode::TypeDeclaration(..)
| RefNode::NetDeclaration(..)
| RefNode::ParameterDeclaration(..)
| RefNode::LocalParameterDeclaration(..)
| RefNode::AnsiPortDeclaration(..)
| RefNode::ModuleDeclaration(..)
| RefNode::PackageDeclaration(..) => {
last_comment = LastComment::None;
stack.push(Scope::new(node.clone(), std::mem::take(&mut comments)));
}
RefNode::SourceText(..)
| RefNode::WhiteSpace(..)
| RefNode::Locate(..)
| RefNode::Description(..)
| RefNode::DescriptionPackageItem(..)
| RefNode::PackageItem(..)
| RefNode::PackageOrGenerateItemDeclaration(..)
| RefNode::DataDeclaration(..)
| RefNode::NonPortModuleItem(..)
| RefNode::ModuleOrGenerateItem(..)
| RefNode::ModuleOrGenerateItemDeclaration(..)
| RefNode::ModuleItem(..)
| RefNode::ParameterPortDeclaration(..)
| RefNode::ModuleCommonItem(..)
| RefNode::ModuleOrGenerateItemModuleItem(..) => (),
_ => {
last_comment = LastComment::None;
if !comments.is_empty() {
debug!("Discarding comments: {:#?}", comments);
trace!("Discarded due to {:?}", node);
comments.clear();
}
}
},
NodeEvent::Leave(node) => {
if stack.last().and_then(|s| s.node.clone()) == Some(node) {
let n = stack.pop().unwrap();
stack.last_mut().unwrap().children.push(n);
}
}
}
}
assert_eq!(stack.len(), 1);
let root = stack.into_iter().next().unwrap();
Self { ast, root }
}
}
#[derive(Default, Debug)]
pub struct Scope<'a> {
pub node: Option<RefNode<'a>>,
pub comments: Vec<&'a str>,
pub children: Vec<Scope<'a>>,
}
impl<'a> Scope<'a> {
fn new(node: RefNode<'a>, comments: Vec<&'a str>) -> Self {
Self {
node: Some(node),
comments,
..Default::default()
}
}
}