From 10fbbd8843145c35f7b904624b14a1abd5187d90 Mon Sep 17 00:00:00 2001 From: Kirigaya <1193466151@qq.com> Date: Fri, 14 Feb 2025 16:39:39 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=A0=E5=85=A5=20codedoc=20=E9=83=A8?= =?UTF-8?q?=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/codedoc/mod.rs | 2 + src/codedoc/vhdl.rs | 137 +++++++++++++++++++++++++ src/codedoc/vlog.rs | 180 +++++++++++++++++++++++++++++++++ src/execute_command/codedoc.rs | 16 +++ src/execute_command/mod.rs | 5 + src/lib.rs | 3 + src/main.rs | 1 + src/sources.rs | 2 +- src/test/mod.rs | 33 ++++++ test/vlog/codedoc.v | 57 +++++++++++ 10 files changed, 435 insertions(+), 1 deletion(-) create mode 100644 src/codedoc/mod.rs create mode 100644 src/codedoc/vhdl.rs create mode 100644 src/codedoc/vlog.rs create mode 100644 src/execute_command/codedoc.rs create mode 100644 test/vlog/codedoc.v diff --git a/src/codedoc/mod.rs b/src/codedoc/mod.rs new file mode 100644 index 0000000..dbbb4da --- /dev/null +++ b/src/codedoc/mod.rs @@ -0,0 +1,2 @@ +pub mod vlog; +pub mod vhdl; diff --git a/src/codedoc/vhdl.rs b/src/codedoc/vhdl.rs new file mode 100644 index 0000000..61b7314 --- /dev/null +++ b/src/codedoc/vhdl.rs @@ -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::::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 { + 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)) +} \ No newline at end of file diff --git a/src/codedoc/vlog.rs b/src/codedoc/vlog.rs new file mode 100644 index 0000000..1cf842a --- /dev/null +++ b/src/codedoc/vlog.rs @@ -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 { + let mut comments = Vec::::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 { + 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 { + 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)) +} \ No newline at end of file diff --git a/src/execute_command/codedoc.rs b/src/execute_command/codedoc.rs new file mode 100644 index 0000000..6a538e2 --- /dev/null +++ b/src/execute_command/codedoc.rs @@ -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 +// ) -> tower_lsp::jsonrpc::Result> { + +// } \ No newline at end of file diff --git a/src/execute_command/mod.rs b/src/execute_command/mod.rs index bf5628d..19a016b 100644 --- a/src/execute_command/mod.rs +++ b/src/execute_command/mod.rs @@ -4,6 +4,9 @@ use tower_lsp::lsp_types::*; use crate::server::Backend; mod diagnostics; +pub use codedoc::*; +mod codedoc; + pub async fn execute_command( backend: &Backend, params: ExecuteCommandParams @@ -17,6 +20,8 @@ pub async fn execute_command( diagnostics::clear_diagnostics(backend, params.arguments).await } + + _ => { Ok(None) } diff --git a/src/lib.rs b/src/lib.rs index 95be780..7ef0d84 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,6 +30,9 @@ pub mod diagnostics; // 格式化 pub mod format; +// 格式化 +pub mod codedoc; + // 基础工具 pub mod utils; diff --git a/src/main.rs b/src/main.rs index dc9ae0d..76af1db 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,6 +24,7 @@ mod document_highlight; mod inlay_hint; mod code_lens; mod utils; +mod codedoc; mod diagnostics; mod format; mod server; diff --git a/src/sources.rs b/src/sources.rs index a11805e..82c16bf 100644 --- a/src/sources.rs +++ b/src/sources.rs @@ -702,7 +702,7 @@ pub fn sv_parser_pipeline( } 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( doc, diff --git a/src/test/mod.rs b/src/test/mod.rs index f415084..012dc0f 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -486,4 +486,37 @@ mod test_file { assert!(is_character_ordered_match("car", "careful")); 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 = 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); + } + } } \ No newline at end of file diff --git a/test/vlog/codedoc.v b/test/vlog/codedoc.v new file mode 100644 index 0000000..424cb47 --- /dev/null +++ b/test/vlog/codedoc.v @@ -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 \ No newline at end of file