This commit is contained in:
锦恢 2024-11-11 21:06:21 +08:00
commit 9333ed0272
5 changed files with 193355 additions and 1 deletions

25893
primitive_files/verilog0.xml Normal file

File diff suppressed because it is too large Load Diff

97703
primitive_files/verilog1.xml Normal file

File diff suppressed because it is too large Load Diff

69504
primitive_files/verilog2.xml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -4,4 +4,6 @@ pub mod sv_parser;
pub mod vhdl_parser; pub mod vhdl_parser;
pub mod cache_storage; pub mod cache_storage;
pub mod primitive_parser;

View File

@ -0,0 +1,252 @@
use std::fs;
use std::path::PathBuf;
use std::{collections::HashMap, fs::File};
use std::io::BufReader;
use bincode::Error;
use ropey::Rope;
use serde::{Serialize, Deserialize};
use sv_parser::{unwrap_node, RefNode};
use xml::reader::{EventReader, XmlEvent};
use super::hdlparam::{FastHdlparam, InstParameter, Macro, Range};
use super::sv_parser::{get_identifier, get_instance_params, get_instance_ports, get_position, get_pp_range};
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Template {
pub text: String,
pub fast: FastHdlparam
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
pub struct PrimitiveXml {
pub name_to_template: HashMap<String, Template>
}
pub fn init_parse_primitive_files() -> Result<PrimitiveXml, Error> {
const XML_DIR: &str = "../../primitive_files";
let mut primitive_xml = PrimitiveXml::default();
for entry in fs::read_dir(XML_DIR)? {
let entry = entry?;
let path = entry.path();
if let Some(ext) = path.extension() {
if ext == "xml" {
if let Ok(primitive) = xml_parser(path.to_str().unwrap()) {
primitive_xml.name_to_template.extend(
primitive.name_to_template
);
};
}
}
}
Ok(primitive_xml)
}
fn xml_parser(path: &str) -> Result<PrimitiveXml, Error> {
let file = File::open(path)?;
let file = BufReader::new(file);
let mut parser = EventReader::new(file);
let mut primitive_xml = PrimitiveXml::default();
loop {
match parser.next() {
Ok(XmlEvent::StartElement { name, .. }) => {
if name.local_name == "Template" {
let (inst_name , template) = xml_parse_template(&mut parser);
primitive_xml.name_to_template.insert(inst_name, template);
}
}
Ok(XmlEvent::EndElement { name }) => {
if name.local_name == "RootFolder" { break; }
}
_ => ()
}
}
Ok((primitive_xml))
}
fn xml_parse_template(parser: &mut EventReader<BufReader<File>>) -> (String, Template) {
loop {
match parser.next() {
Ok(XmlEvent::Characters(text)) => {
if text.contains("Cut code below this line") {
if let Some((name, text, fast)) = xml_parse_text(&text) {
return (name, Template { text, fast });
}
}
}
_ => ()
}
}
}
fn xml_parse_text(text: &str) -> Option<(String, String, FastHdlparam)> {
let module_string = "module primitive_module();\n".to_string() + text + "\nendmodule";
if let Ok((syntax_tree, _)) = sv_parser::parse_sv_str(
&module_string,
PathBuf::new(),
&HashMap::new(),
&Vec::<PathBuf>::new(),
true,
true
) {
let doc = Rope::from_str(syntax_tree.text.text());
let mut res_inst_name = String::new();
let mut hdlparam = FastHdlparam {
fast_macro: Macro {
defines: Vec::new(),
errors: Vec::new(),
includes: Vec::new(),
invalid: Vec::new()
},
content: Vec::new(),
file_type: "primitive".to_string()
};
let res_text = syntax_tree.text.text().to_string();
for node in &syntax_tree {
match node {
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 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);
}
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::<InstParameter>::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();
res_inst_name = inst_type.to_string();
hdlparam.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();
hdlparam.add_instance(
name, inst_type, inst_range,
param_range, Vec::<InstParameter>::new(),
port_range, inst_port_assignments
);
}
_ => ()
}
}
_ => ()
}
}
Some((res_inst_name, res_text, hdlparam))
} else {
None
}
}
#[cfg(test)]
mod tests {
use std::{fs, path::Path};
use super::xml_parser;
const TESTFILE: &str = "D:\\work\\playground\\digital-lsp-server\\primitive_files\\verilog1.xml";
const TESTDIR: &str = "/home/dide/project/Digital-Test/Digital-IDE-test/user/factory/xilinx";
#[test]
fn test_xml() {
let _ = xml_parser(TESTFILE);
}
#[test]
fn test_dir() {
// 判断路径是否存在且为文件夹
let path = Path::new(TESTDIR);
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 == "xml" {
println!("Test file: {:?}", path);
let file_path = path.to_str().unwrap();
let _ = xml_parser(file_path);
}
}
}
}
}
Ok(())
}
}