diff --git a/doc/Changelog.md b/doc/Changelog.md index cdd1afd..39d2465 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -1,4 +1,7 @@ +## 0.9.2 +- (#224) - Ensure fields within expressions can be referenced + ## 0.9.1 - (#221) - Correct a random-stability issue due to solve-order directives - diff --git a/src/vsc/model/expr_indexed_field_ref_model.py b/src/vsc/model/expr_indexed_field_ref_model.py index 8d05eeb..98f34d6 100644 --- a/src/vsc/model/expr_indexed_field_ref_model.py +++ b/src/vsc/model/expr_indexed_field_ref_model.py @@ -16,7 +16,7 @@ def __init__(self, idx_t): super().__init__() - if not isinstance(root, (ExprFieldRefModel,ExprArraySubscriptModel)): + if not isinstance(root, (ExprFieldRefModel,ExprArraySubscriptModel,ExprIndexedFieldRefModel)): raise Exception("unsupported root for an indexed reference: " + str(root)) self.root = root diff --git a/src/vsc/types.py b/src/vsc/types.py index 80ad028..42ce8d0 100644 --- a/src/vsc/types.py +++ b/src/vsc/types.py @@ -40,6 +40,7 @@ from vsc.model.expr_rangelist_model import ExprRangelistModel from vsc.model.expr_unary_model import ExprUnaryModel from vsc.model.field_array_model import FieldArrayModel +from vsc.model.field_composite_model import FieldCompositeModel from vsc.model.field_const_array_model import FieldConstArrayModel from vsc.model.field_scalar_model import FieldScalarModel from vsc.model.unary_expr_type import UnaryExprType @@ -49,6 +50,8 @@ from vsc.impl.expr_mode import get_expr_mode, expr_mode, is_expr_mode from vsc.model.expr_array_product_model import ExprArrayProductModel from vsc.visitors.model_pretty_printer import ModelPrettyPrinter +from vsc.visitors.expr2field_visitor import Expr2FieldVisitor +from vsc.visitors.expr2fieldtype_visitor import Expr2FieldTypeVisitor from vsc.model.expr_indexed_dynref_model import ExprIndexedDynRefModel from vsc.model.source_info import SourceInfo @@ -172,6 +175,29 @@ def not_inside(self, rhs): else: raise Exception("Unsupported 'not_inside' argument of type " + str(type(rhs))) + def __getattr__(self, name): + ret = None + em = object.__getattribute__(self, "em") + fm_t = Expr2FieldTypeVisitor().fieldtype(em) + + if fm_t is not None: + if name in fm_t.field_id_m.keys(): + idx = fm_t.field_id_m[name] + ret = expr(ExprIndexedFieldRefModel(em, [idx])) + else: + raise Exception("Field %s not in type %s" % (name, fm_t.name)) + else: + fm = Expr2FieldVisitor().field(em) + + if name in fm.field_id_m.keys(): + idx = fm.field_id_m[name] + ret = expr(ExprIndexedFieldRefModel(em, [idx])) + else: + raise Exception("Composite %s does not contain a field \"%s\"" % ( + fm.name, name)) + + return ret + def __getitem__(self, k): if is_expr_mode(): if isinstance(k, slice): diff --git a/src/vsc/visitors/expr2fieldtype_visitor.py b/src/vsc/visitors/expr2fieldtype_visitor.py index 4dac494..fee5636 100644 --- a/src/vsc/visitors/expr2fieldtype_visitor.py +++ b/src/vsc/visitors/expr2fieldtype_visitor.py @@ -12,7 +12,7 @@ class Expr2FieldTypeVisitor(ModelVisitor): """Traverses an array-reference expression, returning element-type information""" - DEBUG_EN = False + DEBUG_EN = True def __init__(self): super().__init__() @@ -39,6 +39,9 @@ def visit_field_scalar_array(self, f:FieldArrayModel): self.type = f.type_t if Expr2FieldTypeVisitor.DEBUG_EN: print("--> visit_field_array fm=%s ft=%s" % (str(self.field), str(self.type))) + + def visit_composite_field(self, t): + self.type = None def visit_expr_indexed_fieldref(self, e : ExprIndexedFieldRefModel): if Expr2FieldTypeVisitor.DEBUG_EN: @@ -52,6 +55,14 @@ def visit_expr_array_subscript(self, s : ExprArraySubscriptModel): print("--> visit_expr_array_subscript") s.lhs.accept(self) + if Expr2FieldTypeVisitor.DEBUG_EN: + print("--> visit_expr_array_subscript(visit_type)") + t = self.type + self.type = None + t.accept(self) + if Expr2FieldTypeVisitor.DEBUG_EN: + print("<-- visit_expr_array_subscript(visit_type)") + if Expr2FieldTypeVisitor.DEBUG_EN: print("<-- visit_expr_array_subscript") \ No newline at end of file diff --git a/ve/unit/test_compound_obj.py b/ve/unit/test_compound_obj.py index 34fd477..e3b2b64 100644 --- a/ve/unit/test_compound_obj.py +++ b/ve/unit/test_compound_obj.py @@ -545,4 +545,29 @@ def test_c(self): inst.randomize(debug=0) print(inst.c1[0].a[0].value) print(inst.c2[0].x[0].value) - \ No newline at end of file + + def test_nested_objects(self): + + @vsc.randobj + class Field(object): + def __init__(self): + self.c = vsc.rand_uint8_t() + + + @vsc.randobj + class Child(object): + def __init__(self): + self.b = vsc.rand_attr(Field()) + + + @vsc.randobj + class Parent(object): + def __init__(self): + self.a = vsc.rand_list_t(Child(), 2) + + @vsc.constraint + def eq_c(self): + self.a[0].b.c == self.a[1].b.c + + + item = Parent()