// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. // // Copyright (c) 2018, Olof Kraigher olof.kraigher@gmail.com //! Name conversions use super::*; use crate::data::error_codes::ErrorCode; use crate::data::*; use crate::named_entity::{Concurrent, Sequential}; use crate::TokenSpan; impl WithTokenSpan { pub fn suffix_pos(&self) -> TokenSpan { match self.item { Name::Designator(..) => self.span, Name::Selected(_, ref suffix) => suffix.token.into(), // @TODO add pos of .all? Name::SelectedAll(ref prefix) => prefix.span, Name::CallOrIndexed(ref fcall) => fcall.name.span, Name::Slice(ref prefix, ..) => prefix.span, Name::Attribute(ref attr, ..) => attr.name.span, Name::External(..) => self.span, } } } pub fn to_simple_name(ctx: &dyn TokenAccess, name: WithTokenSpan) -> DiagnosticResult { match name.item { Name::Designator(WithRef { item: Designator::Identifier(ident), .. }) => Ok(WithToken { item: ident, token: name.span.start_token, }), _ => Err(Diagnostic::new( name.span.pos(ctx), "Expected simple name", ErrorCode::SyntaxError, )), } } pub fn as_simple_name_mut(name: &mut Name) -> Option<&mut WithRef> { match name { Name::Designator( des @ WithRef { item: Designator::Identifier(_), .. }, ) => Some(des), _ => None, } } pub fn as_name_mut(expr: &mut Expression) -> Option<&mut Name> { match expr { Expression::Name(name) => Some(name.as_mut()), _ => None, } } pub trait HasDesignator { fn designator(&self) -> &Designator; } impl HasDesignator for WithTokenSpan { fn designator(&self) -> &Designator { self.item.designator() } } impl HasDesignator for Designator { fn designator(&self) -> &Designator { self } } impl HasDesignator for WithRef { fn designator(&self) -> &Designator { self.item.designator() } } impl HasIdent for WithRef { fn ident(&self) -> &Ident { &self.item } } impl Designator { pub fn into_ref(self) -> WithRef { WithRef::new(self) } } impl Ident { pub fn into_ref(self) -> WithRef { WithRef::new(self) } } impl WithTokenSpan { pub fn into_ref(self) -> WithTokenSpan> { self.map_into(|name| name.into_ref()) } } impl WithToken { pub fn into_ref(self) -> WithToken> { self.map_into(|name| name.into_ref()) } } pub trait HasIdent { fn ident(&self) -> &Ident; fn name(&self) -> &Symbol { &self.ident().item } fn ident_pos<'a>(&'a self, ctx: &'a dyn TokenAccess) -> &SrcPos { self.ident().pos(ctx) } } impl HasIdent for Ident { fn ident(&self) -> &Ident { self } } impl HasIdent for WithDecl { fn ident(&self) -> &Ident { self.tree.ident() } } impl HasIdent for EntityDeclaration { fn ident(&self) -> &Ident { self.ident.ident() } } impl HasIdent for PackageDeclaration { fn ident(&self) -> &Ident { self.ident.ident() } } impl HasIdent for PackageBody { fn ident(&self) -> &Ident { &self.ident.tree } } impl HasIdent for ArchitectureBody { fn ident(&self) -> &Ident { self.ident.ident() } } impl HasIdent for PackageInstantiation { fn ident(&self) -> &Ident { self.ident.ident() } } impl HasIdent for ContextDeclaration { fn ident(&self) -> &Ident { self.ident.ident() } } impl HasIdent for ConfigurationDeclaration { fn ident(&self) -> &Ident { self.ident.ident() } } impl HasIdent for AnyPrimaryUnit { fn ident(&self) -> &Ident { match self { AnyPrimaryUnit::Entity(ref unit) => unit.ident(), AnyPrimaryUnit::Configuration(ref unit) => unit.ident(), AnyPrimaryUnit::Package(ref unit) => unit.ident(), AnyPrimaryUnit::PackageInstance(ref unit) => unit.ident(), AnyPrimaryUnit::Context(ref unit) => unit.ident(), } } } impl HasIdent for AnySecondaryUnit { fn ident(&self) -> &Ident { match self { AnySecondaryUnit::PackageBody(ref unit) => unit.ident(), AnySecondaryUnit::Architecture(ref unit) => unit.ident(), } } } impl HasIdent for AnyDesignUnit { fn ident(&self) -> &Ident { match self { AnyDesignUnit::Primary(ref unit) => unit.ident(), AnyDesignUnit::Secondary(ref unit) => unit.ident(), } } } impl<'a, T: HasIdent> From<&'a T> for WithToken { fn from(other: &'a T) -> WithToken { other.ident().to_owned().map_into(Designator::Identifier) } } /// Primary identifier in secondary units pub trait HasPrimaryIdent { fn primary_ident(&self) -> &Ident; fn primary_name(&self) -> &Symbol { &self.primary_ident().item } } impl HasPrimaryIdent for ArchitectureBody { fn primary_ident(&self) -> &Ident { &self.entity_name.item } } impl HasPrimaryIdent for PackageBody { fn primary_ident(&self) -> &Ident { &self.ident.tree } } impl HasPrimaryIdent for AnySecondaryUnit { fn primary_ident(&self) -> &Ident { match self { AnySecondaryUnit::Architecture(unit) => unit.primary_ident(), AnySecondaryUnit::PackageBody(unit) => unit.primary_ident(), } } } impl From for Designator { fn from(other: EnumerationLiteral) -> Designator { match other { EnumerationLiteral::Identifier(ident) => Designator::Identifier(ident), EnumerationLiteral::Character(byte) => Designator::Character(byte), } } } impl From for Designator { fn from(other: Symbol) -> Designator { Designator::Identifier(other) } } impl From> for WithTokenSpan { fn from(other: WithTokenSpan) -> WithTokenSpan { other.map_into(|sym| sym.into()) } } impl<'a> From<&'a Symbol> for Designator { fn from(other: &'a Symbol) -> Designator { other.clone().into() } } impl SubprogramDesignator { pub fn into_designator(self) -> Designator { match self { SubprogramDesignator::Identifier(ident) => Designator::Identifier(ident), SubprogramDesignator::OperatorSymbol(ident) => Designator::OperatorSymbol(ident), } } } impl SubprogramSpecification { pub fn token(&self) -> TokenId { match self { SubprogramSpecification::Function(ref function) => function.designator.tree.token, SubprogramSpecification::Procedure(ref procedure) => procedure.designator.tree.token, } } } impl EnumerationLiteral { pub fn into_designator(self) -> Designator { match self { EnumerationLiteral::Identifier(ident) => Designator::Identifier(ident), EnumerationLiteral::Character(byte) => Designator::Character(byte), } } } impl Designator { pub fn as_identifier(&self) -> Option<&Symbol> { if let Designator::Identifier(sym) = self { Some(sym) } else { None } } pub fn expect_identifier(&self) -> &Symbol { self.as_identifier().unwrap() } pub fn describe(&self) -> String { match self { Designator::Character(chr) => format!("'{chr}'"), Designator::Identifier(ident) => format!("'{ident}'"), Designator::OperatorSymbol(op) => format!("operator \"{op}\""), Designator::Anonymous(_) => "".to_owned(), } } } impl Name { pub fn suffix_reference_mut(&mut self) -> Option<&mut Reference> { match self { Name::Designator(suffix) => Some(&mut suffix.reference), Name::Selected(_, suffix) => Some(&mut suffix.item.reference), _ => None, } } // Get an already set suffix reference such as when an ambiguous overloaded call has already been resolved pub fn get_suffix_reference(&self) -> Option { match self { Name::Designator(suffix) => suffix.reference.get(), Name::Selected(_, suffix) => suffix.item.reference.get(), _ => None, } } pub fn prefix(&self) -> Option<&Designator> { match self { Self::Attribute(attr) => attr.name.item.prefix(), Self::Designator(d) => Some(d.designator()), Self::External(..) => None, Self::CallOrIndexed(fcall) => fcall.name.item.prefix(), Self::SelectedAll(name) => name.item.prefix(), Self::Selected(name, ..) => name.item.prefix(), Self::Slice(name, ..) => name.item.prefix(), } } /// Returns true if the name is purely a selected name /// Example: a.b.c pub fn is_selected_name(&self) -> bool { match self { Name::Designator(_) => true, Name::Selected(prefix, _) => prefix.item.is_selected_name(), _ => false, } } } impl CallOrIndexed { // During parsing function calls and indexed names are ambiguous // Thus we convert function calls to indexed names during the analysis stage pub fn as_indexed(&mut self) -> Option> { if !self.could_be_indexed_name() { return None; } let CallOrIndexed { ref mut name, ref mut parameters, } = self; let mut indexes: Vec> = Vec::with_capacity(parameters.items.len()); for elem in parameters.items.iter_mut() { if let ActualPart::Expression(ref mut expr) = &mut elem.actual.item { indexes.push(Index { pos: elem.actual.span, expr, }); } } Some(IndexedName { name, indexes }) } pub fn could_be_indexed_name(&self) -> bool { self.parameters .items .iter() .all(|assoc| assoc.formal.is_none() && !matches!(assoc.actual.item, ActualPart::Open)) } } pub struct IndexedName<'a> { pub name: &'a mut WithTokenSpan, pub indexes: Vec>, } pub struct Index<'a> { pub pos: TokenSpan, pub expr: &'a mut Expression, } impl AttributeName { pub fn as_range(&self) -> Option { if let AttributeDesignator::Range(r) = self.attr.item { Some(r) } else { None } } pub fn as_type(&self) -> Option { if self.signature.is_none() && self.expr.is_none() { if let AttributeDesignator::Type(t) = self.attr.item { Some(t) } else { None } } else { None } } } impl RangeConstraint { pub fn span(&self) -> TokenSpan { self.left_expr.span.combine(self.right_expr.span) } } impl crate::ast::Range { pub fn span(&self) -> TokenSpan { use crate::ast::Range::*; match self { Range(constraint) => constraint.span(), Attribute(attr) => attr.name.span.end_with(attr.attr.token), } } } impl DiscreteRange { pub fn span(&self) -> TokenSpan { match self { DiscreteRange::Discrete(type_mark, _) => type_mark.span, DiscreteRange::Range(range) => range.span(), } } } impl SubprogramSpecification { pub fn subpgm_designator(&self) -> &WithToken { match self { SubprogramSpecification::Procedure(s) => &s.designator.tree, SubprogramSpecification::Function(s) => &s.designator.tree, } } pub fn reference_mut(&mut self) -> &mut Reference { match self { SubprogramSpecification::Function(ref mut function) => &mut function.designator.decl, SubprogramSpecification::Procedure(ref mut procedure) => &mut procedure.designator.decl, } } } impl SubprogramDeclaration { pub fn subpgm_designator(&self) -> &WithToken { self.specification.subpgm_designator() } pub fn reference_mut(&mut self) -> &mut Reference { self.specification.reference_mut() } } impl ConcurrentStatement { pub fn label_typ(&self) -> Option { use ConcurrentStatement::*; match self { ProcedureCall(_) => None, Block(_) => Some(Concurrent::Block), Process(_) => Some(Concurrent::Process), Assert(_) => None, Assignment(_) => None, Instance(_) => Some(Concurrent::Instance), ForGenerate(_) | IfGenerate(_) | CaseGenerate(_) => Some(Concurrent::Generate), } } pub fn end_label_pos(&self) -> Option<&SrcPos> { use ConcurrentStatement::*; match self { ProcedureCall(_) => None, Block(value) => value.end_label_pos.as_ref(), Process(value) => value.end_label_pos.as_ref(), Assert(_) => None, Assignment(_) => None, Instance(_) => None, ForGenerate(value) => value.end_label_pos.as_ref(), IfGenerate(value) => value.end_label_pos.as_ref(), CaseGenerate(value) => value.end_label_pos.as_ref(), } } pub fn can_have_label(&self) -> bool { self.label_typ().is_some() } } impl SequentialStatement { pub fn label_typ(&self) -> Option { use SequentialStatement::*; match self { Wait(_) => None, Assert(_) => None, Report(_) => None, VariableAssignment(_) => None, SignalAssignment(_) => None, SignalForceAssignment(_) => None, SignalReleaseAssignment(_) => None, ProcedureCall(_) => None, If(_) => Some(Sequential::If), Case(_) => Some(Sequential::Case), Loop(_) => Some(Sequential::Loop), Next(_) => None, Exit(_) => None, Return(_) => None, Null => None, } } pub fn end_label_pos(&self) -> Option<&SrcPos> { use SequentialStatement::*; match self { Wait(_) => None, Assert(_) => None, Report(_) => None, VariableAssignment(_) => None, SignalAssignment(_) => None, SignalForceAssignment(_) => None, SignalReleaseAssignment(_) => None, ProcedureCall(_) => None, If(value) => value.end_label_pos.as_ref(), Case(value) => value.end_label_pos.as_ref(), Loop(value) => value.end_label_pos.as_ref(), Next(_) => None, Exit(_) => None, Return(_) => None, Null => None, } } pub fn can_have_label(&self) -> bool { self.label_typ().is_some() } }