use crate::core::hdlparam::{self, FastHdlparam}; use log::info; use ropey::Rope; use sv_parser::*; use tower_lsp::lsp_types::*; // 定义有关 scope 相关的基础类的 pub mod common; // 定义如何把 ast 转变为类似于 common 中的数据结构 pub mod parse; use common::*; use parse::*; type ScopesAndDefs = Option<(Vec>, Vec>)>; /// Take a given syntax node from a sv-parser syntax tree and extract out the definition/scope at /// that point. pub fn match_definitions( syntax_tree: &SyntaxTree, event_iter: &mut EventIter, node: RefNode, url: &Url, ) -> ScopesAndDefs { let mut definitions: Vec> = Vec::new(); let mut scopes: Vec> = Vec::new(); match node { RefNode::IncludeStatement(n) => { info!("enter IncludeStatement"); info!("{:?}", n); } RefNode::ModuleDeclaration(n) => { let module = module_dec(syntax_tree, n, event_iter, url); if module.is_some() { scopes.push(Box::new(module?)); } } RefNode::InterfaceDeclaration(n) => { let interface = interface_dec(syntax_tree, n, event_iter, url); if interface.is_some() { scopes.push(Box::new(interface?)); } } RefNode::UdpDeclaration(n) => { let dec = udp_dec(syntax_tree, n, event_iter, url); if dec.is_some() { scopes.push(Box::new(dec?)); } } RefNode::ProgramDeclaration(n) => { let dec = program_dec(syntax_tree, n, event_iter, url); if dec.is_some() { scopes.push(Box::new(dec?)); } } RefNode::PackageDeclaration(n) => { let dec = package_dec(syntax_tree, n, event_iter, url); if dec.is_some() { scopes.push(Box::new(dec?)); } } RefNode::ConfigDeclaration(n) => { let dec = config_dec(syntax_tree, n, event_iter, url); if dec.is_some() { scopes.push(Box::new(dec?)); } } RefNode::ClassDeclaration(n) => { let dec = class_dec(syntax_tree, n, event_iter, url); if dec.is_some() { scopes.push(Box::new(dec?)); } } RefNode::PortDeclaration(n) => { let ports = port_dec_non_ansi(syntax_tree, n, event_iter, url); if ports.is_some() { for port in ports? { definitions.push(Box::new(port)); } } } RefNode::NetDeclaration(n) => { let nets = net_dec(syntax_tree, n, event_iter, url); if nets.is_some() { for net in nets? { definitions.push(Box::new(net)); } } } RefNode::DataDeclaration(n) => { let vars = data_dec(syntax_tree, n, event_iter, url); if let Some(vars) = vars { for var in vars { match var { Declaration::Dec(dec) => definitions.push(Box::new(dec)), Declaration::Import(dec) => definitions.push(Box::new(dec)), Declaration::Scope(scope) => scopes.push(Box::new(scope)), } } } } RefNode::ParameterDeclaration(n) => { let vars = param_dec(syntax_tree, n, event_iter, url); if vars.is_some() { for var in vars? { definitions.push(Box::new(var)); } } } RefNode::LocalParameterDeclaration(n) => { let vars = localparam_dec(syntax_tree, n, event_iter, url); if vars.is_some() { for var in vars? { definitions.push(Box::new(var)); } } } RefNode::FunctionDeclaration(n) => { let dec = function_dec(syntax_tree, n, event_iter, url); if dec.is_some() { scopes.push(Box::new(dec?)); } } RefNode::TaskDeclaration(n) => { let dec = task_dec(syntax_tree, n, event_iter, url); if dec.is_some() { scopes.push(Box::new(dec?)); } } RefNode::ModportDeclaration(n) => { let decs = modport_dec(syntax_tree, n, event_iter, url); if decs.is_some() { for dec in decs? { definitions.push(Box::new(dec)); } } } RefNode::ModuleInstantiation(n) => { let decs = module_inst(syntax_tree, n, event_iter, url); if decs.is_some() { for dec in decs? { definitions.push(Box::new(dec)); } } } RefNode::TextMacroDefinition(n) => { let dec = text_macro_def(syntax_tree, n, event_iter, url); if dec.is_some() { definitions.push(Box::new(dec?)); } } _ => (), } Some((scopes, definitions)) } /// convert the syntax tree to a scope tree /// the root node is the global scope pub fn get_scopes_from_syntax_tree(syntax_tree: &SyntaxTree, url: &Url) -> Option { let mut scopes: Vec> = Vec::new(); let mut global_scope: GenericScope = GenericScope::new(url); global_scope.ident = String::from("global"); let mut event_iter = syntax_tree.into_iter().event(); // iterate over each enter event and extract out any scopes or definitions // match_definitions is recursively called so we get a tree in the end while let Some(event) = event_iter.next() { match event { NodeEvent::Enter(node) => { let mut result = match_definitions(syntax_tree, &mut event_iter, node, url)?; global_scope.defs.append(&mut result.1); scopes.append(&mut result.0); } NodeEvent::Leave(_) => (), } } global_scope.scopes.append(&mut scopes); Some(global_scope) } pub fn get_scopes_from_vhdl_fast(fast: &FastHdlparam, text: &Rope, url: &Url) -> Option { let mut scopes: Vec> = Vec::new(); let mut global_scope: GenericScope = GenericScope::new(url); global_scope.ident = String::from("global"); for module in &fast.content { let mut scope: GenericScope = GenericScope::new(url); scope.ident = module.name.clone(); let module_range = module.range.clone(); scope.start = position_to_byte_idx(text, &module_range.start); scope.end = position_to_byte_idx(text, &module_range.end); scope.byte_idx = scope.start + 7; for parameter in &module.params { let mut def = GenericDec::new(url); def.ident = parameter.name.clone(); let parameter_range = parameter.range.clone(); def.byte_idx = position_to_byte_idx(text, ¶meter_range.start); def.completion_kind = CompletionItemKind::TYPE_PARAMETER; def.symbol_kind = SymbolKind::TYPE_PARAMETER; scope.defs.push(Box::new(def)); } for port in &module.ports { let mut port_def = PortDec::new(url); port_def.ident = port.name.clone(); let port_range = port.range.clone(); port_def.byte_idx = position_to_byte_idx(text, &port_range.start); port_def.type_str = port.dir_type.clone(); scope.defs.push(Box::new(port_def)); } for inst in &module.instances { let mut instance = ModInst::new(url); instance.ident = inst.name.clone(); let inst_range = inst.range.clone(); instance.byte_idx = position_to_byte_idx(text, &inst_range.start); instance.type_str = inst.inst_type.clone(); instance.mod_ident = inst.inst_type.clone(); scope.defs.push(Box::new(instance)); } scopes.push(Box::new(scope)); } global_scope.scopes.append(&mut scopes); Some(global_scope) } fn position_to_byte_idx(text: &Rope, pos: &hdlparam::Position) -> usize { let char = text.line_to_char(pos.line as usize) + pos.character as usize; text.char_to_byte(char) }