Skip to content

Commit 124c59d

Browse files
committed
Improve loop parameters and attributes
1 parent fed579a commit 124c59d

File tree

11 files changed

+245
-33
lines changed

11 files changed

+245
-33
lines changed

vhdl_lang/src/analysis/concurrent.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,10 @@ impl<'a> AnalyzeContext<'a> {
8585
discrete_range,
8686
body,
8787
} = gen;
88-
self.analyze_discrete_range(scope, discrete_range, diagnostics)?;
88+
let typ = as_fatal(self.discrete_range_type(scope, discrete_range, diagnostics))?;
8989
let nested = scope.nested();
9090
nested.add(
91-
index_name.define(self.arena, AnyEntKind::LoopParameter),
91+
index_name.define(self.arena, AnyEntKind::LoopParameter(typ)),
9292
diagnostics,
9393
);
9494
self.analyze_generate_body(&nested, body, diagnostics)?;

vhdl_lang/src/analysis/named_entity.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ pub enum AnyEntKind<'a> {
4646
ElementDeclaration(Subtype<'a>),
4747
Label,
4848
Object(Object<'a>),
49-
LoopParameter,
49+
LoopParameter(Option<BaseType<'a>>),
5050
PhysicalLiteral(TypeEnt<'a>),
5151
DeferredConstant(Subtype<'a>),
5252
Library,
@@ -103,7 +103,7 @@ impl<'a> AnyEntKind<'a> {
103103
Attribute(..) => "attribute",
104104
Overloaded(overloaded) => overloaded.describe(),
105105
Label => "label",
106-
LoopParameter => "loop parameter",
106+
LoopParameter(_) => "loop parameter",
107107
Object(object) => object.class.describe(),
108108
PhysicalLiteral(..) => "physical literal",
109109
DeferredConstant(..) => "deferred constant",

vhdl_lang/src/analysis/named_entity/types.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,12 +151,12 @@ impl<'a> TypeEnt<'a> {
151151
}
152152
}
153153

154-
pub fn array_type(&self) -> Option<(TypeEnt<'a>, usize)> {
154+
pub fn array_type(&self) -> Option<(TypeEnt<'a>, &'a Vec<Option<BaseType<'a>>>)> {
155155
if let Type::Array {
156156
elem_type, indexes, ..
157157
} = self.base_type().kind()
158158
{
159-
Some((*elem_type, indexes.len()))
159+
Some((*elem_type, indexes))
160160
} else if let Some(accessed_typ) = self.accessed_type() {
161161
accessed_typ.array_type()
162162
} else {

vhdl_lang/src/analysis/names.rs

Lines changed: 184 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ impl<'a> ResolvedName<'a> {
157157
| AnyEntKind::Attribute(_)
158158
| AnyEntKind::ElementDeclaration(_)
159159
| AnyEntKind::Label
160-
| AnyEntKind::LoopParameter => {
160+
| AnyEntKind::LoopParameter(_) => {
161161
return Err(format!(
162162
"{} cannot be selected from design unit",
163163
ent.kind().describe()
@@ -207,7 +207,7 @@ impl<'a> ResolvedName<'a> {
207207
| AnyEntKind::InterfaceFile(_)
208208
| AnyEntKind::Component(_)
209209
| AnyEntKind::Label
210-
| AnyEntKind::LoopParameter
210+
| AnyEntKind::LoopParameter(_)
211211
| AnyEntKind::PhysicalLiteral(_) => ResolvedName::Final(ent),
212212
AnyEntKind::Attribute(_) | AnyEntKind::ElementDeclaration(_) => {
213213
return Err(format!(
@@ -329,9 +329,8 @@ impl<'a> AnalyzeContext<'a> {
329329
))
330330
}
331331
ResolvedName::Final(ent) => match ent.actual_kind() {
332-
AnyEntKind::LoopParameter => {
333-
// TODO cannot handle yet
334-
Ok(None)
332+
AnyEntKind::LoopParameter(typ) => {
333+
Ok(typ.map(|typ| DisambiguatedType::Unambiguous(typ.into())))
335334
}
336335
AnyEntKind::PhysicalLiteral(typ) => Ok(Some(DisambiguatedType::Unambiguous(*typ))),
337336
AnyEntKind::File(subtype) => {
@@ -373,10 +372,7 @@ impl<'a> AnalyzeContext<'a> {
373372
))
374373
}
375374
ResolvedName::Final(ent) => match ent.actual_kind() {
376-
AnyEntKind::LoopParameter => {
377-
// TODO cannot handle yet
378-
Ok(None)
379-
}
375+
AnyEntKind::LoopParameter(typ) => Ok(typ.map(|typ| typ.into())),
380376
AnyEntKind::PhysicalLiteral(typ) => Ok(Some(*typ)),
381377
AnyEntKind::File(subtype) => Ok(Some(subtype.type_mark())),
382378
AnyEntKind::InterfaceFile(typ) => Ok(Some(*typ)),
@@ -502,7 +498,7 @@ impl<'a> AnalyzeContext<'a> {
502498
} else {
503499
None
504500
}),
505-
// @TODO attribute not handled
501+
// @TODO attribute is handled elesewhere
506502
Suffix::Attribute(_) => Ok(None),
507503
// @TODO Prefix must non-overloaded
508504
Suffix::CallOrIndexed(assocs) => {
@@ -518,7 +514,8 @@ impl<'a> AnalyzeContext<'a> {
518514
if could_be_indexed_name(assocs) {
519515
// @TODO check types of indexes
520516
self.analyze_assoc_elems(scope, assocs, diagnostics)?;
521-
if let Some((elem_type, num_indexes)) = prefix_typ.array_type() {
517+
if let Some((elem_type, indexes)) = prefix_typ.array_type() {
518+
let num_indexes = indexes.len();
522519
if assocs.len() != num_indexes {
523520
Err(Diagnostic::dimension_mismatch(
524521
name_pos,
@@ -540,6 +537,46 @@ impl<'a> AnalyzeContext<'a> {
540537
}
541538
}
542539

540+
pub fn attribute_suffix(
541+
&self,
542+
typ: TypeEnt<'a>,
543+
attr: &mut AttributeSuffix,
544+
) -> EvalResult<Option<BaseType<'a>>> {
545+
match attr.attr.item {
546+
// @TODO check that it is a scalar type
547+
AttributeDesignator::Left
548+
| AttributeDesignator::Right
549+
| AttributeDesignator::High
550+
| AttributeDesignator::Low => {
551+
if let Some((_, indexes)) = typ.array_type() {
552+
if attr.expr.is_none() {
553+
// @TODO could also be 'left(2) for different dimensions
554+
Ok(Some(indexes.first().unwrap().unwrap()))
555+
} else {
556+
Err(EvalError::Unknown)
557+
}
558+
} else {
559+
match typ.base().kind() {
560+
Type::Enum(_)
561+
| Type::Integer
562+
| Type::Real
563+
| Type::Physical
564+
| Type::Universal(_) => Ok(Some(typ.into())),
565+
_ => Ok(None),
566+
}
567+
}
568+
}
569+
AttributeDesignator::Length => {
570+
if typ.array_type().is_some() {
571+
Ok(Some(self.universal_integer()))
572+
} else {
573+
Ok(None)
574+
}
575+
}
576+
_ => Err(EvalError::Unknown),
577+
}
578+
}
579+
543580
pub fn name_resolve(
544581
&self,
545582
scope: &Scope<'a>,
@@ -645,18 +682,54 @@ impl<'a> AnalyzeContext<'a> {
645682
}
646683
}
647684

648-
if let Suffix::Attribute(attr) = suffix {
649-
if let Some(signature) = attr.signature {
650-
if let Err(e) = self.resolve_signature(scope, signature) {
651-
diagnostics.push(e.into_non_fatal()?);
685+
// Attributes for non-types not handled yet
686+
if let Suffix::Attribute(ref mut attr) = suffix {
687+
let typ = match resolved {
688+
ResolvedName::Type(typ) => typ,
689+
ResolvedName::ObjectName(oname) => oname.type_mark(),
690+
ResolvedName::Expression(DisambiguatedType::Unambiguous(typ)) => typ,
691+
_ => {
692+
// @TODO ignore for now
693+
if let Some(signature) = attr.signature {
694+
if let Err(e) = self.resolve_signature(scope, signature) {
695+
diagnostics.push(e.into_non_fatal()?);
696+
}
697+
}
698+
if let Some(expr) = attr.expr {
699+
self.analyze_expression(scope, expr, diagnostics)?;
700+
}
701+
702+
// @TODO not handled yet
703+
return Err(EvalError::Unknown);
652704
}
653-
}
654-
if let Some(expr) = attr.expr {
655-
self.analyze_expression(scope, expr, diagnostics)?;
656-
}
705+
};
706+
707+
return match self.attribute_suffix(typ, attr) {
708+
Ok(Some(typ)) => Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous(
709+
typ.into(),
710+
))),
711+
Ok(None) => {
712+
diagnostics.push(Diagnostic::cannot_be_prefix(name_pos, resolved, suffix));
713+
Err(EvalError::Unknown)
714+
}
715+
Err(EvalError::Unknown) => {
716+
// @TODO ignore for now
717+
if let Some(signature) = attr.signature {
718+
if let Err(e) = self.resolve_signature(scope, signature) {
719+
diagnostics.push(e.into_non_fatal()?);
720+
}
721+
}
722+
if let Some(expr) = attr.expr {
723+
self.analyze_expression(scope, expr, diagnostics)?;
724+
}
657725

658-
// @TODO not handled yet
659-
return Err(EvalError::Unknown);
726+
// @TODO not handled yet
727+
return Err(EvalError::Unknown);
728+
}
729+
Err(err) => {
730+
return Err(err);
731+
}
732+
};
660733
}
661734

662735
match resolved {
@@ -830,6 +903,7 @@ impl<'a> AnalyzeContext<'a> {
830903
)));
831904
}
832905
}
906+
833907
diagnostics.push(Diagnostic::cannot_be_prefix(name_pos, resolved, suffix));
834908
return Err(EvalError::Unknown);
835909
}
@@ -1636,4 +1710,93 @@ variable c0 : integer_vector(0 to 6);
16361710
)],
16371711
)
16381712
}
1713+
1714+
#[test]
1715+
fn scalar_type_attribute() {
1716+
let test = TestSetup::new();
1717+
let code = test.snippet("integer'left");
1718+
assert_eq!(
1719+
test.name_resolve(&code, None, &mut NoDiagnostics),
1720+
Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous(
1721+
test.lookup_type("integer")
1722+
)))
1723+
);
1724+
let code = test.snippet("integer'right");
1725+
assert_eq!(
1726+
test.name_resolve(&code, None, &mut NoDiagnostics),
1727+
Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous(
1728+
test.lookup_type("integer")
1729+
)))
1730+
);
1731+
let code = test.snippet("integer'high");
1732+
assert_eq!(
1733+
test.name_resolve(&code, None, &mut NoDiagnostics),
1734+
Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous(
1735+
test.lookup_type("integer")
1736+
)))
1737+
);
1738+
let code = test.snippet("integer'low");
1739+
assert_eq!(
1740+
test.name_resolve(&code, None, &mut NoDiagnostics),
1741+
Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous(
1742+
test.lookup_type("integer")
1743+
)))
1744+
);
1745+
}
1746+
1747+
#[test]
1748+
fn array_type_attribute() {
1749+
let test = TestSetup::new();
1750+
test.declarative_part(
1751+
"
1752+
type arr_t is array (integer range 0 to 3) of integer;
1753+
",
1754+
);
1755+
let code = test.snippet("arr_t'left");
1756+
assert_eq!(
1757+
test.name_resolve(&code, None, &mut NoDiagnostics),
1758+
Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous(
1759+
test.lookup_type("integer")
1760+
)))
1761+
);
1762+
}
1763+
1764+
#[test]
1765+
fn length_attribute_of_array_type() {
1766+
let test = TestSetup::new();
1767+
1768+
test.declarative_part(
1769+
"
1770+
type arr_t is array (integer range 0 to 3) of integer;
1771+
",
1772+
);
1773+
1774+
let code = test.snippet("arr_t'length");
1775+
assert_eq!(
1776+
test.name_resolve(&code, None, &mut NoDiagnostics),
1777+
Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous(
1778+
test.ctx().universal_integer().into()
1779+
)))
1780+
);
1781+
}
1782+
1783+
#[test]
1784+
fn length_attribute_of_array_object() {
1785+
let test = TestSetup::new();
1786+
1787+
test.declarative_part(
1788+
"
1789+
type arr_t is array (integer range 0 to 3) of integer;
1790+
constant c0 : arr_t := (others => 0);
1791+
",
1792+
);
1793+
1794+
let code = test.snippet("c0'length");
1795+
assert_eq!(
1796+
test.name_resolve(&code, None, &mut NoDiagnostics),
1797+
Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous(
1798+
test.ctx().universal_integer().into()
1799+
)))
1800+
);
1801+
}
16391802
}

