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

* implemented code changes
* updated HTL TCK module to current snapshot
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 @@
         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 @@
             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 @@
                     "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 @@
      * @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 @@
         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 @@
 
             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 @@
                 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 @@
                 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 @@
                 }
                 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 @@
 
             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 @@
 
             @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 @@
                 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,