Skip to content

Commit 4936ece

Browse files
committed
Implement references for architecture. #155
1 parent 9c78034 commit 4936ece

File tree

12 files changed

+221
-43
lines changed

12 files changed

+221
-43
lines changed

vhdl_lang/src/analysis/analyze.rs

Lines changed: 70 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ pub(super) struct AnalyzeContext<'a> {
153153
current_unit: UnitId,
154154
pub(super) arena: &'a Arena,
155155
uses: RefCell<FnvHashSet<UnitId>>,
156-
missing_primary: RefCell<FnvHashSet<(Symbol, Symbol)>>,
156+
missing_unit: RefCell<FnvHashSet<(Symbol, Symbol, Option<Symbol>)>>,
157157
uses_library_all: RefCell<FnvHashSet<Symbol>>,
158158
}
159159

@@ -176,7 +176,7 @@ impl<'a> AnalyzeContext<'a> {
176176
current_unit: current_unit.clone(),
177177
arena,
178178
uses: RefCell::new(FnvHashSet::default()),
179-
missing_primary: RefCell::new(FnvHashSet::default()),
179+
missing_unit: RefCell::new(FnvHashSet::default()),
180180
uses_library_all: RefCell::new(FnvHashSet::default()),
181181
}
182182
}
@@ -214,13 +214,26 @@ impl<'a> AnalyzeContext<'a> {
214214
}
215215
}
216216