vhdl_lang/src/analysis/package_instance.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,11 @@ impl<'a> AnalyzeContext<'a> {
274274
}
275275
AnyEntKind::Label => AnyEntKind::Label,
276276
AnyEntKind::Object(obj) => AnyEntKind::Object(self.map_object(mapping, obj)?),
277-
AnyEntKind::LoopParameter => AnyEntKind::LoopParameter,
277+
AnyEntKind::LoopParameter(typ) => AnyEntKind::LoopParameter(if let Some(typ) = typ {
278+
Some(self.map_type_ent(mapping, (*typ).into())?.base())
279+
} else {
280+
None
281+
}),
278282
AnyEntKind::PhysicalLiteral(typ) => {
279283
AnyEntKind::PhysicalLiteral(self.map_type_ent(mapping, *typ)?)
280284
}

vhdl_lang/src/analysis/range.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,17 @@ impl<'a> AnalyzeContext<'a> {
146146
}
147147
};
148148

149-
if let Type::Array { indexes, .. } = typ.base().kind() {
149+
if let Some((_, indexes)) = typ.array_type() {
150150
Ok(indexes.first().unwrap().unwrap())
151151
} else {
152-
todo!()
152+
diagnostics.error(
153+
&attr.name.pos,
154+
format!(
155+
"{} cannot be prefix of range attribute, array type or object is required",
156+
resolved.describe()
157+
),
158+
);
159+
Err(EvalError::Unknown)
153160
}
154161
}
155162
}
@@ -479,4 +486,23 @@ function myfun return arr_t;
479486
)],
480487
);
481488
}
489+
490+
#[test]
491+
fn range_attribute_name_of_access_type() {
492+
let test = TestSetup::new();
493+
494+
test.declarative_part(
495+
"
496+
type arr_t is array (integer range <>) of boolean;
497+
type ptr_t is access arr_t;
498+
variable v : ptr_t;
499+
",
500+
);
501+
502+
let code = test.snippet("v'range");
503+
assert_eq!(
504+
test.range_type(&code, &mut NoDiagnostics),
505+
Ok(test.lookup_type("integer").base())
506+
);
507+
}
482508
}

vhdl_lang/src/analysis/sequential.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,10 @@ impl<'a> AnalyzeContext<'a> {
125125
} = loop_stmt;
126126
match iteration_scheme {
127127
Some(IterationScheme::For(ref mut index, ref mut drange)) => {
128-
self.analyze_discrete_range(scope, drange, diagnostics)?;
128+
let typ = as_fatal(self.discrete_range_type(scope, drange, diagnostics))?;
129129
let region = scope.nested();
130130
region.add(
131-
self.arena.define(index, AnyEntKind::LoopParameter),
131+
self.arena.define(index, AnyEntKind::LoopParameter(typ)),
132132
diagnostics,
133133
);
134134
self.analyze_sequential_part(&region, statements, diagnostics)?;

0 commit comments

Comments
 (0)