From f2309875e50e66ab61c32522d613d5420c557dfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Boh=C3=A1=C4=8Dek?= Date: Sat, 2 Sep 2023 09:40:28 +0200 Subject: [PATCH] feat: map new parsers to tcl generator inputs --- src/main.rs | 177 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 140 insertions(+), 37 deletions(-) diff --git a/src/main.rs b/src/main.rs index e9410b3..f2ec6d3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,19 @@ -pub mod file_parser; +pub mod comment_parser; pub mod display_elements; +pub mod file_parser; pub mod tcl_generator; -use std::{path::PathBuf, fs::File, io::Write}; +use std::{fs::File, io::Write, path::PathBuf}; use clap::{arg, Parser}; -use file_parser::FileParser; +use comment_parser::{CommentParser, ContextUpdate, Operation}; +use display_elements::DisplayFormat; +use file_parser::{FileParser, ParsedArchitecturePart, ParsedEntity}; use glob::glob; use tcl_generator::TclGenerator; use vhdl_lang::{syntax::Symbols, Source}; -use crate::display_elements::{Signal, DisplayOption, DisplayColor}; +use crate::display_elements::DisplayColor; #[derive(Parser)] #[command(author, version, about, long_about = None)] @@ -38,44 +41,23 @@ fn main() { let source = Source::from_latin1_file(file.as_path()).unwrap(); let contents = source.contents(); - let mut parser = FileParser::new(&source, &contents, &symbols); - - match parser.find_next_entity() { - Ok(entity) => { - if entity.name() != &cli.testbench[..] { - continue; - } - found = true; - - println!("Found the testbench."); - - let entity = parser.parse_entity_architecture(entity).unwrap(); - let architecture = entity.architecture().unwrap(); + let mut entities = FileParser::parse_file(&source, &contents, &symbols).unwrap(); - let mut generator = TclGenerator::new("top.".to_owned() + &cli.testbench + "."); - generator.add_signal(&Signal::new("clk".to_owned(), vec![DisplayOption::Color(DisplayColor::Indigo)])) - .add_signal(&Signal::new("rst".to_owned(), vec![DisplayOption::Color(DisplayColor::Indigo)])) - .add_empty() - .zoom_out(); - - for signal in architecture.signals() { - if signal.name() == "clk" || signal.name() == "rst" { - continue; - } + for entity in entities { + if entity.name() != cli.testbench { + continue; + } + found = true; + println!("Found the testbench."); - generator.add_signal(signal); - } + let tcl = generate_tcl(entity); - let generated = generator.generate(); + let mut file = File::create(cli.output.clone()).unwrap(); + file.write_all(tcl.as_bytes()).unwrap(); - let mut file = File::create(&cli.output).unwrap(); - file.write_all(generated.as_bytes()).unwrap(); + println!("Generated {}.", cli.output.display()); - break; - }, - Err(err) => { - println!("{:?}", err); - } + break; } if found { @@ -87,3 +69,124 @@ fn main() { println!("Could not find the entity.") } } + +#[derive(Eq, PartialEq, Clone)] +struct Context { + color: Option, + format: Option, + omit: bool, +} + +impl Context { + pub fn update<'a>(&mut self, updates: impl Iterator) { + for update in updates { + match update { + ContextUpdate::Reset => { + self.color = None; + self.format = None; + self.omit = false; + } + ContextUpdate::SetOmit(omit) => { + self.omit = omit.clone(); + } + ContextUpdate::UpdateColor(color) => { + self.color = color.clone(); + } + ContextUpdate::UpdateFormat(format) => { + self.format = Some(format.clone()); + } + } + } + } + + pub fn fork<'a>(&self, updates: impl Iterator) -> Context { + let mut clone = self.clone(); + clone.update(updates); + + clone + } + + pub fn decompose(&self) -> (Option, Option, bool) { + (self.color, self.format, self.omit) + } +} + +fn generate_tcl(entity: ParsedEntity) -> String { + let architecture = entity.architecture().unwrap(); + + let mut generator = TclGenerator::new("top.".to_owned() + entity.name() + "."); + + let mut context = Context { + color: None, + format: None, + omit: false, + }; + + for part in architecture.parts() { + match part { + ParsedArchitecturePart::Comment(comment) => { + let operations = CommentParser::parse_comment(&comment[..]); + if let Some(operation) = operations.first() { + if let Operation::AddSignal(signal) = operation { + let context_operations = operations.iter().skip(1); + add_signal( + &mut generator, + signal.clone(), + Some(context_operations), + &context, + ); + } + } else { + let updates = operations.iter().filter_map(|op| match op { + Operation::UpdateContext(update) => Some(update), + Operation::AddEmpty => { + generator.add_empty(); + None + } + _ => panic!(), + }); + context.update(updates); + } + } + ParsedArchitecturePart::Signal(signal) => { + let mut operations = None; + + if let Some(comment) = signal.comment() { + operations = Some(CommentParser::parse_comment(comment)); + } + + add_signal( + &mut generator, + signal.name().to_owned(), + operations.as_ref().map(|x| x.iter()), + &context, + ); + } + } + } + + generator.generate() +} + +fn add_signal<'a>( + generator: &mut TclGenerator, + signal: String, + operations: Option>, + context: &Context, +) { + let (color, format, omit) = if let Some(operations) = operations { + let updates = operations.into_iter().filter_map(|op| { + if let Operation::UpdateContext(update) = op { + Some(update) + } else { + None + } + }); + + context.fork(updates).decompose() + } else { + context.decompose() + }; + + generator.add_signal(signal, color, format); +} -- 2.49.0