mirror of https://github.com/apache/lucene.git
LUCENE-5806: Extend expression grammar to allow advanced "variables"
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1609337 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
4a7b55d258
commit
e37d59b4c8
|
@ -105,6 +105,10 @@ New Features
|
|||
BBoxSpatialStrategy using most predicates. Sort documents by relative overlap
|
||||
of query areas or just by indexed shape area. (Ryan McKinley, David Smiley)
|
||||
|
||||
* LUCENE-5806: Extend expressions grammar to support array access in variables.
|
||||
Added helper class VariableContext to parse complex variable into pieces.
|
||||
(Ryan Ernst)
|
||||
|
||||
API Changes
|
||||
|
||||
* LUCENE-5752: Simplified Automaton API to be immutable. (Mike McCandless)
|
||||
|
|
|
@ -63,6 +63,11 @@ public final class SimpleBindings extends Bindings {
|
|||
map.put(sortField.getField(), sortField);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind a {@link ValueSource} directly to the given name.
|
||||
*/
|
||||
public void add(String name, ValueSource source) { map.put(name, source); }
|
||||
|
||||
/**
|
||||
* Adds an Expression to the bindings.
|
||||
* <p>
|
||||
|
@ -79,6 +84,8 @@ public final class SimpleBindings extends Bindings {
|
|||
throw new IllegalArgumentException("Invalid reference '" + name + "'");
|
||||
} else if (o instanceof Expression) {
|
||||
return ((Expression)o).getValueSource(this);
|
||||
} else if (o instanceof ValueSource) {
|
||||
return ((ValueSource)o);
|
||||
}
|
||||
SortField field = (SortField) o;
|
||||
switch(field.getType()) {
|
||||
|
|
|
@ -309,11 +309,11 @@ unary_operator
|
|||
|
||||
postfix
|
||||
: primary
|
||||
| NAMESPACE_ID arguments -> ^(AT_CALL NAMESPACE_ID arguments?)
|
||||
| VARIABLE arguments -> ^(AT_CALL VARIABLE arguments?)
|
||||
;
|
||||
|
||||
primary
|
||||
: NAMESPACE_ID
|
||||
: VARIABLE
|
||||
| numeric
|
||||
| AT_LPAREN! conditional AT_RPAREN!
|
||||
;
|
||||
|
@ -330,8 +330,19 @@ numeric
|
|||
// * Lexer Rules
|
||||
// ***********************************************************************
|
||||
|
||||
NAMESPACE_ID
|
||||
: ID (AT_DOT ID)*
|
||||
VARIABLE
|
||||
: OBJECT (AT_DOT OBJECT)*
|
||||
;
|
||||
|
||||
fragment
|
||||
OBJECT
|
||||
: ID ARRAY*
|
||||
;
|
||||
|
||||
fragment
|
||||
ARRAY
|
||||
: '[' STRING ']'
|
||||
| '[' DECIMALINTEGER ']'
|
||||
;
|
||||
|
||||
fragment
|
||||
|
@ -339,6 +350,26 @@ ID
|
|||
: ('a'..'z'|'A'..'Z'|'_'|'$') ('a'..'z'|'A'..'Z'|'0'..'9'|'_'|'$')*
|
||||
;
|
||||
|
||||
fragment
|
||||
STRING
|
||||
: '\'' SINGLE_STRING_CHAR* '\'' { }
|
||||
| '"' DOUBLE_STRING_CHAR* '"'
|
||||
;
|
||||
|
||||
fragment
|
||||
SINGLE_STRING_CHAR
|
||||
: '\\\''
|
||||
| '\\\\'
|
||||
| ~('\\'|'\'')
|
||||
;
|
||||
|
||||
fragment
|
||||
DOUBLE_STRING_CHAR
|
||||
: '\\"'
|
||||
| '\\\\'
|
||||
| ~('\\'|'"')
|
||||
;
|
||||
|
||||
WS
|
||||
: (' '|'\t'|'\n'|'\r')+ {skip();}
|
||||
;
|
||||
|
|
|
@ -1,67 +1,72 @@
|
|||
AT_ADD=4
|
||||
AT_BIT_AND=5
|
||||
AT_BIT_NOT=6
|
||||
AT_BIT_OR=7
|
||||
AT_BIT_SHL=8
|
||||
AT_BIT_SHR=9
|
||||
AT_BIT_SHU=10
|
||||
AT_BIT_XOR=11
|
||||
AT_BOOL_AND=12
|
||||
AT_BOOL_NOT=13
|
||||
AT_BOOL_OR=14
|
||||
AT_CALL=15
|
||||
AT_COLON=16
|
||||
AT_COMMA=17
|
||||
AT_COMP_EQ=18
|
||||
AT_COMP_GT=19
|
||||
AT_COMP_GTE=20
|
||||
AT_COMP_LT=21
|
||||
AT_COMP_LTE=22
|
||||
AT_COMP_NEQ=23
|
||||
AT_COND_QUE=24
|
||||
AT_DIVIDE=25
|
||||
AT_DOT=26
|
||||
AT_LPAREN=27
|
||||
AT_MODULO=28
|
||||
AT_MULTIPLY=29
|
||||
AT_NEGATE=30
|
||||
AT_RPAREN=31
|
||||
AT_SUBTRACT=32
|
||||
DECIMAL=33
|
||||
DECIMALDIGIT=34
|
||||
DECIMALINTEGER=35
|
||||
EXPONENT=36
|
||||
HEX=37
|
||||
HEXDIGIT=38
|
||||
ID=39
|
||||
NAMESPACE_ID=40
|
||||
OCTAL=41
|
||||
OCTALDIGIT=42
|
||||
WS=43
|
||||
'!'=13
|
||||
'!='=23
|
||||
'%'=28
|
||||
'&&'=12
|
||||
'&'=5
|
||||
'('=27
|
||||
')'=31
|
||||
'*'=29
|
||||
'+'=4
|
||||
','=17
|
||||
'-'=32
|
||||
'.'=26
|
||||
'/'=25
|
||||
':'=16
|
||||
'<'=21
|
||||
'<<'=8
|
||||
'<='=22
|
||||
'=='=18
|
||||
'>'=19
|
||||
'>='=20
|
||||
'>>'=9
|
||||
'>>>'=10
|
||||
'?'=24
|
||||
'^'=11
|
||||
'|'=7
|
||||
'||'=14
|
||||
'~'=6
|
||||
ARRAY=4
|
||||
AT_ADD=5
|
||||
AT_BIT_AND=6
|
||||
AT_BIT_NOT=7
|
||||
AT_BIT_OR=8
|
||||
AT_BIT_SHL=9
|
||||
AT_BIT_SHR=10
|
||||
AT_BIT_SHU=11
|
||||
AT_BIT_XOR=12
|
||||
AT_BOOL_AND=13
|
||||
AT_BOOL_NOT=14
|
||||
AT_BOOL_OR=15
|
||||
AT_CALL=16
|
||||
AT_COLON=17
|
||||
AT_COMMA=18
|
||||
AT_COMP_EQ=19
|
||||
AT_COMP_GT=20
|
||||
AT_COMP_GTE=21
|
||||
AT_COMP_LT=22
|
||||
AT_COMP_LTE=23
|
||||
AT_COMP_NEQ=24
|
||||
AT_COND_QUE=25
|
||||
AT_DIVIDE=26
|
||||
AT_DOT=27
|
||||
AT_LPAREN=28
|
||||
AT_MODULO=29
|
||||
AT_MULTIPLY=30
|
||||
AT_NEGATE=31
|
||||
AT_RPAREN=32
|
||||
AT_SUBTRACT=33
|
||||
DECIMAL=34
|
||||
DECIMALDIGIT=35
|
||||
DECIMALINTEGER=36
|
||||
DOUBLE_STRING_CHAR=37
|
||||
EXPONENT=38
|
||||
HEX=39
|
||||
HEXDIGIT=40
|
||||
ID=41
|
||||
OBJECT=42
|
||||
OCTAL=43
|
||||
OCTALDIGIT=44
|
||||
SINGLE_STRING_CHAR=45
|
||||
STRING=46
|
||||
VARIABLE=47
|
||||
WS=48
|
||||
'!'=14
|
||||
'!='=24
|
||||
'%'=29
|
||||
'&&'=13
|
||||
'&'=6
|
||||
'('=28
|
||||
')'=32
|
||||
'*'=30
|
||||
'+'=5
|
||||
','=18
|
||||
'-'=33
|
||||
'.'=27
|
||||
'/'=26
|
||||
':'=17
|
||||
'<'=22
|
||||
'<<'=9
|
||||
'<='=23
|
||||
'=='=19
|
||||
'>'=20
|
||||
'>='=21
|
||||
'>>'=10
|
||||
'>>>'=11
|
||||
'?'=25
|
||||
'^'=12
|
||||
'|'=8
|
||||
'||'=15
|
||||
'~'=7
|
||||
|
|
|
@ -254,9 +254,13 @@ public class JavascriptCompiler {
|
|||
|
||||
gen.cast(Type.DOUBLE_TYPE, expected);
|
||||
break;
|
||||
case JavascriptParser.NAMESPACE_ID:
|
||||
case JavascriptParser.VARIABLE:
|
||||
int index;
|
||||
|
||||
// normalize quotes
|
||||
text = normalizeQuotes(text);
|
||||
|
||||
|
||||
if (externalsMap.containsKey(text)) {
|
||||
index = externalsMap.get(text);
|
||||
} else {
|
||||
|
@ -492,6 +496,46 @@ public class JavascriptCompiler {
|
|||
}
|
||||
}
|
||||
|
||||
private static String normalizeQuotes(String text) {
|
||||
StringBuilder out = new StringBuilder(text.length());
|
||||
boolean inDoubleQuotes = false;
|
||||
for (int i = 0; i < text.length(); ++i) {
|
||||
char c = text.charAt(i);
|
||||
if (c == '\\') {
|
||||
c = text.charAt(++i);
|
||||
if (c == '\\') {
|
||||
out.append('\\'); // re-escape the backslash
|
||||
}
|
||||
// no escape for double quote
|
||||
} else if (c == '\'') {
|
||||
if (inDoubleQuotes) {
|
||||
// escape in output
|
||||
out.append('\\');
|
||||
} else {
|
||||
int j = findSingleQuoteStringEnd(text, i);
|
||||
out.append(text, i, j); // copy up to end quote (leave end for append below)
|
||||
i = j;
|
||||
}
|
||||
} else if (c == '"') {
|
||||
c = '\''; // change beginning/ending doubles to singles
|
||||
inDoubleQuotes = !inDoubleQuotes;
|
||||
}
|
||||
out.append(c);
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
private static int findSingleQuoteStringEnd(String text, int start) {
|
||||
++start; // skip beginning
|
||||
while (text.charAt(start) != '\'') {
|
||||
if (text.charAt(start) == '\\') {
|
||||
++start; // blindly consume escape value
|
||||
}
|
||||
++start;
|
||||
}
|
||||
return start;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default set of functions available to expressions.
|
||||
* <p>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -16,56 +16,62 @@ import org.antlr.runtime.tree.*;
|
|||
@SuppressWarnings("all")
|
||||
class JavascriptParser extends Parser {
|
||||
public static final String[] tokenNames = new String[] {
|
||||
"<invalid>", "<EOR>", "<DOWN>", "<UP>", "AT_ADD", "AT_BIT_AND", "AT_BIT_NOT",
|
||||
"AT_BIT_OR", "AT_BIT_SHL", "AT_BIT_SHR", "AT_BIT_SHU", "AT_BIT_XOR", "AT_BOOL_AND",
|
||||
"AT_BOOL_NOT", "AT_BOOL_OR", "AT_CALL", "AT_COLON", "AT_COMMA", "AT_COMP_EQ",
|
||||
"AT_COMP_GT", "AT_COMP_GTE", "AT_COMP_LT", "AT_COMP_LTE", "AT_COMP_NEQ",
|
||||
"AT_COND_QUE", "AT_DIVIDE", "AT_DOT", "AT_LPAREN", "AT_MODULO", "AT_MULTIPLY",
|
||||
"AT_NEGATE", "AT_RPAREN", "AT_SUBTRACT", "DECIMAL", "DECIMALDIGIT", "DECIMALINTEGER",
|
||||
"EXPONENT", "HEX", "HEXDIGIT", "ID", "NAMESPACE_ID", "OCTAL", "OCTALDIGIT",
|
||||
"WS"
|
||||
"<invalid>", "<EOR>", "<DOWN>", "<UP>", "ARRAY", "AT_ADD", "AT_BIT_AND",
|
||||
"AT_BIT_NOT", "AT_BIT_OR", "AT_BIT_SHL", "AT_BIT_SHR", "AT_BIT_SHU", "AT_BIT_XOR",
|
||||
"AT_BOOL_AND", "AT_BOOL_NOT", "AT_BOOL_OR", "AT_CALL", "AT_COLON", "AT_COMMA",
|
||||
"AT_COMP_EQ", "AT_COMP_GT", "AT_COMP_GTE", "AT_COMP_LT", "AT_COMP_LTE",
|
||||
"AT_COMP_NEQ", "AT_COND_QUE", "AT_DIVIDE", "AT_DOT", "AT_LPAREN", "AT_MODULO",
|
||||
"AT_MULTIPLY", "AT_NEGATE", "AT_RPAREN", "AT_SUBTRACT", "DECIMAL", "DECIMALDIGIT",
|
||||
"DECIMALINTEGER", "DOUBLE_STRING_CHAR", "EXPONENT", "HEX", "HEXDIGIT",
|
||||
"ID", "OBJECT", "OCTAL", "OCTALDIGIT", "SINGLE_STRING_CHAR", "STRING",
|
||||
"VARIABLE", "WS"
|
||||
};
|
||||
public static final int EOF=-1;
|
||||
public static final int AT_ADD=4;
|
||||
public static final int AT_BIT_AND=5;
|
||||
public static final int AT_BIT_NOT=6;
|
||||
public static final int AT_BIT_OR=7;
|
||||
public static final int AT_BIT_SHL=8;
|
||||
public static final int AT_BIT_SHR=9;
|
||||
public static final int AT_BIT_SHU=10;
|
||||
public static final int AT_BIT_XOR=11;
|
||||
public static final int AT_BOOL_AND=12;
|
||||
public static final int AT_BOOL_NOT=13;
|
||||
public static final int AT_BOOL_OR=14;
|
||||
public static final int AT_CALL=15;
|
||||
public static final int AT_COLON=16;
|
||||
public static final int AT_COMMA=17;
|
||||
public static final int AT_COMP_EQ=18;
|
||||
public static final int AT_COMP_GT=19;
|
||||
public static final int AT_COMP_GTE=20;
|
||||
public static final int AT_COMP_LT=21;
|
||||
public static final int AT_COMP_LTE=22;
|
||||
public static final int AT_COMP_NEQ=23;
|
||||
public static final int AT_COND_QUE=24;
|
||||
public static final int AT_DIVIDE=25;
|
||||
public static final int AT_DOT=26;
|
||||
public static final int AT_LPAREN=27;
|
||||
public static final int AT_MODULO=28;
|
||||
public static final int AT_MULTIPLY=29;
|
||||
public static final int AT_NEGATE=30;
|
||||
public static final int AT_RPAREN=31;
|
||||
public static final int AT_SUBTRACT=32;
|
||||
public static final int DECIMAL=33;
|
||||
public static final int DECIMALDIGIT=34;
|
||||
public static final int DECIMALINTEGER=35;
|
||||
public static final int EXPONENT=36;
|
||||
public static final int HEX=37;
|
||||
public static final int HEXDIGIT=38;
|
||||
public static final int ID=39;
|
||||
public static final int NAMESPACE_ID=40;
|
||||
public static final int OCTAL=41;
|
||||
public static final int OCTALDIGIT=42;
|
||||
public static final int WS=43;
|
||||
public static final int ARRAY=4;
|
||||
public static final int AT_ADD=5;
|
||||
public static final int AT_BIT_AND=6;
|
||||
public static final int AT_BIT_NOT=7;
|
||||
public static final int AT_BIT_OR=8;
|
||||
public static final int AT_BIT_SHL=9;
|
||||
public static final int AT_BIT_SHR=10;
|
||||
public static final int AT_BIT_SHU=11;
|
||||
public static final int AT_BIT_XOR=12;
|
||||
public static final int AT_BOOL_AND=13;
|
||||
public static final int AT_BOOL_NOT=14;
|
||||
public static final int AT_BOOL_OR=15;
|
||||
public static final int AT_CALL=16;
|
||||
public static final int AT_COLON=17;
|
||||
public static final int AT_COMMA=18;
|
||||
public static final int AT_COMP_EQ=19;
|
||||
public static final int AT_COMP_GT=20;
|
||||
public static final int AT_COMP_GTE=21;
|
||||
public static final int AT_COMP_LT=22;
|
||||
public static final int AT_COMP_LTE=23;
|
||||
public static final int AT_COMP_NEQ=24;
|
||||
public static final int AT_COND_QUE=25;
|
||||
public static final int AT_DIVIDE=26;
|
||||
public static final int AT_DOT=27;
|
||||
public static final int AT_LPAREN=28;
|
||||
public static final int AT_MODULO=29;
|
||||
public static final int AT_MULTIPLY=30;
|
||||
public static final int AT_NEGATE=31;
|
||||
public static final int AT_RPAREN=32;
|
||||
public static final int AT_SUBTRACT=33;
|
||||
public static final int DECIMAL=34;
|
||||
public static final int DECIMALDIGIT=35;
|
||||
public static final int DECIMALINTEGER=36;
|
||||
public static final int DOUBLE_STRING_CHAR=37;
|
||||
public static final int EXPONENT=38;
|
||||
public static final int HEX=39;
|
||||
public static final int HEXDIGIT=40;
|
||||
public static final int ID=41;
|
||||
public static final int OBJECT=42;
|
||||
public static final int OCTAL=43;
|
||||
public static final int OCTALDIGIT=44;
|
||||
public static final int SINGLE_STRING_CHAR=45;
|
||||
public static final int STRING=46;
|
||||
public static final int VARIABLE=47;
|
||||
public static final int WS=48;
|
||||
|
||||
// delegates
|
||||
public Parser[] getDelegates() {
|
||||
|
@ -1271,8 +1277,8 @@ class JavascriptParser extends Parser {
|
|||
case AT_LPAREN:
|
||||
case DECIMAL:
|
||||
case HEX:
|
||||
case NAMESPACE_ID:
|
||||
case OCTAL:
|
||||
case VARIABLE:
|
||||
{
|
||||
alt12=1;
|
||||
}
|
||||
|
@ -1493,26 +1499,26 @@ class JavascriptParser extends Parser {
|
|||
|
||||
|
||||
// $ANTLR start "postfix"
|
||||
// src/java/org/apache/lucene/expressions/js/Javascript.g:310:1: postfix : ( primary | NAMESPACE_ID arguments -> ^( AT_CALL NAMESPACE_ID ( arguments )? ) );
|
||||
// src/java/org/apache/lucene/expressions/js/Javascript.g:310:1: postfix : ( primary | VARIABLE arguments -> ^( AT_CALL VARIABLE ( arguments )? ) );
|
||||
public final JavascriptParser.postfix_return postfix() throws RecognitionException {
|
||||
JavascriptParser.postfix_return retval = new JavascriptParser.postfix_return();
|
||||
retval.start = input.LT(1);
|
||||
|
||||
CommonTree root_0 = null;
|
||||
|
||||
Token NAMESPACE_ID47=null;
|
||||
Token VARIABLE47=null;
|
||||
ParserRuleReturnScope primary46 =null;
|
||||
ParserRuleReturnScope arguments48 =null;
|
||||
|
||||
CommonTree NAMESPACE_ID47_tree=null;
|
||||
RewriteRuleTokenStream stream_NAMESPACE_ID=new RewriteRuleTokenStream(adaptor,"token NAMESPACE_ID");
|
||||
CommonTree VARIABLE47_tree=null;
|
||||
RewriteRuleTokenStream stream_VARIABLE=new RewriteRuleTokenStream(adaptor,"token VARIABLE");
|
||||
RewriteRuleSubtreeStream stream_arguments=new RewriteRuleSubtreeStream(adaptor,"rule arguments");
|
||||
|
||||
try {
|
||||
// src/java/org/apache/lucene/expressions/js/Javascript.g:311:5: ( primary | NAMESPACE_ID arguments -> ^( AT_CALL NAMESPACE_ID ( arguments )? ) )
|
||||
// src/java/org/apache/lucene/expressions/js/Javascript.g:311:5: ( primary | VARIABLE arguments -> ^( AT_CALL VARIABLE ( arguments )? ) )
|
||||
int alt14=2;
|
||||
int LA14_0 = input.LA(1);
|
||||
if ( (LA14_0==NAMESPACE_ID) ) {
|
||||
if ( (LA14_0==VARIABLE) ) {
|
||||
int LA14_1 = input.LA(2);
|
||||
if ( (LA14_1==EOF||(LA14_1 >= AT_ADD && LA14_1 <= AT_BIT_AND)||(LA14_1 >= AT_BIT_OR && LA14_1 <= AT_BOOL_AND)||LA14_1==AT_BOOL_OR||(LA14_1 >= AT_COLON && LA14_1 <= AT_DIVIDE)||(LA14_1 >= AT_MODULO && LA14_1 <= AT_MULTIPLY)||(LA14_1 >= AT_RPAREN && LA14_1 <= AT_SUBTRACT)) ) {
|
||||
alt14=1;
|
||||
|
@ -1560,10 +1566,10 @@ class JavascriptParser extends Parser {
|
|||
}
|
||||
break;
|
||||
case 2 :
|
||||
// src/java/org/apache/lucene/expressions/js/Javascript.g:312:7: NAMESPACE_ID arguments
|
||||
// src/java/org/apache/lucene/expressions/js/Javascript.g:312:7: VARIABLE arguments
|
||||
{
|
||||
NAMESPACE_ID47=(Token)match(input,NAMESPACE_ID,FOLLOW_NAMESPACE_ID_in_postfix1168);
|
||||
stream_NAMESPACE_ID.add(NAMESPACE_ID47);
|
||||
VARIABLE47=(Token)match(input,VARIABLE,FOLLOW_VARIABLE_in_postfix1168);
|
||||
stream_VARIABLE.add(VARIABLE47);
|
||||
|
||||
pushFollow(FOLLOW_arguments_in_postfix1170);
|
||||
arguments48=arguments();
|
||||
|
@ -1571,7 +1577,7 @@ class JavascriptParser extends Parser {
|
|||
|
||||
stream_arguments.add(arguments48.getTree());
|
||||
// AST REWRITE
|
||||
// elements: arguments, NAMESPACE_ID
|
||||
// elements: VARIABLE, arguments
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -1581,14 +1587,14 @@ class JavascriptParser extends Parser {
|
|||
RewriteRuleSubtreeStream stream_retval=new RewriteRuleSubtreeStream(adaptor,"rule retval",retval!=null?retval.getTree():null);
|
||||
|
||||
root_0 = (CommonTree)adaptor.nil();
|
||||
// 312:30: -> ^( AT_CALL NAMESPACE_ID ( arguments )? )
|
||||
// 312:26: -> ^( AT_CALL VARIABLE ( arguments )? )
|
||||
{
|
||||
// src/java/org/apache/lucene/expressions/js/Javascript.g:312:33: ^( AT_CALL NAMESPACE_ID ( arguments )? )
|
||||
// src/java/org/apache/lucene/expressions/js/Javascript.g:312:29: ^( AT_CALL VARIABLE ( arguments )? )
|
||||
{
|
||||
CommonTree root_1 = (CommonTree)adaptor.nil();
|
||||
root_1 = (CommonTree)adaptor.becomeRoot((CommonTree)adaptor.create(AT_CALL, "AT_CALL"), root_1);
|
||||
adaptor.addChild(root_1, stream_NAMESPACE_ID.nextNode());
|
||||
// src/java/org/apache/lucene/expressions/js/Javascript.g:312:56: ( arguments )?
|
||||
adaptor.addChild(root_1, stream_VARIABLE.nextNode());
|
||||
// src/java/org/apache/lucene/expressions/js/Javascript.g:312:48: ( arguments )?
|
||||
if ( stream_arguments.hasNext() ) {
|
||||
adaptor.addChild(root_1, stream_arguments.nextTree());
|
||||
}
|
||||
|
@ -1633,28 +1639,28 @@ class JavascriptParser extends Parser {
|
|||
|
||||
|
||||
// $ANTLR start "primary"
|
||||
// src/java/org/apache/lucene/expressions/js/Javascript.g:315:1: primary : ( NAMESPACE_ID | numeric | AT_LPAREN ! conditional AT_RPAREN !);
|
||||
// src/java/org/apache/lucene/expressions/js/Javascript.g:315:1: primary : ( VARIABLE | numeric | AT_LPAREN ! conditional AT_RPAREN !);
|
||||
public final JavascriptParser.primary_return primary() throws RecognitionException {
|
||||
JavascriptParser.primary_return retval = new JavascriptParser.primary_return();
|
||||
retval.start = input.LT(1);
|
||||
|
||||
CommonTree root_0 = null;
|
||||
|
||||
Token NAMESPACE_ID49=null;
|
||||
Token VARIABLE49=null;
|
||||
Token AT_LPAREN51=null;
|
||||
Token AT_RPAREN53=null;
|
||||
ParserRuleReturnScope numeric50 =null;
|
||||
ParserRuleReturnScope conditional52 =null;
|
||||
|
||||
CommonTree NAMESPACE_ID49_tree=null;
|
||||
CommonTree VARIABLE49_tree=null;
|
||||
CommonTree AT_LPAREN51_tree=null;
|
||||
CommonTree AT_RPAREN53_tree=null;
|
||||
|
||||
try {
|
||||
// src/java/org/apache/lucene/expressions/js/Javascript.g:316:5: ( NAMESPACE_ID | numeric | AT_LPAREN ! conditional AT_RPAREN !)
|
||||
// src/java/org/apache/lucene/expressions/js/Javascript.g:316:5: ( VARIABLE | numeric | AT_LPAREN ! conditional AT_RPAREN !)
|
||||
int alt15=3;
|
||||
switch ( input.LA(1) ) {
|
||||
case NAMESPACE_ID:
|
||||
case VARIABLE:
|
||||
{
|
||||
alt15=1;
|
||||
}
|
||||
|
@ -1678,14 +1684,14 @@ class JavascriptParser extends Parser {
|
|||
}
|
||||
switch (alt15) {
|
||||
case 1 :
|
||||
// src/java/org/apache/lucene/expressions/js/Javascript.g:316:7: NAMESPACE_ID
|
||||
// src/java/org/apache/lucene/expressions/js/Javascript.g:316:7: VARIABLE
|
||||
{
|
||||
root_0 = (CommonTree)adaptor.nil();
|
||||
|
||||
|
||||
NAMESPACE_ID49=(Token)match(input,NAMESPACE_ID,FOLLOW_NAMESPACE_ID_in_primary1198);
|
||||
NAMESPACE_ID49_tree = (CommonTree)adaptor.create(NAMESPACE_ID49);
|
||||
adaptor.addChild(root_0, NAMESPACE_ID49_tree);
|
||||
VARIABLE49=(Token)match(input,VARIABLE,FOLLOW_VARIABLE_in_primary1198);
|
||||
VARIABLE49_tree = (CommonTree)adaptor.create(VARIABLE49);
|
||||
adaptor.addChild(root_0, VARIABLE49_tree);
|
||||
|
||||
}
|
||||
break;
|
||||
|
@ -1776,7 +1782,7 @@ class JavascriptParser extends Parser {
|
|||
// src/java/org/apache/lucene/expressions/js/Javascript.g:322:18: ( conditional ( AT_COMMA ! conditional )* )?
|
||||
int alt17=2;
|
||||
int LA17_0 = input.LA(1);
|
||||
if ( (LA17_0==AT_ADD||LA17_0==AT_BIT_NOT||LA17_0==AT_BOOL_NOT||LA17_0==AT_LPAREN||(LA17_0 >= AT_SUBTRACT && LA17_0 <= DECIMAL)||LA17_0==HEX||(LA17_0 >= NAMESPACE_ID && LA17_0 <= OCTAL)) ) {
|
||||
if ( (LA17_0==AT_ADD||LA17_0==AT_BIT_NOT||LA17_0==AT_BOOL_NOT||LA17_0==AT_LPAREN||(LA17_0 >= AT_SUBTRACT && LA17_0 <= DECIMAL)||LA17_0==HEX||LA17_0==OCTAL||LA17_0==VARIABLE) ) {
|
||||
alt17=1;
|
||||
}
|
||||
switch (alt17) {
|
||||
|
@ -1906,60 +1912,60 @@ class JavascriptParser extends Parser {
|
|||
|
||||
public static final BitSet FOLLOW_conditional_in_expression737 = new BitSet(new long[]{0x0000000000000000L});
|
||||
public static final BitSet FOLLOW_EOF_in_expression739 = new BitSet(new long[]{0x0000000000000002L});
|
||||
public static final BitSet FOLLOW_logical_or_in_conditional757 = new BitSet(new long[]{0x0000000001000002L});
|
||||
public static final BitSet FOLLOW_AT_COND_QUE_in_conditional760 = new BitSet(new long[]{0x0000032308002050L});
|
||||
public static final BitSet FOLLOW_conditional_in_conditional763 = new BitSet(new long[]{0x0000000000010000L});
|
||||
public static final BitSet FOLLOW_AT_COLON_in_conditional765 = new BitSet(new long[]{0x0000032308002050L});
|
||||
public static final BitSet FOLLOW_logical_or_in_conditional757 = new BitSet(new long[]{0x0000000002000002L});
|
||||
public static final BitSet FOLLOW_AT_COND_QUE_in_conditional760 = new BitSet(new long[]{0x00008886100040A0L});
|
||||
public static final BitSet FOLLOW_conditional_in_conditional763 = new BitSet(new long[]{0x0000000000020000L});
|
||||
public static final BitSet FOLLOW_AT_COLON_in_conditional765 = new BitSet(new long[]{0x00008886100040A0L});
|
||||
public static final BitSet FOLLOW_conditional_in_conditional768 = new BitSet(new long[]{0x0000000000000002L});
|
||||
public static final BitSet FOLLOW_logical_and_in_logical_or787 = new BitSet(new long[]{0x0000000000004002L});
|
||||
public static final BitSet FOLLOW_AT_BOOL_OR_in_logical_or790 = new BitSet(new long[]{0x0000032308002050L});
|
||||
public static final BitSet FOLLOW_logical_and_in_logical_or793 = new BitSet(new long[]{0x0000000000004002L});
|
||||
public static final BitSet FOLLOW_bitwise_or_in_logical_and812 = new BitSet(new long[]{0x0000000000001002L});
|
||||
public static final BitSet FOLLOW_AT_BOOL_AND_in_logical_and815 = new BitSet(new long[]{0x0000032308002050L});
|
||||
public static final BitSet FOLLOW_bitwise_or_in_logical_and818 = new BitSet(new long[]{0x0000000000001002L});
|
||||
public static final BitSet FOLLOW_bitwise_xor_in_bitwise_or837 = new BitSet(new long[]{0x0000000000000082L});
|
||||
public static final BitSet FOLLOW_AT_BIT_OR_in_bitwise_or840 = new BitSet(new long[]{0x0000032308002050L});
|
||||
public static final BitSet FOLLOW_bitwise_xor_in_bitwise_or843 = new BitSet(new long[]{0x0000000000000082L});
|
||||
public static final BitSet FOLLOW_bitwise_and_in_bitwise_xor862 = new BitSet(new long[]{0x0000000000000802L});
|
||||
public static final BitSet FOLLOW_AT_BIT_XOR_in_bitwise_xor865 = new BitSet(new long[]{0x0000032308002050L});
|
||||
public static final BitSet FOLLOW_bitwise_and_in_bitwise_xor868 = new BitSet(new long[]{0x0000000000000802L});
|
||||
public static final BitSet FOLLOW_equality_in_bitwise_and888 = new BitSet(new long[]{0x0000000000000022L});
|
||||
public static final BitSet FOLLOW_AT_BIT_AND_in_bitwise_and891 = new BitSet(new long[]{0x0000032308002050L});
|
||||
public static final BitSet FOLLOW_equality_in_bitwise_and894 = new BitSet(new long[]{0x0000000000000022L});
|
||||
public static final BitSet FOLLOW_relational_in_equality913 = new BitSet(new long[]{0x0000000000840002L});
|
||||
public static final BitSet FOLLOW_set_in_equality916 = new BitSet(new long[]{0x0000032308002050L});
|
||||
public static final BitSet FOLLOW_relational_in_equality925 = new BitSet(new long[]{0x0000000000840002L});
|
||||
public static final BitSet FOLLOW_shift_in_relational944 = new BitSet(new long[]{0x0000000000780002L});
|
||||
public static final BitSet FOLLOW_set_in_relational947 = new BitSet(new long[]{0x0000032308002050L});
|
||||
public static final BitSet FOLLOW_shift_in_relational964 = new BitSet(new long[]{0x0000000000780002L});
|
||||
public static final BitSet FOLLOW_additive_in_shift983 = new BitSet(new long[]{0x0000000000000702L});
|
||||
public static final BitSet FOLLOW_set_in_shift986 = new BitSet(new long[]{0x0000032308002050L});
|
||||
public static final BitSet FOLLOW_additive_in_shift999 = new BitSet(new long[]{0x0000000000000702L});
|
||||
public static final BitSet FOLLOW_multiplicative_in_additive1018 = new BitSet(new long[]{0x0000000100000012L});
|
||||
public static final BitSet FOLLOW_set_in_additive1021 = new BitSet(new long[]{0x0000032308002050L});
|
||||
public static final BitSet FOLLOW_multiplicative_in_additive1030 = new BitSet(new long[]{0x0000000100000012L});
|
||||
public static final BitSet FOLLOW_unary_in_multiplicative1049 = new BitSet(new long[]{0x0000000032000002L});
|
||||
public static final BitSet FOLLOW_set_in_multiplicative1052 = new BitSet(new long[]{0x0000032308002050L});
|
||||
public static final BitSet FOLLOW_unary_in_multiplicative1065 = new BitSet(new long[]{0x0000000032000002L});
|
||||
public static final BitSet FOLLOW_logical_and_in_logical_or787 = new BitSet(new long[]{0x0000000000008002L});
|
||||
public static final BitSet FOLLOW_AT_BOOL_OR_in_logical_or790 = new BitSet(new long[]{0x00008886100040A0L});
|
||||
public static final BitSet FOLLOW_logical_and_in_logical_or793 = new BitSet(new long[]{0x0000000000008002L});
|
||||
public static final BitSet FOLLOW_bitwise_or_in_logical_and812 = new BitSet(new long[]{0x0000000000002002L});
|
||||
public static final BitSet FOLLOW_AT_BOOL_AND_in_logical_and815 = new BitSet(new long[]{0x00008886100040A0L});
|
||||
public static final BitSet FOLLOW_bitwise_or_in_logical_and818 = new BitSet(new long[]{0x0000000000002002L});
|
||||
public static final BitSet FOLLOW_bitwise_xor_in_bitwise_or837 = new BitSet(new long[]{0x0000000000000102L});
|
||||
public static final BitSet FOLLOW_AT_BIT_OR_in_bitwise_or840 = new BitSet(new long[]{0x00008886100040A0L});
|
||||
public static final BitSet FOLLOW_bitwise_xor_in_bitwise_or843 = new BitSet(new long[]{0x0000000000000102L});
|
||||
public static final BitSet FOLLOW_bitwise_and_in_bitwise_xor862 = new BitSet(new long[]{0x0000000000001002L});
|
||||
public static final BitSet FOLLOW_AT_BIT_XOR_in_bitwise_xor865 = new BitSet(new long[]{0x00008886100040A0L});
|
||||
public static final BitSet FOLLOW_bitwise_and_in_bitwise_xor868 = new BitSet(new long[]{0x0000000000001002L});
|
||||
public static final BitSet FOLLOW_equality_in_bitwise_and888 = new BitSet(new long[]{0x0000000000000042L});
|
||||
public static final BitSet FOLLOW_AT_BIT_AND_in_bitwise_and891 = new BitSet(new long[]{0x00008886100040A0L});
|
||||
public static final BitSet FOLLOW_equality_in_bitwise_and894 = new BitSet(new long[]{0x0000000000000042L});
|
||||
public static final BitSet FOLLOW_relational_in_equality913 = new BitSet(new long[]{0x0000000001080002L});
|
||||
public static final BitSet FOLLOW_set_in_equality916 = new BitSet(new long[]{0x00008886100040A0L});
|
||||
public static final BitSet FOLLOW_relational_in_equality925 = new BitSet(new long[]{0x0000000001080002L});
|
||||
public static final BitSet FOLLOW_shift_in_relational944 = new BitSet(new long[]{0x0000000000F00002L});
|
||||
public static final BitSet FOLLOW_set_in_relational947 = new BitSet(new long[]{0x00008886100040A0L});
|
||||
public static final BitSet FOLLOW_shift_in_relational964 = new BitSet(new long[]{0x0000000000F00002L});
|
||||
public static final BitSet FOLLOW_additive_in_shift983 = new BitSet(new long[]{0x0000000000000E02L});
|
||||
public static final BitSet FOLLOW_set_in_shift986 = new BitSet(new long[]{0x00008886100040A0L});
|
||||
public static final BitSet FOLLOW_additive_in_shift999 = new BitSet(new long[]{0x0000000000000E02L});
|
||||
public static final BitSet FOLLOW_multiplicative_in_additive1018 = new BitSet(new long[]{0x0000000200000022L});
|
||||
public static final BitSet FOLLOW_set_in_additive1021 = new BitSet(new long[]{0x00008886100040A0L});
|
||||
public static final BitSet FOLLOW_multiplicative_in_additive1030 = new BitSet(new long[]{0x0000000200000022L});
|
||||
public static final BitSet FOLLOW_unary_in_multiplicative1049 = new BitSet(new long[]{0x0000000064000002L});
|
||||
public static final BitSet FOLLOW_set_in_multiplicative1052 = new BitSet(new long[]{0x00008886100040A0L});
|
||||
public static final BitSet FOLLOW_unary_in_multiplicative1065 = new BitSet(new long[]{0x0000000064000002L});
|
||||
public static final BitSet FOLLOW_postfix_in_unary1084 = new BitSet(new long[]{0x0000000000000002L});
|
||||
public static final BitSet FOLLOW_AT_ADD_in_unary1092 = new BitSet(new long[]{0x0000032308002050L});
|
||||
public static final BitSet FOLLOW_AT_ADD_in_unary1092 = new BitSet(new long[]{0x00008886100040A0L});
|
||||
public static final BitSet FOLLOW_unary_in_unary1095 = new BitSet(new long[]{0x0000000000000002L});
|
||||
public static final BitSet FOLLOW_unary_operator_in_unary1103 = new BitSet(new long[]{0x0000032308002050L});
|
||||
public static final BitSet FOLLOW_unary_operator_in_unary1103 = new BitSet(new long[]{0x00008886100040A0L});
|
||||
public static final BitSet FOLLOW_unary_in_unary1106 = new BitSet(new long[]{0x0000000000000002L});
|
||||
public static final BitSet FOLLOW_AT_SUBTRACT_in_unary_operator1123 = new BitSet(new long[]{0x0000000000000002L});
|
||||
public static final BitSet FOLLOW_AT_BIT_NOT_in_unary_operator1135 = new BitSet(new long[]{0x0000000000000002L});
|
||||
public static final BitSet FOLLOW_AT_BOOL_NOT_in_unary_operator1143 = new BitSet(new long[]{0x0000000000000002L});
|
||||
public static final BitSet FOLLOW_primary_in_postfix1160 = new BitSet(new long[]{0x0000000000000002L});
|
||||
public static final BitSet FOLLOW_NAMESPACE_ID_in_postfix1168 = new BitSet(new long[]{0x0000000008000000L});
|
||||
public static final BitSet FOLLOW_VARIABLE_in_postfix1168 = new BitSet(new long[]{0x0000000010000000L});
|
||||
public static final BitSet FOLLOW_arguments_in_postfix1170 = new BitSet(new long[]{0x0000000000000002L});
|
||||
public static final BitSet FOLLOW_NAMESPACE_ID_in_primary1198 = new BitSet(new long[]{0x0000000000000002L});
|
||||
public static final BitSet FOLLOW_VARIABLE_in_primary1198 = new BitSet(new long[]{0x0000000000000002L});
|
||||
public static final BitSet FOLLOW_numeric_in_primary1206 = new BitSet(new long[]{0x0000000000000002L});
|
||||
public static final BitSet FOLLOW_AT_LPAREN_in_primary1214 = new BitSet(new long[]{0x0000032308002050L});
|
||||
public static final BitSet FOLLOW_conditional_in_primary1217 = new BitSet(new long[]{0x0000000080000000L});
|
||||
public static final BitSet FOLLOW_AT_LPAREN_in_primary1214 = new BitSet(new long[]{0x00008886100040A0L});
|
||||
public static final BitSet FOLLOW_conditional_in_primary1217 = new BitSet(new long[]{0x0000000100000000L});
|
||||
public static final BitSet FOLLOW_AT_RPAREN_in_primary1219 = new BitSet(new long[]{0x0000000000000002L});
|
||||
public static final BitSet FOLLOW_AT_LPAREN_in_arguments1237 = new BitSet(new long[]{0x0000032388002050L});
|
||||
public static final BitSet FOLLOW_conditional_in_arguments1241 = new BitSet(new long[]{0x0000000080020000L});
|
||||
public static final BitSet FOLLOW_AT_COMMA_in_arguments1244 = new BitSet(new long[]{0x0000032308002050L});
|
||||
public static final BitSet FOLLOW_conditional_in_arguments1247 = new BitSet(new long[]{0x0000000080020000L});
|
||||
public static final BitSet FOLLOW_AT_LPAREN_in_arguments1237 = new BitSet(new long[]{0x00008887100040A0L});
|
||||
public static final BitSet FOLLOW_conditional_in_arguments1241 = new BitSet(new long[]{0x0000000100040000L});
|
||||
public static final BitSet FOLLOW_AT_COMMA_in_arguments1244 = new BitSet(new long[]{0x00008886100040A0L});
|
||||
public static final BitSet FOLLOW_conditional_in_arguments1247 = new BitSet(new long[]{0x0000000100040000L});
|
||||
public static final BitSet FOLLOW_AT_RPAREN_in_arguments1253 = new BitSet(new long[]{0x0000000000000002L});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
package org.apache.lucene.expressions.js;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A helper to parse the context of a variable name, which is the base variable, followed by the
|
||||
* sequence of array (integer or string indexed) and member accesses.
|
||||
*/
|
||||
public class VariableContext {
|
||||
|
||||
/**
|
||||
* Represents what a piece of a variable does.
|
||||
*/
|
||||
public static enum Type {
|
||||
/**
|
||||
* A member of the previous context (ie "dot" access).
|
||||
*/
|
||||
MEMBER,
|
||||
|
||||
/**
|
||||
* Brackets containing a string as the "index".
|
||||
*/
|
||||
STR_INDEX,
|
||||
|
||||
/**
|
||||
* Brackets containg an integer index (ie an array).
|
||||
*/
|
||||
INT_INDEX
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of this piece of a variable.
|
||||
*/
|
||||
public final Type type;
|
||||
|
||||
/**
|
||||
* The text of this piece of the variable. Used for {@link Type#MEMBER} and {@link Type#STR_INDEX} types.
|
||||
*/
|
||||
public final String text;
|
||||
|
||||
/**
|
||||
* The integer value for this piece of the variable. Used for {@link Type#INT_INDEX}.
|
||||
*/
|
||||
public final int integer;
|
||||
|
||||
private VariableContext(Type c, String s, int i) {
|
||||
type = c;
|
||||
text = s;
|
||||
integer = i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a normalized javascript variable. All strings in the variable should be single quoted,
|
||||
* and no spaces (except possibly within strings).
|
||||
*/
|
||||
public static final VariableContext[] parse(String variable) {
|
||||
char[] text = variable.toCharArray();
|
||||
List<VariableContext> contexts = new ArrayList<>();
|
||||
int i = addMember(text, 0, contexts); // base variable is a "member" of the global namespace
|
||||
while (i < text.length) {
|
||||
if (text[i] == '[') {
|
||||
if (text[++i] == '\'') {
|
||||
i = addStringIndex(text, i, contexts);
|
||||
} else {
|
||||
i = addIntIndex(text, i, contexts);
|
||||
}
|
||||
++i; // move past end bracket
|
||||
} else { // text[i] == '.', ie object member
|
||||
i = addMember(text, i + 1, contexts);
|
||||
}
|
||||
}
|
||||
return contexts.toArray(new VariableContext[contexts.size()]);
|
||||
}
|
||||
|
||||
// i points to start of member name
|
||||
private static int addMember(final char[] text, int i, List<VariableContext> contexts) {
|
||||
int j = i + 1;
|
||||
while (j < text.length && text[j] != '[' && text[j] != '.') ++j; // find first array or member access
|
||||
contexts.add(new VariableContext(Type.MEMBER, new String(text, i, j - i), -1));
|
||||
return j;
|
||||
}
|
||||
|
||||
// i points to start of single quoted index
|
||||
private static int addStringIndex(final char[] text, int i, List<VariableContext> contexts) {
|
||||
++i; // move past quote
|
||||
int j = i;
|
||||
while (text[j] != '\'') { // find end of single quoted string
|
||||
if (text[j] == '\\') ++j; // skip over escapes
|
||||
++j;
|
||||
}
|
||||
StringBuffer buf = new StringBuffer(j - i); // space for string, without end quote
|
||||
while (i < j) { // copy string to buffer (without begin/end quotes)
|
||||
if (text[i] == '\\') ++i; // unescape escapes
|
||||
buf.append(text[i]);
|
||||
++i;
|
||||
}
|
||||
contexts.add(new VariableContext(Type.STR_INDEX, buf.toString(), -1));
|
||||
return j + 1; // move past quote, return end bracket location
|
||||
}
|
||||
|
||||
// i points to start of integer index
|
||||
private static int addIntIndex(final char[] text, int i, List<VariableContext> contexts) {
|
||||
int j = i + 1;
|
||||
while (text[j] != ']') ++j; // find end of array access
|
||||
int index = Integer.parseInt(new String(text, i, j - i));
|
||||
contexts.add(new VariableContext(Type.INT_INDEX, null, index));
|
||||
return j ;
|
||||
}
|
||||
}
|
|
@ -4,9 +4,13 @@ import org.apache.lucene.document.Document;
|
|||
import org.apache.lucene.document.Field;
|
||||
import org.apache.lucene.document.NumericDocValuesField;
|
||||
import org.apache.lucene.expressions.js.JavascriptCompiler;
|
||||
import org.apache.lucene.expressions.js.VariableContext;
|
||||
import org.apache.lucene.index.DirectoryReader;
|
||||
import org.apache.lucene.index.RandomIndexWriter;
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.queries.function.ValueSource;
|
||||
import org.apache.lucene.queries.function.valuesource.DoubleConstValueSource;
|
||||
import org.apache.lucene.queries.function.valuesource.IntFieldSource;
|
||||
import org.apache.lucene.search.CheckHits;
|
||||
import org.apache.lucene.search.FieldDoc;
|
||||
import org.apache.lucene.search.IndexSearcher;
|
||||
|
@ -19,6 +23,10 @@ import org.apache.lucene.search.TopFieldDocs;
|
|||
import org.apache.lucene.store.Directory;
|
||||
import org.apache.lucene.util.LuceneTestCase;
|
||||
|
||||
import static org.apache.lucene.expressions.js.VariableContext.Type.MEMBER;
|
||||
import static org.apache.lucene.expressions.js.VariableContext.Type.STR_INDEX;
|
||||
import static org.apache.lucene.expressions.js.VariableContext.Type.INT_INDEX;
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
|
@ -224,4 +232,71 @@ public class TestDemoExpressions extends LuceneTestCase {
|
|||
d = (FieldDoc) td.scoreDocs[2];
|
||||
assertEquals(5.2842D, (Double)d.fields[0], 1E-4);
|
||||
}
|
||||
|
||||
public void testStaticExtendedVariableExample() throws Exception {
|
||||
Expression popularity = JavascriptCompiler.compile("doc[\"popularity\"].value");
|
||||
SimpleBindings bindings = new SimpleBindings();
|
||||
bindings.add("doc['popularity'].value", new IntFieldSource("popularity"));
|
||||
Sort sort = new Sort(popularity.getSortField(bindings, true));
|
||||
TopFieldDocs td = searcher.search(new MatchAllDocsQuery(), null, 3, sort);
|
||||
|
||||
FieldDoc d = (FieldDoc)td.scoreDocs[0];
|
||||
assertEquals(20D, (Double)d.fields[0], 1E-4);
|
||||
|
||||
d = (FieldDoc)td.scoreDocs[1];
|
||||
assertEquals(5D, (Double)d.fields[0], 1E-4);
|
||||
|
||||
d = (FieldDoc)td.scoreDocs[2];
|
||||
assertEquals(2D, (Double)d.fields[0], 1E-4);
|
||||
}
|
||||
|
||||
public void testDynamicExtendedVariableExample() throws Exception {
|
||||
Expression popularity = JavascriptCompiler.compile("doc['popularity'].value + magicarray[0] + fourtytwo");
|
||||
|
||||
// The following is an example of how to write bindings which parse the variable name into pieces.
|
||||
// Note, however, that this requires a lot of error checking. Each "error case" below should be
|
||||
// filled in with proper error messages for a real use case.
|
||||
Bindings bindings = new Bindings() {
|
||||
@Override
|
||||
public ValueSource getValueSource(String name) {
|
||||
VariableContext[] var = VariableContext.parse(name);
|
||||
assert var[0].type == MEMBER;
|
||||
String base = var[0].text;
|
||||
if (base.equals("doc")) {
|
||||
if (var.length > 1 && var[1].type == STR_INDEX) {
|
||||
String field = var[1].text;
|
||||
if (var.length > 2 && var[2].type == MEMBER && var[2].text.equals("value")) {
|
||||
return new IntFieldSource(field);
|
||||
} else {
|
||||
fail("member: " + var[2].text);// error case, non/missing "value" member access
|
||||
}
|
||||
} else {
|
||||
fail();// error case, doc should be a str indexed array
|
||||
}
|
||||
} else if (base.equals("magicarray")) {
|
||||
if (var.length > 1 && var[1].type == INT_INDEX) {
|
||||
return new DoubleConstValueSource(2048);
|
||||
} else {
|
||||
fail();// error case, magic array isn't an array
|
||||
}
|
||||
} else if (base.equals("fourtytwo")) {
|
||||
return new DoubleConstValueSource(42);
|
||||
} else {
|
||||
fail();// error case (variable doesn't exist)
|
||||
}
|
||||
throw new IllegalArgumentException("Illegal reference '" + name + "'");
|
||||
}
|
||||
};
|
||||
Sort sort = new Sort(popularity.getSortField(bindings, false));
|
||||
TopFieldDocs td = searcher.search(new MatchAllDocsQuery(), null, 3, sort);
|
||||
|
||||
FieldDoc d = (FieldDoc)td.scoreDocs[0];
|
||||
assertEquals(2092D, (Double)d.fields[0], 1E-4);
|
||||
|
||||
d = (FieldDoc)td.scoreDocs[1];
|
||||
assertEquals(2095D, (Double)d.fields[0], 1E-4);
|
||||
|
||||
d = (FieldDoc)td.scoreDocs[2];
|
||||
assertEquals(2110D, (Double)d.fields[0], 1E-4);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.apache.lucene.expressions.js;
|
|||
|
||||
import java.text.ParseException;
|
||||
|
||||
import org.apache.lucene.expressions.Expression;
|
||||
import org.apache.lucene.util.LuceneTestCase;
|
||||
|
||||
public class TestJavascriptCompiler extends LuceneTestCase {
|
||||
|
@ -29,39 +30,60 @@ public class TestJavascriptCompiler extends LuceneTestCase {
|
|||
assertNotNull(JavascriptCompiler.compile("logn(2, 20+10-5.0)"));
|
||||
}
|
||||
|
||||
public void testValidNamespaces() throws Exception {
|
||||
assertNotNull(JavascriptCompiler.compile("object.valid0"));
|
||||
assertNotNull(JavascriptCompiler.compile("object0.object1.valid1"));
|
||||
public void testValidVariables() throws Exception {
|
||||
doTestValidVariable("object.valid0");
|
||||
doTestValidVariable("object0.object1.valid1");
|
||||
doTestValidVariable("array0[1]");
|
||||
doTestValidVariable("array0[1].x");
|
||||
doTestValidVariable("multiarray[0][0]");
|
||||
doTestValidVariable("multiarray[0][0].x");
|
||||
doTestValidVariable("strindex['hello']");
|
||||
doTestValidVariable("strindex[\"hello\"]", "strindex['hello']");
|
||||
doTestValidVariable("empty['']");
|
||||
doTestValidVariable("empty[\"\"]", "empty['']");
|
||||
doTestValidVariable("strindex['\u304A\u65E9\u3046\u3054\u3056\u3044\u307E\u3059']");
|
||||
doTestValidVariable("strindex[\"\u304A\u65E9\u3046\u3054\u3056\u3044\u307E\u3059\"]",
|
||||
"strindex['\u304A\u65E9\u3046\u3054\u3056\u3044\u307E\u3059']");
|
||||
doTestValidVariable("escapes['\\\\\\'']");
|
||||
doTestValidVariable("escapes[\"\\\\\\\"\"]", "escapes['\\\\\"']");
|
||||
doTestValidVariable("mixed[23]['key'].sub.sub");
|
||||
doTestValidVariable("mixed[23]['key'].sub.sub[1]");
|
||||
doTestValidVariable("mixed[23]['key'].sub.sub[1].sub");
|
||||
doTestValidVariable("mixed[23]['key'].sub.sub[1].sub['abc']");
|
||||
}
|
||||
|
||||
public void testInvalidNamespaces() throws Exception {
|
||||
try {
|
||||
JavascriptCompiler.compile("object.0invalid");
|
||||
fail();
|
||||
}
|
||||
catch (ParseException expected) {
|
||||
//expected
|
||||
void doTestValidVariable(String variable) throws Exception {
|
||||
doTestValidVariable(variable, variable);
|
||||
}
|
||||
|
||||
try {
|
||||
JavascriptCompiler.compile("0.invalid");
|
||||
fail();
|
||||
}
|
||||
catch (ParseException expected) {
|
||||
//expected
|
||||
void doTestValidVariable(String variable, String output) throws Exception {
|
||||
Expression e = JavascriptCompiler.compile(variable);
|
||||
assertNotNull(e);
|
||||
assertEquals(1, e.variables.length);
|
||||
assertEquals(output, e.variables[0]);
|
||||
}
|
||||
|
||||
try {
|
||||
JavascriptCompiler.compile("object..invalid");
|
||||
fail();
|
||||
}
|
||||
catch (ParseException expected) {
|
||||
//expected
|
||||
public void testInvalidVariables() throws Exception {
|
||||
doTestInvalidVariable("object.0invalid");
|
||||
doTestInvalidVariable("0.invalid");
|
||||
doTestInvalidVariable("object..invalid");
|
||||
doTestInvalidVariable(".invalid");
|
||||
doTestInvalidVariable("negative[-1]");
|
||||
doTestInvalidVariable("float[1.0]");
|
||||
doTestInvalidVariable("missing_end['abc]");
|
||||
doTestInvalidVariable("missing_end[\"abc]");
|
||||
doTestInvalidVariable("missing_begin[abc']");
|
||||
doTestInvalidVariable("missing_begin[abc\"]");
|
||||
doTestInvalidVariable("dot_needed[1]sub");
|
||||
doTestInvalidVariable("dot_needed[1]sub");
|
||||
doTestInvalidVariable("opposite_escape['\\\"']");
|
||||
doTestInvalidVariable("opposite_escape[\"\\'\"]");
|
||||
}
|
||||
|
||||
void doTestInvalidVariable(String variable) {
|
||||
try {
|
||||
JavascriptCompiler.compile(".invalid");
|
||||
fail();
|
||||
JavascriptCompiler.compile(variable);
|
||||
fail("\"" + variable + " should have failed to compile");
|
||||
}
|
||||
catch (ParseException expected) {
|
||||
//expected
|
||||
|
@ -152,4 +174,30 @@ public class TestJavascriptCompiler extends LuceneTestCase {
|
|||
assertTrue(expected.getMessage().contains("arguments for method call"));
|
||||
}
|
||||
}
|
||||
|
||||
public void testVariableNormalization() throws Exception {
|
||||
// multiple double quotes
|
||||
Expression x = JavascriptCompiler.compile("foo[\"a\"][\"b\"]");
|
||||
assertEquals("foo['a']['b']", x.variables[0]);
|
||||
|
||||
// single and double in the same var
|
||||
x = JavascriptCompiler.compile("foo['a'][\"b\"]");
|
||||
assertEquals("foo['a']['b']", x.variables[0]);
|
||||
|
||||
// escapes remain the same in single quoted strings
|
||||
x = JavascriptCompiler.compile("foo['\\\\\\'\"']");
|
||||
assertEquals("foo['\\\\\\'\"']", x.variables[0]);
|
||||
|
||||
// single quotes are escaped
|
||||
x = JavascriptCompiler.compile("foo[\"'\"]");
|
||||
assertEquals("foo['\\'']", x.variables[0]);
|
||||
|
||||
// double quotes are unescaped
|
||||
x = JavascriptCompiler.compile("foo[\"\\\"\"]");
|
||||
assertEquals("foo['\"']", x.variables[0]);
|
||||
|
||||
// backslash escapes are kept the same
|
||||
x = JavascriptCompiler.compile("foo['\\\\'][\"\\\\\"]");
|
||||
assertEquals("foo['\\\\']['\\\\']", x.variables[0]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
package org.apache.lucene.expressions.js;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import org.apache.lucene.util.LuceneTestCase;
|
||||
|
||||
import static org.apache.lucene.expressions.js.VariableContext.Type.MEMBER;
|
||||
import static org.apache.lucene.expressions.js.VariableContext.Type.STR_INDEX;
|
||||
import static org.apache.lucene.expressions.js.VariableContext.Type.INT_INDEX;
|
||||
|
||||
public class TestVariableContext extends LuceneTestCase {
|
||||
|
||||
public void testSimpleVar() {
|
||||
VariableContext[] x = VariableContext.parse("foo");
|
||||
assertEquals(1, x.length);
|
||||
assertEquals(x[0].type, MEMBER);
|
||||
assertEquals(x[0].text, "foo");
|
||||
}
|
||||
|
||||
public void testEmptyString() {
|
||||
VariableContext[] x = VariableContext.parse("foo['']");
|
||||
assertEquals(2, x.length);
|
||||
assertEquals(x[1].type, STR_INDEX);
|
||||
assertEquals(x[1].text, "");
|
||||
}
|
||||
|
||||
public void testUnescapeString() {
|
||||
VariableContext[] x = VariableContext.parse("foo['\\'\\\\']");
|
||||
assertEquals(2, x.length);
|
||||
assertEquals(x[1].type, STR_INDEX);
|
||||
assertEquals(x[1].text, "'\\");
|
||||
}
|
||||
|
||||
public void testMember() {
|
||||
VariableContext[] x = VariableContext.parse("foo.bar");
|
||||
assertEquals(2, x.length);
|
||||
assertEquals(x[1].type, MEMBER);
|
||||
assertEquals(x[1].text, "bar");
|
||||
}
|
||||
|
||||
public void testMemberFollowedByMember() {
|
||||
VariableContext[] x = VariableContext.parse("foo.bar.baz");
|
||||
assertEquals(3, x.length);
|
||||
assertEquals(x[2].type, MEMBER);
|
||||
assertEquals(x[2].text, "baz");
|
||||
}
|
||||
|
||||
public void testMemberFollowedByIntArray() {
|
||||
VariableContext[] x = VariableContext.parse("foo.bar[1]");
|
||||
assertEquals(3, x.length);
|
||||
assertEquals(x[2].type, INT_INDEX);
|
||||
assertEquals(x[2].integer, 1);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue