diff --git a/TestHScript.hx b/TestHScript.hx index a3fddc7..844eda1 100644 --- a/TestHScript.hx +++ b/TestHScript.hx @@ -154,6 +154,7 @@ class TestHScript extends TestCase { assertScript("ptnull?.x", null, vars); assertScript("ptnull?.pt.x", null, vars); assertScript("ptnull?.call()", null, vars); + assertScript("ptnull?.pt.call()", null, vars); assertScript("pt?.x", 10, vars); assertScript("pt?.call()", 11, vars); assertScript("pt2null?.pt", null, vars); @@ -162,6 +163,11 @@ class TestHScript extends TestCase { assertScript("pt2?.pt", pt, vars); assertScript("pt2?.pt?.x", 10, vars); assertScript("pt2?.pt?.call()", 11, vars); + assertScript("ptnull ?? 12", 12, vars); + assertScript("pt2null.pt ?? 12", 12, vars); + assertScript("ptnull?.x ?? 12", 12, vars); + assertScript("pt?.x ?? 12", 10, vars); + assertScript("pt.y ?? 12", 12, vars); } function testIsOperator():Void { diff --git a/hscript/JsInterp.hx b/hscript/JsInterp.hx index 9161c44..69f09ea 100644 --- a/hscript/JsInterp.hx +++ b/hscript/JsInterp.hx @@ -222,7 +222,7 @@ class JsInterp extends Interp { return '$$i.get(${exprValue(e)},"$f")'; case EBinop(op, e1, e2): switch( op ) { - case "+","-","*","/","%","&","|","^",">>","<<",">>>","==","!=",">=","<=",">","<": + case "+","-","*","/","%","&","|","^",">>","<<",">>>","==","!=",">=","<=",">","<","??": return '${exprOp(e1)} $op ${exprOp(e2)}'; case "||","&&": return '(${exprCond(e1)} $op ${exprCond(e2)})'; diff --git a/hscript/Parser.hx b/hscript/Parser.hx index 83988d7..0f7ccba 100644 --- a/hscript/Parser.hx +++ b/hscript/Parser.hx @@ -33,7 +33,6 @@ enum Token { TBrClose; TDot; TQuestionDot; - TQuestionDouble; TComma; TSemicolon; TBkOpen; @@ -837,10 +836,10 @@ class Parser { } } - function parseExprNext( e1 : Expr ) { + function parseExprNext( e1 : Expr, ?noOp = false ) { var tk = token(); switch( tk ) { - case TOp(op): + case TOp(op) if( !noOp ): if( op == "->" ) { // single arg reinterpretation of `f -> e` , `(f) -> e` and `(f:T) -> e` @@ -864,15 +863,15 @@ class Parser { return parseExprNext(mk(EUnop(op,false,e1),pmin(e1))); } return makeBinop(op,e1,parseExpr()); - case TId(op) if( opPriority.exists(op) ): + case TId(op) if( !noOp && opPriority.exists(op) ): return parseExprNext(makeBinop(op,e1,parseExpr())); case TDot: var field = getIdent(); - return parseExprNext(mk(EField(e1,field),pmin(e1))); + return parseExprNext(mk(EField(e1,field),pmin(e1)), noOp); case TQuestionDot: var tmp = "__a_" + (uid++); push(TDot); - var e2 = parseExprNext(mk(EIdent(tmp),pmin(e1),pmax(e1))); + var e2 = parseExprNext(mk(EIdent(tmp),pmin(e1),pmax(e1)), true); var e = mk(EBlock([ mk(EVar(tmp, null, e1), pmin(e1), pmax(e1)), mk(ETernary( @@ -881,21 +880,18 @@ class Parser { e2 )) ]),pmin(e1)); - return e; + return parseExprNext(e, noOp); case TPOpen: - return parseExprNext(mk(ECall(e1,parseExprList(TPClose)),pmin(e1))); + return parseExprNext(mk(ECall(e1,parseExprList(TPClose)),pmin(e1)), noOp); case TBkOpen: var e2 = parseExpr(); ensure(TBkClose); - return parseExprNext(mk(EArray(e1,e2),pmin(e1))); - case TQuestion: + return parseExprNext(mk(EArray(e1,e2),pmin(e1)), noOp); + case TQuestion if( !noOp ): var e2 = parseExpr(); ensure(TDoubleDot); var e3 = parseExpr(); return mk(ETernary(e1,e2,e3),pmin(e1),pmax(e3)); - case TQuestionDouble: - var e2 = parseExpr(); - return makeBinop("??",e1,e2); default: push(tk); return e1; @@ -1573,7 +1569,7 @@ class Parser { if( char == ".".code ) return TQuestionDot; if( char == "?".code ) - return TQuestionDouble; + return TOp("??"); this.char = char; return TQuestion; case ":".code: return TDoubleDot; @@ -1803,7 +1799,6 @@ class Parser { case TBrClose: "}"; case TDot: "."; case TQuestionDot: "?."; - case TQuestionDouble: "??"; case TComma: ","; case TSemicolon: ";"; case TBkOpen: "[";