use std::collections::HashSet; use std::path::PathBuf; use vhdl_lang::{kind_str, Token, VHDLParser, VHDLStandard}; use super::fast_hdlparam::*; pub fn vhdl_parser(path: &str) -> FastHdlparam { // The path of SystemVerilog source file let path = PathBuf::from(path); let mut hdlparam = FastHdlparam { fast: Vec::new() }; let parser = VHDLParser::new(VHDLStandard::VHDL2008); let mut diagnostics = Vec::new(); let (_, design_file) = parser.parse_design_file(&path, &mut diagnostics).unwrap(); let mut all_tockens = Vec::new(); for (tokens, _) in design_file.design_units { all_tockens.extend(tokens); } hdlparam.fast.extend(parse_tokens(all_tockens)); hdlparam } fn parse_tokens(tokens: Vec) -> Vec { let mut modules = Vec::new(); let mut instance_type = HashSet::new(); let mut i = 0; while i < tokens.len() { let token = &tokens[i]; match kind_str(token.kind) { "entity" => { i += 1; let module = Module { name: get_value(&tokens[i]), params: Vec::new(), ports: Vec::new(), instances: Vec::new(), range: Range { start: Position { line: tokens[i].pos.range.start.line + 1, character: tokens[i].pos.range.start.character + 1 }, end: Position { line: tokens[i].pos.range.end.line + 1, character: tokens[i].pos.range.end.character + 1 } } }; modules.push(module); } "component" => { i += 1; instance_type.insert(get_value(&tokens[i])); while !(kind_str(tokens[i].kind) == "end" && kind_str(tokens[i+1].kind) == "component") { i += 1; } i += 1; } ":" => { if instance_type.contains(&get_value(&tokens[i+1])) { let instance = Instance { name: get_value(&tokens[i-1]), inst_type: get_value(&tokens[i+1]), instports: None, instparams: None, range: Range { start: Position { line: tokens[i-1].pos.range.start.line, character: tokens[i-1].pos.range.start.character }, end: Position { line: tokens[i+1].pos.range.start.line, character: tokens[i+1].pos.range.start.character } } }; modules.last_mut().unwrap().instances.push(instance); } } "generic" => { let is_map = kind_str(tokens[i+1].kind) == "map"; let (params, next_index) = parse_parameters(&tokens, i + 1, is_map); if is_map { let start = params.first().unwrap().range.start.clone(); let end = params.last().unwrap().range.start.clone(); modules.last_mut().unwrap().instances.last_mut().unwrap().instparams = Some(Range { start, end }); } else { modules.last_mut().unwrap().params.extend(params); } i = next_index; } "port" => { let is_map = kind_str(tokens[i+1].kind) == "map"; let (ports, next_index) = parse_port(&tokens, i + 1, is_map); if is_map { let start = ports.first().unwrap().range.start.clone(); let end = ports.last().unwrap().range.start.clone(); modules.last_mut().unwrap().instances.last_mut().unwrap().instports = Some(Range { start, end }); } else { modules.last_mut().unwrap().ports.extend(ports); } i = next_index; } _ => {} } i += 1; } // println!("{:?}", modules); modules } fn parse_port(tokens: &[Token], start: usize, is_map: bool) -> (Vec, usize) { let mut ports = Vec::new(); let mut i = start; let mut stack = Vec::new(); while i < tokens.len() { let token = &tokens[i]; match kind_str(token.kind) { "(" => { stack.push(token); } ")" => { if stack.is_empty() { break; } stack.pop(); } ";" => { if stack.is_empty() { break; } } "{identifier}" => { if is_map { let start_pos = tokens[i].pos.range.start; let end_pos = tokens[i+3].pos.range.end; let port = Port { name: get_value(&tokens[i]), dir_type: "none".to_string(), net_type: get_value(&tokens[i+2]), width: "none".to_string(), signed: "unsigned".to_string(), range: Range { start: Position { line: start_pos.line + 1, character: start_pos.character + 1 }, end: Position { line: end_pos.line + 1, character: end_pos.character + 1 } }, }; i += 2; ports.push(port); } else { let start_pos = tokens[i].pos.range.start; let width ; let end_idx; if get_value(&tokens[i+3]).contains("VECTOR") || get_value(&tokens[i+3]).contains("vector") { let (width_str, index) = parse_width(&tokens, i+4); width = "[".to_string() + &width_str + "]"; end_idx = index; } else { width = "1".to_string(); end_idx = i+3; } let end_pos = tokens[end_idx].pos.range.end; let direction = if kind_str(tokens[i+2].kind) == "buffer" { "out" } else { kind_str(tokens[i+2].kind) }; let port = Port { name: get_value(&tokens[i]), dir_type: direction.to_string(), net_type: get_value(&tokens[i+3]), width, signed: "unsigned".to_string(), range: Range { start: Position { line: start_pos.line + 1, character: start_pos.character + 1 }, end: Position { line: end_pos.line + 1, character: end_pos.character + 1 } }, }; i = end_idx; ports.push(port); } } _ => {} } i += 1; } (ports, i) } fn parse_width(tokens: &[Token], start: usize) -> (String, usize) { let mut width = String::new(); let mut i = start; let mut stack = Vec::new(); while i < tokens.len() { match kind_str(tokens[i].kind) { "(" => { stack.push(&tokens[i]); } ")" => { if stack.is_empty() { break; } stack.pop(); } ";" => { if stack.is_empty() { break; } } _ => { if stack.len() >= 1 { if get_value(&tokens[i]) == "None" { if kind_str(tokens[i].kind) == "downto" || kind_str(tokens[i].kind) == "to" { width = width + ":"; } else { width = width + kind_str(tokens[i].kind); } } else { width = width + &get_value(&tokens[i]); } } } } i += 1; } (width, i) } fn parse_parameters(tokens: &[Token], start: usize, is_map: bool) -> (Vec, usize) { let mut params = Vec::new(); let mut i = start; let mut stack = Vec::new(); while i < tokens.len() { let token = &tokens[i]; match kind_str(token.kind) { "(" => { stack.push(token); } ")" => { if stack.is_empty() { break; } stack.pop(); } ";" => { if stack.is_empty() { break; } } "{identifier}" => { if is_map { let start_pos = tokens[i].pos.range.start; let end_pos = tokens[i+2].pos.range.end; let param = Parameter { name: get_value(&tokens[i]), net_type: get_value(&tokens[i+2]), init: get_value(&tokens[i+2]), range: Range { start: Position { line: start_pos.line + 1, character: start_pos.character + 1 }, end: Position { line: end_pos.line + 1, character: end_pos.character + 1 } }, }; i += 2; params.push(param); } else { let start_pos = tokens[i].pos.range.start; let end_pos = tokens[i+4].pos.range.end; let param = Parameter { name: get_value(&tokens[i]), net_type: get_value(&tokens[i+2]), init: get_value(&tokens[i+4]), range: Range { start: Position { line: start_pos.line + 1, character: start_pos.character + 1 }, end: Position { line: end_pos.line + 1, character: end_pos.character + 1 } }, }; i += 4; params.push(param); } } _ => {} } i += 1; } (params, i) } fn get_value(token: &Token) -> String { match &token.value { vhdl_lang::Value::Identifier(symbol) => { return symbol.name_utf8(); } vhdl_lang::Value::String(latin1_string) => { return latin1_string.to_string(); } vhdl_lang::Value::BitString(latin1_string, _) => { return latin1_string.to_string().replace("\\", ""); } vhdl_lang::Value::AbstractLiteral(latin1_string, _) => { return latin1_string.to_string(); } vhdl_lang::Value::Character(character) => { return character.to_string(); } vhdl_lang::Value::Text(latin1_string) => { return latin1_string.to_string(); } vhdl_lang::Value::None => { return "None".to_string(); } } }