Skip to content

Commit

Permalink
Add support for null safe field access (#127)
Browse files Browse the repository at this point in the history
  • Loading branch information
yuxiaomao authored May 31, 2024
1 parent daaa4e5 commit b92fcae
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 1 deletion.
16 changes: 16 additions & 0 deletions TestHScript.hx
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,22 @@ class TestHScript extends TestCase {
assertScript("var a = 10; var b = 5; a - b / 2", 7.5);
}

function testNullFieldAccess():Void {
var pt = {x : 10};
var vars = {
ptnull : null,
pt: pt,
pt2null : {pt : null},
pt2: {pt : pt}
}
assertScript("ptnull?.x", null, vars);
assertScript("pt?.x", 10, vars);
assertScript("pt2null?.pt", null, vars);
assertScript("pt2null?.pt?.x", null, vars);
assertScript("pt2?.pt", pt, vars);
assertScript("pt2?.pt?.x", 10, vars);
}

function testMap():Void {
var objKey = { ok:true };
var vars = {
Expand Down
21 changes: 20 additions & 1 deletion hscript/Parser.hx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ enum Token {
TBrOpen;
TBrClose;
TDot;
TQuestionDot;
TComma;
TSemicolon;
TBkOpen;
Expand Down Expand Up @@ -806,6 +807,18 @@ class Parser {
case TDot:
var field = getIdent();
return parseExprNext(mk(EField(e1,field),pmin(e1)));
case TQuestionDot:
var field = getIdent();
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)))),
mk(EIdent("null"),pmin(e1),pmax(e1)),
mk(EField(mk(EIdent(tmp),pmin(e1),pmax(e1)),field),pmin(e1))
))
]),pmin(e1));
return parseExprNext(e);
case TPOpen:
return parseExprNext(mk(ECall(e1,parseExprList(TPClose)),pmin(e1)));
case TBkOpen:
Expand Down Expand Up @@ -1489,7 +1502,12 @@ class Parser {
case "[".code: return TBkOpen;
case "]".code: return TBkClose;
case "'".code, '"'.code: return TConst( CString(readString(char)) );
case "?".code: return TQuestion;
case "?".code:
char = readChar();
if( char == ".".code )
return TQuestionDot;
this.char = char;
return TQuestion;
case ":".code: return TDoubleDot;
case '='.code:
char = readChar();
Expand Down Expand Up @@ -1717,6 +1735,7 @@ class Parser {
case TBrOpen: "{";
case TBrClose: "}";
case TDot: ".";
case TQuestionDot: "?.";
case TComma: ",";
case TSemicolon: ";";
case TBkOpen: "[";
Expand Down

0 comments on commit b92fcae

Please sign in to comment.