This is an automated email from the ASF dual-hosted git repository.

ntimofeev pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git


The following commit(s) were added to refs/heads/master by this push:
     new b8046c88c CAY-2736 Can't use function names as a path in a 
string-based expression
b8046c88c is described below

commit b8046c88c92f5a7617403c292efa8e177ddcafa6
Author: Nikita Timofeev <[email protected]>
AuthorDate: Fri May 20 18:14:03 2022 +0300

    CAY-2736 Can't use function names as a path in a string-based expression
---
 RELEASE-NOTES.txt                                  |   1 +
 .../cayenne/exp/parser/ExpressionParser.java       | 201 +++++++++++++++++----
 .../exp/parser/ExpressionParserTokenManager.java   |   3 +-
 .../exp/parser/ExpressionParserTreeConstants.java  |   4 +-
 .../exp/parser/JJTExpressionParserState.java       |   4 +-
 .../apache/cayenne/exp/parser/ParseException.java  |  48 +++--
 .../apache/cayenne/exp/parser/TokenMgrError.java   |  37 ++--
 .../apache/cayenne/exp/parser/ExpressionParser.jjt |  57 +++++-
 .../org/apache/cayenne/exp/ExpressionTest.java     |  22 +++
 9 files changed, 292 insertions(+), 85 deletions(-)

diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index bd6d25c29..b5467ba26 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -23,6 +23,7 @@ CAY-2727 Modeler: cgen destDir Unix platform path separator
 CAY-2729 Unable to use custom templates from a folder at upper level then 
datamap
 CAY-2730 Duplicating lines in a cgen config saved to datamap.xml
 CAY-2731 Exception when setting a CLOB on H2 v2.0.202
