aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cffc.hff4
-rw-r--r--src/parse.cff32
-rw-r--r--src/type.cff3
3 files changed, 33 insertions, 6 deletions
diff --git a/src/cffc.hff b/src/cffc.hff
index 9fd9080..4563583 100644
--- a/src/cffc.hff
+++ b/src/cffc.hff
@@ -172,7 +172,7 @@ struct Expr {
Slice struct { lhs *Expr, begin *Expr, end *Expr },
Call struct { lhs *Expr, args [#]Expr },
ZeroIni,
- EnumIni struct { name *const u8, val i64 },
+ EnumIni i64,
EUnionIni struct { var *const AggField, ex *Expr },
AggIni struct { flds [#]*const AggField, exs [#]Expr },
ArrIni struct { idxs [#]u32, exs [#]Expr, maxn i64 },
@@ -412,7 +412,7 @@ fn childtype(ty *const Type) *const Type {
}
extern fn completetype(ty *const Type) bool;
fn isnumtype(ty *const Type) bool {
- return ty->is(:Int) or ty->is(:Flo);
+ return ty->is(:Int) or ty->is(:Flo) or (ty->is(:Enum) and ty.u.Enum.lax);
}
extern fn typeof2(a *const Type, b *const Type) *const Type;
diff --git a/src/parse.cff b/src/parse.cff
index 3453485..89a059f 100644
--- a/src/parse.cff
+++ b/src/parse.cff
@@ -634,6 +634,14 @@ typedef DeclYielder *fn(*Decl, *void) void;
fn parsedecls(P *Parser, loc Loc, yield DeclYielder, yarg *void, toplevel bool) void;
fn parseenum(P *Parser, name *const u8, lax bool) *const Type {
+ let intty *const Type = #null;
+ let tok Tok #?;
+ if lexmatch(P, &tok, ':') {
+ intty = parsetype(P);
+ if !intty->is(:Int) {
+ fatal(P, tok.loc, "enum backing type must be integral (%t)", intty);
+ }
+ }
lexexpect(P, '{');
let iota = 0i64;
let max = iota;
@@ -656,10 +664,10 @@ fn parseenum(P *Parser, name *const u8, lax bool) *const Type {
break;
}
}
- let intty *const Type =
+ let intty *const Type = intty ?? (
max < 1u64 << ((g_targ.intsize * 8) - 1) ? ty_int
: max < 1u64 << 31 ? ty_i32
- : ty_i64;
+ : ty_i64);
static id int = 0;
return interntype({ .u: :Enum { intty, name, lax, id++, vals->move(P.alloc) }});
}
@@ -1033,6 +1041,22 @@ fn parsetype(P *Parser) *const Type {
case lexmatch(P, &tok, :kw_fn);
return parsefntype(P);
+ case lexmatch(P, &tok, :kw_struct);
+ let decl *Decl;
+ return parseagg(P, tok.loc, :Struct, #null, &decl);
+
+ case lexmatch(P, &tok, :kw_union);
+ let decl *Decl;
+ return parseagg(P, tok.loc, :Union, #null, &decl);
+
+ case lexmatch(P, &tok, :kw_enum);
+ let decl *Decl;
+ if lexmatch(P, #null, :kw_union) {
+ return parseagg(P, tok.loc, :EUnion, #null, &decl);
+ } else {
+ return parseenum(P, #null, #{lax?} #f);
+ }
+
case else;
fatal(P, tok.loc, "expected type (near %qT)", tok);
}
@@ -1388,7 +1412,7 @@ fn pexprimary(P *Parser) Expr {
}
fatal(P, tok.loc, "%t has no such variant %qT", ty, tok);
} while #f;
- ex = { tok.loc, ty, :EnumIni { name, i }};
+ ex = { tok.loc, ty, :EnumIni(i) };
} else if ty->is(:Agg) and ty.u.Agg.kind == :EUnion {
let name = (tok = lexexpects(P, :ident, "variant name")).u.ident;
let fld = findaggfield(ty, name);
@@ -2610,7 +2634,7 @@ fn parsedecls(P *Parser, loc Loc, yield DeclYielder, yarg *void, toplevel bool)
}
} else {
let name = lexexpect(P, :ident).u.ident;
- let ty = parseenum(P, name, #{lax} #f);
+ let ty = parseenum(P, name, (attr & ATTR_LAX) != 0);
decl = putdecl(P, loc, { name, loc, .u: :Ty(ty) });
}
diff --git a/src/type.cff b/src/type.cff
index b0cb259..a07ea0d 100644
--- a/src/type.cff
+++ b/src/type.cff
@@ -208,6 +208,9 @@ extern fn mkslicetype(child *const Type) *const Type {
fn numtype2rank(ty *const Type) int {
ty = unconstify(ty);
switch {
+ case ty->is(:Enum);
+ assert(ty.u.Enum.lax, "lax");
+ return numtype2rank(ty.u.Enum.intty);
case ty->is(:Int) and (ty == ty_int or ty.size < ty_int.size);
return 0;
case ty == ty_uint; return 1;