From f055b2bbc37697e90127902aeae548f5f80ade10 Mon Sep 17 00:00:00 2001 From: LSTM-Kirigaya <1193466151@qq.com> Date: Mon, 11 Nov 2024 02:06:41 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AF=B9=E4=BA=8E=20xilinx?= =?UTF-8?q?=20IP=20=E7=9A=84=20entity=20=E5=86=85=E9=83=A8=20port=20?= =?UTF-8?q?=E7=9A=84=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/vhdl_parser.rs | 39 +++++++++++++++++++--------- src/hover/feature.rs | 57 +++++++++++++++++++++++++++++++++++++++-- src/request/mod.rs | 56 +++++++++++++++++++++++----------------- src/server.rs | 2 +- 4 files changed, 115 insertions(+), 39 deletions(-) diff --git a/src/core/vhdl_parser.rs b/src/core/vhdl_parser.rs index 8a25380..e4a3f51 100644 --- a/src/core/vhdl_parser.rs +++ b/src/core/vhdl_parser.rs @@ -1,5 +1,6 @@ use std::collections::HashSet; use std::path::PathBuf; +use log::info; use vhdl_lang::ast::DesignFile; use vhdl_lang::{kind_str, Token, VHDLParser, VHDLStandard}; @@ -67,7 +68,6 @@ pub fn make_fast_from_design_file(design_file: &DesignFile) -> Option) -> Vec { let mut modules = Vec::new(); let mut last_module_name = String::new(); @@ -81,24 +81,31 @@ fn parse_tokens(tokens: Vec) -> Vec { let start_pos = tokens[i].pos.range.start; i += 1; let entity_name = get_value(&tokens[i]); - // println!("entity name {:?}", entity_name); - if (i >= 2 as usize) && (kind_str(tokens[i-2].kind) != "use") || (i < 2) { + + if (i >= 2 as usize) && (kind_str(tokens[i - 2].kind) != "use") || (i < 2) { + // 遍历整个 entity 内部的 token,找到结束的 token 和代表 port 的 token let mut end = i; + let mut port_begin: usize = 0; while ( - end+1 < tokens.len()) && + end + 1 < tokens.len()) && !(kind_str(tokens[end].kind) == "end" && - (kind_str(tokens[end+1].kind) == "entity" || get_value(&tokens[end+1]) == entity_name)) { + (kind_str(tokens[end + 1].kind) == "entity" || get_value(&tokens[end + 1]) == entity_name) + ) { + if kind_str(tokens[end].kind) == "port" { + port_begin = end; + } end += 1; } - let end_pos = if end+1 < tokens.len() && get_value(&tokens[end+1]) == entity_name { - i = end + 1; - tokens[end+2].pos.range.end + + let (next_i, end_pos) = if end + 1 < tokens.len() && get_value(&tokens[end + 1]) == entity_name { + (end + 1, tokens[end + 2].pos.range.end) } else if end + 3 < tokens.len() { - i = end + 2; - tokens[end+3].pos.range.end + (end + 2, tokens[end + 3].pos.range.end) } else { - tokens[end].pos.range.end + (i, tokens[end].pos.range.end) }; + + // 创建一个空的 module 并标记上 last_module_name let module = Module { name: entity_name.to_string(), params: Vec::new(), @@ -117,6 +124,14 @@ fn parse_tokens(tokens: Vec) -> Vec { }; last_module_name = entity_name.to_string(); modules.push(module); + + // 如果内部含有 port,则不能直接跳过,否则直接跳过 + if port_begin > 0 { + i = port_begin; + continue; + } else { + i = next_i; + } } } "architecture" => { @@ -289,7 +304,7 @@ fn parse_tokens(tokens: Vec) -> Vec { let start = params.first().unwrap().range.start.clone(); let end = params.last().unwrap().range.start.clone(); if let Some(module) = modules.iter_mut().find(|module| module.name == last_module_name) { - module.instances.last_mut().unwrap().instparams = Some(Range { start, end });; + module.instances.last_mut().unwrap().instparams = Some(Range { start, end }); } } else { if let Some(module) = modules.iter_mut().find(|module| module.name == last_module_name) { diff --git a/src/hover/feature.rs b/src/hover/feature.rs index d43ffa8..9226287 100644 --- a/src/hover/feature.rs +++ b/src/hover/feature.rs @@ -322,7 +322,7 @@ pub fn hover_module_declaration( #[allow(unused)] language_id: &str ) -> Option { - // info!("token: {:?}, module info: {:?}", token_name, module_info); + // info!("hover_module_declaration token: {:?}", token_name); // let test = server.srcs.hdl_param.module_name_to_path.read().unwrap(); // info!("module name to path: {:#?}", test); @@ -429,7 +429,60 @@ fn hover_ip_module_declaration( #[allow(unused)] def_path: &str ) -> Option { - None + let def_path_buf = PathBuf::from_str(def_path).unwrap(); + + if def_path_buf.exists() { + // TODO: 当前工具链只支持 Xilinx 下的工具链,所以此处的代码是 vhdl 的代码 + let path_uri = Url::from_file_path(def_path.to_string()).unwrap().to_string(); + let def_row = module.range.start.line; + let def_col = module.range.start.character; + let define_info = format!("Go to [Definition]({path_uri}#L{def_row}:{def_col})"); + + let port_num = module.ports.len(); + let param_num = module.params.len(); + let instance_num = module.instances.len(); + + let port_desc = format!("`port` {port_num}, `generic` {param_num}, `instantiation` {instance_num}"); + + // 统计 dir + let mut input_count = 0 as u32; + let mut output_count = 0 as u32; + let mut inout_count = 0 as u32; + + for port in &module.ports { + match port.dir_type.as_str() { + "input" => input_count += 1, + "output" => output_count += 1, + "inout" => inout_count += 1, + _ => {} + } + } + + let io_desc = format!("`input` {input_count}, `output` {output_count}, `inout` {inout_count}"); + + let mut markdowns = Vec::::new(); + markdowns.push(MarkedString::String(port_desc)); + markdowns.push(MarkedString::String(io_desc)); + markdowns.push(MarkedString::String(define_info)); + markdowns.push(MarkedString::String("---".to_string())); + + let language_id = get_language_id_by_path_str(def_path); + let module_profile = make_module_profile_code(&module); + let profile_markdown = LanguageString { + language: language_id.to_string(), + value: module_profile + }; + markdowns.push(MarkedString::LanguageString(profile_markdown)); + + let hover = Hover { + contents: HoverContents::Array(markdowns), + range: None + }; + + Some(hover) + } else { + None + } } fn hover_primitives_module_declaration( diff --git a/src/request/mod.rs b/src/request/mod.rs index d41fbc4..bfe0256 100644 --- a/src/request/mod.rs +++ b/src/request/mod.rs @@ -227,38 +227,46 @@ fn do_vhdl_fast( // TODO: 支持对于 synth 下的 vhdl 文件的解析,从而提供更加丰富的 IP 支持 if file_type == "ip" { match tool_chain { + // 此时的 pathbuf 类似 {ip_name}/synth/{ip_name}.vhd "xilinx" => { - let ip_name = pathbuf.file_name().unwrap().to_str().unwrap(); - let ip_name = ip_name.strip_suffix(".vhd").unwrap(); - info!("get ip_name: {}", ip_name); - let fake_content = vec![ - core::hdlparam::Module { - name: ip_name.to_string(), - params: vec![], - ports: vec![], - instances: vec![], - range: core::hdlparam::Range::default() - } - ]; - let ip_fast = core::hdlparam::FastHdlparam { - fast_macro: core::hdlparam::Macro { - includes: vec![], - defines: vec![], - errors: vec![], - invalid: vec![] - }, - file_type: "ip".to_string(), - content: fake_content - }; - hdl_param.update_fast(path.to_string(), ip_fast.clone()); - return Ok(ip_fast); + // 如果 ip 描述文件存在,则解析它,否则,创建空的写入 + // IP 描述文件一般都不会很大,所以不需要缓存 + if !pathbuf.exists() { + let ip_name = pathbuf.file_name().unwrap().to_str().unwrap(); + let ip_name = ip_name.strip_suffix(".vhd").unwrap(); + let fake_content = vec![ + core::hdlparam::Module { + name: ip_name.to_string(), + params: vec![], + ports: vec![], + instances: vec![], + range: core::hdlparam::Range::default() + } + ]; + let ip_fast = core::hdlparam::FastHdlparam { + fast_macro: core::hdlparam::Macro { + includes: vec![], + defines: vec![], + errors: vec![], + invalid: vec![] + }, + file_type: "ip".to_string(), + content: fake_content + }; + hdl_param.update_fast(path.to_string(), ip_fast.clone()); + return Ok(ip_fast); + } }, _ => {} } } + // 没有特殊情况,则正常解析并写入 if let Some(design_file) = vhdl_parse(&pathbuf) { if let Some(mut fast) = make_fast_from_design_file(&design_file) { + if path.contains("ip") { + info!("vhdl fast: {:?}", fast); + } fast.file_type = file_type.to_string(); hdl_param.update_fast(path.to_string(), fast.clone()); return Ok(fast); diff --git a/src/server.rs b/src/server.rs index f6c299d..52b21d2 100644 --- a/src/server.rs +++ b/src/server.rs @@ -230,7 +230,7 @@ impl LanguageServer for Backend { self.client .log_message(MessageType::INFO, "Digital LSP initialized!") .await; - + // self.client.send_notification::(StringNotification { content: "hello from lsp server".to_string() }).await; }