LUCENE-6451: Expressions now support bindings keys that look like zero arg functions

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1675926 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Ryan Ernst 2015-04-24 18:15:42 +00:00
parent 665725e27e
commit 458f504202
4 changed files with 61 additions and 25 deletions

View File

@ -82,6 +82,9 @@ New Features
When used, you should typically disable RPT's pruneLeafyBranches option.
(Nick Knize, David Smiley)
* LUCENE-6451: Expressions now support bindings keys that look like
zero arg functions (Jack Conradson via Ryan Ernst)
Optimizations
* LUCENE-6379: IndexWriter.deleteDocuments(Query...) now detects if

View File

@ -235,31 +235,33 @@ public class JavascriptCompiler {
int arguments = current.getChildCount() - 1;
Method method = functions.get(call);
if (method == null) {
throw new IllegalArgumentException("Unrecognized method call (" + call + ").");
if (method == null && (arguments > 0 || !call.contains("."))) {
throw new IllegalArgumentException("Unrecognized function call (" + call + ").");
} else if (method != null) {
int arity = method.getParameterTypes().length;
if (arguments != arity) {
throw new IllegalArgumentException("Expected (" + arity + ") arguments for function call (" +
call + "), but found (" + arguments + ").");
}
for (int argument = 1; argument <= arguments; ++argument) {
recursiveCompile(current.getChild(argument), Type.DOUBLE_TYPE);
}
gen.invokeStatic(Type.getType(method.getDeclaringClass()),
org.objectweb.asm.commons.Method.getMethod(method));
gen.cast(Type.DOUBLE_TYPE, expected);
break;
} else {
text = call + "()";
// intentionally fall through to the variable case to allow this non-static
// method to be forwarded to the bindings for processing
}
int arity = method.getParameterTypes().length;
if (arguments != arity) {
throw new IllegalArgumentException("Expected (" + arity + ") arguments for method call (" +
call + "), but found (" + arguments + ").");
}
for (int argument = 1; argument <= arguments; ++argument) {
recursiveCompile(current.getChild(argument), Type.DOUBLE_TYPE);
}
gen.invokeStatic(Type.getType(method.getDeclaringClass()),
org.objectweb.asm.commons.Method.getMethod(method));
gen.cast(Type.DOUBLE_TYPE, expected);
break;
case JavascriptParser.VARIABLE:
int index;
// normalize quotes
text = normalizeQuotes(text);
if (externalsMap.containsKey(text)) {
index = externalsMap.get(text);

View File

@ -20,6 +20,7 @@ package org.apache.lucene.expressions.js;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@ -42,7 +43,7 @@ public class TestCustomFunctions extends LuceneTestCase {
JavascriptCompiler.compile("sqrt(20)", functions, getClass().getClassLoader());
fail();
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains("Unrecognized method"));
assertTrue(e.getMessage().contains("Unrecognized function"));
}
}
@ -62,7 +63,7 @@ public class TestCustomFunctions extends LuceneTestCase {
Expression expr = JavascriptCompiler.compile("foo()", functions, getClass().getClassLoader());
assertEquals(5, expr.evaluate(0, null), DELTA);
}
public static double oneArgMethod(double arg1) { return 3 + arg1; }
/** tests a method with one arguments */
@ -91,7 +92,28 @@ public class TestCustomFunctions extends LuceneTestCase {
Expression expr = JavascriptCompiler.compile("foo() + bar(3)", functions, getClass().getClassLoader());
assertEquals(11, expr.evaluate(0, null), DELTA);
}
/** tests invalid methods that are not allowed to become variables to be mapped */
public void testInvalidVariableMethods() {
try {
JavascriptCompiler.compile("method()");
fail();
} catch (ParseException exception) {
fail();
} catch (IllegalArgumentException exception) {
//expected
}
try {
JavascriptCompiler.compile("method.method(1)");
fail();
} catch (ParseException exception) {
fail();
} catch (IllegalArgumentException exception) {
//expected
}
}
public static String bogusReturnType() { return "bogus!"; }
/** wrong return type: must be double */

View File

@ -50,6 +50,15 @@ public class TestJavascriptCompiler extends LuceneTestCase {
doTestValidVariable("mixed[23]['key'].sub.sub[1]");
doTestValidVariable("mixed[23]['key'].sub.sub[1].sub");
doTestValidVariable("mixed[23]['key'].sub.sub[1].sub['abc']");
doTestValidVariable("method.method()");
doTestValidVariable("method.getMethod()");
doTestValidVariable("method.METHOD()");
doTestValidVariable("method['key'].method()");
doTestValidVariable("method['key'].getMethod()");
doTestValidVariable("method['key'].METHOD()");
doTestValidVariable("method[23][\"key\"].method()", "method[23]['key'].method()");
doTestValidVariable("method[23][\"key\"].getMethod()", "method[23]['key'].getMethod()");
doTestValidVariable("method[23][\"key\"].METHOD()", "method[23]['key'].METHOD()");
}
void doTestValidVariable(String variable) throws Exception {
@ -164,14 +173,14 @@ public class TestJavascriptCompiler extends LuceneTestCase {
JavascriptCompiler.compile("tan()");
fail();
} catch (IllegalArgumentException expected) {
assertTrue(expected.getMessage().contains("arguments for method call"));
assertTrue(expected.getMessage().contains("arguments for function call"));
}
try {
JavascriptCompiler.compile("tan(1, 1)");
fail();
} catch (IllegalArgumentException expected) {
assertTrue(expected.getMessage().contains("arguments for method call"));
assertTrue(expected.getMessage().contains("arguments for function call"));
}
}