768 lines
35 KiB
Rust
768 lines
35 KiB
Rust
use std::fs::{self, File};
|
||
use std::io::BufRead;
|
||
use std::io::BufReader;
|
||
use std::path::PathBuf;
|
||
use regex::Regex;
|
||
use ropey::Rope;
|
||
use tower_lsp::lsp_types::Url;
|
||
use sv_parser::{unwrap_node, Locate, RefNode, SyntaxTree};
|
||
|
||
use crate::sources::recovery_sv_parse;
|
||
use crate::utils::to_escape_path;
|
||
|
||
use super::hdlparam::{FastHdlparam, Macro};
|
||
|
||
#[allow(unused)]
|
||
pub fn sv_parser(path: &str) -> Option<FastHdlparam> {
|
||
// The path of SystemVerilog source file
|
||
let path = PathBuf::from(path);
|
||
// The list of include paths
|
||
let includes: Vec<PathBuf> = 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(&doc, &uri, &None, &includes);
|
||
|
||
// println!("result: {result:?}");
|
||
|
||
if let Some(syntax_tree) = result {
|
||
if let Ok(hdlparam) = make_fast_from_syntaxtree(&syntax_tree, &path) {
|
||
return Some(hdlparam);
|
||
}
|
||
}
|
||
|
||
None
|
||
}
|
||
|
||
pub fn make_fast_from_syntaxtree(syntax_tree: &SyntaxTree, path: &PathBuf) -> Result<FastHdlparam, std::io::Error> {
|
||
// 对不同操作系统文件路径的支持
|
||
let path = to_escape_path(path);
|
||
|
||
let mut hdlparam = FastHdlparam {
|
||
fast_macro: Macro {
|
||
defines: Vec::new(),
|
||
errors: Vec::new(),
|
||
includes: get_includes(&path),
|
||
invalid: Vec::new()
|
||
},
|
||
content: Vec::new()
|
||
};
|
||
let mut ansi_port_last_dir = "";
|
||
|
||
let content = syntax_tree.text.text().split('\n')
|
||
.map(|s| s.to_string())
|
||
.collect::<Vec<String>>();
|
||
// println!("{:?}", syntax_tree);
|
||
// &SyntaxTree is iterable
|
||
for node in syntax_tree {
|
||
match node {
|
||
RefNode::TextMacroDefinition(x) => {
|
||
if let Some(start) = unwrap_node!(x, TextMacroDefinition) {
|
||
let start = get_identifier(start).unwrap();
|
||
let (start_line, start_character) = (start.line, get_column_by_offset(&content, start.offset));
|
||
|
||
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_line, end_character, replacement) = if let Some(RefNode::MacroText(x)) = unwrap_node!(x, MacroText) {
|
||
let replacement = x.nodes.0;
|
||
(replacement.line, get_column_by_offset(&content, replacement.offset) + replacement.len, syntax_tree.get_str(&replacement).unwrap())
|
||
} else {
|
||
(start_line, start_character + start.len, "unknown")
|
||
};
|
||
|
||
hdlparam.add_define(name, replacement, start_line, start_character as u32, end_line, end_character as u32, params_vec);
|
||
}
|
||
}
|
||
RefNode::ModuleDeclaration(x) => {
|
||
let id = unwrap_node!(x, ModuleIdentifier).unwrap();
|
||
let id = get_identifier(id).unwrap();
|
||
let (line, character) = (id.line, get_column_by_offset(&content, id.offset) as u32);
|
||
let end_character = character + id.len as u32;
|
||
let name = syntax_tree.get_str(&id).unwrap();
|
||
hdlparam.new_module(name, line, character, end_character);
|
||
}
|
||
RefNode::ParameterPortDeclaration(x) => {
|
||
if let Some(id) = unwrap_node!(x, ParameterIdentifier) {
|
||
let id = get_identifier(id).unwrap();
|
||
let name = syntax_tree.get_str(&id).unwrap();
|
||
match unwrap_node!(x, ParameterDeclarationParam, ParameterPortDeclarationParamList) {
|
||
Some(RefNode::ParameterDeclarationParam(param_node)) => {
|
||
// println!("{:?}", param_node);
|
||
let keyword_locate = param_node.nodes.0.nodes.0;
|
||
// println!("keyword {:#?}", keyword_locate);
|
||
let (start_line, start_character) = (id.line, get_column_by_offset(&content, keyword_locate.offset) as u32);
|
||
let (mut end_line, mut end_character) = (id.line, start_character + id.len as u32);
|
||
let net_type = match unwrap_node!(param_node, 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"
|
||
};
|
||
let init = if let Some(init) = unwrap_node!(param_node, ConstantMintypmaxExpression) {
|
||
match init {
|
||
RefNode::ConstantMintypmaxExpression(expression) => {
|
||
// println!("expression {:?}", x);
|
||
let param_init = sv_parser::NeedParseExpression::Parameter(expression.clone());
|
||
let (exp, last_locate) = parse_expression(&syntax_tree, ¶m_init);
|
||
(end_line, end_character) = if last_locate != None {
|
||
// println!("param {:?} lastlocate {:?}", name, last_locate);
|
||
(last_locate.unwrap().line, (get_column_by_offset(&content, last_locate.unwrap().offset) + last_locate.unwrap().len) as u32)
|
||
} else {
|
||
(end_line, end_character)
|
||
};
|
||
// println!("end pos {} {}", end_line, end_character);
|
||
exp
|
||
}
|
||
_ => "unknown".to_string()
|
||
}
|
||
} else {
|
||
"unknown".to_string()
|
||
};
|
||
hdlparam.add_parameter(name, net_type, init.as_str(), start_line, start_character, end_line, end_character);
|
||
}
|
||
_ => ()
|
||
}
|
||
}
|
||
}
|
||
RefNode::ParameterDeclaration(x) => {
|
||
if let Some(id) = unwrap_node!(x, ParameterIdentifier) {
|
||
let id = get_identifier(id).unwrap();
|
||
let name = syntax_tree.get_str(&id).unwrap();
|
||
match unwrap_node!(x, ParameterDeclarationParam, ParameterPortDeclarationParamList) {
|
||
Some(RefNode::ParameterDeclarationParam(param_node)) => {
|
||
// println!("{:?}", param_node);
|
||
let keyword_locate = param_node.nodes.0.nodes.0;
|
||
// println!("keyword {:#?}", keyword_locate);
|
||
let (start_line, start_character) = (id.line, get_column_by_offset(&content, keyword_locate.offset) as u32);
|
||
let (mut end_line, mut end_character) = (id.line, start_character + id.len as u32);
|
||
let net_type = match unwrap_node!(param_node, 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"
|
||
};
|
||
let init = if let Some(init) = unwrap_node!(param_node, ConstantMintypmaxExpression) {
|
||
match init {
|
||
RefNode::ConstantMintypmaxExpression(expression) => {
|
||
// println!("expression {:?}", x);
|
||
let param_init = sv_parser::NeedParseExpression::Parameter(expression.clone());
|
||
let (exp, last_locate) = parse_expression(&syntax_tree, ¶m_init);
|
||
(end_line, end_character) = if last_locate != None {
|
||
// println!("param {:?} lastlocate {:?}", name, last_locate);
|
||
(last_locate.unwrap().line, (get_column_by_offset(&content, last_locate.unwrap().offset) + last_locate.unwrap().len) as u32)
|
||
} else {
|
||
(end_line, end_character)
|
||
};
|
||
// println!("end pos {} {}", end_line, end_character);
|
||
exp
|
||
}
|
||
_ => "unknown".to_string()
|
||
}
|
||
} else {
|
||
"unknown".to_string()
|
||
};
|
||
hdlparam.add_parameter(name, net_type, init.as_str(), start_line, start_character, end_line, end_character);
|
||
}
|
||
_ => ()
|
||
}
|
||
}
|
||
}
|
||
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 (dir_line, dir_character) = (id.line, get_column_by_offset(&content, id.offset) as u32);
|
||
|
||
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 (start_line, start_character, end_line, end_character) =
|
||
(dir_line, dir_character, id.line, (get_column_by_offset(&content, id.offset) + id.len) as u32);
|
||
|
||
hdlparam.add_port(name, dir_type, net_type, width.as_str(), start_line, start_character,
|
||
end_line, end_character);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
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_line, end_character) = (name_locate.line, (character + name_locate.len) as u32);
|
||
|
||
let id = unwrap_node!(x, PortDirection);
|
||
let (start_line, start_character) = 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();
|
||
(dir_locate.line, get_column_by_offset(&content, dir_locate.offset) as u32)
|
||
} else {
|
||
(name_locate.line, character as u32)
|
||
};
|
||
|
||
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()
|
||
};
|
||
|
||
hdlparam.add_port(name, ansi_port_last_dir, net_type, width.as_str(), start_line, start_character, end_line, end_character);
|
||
}
|
||
}
|
||
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();
|
||
|
||
if let Some(id) = unwrap_node!(x, HierarchicalInstance) {
|
||
let id = get_identifier(id).unwrap();
|
||
let name = syntax_tree.get_str(&id).unwrap();
|
||
let (line, character) = (id.line, get_column_by_offset(&content, id.offset) as u32);
|
||
let end_character = character + id.len as u32;
|
||
|
||
let (param_start_line, param_start_character,
|
||
param_end_line, param_end_character) = match unwrap_node!(x, ListOfParameterAssignments) {
|
||
Some(RefNode::ListOfParameterAssignments(x)) => {
|
||
let param_assignments = sv_parser::NeedGetLocate::ParamAssignments(x.clone());
|
||
get_port_parameter_range(&content, ¶m_assignments)
|
||
}
|
||
_ => (0, 0, 0, 0)
|
||
};
|
||
|
||
let (port_start_line, port_start_character,
|
||
port_end_line, port_end_character) = match unwrap_node!(x, ListOfPortConnections) {
|
||
Some(RefNode::ListOfPortConnections(x)) => {
|
||
let param_assignments = sv_parser::NeedGetLocate::PortConnections(x.clone());
|
||
get_port_parameter_range(&content, ¶m_assignments)
|
||
}
|
||
_ => (0, 0, 0, 0)
|
||
};
|
||
|
||
hdlparam.add_instance(name, inst_type, line, character, end_character,
|
||
param_start_line, param_start_character, param_end_line, param_end_character,
|
||
port_start_line, port_start_character, port_end_line, port_end_character
|
||
);
|
||
}
|
||
}
|
||
}
|
||
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();
|
||
|
||
match unwrap_node!(x, NInputGateInstance, NOutputGateInstance) {
|
||
Some(id) => {
|
||
let id = get_identifier(id).unwrap();
|
||
let name = syntax_tree.get_str(&id).unwrap();
|
||
let (line, character) = (id.line, get_column_by_offset(&content, id.offset) as u32);
|
||
let end_character = character + id.len as u32;
|
||
|
||
let gate_instance = sv_parser::NeedGetLocate::GateInstantiation(x.clone());
|
||
let (param_start_line, param_start_character, param_end_line, param_end_character) = (0, 0, 0, 0);
|
||
let (port_start_line, port_start_character,
|
||
port_end_line, port_end_character) = get_port_parameter_range(&content, &gate_instance);
|
||
|
||
hdlparam.add_instance(name, inst_type, line, character, end_character,
|
||
param_start_line, param_start_character, param_end_line, param_end_character,
|
||
port_start_line, port_start_character, port_end_line, port_end_character
|
||
);
|
||
}
|
||
_ => ()
|
||
}
|
||
}
|
||
_ => ()
|
||
}
|
||
}
|
||
|
||
// update_module_range(&path, &mut hdlparam);
|
||
|
||
Ok(hdlparam)
|
||
}
|
||
|
||
fn get_port_parameter_range(content: &[String], x: &sv_parser::NeedGetLocate) -> (u32, u32, u32, u32) {
|
||
let locate = get_first_last_locate(&x);
|
||
if locate.is_none() {
|
||
(0,0,0,0)
|
||
} else {
|
||
(
|
||
locate.unwrap().0.line, get_column_by_offset(&content, locate.unwrap().0.offset) as u32,
|
||
locate.unwrap().1.line, (get_column_by_offset(&content, locate.unwrap().1.offset) + locate.unwrap().1.len) as u32
|
||
)
|
||
}
|
||
}
|
||
|
||
fn get_first_last_locate(x: &sv_parser::NeedGetLocate) -> 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 };
|
||
|
||
match x {
|
||
sv_parser::NeedGetLocate::GateInstantiation(gate) => {
|
||
for node in gate {
|
||
match unwrap_node!(node, InputTerminal, OutputTerminal) {
|
||
Some(RefNode::InputTerminal(x)) => {
|
||
if let Some(id) = unwrap_node!(x, Identifier) {
|
||
let locate = get_identifier(id).unwrap();
|
||
if locate != last_locate { last_locate = locate; }
|
||
if first_locate.offset == 0 { first_locate = locate; };
|
||
} else if let Some(RefNode::Expression(x)) = unwrap_node!(x, Expression) {
|
||
let exp = sv_parser::NeedParseExpression::Expression(x.clone());
|
||
if let Some(locate) = parse_expression_only_locate(&exp) {
|
||
if locate != last_locate { last_locate = locate; }
|
||
if first_locate.offset == 0 { first_locate = locate; };
|
||
}
|
||
}
|
||
}
|
||
Some(RefNode::OutputTerminal(x)) => {
|
||
if let Some(id) = unwrap_node!(x, Identifier) {
|
||
let locate = get_identifier(id).unwrap();
|
||
if locate != last_locate { last_locate = locate; }
|
||
if first_locate.offset == 0 { first_locate = locate; };
|
||
} else if let Some(RefNode::Expression(x)) = unwrap_node!(x, Expression) {
|
||
let exp = sv_parser::NeedParseExpression::Expression(x.clone());
|
||
if let Some(locate) = parse_expression_only_locate(&exp) {
|
||
if locate != last_locate { last_locate = locate; }
|
||
if first_locate.offset == 0 { first_locate = locate; };
|
||
}
|
||
}
|
||
}
|
||
_ => ()
|
||
}
|
||
}
|
||
}
|
||
_ => {
|
||
for node in x {
|
||
match unwrap_node!(node, SimpleIdentifier, Symbol) {
|
||
Some(RefNode::SimpleIdentifier(x)) => {
|
||
let locate = x.nodes.0;
|
||
if locate != last_locate { last_locate = locate; }
|
||
if first_locate.offset == 0 { first_locate = locate; };
|
||
}
|
||
Some(RefNode::Symbol(x)) => {
|
||
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))
|
||
}
|
||
}
|
||
|
||
fn parse_expression_only_locate(x: &sv_parser::NeedParseExpression) -> Option<Locate> {
|
||
let mut last_locate = Locate { offset: 0, line: 0, len: 0 };
|
||
|
||
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;
|
||
}
|
||
}
|
||
Some(RefNode::Symbol(x)) => {
|
||
let locate = x.nodes.0;
|
||
if locate != last_locate {
|
||
last_locate = locate;
|
||
}
|
||
}
|
||
Some(RefNode::UnsignedNumber(x)) => {
|
||
let locate = x.nodes.0;
|
||
if locate != last_locate {
|
||
last_locate = locate;
|
||
}
|
||
}
|
||
Some(RefNode::HexNumber(x)) => {
|
||
let locate = x.nodes.1.nodes.0;
|
||
if locate != last_locate {
|
||
last_locate = locate;
|
||
}
|
||
}
|
||
Some(RefNode::OctalNumber(x)) => {
|
||
let locate = x.nodes.1.nodes.0;
|
||
if locate != last_locate {
|
||
last_locate = locate;
|
||
}
|
||
}
|
||
Some(RefNode::BinaryNumber(x)) => {
|
||
let locate = x.nodes.1.nodes.0;
|
||
if locate != last_locate {
|
||
last_locate = locate;
|
||
}
|
||
}
|
||
_ => ()
|
||
}
|
||
}
|
||
|
||
if last_locate.offset == 0 {
|
||
Some(last_locate)
|
||
} else {
|
||
None
|
||
}
|
||
}
|
||
|
||
fn parse_expression(syntax_tree: &SyntaxTree, x: &sv_parser::NeedParseExpression) -> (String, Option<Locate>) {
|
||
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))
|
||
}
|
||
}
|
||
|
||
fn get_identifier(node: RefNode) -> Option<Locate> {
|
||
// 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,
|
||
}
|
||
}
|
||
|
||
fn get_includes(path: &PathBuf) -> Vec<crate::core::hdlparam::Include> {
|
||
let mut includes = Vec::new();
|
||
|
||
let file = File::open(path).unwrap();
|
||
let reader = BufReader::new(file);
|
||
|
||
for (line_number, line_content) in reader.lines().enumerate() {
|
||
let line_content = line_content.unwrap();
|
||
|
||
if line_content.trim().starts_with("`include") {
|
||
|
||
let parts: Vec<&str> = line_content.split_whitespace().collect();
|
||
|
||
if parts.len() >= 2 {
|
||
let path = parts[1];
|
||
let last_character = line_content.find(path).unwrap() + path.len();
|
||
|
||
includes.push(crate::core::hdlparam::Include {
|
||
path: path.to_string(),
|
||
range: crate::core::hdlparam::Range {
|
||
start: crate::core::hdlparam::Position {
|
||
line: (line_number + 1) as u32, character: 1
|
||
},
|
||
end: crate::core::hdlparam::Position {
|
||
line: (line_number + 1) as u32, character: last_character as u32
|
||
}
|
||
}
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
includes
|
||
}
|
||
|
||
#[allow(unused)]
|
||
fn update_module_range(path: &PathBuf, hdlparam: &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<String> = 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() {
|
||
hdlparam.update_module_range(&module_name, (line_number + 1) as u32, current_offset as u32);
|
||
// println!("Module {} ends.", module_name);
|
||
}
|
||
}
|
||
}
|
||
_ => ()
|
||
}
|
||
}
|
||
}
|
||
|
||
fn get_column_by_offset(content: &[String], offset: usize) -> usize {
|
||
let mut current_offset = 0;
|
||
|
||
for line_content in content {
|
||
let line_length = line_content.len() + 1; // +1 for newline character
|
||
// println!("now line {} len {}", line_content, line_length);
|
||
// println!("now offset {} offset {}", current_offset + line_length, offset);
|
||
if current_offset + line_length > offset {
|
||
return offset - current_offset + 1;
|
||
}
|
||
current_offset += line_length;
|
||
}
|
||
|
||
1 // if offset over the file lentgh,return 1
|
||
}
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use std::{fs, path::Path};
|
||
use super::sv_parser;
|
||
|
||
const TESTFILES_DIR: &str = "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<dyn std::error::Error>> {
|
||
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(())
|
||
}
|
||
} |