You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@royale.apache.org by gr...@apache.org on 2022/01/24 01:34:14 UTC

[royale-compiler] branch develop updated: [JS] Fixes for XMLList addition, for boolean equality checking vs. XML, and for QName inequality checking.

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

gregdove 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 5a23c75  [JS] Fixes for XMLList addition, for boolean equality checking vs. XML, and for QName inequality checking.
5a23c75 is described below

commit 5a23c75f66247b3c84b55eb476951c3e5289ac31
Author: greg-dove <gr...@gmail.com>
AuthorDate: Mon Jan 24 14:30:35 2022 +1300

    [JS] Fixes for XMLList addition, for boolean equality checking vs. XML, and for QName inequality checking.
---
 .../codegen/js/jx/BinaryOperatorEmitter.java       |  46 +++++--
 .../compiler/internal/semantics/SemanticUtils.java | 139 ++++++++++++++-------
 2 files changed, 132 insertions(+), 53 deletions(-)

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 bfbdc2b..051f3ff 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
@@ -255,15 +255,6 @@ public class BinaryOperatorEmitter extends JSSubEmitter implements
 	                    write(ASEmitterTokens.PAREN_CLOSE);
 	                    return;
                 	}
-                	else if (node.getNodeID() == ASTNodeID.Op_EqualID &&
-                			node.getRightOperandNode().getNodeID() == ASTNodeID.LiteralBooleanID)
-                	{
-                		getWalker().walk(xmlNode);
-                		write(" == '");
-	                    getWalker().walk(node.getRightOperandNode());
-                		write("'");
-                		return;
-                	}
                 }
                 else if (isDynamicAccess && ((JSRoyaleEmitter)getEmitter()).isXMLish((IExpressionNode)lnode))
                 {
@@ -480,12 +471,13 @@ public class BinaryOperatorEmitter extends JSSubEmitter implements
             	}
             }
             
