diff --git a/.vscode/lsp.code-snippets b/.vscode/lsp.code-snippets new file mode 100644 index 0000000..334faab --- /dev/null +++ b/.vscode/lsp.code-snippets @@ -0,0 +1,19 @@ +{ + // "Print to console": { + // "scope": "javascript,typescript", + // "prefix": "log", + // "body": [ + // "console.log('$1');", + // "$2" + // ], + // "description": "Log output to console" + // } + "allow unused": { + "scope": "rust", + "prefix": "allowunused", + "body": [ + "#[allow(unused)]" + ], + "description": "#[allow(unused)]" + } +} \ No newline at end of file diff --git a/src/completion/feature.rs b/src/completion/feature.rs index 8e2c6e4..4946cd2 100644 --- a/src/completion/feature.rs +++ b/src/completion/feature.rs @@ -1,11 +1,10 @@ use std::{fs, path::PathBuf, str::FromStr}; use log::info; -use regex::Regex; use ropey::RopeSlice; use tower_lsp::lsp_types::{CompletionItem, CompletionItemKind, CompletionItemLabelDetails, CompletionList, Position, Url}; -use crate::{server::LSPServer, utils::{get_word_range_at_position, resolve_path, to_escape_path}}; +use crate::{server::LSPServer, utils::{resolve_path, to_escape_path}}; pub fn include_path_completion(uri: &Url, line: &RopeSlice, pos: Position) -> Option { let line_text = line.as_str().unwrap_or(""); @@ -144,9 +143,11 @@ fn is_port_completion(line: &RopeSlice, pos: &Position) -> bool { fn get_position_port_param_completion( server: &LSPServer, + #[allow(unused)] line: &RopeSlice, url: &Url, pos: &Position, + #[allow(unused)] language_id: &str ) -> Option { // 判断在不在一个模块内,并获取这个模块 @@ -225,7 +226,7 @@ fn get_position_port_param_completion( None } -fn make_port_desc(port: &crate::core::fast_hdlparam::Port) -> String { +fn make_port_desc(port: &crate::core::hdlparam::Port) -> String { let mut port_desc_array = Vec::::new(); port_desc_array.push(port.dir_type.to_string()); if port.net_type != "unknown" { @@ -245,11 +246,12 @@ fn make_port_desc(port: &crate::core::fast_hdlparam::Port) -> String { port_desc } -fn make_param_desc(param: &crate::core::fast_hdlparam::Parameter) -> String { +fn make_param_desc(param: &crate::core::hdlparam::Parameter) -> String { let mut param_desc_array = Vec::::new(); param_desc_array.push(format!("parameter {}", param.name)); if param.init != "unknown" { + param_desc_array.push("=".to_string()); param_desc_array.push(param.init.to_string()); } diff --git a/src/completion/vhdl.rs b/src/completion/vhdl.rs index e09367a..2456e4e 100644 --- a/src/completion/vhdl.rs +++ b/src/completion/vhdl.rs @@ -65,6 +65,7 @@ pub fn completion(server: &LSPServer, params: &CompletionParams) -> Option CompletionItem { diff --git a/src/core/cache_storage.rs b/src/core/cache_storage.rs new file mode 100644 index 0000000..0ca4134 --- /dev/null +++ b/src/core/cache_storage.rs @@ -0,0 +1,12 @@ +/// 用于进行高效 IR 缓存的模块 + + +#[allow(unused)] +pub fn dump_ir_storage() { + +} + +#[allow(unused)] +pub fn load_ir_storage() { + +} \ No newline at end of file diff --git a/src/core/fast_hdlparam.rs b/src/core/hdlparam.rs similarity index 100% rename from src/core/fast_hdlparam.rs rename to src/core/hdlparam.rs diff --git a/src/core/mod.rs b/src/core/mod.rs index d9427ff..4650153 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -1,7 +1,7 @@ -pub mod fast_hdlparam; -// pub use fast_hdlparam::*; +pub mod hdlparam; pub mod sv_parser; -// pub use sv_parser::*; -pub mod vhdl_parser; \ No newline at end of file +pub mod vhdl_parser; + +pub mod cache_storage; \ No newline at end of file diff --git a/src/core/sv_parser.rs b/src/core/sv_parser.rs index 2f22df5..f60247b 100644 --- a/src/core/sv_parser.rs +++ b/src/core/sv_parser.rs @@ -11,7 +11,7 @@ use sv_parser::{unwrap_node, Locate, RefNode, SyntaxTree}; use crate::sources::recovery_sv_parse; use crate::utils::to_escape_path; -use super::fast_hdlparam::{FastHdlparam, Macro}; +use super::hdlparam::{FastHdlparam, Macro}; #[allow(unused)] pub fn sv_parser(path: &str) -> Option { @@ -86,7 +86,7 @@ pub fn make_fast_from_syntaxtree(syntax_tree: &SyntaxTree, path: &PathBuf) -> Re Some(RefNode::DefaultText(x)) => syntax_tree.get_str(&x.nodes.0).unwrap(), _ => "Unknown" }; - params_vec.push(crate::core::fast_hdlparam::DefineParam { name: param_name.to_string(), value: param_val.to_string() }); + params_vec.push(crate::core::hdlparam::DefineParam { name: param_name.to_string(), value: param_val.to_string() }); } } } @@ -590,7 +590,7 @@ fn get_identifier(node: RefNode) -> Option { } } -fn get_includes(path: &PathBuf) -> Vec { +fn get_includes(path: &PathBuf) -> Vec { let mut includes = Vec::new(); let file = File::open(path).unwrap(); @@ -607,13 +607,13 @@ fn get_includes(path: &PathBuf) -> Vec { let path = parts[1]; let last_character = line_content.find(path).unwrap() + path.len(); - includes.push(crate::core::fast_hdlparam::Include { + includes.push(crate::core::hdlparam::Include { path: path.to_string(), - range: crate::core::fast_hdlparam::Range { - start: crate::core::fast_hdlparam::Position { + range: crate::core::hdlparam::Range { + start: crate::core::hdlparam::Position { line: (line_number + 1) as u32, character: 1 }, - end: crate::core::fast_hdlparam::Position { + end: crate::core::hdlparam::Position { line: (line_number + 1) as u32, character: last_character as u32 } } diff --git a/src/core/vhdl_parser.rs b/src/core/vhdl_parser.rs index 0e8976a..d648720 100644 --- a/src/core/vhdl_parser.rs +++ b/src/core/vhdl_parser.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; use vhdl_lang::ast::DesignFile; use vhdl_lang::{kind_str, Token, VHDLParser, VHDLStandard}; -use super::fast_hdlparam::*; +use super::hdlparam::*; #[allow(unused)] pub fn vhdl_parser(path: &str) -> FastHdlparam { diff --git a/src/definition/feature.rs b/src/definition/feature.rs index 5e5b94b..343cf4c 100644 --- a/src/definition/feature.rs +++ b/src/definition/feature.rs @@ -5,7 +5,7 @@ use regex::Regex; use ropey::RopeSlice; use tower_lsp::lsp_types::{GotoDefinitionResponse, LocationLink, Position, Range, Url}; -use crate::{core::fast_hdlparam::FastHdlparam, server::LSPServer, utils::{get_word_range_at_position, resolve_path, to_escape_path}}; +use crate::{core::hdlparam::FastHdlparam, server::LSPServer, utils::{get_word_range_at_position, resolve_path, to_escape_path}}; /// 跳转到 include 的文件 pub fn goto_include_definition(uri: &Url, line: &RopeSlice, pos: Position) -> Option { diff --git a/src/hover/feature.rs b/src/hover/feature.rs index 1fbc935..58573b7 100644 --- a/src/hover/feature.rs +++ b/src/hover/feature.rs @@ -5,7 +5,7 @@ use regex::Regex; use ropey::RopeSlice; use tower_lsp::lsp_types::{Hover, HoverContents, LanguageString, MarkedString, Position, Range, Url}; -use crate::{core::fast_hdlparam::{Define, FastHdlparam}, server::LSPServer}; +use crate::{core::hdlparam::{Define, FastHdlparam}, server::LSPServer}; use super::{get_word_range_at_position, resolve_path, to_escape_path}; @@ -290,7 +290,7 @@ pub fn hover_position_port_param( None } -fn make_port_desc_hover(port: &crate::core::fast_hdlparam::Port, range: &Range, language_id: &str) -> Hover { +fn make_port_desc_hover(port: &crate::core::hdlparam::Port, range: &Range, language_id: &str) -> Hover { let mut port_desc_array = Vec::::new(); port_desc_array.push(port.dir_type.to_string()); if port.net_type != "unknown" { @@ -317,11 +317,12 @@ fn make_port_desc_hover(port: &crate::core::fast_hdlparam::Port, range: &Range, } } -fn make_param_desc_hover(param: &crate::core::fast_hdlparam::Parameter, range: &Range, language_id: &str) -> Hover { +fn make_param_desc_hover(param: &crate::core::hdlparam::Parameter, range: &Range, language_id: &str) -> Hover { let mut param_desc_array = Vec::::new(); param_desc_array.push(format!("parameter {}", param.name)); if param.init != "unknown" { + param_desc_array.push("=".to_string()); param_desc_array.push(param.init.to_string()); } @@ -394,7 +395,7 @@ pub fn hover_module_declaration( /// 根据 module 获取 module 的简单描述代码 -fn make_module_profile_code(module: &crate::core::fast_hdlparam::Module) -> String { +fn make_module_profile_code(module: &crate::core::hdlparam::Module) -> String { let mut codes = Vec::::new(); let param_num = module.params.len(); let port_num = module.ports.len(); diff --git a/src/request/mod.rs b/src/request/mod.rs index e6ce8be..b106c97 100644 --- a/src/request/mod.rs +++ b/src/request/mod.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; +use std::str::FromStr; use std::{fs, future}; use std::path::PathBuf; use std::sync::Arc; @@ -9,9 +11,10 @@ use serde::{Deserialize, Serialize}; use tower_lsp::jsonrpc::Result; use tower_lsp::lsp_types::*; -use crate::core::fast_hdlparam::FastHdlparam; +use crate::core::hdlparam::FastHdlparam; use crate::core::sv_parser::make_fast_from_syntaxtree; +use crate::core::vhdl_parser::{make_fast_from_design_file, vhdl_parse}; use crate::utils::*; use crate::server::{Backend, GLOBAL_BACKEND}; use crate::sources::recovery_sv_parse; @@ -85,9 +88,22 @@ fn make_textdocumenitem_from_path(path_buf: &PathBuf) -> Option(path: String, _server: &Arc) -> Result { +pub fn do_fast<'a>(path: String, backend: &Arc) -> Result { info!("parse fast {}", path); + + let language_id = get_language_id_by_path_str(&path); + match language_id.as_str() { + "vhdl" => do_vhdl_fast(&path, backend), + "verilog" | "systemverilog" => do_sv_fast(&path, backend), + _ => Err(tower_lsp::jsonrpc::Error { + code: tower_lsp::jsonrpc::ErrorCode::InvalidRequest, + message: Cow::Owned(format!("invalid file: {path}, expect vhdl, verilog or system verilog!")), + data: None + }) + } +} +fn do_sv_fast(path: &str, backend: &Arc) -> Result { let path_buf = PathBuf::from(&path); let doc = match make_textdocumenitem_from_path(&path_buf) { @@ -95,7 +111,7 @@ pub fn do_fast<'a>(path: String, _server: &Arc) -> Result { let api_error = tower_lsp::jsonrpc::Error { code: tower_lsp::jsonrpc::ErrorCode::InvalidParams, - message: std::borrow::Cow::Owned(format!("cannot make doc from path : {path}")), + message: Cow::Owned(format!("cannot make doc from path : {path}")), data: None }; @@ -115,27 +131,42 @@ pub fn do_fast<'a>(path: String, _server: &Arc) -> Result) -> Result { + let sources = &backend.server.srcs; + let pathbuf = PathBuf::from_str(path).unwrap(); + if let Some(design_file) = vhdl_parse(&pathbuf) { + let hdl_param = sources.hdl_param.clone(); + if let Some(fast) = make_fast_from_design_file(&design_file) { + hdl_param.update_fast(path.to_string(), fast.clone()); + return Ok(fast); + } + } + + Err(tower_lsp::jsonrpc::Error { + code: tower_lsp::jsonrpc::ErrorCode::ParseError, + message: Cow::Owned(format!("error happen when parse {path} in [do_vhdl_fast]")), + data: None + }) } - // 下面是服务端发送给客户端的 - #[derive(Serialize, Deserialize)] pub struct StringNotification { pub content: String diff --git a/src/sources.rs b/src/sources.rs index 7f60bbf..77f54f1 100644 --- a/src/sources.rs +++ b/src/sources.rs @@ -1,4 +1,4 @@ -use crate::core::fast_hdlparam::HdlParam; +use crate::core::hdlparam::HdlParam; use crate::core::sv_parser::make_fast_from_syntaxtree; use crate::core::vhdl_parser::make_fast_from_design_file; use crate::core::vhdl_parser::vhdl_parse; diff --git a/src/utils/fast.rs b/src/utils/fast.rs index 9a02b63..babafd6 100644 --- a/src/utils/fast.rs +++ b/src/utils/fast.rs @@ -1,5 +1,5 @@ -use crate::{core::fast_hdlparam::Define, server::LSPServer}; +use crate::{core::hdlparam::Define, server::LSPServer}; impl LSPServer { /// 根据输入的 macro 名字,寻找 fast 中存在的第一个 macro diff --git a/src/utils/file.rs b/src/utils/file.rs index dc529ff..ac4fcf7 100644 --- a/src/utils/file.rs +++ b/src/utils/file.rs @@ -1,4 +1,4 @@ -use std::{fs, path::PathBuf, str::FromStr}; +use std::{fs, path::PathBuf}; use log::info; use ropey::Rope; diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 2d83b0c..c38e2ec 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -79,6 +79,8 @@ pub fn get_word_range_at_position(line: &RopeSlice, pos: Position, regex: Regex) } /// 根据 uri 获取 hdl 的 language id +/// 返回值为 "vhdl" | "verilog" | "systemverilog" | "plaintext" +/// 不采用枚举是因为需要在 lsp 中使用到它们的字符串值 pub fn get_language_id_by_uri(uri: &Url) -> String { let path = uri.path(); let ext_name = std::path::Path::new(path) @@ -86,13 +88,28 @@ pub fn get_language_id_by_uri(uri: &Url) -> String { .and_then(std::ffi::OsStr::to_str) .unwrap_or(""); + get_language_id_by_extname(ext_name) +} + +/// 根据路径字符串获取 hdl 的 language id +/// 返回值为 "vhdl" | "verilog" | "systemverilog" | "plaintext" +/// 不采用枚举是因为需要在 lsp 中使用到它们的字符串值 +pub fn get_language_id_by_path_str(path_str: &str) -> String { + let ext_name = std::path::Path::new(path_str) + .extension() + .and_then(std::ffi::OsStr::to_str) + .unwrap_or(""); + get_language_id_by_extname(ext_name) +} + +fn get_language_id_by_extname(ext_name: &str) -> String { match ext_name { "vhd" | "vhdl" | "vho" | "vht" => "vhdl".to_string(), "v" | "V" | "vh" | "vl" => "verilog".to_string(), "sv" | "svh" => "systemverilog".to_string(), _ => "plaintext".to_string() } -} +} /// 根据基础路径和给出的 path 路径,计算出绝对路径 ///