aboutsummaryrefslogtreecommitdiff
path: root/src/parse.cff
diff options
context:
space:
mode:
Diffstat (limited to 'src/parse.cff')
-rw-r--r--src/parse.cff66
1 files changed, 63 insertions, 3 deletions
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 {