Merge pull request #802 from larsclausen/forward-typedef

Add support for forward type declarations
This commit is contained in:
Stephen Williams 2022-12-11 13:16:17 -08:00 committed by GitHub
commit 1434936aaa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 664 additions and 164 deletions

View File

@ -51,8 +51,8 @@ PScope::PScope(perm_string n, LexicalScope*parent)
PScope::~PScope()
{
for(map<perm_string, data_type_t*>::iterator it = typedefs.begin();
it != typedefs.end(); ++it)
for(typedef_map_t::iterator it = typedefs.begin(); it != typedefs.end();
++it)
delete it->second;
}

View File

@ -120,7 +120,8 @@ class LexicalScope {
bool has_parameter_port_list;
// Defined types in the scope.
std::map<perm_string,data_type_t*>typedefs;
typedef std::map<perm_string,typedef_t*> typedef_map_t;
typedef_map_t typedefs;
// Named events in the scope.
std::map<perm_string,PEvent*>events;

View File

@ -169,34 +169,11 @@ static void collect_scope_specparams(Design*des, NetScope*scope,
static void elaborate_scope_enumeration(Design*des, NetScope*scope,
enum_type_t*enum_type)
{
ivl_type_t base_type;
bool rc_flag;
base_type = enum_type->base_type->elaborate_type(des, scope);
enum_type->elaborate_type(des, scope);
const struct netvector_t *vec_type = dynamic_cast<const netvector_t*>(base_type);
if (!vec_type && !dynamic_cast<const netparray_t*>(base_type)) {
cerr << enum_type->get_fileline() << ": error: "
<< "Invalid enum base type `" << *base_type << "`."
<< endl;
des->errors++;
} else if (base_type->slice_dimensions().size() > 1) {
cerr << enum_type->get_fileline() << ": error: "
<< "Enum type must not have more than 1 packed dimension."
<< endl;
des->errors++;
}
bool integer_flag = false;
if (vec_type)
integer_flag = vec_type->get_isint();
netenum_t*use_enum = new netenum_t(base_type, enum_type->names->size(),
integer_flag);
use_enum->set_line(*enum_type);
scope->add_enumeration_set(enum_type, use_enum);
netenum_t *use_enum = scope->enumeration_for_key(enum_type);
size_t name_idx = 0;
// Find the enumeration width.

View File

@ -43,14 +43,26 @@ ivl_type_t data_type_t::elaborate_type(Design*des, NetScope*scope)
{
scope = find_scope(des, scope);
ivl_assert(*this, scope);
Definitions*use_definitions = scope;
map<Definitions*,ivl_type_t>::iterator pos = cache_type_elaborate_.lower_bound(use_definitions);
if (pos != cache_type_elaborate_.end() && pos->first == use_definitions)
return pos->second;
ivl_type_t tmp = elaborate_type_raw(des, scope);
ivl_type_t tmp;
if (elaborating) {
des->errors++;
cerr << get_fileline() << ": error: "
<< "Circular type definition found involving `" << *this << "`."
<< endl;
// Try to recover
tmp = netvector_t::integer_type();
} else {
elaborating = true;
tmp = elaborate_type_raw(des, scope);
elaborating = false;
}
cache_type_elaborate_.insert(pos, pair<NetScope*,ivl_type_t>(scope, tmp));
return tmp;
}
@ -124,13 +136,34 @@ ivl_type_t class_type_t::elaborate_type_raw(Design*des, NetScope*scope) const
* available at the right time. At that time, the netenum_t* object is
* stashed in the scope so that I can retrieve it here.
*/
ivl_type_t enum_type_t::elaborate_type_raw(Design*, NetScope*scope) const
ivl_type_t enum_type_t::elaborate_type_raw(Design *des, NetScope *scope) const
{
ivl_assert(*this, scope);
ivl_type_t tmp = scope->enumeration_for_key(this);
if (tmp == 0 && scope->unit())
tmp = scope->unit()->enumeration_for_key(this);
return tmp;
ivl_type_t base = base_type->elaborate_type(des, scope);
const struct netvector_t *vec_type = dynamic_cast<const netvector_t*>(base);
if (!vec_type && !dynamic_cast<const netparray_t*>(base)) {
cerr << get_fileline() << ": error: "
<< "Invalid enum base type `" << *base << "`."
<< endl;
des->errors++;
} else if (base->slice_dimensions().size() > 1) {
cerr << get_fileline() << ": error: "
<< "Enum type must not have more than 1 packed dimension."
<< endl;
des->errors++;
}
bool integer_flag = false;
if (vec_type)
integer_flag = vec_type->get_isint();
netenum_t *type = new netenum_t(base, names->size(), integer_flag);
type->set_line(*this);
scope->add_enumeration_set(this, type);
return type;
}
ivl_type_t vector_type_t::elaborate_type_raw(Design*des, NetScope*scope) const
@ -172,13 +205,8 @@ ivl_type_t parray_type_t::elaborate_type_raw(Design*des, NetScope*scope) const
ivl_type_t etype = base_type->elaborate_type(des, scope);
if (!etype->packed()) {
cerr << this->get_fileline() << " error: Packed array ";
if (!name.nil())
cerr << "`" << name << "` ";
cerr << "base-type `";
if (base_type->name.nil())
cerr << *base_type;
else
cerr << base_type->name;
cerr << *base_type;
cerr << "` is not packed." << endl;
des->errors++;
}
@ -385,8 +413,66 @@ NetScope *typeref_t::find_scope(Design *des, NetScope *s) const
if (scope)
s = des->find_package(scope->pscope_name());
if (!type->name.nil())
s = s->find_typedef_scope(des, type);
return s;
}
ivl_type_t typedef_t::elaborate_type(Design *des, NetScope *scope)
{
if (!data_type.get()) {
cerr << get_fileline() << ": error: Undefined type `" << name << "`."
<< endl;
des->errors++;
// Try to recover
return netvector_t::integer_type();
}
// Search upwards from where the type was referenced
scope = scope->find_typedef_scope(des, this);
if (!scope) {
cerr << get_fileline() << ": sorry: "
<< "Can not find the scope type defintion `" << name << "`."
<< endl;
des->errors++;
// Try to recover
return netvector_t::integer_type();
}
ivl_type_t elab_type = data_type->elaborate_type(des, scope);
if (!elab_type)
return netvector_t::integer_type();
bool type_ok = true;
switch (basic_type) {
case ENUM:
type_ok = dynamic_cast<const netenum_t *>(elab_type);
break;
case STRUCT: {
const netstruct_t *struct_type = dynamic_cast<const netstruct_t *>(elab_type);
type_ok = struct_type && !struct_type->union_flag();
break;
}
case UNION: {
const netstruct_t *struct_type = dynamic_cast<const netstruct_t *>(elab_type);
type_ok = struct_type && struct_type->union_flag();
break;
}
case CLASS:
type_ok = dynamic_cast<const netclass_t *>(elab_type);
break;
default:
break;
}
if (!type_ok) {
cerr << data_type->get_fileline() << " error: "
<< "Unexpected type `" << *elab_type << "` for `" << name
<< "`. It was forward declared as `" << basic_type
<< "` at " << get_fileline() << "."
<< endl;
des->errors++;
}
return elab_type;
}

View File

@ -0,0 +1,14 @@
// Check that circular type definitions are detected and an error is reported.
module test;
typedef T1;
typedef T1 T2;
typedef T2 T1;
T2 x;
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,18 @@
// Check that longer chains of circular type definitions are detected as an
// error.
module test;
typedef T1;
typedef struct packed {
T1 x;
} T2;
typedef T2 [1:0] T3;
typedef T3 T1;
T1 x;
endmodule

View File

@ -0,0 +1,47 @@
// Check that forward typedefs of basic types are supported
`define check(val, exp) \
if (val != exp) begin \
$display("FAILED(%0d). '%s' expected ", `__LINE__, `"val`", exp, " got ", val, ); \
failed = 1'b1; \
end
bit failed = 1'b0;
module test;
typedef T1;
typedef T1; // Check forward typedef twice for the same type
typedef T2;
typedef T3;
typedef T4;
T1 x = -1;
T2 y = 1.23;
T3 z = "Hello";
T4 w;
typedef integer T1;
// There can be as many forward typedefs as we like, even after the type
// itself has already been declared.
typedef T1;
typedef T1;
typedef real T2;
typedef string T3;
typedef logic [1:0] T4[3:0];
initial begin
`check($bits(x), $bits(integer))
`check($bits(T1), $bits(integer))
`check(x, -1)
`check(y, 1.23)
`check(z, "Hello")
`check($unpacked_dimensions(w), 1)
`check($size(w), 4)
if (!failed) begin
$display("PASSED");
end
end
endmodule

View File

@ -0,0 +1,46 @@
// Check that forward typedefs of classes are supported
module test;
`define check(val, exp) \
if (val !== exp) begin \
$display("FAILED(%0d). '%s' expected %d, got %d", `__LINE__, `"val`", exp, val); \
failed = 1'b1; \
end
bit failed = 1'b0;
typedef class C;
typedef C;
C x;
class C;
int x;
endclass
C y;
// There can be as many forward typedefs as we like, even after the type
// itself has already been declared.
typedef C;
typedef class C;
C z;
initial begin
// Check they are all the same type and can be assigned to each other
x = y;
y = z;
z = x;
`check($bits(x.x), $bits(int));
`check($bits(y.x), $bits(int));
`check($bits(z.x), $bits(int));
if (!failed) begin
$display("PASSED");
end
end
endmodule

View File

@ -0,0 +1,44 @@
// Check that forward enum typedefs are supported
module test;
`define check(val, exp) \
if (val !== exp) begin \
$display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, `"val`", exp, val); \
failed = 1'b1; \
end
bit failed = 1'b0;
typedef T;
typedef enum T;
T x;
typedef enum integer {
A, B
} T;
T y;
typedef enum T;
typedef T;
T z;
initial begin
// Check that they are all the same type and can be assigned to each other
x = y;
y = z;
z = x;
`check($bits(x), $bits(integer))
`check($bits(y), $bits(integer))
`check($bits(z), $bits(integer))
if (!failed) begin
$display("PASSED");
end
end
endmodule

View File

@ -0,0 +1,23 @@
// Check that the base type of an enum can be a forward typedef
module test;
typedef T1;
typedef enum T1 {
A, B
} T2;
typedef logic [31:0] T1;
T2 z;
initial begin
if ($bits(z) == 32) begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
endmodule

View File

@ -0,0 +1,26 @@
// Check that a forwarded enum typedef can be referenced in a class
module test;
typedef T;
class C;
T x;
endclass
typedef enum integer {
X, Y
} T;
initial begin
C c;
c = new;
if ($bits(c.x) == 32) begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
endmodule

View File

@ -0,0 +1,14 @@
// Check that a enum can't be its own base type
module test;
typedef T;
typedef enum T {
A, B
} T;
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,39 @@
// Check that forward struct typedefs are supported
module test;
`define check(val, exp) \
if (val !== exp) begin \
$display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, `"val`", exp, val); \
failed = 1'b1; \
end
bit failed = 1'b0;
typedef T;
typedef struct T;
T x;
typedef struct packed {
int x;
} T;
T y;
typedef struct T;
typedef T;
T z;
initial begin
`check($bits(x), $bits(int))
`check($bits(y), $bits(int))
`check($bits(z), $bits(int))
if (!failed) begin
$display("PASSED");
end
end
endmodule

View File

@ -0,0 +1,18 @@
// Check that it is an error to use a forwarded struct type as the type for the
// member in the struct itself.
module test;
typedef T;
typedef struct packed {
T x;
} T;
T x;
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,41 @@
// Check that forward typdes of unions are supported
module test;
`define check(val, exp) \
if (val !== exp) begin \
$display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, `"val`", exp, val); \
failed = 1'b1; \
end
bit failed = 1'b0;
typedef union T;
typedef T;
T x;
typedef union packed {
int x;
logic [3:0][7:0] y;
} T;
T y;
// There can be as many forward typedefs as we like, even after the type
// itself has already been declared.
typedef T;
typedef union T;
T z;
initial begin
`check($bits(x), $bits(int));
`check($bits(y), $bits(int));
`check($bits(z), $bits(int));
if (!failed) begin
$display("PASSED");
end
end
endmodule

View File

@ -0,0 +1,18 @@
// Check that it is an error to use a forwarded union type as the type for the
// members in the union itself.
module test;
typedef T;
typedef union packed {
T x;
} T;
T x;
initial begin
$display("FAILED");
end
endmodule

View File

@ -716,10 +716,22 @@ sv_typedef_array_base2 normal,-g2009 ivltests
sv_typedef_array_base3 normal,-g2009 ivltests
sv_typedef_array_base4 normal,-g2009 ivltests
sv_typedef_chained normal,-g2009 ivltests
sv_typedef_circular1 CE,-g2009 ivltests
sv_typedef_circular2 CE,-g2009 ivltests
sv_typedef_darray_base1 normal,-g2009 ivltests
sv_typedef_darray_base2 normal,-g2009 ivltests
sv_typedef_darray_base3 normal,-g2009 ivltests
sv_typedef_darray_base4 normal,-g2009 ivltests
sv_typedef_fwd_base normal,-g2009 ivltests
sv_typedef_fwd_class normal,-g2009 ivltests
sv_typedef_fwd_union normal,-g2009 ivltests
sv_typedef_fwd_union_fail CE,-g2009 ivltests
sv_typedef_fwd_enum1 normal,-g2009 ivltests
sv_typedef_fwd_enum2 normal,-g2009 ivltests
sv_typedef_fwd_enum3 normal,-g2009 ivltests
sv_typedef_fwd_enum_fail CE,-g2009 ivltests
sv_typedef_fwd_struct normal,-g2009 ivltests
sv_typedef_fwd_struct_fail CE,-g2009 ivltests
sv_typedef_nested_array normal,-g2009 ivltests
sv_typedef_queue_base1 normal,-g2009 ivltests
sv_typedef_queue_base2 normal,-g2009 ivltests

View File

@ -302,6 +302,7 @@ sv_string5 CE,-g2009 ivltests
sv_string6 CE,-g2009,-pallowsigned=1 ivltests
sv_string7 CE,-g2009,-pallowsigned=1 ivltests
sv_string7b CE,-g2009,-pallowsigned=1 ivltests
sv_typedef_fwd_base CE,-g2009 ivltests
vhdl_string_lim CE,-g2005-sv,-pallowsigned=1,ivltests/vhdl_string_lim.vhd ivltests
vhdl_textio_write CE,-g2005-sv,-pallowsigned=1,ivltests/vhdl_textio_write.vhd ivltests
vhdl_textio_read CE,-g2005-sv,-pallowsigned=1,ivltests/vhdl_textio_read.vhd ivltests
@ -440,6 +441,8 @@ sv_port_default8 CE,-g2009,-pallowsigned=1 ivltests
sv_port_default9 CE,-g2009 ivltests
sv_ps_type_class1 CE,-g2009 ivltests
sv_root_class CE,-g2009 ivltests
sv_typedef_fwd_class CE,-g2009 ivltests
sv_typedef_fwd_enum3 CE,-g2009 ivltests
sv_typedef_scope3 CE,-g2009 ivltests
sv_unit2b CE,-g2009 ivltests
sv_unit3b CE,-g2009 ivltests

View File

@ -369,7 +369,7 @@ TU [munpf]
identifier here and interpret it in the package scope. */
if (in_package_scope) {
if (rc == IDENTIFIER) {
if (data_type_t*type = pform_test_type_identifier(in_package_scope, yylval.text)) {
if (typedef_t*type = pform_test_type_identifier(in_package_scope, yylval.text)) {
yylval.type_identifier.text = yylval.text;
yylval.type_identifier.type = type;
rc = TYPE_IDENTIFIER;
@ -405,7 +405,7 @@ TU [munpf]
/* If this identifier names a previously declared type, then
return this as a TYPE_IDENTIFIER instead. */
if (rc == IDENTIFIER && gn_system_verilog()) {
if (data_type_t*type = pform_test_type_identifier(yylloc, yylval.text)) {
if (typedef_t*type = pform_test_type_identifier(yylloc, yylval.text)) {
yylval.type_identifier.text = yylval.text;
yylval.type_identifier.type = type;
rc = TYPE_IDENTIFIER;
@ -426,7 +426,7 @@ TU [munpf]
}
}
if (gn_system_verilog()) {
if (data_type_t*type = pform_test_type_identifier(yylloc, yylval.text)) {
if (typedef_t*type = pform_test_type_identifier(yylloc, yylval.text)) {
yylval.type_identifier.text = yylval.text;
yylval.type_identifier.type = type;
return TYPE_IDENTIFIER;

View File

@ -232,19 +232,20 @@ NetScope*NetScope::find_import(const Design*des, perm_string name)
return 0;
}
void NetScope::add_typedefs(const map<perm_string,data_type_t*>*typedefs)
void NetScope::add_typedefs(const map<perm_string,typedef_t*>*typedefs)
{
if (!typedefs->empty())
typedefs_ = *typedefs;
}
NetScope*NetScope::find_typedef_scope(const Design*des, data_type_t*type)
NetScope*NetScope::find_typedef_scope(const Design*des, const typedef_t*type)
{
assert(type);
NetScope *cur_scope = this;
while (cur_scope) {
if (cur_scope->typedefs_.find(type->name) != cur_scope->typedefs_.end())
auto it = cur_scope->typedefs_.find(type->name);
if (it != cur_scope->typedefs_.end() && it->second == type)
return cur_scope;
NetScope*import_scope = cur_scope->find_import(des, type->name);
if (import_scope)

View File

@ -940,10 +940,10 @@ class NetScope : public Definitions, public Attrib {
void add_imports(const std::map<perm_string,PPackage*>*imports);
NetScope*find_import(const Design*des, perm_string name);
void add_typedefs(const std::map<perm_string,data_type_t*>*typedefs);
void add_typedefs(const std::map<perm_string,typedef_t*>*typedefs);
/* Search the scope hierarchy for the scope where 'type' was defined. */
NetScope*find_typedef_scope(const Design*des, data_type_t*type);
NetScope*find_typedef_scope(const Design*des, const typedef_t*type);
/* Parameters exist within a scope, and these methods allow
one to manipulate the set. In these cases, the name is the
@ -1268,7 +1268,7 @@ class NetScope : public Definitions, public Attrib {
const std::map<perm_string,PPackage*>*imports_;
std::map<perm_string,data_type_t*>typedefs_;
std::map<perm_string,typedef_t*>typedefs_;
NetEvent *events_;

113
parse.y
View File

@ -438,7 +438,7 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector<Statem
struct {
char*text;
data_type_t*type;
typedef_t*type;
} type_identifier;
struct {
@ -464,6 +464,8 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector<Statem
std::list<index_component_t> *dimensions;
LexicalScope::lifetime_t lifetime;
enum typedef_t::basic_type typedef_basic_type;
};
%token <text> IDENTIFIER SYSTEM_IDENTIFIER STRING TIME_LITERAL
@ -589,6 +591,7 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector<Statem
%type <text> event_variable label_opt class_declaration_endlabel_opt
%type <text> block_identifier_opt
%type <text> identifier_name
%type <perm_strings> event_variable_list
%type <perm_strings> list_of_identifiers loop_variables
%type <port_list> list_of_port_identifiers list_of_variable_port_identifiers
@ -646,7 +649,6 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector<Statem
%type <data_type> packed_array_data_type
%type <data_type> ps_type_identifier
%type <data_type> simple_packed_type
%type <class_type> class_identifier
%type <struct_member> struct_union_member
%type <struct_members> struct_union_member_list
%type <struct_type> struct_data_type
@ -706,6 +708,8 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector<Statem
%type <letter> compressed_operator
%type <typedef_basic_type> typedef_basic_type
%token K_TAND
%nonassoc K_PLUS_EQ K_MINUS_EQ K_MUL_EQ K_DIV_EQ K_MOD_EQ K_AND_EQ K_OR_EQ
%nonassoc K_XOR_EQ K_LS_EQ K_RS_EQ K_RSS_EQ K_NB_TRIGGER
@ -786,15 +790,22 @@ block_identifier_opt /* */
;
class_declaration /* IEEE1800-2005: A.1.2 */
: K_virtual_opt K_class lifetime_opt class_identifier class_declaration_extends_opt ';'
{ pform_start_class_declaration(@2, $4, $5.type, $5.exprs, $3); }
: K_virtual_opt K_class lifetime_opt identifier_name class_declaration_extends_opt ';'
{
perm_string name = lex_strings.make($4);
class_type_t *class_type= new class_type_t(name);
FILE_NAME(class_type, @4);
pform_set_typedef(@4, name, class_type, nullptr);
pform_start_class_declaration(@2, class_type, $5.type, $5.exprs, $3);
}
class_items_opt K_endclass
{ // Process a class.
pform_end_class_declaration(@9);
}
class_declaration_endlabel_opt
{ // Wrap up the class.
check_end_label(@11, "class", $4->name, $11);
check_end_label(@11, "class", $4, $11);
delete[] $4;
}
;
@ -803,33 +814,18 @@ class_constraint /* IEEE1800-2005: A.1.8 */
| constraint_declaration
;
class_identifier
: IDENTIFIER
{ // Create a synthetic typedef for the class name so that the
// lexor detects the name as a type.
perm_string name = lex_strings.make($1);
class_type_t*tmp = new class_type_t(name);
FILE_NAME(tmp, @1);
pform_set_typedef(name, tmp, NULL);
delete[]$1;
$$ = tmp;
}
| TYPE_IDENTIFIER
{ class_type_t*tmp = dynamic_cast<class_type_t*>($1.type);
if (tmp == 0) {
yyerror(@1, "Type name \"%s\"is not a predeclared class name.", $1.text);
}
delete[]$1.text;
$$ = tmp;
}
// This is used in places where a new type can be declared or an existig type
// is referenced. E.g. typedefs.
identifier_name
: IDENTIFIER { $$ = $1; }
| TYPE_IDENTIFIER { $$ = $1.text; }
;
/* The endlabel after a class declaration is a little tricky because
the class name is detected by the lexor as a TYPE_IDENTIFIER if it
does indeed match a name. */
class_declaration_endlabel_opt
: ':' TYPE_IDENTIFIER { $$ = $2.text; }
| ':' IDENTIFIER { $$ = $2; }
: ':' identifier_name { $$ = $2; }
| { $$ = 0; }
;
@ -2651,56 +2647,43 @@ block_item_decls_opt
| { $$ = false; }
;
/* We need to handle K_enum separately because
* `typedef enum <TYPE_IDENTIFIER>` can either be the start of a enum forward
* declaration or a enum type declaration with a type identifier as its base
* type. And this abmiguity can not be resolved if we reduce the K_enum to
* typedef_basic_type. */
typedef_basic_type
: K_struct { $$ = typedef_t::STRUCT; }
| K_union { $$ = typedef_t::UNION; }
| K_class { $$ = typedef_t::CLASS; }
;
/* Type declarations are parsed here. The rule actions call pform
functions that add the declaration to the current lexical scope. */
type_declaration
: K_typedef data_type IDENTIFIER dimensions_opt ';'
: K_typedef data_type identifier_name dimensions_opt ';'
{ perm_string name = lex_strings.make($3);
pform_set_typedef(name, $2, $4);
pform_set_typedef(@3, name, $2, $4);
delete[]$3;
}
/* If the IDENTIFIER already is a typedef, it is possible for this
code to override the definition, but only if the typedef is
inherited from a different scope. */
| K_typedef data_type TYPE_IDENTIFIER dimensions_opt ';'
{ perm_string name = lex_strings.make($3.text);
if (pform_test_type_identifier_local(name)) {
yyerror(@3, "error: Typedef identifier \"%s\" is already a type name.", $3.text);
delete $4;
} else {
pform_set_typedef(name, $2, $4);
}
delete[]$3.text;
}
/* These are forward declarations... */
| K_typedef K_class IDENTIFIER ';'
{ // Create a synthetic typedef for the class name so that the
// lexor detects the name as a type.
perm_string name = lex_strings.make($3);
class_type_t*tmp = new class_type_t(name);
FILE_NAME(tmp, @3);
pform_set_typedef(name, tmp, NULL);
delete[]$3;
}
| K_typedef K_enum IDENTIFIER ';'
{ yyerror(@1, "sorry: Enum forward declarations not supported yet."); }
| K_typedef K_struct IDENTIFIER ';'
{ yyerror(@1, "sorry: Struct forward declarations not supported yet."); }
| K_typedef K_union IDENTIFIER ';'
{ yyerror(@1, "sorry: Union forward declarations not supported yet."); }
| K_typedef IDENTIFIER ';'
{ // Create a synthetic typedef for the class name so that the
// lexor detects the name as a type.
perm_string name = lex_strings.make($2);
class_type_t*tmp = new class_type_t(name);
FILE_NAME(tmp, @2);
pform_set_typedef(name, tmp, NULL);
| K_typedef identifier_name ';'
{ perm_string name = lex_strings.make($2);
pform_forward_typedef(@2, name, typedef_t::ANY);
delete[]$2;
}
| K_typedef typedef_basic_type identifier_name ';'
{ perm_string name = lex_strings.make($3);
pform_forward_typedef(@3, name, $2);
delete[]$3;
}
| K_typedef K_enum identifier_name ';'
{ perm_string name = lex_strings.make($3);
pform_forward_typedef(@3, name, typedef_t::ENUM);
delete[]$3;
}
| K_typedef error ';'
{ yyerror(@2, "error: Syntax error in typedef clause.");
yyerrok;

View File

@ -89,10 +89,8 @@ extern void lex_in_package_scope(PPackage*pkg);
* parser detects typedefs and marks the typedef'ed identifiers as
* type names.
*/
extern data_type_t* pform_test_type_identifier(const YYLTYPE&loc, const char*txt);
extern data_type_t* pform_test_type_identifier(PPackage*pkg, const char*txt);
extern bool pform_test_type_identifier_local(perm_string txt);
extern typedef_t* pform_test_type_identifier(const YYLTYPE&loc, const char*txt);
extern typedef_t* pform_test_type_identifier(PPackage*pkg, const char*txt);
/*
* Test if this identifier is a package name. The pform needs to help

View File

@ -858,18 +858,49 @@ void pform_put_enum_type_in_scope(enum_type_t*enum_set)
lexical_scope->enum_sets.push_back(enum_set);
}
void pform_set_typedef(perm_string name, data_type_t*data_type, std::list<pform_range_t>*unp_ranges)
static typedef_t *pform_get_typedef(const struct vlltype&loc, perm_string name)
{
typedef_t *&td = lexical_scope->typedefs[name];
if (!td) {
td = new typedef_t(name);
FILE_NAME(td, loc);
add_local_symbol(lexical_scope, name, td);
}
return td;
}
void pform_forward_typedef(const struct vlltype&loc, perm_string name,
enum typedef_t::basic_type basic_type)
{
typedef_t *td = pform_get_typedef(loc, name);
if (!td->set_basic_type(basic_type)) {
cout << loc << " error: Incompatible basic type `" << basic_type
<< "` for `" << name
<< "`. Previously declared in this scope as `"
<< td->get_basic_type() << "` at " << td->get_fileline() << "."
<< endl;
error_count++;
}
}
void pform_set_typedef(const struct vlltype&loc, perm_string name,
data_type_t*data_type,
std::list<pform_range_t>*unp_ranges)
{
typedef_t *td = pform_get_typedef(loc, name);
if(unp_ranges)
data_type = new uarray_type_t(data_type, unp_ranges);
add_local_symbol(lexical_scope, name, data_type);
data_type_t*&ref = lexical_scope->typedefs[name];
ivl_assert(*data_type, ref == 0);
ref = data_type;
ref->name = name;
if (!td->set_data_type(data_type)) {
cerr << loc << " error: Type identifier `" << name
<< "` has already been declared in this scope at "
<< td->get_data_type()->get_fileline() << "."
<< endl;
error_count++;
delete data_type;
}
}
void pform_set_type_referenced(const struct vlltype&loc, const char*name)
@ -878,13 +909,13 @@ void pform_set_type_referenced(const struct vlltype&loc, const char*name)
check_potential_imports(loc, lex_name, false);
}
data_type_t* pform_test_type_identifier(const struct vlltype&loc, const char*txt)
typedef_t* pform_test_type_identifier(const struct vlltype&loc, const char*txt)
{
perm_string name = lex_strings.make(txt);
LexicalScope*cur_scope = lexical_scope;
do {
map<perm_string,data_type_t*>::iterator cur;
LexicalScope::typedef_map_t::iterator cur;
// First look to see if this identifier is imported from
// a package. If it is, see if it is a type in that
@ -924,24 +955,6 @@ data_type_t* pform_test_type_identifier(const struct vlltype&loc, const char*txt
return 0;
}
/*
* The parser uses this function to test if the name is a typedef in
* the current scope. We use this to know if we can override the
* definition because it shadows a containing scope.
*/
bool pform_test_type_identifier_local(perm_string name)
{
LexicalScope*cur_scope = lexical_scope;
map<perm_string,data_type_t*>::iterator cur;
cur = cur_scope->typedefs.find(name);
if (cur != cur_scope->typedefs.end())
return true;
return false;
}
PECallFunction* pform_make_call_function(const struct vlltype&loc,
const pform_name_t&name,
const list<PExpr*>&parms)

View File

@ -303,8 +303,11 @@ extern void pform_make_elab_task(const struct vlltype&li,
perm_string name,
const std::list<PExpr*>&params);
extern void pform_set_typedef(perm_string name, data_type_t*data_type,
std::list<pform_range_t>*unp_ranges);
extern void pform_set_typedef(const struct vlltype&loc, perm_string name,
data_type_t*data_type,
std::list<pform_range_t>*unp_ranges = nullptr);
extern void pform_forward_typedef(const struct vlltype&loc, perm_string name,
enum typedef_t::basic_type basic_type);
extern void pform_set_type_referenced(const struct vlltype&loc, const char*name);

View File

@ -1502,10 +1502,10 @@ void PGenerate::dump(ostream&out, unsigned indent) const
void LexicalScope::dump_typedefs_(ostream&out, unsigned indent) const
{
typedef map<perm_string,data_type_t*>::const_iterator iter_t;
typedef typedef_map_t::const_iterator iter_t;
for (iter_t cur = typedefs.begin() ; cur != typedefs.end() ; ++ cur) {
out << setw(indent) << "" << "typedef of " << cur->first << ":" << endl;
cur->second->pform_dump(out, indent+4);
cur->second->get_data_type()->pform_dump(out, indent+4);
}
}

View File

@ -143,10 +143,12 @@ PExpr* pform_package_ident(const struct vlltype&loc,
return tmp;
}
data_type_t* pform_test_type_identifier(PPackage*pkg, const char*txt)
typedef_t* pform_test_type_identifier(PPackage*pkg, const char*txt)
{
perm_string use_name = lex_strings.make(txt);
map<perm_string,data_type_t*>::const_iterator cur = pkg->typedefs.find(use_name);
LexicalScope::typedef_map_t::const_iterator cur;
cur = pkg->typedefs.find(use_name);
if (cur != pkg->typedefs.end())
return cur->second;

View File

@ -44,3 +44,48 @@ PNamedItem::SymbolType class_type_t::symbol_type() const
{
return CLASS;
}
bool typedef_t::set_data_type(data_type_t *t)
{
if (data_type.get())
return false;
data_type.reset(t);
return true;
}
bool typedef_t::set_basic_type(enum basic_type bt)
{
if (bt == ANY)
return true;
if (basic_type != ANY && bt != basic_type)
return false;
basic_type = bt;
return true;
}
std::ostream& operator<< (std::ostream&out, enum typedef_t::basic_type bt)
{
switch (bt) {
case typedef_t::ANY:
out << "any";
break;
case typedef_t::ENUM:
out << "enum";
break;
case typedef_t::STRUCT:
out << "struct";
break;
case typedef_t::UNION:
out << "union";
break;
case typedef_t::CLASS:
out << "class";
break;
}
return out;
}

View File

@ -162,20 +162,45 @@ class data_type_t : public PNamedItem {
virtual SymbolType symbol_type() const;
virtual NetScope *find_scope(Design* des, NetScope *scope) const;
perm_string name;
private:
// Elaborate the type to an ivl_type_s type.
virtual ivl_type_t elaborate_type_raw(Design*des, NetScope*scope) const;
virtual NetScope *find_scope(Design* des, NetScope *scope) const;
bool elaborating = false;
// Keep per-scope elaboration results cached.
std::map<Definitions*,ivl_type_t> cache_type_elaborate_;
};
struct typedef_t : public PNamedItem {
explicit typedef_t(perm_string n) : basic_type(ANY), name(n) { };
ivl_type_t elaborate_type(Design*des, NetScope*scope);
enum basic_type {
ANY,
ENUM,
STRUCT,
UNION,
CLASS
};
bool set_data_type(data_type_t *t);
const data_type_t *get_data_type() const { return data_type.get(); }
bool set_basic_type(basic_type bt);
enum basic_type get_basic_type() const { return basic_type; }
protected:
enum basic_type basic_type;
std::unique_ptr<data_type_t> data_type;
public:
perm_string name;
};
struct typeref_t : public data_type_t {
explicit typeref_t(data_type_t *t, PScope *s = 0) : scope(s), type(t) {}
explicit typeref_t(typedef_t *t, PScope *s = 0) : scope(s), type(t) {}
ivl_type_t elaborate_type_raw(Design*des, NetScope*scope) const;
NetScope *find_scope(Design* des, NetScope *scope) const;
@ -184,7 +209,7 @@ struct typeref_t : public data_type_t {
private:
PScope *scope;
data_type_t *type;
typedef_t *type;
};
struct void_type_t : public data_type_t {
@ -335,7 +360,7 @@ struct string_type_t : public data_type_t {
struct class_type_t : public data_type_t {
inline explicit class_type_t(perm_string n) { name = n; }
inline explicit class_type_t(perm_string n) : name(n) { }
void pform_dump(std::ostream&out, unsigned indent) const;
void pform_dump_init(std::ostream&out, unsigned indent) const;
@ -370,6 +395,8 @@ struct class_type_t : public data_type_t {
ivl_type_t elaborate_type_raw(Design*, NetScope*) const;
perm_string name;
virtual SymbolType symbol_type() const;
};
@ -432,5 +459,6 @@ static inline std::ostream& operator<< (std::ostream&out, const data_type_t&that
extern std::ostream& operator<< (std::ostream&out, const pform_name_t&);
extern std::ostream& operator<< (std::ostream&out, const name_component_t&that);
extern std::ostream& operator<< (std::ostream&out, const index_component_t&that);
extern std::ostream& operator<< (std::ostream&out, enum typedef_t::basic_type bt);
#endif /* IVL_pform_types_H */