Skip to content

Commit 16c280a

Browse files
committed
Handle 'range attributes as sliced name
1 parent 65503d6 commit 16c280a

File tree

3 files changed

+61
-11
lines changed

3 files changed

+61
-11
lines changed

vhdl_lang/src/ast/util.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,3 +398,12 @@ fn assoc_elems_to_indexes(assoc_elems: &[AssociationElement]) -> Option<Vec<With
398398

399399
Some(result)
400400
}
401+
402+
impl AttributeName {
403+
pub fn is_range(&self) -> bool {
404+
matches!(
405+
self.attr.item,
406+
AttributeDesignator::Range | AttributeDesignator::ReverseRange,
407+
)
408+
}
409+
}

vhdl_lang/src/syntax/names.rs

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -433,14 +433,15 @@ pub fn parse_name_initial_token(
433433
},
434434
RightPar => {
435435
let pos = sep_token.pos.combine_into(&name);
436-
name = WithPos {
437-
item: Name::FunctionCall(Box::new(
438-
FunctionCall {
439-
name,
440-
parameters: vec![assoc]
441-
})),
442-
pos,
436+
let item = match into_range(assoc) {
437+
Ok(range) => Name::Slice(Box::new(name), Box::new(DiscreteRange::Range(range))),
438+
Err(assoc) => Name::FunctionCall(Box::new(FunctionCall {
439+
name,
440+
parameters: vec![assoc],
441+
})),
443442
};
443+
444+
name = WithPos::new(item, pos);
444445
}
445446
)
446447
}
@@ -453,6 +454,31 @@ pub fn parse_name_initial_token(
453454
Ok(name)
454455
}
455456

457+
pub fn into_range(assoc: AssociationElement) -> Result<ast::Range, AssociationElement> {
458+
if assoc.formal.is_some() {
459+
return Err(assoc);
460+
}
461+
462+
if let ActualPart::Expression(Expression::Name(ref name)) = &assoc.actual.item {
463+
if let Name::Attribute(attr) = name.as_ref() {
464+
if attr.is_range() {
465+
if let ActualPart::Expression(Expression::Name(name)) = assoc.actual.item {
466+
if let Name::Attribute(attr) = *name {
467+
return Ok(ast::Range::Attribute(attr));
468+
}
469+
}
470+
unreachable!();
471+
} else {
472+
Err(assoc)
473+
}
474+
} else {
475+
Err(assoc)
476+
}
477+
} else {
478+
Err(assoc)
479+
}
480+
}
481+
456482
pub fn parse_name(stream: &mut TokenStream) -> ParseResult<WithPos<Name>> {
457483
let initial_token = stream.expect()?;
458484
parse_name_initial_token(stream, initial_token)
@@ -462,6 +488,7 @@ pub fn parse_name(stream: &mut TokenStream) -> ParseResult<WithPos<Name>> {
462488
mod tests {
463489
use super::*;
464490
use crate::syntax::test::Code;
491+
use pretty_assertions::assert_eq;
465492

466493
#[test]
467494
fn test_parse_selected_name_single() {
@@ -660,6 +687,23 @@ mod tests {
660687
assert_eq!(code.with_stream(parse_name), slice);
661688
}
662689

690+
#[test]
691+
fn test_slice_range_attribute() {
692+
let code = Code::new("prefix(foo(0)'range)");
693+
let prefix = WithPos {
694+
item: Name::Designator(Designator::Identifier(code.symbol("prefix")).into_ref()),
695+
pos: code.s1("prefix").pos(),
696+
};
697+
let slice = WithPos {
698+
item: Name::Slice(
699+
Box::new(prefix),
700+
Box::new(code.s1("foo(0)'range").discrete_range()),
701+
),
702+
pos: code.s1("prefix(foo(0)'range)").pos(),
703+
};
704+
assert_eq!(code.with_stream(parse_name), slice);
705+
}
706+
663707
#[test]
664708
fn test_attribute_name() {
665709
let code = Code::new("prefix'foo");

vhdl_lang/src/syntax/range.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,7 @@ fn parse_name_or_range(stream: &mut TokenStream) -> ParseResult<NameOrRange> {
5252
} = expr
5353
{
5454
if let Name::Attribute(attribute_name) = *name {
55-
if matches!(
56-
attribute_name.attr.item,
57-
AttributeDesignator::Range | AttributeDesignator::ReverseRange
58-
) {
55+
if attribute_name.is_range() {
5956
let range = ast::Range::Attribute(attribute_name);
6057
Ok(NameOrRange::Range(WithPos::from(range, pos)))
6158
} else {

0 commit comments

Comments
 (0)