From a7d2b119989a5b140f006ae4da027c18f3b824f6 Mon Sep 17 00:00:00 2001 From: Yehowshua Immanuel Date: Sun, 7 Aug 2022 18:57:58 -0400 Subject: [PATCH] now running much faster, but due for refactor --- README.md | 9 +- src/vcd/parse.rs | 60 +++++-- src/vcd/parse/events.rs | 355 ++++++++++++++++++++++++---------------- 3 files changed, 267 insertions(+), 157 deletions(-) diff --git a/README.md b/README.md index 70fe645..21b5df2 100644 --- a/README.md +++ b/README.md @@ -3,13 +3,13 @@ Copyright - Yehowshua Immanuel # A High performance, VCD Parser written in Rust ## Current Features - - pretty fast, parses 3.04 GB VCD file in ~54s on M1 Macbook Air with + - pretty fast, parses 3.04 GB VCD file in ~27.23s on M1 Macbook Air with respect to 30s with GTKWave on the same device. FastWave currently - offers highly robust error handling which GTKWave doesn't have. + offers highly robust error(at least on the sample VCD files in this + repository) handling which GTKWave doesn't have. I noticed that when running FastWave in the VsCode terminal as opposed - to the MacOS system terminal or the Lapce terminal, FastWave takes 67s - to parse the 3.04GB file. + to the MacOS system terminal or the Lapce terminal. # Current Limitations @@ -40,6 +40,7 @@ Here's a command to test on a malformed VCD: ## Features - [ ] macro for getting line number when propagating errors + - [ ] search for any ok_or's - [ ] search for any unwraps or any direct vectors indexing - [ ] re-order all signal timelines as binary balanced trees with respect to timestamps - support multithreaded re-ordering diff --git a/src/vcd/parse.rs b/src/vcd/parse.rs index 8927102..813a9eb 100644 --- a/src/vcd/parse.rs +++ b/src/vcd/parse.rs @@ -22,9 +22,31 @@ use events::*; use std::cmp::Ordering; fn compare_strs(a: &str, b: &str) -> Ordering { - let last_idx = if a.len() > b.len() { a.len() } else { b.len() }; - // let last_idx += -1; - Ordering::Less + // choose the smaller of the two indices + let upper_bound = if a.len() > b.len() { b.len() } else { a.len() }; + let a_as_bytes = a.as_bytes(); + let b_as_bytes = b.as_bytes(); + + for i in 0..upper_bound { + let a_byte = a_as_bytes[i]; + let b_byte = b_as_bytes[i]; + if a_byte > b_byte { + return Ordering::Greater; + } + if b_byte > a_byte { + return Ordering::Less; + } + } + + if a.len() > b.len() { + return Ordering::Greater; + } + + if a.len() < b.len() { + return Ordering::Less; + } + + return Ordering::Equal; } fn ordered_binary_lookup(map: &Vec<(String, SignalIdx)>, key: &str) -> Result { @@ -34,7 +56,7 @@ fn ordered_binary_lookup(map: &Vec<(String, SignalIdx)>, key: &str) -> Result { @@ -93,21 +115,35 @@ pub fn parse_vcd(file: File) -> Result { signal_map1.sort_by(|a: &(String, SignalIdx), b: &(String, SignalIdx)| { let a = &a.0; let b = &b.0; - a.partial_cmp(&b).unwrap() + compare_strs(a, b) }); - let now = std::time::Instant::now(); for (k, v) in &signal_map1 { let signal_idx = ordered_binary_lookup(&signal_map1, k.as_str())?; assert!(*v == signal_idx); } - let ordered_binary_search_elapsed = now.elapsed(); - println!( - "ordered_binary_search_elapsed: {:.2?}", - ordered_binary_search_elapsed - ); - // parse_events(&mut wosrd_gen, &mut vcd, &mut signal_map)?; + // let now = std::time::Instant::now(); + // for (k, v) in &signal_map1 { + // let signal_idx = ordered_binary_lookup(&signal_map1, k.as_str())?; + // assert!(*v == signal_idx); + // } + // let ordered_binary_search_elapsed = now.elapsed(); + // println!( + // "ordered_binary_search_elapsed: {:.2?}", + // ordered_binary_search_elapsed + // ); + + // let now = std::time::Instant::now(); + // for (k, v) in &signal_map1 { + // // let signal_idx = ordered_binary_lookup(&signal_map1, k.as_str())?; + // let signal_idx = signal_map.get(k).unwrap(); + // assert!(*v == *signal_idx); + // } + // let hashmap_search_elapsed = now.elapsed(); + // println!("hashmap_search_elapsed: {:.2?}", hashmap_search_elapsed); + + parse_events(&mut word_gen, &mut vcd, &mut signal_map)?; Ok(vcd) } diff --git a/src/vcd/parse/events.rs b/src/vcd/parse/events.rs index 14bb81c..e280e14 100644 --- a/src/vcd/parse/events.rs +++ b/src/vcd/parse/events.rs @@ -1,18 +1,26 @@ //! part of the vcd parser that handles parsing the signal tree and //! building the resulting signal tree +use core::time; + use super::*; #[derive(Debug)] -pub(super) enum BinaryParserErrTypes {XValue, ZValue, UValue, OtherValue(char), TooLong} +pub(super) enum BinaryParserErrTypes { + XValue, + ZValue, + UValue, + OtherValue(char), + TooLong, +} // We build a quick and not so dirty bit string parser. -fn base2_str_to_byte(word : &[u8]) -> Result { +fn base2_str_to_byte(word: &[u8]) -> Result { let mut val = 0u8; // shouldn't have more than 8 chars in str let len = word.len(); if len > 8 { - return Err(BinaryParserErrTypes::TooLong) + return Err(BinaryParserErrTypes::TooLong); } let bit_lut = [ @@ -23,89 +31,93 @@ fn base2_str_to_byte(word : &[u8]) -> Result { 0b0001_0000u8, 0b0010_0000u8, 0b0100_0000u8, - 0b1000_0000u8 + 0b1000_0000u8, ]; for (idx, chr) in word.iter().rev().enumerate() { match chr { - b'1' => {val = bit_lut[idx] | val} + b'1' => val = bit_lut[idx] | val, b'0' => {} - b'x' | b'X' => {return Err(BinaryParserErrTypes::XValue)} - b'z' | b'Z' => {return Err(BinaryParserErrTypes::ZValue)} - b'u' | b'U' => {return Err(BinaryParserErrTypes::UValue)} - _ => {return Err(BinaryParserErrTypes::OtherValue(*chr as char))} + b'x' | b'X' => return Err(BinaryParserErrTypes::XValue), + b'z' | b'Z' => return Err(BinaryParserErrTypes::ZValue), + b'u' | b'U' => return Err(BinaryParserErrTypes::UValue), + _ => return Err(BinaryParserErrTypes::OtherValue(*chr as char)), } - } Ok(val) } -fn binary_str_to_vec_u8(binary_str : &str) -> Result, BinaryParserErrTypes> { - let mut vec_u8 : Vec = Vec::new(); +fn binary_str_to_vec_u8(binary_str: &str) -> Result, BinaryParserErrTypes> { + let mut vec_u8: Vec = Vec::new(); let binary_str_as_bytes = binary_str.as_bytes(); let mut tail_idx = binary_str_as_bytes.len(); // clamp head if provided binary str is less than 8 long - let mut head_idx = - if tail_idx >= 8 - {binary_str_as_bytes.len() - 8} - else - {0}; + let mut head_idx = if tail_idx >= 8 { + binary_str_as_bytes.len() - 8 + } else { + 0 + }; while tail_idx > 0 { let curr_b_val = &binary_str_as_bytes[head_idx..tail_idx]; let val_u8 = base2_str_to_byte(curr_b_val)?; vec_u8.push(val_u8); - if head_idx < 8 { head_idx = 0 - } - else { + } else { head_idx = head_idx - 8; } if tail_idx < 8 { tail_idx = 0 - } - else { + } else { tail_idx = tail_idx - 8; } - } Ok(vec_u8) } pub(super) fn parse_events<'a>( - word_reader : &mut WordReader, - vcd : &'a mut VCD, - signal_map : &mut HashMap + word_reader: &mut WordReader, + vcd: &'a mut VCD, + signal_map: &mut HashMap, ) -> Result<(), String> { + // let hash_time = std::time::Duration::ZERO; + // let hash_time = std::time::Duration::ZERO; loop { let next_word = word_reader.next_word(); // The following is the only case where eof is not an error. // If we've reached the end of the file, then there is obviously // nothing left to do... - if next_word.is_err() {break}; + if next_word.is_err() { + break; + }; let (word, cursor) = next_word.unwrap(); let Cursor(Line(_), Word(word_in_line_idx)) = cursor; // we only want to match on the first word in a line - if word_in_line_idx != 1 {continue} + if word_in_line_idx != 1 { + continue; + } match &word[0..1] { "$" => {} "#" => { let value = &word[1..]; - let (f, l )= (file!(), line!()); + let (f, l) = (file!(), line!()); let value = BigInt::parse_bytes(value.as_bytes(), 10).ok_or( - format!("Error near {f}:{l}. Failed to parse {value} as BigInt at {cursor:?}").as_str())?; + format!("Error near {f}:{l}. Failed to parse {value} as BigInt at {cursor:?}") + .as_str(), + )?; let (_, mut value) = value.to_bytes_le(); - // TODO : u32 helps with less memory, but should ideally likely be - // configurable. - let (f, l )= (file!(), line!()); - let start_idx = u32::try_from(vcd.timeline.len()).map_err( - |_| format!("Error near {f}:{l}. Failed to convert from usize to u32."))?; + // TODO : u32 helps with less memory, but should ideally likely be + // configurable. + let (f, l) = (file!(), line!()); + let start_idx = u32::try_from(vcd.timeline.len()).map_err(|_| { + format!("Error near {f}:{l}. Failed to convert from usize to u32.") + })?; vcd.timeline_markers.push(StartIdx(start_idx)); vcd.timeline.append(&mut value); } @@ -115,50 +127,55 @@ pub(super) fn parse_events<'a>( let binary_value = &word[1..]; let observed_num_bits = binary_value.len(); - let mut value_u8 : Vec = Vec::new(); + let mut value_u8: Vec = Vec::new(); let mut value_string = String::new(); - + let mut store_as_string = false; // If we encounter x or z in a value, we can recover from // the error and store the value as a string. // Or else, we we propagate up other errors. match binary_str_to_vec_u8(binary_value) { - Ok(result) => {value_u8 = result;} - Err(BinaryParserErrTypes::XValue | - BinaryParserErrTypes::ZValue | - BinaryParserErrTypes::UValue - ) => - { - store_as_string = true; - value_string = binary_value.to_string(); - } + Ok(result) => { + value_u8 = result; + } + Err( + BinaryParserErrTypes::XValue + | BinaryParserErrTypes::ZValue + | BinaryParserErrTypes::UValue, + ) => { + store_as_string = true; + value_string = binary_value.to_string(); + } Err(e) => { - let (f, l )= (file!(), line!()); - Err(e).map_err( - |e| format!("Error near {f}:{l}. Error {e:?} at {cursor:?}."))?; + let (f, l) = (file!(), line!()); + Err(e).map_err(|e| { + format!("Error near {f}:{l}. Error {e:?} at {cursor:?}.") + })?; } } - + // this word should be the signal alias let (word, cursor) = word_reader.next_word().unwrap(); // lookup signal idx - let (f, l )= (file!(), line!()); - let SignalIdx(ref signal_idx) = signal_map.get(word).ok_or( - format!("Error near {f}:{l}. Failed to lookup signal {word} at {cursor:?}"))?; + let SignalIdx(ref signal_idx) = signal_map.get(word).ok_or(()).map_err(|_| { + format!( + "Error near {}:{}. Failed to lookup signal {word} at {cursor:?}", + file!(), + line!() + ) + })?; // account for fact that signal idx could be an alias, so there // could be one step of indirection - let signal_idx = - { + let signal_idx = { let signal = vcd.all_signals.get(*signal_idx).unwrap(); match signal { - Signal::Data {..} => {*signal_idx} - Signal::Alias {signal_alias, ..} => { + Signal::Data { .. } => *signal_idx, + Signal::Alias { signal_alias, .. } => { let SignalIdx(ref signal_idx) = signal_alias; signal_idx.clone() - } } }; @@ -167,11 +184,20 @@ pub(super) fn parse_events<'a>( // of the signal signal_idx references let signal = vcd.all_signals.get_mut(signal_idx).unwrap(); match signal { - Signal::Data {name, sig_type, ref mut signal_error, num_bits, - u8_timeline, u8_timeline_markers, string_timeline, - string_timeline_markers, ..} => { - - if signal_error.is_some() {continue;} + Signal::Data { + name, + sig_type, + ref mut signal_error, + num_bits, + u8_timeline, + u8_timeline_markers, + string_timeline, + string_timeline_markers, + .. + } => { + if signal_error.is_some() { + continue; + } // Get the observed number of bits for the value parsed earlier // and verify that it is not greater than the numbits declared @@ -193,39 +219,40 @@ pub(super) fn parse_events<'a>( } None => { let (f, l) = (file!(), line!()); - let msg = format!("\ + let msg = format!( + "\ Error near {f}:{l}. The bitwidth for signal {name} \ must be specified for a signal of type {sig_type:?}. \ This error occurred while parsing the vcd file at \ - {cursor:?}"); + {cursor:?}" + ); Err(msg)?; } }; - let (f, l )= (file!(), line!()); - let timeline_idx = u32::try_from(vcd.timeline.len()).map_err( - |_| format!("Error near {f}:{l}. Failed to convert from usize to u32."))?; + let (f, l) = (file!(), line!()); + let timeline_idx = u32::try_from(vcd.timeline.len()).map_err(|_| { + format!("Error near {f}:{l}. Failed to convert from usize to u32.") + })?; let timeline_idx = TimelineIdx(timeline_idx); if store_as_string { string_timeline_markers.push(timeline_idx); string_timeline.push(value_string); Ok(()) - - } - else { + } else { u8_timeline_markers.push(timeline_idx); - + let mut curr_num_bytes = value_u8.len(); u8_timeline.append(&mut value_u8); - // we may need to zero extend values + // we may need to zero extend values // so that we end up storing all values // of a particular signal in a consistent // amount of bytes let num_bits = num_bits.unwrap(); - let bytes_required = (num_bits / 8) + - if (num_bits % 8) > 0 {1} else {0}; + let bytes_required = + (num_bits / 8) + if (num_bits % 8) > 0 { 1 } else { 0 }; while curr_num_bytes < bytes_required { // useful for debugging @@ -243,8 +270,8 @@ pub(super) fn parse_events<'a>( Ok(()) } } - Signal::Alias {..} => { - let (f, l )= (file!(), line!()); + Signal::Alias { .. } => { + let (f, l) = (file!(), line!()); let msg = format!( "Error near {f}:{l}, a signal alias should not point to a signal alias.\n\ This error occurred while parsing vcd file at {cursor:?}"); @@ -257,21 +284,24 @@ pub(super) fn parse_events<'a>( "0" => { // lookup signal idx let hash = &word[1..]; - let (f, l )= (file!(), line!()); - let SignalIdx(ref signal_idx) = signal_map.get(hash).ok_or( - format!("Error near {f}:{l}. Failed to lookup signal {hash} at {cursor:?}"))?; + let (f, l) = (file!(), line!()); + let SignalIdx(ref signal_idx) = signal_map.get(hash).ok_or(()).map_err(|_| { + format!( + "Error near {}:{}. Failed to lookup signal {hash} at {cursor:?}", + file!(), + line!() + ) + })?; // account for fact that signal idx could be an alias, so there // could be one step of indirection - let signal_idx = - { + let signal_idx = { let signal = vcd.all_signals.get(*signal_idx).unwrap(); match signal { - Signal::Data {..} => {*signal_idx} - Signal::Alias {signal_alias, ..} => { + Signal::Data { .. } => *signal_idx, + Signal::Alias { signal_alias, .. } => { let SignalIdx(ref signal_idx) = signal_alias; signal_idx.clone() - } } }; @@ -280,11 +310,19 @@ pub(super) fn parse_events<'a>( // of the signal signal_idx references let signal = vcd.all_signals.get_mut(signal_idx).unwrap(); match signal { - Signal::Data {name, sig_type, ref mut signal_error, num_bits, - u8_timeline, u8_timeline_markers, ..} => { - + Signal::Data { + name, + sig_type, + ref mut signal_error, + num_bits, + u8_timeline, + u8_timeline_markers, + .. + } => { // if this is a bad signal, go ahead and skip it - if signal_error.is_some() {continue;} + if signal_error.is_some() { + continue; + } // Get bitwidth and verify that it is 1. // Also account for the error case of a bitwidth of `None` @@ -292,38 +330,43 @@ pub(super) fn parse_events<'a>( Some(ref num_bits) => { if *num_bits != 1 { let (f, l) = (file!(), line!()); - let msg = format!("\ + let msg = format!( + "\ Error near {f}:{l}. The bitwidth for signal {name} \ of sig_type {sig_type:?} is expected to be `1` not \ `{num_bits}`. \ This error occurred while parsing the vcd file at \ - {cursor:?}"); + {cursor:?}" + ); *signal_error = Some(msg); continue; } } None => { let (f, l) = (file!(), line!()); - let msg = format!("\ + let msg = format!( + "\ Error near {f}:{l}. The bitwidth for signal {name} \ must be specified for a signal of type {sig_type:?}. \ This error occurred while parsing the vcd file at \ - {cursor:?}"); + {cursor:?}" + ); Err(msg)?; } }; - let (f, l )= (file!(), line!()); - let timeline_idx = u32::try_from(vcd.timeline.len()).map_err( - |_| format!("Error near {f}:{l}. Failed to convert from usize to u32."))?; + let (f, l) = (file!(), line!()); + let timeline_idx = u32::try_from(vcd.timeline.len()).map_err(|_| { + format!("Error near {f}:{l}. Failed to convert from usize to u32.") + })?; let timeline_idx = TimelineIdx(timeline_idx); u8_timeline_markers.push(timeline_idx); u8_timeline.push(0u8); Ok(()) } - Signal::Alias {..} => { - let (f, l )= (file!(), line!()); + Signal::Alias { .. } => { + let (f, l) = (file!(), line!()); let msg = format!( "Error near {f}:{l}, a signal alias should not point to a signal alias.\n\ This error occurred while parsing vcd file at {cursor:?}"); @@ -335,21 +378,23 @@ pub(super) fn parse_events<'a>( "1" => { // lokup signal idx let hash = &word[1..]; - let (f, l )= (file!(), line!()); - let SignalIdx(ref signal_idx) = signal_map.get(hash).ok_or( - format!("Error near {f}:{l}. Failed to lookup signal {hash} at {cursor:?}"))?; + let SignalIdx(ref signal_idx) = signal_map.get(hash).ok_or(()).map_err(|_| { + format!( + "Error near {}:{}. Failed to lookup signal {hash} at {cursor:?}", + file!(), + line!() + ) + })?; // account for fact that signal idx could be an alias, so there // could be one step of indirection - let signal_idx = - { + let signal_idx = { let signal = vcd.all_signals.get(*signal_idx).unwrap(); match signal { - Signal::Data {..} => {*signal_idx} - Signal::Alias {signal_alias, ..} => { + Signal::Data { .. } => *signal_idx, + Signal::Alias { signal_alias, .. } => { let SignalIdx(ref signal_idx) = signal_alias; signal_idx.clone() - } } }; @@ -358,11 +403,19 @@ pub(super) fn parse_events<'a>( // of the signal signal_idx references let signal = vcd.all_signals.get_mut(signal_idx).unwrap(); match signal { - Signal::Data {name, sig_type, ref mut signal_error, num_bits, - u8_timeline, u8_timeline_markers, ..} => { - + Signal::Data { + name, + sig_type, + ref mut signal_error, + num_bits, + u8_timeline, + u8_timeline_markers, + .. + } => { // if this is a bad signal, go ahead and skip it - if signal_error.is_some() {continue;} + if signal_error.is_some() { + continue; + } // Get bitwidth and verify that it is 1. // Also account for the error case of a bitwidth of `None` @@ -370,38 +423,43 @@ pub(super) fn parse_events<'a>( Some(ref num_bits) => { if *num_bits != 1 { let (f, l) = (file!(), line!()); - let msg = format!("\ + let msg = format!( + "\ Error near {f}:{l}. The bitwidth for signal {name} \ of sig_type {sig_type:?} is expected to be `1` not \ `{num_bits}`. \ This error occurred while parsing the vcd file at \ - {cursor:?}"); + {cursor:?}" + ); *signal_error = Some(msg); continue; } } None => { let (f, l) = (file!(), line!()); - let msg = format!("\ + let msg = format!( + "\ Error near {f}:{l}. The bitwidth for signal {name} \ must be specified for a signal of type {sig_type:?}. \ This error occurred while parsing the vcd file at \ - {cursor:?}"); + {cursor:?}" + ); Err(msg)?; } }; - let (f, l )= (file!(), line!()); - let timeline_idx = u32::try_from(vcd.timeline.len()).map_err( - |_| format!("Error near {f}:{l}. Failed to convert from usize to u32."))?; + let (f, l) = (file!(), line!()); + let timeline_idx = u32::try_from(vcd.timeline.len()).map_err(|_| { + format!("Error near {f}:{l}. Failed to convert from usize to u32.") + })?; let timeline_idx = TimelineIdx(timeline_idx); u8_timeline_markers.push(timeline_idx); u8_timeline.push(1u8); Ok(()) } - Signal::Alias {..} => { - let (f, l )= (file!(), line!()); + Signal::Alias { .. } => { + let (f, l) = (file!(), line!()); let msg = format!( "Error near {f}:{l}, a signal alias should not point to a signal alias.\n\ This error occurred while parsing vcd file at {cursor:?}"); @@ -414,21 +472,23 @@ pub(super) fn parse_events<'a>( let val = word.to_string(); // lokup signal idx let hash = &word[1..]; - let (f, l )= (file!(), line!()); - let SignalIdx(ref signal_idx) = signal_map.get(hash).ok_or( - format!("Error near {f}:{l}. Failed to lookup signal {hash} at {cursor:?}"))?; + let SignalIdx(ref signal_idx) = signal_map.get(hash).ok_or(()).map_err(|_| { + format!( + "Error near {}:{}. Failed to lookup signal {hash} at {cursor:?}", + file!(), + line!() + ) + })?; // account for fact that signal idx could be an alias, so there // could be one step of indirection - let signal_idx = - { + let signal_idx = { let signal = vcd.all_signals.get(*signal_idx).unwrap(); match signal { - Signal::Data {..} => {*signal_idx} - Signal::Alias {signal_alias, ..} => { + Signal::Data { .. } => *signal_idx, + Signal::Alias { signal_alias, .. } => { let SignalIdx(ref signal_idx) = signal_alias; signal_idx.clone() - } } }; @@ -437,11 +497,19 @@ pub(super) fn parse_events<'a>( // of the signal signal_idx references let signal = vcd.all_signals.get_mut(signal_idx).unwrap(); match signal { - Signal::Data {name, sig_type, ref mut signal_error, num_bits, - string_timeline, string_timeline_markers, ..} => { - + Signal::Data { + name, + sig_type, + ref mut signal_error, + num_bits, + string_timeline, + string_timeline_markers, + .. + } => { // if this is a bad signal, go ahead and skip it - if signal_error.is_some() {continue;} + if signal_error.is_some() { + continue; + } // Get bitwidth and verify that it is 1. // Also account for the error case of a bitwidth of `None` @@ -449,38 +517,43 @@ pub(super) fn parse_events<'a>( Some(ref num_bits) => { if *num_bits != 1 { let (f, l) = (file!(), line!()); - let msg = format!("\ + let msg = format!( + "\ Error near {f}:{l}. The bitwidth for signal {name} \ of sig_type {sig_type:?} is expected to be `1` not \ `{num_bits}`. \ This error occurred while parsing the vcd file at \ - {cursor:?}"); + {cursor:?}" + ); *signal_error = Some(msg); continue; } } None => { let (f, l) = (file!(), line!()); - let msg = format!("\ + let msg = format!( + "\ Error near {f}:{l}. The bitwidth for signal {name} \ must be specified for a signal of type {sig_type:?}. \ This error occurred while parsing the vcd file at \ - {cursor:?}"); + {cursor:?}" + ); Err(msg)?; } }; - let (f, l )= (file!(), line!()); - let timeline_idx = u32::try_from(vcd.timeline.len()).map_err( - |_| format!("Error near {f}:{l}. Failed to convert from usize to u32."))?; + let (f, l) = (file!(), line!()); + let timeline_idx = u32::try_from(vcd.timeline.len()).map_err(|_| { + format!("Error near {f}:{l}. Failed to convert from usize to u32.") + })?; let timeline_idx = TimelineIdx(timeline_idx); string_timeline_markers.push(timeline_idx); string_timeline.push(val); Ok(()) } - Signal::Alias {..} => { - let (f, l )= (file!(), line!()); + Signal::Alias { .. } => { + let (f, l) = (file!(), line!()); let msg = format!( "Error near {f}:{l}, a signal alias should not point to a signal alias.\n\ This error occurred while parsing vcd file at {cursor:?}"); @@ -494,4 +567,4 @@ pub(super) fn parse_events<'a>( } Ok(()) -} \ No newline at end of file +}