use std::fs::{self, File}; use std::io::BufRead; use std::io::BufReader; use std::path::PathBuf; #[allow(unused)] use log::info; use regex::Regex; use ropey::Rope; use tower_lsp::lsp_types::Url; use sv_parser::{unwrap_locate, unwrap_node, EventIter, ListOfParamAssignments, Locate, NodeEvent, ParamAssignment, ParameterDeclaration, RefNode, SyntaxTree}; use crate::core::hdlparam::{AssignType, Position, Range}; use crate::sources::{recovery_sv_parse_with_retry, LSPSupport}; use crate::utils::to_escape_path; use super::hdlparam::{self, FastHdlparam, Include, InstParameter, InstPort, Macro}; macro_rules! advance_until_leave { ($tokens:ident, $tree:ident, $event_iter:ident, $node:path) => {{ let mut result: Option = None; while let Some(event) = $event_iter.next() { match event { NodeEvent::Leave(x) => match x { $node(node) => { result = Some($node(node)); break; } RefNode::Locate(node) => { $tokens.push(' '); $tokens.push_str($tree.get_str(node).unwrap()); } _ => (), }, NodeEvent::Enter(_) => (), } } result }}; } macro_rules! skip_until_enter { ($tree:ident, $event_iter:ident, $node:path, $type:ty) => {{ let mut result: Option<$type> = None; while let Some(event) = $event_iter.next() { match event { NodeEvent::Enter(x) => match x { $node(node) => { result = Some(node); break; } _ => (), }, NodeEvent::Leave(_) => (), } } result }}; } #[allow(unused)] pub fn sv_parser(path: &str) -> Option { // The path of SystemVerilog source file let path = PathBuf::from(path); // The list of include paths let includes: Vec = Vec::new(); let text = match fs::read_to_string(&path) { Ok(text) => text, Err(_) => return None }; 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 { if let Ok(fast) = make_fast_from_syntaxtree(&syntax_tree) { return Some(fast); } } None } pub fn make_fast_from_syntaxtree( syntax_tree: &SyntaxTree ) -> Result { // 对不同操作系统文件路径的支持 let mut fast: FastHdlparam = FastHdlparam { fast_macro: Macro { defines: Vec::new(), errors: Vec::new(), includes: Vec::::new(), invalid: Vec::new() }, content: Vec::new(), entitys: Vec::new(), file_type: "common".to_string() }; let mut ansi_port_last_dir = ""; // &SyntaxTree is iterable let doc = Rope::from_str(syntax_tree.text.text()); // 上一个 module 可以在 fast 的 content 的最后一个中找到 for node in syntax_tree { match node { RefNode::IncludeCompilerDirective(x) => { match x { sv_parser::IncludeCompilerDirective::DoubleQuote(x) => { let (_, ref keyword, ref literal) = x.nodes; let (keyword_locate, _) = keyword.nodes; let (literal_locate, _) = literal.nodes; let include_path_string = syntax_tree.get_str_trim(literal).unwrap().trim_matches('"'); let include_range = Range { start: get_position(&doc, keyword_locate, 0), end: get_position(&doc, literal_locate, literal_locate.len) }; fast.fast_macro.includes.push(Include { path: include_path_string.to_string(), range: include_range }); } sv_parser::IncludeCompilerDirective::AngleBracket(_) => { }, sv_parser::IncludeCompilerDirective::TextMacroUsage(_) => { }, } } RefNode::TextMacroDefinition(x) => { if let Some(start) = unwrap_node!(x, TextMacroDefinition) { let start = get_identifier(start).unwrap(); let start_pos = get_position(&doc, start, 0); let name = if let Some(name) = unwrap_node!(x, TextMacroName) { let name = get_identifier(name).unwrap(); syntax_tree.get_str(&name).unwrap() } else { "unknown" }; let mut params_vec = Vec::new(); if let Some(RefNode::ListOfFormalArguments(x)) = unwrap_node!(x, ListOfFormalArguments) { for node in x { if let RefNode::FormalArgument(x) = node { let param_name = if let Some(param_name) = unwrap_node!(x, SimpleIdentifier) { let param_name = get_identifier(param_name).unwrap(); syntax_tree.get_str(¶m_name).unwrap() } else { "unknown" }; let param_val = match unwrap_node!(x, DefaultText) { Some(RefNode::DefaultText(x)) => syntax_tree.get_str(&x.nodes.0).unwrap(), _ => "Unknown" }; params_vec.push(crate::core::hdlparam::DefineParam { name: param_name.to_string(), value: param_val.to_string() }); } } } let (end_pos, replacement) = if let Some(RefNode::MacroText(x)) = unwrap_node!(x, MacroText) { let replacement = x.nodes.0; (get_position(&doc, replacement,replacement.len), syntax_tree.get_str(&replacement).unwrap()) } else { (get_position(&doc, start, start.len), "unknown") }; let define_range = Range { start: start_pos, end: end_pos }; 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 = 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(); fast.new_module(name, module_range); } RefNode::ParameterDeclaration(param_dec) => { let mut event_iter = param_dec.into_iter().event(); match param_dec { ParameterDeclaration::Param(x) => { let keyword_locate = &x.nodes.0.nodes.0; // println!("keyword {:#?}", keyword_locate); let start_pos = get_position(&doc, keyword_locate.clone(), 0); let net_type = match unwrap_node!(RefNode::ParameterDeclarationParam(x), DataType) { Some(RefNode::DataType(data_type)) => { let id = unwrap_node!(data_type, SimpleIdentifier, Keyword); if id == None { "wire" } else { let id = get_identifier(id.unwrap()).unwrap(); syntax_tree.get_str(&id).unwrap() } } _ => "wire" }; for (index, (name, loc, init)) in list_param_assignment(syntax_tree, &x.nodes.2, &mut event_iter).iter().enumerate() { let start_pos = if index != 0 { get_position(&doc, loc.clone(), 0) } else { start_pos.clone() }; let end_pos = get_position(&doc, loc.clone(), loc.len); let param_range = Range { start: start_pos, end: end_pos }; fast.add_parameter(name, net_type, init, param_range); } } _ => () } } RefNode::PortDeclaration(x) => { if let Some(id) = unwrap_node!(x, InputDeclaration, OutputDeclaration, InoutDeclaration) { let id = get_identifier(id).unwrap(); let dir_type = syntax_tree.get_str(&id).unwrap(); let start_pos = get_position(&doc, id, 0); let net_type = match unwrap_node!(x, DataType, ImplicitDataType) { Some(RefNode::DataType(x)) => { let id = unwrap_node!(x, Keyword); if id != None { syntax_tree.get_str(&get_identifier(id.unwrap()).unwrap()).unwrap() } else { "unknown" } }, Some(RefNode::ImplicitDataType(_)) => "wire", _ => "unknown" }; let width = match unwrap_node!(x, PackedDimensionRange) { Some(RefNode::PackedDimensionRange(x)) => { let port_width = sv_parser::NeedParseExpression::Port(x.clone()); let (width, _) = parse_expression(&syntax_tree, &port_width); width } _ => "1".to_string() }; if let Some(RefNode::ListOfPortIdentifiers(x)) = unwrap_node!(x, ListOfPortIdentifiers) { for node in x { if let RefNode::PortIdentifier(x) = node { let id = unwrap_node!(x, Identifier).unwrap(); let id = get_identifier(id).unwrap(); let name = syntax_tree.get_str(&id).unwrap(); let port_range = Range { start: start_pos.clone(), end: get_position(&doc, id, id.len) }; fast.add_port(name, dir_type, net_type, width.as_str(), port_range); } } } } } RefNode::AnsiPortDeclaration(x) => { if let Some(id) = unwrap_node!(x, PortIdentifier) { let name_locate = get_identifier(id).unwrap(); let name = syntax_tree.get_str(&name_locate).unwrap(); // let character = get_column_by_offset(&content, name_locate.offset); let end_pos = get_position(&doc, name_locate, name_locate.len); let id = unwrap_node!(x, PortDirection); let port_range = if id != None { let id = id.unwrap(); let dir_locate = get_identifier(id).unwrap(); ansi_port_last_dir = syntax_tree.get_str(&dir_locate).unwrap(); Range { start: get_position(&doc, dir_locate, 0), end: end_pos } } else { Range { start: get_position(&doc, name_locate, 0), end: end_pos } }; let net_type = if unwrap_node!(x, AnsiPortDeclarationVariable) != None { "wire" } else { match unwrap_node!(x, DataType, ImplicitDataType) { Some(RefNode::DataType(x)) => { let id = unwrap_node!(x, Keyword); if id != None { syntax_tree.get_str(&get_identifier(id.unwrap()).unwrap()).unwrap() } else { "unknown" } }, Some(RefNode::ImplicitDataType(_)) => "wire", _ => "unknown" } }; let width = match unwrap_node!(x, PackedDimensionRange) { Some(RefNode::PackedDimensionRange(x)) => { let port_width = sv_parser::NeedParseExpression::Port(x.clone()); let (width, _) = parse_expression(&syntax_tree, &port_width); width } _ => "1".to_string() }; fast.add_port(name, ansi_port_last_dir, net_type, width.as_str(), port_range); } } RefNode::ModuleInstantiation(x) => { if let Some(id) = unwrap_node!(x, ModuleIdentifier) { let id = get_identifier(id).unwrap(); let inst_type = syntax_tree.get_str(&id).unwrap(); let start_pos = get_position(&doc, id, 0); let range = get_pp_range(&doc, RefNode::ModuleInstantiation(x)); let inst_range = Range { start: start_pos, end: range.end }; if let Some(id) = unwrap_node!(x, HierarchicalInstance) { let hier_node = id.clone(); let id = get_identifier(id).unwrap(); let name = syntax_tree.get_str(&id).unwrap(); let param_range = match unwrap_node!(x, ParameterValueAssignment) { Some(inst_node) => { get_pp_range(&doc, inst_node).to_option() } _ => None }; let inst_param_assignments = if let Some(param_node) = unwrap_node!(x, ParameterValueAssignment) { get_instance_params(syntax_tree, &doc, param_node) } else { Vec::::new() }; let inst_port_assignments = get_instance_ports(&syntax_tree, &doc, hier_node.clone()); let port_range = get_pp_range(&doc, hier_node).to_option(); fast.add_instance( name, inst_type, inst_range, param_range, inst_param_assignments, port_range, inst_port_assignments ); } } } RefNode::GateInstantiation(x) => { let id = unwrap_node!(x, GateInstantiation).unwrap(); let id = get_identifier(id).unwrap(); let inst_type = syntax_tree.get_str(&id).unwrap(); let start_pos = get_position(&doc, id, 0); let range = get_pp_range(&doc, RefNode::GateInstantiation(x)); let inst_range = Range { start: start_pos, end: range.end }; match unwrap_node!(x, NInputGateInstance, NOutputGateInstance) { Some(id) => { let gate_node = id.clone(); let id = get_identifier(id).unwrap(); let name = syntax_tree.get_str(&id).unwrap(); let param_range = None; let inst_port_assignments = get_instance_ports(&syntax_tree, &doc, gate_node.clone()); let port_range = get_pp_range(&doc, gate_node).to_option(); fast.add_instance( name, inst_type, inst_range, param_range, Vec::::new(), port_range, inst_port_assignments ); } _ => () } } 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.character; } }, _ => {} } } _ => () } } // update_module_range(&path, &mut hdlparam); Ok(fast) } // 获取 port 或者 param 的 range /// 返回的四元组:(start_line, start_character, end_line, end_character) pub fn get_pp_range(doc: &Rope, node: RefNode) -> Range { if let Some(locate) = get_first_last_locate(node) { Range { start: get_position(doc, locate.0, 0), end: get_position(doc, locate.1, locate.1.len) } } else { Range { start: Position { line: 0, character: 0}, end: Position { line: 0, character: 0} } } } fn get_first_last_locate(node: RefNode) -> Option<(Locate, Locate)> { let mut first_locate = Locate { offset: 0, line: 0, len: 0 }; let mut last_locate = Locate { offset: 0, line: 0, len: 0 }; for n in node { if let RefNode::Symbol(x) = n { let locate = x.nodes.0; if locate != last_locate { last_locate = locate; } if first_locate.offset == 0 { first_locate = locate; }; } } if last_locate.offset == 0 { None } else { Some((first_locate, last_locate)) } } pub fn get_instance_params(syntax_tree: &SyntaxTree, doc: &Rope, node: RefNode) -> Vec { let mut parameters = Vec::new(); for list in node { match unwrap_node!(list, ListOfParameterAssignmentsNamed, ListOfParameterAssignmentsOrdered) { Some(RefNode::ListOfParameterAssignmentsNamed(x)) => { for assign in x { if let RefNode::NamedParameterAssignment(ident) = assign { let param_range = get_pp_range(doc, assign); let param_name_locate = get_identifier(RefNode::ParameterIdentifier(&(ident.nodes.1))); let param_name = syntax_tree.get_str(¶m_name_locate).unwrap(); let name = if let (_, Some(name_expr), _) = ident.nodes.2.nodes.clone() { if let Some(RefNode::Expression(name_expr)) = unwrap_node!(name_expr.into_iter(), Expression) { let expr = sv_parser::NeedParseExpression::Expression(name_expr.clone()); let (expr, _) = parse_expression(syntax_tree, &expr); Some(expr) } else { None } } else { None }; let param = InstParameter { parameter: Some(param_name.to_string()), assign_val: name, assign_type: AssignType::Named, range: param_range }; parameters.push(param); }; } } Some(RefNode::ListOfParameterAssignmentsOrdered(x)) => { for assign in x { if let RefNode::OrderedParameterAssignment(ident) = assign { let expr = ident.nodes.0.clone(); if let Some(RefNode::Expression(expr)) = unwrap_node!(expr.into_iter(), Expression) { let start_locate = get_identifier(RefNode::Expression(expr)); let expr = sv_parser::NeedParseExpression::Expression(expr.clone()); let (expr, end_locate) = parse_expression(syntax_tree, &expr); let start_locate = start_locate.unwrap_or(Locate { offset: 0, line: 0, len: 0 }); let end_locate = end_locate.unwrap_or(start_locate); let param = InstParameter { parameter: None, assign_val: Some(expr), assign_type: AssignType::Ordered, range: Range { start: get_position(doc, start_locate, 0), end: get_position(doc, end_locate, end_locate.len) } }; parameters.push(param); } } } } _ => {} } } parameters.sort_by_key(|p| p.range.clone()); parameters.dedup_by_key(|p| p.range.clone()); parameters } pub fn get_instance_ports(syntax_tree: &SyntaxTree, doc: &Rope, node: RefNode) -> Vec { let mut ports = Vec::new(); for list in node { match unwrap_node!(list, ListOfPortConnectionsNamed, ListOfPortConnectionsOrdered, InputTerminal, OutputTerminal) { Some(RefNode::ListOfPortConnectionsNamed(x)) => { for connect in x { if let RefNode::NamedPortConnectionIdentifier(ident) = connect { let port_range = get_pp_range(doc, connect); let port_name_locate = get_identifier(RefNode::PortIdentifier(&(ident.nodes.2))); let port_name = syntax_tree.get_str(&port_name_locate).unwrap(); let name = if ident.nodes.3.is_some() { if let (_, Some(name_expr), _) = ident.nodes.3.clone().unwrap().nodes { let expr = sv_parser::NeedParseExpression::Expression(name_expr); let (expr, _) = parse_expression(syntax_tree, &expr); Some(expr) } else { None } } else { None }; let port = InstPort { port: Some(port_name.to_string()), assign_val: name, assign_type: AssignType::Named, range: port_range }; ports.push(port); }; } } Some(RefNode::ListOfPortConnectionsOrdered(x)) => { for connect in x { if let RefNode::OrderedPortConnection(ident) = connect { if let Some(expr) = ident.nodes.1.clone() { let start_locate = get_identifier(RefNode::Expression(&expr)); let expr = sv_parser::NeedParseExpression::Expression(expr); let (expr, end_locate) = parse_expression(syntax_tree, &expr); let start_locate = start_locate.unwrap_or(Locate { offset: 0, line: 0, len: 0 }); let end_locate = end_locate.unwrap_or(start_locate); let port = InstPort { port: None, assign_val: Some(expr), assign_type: AssignType::Ordered, range: Range { start: get_position(doc, start_locate, 0), end: get_position(doc, end_locate, end_locate.len) } }; ports.push(port); } }; } } Some(RefNode::InputTerminal(x)) => { let expr = x.nodes.0.clone(); let start_locate = get_identifier(RefNode::Expression(&expr)); let expr = sv_parser::NeedParseExpression::Expression(expr); let (expr, end_locate) = parse_expression(syntax_tree, &expr); let start_locate = start_locate.unwrap_or(Locate { offset: 0, line: 0, len: 0 }); let end_locate = end_locate.unwrap_or(start_locate); let port = InstPort { port: None, assign_val: Some(expr), assign_type: AssignType::Ordered, range: Range { start: get_position(doc, start_locate, 0), end: get_position(doc, end_locate, end_locate.len) } }; ports.push(port); } Some(RefNode::OutputTerminal(x)) => { let expr = x.nodes.0.clone(); let start_locate = get_identifier(RefNode::NetLvalue(&expr)); let expr = sv_parser::NeedParseExpression::NetValue(expr); let (expr, end_locate) = parse_expression(syntax_tree, &expr); let start_locate = start_locate.unwrap_or(Locate { offset: 0, line: 0, len: 0 }); let end_locate = end_locate.unwrap_or(start_locate); let port = InstPort { port: None, assign_val: Some(expr), assign_type: AssignType::Ordered, range: Range { start: get_position(doc, start_locate, 0), end: get_position(doc, end_locate, end_locate.len) } }; ports.push(port); } _ => () } } ports.sort_by_key(|p| p.range.clone()); ports.dedup_by_key(|p| p.range.clone()); ports } fn parse_expression(syntax_tree: &SyntaxTree, x: &sv_parser::NeedParseExpression) -> (String, Option) { let mut last_locate = Locate { offset: 0, line: 0, len: 0 }; let mut expression = String::new(); for node in x { // println!("parse expression::node {:#?}", node); match unwrap_node!(node, SimpleIdentifier, Symbol, UnsignedNumber, HexNumber, OctalNumber, BinaryNumber) { Some(RefNode::SimpleIdentifier(x)) => { let locate = x.nodes.0; if locate != last_locate { last_locate = locate; let s = syntax_tree.get_str(&locate).unwrap(); expression = expression + s; // println!("parse expression {}", s); } } Some(RefNode::Symbol(x)) => { let locate = x.nodes.0; if locate != last_locate { last_locate = locate; let s = syntax_tree.get_str(&x.nodes.0).unwrap(); expression = expression + s; // println!("parse expression {}", s); } } Some(RefNode::UnsignedNumber(x)) => { let locate = x.nodes.0; if locate != last_locate { last_locate = locate; let s = syntax_tree.get_str(&x.nodes.0).unwrap(); expression = expression + s; // println!("parse expression {}", s); } } Some(RefNode::HexNumber(x)) => { let locate = x.nodes.1.nodes.0; if locate != last_locate { last_locate = locate; let size = if x.nodes.0 != None { syntax_tree.get_str(&x.nodes.0).unwrap() } else { "" }; let base = syntax_tree.get_str(&x.nodes.1.nodes.0).unwrap(); let number = syntax_tree.get_str(&x.nodes.2.nodes.0).unwrap(); expression = expression + size + base + number; // println!("parse expression {}", expression); } } Some(RefNode::OctalNumber(x)) => { let locate = x.nodes.1.nodes.0; if locate != last_locate { last_locate = locate; let size = if x.nodes.0 != None { syntax_tree.get_str(&x.nodes.0).unwrap() } else { "" }; let base = syntax_tree.get_str(&x.nodes.1.nodes.0).unwrap(); let number = syntax_tree.get_str(&x.nodes.2.nodes.0).unwrap(); expression = expression + size + base + number; // println!("parse expression {}", expression); } } Some(RefNode::BinaryNumber(x)) => { let locate = x.nodes.1.nodes.0; if locate != last_locate { last_locate = locate; let size = if x.nodes.0 != None { syntax_tree.get_str(&x.nodes.0).unwrap() } else { "" }; let base = syntax_tree.get_str(&x.nodes.1.nodes.0).unwrap(); let number = syntax_tree.get_str(&x.nodes.2.nodes.0).unwrap(); expression = expression + size + base + number; // println!("parse expression {}", expression); } } _ => () } } if expression == "" { ("unknown".to_string(), None) } else { // println!("parse function lastlocate {:?}", last_locate); (expression, Some(last_locate)) } } pub fn get_identifier(node: RefNode) -> Option { // unwrap_node! can take multiple types match unwrap_node!(node, SimpleIdentifier, EscapedIdentifier, Keyword) { Some(RefNode::SimpleIdentifier(x)) => { return Some(x.nodes.0); } Some(RefNode::EscapedIdentifier(x)) => { return Some(x.nodes.0); } Some(RefNode::Keyword(x)) => { return Some(x.nodes.0); } _ => None, } } pub fn get_position(doc: &Rope, locate: Locate, offset: usize) -> Position { let byte = locate.offset + offset; let pos = doc.byte_to_pos(byte); hdlparam::Position::from_lsp_position(&pos) } #[allow(unused)] fn update_module_range(path: &PathBuf, fast: &mut FastHdlparam) { let file = File::open(path).unwrap(); let reader = BufReader::new(file); let re_module = Regex::new(r"^\s*module\s+(\w+)\s*\(").unwrap(); let re_endmodule = Regex::new(r"^\s*endmodule\s*$").unwrap(); let mut current_offset = 0; let mut module_stack: Vec = Vec::new(); for (line_number, line_content) in reader.lines().enumerate() { match line_content { Ok(line) => { let line_length = line.len() + 1; // +1 for newline character current_offset += line_length; if let Some(captures) = re_module.captures(&line) { let module_name = captures.get(1).unwrap().as_str().to_string(); module_stack.push(module_name.clone()); } else if re_endmodule.is_match(&line) { if let Some(module_name) = module_stack.pop() { fast.update_module_range(&module_name, (line_number + 1) as u32, current_offset as u32); // println!("Module {} ends.", module_name); } } } _ => () } } } fn param_assignment( tree: &SyntaxTree, _: &ParamAssignment, event_iter: &mut EventIter, ) -> Option<(String, Locate, String)> { if let Some(param_assign) = skip_until_enter!(tree, event_iter, RefNode::ParamAssignment, &ParamAssignment) { let ident = get_ident(tree, RefNode::ParameterIdentifier(¶m_assign.nodes.0)); let mut type_str = String::new(); advance_until_leave!(type_str, tree, event_iter, RefNode::ParamAssignment); let parts: Vec<&str> = type_str.split_whitespace().collect(); type_str = if let Some(last_part) = parts.last() { last_part.to_string() } else { "unknown".to_string() }; Some((ident.0, ident.1, type_str)) } else { None } } fn list_param_assignment( tree: &SyntaxTree, _: &ListOfParamAssignments, event_iter: &mut EventIter, ) -> Vec<(String, Locate, String)>{ let mut params = Vec::new(); // let mut defs: Vec = Vec::new(); if let Some(p_a_list) = skip_until_enter!( tree, event_iter, RefNode::ListOfParamAssignments, &ListOfParamAssignments ) { for param_assign in p_a_list.nodes.0.contents() { if let Some(assignment) = param_assignment(tree, param_assign, event_iter) { params.push(assignment); } } }; params } /// 找到 node 的 名字,开始的位置和结束的位置 pub fn get_ident(tree: &SyntaxTree, node: RefNode) -> (String, Locate) { let loc = unwrap_locate!(node).unwrap(); let ident_str = tree.get_str(loc).unwrap().to_string(); (ident_str, *loc) } #[cfg(test)] mod tests { use std::{fs, path::Path}; use super::sv_parser; const TESTFILES_DIR: &str = "/home/dide/project/digital-lsp-server/testfiles"; const DIGTIAL_IDE_TEST: &str = "/home/dide/project/Digital-Test/Digital-IDE-test/user"; macro_rules! unwrap_result { ($expr:expr) => { match $expr { Ok(e) => e, Err(_) => return } }; } macro_rules! unwrap_option { ($expr:expr) => { match $expr { Some(e) => e, None => return } }; } #[test] fn test_sv_parse() { let entries = unwrap_result!(fs::read_dir(TESTFILES_DIR)); for entry in entries { let entry = unwrap_result!(entry); let file_path = entry.path(); if file_path.is_file() { let extension = unwrap_option!(file_path.extension()); let file_path = unwrap_option!(file_path.to_str()); if extension == "v" || extension == "sv" { let _ = sv_parser(file_path); } } } } #[test] fn test_digital_ide_test() { // 判断路径是否存在且为文件夹 let path = Path::new(DIGTIAL_IDE_TEST); if path.exists() && path.is_dir() { // 递归遍历文件夹 if let Err(e) = traverse_directory(path) { eprintln!("Error: {}", e); } } else { eprintln!("Path does not exist or is not a directory"); } } fn traverse_directory(dir: &Path) -> Result<(), Box> { if dir.is_dir() { for entry in fs::read_dir(dir)? { let entry = entry?; let path = entry.path(); if path.is_dir() { // 递归遍历子文件夹 traverse_directory(&path)?; } else if path.is_file() { // 检查文件扩展名 if let Some(ext) = path.extension() { if ext == "v" || ext == "sv" { println!("Test file: {:?}", path); // TODO: Check Stack Overflow tests if path.to_str().unwrap() == "/home/dide/project/Digital-Test/Digital-IDE-test/user/src/svlog/tools/ivtest/comp1001.sv" { continue; } if path.to_str().unwrap() == "/home/dide/project/Digital-Test/Digital-IDE-test/user/src/svlog/tools/ivtest/comp1000.sv" { continue; } if path.to_str().unwrap() == "/home/dide/project/Digital-Test/Digital-IDE-test/user/src/svlog/tools/ivtest/br_gh330.sv" { continue; } if path.to_str().unwrap() == "/home/dide/project/Digital-Test/Digital-IDE-test/user/src/svlog/tools/hdlconv/pri_encoder_using_assign.sv" { continue; } let file_path = path.to_str().unwrap(); let _ = sv_parser(file_path); } } } } } Ok(()) } }