Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for null coalescing (?? & ??=) #131

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions TestHScript.hx
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,31 @@ class TestHScript extends TestCase {
assertScript("pt2?.pt?.x", 10, vars);
}

function testNullCoalescing():Void {
var pt = {x: 10};
var vars = {
ptnull: null,
pt: pt,
pt2null: {pt: null},
pt2: {pt: pt},
valuenull: null,
value: 10
}
assertScript("ptnull?.x ?? 5", 5, vars);
assertScript("pt?.x ?? 5", 10, vars);
assertScript("pt2null?.pt ?? 5", 5, vars);
assertScript("pt2null?.pt?.x ?? 5", 5, vars);
assertScript("pt2?.pt ?? 5", pt, vars);
assertScript("pt2?.pt?.x ?? 5", 10, vars);
#if cpp
assertScript('valuenull ??${"="} 5; valuenull', 5, vars);
assertScript('value ??${"="} 5; value', 10, vars);
#else
assertScript("valuenull ??= 5; valuenull", 5, vars);
assertScript("value ??= 5; value", 10, vars);
#end
}

function testIsOperator():Void {
var vars = {
String: String,
Expand Down
1 change: 1 addition & 0 deletions hscript/Interp.hx
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ class Interp {
assignOp("*=",function(v1:Float,v2:Float) return v1 * v2);
assignOp("/=",function(v1:Float,v2:Float) return v1 / v2);
assignOp("%=",function(v1:Float,v2:Float) return v1 % v2);
assignOp(#if cpp "??"+"=" #else "??=" #end,function(v1:Dynamic,v2:Dynamic) if ( v1 == null ) return v1 = v2 else return v1);
assignOp("&=",function(v1,v2) return v1 & v2);
assignOp("|=",function(v1,v2) return v1 | v2);
assignOp("^=",function(v1,v2) return v1 ^ v2);
Expand Down
22 changes: 21 additions & 1 deletion hscript/Parser.hx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ enum Token {
TBrClose;
TDot;
TQuestionDot;
TQuestionQuestion;
TComma;
TSemicolon;
TBkOpen;
Expand Down Expand Up @@ -127,7 +128,7 @@ class Parser {
["..."],
["&&"],
["||"],
["=","+=","-=","*=","/=","%=","<<=",">>=",">>>=","|=","&=","^=","=>"],
["=","+=","-=","*=","/=","%=",#if cpp "??"+"=" #else "??=" #end,"<<=",">>=",">>>=","|=","&=","^=","=>"],
["->"]
];
#if haxe3
Expand Down Expand Up @@ -821,6 +822,18 @@ class Parser {
))
]),pmin(e1));
return parseExprNext(e);
case TQuestionQuestion:
var e2 = parseExpr();
var tmp = "__a_" + (uid++);
var e = mk(EBlock([
mk(EVar(tmp, null, e1), pmin(e1), pmax(e1)),
mk(ETernary(
mk(EBinop("==", mk(EIdent(tmp),pmin(e1),pmax(e1)), mk(EIdent("null"),pmin(e1),pmax(e1)))),
e2,
mk(EIdent(tmp),pmin(e1),pmax(e1))
))
]),pmin(e1));
return parseExprNext(e);
case TPOpen:
return parseExprNext(mk(ECall(e1,parseExprList(TPClose)),pmin(e1)));
case TBkOpen:
Expand Down Expand Up @@ -1508,6 +1521,12 @@ class Parser {
char = readChar();
if( char == ".".code )
return TQuestionDot;
else if ( char == "?".code ) {
char = readChar();
if ( char == "=".code )
return TOp(#if cpp "??"+"=" #else "??=" #end);
return TQuestionQuestion;
}
this.char = char;
return TQuestion;
case ":".code: return TDoubleDot;
Expand Down Expand Up @@ -1738,6 +1757,7 @@ class Parser {
case TBrClose: "}";
case TDot: ".";
case TQuestionDot: "?.";
case TQuestionQuestion: "??";
case TComma: ",";
case TSemicolon: ";";
case TBkOpen: "[";
Expand Down
Loading