Merge pull request #663 from larsclausen/class-constructor

Small class syntax improvements
This commit is contained in:
Stephen Williams 2022-04-10 14:56:51 -07:00 committed by GitHub
commit 070b8af63c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 164 additions and 103 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -476,11 +476,16 @@ sv_class21 normal,-g2009 ivltests
sv_class22 normal,-g2009 ivltests sv_class22 normal,-g2009 ivltests
sv_class23 normal,-g2009 ivltests sv_class23 normal,-g2009 ivltests
sv_class24 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_empty_item normal,-g2009 ivltests
sv_class_extends_scoped normal,-g2009 ivltests sv_class_extends_scoped normal,-g2009 ivltests
sv_class_localparam normal,-g2009 ivltests sv_class_localparam normal,-g2009 ivltests
sv_class_new_init normal,-g2009 ivltests sv_class_new_init normal,-g2009 ivltests
sv_class_in_module_decl 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_darray1 normal,-g2009 ivltests
sv_darray2 normal,-g2009 ivltests sv_darray2 normal,-g2009 ivltests
sv_darray3 normal,-g2009 ivltests sv_darray3 normal,-g2009 ivltests

View File

@ -374,11 +374,15 @@ sv_class21 CE,-g2009 ivltests
sv_class22 CE,-g2009 ivltests sv_class22 CE,-g2009 ivltests
sv_class23 CE,-g2009 ivltests sv_class23 CE,-g2009 ivltests
sv_class24 CE,-g2009 ivltests sv_class24 CE,-g2009 ivltests
sv_class_constructor1 CE,-g2009 ivltests
sv_class_empty_item CE,-g2009 ivltests sv_class_empty_item CE,-g2009 ivltests
sv_class_extends_scoped CE,-g2009 ivltests sv_class_extends_scoped CE,-g2009 ivltests
sv_class_localparam CE,-g2009 ivltests sv_class_localparam CE,-g2009 ivltests
sv_class_new_init CE,-g2009 ivltests sv_class_new_init CE,-g2009 ivltests
sv_class_in_module_decl 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_end_label CE,-g2009 ivltests # Also generate
sv_foreach2 CE,-g2009,-pallowsigned=1 ivltests sv_foreach2 CE,-g2009,-pallowsigned=1 ivltests
sv_foreach3 CE,-g2009 ivltests sv_foreach3 CE,-g2009 ivltests

166
parse.y
View File

