665 lines
26 KiB
Rust
665 lines
26 KiB
Rust
use std::collections::HashSet;
|
||
use std::path::PathBuf;
|
||
use log::info;
|
||
use vhdl_lang::ast::{AnyDesignUnit, DesignFile};
|
||
use vhdl_lang::{kind_str, Token, VHDLParser, VHDLStandard};
|
||
|
||
use super::hdlparam::*;
|
||
|
||
#[allow(unused)]
|
||
pub fn vhdl_parser(path: &str) -> FastHdlparam {
|
||
// The path of SystemVerilog source file
|
||
let path = PathBuf::from(path);
|
||
|
||
let mut hdlparam = FastHdlparam {
|
||
fast_macro: Macro {
|
||
defines: Vec::new(),
|
||
errors: Vec::new(),
|
||
includes: Vec::new(),
|
||
invalid: Vec::new()
|
||
},
|
||
content: Vec::new(),
|
||
file_type: "common".to_string()
|
||
};
|
||
|
||
let parser = VHDLParser::new(VHDLStandard::VHDL2008);
|
||
let mut diagnostics = Vec::new();
|
||
let (_, design_file) = parser.parse_design_file(&path, &mut diagnostics).unwrap();
|
||
|
||
let mut all_tockens = Vec::new();
|
||
for (tokens, _) in design_file.design_units {
|
||
all_tockens.extend(tokens);
|
||
}
|
||
|
||
hdlparam.content.extend(parse_tokens(all_tockens));
|
||
hdlparam
|
||
}
|
||
|
||
pub fn vhdl_parse(path: &PathBuf) -> Option<DesignFile> {
|
||
let mut diagnostics = Vec::new();
|
||
let parser = VHDLParser::new(VHDLStandard::VHDL2008);
|
||
if let Ok((_, design_file)) = parser.parse_design_file(path, &mut diagnostics) {
|
||
return Some(design_file);
|
||
}
|
||
None
|
||
}
|
||
|
||
pub fn vhdl_parse_str(path: &PathBuf, code: &str) -> Option<DesignFile> {
|
||
let mut diagnostics = Vec::new();
|
||
let parser = VHDLParser::new(VHDLStandard::VHDL2008);
|
||
if let Ok((_, design_file)) = parser.parse_vhdl_str(code, path, &mut diagnostics) {
|
||
return Some(design_file);
|
||
}
|
||
None
|
||
}
|
||
|
||
pub fn new_make_fast_from_design_file(units: Vec<(AnyDesignUnit, Vec<Token>)>, design_file: &DesignFile) -> Option<FastHdlparam> {
|
||
let mut hdlparam = FastHdlparam {
|
||
fast_macro: Macro {
|
||
defines: Vec::new(),
|
||
errors: Vec::new(),
|
||
includes: Vec::new(),
|
||
invalid: Vec::new()
|
||
},
|
||
content: Vec::new(),
|
||
file_type: "common".to_string()
|
||
};
|
||
|
||
|
||
info!("get units {:#?}", units);
|
||
// for (tokens, design_unit) in &design_file.design_units {
|
||
|
||
// }
|
||
|
||
Some(hdlparam)
|
||
}
|
||
|
||
pub fn make_fast_from_design_file(design_file: &DesignFile) -> Option<FastHdlparam> {
|
||
let mut hdlparam = FastHdlparam {
|
||
fast_macro: Macro {
|
||
defines: Vec::new(),
|
||
errors: Vec::new(),
|
||
includes: Vec::new(),
|
||
invalid: Vec::new()
|
||
},
|
||
content: Vec::new(),
|
||
file_type: "common".to_string()
|
||
};
|
||
|
||
let mut all_tockens = Vec::new();
|
||
for (tokens, _) in &design_file.design_units {
|
||
all_tockens.extend(tokens.clone());
|
||
}
|
||
|
||
hdlparam.content.extend(parse_tokens(all_tockens));
|
||
Some(hdlparam)
|
||
}
|
||
|
||
|
||
fn parse_tokens(tokens: Vec<Token>) -> Vec<Module> {
|
||
let mut modules = Vec::new();
|
||
let mut last_module_name = String::new();
|
||
let mut instance_type = HashSet::new();
|
||
|
||
let mut i = 0;
|
||
while i < tokens.len() {
|
||
let token = &tokens[i];
|
||
match kind_str(token.kind) {
|
||
"entity" => {
|
||
let start_pos = tokens[i].pos.range.start;
|
||
i += 1;
|
||
let entity_name = get_value(&tokens[i]);
|
||
|
||
if (i >= 2 as usize) && (kind_str(tokens[i - 2].kind) != "use") || (i < 2) {
|
||
// 遍历整个 entity 内部的 token,找到结束的 token 和代表 port 的 token
|
||
let mut end = i;
|
||
let mut port_begin: usize = 0;
|
||
while (
|
||
end + 1 < tokens.len()) &&
|
||
!(kind_str(tokens[end].kind) == "end" &&
|
||
(kind_str(tokens[end + 1].kind) == "entity" || get_value(&tokens[end + 1]) == entity_name)
|
||
) {
|
||
if kind_str(tokens[end].kind) == "port" {
|
||
port_begin = end;
|
||
}
|
||
end += 1;
|
||
}
|
||
|
||
let (next_i, end_pos) = if end + 1 < tokens.len() && get_value(&tokens[end + 1]) == entity_name {
|
||
(end + 1, tokens[end + 2].pos.range.end)
|
||
} else if end + 3 < tokens.len() {
|
||
(end + 2, tokens[end + 3].pos.range.end)
|
||
} else {
|
||
(i, tokens[end].pos.range.end)
|
||
};
|
||
|
||
// 创建一个空的 module 并标记上 last_module_name
|
||
let module = Module {
|
||
name: entity_name.to_string(),
|
||
params: Vec::new(),
|
||
ports: Vec::new(),
|
||
instances: Vec::new(),
|
||
range: Range {
|
||
start: Position {
|
||
line: start_pos.line + 1,
|
||
character: start_pos.character + 1
|
||
},
|
||
end: Position {
|
||
line: end_pos.line + 1,
|
||
character: end_pos.character + 1
|
||
}
|
||
}
|
||
};
|
||
last_module_name = entity_name.to_string();
|
||
modules.push(module);
|
||
|
||
// 如果内部含有 port,则不能直接跳过,否则直接跳过
|
||
if port_begin > 0 {
|
||
i = port_begin;
|
||
continue;
|
||
} else {
|
||
i = next_i;
|
||
}
|
||
}
|
||
}
|
||
"architecture" => {
|
||
if (i >= 1 as usize) && (kind_str(tokens[i-1].kind) != "end") || (i < 1) {
|
||
// !!! We not think of Architecture as VHDL Module Now
|
||
// !!! So skip all Architecture Parse when there is no it's Entity
|
||
let name = get_value(&tokens[i+3]);
|
||
if let None = modules.iter().find(|module| module.name == name) {
|
||
// let start_pos = tokens[i].pos.range.start;
|
||
i += 1;
|
||
let arch_name = get_value(&tokens[i]);
|
||
// println!("arch name {:?}", arch_name);
|
||
let mut end = i;
|
||
while (end+1 < tokens.len()) &&
|
||
!(kind_str(tokens[end].kind) == "end" &&
|
||
(kind_str(tokens[end+1].kind) == "architecture" || get_value(&tokens[end+1]) == arch_name)) {
|
||
end += 1;
|
||
}
|
||
if end+1 < tokens.len() && get_value(&tokens[end+1]) == arch_name {
|
||
i = end + 2;
|
||
} else if end + 3 < tokens.len() {
|
||
i = end + 3;
|
||
} else {
|
||
i = end;
|
||
};
|
||
// let end_pos = if end+1 < tokens.len() && get_value(&tokens[end+1]) == arch_name {
|
||
// i = end + 2;
|
||
// tokens[end+2].pos.range.end
|
||
// } else if end + 3 < tokens.len() {
|
||
// i = end + 3;
|
||
// tokens[end+3].pos.range.end
|
||
// } else {
|
||
// i = end;
|
||
// tokens[end].pos.range.end
|
||
// };
|
||
// let module = Module {
|
||
// name: name.to_string(),
|
||
// params: Vec::new(),
|
||
// ports: Vec::new(),
|
||
// instances: Vec::new(),
|
||
// range: Range {
|
||
// start: Position {
|
||
// line: start_pos.line + 1,
|
||
// character: start_pos.character + 1
|
||
// },
|
||
// end: Position {
|
||
// line: end_pos.line + 1,
|
||
// character: end_pos.character + 1
|
||
// }
|
||
// }
|
||
// };
|
||
// last_module_name = name.to_string();
|
||
// modules.push(module);
|
||
} else {
|
||
let module = modules.iter_mut().find(|module| module.name == name).unwrap();
|
||
let arch_name = get_value(&tokens[i+1]);
|
||
let entity_name = module.name.clone();
|
||
module.name = entity_name + "(" + arch_name.as_str() + ")";
|
||
}
|
||
}
|
||
}
|
||
"configuration" => {
|
||
i += 1;
|
||
while i < tokens.len() && !(kind_str(tokens[i].kind) == "end" && kind_str(tokens[i+1].kind) == "configuration") {
|
||
i += 1;
|
||
}
|
||
i += 1;
|
||
}
|
||
"package" => {
|
||
i += 1;
|
||
// println!("get package");
|
||
while i < tokens.len() && !(kind_str(tokens[i].kind) == "end" && kind_str(tokens[i+1].kind) == "package") {
|
||
i += 1;
|
||
}
|
||
i += 1;
|
||
}
|
||
"component" => {
|
||
i += 1;
|
||
instance_type.insert(get_value(&tokens[i]));
|
||
// println!("instance {:?}", kind_str(tokens[i].kind));
|
||
while i < tokens.len() && !(kind_str(tokens[i].kind) == "end" && kind_str(tokens[i+1].kind) == "component") {
|
||
i += 1;
|
||
}
|
||
i += 1;
|
||
}
|
||
"signal" => {
|
||
i += 1;
|
||
while !(kind_str(tokens[i+1].kind) == ";") {
|
||
i += 1;
|
||
}
|
||
}
|
||
"attribute" => {
|
||
i += 1;
|
||
while !(kind_str(tokens[i+1].kind) == ";") {
|
||
i += 1;
|
||
}
|
||
}
|
||
":" => {
|
||
if (i+2 < tokens.len()) && (kind_str(tokens[i+2].kind) != "use") {
|
||
if instance_type.contains(&get_value(&tokens[i+1])) {
|
||
let instance = Instance {
|
||
name: get_value(&tokens[i-1]),
|
||
inst_type: get_value(&tokens[i+1]),
|
||
instports: None,
|
||
instparams: None,
|
||
intstport_assignments: Vec::new(),
|
||
intstparam_assignments: Vec::new(),
|
||
range: Range {
|
||
start: Position {
|
||
line: tokens[i-1].pos.range.start.line + 1,
|
||
character: tokens[i-1].pos.range.start.character + 1
|
||
},
|
||
end: Position {
|
||
line: tokens[i+1].pos.range.start.line + 1,
|
||
character: tokens[i+1].pos.range.start.character + 1
|
||
}
|
||
}
|
||
};
|
||
if let Some(module) = modules.iter_mut().find(|module| module.name == last_module_name) {
|
||
module.instances.push(instance);
|
||
}
|
||
} else if kind_str(tokens[i+1].kind) == "entity" {
|
||
let instance = Instance {
|
||
name: get_value(&tokens[i-1]),
|
||
inst_type: get_value(&tokens[i+2]),
|
||
instports: None,
|
||
instparams: None,
|
||
intstport_assignments: Vec::new(),
|
||
intstparam_assignments: Vec::new(),
|
||
range: Range {
|
||
start: Position {
|
||
line: tokens[i-1].pos.range.start.line + 1,
|
||
character: tokens[i-1].pos.range.start.character + 1
|
||
},
|
||
end: Position {
|
||
line: tokens[i+2].pos.range.start.line + 1,
|
||
character: tokens[i+2].pos.range.start.character + 1
|
||
}
|
||
}
|
||
};
|
||
if let Some(module) = modules.iter_mut().find(|module| module.name == last_module_name) {
|
||
module.instances.push(instance);
|
||
}
|
||
i += 1;
|
||
} else {
|
||
let name = get_value(&tokens[i-1]);
|
||
let mut inst_type = String::new();
|
||
while i < tokens.len() {
|
||
if kind_str(tokens[i].kind) == "generic" || kind_str(tokens[i].kind) == "port" || kind_str(tokens[i].kind) == "end" {
|
||
i = i - 1;
|
||
break;
|
||
}
|
||
inst_type = inst_type + &get_value(&tokens[i]);
|
||
i += 1;
|
||
}
|
||
let instance = Instance {
|
||
name,
|
||
inst_type,
|
||
instports: None,
|
||
instparams: None,
|
||
intstport_assignments: Vec::new(),
|
||
intstparam_assignments: Vec::new(),
|
||
range: Range {
|
||
start: Position {
|
||
line: tokens[i-1].pos.range.start.line + 1,
|
||
character: tokens[i-1].pos.range.start.character + 1
|
||
},
|
||
end: Position {
|
||
line: tokens[i+1].pos.range.start.line + 1,
|
||
character: tokens[i+1].pos.range.start.character + 1
|
||
}
|
||
}
|
||
};
|
||
if let Some(module) = modules.iter_mut().find(|module| module.name == last_module_name) {
|
||
module.instances.push(instance);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
"generic" => {
|
||
let is_map = kind_str(tokens[i+1].kind) == "map";
|
||
let (params, next_index) = parse_parameters(&tokens, i + 1, is_map);
|
||
if is_map {
|
||
let start = params.first().unwrap().range.start.clone();
|
||
let end = params.last().unwrap().range.start.clone();
|
||
if let Some(module) = modules.iter_mut().find(|module| module.name == last_module_name) {
|
||
module.instances.last_mut().unwrap().instparams = Some(Range { start, end });
|
||
}
|
||
} else {
|
||
if let Some(module) = modules.iter_mut().find(|module| module.name == last_module_name) {
|
||
module.params.extend(params);
|
||
}
|
||
}
|
||
i = next_index;
|
||
}
|
||
"port" => {
|
||
let is_map = kind_str(tokens[i+1].kind) == "map";
|
||
let (ports, next_index) = parse_port(&tokens, i + 1, is_map);
|
||
if is_map {
|
||
let start = ports.first().unwrap().range.start.clone();
|
||
let end = ports.last().unwrap().range.start.clone();
|
||
if let Some(module) = modules.iter_mut().find(|module| module.name == last_module_name) {
|
||
module.instances.last_mut().unwrap().instports = Some(Range { start, end });
|
||
}
|
||
} else {
|
||
if let Some(module) = modules.iter_mut().find(|module| module.name == last_module_name) {
|
||
module.ports.extend(ports);
|
||
}
|
||
}
|
||
i = next_index;
|
||
}
|
||
_ => {}
|
||
}
|
||
i += 1;
|
||
}
|
||
|
||
// println!("{:?}", modules);
|
||
modules
|
||
|
||
}
|
||
|
||
|
||
#[allow(unused)]
|
||
fn parse_port(tokens: &[Token], start: usize, is_map: bool) -> (Vec<Port>, usize) {
|
||
let mut ports = Vec::new();
|
||
let mut i = start;
|
||
let mut stack = Vec::new();
|
||
|
||
while i < tokens.len() {
|
||
let token = &tokens[i];
|
||
match kind_str(token.kind) {
|
||
"(" => {
|
||
stack.push(token);
|
||
}
|
||
")" => {
|
||
if stack.is_empty() {
|
||
break;
|
||
}
|
||
stack.pop();
|
||
}
|
||
";" => {
|
||
if stack.is_empty() {
|
||
break;
|
||
}
|
||
}
|
||
"{identifier}" => {
|
||
if is_map {
|
||
let start_pos = tokens[i].pos.range.start;
|
||
while kind_str(tokens[i+1].kind) != ")" {
|
||
i += 1;
|
||
}
|
||
let end_pos = tokens[i].pos.range.end;
|
||
let port = Port {
|
||
name: "none".to_string(),
|
||
dir_type: "none".to_string(),
|
||
net_type: "none".to_string(),
|
||
width: "none".to_string(),
|
||
signed: "unsigned".to_string(),
|
||
range: Range {
|
||
start: Position {
|
||
line: start_pos.line + 1,
|
||
character: start_pos.character + 1
|
||
},
|
||
end: Position {
|
||
line: end_pos.line + 1,
|
||
character: end_pos.character + 1
|
||
}
|
||
},
|
||
};
|
||
ports.push(port);
|
||
} else {
|
||
let mut ports_token = Vec::new();
|
||
while kind_str(tokens[i].kind) != ":" {
|
||
// println!("{:?}", kind_str(tokens[i].kind));
|
||
if kind_str(tokens[i].kind) == "{identifier}" {
|
||
ports_token.push(&tokens[i]);
|
||
}
|
||
i += 1;
|
||
}
|
||
// let start_pos = tokens[i].pos.range.start;
|
||
let width ;
|
||
let end_idx;
|
||
let direction = if kind_str(tokens[i+1].kind) == "buffer" || kind_str(tokens[i+1].kind) == "out" {
|
||
i += 1;
|
||
"out"
|
||
} else if kind_str(tokens[i+1].kind) == "in" {
|
||
i += 1;
|
||
"in"
|
||
} else {
|
||
"unknown"
|
||
};
|
||
if kind_str(tokens[i+2].kind) == "(" {
|
||
let (width_str, index) = parse_width(&tokens, i+2);
|
||
width = "[".to_string() + &width_str + "]";
|
||
end_idx = index-1;
|
||
} else if kind_str(tokens[i+2].kind) == "range" {
|
||
width = "[".to_string() + &get_value(&tokens[i+3]) + ":" + &get_value(&tokens[i+5]) + "]";
|
||
end_idx = i+5;
|
||
} else {
|
||
width = "1".to_string();
|
||
end_idx = i+1;
|
||
}
|
||
let end_pos = tokens[end_idx].pos.range.end;
|
||
for tok in ports_token {
|
||
let port = Port {
|
||
name: get_value(&tok),
|
||
dir_type: direction.to_string(),
|
||
net_type: get_value(&tokens[i+1]),
|
||
width: width.to_string(),
|
||
signed: "unsigned".to_string(),
|
||
range: Range {
|
||
start: Position {
|
||
line: tok.pos.range.start.line + 1,
|
||
character: tok.pos.range.start.character + 1
|
||
},
|
||
end: Position {
|
||
line: end_pos.line + 1,
|
||
character: end_pos.character + 1
|
||
}
|
||
},
|
||
};
|
||
ports.push(port);
|
||
}
|
||
i = end_idx;
|
||
}
|
||
}
|
||
_ => {}
|
||
}
|
||
i += 1;
|
||
}
|
||
|
||
(ports, i)
|
||
}
|
||
|
||
|
||
#[allow(unused)]
|
||
fn parse_width(tokens: &[Token], start: usize) -> (String, usize) {
|
||
let mut width = String::new();
|
||
let mut i = start;
|
||
let mut stack = Vec::new();
|
||
|
||
while i < tokens.len() {
|
||
match kind_str(tokens[i].kind) {
|
||
"(" => {
|
||
stack.push(&tokens[i]);
|
||
}
|
||
")" => {
|
||
if stack.is_empty() {
|
||
break;
|
||
}
|
||
stack.pop();
|
||
}
|
||
";" => {
|
||
if stack.is_empty() {
|
||
break;
|
||
}
|
||
}
|
||
_ => {
|
||
if stack.len() >= 1 {
|
||
if get_value(&tokens[i]) == "None" {
|
||
if kind_str(tokens[i].kind) == "downto" || kind_str(tokens[i].kind) == "to" {
|
||
width = width + ":";
|
||
} else {
|
||
width = width + kind_str(tokens[i].kind);
|
||
}
|
||
} else {
|
||
width = width + &get_value(&tokens[i]);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
i += 1;
|
||
}
|
||
(width, i)
|
||
}
|
||
|
||
|
||
#[allow(unused)]
|
||
fn parse_parameters(tokens: &[Token], start: usize, is_map: bool) -> (Vec<Parameter>, usize) {
|
||
// println!("I am here, start {start}");
|
||
let mut params = Vec::new();
|
||
let mut i = start;
|
||
let mut stack = Vec::new();
|
||
|
||
while i < tokens.len() {
|
||
let token = &tokens[i];
|
||
match kind_str(token.kind) {
|
||
"(" => {
|
||
stack.push(token);
|
||
}
|
||
")" => {
|
||
if stack.is_empty() {
|
||
break;
|
||
}
|
||
stack.pop();
|
||
}
|
||
";" => {
|
||
if stack.is_empty() {
|
||
break;
|
||
}
|
||
}
|
||
"{identifier}" => {
|
||
if is_map {
|
||
let start_pos = tokens[i].pos.range.start;
|
||
let end_pos = tokens[i+2].pos.range.end;
|
||
let param = Parameter {
|
||
name: get_value(&tokens[i]),
|
||
net_type: get_value(&tokens[i+2]),
|
||
init: get_value(&tokens[i+2]),
|
||
range: Range {
|
||
start: Position {
|
||
line: start_pos.line + 1,
|
||
character: start_pos.character + 1
|
||
},
|
||
end: Position {
|
||
line: end_pos.line + 1,
|
||
character: end_pos.character + 1
|
||
}
|
||
},
|
||
};
|
||
i += 2;
|
||
params.push(param);
|
||
} else {
|
||
let mut parameters = Vec::new();
|
||
while kind_str(tokens[i].kind) != ":" {
|
||
// println!("{:?}", kind_str(tokens[i].kind));
|
||
if kind_str(tokens[i].kind) == "{identifier}" {
|
||
parameters.push(&tokens[i]);
|
||
}
|
||
i += 1;
|
||
}
|
||
let net_type = get_value(&tokens[i+1]);
|
||
let init = if kind_str(tokens[i+2].kind) == ":=" {
|
||
get_value(&tokens[i+3])
|
||
} else {
|
||
"unknown".to_string()
|
||
};
|
||
let end_pos = if kind_str(tokens[i+2].kind) == ":=" {
|
||
tokens[i+2].pos.range.end
|
||
} else {
|
||
tokens[i+1].pos.range.end
|
||
};
|
||
i = if kind_str(tokens[i+2].kind) == ":=" {
|
||
i + 3
|
||
} else {
|
||
i + 1
|
||
};
|
||
for param_token in parameters {
|
||
let start_pos = param_token.pos.range.start;
|
||
let param = Parameter {
|
||
name: get_value(param_token),
|
||
net_type: net_type.to_string(),
|
||
init: init.to_string(),
|
||
range: Range {
|
||
start: Position {
|
||
line: start_pos.line + 1,
|
||
character: start_pos.character + 1
|
||
},
|
||
end: Position {
|
||
line: end_pos.line + 1,
|
||
character: end_pos.character + 1
|
||
}
|
||
},
|
||
};
|
||
params.push(param);
|
||
}
|
||
}
|
||
}
|
||
_ => {}
|
||
}
|
||
i += 1;
|
||
}
|
||
|
||
(params, i)
|
||
}
|
||
|
||
|
||
#[allow(unused)]
|
||
fn get_value(token: &Token) -> String {
|
||
match &token.value {
|
||
vhdl_lang::Value::Identifier(symbol) => {
|
||
return symbol.name_utf8();
|
||
}
|
||
vhdl_lang::Value::String(latin1_string) => {
|
||
return latin1_string.to_string();
|
||
}
|
||
vhdl_lang::Value::BitString(latin1_string, _) => {
|
||
return latin1_string.to_string().replace("\\", "");
|
||
}
|
||
vhdl_lang::Value::AbstractLiteral(latin1_string, _) => {
|
||
return latin1_string.to_string();
|
||
}
|
||
vhdl_lang::Value::Character(character) => {
|
||
return character.to_string();
|
||
}
|
||
vhdl_lang::Value::Text(latin1_string) => {
|
||
return latin1_string.to_string();
|
||
}
|
||
vhdl_lang::Value::None => {
|
||
return "None".to_string();
|
||
}
|
||
}
|
||
} |