diff --git a/vhdl_lang/src/analysis/association.rs b/vhdl_lang/src/analysis/association.rs index 67b71aac..d7b929d5 100644 --- a/vhdl_lang/src/analysis/association.rs +++ b/vhdl_lang/src/analysis/association.rs @@ -176,7 +176,7 @@ impl<'a> AnalyzeContext<'a> { format!("Ambiguous call to function '{}'", des), ); - diagnostic.add_subprogram_candidates("migth be", &candidates); + diagnostic.add_subprogram_candidates("migth be", candidates); return Err(diagnostic.into()); } else if let Some(ent) = candidates.pop() { diff --git a/vhdl_lang/src/analysis/declarative.rs b/vhdl_lang/src/analysis/declarative.rs index 21246ce7..000fce96 100644 --- a/vhdl_lang/src/analysis/declarative.rs +++ b/vhdl_lang/src/analysis/declarative.rs @@ -141,7 +141,7 @@ impl<'a> AnalyzeContext<'a> { match resolved_name { ResolvedName::ObjectName(oname) => { if let Some(ref signature) = signature { - diagnostics.push(signature_error(signature)); + diagnostics.push(Diagnostic::should_not_have_signature("Alias", signature)); } match oname.base { ObjectBase::Object(base_object) => AnyEntKind::ObjectAlias { @@ -166,7 +166,7 @@ impl<'a> AnalyzeContext<'a> { | ResolvedName::Design(_) | ResolvedName::Expression(_) => { if let Some(ref signature) = signature { - diagnostics.push(signature_error(signature)); + diagnostics.push(Diagnostic::should_not_have_signature("Alias", signature)); } diagnostics.error( &name.pos, @@ -176,7 +176,7 @@ impl<'a> AnalyzeContext<'a> { } ResolvedName::Type(typ) => { if let Some(ref signature) = signature { - diagnostics.push(signature_error(signature)); + diagnostics.push(Diagnostic::should_not_have_signature("Alias", signature)); } AnyEntKind::Type(Type::Alias(typ)) } @@ -190,22 +190,11 @@ impl<'a> AnalyzeContext<'a> { } AnyEntKind::Overloaded(Overloaded::Alias(ent)) } else { - let mut diagnostic = Diagnostic::error( - name, - format!( - "Could not find declaration of {} with given signature", - des.item.describe() - ), - ); - for ent in overloaded.entities() { - if let Some(pos) = ent.decl_pos() { - diagnostic.add_related( - pos, - format!("Found {}", ent.describe()), - ); - } - } - diagnostics.push(diagnostic); + diagnostics.push(Diagnostic::no_overloaded_with_signature( + &des.pos, + &des.item, + &overloaded, + )); return Ok(None); } } @@ -215,10 +204,7 @@ impl<'a> AnalyzeContext<'a> { } } } else { - diagnostics.error( - name, - "Signature required for alias of subprogram and enum literals", - ); + diagnostics.push(Diagnostic::signature_required(name)); return Ok(None); } } @@ -350,17 +336,107 @@ impl<'a> AnalyzeContext<'a> { } Declaration::Attribute(ref mut attr) => match attr { Attribute::Declaration(ref mut attr_decl) => { - if let Err(err) = self.resolve_type_mark(scope, &mut attr_decl.type_mark) { - err.add_to(diagnostics)?; + match self.resolve_type_mark(scope, &mut attr_decl.type_mark) { + Ok(typ) => { + scope.add( + self.arena + .define(&mut attr_decl.ident, AnyEntKind::Attribute(typ)), + diagnostics, + ); + } + Err(err) => { + err.add_to(diagnostics)?; + } } - scope.add( - self.arena - .define(&mut attr_decl.ident, AnyEntKind::Attribute), - diagnostics, - ); } // @TODO Ignored for now - Attribute::Specification(..) => {} + Attribute::Specification(ref mut attr_spec) => { + let AttributeSpecification { + ident, + entity_name, + // @TODO also check the entity class + entity_class: _, + expr, + } = attr_spec; + + match scope.lookup( + &ident.item.pos, + &Designator::Identifier(ident.item.name().clone()), + ) { + Ok(NamedEntities::Single(ent)) => { + ident.set_unique_reference(ent); + if let AnyEntKind::Attribute(typ) = ent.actual_kind() { + self.analyze_expression_with_target_type( + scope, + *typ, + &expr.pos, + &mut expr.item, + diagnostics, + )?; + } else { + diagnostics.error( + &ident.item.pos, + format!("{} is not an attribute", ent.describe()), + ); + } + } + Ok(NamedEntities::Overloaded(_)) => { + diagnostics.error( + &ident.item.pos, + format!("Overloaded name '{}' is not an attribute", ident.item), + ); + } + Err(err) => { + diagnostics.push(err); + } + } + + if let EntityName::Name(EntityTag { + designator, + signature, + }) = entity_name + { + match scope.lookup(&designator.pos, &designator.item.item) { + Ok(NamedEntities::Single(ent)) => { + designator.set_unique_reference(ent); + + if let Some(signature) = signature { + diagnostics.push(Diagnostic::should_not_have_signature( + "Attribute specification", + &signature.pos, + )); + } + } + Ok(NamedEntities::Overloaded(overloaded)) => { + if let Some(signature) = signature { + match self.resolve_signature(scope, signature) { + Ok(signature_key) => { + if let Some(ent) = overloaded.get(&signature_key) { + designator.set_unique_reference(&ent); + } else { + diagnostics.push( + Diagnostic::no_overloaded_with_signature( + &designator.pos, + &designator.item.item, + &overloaded, + ), + ); + } + } + Err(err) => { + err.add_to(diagnostics)?; + } + } + } else { + diagnostics.push(Diagnostic::signature_required(designator)); + } + } + Err(err) => { + diagnostics.push(err); + } + } + } + } }, Declaration::SubprogramBody(ref mut body) => { let subpgm_region = scope.nested(); @@ -1119,11 +1195,39 @@ fn find_full_type_definition<'a>( None } -fn signature_error(pos: impl AsRef) -> Diagnostic { - Diagnostic::error( - pos, - "Alias should only have a signature for subprograms and enum literals", - ) +impl Diagnostic { + fn no_overloaded_with_signature( + pos: &SrcPos, + des: &Designator, + overloaded: &OverloadedName, + ) -> Diagnostic { + let mut diagnostic = Diagnostic::error( + pos, + format!( + "Could not find declaration of {} with given signature", + des.describe() + ), + ); + diagnostic.add_subprogram_candidates("Found", overloaded.entities()); + diagnostic + } + + fn should_not_have_signature(prefix: &str, pos: impl AsRef) -> Diagnostic { + Diagnostic::error( + pos, + format!( + "{} should only have a signature for subprograms and enum literals", + prefix + ), + ) + } + + fn signature_required(pos: impl AsRef) -> Diagnostic { + Diagnostic::error( + pos, + "Signature required for alias of subprogram and enum literals", + ) + } } /// @TODO A simple and incomplete way to disambiguate integer and real in standard.vhd diff --git a/vhdl_lang/src/analysis/expression.rs b/vhdl_lang/src/analysis/expression.rs index 37ac4ca4..54e06cde 100644 --- a/vhdl_lang/src/analysis/expression.rs +++ b/vhdl_lang/src/analysis/expression.rs @@ -168,7 +168,7 @@ impl<'a> AnalyzeContext<'a> { format!("Found no match for {}", designator.describe()), ); - diag.add_subprogram_candidates("Does not match", &overloaded); + diag.add_subprogram_candidates("Does not match", overloaded); diagnostics.push(diag); Ok(None) } else if type_candidates.len() == 1 { diff --git a/vhdl_lang/src/analysis/named_entity.rs b/vhdl_lang/src/analysis/named_entity.rs index 7b08841e..44529528 100644 --- a/vhdl_lang/src/analysis/named_entity.rs +++ b/vhdl_lang/src/analysis/named_entity.rs @@ -40,7 +40,7 @@ pub enum AnyEntKind<'a> { File(Subtype<'a>), InterfaceFile(TypeEnt<'a>), Component(Region<'a>), - Attribute, + Attribute(TypeEnt<'a>), Overloaded(Overloaded<'a>), Type(Type<'a>), ElementDeclaration(Subtype<'a>), @@ -109,7 +109,7 @@ impl<'a> AnyEntKind<'a> { InterfaceFile(..) => "file", ElementDeclaration(..) => "element declaration", Component(..) => "component", - Attribute => "attribute", + Attribute(..) => "attribute", Overloaded(overloaded) => overloaded.describe(), Label => "label", LoopParameter => "loop parameter", diff --git a/vhdl_lang/src/analysis/names.rs b/vhdl_lang/src/analysis/names.rs index a5399687..9096c970 100644 --- a/vhdl_lang/src/analysis/names.rs +++ b/vhdl_lang/src/analysis/names.rs @@ -166,7 +166,7 @@ impl<'a> ResolvedName<'a> { | AnyEntKind::PhysicalLiteral(_) => ResolvedName::Final(ent), AnyEntKind::Design(_) | AnyEntKind::Library - | AnyEntKind::Attribute + | AnyEntKind::Attribute(_) | AnyEntKind::ElementDeclaration(_) | AnyEntKind::Label | AnyEntKind::LoopParameter => { @@ -221,7 +221,7 @@ impl<'a> ResolvedName<'a> { | AnyEntKind::Label | AnyEntKind::LoopParameter | AnyEntKind::PhysicalLiteral(_) => ResolvedName::Final(ent), - AnyEntKind::Attribute | AnyEntKind::ElementDeclaration(_) => { + AnyEntKind::Attribute(_) | AnyEntKind::ElementDeclaration(_) => { return Err(format!( "{} should never be looked up from the current scope", ent.kind().describe() @@ -407,7 +407,7 @@ impl<'a> AnalyzeContext<'a> { Ok(Some(ent.return_type().unwrap())) } Disambiguated::Ambiguous(overloaded) => { - Err(Diagnostic::ambiguous_call(des, &overloaded)) + Err(Diagnostic::ambiguous_call(des, overloaded)) } } } else { @@ -1214,7 +1214,10 @@ impl Diagnostic { ) } - fn ambiguous_call(call_name: &WithPos, candidates: &[OverloadedEnt]) -> Diagnostic { + fn ambiguous_call<'a>( + call_name: &WithPos, + candidates: impl IntoIterator>, + ) -> Diagnostic { let mut diag = Diagnostic::error( &call_name.pos, format!("Ambiguous call to {}", call_name.item.describe()), diff --git a/vhdl_lang/src/analysis/overloaded.rs b/vhdl_lang/src/analysis/overloaded.rs index be35d038..ba8fa0fe 100644 --- a/vhdl_lang/src/analysis/overloaded.rs +++ b/vhdl_lang/src/analysis/overloaded.rs @@ -222,7 +222,7 @@ impl<'a> AnalyzeContext<'a> { &call_name.pos, format!("Could not resolve call to '{}'", call_name.designator()), ); - diag.add_subprogram_candidates("Does not match", &all_overloaded); + diag.add_subprogram_candidates("Does not match", all_overloaded); diagnostics.push(diag); return Ok(None); } @@ -262,7 +262,7 @@ impl<'a> AnalyzeContext<'a> { &call_name.pos, format!("Could not resolve call to '{}'", call_name.designator()), ); - diag.add_subprogram_candidates("Does not match", &overloaded); + diag.add_subprogram_candidates("Does not match", overloaded); diagnostics.push(diag); Ok(None) }; @@ -313,7 +313,7 @@ impl<'a> AnalyzeContext<'a> { &call_name.pos, format!("Could not resolve call to '{}'", call_name.designator()), ); - diag.add_subprogram_candidates("Does not match", &overloaded); + diag.add_subprogram_candidates("Does not match", overloaded); diagnostics.push(diag); Ok(None) } else { diff --git a/vhdl_lang/src/analysis/semantic.rs b/vhdl_lang/src/analysis/semantic.rs index 1e8a8d5a..09719bc0 100644 --- a/vhdl_lang/src/analysis/semantic.rs +++ b/vhdl_lang/src/analysis/semantic.rs @@ -309,8 +309,12 @@ impl<'a> AnalyzeContext<'a> { } impl Diagnostic { - pub fn add_subprogram_candidates(&mut self, prefix: &str, candidates: &[OverloadedEnt]) { - let mut candidates = candidates.to_vec(); + pub fn add_subprogram_candidates<'a>( + &mut self, + prefix: &str, + candidates: impl IntoIterator>, + ) { + let mut candidates: Vec<_> = candidates.into_iter().collect(); candidates.sort_by(|x, y| x.decl_pos().cmp(&y.decl_pos())); for ent in candidates { diff --git a/vhdl_lang/src/analysis/tests/resolves_names.rs b/vhdl_lang/src/analysis/tests/resolves_names.rs index c7449273..14e9a595 100644 --- a/vhdl_lang/src/analysis/tests/resolves_names.rs +++ b/vhdl_lang/src/analysis/tests/resolves_names.rs @@ -1606,3 +1606,99 @@ constant good1 : integer := i0 + i0; check_no_diagnostics(&diagnostics); } + +#[test] +fn attribute_happy_path() { + let mut builder = LibraryBuilder::new(); + let code = builder.in_declarative_region( + " +constant c0 : string := \"block\"; +attribute ram_style : string; +signal ram : integer_vector(0 to 15); + +attribute ram_style of ram : signal is c0; + ", + ); + + let (root, diagnostics) = builder.get_analyzed_root(); + check_no_diagnostics(&diagnostics); + + { + // References in the expression + let ref_pos = code.s1("signal is c0;").s1("c0"); + let decl = root + .search_reference(code.source(), ref_pos.start()) + .unwrap(); + assert_eq!(code.s1("c0").pos(), decl.decl_pos().cloned().unwrap()); + } + { + // References to the attribute itself + let ref_pos = code.s1("attribute ram_style of").s1("ram_style"); + let decl = root + .search_reference(code.source(), ref_pos.start()) + .unwrap(); + assert_eq!( + code.s1("attribute ram_style").s1("ram_style").pos(), + decl.decl_pos().cloned().unwrap() + ); + } + + { + // References to the named entity + let ref_pos = code.s1("of ram").s1("ram"); + let decl = root + .search_reference(code.source(), ref_pos.start()) + .unwrap(); + assert_eq!( + code.s1("signal ram").s1("ram").pos(), + decl.decl_pos().cloned().unwrap() + ); + } +} + +#[test] +fn attribute_missing_names() { + let mut builder = LibraryBuilder::new(); + let code = builder.in_declarative_region( + " +constant c0 : string := \"block\"; +attribute ram_style : string; +signal ram : integer_vector(0 to 15); + +attribute missing1 of ram : signal is c0; +attribute ram_style of missing2 : signal is c0; +attribute ram_style of ram : signal is missing3; + ", + ); + + let diagnostics = builder.analyze(); + check_diagnostics( + diagnostics, + vec![ + Diagnostic::error(code.s1("missing1"), "No declaration of 'missing1'"), + Diagnostic::error(code.s1("missing2"), "No declaration of 'missing2'"), + Diagnostic::error(code.s1("missing3"), "No declaration of 'missing3'"), + ], + ); +} + +#[test] +fn attribute_spec_with_non_attribute() { + let mut builder = LibraryBuilder::new(); + let code = builder.in_declarative_region( + " +constant bad : natural := 0; +signal ram : integer_vector(0 to 15); +attribute bad of ram : signal is 0; + ", + ); + + let diagnostics = builder.analyze(); + check_diagnostics( + diagnostics, + vec![Diagnostic::error( + code.s1("attribute bad").s1("bad"), + "constant 'bad' is not an attribute", + )], + ); +} diff --git a/vhdl_lang/src/analysis/tests/typecheck_expression.rs b/vhdl_lang/src/analysis/tests/typecheck_expression.rs index 2624d9c2..c00915eb 100644 --- a/vhdl_lang/src/analysis/tests/typecheck_expression.rs +++ b/vhdl_lang/src/analysis/tests/typecheck_expression.rs @@ -1096,3 +1096,66 @@ end architecture;", let diagnostics = builder.analyze(); check_no_diagnostics(&diagnostics); } + +#[test] +fn attribute_spec_typecheck() { + let mut builder = LibraryBuilder::new(); + let code = builder.in_declarative_region( + " +attribute ram_style : integer; +signal good, bad : integer_vector(0 to 15); +attribute ram_style of good : signal is 0; +attribute ram_style of bad : signal is 'c'; + ", + ); + + let diagnostics = builder.analyze(); + check_diagnostics( + diagnostics, + vec![Diagnostic::error( + code.s1("'c'"), + "character literal does not match integer type 'INTEGER'", + )], + ); +} + +#[test] +fn attribute_spec_signature() { + let mut builder = LibraryBuilder::new(); + let code = builder.in_declarative_region( + " +attribute ram_style : integer; + +signal good_sig : integer_vector(0 to 15); +signal bad_sig : integer_vector(0 to 15); +attribute ram_style of good_sig : signal is 0; +attribute ram_style of bad_sig[return integer] : signal is 0; + +function good_fun return natural; +function bad_fun1 return natural; +function bad_fun2 return natural; + +attribute ram_style of good_fun[return natural] : signal is 0; +attribute ram_style of bad_fun1 : signal is 0; +attribute ram_style of bad_fun2[return boolean] : signal is 0; + +", + ); + + let diagnostics = builder.analyze(); + check_diagnostics( + diagnostics, + vec![Diagnostic::error( + code.s1("[return integer]"), + "Attribute specification should only have a signature for subprograms and enum literals", + ), + Diagnostic::error( + code.s1("bad_fun1 : signal").s1("bad_fun1"), + "Signature required for alias of subprogram and enum literals", + ), + Diagnostic::error( + code.s1("bad_fun2[return boolean]").s1("bad_fun2"), + "Could not find declaration of 'bad_fun2' with given signature", + ).related(code.s1("bad_fun2"), "Found bad_fun2[return NATURAL]")], + ); +} diff --git a/vhdl_lang/src/ast.rs b/vhdl_lang/src/ast.rs index 46b3cd45..77d55cb4 100644 --- a/vhdl_lang/src/ast.rs +++ b/vhdl_lang/src/ast.rs @@ -448,7 +448,7 @@ pub struct AttributeDeclaration { /// LRM 7.2 Attribute specification #[derive(PartialEq, Debug, Clone)] pub struct EntityTag { - pub designator: WithPos, + pub designator: WithPos>, pub signature: Option>, } @@ -481,7 +481,7 @@ pub enum EntityClass { /// LRM 7.2 Attribute specification #[derive(PartialEq, Debug, Clone)] pub struct AttributeSpecification { - pub ident: WithDecl, + pub ident: WithRef, pub entity_name: EntityName, pub entity_class: EntityClass, pub expr: WithPos, diff --git a/vhdl_lang/src/ast/display.rs b/vhdl_lang/src/ast/display.rs index 2ca0aa0f..86920aaf 100644 --- a/vhdl_lang/src/ast/display.rs +++ b/vhdl_lang/src/ast/display.rs @@ -198,6 +198,12 @@ impl Display for CallOrIndexed { } } +impl Display for AttributeDeclaration { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "attribute {} : {};", self.ident, self.type_mark) + } +} + impl Display for Choice { fn fmt(&self, f: &mut Formatter<'_>) -> Result { match self { diff --git a/vhdl_lang/src/ast/search.rs b/vhdl_lang/src/ast/search.rs index eada3e81..2642428b 100644 --- a/vhdl_lang/src/ast/search.rs +++ b/vhdl_lang/src/ast/search.rs @@ -51,7 +51,7 @@ pub enum FoundDeclaration<'a> { PhysicalTypePrimary(&'a mut WithDecl), PhysicalTypeSecondary(&'a mut WithDecl, &'a mut PhysicalLiteral), Component(&'a mut ComponentDeclaration), - //Attribute(&'a mut AttributeDeclaration), + Attribute(&'a mut AttributeDeclaration), Alias(&'a mut AliasDeclaration), Function(&'a mut FunctionSpecification), Procedure(&'a mut ProcedureSpecification), @@ -917,8 +917,33 @@ impl Search for Declaration { return_if_found!(decl.search(searcher)); } Declaration::Attribute(Attribute::Declaration(decl)) => { + return_if_found!(searcher + .search_decl(FoundDeclaration::Attribute(decl)) + .or_not_found()); return_if_found!(decl.type_mark.search(searcher)); } + Declaration::Attribute(Attribute::Specification(AttributeSpecification { + ident, + entity_name, + entity_class: _, + expr, + })) => { + return_if_found!(searcher.search_ident_ref(ident).or_not_found()); + if let EntityName::Name(EntityTag { + designator, + signature, + }) = entity_name + { + return_if_found!(searcher + .search_pos_with_ref(&designator.pos, &mut designator.item.reference) + .or_not_found()); + if let Some(signature) = signature { + return_if_found!(signature.item.search(searcher)); + } + } + + return_if_found!(expr.search(searcher)); + } Declaration::Alias(alias) => { return_if_found!(searcher .search_decl(FoundDeclaration::Alias(alias)) @@ -1327,6 +1352,7 @@ impl<'a> HasEntityId for FoundDeclaration<'a> { FoundDeclaration::PhysicalTypePrimary(value) => value.decl, FoundDeclaration::PhysicalTypeSecondary(value, _) => value.decl, FoundDeclaration::Component(value) => value.ident.decl, + FoundDeclaration::Attribute(value) => value.ident.decl, FoundDeclaration::Alias(value) => value.designator.decl, FoundDeclaration::Package(value) => value.ident.decl, FoundDeclaration::PackageInstance(value) => value.ident.decl, @@ -1357,6 +1383,7 @@ impl<'a> HasSrcPos for FoundDeclaration<'a> { FoundDeclaration::PhysicalTypeSecondary(value, _) => value.as_ref(), FoundDeclaration::Component(value) => value.ident.pos(), FoundDeclaration::Alias(value) => &value.designator.tree.pos, + FoundDeclaration::Attribute(value) => value.ident.pos(), FoundDeclaration::Package(value) => value.ident.pos(), FoundDeclaration::PackageInstance(value) => value.ident.pos(), FoundDeclaration::Configuration(value) => value.ident.pos(), @@ -1417,6 +1444,9 @@ impl std::fmt::Display for FoundDeclaration<'_> { FoundDeclaration::Alias(ref value) => { write!(f, "{}", value) } + FoundDeclaration::Attribute(ref value) => { + write!(f, "{}", value) + } FoundDeclaration::Package(ref value) => { write!(f, "{}", value) } diff --git a/vhdl_lang/src/syntax/attributes.rs b/vhdl_lang/src/syntax/attributes.rs index f69b0d9d..087c7cce 100644 --- a/vhdl_lang/src/syntax/attributes.rs +++ b/vhdl_lang/src/syntax/attributes.rs @@ -11,7 +11,7 @@ use super::subprogram::parse_signature; use super::tokens::{Kind::*, TokenStream}; use crate::ast::{ Attribute, AttributeDeclaration, AttributeSpecification, Designator, EntityClass, EntityName, - EntityTag, + EntityTag, WithRef, }; fn parse_entity_class(stream: &mut TokenStream) -> ParseResult { @@ -55,7 +55,7 @@ pub fn parse_entity_name_list(stream: &mut TokenStream) -> ParseResult ParseResult> .into_iter() .map(|entity_name| { Attribute::Specification(AttributeSpecification { - ident: ident.clone().into(), + ident: WithRef::new(ident.clone()), entity_name, entity_class, expr: expr.clone(), @@ -144,9 +144,9 @@ mod tests { assert_eq!( code.with_stream(parse_attribute), vec![Attribute::Specification(AttributeSpecification { - ident: code.s1("attr_name").decl_ident(), + ident: WithRef::new(code.s1("attr_name").ident()), entity_name: EntityName::Name(EntityTag { - designator: code.s1("foo").designator(), + designator: code.s1("foo").ref_designator(), signature: None }), entity_class: EntityClass::Signal, @@ -161,9 +161,9 @@ mod tests { assert_eq!( code.with_stream(parse_attribute), vec![Attribute::Specification(AttributeSpecification { - ident: code.s1("attr_name").decl_ident(), + ident: WithRef::new(code.s1("attr_name").ident()), entity_name: EntityName::Name(EntityTag { - designator: code.s1("\"**\"").designator(), + designator: code.s1("\"**\"").ref_designator(), signature: None }), entity_class: EntityClass::Function, @@ -179,18 +179,18 @@ mod tests { code.with_stream(parse_attribute), vec![ Attribute::Specification(AttributeSpecification { - ident: code.s1("attr_name").decl_ident(), + ident: WithRef::new(code.s1("attr_name").ident()), entity_name: EntityName::Name(EntityTag { - designator: code.s1("foo").designator(), + designator: code.s1("foo").ref_designator(), signature: None }), entity_class: EntityClass::Signal, expr: code.s1("0+1").expr() }), Attribute::Specification(AttributeSpecification { - ident: code.s1("attr_name").decl_ident(), + ident: WithRef::new(code.s1("attr_name").ident()), entity_name: EntityName::Name(EntityTag { - designator: code.s1("bar").designator(), + designator: code.s1("bar").ref_designator(), signature: None }), entity_class: EntityClass::Signal, @@ -206,7 +206,7 @@ mod tests { assert_eq!( code.with_stream(parse_attribute), vec![Attribute::Specification(AttributeSpecification { - ident: code.s1("attr_name").decl_ident(), + ident: WithRef::new(code.s1("attr_name").ident()), entity_name: EntityName::All, entity_class: EntityClass::Signal, expr: code.s1("0+1").expr() @@ -220,7 +220,7 @@ mod tests { assert_eq!( code.with_stream(parse_attribute), vec![Attribute::Specification(AttributeSpecification { - ident: code.s1("attr_name").decl_ident(), + ident: WithRef::new(code.s1("attr_name").ident()), entity_name: EntityName::Others, entity_class: EntityClass::Signal, expr: code.s1("0+1").expr() @@ -234,9 +234,9 @@ mod tests { assert_eq!( code.with_stream(parse_attribute), vec![Attribute::Specification(AttributeSpecification { - ident: code.s1("attr_name").decl_ident(), + ident: WithRef::new(code.s1("attr_name").ident()), entity_name: EntityName::Name(EntityTag { - designator: code.s1("foo").designator(), + designator: code.s1("foo").ref_designator(), signature: Some(code.s1("[return natural]").signature()) }), entity_class: EntityClass::Function, diff --git a/vhdl_lang/src/syntax/test.rs b/vhdl_lang/src/syntax/test.rs index 89b0b914..c5cc9368 100644 --- a/vhdl_lang/src/syntax/test.rs +++ b/vhdl_lang/src/syntax/test.rs @@ -316,6 +316,9 @@ impl Code { pub fn decl_designator(&self) -> WithDecl> { WithDecl::new(self.parse_ok(parse_designator)) } + pub fn ref_designator(&self) -> WithPos> { + self.parse_ok(parse_designator).map_into(WithRef::new) + } pub fn character(&self) -> WithPos { self.parse_ok(|stream: &mut TokenStream| stream.expect()?.expect_character())