FastWaveBackend/src/main.rs

448 lines
14 KiB
Rust
Raw Normal View History

2022-04-14 04:50:37 +00:00
use std::io::prelude::*;
use std::io;
use std::fs::File;
2022-05-18 02:04:32 +00:00
use std::collections::BTreeMap;
2022-05-19 07:44:24 +00:00
use chrono::prelude::*;
use ::function_name::named;
2022-04-14 04:50:37 +00:00
use num::*;
use clap::Parser;
2022-06-02 20:51:56 +00:00
use std::slice;
use std::str;
2022-04-14 04:50:37 +00:00
#[derive(Parser)]
struct Cli {
/// The path to the file to read
#[clap(parse(from_os_str))]
path: std::path::PathBuf}
2022-04-14 04:50:37 +00:00
2022-05-19 07:44:24 +00:00
// TODO: implement any timescales greater than a second
2022-05-23 03:00:03 +00:00
#[derive(Debug)]
enum Timescale {ps, ns, us, ms, s, unit}
2022-05-19 07:44:24 +00:00
2022-05-23 03:00:03 +00:00
#[derive(Debug)]
struct Scope_Idx(usize);
2022-05-23 03:00:03 +00:00
#[derive(Debug)]
struct Signal_Idx(usize);
2022-05-23 03:00:03 +00:00
#[derive(Debug)]
2022-05-23 23:19:17 +00:00
struct Version(String);
2022-05-19 07:44:24 +00:00
2022-05-23 03:00:03 +00:00
#[derive(Debug)]
struct Metadata {
2022-05-23 23:19:17 +00:00
date : Option<DateTime<Utc>>,
version : Option<Version>,
2022-05-28 00:48:17 +00:00
timescale : (Option<u32>, Timescale)}
2022-05-19 07:44:24 +00:00
2022-05-23 03:00:03 +00:00
#[derive(Debug)]
2022-05-19 07:44:24 +00:00
enum SignalGeneric{
2022-05-23 03:00:03 +00:00
Signal{
name : String,
timeline : BTreeMap<BigInt, BigInt>,
scope_parent : Scope_Idx},
SignalAlias{
name : String,
signal_alias : Signal_Idx}
}
2022-05-18 02:04:32 +00:00
2022-05-23 03:00:03 +00:00
#[derive(Debug)]
2022-05-19 07:44:24 +00:00
struct Scope {
name : String,
child_signals : Vec<Signal_Idx>,
child_scopes : Vec<Scope_Idx>}
2022-05-19 07:44:24 +00:00
2022-05-23 03:00:03 +00:00
#[derive(Debug)]
2022-05-19 07:44:24 +00:00
struct VCD {
metadata : Metadata,
all_signals : Vec<SignalGeneric>,
// the root scope should always be placed at index 0
all_scopes : Vec<Scope>}
2022-05-29 01:37:43 +00:00
#[derive(Debug, PartialEq)]
enum Date_Parser_State {Begin, Parsing}
2022-05-29 01:37:43 +00:00
#[derive(Debug, PartialEq)]
enum Version_Parser_State {Begin, Parsing}
2022-05-29 01:37:43 +00:00
#[derive(Debug, PartialEq)]
enum Timescale_Parser_State {Begin, Parsing}
2022-05-29 01:37:43 +00:00
#[derive(Debug, PartialEq)]
2022-05-28 00:48:17 +00:00
enum Signal_Tree_Parser_State {Begin, Parsing}
2022-05-23 03:00:03 +00:00
2022-05-22 00:40:46 +00:00
2022-05-29 01:37:43 +00:00
#[derive(Debug, PartialEq)]
enum Parser_State {
Date(Date_Parser_State),
Version(Version_Parser_State),
Timescale(Timescale_Parser_State),
2022-05-28 00:48:17 +00:00
Signal_Tree(Signal_Tree_Parser_State),
2022-05-22 00:40:46 +00:00
Parse_Signal_Values}
struct VCD_Parser<'a> {
vcd_parser_state : Parser_State,
buffer : Option<String>,
2022-05-22 00:40:46 +00:00
vcd : &'a mut VCD,
2022-05-23 03:00:03 +00:00
curr_scope : Option<&'a Scope>,
curr_parent_scope : Option<&'a Scope>}
impl VCD {
pub fn new() -> Self {
let metadata = Metadata {
2022-05-23 23:19:17 +00:00
date : None,
version : None,
2022-05-28 00:48:17 +00:00
timescale : (None, Timescale::unit)};
VCD {
metadata : metadata,
all_signals : Vec::<SignalGeneric>::new(),
2022-05-24 03:59:57 +00:00
all_scopes : Vec::<Scope>::new()}
}
}
impl<'a> VCD_Parser<'a> {
2022-05-23 03:00:03 +00:00
pub fn new(vcd : &'a mut VCD) -> Self {
VCD_Parser {
vcd_parser_state : Parser_State::Date(Date_Parser_State::Begin),
buffer : None,
2022-05-23 03:00:03 +00:00
vcd : vcd,
curr_scope : None,
curr_parent_scope : None
}
}
pub fn parse_word(&mut self, word : &str) -> Result<(), String> {
let mut state = &mut self.vcd_parser_state;
2022-05-23 03:00:03 +00:00
let t = &self.vcd;
match state {
Parser_State::Date(_) => self.parse_date(word),
Parser_State::Version(_) => self.parse_version(word),
2022-05-28 00:48:17 +00:00
Parser_State::Timescale(_) => self.parse_timescale(word),
2022-05-23 03:00:03 +00:00
// TODO : Enable the following in production
2022-05-28 00:48:17 +00:00
// _ => Err(format!("parser in bad state : {state:?}"))
2022-05-23 03:00:03 +00:00
// TODO : Disable the following in production
2022-05-24 03:59:57 +00:00
_ => {
Err(format!("parser in bad state : {state:?}; {t:?}"))
}
2022-05-23 03:00:03 +00:00
}
}
2022-05-19 07:44:24 +00:00
#[named]
pub fn parse_date(&mut self, word : &str) -> Result<(), String> {
let mut state = &mut self.vcd_parser_state;
match state {
Parser_State::Date(Date_Parser_State::Begin) =>
match word {
"$date" => {
*state = Parser_State::Date(Date_Parser_State::Parsing);
Ok(())
}
_ => {
*state = Parser_State::Version(Version_Parser_State::Begin);
2022-05-24 03:59:57 +00:00
self.parse_version(word)
}
2022-05-22 00:40:46 +00:00
}
Parser_State::Date(Date_Parser_State::Parsing) =>
match word {
"$end" => {
let s = self.buffer.take().unwrap();
let dt = Utc.datetime_from_str(s.as_str(), "%a %b %e %T %Y")
2022-05-28 00:48:17 +00:00
.expect(&format!("invalid date {s}").as_str());
*state = Parser_State::Version(Version_Parser_State::Begin);
self.vcd.metadata.date = Some(dt);
Ok(())
}
_ => {
if let Some(ref mut buffer) = self.buffer {
buffer.push_str(" ");
buffer.push_str(word);
}
else {
self.buffer = Some(word.to_string());
}
Ok(())
}
2022-05-22 00:40:46 +00:00
}
_ => Err(format!("{state:?} should be unreachable within {}.",function_name!())),
}
}
2022-05-29 01:37:43 +00:00
#[named]
pub fn parse_statement(
&'a mut self,
curr_word : &str,
key_word : &str,
begin_state : Parser_State,
parsing_state : Parser_State,
end_state : Parser_State,
next_parser : fn(&'a mut VCD_Parser, &str) -> Result<(), String>
) -> Result<(), String> {
let mut state = &mut self.vcd_parser_state;
if (*state == begin_state) {
return match curr_word {
key_word => {
*state = Parser_State::Date(Date_Parser_State::Parsing);
Ok(())
}
_ => {
*state = Parser_State::Version(Version_Parser_State::Begin);
next_parser(self, curr_word)
}
}
}
else {
Ok(())
}
// Ok(())
// match state {
// Parser_State::Date(Date_Parser_State::Begin) =>
// match curr_word {
// key_word => {
// *state = Parser_State::Date(Date_Parser_State::Parsing);
// Ok(())
// }
// _ => {
// *state = Parser_State::Version(Version_Parser_State::Begin);
// self.parse_version(curr_word)
// }
// }
// Parser_State::Date(Date_Parser_State::Parsing) =>
// match curr_word {
// "$end" => {
// let s = self.buffer.take().unwrap();
// let dt = Utc.datetime_from_str(s.as_str(), "%a %b %e %T %Y")
// .expect(&format!("invalid date {s}").as_str());
// *state = Parser_State::Version(Version_Parser_State::Begin);
// self.vcd.metadata.date = Some(dt);
// Ok(())
// }
// _ => {
// if let Some(ref mut buffer) = self.buffer {
// buffer.push_str(" ");
// buffer.push_str(curr_word);
// }
// else {
// self.buffer = Some(curr_word.to_string());
// }
// Ok(())
// }
// }
// _ => Err(format!("{state:?} should be unreachable within {}.",function_name!())),
// }
}
#[named]
pub fn parse_version(&mut self, word : &str) -> Result<(), String> {
let mut state = &mut self.vcd_parser_state;
match state {
Parser_State::Version(Version_Parser_State::Begin) =>
2022-05-23 03:00:03 +00:00
match word {
"$version" => {
*state = Parser_State::Version(Version_Parser_State::Parsing);
Ok(())
}
_ => {
*state = Parser_State::Timescale(Timescale_Parser_State::Begin);
2022-05-23 23:19:17 +00:00
Ok(())
}
2022-05-23 03:00:03 +00:00
}
Parser_State::Version(Version_Parser_State::Parsing) =>
match word {
"$end" => {
let s = self.buffer.take().unwrap();
self.vcd.metadata.version = Some(Version(s));
2022-05-28 00:48:17 +00:00
*state = Parser_State::Timescale(Timescale_Parser_State::Begin);
Ok(())
}
_ => {
if let Some(ref mut buffer) = self.buffer {
buffer.push_str(" ");
buffer.push_str(word);
}
else {
self.buffer = Some(word.to_string());
}
Ok(())
}
}
_ => Err(format!("{state:?} should be unreachable within {}.",function_name!())),
}
}
#[named]
pub fn parse_timescale(&mut self, word : &str) -> Result<(), String> {
let mut state = &mut self.vcd_parser_state;
match state {
Parser_State::Timescale(Timescale_Parser_State::Begin) =>
match word {
"$timescale" => {
*state = Parser_State::Timescale(Timescale_Parser_State::Parsing);
Ok(())
}
_ => {
*state = Parser_State::Signal_Tree(Signal_Tree_Parser_State::Begin);
Ok(())
}
}
Parser_State::Timescale(Timescale_Parser_State::Parsing) =>
match word {
"$end" => {
let s = self.buffer.take().unwrap();
let s = s.split_ascii_whitespace();
let s = s.collect::<Vec<&str>>();
let scalar = s[0].to_string().parse::<u32>().unwrap();
let unit = s[1];
let unit = match unit {
"ps" => Ok(Timescale::ps),
"ns" => Ok(Timescale::ns),
"us" => Ok(Timescale::us),
"ms" => Ok(Timescale::ms),
"s" => Ok(Timescale::s),
// TODO : see if there is a way to easily print out all enum variants
// _ => Err(format!("{word} is not a valid unit of time in {Timescale}"))
_ => Err(format!("{unit} is not a valid unit"))
}.unwrap();
dbg!(s);
self.vcd.metadata.timescale = (Some(scalar), unit);
*state = Parser_State::Timescale(Timescale_Parser_State::Begin);
Ok(())
}
_ => {
if let Some(ref mut buffer) = self.buffer {
buffer.push_str(" ");
buffer.push_str(word);
}
else {
self.buffer = Some(word.to_string());
}
Ok(())
}
2022-05-23 03:00:03 +00:00
}
_ => Err(format!("{state:?} should be unreachable within {}.",function_name!())),
}
}
}
2022-04-14 04:50:37 +00:00
2022-06-02 20:51:56 +00:00
struct Line(u32);
struct Col(u32);
struct Position(Line, Col);
fn yield_word_and_apply(file : File, mut f : impl FnMut(&[u8], Position) -> Result<(), String>) {
2022-04-14 04:50:37 +00:00
let mut reader = io::BufReader::new(file);
let mut buffer = String::new();
2022-06-02 20:51:56 +00:00
let mut line = 0u32;
while true {
let bytes_read = reader.read_line(&mut buffer).unwrap();
if bytes_read == 0 {break}
line += 1;
let mut col = 1u32;
let mut words = buffer.split_ascii_whitespace();
for word in words {
2022-06-02 20:51:56 +00:00
let word = word.as_bytes();
let position = Position(Line(line), Col(col));
f(word, position).unwrap();
col += (word.len() as u32) + 1;
}
buffer.clear();
2022-04-14 04:50:37 +00:00
}
}
2022-06-02 20:51:56 +00:00
struct YieldByWord {
reader : io::BufReader<File>,
words : Vec<String>,
EOF : bool,
buffer : String,
str_slices : Vec<(*const u8, usize)>,
}
impl YieldByWord {
fn new(file : File) -> YieldByWord {
let mut reader = io::BufReader::new(file);
YieldByWord {
reader : reader,
words : vec![],
EOF : false,
buffer : "".to_string(),
str_slices : vec![],
}
}
fn next_word(&mut self) -> Option<&str> {
// if there are no more words, attempt to read more content
// from the file
if self.str_slices.is_empty() {
self.buffer.clear();
if self.EOF {return None}
let line_chunk_size = 10;
for _ in 0..line_chunk_size {
let bytes_read = self.reader.read_line(&mut self.buffer).unwrap();
// we hit the end of the file, so we go ahead and return None
if bytes_read == 0 {self.EOF = true}
}
let words = self.buffer.split_ascii_whitespace();
self.str_slices = words
.rev()
.map(|s| (s.as_ptr(), s.len()))
.collect();
}
// if we make it here, we return the next word
unsafe {
let (ptr, len) = self.str_slices.pop().unwrap();
let slice = slice::from_raw_parts(ptr, len);
return Some(str::from_utf8(slice).unwrap());
};
}
}
fn main() -> std::io::Result<()> {
let args = Cli::parse();
2022-05-19 07:44:24 +00:00
let file = File::open(&args.path)?;
2022-06-02 20:51:56 +00:00
let mut word_gen = YieldByWord::new(file);
let mut word_count = 0;
let mut last_word = String::new();
// for word in 0..5 {
// dbg!(word_gen.next_word());
// }
while word_gen.next_word().is_some() {
word_count += 1;
}
dbg!(word_count);
// loop {
// let next_word = word_gen.next_word();
// if next_word.is_some() {
// last_word = next_word.unwrap();
// }
// else {
// break
// }
// }
// dbg!(last_word);
2022-05-23 03:00:03 +00:00
2022-04-14 04:50:37 +00:00
Ok(())
}