Implement const properties of classes.
This implementation works by detecting assignments to constant properties in elaboration. Allow initializer assignments to assign to the constant, error all other assignments, and otherwise treat the constant like any other property.
This commit is contained in:
parent
cf47a759d1
commit
4ef3ac5ca6
40
elab_lval.cc
40
elab_lval.cc
|
|
@ -343,6 +343,40 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des,
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Detect assignment to constant properties. Note that the
|
||||
// initializer constructor MAY assign to constant properties,
|
||||
// as this is how the property gets its value.
|
||||
property_qualifier_t qual = class_type->get_prop_qual(pidx);
|
||||
if (qual.test_const()) {
|
||||
if (class_type->get_prop_initialized(pidx)) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Property " << class_type->get_prop_name(pidx)
|
||||
<< " is constant in this method."
|
||||
<< " (scope=" << scope_path(scope) << ")" << endl;
|
||||
des->errors += 1;
|
||||
|
||||
} else if (scope->basename()!="new" && scope->basename()!="new@") {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Property " << class_type->get_prop_name(pidx)
|
||||
<< " is constant in this method."
|
||||
<< " (scope=" << scope_path(scope) << ")" << endl;
|
||||
des->errors += 1;
|
||||
|
||||
} else {
|
||||
|
||||
// Mark this property as initilized. This is used
|
||||
// to know that we have initialized the constant
|
||||
// object so the next assignment will be marked as
|
||||
// illegal.
|
||||
class_type->set_prop_initialized(pidx);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_lval_method_class_member_: "
|
||||
<< "Found initilzers for property " << class_type->get_prop_name(pidx) << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NetAssign_*this_lval = new NetAssign_(this_net);
|
||||
this_lval->set_property(member_name);
|
||||
|
||||
|
|
@ -842,6 +876,12 @@ bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope,
|
|||
<< " is not accessible (l-value) in this context."
|
||||
<< " (scope=" << scope_path(scope) << ")" << endl;
|
||||
des->errors += 1;
|
||||
|
||||
} else if (qual.test_const()) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Property " << class_type->get_prop_name(pidx)
|
||||
<< " is constant in this context." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
lv->set_property(method_name);
|
||||
|
|
|
|||
|
|
@ -4883,6 +4883,13 @@ static void elaborate_classes(Design*des, NetScope*scope,
|
|||
; cur != classes.end() ; ++ cur) {
|
||||
netclass_t*use_class = scope->find_class(cur->second->pscope_name());
|
||||
use_class->elaborate(des, cur->second);
|
||||
|
||||
if (use_class->test_for_missing_initializers()) {
|
||||
cerr << cur->second->get_fileline() << ": error: "
|
||||
<< "Const properties of class " << use_class->get_name()
|
||||
<< " are missing initialization." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
26
netclass.cc
26
netclass.cc
|
|
@ -43,6 +43,7 @@ bool netclass_t::set_property(perm_string pname, property_qualifier_t qual, ivl_
|
|||
tmp.name = pname;
|
||||
tmp.qual = qual;
|
||||
tmp.type = ptype;
|
||||
tmp.initialized_flag = false;
|
||||
property_table_.push_back(tmp);
|
||||
|
||||
properties_[pname] = property_table_.size()-1;
|
||||
|
|
@ -88,6 +89,31 @@ ivl_type_t netclass_t::get_prop_type(size_t idx) const
|
|||
return property_table_[idx].type;
|
||||
}
|
||||
|
||||
bool netclass_t::get_prop_initialized(size_t idx) const
|
||||
{
|
||||
assert(idx < property_table_.size());
|
||||
return property_table_[idx].initialized_flag;
|
||||
}
|
||||
|
||||
void netclass_t::set_prop_initialized(size_t idx) const
|
||||
{
|
||||
assert(idx < property_table_.size());
|
||||
assert(! property_table_[idx].initialized_flag);
|
||||
property_table_[idx].initialized_flag = true;
|
||||
}
|
||||
|
||||
bool netclass_t::test_for_missing_initializers() const
|
||||
{
|
||||
for (size_t idx = 0 ; idx < property_table_.size() ; idx += 1) {
|
||||
if (property_table_[idx].initialized_flag)
|
||||
continue;
|
||||
if (property_table_[idx].qual.test_const())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
NetScope*netclass_t::method_from_name(perm_string name) const
|
||||
{
|
||||
NetScope*task = class_scope_->child( hname_t(name) );
|
||||
|
|
|
|||
10
netclass.h
10
netclass.h
|
|
@ -57,6 +57,15 @@ class netclass_t : public ivl_type_s {
|
|||
property_qualifier_t get_prop_qual(size_t idx) const;
|
||||
ivl_type_t get_prop_type(size_t idx) const;
|
||||
|
||||
// These methods are used by the elaborator to note the
|
||||
// initializer for constant properties. Properties start out
|
||||
// as not initialized, and when elaboration detects an
|
||||
// assignment to the property, it is marked initialized.
|
||||
bool get_prop_initialized(size_t idx) const;
|
||||
void set_prop_initialized(size_t idx) const;
|
||||
|
||||
bool test_for_missing_initializers(void) const;
|
||||
|
||||
// Map the name of a property to its index.
|
||||
int property_idx_from_name(perm_string pname) const;
|
||||
|
||||
|
|
@ -84,6 +93,7 @@ class netclass_t : public ivl_type_s {
|
|||
perm_string name;
|
||||
property_qualifier_t qual;
|
||||
ivl_type_s* type;
|
||||
mutable bool initialized_flag;
|
||||
};
|
||||
std::vector<prop_t> property_table_;
|
||||
|
||||
|
|
|
|||
19
parse.y
19
parse.y
|
|
@ -581,7 +581,8 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
|
|||
%type <struct_type> struct_data_type
|
||||
|
||||
%type <property_qualifier> class_item_qualifier property_qualifier
|
||||
%type <property_qualifier> property_qualifier_list property_qualifier_opt
|
||||
%type <property_qualifier> class_item_qualifier_list property_qualifier_list
|
||||
%type <property_qualifier> class_item_qualifier_opt property_qualifier_opt
|
||||
%type <property_qualifier> random_qualifier
|
||||
|
||||
%type <ranges> range range_opt variable_dimension
|
||||
|
|
@ -695,6 +696,7 @@ class_identifier
|
|||
// 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);
|
||||
delete[]$1;
|
||||
$$ = tmp;
|
||||
|
|
@ -793,6 +795,9 @@ class_item /* IEEE1800-2005: A.1.8 */
|
|||
| property_qualifier_opt data_type list_of_variable_decl_assignments ';'
|
||||
{ pform_class_property(@2, $1, $2, $3); }
|
||||
|
||||
| K_const class_item_qualifier_opt data_type list_of_variable_decl_assignments ';'
|
||||
{ pform_class_property(@1, $2 | property_qualifier_t::make_const(), $3, $4); }
|
||||
|
||||
/* Class methods... */
|
||||
|
||||
| method_qualifier_opt task_declaration
|
||||
|
|
@ -837,6 +842,16 @@ class_item_qualifier /* IEEE1800-2005 A.1.8 */
|
|||
| K_local { $$ = property_qualifier_t::make_local(); }
|
||||
;
|
||||
|
||||
class_item_qualifier_list
|
||||
: class_item_qualifier_list class_item_qualifier { $$ = $1 | $2; }
|
||||
| class_item_qualifier { $$ = $1; }
|
||||
;
|
||||
|
||||
class_item_qualifier_opt
|
||||
: class_item_qualifier_list { $$ = $1; }
|
||||
| { $$ = property_qualifier_t::make_none(); }
|
||||
;
|
||||
|
||||
class_new /* IEEE1800-2005 A.2.4 */
|
||||
: K_new '(' ')'
|
||||
{ PENewClass*tmp = new PENewClass;
|
||||
|
|
@ -2056,6 +2071,7 @@ type_declaration
|
|||
// 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);
|
||||
delete[]$3;
|
||||
}
|
||||
|
|
@ -2070,6 +2086,7 @@ type_declaration
|
|||
// 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);
|
||||
delete[]$2;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,9 @@ class property_qualifier_t {
|
|||
static inline property_qualifier_t make_randc()
|
||||
{ property_qualifier_t res; res.mask_ = 16; return res; }
|
||||
|
||||
static inline property_qualifier_t make_const()
|
||||
{ property_qualifier_t res; res.mask_ = 32; return res; }
|
||||
|
||||
inline property_qualifier_t operator | (property_qualifier_t r)
|
||||
{ property_qualifier_t res; res.mask_ = mask_ | r.mask_; return res; }
|
||||
|
||||
|
|
@ -48,6 +51,7 @@ class property_qualifier_t {
|
|||
inline bool test_local() const { return mask_ & 4; }
|
||||
inline bool test_rand() const { return mask_ & 8; }
|
||||
inline bool test_randc() const { return mask_ & 16; }
|
||||
inline bool test_const() const { return mask_ & 32; }
|
||||
|
||||
private:
|
||||
int mask_;
|
||||
|
|
|
|||
Loading…
Reference in New Issue