diff options
-rw-r--r-- | cgen.c | 4 | ||||
-rw-r--r-- | copy.c | 32 | ||||
-rw-r--r-- | decls_cgen.c | 4 | ||||
-rw-r--r-- | err.c | 22 | ||||
-rw-r--r-- | eval.c | 2 | ||||
-rw-r--r-- | foreign.c | 2 | ||||
-rw-r--r-- | infer.c | 15 | ||||
-rw-r--r-- | instance_table.c | 4 | ||||
-rw-r--r-- | main.c | 5 | ||||
-rw-r--r-- | parse.c | 54 | ||||
-rwxr-xr-x | test-build.sh | 1 | ||||
-rw-r--r-- | test.toc | 75 | ||||
-rw-r--r-- | types.c | 106 | ||||
-rw-r--r-- | types.h | 18 |
14 files changed, 148 insertions, 196 deletions
@@ -295,7 +295,7 @@ static void cgen_struct_name(CGenerator *g, StructDef *sdef) { } if (sdef->instance_id) { possibly_static_assert(sizeof sdef->instance_id == 8); - cgen_write(g, U64_FMT, sdef->instance_id); + cgen_write(g, U64_FMT "_", sdef->instance_id); } } @@ -515,7 +515,7 @@ static void cgen_val_ptr(CGenerator *g, void *v, Type *t) { arr_foreach(t->struc->fields, Field, f) { if (f != t->struc->fields) cgen_write(g, ", "); - cgen_val_ptr(g, (char *)v + f->offset, &f->type); + cgen_val_ptr(g, (char *)v + f->offset, f->type); } cgen_write(g, "}"); break; @@ -90,22 +90,30 @@ 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; - out->scope = in->scope; idents_create(&out->scope.idents, c->allocr, &out->scope); Block *prev = c->block; copy_block(c, &out->scope, &in->scope, 0); c->block = &out->scope; + if (in->flags & STRUCT_DEF_RESOLVED) { + 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); + 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; + fout->type = copy_type_(c, fin->type); + } + out->constants = NULL; + size_t nconstants = arr_len(in->constants); + arr_set_lena(&out->constants, nconstants, c->allocr); + for (size_t i = 0; i < nconstants; ++i) { + copy_decl(c, out->constants[i] = allocr_malloc(c->allocr, sizeof *out->constants[i]), + in->constants[i]); + } } size_t nparams = arr_len(in->params); out->params = NULL; @@ -113,12 +121,6 @@ static void copy_struct(Copier *c, StructDef *out, StructDef *in) { for (size_t i = 0; i < nparams; ++i) { copy_decl(c, &out->params[i], &in->params[i]); } - out->constants = NULL; - size_t nconstants = arr_len(in->constants); - arr_set_lena(&out->constants, nconstants, c->allocr); - for (size_t i = 0; i < nconstants; ++i) { - copy_decl(c, &out->constants[i], &in->constants[i]); - } c->block = prev; } diff --git a/decls_cgen.c b/decls_cgen.c index 048dd9d..967294f 100644 --- a/decls_cgen.c +++ b/decls_cgen.c @@ -182,10 +182,10 @@ static void cgen_decls_type(CGenerator *g, Type *type) { cgen_nl(g); ++g->indent_lvl; arr_foreach(sdef->fields, Field, f) { - cgen_type_pre(g, &f->type); + cgen_type_pre(g, f->type); cgen_write(g, " "); cgen_ident_simple(g, f->name); - cgen_type_post(g, &f->type); + cgen_type_post(g, f->type); cgen_write(g, ";"); cgen_nl(g); } @@ -79,16 +79,7 @@ static void print_location_highlight(FILE *out, Location where) { /* for debugging */ static void fprint_location(FILE *out, Location location) { - if (location.start) { - fprintf(out, "Line %ld of %s: ", (long)location.start->pos.line, location.file->filename); - } else { - U32 line = location.simple_location.line; - if (line) - fprintf(out, "Line %lu of %s: ", (unsigned long)line, location.file->filename); - else - fprintf(out, "In file %s: ", location.file->filename); - return; - } + fprintf(out, "Line %ld of %s: ", (long)location.start->pos.line, location.file->filename); print_location_highlight(out, location); } @@ -151,16 +142,7 @@ static void err_vfprint(ErrCtx *ctx, const char *fmt, va_list args) { static void err_print_line_file(Location where) { ErrCtx *ctx = where.file->ctx; - if (where.start) { - err_fprint(ctx, " at line %lu of %s:\n", (unsigned long)where.start->pos.line, where.file->filename); - } else { - U32 line = where.simple_location.line; - if (line) - err_fprint(ctx, " at line %lu of %s:\n", (unsigned long)line, where.file->filename); - else - err_fprint(ctx, ":\n"); - } - + err_fprint(ctx, " at line %lu of %s:\n", (unsigned long)where.start->pos.line, where.file->filename); } static void err_print_header_(Location where) { @@ -245,7 +245,7 @@ static void fprint_val_ptr(FILE *f, void *p, Type *t) { fprintf(f, ", "); fprint_ident_debug(f, fi->name); fprintf(f, ": "); - fprint_val_ptr(f, (char *)p + fi->offset, &fi->type); + fprint_val_ptr(f, (char *)p + fi->offset, fi->type); } fprintf(f, "]"); break; @@ -176,7 +176,7 @@ static bool arg_list_start(av_alist *arg_list, void (*fn)(), Value *return_val, splittable = true; size_t word_size = sizeof(__avword); arr_foreach(struc->fields, Field, f) { - if (f->offset / word_size != (f->offset + compiler_sizeof(&f->type) - 1) / word_size) { + if (f->offset / word_size != (f->offset + compiler_sizeof(f->type) - 1) / word_size) { splittable = false; break; } @@ -197,17 +197,10 @@ static bool infer_from_type(Typer *tr, Type *match, Type *to, Identifier *idents if (!infer_from_type(tr, match->slice, to->slice, idents, vals, types, where)) return false; break; - case TYPE_STRUCT: { - if (to->kind != TYPE_STRUCT) return true; - Field *fields_m = match->struc->fields; - Field *fields_t = to->struc->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, where)) - return false; - } - } break; + case TYPE_STRUCT: + /* this would be difficult because match could contain #ifs and + no sane person will ever write something that needs this */ + break; case TYPE_EXPR: { Expression *to_expr = to->was_expr; Expression e = {0}; diff --git a/instance_table.c b/instance_table.c index d1533cd..125c2cf 100644 --- a/instance_table.c +++ b/instance_table.c @@ -192,7 +192,7 @@ static U64 val_ptr_hash(void *v, Type *t) { U32 x = 1; U64 hash = 0; arr_foreach(t->struc->fields, Field, f) { - hash += (U64)x * val_ptr_hash((char *)v + f->offset, &f->type); + hash += (U64)x * val_ptr_hash((char *)v + f->offset, f->type); x = rand_u32(x); } return hash; @@ -287,7 +287,7 @@ static bool val_ptr_eq(void *u, void *v, Type *t) { } case TYPE_STRUCT: arr_foreach(t->struc->fields, Field, f) { - if (!val_ptr_eq((char *)u + f->offset, (char *)v + f->offset, &f->type)) + if (!val_ptr_eq((char *)u + f->offset, (char *)v + f->offset, f->type)) return false; } return true; @@ -8,10 +8,8 @@ /* TODO: -allow #ifs in structs - - you can just have a dyn array of stmts and when you want to resolve the struct, - just type the statements, then loop over them (going into blocks if necessary) use + - use with a decl, e.g. use p : Point; &&, || start making a standard library... (printf; stringbuilder would be nice to have) switch @@ -81,6 +79,7 @@ int main(int argc, char **argv) { signal(SIGSEGV, signal_handler); #endif #ifdef RUN_TESTS + printf("running tests...\n"); test_all(); #endif @@ -14,6 +14,10 @@ enum { }; static Status parse_decl(Parser *p, Declaration *d, DeclEndKind ends_with, U16 flags); static Status parse_decl_list(Parser *p, Declaration **decls, DeclEndKind decl_end); +enum { + PARSE_BLOCK_DONT_CREATE_IDENTS = 0x01 +}; +static bool parse_block(Parser *p, Block *b, U8 flags); static bool is_decl(Tokenizer *t); static inline bool ends_decl(Token *t, DeclEndKind ends_with); @@ -574,9 +578,7 @@ static Status parse_type(Parser *p, Type *type, Location *where) { struc->name = NULL; /* help cgen out */ struc->c.id = 0; - struc->fields = NULL; struc->params = NULL; - struc->constants = NULL; struc->where = parser_mk_loc(p); struc->where.start = t->token; memset(&struc->scope, 0, sizeof struc->scope); @@ -615,48 +617,11 @@ static Status parse_type(Parser *p, Type *type, Location *where) { param->flags |= DECL_IS_PARAM; } } - if (!token_is_kw(t->token, KW_LBRACE)) { - tokr_err(t, "Expected { to follow struct."); - 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, PARSE_DECL_DONT_SET_IDECLS)) { - goto struct_fail; - } - if (field_decl.flags & DECL_IS_CONST) { - Declaration *d = parser_arr_add(p, &struc->constants); - *d = field_decl; - } else { - if (field_decl.flags & DECL_HAS_EXPR) { - err_print(field_decl.where, "struct members cannot have initializers."); - goto struct_fail; - } - 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, &struc->fields); - f->name = *fident; - f->where = field_decl.where; - f->type = *ftype; - ++idx; - } - } - } - arr_foreach(struc->constants, Declaration, c) { - arr_foreach(c->idents, Identifier, ip) { - Identifier i = *ip; - i->decl = c; - i->decl_kind = IDECL_DECL; - } - } - ++t->token; - struc->where.end = t->token; - } - struc->scope.where = struc->where; + p->block = prev_block; + if (!parse_block(p, &struc->scope, PARSE_BLOCK_DONT_CREATE_IDENTS)) + return false; + struc->where = struc->scope.where; break; struct_fail: @@ -819,9 +784,6 @@ static bool parser_is_definitely_type(Parser *p, Token **end) { return ret; } -enum { - PARSE_BLOCK_DONT_CREATE_IDENTS = 0x01 -}; static Status parse_block(Parser *p, Block *b, U8 flags) { Tokenizer *t = p->tokr; Block *prev_block = p->block; diff --git a/test-build.sh b/test-build.sh index 370e329..263c657 100755 --- a/test-build.sh +++ b/test-build.sh @@ -4,5 +4,6 @@ for CC in tcc gcc clang g++ ; do CC="$CC" CFLAGS='-Werror' ./build.sh || exit 1 CC="$CC" CFLAGS='-Werror' ./build.sh release || exit 1 done +CC='' CFLAGS='-Werror' ./build.sh release || exit 1 CFLAGS='-Werror' ./build.sh || exit 1 @@ -1,65 +1,24 @@ #include "std/io.toc", io; -plusone ::= fn(n : int) x := n { - defer x += 1; -} - -same ::= fn(n : int) int { - x := n; - defer x += 1; - x -} - -thing1 ::= fn() (int, int) { - x := 5; - y := 6; - defer x += 1; - x, y -} -thing2 ::= fn() x := 5, y := 6 { - defer x += 1; +s ::= struct (t :: Type, hasz ::= true) { + x, y: t; + #if hasz { + z: t; + a :: t = 3 as t; + } } main ::= fn() { - io.puti(plusone(3)); - io.puti(same(3)); - a, b := thing1(); - c, d := thing2(); - io.puti(a); - io.puti(b); - io.puti(c); - io.puti(d); - defer io.puts("deferred from main()"); - for i := 1..10 { - defer io.puts("deferred from for"); - io.puti(i); - if i == 2 { - defer io.puts("deferred from if1"); - defer io.puts("deferred from if2"); - defer io.puts("deferred from if3"); - defer io.puts("deferred from if4"); - defer io.puts("deferred from if5"); - defer io.puts("deferred from if6"); - defer io.puts("deferred from if7"); - defer io.puts("deferred from if8"); - continue; - } - if i == 8 { - break; - } - } - i := 0; - while { - defer io.puts("deferred from while"); - i += 1; - io.puti(i); - if i % 2 == 0 { continue; } - if i == 7 { - defer io.puts("deferred from if"); - break; - } - - } - io.puts("end of main()"); + p: s(float); + p.x = 7; + p.y = 13; + p.z = 12; + io.puti(p.x as int); + io.puti(s(int).a as int); + q: s(int, false); + q.x = 13; + io.puti(q.x); + //io.puti(q.a); } + @@ -85,12 +85,12 @@ static Status struct_find_offsets(StructDef *s) { size_t bytes = 0; size_t total_align = 1; arr_foreach(s->fields, Field, f) { - size_t size = compiler_sizeof(&f->type); + size_t size = compiler_sizeof(f->type); if (size == SIZE_MAX) { info_print(f->where, "... while descending into this field of a struct."); return false; } - size_t falign = compiler_alignof(&f->type); + size_t falign = compiler_alignof(f->type); if (falign > total_align) total_align = falign; /* align */ @@ -648,7 +648,6 @@ static Status type_of_ident(Typer *tr, Location where, Identifier *ident, Type * } /* are we inside this declaration? */ - typedef Declaration *DeclarationPtr; arr_foreach(tr->in_decls, DeclarationPtr, in_decl) { if (d == *in_decl) { /* d needn't have an expression, because it could be its type that refers to itself */ @@ -728,6 +727,68 @@ static Status type_of_ident(Typer *tr, Location where, Identifier *ident, Type * } return true; } +static Status add_block_to_struct(Typer *tr, Block *b, StructDef *s) { + arr_foreach(b->stmts, Statement, stmt) { + if (stmt->kind == STMT_EXPR) { + if (stmt->expr.kind == EXPR_BLOCK) { + if (!add_block_to_struct(tr, stmt->expr.block, s)) + return false; + continue; + } + } + if (stmt->kind != STMT_DECL) { + err_print(stmt->where, "structs can only contain declarations."); + return false; + } + Declaration *d = stmt->decl; + DeclFlags flags = d->flags; + if (flags & DECL_EXPORT) { + err_print(d->where, "struct members can't be exported."); + return false; + } + if (flags & DECL_IS_CONST) { + if (flags & DECL_INFER) { + err_print(d->where, "struct members can't be inferred."); + return false; + } + *(Declaration **)typer_arr_add(tr, &s->constants) = d; + } else { + if (flags & DECL_SEMI_CONST) { + err_print(d->where, "struct members can't be semi-constant."); + return false; + } + if (flags & DECL_HAS_EXPR) { + err_print(d->where, "Non-constant struct members can't have initializers."); + return false; + } + int i = 0; + arr_foreach(d->idents, Identifier, ident) { + Field *field = typer_arr_add(tr, &s->fields); + field->where = d->where; + field->name = *ident; + field->type = decl_type_at_index(d, i); + ++i; + } + } + if (b != &s->scope) { + /* we need to translate d's identifiers to s's scope */ + arr_foreach(d->idents, Identifier, ip) { + Identifier redeclared = ident_get(&s->scope.idents, (*ip)->str); + if (redeclared && redeclared->decl_kind != IDECL_NONE) { + char *str = ident_to_str(*ip); + err_print(d->where, "Redeclaration of struct member %s", str); + info_print(ident_decl_location(d->where.file, redeclared), "Previous declaration was here."); + free(str); + return false; + } + *ip = ident_translate_forced(*ip, &s->scope.idents); + (*ip)->decl_kind = IDECL_DECL; + (*ip)->decl = d; + } + } + } + return true; +} /* fixes the type (replaces [5+3]int with [8]int, etc.) */ static Status type_resolve(Typer *tr, Type *t, Location where) { @@ -789,24 +850,17 @@ static Status type_resolve(Typer *tr, Type *t, Location where) { return false; break; 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)) { - typer_block_exit(tr); - return false; - } - } - arr_foreach(t->struc->constants, Declaration, c) { - if (!types_decl(tr, c)) { - typer_block_exit(tr); - return false; - } - } - typer_block_exit(tr); - assert(tr->block != &t->struc->scope); - t->struc->instance_id = 0; - t->struc->flags |= STRUCT_DEF_RESOLVED; + StructDef *s = t->struc; + if (!(s->flags & STRUCT_DEF_RESOLVED)) { + if (!types_block(tr, &s->scope)) + return false; + s->fields = NULL; + s->constants = NULL; + if (!add_block_to_struct(tr, &s->scope, s)) + return false; + + s->instance_id = 0; + s->flags |= STRUCT_DEF_RESOLVED; } } break; case TYPE_EXPR: { @@ -1422,7 +1476,11 @@ static void get_builtin_val_type(Allocator *a, BuiltinVal val, Type *t) { /* gets a struct's constant or parameter, and puts it into e->val. */ -static Status get_struct_constant(StructDef *struc, Identifier member, Expression *e) { +static Status get_struct_constant(StructDef *struc, Identifier member, Expression *e) { + if (struc->params && !(struc->params[0].flags & DECL_FOUND_VAL)) { + err_print(e->where, "To access constants from a parameterized struct, you must supply its arguments."); + return false; + } Identifier i = ident_translate(member, &struc->scope.idents); if (!i || i->decl_kind == IDECL_NONE) { char *member_s = ident_to_str(member); @@ -2785,7 +2843,7 @@ static Status types_expr(Typer *tr, Expression *e) { arr_foreach(lhs_type->struc->fields, Field, f) { if (ident_eq_str(f->name, field_name.slice.data)) { is_field = true; - *t = f->type; + *t = *f->type; e->binary.dot.field = f; } } @@ -2898,7 +2956,7 @@ static Status types_expr(Typer *tr, Expression *e) { arr_foreach(struct_type->struc->fields, Field, f) { if (ident_eq(f->name, rhs->ident)) { is_field = true; - *t = f->type; + *t = *f->type; e->binary.dot.field = f; } } @@ -200,7 +200,6 @@ typedef struct IdentSlot { }; struct Identifiers *idents; struct Namespace *nms; /* only exists after typing, and only for namespace-level declarations (i.e. not local variables) */ - SOURCE_LOCATION } IdentSlot; typedef struct StrHashTableSlot { @@ -386,14 +385,8 @@ typedef struct { typedef struct Location { File *file; - /* if start is NULL, simple_location will be used. */ Token *start; - union { - Token *end; /* Exclusive */ - struct { - U32 line; /* if 0, this is a null location */ - } simple_location; - }; + Token *end; /* Exclusive */ } Location; @@ -486,7 +479,7 @@ typedef struct Type { typedef struct Field { Location where; Identifier name; - Type type; + Type *type; size_t offset; /* offset during compile time */ } Field; @@ -520,11 +513,13 @@ enum { STRUCT_DEF_RESOLVED = 0x10 }; typedef struct StructDef { + /* these two only exist after resolving (before then, it's scope.stmts) */ Field *fields; - struct Declaration *constants; + struct Declaration **constants; + Location where; U8 flags; - Block scope; /* to make sure that parameters and constants live somewhere. fields are not kept here. */ + Block scope; /* parameters and constants live here. statements aren't used after resolving (but are kept around because why not) */ union { HashTable instances; struct { @@ -908,6 +903,7 @@ typedef struct Declaration { /* OPTIM: some block array of values somewhere which we can just use a pointer to, which is freed when the block is exited? */ Value **val_stack; } Declaration; +typedef Declaration *DeclarationPtr; typedef enum { STMT_DECL, |