digital-lsp-server/src/core/vhdl_parser.rs
2024-09-21 22:42:00 +08:00

343 lines
12 KiB
Rust

use std::collections::HashSet;
use std::path::PathBuf;
use vhdl_lang::{kind_str, Token, VHDLParser, VHDLStandard};
use super::fast_hdlparam::*;
pub fn vhdl_parser(path: &str) -> FastHdlparam {
// The path of SystemVerilog source file
let path = PathBuf::from(path);
let mut hdlparam = FastHdlparam {
fast: Vec::new()
};
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.fast.extend(parse_tokens(all_tockens));
hdlparam
}
fn parse_tokens(tokens: Vec<Token>) -> Vec<Module> {
let mut modules = Vec::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" => {
i += 1;
let module = Module {
name: get_value(&tokens[i]),
params: Vec::new(),
ports: Vec::new(),
instances: Vec::new(),
range: Range {
start: Position {
line: tokens[i].pos.range.start.line + 1,
character: tokens[i].pos.range.start.character + 1
},
end: Position {
line: tokens[i].pos.range.end.line + 1,
character: tokens[i].pos.range.end.character + 1
}
}
};
modules.push(module);
}
"component" => {
i += 1;
instance_type.insert(get_value(&tokens[i]));
while !(kind_str(tokens[i].kind) == "end" && kind_str(tokens[i+1].kind) == "component") {
i += 1;
}
i += 1;
}
":" => {
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,
range: Range {
start: Position {
line: tokens[i-1].pos.range.start.line,
character: tokens[i-1].pos.range.start.character
},
end: Position {
line: tokens[i+1].pos.range.start.line,
character: tokens[i+1].pos.range.start.character
}
}
};
modules.last_mut().unwrap().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();
modules.last_mut().unwrap().instances.last_mut().unwrap().instparams = Some(Range { start, end });
} else {
modules.last_mut().unwrap().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();
modules.last_mut().unwrap().instances.last_mut().unwrap().instports = Some(Range { start, end });
} else {
modules.last_mut().unwrap().ports.extend(ports);
}
i = next_index;
}
_ => {}
}
i += 1;
}
// println!("{:?}", modules);
modules
}
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;
let end_pos = tokens[i+3].pos.range.end;
let port = Port {
name: get_value(&tokens[i]),
dir_type: "none".to_string(),
net_type: get_value(&tokens[i+2]),
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
}
},
};
i += 2;
ports.push(port);
} else {
let start_pos = tokens[i].pos.range.start;
let width ;
let end_idx;
if get_value(&tokens[i+3]).contains("VECTOR") || get_value(&tokens[i+3]).contains("vector") {
let (width_str, index) = parse_width(&tokens, i+4);
width = "[".to_string() + &width_str + "]";
end_idx = index;
} else {
width = "1".to_string();
end_idx = i+3;
}
let end_pos = tokens[end_idx].pos.range.end;
let direction = if kind_str(tokens[i+2].kind) == "buffer" { "out" } else { kind_str(tokens[i+2].kind) };
let port = Port {
name: get_value(&tokens[i]),
dir_type: direction.to_string(),
net_type: get_value(&tokens[i+3]),
width,
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
}
},
};
i = end_idx;
ports.push(port);
}
}
_ => {}
}
i += 1;
}
(ports, i)
}
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)
}
fn parse_parameters(tokens: &[Token], start: usize, is_map: bool) -> (Vec<Parameter>, usize) {
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 start_pos = tokens[i].pos.range.start;
let end_pos = tokens[i+4].pos.range.end;
let param = Parameter {
name: get_value(&tokens[i]),
net_type: get_value(&tokens[i+2]),
init: get_value(&tokens[i+4]),
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 += 4;
params.push(param);
}
}
_ => {}
}
i += 1;
}
(params, i)
}
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();
}
}
}