Author: henrib
Date: Tue Jul 31 14:30:43 2012
New Revision: 1367576
URL: http://svn.apache.org/viewvc?rev=1367576&view=rev
Log:
JEXL-133:
Added 'not startsWith' (^!) and 'not endsWith' (!$) operators
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/Interpreter.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/JexlParser.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
commons/proper/jexl/trunk/src/site/xdoc/changes.xml
commons/proper/jexl/trunk/src/site/xdoc/reference/syntax.xml
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticOperatorTest.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=1367576&r1=1367575&r2=1367576&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
Tue Jul 31 14:30:43 2012
@@ -77,6 +77,8 @@ import org.apache.commons.jexl3.parser.J
import org.apache.commons.jexl3.parser.ParserVisitor;
import java.util.regex.Pattern;
+import org.apache.commons.jexl3.parser.ASTNEWNode;
+import org.apache.commons.jexl3.parser.ASTNSWNode;
/**
* Helps pinpoint the cause of problems in expressions that fail during
evaluation.
@@ -470,6 +472,16 @@ public final class Debugger extends Pars
}
@Override
+ protected Object visit(ASTNSWNode node, Object data) {
+ return infixChildren(node, " !^ ", false, data);
+ }
+
+ @Override
+ protected Object visit(ASTNEWNode node, Object data) {
+ return infixChildren(node, " !$ ", false, data);
+ }
+
+ @Override
protected Object visit(ASTFalseNode node, Object data) {
return check(node, "false", data);
}
Modified:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java?rev=1367576&r1=1367575&r2=1367576&view=diff
==============================================================================
---
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
(original)
+++
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
Tue Jul 31 14:30:43 2012
@@ -16,6 +16,7 @@
*/
package org.apache.commons.jexl3.internal;
+
import org.apache.commons.jexl3.JexlArithmetic;
import org.apache.commons.jexl3.JexlContext;
import org.apache.commons.jexl3.JexlEngine;
@@ -61,20 +62,22 @@ import org.apache.commons.jexl3.parser.A
import org.apache.commons.jexl3.parser.ASTModNode;
import org.apache.commons.jexl3.parser.ASTMulNode;
import org.apache.commons.jexl3.parser.ASTNENode;
+import org.apache.commons.jexl3.parser.ASTNEWNode;
import org.apache.commons.jexl3.parser.ASTNRNode;
+import org.apache.commons.jexl3.parser.ASTNSWNode;
import org.apache.commons.jexl3.parser.ASTNotNode;
import org.apache.commons.jexl3.parser.ASTNullLiteral;
import org.apache.commons.jexl3.parser.ASTNumberLiteral;
import org.apache.commons.jexl3.parser.ASTOrNode;
+import org.apache.commons.jexl3.parser.ASTRangeNode;
import org.apache.commons.jexl3.parser.ASTReference;
import org.apache.commons.jexl3.parser.ASTReferenceExpression;
import org.apache.commons.jexl3.parser.ASTReturnStatement;
+import org.apache.commons.jexl3.parser.ASTSWNode;
import org.apache.commons.jexl3.parser.ASTSizeFunction;
import org.apache.commons.jexl3.parser.ASTSizeMethod;
import org.apache.commons.jexl3.parser.ASTStringLiteral;
import org.apache.commons.jexl3.parser.ASTSubNode;
-import org.apache.commons.jexl3.parser.ASTSWNode;
-import org.apache.commons.jexl3.parser.ASTRangeNode;
import org.apache.commons.jexl3.parser.ASTTernaryNode;
import org.apache.commons.jexl3.parser.ASTTrueNode;
import org.apache.commons.jexl3.parser.ASTUnaryMinusNode;
@@ -502,10 +505,15 @@ public class Interpreter extends ParserV
}
}
- @Override
- protected Object visit(ASTSWNode node, Object data) {
- Object left = node.jjtGetChild(0).jjtAccept(this, data);
- Object right = node.jjtGetChild(1).jjtAccept(this, data);
+ /**
+ * The 'startsWith' operator implementation.
+ * @param node the node
+ * @param operator the calling operator, $= or $!
+ * @param left the left operand
+ * @param right the right operand
+ * @return true if left starts with right, false otherwise
+ */
+ protected boolean startsWith(JexlNode node, String operator, Object left,
Object right) {
try {
if (left == null || right == null) {
return false;
@@ -526,22 +534,41 @@ public class Interpreter extends ParserV
}
}
} catch (InvocationTargetException e) {
- throw new JexlException(node, "=^ invocation error",
e.getCause());
+ throw new JexlException(node, operator + " invocation
error", e.getCause());
} catch (Exception e) {
- throw new JexlException(node, "=^ error", e);
+ throw new JexlException(node, operator + " error", e);
}
}
// defaults to equal
return arithmetic.equals(left, right) ? Boolean.TRUE :
Boolean.FALSE;
} catch (ArithmeticException xrt) {
- throw new JexlException(node, "=^ error", xrt);
+ throw new JexlException(node, operator + " error", xrt);
}
}
@Override
- protected Object visit(ASTEWNode node, Object data) {
+ protected Object visit(ASTSWNode node, Object data) {
+ Object left = node.jjtGetChild(0).jjtAccept(this, data);
+ Object right = node.jjtGetChild(1).jjtAccept(this, data);
+ return startsWith(node, "^=", left, right)? Boolean.TRUE :
Boolean.FALSE;
+ }
+
+ @Override
+ protected Object visit(ASTNSWNode node, Object data) {
Object left = node.jjtGetChild(0).jjtAccept(this, data);
Object right = node.jjtGetChild(1).jjtAccept(this, data);
+ return startsWith(node, "^!", left, right)? Boolean.FALSE :
Boolean.TRUE;
+ }
+
+ /**
+ * The 'endsWith' operator implementation.
+ * @param node the node
+ * @param operator the calling operator, ^= or ^!
+ * @param left the left operand
+ * @param right the right operand
+ * @return true if left ends with right, false otherwise
+ */
+ protected boolean endsWith(JexlNode node, String operator, Object left,
Object right) {
try {
if (left == null || right == null) {
return false;
@@ -562,59 +589,73 @@ public class Interpreter extends ParserV
}
}
} catch (InvocationTargetException e) {
- throw new JexlException(node, "=$ invocation error",
e.getCause());
+ throw new JexlException(node, operator + " invocation
error", e.getCause());
} catch (Exception e) {
- throw new JexlException(node, "=$ error", e);
+ throw new JexlException(node, operator + " error", e);
}
// defaults to equal
return arithmetic.equals(left, right) ? Boolean.TRUE :
Boolean.FALSE;
}
} catch (ArithmeticException xrt) {
- throw new JexlException(node, "=$ error", xrt);
+ throw new JexlException(node, operator + " error", xrt);
}
}
+ @Override
+ protected Object visit(ASTEWNode node, Object data) {
+ Object left = node.jjtGetChild(0).jjtAccept(this, data);
+ Object right = node.jjtGetChild(1).jjtAccept(this, data);
+ return endsWith(node, "$=", left, right) ? Boolean.TRUE :
Boolean.FALSE;
+ }
+
+ @Override
+ protected Object visit(ASTNEWNode node, Object data) {
+ Object left = node.jjtGetChild(0).jjtAccept(this, data);
+ Object right = node.jjtGetChild(1).jjtAccept(this, data);
+ return endsWith(node, "$!", left, right) ? Boolean.FALSE :
Boolean.TRUE;
+ }
+
/**
* The 'match'/'in' operator implementation.
- * @param node the node
- * @param op the calling operator, =~ or !=
- * @param left the left operand
+ * @param node the node
+ * @param op the calling operator, =~ or !=
+ * @param left the left operand
* @param right the right operand
* @return true if left matches right, false otherwise
*/
- protected Object matches(JexlNode node, String op, Object left, Object
right) {
+ protected boolean matches(JexlNode node, String op, Object left, Object
right) {
try {
// use arithmetic / pattern matching ?
if (right instanceof java.util.regex.Pattern || right instanceof
String) {
- return arithmetic.matches(left, right) ? Boolean.TRUE :
Boolean.FALSE;
+ return arithmetic.matches(left, right);
}
// left in right ? <=> right.contains(left) ?
// try contains on collection
if (right instanceof Set<?>) {
- return ((Set<?>) right).contains(left) ? Boolean.TRUE :
Boolean.FALSE;
+ return ((Set<?>) right).contains(left);
}
// try contains on map key
if (right instanceof Map<?, ?>) {
- return ((Map<?, ?>) right).containsKey(left) ? Boolean.TRUE :
Boolean.FALSE;
+ return ((Map<?, ?>) right).containsKey(left);
}
// try contains on collection
if (right instanceof Collection<?>) {
- return ((Collection<?>) right).contains(left) ? Boolean.TRUE :
Boolean.FALSE;
+ return ((Collection<?>) right).contains(left);
}
// try a contains method (duck type set)
try {
Object[] argv = {left};
JexlMethod vm = uberspect.getMethod(right, "contains", argv);
if (vm != null) {
- return arithmetic.toBoolean(vm.invoke(right, argv)) ?
Boolean.TRUE : Boolean.FALSE;
+ return arithmetic.toBoolean(vm.invoke(right, argv));
} else if (arithmetic.narrowArguments(argv)) {
vm = uberspect.getMethod(right, "contains", argv);
if (vm != null) {
- return arithmetic.toBoolean(vm.invoke(right, argv)) ?
Boolean.TRUE : Boolean.FALSE;
+ return arithmetic.toBoolean(vm.invoke(right, argv));
}
}
} catch (InvocationTargetException e) {
- throw new JexlException(node, op +" invocation error",
e.getCause());
+ throw new JexlException(node, op + " invocation error",
e.getCause());
} catch (Exception e) {
throw new JexlException(node, op + " error", e);
}
@@ -627,10 +668,10 @@ public class Interpreter extends ParserV
return Boolean.TRUE;
}
}
- return Boolean.FALSE;
+ return false;
}
// defaults to equal
- return arithmetic.equals(left, right) ? Boolean.TRUE :
Boolean.FALSE;
+ return arithmetic.equals(left, right);
} catch (ArithmeticException xrt) {
throw new JexlException(node, op + " error", xrt);
}
@@ -640,15 +681,14 @@ public class Interpreter extends ParserV
protected Object visit(ASTERNode node, Object data) {
Object left = node.jjtGetChild(0).jjtAccept(this, data);
Object right = node.jjtGetChild(1).jjtAccept(this, data);
- return matches(node, "=~", left, right);
+ return matches(node, "=~", left, right) ? Boolean.TRUE : Boolean.FALSE;
}
@Override
protected Object visit(ASTNRNode node, Object data) {
Object left = node.jjtGetChild(0).jjtAccept(this, data);
Object right = node.jjtGetChild(1).jjtAccept(this, data);
- Object result = matches(node, "!~", left, right);
- return arithmetic.toBoolean(result) ? Boolean.FALSE : Boolean.TRUE;
+ return matches(node, "!~", left, right) ? Boolean.FALSE : Boolean.TRUE;
}
@Override
Modified:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java?rev=1367576&r1=1367575&r2=1367576&view=diff
==============================================================================
---
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java
(original)
+++
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java
Tue Jul 31 14:30:43 2012
@@ -16,7 +16,6 @@
*/
package org.apache.commons.jexl3.parser;
-import org.apache.commons.jexl3.JexlException;
import org.apache.commons.jexl3.JexlInfo;
import org.apache.commons.jexl3.introspection.JexlMethod;
import org.apache.commons.jexl3.introspection.JexlPropertyGet;
Modified:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java?rev=1367576&r1=1367575&r2=1367576&view=diff
==============================================================================
---
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java
(original)
+++
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java
Tue Jul 31 14:30:43 2012
@@ -48,7 +48,7 @@ public abstract class JexlParser extends
public void allowRegisters(boolean registers) {
ALLOW_REGISTERS = registers;
}
-
+
/**
* Sets the frame to use by this parser.
* <p> This is used to allow parameters to be declared before parsing. </p>
@@ -148,7 +148,7 @@ public abstract class JexlParser extends
return null;
}
- void jjtreeOpenNodeScope(JexlNode n) {
+ void jjtreeOpenNodeScope(JexlNode node) {
}
/**
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=1367576&r1=1367575&r2=1367576&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
Tue Jul 31 14:30:43 2012
@@ -129,10 +129,12 @@ PARSER_END(Parser)
<*> TOKEN : { /* COMPARISONS */
< eq : "==" | "eq" >
| < ne : "!=" | "ne" >
- | < req : "=~" >
- | < rne : "!~" >
- | < sw : "=^" >
- | < ew : "=$" >
+ | < req : "=~" > // regexp equal
+ | < rne : "!~" > // regexp not equal
+ | < seq : "=^" > // starts equal
+ | < eeq : "=$" > // ends equal
+ | < sne : "!^" > // start not equal
+ | < ene : "!$" > // ends not equal
| < gt : ">" | "gt" >
| < ge : ">=" | "ge" >
| < lt : "<" | "lt" >
@@ -359,9 +361,13 @@ void RelationalExpression() #void : {}
|
<rne> AdditiveExpression() #NRNode(2) // not equals regexp
|
- <sw> AdditiveExpression() #SWNode(2) // starts with
+ <seq> AdditiveExpression() #SWNode(2) // starts with
|
- <ew> AdditiveExpression() #EWNode(2) // ends with
+ <sne> AdditiveExpression() #NSWNode(2) // not starts with
+ |
+ <eeq> AdditiveExpression() #EWNode(2) // ends with
+ |
+ <ene> AdditiveExpression() #NEWNode(2) // not ends with
)?
}
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=1367576&r1=1367575&r2=1367576&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
Tue Jul 31 14:30:43 2012
@@ -88,8 +88,12 @@ public abstract class ParserVisitor {
protected abstract Object visit(ASTSWNode node, Object data);
+ protected abstract Object visit(ASTNSWNode node, Object data);
+
protected abstract Object visit(ASTEWNode node, Object data);
+ protected abstract Object visit(ASTNEWNode node, Object data);
+
protected abstract Object visit(ASTAddNode node, Object data);
protected abstract Object visit(ASTSubNode node, Object data);
Modified: commons/proper/jexl/trunk/src/site/xdoc/changes.xml
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/site/xdoc/changes.xml?rev=1367576&r1=1367575&r2=1367576&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/site/xdoc/changes.xml (original)
+++ commons/proper/jexl/trunk/src/site/xdoc/changes.xml Tue Jul 31 14:30:43 2012
@@ -26,7 +26,7 @@
</properties>
<body>
<release version="3.0" date="2012-07-30">
- <action dev="henrib" type="add" issue="JEXL-131" due-to="Alfred
Reibenschuh">
+ <action dev="henrib" type="add" issue="JEXL-133" due-to="Alfred
Reibenschuh">
String matching Operator short-hand inspired by CSS3
</action>
<action dev="henrib" type="add" >
Modified: commons/proper/jexl/trunk/src/site/xdoc/reference/syntax.xml
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/site/xdoc/reference/syntax.xml?rev=1367576&r1=1367575&r2=1367576&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/site/xdoc/reference/syntax.xml (original)
+++ commons/proper/jexl/trunk/src/site/xdoc/reference/syntax.xml Tue Jul 31
14:30:43 2012
@@ -502,6 +502,12 @@
</td>
</tr>
<tr>
+ <td>Not Starts With<code>!^</code></td>
+ <td>
+ This is the negation of the 'starts with' operator.
+ <code>a ^! "abc"</code> is equivalent to <code>!(a ^= "abc")</code>
+ </td>
+ <tr>
<td>Ends With<code>=$</code></td>
<td>The syntactically CSS3 inspired <code>=$</code> operator is a
short-hand for the 'endsWith' method.
For example,
@@ -511,12 +517,19 @@
</td>
</tr>
<tr>
- <td>Range<code>..</code></td>
- <td>
- This operator creates a 'range' of values (in the form of a
java iterable).
- For example,
- <code>for(var x: 1 .. 3) {}</code> will loop 3 times with the
value of 'x' being 1, 2 and 3.
- </td>
+ <td>Not Ends With<code>!^</code></td>
+ <td>
+ This is the negation of the 'ends with' operator.
+ <code>a $! "abc"</code> is equivalent to <code>!(a $= "abc")</code>
+ </td>
+ <tr>
+ <tr>
+ <td>Range<code>..</code></td>
+ <td>
+ This operator creates a 'range' of values (in the form of a java
iterable).
+ For example,
+ <code>for(var x: 1 .. 3) {}</code> will loop 3 times with the
value of 'x' being 1, 2 and 3.
+ </td>
</tr>
<tr>
<td>Addition</td>
Modified:
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticOperatorTest.java
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticOperatorTest.java?rev=1367576&r1=1367575&r2=1367576&view=diff
==============================================================================
---
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticOperatorTest.java
(original)
+++
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticOperatorTest.java
Tue Jul 31 14:30:43 2012
@@ -80,6 +80,15 @@ public class ArithmeticOperatorTest exte
asserter.assertExpression("x =$ 'foo'", Boolean.TRUE);
}
+ public void testNotStartsEndsWithString() throws Exception {
+ asserter.setVariable("x", "foobar");
+ asserter.assertExpression("x !^ 'foo'", Boolean.FALSE);
+ asserter.assertExpression("x !$ 'foo'", Boolean.TRUE);
+ asserter.setVariable("x", "barfoo");
+ asserter.assertExpression("x !^ 'foo'", Boolean.TRUE);
+ asserter.assertExpression("x !$ 'foo'", Boolean.FALSE);
+ }
+
public static class MatchingContainer {
private final Set<Integer> values;
@@ -187,6 +196,25 @@ public class ArithmeticOperatorTest exte
asserter.assertExpression("x =^ [42, 54]", Boolean.TRUE);
}
+ public void testNotStartsEndsWith() throws Exception {
+ asserter.setVariable("x", "foobar");
+ asserter.assertExpression("x !^ 'foo'", Boolean.FALSE);
+ asserter.assertExpression("x !$ 'foo'", Boolean.TRUE);
+ asserter.setVariable("x", "barfoo");
+ asserter.assertExpression("x !^ 'foo'", Boolean.TRUE);
+ asserter.assertExpression("x !$ 'foo'", Boolean.FALSE);
+
+ int[] ai = {2, 4, 42, 54};
+ IterableContainer ic = new IterableContainer(ai);
+ asserter.setVariable("x", ic);
+ asserter.assertExpression("x !^ 2", Boolean.FALSE);
+ asserter.assertExpression("x !$ 54", Boolean.FALSE);
+ asserter.assertExpression("x !^ 4", Boolean.TRUE);
+ asserter.assertExpression("x !$ 42", Boolean.TRUE);
+ asserter.assertExpression("x !^ [2, 4]", Boolean.FALSE);
+ asserter.assertExpression("x !^ [42, 54]", Boolean.FALSE);
+ }
+
public static class Aggregate {
private Aggregate() {}
public static int sum(Iterable<Integer> ii) {