Skip to content

Commit 36c9ca7

Browse files
authored
Merge pull request #186 from Schottkyc137/consecutive-attributes
Feat: Enable type attributes
2 parents b6ae580 + 20ceb37 commit 36c9ca7

File tree

2 files changed

+192
-51
lines changed

2 files changed

+192
-51
lines changed

vhdl_lang/src/analysis/expression.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1453,6 +1453,24 @@ mod test {
14531453
);
14541454
}
14551455

1456+
#[test]
1457+
fn type_attributes_cannot_be_used_as_an_expression() {
1458+
let test = TestSetup::new();
1459+
test.declarative_part("variable x : integer;");
1460+
let code = test.snippet("x'subtype");
1461+
1462+
let mut diagnostics = Vec::new();
1463+
assert_eq!(test.expr_type(&code, &mut diagnostics), None);
1464+
1465+
check_diagnostics(
1466+
diagnostics,
1467+
vec![Diagnostic::error(
1468+
code.s1("x'subtype"),
1469+
"integer type 'INTEGER' cannot be used in an expression",
1470+
)],
1471+
);
1472+
}
1473+
14561474
#[test]
14571475
fn binary_expression_missing_names() {
14581476
let test = TestSetup::new();

vhdl_lang/src/analysis/names.rs

Lines changed: 174 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,31 @@ impl<'a> ResolvedName<'a> {
316316
);
317317
Err(EvalError::Unknown)
318318
}
319+
320+
/// Convenience function that returns `Some(name)` when self is an object name, else `None`
321+
fn as_object_name(&self) -> Option<ObjectName<'a>> {
322+
match self {
323+
ResolvedName::ObjectName(oname) => Some(*oname),
324+
_ => None,
325+
}
326+
}
327+
}
328+
329+
/// Represents the result when resolving an attribute.
330+
/// This can either be a value or a type.
331+
///
332+
/// in the future, the value case might also hold the value
333+
/// of the static expression of the attribute.
334+
///
335+
/// Values are returned for attributes such as `'low`, `'high`, `'val(..)`, e.t.c.
336+
/// Types are returned for attributes such as `'base`, `'subtype`, `'element`
337+
pub enum AttrResolveResult<'a> {
338+
/// The result type is a type. E.g. `a'base`, `a'subtype`, `a'element`
339+
Type(BaseType<'a>),
340+
/// The result type is a value with type, e.g. `a'low`, `b'high`, `c'image(x)`
341+
Value(BaseType<'a>),
319342
}
343+
320344
#[derive(Debug)]
321345
pub struct AttributeSuffix<'a> {
322346
pub signature: &'a mut Option<WithPos<crate::ast::Signature>>,
@@ -712,7 +736,7 @@ impl<'a> AnalyzeContext<'a> {
712736
prefix: &ResolvedName<'a>,
713737
attr: &mut AttributeSuffix,
714738
diagnostics: &mut dyn DiagnosticHandler,
715-
) -> EvalResult<BaseType<'a>> {
739+
) -> EvalResult<AttrResolveResult<'a>> {
716740
match attr.attr.item {
717741
AttributeDesignator::Left
718742
| AttributeDesignator::Right
@@ -726,9 +750,10 @@ impl<'a> AnalyzeContext<'a> {
726750
attr.expr.as_mut().map(|expr| expr.as_mut()),
727751
diagnostics,
728752
)
753+
.map(AttrResolveResult::Value)
729754
} else if typ.is_scalar() {
730755
check_no_attr_argument(attr, diagnostics);
731-
Ok(typ.into())
756+
Ok(AttrResolveResult::Value(typ.into()))
732757
} else {
733758
diagnostics.push(Diagnostic::cannot_be_prefix_of_attribute(
734759
name_pos, prefix, attr,
@@ -740,10 +765,10 @@ impl<'a> AnalyzeContext<'a> {
740765
let typ = prefix.as_type_of_attr_prefix(prefix_pos, attr, diagnostics)?;
741766

742767
if typ.array_type().is_some() {
743-
Ok(self.boolean().base())
768+
Ok(AttrResolveResult::Value(self.boolean().base()))
744769
} else if typ.is_scalar() {
745770
check_no_attr_argument(attr, diagnostics);
746-
Ok(self.boolean().base())
771+
Ok(AttrResolveResult::Value(self.boolean().base()))
747772
} else {
748773
diagnostics.push(Diagnostic::cannot_be_prefix_of_attribute(
749774
name_pos, prefix, attr,
@@ -759,7 +784,7 @@ impl<'a> AnalyzeContext<'a> {
759784
}
760785

761786
if typ.is_scalar() {
762-
Ok(self.string().base())
787+
Ok(AttrResolveResult::Value(self.string().base()))
763788
} else {
764789
diagnostics.push(Diagnostic::cannot_be_prefix_of_attribute(
765790
name_pos, prefix, attr,
@@ -775,7 +800,7 @@ impl<'a> AnalyzeContext<'a> {
775800
}
776801

777802
if typ.is_scalar() {
778-
Ok(typ.base())
803+
Ok(AttrResolveResult::Value(typ.base()))
779804
} else {
780805
diagnostics.push(Diagnostic::cannot_be_prefix_of_attribute(
781806
name_pos, prefix, attr,
@@ -790,7 +815,7 @@ impl<'a> AnalyzeContext<'a> {
790815
if let Some(ref mut expr) = check_single_argument(name_pos, attr, diagnostics) {
791816
self.expr_with_ttyp(scope, typ, expr, diagnostics)?;
792817
}
793-
Ok(self.universal_integer())
818+
Ok(AttrResolveResult::Value(self.universal_integer()))
794819
} else {
795820
diagnostics.push(Diagnostic::cannot_be_prefix_of_attribute(
796821
name_pos, prefix, attr,
@@ -805,7 +830,7 @@ impl<'a> AnalyzeContext<'a> {
805830
if let Some(ref mut expr) = check_single_argument(name_pos, attr, diagnostics) {
806831
self.integer_expr(scope, expr, diagnostics)?;
807832
}
808-
Ok(typ.base())
833+
Ok(AttrResolveResult::Value(typ.base()))
809834
} else {
810835
diagnostics.push(Diagnostic::cannot_be_prefix_of_attribute(
811836
name_pos, prefix, attr,
@@ -823,7 +848,7 @@ impl<'a> AnalyzeContext<'a> {
823848
if let Some(ref mut expr) = check_single_argument(name_pos, attr, diagnostics) {
824849
self.expr_with_ttyp(scope, typ, expr, diagnostics)?;
825850
}
826-
Ok(typ.base())
851+
Ok(AttrResolveResult::Value(typ.base()))
827852
} else {
828853
diagnostics.push(Diagnostic::cannot_be_prefix_of_attribute(
829854
name_pos, prefix, attr,
@@ -835,7 +860,7 @@ impl<'a> AnalyzeContext<'a> {
835860
let typ = prefix.as_type_of_attr_prefix(prefix_pos, attr, diagnostics)?;
836861

837862
if typ.array_type().is_some() {
838-
Ok(self.universal_integer())
863+
Ok(AttrResolveResult::Value(self.universal_integer()))
839864
} else {
840865
diagnostics.push(Diagnostic::cannot_be_prefix_of_attribute(
841866
name_pos, prefix, attr,
@@ -847,7 +872,7 @@ impl<'a> AnalyzeContext<'a> {
847872
| AttributeDesignator::InstanceName
848873
| AttributeDesignator::PathName => {
849874
check_no_attr_argument(attr, diagnostics);
850-
Ok(self.string().base())
875+
Ok(AttrResolveResult::Value(self.string().base()))
851876
}
852877

853878
AttributeDesignator::Signal(sattr) => {
@@ -858,45 +883,45 @@ impl<'a> AnalyzeContext<'a> {
858883
if let Some(expr) = attr.expr {
859884
self.expr_with_ttyp(scope, self.time(), expr, diagnostics)?;
860885
}
861-
Ok(typ.base())
886+
Ok(AttrResolveResult::Value(typ.base()))
862887
}
863888
SignalAttribute::Stable | SignalAttribute::Quiet => {
864889
if let Some(expr) = expr {
865890
self.expr_with_ttyp(scope, self.time(), expr, diagnostics)?;
866891
}
867-
Ok(self.boolean().base())
892+
Ok(AttrResolveResult::Value(self.boolean().base()))
868893
}
869894
SignalAttribute::Transaction => {
870895
check_no_sattr_argument(sattr, expr, diagnostics);
871-
Ok(self.bit().base())
896+
Ok(AttrResolveResult::Value(self.bit().base()))
872897
}
873898
SignalAttribute::Event => {
874899
check_no_sattr_argument(sattr, expr, diagnostics);
875-
Ok(self.boolean().base())
900+
Ok(AttrResolveResult::Value(self.boolean().base()))
876901
}
877902
SignalAttribute::Active => {
878903
check_no_sattr_argument(sattr, expr, diagnostics);
879-
Ok(self.boolean().base())
904+
Ok(AttrResolveResult::Value(self.boolean().base()))
880905
}
881906
SignalAttribute::LastEvent => {
882907
check_no_sattr_argument(sattr, expr, diagnostics);
883-
Ok(self.time().base())
908+
Ok(AttrResolveResult::Value(self.time().base()))
884909
}
885910
SignalAttribute::LastActive => {
886911
check_no_sattr_argument(sattr, expr, diagnostics);
887-
Ok(self.time().base())
912+
Ok(AttrResolveResult::Value(self.time().base()))
888913
}
889914
SignalAttribute::LastValue => {
890915
check_no_sattr_argument(sattr, expr, diagnostics);
891-
Ok(typ.base())
916+
Ok(AttrResolveResult::Value(typ.base()))
892917
}
893918
SignalAttribute::Driving => {
894919
check_no_sattr_argument(sattr, expr, diagnostics);
895-
Ok(self.boolean().base())
920+
Ok(AttrResolveResult::Value(self.boolean().base()))
896921
}
897922
SignalAttribute::DrivingValue => {
898923
check_no_sattr_argument(sattr, expr, diagnostics);
899-
Ok(typ.base())
924+
Ok(AttrResolveResult::Value(typ.base()))
900925
}
901926
}
902927
}
@@ -912,9 +937,44 @@ impl<'a> AnalyzeContext<'a> {
912937
diagnostics.error(name_pos, "Range cannot be used as an expression");
913938
Err(EvalError::Unknown)
914939
}
915-
AttributeDesignator::Type(_) => {
916-
diagnostics.error(name_pos, "Type cannot be used as an expression");
917-
Err(EvalError::Unknown)
940+
AttributeDesignator::Type(attr) => self
941+
.resolve_type_attribute_suffix(prefix, &attr, name_pos, diagnostics)
942+
.map(|typ| AttrResolveResult::Type(typ.base())),
943+
}
944+
}
945+
946+
/// Resolves any type attribute suffixes
947+
///
948+
/// # Example
949+
/// ```vhdl
950+
/// variable x: std_logic_vector(2 downto 0);
951+
/// x'subtype -> std_logic_vector(2 downto 0)
952+
/// x'element -> std_logic
953+
/// ```
954+
fn resolve_type_attribute_suffix(
955+
&self,
956+
prefix: &ResolvedName<'a>,
957+
suffix: &TypeAttribute,
958+
pos: &SrcPos,
959+
diagnostics: &mut dyn DiagnosticHandler,
960+
) -> EvalResult<TypeEnt<'a>> {
961+
// all type attribute suffixes require that the prefix be an object type
962+
let Some(obj) = prefix.as_object_name() else {
963+
diagnostics.error(pos,format!("The {} attribute can only be used on objects, not {}", suffix, prefix.describe()));
964+
return Err(EvalError::Unknown)
965+
};
966+
match suffix {
967+
TypeAttribute::Subtype => Ok(obj.type_mark()),
968+
TypeAttribute::Element => {
969+
if let Some((elem_type, _)) = obj.type_mark().array_type() {
970+
Ok(elem_type)
971+
} else {
972+
diagnostics.error(
973+
pos,
974+
"The element attribute can only be used for array types",
975+
);
976+
Err(EvalError::Unknown)
977+
}
918978
}
919979
}
920980
}
@@ -1035,13 +1095,15 @@ impl<'a> AnalyzeContext<'a> {
10351095
}
10361096
}
10371097

1038-
// Attributes for non-types not handled yet
10391098
if let Suffix::Attribute(ref mut attr) = suffix {
10401099
let typ =
10411100
self.attribute_suffix(name_pos, &prefix.pos, scope, &resolved, attr, diagnostics)?;
1042-
return Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous(
1043-
typ.into(),
1044-
)));
1101+
return match typ {
1102+
AttrResolveResult::Type(base) => Ok(ResolvedName::Type(base.into())),
1103+
AttrResolveResult::Value(base) => Ok(ResolvedName::Expression(
1104+
DisambiguatedType::Unambiguous(base.into()),
1105+
)),
1106+
};
10451107
}
10461108

10471109
match resolved {
@@ -1737,6 +1799,90 @@ mod test {
17371799
}
17381800
}
17391801

1802+
#[test]
1803+
fn consecutive_name_attributes() {
1804+
let test = TestSetup::new();
1805+
test.declarative_part(
1806+
"\
1807+
variable a: natural range 0 to 9 := 9;
1808+
variable b: natural range 0 to a'subtype'high;
1809+
",
1810+
);
1811+
assert_matches!(
1812+
test.name_resolve(&test.snippet("b"), None, &mut NoDiagnostics),
1813+
Ok(ResolvedName::ObjectName(_))
1814+
);
1815+
}
1816+
1817+
#[test]
1818+
fn element_subtype_for_non_arrays() {
1819+
let test = TestSetup::new();
1820+
test.declarative_part(
1821+
"
1822+
variable thevar : integer;
1823+
",
1824+
);
1825+
let code = test.snippet("thevar'element");
1826+
let mut diagnostics = Vec::new();
1827+
assert_eq!(
1828+
test.name_resolve(&code, None, &mut diagnostics),
1829+
Err(EvalError::Unknown)
1830+
);
1831+
check_diagnostics(
1832+
diagnostics,
1833+
vec![Diagnostic::error(
1834+
code.s1("thevar'element"),
1835+
"The element attribute can only be used for array types",
1836+
)],
1837+
)
1838+
}
1839+
1840+
#[test]
1841+
fn element_type_attributes_on_non_object_types() {
1842+
let test = TestSetup::new();
1843+
test.declarative_part(
1844+
"
1845+
type my_type is array(natural range<>) of integer;
1846+
",
1847+
);
1848+
let code = test.snippet("my_type'subtype");
1849+
let mut diagnostics = Vec::new();
1850+
assert_eq!(
1851+
test.name_resolve(&code, None, &mut diagnostics),
1852+
Err(EvalError::Unknown)
1853+
);
1854+
check_diagnostics(
1855+
diagnostics,
1856+
vec![Diagnostic::error(
1857+
code.s1("my_type'subtype"),
1858+
"The subtype attribute can only be used on objects, not array type 'my_type'",
1859+
)],
1860+
)
1861+
}
1862+
1863+
#[test]
1864+
fn consecutive_type_attributes() {
1865+
let test = TestSetup::new();
1866+
test.declarative_part(
1867+
"
1868+
variable x: integer;
1869+
",
1870+
);
1871+
let code = test.snippet("x'subtype'subtype'high");
1872+
let mut diagnostics = Vec::new();
1873+
assert_eq!(
1874+
test.name_resolve(&code, None, &mut diagnostics),
1875+
Err(EvalError::Unknown)
1876+
);
1877+
check_diagnostics(
1878+
diagnostics,
1879+
vec![Diagnostic::error(
1880+
code.s1("x'subtype'subtype"),
1881+
"The subtype attribute can only be used on objects, not integer type 'INTEGER'",
1882+
)],
1883+
)
1884+
}
1885+
17401886
#[test]
17411887
fn object_name() {
17421888
let test = TestSetup::new();
@@ -2579,29 +2725,6 @@ variable thevar : integer_vector(0 to 1);
25792725
)
25802726
}
25812727

2582-
#[test]
2583-
fn subtype_attribute() {
2584-
let test = TestSetup::new();
2585-
test.declarative_part(
2586-
"
2587-
variable thevar : integer_vector(0 to 1);
2588-
",
2589-
);
2590-
let code = test.snippet("thevar'subtype");
2591-
let mut diagnostics = Vec::new();
2592-
assert_eq!(
2593-
test.name_resolve(&code, None, &mut diagnostics),
2594-
Err(EvalError::Unknown)
2595-
);
2596-
check_diagnostics(
2597-
diagnostics,
2598-
vec![Diagnostic::error(
2599-
code,
2600-
"Type cannot be used as an expression",
2601-
)],
2602-
)
2603-
}
2604-
26052728
#[test]
26062729
fn name_attributes() {
26072730
let test = TestSetup::new();

0 commit comments

Comments
 (0)