Merge pull request #18711 from rmuir/painless_compile_exceptions

Improve painless compile-time exceptions
This commit is contained in:
Robert Muir 2016-06-02 20:43:01 -04:00
commit ad118eb1e5
72 changed files with 791 additions and 631 deletions

View File

@ -22,6 +22,7 @@ package org.elasticsearch.painless;
import org.elasticsearch.painless.Definition.Cast; import org.elasticsearch.painless.Definition.Cast;
import org.elasticsearch.painless.Definition.Sort; import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.node.ANode;
/** /**
* Used during the analysis phase to collect legal type casts and promotions * Used during the analysis phase to collect legal type casts and promotions
@ -29,7 +30,7 @@ import org.elasticsearch.painless.Definition.Type;
*/ */
public final class AnalyzerCaster { public final class AnalyzerCaster {
public static Cast getLegalCast(String location, Type actual, Type expected, boolean explicit, boolean internal) { public static Cast getLegalCast(Location location, Type actual, Type expected, boolean explicit, boolean internal) {
if (actual.equals(expected)) { if (actual.equals(expected)) {
return null; return null;
} }
@ -653,11 +654,11 @@ public final class AnalyzerCaster {
explicit && actual.clazz.isAssignableFrom(expected.clazz)) { explicit && actual.clazz.isAssignableFrom(expected.clazz)) {
return new Cast(actual, expected, explicit); return new Cast(actual, expected, explicit);
} else { } else {
throw new ClassCastException("Error" + location + ": Cannot cast from [" + actual.name + "] to [" + expected.name + "]."); throw location.createError(new ClassCastException("Cannot cast from [" + actual.name + "] to [" + expected.name + "]."));
} }
} }
public static Object constCast(final String location, final Object constant, final Cast cast) { public static Object constCast(Location location, final Object constant, final Cast cast) {
final Sort fsort = cast.from.sort; final Sort fsort = cast.from.sort;
final Sort tsort = cast.to.sort; final Sort tsort = cast.to.sort;
@ -685,12 +686,12 @@ public final class AnalyzerCaster {
case FLOAT: return number.floatValue(); case FLOAT: return number.floatValue();
case DOUBLE: return number.doubleValue(); case DOUBLE: return number.doubleValue();
default: default:
throw new IllegalStateException("Error" + location + ": Cannot cast from " + throw location.createError(new IllegalStateException("Cannot cast from " +
"[" + cast.from.clazz.getCanonicalName() + "] to [" + cast.to.clazz.getCanonicalName() + "]."); "[" + cast.from.clazz.getCanonicalName() + "] to [" + cast.to.clazz.getCanonicalName() + "]."));
} }
} else { } else {
throw new IllegalStateException("Error" + location + ": Cannot cast from " + throw location.createError(new IllegalStateException("Cannot cast from " +
"[" + cast.from.clazz.getCanonicalName() + "] to [" + cast.to.clazz.getCanonicalName() + "]."); "[" + cast.from.clazz.getCanonicalName() + "] to [" + cast.to.clazz.getCanonicalName() + "]."));
} }
} }

View File

@ -101,7 +101,7 @@ final class Compiler {
} }
Reserved reserved = new Reserved(); Reserved reserved = new Reserved();
SSource root = Walker.buildPainlessTree(source, reserved, settings); SSource root = Walker.buildPainlessTree(name, source, reserved, settings);
Variables variables = Analyzer.analyze(reserved, root); Variables variables = Analyzer.analyze(reserved, root);
BitSet expressions = new BitSet(source.length()); BitSet expressions = new BitSet(source.length());
@ -132,7 +132,7 @@ final class Compiler {
} }
Reserved reserved = new Reserved(); Reserved reserved = new Reserved();
SSource root = Walker.buildPainlessTree(source, reserved, settings); SSource root = Walker.buildPainlessTree(name, source, reserved, settings);
Variables variables = Analyzer.analyze(reserved, root); Variables variables = Analyzer.analyze(reserved, root);
return Writer.write(settings, name, source, variables, root, new BitSet(source.length())); return Writer.write(settings, name, source, variables, root, new BitSet(source.length()));

View File

