From b59bffb882f63d6cf306f85244a70424a592f4de Mon Sep 17 00:00:00 2001 From: gamerbross <55158797+gamerbross@users.noreply.github.com> Date: Thu, 27 Jun 2024 22:09:23 +0200 Subject: [PATCH 1/4] Add support for null coalescing --- TestHScript.hx | 16 ++++++++++++++++ hscript/Parser.hx | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/TestHScript.hx b/TestHScript.hx index db27955..6d17f6a 100644 --- a/TestHScript.hx +++ b/TestHScript.hx @@ -131,6 +131,22 @@ 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} + } + 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); + } + function testIsOperator():Void { var vars = { String: String, diff --git a/hscript/Parser.hx b/hscript/Parser.hx index 12c51e7..9d888d2 100644 --- a/hscript/Parser.hx +++ b/hscript/Parser.hx @@ -33,6 +33,7 @@ enum Token { TBrClose; TDot; TQuestionDot; + TQuestionQuestion; TComma; TSemicolon; TBkOpen; @@ -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, + e1 + )) + ]),pmin(e1)); + return parseExprNext(e); case TPOpen: return parseExprNext(mk(ECall(e1,parseExprList(TPClose)),pmin(e1))); case TBkOpen: @@ -1508,6 +1521,8 @@ class Parser { char = readChar(); if( char == ".".code ) return TQuestionDot; + else if ( char == "?".code ) + return TQuestionQuestion; this.char = char; return TQuestion; case ":".code: return TDoubleDot; @@ -1738,6 +1753,7 @@ class Parser { case TBrClose: "}"; case TDot: "."; case TQuestionDot: "?."; + case TQuestionQuestion: "??"; case TComma: ","; case TSemicolon: ";"; case TBkOpen: "["; From a84dfa1a3bbbd9e64117068b2b36352854f63fc1 Mon Sep 17 00:00:00 2001 From: gamerbross <55158797+gamerbross@users.noreply.github.com> Date: Thu, 27 Jun 2024 22:25:24 +0200 Subject: [PATCH 2/4] Fix code duplication --- hscript/Parser.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hscript/Parser.hx b/hscript/Parser.hx index 9d888d2..fc198e8 100644 --- a/hscript/Parser.hx +++ b/hscript/Parser.hx @@ -830,7 +830,7 @@ class Parser { mk(ETernary( mk(EBinop("==", mk(EIdent(tmp),pmin(e1),pmax(e1)), mk(EIdent("null"),pmin(e1),pmax(e1)))), e2, - e1 + mk(EIdent(tmp),pmin(e1),pmax(e1)) )) ]),pmin(e1)); return parseExprNext(e); From 3b7f21e34e9f11af4eef7c46e4ebc5a0fa1d314d Mon Sep 17 00:00:00 2001 From: gamerbross <55158797+gamerbross@users.noreply.github.com> Date: Wed, 17 Jul 2024 16:37:26 +0200 Subject: [PATCH 3/4] Add "??=" operator --- TestHScript.hx | 6 +++++- hscript/Interp.hx | 1 + hscript/Parser.hx | 8 ++++++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/TestHScript.hx b/TestHScript.hx index 6d17f6a..1caf171 100644 --- a/TestHScript.hx +++ b/TestHScript.hx @@ -137,7 +137,9 @@ class TestHScript extends TestCase { ptnull: null, pt: pt, pt2null: {pt: null}, - pt2: {pt: pt} + pt2: {pt: pt}, + valuenull: null, + value: 10 } assertScript("ptnull?.x ?? 5", 5, vars); assertScript("pt?.x ?? 5", 10, vars); @@ -145,6 +147,8 @@ class TestHScript extends TestCase { assertScript("pt2null?.pt?.x ?? 5", 5, vars); assertScript("pt2?.pt ?? 5", pt, vars); assertScript("pt2?.pt?.x ?? 5", 10, vars); + assertScript("valuenull ??= 5; valuenull", 5, vars); + assertScript("value ??= 5; value", 10, vars); } function testIsOperator():Void { diff --git a/hscript/Interp.hx b/hscript/Interp.hx index 4663239..cda353e 100644 --- a/hscript/Interp.hx +++ b/hscript/Interp.hx @@ -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("??=",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); diff --git a/hscript/Parser.hx b/hscript/Parser.hx index fc198e8..8bc458d 100644 --- a/hscript/Parser.hx +++ b/hscript/Parser.hx @@ -128,7 +128,7 @@ class Parser { ["..."], ["&&"], ["||"], - ["=","+=","-=","*=","/=","%=","<<=",">>=",">>>=","|=","&=","^=","=>"], + ["=","+=","-=","*=","/=","%=","??=","<<=",">>=",">>>=","|=","&=","^=","=>"], ["->"] ]; #if haxe3 @@ -1521,8 +1521,12 @@ class Parser { char = readChar(); if( char == ".".code ) return TQuestionDot; - else if ( char == "?".code ) + else if ( char == "?".code ) { + char = readChar(); + if ( char == "=".code ) + return TOp("??="); return TQuestionQuestion; + } this.char = char; return TQuestion; case ":".code: return TDoubleDot; From 8f88c6f41b0d6180ef85eb3480553d28a7acec90 Mon Sep 17 00:00:00 2001 From: gamerbross <55158797+gamerbross@users.noreply.github.com> Date: Wed, 21 Aug 2024 22:25:43 +0200 Subject: [PATCH 4/4] Fix C++ with trigraphs --- TestHScript.hx | 5 +++++ hscript/Interp.hx | 2 +- hscript/Parser.hx | 4 ++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/TestHScript.hx b/TestHScript.hx index 1caf171..4fbc881 100644 --- a/TestHScript.hx +++ b/TestHScript.hx @@ -147,8 +147,13 @@ class TestHScript extends TestCase { 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 { diff --git a/hscript/Interp.hx b/hscript/Interp.hx index cda353e..170cc83 100644 --- a/hscript/Interp.hx +++ b/hscript/Interp.hx @@ -122,7 +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("??=",function(v1:Dynamic,v2:Dynamic) if ( v1 == null ) return v1 = v2 else return v1); + 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); diff --git a/hscript/Parser.hx b/hscript/Parser.hx index 8bc458d..ed35ed0 100644 --- a/hscript/Parser.hx +++ b/hscript/Parser.hx @@ -128,7 +128,7 @@ class Parser { ["..."], ["&&"], ["||"], - ["=","+=","-=","*=","/=","%=","??=","<<=",">>=",">>>=","|=","&=","^=","=>"], + ["=","+=","-=","*=","/=","%=",#if cpp "??"+"=" #else "??=" #end,"<<=",">>=",">>>=","|=","&=","^=","=>"], ["->"] ]; #if haxe3 @@ -1524,7 +1524,7 @@ class Parser { else if ( char == "?".code ) { char = readChar(); if ( char == "=".code ) - return TOp("??="); + return TOp(#if cpp "??"+"=" #else "??=" #end); return TQuestionQuestion; } this.char = char;