1use super::common::check_end_identifier_mismatch;
8use super::common::ParseResult;
9use super::declarative_part::parse_declarative_part;
10use super::names::parse_identifier_list;
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::*, TokenSpan};
15use crate::ast::token_range::WithTokenSpan;
16use crate::ast::*;
17use crate::ast::{AbstractLiteral, Range};
18use crate::named_entity::Reference;
19use crate::syntax::names::parse_type_mark;
20use crate::syntax::recover::{expect_semicolon, expect_semicolon_or_last};
21use itertools::Itertools;
22use vhdl_lang::syntax::parser::ParsingContext;
23use vhdl_lang::TokenId;
24
25fn parse_enumeration_type_definition(ctx: &mut ParsingContext<'_>) -> ParseResult<TypeDefinition> {
27 let mut enum_literals = Vec::new();
28 loop {
29 expect_token!(ctx.stream,
30 literal_token,
31 literal_token_id,
32 Identifier | Character => {
33 let enum_literal = match literal_token.kind {
34 Identifier => literal_token.to_identifier_value(literal_token_id)?.map_into(EnumerationLiteral::Identifier),
35 Character => literal_token.to_character_value(literal_token_id)?.map_into(EnumerationLiteral::Character),
36 _ => unreachable!()
37 };
38 enum_literals.push(WithDecl::new(enum_literal));
39
40 expect_token!(ctx.stream, token,
41 RightPar => { break; },
42 Comma => {}
43 );
44 }
45 );
46 }
47
48 Ok(TypeDefinition::Enumeration(enum_literals))
49}
50
51fn parse_array_index_constraints(ctx: &mut ParsingContext<'_>) -> ParseResult<Vec<ArrayIndex>> {
52 ctx.stream.expect_kind(LeftPar)?;
53 let mut indexes = Vec::new();
54 loop {
55 indexes.push(parse_array_index_constraint(ctx)?);
56
57 expect_token!(ctx.stream, token,
58 RightPar => {
59 return Ok(indexes);
60 },
61 Comma => {}
62 )
63 }
64}
65
66fn parse_array_type_definition(ctx: &mut ParsingContext<'_>) -> ParseResult<TypeDefinition> {
68 let index_constraints = parse_array_index_constraints(ctx)?;
69 let of_token = ctx.stream.expect_kind(Of)?;
70 let element_subtype = parse_subtype_indication(ctx)?;
71 Ok(TypeDefinition::Array(
72 index_constraints,
73 of_token,
74 element_subtype,
75 ))
76}
77
78fn parse_record_type_definition(
80 ctx: &mut ParsingContext<'_>,
81) -> ParseResult<(TypeDefinition, Option<Ident>)> {
82 let mut elem_decls = Vec::new();
83
84 loop {
85 if ctx.stream.skip_if_kind(End) {
86 ctx.stream.pop_if_kind(Record);
87 let end_ident = ctx.stream.pop_optional_ident();
88 return Ok((TypeDefinition::Record(elem_decls), end_ident));
89 };
90
91 let start_token = ctx.stream.get_current_token_id();
92
93 let idents = parse_identifier_list(ctx)?
94 .into_iter()
95 .map(WithDecl::new)
96 .collect_vec();
97 let colon_token = ctx.stream.expect_kind(Colon)?;
98 let subtype = parse_subtype_indication(ctx)?;
99 let end_token = expect_semicolon_or_last(ctx);
100 elem_decls.push(ElementDeclaration {
101 idents,
102 subtype: subtype.clone(),
103 colon_token,
104 span: TokenSpan::new(start_token, end_token),
105 });
106 }
107}
108
109pub fn parse_subtype_declaration(ctx: &mut ParsingContext<'_>) -> ParseResult<TypeDeclaration> {
110 let start_token = ctx.stream.expect_kind(Subtype)?;
111 let ident = ctx.stream.expect_ident()?;
112 ctx.stream.expect_kind(Is)?;
113 let subtype_indication = parse_subtype_indication(ctx)?;
114 let end_token = expect_semicolon_or_last(ctx);
115 Ok(TypeDeclaration {
116 span: TokenSpan::new(start_token, end_token),
117 ident: ident.into(),
118 def: TypeDefinition::Subtype(subtype_indication),
119 end_ident_pos: None,
120 })
121}
122
123pub fn parse_protected_type_declaration(
125 ctx: &mut ParsingContext<'_>,
126) -> ParseResult<(ProtectedTypeDeclaration, Option<Ident>)> {
127 let mut items = Vec::new();
128
129 loop {
130 let token = ctx.stream.peek_expect()?;
131
132 try_init_token_kind!(
133 token,
134 Impure | Function | Procedure => items.push(ProtectedTypeDeclarativeItem::Subprogram(
135 parse_subprogram_declaration(ctx)?,
136 )),
137 End => {
138 ctx.stream.skip();
139 break;
140 }
141 );
142 }
143 ctx.stream.expect_kind(Protected)?;
144 let end_ident = ctx.stream.pop_optional_ident();
145 Ok((ProtectedTypeDeclaration { items }, end_ident))
146}
147
148fn parse_physical_type_definition(
150 ctx: &mut ParsingContext<'_>,
151 range: Range,
152 units_token: TokenId,
153) -> ParseResult<(TypeDefinition, Option<Ident>)> {
154 let primary_unit = WithDecl::new(ctx.stream.expect_ident()?);
155 expect_semicolon(ctx);
156
157 let mut secondary_units = Vec::new();
158
159 loop {
160 peek_token!(
161 ctx.stream, token, token_id,
162 End => {
163 break;
164 },
165 Identifier => {
166 ctx.stream.skip();
167 let ident = WithDecl::new(token.to_identifier_value(token_id)?);
168 ctx.stream.expect_kind(EQ)?;
169 let literal = {
170 expect_token!(ctx.stream,
171 value_token,
172 value_token_id,
173 AbstractLiteral => {
174 let value = value_token.to_abstract_literal(value_token_id)?.item;
175 let unit_token = ctx.stream.get_current_token_id();
176 let unit = ctx.stream.expect_ident()?;
177 WithTokenSpan::new(PhysicalLiteral {value, unit: unit.into_ref()}, TokenSpan::new(value_token_id, unit_token))
178 },
179 Identifier => {
180 let unit = value_token.to_identifier_value(value_token_id)?;
181 WithTokenSpan::new(PhysicalLiteral {value: AbstractLiteral::Integer(1), unit: unit.into_ref()}, TokenSpan::new(value_token_id, value_token_id))
182 }
183 )
184 };
185
186 secondary_units.push((ident, literal));
187 expect_semicolon(ctx);
188 }
189 )
190 }
191
192 ctx.stream.expect_kind(End)?;
193 ctx.stream.expect_kind(Units)?;
194 let end_ident = ctx.stream.pop_optional_ident();
195
196 Ok((
197 TypeDefinition::Physical(PhysicalTypeDeclaration {
198 range,
199 units_token,
200 primary_unit,
201 secondary_units,
202 }),
203 end_ident,
204 ))
205}
206
207pub fn parse_type_declaration(ctx: &mut ParsingContext<'_>) -> ParseResult<TypeDeclaration> {
209 let start_token = ctx.stream.get_current_token_id();
210 peek_token!(
211 ctx.stream, token,
212 Subtype => {
213 return parse_subtype_declaration(ctx);
214 },
215 Type => {
216 ctx.stream.skip();
217 }
218 );
219
220 let ident = WithDecl::new(ctx.stream.expect_ident()?);
221 let mut end_ident_pos = None;
222
223 expect_token!(
224 ctx.stream, token,
225 Is => {},
226 SemiColon => {
227 return Ok(TypeDeclaration {
228 span: TokenSpan::new(start_token, ctx.stream.get_last_token_id()),
229 ident,
230 def: TypeDefinition::Incomplete(Reference::undefined()),
231 end_ident_pos
232 });
233 }
234 );
235
236 let def = expect_token!(
237 ctx.stream, token,
238 Range => {
240 let constraint = parse_range(ctx)?.item;
241 expect_token!(
242 ctx.stream, token, token_id,
243 SemiColon => {
244 ctx.stream.back(); TypeDefinition::Numeric(constraint)
246 },
247 Units => {
248 let (def, end_ident) = parse_physical_type_definition(ctx, constraint, token_id)?;
249 end_ident_pos = check_end_identifier_mismatch(ctx, &ident.tree, end_ident);
250 def
251 }
252 )
253 },
254
255 Access => {
256 let subtype_indication = parse_subtype_indication(ctx)?;
257 TypeDefinition::Access(subtype_indication)
258 },
259
260 Protected => {
261 if ctx.stream.skip_if_kind(Body) {
262 let decl = parse_declarative_part(ctx)?;
263 ctx.stream.expect_kind(End)?;
264 ctx.stream.expect_kind(Protected)?;
265 ctx.stream.expect_kind(Body)?;
266 let end_ident = ctx.stream.pop_optional_ident();
267 end_ident_pos = check_end_identifier_mismatch(ctx, &ident.tree, end_ident);
268
269 TypeDefinition::ProtectedBody(ProtectedTypeBody {decl})
270 } else {
271 let (protected_type_decl, end_ident) = parse_protected_type_declaration(ctx)?;
272 end_ident_pos = check_end_identifier_mismatch(ctx, &ident.tree, end_ident);
273 TypeDefinition::Protected(protected_type_decl)
274 }
275 },
276 File => {
277 ctx.stream.expect_kind(Of)?;
278 let type_mark = parse_type_mark(ctx)?;
279 TypeDefinition::File(type_mark)
280 },
281 Array => parse_array_type_definition(ctx)?,
282 Record => {
283 let (def, end_ident) = parse_record_type_definition(ctx)?;
284 end_ident_pos = check_end_identifier_mismatch(ctx, &ident.tree, end_ident);
285 def
286 },
287 LeftPar => parse_enumeration_type_definition(ctx)?
289 );
290
291 let end_token = expect_semicolon_or_last(ctx);
292 Ok(TypeDeclaration {
293 span: TokenSpan::new(start_token, end_token),
294 ident,
295 def,
296 end_ident_pos,
297 })
298}
299
300#[cfg(test)]
301mod tests {
302 use itertools::Itertools;
303
304 use super::*;
305
306 use crate::{HasTokenSpan, TokenId};
307
308 use crate::ast::{DiscreteRange, Ident};
309 use crate::syntax::test::{token_to_string, Code};
310
311 #[test]
312 fn parse_integer_scalar_type_definition() {
313 let code = Code::new("type foo is range 0 to 1;");
314
315 let type_decl = TypeDeclaration {
316 span: code.token_span(),
317 ident: code.s1("foo").decl_ident(),
318 def: TypeDefinition::Numeric(code.s1("0 to 1").range()),
319 end_ident_pos: None,
320 };
321 assert_eq!(
322 code.with_stream_no_diagnostics(parse_type_declaration),
323 type_decl
324 );
325 }
326
327 #[test]
328 fn parse_enumeration_scalar_type_definition() {
329 let code = Code::new("type foo is (alpha, beta);");
330
331 let type_decl = TypeDeclaration {
332 span: code.token_span(),
333 ident: code.s1("foo").decl_ident(),
334 def: TypeDefinition::Enumeration(vec![
335 code.s1("alpha")
336 .ident()
337 .map_into(EnumerationLiteral::Identifier)
338 .into(),
339 code.s1("beta")
340 .ident()
341 .map_into(EnumerationLiteral::Identifier)
342 .into(),
343 ]),
344 end_ident_pos: None,
345 };
346 assert_eq!(
347 code.with_stream_no_diagnostics(parse_type_declaration),
348 type_decl
349 );
350 }
351
352 #[test]
353 fn parse_enumeration_scalar_type_definition_character() {
354 let code = Code::new("type foo is ('a', 'b');");
355
356 let type_decl = TypeDeclaration {
357 span: code.token_span(),
358 ident: code.s1("foo").decl_ident(),
359 def: TypeDefinition::Enumeration(vec![
360 code.s1("'a'")
361 .character()
362 .map_into(EnumerationLiteral::Character)
363 .into(),
364 code.s1("'b'")
365 .character()
366 .map_into(EnumerationLiteral::Character)
367 .into(),
368 ]),
369 end_ident_pos: None,
370 };
371 assert_eq!(
372 code.with_stream_no_diagnostics(parse_type_declaration),
373 type_decl
374 );
375 }
376
377 #[test]
378 fn mixing_identifier_and_scalar_in_enumerations() {
379 let code = Code::new("type foo is (ident, 'b');");
380
381 let type_decl = TypeDeclaration {
382 span: code.token_span(),
383 ident: code.s1("foo").decl_ident(),
384 def: TypeDefinition::Enumeration(vec![
385 code.s1("ident")
386 .ident()
387 .map_into(EnumerationLiteral::Identifier)
388 .into(),
389 code.s1("'b'")
390 .character()
391 .map_into(EnumerationLiteral::Character)
392 .into(),
393 ]),
394 end_ident_pos: None,
395 };
396 assert_eq!(
397 code.with_stream_no_diagnostics(parse_type_declaration),
398 type_decl
399 );
400 }
401
402 #[test]
403 fn parse_array_type_definition_with_index_subtype_definition() {
404 let code = Code::new("type foo is array (natural range <>) of boolean;");
405
406 let type_decl = TypeDeclaration {
407 span: code.token_span(),
408 ident: code.s1("foo").decl_ident(),
409 def: TypeDefinition::Array(
410 vec![ArrayIndex::IndexSubtypeDefintion(
411 code.s1("natural").type_mark(),
412 )],
413 code.s1("of").token(),
414 code.s1("boolean").subtype_indication(),
415 ),
416 end_ident_pos: None,
417 };
418
419 assert_eq!(
420 code.with_stream_no_diagnostics(parse_type_declaration),
421 type_decl
422 );
423 }
424
425 #[test]
426 fn parse_array_type_definition_with_discrete_subtype_definition() {
427 let code = Code::new("type foo is array (natural) of boolean;");
428
429 let type_decl = TypeDeclaration {
430 span: code.token_span(),
431 ident: code.s1("foo").decl_ident(),
432 def: TypeDefinition::Array(
433 vec![ArrayIndex::Discrete(WithTokenSpan::new(
434 DiscreteRange::Discrete(code.s1("natural").type_mark(), None),
435 code.s1("natural").token_span(),
436 ))],
437 code.s1("of").token(),
438 code.s1("boolean").subtype_indication(),
439 ),
440 end_ident_pos: None,
441 };
442
443 assert_eq!(
444 code.with_stream_no_diagnostics(parse_type_declaration),
445 type_decl
446 );
447 }
448
449 #[test]
450 fn parse_array_type_definition_with_selected_name() {
451 let code = Code::new("type foo is array (lib.pkg.foo) of boolean;");
452
453 let type_decl = TypeDeclaration {
454 span: code.token_span(),
455 ident: code.s1("foo").decl_ident(),
456 def: TypeDefinition::Array(
457 vec![ArrayIndex::Discrete(WithTokenSpan::new(
458 DiscreteRange::Discrete(code.s1("lib.pkg.foo").type_mark(), None),
459 code.s1("lib.pkg.foo").token_span(),
460 ))],
461 code.s1("of").token(),
462 code.s1("boolean").subtype_indication(),
463 ),
464 end_ident_pos: None,
465 };
466
467 assert_eq!(
468 code.with_stream_no_diagnostics(parse_type_declaration),
469 type_decl
470 );
471 }
472
473 #[test]
474 fn parse_array_type_definition_with_range_attribute_name() {
475 let code = Code::new("type foo is array (arr_t'range) of boolean;");
476
477 let type_decl = TypeDeclaration {
478 span: code.token_span(),
479 ident: code.s1("foo").decl_ident(),
480 def: TypeDefinition::Array(
481 vec![ArrayIndex::Discrete(WithTokenSpan::new(
482 DiscreteRange::Range(code.s1("arr_t'range").range()),
483 code.s1("arr_t'range").token_span(),
484 ))],
485 code.s1("of").token(),
486 code.s1("boolean").subtype_indication(),
487 ),
488 end_ident_pos: None,
489 };
490
491 assert_eq!(
492 code.with_stream_no_diagnostics(parse_type_declaration),
493 type_decl
494 );
495 }
496
497 #[test]
498 fn parse_array_type_definition_with_constraint() {
499 let code = Code::new("type foo is array (2-1 downto 0) of boolean;");
500
501 let index = ArrayIndex::Discrete(WithTokenSpan::new(
502 DiscreteRange::Range(code.s1("2-1 downto 0").range()),
503 code.s1("2-1 downto 0").token_span(),
504 ));
505
506 let type_decl = TypeDeclaration {
507 span: code.token_span(),
508 ident: code.s1("foo").decl_ident(),
509 def: TypeDefinition::Array(
510 vec![index],
511 code.s1("of").token(),
512 code.s1("boolean").subtype_indication(),
513 ),
514 end_ident_pos: None,
515 };
516
517 assert_eq!(
518 code.with_stream_no_diagnostics(parse_type_declaration),
519 type_decl
520 );
521 }
522
523 #[test]
524 fn parse_array_type_definition_mixed() {
525 let code = Code::new("type foo is array (2-1 downto 0, integer range <>) of boolean;");
526
527 let index0 = ArrayIndex::Discrete(WithTokenSpan::new(
528 DiscreteRange::Range(code.s1("2-1 downto 0").range()),
529 code.s1("2-1 downto 0").token_span(),
530 ));
531
532 let index1 = ArrayIndex::IndexSubtypeDefintion(code.s1("integer").type_mark());
533
534 let type_decl = TypeDeclaration {
535 span: code.token_span(),
536 ident: code.s1("foo").decl_ident(),
537 def: TypeDefinition::Array(
538 vec![index0, index1],
539 code.s1("of").token(),
540 code.s1("boolean").subtype_indication(),
541 ),
542 end_ident_pos: None,
543 };
544
545 assert_eq!(
546 code.with_stream_no_diagnostics(parse_type_declaration),
547 type_decl
548 );
549 }
550
551 #[test]
552 fn parse_record_type_definition() {
553 let code = Code::new(
554 "\
555type foo is record
556 element : boolean;
557end record;",
558 );
559
560 let elem_decl = ElementDeclaration {
561 idents: vec![code.s1("element").decl_ident()],
562 subtype: code.s1("boolean").subtype_indication(),
563 colon_token: code.s1(":").token(),
564 span: code.s1("element : boolean;").token_span(),
565 };
566
567 let type_decl = TypeDeclaration {
568 span: code.token_span(),
569 ident: code.s1("foo").decl_ident(),
570 def: TypeDefinition::Record(vec![elem_decl]),
571 end_ident_pos: None,
572 };
573
574 assert_eq!(
575 code.with_stream_no_diagnostics(parse_type_declaration),
576 type_decl
577 );
578 }
579
580 #[test]
581 fn parse_record_type_definition_many() {
582 let code = Code::new(
583 "\
584 type foo is record
585 element, field : boolean;
586 other_element : std_logic_vector(0 to 1);
587end foo;",
588 );
589
590 let elem_decl0 = ElementDeclaration {
591 idents: vec![
592 code.s1("element").decl_ident(),
593 code.s1("field").decl_ident(),
594 ],
595 colon_token: code.s1(":").token(),
596 subtype: code.s1("boolean").subtype_indication(),
597 span: code.s1("element, field : boolean;").token_span(),
598 };
599
600 let elem_decl1 = ElementDeclaration {
601 idents: vec![code.s1("other_element").decl_ident()],
602 colon_token: code.s(":", 2).token(),
603 subtype: code.s1("std_logic_vector(0 to 1)").subtype_indication(),
604 span: code
605 .s1("other_element : std_logic_vector(0 to 1);")
606 .token_span(),
607 };
608
609 let type_decl = TypeDeclaration {
610 span: code.token_span(),
611 ident: code.s1("foo").decl_ident(),
612 def: TypeDefinition::Record(vec![elem_decl0, elem_decl1]),
613 end_ident_pos: Some(code.s("foo", 2).token()),
614 };
615
616 assert_eq!(
617 code.with_stream_no_diagnostics(parse_type_declaration),
618 type_decl
619 );
620 }
621
622 #[test]
623 fn test_parse_subtype_declaration() {
624 let code = Code::new("subtype vec_t is integer_vector(2-1 downto 0);");
625
626 assert_eq!(
627 code.with_stream_no_diagnostics(parse_type_declaration),
628 TypeDeclaration {
629 span: code.token_span(),
630 ident: code.s1("vec_t").decl_ident(),
631 def: TypeDefinition::Subtype(
632 code.s1("integer_vector(2-1 downto 0)").subtype_indication()
633 ),
634 end_ident_pos: None,
635 }
636 );
637 }
638
639 #[test]
640 fn test_parse_access_type_declaration() {
641 let code = Code::new("type ptr_t is access integer_vector(2-1 downto 0);");
642
643 assert_eq!(
644 code.with_stream_no_diagnostics(parse_type_declaration),
645 TypeDeclaration {
646 span: code.token_span(),
647 ident: code.s1("ptr_t").decl_ident(),
648 def: TypeDefinition::Access(
649 code.s1("integer_vector(2-1 downto 0)").subtype_indication()
650 ),
651 end_ident_pos: None,
652 }
653 );
654 }
655
656 #[test]
657 fn test_incomplete_type_declaration() {
658 let code = Code::new("type incomplete;");
659
660 assert_eq!(
661 code.with_stream_no_diagnostics(parse_type_declaration),
662 TypeDeclaration {
663 span: code.token_span(),
664 ident: code.s1("incomplete").decl_ident(),
665 def: TypeDefinition::Incomplete(Reference::undefined()),
666 end_ident_pos: None,
667 }
668 );
669 }
670
671 #[test]
672 fn test_file_type_declaration() {
673 let code = Code::new("type foo is file of character;");
674
675 assert_eq!(
676 code.with_stream_no_diagnostics(parse_type_declaration),
677 TypeDeclaration {
678 span: code.token_span(),
679 ident: code.s1("foo").decl_ident(),
680 def: TypeDefinition::File(code.s1("character").type_mark()),
681 end_ident_pos: None,
682 }
683 );
684 }
685
686 fn protected_decl(
687 ident: Ident,
688 token_span: TokenSpan,
689 items: Vec<ProtectedTypeDeclarativeItem>,
690 end_ident_pos: Option<TokenId>,
691 ) -> TypeDeclaration {
692 TypeDeclaration {
693 span: token_span,
694 ident: ident.into(),
695 def: TypeDefinition::Protected(ProtectedTypeDeclaration { items }),
696 end_ident_pos,
697 }
698 }
699
700 #[test]
701 fn test_protected_type_declaration() {
702 let code = Code::new(
703 "\
704type foo is protected
705end protected;
706",
707 );
708 assert_eq!(
709 code.with_stream_no_diagnostics(parse_type_declaration),
710 protected_decl(code.s1("foo").ident(), code.token_span(), vec![], None)
711 )
712 }
713
714 #[test]
715 fn test_protected_type_declaration_simple_name_suffix() {
716 let code = Code::new(
717 "\
718type foo is protected
719end protected foo;
720",
721 );
722 assert_eq!(
723 code.with_stream_no_diagnostics(parse_type_declaration),
724 protected_decl(
725 code.s1("foo").ident(),
726 code.token_span(),
727 vec![],
728 Some(code.s("foo", 2).token())
729 )
730 )
731 }
732
733 #[test]
734 fn test_protected_type_declaration_with_subprograms() {
735 let code = Code::new(
736 "\
737type foo is protected
738 procedure proc;
739 function fun return ret;
740end protected;
741",
742 );
743 let items = vec![
744 ProtectedTypeDeclarativeItem::Subprogram(code.s1("procedure proc;").subprogram_decl()),
745 ProtectedTypeDeclarativeItem::Subprogram(
746 code.s1("function fun return ret;").subprogram_decl(),
747 ),
748 ];
749
750 assert_eq!(
751 code.with_stream_no_diagnostics(parse_type_declaration),
752 protected_decl(code.s1("foo").ident(), code.token_span(), items, None)
753 )
754 }
755
756 #[test]
757 fn test_protected_type_body() {
758 let code = Code::new(
759 "\
760type foo is protected body
761 variable foo : natural;
762 procedure proc is
763 begin
764 end;
765end protected body;
766",
767 );
768
769 let decl = code
770 .s1("\
771 variable foo : natural;
772 procedure proc is
773 begin
774 end;")
775 .declarative_part();
776
777 let ident = code.s1("foo").decl_ident();
778 assert_eq!(
779 code.with_stream_no_diagnostics(parse_type_declaration),
780 TypeDeclaration {
781 span: code.token_span(),
782 ident,
783 def: TypeDefinition::ProtectedBody(ProtectedTypeBody { decl }),
784 end_ident_pos: None,
785 }
786 )
787 }
788
789 #[test]
790 fn test_physical_type_declaration() {
791 let code = Code::new(
792 "\
793type phys is range 0 to 15 units
794 primary_unit;
795end units phys;
796",
797 );
798
799 assert_eq!(
800 code.with_stream_no_diagnostics(parse_type_declaration),
801 TypeDeclaration {
802 span: code.token_span(),
803 ident: code.s1("phys").decl_ident(),
804 def: TypeDefinition::Physical(PhysicalTypeDeclaration {
805 range: code.s1("0 to 15").range(),
806 units_token: code.s1("units").token(),
807 primary_unit: code.s1("primary_unit").decl_ident(),
808 secondary_units: vec![]
809 }),
810 end_ident_pos: Some(code.s("phys", 2).token()),
811 }
812 )
813 }
814
815 #[test]
816 fn test_physical_type_declaration_secondary_units() {
817 let code = Code::new(
818 "\
819type phys is range 0 to 15 units
820 primary_unit;
821 secondary_unit = 5 primary_unit;
822end units;
823",
824 );
825
826 assert_eq!(
827 code.with_stream_no_diagnostics(parse_type_declaration),
828 TypeDeclaration {
829 span: code.token_span(),
830 ident: code.s1("phys").decl_ident(),
831 def: TypeDefinition::Physical(PhysicalTypeDeclaration {
832 range: code.s1("0 to 15").range(),
833 units_token: code.s1("units").token(),
834 primary_unit: code.s1("primary_unit").decl_ident(),
835 secondary_units: vec![(
836 code.s1("secondary_unit").decl_ident(),
837 WithTokenSpan::new(
838 PhysicalLiteral {
839 value: AbstractLiteral::Integer(5),
840 unit: code.s("primary_unit", 2).ident().into_ref()
841 },
842 code.s1("5 primary_unit").token_span()
843 )
844 ),]
845 }),
846 end_ident_pos: None,
847 }
848 )
849 }
850
851 #[test]
852 fn test_physical_type_declaration_implicit_secondary_units() {
853 let code = Code::new(
854 "\
855type phys is range 0 to 15 units
856 primary_unit;
857 secondary_unit = primary_unit;
858end units;
859",
860 );
861
862 assert_eq!(
863 code.with_stream_no_diagnostics(parse_type_declaration),
864 TypeDeclaration {
865 span: code.token_span(),
866 ident: code.s1("phys").decl_ident(),
867 def: TypeDefinition::Physical(PhysicalTypeDeclaration {
868 range: code.s1("0 to 15").range(),
869 units_token: code.s1("units").token(),
870 primary_unit: code.s1("primary_unit").decl_ident(),
871 secondary_units: vec![(
872 code.s1("secondary_unit").decl_ident(),
873 WithTokenSpan::new(
874 PhysicalLiteral {
875 value: AbstractLiteral::Integer(1),
876 unit: code.s("primary_unit", 2).ident().into_ref()
877 },
878 code.s("primary_unit", 2).token_span()
879 )
880 ),]
881 }),
882 end_ident_pos: None,
883 }
884 )
885 }
886
887 #[test]
888 pub fn test_token_span() {
889 let code = Code::new(
890 "\
891package pkg is
892 subtype negative is integer range -2**31 to -1;
893 type incomplete;
894 type new_integer is range 100 downto -100;
895 type line is access string;
896 type prot is
897 protected
898 procedure proc;
899 end protected;
900 type IntegerFile is file of INTEGER;
901 type arr is array (natural range <>) of positive;
902 type dummy_rec is
903 record
904 dummy: bit;
905 end record;
906 type enum is (V1, V2, V3);
907end package;
908",
909 );
910 let ctx = code.tokenize();
911 let pkg = code.package_declaration();
912 let type_decls = pkg
913 .decl
914 .iter()
915 .map(|d| {
916 if let Declaration::Type(obj) = &d.item {
917 obj
918 } else {
919 panic!("Only object declarations are expected!")
920 }
921 })
922 .collect_vec();
923
924 let type_decl_strings: Vec<Vec<String>> = type_decls
925 .iter()
926 .map(|decl| {
927 decl.get_token_slice(&ctx)
928 .iter()
929 .map(token_to_string)
930 .collect()
931 })
932 .collect_vec();
933
934 assert_eq!(
935 type_decl_strings[0],
936 vec![
937 "subtype", "negative", "is", "integer", "range", "-", "2", "**", "31", "to", "-",
938 "1", ";"
939 ],
940 );
941 assert_eq!(type_decl_strings[1], vec!["type", "incomplete", ";"],);
942 assert_eq!(
943 type_decl_strings[2],
944 vec![
945 "type",
946 "new_integer",
947 "is",
948 "range",
949 "100",
950 "downto",
951 "-",
952 "100",
953 ";"
954 ],
955 );
956 assert_eq!(
957 type_decl_strings[3],
958 vec!["type", "line", "is", "access", "string", ";"],
959 );
960 assert_eq!(
961 type_decl_strings[4],
962 vec![
963 "type",
964 "prot",
965 "is",
966 "protected",
967 "procedure",
968 "proc",
969 ";",
970 "end",
971 "protected",
972 ";"
973 ],
974 );
975 assert_eq!(
976 type_decl_strings[5],
977 vec!["type", "IntegerFile", "is", "file", "of", "INTEGER", ";"],
978 );
979 assert_eq!(
980 type_decl_strings[6],
981 vec![
982 "type", "arr", "is", "array", "(", "natural", "range", "<>", ")", "of", "positive",
983 ";",
984 ],
985 );
986 assert_eq!(
987 type_decl_strings[7],
988 vec![
989 "type",
990 "dummy_rec",
991 "is",
992 "record",
993 "dummy",
994 ":",
995 "bit",
996 ";",
997 "end",
998 "record",
999 ";",
1000 ],
1001 );
1002 }
1003}