You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@royale.apache.org by jo...@apache.org on 2022/12/12 22:31:50 UTC

[royale-compiler] branch develop updated: BinaryOperatorEmitter: Fix setting Date properties inside chained assignment (closes #212)

This is an automated email from the ASF dual-hosted git repository.

joshtynjala pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/royale-compiler.git


The following commit(s) were added to refs/heads/develop by this push:
     new d42679c7d BinaryOperatorEmitter: Fix setting Date properties inside chained assignment (closes #212)
d42679c7d is described below

commit d42679c7daf821a28b315dbcfabdef67308dddf9
Author: Josh Tynjala <jo...@apache.org>
AuthorDate: Mon Dec 12 14:26:43 2022 -0800

    BinaryOperatorEmitter: Fix setting Date properties inside chained assignment (closes #212)
    
    Previously, something like this would result in NaN for hours and minutes: d.hours = d.minutes = d.seconds = xyz
    
    This is because setSeconds/setMinutes and other methods return void. The fix is to use a comma operator and call getSeconds/getMinutes so that the value propagates. The double function call should be wrapped in parentheses to avoid confusion with commas in other contexts, such as function calls.
    
    The code in the example above becomes: d.setHours((d.setMinutes((d.setSeconds(xyz), d.getSeconds())), d.getMinutes()));
    
    Notice that the setHours() call doesn't include a matching getHours() call because it's not necessary to propagate the value further.
---
 .../codegen/js/jx/BinaryOperatorEmitter.java       |  25 +-
 .../codegen/js/royale/TestRoyaleGlobalClasses.java | 316 +++++++++++++++++++++
 2 files changed, 340 insertions(+), 1 deletion(-)

diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/BinaryOperatorEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/BinaryOperatorEmitter.java
index 5a1890d46..b5b3b37ba 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/BinaryOperatorEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/BinaryOperatorEmitter.java
@@ -889,7 +889,9 @@ public class BinaryOperatorEmitter extends JSSubEmitter implements
     void specialCaseDate(IBinaryOperatorNode node, MemberAccessExpressionNode leftSide)
     {
         if (ASNodeUtils.hasParenOpen(node))
+		{
             write(ASEmitterTokens.PAREN_OPEN);
+		}
 
     	MemberAccessExpressionNode dateNode = (MemberAccessExpressionNode)leftSide;
         IIdentifierNode rightSide = (IIdentifierNode)dateNode.getRightOperandNode();
@@ -898,6 +900,11 @@ public class BinaryOperatorEmitter extends JSSubEmitter implements
                 && !op.contains("==")
                 && !(op.startsWith("<") || op.startsWith(">") || op
                         .startsWith("!"));
+		boolean assignmentNeedsGetter = isAssignment && !(node.getParent() instanceof IBlockNode);
+		if (assignmentNeedsGetter)
+		{
+            write(ASEmitterTokens.PAREN_OPEN);
+		}
         getWalker().walk(dateNode.getLeftOperandNode());
         String rightName = rightSide.getName();
         if (isAssignment)
@@ -920,6 +927,17 @@ public class BinaryOperatorEmitter extends JSSubEmitter implements
 	        }
 	        getWalker().walk(node.getRightOperandNode());
 	        write(ASEmitterTokens.PAREN_CLOSE);
+			if (assignmentNeedsGetter)
+			{
+				write(ASEmitterTokens.COMMA);
+	        	write(ASEmitterTokens.SPACE);
+				getWalker().walk(dateNode.getLeftOperandNode());
+				DatePropertiesGetters propGetter = DatePropertiesGetters.valueOf(rightName.toUpperCase());
+				write(ASEmitterTokens.MEMBER_ACCESS);
+				write(propGetter.getFunctionName());
+				write(ASEmitterTokens.PAREN_OPEN);
+				write(ASEmitterTokens.PAREN_CLOSE);
+			}
         }
         else
         {
@@ -933,8 +951,13 @@ public class BinaryOperatorEmitter extends JSSubEmitter implements
         	write(ASEmitterTokens.SPACE);
 	        getWalker().walk(node.getRightOperandNode());
         }
-
+		if (assignmentNeedsGetter)
+		{
+            write(ASEmitterTokens.PAREN_CLOSE);
+		}
         if (ASNodeUtils.hasParenOpen(node))
+		{
             write(ASEmitterTokens.PAREN_CLOSE);
+		}
     }
 }
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalClasses.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalClasses.java
index 582b920b9..403ab413e 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalClasses.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalClasses.java
@@ -316,6 +316,15 @@ public class TestRoyaleGlobalClasses extends TestGoogGlobalClasses
         assertOut("var /** @type {*} */ b = org.apache.royale.utils.Language.resolveUncertain(new a('test'))");
     }
 
