diff --git a/ivtest/ivltests/sv_class_constructor1.v b/ivtest/ivltests/sv_class_constructor1.v new file mode 100644 index 000000000..e886b6f57 --- /dev/null +++ b/ivtest/ivltests/sv_class_constructor1.v @@ -0,0 +1,14 @@ +// Check that a class constructor declaration without parenthesis after the +// `new` is supported. + +module test; + + class C; + function new; + $display("PASSED"); + endfunction + endclass + + C c = new; + +endmodule diff --git a/ivtest/ivltests/sv_class_constructor_fail.v b/ivtest/ivltests/sv_class_constructor_fail.v new file mode 100644 index 000000000..66490d706 --- /dev/null +++ b/ivtest/ivltests/sv_class_constructor_fail.v @@ -0,0 +1,14 @@ +// Check that a class constructor with non-ANSI port results in an error. + +module test; + + class C; + function new; + input x; // This is a syntax error + $display("FAILED"); + endfunction + endclass + + C c = new; + +endmodule diff --git a/ivtest/ivltests/sv_class_super1.v b/ivtest/ivltests/sv_class_super1.v new file mode 100644 index 000000000..ddc7b1a77 --- /dev/null +++ b/ivtest/ivltests/sv_class_super1.v @@ -0,0 +1,21 @@ +// Check that it is possible to explicitly call the base class constructor, even +// if it does not take any parameters. Check that it is possible to call it with +// parenthesis after the `new`. + +module test; + + class B; + function new(); + $display("PASSED"); + endfunction + endclass + + class C extends B; + function new(); + super.new(); + endfunction + endclass + + C c = new; + +endmodule diff --git a/ivtest/ivltests/sv_class_super2.v b/ivtest/ivltests/sv_class_super2.v new file mode 100644 index 000000000..b21165d1f --- /dev/null +++ b/ivtest/ivltests/sv_class_super2.v @@ -0,0 +1,21 @@ +// Check that it is possible to explicitly call the base class constructor, even +// if it does not take any parameters. Check that it is possible to call it +// without parenthesis after the `new`. + +module test; + + class B; + function new(); + $display("PASSED"); + endfunction + endclass + + class C extends B; + function new(); + super.new; + endfunction + endclass + + C c = new; + +endmodule diff --git a/ivtest/ivltests/sv_class_task1.v b/ivtest/ivltests/sv_class_task1.v new file mode 100644 index 000000000..5674ec950 --- /dev/null +++ b/ivtest/ivltests/sv_class_task1.v @@ -0,0 +1,22 @@ +// Check that it is possible to call a class task without parenthesis after the +// task name when using the implicit `this` class handle. + +module test; + + class C; + task a; + $display("PASSED"); + endtask + + task b; + this.a; + endtask + endclass + + C c = new; + + initial begin + c.b; + end + +endmodule diff --git a/ivtest/regress-sv.list b/ivtest/regress-sv.list index b135d511c..1866f95cd 100644 --- a/ivtest/regress-sv.list +++ b/ivtest/regress-sv.list @@ -476,11 +476,16 @@ sv_class21 normal,-g2009 ivltests sv_class22 normal,-g2009 ivltests sv_class23 normal,-g2009 ivltests sv_class24 normal,-g2009 ivltests +sv_class_constructor1 normal,-g2009 ivltests +sv_class_constructor_fail CE,-g2009 ivltests sv_class_empty_item normal,-g2009 ivltests sv_class_extends_scoped normal,-g2009 ivltests sv_class_localparam normal,-g2009 ivltests sv_class_new_init normal,-g2009 ivltests sv_class_in_module_decl normal,-g2009 ivltests +sv_class_super1 normal,-g2009 ivltests +sv_class_super2 normal,-g2009 ivltests +sv_class_task1 normal,-g2009 ivltests sv_darray1 normal,-g2009 ivltests sv_darray2 normal,-g2009 ivltests sv_darray3 normal,-g2009 ivltests diff --git a/ivtest/regress-vlog95.list b/ivtest/regress-vlog95.list index 83145393d..372efc87b 100644 --- a/ivtest/regress-vlog95.list +++ b/ivtest/regress-vlog95.list @@ -374,11 +374,15 @@ sv_class21 CE,-g2009 ivltests sv_class22 CE,-g2009 ivltests sv_class23 CE,-g2009 ivltests sv_class24 CE,-g2009 ivltests +sv_class_constructor1 CE,-g2009 ivltests sv_class_empty_item CE,-g2009 ivltests sv_class_extends_scoped CE,-g2009 ivltests sv_class_localparam CE,-g2009 ivltests sv_class_new_init CE,-g2009 ivltests sv_class_in_module_decl CE,-g2009 ivltests +sv_class_super1 CE,-g2009 ivltests +sv_class_super2 CE,-g2009 ivltests +sv_class_task1 CE,-g2009 ivltests sv_end_label CE,-g2009 ivltests # Also generate sv_foreach2 CE,-g2009,-pallowsigned=1 ivltests sv_foreach3 CE,-g2009 ivltests diff --git a/parse.y b/parse.y index 1e802d8a4..16b9b7931 100644 --- a/parse.y +++ b/parse.y @@ -621,7 +621,8 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector enum_data_type enum_base_type %type tf_item_declaration tf_item_list tf_item_list_opt -%type tf_port_declaration tf_port_item tf_port_item_list tf_port_list tf_port_list_opt +%type tf_port_declaration tf_port_item tf_port_item_list +%type tf_port_list tf_port_list_opt tf_port_list_parens_opt %type modport_simple_port port_name parameter_value_byname %type port_name_list parameter_value_byname_list @@ -638,7 +639,7 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector let_port_list_opt let_port_list %type let_port_item -%type hierarchy_identifier implicit_class_handle +%type hierarchy_identifier implicit_class_handle class_hierarchy_identifier %type assignment_pattern expression expr_mintypmax %type expr_primary_or_typename expr_primary %type class_new dynamic_array_new let_default_opt @@ -648,6 +649,7 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector delay_value delay_value_simple %type delay1 delay3 delay3_opt delay_value_list %type expression_list_with_nuls expression_list_proper +%type argument_list_parens_opt %type cont_assign cont_assign_list %type variable_decl_assignment @@ -861,13 +863,9 @@ class_declaration_endlabel_opt a data_type. */ class_declaration_extends_opt /* IEEE1800-2005: A.1.2 */ - : K_extends ps_type_identifier + : K_extends ps_type_identifier argument_list_parens_opt { $$.type = $2; - $$.exprs = 0; - } - | K_extends ps_type_identifier '(' expression_list_with_nuls ')' - { $$.type = $2; - $$.exprs = $4; + $$.exprs = $3; } | { $$.type = 0; $$.exprs = 0; } @@ -893,14 +891,14 @@ class_item /* IEEE1800-2005: A.1.8 */ { assert(current_function==0); current_function = pform_push_constructor_scope(@3); } - '(' tf_port_list_opt ')' ';' - tf_item_list_opt + tf_port_list_parens_opt ';' + block_item_decls_opt statement_or_null_list_opt K_endfunction endnew_opt - { current_function->set_ports($6); + { current_function->set_ports($5); pform_set_constructor_return(current_function); pform_set_this_class(@3, current_function); - current_function_set_statement(@3, $10); + current_function_set_statement(@3, $8); pform_pop_scope(); current_function = 0; } @@ -928,25 +926,14 @@ class_item /* IEEE1800-2005: A.1.8 */ /* External class method definitions... */ - | K_extern method_qualifier_opt K_function K_new ';' - { yyerror(@1, "sorry: External constructors are not yet supported."); } - | K_extern method_qualifier_opt K_function K_new '(' tf_port_list_opt ')' ';' + | K_extern method_qualifier_opt K_function K_new tf_port_list_parens_opt ';' { yyerror(@1, "sorry: External constructors are not yet supported."); } | K_extern method_qualifier_opt K_function data_type_or_implicit_or_void - IDENTIFIER ';' + IDENTIFIER tf_port_list_parens_opt ';' { yyerror(@1, "sorry: External methods are not yet supported."); delete[] $5; } - | K_extern method_qualifier_opt K_function data_type_or_implicit_or_void - IDENTIFIER '(' tf_port_list_opt ')' ';' - { yyerror(@1, "sorry: External methods are not yet supported."); - delete[] $5; - } - | K_extern method_qualifier_opt K_task IDENTIFIER ';' - { yyerror(@1, "sorry: External methods are not yet supported."); - delete[] $4; - } - | K_extern method_qualifier_opt K_task IDENTIFIER '(' tf_port_list_opt ')' ';' + | K_extern method_qualifier_opt K_task IDENTIFIER tf_port_list_parens_opt ';' { yyerror(@1, "sorry: External methods are not yet supported."); delete[] $4; } @@ -1002,12 +989,12 @@ class_item_qualifier_opt ; class_new /* IEEE1800-2005 A.2.4 */ - : K_new '(' expression_list_with_nuls ')' - { std::list*expr_list = $3; + : K_new argument_list_parens_opt + { std::list*expr_list = $2; strip_tail_items(expr_list); PENewClass*tmp = new PENewClass(*expr_list); FILE_NAME(tmp, @1); - delete $3; + delete $2; $$ = tmp; } | K_new hierarchy_identifier @@ -1018,11 +1005,6 @@ class_new /* IEEE1800-2005 A.2.4 */ delete $2; $$ = tmp; } - | K_new - { PENewClass*tmp = new PENewClass; - FILE_NAME(tmp, @1); - $$ = tmp; - } ; /* The concurrent_assertion_item pulls together the @@ -1554,6 +1536,15 @@ implicit_class_handle /* IEEE1800-2005: A.8.4 */ | K_super { $$ = pform_create_super(); } ; +/* `this` or `super` followed by an identifier */ +class_hierarchy_identifier + : implicit_class_handle '.' hierarchy_identifier + { $1->splice($1->end(), *$3); + delete $3; + $$ = $1; + } + ; + /* SystemVerilog adds support for the increment/decrement expressions, which look like a++, --a, etc. These are primaries but are in their own rules because they can also be @@ -1937,10 +1928,8 @@ modport_simple_port ; modport_tf_port - : K_task IDENTIFIER - | K_task IDENTIFIER '(' tf_port_list_opt ')' - | K_function data_type_or_implicit_or_void IDENTIFIER - | K_function data_type_or_implicit_or_void IDENTIFIER '(' tf_port_list_opt ')' + : K_task IDENTIFIER tf_port_list_parens_opt + | K_function data_type_or_implicit_or_void IDENTIFIER tf_port_list_parens_opt ; non_integer_type /* IEEE1800-2005: A.2.2.1 */ @@ -3637,6 +3626,13 @@ expression_list_with_nuls } ; + /* A task or function can be invoked with the task/function name followed by + * an argument list in parenthesis or with just the task/function name by + * itself. When an argument list is used it might be empty. */ +argument_list_parens_opt + : '(' expression_list_with_nuls ')' { $$ = $2; } + | { $$ = new std::list; } + expression_list_proper : expression_list_proper ',' expression { std::list*tmp = $1; @@ -3772,17 +3768,11 @@ expr_primary delete $2; $$ = tmp; } - | implicit_class_handle '.' hierarchy_identifier '(' expression_list_with_nuls ')' - { pform_name_t*t_name = $1; - while (! $3->empty()) { - t_name->push_back($3->front()); - $3->pop_front(); - } - list*expr_list = $5; + | class_hierarchy_identifier '(' expression_list_with_nuls ')' + { list*expr_list = $3; strip_tail_items(expr_list); - PECallFunction*tmp = pform_make_call_function(@1, *t_name, *expr_list); + PECallFunction*tmp = pform_make_call_function(@1, *$1, *expr_list); delete $1; - delete $3; $$ = tmp; } | SYSTEM_IDENTIFIER '(' expression_list_proper ')' @@ -3816,16 +3806,10 @@ expr_primary $$ = tmp; } - | implicit_class_handle '.' hierarchy_identifier - { pform_name_t*t_name = $1; - while (! $3->empty()) { - t_name->push_back($3->front()); - $3->pop_front(); - } - PEIdent*tmp = new PEIdent(*t_name); - FILE_NAME(tmp,@1); + | class_hierarchy_identifier + { PEIdent*tmp = new PEIdent(*$1); + FILE_NAME(tmp, @1); delete $1; - delete $3; $$ = tmp; } @@ -4623,17 +4607,11 @@ lpvalue delete $1; } - | implicit_class_handle '.' hierarchy_identifier - { pform_name_t*t_name = $1; - while (!$3->empty()) { - t_name->push_back($3->front()); - $3->pop_front(); - } - PEIdent*tmp = new PEIdent(*t_name); + | class_hierarchy_identifier + { PEIdent*tmp = new PEIdent(*$1); FILE_NAME(tmp, @1); $$ = tmp; delete $1; - delete $3; } | '{' expression_list_proper '}' @@ -5193,15 +5171,10 @@ module_item { pform_endgenerate(true); } /* Elaboration system tasks. */ - | SYSTEM_IDENTIFIER '(' expression_list_with_nuls ')' ';' - { pform_make_elab_task(@1, lex_strings.make($1), *$3); - delete[]$1; - delete $3; - } - | SYSTEM_IDENTIFIER ';' - { std::listpt; - pform_make_elab_task(@1, lex_strings.make($1), pt); + | SYSTEM_IDENTIFIER argument_list_parens_opt ';' + { pform_make_elab_task(@1, lex_strings.make($1), *$2); delete[]$1; + delete $2; } | modport_declaration @@ -6638,25 +6611,18 @@ statement_item /* This is roughly statement_item in the LRM */ FILE_NAME(tmp,@1); $$ = tmp; } - | SYSTEM_IDENTIFIER '(' expression_list_with_nuls ')' ';' - { PCallTask*tmp = new PCallTask(lex_strings.make($1), *$3); - FILE_NAME(tmp,@1); - delete[]$1; - delete $3; - $$ = tmp; - } - | SYSTEM_IDENTIFIER ';' - { std::listpt; - PCallTask*tmp = new PCallTask(lex_strings.make($1), pt); + | SYSTEM_IDENTIFIER argument_list_parens_opt ';' + { PCallTask*tmp = new PCallTask(lex_strings.make($1), *$2); FILE_NAME(tmp,@1); delete[]$1; + delete $2; $$ = tmp; } - | hierarchy_identifier '(' expression_list_with_nuls ')' ';' - { PCallTask*tmp = pform_make_call_task(@1, *$1, *$3); + | hierarchy_identifier argument_list_parens_opt ';' + { PCallTask*tmp = pform_make_call_task(@1, *$1, *$2); delete $1; - delete $3; + delete $2; $$ = tmp; } @@ -6675,24 +6641,11 @@ statement_item /* This is roughly statement_item in the LRM */ $$ = tmp; } - | implicit_class_handle '.' hierarchy_identifier '(' expression_list_with_nuls ')' ';' - { pform_name_t*t_name = $1; - while (! $3->empty()) { - t_name->push_back($3->front()); - $3->pop_front(); - } - PCallTask*tmp = new PCallTask(*t_name, *$5); + | class_hierarchy_identifier argument_list_parens_opt ';' + { PCallTask*tmp = new PCallTask(*$1, *$2); FILE_NAME(tmp, @1); delete $1; - delete $3; - delete $5; - $$ = tmp; - } - - | hierarchy_identifier ';' - { std::listpt; - PCallTask*tmp = pform_make_call_task(@1, *$1, pt); - delete $1; + delete $2; $$ = tmp; } @@ -6703,8 +6656,8 @@ statement_item /* This is roughly statement_item in the LRM */ beginning of a constructor, but let the elaborator figure that out. */ - | implicit_class_handle '.' K_new '(' expression_list_with_nuls ')' ';' - { PChainConstructor*tmp = new PChainConstructor(*$5); + | implicit_class_handle '.' K_new argument_list_parens_opt ';' + { PChainConstructor*tmp = new PChainConstructor(*$4); FILE_NAME(tmp, @3); if (peek_head_name(*$1) == THIS_TOKEN) { yyerror(@1, "error: this.new is invalid syntax. Did you mean super.new?"); @@ -6817,6 +6770,13 @@ tf_port_list_opt | { $$ = 0; } ; + /* A task or function prototype can be declared with the task/function name + * followed by a port list in parenthesis or or just the task/function name by + * itself. When a port list is used it might be empty. */ +tf_port_list_parens_opt + : '(' tf_port_list_opt ')' { $$ = $2; } + | { $$ = 0; } + /* Note that the lexor notices the "table" keyword and starts the UDPTABLE state. It needs to happen there so that all the characters in the table are interpreted in that mode. It is still