diff options
| author | 2022-08-19 12:52:29 +0200 | |
|---|---|---|
| committer | 2022-08-19 12:52:29 +0200 | |
| commit | 5f1827beb3199a9f4cec44de5001d599be55cfc8 (patch) | |
| tree | c42ddaf91c2ebef9efdb81ac07818b42a5377449 | |
| parent | b1934f206b3590cf6c7436f50e2bf6dba653c04c (diff) | |
EUSwitch and #tag
| -rw-r--r-- | bootstrap/test2.cff | 2 | ||||
| -rw-r--r-- | src/cffc.hff | 13 | ||||
| -rw-r--r-- | src/parse.cff | 66 |
3 files changed, 75 insertions, 6 deletions
diff --git a/bootstrap/test2.cff b/bootstrap/test2.cff index c120d05..c4aedd9 100644 --- a/bootstrap/test2.cff +++ b/bootstrap/test2.cff @@ -45,7 +45,6 @@ extern fn main() void { x = X + 1 + Y; let const v= Value:None; -#{ switch v { case None; case Int i; @@ -80,4 +79,3 @@ extern fn main() void { Bit<i32>:foo(3); Bit<i64>:foo(3); } -} diff --git a/src/cffc.hff b/src/cffc.hff index c8c90ac..131b3d9 100644 --- a/src/cffc.hff +++ b/src/cffc.hff @@ -184,6 +184,16 @@ struct ISwitchCase { t [#]Stmt } +struct EUSwitchCase { + capt *const u8, + captptr bool, + captid int, + variant int, + captty *const Type, + fld *AggField, + t [#]Stmt +} + struct Stmt { loc Loc, u enum union { @@ -202,7 +212,8 @@ struct Stmt { Return Option<Expr>, Expr Expr, Decl *Decl, - ISwitch struct { ex Expr, cs [#]ISwitchCase, f [#]Stmt } + ISwitch struct { ex Expr, cs [#]ISwitchCase, f [#]Stmt }, + EUSwitch struct { ex Expr, cs [#]EUSwitchCase, f [#]Stmt }, } } diff --git a/src/parse.cff b/src/parse.cff index e237a90..4f78b21 100644 --- a/src/parse.cff +++ b/src/parse.cff @@ -1548,7 +1548,15 @@ fn pexpostfix(P *Parser) Expr { case else; fatal(P, ex.loc, "invalid operand to `#len' (%t)", ex.ty); } - // case lexmatch(P, &tok, '#tag'); + case lexmatch(P, &tok, '#tag'); + let ty = ex.ty; + if ty->is(:Ptr) { + ty = ty.u.Ptr; + } + if !ty->is(:Agg) or ty.u.Agg.kind != :EUnion { + fatal(P, ex.loc, "invalid operand to #tag (%t)", ex.ty); + } + ex = { tok.loc, ty.u.Agg.enumty, :EUTag(exprdup(P.alloc, ex)) }; case else; lexexpects(P, :ident, "field name"); @@ -2027,8 +2035,60 @@ fn pstiswitch(P *Parser, loc Loc, ex Expr) Stmt { return { loc, :ISwitch { ex, cs->move(P.alloc), f }}; } -fn psteuswitch(P *Parser, loc Loc, ex Expr) Stmt { - let ty = ex.ty; +fn psteuswitch(P *Parser, loc Loc, test Expr) Stmt { + let cs Vec<EUSwitchCase> = {}; + let tok Tok #?; + let f [#]Stmt = {}; + let elsep = #f; + + while !lexmatch(P, &tok, '}') { + let c EUSwitchCase = {}; + lexexpect(P, :kw_case); + if lexmatch(P, &tok, :kw_else) { + if elsep { + err(P, tok.loc, "duplicate 'case else' block"); + } + elsep = #t; + f = parseblock0(P); + continue; + } + let vname = (tok = lexexpect(P, :ident)).u.ident; + c.fld = findaggfield(test.ty, vname); + if c.fld == #null { + fatal(P, tok.loc, "%t has no such variant %qT", test.ty, tok); + } + c.variant = c.fld - test.ty.u.Agg.flds.#ptr; + if c.fld.ty != #null and lexmatch(P, &tok, '*') { + if !islvalue(test) { + fatal(P, tok.loc, "cannot capture by pointer, test expression is not lvalue"); + } + c.captptr = #t; + if lexpeek(P).t != :ident { + lexexpect(P, :ident); + } + } + let env = mkenv(P.curenv, P.alloc); + if c.fld.ty != #null and lexmatch(P, &tok, :ident) { + let ty = c.fld.ty; + c.capt = tok.u.ident; + if c.captptr { + ty = mkptrtype(test.ty.konst ? constify(ty) : ty); + } + pushenv(P, env); + putdecl(P, tok.loc, { + c.capt, tok.loc, .u: :Let { c.captty = ty, :None, #f, P.curfn.id } + }); + } + lexexpect(P, ';'); + c.t = parseblock0(P); + if c.capt { + popenv(P); + } + envfree(env); + } + + + return { loc, :EUSwitch { test, cs->move(P.alloc), f }}; } fn pstswitch(P *Parser, loc Loc) Stmt { |