From 289b72b1266bb59daa683f7a2b122b170bc74dee Mon Sep 17 00:00:00 2001 From: Lukas Scheller Date: Sat, 7 Oct 2023 20:23:07 +0200 Subject: [PATCH 01/13] Implement initial completion for instantiation declarations --- vhdl_lang/src/analysis/completion.rs | 140 +- vhdl_lang/src/analysis/concurrent.rs | 23 +- vhdl_lang/src/analysis/design_unit.rs | 6 +- vhdl_lang/src/analysis/lock.rs | 4 + vhdl_lang/src/analysis/package_instance.rs | 2 +- vhdl_lang/src/analysis/root.rs | 57 +- vhdl_lang/src/ast.rs | 40 +- vhdl_lang/src/ast/display.rs | 4 +- vhdl_lang/src/ast/search.rs | 10 +- vhdl_lang/src/ast/visitor.rs | 2428 +++++++++++++++++ vhdl_lang/src/syntax/concurrent_statement.rs | 65 +- vhdl_lang/src/syntax/context.rs | 10 +- vhdl_lang/src/syntax/declarative_part.rs | 15 +- vhdl_lang/src/syntax/interface_declaration.rs | 5 +- vhdl_lang/src/syntax/names.rs | 21 +- vhdl_lang/src/syntax/separated_list.rs | 8 +- 16 files changed, 2714 insertions(+), 124 deletions(-) create mode 100644 vhdl_lang/src/ast/visitor.rs diff --git a/vhdl_lang/src/analysis/completion.rs b/vhdl_lang/src/analysis/completion.rs index d2440739..25eea940 100644 --- a/vhdl_lang/src/analysis/completion.rs +++ b/vhdl_lang/src/analysis/completion.rs @@ -1,11 +1,13 @@ -use crate::analysis::DesignRoot; -use crate::ast::{AnyDesignUnit, AnyPrimaryUnit, Declaration, UnitKey}; +use crate::analysis::{DesignRoot, HasEntityId}; +use crate::ast::{AnyDesignUnit, AnyPrimaryUnit, Declaration, InstantiatedUnit, InstantiationStatement, InterfaceDeclaration, MapAspect, Name, SelectedName, SubprogramDeclaration, UnitKey}; use crate::data::{ContentReader, Symbol}; use crate::syntax::Kind::*; -use crate::syntax::{Symbols, Token, Tokenizer, Value}; -use crate::{Position, Source}; +use crate::syntax::{Symbols, Token, TokenAccess, Tokenizer, Value}; +use crate::{EntityId, Position, Source}; use itertools::Itertools; use std::default::Default; +use crate::ast::search::{FoundDeclaration, Searcher, SearchResult, SearchState}; +use crate::ast::visitor::{Visitor, VisitorResult}; macro_rules! kind { ($kind: pat) => { @@ -23,6 +25,125 @@ macro_rules! ident { }; } +#[derive(Eq, PartialEq, Debug)] +enum MapAspectKind { + Port, + Generic +} + +struct EntityPortAndGenericsExtractor<'a> { + id: EntityId, + items: &'a mut Vec, + kind: MapAspectKind +} + +impl <'a> Searcher for EntityPortAndGenericsExtractor<'a> { + fn search_decl(&mut self, _ctx: &dyn TokenAccess, decl: FoundDeclaration) -> SearchState { + if decl.ent_id() == Some(self.id) { + match decl { + FoundDeclaration::Entity(ent) => { + if ent.ident.decl != Some(self.id) { + return SearchState::NotFinished; + } + if self.kind == MapAspectKind::Port { + if let Some(ports) = &ent.port_clause { + for port in ports { + self.items.push(port.completable_name()) + } + } + } + if self.kind == MapAspectKind::Generic { + if let Some(generics) = &ent.generic_clause { + for generic in generics { + self.items.push(generic.completable_name()) + } + } + } + SearchState::Finished(SearchResult::Found) + }, + _ => SearchState::NotFinished + } + } else { + SearchState::NotFinished + } + } +} + +impl InterfaceDeclaration { + fn completable_name(&self) -> String { + match self { + InterfaceDeclaration::Object(obj) => obj.ident.tree.to_string(), + InterfaceDeclaration::File(file) => file.ident.to_string(), + InterfaceDeclaration::Type(typ) => typ.tree.item.name().to_string(), + InterfaceDeclaration::Subprogram(decl, _) => match decl { + SubprogramDeclaration::Procedure(proc) => proc.designator.to_string(), + SubprogramDeclaration::Function(func) => func.designator.to_string(), + } + InterfaceDeclaration::Package(package) => package.package_name.to_string(), + } + } +} + + +struct AutocompletionVisitor<'a> { + root: &'a DesignRoot, + cursor: Position, + completions: &'a mut Vec +} + +impl <'a> AutocompletionVisitor<'a> { + fn get_ent(&self, node: &InstantiationStatement) -> Option { + match &node.unit { + InstantiatedUnit::Entity(name, _) => { + let Some(ent_id) = (match &name.item { + SelectedName::Designator(desi) => {desi.reference} + SelectedName::Selected(_, desi) => {desi.item.reference} + }) else { + return None; + }; + Some(ent_id) + } + _ => None + } + } + + fn process_map_aspect(&mut self, node: &InstantiationStatement, map: &MapAspect, ctx: &dyn TokenAccess, kind: MapAspectKind) { + if ctx.get_span(map.start, map.closing_paren).range().contains(self.cursor) { + let items_in_node = map.list.items.iter().filter_map(|el| { + match &el.formal { + None => None, + Some(name) => match &name.item { + Name::Designator(desi) => Some(desi.item.to_string().to_lowercase()), + _ => None + } + } + }).collect_vec(); + if let Some(ent) = self.get_ent(node) { + let mut searcher = EntityPortAndGenericsExtractor { + id: ent, + items: &mut self.completions, + kind, + }; + let _ = self.root.search(&mut searcher); + self.completions.retain(|name| !items_in_node.contains(&name.to_lowercase())); + } + } + } +} + +impl <'a> Visitor for AutocompletionVisitor<'a> { + + fn visit_instantiation_statement(&mut self, node: &InstantiationStatement, ctx: &dyn TokenAccess) -> VisitorResult { + if let Some(map) = &node.generic_map { + self.process_map_aspect(node, map, ctx, MapAspectKind::Generic) + } + if let Some(map) = &node.port_map { + self.process_map_aspect(node, map, ctx, MapAspectKind::Port) + } + VisitorResult::Skip + } +} + /// Returns the completable string representation of a declaration /// for example: /// `let alias = parse_vhdl("alias my_alias is ...")` @@ -147,7 +268,16 @@ impl DesignRoot { | [.., kind!(Use), ident!(library), kind!(Dot), ident!(selected), kind!(Dot), kind!(StringLiteral | Identifier)] => { self.list_available_declarations(library, selected) } - _ => vec![], + _ => { + let mut completions = vec![]; + let mut visitor = AutocompletionVisitor { + completions: &mut completions, + root: self, + cursor + }; + self.walk(&mut visitor); + completions + }, } } } diff --git a/vhdl_lang/src/analysis/concurrent.rs b/vhdl_lang/src/analysis/concurrent.rs index e9de2ac1..bfdf72a2 100644 --- a/vhdl_lang/src/analysis/concurrent.rs +++ b/vhdl_lang/src/analysis/concurrent.rs @@ -86,13 +86,13 @@ impl<'a> AnalyzeContext<'a> { self.analyze_interface_list(&nested, parent, list, diagnostics)?; } if let Some(ref mut list) = block.header.generic_map { - self.analyze_assoc_elems(scope, list, diagnostics)?; + self.analyze_assoc_elems(scope, &mut list.list.items[..], diagnostics)?; } if let Some(ref mut list) = block.header.port_clause { self.analyze_interface_list(&nested, parent, list, diagnostics)?; } if let Some(ref mut list) = block.header.port_map { - self.analyze_assoc_elems(scope, list, diagnostics)?; + self.analyze_assoc_elems(scope, &mut list.list.items[..], diagnostics)?; } self.define_labels_for_concurrent_part( @@ -288,14 +288,14 @@ impl<'a> AnalyzeContext<'a> { &entity_name.pos, &generic_region, scope, - &mut instance.generic_map, + &mut instance.generic_map.as_mut().map(|it| it.list.items.as_mut_slice()).unwrap_or(&mut []), diagnostics, )?; self.analyze_assoc_elems_with_formal_region( &entity_name.pos, &port_region, scope, - &mut instance.port_map, + &mut instance.port_map.as_mut().map(|it| it.list.items.as_mut_slice()).unwrap_or(&mut []), diagnostics, )?; Ok(()) @@ -326,14 +326,14 @@ impl<'a> AnalyzeContext<'a> { &component_name.pos, &generic_region, scope, - &mut instance.generic_map, + &mut instance.generic_map.as_mut().map(|it| it.list.items.as_mut_slice()).unwrap_or(&mut []), diagnostics, )?; self.analyze_assoc_elems_with_formal_region( &component_name.pos, &port_region, scope, - &mut instance.port_map, + &mut instance.port_map.as_mut().map(|it| it.list.items.as_mut_slice()).unwrap_or(&mut []), diagnostics, )?; Ok(()) @@ -366,14 +366,21 @@ impl<'a> AnalyzeContext<'a> { err.add_to(diagnostics)?; } - self.analyze_assoc_elems(scope, &mut instance.generic_map, diagnostics)?; - self.analyze_assoc_elems(scope, &mut instance.port_map, diagnostics)?; + self.analyze_map_aspect(scope, &mut instance.generic_map, diagnostics)?; + self.analyze_map_aspect(scope, &mut instance.port_map, diagnostics)?; } }; Ok(()) } + pub fn analyze_map_aspect(&self, scope: & Scope<'a>, map: & mut Option, diagnostics: &mut dyn DiagnosticHandler) -> FatalResult { + let Some(aspect) = map else { + return Ok(()); + }; + self.analyze_assoc_elems(scope, aspect.list.items.as_mut_slice(), diagnostics) + } + pub fn sensitivity_list_check( &self, scope: &Scope<'a>, diff --git a/vhdl_lang/src/analysis/design_unit.rs b/vhdl_lang/src/analysis/design_unit.rs index 9e22d7af..8a0ee12a 100644 --- a/vhdl_lang/src/analysis/design_unit.rs +++ b/vhdl_lang/src/analysis/design_unit.rs @@ -479,7 +479,7 @@ impl<'a> AnalyzeContext<'a> { ContextItem::Library(LibraryClause { ref mut name_list, .. }) => { - for library_name in name_list.items_mut() { + for library_name in name_list.items.iter_mut() { if self.work_sym == library_name.item.item { library_name.set_unique_reference(self.work_library()); diagnostics.push(Diagnostic::hint( @@ -503,7 +503,7 @@ impl<'a> AnalyzeContext<'a> { ContextItem::Context(ContextReference { ref mut name_list, .. }) => { - for name in name_list.items_mut() { + for name in name_list.items.iter_mut() { match name.item { Name::Selected(..) => {} _ => { @@ -560,7 +560,7 @@ impl<'a> AnalyzeContext<'a> { use_clause: &mut UseClause, diagnostics: &mut dyn DiagnosticHandler, ) -> FatalResult { - for name in use_clause.name_list.items_mut() { + for name in use_clause.name_list.items.iter_mut() { match name.item { Name::Selected(..) => {} Name::SelectedAll(..) => {} diff --git a/vhdl_lang/src/analysis/lock.rs b/vhdl_lang/src/analysis/lock.rs index c54afacb..3c470086 100644 --- a/vhdl_lang/src/analysis/lock.rs +++ b/vhdl_lang/src/analysis/lock.rs @@ -111,6 +111,10 @@ impl<'a, T, R> ReadGuard<'a, T, R> { pub fn result(&self) -> &R { self.guard.result.as_ref().unwrap() } + + pub fn data(&self) -> &T { + &self.guard.data + } } impl<'a, T, R> std::ops::Deref for ReadGuard<'a, T, R> { diff --git a/vhdl_lang/src/analysis/package_instance.rs b/vhdl_lang/src/analysis/package_instance.rs index 6765fbdf..a5071337 100644 --- a/vhdl_lang/src/analysis/package_instance.rs +++ b/vhdl_lang/src/analysis/package_instance.rs @@ -225,7 +225,7 @@ impl<'a> AnalyzeContext<'a> { let (generics, other) = package_region.to_package_generic(); let mapping = if let Some(generic_map) = generic_map { - self.package_generic_map(&nested, generics, generic_map, diagnostics)? + self.package_generic_map(&nested, generics, generic_map.list.items.as_mut_slice(), diagnostics)? } else { FnvHashMap::default() }; diff --git a/vhdl_lang/src/analysis/root.rs b/vhdl_lang/src/analysis/root.rs index 7bfca3a7..ada042fe 100644 --- a/vhdl_lang/src/analysis/root.rs +++ b/vhdl_lang/src/analysis/root.rs @@ -23,6 +23,7 @@ use parking_lot::RwLock; use std::collections::hash_map::Entry; use std::ops::Deref; use std::sync::Arc; +use crate::ast::visitor::{Visitor, walk}; /// A design unit with design unit data pub(super) struct AnalysisData { @@ -180,7 +181,7 @@ impl Library { UnitKey::Secondary(ref primary_name, ref name) => match unit.kind() { AnyKind::Secondary(SecondaryKind::Architecture) => Diagnostic::error( unit.ident(), - format!("Duplicate architecture '{name}' of entity '{primary_name}'",), + format!("Duplicate architecture '{name}' of entity '{primary_name}'", ), ), AnyKind::Secondary(SecondaryKind::PackageBody) => Diagnostic::error( unit.pos(), @@ -325,7 +326,7 @@ impl DesignRoot { } /// Iterates over all available library symbols. - pub fn available_libraries(&self) -> impl Iterator { + pub fn available_libraries(&self) -> impl Iterator { self.libraries.keys() } @@ -467,10 +468,10 @@ impl DesignRoot { searcher.references } - pub fn public_symbols<'a>(&'a self) -> Box> + 'a> { + pub fn public_symbols<'a>(&'a self) -> Box> + 'a> { Box::new(self.libraries.values().flat_map(|library| { std::iter::once(self.arenas.get(library.id)).chain(library.units.values().flat_map( - |unit| -> Box>> { + |unit| -> Box>> { if matches!(unit.kind(), AnyKind::Primary(_)) { let data = self.get_analysis(unit); if let AnyDesignUnit::Primary(primary) = data.deref() { @@ -580,6 +581,18 @@ impl DesignRoot { NotFound } + pub fn walk(&self, visitor: &mut impl Visitor) { + for library in self.libraries.values() { + for unit_id in library.sorted_unit_ids() { + let unit = library.units.get(unit_id.key()).unwrap(); + let tokens = &unit.tokens; + if let Some(unit) = unit.unit.get() { + walk(unit.data(), visitor, tokens); + } + } + } + } + pub fn search_library( &self, library_name: &Symbol, @@ -843,13 +856,13 @@ impl DesignRoot { .libraries .get(&std_lib_name) .map(|library| &library.units) - else { - return; - }; + else { + return; + }; let Some(locked_unit) = standard_units.get(&UnitKey::Primary(self.symbol_utf8("standard"))) - else { - return; - }; + else { + return; + }; let AnalysisEntry::Vacant(mut unit) = locked_unit.unit.entry() else { return; }; @@ -911,7 +924,7 @@ impl DesignRoot { } for ent in - context.universal_implicits(UniversalType::Real, context.universal_real().into()) + context.universal_implicits(UniversalType::Real, context.universal_real().into()) { unsafe { arena.add_implicit(universal.real, ent); @@ -975,9 +988,9 @@ impl DesignRoot { if let Some(ent) = primary.ent_id() { let AnyEntKind::Design(Design::Package(_, ref region)) = std_logic_arena.get(ent).kind() - else { - unreachable!() - }; + else { + unreachable!() + }; if let Some(NamedEntities::Single(ent)) = region.lookup_immediate( &Designator::Identifier(self.symbol_utf8("std_ulogic")), @@ -1200,21 +1213,21 @@ package pkg is new gpkg generic map (const => foo); vec![ Diagnostic::error( code.s("pkg", 2), - "A primary unit has already been declared with name 'pkg' in library 'libname'" + "A primary unit has already been declared with name 'pkg' in library 'libname'", ).related(code.s("pkg", 1), "Previously defined here"), Diagnostic::error( code.s("entname", 2), - "A primary unit has already been declared with name 'entname' in library 'libname'" + "A primary unit has already been declared with name 'entname' in library 'libname'", ).related(code.s("entname", 1), "Previously defined here"), Diagnostic::error( code.s("pkg", 3), - "A primary unit has already been declared with name 'pkg' in library 'libname'" + "A primary unit has already been declared with name 'pkg' in library 'libname'", ).related(code.s("pkg", 1), "Previously defined here"), Diagnostic::error( code.s("pkg", 4), - "A primary unit has already been declared with name 'pkg' in library 'libname'" + "A primary unit has already been declared with name 'pkg' in library 'libname'", ).related(code.s("pkg", 1), "Previously defined here"), - ] + ], ); } @@ -1244,7 +1257,7 @@ end architecture; code.s("rtl", 2), "Duplicate architecture 'rtl' of entity 'ent'", ) - .related(code.s("rtl", 1), "Previously defined here")], + .related(code.s("rtl", 1), "Previously defined here")], ); } @@ -1274,14 +1287,14 @@ end configuration; code.s("cfg", 2), "A primary unit has already been declared with name 'cfg' in library 'libname'", ) - .related(code.s1("cfg"), "Previously defined here")], + .related(code.s1("cfg"), "Previously defined here")], ); assert_eq!(library.units.len(), 2); assert_eq!(library.duplicates.len(), 1); } } -fn public_symbols<'a>(ent: EntRef<'a>) -> Box> + 'a> { +fn public_symbols<'a>(ent: EntRef<'a>) -> Box> + 'a> { match ent.kind() { AnyEntKind::Design(d) => match d { Design::Entity(_, region) diff --git a/vhdl_lang/src/ast.rs b/vhdl_lang/src/ast.rs index 307ade99..bf4d55d1 100644 --- a/vhdl_lang/src/ast.rs +++ b/vhdl_lang/src/ast.rs @@ -17,11 +17,11 @@ mod any_design_unit; #[macro_use] pub mod search; +pub mod visitor; pub use self::display::*; pub(crate) use self::util::*; pub(crate) use any_design_unit::*; -use std::iter; use crate::analysis::EntityId; use crate::data::*; @@ -697,7 +697,7 @@ pub enum SubprogramDefault { /// LRM 6.5.5 Interface package declaration #[derive(PartialEq, Debug, Clone)] pub enum InterfacePackageGenericMapAspect { - Map(Vec), + Map(SeparatedList), Box, Default, } @@ -969,9 +969,9 @@ pub struct BlockStatement { #[derive(PartialEq, Debug, Clone)] pub struct BlockHeader { pub generic_clause: Option>, - pub generic_map: Option>, + pub generic_map: Option, pub port_clause: Option>, - pub port_map: Option>, + pub port_map: Option, } #[derive(PartialEq, Debug, Clone)] @@ -1022,12 +1022,20 @@ pub enum InstantiatedUnit { Configuration(WithPos), } +#[derive(PartialEq, Debug, Clone)] +pub struct MapAspect { + pub start: TokenId, // `generic` or `map` + pub list: SeparatedList, + pub closing_paren: TokenId, +} + /// 11.7 Component instantiation statements #[derive(PartialEq, Debug, Clone)] pub struct InstantiationStatement { pub unit: InstantiatedUnit, - pub generic_map: Vec, - pub port_map: Vec, + pub generic_map: Option, + pub port_map: Option, + pub semicolon: TokenId, } /// 11.8 Generate statements @@ -1092,23 +1100,13 @@ pub struct LibraryClause { /// Represents a token-separated list of some generic type `T` #[derive(PartialEq, Debug, Clone)] pub struct SeparatedList { - pub first: T, - pub remainder: Vec<(TokenId, T)>, + pub items: Vec, + pub tokens: Vec, } pub type IdentList = SeparatedList>; pub type NameList = SeparatedList>; -impl SeparatedList { - pub fn items(&self) -> impl Iterator { - iter::once(&self.first).chain(self.remainder.iter().map(|it| &it.1)) - } - - pub fn items_mut(&mut self) -> impl Iterator { - iter::once(&mut self.first).chain(self.remainder.iter_mut().map(|it| &mut it.1)) - } -} - /// LRM 12.4. Use clauses #[derive(PartialEq, Debug, Clone)] pub struct UseClause { @@ -1147,7 +1145,7 @@ pub struct PackageInstantiation { pub context_clause: ContextClause, pub ident: WithDecl, pub package_name: WithPos, - pub generic_map: Option>, + pub generic_map: Option, } /// LRM 7.3 Configuration specification @@ -1170,8 +1168,8 @@ pub enum EntityAspect { #[derive(PartialEq, Debug, Clone)] pub struct BindingIndication { pub entity_aspect: Option, - pub generic_map: Option>, - pub port_map: Option>, + pub generic_map: Option, + pub port_map: Option, } /// LRM 7.3 Configuration specification diff --git a/vhdl_lang/src/ast/display.rs b/vhdl_lang/src/ast/display.rs index 65db0ba1..4a581300 100644 --- a/vhdl_lang/src/ast/display.rs +++ b/vhdl_lang/src/ast/display.rs @@ -916,7 +916,7 @@ impl Display for InterfacePackageDeclaration { match &self.generic_map { InterfacePackageGenericMapAspect::Map(assoc_list) => { let mut first = true; - for assoc in assoc_list { + for assoc in &assoc_list.items { if first { write!(f, "\n {assoc}")?; } else { @@ -1020,7 +1020,7 @@ impl Display for PackageInstantiation { write!(f, "package {} is new {}", self.ident, self.package_name)?; if let Some(assoc_list) = &self.generic_map { let mut first = true; - for assoc in assoc_list { + for assoc in &assoc_list.list.items { if first { write!(f, "\n generic map (\n {assoc}")?; } else { diff --git a/vhdl_lang/src/ast/search.rs b/vhdl_lang/src/ast/search.rs index a6926ce5..dcee5207 100644 --- a/vhdl_lang/src/ast/search.rs +++ b/vhdl_lang/src/ast/search.rs @@ -277,7 +277,7 @@ impl Search for WithPos { impl Search for SeparatedList { fn search(&mut self, ctx: &dyn TokenAccess, searcher: &mut impl Searcher) -> SearchResult { - for item in self.items_mut() { + for item in self.items.iter_mut() { return_if_found!(item.search(ctx, searcher)); } NotFound @@ -1199,7 +1199,7 @@ impl Search for FunctionSpecification { impl Search for LibraryClause { fn search(&mut self, ctx: &dyn TokenAccess, searcher: &mut impl Searcher) -> SearchResult { - for name in self.name_list.items_mut() { + for name in self.name_list.items.iter_mut() { return_if_found!(searcher .search_pos_with_ref(ctx, &name.item.pos, &mut name.reference) .or_not_found()); @@ -1343,6 +1343,12 @@ impl Search for CaseStatement { } } +impl Search for MapAspect { + fn search(&mut self, ctx: &dyn TokenAccess, searcher: &mut impl Searcher) -> SearchResult { + self.list.search(ctx, searcher) + } +} + // Search for reference to declaration/definition at cursor pub struct ItemAtCursor { source: Source, diff --git a/vhdl_lang/src/ast/visitor.rs b/vhdl_lang/src/ast/visitor.rs new file mode 100644 index 00000000..75a037c1 --- /dev/null +++ b/vhdl_lang/src/ast/visitor.rs @@ -0,0 +1,2428 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// Lic// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// This Source Code Form is subject to the terms of the Mozilla Public +// You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) 2023, Olof Kraigher olof.kraigher@gmail.com + +use crate::ast::visitor::VisitorResult::{Continue, Skip, Stop}; +use crate::ast::*; +use crate::syntax::TokenAccess; +use itertools::Itertools; +use std::ops::Deref; + +#[derive(PartialEq)] +pub enum VisitorResult { + Continue, + Stop, + Skip, +} + +pub trait Visitor { + fn visit_attribute_name( + &mut self, + _node: &AttributeName, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_attribute_designator( + &mut self, + _node: &AttributeDesignator, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_external_path( + &mut self, + _node: &ExternalPath, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_external_name( + &mut self, + _node: &ExternalName, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_name(&mut self, _node: &Name, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + fn visit_selected_name( + &mut self, + _node: &SelectedName, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_call_or_indexed( + &mut self, + _node: &CallOrIndexed, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_choice(&mut self, _node: &Choice, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + fn visit_element_association( + &mut self, + _node: &ElementAssociation, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_actual_part(&mut self, _node: &ActualPart, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + fn visit_association_element( + &mut self, + _node: &AssociationElement, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_abstract_literal( + &mut self, + _node: &AbstractLiteral, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_bit_string(&mut self, _node: &BitString, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + fn visit_physical_literal( + &mut self, + _node: &PhysicalLiteral, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_literal(&mut self, _node: &Literal, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + fn visit_allocator(&mut self, _node: &Allocator, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + fn visit_qualified_expression( + &mut self, + _node: &QualifiedExpression, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_expression(&mut self, _node: &Expression, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + fn visit_ident(&mut self, _node: &Ident, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + fn visit_discrete_range( + &mut self, + _node: &DiscreteRange, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_range_constraint( + &mut self, + _node: &RangeConstraint, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_range(&mut self, _node: &Range, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + fn visit_element_constraint( + &mut self, + _node: &ElementConstraint, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_subtype_constraint( + &mut self, + _node: &SubtypeConstraint, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_record_element_resolution( + &mut self, + _node: &RecordElementResolution, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_resolution_indication( + &mut self, + _node: &ResolutionIndication, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_type_mark(&mut self, _node: &TypeMark, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + fn visit_subtype_indication( + &mut self, + _node: &SubtypeIndication, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_array_index(&mut self, _node: &ArrayIndex, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + fn visit_element_declaration( + &mut self, + _node: &ElementDeclaration, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_protected_type_declarative_item( + &mut self, + _node: &ProtectedTypeDeclarativeItem, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_designator(&mut self, _node: &Designator, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + fn visit_alias_declaration( + &mut self, + _node: &AliasDeclaration, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_attribute_declaration( + &mut self, + _node: &AttributeDeclaration, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_entity_tag(&mut self, _node: &EntityTag, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + fn visit_entity_name(&mut self, _node: &EntityName, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + fn visit_attribute_specification( + &mut self, + _node: &AttributeSpecification, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_attribute(&mut self, _node: &Attribute, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + fn visit_protected_type_declaration( + &mut self, + _node: &ProtectedTypeDeclaration, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_protected_type_body( + &mut self, + _node: &ProtectedTypeBody, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_physical_type_declaration( + &mut self, + _node: &PhysicalTypeDeclaration, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_enumeration_literal( + &mut self, + _node: &EnumerationLiteral, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_type_definition( + &mut self, + _node: &TypeDefinition, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_type_declaration( + &mut self, + _node: &TypeDeclaration, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_object_declaration( + &mut self, + _node: &ObjectDeclaration, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_file_declaration( + &mut self, + _node: &FileDeclaration, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_subprogram_designator( + &mut self, + _node: &SubprogramDesignator, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_procedure_specification( + &mut self, + _node: &ProcedureSpecification, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_function_specification( + &mut self, + _node: &FunctionSpecification, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_subprogram_body( + &mut self, + _node: &SubprogramBody, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_signature(&mut self, _node: &Signature, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + fn visit_subprogram_declaration( + &mut self, + _node: &SubprogramDeclaration, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_interface_file_declaration( + &mut self, + _node: &InterfaceFileDeclaration, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_interface_object_declaration( + &mut self, + _node: &InterfaceObjectDeclaration, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_subprogram_default( + &mut self, + _node: &SubprogramDefault, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_interface_package_generic_map_aspect( + &mut self, + _node: &InterfacePackageGenericMapAspect, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_interface_package_declaration( + &mut self, + _node: &InterfacePackageDeclaration, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_interface_declaration( + &mut self, + _node: &InterfaceDeclaration, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_port_clause(&mut self, _node: &PortClause, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + fn visit_component_declaration( + &mut self, + _node: &ComponentDeclaration, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_declaration(&mut self, _node: &Declaration, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + fn visit_wait_statement( + &mut self, + _node: &WaitStatement, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_assert_statement( + &mut self, + _node: &AssertStatement, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_report_statement( + &mut self, + _node: &ReportStatement, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_target(&mut self, _node: &Target, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + fn visit_waveform_element( + &mut self, + _node: &WaveformElement, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_waveform(&mut self, _node: &Waveform, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + fn visit_delay_mechanism( + &mut self, + _node: &DelayMechanism, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_signal_assignment( + &mut self, + _node: &SignalAssignment, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_signal_force_assignment( + &mut self, + _node: &SignalForceAssignment, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_signal_release_assignment( + &mut self, + _node: &SignalReleaseAssignment, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_variable_assignment( + &mut self, + _node: &VariableAssignment, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_if_statement(&mut self, _node: &IfStatement, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + fn visit_case_statement( + &mut self, + _node: &CaseStatement, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_iteration_scheme( + &mut self, + _node: &IterationScheme, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_loop_statement( + &mut self, + _node: &LoopStatement, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_next_statement( + &mut self, + _node: &NextStatement, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_exit_statement( + &mut self, + _node: &ExitStatement, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_return_statement( + &mut self, + _node: &ReturnStatement, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_sequential_statement( + &mut self, + _node: &SequentialStatement, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_labeled_sequential_statement( + &mut self, + _node: &LabeledSequentialStatement, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_block_statement( + &mut self, + _node: &BlockStatement, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_block_header(&mut self, _node: &BlockHeader, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + fn visit_sensitivity_list( + &mut self, + _node: &SensitivityList, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_process_statement( + &mut self, + _node: &ProcessStatement, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_concurrent_procedure_call( + &mut self, + _node: &ConcurrentProcedureCall, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_concurrent_assert_statement( + &mut self, + _node: &ConcurrentAssertStatement, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_concurrent_signal_assignment( + &mut self, + _node: &ConcurrentSignalAssignment, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_instantiated_unit( + &mut self, + _node: &InstantiatedUnit, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_instantiation_statement( + &mut self, + _node: &InstantiationStatement, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_generate_body( + &mut self, + _node: &GenerateBody, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_for_generate_statement( + &mut self, + _node: &ForGenerateStatement, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_if_generate_statement( + &mut self, + _node: &IfGenerateStatement, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_case_generate_statement( + &mut self, + _node: &CaseGenerateStatement, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_concurrent_statement( + &mut self, + _node: &ConcurrentStatement, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_labeled_concurrent_statement( + &mut self, + _node: &LabeledConcurrentStatement, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_library_clause( + &mut self, + _node: &LibraryClause, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_use_clause(&mut self, _node: &UseClause, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + fn visit_context_reference( + &mut self, + _node: &ContextReference, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_context_item(&mut self, _node: &ContextItem, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + fn visit_context_declaration( + &mut self, + _node: &ContextDeclaration, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_package_instantiation( + &mut self, + _node: &PackageInstantiation, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_instantiation_list( + &mut self, + _node: &InstantiationList, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_entity_aspect( + &mut self, + _node: &EntityAspect, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_binding_indication( + &mut self, + _node: &BindingIndication, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_component_specification( + &mut self, + _node: &ComponentSpecification, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_v_unit_binding_indication( + &mut self, + _node: &VUnitBindingIndication, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_configuration_specification( + &mut self, + _node: &ConfigurationSpecification, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_configuration_declarative_item( + &mut self, + _node: &ConfigurationDeclarativeItem, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_component_configuration( + &mut self, + _node: &ComponentConfiguration, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_configuration_item( + &mut self, + _node: &ConfigurationItem, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_block_configuration( + &mut self, + _node: &BlockConfiguration, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_configuration_declaration( + &mut self, + _node: &ConfigurationDeclaration, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_entity_declaration( + &mut self, + _node: &EntityDeclaration, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_architecture_body( + &mut self, + _node: &ArchitectureBody, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_package_declaration( + &mut self, + _node: &PackageDeclaration, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_package_body(&mut self, _node: &PackageBody, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + fn visit_any_primary_unit( + &mut self, + _node: &AnyPrimaryUnit, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_any_secondary_unit( + &mut self, + _node: &AnySecondaryUnit, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_any_design_unit( + &mut self, + _node: &AnyDesignUnit, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_design_file(&mut self, _node: &DesignFile) -> VisitorResult { + Continue + } + fn visit_reference(&mut self, _node: &Reference, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + fn visit_item_with_pos( + &mut self, + _pos: &SrcPos, + _node: &dyn ASTNode, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_item_with_decl( + &mut self, + _decl: &Option, + _node: &dyn ASTNode, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_item_with_reference( + &mut self, + _ref: &Reference, + _node: &dyn ASTNode, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + Continue + } + fn visit_name_list(&mut self, _node: &NameList, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + + fn visit_map_aspect(&mut self, _node: &MapAspect, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } +} + +/// An AST Node has two methods it needs to declare: +/// - A `visit(Visitor, Context)` method. +/// - A `children()` method. +/// +/// The `visit` method +pub trait ASTNode { + fn visit(&self, visitor: &mut dyn Visitor, _ctx: &dyn TokenAccess) -> VisitorResult; + + fn children(&self) -> Vec<&dyn ASTNode>; +} + +pub fn walk(node: &dyn ASTNode, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) { + let mut stack: Vec<&dyn ASTNode> = vec![node]; + while let Some(node) = stack.pop() { + match node.visit(visitor, ctx) { + Stop => return, + Skip => continue, + _ => {} + } + for child in node.children().into_iter().rev() { + stack.push(child); + } + } +} + +pub fn walk_design_file(node: &DesignFile, visitor: &mut dyn Visitor) { + visitor.visit_design_file(node); + for (tokens, unit) in &node.design_units { + walk(unit, visitor, tokens); + } +} + +impl ASTNode for Box { + fn visit(&self, _visitor: &mut dyn Visitor, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![self.deref()] + } +} + +impl ASTNode for Option { + fn visit(&self, _visitor: &mut dyn Visitor, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match &self { + None => vec![], + Some(el) => vec![el], + } + } +} + +impl ASTNode for (T, U) { + fn visit(&self, _visitor: &mut dyn Visitor, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.0, &self.1] + } +} + +impl ASTNode for Vec { + fn visit(&self, _visitor: &mut dyn Visitor, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + + fn children(&self) -> Vec<&dyn ASTNode> { + self.iter().map(|f| f as &dyn ASTNode).collect() + } +} + +impl ASTNode for WithPos { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_item_with_pos(&self.pos, &self.item, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.item] + } +} + +impl ASTNode for WithDecl { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_item_with_decl(&self.decl, &self.tree, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.tree] + } +} + +impl ASTNode for WithRef { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_item_with_reference(&self.reference, &self.item, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.reference, &self.item] + } +} + +impl ASTNode for Conditional { + fn visit(&self, _visitor: &mut dyn Visitor, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.condition, &self.item] + } +} + +impl ASTNode for Conditionals { + fn visit(&self, _visitor: &mut dyn Visitor, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.conditionals, &self.else_item] + } +} + +impl ASTNode for Selection { + fn visit(&self, _visitor: &mut dyn Visitor, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.alternatives, &self.expression] + } +} + +impl ASTNode for AssignmentRightHand { + fn visit(&self, _visitor: &mut dyn Visitor, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match &self { + AssignmentRightHand::Simple(expr) => vec![expr], + AssignmentRightHand::Conditional(conds) => vec![conds], + AssignmentRightHand::Selected(sel) => vec![sel], + } + } +} + +impl ASTNode for Alternative { + fn visit(&self, _visitor: &mut dyn Visitor, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.choices, &self.item] + } +} + +impl ASTNode for DesignFile { + fn visit(&self, visitor: &mut dyn Visitor, _ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_design_file(self) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + self.design_units + .iter() + .map(|it| &it.1 as &dyn ASTNode) + .collect_vec() + } +} + +impl ASTNode for AnyDesignUnit { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_any_design_unit(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + AnyDesignUnit::Primary(unit) => vec![unit], + AnyDesignUnit::Secondary(unit) => vec![unit], + } + } +} + +impl ASTNode for AnyPrimaryUnit { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_any_primary_unit(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + AnyPrimaryUnit::Entity(decl) => vec![decl], + AnyPrimaryUnit::Configuration(decl) => vec![decl], + AnyPrimaryUnit::Package(decl) => vec![decl], + AnyPrimaryUnit::PackageInstance(decl) => vec![decl], + AnyPrimaryUnit::Context(decl) => vec![decl], + } + } +} + +impl ASTNode for ContextDeclaration { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_context_declaration(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.ident, &self.items] + } +} + +impl ASTNode for ContextItem { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_context_item(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + ContextItem::Use(clause) => vec![clause], + ContextItem::Library(clause) => vec![clause], + ContextItem::Context(clause) => vec![clause], + } + } +} + +impl ASTNode for ContextReference { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_context_reference(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.name_list] + } +} + +impl ASTNode for SeparatedList { + fn visit(&self, _visitor: &mut dyn Visitor, _ctx: &dyn TokenAccess) -> VisitorResult { + Continue + } + + fn children(&self) -> Vec<&dyn ASTNode> { + self.items.iter().map(|it| it as &dyn ASTNode).collect_vec() + } +} + +impl ASTNode for LibraryClause { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_library_clause(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.name_list] + } +} + +impl ASTNode for UseClause { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_use_clause(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.name_list] + } +} + +impl ASTNode for Ident { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_ident(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![] + } +} + +impl ASTNode for PackageInstantiation { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_package_instantiation(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![ + &self.context_clause, + &self.ident, + &self.package_name, + &self.generic_map, + ] + } +} + +impl ASTNode for AssociationElement { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_association_element(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.formal, &self.actual] + } +} + +impl ASTNode for ActualPart { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_actual_part(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + ActualPart::Expression(expr) => vec![expr], + ActualPart::Open => vec![], + } + } +} + +impl ASTNode for SelectedName { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_selected_name(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + SelectedName::Designator(desi) => vec![desi], + SelectedName::Selected(name, desi) => vec![name, desi], + } + } +} + +impl ASTNode for Designator { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_designator(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![] + } +} + +impl ASTNode for PackageDeclaration { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_package_declaration(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![ + &self.context_clause, + &self.ident, + &self.generic_clause, + &self.decl, + ] + } +} + +impl ASTNode for Declaration { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_declaration(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + Declaration::Object(decl) => vec![decl], + Declaration::File(decl) => vec![decl], + Declaration::Type(decl) => vec![decl], + Declaration::Component(decl) => vec![decl], + Declaration::Attribute(decl) => vec![decl], + Declaration::Alias(decl) => vec![decl], + Declaration::SubprogramDeclaration(decl) => vec![decl], + Declaration::SubprogramBody(decl) => vec![decl], + Declaration::Use(decl) => vec![decl], + Declaration::Package(decl) => vec![decl], + Declaration::Configuration(decl) => vec![decl], + } + } +} + +impl ASTNode for ConfigurationSpecification { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_configuration_specification(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.spec, &self.bind_ind, &self.vunit_bind_inds] + } +} + +impl ASTNode for VUnitBindingIndication { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_v_unit_binding_indication(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.vunit_list] + } +} + +impl ASTNode for BindingIndication { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_binding_indication(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.entity_aspect, &self.generic_map, &self.port_map] + } +} + +impl ASTNode for EntityAspect { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_entity_aspect(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + EntityAspect::Entity(name, id) => vec![name, id], + EntityAspect::Configuration(config) => vec![config], + EntityAspect::Open => vec![], + } + } +} + +impl ASTNode for ComponentSpecification { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_component_specification(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.instantiation_list, &self.component_name] + } +} + +impl ASTNode for InstantiationList { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_instantiation_list(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + InstantiationList::Labels(idents) => vec![idents], + InstantiationList::Others => vec![], + InstantiationList::All => vec![], + } + } +} + +impl ASTNode for SubprogramBody { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_subprogram_body(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.specification, &self.declarations, &self.statements] + } +} + +impl ASTNode for LabeledSequentialStatement { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_labeled_sequential_statement(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.label, &self.statement] + } +} + +impl ASTNode for SubprogramDeclaration { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_subprogram_declaration(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + SubprogramDeclaration::Procedure(proc) => vec![proc], + SubprogramDeclaration::Function(func) => vec![func], + } + } +} + +impl ASTNode for SequentialStatement { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_sequential_statement(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + SequentialStatement::Wait(stmt) => vec![stmt], + SequentialStatement::Assert(stmt) => vec![stmt], + SequentialStatement::Report(stmt) => vec![stmt], + SequentialStatement::VariableAssignment(stmt) => vec![stmt], + SequentialStatement::SignalAssignment(stmt) => vec![stmt], + SequentialStatement::SignalForceAssignment(stmt) => vec![stmt], + SequentialStatement::SignalReleaseAssignment(stmt) => vec![stmt], + SequentialStatement::ProcedureCall(stmt) => vec![stmt], + SequentialStatement::If(stmt) => vec![stmt], + SequentialStatement::Case(stmt) => vec![stmt], + SequentialStatement::Loop(stmt) => vec![stmt], + SequentialStatement::Next(stmt) => vec![stmt], + SequentialStatement::Exit(stmt) => vec![stmt], + SequentialStatement::Return(stmt) => vec![stmt], + SequentialStatement::Null => vec![], + } + } +} + +impl ASTNode for CaseStatement { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_case_statement(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.expression, &self.alternatives] + } +} + +impl ASTNode for ReturnStatement { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_return_statement(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match &self.expression { + Some(expr) => vec![expr], + None => vec![], + } + } +} + +impl ASTNode for ExitStatement { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_exit_statement(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.loop_label, &self.condition] + } +} + +impl ASTNode for NextStatement { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_next_statement(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.loop_label, &self.condition] + } +} + +impl ASTNode for LoopStatement { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_loop_statement(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.iteration_scheme, &self.statements] + } +} + +impl ASTNode for IterationScheme { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_iteration_scheme(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + IterationScheme::While(scheme) => vec![scheme], + IterationScheme::For(ident, range) => vec![ident, range], + } + } +} + +impl ASTNode for DiscreteRange { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_discrete_range(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + DiscreteRange::Discrete(type_mark, range) => vec![type_mark, range], + DiscreteRange::Range(range) => vec![range], + } + } +} + +impl ASTNode for TypeMark { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_type_mark(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.name] + } +} + +impl ASTNode for Range { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_range(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + Range::Range(constraint) => vec![constraint], + Range::Attribute(attr) => vec![attr.deref()], + } + } +} + +impl ASTNode for RangeConstraint { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_range_constraint(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.left_expr, &self.right_expr] + } +} + +impl ASTNode for IfStatement { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_if_statement(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.conds] + } +} + +impl ASTNode for CallOrIndexed { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_call_or_indexed(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.name, &self.parameters] + } +} + +impl ASTNode for SignalReleaseAssignment { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_signal_release_assignment(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.target] + } +} + +impl ASTNode for Target { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_target(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + Target::Name(name) => vec![name], + Target::Aggregate(aggr) => vec![aggr], + } + } +} + +impl ASTNode for ElementAssociation { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_element_association(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + ElementAssociation::Positional(expr) => vec![expr], + ElementAssociation::Named(choices, expr) => vec![choices, expr], + } + } +} + +impl ASTNode for SignalForceAssignment { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_signal_force_assignment(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.rhs] + } +} + +impl ASTNode for SignalAssignment { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_signal_assignment(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.target, &self.delay_mechanism, &self.rhs] + } +} + +impl ASTNode for DelayMechanism { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_delay_mechanism(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + DelayMechanism::Transport => vec![], + DelayMechanism::Inertial { reject } => vec![reject], + } + } +} + +impl ASTNode for Waveform { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_waveform(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + Waveform::Elements(elements) => vec![elements], + Waveform::Unaffected => vec![], + } + } +} + +impl ASTNode for WaveformElement { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_waveform_element(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.value, &self.after] + } +} + +impl ASTNode for VariableAssignment { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_variable_assignment(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.target, &self.rhs] + } +} + +impl ASTNode for ReportStatement { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_report_statement(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.severity, &self.report] + } +} + +impl ASTNode for AssertStatement { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_assert_statement(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.condition, &self.report, &self.severity] + } +} + +impl ASTNode for Choice { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_choice(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + Choice::Expression(expr) => vec![expr], + Choice::DiscreteRange(range) => vec![range], + Choice::Others => vec![], + } + } +} + +impl ASTNode for WaitStatement { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_wait_statement(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![ + &self.sensitivity_clause, + &self.condition_clause, + &self.timeout_clause, + ] + } +} + +impl ASTNode for FunctionSpecification { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_function_specification(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.parameter_list, &self.return_type] + } +} + +impl ASTNode for ProcedureSpecification { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_procedure_specification(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.designator, &self.parameter_list] + } +} + +impl ASTNode for SubprogramDesignator { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_subprogram_designator(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![] + } +} + +impl ASTNode for AliasDeclaration { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_alias_declaration(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![ + &self.designator, + &self.subtype_indication, + &self.name, + &self.signature, + ] + } +} + +impl ASTNode for Attribute { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_attribute(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + Attribute::Specification(spec) => vec![spec], + Attribute::Declaration(decl) => vec![decl], + } + } +} + +impl ASTNode for SubtypeIndication { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_subtype_indication(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.resolution, &self.type_mark, &self.constraint] + } +} + +impl ASTNode for AttributeSpecification { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_attribute_specification(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.ident, &self.entity_name, &self.expr] + } +} + +impl ASTNode for EntityName { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_entity_name(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + EntityName::Name(name) => vec![name], + EntityName::All | EntityName::Others => vec![], + } + } +} + +impl ASTNode for ResolutionIndication { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_resolution_indication(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + ResolutionIndication::FunctionName(name) => vec![name], + ResolutionIndication::ArrayElement(name) => vec![name], + ResolutionIndication::Record(record) => vec![record], + ResolutionIndication::Unresolved => vec![], + } + } +} + +impl ASTNode for RecordElementResolution { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_record_element_resolution(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.ident, &self.resolution] + } +} + +impl ASTNode for SubtypeConstraint { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_subtype_constraint(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + SubtypeConstraint::Range(range) => vec![range], + SubtypeConstraint::Array(ranges, constraint) => vec![ranges, constraint], + SubtypeConstraint::Record(constraints) => vec![constraints], + } + } +} + +impl ASTNode for ElementConstraint { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_element_constraint(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.ident, &self.constraint] + } +} + +impl ASTNode for AttributeDeclaration { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_attribute_declaration(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.ident, &self.type_mark] + } +} + +impl ASTNode for ComponentDeclaration { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_component_declaration(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.ident, &self.generic_list, &self.port_list] + } +} + +impl ASTNode for TypeDeclaration { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_type_declaration(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.ident, &self.def] + } +} + +impl ASTNode for TypeDefinition { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_type_definition(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + TypeDefinition::Enumeration(literals) => vec![literals], + TypeDefinition::Numeric(range) => vec![range], + TypeDefinition::Physical(decl) => vec![decl], + TypeDefinition::Array(indices, indication) => vec![indices, indication], + TypeDefinition::Record(record) => vec![record], + TypeDefinition::Access(subtype) => vec![subtype], + TypeDefinition::Incomplete(reference) => vec![reference], + TypeDefinition::File(type_mark) => vec![type_mark], + TypeDefinition::Protected(decl) => vec![decl], + TypeDefinition::ProtectedBody(body) => vec![body], + TypeDefinition::Subtype(subtype) => vec![subtype], + } + } +} + +impl ASTNode for Reference { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_reference(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![] + } +} + +impl ASTNode for ProtectedTypeBody { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_protected_type_body(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.decl] + } +} + +impl ASTNode for ProtectedTypeDeclaration { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_protected_type_declaration(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.items] + } +} + +impl ASTNode for ProtectedTypeDeclarativeItem { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_protected_type_declarative_item(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + ProtectedTypeDeclarativeItem::Subprogram(decl) => vec![decl], + } + } +} + +impl ASTNode for ElementDeclaration { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_element_declaration(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.ident, &self.subtype] + } +} + +impl ASTNode for ArrayIndex { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_array_index(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + ArrayIndex::IndexSubtypeDefintion(type_mark) => vec![type_mark], + ArrayIndex::Discrete(range) => vec![range], + } + } +} + +impl ASTNode for PhysicalTypeDeclaration { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_physical_type_declaration(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.range, &self.primary_unit, &self.secondary_units] + } +} + +impl ASTNode for PhysicalLiteral { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_physical_literal(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.value, &self.unit] + } +} + +impl ASTNode for EnumerationLiteral { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_enumeration_literal(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![] + } +} + +impl ASTNode for FileDeclaration { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_file_declaration(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![ + &self.ident, + &self.subtype_indication, + &self.file_name, + &self.open_info, + ] + } +} + +impl ASTNode for ObjectDeclaration { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_object_declaration(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.ident, &self.subtype_indication, &self.expression] + } +} + +impl ASTNode for InterfaceDeclaration { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_interface_declaration(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + InterfaceDeclaration::Object(obj) => vec![obj], + InterfaceDeclaration::File(obj) => vec![obj], + InterfaceDeclaration::Type(obj) => vec![obj], + InterfaceDeclaration::Subprogram(decl, default) => vec![decl, default], + InterfaceDeclaration::Package(pkg) => vec![pkg], + } + } +} + +impl ASTNode for InterfaceObjectDeclaration { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_interface_object_declaration(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.ident, &self.subtype_indication, &self.expression] + } +} + +impl ASTNode for InterfaceFileDeclaration { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_interface_file_declaration(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.ident, &self.subtype_indication] + } +} + +impl ASTNode for SubprogramDefault { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_subprogram_default(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + SubprogramDefault::Name(name) => vec![name], + SubprogramDefault::Box => vec![], + } + } +} + +impl ASTNode for InterfacePackageDeclaration { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_interface_package_declaration(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.ident, &self.package_name, &self.generic_map] + } +} + +impl ASTNode for InterfacePackageGenericMapAspect { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_interface_package_generic_map_aspect(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + InterfacePackageGenericMapAspect::Map(map) => vec![map], + InterfacePackageGenericMapAspect::Box => vec![], + InterfacePackageGenericMapAspect::Default => vec![], + } + } +} + +impl ASTNode for ConfigurationDeclaration { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_configuration_declaration(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![ + &self.context_clause, + &self.ident, + &self.entity_name, + &self.decl, + &self.vunit_bind_inds, + &self.block_config, + ] + } +} + +impl ASTNode for ConfigurationDeclarativeItem { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_configuration_declarative_item(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + ConfigurationDeclarativeItem::Use(clause) => vec![clause], + } + } +} + +impl ASTNode for BlockConfiguration { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_block_configuration(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.block_spec, &self.use_clauses, &self.items] + } +} + +impl ASTNode for ConfigurationItem { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_configuration_item(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + ConfigurationItem::Block(block) => vec![block], + ConfigurationItem::Component(component) => vec![component], + } + } +} + +impl ASTNode for ComponentConfiguration { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_component_configuration(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![ + &self.spec, + &self.bind_ind, + &self.vunit_bind_inds, + &self.block_config, + ] + } +} + +impl ASTNode for EntityDeclaration { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_entity_declaration(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![ + &self.context_clause, + &self.ident, + &self.generic_clause, + &self.port_clause, + &self.decl, + &self.statements, + ] + } +} + +impl ASTNode for AnySecondaryUnit { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_any_secondary_unit(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + AnySecondaryUnit::Architecture(arch) => vec![arch], + AnySecondaryUnit::PackageBody(package) => vec![package], + } + } +} + +impl ASTNode for LabeledConcurrentStatement { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_labeled_concurrent_statement(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.label, &self.statement] + } +} + +impl ASTNode for ConcurrentStatement { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_concurrent_statement(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match &self { + ConcurrentStatement::ProcedureCall(stmt) => vec![stmt], + ConcurrentStatement::Block(stmt) => vec![stmt], + ConcurrentStatement::Process(stmt) => vec![stmt], + ConcurrentStatement::Assert(stmt) => vec![stmt], + ConcurrentStatement::Assignment(stmt) => vec![stmt], + ConcurrentStatement::Instance(stmt) => vec![stmt], + ConcurrentStatement::ForGenerate(stmt) => vec![stmt], + ConcurrentStatement::IfGenerate(stmt) => vec![stmt], + ConcurrentStatement::CaseGenerate(stmt) => vec![stmt], + } + } +} + +impl ASTNode for CaseGenerateStatement { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_case_generate_statement(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.sels] + } +} + +impl ASTNode for IfGenerateStatement { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_if_generate_statement(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.conds] + } +} + +impl ASTNode for ForGenerateStatement { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_for_generate_statement(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.index_name, &self.discrete_range, &self.body] + } +} + +impl ASTNode for InstantiationStatement { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_instantiation_statement(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.unit, &self.generic_map, &self.port_map] + } +} + +impl ASTNode for GenerateBody { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_generate_body(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.alternative_label, &self.decl, &self.statements] + } +} + +impl ASTNode for InstantiatedUnit { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_instantiated_unit(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + InstantiatedUnit::Component(component) => vec![component], + InstantiatedUnit::Entity(name, ident) => vec![name, ident], + InstantiatedUnit::Configuration(config) => vec![config], + } + } +} + +impl ASTNode for ConcurrentSignalAssignment { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_concurrent_signal_assignment(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.target, &self.delay_mechanism, &self.rhs] + } +} + +impl ASTNode for ConcurrentAssertStatement { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_concurrent_assert_statement(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.statement] + } +} + +impl ASTNode for ProcessStatement { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_process_statement(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.sensitivity_list, &self.decl, &self.statements] + } +} + +impl ASTNode for BlockStatement { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_block_statement(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![ + &self.guard_condition, + &self.header, + &self.decl, + &self.statements, + ] + } +} + +impl ASTNode for BlockHeader { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_block_header(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![ + &self.generic_map, + &self.generic_map, + &self.port_map, + &self.port_map, + ] + } +} + +impl ASTNode for ConcurrentProcedureCall { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_concurrent_procedure_call(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.call] + } +} + +impl ASTNode for PackageBody { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_package_body(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.context_clause, &self.ident, &self.decl] + } +} + +impl ASTNode for SensitivityList { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_sensitivity_list(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + SensitivityList::Names(names) => vec![names], + SensitivityList::All => vec![], + } + } +} + +impl ASTNode for ArchitectureBody { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_architecture_body(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![ + &self.context_clause, + &self.ident, + &self.entity_name, + &self.decl, + &self.statements, + ] + } +} + +impl ASTNode for Expression { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_expression(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + Expression::Binary(_, lhs, rhs) => vec![lhs, rhs], + Expression::Unary(_, expr) => vec![expr], + Expression::Aggregate(elements) => vec![elements], + Expression::Qualified(qual) => vec![qual], + Expression::Name(name) => vec![name], + Expression::Literal(lit) => vec![lit], + Expression::New(allocator) => vec![allocator], + } + } +} + +impl ASTNode for QualifiedExpression { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_qualified_expression(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.type_mark, &self.expr] + } +} + +impl ASTNode for Allocator { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_allocator(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + Allocator::Qualified(qual) => vec![qual], + Allocator::Subtype(subtype) => vec![subtype], + } + } +} + +impl ASTNode for AttributeDesignator { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_attribute_designator(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![] + } +} + +impl ASTNode for Signature { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_signature(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + Signature::Function(t1, t2) => vec![t1, t2], + Signature::Procedure(proc) => vec![proc], + } + } +} + +impl ASTNode for Name { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_name(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + Name::Designator(desi) => vec![desi], + Name::Selected(name, desi) => vec![name, desi], + Name::SelectedAll(name) => vec![name], + Name::Slice(name, range) => vec![name, range], + Name::Attribute(attr) => vec![attr], + Name::CallOrIndexed(coi) => vec![coi], + Name::External(external) => vec![external], + } + } +} + +impl ASTNode for ExternalName { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_external_name(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.path, &self.subtype] + } +} + +impl ASTNode for ExternalPath { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_external_path(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + ExternalPath::Package(name) => vec![name], + ExternalPath::Absolute(name) => vec![name], + ExternalPath::Relative(name, _) => vec![name], + } + } +} + +impl ASTNode for AttributeName { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_attribute_name(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.name, &self.signature, &self.attr, &self.expr] + } +} + +impl ASTNode for AbstractLiteral { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_abstract_literal(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![] + } +} + +impl ASTNode for Literal { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_literal(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + match self { + Literal::String(_) | Literal::BitString(_) | Literal::Character(_) | Literal::Null => { + vec![] + } + Literal::AbstractLiteral(lit) => vec![lit], + Literal::Physical(phy) => vec![phy], + } + } +} + +impl ASTNode for EntityTag { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_entity_tag(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.designator, &self.signature] + } +} + +impl ASTNode for MapAspect { + fn visit(&self, visitor: &mut dyn Visitor, ctx: &dyn TokenAccess) -> VisitorResult { + visitor.visit_map_aspect(self, ctx) + } + + fn children(&self) -> Vec<&dyn ASTNode> { + vec![&self.list] + } +} diff --git a/vhdl_lang/src/syntax/concurrent_statement.rs b/vhdl_lang/src/syntax/concurrent_statement.rs index fae98edf..6ff244f9 100644 --- a/vhdl_lang/src/syntax/concurrent_statement.rs +++ b/vhdl_lang/src/syntax/concurrent_statement.rs @@ -23,7 +23,7 @@ use super::tokens::{Kind::*, TokenStream}; use super::waveform::{parse_delay_mechanism, parse_waveform}; use crate::ast::*; use crate::data::*; -use crate::syntax::TokenAccess; +use crate::syntax::{Kind, TokenAccess}; /// LRM 11.2 Block statement pub fn parse_block_statement( @@ -72,6 +72,7 @@ fn parse_block_header( let mut port_map = None; loop { + let token_id = stream.get_token_id(); let token = stream.peek_expect()?; match token.kind { Generic => { @@ -85,7 +86,7 @@ fn parse_block_header( } else if generic_clause.is_none() { diagnostics.push(Diagnostic::error( stream.get_token(map_token), - "Generic map declared without preceeding generic clause", + "Generic map declared without preceding generic clause", )); } else if generic_map.is_some() { diagnostics.push(Diagnostic::error( @@ -93,10 +94,14 @@ fn parse_block_header( "Duplicate generic map", )); } - let parsed_generic_map = Some(parse_association_list(stream)?); + let (list, closing_paren) = parse_association_list(stream)?; stream.expect_kind(SemiColon)?; if generic_map.is_none() { - generic_map = parsed_generic_map; + generic_map = Some(MapAspect { + start: token_id, + list, + closing_paren + }); } } else { if generic_map.is_some() { @@ -128,10 +133,14 @@ fn parse_block_header( "Duplicate port map", )); } - let parsed_port_map = Some(parse_association_list(stream)?); + let (list, closing_paren) = parse_association_list(stream)?; stream.expect_kind(SemiColon)?; if port_map.is_none() { - port_map = parsed_port_map; + port_map = Some(MapAspect { + start: token_id, + list, + closing_paren + }); } } else { if port_map.is_some() { @@ -323,29 +332,29 @@ pub fn parse_concurrent_assert_statement( }) } +pub fn parse_generic_map_aspect(stream: &TokenStream, aspect_kind: Kind) -> ParseResult> { + if let Some(aspect) = stream.pop_if_kind(aspect_kind) { + stream.expect_kind(Map)?; + let (list, closing_paren) = parse_association_list(stream)?; + Ok(Some(MapAspect { + start: aspect, + list, + closing_paren, + })) + } else { + Ok(None) + } +} + #[allow(clippy::type_complexity)] pub fn parse_generic_and_port_map( stream: &TokenStream, ) -> ParseResult<( - Option>, - Option>, + Option, + Option, )> { - let generic_map = { - if stream.skip_if_kind(Generic) { - stream.expect_kind(Map)?; - Some(parse_association_list(stream)?) - } else { - None - } - }; - let port_map = { - if stream.skip_if_kind(Port) { - stream.expect_kind(Map)?; - Some(parse_association_list(stream)?) - } else { - None - } - }; + let generic_map = parse_generic_map_aspect(stream, Generic)?; + let port_map = parse_generic_map_aspect(stream, Port)?; Ok((generic_map, port_map)) } @@ -356,12 +365,14 @@ pub fn parse_instantiation_statement( ) -> ParseResult { let (generic_map, port_map) = parse_generic_and_port_map(stream)?; + let semi = stream.expect_kind(SemiColon)?; + let inst = InstantiationStatement { unit, - generic_map: generic_map.unwrap_or_default(), - port_map: port_map.unwrap_or_default(), + generic_map, + port_map, + semicolon: semi }; - stream.expect_kind(SemiColon)?; Ok(inst) } diff --git a/vhdl_lang/src/syntax/context.rs b/vhdl_lang/src/syntax/context.rs index ab9361c3..b0866cb4 100644 --- a/vhdl_lang/src/syntax/context.rs +++ b/vhdl_lang/src/syntax/context.rs @@ -90,13 +90,15 @@ pub fn parse_context( })) } else { // Context reference - let mut name_list = Vec::new(); + let mut items = vec![name]; + let mut tokens = Vec::new(); while let Some(comma) = stream.pop_if_kind(Comma) { - name_list.push((comma, parse_name(stream)?)); + items.push(parse_name(stream)?); + tokens.push(comma); } let name_list = SeparatedList { - first: name, - remainder: name_list, + items, + tokens }; let semi_token = stream.expect_kind(SemiColon)?; Ok(DeclarationOrReference::Reference(ContextReference { diff --git a/vhdl_lang/src/syntax/declarative_part.rs b/vhdl_lang/src/syntax/declarative_part.rs index d492e60f..8a27d3bc 100644 --- a/vhdl_lang/src/syntax/declarative_part.rs +++ b/vhdl_lang/src/syntax/declarative_part.rs @@ -10,13 +10,14 @@ use super::common::ParseResult; use super::component_declaration::parse_component_declaration; use super::configuration::parse_configuration_specification; use super::context::parse_use_clause; -use super::names::{parse_association_list, parse_selected_name}; +use super::names::{parse_selected_name}; use super::object_declaration::{parse_file_declaration, parse_object_declaration}; use super::subprogram::parse_subprogram; use super::tokens::{Kind::*, *}; use super::type_declaration::parse_type_declaration; use crate::ast::{ContextClause, Declaration, PackageInstantiation}; use crate::data::DiagnosticHandler; +use crate::syntax::concurrent_statement::parse_generic_map_aspect; pub fn parse_package_instantiation(stream: &TokenStream) -> ParseResult { stream.expect_kind(Package)?; @@ -24,17 +25,9 @@ pub fn parse_package_instantiation(stream: &TokenStream) -> ParseResult { - stream.expect_kind(Map)?; - let association_list = parse_association_list(stream)?; - stream.expect_kind(SemiColon)?; - Some(association_list) - }, - SemiColon => None); Ok(PackageInstantiation { context_clause: ContextClause::default(), ident: ident.into(), diff --git a/vhdl_lang/src/syntax/interface_declaration.rs b/vhdl_lang/src/syntax/interface_declaration.rs index bc44a7c7..9f7c2f83 100644 --- a/vhdl_lang/src/syntax/interface_declaration.rs +++ b/vhdl_lang/src/syntax/interface_declaration.rs @@ -200,7 +200,10 @@ fn parse_interface_package(stream: &TokenStream) -> ParseResult InterfacePackageGenericMapAspect::Map(parse_association_list_no_leftpar(stream)?), + _ => { + let (list, _) = parse_association_list_no_leftpar(stream)?; + InterfacePackageGenericMapAspect::Map(list) + }, } }; diff --git a/vhdl_lang/src/syntax/names.rs b/vhdl_lang/src/syntax/names.rs index f8d2c039..1a8e1837 100644 --- a/vhdl_lang/src/syntax/names.rs +++ b/vhdl_lang/src/syntax/names.rs @@ -13,6 +13,8 @@ use super::tokens::{Kind::*, TokenAccess, TokenStream}; use crate::ast; use crate::ast::*; use crate::data::{Diagnostic, WithPos}; +use crate::syntax::separated_list::parse_list_with_separator; +use crate::syntax::TokenId; pub fn parse_designator(stream: &TokenStream) -> ParseResult> { Ok(expect_token!( @@ -178,26 +180,17 @@ fn parse_association_element(stream: &TokenStream) -> ParseResult ParseResult> { +pub fn parse_association_list(stream: &TokenStream) -> ParseResult<(SeparatedList, TokenId)> { stream.expect_kind(LeftPar)?; parse_association_list_no_leftpar(stream) } pub fn parse_association_list_no_leftpar( stream: &TokenStream, -) -> ParseResult> { - let mut association_elements = Vec::with_capacity(1); - loop { - association_elements.push(parse_association_element(stream)?); - expect_token!( - stream, - token, - Comma => {}, - RightPar => { - return Ok(association_elements); - } - ) - } +) -> ParseResult<(SeparatedList, TokenId)> { + let list = parse_list_with_separator(stream, Comma, parse_association_element)?; + let comma = stream.expect_kind(RightPar)?; + Ok((list, comma)) } fn parse_function_call( diff --git a/vhdl_lang/src/syntax/separated_list.rs b/vhdl_lang/src/syntax/separated_list.rs index 926aac9b..19f2ed2f 100644 --- a/vhdl_lang/src/syntax/separated_list.rs +++ b/vhdl_lang/src/syntax/separated_list.rs @@ -24,11 +24,13 @@ where F: Fn(&TokenStream) -> ParseResult, { let first = parse_fn(stream)?; - let mut remainder = Vec::new(); + let mut items = vec![first]; + let mut tokens = Vec::new(); while let Some(separator) = stream.pop_if_kind(separator) { - remainder.push((separator, parse_fn(stream)?)); + items.push(parse_fn(stream)?); + tokens.push(separator); } - Ok(SeparatedList { first, remainder }) + Ok(SeparatedList { items, tokens }) } pub fn parse_name_list(stream: &TokenStream) -> DiagnosticResult { From 5190cad510fb51637798129a8324e7fc49ce0799 Mon Sep 17 00:00:00 2001 From: Lukas Scheller Date: Sun, 8 Oct 2023 09:24:31 +0200 Subject: [PATCH 02/13] Fix tests; cargo fmt --- vhdl_lang/src/syntax/concurrent_statement.rs | 61 +++++++++++--------- vhdl_lang/src/syntax/declarative_part.rs | 8 +-- vhdl_lang/src/syntax/names.rs | 8 ++- vhdl_lang/src/syntax/separated_list.rs | 19 ++---- vhdl_lang/src/syntax/test.rs | 22 ++++++- 5 files changed, 71 insertions(+), 47 deletions(-) diff --git a/vhdl_lang/src/syntax/concurrent_statement.rs b/vhdl_lang/src/syntax/concurrent_statement.rs index 6ff244f9..8b6e39ba 100644 --- a/vhdl_lang/src/syntax/concurrent_statement.rs +++ b/vhdl_lang/src/syntax/concurrent_statement.rs @@ -332,7 +332,7 @@ pub fn parse_concurrent_assert_statement( }) } -pub fn parse_generic_map_aspect(stream: &TokenStream, aspect_kind: Kind) -> ParseResult> { +pub fn parse_map_aspect(stream: &TokenStream, aspect_kind: Kind) -> ParseResult> { if let Some(aspect) = stream.pop_if_kind(aspect_kind) { stream.expect_kind(Map)?; let (list, closing_paren) = parse_association_list(stream)?; @@ -353,8 +353,8 @@ pub fn parse_generic_and_port_map( Option, Option, )> { - let generic_map = parse_generic_map_aspect(stream, Generic)?; - let port_map = parse_generic_map_aspect(stream, Port)?; + let generic_map = parse_map_aspect(stream, Generic)?; + let port_map = parse_map_aspect(stream, Port)?; Ok((generic_map, port_map)) } @@ -925,9 +925,9 @@ end block;", guard_condition: None, header: BlockHeader { generic_clause: Some(vec![code.s1("gen: integer := 1").generic()]), - generic_map: Some(code.s1("(gen => 1)").association_list()), + generic_map: Some(code.s1("generic map(gen => 1)").generic_map_aspect()), port_clause: Some(vec![code.s1("prt: integer := 1").port()]), - port_map: Some(code.s1("(prt => 2)").association_list()), + port_map: Some(code.s1("port map(prt => 2)").port_map_aspect()), }, decl: vec![], statements: vec![], @@ -1263,8 +1263,9 @@ with x(0) + 1 select let inst = InstantiationStatement { unit: InstantiatedUnit::Component(code.s1("lib.foo.bar").selected_name()), - generic_map: vec![], - port_map: vec![], + generic_map: None, + port_map: None, + semicolon: code.s1(";").token(), }; let stmt = code.with_stream_no_diagnostics(parse_labeled_concurrent_statement); assert_eq!(stmt.label.tree, Some(code.s1("inst").ident())); @@ -1283,8 +1284,9 @@ with x(0) + 1 select let inst = InstantiationStatement { unit: InstantiatedUnit::Configuration(code.s1("lib.foo.bar").selected_name()), - generic_map: vec![], - port_map: vec![], + generic_map: None, + port_map: None, + semicolon: code.s1(";").token() }; let stmt = code.with_stream_no_diagnostics(parse_labeled_concurrent_statement); assert_eq!(stmt.label.tree, Some(code.s1("inst").ident())); @@ -1303,8 +1305,9 @@ with x(0) + 1 select let inst = InstantiationStatement { unit: InstantiatedUnit::Entity(code.s1("lib.foo.bar").selected_name(), None), - generic_map: vec![], - port_map: vec![], + generic_map: None, + port_map: None, + semicolon: code.s1(";").token() }; let stmt = code.with_stream_no_diagnostics(parse_labeled_concurrent_statement); assert_eq!(stmt.label.tree, Some(code.s1("inst").ident())); @@ -1326,8 +1329,9 @@ with x(0) + 1 select code.s1("lib.foo.bar").selected_name(), Some(WithRef::new(code.s1("arch").ident())), ), - generic_map: vec![], - port_map: vec![], + generic_map: None, + port_map: None, + semicolon: code.s1(";").token(), }; let stmt = code.with_stream_no_diagnostics(parse_labeled_concurrent_statement); assert_eq!(stmt.label.tree, Some(code.s1("inst").ident())); @@ -1355,16 +1359,17 @@ inst: component lib.foo.bar let inst = InstantiationStatement { unit: InstantiatedUnit::Component(code.s1("lib.foo.bar").selected_name()), - generic_map: code - .s1("( + generic_map: Some(code + .s1("generic map ( const => 1 )") - .association_list(), - port_map: code - .s1("( + .generic_map_aspect()), + port_map: Some(code + .s1("port map ( clk => clk_foo )") - .association_list(), + .port_map_aspect()), + semicolon: code.s1(";").token(), }; let stmt = code.with_stream_no_diagnostics(parse_labeled_concurrent_statement); assert_eq!(stmt.label.tree, Some(code.s1("inst").ident())); @@ -1389,12 +1394,13 @@ inst: lib.foo.bar let inst = InstantiationStatement { unit: InstantiatedUnit::Component(code.s1("lib.foo.bar").selected_name()), - generic_map: vec![], - port_map: code - .s1("( + generic_map: None, + port_map: Some(code + .s1("port map ( clk => clk_foo )") - .association_list(), + .port_map_aspect()), + semicolon: code.s1(";").token() }; let stmt = code.with_stream_no_diagnostics(parse_labeled_concurrent_statement); assert_eq!(stmt.label.tree, Some(code.s1("inst").ident())); @@ -1419,12 +1425,13 @@ inst: lib.foo.bar let inst = InstantiationStatement { unit: InstantiatedUnit::Component(code.s1("lib.foo.bar").selected_name()), - generic_map: code - .s1("( + generic_map: Some(code + .s1("generic map ( const => 1 )") - .association_list(), - port_map: vec![], + .generic_map_aspect()), + port_map: None, + semicolon: code.s1(";").token() }; let stmt = code.with_stream_no_diagnostics(parse_labeled_concurrent_statement); assert_eq!(stmt.label.tree, Some(code.s1("inst").ident())); diff --git a/vhdl_lang/src/syntax/declarative_part.rs b/vhdl_lang/src/syntax/declarative_part.rs index 8a27d3bc..e178f44f 100644 --- a/vhdl_lang/src/syntax/declarative_part.rs +++ b/vhdl_lang/src/syntax/declarative_part.rs @@ -17,7 +17,7 @@ use super::tokens::{Kind::*, *}; use super::type_declaration::parse_type_declaration; use crate::ast::{ContextClause, Declaration, PackageInstantiation}; use crate::data::DiagnosticHandler; -use crate::syntax::concurrent_statement::parse_generic_map_aspect; +use crate::syntax::concurrent_statement::parse_map_aspect; pub fn parse_package_instantiation(stream: &TokenStream) -> ParseResult { stream.expect_kind(Package)?; @@ -25,7 +25,7 @@ pub fn parse_package_instantiation(stream: &TokenStream) -> ParseResult bar )") - .association_list() + .generic_map_aspect() ) } ); diff --git a/vhdl_lang/src/syntax/names.rs b/vhdl_lang/src/syntax/names.rs index 1a8e1837..0ce187e8 100644 --- a/vhdl_lang/src/syntax/names.rs +++ b/vhdl_lang/src/syntax/names.rs @@ -188,6 +188,9 @@ pub fn parse_association_list(stream: &TokenStream) -> ParseResult<(SeparatedLis pub fn parse_association_list_no_leftpar( stream: &TokenStream, ) -> ParseResult<(SeparatedList, TokenId)> { + if let Some(right_par) = stream.pop_if_kind(RightPar) { + return Err(Diagnostic::error(stream.get_pos(right_par), "Association list cannot be empty")); + } let list = parse_list_with_separator(stream, Comma, parse_association_element)?; let comma = stream.expect_kind(RightPar)?; Ok((list, comma)) @@ -1013,7 +1016,10 @@ mod tests { formal: Some(code.s1("arg").name()), actual: WithPos::new(ActualPart::Open, code.s("open", 2)), }; - assert_eq!(code.with_stream(parse_association_list), vec![elem1, elem2]); + assert_eq!(code.with_stream(parse_association_list), (SeparatedList { + items: vec![elem1, elem2], + tokens: vec![code.s1(",").token()] + }, code.s1(")").token())); } #[test] diff --git a/vhdl_lang/src/syntax/separated_list.rs b/vhdl_lang/src/syntax/separated_list.rs index 19f2ed2f..862e8021 100644 --- a/vhdl_lang/src/syntax/separated_list.rs +++ b/vhdl_lang/src/syntax/separated_list.rs @@ -23,8 +23,7 @@ pub fn parse_list_with_separator( where F: Fn(&TokenStream) -> ParseResult, { - let first = parse_fn(stream)?; - let mut items = vec![first]; + let mut items = vec![parse_fn(stream)?]; let mut tokens = Vec::new(); while let Some(separator) = stream.pop_if_kind(separator) { items.push(parse_fn(stream)?); @@ -61,10 +60,7 @@ mod test { let code = Code::new("abc"); assert_eq!( code.parse_ok(parse_ident_list), - IdentList { - first: code.s1("abc").ident().into_ref(), - remainder: vec![] - } + IdentList::single(code.s1("abc").ident().into_ref()) ) } @@ -74,11 +70,8 @@ mod test { assert_eq!( code.parse_ok(parse_ident_list), IdentList { - first: code.s1("abc").ident().into_ref(), - remainder: vec![ - (code.s(",", 1).token(), code.s1("def").ident().into_ref()), - (code.s(",", 2).token(), code.s1("ghi").ident().into_ref()), - ] + items: vec![code.s1("abc").ident().into_ref(), code.s1("def").ident().into_ref(), code.s1("ghi").ident().into_ref()], + tokens: vec![code.s(",", 1).token(), code.s(",", 2).token()] } ) } @@ -89,8 +82,8 @@ mod test { assert_eq!( code.parse_ok(parse_name_list), NameList { - first: code.s1("work.foo").name(), - remainder: vec![(code.s1(",").token(), code.s1("lib.bar.all").name())] + items: vec![code.s1("work.foo").name(), code.s1("lib.bar.all").name()], + tokens: vec![code.s1(",").token()], } ) } diff --git a/vhdl_lang/src/syntax/test.rs b/vhdl_lang/src/syntax/test.rs index 3e7d9d88..dd75210e 100644 --- a/vhdl_lang/src/syntax/test.rs +++ b/vhdl_lang/src/syntax/test.rs @@ -37,6 +37,7 @@ use std::collections::HashMap; use std::fmt::Debug; use std::hash::Hasher; use std::sync::Arc; +use crate::syntax::concurrent_statement::parse_map_aspect; pub struct CodeBuilder { pub symbols: Arc, @@ -105,6 +106,15 @@ impl CodeBuilder { } } +impl SeparatedList { + pub fn single(item: T) -> SeparatedList { + SeparatedList { + items: vec![item], + tokens: vec![], + } + } +} + #[derive(Clone)] pub struct Code { pub symbols: Arc, @@ -503,8 +513,16 @@ impl Code { self.parse_ok_no_diagnostics(parse_labeled_concurrent_statement) } - pub fn association_list(&self) -> Vec { - self.parse_ok(parse_association_list) + pub fn association_list(&self) -> SeparatedList { + self.parse_ok(parse_association_list).0 + } + + pub fn port_map_aspect(&self) -> MapAspect { + self.parse_ok(|stream| parse_map_aspect(stream, Kind::Port)).expect("Expecting port map aspect") + } + + pub fn generic_map_aspect(&self) -> MapAspect { + self.parse_ok(|stream| parse_map_aspect(stream, Kind::Generic)).expect("Expecting generic map aspect") } pub fn waveform(&self) -> Waveform { From 75a61cead7d2eb39fc971456b466a3ae07fb33b9 Mon Sep 17 00:00:00 2001 From: Lukas Scheller Date: Sun, 8 Oct 2023 09:26:23 +0200 Subject: [PATCH 03/13] clippy --- vhdl_lang/src/analysis/completion.rs | 2 +- vhdl_lang/src/analysis/concurrent.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/vhdl_lang/src/analysis/completion.rs b/vhdl_lang/src/analysis/completion.rs index 25eea940..f3b5bebb 100644 --- a/vhdl_lang/src/analysis/completion.rs +++ b/vhdl_lang/src/analysis/completion.rs @@ -121,7 +121,7 @@ impl <'a> AutocompletionVisitor<'a> { if let Some(ent) = self.get_ent(node) { let mut searcher = EntityPortAndGenericsExtractor { id: ent, - items: &mut self.completions, + items: self.completions, kind, }; let _ = self.root.search(&mut searcher); diff --git a/vhdl_lang/src/analysis/concurrent.rs b/vhdl_lang/src/analysis/concurrent.rs index bfdf72a2..19b96b07 100644 --- a/vhdl_lang/src/analysis/concurrent.rs +++ b/vhdl_lang/src/analysis/concurrent.rs @@ -288,14 +288,14 @@ impl<'a> AnalyzeContext<'a> { &entity_name.pos, &generic_region, scope, - &mut instance.generic_map.as_mut().map(|it| it.list.items.as_mut_slice()).unwrap_or(&mut []), + instance.generic_map.as_mut().map(|it| it.list.items.as_mut_slice()).unwrap_or(&mut []), diagnostics, )?; self.analyze_assoc_elems_with_formal_region( &entity_name.pos, &port_region, scope, - &mut instance.port_map.as_mut().map(|it| it.list.items.as_mut_slice()).unwrap_or(&mut []), + instance.port_map.as_mut().map(|it| it.list.items.as_mut_slice()).unwrap_or(&mut []), diagnostics, )?; Ok(()) @@ -326,14 +326,14 @@ impl<'a> AnalyzeContext<'a> { &component_name.pos, &generic_region, scope, - &mut instance.generic_map.as_mut().map(|it| it.list.items.as_mut_slice()).unwrap_or(&mut []), + instance.generic_map.as_mut().map(|it| it.list.items.as_mut_slice()).unwrap_or(&mut []), diagnostics, )?; self.analyze_assoc_elems_with_formal_region( &component_name.pos, &port_region, scope, - &mut instance.port_map.as_mut().map(|it| it.list.items.as_mut_slice()).unwrap_or(&mut []), + instance.port_map.as_mut().map(|it| it.list.items.as_mut_slice()).unwrap_or(&mut []), diagnostics, )?; Ok(()) From 69c89cb5136eb6a44cbbb5a421f3f677131644d2 Mon Sep 17 00:00:00 2001 From: Lukas Scheller Date: Sun, 8 Oct 2023 09:28:41 +0200 Subject: [PATCH 04/13] fmt --- vhdl_lang/src/analysis/completion.rs | 74 +++++++++++-------- vhdl_lang/src/analysis/concurrent.rs | 31 ++++++-- vhdl_lang/src/analysis/package_instance.rs | 7 +- vhdl_lang/src/analysis/root.rs | 36 ++++----- vhdl_lang/src/syntax/concurrent_statement.rs | 47 ++++++------ vhdl_lang/src/syntax/context.rs | 5 +- vhdl_lang/src/syntax/declarative_part.rs | 2 +- vhdl_lang/src/syntax/interface_declaration.rs | 2 +- vhdl_lang/src/syntax/names.rs | 23 ++++-- vhdl_lang/src/syntax/separated_list.rs | 6 +- vhdl_lang/src/syntax/test.rs | 10 ++- 11 files changed, 150 insertions(+), 93 deletions(-) diff --git a/vhdl_lang/src/analysis/completion.rs b/vhdl_lang/src/analysis/completion.rs index f3b5bebb..85643662 100644 --- a/vhdl_lang/src/analysis/completion.rs +++ b/vhdl_lang/src/analysis/completion.rs @@ -1,13 +1,17 @@ use crate::analysis::{DesignRoot, HasEntityId}; -use crate::ast::{AnyDesignUnit, AnyPrimaryUnit, Declaration, InstantiatedUnit, InstantiationStatement, InterfaceDeclaration, MapAspect, Name, SelectedName, SubprogramDeclaration, UnitKey}; +use crate::ast::search::{FoundDeclaration, SearchResult, SearchState, Searcher}; +use crate::ast::visitor::{Visitor, VisitorResult}; +use crate::ast::{ + AnyDesignUnit, AnyPrimaryUnit, Declaration, InstantiatedUnit, InstantiationStatement, + InterfaceDeclaration, MapAspect, Name, SelectedName, SubprogramDeclaration, UnitKey, +}; use crate::data::{ContentReader, Symbol}; use crate::syntax::Kind::*; use crate::syntax::{Symbols, Token, TokenAccess, Tokenizer, Value}; use crate::{EntityId, Position, Source}; use itertools::Itertools; +use std::collections::HashSet; use std::default::Default; -use crate::ast::search::{FoundDeclaration, Searcher, SearchResult, SearchState}; -use crate::ast::visitor::{Visitor, VisitorResult}; macro_rules! kind { ($kind: pat) => { @@ -28,16 +32,16 @@ macro_rules! ident { #[derive(Eq, PartialEq, Debug)] enum MapAspectKind { Port, - Generic + Generic, } struct EntityPortAndGenericsExtractor<'a> { id: EntityId, items: &'a mut Vec, - kind: MapAspectKind + kind: MapAspectKind, } -impl <'a> Searcher for EntityPortAndGenericsExtractor<'a> { +impl<'a> Searcher for EntityPortAndGenericsExtractor<'a> { fn search_decl(&mut self, _ctx: &dyn TokenAccess, decl: FoundDeclaration) -> SearchState { if decl.ent_id() == Some(self.id) { match decl { @@ -60,8 +64,8 @@ impl <'a> Searcher for EntityPortAndGenericsExtractor<'a> { } } SearchState::Finished(SearchResult::Found) - }, - _ => SearchState::NotFinished + } + _ => SearchState::NotFinished, } } else { SearchState::NotFinished @@ -78,46 +82,54 @@ impl InterfaceDeclaration { InterfaceDeclaration::Subprogram(decl, _) => match decl { SubprogramDeclaration::Procedure(proc) => proc.designator.to_string(), SubprogramDeclaration::Function(func) => func.designator.to_string(), - } + }, InterfaceDeclaration::Package(package) => package.package_name.to_string(), } } } - struct AutocompletionVisitor<'a> { root: &'a DesignRoot, cursor: Position, - completions: &'a mut Vec + completions: &'a mut Vec, } -impl <'a> AutocompletionVisitor<'a> { +impl<'a> AutocompletionVisitor<'a> { fn get_ent(&self, node: &InstantiationStatement) -> Option { match &node.unit { InstantiatedUnit::Entity(name, _) => { let Some(ent_id) = (match &name.item { - SelectedName::Designator(desi) => {desi.reference} - SelectedName::Selected(_, desi) => {desi.item.reference} + SelectedName::Designator(desi) => desi.reference, + SelectedName::Selected(_, desi) => desi.item.reference, }) else { return None; }; Some(ent_id) } - _ => None + _ => None, } } - fn process_map_aspect(&mut self, node: &InstantiationStatement, map: &MapAspect, ctx: &dyn TokenAccess, kind: MapAspectKind) { - if ctx.get_span(map.start, map.closing_paren).range().contains(self.cursor) { - let items_in_node = map.list.items.iter().filter_map(|el| { - match &el.formal { + fn process_map_aspect( + &mut self, + node: &InstantiationStatement, + map: &MapAspect, + ctx: &dyn TokenAccess, + kind: MapAspectKind, + ) { + if ctx + .get_span(map.start, map.closing_paren) + .range() + .contains(self.cursor) + { + let items_in_node: HashSet = + HashSet::from_iter(map.list.items.iter().filter_map(|el| match &el.formal { None => None, Some(name) => match &name.item { Name::Designator(desi) => Some(desi.item.to_string().to_lowercase()), - _ => None - } - } - }).collect_vec(); + _ => None, + }, + })); if let Some(ent) = self.get_ent(node) { let mut searcher = EntityPortAndGenericsExtractor { id: ent, @@ -125,15 +137,19 @@ impl <'a> AutocompletionVisitor<'a> { kind, }; let _ = self.root.search(&mut searcher); - self.completions.retain(|name| !items_in_node.contains(&name.to_lowercase())); + self.completions + .retain(|name| !items_in_node.contains(&name.to_lowercase())); } } } } -impl <'a> Visitor for AutocompletionVisitor<'a> { - - fn visit_instantiation_statement(&mut self, node: &InstantiationStatement, ctx: &dyn TokenAccess) -> VisitorResult { +impl<'a> Visitor for AutocompletionVisitor<'a> { + fn visit_instantiation_statement( + &mut self, + node: &InstantiationStatement, + ctx: &dyn TokenAccess, + ) -> VisitorResult { if let Some(map) = &node.generic_map { self.process_map_aspect(node, map, ctx, MapAspectKind::Generic) } @@ -273,11 +289,11 @@ impl DesignRoot { let mut visitor = AutocompletionVisitor { completions: &mut completions, root: self, - cursor + cursor, }; self.walk(&mut visitor); completions - }, + } } } } diff --git a/vhdl_lang/src/analysis/concurrent.rs b/vhdl_lang/src/analysis/concurrent.rs index 19b96b07..cbf6066e 100644 --- a/vhdl_lang/src/analysis/concurrent.rs +++ b/vhdl_lang/src/analysis/concurrent.rs @@ -288,14 +288,22 @@ impl<'a> AnalyzeContext<'a> { &entity_name.pos, &generic_region, scope, - instance.generic_map.as_mut().map(|it| it.list.items.as_mut_slice()).unwrap_or(&mut []), + instance + .generic_map + .as_mut() + .map(|it| it.list.items.as_mut_slice()) + .unwrap_or(&mut []), diagnostics, )?; self.analyze_assoc_elems_with_formal_region( &entity_name.pos, &port_region, scope, - instance.port_map.as_mut().map(|it| it.list.items.as_mut_slice()).unwrap_or(&mut []), + instance + .port_map + .as_mut() + .map(|it| it.list.items.as_mut_slice()) + .unwrap_or(&mut []), diagnostics, )?; Ok(()) @@ -326,14 +334,22 @@ impl<'a> AnalyzeContext<'a> { &component_name.pos, &generic_region, scope, - instance.generic_map.as_mut().map(|it| it.list.items.as_mut_slice()).unwrap_or(&mut []), + instance + .generic_map + .as_mut() + .map(|it| it.list.items.as_mut_slice()) + .unwrap_or(&mut []), diagnostics, )?; self.analyze_assoc_elems_with_formal_region( &component_name.pos, &port_region, scope, - instance.port_map.as_mut().map(|it| it.list.items.as_mut_slice()).unwrap_or(&mut []), + instance + .port_map + .as_mut() + .map(|it| it.list.items.as_mut_slice()) + .unwrap_or(&mut []), diagnostics, )?; Ok(()) @@ -374,7 +390,12 @@ impl<'a> AnalyzeContext<'a> { Ok(()) } - pub fn analyze_map_aspect(&self, scope: & Scope<'a>, map: & mut Option, diagnostics: &mut dyn DiagnosticHandler) -> FatalResult { + pub fn analyze_map_aspect( + &self, + scope: &Scope<'a>, + map: &mut Option, + diagnostics: &mut dyn DiagnosticHandler, + ) -> FatalResult { let Some(aspect) = map else { return Ok(()); }; diff --git a/vhdl_lang/src/analysis/package_instance.rs b/vhdl_lang/src/analysis/package_instance.rs index a5071337..2c9c0341 100644 --- a/vhdl_lang/src/analysis/package_instance.rs +++ b/vhdl_lang/src/analysis/package_instance.rs @@ -225,7 +225,12 @@ impl<'a> AnalyzeContext<'a> { let (generics, other) = package_region.to_package_generic(); let mapping = if let Some(generic_map) = generic_map { - self.package_generic_map(&nested, generics, generic_map.list.items.as_mut_slice(), diagnostics)? + self.package_generic_map( + &nested, + generics, + generic_map.list.items.as_mut_slice(), + diagnostics, + )? } else { FnvHashMap::default() }; diff --git a/vhdl_lang/src/analysis/root.rs b/vhdl_lang/src/analysis/root.rs index ada042fe..a9e1a39c 100644 --- a/vhdl_lang/src/analysis/root.rs +++ b/vhdl_lang/src/analysis/root.rs @@ -15,6 +15,7 @@ use super::standard::UniversalTypes; use super::visibility::Visibility; use crate::ast::search::*; +use crate::ast::visitor::{walk, Visitor}; use crate::ast::*; use crate::data::*; use crate::syntax::{Symbols, Token, TokenAccess}; @@ -23,7 +24,6 @@ use parking_lot::RwLock; use std::collections::hash_map::Entry; use std::ops::Deref; use std::sync::Arc; -use crate::ast::visitor::{Visitor, walk}; /// A design unit with design unit data pub(super) struct AnalysisData { @@ -181,7 +181,7 @@ impl Library { UnitKey::Secondary(ref primary_name, ref name) => match unit.kind() { AnyKind::Secondary(SecondaryKind::Architecture) => Diagnostic::error( unit.ident(), - format!("Duplicate architecture '{name}' of entity '{primary_name}'", ), + format!("Duplicate architecture '{name}' of entity '{primary_name}'",), ), AnyKind::Secondary(SecondaryKind::PackageBody) => Diagnostic::error( unit.pos(), @@ -326,7 +326,7 @@ impl DesignRoot { } /// Iterates over all available library symbols. - pub fn available_libraries(&self) -> impl Iterator { + pub fn available_libraries(&self) -> impl Iterator { self.libraries.keys() } @@ -468,10 +468,10 @@ impl DesignRoot { searcher.references } - pub fn public_symbols<'a>(&'a self) -> Box> + 'a> { + pub fn public_symbols<'a>(&'a self) -> Box> + 'a> { Box::new(self.libraries.values().flat_map(|library| { std::iter::once(self.arenas.get(library.id)).chain(library.units.values().flat_map( - |unit| -> Box>> { + |unit| -> Box>> { if matches!(unit.kind(), AnyKind::Primary(_)) { let data = self.get_analysis(unit); if let AnyDesignUnit::Primary(primary) = data.deref() { @@ -856,13 +856,13 @@ impl DesignRoot { .libraries .get(&std_lib_name) .map(|library| &library.units) - else { - return; - }; + else { + return; + }; let Some(locked_unit) = standard_units.get(&UnitKey::Primary(self.symbol_utf8("standard"))) - else { - return; - }; + else { + return; + }; let AnalysisEntry::Vacant(mut unit) = locked_unit.unit.entry() else { return; }; @@ -924,7 +924,7 @@ impl DesignRoot { } for ent in - context.universal_implicits(UniversalType::Real, context.universal_real().into()) + context.universal_implicits(UniversalType::Real, context.universal_real().into()) { unsafe { arena.add_implicit(universal.real, ent); @@ -988,9 +988,9 @@ impl DesignRoot { if let Some(ent) = primary.ent_id() { let AnyEntKind::Design(Design::Package(_, ref region)) = std_logic_arena.get(ent).kind() - else { - unreachable!() - }; + else { + unreachable!() + }; if let Some(NamedEntities::Single(ent)) = region.lookup_immediate( &Designator::Identifier(self.symbol_utf8("std_ulogic")), @@ -1257,7 +1257,7 @@ end architecture; code.s("rtl", 2), "Duplicate architecture 'rtl' of entity 'ent'", ) - .related(code.s("rtl", 1), "Previously defined here")], + .related(code.s("rtl", 1), "Previously defined here")], ); } @@ -1287,14 +1287,14 @@ end configuration; code.s("cfg", 2), "A primary unit has already been declared with name 'cfg' in library 'libname'", ) - .related(code.s1("cfg"), "Previously defined here")], + .related(code.s1("cfg"), "Previously defined here")], ); assert_eq!(library.units.len(), 2); assert_eq!(library.duplicates.len(), 1); } } -fn public_symbols<'a>(ent: EntRef<'a>) -> Box> + 'a> { +fn public_symbols<'a>(ent: EntRef<'a>) -> Box> + 'a> { match ent.kind() { AnyEntKind::Design(d) => match d { Design::Entity(_, region) diff --git a/vhdl_lang/src/syntax/concurrent_statement.rs b/vhdl_lang/src/syntax/concurrent_statement.rs index 8b6e39ba..dba79810 100644 --- a/vhdl_lang/src/syntax/concurrent_statement.rs +++ b/vhdl_lang/src/syntax/concurrent_statement.rs @@ -100,7 +100,7 @@ fn parse_block_header( generic_map = Some(MapAspect { start: token_id, list, - closing_paren + closing_paren, }); } } else { @@ -139,7 +139,7 @@ fn parse_block_header( port_map = Some(MapAspect { start: token_id, list, - closing_paren + closing_paren, }); } } else { @@ -349,10 +349,7 @@ pub fn parse_map_aspect(stream: &TokenStream, aspect_kind: Kind) -> ParseResult< #[allow(clippy::type_complexity)] pub fn parse_generic_and_port_map( stream: &TokenStream, -) -> ParseResult<( - Option, - Option, -)> { +) -> ParseResult<(Option, Option)> { let generic_map = parse_map_aspect(stream, Generic)?; let port_map = parse_map_aspect(stream, Port)?; @@ -371,7 +368,7 @@ pub fn parse_instantiation_statement( unit, generic_map, port_map, - semicolon: semi + semicolon: semi, }; Ok(inst) } @@ -1286,7 +1283,7 @@ with x(0) + 1 select unit: InstantiatedUnit::Configuration(code.s1("lib.foo.bar").selected_name()), generic_map: None, port_map: None, - semicolon: code.s1(";").token() + semicolon: code.s1(";").token(), }; let stmt = code.with_stream_no_diagnostics(parse_labeled_concurrent_statement); assert_eq!(stmt.label.tree, Some(code.s1("inst").ident())); @@ -1307,7 +1304,7 @@ with x(0) + 1 select unit: InstantiatedUnit::Entity(code.s1("lib.foo.bar").selected_name(), None), generic_map: None, port_map: None, - semicolon: code.s1(";").token() + semicolon: code.s1(";").token(), }; let stmt = code.with_stream_no_diagnostics(parse_labeled_concurrent_statement); assert_eq!(stmt.label.tree, Some(code.s1("inst").ident())); @@ -1359,16 +1356,18 @@ inst: component lib.foo.bar let inst = InstantiationStatement { unit: InstantiatedUnit::Component(code.s1("lib.foo.bar").selected_name()), - generic_map: Some(code - .s1("generic map ( + generic_map: Some( + code.s1("generic map ( const => 1 )") - .generic_map_aspect()), - port_map: Some(code - .s1("port map ( + .generic_map_aspect(), + ), + port_map: Some( + code.s1("port map ( clk => clk_foo )") - .port_map_aspect()), + .port_map_aspect(), + ), semicolon: code.s1(";").token(), }; let stmt = code.with_stream_no_diagnostics(parse_labeled_concurrent_statement); @@ -1395,12 +1394,13 @@ inst: lib.foo.bar let inst = InstantiationStatement { unit: InstantiatedUnit::Component(code.s1("lib.foo.bar").selected_name()), generic_map: None, - port_map: Some(code - .s1("port map ( + port_map: Some( + code.s1("port map ( clk => clk_foo )") - .port_map_aspect()), - semicolon: code.s1(";").token() + .port_map_aspect(), + ), + semicolon: code.s1(";").token(), }; let stmt = code.with_stream_no_diagnostics(parse_labeled_concurrent_statement); assert_eq!(stmt.label.tree, Some(code.s1("inst").ident())); @@ -1425,13 +1425,14 @@ inst: lib.foo.bar let inst = InstantiationStatement { unit: InstantiatedUnit::Component(code.s1("lib.foo.bar").selected_name()), - generic_map: Some(code - .s1("generic map ( + generic_map: Some( + code.s1("generic map ( const => 1 )") - .generic_map_aspect()), + .generic_map_aspect(), + ), port_map: None, - semicolon: code.s1(";").token() + semicolon: code.s1(";").token(), }; let stmt = code.with_stream_no_diagnostics(parse_labeled_concurrent_statement); assert_eq!(stmt.label.tree, Some(code.s1("inst").ident())); diff --git a/vhdl_lang/src/syntax/context.rs b/vhdl_lang/src/syntax/context.rs index b0866cb4..0382694c 100644 --- a/vhdl_lang/src/syntax/context.rs +++ b/vhdl_lang/src/syntax/context.rs @@ -96,10 +96,7 @@ pub fn parse_context( items.push(parse_name(stream)?); tokens.push(comma); } - let name_list = SeparatedList { - items, - tokens - }; + let name_list = SeparatedList { items, tokens }; let semi_token = stream.expect_kind(SemiColon)?; Ok(DeclarationOrReference::Reference(ContextReference { context_token, diff --git a/vhdl_lang/src/syntax/declarative_part.rs b/vhdl_lang/src/syntax/declarative_part.rs index e178f44f..fd06c7b8 100644 --- a/vhdl_lang/src/syntax/declarative_part.rs +++ b/vhdl_lang/src/syntax/declarative_part.rs @@ -10,7 +10,7 @@ use super::common::ParseResult; use super::component_declaration::parse_component_declaration; use super::configuration::parse_configuration_specification; use super::context::parse_use_clause; -use super::names::{parse_selected_name}; +use super::names::parse_selected_name; use super::object_declaration::{parse_file_declaration, parse_object_declaration}; use super::subprogram::parse_subprogram; use super::tokens::{Kind::*, *}; diff --git a/vhdl_lang/src/syntax/interface_declaration.rs b/vhdl_lang/src/syntax/interface_declaration.rs index 9f7c2f83..f961fa0a 100644 --- a/vhdl_lang/src/syntax/interface_declaration.rs +++ b/vhdl_lang/src/syntax/interface_declaration.rs @@ -203,7 +203,7 @@ fn parse_interface_package(stream: &TokenStream) -> ParseResult { let (list, _) = parse_association_list_no_leftpar(stream)?; InterfacePackageGenericMapAspect::Map(list) - }, + } } }; diff --git a/vhdl_lang/src/syntax/names.rs b/vhdl_lang/src/syntax/names.rs index 0ce187e8..538897d7 100644 --- a/vhdl_lang/src/syntax/names.rs +++ b/vhdl_lang/src/syntax/names.rs @@ -180,7 +180,9 @@ fn parse_association_element(stream: &TokenStream) -> ParseResult ParseResult<(SeparatedList, TokenId)> { +pub fn parse_association_list( + stream: &TokenStream, +) -> ParseResult<(SeparatedList, TokenId)> { stream.expect_kind(LeftPar)?; parse_association_list_no_leftpar(stream) } @@ -189,7 +191,10 @@ pub fn parse_association_list_no_leftpar( stream: &TokenStream, ) -> ParseResult<(SeparatedList, TokenId)> { if let Some(right_par) = stream.pop_if_kind(RightPar) { - return Err(Diagnostic::error(stream.get_pos(right_par), "Association list cannot be empty")); + return Err(Diagnostic::error( + stream.get_pos(right_par), + "Association list cannot be empty", + )); } let list = parse_list_with_separator(stream, Comma, parse_association_element)?; let comma = stream.expect_kind(RightPar)?; @@ -1016,10 +1021,16 @@ mod tests { formal: Some(code.s1("arg").name()), actual: WithPos::new(ActualPart::Open, code.s("open", 2)), }; - assert_eq!(code.with_stream(parse_association_list), (SeparatedList { - items: vec![elem1, elem2], - tokens: vec![code.s1(",").token()] - }, code.s1(")").token())); + assert_eq!( + code.with_stream(parse_association_list), + ( + SeparatedList { + items: vec![elem1, elem2], + tokens: vec![code.s1(",").token()] + }, + code.s1(")").token() + ) + ); } #[test] diff --git a/vhdl_lang/src/syntax/separated_list.rs b/vhdl_lang/src/syntax/separated_list.rs index 862e8021..fda669b3 100644 --- a/vhdl_lang/src/syntax/separated_list.rs +++ b/vhdl_lang/src/syntax/separated_list.rs @@ -70,7 +70,11 @@ mod test { assert_eq!( code.parse_ok(parse_ident_list), IdentList { - items: vec![code.s1("abc").ident().into_ref(), code.s1("def").ident().into_ref(), code.s1("ghi").ident().into_ref()], + items: vec![ + code.s1("abc").ident().into_ref(), + code.s1("def").ident().into_ref(), + code.s1("ghi").ident().into_ref() + ], tokens: vec![code.s(",", 1).token(), code.s(",", 2).token()] } ) diff --git a/vhdl_lang/src/syntax/test.rs b/vhdl_lang/src/syntax/test.rs index dd75210e..32a0945e 100644 --- a/vhdl_lang/src/syntax/test.rs +++ b/vhdl_lang/src/syntax/test.rs @@ -29,6 +29,7 @@ use crate::ast; use crate::ast::*; use crate::data::Range; use crate::data::*; +use crate::syntax::concurrent_statement::parse_map_aspect; use crate::syntax::context::{parse_context, DeclarationOrReference}; use crate::syntax::{TokenAccess, TokenId}; use std::collections::hash_map::DefaultHasher; @@ -37,7 +38,6 @@ use std::collections::HashMap; use std::fmt::Debug; use std::hash::Hasher; use std::sync::Arc; -use crate::syntax::concurrent_statement::parse_map_aspect; pub struct CodeBuilder { pub symbols: Arc, @@ -106,7 +106,7 @@ impl CodeBuilder { } } -impl SeparatedList { +impl SeparatedList { pub fn single(item: T) -> SeparatedList { SeparatedList { items: vec![item], @@ -518,11 +518,13 @@ impl Code { } pub fn port_map_aspect(&self) -> MapAspect { - self.parse_ok(|stream| parse_map_aspect(stream, Kind::Port)).expect("Expecting port map aspect") + self.parse_ok(|stream| parse_map_aspect(stream, Kind::Port)) + .expect("Expecting port map aspect") } pub fn generic_map_aspect(&self) -> MapAspect { - self.parse_ok(|stream| parse_map_aspect(stream, Kind::Generic)).expect("Expecting generic map aspect") + self.parse_ok(|stream| parse_map_aspect(stream, Kind::Generic)) + .expect("Expecting generic map aspect") } pub fn waveform(&self) -> Waveform { From 29a477c9127fdcc9ef0dbf3a509526163a2f7b2c Mon Sep 17 00:00:00 2001 From: Lukas Scheller Date: Sun, 8 Oct 2023 10:15:04 +0200 Subject: [PATCH 05/13] documentation; code quality --- vhdl_lang/src/analysis/completion.rs | 120 +++++++++++++-------------- vhdl_lang/src/ast.rs | 55 +++++++++++- vhdl_lang/src/data/source.rs | 4 + 3 files changed, 115 insertions(+), 64 deletions(-) diff --git a/vhdl_lang/src/analysis/completion.rs b/vhdl_lang/src/analysis/completion.rs index 85643662..3571e8a1 100644 --- a/vhdl_lang/src/analysis/completion.rs +++ b/vhdl_lang/src/analysis/completion.rs @@ -2,8 +2,8 @@ use crate::analysis::{DesignRoot, HasEntityId}; use crate::ast::search::{FoundDeclaration, SearchResult, SearchState, Searcher}; use crate::ast::visitor::{Visitor, VisitorResult}; use crate::ast::{ - AnyDesignUnit, AnyPrimaryUnit, Declaration, InstantiatedUnit, InstantiationStatement, - InterfaceDeclaration, MapAspect, Name, SelectedName, SubprogramDeclaration, UnitKey, + AnyDesignUnit, AnyPrimaryUnit, Declaration, InstantiationStatement, InterfaceDeclaration, + MapAspect, SubprogramDeclaration, UnitKey, }; use crate::data::{ContentReader, Symbol}; use crate::syntax::Kind::*; @@ -41,39 +41,50 @@ struct EntityPortAndGenericsExtractor<'a> { kind: MapAspectKind, } +impl DesignRoot { + fn extract_port_or_generic_names( + &self, + id: EntityId, + items: &mut Vec, + kind: MapAspectKind, + ) { + let mut searcher = EntityPortAndGenericsExtractor { id, items, kind }; + let _ = self.search(&mut searcher); + } +} + impl<'a> Searcher for EntityPortAndGenericsExtractor<'a> { fn search_decl(&mut self, _ctx: &dyn TokenAccess, decl: FoundDeclaration) -> SearchState { - if decl.ent_id() == Some(self.id) { - match decl { - FoundDeclaration::Entity(ent) => { - if ent.ident.decl != Some(self.id) { - return SearchState::NotFinished; - } - if self.kind == MapAspectKind::Port { - if let Some(ports) = &ent.port_clause { - for port in ports { - self.items.push(port.completable_name()) - } + if decl.ent_id() != Some(self.id) { + return SearchState::NotFinished; + } + match decl { + FoundDeclaration::Entity(ent) => { + if self.kind == MapAspectKind::Port { + if let Some(ports) = &ent.port_clause { + for port in ports { + self.items.push(port.completable_name()) } } - if self.kind == MapAspectKind::Generic { - if let Some(generics) = &ent.generic_clause { - for generic in generics { - self.items.push(generic.completable_name()) - } + } + if self.kind == MapAspectKind::Generic { + if let Some(generics) = &ent.generic_clause { + for generic in generics { + self.items.push(generic.completable_name()) } } - SearchState::Finished(SearchResult::Found) } - _ => SearchState::NotFinished, + SearchState::Finished(SearchResult::Found) } - } else { - SearchState::NotFinished + _ => SearchState::NotFinished, } } } impl InterfaceDeclaration { + /// Returns completable names for an interface declarations. + /// Example: + /// `signal my_signal : natural := 5` => `my_signal` fn completable_name(&self) -> String { match self { InterfaceDeclaration::Object(obj) => obj.ident.tree.to_string(), @@ -88,6 +99,7 @@ impl InterfaceDeclaration { } } +/// Visitor responsible for completions in selected AST elements struct AutocompletionVisitor<'a> { root: &'a DesignRoot, cursor: Position, @@ -95,66 +107,48 @@ struct AutocompletionVisitor<'a> { } impl<'a> AutocompletionVisitor<'a> { - fn get_ent(&self, node: &InstantiationStatement) -> Option { - match &node.unit { - InstantiatedUnit::Entity(name, _) => { - let Some(ent_id) = (match &name.item { - SelectedName::Designator(desi) => desi.reference, - SelectedName::Selected(_, desi) => desi.item.reference, - }) else { - return None; - }; - Some(ent_id) - } - _ => None, - } - } - fn process_map_aspect( + /// Loads completion options for the given map aspect. + /// Returns `true`, when the cursor is inside the map aspect and the search should not continue. + /// Returns `false` otherwise + fn load_completions_for_map_aspect( &mut self, node: &InstantiationStatement, map: &MapAspect, ctx: &dyn TokenAccess, kind: MapAspectKind, - ) { - if ctx - .get_span(map.start, map.closing_paren) - .range() - .contains(self.cursor) - { - let items_in_node: HashSet = - HashSet::from_iter(map.list.items.iter().filter_map(|el| match &el.formal { - None => None, - Some(name) => match &name.item { - Name::Designator(desi) => Some(desi.item.to_string().to_lowercase()), - _ => None, - }, - })); - if let Some(ent) = self.get_ent(node) { - let mut searcher = EntityPortAndGenericsExtractor { - id: ent, - items: self.completions, - kind, - }; - let _ = self.root.search(&mut searcher); - self.completions - .retain(|name| !items_in_node.contains(&name.to_lowercase())); - } + ) -> bool { + if !map.span(ctx).contains(self.cursor) { + return false; + } + let formals_in_map: HashSet = + HashSet::from_iter(map.formals().map(|name| name.to_string().to_lowercase())); + if let Some(ent) = node.entity_reference() { + self.root + .extract_port_or_generic_names(ent, self.completions, kind); + self.completions + .retain(|name| !formals_in_map.contains(&name.to_lowercase())); } + true } } impl<'a> Visitor for AutocompletionVisitor<'a> { + /// Visit an instantiation statement extracting completions for ports or generics. fn visit_instantiation_statement( &mut self, node: &InstantiationStatement, ctx: &dyn TokenAccess, ) -> VisitorResult { if let Some(map) = &node.generic_map { - self.process_map_aspect(node, map, ctx, MapAspectKind::Generic) + if self.load_completions_for_map_aspect(node, map, ctx, MapAspectKind::Generic) { + return VisitorResult::Stop; + } } if let Some(map) = &node.port_map { - self.process_map_aspect(node, map, ctx, MapAspectKind::Port) + if self.load_completions_for_map_aspect(node, map, ctx, MapAspectKind::Port) { + return VisitorResult::Stop; + } } VisitorResult::Skip } diff --git a/vhdl_lang/src/ast.rs b/vhdl_lang/src/ast.rs index bf4d55d1..cf2aa63a 100644 --- a/vhdl_lang/src/ast.rs +++ b/vhdl_lang/src/ast.rs @@ -25,7 +25,7 @@ pub(crate) use any_design_unit::*; use crate::analysis::EntityId; use crate::data::*; -use crate::syntax::{Token, TokenId}; +use crate::syntax::{Token, TokenAccess, TokenId}; /// LRM 15.8 Bit string literals #[derive(PartialEq, Eq, Copy, Clone, Debug)] @@ -204,6 +204,16 @@ pub enum SelectedName { Selected(Box>, WithPos>), } +impl SelectedName { + /// Returns the reference that this name selects + pub fn reference(&self) -> Reference { + match &self { + SelectedName::Designator(desi) => desi.reference, + SelectedName::Selected(_, desi) => desi.item.reference, + } + } +} + /// LRM 9.3.4 Function calls #[derive(PartialEq, Debug, Clone)] pub struct CallOrIndexed { @@ -1022,6 +1032,17 @@ pub enum InstantiatedUnit { Configuration(WithPos), } +impl InstantiatedUnit { + /// Returns a reference to the unit that this instantiation declares + pub fn entity_reference(&self) -> Reference { + match &self { + InstantiatedUnit::Entity(name, _) => name.item.reference(), + InstantiatedUnit::Configuration(name) => name.item.reference(), + InstantiatedUnit::Component(name) => name.item.reference(), + } + } +} + #[derive(PartialEq, Debug, Clone)] pub struct MapAspect { pub start: TokenId, // `generic` or `map` @@ -1029,6 +1050,18 @@ pub struct MapAspect { pub closing_paren: TokenId, } +impl MapAspect { + /// Returns an iterator over the formal elements of this map + pub fn formals(&self) -> impl Iterator { + self.list.formals() + } + + /// Returns the span that this aspect encompasses + pub fn span(&self, ctx: &dyn TokenAccess) -> SrcPos { + ctx.get_span(self.start, self.closing_paren) + } +} + /// 11.7 Component instantiation statements #[derive(PartialEq, Debug, Clone)] pub struct InstantiationStatement { @@ -1038,6 +1071,13 @@ pub struct InstantiationStatement { pub semicolon: TokenId, } +impl InstantiationStatement { + /// Returns the reference to the entity declaring this instance + pub fn entity_reference(&self) -> Reference { + self.unit.entity_reference() + } +} + /// 11.8 Generate statements #[derive(PartialEq, Debug, Clone)] pub struct GenerateBody { @@ -1104,6 +1144,19 @@ pub struct SeparatedList { pub tokens: Vec, } +impl SeparatedList { + /// Returns an iterator over the formal elements of this list + pub fn formals(&self) -> impl Iterator { + self.items.iter().filter_map(|el| match &el.formal { + None => None, + Some(name) => match &name.item { + Name::Designator(desi) => Some(&desi.item), + _ => None, + }, + }) + } +} + pub type IdentList = SeparatedList>; pub type NameList = SeparatedList>; diff --git a/vhdl_lang/src/data/source.rs b/vhdl_lang/src/data/source.rs index f6ba18ef..7ad3db15 100644 --- a/vhdl_lang/src/data/source.rs +++ b/vhdl_lang/src/data/source.rs @@ -541,6 +541,10 @@ impl SrcPos { pub fn combine(&self, other: &dyn AsRef) -> Self { self.clone().combine_into(other) } + + pub fn contains(&self, pos: Position) -> bool { + self.range.contains(pos) + } } /// Denotes an item with an associated source file. From 26552a7557a6c03d4b108dec9b066b80bebf077a Mon Sep 17 00:00:00 2001 From: Lukas Scheller Date: Sun, 8 Oct 2023 11:49:36 +0200 Subject: [PATCH 06/13] replace searcher with visitor --- vhdl_lang/src/analysis/completion.rs | 170 +++++++++++++++++++++------ 1 file changed, 137 insertions(+), 33 deletions(-) diff --git a/vhdl_lang/src/analysis/completion.rs b/vhdl_lang/src/analysis/completion.rs index 3571e8a1..9273fd97 100644 --- a/vhdl_lang/src/analysis/completion.rs +++ b/vhdl_lang/src/analysis/completion.rs @@ -1,11 +1,7 @@ -use crate::analysis::{DesignRoot, HasEntityId}; -use crate::ast::search::{FoundDeclaration, SearchResult, SearchState, Searcher}; +use crate::analysis::{DesignRoot}; use crate::ast::visitor::{Visitor, VisitorResult}; -use crate::ast::{ - AnyDesignUnit, AnyPrimaryUnit, Declaration, InstantiationStatement, InterfaceDeclaration, - MapAspect, SubprogramDeclaration, UnitKey, -}; -use crate::data::{ContentReader, Symbol}; +use crate::ast::{AnyDesignUnit, AnyPrimaryUnit, AnySecondaryUnit, ComponentDeclaration, Declaration, EntityDeclaration, InstantiationStatement, InterfaceDeclaration, MapAspect, PackageDeclaration, SubprogramDeclaration, UnitKey}; +use crate::data::{ContentReader, HasSource, Symbol}; use crate::syntax::Kind::*; use crate::syntax::{Symbols, Token, TokenAccess, Tokenizer, Value}; use crate::{EntityId, Position, Source}; @@ -35,49 +31,90 @@ enum MapAspectKind { Generic, } -struct EntityPortAndGenericsExtractor<'a> { +struct PortAndGenericsExtractor<'a> { id: EntityId, items: &'a mut Vec, kind: MapAspectKind, + source: &'a Source, } impl DesignRoot { fn extract_port_or_generic_names( &self, + source: &Source, id: EntityId, items: &mut Vec, kind: MapAspectKind, ) { - let mut searcher = EntityPortAndGenericsExtractor { id, items, kind }; - let _ = self.search(&mut searcher); + let mut searcher = PortAndGenericsExtractor { + id, + items, + kind, + source, + }; + self.walk(&mut searcher); } } -impl<'a> Searcher for EntityPortAndGenericsExtractor<'a> { - fn search_decl(&mut self, _ctx: &dyn TokenAccess, decl: FoundDeclaration) -> SearchState { - if decl.ent_id() != Some(self.id) { - return SearchState::NotFinished; +impl<'a> Visitor for PortAndGenericsExtractor<'a> { + fn visit_entity_declaration( + &mut self, + node: &EntityDeclaration, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + if node.ident.decl != Some(self.id) { + return VisitorResult::Skip; + } + if self.kind == MapAspectKind::Port { + if let Some(ports) = &node.port_clause { + for port in ports { + self.items.push(port.completable_name()) + } + } } - match decl { - FoundDeclaration::Entity(ent) => { - if self.kind == MapAspectKind::Port { - if let Some(ports) = &ent.port_clause { - for port in ports { - self.items.push(port.completable_name()) - } - } + if self.kind == MapAspectKind::Generic { + if let Some(generics) = &node.generic_clause { + for generic in generics { + self.items.push(generic.completable_name()) } - if self.kind == MapAspectKind::Generic { - if let Some(generics) = &ent.generic_clause { - for generic in generics { - self.items.push(generic.completable_name()) - } - } + } + } + VisitorResult::Stop + } + + fn visit_component_declaration( + &mut self, + node: &ComponentDeclaration, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + if node.ident.decl != Some(self.id) { + return VisitorResult::Skip; + } + if self.kind == MapAspectKind::Port { + for port in &node.port_list { + self.items.push(port.completable_name()) + } + } + if self.kind == MapAspectKind::Generic { + for generic in &node.generic_list { + self.items.push(generic.completable_name()) + } + } + VisitorResult::Stop + } + + fn visit_package_declaration(&mut self, node: &PackageDeclaration, _ctx: &dyn TokenAccess) -> VisitorResult { + if node.ident.decl != Some(self.id) { + return VisitorResult::Skip; + } + if self.kind == MapAspectKind::Generic { + if let Some(generics) = &node.generic_clause { + for generic in generics { + self.items.push(generic.completable_name()) } - SearchState::Finished(SearchResult::Found) } - _ => SearchState::NotFinished, } + VisitorResult::Stop } } @@ -107,7 +144,6 @@ struct AutocompletionVisitor<'a> { } impl<'a> AutocompletionVisitor<'a> { - /// Loads completion options for the given map aspect. /// Returns `true`, when the cursor is inside the map aspect and the search should not continue. /// Returns `false` otherwise @@ -124,8 +160,12 @@ impl<'a> AutocompletionVisitor<'a> { let formals_in_map: HashSet = HashSet::from_iter(map.formals().map(|name| name.to_string().to_lowercase())); if let Some(ent) = node.entity_reference() { - self.root - .extract_port_or_generic_names(ent, self.completions, kind); + self.root.extract_port_or_generic_names( + ctx.get_pos(map.start).source(), + ent, + self.completions, + kind, + ); self.completions .retain(|name| !formals_in_map.contains(&name.to_lowercase())); } @@ -152,6 +192,27 @@ impl<'a> Visitor for AutocompletionVisitor<'a> { } VisitorResult::Skip } + + // preliminary optimizations: only visit architecture + fn visit_any_primary_unit( + &mut self, + _node: &AnyPrimaryUnit, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + VisitorResult::Skip + } + + // preliminary optimizations: only visit architecture + fn visit_any_secondary_unit( + &mut self, + node: &AnySecondaryUnit, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { + match node { + AnySecondaryUnit::Architecture(_) => VisitorResult::Continue, + AnySecondaryUnit::PackageBody(_) => VisitorResult::Skip, + } + } } /// Returns the completable string representation of a declaration @@ -383,4 +444,47 @@ mod test { let options = root.list_completion_options(code.source(), cursor); assert_eq!(options, vec!["stop", "finish", "resolution_limit", "all"]) } + + #[test] + pub fn completing_instantiation_statement() { + let mut input = LibraryBuilder::new(); + let code = input.code( + "libname", + "\ +entity my_ent is +end entity my_ent; + +architecture arch of my_ent is + component comp is + generic ( + A: natural := 5; + B: integer + ); + port ( + clk : in bit; + rst : in bit; + dout : out bit + ); + end component comp; + signal clk, rst: bit; +begin + comp_inst: comp + generic map ( + A => 2 + ) + port map ( + clk => clk + ); +end arch; + ", + ); + let (root, _) = input.get_analyzed_root(); + let cursor = code.s1("generic map (").pos().end(); + let options = root.list_completion_options(code.source(), cursor); + assert_eq!(options, vec!["B"]); + + let cursor = code.s1("port map (").pos().end(); + let options = root.list_completion_options(code.source(), cursor); + assert_eq!(options, vec!["rst", "dout"]); + } } From b3375af5c9fac20ad69d94836bc20575d0fba8f2 Mon Sep 17 00:00:00 2001 From: Lukas Scheller Date: Sun, 8 Oct 2023 11:53:37 +0200 Subject: [PATCH 07/13] Rename PortAndGenericsExtractor to PortsOrGenericsExtractor --- vhdl_lang/src/analysis/completion.rs | 48 ++++++++++++++-------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/vhdl_lang/src/analysis/completion.rs b/vhdl_lang/src/analysis/completion.rs index 9273fd97..d46c327f 100644 --- a/vhdl_lang/src/analysis/completion.rs +++ b/vhdl_lang/src/analysis/completion.rs @@ -31,73 +31,74 @@ enum MapAspectKind { Generic, } -struct PortAndGenericsExtractor<'a> { +/// Extracts the name of ports or generics from an AST for an entity with a certain ID. +/// The entity can be an `Entity`, `Component` or `Package`. +/// After walking the AST, the ports or generics are written to the `items` vector. +/// The `kind` member chooses whether to select ports or generics. +struct PortsOrGenericsExtractor<'a> { id: EntityId, items: &'a mut Vec, - kind: MapAspectKind, - source: &'a Source, + kind: MapAspectKind } impl DesignRoot { fn extract_port_or_generic_names( &self, - source: &Source, id: EntityId, items: &mut Vec, kind: MapAspectKind, ) { - let mut searcher = PortAndGenericsExtractor { + let mut searcher = PortsOrGenericsExtractor { id, items, kind, - source, }; self.walk(&mut searcher); } } -impl<'a> Visitor for PortAndGenericsExtractor<'a> { - fn visit_entity_declaration( +impl<'a> Visitor for PortsOrGenericsExtractor<'a> { + fn visit_component_declaration( &mut self, - node: &EntityDeclaration, + node: &ComponentDeclaration, _ctx: &dyn TokenAccess, ) -> VisitorResult { if node.ident.decl != Some(self.id) { return VisitorResult::Skip; } if self.kind == MapAspectKind::Port { - if let Some(ports) = &node.port_clause { - for port in ports { - self.items.push(port.completable_name()) - } + for port in &node.port_list { + self.items.push(port.completable_name()) } } if self.kind == MapAspectKind::Generic { - if let Some(generics) = &node.generic_clause { - for generic in generics { - self.items.push(generic.completable_name()) - } + for generic in &node.generic_list { + self.items.push(generic.completable_name()) } } VisitorResult::Stop } - fn visit_component_declaration( + fn visit_entity_declaration( &mut self, - node: &ComponentDeclaration, + node: &EntityDeclaration, _ctx: &dyn TokenAccess, ) -> VisitorResult { if node.ident.decl != Some(self.id) { return VisitorResult::Skip; } if self.kind == MapAspectKind::Port { - for port in &node.port_list { - self.items.push(port.completable_name()) + if let Some(ports) = &node.port_clause { + for port in ports { + self.items.push(port.completable_name()) + } } } if self.kind == MapAspectKind::Generic { - for generic in &node.generic_list { - self.items.push(generic.completable_name()) + if let Some(generics) = &node.generic_clause { + for generic in generics { + self.items.push(generic.completable_name()) + } } } VisitorResult::Stop @@ -161,7 +162,6 @@ impl<'a> AutocompletionVisitor<'a> { HashSet::from_iter(map.formals().map(|name| name.to_string().to_lowercase())); if let Some(ent) = node.entity_reference() { self.root.extract_port_or_generic_names( - ctx.get_pos(map.start).source(), ent, self.completions, kind, From 5e3afc4aab4ba2378cedc6577936bc7a2a55fb94 Mon Sep 17 00:00:00 2001 From: Lukas Scheller Date: Sun, 8 Oct 2023 11:54:51 +0200 Subject: [PATCH 08/13] clippy; fmt --- vhdl_lang/src/analysis/completion.rs | 31 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/vhdl_lang/src/analysis/completion.rs b/vhdl_lang/src/analysis/completion.rs index d46c327f..d4237e0d 100644 --- a/vhdl_lang/src/analysis/completion.rs +++ b/vhdl_lang/src/analysis/completion.rs @@ -1,7 +1,11 @@ -use crate::analysis::{DesignRoot}; +use crate::analysis::DesignRoot; use crate::ast::visitor::{Visitor, VisitorResult}; -use crate::ast::{AnyDesignUnit, AnyPrimaryUnit, AnySecondaryUnit, ComponentDeclaration, Declaration, EntityDeclaration, InstantiationStatement, InterfaceDeclaration, MapAspect, PackageDeclaration, SubprogramDeclaration, UnitKey}; -use crate::data::{ContentReader, HasSource, Symbol}; +use crate::ast::{ + AnyDesignUnit, AnyPrimaryUnit, AnySecondaryUnit, ComponentDeclaration, Declaration, + EntityDeclaration, InstantiationStatement, InterfaceDeclaration, MapAspect, PackageDeclaration, + SubprogramDeclaration, UnitKey, +}; +use crate::data::{ContentReader, Symbol}; use crate::syntax::Kind::*; use crate::syntax::{Symbols, Token, TokenAccess, Tokenizer, Value}; use crate::{EntityId, Position, Source}; @@ -38,7 +42,7 @@ enum MapAspectKind { struct PortsOrGenericsExtractor<'a> { id: EntityId, items: &'a mut Vec, - kind: MapAspectKind + kind: MapAspectKind, } impl DesignRoot { @@ -48,11 +52,7 @@ impl DesignRoot { items: &mut Vec, kind: MapAspectKind, ) { - let mut searcher = PortsOrGenericsExtractor { - id, - items, - kind, - }; + let mut searcher = PortsOrGenericsExtractor { id, items, kind }; self.walk(&mut searcher); } } @@ -104,7 +104,11 @@ impl<'a> Visitor for PortsOrGenericsExtractor<'a> { VisitorResult::Stop } - fn visit_package_declaration(&mut self, node: &PackageDeclaration, _ctx: &dyn TokenAccess) -> VisitorResult { + fn visit_package_declaration( + &mut self, + node: &PackageDeclaration, + _ctx: &dyn TokenAccess, + ) -> VisitorResult { if node.ident.decl != Some(self.id) { return VisitorResult::Skip; } @@ -161,11 +165,8 @@ impl<'a> AutocompletionVisitor<'a> { let formals_in_map: HashSet = HashSet::from_iter(map.formals().map(|name| name.to_string().to_lowercase())); if let Some(ent) = node.entity_reference() { - self.root.extract_port_or_generic_names( - ent, - self.completions, - kind, - ); + self.root + .extract_port_or_generic_names(ent, self.completions, kind); self.completions .retain(|name| !formals_in_map.contains(&name.to_lowercase())); } From d156a5a303c38a220be1323ce30d738c2db7b5d5 Mon Sep 17 00:00:00 2001 From: Lukas Scheller Date: Sun, 8 Oct 2023 12:26:03 +0200 Subject: [PATCH 09/13] rustup --- vhdl_lang/src/analysis/named_entity.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vhdl_lang/src/analysis/named_entity.rs b/vhdl_lang/src/analysis/named_entity.rs index 364f14ab..8bc03ac5 100644 --- a/vhdl_lang/src/analysis/named_entity.rs +++ b/vhdl_lang/src/analysis/named_entity.rs @@ -411,8 +411,9 @@ impl<'a> AnyEnt<'a> { #[allow(clippy::mut_from_ref)] unsafe fn unsafe_ref_mut(&self) -> &mut Self { // NOTE: Use read_volatile to prevent compiler to optimization away assignment to the returned reference - let mut_self: *mut AnyEnt = std::ptr::read_volatile(&self) as *const AnyEnt as *mut AnyEnt; - &mut *mut_self + let const_ptr = std::ptr::read_volatile(&self) as *const Self; + let mut_ptr = const_ptr as *mut Self; + &mut *mut_ptr } // Used to update the kind of pre-declared symbols that are visible before they have been fully analyzed From b76e97cc25240609219c76ec9d277c8995eb6fc2 Mon Sep 17 00:00:00 2001 From: Lukas Scheller Date: Sun, 8 Oct 2023 12:35:30 +0200 Subject: [PATCH 10/13] doc --- vhdl_lang/src/ast/visitor.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/vhdl_lang/src/ast/visitor.rs b/vhdl_lang/src/ast/visitor.rs index 75a037c1..f12d2d61 100644 --- a/vhdl_lang/src/ast/visitor.rs +++ b/vhdl_lang/src/ast/visitor.rs @@ -10,6 +10,7 @@ use crate::ast::*; use crate::syntax::TokenAccess; use itertools::Itertools; use std::ops::Deref; +use std::os::unix::raw::time_t; #[derive(PartialEq)] pub enum VisitorResult { @@ -801,11 +802,18 @@ pub trait Visitor { /// An AST Node has two methods it needs to declare: /// - A `visit(Visitor, Context)` method. /// - A `children()` method. -/// -/// The `visit` method pub trait ASTNode { + + /// Called when traversing the AST. + /// Each node must call the respective method in the `Visitor` class. + /// If the node doesn't have a representation + /// (for example, for utility types such as `Box` or `Vec`), + /// simply return `Continue`. fn visit(&self, visitor: &mut dyn Visitor, _ctx: &dyn TokenAccess) -> VisitorResult; + /// Returns the Children of this Node. + /// Must return all children that are considered AST elements. + /// Doesn't return auxiliary information such as the Tokens. fn children(&self) -> Vec<&dyn ASTNode>; } From c837b7f92aa2075bca0b78b5f0273397437338fc Mon Sep 17 00:00:00 2001 From: Lukas Scheller Date: Sun, 8 Oct 2023 12:37:18 +0200 Subject: [PATCH 11/13] remove unused import --- vhdl_lang/src/ast/visitor.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/vhdl_lang/src/ast/visitor.rs b/vhdl_lang/src/ast/visitor.rs index f12d2d61..aa7a0b8b 100644 --- a/vhdl_lang/src/ast/visitor.rs +++ b/vhdl_lang/src/ast/visitor.rs @@ -10,7 +10,6 @@ use crate::ast::*; use crate::syntax::TokenAccess; use itertools::Itertools; use std::ops::Deref; -use std::os::unix::raw::time_t; #[derive(PartialEq)] pub enum VisitorResult { From e9a6fecfccbb19d4180f1a7ea964d9a4fd60d8a6 Mon Sep 17 00:00:00 2001 From: Lukas Scheller Date: Sun, 8 Oct 2023 12:40:14 +0200 Subject: [PATCH 12/13] rustup 2 --- vhdl_lang/src/ast/visitor.rs | 1 - vhdl_lang/src/syntax/expression.rs | 2 +- vhdl_lang/src/syntax/range.rs | 12 ++++++------ 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/vhdl_lang/src/ast/visitor.rs b/vhdl_lang/src/ast/visitor.rs index aa7a0b8b..7c00ea85 100644 --- a/vhdl_lang/src/ast/visitor.rs +++ b/vhdl_lang/src/ast/visitor.rs @@ -802,7 +802,6 @@ pub trait Visitor { /// - A `visit(Visitor, Context)` method. /// - A `children()` method. pub trait ASTNode { - /// Called when traversing the AST. /// Each node must call the respective method in the `Visitor` class. /// If the node doesn't have a representation diff --git a/vhdl_lang/src/syntax/expression.rs b/vhdl_lang/src/syntax/expression.rs index 2674b4ad..49954660 100644 --- a/vhdl_lang/src/syntax/expression.rs +++ b/vhdl_lang/src/syntax/expression.rs @@ -1056,7 +1056,7 @@ mod tests { pos: code.s1("2").pos(), }; - let range = DiscreteRange::Range(Range::Range(RangeConstraint { + let range = DiscreteRange::Range(ast::Range::Range(RangeConstraint { direction: *direction, left_expr: Box::new(one_expr), right_expr: Box::new(zero_expr), diff --git a/vhdl_lang/src/syntax/range.rs b/vhdl_lang/src/syntax/range.rs index 376e5e17..5a340023 100644 --- a/vhdl_lang/src/syntax/range.rs +++ b/vhdl_lang/src/syntax/range.rs @@ -127,7 +127,7 @@ mod tests { assert_eq!( code.with_stream(parse_range), WithPos::new( - Range::Range(RangeConstraint { + ast::Range::Range(RangeConstraint { direction: Direction::Ascending, left_expr: Box::new(code.s1("foo.bar").expr()), right_expr: Box::new(code.s1("1").expr()) @@ -143,7 +143,7 @@ mod tests { assert_eq!( code.with_stream(parse_range), WithPos::new( - Range::Attribute(Box::new(code.s1("foo.bar'range").attribute_name())), + ast::Range::Attribute(Box::new(code.s1("foo.bar'range").attribute_name())), code.pos() ) ); @@ -155,7 +155,7 @@ mod tests { assert_eq!( code.with_stream(parse_range), WithPos::new( - Range::Attribute(Box::new(code.s1("foo.bar'reverse_range").attribute_name())), + ast::Range::Attribute(Box::new(code.s1("foo.bar'reverse_range").attribute_name())), code.pos() ) ); @@ -167,7 +167,7 @@ mod tests { assert_eq!( code.with_stream(parse_range), WithPos::new( - Range::Range(RangeConstraint { + ast::Range::Range(RangeConstraint { direction: Direction::Descending, left_expr: Box::new(code.s1("foo.bar'length").expr()), right_expr: Box::new(code.s1("0").expr()) @@ -182,7 +182,7 @@ mod tests { let code = Code::new("foo.bar to 1"); assert_eq!( code.with_stream(parse_discrete_range), - DiscreteRange::Range(Range::Range(RangeConstraint { + DiscreteRange::Range(ast::Range::Range(RangeConstraint { direction: Direction::Ascending, left_expr: Box::new(code.s1("foo.bar").expr()), right_expr: Box::new(code.s1("1").expr()) @@ -195,7 +195,7 @@ mod tests { let code = Code::new("foo.bar'range"); assert_eq!( code.with_stream(parse_discrete_range), - DiscreteRange::Range(Range::Attribute(Box::new( + DiscreteRange::Range(ast::Range::Attribute(Box::new( code.s1("foo.bar'range").attribute_name() ))) ); From cee7a286b0e875d011cf5df3d08cc313ee6a6827 Mon Sep 17 00:00:00 2001 From: Lukas Scheller Date: Sun, 8 Oct 2023 21:44:16 +0200 Subject: [PATCH 13/13] Correct issues from rebase --- vhdl_lang/src/ast.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/vhdl_lang/src/ast.rs b/vhdl_lang/src/ast.rs index 5d31b989..cf2aa63a 100644 --- a/vhdl_lang/src/ast.rs +++ b/vhdl_lang/src/ast.rs @@ -17,6 +17,7 @@ mod any_design_unit; #[macro_use] pub mod search; +pub mod visitor; pub use self::display::*; pub(crate) use self::util::*; @@ -203,6 +204,16 @@ pub enum SelectedName { Selected(Box>, WithPos>), } +impl SelectedName { + /// Returns the reference that this name selects + pub fn reference(&self) -> Reference { + match &self { + SelectedName::Designator(desi) => desi.reference, + SelectedName::Selected(_, desi) => desi.item.reference, + } + } +} + /// LRM 9.3.4 Function calls #[derive(PartialEq, Debug, Clone)] pub struct CallOrIndexed { @@ -1021,6 +1032,17 @@ pub enum InstantiatedUnit { Configuration(WithPos), } +impl InstantiatedUnit { + /// Returns a reference to the unit that this instantiation declares + pub fn entity_reference(&self) -> Reference { + match &self { + InstantiatedUnit::Entity(name, _) => name.item.reference(), + InstantiatedUnit::Configuration(name) => name.item.reference(), + InstantiatedUnit::Component(name) => name.item.reference(), + } + } +} + #[derive(PartialEq, Debug, Clone)] pub struct MapAspect { pub start: TokenId, // `generic` or `map` @@ -1049,6 +1071,13 @@ pub struct InstantiationStatement { pub semicolon: TokenId, } +impl InstantiationStatement { + /// Returns the reference to the entity declaring this instance + pub fn entity_reference(&self) -> Reference { + self.unit.entity_reference() + } +} + /// 11.8 Generate statements #[derive(PartialEq, Debug, Clone)] pub struct GenerateBody {