@ -164,6 +164,11 @@ public final class Definition {
return result; return result;
} }
@Override
public String toString() {
return name;
}
} }
public static final class Constructor { public static final class Constructor {

View File

@ -0,0 +1,111 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch 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.
*/
package org.elasticsearch.painless;
import java.util.Objects;
/**
* Represents a location in script code (name of script + character offset)
*/
public final class Location {
private final String sourceName;
private final int offset;
/**
* Create a new Location
* @param sourceName script's name
* @param offset character offset of script element
*/
public Location(String sourceName, int offset) {
this.sourceName = Objects.requireNonNull(sourceName);
this.offset = offset;
}
/**
* Return the script's name
*/
public String getSourceName() {
return sourceName;
}
/**
* Return the character offset
*/
public int getOffset() {
return offset;
}
/**
* Augments an exception with this location's information.
*/
public RuntimeException createError(RuntimeException exception) {
StackTraceElement element = new StackTraceElement(WriterConstants.CLASS_NAME, "compile", sourceName, offset + 1);
StackTraceElement[] oldStack = exception.getStackTrace();
StackTraceElement[] newStack = new StackTraceElement[oldStack.length + 1];
System.arraycopy(oldStack, 0, newStack, 1, oldStack.length);
newStack[0] = element;
exception.setStackTrace(newStack);
assert exception.getStackTrace().length == newStack.length : "non-writeable stacktrace for exception: " + exception.getClass();
return exception;
}
// This maximum length is theoretically 65535 bytes, but as it's CESU-8 encoded we dont know how large it is in bytes, so be safe
private static final int MAX_NAME_LENGTH = 256;
/** Computes the file name (mostly important for stacktraces) */
public static String computeSourceName(String scriptName, String source) {
StringBuilder fileName = new StringBuilder();
if (scriptName.equals(PainlessScriptEngineService.INLINE_NAME)) {
// its an anonymous script, include at least a portion of the source to help identify which one it is
// but don't create stacktraces with filenames that contain newlines or huge names.
// truncate to the first newline
int limit = source.indexOf('\n');
if (limit >= 0) {
int limit2 = source.indexOf('\r');
if (limit2 >= 0) {
limit = Math.min(limit, limit2);
}
} else {
limit = source.length();
}
// truncate to our limit
limit = Math.min(limit, MAX_NAME_LENGTH);
fileName.append(source, 0, limit);
// if we truncated, make it obvious
if (limit != source.length()) {
fileName.append(" ...");
}
fileName.append(" @ <inline script>");
} else {
// its a named script, just use the name
// but don't trust this has a reasonable length!
if (scriptName.length() > MAX_NAME_LENGTH) {
fileName.append(scriptName, 0, MAX_NAME_LENGTH);
fileName.append(" ...");
} else {
fileName.append(scriptName);
}
}
return fileName.toString();
}
}

View File

@ -114,7 +114,8 @@ public final class MethodWriter extends GeneratorAdapter {
* <p> * <p>
* This is invoked for each statement boundary (leaf {@code S*} nodes). * This is invoked for each statement boundary (leaf {@code S*} nodes).
*/ */
public void writeStatementOffset(int offset) { public void writeStatementOffset(Location location) {
int offset = location.getOffset();
// ensure we don't have duplicate stuff going in here. can catch bugs // ensure we don't have duplicate stuff going in here. can catch bugs
// (e.g. nodes get assigned wrong offsets by antlr walker) // (e.g. nodes get assigned wrong offsets by antlr walker)
assert statements.get(offset) == false; assert statements.get(offset) == false;
@ -126,16 +127,16 @@ public final class MethodWriter extends GeneratorAdapter {
* <p> * <p>
* This is invoked before instructions that can hit exceptions. * This is invoked before instructions that can hit exceptions.
*/ */
public void writeDebugInfo(int offset) { public void writeDebugInfo(Location location) {
// TODO: maybe track these in bitsets too? this is trickier... // TODO: maybe track these in bitsets too? this is trickier...
Label label = new Label(); Label label = new Label();
visitLabel(label); visitLabel(label);
visitLineNumber(offset + 1, label); visitLineNumber(location.getOffset() + 1, label);
} }
public void writeLoopCounter(int slot, int count, int offset) { public void writeLoopCounter(int slot, int count, Location location) {
if (slot > -1) { if (slot > -1) {
writeDebugInfo(offset); writeDebugInfo(location);
final Label end = new Label(); final Label end = new Label();
iinc(slot, -count); iinc(slot, -count);
@ -281,14 +282,14 @@ public final class MethodWriter extends GeneratorAdapter {
} }
} }
public void writeBinaryInstruction(final String location, final Type type, final Operation operation) { public void writeBinaryInstruction(Location location, Type type, Operation operation) {
final Sort sort = type.sort; final Sort sort = type.sort;
if ((sort == Sort.FLOAT || sort == Sort.DOUBLE) && if ((sort == Sort.FLOAT || sort == Sort.DOUBLE) &&
(operation == Operation.LSH || operation == Operation.USH || (operation == Operation.LSH || operation == Operation.USH ||
operation == Operation.RSH || operation == Operation.BWAND || operation == Operation.RSH || operation == Operation.BWAND ||
operation == Operation.XOR || operation == Operation.BWOR)) { operation == Operation.XOR || operation == Operation.BWOR)) {
throw new IllegalStateException("Error " + location + ": Illegal tree structure."); throw location.createError(new IllegalStateException("Illegal tree structure."));
} }
if (sort == Sort.DEF) { if (sort == Sort.DEF) {
@ -305,7 +306,7 @@ public final class MethodWriter extends GeneratorAdapter {
case XOR: invokeStatic(DEF_UTIL_TYPE, DEF_XOR_CALL); break; case XOR: invokeStatic(DEF_UTIL_TYPE, DEF_XOR_CALL); break;
case BWOR: invokeStatic(DEF_UTIL_TYPE, DEF_OR_CALL); break; case BWOR: invokeStatic(DEF_UTIL_TYPE, DEF_OR_CALL); break;
default: default:
throw new IllegalStateException("Error " + location + ": Illegal tree structure."); throw location.createError(new IllegalStateException("Illegal tree structure."));
} }
} else { } else {
switch (operation) { switch (operation) {
@ -321,7 +322,7 @@ public final class MethodWriter extends GeneratorAdapter {
case XOR: math(GeneratorAdapter.XOR, type.type); break; case XOR: math(GeneratorAdapter.XOR, type.type); break;
case BWOR: math(GeneratorAdapter.OR, type.type); break; case BWOR: math(GeneratorAdapter.OR, type.type); break;
default: default:
throw new IllegalStateException("Error " + location + ": Illegal tree structure."); throw location.createError(new IllegalStateException("Illegal tree structure."));
} }
} }
} }

View File

@ -29,6 +29,7 @@ import org.elasticsearch.script.CompiledScript;
import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.LeafSearchScript; import org.elasticsearch.script.LeafSearchScript;
import org.elasticsearch.script.ScriptEngineService; import org.elasticsearch.script.ScriptEngineService;
import org.elasticsearch.script.ScriptException;
import org.elasticsearch.script.SearchScript; import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.lookup.SearchLookup; import org.elasticsearch.search.lookup.SearchLookup;
@ -38,7 +39,10 @@ import java.security.AccessController;
import java.security.Permissions; import java.security.Permissions;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import java.security.ProtectionDomain; import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
@ -147,13 +151,17 @@ public final class PainlessScriptEngineService extends AbstractComponent impleme
} }
}); });
// Drop all permissions to actually compile the code itself. try {
return AccessController.doPrivileged(new PrivilegedAction<Executable>() { // Drop all permissions to actually compile the code itself.
@Override return AccessController.doPrivileged(new PrivilegedAction<Executable>() {
public Executable run() { @Override
return Compiler.compile(loader, scriptName == null ? INLINE_NAME : scriptName, scriptSource, compilerSettings); public Executable run() {
} return Compiler.compile(loader, scriptName == null ? INLINE_NAME : scriptName, scriptSource, compilerSettings);
}, COMPILATION_CONTEXT); }
}, COMPILATION_CONTEXT);
} catch (Exception e) {
throw convertToScriptException(scriptName == null ? scriptSource : scriptName, scriptSource, e);
}
} }
/** /**
@ -213,4 +221,51 @@ public final class PainlessScriptEngineService extends AbstractComponent impleme
public void close() { public void close() {
// Nothing to do. // Nothing to do.
} }
private ScriptException convertToScriptException(String scriptName, String scriptSource, Throwable t) {
// create a script stack: this is just the script portion
List<String> scriptStack = new ArrayList<>();
for (StackTraceElement element : t.getStackTrace()) {
if (WriterConstants.CLASS_NAME.equals(element.getClassName())) {
// found the script portion
int offset = element.getLineNumber();
if (offset == -1) {
scriptStack.add("<<< unknown portion of script >>>");
} else {
offset--; // offset is 1 based, line numbers must be!
int startOffset = getPreviousStatement(scriptSource, offset);
int endOffset = getNextStatement(scriptSource, offset);
StringBuilder snippet = new StringBuilder();
if (startOffset > 0) {
snippet.append("... ");
}
snippet.append(scriptSource.substring(startOffset, endOffset));
if (endOffset < scriptSource.length()) {
snippet.append(" ...");
}
scriptStack.add(snippet.toString());
StringBuilder pointer = new StringBuilder();
if (startOffset > 0) {
pointer.append(" ");
}
for (int i = startOffset; i < offset; i++) {
pointer.append(' ');
}
pointer.append("^---- HERE");
scriptStack.add(pointer.toString());
}
break;
}
}
throw new ScriptException("compile error", t, scriptStack, scriptSource, PainlessScriptEngineService.NAME);
}
// very simple heuristic: +/- 25 chars. can be improved later.
private int getPreviousStatement(String scriptSource, int offset) {
return Math.max(0, offset - 25);
}
private int getNextStatement(String scriptSource, int offset) {
return Math.min(scriptSource.length(), offset + 25);
}
} }

View File

@ -173,7 +173,8 @@ final class ScriptImpl implements ExecutableScript, LeafSearchScript {
/** returns true for methods that are part of the runtime */ /** returns true for methods that are part of the runtime */
private static boolean shouldFilter(StackTraceElement element) { private static boolean shouldFilter(StackTraceElement element) {
return element.getClassName().startsWith("org.elasticsearch.painless.") || return element.getClassName().startsWith("org.elasticsearch.painless.") ||
element.getClassName().startsWith("java.lang.invoke."); element.getClassName().startsWith("java.lang.invoke.") ||
element.getClassName().startsWith("sun.invoke.");
} }
/** /**

View File

@ -69,7 +69,7 @@ public final class Variables {
} }
public static final class Variable { public static final class Variable {
public final String location; public final Location location;
public final String name; public final String name;
public final Type type; public final Type type;
public final int slot; public final int slot;
@ -77,7 +77,7 @@ public final class Variables {
public boolean read = false; public boolean read = false;
private Variable(String location, String name, Type type, int slot, boolean readonly) { private Variable(Location location, String name, Type type, int slot, boolean readonly) {
this.location = location; this.location = location;
this.name = name; this.name = name;
this.type = type; this.type = type;
@ -88,6 +88,7 @@ public final class Variables {
final Reserved reserved; final Reserved reserved;
// TODO: this datastructure runs in linear time for nearly all operations. use linkedhashset instead?
private final Deque<Integer> scopes = new ArrayDeque<>(); private final Deque<Integer> scopes = new ArrayDeque<>();
private final Deque<Variable> variables = new ArrayDeque<>(); private final Deque<Variable> variables = new ArrayDeque<>();
@ -99,35 +100,35 @@ public final class Variables {
// Method variables. // Method variables.
// This reference. Internal use only. // This reference. Internal use only.
addVariable("[" + Reserved.THIS + "]", Definition.getType("Object"), Reserved.THIS, true, true); addVariable(null, Definition.getType("Object"), Reserved.THIS, true, true);
// Input map of variables passed to the script. // Input map of variables passed to the script.
addVariable("[" + Reserved.PARAMS + "]", Definition.getType("Map"), Reserved.PARAMS, true, true); addVariable(null, Definition.getType("Map"), Reserved.PARAMS, true, true);
// Scorer parameter passed to the script. Internal use only. // Scorer parameter passed to the script. Internal use only.
addVariable("[" + Reserved.SCORER + "]", Definition.DEF_TYPE, Reserved.SCORER, true, true); addVariable(null, Definition.DEF_TYPE, Reserved.SCORER, true, true);
// Doc parameter passed to the script. TODO: Currently working as a Map, we can do better? // Doc parameter passed to the script. TODO: Currently working as a Map, we can do better?
addVariable("[" + Reserved.DOC + "]", Definition.getType("Map"), Reserved.DOC, true, true); addVariable(null, Definition.getType("Map"), Reserved.DOC, true, true);
// Aggregation _value parameter passed to the script. // Aggregation _value parameter passed to the script.
addVariable("[" + Reserved.VALUE + "]", Definition.DEF_TYPE, Reserved.VALUE, true, true); addVariable(null, Definition.DEF_TYPE, Reserved.VALUE, true, true);
// Shortcut variables. // Shortcut variables.
// Document's score as a read-only double. // Document's score as a read-only double.
if (reserved.score) { if (reserved.score) {
addVariable("[" + Reserved.SCORE + "]", Definition.DOUBLE_TYPE, Reserved.SCORE, true, true); addVariable(null, Definition.DOUBLE_TYPE, Reserved.SCORE, true, true);
} }
// The ctx map set by executable scripts as a read-only map. // The ctx map set by executable scripts as a read-only map.
if (reserved.ctx) { if (reserved.ctx) {
addVariable("[" + Reserved.CTX + "]", Definition.getType("Map"), Reserved.CTX, true, true); addVariable(null, Definition.getType("Map"), Reserved.CTX, true, true);
} }
// Loop counter to catch infinite loops. Internal use only. // Loop counter to catch infinite loops. Internal use only.
if (reserved.loop) { if (reserved.loop) {
addVariable("[" + Reserved.LOOP + "]", Definition.INT_TYPE, Reserved.LOOP, true, true); addVariable(null, Definition.INT_TYPE, Reserved.LOOP, true, true);
} }
} }
@ -137,19 +138,20 @@ public final class Variables {
public void decrementScope() { public void decrementScope() {
int remove = scopes.pop(); int remove = scopes.pop();
while (remove > 0) { while (remove > 0) {
Variable variable = variables.pop(); Variable variable = variables.pop();
// TODO: is this working? the code reads backwards...
if (variable.read) { if (variable.read) {
throw new IllegalArgumentException("Error [" + variable.location + "]: Variable [" + variable.name + "] never used."); throw variable.location.createError(new IllegalArgumentException("Variable [" + variable.name + "] never used."));
} }
--remove; --remove;
} }
} }
public Variable getVariable(String location, String name) { public Variable getVariable(Location location, String name) {
Iterator<Variable> itr = variables.iterator(); Iterator<Variable> itr = variables.iterator();
while (itr.hasNext()) { while (itr.hasNext()) {
@ -160,20 +162,20 @@ public final class Variables {
} }
} }
if (location != null) { throw location.createError(new IllegalArgumentException("Variable [" + name + "] not defined."));
throw new IllegalArgumentException("Error " + location + ": Variable [" + name + "] not defined.");
}
return null;
} }
public Variable addVariable(String location, Type type, String name, boolean readonly, boolean reserved) { private boolean variableExists(String name) {
return variables.contains(name);
}
public Variable addVariable(Location location, Type type, String name, boolean readonly, boolean reserved) {
if (!reserved && this.reserved.isReserved(name)) { if (!reserved && this.reserved.isReserved(name)) {
throw new IllegalArgumentException("Error " + location + ": Variable name [" + name + "] is reserved."); throw location.createError(new IllegalArgumentException("Variable name [" + name + "] is reserved."));
} }
if (getVariable(null, name) != null) { if (variableExists(name)) {
throw new IllegalArgumentException("Error " + location + ": Variable name [" + name + "] already defined."); throw new IllegalArgumentException("Variable name [" + name + "] already defined.");
} }
try { try {

View File

@ -72,9 +72,6 @@ final class Writer {
writeEnd(); writeEnd();
} }
// This maximum length is theoretically 65535 bytes, but as it's CESU-8 encoded we dont know how large it is in bytes, so be safe
private static final int MAX_NAME_LENGTH = 256;
private void writeBegin() { private void writeBegin() {
final int version = Opcodes.V1_8; final int version = Opcodes.V1_8;
final int access = Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER | Opcodes.ACC_FINAL; final int access = Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER | Opcodes.ACC_FINAL;
@ -86,47 +83,7 @@ final class Writer {
new String[] { WriterConstants.NEEDS_SCORE_TYPE.getInternalName() } : null; new String[] { WriterConstants.NEEDS_SCORE_TYPE.getInternalName() } : null;
writer.visit(version, access, name, null, base, interfaces); writer.visit(version, access, name, null, base, interfaces);
writer.visitSource(computeSourceName(), null); writer.visitSource(Location.computeSourceName(scriptName,source), null);
}
/** Computes the file name (mostly important for stacktraces) */
private String computeSourceName() {
StringBuilder fileName = new StringBuilder();
if (scriptName.equals(PainlessScriptEngineService.INLINE_NAME)) {
// its an anonymous script, include at least a portion of the source to help identify which one it is
// but don't create stacktraces with filenames that contain newlines or huge names.
// truncate to the first newline
int limit = source.indexOf('\n');
if (limit >= 0) {
int limit2 = source.indexOf('\r');
if (limit2 >= 0) {
limit = Math.min(limit, limit2);
}
} else {
limit = source.length();
}
// truncate to our limit
limit = Math.min(limit, MAX_NAME_LENGTH);
fileName.append(source, 0, limit);
// if we truncated, make it obvious
if (limit != source.length()) {
fileName.append(" ...");
}
fileName.append(" @ <inline script>");
} else {
// its a named script, just use the name
// but don't trust this has a reasonable length!
if (scriptName.length() > MAX_NAME_LENGTH) {
fileName.append(scriptName, 0, MAX_NAME_LENGTH);
fileName.append(" ...");
} else {
fileName.append(scriptName);
}
}
return fileName.toString();
} }
private void writeConstructor() { private void writeConstructor() {

View File

@ -22,16 +22,17 @@ package org.elasticsearch.painless.antlr;
import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.LexerNoViableAltException; import org.antlr.v4.runtime.LexerNoViableAltException;
import org.antlr.v4.runtime.misc.Interval; import org.antlr.v4.runtime.misc.Interval;
import org.elasticsearch.painless.Location;
import java.text.ParseException;
/** /**
* A lexer that will override the default error behavior to fail on the first error. * A lexer that will override the default error behavior to fail on the first error.
*/ */
final class ErrorHandlingLexer extends PainlessLexer { final class ErrorHandlingLexer extends PainlessLexer {
final String sourceName;
ErrorHandlingLexer(final CharStream charStream) { ErrorHandlingLexer(CharStream charStream, String sourceName) {
super(charStream); super(charStream);
this.sourceName = sourceName;
} }
@Override @Override
@ -40,11 +41,7 @@ final class ErrorHandlingLexer extends PainlessLexer {
final int startIndex = lnvae.getStartIndex(); final int startIndex = lnvae.getStartIndex();
final String text = charStream.getText(Interval.of(startIndex, charStream.index())); final String text = charStream.getText(Interval.of(startIndex, charStream.index()));
final ParseException parseException = new ParseException("Error [" + _tokenStartLine + ":" + Location location = new Location(sourceName, _tokenStartCharIndex);
_tokenStartCharPositionInLine + "]: unexpected character [" + throw location.createError(new IllegalArgumentException("unexpected character [" + getErrorDisplay(text) + "].", lnvae));
getErrorDisplay(text) + "].", _tokenStartCharIndex);
parseException.initCause(lnvae);
throw new RuntimeException(parseException);
} }
} }

View File

@ -25,13 +25,17 @@ import org.antlr.v4.runtime.NoViableAltException;
import org.antlr.v4.runtime.Parser; import org.antlr.v4.runtime.Parser;
import org.antlr.v4.runtime.RecognitionException; import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.Token;
import org.elasticsearch.painless.Location;
import java.text.ParseException;
/** /**
* An error strategy that will override the default error behavior to fail on the first parser error. * An error strategy that will override the default error behavior to fail on the first parser error.
*/ */
final class ParserErrorStrategy extends DefaultErrorStrategy { final class ParserErrorStrategy extends DefaultErrorStrategy {
final String sourceName;
ParserErrorStrategy(String sourceName) {
this.sourceName = sourceName;
}
@Override @Override
public void recover(final Parser recognizer, final RecognitionException re) { public void recover(final Parser recognizer, final RecognitionException re) {
@ -39,38 +43,32 @@ final class ParserErrorStrategy extends DefaultErrorStrategy {
String message; String message;
if (token == null) { if (token == null) {
message = "Error: no parse token found."; message = "no parse token found.";
} else if (re instanceof InputMismatchException) { } else if (re instanceof InputMismatchException) {
message = "Error[" + token.getLine() + ":" + token.getCharPositionInLine() + "]:" + message = "unexpected token [" + getTokenErrorDisplay(token) + "]" +
" unexpected token [" + getTokenErrorDisplay(token) + "]" +
" was expecting one of [" + re.getExpectedTokens().toString(recognizer.getVocabulary()) + "]."; " was expecting one of [" + re.getExpectedTokens().toString(recognizer.getVocabulary()) + "].";
} else if (re instanceof NoViableAltException) { } else if (re instanceof NoViableAltException) {
if (token.getType() == PainlessParser.EOF) { if (token.getType() == PainlessParser.EOF) {
message = "Error: unexpected end of script."; message = "unexpected end of script.";
} else { } else {
message = "Error[" + token.getLine() + ":" + token.getCharPositionInLine() + "]:" + message = "invalid sequence of tokens near [" + getTokenErrorDisplay(token) + "].";
"invalid sequence of tokens near [" + getTokenErrorDisplay(token) + "].";
} }
} else { } else {
message = "Error[" + token.getLine() + ":" + token.getCharPositionInLine() + "]:" + message = "unexpected token near [" + getTokenErrorDisplay(token) + "].";
" unexpected token near [" + getTokenErrorDisplay(token) + "].";
} }
final ParseException parseException = new ParseException(message, token == null ? -1 : token.getStartIndex()); Location location = new Location(sourceName, token == null ? -1 : token.getStartIndex());
parseException.initCause(re); throw location.createError(new IllegalArgumentException(message, re));
throw new RuntimeException(parseException);
} }
@Override @Override
public Token recoverInline(final Parser recognizer) throws RecognitionException { public Token recoverInline(final Parser recognizer) throws RecognitionException {
final Token token = recognizer.getCurrentToken(); final Token token = recognizer.getCurrentToken();
final String message = "Error[" + token.getLine() + ":" + token.getCharPositionInLine() + "]:" + final String message = "unexpected token [" + getTokenErrorDisplay(token) + "]" +
" unexpected token [" + getTokenErrorDisplay(token) + "]" +
" was expecting one of [" + recognizer.getExpectedTokens().toString(recognizer.getVocabulary()) + "]."; " was expecting one of [" + recognizer.getExpectedTokens().toString(recognizer.getVocabulary()) + "].";
final ParseException parseException = new ParseException(message, token.getStartIndex());
throw new RuntimeException(parseException); Location location = new Location(sourceName, token.getStartIndex());
throw location.createError(new IllegalArgumentException(message));
} }
@Override @Override

View File

@ -28,6 +28,7 @@ import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Recognizer; import org.antlr.v4.runtime.Recognizer;
import org.antlr.v4.runtime.atn.PredictionMode; import org.antlr.v4.runtime.atn.PredictionMode;
import org.elasticsearch.painless.CompilerSettings; import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.Operation;
import org.elasticsearch.painless.Variables.Reserved; import org.elasticsearch.painless.Variables.Reserved;
import org.elasticsearch.painless.antlr.PainlessParser.AfterthoughtContext; import org.elasticsearch.painless.antlr.PainlessParser.AfterthoughtContext;
@ -135,25 +136,27 @@ import java.util.List;
*/ */
public final class Walker extends PainlessParserBaseVisitor<Object> { public final class Walker extends PainlessParserBaseVisitor<Object> {
public static SSource buildPainlessTree(String source, Reserved reserved, CompilerSettings settings) { public static SSource buildPainlessTree(String name, String sourceText, Reserved reserved, CompilerSettings settings) {
return new Walker(source, reserved, settings).source; return new Walker(name, sourceText, reserved, settings).source;
} }
private final Reserved reserved; private final Reserved reserved;
private final SSource source; private final SSource source;
private final CompilerSettings settings; private final CompilerSettings settings;
private final String sourceName;
private Walker(String source, Reserved reserved, CompilerSettings settings) { private Walker(String name, String sourceText, Reserved reserved, CompilerSettings settings) {
this.reserved = reserved; this.reserved = reserved;
this.settings = settings; this.settings = settings;
this.source = (SSource)visit(buildAntlrTree(source)); this.sourceName = Location.computeSourceName(name, sourceText);
this.source = (SSource)visit(buildAntlrTree(sourceText));
} }
private SourceContext buildAntlrTree(String source) { private SourceContext buildAntlrTree(String source) {
ANTLRInputStream stream = new ANTLRInputStream(source); ANTLRInputStream stream = new ANTLRInputStream(source);
PainlessLexer lexer = new ErrorHandlingLexer(stream); PainlessLexer lexer = new ErrorHandlingLexer(stream, sourceName);
PainlessParser parser = new PainlessParser(new CommonTokenStream(lexer)); PainlessParser parser = new PainlessParser(new CommonTokenStream(lexer));
ParserErrorStrategy strategy = new ParserErrorStrategy(); ParserErrorStrategy strategy = new ParserErrorStrategy(sourceName);
lexer.removeErrorListeners(); lexer.removeErrorListeners();
parser.removeErrorListeners(); parser.removeErrorListeners();
@ -185,16 +188,8 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
parser.getInterpreter().setPredictionMode(PredictionMode.LL_EXACT_AMBIG_DETECTION); parser.getInterpreter().setPredictionMode(PredictionMode.LL_EXACT_AMBIG_DETECTION);
} }
private int line(ParserRuleContext ctx) { private Location location(ParserRuleContext ctx) {
return ctx.getStart().getLine(); return new Location(sourceName, ctx.getStart().getStartIndex());
}
private int offset(ParserRuleContext ctx) {
return ctx.getStart().getStartIndex();
}
private String location(ParserRuleContext ctx) {
return "[ " + ctx.getStart().getLine() + " : " + ctx.getStart().getCharPositionInLine() + " ]";
} }
@Override @Override
@ -205,7 +200,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
statements.add((AStatement)visit(statement)); statements.add((AStatement)visit(statement));
} }
return new SSource(line(ctx), offset(ctx), location(ctx), statements); return new SSource(location(ctx), statements);
} }
@Override @Override
@ -216,9 +211,9 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
if (ctx.trailer().size() > 1) { if (ctx.trailer().size() > 1) {
SBlock elseblock = (SBlock)visit(ctx.trailer(1)); SBlock elseblock = (SBlock)visit(ctx.trailer(1));
return new SIfElse(line(ctx), offset(ctx), location(ctx), expression, ifblock, elseblock); return new SIfElse(location(ctx), expression, ifblock, elseblock);
} else { } else {
return new SIf(line(ctx), offset(ctx), location(ctx), expression, ifblock); return new SIf(location(ctx), expression, ifblock);
} }
} }
@ -233,11 +228,11 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
if (ctx.trailer() != null) { if (ctx.trailer() != null) {
SBlock block = (SBlock)visit(ctx.trailer()); SBlock block = (SBlock)visit(ctx.trailer());
return new SWhile(line(ctx), offset(ctx), location(ctx), settings.getMaxLoopCounter(), expression, block); return new SWhile(location(ctx), settings.getMaxLoopCounter(), expression, block);
} else if (ctx.empty() != null) { } else if (ctx.empty() != null) {
return new SWhile(line(ctx), offset(ctx), location(ctx), settings.getMaxLoopCounter(), expression, null); return new SWhile(location(ctx), settings.getMaxLoopCounter(), expression, null);
} else { } else {
throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure."); throw location(ctx).createError(new IllegalStateException(" Illegal tree structure."));
} }
} }
@ -250,7 +245,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
AExpression expression = (AExpression)visitExpression(ctx.expression()); AExpression expression = (AExpression)visitExpression(ctx.expression());
SBlock block = (SBlock)visit(ctx.block()); SBlock block = (SBlock)visit(ctx.block());
return new SDo(line(ctx), offset(ctx), location(ctx), settings.getMaxLoopCounter(), block, expression); return new SDo(location(ctx), settings.getMaxLoopCounter(), block, expression);
} }
@Override @Override
@ -266,13 +261,13 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
if (ctx.trailer() != null) { if (ctx.trailer() != null) {
SBlock block = (SBlock)visit(ctx.trailer()); SBlock block = (SBlock)visit(ctx.trailer());
return new SFor(line(ctx), offset(ctx), location(ctx), return new SFor(location(ctx),
settings.getMaxLoopCounter(), initializer, expression, afterthought, block); settings.getMaxLoopCounter(), initializer, expression, afterthought, block);
} else if (ctx.empty() != null) { } else if (ctx.empty() != null) {
return new SFor(line(ctx), offset(ctx), location(ctx), return new SFor(location(ctx),
settings.getMaxLoopCounter(), initializer, expression, afterthought, null); settings.getMaxLoopCounter(), initializer, expression, afterthought, null);
} else { } else {
throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure."); throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -283,19 +278,19 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
@Override @Override
public Object visitContinue(ContinueContext ctx) { public Object visitContinue(ContinueContext ctx) {
return new SContinue(line(ctx), offset(ctx), location(ctx)); return new SContinue(location(ctx));
} }
@Override @Override
public Object visitBreak(BreakContext ctx) { public Object visitBreak(BreakContext ctx) {
return new SBreak(line(ctx), offset(ctx), location(ctx)); return new SBreak(location(ctx));
} }
@Override @Override
public Object visitReturn(ReturnContext ctx) { public Object visitReturn(ReturnContext ctx) {
AExpression expression = (AExpression)visitExpression(ctx.expression()); AExpression expression = (AExpression)visitExpression(ctx.expression());
return new SReturn(line(ctx), offset(ctx), location(ctx), expression); return new SReturn(location(ctx), expression);
} }
@Override @Override
@ -307,21 +302,21 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
catches.add((SCatch)visit(trap)); catches.add((SCatch)visit(trap));
} }
return new STry(line(ctx), offset(ctx), location(ctx), block, catches); return new STry(location(ctx), block, catches);
} }
@Override @Override
public Object visitThrow(ThrowContext ctx) { public Object visitThrow(ThrowContext ctx) {
AExpression expression = (AExpression)visitExpression(ctx.expression()); AExpression expression = (AExpression)visitExpression(ctx.expression());
return new SThrow(line(ctx), offset(ctx), location(ctx), expression); return new SThrow(location(ctx), expression);
} }
@Override @Override
public Object visitExpr(ExprContext ctx) { public Object visitExpr(ExprContext ctx) {
AExpression expression = (AExpression)visitExpression(ctx.expression()); AExpression expression = (AExpression)visitExpression(ctx.expression());
return new SExpression(line(ctx), offset(ctx), location(ctx), expression); return new SExpression(location(ctx), expression);
} }
@Override @Override
@ -332,9 +327,9 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
List<AStatement> statements = new ArrayList<>(); List<AStatement> statements = new ArrayList<>();
statements.add((AStatement)visit(ctx.statement())); statements.add((AStatement)visit(ctx.statement()));
return new SBlock(line(ctx), offset(ctx), location(ctx), statements); return new SBlock(location(ctx), statements);
} else { } else {
throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure."); throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -349,13 +344,13 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
statements.add((AStatement)visit(statement)); statements.add((AStatement)visit(statement));
} }
return new SBlock(line(ctx), offset(ctx), location(ctx), statements); return new SBlock(location(ctx), statements);
} }
} }
@Override @Override
public Object visitEmpty(EmptyContext ctx) { public Object visitEmpty(EmptyContext ctx) {
throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure."); throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
} }
@Override @Override
@ -365,7 +360,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
} else if (ctx.expression() != null) { } else if (ctx.expression() != null) {
return visitExpression(ctx.expression()); return visitExpression(ctx.expression());
} else { } else {
throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure."); throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -383,25 +378,25 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
String name = declvar.ID().getText(); String name = declvar.ID().getText();
AExpression expression = declvar.expression() == null ? null : (AExpression)visitExpression(declvar.expression()); AExpression expression = declvar.expression() == null ? null : (AExpression)visitExpression(declvar.expression());
declarations.add(new SDeclaration(line(declvar), offset(declvar), location(declvar), type, name, expression)); declarations.add(new SDeclaration(location(declvar), type, name, expression));
} }
return new SDeclBlock(line(ctx), offset(ctx), location(ctx), declarations); return new SDeclBlock(location(ctx), declarations);
} }
@Override @Override
public Object visitDecltype(DecltypeContext ctx) { public Object visitDecltype(DecltypeContext ctx) {
throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure."); throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
} }
@Override @Override
public Object visitFuncref(FuncrefContext ctx) { public Object visitFuncref(FuncrefContext ctx) {
return new EFunctionRef(line(ctx), offset(ctx), location(ctx), ctx.TYPE().getText(), ctx.ID().getText()); return new EFunctionRef(location(ctx), ctx.TYPE().getText(), ctx.ID().getText());
} }
@Override @Override
public Object visitDeclvar(DeclvarContext ctx) { public Object visitDeclvar(DeclvarContext ctx) {
throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure."); throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
} }
@Override @Override
@ -410,12 +405,12 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
String name = ctx.ID().getText(); String name = ctx.ID().getText();
SBlock block = (SBlock)visit(ctx.block()); SBlock block = (SBlock)visit(ctx.block());
return new SCatch(line(ctx), offset(ctx), location(ctx), type, name, block); return new SCatch(location(ctx), type, name, block);
} }
@Override @Override
public Object visitDelimiter(DelimiterContext ctx) { public Object visitDelimiter(DelimiterContext ctx) {
throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure."); throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
} }
private Object visitExpression(ExpressionContext ctx) { private Object visitExpression(ExpressionContext ctx) {
@ -425,7 +420,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
List<ALink> links = (List<ALink>)expression; List<ALink> links = (List<ALink>)expression;
return new EChain(line(ctx), offset(ctx), location(ctx), links, false, false, null, null); return new EChain(location(ctx), links, false, false, null, null);
} else { } else {
return expression; return expression;
} }
@ -465,10 +460,10 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
} else if (ctx.BWOR() != null) { } else if (ctx.BWOR() != null) {
operation = Operation.BWOR; operation = Operation.BWOR;
} else { } else {
throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state."); throw location(ctx).createError(new IllegalStateException("Unexpected state."));
} }
return new EBinary(line(ctx), offset(ctx), location(ctx), operation, left, right); return new EBinary(location(ctx), operation, left, right);
} }
@Override @Override
@ -494,10 +489,10 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
} else if (ctx.NER() != null) { } else if (ctx.NER() != null) {
operation = Operation.NER; operation = Operation.NER;
} else { } else {
throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state."); throw location(ctx).createError(new IllegalStateException("Unexpected state."));
} }
return new EComp(line(ctx), offset(ctx), location(ctx), operation, left, right); return new EComp(location(ctx), operation, left, right);
} }
@Override @Override
@ -511,10 +506,10 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
} else if (ctx.BOOLOR() != null) { } else if (ctx.BOOLOR() != null) {
operation = Operation.OR; operation = Operation.OR;
} else { } else {
throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state."); throw location(ctx).createError(new IllegalStateException("Unexpected state."));
} }
return new EBool(line(ctx), offset(ctx), location(ctx), operation, left, right); return new EBool(location(ctx), operation, left, right);
} }
@Override @Override
@ -523,7 +518,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
AExpression left = (AExpression)visitExpression(ctx.expression(1)); AExpression left = (AExpression)visitExpression(ctx.expression(1));
AExpression right = (AExpression)visitExpression(ctx.expression(2)); AExpression right = (AExpression)visitExpression(ctx.expression(2));
return new EConditional(line(ctx), offset(ctx), location(ctx), condition, left, right); return new EConditional(location(ctx), condition, left, right);
} }
@Override @Override
@ -557,12 +552,12 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
} else if (ctx.AOR() != null) { } else if (ctx.AOR() != null) {
operation = Operation.BWOR; operation = Operation.BWOR;
} else { } else {
throw new IllegalStateException("Error " + location(ctx) + ": Illegal tree structure."); throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
} }
AExpression expression = (AExpression)visitExpression(ctx.expression()); AExpression expression = (AExpression)visitExpression(ctx.expression());
return new EChain(line(ctx), offset(ctx), location(ctx), links, false, false, operation, expression); return new EChain(location(ctx), links, false, false, operation, expression);
} }
private Object visitUnary(UnaryContext ctx) { private Object visitUnary(UnaryContext ctx) {
@ -572,7 +567,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
List<ALink> links = (List<ALink>)expression; List<ALink> links = (List<ALink>)expression;
return new EChain(line(ctx), offset(ctx), location(ctx), links, false, false, null, null); return new EChain(location(ctx), links, false, false, null, null);
} else { } else {
return expression; return expression;
} }
@ -589,10 +584,10 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
} else if (ctx.DECR() != null) { } else if (ctx.DECR() != null) {
operation = Operation.DECR; operation = Operation.DECR;
} else { } else {
throw new IllegalStateException("Error " + location(ctx) + ": Illegal tree structure."); throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
} }
return new EChain(line(ctx), offset(ctx), location(ctx), links, true, false, operation, null); return new EChain(location(ctx), links, true, false, operation, null);
} }
@Override @Override
@ -606,10 +601,10 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
} else if (ctx.DECR() != null) { } else if (ctx.DECR() != null) {
operation = Operation.DECR; operation = Operation.DECR;
} else { } else {
throw new IllegalStateException("Error " + location(ctx) + ": Illegal tree structure."); throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
} }
return new EChain(line(ctx), offset(ctx), location(ctx), links, false, true, operation, null); return new EChain(location(ctx), links, false, true, operation, null);
} }
@Override @Override
@ -622,31 +617,31 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
final boolean negate = ctx.parent instanceof OperatorContext && ((OperatorContext)ctx.parent).SUB() != null; final boolean negate = ctx.parent instanceof OperatorContext && ((OperatorContext)ctx.parent).SUB() != null;
if (ctx.DECIMAL() != null) { if (ctx.DECIMAL() != null) {
return new EDecimal(line(ctx), offset(ctx), location(ctx), (negate ? "-" : "") + ctx.DECIMAL().getText()); return new EDecimal(location(ctx), (negate ? "-" : "") + ctx.DECIMAL().getText());
} else if (ctx.HEX() != null) { } else if (ctx.HEX() != null) {
return new ENumeric(line(ctx), offset(ctx), location(ctx), (negate ? "-" : "") + ctx.HEX().getText().substring(2), 16); return new ENumeric(location(ctx), (negate ? "-" : "") + ctx.HEX().getText().substring(2), 16);
} else if (ctx.INTEGER() != null) { } else if (ctx.INTEGER() != null) {
return new ENumeric(line(ctx), offset(ctx), location(ctx), (negate ? "-" : "") + ctx.INTEGER().getText(), 10); return new ENumeric(location(ctx), (negate ? "-" : "") + ctx.INTEGER().getText(), 10);
} else if (ctx.OCTAL() != null) { } else if (ctx.OCTAL() != null) {
return new ENumeric(line(ctx), offset(ctx), location(ctx), (negate ? "-" : "") + ctx.OCTAL().getText().substring(1), 8); return new ENumeric(location(ctx), (negate ? "-" : "") + ctx.OCTAL().getText().substring(1), 8);
} else { } else {
throw new IllegalStateException("Error " + location(ctx) + ": Illegal tree structure."); throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@Override @Override
public Object visitTrue(TrueContext ctx) { public Object visitTrue(TrueContext ctx) {
return new EBoolean(line(ctx), offset(ctx), location(ctx), true); return new EBoolean(location(ctx), true);
} }
@Override @Override
public Object visitFalse(FalseContext ctx) { public Object visitFalse(FalseContext ctx) {
return new EBoolean(line(ctx), offset(ctx), location(ctx), false); return new EBoolean(location(ctx), false);
} }
@Override @Override
public Object visitNull(NullContext ctx) { public Object visitNull(NullContext ctx) {
return new ENull(line(ctx), offset(ctx), location(ctx)); return new ENull(location(ctx));
} }
@Override @Override
@ -666,10 +661,10 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
} else if (ctx.SUB() != null) { } else if (ctx.SUB() != null) {
operation = Operation.SUB; operation = Operation.SUB;
} else { } else {
throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure."); throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
} }
return new EUnary(line(ctx), offset(ctx), location(ctx), operation, expression); return new EUnary(location(ctx), operation, expression);
} }
} }
@ -681,11 +676,11 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
if (child instanceof List) { if (child instanceof List) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
List<ALink> links = (List<ALink>)child; List<ALink> links = (List<ALink>)child;
links.add(new LCast(line(ctx), offset(ctx), location(ctx), type)); links.add(new LCast(location(ctx), type));
return links; return links;
} else { } else {
return new EExplicit(line(ctx), offset(ctx), location(ctx), type, (AExpression)child); return new EExplicit(location(ctx), type, (AExpression)child);
} }
} }
@ -703,7 +698,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
return links; return links;
} else if (!ctx.secondary().isEmpty()) { } else if (!ctx.secondary().isEmpty()) {
throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure."); throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
} else { } else {
return child; return child;
} }
@ -714,7 +709,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
String type = ctx.decltype().getText(); String type = ctx.decltype().getText();
List<ALink> links = new ArrayList<>(); List<ALink> links = new ArrayList<>();
links.add(new LStatic(line(ctx), offset(ctx), location(ctx), type)); links.add(new LStatic(location(ctx), type));
links.add((ALink)visit(ctx.dot())); links.add((ALink)visit(ctx.dot()));
for (SecondaryContext secondary : ctx.secondary()) { for (SecondaryContext secondary : ctx.secondary()) {
@ -734,7 +729,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
} }
List<ALink> links = new ArrayList<>(); List<ALink> links = new ArrayList<>();
links.add(new LNewArray(line(ctx), offset(ctx), location(ctx), type, expressions)); links.add(new LNewArray(location(ctx), type, expressions));
if (ctx.dot() != null) { if (ctx.dot() != null) {
links.add((ALink)visit(ctx.dot())); links.add((ALink)visit(ctx.dot()));
@ -743,7 +738,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
links.add((ALink)visit(secondary)); links.add((ALink)visit(secondary));
} }
} else if (!ctx.secondary().isEmpty()) { } else if (!ctx.secondary().isEmpty()) {
throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure."); throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
} }
return links; return links;
@ -763,7 +758,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
public Object visitString(StringContext ctx) { public Object visitString(StringContext ctx) {
String string = ctx.STRING().getText().substring(1, ctx.STRING().getText().length() - 1); String string = ctx.STRING().getText().substring(1, ctx.STRING().getText().length() - 1);
List<ALink> links = new ArrayList<>(); List<ALink> links = new ArrayList<>();
links.add(new LString(line(ctx), offset(ctx), location(ctx), string)); links.add(new LString(location(ctx), string));
return links; return links;
} }
@ -772,7 +767,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
public Object visitVariable(VariableContext ctx) { public Object visitVariable(VariableContext ctx) {
String name = ctx.ID().getText(); String name = ctx.ID().getText();
List<ALink> links = new ArrayList<>(); List<ALink> links = new ArrayList<>();
links.add(new LVariable(line(ctx), offset(ctx), location(ctx), name)); links.add(new LVariable(location(ctx), name));
reserved.markReserved(name); reserved.markReserved(name);
@ -786,7 +781,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
List<AExpression> arguments = (List<AExpression>)visit(ctx.arguments()); List<AExpression> arguments = (List<AExpression>)visit(ctx.arguments());
List<ALink> links = new ArrayList<>(); List<ALink> links = new ArrayList<>();
links.add(new LNewObj(line(ctx), offset(ctx), location(ctx), type, arguments)); links.add(new LNewObj(location(ctx), type, arguments));
return links; return links;
} }
@ -798,7 +793,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
} else if (ctx.brace() != null) { } else if (ctx.brace() != null) {
return visit(ctx.brace()); return visit(ctx.brace());
} else { } else {
throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure."); throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -808,7 +803,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
List<AExpression> arguments = (List<AExpression>)visit(ctx.arguments()); List<AExpression> arguments = (List<AExpression>)visit(ctx.arguments());
return new LCall(line(ctx), offset(ctx), location(ctx), name, arguments); return new LCall(location(ctx), name, arguments);
} }
@Override @Override
@ -820,17 +815,17 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
} else if (ctx.DOTINTEGER() != null) { } else if (ctx.DOTINTEGER() != null) {
value = ctx.DOTINTEGER().getText(); value = ctx.DOTINTEGER().getText();
} else { } else {
throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure."); throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
} }
return new LField(line(ctx), offset(ctx), location(ctx), value); return new LField(location(ctx), value);
} }
@Override @Override
public Object visitBraceaccess(BraceaccessContext ctx) { public Object visitBraceaccess(BraceaccessContext ctx) {
AExpression expression = (AExpression)visitExpression(ctx.expression()); AExpression expression = (AExpression)visitExpression(ctx.expression());
return new LBrace(line(ctx), offset(ctx), location(ctx), expression); return new LBrace(location(ctx), expression);
} }
@Override @Override
@ -851,7 +846,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
} else if (ctx.funcref() != null) { } else if (ctx.funcref() != null) {
return visit(ctx.funcref()); return visit(ctx.funcref());
} else { } else {
throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure."); throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
} }
} }
} }

