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 2019/02/20 23:53:35 UTC

[royale-compiler] branch develop updated: VarDeclarationEmitter: uses same type coercion behavior as returns, function arguments, and binary operator assignment

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 1490d2d  VarDeclarationEmitter: uses same type coercion behavior as returns, function arguments, and binary operator assignment
1490d2d is described below

commit 1490d2d5eb80b2462cce1fc3484572953f7bc7d9
Author: Josh Tynjala <jo...@apache.org>
AuthorDate: Wed Feb 20 15:53:24 2019 -0800

    VarDeclarationEmitter: uses same type coercion behavior as returns, function arguments, and binary operator assignment
    
    All automatic type coercion code is now consolidated in one place so that behavior will be more consistent everywhere
---
 .../compiler/internal/codegen/js/JSEmitter.java    |   2 +-
 .../internal/codegen/js/goog/JSGoogEmitter.java    |   3 -
 .../codegen/js/jx/VarDeclarationEmitter.java       | 211 +--------------------
 .../codegen/js/royale/TestRoyaleExpressions.java   |  24 +++
 .../codegen/js/royale/TestRoyaleStatements.java    |   9 +
 5 files changed, 35 insertions(+), 214 deletions(-)

diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSEmitter.java
index cb3d743..b9e80bb 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSEmitter.java
@@ -700,7 +700,7 @@ public class JSEmitter extends ASEmitter implements IJSEmitter
 		{
 			write(coercionStart);
         }
