diff options
| author | 2022-08-18 19:15:35 +0200 | |
|---|---|---|
| committer | 2022-08-18 19:15:35 +0200 | |
| commit | 8f3f9a5ba1fe069edf9d64f0d6743b9b3d9f5bcb (patch) | |
| tree | 2aad40c700579a45185056a15a8be107adabcc1a /src | |
| parent | 9c485da5e1d955031fa2a3654bfc2ef814898167 (diff) | |
iswitch
Diffstat (limited to 'src')
| -rw-r--r-- | src/cffc.hff | 5 | ||||
| -rw-r--r-- | src/parse.cff | 60 |
2 files changed, 64 insertions, 1 deletions
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, |