+    @Test
+    public void testDateGetSeconds()
+    {
+        IVariableNode node = getVariable("var a:Date = new Date(); var b:Number = a.seconds");
+        node = (IVariableNode)(node.getParent().getChild(1));
+        asBlockWalker.visitVariable(node);
+        assertOut("var /** @type {number} */ b = a.getSeconds()");
+    }
+
     @Test
     public void testDateSetSeconds()
     {
@@ -324,6 +333,49 @@ public class TestRoyaleGlobalClasses extends TestGoogGlobalClasses
         assertOut("a.setSeconds(10)");
     }
 
+    @Test
+    public void testDateGetAndSetSeconds()
+    {
+    	IBinaryOperatorNode node = getBinaryNode("var a:Date = new Date(); var b:Number = a.seconds = 10");
+        asBlockWalker.visitBinaryOperator(node);
+        assertOut("(a.setSeconds(10), a.getSeconds())");
+    }
+
+    @Test
+    public void testDateIncreaseSeconds()
+    {
+    	IBinaryOperatorNode node = getBinaryNode("var a:Date = new Date(); a.seconds += 10");
+        asBlockWalker.visitBinaryOperator(node);
+        assertOut("a.setSeconds(a.getSeconds() + 10)");
+    }
+
+    @Test
+    public void testDateGetSecondsMethod()
+    {
+        IVariableNode node = getVariable("var a:Date = new Date(); var b:Number = a.getSeconds()");
+        node = (IVariableNode)(node.getParent().getChild(1));
+        asBlockWalker.visitVariable(node);
+        assertOut("var /** @type {number} */ b = a.getSeconds()");
+    }
+
+    @Test
+    public void testDateSetSecondsMethod()
+    {
+    	IBinaryOperatorNode node = getBinaryNode("var a:Date = new Date(); a.setSeconds(10, 0)");
+    	IFunctionCallNode parentNode = (IFunctionCallNode)(node.getParent());
+        asBlockWalker.visitFunctionCall(parentNode);
+        assertOut("a.setSeconds(10, 0)");
+    }
+
+    @Test
+    public void testDateGetDate()
+    {
+        IVariableNode node = getVariable("var a:Date = new Date(); var b:Number = a.date");
+        node = (IVariableNode)(node.getParent().getChild(1));
+        asBlockWalker.visitVariable(node);
+        assertOut("var /** @type {number} */ b = a.getDate()");
+    }
+
     @Test
     public void testDateSetDate()
     {
@@ -332,6 +384,40 @@ public class TestRoyaleGlobalClasses extends TestGoogGlobalClasses
         assertOut("a.setDate(10)");
     }
 
+    @Test
+    public void testDateGetAndSetDate()
+    {
+    	IBinaryOperatorNode node = getBinaryNode("var a:Date = new Date(); var b:Number = a.date = 10");
+        asBlockWalker.visitBinaryOperator(node);
+        assertOut("(a.setDate(10), a.getDate())");
+    }
+
+    @Test
+    public void testDateIncreaseDate()
+    {
+    	IBinaryOperatorNode node = getBinaryNode("var a:Date = new Date(); a.date += 10");
+        asBlockWalker.visitBinaryOperator(node);
+        assertOut("a.setDate(a.getDate() + 10)");
+    }
+
+    @Test
+    public void testDateGetDateMethod()
+    {
+        IVariableNode node = getVariable("var a:Date = new Date(); var b:Number = a.getDate()");
+        node = (IVariableNode)(node.getParent().getChild(1));
+        asBlockWalker.visitVariable(node);
+        assertOut("var /** @type {number} */ b = a.getDate()");
+    }
+
+    @Test
+    public void testDateSetDateMethod()
+    {
+    	IBinaryOperatorNode node = getBinaryNode("var a:Date = new Date(); a.setDate(10)");
+    	IFunctionCallNode parentNode = (IFunctionCallNode)(node.getParent());
+        asBlockWalker.visitFunctionCall(parentNode);
+        assertOut("a.setDate(10)");
+    }
+
     @Test
     public void testDateGetTimeInMilliseconds()
     {
@@ -357,6 +443,24 @@ public class TestRoyaleGlobalClasses extends TestGoogGlobalClasses
         assertOut("a.setTime(a.getTime() + 10)");
     }
 
+    @Test
+    public void testDateGetTimeInMillisecondsMethod()
+    {
+        IVariableNode node = getVariable("var a:Date = new Date(); var b:Number = a.getTime()");
+        node = (IVariableNode)(node.getParent().getChild(1));
+        asBlockWalker.visitVariable(node);
+        assertOut("var /** @type {number} */ b = a.getTime()");
+    }
+
+    @Test
+    public void testDateSetTimeInMillisecondsMethod()
+    {
+    	IBinaryOperatorNode node = getBinaryNode("var a:Date = new Date(); a.setTime(10)");
+    	IFunctionCallNode parentNode = (IFunctionCallNode)(node.getParent());
+        asBlockWalker.visitFunctionCall(parentNode);
+        assertOut("a.setTime(10)");
+    }
+
     @Test
     public void testDateGetMinutes()
     {
@@ -374,6 +478,14 @@ public class TestRoyaleGlobalClasses extends TestGoogGlobalClasses
         assertOut("a.setMinutes(10)");
     }
 
