aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2022-08-16 05:42:36 +0200
committerlemon <lsof@mailbox.org>2022-08-16 05:42:36 +0200
commit04c7892134d49f3b295a51cc741affe9f02e374d (patch)
treec94c4501b9d448c057bd736ee7b718daefcb304f
parent5bc23671b5569d86196643f58f4f70997383b4a4 (diff)
nullish coalescing operator ??
-rw-r--r--bootstrap/cgen.c2
-rw-r--r--bootstrap/parse.c37
-rw-r--r--src/parse.cff8
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 {