digital-lsp-server/src/core/vhdl_parser.rs
2024-11-16 10:23:49 +08:00

639 lines
25 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use std::collections::HashSet;
use std::path::PathBuf;
use log::info;
use vhdl_lang::ast::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 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);
}
}
}
"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();
}
}
}