Skip to main content

vhdl_parser/analysis/
region.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this file,
3// You can obtain one at http://mozilla.org/MPL/2.0/.
4//
5// Copyright (c) 2018, Olof Kraigher olof.kraigher@gmail.com
6use crate::ast::*;
7use crate::data::*;
8
9use fnv::{FnvHashMap, FnvHashSet};
10use std::collections::hash_map::Entry;
11use std::sync::Arc;
12
13#[derive(Clone)]
14pub enum NamedEntityKind {
15    AliasOf(Box<NamedEntityKind>),
16    Other,
17    Overloaded,
18    // An optional region with implicit declarations
19    TypeDeclaration(Option<Arc<Region<'static>>>),
20    IncompleteType,
21    Constant,
22    DeferredConstant,
23    // The region of the protected type which needs to be extendend by the body
24    ProtectedType(Arc<Region<'static>>),
25    Library(Symbol),
26    Entity(UnitId, Arc<Region<'static>>),
27    Configuration(UnitId, Arc<Region<'static>>),
28    Package(UnitId, Arc<Region<'static>>),
29    UninstPackage(UnitId, Arc<Region<'static>>),
30    PackageInstance(UnitId, Arc<Region<'static>>),
31    Context(UnitId, Arc<Region<'static>>),
32    LocalPackageInstance(Symbol, Arc<Region<'static>>),
33}
34
35impl NamedEntityKind {
36    pub fn from_object_declaration(decl: &ObjectDeclaration) -> NamedEntityKind {
37        match decl {
38            ObjectDeclaration {
39                class: ObjectClass::Constant,
40                ref expression,
41                ..
42            } => {
43                if expression.is_none() {
44                    NamedEntityKind::DeferredConstant
45                } else {
46                    NamedEntityKind::Constant
47                }
48            }
49            _ => NamedEntityKind::Other,
50        }
51    }
52
53    fn is_deferred_constant(&self) -> bool {
54        if let NamedEntityKind::DeferredConstant = self {
55            true
56        } else {
57            false
58        }
59    }
60
61    fn is_non_deferred_constant(&self) -> bool {
62        if let NamedEntityKind::Constant = self {
63            true
64        } else {
65            false
66        }
67    }
68
69    fn is_protected_type(&self) -> bool {
70        if let NamedEntityKind::ProtectedType(..) = self {
71            true
72        } else {
73            false
74        }
75    }
76
77    fn is_incomplete_type(&self) -> bool {
78        if let NamedEntityKind::IncompleteType = self {
79            true
80        } else {
81            false
82        }
83    }
84
85    fn is_type_declaration(&self) -> bool {
86        if let NamedEntityKind::TypeDeclaration(..) = self {
87            true
88        } else {
89            false
90        }
91    }
92}
93
94#[derive(Clone)]
95pub struct NamedEntity {
96    /// The location where the declaration was made
97    /// Builtin and implicit declaration will not have a source position
98    decl_pos: Option<SrcPos>,
99    kind: NamedEntityKind,
100}
101
102impl NamedEntity {
103    pub fn new(kind: NamedEntityKind, decl_pos: Option<&SrcPos>) -> NamedEntity {
104        NamedEntity {
105            kind,
106            decl_pos: decl_pos.cloned(),
107        }
108    }
109
110    pub fn decl_pos(&self) -> Option<&SrcPos> {
111        self.decl_pos.as_ref()
112    }
113
114    pub fn kind(&self) -> &NamedEntityKind {
115        &self.kind
116    }
117
118    fn error(&self, diagnostics: &mut dyn DiagnosticHandler, message: impl Into<String>) {
119        if let Some(ref pos) = self.decl_pos {
120            diagnostics.push(Diagnostic::error(pos, message));
121        }
122    }
123
124    fn hint(&self, diagnostics: &mut dyn DiagnosticHandler, message: impl Into<String>) {
125        if let Some(ref pos) = self.decl_pos {
126            diagnostics.push(Diagnostic::hint(pos, message));
127        }
128    }
129
130    fn is_overloaded(&self) -> bool {
131        if let NamedEntityKind::Overloaded = self.kind {
132            true
133        } else {
134            false
135        }
136    }
137
138    /// Return a duplicate declaration of the previously declared named entity
139    fn is_duplicate_of<'a>(&self, prev: &'a Self) -> bool {
140        if self.is_overloaded() && prev.is_overloaded() {
141            return false;
142        }
143
144        match prev.kind {
145            // Everything expect deferred combinations are forbidden
146            NamedEntityKind::DeferredConstant if self.kind.is_non_deferred_constant() => {}
147            NamedEntityKind::IncompleteType if self.kind.is_type_declaration() => {}
148            _ => {
149                return true;
150            }
151        }
152
153        false
154    }
155}
156
157#[derive(Clone)]
158pub struct VisibleDeclaration {
159    designator: Designator,
160    named_entities: Vec<NamedEntity>,
161}
162
163impl VisibleDeclaration {
164    pub fn new(designator: Designator, named_entity: NamedEntity) -> VisibleDeclaration {
165        VisibleDeclaration {
166            designator,
167            named_entities: vec![named_entity],
168        }
169    }
170
171    /// Return single named entity if unique name is visible
172    pub fn as_unique(&self) -> Option<&NamedEntity> {
173        if self.named_entities.len() == 1 {
174            self.named_entities.first()
175        } else {
176            None
177        }
178    }
179
180    pub fn to_unique(mut self) -> Option<NamedEntity> {
181        if self.named_entities.len() == 1 {
182            self.named_entities.pop()
183        } else {
184            None
185        }
186    }
187
188    fn first(&self) -> &NamedEntity {
189        self.named_entities
190            .first()
191            .expect("Declaration always contains one entry")
192    }
193
194    pub fn first_kind(&self) -> &NamedEntityKind {
195        &self.first().kind
196    }
197
198    pub fn first_pos(&self) -> Option<&SrcPos> {
199        self.first().decl_pos.as_ref()
200    }
201
202    fn second(&self) -> Option<&NamedEntityKind> {
203        self.named_entities.get(1).map(|ent| &ent.kind)
204    }
205
206    fn named_entities(&self) -> impl Iterator<Item = &NamedEntity> {
207        self.named_entities.iter()
208    }
209
210    fn is_overloaded(&self) -> bool {
211        self.first().is_overloaded()
212    }
213
214    fn push(&mut self, ent: NamedEntity) {
215        self.named_entities.push(ent);
216    }
217
218    pub fn make_potentially_visible_in(&self, region: &mut Region<'_>) {
219        for ent in self.named_entities.iter() {
220            region.make_potentially_visible(self.designator.clone(), ent.clone());
221        }
222    }
223}
224#[derive(Copy, Clone, PartialEq)]
225#[cfg_attr(test, derive(Debug))]
226enum RegionKind {
227    PackageDeclaration,
228    PackageBody,
229    Other,
230}
231
232impl Default for RegionKind {
233    fn default() -> RegionKind {
234        RegionKind::Other
235    }
236}
237
238#[derive(Clone, Default)]
239pub struct Region<'a> {
240    parent: Option<&'a Region<'a>>,
241    extends: Option<&'a Region<'a>>,
242    hidden: FnvHashSet<Designator>,
243    visible: FnvHashMap<Designator, VisibleDeclaration>,
244    decls: FnvHashMap<Designator, VisibleDeclaration>,
245    protected_bodies: FnvHashMap<Symbol, SrcPos>,
246    kind: RegionKind,
247}
248
249impl<'a> Region<'a> {
250    pub fn default() -> Region<'static> {
251        Region {
252            parent: None,
253            extends: None,
254            hidden: FnvHashSet::default(),
255            visible: FnvHashMap::default(),
256            decls: FnvHashMap::default(),
257            protected_bodies: FnvHashMap::default(),
258            kind: RegionKind::Other,
259        }
260    }
261
262    pub fn nested(&'a self) -> Region<'a> {
263        Region {
264            parent: Some(self),
265            extends: None,
266            ..Region::default()
267        }
268    }
269
270    pub fn without_parent(self) -> Region<'static> {
271        Region {
272            parent: None,
273            extends: None,
274            hidden: self.hidden,
275            visible: self.visible,
276            decls: self.decls,
277            protected_bodies: self.protected_bodies,
278            kind: self.kind,
279        }
280    }
281
282    pub fn in_package_declaration(mut self) -> Region<'a> {
283        self.kind = RegionKind::PackageDeclaration;
284        self
285    }
286
287    pub fn extend(region: &'a Region<'a>, parent: Option<&'a Region<'a>>) -> Region<'a> {
288        let kind = match region.kind {
289            RegionKind::PackageDeclaration => RegionKind::PackageBody,
290            _ => RegionKind::Other,
291        };
292
293        Region {
294            parent: parent,
295            extends: Some(region),
296            kind,
297            ..Region::default()
298        }
299    }
300
301    pub fn close_immediate(&mut self, diagnostics: &mut dyn DiagnosticHandler) {
302        assert!(self.extends.is_none());
303        self.check_incomplete_types_are_defined(diagnostics);
304    }
305
306    /// Incomplete types must be defined in the same immediate region as they are declared
307    fn check_incomplete_types_are_defined(&self, diagnostics: &mut dyn DiagnosticHandler) {
308        for decl in self.decls.values() {
309            if decl.first_kind().is_incomplete_type() {
310                let mut check_ok = false;
311                if let Some(second) = decl.second() {
312                    if second.is_type_declaration() {
313                        check_ok = true;
314                    }
315                }
316
317                if !check_ok {
318                    decl.first().error(
319                        diagnostics,
320                        format!(
321                            "Missing full type declaration of incomplete type '{}'",
322                            &decl.designator
323                        ),
324                    );
325                    decl.first().hint(diagnostics, "The full type declaration shall occur immediately within the same declarative part");
326                }
327            }
328        }
329    }
330
331    fn check_deferred_constant_pairs(&self, diagnostics: &mut dyn DiagnosticHandler) {
332        match self.kind {
333            // Package without body may not have deferred constants
334            RegionKind::PackageDeclaration => {
335                for decl in self.decls.values() {
336                    match decl.first_kind() {
337                        NamedEntityKind::DeferredConstant => {
338                            decl.first().error(diagnostics, format!("Deferred constant '{}' lacks corresponding full constant declaration in package body", &decl.designator));
339                        }
340                        _ => {}
341                    }
342                }
343            }
344            RegionKind::PackageBody => {
345                let ref extends = self
346                    .extends
347                    .as_ref()
348                    .expect("Package body must extend package");
349                for ext_decl in extends.decls.values() {
350                    match ext_decl.first_kind() {
351                        NamedEntityKind::DeferredConstant => {
352                            // Deferred constants may only be located in a package
353                            // And only matched with a constant in the body
354                            let mut found = false;
355                            let decl = self.decls.get(&ext_decl.designator);
356
357                            if let Some(decl) = decl {
358                                if let NamedEntityKind::Constant = decl.first_kind() {
359                                    found = true;
360                                }
361                            }
362
363                            if !found {
364                                ext_decl.first().error(diagnostics, format!("Deferred constant '{}' lacks corresponding full constant declaration in package body", &ext_decl.designator));
365                            }
366                        }
367                        _ => {}
368                    }
369                }
370            }
371            RegionKind::Other => {}
372        }
373    }
374
375    fn get_protected_body(&self, name: &Symbol) -> Option<&SrcPos> {
376        self.protected_bodies.get(name).or_else(|| {
377            self.extends
378                .and_then(|extends| extends.get_protected_body(name))
379        })
380    }
381
382    fn has_protected_body(&self, name: &Symbol) -> bool {
383        self.get_protected_body(name).is_some()
384    }
385
386    fn check_protected_types_have_body(&self, diagnostics: &mut dyn DiagnosticHandler) {
387        for decl in self.decls.values() {
388            if decl.first_kind().is_protected_type() {
389                if !self.has_protected_body(&decl.designator.expect_identifier()) {
390                    decl.first().error(
391                        diagnostics,
392                        format!("Missing body for protected type '{}'", &decl.designator),
393                    );
394                }
395            }
396        }
397
398        if let Some(ref extends) = self.extends {
399            for ext_decl in extends.decls.values() {
400                if ext_decl.first_kind().is_protected_type() {
401                    if !self.has_protected_body(&ext_decl.designator.expect_identifier()) {
402                        ext_decl.first().error(
403                            diagnostics,
404                            format!("Missing body for protected type '{}'", &ext_decl.designator),
405                        );
406                    }
407                }
408            }
409        }
410    }
411
412    #[must_use]
413    fn check_deferred_constant_only_in_package(
414        &self,
415        ent: &NamedEntity,
416        diagnostics: &mut dyn DiagnosticHandler,
417    ) -> bool {
418        if self.kind != RegionKind::PackageDeclaration && ent.kind.is_deferred_constant() {
419            ent.error(
420                diagnostics,
421                "Deferred constants are only allowed in package declarations (not body)",
422            );
423            false
424        } else {
425            true
426        }
427    }
428
429    #[must_use]
430    fn check_full_constand_of_deferred_only_in_body(
431        &self,
432        ent: &NamedEntity,
433        prev_decl: &VisibleDeclaration,
434        diagnostics: &mut dyn DiagnosticHandler,
435    ) -> bool {
436        if self.kind != RegionKind::PackageBody && ent.kind.is_non_deferred_constant() {
437            if prev_decl.first_kind().is_deferred_constant() {
438                ent.error(
439                    diagnostics,
440                    "Full declaration of deferred constant is only allowed in a package body",
441                );
442                return false;
443            }
444        }
445        true
446    }
447
448    pub fn close_both(&mut self, diagnostics: &mut dyn DiagnosticHandler) {
449        self.check_incomplete_types_are_defined(diagnostics);
450        self.check_deferred_constant_pairs(diagnostics);
451        self.check_protected_types_have_body(diagnostics);
452    }
453
454    /// Check duplicate declarations
455    /// Allow deferred constants, incomplete types and protected type bodies
456    /// Returns true if the declaration does not duplicates an existing declaration
457    #[must_use]
458    fn check_duplicate(
459        ent: &NamedEntity,
460        prev_decl: &VisibleDeclaration,
461        diagnostics: &mut dyn DiagnosticHandler,
462    ) -> bool {
463        for prev_ent in prev_decl.named_entities() {
464            if ent.is_duplicate_of(&prev_ent) {
465                if let Some(ref pos) = ent.decl_pos {
466                    diagnostics.push(duplicate_error(
467                        &prev_decl.designator,
468                        pos,
469                        prev_ent.decl_pos.as_ref(),
470                    ));
471                }
472                return false;
473            }
474        }
475
476        true
477    }
478
479    /// true if the declaration can be added
480    fn check_add(
481        // The named entity to add
482        ent: &NamedEntity,
483        // Previous declaration in the same region
484        prev_decl: Option<&VisibleDeclaration>,
485        // Previous declaration in the region extended by this region
486        ext_decl: Option<&VisibleDeclaration>,
487        diagnostics: &mut dyn DiagnosticHandler,
488    ) -> bool {
489        let mut check_ok = true;
490
491        if let Some(prev_decl) = prev_decl {
492            if !Self::check_duplicate(&ent, &prev_decl, diagnostics) {
493                check_ok = false;
494            }
495        }
496
497        if let Some(ext_decl) = ext_decl {
498            if !Self::check_duplicate(&ent, &ext_decl, diagnostics) {
499                check_ok = false;
500            }
501        }
502
503        check_ok
504    }
505
506    pub fn add_protected_body(&mut self, ident: Ident, diagnostics: &mut dyn DiagnosticHandler) {
507        if let Some(prev_pos) = self.get_protected_body(&ident.item) {
508            diagnostics.push(duplicate_error(&ident.item, &ident.pos, Some(prev_pos)));
509        } else {
510            self.protected_bodies.insert(ident.item, ident.pos);
511        }
512    }
513
514    fn add_named_entity(
515        &mut self,
516        designator: Designator,
517        ent: NamedEntity,
518        diagnostics: &mut dyn DiagnosticHandler,
519    ) {
520        let ext_decl = self
521            .extends
522            .as_ref()
523            .and_then(|extends| extends.decls.get(&designator));
524
525        if !self.check_deferred_constant_only_in_package(&ent, diagnostics) {
526            return;
527        }
528
529        if let Some(ext_decl) = ext_decl {
530            if !self.check_full_constand_of_deferred_only_in_body(&ent, ext_decl, diagnostics) {
531                return;
532            }
533        }
534
535        // @TODO merge with .entry below
536        if let Some(prev_decl) = self.decls.get(&designator) {
537            if !self.check_full_constand_of_deferred_only_in_body(&ent, prev_decl, diagnostics) {
538                return;
539            }
540        }
541
542        match self.decls.entry(designator.clone()) {
543            Entry::Occupied(ref mut entry) => {
544                let prev_decl = entry.get_mut();
545
546                if Self::check_add(&ent, Some(&prev_decl), ext_decl, diagnostics) {
547                    prev_decl.push(ent);
548                }
549            }
550            Entry::Vacant(entry) => {
551                if Self::check_add(&ent, None, ext_decl, diagnostics) {
552                    entry.insert(VisibleDeclaration::new(designator, ent));
553                }
554            }
555        }
556    }
557
558    pub fn add(
559        &mut self,
560        designator: impl Into<WithPos<Designator>>,
561        kind: NamedEntityKind,
562        diagnostics: &mut dyn DiagnosticHandler,
563    ) {
564        let designator = designator.into();
565        self.add_named_entity(
566            designator.item,
567            NamedEntity::new(kind, Some(&designator.pos)),
568            diagnostics,
569        );
570    }
571
572    pub fn overwrite(&mut self, designator: impl Into<WithPos<Designator>>, kind: NamedEntityKind) {
573        let designator = designator.into();
574        let decl = VisibleDeclaration::new(
575            designator.item,
576            NamedEntity::new(kind, Some(&designator.pos)),
577        );
578        self.decls.insert(decl.designator.clone(), decl);
579    }
580
581    pub fn add_implicit(
582        &mut self,
583        designator: impl Into<Designator>,
584        decl_pos: Option<&SrcPos>,
585        kind: NamedEntityKind,
586        diagnostics: &mut dyn DiagnosticHandler,
587    ) {
588        self.add_named_entity(
589            designator.into(),
590            NamedEntity {
591                decl_pos: decl_pos.cloned(),
592                kind,
593            },
594            diagnostics,
595        );
596    }
597
598    pub fn make_library_visible(
599        &mut self,
600        designator: impl Into<Designator>,
601        library_name: &Symbol,
602        decl_pos: Option<SrcPos>,
603    ) {
604        let ent = NamedEntity {
605            decl_pos: decl_pos.clone(),
606            kind: NamedEntityKind::Library(library_name.clone()),
607        };
608        self.make_potentially_visible(designator.into(), ent);
609    }
610
611    /// Add implicit declarations when using declaration
612    /// For example all enum literals are made implicititly visible when using an enum type
613    fn add_implicit_declarations(&mut self, kind: &NamedEntityKind) {
614        match kind {
615            NamedEntityKind::TypeDeclaration(ref implicit) => {
616                // Add implicitic declarations when using type
617                if let Some(implicit) = implicit {
618                    self.make_all_potentially_visible(&implicit);
619                }
620            }
621            NamedEntityKind::AliasOf(ref kind) => {
622                self.add_implicit_declarations(kind);
623            }
624            _ => {}
625        }
626    }
627
628    fn has_duplicate(&self, designator: &Designator, ent: &NamedEntity) -> bool {
629        if let Some(prev) = self.visible.get(&designator) {
630            if !ent.is_overloaded() && !prev.is_overloaded() {
631                // @TODO check that they actually correspond to the same object
632                // The decl_pos serves as a good proxy for this except for libraries
633                if ent.decl_pos() != prev.first_pos() {
634                    if let NamedEntityKind::Library(..) = ent.kind() {
635                    } else if let NamedEntityKind::Library(..) = prev.first_kind() {
636                        // Until we have unique id:s we disable hidden check for alias
637                    } else if let NamedEntityKind::AliasOf(..) = ent.kind() {
638                    } else if let NamedEntityKind::AliasOf(..) = prev.first_kind() {
639                    } else {
640                        return true;
641                    }
642                }
643            }
644        }
645
646        if let Some(parent) = self.parent {
647            parent.has_duplicate(designator, ent)
648        } else {
649            false
650        }
651    }
652
653    pub fn make_potentially_visible(&mut self, designator: Designator, ent: NamedEntity) {
654        if self.has_duplicate(&designator, &ent) {
655            // @TODO add error message when hiding
656            self.hidden.insert(designator);
657        } else {
658            self.add_implicit_declarations(&ent.kind);
659            match self.visible.entry(designator.clone()) {
660                Entry::Vacant(entry) => {
661                    entry.insert(VisibleDeclaration::new(designator, ent));
662                }
663                Entry::Occupied(mut entry) => {
664                    entry.get_mut().push(ent);
665                }
666            }
667        }
668    }
669
670    pub fn make_all_potentially_visible(&mut self, region: &Region<'a>) {
671        for visible in region.decls.values() {
672            for ent in visible.named_entities() {
673                self.make_potentially_visible(visible.designator.clone(), ent.clone());
674            }
675        }
676    }
677
678    /// Used when using context clauses
679    pub fn copy_visibility_from(&mut self, region: &Region<'a>) {
680        for visible in region.visible.values() {
681            for ent in visible.named_entities() {
682                self.make_potentially_visible(visible.designator.clone(), ent.clone());
683            }
684        }
685    }
686
687    /// Helper function lookup a visible declaration within the region
688    fn lookup(&self, designator: &Designator, is_selected: bool) -> Option<&VisibleDeclaration> {
689        self.decls
690            .get(designator)
691            .or_else(|| {
692                self.extends
693                    .as_ref()
694                    .and_then(|region| region.lookup(designator, is_selected))
695            })
696            .or_else(|| {
697                if is_selected || self.hidden.contains(designator) {
698                    None
699                } else {
700                    self.visible.get(designator)
701                }
702            })
703            .or_else(|| {
704                if is_selected || self.hidden.contains(designator) {
705                    None
706                } else {
707                    self.parent
708                        .as_ref()
709                        .and_then(|region| region.lookup_within(designator))
710                }
711            })
712    }
713
714    /// Lookup where this region is the prefix of a selected name
715    /// Thus any visibility inside the region is irrelevant
716    pub fn lookup_selected(&self, designator: &Designator) -> Option<&VisibleDeclaration> {
717        self.lookup(designator, true)
718    }
719
720    /// Lookup a designator from within the region itself
721    /// Thus all parent regions and visibility is relevant
722    pub fn lookup_within(&self, designator: &Designator) -> Option<&VisibleDeclaration> {
723        self.lookup(designator, false)
724    }
725}
726
727pub trait SetReference {
728    fn set_unique_reference(&mut self, ent: &NamedEntity) {
729        // @TODO handle built-ins without position
730        // @TODO handle mutliple overloaded declarations
731        if !ent.is_overloaded() {
732            // We do not set references to overloaded names to avoid
733            // incorrect behavior which will appear as low quality
734            self.set_reference_pos(ent.decl_pos.as_ref());
735        } else {
736            self.clear_reference();
737        }
738    }
739
740    fn set_reference(&mut self, visible: &VisibleDeclaration) {
741        if let Some(ent) = visible.as_unique() {
742            // We do not set references to non-unqiue names
743            //  incorrect behavior which will appear as low quality
744            self.set_unique_reference(ent);
745        } else {
746            self.clear_reference();
747        }
748    }
749
750    fn clear_reference(&mut self) {
751        self.set_reference_pos(None);
752    }
753
754    fn set_reference_pos(&mut self, pos: Option<&SrcPos>);
755}
756
757impl<T> SetReference for WithRef<T> {
758    fn set_reference_pos(&mut self, pos: Option<&SrcPos>) {
759        self.reference = pos.cloned();
760    }
761}
762
763impl<T: SetReference> SetReference for WithPos<T> {
764    fn set_reference_pos(&mut self, pos: Option<&SrcPos>) {
765        self.item.set_reference_pos(pos);
766    }
767}
768
769fn duplicate_error(
770    name: &impl std::fmt::Display,
771    pos: &SrcPos,
772    prev_pos: Option<&SrcPos>,
773) -> Diagnostic {
774    let mut diagnostic = Diagnostic::error(pos, format!("Duplicate declaration of '{}'", name));
775
776    if let Some(prev_pos) = prev_pos {
777        diagnostic.add_related(prev_pos, "Previously defined here");
778    }
779
780    diagnostic
781}