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 2009/08/29 10:39:05 UTC

svn commit: r809099 - in /commons/proper/jexl/branches/2.0/src: main/java/org/apache/commons/jexl/ main/java/org/apache/commons/jexl/parser/ test/java/org/apache/commons/jexl/

Author: henrib
Date: Sat Aug 29 08:39:04 2009
New Revision: 809099

URL: http://svn.apache.org/viewvc?rev=809099&view=rev
Log:
added Unicode escape sequence to String literal handling; fixed non-escapable character handling; added $ as escapable character in UnifiedJEXL

Modified:
    commons/proper/jexl/branches/2.0/src/main/java/org/apache/commons/jexl/UnifiedJEXL.java
    commons/proper/jexl/branches/2.0/src/main/java/org/apache/commons/jexl/parser/StringParser.java
    commons/proper/jexl/branches/2.0/src/test/java/org/apache/commons/jexl/JexlTest.java
    commons/proper/jexl/branches/2.0/src/test/java/org/apache/commons/jexl/UnifiedJEXLTest.java

Modified: commons/proper/jexl/branches/2.0/src/main/java/org/apache/commons/jexl/UnifiedJEXL.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/main/java/org/apache/commons/jexl/UnifiedJEXL.java?rev=809099&r1=809098&r2=809099&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/main/java/org/apache/commons/jexl/UnifiedJEXL.java (original)
+++ commons/proper/jexl/branches/2.0/src/main/java/org/apache/commons/jexl/UnifiedJEXL.java Sat Aug 29 08:39:04 2009
@@ -869,11 +869,11 @@
         IMMEDIATE0,
         /** Parsing after # .*/
         DEFERRED0,
-        /** Parsing afer ${ . */
+        /** Parsing afer ${ .*/
         IMMEDIATE1,
-        /** Parsing afer #{ . */
+        /** Parsing afer #{ .*/
         DEFERRED1,
-        /** Parsing afer \ . */
+        /** Parsing afer \ .*/
         ESCAPE
     }
 
