Skip to main content

vhdl_parser/syntax/
type_declaration.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::error_on_end_identifier_mismatch;
8use super::common::ParseResult;
9use super::declarative_part::parse_declarative_part;
10use super::names::{parse_identifier_list, parse_selected_name};
11use super::range::{parse_array_index_constraint, parse_range};
12use super::subprogram::parse_subprogram_declaration;
13use super::subtype_indication::parse_subtype_indication;
14use super::tokens::{Kind::*, TokenStream};
15use crate::ast::*;
16use crate::ast::{AbstractLiteral, Range};
17use crate::data::{push_some, DiagnosticHandler};
18
19/// LRM 5.2.2 Enumeration types
20fn parse_enumeration_type_definition(stream: &mut TokenStream) -> ParseResult<TypeDefinition> {
21    let mut enum_literals = Vec::new();
22    loop {
23        let literal_token = stream.expect()?;
24
25        try_token_kind!(
26            literal_token,
27            Identifier | Character => {
28                let enum_literal = try_token_kind!(
29                    literal_token,
30                    Identifier => literal_token.expect_ident()?.map_into(EnumerationLiteral::Identifier),
31                    Character => literal_token.expect_character()?.map_into(EnumerationLiteral::Character)
32                );
33                enum_literals.push(enum_literal);
34
35                try_token_kind!(
36                    stream.expect()?,
37                    RightPar => {
38                        stream.expect_kind(SemiColon)?;
39                        break;
40                    },
41                    Comma => {}
42                );
43            }
44        );
45    }
46
47    Ok(TypeDefinition::Enumeration(enum_literals))
48}
49
50fn parse_array_index_constraints(stream: &mut TokenStream) -> ParseResult<Vec<ArrayIndex>> {
51    stream.expect_kind(LeftPar)?;
52    let mut indexes = Vec::new();
53    loop {
54        indexes.push(parse_array_index_constraint(stream)?);
55
56        try_token_kind!(
57            stream.expect()?,
58            RightPar => {
59                return Ok(indexes);
60            },
61            Comma => {}
62        )
63    }
64}
65
66/// LRM 5.3.2 Array types
67fn parse_array_type_definition(stream: &mut TokenStream) -> ParseResult<TypeDefinition> {
68    let index_constraints = parse_array_index_constraints(stream)?;
69    stream.expect_kind(Of)?;
70    let element_subtype = parse_subtype_indication(stream)?;
71    stream.expect_kind(SemiColon)?;
72    Ok(TypeDefinition::Array(index_constraints, element_subtype))
73}
74
75/// LRM 5.3.3 Record types
76fn parse_record_type_definition(
77    stream: &mut TokenStream,
78) -> ParseResult<(TypeDefinition, Option<Ident>)> {
79    let mut elem_decls = Vec::new();
80
81    loop {
82        let token = stream.peek_expect()?;
83        if token.kind == End {
84            stream.move_after(&token); // End
85            stream.pop_if_kind(Record)?;
86            let end_ident = stream.pop_optional_ident()?;
87            stream.expect_kind(SemiColon)?;
88            return Ok((TypeDefinition::Record(elem_decls), end_ident));
89        };
90
91        let idents = parse_identifier_list(stream)?;
92        stream.expect_kind(Colon)?;
93        let subtype = parse_subtype_indication(stream)?;
94        for ident in idents {
95            elem_decls.push(ElementDeclaration {
96                ident,
97                subtype: subtype.clone(),
98            });
99        }
100        stream.expect_kind(SemiColon)?;
101    }
102}
103
104pub fn parse_subtype_declaration(stream: &mut TokenStream) -> ParseResult<TypeDeclaration> {
105    stream.expect_kind(Subtype)?;
106    let ident = stream.expect_ident()?;
107    stream.expect_kind(Is)?;
108    let subtype_indication = parse_subtype_indication(stream)?;
109    stream.expect_kind(SemiColon)?;
110    Ok(TypeDeclaration {
111        ident,
112        def: TypeDefinition::Subtype(subtype_indication),
113    })
114}
115
116/// LRM 5.6.2 Protected type declarations
117pub fn parse_protected_type_declaration(
118    stream: &mut TokenStream,
119    diagnostics: &mut dyn DiagnosticHandler,
120) -> ParseResult<(ProtectedTypeDeclaration, Option<Ident>)> {
121    let mut items = Vec::new();
122
123    loop {
124        let token = stream.peek_expect()?;
125
126        try_token_kind!(
127            token,
128            Impure | Function | Procedure => items.push(ProtectedTypeDeclarativeItem::Subprogram(
129                parse_subprogram_declaration(stream, diagnostics)?,
130            )),
131            End => {
132                stream.move_after(&token);
133                break;
134            }
135        );
136    }
137    stream.expect_kind(Protected)?;
138    let end_ident = stream.pop_optional_ident()?;
139    Ok((ProtectedTypeDeclaration { items }, end_ident))
140}
141
142/// LRM 5.2.4 Physical types
143fn parse_physical_type_definition(
144    stream: &mut TokenStream,
145    range: Range,
146) -> ParseResult<(TypeDefinition, Option<Ident>)> {
147    let primary_unit = stream.expect_ident()?;
148    stream.expect_kind(SemiColon)?;
149
150    let mut secondary_units = Vec::new();
151
152    loop {
153        let token = stream.peek_expect()?;
154        try_token_kind!(
155            token,
156            End => {
157                break;
158            },
159            Identifier => {
160                stream.move_after(&token);
161                let ident = token.expect_ident()?;
162                stream.expect_kind(EQ)?;
163                let literal = {
164                    let value_token = stream.expect()?;
165                    try_token_kind!(
166                        value_token,
167                        AbstractLiteral => {
168                            let value = value_token.expect_abstract_literal()?.item;
169                            let unit = stream.expect_ident()?;
170                            Literal::Physical(value, unit.item)
171                        },
172                        Identifier => {
173                            let unit = value_token.expect_ident()?;
174                            Literal::Physical(AbstractLiteral::Integer(1), unit.item)
175                        }
176                    )
177                };
178
179                secondary_units.push((ident, literal));
180                stream.expect_kind(SemiColon)?;
181            }
182        )
183    }
184
185    stream.expect_kind(End)?;
186    stream.expect_kind(Units)?;
187    let end_ident = stream.pop_optional_ident()?;
188    stream.expect_kind(SemiColon)?;
189
190    Ok((
191        TypeDefinition::Physical(PhysicalTypeDeclaration {
192            range,
193            primary_unit,
194            secondary_units,
195        }),
196        end_ident,
197    ))
198}
199
200/// LRM 6.2
201pub fn parse_type_declaration(
202    stream: &mut TokenStream,
203    diagnostics: &mut dyn DiagnosticHandler,
204) -> ParseResult<TypeDeclaration> {
205    let token = stream.peek_expect()?;
206    try_token_kind!(
207        token,
208        Subtype => {
209            return parse_subtype_declaration(stream);
210        },
211        Type => {
212            stream.move_after(&token);
213        }
214    );
215
216    let ident = stream.expect_ident()?;
217
218    try_token_kind!(
219        stream.expect()?,
220        Is => {},
221        SemiColon => {
222            return Ok(TypeDeclaration {
223                ident,
224                def: TypeDefinition::Incomplete,
225            });
226        }
227    );
228
229    let def = try_token_kind!(
230        stream.expect()?,
231        // Integer
232        Range => {
233            let constraint = parse_range(stream)?.item;
234            try_token_kind!(
235                stream.expect()?,
236                SemiColon => TypeDefinition::Integer(constraint),
237                Units => {
238                    let (def, end_ident) = parse_physical_type_definition(stream, constraint)?;
239                    push_some(diagnostics, error_on_end_identifier_mismatch(&ident, &end_ident));
240                    def
241                }
242            )
243        },
244
245        Access => {
246            let subtype_indication = parse_subtype_indication(stream)?;
247            stream.expect_kind(SemiColon)?;
248            TypeDefinition::Access(subtype_indication)
249        },
250
251        Protected => {
252            if stream.skip_if_kind(Body)? {
253                let decl = parse_declarative_part(stream, diagnostics, false)?;
254                stream.expect_kind(Protected)?;
255                stream.expect_kind(Body)?;
256                // @TODO check name
257                stream.pop_if_kind(Identifier)?;
258                stream.expect_kind(SemiColon)?;
259                TypeDefinition::ProtectedBody(ProtectedTypeBody {name: WithRef::new(ident.clone()), decl})
260            } else {
261                let (protected_type_decl, end_ident) = parse_protected_type_declaration(stream, diagnostics)?;
262                push_some(diagnostics, error_on_end_identifier_mismatch(&ident, &end_ident));
263                stream.expect_kind(SemiColon)?;
264                TypeDefinition::Protected(protected_type_decl)
265            }
266        },
267        File => {
268            stream.expect_kind(Of)?;
269            let selected_name = parse_selected_name(stream)?;
270            stream.expect_kind(SemiColon)?;
271            TypeDefinition::File(selected_name)
272        },
273        Array => parse_array_type_definition(stream)?,
274        Record =>  {
275            let (def, end_ident) = parse_record_type_definition(stream)?;
276            push_some(diagnostics, error_on_end_identifier_mismatch(&ident, &end_ident));
277            def
278        },
279        // Enumeration
280        LeftPar => parse_enumeration_type_definition(stream)?
281    );
282
283    Ok(TypeDeclaration { ident, def })
284}
285
286#[cfg(test)]
287mod tests {
288    use super::*;
289
290    use crate::ast::{DiscreteRange, Ident};
291    use crate::syntax::test::Code;
292
293    #[test]
294    fn parse_integer_scalar_type_definition() {
295        let code = Code::new("type foo is range 0 to 1;");
296
297        let type_decl = TypeDeclaration {
298            ident: code.s1("foo").ident(),
299            def: TypeDefinition::Integer(code.s1("0 to 1").range()),
300        };
301        assert_eq!(
302            code.with_stream_no_diagnostics(parse_type_declaration),
303            type_decl
304        );
305    }
306
307    #[test]
308    fn parse_enumeration_scalar_type_definition() {
309        let code = Code::new("type foo is (alpha, beta);");
310
311        let type_decl = TypeDeclaration {
312            ident: code.s1("foo").ident(),
313            def: TypeDefinition::Enumeration(vec![
314                code.s1("alpha")
315                    .ident()
316                    .map_into(EnumerationLiteral::Identifier),
317                code.s1("beta")
318                    .ident()
319                    .map_into(EnumerationLiteral::Identifier),
320            ]),
321        };
322        assert_eq!(
323            code.with_stream_no_diagnostics(parse_type_declaration),
324            type_decl
325        );
326    }
327
328    #[test]
329    fn parse_enumeration_scalar_type_definition_character() {
330        let code = Code::new("type foo is ('a', 'b');");
331
332        let type_decl = TypeDeclaration {
333            ident: code.s1("foo").ident(),
334            def: TypeDefinition::Enumeration(vec![
335                code.s1("'a'")
336                    .character()
337                    .map_into(EnumerationLiteral::Character),
338                code.s1("'b'")
339                    .character()
340                    .map_into(EnumerationLiteral::Character),
341            ]),
342        };
343        assert_eq!(
344            code.with_stream_no_diagnostics(parse_type_declaration),
345            type_decl
346        );
347    }
348
349    #[test]
350    fn mixing_identifier_and_scalar_in_enumerations() {
351        let code = Code::new("type foo is (ident, 'b');");
352
353        let type_decl = TypeDeclaration {
354            ident: code.s1("foo").ident(),
355            def: TypeDefinition::Enumeration(vec![
356                code.s1("ident")
357                    .ident()
358                    .map_into(EnumerationLiteral::Identifier),
359                code.s1("'b'")
360                    .character()
361                    .map_into(EnumerationLiteral::Character),
362            ]),
363        };
364        assert_eq!(
365            code.with_stream_no_diagnostics(parse_type_declaration),
366            type_decl
367        );
368    }
369
370    #[test]
371    fn parse_array_type_definition_with_index_subtype_definition() {
372        let code = Code::new("type foo is array (natural range <>) of boolean;");
373
374        let type_decl = TypeDeclaration {
375            ident: code.s1("foo").ident(),
376            def: TypeDefinition::Array(
377                vec![ArrayIndex::IndexSubtypeDefintion(
378                    code.s1("natural").selected_name(),
379                )],
380                code.s1("boolean").subtype_indication(),
381            ),
382        };
383
384        assert_eq!(
385            code.with_stream_no_diagnostics(parse_type_declaration),
386            type_decl
387        );
388    }
389
390    #[test]
391    fn parse_array_type_definition_with_discrete_subtype_definition() {
392        let code = Code::new("type foo is array (natural) of boolean;");
393
394        let type_decl = TypeDeclaration {
395            ident: code.s1("foo").ident(),
396            def: TypeDefinition::Array(
397                vec![ArrayIndex::Discrete(DiscreteRange::Discrete(
398                    code.s1("natural").selected_name(),
399                    None,
400                ))],
401                code.s1("boolean").subtype_indication(),
402            ),
403        };
404
405        assert_eq!(
406            code.with_stream_no_diagnostics(parse_type_declaration),
407            type_decl
408        );
409    }
410
411    #[test]
412    fn parse_array_type_definition_with_selected_name() {
413        let code = Code::new("type foo is array (lib.pkg.foo) of boolean;");
414
415        let type_decl = TypeDeclaration {
416            ident: code.s1("foo").ident(),
417            def: TypeDefinition::Array(
418                vec![ArrayIndex::Discrete(DiscreteRange::Discrete(
419                    code.s1("lib.pkg.foo").selected_name(),
420                    None,
421                ))],
422                code.s1("boolean").subtype_indication(),
423            ),
424        };
425
426        assert_eq!(
427            code.with_stream_no_diagnostics(parse_type_declaration),
428            type_decl
429        );
430    }
431
432    #[test]
433    fn parse_array_type_definition_with_range_attribute_name() {
434        let code = Code::new("type foo is array (arr_t'range) of boolean;");
435
436        let type_decl = TypeDeclaration {
437            ident: code.s1("foo").ident(),
438            def: TypeDefinition::Array(
439                vec![ArrayIndex::Discrete(DiscreteRange::Range(
440                    code.s1("arr_t'range").range(),
441                ))],
442                code.s1("boolean").subtype_indication(),
443            ),
444        };
445
446        assert_eq!(
447            code.with_stream_no_diagnostics(parse_type_declaration),
448            type_decl
449        );
450    }
451
452    #[test]
453    fn parse_array_type_definition_with_constraint() {
454        let code = Code::new("type foo is array (2-1 downto 0) of boolean;");
455
456        let index = ArrayIndex::Discrete(DiscreteRange::Range(code.s1("2-1 downto 0").range()));
457
458        let type_decl = TypeDeclaration {
459            ident: code.s1("foo").ident(),
460            def: TypeDefinition::Array(vec![index], code.s1("boolean").subtype_indication()),
461        };
462
463        assert_eq!(
464            code.with_stream_no_diagnostics(parse_type_declaration),
465            type_decl
466        );
467    }
468
469    #[test]
470    fn parse_array_type_definition_mixed() {
471        let code = Code::new("type foo is array (2-1 downto 0, integer range <>) of boolean;");
472
473        let index0 = ArrayIndex::Discrete(DiscreteRange::Range(code.s1("2-1 downto 0").range()));
474
475        let index1 = ArrayIndex::IndexSubtypeDefintion(code.s1("integer").selected_name());
476
477        let type_decl = TypeDeclaration {
478            ident: code.s1("foo").ident(),
479            def: TypeDefinition::Array(
480                vec![index0, index1],
481                code.s1("boolean").subtype_indication(),
482            ),
483        };
484
485        assert_eq!(
486            code.with_stream_no_diagnostics(parse_type_declaration),
487            type_decl
488        );
489    }
490
491    #[test]
492    fn parse_record_type_definition() {
493        let code = Code::new(
494            "\
495            type foo is record
496  element : boolean;
497end record;",
498        );
499
500        let elem_decl = ElementDeclaration {
501            ident: code.s1("element").ident(),
502            subtype: code.s1("boolean").subtype_indication(),
503        };
504
505        let type_decl = TypeDeclaration {
506            ident: code.s1("foo").ident(),
507            def: TypeDefinition::Record(vec![elem_decl]),
508        };
509
510        assert_eq!(
511            code.with_stream_no_diagnostics(parse_type_declaration),
512            type_decl
513        );
514    }
515
516    #[test]
517    fn parse_record_type_definition_many() {
518        let code = Code::new(
519            "\
520            type foo is record
521  element, field : boolean;
522  other_element : std_logic_vector(0 to 1);
523end foo;",
524        );
525
526        let elem_decl0a = ElementDeclaration {
527            ident: code.s1("element").ident(),
528            subtype: code.s1("boolean").subtype_indication(),
529        };
530
531        let elem_decl0b = ElementDeclaration {
532            ident: code.s1("field").ident(),
533            subtype: code.s1("boolean").subtype_indication(),
534        };
535
536        let elem_decl1 = ElementDeclaration {
537            ident: code.s1("other_element").ident(),
538            subtype: code.s1("std_logic_vector(0 to 1)").subtype_indication(),
539        };
540
541        let type_decl = TypeDeclaration {
542            ident: code.s1("foo").ident(),
543            def: TypeDefinition::Record(vec![elem_decl0a, elem_decl0b, elem_decl1]),
544        };
545
546        assert_eq!(
547            code.with_stream_no_diagnostics(parse_type_declaration),
548            type_decl
549        );
550    }
551
552    #[test]
553    fn test_parse_subtype_declaration() {
554        let code = Code::new("subtype vec_t is integer_vector(2-1 downto 0);");
555
556        assert_eq!(
557            code.with_stream_no_diagnostics(parse_type_declaration),
558            TypeDeclaration {
559                ident: code.s1("vec_t").ident(),
560                def: TypeDefinition::Subtype(
561                    code.s1("integer_vector(2-1 downto 0)").subtype_indication()
562                )
563            }
564        );
565    }
566
567    #[test]
568    fn test_parse_access_type_declaration() {
569        let code = Code::new("type ptr_t is access integer_vector(2-1 downto 0);");
570
571        assert_eq!(
572            code.with_stream_no_diagnostics(parse_type_declaration),
573            TypeDeclaration {
574                ident: code.s1("ptr_t").ident(),
575                def: TypeDefinition::Access(
576                    code.s1("integer_vector(2-1 downto 0)").subtype_indication()
577                )
578            }
579        );
580    }
581
582    #[test]
583    fn test_incomplete_type_declaration() {
584        let code = Code::new("type incomplete;");
585
586        assert_eq!(
587            code.with_stream_no_diagnostics(parse_type_declaration),
588            TypeDeclaration {
589                ident: code.s1("incomplete").ident(),
590                def: TypeDefinition::Incomplete
591            }
592        );
593    }
594
595    #[test]
596    fn test_file_type_declaration() {
597        let code = Code::new("type foo is file of character;");
598
599        assert_eq!(
600            code.with_stream_no_diagnostics(parse_type_declaration),
601            TypeDeclaration {
602                ident: code.s1("foo").ident(),
603                def: TypeDefinition::File(code.s1("character").selected_name())
604            }
605        );
606    }
607
608    fn protected_decl(ident: Ident, items: Vec<ProtectedTypeDeclarativeItem>) -> TypeDeclaration {
609        TypeDeclaration {
610            ident,
611            def: TypeDefinition::Protected(ProtectedTypeDeclaration { items }),
612        }
613    }
614
615    #[test]
616    fn test_protected_type_declaration() {
617        let code = Code::new(
618            "\
619type foo is protected
620end protected;
621",
622        );
623        assert_eq!(
624            code.with_stream_no_diagnostics(parse_type_declaration),
625            protected_decl(code.s1("foo").ident(), vec![])
626        )
627    }
628
629    #[test]
630    fn test_protected_type_declaration_simple_name_suffix() {
631        let code = Code::new(
632            "\
633type foo is protected
634end protected foo;
635",
636        );
637        assert_eq!(
638            code.with_stream_no_diagnostics(parse_type_declaration),
639            protected_decl(code.s1("foo").ident(), vec![])
640        )
641    }
642
643    #[test]
644    fn test_protected_type_declaration_with_subprograms() {
645        let code = Code::new(
646            "\
647type foo is protected
648  procedure proc;
649  function fun return ret;
650end protected;
651",
652        );
653        let items = vec![
654            ProtectedTypeDeclarativeItem::Subprogram(code.s1("procedure proc").subprogram_decl()),
655            ProtectedTypeDeclarativeItem::Subprogram(
656                code.s1("function fun return ret").subprogram_decl(),
657            ),
658        ];
659
660        assert_eq!(
661            code.with_stream_no_diagnostics(parse_type_declaration),
662            protected_decl(code.s1("foo").ident(), items)
663        )
664    }
665
666    #[test]
667    fn test_protected_type_body() {
668        let code = Code::new(
669            "\
670type foo is protected body
671  variable foo : natural;
672  procedure proc is
673  begin
674  end;
675end protected body;
676",
677        );
678
679        let decl = code
680            .s1("\
681  variable foo : natural;
682  procedure proc is
683  begin
684  end;")
685            .declarative_part();
686
687        let ident = code.s1("foo").ident();
688        assert_eq!(
689            code.with_stream_no_diagnostics(parse_type_declaration),
690            TypeDeclaration {
691                ident: ident.clone(),
692                def: TypeDefinition::ProtectedBody(ProtectedTypeBody {
693                    name: WithRef::new(ident),
694                    decl
695                }),
696            }
697        )
698    }
699
700    #[test]
701    fn test_physical_type_declaration() {
702        let code = Code::new(
703            "\
704type phys is range 0 to 15 units
705   primary_unit;
706end units phys;
707",
708        );
709
710        assert_eq!(
711            code.with_stream_no_diagnostics(parse_type_declaration),
712            TypeDeclaration {
713                ident: code.s1("phys").ident(),
714                def: TypeDefinition::Physical(PhysicalTypeDeclaration {
715                    range: code.s1("0 to 15").range(),
716                    primary_unit: code.s1("primary_unit").ident(),
717                    secondary_units: vec![]
718                })
719            }
720        )
721    }
722
723    #[test]
724    fn test_physical_type_declaration_secondary_units() {
725        let code = Code::new(
726            "\
727type phys is range 0 to 15 units
728   primary_unit;
729   secondary_unit = 5 primary_unit;
730end units;
731",
732        );
733
734        assert_eq!(
735            code.with_stream_no_diagnostics(parse_type_declaration),
736            TypeDeclaration {
737                ident: code.s1("phys").ident(),
738                def: TypeDefinition::Physical(PhysicalTypeDeclaration {
739                    range: code.s1("0 to 15").range(),
740                    primary_unit: code.s1("primary_unit").ident(),
741                    secondary_units: vec![(
742                        code.s1("secondary_unit").ident(),
743                        Literal::Physical(AbstractLiteral::Integer(5), code.symbol("primary_unit"))
744                    ),]
745                })
746            }
747        )
748    }
749
750    #[test]
751    fn test_physical_type_declaration_implicit_secondary_units() {
752        let code = Code::new(
753            "\
754type phys is range 0 to 15 units
755   primary_unit;
756   secondary_unit = primary_unit;
757end units;
758",
759        );
760
761        assert_eq!(
762            code.with_stream_no_diagnostics(parse_type_declaration),
763            TypeDeclaration {
764                ident: code.s1("phys").ident(),
765                def: TypeDefinition::Physical(PhysicalTypeDeclaration {
766                    range: code.s1("0 to 15").range(),
767                    primary_unit: code.s1("primary_unit").ident(),
768                    secondary_units: vec![(
769                        code.s1("secondary_unit").ident(),
770                        Literal::Physical(AbstractLiteral::Integer(1), code.symbol("primary_unit"))
771                    ),]
772                })
773            }
774        )
775    }
776}