summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2020-02-14 12:14:53 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2020-02-14 12:14:53 -0500
commit41ba175c4bcfac35bf55d569a3d06198465ae33e (patch)
treef8d2797a1eff55076d4f499cdee4a9643c442211
parentae45eba904bd5fd1008e19630eaf1d384c597545 (diff)
minor improvements and preparing for struct arguments
-rw-r--r--cgen.c12
-rw-r--r--copy.c41
-rw-r--r--decls_cgen.c4
-rw-r--r--eval.c14
-rw-r--r--foreign.c2
-rw-r--r--infer.c27
-rw-r--r--instance_table.c6
-rw-r--r--main.c3
-rw-r--r--parse.c46
-rw-r--r--sdecls_cgen.c2
-rw-r--r--types.c12
-rw-r--r--types.h7
12 files changed, 125 insertions, 51 deletions
diff --git a/cgen.c b/cgen.c
index 7628bd2..5586b6f 100644
--- a/cgen.c
+++ b/cgen.c
@@ -387,10 +387,10 @@ static bool cgen_type_pre(CGenerator *g, Type *t, Location where) {
return false;
case TYPE_STRUCT:
cgen_write(g, "struct ");
- if (t->struc->name) {
- cgen_ident(g, t->struc->name);
- } else if (t->struc->c.id) {
- cgen_ident_id(g, t->struc->c.id);
+ if (t->struc.def->name) {
+ cgen_ident(g, t->struc.def->name);
+ } else if (t->struc.def->c.id) {
+ cgen_ident_id(g, t->struc.def->c.id);
} else {
assert(0);
}
@@ -1832,8 +1832,8 @@ static bool cgen_val_ptr(CGenerator *g, void *v, Type *t, Location where) {
break;
case TYPE_STRUCT:
cgen_write(g, "{");
- arr_foreach(t->struc->fields, Field, f) {
- if (f != t->struc->fields)
+ arr_foreach(t->struc.def->fields, Field, f) {
+ if (f != t->struc.def->fields)
cgen_write(g, ", ");
cgen_val_ptr(g, (char *)v + f->offset, &f->type, where);
}
diff --git a/copy.c b/copy.c
index 0b03257..f9b16ec 100644
--- a/copy.c
+++ b/copy.c
@@ -62,6 +62,7 @@ static void copy_val(Allocator *a, Value *out, Value *in, Type *t) {
} break;
case TYPE_EXPR:
assert(0);
+ break;
}
}
@@ -76,7 +77,7 @@ static void copy_val_full(Copier *c, Value *out, Value *in, Type *t) {
}
-/* works on unresolved and resolved types */
+/* works on unresolved and resolved types (for inference) */
static void copy_type(Copier *c, Type *out, Type *in) {
*out = *in;
switch (in->kind) {
@@ -118,18 +119,34 @@ static void copy_type(Copier *c, Type *out, Type *in) {
out->slice = copy_type_(c, in->slice);
break;
case TYPE_STRUCT: {
- /* FIXME */
- out->struc = allocr_malloc(c->allocr, sizeof *out->struc);
- *out->struc = *in->struc;
- size_t nfields = arr_len(in->struc->fields);
- out->struc->fields = NULL;
+ if (in->flags & TYPE_IS_RESOLVED) {
+ /* we don't actually need to make a copy of the struct for inference */
+ } else {
+ /*
+ it's okay to copy the struct definition here, because before resolving,
+ only one thing can point to a given StructDef
+ */
+ StructType *sout = &out->struc, *sin = &in->struc;
+
+ sout->def = allocr_malloc(c->allocr, sizeof *sout->def);
+ *sout->def = *sin->def;
+ size_t nfields = arr_len(sin->def->fields);
+ sout->def->fields = NULL;
- arr_set_lena(&out->struc->fields, nfields, c->allocr);
- for (size_t i = 0; i < nfields; ++i) {
- Field *fout = &out->struc->fields[i];
- Field *fin = &in->struc->fields[i];
- *fout = *fin;
- copy_type(c, &fout->type, &fin->type);
+ arr_set_lena(&sout->def->fields, nfields, c->allocr);
+ for (size_t i = 0; i < nfields; ++i) {
+ Field *fout = &sout->def->fields[i];
+ Field *fin = &sin->def->fields[i];
+ *fout = *fin;
+ copy_type(c, &fout->type, &fin->type);
+ }
+
+ size_t nargs = arr_len(sin->args);
+ sout->args = NULL;
+ arr_set_lena(&sout->args, nargs, c->allocr);
+ for (size_t i = 0; i < nargs; ++i) {
+ copy_expr(c, &sout->args[i], &sin->args[i]);
+ }
}
} break;
}
diff --git a/decls_cgen.c b/decls_cgen.c
index d18f533..bb72110 100644
--- a/decls_cgen.c
+++ b/decls_cgen.c
@@ -11,7 +11,7 @@ static bool cgen_decls_type(CGenerator *g, Type *type) {
if (!(type->flags & TYPE_IS_RESOLVED)) /* non-instance constant fn parameter type */
return true;
if (type->kind == TYPE_STRUCT) {
- StructDef *sdef = type->struc;
+ StructDef *sdef = type->struc.def;
if (!(sdef->flags & STRUCT_DEF_CGEN_DEFINED)) {
/* generate struct definition */
cgen_write(g, "struct ");
@@ -158,7 +158,7 @@ static bool cgen_decls_decl(CGenerator *g, Declaration *d) {
cgen_write(g, "static ");
if (!cgen_type_pre(g, &d->type, d->where))
return false;
- cgen_write(g, " ");
+ cgen_write(g, " const ");
cgen_ident(g, d->idents[0]);
if (!cgen_type_post(g, &d->type, d->where))
return false;
diff --git a/eval.c b/eval.c
index 865d16e..489b40f 100644
--- a/eval.c
+++ b/eval.c
@@ -94,8 +94,8 @@ static size_t compiler_alignof(Type *t) {
return sizeof(size_t);
case TYPE_STRUCT: {
/* assume the align of a struct is (at most) the greatest align out of its children's */
- eval_struct_find_offsets(t->struc);
- return t->struc->align;
+ eval_struct_find_offsets(t->struc.def);
+ return t->struc.def->align;
}
case TYPE_UNKNOWN:
case TYPE_EXPR:
@@ -123,8 +123,8 @@ static size_t compiler_sizeof(Type *t) {
case TYPE_SLICE:
return sizeof v.slice;
case TYPE_STRUCT: {
- eval_struct_find_offsets(t->struc);
- return t->struc->size;
+ eval_struct_find_offsets(t->struc.def);
+ return t->struc.def->size;
} break;
case TYPE_VOID:
case TYPE_UNKNOWN:
@@ -341,8 +341,8 @@ static void fprint_val_ptr(FILE *f, void *p, Type *t) {
} break;
case TYPE_STRUCT:
fprintf(f, "["); /* TODO: change? when struct initializers are added */
- arr_foreach(t->struc->fields, Field, fi) {
- if (fi != t->struc->fields)
+ arr_foreach(t->struc.def->fields, Field, fi) {
+ if (fi != t->struc.def->fields)
fprintf(f, ", ");
fprint_ident_debug(f, fi->name);
fprintf(f, ": ");
@@ -777,7 +777,7 @@ static bool eval_ptr_to_struct_field(Evaluator *ev, Expression *dot_expr, void *
struct_type = struct_type->ptr;
}
if (struct_type->kind == TYPE_STRUCT) {
- eval_struct_find_offsets(struct_type->struc);
+ eval_struct_find_offsets(struct_type->struc.def);
Value struc;
if (!eval_expr(ev, dot_expr->binary.lhs, &struc))
diff --git a/foreign.c b/foreign.c
index 2c1e54a..f91d4d7 100644
--- a/foreign.c
+++ b/foreign.c
@@ -146,7 +146,7 @@ static bool arg_list_start(av_alist *arg_list, void (*fn)(), Value *return_val,
break;
case TYPE_STRUCT: {
size_t struct_size = compiler_sizeof(return_type);
- StructDef *struc = return_type->struc;
+ StructDef *struc = return_type->struc.def;
return_val->struc = err_calloc(1, struct_size);
bool splittable;
/* hopefully this is right! */
diff --git a/infer.c b/infer.c
index 2a47865..b0b5433 100644
--- a/infer.c
+++ b/infer.c
@@ -2,6 +2,7 @@ static bool call_arg_param_order(Allocator *allocr, FnExpr *fn, Type *fn_type, A
static bool types_expr(Typer *tr, Expression *e);
/* resolved_to should have the same value as to, but not consist of any identifiers which aren't in scope right now */
+/* TODO: is resolved_to necessary? */
static bool infer_from_expr(Typer *tr, Expression *match, Expression *to, Expression *resolved_to, Identifier *idents, Value *vals, Type *types) {
assert(!(match->flags & EXPR_FOUND_TYPE));
assert(to->flags & EXPR_FOUND_TYPE);
@@ -78,7 +79,7 @@ static bool infer_from_expr(Typer *tr, Expression *match, Expression *to, Expres
/* if match is not the same kind of type as to, returns true */
static bool infer_from_type(Typer *tr, Type *match, Type *to, Identifier *idents, Value *vals, Type *types) {
assert(to->flags & TYPE_IS_RESOLVED);
-
+ assert(!(match->flags & TYPE_IS_RESOLVED));
switch (match->kind) {
case TYPE_VOID:
case TYPE_UNKNOWN:
@@ -118,14 +119,34 @@ static bool infer_from_type(Typer *tr, Type *match, Type *to, Identifier *idents
break;
case TYPE_STRUCT: {
if (to->kind != TYPE_STRUCT) return true;
- Field *fields_m = match->struc->fields;
- Field *fields_t = to->struc->fields;
+ Field *fields_m = match->struc.def->fields;
+ Field *fields_t = to->struc.def->fields;
size_t i, len = arr_len(fields_m);
if (len != arr_len(fields_t)) return true;
for (i = 0; i < len; ++i) {
if (!infer_from_type(tr, &fields_m[i].type, &fields_t[i].type, idents, vals, types))
return false;
}
+ size_t nargs = arr_len(match->struc.args);
+ Declaration *param = to->struc.def->params;
+ int ident_idx = 0;
+ for (i = 0; i < nargs; ++i) {
+ Expression *arg = &match->struc.args[i];
+ Value val = *decl_val_at_index(param, ident_idx);
+ Expression val_expr = {0};
+ val_expr.kind = EXPR_VAL;
+ val_expr.val = val;
+ val_expr.type = *decl_type_at_index(param, ident_idx);
+ val_expr.flags = EXPR_FOUND_TYPE;
+ if (!infer_from_expr(tr, arg, &val_expr, &val_expr, idents, vals, types)) {
+ return false;
+ }
+ ++ident_idx;
+ if (ident_idx >= (int)arr_len(param->idents)) {
+ ++param;
+ ident_idx = 0;
+ }
+ }
} break;
case TYPE_EXPR: {
Expression *to_expr = to->was_expr;
diff --git a/instance_table.c b/instance_table.c
index 0f8948a..85a2abc 100644
--- a/instance_table.c
+++ b/instance_table.c
@@ -109,7 +109,7 @@ static U64 type_hash(Type *t) {
hash += type_hash(t->slice) * 0x67a571620f9a5d6a + 0xc3f91e92c844ab1f;
return hash;
case TYPE_STRUCT:
- hash += (U64)t->struc;
+ hash += (U64)t->struc.def;
return hash;
case TYPE_ARR:
hash += type_hash(t->arr.of) * 0x3b6256104800a414 + 0xa901e68bbd8968a1
@@ -183,7 +183,7 @@ static U64 val_ptr_hash(void *v, Type *t) {
case TYPE_STRUCT: {
U32 x = 1;
U64 hash = 0;
- arr_foreach(t->struc->fields, Field, f) {
+ arr_foreach(t->struc.def->fields, Field, f) {
hash += (U64)x * val_ptr_hash((char *)v + f->offset, &f->type);
x = rand_u32(x);
}
@@ -265,7 +265,7 @@ static bool val_ptr_eq(void *u, void *v, Type *t) {
return true;
}
case TYPE_STRUCT:
- arr_foreach(t->struc->fields, Field, f) {
+ arr_foreach(t->struc.def->fields, Field, f) {
if (!val_ptr_eq((char *)u + f->offset, (char *)v + f->offset, &f->type))
return false;
}
diff --git a/main.c b/main.c
index 80e1db1..6987aa0 100644
--- a/main.c
+++ b/main.c
@@ -19,7 +19,8 @@
/*
TODO:
struct parameters
-fix struct copying
+- make sure you test inference
+see infer.c "is resolved_to necessary" (now that ident system has changed)
replace is_reference in type_resolve_ with system for checking if type is
circularly dependent in a bad way, with compiler_sizeof
foo, _ := bar();
diff --git a/parse.c b/parse.c
index b03a213..3e5b363 100644
--- a/parse.c
+++ b/parse.c
@@ -184,6 +184,7 @@ static Keyword builtin_type_to_kw(BuiltinType t) {
/* returns the number of characters written, not including the null character */
static size_t type_to_str_(Type *t, char *buffer, size_t bufsize) {
+ bool resolved = (t->flags & TYPE_IS_RESOLVED) != 0;
switch (t->kind) {
case TYPE_VOID:
return str_copy(buffer, bufsize, "void");
@@ -223,18 +224,44 @@ static size_t type_to_str_(Type *t, char *buffer, size_t bufsize) {
return written;
}
case TYPE_STRUCT: {
- if (t->struc->name) {
- char *namestr = ident_to_str(t->struc->name);
- size_t bytes = str_copy(buffer, bufsize, namestr);
+ size_t written = 0;
+ StructDef *def = t->struc.def;
+ Identifier name = def->name;
+ if (name) {
+ char *namestr = ident_to_str(name);
+ written = str_copy(buffer, bufsize, namestr);
free(namestr);
- return bytes;
+ } else {
+ written = str_copy(buffer, bufsize, "anonymous struct");
}
- return str_copy(buffer, bufsize, "anonymous struct");
-
+ if (resolved) {
+ if (t->struc.args) {
+ written += str_copy(buffer + written, bufsize - written, "(");
+ arr_foreach(t->struc.args, Expression, arg) {
+ /* TODO: print arguments, maybe, but do we even ever call this (for non-debugging purposes) with an unresolved type? */
+ if (arg != t->struc.args)
+ written += str_copy(buffer + written, bufsize - written, ", ");
+ written += str_copy(buffer + written, bufsize - written, "<argument>");
+ }
+ written += str_copy(buffer + written, bufsize - written, ")");
+ }
+ } else {
+ if (def->params) {
+ written += str_copy(buffer + written, bufsize - written, "(");
+ arr_foreach(def->params, Declaration, param) {
+ /* TODO: val to str */
+ if (param != def->params)
+ written += str_copy(buffer + written, bufsize - written, ", ");
+ written += str_copy(buffer + written, bufsize - written, "<argument>");
+ }
+ written += str_copy(buffer + written, bufsize - written, ")");
+ }
+ }
+ return written;
}
case TYPE_ARR: {
size_t written = str_copy(buffer, bufsize, "[");
- if (t->flags & TYPE_IS_RESOLVED) {
+ if (resolved) {
snprintf(buffer + written, bufsize - written, U64_FMT, t->arr.n);
written += strlen(buffer + written);
} else {
@@ -574,7 +601,8 @@ static bool parse_type(Parser *p, Type *type) {
case KW_STRUCT: {
/* struct */
type->kind = TYPE_STRUCT;
- StructDef *struc = type->struc = parser_malloc(p, sizeof *type->struc);
+ type->struc.args = NULL;
+ StructDef *struc = type->struc.def = parser_malloc(p, sizeof *type->struc.def);
struc->flags = 0;
struc->name = NULL;
/* help cgen out */
@@ -612,7 +640,7 @@ static bool parse_type(Parser *p, Type *type) {
long idx = 0;
arr_foreach(field_decl.idents, Identifier, fident) {
Type *ftype = field_decl.type.kind == TYPE_TUPLE ? &field_decl.type.tuple[idx] : &field_decl.type;
- Field *f = parser_arr_add(p, &type->struc->fields);
+ Field *f = parser_arr_add(p, &struc->fields);
f->name = *fident;
f->type = *ftype;
++idx;
diff --git a/sdecls_cgen.c b/sdecls_cgen.c
index 83c978e..e84b459 100644
--- a/sdecls_cgen.c
+++ b/sdecls_cgen.c
@@ -13,7 +13,7 @@ static bool cgen_sdecls_type(CGenerator *g, Type *type) {
if (!(type->flags & TYPE_IS_RESOLVED)) /* non-instance constant fn parameter type */
return true;
if (type->kind == TYPE_STRUCT) {
- StructDef *sdef = type->struc;
+ StructDef *sdef = type->struc.def;
/* we'll actually define the struct later; here we can just declare it */
if (sdef->flags & STRUCT_DEF_CGEN_DECLARED) {
diff --git a/types.c b/types.c
index bf03f88..56411b6 100644
--- a/types.c
+++ b/types.c
@@ -59,7 +59,8 @@ static bool type_eq(Type *a, Type *b) {
case TYPE_UNKNOWN: assert(0); return false;
case TYPE_BUILTIN:
return a->builtin == b->builtin;
- case TYPE_STRUCT: return a->struc == b->struc;
+ case TYPE_STRUCT:
+ return a->struc.def == b->struc.def;
case TYPE_FN: {
if (arr_len(a->fn.types) != arr_len(b->fn.types)) return false;
Type *a_types = a->fn.types, *b_types = b->fn.types;
@@ -571,7 +572,8 @@ static bool type_resolve_(Typer *tr, Type *t, Location where, bool is_reference)
return false;
break;
case TYPE_STRUCT:
- arr_foreach(t->struc->fields, Field, f) {
+ /* TODO: lookup args! */
+ arr_foreach(t->struc.def->fields, Field, f) {
if (!type_resolve_(tr, &f->type, where, is_reference))
return false;
}
@@ -2032,7 +2034,7 @@ static bool types_expr(Typer *tr, Expression *e) {
e->binary.op = BINARY_DOT;
bool is_field = false;
if (!eval_expr(tr->evalr, rhs, &field_name)) return false;
- arr_foreach(lhs_type->struc->fields, Field, f) {
+ arr_foreach(lhs_type->struc.def->fields, Field, f) {
if (ident_eq_str(f->name, field_name.slice.data)) {
is_field = true;
*t = f->type;
@@ -2095,7 +2097,7 @@ static bool types_expr(Typer *tr, Expression *e) {
}
if (struct_type->kind == TYPE_STRUCT) {
bool is_field = false;
- arr_foreach(struct_type->struc->fields, Field, f) {
+ arr_foreach(struct_type->struc.def->fields, Field, f) {
if (ident_eq(f->name, rhs->ident)) {
is_field = true;
*t = f->type;
@@ -2265,7 +2267,7 @@ static bool types_decl(Typer *tr, Declaration *d) {
if ((d->flags & DECL_HAS_EXPR)
&& d->expr.kind == EXPR_TYPE
&& d->expr.typeval.kind == TYPE_STRUCT) {
- d->expr.typeval.struc->name = d->idents[0];
+ d->expr.typeval.struc.def->name = d->idents[0];
}
if (d->flags & DECL_INFER) {
diff --git a/types.h b/types.h
index 9f85f0b..6ece6b1 100644
--- a/types.h
+++ b/types.h
@@ -417,6 +417,10 @@ enum {
TYPE_IS_RESOLVED = 0x02,
};
typedef U8 TypeFlags;
+typedef struct {
+ struct StructDef *def; /* it's a pointer so that multiple Types can reference the same struct definition */
+ struct Expression *args; /* only exists before resolving */
+} StructType;
typedef struct Type {
Location where;
struct Expression *was_expr; /* if non-NULL, indicates that this type used to be an expression (TYPE_EXPR) */
@@ -435,7 +439,7 @@ typedef struct Type {
} arr;
struct Type *ptr;
struct Type *slice;
- struct StructDef *struc; /* it's a pointer so that multiple Types can reference the same struct definition */
+ StructType struc;
struct Expression *expr;
};
} Type;
@@ -461,6 +465,7 @@ typedef struct StructDef {
size_t size; /* size of this struct during compile time */
size_t align;
Identifier name;
+ struct Declaration *params;
struct {
/* if name is NULL, use this */
IdentID id;