summaryrefslogtreecommitdiff
path: root/types.c
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2019-10-31 13:28:39 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2019-10-31 13:28:39 -0400
commit8ce406bdb55c19d83abb8f7511212ee0c02cb487 (patch)
tree837e2f0c7b4fb6621ab81ad9cad415a2c2035b0b /types.c
parentfc6c746a726b3a56f2489c3db884c8ac2cd491d7 (diff)
basic . operator
Diffstat (limited to 'types.c')
-rw-r--r--types.c72
1 files changed, 65 insertions, 7 deletions
diff --git a/types.c b/types.c
index 1f7169f..8769907 100644
--- a/types.c
+++ b/types.c
@@ -16,6 +16,10 @@ static inline void *typer_arr_add_(Typer *tr, void **arr, size_t sz) {
return arr_adda_(arr, sz, &tr->allocr);
}
+static inline bool type_is_builtin(Type *t, BuiltinType b) {
+ return t->kind == TYPE_BUILTIN && t->builtin == b;
+}
+
#define typer_arr_add(tr, a) typer_arr_add_(tr, (void **)(a), sizeof **(a))
static bool type_eq(Type *a, Type *b) {
@@ -940,13 +944,16 @@ static bool types_expr(Typer *tr, Expression *e) {
Expression *rhs = e->binary.rhs;
Type *lhs_type = &lhs->type;
Type *rhs_type = &rhs->type;
- if (!types_expr(tr, lhs)
- || !types_expr(tr, rhs))
- return false;
- if (lhs_type->kind == TYPE_UNKNOWN || rhs_type->kind == TYPE_UNKNOWN) {
- return true;
+ BinaryOp o = e->binary.op;
+ if (o != BINARY_DOT) {
+ if (!types_expr(tr, lhs)
+ || !types_expr(tr, rhs))
+ return false;
+ if (lhs_type->kind == TYPE_UNKNOWN || rhs_type->kind == TYPE_UNKNOWN) {
+ return true;
+ }
}
- switch (e->binary.op) {
+ switch (o) {
case BINARY_SET:
if (!expr_must_lval(e->binary.lhs)) {
return false;
@@ -972,7 +979,6 @@ static bool types_expr(Typer *tr, Expression *e) {
case BINARY_GE:
case BINARY_EQ:
case BINARY_NE: {
- BinaryOp o = e->binary.op;
bool valid = false;
if (o == BINARY_SET) {
valid = type_eq(lhs_type, rhs_type);
@@ -1074,6 +1080,58 @@ 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) {
+ bool is_field = false;
+ if (rhs->kind == EXPR_IDENT) {
+ /* maybe accessing a field? */
+ arr_foreach(inner_type->struc.fields, Field, f) {
+ if (f->name == rhs->ident) {
+ is_field = true;
+ *t = *f->type;
+ e->binary.field = f;
+ }
+ }
+ }
+
+ if (!is_field) {
+ /* allow some_struct."foo" */
+ Value field_name;
+ if (!types_expr(tr, rhs)) return false;
+ if (rhs_type->kind != TYPE_SLICE || !type_is_builtin(rhs_type->slice, BUILTIN_CHAR)) {
+ err_print(e->where, "Invalid field of type %s.");
+ return false;
+
+ }
+ if (!eval_expr(tr->evalr, rhs, &field_name)) return false;
+ arr_foreach(inner_type->struc.fields, Field, f) {
+ if (ident_eq_str(f->name, field_name.slice.data)) {
+ is_field = true;
+ *t = *f->type;
+ e->binary.field = f;
+ }
+ }
+ if (!is_field) {
+ char *fstr = err_malloc(field_name.slice.n + 1);
+ memcpy(fstr, field_name.slice.data, field_name.slice.n);
+ fstr[field_name.slice.n] = 0; /* null-terminate */
+ char *typestr = type_to_str(lhs_type);
+ err_print(e->where, "%s is not a field of structure %s.", fstr, typestr);
+ free(fstr); free(typestr);
+ return false;
+ }
+ }
+ } else {
+ char *s = type_to_str(lhs_type);
+ err_print(e->where, "Operator . applied to type %s, which is not a structure.", s);
+ free(s);
+ return false;
+ }
+ } break;
} break;
} break;
case EXPR_TUPLE: