diff options
Diffstat (limited to 'bootstrap')
| -rw-r--r-- | bootstrap/all.h | 40 | ||||
| -rw-r--r-- | bootstrap/cgen.c | 78 | ||||
| -rw-r--r-- | bootstrap/dump.c | 2 | ||||
| -rw-r--r-- | bootstrap/fold.c | 13 | ||||
| -rw-r--r-- | bootstrap/parse.c | 217 | ||||
| -rw-r--r-- | bootstrap/test.cff | 36 | ||||
| -rw-r--r-- | bootstrap/types.c | 38 |
7 files changed, 376 insertions, 48 deletions
diff --git a/bootstrap/all.h b/bootstrap/all.h index cb221da..bbe23b3 100644 --- a/bootstrap/all.h +++ b/bootstrap/all.h @@ -136,12 +136,16 @@ enum typetype { TYslice, TYfn, TYenum, + TYstruct, + TYunion, + TYeunion, }; struct type { enum typetype t; size_t size, align; bool konst; + int _id; union { bool int_signed; struct { @@ -156,12 +160,22 @@ struct type { struct { const struct type *intty; const char *name; - slice_t(struct enumfield { + slice_t(struct enumval { const char *name; i64 i; }) vals; int id; } enu; + struct { + const char *name; + slice_t(struct aggfield { + size_t off; + const char *name; + const struct type *ty; + }) flds; + bool fwd; + int id; + } agg; }; // for cgen.c hack (mutated later, not hashed or involved in equality) const char *_cname; @@ -242,6 +256,8 @@ enum exprtype { Eblock, Eas, Eenumval, + Ezeroini, + Eini, }; struct blockstmt { @@ -288,9 +304,20 @@ struct expr { i64 i; const char *vname; } enu; + struct { + slice_t(struct iniarg) args; + } ini; }; }; +struct iniarg { + union { + size_t idx; + const char *fld; + }; + struct expr ex; +}; + enum stmttype { Sblock, Sexpr, @@ -376,6 +403,7 @@ static const struct targ { for (T __old = (var), *__dummy = ((var) = (new), NULL); \ !__dummy; \ __dummy++, (var) = __old) +#define ALIGNUP(x,a) (((x) + ((a) - 1)) & -(a)) static inline u32 bswap32(u32 x) { @@ -393,13 +421,16 @@ bswap64(u64 x) { #define vec_slice_cpy(slice, v) \ ((slice)->d = vec_compact(v), \ (slice)->n = (v)->length) - -#define jkhashv(h, v) jkhash(h, (void *)&(v), sizeof((v))) - +/// ///////////////////////////////// /** util.c **/ u32 jkhash(u32 hash, const u8 *data, size_t length); +#define jkhashv(h, v) jkhash(h, (void *)&(v), sizeof((v))) +static inline u32 +jkhashu32(u32 h, u32 x) { + return jkhashv(h, x); +} int addfilepath(const char *); const char *fileid2path(int); void *xmalloc(size_t); @@ -426,6 +457,7 @@ extern const struct type *ty_c_ullong; void inittypes(void); const struct type *interntype(struct type); +void uninterntype(const struct type *); bool typeeql(const struct type *lhs, const struct type *rhs); bool completetype(const struct type *); void putprimtypes(struct env *); diff --git a/bootstrap/cgen.c b/bootstrap/cgen.c index aac0893..fe937d6 100644 --- a/bootstrap/cgen.c +++ b/bootstrap/cgen.c @@ -28,6 +28,9 @@ gentype(const struct type *ty) { assert(ty->length >= 0); case TYslice: case TYfn: + case TYstruct: + case TYunion: + case TYeunion: assert(ty->_cname); pri("%s", ty->_cname); return; @@ -53,6 +56,7 @@ pristring(const char *s, u64 n) { } static void genexpr(struct expr *expr); +static void geniniex(struct expr *ex); void pri(const char *fmt, ...) { @@ -115,6 +119,9 @@ pri(const char *fmt, ...) { case 'e': genexpr(va_arg(ap, struct expr *)); break; + case 'n': + geniniex(va_arg(ap, struct expr *)); + break; default: fprintf(outfp, "pri(): bad fmt '%%%c'\n", c); abort(); @@ -127,6 +134,25 @@ pri(const char *fmt, ...) { static void genblock(struct blockstmt block); static void +geniniex(struct expr *ex) { + if (ex->t == Ezeroini) + pri("{0}"); + else { + assert(ex->t == Eini); + pri("{ "); + for (int i = 0; i < ex->ini.args.n; ++i) { + struct iniarg *arg = &ex->ini.args.d[i]; + if (ex->ty->t == TYarr) + pri("[%I] = %e, ", arg->idx, arg->ex); + else + pri(".%s = %e, ", arg->fld, arg->ex); + } + + pri("}"); + } +} + +static void genexpr(struct expr *ex) { const struct type *ty = unconstify(ex->ty); switch (ex->t) { @@ -194,6 +220,15 @@ genexpr(struct expr *ex) { ty = ex->ty->enu.intty; goto intlit; break; + case Ezeroini: + if (ty->t == TYarr || ty->t == TYstruct) + pri("((%t){0})", ty); + else + pri("((%t)0)", ty); + break; + case Eini: + pri("((%t)%n)", ty, ex); + break; } } @@ -218,8 +253,16 @@ genstmt(struct stmt *stmt) { switch (decl.t) { case Dlet: pri("%t %s", decl.var.ty, decl.name); - if (decl.var.ini) - pri(" = %e", decl.var.ini); + if (decl.var.ini) { + pri(" = "); + if ((decl.var.ty->t == TYstruct || decl.var.ty->t == TYarr) + && (decl.var.ini->t == Ezeroini || decl.var.ini->t == Eini)) + { + geniniex(decl.var.ini); + } else { + pri("%e", decl.var.ini); + } + } pri(";\n"); break; case Dfn: @@ -300,6 +343,7 @@ liftnestedex(struct expr *ex) { switch (ex->t) { case Eintlit: case Eflolit: case Estrlit: case Eboolit: case Enullit: case Ename: + case Ezeroini: case Eenumval: break; case Eprefix: @@ -332,6 +376,10 @@ liftnestedex(struct expr *ex) { case Eas: liftnestedex(ex->child); break; + case Eini: + for (int i = 0; i < ex->ini.args.n; ++i) + liftnestedex(&ex->ini.args.d[i].ex); + break; } } @@ -461,12 +509,13 @@ static void defctype(const struct type *ty, void *_) { static int id; char **cname = (char **)&ty->_cname; + const char *kind; if (!ty->_cname) switch (ty->t) { case TYvoid: case TYbool: case TYint: case TYfloat: - case TYptr: + case TYptr: case TYenum: return; case TYarr: assert(ty->length >= 0); @@ -495,8 +544,27 @@ defctype(const struct type *ty, void *_) { pri("..."); pri(");\n"); break; - case TYenum: - *cname = xasprintf("__ty%d", id++); + case TYstruct: + kind = "struct"; + goto agg; + case TYunion: + kind = "union"; + agg: + *cname = xasprintf("__ty%s%d", ty->agg.name ? ty->agg.name : "", id++); + pri("typedef %s %s %s;\n", kind, *cname, *cname); + if (!ty->agg.fwd) { + pri("%s %s {\n", kind, *cname); + for (int i = 0; i < ty->agg.flds.n; ++i) { + struct aggfield fld = ty->agg.flds.d[i]; + pri("%t %s;\n", fld.ty, fld.name); + } + pri("};\n"); + pri("_Static_assert(sizeof(%s) == %U);\n", *cname, (long long)ty->size); + pri("_Static_assert(__alignof__(%s) == %U);\n", *cname, (long long)ty->align); + } + break; + case TYeunion: + break; } } diff --git a/bootstrap/dump.c b/bootstrap/dump.c index d01f4a7..0ea5c07 100644 --- a/bootstrap/dump.c +++ b/bootstrap/dump.c @@ -41,7 +41,7 @@ pritype(const struct type *ty) { if (ty->fn.variadic) pri("..."); pri(") %t", ty->fn.retty); - case TYenum: + default:assert(0); } } diff --git a/bootstrap/fold.c b/bootstrap/fold.c index f7962d4..efe1f83 100644 --- a/bootstrap/fold.c +++ b/bootstrap/fold.c @@ -238,6 +238,17 @@ fas(struct expr *ex) { free(child); } +static void +fzeroini(struct expr *ex) { + const struct type *ty = ex->ty; + if (ty->t == TYint || ty->t == TYfloat || ty->t == TYbool || ty->t == TYenum) { + ex->i = 0; + numcast(ex, ty); + if (ty->t == TYenum) + trysetenumvname(ex); + } +} + int fold(struct expr *ex) { switch (ex->t) { @@ -261,6 +272,8 @@ fold(struct expr *ex) { case Eas: fas(ex); break; + case Ezeroini: + fzeroini(ex); default: break; } diff --git a/bootstrap/parse.c b/bootstrap/parse.c index 71e2a74..659f756 100644 --- a/bootstrap/parse.c +++ b/bootstrap/parse.c @@ -531,12 +531,12 @@ parsetype(struct parser *P) { struct tok tok; if (lexmatch(P, &tok, '*')) { return interntype((struct type) { - TYptr, - g_targ.ptrsize, + TYptr, g_targ.ptrsize, .child = parsetype(P) }); } else if (lexmatch(P, &tok, '[')) { i64 length = -1; + const struct type *child; if (!lexmatch(P, &tok, ']')) { struct expr ex = parseexpr(P); if (!fold(&ex) || ex.t != Eintlit) @@ -546,11 +546,12 @@ parsetype(struct parser *P) { fatal(P, ex.span, "negative array length"); lexexpect(P, ']'); } + child = parsetype(P); + if (!completetype(child)) + fatal(P, tok.span, "array of incomplete type"); return interntype((struct type) { - TYarr, - g_targ.ptrsize, - .child = parsetype(P), - .length = length + TYarr, length * child->size, child->align, + .child = child, .length = length }); } else if (lexmatch(P, &tok, TKkw_const)) { return constify(parsetype(P)); @@ -626,6 +627,111 @@ mkarraytype(const struct type *child, size_t n) { }); } +static struct aggfield * +structidx2fld(const struct type *ty, int idx) { + if (idx < 0 || idx >= ty->agg.flds.n) + return NULL; + return &ty->agg.flds.d[idx]; +} + +static int +structfldnam2idx(const struct type *ty, const char *name) { + int i; + assert(name); + for (i = 0; i < ty->agg.flds.n; ++i) + if (!strcmp(name, ty->agg.flds.d[i].name)) + return i; + return -1; +} + +static struct expr +parsestructini(struct parser *P, const struct type *ty) { + struct expr ex = {Eini}; + struct tok tok; + vec_t(struct iniarg) args = {0}; + int idx = 0; + struct aggfield *fld; + + ex.span = lexpeek(P).span; + + while (!lexmatch(P, &tok, '}')) { + struct expr e; + + if (lexmatch(P, &tok, '.')) { + const char *fnam = (tok = lexexpect(P, TKident)).str; + lexexpect(P, ':'); + idx = structfldnam2idx(ty, fnam); + if (idx < 0) + fatal(P, tok.span, "struct has no field `%s'", fnam); + } + + fld = structidx2fld(ty, idx++); + e = parseexpr(P); + if (!fld) + fatal(P, e.span, + "excess elements in struct initializer"); + if (!typeof2(e.ty, fld->ty)) + fatal(P, e.span, "incompatible element type in struct initializer"); + + vec_push(&args, ((struct iniarg) { + .fld = fld->name, + e + })); + + if (!lexmatch(P, &tok, ',')) { + lexexpect(P, '}'); + break; + } + } + + ex.ty = ty; + vec_slice_cpy(&ex.ini.args, &args); + return ex; +} + +static struct expr +parsearrini(struct parser *P, const struct type *ty) { + struct expr ex = {Eini}; + struct tok tok; + vec_t(struct iniarg) args = {0}; + i64 iota = 0; + + ex.span = lexpeek(P).span; + + while (!lexmatch(P, &tok, '}')) { + struct expr e; + + if (lexmatch(P, &tok, '[')) { + struct expr i = parseexpr(P); + if (!fold(&i) || i.t != Eintlit) + fatal(P, i.span, + "array initializer element index not a compile-time integer"); + iota = i.i; + if (iota < 0) + fatal(P, i.span, "array initializer element index is negative"); + lexexpect(P, ']'); + lexexpect(P, '='); + } + + e = parseexpr(P); + if (!typeof2(ty->child, e.ty)) + fatal(P, e.span, "incompatible element type in array initializer"); + if (ty->length >= 0 && iota >= ty->length) + fatal(P, e.span, + "excess elements in array initializer"); + vec_push(&args, ((struct iniarg) { .idx = iota++, e })); + + if (!lexmatch(P, &tok, ',')) { + lexexpect(P, '}'); + break; + } + } + + ex.ty = ty; + vec_slice_cpy(&ex.ini.args, &args); + return ex; +} + static struct expr pexprimary(struct parser *P) { struct expr ex = {0}; @@ -736,6 +842,16 @@ pexprimary(struct parser *P) { ex.t = Eenumval; ex.enu.vname = vname; ex.enu.i = ex.ty->enu.vals.d[i].i; + } else if (lexmatch(P, &tok, '{')) { + P->used_targetty = 1; + if (!P->targty) + fatal(P, tok.span, "cannot infer type for compound initializer"); + if (lexmatch(P, &tok, '}')) + ex.t = Ezeroini, ex.ty = P->targty; + else if (P->targty->t == TYstruct) + ex = parsestructini(P, P->targty); + else if (P->targty->t == TYarr) + ex = parsearrini(P, P->targty); } else { experr: fatal(P, tok.span, "expected expression (near %s)", tok2str(tok)); @@ -1176,8 +1292,9 @@ parsevardecl(struct parser *P, struct decl *decl) { } } - if (ini && decl->t == Dstatic && !fold(ini)) - fatal(P, ini->span, "static initializer isn't constant"); + // TODO static initialzier constants are a superset of folded constants + // if (ini && decl->t == Dstatic && !fold(ini)) + // fatal(P, ini->span, "static initializer isn't constant"); if (ini && !typeof2(ty, ini->ty)) fatal(P, tok.span, "incompatible initializer type"); @@ -1585,6 +1702,9 @@ parsefn(struct decl *decl, struct parser *P) { } vec_slice_cpy(&fn->params, ¶ms); fn->retty = unconstify(parsetype(P)); + if (fn->retty != ty_void && !completetype(fn->retty)) { + fatal(P, tok.span, "return type is incomplette"); + } fn->selfty = fntype(fn); if (!lexmatch(P, &tok, ';')) { struct env *env = xcalloc(1, sizeof *env); @@ -1732,7 +1852,7 @@ parseenum(struct parser *P, const char *name) { struct type ty = {TYenum}; static int id = 0; i64 iota = 0, max = 0, min = 0; - vec_t(struct enumfield) vals = {0}; + vec_t(struct enumval) vals = {0}; if (lexmatch(P, &tok, ':')) { ty.enu.intty = unconstify(parsetype(P)); @@ -1760,7 +1880,7 @@ parseenum(struct parser *P, const char *name) { if (val > max) max = val; iota = val + 1; - vec_push(&vals, ((struct enumfield) { fnam, val })); + vec_push(&vals, ((struct enumval) { fnam, val })); if (!lexmatch(P, &tok, ',')) { lexexpect(P, '}'); @@ -1779,10 +1899,56 @@ parseenum(struct parser *P, const char *name) { assert(ty.enu.intty); } + ty.size = ty.enu.intty->size; + ty.align = ty.enu.intty->align; ty.enu.name = name; ty.enu.id = id++; vec_slice_cpy(&ty.enu.vals, &vals); + return interntype(ty); +} + +static const struct type * +parseagg(struct parser *P, const char *name, int kind) { + struct tok tok; + struct type ty = {kind}; + static int id = 0; + size_t size = 0, align = 1; + vec_t(struct aggfield) flds = {0}; + + if (lexmatch(P, &tok, ';')) { + ty.agg.fwd = 1; + } else { + lexexpect(P, '{'); + while (!lexmatch(P, &tok, '}')) { + const char *fnam = (tok = lexexpect(P, TKident)).str; + const struct type *ty = parsetype(P); + size_t off = kind == TYunion ? 0 : ALIGNUP(size, ty->align); + + if (!completetype(ty)) + fatal(P, tok.span, "aggregate field `%s' is of incomplete type", fnam); + + align = MAX(align, ty->align); + if (kind == TYstruct) + size = off + ty->size; + else + size = MAX(size, ty->size); + + vec_push(&flds, ((struct aggfield) { + off, fnam, ty + })); + + if (!lexmatch(P, &tok, ',')) { + lexexpect(P, '}'); + break; + } + } + } + ty.size = ALIGNUP(size, align); + ty.align = align; + ty.agg.name = name; + vec_slice_cpy(&ty.agg.flds, &flds); + ty.agg.id = id++; return interntype(ty); } @@ -1790,7 +1956,8 @@ static void parsedecl(struct decl *decl, struct parser *P, bool toplevel) { struct tok tok = { .span = P->tokspan }; bool externp = 0; - const char *name ; + const char *name; + int kind; memset(decl, 0, sizeof *decl); if (lexmatch(P, &tok, TKkw_extern)) @@ -1834,14 +2001,38 @@ parsedecl(struct decl *decl, struct parser *P, bool toplevel) { if (externp) fatal(P, tok.span, "enum cannot be `extern'"); decl->name = lexexpects(P, TKident, "enum name").str; decl->ty = parseenum(P, decl->name); - + } else if (lexmatch(P, &tok, TKkw_struct)) { + struct decl *d2; + kind = TYstruct; + if (externp) fatal(P, tok.span, "struct cannot be `extern'"); + agg: + decl->name = lexexpects(P, TKident, "struct name").str; + decl->ty = parseagg(P, decl->name, kind); + d2 = (struct decl *)finddecl(P, decl->name); + if (d2 && d2->t == Dtype && d2->ty->t == kind && d2->ty->agg.fwd) { + // modify existing forward declaration + *(size_t *)&d2->ty->size = decl->ty->size; + *(size_t *)&d2->ty->align = decl->ty->align; + *(bool *)&d2->ty->agg.fwd = 0; + memcpy((void *)&d2->ty->agg.flds, &decl->ty->agg.flds, + sizeof d2->ty->agg.flds); + uninterntype(decl->ty); + decl = d2; + envput(P->curenv, d2); + goto noputdecl; + } + } else if (lexmatch(P, &tok, TKkw_union)) { + if (externp) fatal(P, tok.span, "union cannot be `extern'"); + kind = TYunion; + goto agg; } else { fatal(P, tok.span, "expected declaration (near %s)", tok2str(tok)); } - decl->span = tok.span; putdecl(P, tok.span, decl); +noputdecl: + decl->span = tok.span; } void diff --git a/bootstrap/test.cff b/bootstrap/test.cff index 89a21eb..651c2ce 100644 --- a/bootstrap/test.cff +++ b/bootstrap/test.cff @@ -1,30 +1,28 @@ -typedef v3f ["!"[~-1] - as(i16)30.4f64]f32; -enum Color { - Red = 7, - Green = -10, - Blue, +struct Vec2f; +struct Vec2f { + x f32, + y f32, } -fn best() Color { - return :Green; +union Val { + x i64, + lo i32, + y f64, } -fn hex(c Color) u32 { - switch (c) { - case :Red; return 0xFF0000; - case :Green; return 0x00FF00; - case :Blue; return 0x0000FF; - } -} +static xs *void = {}; extern fn main (argc int, argv **u8) void { extern fn printf(fmt *const u8, ...) int; - printf("red %d\n", Color:Red); - printf("green %d\n", Color:Green); - printf("blue %d\n", Color:Blue); - printf("red ! %.8X\n", hex(:Red)); - + let x Vec2f = { .y: 1, .x: 2.4 }; + printf("v = { %g, %g }\n", x.x, x.y); + + let is [10]int = { [4] = 1, 2, [1 - 1] = 3 }; + for let i = 0; i < 10; ++i { + printf("%d\n", is[i]); + } + return; } diff --git a/bootstrap/types.c b/bootstrap/types.c index 0353041..7491b4b 100644 --- a/bootstrap/types.c +++ b/bootstrap/types.c @@ -23,7 +23,7 @@ inittypes() { free(types.buckets); types.size = 0; - types.buckets = calloc(types.nbuckets = 16, sizeof(struct typesnode *)); + types.buckets = calloc(types.nbuckets = 64, sizeof(struct typesnode *)); } static u32 @@ -41,20 +41,23 @@ hashtype(const struct type *ty) { break; case TYptr: case TYslice: - h = jkhashv(h, ty->child); + h = jkhashv(h, ty->child->_id); break; case TYarr: - h = jkhashv(h, ty->child); + h = jkhashv(h, ty->child->_id); h = jkhashv(h, ty->length); break; case TYfn: - h = jkhashv(h, ty->fn.retty); + h = jkhashv(h, ty->fn.retty->_id); h = jkhashv(h, ty->fn.params.n); for (int i = 0; i < ty->fn.params.n; ++i) - h = jkhashv(h, ty->fn.params.d[i]); + h = jkhashv(h, ty->fn.params.d[i]->_id); case TYenum: h = jkhashv(h, ty->enu.id); break; + case TYstruct: case TYunion: case TYeunion: + h = jkhashv(h, ty->agg.id); + break; } return h; } @@ -85,7 +88,9 @@ typeeql(const struct type *lhs, const struct type *rhs) { return 0; return 1; case TYenum: - return 0; + return lhs->enu.id == rhs->enu.id; + case TYstruct: case TYunion: case TYeunion: + return lhs->agg.id == rhs->agg.id; } assert(0 && "unreachable"); } @@ -117,16 +122,35 @@ typesput(const struct type *key) { const struct type * interntype(struct type ty) { + static int id; if (!ty.align) ty.align = ty.size; const struct type *ty2 = typesfind(&ty); if (ty2) return ty2; + ty._id = id++; ty2 = typesput(&ty); assert(ty2); return ty2; } +void +uninterntype(const struct type *key) { + u32 hash = hashtype(key); + size_t idx = hash & (types.nbuckets - 1); + for (struct typesnode *n = types.buckets[idx], *prev = NULL; n; n = n->next) { + if (key == &n->ty) { + if (prev) { + prev->next = n->next; + } else { + types.buckets[idx] = n->next; + } + break; + } + prev = n; + } +} + bool completetype(const struct type *ty) { if (ty->t == TYvoid) @@ -135,6 +159,8 @@ completetype(const struct type *ty) { return 0; if (ty->t == TYarr && ty->length < 0) return 0; + if (ty->t == TYstruct || ty->t == TYunion || ty->t == TYeunion) + return !ty->agg.fwd; return 1; } |