vhdl_lang/ast/
util.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
6
7//! Name conversions
8use super::*;
9use crate::data::error_codes::ErrorCode;
10use crate::data::*;
11use crate::named_entity::{Concurrent, Sequential};
12use crate::TokenSpan;
13
14impl WithTokenSpan<Name> {
15    pub fn suffix_pos(&self) -> TokenSpan {
16        match self.item {
17            Name::Designator(..) => self.span,
18            Name::Selected(_, ref suffix) => suffix.token.into(),
19            // @TODO add pos of .all?
20            Name::SelectedAll(ref prefix) => prefix.span,
21            Name::CallOrIndexed(ref fcall) => fcall.name.span,
22            Name::Slice(ref prefix, ..) => prefix.span,
23            Name::Attribute(ref attr, ..) => attr.name.span,
24            Name::External(..) => self.span,
25        }
26    }
27}
28
29pub fn to_simple_name(ctx: &dyn TokenAccess, name: WithTokenSpan<Name>) -> DiagnosticResult<Ident> {
30    match name.item {
31        Name::Designator(WithRef {
32            item: Designator::Identifier(ident),
33            ..
34        }) => Ok(WithToken {
35            item: ident,
36            token: name.span.start_token,
37        }),
38        _ => Err(Diagnostic::new(
39            name.span.pos(ctx),
40            "Expected simple name",
41            ErrorCode::SyntaxError,
42        )),
43    }
44}
45
46pub fn as_simple_name_mut(name: &mut Name) -> Option<&mut WithRef<Designator>> {
47    match name {
48        Name::Designator(
49            des @ WithRef {
50                item: Designator::Identifier(_),
51                ..
52            },
53        ) => Some(des),
54        _ => None,
55    }
56}
57
58pub fn as_name_mut(expr: &mut Expression) -> Option<&mut Name> {
59    match expr {
60        Expression::Name(name) => Some(name.as_mut()),
61        _ => None,
62    }
63}
64
65pub trait HasDesignator {
66    fn designator(&self) -> &Designator;
67}
68
69impl<T: HasDesignator> HasDesignator for WithTokenSpan<T> {
70    fn designator(&self) -> &Designator {
71        self.item.designator()
72    }
73}
74
75impl HasDesignator for Designator {
76    fn designator(&self) -> &Designator {
77        self
78    }
79}
80
81impl<T: HasDesignator> HasDesignator for WithRef<T> {
82    fn designator(&self) -> &Designator {
83        self.item.designator()
84    }
85}
86
87impl HasIdent for WithRef<Ident> {
88    fn ident(&self) -> &Ident {
89        &self.item
90    }
91}
92
93impl Designator {
94    pub fn into_ref(self) -> WithRef<Designator> {
95        WithRef::new(self)
96    }
97}
98
99impl Ident {
100    pub fn into_ref(self) -> WithRef<Ident> {
101        WithRef::new(self)
102    }
103}
104
105impl WithTokenSpan<Designator> {
106    pub fn into_ref(self) -> WithTokenSpan<WithRef<Designator>> {
107        self.map_into(|name| name.into_ref())
108    }
109}
110
111impl WithToken<Designator> {
112    pub fn into_ref(self) -> WithToken<WithRef<Designator>> {
113        self.map_into(|name| name.into_ref())
114    }
115}
116
117pub trait HasIdent {
118    fn ident(&self) -> &Ident;
119    fn name(&self) -> &Symbol {
120        &self.ident().item
121    }
122
123    fn ident_pos<'a>(&'a self, ctx: &'a dyn TokenAccess) -> &'a SrcPos {
124        self.ident().pos(ctx)
125    }
126}
127
128impl HasIdent for Ident {
129    fn ident(&self) -> &Ident {
130        self
131    }
132}
133
134impl<T: HasIdent> HasIdent for WithDecl<T> {
135    fn ident(&self) -> &Ident {
136        self.tree.ident()
137    }
138}
139
140impl HasIdent for EntityDeclaration {
141    fn ident(&self) -> &Ident {
142        self.ident.ident()
143    }
144}
145
146impl HasIdent for PackageDeclaration {
147    fn ident(&self) -> &Ident {
148        self.ident.ident()
149    }
150}
151
152impl HasIdent for PackageBody {
153    fn ident(&self) -> &Ident {
154        &self.ident.tree
155    }
156}
157
158impl HasIdent for ArchitectureBody {
159    fn ident(&self) -> &Ident {
160        self.ident.ident()
161    }
162}
163
164impl HasIdent for PackageInstantiation {
165    fn ident(&self) -> &Ident {
166        self.ident.ident()
167    }
168}
169
170impl HasIdent for ContextDeclaration {
171    fn ident(&self) -> &Ident {
172        self.ident.ident()
173    }
174}
175
176impl HasIdent for ConfigurationDeclaration {
177    fn ident(&self) -> &Ident {
178        self.ident.ident()
179    }
180}
181
182impl HasIdent for AnyPrimaryUnit {
183    fn ident(&self) -> &Ident {
184        match self {
185            AnyPrimaryUnit::Entity(ref unit) => unit.ident(),
186            AnyPrimaryUnit::Configuration(ref unit) => unit.ident(),
187            AnyPrimaryUnit::Package(ref unit) => unit.ident(),
188            AnyPrimaryUnit::PackageInstance(ref unit) => unit.ident(),
189            AnyPrimaryUnit::Context(ref unit) => unit.ident(),
190        }
191    }
192}
193
194impl HasIdent for AnySecondaryUnit {
195    fn ident(&self) -> &Ident {
196        match self {
197            AnySecondaryUnit::PackageBody(ref unit) => unit.ident(),
198            AnySecondaryUnit::Architecture(ref unit) => unit.ident(),
199        }
200    }
201}
202
203impl HasIdent for AnyDesignUnit {
204    fn ident(&self) -> &Ident {
205        match self {
206            AnyDesignUnit::Primary(ref unit) => unit.ident(),
207            AnyDesignUnit::Secondary(ref unit) => unit.ident(),
208        }
209    }
210}
211
212impl<'a, T: HasIdent> From<&'a T> for WithToken<Designator> {
213    fn from(other: &'a T) -> WithToken<Designator> {
214        other.ident().to_owned().map_into(Designator::Identifier)
215    }
216}
217
218/// Primary identifier in secondary units
219pub trait HasPrimaryIdent {
220    fn primary_ident(&self) -> &Ident;
221    fn primary_name(&self) -> &Symbol {
222        &self.primary_ident().item
223    }
224}
225
226impl HasPrimaryIdent for ArchitectureBody {
227    fn primary_ident(&self) -> &Ident {
228        &self.entity_name.item
229    }
230}
231
232impl HasPrimaryIdent for PackageBody {
233    fn primary_ident(&self) -> &Ident {
234        &self.ident.tree
235    }
236}
237
238impl HasPrimaryIdent for AnySecondaryUnit {
239    fn primary_ident(&self) -> &Ident {
240        match self {
241            AnySecondaryUnit::Architecture(unit) => unit.primary_ident(),
242            AnySecondaryUnit::PackageBody(unit) => unit.primary_ident(),
243        }
244    }
245}
246
247impl From<EnumerationLiteral> for Designator {
248    fn from(other: EnumerationLiteral) -> Designator {
249        match other {
250            EnumerationLiteral::Identifier(ident) => Designator::Identifier(ident),
251            EnumerationLiteral::Character(byte) => Designator::Character(byte),
252        }
253    }
254}
255
256impl From<Symbol> for Designator {
257    fn from(other: Symbol) -> Designator {
258        Designator::Identifier(other)
259    }
260}
261
262impl From<WithTokenSpan<Symbol>> for WithTokenSpan<Designator> {
263    fn from(other: WithTokenSpan<Symbol>) -> WithTokenSpan<Designator> {
264        other.map_into(|sym| sym.into())
265    }
266}
267
268impl<'a> From<&'a Symbol> for Designator {
269    fn from(other: &'a Symbol) -> Designator {
270        other.clone().into()
271    }
272}
273
274impl SubprogramDesignator {
275    pub fn into_designator(self) -> Designator {
276        match self {
277            SubprogramDesignator::Identifier(ident) => Designator::Identifier(ident),
278            SubprogramDesignator::OperatorSymbol(ident) => Designator::OperatorSymbol(ident),
279        }
280    }
281}
282
283impl SubprogramSpecification {
284    pub fn token(&self) -> TokenId {
285        match self {
286            SubprogramSpecification::Function(ref function) => function.designator.tree.token,
287            SubprogramSpecification::Procedure(ref procedure) => procedure.designator.tree.token,
288        }
289    }
290}
291
292impl EnumerationLiteral {
293    pub fn into_designator(self) -> Designator {
294        match self {
295            EnumerationLiteral::Identifier(ident) => Designator::Identifier(ident),
296            EnumerationLiteral::Character(byte) => Designator::Character(byte),
297        }
298    }
299}
300
301impl Designator {
302    pub fn as_identifier(&self) -> Option<&Symbol> {
303        if let Designator::Identifier(sym) = self {
304            Some(sym)
305        } else {
306            None
307        }
308    }
309
310    pub fn expect_identifier(&self) -> &Symbol {
311        self.as_identifier().unwrap()
312    }
313
314    pub fn describe(&self) -> String {
315        match self {
316            Designator::Character(chr) => format!("'{chr}'"),
317            Designator::Identifier(ident) => format!("'{ident}'"),
318            Designator::OperatorSymbol(op) => format!("operator \"{op}\""),
319            Designator::Anonymous(_) => "<anonymous>".to_owned(),
320        }
321    }
322}
323
324impl Name {
325    pub fn suffix_reference_mut(&mut self) -> Option<&mut Reference> {
326        match self {
327            Name::Designator(suffix) => Some(&mut suffix.reference),
328            Name::Selected(_, suffix) => Some(&mut suffix.item.reference),
329            _ => None,
330        }
331    }
332
333    // Get an already set suffix reference such as when an ambiguous overloaded call has already been resolved
334    pub fn get_suffix_reference(&self) -> Option<EntityId> {
335        match self {
336            Name::Designator(suffix) => suffix.reference.get(),
337            Name::Selected(_, suffix) => suffix.item.reference.get(),
338            _ => None,
339        }
340    }
341
342    /// Like [self.get_suffix_reference], but disregards final indexes, such as
343    /// `foo.bar.baz(0)`
344    pub fn get_suffix_reference_disregard_index(&self) -> Option<EntityId> {
345        use Name::*;
346        match self {
347            Designator(suffix) => suffix.reference.get(),
348            Selected(_, suffix) => suffix.item.reference.get(),
349            Slice(name, _) => name.item.get_suffix_reference_disregard_index(),
350            CallOrIndexed(coi) => coi.name.item.get_suffix_reference_disregard_index(),
351            _ => None,
352        }
353    }
354
355    pub fn prefix(&self) -> Option<&Designator> {
356        match self {
357            Self::Attribute(attr) => attr.name.item.prefix(),
358            Self::Designator(d) => Some(d.designator()),
359            Self::External(..) => None,
360            Self::CallOrIndexed(fcall) => fcall.name.item.prefix(),
361            Self::SelectedAll(name) => name.item.prefix(),
362            Self::Selected(name, ..) => name.item.prefix(),
363            Self::Slice(name, ..) => name.item.prefix(),
364        }
365    }
366
367    /// Returns true if the name is purely a selected name
368    /// Example: a.b.c
369    pub fn is_selected_name(&self) -> bool {
370        match self {
371            Name::Designator(_) => true,
372            Name::Selected(prefix, _) => prefix.item.is_selected_name(),
373            _ => false,
374        }
375    }
376}
377
378impl CallOrIndexed {
379    // During parsing function calls and indexed names are ambiguous
380    // Thus we convert function calls to indexed names during the analysis stage
381    pub fn as_indexed(&mut self) -> Option<IndexedName<'_>> {
382        if !self.could_be_indexed_name() {
383            return None;
384        }
385
386        let CallOrIndexed {
387            ref mut name,
388            ref mut parameters,
389        } = self;
390
391        let mut indexes: Vec<Index<'_>> = Vec::with_capacity(parameters.items.len());
392
393        for elem in parameters.items.iter_mut() {
394            if let ActualPart::Expression(ref mut expr) = &mut elem.actual.item {
395                indexes.push(Index {
396                    pos: elem.actual.span,
397                    expr,
398                });
399            }
400        }
401
402        Some(IndexedName { name, indexes })
403    }
404
405    pub fn could_be_indexed_name(&self) -> bool {
406        self.parameters
407            .items
408            .iter()
409            .all(|assoc| assoc.formal.is_none() && !matches!(assoc.actual.item, ActualPart::Open))
410    }
411}
412
413pub struct IndexedName<'a> {
414    pub name: &'a mut WithTokenSpan<Name>,
415    pub indexes: Vec<Index<'a>>,
416}
417
418pub struct Index<'a> {
419    pub pos: TokenSpan,
420    pub expr: &'a mut Expression,
421}
422
423impl AttributeName {
424    pub fn as_range(&self) -> Option<RangeAttribute> {
425        if let AttributeDesignator::Range(r) = self.attr.item {
426            Some(r)
427        } else {
428            None
429        }
430    }
431
432    pub fn as_type(&self) -> Option<TypeAttribute> {
433        if self.signature.is_none() && self.expr.is_none() {
434            if let AttributeDesignator::Type(t) = self.attr.item {
435                Some(t)
436            } else {
437                None
438            }
439        } else {
440            None
441        }
442    }
443}
444
445impl RangeConstraint {
446    pub fn span(&self) -> TokenSpan {
447        self.left_expr.span.combine(self.right_expr.span)
448    }
449}
450
451impl crate::ast::Range {
452    pub fn span(&self) -> TokenSpan {
453        use crate::ast::Range::*;
454        match self {
455            Range(constraint) => constraint.span(),
456            Attribute(attr) => attr.name.span.end_with(attr.attr.token),
457        }
458    }
459}
460
461impl DiscreteRange {
462    pub fn span(&self) -> TokenSpan {
463        match self {
464            DiscreteRange::Discrete(type_mark, _) => type_mark.span,
465            DiscreteRange::Range(range) => range.span(),
466        }
467    }
468}
469
470impl SubprogramSpecification {
471    pub fn subpgm_designator(&self) -> &WithToken<SubprogramDesignator> {
472        match self {
473            SubprogramSpecification::Procedure(s) => &s.designator.tree,
474            SubprogramSpecification::Function(s) => &s.designator.tree,
475        }
476    }
477
478    pub fn reference_mut(&mut self) -> &mut Reference {
479        match self {
480            SubprogramSpecification::Function(ref mut function) => &mut function.designator.decl,
481            SubprogramSpecification::Procedure(ref mut procedure) => &mut procedure.designator.decl,
482        }
483    }
484}
485
486impl SubprogramDeclaration {
487    pub fn subpgm_designator(&self) -> &WithToken<SubprogramDesignator> {
488        self.specification.subpgm_designator()
489    }
490
491    pub fn reference_mut(&mut self) -> &mut Reference {
492        self.specification.reference_mut()
493    }
494}
495
496impl ConcurrentStatement {
497    pub fn label_typ(&self) -> Option<Concurrent> {
498        use ConcurrentStatement::*;
499        match self {
500            ProcedureCall(_) => None,
501            Block(_) => Some(Concurrent::Block),
502            Process(_) => Some(Concurrent::Process),
503            Assert(_) => None,
504            Assignment(_) => None,
505            Instance(_) => Some(Concurrent::Instance),
506            ForGenerate(_) | IfGenerate(_) | CaseGenerate(_) => Some(Concurrent::Generate),
507        }
508    }
509
510    pub fn end_label_pos(&self) -> Option<&SrcPos> {
511        use ConcurrentStatement::*;
512
513        match self {
514            ProcedureCall(_) => None,
515            Block(value) => value.end_label_pos.as_ref(),
516            Process(value) => value.end_label_pos.as_ref(),
517            Assert(_) => None,
518            Assignment(_) => None,
519            Instance(_) => None,
520            ForGenerate(value) => value.end_label_pos.as_ref(),
521            IfGenerate(value) => value.end_label_pos.as_ref(),
522            CaseGenerate(value) => value.end_label_pos.as_ref(),
523        }
524    }
525
526    pub fn can_have_label(&self) -> bool {
527        self.label_typ().is_some()
528    }
529}
530
531impl SequentialStatement {
532    pub fn label_typ(&self) -> Option<Sequential> {
533        use SequentialStatement::*;
534        match self {
535            Wait(_) => None,
536            Assert(_) => None,
537            Report(_) => None,
538            VariableAssignment(_) => None,
539            SignalAssignment(_) => None,
540            SignalForceAssignment(_) => None,
541            SignalReleaseAssignment(_) => None,
542            ProcedureCall(_) => None,
543            If(_) => Some(Sequential::If),
544            Case(_) => Some(Sequential::Case),
545            Loop(_) => Some(Sequential::Loop),
546            Next(_) => None,
547            Exit(_) => None,
548            Return(_) => None,
549            Null => None,
550        }
551    }
552
553    pub fn end_label_pos(&self) -> Option<&SrcPos> {
554        use SequentialStatement::*;
555        match self {
556            Wait(_) => None,
557            Assert(_) => None,
558            Report(_) => None,
559            VariableAssignment(_) => None,
560            SignalAssignment(_) => None,
561            SignalForceAssignment(_) => None,
562            SignalReleaseAssignment(_) => None,
563            ProcedureCall(_) => None,
564            If(value) => value.end_label_pos.as_ref(),
565            Case(value) => value.end_label_pos.as_ref(),
566            Loop(value) => value.end_label_pos.as_ref(),
567            Next(_) => None,
568            Exit(_) => None,
569            Return(_) => None,
570            Null => None,
571        }
572    }
573
574    pub fn can_have_label(&self) -> bool {
575        self.label_typ().is_some()
576    }
577}