217-
fn make_use_of_missing_primary(&self, library_name: &Symbol, primary_name: &Symbol) {
218-
let key = (library_name.clone(), primary_name.clone());
217+
fn make_use_of_missing_unit(
218+
&self,
219+
library_name: &Symbol,
220+
primary_name: &Symbol,
221+
secondary_name: Option<&Symbol>,
222+
) {
223+
let key = (
224+
library_name.clone(),
225+
primary_name.clone(),
226+
secondary_name.cloned(),
227+
);
219228

220229
// Check local cache before taking lock
221-
if self.missing_primary.borrow_mut().insert(key) {
222-
self.root
223-
.make_use_of_missing_primary(&self.current_unit, library_name, primary_name);
230+
if self.missing_unit.borrow_mut().insert(key) {
231+
self.root.make_use_of_missing_unit(
232+
&self.current_unit,
233+
library_name,
234+
primary_name,
235+
secondary_name,
236+
);
224237
}
225238
}
226239

@@ -334,16 +347,63 @@ impl<'a> AnalyzeContext<'a> {
334347

335348
fn get_primary_unit(&self, library_name: &Symbol, name: &Symbol) -> Option<&'a LockedUnit> {
336349
let units = self.root.get_library_units(library_name)?;
337-
// @TODO missing library
338-
339350
if let Some(unit) = units.get(&UnitKey::Primary(name.clone())) {
340351
return Some(unit);
341352
}
353+
self.make_use_of_missing_unit(library_name, name, None);
354+
None
355+
}
342356

343-
self.make_use_of_missing_primary(library_name, name);
357+
fn get_secondary_unit(
358+
&self,
359+
library_name: &Symbol,
360+
primary: &Symbol,
361+
name: &Symbol,
362+
) -> Option<&'a LockedUnit> {
363+
let units = self.root.get_library_units(library_name)?;
364+
if let Some(unit) = units.get(&UnitKey::Secondary(primary.clone(), name.clone())) {
365+
return Some(unit);
366+
}
367+
self.make_use_of_missing_unit(library_name, primary, Some(name));
344368
None
345369
}
346370

371+
pub(super) fn get_architecture(
372+
&self,
373+
library_name: &Symbol,
374+
pos: &SrcPos,
375+
entity_name: &Symbol,
376+
architecture_name: &Symbol,
377+
) -> AnalysisResult<DesignEnt<'a>> {
378+
if let Some(unit) = self.get_secondary_unit(library_name, entity_name, architecture_name) {
379+
let data = self.get_analysis(Some(pos), unit)?;
380+
if let AnyDesignUnit::Secondary(AnySecondaryUnit::Architecture(arch)) = data.deref() {
381+
if let Some(id) = arch.ident.decl {
382+
let ent = self.arena.get(id);
383+
let design = DesignEnt::from_any(ent).ok_or_else(|| {
384+
// Almost impossible but better not fail silently
385+
Diagnostic::error(
386+
pos,
387+
format!(
388+
"Found non-design {} unit within library {}",
389+
ent.describe(),
390+
library_name
391+
),
392+
)
393+
})?;
394+
return Ok(design);
395+
}
396+
}
397+
}
398+
399+
Err(AnalysisError::NotFatal(Diagnostic::error(
400+
pos,
401+
format!(
402+
"No architecture '{architecture_name}' for entity '{library_name}.{entity_name}'"
403+
),
404+
)))
405+
}
406+
347407
pub fn lookup_in_library(
348408
&self,
349409
library_name: &Symbol,

vhdl_lang/src/analysis/concurrent.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,8 +208,7 @@ impl<'a> AnalyzeContext<'a> {
208208
diagnostics: &mut dyn DiagnosticHandler,
209209
) -> FatalResult {
210210
match instance.unit {
211-
// @TODO architecture
212-
InstantiatedUnit::Entity(ref mut entity_name, ..) => {
211+
InstantiatedUnit::Entity(ref mut entity_name, ref mut architecture_name) => {
213212
if let Err(err) =
214213
self.resolve_selected_name(scope, entity_name)
215214
.and_then(|entities| {
@@ -220,7 +219,27 @@ impl<'a> AnalyzeContext<'a> {
220219
expected,
221220
)?;
222221

223-
if let AnyEntKind::Design(Design::Entity(_, ent_region)) = ent.kind() {
222+
if let AnyEntKind::Design(Design::Entity(library_name, _, ent_region)) =
223+
ent.kind()
224+
{
225+
if let Designator::Identifier(entity_ident) = ent.designator() {
226+
if let Some(ref mut architecture_name) = architecture_name {
227+
match self.get_architecture(
228+
library_name,
229+
&architecture_name.item.pos,
230+
entity_ident,
231+
&architecture_name.item.item,
232+
) {
233+
Ok(arch) => {
234+
architecture_name.set_unique_reference(&arch);
235+
}
236+
Err(err) => {
237+
diagnostics.push(err.into_non_fatal()?);
238+
}
239+
}
240+
}
241+
}
242+
224243
let (generic_region, port_region) = ent_region.to_entity_formal();
225244

226245
self.analyze_assoc_elems_with_formal_region(

vhdl_lang/src/analysis/design_unit.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,11 @@ impl<'a> AnalyzeContext<'a> {
7171
self.redefine(
7272
id,
7373
&mut unit.ident,
74-
AnyEntKind::Design(Design::Entity(visibility, region)),
74+
AnyEntKind::Design(Design::Entity(
75+
self.work_library_name().clone(),
76+
visibility,
77+
region,
78+
)),
7579
);
7680

7781
Ok(())
@@ -217,7 +221,7 @@ impl<'a> AnalyzeContext<'a> {
217221
self.check_secondary_before_primary(&primary, unit.pos(), diagnostics);
218222

219223
let (visibility, region) =
220-
if let Design::Entity(ref visibility, ref region) = primary.kind() {
224+
if let Design::Entity(_, ref visibility, ref region) = primary.kind() {
221225
(visibility, region)
222226
} else {
223227
let mut diagnostic = Diagnostic::error(unit.pos(), "Expected an entity");
@@ -233,13 +237,14 @@ impl<'a> AnalyzeContext<'a> {
233237
self.analyze_context_clause(&root_scope, &mut unit.context_clause, diagnostics)?;
234238
let scope = Scope::extend(region, Some(&root_scope));
235239

236-
// Architecture name is visible
237-
scope.make_potentially_visible(
238-
Some(unit.pos()),
239-
self.arena
240-
.explicit(unit.name().clone(), AnyEntKind::Label, Some(unit.pos())),
240+
let arch = self.arena.define(
241+
&mut unit.ident,
242+
AnyEntKind::Design(Design::Architecture(primary)),
241243
);
242244

245+
// Architecture name is visible
246+
scope.make_potentially_visible(Some(unit.pos()), arch);
247+
243248
self.define_labels_for_concurrent_part(&scope, &mut unit.statements, diagnostics)?;
244249
self.analyze_declarative_part(&scope, &mut unit.decl, diagnostics)?;
245250
self.analyze_concurrent_part(&scope, &mut unit.statements, diagnostics)?;

vhdl_lang/src/analysis/named_entity/design.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@ use crate::analysis::visibility::Visibility;
1515
use crate::ast::Designator;
1616
use crate::ast::HasDesignator;
1717
use crate::ast::WithRef;
18+
use crate::data::Symbol;
1819
use crate::data::WithPos;
1920
use crate::Diagnostic;
2021
use crate::SrcPos;
2122

2223
pub enum Design<'a> {
23-
Entity(Visibility<'a>, Region<'a>),
24+
Entity(Symbol, Visibility<'a>, Region<'a>),
25+
Architecture(DesignEnt<'a>),
2426
Configuration,
2527
Package(Visibility<'a>, Region<'a>),
2628
UninstPackage(Visibility<'a>, Region<'a>),
@@ -33,6 +35,7 @@ impl<'a> Design<'a> {
3335
use Design::*;
3436
match self {
3537
Entity(..) => "entity",
38+
Architecture(..) => "architecture",
3639
Configuration => "configuration",
3740
Package(..) => "package",
3841
UninstPackage(..) => "uninstantiated package",

vhdl_lang/src/analysis/root.rs

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,9 @@ pub struct DesignRoot {
267267
// user => set(users)
268268
users_of: RwLock<FnvHashMap<UnitId, FnvHashSet<UnitId>>>,
269269

270-
// missing primary name => set(affected)
271-
missing_primary: RwLock<FnvHashMap<(Symbol, Symbol), FnvHashSet<UnitId>>>,
270+
// missing unit name => set(affected)
271+
#[allow(clippy::type_complexity)]
272+
missing_unit: RwLock<FnvHashMap<(Symbol, Symbol, Option<Symbol>), FnvHashSet<UnitId>>>,
272273

273274
// Tracks which units have a "use library.all;" clause.
274275
// library name => set(affected)
@@ -287,7 +288,7 @@ impl DesignRoot {
287288
arenas: FinalArena::default(),
288289
libraries: FnvHashMap::default(),
289290
users_of: RwLock::new(FnvHashMap::default()),
290-
missing_primary: RwLock::new(FnvHashMap::default()),
291+
missing_unit: RwLock::new(FnvHashMap::default()),
291292
users_of_library_all: RwLock::new(FnvHashMap::default()),
292293
}
293294
}
@@ -607,16 +608,21 @@ impl DesignRoot {
607608
}
608609
}
609610

610-
/// Make use of a missing primary name. The library unit will be sensitive to adding such a primary unit in the future.
611-
pub(super) fn make_use_of_missing_primary(
611+
/// Make use of a missing unit name. The library unit will be sensitive to adding such a unit in the future.
612+
pub(super) fn make_use_of_missing_unit(
612613
&self,
613614
user: &UnitId,
614615
library_name: &Symbol,
615616
primary_name: &Symbol,
617+
secondary_name: Option<&Symbol>,
616618
) {
617-
let mut missing_primary = self.missing_primary.write();
618-
let key = (library_name.clone(), primary_name.clone());
619-
match missing_primary.entry(key) {
619+
let mut missing_unit = self.missing_unit.write();
620+
let key = (
621+
library_name.clone(),
622+
primary_name.clone(),
623+
secondary_name.cloned(),
624+
);
625+
match missing_unit.entry(key) {
620626
Entry::Occupied(mut entry) => {
621627
entry.get_mut().insert(user.clone());
622628
}
@@ -659,10 +665,12 @@ impl DesignRoot {
659665
}
660666
}
661667
}
662-
let missing_primary = self.missing_primary.read();
663-
for ((library_name, primary_name), unit_ids) in missing_primary.iter() {
668+
let missing_unit = self.missing_unit.read();
669+
for ((library_name, primary_name, secondary_name), unit_ids) in missing_unit.iter() {
664670
let was_added = added.iter().any(|added_id| {
665-
added_id.library_name() == library_name && added_id.primary_name() == primary_name
671+
added_id.library_name() == library_name
672+
&& added_id.primary_name() == primary_name
673+
&& added_id.secondary_name() == secondary_name.as_ref()
666674
});
667675

668676
if was_added {
@@ -686,11 +694,11 @@ impl DesignRoot {
686694
self.reset_affected(get_all_affected(&users_of, affected));
687695
drop(users_of);
688696
drop(users_of_library_all);
689-
drop(missing_primary);
697+
drop(missing_unit);
690698

691699
let mut users_of = self.users_of.write();
692700
let mut users_of_library_all = self.users_of_library_all.write();
693-
let mut missing_primary = self.missing_primary.write();
701+
let mut missing_unit = self.missing_unit.write();
694702

695703
// Clean-up after removed units
696704
for removed_unit in removed.iter() {
@@ -701,7 +709,7 @@ impl DesignRoot {
701709
library_all_affected.remove(removed_unit);
702710
}
703711

704-
missing_primary.retain(|_, unit_ids| {
712+
missing_unit.retain(|_, unit_ids| {
705713
unit_ids.remove(removed_unit);
706714
!unit_ids.is_empty()
707715
});

vhdl_lang/src/analysis/tests/resolves_names.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1841,3 +1841,62 @@ end package body;
18411841
Some(&code.s("c0", 2).pos())
18421842
);
18431843
}
1844+
1845+
#[test]
1846+
fn find_architecture_references() {
1847+
let mut builder = LibraryBuilder::new();
1848+
let code = builder.code(
1849+
"libname",
1850+
"
1851+
entity ent1 is
1852+
end entity;
1853+
1854+
architecture a1 of ent1 is
1855+
begin
1856+
end architecture;
1857+
1858+
architecture a2 of ent1 is
1859+
begin
1860+
end architecture;
1861+
1862+
entity ent2 is
1863+
end entity;
1864+
1865+
architecture a of ent2 is
1866+
begin
1867+
good_inst1 : entity work.ent1(a1);
1868+
good_inst2 : entity work.ent1(a2);
1869+
bad_inst : entity work.ent1(a3);
1870+
end architecture;
1871+
",
1872+
);
1873+
1874+
let (root, diagnostics) = builder.get_analyzed_root();
1875+
check_diagnostics(
1876+
diagnostics,
1877+
vec![Diagnostic::error(
1878+
code.sa("work.ent1(", "a3"),
1879+
"No architecture 'a3' for entity 'libname.ent1'",
1880+
)],
1881+
);
1882+
1883+
assert_eq_unordered(
1884+
&root.find_all_references_pos(&code.s("a1", 1).pos()),
1885+
&[code.s("a1", 1).pos(), code.s("a1", 2).pos()],
1886+
);
1887+
1888+
assert_eq_unordered(
1889+
&root.find_all_references_pos(&code.s("a1", 2).pos()),
1890+
&[code.s("a1", 1).pos(), code.s("a1", 2).pos()],
1891+
);
1892+
1893+
assert_eq!(
1894+
root.find_definition_of(
1895+
root.search_reference(code.source(), code.s("a2", 2).start())
1896+
.unwrap()
1897+
)
1898+
.unwrap()
1899+
.decl_pos(),
1900+
Some(&code.s("a2", 1).pos())
1901+
);
1902+
}

vhdl_lang/src/ast.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,7 +1007,7 @@ pub struct ConcurrentSignalAssignment {
10071007
#[derive(PartialEq, Debug, Clone)]
10081008
pub enum InstantiatedUnit {
10091009
Component(WithPos<SelectedName>),
1010-
Entity(WithPos<SelectedName>, Option<Ident>),
1010+
Entity(WithPos<SelectedName>, Option<WithRef<Ident>>),
10111011
Configuration(WithPos<SelectedName>),
10121012
}
10131013

@@ -1204,7 +1204,7 @@ pub struct EntityDeclaration {
12041204
#[derive(PartialEq, Debug, Clone)]
12051205
pub struct ArchitectureBody {
12061206
pub context_clause: ContextClause,
1207-
pub ident: Ident,
1207+
pub ident: WithDecl<Ident>,
12081208
pub entity_name: WithRef<Ident>,
12091209
pub decl: Vec<Declaration>,
12101210
pub statements: Vec<LabeledConcurrentStatement>,

0 commit comments

Comments
 (0)