合并 vhdl
This commit is contained in:
parent
ebb4abe1a5
commit
fedde4a4d4
@ -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> {
|
||||
|
@ -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,32 +18,61 @@ 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()?;
|
||||
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)
|
||||
.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);
|
||||
|
||||
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)> {
|
||||
|
5
src/document_highlight/vhdl.rs
Normal file
5
src/document_highlight/vhdl.rs
Normal file
@ -0,0 +1,5 @@
|
||||
use tower_lsp::lsp_types::*;
|
||||
|
||||
pub fn vhdl_document_highlight() -> Option<Vec<DocumentHighlight>> {
|
||||
None
|
||||
}
|
181
src/sources.rs
181
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<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" | "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;
|
||||
}
|
||||
|
||||
pub fn vhdl_parser_pipeline() {
|
||||
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(
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user