加入 codedoc 部分

This commit is contained in:
锦恢 2025-02-14 16:39:39 +08:00
parent 3d91cd1ee3
commit 10fbbd8843
10 changed files with 435 additions and 1 deletions

2
src/codedoc/mod.rs Normal file
View File

@ -0,0 +1,2 @@
pub mod vlog;
pub mod vhdl;

137
src/codedoc/vhdl.rs Normal file
View File

@ -0,0 +1,137 @@
use std::collections::HashMap;
use ropey::Rope;
use sv_parser::{RefNode, SyntaxTree};
use serde_json::{Value, json};
use crate::core::sv_parser::{get_identifier, get_position};
struct CommentSymbol {
comment_string: String,
start_pos: crate::core::hdlparam::Position,
end_pos: crate::core::hdlparam::Position
}
pub fn get_comments_from_ast(doc: &Rope, syntax_tree: &SyntaxTree) {
// 创造一个收容 comment 的栈,对连续的注释进行合并
let mut comments = Vec::<CommentSymbol>::new();
for node in syntax_tree {
match node {
RefNode::Comment(x) => {
let locate = x.nodes.0;
let comment_string = syntax_tree.get_str(&locate).unwrap();
let start_pos = get_position(doc, locate, 0);
let end_pos = get_position(doc, locate, locate.len);
println!("{:?}", comment_string);
println!("start {:?}", start_pos);
println!("end {:?}", end_pos);
if let Some(mut last_comment) = comments.last_mut() {
// 判断是否需要合并
let last_end_line = last_comment.end_pos.line;
let current_start_line = start_pos.line;
}
// 否则,直接加入
comments.push(CommentSymbol {
comment_string: comment_string.to_string(),
start_pos, end_pos
});
}
_ => {}
}
}
}
/// 解析第一行 tag
/// /* @meta
/// *
/// */
///
/// /* @module
/// *
/// */
///
/// /* @wavedrom xxx
/// *
/// */
///
/// 或者压根儿没有
/// /*
/// *
/// */
fn parse_first_line_tag(comment: &str) {
}
/// 解析不同的注释块
fn codedoc_parse_pipeline(comment: &str) {
}
fn parse_c_style_comment(comment: &str) -> Result<Value, String> {
let mut result = HashMap::new();
let mut revision_vec = Vec::new();
let mut in_revision = false;
for line in comment.lines() {
let line = line.trim();
if line.is_empty() || line.starts_with("/*") || line.starts_with("*/") {
continue;
}
if line.starts_with("*") {
let line = line[1..].trim();
if line.starts_with("@meta") {
continue;
}
if let Some((key, value)) = line.split_once(':') {
let key = key.trim();
let value = value.trim();
match key {
"Tool Versions" => {
let tools: Vec<&str> = value.split('&').map(|s| s.trim()).collect();
result.insert(key.to_string(), json!(tools));
}
"Revision" => {
in_revision = true;
}
_ => {
if in_revision {
if value.matches('&').count() == 2 {
let parts: Vec<&str> = value.split('&').map(|s| s.trim()).collect();
let revision = json!({
"date": parts[0],
"version": parts[1],
"revision": parts[2]
});
revision_vec.push(revision);
} else {
in_revision = false;
result.insert(key.to_string(), json!(revision_vec));
}
} else {
result.insert(key.to_string(), json!(value));
}
}
}
}
}
}
// Handle Copyright field
if let Some(copyright) = result.get_mut("Copyright") {
let copyright_str = copyright.as_str().unwrap_or("");
*copyright = json!(format!("Copyright(c) {}", copyright_str));
}
Ok(json!(result))
}

180
src/codedoc/vlog.rs Normal file
View File

