You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ra...@apache.org on 2018/05/25 11:28:13 UTC

[sling-org-apache-sling-scripting-sightly-compiler] branch issue/SLING-7682 created (now 97f42d1)

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

radu pushed a change to branch issue/SLING-7682
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-sightly-compiler.git.


      at 97f42d1  SLING-7682 - Add support for data-sly-list and data-sly-repeat iteration control

This branch includes the following new commits:

     new 97f42d1  SLING-7682 - Add support for data-sly-list and data-sly-repeat iteration control

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


-- 
To stop receiving notification emails like this one, please contact
radu@apache.org.

[sling-org-apache-sling-scripting-sightly-compiler] 01/01: SLING-7682 - Add support for data-sly-list and data-sly-repeat iteration control

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

radu pushed a commit to branch issue/SLING-7682
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-sightly-compiler.git

commit 97f42d1168b2093914f9e0842b2a40c4da8b8c4d
Author: Radu Cotescu <ra...@apache.org>
AuthorDate: Fri May 25 13:27:45 2018 +0200

    SLING-7682 - Add support for data-sly-list and data-sly-repeat iteration control
    
    * implemented code changes
    * updated HTL TCK module to current snapshot
---
 pom.xml                                            |   5 +-
 .../scripting/sightly/compiler/commands/Loop.java  |  25 ++++
 .../sightly/compiler/commands/package-info.java    |   2 +-
 .../sightly/compiler/util/VariableTracker.java     |  16 +--
 .../impl/compiler/visitor/TrackingVisitor.java     |   3 +
 .../sightly/impl/plugin/AbstractRepeatPlugin.java  |  71 ++++++++++++
 .../scripting/sightly/impl/plugin/ListPlugin.java  | 126 +++++++++++++--------
 .../sightly/impl/plugin/RepeatPlugin.java          | 118 +++++++++++++------
 8 files changed, 275 insertions(+), 91 deletions(-)

diff --git a/pom.xml b/pom.xml
index ce2529a..6e9b88c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -37,7 +37,7 @@
         The versioning scheme defined here corresponds to SLING-7406 (<module_version>-<htl_specification_version>). Take care when
         releasing to only increase the first part, unless the module provides support for a newer version of the HTL specification.
     -->
-    <version>1.0.21-1.3.1-SNAPSHOT</version>
+    <version>1.0.21-1.4.0-SNAPSHOT</version>
     <packaging>bundle</packaging>
 
     <name>Apache Sling Scripting HTL Compiler</name>
@@ -85,7 +85,8 @@
                             io.sightly.compiler; version:Version=1.1,
                             io.sightly.compiler; version:Version=1.2,
                             io.sightly.compiler; version:Version=1.3,
-                            io.sightly.compiler; version:Version=1.3.1
+                            io.sightly.compiler; version:Version=1.3.1,
+                            io.sightly.compiler; version:Version=1.4.0
                         </Provide-Capability>
                     </instructions>
                 </configuration>
