Implement the "local" class member protection.
Test during elaboration that the member really is accessible in the context where the elaboration happens.
This commit is contained in:
parent
046535cfbb
commit
cf47a759d1
47
elab_expr.cc
47
elab_expr.cc
|
|
@ -1135,7 +1135,11 @@ unsigned PECallFunction::test_width_method_(Design*des, NetScope*scope,
|
|||
}
|
||||
|
||||
const netclass_t* class_type = net->class_type();
|
||||
member_type = class_type->get_property(member_name);
|
||||
int midx = class_type->property_idx_from_name(member_name);
|
||||
if (midx >= 0)
|
||||
member_type = class_type->get_prop_type(midx);
|
||||
else
|
||||
member_type = 0;
|
||||
use_path = tmp_path;
|
||||
|
||||
use_darray = dynamic_cast<const netdarray_t*> (member_type);
|
||||
|
|
@ -1756,14 +1760,13 @@ static NetExpr* check_for_struct_members(const LineInfo*li,
|
|||
}
|
||||
|
||||
static NetExpr* check_for_class_property(const LineInfo*li,
|
||||
Design*des, NetScope*,
|
||||
Design*des, NetScope*scope,
|
||||
NetNet*net,
|
||||
const name_component_t&comp)
|
||||
{
|
||||
const netclass_t*class_type = net->class_type();
|
||||
const ivl_type_s*ptype = class_type->get_property(comp.name);
|
||||
|
||||
if (ptype == 0) {
|
||||
int pidx = class_type->property_idx_from_name(comp.name);
|
||||
if (pidx < 0) {
|
||||
cerr << li->get_fileline() << ": error: "
|
||||
<< "Class " << class_type->get_name()
|
||||
<< " has no property " << comp.name << "." << endl;
|
||||
|
|
@ -1771,6 +1774,23 @@ static NetExpr* check_for_class_property(const LineInfo*li,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << li->get_fileline() << ": check_for_class_property: "
|
||||
<< "Property " << comp.name
|
||||
<< " of net " << net->name()
|
||||
<< ", context scope=" << scope_path(scope)
|
||||
<< endl;
|
||||
}
|
||||
|
||||
property_qualifier_t qual = class_type->get_prop_qual(pidx);
|
||||
if (qual.test_local() && ! class_type->test_scope_is_method(scope)) {
|
||||
cerr << li->get_fileline() << ": error: "
|
||||
<< "Local property " << class_type->get_prop_name(pidx)
|
||||
<< " is not accessible in this context."
|
||||
<< " (scope=" << scope_path(scope) << ")" << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
NetEProperty*tmp = new NetEProperty(net, comp.name);
|
||||
tmp->set_line(*li);
|
||||
return tmp;
|
||||
|
|
@ -2715,8 +2735,9 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
|||
}
|
||||
|
||||
if (const netclass_t*class_type = net->class_type()) {
|
||||
const ivl_type_s*ptype = class_type->get_property(method_name);
|
||||
if (ptype) {
|
||||
int pidx = class_type->property_idx_from_name(method_name);
|
||||
if (pidx >= 0) {
|
||||
ivl_type_t ptype = class_type->get_prop_type(pidx);
|
||||
expr_type_ = ptype->base_type();
|
||||
expr_width_ = ptype->packed_width();
|
||||
min_width_ = expr_width_;
|
||||
|
|
@ -2823,7 +2844,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
* not a method, or the name is not in the parent class, then
|
||||
* fail. Otherwise, return a NetEProperty.
|
||||
*/
|
||||
NetExpr* PEIdent::elaborate_expr_class_member_(Design*, NetScope*scope,
|
||||
NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope,
|
||||
unsigned, unsigned) const
|
||||
{
|
||||
if (!gn_system_verilog())
|
||||
|
|
@ -2854,9 +2875,19 @@ NetExpr* PEIdent::elaborate_expr_class_member_(Design*, NetScope*scope,
|
|||
cerr << get_fileline() << ": PEIdent::elaborate_expr_class_member: "
|
||||
<< "Found member " << member_name
|
||||
<< " is a member of class " << class_type->get_name()
|
||||
<< ", context scope=" << scope_path(scope)
|
||||
<< ", so synthesizing a NetEProperty." << endl;
|
||||
}
|
||||
|
||||
property_qualifier_t qual = class_type->get_prop_qual(pidx);
|
||||
if (qual.test_local() && ! class_type->test_scope_is_method(scope)) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Local property " << class_type->get_prop_name(pidx)
|
||||
<< " is not accessible in this context."
|
||||
<< " (scope=" << scope_path(scope) << ")" << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
NetEProperty*tmp = new NetEProperty(this_net, member_name);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
|
|
|
|||
18
elab_lval.cc
18
elab_lval.cc
|
|
@ -316,7 +316,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
|||
return lv;
|
||||
}
|
||||
|
||||
NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*,
|
||||
NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des,
|
||||
NetScope*scope) const
|
||||
{
|
||||
if (!gn_system_verilog())
|
||||
|
|
@ -812,7 +812,7 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*,
|
||||
bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope,
|
||||
NetAssign_*lv,
|
||||
const perm_string&method_name) const
|
||||
{
|
||||
|
|
@ -827,16 +827,26 @@ bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*,
|
|||
|
||||
/* Make sure the property is really present in the class. If
|
||||
not, then generate an error message and return an error. */
|
||||
ivl_type_t ptype = class_type->get_property(method_name);
|
||||
if (ptype == 0) {
|
||||
int pidx = class_type->property_idx_from_name(method_name);
|
||||
if (pidx < 0) {
|
||||
cerr << get_fileline() << ": error: Class " << class_type->get_name()
|
||||
<< " does not have a property " << method_name << "." << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
property_qualifier_t qual = class_type->get_prop_qual(pidx);
|
||||
if (qual.test_local() && ! class_type->test_scope_is_method(scope)) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Local property " << class_type->get_prop_name(pidx)
|
||||
<< " is not accessible (l-value) in this context."
|
||||
<< " (scope=" << scope_path(scope) << ")" << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
lv->set_property(method_name);
|
||||
|
||||
ivl_type_t ptype = class_type->get_prop_type(pidx);
|
||||
const netdarray_t*mtype = dynamic_cast<const netdarray_t*> (ptype);
|
||||
if (mtype) {
|
||||
const name_component_t&name_tail = path_.back();
|
||||
|
|
|
|||
|
|
@ -366,15 +366,15 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass)
|
|||
|
||||
// Collect the properties, elaborate them, and add them to the
|
||||
// elaborated class definition.
|
||||
for (map<perm_string, data_type_t*>::iterator cur = use_type->properties.begin()
|
||||
for (map<perm_string, class_type_t::prop_info_t>::iterator cur = use_type->properties.begin()
|
||||
; cur != use_type->properties.end() ; ++ cur) {
|
||||
if (debug_scopes) {
|
||||
cerr << pclass->get_fileline() << ": elaborate_scope_class: "
|
||||
<< " Property " << cur->first << endl;
|
||||
}
|
||||
ivl_type_s*tmp = cur->second->elaborate_type(des, scope);
|
||||
ivl_type_s*tmp = cur->second.type->elaborate_type(des, scope);
|
||||
ivl_assert(*pclass, tmp);
|
||||
use_class->set_property(cur->first, tmp);
|
||||
use_class->set_property(cur->first, cur->second.qual, tmp);
|
||||
}
|
||||
|
||||
for (map<perm_string,PTask*>::iterator cur = pclass->tasks.begin()
|
||||
|
|
|
|||
|
|
@ -96,9 +96,9 @@ unsigned NetAssign_::lwidth() const
|
|||
if (member_.nil())
|
||||
return 1;
|
||||
|
||||
const ivl_type_s*ptype = class_type->get_property(member_);
|
||||
ivl_assert(*sig_, ptype);
|
||||
|
||||
int pidx = class_type->property_idx_from_name(member_);
|
||||
ivl_assert(*sig_, pidx >= 0);
|
||||
ivl_type_t ptype = class_type->get_prop_type(pidx);
|
||||
return ptype->packed_width();
|
||||
}
|
||||
|
||||
|
|
@ -118,7 +118,9 @@ ivl_variable_type_t NetAssign_::expr_type() const
|
|||
if (member_.nil())
|
||||
return sig_->data_type();
|
||||
|
||||
const ivl_type_s*tmp = class_type->get_property(member_);
|
||||
int pidx = class_type->property_idx_from_name(member_);
|
||||
ivl_assert(*sig_, pidx >= 0);
|
||||
ivl_type_t tmp = class_type->get_prop_type(pidx);
|
||||
return tmp->base_type();
|
||||
}
|
||||
|
||||
|
|
@ -138,8 +140,9 @@ const ivl_type_s* NetAssign_::net_type() const
|
|||
if (member_.nil())
|
||||
return sig_->net_type();
|
||||
|
||||
const ivl_type_s*tmp = class_type->get_property(member_);
|
||||
ivl_assert(*sig_, tmp);
|
||||
int pidx = class_type->property_idx_from_name(member_);
|
||||
ivl_assert(*sig_, pidx >= 0);
|
||||
ivl_type_t tmp = class_type->get_prop_type(pidx);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
|
|
|||
32
netclass.cc
32
netclass.cc
|
|
@ -32,7 +32,7 @@ netclass_t::~netclass_t()
|
|||
{
|
||||
}
|
||||
|
||||
bool netclass_t::set_property(perm_string pname, ivl_type_s*ptype)
|
||||
bool netclass_t::set_property(perm_string pname, property_qualifier_t qual, ivl_type_s*ptype)
|
||||
{
|
||||
map<perm_string,size_t>::const_iterator cur;
|
||||
cur = properties_.find(pname);
|
||||
|
|
@ -41,6 +41,7 @@ bool netclass_t::set_property(perm_string pname, ivl_type_s*ptype)
|
|||
|
||||
prop_t tmp;
|
||||
tmp.name = pname;
|
||||
tmp.qual = qual;
|
||||
tmp.type = ptype;
|
||||
property_table_.push_back(tmp);
|
||||
|
||||
|
|
@ -59,17 +60,6 @@ ivl_variable_type_t netclass_t::base_type() const
|
|||
return IVL_VT_CLASS;
|
||||
}
|
||||
|
||||
const ivl_type_s* netclass_t::get_property(perm_string pname) const
|
||||
{
|
||||
map<perm_string,size_t>::const_iterator cur;
|
||||
cur = properties_.find(pname);
|
||||
if (cur == properties_.end())
|
||||
return 0;
|
||||
|
||||
assert(property_table_.size() > cur->second);
|
||||
return property_table_[cur->second].type;
|
||||
}
|
||||
|
||||
int netclass_t::property_idx_from_name(perm_string pname) const
|
||||
{
|
||||
map<perm_string,size_t>::const_iterator cur;
|
||||
|
|
@ -86,6 +76,12 @@ const char*netclass_t::get_prop_name(size_t idx) const
|
|||
return property_table_[idx].name;
|
||||
}
|
||||
|
||||
property_qualifier_t netclass_t::get_prop_qual(size_t idx) const
|
||||
{
|
||||
assert(idx < property_table_.size());
|
||||
return property_table_[idx].qual;
|
||||
}
|
||||
|
||||
ivl_type_t netclass_t::get_prop_type(size_t idx) const
|
||||
{
|
||||
assert(idx < property_table_.size());
|
||||
|
|
@ -99,3 +95,15 @@ NetScope*netclass_t::method_from_name(perm_string name) const
|
|||
return task;
|
||||
|
||||
}
|
||||
|
||||
bool netclass_t::test_scope_is_method(const NetScope*scope) const
|
||||
{
|
||||
while (scope && scope != class_scope_) {
|
||||
scope = scope->parent();
|
||||
}
|
||||
|
||||
if (scope == 0)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
14
netclass.h
14
netclass.h
|
|
@ -22,6 +22,7 @@
|
|||
# include "LineInfo.h"
|
||||
# include "ivl_target.h"
|
||||
# include "nettypes.h"
|
||||
# include "property_qual.h"
|
||||
# include <iostream>
|
||||
# include <map>
|
||||
|
||||
|
|
@ -37,7 +38,7 @@ class netclass_t : public ivl_type_s {
|
|||
// Set the property of the class during elaboration. Set the
|
||||
// name and type, and return true. If the name is already
|
||||
// present, then return false.
|
||||
bool set_property(perm_string pname, ivl_type_s*ptype);
|
||||
bool set_property(perm_string pname, property_qualifier_t qual, ivl_type_s*ptype);
|
||||
|
||||
// Set the scope for the class. The scope has no parents and
|
||||
// is used for the elaboration of methods (tasks/functions).
|
||||
|
|
@ -50,17 +51,23 @@ class netclass_t : public ivl_type_s {
|
|||
// This is the name of the class type
|
||||
inline perm_string get_name() const { return name_; }
|
||||
|
||||
const ivl_type_s* get_property(perm_string pname) const;
|
||||
|
||||
inline size_t get_properties(void) const { return properties_.size(); }
|
||||
// Get information about each property.
|
||||
const char*get_prop_name(size_t idx) const;
|
||||
property_qualifier_t get_prop_qual(size_t idx) const;
|
||||
ivl_type_t get_prop_type(size_t idx) const;
|
||||
|
||||
// Map the name of a property to its index.
|
||||
int property_idx_from_name(perm_string pname) const;
|
||||
|
||||
// The task method scopes from the method name.
|
||||
NetScope*method_from_name(perm_string mname) const;
|
||||
|
||||
// Test if this scope is a method within the class. This is
|
||||
// used to check scope for handling data protection keywords
|
||||
// "local" and "protected".
|
||||
bool test_scope_is_method(const NetScope*scope) const;
|
||||
|
||||
void elaborate_sig(Design*des, PClass*pclass);
|
||||
void elaborate(Design*des, PClass*pclass);
|
||||
|
||||
|
|
@ -75,6 +82,7 @@ class netclass_t : public ivl_type_s {
|
|||
// Vector of properties.
|
||||
struct prop_t {
|
||||
perm_string name;
|
||||
property_qualifier_t qual;
|
||||
ivl_type_s* type;
|
||||
};
|
||||
std::vector<prop_t> property_table_;
|
||||
|
|
|
|||
12
parse.y
12
parse.y
|
|
@ -832,9 +832,9 @@ class_item /* IEEE1800-2005: A.1.8 */
|
|||
;
|
||||
|
||||
class_item_qualifier /* IEEE1800-2005 A.1.8 */
|
||||
: K_static { $$ = property_qualifier_t::set_static(); }
|
||||
| K_protected { $$ = property_qualifier_t::set_protected(); }
|
||||
| K_local { $$ = property_qualifier_t::set_local(); }
|
||||
: K_static { $$ = property_qualifier_t::make_static(); }
|
||||
| K_protected { $$ = property_qualifier_t::make_protected(); }
|
||||
| K_local { $$ = property_qualifier_t::make_local(); }
|
||||
;
|
||||
|
||||
class_new /* IEEE1800-2005 A.2.4 */
|
||||
|
|
@ -1493,7 +1493,7 @@ property_qualifier /* IEEE1800-2005 A.1.8 */
|
|||
|
||||
property_qualifier_opt /* IEEE1800-2005 A.1.8: ... { property_qualifier } */
|
||||
: property_qualifier_list { $$ = $1; }
|
||||
| { $$ = property_qualifier_t::set_none(); }
|
||||
| { $$ = property_qualifier_t::make_none(); }
|
||||
;
|
||||
|
||||
property_qualifier_list /* IEEE1800-2005 A.1.8 */
|
||||
|
|
@ -1502,8 +1502,8 @@ property_qualifier_list /* IEEE1800-2005 A.1.8 */
|
|||
;
|
||||
|
||||
random_qualifier /* IEEE1800-2005 A.1.8 */
|
||||
: K_rand { $$ = property_qualifier_t::set_rand(); }
|
||||
| K_randc { $$ = property_qualifier_t::set_randc(); }
|
||||
: K_rand { $$ = property_qualifier_t::make_rand(); }
|
||||
| K_randc { $$ = property_qualifier_t::make_randc(); }
|
||||
;
|
||||
|
||||
/* real and realtime are exactly the same so save some code
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ void class_type_t::pform_dump(ostream&out, unsigned indent) const
|
|||
{
|
||||
out << setw(indent) << "" << "class " << name << " {";
|
||||
|
||||
for (map<perm_string,data_type_t*>::const_iterator cur = properties.begin()
|
||||
for (map<perm_string,prop_info_t>::const_iterator cur = properties.begin()
|
||||
; cur != properties.end() ; ++cur) {
|
||||
out << " " << cur->first;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,8 @@ void pform_class_property(const struct vlltype&loc,
|
|||
use_type = new uarray_type_t(use_type, pd);
|
||||
}
|
||||
|
||||
pform_cur_class->type->properties[curp->name] = use_type;
|
||||
pform_cur_class->type->properties[curp->name]
|
||||
= class_type_t::prop_info_t(property_qual,use_type);
|
||||
|
||||
if (PExpr*rval = curp->expr.release()) {
|
||||
PExpr*lval = new PEIdent(curp->name);
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
# include "LineInfo.h"
|
||||
# include "verinum.h"
|
||||
# include "named.h"
|
||||
# include "property_qual.h"
|
||||
# include "ivl_target.h"
|
||||
# include <iostream>
|
||||
# include <list>
|
||||
|
|
@ -219,7 +220,13 @@ struct class_type_t : public data_type_t {
|
|||
// This is the name of the class type.
|
||||
perm_string name;
|
||||
// This is a map of the properties. Map the name to the type.
|
||||
std::map<perm_string, data_type_t*> properties;
|
||||
struct prop_info_t {
|
||||
inline prop_info_t() : qual(property_qualifier_t::make_none()), type(0) { }
|
||||
inline prop_info_t(property_qualifier_t q, data_type_t*t) : qual(q), type(t) { }
|
||||
property_qualifier_t qual;
|
||||
data_type_t* type;
|
||||
};
|
||||
std::map<perm_string, struct prop_info_t> properties;
|
||||
|
||||
// This is an ordered list of property initializers. The name
|
||||
// is the name of the property to be assigned, and the val is
|
||||
|
|
@ -229,38 +236,6 @@ struct class_type_t : public data_type_t {
|
|||
ivl_type_s* elaborate_type(Design*, NetScope*) const;
|
||||
};
|
||||
|
||||
class property_qualifier_t {
|
||||
public:
|
||||
static inline property_qualifier_t set_none()
|
||||
{ property_qualifier_t res; res.mask_ = 0; return res; }
|
||||
|
||||
static inline property_qualifier_t set_static()
|
||||
{ property_qualifier_t res; res.mask_ = 1; return res; }
|
||||
|
||||
static inline property_qualifier_t set_protected()
|
||||
{ property_qualifier_t res; res.mask_ = 2; return res; }
|
||||
|
||||
static inline property_qualifier_t set_local()
|
||||
{ property_qualifier_t res; res.mask_ = 4; return res; }
|
||||
|
||||
static inline property_qualifier_t set_rand()
|
||||
{ property_qualifier_t res; res.mask_ = 8; return res; }
|
||||
|
||||
static inline property_qualifier_t set_randc()
|
||||
{ property_qualifier_t res; res.mask_ = 16; return res; }
|
||||
|
||||
inline property_qualifier_t operator | (property_qualifier_t r)
|
||||
{ property_qualifier_t res; res.mask_ = mask_ | r.mask_; return res; }
|
||||
|
||||
public:
|
||||
inline bool test_static() const { return mask_ & 1; }
|
||||
inline bool test_protected() const { return mask_ & 2; }
|
||||
inline bool test_local() const { return mask_ & 4; }
|
||||
|
||||
private:
|
||||
int mask_;
|
||||
};
|
||||
|
||||
/*
|
||||
* The pform_name_t is the general form for a hierarchical
|
||||
* identifier. It is an ordered list of name components. Each name
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
#ifndef __property_qual_H
|
||||
#define __property_qual_H
|
||||
/*
|
||||
* Copyright (c) 2013 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
class property_qualifier_t {
|
||||
public:
|
||||
static inline property_qualifier_t make_none()
|
||||
{ property_qualifier_t res; res.mask_ = 0; return res; }
|
||||
|
||||
static inline property_qualifier_t make_static()
|
||||
{ property_qualifier_t res; res.mask_ = 1; return res; }
|
||||
|
||||
static inline property_qualifier_t make_protected()
|
||||
{ property_qualifier_t res; res.mask_ = 2; return res; }
|
||||
|
||||
static inline property_qualifier_t make_local()
|
||||
{ property_qualifier_t res; res.mask_ = 4; return res; }
|
||||
|
||||
static inline property_qualifier_t make_rand()
|
||||
{ property_qualifier_t res; res.mask_ = 8; return res; }
|
||||
|
||||
static inline property_qualifier_t make_randc()
|
||||
{ property_qualifier_t res; res.mask_ = 16; return res; }
|
||||
|
||||
inline property_qualifier_t operator | (property_qualifier_t r)
|
||||
{ property_qualifier_t res; res.mask_ = mask_ | r.mask_; return res; }
|
||||
|
||||
public:
|
||||
inline bool test_static() const { return mask_ & 1; }
|
||||
inline bool test_protected() const { return mask_ & 2; }
|
||||
inline bool test_local() const { return mask_ & 4; }
|
||||
inline bool test_rand() const { return mask_ & 8; }
|
||||
inline bool test_randc() const { return mask_ & 16; }
|
||||
|
||||
private:
|
||||
int mask_;
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
Reference in New Issue