232 lines
8.3 KiB
Rust
232 lines
8.3 KiB
Rust
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<Box<dyn Scope>>, Vec<Box<dyn Definition>>)>;
|
|
|
|
/// 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<Box<dyn Definition>> = Vec::new();
|
|
let mut scopes: Vec<Box<dyn Scope>> = 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<GenericScope> {
|
|
let mut scopes: Vec<Box<dyn Scope>> = 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<GenericScope> {
|
|
let mut scopes: Vec<Box<dyn Scope>> = 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)
|
|
}
|