aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bootstrap/test.cff9
-rw-r--r--src/cffc.hff5
-rw-r--r--src/parse.cff60
3 files changed, 73 insertions, 1 deletions
diff --git a/bootstrap/test.cff b/bootstrap/test.cff
index c7309a9..6f20b6e 100644
--- a/bootstrap/test.cff
+++ b/bootstrap/test.cff
@@ -109,6 +109,15 @@ extern fn main (argc int, argv **u8) int {
printf("sizeof *void = %zu\n", sizeof *void);
printf("1.2 -> %#.8x\n", transmute(u32, 1.2f));
+ switch is.#len {
+ case 0, 1;
+ is.#len < 2;
+ case 3;
+ 3;
+ case else;
+ "idk";
+ }
+
return 0;
}
diff --git a/src/cffc.hff b/src/cffc.hff
index 2af06d6..d4b0ec1 100644
--- a/src/cffc.hff
+++ b/src/cffc.hff
@@ -173,6 +173,10 @@ struct Expr {
}
}
+struct ISwitchCase {
+ es [#]Expr,
+ t [#]Stmt
+}
struct Stmt {
loc Loc,
@@ -192,6 +196,7 @@ struct Stmt {
Return Option<Expr>,
Expr Expr,
Decl *Decl,
+ ISwitch struct { ex Expr, cs [#]ISwitchCase, f [#]Stmt }
}
}
diff --git a/src/parse.cff b/src/parse.cff
index 613b4ae..7ce605c 100644
--- a/src/parse.cff
+++ b/src/parse.cff
@@ -646,7 +646,10 @@ fn parseenum(P *Parser, name *const u8, lax bool) *const Type {
break;
}
}
- let intty *const Type = #null;
+ let intty *const Type =
+ max < 1u64 << ((g_targ.intsize * 8) - 1) ? ty_int
+ : max < 1u64 << 31 ? ty_i32
+ : ty_i64;
static id int = 0;
return interntype({ .u: :Enum { intty, name, lax, id++, vals->move(P.alloc) }});
}
@@ -1788,6 +1791,58 @@ fn pstfor(P *Parser) Stmt {
return { loc, :For { ini, test, next, body, P.loopid }};
}
+fn pstiswitch(P *Parser, loc Loc, ex Expr) Stmt {
+ let tok Tok #?;
+ let cs Vec<ISwitchCase> = {};
+ let f [#]Stmt = {};
+ let elsep = #f;
+ while !lexmatch(P, &tok, '}') {
+ lexexpect(P, :kw_case);
+ if lexmatch(P, &tok, :kw_else) {
+ if elsep {
+ err(P, tok.loc, "duplicate else case");
+ }
+ elsep = #t;
+ f = parseblock0(P);
+ continue;
+ }
+ let es Vec<Expr> = {};
+ do {
+ let e = parseexpr(P);
+ if !fold(&e) {
+ err(P, e.loc, "expected compile-time expression");
+ }
+ if !typematchestarg(ex.ty, e.ty) {
+ err(P, e.loc, "bad case expression (%t, expected %t)", e.ty, ex.ty);
+ }
+ es->push(e);
+ if !lexmatch(P, #null, ',') {
+ lexexpect(P, ';');
+ break;
+ }
+ } while !lexmatch(P, #null, ';');
+ cs->push({ es->move(P.alloc), parseblock0(P) });
+ }
+
+ return { loc, :ISwitch { ex, cs->move(P.alloc), f }};
+}
+
+fn pstswitch(P *Parser) Stmt {
+ let loc = P.tokloc;
+ let tok Tok #?;
+ if lexmatch(P, &tok, '{') {
+ } else {
+ let ex = parseexpr(P);
+ lexexpect(P, '{');
+ if ex.ty->is(:Int) or ex.ty->is(:Enum) {
+ return pstiswitch(P, loc, ex);
+ } else if ex.ty->is(:Agg) and ex.ty.u.Agg.kind == :EUnion {
+ } else {
+ fatal(P, tok.loc, "invalid switch test expression type (%t)", ex.ty);
+ }
+ }
+}
+
fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void {
let tok Tok = {};
switch {
@@ -1825,6 +1880,9 @@ fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void {
lexexpect(P, ';');
return yield({ tok.loc, :Continue(P.curloop) }, yarg);
+ case lexmatch(P, &tok, :kw_switch);
+ return yield(pstswitch(P), yarg);
+
case isdecltokt(tok.t);
struct Arg {
P *Parser,