summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2019-11-01 13:57:28 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2019-11-01 13:57:28 -0400
commitbedd8ae2b1fead877438feb85ff57df3da21fb2b (patch)
treea9bbd7be4df13847655d187e3f9040d3f3cc5940
parent946da358819261056fad49d9318c6080e9c76c0d (diff)
. with pointers to structs
-rw-r--r--cgen.c7
-rw-r--r--eval.c41
-rw-r--r--test.toc4
-rw-r--r--types.c16
4 files changed, 43 insertions, 25 deletions
diff --git a/cgen.c b/cgen.c
index 78a2b5f..be35274 100644
--- a/cgen.c
+++ b/cgen.c
@@ -852,14 +852,15 @@ static bool cgen_expr(CGenerator *g, Expression *e) {
cgen_write(g, ")");
handled = true;
break;
- case BINARY_DOT:
+ case BINARY_DOT: {
cgen_write(g, "(");
cgen_expr(g, e->binary.lhs);
- cgen_write(g, ".");
+ bool is_ptr = type_inner(&e->binary.lhs->type)->kind == TYPE_PTR;
+ cgen_write(g, is_ptr ? "->" : ".");
cgen_ident(g, e->binary.field->name);
cgen_write(g, ")");
handled = true;
- break;
+ } break;
}
if (handled) break;
cgen_write(g, "(");
diff --git a/eval.c b/eval.c
index a6ad31c..c7a6f43 100644
--- a/eval.c
+++ b/eval.c
@@ -655,6 +655,26 @@ static bool eval_expr_ptr_at_index(Evaluator *ev, Expression *e, void **ptr, Typ
return eval_val_ptr_at_index(ev, e->where, &arr, i, ltype, rtype, ptr, type);
}
+static void *eval_ptr_to_struct_field(Evaluator *ev, Expression *dot_expr) {
+ Type *struct_type = type_inner(&dot_expr->binary.lhs->type);
+ bool is_ptr = struct_type->kind == TYPE_PTR;
+ if (is_ptr) {
+ struct_type = type_inner(struct_type->ptr);
+ }
+ eval_struct_find_offsets(struct_type);
+
+ Value struc;
+ if (!eval_expr(ev, dot_expr->binary.lhs, &struc))
+ return false;
+ void *struc_data;
+ if (is_ptr) {
+ struc_data = *(void **)struc.ptr;
+ } else {
+ struc_data = struc.struc;
+ }
+ return (char *)struc_data + dot_expr->binary.field->offset;
+}
+
static bool eval_set(Evaluator *ev, Expression *set, Value *to) {
switch (set->kind) {
case EXPR_IDENT: {
@@ -687,11 +707,8 @@ static bool eval_set(Evaluator *ev, Expression *set, Value *to) {
eval_deref_set(ptr, to, type);
} break;
case BINARY_DOT: {
- Value struc;
- if (!eval_expr(ev, set->binary.lhs, &struc))
- return false;
- eval_struct_find_offsets(type_inner(&set->binary.lhs->type));
- void *ptr = (char *)struc.struc + set->binary.field->offset;
+ void *ptr = eval_ptr_to_struct_field(ev, set);
+ if (!ptr) return false;
eval_deref_set(ptr, to, set->binary.field->type);
} break;
default: assert(0); break;
@@ -852,8 +869,9 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) {
Value struc;
if (!eval_expr(ev, o->binary.lhs, &struc))
return false;
- eval_struct_find_offsets(type_inner(&o->binary.lhs->type));
- v->ptr = (char *)struc.struc + o->binary.field->offset;
+ v->ptr = eval_ptr_to_struct_field(ev, o);
+ if (!v->ptr)
+ return false;
} break;
default: assert(0); break;
}
@@ -895,12 +913,9 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) {
BuiltinType builtin = e->binary.lhs->type.builtin;
switch (e->binary.op) {
case BINARY_DOT: {
- Type *inner_type = &e->binary.lhs->type;
- while (inner_type->kind == TYPE_USER)
- inner_type = ident_typeval(inner_type->user.name);
- eval_struct_find_offsets(inner_type);
-
- eval_deref(v, (char *)lhs.struc + e->binary.field->offset, &e->type);
+ void *ptr = eval_ptr_to_struct_field(ev, e);
+ if (!ptr) return false;
+ eval_deref(v, ptr, &e->type);
} break;
case BINARY_ADD:
if (e->binary.lhs->type.kind == TYPE_PTR) {
diff --git a/test.toc b/test.toc
index 2aaca38..08989ed 100644
--- a/test.toc
+++ b/test.toc
@@ -7,9 +7,9 @@ puti @= fn(x: int) {
};
main @= fn() {
-// puti(somesum());
+puti(somesum());
foo @= somesum();
-// puti(foo);
+puti(foo);
};
Point @= struct {
x, y : int;
diff --git a/types.c b/types.c
index a370ba9..5f44db2 100644
--- a/types.c
+++ b/types.c
@@ -1081,14 +1081,16 @@ static bool types_expr(Typer *tr, Expression *e) {
break;
case BINARY_DOT: {
if (!types_expr(tr, lhs)) return false;
- Type *inner_type = lhs_type;
- while (inner_type->kind == TYPE_USER)
- inner_type = ident_typeval(inner_type->user.name);
- if (inner_type->kind == TYPE_STRUCT) {
+ Type *struct_type = type_inner(lhs_type);
+ if (struct_type->kind == TYPE_PTR)
+ struct_type = struct_type->ptr;
+ struct_type = type_inner(struct_type);
+
+ if (struct_type->kind == TYPE_STRUCT) {
bool is_field = false;
if (rhs->kind == EXPR_IDENT) {
/* maybe accessing a field? */
- arr_foreach(inner_type->struc.fields, Field, f) {
+ arr_foreach(struct_type->struc.fields, Field, f) {
if (f->name == rhs->ident) {
is_field = true;
*t = *f->type;
@@ -1107,7 +1109,7 @@ static bool types_expr(Typer *tr, Expression *e) {
}
if (!eval_expr(tr->evalr, rhs, &field_name)) return false;
- arr_foreach(inner_type->struc.fields, Field, f) {
+ arr_foreach(struct_type->struc.fields, Field, f) {
if (ident_eq_str(f->name, field_name.slice.data)) {
is_field = true;
*t = *f->type;
@@ -1126,7 +1128,7 @@ static bool types_expr(Typer *tr, Expression *e) {
}
} else {
char *s = type_to_str(lhs_type);
- err_print(e->where, "Operator . applied to type %s, which is not a structure.", s);
+ err_print(e->where, "Operator . applied to type %s, which is not a structure or pointer to structure.", s);
free(s);
return false;
}