View File

@ -21,6 +21,7 @@ package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition.Cast; import org.elasticsearch.painless.Definition.Cast;
import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.AnalyzerCaster;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Label; import org.objectweb.asm.Label;
@ -98,8 +99,8 @@ public abstract class AExpression extends ANode {
*/ */
protected Label fals = null; protected Label fals = null;
public AExpression(int line, int offset, String location) { public AExpression(Location location) {
super(line, offset, location); super(location);
} }
/** /**
@ -124,18 +125,18 @@ public abstract class AExpression extends ANode {
if (constant == null || this instanceof EConstant) { if (constant == null || this instanceof EConstant) {
return this; return this;
} else { } else {
final EConstant econstant = new EConstant(line, offset, location, constant); final EConstant econstant = new EConstant(location, constant);
econstant.analyze(variables); econstant.analyze(variables);
if (!expected.equals(econstant.actual)) { if (!expected.equals(econstant.actual)) {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
return econstant; return econstant;
} }
} else { } else {
if (constant == null) { if (constant == null) {
final ECast ecast = new ECast(line, offset, location, this, cast); final ECast ecast = new ECast(location, this, cast);
ecast.statement = statement; ecast.statement = statement;
ecast.actual = expected; ecast.actual = expected;
ecast.isNull = isNull; ecast.isNull = isNull;
@ -145,28 +146,28 @@ public abstract class AExpression extends ANode {
if (expected.sort.constant) { if (expected.sort.constant) {
constant = AnalyzerCaster.constCast(location, constant, cast); constant = AnalyzerCaster.constCast(location, constant, cast);
final EConstant econstant = new EConstant(line, offset, location, constant); final EConstant econstant = new EConstant(location, constant);
econstant.analyze(variables); econstant.analyze(variables);
if (!expected.equals(econstant.actual)) { if (!expected.equals(econstant.actual)) {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
return econstant; return econstant;
} else if (this instanceof EConstant) { } else if (this instanceof EConstant) {
final ECast ecast = new ECast(line, offset, location, this, cast); final ECast ecast = new ECast(location, this, cast);
ecast.actual = expected; ecast.actual = expected;
return ecast; return ecast;
} else { } else {
final EConstant econstant = new EConstant(line, offset, location, constant); final EConstant econstant = new EConstant(location, constant);
econstant.analyze(variables); econstant.analyze(variables);
if (!actual.equals(econstant.actual)) { if (!actual.equals(econstant.actual)) {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
final ECast ecast = new ECast(line, offset, location, econstant, cast); final ECast ecast = new ECast(location, econstant, cast);
ecast.actual = expected; ecast.actual = expected;
return ecast; return ecast;

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
@ -73,8 +74,8 @@ public abstract class ALink extends ANode {
*/ */
String string = null; String string = null;
ALink(int line, int offset, String location, int size) { ALink(Location location, int size) {
super(line, offset, location); super(location);
this.size = size; this.size = size;
} }

View File

@ -19,33 +19,22 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Location;
/** /**
* The superclass for all other nodes. * The superclass for all other nodes.
*/ */
public abstract class ANode { public abstract class ANode {
/** /**
* The line number in the original source used for debugging and errors. * The identifier of the script and character offset used for debugging and errors.
*/ */
final int line; final Location location;
/** ANode(Location location) {
* The character offset in the original source used for debugging and errors.
*/
final int offset;
/**
* The location in the original source to be printed in error messages.
*/
final String location;
ANode(int line, int offset, String location) {
this.line = line;
this.offset = offset;
this.location = location; this.location = location;
} }
public String error(final String message) { public RuntimeException createError(RuntimeException exception) {
return "Error " + location + ": " + message; return location.createError(exception);
} }
} }

View File