@ -0,0 +1,180 @@
use std::collections::HashMap;
use ropey::Rope;
use sv_parser::{RefNode, SyntaxTree};
use serde_json::{Value, json};
use crate::core::sv_parser::{get_identifier, get_position};
struct CommentSymbol {
comment_string: String,
start_pos: crate::core::hdlparam::Position,
end_pos: crate::core::hdlparam::Position
}
pub fn get_comments_from_ast(doc: &Rope, syntax_tree: &SyntaxTree) {
let comments = make_comment_list(doc, syntax_tree);
for comment in &comments {
if let Some(comment_meta) = get_meta_info(comment) {
} else {
// 处理为普通注释
}
}
}
/// 创造一个收容 comment 的栈,对连续的注释进行合并
fn make_comment_list(doc: &Rope, syntax_tree: &SyntaxTree) -> Vec<CommentSymbol> {
let mut comments = Vec::<CommentSymbol>::new();
for node in syntax_tree {
match node {
RefNode::Comment(x) => {
let locate = x.nodes.0;
let comment_string = syntax_tree.get_str(&locate).unwrap();
let start_pos = get_position(doc, locate, 0);
let end_pos = get_position(doc, locate, locate.len);
println!("{:?}", comment_string);
println!("start {:?}", start_pos);
println!("end {:?}", end_pos);
if let Some(last_comment) = comments.last_mut() {
// 判断是否需要合并
// vlog 只合并单行注释
let last_end_line = last_comment.end_pos.line;
let current_start_line = start_pos.line;
if current_start_line - last_end_line <= 1
&& last_comment.comment_string.starts_with("//")
&& comment_string.starts_with("//") {
last_comment.comment_string += comment_string;
last_comment.end_pos = end_pos;
continue;
}
}
// 否则,直接加入
comments.push(CommentSymbol {
comment_string: comment_string.to_string(),
start_pos, end_pos
});
}
_ => {}
}
}
comments
}
struct CommentMeta<'a> {
comment_type: &'a str,
argruments: Vec::<&'a str>
}
/// 解析第一行 tag
/// /* @meta
/// *
/// */
///
/// /* @module
/// *
/// */
///
/// /* @wavedrom xxx
/// *
/// */
///
/// 或者压根儿没有
/// /*
/// *
/// */
fn get_meta_info(comment: &str) -> Option<CommentMeta> {
let first_line = comment.lines().next().unwrap_or("").trim();
// 注释开头都是 // 或者 /* ,都是两个字符
let comment_meta = &first_line[2..];
if comment_meta.trim().starts_with("@") {
let arguments: Vec<&str> = comment_meta.split_whitespace().collect();
if arguments.len() > 0 {
let comment_type = arguments[0];
let arguments = &arguments[1..];
Some(CommentMeta {
comment_type,
argruments: arguments.to_vec()
})
} else {
None
}
} else {
None
}
}
/// 解析不同的注释块
fn codedoc_parse_pipeline(comment: &str) {
}
fn parse_c_style_comment(comment: &str) -> Result<Value, String> {
let mut result = HashMap::new();
let mut revision_vec = Vec::new();
let mut in_revision = false;
for line in comment.lines() {
let line = line.trim();
if line.is_empty() || line.starts_with("/*") || line.starts_with("*/") {
continue;
}
if line.starts_with("*") {
let line = line[1..].trim();
if line.starts_with("@meta") {
continue;
}
if let Some((key, value)) = line.split_once(':') {
let key = key.trim();
let value = value.trim();
match key {
"Tool Versions" => {
let tools: Vec<&str> = value.split('&').map(|s| s.trim()).collect();
result.insert(key.to_string(), json!(tools));
}
"Revision" => {
in_revision = true;
}
_ => {
if in_revision {
if value.matches('&').count() == 2 {
let parts: Vec<&str> = value.split('&').map(|s| s.trim()).collect();
let revision = json!({
"date": parts[0],
"version": parts[1],
"revision": parts[2]
});
revision_vec.push(revision);
} else {
in_revision = false;
result.insert(key.to_string(), json!(revision_vec));
}
} else {
result.insert(key.to_string(), json!(value));
}
}
}
}
}
}
// Handle Copyright field
if let Some(copyright) = result.get_mut("Copyright") {
let copyright_str = copyright.as_str().unwrap_or("");
*copyright = json!(format!("Copyright(c) {}", copyright_str));
}
Ok(json!(result))
}

View File

@ -0,0 +1,16 @@
use std::{path::PathBuf, str::FromStr};
use log::info;
use serde_json::Value;
use tower_lsp::lsp_types::{Diagnostic, Url};
use crate::{diagnostics::provide_diagnostics, server::Backend, utils::{from_uri_to_escape_path_string, open_doc_as_rope}};
// /// 前端请求,发布诊断结果,仅在初始化和修改配置时触发
// /// 参数为 [file_path: string]
// pub async fn publish_diagnostics(
// backend: &Backend,
// arguments: Vec<Value>
// ) -> tower_lsp::jsonrpc::Result<Option<Value>> {
// }

View File

