Skip to main content

vhdl_parser/syntax/
attributes.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this file,
3// You can obtain one at http://mozilla.org/MPL/2.0/.
4//
5// Copyright (c) 2018, Olof Kraigher olof.kraigher@gmail.com
6
7use 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}