Browse files

Handle dereferencing through record accesses

  • Loading branch information...
1 parent 5a6e98b commit 0db3bb4c05b6b9d00be1219e3182e2473a03263b @nickg committed Dec 27, 2012
Showing with 88 additions and 10 deletions.
  1. +11 −0 src/parse.y
  2. +55 −6 src/sem.c
  3. +17 −0 test/sem/access.vhd
  4. +5 −4 test/test_sem.c
View
11 src/parse.y
@@ -2137,6 +2137,17 @@ name
tree_set_value($$, $1);
tree_set_loc($$, &@$);
}
+| name tALL tDOT selected_id
+ {
+ tree_t all = tree_new(T_ALL);
+ tree_set_value(all, $1);
+ tree_set_loc(all, &@$);
+
+ $$ = tree_new(T_RECORD_REF);
+ tree_set_value($$, all);
+ tree_set_ident($$, $4);
+ tree_set_loc($$, &@$);
+ }
;
name_list
View
61 src/sem.c
@@ -1635,6 +1635,13 @@ static bool sem_check_decl(tree_t t)
sem_declare_fields(type, tree_ident(t));
}
+ else if (type_kind(type) == T_ACCESS) {
+ type_t deref_type = type_access(type);
+ if (type_kind(deref_type) == T_RECORD) {
+ // Pointers to records can be dereferenced implicitly
+ sem_declare_fields(deref_type, tree_ident(t));
+ }
+ }
sem_add_attributes(t);
@@ -3184,10 +3191,10 @@ static bool sem_check_literal(tree_t t)
{
type_t access_type;
if (!type_set_uniq(&access_type))
- sem_error(t, "invalid use of NULL expression");
+ sem_error(t, "invalid use of null expression");
if (type_kind(access_type) != T_ACCESS)
- sem_error(t, "NULL expression must have access type");
+ sem_error(t, "null expression must have access type");
tree_set_type(t, access_type);
}
@@ -3464,16 +3471,26 @@ static void sem_convert_to_record_ref(tree_t t, tree_t decl)
ident_t base = ident_runtil(tree_ident(t), '.');
tree_t rec = scope_find(base);
assert(rec != NULL);
- assert(type_kind(tree_type(rec)) == T_RECORD);
- tree_t value;
+ tree_t value = NULL;
+
+ type_kind_t kind = type_kind(tree_type(rec));
+ if (kind == T_ACCESS) {
+ // Record fields can be dereferenced implicitly
+ value = tree_new(T_ALL);
+ tree_set_value(value, sem_make_ref(rec));
+ tree_set_type(value, type_access(tree_type(rec)));
+ }
+ else
+ assert(kind == T_RECORD);
+
if (tree_kind(rec) == T_FIELD_DECL) {
value = tree_new(T_REF);
tree_set_loc(value, tree_loc(t));
tree_set_ident(value, base);
sem_convert_to_record_ref(value, rec);
}
- else
+ else if (value == NULL)
value = sem_make_ref(rec);
tree_change_kind(t, T_RECORD_REF);
@@ -3537,6 +3554,35 @@ static bool sem_check_ref(tree_t t)
return true;
}
+static bool sem_check_record_ref(tree_t t)
+{
+ tree_t value = tree_value(t);
+ if (!sem_check_constrained(value, NULL))
+ return false;
+
+ type_t value_type = tree_type(value);
+ if (type_kind(value_type) != T_RECORD)
+ sem_error(value, "expected record type but found %s",
+ type_pp(value_type));
+
+ ident_t fname = tree_ident(t);
+
+ const int nfields = type_fields(value_type);
+ tree_t field = NULL;
+ for (int i = 0; i < nfields; i++) {
+ field = type_field(value_type, i);
+ if (tree_ident(field) == fname)
+ break;
+ }
+
+ if (field == NULL)
+ sem_error(t, "record type %s has no field %s",
+ type_pp(value_type), istr(fname));
+
+ tree_set_type(t, tree_type(field));
+ return true;
+}
+
static bool sem_check_array_ref(tree_t t)
{
tree_t value = tree_value(t);
@@ -4266,7 +4312,8 @@ static bool sem_check_all(tree_t t)
type_t value_type = tree_type(value);
if (type_kind(value_type) != T_ACCESS)
- sem_error(value, "expression must have access type");
+ sem_error(value, "expression type %s is not access",
+ type_pp(value_type));
tree_set_type(t, type_access(value_type));
return true;
@@ -4387,6 +4434,8 @@ bool sem_check(tree_t t)
return sem_check_new(t);
case T_ALL:
return sem_check_all(t);
+ case T_RECORD_REF:
+ return sem_check_record_ref(t);
default:
sem_error(t, "cannot check %s", tree_kind_str(tree_kind(t)));
}
View
17 test/sem/access.vhd
@@ -4,13 +4,23 @@ package p is
type bad1 is access foo; -- Error
+ type rec;
+
+ type rec_ptr is access rec;
+
+ type rec is record
+ value : integer;
+ link : rec_ptr;
+ end record;
+
end package;
package body p is
procedure test is
variable v : int_ptr;
variable i : integer;
+ variable r : rec_ptr;
begin
v := null; -- OK
i := null; -- Error
@@ -22,6 +32,13 @@ package body p is
v.all := 5; -- OK
v := 5; -- Error
i := v.all + 5; -- OK
+ r := new rec; -- OK
+ r.all.value := 1; -- OK
+ r.value := 1; -- OK
+ r.link := r; -- OK
+ r.link := r.all; -- Error
+ i := r.value; -- OK
+ r := r.all.link; -- OK
end procedure;
end package body;
View
9 test/test_sem.c
@@ -950,10 +950,11 @@ START_TEST(test_access)
const error_t expect[] = {
{ 5, "type FOO is not defined" },
- { 16, "NULL expression must have access type" },
- { 20, "invalid allocator expression" },
- { 21, "I does not name a type" },
- { 23, "does not match type of target WORK.P.INT_PTR" },
+ { 26, "null expression must have access type" },
+ { 30, "invalid allocator expression" },
+ { 31, "I does not name a type" },
+ { 33, "does not match type of target WORK.P.INT_PTR" },
+ { 39, "type of value WORK.P.REC does not match type of" },
{ -1, NULL }
};
expect_errors(expect);

0 comments on commit 0db3bb4

Please sign in to comment.