diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2020-02-19 11:13:17 -0500 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2020-02-19 11:13:17 -0500 |
commit | 9bb0fab71acd8c730fff396bd93154f916ba397b (patch) | |
tree | 7910460de8e35fc322505178db3870ecce07fc62 | |
parent | dc2445ffcf7e88fd33bbf8d878c0812ec2732ccf (diff) |
struct parameters seem to be working
-rw-r--r-- | cgen.c | 23 | ||||
-rw-r--r-- | copy.c | 31 | ||||
-rw-r--r-- | decls_cgen.c | 7 | ||||
-rw-r--r-- | instance_table.c | 1 | ||||
-rw-r--r-- | parse.c | 29 | ||||
-rw-r--r-- | sdecls_cgen.c | 11 | ||||
-rw-r--r-- | test.toc | 15 | ||||
-rw-r--r-- | types.c | 82 | ||||
-rw-r--r-- | types.h | 57 |
9 files changed, 169 insertions, 87 deletions
@@ -338,6 +338,19 @@ static bool cgen_uses_ptr(Type *t) { return false; } +static void cgen_struct_name(CGenerator *g, StructDef *sdef) { + if (sdef->name) { + cgen_ident(g, sdef->name); + } else { + assert(sdef->c.id); + cgen_ident_id(g, sdef->c.id); + } + if (sdef->instance_id) { + possibly_static_assert(sizeof sdef->instance_id == 8); + cgen_write(g, U64_FMT, sdef->instance_id); + } +} + static bool cgen_type_pre(CGenerator *g, Type *t, Location where) { assert(t->flags & TYPE_IS_RESOLVED); switch (t->kind) { @@ -387,13 +400,7 @@ 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); - } else { - assert(0); - } + cgen_struct_name(g, t->struc); break; case TYPE_TUPLE: case TYPE_EXPR: @@ -1591,7 +1598,7 @@ static bool cgen_expr(CGenerator *g, Expression *e) { case BUILTIN_SIZEOF_SIZE_T: case BUILTIN_TSIZEOF_SIZE_T: { Value val = get_builtin_val(e->builtin.which.val); - cgen_write(g, "%"I64_FMT, val.i64); + cgen_write(g, I64_FMT, val.i64); } break; } break; @@ -76,6 +76,25 @@ static void copy_val_full(Copier *c, Value *out, Value *in, Type *t) { } } +static void copy_struct(Copier *c, StructDef *out, StructDef *in) { + *out = *in; + size_t nfields = arr_len(in->fields); + out->fields = NULL; + + arr_set_lena(&out->fields, nfields, c->allocr); + for (size_t i = 0; i < nfields; ++i) { + Field *fout = &out->fields[i]; + Field *fin = &in->fields[i]; + *fout = *fin; + copy_type(c, &fout->type, &fin->type); + } + size_t nparams = arr_len(in->params); + out->params = NULL; + arr_set_lena(&out->params, nparams, c->allocr); + for (size_t i = 0; i < nparams; ++i) { + copy_decl(c, &out->params[i], &in->params[i]); + } +} /* works on unresolved and resolved types (for inference) */ static void copy_type(Copier *c, Type *out, Type *in) { @@ -127,17 +146,7 @@ static void copy_type(Copier *c, Type *out, Type *in) { only one thing can point to a given StructDef */ 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; - - 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); - } + copy_struct(c, out->struc, in->struc); } } break; } diff --git a/decls_cgen.c b/decls_cgen.c index 61c93e8..2c6fc63 100644 --- a/decls_cgen.c +++ b/decls_cgen.c @@ -15,12 +15,7 @@ static bool cgen_decls_type(CGenerator *g, Type *type) { if (!(sdef->flags & STRUCT_DEF_CGEN_DEFINED)) { /* generate struct definition */ cgen_write(g, "struct "); - if (sdef->name) { - cgen_ident(g, sdef->name); - } else { - assert(sdef->c.id); - cgen_ident_id(g, sdef->c.id); - } + cgen_struct_name(g, sdef); cgen_write(g, "{"); cgen_nl(g); ++g->indent_lvl; diff --git a/instance_table.c b/instance_table.c index 0f8948a..58dc635 100644 --- a/instance_table.c +++ b/instance_table.c @@ -283,6 +283,7 @@ static bool val_eq(Value u, Value v, Type *t) { /* if already_exists is not NULL, this will create the instance if it does not exist, and set already_exists accordingly + make sure v's data remains valid */ /* OPTIM: store instances in a block array (remember that the pointers need to stay valid!) */ static Instance *instance_table_adda(Allocator *a, HashTable *h, Value v, Type *t, @@ -599,37 +599,43 @@ static bool parse_type(Parser *p, Type *type) { struc->params = NULL; struc->where = parser_mk_loc(p); struc->where.start = t->token; - + memset(&struc->scope, 0, sizeof struc->scope); + idents_create(&struc->scope.idents, p->allocr, &struc->scope); + memset(&struc->instances, 0, sizeof struc->instances); + + Block *prev_block = p->block; + p->block = &struc->scope; + ++t->token; if (token_is_kw(t->token, KW_LPAREN)) { ++t->token; if (!parse_decl_list(p, &struc->params, DECL_END_RPAREN_COMMA)) - return false; + goto struct_fail; } if (!token_is_kw(t->token, KW_LBRACE)) { tokr_err(t, "Expected { to follow struct."); - return false; + goto struct_fail; } ++t->token; { while (!token_is_kw(t->token, KW_RBRACE)) { Declaration field_decl; if (!parse_decl(p, &field_decl, DECL_END_SEMICOLON, 0)) { - return false; + goto struct_fail; } if (field_decl.flags & DECL_IS_CONST) { /* TODO */ err_print(field_decl.where, "Constant struct members are not supported (yet)."); - return false; + goto struct_fail; } if ((field_decl.flags & DECL_FOREIGN) && !(field_decl.flags & DECL_IS_CONST)) { err_print(field_decl.where, "Non-constant struct members cannot be foreign."); - return false; + goto struct_fail; } if (field_decl.flags & DECL_HAS_EXPR) { err_print(field_decl.where, "struct members cannot have initializers."); - return false; + goto struct_fail; } long idx = 0; arr_foreach(field_decl.idents, Identifier, fident) { @@ -643,7 +649,14 @@ static bool parse_type(Parser *p, Type *type) { ++t->token; struc->where.end = t->token; } - } break; + p->block = prev_block; + break; + + struct_fail: + p->block = prev_block; + return false; + } + default: goto type_expr; } diff --git a/sdecls_cgen.c b/sdecls_cgen.c index 83c978e..a146eb2 100644 --- a/sdecls_cgen.c +++ b/sdecls_cgen.c @@ -20,13 +20,10 @@ static bool cgen_sdecls_type(CGenerator *g, Type *type) { /* we've already done this */ } else { cgen_write(g, "struct "); - if (sdef->name) { - cgen_ident(g, sdef->name); - } else { - IdentID id = ++g->ident_counter; - cgen_ident_id(g, id); - sdef->c.id = id; - } + if (!sdef->name) { + sdef->c.id = ++g->ident_counter; + } + cgen_struct_name(g, sdef); cgen_write(g, ";"); cgen_nl(g); sdef->flags |= STRUCT_DEF_CGEN_DECLARED; @@ -1,11 +1,14 @@ -// io ::= nms { - // #include "std/io.toc"; -// }; +io ::= nms { + #include "std/io.toc"; +}; -foo ::= struct(t::Type,u::Type) { - x: t; +Arr ::= struct(t::Type) { + data: []t; }; main ::= fn() { - foo(u = int, u = float); + x:Arr(int); + x.data = new(int, 10); + x.data[0] = 17; + io.puti(x.data[0]); };
\ No newline at end of file @@ -571,17 +571,20 @@ static bool type_resolve_(Typer *tr, Type *t, Location where, bool is_reference) if (!type_resolve_(tr, t->slice, where, true)) return false; break; - case TYPE_STRUCT: - if (t->struc->params) { - err_print(where, "Expected arguments to structure."); - info_print(t->struc->where, "Structure was declared here."); - return false; - } - arr_foreach(t->struc->fields, Field, f) { - if (!type_resolve_(tr, &f->type, where, is_reference)) - return false; + case TYPE_STRUCT: { + if (!(t->struc->flags & STRUCT_DEF_RESOLVED)) { + typer_block_enter(tr, &t->struc->scope); + arr_foreach(t->struc->fields, Field, f) { + if (!type_resolve_(tr, &f->type, where, is_reference)) { + typer_block_exit(tr); + return false; + } + } + typer_block_exit(tr); + t->struc->instance_id = 0; + t->struc->flags |= STRUCT_DEF_RESOLVED; } - break; + } break; case TYPE_EXPR: { Value typeval; *(bool *)arr_add(&tr->is_reference_stack) = is_reference; @@ -1436,8 +1439,9 @@ static bool types_expr(Typer *tr, Expression *e) { it would be nice if this code and the code for arguments to normal functions used the same stuff for named arguments, etc. */ - Value *arg_vals = err_malloc(nparams * sizeof *arg_vals); - Type *arg_types = err_malloc(nparams * sizeof *arg_types); + Value *arg_vals = typer_malloc(tr, nparams * sizeof *arg_vals); + Type *arg_types = NULL; + arr_set_len(&arg_types, nparams); U8 *params_set = err_calloc(1, nparams); int p = 0; /* sequential parameter */ @@ -1483,13 +1487,54 @@ static bool types_expr(Typer *tr, Expression *e) { for (size_t i = 0; i < nparams; ++i) print_val(arg_vals[i], arg_types + i); - - /* TODO: look up args in instance table, etc. */ - - free(arg_vals); - free(arg_types); + + HashTable *table = &base->struc->instances; + bool already_exists; + Value args_val = {0}; + Type args_type = {0}; + args_val.tuple = arg_vals; + args_type.tuple = arg_types; + args_type.kind = TYPE_TUPLE; + args_type.flags = TYPE_IS_RESOLVED; + Instance *inst = instance_table_adda(tr->allocr, table, args_val, &args_type, &already_exists); + if (!already_exists) { + Copier cop = copier_create(tr->allocr, tr->block); + copy_struct(&cop, &inst->struc, base->struc); + size_t i = 0; + arr_foreach(inst->struc.params, Declaration, param) { + param->flags |= DECL_FOUND_VAL; + if (arr_len(param->idents) == 1) { + param->val = arg_vals[i]; + ++i; + } else { + assert(param->type.kind == TYPE_TUPLE); + size_t nmembers = arr_len(param->type.tuple); + param->val.tuple = typer_malloc(tr, nmembers * sizeof *param->val.tuple); + for (size_t idx = 0; idx < nmembers; ++idx) { + param->val.tuple[idx] = arg_vals[i]; + ++i; + } + } + } + assert(i == nparams); + Type struct_t = {0}; + struct_t.kind = TYPE_STRUCT; + struct_t.struc = &inst->struc; + if (!type_resolve(tr, &struct_t, e->where)) /* resolve the struct */ + return false; + inst->struc.instance_id = table->n; + } + /* expression is actually a type */ + e->kind = EXPR_TYPE; + memset(&e->typeval, 0, sizeof e->typeval); + e->typeval.kind = TYPE_STRUCT; + e->typeval.flags = TYPE_IS_RESOLVED; + e->typeval.struc = &inst->struc; + t->kind = TYPE_BUILTIN; + t->builtin = BUILTIN_TYPE; + arr_clear(&arg_types); free(params_set); - return true; + goto ret; } fn_decl = val.fn; @@ -2308,6 +2353,7 @@ static bool types_expr(Typer *tr, Expression *e) { assert(0); return false; } + ret: t->flags |= TYPE_IS_RESOLVED; return true; } @@ -448,18 +448,41 @@ typedef struct Field { size_t offset; /* offset during compile time */ } Field; + +enum { + BLOCK_IS_FN = 0x01, + BLOCK_IS_NMS = 0x02, + BLOCK_FINDING_TYPES = 0x04, + BLOCK_FOUND_TYPES = 0x08 +}; +typedef U8 BlockFlags; +typedef struct Block { + BlockFlags flags; + Location where; + Identifiers idents; + struct Statement *stmts; + struct Expression *ret_expr; /* the return expression of this block, e.g. {foo(); 3} => 3 NULL for no expression. */ +} Block; + enum { STRUCT_DEF_FOUND_OFFSETS = 0x01, STRUCT_DEF_CGEN_DECLARED = 0x02, - STRUCT_DEF_CGEN_DEFINED = 0x04 + STRUCT_DEF_CGEN_DEFINED = 0x04, + STRUCT_DEF_RESOLVED = 0x08 }; - typedef struct StructDef { Field *fields; Location where; U8 flags; - size_t size; /* size of this struct during compile time */ - size_t align; + Block scope; /* to make sure that parameters live somewhere. fields are not kept here. */ + union { + HashTable instances; + struct { + size_t size; /* size of this struct during compile time */ + size_t align; + U64 instance_id; /* ID of instance */ + }; + }; Identifier name; struct Declaration *params; struct { @@ -469,21 +492,6 @@ typedef struct StructDef { } StructDef; -enum { - BLOCK_IS_FN = 0x01, - BLOCK_IS_NMS = 0x02, - BLOCK_FINDING_TYPES = 0x04, - BLOCK_FOUND_TYPES = 0x08 -}; -typedef U8 BlockFlags; -typedef struct Block { - BlockFlags flags; - Location where; - Identifiers idents; - struct Statement *stmts; - struct Expression *ret_expr; /* the return expression of this block, e.g. {foo(); 3} => 3 NULL for no expression. */ -} Block; - typedef enum { EXPR_LITERAL_FLOAT, EXPR_LITERAL_INT, @@ -628,11 +636,14 @@ typedef struct FnExpr { typedef struct Instance { Value val; /* key into hash table */ - struct { - FnExpr *fn; /* the typed function */ + union { struct { - U64 id; - } c; + FnExpr *fn; /* the typed function */ + struct { + U64 id; + } c; + }; + StructDef struc; }; } Instance; |