diff options
| -rw-r--r-- | bootstrap/test.cff | 9 | ||||
| -rw-r--r-- | src/cffc.hff | 5 | ||||
| -rw-r--r-- | src/parse.cff | 60 |
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, |