You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by us...@apache.org on 2015/08/07 09:10:41 UTC
svn commit: r1694614 [1/4] - in /lucene/dev/trunk: lucene/
lucene/expressions/
lucene/expressions/src/java/org/apache/lucene/expressions/js/
lucene/expressions/src/test/org/apache/lucene/expressions/js/
lucene/licenses/ solr/core/ solr/licenses/
Author: uschindler
Date: Fri Aug 7 07:10:40 2015
New Revision: 1694614
URL: http://svn.apache.org/r1694614
Log:
LUCENE-6417: Upgrade ANTLR used in expressions module to version 4.5
Added:
lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/JavascriptBaseVisitor.java (with props)
lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/JavascriptErrorHandlingLexer.java (with props)
lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/JavascriptLexer.tokens (with props)
lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/JavascriptParserErrorStrategy.java (with props)
lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/JavascriptVisitor.java (with props)
lucene/dev/trunk/lucene/licenses/antlr4-runtime-4.5.jar.sha1 (with props)
lucene/dev/trunk/lucene/licenses/antlr4-runtime-LICENSE-BSD.txt (with props)
lucene/dev/trunk/lucene/licenses/antlr4-runtime-NOTICE.txt (with props)
Removed:
lucene/dev/trunk/lucene/licenses/antlr-runtime-3.5.jar.sha1
lucene/dev/trunk/lucene/licenses/antlr-runtime-LICENSE-BSD_LIKE.txt
lucene/dev/trunk/lucene/licenses/antlr-runtime-NOTICE.txt
lucene/dev/trunk/solr/licenses/antlr-runtime-3.5.jar.sha1
lucene/dev/trunk/solr/licenses/antlr-runtime-LICENSE-BSD_LIKE.txt
lucene/dev/trunk/solr/licenses/antlr-runtime-NOTICE.txt
Modified:
lucene/dev/trunk/lucene/CHANGES.txt
lucene/dev/trunk/lucene/expressions/build.xml
lucene/dev/trunk/lucene/expressions/ivy.xml
lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/Javascript.g
lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/Javascript.tokens
lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/JavascriptCompiler.java
lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/JavascriptLexer.java
lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/JavascriptParser.java
lucene/dev/trunk/lucene/expressions/src/test/org/apache/lucene/expressions/js/TestJavascriptCompiler.java
lucene/dev/trunk/lucene/ivy-versions.properties
lucene/dev/trunk/solr/core/ivy.xml
Modified: lucene/dev/trunk/lucene/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/CHANGES.txt?rev=1694614&r1=1694613&r2=1694614&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/CHANGES.txt (original)
+++ lucene/dev/trunk/lucene/CHANGES.txt Fri Aug 7 07:10:40 2015
@@ -58,6 +58,11 @@ Optimizations
* LUCENE-6720: ValueSourceScorer, returned from
FunctionValues.getRangeScorer(), now uses TwoPhaseIterator. (David Smiley)
+Other
+
+* LUCENE-6417: Upgrade ANTLR used in expressions module to version 4.5.
+ (Jack Conradson via Uwe Schindler)
+
======================= Lucene 5.3.0 =======================
New Features
Modified: lucene/dev/trunk/lucene/expressions/build.xml
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/expressions/build.xml?rev=1694614&r1=1694613&r2=1694614&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/expressions/build.xml (original)
+++ lucene/dev/trunk/lucene/expressions/build.xml Fri Aug 7 07:10:40 2015
@@ -51,7 +51,7 @@
<target name="regenerate" depends="run-antlr"/>
<target name="resolve-antlr" xmlns:ivy="antlib:org.apache.ivy.ant">
- <ivy:cachepath organisation="org.antlr" module="antlr" revision="3.5"
+ <ivy:cachepath organisation="org.antlr" module="antlr4" revision="4.5"
inline="true" conf="default" type="jar" pathid="antlr.classpath"/>
</target>
@@ -97,13 +97,15 @@
<replace-value property="grammar.matchpath" value="${grammar.path}${file.separator}" from="\" to="\\"/>
<property name="-grammar.relative.path" location="${grammar.path}" relative="true"/>
<replace-value property="grammar.relative.path" value="${-grammar.relative.path}${file.separator}" from="${file.separator}" to="/"/>
- <java classname="org.antlr.Tool" fork="true" failonerror="true" classpathref="antlr.classpath" taskname="antlr">
+ <java classname="org.antlr.v4.Tool" fork="true" failonerror="true" classpathref="antlr.classpath" taskname="antlr">
<sysproperty key="file.encoding" value="UTF-8"/>
<sysproperty key="user.language" value="en"/>
<sysproperty key="user.country" value="US"/>
<sysproperty key="user.variant" value=""/>
- <arg value="-verbose"/>
- <arg value="-make"/>
+ <arg value="-package"/>
+ <arg value="org.apache.lucene.expressions.@{package}"/>
+ <arg value="-no-listener"/>
+ <arg value="-visitor"/>
<arg value="-o"/>
<arg path="${grammar.path}"/>
<arg path="${grammar.path}/@{grammar}.g"/>
@@ -111,18 +113,28 @@
<!-- replace absolute paths by relative ones -->
<replace file="${grammar.path}/@{grammar}Parser.java" token="${grammar.matchpath}" value="${grammar.relative.path}" encoding="UTF-8"/>
<replace file="${grammar.path}/@{grammar}Lexer.java" token="${grammar.matchpath}" value="${grammar.relative.path}" encoding="UTF-8"/>
- <!-- make the generated classes package private (it's an antlr option with 4.0) -->
+ <replace file="${grammar.path}/@{grammar}Visitor.java" token="${grammar.matchpath}" value="${grammar.relative.path}" encoding="UTF-8"/>
+ <replace file="${grammar.path}/@{grammar}BaseVisitor.java" token="${grammar.matchpath}" value="${grammar.relative.path}" encoding="UTF-8"/>
+ <!-- make the generated classes package private -->
<replace file="${grammar.path}/@{grammar}Parser.java" token="public class @{grammar}Parser" value="class @{grammar}Parser" encoding="UTF-8"/>
<replace file="${grammar.path}/@{grammar}Lexer.java" token="public class @{grammar}Lexer" value="class @{grammar}Lexer" encoding="UTF-8"/>
+ <replace file="${grammar.path}/@{grammar}Visitor.java" token="public interface @{grammar}Visitor" value="interface @{grammar}Visitor" encoding="UTF-8"/>
+ <replace file="${grammar.path}/@{grammar}BaseVisitor.java" token="public class @{grammar}BaseVisitor" value="class @{grammar}BaseVisitor" encoding="UTF-8"/>
<!-- nuke timestamps in generated files -->
<replaceregexp file="${grammar.path}/@{grammar}Parser.java" match=".*" replace="\/\/ ANTLR GENERATED CODE: DO NOT EDIT" encoding="UTF-8"/>
<replaceregexp file="${grammar.path}/@{grammar}Lexer.java" match=".*" replace="\/\/ ANTLR GENERATED CODE: DO NOT EDIT" encoding="UTF-8"/>
+ <replaceregexp file="${grammar.path}/@{grammar}Visitor.java" match=".*" replace="\/\/ ANTLR GENERATED CODE: DO NOT EDIT" encoding="UTF-8"/>
+ <replaceregexp file="${grammar.path}/@{grammar}BaseVisitor.java" match=".*" replace="\/\/ ANTLR GENERATED CODE: DO NOT EDIT" encoding="UTF-8"/>
<!-- remove tabs in antlr generated files -->
<replaceregexp file="${grammar.path}/@{grammar}Parser.java" match="\t" flags="g" replace=" " encoding="UTF-8"/>
<replaceregexp file="${grammar.path}/@{grammar}Lexer.java" match="\t" flags="g" replace=" " encoding="UTF-8"/>
+ <replaceregexp file="${grammar.path}/@{grammar}Visitor.java" match="\t" flags="g" replace=" " encoding="UTF-8"/>
+ <replaceregexp file="${grammar.path}/@{grammar}BaseVisitor.java" match="\t" flags="g" replace=" " encoding="UTF-8"/>
<!-- fix line endings -->
<fixcrlf file="${grammar.path}/@{grammar}Parser.java"/>
<fixcrlf file="${grammar.path}/@{grammar}Lexer.java"/>
+ <fixcrlf file="${grammar.path}/@{grammar}Visitor.java"/>
+ <fixcrlf file="${grammar.path}/@{grammar}BaseVisitor.java"/>
</sequential>
</macrodef>
</project>
Modified: lucene/dev/trunk/lucene/expressions/ivy.xml
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/expressions/ivy.xml?rev=1694614&r1=1694613&r2=1694614&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/expressions/ivy.xml (original)
+++ lucene/dev/trunk/lucene/expressions/ivy.xml Fri Aug 7 07:10:40 2015
@@ -22,7 +22,7 @@
<conf name="compile" transitive="false"/>
</configurations>
<dependencies>
- <dependency org="org.antlr" name="antlr-runtime" rev="${/org.antlr/antlr-runtime}" conf="compile"/>
+ <dependency org="org.antlr" name="antlr4-runtime" rev="${/org.antlr/antlr4-runtime}" conf="compile"/>
<dependency org="org.ow2.asm" name="asm" rev="${/org.ow2.asm/asm}" conf="compile"/>
<dependency org="org.ow2.asm" name="asm-commons" rev="${/org.ow2.asm/asm-commons}" conf="compile"/>
<exclude org="*" ext="*" matcher="regexp" type="${ivy.exclude.types}"/>
Modified: lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/Javascript.g
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/Javascript.g?rev=1694614&r1=1694613&r2=1694614&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/Javascript.g (original)
+++ lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/Javascript.g Fri Aug 7 07:10:40 2015
@@ -1,417 +1,89 @@
/*
- Javascript.g
- An expression syntax based on ECMAScript/Javascript.
-
- This file was adapted from a general ECMAScript language definition at http://research.xebic.com/es3.
- The major changes are the following:
- * Stripped grammar of all parts not relevant for expression syntax.
- * Stripped grammar of unicode character support.
- * Added override function for customized error handling.
- * Renaming of many grammar rules.
- * Removal of annotations no longer relevant for stripped pieces.
-
- The Original Copyright Notice is the following:
-
- Copyrights 2008-2009 Xebic Reasearch BV. All rights reserved..
- Original work by Patrick Hulsmeijer.
-
- This ANTLR 3 LL(*) grammar is based on Ecma-262 3rd edition (JavaScript 1.5, JScript 5.5).
- The annotations refer to the "A Grammar Summary" section (e.g. A.1 Lexical Grammar)
- and the numbers in parenthesis to the paragraph numbers (e.g. (7.8) ).
- This document is best viewed with ANTLRWorks (www.antlr.org).
-
- Software License Agreement (BSD License)
-
- Copyright (c) 2008-2010, Xebic Research B.V.
- All rights reserved.
-
- Redistribution and use of this software in source and binary forms, with or without modification, are
- permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
-
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
-
- * Neither the name of Xebic Research B.V. nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of Xebic Research B.V.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
- WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 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.
*/
-// ***********************************************************************
-// * ANTLRv3 grammar for Lucene expression language.
-// ***********************************************************************
-
-grammar Javascript;
-
-options {
- language = Java;
- output = AST;
- ASTLabelType=CommonTree;
-}
-
-tokens
-{
- AT_LPAREN = '(' ;
- AT_RPAREN = ')' ;
- AT_DOT = '.' ;
- AT_COMMA = ',' ;
- AT_COLON = ':' ;
-
- AT_COMP_LT = '<' ;
- AT_COMP_LTE = '<=' ;
- AT_COMP_EQ = '==' ;
- AT_COMP_NEQ = '!=' ;
- AT_COMP_GTE = '>=' ;
- AT_COMP_GT = '>' ;
-
- AT_BOOL_NOT = '!' ;
- AT_BOOL_AND = '&&' ;
- AT_BOOL_OR = '||' ;
- AT_COND_QUE = '?' ;
-
- AT_NEGATE ;
- AT_ADD = '+' ;
- AT_SUBTRACT = '-' ;
- AT_MULTIPLY = '*' ;
- AT_DIVIDE = '/' ;
- AT_MODULO = '%' ;
-
- AT_BIT_SHL = '<<' ;
- AT_BIT_SHR = '>>' ;
- AT_BIT_SHU = '>>>';
- AT_BIT_AND = '&' ;
- AT_BIT_OR = '|' ;
- AT_BIT_XOR = '^' ;
- AT_BIT_NOT = '~' ;
-
- AT_CALL ;
-}
-
-// ***********************************************************************
-// * Java Package
-// ***********************************************************************
-
-@lexer::header {
-package org.apache.lucene.expressions.js;
-
-import java.text.ParseException;
-}
-
-@parser::header {
-package org.apache.lucene.expressions.js;
-
-import java.text.ParseException;
-}
-
-// ***********************************************************************
-// * Error Handling
-// ***********************************************************************
-
-@lexer::members {
-
-@Override
-public void displayRecognitionError(String[] tokenNames, RecognitionException re) {
- String message = " unexpected character '" + (char)re.c
- + "' at position (" + re.charPositionInLine + ").";
- ParseException parseException = new ParseException(message, re.charPositionInLine);
- parseException.initCause(re);
- throw new RuntimeException(parseException);
-}
-
-}
-
-@parser::members {
-
-@Override
-public void displayRecognitionError(String[] tokenNames, RecognitionException re) {
- String message;
-
- if (re.token == null) {
- message = " unknown error (missing token).";
- }
- else if (re instanceof UnwantedTokenException) {
- message = " extraneous " + getReadableTokenString(re.token)
- + " at position (" + re.charPositionInLine + ").";
- }
- else if (re instanceof MissingTokenException) {
- message = " missing " + getReadableTokenString(re.token)
- + " at position (" + re.charPositionInLine + ").";
- }
- else if (re instanceof NoViableAltException) {
- switch (re.token.getType()) {
- case EOF:
- message = " unexpected end of expression.";
- break;
- default:
- message = " invalid sequence of tokens near " + getReadableTokenString(re.token)
- + " at position (" + re.charPositionInLine + ").";
- break;
- }
- }
- else {
- message = " unexpected token " + getReadableTokenString(re.token)
- + " at position (" + re.charPositionInLine + ").";
- }
- ParseException parseException = new ParseException(message, re.charPositionInLine);
- parseException.initCause(re);
- throw new RuntimeException(parseException);
-}
-
-public static String getReadableTokenString(Token token) {
- if (token == null) {
- return "unknown token";
- }
-
- switch (token.getType()) {
- case AT_LPAREN:
- return "open parenthesis '('";
- case AT_RPAREN:
- return "close parenthesis ')'";
- case AT_COMP_LT:
- return "less than '<'";
- case AT_COMP_LTE:
- return "less than or equal '<='";
- case AT_COMP_GT:
- return "greater than '>'";
- case AT_COMP_GTE:
- return "greater than or equal '>='";
- case AT_COMP_EQ:
- return "equal '=='";
- case AT_NEGATE:
- return "negate '!='";
- case AT_BOOL_NOT:
- return "boolean not '!'";
- case AT_BOOL_AND:
- return "boolean and '&&'";
- case AT_BOOL_OR:
- return "boolean or '||'";
- case AT_COND_QUE:
- return "conditional '?'";
- case AT_ADD:
- return "addition '+'";
- case AT_SUBTRACT:
- return "subtraction '-'";
- case AT_MULTIPLY:
- return "multiplication '*'";
- case AT_DIVIDE:
- return "division '/'";
- case AT_MODULO:
- return "modulo '\%'";
- case AT_BIT_SHL:
- return "bit shift left '<<'";
- case AT_BIT_SHR:
- return "bit shift right '>>'";
- case AT_BIT_SHU:
- return "unsigned bit shift right '>>>'";
- case AT_BIT_AND:
- return "bitwise and '&'";
- case AT_BIT_OR:
- return "bitwise or '|'";
- case AT_BIT_XOR:
- return "bitwise xor '^'";
- case AT_BIT_NOT:
- return "bitwise not '~'";
- case ID:
- return "identifier '" + token.getText() + "'";
- case DECIMAL:
- return "decimal '" + token.getText() + "'";
- case OCTAL:
- return "octal '" + token.getText() + "'";
- case HEX:
- return "hex '" + token.getText() + "'";
- case EOF:
- return "end of expression";
- default:
- return "'" + token.getText() + "'";
- }
-}
-
-}
-
-// ***********************************************************************
-// * Parser Rules
-// ***********************************************************************
-
-expression
- : conditional EOF!
- ;
-
-conditional
- : logical_or (AT_COND_QUE^ conditional AT_COLON! conditional)?
- ;
-
-logical_or
- : logical_and (AT_BOOL_OR^ logical_and)*
- ;
-
-logical_and
- : bitwise_or (AT_BOOL_AND^ bitwise_or)*
- ;
-
-bitwise_or
- : bitwise_xor (AT_BIT_OR^ bitwise_xor)*
- ;
-
-bitwise_xor
- : bitwise_and (AT_BIT_XOR^ bitwise_and)*
- ;
-
-bitwise_and
- : equality (AT_BIT_AND^ equality)*
- ;
-
-equality
- : relational ((AT_COMP_EQ | AT_COMP_NEQ)^ relational)*
- ;
-
-relational
- : shift ((AT_COMP_LT | AT_COMP_GT | AT_COMP_LTE | AT_COMP_GTE)^ shift)*
- ;
-
-shift
- : additive ((AT_BIT_SHL | AT_BIT_SHR | AT_BIT_SHU)^ additive)*
- ;
-
-additive
- : multiplicative ((AT_ADD | AT_SUBTRACT)^ multiplicative)*
- ;
-
-multiplicative
- : unary ((AT_MULTIPLY | AT_DIVIDE | AT_MODULO)^ unary)*
- ;
-
-unary
- : postfix
- | AT_ADD! unary
- | unary_operator^ unary
- ;
-
-unary_operator
- : AT_SUBTRACT -> AT_NEGATE
- | AT_BIT_NOT
- | AT_BOOL_NOT
- ;
-
-postfix
- : primary
- | VARIABLE arguments -> ^(AT_CALL VARIABLE arguments?)
- ;
-
-primary
- : VARIABLE
- | numeric
- | AT_LPAREN! conditional AT_RPAREN!
- ;
-
-arguments
- : AT_LPAREN! (conditional (AT_COMMA! conditional)*)? AT_RPAREN!
- ;
-
-numeric
- : HEX | OCTAL | DECIMAL
- ;
-
-// ***********************************************************************
-// * Lexer Rules
-// ***********************************************************************
-
-VARIABLE
- : OBJECT (AT_DOT OBJECT)*
- ;
-
-fragment
-OBJECT
- : ID ARRAY*
- ;
-
-fragment
-ARRAY
- : '[' STRING ']'
- | '[' DECIMALINTEGER ']'
- ;
-
-fragment
-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();}
- ;
-
-DECIMAL
- : DECIMALINTEGER AT_DOT DECIMALDIGIT* EXPONENT?
- | AT_DOT DECIMALDIGIT+ EXPONENT?
- | DECIMALINTEGER EXPONENT?
- ;
-
-OCTAL
- : '0' OCTALDIGIT+
- ;
-
-HEX
- : ('0x'|'0X') HEXDIGIT+
- ;
-
-fragment
-DECIMALINTEGER
- : '0'
- | '1'..'9' DECIMALDIGIT*
- ;
-
-fragment
-EXPONENT
- : ('e'|'E') ('+'|'-')? DECIMALDIGIT+
- ;
+/*
+ * ANTLRv4 grammar for the Lucene expressions language
+ */
-fragment
-DECIMALDIGIT
- : '0'..'9'
- ;
+grammar Javascript;
-fragment
-HEXDIGIT
- : DECIMALDIGIT
- | 'a'..'f'
- | 'A'..'F'
+compile
+ : expression EOF
;
-fragment
-OCTALDIGIT
- : '0'..'7'
+expression
+ : LP expression RP # precedence
+ | ( OCTAL | HEX | DECIMAL ) # numeric
+ | VARIABLE ( LP (expression (COMMA expression)*)? RP )? # external
+ | ( BOOLNOT | BWNOT | ADD | SUB ) expression # unary
+ | expression ( MUL | DIV | REM ) expression # muldiv
+ | expression ( ADD | SUB ) expression # addsub
+ | expression ( LSH | RSH | USH ) expression # bwshift
+ | expression ( LT | LTE | GT | GTE ) expression # boolcomp
+ | expression ( EQ | NE ) expression # booleqne
+ | expression BWAND expression # bwand
+ | expression BWXOR expression # bwxor
+ | expression BWOR expression # bwor
+ | expression BOOLAND expression # booland
+ | expression BOOLOR expression # boolor
+ | <assoc=right> expression COND expression COLON expression # conditional
+ ;
+
+LP: [(];
+RP: [)];
+COMMA: [,];
+BOOLNOT: [!];
+BWNOT: [~];
+MUL: [*];
+DIV: [/];
+REM: [%];
+ADD: [+];
+SUB: [\-];
+LSH: '<<';
+RSH: '>>';
+USH: '>>>';
+LT: [<];
+LTE: '<=';
+GT: [>];
+GTE: '>=';
+EQ: '==';
+NE: '!=';
+BWAND: [&];
+BWXOR: [^];
+BWOR: [|];
+BOOLAND: '&&';
+BOOLOR: '||';
+COND: [?];
+COLON: [:];
+
+WS: [ \t\n\r]+ -> skip;
+
+VARIABLE: ID ARRAY* ( [.] ID ARRAY* )*;
+fragment ARRAY: [[] ( STRING | INTEGER ) [\]];
+fragment ID: [_$a-zA-Z] [_$a-zA-Z0-9]*;
+fragment STRING
+ : ['] ( '\\\'' | '\\\\' | ~[\\'] )*? [']
+ | ["] ( '\\"' | '\\\\' | ~[\\"] )*? ["]
+ ;
+
+OCTAL: [0] [0-7]+;
+HEX: [0] [xX] [0-9a-fA-F]+;
+DECIMAL: ( INTEGER ( [.] [0-9]* )? | [.] [0-9]+ ) ( [eE] [+\-]? [0-9]+ )?;
+fragment INTEGER
+ : [0]
+ | [1-9] [0-9]*
;
Modified: lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/Javascript.tokens
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/Javascript.tokens?rev=1694614&r1=1694613&r2=1694614&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/Javascript.tokens (original)
+++ lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/Javascript.tokens Fri Aug 7 07:10:40 2015
@@ -1,72 +1,40 @@
-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
+LP=1
+RP=2
+COMMA=3
+BOOLNOT=4
+BWNOT=5
+MUL=6
+DIV=7
+REM=8
+ADD=9
+SUB=10
+LSH=11
+RSH=12
+USH=13
+LT=14
+LTE=15
+GT=16
+GTE=17
+EQ=18
+NE=19
+BWAND=20
+BWXOR=21
+BWOR=22
+BOOLAND=23
+BOOLOR=24
+COND=25
+COLON=26
+WS=27
+VARIABLE=28
+OCTAL=29
+HEX=30
+DECIMAL=31
+'<<'=11
+'>>'=12
+'>>>'=13
+'<='=15
+'>='=17
+'=='=18
+'!='=19
+'&&'=23
+'||'=24
Added: lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/JavascriptBaseVisitor.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/JavascriptBaseVisitor.java?rev=1694614&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/JavascriptBaseVisitor.java (added)
+++ lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/JavascriptBaseVisitor.java Fri Aug 7 07:10:40 2015
@@ -0,0 +1,127 @@
+// ANTLR GENERATED CODE: DO NOT EDIT
+package org.apache.lucene.expressions.js;
+import org.antlr.v4.runtime.misc.NotNull;
+import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;
+
+/**
+ * This class provides an empty implementation of {@link JavascriptVisitor},
+ * which can be extended to create a visitor which only needs to handle a subset
+ * of the available methods.
+ *
+ * @param <T> The return type of the visit operation. Use {@link Void} for
+ * operations with no return type.
+ */
+class JavascriptBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements JavascriptVisitor<T> {
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.</p>
+ */
+ @Override public T visitCompile(JavascriptParser.CompileContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.</p>
+ */
+ @Override public T visitConditional(JavascriptParser.ConditionalContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.</p>
+ */
+ @Override public T visitBoolor(JavascriptParser.BoolorContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.</p>
+ */
+ @Override public T visitBoolcomp(JavascriptParser.BoolcompContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.</p>
+ */
+ @Override public T visitNumeric(JavascriptParser.NumericContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.</p>
+ */
+ @Override public T visitAddsub(JavascriptParser.AddsubContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.</p>
+ */
+ @Override public T visitUnary(JavascriptParser.UnaryContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.</p>
+ */
+ @Override public T visitPrecedence(JavascriptParser.PrecedenceContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.</p>
+ */
+ @Override public T visitMuldiv(JavascriptParser.MuldivContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.</p>
+ */
+ @Override public T visitExternal(JavascriptParser.ExternalContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.</p>
+ */
+ @Override public T visitBwshift(JavascriptParser.BwshiftContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.</p>
+ */
+ @Override public T visitBwor(JavascriptParser.BworContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.</p>
+ */
+ @Override public T visitBooland(JavascriptParser.BoolandContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.</p>
+ */
+ @Override public T visitBwxor(JavascriptParser.BwxorContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.</p>
+ */
+ @Override public T visitBwand(JavascriptParser.BwandContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.</p>
+ */
+ @Override public T visitBooleqne(JavascriptParser.BooleqneContext ctx) { return visitChildren(ctx); }
+}
Modified: lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/JavascriptCompiler.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/JavascriptCompiler.java?rev=1694614&r1=1694613&r2=1694614&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/JavascriptCompiler.java (original)
+++ lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/JavascriptCompiler.java Fri Aug 7 07:10:40 2015
@@ -24,18 +24,18 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
+import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Collections;
+import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
-import org.antlr.runtime.ANTLRStringStream;
-import org.antlr.runtime.CharStream;
-import org.antlr.runtime.CommonTokenStream;
-import org.antlr.runtime.RecognitionException;
-import org.antlr.runtime.tree.Tree;
+import org.antlr.v4.runtime.ANTLRInputStream;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.tree.ParseTree;
import org.apache.lucene.expressions.Expression;
import org.apache.lucene.queries.function.FunctionValues;
import org.apache.lucene.util.IOUtils;
@@ -45,6 +45,8 @@ import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;
+import static org.apache.lucene.expressions.js.JavascriptParser.ExpressionContext;
+
/**
* An expression compiler for javascript expressions.
* <p>
@@ -73,7 +75,6 @@ import org.objectweb.asm.commons.Generat
* @lucene.experimental
*/
public class JavascriptCompiler {
-
static final class Loader extends ClassLoader {
Loader(ClassLoader parent) {
super(parent);
@@ -91,13 +92,14 @@ public class JavascriptCompiler {
private static final String COMPILED_EXPRESSION_CLASS = JavascriptCompiler.class.getName() + "$CompiledExpression";
private static final String COMPILED_EXPRESSION_INTERNAL = COMPILED_EXPRESSION_CLASS.replace('.', '/');
- private static final Type EXPRESSION_TYPE = Type.getType(Expression.class);
- private static final Type FUNCTION_VALUES_TYPE = Type.getType(FunctionValues.class);
+ static final Type EXPRESSION_TYPE = Type.getType(Expression.class);
+ static final Type FUNCTION_VALUES_TYPE = Type.getType(FunctionValues.class);
private static final org.objectweb.asm.commons.Method
EXPRESSION_CTOR = getMethod("void <init>(String, String[])"),
- EVALUATE_METHOD = getMethod("double evaluate(int, " + FunctionValues.class.getName() + "[])"),
- DOUBLE_VAL_METHOD = getMethod("double doubleVal(int)");
+ EVALUATE_METHOD = getMethod("double evaluate(int, " + FunctionValues.class.getName() + "[])");
+
+ static final org.objectweb.asm.commons.Method DOUBLE_VAL_METHOD = getMethod("double doubleVal(int)");
// to work around import clash:
private static org.objectweb.asm.commons.Method getMethod(String method) {
@@ -108,12 +110,12 @@ public class JavascriptCompiler {
// rcmuir: "If your ranking function is that large you need to check yourself into a mental institution!"
private static final int MAX_SOURCE_LENGTH = 16384;
- private final String sourceText;
- private final Map<String, Integer> externalsMap = new LinkedHashMap<>();
- private final ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
- private GeneratorAdapter gen;
+ final String sourceText;
+ final Map<String, Integer> externalsMap = new LinkedHashMap<>();
+ final ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
+ GeneratorAdapter gen;
- private final Map<String,Method> functions;
+ final Map<String,Method> functions;
/**
* Compiles the given expression.
@@ -188,21 +190,45 @@ public class JavascriptCompiler {
*/
private Expression compileExpression(ClassLoader parent) throws ParseException {
try {
- Tree antlrTree = getAntlrComputedExpressionTree();
-
+ ParseTree parseTree = getAntlrParseTree();
+
beginCompile();
- recursiveCompile(antlrTree, Type.DOUBLE_TYPE);
+ internalCompile(parseTree);
endCompile();
- Class<? extends Expression> evaluatorClass = new Loader(parent)
+ final Class<? extends Expression> evaluatorClass = new Loader(parent)
.define(COMPILED_EXPRESSION_CLASS, classWriter.toByteArray());
- Constructor<? extends Expression> constructor = evaluatorClass.getConstructor(String.class, String[].class);
+ final Constructor<? extends Expression> constructor = evaluatorClass.getConstructor(String.class, String[].class);
+
return constructor.newInstance(sourceText, externalsMap.keySet().toArray(new String[externalsMap.size()]));
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException exception) {
throw new IllegalStateException("An internal error occurred attempting to compile the expression (" + sourceText + ").", exception);
}
}
-
+
+ /**
+ * Parses the sourceText into an ANTLR 4 parse tree
+ *
+ * @return The ANTLR parse tree
+ * @throws ParseException on failure to parse
+ */
+ private ParseTree getAntlrParseTree() throws ParseException {
+ try {
+ final ANTLRInputStream antlrInputStream = new ANTLRInputStream(sourceText);
+ final JavascriptErrorHandlingLexer javascriptLexer = new JavascriptErrorHandlingLexer(antlrInputStream);
+ javascriptLexer.removeErrorListeners();
+ final JavascriptParser javascriptParser = new JavascriptParser(new CommonTokenStream(javascriptLexer));
+ javascriptParser.removeErrorListeners();
+ javascriptParser.setErrorHandler(new JavascriptParserErrorStrategy());
+ return javascriptParser.compile();
+ } catch (RuntimeException re) {
+ if (re.getCause() instanceof ParseException) {
+ throw (ParseException)re.getCause();
+ }
+ throw re;
+ }
+ }
+
private void beginCompile() {
classWriter.visit(CLASSFILE_VERSION,
Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER | Opcodes.ACC_FINAL | Opcodes.ACC_SYNTHETIC,
@@ -223,253 +249,431 @@ public class JavascriptCompiler {
gen = new GeneratorAdapter(Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC,
EVALUATE_METHOD, null, null, classWriter);
}
-
- private void recursiveCompile(Tree current, Type expected) {
- int type = current.getType();
- String text = current.getText();
-
- switch (type) {
- case JavascriptParser.AT_CALL:
- Tree identifier = current.getChild(0);
- String call = identifier.getText();
- int arguments = current.getChildCount() - 1;
-
- Method method = functions.get(call);
- if (method == null && (arguments > 0 || !call.contains("."))) {
- throw new IllegalArgumentException("Unrecognized function call (" + call + ").");
- } else if (method != null) {
+
+ // internalCompile is used to create an anonymous inner class around the ANTLR listener
+ // to completely hide the implementation details of expression compilation
+ private void internalCompile(ParseTree parseTree) {
+ new JavascriptBaseVisitor<Void>() {
+ private final Deque<Type> typeStack = new ArrayDeque<>();
+
+ /**
+ * For internal compiler use only, do NOT use
+ */
+ @Override
+ public Void visitCompile(JavascriptParser.CompileContext ctx) {
+ typeStack.push(Type.DOUBLE_TYPE);
+ visit(ctx.expression());
+ typeStack.pop();
+
+ return null;
+ }
+
+ /**
+ * For internal compiler use only, do NOT use
+ */
+ @Override
+ public Void visitPrecedence(JavascriptParser.PrecedenceContext ctx) {
+ visit(ctx.expression());
+
+ return null;
+ }
+
+ /**
+ * For internal compiler use only, do NOT use
+ */
+ @Override
+ public Void visitNumeric(JavascriptParser.NumericContext ctx) {
+ if (ctx.HEX() != null) {
+ pushLong(Long.parseLong(ctx.HEX().getText().substring(2), 16));
+ } else if (ctx.OCTAL() != null) {
+ pushLong(Long.parseLong(ctx.OCTAL().getText().substring(1), 8));
+ } else if (ctx.DECIMAL() != null) {
+ gen.push(Double.parseDouble(ctx.DECIMAL().getText()));
+ gen.cast(Type.DOUBLE_TYPE, typeStack.peek());
+ } else {
+ throw new IllegalStateException("Unknown operation specified: " + ctx.getText());
+ }
+
+ return null;
+ }
+
+ /**
+ * For internal compiler use only, do NOT use
+ */
+ @Override
+ public Void visitExternal(JavascriptParser.ExternalContext ctx) {
+ String text = ctx.VARIABLE().getText();
+ int arguments = ctx.expression().size();
+ boolean parens = ctx.LP() != null && ctx.RP() != null;
+ Method method = parens ? functions.get(text) : null;
+
+ if (method != null) {
int arity = method.getParameterTypes().length;
+
if (arguments != arity) {
- throw new IllegalArgumentException("Expected (" + arity + ") arguments for function call (" +
- call + "), but found (" + arguments + ").");
+ throw new IllegalArgumentException(
+ "Expected (" + arity + ") arguments for function call (" + text + "), but found (" + arguments + ").");
}
- for (int argument = 1; argument <= arguments; ++argument) {
- recursiveCompile(current.getChild(argument), Type.DOUBLE_TYPE);
+ typeStack.push(Type.DOUBLE_TYPE);
+
+ for (int argument = 0; argument < arguments; ++argument) {
+ visit(ctx.expression(argument));
}
+ typeStack.pop();
+
gen.invokeStatic(Type.getType(method.getDeclaringClass()),
org.objectweb.asm.commons.Method.getMethod(method));
- gen.cast(Type.DOUBLE_TYPE, expected);
- break;
+ gen.cast(Type.DOUBLE_TYPE, typeStack.peek());
+ } else if (!parens || arguments == 0 && text.contains(".")) {
+ int index;
+
+ text = normalizeQuotes(ctx.getText());
+
+ if (externalsMap.containsKey(text)) {
+ index = externalsMap.get(text);
+ } else {
+ index = externalsMap.size();
+ externalsMap.put(text, index);
+ }
+
+ gen.loadArg(1);
+ gen.push(index);
+ gen.arrayLoad(FUNCTION_VALUES_TYPE);
+ gen.loadArg(0);
+ gen.invokeVirtual(FUNCTION_VALUES_TYPE, DOUBLE_VAL_METHOD);
+ gen.cast(Type.DOUBLE_TYPE, typeStack.peek());
+ } else {
+ throw new IllegalArgumentException("Unrecognized function call (" + text + ").");
+ }
+
+ return null;
+ }
+
+ /**
+ * For internal compiler use only, do NOT use
+ */
+ @Override
+ public Void visitUnary(JavascriptParser.UnaryContext ctx) {
+ if (ctx.BOOLNOT() != null) {
+ Label labelNotTrue = new Label();
+ Label labelNotReturn = new Label();
+
+ typeStack.push(Type.INT_TYPE);
+ visit(ctx.expression());
+ typeStack.pop();
+ gen.visitJumpInsn(Opcodes.IFEQ, labelNotTrue);
+ pushBoolean(false);
+ gen.goTo(labelNotReturn);
+ gen.visitLabel(labelNotTrue);
+ pushBoolean(true);
+ gen.visitLabel(labelNotReturn);
+
+ } else if (ctx.BWNOT() != null) {
+ typeStack.push(Type.LONG_TYPE);
+ visit(ctx.expression());
+ typeStack.pop();
+ gen.push(-1L);
+ gen.visitInsn(Opcodes.LXOR);
+ gen.cast(Type.LONG_TYPE, typeStack.peek());
+
+ } else if (ctx.ADD() != null) {
+ visit(ctx.expression());
+
+ } else if (ctx.SUB() != null) {
+ typeStack.push(Type.DOUBLE_TYPE);
+ visit(ctx.expression());
+ typeStack.pop();
+ gen.visitInsn(Opcodes.DNEG);
+ gen.cast(Type.DOUBLE_TYPE, typeStack.peek());
+
} else {
- text = call + "()";
- // intentionally fall through to the variable case to allow this non-static
- // method to be forwarded to the bindings for processing
- }
- case JavascriptParser.VARIABLE:
- int index;
-
- text = normalizeQuotes(text);
-
- if (externalsMap.containsKey(text)) {
- index = externalsMap.get(text);
+ throw new IllegalStateException("Unknown operation specified: " + ctx.getText());
+ }
+
+ return null;
+ }
+
+ /**
+ * For internal compiler use only, do NOT use
+ */
+ @Override
+ public Void visitMuldiv(JavascriptParser.MuldivContext ctx) {
+ int opcode;
+
+ if (ctx.MUL() != null) {
+ opcode = Opcodes.DMUL;
+ } else if (ctx.DIV() != null) {
+ opcode = Opcodes.DDIV;
+ } else if (ctx.REM() != null) {
+ opcode = Opcodes.DREM;
+ } else {
+ throw new IllegalStateException("Unknown operation specified: " + ctx.getText());
+ }
+
+ pushArith(opcode, ctx.expression(0), ctx.expression(1));
+
+ return null;
+ }
+
+ /**
+ * For internal compiler use only, do NOT use
+ */
+ @Override
+ public Void visitAddsub(JavascriptParser.AddsubContext ctx) {
+ int opcode;
+
+ if (ctx.ADD() != null) {
+ opcode = Opcodes.DADD;
+ } else if (ctx.SUB() != null) {
+ opcode = Opcodes.DSUB;
+ } else {
+ throw new IllegalStateException("Unknown operation specified: " + ctx.getText());
+ }
+
+ pushArith(opcode, ctx.expression(0), ctx.expression(1));
+
+ return null;
+ }
+
+ /**
+ * For internal compiler use only, do NOT use
+ */
+ @Override
+ public Void visitBwshift(JavascriptParser.BwshiftContext ctx) {
+ int opcode;
+
+ if (ctx.LSH() != null) {
+ opcode = Opcodes.LSHL;
+ } else if (ctx.RSH() != null) {
+ opcode = Opcodes.LSHR;
+ } else if (ctx.USH() != null) {
+ opcode = Opcodes.LUSHR;
+ } else {
+ throw new IllegalStateException("Unknown operation specified: " + ctx.getText());
+ }
+
+ pushShift(opcode, ctx.expression(0), ctx.expression(1));
+
+ return null;
+ }
+
+ /**
+ * For internal compiler use only, do NOT use
+ */
+ @Override
+ public Void visitBoolcomp(JavascriptParser.BoolcompContext ctx) {
+ int opcode;
+
+ if (ctx.LT() != null) {
+ opcode = GeneratorAdapter.LT;
+ } else if (ctx.LTE() != null) {
+ opcode = GeneratorAdapter.LE;
+ } else if (ctx.GT() != null) {
+ opcode = GeneratorAdapter.GT;
+ } else if (ctx.GTE() != null) {
+ opcode = GeneratorAdapter.GE;
+ } else {
+ throw new IllegalStateException("Unknown operation specified: " + ctx.getText());
+ }
+
+ pushCond(opcode, ctx.expression(0), ctx.expression(1));
+
+ return null;
+ }
+
+ /**
+ * For internal compiler use only, do NOT use
+ */
+ @Override
+ public Void visitBooleqne(JavascriptParser.BooleqneContext ctx) {
+ int opcode;
+
+ if (ctx.EQ() != null) {
+ opcode = GeneratorAdapter.EQ;
+ } else if (ctx.NE() != null) {
+ opcode = GeneratorAdapter.NE;
} else {
- index = externalsMap.size();
- externalsMap.put(text, index);
+ throw new IllegalStateException("Unknown operation specified: " + ctx.getText());
}
-
- gen.loadArg(1);
- gen.push(index);
- gen.arrayLoad(FUNCTION_VALUES_TYPE);
- gen.loadArg(0);
- gen.invokeVirtual(FUNCTION_VALUES_TYPE, DOUBLE_VAL_METHOD);
- gen.cast(Type.DOUBLE_TYPE, expected);
- break;
- case JavascriptParser.HEX:
- pushLong(expected, Long.parseLong(text.substring(2), 16));
- break;
- case JavascriptParser.OCTAL:
- pushLong(expected, Long.parseLong(text.substring(1), 8));
- break;
- case JavascriptParser.DECIMAL:
- gen.push(Double.parseDouble(text));
- gen.cast(Type.DOUBLE_TYPE, expected);
- break;
- case JavascriptParser.AT_NEGATE:
- recursiveCompile(current.getChild(0), Type.DOUBLE_TYPE);
- gen.visitInsn(Opcodes.DNEG);
- gen.cast(Type.DOUBLE_TYPE, expected);
- break;
- case JavascriptParser.AT_ADD:
- pushArith(Opcodes.DADD, current, expected);
- break;
- case JavascriptParser.AT_SUBTRACT:
- pushArith(Opcodes.DSUB, current, expected);
- break;
- case JavascriptParser.AT_MULTIPLY:
- pushArith(Opcodes.DMUL, current, expected);
- break;
- case JavascriptParser.AT_DIVIDE:
- pushArith(Opcodes.DDIV, current, expected);
- break;
- case JavascriptParser.AT_MODULO:
- pushArith(Opcodes.DREM, current, expected);
- break;
- case JavascriptParser.AT_BIT_SHL:
- pushShift(Opcodes.LSHL, current, expected);
- break;
- case JavascriptParser.AT_BIT_SHR:
- pushShift(Opcodes.LSHR, current, expected);
- break;
- case JavascriptParser.AT_BIT_SHU:
- pushShift(Opcodes.LUSHR, current, expected);
- break;
- case JavascriptParser.AT_BIT_AND:
- pushBitwise(Opcodes.LAND, current, expected);
- break;
- case JavascriptParser.AT_BIT_OR:
- pushBitwise(Opcodes.LOR, current, expected);
- break;
- case JavascriptParser.AT_BIT_XOR:
- pushBitwise(Opcodes.LXOR, current, expected);
- break;
- case JavascriptParser.AT_BIT_NOT:
- recursiveCompile(current.getChild(0), Type.LONG_TYPE);
- gen.push(-1L);
- gen.visitInsn(Opcodes.LXOR);
- gen.cast(Type.LONG_TYPE, expected);
- break;
- case JavascriptParser.AT_COMP_EQ:
- pushCond(GeneratorAdapter.EQ, current, expected);
- break;
- case JavascriptParser.AT_COMP_NEQ:
- pushCond(GeneratorAdapter.NE, current, expected);
- break;
- case JavascriptParser.AT_COMP_LT:
- pushCond(GeneratorAdapter.LT, current, expected);
- break;
- case JavascriptParser.AT_COMP_GT:
- pushCond(GeneratorAdapter.GT, current, expected);
- break;
- case JavascriptParser.AT_COMP_LTE:
- pushCond(GeneratorAdapter.LE, current, expected);
- break;
- case JavascriptParser.AT_COMP_GTE:
- pushCond(GeneratorAdapter.GE, current, expected);
- break;
- case JavascriptParser.AT_BOOL_NOT:
- Label labelNotTrue = new Label();
- Label labelNotReturn = new Label();
-
- recursiveCompile(current.getChild(0), Type.INT_TYPE);
- gen.visitJumpInsn(Opcodes.IFEQ, labelNotTrue);
- pushBoolean(expected, false);
- gen.goTo(labelNotReturn);
- gen.visitLabel(labelNotTrue);
- pushBoolean(expected, true);
- gen.visitLabel(labelNotReturn);
- break;
- case JavascriptParser.AT_BOOL_AND:
+
+ pushCond(opcode, ctx.expression(0), ctx.expression(1));
+
+ return null;
+ }
+
+ /**
+ * For internal compiler use only, do NOT use
+ */
+ @Override
+ public Void visitBwand(JavascriptParser.BwandContext ctx) {
+ pushBitwise(Opcodes.LAND, ctx.expression(0), ctx.expression(1));
+
+ return null;
+ }
+
+ /**
+ * For internal compiler use only, do NOT use
+ */
+ @Override
+ public Void visitBwxor(JavascriptParser.BwxorContext ctx) {
+ pushBitwise(Opcodes.LXOR, ctx.expression(0), ctx.expression(1));
+
+ return null;
+ }
+
+ /**
+ * For internal compiler use only, do NOT use
+ */
+ @Override
+ public Void visitBwor(JavascriptParser.BworContext ctx) {
+ pushBitwise(Opcodes.LOR, ctx.expression(0), ctx.expression(1));
+
+ return null;
+ }
+
+ /**
+ * For internal compiler use only, do NOT use
+ */
+ @Override
+ public Void visitBooland(JavascriptParser.BoolandContext ctx) {
Label andFalse = new Label();
Label andEnd = new Label();
-
- recursiveCompile(current.getChild(0), Type.INT_TYPE);
+
+ typeStack.push(Type.INT_TYPE);
+ visit(ctx.expression(0));
gen.visitJumpInsn(Opcodes.IFEQ, andFalse);
- recursiveCompile(current.getChild(1), Type.INT_TYPE);
+ visit(ctx.expression(1));
gen.visitJumpInsn(Opcodes.IFEQ, andFalse);
- pushBoolean(expected, true);
+ typeStack.pop();
+ pushBoolean(true);
gen.goTo(andEnd);
gen.visitLabel(andFalse);
- pushBoolean(expected, false);
+ pushBoolean(false);
gen.visitLabel(andEnd);
- break;
- case JavascriptParser.AT_BOOL_OR:
+
+ return null;
+ }
+
+ /**
+ * For internal compiler use only, do NOT use
+ */
+ @Override
+ public Void visitBoolor(JavascriptParser.BoolorContext ctx) {
Label orTrue = new Label();
Label orEnd = new Label();
-
- recursiveCompile(current.getChild(0), Type.INT_TYPE);
+
+ typeStack.push(Type.INT_TYPE);
+ visit(ctx.expression(0));
gen.visitJumpInsn(Opcodes.IFNE, orTrue);
- recursiveCompile(current.getChild(1), Type.INT_TYPE);
+ visit(ctx.expression(1));
gen.visitJumpInsn(Opcodes.IFNE, orTrue);
- pushBoolean(expected, false);
+ typeStack.pop();
+ pushBoolean(false);
gen.goTo(orEnd);
gen.visitLabel(orTrue);
- pushBoolean(expected, true);
+ pushBoolean(true);
gen.visitLabel(orEnd);
- break;
- case JavascriptParser.AT_COND_QUE:
+
+ return null;
+ }
+
+ /**
+ * For internal compiler use only, do NOT use
+ */
+ @Override
+ public Void visitConditional(JavascriptParser.ConditionalContext ctx) {
Label condFalse = new Label();
Label condEnd = new Label();
-
- recursiveCompile(current.getChild(0), Type.INT_TYPE);
+
+ typeStack.push(Type.INT_TYPE);
+ visit(ctx.expression(0));
+ typeStack.pop();
gen.visitJumpInsn(Opcodes.IFEQ, condFalse);
- recursiveCompile(current.getChild(1), expected);
+ visit(ctx.expression(1));
gen.goTo(condEnd);
gen.visitLabel(condFalse);
- recursiveCompile(current.getChild(2), expected);
+ visit(ctx.expression(2));
gen.visitLabel(condEnd);
- break;
- default:
- throw new IllegalStateException("Unknown operation specified: (" + current.getText() + ").");
- }
- }
- private void pushArith(int operator, Tree current, Type expected) {
- pushBinaryOp(operator, current, expected, Type.DOUBLE_TYPE, Type.DOUBLE_TYPE, Type.DOUBLE_TYPE);
- }
-
- private void pushShift(int operator, Tree current, Type expected) {
- pushBinaryOp(operator, current, expected, Type.LONG_TYPE, Type.INT_TYPE, Type.LONG_TYPE);
- }
-
- private void pushBitwise(int operator, Tree current, Type expected) {
- pushBinaryOp(operator, current, expected, Type.LONG_TYPE, Type.LONG_TYPE, Type.LONG_TYPE);
- }
-
- private void pushBinaryOp(int operator, Tree current, Type expected, Type arg1, Type arg2, Type returnType) {
- recursiveCompile(current.getChild(0), arg1);
- recursiveCompile(current.getChild(1), arg2);
- gen.visitInsn(operator);
- gen.cast(returnType, expected);
- }
-
- private void pushCond(int operator, Tree current, Type expected) {
- Label labelTrue = new Label();
- Label labelReturn = new Label();
-
- recursiveCompile(current.getChild(0), Type.DOUBLE_TYPE);
- recursiveCompile(current.getChild(1), Type.DOUBLE_TYPE);
-
- gen.ifCmp(Type.DOUBLE_TYPE, operator, labelTrue);
- pushBoolean(expected, false);
- gen.goTo(labelReturn);
- gen.visitLabel(labelTrue);
- pushBoolean(expected, true);
- gen.visitLabel(labelReturn);
- }
-
- private void pushBoolean(Type expected, boolean truth) {
- switch (expected.getSort()) {
- case Type.INT:
- gen.push(truth);
- break;
- case Type.LONG:
- gen.push(truth ? 1L : 0L);
- break;
- case Type.DOUBLE:
- gen.push(truth ? 1. : 0.);
- break;
- default:
- throw new IllegalStateException("Invalid expected type: " + expected);
- }
- }
-
- private void pushLong(Type expected, long i) {
- switch (expected.getSort()) {
- case Type.INT:
- gen.push((int) i);
- break;
- case Type.LONG:
- gen.push(i);
- break;
- case Type.DOUBLE:
- gen.push((double) i);
- break;
- default:
- throw new IllegalStateException("Invalid expected type: " + expected);
- }
+ return null;
+ }
+
+ private void pushArith(int operator, ExpressionContext left, ExpressionContext right) {
+ pushBinaryOp(operator, left, right, Type.DOUBLE_TYPE, Type.DOUBLE_TYPE, Type.DOUBLE_TYPE);
+ }
+
+ private void pushShift(int operator, ExpressionContext left, ExpressionContext right) {
+ pushBinaryOp(operator, left, right, Type.LONG_TYPE, Type.INT_TYPE, Type.LONG_TYPE);
+ }
+
+ private void pushBitwise(int operator, ExpressionContext left, ExpressionContext right) {
+ pushBinaryOp(operator, left, right, Type.LONG_TYPE, Type.LONG_TYPE, Type.LONG_TYPE);
+ }
+
+ private void pushBinaryOp(int operator, ExpressionContext left, ExpressionContext right,
+ Type leftType, Type rightType, Type returnType) {
+ typeStack.push(leftType);
+ visit(left);
+ typeStack.pop();
+ typeStack.push(rightType);
+ visit(right);
+ typeStack.pop();
+ gen.visitInsn(operator);
+ gen.cast(returnType, typeStack.peek());
+ }
+
+ private void pushCond(int operator, ExpressionContext left, ExpressionContext right) {
+ Label labelTrue = new Label();
+ Label labelReturn = new Label();
+
+ typeStack.push(Type.DOUBLE_TYPE);
+ visit(left);
+ visit(right);
+ typeStack.pop();
+
+ gen.ifCmp(Type.DOUBLE_TYPE, operator, labelTrue);
+ pushBoolean(false);
+ gen.goTo(labelReturn);
+ gen.visitLabel(labelTrue);
+ pushBoolean(true);
+ gen.visitLabel(labelReturn);
+ }
+
+ private void pushBoolean(boolean truth) {
+ switch (typeStack.peek().getSort()) {
+ case Type.INT:
+ gen.push(truth);
+ break;
+ case Type.LONG:
+ gen.push(truth ? 1L : 0L);
+ break;
+ case Type.DOUBLE:
+ gen.push(truth ? 1. : 0.);
+ break;
+ default:
+ throw new IllegalStateException("Invalid expected type: " + typeStack.peek());
+ }
+ }
+
+ private void pushLong(long i) {
+ switch (typeStack.peek().getSort()) {
+ case Type.INT:
+ gen.push((int) i);
+ break;
+ case Type.LONG:
+ gen.push(i);
+ break;
+ case Type.DOUBLE:
+ gen.push((double) i);
+ break;
+ default:
+ throw new IllegalStateException("Invalid expected type: " + typeStack.peek());
+ }
+ }
+ }.visit(parseTree);
}
private void endCompile() {
@@ -479,26 +683,7 @@ public class JavascriptCompiler {
classWriter.visitEnd();
}
- private Tree getAntlrComputedExpressionTree() throws ParseException {
- CharStream input = new ANTLRStringStream(sourceText);
- JavascriptLexer lexer = new JavascriptLexer(input);
- CommonTokenStream tokens = new CommonTokenStream(lexer);
- JavascriptParser parser = new JavascriptParser(tokens);
-
- try {
- return parser.expression().tree;
-
- } catch (RecognitionException exception) {
- throw new IllegalArgumentException(exception);
- } catch (RuntimeException exception) {
- if (exception.getCause() instanceof ParseException) {
- throw (ParseException)exception.getCause();
- }
- throw exception;
- }
- }
-
- private static String normalizeQuotes(String text) {
+ static String normalizeQuotes(String text) {
StringBuilder out = new StringBuilder(text.length());
boolean inDoubleQuotes = false;
for (int i = 0; i < text.length(); ++i) {
@@ -527,7 +712,7 @@ public class JavascriptCompiler {
return out.toString();
}
- private static int findSingleQuoteStringEnd(String text, int start) {
+ static int findSingleQuoteStringEnd(String text, int start) {
++start; // skip beginning
while (text.charAt(start) != '\'') {
if (text.charAt(start) == '\\') {
Added: lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/JavascriptErrorHandlingLexer.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/JavascriptErrorHandlingLexer.java?rev=1694614&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/JavascriptErrorHandlingLexer.java (added)
+++ lucene/dev/trunk/lucene/expressions/src/java/org/apache/lucene/expressions/js/JavascriptErrorHandlingLexer.java Fri Aug 7 07:10:40 2015
@@ -0,0 +1,53 @@
+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.text.ParseException;
+
+import org.antlr.v4.runtime.CharStream;
+import org.antlr.v4.runtime.LexerNoViableAltException;
+import org.antlr.v4.runtime.misc.Interval;
+
+/**
+ * Overrides the ANTLR 4 generated JavascriptLexer to allow for proper error handling
+ */
+class JavascriptErrorHandlingLexer extends JavascriptLexer {
+ /**
+ * Constructor for JavascriptErrorHandlingLexer
+ * @param charStream the stream for the source text
+ */
+ public JavascriptErrorHandlingLexer(CharStream charStream) {
+ super(charStream);
+ }
+
+ /**
+ * Ensures the ANTLR lexer will throw an exception after the first error
+ * @param lnvae the lexer exception
+ */
+ @Override
+ public void recover(LexerNoViableAltException lnvae) {
+ CharStream charStream = lnvae.getInputStream();
+ int startIndex = lnvae.getStartIndex();
+ String text = charStream.getText(Interval.of(startIndex, charStream.index()));
+
+ ParseException parseException = new ParseException("unexpected character '" + getErrorDisplay(text) + "'" +
+ " on line (" + _tokenStartLine + ") position (" + _tokenStartCharPositionInLine + ")", _tokenStartCharIndex);
+ parseException.initCause(lnvae);
+ throw new RuntimeException(parseException);
+ }
+}