diff options
| author | 2022-08-16 05:42:36 +0200 | |
|---|---|---|
| committer | 2022-08-16 05:42:36 +0200 | |
| commit | 04c7892134d49f3b295a51cc741affe9f02e374d (patch) | |
| tree | c94c4501b9d448c057bd736ee7b718daefcb304f | |
| parent | 5bc23671b5569d86196643f58f4f70997383b4a4 (diff) | |
nullish coalescing operator ??
| -rw-r--r-- | bootstrap/cgen.c | 2 | ||||
| -rw-r--r-- | bootstrap/parse.c | 37 | ||||
| -rw-r--r-- | src/parse.cff | 8 |
3 files changed, 34 insertions, 13 deletions
diff --git a/bootstrap/cgen.c b/bootstrap/cgen.c index 665bdc5..15fab93 100644 --- a/bootstrap/cgen.c +++ b/bootstrap/cgen.c @@ -222,7 +222,7 @@ genexpr(struct expr *ex) { pri("(%e)%c", ex->unop.child, ex->unop.op); break; case Ebinop: - pri("(%e %c %e)", ex->binop.lhs, ex->binop.op, ex->binop.rhs); + pri("((%e) %c (%e))", ex->binop.lhs, ex->binop.op == '?\?' ? '?:' : ex->binop.op, ex->binop.rhs); break; case Econd: pri("((%e) ? (%e) : (%e))", ex->cond.test, ex->cond.t, ex->cond.f); diff --git a/bootstrap/parse.c b/bootstrap/parse.c index 08f83a8..2eda662 100644 --- a/bootstrap/parse.c +++ b/bootstrap/parse.c @@ -439,9 +439,13 @@ lex(struct parser *P) { switch ((c = chr(P))) { case '(': case ')': case '[': case ']': case '{': case '}': case ',': - case ';': case '?': case '~': + case ';': case '~': tok.t = c; return tok; + case '?': + if (chrmatch(P, '?')) tok.t = '\?\?'; + else tok.t = '?'; + return tok; case '.': if (chrmatch(P, '.')) { if (chr(P) != '.') @@ -1720,20 +1724,33 @@ pexlog(struct parser *P) { if (P->used_targty) return ex; tok = lexpeek(P); tokt = tok.t; - if (tokt != TKkw_and && tokt != TKkw_or) + if (tokt != TKkw_and && tokt != TKkw_or && tokt != '?\?') return ex; while (lexmatch(P, &tok, tokt)) { struct expr rhs = pexcmp(P); - if (ex.ty->t != TYbool || rhs.ty->t != TYbool) - fatal(P, tok.span, - "invalid operands %t and %t to binary operator %k", + if (tokt == '?\?') { + const struct type *ty = typeof2(ex.ty, rhs.ty); + if (ex.ty->t != TYptr || rhs.ty->t != TYptr || !ty) + fatal(P, tok.span, + "invalid operands %t and %t to binary operator %k", ex.ty, rhs.ty, tok.t); - ex = (struct expr) { - Ebinop, tok.span, ty_bool, .binop = { - tokt == TKkw_and ? 'and' : 'or', exprdup(ex), exprdup(rhs) - } - }; + ex = (struct expr) { + Ebinop, tok.span, ty, .binop = { + '?\?', exprdup(ex), exprdup(rhs) + } + }; + } else { + if (ex.ty->t != TYbool || rhs.ty->t != TYbool) + fatal(P, tok.span, + "invalid operands %t and %t to binary operator %k", + ex.ty, rhs.ty, tok.t); + ex = (struct expr) { + Ebinop, tok.span, ty_bool, .binop = { + tokt == TKkw_and ? 'and' : 'or', exprdup(ex), exprdup(rhs) + } + }; + } } diff --git a/src/parse.cff b/src/parse.cff index c331986..87ca850 100644 --- a/src/parse.cff +++ b/src/parse.cff @@ -414,9 +414,13 @@ fn lex(P *Parser) Tok { } switch c = chr(P) { case '(', ')', '[', ']', '{', - '}', ',', ';', '?', '~'; + '}', ',', ';', '~'; tok.t = c; return tok; + case '?'; + if chrmatch(P, '?') { tok.t = '??'; } + else { tok.t = '?'; } + return tok; case '.'; if chrmatch(P, '.') { if chrmatch(P, '.') { tok.t = '...'; } @@ -541,7 +545,7 @@ fn finddecl(P *Parser, name *const u8) *Decl { putprimtypes(primenv); } let p = envfind(primenv, name); - return p ? p : envfind(P.curenv, name); + return p ?? envfind(P.curenv, name); } fn putdecl(P *Parser, decl Decl) *Decl { |