diff options
Diffstat (limited to 'bootstrap')
| -rw-r--r-- | bootstrap/all.h | 7 | ||||
| -rw-r--r-- | bootstrap/cgen.c | 54 | ||||
| -rw-r--r-- | bootstrap/parse.c | 108 | ||||
| -rw-r--r-- | bootstrap/test2.cff | 9 |
4 files changed, 153 insertions, 25 deletions
diff --git a/bootstrap/all.h b/bootstrap/all.h index fb6bfe6..6e63058 100644 --- a/bootstrap/all.h +++ b/bootstrap/all.h @@ -180,6 +180,7 @@ struct type { } enu; struct { const char *name; + const struct type *enumty; slice_t(struct aggfield { size_t off; const char *name; @@ -304,6 +305,7 @@ enum exprtype { Emcall, Eslice, Elen, + Eeuini, }; struct blockstmt { @@ -365,6 +367,11 @@ struct expr { struct { struct expr *lhs, *start, *end; } slice; + struct { + const char *fnam; + i64 tag; + struct expr *ini; + } euini; }; }; diff --git a/bootstrap/cgen.c b/bootstrap/cgen.c index df5ccbc..8bea8bc 100644 --- a/bootstrap/cgen.c +++ b/bootstrap/cgen.c @@ -153,6 +153,20 @@ geniniex(struct expr *ex) { } static void +geneuiniex(struct expr *ex) { + if (ex->t == Ezeroini) + pri("{0}"); + else { + assert(ex->t == Eeuini); + if (ex->euini.ini) + pri("{ /* %s */ %I, .u.%s = %e }", ex->euini.fnam, ex->euini.tag, + ex->euini.fnam, ex->euini.ini); + else + pri("{ /* %s */ %I }", ex->euini.fnam, ex->euini.tag); + } +} + +static void genexpr(struct expr *ex) { const struct type *ty = unconstify(ex->ty); struct decl *decl; @@ -237,7 +251,7 @@ genexpr(struct expr *ex) { case Eget: pri("%e%s%s", ex->get.lhs, ex->get.lhs->ty->t == TYptr ? "->" : ".", ex->get.fld); break; - case Emcall: + case Emcall: decl = container_of(ex->mcall.met, struct decl, fn); assert(*decl->_cname); pri("%s(", *decl->_cname); @@ -248,7 +262,7 @@ genexpr(struct expr *ex) { } pri(")"); break; - case Eslice: + case Eslice: ;static int id; // TODO range assertions pri("({ %t __start%d = %e; ", ex->slice.start->ty, id, ex->slice.start); @@ -256,9 +270,14 @@ genexpr(struct expr *ex) { ex->ty, ex->slice.lhs, ex->slice.lhs->ty->t == TYslice ? ".ptr" : "", id, ex->slice.end, id); ++id; break; - case Elen: + case Elen: pri("%e.len", ex->child); break; + case Eeuini: + pri("((%t)", ty); + geneuiniex(ex); + pri(")"); + break; } } @@ -285,10 +304,12 @@ genstmt(struct stmt *stmt) { pri("%t %s_%d", decl.var.ty, decl.name, decl.var.id); if (decl.var.ini) { pri(" = "); - if ((decl.var.ty->t == TYstruct || decl.var.ty->t == TYarr) + if ((decl.var.ty->t == TYstruct || decl.var.ty->t == TYunion || decl.var.ty->t == TYarr) && (decl.var.ini->t == Ezeroini || decl.var.ini->t == Eini)) { geniniex(decl.var.ini); + } else if (decl.var.ty->t == TYeunion) { + geneuiniex(decl.var.ini); } else { pri("%e", decl.var.ini); } @@ -425,6 +446,9 @@ liftnestedex(struct expr *ex) { liftnestedex(ex->slice.start); liftnestedex(ex->slice.end); break; + case Eeuini: + liftnestedex(ex->euini.ini); + break; } } @@ -631,6 +655,28 @@ defctype(const struct type *ty, void *_) { liftdecl(ty->agg.decls.d[i]); break; case TYeunion: + if (ty->konst) { + defctype(unconstify(ty), NULL); + *cname = (char *)unconstify(ty)->_cname; + break; + } + *cname = xasprintf("__ty%s%d", ty->agg.name ? ty->agg.name : "", id++); + pri("typedef struct %s %s;\n", *cname, *cname); + if (!ty->agg.fwd) { + pri("struct %s {\n", *cname); + pri("%t t;\n", ty->agg.enumty); + pri("union {\n", ty->agg.enumty); + for (int i = 0; i < ty->agg.flds.n; ++i) { + struct aggfield *fld = &ty->agg.flds.d[i]; + if (fld->ty) + pri("%t %s;\n", fld->ty, fld->name); + } + pri("} u;\n};\n"); + pri("_Static_assert(sizeof(%s) == %U, \"sizeof(%t) == %U\");\n", + *cname, (u64)ty->size, ty, (u64)ty->size); + pri("_Static_assert(__alignof__(%s) == %U, \"__alignof__(%t) == %U\");\n", + *cname, (u64)ty->align, ty, (u64)ty->align); + } break; } diff --git a/bootstrap/parse.c b/bootstrap/parse.c index 2b44ca8..963b986 100644 --- a/bootstrap/parse.c +++ b/bootstrap/parse.c @@ -1091,17 +1091,34 @@ pexprimary(struct parser *P) { int i; enumlit: vname = (tok = lexexpect(P, TKident)).str; - if (!(ex.ty = P->targty) || ex.ty->t != TYenum) + if (!(ex.ty = P->targty) || (ex.ty->t != TYenum && ex.ty->t != TYeunion)) fatal(P, tok.span, "cannot infer type for enum literal `:%s'", vname); - for (i = 0; i < ex.ty->enu.vals.n; ++i) - if (!strcmp(ex.ty->enu.vals.d[i].name, vname)) - goto found; - fatal(P, tok.span, "enum %t contains no variant `%s'", ex.ty, vname); - found: - P->used_targty = 1; - ex.t = Eenumval; - ex.enu.vname = vname; - ex.enu.i = ex.ty->enu.vals.d[i].i; + if (ex.ty->t == TYenum) { + for (i = 0; i < ex.ty->enu.vals.n; ++i) + if (!strcmp(ex.ty->enu.vals.d[i].name, vname)) + goto found; + fatal(P, tok.span, "enum %t contains no variant `%s'", ex.ty, vname); + found: + P->used_targty = 1; + ex.t = Eenumval; + ex.span = tok.span; + ex.enu.vname = vname; + ex.enu.i = ex.ty->enu.vals.d[i].i; + } else { + const struct aggfield *fld; + for (i = 0; i < ex.ty->agg.flds.n; ++i) + if (!strcmp((fld = &ex.ty->agg.flds.d[i])->name, vname)) + goto found1; + fatal(P, tok.span, "tagged union %t contains no variant `%s'", ex.ty, vname); + found1: + P->used_targty = 1; + ex.t = Eeuini; + ex.span = tok.span; + ex.euini.fnam = fld->name; + ex.euini.tag = ex.ty->agg.enumty->enu.vals.d[i].i; + if (fld->ty) + ex.euini.ini = exprdup(parseexpr(P)); + } } else if (lexmatch(P, &tok, '{')) { aggini: P->used_targty = 1; @@ -2408,6 +2425,7 @@ parseenum(struct parser *P, const char *name) { 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); @@ -2439,6 +2457,7 @@ parseagg(struct parser *P, const char *name, int kind, struct decl **retdecl) { const struct type *pty = NULL; static int id = 0; size_t size = 0, align = 1; + i64 f0align = -1; bool decls = 0; vec_t(struct aggfield) flds = {0}; @@ -2471,23 +2490,31 @@ parseagg(struct parser *P, const char *name, int kind, struct decl **retdecl) { } const char *fnam = (tok = lexexpect(P, TKident)).str; - const struct type *ty = parsetype(P); - size_t off = kind == TYunion ? 0 : ALIGNUP(size, ty->align); + const struct type *ty = NULL; + size_t off = size; + if (kind != TYeunion || ((tok = lexpeek(P)).t != ',' && tok.t != '}' && !isdecltokt(tok.t))) { + ty = parsetype(P); + if (f0align < 0) + f0align = ty->align; + off = kind != TYstruct ? 0 : ALIGNUP(size, ty->align); + } int i; struct aggfield fld; vec_foreach(&flds, fld, i) if (!strcmp(fnam, fld.name)) fatal(P, tok.span, "duplicate field %T", tok); - if (!completetype(ty)) + if (ty && !completetype(ty)) fatal(P, tok.span, "aggregate field `%s' is of incomplete type (%t)", fnam, ty); - align = MAX(align, ty->align); - if (kind == TYstruct) - size = off + ty->size; - else - size = MAX(size, ty->size); + if (ty) { + 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 @@ -2498,10 +2525,43 @@ parseagg(struct parser *P, const char *name, int kind, struct decl **retdecl) { break; } } + struct type *ppty = (struct type *)pty; ppty->size = ALIGNUP(size, align); ppty->align = align; vec_slice_cpy(&ppty->agg.flds, &flds); + + if (kind == TYeunion) { + struct type enumty = {TYenum, .enu.id = id++}; + int n = flds.length; + + enumty.enu.name = name; + enumty.enu.vals.d = xmalloc(n * sizeof(struct enumval)); + enumty.enu.vals.n = n; + if (n < 256) + enumty.enu.intty = ty_u8; + else if (n < 65536) + enumty.enu.intty = ty_u16; + else assert(0); + enumty.size = enumty.enu.intty->size; + enumty.align = enumty.enu.intty->align; + + int i; struct aggfield fld; + vec_foreach(&flds, fld, i) { + struct enumval *ev = &enumty.enu.vals.d[i]; + ev->name = fld.name; + ev->i = i; + } + ppty->agg.enumty = interntype(enumty); + + size_t off = f0align < 0 ? 0 : ALIGNUP(enumty.size, f0align); + ppty->size += off; + align = MAX(align, enumty.align); + + for (int i = 0; i < ppty->agg.flds.n; ++i) + ppty->agg.flds.d[i].off += off; + } + if (!decls) return pty; else { @@ -2701,10 +2761,16 @@ parsedecl(decl_yielder_t yield, void *yarg, struct parser *P, bool toplevel) { decl.macro = parsemacro(P); decl.macro.name = name; } else if (lexmatch(P, &tok, TKkw_enum)) { - if (externp) fatal(P, tok.span, "enum cannot be `extern'"); decl.t = Dtype; - decl.name = lexexpects(P, TKident, "enum name").str; - decl.ty = parseenum(P, decl.name); + if (lexmatch(P, &tok, TKkw_union)) { + if (externp) fatal(P, tok.span, "enum union cannot be `extern'"); + kind = TYeunion; + goto agg; + } else { + 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)) { kind = TYstruct; if (externp) fatal(P, tok.span, "struct cannot be `extern'"); diff --git a/bootstrap/test2.cff b/bootstrap/test2.cff index 3061d6e..e5e484a 100644 --- a/bootstrap/test2.cff +++ b/bootstrap/test2.cff @@ -18,6 +18,12 @@ struct Bit<T> { def Y = 3.3; +enum union Value { + None, + Int i32, + Flo f32, +} + extern fn main() void { let n Node<int> = {#null, 0}; let n Node<int> = {&n, 1}; @@ -25,6 +31,9 @@ extern fn main() void { let x int #?; x = X + 1 + Y; + let v Value = :None; + v = :Int 3; + printf("n %d\n", n.value); printf("n link %d\n", n.link.value); |