合并 vhdl

This commit is contained in:
锦恢 2024-09-30 15:57:03 +08:00
parent ebb4abe1a5
commit fedde4a4d4
4 changed files with 208 additions and 84 deletions

View File

@ -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<DesignFile> {
let path = uri.path();
let path = PathBuf::from_str(path).unwrap();
let path = to_escape_path(&path);
pub fn vhdl_parse(path: &PathBuf) -> Option<DesignFile> {
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<FastHdlparam> {
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<Token>) -> Vec<Module> {

View File

@ -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<Vec<DocumentHighlight>> {
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();

View File

@ -0,0 +1,5 @@
use tower_lsp::lsp_types::*;
pub fn vhdl_document_highlight() -> Option<Vec<DocumentHighlight>> {
None
}

View File

@ -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<RwLock<HashMap<Url, usize>>>,
// file metadata
pub meta: Arc<RwLock<Vec<Arc<RwLock<SourceMeta>>>>>,
// 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<RwLock<Option<GenericScope>>>,
/// 存储 vhdl design file ir 的对象
pub design_file_map: Arc<RwLock<HashMap<String, DesignFile>>>,
// include directories, passed to parser to resolve `include
pub include_dirs: Arc<RwLock<Vec<PathBuf>>>,
// 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<RwLock<Source>>,
scope_handle: &Arc<RwLock<Option<GenericScope>>>,
fast_map_handle: &Arc<RwLock<HashMap<String, FastHdlparam>>>,
doc: &Rope,
uri: &Url,
last_change_range: &Option<Range>,
include_dirs: &Vec<PathBuf>
) {
let path = match PathBuf::from_str(uri.path()) {
Ok(path) => path,
Err(error) => {
info!("error happen in <goto_include_definition>: {:?}", 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<RwLock<HashMap<String, DesignFile>>>,
fast_map_handle: &Arc<RwLock<HashMap<String, FastHdlparam>>>,
uri: &Url
) {
let path = match PathBuf::from_str(uri.path()) {
Ok(path) => path,
Err(error) => {
info!("error happen in <goto_include_definition>: {:?}", 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