@ -21,6 +21,7 @@ package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Label; import org.objectweb.asm.Label;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
/** /**
@ -107,8 +108,8 @@ public abstract class AStatement extends ANode {
*/ */
Label brake = null; Label brake = null;
AStatement(int line, int offset, String location) { AStatement(Location location) {
super(line, offset, location); super(location);
} }
/** /**

View File

@ -23,6 +23,7 @@ import org.elasticsearch.painless.AnalyzerCaster;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Sort; import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.Operation;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
@ -38,8 +39,8 @@ public final class EBinary extends AExpression {
boolean cat = false; boolean cat = false;
public EBinary(int line, int offset, String location, Operation operation, AExpression left, AExpression right) { public EBinary(Location location, Operation operation, AExpression left, AExpression right) {
super(line, offset, location); super(location);
this.operation = operation; this.operation = operation;
this.left = left; this.left = left;
@ -71,7 +72,7 @@ public final class EBinary extends AExpression {
} else if (operation == Operation.BWOR) { } else if (operation == Operation.BWOR) {
analyzeBWOr(variables); analyzeBWOr(variables);
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -82,7 +83,7 @@ public final class EBinary extends AExpression {
Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true); Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
if (promote == null) { if (promote == null) {
throw new ClassCastException(error("Cannot apply multiply [*] to types " + throw createError(new ClassCastException("Cannot apply multiply [*] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + left.actual.name + "] and [" + right.actual.name + "]."));
} }
@ -104,7 +105,7 @@ public final class EBinary extends AExpression {
} else if (sort == Sort.DOUBLE) { } else if (sort == Sort.DOUBLE) {
constant = (double)left.constant * (double)right.constant; constant = (double)left.constant * (double)right.constant;
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -118,7 +119,7 @@ public final class EBinary extends AExpression {
Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true); Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
if (promote == null) { if (promote == null) {
throw new ClassCastException(error("Cannot apply divide [/] to types " + throw createError(new ClassCastException("Cannot apply divide [/] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + left.actual.name + "] and [" + right.actual.name + "]."));
} }
@ -131,16 +132,20 @@ public final class EBinary extends AExpression {
if (left.constant != null && right.constant != null) { if (left.constant != null && right.constant != null) {
Sort sort = promote.sort; Sort sort = promote.sort;
if (sort == Sort.INT) { try {
constant = (int)left.constant / (int)right.constant; if (sort == Sort.INT) {
} else if (sort == Sort.LONG) { constant = (int)left.constant / (int)right.constant;
constant = (long)left.constant / (long)right.constant; } else if (sort == Sort.LONG) {
} else if (sort == Sort.FLOAT) { constant = (long)left.constant / (long)right.constant;
constant = (float)left.constant / (float)right.constant; } else if (sort == Sort.FLOAT) {
} else if (sort == Sort.DOUBLE) { constant = (float)left.constant / (float)right.constant;
constant = (double)left.constant / (double)right.constant; } else if (sort == Sort.DOUBLE) {
} else { constant = (double)left.constant / (double)right.constant;
throw new IllegalStateException(error("Illegal tree structure.")); } else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
} catch (ArithmeticException e) {
throw createError(e);
} }
} }
@ -154,7 +159,7 @@ public final class EBinary extends AExpression {
Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true); Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
if (promote == null) { if (promote == null) {
throw new ClassCastException(error("Cannot apply remainder [%] to types " + throw createError(new ClassCastException("Cannot apply remainder [%] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + left.actual.name + "] and [" + right.actual.name + "]."));
} }
@ -167,16 +172,20 @@ public final class EBinary extends AExpression {
if (left.constant != null && right.constant != null) { if (left.constant != null && right.constant != null) {
Sort sort = promote.sort; Sort sort = promote.sort;
if (sort == Sort.INT) { try {
constant = (int)left.constant % (int)right.constant; if (sort == Sort.INT) {
} else if (sort == Sort.LONG) { constant = (int)left.constant % (int)right.constant;
constant = (long)left.constant % (long)right.constant; } else if (sort == Sort.LONG) {
} else if (sort == Sort.FLOAT) { constant = (long)left.constant % (long)right.constant;
constant = (float)left.constant % (float)right.constant; } else if (sort == Sort.FLOAT) {
} else if (sort == Sort.DOUBLE) { constant = (float)left.constant % (float)right.constant;
constant = (double)left.constant % (double)right.constant; } else if (sort == Sort.DOUBLE) {
} else { constant = (double)left.constant % (double)right.constant;
throw new IllegalStateException(error("Illegal tree structure.")); } else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
} catch (ArithmeticException e) {
throw createError(e);
} }
} }
@ -190,7 +199,7 @@ public final class EBinary extends AExpression {
Type promote = AnalyzerCaster.promoteAdd(left.actual, right.actual); Type promote = AnalyzerCaster.promoteAdd(left.actual, right.actual);
if (promote == null) { if (promote == null) {
throw new ClassCastException(error("Cannot apply add [+] to types " + throw createError(new ClassCastException("Cannot apply add [+] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + left.actual.name + "] and [" + right.actual.name + "]."));
} }
@ -228,7 +237,7 @@ public final class EBinary extends AExpression {
} else if (sort == Sort.STRING) { } else if (sort == Sort.STRING) {
constant = "" + left.constant + right.constant; constant = "" + left.constant + right.constant;
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -242,7 +251,7 @@ public final class EBinary extends AExpression {
Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true); Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
if (promote == null) { if (promote == null) {
throw new ClassCastException(error("Cannot apply subtract [-] to types " + throw createError(new ClassCastException("Cannot apply subtract [-] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + left.actual.name + "] and [" + right.actual.name + "]."));
} }
@ -264,7 +273,7 @@ public final class EBinary extends AExpression {
} else if (sort == Sort.DOUBLE) { } else if (sort == Sort.DOUBLE) {
constant = (double)left.constant - (double)right.constant; constant = (double)left.constant - (double)right.constant;
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -278,7 +287,7 @@ public final class EBinary extends AExpression {
Type promote = AnalyzerCaster.promoteNumeric(left.actual, false); Type promote = AnalyzerCaster.promoteNumeric(left.actual, false);
if (promote == null) { if (promote == null) {
throw new ClassCastException(error("Cannot apply left shift [<<] to types " + throw createError(new ClassCastException("Cannot apply left shift [<<] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + left.actual.name + "] and [" + right.actual.name + "]."));
} }
@ -297,7 +306,7 @@ public final class EBinary extends AExpression {
} else if (sort == Sort.LONG) { } else if (sort == Sort.LONG) {
constant = (long)left.constant << (int)right.constant; constant = (long)left.constant << (int)right.constant;
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -311,7 +320,7 @@ public final class EBinary extends AExpression {
Type promote = AnalyzerCaster.promoteNumeric(left.actual, false); Type promote = AnalyzerCaster.promoteNumeric(left.actual, false);
if (promote == null) { if (promote == null) {
throw new ClassCastException(error("Cannot apply right shift [>>] to types " + throw createError(new ClassCastException("Cannot apply right shift [>>] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + left.actual.name + "] and [" + right.actual.name + "]."));
} }
@ -330,7 +339,7 @@ public final class EBinary extends AExpression {
} else if (sort == Sort.LONG) { } else if (sort == Sort.LONG) {
constant = (long)left.constant >> (int)right.constant; constant = (long)left.constant >> (int)right.constant;
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -344,7 +353,7 @@ public final class EBinary extends AExpression {
Type promote = AnalyzerCaster.promoteNumeric(left.actual, false); Type promote = AnalyzerCaster.promoteNumeric(left.actual, false);
if (promote == null) { if (promote == null) {
throw new ClassCastException(error("Cannot apply unsigned shift [>>>] to types " + throw createError(new ClassCastException("Cannot apply unsigned shift [>>>] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + left.actual.name + "] and [" + right.actual.name + "]."));
} }
@ -363,7 +372,7 @@ public final class EBinary extends AExpression {
} else if (sort == Sort.LONG) { } else if (sort == Sort.LONG) {
constant = (long)left.constant >>> (int)right.constant; constant = (long)left.constant >>> (int)right.constant;
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -377,7 +386,7 @@ public final class EBinary extends AExpression {
Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, false); Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, false);
if (promote == null) { if (promote == null) {
throw new ClassCastException(error("Cannot apply and [&] to types " + throw createError(new ClassCastException("Cannot apply and [&] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + left.actual.name + "] and [" + right.actual.name + "]."));
} }
@ -395,7 +404,7 @@ public final class EBinary extends AExpression {
} else if (sort == Sort.LONG) { } else if (sort == Sort.LONG) {
constant = (long)left.constant & (long)right.constant; constant = (long)left.constant & (long)right.constant;
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -409,7 +418,7 @@ public final class EBinary extends AExpression {
Type promote = AnalyzerCaster.promoteXor(left.actual, right.actual); Type promote = AnalyzerCaster.promoteXor(left.actual, right.actual);
if (promote == null) { if (promote == null) {
throw new ClassCastException(error("Cannot apply xor [^] to types " + throw createError(new ClassCastException("Cannot apply xor [^] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + left.actual.name + "] and [" + right.actual.name + "]."));
} }
@ -429,7 +438,7 @@ public final class EBinary extends AExpression {
} else if (sort == Sort.LONG) { } else if (sort == Sort.LONG) {
constant = (long)left.constant ^ (long)right.constant; constant = (long)left.constant ^ (long)right.constant;
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -443,7 +452,7 @@ public final class EBinary extends AExpression {
Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, false); Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, false);
if (promote == null) { if (promote == null) {
throw new ClassCastException(error("Cannot apply or [|] to types " + throw createError(new ClassCastException("Cannot apply or [|] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + left.actual.name + "] and [" + right.actual.name + "]."));
} }
@ -461,7 +470,7 @@ public final class EBinary extends AExpression {
} else if (sort == Sort.LONG) { } else if (sort == Sort.LONG) {
constant = (long)left.constant | (long)right.constant; constant = (long)left.constant | (long)right.constant;
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -470,7 +479,7 @@ public final class EBinary extends AExpression {
@Override @Override
void write(MethodWriter writer) { void write(MethodWriter writer) {
writer.writeDebugInfo(offset); writer.writeDebugInfo(location);
if (actual.sort == Sort.STRING && operation == Operation.ADD) { if (actual.sort == Sort.STRING && operation == Operation.ADD) {
if (!cat) { if (!cat) {
writer.writeNewStrings(); writer.writeNewStrings();

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.Operation;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Label; import org.objectweb.asm.Label;
@ -34,8 +35,8 @@ public final class EBool extends AExpression {
AExpression left; AExpression left;
AExpression right; AExpression right;
public EBool(int line, int offset, String location, Operation operation, AExpression left, AExpression right) { public EBool(Location location, Operation operation, AExpression left, AExpression right) {
super(line, offset, location); super(location);
this.operation = operation; this.operation = operation;
this.left = left; this.left = left;
@ -58,7 +59,7 @@ public final class EBool extends AExpression {
} else if (operation == Operation.OR) { } else if (operation == Operation.OR) {
constant = (boolean)left.constant || (boolean)right.constant; constant = (boolean)left.constant || (boolean)right.constant;
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -95,7 +96,7 @@ public final class EBool extends AExpression {
writer.mark(localtru); writer.mark(localtru);
} }
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} else { } else {
if (operation == Operation.AND) { if (operation == Operation.AND) {
@ -131,7 +132,7 @@ public final class EBool extends AExpression {
writer.push(false); writer.push(false);
writer.mark(end); writer.mark(end);
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
} }

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
@ -28,8 +29,8 @@ import org.elasticsearch.painless.MethodWriter;
*/ */
public final class EBoolean extends AExpression { public final class EBoolean extends AExpression {
public EBoolean(int line, int offset, String location, boolean constant) { public EBoolean(Location location, boolean constant) {
super(line, offset, location); super(location);
this.constant = constant; this.constant = constant;
} }
@ -41,6 +42,6 @@ public final class EBoolean extends AExpression {
@Override @Override
void write(MethodWriter adapter) { void write(MethodWriter adapter) {
throw new IllegalArgumentException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition.Cast; import org.elasticsearch.painless.Definition.Cast;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
@ -34,8 +35,8 @@ final class ECast extends AExpression {
Cast cast = null; Cast cast = null;
ECast(int line, int offset, String location, AExpression child, Cast cast) { ECast(Location location, AExpression child, Cast cast) {
super(line, offset, location); super(location);
this.type = null; this.type = null;
this.child = child; this.child = child;
@ -45,13 +46,13 @@ final class ECast extends AExpression {
@Override @Override
void analyze(Variables variables) { void analyze(Variables variables) {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
@Override @Override
void write(MethodWriter writer) { void write(MethodWriter writer) {
child.write(writer); child.write(writer);
writer.writeDebugInfo(offset); writer.writeDebugInfo(location);
writer.writeCast(cast); writer.writeCast(cast);
writer.writeBranch(tru, fals); writer.writeBranch(tru, fals);
} }

View File

@ -23,6 +23,7 @@ import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Cast; import org.elasticsearch.painless.Definition.Cast;
import org.elasticsearch.painless.Definition.Sort; import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.AnalyzerCaster;
import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.Operation;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
@ -46,9 +47,9 @@ public final class EChain extends AExpression {
Cast there = null; Cast there = null;
Cast back = null; Cast back = null;
public EChain(int line, int offset, String location, List<ALink> links, public EChain(Location location, List<ALink> links,
boolean pre, boolean post, Operation operation, AExpression expression) { boolean pre, boolean post, Operation operation, AExpression expression) {
super(line, offset, location); super(location);
this.links = links; this.links = links;
this.pre = pre; this.pre = pre;
@ -114,40 +115,40 @@ public final class EChain extends AExpression {
ALink last = links.get(links.size() - 1); ALink last = links.get(links.size() - 1);
if (pre && post) { if (pre && post) {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} else if (pre || post) { } else if (pre || post) {
if (expression != null) { if (expression != null) {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
Sort sort = last.after.sort; Sort sort = last.after.sort;
if (operation == Operation.INCR) { if (operation == Operation.INCR) {
if (sort == Sort.DOUBLE) { if (sort == Sort.DOUBLE) {
expression = new EConstant(line, offset, location, 1D); expression = new EConstant(location, 1D);
} else if (sort == Sort.FLOAT) { } else if (sort == Sort.FLOAT) {
expression = new EConstant(line, offset, location, 1F); expression = new EConstant(location, 1F);
} else if (sort == Sort.LONG) { } else if (sort == Sort.LONG) {
expression = new EConstant(line, offset, location, 1L); expression = new EConstant(location, 1L);
} else { } else {
expression = new EConstant(line, offset, location, 1); expression = new EConstant(location, 1);
} }
operation = Operation.ADD; operation = Operation.ADD;
} else if (operation == Operation.DECR) { } else if (operation == Operation.DECR) {
if (sort == Sort.DOUBLE) { if (sort == Sort.DOUBLE) {
expression = new EConstant(line, offset, location, 1D); expression = new EConstant(location, 1D);
} else if (sort == Sort.FLOAT) { } else if (sort == Sort.FLOAT) {
expression = new EConstant(line, offset, location, 1F); expression = new EConstant(location, 1F);
} else if (sort == Sort.LONG) { } else if (sort == Sort.LONG) {
expression = new EConstant(line, offset, location, 1L); expression = new EConstant(location, 1L);
} else { } else {
expression = new EConstant(line, offset, location, 1); expression = new EConstant(location, 1);
} }
operation = Operation.SUB; operation = Operation.SUB;
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
} }
@ -180,12 +181,12 @@ public final class EChain extends AExpression {
} else if (operation == Operation.BWOR) { } else if (operation == Operation.BWOR) {
promote = AnalyzerCaster.promoteXor(last.after, expression.actual); promote = AnalyzerCaster.promoteXor(last.after, expression.actual);
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
if (promote == null) { if (promote == null) {
throw new ClassCastException("Cannot apply compound assignment " + throw createError(new ClassCastException("Cannot apply compound assignment " +
"[" + operation.symbol + "=] to types [" + last.after + "] and [" + expression.actual + "]."); "[" + operation.symbol + "=] to types [" + last.after + "] and [" + expression.actual + "]."));
} }
cat = operation == Operation.ADD && promote.sort == Sort.STRING; cat = operation == Operation.ADD && promote.sort == Sort.STRING;
@ -248,9 +249,8 @@ public final class EChain extends AExpression {
@Override @Override
void write(MethodWriter writer) { void write(MethodWriter writer) {
if (cat) { // can cause class cast exception among other things at runtime
writer.writeDebugInfo(offset); writer.writeDebugInfo(location);
}
if (cat) { if (cat) {
writer.writeNewStrings(); writer.writeNewStrings();

View File

@ -22,6 +22,7 @@ package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Sort; import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.AnalyzerCaster;
import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.Operation;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
@ -46,8 +47,8 @@ public final class EComp extends AExpression {
AExpression left; AExpression left;
AExpression right; AExpression right;
public EComp(int line, int offset, String location, Operation operation, AExpression left, AExpression right) { public EComp(Location location, Operation operation, AExpression left, AExpression right) {
super(line, offset, location); super(location);
this.operation = operation; this.operation = operation;
this.left = left; this.left = left;
@ -73,7 +74,7 @@ public final class EComp extends AExpression {
} else if (operation == Operation.LT) { } else if (operation == Operation.LT) {
analyzeLT(variables); analyzeLT(variables);
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -84,7 +85,7 @@ public final class EComp extends AExpression {
Type promote = AnalyzerCaster.promoteEquality(left.actual, right.actual); Type promote = AnalyzerCaster.promoteEquality(left.actual, right.actual);
if (promote == null) { if (promote == null) {
throw new ClassCastException(error("Cannot apply equals [==] to types " + throw createError(new ClassCastException("Cannot apply equals [==] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + left.actual.name + "] and [" + right.actual.name + "]."));
} }
@ -95,7 +96,7 @@ public final class EComp extends AExpression {
right = right.cast(variables); right = right.cast(variables);
if (left.isNull && right.isNull) { if (left.isNull && right.isNull) {
throw new IllegalArgumentException(error("Extraneous comparison of null constants.")); throw createError(new IllegalArgumentException("Extraneous comparison of null constants."));
} }
if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) { if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) {
@ -116,7 +117,7 @@ public final class EComp extends AExpression {
} else if (!right.isNull) { } else if (!right.isNull) {
constant = right.constant.equals(null); constant = right.constant.equals(null);
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -130,7 +131,7 @@ public final class EComp extends AExpression {
Type promote = AnalyzerCaster.promoteEquality(left.actual, right.actual); Type promote = AnalyzerCaster.promoteEquality(left.actual, right.actual);
if (promote == null) { if (promote == null) {
throw new ClassCastException(error("Cannot apply reference equals [===] to types " + throw createError(new ClassCastException("Cannot apply reference equals [===] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + left.actual.name + "] and [" + right.actual.name + "]."));
} }
@ -141,7 +142,7 @@ public final class EComp extends AExpression {
right = right.cast(variables); right = right.cast(variables);
if (left.isNull && right.isNull) { if (left.isNull && right.isNull) {
throw new IllegalArgumentException(error("Extraneous comparison of null constants.")); throw createError(new IllegalArgumentException("Extraneous comparison of null constants."));
} }
if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) { if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) {
@ -172,7 +173,7 @@ public final class EComp extends AExpression {
Type promote = AnalyzerCaster.promoteEquality(left.actual, right.actual); Type promote = AnalyzerCaster.promoteEquality(left.actual, right.actual);
if (promote == null) { if (promote == null) {
throw new ClassCastException(error("Cannot apply not equals [!=] to types " + throw createError(new ClassCastException("Cannot apply not equals [!=] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + left.actual.name + "] and [" + right.actual.name + "]."));
} }
@ -183,7 +184,7 @@ public final class EComp extends AExpression {
right = right.cast(variables); right = right.cast(variables);
if (left.isNull && right.isNull) { if (left.isNull && right.isNull) {
throw new IllegalArgumentException(error("Extraneous comparison of null constants.")); throw createError(new IllegalArgumentException("Extraneous comparison of null constants."));
} }
if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) { if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) {
@ -204,7 +205,7 @@ public final class EComp extends AExpression {
} else if (!right.isNull) { } else if (!right.isNull) {
constant = !right.constant.equals(null); constant = !right.constant.equals(null);
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -218,7 +219,7 @@ public final class EComp extends AExpression {
Type promote = AnalyzerCaster.promoteEquality(left.actual, right.actual); Type promote = AnalyzerCaster.promoteEquality(left.actual, right.actual);
if (promote == null) { if (promote == null) {
throw new ClassCastException(error("Cannot apply reference not equals [!==] to types " + throw createError(new ClassCastException("Cannot apply reference not equals [!==] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + left.actual.name + "] and [" + right.actual.name + "]."));
} }
@ -229,7 +230,7 @@ public final class EComp extends AExpression {
right = right.cast(variables); right = right.cast(variables);
if (left.isNull && right.isNull) { if (left.isNull && right.isNull) {
throw new IllegalArgumentException(error("Extraneous comparison of null constants.")); throw createError(new IllegalArgumentException("Extraneous comparison of null constants."));
} }
if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) { if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) {
@ -260,7 +261,7 @@ public final class EComp extends AExpression {
Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true); Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
if (promote == null) { if (promote == null) {
throw new ClassCastException(error("Cannot apply greater than or equals [>=] to types " + throw createError(new ClassCastException("Cannot apply greater than or equals [>=] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + left.actual.name + "] and [" + right.actual.name + "]."));
} }
@ -282,7 +283,7 @@ public final class EComp extends AExpression {
} else if (sort == Sort.DOUBLE) { } else if (sort == Sort.DOUBLE) {
constant = (double)left.constant >= (double)right.constant; constant = (double)left.constant >= (double)right.constant;
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -296,7 +297,7 @@ public final class EComp extends AExpression {
Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true); Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
if (promote == null) { if (promote == null) {
throw new ClassCastException(error("Cannot apply greater than [>] to types " + throw createError(new ClassCastException("Cannot apply greater than [>] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + left.actual.name + "] and [" + right.actual.name + "]."));
} }
@ -318,7 +319,7 @@ public final class EComp extends AExpression {
} else if (sort == Sort.DOUBLE) { } else if (sort == Sort.DOUBLE) {
constant = (double)left.constant > (double)right.constant; constant = (double)left.constant > (double)right.constant;
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -332,7 +333,7 @@ public final class EComp extends AExpression {
Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true); Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
if (promote == null) { if (promote == null) {
throw new ClassCastException(error("Cannot apply less than or equals [<=] to types " + throw createError(new ClassCastException("Cannot apply less than or equals [<=] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + left.actual.name + "] and [" + right.actual.name + "]."));
} }
@ -354,7 +355,7 @@ public final class EComp extends AExpression {
} else if (sort == Sort.DOUBLE) { } else if (sort == Sort.DOUBLE) {
constant = (double)left.constant <= (double)right.constant; constant = (double)left.constant <= (double)right.constant;
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -368,7 +369,7 @@ public final class EComp extends AExpression {
Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true); Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
if (promote == null) { if (promote == null) {
throw new ClassCastException(error("Cannot apply less than [>=] to types " + throw createError(new ClassCastException("Cannot apply less than [>=] to types " +
"[" + left.actual.name + "] and [" + right.actual.name + "].")); "[" + left.actual.name + "] and [" + right.actual.name + "]."));
} }
@ -390,7 +391,7 @@ public final class EComp extends AExpression {
} else if (sort == Sort.DOUBLE) { } else if (sort == Sort.DOUBLE) {
constant = (double)left.constant < (double)right.constant; constant = (double)left.constant < (double)right.constant;
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -399,7 +400,7 @@ public final class EComp extends AExpression {
@Override @Override
void write(MethodWriter writer) { void write(MethodWriter writer) {
writer.writeDebugInfo(offset); writer.writeDebugInfo(location);
boolean branch = tru != null || fals != null; boolean branch = tru != null || fals != null;
org.objectweb.asm.Type rtype = right.actual.type; org.objectweb.asm.Type rtype = right.actual.type;
Sort rsort = right.actual.sort; Sort rsort = right.actual.sort;
@ -429,12 +430,12 @@ public final class EComp extends AExpression {
case BYTE: case BYTE:
case SHORT: case SHORT:
case CHAR: case CHAR:
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
case BOOL: case BOOL:
if (eq) writer.ifZCmp(MethodWriter.EQ, jump); if (eq) writer.ifZCmp(MethodWriter.EQ, jump);
else if (ne) writer.ifZCmp(MethodWriter.NE, jump); else if (ne) writer.ifZCmp(MethodWriter.NE, jump);
else { else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
break; break;
@ -449,7 +450,7 @@ public final class EComp extends AExpression {
else if (gt) writer.ifCmp(rtype, MethodWriter.GT, jump); else if (gt) writer.ifCmp(rtype, MethodWriter.GT, jump);
else if (gte) writer.ifCmp(rtype, MethodWriter.GE, jump); else if (gte) writer.ifCmp(rtype, MethodWriter.GE, jump);
else { else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
break; break;
@ -485,7 +486,7 @@ public final class EComp extends AExpression {
writer.invokeStatic(DEF_UTIL_TYPE, DEF_GTE_CALL); writer.invokeStatic(DEF_UTIL_TYPE, DEF_GTE_CALL);
writejump = false; writejump = false;
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
if (branch && !writejump) { if (branch && !writejump) {
@ -518,7 +519,7 @@ public final class EComp extends AExpression {
writer.ifCmp(rtype, MethodWriter.NE, jump); writer.ifCmp(rtype, MethodWriter.NE, jump);
} }
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }

View File

@ -21,6 +21,7 @@ package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.AnalyzerCaster;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Label; import org.objectweb.asm.Label;
@ -35,8 +36,8 @@ public final class EConditional extends AExpression {
AExpression left; AExpression left;
AExpression right; AExpression right;
public EConditional(int line, int offset, String location, AExpression condition, AExpression left, AExpression right) { public EConditional(Location location, AExpression condition, AExpression left, AExpression right) {
super(line, offset, location); super(location);
this.condition = condition; this.condition = condition;
this.left = left; this.left = left;
@ -50,7 +51,7 @@ public final class EConditional extends AExpression {
condition = condition.cast(variables); condition = condition.cast(variables);
if (condition.constant != null) { if (condition.constant != null) {
throw new IllegalArgumentException(error("Extraneous conditional statement.")); throw createError(new IllegalArgumentException("Extraneous conditional statement."));
} }
left.expected = expected; left.expected = expected;
@ -78,7 +79,7 @@ public final class EConditional extends AExpression {
@Override @Override
void write(MethodWriter writer) { void write(MethodWriter writer) {
writer.writeDebugInfo(offset); writer.writeDebugInfo(location);
Label localfals = new Label(); Label localfals = new Label();
Label end = new Label(); Label end = new Label();

View File

@ -21,17 +21,18 @@ package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Sort; import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
/** /**
* Respresents a constant. Note this replaces any other expression * Represents a constant. Note this replaces any other expression
* node with a constant value set during a cast. (Internal only.) * node with a constant value set during a cast. (Internal only.)
*/ */
final class EConstant extends AExpression { final class EConstant extends AExpression {
EConstant(int line, int offset, String location, Object constant) { EConstant(Location location, Object constant) {
super(line, offset, location); super(location);
this.constant = constant; this.constant = constant;
} }
@ -57,7 +58,7 @@ final class EConstant extends AExpression {
} else if (constant instanceof Boolean) { } else if (constant instanceof Boolean) {
actual = Definition.BOOLEAN_TYPE; actual = Definition.BOOLEAN_TYPE;
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -85,7 +86,7 @@ final class EConstant extends AExpression {
break; break;
default: default:
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
if (sort != Sort.BOOL) { if (sort != Sort.BOOL) {

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
@ -30,8 +31,8 @@ public final class EDecimal extends AExpression {
final String value; final String value;
public EDecimal(int line, int offset, String location, String value) { public EDecimal(Location location, String value) {
super(line, offset, location); super(location);
this.value = value; this.value = value;
} }
@ -43,20 +44,20 @@ public final class EDecimal extends AExpression {
constant = Float.parseFloat(value.substring(0, value.length() - 1)); constant = Float.parseFloat(value.substring(0, value.length() - 1));
actual = Definition.FLOAT_TYPE; actual = Definition.FLOAT_TYPE;
} catch (NumberFormatException exception) { } catch (NumberFormatException exception) {
throw new IllegalArgumentException(error("Invalid float constant [" + value + "].")); throw createError(new IllegalArgumentException("Invalid float constant [" + value + "]."));
} }
} else { } else {
try { try {
constant = Double.parseDouble(value); constant = Double.parseDouble(value);
actual = Definition.DOUBLE_TYPE; actual = Definition.DOUBLE_TYPE;
} catch (NumberFormatException exception) { } catch (NumberFormatException exception) {
throw new IllegalArgumentException(error("Invalid double constant [" + value + "].")); throw createError(new IllegalArgumentException("Invalid double constant [" + value + "]."));
} }
} }
} }
@Override @Override
void write(MethodWriter writer) { void write(MethodWriter writer) {
throw new IllegalArgumentException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
@ -31,8 +32,8 @@ public final class EExplicit extends AExpression {
final String type; final String type;
AExpression child; AExpression child;
public EExplicit(int line, int offset, String location, String type, AExpression child) { public EExplicit(Location location, String type, AExpression child) {
super(line, offset, location); super(location);
this.type = type; this.type = type;
this.child = child; this.child = child;
@ -43,7 +44,7 @@ public final class EExplicit extends AExpression {
try { try {
actual = Definition.getType(this.type); actual = Definition.getType(this.type);
} catch (IllegalArgumentException exception) { } catch (IllegalArgumentException exception) {
throw new IllegalArgumentException(error("Not a type [" + this.type + "].")); throw createError(new IllegalArgumentException("Not a type [" + this.type + "]."));
} }
child.expected = actual; child.expected = actual;
@ -54,7 +55,7 @@ public final class EExplicit extends AExpression {
@Override @Override
void write(MethodWriter writer) { void write(MethodWriter writer) {
throw new IllegalArgumentException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
AExpression cast(Variables variables) { AExpression cast(Variables variables) {

View File

@ -19,6 +19,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
@ -29,8 +30,8 @@ public class EFunctionRef extends AExpression {
public String type; public String type;
public String call; public String call;
public EFunctionRef(int line, int offset, String location, String type, String call) { public EFunctionRef(Location location, String type, String call) {
super(line, offset, location); super(location);
this.type = type; this.type = type;
this.call = call; this.call = call;
@ -38,11 +39,12 @@ public class EFunctionRef extends AExpression {
@Override @Override
void analyze(Variables variables) { void analyze(Variables variables) {
throw new UnsupportedOperationException(error("Function references [" + type + "::" + call + "] are not currently supported.")); throw createError(new UnsupportedOperationException("Function references [" + type + "::" + call +
"] are not currently supported."));
} }
@Override @Override
void write(MethodWriter writer) { void write(MethodWriter writer) {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
@ -29,8 +30,8 @@ import org.elasticsearch.painless.MethodWriter;
*/ */
public final class ENull extends AExpression { public final class ENull extends AExpression {
public ENull(int line, int offset, String location) { public ENull(Location location) {
super(line, offset, location); super(location);
} }
@Override @Override
@ -39,7 +40,7 @@ public final class ENull extends AExpression {
if (expected != null) { if (expected != null) {
if (expected.sort.primitive) { if (expected.sort.primitive) {
throw new IllegalArgumentException(error("Cannot cast null to a primitive type [" + expected.name + "].")); throw createError(new IllegalArgumentException("Cannot cast null to a primitive type [" + expected.name + "]."));
} }
actual = expected; actual = expected;

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Sort; import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
@ -32,8 +33,8 @@ public final class ENumeric extends AExpression {
final String value; final String value;
int radix; int radix;
public ENumeric(int line, int offset, String location, String value, int radix) { public ENumeric(Location location, String value, int radix) {
super(line, offset, location); super(location);
this.value = value; this.value = value;
this.radix = radix; this.radix = radix;
@ -43,32 +44,32 @@ public final class ENumeric extends AExpression {
void analyze(Variables variables) { void analyze(Variables variables) {
if (value.endsWith("d") || value.endsWith("D")) { if (value.endsWith("d") || value.endsWith("D")) {
if (radix != 10) { if (radix != 10) {
throw new IllegalStateException(error("Invalid tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
try { try {
constant = Double.parseDouble(value.substring(0, value.length() - 1)); constant = Double.parseDouble(value.substring(0, value.length() - 1));
actual = Definition.DOUBLE_TYPE; actual = Definition.DOUBLE_TYPE;
} catch (NumberFormatException exception) { } catch (NumberFormatException exception) {
throw new IllegalArgumentException(error("Invalid double constant [" + value + "].")); throw createError(new IllegalArgumentException("Invalid double constant [" + value + "]."));
} }
} else if (value.endsWith("f") || value.endsWith("F")) { } else if (value.endsWith("f") || value.endsWith("F")) {
if (radix != 10) { if (radix != 10) {
throw new IllegalStateException(error("Invalid tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
try { try {
constant = Float.parseFloat(value.substring(0, value.length() - 1)); constant = Float.parseFloat(value.substring(0, value.length() - 1));
actual = Definition.FLOAT_TYPE; actual = Definition.FLOAT_TYPE;
} catch (NumberFormatException exception) { } catch (NumberFormatException exception) {
throw new IllegalArgumentException(error("Invalid float constant [" + value + "].")); throw createError(new IllegalArgumentException("Invalid float constant [" + value + "]."));
} }
} else if (value.endsWith("l") || value.endsWith("L")) { } else if (value.endsWith("l") || value.endsWith("L")) {
try { try {
constant = Long.parseLong(value.substring(0, value.length() - 1), radix); constant = Long.parseLong(value.substring(0, value.length() - 1), radix);
actual = Definition.LONG_TYPE; actual = Definition.LONG_TYPE;
} catch (NumberFormatException exception) { } catch (NumberFormatException exception) {
throw new IllegalArgumentException(error("Invalid long constant [" + value + "].")); throw createError(new IllegalArgumentException("Invalid long constant [" + value + "]."));
} }
} else { } else {
try { try {
@ -89,13 +90,13 @@ public final class ENumeric extends AExpression {
actual = Definition.INT_TYPE; actual = Definition.INT_TYPE;
} }
} catch (NumberFormatException exception) { } catch (NumberFormatException exception) {
throw new IllegalArgumentException(error("Invalid int constant [" + value + "].")); throw createError(new IllegalArgumentException("Invalid int constant [" + value + "]."));
} }
} }
} }
@Override @Override
void write(MethodWriter writer) { void write(MethodWriter writer) {
throw new IllegalArgumentException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Sort; import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.AnalyzerCaster;
@ -40,8 +41,8 @@ public final class EUnary extends AExpression {
final Operation operation; final Operation operation;
AExpression child; AExpression child;
public EUnary(int line, int offset, String location, Operation operation, AExpression child) { public EUnary(Location location, Operation operation, AExpression child) {
super(line, offset, location); super(location);
this.operation = operation; this.operation = operation;
this.child = child; this.child = child;
@ -58,7 +59,7 @@ public final class EUnary extends AExpression {
} else if (operation == Operation.SUB) { } else if (operation == Operation.SUB) {
analyzerSub(variables); analyzerSub(variables);
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -80,7 +81,7 @@ public final class EUnary extends AExpression {
Type promote = AnalyzerCaster.promoteNumeric(child.actual, false); Type promote = AnalyzerCaster.promoteNumeric(child.actual, false);
if (promote == null) { if (promote == null) {
throw new ClassCastException(error("Cannot apply not [~] to type [" + child.actual.name + "].")); throw createError(new ClassCastException("Cannot apply not [~] to type [" + child.actual.name + "]."));
} }
child.expected = promote; child.expected = promote;
@ -94,7 +95,7 @@ public final class EUnary extends AExpression {
} else if (sort == Sort.LONG) { } else if (sort == Sort.LONG) {
constant = ~(long)child.constant; constant = ~(long)child.constant;
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -107,7 +108,7 @@ public final class EUnary extends AExpression {
Type promote = AnalyzerCaster.promoteNumeric(child.actual, true); Type promote = AnalyzerCaster.promoteNumeric(child.actual, true);
if (promote == null) { if (promote == null) {
throw new ClassCastException(error("Cannot apply positive [+] to type [" + child.actual.name + "].")); throw createError(new ClassCastException("Cannot apply positive [+] to type [" + child.actual.name + "]."));
} }
child.expected = promote; child.expected = promote;
@ -125,7 +126,7 @@ public final class EUnary extends AExpression {
} else if (sort == Sort.DOUBLE) { } else if (sort == Sort.DOUBLE) {
constant = +(double)child.constant; constant = +(double)child.constant;
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -138,7 +139,7 @@ public final class EUnary extends AExpression {
Type promote = AnalyzerCaster.promoteNumeric(child.actual, true); Type promote = AnalyzerCaster.promoteNumeric(child.actual, true);
if (promote == null) { if (promote == null) {
throw new ClassCastException(error("Cannot apply negative [-] to type [" + child.actual.name + "].")); throw createError(new ClassCastException("Cannot apply negative [-] to type [" + child.actual.name + "]."));
} }
child.expected = promote; child.expected = promote;
@ -156,7 +157,7 @@ public final class EUnary extends AExpression {
} else if (sort == Sort.DOUBLE) { } else if (sort == Sort.DOUBLE) {
constant = -(double)child.constant; constant = -(double)child.constant;
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -165,7 +166,7 @@ public final class EUnary extends AExpression {
@Override @Override
void write(MethodWriter writer) { void write(MethodWriter writer) {
writer.writeDebugInfo(offset); writer.writeDebugInfo(location);
if (operation == Operation.NOT) { if (operation == Operation.NOT) {
if (tru == null && fals == null) { if (tru == null && fals == null) {
Label localfals = new Label(); Label localfals = new Label();
@ -199,7 +200,7 @@ public final class EUnary extends AExpression {
} else if (sort == Sort.LONG) { } else if (sort == Sort.LONG) {
writer.push(-1L); writer.push(-1L);
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
writer.math(MethodWriter.XOR, type); writer.math(MethodWriter.XOR, type);
@ -211,7 +212,7 @@ public final class EUnary extends AExpression {
writer.math(MethodWriter.NEG, type); writer.math(MethodWriter.NEG, type);
} }
} else if (operation != Operation.ADD) { } else if (operation != Operation.ADD) {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
writer.writeBranch(tru, fals); writer.writeBranch(tru, fals);

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
@ -30,8 +31,8 @@ public final class LArrayLength extends ALink {
final String value; final String value;
LArrayLength(int line, int offset, String location, String value) { LArrayLength(Location location, String value) {
super(line, offset, location, -1); super(location, -1);
this.value = value; this.value = value;
} }
@ -40,14 +41,14 @@ public final class LArrayLength extends ALink {
ALink analyze(Variables variables) { ALink analyze(Variables variables) {
if ("length".equals(value)) { if ("length".equals(value)) {
if (!load) { if (!load) {
throw new IllegalArgumentException(error("Must read array field [length].")); throw createError(new IllegalArgumentException("Must read array field [length]."));
} else if (store) { } else if (store) {
throw new IllegalArgumentException(error("Cannot write to read-only array field [length].")); throw createError(new IllegalArgumentException("Cannot write to read-only array field [length]."));
} }
after = Definition.INT_TYPE; after = Definition.INT_TYPE;
} else { } else {
throw new IllegalArgumentException(error("Illegal field access [" + value + "].")); throw createError(new IllegalArgumentException("Illegal field access [" + value + "]."));
} }
return this; return this;
@ -60,12 +61,12 @@ public final class LArrayLength extends ALink {
@Override @Override
void load(MethodWriter writer) { void load(MethodWriter writer) {
writer.writeDebugInfo(offset); writer.writeDebugInfo(location);
writer.arrayLength(); writer.arrayLength();
} }
@Override @Override
void store(MethodWriter writer) { void store(MethodWriter writer) {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Sort; import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
@ -34,8 +35,8 @@ public final class LBrace extends ALink {
AExpression index; AExpression index;
public LBrace(int line, int offset, String location, AExpression index) { public LBrace(Location location, AExpression index) {
super(line, offset, location, 2); super(location, 2);
this.index = index; this.index = index;
} }
@ -43,7 +44,7 @@ public final class LBrace extends ALink {
@Override @Override
ALink analyze(Variables variables) { ALink analyze(Variables variables) {
if (before == null) { if (before == null) {
throw new IllegalArgumentException(error("Illegal array access made without target.")); throw createError(new IllegalArgumentException("Illegal array access made without target."));
} }
final Sort sort = before.sort; final Sort sort = before.sort;
@ -57,14 +58,14 @@ public final class LBrace extends ALink {
return this; return this;
} else if (sort == Sort.DEF) { } else if (sort == Sort.DEF) {
return new LDefArray(line, offset, location, index).copy(this).analyze(variables); return new LDefArray(location, index).copy(this).analyze(variables);
} else if (Map.class.isAssignableFrom(before.clazz)) { } else if (Map.class.isAssignableFrom(before.clazz)) {
return new LMapShortcut(line, offset, location, index).copy(this).analyze(variables); return new LMapShortcut(location, index).copy(this).analyze(variables);
} else if (List.class.isAssignableFrom(before.clazz)) { } else if (List.class.isAssignableFrom(before.clazz)) {
return new LListShortcut(line, offset, location, index).copy(this).analyze(variables); return new LListShortcut(location, index).copy(this).analyze(variables);
} }
throw new IllegalArgumentException(error("Illegal array access on type [" + before.name + "].")); throw createError(new IllegalArgumentException("Illegal array access on type [" + before.name + "]."));
} }
@Override @Override
@ -74,13 +75,13 @@ public final class LBrace extends ALink {
@Override @Override
void load(MethodWriter writer) { void load(MethodWriter writer) {
writer.writeDebugInfo(offset); writer.writeDebugInfo(location);
writer.arrayLoad(after.type); writer.arrayLoad(after.type);
} }
@Override @Override
void store(MethodWriter writer) { void store(MethodWriter writer) {
writer.writeDebugInfo(offset); writer.writeDebugInfo(location);
writer.arrayStore(after.type); writer.arrayStore(after.type);
} }

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.Method;
import org.elasticsearch.painless.Definition.Sort; import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Definition.Struct; import org.elasticsearch.painless.Definition.Struct;
@ -38,8 +39,8 @@ public final class LCall extends ALink {
Method method = null; Method method = null;
public LCall(int line, int offset, String location, String name, List<AExpression> arguments) { public LCall(Location location, String name, List<AExpression> arguments) {
super(line, offset, location, -1); super(location, -1);
this.name = name; this.name = name;
this.arguments = arguments; this.arguments = arguments;
@ -48,11 +49,11 @@ public final class LCall extends ALink {
@Override @Override
ALink analyze(Variables variables) { ALink analyze(Variables variables) {
if (before == null) { if (before == null) {
throw new IllegalArgumentException(error("Illegal call [" + name + "] made without target.")); throw createError(new IllegalArgumentException("Illegal call [" + name + "] made without target."));
} else if (before.sort == Sort.ARRAY) { } else if (before.sort == Sort.ARRAY) {
throw new IllegalArgumentException(error("Illegal call [" + name + "] on array type.")); throw createError(new IllegalArgumentException("Illegal call [" + name + "] on array type."));
} else if (store) { } else if (store) {
throw new IllegalArgumentException(error("Cannot assign a value to a call [" + name + "].")); throw createError(new IllegalArgumentException("Cannot assign a value to a call [" + name + "]."));
} }
Definition.MethodKey methodKey = new Definition.MethodKey(name, arguments.size()); Definition.MethodKey methodKey = new Definition.MethodKey(name, arguments.size());
@ -74,13 +75,13 @@ public final class LCall extends ALink {
return this; return this;
} else if (before.sort == Sort.DEF) { } else if (before.sort == Sort.DEF) {
ALink link = new LDefCall(line, offset, location, name, arguments); ALink link = new LDefCall(location, name, arguments);
link.copy(this); link.copy(this);
return link.analyze(variables); return link.analyze(variables);
} }
throw new IllegalArgumentException(error("Unknown call [" + name + "] with [" + arguments.size() + throw createError(new IllegalArgumentException("Unknown call [" + name + "] with [" + arguments.size() +
"] arguments on type [" + struct.name + "].")); "] arguments on type [" + struct.name + "]."));
} }
@ -91,7 +92,7 @@ public final class LCall extends ALink {
@Override @Override
void load(MethodWriter writer) { void load(MethodWriter writer) {
writer.writeDebugInfo(offset); writer.writeDebugInfo(location);
for (AExpression argument : arguments) { for (AExpression argument : arguments) {
argument.write(writer); argument.write(writer);
} }
@ -111,6 +112,6 @@ public final class LCall extends ALink {
@Override @Override
void store(MethodWriter writer) { void store(MethodWriter writer) {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Cast; import org.elasticsearch.painless.Definition.Cast;
import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.AnalyzerCaster;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
@ -34,8 +35,8 @@ public final class LCast extends ALink {
Cast cast = null; Cast cast = null;
public LCast(int line, int offset, String location, String type) { public LCast(Location location, String type) {
super(line, offset, location, -1); super(location, -1);
this.type = type; this.type = type;
} }
@ -43,15 +44,15 @@ public final class LCast extends ALink {
@Override @Override
ALink analyze(Variables variables) { ALink analyze(Variables variables) {
if (before == null) { if (before == null) {
throw new IllegalStateException(error("Illegal cast without a target.")); throw createError(new IllegalStateException("Illegal cast without a target."));
} else if (store) { } else if (store) {
throw new IllegalArgumentException(error("Cannot assign a value to a cast.")); throw createError(new IllegalArgumentException("Cannot assign a value to a cast."));
} }
try { try {
after = Definition.getType(type); after = Definition.getType(type);
} catch (IllegalArgumentException exception) { } catch (IllegalArgumentException exception) {
throw new IllegalArgumentException(error("Not a type [" + type + "].")); throw createError(new IllegalArgumentException("Not a type [" + type + "]."));
} }
cast = AnalyzerCaster.getLegalCast(location, before, after, true, false); cast = AnalyzerCaster.getLegalCast(location, before, after, true, false);
@ -61,7 +62,7 @@ public final class LCast extends ALink {
@Override @Override
void write(MethodWriter writer) { void write(MethodWriter writer) {
writer.writeDebugInfo(offset); writer.writeDebugInfo(location);
writer.writeCast(cast); writer.writeCast(cast);
} }
@ -72,6 +73,6 @@ public final class LCast extends ALink {
@Override @Override
void store(MethodWriter writer) { void store(MethodWriter writer) {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.DefBootstrap;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
@ -34,8 +35,8 @@ final class LDefArray extends ALink implements IDefLink {
AExpression index; AExpression index;
LDefArray(int line, int offset, String location, AExpression index) { LDefArray(Location location, AExpression index) {
super(line, offset, location, 2); super(location, 2);
this.index = index; this.index = index;
} }
@ -58,14 +59,14 @@ final class LDefArray extends ALink implements IDefLink {
@Override @Override
void load(MethodWriter writer) { void load(MethodWriter writer) {
writer.writeDebugInfo(offset); writer.writeDebugInfo(location);
String desc = Type.getMethodDescriptor(after.type, Definition.DEF_TYPE.type, index.actual.type); String desc = Type.getMethodDescriptor(after.type, Definition.DEF_TYPE.type, index.actual.type);
writer.invokeDynamic("arrayLoad", desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.ARRAY_LOAD); writer.invokeDynamic("arrayLoad", desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.ARRAY_LOAD);
} }
@Override @Override
void store(MethodWriter writer) { void store(MethodWriter writer) {
writer.writeDebugInfo(offset); writer.writeDebugInfo(location);
String desc = Type.getMethodDescriptor(Definition.VOID_TYPE.type, Definition.DEF_TYPE.type, index.actual.type, after.type); String desc = Type.getMethodDescriptor(Definition.VOID_TYPE.type, Definition.DEF_TYPE.type, index.actual.type, after.type);
writer.invokeDynamic("arrayStore", desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.ARRAY_STORE); writer.invokeDynamic("arrayStore", desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.ARRAY_STORE);
} }

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.DefBootstrap;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
@ -36,8 +37,8 @@ final class LDefCall extends ALink implements IDefLink {
final String name; final String name;
final List<AExpression> arguments; final List<AExpression> arguments;
LDefCall(int line, int offset, String location, String name, List<AExpression> arguments) { LDefCall(Location location, String name, List<AExpression> arguments) {
super(line, offset, location, -1); super(location, -1);
this.name = name; this.name = name;
this.arguments = arguments; this.arguments = arguments;
@ -67,7 +68,7 @@ final class LDefCall extends ALink implements IDefLink {
@Override @Override
void load(MethodWriter writer) { void load(MethodWriter writer) {
writer.writeDebugInfo(offset); writer.writeDebugInfo(location);
StringBuilder signature = new StringBuilder(); StringBuilder signature = new StringBuilder();
signature.append('('); signature.append('(');
@ -88,6 +89,6 @@ final class LDefCall extends ALink implements IDefLink {
@Override @Override
void store(MethodWriter writer) { void store(MethodWriter writer) {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.DefBootstrap;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
@ -34,8 +35,8 @@ final class LDefField extends ALink implements IDefLink {
final String value; final String value;
LDefField(int line, int offset, String location, String value) { LDefField(Location location, String value) {
super(line, offset, location, 1); super(location, 1);
this.value = value; this.value = value;
} }
@ -55,14 +56,14 @@ final class LDefField extends ALink implements IDefLink {
@Override @Override
void load(MethodWriter writer) { void load(MethodWriter writer) {
writer.writeDebugInfo(offset); writer.writeDebugInfo(location);
String desc = Type.getMethodDescriptor(after.type, Definition.DEF_TYPE.type); String desc = Type.getMethodDescriptor(after.type, Definition.DEF_TYPE.type);
writer.invokeDynamic(value, desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.LOAD); writer.invokeDynamic(value, desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.LOAD);
} }
@Override @Override
void store(MethodWriter writer) { void store(MethodWriter writer) {
writer.writeDebugInfo(offset); writer.writeDebugInfo(location);
String desc = Type.getMethodDescriptor(Definition.VOID_TYPE.type, Definition.DEF_TYPE.type, after.type); String desc = Type.getMethodDescriptor(Definition.VOID_TYPE.type, Definition.DEF_TYPE.type, after.type);
writer.invokeDynamic(value, desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.STORE); writer.invokeDynamic(value, desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.STORE);
} }

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Field; import org.elasticsearch.painless.Definition.Field;
import org.elasticsearch.painless.Definition.Sort; import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Definition.Struct; import org.elasticsearch.painless.Definition.Struct;
@ -38,8 +39,8 @@ public final class LField extends ALink {
Field field; Field field;
public LField(int line, int offset, String location, String value) { public LField(Location location, String value) {
super(line, offset, location, 1); super(location, 1);
this.value = value; this.value = value;
} }
@ -47,15 +48,15 @@ public final class LField extends ALink {
@Override @Override
ALink analyze(Variables variables) { ALink analyze(Variables variables) {
if (before == null) { if (before == null) {
throw new IllegalArgumentException(error("Illegal field [" + value + "] access made without target.")); throw createError(new IllegalArgumentException("Illegal field [" + value + "] access made without target."));
} }
Sort sort = before.sort; Sort sort = before.sort;
if (sort == Sort.ARRAY) { if (sort == Sort.ARRAY) {
return new LArrayLength(line, offset, location, value).copy(this).analyze(variables); return new LArrayLength(location, value).copy(this).analyze(variables);
} else if (sort == Sort.DEF) { } else if (sort == Sort.DEF) {
return new LDefField(line, offset, location, value).copy(this).analyze(variables); return new LDefField(location, value).copy(this).analyze(variables);
} }
Struct struct = before.struct; Struct struct = before.struct;
@ -63,7 +64,7 @@ public final class LField extends ALink {
if (field != null) { if (field != null) {
if (store && java.lang.reflect.Modifier.isFinal(field.modifiers)) { if (store && java.lang.reflect.Modifier.isFinal(field.modifiers)) {
throw new IllegalArgumentException(error( throw createError(new IllegalArgumentException(
"Cannot write to read-only field [" + value + "] for type [" + struct.name + "].")); "Cannot write to read-only field [" + value + "] for type [" + struct.name + "]."));
} }
@ -80,22 +81,22 @@ public final class LField extends ALink {
Character.toUpperCase(value.charAt(0)) + value.substring(1), 1)); Character.toUpperCase(value.charAt(0)) + value.substring(1), 1));
if (shortcut) { if (shortcut) {
return new LShortcut(line, offset, location, value).copy(this).analyze(variables); return new LShortcut(location, value).copy(this).analyze(variables);
} else { } else {
EConstant index = new EConstant(line, offset, location, value); EConstant index = new EConstant(location, value);
index.analyze(variables); index.analyze(variables);
if (Map.class.isAssignableFrom(before.clazz)) { if (Map.class.isAssignableFrom(before.clazz)) {
return new LMapShortcut(line, offset, location, index).copy(this).analyze(variables); return new LMapShortcut(location, index).copy(this).analyze(variables);
} }
if (List.class.isAssignableFrom(before.clazz)) { if (List.class.isAssignableFrom(before.clazz)) {
return new LListShortcut(line, offset, location, index).copy(this).analyze(variables); return new LListShortcut(location, index).copy(this).analyze(variables);
} }
} }
} }
throw new IllegalArgumentException(error("Unknown field [" + value + "] for type [" + struct.name + "].")); throw createError(new IllegalArgumentException("Unknown field [" + value + "] for type [" + struct.name + "]."));
} }
@Override @Override
@ -105,7 +106,7 @@ public final class LField extends ALink {
@Override @Override
void load(MethodWriter writer) { void load(MethodWriter writer) {
writer.writeDebugInfo(offset); writer.writeDebugInfo(location);
if (java.lang.reflect.Modifier.isStatic(field.modifiers)) { if (java.lang.reflect.Modifier.isStatic(field.modifiers)) {
writer.getStatic(field.owner.type, field.javaName, field.type.type); writer.getStatic(field.owner.type, field.javaName, field.type.type);
} else { } else {
@ -115,7 +116,7 @@ public final class LField extends ALink {
@Override @Override
void store(MethodWriter writer) { void store(MethodWriter writer) {
writer.writeDebugInfo(offset); writer.writeDebugInfo(location);
if (java.lang.reflect.Modifier.isStatic(field.modifiers)) { if (java.lang.reflect.Modifier.isStatic(field.modifiers)) {
writer.putStatic(field.owner.type, field.javaName, field.type.type); writer.putStatic(field.owner.type, field.javaName, field.type.type);
} else { } else {

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.Method;
import org.elasticsearch.painless.Definition.Sort; import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
@ -34,8 +35,8 @@ final class LListShortcut extends ALink {
Method getter; Method getter;
Method setter; Method setter;
LListShortcut(int line, int offset, String location, AExpression index) { LListShortcut(Location location, AExpression index) {
super(line, offset, location, 2); super(location, 2);
this.index = index; this.index = index;
} }
@ -47,16 +48,16 @@ final class LListShortcut extends ALink {
if (getter != null && (getter.rtn.sort == Sort.VOID || getter.arguments.size() != 1 || if (getter != null && (getter.rtn.sort == Sort.VOID || getter.arguments.size() != 1 ||
getter.arguments.get(0).sort != Sort.INT)) { getter.arguments.get(0).sort != Sort.INT)) {
throw new IllegalArgumentException(error("Illegal list get shortcut for type [" + before.name + "].")); throw createError(new IllegalArgumentException("Illegal list get shortcut for type [" + before.name + "]."));
} }
if (setter != null && (setter.arguments.size() != 2 || setter.arguments.get(0).sort != Sort.INT)) { if (setter != null && (setter.arguments.size() != 2 || setter.arguments.get(0).sort != Sort.INT)) {
throw new IllegalArgumentException(error("Illegal list set shortcut for type [" + before.name + "].")); throw createError(new IllegalArgumentException("Illegal list set shortcut for type [" + before.name + "]."));
} }
if (getter != null && setter != null && (!getter.arguments.get(0).equals(setter.arguments.get(0)) if (getter != null && setter != null && (!getter.arguments.get(0).equals(setter.arguments.get(0))
|| !getter.rtn.equals(setter.arguments.get(1)))) { || !getter.rtn.equals(setter.arguments.get(1)))) {
throw new IllegalArgumentException(error("Shortcut argument types must match.")); throw createError(new IllegalArgumentException("Shortcut argument types must match."));
} }
if ((load || store) && (!load || getter != null) && (!store || setter != null)) { if ((load || store) && (!load || getter != null) && (!store || setter != null)) {
@ -66,7 +67,7 @@ final class LListShortcut extends ALink {
after = setter != null ? setter.arguments.get(1) : getter.rtn; after = setter != null ? setter.arguments.get(1) : getter.rtn;
} else { } else {
throw new IllegalArgumentException(error("Illegal list shortcut for type [" + before.name + "].")); throw createError(new IllegalArgumentException("Illegal list shortcut for type [" + before.name + "]."));
} }
return this; return this;
@ -79,7 +80,7 @@ final class LListShortcut extends ALink {
@Override @Override
void load(MethodWriter writer) { void load(MethodWriter writer) {
writer.writeDebugInfo(offset); writer.writeDebugInfo(location);
if (java.lang.reflect.Modifier.isInterface(getter.owner.clazz.getModifiers())) { if (java.lang.reflect.Modifier.isInterface(getter.owner.clazz.getModifiers())) {
writer.invokeInterface(getter.owner.type, getter.method); writer.invokeInterface(getter.owner.type, getter.method);
} else { } else {
@ -93,7 +94,7 @@ final class LListShortcut extends ALink {
@Override @Override
void store(MethodWriter writer) { void store(MethodWriter writer) {
writer.writeDebugInfo(offset); writer.writeDebugInfo(location);
if (java.lang.reflect.Modifier.isInterface(setter.owner.clazz.getModifiers())) { if (java.lang.reflect.Modifier.isInterface(setter.owner.clazz.getModifiers())) {
writer.invokeInterface(setter.owner.type, setter.method); writer.invokeInterface(setter.owner.type, setter.method);
} else { } else {

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.Method;
import org.elasticsearch.painless.Definition.Sort; import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
@ -34,8 +35,8 @@ final class LMapShortcut extends ALink {
Method getter; Method getter;
Method setter; Method setter;
LMapShortcut(int line, int offset, String location, AExpression index) { LMapShortcut(Location location, AExpression index) {
super(line, offset, location, 2); super(location, 2);
this.index = index; this.index = index;
} }
@ -46,16 +47,16 @@ final class LMapShortcut extends ALink {
setter = before.struct.methods.get(new Definition.MethodKey("put", 2)); setter = before.struct.methods.get(new Definition.MethodKey("put", 2));
if (getter != null && (getter.rtn.sort == Sort.VOID || getter.arguments.size() != 1)) { if (getter != null && (getter.rtn.sort == Sort.VOID || getter.arguments.size() != 1)) {
throw new IllegalArgumentException(error("Illegal map get shortcut for type [" + before.name + "].")); throw createError(new IllegalArgumentException("Illegal map get shortcut for type [" + before.name + "]."));
} }
if (setter != null && setter.arguments.size() != 2) { if (setter != null && setter.arguments.size() != 2) {
throw new IllegalArgumentException(error("Illegal map set shortcut for type [" + before.name + "].")); throw createError(new IllegalArgumentException("Illegal map set shortcut for type [" + before.name + "]."));
} }
if (getter != null && setter != null && if (getter != null && setter != null &&
(!getter.arguments.get(0).equals(setter.arguments.get(0)) || !getter.rtn.equals(setter.arguments.get(1)))) { (!getter.arguments.get(0).equals(setter.arguments.get(0)) || !getter.rtn.equals(setter.arguments.get(1)))) {
throw new IllegalArgumentException(error("Shortcut argument types must match.")); throw createError(new IllegalArgumentException("Shortcut argument types must match."));
} }
if ((load || store) && (!load || getter != null) && (!store || setter != null)) { if ((load || store) && (!load || getter != null) && (!store || setter != null)) {
@ -65,7 +66,7 @@ final class LMapShortcut extends ALink {
after = setter != null ? setter.arguments.get(1) : getter.rtn; after = setter != null ? setter.arguments.get(1) : getter.rtn;
} else { } else {
throw new IllegalArgumentException(error("Illegal map shortcut for type [" + before.name + "].")); throw createError(new IllegalArgumentException("Illegal map shortcut for type [" + before.name + "]."));
} }
return this; return this;
@ -78,7 +79,7 @@ final class LMapShortcut extends ALink {
@Override @Override
void load(MethodWriter writer) { void load(MethodWriter writer) {
writer.writeDebugInfo(offset); writer.writeDebugInfo(location);
if (java.lang.reflect.Modifier.isInterface(getter.owner.clazz.getModifiers())) { if (java.lang.reflect.Modifier.isInterface(getter.owner.clazz.getModifiers())) {
writer.invokeInterface(getter.owner.type, getter.method); writer.invokeInterface(getter.owner.type, getter.method);
} else { } else {
@ -92,7 +93,7 @@ final class LMapShortcut extends ALink {
@Override @Override
void store(MethodWriter writer) { void store(MethodWriter writer) {
writer.writeDebugInfo(offset); writer.writeDebugInfo(location);
if (java.lang.reflect.Modifier.isInterface(setter.owner.clazz.getModifiers())) { if (java.lang.reflect.Modifier.isInterface(setter.owner.clazz.getModifiers())) {
writer.invokeInterface(setter.owner.type, setter.method); writer.invokeInterface(setter.owner.type, setter.method);
} else { } else {

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
@ -34,8 +35,8 @@ public final class LNewArray extends ALink {
final String type; final String type;
final List<AExpression> arguments; final List<AExpression> arguments;
public LNewArray(int line, int offset, String location, String type, List<AExpression> arguments) { public LNewArray(Location location, String type, List<AExpression> arguments) {
super(line, offset, location, -1); super(location, -1);
this.type = type; this.type = type;
this.arguments = arguments; this.arguments = arguments;
@ -44,11 +45,11 @@ public final class LNewArray extends ALink {
@Override @Override
ALink analyze(Variables variables) { ALink analyze(Variables variables) {
if (before != null) { if (before != null) {
throw new IllegalArgumentException(error("Cannot create a new array with a target already defined.")); throw createError(new IllegalArgumentException("Cannot create a new array with a target already defined."));
} else if (store) { } else if (store) {
throw new IllegalArgumentException(error("Cannot assign a value to a new array.")); throw createError(new IllegalArgumentException("Cannot assign a value to a new array."));
} else if (!load) { } else if (!load) {
throw new IllegalArgumentException(error("A newly created array must be read.")); throw createError(new IllegalArgumentException("A newly created array must be read."));
} }
final Type type; final Type type;
@ -56,7 +57,7 @@ public final class LNewArray extends ALink {
try { try {
type = Definition.getType(this.type); type = Definition.getType(this.type);
} catch (IllegalArgumentException exception) { } catch (IllegalArgumentException exception) {
throw new IllegalArgumentException(error("Not a type [" + this.type + "].")); throw createError(new IllegalArgumentException("Not a type [" + this.type + "]."));
} }
for (int argument = 0; argument < arguments.size(); ++argument) { for (int argument = 0; argument < arguments.size(); ++argument) {
@ -79,7 +80,7 @@ public final class LNewArray extends ALink {
@Override @Override
void load(MethodWriter writer) { void load(MethodWriter writer) {
writer.writeDebugInfo(offset); writer.writeDebugInfo(location);
for (AExpression argument : arguments) { for (AExpression argument : arguments) {
argument.write(writer); argument.write(writer);
} }
@ -93,6 +94,6 @@ public final class LNewArray extends ALink {
@Override @Override
void store(MethodWriter writer) { void store(MethodWriter writer) {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Constructor; import org.elasticsearch.painless.Definition.Constructor;
import org.elasticsearch.painless.Definition.Struct; import org.elasticsearch.painless.Definition.Struct;
import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Definition.Type;
@ -29,7 +30,7 @@ import org.elasticsearch.painless.MethodWriter;
import java.util.List; import java.util.List;
/** /**
* Respresents and object instantiation. * Represents and object instantiation.
*/ */
public final class LNewObj extends ALink { public final class LNewObj extends ALink {
@ -38,8 +39,8 @@ public final class LNewObj extends ALink {
Constructor constructor; Constructor constructor;
public LNewObj(int line, int offset, String location, String type, List<AExpression> arguments) { public LNewObj(Location location, String type, List<AExpression> arguments) {
super(line, offset, location, -1); super(location, -1);
this.type = type; this.type = type;
this.arguments = arguments; this.arguments = arguments;
@ -48,9 +49,9 @@ public final class LNewObj extends ALink {
@Override @Override
ALink analyze(Variables variables) { ALink analyze(Variables variables) {
if (before != null) { if (before != null) {
throw new IllegalArgumentException(error("Illegal new call with a target already defined.")); throw createError(new IllegalArgumentException("Illegal new call with a target already defined."));
} else if (store) { } else if (store) {
throw new IllegalArgumentException(error("Cannot assign a value to a new call.")); throw createError(new IllegalArgumentException("Cannot assign a value to a new call."));
} }
final Type type; final Type type;
@ -58,7 +59,7 @@ public final class LNewObj extends ALink {
try { try {
type = Definition.getType(this.type); type = Definition.getType(this.type);
} catch (IllegalArgumentException exception) { } catch (IllegalArgumentException exception) {
throw new IllegalArgumentException(error("Not a type [" + this.type + "].")); throw createError(new IllegalArgumentException("Not a type [" + this.type + "]."));
} }
Struct struct = type.struct; Struct struct = type.struct;
@ -69,7 +70,7 @@ public final class LNewObj extends ALink {
constructor.arguments.toArray(types); constructor.arguments.toArray(types);
if (constructor.arguments.size() != arguments.size()) { if (constructor.arguments.size() != arguments.size()) {
throw new IllegalArgumentException(error("When calling constructor on type [" + struct.name + "]" + throw createError(new IllegalArgumentException("When calling constructor on type [" + struct.name + "]" +
" expected [" + constructor.arguments.size() + "] arguments, but found [" + arguments.size() + "].")); " expected [" + constructor.arguments.size() + "] arguments, but found [" + arguments.size() + "]."));
} }
@ -85,7 +86,7 @@ public final class LNewObj extends ALink {
statement = true; statement = true;
after = type; after = type;
} else { } else {
throw new IllegalArgumentException(error("Unknown new call on type [" + struct.name + "].")); throw createError(new IllegalArgumentException("Unknown new call on type [" + struct.name + "]."));
} }
return this; return this;
@ -98,7 +99,7 @@ public final class LNewObj extends ALink {
@Override @Override
void load(MethodWriter writer) { void load(MethodWriter writer) {
writer.writeDebugInfo(offset); writer.writeDebugInfo(location);
writer.newInstance(after.type); writer.newInstance(after.type);
if (load) { if (load) {
@ -114,6 +115,6 @@ public final class LNewObj extends ALink {
@Override @Override
void store(MethodWriter writer) { void store(MethodWriter writer) {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.Method;
import org.elasticsearch.painless.Definition.Sort; import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Definition.Struct; import org.elasticsearch.painless.Definition.Struct;
@ -36,8 +37,8 @@ final class LShortcut extends ALink {
Method getter = null; Method getter = null;
Method setter = null; Method setter = null;
LShortcut(int line, int offset, String location, String value) { LShortcut(Location location, String value) {
super(line, offset, location, 1); super(location, 1);
this.value = value; this.value = value;
} }
@ -55,23 +56,23 @@ final class LShortcut extends ALink {
setter = struct.methods.get(new Definition.MethodKey("set" + Character.toUpperCase(value.charAt(0)) + value.substring(1), 1)); setter = struct.methods.get(new Definition.MethodKey("set" + Character.toUpperCase(value.charAt(0)) + value.substring(1), 1));
if (getter != null && (getter.rtn.sort == Sort.VOID || !getter.arguments.isEmpty())) { if (getter != null && (getter.rtn.sort == Sort.VOID || !getter.arguments.isEmpty())) {
throw new IllegalArgumentException(error( throw createError(new IllegalArgumentException(
"Illegal get shortcut on field [" + value + "] for type [" + struct.name + "].")); "Illegal get shortcut on field [" + value + "] for type [" + struct.name + "]."));
} }
if (setter != null && (setter.rtn.sort != Sort.VOID || setter.arguments.size() != 1)) { if (setter != null && (setter.rtn.sort != Sort.VOID || setter.arguments.size() != 1)) {
throw new IllegalArgumentException(error( throw createError(new IllegalArgumentException(
"Illegal set shortcut on field [" + value + "] for type [" + struct.name + "].")); "Illegal set shortcut on field [" + value + "] for type [" + struct.name + "]."));
} }
if (getter != null && setter != null && setter.arguments.get(0) != getter.rtn) { if (getter != null && setter != null && setter.arguments.get(0) != getter.rtn) {
throw new IllegalArgumentException(error("Shortcut argument types must match.")); throw createError(new IllegalArgumentException("Shortcut argument types must match."));
} }
if ((getter != null || setter != null) && (!load || getter != null) && (!store || setter != null)) { if ((getter != null || setter != null) && (!load || getter != null) && (!store || setter != null)) {
after = setter != null ? setter.arguments.get(0) : getter.rtn; after = setter != null ? setter.arguments.get(0) : getter.rtn;
} else { } else {
throw new IllegalArgumentException(error("Illegal shortcut on field [" + value + "] for type [" + struct.name + "].")); throw createError(new IllegalArgumentException("Illegal shortcut on field [" + value + "] for type [" + struct.name + "]."));
} }
return this; return this;
@ -84,7 +85,7 @@ final class LShortcut extends ALink {
@Override @Override
void load(MethodWriter writer) { void load(MethodWriter writer) {
writer.writeDebugInfo(offset); writer.writeDebugInfo(location);
if (java.lang.reflect.Modifier.isInterface(getter.owner.clazz.getModifiers())) { if (java.lang.reflect.Modifier.isInterface(getter.owner.clazz.getModifiers())) {
writer.invokeInterface(getter.owner.type, getter.method); writer.invokeInterface(getter.owner.type, getter.method);
} else { } else {
@ -98,7 +99,7 @@ final class LShortcut extends ALink {
@Override @Override
void store(MethodWriter writer) { void store(MethodWriter writer) {
writer.writeDebugInfo(offset); writer.writeDebugInfo(location);
if (java.lang.reflect.Modifier.isInterface(setter.owner.clazz.getModifiers())) { if (java.lang.reflect.Modifier.isInterface(setter.owner.clazz.getModifiers())) {
writer.invokeInterface(setter.owner.type, setter.method); writer.invokeInterface(setter.owner.type, setter.method);
} else { } else {

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
@ -30,8 +31,8 @@ public final class LStatic extends ALink {
final String type; final String type;
public LStatic(int line, int offset, String location, String type) { public LStatic(Location location, String type) {
super(line, offset, location, 0); super(location, 0);
this.type = type; this.type = type;
} }
@ -39,14 +40,14 @@ public final class LStatic extends ALink {
@Override @Override
ALink analyze(Variables variables) { ALink analyze(Variables variables) {
if (before != null) { if (before != null) {
throw new IllegalArgumentException(error("Illegal static type [" + type + "] after target already defined.")); throw createError(new IllegalArgumentException("Illegal static type [" + type + "] after target already defined."));
} }
try { try {
after = Definition.getType(type); after = Definition.getType(type);
statik = true; statik = true;
} catch (IllegalArgumentException exception) { } catch (IllegalArgumentException exception) {
throw new IllegalArgumentException(error("Not a type [" + type + "].")); throw createError(new IllegalArgumentException("Not a type [" + type + "]."));
} }
return this; return this;
@ -54,16 +55,16 @@ public final class LStatic extends ALink {
@Override @Override
void write(MethodWriter writer) { void write(MethodWriter writer) {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
@Override @Override
void load(MethodWriter writer) { void load(MethodWriter writer) {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
@Override @Override
void store(MethodWriter writer) { void store(MethodWriter writer) {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
@ -28,8 +29,8 @@ import org.elasticsearch.painless.MethodWriter;
*/ */
public final class LString extends ALink { public final class LString extends ALink {
public LString(int line, int offset, String location, String string) { public LString(Location location, String string) {
super(line, offset, location, -1); super(location, -1);
this.string = string; this.string = string;
} }
@ -37,11 +38,11 @@ public final class LString extends ALink {
@Override @Override
ALink analyze(Variables variables) { ALink analyze(Variables variables) {
if (before != null) { if (before != null) {
throw new IllegalArgumentException(error("Illegal String constant [" + string + "].")); throw createError(new IllegalArgumentException("Illegal String constant [" + string + "]."));
} else if (store) { } else if (store) {
throw new IllegalArgumentException(error("Cannot write to read-only String constant [" + string + "].")); throw createError(new IllegalArgumentException("Cannot write to read-only String constant [" + string + "]."));
} else if (!load) { } else if (!load) {
throw new IllegalArgumentException(error("Must read String constant [" + string + "].")); throw createError(new IllegalArgumentException("Must read String constant [" + string + "]."));
} }
after = Definition.STRING_TYPE; after = Definition.STRING_TYPE;
@ -61,6 +62,6 @@ public final class LString extends ALink {
@Override @Override
void store(MethodWriter writer) { void store(MethodWriter writer) {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }

View File

@ -19,6 +19,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.Variables.Variable; import org.elasticsearch.painless.Variables.Variable;
@ -33,8 +34,8 @@ public final class LVariable extends ALink {
int slot; int slot;
public LVariable(int line, int offset, String location, String name) { public LVariable(Location location, String name) {
super(line, offset, location, 0); super(location, 0);
this.name = name; this.name = name;
} }
@ -42,13 +43,13 @@ public final class LVariable extends ALink {
@Override @Override
ALink analyze(Variables variables) { ALink analyze(Variables variables) {
if (before != null) { if (before != null) {
throw new IllegalArgumentException(error("Illegal variable [" + name + "] access with target already defined.")); throw createError(new IllegalArgumentException("Illegal variable [" + name + "] access with target already defined."));
} }
Variable variable = variables.getVariable(location, name); Variable variable = variables.getVariable(location, name);
if (store && variable.readonly) { if (store && variable.readonly) {
throw new IllegalArgumentException(error("Variable [" + variable.name + "] is read-only.")); throw createError(new IllegalArgumentException("Variable [" + variable.name + "] is read-only."));
} }
slot = variable.slot; slot = variable.slot;

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
import java.util.Collections; import java.util.Collections;
@ -32,8 +33,8 @@ public final class SBlock extends AStatement {
final List<AStatement> statements; final List<AStatement> statements;
public SBlock(int line, int offset, String location, List<AStatement> statements) { public SBlock(Location location, List<AStatement> statements) {
super(line, offset, location); super(location);
this.statements = Collections.unmodifiableList(statements); this.statements = Collections.unmodifiableList(statements);
} }
@ -41,14 +42,14 @@ public final class SBlock extends AStatement {
@Override @Override
void analyze(Variables variables) { void analyze(Variables variables) {
if (statements == null || statements.isEmpty()) { if (statements == null || statements.isEmpty()) {
throw new IllegalArgumentException(error("A block must contain at least one statement.")); throw createError(new IllegalArgumentException("A block must contain at least one statement."));
} }
final AStatement last = statements.get(statements.size() - 1); final AStatement last = statements.get(statements.size() - 1);
for (AStatement statement : statements) { for (AStatement statement : statements) {
if (allEscape) { if (allEscape) {
throw new IllegalArgumentException(error("Unreachable statement.")); throw createError(new IllegalArgumentException("Unreachable statement."));
} }
statement.inLoop = inLoop; statement.inLoop = inLoop;

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
/** /**
@ -27,14 +28,14 @@ import org.elasticsearch.painless.MethodWriter;
*/ */
public final class SBreak extends AStatement { public final class SBreak extends AStatement {
public SBreak(int line, int offset, String location) { public SBreak(Location location) {
super(line, offset, location); super(location);
} }
@Override @Override
void analyze(Variables variables) { void analyze(Variables variables) {
if (!inLoop) { if (!inLoop) {
throw new IllegalArgumentException(error("Break statement outside of a loop.")); throw createError(new IllegalArgumentException("Break statement outside of a loop."));
} }
loopEscape = true; loopEscape = true;

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.Variables.Variable; import org.elasticsearch.painless.Variables.Variable;
@ -42,8 +43,8 @@ public final class SCatch extends AStatement {
Label end; Label end;
Label exception; Label exception;
public SCatch(int line, int offset, String location, String type, String name, SBlock block) { public SCatch(Location location, String type, String name, SBlock block) {
super(line, offset, location); super(location);
this.type = type; this.type = type;
this.name = name; this.name = name;
@ -57,11 +58,11 @@ public final class SCatch extends AStatement {
try { try {
type = Definition.getType(this.type); type = Definition.getType(this.type);
} catch (IllegalArgumentException exception) { } catch (IllegalArgumentException exception) {
throw new IllegalArgumentException(error("Not a type [" + this.type + "].")); throw createError(new IllegalArgumentException("Not a type [" + this.type + "]."));
} }
if (!Exception.class.isAssignableFrom(type.clazz)) { if (!Exception.class.isAssignableFrom(type.clazz)) {
throw new ClassCastException(error("Not an exception type [" + this.type + "].")); throw createError(new ClassCastException("Not an exception type [" + this.type + "]."));
} }
variable = variables.addVariable(location, type, name, true, false); variable = variables.addVariable(location, type, name, true, false);
@ -84,7 +85,7 @@ public final class SCatch extends AStatement {
@Override @Override
void write(MethodWriter writer) { void write(MethodWriter writer) {
writer.writeStatementOffset(offset); writer.writeStatementOffset(location);
Label jump = new Label(); Label jump = new Label();
writer.mark(jump); writer.mark(jump);

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
/** /**
@ -27,18 +28,18 @@ import org.elasticsearch.painless.MethodWriter;
*/ */
public final class SContinue extends AStatement { public final class SContinue extends AStatement {
public SContinue(int line, int offset, String location) { public SContinue(Location location) {
super(line, offset, location); super(location);
} }
@Override @Override
void analyze(Variables variables) { void analyze(Variables variables) {
if (!inLoop) { if (!inLoop) {
throw new IllegalArgumentException(error("Continue statement outside of a loop.")); throw createError(new IllegalArgumentException("Continue statement outside of a loop."));
} }
if (lastLoop) { if (lastLoop) {
throw new IllegalArgumentException(error("Extraneous continue statement.")); throw createError(new IllegalArgumentException("Extraneous continue statement."));
} }
allEscape = true; allEscape = true;

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
import java.util.Collections; import java.util.Collections;
@ -32,8 +33,8 @@ public final class SDeclBlock extends AStatement {
final List<SDeclaration> declarations; final List<SDeclaration> declarations;
public SDeclBlock(int line, int offset, String location, List<SDeclaration> declarations) { public SDeclBlock(Location location, List<SDeclaration> declarations) {
super(line, offset, location); super(location);
this.declarations = Collections.unmodifiableList(declarations); this.declarations = Collections.unmodifiableList(declarations);
} }

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.Variables.Variable; import org.elasticsearch.painless.Variables.Variable;
@ -37,8 +38,8 @@ public final class SDeclaration extends AStatement {
Variable variable; Variable variable;
public SDeclaration(int line, int offset, String location, String type, String name, AExpression expression) { public SDeclaration(Location location, String type, String name, AExpression expression) {
super(line, offset, location); super(location);
this.type = type; this.type = type;
this.name = name; this.name = name;
@ -52,7 +53,7 @@ public final class SDeclaration extends AStatement {
try { try {
type = Definition.getType(this.type); type = Definition.getType(this.type);
} catch (IllegalArgumentException exception) { } catch (IllegalArgumentException exception) {
throw new IllegalArgumentException(error("Not a type [" + this.type + "].")); throw createError(new IllegalArgumentException("Not a type [" + this.type + "]."));
} }
if (expression != null) { if (expression != null) {
@ -66,10 +67,10 @@ public final class SDeclaration extends AStatement {
@Override @Override
void write(MethodWriter writer) { void write(MethodWriter writer) {
writer.writeStatementOffset(offset); writer.writeStatementOffset(location);
if (expression == null) { if (expression == null) {
switch (variable.type.sort) { switch (variable.type.sort) {
case VOID: throw new IllegalStateException(error("Illegal tree structure.")); case VOID: throw createError(new IllegalStateException("Illegal tree structure."));
case BOOL: case BOOL:
case BYTE: case BYTE:
case SHORT: case SHORT:

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Label; import org.objectweb.asm.Label;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
@ -33,8 +34,8 @@ public final class SDo extends AStatement {
final SBlock block; final SBlock block;
AExpression condition; AExpression condition;
public SDo(int line, int offset, String location, int maxLoopCounter, SBlock block, AExpression condition) { public SDo(Location location, int maxLoopCounter, SBlock block, AExpression condition) {
super(line, offset, location); super(location);
this.condition = condition; this.condition = condition;
this.block = block; this.block = block;
@ -46,7 +47,7 @@ public final class SDo extends AStatement {
variables.incrementScope(); variables.incrementScope();
if (block == null) { if (block == null) {
throw new IllegalArgumentException(error("Extraneous do while loop.")); throw createError(new IllegalArgumentException("Extraneous do while loop."));
} }
block.beginLoop = true; block.beginLoop = true;
@ -55,7 +56,7 @@ public final class SDo extends AStatement {
block.analyze(variables); block.analyze(variables);
if (block.loopEscape && !block.anyContinue) { if (block.loopEscape && !block.anyContinue) {
throw new IllegalArgumentException(error("Extraneous do while loop.")); throw createError(new IllegalArgumentException("Extraneous do while loop."));
} }
condition.expected = Definition.BOOLEAN_TYPE; condition.expected = Definition.BOOLEAN_TYPE;
@ -66,7 +67,7 @@ public final class SDo extends AStatement {
final boolean continuous = (boolean)condition.constant; final boolean continuous = (boolean)condition.constant;
if (!continuous) { if (!continuous) {
throw new IllegalArgumentException(error("Extraneous do while loop.")); throw createError(new IllegalArgumentException("Extraneous do while loop."));
} }
if (!block.anyBreak) { if (!block.anyBreak) {
@ -86,7 +87,7 @@ public final class SDo extends AStatement {
@Override @Override
void write(MethodWriter writer) { void write(MethodWriter writer) {
writer.writeStatementOffset(offset); writer.writeStatementOffset(location);
Label start = new Label(); Label start = new Label();
Label begin = new Label(); Label begin = new Label();
Label end = new Label(); Label end = new Label();
@ -102,7 +103,7 @@ public final class SDo extends AStatement {
condition.fals = end; condition.fals = end;
condition.write(writer); condition.write(writer);
writer.writeLoopCounter(loopCounterSlot, Math.max(1, block.statementCount), offset); writer.writeLoopCounter(loopCounterSlot, Math.max(1, block.statementCount), location);
writer.goTo(start); writer.goTo(start);
writer.mark(end); writer.mark(end);

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Sort; import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
@ -31,8 +32,8 @@ public final class SExpression extends AStatement {
AExpression expression; AExpression expression;
public SExpression(int line, int offset, String location, AExpression expression) { public SExpression(Location location, AExpression expression) {
super(line, offset, location); super(location);
this.expression = expression; this.expression = expression;
} }
@ -43,7 +44,7 @@ public final class SExpression extends AStatement {
expression.analyze(variables); expression.analyze(variables);
if (!lastSource && !expression.statement) { if (!lastSource && !expression.statement) {
throw new IllegalArgumentException(error("Not a statement.")); throw createError(new IllegalArgumentException("Not a statement."));
} }
final boolean rtn = lastSource && expression.actual.sort != Sort.VOID; final boolean rtn = lastSource && expression.actual.sort != Sort.VOID;
@ -60,7 +61,7 @@ public final class SExpression extends AStatement {
@Override @Override
void write(MethodWriter writer) { void write(MethodWriter writer) {
writer.writeStatementOffset(offset); writer.writeStatementOffset(location);
expression.write(writer); expression.write(writer);
if (methodEscape) { if (methodEscape) {

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Label; import org.objectweb.asm.Label;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
@ -35,9 +36,9 @@ public final class SFor extends AStatement {
AExpression afterthought; AExpression afterthought;
final SBlock block; final SBlock block;
public SFor(int line, int offset, String location, int maxLoopCounter, public SFor(Location location, int maxLoopCounter,
ANode initializer, AExpression condition, AExpression afterthought, SBlock block) { ANode initializer, AExpression condition, AExpression afterthought, SBlock block) {
super(line, offset, location); super(location);
this.initializer = initializer; this.initializer = initializer;
this.condition = condition; this.condition = condition;
@ -62,10 +63,10 @@ public final class SFor extends AStatement {
initializer.analyze(variables); initializer.analyze(variables);
if (!initializer.statement) { if (!initializer.statement) {
throw new IllegalArgumentException(initializer.error("Not a statement.")); throw createError(new IllegalArgumentException("Not a statement."));
} }
} else { } else {
throw new IllegalStateException(error("Illegal tree structure.")); throw createError(new IllegalStateException("Illegal tree structure."));
} }
} }
@ -78,11 +79,11 @@ public final class SFor extends AStatement {
continuous = (boolean)condition.constant; continuous = (boolean)condition.constant;
if (!continuous) { if (!continuous) {
throw new IllegalArgumentException(error("Extraneous for loop.")); throw createError(new IllegalArgumentException("Extraneous for loop."));
} }
if (block == null) { if (block == null) {
throw new IllegalArgumentException(error("For loop has no escape.")); throw createError(new IllegalArgumentException("For loop has no escape."));
} }
} }
} else { } else {
@ -94,7 +95,7 @@ public final class SFor extends AStatement {
afterthought.analyze(variables); afterthought.analyze(variables);
if (!afterthought.statement) { if (!afterthought.statement) {
throw new IllegalArgumentException(afterthought.error("Not a statement.")); throw createError(new IllegalArgumentException("Not a statement."));
} }
} }
@ -105,7 +106,7 @@ public final class SFor extends AStatement {
block.analyze(variables); block.analyze(variables);
if (block.loopEscape && !block.anyContinue) { if (block.loopEscape && !block.anyContinue) {
throw new IllegalArgumentException(error("Extraneous for loop.")); throw createError(new IllegalArgumentException("Extraneous for loop."));
} }
if (continuous && !block.anyBreak) { if (continuous && !block.anyBreak) {
@ -127,7 +128,7 @@ public final class SFor extends AStatement {
@Override @Override
void write(MethodWriter writer) { void write(MethodWriter writer) {
writer.writeStatementOffset(offset); writer.writeStatementOffset(location);
Label start = new Label(); Label start = new Label();
Label begin = afterthought == null ? start : new Label(); Label begin = afterthought == null ? start : new Label();
Label end = new Label(); Label end = new Label();
@ -159,10 +160,10 @@ public final class SFor extends AStatement {
++statementCount; ++statementCount;
} }
writer.writeLoopCounter(loopCounterSlot, statementCount, offset); writer.writeLoopCounter(loopCounterSlot, statementCount, location);
block.write(writer); block.write(writer);
} else { } else {
writer.writeLoopCounter(loopCounterSlot, 1, offset); writer.writeLoopCounter(loopCounterSlot, 1, location);
} }
if (afterthought != null) { if (afterthought != null) {

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Label; import org.objectweb.asm.Label;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
@ -32,8 +33,8 @@ public final class SIf extends AStatement {
AExpression condition; AExpression condition;
final SBlock ifblock; final SBlock ifblock;
public SIf(int line, int offset, String location, AExpression condition, SBlock ifblock) { public SIf(Location location, AExpression condition, SBlock ifblock) {
super(line, offset, location); super(location);
this.condition = condition; this.condition = condition;
this.ifblock = ifblock; this.ifblock = ifblock;
@ -46,11 +47,11 @@ public final class SIf extends AStatement {
condition = condition.cast(variables); condition = condition.cast(variables);
if (condition.constant != null) { if (condition.constant != null) {
throw new IllegalArgumentException(error("Extraneous if statement.")); throw createError(new IllegalArgumentException("Extraneous if statement."));
} }
if (ifblock == null) { if (ifblock == null) {
throw new IllegalArgumentException(error("Extraneous if statement.")); throw createError(new IllegalArgumentException("Extraneous if statement."));
} }
ifblock.lastSource = lastSource; ifblock.lastSource = lastSource;
@ -68,7 +69,7 @@ public final class SIf extends AStatement {
@Override @Override
void write(MethodWriter writer) { void write(MethodWriter writer) {
writer.writeStatementOffset(offset); writer.writeStatementOffset(location);
Label fals = new Label(); Label fals = new Label();
condition.fals = fals; condition.fals = fals;

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Label; import org.objectweb.asm.Label;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
@ -33,8 +34,8 @@ public final class SIfElse extends AStatement {
final SBlock ifblock; final SBlock ifblock;
final SBlock elseblock; final SBlock elseblock;
public SIfElse(int line, int offset, String location, AExpression condition, SBlock ifblock, SBlock elseblock) { public SIfElse(Location location, AExpression condition, SBlock ifblock, SBlock elseblock) {
super(line, offset, location); super(location);
this.condition = condition; this.condition = condition;
this.ifblock = ifblock; this.ifblock = ifblock;
@ -48,11 +49,11 @@ public final class SIfElse extends AStatement {
condition = condition.cast(variables); condition = condition.cast(variables);
if (condition.constant != null) { if (condition.constant != null) {
throw new IllegalArgumentException(error("Extraneous if statement.")); throw createError(new IllegalArgumentException("Extraneous if statement."));
} }
if (ifblock == null) { if (ifblock == null) {
throw new IllegalArgumentException(error("Extraneous if statement.")); throw createError(new IllegalArgumentException("Extraneous if statement."));
} }
ifblock.lastSource = lastSource; ifblock.lastSource = lastSource;
@ -68,7 +69,7 @@ public final class SIfElse extends AStatement {
statementCount = ifblock.statementCount; statementCount = ifblock.statementCount;
if (elseblock == null) { if (elseblock == null) {
throw new IllegalArgumentException(error("Extraneous else statement.")); throw createError(new IllegalArgumentException("Extraneous else statement."));
} }
elseblock.lastSource = lastSource; elseblock.lastSource = lastSource;
@ -89,7 +90,7 @@ public final class SIfElse extends AStatement {
@Override @Override
void write(MethodWriter writer) { void write(MethodWriter writer) {
writer.writeStatementOffset(offset); writer.writeStatementOffset(location);
Label end = new Label(); Label end = new Label();
Label fals = elseblock != null ? new Label() : end; Label fals = elseblock != null ? new Label() : end;

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
@ -30,8 +31,8 @@ public final class SReturn extends AStatement {
AExpression expression; AExpression expression;
public SReturn(int line, int offset, String location, AExpression expression) { public SReturn(Location location, AExpression expression) {
super(line, offset, location); super(location);
this.expression = expression; this.expression = expression;
} }
@ -52,7 +53,7 @@ public final class SReturn extends AStatement {
@Override @Override
void write(MethodWriter writer) { void write(MethodWriter writer) {
writer.writeStatementOffset(offset); writer.writeStatementOffset(location);
expression.write(writer); expression.write(writer);
writer.returnValue(); writer.returnValue();
} }

View File

@ -21,6 +21,7 @@ package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
import java.util.Collections; import java.util.Collections;
@ -33,8 +34,8 @@ public final class SSource extends AStatement {
final List<AStatement> statements; final List<AStatement> statements;
public SSource(int line, int offset, String location, List<AStatement> statements) { public SSource(Location location, List<AStatement> statements) {
super(line, offset, location); super(location);
this.statements = Collections.unmodifiableList(statements); this.statements = Collections.unmodifiableList(statements);
} }
@ -42,7 +43,7 @@ public final class SSource extends AStatement {
@Override @Override
public void analyze(Variables variables) { public void analyze(Variables variables) {
if (statements == null || statements.isEmpty()) { if (statements == null || statements.isEmpty()) {
throw new IllegalArgumentException(error("Cannot generate an empty script.")); throw createError(new IllegalArgumentException("Cannot generate an empty script."));
} }
variables.incrementScope(); variables.incrementScope();
@ -50,8 +51,9 @@ public final class SSource extends AStatement {
final AStatement last = statements.get(statements.size() - 1); final AStatement last = statements.get(statements.size() - 1);
for (AStatement statement : statements) { for (AStatement statement : statements) {
// TODO: why are we checking only statements 0..n-1 (this effectively checks only the previous statement)
if (allEscape) { if (allEscape) {
throw new IllegalArgumentException(error("Unreachable statement.")); throw createError(new IllegalArgumentException("Unreachable statement."));
} }
statement.lastSource = statement == last; statement.lastSource = statement == last;

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
@ -30,8 +31,8 @@ public final class SThrow extends AStatement {
AExpression expression; AExpression expression;
public SThrow(int line, int offset, String location, AExpression expression) { public SThrow(Location location, AExpression expression) {
super(line, offset, location); super(location);
this.expression = expression; this.expression = expression;
} }
@ -50,7 +51,7 @@ public final class SThrow extends AStatement {
@Override @Override
void write(MethodWriter writer) { void write(MethodWriter writer) {
writer.writeStatementOffset(offset); writer.writeStatementOffset(location);
expression.write(writer); expression.write(writer);
writer.throwException(); writer.throwException();
} }

View File

@ -21,6 +21,7 @@ package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Label; import org.objectweb.asm.Label;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
import java.util.Collections; import java.util.Collections;
@ -34,8 +35,8 @@ public final class STry extends AStatement {
final SBlock block; final SBlock block;
final List<SCatch> catches; final List<SCatch> catches;
public STry(int line, int offset, String location, SBlock block, List<SCatch> traps) { public STry(Location location, SBlock block, List<SCatch> traps) {
super(line, offset, location); super(location);
this.block = block; this.block = block;
this.catches = Collections.unmodifiableList(traps); this.catches = Collections.unmodifiableList(traps);
@ -44,7 +45,7 @@ public final class STry extends AStatement {
@Override @Override
void analyze(Variables variables) { void analyze(Variables variables) {
if (block == null) { if (block == null) {
throw new IllegalArgumentException(error("Extraneous try statement.")); throw createError(new IllegalArgumentException("Extraneous try statement."));
} }
block.lastSource = lastSource; block.lastSource = lastSource;
@ -86,7 +87,7 @@ public final class STry extends AStatement {
@Override @Override
void write(MethodWriter writer) { void write(MethodWriter writer) {
writer.writeStatementOffset(offset); writer.writeStatementOffset(location);
Label begin = new Label(); Label begin = new Label();
Label end = new Label(); Label end = new Label();
Label exception = new Label(); Label exception = new Label();

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Label; import org.objectweb.asm.Label;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
@ -33,8 +34,8 @@ public final class SWhile extends AStatement {
AExpression condition; AExpression condition;
final SBlock block; final SBlock block;
public SWhile(int line, int offset, String location, int maxLoopCounter, AExpression condition, SBlock block) { public SWhile(Location location, int maxLoopCounter, AExpression condition, SBlock block) {
super(line, offset, location); super(location);
this.maxLoopCounter = maxLoopCounter; this.maxLoopCounter = maxLoopCounter;
this.condition = condition; this.condition = condition;
@ -55,11 +56,11 @@ public final class SWhile extends AStatement {
continuous = (boolean)condition.constant; continuous = (boolean)condition.constant;
if (!continuous) { if (!continuous) {
throw new IllegalArgumentException(error("Extraneous while loop.")); throw createError(new IllegalArgumentException("Extraneous while loop."));
} }
if (block == null) { if (block == null) {
throw new IllegalArgumentException(error("While loop has no escape.")); throw createError(new IllegalArgumentException("While loop has no escape."));
} }
} }
@ -70,7 +71,7 @@ public final class SWhile extends AStatement {
block.analyze(variables); block.analyze(variables);
if (block.loopEscape && !block.anyContinue) { if (block.loopEscape && !block.anyContinue) {
throw new IllegalArgumentException(error("Extraneous while loop.")); throw createError(new IllegalArgumentException("Extraneous while loop."));
} }
if (continuous && !block.anyBreak) { if (continuous && !block.anyBreak) {
@ -92,7 +93,7 @@ public final class SWhile extends AStatement {
@Override @Override
void write(MethodWriter writer) { void write(MethodWriter writer) {
writer.writeStatementOffset(offset); writer.writeStatementOffset(location);
Label begin = new Label(); Label begin = new Label();
Label end = new Label(); Label end = new Label();
@ -102,13 +103,13 @@ public final class SWhile extends AStatement {
condition.write(writer); condition.write(writer);
if (block != null) { if (block != null) {
writer.writeLoopCounter(loopCounterSlot, Math.max(1, block.statementCount), offset); writer.writeLoopCounter(loopCounterSlot, Math.max(1, block.statementCount), location);
block.continu = begin; block.continu = begin;
block.brake = end; block.brake = end;
block.write(writer); block.write(writer);
} else { } else {
writer.writeLoopCounter(loopCounterSlot, 1, offset); writer.writeLoopCounter(loopCounterSlot, 1, location);
} }
if (block == null || !block.allEscape) { if (block == null || !block.allEscape) {

View File

@ -24,8 +24,8 @@
* A* (abstract) - These are the abstract nodes that are the superclasses for the other types. * A* (abstract) - These are the abstract nodes that are the superclasses for the other types.
* I* (interface) -- Thse are marker interfaces to denote a property of the node. * I* (interface) -- Thse are marker interfaces to denote a property of the node.
* S* (statement) - These are nodes that represent a statement in Painless. These are the highest level nodes. * S* (statement) - These are nodes that represent a statement in Painless. These are the highest level nodes.
* E* (expression) - These are nodess that represent an expression in Painless. These are the middle level nodes. * E* (expression) - These are nodes that represent an expression in Painless. These are the middle level nodes.
* L* (link) - These are nodes that respresent a piece of a variable/method chain. The are the lowest level nodes. * L* (link) - These are nodes that represent a piece of a variable/method chain. The are the lowest level nodes.
* <p> * <p>
* The following is a brief description of each node: * The following is a brief description of each node:
* {@link org.elasticsearch.painless.node.AExpression} - The superclass for all E* (expression) nodes. * {@link org.elasticsearch.painless.node.AExpression} - The superclass for all E* (expression) nodes.
@ -38,18 +38,18 @@
* {@link org.elasticsearch.painless.node.ECast} - Represents an implicit cast in most cases. (Internal only.) * {@link org.elasticsearch.painless.node.ECast} - Represents an implicit cast in most cases. (Internal only.)
* {@link org.elasticsearch.painless.node.EChain} - Represents the entirety of a variable/method chain for read/write operations. * {@link org.elasticsearch.painless.node.EChain} - Represents the entirety of a variable/method chain for read/write operations.
* {@link org.elasticsearch.painless.node.EComp} - Represents a comparison expression. * {@link org.elasticsearch.painless.node.EComp} - Represents a comparison expression.
* {@link org.elasticsearch.painless.node.EConditional} - Respresents a conditional expression. * {@link org.elasticsearch.painless.node.EConditional} - Represents a conditional expression.
* {@link org.elasticsearch.painless.node.EConstant} - Respresents a constant. (Internal only.) * {@link org.elasticsearch.painless.node.EConstant} - Represents a constant. (Internal only.)
* {@link org.elasticsearch.painless.node.EDecimal} - Respresents a decimal constant. * {@link org.elasticsearch.painless.node.EDecimal} - Represents a decimal constant.
* {@link org.elasticsearch.painless.node.EExplicit} - Represents an explicit cast. * {@link org.elasticsearch.painless.node.EExplicit} - Represents an explicit cast.
* {@link org.elasticsearch.painless.node.EFunctionRef} - Represents a function reference. * {@link org.elasticsearch.painless.node.EFunctionRef} - Represents a function reference.
* {@link org.elasticsearch.painless.node.ENull} - Represents a null constant. * {@link org.elasticsearch.painless.node.ENull} - Represents a null constant.
* {@link org.elasticsearch.painless.node.ENumeric} - Respresents a non-decimal numeric constant. * {@link org.elasticsearch.painless.node.ENumeric} - Represents a non-decimal numeric constant.
* {@link org.elasticsearch.painless.node.EUnary} - Represents a unary math expression. * {@link org.elasticsearch.painless.node.EUnary} - Represents a unary math expression.
* {@link org.elasticsearch.painless.node.IDefLink} - A marker interface for all LDef* (link) nodes. * {@link org.elasticsearch.painless.node.IDefLink} - A marker interface for all LDef* (link) nodes.
* {@link org.elasticsearch.painless.node.LArrayLength} - Represents an array length field load. * {@link org.elasticsearch.painless.node.LArrayLength} - Represents an array length field load.
* {@link org.elasticsearch.painless.node.LBrace} - Represents an array load/store or defers to possible shortcuts. * {@link org.elasticsearch.painless.node.LBrace} - Represents an array load/store or defers to possible shortcuts.
* {@link org.elasticsearch.painless.node.LCall} - Represents a method call or deferes to a def call. * {@link org.elasticsearch.painless.node.LCall} - Represents a method call or defers to a def call.
* {@link org.elasticsearch.painless.node.LCast} - Represents a cast made in a variable/method chain. * {@link org.elasticsearch.painless.node.LCast} - Represents a cast made in a variable/method chain.
* {@link org.elasticsearch.painless.node.LDefArray} - Represents an array load/store or shortcut on a def type. (Internal only.) * {@link org.elasticsearch.painless.node.LDefArray} - Represents an array load/store or shortcut on a def type. (Internal only.)
* {@link org.elasticsearch.painless.node.LDefCall} - Represents a method call made on a def type. (Internal only.) * {@link org.elasticsearch.painless.node.LDefCall} - Represents a method call made on a def type. (Internal only.)
@ -58,7 +58,7 @@
* {@link org.elasticsearch.painless.node.LListShortcut} - Represents a list load/store shortcut. (Internal only.) * {@link org.elasticsearch.painless.node.LListShortcut} - Represents a list load/store shortcut. (Internal only.)
* {@link org.elasticsearch.painless.node.LMapShortcut} - Represents a map load/store shortcut. (Internal only.) * {@link org.elasticsearch.painless.node.LMapShortcut} - Represents a map load/store shortcut. (Internal only.)
* {@link org.elasticsearch.painless.node.LNewArray} - Represents an array instantiation. * {@link org.elasticsearch.painless.node.LNewArray} - Represents an array instantiation.
* {@link org.elasticsearch.painless.node.LNewObj} - Respresents and object instantiation. * {@link org.elasticsearch.painless.node.LNewObj} - Represents and object instantiation.
* {@link org.elasticsearch.painless.node.LShortcut} - Represents a field load/store shortcut. (Internal only.) * {@link org.elasticsearch.painless.node.LShortcut} - Represents a field load/store shortcut. (Internal only.)
* {@link org.elasticsearch.painless.node.LStatic} - Represents a static type target. * {@link org.elasticsearch.painless.node.LStatic} - Represents a static type target.
* {@link org.elasticsearch.painless.node.LString} - Represents a string constant. * {@link org.elasticsearch.painless.node.LString} - Represents a string constant.

View File

@ -70,24 +70,20 @@ public class ConditionalTests extends ScriptTestCase {
} }
public void testIncompatibleAssignment() { public void testIncompatibleAssignment() {
try { expectScriptThrows(ClassCastException.class, () -> {
exec("boolean x = false; byte z = x ? 2 : 4.0F; return z;"); exec("boolean x = false; byte z = x ? 2 : 4.0F; return z;");
fail("expected class cast exception"); });
} catch (ClassCastException expected) {}
try { expectScriptThrows(ClassCastException.class, () -> {
exec("boolean x = false; Map z = x ? 4 : (byte)7; return z;"); exec("boolean x = false; Map z = x ? 4 : (byte)7; return z;");
fail("expected class cast exception"); });
} catch (ClassCastException expected) {}
try { expectScriptThrows(ClassCastException.class, () -> {
exec("boolean x = false; Map z = x ? new HashMap() : new ArrayList(); return z;"); exec("boolean x = false; Map z = x ? new HashMap() : new ArrayList(); return z;");
fail("expected class cast exception"); });
} catch (ClassCastException expected) {}
try { expectScriptThrows(ClassCastException.class, () -> {
exec("boolean x = false; int y = 2; byte z = x ? y : 7; return z;"); exec("boolean x = false; int y = 2; byte z = x ? y : 7; return z;");
fail("expected class cast exception"); });
} catch (ClassCastException expected) {}
} }
} }

View File

@ -124,11 +124,11 @@ public class DivisionTests extends ScriptTestCase {
} }
public void testDivideByZeroConst() throws Exception { public void testDivideByZeroConst() throws Exception {
expectThrows(ArithmeticException.class, () -> { expectScriptThrows(ArithmeticException.class, () -> {
exec("return 1/0;"); exec("return 1/0;");
}); });
expectThrows(ArithmeticException.class, () -> { expectScriptThrows(ArithmeticException.class, () -> {
exec("return 1L/0L;"); exec("return 1L/0L;");
}); });
} }

View File

@ -21,7 +21,7 @@ package org.elasticsearch.painless;
public class FunctionRefTests extends ScriptTestCase { public class FunctionRefTests extends ScriptTestCase {
public void testUnsupported() { public void testUnsupported() {
expectThrows(UnsupportedOperationException.class, () -> { expectScriptThrows(UnsupportedOperationException.class, () -> {
exec("DoubleStream.Builder builder = DoubleStream.builder();" + exec("DoubleStream.Builder builder = DoubleStream.builder();" +
"builder.add(2.0); builder.add(1.0); builder.add(3.0);" + "builder.add(2.0); builder.add(1.0); builder.add(3.0);" +
"builder.build().reduce(Double::unsupported);"); "builder.build().reduce(Double::unsupported);");

View File

@ -25,7 +25,7 @@ public class OverloadTests extends ScriptTestCase {
public void testMethod() { public void testMethod() {
assertEquals(2, exec("return 'abc123abc'.indexOf('c');")); assertEquals(2, exec("return 'abc123abc'.indexOf('c');"));
assertEquals(8, exec("return 'abc123abc'.indexOf('c', 3);")); assertEquals(8, exec("return 'abc123abc'.indexOf('c', 3);"));
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> { IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("return 'abc123abc'.indexOf('c', 3, 'bogus');"); exec("return 'abc123abc'.indexOf('c', 3, 'bogus');");
}); });
assertTrue(expected.getMessage().contains("[indexOf] with [3] arguments")); assertTrue(expected.getMessage().contains("[indexOf] with [3] arguments"));

View File

@ -124,18 +124,12 @@ public class RemainderTests extends ScriptTestCase {
} }
public void testDivideByZeroConst() throws Exception { public void testDivideByZeroConst() throws Exception {
try { expectScriptThrows(ArithmeticException.class, () -> {
exec("return 1%0;"); exec("return 1%0;");
fail("should have hit exception"); });
} catch (ArithmeticException expected) {
// divide by zero
}
try { expectScriptThrows(ArithmeticException.class, () -> {
exec("return 1L%0L;"); exec("return 1L%0L;");
fail("should have hit exception"); });
} catch (ArithmeticException expected) {
// divide by zero
}
} }
} }

View File

@ -27,7 +27,7 @@ public class ReservedWordTests extends ScriptTestCase {
/** check that we can't declare a variable of _score, its really reserved! */ /** check that we can't declare a variable of _score, its really reserved! */
public void testScoreVar() { public void testScoreVar() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> { IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("int _score = 5; return _score;"); exec("int _score = 5; return _score;");
}); });
assertTrue(expected.getMessage().contains("Variable name [_score] is reserved")); assertTrue(expected.getMessage().contains("Variable name [_score] is reserved"));
@ -35,7 +35,7 @@ public class ReservedWordTests extends ScriptTestCase {
/** check that we can't write to _score, its read-only! */ /** check that we can't write to _score, its read-only! */
public void testScoreStore() { public void testScoreStore() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> { IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("_score = 5; return _score;"); exec("_score = 5; return _score;");
}); });
assertTrue(expected.getMessage().contains("Variable [_score] is read-only")); assertTrue(expected.getMessage().contains("Variable [_score] is read-only"));
@ -43,7 +43,7 @@ public class ReservedWordTests extends ScriptTestCase {
/** check that we can't declare a variable of doc, its really reserved! */ /** check that we can't declare a variable of doc, its really reserved! */
public void testDocVar() { public void testDocVar() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> { IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("int doc = 5; return doc;"); exec("int doc = 5; return doc;");
}); });
assertTrue(expected.getMessage().contains("Variable name [doc] is reserved")); assertTrue(expected.getMessage().contains("Variable name [doc] is reserved"));
@ -51,7 +51,7 @@ public class ReservedWordTests extends ScriptTestCase {
/** check that we can't write to doc, its read-only! */ /** check that we can't write to doc, its read-only! */
public void testDocStore() { public void testDocStore() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> { IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("doc = 5; return doc;"); exec("doc = 5; return doc;");
}); });
assertTrue(expected.getMessage().contains("Variable [doc] is read-only")); assertTrue(expected.getMessage().contains("Variable [doc] is read-only"));
@ -59,7 +59,7 @@ public class ReservedWordTests extends ScriptTestCase {
/** check that we can't declare a variable of ctx, its really reserved! */ /** check that we can't declare a variable of ctx, its really reserved! */
public void testCtxVar() { public void testCtxVar() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> { IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("int ctx = 5; return ctx;"); exec("int ctx = 5; return ctx;");
}); });
assertTrue(expected.getMessage().contains("Variable name [ctx] is reserved")); assertTrue(expected.getMessage().contains("Variable name [ctx] is reserved"));
@ -67,7 +67,7 @@ public class ReservedWordTests extends ScriptTestCase {
/** check that we can't write to ctx, its read-only! */ /** check that we can't write to ctx, its read-only! */
public void testCtxStore() { public void testCtxStore() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> { IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("ctx = 5; return ctx;"); exec("ctx = 5; return ctx;");
}); });
assertTrue(expected.getMessage().contains("Variable [ctx] is read-only")); assertTrue(expected.getMessage().contains("Variable [ctx] is read-only"));
@ -80,7 +80,7 @@ public class ReservedWordTests extends ScriptTestCase {
/** check that we can't declare a variable of _value, its really reserved! */ /** check that we can't declare a variable of _value, its really reserved! */
public void testAggregationValueVar() { public void testAggregationValueVar() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> { IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("int _value = 5; return _value;"); exec("int _value = 5; return _value;");
}); });
assertTrue(expected.getMessage().contains("Variable name [_value] is reserved")); assertTrue(expected.getMessage().contains("Variable name [_value] is reserved"));
@ -88,7 +88,7 @@ public class ReservedWordTests extends ScriptTestCase {
/** check that we can't write to _value, its read-only! */ /** check that we can't write to _value, its read-only! */
public void testAggregationValueStore() { public void testAggregationValueStore() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> { IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("_value = 5; return _value;"); exec("_value = 5; return _value;");
}); });
assertTrue(expected.getMessage().contains("Variable [_value] is read-only")); assertTrue(expected.getMessage().contains("Variable [_value] is read-only"));

View File

@ -71,11 +71,11 @@ public class WhenThingsGoWrongTests extends ScriptTestCase {
} }
public void testInvalidShift() { public void testInvalidShift() {
expectThrows(ClassCastException.class, () -> { expectScriptThrows(ClassCastException.class, () -> {
exec("float x = 15F; x <<= 2; return x;"); exec("float x = 15F; x <<= 2; return x;");
}); });
expectThrows(ClassCastException.class, () -> { expectScriptThrows(ClassCastException.class, () -> {
exec("double x = 15F; x <<= 2; return x;"); exec("double x = 15F; x <<= 2; return x;");
}); });
} }
@ -134,7 +134,7 @@ public class WhenThingsGoWrongTests extends ScriptTestCase {
assertTrue(expected.getMessage().contains( assertTrue(expected.getMessage().contains(
"The maximum number of statements that can be executed in a loop has been reached.")); "The maximum number of statements that can be executed in a loop has been reached."));
RuntimeException parseException = expectThrows(RuntimeException.class, () -> { RuntimeException parseException = expectScriptThrows(RuntimeException.class, () -> {
exec("try { int x; } catch (PainlessError error) {}"); exec("try { int x; } catch (PainlessError error) {}");
fail("should have hit ParseException"); fail("should have hit ParseException");
}); });
@ -156,7 +156,7 @@ public class WhenThingsGoWrongTests extends ScriptTestCase {
final char[] tooManyChars = new char[Compiler.MAXIMUM_SOURCE_LENGTH + 1]; final char[] tooManyChars = new char[Compiler.MAXIMUM_SOURCE_LENGTH + 1];
Arrays.fill(tooManyChars, '0'); Arrays.fill(tooManyChars, '0');
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> { IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec(new String(tooManyChars)); exec(new String(tooManyChars));
}); });
assertTrue(expected.getMessage().contains("Scripts may be no longer than")); assertTrue(expected.getMessage().contains("Scripts may be no longer than"));

View File

@ -40,9 +40,9 @@ public class ParserTests extends ScriptTestCase {
private SourceContext buildAntlrTree(String source) { private SourceContext buildAntlrTree(String source) {
ANTLRInputStream stream = new ANTLRInputStream(source); ANTLRInputStream stream = new ANTLRInputStream(source);
PainlessLexer lexer = new ErrorHandlingLexer(stream); PainlessLexer lexer = new ErrorHandlingLexer(stream, "testing");
PainlessParser parser = new PainlessParser(new CommonTokenStream(lexer)); PainlessParser parser = new PainlessParser(new CommonTokenStream(lexer));
ParserErrorStrategy strategy = new ParserErrorStrategy(); ParserErrorStrategy strategy = new ParserErrorStrategy("testing");
lexer.removeErrorListeners(); lexer.removeErrorListeners();
parser.removeErrorListeners(); parser.removeErrorListeners();

View File

@ -47,7 +47,7 @@
body: { "script": "_score * foo bar + doc['myParent.weight'].value" } body: { "script": "_score * foo bar + doc['myParent.weight'].value" }
- do: - do:
catch: /Unable.to.parse.*/ catch: /compile error/
put_script: put_script:
id: "1" id: "1"
lang: "painless" lang: "painless"