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

commit 5b48c59756394908d0c31ac25ad8e838130a1e65
Author: greg-dove <[email protected]>
AuthorDate: Wed Oct 2 12:43:25 2019 +1300

    Support iteration over keys as well as values (for-in in addition to 
for-each-in)
---
 .../royale/compiler/internal/scopes/ASScope.java   | 26 +++++++++++-----------
 .../compiler/internal/tree/as/ForLoopNode.java     |  6 +++--
 .../main/java/org/apache/royale/utils/ASTUtil.java |  4 ++--
 .../org/apache/royale/utils/ArrayLikeUtil.java     | 22 +++++++++++++-----
 4 files changed, 35 insertions(+), 23 deletions(-)

diff --git 
a/compiler/src/main/java/org/apache/royale/compiler/internal/scopes/ASScope.java
 
b/compiler/src/main/java/org/apache/royale/compiler/internal/scopes/ASScope.java
index 3893bb4..da46edc 100644
--- 
a/compiler/src/main/java/org/apache/royale/compiler/internal/scopes/ASScope.java
+++ 
b/compiler/src/main/java/org/apache/royale/compiler/internal/scopes/ASScope.java
@@ -71,7 +71,7 @@ public abstract class ASScope extends ASScopeBase
     protected static final NamespaceDefinition.IUseNamespaceDirective[] 
EMPTY_USE_ARRAY =
             new NamespaceDefinition.IUseNamespaceDirective[0];
     
-    private static IForLoopNode[] EMPTY_FOREACH_ARRAY = new IForLoopNode[0];
+    private static IForLoopNode[] EMPTY_LOOPCHECK_ARRAY = new IForLoopNode[0];
 
     /**
      * Constructor
@@ -126,18 +126,18 @@ public abstract class ASScope extends ASScopeBase
 
     private boolean inWith = false;
     
-    private Object forEachs = null;
-    public boolean getHasForEach(){
-        return forEachs != null;
-    }
-    public void addForEach(IForLoopNode value){
-        if (forEachs == null) forEachs = CheapArray.create(1);
-        CheapArray.add(value, forEachs);
-    }
-    public IForLoopNode[] getForEachs(boolean remove){
-        IForLoopNode[] returnForEachs = (IForLoopNode[]) 
CheapArray.toArray(forEachs, EMPTY_FOREACH_ARRAY);
-        if (remove) forEachs = null;
-        return returnForEachs;
+    private Object loopChecks = null;
+    public boolean getHasLoopCheck(){
+        return loopChecks != null;
+    }
+    public void addLoopCheck(IForLoopNode value){
+        if (loopChecks == null) loopChecks = CheapArray.create(1);
+        CheapArray.add(value, loopChecks);
+    }
+    public IForLoopNode[] getLoopChecks(boolean remove){
+        IForLoopNode[] returnLoopChecks = (IForLoopNode[]) 
CheapArray.toArray(loopChecks, EMPTY_LOOPCHECK_ARRAY);
+        if (remove) loopChecks = null;
+        return returnLoopChecks;
     }
     /**
      * Sets the scope which lexically contains this scope.
diff --git 
a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/ForLoopNode.java
 
b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/ForLoopNode.java
index 9a58bcd..bdd7c4c 100644
--- 
a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/ForLoopNode.java
+++ 
b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/ForLoopNode.java
@@ -144,8 +144,10 @@ public class ForLoopNode extends FixedChildrenNode 
implements IForLoopNode
         conditionsStatementsNode.analyze(set, scope, problems);
         contentsNode.analyze(set, scope, problems);
         // add for-each kind for subsequent post-processing step at function 
scope level
-        if (kind == ForLoopKind.FOR_EACH) {
-            scope.addForEach(this);
+        if (kind == ForLoopKind.FOR_EACH
+                //also support for - in loops:
+                || conditionsStatementsNode.getChildCount() == 1 && 
conditionsStatementsNode.getChild(0).getNodeID() == ASTNodeID.Op_InID) {
+            scope.addLoopCheck(this);
         }
     }
     
diff --git a/compiler/src/main/java/org/apache/royale/utils/ASTUtil.java 
b/compiler/src/main/java/org/apache/royale/utils/ASTUtil.java
index 8cd5aaf..af23f1d 100644
--- a/compiler/src/main/java/org/apache/royale/utils/ASTUtil.java
+++ b/compiler/src/main/java/org/apache/royale/utils/ASTUtil.java
@@ -32,9 +32,9 @@ public class ASTUtil {
             return;
         }
         ArrayLikeUtil.preProcessGetterSetters(project, 
funcNode.getScopedNode(), null);
-        if (funcNode.getDefinition().getContainedScope().getHasForEach()) {
+        if (funcNode.getDefinition().getContainedScope().getHasLoopCheck()) {
             //pre-process for 'ArrayLike' for-each mutations
-            
ArrayLikeUtil.preProcessForEachLoops(funcNode.getDefinition().getContainedScope(),
 project, dynamicTarget);
+            
ArrayLikeUtil.preProcessLoopChecks(funcNode.getDefinition().getContainedScope(),
 project, dynamicTarget);
         }
        
     }
diff --git a/compiler/src/main/java/org/apache/royale/utils/ArrayLikeUtil.java 
b/compiler/src/main/java/org/apache/royale/utils/ArrayLikeUtil.java
index e32b891..421a4b1 100644
--- a/compiler/src/main/java/org/apache/royale/utils/ArrayLikeUtil.java
+++ b/compiler/src/main/java/org/apache/royale/utils/ArrayLikeUtil.java
@@ -277,23 +277,25 @@ public class ArrayLikeUtil
      * @param project
      * @param useDynamicAccess
      */
