Skip to content

Commit b92fcae

Browse files
authored
Add support for null safe field access (#127)
1 parent daaa4e5 commit b92fcae

File tree

2 files changed

+36
-1
lines changed

2 files changed

+36
-1
lines changed

TestHScript.hx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,22 @@ class TestHScript extends TestCase {
115115
assertScript("var a = 10; var b = 5; a - b / 2", 7.5);
116116
}
117117

118+
function testNullFieldAccess():Void {
119+
var pt = {x : 10};
120+
var vars = {
121+
ptnull : null,
122+
pt: pt,
123+
pt2null : {pt : null},
124+
pt2: {pt : pt}
125+
}
126+
assertScript("ptnull?.x", null, vars);
127+
assertScript("pt?.x", 10, vars);
128+
assertScript("pt2null?.pt", null, vars);
129+
assertScript("pt2null?.pt?.x", null, vars);
130+
assertScript("pt2?.pt", pt, vars);
131+
assertScript("pt2?.pt?.x", 10, vars);
132+
}
133+
118134
function testMap():Void {
119135
var objKey = { ok:true };
120136
var vars = {

hscript/Parser.hx

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ enum Token {
3232
TBrOpen;
3333
TBrClose;
3434
TDot;
35+
TQuestionDot;
3536
TComma;
3637
TSemicolon;
3738
TBkOpen;
@@ -806,6 +807,18 @@ class Parser {
806807
case TDot:
807808
var field = getIdent();
808809
return parseExprNext(mk(EField(e1,field),pmin(e1)));
810+
case TQuestionDot:
811+
var field = getIdent();
812+
var tmp = "__a_" + (uid++);
813+
var e = mk(EBlock([
814+
mk(EVar(tmp, null, e1), pmin(e1), pmax(e1)),
815+
mk(ETernary(
816+
mk(EBinop("==", mk(EIdent(tmp),pmin(e1),pmax(e1)), mk(EIdent("null"),pmin(e1),pmax(e1)))),
817+
mk(EIdent("null"),pmin(e1),pmax(e1)),
818+
mk(EField(mk(EIdent(tmp),pmin(e1),pmax(e1)),field),pmin(e1))
819+
))
820+
]),pmin(e1));
821+
return parseExprNext(e);
809822
case TPOpen:
810823
return parseExprNext(mk(ECall(e1,parseExprList(TPClose)),pmin(e1)));
811824
case TBkOpen:
@@ -1489,7 +1502,12 @@ class Parser {
14891502
case "[".code: return TBkOpen;
14901503
case "]".code: return TBkClose;
14911504
case "'".code, '"'.code: return TConst( CString(readString(char)) );
1492-
case "?".code: return TQuestion;
1505+
case "?".code:
1506+
char = readChar();
1507+
if( char == ".".code )
1508+
return TQuestionDot;
1509+
this.char = char;
1510+
return TQuestion;
14931511
case ":".code: return TDoubleDot;
14941512
case '='.code:
14951513
char = readChar();
@@ -1717,6 +1735,7 @@ class Parser {
17171735
case TBrOpen: "{";
17181736
case TBrClose: "}";
17191737
case TDot: ".";
1738+
case TQuestionDot: "?.";
17201739
case TComma: ",";
17211740
case TSemicolon: ";";
17221741
case TBkOpen: "[";

0 commit comments

Comments
 (0)