Merge branch 'main' of https://github.com/Digital-EDA/digital-lsp-server
This commit is contained in:
commit
9333ed0272
25893
primitive_files/verilog0.xml
Normal file
25893
primitive_files/verilog0.xml
Normal file
File diff suppressed because it is too large
Load Diff
97703
primitive_files/verilog1.xml
Normal file
97703
primitive_files/verilog1.xml
Normal file
File diff suppressed because it is too large
Load Diff
69504
primitive_files/verilog2.xml
Normal file
69504
primitive_files/verilog2.xml
Normal file
File diff suppressed because it is too large
Load Diff
@ -4,4 +4,6 @@ pub mod sv_parser;
|
||||
|
||||
pub mod vhdl_parser;
|
||||
|
||||
pub mod cache_storage;
|
||||
pub mod cache_storage;
|
||||
|
||||
pub mod primitive_parser;
|
||||
|
252
src/core/primitive_parser.rs
Normal file
252
src/core/primitive_parser.rs
Normal 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(())
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user