summaryrefslogtreecommitdiff
path: root/parse
diff options
context:
space:
mode:
authorOri Bernstein <ori@eigenstate.org>2018-03-06 11:47:45 -0800
committerOri Bernstein <ori@markovcorp.com>2018-03-06 11:47:45 -0800
commit7b024df82962f4bfe24db5b74fe2a92aac26cf8e (patch)
tree71c499cbc5964b8a9823fef21d1e8b09ee98c0b3 /parse
parent27b4f894b3b7456b64908ad8c2d50ba66ebb513a (diff)
downloadmc-7b024df82962f4bfe24db5b74fe2a92aac26cf8e.tar.gz
Add ternary operator.
Diffstat (limited to 'parse')
-rw-r--r--parse/gram.y13
-rw-r--r--parse/infer.c96
-rw-r--r--parse/ops.def1
-rw-r--r--parse/tok.c1
4 files changed, 48 insertions, 63 deletions
diff --git a/parse/gram.y b/parse/gram.y
index 5c73295..8fb448b 100644
--- a/parse/gram.y
+++ b/parse/gram.y
@@ -83,6 +83,7 @@ static void setupinit(Node *n);
%token<tok> Tcsqbrac /* ] */
%token<tok> Ttick /* ` */
%token<tok> Tderef /* # */
+%token<tok> Tqmark /* ? */
%token<tok> Ttype /* type */
%token<tok> Tfor /* for */
@@ -145,7 +146,7 @@ static void setupinit(Node *n);
%type<node> exprln retexpr goto continue break expr atomicexpr
%type<node> littok literal lorexpr landexpr borexpr strlit bandexpr
-%type<node> cmpexpr addexpr mulexpr shiftexpr prefixexpr
+%type<node> cmpexpr addexpr mulexpr shiftexpr prefixexpr ternexpr
%type<node> postfixexpr funclit seqlit tuplit name block stmt label
%type<node> use fnparam declbody declcore typedeclcore autodecl structent
%type<node> arrayelt structelt tuphead ifstmt forstmt whilestmt
@@ -692,9 +693,9 @@ optexprln
exprln : expr Tendln
;
-expr : lorexpr asnop expr
+expr : ternexpr asnop expr
{$$ = mkexpr($1->loc, binop($2->type), $1, $3, NULL);}
- | lorexpr
+ | ternexpr
;
asnop : Tasn
@@ -710,6 +711,12 @@ asnop : Tasn
| Tbsreq /* >>= */
;
+ternexpr
+ : lorexpr
+ | lorexpr Tqmark lorexpr Tcolon lorexpr
+ {$$ = mkexpr($1->loc, Otern, $1, $3, $5, NULL);}
+ ;
+
lorexpr : lorexpr Tlor landexpr
{$$ = mkexpr($1->loc, binop($2->type), $1, $3, NULL);}
| landexpr
diff --git a/parse/infer.c b/parse/infer.c
index 360ca36..5424be9 100644
--- a/parse/infer.c
+++ b/parse/infer.c
@@ -1772,10 +1772,10 @@ inferexpr(Node **np, Type *ret, int *sawret)
break;
case Oret: /* -> @a -> void */
infersub(n, ret, sawret, &isconst);
- if (sawret)
- *sawret = 1;
if (!ret)
fatal(n, "returns are not valid near %s", ctxstr(n));
+ if (sawret)
+ *sawret = 1;
t = unify(n, ret, type(args[0]));
settype(n, t);
break;
@@ -1817,70 +1817,46 @@ inferexpr(Node **np, Type *ret, int *sawret)
case Ostruct: inferstruct(n, &n->expr.isconst); break;
case Oarr: inferarray(n, &n->expr.isconst); break;
case Olit: /* <lit>:@a::tyclass -> @a */
- infersub(n, ret, sawret, &isconst);
- switch (args[0]->lit.littype) {
- case Lfunc:
- infernode(&args[0]->lit.fnval, NULL, NULL);
- /* FIXME: env capture means this is non-const */
- n->expr.isconst = 1;
- break;
- case Llbl:
- s = getlbl(curstab(), args[0]->loc, args[0]->lit.lblname);
- if (!s)
- fatal(n, "unable to find label %s in function scope\n", args[0]->lit.lblname);
- *np = s;
- break;
- default:
- n->expr.isconst = 1;
- break;
- }
- settype(n, type(args[0]));
- break;
+ infersub(n, ret, sawret, &isconst);
+ switch (args[0]->lit.littype) {
+ case Lfunc:
+ infernode(&args[0]->lit.fnval, NULL, NULL);
+ /* FIXME: env capture means this is non-const */
+ n->expr.isconst = 1;
+ break;
+ case Llbl:
+ s = getlbl(curstab(), args[0]->loc, args[0]->lit.lblname);
+ if (!s)
+ fatal(n, "unable to find label %s in function scope\n", args[0]->lit.lblname);
+ *np = s;
+ break;
+ default:
+ n->expr.isconst = 1;
+ break;
+ }
+ settype(n, type(args[0]));
+ break;
+ case Otern:
+ infersub(n, NULL, sawret, &isconst);
+ unify(n, type(args[0]), mktype(n->loc, Tybool));
+ unify(n, type(args[1]), type(args[2]));
+ settype(n, type(args[1]));
+ break;
case Oundef:
- infersub(n, ret, sawret, &isconst);
- settype(n, mktype(n->loc, Tyvoid));
- break;
+ infersub(n, ret, sawret, &isconst);
+ settype(n, mktype(n->loc, Tyvoid));
+ break;
case Odef:
case Odead:
n->expr.type = mktype(n->loc, Tyvoid);
break;
/* unexpected in frontend */
- case Obad:
- case Ocjmp:
- case Ovjmp:
- case Oset:
- case Oslbase:
- case Osllen:
- case Outag:
- case Ocallind:
- case Oblit:
- case Oclear:
- case Oudata:
- case Otrunc:
- case Oswiden:
- case Ozwiden:
- case Oint2flt:
- case Oflt2int:
- case Oflt2flt:
- case Ofadd:
- case Ofsub:
- case Ofmul:
- case Ofdiv:
- case Ofneg:
- case Ofeq:
- case Ofne:
- case Ofgt:
- case Ofge:
- case Oflt:
- case Ofle:
- case Oueq:
- case Oune:
- case Ougt:
- case Ouge:
- case Oult:
- case Oule:
- case Otupget:
- case Numops:
+ case Obad: case Ocjmp: case Ovjmp: case Oset: case Oslbase: case Osllen:
+ case Outag: case Ocallind: case Oblit: case Oclear: case Oudata: case Otrunc:
+ case Oswiden: case Ozwiden: case Oint2flt: case Oflt2int: case Oflt2flt:
+ case Ofadd: case Ofsub: case Ofmul: case Ofdiv: case Ofneg: case Ofeq:
+ case Ofne: case Ofgt: case Ofge: case Oflt: case Ofle: case Oueq: case Oune:
+ case Ougt: case Ouge: case Oult: case Oule: case Otupget: case Numops:
die("Should not see %s in fe", opstr[exprop(n)]);
break;
}
diff --git a/parse/ops.def b/parse/ops.def
index dd9447a..c29ca1e 100644
--- a/parse/ops.def
+++ b/parse/ops.def
@@ -55,6 +55,7 @@ O(Oucon, 1, OTmisc, "`")
O(Otup, 1, OTmisc, NULL)
O(Ostruct, 1, OTmisc, NULL)
O(Oarr, 1, OTmisc, NULL)
+O(Otern, 1, OTmisc, "?:")
/* all below this point are backend-only */
O(Odead, 0, OTmisc, "DEAD") /* dead code */
diff --git a/parse/tok.c b/parse/tok.c
index eb5ba1c..5c55cbc 100644
--- a/parse/tok.c
+++ b/parse/tok.c
@@ -522,6 +522,7 @@ oper(void)
case ',': tt = Tcomma; break;
case '`': tt = Ttick; break;
case '#': tt = Tderef; break;
+ case '?': tt = Tqmark; break;
case ':':
if (match(':'))
tt = Twith;