diff --git a/src/core/vhdl_parser.rs b/src/core/vhdl_parser.rs index 6a132da..0e8976a 100644 --- a/src/core/vhdl_parser.rs +++ b/src/core/vhdl_parser.rs @@ -1,9 +1,7 @@ -use std::{collections::HashSet, str::FromStr}; +use std::collections::HashSet; use std::path::PathBuf; -use tower_lsp::lsp_types::Url; use vhdl_lang::ast::DesignFile; use vhdl_lang::{kind_str, Token, VHDLParser, VHDLStandard}; -use crate::utils::to_escape_path; use super::fast_hdlparam::*; @@ -36,19 +34,36 @@ pub fn vhdl_parser(path: &str) -> FastHdlparam { } -pub fn vhdl_parse(uri: &Url) -> Option { - let path = uri.path(); - let path = PathBuf::from_str(path).unwrap(); - let path = to_escape_path(&path); +pub fn vhdl_parse(path: &PathBuf) -> Option { let mut diagnostics = Vec::new(); let parser = VHDLParser::new(VHDLStandard::VHDL2008); - if let Ok((_, design_file)) = parser.parse_design_file(&path, &mut diagnostics) { + if let Ok((_, design_file)) = parser.parse_design_file(path, &mut diagnostics) { return Some(design_file); } None } +pub fn make_fast_from_design_file(design_file: &DesignFile) -> Option { + let mut hdlparam = FastHdlparam { + fast_macro: Macro { + defines: Vec::new(), + errors: Vec::new(), + includes: Vec::new(), + invalid: Vec::new() + }, + content: Vec::new() + }; + + let mut all_tockens = Vec::new(); + for (tokens, _) in &design_file.design_units { + all_tockens.extend(tokens.clone()); + } + + hdlparam.content.extend(parse_tokens(all_tockens)); + Some(hdlparam) +} + #[allow(unused)] fn parse_tokens(tokens: Vec) -> Vec { diff --git a/src/document_highlight/mod.rs b/src/document_highlight/mod.rs index 44b8393..ea9f358 100644 --- a/src/document_highlight/mod.rs +++ b/src/document_highlight/mod.rs @@ -1,8 +1,12 @@ -use crate::{definition::Scope, server::LSPServer, sources::LSPSupport, utils::{get_definition_token, get_language_id_by_uri}}; +use crate::{definition::Scope, server::LSPServer, sources::{LSPSupport, ParseIR, Source}, utils::{get_definition_token, get_language_id_by_uri}}; +use log::info; use sv_parser::{RefNode, SyntaxTree}; +use vhdl::vhdl_document_highlight; use crate::definition::extract_defs::get_ident; use tower_lsp::lsp_types::*; +pub mod vhdl; + impl LSPServer { pub fn document_highlight( &self, @@ -14,33 +18,62 @@ impl LSPServer { self.srcs.wait_parse_ready(file_id, false); let file = self.srcs.get_file(file_id)?; let file = file.read().ok()?; - let line_text = file.text.line(pos.line as usize); let token = get_definition_token(&line_text, pos); let language_id = get_language_id_by_uri(&uri); - let scope_tree = self.srcs.scope_tree.read().ok()?; - // use the byte_idx of the definition if possible, otherwise use the cursor - let byte_idx = - match scope_tree - .as_ref()? - .get_definition(&token, file.text.pos_to_byte(&pos), &uri) - { - Some(def) => def.byte_idx, - None => file.text.pos_to_byte(&pos), - }; - let syntax_tree = file.syntax_tree.as_ref()?; - let references = all_identifiers(syntax_tree, &token); - - Some( - scope_tree - .as_ref()? - .document_highlights(&uri, &file.text, references, byte_idx), - ) + match language_id.as_str() { + "vhdl" => vhdl_document_highlight(), + "verilog" | "systemverilog" => sv_document_highlight( + self, + &token, + &file, + pos, + &uri + ), + _ => None + } } } +fn sv_document_highlight( + server: &LSPServer, + token: &str, + file: &Source, + pos: Position, + uri: &Url +) -> Option> { + let scope_tree = server.srcs.scope_tree.read().ok()?; + + // use the byte_idx of the definition if possible, otherwise use the cursor + let byte_idx = + match scope_tree + .as_ref()? + .get_definition(token, file.text.pos_to_byte(&pos), uri) + { + Some(def) => def.byte_idx, + None => file.text.pos_to_byte(&pos), + }; + let syntax_tree = file.parse_ir.as_ref()?; + match syntax_tree { + ParseIR::SyntaxTree(syntax_tree) => { + let references = all_identifiers(&syntax_tree, &token); + Some( + scope_tree + .as_ref()? + .document_highlights(&uri, &file.text, references, byte_idx), + ) + }, + _ => { + info!("error happen in [sv_document_highlight]"); + None + } + } +} + + + /// return all identifiers in a syntax tree matching a given token fn all_identifiers(syntax_tree: &SyntaxTree, token: &str) -> Vec<(String, usize)> { let mut idents: Vec<(String, usize)> = Vec::new(); diff --git a/src/document_highlight/vhdl.rs b/src/document_highlight/vhdl.rs new file mode 100644 index 0000000..6eeca88 --- /dev/null +++ b/src/document_highlight/vhdl.rs @@ -0,0 +1,5 @@ +use tower_lsp::lsp_types::*; + +pub fn vhdl_document_highlight() -> Option> { + None +} \ No newline at end of file diff --git a/src/sources.rs b/src/sources.rs index 1e074ac..223914a 100644 --- a/src/sources.rs +++ b/src/sources.rs @@ -1,13 +1,18 @@ use crate::core::fast_hdlparam::FastHdlparam; +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; use crate::definition::def_types::*; use crate::definition::get_scopes_from_syntax_tree; use crate::diagnostics::{get_diagnostics, is_hidden}; use crate::server::LSPServer; +use crate::utils::to_escape_path; #[allow(unused)] use log::info; use log::{debug, error}; use pathdiff::diff_paths; use ropey::{Rope, RopeSlice}; +use vhdl_lang::ast::DesignFile; use std::cmp::min; use std::collections::HashMap; use std::env::current_dir; @@ -16,6 +21,7 @@ use std::fs; use std::ops::Deref; use std::ops::Range as StdRange; use std::path::PathBuf; +use std::str::FromStr; use std::sync::{Arc, Condvar, Mutex, RwLock}; use std::thread; use sv_parser::*; @@ -167,10 +173,10 @@ pub struct Sources { pub names: Arc>>, // file metadata pub meta: Arc>>>>, - // all source files are indexed into this tree, which can then - - // be used for completion, name resolution + /// scope tree 类型的树形结构,用于提供 sv 的 lsp pub scope_tree: Arc>>, + /// 存储 vhdl design file ir 的对象 + pub design_file_map: Arc>>, // include directories, passed to parser to resolve `include pub include_dirs: Arc>>, // source directories @@ -192,6 +198,7 @@ impl Sources { names: Arc::new(RwLock::new(HashMap::new())), meta: Arc::new(RwLock::new(Vec::new())), scope_tree: Arc::new(RwLock::new(None)), + design_file_map: Arc::new(RwLock::new(HashMap::new())), include_dirs: Arc::new(RwLock::new(Vec::new())), source_dirs: Arc::new(RwLock::new(Vec::new())), fast_map: Arc::new(RwLock::new(HashMap::new())) @@ -240,6 +247,8 @@ impl Sources { })); let source_handle = source.clone(); let scope_handle = self.scope_tree.clone(); + let design_file_handle = self.design_file_map.clone(); + let fast_map_handle = self.fast_map.clone(); let inc_dirs = self.include_dirs.clone(); info!("launch worker to parse {:?}", doc.uri.to_string()); @@ -255,64 +264,30 @@ impl Sources { let range = &file.last_change_range.clone(); drop(file); - info!("do parse in {:?}", uri.to_string()); - - + info!("do parse in {:?}, language_id: {:?}", uri.to_string(), language_id); match language_id.as_str() { "vhdl" => { - + vhdl_parser_pipeline( + &design_file_handle, + &fast_map_handle, + uri, + ); }, - "verilog" | "system verilog" => { - + "verilog" | "systemverilog" => { + sv_parser_pipeline( + &source_handle, + &scope_handle, + &fast_map_handle, + &text, + uri, + range, + &inc_dirs.read().unwrap() + ); }, _ => {} } - let syntax_tree = recovery_sv_parse(&text, uri, range, &inc_dirs.read().unwrap()); - - let mut scope_tree = match &syntax_tree { - Some(tree) => get_scopes_from_syntax_tree(tree, uri), - None => None, - }; - - info!("finish parse {:?}", uri.to_string()); - - let mut file = source_handle.write().unwrap(); - - // 加入语法树 - if let Some(syntax_tree) = syntax_tree { - let parse_ir = ParseIR::SyntaxTree(syntax_tree); - file.parse_ir = Some(parse_ir); - } else { - file.parse_ir = None; - } - // file.syntax_tree = syntax_tree; - drop(file); - - // 更新 global_scope,用于 sv 的解析 - // global_scope 为全局最大的那个 scope,它的 scopes 和 defs 下的元素和每一个文件一一对应 - let mut global_scope = scope_handle.write().unwrap(); - match &mut *global_scope { - Some(scope) => match &mut scope_tree { - Some(tree) => { - // 更新所有 uri 为当前 uri 的文件结构 - scope.defs.retain(|x| &x.url() != uri); - scope.scopes.retain(|x| &x.url() != uri); - - scope.defs.append(&mut tree.defs); - scope.scopes.append(&mut tree.scopes); - - } - None => (), - }, - // 使用 scope_tree 来更新全局的 scope - None => *global_scope = scope_tree, - } - // eprintln!("{:#?}", *global_scope); - drop(global_scope); - - // 通过条件锁进行控制 let mut valid = lock.lock().unwrap(); *valid = true; @@ -514,12 +489,108 @@ pub fn recovery_sv_parse( } -pub fn sv_parser_pipeline() { +pub fn sv_parser_pipeline( + source_handle: &Arc>, + scope_handle: &Arc>>, + fast_map_handle: &Arc>>, + doc: &Rope, + uri: &Url, + last_change_range: &Option, + include_dirs: &Vec +) { + let path = match PathBuf::from_str(uri.path()) { + Ok(path) => path, + Err(error) => { + info!("error happen in : {:?}", error); + return; + } + }; + let escape_path = to_escape_path(&path); + let escape_path_string = escape_path.to_str().unwrap_or(""); + if escape_path_string.len() == 0 { + info!("error happen in [sv_parser_pipeline], escape_path_string is empty"); + return; + } + let syntax_tree = recovery_sv_parse( + doc, + uri, + last_change_range, + include_dirs + ); + + // 更新 scope tree + let mut scope_tree = match &syntax_tree { + Some(tree) => get_scopes_from_syntax_tree(tree, uri), + None => None, + }; + + info!("finish parse {:?}", uri.to_string()); + + let mut file = source_handle.write().unwrap(); + + // 加入语法树 & 更新 fast + if let Some(syntax_tree) = syntax_tree { + if let Ok(hdlparam) = make_fast_from_syntaxtree(&syntax_tree, &escape_path) { + let mut fast_map = fast_map_handle.write().unwrap(); + fast_map.insert(escape_path_string.to_string(), hdlparam); + } + let parse_ir = ParseIR::SyntaxTree(syntax_tree); + file.parse_ir = Some(parse_ir); + } else { + file.parse_ir = None; + } + // file.syntax_tree = syntax_tree; + drop(file); + + // 更新 global_scope,用于 sv 的解析 + // global_scope 为全局最大的那个 scope,它的 scopes 和 defs 下的元素和每一个文件一一对应 + let mut global_scope = scope_handle.write().unwrap(); + match &mut *global_scope { + Some(scope) => match &mut scope_tree { + Some(tree) => { + // 更新所有 uri 为当前 uri 的文件结构 + scope.defs.retain(|x| &x.url() != uri); + scope.scopes.retain(|x| &x.url() != uri); + + scope.defs.append(&mut tree.defs); + scope.scopes.append(&mut tree.scopes); + } + None => (), + }, + // 使用 scope_tree 来更新全局的 scope + None => *global_scope = scope_tree, + } + // eprintln!("{:#?}", *global_scope); + drop(global_scope); } -pub fn vhdl_parser_pipeline() { - +pub fn vhdl_parser_pipeline( + design_file_handle: &Arc>>, + fast_map_handle: &Arc>>, + uri: &Url +) { + let path = match PathBuf::from_str(uri.path()) { + Ok(path) => path, + Err(error) => { + info!("error happen in : {:?}", error); + return; + } + }; + let escape_path = to_escape_path(&path); + let escape_path_string = escape_path.to_str().unwrap_or(""); + if escape_path_string.len() == 0 { + info!("error happen in [vhdl_parser_pipeline], escape_path_string is empty"); + return; + } + if let Some(design_file) = vhdl_parse(&escape_path) { + let mut design_files = design_file_handle.write().unwrap(); + if let Some(hdlparam) = make_fast_from_design_file(&design_file) { + let mut fast_map = fast_map_handle.write().unwrap(); + fast_map.insert(escape_path_string.to_string(), hdlparam); + } + design_files.insert(escape_path_string.to_string(), design_file); + } } //TODO: add bounds checking for utf8<->utf16 conversions