vhdl_parser/syntax/
attributes.rs1use super::common::ParseResult;
8use super::expression::parse_expression;
9use super::names::parse_selected_name;
10use super::subprogram::parse_signature;
11use super::tokens::{Kind::*, TokenStream};
12use crate::ast::{
13 Attribute, AttributeDeclaration, AttributeSpecification, Designator, EntityClass, EntityName,
14 EntityTag,
15};
16
17fn parse_entity_class(stream: &mut TokenStream) -> ParseResult<EntityClass> {
18 let token = stream.expect()?;
19 Ok(try_token_kind!(
20 token,
21 Entity => EntityClass::Entity,
22 Architecture => EntityClass::Architecture,
23 Configuration => EntityClass::Configuration,
24 Package => EntityClass::Package,
25 Signal => EntityClass::Signal,
26 Variable => EntityClass::Variable,
27 Procedure => EntityClass::Procedure,
28 Function => EntityClass::Function,
29 Component => EntityClass::Component,
30 Constant => EntityClass::Constant,
31 Type => EntityClass::Type,
32 Label => EntityClass::Label
33 ))
34}
35
36pub fn parse_entity_name_list(stream: &mut TokenStream) -> ParseResult<Vec<EntityName>> {
37 let token = stream.peek_expect()?;
38 Ok(try_token_kind!(
39 token,
40 Identifier | StringLiteral => {
41 let mut entity_name_list = Vec::new();
42 loop {
43 let designator_token = stream.expect()?;
44 let designator = try_token_kind!(
45 designator_token,
46 Identifier => designator_token.expect_ident()?.map_into(Designator::Identifier),
47 StringLiteral => designator_token.expect_string()?.map_into(Designator::OperatorSymbol));
48
49 let signature = {
50 if stream.peek_kind()? == Some(LeftSquare) {
51 Some(parse_signature(stream)?)
52 } else {
53 None
54 }
55 };
56
57 entity_name_list.push(EntityName::Name(EntityTag {
58 designator,
59 signature,
60 }));
61
62 let sep_token = stream.peek_expect()?;
63
64 try_token_kind!(
65 sep_token,
66
67 Comma => {
68 stream.move_after(&sep_token);
69 },
70 Colon => {
71 break entity_name_list;
72 }
73 )
74 }
75 },
76 Others => {
77 stream.move_after(&token);
78 vec![EntityName::Others]
79 },
80 All => {
81 stream.move_after(&token);
82 vec![EntityName::All]
83 }
84 ))
85}
86
87pub fn parse_attribute(stream: &mut TokenStream) -> ParseResult<Vec<Attribute>> {
88 stream.expect_kind(Attribute)?;
89 let ident = stream.expect_ident()?;
90 let token = stream.expect()?;
91
92 Ok(try_token_kind!(
93 token,
94 Colon => {
95 let type_mark = parse_selected_name(stream)?;
96 stream.expect_kind(SemiColon)?;
97 vec![Attribute::Declaration(AttributeDeclaration {
98 ident,
99 type_mark,
100 })]
101 },
102 Of => {
103 let entity_names = parse_entity_name_list(stream)?;
104 stream.expect_kind(Colon)?;
105 let entity_class = parse_entity_class(stream)?;
106 stream.expect_kind(Is)?;
107 let expr = parse_expression(stream)?;
108 stream.expect_kind(SemiColon)?;
109
110 entity_names
111 .into_iter()
112 .map(|entity_name| {
113 Attribute::Specification(AttributeSpecification {
114 ident: ident.clone(),
115 entity_name: entity_name.clone(),
116 entity_class: entity_class,
117 expr: expr.clone(),
118 })
119 }).collect()
120 }
121 ))
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127 use crate::syntax::test::Code;
128
129 #[test]
130 fn parse_simple_attribute_declaration() {
131 let code = Code::new("attribute foo : lib.name;");
132 assert_eq!(
133 code.with_stream(parse_attribute),
134 vec![Attribute::Declaration(AttributeDeclaration {
135 ident: code.s1("foo").ident(),
136 type_mark: code.s1("lib.name").selected_name()
137 })]
138 )
139 }
140
141 #[test]
142 fn parse_simple_attribute_specification() {
143 let code = Code::new("attribute attr_name of foo : signal is 0+1;");
144 assert_eq!(
145 code.with_stream(parse_attribute),
146 vec![Attribute::Specification(AttributeSpecification {
147 ident: code.s1("attr_name").ident(),
148 entity_name: EntityName::Name(EntityTag {
149 designator: code.s1("foo").designator(),
150 signature: None
151 }),
152 entity_class: EntityClass::Signal,
153 expr: code.s1("0+1").expr()
154 })]
155 )
156 }
157
158 #[test]
159 fn parse_simple_attribute_specification_operator_symbol() {
160 let code = Code::new("attribute attr_name of \"**\" : function is 0+1;");
161 assert_eq!(
162 code.with_stream(parse_attribute),
163 vec![Attribute::Specification(AttributeSpecification {
164 ident: code.s1("attr_name").ident(),
165 entity_name: EntityName::Name(EntityTag {
166 designator: code.s1("\"**\"").designator(),
167 signature: None
168 }),
169 entity_class: EntityClass::Function,
170 expr: code.s1("0+1").expr()
171 })]
172 )
173 }
174
175 #[test]
176 fn parse_attribute_specification_list() {
177 let code = Code::new("attribute attr_name of foo, bar : signal is 0+1;");
178 assert_eq!(
179 code.with_stream(parse_attribute),
180 vec![
181 Attribute::Specification(AttributeSpecification {
182 ident: code.s1("attr_name").ident(),
183 entity_name: EntityName::Name(EntityTag {
184 designator: code.s1("foo").designator(),
185 signature: None
186 }),
187 entity_class: EntityClass::Signal,
188 expr: code.s1("0+1").expr()
189 }),
190 Attribute::Specification(AttributeSpecification {
191 ident: code.s1("attr_name").ident(),
192 entity_name: EntityName::Name(EntityTag {
193 designator: code.s1("bar").designator(),
194 signature: None
195 }),
196 entity_class: EntityClass::Signal,
197 expr: code.s1("0+1").expr()
198 })
199 ]
200 )
201 }
202
203 #[test]
204 fn parse_attribute_specification_all() {
205 let code = Code::new("attribute attr_name of all : signal is 0+1;");
206 assert_eq!(
207 code.with_stream(parse_attribute),
208 vec![Attribute::Specification(AttributeSpecification {
209 ident: code.s1("attr_name").ident(),
210 entity_name: EntityName::All,
211 entity_class: EntityClass::Signal,
212 expr: code.s1("0+1").expr()
213 })]
214 )
215 }
216
217 #[test]
218 fn parse_attribute_specification_others() {
219 let code = Code::new("attribute attr_name of others : signal is 0+1;");
220 assert_eq!(
221 code.with_stream(parse_attribute),
222 vec![Attribute::Specification(AttributeSpecification {
223 ident: code.s1("attr_name").ident(),
224 entity_name: EntityName::Others,
225 entity_class: EntityClass::Signal,
226 expr: code.s1("0+1").expr()
227 })]
228 )
229 }
230
231 #[test]
232 fn parse_attribute_specification_with_signature() {
233 let code = Code::new("attribute attr_name of foo[return natural] : function is 0+1;");
234 assert_eq!(
235 code.with_stream(parse_attribute),
236 vec![Attribute::Specification(AttributeSpecification {
237 ident: code.s1("attr_name").ident(),
238 entity_name: EntityName::Name(EntityTag {
239 designator: code.s1("foo").designator(),
240 signature: Some(code.s1("[return natural]").signature())
241 }),
242 entity_class: EntityClass::Function,
243 expr: code.s1("0+1").expr()
244 })]
245 )
246 }
247}