You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by bd...@apache.org on 2014/11/14 15:05:03 UTC

svn commit: r1639641 [6/15] - in /sling/trunk/contrib/scripting/sightly: ./ engine/ engine/src/ engine/src/main/ engine/src/main/antlr4/ engine/src/main/antlr4/org/ engine/src/main/antlr4/org/apache/ engine/src/main/antlr4/org/apache/sling/ engine/src/...

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/api/ris/command/Patterns.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/api/ris/command/Patterns.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/api/ris/command/Patterns.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/api/ris/command/Patterns.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * 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.compiler.api.ris.command;
+
+import org.apache.sling.scripting.sightly.compiler.util.stream.PushStream;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.BooleanConstant;
+
+/**
+ * Usual command patterns
+ */
+public class Patterns {
+
+    private static final String ALWAYS_FALSE_VAR = "always_false";
+
+    /**
+     * Inserts a sequence of commands that will ignore the rest of the stream until
+     * the end stream sequence is inserted
+     * @param stream - the stream
+     */
+    public static void beginStreamIgnore(PushStream stream) {
+        stream.emit(new VariableBinding.Start(ALWAYS_FALSE_VAR, BooleanConstant.FALSE));
+        stream.emit(new Conditional.Start(ALWAYS_FALSE_VAR, true));
+    }
+
+    /**
+     * Inserts a sequence of commands that cancels stream ignore
+     * @param stream - the input stream
+     */
+    public static void endStreamIgnore(PushStream stream) {
+        stream.emit(Conditional.END);
+        stream.emit(VariableBinding.END);
+    }
+
+
+}

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/api/ris/command/Procedure.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/api/ris/command/Procedure.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/api/ris/command/Procedure.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/api/ris/command/Procedure.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * 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.compiler.api.ris.command;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.sling.scripting.sightly.compiler.api.ris.Command;
+import org.apache.sling.scripting.sightly.compiler.api.ris.CommandVisitor;
+import org.apache.sling.scripting.sightly.compiler.api.ris.Command;
+import org.apache.sling.scripting.sightly.compiler.api.ris.CommandVisitor;
+
+/**
+ * Commands that delimitate a procedure
+ */
+public class Procedure {
+
+    public static class Start implements Command {
+
+        private String name;
+        private Set<String> parameters;
+
+        public Start(String name, Set<String> parameters) {
+            this.name = name;
+            this.parameters = new HashSet<String>(parameters);
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public Set<String> getParameters() {
+            return Collections.unmodifiableSet(parameters);
+        }
+
+        @Override
+        public void accept(CommandVisitor visitor) {
+            visitor.visit(this);
+        }
+    }
+
+    public static final End END = new End();
+
+    public static final class End implements Command {
+
+        private End() {
+        }
+
+        @Override
+        public void accept(CommandVisitor visitor) {
+            visitor.visit(this);
+        }
+    }
+
+    public static class Call implements Command {
+
+        private final String templateVariable;
+        private final String argumentsVariable;
+
+        public Call(String templateVariable, String argumentsVariable) {
+            this.templateVariable = templateVariable;
+            this.argumentsVariable = argumentsVariable;
+        }
+
+        public String getTemplateVariable() {
+            return templateVariable;
+        }
+
+        public String getArgumentsVariable() {
+            return argumentsVariable;
+        }
+
+        @Override
+        public void accept(CommandVisitor visitor) {
+            visitor.visit(this);
+        }
+    }
+
+}

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/api/ris/command/VariableBinding.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/api/ris/command/VariableBinding.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/api/ris/command/VariableBinding.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/api/ris/command/VariableBinding.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * 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.compiler.api.ris.command;
+
+import org.apache.sling.scripting.sightly.compiler.api.ris.Command;
+import org.apache.sling.scripting.sightly.compiler.api.ris.CommandVisitor;
+import org.apache.sling.scripting.sightly.compiler.api.expression.ExpressionNode;
+import org.apache.sling.scripting.sightly.compiler.api.ris.Command;
+import org.apache.sling.scripting.sightly.compiler.api.ris.CommandVisitor;
+
+/**
+ * Marks the binding of a variable. Must have a corresponding binding end later in the stream
+ */
+public class VariableBinding {
+
+    public static class Start implements Command {
+        private String variableName;
+        private ExpressionNode expression;
+
+        public Start(String variableName, ExpressionNode expression) {
+            this.variableName = variableName;
+            this.expression = expression;
+        }
+
+        public String getVariableName() {
+            return variableName;
+        }
+
+        public ExpressionNode getExpression() {
+            return expression;
+        }
+
+        @Override
+        public void accept(CommandVisitor visitor) {
+            visitor.visit(this);
+        }
+
+        @Override
+        public String toString() {
+            return "VariableBinding.Start{" +
+                    "variableName='" + variableName + '\'' +
+                    ", expression=" + expression +
+                    '}';
+        }
+    }
+
+    public static final End END = new End();
+
+    public static final class End implements Command {
+
+        private End() {
+        }
+
+        @Override
+        public void accept(CommandVisitor visitor) {
+            visitor.visit(this);
+        }
+
+        @Override
+        public String toString() {
+            return "VariableBinding.End{}";
+        }
+    }
+
+    public static final class Global implements Command {
+
+        private final String variableName;
+        private final ExpressionNode expressionNode;
+
+        public Global(String variableName, ExpressionNode expressionNode) {
+            this.variableName = variableName;
+            this.expressionNode = expressionNode;
+        }
+
+        public String getVariableName() {
+            return variableName;
+        }
+
+        public ExpressionNode getExpression() {
+            return expressionNode;
+        }
+
+
+        @Override
+        public void accept(CommandVisitor visitor) {
+            visitor.visit(this);
+        }
+    }
+}

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/common/DefaultPluginInvoke.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/common/DefaultPluginInvoke.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/common/DefaultPluginInvoke.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/common/DefaultPluginInvoke.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * 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.compiler.common;
+
+import org.apache.sling.scripting.sightly.compiler.api.expression.Expression;
+import org.apache.sling.scripting.sightly.compiler.api.expression.ExpressionNode;
+import org.apache.sling.scripting.sightly.compiler.api.plugin.PluginCallInfo;
+import org.apache.sling.scripting.sightly.compiler.api.plugin.PluginInvoke;
+import org.apache.sling.scripting.sightly.compiler.util.stream.PushStream;
+import org.apache.sling.scripting.sightly.compiler.api.expression.Expression;
+import org.apache.sling.scripting.sightly.compiler.api.plugin.PluginCallInfo;
+import org.apache.sling.scripting.sightly.compiler.util.stream.PushStream;
+
+/**
+ * Empty implementation for plugin invocation. Use this to implement
+ * methods selectively.
+ * @see org.apache.sling.scripting.sightly.compiler.api.plugin.Plugin
+ */
+public class DefaultPluginInvoke implements PluginInvoke {
+
+    @Override
+    public void beforeElement(PushStream stream, String tagName) {
+        
+    }
+
+    @Override
+    public void beforeTagOpen(PushStream stream) {
+
+    }
+
+    @Override
+    public void beforeAttributes(PushStream stream) {
+
+    }
+
+    @Override
+    public void beforeAttribute(PushStream stream, String attributeName) {
+
+    }
+
+    @Override
+    public void beforeAttributeValue(PushStream stream, String attributeName, ExpressionNode attributeValue) {
+
+    }
+
+    @Override
+    public void afterAttributeValue(PushStream stream, String attributeName) {
+
+    }
+
+    @Override
+    public void afterAttribute(PushStream stream, String attributeName) {
+
+    }
+
+    @Override
+    public void onPluginCall(PushStream stream, PluginCallInfo callInfo, Expression expression) {
+
+    }
+
+    @Override
+    public void afterAttributes(PushStream stream) {
+
+    }
+
+    @Override
+    public void afterTagOpen(PushStream stream) {
+
+    }
+
+    @Override
+    public void beforeChildren(PushStream stream) {
+
+    }
+
+    @Override
+    public void afterChildren(PushStream stream) {
+
+    }
+
+    @Override
+    public void beforeTagClose(PushStream stream, boolean isSelfClosing) {
+
+    }
+
+    @Override
+    public void afterTagClose(PushStream stream, boolean isSelfClosing) {
+
+    }
+
+    @Override
+    public void afterElement(PushStream stream) {
+
+    }
+}

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/debug/LoggingHandler.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/debug/LoggingHandler.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/debug/LoggingHandler.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/debug/LoggingHandler.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * 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.compiler.debug;
+
+import org.apache.sling.scripting.sightly.compiler.api.ris.Command;
+import org.apache.sling.scripting.sightly.compiler.api.ris.CommandHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.sling.scripting.sightly.compiler.api.ris.Command;
+import org.apache.sling.scripting.sightly.compiler.api.ris.CommandHandler;
+
+/**
+ * Handler which logs all commands
+ */
+public final class LoggingHandler implements CommandHandler {
+
+    public static final LoggingHandler INSTANCE = new LoggingHandler();
+
+    private final Logger LOG = LoggerFactory.getLogger(LoggingHandler.class);
+
+    private LoggingHandler() {
+    }
+
+    @Override
+    public void onEmit(Command command) {
+        LOG.info("Emitting {}", command);
+    }
+
+    @Override
+    public void onError(String errorMessage) {
+        LOG.info("Error: {}", errorMessage);
+    }
+
+    @Override
+    public void onDone() {
+        LOG.info("Finished");
+    }
+}

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/debug/SanityChecker.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/debug/SanityChecker.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/debug/SanityChecker.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/debug/SanityChecker.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,167 @@
+/*******************************************************************************
+ * 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.compiler.debug;
+
+import java.util.Stack;
+
+import org.apache.sling.scripting.sightly.compiler.api.ris.Command;
+import org.apache.sling.scripting.sightly.compiler.api.ris.CommandVisitor;
+import org.apache.sling.scripting.sightly.compiler.api.ris.command.BufferControl;
+import org.apache.sling.scripting.sightly.compiler.api.ris.command.Conditional;
+import org.apache.sling.scripting.sightly.compiler.api.ris.command.Loop;
+import org.apache.sling.scripting.sightly.compiler.api.ris.command.OutText;
+import org.apache.sling.scripting.sightly.compiler.api.ris.command.OutVariable;
+import org.apache.sling.scripting.sightly.compiler.api.ris.command.Procedure;
+import org.apache.sling.scripting.sightly.compiler.api.ris.command.VariableBinding;
+import org.apache.sling.scripting.sightly.compiler.api.ris.CommandHandler;
+import org.apache.sling.scripting.sightly.compiler.api.ris.CommandStream;
+import org.apache.sling.scripting.sightly.compiler.api.ris.Command;
+import org.apache.sling.scripting.sightly.compiler.api.ris.CommandHandler;
+import org.apache.sling.scripting.sightly.compiler.api.ris.CommandStream;
+import org.apache.sling.scripting.sightly.compiler.api.ris.CommandVisitor;
+import org.apache.sling.scripting.sightly.compiler.api.ris.command.*;
+
+/**
+ * A visitor which checks a stream for correct closing of things
+ */
+public final class SanityChecker implements CommandVisitor, CommandHandler {
+
+    private enum NestedType {
+        CONDITIONAL, VARIABLE_BIND, LOOP
+    }
+
+    private final Stack<NestedType> stack = new Stack<NestedType>();
+    private int bufferPushCount;
+    private boolean inProcedure;
+
+    private SanityChecker() {
+    }
+
+    public static void attachChecker(CommandStream commandStream) {
+        commandStream.addHandler(new SanityChecker());
+    }
+
+    @Override
+    public void onEmit(Command command) {
+        command.accept(this);
+    }
+
+    @Override
+    public void onError(String errorMessage) {
+        throw new RuntimeException(errorMessage);
+    }
+
+    @Override
+    public void onDone() {
+        if (!stack.isEmpty()) {
+            throw new IllegalStateException("Unclosed commands left");
+        }
+        if (bufferPushCount > 0) {
+            throw new IllegalStateException("There are pushed buffer writers at stream end");
+        }
+    }
+
+
+    @Override
+    public void visit(Conditional.Start conditionalStart) {
+        stack.push(NestedType.CONDITIONAL);
+    }
+
+    @Override
+    public void visit(Conditional.End conditionalEnd) {
+        popCheck(NestedType.CONDITIONAL);
+    }
+
+    @Override
+    public void visit(VariableBinding.Start variableBindingStart) {
+        stack.push(NestedType.VARIABLE_BIND);
+    }
+
+    @Override
+    public void visit(VariableBinding.End variableBindingEnd) {
+        popCheck(NestedType.VARIABLE_BIND);
+    }
+
+    @Override
+    public void visit(VariableBinding.Global globalAssignment) {
+    }
+
+    @Override
+    public void visit(OutVariable outVariable) {
+    }
+
+    @Override
+    public void visit(OutText outText) {
+    }
+
+    @Override
+    public void visit(Loop.Start loopStart) {
+        stack.push(NestedType.LOOP);
+    }
+
+    @Override
+    public void visit(Loop.End loopEnd) {
+        popCheck(NestedType.LOOP);
+    }
+
+    @Override
+    public void visit(BufferControl.Push bufferPush) {
+        bufferPushCount++;
+    }
+
+    @Override
+    public void visit(BufferControl.Pop bufferPop) {
+        if (bufferPushCount == 0) {
+            throw new IllegalStateException("There are more buffer pop commands than push");
+        }
+        bufferPushCount--;
+        stack.push(NestedType.VARIABLE_BIND);
+    }
+
+    @Override
+    public void visit(Procedure.Start startProcedure) {
+        if (inProcedure) {
+            throw new IllegalStateException("Cannot have nested procedures: " + startProcedure.getName());
+        }
+        inProcedure = true;
+    }
+
+    @Override
+    public void visit(Procedure.End endProcedure) {
+        if (!inProcedure) {
+            throw new IllegalStateException("Procedure closing is unmatched");
+        }
+        inProcedure = false;
+    }
+
+    @Override
+    public void visit(Procedure.Call procedureCall) {
+    }
+
+    private void popCheck(NestedType nestedType) {
+        if (stack.isEmpty()) {
+            throw new IllegalStateException("Unbalanced command: " + nestedType);
+        }
+        NestedType top = stack.pop();
+        if (top != nestedType) {
+            throw new IllegalStateException("Command closing is unmatched. Expected " + top + ", actual: " + nestedType);
+        }
+    }
+
+}

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/AggregatePluginInvoke.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/AggregatePluginInvoke.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/AggregatePluginInvoke.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/AggregatePluginInvoke.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * 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.compiler.frontend;
+
+import org.apache.sling.scripting.sightly.compiler.api.expression.Expression;
+import org.apache.sling.scripting.sightly.compiler.api.expression.ExpressionNode;
+import org.apache.sling.scripting.sightly.compiler.api.plugin.PluginCallInfo;
+import org.apache.sling.scripting.sightly.compiler.api.plugin.PluginInvoke;
+import org.apache.sling.scripting.sightly.compiler.util.stream.PushStream;
+import org.apache.sling.scripting.sightly.compiler.api.expression.Expression;
+import org.apache.sling.scripting.sightly.compiler.api.plugin.PluginCallInfo;
+
+import java.util.List;
+
+/**
+ * Plugin invoke which aggregates the behavior of several plugin invokes
+ */
+public class AggregatePluginInvoke implements PluginInvoke {
+
+    private final List<PluginInvoke> invokes;
+
+    public AggregatePluginInvoke(List<PluginInvoke> invokes) {
+        this.invokes = invokes;
+    }
+
+    @Override
+    public void beforeElement(PushStream stream, String tagName) {
+        for (PluginInvoke invoke : invokes) {
+            invoke.beforeElement(stream, tagName);
+        }
+    }
+
+    @Override
+    public void beforeTagOpen(PushStream stream) {
+        for (PluginInvoke invoke : invokes) {
+            invoke.beforeTagOpen(stream);
+        }
+    }
+
+    @Override
+    public void beforeAttributes(PushStream stream) {
+        for (PluginInvoke invoke : invokes) {
+            invoke.beforeAttributes(stream);
+        }
+    }
+
+    @Override
+    public void beforeAttribute(PushStream stream, String attributeName) {
+        for (PluginInvoke invoke : invokes) {
+            invoke.beforeAttribute(stream, attributeName);
+        }
+    }
+
+    @Override
+    public void beforeAttributeValue(PushStream stream, String attributeName, ExpressionNode attributeValue) {
+        for (PluginInvoke invoke : invokes) {
+            invoke.beforeAttributeValue(stream, attributeName, attributeValue);
+        }
+    }
+
+    @Override
+    public void afterAttributeValue(PushStream stream, String attributeName) {
+        for (int i = invokes.size() - 1; i >= 0; i--) {
+            PluginInvoke invoke = invokes.get(i);
+            invoke.afterAttributeValue(stream, attributeName);
+        }
+    }
+
+    @Override
+    public void afterAttribute(PushStream stream, String attributeName) {
+        for (int i = invokes.size() - 1; i >= 0; i--) {
+            PluginInvoke invoke = invokes.get(i);
+            invoke.afterAttribute(stream, attributeName);
+        }
+    }
+
+    @Override
+    public void onPluginCall(PushStream stream, PluginCallInfo callInfo, Expression expression) {
+        for (PluginInvoke invoke : invokes) {
+            invoke.onPluginCall(stream, callInfo, expression);
+        }
+    }
+
+    @Override
+    public void afterAttributes(PushStream stream) {
+        for (int i = invokes.size() - 1; i >= 0; i--) {
+            PluginInvoke invoke = invokes.get(i);
+            invoke.afterAttributes(stream);
+        }
+    }
+
+    @Override
+    public void afterTagOpen(PushStream stream) {
+        for (int i = invokes.size() - 1; i >= 0; i--) {
+            PluginInvoke invoke = invokes.get(i);
+            invoke.afterTagOpen(stream);
+        }
+    }
+
+    @Override
+    public void beforeChildren(PushStream stream) {
+        for (PluginInvoke invoke : invokes) {
+            invoke.beforeChildren(stream);
+        }
+    }
+
+    @Override
+    public void afterChildren(PushStream stream) {
+        for (int i = invokes.size() - 1; i >= 0; i--) {
+            PluginInvoke invoke = invokes.get(i);
+            invoke.afterChildren(stream);
+        }
+    }
+
+    @Override
+    public void beforeTagClose(PushStream stream, boolean isSelfClosing) {
+        for (PluginInvoke invoke : invokes) {
+            invoke.beforeTagClose(stream, isSelfClosing);
+        }
+    }
+
+    @Override
+    public void afterTagClose(PushStream stream, boolean isSelfClosing) {
+        for (int i = invokes.size() - 1; i >= 0; i--) {
+            PluginInvoke invoke = invokes.get(i);
+            invoke.afterTagClose(stream, isSelfClosing);
+        }
+    }
+
+    @Override
+    public void afterElement(PushStream stream) {
+        for (int i = invokes.size() - 1; i >= 0; i--) {
+            PluginInvoke invoke = invokes.get(i);
+            invoke.afterElement(stream);
+        }
+    }
+}

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/DefaultCompilerContext.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/DefaultCompilerContext.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/DefaultCompilerContext.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/DefaultCompilerContext.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * 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.compiler.frontend;
+
+import org.apache.sling.scripting.sightly.compiler.Syntax;
+import org.apache.sling.scripting.sightly.compiler.api.expression.Expression;
+import org.apache.sling.scripting.sightly.compiler.api.plugin.CompilerContext;
+import org.apache.sling.scripting.sightly.compiler.api.plugin.MarkupContext;
+import org.apache.sling.scripting.sightly.compiler.util.SymbolGenerator;
+import org.apache.sling.scripting.sightly.compiler.Syntax;
+import org.apache.sling.scripting.sightly.compiler.api.expression.Expression;
+import org.apache.sling.scripting.sightly.compiler.api.plugin.CompilerContext;
+import org.apache.sling.scripting.sightly.compiler.util.SymbolGenerator;
+
+
+/**
+ * Default implementation for the compiler context
+ * @see org.apache.sling.scripting.sightly.compiler.api.plugin.Plugin
+ */
+public class DefaultCompilerContext implements CompilerContext {
+
+    private SymbolGenerator symbolGenerator;
+    private ExpressionWrapper expressionWrapper;
+
+    DefaultCompilerContext(SymbolGenerator symbolGenerator, ExpressionWrapper wrapper) {
+        this.symbolGenerator = symbolGenerator;
+        this.expressionWrapper = wrapper;
+    }
+
+    @Override
+    public String generateVariable(String hint) {
+        return symbolGenerator.next(hint);
+    }
+
+    @Override
+    public Expression adjustToContext(Expression expression, MarkupContext context) {
+        if (!expression.getOptions().containsKey(Syntax.CONTEXT_OPTION)) {
+            return expressionWrapper.adjustToContext(expression, context);
+        }
+        return expression;
+    }
+}

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/ElementContext.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/ElementContext.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/ElementContext.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/ElementContext.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * 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.compiler.frontend;
+
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.sling.scripting.sightly.compiler.api.expression.Expression;
+import org.apache.sling.scripting.sightly.compiler.api.plugin.PluginCallInfo;
+import org.apache.sling.scripting.sightly.compiler.api.plugin.PluginInvoke;
+
+/**
+ * Data structure used by {@link MarkupHandlerImpl}
+ */
+class ElementContext {
+    private final String tagName;
+    private final String openTagStartMarkup;
+
+    private final List<PrioritizedInvoke> invokeList = new ArrayList<PrioritizedInvoke>();
+    private final List<Map.Entry<String, Object>> attributes = new ArrayList<Map.Entry<String, Object>>();
+    private PluginInvoke aggregateInvoke;
+
+    public ElementContext(String tagName, String openTagStartMarkup) {
+        this.tagName = tagName;
+        this.openTagStartMarkup = openTagStartMarkup;
+    }
+
+    public String getTagName() {
+        return tagName;
+    }
+
+    public String getOpenTagStartMarkup() {
+        return openTagStartMarkup;
+    }
+
+    public void addPlugin(PluginInvoke invoke, int priority) {
+        invokeList.add(new PrioritizedInvoke(invoke, priority));
+    }
+
+    public void addAttribute(String name, String value) {
+        attributes.add(new AbstractMap.SimpleEntry<String, Object>(name, value));
+    }
+
+    public void addPluginCall(String name, PluginCallInfo info, Expression expression) {
+        attributes.add(new AbstractMap.SimpleEntry<String, Object>(name,
+                new AbstractMap.SimpleEntry<PluginCallInfo, Expression>(info, expression)));
+    }
+
+    public Iterable<Map.Entry<String, Object>> getAttributes() {
+        return attributes;
+    }
+
+    public PluginInvoke pluginInvoke() {
+        if (aggregateInvoke == null) {
+            Collections.sort(invokeList);
+            ArrayList<PluginInvoke> result = new ArrayList<PluginInvoke>();
+            for (PrioritizedInvoke prioritizedInvoke : invokeList) {
+                result.add(prioritizedInvoke.invoke);
+            }
+            aggregateInvoke = new AggregatePluginInvoke(result);
+        }
+        return aggregateInvoke;
+    }
+
+
+    private static final class PrioritizedInvoke implements Comparable<PrioritizedInvoke> {
+
+        private final PluginInvoke invoke;
+        private final int priority;
+
+        private PrioritizedInvoke(PluginInvoke invoke, int priority) {
+            this.invoke = invoke;
+            this.priority = priority;
+        }
+
+        @Override
+        public int compareTo(PrioritizedInvoke o) {
+            if (this.priority < o.priority) {
+                return -1;
+            } else if (this.priority == o.priority) {
+                return  0;
+            }
+            return 1;
+        }
+    }
+}

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/ExpressionParser.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/ExpressionParser.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/ExpressionParser.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/ExpressionParser.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * 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.compiler.frontend;
+
+
+/**
+ * Sightly expression parser service interface
+ *
+ * */
+public interface ExpressionParser {
+
+    /**
+     * Parses the expression string.
+     *
+     * @param exprString as defined by the Sightly spec (http://apache.org)
+     *
+     * @return Parsed Expression object
+     *
+     * @throws NullPointerException is the given exprString is null
+     * @throws ParserException if an error occurs while parsing the expression
+     * */
+    public Interpolation parseInterpolation(String exprString);
+
+}

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/ExpressionParserImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/ExpressionParserImpl.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/ExpressionParserImpl.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/ExpressionParserImpl.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * 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.compiler.frontend;
+
+import org.apache.sling.parser.expr.generated.SightlyLexer;
+import org.apache.sling.parser.expr.generated.SightlyParser;
+import org.antlr.v4.runtime.ANTLRInputStream;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.RecognitionException;
+
+public class ExpressionParserImpl implements ExpressionParser {
+
+    public Interpolation parseInterpolation(String text) throws ParserException {
+        SightlyParser parser = createParser(text);
+        try {
+            return parser.interpolation().interp;
+        } catch (RecognitionException e) {
+            throw new ParserException(e);
+        }
+    }
+
+    private SightlyParser createParser(String str) {
+        SightlyLexer lexer = new SightlyLexer(new ANTLRInputStream(str));
+        CommonTokenStream tokenStream = new CommonTokenStream(lexer);
+        SightlyParser parser = new SightlyParser(tokenStream);
+        parser.removeErrorListeners();
+        parser.addErrorListener(new SightlyParserErrorListener());
+        return parser;
+    }
+
+}

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/ExpressionWrapper.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/ExpressionWrapper.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/ExpressionWrapper.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/ExpressionWrapper.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * 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.compiler.frontend;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.sling.scripting.sightly.compiler.Syntax;
+import org.apache.sling.scripting.sightly.compiler.api.Filter;
+import org.apache.sling.scripting.sightly.compiler.api.expression.Expression;
+import org.apache.sling.scripting.sightly.compiler.api.expression.ExpressionNode;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.BinaryOperation;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.BinaryOperator;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.StringConstant;
+import org.apache.sling.scripting.sightly.compiler.api.plugin.MarkupContext;
+import org.apache.sling.scripting.sightly.compiler.api.Filter;
+import org.apache.sling.scripting.sightly.compiler.api.expression.Expression;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.BinaryOperation;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.StringConstant;
+
+/**
+ * This object wraps expressions in filter applications depending
+ * on options
+ */
+class ExpressionWrapper {
+
+    private final List<Filter> filters;
+
+    ExpressionWrapper(Collection<Filter> filters) {
+        this.filters = new ArrayList<Filter>();
+        this.filters.addAll(filters);
+        Collections.sort(this.filters);
+    }
+
+    public Expression transform(Interpolation interpolation, MarkupContext markupContext) {
+        ArrayList<ExpressionNode> nodes = new ArrayList<ExpressionNode>();
+        HashMap<String, ExpressionNode> options = new HashMap<String, ExpressionNode>();
+        for (Fragment fragment : interpolation.getFragments()) {
+            if (fragment.isString()) {
+                nodes.add(new StringConstant(fragment.getText()));
+            } else {
+                Expression expression = fragment.getExpression();
+                options.putAll(expression.getOptions());
+                nodes.add(transformExpr(expression, markupContext).getRoot());
+            }
+        }
+        ExpressionNode root = join(nodes);
+        if (interpolation.size() > 1 && options.containsKey(Syntax.CONTEXT_OPTION)) {
+            //context must not be calculated by merging
+            options.remove(Syntax.CONTEXT_OPTION);
+        }
+        return new Expression(root, options);
+    }
+
+    private Expression applyFilters(Expression expression) {
+        Expression result = expression;
+        for (Filter filter : filters) {
+            result = filter.apply(result);
+        }
+        return result;
+    }
+
+    public Expression adjustToContext(Expression expression, MarkupContext markupContext) {
+        if (expression.containsOption(Syntax.CONTEXT_OPTION)) {
+            return expression;
+        }
+        Map<String, ExpressionNode> opt = addDefaultContext(Collections.<String, ExpressionNode>emptyMap(), markupContext);
+        Expression result = applyFilters(new Expression(expression.getRoot(), opt));
+        return expression.withNode(result.getRoot());
+    }
+
+    private ExpressionNode join(List<ExpressionNode> nodes) {
+        if (nodes.isEmpty()) {
+            return StringConstant.EMPTY;
+        }
+        ExpressionNode root = nodes.get(0);
+        for (int i = 1; i < nodes.size(); i++) {
+            ExpressionNode node = nodes.get(i);
+            root = new BinaryOperation(BinaryOperator.CONCATENATE, root, node);
+        }
+        return root;
+    }
+
+    private Expression transformExpr(Expression expression, MarkupContext markupContext) {
+        expression = addDefaultContext(expression, markupContext);
+        return applyFilters(expression);
+    }
+
+    private Expression addDefaultContext(Expression expression, MarkupContext context) {
+        return new Expression(expression.getRoot(), addDefaultContext(expression.getOptions(), context));
+    }
+
+    private Map<String, ExpressionNode> addDefaultContext(Map<String, ExpressionNode> options, MarkupContext context) {
+        if (context == null || options.containsKey(Syntax.CONTEXT_OPTION)) {
+            return options;
+        }
+        HashMap<String, ExpressionNode> newOptions = new HashMap<String, ExpressionNode>(options);
+        newOptions.put(Syntax.CONTEXT_OPTION, new StringConstant(context.getName()));
+        return newOptions;
+    }
+
+}

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/Fragment.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/Fragment.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/Fragment.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/Fragment.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * 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.compiler.frontend;
+
+import org.apache.sling.scripting.sightly.compiler.api.expression.Expression;
+
+/**
+ * A segment in an interpolation.
+ */
+public interface Fragment {
+
+    boolean isString();
+    boolean isExpression();
+
+    Expression getExpression();
+    String getText();
+
+    /**
+     * A fragment which is an expression.
+     */
+    public static class Expr implements Fragment {
+
+        private Expression expression;
+
+        public Expr(Expression expression) {
+            this.expression = expression;
+        }
+
+        @Override
+        public Expression getExpression() {
+            return expression;
+        }
+
+        @Override
+        public String getText() {
+            throw new UnsupportedOperationException("Not a text fragment");
+        }
+
+        public boolean isString() {
+            return false;
+        }
+
+        public boolean isExpression() {
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            return "Expr{" +
+                    "expression=" + expression +
+                    '}';
+        }
+    }
+
+    /**
+     * A text fragment.
+     */
+    public static class Text implements Fragment {
+        private String text;
+
+        public Text(String text) {
+            this.text = text;
+        }
+
+        @Override
+        public String getText() {
+            return text;
+        }
+
+        public boolean isString() {
+            return true;
+        }
+
+        public boolean isExpression() {
+            return false;
+        }
+
+        @Override
+        public Expression getExpression() {
+            throw new UnsupportedOperationException("Not an expression fragment");
+        }
+
+        @Override
+        public String toString() {
+            return "Text{" +
+                    "text='" + text + '\'' +
+                    '}';
+        }
+    }
+}

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/Interpolation.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/Interpolation.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/Interpolation.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/Interpolation.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * 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.compiler.frontend;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.sling.scripting.sightly.compiler.api.expression.Expression;
+import org.apache.sling.scripting.sightly.compiler.api.expression.Expression;
+
+/**
+ * A sequence with alternating string fragments and Sightly expressions.
+ * These result from parsing HTML attributes or string nodes.
+ * For instance "Hello ${World}!" would result in 3 fragments:
+ * "Hello ", ${World} and "!"
+ */
+public class Interpolation {
+
+    //todo: this should be immutable to maintain the design consistent
+
+    private List<Fragment> fragments = new ArrayList<Fragment>();
+
+    public void addFragment(Fragment fragment) {
+        fragments.add(fragment);
+    }
+
+    public void addExpression(Expression expression) {
+        fragments.add(new Fragment.Expr(expression));
+    }
+
+    public void addText(String text) {
+        fragments.add(new Fragment.Text(text));
+    }
+
+    /**
+     * Get the number of fragments
+     * @return the number of fragments
+     */
+    public int size() {
+        return fragments.size();
+    }
+
+    /**
+     * Return the fragment with the specified index
+     * @param index - the index of the fragments. must be less than the size of the interpolation
+     * @return - the specified fragment
+     * @throws IndexOutOfBoundsException - if the index is negative or greater or equal than size
+     */
+    public Fragment getFragment(int index) {
+        return fragments.get(index);
+    }
+
+    public Iterable<Fragment> getFragments() {
+        return fragments;
+    }
+
+    @Override
+    public String toString() {
+        return "Interpolation{" +
+                "fragments=" + fragments +
+                '}';
+    }
+}

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/MarkupHandlerImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/MarkupHandlerImpl.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/MarkupHandlerImpl.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/MarkupHandlerImpl.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,405 @@
+/*******************************************************************************
+ * 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.compiler.frontend;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Stack;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.sling.scripting.sightly.compiler.Syntax;
+import org.apache.sling.scripting.sightly.compiler.api.Filter;
+import org.apache.sling.scripting.sightly.compiler.api.MarkupHandler;
+import org.apache.sling.scripting.sightly.compiler.api.expression.Expression;
+import org.apache.sling.scripting.sightly.compiler.api.expression.ExpressionNode;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.BinaryOperation;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.BinaryOperator;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.BooleanConstant;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.Identifier;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.StringConstant;
+import org.apache.sling.scripting.sightly.compiler.api.plugin.CompilerContext;
+import org.apache.sling.scripting.sightly.compiler.api.plugin.MarkupContext;
+import org.apache.sling.scripting.sightly.compiler.api.plugin.Plugin;
+import org.apache.sling.scripting.sightly.compiler.api.plugin.PluginCallInfo;
+import org.apache.sling.scripting.sightly.compiler.api.plugin.PluginInvoke;
+import org.apache.sling.scripting.sightly.compiler.api.ris.command.Conditional;
+import org.apache.sling.scripting.sightly.compiler.api.ris.command.OutText;
+import org.apache.sling.scripting.sightly.compiler.api.ris.command.OutVariable;
+import org.apache.sling.scripting.sightly.compiler.api.ris.command.VariableBinding;
+import org.apache.sling.scripting.sightly.compiler.util.SymbolGenerator;
+import org.apache.sling.scripting.sightly.compiler.util.stream.PushStream;
+import org.apache.sling.scripting.sightly.html.MarkupUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implementation for the markup handler
+ */
+public class MarkupHandlerImpl implements MarkupHandler {
+
+    private static final Logger log = LoggerFactory.getLogger(MarkupHandlerImpl.class);
+
+    private final PushStream stream;
+    private final SymbolGenerator symbolGenerator = new SymbolGenerator();
+    private final ExpressionParser expressionParser = new ExpressionParserImpl();
+    private final Map<String, Plugin> pluginRegistry;
+    private final CompilerContext compilerContext;
+    private final ExpressionWrapper expressionWrapper;
+
+    private final Stack<ElementContext> elementStack = new Stack<ElementContext>();
+
+    public MarkupHandlerImpl(PushStream stream, Map<String, Plugin> pluginRegistry, Collection<Filter> filters) {
+        this.stream = stream;
+        this.pluginRegistry = pluginRegistry;
+        this.expressionWrapper = new ExpressionWrapper(filters);
+        this.compilerContext = new DefaultCompilerContext(symbolGenerator, expressionWrapper);
+    }
+
+    @Override
+    public void onOpenTagStart(String markup, String tagName) {
+        ElementContext context = new ElementContext(tagName, markup);
+        elementStack.push(context);
+    }
+
+    @Override
+    public void onAttribute(String name, String value) {
+        ElementContext context = elementStack.peek();
+        if (Syntax.isPluginAttribute(name)) {
+            handlePlugin(name, StringUtils.defaultString(value, ""), context);
+        } else {
+            context.addAttribute(name, value);
+        }
+    }
+
+    @Override
+    public void onOpenTagEnd(String markup) {
+        ElementContext context = elementStack.peek();
+        PluginInvoke invoke = context.pluginInvoke();
+        invoke.beforeElement(stream, context.getTagName());
+        invoke.beforeTagOpen(stream);
+        out(context.getOpenTagStartMarkup());
+        invoke.beforeAttributes(stream);
+        traverseAttributes(context, invoke);
+        invoke.afterAttributes(stream);
+        out(markup);
+        invoke.afterTagOpen(stream);
+        invoke.beforeChildren(stream);
+    }
+
+    private void traverseAttributes(ElementContext context, PluginInvoke invoke) {
+        for (Map.Entry<String, Object> attribute : context.getAttributes()) {
+            String attrName = attribute.getKey();
+            Object contentObj = attribute.getValue();
+            if (contentObj == null || contentObj instanceof String) {
+                String content = (String) contentObj;
+                emitAttribute(attrName, content, invoke);
+            } else if (contentObj instanceof Map.Entry) {
+                Map.Entry entry = (Map.Entry) contentObj;
+                PluginCallInfo info = (PluginCallInfo) entry.getKey();
+                Expression expression = (Expression) entry.getValue();
+                invoke.onPluginCall(stream, info, expression);
+            }
+        }
+    }
+
+    private void emitAttribute(String name, String content, PluginInvoke invoke) {
+        invoke.beforeAttribute(stream, name);
+        if (content == null) {
+            emitSimpleTextAttribute(name, null, invoke);
+        } else {
+            Interpolation interpolation = expressionParser.parseInterpolation(content);
+            String text = tryAsSimpleText(interpolation);
+            if (text != null) {
+                emitSimpleTextAttribute(name, text, invoke);
+            } else {
+                emitExpressionAttribute(name, interpolation, invoke);
+            }
+        }
+        invoke.afterAttribute(stream, name);
+    }
+
+    private void emitSimpleTextAttribute(String name, String textValue, PluginInvoke invoke) {
+        emitAttributeStart(name);
+        invoke.beforeAttributeValue(stream, name, new StringConstant(textValue));
+        if (textValue != null) {
+            emitAttributeValueStart();
+            textValue = escapeQuotes(textValue);
+            out(textValue);
+            emitAttributeEnd();
+        }
+        invoke.afterAttributeValue(stream, name);
+    }
+
+    private String escapeQuotes(String textValue) {
+        return textValue.replace("\"", "&quot;");
+    }
+
+    private void emitExpressionAttribute(String name, Interpolation interpolation, PluginInvoke invoke) {
+        interpolation = attributeChecked(name, interpolation);
+        if (interpolation.size() == 1) {
+            emitSingleFragment(name, interpolation, invoke);
+        } else {
+            emitMultipleFragment(name, interpolation, invoke);
+        }
+    }
+
+    private void emitMultipleFragment(String name, Interpolation interpolation, PluginInvoke invoke) {
+        // Simplified algorithm for attribute output, which works when the interpolation is not of size 1. In this
+        // case we are certain that the attribute value cannot be the boolean value true, so we can skip this test
+        // altogether
+        Expression expression = expressionWrapper.transform(interpolation, getAttributeMarkupContext(name));
+        String attrContent = symbolGenerator.next("attrContent");
+        String shouldDisplayAttr = symbolGenerator.next("shouldDisplayAttr");
+        stream.emit(new VariableBinding.Start(attrContent, expression.getRoot()));
+        stream.emit(
+                new VariableBinding.Start(
+                        shouldDisplayAttr,
+                        new BinaryOperation(
+                                BinaryOperator.OR,
+                                new Identifier(attrContent),
+                                new BinaryOperation(BinaryOperator.EQ, new StringConstant("false"), new Identifier(attrContent))
+                        )
+                )
+        );
+        stream.emit(new Conditional.Start(shouldDisplayAttr, true));
+        emitAttributeStart(name);
+        invoke.beforeAttributeValue(stream, name, expression.getRoot());
+        emitAttributeValueStart();
+        stream.emit(new OutVariable(attrContent));
+        emitAttributeEnd();
+        invoke.afterAttributeValue(stream, name);
+        stream.emit(Conditional.END);
+        stream.emit(VariableBinding.END);
+        stream.emit(VariableBinding.END);
+    }
+
+    private void emitSingleFragment(String name, Interpolation interpolation, PluginInvoke invoke) {
+        Expression valueExpression = expressionWrapper.transform(interpolation, null); //raw expression
+        String attrValue = symbolGenerator.next("attrValue"); //holds the raw attribute value
+        String attrContent = symbolGenerator.next("attrContent"); //holds the escaped attribute value
+        String isTrueVar = symbolGenerator.next("isTrueAttr"); // holds the comparison (attrValue == true)
+        String shouldDisplayAttr = symbolGenerator.next("shouldDisplayAttr");
+        MarkupContext markupContext = getAttributeMarkupContext(name);
+        Expression contentExpression = valueExpression.withNode(new Identifier(attrValue));
+        ExpressionNode node = valueExpression.getRoot();
+        stream.emit(new VariableBinding.Start(attrValue, node)); //attrContent = <expr>
+        stream.emit(new VariableBinding.Start(attrContent, expressionWrapper.adjustToContext(contentExpression, markupContext).getRoot()));
+        stream.emit(
+                new VariableBinding.Start(
+                        shouldDisplayAttr,
+                        new BinaryOperation(
+                                BinaryOperator.OR,
+                                new Identifier(attrContent),
+                                new BinaryOperation(BinaryOperator.EQ, new StringConstant("false"), new Identifier(attrValue))
+                        )
+                )
+        );
+        stream.emit(new Conditional.Start(shouldDisplayAttr, true)); // if (attrContent)
+        emitAttributeStart(name);   //write("attrName");
+        invoke.beforeAttributeValue(stream, name, node);
+        stream.emit(new VariableBinding.Start(isTrueVar, //isTrueAttr = (attrValue == true)
+                new BinaryOperation(BinaryOperator.EQ, new Identifier(attrValue), BooleanConstant.TRUE)));
+        stream.emit(new Conditional.Start(isTrueVar, false)); //if (!isTrueAttr)
+        emitAttributeValueStart(); // write("='");
+        stream.emit(new OutVariable(attrContent)); //write(attrContent)
+        emitAttributeEnd(); //write("'");
+        stream.emit(Conditional.END); //end if isTrueAttr
+        stream.emit(VariableBinding.END); //end scope for isTrueAttr
+        invoke.afterAttributeValue(stream, name);
+        stream.emit(Conditional.END); //end if attrContent
+        stream.emit(VariableBinding.END);
+        stream.emit(VariableBinding.END); //end scope for attrContent
+        stream.emit(VariableBinding.END); //end scope for attrValue
+    }
+
+
+    private void emitAttributeStart(String name) {
+        out(" " + name);
+    }
+
+    private void emitAttributeValueStart() {
+        out("=\"");
+    }
+
+    private void emitAttributeEnd() {
+        out("\"");
+    }
+
+    @Override
+    public void onCloseTag(String markup) {
+        ElementContext context = elementStack.pop();
+        PluginInvoke invoke = context.pluginInvoke();
+        invoke.afterChildren(stream);
+        boolean selfClosingTag = StringUtils.isEmpty(markup);
+        invoke.beforeTagClose(stream, selfClosingTag);
+        out(markup);
+        invoke.afterTagClose(stream, selfClosingTag);
+        invoke.afterElement(stream);
+    }
+
+    @Override
+    public void onText(String text) {
+        String tag = currentElementTag();
+        boolean explicitContextRequired = isExplicitContextRequired(tag);
+        MarkupContext markupContext = (explicitContextRequired) ? null : MarkupContext.TEXT;
+        outText(text, markupContext);
+    }
+
+    @Override
+    public void onComment(String markup) {
+        if (!Syntax.isSightlyComment(markup)) {
+            outText(markup, MarkupContext.COMMENT);
+        }
+    }
+
+    @Override
+    public void onDataNode(String markup) {
+        out(markup);
+    }
+
+    @Override
+    public void onDocType(String markup) {
+        out(markup);
+    }
+
+    @Override
+    public void onDocumentFinished() {
+        this.stream.signalDone();
+    }
+
+    private void outText(String content, MarkupContext context) {
+        Interpolation interpolation = expressionParser.parseInterpolation(content);
+        if (context == null) {
+            interpolation = requireContext(interpolation);
+        }
+        String text = tryAsSimpleText(interpolation);
+        if (text != null) {
+            out(text);
+        } else {
+            outExprNode(expressionWrapper.transform(interpolation, context).getRoot());
+        }
+    }
+
+    private Interpolation requireContext(Interpolation interpolation) {
+        Interpolation result = new Interpolation();
+        for (Fragment fragment : interpolation.getFragments()) {
+            Fragment addedFragment;
+            if (fragment.isString()) {
+                addedFragment = fragment;
+            } else {
+                if (fragment.getExpression().containsOption(Syntax.CONTEXT_OPTION)) {
+                    addedFragment = fragment;
+                } else {
+                    String currentTag = currentElementTag();
+                    log.warn("Element {} requires that all expressions have an explicit context specified. Expression will be " +
+                            "replaced by the empty string", currentTag);
+                    addedFragment = new Fragment.Expr(new Expression(StringConstant.EMPTY));
+                }
+            }
+            result.addFragment(addedFragment);
+        }
+        return result;
+    }
+
+    private Interpolation attributeChecked(String attributeName, Interpolation interpolation) {
+        if (!MarkupUtils.isSensitiveAttribute(attributeName)) {
+            return interpolation;
+        }
+        Interpolation newInterpolation = new Interpolation();
+        for (Fragment fragment : interpolation.getFragments()) {
+            Fragment addedFragment = fragment;
+            if (fragment.isExpression()) {
+                Expression expression = fragment.getExpression();
+                if (!expression.containsOption(Syntax.CONTEXT_OPTION)) {
+                    log.warn("All expressions within the value of attribute {} need to have an explicit context option. The expression will be erased.",
+                            attributeName);
+                    addedFragment = new Fragment.Text("");
+                }
+            }
+            newInterpolation.addFragment(addedFragment);
+        }
+        return newInterpolation;
+    }
+
+
+    private void outExprNode(ExpressionNode node) {
+        String variable = symbolGenerator.next();
+        stream.emit(new VariableBinding.Start(variable, node));
+        stream.emit(new OutVariable(variable));
+        stream.emit(VariableBinding.END);
+    }
+
+
+    private String tryAsSimpleText(Interpolation interpolation) {
+        if (interpolation.size() == 1) {
+            Fragment fragment = interpolation.getFragment(0);
+            if (fragment.isString()) {
+                return fragment.getText();
+            }
+        } else if (interpolation.size() == 0) {
+            return "";
+        }
+        return null;
+    }
+
+    private void out(String text) {
+        stream.emit(new OutText(text));
+    }
+
+    private void handlePlugin(String name, String value, ElementContext context) {
+        PluginCallInfo callInfo = Syntax.parsePluginAttribute(name);
+        if (callInfo != null) {
+            Plugin plugin = obtainPlugin(callInfo.getName());
+            Expression expr = expressionWrapper.transform(
+                    expressionParser.parseInterpolation(value), null);
+            PluginInvoke invoke = plugin.invoke(expr, callInfo, compilerContext);
+            context.addPlugin(invoke, plugin.priority());
+            context.addPluginCall(name, callInfo, expr);
+        }
+    }
+
+    private Plugin obtainPlugin(String name) {
+        Plugin plugin = pluginRegistry.get(name);
+        if (plugin == null) {
+            throw new UnsupportedOperationException(String.format("Plugin %s does not exist", name));
+        }
+        return plugin;
+    }
+
+    private MarkupContext getAttributeMarkupContext(String attributeName) {
+        if ("src".equalsIgnoreCase(attributeName) || "href".equalsIgnoreCase(attributeName)) {
+            return MarkupContext.URI;
+        }
+        return MarkupContext.ATTRIBUTE;
+    }
+
+    private String currentElementTag() {
+        if (elementStack.isEmpty()) {
+            return null;
+        }
+        ElementContext current = elementStack.peek();
+        return current.getTagName();
+    }
+
+    private boolean isExplicitContextRequired(String parentElementName) {
+        return parentElementName != null &&
+                ("script".equals(parentElementName) || "style".equals(parentElementName));
+    }
+}

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/ParserException.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/ParserException.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/ParserException.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/ParserException.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * 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.compiler.frontend;
+
+/**
+ * Plugin runtime exception to be used for either html or expression parser exceptions.
+ */
+public class ParserException extends RuntimeException {
+
+    public ParserException() {
+        super();
+    }
+
+    public ParserException(String message) {
+        super(message);
+    }
+
+    public ParserException(String message, Throwable throwable) {
+        super(message, throwable);
+    }
+
+    public ParserException(Throwable throwable) {
+        super(throwable);
+    }
+}

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/ParserHelper.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/ParserHelper.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/ParserHelper.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/ParserHelper.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * 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.compiler.frontend;
+
+import org.apache.commons.lang.StringEscapeUtils;
+
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.StringConstant;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.StringConstant;
+
+/**
+ * Helper utilities for the ANTLR parser
+ */
+public class ParserHelper {
+
+    public static String unEscape(String original) {
+        return original.replaceAll("\\\\\"", "\"").replaceAll("\\\\'", "'");
+    }
+
+    public static StringConstant createStringConstant(String original) {
+        String escaped = StringEscapeUtils.unescapeJava(original);
+        String trimmed = escaped.substring(1, escaped.length() - 1);
+        return new StringConstant(trimmed);
+    }
+
+}

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/SightlyParserErrorListener.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/SightlyParserErrorListener.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/SightlyParserErrorListener.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/SightlyParserErrorListener.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * 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.compiler.frontend;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.antlr.v4.runtime.BaseErrorListener;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.Parser;
+import org.antlr.v4.runtime.RecognitionException;
+import org.antlr.v4.runtime.Recognizer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.sling.scripting.sightly.api.SightlyParsingException;
+
+/**
+ * The {@code SightlyParserErrorListener} handles parsing error reporting by sending offending input to a logger.
+ */
+public class SightlyParserErrorListener extends BaseErrorListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SightlyParserErrorListener.class);
+
+    @Override
+    public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) {
+        List<String> stack = ((Parser) recognizer).getRuleInvocationStack();
+        Collections.reverse(stack);
+        StringBuilder errorMessage = new StringBuilder();
+        errorMessage.append("Sightly syntax error detected.\n");
+        errorMessage.append("rule stack: ").append(stack).append("\n");
+        errorMessage.append("error starts at column: ").append(charPositionInLine).append("\n");
+        errorMessage.append(msg);
+        throw new SightlyParsingException("Sightly syntax error detected", ((CommonTokenStream) recognizer.getInputStream()).getTokenSource().getInputStream().toString(), e);
+    }
+}

Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/SimpleFrontend.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/SimpleFrontend.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/SimpleFrontend.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/frontend/SimpleFrontend.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * 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.compiler.frontend;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.sling.scripting.sightly.compiler.CompilerFrontend;
+import org.apache.sling.scripting.sightly.compiler.api.Filter;
+import org.apache.sling.scripting.sightly.compiler.api.MarkupHandler;
+import org.apache.sling.scripting.sightly.compiler.api.MarkupParser;
+import org.apache.sling.scripting.sightly.compiler.api.plugin.Plugin;
+import org.apache.sling.scripting.sightly.compiler.util.stream.PushStream;
+import org.apache.sling.scripting.sightly.compiler.api.MarkupHandler;
+
+/**
+ * DOM-based compiler implementation
+ */
+public class SimpleFrontend implements CompilerFrontend {
+
+    private final MarkupParser parser;
+    private final Map<String, Plugin> plugins;
+    private final List<Filter> filters;
+
+    public SimpleFrontend(MarkupParser markupParser, Collection<Plugin> plugins, Collection<Filter> filters) {
+        this.plugins = new HashMap<String, Plugin>();
+        for (Plugin plugin : plugins) {
+            this.plugins.put(plugin.name(), plugin);
+        }
+        this.filters = new ArrayList<Filter>(filters);
+        this.parser = markupParser;
+    }
+
+    @Override
+    public void compile(PushStream stream, String source) {
+        MarkupHandler markupHandler = new MarkupHandlerImpl(stream, plugins, filters);
+        parser.parse(source, markupHandler);
+    }
+}