This commit is contained in:
锦恢 2024-12-04 01:29:04 +08:00
commit 579684061a
7 changed files with 351 additions and 657 deletions

1
Cargo.lock generated
View File

@ -1416,7 +1416,6 @@ dependencies = [
name = "sv-parser" name = "sv-parser"
version = "0.13.3" version = "0.13.3"
dependencies = [ dependencies = [
"log",
"nom", "nom",
"nom-greedyerror", "nom-greedyerror",
"sv-parser-error", "sv-parser-error",

View File

@ -374,6 +374,18 @@ impl FastHdlparam {
self.content.push(module); self.content.push(module);
} }
pub fn new_vhdl_module(&mut self, name: String, arch_name: String, range: Range) {
let module = Module {
name,
arch_name,
params: Vec::new(),
ports: Vec::new(),
instances: Vec::new(),
range
};
self.content.push(module);
}
pub fn update_module_range(&mut self, name: &str, end_line: u32, end_character: u32) { pub fn update_module_range(&mut self, name: &str, end_line: u32, end_character: u32) {
if let Some(matched_module) = self.content.iter_mut().find(|module| module.name == name) { if let Some(matched_module) = self.content.iter_mut().find(|module| module.name == name) {
matched_module.range.end.line = end_line; matched_module.range.end.line = end_line;

View File

@ -1,49 +1,10 @@
use std::collections::HashSet;
use std::path::PathBuf; use std::path::PathBuf;
use log::info; use log::info;
use vhdl_lang::ast::DesignFile; use vhdl_lang::ast::{ArchitectureBody, ConcurrentStatement, DesignFile, Designator, EntityDeclaration, InstantiatedUnit, InterfaceDeclaration, InterfaceList, LabeledConcurrentStatement, Mode, ModeIndication, Name};
use vhdl_lang::{kind_str, Token, VHDLParser, VHDLStandard}; use vhdl_lang::{kind_str, HasTokenSpan, Token, TokenAccess, TokenSpan, VHDLParser, VHDLStandard};
use super::hdlparam::*; 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> { pub fn vhdl_parse_str(path: &PathBuf, code: &str) -> Option<DesignFile> {
let mut diagnostics = Vec::new(); let mut diagnostics = Vec::new();
let parser = VHDLParser::new(VHDLStandard::VHDL2008); let parser = VHDLParser::new(VHDLStandard::VHDL2008);
@ -53,7 +14,9 @@ pub fn vhdl_parse_str(path: &PathBuf, code: &str) -> Option<DesignFile> {
None None
} }
pub fn make_fast_from_design_file(design_file: &DesignFile) -> Option<FastHdlparam> { pub fn make_fast_from_units(
arch_and_entity: Vec<((ArchitectureBody, Vec<Token>), (EntityDeclaration, Vec<Token>))>,
) -> Option<FastHdlparam> {
let mut hdlparam = FastHdlparam { let mut hdlparam = FastHdlparam {
fast_macro: Macro { fast_macro: Macro {
defines: Vec::new(), defines: Vec::new(),
@ -65,556 +28,234 @@ pub fn make_fast_from_design_file(design_file: &DesignFile) -> Option<FastHdlpar
file_type: "common".to_string() file_type: "common".to_string()
}; };
let mut all_tockens = Vec::new(); arch_and_entity.iter().for_each(|((arch, arch_tokens), (entity, entity_tokens))| {
for (tokens, _) in &design_file.design_units { let name = entity.ident.tree.item.name_utf8();
all_tockens.extend(tokens.clone()); let arch_name = arch.ident.tree.item.name_utf8();
let range = get_range_from_token(
entity_tokens.get_token(entity.span().get_start_token()),
entity_tokens.get_token(entity.span().get_end_token())
);
hdlparam.new_vhdl_module(name, arch_name, range);
if let Some(param_list) = &entity.generic_clause {
parse_interface_list(param_list, &entity_tokens).iter().for_each(|(name, _, net_type, _, init, range)| {
hdlparam.add_parameter(name, net_type, init, range.clone());
});
} }
hdlparam.content.extend(parse_tokens(all_tockens)); if let Some(port_list) = &entity.port_clause {
parse_interface_list(port_list, &entity_tokens).iter().for_each(|(name, dir_type, net_type, width, init, range)| {
hdlparam.add_port(name, dir_type, net_type, width, range.clone());
});
}
let instances = arch.statements.iter().filter(|statement| {
match statement.statement.item {
ConcurrentStatement::Instance(_) => true,
_ => false
}
})
.map(|statement| parse_instance(statement, arch_tokens))
.collect::<Vec<Instance>>();
if let Some(last_module) = hdlparam.content.last_mut() {
last_module.instances = instances
}
});
info!("get fast {:#?}", hdlparam);
Some(hdlparam) Some(hdlparam)
} }
fn parse_instance(statement: &LabeledConcurrentStatement, tokens: &Vec<Token>) -> Instance {
let name = if let Some(tree) = &statement.label.tree { tree.item.name_utf8() } else { "unknown".to_string() };
let range = get_range_from_token(
tokens.get_token(statement.span().get_start_token()),
tokens.get_token(statement.span().get_end_token())
);
fn parse_tokens(tokens: Vec<Token>) -> Vec<Module> { let mut parsed_instance = Instance {
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(),
arch_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]);
module.arch_name = arch_name;
}
}
}
"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, name,
inst_type, inst_type: "".to_string(),
instports: None,
instparams: None, instparams: None,
intstport_assignments: Vec::new(),
intstparam_assignments: Vec::new(), intstparam_assignments: Vec::new(),
range: Range { instports: None,
start: Position { intstport_assignments: Vec::new(),
line: tokens[i-1].pos.range.start.line + 1, range
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); match &statement.statement.item {
ConcurrentStatement::Instance(instance) => {
parsed_instance.inst_type = match &instance.unit {
InstantiatedUnit::Component(name) => {
match &name.item {
Name::Designator(designator) => {
match &designator.item {
Designator::Identifier(symbol) => symbol.name_utf8(),
_ => "unknown".to_string()
} }
} }
_ => "unknown".to_string()
} }
} },
"generic" => { _ => "unknown".to_string()
let is_map = kind_str(tokens[i+1].kind) == "map"; };
let (params, next_index) = parse_parameters(&tokens, i + 1, is_map);
if is_map { if let Some(parameter_list) = &instance.generic_map {
let start = params.first().unwrap().range.start.clone(); parsed_instance.instparams = Some(get_range_from_token(
let end = params.last().unwrap().range.start.clone(); tokens.get_token(parameter_list.span().get_start_token()),
if let Some(module) = modules.iter_mut().find(|module| module.name == last_module_name) { tokens.get_token(parameter_list.span().get_end_token())
module.instances.last_mut().unwrap().instparams = Some(Range { start, end }); ));
}
parsed_instance.intstparam_assignments = parameter_list.list.items.iter().map(|association_ele| {
let formal = association_ele.formal.clone().and_then(|formal|
Some(parse_string_from_tokenspan(formal.span(), tokens))
).unwrap_or(
"unknown".to_string()
);
let actual = parse_string_from_tokenspan(association_ele.actual.span(), tokens);
let assign_range = if association_ele.formal.is_some() {
get_range_from_token(
tokens.get_token(association_ele.formal.clone().unwrap().span().get_start_token()),
tokens.get_token(association_ele.actual.span().get_end_token())
)
} else { } else {
if let Some(module) = modules.iter_mut().find(|module| module.name == last_module_name) { get_range_from_token(
module.params.extend(params); tokens.get_token(association_ele.actual.span().get_start_token()),
} tokens.get_token(association_ele.actual.span().get_end_token())
} )
i = next_index; };
} InstParameter { parameter: Some(formal), assign_val: Some(actual), assign_type: AssignType::Named, range: assign_range }
"port" => { }).collect::<Vec<InstParameter>>();
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); if let Some(port_list) = &instance.port_map {
modules parsed_instance.instports = Some(get_range_from_token(
tokens.get_token(port_list.span().get_start_token()),
tokens.get_token(port_list.span().get_end_token())
));
parsed_instance.intstport_assignments = port_list.list.items.iter().map(|association_ele| {
let formal = association_ele.formal.clone().and_then(|formal|
Some(parse_string_from_tokenspan(formal.span(), tokens))
).unwrap_or(
"unknown".to_string()
);
let actual = parse_string_from_tokenspan(association_ele.actual.span(), tokens);
let assign_range = if association_ele.formal.is_some() {
get_range_from_token(
tokens.get_token(association_ele.formal.clone().unwrap().span().get_start_token()),
tokens.get_token(association_ele.actual.span().get_end_token())
)
} else {
get_range_from_token(
tokens.get_token(association_ele.actual.span().get_start_token()),
tokens.get_token(association_ele.actual.span().get_end_token())
)
};
InstPort { port: Some(formal), assign_val: Some(actual), assign_type: AssignType::Named, range: assign_range }
}).collect::<Vec<InstPort>>();
}
}
_ => ()
};
parsed_instance
} }
fn parse_interface_list(list: &InterfaceList, tokens: &Vec<Token>) -> Vec<(String, String, String, String, String, Range)> {
#[allow(unused)] let mut interface_list = Vec::new();
fn parse_port(tokens: &[Token], start: usize, is_map: bool) -> (Vec<Port>, usize) { list.items.iter().for_each(|interface| {
let mut ports = Vec::new(); let range = get_range_from_token(
let mut i = start; tokens.get_token(interface.span().get_start_token()),
let mut stack = Vec::new(); tokens.get_token(interface.span().get_end_token())
);
while i < tokens.len() { match interface {
let token = &tokens[i]; InterfaceDeclaration::Object(object) => {
match kind_str(token.kind) { let name = object.idents.first().unwrap().tree.item.name_utf8();
"(" => { let (dir_type, net_type, width, init) = match &object.mode {
stack.push(token); ModeIndication::Simple(simple_mode) => {
} let dir_type = if let Some(mode_token) = &simple_mode.mode {
")" => { match mode_token.item {
if stack.is_empty() { Mode::In => "in",
break; Mode::Out => "out",
} Mode::Buffer | Mode::InOut => "inout",
stack.pop(); Mode::Linkage => "unknown"
} }.to_string()
";" => {
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 { } else {
"unknown".to_string() "unknown".to_string()
}; };
let end_pos = if kind_str(tokens[i+2].kind) == ":=" { let net_type = simple_mode.subtype_indication.type_mark.item.to_string();
tokens[i+2].pos.range.end let width = if let Some(constraint) = &simple_mode.subtype_indication.constraint {
parse_width_from_tokenspan(constraint.span(), tokens)
} else { } else {
tokens[i+1].pos.range.end "1".to_string()
}; };
i = if kind_str(tokens[i+2].kind) == ":=" { let init = if let Some(expression) = &simple_mode.expression {
i + 3 parse_width_from_tokenspan(expression.span(), tokens)
} else { } else {
i + 1 "unknown".to_string()
}; };
for param_token in parameters { (dir_type, net_type, width, init)
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
} }
}, _ => ("unknown".to_string(), "unknown".to_string(), "unknown".to_string(), "unknown".to_string())
}; };
params.push(param); interface_list.push((name, dir_type, net_type, width, init, range));
} }
_ => ()
} }
} });
_ => {} interface_list
}
i += 1;
}
(params, i)
} }
fn parse_string_from_tokenspan(span: TokenSpan, tokens: &Vec<Token>) -> String {
span.iter().map(|id| {
if let Some(token) = tokens.get_token(id) {
if get_value(token) == "None" {
kind_str(token.kind).to_string()
} else {
get_value(token)
}
} else {
"".to_string()
}
}).collect()
}
fn parse_width_from_tokenspan(span: TokenSpan, tokens: &Vec<Token>) -> String {
// skip '(' and ')'
span.iter().skip(1).take(span.len() - 2).map(|id| {
if let Some(token) = tokens.get_token(id) {
if get_value(token) == "None" {
if kind_str(token.kind) == "downto" || kind_str(token.kind) == "to" {
":".to_string()
} else {
kind_str(token.kind).to_string()
}
} else {
get_value(token)
}
} else {
"".to_string()
}
}).collect()
}
fn get_range_from_token(start_token: Option<&Token>, end_token: Option<&Token>) -> Range {
let start = if let Some(token) = start_token {
Position { line: token.pos.start().line, character: token.pos.start().character }
} else {
Position { line: 0, character: 0 }
};
let end = if let Some(token) = end_token {
Position { line: token.pos.end().line, character: token.pos.end().character }
} else {
Position { line: 0, character: 0 }
};
Range { start, end }
}
#[allow(unused)] #[allow(unused)]
fn get_value(token: &Token) -> String { fn get_value(token: &Token) -> String {

View File

@ -209,8 +209,7 @@ pub fn get_scopes_from_vhdl_fast(fast: &FastHdlparam, text: &Rope, url: &Url) ->
for module in &fast.content { for module in &fast.content {
let mut scope: GenericScope = GenericScope::new(url); let mut scope: GenericScope = GenericScope::new(url);
scope.ident = module.name.clone(); scope.ident = module.name.clone();
let mut module_range = module.range.clone(); let module_range = module.range.clone();
module_range.affine(-1, -1);
scope.start = position_to_byte_idx(text, &module_range.start); scope.start = position_to_byte_idx(text, &module_range.start);
scope.end = position_to_byte_idx(text, &module_range.end); scope.end = position_to_byte_idx(text, &module_range.end);
scope.byte_idx = scope.start + 7; scope.byte_idx = scope.start + 7;
@ -218,8 +217,7 @@ pub fn get_scopes_from_vhdl_fast(fast: &FastHdlparam, text: &Rope, url: &Url) ->
for parameter in &module.params { for parameter in &module.params {
let mut def = GenericDec::new(url); let mut def = GenericDec::new(url);
def.ident = parameter.name.clone(); def.ident = parameter.name.clone();
let mut parameter_range = parameter.range.clone(); let parameter_range = parameter.range.clone();
parameter_range.affine(-1, -1);
def.byte_idx = position_to_byte_idx(text, &parameter_range.start); def.byte_idx = position_to_byte_idx(text, &parameter_range.start);
def.completion_kind = CompletionItemKind::TYPE_PARAMETER; def.completion_kind = CompletionItemKind::TYPE_PARAMETER;
def.symbol_kind = SymbolKind::TYPE_PARAMETER; def.symbol_kind = SymbolKind::TYPE_PARAMETER;
@ -228,8 +226,7 @@ pub fn get_scopes_from_vhdl_fast(fast: &FastHdlparam, text: &Rope, url: &Url) ->
for port in &module.ports { for port in &module.ports {
let mut port_def = PortDec::new(url); let mut port_def = PortDec::new(url);
port_def.ident = port.name.clone(); port_def.ident = port.name.clone();
let mut port_range = port.range.clone(); let port_range = port.range.clone();
port_range.affine(-1, -1);
port_def.byte_idx = position_to_byte_idx(text, &port_range.start); port_def.byte_idx = position_to_byte_idx(text, &port_range.start);
port_def.type_str = port.dir_type.clone(); port_def.type_str = port.dir_type.clone();
scope.defs.push(Box::new(port_def)); scope.defs.push(Box::new(port_def));
@ -237,8 +234,7 @@ pub fn get_scopes_from_vhdl_fast(fast: &FastHdlparam, text: &Rope, url: &Url) ->
for inst in &module.instances { for inst in &module.instances {
let mut instance = ModInst::new(url); let mut instance = ModInst::new(url);
instance.ident = inst.name.clone(); instance.ident = inst.name.clone();
let mut inst_range = inst.range.clone(); let inst_range = inst.range.clone();
inst_range.affine(-1, -1);
instance.byte_idx = position_to_byte_idx(text, &inst_range.start); instance.byte_idx = position_to_byte_idx(text, &inst_range.start);
instance.type_str = inst.inst_type.clone(); instance.type_str = inst.inst_type.clone();
instance.mod_ident = inst.inst_type.clone(); instance.mod_ident = inst.inst_type.clone();

View File

@ -1,19 +1,21 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::str::FromStr; use std::str::FromStr;
use std::{fs, future}; use std::{fs, future};
use std::path::PathBuf; use std::path::{Path, PathBuf};
use std::sync::Arc; use std::sync::Arc;
use log::info; use log::info;
use ropey::Rope; use ropey::Rope;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tower_lsp::jsonrpc::Result; use tower_lsp::jsonrpc::Result;
use tower_lsp::lsp_types::*; use tower_lsp::lsp_types::*;
use vhdl_lang::Project;
use crate::core::cache_storage::CacheResult; use crate::core::cache_storage::CacheResult;
use crate::core::hdlparam::FastHdlparam; use crate::core::hdlparam::FastHdlparam;
use crate::core::sv_parser::make_fast_from_syntaxtree; use crate::core::sv_parser::make_fast_from_syntaxtree;
use crate::core::vhdl_parser::{make_fast_from_design_file, vhdl_parse}; use crate::core::vhdl_parser::make_fast_from_units;
use crate::definition::VhdlProject;
use crate::{core, utils::*}; use crate::{core, utils::*};
use crate::server::Backend; use crate::server::Backend;
use crate::sources::recovery_sv_parse_with_retry; use crate::sources::recovery_sv_parse_with_retry;
@ -218,6 +220,7 @@ fn do_vhdl_fast(
let sources = &backend.server.srcs; let sources = &backend.server.srcs;
let pathbuf = PathBuf::from_str(path).unwrap(); let pathbuf = PathBuf::from_str(path).unwrap();
let hdl_param = sources.hdl_param.clone(); let hdl_param = sources.hdl_param.clone();
let vhdl_project = sources.vhdl_project.clone();
// TODO: 支持对于 synth 下的 vhdl 文件的解析,从而提供更加丰富的 IP 支持 // TODO: 支持对于 synth 下的 vhdl 文件的解析,从而提供更加丰富的 IP 支持
if file_type == "ip" { if file_type == "ip" {
@ -251,8 +254,26 @@ fn do_vhdl_fast(
}; };
hdl_param.update_fast(path.to_string(), ip_fast.clone()); hdl_param.update_fast(path.to_string(), ip_fast.clone());
return Ok(ip_fast); return Ok(ip_fast);
} else if let Some(design_file) = vhdl_parse(&pathbuf) { } else if let Some(vhdl_project) = &mut *vhdl_project.write().unwrap() {
if let Some(mut fast) = make_fast_from_design_file(&design_file) { vhdl_project.config_file_strs.push(format!("{:?}", pathbuf));
let mut messages = Vec::new();
let config_str = format!(
r#"
[libraries]
digital_lsp.files = [{}]
"#, vhdl_project.config_file_strs.join(",")
);
let config = vhdl_lang::Config::from_str(&config_str, Path::new(""));
if let Ok(mut config) = config {
config.append(&vhdl_project.std_config, &mut messages);
let mut project = Project::from_config(config, &mut messages);
project.analyse();
*vhdl_project = VhdlProject { project, std_config: vhdl_project.std_config.clone(), config_file_strs: vhdl_project.config_file_strs.clone() };
}
let arch_and_entity = vhdl_project.project.get_analyzed_units(&pathbuf);
if let Some(mut fast) = make_fast_from_units(arch_and_entity) {
fast.file_type = file_type.to_string(); fast.file_type = file_type.to_string();
// IP 不需要内部的 instance其实现是加密的只需要暴露 module 的接口即可 // IP 不需要内部的 instance其实现是加密的只需要暴露 module 的接口即可
// 所以此处需要清空所有的 module 中的 instance // 所以此处需要清空所有的 module 中的 instance
@ -275,8 +296,26 @@ fn do_vhdl_fast(
} }
// 没有特殊情况,则正常解析并写入 // 没有特殊情况,则正常解析并写入
if let Some(design_file) = vhdl_parse(&pathbuf) { if let Some(vhdl_project) = &mut *vhdl_project.write().unwrap() {
if let Some(mut fast) = make_fast_from_design_file(&design_file) { vhdl_project.config_file_strs.push(format!("{:?}", pathbuf));
let mut messages = Vec::new();
let config_str = format!(
r#"
[libraries]
digital_lsp.files = [{}]
"#, vhdl_project.config_file_strs.join(",")
);
let config = vhdl_lang::Config::from_str(&config_str, Path::new(""));
if let Ok(mut config) = config {
config.append(&vhdl_project.std_config, &mut messages);
let mut project = Project::from_config(config, &mut messages);
project.analyse();
*vhdl_project = VhdlProject { project, std_config: vhdl_project.std_config.clone(), config_file_strs: vhdl_project.config_file_strs.clone() };
}
let arch_and_entity = vhdl_project.project.get_analyzed_units(&pathbuf);
info!("for file {} arch_and_entity is empty {}", path, arch_and_entity.is_empty());
if let Some(mut fast) = make_fast_from_units(arch_and_entity) {
fast.file_type = file_type.to_string(); fast.file_type = file_type.to_string();
// for module in &fast.content { // for module in &fast.content {
// if module.name == "None" { // if module.name == "None" {

View File

@ -1,7 +1,7 @@
use crate::core::hdlparam::HdlParam; use crate::core::hdlparam::HdlParam;
use crate::core::primitive_parser::PrimitiveText; use crate::core::primitive_parser::PrimitiveText;
use crate::core::sv_parser::make_fast_from_syntaxtree; use crate::core::sv_parser::make_fast_from_syntaxtree;
use crate::core::vhdl_parser::make_fast_from_design_file; use crate::core::vhdl_parser::make_fast_from_units;
use crate::core::vhdl_parser::vhdl_parse_str; use crate::core::vhdl_parser::vhdl_parse_str;
use crate::definition::def_types::*; use crate::definition::def_types::*;
use crate::definition::get_scopes_from_syntax_tree; use crate::definition::get_scopes_from_syntax_tree;
@ -775,10 +775,72 @@ pub fn vhdl_parser_pipeline(
configure.extension_path.to_string() configure.extension_path.to_string()
}; };
let mut global_project = project_handle.write().unwrap();
match &mut *global_project {
Some(vhdl_project) => {
if let Some(source) = vhdl_project.project.get_source(&escape_path) {
source.change(None, &doc.to_string());
vhdl_project.project.update_source(&source);
vhdl_project.project.analyse();
} else {
vhdl_project.config_file_strs.push(format!("{:?}", escape_path));
let mut messages = Vec::new();
let config_str = format!(
r#"
[libraries]
digital_lsp.files = [{}]
"#, vhdl_project.config_file_strs.join(",")
);
let config = vhdl_lang::Config::from_str(&config_str, Path::new(""));
if let Ok(mut config) = config {
config.append(&vhdl_project.std_config, &mut messages);
let mut project = Project::from_config(config, &mut messages);
project.analyse();
*vhdl_project = VhdlProject { project, std_config: vhdl_project.std_config.clone(), config_file_strs: vhdl_project.config_file_strs.clone() };
}
}
}
None => {
let std_cfg_path = match PathBuf::from_str(&(extension_path.clone() + "/resources/dide-lsp/static/vhdl_std_lib/vhdl_ls.toml")) {
Ok(path) => path,
Err(e) => {
info!("error happen in <vhdl_parse_pipeline>: {:?}", e);
return;
}
};
match vhdl_lang::Config::read_file_path(&std_cfg_path) {
Ok(std_config) => {
let config_str = format!(
r#"
[libraries]
digital_lsp.files = [{:?}]
"#, escape_path
);
let mut config_file_strs = Vec::new();
config_file_strs.push(format!("{:?}", escape_path));
let config = vhdl_lang::Config::from_str(&config_str, Path::new(""));
if let Ok(mut config) = config {
let mut messages = Vec::new();
config.append(&std_config, &mut messages);
let mut project = Project::from_config(config, &mut messages);
project.analyse();
*global_project = Some(VhdlProject { project, std_config, config_file_strs });
}
}
Err(e) => info!("error happen in <vhdl_parse_pipeline>: Can't load standard vhdl lib from {std_cfg_path:#?} because {e:#?}")
}
}
}
drop(global_project);
let mut global_project = project_handle.write().unwrap();
match &mut *global_project {
Some(vhdl_project) => {
let mut file = source_handle.write().unwrap(); let mut file = source_handle.write().unwrap();
let text = doc.to_string(); let text = doc.to_string();
let mut scope_tree = if let Some(design_file) = vhdl_parse_str(&escape_path, &text) { let mut scope_tree = if let Some(design_file) = vhdl_parse_str(&escape_path, &text) {
if let Some(mut fast) = make_fast_from_design_file(&design_file) { let arch_and_entity = vhdl_project.project.get_analyzed_units(&escape_path);
if let Some(mut fast) = make_fast_from_units(arch_and_entity) {
let parse_ir = ParseIR::DesignFile(design_file); let parse_ir = ParseIR::DesignFile(design_file);
file.parse_ir = Some(parse_ir); file.parse_ir = Some(parse_ir);
@ -839,65 +901,10 @@ pub fn vhdl_parser_pipeline(
} }
// eprintln!("{:#?}", *global_scope); // eprintln!("{:#?}", *global_scope);
let mut global_project = project_handle.write().unwrap();
match &mut *global_project {
Some(vhdl_project) => {
if let Some(source) = vhdl_project.project.get_source(&escape_path) {
source.change(None, &doc.to_string());
vhdl_project.project.update_source(&source);
vhdl_project.project.analyse();
} else {
vhdl_project.config_file_strs.push(format!("{:?}", escape_path));
let mut messages = Vec::new();
let config_str = format!(
r#"
[libraries]
digital_lsp.files = [{}]
"#, vhdl_project.config_file_strs.join(",")
);
let config = vhdl_lang::Config::from_str(&config_str, Path::new(""));
if let Ok(mut config) = config {
config.append(&vhdl_project.std_config, &mut messages);
let mut project = Project::from_config(config, &mut messages);
project.analyse();
*vhdl_project = VhdlProject { project, std_config: vhdl_project.std_config.clone(), config_file_strs: vhdl_project.config_file_strs.clone() };
}
}
}
None => {
let std_cfg_path = match PathBuf::from_str(&(extension_path + "/resources/dide-lsp/static/vhdl_std_lib/vhdl_ls.toml")) {
Ok(path) => path,
Err(e) => {
info!("error happen in <vhdl_parse_pipeline>: {:?}", e);
return;
}
};
match vhdl_lang::Config::read_file_path(&std_cfg_path) {
Ok(std_config) => {
let config_str = format!(
r#"
[libraries]
digital_lsp.files = [{:?}]
"#, escape_path
);
let mut config_file_strs = Vec::new();
config_file_strs.push(format!("{:?}", escape_path));
let config = vhdl_lang::Config::from_str(&config_str, Path::new(""));
if let Ok(mut config) = config {
let mut messages = Vec::new();
config.append(&std_config, &mut messages);
let mut project = Project::from_config(config, &mut messages);
project.analyse();
*global_project = Some(VhdlProject { project, std_config, config_file_strs });
}
}
Err(e) => info!("error happen in <vhdl_parse_pipeline>: Can't load standard vhdl lib from {std_cfg_path:#?} because {e:#?}")
}
}
}
drop(global_project);
drop(global_scope); drop(global_scope);
}
_ => ()
}
} }
//TODO: add bounds checking for utf8<->utf16 conversions //TODO: add bounds checking for utf8<->utf16 conversions

@ -1 +1 @@
Subproject commit 2446bd0a812d1667ad7033f10cd27a03967fa15e Subproject commit cf95eb9b901e847b54ed824b6b6a780fd2f6eac3