合并 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 std::path::PathBuf;
|
||||||
use tower_lsp::lsp_types::Url;
|
|
||||||
use vhdl_lang::ast::DesignFile;
|
use vhdl_lang::ast::DesignFile;
|
||||||
use vhdl_lang::{kind_str, Token, VHDLParser, VHDLStandard};
|
use vhdl_lang::{kind_str, Token, VHDLParser, VHDLStandard};
|
||||||
use crate::utils::to_escape_path;
|
|
||||||
|
|
||||||
use super::fast_hdlparam::*;
|
use super::fast_hdlparam::*;
|
||||||
|
|
||||||
@ -36,19 +34,36 @@ pub fn vhdl_parser(path: &str) -> FastHdlparam {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn vhdl_parse(uri: &Url) -> Option<DesignFile> {
|
pub fn vhdl_parse(path: &PathBuf) -> Option<DesignFile> {
|
||||||
let path = uri.path();
|
|
||||||
let path = PathBuf::from_str(path).unwrap();
|
|
||||||
let path = to_escape_path(&path);
|
|
||||||
let mut diagnostics = Vec::new();
|
let mut diagnostics = Vec::new();
|
||||||
let parser = VHDLParser::new(VHDLStandard::VHDL2008);
|
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);
|
return Some(design_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
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)]
|
#[allow(unused)]
|
||||||
fn parse_tokens(tokens: Vec<Token>) -> Vec<Module> {
|
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 sv_parser::{RefNode, SyntaxTree};
|
||||||
|
use vhdl::vhdl_document_highlight;
|
||||||
use crate::definition::extract_defs::get_ident;
|
use crate::definition::extract_defs::get_ident;
|
||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp::lsp_types::*;
|
||||||
|
|
||||||
|
pub mod vhdl;
|
||||||
|
|
||||||
impl LSPServer {
|
impl LSPServer {
|
||||||
pub fn document_highlight(
|
pub fn document_highlight(
|
||||||
&self,
|
&self,
|
||||||
@ -14,33 +18,62 @@ impl LSPServer {
|
|||||||
self.srcs.wait_parse_ready(file_id, false);
|
self.srcs.wait_parse_ready(file_id, false);
|
||||||
let file = self.srcs.get_file(file_id)?;
|
let file = self.srcs.get_file(file_id)?;
|
||||||
let file = file.read().ok()?;
|
let file = file.read().ok()?;
|
||||||
|
|
||||||
let line_text = file.text.line(pos.line as usize);
|
let line_text = file.text.line(pos.line as usize);
|
||||||
let token = get_definition_token(&line_text, pos);
|
let token = get_definition_token(&line_text, pos);
|
||||||
|
|
||||||
let language_id = get_language_id_by_uri(&uri);
|
let language_id = get_language_id_by_uri(&uri);
|
||||||
|
|
||||||
let scope_tree = self.srcs.scope_tree.read().ok()?;
|
match language_id.as_str() {
|
||||||
// use the byte_idx of the definition if possible, otherwise use the cursor
|
"vhdl" => vhdl_document_highlight(),
|
||||||
let byte_idx =
|
"verilog" | "systemverilog" => sv_document_highlight(
|
||||||
match scope_tree
|
self,
|
||||||
.as_ref()?
|
&token,
|
||||||
.get_definition(&token, file.text.pos_to_byte(&pos), &uri)
|
&file,
|
||||||
{
|
pos,
|
||||||
Some(def) => def.byte_idx,
|
&uri
|
||||||
None => file.text.pos_to_byte(&pos),
|
),
|
||||||
};
|
_ => None
|
||||||
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),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
/// return all identifiers in a syntax tree matching a given token
|
||||||
fn all_identifiers(syntax_tree: &SyntaxTree, token: &str) -> Vec<(String, usize)> {
|
fn all_identifiers(syntax_tree: &SyntaxTree, token: &str) -> Vec<(String, usize)> {
|
||||||
let mut idents: Vec<(String, usize)> = Vec::new();
|
let mut idents: Vec<(String, usize)> = Vec::new();
|
||||||
|
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
|
||||||
|
}
|
183
src/sources.rs
183
src/sources.rs
@ -1,13 +1,18 @@
|
|||||||
use crate::core::fast_hdlparam::FastHdlparam;
|
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::def_types::*;
|
||||||
use crate::definition::get_scopes_from_syntax_tree;
|
use crate::definition::get_scopes_from_syntax_tree;
|
||||||
use crate::diagnostics::{get_diagnostics, is_hidden};
|
use crate::diagnostics::{get_diagnostics, is_hidden};
|
||||||
use crate::server::LSPServer;
|
use crate::server::LSPServer;
|
||||||
|
use crate::utils::to_escape_path;
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use log::info;
|
use log::info;
|
||||||
use log::{debug, error};
|
use log::{debug, error};
|
||||||
use pathdiff::diff_paths;
|
use pathdiff::diff_paths;
|
||||||
use ropey::{Rope, RopeSlice};
|
use ropey::{Rope, RopeSlice};
|
||||||
|
use vhdl_lang::ast::DesignFile;
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::env::current_dir;
|
use std::env::current_dir;
|
||||||
@ -16,6 +21,7 @@ use std::fs;
|
|||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::ops::Range as StdRange;
|
use std::ops::Range as StdRange;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::str::FromStr;
|
||||||
use std::sync::{Arc, Condvar, Mutex, RwLock};
|
use std::sync::{Arc, Condvar, Mutex, RwLock};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use sv_parser::*;
|
use sv_parser::*;
|
||||||
@ -167,10 +173,10 @@ pub struct Sources {
|
|||||||
pub names: Arc<RwLock<HashMap<Url, usize>>>,
|
pub names: Arc<RwLock<HashMap<Url, usize>>>,
|
||||||
// file metadata
|
// file metadata
|
||||||
pub meta: Arc<RwLock<Vec<Arc<RwLock<SourceMeta>>>>>,
|
pub meta: Arc<RwLock<Vec<Arc<RwLock<SourceMeta>>>>>,
|
||||||
// all source files are indexed into this tree, which can then
|
/// scope tree 类型的树形结构,用于提供 sv 的 lsp
|
||||||
|
|
||||||
// be used for completion, name resolution
|
|
||||||
pub scope_tree: Arc<RwLock<Option<GenericScope>>>,
|
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
|
// include directories, passed to parser to resolve `include
|
||||||
pub include_dirs: Arc<RwLock<Vec<PathBuf>>>,
|
pub include_dirs: Arc<RwLock<Vec<PathBuf>>>,
|
||||||
// source directories
|
// source directories
|
||||||
@ -192,6 +198,7 @@ impl Sources {
|
|||||||
names: Arc::new(RwLock::new(HashMap::new())),
|
names: Arc::new(RwLock::new(HashMap::new())),
|
||||||
meta: Arc::new(RwLock::new(Vec::new())),
|
meta: Arc::new(RwLock::new(Vec::new())),
|
||||||
scope_tree: Arc::new(RwLock::new(None)),
|
scope_tree: Arc::new(RwLock::new(None)),
|
||||||
|
design_file_map: Arc::new(RwLock::new(HashMap::new())),
|
||||||
include_dirs: Arc::new(RwLock::new(Vec::new())),
|
include_dirs: Arc::new(RwLock::new(Vec::new())),
|
||||||
source_dirs: Arc::new(RwLock::new(Vec::new())),
|
source_dirs: Arc::new(RwLock::new(Vec::new())),
|
||||||
fast_map: Arc::new(RwLock::new(HashMap::new()))
|
fast_map: Arc::new(RwLock::new(HashMap::new()))
|
||||||
@ -240,6 +247,8 @@ impl Sources {
|
|||||||
}));
|
}));
|
||||||
let source_handle = source.clone();
|
let source_handle = source.clone();
|
||||||
let scope_handle = self.scope_tree.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();
|
let inc_dirs = self.include_dirs.clone();
|
||||||
|
|
||||||
info!("launch worker to parse {:?}", doc.uri.to_string());
|
info!("launch worker to parse {:?}", doc.uri.to_string());
|
||||||
@ -255,64 +264,30 @@ impl Sources {
|
|||||||
let range = &file.last_change_range.clone();
|
let range = &file.last_change_range.clone();
|
||||||
drop(file);
|
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() {
|
match language_id.as_str() {
|
||||||
"vhdl" => {
|
"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();
|
let mut valid = lock.lock().unwrap();
|
||||||
*valid = true;
|
*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
|
//TODO: add bounds checking for utf8<->utf16 conversions
|
||||||
|
Loading…
x
Reference in New Issue
Block a user