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 { 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)>, Option<(EntityDeclaration, Vec)>)>, ) -> Option { 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 = arch.entity_name.item.item.name_utf8(); 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); if let Some((entity, entity_tokens)) = entity_units { 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()); }); } } let instances = arch.statements.iter().filter(|statement| { match statement.statement.item { ConcurrentStatement::Instance(_) => true, _ => false } }) .map(|statement| parse_instance(statement, arch_tokens)) .collect::>(); 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) -> 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::>(); } 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::>(); } } _ => () }; parsed_instance } fn parse_instance_name(name: &vhdl_lang::ast::token_range::WithTokenSpan) -> 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) -> 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) -> 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) -> String { // skip '(' and ')' let width = 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::(); "[".to_string() + width.as_str() + "]" } 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(); } } }