SLING-8217 - Numeric operations can lead to Java code that doesn't compile
diff --git a/src/main/java/org/apache/sling/scripting/sightly/java/compiler/impl/operator/LongOpGen.java b/src/main/java/org/apache/sling/scripting/sightly/java/compiler/impl/operator/LongOpGen.java
index a2b2502..7876b96 100644
--- a/src/main/java/org/apache/sling/scripting/sightly/java/compiler/impl/operator/LongOpGen.java
+++ b/src/main/java/org/apache/sling/scripting/sightly/java/compiler/impl/operator/LongOpGen.java
@@ -17,6 +17,7 @@
 
 package org.apache.sling.scripting.sightly.java.compiler.impl.operator;
 
+import org.apache.sling.scripting.sightly.compiler.expression.nodes.BinaryOperator;
 import org.apache.sling.scripting.sightly.java.compiler.impl.Type;
 
 /**
@@ -24,8 +25,8 @@
  */
 public class LongOpGen extends NumericOpGen {
 
-    public LongOpGen(String javaOperator) {
-        super(javaOperator);
+    public LongOpGen(String javaOperator, BinaryOperator binaryOperator) {
+        super(javaOperator, binaryOperator);
     }
 
     @Override
diff --git a/src/main/java/org/apache/sling/scripting/sightly/java/compiler/impl/operator/NumericOpGen.java b/src/main/java/org/apache/sling/scripting/sightly/java/compiler/impl/operator/NumericOpGen.java
index be3dc7e..2d57d56 100644
--- a/src/main/java/org/apache/sling/scripting/sightly/java/compiler/impl/operator/NumericOpGen.java
+++ b/src/main/java/org/apache/sling/scripting/sightly/java/compiler/impl/operator/NumericOpGen.java
@@ -17,9 +17,11 @@
 
 package org.apache.sling.scripting.sightly.java.compiler.impl.operator;
 
+import org.apache.sling.scripting.sightly.compiler.expression.nodes.BinaryOperator;
 import org.apache.sling.scripting.sightly.java.compiler.impl.ExpressionTranslator;
 import org.apache.sling.scripting.sightly.java.compiler.impl.GenHelper;
 import org.apache.sling.scripting.sightly.java.compiler.impl.JavaSource;
+import org.apache.sling.scripting.sightly.java.compiler.impl.SourceGenConstants;
 import org.apache.sling.scripting.sightly.java.compiler.impl.Type;
 
 /**
@@ -27,10 +29,15 @@
  */
 public class NumericOpGen implements BinaryOpGen {
 
-    private final String javaOperator;
+    private static final String OBJECT_NAME = BinaryOperator.class.getName();
+    private static final String METHOD_NAME = "eval";
 
-    public NumericOpGen(String javaOperator) {
+    private final String javaOperator;
+    private final BinaryOperator binaryOperator;
+
+    public NumericOpGen(String javaOperator, BinaryOperator binaryOperator) {
         this.javaOperator = javaOperator;
+        this.binaryOperator = binaryOperator;
     }
 
     @Override
@@ -41,9 +48,12 @@
     @Override
     public void generate(JavaSource source, ExpressionTranslator visitor, TypedNode left, TypedNode right) {
         Type commonType = commonType(left.getType(), right.getType());
-        GenHelper.typeCoercion(source, visitor, left, commonType);
-        source.append(" ").append(javaOperator).append(" ");
-        GenHelper.typeCoercion(source, visitor, right, commonType);
+        source.objectModel().startCall(SourceGenConstants.ROM_TO_NUMBER, true).startMethodCall(OBJECT_NAME + "." + binaryOperator.name(),
+                METHOD_NAME);
+        left.getNode().accept(visitor);
+        source.separateArgument();
+        right.getNode().accept(visitor);
+        source.endCall().endCall().startCall(commonType.getNativeClass() + "Value", true).endCall();
     }
 
     protected Type commonType(Type leftType, Type rightType) {
diff --git a/src/main/java/org/apache/sling/scripting/sightly/java/compiler/impl/operator/Operators.java b/src/main/java/org/apache/sling/scripting/sightly/java/compiler/impl/operator/Operators.java
index c445b29..a895e4d 100644
--- a/src/main/java/org/apache/sling/scripting/sightly/java/compiler/impl/operator/Operators.java
+++ b/src/main/java/org/apache/sling/scripting/sightly/java/compiler/impl/operator/Operators.java
@@ -37,12 +37,12 @@
         representationMap.put(BinaryOperator.AND, LogicalOpGen.AND);
         representationMap.put(BinaryOperator.OR, LogicalOpGen.OR);
         representationMap.put(BinaryOperator.CONCATENATE, ConcatenateOpGen.INSTANCE);
-        representationMap.put(BinaryOperator.ADD, new NumericOpGen("+"));
-        representationMap.put(BinaryOperator.SUB, new NumericOpGen("-"));
-        representationMap.put(BinaryOperator.MUL, new NumericOpGen("*"));
-        representationMap.put(BinaryOperator.I_DIV, new LongOpGen("/"));
-        representationMap.put(BinaryOperator.REM, new LongOpGen("%"));
-        representationMap.put(BinaryOperator.DIV, new NumericOpGen("/"));
+        representationMap.put(BinaryOperator.ADD, new NumericOpGen("+", BinaryOperator.ADD));
+        representationMap.put(BinaryOperator.SUB, new NumericOpGen("-", BinaryOperator.SUB));
+        representationMap.put(BinaryOperator.MUL, new NumericOpGen("*", BinaryOperator.MUL));
+        representationMap.put(BinaryOperator.I_DIV, new LongOpGen("/", BinaryOperator.I_DIV));
+        representationMap.put(BinaryOperator.REM, new LongOpGen("%", BinaryOperator.REM));
+        representationMap.put(BinaryOperator.DIV, new NumericOpGen("/", BinaryOperator.DIV));
         representationMap.put(BinaryOperator.EQ, new EquivalenceOpGen(false));
         representationMap.put(BinaryOperator.NEQ, new EquivalenceOpGen(true));
         representationMap.put(BinaryOperator.LT, new ComparisonOpGen(BinaryOperator.LT));
diff --git a/src/test/java/org/apache/sling/scripting/sightly/compiler/java/JavaClassBackendCompilerTest.java b/src/test/java/org/apache/sling/scripting/sightly/compiler/java/JavaClassBackendCompilerTest.java
index a1606c3..9437054 100644
--- a/src/test/java/org/apache/sling/scripting/sightly/compiler/java/JavaClassBackendCompilerTest.java
+++ b/src/test/java/org/apache/sling/scripting/sightly/compiler/java/JavaClassBackendCompilerTest.java
@@ -108,7 +108,27 @@
         CharSequenceJavaCompiler<RenderUnit> compiler = new CharSequenceJavaCompiler<>(classLoader, null);
         compiler.compile(classInfo.getFullyQualifiedClassName(), source);
     }
-    
+
+    @Test
+    public void sling_8217() throws Exception {
+        CompilationUnit compilationUnit = TestUtils.readScriptFromClasspath("/SLING-8217.html");
+        JavaClassBackendCompiler backendCompiler = new JavaClassBackendCompiler();
+        SightlyCompiler sightlyCompiler = new SightlyCompiler();
+        sightlyCompiler.compile(compilationUnit, backendCompiler);
+        ClassInfo classInfo = buildClassInfo("sling_8217");
+        String source = backendCompiler.build(classInfo);
+        StringWriter writer = new StringWriter();
+        Bindings bindings = new SimpleBindings();
+        HashMap<String, Integer> properties = new HashMap<String, Integer>(){{
+            put("begin", 1);
+        }};
+        bindings.put("properties", properties);
+        RenderContext renderContext = buildRenderContext(bindings);
+        render(writer, classInfo, source, renderContext, new SimpleBindings());
+        String expectedOutput = IOUtils.toString(this.getClass().getResourceAsStream("/SLING-8217.output.html"), "UTF-8");
+        assertEquals(expectedOutput, writer.toString());
+    }
+
     private static final String normalizeLineEndings(String input) {
         return StringUtils.replaceAll(input, "\r\n", "\n");
     }
diff --git a/src/test/java/org/apache/sling/scripting/sightly/compiler/java/utils/CharSequenceJavaCompiler.java b/src/test/java/org/apache/sling/scripting/sightly/compiler/java/utils/CharSequenceJavaCompiler.java
index 2ddc681..b4c752d 100644
--- a/src/test/java/org/apache/sling/scripting/sightly/compiler/java/utils/CharSequenceJavaCompiler.java
+++ b/src/test/java/org/apache/sling/scripting/sightly/compiler/java/utils/CharSequenceJavaCompiler.java
@@ -31,6 +31,8 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
+
+import javax.tools.Diagnostic;
 import javax.tools.DiagnosticCollector;
 import javax.tools.FileObject;
 import javax.tools.ForwardingJavaFileManager;
@@ -124,13 +126,20 @@
      */
     public synchronized Class<T> compile(final String qualifiedClassName,
                                          final CharSequence javaSource,
-                                         final Class<?>... types) throws CharSequenceJavaCompilerException,
-            ClassCastException {
+                                         final Class<?>... types) throws ClassCastException {
         Map<String, CharSequence> classes = new HashMap<>(1);
         classes.put(qualifiedClassName, javaSource);
-        Map<String, Class<T>> compiled = compile(classes);
-        Class<T> newClass = compiled.get(qualifiedClassName);
-        return castable(newClass, types);
+        try {
+            Map<String, Class<T>> compiled = compile(classes);
+            Class<T> newClass = compiled.get(qualifiedClassName);
+            return castable(newClass, types);
+        } catch (CharSequenceJavaCompilerException e) {
+            StringBuilder stringBuilder = new StringBuilder();
+            for (Diagnostic diagnostic : e.getDiagnostics().getDiagnostics()) {
+                stringBuilder.append(diagnostic.toString()).append(System.lineSeparator());
+            }
+            throw new RuntimeException(stringBuilder.toString());
+        }
     }
 
     /**
diff --git a/src/test/resources/SLING-8217.html b/src/test/resources/SLING-8217.html
new file mode 100644
index 0000000..8762f89
--- /dev/null
+++ b/src/test/resources/SLING-8217.html
@@ -0,0 +1,21 @@
+<!--/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  ~ 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.
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/-->
+<ul data-sly-list="${[1, 2, 3, 4, 5] @ begin = properties.begin}">
+    <li class="${itemList.index}">${item}</li>
+</ul>
diff --git a/src/test/resources/SLING-8217.output.html b/src/test/resources/SLING-8217.output.html
new file mode 100644
index 0000000..311378e
--- /dev/null
+++ b/src/test/resources/SLING-8217.output.html
@@ -0,0 +1,10 @@
+
+<ul>
+    <li class="1">2</li>
+
+    <li class="2">3</li>
+
+    <li class="3">4</li>
+
+    <li class="4">5</li>
+</ul>