+CAY-2736 Can't use function names as a path in a string-based expression
 
 ----------------------------------
 Release: 4.2.B1
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParser.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParser.java
index ece560dae..4c710a485 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParser.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParser.java
@@ -1,3 +1,4 @@
+/* ExpressionParser.java */
 /* Generated By:JJTree&JavaCC: Do not edit this line. ExpressionParser.java */
 /*****************************************************************
  *   Licensed to the Apache Software Foundation (ASF) under one
@@ -21,6 +22,8 @@
 
 package org.apache.cayenne.exp.parser;
 
+import java.math.BigDecimal;
+import java.math.BigInteger;
 import org.apache.cayenne.exp.Expression;
 
 /**
@@ -2829,69 +2832,69 @@ if (jjtc001) {
       }
     case 68:{
       jj_consume_token(68);
-      t = jj_consume_token(PROPERTY_PATH);
+      t = pathToken();
 ASTObjPath jjtn002 = new ASTObjPath(JJTOBJPATH);
-                                   boolean jjtc002 = true;
-                                   jjtree.openNodeScope(jjtn002);
+                               boolean jjtc002 = true;
+                               jjtree.openNodeScope(jjtn002);
       try {
 jjtree.closeNodeScope(jjtn002,  0);
-                                   jjtc002 = false;
+                               jjtc002 = false;
 ExpressionUtils.parsePath(jjtn002, t.image);
       } finally {
 if (jjtc002) {
-                                     jjtree.closeNodeScope(jjtn002,  0);
-                                   }
+                                 jjtree.closeNodeScope(jjtn002,  0);
+                               }
       }
       break;
       }
     case 69:{
       jj_consume_token(69);
-      t = jj_consume_token(PROPERTY_PATH);
+      t = pathToken();
 ASTDbPath jjtn003 = new ASTDbPath(JJTDBPATH);
-                                   boolean jjtc003 = true;
-                                   jjtree.openNodeScope(jjtn003);
+                               boolean jjtc003 = true;
+                               jjtree.openNodeScope(jjtn003);
       try {
 jjtree.closeNodeScope(jjtn003,  0);
-                                   jjtc003 = false;
+                               jjtc003 = false;
 ExpressionUtils.parsePath(jjtn003, t.image);
       } finally {
 if (jjtc003) {
-                                     jjtree.closeNodeScope(jjtn003,  0);
-                                   }
+                                 jjtree.closeNodeScope(jjtn003,  0);
+                               }
       }
       break;
       }
     case 70:{
       jj_consume_token(70);
-      t = jj_consume_token(PROPERTY_PATH);
+      t = pathToken();
 ASTEnum jjtn004 = new ASTEnum(JJTENUM);
-                                   boolean jjtc004 = true;
-                                   jjtree.openNodeScope(jjtn004);
+                               boolean jjtc004 = true;
+                               jjtree.openNodeScope(jjtn004);
       try {
 jjtree.closeNodeScope(jjtn004,  0);
-                                   jjtc004 = false;
+                               jjtc004 = false;
 jjtn004.setEnumValue(t.image);
       } finally {
 if (jjtc004) {
-                                     jjtree.closeNodeScope(jjtn004,  0);
-                                   }
+                                 jjtree.closeNodeScope(jjtn004,  0);
+                               }
       }
       break;
       }
     case 71:{
       jj_consume_token(71);
-      t = jj_consume_token(PROPERTY_PATH);
+      t = pathToken();
 ASTDbIdPath jjtn005 = new ASTDbIdPath(JJTDBIDPATH);
-                                   boolean jjtc005 = true;
-                                   jjtree.openNodeScope(jjtn005);
+                               boolean jjtc005 = true;
+                               jjtree.openNodeScope(jjtn005);
       try {
 jjtree.closeNodeScope(jjtn005,  0);
-                                   jjtc005 = false;
+                               jjtc005 = false;
 ExpressionUtils.parsePath(jjtn005, t.image);
       } finally {
 if (jjtc005) {
-                                     jjtree.closeNodeScope(jjtn005,  0);
-                                   }
+                                 jjtree.closeNodeScope(jjtn005,  0);
+                               }
       }
       break;
       }
@@ -2902,6 +2905,134 @@ if (jjtc005) {
     }
 }
 
+// this rule returns single token that could be used as a path definition
+  final public Token pathToken() throws ParseException {Token t ;
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case PROPERTY_PATH:{
+      t = jj_consume_token(PROPERTY_PATH);
+      break;
+      }
+    case AVG:{
+      t = jj_consume_token(AVG);
+      break;
+      }
+    case MIN:{
+      t = jj_consume_token(MIN);
+      break;
+      }
+    case MAX:{
+      t = jj_consume_token(MAX);
+      break;
+      }
+    case SUM:{
+      t = jj_consume_token(SUM);
+      break;
+      }
+    case COUNT:{
+      t = jj_consume_token(COUNT);
+      break;
+      }
+    case DISTINCT:{
+      t = jj_consume_token(DISTINCT);
+      break;
+      }
+    case CONCAT:{
+      t = jj_consume_token(CONCAT);
+      break;
+      }
+    case SUBSTRING:{
+      t = jj_consume_token(SUBSTRING);
+      break;
+      }
+    case TRIM:{
+      t = jj_consume_token(TRIM);
+      break;
+      }
+    case LOWER:{
+      t = jj_consume_token(LOWER);
+      break;
+      }
+    case UPPER:{
+      t = jj_consume_token(UPPER);
+      break;
+      }
+    case LENGTH:{
+      t = jj_consume_token(LENGTH);
+      break;
+      }
+    case LOCATE:{
+      t = jj_consume_token(LOCATE);
+      break;
+      }
+    case ABS:{
+      t = jj_consume_token(ABS);
+      break;
+      }
+    case SQRT:{
+      t = jj_consume_token(SQRT);
+      break;
+      }
+    case MOD:{
+      t = jj_consume_token(MOD);
+      break;
+      }
+    case CURRENT_DATE:{
+      t = jj_consume_token(CURRENT_DATE);
+      break;
+      }
+    case CURRENT_TIME:{
+      t = jj_consume_token(CURRENT_TIME);
+      break;
+      }
+    case CURRENT_TIMESTAMP:{
+      t = jj_consume_token(CURRENT_TIMESTAMP);
+      break;
+      }
+    case YEAR:{
+      t = jj_consume_token(YEAR);
+      break;
+      }
+    case MONTH:{
+      t = jj_consume_token(MONTH);
+      break;
+      }
+    case DAY:{
+      t = jj_consume_token(DAY);
+      break;
+      }
+    case HOUR:{
+      t = jj_consume_token(HOUR);
+      break;
+      }
+    case MINUTE:{
+      t = jj_consume_token(MINUTE);
+      break;
+      }
+    case SECOND:{
+      t = jj_consume_token(SECOND);
+      break;
+      }
+    case DAY_OF_MONTH:{
+      t = jj_consume_token(DAY_OF_MONTH);
+      break;
+      }
+    case DAY_OF_WEEK:{
+      t = jj_consume_token(DAY_OF_WEEK);
+      break;
+      }
+    case DAY_OF_YEAR:{
+      t = jj_consume_token(DAY_OF_YEAR);
+      break;
+      }
+    default:
+      jj_la1[47] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+{if ("" != null) return t;}
+    throw new Error("Missing return statement in function");
+}
+
   /** Generated Token Manager. */
   public ExpressionParserTokenManager token_source;
   JavaCharStream jj_input_stream;
