实现 endmodule 的 inlay hints

This commit is contained in:
锦恢 2024-12-13 22:00:40 +08:00
parent 1142aa324f
commit 9688a330bf
4 changed files with 95 additions and 32 deletions

1
Cargo.lock generated
View File

@ -1459,6 +1459,7 @@ dependencies = [
name = "sv-parser-pp"
version = "0.13.3"
dependencies = [
"log",
"nom",
"nom-greedyerror",
"sv-parser-error",

View File

@ -227,7 +227,9 @@ endmodule
// resetall 也常用于开始
// 1834-2005中指出建议的用法是将 `resetall 放在每个源文本文件的开头,后面紧跟着文件中所需的指令。
// 通常可用于源文本开头,避免该文件受到其他文件代码的影响。或放置在末尾,避免编译器设置的进一步传递
r#"`resetall` 用于重置所有编译器设置为默认值。它通常用于在模块或文件的末尾清除所有编译器设置,以确保后续代码不受之前设置的影响。
r#"`resetall` 用于重置所有编译器设置为默认值。通常可用于源文本开头,避免该文件受到其他文件代码的影响。或放置在末尾,避免编译器设置的进一步传递。
1834-2005 `resetall
```verilog
`timescale 1ns/1ps // 设置时间单位和精度
@ -273,7 +275,7 @@ endmodule
// 也即是,仿真时间单位必须大于等于时间精度
// `timescale 1ns/1ns不会报错但是`timescale 1ps/1ns会报错
// [Synth 8-522] parsing error: error in timescale or timeprecision statement. <timeprecision> must be at least as precise as <timeunit>
r#"设置时间单位和精度,设置时间单位和精度,格式为 <code> `timescale </code> 仿真时间单位/时间精度,<code>仿真时间单位</code> 必须大于 <code>时间精度</code>,例如
r#"设置时间单位和精度,设置时间单位和精度,格式为 <code> `timescale </code> 仿真时间单位/时间精度,<code>仿真时间单位</code> 必须大于等于 <code>时间精度</code>,例如
```verilog
`timescale 1ns/1ps
@ -343,7 +345,7 @@ r#"`nounconnected_drive` 和 `unconnected_drive` 是配合使用的编译指令
"begin_keywords",
"`begin_keywords\n$1\n`end_keywords ",
// begin_keywords并不是指定Verilog的编译版本而是指定使用的Verilog关键字版本
r#"`begin_keywords` 和 `end_keywords` 是用于指定 Verilog 语言版本的编译指令。它们允许设计者在同一个文件中使用不同版本的 Verilog 语法,从而实现兼容性或逐步迁移到新版本。
r#"`begin_keywords` 和 `end_keywords` 是用于指定 Verilog 关键字版本的编译指令。它们允许设计者在同一个文件中使用不同版本的 Verilog 关键字语法,从而实现兼容性或逐步迁移到新版本。
`begin_keywords` Verilog

View File

@ -76,8 +76,8 @@ pub fn sv_parser(path: &str) -> Option<FastHdlparam> {
// println!("result: {result:?}");
if let Some(syntax_tree) = result {
if let Ok(hdlparam) = make_fast_from_syntaxtree(&syntax_tree, &path) {
return Some(hdlparam);
if let Ok(fast) = make_fast_from_syntaxtree(&syntax_tree, &path) {
return Some(fast);
}
}
@ -91,7 +91,7 @@ pub fn make_fast_from_syntaxtree(
// 对不同操作系统文件路径的支持
let path = to_escape_path(path);
let mut hdlparam = FastHdlparam {
let mut fast: FastHdlparam = FastHdlparam {
fast_macro: Macro {
defines: Vec::new(),
errors: Vec::new(),
@ -103,10 +103,11 @@ pub fn make_fast_from_syntaxtree(
};
let mut ansi_port_last_dir = "";
// println!("{:?}", syntax_tree);
// &SyntaxTree is iterable
let doc = Rope::from_str(syntax_tree.text.text());
// 上一个 module 可以在 fast 的 content 的最后一个中找到
for node in syntax_tree {
match node {
RefNode::TextMacroDefinition(x) => {
@ -148,20 +149,20 @@ pub fn make_fast_from_syntaxtree(
};
let define_range = Range { start: start_pos, end: end_pos };
hdlparam.add_define(name, replacement, define_range, params_vec);
fast.add_define(name, replacement, define_range, params_vec);
}
}
RefNode::ModuleDeclaration(x) => {
let start_keyword = unwrap_node!(x, Keyword).unwrap();
let start_keyword = get_identifier(start_keyword).unwrap();
let start_pos = get_position(&doc, start_keyword, 0);
let module_range = get_pp_range(&doc, RefNode::ModuleDeclaration(x));
let module_range = Range { start: start_pos, end: module_range.end };
let module_range = Range { start: start_pos.clone(), end: start_pos };
let id = unwrap_node!(x, ModuleIdentifier).unwrap();
let id = get_identifier(id).unwrap();
let name = syntax_tree.get_str(&id).unwrap();
hdlparam.new_module(name, module_range);
fast.new_module(name, module_range);
}
RefNode::ParameterDeclaration(param_dec) => {
let mut event_iter = param_dec.into_iter().event();
@ -192,7 +193,7 @@ pub fn make_fast_from_syntaxtree(
};
let end_pos = get_position(&doc, loc.clone(), loc.len);
let param_range = Range { start: start_pos, end: end_pos };
hdlparam.add_parameter(name, net_type, init, param_range);
fast.add_parameter(name, net_type, init, param_range);
}
}
_ => ()
@ -235,7 +236,7 @@ pub fn make_fast_from_syntaxtree(
let name = syntax_tree.get_str(&id).unwrap();
let port_range = Range { start: start_pos.clone(), end: get_position(&doc, id, id.len) };
hdlparam.add_port(name, dir_type, net_type, width.as_str(), port_range);
fast.add_port(name, dir_type, net_type, width.as_str(), port_range);
}
}
}
@ -284,7 +285,7 @@ pub fn make_fast_from_syntaxtree(
_ => "1".to_string()
};
hdlparam.add_port(name, ansi_port_last_dir, net_type, width.as_str(), port_range);
fast.add_port(name, ansi_port_last_dir, net_type, width.as_str(), port_range);
}
}
RefNode::ModuleInstantiation(x) => {
@ -316,7 +317,7 @@ pub fn make_fast_from_syntaxtree(
let inst_port_assignments = get_instance_ports(&syntax_tree, &doc, hier_node.clone());
let port_range = get_pp_range(&doc, hier_node).to_option();
hdlparam.add_instance(
fast.add_instance(
name, inst_type, inst_range,
param_range, inst_param_assignments,
port_range, inst_port_assignments
@ -342,7 +343,7 @@ pub fn make_fast_from_syntaxtree(
let inst_port_assignments = get_instance_ports(&syntax_tree, &doc, gate_node.clone());
let port_range = get_pp_range(&doc, gate_node).to_option();
hdlparam.add_instance(
fast.add_instance(
name, inst_type, inst_range,
param_range, Vec::<InstParameter>::new(),
port_range, inst_port_assignments
@ -351,13 +352,31 @@ pub fn make_fast_from_syntaxtree(
_ => ()
}
}
RefNode::Keyword(x) => {
let id = x.nodes.0;
let name = syntax_tree.get_str(&id).unwrap();
let pos = get_position(&doc, id, name.len());
// 根据关键词进行特殊处理
// 比如找到 endmodule 的位置来确定目前的这个 module 的 end
match name {
"endmodule" => {
// 尝试获取 content 最后一个元素的可变引用,该引用如果存在,说明已经创建了一个 module
if let Some(last_module) = fast.content.last_mut() {
last_module.range.end.line = pos.line;
last_module.range.end.character = pos.line;
}
},
_ => {}
}
}
_ => ()
}
}
// update_module_range(&path, &mut hdlparam);
Ok(hdlparam)
Ok(fast)
}
// 获取 port 或者 param 的 range
@ -705,7 +724,7 @@ fn get_includes(path: &PathBuf) -> Vec<crate::core::hdlparam::Include> {
}
#[allow(unused)]
fn update_module_range(path: &PathBuf, hdlparam: &mut FastHdlparam) {
fn update_module_range(path: &PathBuf, fast: &mut FastHdlparam) {
let file = File::open(path).unwrap();
let reader = BufReader::new(file);
@ -725,7 +744,7 @@ fn update_module_range(path: &PathBuf, hdlparam: &mut FastHdlparam) {
module_stack.push(module_name.clone());
} else if re_endmodule.is_match(&line) {
if let Some(module_name) = module_stack.pop() {
hdlparam.update_module_range(&module_name, (line_number + 1) as u32, current_offset as u32);
fast.update_module_range(&module_name, (line_number + 1) as u32, current_offset as u32);
// println!("Module {} ends.", module_name);
}
}

View File

@ -33,16 +33,26 @@ pub fn inlay_hint(server: &LspServer, params: &InlayHintParams) -> Option<Vec<In
for module in &fast.content {
for instance in &module.instances {
// 根据在可见视图外面的 range 就不管了
if is_visible_range(&instance.instparams, &visible_range) {
hints.extend(make_instparam_hints(server, params, instance, rope));
if let Some(range) = &instance.instparams {
if is_visible_range(&range, &visible_range) {
hints.extend(make_instparam_hints(server, params, instance, rope));
}
}
if is_visible_range(&instance.instports, &visible_range) {
hints.extend(make_instport_hints(server, params, instance, rope));
if let Some(range) = &instance.instports {
if is_visible_range(range, &visible_range) {
hints.extend(make_instport_hints(server, params, instance, rope));
}
}
}
// 在 endmodule 后面添加 module xxx
if is_visible_range(&module.range, &visible_range) {
hints.extend(make_endmodule_hints(module));
}
}
return Some(hints);
}
@ -50,16 +60,46 @@ pub fn inlay_hint(server: &LspServer, params: &InlayHintParams) -> Option<Vec<In
}
fn is_visible_range(
target_range: &Option<core::hdlparam::Range>,
target_range: &core::hdlparam::Range,
visible_range: &core::hdlparam::Range
) -> bool {
if let Some(target_range) = target_range {
if target_range.before(visible_range) || target_range.after(visible_range) {
return false;
}
return true;
if target_range.before(visible_range) || target_range.after(visible_range) {
false
} else {
true
}
false
}
fn make_endmodule_hints(
module: &core::hdlparam::Module
) -> Vec<InlayHint> {
let mut hints = Vec::<InlayHint>::new();
let end_pos = &module.range.end;
let start_pos = &module.range.start;
if end_pos.character == start_pos.character && end_pos.line == start_pos.line {
// 说明解析器没有找到 endmodule
return hints;
}
let module_desc = MarkupContent {
kind: MarkupKind::Markdown,
value: format!("module {}", module.name)
};
let hint = InlayHint {
position: end_pos.to_lsp_position(),
label: InlayHintLabel::String(format!("module {}", module.name)),
padding_left: Some(true),
padding_right: Some(true),
kind: Some(InlayHintKind::PARAMETER),
text_edits: None,
tooltip: Some(InlayHintTooltip::MarkupContent(module_desc)),
data: None
};
hints.push(hint);
hints
}
fn make_instparam_hints(
@ -112,6 +152,7 @@ fn find_instport_inlay_hints_position(
fn make_instport_hints(
server: &LspServer,
#[allow(unused)]
params: &InlayHintParams,
instance: &core::hdlparam::Instance,
rope: &Rope