From 96ef1857bac446f4e065e7c10530213e361d726a Mon Sep 17 00:00:00 2001 From: lemon Date: Sun, 7 Aug 2022 22:36:57 +0200 Subject: add tagged unions --- bootstrap/parse.c | 108 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 87 insertions(+), 21 deletions(-) (limited to 'bootstrap/parse.c') 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'"); -- cgit v1.2.3