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 [7/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/optimization/CoalescingWrites.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/CoalescingWrites.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/CoalescingWrites.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/CoalescingWrites.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * 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.optimization;
+
+import org.apache.sling.scripting.sightly.compiler.api.ris.Command;
+import org.apache.sling.scripting.sightly.compiler.api.ris.command.OutText;
+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.util.stream.PushStream;
+import org.apache.sling.scripting.sightly.compiler.api.ris.Command;
+import org.apache.sling.scripting.sightly.compiler.api.ris.CommandHandler;
+
+/**
+ * Aggregate consecutive writes in bigger chunks of text
+ */
+public final class CoalescingWrites implements CommandHandler {
+
+ public static final StreamTransformer TRANSFORMER = new StreamTransformer() {
+ @Override
+ public CommandStream transform(CommandStream inStream) {
+ PushStream outputStream = new PushStream();
+ CoalescingWrites instance = new CoalescingWrites(outputStream);
+ inStream.addHandler(instance);
+ return outputStream;
+ }
+ };
+
+ private StringBuilder builder = new StringBuilder();
+ private final PushStream outStream;
+
+ private CoalescingWrites(PushStream stream) {
+ this.outStream = stream;
+ }
+
+ @Override
+ public void onEmit(Command command) {
+ String text = detectText(command);
+ if (text != null) {
+ builder.append(text);
+ } else {
+ flushText();
+ outStream.emit(command);
+ }
+ }
+
+
+ @Override
+ public void onError(String errorMessage) {
+ flushText();
+ outStream.signalError(errorMessage);
+ }
+
+ @Override
+ public void onDone() {
+ flushText();
+ outStream.signalDone();
+ }
+
+ private String detectText(Command command) {
+ if (command instanceof OutText) {
+ return ((OutText) command).getText();
+ }
+ return null;
+ }
+
+ private void flushText() {
+ if (builder.length() > 0) {
+ outStream.emit(new OutText(builder.toString()));
+ builder = new StringBuilder();
+ }
+ }
+}
Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/CommandVariableUsage.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/CommandVariableUsage.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/CommandVariableUsage.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/CommandVariableUsage.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * 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.optimization;
+
+import java.util.ArrayList;
+import java.util.List;
+
+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;
+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.CommandVisitor;
+
+/**
+ * Extracts the variables used in a command
+ */
+public class CommandVariableUsage implements CommandVisitor {
+
+ private ArrayList<String> variables = new ArrayList<String>();
+
+ public static List<String> extractVariables(Command command) {
+ CommandVariableUsage cvu = new CommandVariableUsage();
+ command.accept(cvu);
+ return cvu.variables;
+ }
+
+ @Override
+ public void visit(Conditional.Start conditionalStart) {
+ variables.add(conditionalStart.getVariable());
+ }
+
+ @Override
+ public void visit(Conditional.End conditionalEnd) {
+ }
+
+ @Override
+ public void visit(VariableBinding.Start variableBindingStart) {
+ addFromExpression(variableBindingStart.getExpression());
+ }
+
+ @Override
+ public void visit(VariableBinding.End variableBindingEnd) {
+ }
+
+ @Override
+ public void visit(VariableBinding.Global globalAssignment) {
+ addFromExpression(globalAssignment.getExpression());
+ }
+
+ private void addFromExpression(ExpressionNode node) {
+ variables.addAll(VariableFinder.findVariables(node));
+ }
+
+ @Override
+ public void visit(OutVariable outVariable) {
+ variables.add(outVariable.getVariableName());
+ }
+
+ @Override
+ public void visit(OutText outText) {
+ }
+
+ @Override
+ public void visit(Loop.Start loopStart) {
+ variables.add(loopStart.getListVariable());
+ }
+
+ @Override
+ public void visit(Loop.End loopEnd) {
+ }
+
+ @Override
+ public void visit(BufferControl.Push bufferPush) {
+ }
+
+ @Override
+ public void visit(BufferControl.Pop bufferPop) {
+ }
+
+ @Override
+ public void visit(Procedure.Start startProcedure) {
+ }
+
+ @Override
+ public void visit(Procedure.End endProcedure) {
+ }
+
+ @Override
+ public void visit(Procedure.Call procedureCall) {
+ variables.add(procedureCall.getTemplateVariable());
+ variables.add(procedureCall.getArgumentsVariable());
+ }
+}
Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/DeadCodeRemoval.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/DeadCodeRemoval.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/DeadCodeRemoval.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/DeadCodeRemoval.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * 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.optimization;
+
+import java.util.Stack;
+
+import org.apache.sling.scripting.sightly.compiler.api.expression.ExpressionNode;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.BooleanConstant;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.NullLiteral;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.NumericConstant;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.StringConstant;
+import org.apache.sling.scripting.sightly.compiler.api.ris.Command;
+import org.apache.sling.scripting.sightly.compiler.api.ris.CommandStream;
+import org.apache.sling.scripting.sightly.compiler.api.ris.command.Conditional;
+import org.apache.sling.scripting.sightly.compiler.api.ris.command.VariableBinding;
+import org.apache.sling.scripting.sightly.compiler.util.stream.EmitterVisitor;
+import org.apache.sling.scripting.sightly.compiler.util.stream.PushStream;
+import org.apache.sling.scripting.sightly.compiler.util.stream.Streams;
+import org.apache.sling.scripting.sightly.compiler.visitor.StateControl;
+import org.apache.sling.scripting.sightly.compiler.visitor.StatefulVisitor;
+import org.apache.sling.scripting.sightly.compiler.visitor.StatefulRangeIgnore;
+import org.apache.sling.scripting.sightly.compiler.visitor.TrackingVisitor;
+import org.apache.sling.scripting.sightly.common.Dynamic;
+import org.apache.sling.scripting.sightly.common.Dynamic;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.NullLiteral;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.NumericConstant;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.StringConstant;
+import org.apache.sling.scripting.sightly.compiler.api.ris.Command;
+import org.apache.sling.scripting.sightly.compiler.util.stream.EmitterVisitor;
+import org.apache.sling.scripting.sightly.compiler.util.stream.PushStream;
+import org.apache.sling.scripting.sightly.compiler.util.stream.Streams;
+import org.apache.sling.scripting.sightly.compiler.visitor.StateControl;
+import org.apache.sling.scripting.sightly.compiler.visitor.StatefulRangeIgnore;
+import org.apache.sling.scripting.sightly.compiler.visitor.StatefulVisitor;
+import org.apache.sling.scripting.sightly.compiler.visitor.TrackingVisitor;
+
+/**
+ * Removes code under conditionals which are proven to fail. It is probably
+ * a good idea to run this optimization after running
+ * {@link org.apache.sling.scripting.sightly.compiler.optimization.reduce.ConstantFolding}
+ */
+public class DeadCodeRemoval extends TrackingVisitor<Boolean> implements EmitterVisitor {
+ // this could be merged with constant folding for better accuracy
+
+ public static StreamTransformer transformer(final Dynamic dynamic) {
+ return new StreamTransformer() {
+ @Override
+ public CommandStream transform(CommandStream inStream) {
+ StatefulVisitor visitor = new StatefulVisitor();
+ DeadCodeRemoval dcr = new DeadCodeRemoval(visitor.getControl(), dynamic);
+ visitor.initializeWith(dcr);
+ Streams.connect(inStream, dcr.getOutputStream(), visitor);
+ return dcr.getOutputStream();
+ }
+ };
+ }
+
+ private final PushStream outStream = new PushStream();
+ private final StateControl stateControl;
+ private final Dynamic dynamic;
+ private final Stack<Boolean> keepConditionalEndStack = new Stack<Boolean>();
+
+ public DeadCodeRemoval(StateControl stateControl, Dynamic dynamic) {
+ this.stateControl = stateControl;
+ this.dynamic = dynamic;
+ }
+
+ @Override
+ public void visit(VariableBinding.Start variableBindingStart) {
+ Boolean truthValue = decodeConstantBool(variableBindingStart.getExpression());
+ tracker.pushVariable(variableBindingStart.getVariableName(), truthValue);
+ outStream.emit(variableBindingStart);
+ }
+
+ @Override
+ public void visit(Conditional.Start conditionalStart) {
+ Boolean truthValue = tracker.get(conditionalStart.getVariable());
+ boolean keepConditionalEnd;
+ if (truthValue == null) { //no information about the value of this variable
+ keepConditionalEnd = true;
+ outStream.emit(conditionalStart);
+ } else { //we already know what happens with this conditional. We can remove it
+ keepConditionalEnd = false;
+ if (truthValue != conditionalStart.getExpectedTruthValue()) {
+ //this conditional will always fail. We can ignore everything until
+ //the corresponding end-conditional
+ stateControl.push(new StatefulRangeIgnore(stateControl, Conditional.Start.class, Conditional.End.class));
+ return;
+ }
+ }
+ keepConditionalEndStack.push(keepConditionalEnd);
+ }
+
+ @Override
+ public void visit(Conditional.End conditionalEnd) {
+ boolean keep = keepConditionalEndStack.pop();
+ if (keep) {
+ outStream.emit(conditionalEnd);
+ }
+ }
+
+ @Override
+ public PushStream getOutputStream() {
+ return outStream;
+ }
+
+ @Override
+ protected Boolean assignDefault(Command command) {
+ return null;
+ }
+
+ @Override
+ protected void onCommand(Command command) {
+ outStream.emit(command);
+ }
+
+ private Boolean decodeConstantBool(ExpressionNode node) {
+ if (node instanceof StringConstant) {
+ return dynamic.coerceToBoolean(((StringConstant) node).getText());
+ }
+ if (node instanceof BooleanConstant) {
+ return ((BooleanConstant) node).getValue();
+ }
+ if (node instanceof NumericConstant) {
+ return dynamic.coerceToBoolean(((NumericConstant) node).getValue());
+ }
+ if (node instanceof NullLiteral) {
+ return dynamic.coerceToBoolean(null);
+ }
+ return null;
+ }
+}
Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/SequenceStreamTransformer.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/SequenceStreamTransformer.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/SequenceStreamTransformer.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/SequenceStreamTransformer.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * 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.optimization;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.sling.scripting.sightly.compiler.api.ris.CommandStream;
+
+/**
+ * Applies a list of transformations in sequence
+ */
+public class SequenceStreamTransformer implements StreamTransformer {
+
+ private List<StreamTransformer> transformers;
+
+ public SequenceStreamTransformer(List<StreamTransformer> transformers) {
+ this.transformers = new ArrayList<StreamTransformer>(transformers);
+ }
+
+ @Override
+ public CommandStream transform(CommandStream inStream) {
+ CommandStream stream = inStream;
+ for (StreamTransformer transformer : transformers) {
+ stream = transformer.transform(stream);
+ }
+ return stream;
+ }
+}
Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/StreamTransformer.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/StreamTransformer.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/StreamTransformer.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/StreamTransformer.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * 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.optimization;
+
+import org.apache.sling.scripting.sightly.compiler.api.ris.CommandStream;
+
+/**
+ * Interface for stream transformations
+ */
+public interface StreamTransformer {
+
+ /**
+ * Given the input stream, return a transformed out stream
+ * @param inStream the input stream
+ * @return the result stream
+ */
+ CommandStream transform(CommandStream inStream);
+
+}
Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/SyntheticMapRemoval.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/SyntheticMapRemoval.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/SyntheticMapRemoval.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/SyntheticMapRemoval.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,166 @@
+/*******************************************************************************
+ * 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.optimization;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.scripting.sightly.compiler.api.expression.ExpressionNode;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.Identifier;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.MapLiteral;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.NullLiteral;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.PropertyAccess;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.StringConstant;
+import org.apache.sling.scripting.sightly.compiler.api.ris.Command;
+import org.apache.sling.scripting.sightly.compiler.api.ris.CommandStream;
+import org.apache.sling.scripting.sightly.compiler.api.ris.command.VariableBinding;
+import org.apache.sling.scripting.sightly.compiler.util.expression.NodeTransformer;
+import org.apache.sling.scripting.sightly.compiler.util.stream.EmitterVisitor;
+import org.apache.sling.scripting.sightly.compiler.util.stream.PushStream;
+import org.apache.sling.scripting.sightly.compiler.util.stream.Streams;
+import org.apache.sling.scripting.sightly.compiler.visitor.TrackingVisitor;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.StringConstant;
+import org.apache.sling.scripting.sightly.compiler.api.ris.Command;
+import org.apache.sling.scripting.sightly.compiler.util.expression.NodeTransformer;
+import org.apache.sling.scripting.sightly.compiler.util.stream.EmitterVisitor;
+import org.apache.sling.scripting.sightly.compiler.util.stream.Streams;
+
+/**
+ * This optimization handles variables initialized to map literals. It
+ * initially assigns the values in the map to variables and wherever
+ * the map literal is accessed, the property access is replaced with
+ * the value variable, thus removing the need for a map lookup.
+ */
+public final class SyntheticMapRemoval extends TrackingVisitor<MapLiteral> implements EmitterVisitor {
+
+ public static final StreamTransformer TRANSFORMER = new StreamTransformer() {
+ @Override
+ public CommandStream transform(CommandStream inStream) {
+ return Streams.map(inStream, new SyntheticMapRemoval());
+ }
+ };
+
+ private static final String VARIABLE_MARKER = "_field$_";
+
+ private final PushStream outputStream = new PushStream();
+ private final NodeTransformer transformer = new PropertyAccessTransformer();
+
+ private SyntheticMapRemoval() {
+ }
+
+ @Override
+ public void visit(VariableBinding.Start variableBindingStart) {
+ ExpressionNode node = variableBindingStart.getExpression();
+ String variable = variableBindingStart.getVariableName();
+ ExpressionNode transformed = transform(node);
+ if (transformed instanceof MapLiteral) {
+ MapLiteral newLiteral = overrideMap(variable, (MapLiteral) transformed);
+ tracker.pushVariable(variable, newLiteral);
+ transformed = newLiteral;
+ } else {
+ tracker.pushVariable(variable, null);
+ }
+ outputStream.emit(new VariableBinding.Start(variable, transformed));
+ }
+
+ @Override
+ public void visit(VariableBinding.End variableBindingEnd) {
+ Map.Entry<String, MapLiteral> entry = tracker.peek();
+ super.visit(variableBindingEnd);
+ MapLiteral literal = entry.getValue();
+ if (literal != null) {
+ //need to un-bind all the introduced variables
+ for (int i = 0; i < literal.getMap().size(); i++) {
+ outputStream.emit(VariableBinding.END);
+ }
+ }
+ }
+
+ private ExpressionNode transform(ExpressionNode node) {
+ return transformer.transform(node);
+ }
+
+ private MapLiteral overrideMap(String variableName, MapLiteral mapLiteral) {
+ Map<String, ExpressionNode> newLiteral = new HashMap<String, ExpressionNode>();
+ for (Map.Entry<String, ExpressionNode> entry : mapLiteral.getMap().entrySet()) {
+ String property = entry.getKey();
+ ExpressionNode valueNode = entry.getValue();
+ String valueVariable = valueVariableName(variableName, property);
+ newLiteral.put(property, new Identifier(valueVariable));
+ outputStream.emit(new VariableBinding.Start(valueVariable, valueNode));
+ }
+ return new MapLiteral(newLiteral);
+ }
+
+ private String valueVariableName(String variableName, String propertyName) {
+ return variableName + VARIABLE_MARKER + propertyName;
+ }
+
+ @Override
+ protected MapLiteral assignDefault(Command command) {
+ return null;
+ }
+
+ @Override
+ public void onCommand(Command command) {
+ outputStream.emit(command);
+ }
+
+ @Override
+ public PushStream getOutputStream() {
+ return outputStream;
+ }
+
+ private class PropertyAccessTransformer extends NodeTransformer {
+ @Override
+ public ExpressionNode evaluate(PropertyAccess propertyAccess) {
+ ExpressionNode target = propertyAccess.getTarget();
+ String variable = extractIdentifier(target);
+ if (variable != null) {
+ MapLiteral literal = tracker.get(variable);
+ if (literal != null) {
+ String property = extractProperty(propertyAccess.getProperty());
+ if (property != null) {
+ ExpressionNode replacementNode = literal.getValue(property);
+ if (replacementNode == null) {
+ replacementNode = NullLiteral.INSTANCE;
+ }
+ return replacementNode;
+ }
+ }
+ }
+ return super.evaluate(propertyAccess);
+ }
+
+ private String extractProperty(ExpressionNode expressionNode) {
+ if (expressionNode instanceof StringConstant) {
+ return ((StringConstant) expressionNode).getText();
+ }
+ return null;
+ }
+
+ private String extractIdentifier(ExpressionNode node) {
+ if (node instanceof Identifier) {
+ return ((Identifier) node).getName();
+ }
+ return null;
+ }
+ }
+}
Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/UnusedVariableRemoval.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/UnusedVariableRemoval.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/UnusedVariableRemoval.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/UnusedVariableRemoval.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * 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.optimization;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Stack;
+
+import org.apache.sling.scripting.sightly.compiler.api.ris.Command;
+import org.apache.sling.scripting.sightly.compiler.api.ris.CommandStream;
+import org.apache.sling.scripting.sightly.compiler.api.ris.command.VariableBinding;
+import org.apache.sling.scripting.sightly.compiler.util.stream.EmitterVisitor;
+import org.apache.sling.scripting.sightly.compiler.util.stream.PushStream;
+import org.apache.sling.scripting.sightly.compiler.util.stream.Streams;
+import org.apache.sling.scripting.sightly.compiler.visitor.TrackingVisitor;
+
+/**
+ * This optimization removes variables which are bound but
+ * never used in the command stream
+ */
+public final class UnusedVariableRemoval extends TrackingVisitor<UnusedVariableRemoval.VariableActivity> implements EmitterVisitor {
+
+ public static final StreamTransformer TRANSFORMER = new StreamTransformer() {
+ @Override
+ public CommandStream transform(CommandStream inStream) {
+ return Streams.map(inStream, new UnusedVariableRemoval());
+ }
+ };
+
+ private final PushStream outputStream = new PushStream();
+ private final Stack<List<Command>> storedCommandsStack = new Stack<List<Command>>();
+
+ private UnusedVariableRemoval() {
+ }
+
+ @Override
+ public PushStream getOutputStream() {
+ return outputStream;
+ }
+
+ @Override
+ public void visit(VariableBinding.Start variableBindingStart) {
+ //push a new buffer where we will store the following commands
+ //these commands will be emitted only if this variable will be used in
+ //it's scope
+ storedCommandsStack.push(new ArrayList<Command>());
+ //start tracking the variable
+ tracker.pushVariable(variableBindingStart.getVariableName(), new VariableActivity(variableBindingStart));
+ }
+
+ @Override
+ public void visit(VariableBinding.End variableBindingEnd) {
+ // Get the activity of the exiting variable
+ VariableActivity variableActivity = tracker.peek().getValue();
+ tracker.popVariable();
+ boolean emitBindingEnd = true;
+ if (variableActivity != null) {
+ //this was a tracked variable. Popping all the commands
+ //which were delayed for this variable
+ List<Command> commands = storedCommandsStack.pop();
+ //if the variable binding is emitted than this binding
+ //end must be emitted as well
+ emitBindingEnd = variableActivity.isUsed();
+ if (variableActivity.isUsed()) {
+ VariableBinding.Start variableBindingStart = variableActivity.getCommand();
+ //variable was used. we can let it pass through
+ emit(variableBindingStart);
+ //register the usage of all the variables that appear in the bound expression
+ registerUsage(variableBindingStart);
+ }
+ //emit all the delayed commands
+ for (Command command : commands) {
+ emit(command);
+ }
+ }
+ if (emitBindingEnd) {
+ emit(variableBindingEnd);
+ }
+ }
+
+ @Override
+ protected VariableActivity assignDefault(Command command) {
+ return null;
+ }
+
+ @Override
+ protected void onCommand(Command command) {
+ registerUsage(command);
+ emit(command);
+ }
+
+ /**
+ * Emit the current command. If the command is delayed by
+ * a variable tracking process, than add it to the top command list
+ * @param command a stream command
+ */
+ private void emit(Command command) {
+ if (storedCommandsStack.isEmpty()) {
+ outputStream.emit(command);
+ } else {
+ List<Command> list = storedCommandsStack.peek();
+ list.add(command);
+ }
+ }
+
+ /**
+ * Extract all the variables in this command and mark them
+ * as used
+ * @param command - a stream command
+ */
+ private void registerUsage(Command command) {
+ List<String> usedVariables = CommandVariableUsage.extractVariables(command);
+ for (String usedVariable : usedVariables) {
+ VariableActivity activity = tracker.get(usedVariable);
+ if (activity != null) {
+ activity.markUsed();
+ }
+ }
+ }
+
+ /**
+ * Track the activity of a variable binding
+ */
+ static class VariableActivity {
+ private boolean used;
+ private VariableBinding.Start command;
+
+ VariableActivity(VariableBinding.Start command) {
+ this.command = command;
+ }
+
+ public void markUsed() {
+ used = true;
+ }
+
+ public boolean isUsed() {
+ return used;
+ }
+
+ public VariableBinding.Start getCommand() {
+ return command;
+ }
+ }
+}
Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/VariableFinder.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/VariableFinder.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/VariableFinder.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/VariableFinder.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,132 @@
+/*******************************************************************************
+ * 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.optimization;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.sling.scripting.sightly.compiler.api.expression.ExpressionNode;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.ArrayLiteral;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.BinaryOperation;
+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.MapLiteral;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.NullLiteral;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.NumericConstant;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.PropertyAccess;
+import org.apache.sling.scripting.sightly.compiler.util.expression.SideEffectVisitor;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.StringConstant;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.TernaryOperator;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.UnaryOperation;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.RuntimeCall;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.BinaryOperation;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.NumericConstant;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.StringConstant;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.UnaryOperation;
+
+/**
+ * SideEffectVisitor which extracts all the variables from an expression
+ */
+public class VariableFinder extends SideEffectVisitor {
+
+ private final Set<String> variables;
+
+ public VariableFinder(Set<String> variables) {
+ this.variables = variables;
+ }
+
+ private void traverse(ExpressionNode node) {
+ if (node != null) {
+ node.accept(this);
+ }
+ }
+
+ public static Set<String> findVariables(ExpressionNode node) {
+ HashSet<String> result = new HashSet<String>();
+ VariableFinder finder = new VariableFinder(result);
+ finder.traverse(node);
+ return result;
+ }
+
+ @Override
+ public void visit(PropertyAccess propertyAccess) {
+ traverse(propertyAccess.getTarget());
+ traverse(propertyAccess.getProperty());
+ }
+
+ @Override
+ public void visit(Identifier identifier) {
+ variables.add(identifier.getName());
+ }
+
+ @Override
+ public void visit(StringConstant text) {
+ }
+
+ @Override
+ public void visit(BinaryOperation binaryOperation) {
+ traverse(binaryOperation.getLeftOperand());
+ traverse(binaryOperation.getRightOperand());
+ }
+
+ @Override
+ public void visit(BooleanConstant booleanConstant) {
+ }
+
+ @Override
+ public void visit(NumericConstant numericConstant) {
+ }
+
+ @Override
+ public void visit(UnaryOperation unaryOperation) {
+ traverse(unaryOperation.getTarget());
+ }
+
+ @Override
+ public void visit(TernaryOperator ternaryOperator) {
+ traverse(ternaryOperator.getCondition());
+ traverse(ternaryOperator.getThenBranch());
+ traverse(ternaryOperator.getElseBranch());
+ }
+
+ @Override
+ public void visit(RuntimeCall runtimeCall) {
+ for (ExpressionNode node : runtimeCall.getArguments()) {
+ traverse(node);
+ }
+ }
+
+ @Override
+ public void visit(MapLiteral mapLiteral) {
+ for (ExpressionNode value : mapLiteral.getMap().values()) {
+ traverse(value);
+ }
+ }
+
+ @Override
+ public void visit(ArrayLiteral arrayLiteral) {
+ for (ExpressionNode item : arrayLiteral.getItems()) {
+ traverse(item);
+ }
+ }
+
+ @Override
+ public void visit(NullLiteral nullLiteral) {
+ }
+}
Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/reduce/ConstantFolding.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/reduce/ConstantFolding.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/reduce/ConstantFolding.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/reduce/ConstantFolding.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.optimization.reduce;
+
+import java.util.Collection;
+import java.util.Map;
+
+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.CommandStream;
+import org.apache.sling.scripting.sightly.compiler.api.ris.command.VariableBinding;
+import org.apache.sling.scripting.sightly.compiler.util.stream.EmitterVisitor;
+import org.apache.sling.scripting.sightly.compiler.util.stream.PushStream;
+import org.apache.sling.scripting.sightly.compiler.util.stream.Streams;
+import org.apache.sling.scripting.sightly.compiler.optimization.StreamTransformer;
+import org.apache.sling.scripting.sightly.compiler.visitor.TrackingVisitor;
+import org.apache.sling.scripting.sightly.common.Dynamic;
+import org.apache.sling.scripting.sightly.common.Dynamic;
+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.CommandStream;
+import org.apache.sling.scripting.sightly.compiler.api.ris.command.VariableBinding;
+import org.apache.sling.scripting.sightly.compiler.optimization.StreamTransformer;
+import org.apache.sling.scripting.sightly.compiler.util.stream.EmitterVisitor;
+import org.apache.sling.scripting.sightly.compiler.util.stream.PushStream;
+import org.apache.sling.scripting.sightly.compiler.util.stream.Streams;
+import org.apache.sling.scripting.sightly.compiler.visitor.TrackingVisitor;
+
+/**
+ * Optimization which evaluates constant expressions during compilation-time
+ */
+public final class ConstantFolding extends TrackingVisitor<EvalResult> implements EmitterVisitor {
+
+ private final Dynamic dynamic;
+ private final PushStream outStream = new PushStream();
+
+ private ConstantFolding(Dynamic dynamic) {
+ this.dynamic = dynamic;
+ }
+
+ public static StreamTransformer transformer(final Dynamic dynamic) {
+ return new StreamTransformer() {
+ @Override
+ public CommandStream transform(CommandStream inStream) {
+ return Streams.map(inStream, new ConstantFolding(dynamic));
+ }
+ };
+ }
+
+ @Override
+ public void visit(VariableBinding.Start variableBindingStart) {
+ String variable = variableBindingStart.getVariableName();
+ ExpressionNode node = variableBindingStart.getExpression();
+ EvalResult result = ExpressionReducer.reduce(node, tracker, dynamic);
+ result = avoidFoldingDataStructures(result);
+ tracker.pushVariable(variable, result);
+ outStream.emit(new VariableBinding.Start(variable, result.getNode()));
+ }
+
+ private EvalResult avoidFoldingDataStructures(EvalResult evalResult) {
+ //this prevents us from replacing variables that are bound to maps & collections
+ //in expressions since that would mean we rebuild the same constant data structures
+ //each time
+ if (evalResult.isConstant() && isDataStructure(evalResult.getValue())) {
+ return EvalResult.nonConstant(evalResult.getNode());
+ }
+ return evalResult;
+ }
+
+ private boolean isDataStructure(Object obj) {
+ return (obj instanceof Collection) || (obj instanceof Map);
+ }
+
+ @Override
+ protected EvalResult assignDefault(Command command) {
+ return null;
+ }
+
+ @Override
+ protected void onCommand(Command command) {
+ outStream.emit(command);
+ }
+
+ @Override
+ public PushStream getOutputStream() {
+ return outStream;
+ }
+}
Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/reduce/EvalResult.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/reduce/EvalResult.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/reduce/EvalResult.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/reduce/EvalResult.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * 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.optimization.reduce;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.sling.scripting.sightly.compiler.api.CompilerException;
+import org.apache.sling.scripting.sightly.compiler.api.expression.ExpressionNode;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.ArrayLiteral;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.BooleanConstant;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.MapLiteral;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.NullLiteral;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.NumericConstant;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.StringConstant;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.NullLiteral;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.NumericConstant;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.StringConstant;
+
+/**
+ * Data structure used in expression reducing
+ */
+public final class EvalResult {
+ private final ExpressionNode node;
+ private final Object value;
+
+ public static EvalResult constant(Object obj) {
+ return new EvalResult(null, obj);
+ }
+
+ public static EvalResult nonConstant(ExpressionNode node) {
+ return new EvalResult(node, null);
+ }
+
+ private EvalResult(ExpressionNode node, Object value) {
+ this.node = node;
+ this.value = value;
+ }
+
+ public boolean isConstant() {
+ return node == null;
+ }
+
+ public Object getValue() {
+ if (!isConstant()) {
+ throw new CompilerException(new UnsupportedOperationException("Cannot get constant value from non-constant result"));
+ }
+ return value;
+ }
+
+ public ExpressionNode getNode() {
+ return (isConstant()) ? asLiteral(getValue()) : node;
+ }
+
+ private static ExpressionNode asLiteral(Object value) {
+ if (value instanceof Boolean) {
+ return new BooleanConstant((Boolean) value);
+ }
+ if (value instanceof String) {
+ return new StringConstant((String) value);
+ }
+ if (value instanceof Number) {
+ return new NumericConstant((Number) value);
+ }
+ if (value instanceof Map) {
+ //noinspection unchecked
+ return asMapLiteral((Map<String, Object>) value);
+ }
+ if (value instanceof List) {
+ //noinspection unchecked
+ return asArrayLiteral((List<Object>) value);
+ }
+ if (value == null) {
+ return NullLiteral.INSTANCE;
+ }
+ throw new CompilerException(new UnsupportedOperationException("Cannot transform to literal: " + value));
+ }
+
+ private static MapLiteral asMapLiteral(Map<String, Object> map) {
+ HashMap<String, ExpressionNode> literal = new HashMap<String, ExpressionNode>();
+ for (Map.Entry<String, Object> entry : map.entrySet()) {
+ literal.put(entry.getKey(), asLiteral(entry.getValue()));
+ }
+ return new MapLiteral(literal);
+ }
+
+ private static ArrayLiteral asArrayLiteral(List<Object> list) {
+ ArrayList<ExpressionNode> literal = new ArrayList<ExpressionNode>();
+ for (Object obj : list) {
+ literal.add(asLiteral(obj));
+ }
+ return new ArrayLiteral(literal);
+ }
+}
Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/reduce/ExpressionReducer.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/reduce/ExpressionReducer.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/reduce/ExpressionReducer.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/optimization/reduce/ExpressionReducer.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,248 @@
+/*******************************************************************************
+ * 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.optimization.reduce;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.sling.scripting.sightly.compiler.api.CompilerException;
+import org.apache.sling.scripting.sightly.compiler.api.expression.ExpressionNode;
+import org.apache.sling.scripting.sightly.compiler.api.expression.NodeVisitor;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.ArrayLiteral;
+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.MapLiteral;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.NullLiteral;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.NumericConstant;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.PropertyAccess;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.RuntimeCall;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.StringConstant;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.TernaryOperator;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.UnaryOperation;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.UnaryOperator;
+import org.apache.sling.scripting.sightly.compiler.util.VariableTracker;
+import org.apache.sling.scripting.sightly.common.Dynamic;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.UnaryOperation;
+
+/**
+ * Try to evaluate constant parts in expressions
+ */
+public class ExpressionReducer implements NodeVisitor<EvalResult> {
+
+ private final Dynamic dynamic;
+ private final VariableTracker<EvalResult> tracker;
+
+ public static EvalResult reduce(ExpressionNode node, VariableTracker<EvalResult> tracker, Dynamic dynamic) {
+ ExpressionReducer reducer = new ExpressionReducer(dynamic, tracker);
+ return reducer.eval(node);
+ }
+
+ public ExpressionReducer(Dynamic dynamic, VariableTracker<EvalResult> tracker) {
+ this.dynamic = dynamic;
+ this.tracker = tracker;
+ }
+
+ private EvalResult eval(ExpressionNode node) {
+ try {
+ return node.accept(this);
+ } catch (CompilerException e) {
+ throw e;
+ } catch (Exception e) {
+ //evaluating constant expressions may lead to errors (like division by zero)
+ //in this case we leave the node as-is.
+ return EvalResult.nonConstant(node);
+ }
+ }
+
+ @Override
+ public EvalResult evaluate(PropertyAccess propertyAccess) {
+ EvalResult target = eval(propertyAccess.getTarget());
+ EvalResult property = eval(propertyAccess.getProperty());
+ if (!target.isConstant() || !property.isConstant()) {
+ return EvalResult.nonConstant(new PropertyAccess(
+ target.getNode(),
+ property.getNode()));
+ }
+
+ return EvalResult.constant(dynamic.resolveProperty(
+ target.getValue(), property.getValue()));
+ }
+
+ @Override
+ public EvalResult evaluate(Identifier identifier) {
+ EvalResult result = tracker.get(identifier.getName());
+ if (result != null && result.isConstant()) {
+ return EvalResult.constant(result.getValue());
+ }
+ return EvalResult.nonConstant(identifier);
+ }
+
+ @Override
+ public EvalResult evaluate(StringConstant text) {
+ return EvalResult.constant(text.getText());
+ }
+
+ @Override
+ public EvalResult evaluate(BinaryOperation binaryOperation) {
+ EvalResult left = eval(binaryOperation.getLeftOperand());
+ EvalResult right = eval(binaryOperation.getRightOperand());
+ if (!(left.isConstant() && right.isConstant())) {
+ return EvalResult.nonConstant(new BinaryOperation(
+ binaryOperation.getOperator(),
+ left.getNode(),
+ right.getNode()));
+ }
+ return EvalResult.constant(evalBinary(
+ binaryOperation.getOperator(), left.getValue(), right.getValue()));
+ }
+
+ @Override
+ public EvalResult evaluate(BooleanConstant booleanConstant) {
+ return EvalResult.constant(booleanConstant.getValue());
+ }
+
+ @Override
+ public EvalResult evaluate(NumericConstant numericConstant) {
+ return EvalResult.constant(numericConstant.getValue());
+ }
+
+ @Override
+ public EvalResult evaluate(UnaryOperation unaryOperation) {
+ EvalResult target = eval(unaryOperation.getTarget());
+ if (!target.isConstant()) {
+ return EvalResult.nonConstant(new UnaryOperation(
+ unaryOperation.getOperator(), target.getNode()));
+ }
+ return EvalResult.constant(evalUnary(unaryOperation.getOperator(), target.getValue()));
+ }
+
+ @Override
+ public EvalResult evaluate(TernaryOperator ternaryOperator) {
+ EvalResult condition = eval(ternaryOperator.getCondition());
+ if (!condition.isConstant()) {
+ return EvalResult.nonConstant(new TernaryOperator(
+ condition.getNode(),
+ ternaryOperator.getThenBranch(),
+ ternaryOperator.getElseBranch()));
+ }
+ return (dynamic.coerceToBoolean(condition.getValue()))
+ ? eval(ternaryOperator.getThenBranch())
+ : eval(ternaryOperator.getElseBranch());
+ }
+
+ @Override
+ public EvalResult evaluate(RuntimeCall runtimeCall) {
+ List<ExpressionNode> nodes = new ArrayList<ExpressionNode>();
+ for (ExpressionNode node : runtimeCall.getArguments()) {
+ EvalResult result = eval(node);
+ nodes.add(result.getNode());
+ }
+ return EvalResult.nonConstant(new RuntimeCall(runtimeCall.getFunctionName(), nodes));
+ }
+
+ @Override
+ public EvalResult evaluate(MapLiteral mapLiteral) {
+ HashMap<String, EvalResult> results = new HashMap<String, EvalResult>();
+ boolean isConstant = true;
+ for (Map.Entry<String, ExpressionNode> entry : mapLiteral.getMap().entrySet()) {
+ EvalResult result = eval(entry.getValue());
+ results.put(entry.getKey(), result);
+ isConstant = isConstant && result.isConstant();
+ }
+ if (isConstant) {
+ HashMap<String, Object> map = new HashMap<String, Object>();
+ for (Map.Entry<String, EvalResult> entry : results.entrySet()) {
+ map.put(entry.getKey(), entry.getValue().getValue());
+ }
+ return EvalResult.constant(map);
+ } else {
+ HashMap<String, ExpressionNode> literal = new HashMap<String, ExpressionNode>();
+ for (Map.Entry<String, EvalResult> entry : results.entrySet()) {
+ literal.put(entry.getKey(), entry.getValue().getNode());
+ }
+ return EvalResult.nonConstant(new MapLiteral(literal));
+ }
+ }
+
+ @Override
+ public EvalResult evaluate(ArrayLiteral arrayLiteral) {
+ ArrayList<EvalResult> results = new ArrayList<EvalResult>();
+ boolean isConstant = true;
+ for (ExpressionNode node : arrayLiteral.getItems()) {
+ EvalResult result = eval(node);
+ results.add(result);
+ isConstant = isConstant && result.isConstant();
+ }
+ if (isConstant) {
+ ArrayList<Object> list = new ArrayList<Object>();
+ for (EvalResult result : results) {
+ list.add(result.getValue());
+ }
+ return EvalResult.constant(list);
+ } else {
+ ArrayList<ExpressionNode> literal = new ArrayList<ExpressionNode>();
+ for (EvalResult result : results) {
+ literal.add(result.getNode());
+ }
+ return EvalResult.nonConstant(new ArrayLiteral(literal));
+ }
+ }
+
+ @Override
+ public EvalResult evaluate(NullLiteral nullLiteral) {
+ return EvalResult.constant(null);
+ }
+
+ private Object evalBinary(BinaryOperator operator, Object left, Object right) {
+ switch (operator) {
+ case AND: return dynamic.and(left, right);
+ case OR: return dynamic.or(left, right);
+ case CONCATENATE: return dynamic.concatenate(left, right);
+ case LT: return dynamic.lt(left, right);
+ case LEQ: return dynamic.leq(left, right);
+ case GT: return dynamic.gt(left, right);
+ case GEQ: return dynamic.geq(left, right);
+ case EQ: return dynamic.eq(left, right);
+ case NEQ: return dynamic.neq(left, right);
+ case STRICT_EQ: return dynamic.strictEq(left, right);
+ case STRICT_NEQ: return dynamic.strictNeq(left, right);
+ case ADD: return dynamic.add(left, right);
+ case SUB: return dynamic.sub(left, right);
+ case MUL: return dynamic.mult(left, right);
+ case I_DIV: return dynamic.iDiv(left, right);
+ case REM: return dynamic.rem(left, right);
+ case DIV: return dynamic.div(left, right);
+ }
+ throw new CompilerException(new UnsupportedOperationException("Cannot reduce operator " + operator));
+ }
+
+ private Object evalUnary(UnaryOperator operator, Object operand) {
+ switch (operator) {
+ case IS_WHITESPACE: return dynamic.isWhiteSpace(operand);
+ case LENGTH: return dynamic.length(operand);
+ case NOT: return dynamic.not(operand);
+ }
+ throw new CompilerException(new UnsupportedOperationException("Cannot reduce unary operator " + operator));
+ }
+}
Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/util/GlobalShadowCheckBackend.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/util/GlobalShadowCheckBackend.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/util/GlobalShadowCheckBackend.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/util/GlobalShadowCheckBackend.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * 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.util;
+
+import java.util.Set;
+
+import org.apache.sling.scripting.sightly.compiler.CompilerBackend;
+import org.apache.sling.scripting.sightly.compiler.api.ris.CommandStream;
+import org.apache.sling.scripting.sightly.compiler.util.stream.VisitorHandler;
+
+/**
+ * Wrapping backend that checks for global bindings shadowing
+ */
+public class GlobalShadowCheckBackend implements CompilerBackend {
+
+ private final CompilerBackend baseBackend;
+ private final Set<String> globals;
+
+ public GlobalShadowCheckBackend(CompilerBackend baseBackend, Set<String> globals) {
+ this.baseBackend = baseBackend;
+ this.globals = globals;
+ }
+
+ @Override
+ public void handle(CommandStream stream) {
+ stream.addHandler(new VisitorHandler(new GlobalShadowChecker(globals)));
+ baseBackend.handle(stream);
+ }
+}
Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/util/GlobalShadowChecker.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/util/GlobalShadowChecker.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/util/GlobalShadowChecker.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/util/GlobalShadowChecker.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * 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.util;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+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.Loop;
+import org.apache.sling.scripting.sightly.compiler.api.ris.command.OutText;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+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;
+
+/**
+ * Checks whether variable declarations shadow global bindings
+ */
+public class GlobalShadowChecker implements CommandVisitor {
+
+ private static final Logger log = LoggerFactory.getLogger(GlobalShadowChecker.class);
+ private final Map<String, String> globals;
+
+ public GlobalShadowChecker(Set<String> globals) {
+ this.globals = new HashMap<String, String>();
+ for (String global : globals) {
+ this.globals.put(global.toLowerCase(), global);
+ }
+ }
+
+ @Override
+ public void visit(Conditional.Start conditionalStart) {
+ }
+
+ @Override
+ public void visit(Conditional.End conditionalEnd) {
+ }
+
+ @Override
+ public void visit(VariableBinding.Start variableBindingStart) {
+ checkVariable(variableBindingStart.getVariableName());
+ }
+
+ @Override
+ public void visit(VariableBinding.End variableBindingEnd) {
+
+ }
+
+ @Override
+ public void visit(VariableBinding.Global globalAssignment) {
+ checkVariable(globalAssignment.getVariableName());
+ }
+
+ @Override
+ public void visit(OutVariable outVariable) {
+
+ }
+
+ @Override
+ public void visit(OutText outText) {
+
+ }
+
+ @Override
+ public void visit(Loop.Start loopStart) {
+ checkVariable(loopStart.getItemVariable());
+ checkVariable(loopStart.getIndexVariable());
+ }
+
+ @Override
+ public void visit(Loop.End loopEnd) {
+ }
+
+ @Override
+ public void visit(BufferControl.Push bufferPush) {
+ }
+
+ @Override
+ public void visit(BufferControl.Pop bufferPop) {
+ }
+
+ @Override
+ public void visit(Procedure.Start startProcedure) {
+ checkVariable(startProcedure.getName());
+ }
+
+ @Override
+ public void visit(Procedure.End endProcedure) {
+ }
+
+ @Override
+ public void visit(Procedure.Call procedureCall) {
+ }
+
+ private void checkVariable(String variableName) {
+ variableName = variableName.toLowerCase();
+ if (globals.containsKey(variableName)) {
+ String originalName = globals.get(variableName);
+ log.warn("Global variable '{}' is being overridden in template", originalName);
+ }
+ }
+}
Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/util/SymbolGenerator.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/util/SymbolGenerator.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/util/SymbolGenerator.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/util/SymbolGenerator.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * 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.util;
+
+/**
+ * Created by mdanila on 12/4/13.
+ */
+public class SymbolGenerator {
+
+ public static final String DEFAULT_VAR_PREFIX = "var_";
+
+ private int counter = 0;
+ private final String prefix;
+
+ public SymbolGenerator() {
+ this(DEFAULT_VAR_PREFIX);
+ }
+
+ public SymbolGenerator(String prefix) {
+ this.prefix = prefix;
+ }
+
+ public String next(String hint) {
+ String middle = (hint != null) ? hint.replaceAll("\\-", "_") : "";
+ return prefix + middle + counter++;
+ }
+
+ public String next() {
+ return next(null);
+ }
+
+}
Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/util/VariableTracker.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/util/VariableTracker.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/util/VariableTracker.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/util/VariableTracker.java Fri Nov 14 14:04:56 2014
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ * 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.util;
+
+import java.util.AbstractMap;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+/**
+ * Track information related to Sightly variables
+ */
+public class VariableTracker<T> {
+
+ private final Map<String, Stack<T>> variableData = new HashMap<String, Stack<T>>();
+ private final Stack<String> declarationStack = new Stack<String>();
+
+ public boolean isDeclared(String name) {
+ name = name.toLowerCase();
+ Stack<T> dataStack = variableData.get(name);
+ return dataStack != null;
+ }
+
+ /**
+ * Push a variable. Use this at a variable declaration
+ * @param name - the name of the variable
+ * @param data - data associated with the variable
+ */
+ public void pushVariable(String name, T data) {
+ name = name.toLowerCase();
+ Stack<T> dataStack = variableData.get(name);
+ if (dataStack == null) {
+ dataStack = new Stack<T>();
+ variableData.put(name, dataStack);
+ }
+ dataStack.push(data);
+ declarationStack.push(name);
+ }
+
+ /**
+ * Pop a variable. Use this when a variable goes out of scope
+ * @return - the name of the popped variable
+ * @throws java.util.NoSuchElementException - if there are no declared variables in the scope
+ */
+ public String popVariable() {
+ String variable = declarationStack.pop();
+ Stack<T> dataStack = variableData.get(variable);
+ assert dataStack != null;
+ dataStack.pop();
+ if (dataStack.isEmpty()) {
+ variableData.remove(variable);
+ }
+ return variable;
+ }
+
+ /**
+ * Peek at the top of the declaration stack
+ * @return - the most recently declared variable and it's associated data
+ * @throws java.util.NoSuchElementException - if there are no variables in scope
+ */
+ public Map.Entry<String, T> peek() {
+ String variable = declarationStack.peek();
+ Stack<T> dataStack = variableData.get(variable);
+ assert dataStack != null;
+ T data = dataStack.peek();
+ return new AbstractMap.SimpleImmutableEntry<String, T>(variable, data);
+ }
+
+ public boolean isEmpty() {
+ return declarationStack.isEmpty();
+ }
+
+ /**
+ * Get the data associated with the given variable
+ * @param name - the name of the variable
+ * @return the associated data or null if that variable is not in scope
+ */
+ public T get(String name) {
+ name = name.toLowerCase();
+ Stack<T> dataStack = variableData.get(name);
+ if (dataStack == null) {
+ return null;
+ }
+ assert !dataStack.isEmpty();
+ return dataStack.peek();
+ }
+
+ /**
+ * Check whether a variable was declared and is visible in the current scope
+ * @param name - the name of the variable
+ * @return - the visibility of the variable in the current scope
+ */
+ public boolean isInScope(String name) {
+ name = name.toLowerCase();
+ return variableData.get(name) != null;
+ }
+
+ /**
+ * Get an immutable view of all the data items associated with the specified
+ * variable.
+ * @param name - the name of the variable
+ * @return - a list of all the data associated with this variable name. If the
+ * variable is not declared in the current scope then that list will be empty. Otherwise
+ * it will contain all the data associated for the current scope starting with the data
+ * associated at the topmost scope and ending with the most recently associated data
+ */
+ public List<T> getAll(String name) {
+ name = name.toLowerCase();
+ Stack<T> dataStack = variableData.get(name);
+ if (dataStack == null) {
+ return Collections.emptyList();
+ }
+ return Collections.unmodifiableList(dataStack);
+ }
+
+ /**
+ * Get how many times a variable was declared in the current scope
+ * @param name - the name of the variable
+ * @return - the number of declarations for a variable in the current scope
+ */
+ public int getOccurrenceCount(String name) {
+ name = name.toLowerCase();
+ Stack<T> dataStack = variableData.get(name);
+ if (dataStack == null) {
+ return 0;
+ }
+ return dataStack.size();
+ }
+
+}
Added: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/util/expression/HomogenousNodeVisitor.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/util/expression/HomogenousNodeVisitor.java?rev=1639641&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/util/expression/HomogenousNodeVisitor.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/compiler/util/expression/HomogenousNodeVisitor.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.util.expression;
+
+import org.apache.sling.scripting.sightly.compiler.api.expression.ExpressionNode;
+import org.apache.sling.scripting.sightly.compiler.api.expression.NodeVisitor;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.ArrayLiteral;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.BinaryOperation;
+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.MapLiteral;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.NullLiteral;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.NumericConstant;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.PropertyAccess;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.RuntimeCall;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.StringConstant;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.TernaryOperator;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.UnaryOperation;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.NumericConstant;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.StringConstant;
+import org.apache.sling.scripting.sightly.compiler.api.expression.node.UnaryOperation;
+
+/**
+ * Apply the same evaluation for all expression nodes
+ */
+public abstract class HomogenousNodeVisitor<T> implements NodeVisitor<T> {
+
+ protected abstract T evaluateDefault(ExpressionNode node);
+
+ @Override
+ public T evaluate(PropertyAccess propertyAccess) {
+ return evaluateDefault(propertyAccess);
+ }
+
+ @Override
+ public T evaluate(Identifier identifier) {
+ return evaluateDefault(identifier);
+ }
+
+ @Override
+ public T evaluate(StringConstant text) {
+ return evaluateDefault(text);
+ }
+
+ @Override
+ public T evaluate(BinaryOperation binaryOperation) {
+ return evaluateDefault(binaryOperation);
+ }
+
+ @Override
+ public T evaluate(BooleanConstant booleanConstant) {
+ return evaluateDefault(booleanConstant);
+ }
+
+ @Override
+ public T evaluate(NumericConstant numericConstant) {
+ return evaluateDefault(numericConstant);
+ }
+
+ @Override
+ public T evaluate(UnaryOperation unaryOperation) {
+ return evaluateDefault(unaryOperation);
+ }
+
+ @Override
+ public T evaluate(TernaryOperator ternaryOperator) {
+ return evaluateDefault(ternaryOperator);
+ }
+
+ @Override
+ public T evaluate(RuntimeCall runtimeCall) {
+ return evaluateDefault(runtimeCall);
+ }
+
+ @Override
+ public T evaluate(MapLiteral mapLiteral) {
+ return evaluateDefault(mapLiteral);
+ }
+
+ @Override
+ public T evaluate(ArrayLiteral arrayLiteral) {
+ return evaluateDefault(arrayLiteral);
+ }
+
+ @Override
+ public T evaluate(NullLiteral nullLiteral) {
+ return evaluateDefault(nullLiteral);
+ }
+}