+    @Test
+    public void testDateGetAndSetMinutes()
+    {
+    	IBinaryOperatorNode node = getBinaryNode("var a:Date = new Date(); var b:Number = a.minutes = 10");
+        asBlockWalker.visitBinaryOperator(node);
+        assertOut("(a.setMinutes(10), a.getMinutes())");
+    }
+
     @Test
     public void testDateIncreaseMinutes()
     {
@@ -400,6 +512,210 @@ public class TestRoyaleGlobalClasses extends TestGoogGlobalClasses
         assertOut("a.setMinutes(10, 0, 0)");
     }
 
+    @Test
+    public void testDateGetHours()
+    {
+        IVariableNode node = getVariable("var a:Date = new Date(); var b:Number = a.hours");
+        node = (IVariableNode)(node.getParent().getChild(1));
+        asBlockWalker.visitVariable(node);
+        assertOut("var /** @type {number} */ b = a.getHours()");
+    }
+
+    @Test
+    public void testDateSetHours()
+    {
+    	IBinaryOperatorNode node = getBinaryNode("var a:Date = new Date(); a.hours = 10");
+        asBlockWalker.visitBinaryOperator(node);
+        assertOut("a.setHours(10)");
+    }
+
+    @Test
+    public void testDateGetAndSetHours()
+    {
+    	IBinaryOperatorNode node = getBinaryNode("var a:Date = new Date(); var b:Number = a.hours = 10");
+        asBlockWalker.visitBinaryOperator(node);
+        assertOut("(a.setHours(10), a.getHours())");
+    }
+
+    @Test
+    public void testDateIncreaseHours()
+    {
+    	IBinaryOperatorNode node = getBinaryNode("var a:Date = new Date(); a.hours += 10");
+        asBlockWalker.visitBinaryOperator(node);
+        assertOut("a.setHours(a.getHours() + 10)");
+    }
+
+    @Test
+    public void testDateGetHoursMethod()
+    {
+        IVariableNode node = getVariable("var a:Date = new Date(); var b:Number = a.getHours()");
+        node = (IVariableNode)(node.getParent().getChild(1));
+        asBlockWalker.visitVariable(node);
+        assertOut("var /** @type {number} */ b = a.getHours()");
+    }
+    
+    @Test
+    public void testDateSetHoursMethod()
+    {
+    	IBinaryOperatorNode node = getBinaryNode("var a:Date = new Date(); a.setHours(10, 0, 0, 0)");
+    	IFunctionCallNode parentNode = (IFunctionCallNode)(node.getParent());
+        asBlockWalker.visitFunctionCall(parentNode);
+        assertOut("a.setHours(10, 0, 0, 0)");
+    }
+
+    @Test
+    public void testDateGetMilliseconds()
+    {
+        IVariableNode node = getVariable("var a:Date = new Date(); var b:Number = a.milliseconds");
+        node = (IVariableNode)(node.getParent().getChild(1));
+        asBlockWalker.visitVariable(node);
+        assertOut("var /** @type {number} */ b = a.getMilliseconds()");
+    }
+
+    @Test
+    public void testDateSetMilliseconds()
+    {
+    	IBinaryOperatorNode node = getBinaryNode("var a:Date = new Date(); a.milliseconds = 10");
+        asBlockWalker.visitBinaryOperator(node);
+        assertOut("a.setMilliseconds(10)");
+    }
+
+    @Test
+    public void testDateGetAndSetMilliseconds()
+    {
+    	IBinaryOperatorNode node = getBinaryNode("var a:Date = new Date(); var b:Number = a.milliseconds = 10");
+        asBlockWalker.visitBinaryOperator(node);
+        assertOut("(a.setMilliseconds(10), a.getMilliseconds())");
+    }
+
+    @Test
+    public void testDateIncreaseMilliseconds()
+    {
+    	IBinaryOperatorNode node = getBinaryNode("var a:Date = new Date(); a.milliseconds += 10");
+        asBlockWalker.visitBinaryOperator(node);
+        assertOut("a.setMilliseconds(a.getMilliseconds() + 10)");
+    }
+
+    @Test
+    public void testDateGetMillisecondsMethod()
+    {
+        IVariableNode node = getVariable("var a:Date = new Date(); var b:Number = a.getMilliseconds()");
+        node = (IVariableNode)(node.getParent().getChild(1));
+        asBlockWalker.visitVariable(node);
+        assertOut("var /** @type {number} */ b = a.getMilliseconds()");
+    }
+    
+    @Test
+    public void testDateSetMillisecondsMethod()
+    {
+    	IBinaryOperatorNode node = getBinaryNode("var a:Date = new Date(); a.setMilliseconds(10)");
+    	IFunctionCallNode parentNode = (IFunctionCallNode)(node.getParent());
+        asBlockWalker.visitFunctionCall(parentNode);
+        assertOut("a.setMilliseconds(10)");
+    }
+
+    @Test
+    public void testDateGetMonth()
+    {
+        IVariableNode node = getVariable("var a:Date = new Date(); var b:Number = a.month");
+        node = (IVariableNode)(node.getParent().getChild(1));
+        asBlockWalker.visitVariable(node);
+        assertOut("var /** @type {number} */ b = a.getMonth()");
+    }
+
+    @Test
+    public void testDateSetMonth()
+    {
+    	IBinaryOperatorNode node = getBinaryNode("var a:Date = new Date(); a.month = 10");
+        asBlockWalker.visitBinaryOperator(node);
+        assertOut("a.setMonth(10)");
+    }
+
+    @Test
+    public void testDateGetAndSetMonth()
+    {
+    	IBinaryOperatorNode node = getBinaryNode("var a:Date = new Date(); var b:Number = a.month = 10");
+        asBlockWalker.visitBinaryOperator(node);
+        assertOut("(a.setMonth(10), a.getMonth())");
+    }
+
+    @Test
+    public void testDateIncreaseMonth()
+    {
+    	IBinaryOperatorNode node = getBinaryNode("var a:Date = new Date(); a.month += 10");
+        asBlockWalker.visitBinaryOperator(node);
+        assertOut("a.setMonth(a.getMonth() + 10)");
+    }
+
+    @Test
+    public void testDateGetMonthMethod()
+    {
+        IVariableNode node = getVariable("var a:Date = new Date(); var b:Number = a.getMonth()");
+        node = (IVariableNode)(node.getParent().getChild(1));
+        asBlockWalker.visitVariable(node);
+        assertOut("var /** @type {number} */ b = a.getMonth()");
+    }
+    
+    @Test
+    public void testDateSetMonthMethod()
+    {
+    	IBinaryOperatorNode node = getBinaryNode("var a:Date = new Date(); a.setMonth(10, 0)");
+    	IFunctionCallNode parentNode = (IFunctionCallNode)(node.getParent());
+        asBlockWalker.visitFunctionCall(parentNode);
+        assertOut("a.setMonth(10, 0)");
+    }
+
+    @Test
+    public void testDateGetFullYear()
+    {
+        IVariableNode node = getVariable("var a:Date = new Date(); var b:Number = a.fullYear");
+        node = (IVariableNode)(node.getParent().getChild(1));
+        asBlockWalker.visitVariable(node);
+        assertOut("var /** @type {number} */ b = a.getFullYear()");
+    }
+
+    @Test
+    public void testDateSetFullYear()
+    {
+    	IBinaryOperatorNode node = getBinaryNode("var a:Date = new Date(); a.fullYear = 10");
+        asBlockWalker.visitBinaryOperator(node);
+        assertOut("a.setFullYear(10)");
+    }
+
+    @Test
+    public void testDateGetAndSetFullYear()
+    {
+    	IBinaryOperatorNode node = getBinaryNode("var a:Date = new Date(); var b:Number = a.fullYear = 10");
+        asBlockWalker.visitBinaryOperator(node);
+        assertOut("(a.setFullYear(10), a.getFullYear())");
+    }
+
+    @Test
+    public void testDateIncreaseFullYear()
+    {
+    	IBinaryOperatorNode node = getBinaryNode("var a:Date = new Date(); a.fullYear += 10");
+        asBlockWalker.visitBinaryOperator(node);
+        assertOut("a.setFullYear(a.getFullYear() + 10)");
+    }
+
+    @Test
+    public void testDateGetFullYearMethod()
+    {
+        IVariableNode node = getVariable("var a:Date = new Date(); var b:Number = a.getFullYear()");
+        node = (IVariableNode)(node.getParent().getChild(1));
+        asBlockWalker.visitVariable(node);
+        assertOut("var /** @type {number} */ b = a.getFullYear()");
+    }
+    
+    @Test
+    public void testDateSetFullYearMethod()
+    {
+    	IBinaryOperatorNode node = getBinaryNode("var a:Date = new Date(); a.setFullYear(10, 0, 0)");
+    	IFunctionCallNode parentNode = (IFunctionCallNode)(node.getParent());
+        asBlockWalker.visitFunctionCall(parentNode);
+        assertOut("a.setFullYear(10, 0, 0)");
+    }
+
     @Override
     @Test
     public void testVector()