@@ -9,6 +9,7 @@ use super::common::ParseResult;
99use super :: declarative_part:: { is_declarative_part, parse_declarative_part} ;
1010use super :: expression:: parse_aggregate_leftpar_known;
1111use super :: expression:: { parse_choices, parse_expression} ;
12+ use super :: interface_declaration:: { parse_generic_interface_list, parse_port_interface_list} ;
1213use super :: names:: {
1314 expression_to_ident, into_selected_name, parse_association_list, parse_name_initial_token,
1415 parse_selected_name,
@@ -31,10 +32,6 @@ pub fn parse_block_statement(
3132 let token = stream. peek_expect ( ) ?;
3233 let guard_condition = {
3334 match token. kind {
34- Is => {
35- stream. move_after ( & token) ;
36- None
37- }
3835 LeftPar => {
3936 stream. move_after ( & token) ;
4037 let expr = parse_expression ( stream) ?;
@@ -44,6 +41,8 @@ pub fn parse_block_statement(
4441 _ => None ,
4542 }
4643 } ;
44+ stream. pop_if_kind ( Is ) ?;
45+ let header = parse_block_header ( stream, diagnostics) ?;
4746 let decl = parse_declarative_part ( stream, diagnostics, true ) ?;
4847 let statements = parse_labeled_concurrent_statements ( stream, diagnostics) ?;
4948 stream. expect_kind ( Block ) ?;
@@ -52,11 +51,105 @@ pub fn parse_block_statement(
5251 stream. expect_kind ( SemiColon ) ?;
5352 Ok ( BlockStatement {
5453 guard_condition,
54+ header,
5555 decl,
5656 statements,
5757 } )
5858}
5959
60+ fn parse_block_header (
61+ stream : & mut TokenStream ,
62+ diagnostics : & mut dyn DiagnosticHandler ,
63+ ) -> ParseResult < BlockHeader > {
64+ let mut generic_clause = None ;
65+ let mut generic_map = None ;
66+ let mut port_clause = None ;
67+ let mut port_map = None ;
68+
69+ loop {
70+ let token = stream. peek_expect ( ) ?;
71+ match token. kind {
72+ Generic => {
73+ stream. move_after ( & token) ;
74+ if let Some ( map_token) = stream. pop_if_kind ( Map ) ? {
75+ if port_clause. is_some ( ) || port_map. is_some ( ) {
76+ diagnostics. push ( Diagnostic :: error (
77+ map_token,
78+ "Generic map must come before port clause and port map" ,
79+ ) ) ;
80+ } else if generic_clause. is_none ( ) {
81+ diagnostics. push ( Diagnostic :: error (
82+ map_token,
83+ "Generic map declared without preceeding generic clause" ,
84+ ) ) ;
85+ } else if generic_map. is_some ( ) {
86+ diagnostics. push ( Diagnostic :: error ( map_token, "Duplicate generic map" ) ) ;
87+ }
88+ let parsed_generic_map = Some ( parse_association_list ( stream) ?) ;
89+ stream. expect_kind ( SemiColon ) ?;
90+ if generic_map. is_none ( ) {
91+ generic_map = parsed_generic_map;
92+ }
93+ } else {
94+ if generic_map. is_some ( ) {
95+ diagnostics. push ( Diagnostic :: error (
96+ token,
97+ "Generic clause must come before generic map" ,
98+ ) ) ;
99+ } else if generic_clause. is_some ( ) {
100+ diagnostics. push ( Diagnostic :: error ( token, "Duplicate generic clause" ) ) ;
101+ }
102+ let parsed_generic_list = parse_generic_interface_list ( stream, diagnostics) ?;
103+ stream. expect_kind ( SemiColon ) ?;
104+ if generic_clause. is_none ( ) {
105+ generic_clause = Some ( parsed_generic_list) ;
106+ }
107+ }
108+ }
109+ Port => {
110+ stream. move_after ( & token) ;
111+ if let Some ( map_token) = stream. pop_if_kind ( Map ) ? {
112+ if port_clause. is_none ( ) {
113+ diagnostics. push ( Diagnostic :: error (
114+ map_token,
115+ "Port map declared without preceeding port clause" ,
116+ ) ) ;
117+ } else if port_map. is_some ( ) {
118+ diagnostics. push ( Diagnostic :: error ( map_token, "Duplicate port map" ) ) ;
119+ }
120+ let parsed_port_map = Some ( parse_association_list ( stream) ?) ;
121+ stream. expect_kind ( SemiColon ) ?;
122+ if port_map. is_none ( ) {
123+ port_map = parsed_port_map;
124+ }
125+ } else {
126+ if port_map. is_some ( ) {
127+ diagnostics. push ( Diagnostic :: error (
128+ token,
129+ "Port clause declared after port map" ,
130+ ) ) ;
131+ } else if port_clause. is_some ( ) {
132+ diagnostics. push ( Diagnostic :: error ( token, "Duplicate port clause" ) ) ;
133+ }
134+ let parsed_port_list = parse_port_interface_list ( stream, diagnostics) ?;
135+ stream. expect_kind ( SemiColon ) ?;
136+ if port_clause. is_none ( ) {
137+ port_clause = Some ( parsed_port_list) ;
138+ }
139+ }
140+ }
141+ _ => break ,
142+ }
143+ }
144+
145+ Ok ( BlockHeader {
146+ generic_clause,
147+ generic_map,
148+ port_clause,
149+ port_map,
150+ } )
151+ }
152+
60153/// LRM 11.3 Process statement
61154pub fn parse_process_statement (
62155 stream : & mut TokenStream ,
@@ -687,6 +780,12 @@ end block;
687780
688781 let block = BlockStatement {
689782 guard_condition : None ,
783+ header : BlockHeader {
784+ generic_clause : None ,
785+ generic_map : None ,
786+ port_clause : None ,
787+ port_map : None ,
788+ } ,
690789 decl : code. s1 ( "constant const : natural := 0;" ) . declarative_part ( ) ,
691790 statements : vec ! [ LabeledConcurrentStatement {
692791 label: Some ( code. s1( "name2" ) . ident( ) ) ,
@@ -709,6 +808,12 @@ end block name;
709808 ) ;
710809 let block = BlockStatement {
711810 guard_condition : None ,
811+ header : BlockHeader {
812+ generic_clause : None ,
813+ generic_map : None ,
814+ port_clause : None ,
815+ port_map : None ,
816+ } ,
712817 decl : vec ! [ ] ,
713818 statements : vec ! [ ] ,
714819 } ;
@@ -728,6 +833,66 @@ end block;
728833 ) ;
729834 let block = BlockStatement {
730835 guard_condition : Some ( code. s1 ( "cond = true" ) . expr ( ) ) ,
836+ header : BlockHeader {
837+ generic_clause : None ,
838+ generic_map : None ,
839+ port_clause : None ,
840+ port_map : None ,
841+ } ,
842+ decl : vec ! [ ] ,
843+ statements : vec ! [ ] ,
844+ } ;
845+ let stmt = code. with_stream_no_diagnostics ( parse_labeled_concurrent_statement) ;
846+ assert_eq ! ( stmt. label, Some ( code. s1( "name" ) . ident( ) ) ) ;
847+ assert_eq ! ( stmt. statement, ConcurrentStatement :: Block ( block) ) ;
848+ }
849+
850+ #[ test]
851+ fn test_guarded_block_variant ( ) {
852+ let code = Code :: new (
853+ "\
854+ name : block (cond = true) is
855+ begin
856+ end block;
857+ " ,
858+ ) ;
859+ let block = BlockStatement {
860+ guard_condition : Some ( code. s1 ( "cond = true" ) . expr ( ) ) ,
861+ header : BlockHeader {
862+ generic_clause : None ,
863+ generic_map : None ,
864+ port_clause : None ,
865+ port_map : None ,
866+ } ,
867+ decl : vec ! [ ] ,
868+ statements : vec ! [ ] ,
869+ } ;
870+ let stmt = code. with_stream_no_diagnostics ( parse_labeled_concurrent_statement) ;
871+ assert_eq ! ( stmt. label, Some ( code. s1( "name" ) . ident( ) ) ) ;
872+ assert_eq ! ( stmt. statement, ConcurrentStatement :: Block ( block) ) ;
873+ }
874+
875+ #[ test]
876+ fn test_block_header ( ) {
877+ let code = Code :: new (
878+ "\
879+ name: block is
880+ generic(gen: integer := 1);
881+ generic map(gen => 1);
882+ port(prt: integer := 1);
883+ port map(prt => 2);
884+ begin
885+ end block;
886+ " ,
887+ ) ;
888+ let block = BlockStatement {
889+ guard_condition : None ,
890+ header : BlockHeader {
891+ generic_clause : Some ( vec ! [ code. s1( "gen: integer := 1" ) . generic( ) ] ) ,
892+ generic_map : Some ( code. s1 ( "(gen => 1)" ) . association_list ( ) ) ,
893+ port_clause : Some ( vec ! [ code. s1( "prt: integer := 1" ) . port( ) ] ) ,
894+ port_map : Some ( code. s1 ( "(prt => 2)" ) . association_list ( ) ) ,
895+ } ,
731896 decl : vec ! [ ] ,
732897 statements : vec ! [ ] ,
733898 } ;
0 commit comments