-			if (id == ASTNodeID.Op_EqualID) {
+			if (id == ASTNodeID.Op_EqualID || id ==ASTNodeID.Op_NotEqualID) {
 				//QName == QName
 				if (leftDef != null && leftDef.getQualifiedName().equals("QName")) {
 					IDefinition rightDef = node.getRightOperandNode().resolveType(getProject());
 					if (rightDef != null && rightDef.getQualifiedName().equals("QName")) {
-						//handle non-strict equality a little differently
+						//handle non-strict equality/inequality a little differently
+						if (id == ASTNodeID.Op_NotEqualID) write("!");
 						write("QName.equality(");
 						getWalker().walk(node.getLeftOperandNode());
 						write(",");
@@ -493,6 +485,38 @@ public class BinaryOperatorEmitter extends JSSubEmitter implements
 						write(")");
 						return;
 					}
+				} else if (leftDef != null && getProject().getBuiltinType(BuiltinType.BOOLEAN).equals(leftDef) && SemanticUtils.isXMLish(node.getRightOperandNode(), getProject())) {
+					boolean literalBool = node.getLeftOperandNode().getNodeID() == ASTNodeID.LiteralBooleanID;
+					//note, this only covers boolean ==/!= xmlish, not: xmlish ==/!= boolean
+					if (literalBool) {
+						write("'");
+					}
+					else write("('' + ");
+						getWalker().walk(node.getLeftOperandNode());
+					if (literalBool) {
+						write("'");
+					}
+					else write(")");
+					write(" " + node.getOperator().getOperatorText() + " ");
+
+					getWalker().walk(node.getRightOperandNode());
+					return;
+				} else if ((((leftDef == null || getProject().getBuiltinType(BuiltinType.ANY_TYPE).equals(leftDef)) && SemanticUtils.isXMLish(node.getLeftOperandNode(), getProject())) || SemanticUtils.isXMLish(leftDef, getProject())) && getProject().getBuiltinType(BuiltinType.BOOLEAN).equals(node.getRightOperandNode().resolveType(getProject()))) {
+					boolean literalBool = node.getRightOperandNode().getNodeID() == ASTNodeID.LiteralBooleanID;
+
+					//note, this only covers xmlish ==/!= boolean, not: boolean ==/!= xmlish
+					getWalker().walk(node.getLeftOperandNode());
+					write(" " + node.getOperator().getOperatorText() + " ");
+					if (literalBool) {
+						write("'");
+					}
+					else write("('' + ");
+					getWalker().walk(node.getRightOperandNode());
+					if (literalBool) {
+						write("'");
+					}
+					else write(")");
+					return;
 				}
 			}
 			
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/SemanticUtils.java b/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/SemanticUtils.java
index 7973e71..120b934 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/SemanticUtils.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/SemanticUtils.java
@@ -33,17 +33,8 @@ import org.apache.royale.compiler.common.DependencyType;
 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.IAccessorDefinition;
-import org.apache.royale.compiler.definitions.IClassDefinition;
-import org.apache.royale.compiler.definitions.IConstantDefinition;
-import org.apache.royale.compiler.definitions.IDefinition;
-import org.apache.royale.compiler.definitions.IFunctionDefinition;
+import org.apache.royale.compiler.definitions.*;
 import org.apache.royale.compiler.definitions.IFunctionDefinition.FunctionClassification;
-import org.apache.royale.compiler.definitions.IInterfaceDefinition;
-import org.apache.royale.compiler.definitions.INamespaceDefinition;
-import org.apache.royale.compiler.definitions.IParameterDefinition;
-import org.apache.royale.compiler.definitions.IScopedDefinition;
-import org.apache.royale.compiler.definitions.ITypeDefinition;
 import org.apache.royale.compiler.definitions.metadata.IDeprecationInfo;
 import org.apache.royale.compiler.definitions.references.INamespaceReference;
 import org.apache.royale.compiler.definitions.references.IReference;
@@ -110,28 +101,10 @@ import org.apache.royale.compiler.problems.ScopedToDefaultNamespaceProblem;
 import org.apache.royale.compiler.problems.UnknownSuperclassProblem;
 import org.apache.royale.compiler.projects.ICompilerProject;
 import org.apache.royale.compiler.scopes.IASScope;
+import org.apache.royale.compiler.scopes.IDefinitionSet;
 import org.apache.royale.compiler.tree.ASTNodeID;
-import org.apache.royale.compiler.tree.as.IASNode;
-import org.apache.royale.compiler.tree.as.IClassNode;
-import org.apache.royale.compiler.tree.as.ICommonClassNode;
-import org.apache.royale.compiler.tree.as.IContainerNode;
-import org.apache.royale.compiler.tree.as.IDefinitionNode;
-import org.apache.royale.compiler.tree.as.IExpressionNode;
-import org.apache.royale.compiler.tree.as.IFileNode;
-import org.apache.royale.compiler.tree.as.IFunctionCallNode;
-import org.apache.royale.compiler.tree.as.IFunctionNode;
-import org.apache.royale.compiler.tree.as.IIdentifierNode;
-import org.apache.royale.compiler.tree.as.IImportNode;
-import org.apache.royale.compiler.tree.as.ILanguageIdentifierNode;
+import org.apache.royale.compiler.tree.as.*;
 import org.apache.royale.compiler.tree.as.ILanguageIdentifierNode.LanguageIdentifierKind;
-import org.apache.royale.compiler.tree.as.ILiteralNode;
-import org.apache.royale.compiler.tree.as.IMemberAccessExpressionNode;
-import org.apache.royale.compiler.tree.as.INamespaceDecorationNode;
-import org.apache.royale.compiler.tree.as.INumericLiteralNode;
-import org.apache.royale.compiler.tree.as.IParameterNode;
-import org.apache.royale.compiler.tree.as.IScopedNode;
-import org.apache.royale.compiler.tree.as.ITryNode;
-import org.apache.royale.compiler.tree.as.IVariableNode;
 import org.apache.royale.compiler.tree.mxml.IMXMLEventSpecifierNode;
 
 /**
@@ -981,13 +954,18 @@ public class SemanticUtils
      */
     public static IDefinition resolveXML(IExpressionNode iNode, ICompilerProject project)
     {
+        if (iNode.getNodeID().equals(ASTNodeID.E4XFilterID)) {
+            // return XMLList, we can be certain
+            return project.getBuiltinType(IASLanguageConstants.BuiltinType.XMLLIST);
+        }
         if (iNode instanceof IFunctionCallNode)
         {
             IFunctionCallNode functionCall = (IFunctionCallNode) iNode;
             IExpressionNode nameNode = functionCall.getNameNode();
+            IMemberAccessExpressionNode memberAccess = null;
             if (nameNode instanceof IMemberAccessExpressionNode)
             {
-                IMemberAccessExpressionNode memberAccess = (IMemberAccessExpressionNode) nameNode;
+                memberAccess = (IMemberAccessExpressionNode) nameNode;
                 nameNode = memberAccess.getRightOperandNode();
             }
             if (nameNode instanceof IIdentifierNode)
@@ -1000,46 +978,99 @@ public class SemanticUtils
                             && !(resolvedDef instanceof IAccessorDefinition))
                     {
                         //method call on XML or XMLList instance
+                        resolvedDef = methodXMLishReturnType((IFunctionDefinition)resolvedDef,project);
                         return resolvedDef;
                     }
                 } else {
                     resolvedDef = functionCall.resolveType(project);
                     if (resolvedDef != null && isXMLish(resolvedDef, project)) return resolvedDef;
                 }
+                if (memberAccess !=null) {
+                    //try left
+                    IDefinition leftDef = resolveXML(memberAccess.getLeftOperandNode(), project);
+                    if (leftDef != null) {
+                        IClassDefinition xmlish = (IClassDefinition) leftDef;
+                        IDefinitionSet funcDefs = xmlish.getContainedScope().getLocalDefinitionSetByName(identifierNode.getName());
+
+                        if (funcDefs != null){
+                            if (funcDefs.getSize() == 1) {
+                                IFunctionDefinition funcDef = (IFunctionDefinition)funcDefs.getDefinition(0);
+                                resolvedDef = methodXMLishReturnType(funcDef, project);//.resolveReturnType(project);
+                                if (resolvedDef != null) return resolvedDef;
+                            } //there should be no competing definitions on XMLish classes
+                        } 
+                    }
+                }
+
             }
