aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bootstrap/all.h7
-rw-r--r--bootstrap/cgen.c54
-rw-r--r--bootstrap/parse.c108
-rw-r--r--bootstrap/test2.cff9
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);