commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From hen...@apache.org
Subject svn commit: r1367576 - in /commons/proper/jexl/trunk/src: main/java/org/apache/commons/jexl3/internal/ main/java/org/apache/commons/jexl3/parser/ site/xdoc/ site/xdoc/reference/ test/java/org/apache/commons/jexl3/
Date Tue, 31 Jul 2012 14:30:44 GMT
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) {



Mime
View raw message