2024-12-13 18:10:27 +08:00

889 lines
25 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#[allow(unused)]
use log::info;
use ropey::Rope;
use tower_lsp::lsp_types::*;
use vhdl_lang::Project;
use crate::{sources::LSPSupport, utils::is_character_ordered_match};
/// cleanup the text of a definition so it can be included in completions
pub fn clean_type_str(type_str: &str, ident: &str) -> String {
let endings: &[_] = &[';', ','];
// remove anything after an equals sign
let eq_offset = type_str.find('=').unwrap_or(type_str.len());
let mut result = type_str.to_string();
result.replace_range(eq_offset.., "");
result
.trim_start()
.trim_end()
.trim_end_matches(endings)
.trim_end_matches(ident)
.split_whitespace()
.collect::<Vec<&str>>()
.join(" ")
.replace("[ ", "[")
.replace(" ]", "]")
.replace(" : ", ":")
}
pub fn copy_defs(defs: &[Box<dyn Definition>]) -> Vec<Box<dyn Definition>> {
let mut decs: Vec<Box<dyn Definition>> = Vec::new();
for def in defs {
decs.push(Box::new(GenericDec {
ident: def.ident(),
byte_idx: def.byte_idx(),
url: def.url(),
type_str: def.type_str(),
completion_kind: def.completion_kind(),
symbol_kind: def.symbol_kind(),
def_type: def.def_type(),
}))
}
decs
}
pub fn copy_scopes(scopes: &[Box<dyn Scope>]) -> Vec<Box<dyn Scope>> {
let mut scope_decs: Vec<Box<dyn Scope>> = Vec::new();
for scope in scopes {
let mut scope_copy = GenericScope {
ident: scope.ident(),
byte_idx: scope.byte_idx(),
start: scope.start(),
end: scope.end(),
url: scope.url(),
type_str: scope.type_str(),
completion_kind: scope.completion_kind(),
symbol_kind: scope.symbol_kind(),
def_type: scope.def_type(),
defs: Vec::new(),
scopes: Vec::new(),
};
scope_copy.defs.extend(copy_defs(scope.defs()));
scope_copy.scopes.extend(copy_scopes(scope.scopes()));
scope_decs.push(Box::new(scope_copy))
}
scope_decs
}
/// Definition 是所有非 scope 类型 symbol 的父类
pub trait Definition: std::fmt::Debug + Sync + Send {
/// symbol 或者 scope 的名字identity 的缩写
///
/// 对于 definition而言 ident 就是它的字面量,比如
/// ```verilog
/// parameter wire_size = 12;
/// ```
/// 上面的 `wire_size` 这个 symbol 的 name 就是 `wire_size`
///
/// 对于 scope 而言
/// ```verilog
/// module beginner();
/// adwadwa
/// endmodule
/// 上面这个 module scope 的 ident 就是 `beginner`
/// ```
fn ident(&self) -> String;
/// 相对于文本的偏移量,可以利用 Rope 的 `byte_to_pos` 函数转换成 Position
fn byte_idx(&self) -> usize;
/// 当前 symbol 所在文件的 url
fn url(&self) -> Url;
/// 输出 Definition 的字符
fn type_str(&self) -> String;
/// 类别,用于自动补全
fn completion_kind(&self) -> CompletionItemKind;
/// 类别,用于文件大纲
fn symbol_kind(&self) -> SymbolKind;
/// 类别,内部使用
fn def_type(&self) -> DefinitionType;
/// 等价于 self.ident.starts_with
fn starts_with(&self, token: &str) -> bool;
/// 构造 completion 的 item
fn completion(&self) -> CompletionItem;
}
/// Scope 是所有 scope 类型 symbol 的父类
pub trait Scope: std::fmt::Debug + Definition + Sync + Send {
// the start byte of this scope
fn start(&self) -> usize;
// the end byte of this scope
fn end(&self) -> usize;
// all the within this scope
fn defs(&self) -> &Vec<Box<dyn Definition>>;
// all the scopes within this scope, ex. task inside a module
fn scopes(&self) -> &Vec<Box<dyn Scope>>;
// the definition of this scope
fn definition(&self) -> GenericDec {
GenericDec {
ident: self.ident(),
byte_idx: self.byte_idx(),
url: self.url(),
type_str: self.type_str(),
completion_kind: self.completion_kind(),
symbol_kind: self.symbol_kind(),
def_type: DefinitionType::GenericScope,
}
}
/// return a completion from the scope tree, this function should be called on the global scope
fn get_completion(&self, token: &str, byte_idx: usize, url: &Url) -> Vec<CompletionItem> {
let mut completions: Vec<CompletionItem> = Vec::new();
// first we need to go down the scope tree, to the scope the user is invoking a completion
// in
for scope in self.scopes() {
// 如果当前的 token 在这个 scope 中,那么需要递归获取这个 scope 中的所有补全项目
if &scope.url() == url && scope.start() <= byte_idx && byte_idx <= scope.end() {
completions = scope.get_completion(token, byte_idx, url);
break;
}
}
// let completion_idents: Vec<String> = completions.iter().map(|x| x.label.clone()).collect();
// 寻找前缀相同的 symbol
// 这里面并没有 macro
for symbol in self.defs() {
// 此处的去重会在外部完成
let symbol_name = symbol.ident();
// 此处仍然会给出 module 的补全,但是此处的只是名字的补全,而不是自动例化
match &symbol.def_type() {
DefinitionType::Port => {},
DefinitionType::Net => {},
DefinitionType::Macro => {
// 对于 TextMacro 类型的,因为是全局属性的,不进行补全
// 对于它的补全请参考 vlog_directives_completion & vlog_directives_completion_without_prefix
continue;
},
DefinitionType::Data => {},
DefinitionType::Modport => {},
DefinitionType::Subroutine => {},
DefinitionType::ModuleInstantiation => {},
DefinitionType::GenericScope => {},
DefinitionType::Class => {},
};
if is_character_ordered_match(token, &symbol_name) {
completions.push(symbol.completion());
}
}
// 寻找前缀相同的 scope
for scope in self.scopes() {
if scope.starts_with(token) {
completions.push(scope.completion());
}
}
completions
}
/// 根据输入的 token计算出这个 token 在 scope 中的定义
/// 比如输入 clock则返回 clock 这个变量在哪里被定义,没有则返回 None
/// - `token`: 需要查找定义的完整的单词
/// - `byte_idx`: 当前光标所在文档的偏移量
/// - `url`: 当前文档的 url
fn get_definition(&self, token: &str, byte_idx: usize, url: &Url) -> Option<GenericDec> {
let mut definition: Option<GenericDec> = None;
// 递归进入最浅层的
for scope in self.scopes() {
if &scope.url() == url && scope.start() <= byte_idx && byte_idx <= scope.end() {
definition = scope.get_definition(token, byte_idx, url);
break;
}
}
if definition.is_none() {
// 优先找 定义,再找 scope
for def in self.defs() {
if def.ident() == token {
return Some(GenericDec {
ident: def.ident(),
byte_idx: def.byte_idx(),
url: def.url(),
type_str: def.type_str(),
completion_kind: def.completion_kind(),
symbol_kind: def.symbol_kind(),
def_type: def.def_type(),
});
}
}
for scope in self.scopes() {
if scope.ident() == token {
return Some(scope.definition());
}
}
}
definition
}
/// returns all symbols in a document
fn document_symbols(&self, uri: &Url, doc: &Rope) -> Vec<DocumentSymbol> {
let mut symbols: Vec<DocumentSymbol> = Vec::new();
for scope in self.scopes() {
if &scope.url() == uri {
#[allow(deprecated)]
symbols.push(DocumentSymbol {
name: scope.ident(),
detail: Some(scope.type_str()),
kind: scope.symbol_kind(),
deprecated: None,
range: Range::new(doc.byte_to_pos(scope.start()), doc.byte_to_pos(scope.end())),
selection_range: Range::new(
doc.byte_to_pos(scope.byte_idx()),
doc.byte_to_pos(scope.byte_idx() + scope.ident().len()),
),
children: Some(scope.document_symbols(uri, doc)),
tags: None,
})
}
}
for def in self.defs() {
#[allow(deprecated)]
symbols.push(DocumentSymbol {
name: def.ident(),
detail: Some(def.type_str()),
kind: def.symbol_kind(),
deprecated: None,
range: Range::new(
doc.byte_to_pos(def.byte_idx()),
doc.byte_to_pos(def.byte_idx() + def.ident().len()),
),
selection_range: Range::new(
doc.byte_to_pos(def.byte_idx()),
doc.byte_to_pos(def.byte_idx() + def.ident().len()),
),
children: None,
tags: None,
})
}
symbols
}
/// highlight all references of a symbol
fn document_highlights(
&self,
uri: &Url,
doc: &Rope,
// all references in the doc's syntax tree
references: Vec<(String, usize)>,
// byte_idx of symbol definition
byte_idx: usize,
) -> Vec<DocumentHighlight> {
// to find references we need to grab references from locations downward from the
// definition
for scope in self.scopes() {
if &scope.url() == uri && scope.start() <= byte_idx && byte_idx <= scope.end() {
return scope.document_highlights(uri, doc, references, byte_idx);
}
}
// we should now be in the scope of the definition, so we can grab all references
// in this scope. This also grabs references below this scope.
references
.iter()
.filter(|x| self.start() <= x.1 && x.1 <= self.end())
.map(|x| DocumentHighlight {
range: Range::new(doc.byte_to_pos(x.1), doc.byte_to_pos(x.1 + x.0.len())),
kind: None,
})
.collect()
}
}
#[derive(Debug, Clone, Copy)]
pub enum DefinitionType {
Port,
Net,
Macro,
Data,
Modport,
Subroutine,
ModuleInstantiation,
GenericScope,
Class,
}
#[derive(Debug)]
pub struct PortDec {
pub ident: String,
pub byte_idx: usize,
pub url: Url,
pub type_str: String,
pub completion_kind: CompletionItemKind,
pub symbol_kind: SymbolKind,
pub def_type: DefinitionType,
pub interface: Option<String>,
pub modport: Option<String>,
}
impl PortDec {
pub fn new(url: &Url) -> Self {
Self {
ident: String::new(),
byte_idx: 0,
type_str: String::new(),
completion_kind: CompletionItemKind::PROPERTY,
symbol_kind: SymbolKind::PROPERTY,
def_type: DefinitionType::Port,
interface: None,
modport: None,
url: url.clone(),
}
}
}
impl Definition for PortDec {
fn ident(&self) -> String {
self.ident.clone()
}
fn byte_idx(&self) -> usize {
self.byte_idx
}
fn url(&self) -> Url {
self.url.clone()
}
fn type_str(&self) -> String {
self.type_str.clone()
}
fn completion_kind(&self) -> CompletionItemKind {
self.completion_kind
}
fn symbol_kind(&self) -> SymbolKind {
self.symbol_kind
}
fn def_type(&self) -> DefinitionType {
self.def_type
}
fn starts_with(&self, token: &str) -> bool {
self.ident.starts_with(token)
}
fn completion(&self) -> CompletionItem {
let label_details = CompletionItemLabelDetails {
description: Some("module port".to_string()),
..Default::default()
};
CompletionItem {
label: self.ident.clone(),
detail: Some(clean_type_str(&self.type_str, &self.ident)),
label_details: Some(label_details),
kind: Some(self.completion_kind),
..CompletionItem::default()
}
}
}
#[derive(Debug)]
pub struct GenericDec {
pub ident: String,
pub byte_idx: usize,
pub url: Url,
pub type_str: String,
pub completion_kind: CompletionItemKind,
pub symbol_kind: SymbolKind,
pub def_type: DefinitionType,
}
impl GenericDec {
pub fn new(url: &Url) -> Self {
Self {
ident: String::new(),
byte_idx: 0,
url: url.clone(),
type_str: String::new(),
completion_kind: CompletionItemKind::VARIABLE,
// FIXME: check if this replacement is correct
symbol_kind: SymbolKind::NULL,
def_type: DefinitionType::Net,
}
}
}
impl Definition for GenericDec {
fn ident(&self) -> String {
self.ident.clone()
}
fn byte_idx(&self) -> usize {
self.byte_idx
}
fn url(&self) -> Url {
self.url.clone()
}
fn type_str(&self) -> String {
self.type_str.clone()
}
fn completion_kind(&self) -> CompletionItemKind {
self.completion_kind
}
fn symbol_kind(&self) -> SymbolKind {
self.symbol_kind
}
fn def_type(&self) -> DefinitionType {
self.def_type
}
fn starts_with(&self, token: &str) -> bool {
self.ident.starts_with(token)
}
fn completion(&self) -> CompletionItem {
CompletionItem {
label: self.ident.clone(),
detail: Some(clean_type_str(&self.type_str, &self.ident)),
kind: Some(self.completion_kind),
..CompletionItem::default()
}
}
}
#[derive(Debug)]
pub struct PackageImport {
pub ident: String,
pub byte_idx: usize,
pub url: Url,
pub type_str: String,
pub completion_kind: CompletionItemKind,
pub symbol_kind: SymbolKind,
pub def_type: DefinitionType,
pub asterisk: bool,
pub import_ident: Option<String>,
}
impl PackageImport {
pub fn new(url: &Url) -> Self {
Self {
ident: String::new(),
byte_idx: 0,
url: url.clone(),
type_str: String::new(),
completion_kind: CompletionItemKind::TEXT,
symbol_kind: SymbolKind::NAMESPACE,
def_type: DefinitionType::Data,
asterisk: false,
import_ident: None,
}
}
}
impl Definition for PackageImport {
fn ident(&self) -> String {
self.ident.clone()
}
fn byte_idx(&self) -> usize {
self.byte_idx
}
fn url(&self) -> Url {
self.url.clone()
}
fn type_str(&self) -> String {
self.type_str.clone()
}
fn completion_kind(&self) -> CompletionItemKind {
self.completion_kind
}
fn symbol_kind(&self) -> SymbolKind {
self.symbol_kind
}
fn def_type(&self) -> DefinitionType {
self.def_type
}
fn starts_with(&self, token: &str) -> bool {
self.ident.starts_with(token)
}
fn completion(&self) -> CompletionItem {
CompletionItem {
label: self.ident.clone(),
detail: Some(clean_type_str(&self.type_str, &self.ident.clone())),
kind: Some(self.completion_kind),
..CompletionItem::default()
}
}
}
#[derive(Debug)]
pub struct SubDec {
pub ident: String,
pub byte_idx: usize,
pub url: Url,
pub type_str: String,
pub completion_kind: CompletionItemKind,
pub symbol_kind: SymbolKind,
pub def_type: DefinitionType,
pub start: usize,
pub end: usize,
pub defs: Vec<Box<dyn Definition>>,
pub scopes: Vec<Box<dyn Scope>>,
}
impl SubDec {
pub fn new(url: &Url) -> Self {
Self {
ident: String::new(),
byte_idx: 0,
url: url.clone(),
type_str: String::new(),
completion_kind: CompletionItemKind::FUNCTION,
symbol_kind: SymbolKind::FUNCTION,
def_type: DefinitionType::Subroutine,
start: 0,
end: 0,
defs: Vec::new(),
scopes: Vec::new(),
}
}
}
impl Definition for SubDec {
fn ident(&self) -> String {
self.ident.clone()
}
fn byte_idx(&self) -> usize {
self.byte_idx
}
fn url(&self) -> Url {
self.url.clone()
}
fn type_str(&self) -> String {
self.type_str.clone()
}
fn completion_kind(&self) -> CompletionItemKind {
self.completion_kind
}
fn symbol_kind(&self) -> SymbolKind {
self.symbol_kind
}
fn def_type(&self) -> DefinitionType {
self.def_type
}
fn starts_with(&self, token: &str) -> bool {
self.ident.starts_with(token)
}
fn completion(&self) -> CompletionItem {
CompletionItem {
label: self.ident.clone(),
detail: Some(clean_type_str(&self.type_str, &self.ident)),
kind: Some(self.completion_kind),
..CompletionItem::default()
}
}
}
impl Scope for SubDec {
fn start(&self) -> usize {
self.start
}
fn end(&self) -> usize {
self.end
}
fn defs(&self) -> &Vec<Box<dyn Definition>> {
&self.defs
}
fn scopes(&self) -> &Vec<Box<dyn Scope>> {
&self.scopes
}
}
#[derive(Debug)]
pub struct ModportDec {
pub ident: String,
pub byte_idx: usize,
pub url: Url,
pub type_str: String,
pub completion_kind: CompletionItemKind,
pub symbol_kind: SymbolKind,
pub def_type: DefinitionType,
pub ports: Vec<Box<dyn Definition>>,
}
impl ModportDec {
pub fn new(url: &Url) -> Self {
Self {
ident: String::new(),
byte_idx: 0,
url: url.clone(),
type_str: String::new(),
completion_kind: CompletionItemKind::INTERFACE,
symbol_kind: SymbolKind::INTERFACE,
def_type: DefinitionType::Modport,
ports: Vec::new(),
}
}
}
impl Definition for ModportDec {
fn ident(&self) -> String {
self.ident.clone()
}
fn byte_idx(&self) -> usize {
self.byte_idx
}
fn url(&self) -> Url {
self.url.clone()
}
fn type_str(&self) -> String {
self.type_str.clone()
}
fn completion_kind(&self) -> CompletionItemKind {
self.completion_kind
}
fn symbol_kind(&self) -> SymbolKind {
self.symbol_kind
}
fn def_type(&self) -> DefinitionType {
self.def_type
}
fn starts_with(&self, token: &str) -> bool {
self.ident.starts_with(token)
}
fn completion(&self) -> CompletionItem {
CompletionItem {
label: self.ident.clone(),
detail: Some(clean_type_str(&self.type_str, &self.ident)),
kind: Some(self.completion_kind),
..CompletionItem::default()
}
}
}
#[derive(Debug)]
pub struct ModInst {
pub ident: String,
pub byte_idx: usize,
pub url: Url,
pub type_str: String,
pub completion_kind: CompletionItemKind,
pub symbol_kind: SymbolKind,
pub def_type: DefinitionType,
pub mod_ident: String,
}
impl ModInst {
pub fn new(url: &Url) -> Self {
Self {
ident: String::new(),
byte_idx: 0,
url: url.clone(),
type_str: String::new(),
completion_kind: CompletionItemKind::MODULE,
symbol_kind: SymbolKind::MODULE,
def_type: DefinitionType::ModuleInstantiation,
mod_ident: String::new(),
}
}
}
impl Definition for ModInst {
fn ident(&self) -> String {
self.ident.clone()
}
fn byte_idx(&self) -> usize {
self.byte_idx
}
fn url(&self) -> Url {
self.url.clone()
}
fn type_str(&self) -> String {
self.type_str.clone()
}
fn completion_kind(&self) -> CompletionItemKind {
self.completion_kind
}
fn symbol_kind(&self) -> SymbolKind {
self.symbol_kind
}
fn def_type(&self) -> DefinitionType {
self.def_type
}
fn starts_with(&self, token: &str) -> bool {
self.ident.starts_with(token)
}
fn completion(&self) -> CompletionItem {
CompletionItem {
label: self.ident.clone(),
detail: Some(clean_type_str(&self.type_str, &self.ident)),
kind: Some(self.completion_kind),
..CompletionItem::default()
}
}
}
pub struct VhdlProject {
pub project: Project,
pub std_config: vhdl_lang::Config,
pub config_file_strs: Vec<String>
}
#[derive(Debug)]
pub struct GenericScope {
pub ident: String,
pub byte_idx: usize,
pub start: usize,
pub end: usize,
pub url: Url,
pub type_str: String,
pub completion_kind: CompletionItemKind,
pub symbol_kind: SymbolKind,
pub def_type: DefinitionType,
pub defs: Vec<Box<dyn Definition>>,
pub scopes: Vec<Box<dyn Scope>>,
}
impl GenericScope {
pub fn new(url: &Url) -> Self {
Self {
ident: String::new(),
byte_idx: 0,
start: 0,
end: 0,
url: url.clone(),
type_str: String::new(),
completion_kind: CompletionItemKind::MODULE,
symbol_kind: SymbolKind::MODULE,
def_type: DefinitionType::GenericScope,
defs: Vec::new(),
scopes: Vec::new(),
}
}
}
impl Definition for GenericScope {
fn ident(&self) -> String {
self.ident.clone()
}
fn byte_idx(&self) -> usize {
self.byte_idx
}
fn url(&self) -> Url {
self.url.clone()
}
fn type_str(&self) -> String {
self.type_str.clone()
}
fn completion_kind(&self) -> CompletionItemKind {
self.completion_kind
}
fn symbol_kind(&self) -> SymbolKind {
self.symbol_kind
}
fn def_type(&self) -> DefinitionType {
self.def_type
}
fn starts_with(&self, token: &str) -> bool {
self.ident.starts_with(token)
}
fn completion(&self) -> CompletionItem {
CompletionItem {
label: self.ident.clone(),
detail: Some(clean_type_str(&self.type_str, &self.ident)),
kind: Some(self.completion_kind),
..CompletionItem::default()
}
}
}
impl Scope for GenericScope {
fn start(&self) -> usize {
self.start
}
fn end(&self) -> usize {
self.end
}
fn defs(&self) -> &Vec<Box<dyn Definition>> {
&self.defs
}
fn scopes(&self) -> &Vec<Box<dyn Scope>> {
&self.scopes
}
}
#[derive(Debug)]
pub struct ClassDec {
pub ident: String,
pub byte_idx: usize,
pub start: usize,
pub end: usize,
pub url: Url,
pub type_str: String,
pub completion_kind: CompletionItemKind,
pub symbol_kind: SymbolKind,
pub def_type: DefinitionType,
pub defs: Vec<Box<dyn Definition>>,
pub scopes: Vec<Box<dyn Scope>>,
// class, package
pub extends: (Vec<String>, Option<String>),
// class, package
pub implements: Vec<(String, Option<String>)>,
}
impl ClassDec {
pub fn new(url: &Url) -> Self {
Self {
ident: String::new(),
byte_idx: 0,
start: 0,
end: 0,
url: url.clone(),
type_str: String::new(),
completion_kind: CompletionItemKind::CLASS,
symbol_kind: SymbolKind::CLASS,
def_type: DefinitionType::Class,
defs: Vec::new(),
scopes: Vec::new(),
extends: (Vec::new(), None),
implements: Vec::new(),
}
}
}
impl Definition for ClassDec {
fn ident(&self) -> String {
self.ident.clone()
}
fn byte_idx(&self) -> usize {
self.byte_idx
}
fn url(&self) -> Url {
self.url.clone()
}
fn type_str(&self) -> String {
self.type_str.clone()
}
fn completion_kind(&self) -> CompletionItemKind {
self.completion_kind
}
fn symbol_kind(&self) -> SymbolKind {
self.symbol_kind
}
fn def_type(&self) -> DefinitionType {
self.def_type
}
fn starts_with(&self, token: &str) -> bool {
self.ident.starts_with(token)
}
fn completion(&self) -> CompletionItem {
CompletionItem {
label: self.ident.clone(),
detail: Some(clean_type_str(&self.type_str, &self.ident)),
kind: Some(self.completion_kind),
..CompletionItem::default()
}
}
}
impl Scope for ClassDec {
fn start(&self) -> usize {
self.start
}
fn end(&self) -> usize {
self.end
}
fn defs(&self) -> &Vec<Box<dyn Definition>> {
&self.defs
}
fn scopes(&self) -> &Vec<Box<dyn Scope>> {
&self.scopes
}
}