326 lines
13 KiB
Rust
326 lines
13 KiB
Rust
use std::path::PathBuf;
|
|
use log::info;
|
|
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::*;
|
|
|
|
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_units(
|
|
arch_and_entity: Vec<(Option<(ArchitectureBody, Vec<Token>)>, Option<(EntityDeclaration, Vec<Token>)>)>,
|
|
) -> Option<FastHdlparam> {
|
|
let mut hdlparam = FastHdlparam {
|
|
fast_macro: Macro {
|
|
defines: Vec::new(),
|
|
errors: Vec::new(),
|
|
includes: Vec::new(),
|
|
invalid: Vec::new()
|
|
},
|
|
content: Vec::new(),
|
|
entitys: Vec::new(),
|
|
file_type: "common".to_string()
|
|
};
|
|
|
|
// info!("arch and entity {arch_and_entity:#?}");
|
|
|
|
arch_and_entity.iter().for_each(|units| {
|
|
match units {
|
|
(Some((arch, arch_tokens)), entity_units) => {
|
|
let name = if let Some((entity, _)) = entity_units {
|
|
entity.ident.tree.item.name_utf8()
|
|
} else {
|
|
"".to_string()
|
|
};
|
|
let arch_name = arch.ident.tree.item.name_utf8();
|
|
let range = get_range_from_token(
|
|
arch_tokens.get_token(arch.span().get_start_token()),
|
|
arch_tokens.get_token(arch.span().get_end_token())
|
|
);
|
|
|
|
hdlparam.new_vhdl_module(name, arch_name, range);
|
|
|
|
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
|
|
}
|
|
}
|
|
(None, Some((entity, entity_tokens))) => {
|
|
let name = entity.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_entity(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_entity_parameter(name, net_type, init, range.clone());
|
|
});
|
|
}
|
|
|
|
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_entity_port(name, dir_type, net_type, width, range.clone());
|
|
});
|
|
}
|
|
}
|
|
(None, None) => ()
|
|
}
|
|
});
|
|
|
|
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())
|
|
);
|
|
|
|
let mut parsed_instance = Instance {
|
|
name,
|
|
inst_type: "".to_string(),
|
|
instparams: None,
|
|
intstparam_assignments: Vec::new(),
|
|
instports: None,
|
|
intstport_assignments: Vec::new(),
|
|
range
|
|
};
|
|
|
|
match &statement.statement.item {
|
|
ConcurrentStatement::Instance(instance) => {
|
|
parsed_instance.inst_type = match &instance.unit {
|
|
InstantiatedUnit::Component(name) | InstantiatedUnit::Configuration(name) => {
|
|
parse_instance_name(name)
|
|
},
|
|
InstantiatedUnit::Entity(name, arch_name_ref) => {
|
|
let name = parse_instance_name(name);
|
|
|
|
let arch_name = if let Some(arch_name_ref) = arch_name_ref {
|
|
format!("({})", arch_name_ref.item.item.name_utf8())
|
|
} else {
|
|
"".to_string()
|
|
};
|
|
|
|
name + &arch_name
|
|
}
|
|
_ => "unknown".to_string()
|
|
};
|
|
|
|
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 {
|
|
get_range_from_token(
|
|
tokens.get_token(association_ele.actual.span().get_start_token()),
|
|
tokens.get_token(association_ele.actual.span().get_end_token())
|
|
)
|
|
};
|
|
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 {
|
|
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_instance_name(name: &vhdl_lang::ast::token_range::WithTokenSpan<Name>) -> String {
|
|
match &name.item {
|
|
Name::Designator(designator) => {
|
|
match &designator.item {
|
|
Designator::Identifier(symbol) => symbol.name_utf8(),
|
|
_ => "unknown".to_string()
|
|
}
|
|
}
|
|
Name::Selected(_lib_name, designator_token) => {
|
|
match &designator_token.item.item {
|
|
Designator::Identifier(symbol) => symbol.name_utf8(),
|
|
_ => "unknown".to_string()
|
|
}
|
|
}
|
|
_ => "unknown".to_string()
|
|
}
|
|
}
|
|
|
|
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 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 {
|
|
"1".to_string()
|
|
};
|
|
let init = if let Some(expression) = &simple_mode.expression {
|
|
parse_width_from_tokenspan(expression.span(), tokens)
|
|
} else {
|
|
"unknown".to_string()
|
|
};
|
|
(dir_type, net_type, width, init)
|
|
}
|
|
_ => ("unknown".to_string(), "unknown".to_string(), "unknown".to_string(), "unknown".to_string())
|
|
};
|
|
interface_list.push((name, dir_type, net_type, width, init, range));
|
|
}
|
|
_ => ()
|
|
}
|
|
});
|
|
interface_list
|
|
}
|
|
|
|
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 {
|
|
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();
|
|
}
|
|
}
|
|
} |