Merge branch 'main' of https://github.com/Digital-EDA/digital-lsp-server
This commit is contained in:
commit
579684061a
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1416,7 +1416,6 @@ dependencies = [
|
||||
name = "sv-parser"
|
||||
version = "0.13.3"
|
||||
dependencies = [
|
||||
"log",
|
||||
"nom",
|
||||
"nom-greedyerror",
|
||||
"sv-parser-error",
|
||||
|
@ -374,6 +374,18 @@ impl FastHdlparam {
|
||||
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) {
|
||||
if let Some(matched_module) = self.content.iter_mut().find(|module| module.name == name) {
|
||||
matched_module.range.end.line = end_line;
|
||||
|
@ -1,49 +1,10 @@
|
||||
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 vhdl_lang::ast::{ArchitectureBody, ConcurrentStatement, DesignFile, Designator, EntityDeclaration, InstantiatedUnit, InterfaceDeclaration, InterfaceList, LabeledConcurrentStatement, Mode, ModeIndication, Name};
|
||||
use vhdl_lang::{kind_str, HasTokenSpan, Token, TokenAccess, TokenSpan, 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);
|
||||
@ -53,7 +14,9 @@ pub fn vhdl_parse_str(path: &PathBuf, code: &str) -> Option<DesignFile> {
|
||||
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 {
|
||||
fast_macro: Macro {
|
||||
defines: Vec::new(),
|
||||
@ -65,556 +28,234 @@ pub fn make_fast_from_design_file(design_file: &DesignFile) -> Option<FastHdlpar
|
||||
file_type: "common".to_string()
|
||||
};
|
||||
|
||||
let mut all_tockens = Vec::new();
|
||||
for (tokens, _) in &design_file.design_units {
|
||||
all_tockens.extend(tokens.clone());
|
||||
arch_and_entity.iter().for_each(|((arch, arch_tokens), (entity, entity_tokens))| {
|
||||
let name = entity.ident.tree.item.name_utf8();
|
||||
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)
|
||||
}
|
||||
|
||||
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 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 {
|
||||
let mut parsed_instance = Instance {
|
||||
name,
|
||||
inst_type,
|
||||
instports: None,
|
||||
inst_type: "".to_string(),
|
||||
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
|
||||
}
|
||||
}
|
||||
instports: None,
|
||||
intstport_assignments: Vec::new(),
|
||||
range
|
||||
};
|
||||
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;
|
||||
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()
|
||||
}
|
||||
}
|
||||
"{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
|
||||
_ => "unknown".to_string()
|
||||
}
|
||||
},
|
||||
_ => "unknown".to_string()
|
||||
};
|
||||
ports.push(port);
|
||||
|
||||
if let Some(parameter_list) = &instance.generic_map {
|
||||
parsed_instance.instparams = Some(get_range_from_token(
|
||||
tokens.get_token(parameter_list.span().get_start_token()),
|
||||
tokens.get_token(parameter_list.span().get_end_token())
|
||||
));
|
||||
|
||||
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 {
|
||||
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"
|
||||
get_range_from_token(
|
||||
tokens.get_token(association_ele.actual.span().get_start_token()),
|
||||
tokens.get_token(association_ele.actual.span().get_end_token())
|
||||
)
|
||||
};
|
||||
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;
|
||||
InstParameter { parameter: Some(formal), assign_val: Some(actual), assign_type: AssignType::Named, range: assign_range }
|
||||
}).collect::<Vec<InstParameter>>();
|
||||
}
|
||||
|
||||
if let Some(port_list) = &instance.port_map {
|
||||
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 {
|
||||
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
|
||||
}
|
||||
},
|
||||
get_range_from_token(
|
||||
tokens.get_token(association_ele.actual.span().get_start_token()),
|
||||
tokens.get_token(association_ele.actual.span().get_end_token())
|
||||
)
|
||||
};
|
||||
ports.push(port);
|
||||
}
|
||||
i = end_idx;
|
||||
InstPort { port: Some(formal), assign_val: Some(actual), assign_type: AssignType::Named, range: assign_range }
|
||||
}).collect::<Vec<InstPort>>();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
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]);
|
||||
|
||||
parsed_instance
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
let net_type = get_value(&tokens[i+1]);
|
||||
let init = if kind_str(tokens[i+2].kind) == ":=" {
|
||||
get_value(&tokens[i+3])
|
||||
|
||||
fn parse_interface_list(list: &InterfaceList, tokens: &Vec<Token>) -> Vec<(String, String, String, String, String, Range)> {
|
||||
let mut interface_list = Vec::new();
|
||||
list.items.iter().for_each(|interface| {
|
||||
let range = get_range_from_token(
|
||||
tokens.get_token(interface.span().get_start_token()),
|
||||
tokens.get_token(interface.span().get_end_token())
|
||||
);
|
||||
match interface {
|
||||
InterfaceDeclaration::Object(object) => {
|
||||
let name = object.idents.first().unwrap().tree.item.name_utf8();
|
||||
let (dir_type, net_type, width, init) = match &object.mode {
|
||||
ModeIndication::Simple(simple_mode) => {
|
||||
let dir_type = if let Some(mode_token) = &simple_mode.mode {
|
||||
match mode_token.item {
|
||||
Mode::In => "in",
|
||||
Mode::Out => "out",
|
||||
Mode::Buffer | Mode::InOut => "inout",
|
||||
Mode::Linkage => "unknown"
|
||||
}.to_string()
|
||||
} else {
|
||||
"unknown".to_string()
|
||||
};
|
||||
let end_pos = if kind_str(tokens[i+2].kind) == ":=" {
|
||||
tokens[i+2].pos.range.end
|
||||
let net_type = simple_mode.subtype_indication.type_mark.item.to_string();
|
||||
let width = if let Some(constraint) = &simple_mode.subtype_indication.constraint {
|
||||
parse_width_from_tokenspan(constraint.span(), tokens)
|
||||
} else {
|
||||
tokens[i+1].pos.range.end
|
||||
"1".to_string()
|
||||
};
|
||||
i = if kind_str(tokens[i+2].kind) == ":=" {
|
||||
i + 3
|
||||
let init = if let Some(expression) = &simple_mode.expression {
|
||||
parse_width_from_tokenspan(expression.span(), tokens)
|
||||
} else {
|
||||
i + 1
|
||||
"unknown".to_string()
|
||||
};
|
||||
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
|
||||
(dir_type, net_type, width, init)
|
||||
}
|
||||
},
|
||||
_ => ("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));
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
i += 1;
|
||||
});
|
||||
interface_list
|
||||
}
|
||||
|
||||
(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)]
|
||||
fn get_value(token: &Token) -> String {
|
||||
|
@ -209,8 +209,7 @@ pub fn get_scopes_from_vhdl_fast(fast: &FastHdlparam, text: &Rope, url: &Url) ->
|
||||
for module in &fast.content {
|
||||
let mut scope: GenericScope = GenericScope::new(url);
|
||||
scope.ident = module.name.clone();
|
||||
let mut module_range = module.range.clone();
|
||||
module_range.affine(-1, -1);
|
||||
let module_range = module.range.clone();
|
||||
scope.start = position_to_byte_idx(text, &module_range.start);
|
||||
scope.end = position_to_byte_idx(text, &module_range.end);
|
||||
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 {
|
||||
let mut def = GenericDec::new(url);
|
||||
def.ident = parameter.name.clone();
|
||||
let mut parameter_range = parameter.range.clone();
|
||||
parameter_range.affine(-1, -1);
|
||||
let parameter_range = parameter.range.clone();
|
||||
def.byte_idx = position_to_byte_idx(text, ¶meter_range.start);
|
||||
def.completion_kind = CompletionItemKind::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 {
|
||||
let mut port_def = PortDec::new(url);
|
||||
port_def.ident = port.name.clone();
|
||||
let mut port_range = port.range.clone();
|
||||
port_range.affine(-1, -1);
|
||||
let port_range = port.range.clone();
|
||||
port_def.byte_idx = position_to_byte_idx(text, &port_range.start);
|
||||
port_def.type_str = port.dir_type.clone();
|
||||
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 {
|
||||
let mut instance = ModInst::new(url);
|
||||
instance.ident = inst.name.clone();
|
||||
let mut inst_range = inst.range.clone();
|
||||
inst_range.affine(-1, -1);
|
||||
let inst_range = inst.range.clone();
|
||||
instance.byte_idx = position_to_byte_idx(text, &inst_range.start);
|
||||
instance.type_str = inst.inst_type.clone();
|
||||
instance.mod_ident = inst.inst_type.clone();
|
||||
|
@ -1,19 +1,21 @@
|
||||
use std::borrow::Cow;
|
||||
use std::str::FromStr;
|
||||
use std::{fs, future};
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
use log::info;
|
||||
use ropey::Rope;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tower_lsp::jsonrpc::Result;
|
||||
use tower_lsp::lsp_types::*;
|
||||
use vhdl_lang::Project;
|
||||
|
||||
use crate::core::cache_storage::CacheResult;
|
||||
use crate::core::hdlparam::FastHdlparam;
|
||||
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::server::Backend;
|
||||
use crate::sources::recovery_sv_parse_with_retry;
|
||||
@ -218,6 +220,7 @@ fn do_vhdl_fast(
|
||||
let sources = &backend.server.srcs;
|
||||
let pathbuf = PathBuf::from_str(path).unwrap();
|
||||
let hdl_param = sources.hdl_param.clone();
|
||||
let vhdl_project = sources.vhdl_project.clone();
|
||||
|
||||
// TODO: 支持对于 synth 下的 vhdl 文件的解析,从而提供更加丰富的 IP 支持
|
||||
if file_type == "ip" {
|
||||
@ -251,8 +254,26 @@ fn do_vhdl_fast(
|
||||
};
|
||||
hdl_param.update_fast(path.to_string(), ip_fast.clone());
|
||||
return Ok(ip_fast);
|
||||
} else if let Some(design_file) = vhdl_parse(&pathbuf) {
|
||||
if let Some(mut fast) = make_fast_from_design_file(&design_file) {
|
||||
} else if let Some(vhdl_project) = &mut *vhdl_project.write().unwrap() {
|
||||
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();
|
||||
// IP 不需要内部的 instance,其实现是加密的,只需要暴露 module 的接口即可
|
||||
// 所以此处需要清空所有的 module 中的 instance
|
||||
@ -275,8 +296,26 @@ fn do_vhdl_fast(
|
||||
}
|
||||
|
||||
// 没有特殊情况,则正常解析并写入
|
||||
if let Some(design_file) = vhdl_parse(&pathbuf) {
|
||||
if let Some(mut fast) = make_fast_from_design_file(&design_file) {
|
||||
if let Some(vhdl_project) = &mut *vhdl_project.write().unwrap() {
|
||||
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();
|
||||
// for module in &fast.content {
|
||||
// if module.name == "None" {
|
||||
|
127
src/sources.rs
127
src/sources.rs
@ -1,7 +1,7 @@
|
||||
use crate::core::hdlparam::HdlParam;
|
||||
use crate::core::primitive_parser::PrimitiveText;
|
||||
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::definition::def_types::*;
|
||||
use crate::definition::get_scopes_from_syntax_tree;
|
||||
@ -775,10 +775,72 @@ pub fn vhdl_parser_pipeline(
|
||||
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 text = doc.to_string();
|
||||
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);
|
||||
file.parse_ir = Some(parse_ir);
|
||||
|
||||
@ -839,66 +901,11 @@ pub fn vhdl_parser_pipeline(
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: add bounds checking for utf8<->utf16 conversions
|
||||
/// This trait defines some helper functions to convert between lsp types
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 2446bd0a812d1667ad7033f10cd27a03967fa15e
|
||||
Subproject commit cf95eb9b901e847b54ed824b6b6a780fd2f6eac3
|
Loading…
x
Reference in New Issue
Block a user