restructuring and WIP
This commit is contained in:
parent
c65bdfefac
commit
1c006441fb
84
src/main.rs
84
src/main.rs
|
@ -1,9 +1,4 @@
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use chrono::prelude::*;
|
|
||||||
use ::function_name::named;
|
|
||||||
|
|
||||||
use num::*;
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
||||||
pub mod vcd;
|
pub mod vcd;
|
||||||
|
@ -15,74 +10,27 @@ struct Cli {
|
||||||
#[clap(parse(from_os_str))]
|
#[clap(parse(from_os_str))]
|
||||||
path: std::path::PathBuf}
|
path: std::path::PathBuf}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Version(String);
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum Timescale {ps, ns, us, ms, s, unit}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Metadata {
|
|
||||||
date : Option<DateTime<Utc>>,
|
|
||||||
version : Option<Version>,
|
|
||||||
timescale : (Option<u32>, Timescale)}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Scope_Idx(usize);
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Signal_Idx(usize);
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum SignalGeneric{
|
|
||||||
Signal{
|
|
||||||
name : String,
|
|
||||||
timeline : BTreeMap<BigInt, BigInt>,
|
|
||||||
scope_parent : Scope_Idx},
|
|
||||||
SignalAlias{
|
|
||||||
name : String,
|
|
||||||
signal_alias : Signal_Idx}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Scope {
|
|
||||||
name : String,
|
|
||||||
child_signals : Vec<Signal_Idx>,
|
|
||||||
child_scopes : Vec<Scope_Idx>}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct VCD {
|
|
||||||
metadata : Metadata,
|
|
||||||
all_signals : Vec<SignalGeneric>,
|
|
||||||
// the root scope should always be placed at index 0
|
|
||||||
all_scopes : Vec<Scope>}
|
|
||||||
|
|
||||||
impl VCD {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
let metadata = Metadata {
|
|
||||||
date : None,
|
|
||||||
version : None,
|
|
||||||
timescale : (None, Timescale::unit)};
|
|
||||||
VCD {
|
|
||||||
metadata : metadata,
|
|
||||||
all_signals : Vec::<SignalGeneric>::new(),
|
|
||||||
all_scopes : Vec::<Scope>::new()}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn main() -> std::io::Result<()> {
|
fn main() -> std::io::Result<()> {
|
||||||
let args = Cli::parse();
|
let args = Cli::parse();
|
||||||
|
|
||||||
let file = File::open(&args.path)?;
|
let file = File::open(&args.path)?;
|
||||||
let mut word_gen = WordReader::new(file);
|
dbg!(["hello", "goodbye", "myworld"].contains(&"myworlde"));
|
||||||
let mut word_count = 0;
|
// let mut word_gen = WordReader::new(file);
|
||||||
|
// let mut word_count = 0;
|
||||||
|
|
||||||
|
// while word_gen.next_word().is_some() {
|
||||||
|
// word_count += 1;
|
||||||
|
// }
|
||||||
|
// dbg!(word_count);
|
||||||
|
|
||||||
|
// let word1 = "hello world";
|
||||||
|
// let word2 = "hello planet";
|
||||||
|
// dbg!(&word1[0..6].len());
|
||||||
|
dbg!(take_until("tea time now: and later", b':'));
|
||||||
|
// parse_vcd(file);
|
||||||
|
|
||||||
|
// tag("my oh my");
|
||||||
|
|
||||||
while word_gen.next_word().is_some() {
|
|
||||||
word_count += 1;
|
|
||||||
}
|
|
||||||
dbg!(word_count);
|
|
||||||
|
|
||||||
// loop {
|
// loop {
|
||||||
// let word = word_gen.next_word();
|
// let word = word_gen.next_word();
|
||||||
|
|
|
@ -1,2 +1,8 @@
|
||||||
mod reader;
|
mod reader;
|
||||||
pub use reader::*;
|
pub use reader::*;
|
||||||
|
|
||||||
|
mod types;
|
||||||
|
pub use types::*;
|
||||||
|
|
||||||
|
mod parse;
|
||||||
|
pub use parse::*;
|
188
src/vcd/parse.rs
Normal file
188
src/vcd/parse.rs
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
use super::*;
|
||||||
|
use std::fs::File;
|
||||||
|
use ::function_name::named;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Residual<'a>(&'a str);
|
||||||
|
|
||||||
|
pub fn take_until<'a>(word : &'a str, pattern : u8) -> Option<(&'a str, Residual)> {
|
||||||
|
let mut new_start = 0;
|
||||||
|
|
||||||
|
for chr in word.as_bytes() {
|
||||||
|
if (*chr == pattern) {
|
||||||
|
return Some((&word[0..new_start], Residual(&word[new_start..])));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
new_start += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tag<'a>(word : &'a str, pattern : &'a str) -> Option<&'a str> {
|
||||||
|
let lhs = word.as_bytes().iter();
|
||||||
|
let rhs = pattern.as_bytes();
|
||||||
|
let iter = lhs.zip(rhs);
|
||||||
|
let mut new_start = 0;
|
||||||
|
|
||||||
|
let mut res = true;
|
||||||
|
for (c_lhs, c_rhs) in iter {
|
||||||
|
res = res && (c_lhs == c_rhs);
|
||||||
|
if !res {return None}
|
||||||
|
new_start += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(&word[new_start..])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[named]
|
||||||
|
fn parse_date(word_reader : &mut WordReader) -> Result<(), String> {
|
||||||
|
let mut parsed_day = false;
|
||||||
|
let mut parsed_month = false;
|
||||||
|
let mut parsed_date = false;
|
||||||
|
let mut parsed_hh = false;
|
||||||
|
let mut parsed_mm = false;
|
||||||
|
let mut parsed_ss = false;
|
||||||
|
let mut parsed_year = false;
|
||||||
|
let mut parsed_end = false;
|
||||||
|
|
||||||
|
let day = {
|
||||||
|
// check for another word in the file
|
||||||
|
let (word, cursor) = word_reader.next_word().expect(
|
||||||
|
format!("reached end of file without parser leaving {}", function_name!()).as_str()
|
||||||
|
);
|
||||||
|
|
||||||
|
let days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
||||||
|
if !days.contains(&word) {
|
||||||
|
let msg = format!("reached end of file without parser leaving {}\n", function_name!());
|
||||||
|
let msg2 = format!("{word} is not a valid weekday : expected one of {days:?}\n");
|
||||||
|
let msg3 = format!("failure location: {cursor:?}");
|
||||||
|
return Err(format!("{}{}{}", msg, msg2, msg3))
|
||||||
|
}
|
||||||
|
|
||||||
|
word.to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
let month = {
|
||||||
|
// check for another word in the file
|
||||||
|
let (word, cursor) = word_reader.next_word().expect(
|
||||||
|
format!("reached end of file without parser leaving {}", function_name!()).as_str()
|
||||||
|
);
|
||||||
|
|
||||||
|
let months = [
|
||||||
|
"Jan", "Feb", "Mar", "Apr",
|
||||||
|
"May", "Jun", "Jul", "Aug",
|
||||||
|
"Sept", "Oct", "Nov", "Dec",
|
||||||
|
];
|
||||||
|
|
||||||
|
if !months.contains(&word) {
|
||||||
|
let msg = format!("reached end of file without parser leaving {}\n", function_name!());
|
||||||
|
let msg2 = format!("{word} is not a valid month : expected one of {months:?}\n");
|
||||||
|
let msg3 = format!("failure location: {cursor:?}");
|
||||||
|
return Err(format!("{}{}{}", msg, msg2, msg3))
|
||||||
|
}
|
||||||
|
|
||||||
|
word.to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
let date = {
|
||||||
|
// check for another word in the file
|
||||||
|
let (word, cursor) = word_reader.next_word().expect(
|
||||||
|
format!("reached end of file without parser leaving {}", function_name!()).as_str()
|
||||||
|
);
|
||||||
|
|
||||||
|
let date : u8 = word.to_string().parse().unwrap();
|
||||||
|
|
||||||
|
if date > 31 {
|
||||||
|
let msg = format!("reached end of file without parser leaving {}\n", function_name!());
|
||||||
|
let msg2 = format!("{word} is not a valid date : must be between 0 and 31\n");
|
||||||
|
let msg3 = format!("failure location: {cursor:?}");
|
||||||
|
return Err(format!("{}{}{}", msg, msg2, msg3))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
word.to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
let (hh, mm, ss) = {
|
||||||
|
// check for another word in the file
|
||||||
|
let (word, cursor) = word_reader.next_word().expect(
|
||||||
|
format!("reached end of file without parser leaving {}", function_name!()).as_str()
|
||||||
|
);
|
||||||
|
|
||||||
|
let date : u8 = word.to_string().parse().unwrap();
|
||||||
|
// let hh = take_until(word, b':').unwrap();
|
||||||
|
|
||||||
|
if date > 31 {
|
||||||
|
let msg = format!("reached end of file without parser leaving {}\n", function_name!());
|
||||||
|
let msg2 = format!("{word} is not a valid date : must be between 0 and 31\n");
|
||||||
|
let msg3 = format!("failure location: {cursor:?}");
|
||||||
|
return Err(format!("{}{}{}", msg, msg2, msg3))
|
||||||
|
|
||||||
|
}
|
||||||
|
("", "", "")
|
||||||
|
};
|
||||||
|
|
||||||
|
// else if !parsed_date {
|
||||||
|
|
||||||
|
// }
|
||||||
|
// else if !parsed_hh {
|
||||||
|
|
||||||
|
// }
|
||||||
|
// else if !parsed_mm {
|
||||||
|
|
||||||
|
// }
|
||||||
|
// else if !parsed_ss {
|
||||||
|
|
||||||
|
// }
|
||||||
|
// else if !parsed_year {
|
||||||
|
|
||||||
|
// }
|
||||||
|
// else if !parsed_end {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[named]
|
||||||
|
fn parse_header(word_reader : &mut WordReader) -> Result<(), String> {
|
||||||
|
loop {
|
||||||
|
// check for another word in the file
|
||||||
|
let word = word_reader.next_word();
|
||||||
|
|
||||||
|
// if there isn't another word left in the file, then we exit
|
||||||
|
if word.is_none() {
|
||||||
|
return Err(format!("reached end of file without parser leaving {}", function_name!()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// destructure
|
||||||
|
let (word, cursor) = word.unwrap();
|
||||||
|
let ident = tag(word, "$");
|
||||||
|
|
||||||
|
match tag(word, "$") {
|
||||||
|
// we hope that this word stars with a `$`
|
||||||
|
Some(ident) => {
|
||||||
|
match ident {
|
||||||
|
"date" => {println!("got date")}
|
||||||
|
"version" => {println!("got version")}
|
||||||
|
"timescale" => {println!("got timescale")}
|
||||||
|
"scope" => {return Ok(())}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if not, then we keep looping
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
// Ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_vcd(file : File) {
|
||||||
|
let mut word_gen = WordReader::new(file);
|
||||||
|
|
||||||
|
parse_header(&mut word_gen);
|
||||||
|
}
|
|
@ -1,5 +1,3 @@
|
||||||
use super::*;
|
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
|
59
src/vcd/types.rs
Normal file
59
src/vcd/types.rs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use chrono::prelude::*;
|
||||||
|
use num::BigInt;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Version(String);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Timescale {ps, ns, us, ms, s, unit}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(super) struct Metadata {
|
||||||
|
date : Option<DateTime<Utc>>,
|
||||||
|
version : Option<Version>,
|
||||||
|
timescale : (Option<u32>, Timescale)}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Scope_Idx(usize);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Signal_Idx(usize);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum SignalGeneric{
|
||||||
|
Signal{
|
||||||
|
name : String,
|
||||||
|
timeline : BTreeMap<BigInt, BigInt>,
|
||||||
|
scope_parent : Scope_Idx},
|
||||||
|
SignalAlias{
|
||||||
|
name : String,
|
||||||
|
signal_alias : Signal_Idx}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Scope {
|
||||||
|
name : String,
|
||||||
|
child_signals : Vec<Signal_Idx>,
|
||||||
|
child_scopes : Vec<Scope_Idx>}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct VCD {
|
||||||
|
metadata : Metadata,
|
||||||
|
all_signals : Vec<SignalGeneric>,
|
||||||
|
// the root scope should always be placed at index 0
|
||||||
|
all_scopes : Vec<Scope>}
|
||||||
|
|
||||||
|
impl VCD {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let metadata = Metadata {
|
||||||
|
date : None,
|
||||||
|
version : None,
|
||||||
|
timescale : (None, Timescale::unit)};
|
||||||
|
VCD {
|
||||||
|
metadata : metadata,
|
||||||
|
all_signals : Vec::<SignalGeneric>::new(),
|
||||||
|
all_scopes : Vec::<Scope>::new()}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue