now running much faster, but due for refactor

This commit is contained in:
Yehowshua Immanuel 2022-08-07 18:57:58 -04:00
parent b86e5fd3e4
commit a7d2b11998
3 changed files with 267 additions and 157 deletions

View file

@ -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

View file

@ -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<SignalIdx, String> {
@ -34,7 +56,7 @@ fn ordered_binary_lookup(map: &Vec<(String, SignalIdx)>, key: &str) -> Result<Si
while lower_idx <= upper_idx {
let mid_idx = lower_idx + ((upper_idx - lower_idx) / 2);
let (str_val, signal_idx) = map.get(mid_idx).unwrap();
let ordering = key.partial_cmp(str_val.as_str()).unwrap();
let ordering = compare_strs(key, str_val.as_str());
match ordering {
Ordering::Less => {
@ -93,21 +115,35 @@ pub fn parse_vcd(file: File) -> Result<VCD, String> {
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)
}

View file

@ -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<u8, BinaryParserErrTypes> {
fn base2_str_to_byte(word: &[u8]) -> Result<u8, BinaryParserErrTypes> {
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<u8, BinaryParserErrTypes> {
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<Vec<u8>, BinaryParserErrTypes> {
let mut vec_u8 : Vec<u8> = Vec::new();
fn binary_str_to_vec_u8(binary_str: &str) -> Result<Vec<u8>, BinaryParserErrTypes> {
let mut vec_u8: Vec<u8> = 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<String, SignalIdx>
word_reader: &mut WordReader,
vcd: &'a mut VCD,
signal_map: &mut HashMap<String, SignalIdx>,
) -> 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<u8> = Vec::new();
let mut value_u8: Vec<u8> = 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(())
}
}