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();