-    public static void preProcessForEachLoops(ASScope 
searchScope,ICompilerProject project, boolean useDynamicAccess) {
+    public static void preProcessLoopChecks(ASScope 
searchScope,ICompilerProject project, boolean useDynamicAccess) {
 
         ScopedBlockNode funcScopeNode = (ScopedBlockNode) 
searchScope.getScopeNode();
         
-        IForLoopNode[] forEachs = searchScope.getForEachs(true);
-        List<IForLoopNode> forEachList = Arrays.asList(forEachs);
+        IForLoopNode[] forLoops = searchScope.getLoopChecks(true);
+        List<IForLoopNode> forLoopList = Arrays.asList(forLoops);
         boolean importAdded = false;
         ArrayList<String> usedIterators = new ArrayList<String>();
-        for (IForLoopNode loopNode : forEachList) {
+        for (IForLoopNode loopNode : forLoopList) {
             int depth = 0;
             IASNode nodeCheck = loopNode;
             while (nodeCheck.getParent() != null && nodeCheck.getParent() != 
funcScopeNode) {
-                if (nodeCheck.getParent() instanceof IForLoopNode && 
forEachList.indexOf(nodeCheck.getParent()) != -1) {
+                if (nodeCheck.getParent() instanceof IForLoopNode && 
forLoopList.indexOf(nodeCheck.getParent()) != -1) {
                     depth++;
                 }
                 nodeCheck = nodeCheck.getParent();
             }
+            //are we dealing with a regular for..in or a for each..in loop:
+            boolean isForeach = loopNode.getKind() == 
IForLoopNode.ForLoopKind.FOR_EACH;
             //create a valid name for the iterator at the current depth of 
for-each loops, re-using previous declared variables, where possible
             String arrIter = ARRAY_LIKE_FOREACH_ITERATOR_VARNAME_BASE + depth;
             IDefinition targetType;
@@ -376,7 +378,7 @@ public class ArrayLikeUtil
                 IDefinition metaSource = 
ArrayLikeUtil.resolveArrayLikeDefinitionSource(targetType, project);
                 IMetaTag arrayLikeTag = 
ArrayLikeUtil.getArrayLikeMetaData(metaSource);
         
-                //change the loop node to: for(arrIter:Object = 
arrayLike(instance,"{lengthCheck}","{getterCheck}" or (null if 
getterCheck=="[]"), Boolean(lengthAccess=="method")); arrIter.hasNext();)
+                //change the loop node to: for(arrIter:Object = 
arrayLike(instance,"{lengthCheck}","{getterCheck}" or (null if 
getterCheck=="[]"), Boolean(lengthAccess=="method"), Boolean(!isForEach)); 
arrIter.hasNext();)
                 // {
                 // {!alreadyUsed: var} originalName{!alreadyUsed: 
:OriginalType} =  arrIter.getNext();
                 // {originalBody Loop body}
@@ -413,6 +415,14 @@ public class ArrayLikeUtil
                 metaArg = new LiteralNode(ILiteralNode.LiteralType.BOOLEAN, 
ArrayLikeUtil.getLengthAccessArg(arrayLikeTag).equals("method") ? "true" : 
"false");
                 metaArg.setSynthetic(true); //may not be needed
                 specificIteratorFunc.getArgumentsNode().addItem(metaArg);
+                
+                //distinguish whether this iterator is values (for each(x in 
y)) or keys (regular for (x in y))
+                if (!isForeach) {
+                    //we add an extra boolean true indicating that we only 
want to iterate over keys (and not values)
+                    metaArg = new 
LiteralNode(ILiteralNode.LiteralType.BOOLEAN, "true");
+                    metaArg.setSynthetic(true); //may not be needed
+                    specificIteratorFunc.getArgumentsNode().addItem(metaArg);
+                }
         
                 mutation.prepareConditionals(!alreadyUsed, 
specificIteratorFunc);
                 mutation.prepareContent();

Reply via email to