add utils of vhdl | add document_symbol

This commit is contained in:
light-ly 2024-09-30 23:01:06 +08:00
parent df57c83b0e
commit f0f31c6c97
7 changed files with 337 additions and 18 deletions

2
.gitignore vendored
View File

@ -11,3 +11,5 @@ log_files
test.txt
build.bat
.DS_Store

113
Cargo.lock generated
View File

@ -281,6 +281,15 @@ version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
[[package]]
name = "crossbeam-channel"
version = "0.5.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.5"
@ -343,6 +352,7 @@ dependencies = [
"tokio",
"tower-lsp",
"vhdl_lang",
"vhdl_ls",
"walkdir",
"which",
]
@ -400,6 +410,29 @@ dependencies = [
"syn 2.0.28",
]
[[package]]
name = "env_filter"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab"
dependencies = [
"log",
"regex",
]
[[package]]
name = "env_logger"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c012a26a7f605efc424dd53697843a72be7dc86ad2d01f7814337794a12231d"
dependencies = [
"anstream",
"anstyle",
"env_filter",
"humantime",
"log",
]
[[package]]
name = "equivalent"
version = "1.0.1"
@ -528,6 +561,15 @@ dependencies = [
"slab",
]
[[package]]
name = "fuzzy-matcher"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94"
dependencies = [
"thread_local",
]
[[package]]
name = "getrandom"
version = "0.2.14"
@ -608,6 +650,12 @@ version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "iana-time-zone"
version = "0.1.57"
@ -725,6 +773,18 @@ version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
[[package]]
name = "lsp-server"
version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "550446e84739dcaf6d48a4a093973850669e13e8a34d8f8d64851041be267cd9"
dependencies = [
"crossbeam-channel",
"log",
"serde",
"serde_json",
]
[[package]]
name = "lsp-types"
version = "0.94.1"
@ -738,6 +798,19 @@ dependencies = [
"url",
]
[[package]]
name = "lsp-types"
version = "0.95.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e34d33a8e9b006cd3fc4fe69a921affa097bae4bb65f76271f4644f9a334365"
dependencies = [
"bitflags 1.3.2",
"serde",
"serde_json",
"serde_repr",
"url",
]
[[package]]
name = "memchr"
version = "2.5.0"
@ -1203,18 +1276,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "serde"
version = "1.0.179"
version = "1.0.193"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a5bf42b8d227d4abf38a1ddb08602e229108a517cd4e5bb28f9c7eaafdce5c0"
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.179"
version = "1.0.193"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "741e124f5485c7e60c03b043f79f320bff3527f4bbf12cf3831750dc46a0ec2c"
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
dependencies = [
"proc-macro2",
"quote",
@ -1223,9 +1296,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.104"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c"
checksum = "cb0652c533506ad7a2e353cce269330d6afd8bdfb6d75e0ace5b35aacbd7b9e9"
dependencies = [
"itoa",
"ryu",
@ -1483,6 +1556,16 @@ dependencies = [
"syn 2.0.28",
]
[[package]]
name = "thread_local"
version = "1.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
dependencies = [
"cfg-if",
"once_cell",
]
[[package]]
name = "tinyvec"
version = "1.6.0"
@ -1602,7 +1685,7 @@ dependencies = [
"dashmap",
"futures",
"httparse",
"lsp-types",
"lsp-types 0.94.1",
"memchr",
"serde",
"serde_json",
@ -1760,6 +1843,22 @@ dependencies = [
"syn 2.0.28",
]
[[package]]
name = "vhdl_ls"
version = "0.83.0"
dependencies = [
"clap 4.4.18",
"env_logger",
"fnv",
"fuzzy-matcher",
"log",
"lsp-server",
"lsp-types 0.95.1",
"serde",
"serde_json",
"vhdl_lang",
]
[[package]]
name = "walkdir"
version = "2.3.3"

View File

@ -7,6 +7,7 @@ edition = "2018"
[dependencies]
sv-parser = { version = "0.13.3", path = "sv-parser/sv-parser"}
vhdl_lang = { version = "^0.83.0", path = "rust_hdl/vhdl_lang" }
vhdl_ls = { version = "^0.83.0", path = "rust_hdl/vhdl_ls" }
once_cell = "1.8"
percent-encoding = "2.1.0"
log = "0.4.19"

@ -1 +1 @@
Subproject commit f881ca161ac60accdf65295851ded9abf413da75
Subproject commit d3f01fe8ec8d6d48031e3eaf043a65244297ca9c

View File

@ -1,6 +1,109 @@
use log::info;
use tower_lsp::lsp_types::*;
use crate::server::LSPServer;
use crate::{server::LSPServer, utils::to_lsp_range};
use crate::utils::{to_escape_path, to_symbol_kind};
pub fn vhdl_document_symbol(server: &LSPServer, param: &DocumentSymbolParams) -> Option<DocumentSymbolResponse> {
None
use std::path::PathBuf;
use std::str::FromStr;
use vhdl_lang::{EntHierarchy, Token};
pub fn vhdl_document_symbol(server: &LSPServer, params: &DocumentSymbolParams) -> Option<DocumentSymbolResponse> {
let uri = &params.text_document.uri;
let file_id = server.srcs.get_id(&uri).to_owned();
server.srcs.wait_parse_ready(file_id, false);
let projects = server.srcs.design_file_map.read().ok()?;
let path = match PathBuf::from_str(uri.path()) {
Ok(path) => path,
Err(error) => {
info!("error happen in <goto_include_definition>: {:?}", error);
return None;
}
};
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 None;
}
let project = match projects.get(escape_path_string) {
Some(project) => project,
None => return None
};
let source = project.get_source(&escape_path)?;
// Some files are mapped to multiple libraries, only use the first library for document symbols
let library_name = project
.library_mapping_of(&source)
.into_iter()
.next()?;
// TODO: Confirm vscode support
// if server.client_has_hierarchical_document_symbol_support() {
fn to_document_symbol(
EntHierarchy { ent, children }: EntHierarchy,
ctx: &Vec<Token>,
) -> DocumentSymbol {
// Use the declaration position, if it exists,
// else the position of the first source range token.
// The latter is applicable for unnamed elements, e.g., processes or loops.
let selection_pos = ent.decl_pos().unwrap_or(ent.src_span.start_token.pos(ctx));
let src_range = ent.src_span.pos(ctx).range();
#[allow(deprecated)]
DocumentSymbol {
name: ent.describe(),
kind: to_symbol_kind(ent.kind()),
tags: None,
detail: None,
selection_range: to_lsp_range(selection_pos.range),
range: to_lsp_range(src_range),
children: if !children.is_empty() {
Some(
children
.into_iter()
.map(|hierarchy| to_document_symbol(hierarchy, ctx))
.collect(),
)
} else {
None
},
deprecated: None,
}
}
Some(DocumentSymbolResponse::Nested(
project
.document_symbols(&library_name, &source)
.into_iter()
.map(|(hierarchy, tokens)| to_document_symbol(hierarchy, tokens))
.collect(),
))
// } else {
// #[allow(clippy::ptr_arg)]
// fn to_symbol_information(ent: EntRef, ctx: &Vec<Token>) -> SymbolInformation {
// let selection_pos = ent.decl_pos().unwrap_or(ent.src_span.start_token.pos(ctx));
// #[allow(deprecated)]
// SymbolInformation {
// name: ent.describe(),
// kind: to_symbol_kind(ent.kind()),
// tags: None,
// location: srcpos_to_location(selection_pos),
// deprecated: None,
// container_name: ent.parent_in_same_source().map(|ent| ent.describe()),
// }
// }
// Some(DocumentSymbolResponse::Flat(
// project
// .document_symbols(&library_name, &source)
// .into_iter()
// .flat_map(|(a, ctx)| {
// a.into_flat()
// .into_iter()
// .map(|hierarchy| to_symbol_information(hierarchy, ctx))
// })
// .collect(),
// ))
// }
}

View File

@ -1,4 +1,3 @@
use crate::core::fast_hdlparam::FastHdlparam;
use crate::core::fast_hdlparam::HdlParam;
use crate::core::sv_parser::make_fast_from_syntaxtree;
use crate::core::vhdl_parser::make_fast_from_design_file;
@ -13,7 +12,7 @@ use log::info;
use log::{debug, error};
use pathdiff::diff_paths;
use ropey::{Rope, RopeSlice};
use vhdl_lang::ast::DesignFile;
use vhdl_lang::MessagePrinter;
use std::cmp::min;
use std::collections::HashMap;
use std::env::current_dir;
@ -130,7 +129,7 @@ pub struct Source {
pub enum ParseIR {
/// 基于 rust_hdl 的IR存放 VHDL
#[allow(unused)]
DesignFile(vhdl_lang::ast::DesignFile),
VHDLProject(vhdl_lang::Project),
/// 存放 sv 的 IR
SyntaxTree(sv_parser::SyntaxTree)
}
@ -178,7 +177,7 @@ pub struct Sources {
/// scope tree 类型的树形结构,用于提供 sv 的 lsp
pub scope_tree: Arc<RwLock<Option<GenericScope>>>,
/// 存储 vhdl design file ir 的对象
pub design_file_map: Arc<RwLock<HashMap<String, DesignFile>>>,
pub design_file_map: Arc<RwLock<HashMap<String, vhdl_lang::Project>>>,
// include directories, passed to parser to resolve `include
pub include_dirs: Arc<RwLock<Vec<PathBuf>>>,
// source directories
@ -567,7 +566,7 @@ pub fn sv_parser_pipeline(
}
pub fn vhdl_parser_pipeline(
design_file_handle: &Arc<RwLock<HashMap<String, DesignFile>>>,
design_file_handle: &Arc<RwLock<HashMap<String, vhdl_lang::Project>>>,
hdl_param_handle: &Arc<HdlParam>,
uri: &Url
) {
@ -589,7 +588,9 @@ pub fn vhdl_parser_pipeline(
if let Some(fast) = make_fast_from_design_file(&design_file) {
hdl_param_handle.update_fast(escape_path_string.to_string(), fast);
}
design_files.insert(escape_path_string.to_string(), design_file);
let mut msg_printer = MessagePrinter::default();
let project = vhdl_lang::Project::new_without_config(&escape_path, &mut msg_printer, None);
design_files.insert(escape_path_string.to_string(), project);
}
}

View File

@ -4,6 +4,7 @@ use percent_encoding::percent_decode_str;
use regex::Regex;
use ropey::RopeSlice;
use tower_lsp::lsp_types::*;
use vhdl_lang::{ast::ObjectClass, AnyEntKind, Object, Overloaded, Type, Concurrent};
pub mod fast;
@ -140,3 +141,115 @@ pub fn to_escape_path(path: &PathBuf) -> PathBuf {
},
}
}
pub fn to_lsp_pos(position: vhdl_lang::Position) -> Position {
Position {
line: position.line,
character: position.character,
}
}
pub fn to_lsp_range(range: vhdl_lang::Range) -> Range {
Range {
start: to_lsp_pos(range.start),
end: to_lsp_pos(range.end),
}
}
pub fn to_symbol_kind(kind: &AnyEntKind) -> SymbolKind {
match kind {
AnyEntKind::ExternalAlias { class, .. } => object_class_kind(ObjectClass::from(*class)),
AnyEntKind::ObjectAlias { base_object, .. } => object_kind(base_object.object()),
AnyEntKind::Object(o) => object_kind(o),
AnyEntKind::LoopParameter(_) => SymbolKind::CONSTANT,
AnyEntKind::PhysicalLiteral(_) => SymbolKind::CONSTANT,
AnyEntKind::DeferredConstant(_) => SymbolKind::CONSTANT,
AnyEntKind::File { .. } => SymbolKind::FILE,
AnyEntKind::InterfaceFile { .. } => SymbolKind::INTERFACE,
AnyEntKind::Component(_) => SymbolKind::CLASS,
AnyEntKind::Attribute(_) => SymbolKind::PROPERTY,
AnyEntKind::Overloaded(o) => overloaded_kind(o),
AnyEntKind::Type(t) => type_kind(t),
AnyEntKind::ElementDeclaration(_) => SymbolKind::FIELD,
AnyEntKind::Sequential(_) => SymbolKind::NAMESPACE,
AnyEntKind::Concurrent(Some(Concurrent::Instance)) => SymbolKind::MODULE,
AnyEntKind::Concurrent(_) => SymbolKind::NAMESPACE,
AnyEntKind::Library => SymbolKind::NAMESPACE,
AnyEntKind::View(_) => SymbolKind::INTERFACE,
AnyEntKind::Design(d) => match d {
vhdl_lang::Design::Entity(_, _) => SymbolKind::MODULE,
vhdl_lang::Design::Architecture(..) => SymbolKind::MODULE,
vhdl_lang::Design::Configuration => SymbolKind::MODULE,
vhdl_lang::Design::Package(_, _) => SymbolKind::PACKAGE,
vhdl_lang::Design::PackageBody(..) => SymbolKind::PACKAGE,
vhdl_lang::Design::UninstPackage(_, _) => SymbolKind::PACKAGE,
vhdl_lang::Design::PackageInstance(_) => SymbolKind::PACKAGE,
vhdl_lang::Design::InterfacePackageInstance(_) => SymbolKind::PACKAGE,
vhdl_lang::Design::Context(_) => SymbolKind::NAMESPACE,
},
}
}
pub fn type_kind(t: &Type) -> SymbolKind {
match t {
vhdl_lang::Type::Array { .. } => SymbolKind::ARRAY,
vhdl_lang::Type::Enum(_) => SymbolKind::ENUM,
vhdl_lang::Type::Integer => SymbolKind::NUMBER,
vhdl_lang::Type::Real => SymbolKind::NUMBER,
vhdl_lang::Type::Physical => SymbolKind::NUMBER,
vhdl_lang::Type::Access(_) => SymbolKind::ENUM,
vhdl_lang::Type::Record(_) => SymbolKind::STRUCT,
vhdl_lang::Type::Incomplete => SymbolKind::NULL,
vhdl_lang::Type::Subtype(t) => type_kind(t.type_mark().kind()),
vhdl_lang::Type::Protected(_, _) => SymbolKind::CLASS,
vhdl_lang::Type::File => SymbolKind::FILE,
vhdl_lang::Type::Interface => SymbolKind::TYPE_PARAMETER,
vhdl_lang::Type::Alias(t) => type_kind(t.kind()),
vhdl_lang::Type::Universal(_) => SymbolKind::NUMBER,
}
}
pub fn overloaded_kind(overloaded: &Overloaded) -> SymbolKind {
match overloaded {
Overloaded::SubprogramDecl(_) => SymbolKind::FUNCTION,
Overloaded::Subprogram(_) => SymbolKind::FUNCTION,
Overloaded::UninstSubprogramDecl(..) => SymbolKind::FUNCTION,
Overloaded::UninstSubprogram(..) => SymbolKind::FUNCTION,
Overloaded::InterfaceSubprogram(_) => SymbolKind::FUNCTION,
Overloaded::EnumLiteral(_) => SymbolKind::ENUM_MEMBER,
Overloaded::Alias(o) => overloaded_kind(o.kind()),
}
}
pub fn object_kind(object: &Object) -> SymbolKind {
if matches!(object.subtype.type_mark().kind(), Type::Protected(..)) {
SymbolKind::OBJECT
} else if object.iface.is_some() {
SymbolKind::INTERFACE
} else {
object_class_kind(object.class)
}
}
pub fn object_class_kind(class: ObjectClass) -> SymbolKind {
match class {
ObjectClass::Signal => SymbolKind::EVENT,
ObjectClass::Constant => SymbolKind::CONSTANT,
ObjectClass::Variable => SymbolKind::VARIABLE,
ObjectClass::SharedVariable => SymbolKind::VARIABLE,
}
}
pub fn from_lsp_pos(position: Position) -> vhdl_lang::Position {
vhdl_lang::Position {
line: position.line,
character: position.character,
}
}
pub fn from_lsp_range(range: Range) -> vhdl_lang::Range {
vhdl_lang::Range {
start: from_lsp_pos(range.start),
end: from_lsp_pos(range.end),
}
}