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 2020/03/08 22:59:45 UTC

[royale-compiler] branch develop updated: Try a bit harder to determine the XMLish-ness of a function call return type from an XMLish member-access chain. This avoids the wrong interpretation of things like myXML.name() or myXML.namespace(), but still works for myXML.attributes(), for example

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 5519529  Try a bit harder to determine the XMLish-ness of a function call return type from an XMLish member-access chain. This avoids the wrong interpretation of things like myXML.name() or myXML.namespace(), but still works for myXML.attributes(), for example
5519529 is described below

commit 5519529ec94a7ee6f1968198ff176da0bacec463
Author: greg-dove <gr...@gmail.com>
AuthorDate: Mon Mar 9 11:57:54 2020 +1300

    Try a bit harder to determine the XMLish-ness of a function call return type from an XMLish member-access chain.
    This avoids the wrong interpretation of things like myXML.name() or myXML.namespace(), but still works for myXML.attributes(), for example
---
 .../internal/codegen/js/jx/ForEachEmitter.java     | 35 ++++++++++++++++++--
 .../internal/codegen/js/utils/EmitterUtils.java    | 38 ++++++++++++++++++++++
 2 files changed, 71 insertions(+), 2 deletions(-)

diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/ForEachEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/ForEachEmitter.java
index 2902821..d8f1a4c 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/ForEachEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/ForEachEmitter.java
@@ -22,6 +22,7 @@ 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.IASLanguageConstants;
+import org.apache.royale.compiler.definitions.IDefinition;
 import org.apache.royale.compiler.definitions.IFunctionDefinition;
 import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
 import org.apache.royale.compiler.internal.codegen.js.JSSubEmitter;
@@ -32,6 +33,7 @@ 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.LabeledStatementNode;
 import org.apache.royale.compiler.internal.tree.as.MemberAccessExpressionNode;
+import org.apache.royale.compiler.scopes.IDefinitionSet;
 import org.apache.royale.compiler.tree.ASTNodeID;
 import org.apache.royale.compiler.tree.as.*;
 
@@ -163,14 +165,43 @@ public class ForEachEmitter extends JSSubEmitter implements
         	} else if (funcName instanceof IMemberAccessExpressionNode) {
                 IFunctionDefinition funcDef = (IFunctionDefinition) ((IMemberAccessExpressionNode) funcName).getRightOperandNode().resolve(getProject());
                 if (funcDef == null) {
-                    isXML = EmitterUtils.isXMLList((IMemberAccessExpressionNode)funcName, getProject()) || EmitterUtils.isXML(funcName, getProject());
+                    //we need to check the LHS for XMLishness, and then resolve the method name against the determined XMLish definition (XML or XMLList),
+                    // and then check its return type once we find the public FunctionDefinition for the method name
+                    // (because although it is a member of something XMLish, it may not return something that is also XMLish, such as a QName, a String, a uint, or a Namespace etc)
+                    IDefinitionSet matchingDefinitions = null;
+                    if (EmitterUtils.isLeftNodeXML(((IMemberAccessExpressionNode) funcName).getLeftOperandNode(), getProject())) {
+                        if (((IMemberAccessExpressionNode) funcName).getRightOperandNode().getNodeID() == ASTNodeID.IdentifierID) {
+                            matchingDefinitions = getProject().getBuiltinType(IASLanguageConstants.BuiltinType.XML).getContainedScope().getLocalDefinitionSetByName(((IIdentifierNode)((IMemberAccessExpressionNode) funcName).getRightOperandNode()).getName());
+                        }
+                    } else if (EmitterUtils.isLeftNodeXMLList(((IMemberAccessExpressionNode) funcName).getLeftOperandNode(), getProject())) {
+                        if (((IMemberAccessExpressionNode) funcName).getRightOperandNode().getNodeID() == ASTNodeID.IdentifierID) {
+                            matchingDefinitions = getProject().getBuiltinType(IASLanguageConstants.BuiltinType.XMLLIST).getContainedScope().getLocalDefinitionSetByName(((IIdentifierNode)((IMemberAccessExpressionNode) funcName).getRightOperandNode()).getName());
+                        }
+                    }
+                    if (matchingDefinitions != null) {
+                        for (int i = 0; i< matchingDefinitions.getSize(); i++) {
+                            IDefinition functionDefinition = matchingDefinitions.getDefinition(i);
+                            if (functionDefinition instanceof IFunctionDefinition) {
+                                if (functionDefinition.isPublic()) {
+                                    isXML = SemanticUtils.isXMLish((((IFunctionDefinition) functionDefinition).resolveReturnType(getProject())), getProject());
+                                    break;
+                                }
+                            }
+                        }
+                    }
+
+                    //@todo should we emit a warning here if wasXMLish (from either of the first 2 checks) && !isXML (from the matchingDefinitions check)?
+                    // results will not be consistent in this case.
+                    // e.g. looping over a QName or Namespace instance
+                    // It is probably rare and ill-advised, but it definitely won't work well in javascript currently for those classes, for example.
+
                 } else {
                     isXML = SemanticUtils.isXMLish(funcDef.resolveReturnType(getProject()), getProject());
                 }
                 if (isXML) {
                     write(".elementNames()");
                 }
-            }
+            } //@todo what about dynamic access node for function call? e.g. myXML[string_Value_Here]() ... not so easy really, would likely need a runtime helper/wrapper.
         }
         endMapping(rnode);
         startMapping(node, cnode);
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/utils/EmitterUtils.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/utils/EmitterUtils.java
index 3d35ec3..2e03bf2 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/utils/EmitterUtils.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/utils/EmitterUtils.java
@@ -802,6 +802,44 @@ public class EmitterUtils
             return true;
         return false;
     }
+
+    public static boolean isLeftNodeXMLList(IExpressionNode leftNode, ICompilerProject project) {
+        boolean isXMLList = false;
+        if (isLeftNodeXMLish(leftNode, project)) {
+            //it is not XMLList if it is a DynamicAccessNode with numeric index.
+            //this is limited analysis, because ["0"] would also be the same as [0], but perhaps best we can do without more runtime support
+            if (leftNode instanceof IDynamicAccessNode) { //DynamicAccessNode
+                IExpressionNode dynAccess = ((IDynamicAccessNode) leftNode).getRightOperandNode();
+                IDefinition accessDef = dynAccess.resolveType(project);
+                if (SemanticUtils.isNumericType(accessDef, project)) {
+                    //assume we are XML, not XMLList
+                    isXMLList = false;
+                }
+            } else
+                isXMLList = true;
+
+        }
+        return isXMLList;
+    }
+
+    public static boolean isLeftNodeXML(IExpressionNode leftNode, ICompilerProject project) {
+        boolean isXML = false;
+        if (isLeftNodeXMLish(leftNode, project)) {
+            //it is not XMLList if it is a DynamicAccessNode with numeric index.
+            //this is limited analysis, because ["0"] would also be the same as [0], but perhaps best we can do without more runtime support
+            if (leftNode instanceof IDynamicAccessNode) { //DynamicAccessNode
+                IExpressionNode dynAccess = ((IDynamicAccessNode) leftNode).getRightOperandNode();
+                IDefinition accessDef = dynAccess.resolveType(project);
+                if (SemanticUtils.isNumericType(accessDef, project)) {
+                    //assume we are XML, not XMLList
+                    isXML = true;
+                }
+            } else
+                isXML = false;
+
+        }
+        return isXML;
+    }
     
     
     public static boolean isLeftNodeXMLish(IExpressionNode leftNode, ICompilerProject project)