From 41ba175c4bcfac35bf55d569a3d06198465ae33e Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Fri, 14 Feb 2020 12:14:53 -0500 Subject: minor improvements and preparing for struct arguments --- cgen.c | 12 ++++++------ copy.c | 41 +++++++++++++++++++++++++++++------------ decls_cgen.c | 4 ++-- eval.c | 14 +++++++------- foreign.c | 2 +- infer.c | 27 ++++++++++++++++++++++++--- instance_table.c | 6 +++--- main.c | 3 ++- parse.c | 46 +++++++++++++++++++++++++++++++++++++--------- sdecls_cgen.c | 2 +- types.c | 12 +++++++----- types.h | 7 ++++++- 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, ""); + } + 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, ""); + } + 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; -- cgit v1.2.3