+
             return null;
         }
 
-        if (iNode instanceof IIdentifierNode)
+        else if (iNode instanceof IIdentifierNode)
         {
             IIdentifierNode identifierNode = (IIdentifierNode) iNode;
             IDefinition resolvedDef = identifierNode.resolve(project);
-            if (resolvedDef != null && isXMLish(resolvedDef.getParent(), project))
-            {
-                if (resolvedDef.isPrivate() || resolvedDef.isProtected())
-                {
-                    //private/protected member inside the XML or XMLList class
+            if (resolvedDef instanceof IVariableDefinition) {
+                resolvedDef = resolvedDef.resolveType(project);
+                if (resolvedDef != null && isXMLish(resolvedDef, project)) {
                     return resolvedDef;
                 }
-            } else {
+            }
+            else {
                 resolvedDef = identifierNode.resolveType(project);
                 if (resolvedDef != null && isXMLish(resolvedDef, project)) {
                     return resolvedDef;
                 }
             }
         }
-        if (iNode instanceof IMemberAccessExpressionNode)
+        else if (iNode instanceof IMemberAccessExpressionNode)
         {
             IMemberAccessExpressionNode memberAccess = (IMemberAccessExpressionNode) iNode;
             IExpressionNode nameNode = memberAccess.getRightOperandNode();
-            return resolveXML(nameNode, project);
+            IDefinition resolvedDef = resolveXML(nameNode, project);
+            if (resolvedDef == null) {
+                IDefinition lhs = resolveXML(memberAccess.getLeftOperandNode(), project);
+                if (lhs != null) {
+                    if ((nameNode instanceof IUnaryOperatorNode && nameNode.getNodeID().equals(ASTNodeID.Op_AtID)) ||
+                        nameNode instanceof IIdentifierNode) {
+                        return project.getBuiltinType(BuiltinType.XMLLIST);
+                    }
+                }
+            }
+            return resolvedDef;
+        }
+        else if (iNode instanceof IDynamicAccessNode) {
+            IDynamicAccessNode dynAccess = (IDynamicAccessNode) iNode;
+            boolean isNumericAccess = SemanticUtils.isNumericType(dynAccess.getRightOperandNode().resolveType(project), project);
+            IExpressionNode leftSideExpressioNode = dynAccess.getLeftOperandNode();
+            if (!isNumericAccess && leftSideExpressioNode.getNodeID().equals(ASTNodeID.Op_AtID)) {
+                if (dynAccess.getParent() instanceof IMemberAccessExpressionNode) {
+                    IMemberAccessExpressionNode mae = (IMemberAccessExpressionNode) (dynAccess.getParent());
+                    leftSideExpressioNode = mae.getLeftOperandNode();
+                }
+            }
+            IDefinition lhs = resolveXML(leftSideExpressioNode, project);
+            if (lhs != null) {
+                //if the type is numeric, then assume it is XML, if it is non-numeric, then XMLList
+                return isNumericAccess ? project.getBuiltinType(BuiltinType.XML) : project.getBuiltinType(BuiltinType.XMLLIST);
+            }
+        }
+        else if (iNode instanceof IBinaryOperatorNode) {
+            IBinaryOperatorNode binaryOperatorNode = (IBinaryOperatorNode) iNode;
+            if (binaryOperatorNode.getNodeID().equals(ASTNodeID.Op_AddID)) {
+                //System.out.println("Op_AddID");
+                if (resolveXML(binaryOperatorNode.getLeftOperandNode(),project)!= null && resolveXML(binaryOperatorNode.getRightOperandNode(), project)!=null) {
+                    return project.getBuiltinType(BuiltinType.XMLLIST);
+                }
+            }
         }
         return null;
     }
 
     /**
      * Determine if the definition passed in is one of the XML types (XML or
-     * XMLList) These classes are unrelated, but behave in similar manners.
+     * XMLList) These classes are distinct classes, without shared ancestry or interfaces, but behave in similar manners.
      * 
      * @param iNode the {@link IExpressionNode} to check
      * @param project the {@link ICompilerProject} in which to look up types
@@ -1065,6 +1096,30 @@ public class SemanticUtils
         return (xmlDef != null && def == xmlDef) ||
                 (xmlListDef != null && def == xmlListDef);
     }
+
+    /**
+     * For an unresolved return type, special case the checking of it.
+     * in XML, parent():* and insertChildAfter are some examples
+     * @param method
+     * @param project
+     * @return
+     */
+    private static IDefinition methodXMLishReturnType(IFunctionDefinition method, ICompilerProject project){
+
+        IDefinition returnType = method.resolveReturnType(project);
+        if (returnType.equals(project.getBuiltinType(BuiltinType.ANY_TYPE)) && project.getBuiltinType(BuiltinType.XML).equals(method.getParent())) {
+            //method names which can be considered to return XML instead of '*'
+            //these are either XML or undefined (as opposed to null)
+            //3 methods that can be considered having XMLish return types : "parent", "insertChildAfter", "insertChildBefore"
+            if (method.getBaseName().matches("parent|insertChildAfter|insertChildBefore")) {
+                return project.getBuiltinType(BuiltinType.XML);
+            }
+        }
+        if (isXMLish(returnType,project)) {
+            return returnType;
+        }
+        return null;
+    }
     
     /**
      * Determines if an expression is a toString() function call.
@@ -1347,7 +1402,7 @@ public class SemanticUtils
 
     /**
      *  Is this function node contained within another function node?
-     *  @param iNode - the node of interest.
+     *  @param functionNode - the node of interest.
      *  @return true if the function node is a closure
      */
     public static boolean isFunctionClosure(IFunctionNode functionNode)