@ -621,7 +621,8 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector<Statem
%type <data_type> enum_data_type enum_base_type %type <data_type> enum_data_type enum_base_type
%type <tf_ports> tf_item_declaration tf_item_list tf_item_list_opt %type <tf_ports> tf_item_declaration tf_item_list tf_item_list_opt
%type <tf_ports> tf_port_declaration tf_port_item tf_port_item_list tf_port_list tf_port_list_opt %type <tf_ports> tf_port_declaration tf_port_item tf_port_item_list
%type <tf_ports> tf_port_list tf_port_list_opt tf_port_list_parens_opt
%type <named_pexpr> modport_simple_port port_name parameter_value_byname %type <named_pexpr> modport_simple_port port_name parameter_value_byname
%type <named_pexprs> port_name_list parameter_value_byname_list %type <named_pexprs> port_name_list parameter_value_byname_list
@ -638,7 +639,7 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector<Statem
%type <let_port_lst> let_port_list_opt let_port_list %type <let_port_lst> let_port_list_opt let_port_list
%type <let_port_itm> let_port_item %type <let_port_itm> let_port_item
%type <pform_name> hierarchy_identifier implicit_class_handle %type <pform_name> hierarchy_identifier implicit_class_handle class_hierarchy_identifier
%type <expr> assignment_pattern expression expr_mintypmax %type <expr> assignment_pattern expression expr_mintypmax
%type <expr> expr_primary_or_typename expr_primary %type <expr> expr_primary_or_typename expr_primary
%type <expr> class_new dynamic_array_new let_default_opt %type <expr> class_new dynamic_array_new let_default_opt
@ -648,6 +649,7 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector<Statem
%type <expr> delay_value delay_value_simple %type <expr> delay_value delay_value_simple
%type <exprs> delay1 delay3 delay3_opt delay_value_list %type <exprs> delay1 delay3 delay3_opt delay_value_list
%type <exprs> expression_list_with_nuls expression_list_proper %type <exprs> expression_list_with_nuls expression_list_proper
%type <exprs> argument_list_parens_opt
%type <exprs> cont_assign cont_assign_list %type <exprs> cont_assign cont_assign_list
%type <decl_assignment> variable_decl_assignment %type <decl_assignment> variable_decl_assignment
@ -861,13 +863,9 @@ class_declaration_endlabel_opt
a data_type. */ a data_type. */
class_declaration_extends_opt /* IEEE1800-2005: A.1.2 */ 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; { $$.type = $2;
$$.exprs = 0; $$.exprs = $3;
}
| K_extends ps_type_identifier '(' expression_list_with_nuls ')'
{ $$.type = $2;
$$.exprs = $4;
} }
| |
{ $$.type = 0; $$.exprs = 0; } { $$.type = 0; $$.exprs = 0; }
@ -893,14 +891,14 @@ class_item /* IEEE1800-2005: A.1.8 */
{ assert(current_function==0); { assert(current_function==0);
current_function = pform_push_constructor_scope(@3); current_function = pform_push_constructor_scope(@3);
} }
'(' tf_port_list_opt ')' ';' tf_port_list_parens_opt ';'
tf_item_list_opt block_item_decls_opt
statement_or_null_list_opt statement_or_null_list_opt
K_endfunction endnew_opt K_endfunction endnew_opt
{ current_function->set_ports($6); { current_function->set_ports($5);
pform_set_constructor_return(current_function); pform_set_constructor_return(current_function);
pform_set_this_class(@3, current_function); pform_set_this_class(@3, current_function);
current_function_set_statement(@3, $10); current_function_set_statement(@3, $8);
pform_pop_scope(); pform_pop_scope();
current_function = 0; current_function = 0;
} }
@ -928,25 +926,14 @@ class_item /* IEEE1800-2005: A.1.8 */
/* External class method definitions... */ /* External class method definitions... */
| K_extern method_qualifier_opt K_function K_new ';' | 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 K_new '(' tf_port_list_opt ')' ';'
{ yyerror(@1, "sorry: External constructors are not yet supported."); } { yyerror(@1, "sorry: External constructors are not yet supported."); }
| K_extern method_qualifier_opt K_function data_type_or_implicit_or_void | 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."); { yyerror(@1, "sorry: External methods are not yet supported.");
delete[] $5; delete[] $5;
} }
| K_extern method_qualifier_opt K_function data_type_or_implicit_or_void | K_extern method_qualifier_opt K_task IDENTIFIER tf_port_list_parens_opt ';'
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 ')' ';'
{ yyerror(@1, "sorry: External methods are not yet supported."); { yyerror(@1, "sorry: External methods are not yet supported.");
delete[] $4; delete[] $4;
} }
@ -1002,12 +989,12 @@ class_item_qualifier_opt
; ;
class_new /* IEEE1800-2005 A.2.4 */ class_new /* IEEE1800-2005 A.2.4 */
: K_new '(' expression_list_with_nuls ')' : K_new argument_list_parens_opt
{ std::list<PExpr*>*expr_list = $3; { std::list<PExpr*>*expr_list = $2;
strip_tail_items(expr_list); strip_tail_items(expr_list);
PENewClass*tmp = new PENewClass(*expr_list); PENewClass*tmp = new PENewClass(*expr_list);
FILE_NAME(tmp, @1); FILE_NAME(tmp, @1);
delete $3; delete $2;
$$ = tmp; $$ = tmp;
} }
| K_new hierarchy_identifier | K_new hierarchy_identifier
@ -1018,11 +1005,6 @@ class_new /* IEEE1800-2005 A.2.4 */
delete $2; delete $2;
$$ = tmp; $$ = tmp;
} }
| K_new
{ PENewClass*tmp = new PENewClass;
FILE_NAME(tmp, @1);
$$ = tmp;
}
; ;
/* The concurrent_assertion_item pulls together the /* The concurrent_assertion_item pulls together the
@ -1554,6 +1536,15 @@ implicit_class_handle /* IEEE1800-2005: A.8.4 */
| K_super { $$ = pform_create_super(); } | 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 /* SystemVerilog adds support for the increment/decrement
expressions, which look like a++, --a, etc. These are primaries expressions, which look like a++, --a, etc. These are primaries
but are in their own rules because they can also be but are in their own rules because they can also be
@ -1937,10 +1928,8 @@ modport_simple_port
; ;
modport_tf_port modport_tf_port
: K_task IDENTIFIER : K_task IDENTIFIER tf_port_list_parens_opt
| K_task IDENTIFIER '(' tf_port_list_opt ')' | K_function data_type_or_implicit_or_void IDENTIFIER tf_port_list_parens_opt
| K_function data_type_or_implicit_or_void IDENTIFIER
| K_function data_type_or_implicit_or_void IDENTIFIER '(' tf_port_list_opt ')'
; ;
non_integer_type /* IEEE1800-2005: A.2.2.1 */ 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<PExpr*>; }
expression_list_proper expression_list_proper
: expression_list_proper ',' expression : expression_list_proper ',' expression
{ std::list<PExpr*>*tmp = $1; { std::list<PExpr*>*tmp = $1;
@ -3772,17 +3768,11 @@ expr_primary
delete $2; delete $2;
$$ = tmp; $$ = tmp;
} }
| implicit_class_handle '.' hierarchy_identifier '(' expression_list_with_nuls ')' | class_hierarchy_identifier '(' expression_list_with_nuls ')'
{ pform_name_t*t_name = $1; { list<PExpr*>*expr_list = $3;
while (! $3->empty()) {
t_name->push_back($3->front());
$3->pop_front();
}
list<PExpr*>*expr_list = $5;
strip_tail_items(expr_list); 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 $1;
delete $3;
$$ = tmp; $$ = tmp;
} }
| SYSTEM_IDENTIFIER '(' expression_list_proper ')' | SYSTEM_IDENTIFIER '(' expression_list_proper ')'
@ -3816,16 +3806,10 @@ expr_primary
$$ = tmp; $$ = tmp;
} }
| implicit_class_handle '.' hierarchy_identifier | class_hierarchy_identifier
{ pform_name_t*t_name = $1; { PEIdent*tmp = new PEIdent(*$1);
while (! $3->empty()) { FILE_NAME(tmp, @1);
t_name->push_back($3->front());
$3->pop_front();
}
PEIdent*tmp = new PEIdent(*t_name);
FILE_NAME(tmp,@1);
delete $1; delete $1;
delete $3;
$$ = tmp; $$ = tmp;
} }
@ -4623,17 +4607,11 @@ lpvalue
delete $1; delete $1;
} }
| implicit_class_handle '.' hierarchy_identifier | class_hierarchy_identifier
{ pform_name_t*t_name = $1; { PEIdent*tmp = new PEIdent(*$1);
while (!$3->empty()) {
t_name->push_back($3->front());
$3->pop_front();
}
PEIdent*tmp = new PEIdent(*t_name);
FILE_NAME(tmp, @1); FILE_NAME(tmp, @1);
$$ = tmp; $$ = tmp;
delete $1; delete $1;
delete $3;
} }
| '{' expression_list_proper '}' | '{' expression_list_proper '}'
@ -5193,15 +5171,10 @@ module_item
{ pform_endgenerate(true); } { pform_endgenerate(true); }
/* Elaboration system tasks. */ /* Elaboration system tasks. */
| SYSTEM_IDENTIFIER '(' expression_list_with_nuls ')' ';' | SYSTEM_IDENTIFIER argument_list_parens_opt ';'
{ pform_make_elab_task(@1, lex_strings.make($1), *$3); { pform_make_elab_task(@1, lex_strings.make($1), *$2);
delete[]$1;
delete $3;
}
| SYSTEM_IDENTIFIER ';'
{ std::list<PExpr*>pt;
pform_make_elab_task(@1, lex_strings.make($1), pt);
delete[]$1; delete[]$1;
delete $2;
} }
| modport_declaration | modport_declaration
@ -6638,25 +6611,18 @@ statement_item /* This is roughly statement_item in the LRM */
FILE_NAME(tmp,@1); FILE_NAME(tmp,@1);
$$ = tmp; $$ = tmp;
} }
| SYSTEM_IDENTIFIER '(' expression_list_with_nuls ')' ';' | SYSTEM_IDENTIFIER argument_list_parens_opt ';'
{ PCallTask*tmp = new PCallTask(lex_strings.make($1), *$3); { PCallTask*tmp = new PCallTask(lex_strings.make($1), *$2);
FILE_NAME(tmp,@1);
delete[]$1;
delete $3;
$$ = tmp;
}
| SYSTEM_IDENTIFIER ';'
{ std::list<PExpr*>pt;
PCallTask*tmp = new PCallTask(lex_strings.make($1), pt);
FILE_NAME(tmp,@1); FILE_NAME(tmp,@1);
delete[]$1; delete[]$1;
delete $2;
$$ = tmp; $$ = tmp;
} }
| hierarchy_identifier '(' expression_list_with_nuls ')' ';' | hierarchy_identifier argument_list_parens_opt ';'
{ PCallTask*tmp = pform_make_call_task(@1, *$1, *$3); { PCallTask*tmp = pform_make_call_task(@1, *$1, *$2);
delete $1; delete $1;
delete $3; delete $2;
$$ = tmp; $$ = tmp;
} }
@ -6675,24 +6641,11 @@ statement_item /* This is roughly statement_item in the LRM */
$$ = tmp; $$ = tmp;
} }
| implicit_class_handle '.' hierarchy_identifier '(' expression_list_with_nuls ')' ';' | class_hierarchy_identifier argument_list_parens_opt ';'
{ pform_name_t*t_name = $1; { PCallTask*tmp = new PCallTask(*$1, *$2);
while (! $3->empty()) {
t_name->push_back($3->front());
$3->pop_front();
}
PCallTask*tmp = new PCallTask(*t_name, *$5);
FILE_NAME(tmp, @1); FILE_NAME(tmp, @1);
delete $1; delete $1;
delete $3; delete $2;
delete $5;
$$ = tmp;
}
| hierarchy_identifier ';'
{ std::list<PExpr*>pt;
PCallTask*tmp = pform_make_call_task(@1, *$1, pt);
delete $1;
$$ = tmp; $$ = 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 beginning of a constructor, but let the elaborator figure that
out. */ out. */
| implicit_class_handle '.' K_new '(' expression_list_with_nuls ')' ';' | implicit_class_handle '.' K_new argument_list_parens_opt ';'
{ PChainConstructor*tmp = new PChainConstructor(*$5); { PChainConstructor*tmp = new PChainConstructor(*$4);
FILE_NAME(tmp, @3); FILE_NAME(tmp, @3);
if (peek_head_name(*$1) == THIS_TOKEN) { if (peek_head_name(*$1) == THIS_TOKEN) {
yyerror(@1, "error: this.new is invalid syntax. Did you mean super.new?"); yyerror(@1, "error: this.new is invalid syntax. Did you mean super.new?");
@ -6817,6 +6770,13 @@ tf_port_list_opt
| { $$ = 0; } | { $$ = 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 /* Note that the lexor notices the "table" keyword and starts
the UDPTABLE state. It needs to happen there so that all the the UDPTABLE state. It needs to happen there so that all the
characters in the table are interpreted in that mode. It is still characters in the table are interpreted in that mode. It is still