A => +71 -0
@@ 0,0 1,71 @@
use crate::display_elements::{DisplayColor, DisplayFormat};
pub enum Operation {
UpdateContext(ContextUpdate),
AddEmpty,
AddSignal(String),
}
pub enum ContextUpdate {
UpdateColor(Option<DisplayColor>),
UpdateFormat(DisplayFormat),
SetOmit(bool),
Reset,
}
pub struct CommentParser {}
impl CommentParser {
pub fn parse_comment(comment: &str) -> Vec<Operation> {
comment
.split(['\n', ','].as_ref())
.map(|token| Self::parse_token(token))
.filter(|operation| operation.is_some())
.into_iter()
.map(|operation| operation.unwrap())
.collect()
}
fn parse_token(token: &str) -> Option<Operation> {
Some(match token {
"omit" => Operation::UpdateContext(ContextUpdate::SetOmit(true)),
"empty" => Operation::AddEmpty,
"reset" => Operation::UpdateContext(ContextUpdate::Reset),
_ if token.starts_with("add signal ") => Operation::AddSignal(
token["add signal ".len()..].to_owned(),
),
_ if token.starts_with("format ") => Operation::UpdateContext(
ContextUpdate::UpdateFormat(Self::parse_format(&token["format ".len()..])),
),
_ if token.starts_with("color ") => Operation::UpdateContext(
ContextUpdate::UpdateColor(Self::parse_color(&token["color ".len()..])),
),
_ => return None,
})
}
fn parse_format(format: &str) -> DisplayFormat {
match format {
"hex" => DisplayFormat::Hex,
"decimal" => DisplayFormat::Decimal,
"signed decimal" => DisplayFormat::SignedDecimal,
"binary" => DisplayFormat::Binary,
_ => DisplayFormat::Decimal,
}
}
fn parse_color(color: &str) -> Option<DisplayColor> {
Some(match color {
"normal" => DisplayColor::Normal,
"red" => DisplayColor::Red,
"orange" => DisplayColor::Orange,
"yellow" => DisplayColor::Yellow,
"green" => DisplayColor::Green,
"blue" => DisplayColor::Blue,
"Indigo" => DisplayColor::Indigo,
"Violet" => DisplayColor::Violet,
"Cycle" => DisplayColor::Cycle,
_ => return None,
})
}
}
M src/display_elements.rs => src/display_elements.rs +27 -113
@@ 1,44 1,10 @@
-use std::{slice::Iter, fmt::Display};
-
-#[derive(Eq, PartialEq, Clone)]
-pub enum DisplayElement {
- Signal(Signal),
- Empty(Vec<DisplayOption>)
-}
+use std::{fmt::Display, slice::Iter};
#[derive(Eq, PartialEq, Clone, Copy)]
pub enum DisplayOption {
Color(DisplayColor),
Format(DisplayFormat),
- Omit
-}
-
-#[derive(Eq, PartialEq, Clone)]
-pub struct Signal {
- name: String,
- options: Vec<DisplayOption>
-}
-
-impl From<&str> for Signal {
- fn from(value: &str) -> Self {
- Self {
- name: value.to_owned(),
- options: vec![]
- }
- }
-}
-
-#[derive(Eq, PartialEq, Clone)]
-pub struct Entity {
- name: String,
- architecture: Option<Architecture>,
-}
-
-#[derive(Eq, PartialEq, Clone)]
-pub struct Architecture {
- name: String,
- entity_name: String,
- signals: Vec<Signal>
+ Omit,
}
#[derive(Eq, PartialEq, Copy, Clone)]
@@ 56,17 22,21 @@ pub enum DisplayColor {
impl Display for DisplayColor {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "{}", match self {
- DisplayColor::Normal => "Normal",
- DisplayColor::Red => "Red",
- DisplayColor::Orange => "Orange",
- DisplayColor::Yellow => "Yellow",
- DisplayColor::Green => "Green",
- DisplayColor::Blue => "Blue",
- DisplayColor::Indigo => "Indigo",
- DisplayColor::Violet => "Violet",
- DisplayColor::Cycle => "Cycle",
- })
+ write!(
+ f,
+ "{}",
+ match self {
+ DisplayColor::Normal => "Normal",
+ DisplayColor::Red => "Red",
+ DisplayColor::Orange => "Orange",
+ DisplayColor::Yellow => "Yellow",
+ DisplayColor::Green => "Green",
+ DisplayColor::Blue => "Blue",
+ DisplayColor::Indigo => "Indigo",
+ DisplayColor::Violet => "Violet",
+ DisplayColor::Cycle => "Cycle",
+ }
+ )
}
}
@@ 80,71 50,15 @@ pub enum DisplayFormat {
impl Display for DisplayFormat {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "{}", match self {
- DisplayFormat::Hex => "Hex",
- DisplayFormat::Decimal => "Decimal",
- DisplayFormat::SignedDecimal => "SignedDecimal",
- DisplayFormat::Binary => "Binary",
- })
- }
-}
-
-impl Signal {
- pub fn new(name: String, options: Vec<DisplayOption>) -> Self {
- Self {
- name,
- options
- }
- }
-
- pub fn name(&self) -> &str {
- &self.name
- }
-
- pub fn options(&self) -> Iter<'_, DisplayOption> {
- self.options.iter()
- }
-}
-
-impl Entity {
- pub fn new(name: String) -> Self {
- Self {
- name,
- architecture: None
- }
- }
-
- pub fn name(&self) -> &str {
- &self.name
- }
-
- pub fn add_architecture(&mut self, architecture: Architecture) {
- self.architecture = Some(architecture);
- }
-
- pub fn architecture(&self) -> Option<&Architecture> {
- self.architecture.as_ref()
- }
-}
-
-impl Architecture {
- pub fn new(name: String, entity_name: String, signals: Vec<Signal>) -> Self {
- Self {
- name,
- entity_name,
- signals,
- }
- }
-
- pub fn signals(&self) -> Iter<'_, Signal> {
- self.signals.iter()
- }
-
- pub fn name(&self) -> &str {
- &self.name
- }
-
- pub fn entity_name(&self) -> &str {
- &self.entity_name
+ write!(
+ f,
+ "{}",
+ match self {
+ DisplayFormat::Hex => "Hex",
+ DisplayFormat::Decimal => "Decimal",
+ DisplayFormat::SignedDecimal => "SignedDecimal",
+ DisplayFormat::Binary => "Binary",
+ }
+ )
}
}
M src/file_parser.rs => src/file_parser.rs +126 -158
@@ 1,131 1,128 @@
-use vhdl_lang::{Source, syntax::{tokens::{TokenStream, Tokenizer, Kind, Comment}, Symbols}, Diagnostic, data::{Contents, ContentReader}};
-
-use crate::display_elements::{DisplayColor, Entity, Architecture, Signal, DisplayOption, DisplayFormat};
-
-#[derive(PartialEq, Eq, Clone)]
-struct Context {
- color: Option<DisplayColor>,
- omit: bool
+use vhdl_lang::{
+ data::{ContentReader, Contents},
+ syntax::{
+ tokens::{Comment, Kind, TokenStream, Tokenizer},
+ Symbols,
+ },
+ Diagnostic, Source,
+};
+
+#[derive(Eq, PartialEq)]
+pub struct ParsedEntity {
+ name: String,
+ architecture: Option<ParsedArchitecture>,
}
-pub struct FileParser<'a> {
- diagnostics: Vec<Diagnostic>,
- stream: TokenStream<'a>,
+impl ParsedEntity {
+ pub fn name(&self) -> &str {
+ &self.name[..]
+ }
- entities: Vec<Entity>,
- current_entity: usize
+ pub fn architecture(&self) -> Option<&ParsedArchitecture> {
+ self.architecture.as_ref()
+ }
}
-#[derive(Debug)]
-pub enum ParseError {
- EntityNotPresent,
- ArchitectureNotFound,
- ParsingError(Diagnostic),
- EndOfFile,
+#[derive(Eq, PartialEq)]
+pub struct ParsedArchitecture {
+ name: String,
+ entity_name: String,
+ parts: Vec<ParsedArchitecturePart>,
}
-impl From<Diagnostic> for ParseError {
- fn from(value: Diagnostic) -> Self {
- Self::ParsingError(value)
+impl ParsedArchitecture {
+ pub fn name(&self) -> &str {
+ &self.name
}
-}
-impl From<&Context> for Vec<DisplayOption> {
- fn from(value: &Context) -> Self {
- let mut options = vec![];
-
- if value.omit {
- options.push(DisplayOption::Omit);
- }
-
- if let Some(color) = value.color {
- options.push(DisplayOption::Color(color));
- }
+ pub fn entity_name(&self) -> &str {
+ &self.entity_name
+ }
- options
+ pub fn parts(&self) -> &Vec<ParsedArchitecturePart> {
+ &self.parts
}
}
-impl<'a> FileParser<'a> {
- pub fn new(source: &'a Source, contents: &'a Contents, symbols: &'a Symbols) -> Self {
- let mut diagnostics = vec![];
- let tokenizer = Tokenizer::new(symbols, source, ContentReader::new(contents));
- let stream = TokenStream::new(tokenizer, &mut diagnostics);
+#[derive(PartialEq, Eq)]
+pub struct ParsedSignal {
+ name: String,
+ signal_type: String,
+ comment: Option<String>,
+}
- Self {
- diagnostics,
- stream,
- entities: vec![],
- current_entity: 0,
- }
+impl ParsedSignal {
+ pub fn name(&self) -> &str {
+ &self.name
}
- pub fn find_next_entity(&mut self) -> Result<Entity, ParseError> {
- if self.current_entity < self.entities.len() {
- self.current_entity += 1;
- return Ok(self.entities[self.current_entity - 1].clone());
- }
-
- if self.stream.skip_until(|k| k == Kind::Entity || k == Kind::Architecture).is_err() {
- return Err(ParseError::EndOfFile);
- }
-
- if self.stream.peek_kind().unwrap() == Kind::Entity {
- let entity = Self::parse_entity(&mut self.stream)?;
- self.entities.push(entity.clone());
- self.current_entity += 1;
-
- Ok(entity)
- } else {
- let architecture = Self::parse_architecture(&mut self.stream)?;
-
- if let Some(entity) = self.entities.iter_mut().find(|e| e.name() == architecture.entity_name()) {
- entity.add_architecture(architecture);
- }
-
- self.find_next_entity()
- }
+ pub fn signal_type(&self) -> &str {
+ &self.signal_type
}
- pub fn parse_entity_architecture(&mut self, mut entity: Entity) -> Result<Entity, ParseError> {
- let Some(found_entity) = self.entities.iter_mut().find(|e| e.name() == entity.name()) else {
- return Err(ParseError::EntityNotPresent);
- };
+ pub fn comment(&self) -> Option<&str> {
+ self.comment.as_deref()
+ }
+}
- if entity.architecture().is_some() {
- return Ok(entity);
- }
+#[derive(PartialEq, Eq)]
+pub enum ParsedArchitecturePart {
+ Signal(ParsedSignal),
+ Comment(String),
+}
- if found_entity.architecture().is_some() {
- return Ok(found_entity.clone());
- }
+pub struct FileParser {}
- if self.stream.skip_until(|k| k == Kind::Entity || k == Kind::Architecture).is_err() {
- return Err(ParseError::EndOfFile);
- }
+#[derive(Debug)]
+pub enum ParseError {
+ ArchitectureWithoutEntity,
+ ParsingError(Diagnostic),
+ EndOfFile,
+}
- if self.stream.peek_kind().unwrap() == Kind::Entity {
- let entity = Self::parse_entity(&mut self.stream)?;
- self.entities.push(entity.clone());
- return self.parse_entity_architecture(entity)
- }
+impl From<Diagnostic> for ParseError {
+ fn from(value: Diagnostic) -> Self {
+ Self::ParsingError(value)
+ }
+}
- let architecture = Self::parse_architecture(&mut self.stream)?;
- if architecture.entity_name() == entity.name() {
- entity.add_architecture(architecture.clone());
- found_entity.add_architecture(architecture);
+impl FileParser {
+ pub fn parse_file(
+ source: &Source,
+ contents: &Contents,
+ symbols: &Symbols,
+ ) -> Result<Vec<ParsedEntity>, ParseError> {
+ let mut entities = vec![];
+ let mut diagnostics = vec![];
+ let tokenizer = Tokenizer::new(symbols, source, ContentReader::new(contents));
+ let mut stream = TokenStream::new(tokenizer, &mut diagnostics);
- return Ok(entity);
- }
+ while stream
+ .skip_until(|k| k == Kind::Entity || k == Kind::Architecture)
+ .is_ok()
+ {
+ let kind = stream.peek_kind().unwrap();
- if let Some(matched_entity) = self.entities.iter_mut().find(|e| e.name() == architecture.entity_name()) {
- matched_entity.add_architecture(architecture);
+ match kind {
+ Kind::Entity => {
+ entities.push(Self::parse_entity(&mut stream)?);
+ }
+ Kind::Architecture => {
+ let architecture = Self::parse_architecture(&mut stream)?;
+ let entity = entities
+ .iter_mut()
+ .find(|e| e.name == architecture.entity_name)
+ .ok_or(ParseError::ArchitectureWithoutEntity)?;
+ entity.architecture = Some(architecture);
+ }
+ _ => panic!("Wrong kind. Skip until bugged."),
+ }
}
- self.parse_entity_architecture(entity)
+ Ok(entities)
}
- fn parse_architecture(stream: &mut TokenStream) -> Result<Architecture, ParseError> {
+ fn parse_architecture(stream: &mut TokenStream) -> Result<ParsedArchitecture, ParseError> {
stream.expect_kind(Kind::Architecture)?;
let architecture_name = Self::parse_identifier(stream)?;
@@ 136,31 133,38 @@ impl<'a> FileParser<'a> {
stream.expect_kind(Kind::Is)?;
- let mut context = Context { color: None, omit: false };
- let mut signals = vec![];
+ let mut parts: Vec<ParsedArchitecturePart> = vec![];
- while !stream.next_kind_is(Kind::Begin) {
+ loop {
let token = stream.peek().ok_or(ParseError::EndOfFile)?;
if let Some(comments) = &token.comments {
for comment in &comments.leading {
- Self::update_context(&mut context, comment);
+ parts.push(ParsedArchitecturePart::Comment(comment.value.clone()));
}
}
match token.kind {
- Kind::Signal => signals.append(Self::parse_signals(stream, &context)?.as_mut()),
+ Kind::Signal => parts.extend(
+ Self::parse_signals(stream)?
+ .into_iter()
+ .map(|s| ParsedArchitecturePart::Signal(s)),
+ ),
Kind::Begin => break,
_ => stream.skip(),
}
}
- let architecture = Architecture::new(architecture_name, entity_name, signals);
+ let architecture = ParsedArchitecture {
+ name: architecture_name,
+ entity_name,
+ parts,
+ };
Ok(architecture)
}
- fn parse_signals(stream: &mut TokenStream, context: &Context) -> Result<Vec<Signal>, ParseError> {
+ fn parse_signals(stream: &mut TokenStream) -> Result<Vec<ParsedSignal>, ParseError> {
stream.expect_kind(Kind::Signal)?;
let mut signal_names = vec![];
@@ 178,36 182,33 @@ impl<'a> FileParser<'a> {
stream.skip_until(|k| k == Kind::SemiColon)?;
let semicolon_token = stream.peek().ok_or(ParseError::EndOfFile)?;
- let options: Vec<DisplayOption> = if let Some(comments) = &semicolon_token.comments {
- if let Some(trailing) = &comments.trailing {
- let mut context = context.clone();
- Self::update_context(&mut context, trailing);
- (&context).into()
- } else {
- context.into()
- }
- } else {
- context.into()
- };
+ let comment = semicolon_token.comments.as_ref().and_then(|comments| {
+ comments
+ .trailing
+ .as_ref()
+ .map(|trailing| trailing.value.clone())
+ });
let mut signals = vec![];
for signal_name in signal_names {
- let mut options = options.clone();
- if signal_type.starts_with("std_logic_vector") {
- options.push(DisplayOption::Format(DisplayFormat::Binary));
- }
-
- signals.push(Signal::new(signal_name, options));
+ signals.push(ParsedSignal {
+ name: signal_name,
+ signal_type,
+ comment,
+ });
}
Ok(signals)
}
- fn parse_entity(stream: &mut TokenStream) -> Result<Entity, ParseError> {
+ fn parse_entity(stream: &mut TokenStream) -> Result<ParsedEntity, ParseError> {
stream.expect_kind(Kind::Entity)?;
let name = Self::parse_identifier(stream)?;
- Ok(Entity::new(name))
+ Ok(ParsedEntity {
+ name,
+ architecture: None,
+ })
}
fn parse_identifier(stream: &mut TokenStream) -> Result<String, ParseError> {
@@ 218,37 219,4 @@ impl<'a> FileParser<'a> {
Ok(identifier.item.name_utf8())
}
-
- fn update_context(context: &mut Context, comment: &Comment) {
- let commands = comment.value.split(['\n', ','].as_ref());
-
- for command in commands {
- match command.trim() {
- "omit" => context.omit = true,
- "reset" => {
- context.color = None;
- context.omit = false;
- },
- _ if command.trim().starts_with("color ") => {
- let color = command["color ".len()..].trim();
-
- let color = match color {
- "normal" => DisplayColor::Normal,
- "red" => DisplayColor::Red,
- "orange" => DisplayColor::Orange,
- "yellow" => DisplayColor::Yellow,
- "green" => DisplayColor::Green,
- "blue" => DisplayColor::Blue,
- "Indigo" => DisplayColor::Indigo,
- "Violet" => DisplayColor::Violet,
- "Cycle" => DisplayColor::Cycle,
- _ => DisplayColor::Normal,
- };
-
- context.color = Some(color);
- },
- _ => ()
- }
- }
- }
}
M src/tcl_generator.rs => src/tcl_generator.rs +4 -30
@@ 1,11 1,9 @@
use string_builder::Builder;
-use crate::display_elements::{DisplayColor, DisplayFormat, Signal, DisplayOption};
-
+use crate::display_elements::{DisplayColor, DisplayFormat, DisplayOption};
pub struct TclGenerator {
signals: Vec<(String, Option<DisplayColor>, Option<DisplayFormat>)>,
- zoom_out: bool,
signal_prefix: String,
}
@@ 13,28 11,12 @@ impl TclGenerator {
pub fn new(signal_prefix: String) -> Self {
Self {
signals: vec![],
- zoom_out: false,
signal_prefix,
}
}
- pub fn add_signal(&mut self, signal: &Signal) -> &mut Self {
- let mut color = None;
- let mut format = None;
-
- for option in signal.options() {
- match option {
- DisplayOption::Omit => return self,
- DisplayOption::Color(c) => {
- color = Some(c.clone());
- },
- DisplayOption::Format(f) => {
- format = Some(f.clone());
- }
- }
- }
-
- self.signals.push((signal.name().to_owned(), color, format));
+ pub fn add_signal(&mut self, signal: String, color: Option<DisplayColor>, format: Option<DisplayFormat>) -> &mut Self {
+ self.signals.push((signal, color, format));
self
}
@@ 43,11 25,6 @@ impl TclGenerator {
self
}
- pub fn zoom_out(&mut self) -> &mut Self {
- self.zoom_out = true;
- self
- }
-
pub fn generate(self) -> String {
let mut builder = Builder::new(300);
@@ 56,7 33,6 @@ impl TclGenerator {
builder.append("gtkwave::/View/Show_Filled_High_Values 1\n");
builder.append("gtkwave::/View/Show_Wave_Highlight 1\n");
builder.append("gtkwave::/View/Show_Mouseover 1\n");
- builder.append("gtkwave::/View/Left_Justified_Signals 1\n");
for signal in self.signals {
if signal.0 == "" {
@@ 84,9 60,7 @@ impl TclGenerator {
}
}
- if self.zoom_out {
- builder.append("gtkwave::/Time/Zoom/Zoom_Best_Fit\n");
- }
+ builder.append("gtkwave::/Time/Zoom/Zoom_Best_Fit\n");
builder.string().unwrap()
}