@ -4,6 +4,9 @@ use tower_lsp::lsp_types::*;
use crate::server::Backend; use crate::server::Backend;
mod diagnostics; mod diagnostics;
pub use codedoc::*;
mod codedoc;
pub async fn execute_command( pub async fn execute_command(
backend: &Backend, backend: &Backend,
params: ExecuteCommandParams params: ExecuteCommandParams
@ -17,6 +20,8 @@ pub async fn execute_command(
diagnostics::clear_diagnostics(backend, params.arguments).await diagnostics::clear_diagnostics(backend, params.arguments).await
} }
_ => { _ => {
Ok(None) Ok(None)
} }

View File

@ -30,6 +30,9 @@ pub mod diagnostics;
// 格式化 // 格式化
pub mod format; pub mod format;
// 格式化
pub mod codedoc;
// 基础工具 // 基础工具
pub mod utils; pub mod utils;

View File

@ -24,6 +24,7 @@ mod document_highlight;
mod inlay_hint; mod inlay_hint;
mod code_lens; mod code_lens;
mod utils; mod utils;
mod codedoc;
mod diagnostics; mod diagnostics;
mod format; mod format;
mod server; mod server;

View File

@ -702,7 +702,7 @@ pub fn sv_parser_pipeline(
} }
let escape_path_string = from_uri_to_escape_path_string(uri).unwrap(); let escape_path_string = from_uri_to_escape_path_string(uri).unwrap();
let escape_path = PathBuf::from_str(&escape_path_string).unwrap(); // let escape_path = PathBuf::from_str(&escape_path_string).unwrap();
let ast = recovery_sv_parse_with_retry( let ast = recovery_sv_parse_with_retry(
doc, doc,

View File

@ -487,3 +487,36 @@ mod test_file {
assert!(!is_character_ordered_match("suprt", "super")); assert!(!is_character_ordered_match("suprt", "super"));
} }
} }
#[cfg(test)]
mod test_code_doc {
use std::{env, fs, path::PathBuf};
use ropey::Rope;
use tower_lsp::lsp_types::Url;
use crate::sources::recovery_sv_parse_with_retry;
use crate::codedoc;
#[test]
fn dev_code_doc() {
match env::current_dir() {
Ok(path) => println!("当前工作目录: {}", path.display()),
Err(e) => println!("获取当前工作目录失败: {}", e),
}
let path = PathBuf::from("E:/Project/Digital-IDE/digital-lsp-server/test/vlog/codedoc.v");
let includes: Vec<PathBuf> = Vec::new();
let text = match fs::read_to_string(&path) {
Ok(text) => text,
Err(_) => return
};
let doc = Rope::from_str(&text);
let uri = Url::from_file_path(&path).unwrap();
let result = recovery_sv_parse_with_retry(&doc, &uri, &None, &includes);
if let Some((syntax_tree, _)) = result {
codedoc::vlog::get_comments_from_ast(&doc, &syntax_tree);
}
}
}

57
test/vlog/codedoc.v Normal file
View File

@ -0,0 +1,57 @@
/* @meta
* Create Date : 2/6/2025 14:58
* Author : nitcloud
* Target Device : [Target FPGA and ASIC Device]
* Tool Versions : vivado 18.3 & DC 2016
* Revision Historyc :
* Revision :
* 04/12 0.01 - File Created
* Description :
* Company : ncai Technology .Inc
* Copyright : 1999, ncai Technology Inc, All right reserved
*/
/* @module
* Netlist : level-1
* FSMView : on
* Overview: 4-stage pipelined accumulator.
*/
/*
* 这是一些简单的文字可以随意渲染
* :::info
* 请注意版权问题
* :::
*
* 使用 C 语言如此进行简单的编译
* ```c
* int main() {
* return 0;
* }
* ```
*/
/* @wavedrom accuml this is accuml wavedrom
{signal: [
{name: 'clock', wave: '10101010101010101'},
{name: 'reset', wave: '10...............'},
{name: 'clr', wave: '01.0.............'},
{name: 'idata', wave: 'x3...............', data: ['5']},
{name: 'odata', wave: 'x........5.5.5.5.', data: ['5','10','25','30']},
]}
*/
module adder(
// 这是一个简单的注释
// 这是它们的第二行注释
input a,
input b,
// 这是输出信号
output c,
);
// 具体的代码实现
meta_add u_meta_add(a, b, c);
endmodule