-		getWalker().walk(assignedNode);
+        emitAssignedValue(assignedNode);
 		if (coercionStart != null)
 		{
 			if (coercionEnd != null)
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/goog/JSGoogEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/goog/JSGoogEmitter.java
index 693c476..1b7aacf 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/goog/JSGoogEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/goog/JSGoogEmitter.java
@@ -44,16 +44,13 @@ import org.apache.royale.compiler.internal.codegen.js.JSEmitter;
 import org.apache.royale.compiler.internal.codegen.js.JSEmitterTokens;
 import org.apache.royale.compiler.internal.codegen.js.JSSessionModel;
 import org.apache.royale.compiler.internal.codegen.js.utils.EmitterUtils;
-import org.apache.royale.compiler.internal.definitions.AccessorDefinition;
 import org.apache.royale.compiler.internal.definitions.ClassDefinition;
-import org.apache.royale.compiler.internal.definitions.FunctionDefinition;
 import org.apache.royale.compiler.internal.definitions.NamespaceDefinition.INamepaceDeclarationDirective;
 import org.apache.royale.compiler.internal.definitions.VariableDefinition;
 import org.apache.royale.compiler.internal.scopes.PackageScope;
 import org.apache.royale.compiler.internal.tree.as.ChainedVariableNode;
 import org.apache.royale.compiler.internal.tree.as.FunctionCallNode;
 import org.apache.royale.compiler.internal.tree.as.FunctionNode;
-import org.apache.royale.compiler.internal.tree.as.MemberAccessExpressionNode;
 import org.apache.royale.compiler.problems.ICompilerProblem;
 import org.apache.royale.compiler.problems.VariableUsedBeforeDeclarationProblem;
 import org.apache.royale.compiler.projects.ICompilerProject;
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/VarDeclarationEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/VarDeclarationEmitter.java
index 1c3acef..12b1443 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/VarDeclarationEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/VarDeclarationEmitter.java
@@ -22,28 +22,17 @@ package org.apache.royale.compiler.internal.codegen.js.jx;
 import org.apache.royale.compiler.codegen.ISubEmitter;
 import org.apache.royale.compiler.codegen.js.IJSEmitter;
 import org.apache.royale.compiler.constants.IASKeywordConstants;
-import org.apache.royale.compiler.constants.IASLanguageConstants;
-import org.apache.royale.compiler.constants.IASLanguageConstants.BuiltinType;
 import org.apache.royale.compiler.definitions.IDefinition;
-import org.apache.royale.compiler.definitions.metadata.IMetaTag;
-import org.apache.royale.compiler.definitions.metadata.IMetaTagAttribute;
 import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
 import org.apache.royale.compiler.internal.codegen.js.JSSubEmitter;
-import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleDocEmitter;
 import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitter;
 import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
-import org.apache.royale.compiler.internal.semantics.SemanticUtils;
 import org.apache.royale.compiler.internal.tree.as.ChainedVariableNode;
-import org.apache.royale.compiler.internal.tree.as.DynamicAccessNode;
-import org.apache.royale.compiler.internal.tree.as.FunctionCallNode;
-import org.apache.royale.compiler.internal.tree.as.IdentifierNode;
-import org.apache.royale.compiler.internal.tree.as.MemberAccessExpressionNode;
 import org.apache.royale.compiler.projects.ICompilerProject;
 import org.apache.royale.compiler.tree.ASTNodeID;
 import org.apache.royale.compiler.tree.as.IASNode;
 import org.apache.royale.compiler.tree.as.IEmbedNode;
 import org.apache.royale.compiler.tree.as.IExpressionNode;
-import org.apache.royale.compiler.tree.as.INumericLiteralNode;
 import org.apache.royale.compiler.tree.as.IVariableNode;
 
 /**
@@ -93,21 +82,10 @@ public class VarDeclarationEmitter extends JSSubEmitter implements
                     nameExpressionNode.getColumn() + nameExpressionNode.getAbsoluteEnd() - nameExpressionNode.getAbsoluteStart());
         }
         IExpressionNode avnode = node.getAssignedValueNode();
-        IDefinition avdef = null;
         IDefinition avtypedef = null;
         if (avnode != null)
         {
-            avdef = avnode.resolve(getProject());
         	avtypedef = avnode.resolveType(getProject());
-            if (getProject().getBuiltinType(BuiltinType.ANY_TYPE).equals(avtypedef))
-            {
-                IDefinition resolvedXMLDef = SemanticUtils.resolveXML(avnode, getProject());
-                if (resolvedXMLDef != null)
-                {
-                    avdef = resolvedXMLDef;
-                    avtypedef = SemanticUtils.resolveTypeXML(avnode, getProject());
-                }
-            }
             String opcode = avnode.getNodeID().getParaphrase();
             if (opcode != "AnonymousFunction")
             {
@@ -139,194 +117,7 @@ public class VarDeclarationEmitter extends JSSubEmitter implements
             write(ASEmitterTokens.SPACE);
             writeToken(ASEmitterTokens.EQUAL);
             endMapping(node);
-            boolean varIsInt = (variableTypeNode.getNodeID() == ASTNodeID.IdentifierID && 
-          		  (((IdentifierNode)variableTypeNode).getName().equals(IASLanguageConstants._int) ||
-               		   ((IdentifierNode)variableTypeNode).getName().equals(IASLanguageConstants.uint)));
-            boolean varIsNumber = (variableTypeNode.getNodeID() == ASTNodeID.IdentifierID && 
-            		  (((IdentifierNode)variableTypeNode).getName().equals(IASLanguageConstants.Number) ||
-            		   varIsInt));
-            boolean valIsInt = (avtypedef != null && (avtypedef.getQualifiedName().equals(IASLanguageConstants._int) ||
-					 							  avtypedef.getQualifiedName().equals(IASLanguageConstants.uint) ||
-					 							  (avtypedef.getQualifiedName().equals(IASLanguageConstants.Number) &&
-					 									  (avnode.getNodeID() == ASTNodeID.LiteralIntegerID ||
-					 									   avnode.getNodeID() == ASTNodeID.LiteralIntegerZeroID))));
-            boolean valIsNumber = (avtypedef != null && (avtypedef.getQualifiedName().equals(IASLanguageConstants.Number) ||
-            										 valIsInt));
-            if (!valIsNumber && avtypedef == null && avnode.getNodeID() == ASTNodeID.MemberAccessExpressionID &&
-            		fjs.isDateProperty(avnode, false))
-            	valIsNumber = true;
-            if (varIsNumber && !valIsNumber && (avtypedef == null || avtypedef.getQualifiedName().equals(IASLanguageConstants.ANY_TYPE)))
-            {
-        		if (avnode.getNodeID() == ASTNodeID.FunctionCallID)
-        		{
-	            	IExpressionNode fnNameNode = ((FunctionCallNode)avnode).getNameNode();
-	            	if (fnNameNode.getNodeID() == ASTNodeID.MemberAccessExpressionID)
-	            	{
-	            		MemberAccessExpressionNode mae = (MemberAccessExpressionNode)fnNameNode;
-	            		IExpressionNode rightNode = mae.getRightOperandNode();
-	            		valIsNumber = rightNode.getNodeID() == ASTNodeID.IdentifierID && 
-	            				((IdentifierNode)rightNode).getName().equals("length") &&
-	            				fjs.isXMLList(mae);
-	            	}
-        		}
-        		else if (avnode.getNodeID() == ASTNodeID.ArrayIndexExpressionID)
-        		{
-        			DynamicAccessNode dyn = (DynamicAccessNode)avnode;
-        			IDefinition leftDef = dyn.getLeftOperandNode().resolveType(getProject());
-        			IDefinition rightDef = dyn.getRightOperandNode().resolveType(getProject());
-        			// numeric indexing?
-        			if (leftDef != null && rightDef.getQualifiedName().equals(IASLanguageConstants.Number))
-        			{
-        				IMetaTag[] metas = leftDef.getAllMetaTags();
-        				for (IMetaTag meta : metas)
-        				{
-        					if (meta.getTagName().equals("ArrayElementType"))
-        					{
-        						IMetaTagAttribute[] attrs = meta.getAllAttributes();
-        						for (IMetaTagAttribute attr : attrs)
-        						{
-        							String t = attr.getValue();
-            						if (t.equals(IASLanguageConstants.Number))
-            							valIsNumber = true;
-        						}
-        					}
-        				}
-        			}
-        		}
-            }
-            String coercionStart = null;
-            String coercionEnd = null;
-            String coercedValue = null;
-            if (getProject().getBuiltinType(BuiltinType.INT).equals(variableDef))
-            {
-                boolean needsCoercion = false;
-                if (avnode instanceof INumericLiteralNode)
-                {
-                    INumericLiteralNode numericLiteral = (INumericLiteralNode) avnode;
-                    INumericLiteralNode.INumericValue numericValue = numericLiteral.getNumericValue();
-                    if(numericValue.toString().startsWith("0x"))
-                    {
-                        //for readability, keep the same formatting
-                        coercedValue = "0x" + Integer.toHexString(numericValue.toInt32());
-                    }
-                    else
-                    {
-                        coercedValue = Integer.toString(numericValue.toInt32());
-                    }
-                }
-                else if(!getProject().getBuiltinType(BuiltinType.INT).equals(avtypedef))
-                {
-                    needsCoercion = true;
-                }
-                if (needsCoercion)
-                {
-                    coercionStart = "(";
-                    coercionEnd = ") >> 0";
-                }
-            }
-            else if (getProject().getBuiltinType(BuiltinType.UINT).equals(variableDef))
-            {
-                boolean needsCoercion = false;
-                if (avnode instanceof INumericLiteralNode)
-                {
-                    INumericLiteralNode numericLiteral = (INumericLiteralNode) avnode;
-                    INumericLiteralNode.INumericValue numericValue = numericLiteral.getNumericValue();
-                    if(numericValue.toString().startsWith("0x"))
-                    {
-                        //for readability, keep the same formatting
-                        coercedValue = "0x" + Long.toHexString(numericValue.toUint32());
-                    }
-                    else
-                    {
-                        coercedValue = Long.toString(numericValue.toUint32());
-                    }
-                }
-                else if(!getProject().getBuiltinType(BuiltinType.UINT).equals(avtypedef))
-                {
-                    needsCoercion = true;
-                }
-                if (needsCoercion)
-                {
-                    coercionStart = "(";
-                    coercionEnd = ") >>> 0";
-                }
-            }
-            else if (varIsNumber && !valIsNumber)
-            {
-                coercionStart = "Number(";
-            }
-            else if (getProject().getBuiltinType(BuiltinType.BOOLEAN).equals(variableDef)
-                    && !getProject().getBuiltinType(BuiltinType.BOOLEAN).equals(avtypedef))
-            {
-                if (getProject().getBuiltinType(BuiltinType.NULL).equals(avtypedef)
-                        || (avdef != null && avdef.getQualifiedName().equals(IASLanguageConstants.UNDEFINED)))
-                {
-                    //null and undefined are coerced to false
-                    startMapping(avnode);
-                    write(IASLanguageConstants.FALSE);
-                    endMapping(avnode);
-                    return;
-                }
-                if (avnode instanceof INumericLiteralNode)
-                {
-                    INumericLiteralNode numericLiteral = (INumericLiteralNode) avnode;
-                    INumericLiteralNode.INumericValue numericValue = numericLiteral.getNumericValue();
-                    //zero is coerced to false, and everything else is true
-                    String booleanValue = numericValue.toNumber() == 0.0
-                            ? IASLanguageConstants.FALSE
-                            : IASLanguageConstants.TRUE;
-                    startMapping(avnode);
-                    write(booleanValue);
-                    endMapping(avnode);
-                    return;
-                }
-                coercionStart = "!!(";
-            }
-            else if (getProject().getBuiltinType(BuiltinType.STRING).equals(variableDef)
-                    && !getProject().getBuiltinType(BuiltinType.STRING).equals(avtypedef)
-                    && !getProject().getBuiltinType(BuiltinType.NULL).equals(avtypedef)
-                    && !(getProject().getBuiltinType(BuiltinType.ANY_TYPE).equals(avtypedef)
-                            && SemanticUtils.isToStringFunctionCall(avnode, getProject())))
-            {
-                if(avdef != null && avdef.getQualifiedName().equals(IASLanguageConstants.UNDEFINED))
-                {
-                    //undefined is coerced to null
-                    startMapping(avnode);
-                    write(IASLanguageConstants.NULL);
-                    endMapping(avnode);
-                    return;
-                }
-                JSRoyaleDocEmitter docEmitter = (JSRoyaleDocEmitter) (getEmitter().getDocEmitter());
-                if (docEmitter.emitStringConversions)
-                {
-                    coercionStart = "org.apache.royale.utils.Language.string(";
-                }
-            }
-			if (coercionStart != null)
-			{
-                write(coercionStart);
-            }
-            if (coercedValue != null)
-            {
-                startMapping(avnode);
-                write(coercedValue);
-                endMapping(avnode);
-            }
-            else
-            {
-                fjs.emitAssignedValue(avnode);
-            }
-			if (coercionStart != null)
-			{
-				if (coercionEnd != null)
-				{
-					write(coercionEnd);
-				}
-				else
-				{
-					write(")");
-				}
-			}
+            getEmitter().emitAssignmentCoercion(avnode, variableDef);
         }
         if (avnode == null)
         {
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleExpressions.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleExpressions.java
index 3e062f1..3eea2d3 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleExpressions.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleExpressions.java
@@ -518,6 +518,14 @@ public class TestRoyaleExpressions extends TestGoogExpressions
     }
 
     @Test
+    public void testVisitBinaryOperatorNode_AssignmentDatePropertyToNumber()
+    {
+        IBinaryOperatorNode node = getBinaryNode("var var1:Number;var var2:Date;var1 = var2.month");
+        asBlockWalker.visitBinaryOperator(node);
+        assertOut("var1 = var2.getMonth()");
+    }
+
+    @Test
     public void testVisitBinaryOperatorNode_setterAssignment()
     {
         IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
@@ -1840,6 +1848,14 @@ public class TestRoyaleExpressions extends TestGoogExpressions
     }
 
     @Test
+    public void testVisitReturnNumberWithDateProperty()
+    {
+        IReturnNode node = (IReturnNode) getNode("function():Number { var a:Date; return a.month; }", IReturnNode.class);
+        asBlockWalker.visitReturn(node);
+        assertOut("return a.getMonth()");
+    }
+
+    @Test
     public void testVisitFunctionCallWithIntParameterHex()
     {
         IFunctionCallNode node = (IFunctionCallNode) getNode("function a(foo:int):void {}; a(0xabc)", IFunctionCallNode.class);
@@ -1999,6 +2015,14 @@ public class TestRoyaleExpressions extends TestGoogExpressions
         assertOut("a(org.apache.royale.utils.Language.string(b.child('child')))");
     }
 
+    @Test
+    public void testVisitFunctionCallWithNumberParameterDateProperty()
+    {
+        IFunctionCallNode node = (IFunctionCallNode) getNode("function a(foo:Number):void {}; var b:Date; a(b.month);", IFunctionCallNode.class);
+        asBlockWalker.visitFunctionCall(node);
+        assertOut("a(b.getMonth())");
+    }
+
     protected IBackend createBackend()
     {
         return new RoyaleBackend();
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleStatements.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleStatements.java
index 7c4feb1..e7b6695 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleStatements.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleStatements.java
@@ -258,6 +258,15 @@ public class TestRoyaleStatements extends TestGoogStatements
         assertOut("var /** @type {string} */ a = this.b.toString()");
     }
 
+    @Test
+    public void testVarDeclaration_withTypeNumberAndAssignedDateProperty()
+    {
+        IVariableNode node = (IVariableNode) getNode("function royaleTest_a():Object { var a:Number = b.fullYear; }var b:Date;",
+            IVariableNode.class, WRAP_LEVEL_CLASS);
+        asBlockWalker.visitVariable(node);
+        assertOut("var /** @type {number} */ a = this.b.getFullYear()");
+    }
+
     //----------------------------------
     // const declaration
     //----------------------------------