diff --git a/src/main/java/org/apache/sling/scripting/sightly/compiler/commands/Loop.java b/src/main/java/org/apache/sling/scripting/sightly/compiler/commands/Loop.java
index 74dd016..4b3cc8c 100644
--- a/src/main/java/org/apache/sling/scripting/sightly/compiler/commands/Loop.java
+++ b/src/main/java/org/apache/sling/scripting/sightly/compiler/commands/Loop.java
@@ -28,11 +28,21 @@ public final class Loop {
         private String listVariable;
         private String itemVariable;
         private String indexVariable;
+        private String beginVariable;
+        private String stepVariable;
+        private String endVariable;
 
         public Start(String listVariable, String itemVariable, String indexVariable) {
+            this(listVariable, itemVariable, indexVariable, null, null, null);
+        }
+
+        public Start(String listVariable, String itemVariable, String indexVariable, String beginVariable, String stepVariable, String endVariable) {
             this.listVariable = listVariable;
             this.itemVariable = itemVariable;
             this.indexVariable = indexVariable;
+            this.beginVariable = beginVariable;
+            this.stepVariable = stepVariable;
+            this.endVariable = endVariable;
         }
 
         public String getListVariable() {
@@ -47,6 +57,18 @@ public final class Loop {
             return indexVariable;
         }
 
+        public String getBeginVariable() {
+            return beginVariable;
+        }
+
+        public String getStepVariable() {
+            return stepVariable;
+        }
+
+        public String getEndVariable() {
+            return endVariable;
+        }
+
         @Override
         public void accept(CommandVisitor visitor) {
             visitor.visit(this);
@@ -58,6 +80,9 @@ public final class Loop {
                     "listVariable='" + listVariable + '\'' +
                     ", itemVariable='" + itemVariable + '\'' +
                     ", indexVariable='" + indexVariable + '\'' +
+                    ", beginVariable='" + beginVariable + '\'' +
+                    ", stepVariable='" + stepVariable + '\'' +
+                    ", endVariable='" + endVariable + '\'' +
                     '}';
         }
     }
diff --git a/src/main/java/org/apache/sling/scripting/sightly/compiler/commands/package-info.java b/src/main/java/org/apache/sling/scripting/sightly/compiler/commands/package-info.java
index dd2f081..7656a51 100644
--- a/src/main/java/org/apache/sling/scripting/sightly/compiler/commands/package-info.java
+++ b/src/main/java/org/apache/sling/scripting/sightly/compiler/commands/package-info.java
@@ -21,7 +21,7 @@
  * The {@code org.apache.sling.scripting.sightly.compiler.commands} package defines the API for
  * {@link org.apache.sling.scripting.sightly.compiler.commands.Command} processing.
  */
-@Version("1.0.0")
+@Version("1.1.0")
 package org.apache.sling.scripting.sightly.compiler.commands;
 
 import org.osgi.annotation.versioning.Version;
diff --git a/src/main/java/org/apache/sling/scripting/sightly/compiler/util/VariableTracker.java b/src/main/java/org/apache/sling/scripting/sightly/compiler/util/VariableTracker.java
index 54c4189..1157486 100644
--- a/src/main/java/org/apache/sling/scripting/sightly/compiler/util/VariableTracker.java
+++ b/src/main/java/org/apache/sling/scripting/sightly/compiler/util/VariableTracker.java
@@ -50,14 +50,16 @@ public final class VariableTracker<T> {
      * @param data the data associated with the variable
      */
     public void pushVariable(String name, T data) {
-        name = name.toLowerCase();
-        Stack<T> dataStack = variableData.get(name);
-        if (dataStack == null) {
-            dataStack = new Stack<>();
-            variableData.put(name, dataStack);
+        if (name != null) {
+            name = name.toLowerCase();
+            Stack<T> dataStack = variableData.get(name);
+            if (dataStack == null) {
+                dataStack = new Stack<>();
+                variableData.put(name, dataStack);
+            }
+            dataStack.push(data);
+            declarationStack.push(name);
         }
-        dataStack.push(data);
-        declarationStack.push(name);
     }
 
     /**
diff --git a/src/main/java/org/apache/sling/scripting/sightly/impl/compiler/visitor/TrackingVisitor.java b/src/main/java/org/apache/sling/scripting/sightly/impl/compiler/visitor/TrackingVisitor.java
index 246a8c9..2f773d9 100644
--- a/src/main/java/org/apache/sling/scripting/sightly/impl/compiler/visitor/TrackingVisitor.java
+++ b/src/main/java/org/apache/sling/scripting/sightly/impl/compiler/visitor/TrackingVisitor.java
@@ -47,6 +47,9 @@ public abstract class TrackingVisitor<T> extends UniformVisitor {
         super.visit(loopStart);
         tracker.pushVariable(loopStart.getIndexVariable(), assignDefault(loopStart));
         tracker.pushVariable(loopStart.getItemVariable(), assignDefault(loopStart));
+        tracker.pushVariable(loopStart.getBeginVariable(), assignDefault(loopStart));
+        tracker.pushVariable(loopStart.getStepVariable(), assignDefault(loopStart));
+        tracker.pushVariable(loopStart.getEndVariable(), assignDefault(loopStart));
     }
 
     @Override
diff --git a/src/main/java/org/apache/sling/scripting/sightly/impl/plugin/AbstractRepeatPlugin.java b/src/main/java/org/apache/sling/scripting/sightly/impl/plugin/AbstractRepeatPlugin.java
new file mode 100644
index 0000000..801d4e8
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/sightly/impl/plugin/AbstractRepeatPlugin.java
@@ -0,0 +1,71 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements.  See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership.  The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License.  You may obtain a copy of the License at
+ ~
+ ~   http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied.  See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+package org.apache.sling.scripting.sightly.impl.plugin;
+
+import java.util.HashMap;
+
+import org.apache.sling.scripting.sightly.compiler.expression.ExpressionNode;
+import org.apache.sling.scripting.sightly.compiler.expression.nodes.BinaryOperation;
+import org.apache.sling.scripting.sightly.compiler.expression.nodes.BinaryOperator;
+import org.apache.sling.scripting.sightly.compiler.expression.nodes.Identifier;
+import org.apache.sling.scripting.sightly.compiler.expression.nodes.MapLiteral;
+import org.apache.sling.scripting.sightly.compiler.expression.nodes.NumericConstant;
+import org.apache.sling.scripting.sightly.compiler.expression.nodes.UnaryOperation;
+import org.apache.sling.scripting.sightly.compiler.expression.nodes.UnaryOperator;
+
+public abstract class AbstractRepeatPlugin extends AbstractPlugin {
+
+    protected static final String INDEX = "index";
+    protected static final String COUNT = "count";
+    protected static final String FIRST = "first";
+    protected static final String MIDDLE = "middle";
+    protected static final String LAST = "last";
+    protected static final String ODD = "odd";
+    protected static final String EVEN = "even";
+    protected static final String BEGIN = "begin";
+    protected static final String STEP = "step";
+    protected static final String END = "end";
+
+    protected MapLiteral buildStatusObj(String indexVar, String sizeVar) {
+        HashMap<String, ExpressionNode> obj = new HashMap<>();
+        Identifier indexId = new Identifier(indexVar);
+        BinaryOperation firstExpr = new BinaryOperation(BinaryOperator.EQ, indexId, NumericConstant.ZERO);
+        BinaryOperation lastExpr = new BinaryOperation(
+                BinaryOperator.EQ,
+                indexId,
+                new BinaryOperation(BinaryOperator.SUB, new Identifier(sizeVar), NumericConstant.ONE));
+        obj.put(INDEX, indexId);
+        obj.put(COUNT, new BinaryOperation(BinaryOperator.ADD, indexId, NumericConstant.ONE));
+        obj.put(FIRST, firstExpr);
+        obj.put(MIDDLE, new UnaryOperation(
+                UnaryOperator.NOT,
+                new BinaryOperation(BinaryOperator.OR, firstExpr, lastExpr)));
+        obj.put(LAST, lastExpr);
+        obj.put(ODD, parityCheck(indexId, NumericConstant.ZERO));
+        obj.put(EVEN, parityCheck(indexId, NumericConstant.ONE));
+        return new MapLiteral(obj);
+    }
+
+    private ExpressionNode parityCheck(ExpressionNode numericExpression, NumericConstant expected) {
+        return new BinaryOperation(
+                BinaryOperator.EQ,
+                new BinaryOperation(BinaryOperator.REM, numericExpression, NumericConstant.TWO),
+                expected);
+    }
+}
diff --git a/src/main/java/org/apache/sling/scripting/sightly/impl/plugin/ListPlugin.java b/src/main/java/org/apache/sling/scripting/sightly/impl/plugin/ListPlugin.java
index 6a62c5a..a613a69 100644
--- a/src/main/java/org/apache/sling/scripting/sightly/impl/plugin/ListPlugin.java
+++ b/src/main/java/org/apache/sling/scripting/sightly/impl/plugin/ListPlugin.java
@@ -18,33 +18,24 @@
  ******************************************************************************/
 package org.apache.sling.scripting.sightly.impl.plugin;
 
-import java.util.HashMap;
+import java.util.Map;
 
-import org.apache.sling.scripting.sightly.impl.compiler.Syntax;
+import org.apache.sling.scripting.sightly.compiler.commands.Conditional;
+import org.apache.sling.scripting.sightly.compiler.commands.Loop;
+import org.apache.sling.scripting.sightly.compiler.commands.VariableBinding;
 import org.apache.sling.scripting.sightly.compiler.expression.Expression;
 import org.apache.sling.scripting.sightly.compiler.expression.ExpressionNode;
 import org.apache.sling.scripting.sightly.compiler.expression.nodes.BinaryOperation;
 import org.apache.sling.scripting.sightly.compiler.expression.nodes.BinaryOperator;
 import org.apache.sling.scripting.sightly.compiler.expression.nodes.Identifier;
-import org.apache.sling.scripting.sightly.compiler.expression.nodes.MapLiteral;
 import org.apache.sling.scripting.sightly.compiler.expression.nodes.NumericConstant;
 import org.apache.sling.scripting.sightly.compiler.expression.nodes.UnaryOperation;
 import org.apache.sling.scripting.sightly.compiler.expression.nodes.UnaryOperator;
-import org.apache.sling.scripting.sightly.compiler.commands.Conditional;
-import org.apache.sling.scripting.sightly.compiler.commands.Loop;
-import org.apache.sling.scripting.sightly.compiler.commands.VariableBinding;
-import org.apache.sling.scripting.sightly.impl.compiler.frontend.CompilerContext;
 import org.apache.sling.scripting.sightly.impl.compiler.PushStream;
+import org.apache.sling.scripting.sightly.impl.compiler.Syntax;
+import org.apache.sling.scripting.sightly.impl.compiler.frontend.CompilerContext;
 
-public class ListPlugin extends AbstractPlugin {
-
-    private static final String INDEX = "index";
-    private static final String COUNT = "count";
-    private static final String FIRST = "first";
-    private static final String MIDDLE = "middle";
-    private static final String LAST = "last";
-    private static final String ODD = "odd";
-    private static final String EVEN = "even";
+public class ListPlugin extends AbstractRepeatPlugin {
 
     public ListPlugin() {
         name = "list";
@@ -57,14 +48,51 @@ public class ListPlugin extends AbstractPlugin {
 
             private String listVariable = compilerContext.generateVariable("collectionVar");
             private String collectionSizeVar = compilerContext.generateVariable("size");
+            private String collectionNotEmpty = compilerContext.generateVariable("notEmpty");
+            private String beginVariable = compilerContext.generateVariable(BEGIN);
+            private String stepVariable = compilerContext.generateVariable(STEP);
+            private String endVariable = compilerContext.generateVariable(END);
+            private String validStartStepEnd = compilerContext.generateVariable("validStartStepEnd");
 
             @Override
             public void beforeElement(PushStream stream, String tagName) {
                 stream.write(new VariableBinding.Start(listVariable, expression.getRoot()));
                 stream.write(new VariableBinding.Start(collectionSizeVar,
                         new UnaryOperation(UnaryOperator.LENGTH, new Identifier(listVariable))));
-                stream.write(new Conditional.Start(collectionSizeVar, true));
-
+                stream.write(new VariableBinding.Start(collectionNotEmpty, new BinaryOperation(BinaryOperator.GT, new Identifier
+                        (collectionSizeVar), NumericConstant.ZERO)));
+                stream.write(new Conditional.Start(collectionNotEmpty, true));
+                Map<String, ExpressionNode> options = expression.getOptions();
+                if (options.containsKey(BEGIN)) {
+                    stream.write(new VariableBinding.Start(beginVariable, expression.getOptions().get(BEGIN)));
+                } else {
+                    stream.write(new VariableBinding.Start(beginVariable, NumericConstant.ZERO));
+                }
+                if (options.containsKey(STEP)) {
+                    stream.write(new VariableBinding.Start(stepVariable, expression.getOptions().get(STEP)));
+                } else {
+                    stream.write(new VariableBinding.Start(stepVariable, NumericConstant.ONE));
+                }
+                if (options.containsKey(END)) {
+                    stream.write(new VariableBinding.Start(endVariable, expression.getOptions().get(END)));
+                } else {
+                    stream.write(new VariableBinding.Start(endVariable, new Identifier(collectionSizeVar)));
+                }
+                stream.write(new VariableBinding.Start(validStartStepEnd,
+                            new BinaryOperation(BinaryOperator.AND,
+                                new BinaryOperation(BinaryOperator.AND,
+                                    new BinaryOperation(BinaryOperator.LT, new Identifier(beginVariable), new Identifier(collectionSizeVar)),
+                                    new BinaryOperation(
+                                            BinaryOperator.AND,
+                                            new BinaryOperation(BinaryOperator.GEQ, new Identifier(beginVariable), NumericConstant.ZERO),
+                                            new BinaryOperation(BinaryOperator.GT, new Identifier(stepVariable), NumericConstant.ZERO)
+                                    )
+                                ),
+                                new BinaryOperation(BinaryOperator.GT, new Identifier(endVariable), NumericConstant.ZERO)
+                            )
+                        )
+                );
+                stream.write(new Conditional.Start(validStartStepEnd, true));
             }
 
             @Override
@@ -74,10 +102,39 @@ public class ListPlugin extends AbstractPlugin {
                 String indexVariable = compilerContext.generateVariable("index");
                 stream.write(new Loop.Start(listVariable, itemVariable, indexVariable));
                 stream.write(new VariableBinding.Start(loopStatusVar, buildStatusObj(indexVariable, collectionSizeVar)));
+                String stepConditionVariable = compilerContext.generateVariable("stepCondition");
+                stream.write(new VariableBinding.Start(stepConditionVariable,
+                        new BinaryOperation(
+                                BinaryOperator.REM,
+                                new BinaryOperation(
+                                        BinaryOperator.SUB,
+                                        new Identifier(indexVariable),
+                                        new Identifier(beginVariable)
+                                ),
+                                new Identifier(stepVariable))
+                        )
+                );
+                String loopTraversalVariable = compilerContext.generateVariable("traversal");
+                stream.write(new VariableBinding.Start(loopTraversalVariable,
+                            new BinaryOperation(
+                                BinaryOperator.AND,
+                                new BinaryOperation(
+                                    BinaryOperator.AND,
+                                    new BinaryOperation(BinaryOperator.GEQ, new Identifier(indexVariable), new Identifier(beginVariable)),
+                                    new BinaryOperation(BinaryOperator.LEQ, new Identifier(indexVariable), new Identifier(endVariable))
+                                ),
+                                new BinaryOperation(BinaryOperator.EQ, new Identifier(stepConditionVariable), NumericConstant.ZERO)
+                            )
+                        )
+                );
+                stream.write(new Conditional.Start(loopTraversalVariable, true));
             }
 
             @Override
             public void afterChildren(PushStream stream) {
+                stream.write(Conditional.END);
+                stream.write(VariableBinding.END);
+                stream.write(VariableBinding.END);
                 stream.write(VariableBinding.END);
                 stream.write(Loop.END);
             }
@@ -87,6 +144,12 @@ public class ListPlugin extends AbstractPlugin {
                 stream.write(Conditional.END);
                 stream.write(VariableBinding.END);
                 stream.write(VariableBinding.END);
+                stream.write(VariableBinding.END);
+                stream.write(VariableBinding.END);
+                stream.write(Conditional.END);
+                stream.write(VariableBinding.END);
+                stream.write(VariableBinding.END);
+                stream.write(VariableBinding.END);
             }
 
 
@@ -97,33 +160,6 @@ public class ListPlugin extends AbstractPlugin {
                 }
                 return Syntax.DEFAULT_LIST_ITEM_VAR_NAME;
             }
-
-            private MapLiteral buildStatusObj(String indexVar, String sizeVar) {
-                HashMap<String, ExpressionNode> obj = new HashMap<>();
-                Identifier indexId = new Identifier(indexVar);
-                BinaryOperation firstExpr = new BinaryOperation(BinaryOperator.EQ, indexId, NumericConstant.ZERO);
-                BinaryOperation lastExpr = new BinaryOperation(
-                        BinaryOperator.EQ,
-                        indexId,
-                        new BinaryOperation(BinaryOperator.SUB, new Identifier(sizeVar), NumericConstant.ONE));
-                obj.put(INDEX, indexId);
-                obj.put(COUNT, new BinaryOperation(BinaryOperator.ADD, indexId, NumericConstant.ONE));
-                obj.put(FIRST, firstExpr);
-                obj.put(MIDDLE, new UnaryOperation(
-                        UnaryOperator.NOT,
-                        new BinaryOperation(BinaryOperator.OR, firstExpr, lastExpr)));
-                obj.put(LAST, lastExpr);
-                obj.put(ODD, parityCheck(indexId, NumericConstant.ZERO));
-                obj.put(EVEN, parityCheck(indexId, NumericConstant.ONE));
-                return new MapLiteral(obj);
-            }
-
-            private ExpressionNode parityCheck(ExpressionNode numericExpression, NumericConstant expected) {
-                return new BinaryOperation(
-                        BinaryOperator.EQ,
-                        new BinaryOperation(BinaryOperator.REM, numericExpression, NumericConstant.TWO),
-                        expected);
-            }
         };
     }
 }
diff --git a/src/main/java/org/apache/sling/scripting/sightly/impl/plugin/RepeatPlugin.java b/src/main/java/org/apache/sling/scripting/sightly/impl/plugin/RepeatPlugin.java
index e8ca678..ff8d41d 100644
--- a/src/main/java/org/apache/sling/scripting/sightly/impl/plugin/RepeatPlugin.java
+++ b/src/main/java/org/apache/sling/scripting/sightly/impl/plugin/RepeatPlugin.java
@@ -18,34 +18,26 @@
  ******************************************************************************/
 package org.apache.sling.scripting.sightly.impl.plugin;
 
-import java.util.HashMap;
+import java.util.Map;
 
+import org.apache.sling.scripting.sightly.compiler.commands.Conditional;
+import org.apache.sling.scripting.sightly.compiler.commands.Loop;
 import org.apache.sling.scripting.sightly.compiler.commands.OutText;
-import org.apache.sling.scripting.sightly.impl.compiler.Syntax;
+import org.apache.sling.scripting.sightly.compiler.commands.VariableBinding;
 import org.apache.sling.scripting.sightly.compiler.expression.Expression;
 import org.apache.sling.scripting.sightly.compiler.expression.ExpressionNode;
 import org.apache.sling.scripting.sightly.compiler.expression.nodes.BinaryOperation;
 import org.apache.sling.scripting.sightly.compiler.expression.nodes.BinaryOperator;
 import org.apache.sling.scripting.sightly.compiler.expression.nodes.Identifier;
-import org.apache.sling.scripting.sightly.compiler.expression.nodes.MapLiteral;
 import org.apache.sling.scripting.sightly.compiler.expression.nodes.NumericConstant;
 import org.apache.sling.scripting.sightly.compiler.expression.nodes.UnaryOperation;
 import org.apache.sling.scripting.sightly.compiler.expression.nodes.UnaryOperator;
-import org.apache.sling.scripting.sightly.impl.compiler.frontend.CompilerContext;
-import org.apache.sling.scripting.sightly.compiler.commands.Conditional;
-import org.apache.sling.scripting.sightly.compiler.commands.Loop;
-import org.apache.sling.scripting.sightly.compiler.commands.VariableBinding;
 import org.apache.sling.scripting.sightly.impl.compiler.PushStream;
+import org.apache.sling.scripting.sightly.impl.compiler.Syntax;
+import org.apache.sling.scripting.sightly.impl.compiler.frontend.CompilerContext;
 
-public class RepeatPlugin extends AbstractPlugin {
+public class RepeatPlugin extends AbstractRepeatPlugin {
 
-    private static final String INDEX = "index";
-    private static final String COUNT = "count";
-    private static final String FIRST = "first";
-    private static final String MIDDLE = "middle";
-    private static final String LAST = "last";
-    private static final String ODD = "odd";
-    private static final String EVEN = "even";
     private static final OutText NEW_LINE = new OutText("\n");
 
     public RepeatPlugin() {
@@ -59,18 +51,83 @@ public class RepeatPlugin extends AbstractPlugin {
 
             private String listVariable = compilerContext.generateVariable("collectionVar");
             private String collectionSizeVar = compilerContext.generateVariable("size");
+            private String collectionNotEmpty = compilerContext.generateVariable("notEmpty");
+            private String beginVariable = compilerContext.generateVariable(BEGIN);
+            private String stepVariable = compilerContext.generateVariable(STEP);
+            private String endVariable = compilerContext.generateVariable(END);
+            private String validStartStepEnd = compilerContext.generateVariable("validStartStepEnd");
 
             @Override
             public void beforeElement(PushStream stream, String tagName) {
                 stream.write(new VariableBinding.Start(listVariable, expression.getRoot()));
                 stream.write(new VariableBinding.Start(collectionSizeVar,
                         new UnaryOperation(UnaryOperator.LENGTH, new Identifier(listVariable))));
-                stream.write(new Conditional.Start(collectionSizeVar, true));
+                stream.write(new VariableBinding.Start(collectionNotEmpty, new BinaryOperation(BinaryOperator.GT, new Identifier
+                        (collectionSizeVar), NumericConstant.ZERO)));
+                stream.write(new Conditional.Start(collectionNotEmpty, true));
+                Map<String, ExpressionNode> options = expression.getOptions();
+                if (options.containsKey(BEGIN)) {
+                    stream.write(new VariableBinding.Start(beginVariable, expression.getOptions().get(BEGIN)));
+                } else {
+                    stream.write(new VariableBinding.Start(beginVariable, NumericConstant.ZERO));
+                }
+                if (options.containsKey(STEP)) {
+                    stream.write(new VariableBinding.Start(stepVariable, expression.getOptions().get(STEP)));
+                } else {
+                    stream.write(new VariableBinding.Start(stepVariable, NumericConstant.ONE));
+                }
+                if (options.containsKey(END)) {
+                    stream.write(new VariableBinding.Start(endVariable, expression.getOptions().get(END)));
+                } else {
+                    stream.write(new VariableBinding.Start(endVariable, new Identifier(collectionSizeVar)));
+                }
+                stream.write(new VariableBinding.Start(validStartStepEnd,
+                                new BinaryOperation(BinaryOperator.AND,
+                                        new BinaryOperation(BinaryOperator.AND,
+                                                new BinaryOperation(BinaryOperator.LT, new Identifier(beginVariable), new Identifier(collectionSizeVar)),
+                                                new BinaryOperation(
+                                                        BinaryOperator.AND,
+                                                        new BinaryOperation(BinaryOperator.GEQ, new Identifier(beginVariable), NumericConstant.ZERO),
+                                                        new BinaryOperation(BinaryOperator.GT, new Identifier(stepVariable), NumericConstant.ZERO)
+                                                )
+                                        ),
+                                        new BinaryOperation(BinaryOperator.GT, new Identifier(endVariable), NumericConstant.ZERO)
+                                )
+                        )
+                );
+                stream.write(new Conditional.Start(validStartStepEnd, true));
                 String itemVariable = decodeItemVariable();
                 String loopStatusVar = Syntax.itemLoopStatusVariable(itemVariable);
                 String indexVariable = compilerContext.generateVariable("index");
                 stream.write(new Loop.Start(listVariable, itemVariable, indexVariable));
                 stream.write(new VariableBinding.Start(loopStatusVar, buildStatusObj(indexVariable, collectionSizeVar)));
+                String stepConditionVariable = compilerContext.generateVariable("stepCondition");
+                stream.write(new VariableBinding.Start(stepConditionVariable,
+                                new BinaryOperation(
+                                        BinaryOperator.REM,
+                                        new BinaryOperation(
+                                                BinaryOperator.SUB,
+                                                new Identifier(indexVariable),
+                                                new Identifier(beginVariable)
+                                        ),
+                                        new Identifier(stepVariable))
+                        )
+                );
+                String loopTraversalVariable = compilerContext.generateVariable("traversal");
+                stream.write(new VariableBinding.Start(loopTraversalVariable,
+                                new BinaryOperation(
+                                        BinaryOperator.AND,
+                                        new BinaryOperation(
+                                                BinaryOperator.AND,
+                                                new BinaryOperation(BinaryOperator.GEQ, new Identifier(indexVariable), new Identifier(
+                                                        beginVariable)),
+                                                new BinaryOperation(BinaryOperator.LEQ, new Identifier(indexVariable), new Identifier(endVariable))
+                                        ),
+                                        new BinaryOperation(BinaryOperator.EQ, new Identifier(stepConditionVariable), NumericConstant.ZERO)
+                                )
+                        )
+                );
+                stream.write(new Conditional.Start(loopTraversalVariable, true));
 
             }
 
@@ -81,11 +138,20 @@ public class RepeatPlugin extends AbstractPlugin {
 
             @Override
             public void afterElement(PushStream stream) {
+                stream.write(Conditional.END);
+                stream.write(VariableBinding.END);
+                stream.write(VariableBinding.END);
                 stream.write(VariableBinding.END);
                 stream.write(Loop.END);
                 stream.write(Conditional.END);
                 stream.write(VariableBinding.END);
                 stream.write(VariableBinding.END);
+                stream.write(VariableBinding.END);
+                stream.write(VariableBinding.END);
+                stream.write(Conditional.END);
+                stream.write(VariableBinding.END);
+                stream.write(VariableBinding.END);
+                stream.write(VariableBinding.END);
             }
 
 
@@ -97,26 +163,6 @@ public class RepeatPlugin extends AbstractPlugin {
                 return Syntax.DEFAULT_LIST_ITEM_VAR_NAME;
             }
 
-            private MapLiteral buildStatusObj(String indexVar, String sizeVar) {
-                HashMap<String, ExpressionNode> obj = new HashMap<>();
-                Identifier indexId = new Identifier(indexVar);
-                BinaryOperation firstExpr = new BinaryOperation(BinaryOperator.EQ, indexId, NumericConstant.ZERO);
-                BinaryOperation lastExpr = new BinaryOperation(
-                        BinaryOperator.EQ,
-                        indexId,
-                        new BinaryOperation(BinaryOperator.SUB, new Identifier(sizeVar), NumericConstant.ONE));
-                obj.put(INDEX, indexId);
-                obj.put(COUNT, new BinaryOperation(BinaryOperator.ADD, indexId, NumericConstant.ONE));
-                obj.put(FIRST, firstExpr);
-                obj.put(MIDDLE, new UnaryOperation(
-                        UnaryOperator.NOT,
-                        new BinaryOperation(BinaryOperator.OR, firstExpr, lastExpr)));
-                obj.put(LAST, lastExpr);
-                obj.put(ODD, parityCheck(indexId, NumericConstant.ZERO));
-                obj.put(EVEN, parityCheck(indexId, NumericConstant.ONE));
-                return new MapLiteral(obj);
-            }
-
             private ExpressionNode parityCheck(ExpressionNode numericExpression, NumericConstant expected) {
                 return new BinaryOperation(
                         BinaryOperator.EQ,

-- 
To stop receiving notification emails like this one, please contact
radu@apache.org.