From 5f1827beb3199a9f4cec44de5001d599be55cfc8 Mon Sep 17 00:00:00 2001 From: lemon Date: Fri, 19 Aug 2022 12:52:29 +0200 Subject: EUSwitch and #tag --- src/cffc.hff | 13 +++++++++++- src/parse.cff | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 75 insertions(+), 4 deletions(-) (limited to 'src') 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, 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 = {}; + 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 { -- cgit v1.2.3