From 4ef3ac5ca66428ebc1dc8072cab80f82f875fadc Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 28 Jun 2013 10:57:35 -0400 Subject: [PATCH] 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. --- elab_lval.cc | 40 ++++++++++++++++++++++++++++++++++++++++ elaborate.cc | 7 +++++++ netclass.cc | 26 ++++++++++++++++++++++++++ netclass.h | 10 ++++++++++ parse.y | 19 ++++++++++++++++++- property_qual.h | 4 ++++ 6 files changed, 105 insertions(+), 1 deletion(-) diff --git a/elab_lval.cc b/elab_lval.cc index 86cecdcb0..3c5c8011e 100644 --- a/elab_lval.cc +++ b/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); diff --git a/elaborate.cc b/elaborate.cc index 418206c20..204af613d 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -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; + } } } diff --git a/netclass.cc b/netclass.cc index 91636b95d..abf42071a 100644 --- a/netclass.cc +++ b/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) ); diff --git a/netclass.h b/netclass.h index 8aac64583..71cd32d6a 100644 --- a/netclass.h +++ b/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 property_table_; diff --git a/parse.y b/parse.y index bc120c050..32548fb11 100644 --- a/parse.y +++ b/parse.y @@ -581,7 +581,8 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type struct_data_type %type class_item_qualifier property_qualifier -%type property_qualifier_list property_qualifier_opt +%type class_item_qualifier_list property_qualifier_list +%type class_item_qualifier_opt property_qualifier_opt %type random_qualifier %type 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; } diff --git a/property_qual.h b/property_qual.h index df02c7080..aaaa37b86 100644 --- a/property_qual.h +++ b/property_qual.h @@ -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_;