You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by he...@apache.org on 2015/08/27 21:57:16 UTC
svn commit: r1698221 - in
/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3:
internal/Debugger.java internal/Engine.java internal/Scope.java
parser/ASTJxltLiteral.java parser/Parser.jjt parser/ParserVisitor.java
Author: henrib
Date: Thu Aug 27 19:57:16 2015
New Revision: 1698221
URL: http://svn.apache.org/r1698221
Log:
JEXL:
Implemented JEXL-177; multiline formats use backquote (`) as delimiter and interpolate ${...} expressions
Added:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJxltLiteral.java (with props)
Modified:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Engine.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Scope.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ParserVisitor.java
Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java?rev=1698221&r1=1698220&r2=1698221&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java Thu Aug 27 19:57:16 2015
@@ -51,6 +51,7 @@ import org.apache.commons.jexl3.parser.A
import org.apache.commons.jexl3.parser.ASTIfStatement;
import org.apache.commons.jexl3.parser.ASTJexlLambda;
import org.apache.commons.jexl3.parser.ASTJexlScript;
+import org.apache.commons.jexl3.parser.ASTJxltLiteral;
import org.apache.commons.jexl3.parser.ASTLENode;
import org.apache.commons.jexl3.parser.ASTLTNode;
import org.apache.commons.jexl3.parser.ASTMapEntry;
@@ -98,23 +99,23 @@ import java.util.regex.Pattern;
* Helps pinpoint the cause of problems in expressions that fail during evaluation.
* <p>
* It rebuilds an expression string from the tree and the start/end offsets of the cause in that string.
- * This implies that exceptions during evaluation do allways carry the node that's causing the error.
+ * This implies that exceptions during evaluation do always carry the node that's causing the error.
* </p>
* @since 2.0
*/
-public final class Debugger extends ParserVisitor implements JexlInfo.Detail {
+public class Debugger extends ParserVisitor implements JexlInfo.Detail {
/** The builder to compose messages. */
- private final StringBuilder builder = new StringBuilder();
+ protected final StringBuilder builder = new StringBuilder();
/** The cause of the issue to debug. */
- private JexlNode cause = null;
+ protected JexlNode cause = null;
/** The starting character location offset of the cause in the builder. */
- private int start = 0;
+ protected int start = 0;
/** The ending character location offset of the cause in the builder. */
- private int end = 0;
+ protected int end = 0;
/** The indentation level. */
- private int indentLevel = 0;
+ protected int indentLevel = 0;
/** Perform indentation?. */
- private boolean indent = true;
+ protected int indent = 2;
/**
* Creates a Debugger.
@@ -167,18 +168,17 @@ public final class Debugger extends Pars
start = 0;
end = 0;
indentLevel = 0;
- indent = true;
if (node != null) {
builder.setLength(0);
cause = node;
// make arg cause become the root cause
- JexlNode root = node;
+ JexlNode walk = node;
if (r) {
- while (root.jjtGetParent() != null) {
- root = root.jjtGetParent();
+ while (walk.jjtGetParent() != null) {
+ walk = walk.jjtGetParent();
}
}
- root.jjtAccept(this, null);
+ accept(walk, null);
}
return end > 0;
}
@@ -201,11 +201,10 @@ public final class Debugger extends Pars
start = 0;
end = 0;
indentLevel = 0;
- indent = true;
if (node != null) {
builder.setLength(0);
- this.cause = node;
- node.jjtAccept(this, null);
+ cause = node;
+ accept(node, null);
}
return builder.toString();
}
@@ -227,12 +226,25 @@ public final class Debugger extends Pars
}
/**
+ * Sets the indentation level.
+ * @param level the number of spaces for indentation, none if less or equal to zero
+ */
+ public void setIndentation(int level) {
+ if (level <= 0) {
+ indent = 0;
+ } else {
+ indent = level;
+ }
+ indentLevel = 0;
+ }
+
+ /**
* Checks if a child node is the cause to debug & adds its representation to the rebuilt expression.
* @param node the child node
* @param data visitor pattern argument
* @return visitor pattern value
*/
- private Object accept(JexlNode node, Object data) {
+ protected Object accept(JexlNode node, Object data) {
if (node == cause) {
start = builder.length();
}
@@ -249,22 +261,25 @@ public final class Debugger extends Pars
* @param data visitor pattern argument
* @return visitor pattern value
*/
- private Object acceptStatement(JexlNode child, Object data) {
- if (indent) {
+ protected Object acceptStatement(JexlNode child, Object data) {
+ JexlNode parent = child.jjtGetParent();
+ if (indent > 0 && (parent instanceof ASTBlock || parent instanceof ASTJexlScript)) {
for (int i = 0; i < indentLevel; ++i) {
- builder.append(" ");
+ for(int s = 0; s < indent; ++s) {
+ builder.append(' ');
+ }
}
}
Object value = accept(child, data);
// blocks, if, for & while dont need a ';' at end
if (!(child instanceof ASTJexlScript
- || child instanceof ASTBlock
- || child instanceof ASTIfStatement
- || child instanceof ASTForeachStatement
- || child instanceof ASTWhileStatement)) {
- builder.append(";");
- if (indent) {
- builder.append("\n");
+ || child instanceof ASTBlock
+ || child instanceof ASTIfStatement
+ || child instanceof ASTForeachStatement
+ || child instanceof ASTWhileStatement)) {
+ builder.append(';');
+ if (indent > 0) {
+ builder.append('\n');
} else {
builder.append(' ');
}
@@ -279,7 +294,7 @@ public final class Debugger extends Pars
* @param data visitor pattern argument
* @return visitor pattern value
*/
- private Object check(JexlNode node, String image, Object data) {
+ protected Object check(JexlNode node, String image, Object data) {
if (node == cause) {
start = builder.length();
}
@@ -303,10 +318,10 @@ public final class Debugger extends Pars
* @param data visitor pattern argument
* @return visitor pattern value
*/
- private Object infixChildren(JexlNode node, String infix, boolean paren, Object data) {
+ protected Object infixChildren(JexlNode node, String infix, boolean paren, Object data) {
int num = node.jjtGetNumChildren(); //child.jjtGetNumChildren() > 1;
if (paren) {
- builder.append("(");
+ builder.append('(');
}
for (int i = 0; i < num; ++i) {
if (i > 0) {
@@ -315,7 +330,7 @@ public final class Debugger extends Pars
accept(node.jjtGetChild(i), data);
}
if (paren) {
- builder.append(")");
+ builder.append(')');
}
return data;
}
@@ -328,15 +343,15 @@ public final class Debugger extends Pars
* @param data visitor pattern argument
* @return visitor pattern value
*/
- private Object prefixChild(JexlNode node, String prefix, Object data) {
+ protected Object prefixChild(JexlNode node, String prefix, Object data) {
boolean paren = node.jjtGetChild(0).jjtGetNumChildren() > 1;
builder.append(prefix);
if (paren) {
- builder.append("(");
+ builder.append('(');
}
accept(node.jjtGetChild(0), data);
if (paren) {
- builder.append(")");
+ builder.append(')');
}
return data;
}
@@ -358,14 +373,14 @@ public final class Debugger extends Pars
* @param data visitor pattern argument
* @return visitor pattern value
*/
- private Object additiveNode(JexlNode node, String op, Object data) {
+ protected Object additiveNode(JexlNode node, String op, Object data) {
// need parenthesis if not in operator precedence order
boolean paren = node.jjtGetParent() instanceof ASTMulNode
|| node.jjtGetParent() instanceof ASTDivNode
|| node.jjtGetParent() instanceof ASTModNode;
int num = node.jjtGetNumChildren();
if (paren) {
- builder.append("(");
+ builder.append('(');
}
accept(node.jjtGetChild(0), data);
for (int i = 1; i < num; ++i) {
@@ -373,7 +388,7 @@ public final class Debugger extends Pars
accept(node.jjtGetChild(i), data);
}
if (paren) {
- builder.append(")");
+ builder.append(')');
}
return data;
}
@@ -387,9 +402,9 @@ public final class Debugger extends Pars
protected Object visit(ASTArrayAccess node, Object data) {
int num = node.jjtGetNumChildren();
for (int i = 0; i < num; ++i) {
- builder.append("[");
+ builder.append('[');
accept(node.jjtGetChild(i), data);
- builder.append("]");
+ builder.append(']');
}
return data;
}
@@ -449,20 +464,27 @@ public final class Debugger extends Pars
@Override
protected Object visit(ASTBlock node, Object data) {
- builder.append("{");
- if (indent) {
- builder.append("\n");
+ builder.append('{');
+ if (indent > 0) {
+ indentLevel += 1;
+ builder.append('\n');
} else {
builder.append(' ');
}
- indentLevel += 1;
int num = node.jjtGetNumChildren();
for (int i = 0; i < num; ++i) {
JexlNode child = node.jjtGetChild(i);
acceptStatement(child, data);
}
- indentLevel -= 1;
- builder.append("}");
+ if (indent > 0) {
+ indentLevel -= 1;
+ for (int i = 0; i < indentLevel; ++i) {
+ for(int s = 0; s < indent; ++s) {
+ builder.append(' ');
+ }
+ }
+ }
+ builder.append('}');
return data;
}
@@ -555,9 +577,9 @@ public final class Debugger extends Pars
return infixChildren(node, " > ", false, data);
}
/** Checks identifiers that contain space, quote, double-quotes or backspace. */
- private static final Pattern QUOTED_IDENTIFIER = Pattern.compile("['\"\\s\\\\]");
+ protected static final Pattern QUOTED_IDENTIFIER = Pattern.compile("['\"\\s\\\\]");
/** Checks number used as identifiers. */
- private static final Pattern NUMBER_IDENTIFIER = Pattern.compile("^\\d*$");
+ protected static final Pattern NUMBER_IDENTIFIER = Pattern.compile("^\\d*$");
@Override
protected Object visit(ASTIdentifier node, Object data) {
@@ -603,9 +625,19 @@ public final class Debugger extends Pars
return check(node, node.toString(), data);
}
+ /**
+ * A pseudo visitor for parameters.
+ * @param p the parameter name
+ * @param data the visitor argument
+ * @return the parameter name to use
+ */
+ protected String visitParameter(String p, Object data) {
+ return p;
+ }
+
@Override
protected Object visit(ASTJexlScript node, Object data) {
- boolean ii = true;
+ // if lambda, produce parameters
if (node instanceof ASTJexlLambda) {
JexlNode parent = node.jjtGetParent();
// use lambda syntax if not assigned
@@ -616,10 +648,10 @@ public final class Debugger extends Pars
builder.append('(');
String[] params = node.getParameters();
if (params != null && params.length > 0) {
- builder.append(params[0]);
+ builder.append(visitParameter(params[0], data));
for (int p = 1; p < params.length; ++p) {
builder.append(", ");
- builder.append(params[p]);
+ builder.append(visitParameter(params[p], data));
}
}
builder.append(')');
@@ -627,12 +659,10 @@ public final class Debugger extends Pars
builder.append(' ');
} else {
builder.append("->");
- ii = false;
}
+ // we will need a block...
}
- if (!ii) {
- indent = false;
- }
+ // no parameters or done with them
int num = node.jjtGetNumChildren();
if (num == 1 && !(node instanceof ASTJexlLambda)) {
data = accept(node.jjtGetChild(0), data);
@@ -642,9 +672,6 @@ public final class Debugger extends Pars
acceptStatement(child, data);
}
}
- if (!ii) {
- indent = true;
- }
return data;
}
@@ -672,11 +699,11 @@ public final class Debugger extends Pars
builder.append("{ ");
if (num > 0) {
accept(node.jjtGetChild(0), data);
- for (int i = 1; i < num; ++i) {
- builder.append(",");
- accept(node.jjtGetChild(i), data);
- }
+ for (int i = 1; i < num; ++i) {
+ builder.append(",");
+ accept(node.jjtGetChild(i), data);
}
+ }
builder.append(" }");
return data;
}
@@ -701,8 +728,7 @@ public final class Debugger extends Pars
@Override
protected Object visit(ASTConstructorNode node, Object data) {
int num = node.jjtGetNumChildren();
- builder.append("new ");
- builder.append("(");
+ builder.append("new(");
accept(node.jjtGetChild(0), data);
for (int i = 1; i < num; ++i) {
builder.append(", ");
@@ -929,4 +955,10 @@ public final class Debugger extends Pars
protected Object visit(ASTSetXorNode node, Object data) {
return infixChildren(node, " ^= ", false, data);
}
+
+ @Override
+ protected Object visit(ASTJxltLiteral node, Object data) {
+ String img = node.getLiteral().replace("`", "\\`");
+ return check(node, "`" + img + "`", data);
+ }
}
\ No newline at end of file
Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Engine.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Engine.java?rev=1698221&r1=1698220&r2=1698221&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Engine.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Engine.java Thu Aug 27 19:57:16 2015
@@ -71,8 +71,7 @@ public class Engine extends JexlEngine {
new Uberspect(LogManager.getLogger(JexlEngine.class), JexlUberspect.JEXL_STRATEGY);
/** Non-instantiable. */
- private UberspectHolder() {
- }
+ private UberspectHolder() {}
}
/**
* The JexlUberspect instance.
@@ -120,6 +119,10 @@ public class Engine extends JexlEngine {
*/
protected final Charset charset;
/**
+ * The default jxlt engine.
+ */
+ protected volatile TemplateEngine jxlt = null;
+ /**
* The default cache load factor.
*/
private static final float LOAD_FACTOR = 0.75f;
@@ -149,9 +152,9 @@ public class Engine extends JexlEngine {
}
this.logger = conf.logger() == null ? LogManager.getLogger(JexlEngine.class) : conf.logger();
this.functions = conf.namespaces() == null ? Collections.<String, Object>emptyMap() : conf.namespaces();
- this.silent = conf.silent() == null ? false : conf.silent().booleanValue();
- this.debug = conf.debug() == null ? true : conf.debug().booleanValue();
- this.strict = conf.strict() == null ? true : conf.strict().booleanValue();
+ this.silent = conf.silent() == null ? false : conf.silent();
+ this.debug = conf.debug() == null ? true : conf.debug();
+ this.strict = conf.strict() == null ? true : conf.strict();
this.arithmetic = conf.arithmetic() == null ? new JexlArithmetic(this.strict) : conf.arithmetic();
this.cache = conf.cache() <= 0 ? null : new SoftCache<String, ASTJexlScript>(conf.cache());
this.cacheThreshold = conf.cacheThreshold();
@@ -710,4 +713,21 @@ public class Engine extends JexlEngine {
}
return null;
}
+
+ /**
+ * Gets and/or creates a default template engine.
+ * @return a template engine
+ */
+ protected TemplateEngine jxlt() {
+ TemplateEngine e = jxlt;
+ if (e == null) {
+ synchronized(this) {
+ if (jxlt == null) {
+ e = new TemplateEngine(this, true, 0, '$', '#');
+ jxlt = e;
+ }
+ }
+ }
+ return e;
+ }
}
Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Scope.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Scope.java?rev=1698221&r1=1698220&r2=1698221&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Scope.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Scope.java Thu Aug 27 19:57:16 2015
@@ -74,24 +74,20 @@ public final class Scope {
@Override
public boolean equals(Object o) {
- return o instanceof Scope && equals((Scope) o);
- }
-
- /**
- * Whether this frame is equal to another.
- * @param frame the frame to compare to
- * @return true if equal, false otherwise
- */
- public boolean equals(Scope frame) {
- if (this == frame) {
+ if (this == o) {
return true;
- } else if (frame == null || parms != frame.parms) {
+ }
+ if (!(o instanceof Scope)) {
return false;
- } else if (namedVariables == null) {
- return frame.namedVariables == null;
- } else {
- return namedVariables.equals(frame.namedVariables);
}
+ Scope scope = (Scope) o;
+ if (parms != scope.parms) {
+ return false;
+ }
+ if (namedVariables == null) {
+ return scope.namedVariables == null;
+ }
+ return namedVariables.equals(scope.namedVariables);
}
/**
@@ -197,7 +193,7 @@ public final class Scope {
arguments[target.intValue()] = arg;
}
}
- return new Frame(arguments);
+ return new Frame(this, arguments);
} else {
return null;
}
@@ -280,17 +276,29 @@ public final class Scope {
* @since 3.0
*/
public static final class Frame {
+ /** The scope. */
+ private final Scope scope;
/** The actual stack frame. */
private final Object[] stack;
/**
* Creates a new frame.
+ * @param s the scope
* @param r the stack frame
*/
- public Frame(Object[] r) {
+ public Frame(Scope s, Object[] r) {
+ scope = s;
stack = r;
}
+ /**
+ * Gets the scope.
+ * @return this frame scope
+ */
+ public Scope getScope() {
+ return scope;
+ }
+
@Override
public int hashCode() {
return Arrays.deepHashCode(this.stack);
@@ -335,7 +343,7 @@ public final class Scope {
if (stack != null && values != null && values.length > 0) {
Object[] copy = stack.clone();
System.arraycopy(values, 0, copy, 0, Math.min(copy.length, values.length));
- return new Frame(copy);
+ return new Frame(scope, copy);
}
return this;
}
Added: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJxltLiteral.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJxltLiteral.java?rev=1698221&view=auto
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJxltLiteral.java (added)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJxltLiteral.java Thu Aug 27 19:57:16 2015
@@ -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.commons.jexl3.parser;
+
+public final class ASTJxltLiteral extends JexlNode {
+ /** The actual literal value; the inherited 'value' member may host a cached template expression. */
+ private String literal = null;
+
+ ASTJxltLiteral(int id) {
+ super(id);
+ }
+
+ ASTJxltLiteral(Parser p, int id) {
+ super(p, id);
+ }
+
+ void setLiteral(String literal) {
+ this.literal = literal;
+ }
+
+ /**
+ * Gets the literal value.
+ * @return the string literal
+ */
+ public String getLiteral() {
+ return this.literal;
+ }
+
+ @Override
+ public String toString() {
+ return this.literal;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Object jjtAccept(ParserVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+}
Propchange: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJxltLiteral.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt?rev=1698221&r1=1698220&r2=1698221&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt Thu Aug 27 19:57:16 2015
@@ -228,6 +228,13 @@ PARSER_END(Parser)
>
}
+<*> TOKEN :
+{
+ < JXLT_LITERAL:
+ "`" (~["`","\\"] | "\\" ~["\u0000"])* "`"
+ >
+}
+
/***************************************
* Statements
***************************************/
@@ -560,6 +567,8 @@ void Literal() #void :
|
BooleanLiteral()
|
+ JxltLiteral()
+|
StringLiteral()
|
NullLiteral()
@@ -614,6 +623,16 @@ void StringLiteral() :
{ jjtThis.setLiteral(Parser.buildString(t.image, true)); }
}
+
+void JxltLiteral() #JxltLiteral :
+{
+ Token t;
+}
+{
+ t=<JXLT_LITERAL>
+ { jjtThis.setLiteral(Parser.buildString(t.image, true)); }
+}
+
void ExtendedLiteral() #ExtendedLiteral() : {}
{
<ELIPSIS>
Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ParserVisitor.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ParserVisitor.java?rev=1698221&r1=1698220&r2=1698221&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ParserVisitor.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ParserVisitor.java Thu Aug 27 19:57:16 2015
@@ -175,4 +175,6 @@ public abstract class ParserVisitor {
protected abstract Object visit(ASTSetOrNode node, Object data);
protected abstract Object visit(ASTSetXorNode node, Object data);
+
+ protected abstract Object visit(ASTJxltLiteral node, Object data);
}