~ruther/gtkwave-tcl-generator

f2309875e50e66ab61c32522d613d5420c557dfa — František Boháček 1 year, 10 months ago 8eaa162
feat: map new parsers to tcl generator inputs
1 files changed, 140 insertions(+), 37 deletions(-)

M src/main.rs
M src/main.rs => src/main.rs +140 -37
@@ 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<DisplayColor>,
    format: Option<DisplayFormat>,
    omit: bool,
}

impl Context {
    pub fn update<'a>(&mut self, updates: impl Iterator<Item = &'a ContextUpdate>) {
        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<Item = &'a ContextUpdate>) -> Context {
        let mut clone = self.clone();
        clone.update(updates);

        clone
    }

    pub fn decompose(&self) -> (Option<DisplayColor>, Option<DisplayFormat>, 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<impl Iterator<Item = &'a Operation>>,
    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);
}

Do not follow this link