@@ -944,7 +944,6 @@
                 case IMMEDIATE1: // ${...
                     if (c == '}') {
                         // materialize the immediate expr
-                        //Expression iexpr = createExpression(ExpressionType.IMMEDIATE, strb, null);
                         Expression iexpr = new ImmediateExpression(strb.toString(), toNode(strb), null);
                         builder.add(iexpr);
                         strb.delete(0, Integer.MAX_VALUE);
@@ -996,6 +995,8 @@
                 case ESCAPE:
                     if (c == '#') {
                         strb.append('#');
+                    } else if (c == '$') {
+                        strb.append('$');
                     } else {
                         strb.append('\\');
                         strb.append(c);

Modified: commons/proper/jexl/branches/2.0/src/main/java/org/apache/commons/jexl/parser/StringParser.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/main/java/org/apache/commons/jexl/parser/StringParser.java?rev=809099&r1=809098&r2=809099&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/main/java/org/apache/commons/jexl/parser/StringParser.java (original)
+++ commons/proper/jexl/branches/2.0/src/main/java/org/apache/commons/jexl/parser/StringParser.java Sat Aug 29 08:39:04 2009
@@ -18,6 +18,20 @@
 
 /**
  * Common constant strings utilities.
+ * <p>
+ * This package methods read JEXL string literals and handle escaping through the
+ * 'backslash' (ie: \) character. Escaping is used to neutralize string delimiters (the single
+ * and double quotes) and read Unicode hexadecimal encoded characters.
+ * </p>
+ * <p>
+ * The only escapable characters are the single and double quotes - ''' and '"' -,
+ * a Unicode sequence starting with 'u' followed by 4 hexadecimals and
+ * the backslash character - '\' - itself.
+ * </p>
+ * <p>
+ * A sequence where '\' occurs before any non-escapable character or sequence has no effect, the
+ * sequence output being the same as the input.
+ * </p>
  */
 public class StringParser {
     /**
@@ -47,7 +61,7 @@
     public static int readString(StringBuilder strb, CharSequence str, int index, char sep) {
         return read(strb, str, index, str.length(), sep);
     }
-    
+
     /**
      * Read the remainder of a string till a given separator,
      * handles escaping through '\' syntax.
@@ -64,9 +78,17 @@
         for (; index < end; ++index) {
             char c = str.charAt(index);
             if (escape) {
-                strb.append(c);
-                if (c == '\\')
-                    strb.append('\\');
+                if (c == 'u' && (index + 4) < end && readUnicodeChar(strb, str, index + 1) > 0) {
+                    index += 4;
+                }
+                else {
+                    // if c is not an escapable character, re-emmit the backslash before it
+                    boolean notSeparator = sep == 0? c != '\'' && c != '"' : c != sep;
+                    if (notSeparator && c != '\\' ) {
+                        strb.append('\\');
+                    }
+                    strb.append(c);
+                }
                 escape = false;
                 continue;
             }
@@ -81,4 +103,36 @@
         }
         return index;
     }
+
+    /**
+     * Reads a Unicode escape character.
+     * @param strb the builder to write the character to
+     * @param str the sequence
+     * @param begin the begin offset in sequence (after the '\\u')
+     * @return 0 if char could not be read, 4 otherwise
+     */
+    private static final int readUnicodeChar(StringBuilder strb, CharSequence str, int begin) {
+        char xc = 0;
+        int bits = 12;
+        int value = 0;
+        for(int offset = 0; offset < 4; ++offset) {
+            char c = str.charAt(begin + offset);
+            if (c >= '0' && c <= '9') {
+                value = (c - '0');
+            }
+            else if (c >= 'a' && c <= 'h') {
+               value = (c - 'a' + 10);
+            }
+            else if (c >= 'A' && c <= 'H') {
+                value = (c - 'A' + 10);
+            }
+            else {
+                return 0;
+            }
+            xc |= value << bits;
+            bits -= 4;
+        }
+        strb.append(xc);
+        return 4;
+    }
 }
\ No newline at end of file

Modified: commons/proper/jexl/branches/2.0/src/test/java/org/apache/commons/jexl/JexlTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/test/java/org/apache/commons/jexl/JexlTest.java?rev=809099&r1=809098&r2=809099&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/test/java/org/apache/commons/jexl/JexlTest.java (original)
+++ commons/proper/jexl/branches/2.0/src/test/java/org/apache/commons/jexl/JexlTest.java Sat Aug 29 08:39:04 2009
@@ -739,10 +739,15 @@
 //        jc.getVars().put("commons-logging", version);
 //        assertExpression(jc, "commons-logging", version);
     }
-    
+
     public void testUnicodeSupport() throws Exception
     {
-        assertExpression(JexlHelper.createContext(), "myvar == 'Użytkownik'", Boolean.FALSE);
+        JexlContext jc = JexlHelper.createContext();
+        assertExpression(jc, "myvar == 'Użytkownik'", Boolean.FALSE);
+        assertExpression(jc, "'c:\\some\\windows\\path'", "c:\\some\\windows\\path");
+        assertExpression(jc, "'foo\\u0020bar'", "foo\u0020bar");
+        assertExpression(jc, "'foo\\u0020\\u0020bar'", "foo\u0020\u0020bar");
+        assertExpression(jc, "'\\u0020foobar\\u0020'", "\u0020foobar\u0020");
     }
 
     public static final class Duck {

Modified: commons/proper/jexl/branches/2.0/src/test/java/org/apache/commons/jexl/UnifiedJEXLTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/test/java/org/apache/commons/jexl/UnifiedJEXLTest.java?rev=809099&r1=809098&r2=809099&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/test/java/org/apache/commons/jexl/UnifiedJEXLTest.java (original)
+++ commons/proper/jexl/branches/2.0/src/test/java/org/apache/commons/jexl/UnifiedJEXLTest.java Sat Aug 29 08:39:04 2009
@@ -157,10 +157,16 @@
     }
 
     public void testEscape() throws Exception {
-        UnifiedJEXL.Expression expr = EL.parse("#\\{'world'\\}");
         JexlContext none = null;
-        Object o = expr.evaluate(none);
+        UnifiedJEXL.Expression expr;
+        Object o;
+        // $ and # are escapable in UnifiedJEXL
+        expr = EL.parse("\\#{'world'}");
+        o = expr.evaluate(none);
         assertEquals("#{'world'}", o);
+        expr = EL.parse("\\${'world'}");
+        o = expr.evaluate(none);
+        assertEquals("${'world'}", o);
     }
 
     public void testEscapeString() throws Exception {
@@ -170,6 +176,13 @@
         assertEquals("\"world's finest\"", o);
     }
 
+    public void testNonEscapeString() throws Exception {
+        UnifiedJEXL.Expression expr = EL.parse("c:\\some\\windows\\path");
+        JexlContext none = null;
+        Object o = expr.evaluate(none);
+        assertEquals("c:\\some\\windows\\path", o);
+    }
+
     public void testMalformed() throws Exception {
         try {
             UnifiedJEXL.Expression expr = EL.parse("${'world'");
@@ -237,4 +250,4 @@
         test.setUp();
         test.testBadContextNested();
     }
-}
\ No newline at end of file
+}