@@ -2911,7 +3042,7 @@ if (jjtc005) {
   public Token jj_nt;
   private int jj_ntk;
   private int jj_gen;
-  final private int[] jj_la1 = new int[47];
+  final private int[] jj_la1 = new int[48];
   static private int[] jj_la1_0;
   static private int[] jj_la1_1;
   static private int[] jj_la1_2;
@@ -2921,13 +3052,13 @@ if (jjtc005) {
           jj_la1_init_2();
        }
        private static void jj_la1_init_0() {
-          jj_la1_0 = new int[] 
{0x2,0x4,0x18,0x16010018,0x60,0x180,0x10000,0x4fff8,0x4fff8,0x16010000,0x18,0x10000,0x4e000,0x80000,0x16010000,0x0,0x0,0x0,0x16010000,0x0,0x100000,0x200000,0x400000,0x1800000,0x1800000,0x6000000,0x6000000,0x8000000,0x8000000,0x16010000,0x2000000,0x6010000,0x10000,0x0,0x80000,0x16010000,0x80000,0x16010000,0x80000,0x80000,0x0,0x80000,0x0,0x0,0x0,0x0,0x0,};
+          jj_la1_0 = new int[] 
{0x2,0x4,0x18,0x16010018,0x60,0x180,0x10000,0x4fff8,0x4fff8,0x16010000,0x18,0x10000,0x4e000,0x80000,0x16010000,0x0,0x0,0x0,0x16010000,0x0,0x100000,0x200000,0x400000,0x1800000,0x1800000,0x6000000,0x6000000,0x8000000,0x8000000,0x16010000,0x2000000,0x6010000,0x10000,0x0,0x80000,0x16010000,0x80000,0x16010000,0x80000,0x80000,0x0,0x80000,0x0,0x0,0x0,0x0,0x0,0x0,};
        }
        private static void jj_la1_init_1() {
-          jj_la1_1 = new int[] 
{0x0,0x0,0x0,0xfffffdfe,0x0,0x0,0x0,0x0,0x0,0xfffffdfe,0x0,0x0,0x0,0x0,0xfffffdf2,0x7c00,0x0,0x7c00,0xfffffdfe,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff8f8000,0x0,0xff8f8000,0xff8f8000,0x7c00,0x0,0xff8ffc00,0x0,0xff8ffc00,0x0,0x0,0xff8f8000,0x0,0x1f0,0x200,0x700000,0xff800000,0x0,};
+          jj_la1_1 = new int[] 
{0x0,0x0,0x0,0xfffffdfe,0x0,0x0,0x0,0x0,0x0,0xfffffdfe,0x0,0x0,0x0,0x0,0xfffffdf2,0x7c00,0x0,0x7c00,0xfffffdfe,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff8f8000,0x0,0xff8f8000,0xff8f8000,0x7c00,0x0,0xff8ffc00,0x0,0xff8ffc00,0x0,0x0,0xff8f8000,0x0,0x1f0,0x200,0x700000,0xff800000,0x0,0xfdfffff0,};
        }
        private static void jj_la1_init_2() {
-          jj_la1_2 = new int[] 
{0x0,0x0,0x0,0xe402ff,0x0,0x0,0x8,0x0,0x0,0xe402ff,0x0,0x8,0x0,0x0,0xe402ff,0x2402f0,0x240000,0x240000,0xe402ff,0xe40008,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100,0x100,0xc002ff,0x0,0xc002ff,0xc002ff,0x0,0x0,0xe402ff,0x0,0xe402ff,0x0,0x0,0x1,0x0,0x0,0x3f0,0x0,0x1,0x2f0,};
+          jj_la1_2 = new int[] 
{0x0,0x0,0x0,0xe402ff,0x0,0x0,0x8,0x0,0x0,0xe402ff,0x0,0x8,0x0,0x0,0xe402ff,0x2402f0,0x240000,0x240000,0xe402ff,0xe40008,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100,0x100,0xc002ff,0x0,0xc002ff,0xc002ff,0x0,0x0,0xe402ff,0x0,0xe402ff,0x0,0x0,0x1,0x0,0x0,0x3f0,0x0,0x1,0x2f0,0x201,};
        }
 
   /** Constructor with InputStream. */
@@ -2941,7 +3072,7 @@ if (jjtc005) {
         token = new Token();
         jj_ntk = -1;
         jj_gen = 0;
-        for (int i = 0; i < 47; i++) jj_la1[i] = -1;
+        for (int i = 0; i < 48; i++) jj_la1[i] = -1;
   }
 
   /** Reinitialise. */
@@ -2956,7 +3087,7 @@ if (jjtc005) {
         jj_ntk = -1;
         jjtree.reset();
         jj_gen = 0;
-        for (int i = 0; i < 47; i++) jj_la1[i] = -1;
+        for (int i = 0; i < 48; i++) jj_la1[i] = -1;
   }
 
   /** Constructor. */
@@ -2966,7 +3097,7 @@ if (jjtc005) {
         token = new Token();
         jj_ntk = -1;
         jj_gen = 0;
-        for (int i = 0; i < 47; i++) jj_la1[i] = -1;
+        for (int i = 0; i < 48; i++) jj_la1[i] = -1;
   }
 
   /** Reinitialise. */
@@ -2985,7 +3116,7 @@ if (jjtc005) {
         jj_ntk = -1;
         jjtree.reset();
         jj_gen = 0;
-        for (int i = 0; i < 47; i++) jj_la1[i] = -1;
+        for (int i = 0; i < 48; i++) jj_la1[i] = -1;
   }
 
   /** Constructor with generated Token Manager. */
@@ -2994,7 +3125,7 @@ if (jjtc005) {
         token = new Token();
         jj_ntk = -1;
         jj_gen = 0;
-        for (int i = 0; i < 47; i++) jj_la1[i] = -1;
+        for (int i = 0; i < 48; i++) jj_la1[i] = -1;
   }
 
   /** Reinitialise. */
@@ -3004,7 +3135,7 @@ if (jjtc005) {
         jj_ntk = -1;
         jjtree.reset();
         jj_gen = 0;
-        for (int i = 0; i < 47; i++) jj_la1[i] = -1;
+        for (int i = 0; i < 48; i++) jj_la1[i] = -1;
   }
 
   private Token jj_consume_token(int kind) throws ParseException {
@@ -3060,7 +3191,7 @@ if (jjtc005) {
           la1tokens[jj_kind] = true;
           jj_kind = -1;
         }
-        for (int i = 0; i < 47; i++) {
+        for (int i = 0; i < 48; i++) {
           if (jj_la1[i] == jj_gen) {
                 for (int j = 0; j < 32; j++) {
                   if ((jj_la1_0[i] & (1<<j)) != 0) {
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserTokenManager.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserTokenManager.java
index 697688090..2bcb7bfcf 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserTokenManager.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserTokenManager.java
@@ -1,3 +1,4 @@
+/* ExpressionParserTokenManager.java */
 /* Generated By:JJTree&JavaCC: Do not edit this line. 
ExpressionParserTokenManager.java */
 /*****************************************************************
  *   Licensed to the Apache Software Foundation (ASF) under one
@@ -2792,5 +2793,5 @@ static final long[] jjtoMore = {
     private StringBuilder image = jjimage;
     private int jjimageLen;
     private int lengthOfMatch;
-    protected char curChar;
+    protected int curChar;
 }
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserTreeConstants.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserTreeConstants.java
index c3b3539a8..ab38843b2 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserTreeConstants.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserTreeConstants.java
@@ -1,4 +1,4 @@
-/* Generated By:JavaCC: Do not edit this line. 
ExpressionParserTreeConstants.java Version 7.0.5 */
+/* Generated By:JavaCC: Do not edit this line. 
ExpressionParserTreeConstants.java Version 7.0.11 */
 package org.apache.cayenne.exp.parser;
 
 public interface ExpressionParserTreeConstants
@@ -130,4 +130,4 @@ public interface ExpressionParserTreeConstants
     "DbIdPath",
   };
 }
-/* JavaCC - OriginalChecksum=cd72c6d845f6bcd460bdcd71d3700282 (do not edit 
this line) */
+/* JavaCC - OriginalChecksum=a6c359f491d0d2af8555386242238a43 (do not edit 
this line) */
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/JJTExpressionParserState.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/JJTExpressionParserState.java
index 063fef2d9..139896c7a 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/JJTExpressionParserState.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/JJTExpressionParserState.java
@@ -1,4 +1,4 @@
-/* Generated By:JavaCC: Do not edit this line. JJTExpressionParserState.java 
Version 7.0.5 */
+/* Generated By:JavaCC: Do not edit this line. JJTExpressionParserState.java 
Version 7.0.11 */
 package org.apache.cayenne.exp.parser;
 
 public class JJTExpressionParserState {
@@ -120,4 +120,4 @@ public class JJTExpressionParserState {
     }
   }
 }
-/* JavaCC - OriginalChecksum=4600ff3b66322d8f3f50176b034a1b48 (do not edit 
this line) */
+/* JavaCC - OriginalChecksum=2565d2cc35252acbdc49135562b6fa02 (do not edit 
this line) */
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ParseException.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ParseException.java
index d8c439e41..f20110b8f 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ParseException.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ParseException.java
@@ -1,5 +1,5 @@
-/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 5.0 
*/
-/* JavaCCOptions:KEEP_LINE_COL=null */
+/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 7.0 
*/
+/* JavaCCOptions:KEEP_LINE_COLUMN=true */
 /*****************************************************************
  *   Licensed to the Apache Software Foundation (ASF) under one
  *  or more contributor license agreements.  See the NOTICE file
@@ -40,6 +40,11 @@ public class ParseException extends Exception {
    */
   private static final long serialVersionUID = 1L;
 
+  /**
+   * The end of line string for this machine.
+   */
+  protected static String EOL = System.getProperty("line.separator", "\n");
+
   /**
    * This constructor is used by the method "generateParseException"
    * in the generated parser.  Calling this constructor generates
@@ -80,7 +85,7 @@ public class ParseException extends Exception {
   /**
    * This is the last token that has been consumed successfully.  If
    * this object has been created due to a parse error, the token
-   * followng this token will (therefore) be the first error token.
+   * following this token will (therefore) be the first error token.
    */
   public Token currentToken;
 
@@ -108,8 +113,8 @@ public class ParseException extends Exception {
   private static String initialise(Token currentToken,
                            int[][] expectedTokenSequences,
                            String[] tokenImage) {
-    String eol = System.getProperty("line.separator", "\n");
-    StringBuffer expected = new StringBuffer();
+
+    StringBuilder expected = new StringBuilder();
     int maxSize = 0;
     for (int i = 0; i < expectedTokenSequences.length; i++) {
       if (maxSize < expectedTokenSequences[i].length) {
@@ -121,7 +126,7 @@ public class ParseException extends Exception {
       if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 
0) {
         expected.append("...");
       }
-      expected.append(eol).append("    ");
+      expected.append(EOL).append("    ");
     }
     String retval = "Encountered \"";
     Token tok = currentToken.next;
@@ -137,21 +142,26 @@ public class ParseException extends Exception {
       retval += " \"";
       tok = tok.next;
     }
-    retval += "\" at line " + currentToken.next.beginLine + ", column " + 
currentToken.next.beginColumn;
-    retval += "." + eol;
-    if (expectedTokenSequences.length == 1) {
-      retval += "Was expecting:" + eol + "    ";
+    if (currentToken.next != null) {
+      retval += "\" at line " + currentToken.next.beginLine + ", column " + 
currentToken.next.beginColumn;
+    }
+    retval += "." + EOL;
+    
+    
+    if (expectedTokenSequences.length == 0) {
+        // Nothing to add here
     } else {
-      retval += "Was expecting one of:" + eol + "    ";
+           if (expectedTokenSequences.length == 1) {
+             retval += "Was expecting:" + EOL + "    ";
+           } else {
+             retval += "Was expecting one of:" + EOL + "    ";
+           }
+           retval += expected.toString();
     }
-    retval += expected.toString();
+    
     return retval;
   }
 
-  /**
-   * The end of line string for this machine.
-   */
-  protected String eol = System.getProperty("line.separator", "\n");
 
   /**
    * Used to convert raw characters to their escaped version
@@ -159,13 +169,11 @@ public class ParseException extends Exception {
    * string literal.
    */
   static String add_escapes(String str) {
-      StringBuffer retval = new StringBuffer();
+      StringBuilder retval = new StringBuilder();
       char ch;
       for (int i = 0; i < str.length(); i++) {
         switch (str.charAt(i))
         {
-           case 0 :
-              continue;
            case '\b':
               retval.append("\\b");
               continue;
@@ -204,4 +212,4 @@ public class ParseException extends Exception {
    }
 
 }
-/* JavaCC - OriginalChecksum=eb8dac072dfd4dad1a11088427fd2da3 (do not edit 
this line) */
+/* JavaCC - OriginalChecksum=7691b3e8db296ac7fb754fa94b972967 (do not edit 
this line) */
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/TokenMgrError.java 
b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/TokenMgrError.java
index c7850b17e..1289469eb 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/TokenMgrError.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/TokenMgrError.java
@@ -1,4 +1,4 @@
-/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 5.0 
*/
+/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 7.0 
*/
 /* JavaCCOptions: */
 /*****************************************************************
  *   Licensed to the Apache Software Foundation (ASF) under one
@@ -40,22 +40,22 @@ public class TokenMgrError extends Error
   /**
    * Lexical error occurred.
    */
-  static final int LEXICAL_ERROR = 0;
+  public static final int LEXICAL_ERROR = 0;
 
   /**
    * An attempt was made to create a second instance of a static token manager.
    */
-  static final int STATIC_LEXER_ERROR = 1;
+  public static final int STATIC_LEXER_ERROR = 1;
 
   /**
    * Tried to change to an invalid lexical state.
    */
-  static final int INVALID_LEXICAL_STATE = 2;
+  public static final int INVALID_LEXICAL_STATE = 2;
 
   /**
    * Detected (and bailed out of) an infinite loop in the token manager.
    */
-  static final int LOOP_DETECTED = 3;
+  public static final int LOOP_DETECTED = 3;
 
   /**
    * Indicates the reason why the exception is thrown. It will have
@@ -68,13 +68,11 @@ public class TokenMgrError extends Error
    * equivalents in the given string
    */
   protected static final String addEscapes(String str) {
-    StringBuffer retval = new StringBuffer();
+    StringBuilder retval = new StringBuilder();
     char ch;
     for (int i = 0; i < str.length(); i++) {
       switch (str.charAt(i))
       {
-        case 0 :
-          continue;
         case '\b':
           retval.append("\\b");
           continue;
@@ -117,19 +115,21 @@ public class TokenMgrError extends Error
    * token manager to indicate a lexical error.
    * Parameters :
    *    EOFSeen     : indicates if EOF caused the lexical error
-   *    curLexState : lexical state in which this error occurred
+   *    lexState    : lexical state in which this error occurred
    *    errorLine   : line number when the error occurred
    *    errorColumn : column number when the error occurred
    *    errorAfter  : prefix that was seen before this error occurred
    *    curchar     : the offending character
    * Note: You can customize the lexical error message by modifying this 
method.
    */
-  protected static String LexicalError(boolean EOFSeen, int lexState, int 
errorLine, int errorColumn, String errorAfter, char curChar) {
-    return("Lexical error at line " +
-          errorLine + ", column " +
-          errorColumn + ".  Encountered: " +
-          (EOFSeen ? "<EOF> " : ("\"" + addEscapes(String.valueOf(curChar)) + 
"\"") + " (" + (int)curChar + "), ") +
-          "after : \"" + addEscapes(errorAfter) + "\"");
+  protected static String LexicalErr(boolean EOFSeen, int lexState, int 
errorLine, int errorColumn, String errorAfter, int curChar) {
+    char curChar1 = (char)curChar;
+    return("Lexical error at line " + //
+          errorLine + ", column " + //
+          errorColumn + ".  Encountered: " + //
+          (EOFSeen ? "<EOF>" : ("'" + addEscapes(String.valueOf(curChar)) + "' 
(" + (int)curChar + "),")) + //
+          (errorAfter == null || errorAfter.length() == 0 ? "" : " after 
prefix \"" + addEscapes(errorAfter) + "\"")) + //
+          (lexState == 0 ? "" : " (in lexical state " + lexState + ")");
   }
 
   /**
@@ -141,6 +141,7 @@ public class TokenMgrError extends Error
    *
    * from this method for such cases in the release version of your parser.
    */
+  @Override
   public String getMessage() {
     return super.getMessage();
   }
@@ -160,8 +161,8 @@ public class TokenMgrError extends Error
   }
 
   /** Full Constructor. */
-  public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int 
errorColumn, String errorAfter, char curChar, int reason) {
-    this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, 
curChar), reason);
+  public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int 
errorColumn, String errorAfter, int curChar, int reason) {
+    this(LexicalErr(EOFSeen, lexState, errorLine, errorColumn, errorAfter, 
curChar), reason);
   }
 }
-/* JavaCC - OriginalChecksum=347e14790694eecc248c9f72c50d0b1d (do not edit 
this line) */
+/* JavaCC - OriginalChecksum=5088d3d182ac63ec68e3c489b6f0b93c (do not edit 
this line) */
diff --git 
a/cayenne-server/src/main/jjtree/org/apache/cayenne/exp/parser/ExpressionParser.jjt
 
b/cayenne-server/src/main/jjtree/org/apache/cayenne/exp/parser/ExpressionParser.jjt
index 90fbea299..0b3200340 100644
--- 
a/cayenne-server/src/main/jjtree/org/apache/cayenne/exp/parser/ExpressionParser.jjt
+++ 
b/cayenne-server/src/main/jjtree/org/apache/cayenne/exp/parser/ExpressionParser.jjt
@@ -440,7 +440,7 @@ void dateTimeExtractingFunction() #Extract(1) : {
 
 void distinct() #Distinct : { }
 {
-       <DISTINCT> "(" ( pathExpression() ) ")"
+       <DISTINCT> "(" pathExpression() ")"
 }
 
 TOKEN_MGR_DECLS:
@@ -606,23 +606,66 @@ void pathExpression() : {
    Token t;
 }
 {
-   (
              t = <PROPERTY_PATH> { ExpressionUtils.parsePath(jjtThis, 
t.image); } #ObjPath(0)
    |
-     "obj:"  t = <PROPERTY_PATH> { ExpressionUtils.parsePath(jjtThis, 
t.image); } #ObjPath(0)
+     "obj:"  t = pathToken() { ExpressionUtils.parsePath(jjtThis, t.image); } 
#ObjPath(0)
    |
-     "db:"   t = <PROPERTY_PATH> { ExpressionUtils.parsePath(jjtThis, 
t.image); } #DbPath(0)
+     "db:"   t = pathToken() { ExpressionUtils.parsePath(jjtThis, t.image); } 
#DbPath(0)
    |
-     "enum:" t = <PROPERTY_PATH> { jjtThis.setEnumValue(t.image); } #Enum(0)
+     "enum:" t = pathToken() { jjtThis.setEnumValue(t.image); } #Enum(0)
    |
-     "dbid:" t = <PROPERTY_PATH> { ExpressionUtils.parsePath(jjtThis, 
t.image); } #DbIdPath(0)
-   )
+     "dbid:" t = pathToken() { ExpressionUtils.parsePath(jjtThis, t.image); } 
#DbIdPath(0)
 }
 
 TOKEN : {
     <ASTERISK: "*">
 }
 
+// this rule returns single token that could be used as a path definition
+Token pathToken() : {
+    Token t ;
+}
+{
+    (
+      t = <PROPERTY_PATH>
+
+    | t = <AVG>
+    | t = <MIN>
+    | t = <MAX>
+    | t = <SUM>
+    | t = <COUNT>
+    | t = <DISTINCT>
+
+    | t = <CONCAT>
+    | t = <SUBSTRING>
+    | t = <TRIM>
+    | t = <LOWER>
+    | t = <UPPER>
+
+    | t = <LENGTH>
+    | t = <LOCATE>
+    | t = <ABS>
+    | t = <SQRT>
+    | t = <MOD>
+
+    | t = <CURRENT_DATE>
+    | t = <CURRENT_TIME>
+    | t = <CURRENT_TIMESTAMP>
+
+    | t = <YEAR>
+    | t = <MONTH>
+    | t = <DAY>
+    | t = <HOUR>
+    | t = <MINUTE>
+    | t = <SECOND>
+    | t = <DAY_OF_MONTH>
+    | t = <DAY_OF_WEEK>
+    | t = <DAY_OF_YEAR>
+
+    )
+    {return t;}
+}
+
 TOKEN : {
        <PROPERTY_PATH: <IDENTIFIER> ( "." <IDENTIFIER>) *>
 }
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionTest.java 
b/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionTest.java
index 86aa667e7..5af763f74 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionTest.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionTest.java
@@ -19,6 +19,7 @@
 package org.apache.cayenne.exp;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -26,7 +27,9 @@ import java.util.Date;
 import java.util.List;
 
 import org.apache.cayenne.ObjectId;
+import org.apache.cayenne.exp.parser.ASTDbPath;
 import org.apache.cayenne.exp.parser.ASTFalse;
+import org.apache.cayenne.exp.parser.ASTObjPath;
 import org.apache.cayenne.exp.parser.SimpleNode;
 import org.apache.cayenne.testdo.testmap.Artist;
 import org.junit.Test;
@@ -442,4 +445,23 @@ public class ExpressionTest {
                assertEquals("true and true", transformed.toString());
        }
 
+       @Test
+       public void testObjPathFunctionName() throws IOException {
+               Expression exp = 
ExpressionFactory.exp("obj:year.month.day.avg");
+               assertTrue(exp instanceof ASTObjPath);
+
+               StringBuilder buffer = new StringBuilder();
+               exp.appendAsString(buffer);
+               assertEquals("year.month.day.avg", buffer.toString());
+       }
+
+       @Test
+       public void testDbPathFunctionName() throws IOException {
+               Expression exp = ExpressionFactory.exp("db:year.month.day.avg");
+               assertTrue(exp instanceof ASTDbPath);
+
+               StringBuilder buffer = new StringBuilder();
+               exp.appendAsString(buffer);
+               assertEquals("db:year.month.day.avg", buffer.toString());
+       }
 }

Reply via email to