Improve painless compile-time exceptions

This commit is contained in:
Robert Muir 2016-06-02 18:23:47 -04:00
parent 3ccd59592a
commit b5393ce55e
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.Sort;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.node.ANode;
/**
* 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 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)) {
return null;
}
@ -653,11 +654,11 @@ public final class AnalyzerCaster {
explicit && actual.clazz.isAssignableFrom(expected.clazz)) {
return new Cast(actual, expected, explicit);
} 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 tsort = cast.to.sort;
@ -685,12 +686,12 @@ public final class AnalyzerCaster {
case FLOAT: return number.floatValue();
case DOUBLE: return number.doubleValue();
default:
throw new IllegalStateException("Error" + location + ": Cannot cast from " +
"[" + cast.from.clazz.getCanonicalName() + "] to [" + cast.to.clazz.getCanonicalName() + "].");
throw location.createError(new IllegalStateException("Cannot cast from " +
"[" + cast.from.clazz.getCanonicalName() + "] to [" + cast.to.clazz.getCanonicalName() + "]."));
}
} else {
throw new IllegalStateException("Error" + location + ": Cannot cast from " +
"[" + cast.from.clazz.getCanonicalName() + "] to [" + cast.to.clazz.getCanonicalName() + "].");
throw location.createError(new IllegalStateException("Cannot cast from " +
"[" + cast.from.clazz.getCanonicalName() + "] to [" + cast.to.clazz.getCanonicalName() + "]."));
}
}

View File

@ -101,7 +101,7 @@ final class Compiler {
}
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);
BitSet expressions = new BitSet(source.length());
@ -132,7 +132,7 @@ final class Compiler {
}
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);
return Writer.write(settings, name, source, variables, root, new BitSet(source.length()));

View File

@ -164,6 +164,11 @@ public final class Definition {
return result;
}
@Override
public String toString() {
return name;
}
}
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>
* 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
// (e.g. nodes get assigned wrong offsets by antlr walker)
assert statements.get(offset) == false;
@ -126,16 +127,16 @@ public final class MethodWriter extends GeneratorAdapter {
* <p>
* 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...
Label label = new 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) {
writeDebugInfo(offset);
writeDebugInfo(location);
final Label end = new Label();
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;
if ((sort == Sort.FLOAT || sort == Sort.DOUBLE) &&
(operation == Operation.LSH || operation == Operation.USH ||
operation == Operation.RSH || operation == Operation.BWAND ||
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) {
@ -305,7 +306,7 @@ public final class MethodWriter extends GeneratorAdapter {
case XOR: invokeStatic(DEF_UTIL_TYPE, DEF_XOR_CALL); break;
case BWOR: invokeStatic(DEF_UTIL_TYPE, DEF_OR_CALL); break;
default:
throw new IllegalStateException("Error " + location + ": Illegal tree structure.");
throw location.createError(new IllegalStateException("Illegal tree structure."));
}
} else {
switch (operation) {
@ -321,7 +322,7 @@ public final class MethodWriter extends GeneratorAdapter {
case XOR: math(GeneratorAdapter.XOR, type.type); break;
case BWOR: math(GeneratorAdapter.OR, type.type); break;
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.LeafSearchScript;
import org.elasticsearch.script.ScriptEngineService;
import org.elasticsearch.script.ScriptException;
import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.lookup.SearchLookup;
@ -38,7 +39,10 @@ import java.security.AccessController;
import java.security.Permissions;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
@ -147,13 +151,17 @@ public final class PainlessScriptEngineService extends AbstractComponent impleme
}
});
// Drop all permissions to actually compile the code itself.
return AccessController.doPrivileged(new PrivilegedAction<Executable>() {
@Override
public Executable run() {
return Compiler.compile(loader, scriptName == null ? INLINE_NAME : scriptName, scriptSource, compilerSettings);
}
}, COMPILATION_CONTEXT);
try {
// Drop all permissions to actually compile the code itself.
return AccessController.doPrivileged(new PrivilegedAction<Executable>() {
@Override
public Executable run() {
return Compiler.compile(loader, scriptName == null ? INLINE_NAME : scriptName, scriptSource, compilerSettings);
}
}, 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() {
// 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 */
private static boolean shouldFilter(StackTraceElement element) {
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 final String location;
public final Location location;
public final String name;
public final Type type;
public final int slot;
@ -77,7 +77,7 @@ public final class Variables {
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.name = name;
this.type = type;
@ -88,6 +88,7 @@ public final class Variables {
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<Variable> variables = new ArrayDeque<>();
@ -99,35 +100,35 @@ public final class Variables {
// Method variables.
// 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.
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.
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?
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.
addVariable("[" + Reserved.VALUE + "]", Definition.DEF_TYPE, Reserved.VALUE, true, true);
addVariable(null, Definition.DEF_TYPE, Reserved.VALUE, true, true);
// Shortcut variables.
// Document's score as a read-only double.
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.
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.
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() {
int remove = scopes.pop();
while (remove > 0) {
Variable variable = variables.pop();
Variable variable = variables.pop();
// TODO: is this working? the code reads backwards...
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;
}
}
public Variable getVariable(String location, String name) {
public Variable getVariable(Location location, String name) {
Iterator<Variable> itr = variables.iterator();
while (itr.hasNext()) {
@ -160,20 +162,20 @@ public final class Variables {
}
}
if (location != null) {
throw new IllegalArgumentException("Error " + location + ": Variable [" + name + "] not defined.");
}
return null;
throw location.createError(new IllegalArgumentException("Variable [" + name + "] not defined."));
}
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)) {
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) {
throw new IllegalArgumentException("Error " + location + ": Variable name [" + name + "] already defined.");
if (variableExists(name)) {
throw new IllegalArgumentException("Variable name [" + name + "] already defined.");
}
try {

View File

@ -72,9 +72,6 @@ final class Writer {
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() {
final int version = Opcodes.V1_8;
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;
writer.visit(version, access, name, null, base, interfaces);
writer.visitSource(computeSourceName(), 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();
writer.visitSource(Location.computeSourceName(scriptName,source), null);
}
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.LexerNoViableAltException;
import org.antlr.v4.runtime.misc.Interval;
import java.text.ParseException;
import org.elasticsearch.painless.Location;
/**
* A lexer that will override the default error behavior to fail on the first error.
*/
final class ErrorHandlingLexer extends PainlessLexer {
final String sourceName;
ErrorHandlingLexer(final CharStream charStream) {
ErrorHandlingLexer(CharStream charStream, String sourceName) {
super(charStream);
this.sourceName = sourceName;
}
@Override
@ -40,11 +41,7 @@ final class ErrorHandlingLexer extends PainlessLexer {
final int startIndex = lnvae.getStartIndex();
final String text = charStream.getText(Interval.of(startIndex, charStream.index()));
final ParseException parseException = new ParseException("Error [" + _tokenStartLine + ":" +
_tokenStartCharPositionInLine + "]: unexpected character [" +
getErrorDisplay(text) + "].", _tokenStartCharIndex);
parseException.initCause(lnvae);
throw new RuntimeException(parseException);
Location location = new Location(sourceName, _tokenStartCharIndex);
throw location.createError(new IllegalArgumentException("unexpected character [" + getErrorDisplay(text) + "].", lnvae));
}
}

View File

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

View File

@ -28,6 +28,7 @@ import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Recognizer;
import org.antlr.v4.runtime.atn.PredictionMode;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Operation;
import org.elasticsearch.painless.Variables.Reserved;
import org.elasticsearch.painless.antlr.PainlessParser.AfterthoughtContext;
@ -135,25 +136,27 @@ import java.util.List;
*/
public final class Walker extends PainlessParserBaseVisitor<Object> {
public static SSource buildPainlessTree(String source, Reserved reserved, CompilerSettings settings) {
return new Walker(source, reserved, settings).source;
public static SSource buildPainlessTree(String name, String sourceText, Reserved reserved, CompilerSettings settings) {
return new Walker(name, sourceText, reserved, settings).source;
}
private final Reserved reserved;
private final SSource source;
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.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) {
ANTLRInputStream stream = new ANTLRInputStream(source);
PainlessLexer lexer = new ErrorHandlingLexer(stream);
PainlessLexer lexer = new ErrorHandlingLexer(stream, sourceName);
PainlessParser parser = new PainlessParser(new CommonTokenStream(lexer));
ParserErrorStrategy strategy = new ParserErrorStrategy();
ParserErrorStrategy strategy = new ParserErrorStrategy(sourceName);
lexer.removeErrorListeners();
parser.removeErrorListeners();
@ -185,16 +188,8 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
parser.getInterpreter().setPredictionMode(PredictionMode.LL_EXACT_AMBIG_DETECTION);
}
private int line(ParserRuleContext ctx) {
return ctx.getStart().getLine();
}
private int offset(ParserRuleContext ctx) {
return ctx.getStart().getStartIndex();
}
private String location(ParserRuleContext ctx) {
return "[ " + ctx.getStart().getLine() + " : " + ctx.getStart().getCharPositionInLine() + " ]";
private Location location(ParserRuleContext ctx) {
return new Location(sourceName, ctx.getStart().getStartIndex());
}
@Override
@ -205,7 +200,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
statements.add((AStatement)visit(statement));
}
return new SSource(line(ctx), offset(ctx), location(ctx), statements);
return new SSource(location(ctx), statements);
}
@Override
@ -216,9 +211,9 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
if (ctx.trailer().size() > 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 {
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) {
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) {
return new SWhile(line(ctx), offset(ctx), location(ctx), settings.getMaxLoopCounter(), expression, null);
return new SWhile(location(ctx), settings.getMaxLoopCounter(), expression, null);
} 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());
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
@ -266,13 +261,13 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
if (ctx.trailer() != null) {
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);
} 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);
} 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
public Object visitContinue(ContinueContext ctx) {
return new SContinue(line(ctx), offset(ctx), location(ctx));
return new SContinue(location(ctx));
}
@Override
public Object visitBreak(BreakContext ctx) {
return new SBreak(line(ctx), offset(ctx), location(ctx));
return new SBreak(location(ctx));
}
@Override
public Object visitReturn(ReturnContext ctx) {
AExpression expression = (AExpression)visitExpression(ctx.expression());
return new SReturn(line(ctx), offset(ctx), location(ctx), expression);
return new SReturn(location(ctx), expression);
}
@Override
@ -307,21 +302,21 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
catches.add((SCatch)visit(trap));
}
return new STry(line(ctx), offset(ctx), location(ctx), block, catches);
return new STry(location(ctx), block, catches);
}
@Override
public Object visitThrow(ThrowContext ctx) {
AExpression expression = (AExpression)visitExpression(ctx.expression());
return new SThrow(line(ctx), offset(ctx), location(ctx), expression);
return new SThrow(location(ctx), expression);
}
@Override
public Object visitExpr(ExprContext ctx) {
AExpression expression = (AExpression)visitExpression(ctx.expression());
return new SExpression(line(ctx), offset(ctx), location(ctx), expression);
return new SExpression(location(ctx), expression);
}
@Override
@ -332,9 +327,9 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
List<AStatement> statements = new ArrayList<>();
statements.add((AStatement)visit(ctx.statement()));
return new SBlock(line(ctx), offset(ctx), location(ctx), statements);
return new SBlock(location(ctx), statements);
} 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));
}
return new SBlock(line(ctx), offset(ctx), location(ctx), statements);
return new SBlock(location(ctx), statements);
}
}
@Override
public Object visitEmpty(EmptyContext ctx) {
throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure.");
throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
}
@Override
@ -365,7 +360,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
} else if (ctx.expression() != null) {
return visitExpression(ctx.expression());
} 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();
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
public Object visitDecltype(DecltypeContext ctx) {
throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure.");
throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
}
@Override
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
public Object visitDeclvar(DeclvarContext ctx) {
throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure.");
throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
}
@Override
@ -410,12 +405,12 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
String name = ctx.ID().getText();
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
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) {
@ -425,7 +420,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
@SuppressWarnings("unchecked")
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 {
return expression;
}
@ -465,10 +460,10 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
} else if (ctx.BWOR() != null) {
operation = Operation.BWOR;
} 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
@ -494,10 +489,10 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
} else if (ctx.NER() != null) {
operation = Operation.NER;
} 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
@ -511,10 +506,10 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
} else if (ctx.BOOLOR() != null) {
operation = Operation.OR;
} 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
@ -523,7 +518,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
AExpression left = (AExpression)visitExpression(ctx.expression(1));
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
@ -557,12 +552,12 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
} else if (ctx.AOR() != null) {
operation = Operation.BWOR;
} 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());
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) {
@ -572,7 +567,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
@SuppressWarnings("unchecked")
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 {
return expression;
}
@ -589,10 +584,10 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
} else if (ctx.DECR() != null) {
operation = Operation.DECR;
} 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
@ -606,10 +601,10 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
} else if (ctx.DECR() != null) {
operation = Operation.DECR;
} 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
@ -622,31 +617,31 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
final boolean negate = ctx.parent instanceof OperatorContext && ((OperatorContext)ctx.parent).SUB() != 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) {
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) {
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) {
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 {
throw new IllegalStateException("Error " + location(ctx) + ": Illegal tree structure.");
throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
}
}
@Override
public Object visitTrue(TrueContext ctx) {
return new EBoolean(line(ctx), offset(ctx), location(ctx), true);
return new EBoolean(location(ctx), true);
}
@Override
public Object visitFalse(FalseContext ctx) {
return new EBoolean(line(ctx), offset(ctx), location(ctx), false);
return new EBoolean(location(ctx), false);
}
@Override
public Object visitNull(NullContext ctx) {
return new ENull(line(ctx), offset(ctx), location(ctx));
return new ENull(location(ctx));
}
@Override
@ -666,10 +661,10 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
} else if (ctx.SUB() != null) {
operation = Operation.SUB;
} 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) {
@SuppressWarnings("unchecked")
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;
} 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;
} else if (!ctx.secondary().isEmpty()) {
throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure.");
throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
} else {
return child;
}
@ -714,7 +709,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
String type = ctx.decltype().getText();
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()));
for (SecondaryContext secondary : ctx.secondary()) {
@ -734,7 +729,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
}
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) {
links.add((ALink)visit(ctx.dot()));
@ -743,7 +738,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
links.add((ALink)visit(secondary));
}
} 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;
@ -763,7 +758,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
public Object visitString(StringContext ctx) {
String string = ctx.STRING().getText().substring(1, ctx.STRING().getText().length() - 1);
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;
}
@ -772,7 +767,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
public Object visitVariable(VariableContext ctx) {
String name = ctx.ID().getText();
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);
@ -786,7 +781,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
List<AExpression> arguments = (List<AExpression>)visit(ctx.arguments());
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;
}
@ -798,7 +793,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
} else if (ctx.brace() != null) {
return visit(ctx.brace());
} 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")
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
@ -820,17 +815,17 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
} else if (ctx.DOTINTEGER() != null) {
value = ctx.DOTINTEGER().getText();
} 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
public Object visitBraceaccess(BraceaccessContext ctx) {
AExpression expression = (AExpression)visitExpression(ctx.expression());
return new LBrace(line(ctx), offset(ctx), location(ctx), expression);
return new LBrace(location(ctx), expression);
}
@Override
@ -851,7 +846,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
} else if (ctx.funcref() != null) {
return visit(ctx.funcref());
} 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.Type;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.AnalyzerCaster;
import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Label;
@ -98,8 +99,8 @@ public abstract class AExpression extends ANode {
*/
protected Label fals = null;
public AExpression(int line, int offset, String location) {
super(line, offset, location);
public AExpression(Location location) {
super(location);
}
/**
@ -124,18 +125,18 @@ public abstract class AExpression extends ANode {
if (constant == null || this instanceof EConstant) {
return this;
} else {
final EConstant econstant = new EConstant(line, offset, location, constant);
final EConstant econstant = new EConstant(location, constant);
econstant.analyze(variables);
if (!expected.equals(econstant.actual)) {
throw new IllegalStateException(error("Illegal tree structure."));
throw createError(new IllegalStateException("Illegal tree structure."));
}
return econstant;
}
} else {
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.actual = expected;
ecast.isNull = isNull;
@ -145,28 +146,28 @@ public abstract class AExpression extends ANode {
if (expected.sort.constant) {
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);
if (!expected.equals(econstant.actual)) {
throw new IllegalStateException(error("Illegal tree structure."));
throw createError(new IllegalStateException("Illegal tree structure."));
}
return 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;
return ecast;
} else {
final EConstant econstant = new EConstant(line, offset, location, constant);
final EConstant econstant = new EConstant(location, constant);
econstant.analyze(variables);
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;
return ecast;

View File

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

View File

@ -19,33 +19,22 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Location;
/**
* The superclass for all other nodes.
*/
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;
/**
* 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;
ANode(Location location) {
this.location = location;
}
public String error(final String message) {
return "Error " + location + ": " + message;
public RuntimeException createError(RuntimeException exception) {
return location.createError(exception);
}
}

View File

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

View File

@ -23,6 +23,7 @@ import org.elasticsearch.painless.AnalyzerCaster;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.Operation;
import org.elasticsearch.painless.Variables;
@ -38,8 +39,8 @@ public final class EBinary extends AExpression {
boolean cat = false;
public EBinary(int line, int offset, String location, Operation operation, AExpression left, AExpression right) {
super(line, offset, location);
public EBinary(Location location, Operation operation, AExpression left, AExpression right) {
super(location);
this.operation = operation;
this.left = left;
@ -71,7 +72,7 @@ public final class EBinary extends AExpression {
} else if (operation == Operation.BWOR) {
analyzeBWOr(variables);
} 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);
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 + "]."));
}
@ -104,7 +105,7 @@ public final class EBinary extends AExpression {
} else if (sort == Sort.DOUBLE) {
constant = (double)left.constant * (double)right.constant;
} 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);
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 + "]."));
}
@ -131,16 +132,20 @@ public final class EBinary extends AExpression {
if (left.constant != null && right.constant != null) {
Sort sort = promote.sort;
if (sort == Sort.INT) {
constant = (int)left.constant / (int)right.constant;
} else if (sort == Sort.LONG) {
constant = (long)left.constant / (long)right.constant;
} else if (sort == Sort.FLOAT) {
constant = (float)left.constant / (float)right.constant;
} else if (sort == Sort.DOUBLE) {
constant = (double)left.constant / (double)right.constant;
} else {
throw new IllegalStateException(error("Illegal tree structure."));
try {
if (sort == Sort.INT) {
constant = (int)left.constant / (int)right.constant;
} else if (sort == Sort.LONG) {
constant = (long)left.constant / (long)right.constant;
} else if (sort == Sort.FLOAT) {
constant = (float)left.constant / (float)right.constant;
} else if (sort == Sort.DOUBLE) {
constant = (double)left.constant / (double)right.constant;
} 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);
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 + "]."));
}
@ -167,16 +172,20 @@ public final class EBinary extends AExpression {
if (left.constant != null && right.constant != null) {
Sort sort = promote.sort;
if (sort == Sort.INT) {
constant = (int)left.constant % (int)right.constant;
} else if (sort == Sort.LONG) {
constant = (long)left.constant % (long)right.constant;
} else if (sort == Sort.FLOAT) {
constant = (float)left.constant % (float)right.constant;
} else if (sort == Sort.DOUBLE) {
constant = (double)left.constant % (double)right.constant;
} else {
throw new IllegalStateException(error("Illegal tree structure."));
try {
if (sort == Sort.INT) {
constant = (int)left.constant % (int)right.constant;
} else if (sort == Sort.LONG) {
constant = (long)left.constant % (long)right.constant;
} else if (sort == Sort.FLOAT) {
constant = (float)left.constant % (float)right.constant;
} else if (sort == Sort.DOUBLE) {
constant = (double)left.constant % (double)right.constant;
} 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);
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 + "]."));
}
@ -228,7 +237,7 @@ public final class EBinary extends AExpression {
} else if (sort == Sort.STRING) {
constant = "" + left.constant + right.constant;
} 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);
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 + "]."));
}
@ -264,7 +273,7 @@ public final class EBinary extends AExpression {
} else if (sort == Sort.DOUBLE) {
constant = (double)left.constant - (double)right.constant;
} 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);
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 + "]."));
}
@ -297,7 +306,7 @@ public final class EBinary extends AExpression {
} else if (sort == Sort.LONG) {
constant = (long)left.constant << (int)right.constant;
} 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);
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 + "]."));
}
@ -330,7 +339,7 @@ public final class EBinary extends AExpression {
} else if (sort == Sort.LONG) {
constant = (long)left.constant >> (int)right.constant;
} 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);
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 + "]."));
}
@ -363,7 +372,7 @@ public final class EBinary extends AExpression {
} else if (sort == Sort.LONG) {
constant = (long)left.constant >>> (int)right.constant;
} 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);
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 + "]."));
}
@ -395,7 +404,7 @@ public final class EBinary extends AExpression {
} else if (sort == Sort.LONG) {
constant = (long)left.constant & (long)right.constant;
} 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);
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 + "]."));
}
@ -429,7 +438,7 @@ public final class EBinary extends AExpression {
} else if (sort == Sort.LONG) {
constant = (long)left.constant ^ (long)right.constant;
} 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);
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 + "]."));
}
@ -461,7 +470,7 @@ public final class EBinary extends AExpression {
} else if (sort == Sort.LONG) {
constant = (long)left.constant | (long)right.constant;
} 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
void write(MethodWriter writer) {
writer.writeDebugInfo(offset);
writer.writeDebugInfo(location);
if (actual.sort == Sort.STRING && operation == Operation.ADD) {
if (!cat) {
writer.writeNewStrings();

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Operation;
import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Label;
@ -34,8 +35,8 @@ public final class EBool extends AExpression {
AExpression left;
AExpression right;
public EBool(int line, int offset, String location, Operation operation, AExpression left, AExpression right) {
super(line, offset, location);
public EBool(Location location, Operation operation, AExpression left, AExpression right) {
super(location);
this.operation = operation;
this.left = left;
@ -58,7 +59,7 @@ public final class EBool extends AExpression {
} else if (operation == Operation.OR) {
constant = (boolean)left.constant || (boolean)right.constant;
} 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);
}
} else {
throw new IllegalStateException(error("Illegal tree structure."));
throw createError(new IllegalStateException("Illegal tree structure."));
}
} else {
if (operation == Operation.AND) {
@ -131,7 +132,7 @@ public final class EBool extends AExpression {
writer.push(false);
writer.mark(end);
} 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;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter;
@ -28,8 +29,8 @@ import org.elasticsearch.painless.MethodWriter;
*/
public final class EBoolean extends AExpression {
public EBoolean(int line, int offset, String location, boolean constant) {
super(line, offset, location);
public EBoolean(Location location, boolean constant) {
super(location);
this.constant = constant;
}
@ -41,6 +42,6 @@ public final class EBoolean extends AExpression {
@Override
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;
import org.elasticsearch.painless.Definition.Cast;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter;
@ -34,8 +35,8 @@ final class ECast extends AExpression {
Cast cast = null;
ECast(int line, int offset, String location, AExpression child, Cast cast) {
super(line, offset, location);
ECast(Location location, AExpression child, Cast cast) {
super(location);
this.type = null;
this.child = child;
@ -45,13 +46,13 @@ final class ECast extends AExpression {
@Override
void analyze(Variables variables) {
throw new IllegalStateException(error("Illegal tree structure."));
throw createError(new IllegalStateException("Illegal tree structure."));
}
@Override
void write(MethodWriter writer) {
child.write(writer);
writer.writeDebugInfo(offset);
writer.writeDebugInfo(location);
writer.writeCast(cast);
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.Sort;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.AnalyzerCaster;
import org.elasticsearch.painless.Operation;
import org.elasticsearch.painless.Variables;
@ -46,9 +47,9 @@ public final class EChain extends AExpression {
Cast there = 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) {
super(line, offset, location);
super(location);
this.links = links;
this.pre = pre;
@ -114,40 +115,40 @@ public final class EChain extends AExpression {
ALink last = links.get(links.size() - 1);
if (pre && post) {
throw new IllegalStateException(error("Illegal tree structure."));
throw createError(new IllegalStateException("Illegal tree structure."));
} else if (pre || post) {
if (expression != null) {
throw new IllegalStateException(error("Illegal tree structure."));
throw createError(new IllegalStateException("Illegal tree structure."));
}
Sort sort = last.after.sort;
if (operation == Operation.INCR) {
if (sort == Sort.DOUBLE) {
expression = new EConstant(line, offset, location, 1D);
expression = new EConstant(location, 1D);
} else if (sort == Sort.FLOAT) {
expression = new EConstant(line, offset, location, 1F);
expression = new EConstant(location, 1F);
} else if (sort == Sort.LONG) {
expression = new EConstant(line, offset, location, 1L);
expression = new EConstant(location, 1L);
} else {
expression = new EConstant(line, offset, location, 1);
expression = new EConstant(location, 1);
}
operation = Operation.ADD;
} else if (operation == Operation.DECR) {
if (sort == Sort.DOUBLE) {
expression = new EConstant(line, offset, location, 1D);
expression = new EConstant(location, 1D);
} else if (sort == Sort.FLOAT) {
expression = new EConstant(line, offset, location, 1F);
expression = new EConstant(location, 1F);
} else if (sort == Sort.LONG) {
expression = new EConstant(line, offset, location, 1L);
expression = new EConstant(location, 1L);
} else {
expression = new EConstant(line, offset, location, 1);
expression = new EConstant(location, 1);
}
operation = Operation.SUB;
} 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) {
promote = AnalyzerCaster.promoteXor(last.after, expression.actual);
} else {
throw new IllegalStateException(error("Illegal tree structure."));
throw createError(new IllegalStateException("Illegal tree structure."));
}
if (promote == null) {
throw new ClassCastException("Cannot apply compound assignment " +
"[" + operation.symbol + "=] to types [" + last.after + "] and [" + expression.actual + "].");
throw createError(new ClassCastException("Cannot apply compound assignment " +
"[" + operation.symbol + "=] to types [" + last.after + "] and [" + expression.actual + "]."));
}
cat = operation == Operation.ADD && promote.sort == Sort.STRING;
@ -248,9 +249,8 @@ public final class EChain extends AExpression {
@Override
void write(MethodWriter writer) {
if (cat) {
writer.writeDebugInfo(offset);
}
// can cause class cast exception among other things at runtime
writer.writeDebugInfo(location);
if (cat) {
writer.writeNewStrings();

View File

@ -22,6 +22,7 @@ package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.AnalyzerCaster;
import org.elasticsearch.painless.Operation;
import org.elasticsearch.painless.Variables;
@ -46,8 +47,8 @@ public final class EComp extends AExpression {
AExpression left;
AExpression right;
public EComp(int line, int offset, String location, Operation operation, AExpression left, AExpression right) {
super(line, offset, location);
public EComp(Location location, Operation operation, AExpression left, AExpression right) {
super(location);
this.operation = operation;
this.left = left;
@ -73,7 +74,7 @@ public final class EComp extends AExpression {
} else if (operation == Operation.LT) {
analyzeLT(variables);
} 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);
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 + "]."));
}
@ -95,7 +96,7 @@ public final class EComp extends AExpression {
right = right.cast(variables);
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)) {
@ -116,7 +117,7 @@ public final class EComp extends AExpression {
} else if (!right.isNull) {
constant = right.constant.equals(null);
} 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);
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 + "]."));
}
@ -141,7 +142,7 @@ public final class EComp extends AExpression {
right = right.cast(variables);
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)) {
@ -172,7 +173,7 @@ public final class EComp extends AExpression {
Type promote = AnalyzerCaster.promoteEquality(left.actual, right.actual);
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 + "]."));
}
@ -183,7 +184,7 @@ public final class EComp extends AExpression {
right = right.cast(variables);
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)) {
@ -204,7 +205,7 @@ public final class EComp extends AExpression {
} else if (!right.isNull) {
constant = !right.constant.equals(null);
} 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);
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 + "]."));
}
@ -229,7 +230,7 @@ public final class EComp extends AExpression {
right = right.cast(variables);
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)) {
@ -260,7 +261,7 @@ public final class EComp extends AExpression {
Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
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 + "]."));
}
@ -282,7 +283,7 @@ public final class EComp extends AExpression {
} else if (sort == Sort.DOUBLE) {
constant = (double)left.constant >= (double)right.constant;
} 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);
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 + "]."));
}
@ -318,7 +319,7 @@ public final class EComp extends AExpression {
} else if (sort == Sort.DOUBLE) {
constant = (double)left.constant > (double)right.constant;
} 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);
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 + "]."));
}
@ -354,7 +355,7 @@ public final class EComp extends AExpression {
} else if (sort == Sort.DOUBLE) {
constant = (double)left.constant <= (double)right.constant;
} 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);
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 + "]."));
}
@ -390,7 +391,7 @@ public final class EComp extends AExpression {
} else if (sort == Sort.DOUBLE) {
constant = (double)left.constant < (double)right.constant;
} 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
void write(MethodWriter writer) {
writer.writeDebugInfo(offset);
writer.writeDebugInfo(location);
boolean branch = tru != null || fals != null;
org.objectweb.asm.Type rtype = right.actual.type;
Sort rsort = right.actual.sort;
@ -429,12 +430,12 @@ public final class EComp extends AExpression {
case BYTE:
case SHORT:
case CHAR:
throw new IllegalStateException(error("Illegal tree structure."));
throw createError(new IllegalStateException("Illegal tree structure."));
case BOOL:
if (eq) writer.ifZCmp(MethodWriter.EQ, jump);
else if (ne) writer.ifZCmp(MethodWriter.NE, jump);
else {
throw new IllegalStateException(error("Illegal tree structure."));
throw createError(new IllegalStateException("Illegal tree structure."));
}
break;
@ -449,7 +450,7 @@ public final class EComp extends AExpression {
else if (gt) writer.ifCmp(rtype, MethodWriter.GT, jump);
else if (gte) writer.ifCmp(rtype, MethodWriter.GE, jump);
else {
throw new IllegalStateException(error("Illegal tree structure."));
throw createError(new IllegalStateException("Illegal tree structure."));
}
break;
@ -485,7 +486,7 @@ public final class EComp extends AExpression {
writer.invokeStatic(DEF_UTIL_TYPE, DEF_GTE_CALL);
writejump = false;
} else {
throw new IllegalStateException(error("Illegal tree structure."));
throw createError(new IllegalStateException("Illegal tree structure."));
}
if (branch && !writejump) {
@ -518,7 +519,7 @@ public final class EComp extends AExpression {
writer.ifCmp(rtype, MethodWriter.NE, jump);
}
} 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.Type;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.AnalyzerCaster;
import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Label;
@ -35,8 +36,8 @@ public final class EConditional extends AExpression {
AExpression left;
AExpression right;
public EConditional(int line, int offset, String location, AExpression condition, AExpression left, AExpression right) {
super(line, offset, location);
public EConditional(Location location, AExpression condition, AExpression left, AExpression right) {
super(location);
this.condition = condition;
this.left = left;
@ -50,7 +51,7 @@ public final class EConditional extends AExpression {
condition = condition.cast(variables);
if (condition.constant != null) {
throw new IllegalArgumentException(error("Extraneous conditional statement."));
throw createError(new IllegalArgumentException("Extraneous conditional statement."));
}
left.expected = expected;
@ -78,7 +79,7 @@ public final class EConditional extends AExpression {
@Override
void write(MethodWriter writer) {
writer.writeDebugInfo(offset);
writer.writeDebugInfo(location);
Label localfals = 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.Sort;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Variables;
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.)
*/
final class EConstant extends AExpression {
EConstant(int line, int offset, String location, Object constant) {
super(line, offset, location);
EConstant(Location location, Object constant) {
super(location);
this.constant = constant;
}
@ -57,7 +58,7 @@ final class EConstant extends AExpression {
} else if (constant instanceof Boolean) {
actual = Definition.BOOLEAN_TYPE;
} 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;
default:
throw new IllegalStateException(error("Illegal tree structure."));
throw createError(new IllegalStateException("Illegal tree structure."));
}
if (sort != Sort.BOOL) {

View File

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

View File

@ -19,6 +19,7 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.Variables;
@ -29,8 +30,8 @@ public class EFunctionRef extends AExpression {
public String type;
public String call;
public EFunctionRef(int line, int offset, String location, String type, String call) {
super(line, offset, location);
public EFunctionRef(Location location, String type, String call) {
super(location);
this.type = type;
this.call = call;
@ -38,11 +39,12 @@ public class EFunctionRef extends AExpression {
@Override
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
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;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Opcodes;
import org.elasticsearch.painless.MethodWriter;
@ -29,8 +30,8 @@ import org.elasticsearch.painless.MethodWriter;
*/
public final class ENull extends AExpression {
public ENull(int line, int offset, String location) {
super(line, offset, location);
public ENull(Location location) {
super(location);
}
@Override
@ -39,7 +40,7 @@ public final class ENull extends AExpression {
if (expected != null) {
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;

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter;
@ -32,8 +33,8 @@ public final class ENumeric extends AExpression {
final String value;
int radix;
public ENumeric(int line, int offset, String location, String value, int radix) {
super(line, offset, location);
public ENumeric(Location location, String value, int radix) {
super(location);
this.value = value;
this.radix = radix;
@ -43,32 +44,32 @@ public final class ENumeric extends AExpression {
void analyze(Variables variables) {
if (value.endsWith("d") || value.endsWith("D")) {
if (radix != 10) {
throw new IllegalStateException(error("Invalid tree structure."));
throw createError(new IllegalStateException("Illegal tree structure."));
}
try {
constant = Double.parseDouble(value.substring(0, value.length() - 1));
actual = Definition.DOUBLE_TYPE;
} 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")) {
if (radix != 10) {
throw new IllegalStateException(error("Invalid tree structure."));
throw createError(new IllegalStateException("Illegal tree structure."));
}
try {
constant = Float.parseFloat(value.substring(0, value.length() - 1));
actual = Definition.FLOAT_TYPE;
} 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")) {
try {
constant = Long.parseLong(value.substring(0, value.length() - 1), radix);
actual = Definition.LONG_TYPE;
} catch (NumberFormatException exception) {
throw new IllegalArgumentException(error("Invalid long constant [" + value + "]."));
throw createError(new IllegalArgumentException("Invalid long constant [" + value + "]."));
}
} else {
try {
@ -89,13 +90,13 @@ public final class ENumeric extends AExpression {
actual = Definition.INT_TYPE;
}
} catch (NumberFormatException exception) {
throw new IllegalArgumentException(error("Invalid int constant [" + value + "]."));
throw createError(new IllegalArgumentException("Invalid int constant [" + value + "]."));
}
}
}
@Override
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;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.AnalyzerCaster;
@ -40,8 +41,8 @@ public final class EUnary extends AExpression {
final Operation operation;
AExpression child;
public EUnary(int line, int offset, String location, Operation operation, AExpression child) {
super(line, offset, location);
public EUnary(Location location, Operation operation, AExpression child) {
super(location);
this.operation = operation;
this.child = child;
@ -58,7 +59,7 @@ public final class EUnary extends AExpression {
} else if (operation == Operation.SUB) {
analyzerSub(variables);
} 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);
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;
@ -94,7 +95,7 @@ public final class EUnary extends AExpression {
} else if (sort == Sort.LONG) {
constant = ~(long)child.constant;
} 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);
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;
@ -125,7 +126,7 @@ public final class EUnary extends AExpression {
} else if (sort == Sort.DOUBLE) {
constant = +(double)child.constant;
} 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);
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;
@ -156,7 +157,7 @@ public final class EUnary extends AExpression {
} else if (sort == Sort.DOUBLE) {
constant = -(double)child.constant;
} 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
void write(MethodWriter writer) {
writer.writeDebugInfo(offset);
writer.writeDebugInfo(location);
if (operation == Operation.NOT) {
if (tru == null && fals == null) {
Label localfals = new Label();
@ -199,7 +200,7 @@ public final class EUnary extends AExpression {
} else if (sort == Sort.LONG) {
writer.push(-1L);
} else {
throw new IllegalStateException(error("Illegal tree structure."));
throw createError(new IllegalStateException("Illegal tree structure."));
}
writer.math(MethodWriter.XOR, type);
@ -211,7 +212,7 @@ public final class EUnary extends AExpression {
writer.math(MethodWriter.NEG, type);
}
} else if (operation != Operation.ADD) {
throw new IllegalStateException(error("Illegal tree structure."));
throw createError(new IllegalStateException("Illegal tree structure."));
}
writer.writeBranch(tru, fals);

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter;
@ -30,8 +31,8 @@ public final class LArrayLength extends ALink {
final String value;
LArrayLength(int line, int offset, String location, String value) {
super(line, offset, location, -1);
LArrayLength(Location location, String value) {
super(location, -1);
this.value = value;
}
@ -40,14 +41,14 @@ public final class LArrayLength extends ALink {
ALink analyze(Variables variables) {
if ("length".equals(value)) {
if (!load) {
throw new IllegalArgumentException(error("Must read array field [length]."));
throw createError(new IllegalArgumentException("Must read array field [length]."));
} 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;
} else {
throw new IllegalArgumentException(error("Illegal field access [" + value + "]."));
throw createError(new IllegalArgumentException("Illegal field access [" + value + "]."));
}
return this;
@ -60,12 +61,12 @@ public final class LArrayLength extends ALink {
@Override
void load(MethodWriter writer) {
writer.writeDebugInfo(offset);
writer.writeDebugInfo(location);
writer.arrayLength();
}
@Override
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;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter;
@ -34,8 +35,8 @@ public final class LBrace extends ALink {
AExpression index;
public LBrace(int line, int offset, String location, AExpression index) {
super(line, offset, location, 2);
public LBrace(Location location, AExpression index) {
super(location, 2);
this.index = index;
}
@ -43,7 +44,7 @@ public final class LBrace extends ALink {
@Override
ALink analyze(Variables variables) {
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;
@ -57,14 +58,14 @@ public final class LBrace extends ALink {
return this;
} 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)) {
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)) {
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
@ -74,13 +75,13 @@ public final class LBrace extends ALink {
@Override
void load(MethodWriter writer) {
writer.writeDebugInfo(offset);
writer.writeDebugInfo(location);
writer.arrayLoad(after.type);
}
@Override
void store(MethodWriter writer) {
writer.writeDebugInfo(offset);
writer.writeDebugInfo(location);
writer.arrayStore(after.type);
}

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Method;
import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Definition.Struct;
@ -38,8 +39,8 @@ public final class LCall extends ALink {
Method method = null;
public LCall(int line, int offset, String location, String name, List<AExpression> arguments) {
super(line, offset, location, -1);
public LCall(Location location, String name, List<AExpression> arguments) {
super(location, -1);
this.name = name;
this.arguments = arguments;
@ -48,11 +49,11 @@ public final class LCall extends ALink {
@Override
ALink analyze(Variables variables) {
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) {
throw new IllegalArgumentException(error("Illegal call [" + name + "] on array type."));
throw createError(new IllegalArgumentException("Illegal call [" + name + "] on array type."));
} 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());
@ -74,13 +75,13 @@ public final class LCall extends ALink {
return this;
} 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);
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 + "]."));
}
@ -91,7 +92,7 @@ public final class LCall extends ALink {
@Override
void load(MethodWriter writer) {
writer.writeDebugInfo(offset);
writer.writeDebugInfo(location);
for (AExpression argument : arguments) {
argument.write(writer);
}
@ -111,6 +112,6 @@ public final class LCall extends ALink {
@Override
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;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Cast;
import org.elasticsearch.painless.AnalyzerCaster;
import org.elasticsearch.painless.Variables;
@ -34,8 +35,8 @@ public final class LCast extends ALink {
Cast cast = null;
public LCast(int line, int offset, String location, String type) {
super(line, offset, location, -1);
public LCast(Location location, String type) {
super(location, -1);
this.type = type;
}
@ -43,15 +44,15 @@ public final class LCast extends ALink {
@Override
ALink analyze(Variables variables) {
if (before == null) {
throw new IllegalStateException(error("Illegal cast without a target."));
throw createError(new IllegalStateException("Illegal cast without a target."));
} 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 {
after = Definition.getType(type);
} 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);
@ -61,7 +62,7 @@ public final class LCast extends ALink {
@Override
void write(MethodWriter writer) {
writer.writeDebugInfo(offset);
writer.writeDebugInfo(location);
writer.writeCast(cast);
}
@ -72,6 +73,6 @@ public final class LCast extends ALink {
@Override
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;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.DefBootstrap;
import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Type;
@ -34,8 +35,8 @@ final class LDefArray extends ALink implements IDefLink {
AExpression index;
LDefArray(int line, int offset, String location, AExpression index) {
super(line, offset, location, 2);
LDefArray(Location location, AExpression index) {
super(location, 2);
this.index = index;
}
@ -58,14 +59,14 @@ final class LDefArray extends ALink implements IDefLink {
@Override
void load(MethodWriter writer) {
writer.writeDebugInfo(offset);
writer.writeDebugInfo(location);
String desc = Type.getMethodDescriptor(after.type, Definition.DEF_TYPE.type, index.actual.type);
writer.invokeDynamic("arrayLoad", desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.ARRAY_LOAD);
}
@Override
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);
writer.invokeDynamic("arrayStore", desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.ARRAY_STORE);
}

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.DefBootstrap;
import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter;
@ -36,8 +37,8 @@ final class LDefCall extends ALink implements IDefLink {
final String name;
final List<AExpression> arguments;
LDefCall(int line, int offset, String location, String name, List<AExpression> arguments) {
super(line, offset, location, -1);
LDefCall(Location location, String name, List<AExpression> arguments) {
super(location, -1);
this.name = name;
this.arguments = arguments;
@ -67,7 +68,7 @@ final class LDefCall extends ALink implements IDefLink {
@Override
void load(MethodWriter writer) {
writer.writeDebugInfo(offset);
writer.writeDebugInfo(location);
StringBuilder signature = new StringBuilder();
signature.append('(');
@ -88,6 +89,6 @@ final class LDefCall extends ALink implements IDefLink {
@Override
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;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.DefBootstrap;
import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Type;
@ -34,8 +35,8 @@ final class LDefField extends ALink implements IDefLink {
final String value;
LDefField(int line, int offset, String location, String value) {
super(line, offset, location, 1);
LDefField(Location location, String value) {
super(location, 1);
this.value = value;
}
@ -55,14 +56,14 @@ final class LDefField extends ALink implements IDefLink {
@Override
void load(MethodWriter writer) {
writer.writeDebugInfo(offset);
writer.writeDebugInfo(location);
String desc = Type.getMethodDescriptor(after.type, Definition.DEF_TYPE.type);
writer.invokeDynamic(value, desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.LOAD);
}
@Override
void store(MethodWriter writer) {
writer.writeDebugInfo(offset);
writer.writeDebugInfo(location);
String desc = Type.getMethodDescriptor(Definition.VOID_TYPE.type, Definition.DEF_TYPE.type, after.type);
writer.invokeDynamic(value, desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.STORE);
}

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Field;
import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Definition.Struct;
@ -38,8 +39,8 @@ public final class LField extends ALink {
Field field;
public LField(int line, int offset, String location, String value) {
super(line, offset, location, 1);
public LField(Location location, String value) {
super(location, 1);
this.value = value;
}
@ -47,15 +48,15 @@ public final class LField extends ALink {
@Override
ALink analyze(Variables variables) {
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;
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) {
return new LDefField(line, offset, location, value).copy(this).analyze(variables);
return new LDefField(location, value).copy(this).analyze(variables);
}
Struct struct = before.struct;
@ -63,7 +64,7 @@ public final class LField extends ALink {
if (field != null) {
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 + "]."));
}
@ -80,22 +81,22 @@ public final class LField extends ALink {
Character.toUpperCase(value.charAt(0)) + value.substring(1), 1));
if (shortcut) {
return new LShortcut(line, offset, location, value).copy(this).analyze(variables);
return new LShortcut(location, value).copy(this).analyze(variables);
} else {
EConstant index = new EConstant(line, offset, location, value);
EConstant index = new EConstant(location, value);
index.analyze(variables);
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)) {
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
@ -105,7 +106,7 @@ public final class LField extends ALink {
@Override
void load(MethodWriter writer) {
writer.writeDebugInfo(offset);
writer.writeDebugInfo(location);
if (java.lang.reflect.Modifier.isStatic(field.modifiers)) {
writer.getStatic(field.owner.type, field.javaName, field.type.type);
} else {
@ -115,7 +116,7 @@ public final class LField extends ALink {
@Override
void store(MethodWriter writer) {
writer.writeDebugInfo(offset);
writer.writeDebugInfo(location);
if (java.lang.reflect.Modifier.isStatic(field.modifiers)) {
writer.putStatic(field.owner.type, field.javaName, field.type.type);
} else {

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Method;
import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Variables;
@ -34,8 +35,8 @@ final class LListShortcut extends ALink {
Method getter;
Method setter;
LListShortcut(int line, int offset, String location, AExpression index) {
super(line, offset, location, 2);
LListShortcut(Location location, AExpression index) {
super(location, 2);
this.index = index;
}
@ -47,16 +48,16 @@ final class LListShortcut extends ALink {
if (getter != null && (getter.rtn.sort == Sort.VOID || getter.arguments.size() != 1 ||
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)) {
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))
|| !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)) {
@ -66,7 +67,7 @@ final class LListShortcut extends ALink {
after = setter != null ? setter.arguments.get(1) : getter.rtn;
} 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;
@ -79,7 +80,7 @@ final class LListShortcut extends ALink {
@Override
void load(MethodWriter writer) {
writer.writeDebugInfo(offset);
writer.writeDebugInfo(location);
if (java.lang.reflect.Modifier.isInterface(getter.owner.clazz.getModifiers())) {
writer.invokeInterface(getter.owner.type, getter.method);
} else {
@ -93,7 +94,7 @@ final class LListShortcut extends ALink {
@Override
void store(MethodWriter writer) {
writer.writeDebugInfo(offset);
writer.writeDebugInfo(location);
if (java.lang.reflect.Modifier.isInterface(setter.owner.clazz.getModifiers())) {
writer.invokeInterface(setter.owner.type, setter.method);
} else {

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Method;
import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Variables;
@ -34,8 +35,8 @@ final class LMapShortcut extends ALink {
Method getter;
Method setter;
LMapShortcut(int line, int offset, String location, AExpression index) {
super(line, offset, location, 2);
LMapShortcut(Location location, AExpression index) {
super(location, 2);
this.index = index;
}
@ -46,16 +47,16 @@ final class LMapShortcut extends ALink {
setter = before.struct.methods.get(new Definition.MethodKey("put", 2));
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) {
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 &&
(!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)) {
@ -65,7 +66,7 @@ final class LMapShortcut extends ALink {
after = setter != null ? setter.arguments.get(1) : getter.rtn;
} 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;
@ -78,7 +79,7 @@ final class LMapShortcut extends ALink {
@Override
void load(MethodWriter writer) {
writer.writeDebugInfo(offset);
writer.writeDebugInfo(location);
if (java.lang.reflect.Modifier.isInterface(getter.owner.clazz.getModifiers())) {
writer.invokeInterface(getter.owner.type, getter.method);
} else {
@ -92,7 +93,7 @@ final class LMapShortcut extends ALink {
@Override
void store(MethodWriter writer) {
writer.writeDebugInfo(offset);
writer.writeDebugInfo(location);
if (java.lang.reflect.Modifier.isInterface(setter.owner.clazz.getModifiers())) {
writer.invokeInterface(setter.owner.type, setter.method);
} else {

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter;
@ -34,8 +35,8 @@ public final class LNewArray extends ALink {
final String type;
final List<AExpression> arguments;
public LNewArray(int line, int offset, String location, String type, List<AExpression> arguments) {
super(line, offset, location, -1);
public LNewArray(Location location, String type, List<AExpression> arguments) {
super(location, -1);
this.type = type;
this.arguments = arguments;
@ -44,11 +45,11 @@ public final class LNewArray extends ALink {
@Override
ALink analyze(Variables variables) {
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) {
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) {
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;
@ -56,7 +57,7 @@ public final class LNewArray extends ALink {
try {
type = Definition.getType(this.type);
} 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) {
@ -79,7 +80,7 @@ public final class LNewArray extends ALink {
@Override
void load(MethodWriter writer) {
writer.writeDebugInfo(offset);
writer.writeDebugInfo(location);
for (AExpression argument : arguments) {
argument.write(writer);
}
@ -93,6 +94,6 @@ public final class LNewArray extends ALink {
@Override
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;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Constructor;
import org.elasticsearch.painless.Definition.Struct;
import org.elasticsearch.painless.Definition.Type;
@ -29,7 +30,7 @@ import org.elasticsearch.painless.MethodWriter;
import java.util.List;
/**
* Respresents and object instantiation.
* Represents and object instantiation.
*/
public final class LNewObj extends ALink {
@ -38,8 +39,8 @@ public final class LNewObj extends ALink {
Constructor constructor;
public LNewObj(int line, int offset, String location, String type, List<AExpression> arguments) {
super(line, offset, location, -1);
public LNewObj(Location location, String type, List<AExpression> arguments) {
super(location, -1);
this.type = type;
this.arguments = arguments;
@ -48,9 +49,9 @@ public final class LNewObj extends ALink {
@Override
ALink analyze(Variables variables) {
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) {
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;
@ -58,7 +59,7 @@ public final class LNewObj extends ALink {
try {
type = Definition.getType(this.type);
} 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;
@ -69,7 +70,7 @@ public final class LNewObj extends ALink {
constructor.arguments.toArray(types);
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() + "]."));
}
@ -85,7 +86,7 @@ public final class LNewObj extends ALink {
statement = true;
after = type;
} 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;
@ -98,7 +99,7 @@ public final class LNewObj extends ALink {
@Override
void load(MethodWriter writer) {
writer.writeDebugInfo(offset);
writer.writeDebugInfo(location);
writer.newInstance(after.type);
if (load) {
@ -114,6 +115,6 @@ public final class LNewObj extends ALink {
@Override
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;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Method;
import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Definition.Struct;
@ -36,8 +37,8 @@ final class LShortcut extends ALink {
Method getter = null;
Method setter = null;
LShortcut(int line, int offset, String location, String value) {
super(line, offset, location, 1);
LShortcut(Location location, String value) {
super(location, 1);
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));
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 + "]."));
}
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 + "]."));
}
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)) {
after = setter != null ? setter.arguments.get(0) : getter.rtn;
} 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;
@ -84,7 +85,7 @@ final class LShortcut extends ALink {
@Override
void load(MethodWriter writer) {
writer.writeDebugInfo(offset);
writer.writeDebugInfo(location);
if (java.lang.reflect.Modifier.isInterface(getter.owner.clazz.getModifiers())) {
writer.invokeInterface(getter.owner.type, getter.method);
} else {
@ -98,7 +99,7 @@ final class LShortcut extends ALink {
@Override
void store(MethodWriter writer) {
writer.writeDebugInfo(offset);
writer.writeDebugInfo(location);
if (java.lang.reflect.Modifier.isInterface(setter.owner.clazz.getModifiers())) {
writer.invokeInterface(setter.owner.type, setter.method);
} else {

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.Variables;
@ -30,8 +31,8 @@ public final class LStatic extends ALink {
final String type;
public LStatic(int line, int offset, String location, String type) {
super(line, offset, location, 0);
public LStatic(Location location, String type) {
super(location, 0);
this.type = type;
}
@ -39,14 +40,14 @@ public final class LStatic extends ALink {
@Override
ALink analyze(Variables variables) {
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 {
after = Definition.getType(type);
statik = true;
} catch (IllegalArgumentException exception) {
throw new IllegalArgumentException(error("Not a type [" + type + "]."));
throw createError(new IllegalArgumentException("Not a type [" + type + "]."));
}
return this;
@ -54,16 +55,16 @@ public final class LStatic extends ALink {
@Override
void write(MethodWriter writer) {
throw new IllegalStateException(error("Illegal tree structure."));
throw createError(new IllegalStateException("Illegal tree structure."));
}
@Override
void load(MethodWriter writer) {
throw new IllegalStateException(error("Illegal tree structure."));
throw createError(new IllegalStateException("Illegal tree structure."));
}
@Override
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;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter;
@ -28,8 +29,8 @@ import org.elasticsearch.painless.MethodWriter;
*/
public final class LString extends ALink {
public LString(int line, int offset, String location, String string) {
super(line, offset, location, -1);
public LString(Location location, String string) {
super(location, -1);
this.string = string;
}
@ -37,11 +38,11 @@ public final class LString extends ALink {
@Override
ALink analyze(Variables variables) {
if (before != null) {
throw new IllegalArgumentException(error("Illegal String constant [" + string + "]."));
throw createError(new IllegalArgumentException("Illegal String constant [" + string + "]."));
} 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) {
throw new IllegalArgumentException(error("Must read String constant [" + string + "]."));
throw createError(new IllegalArgumentException("Must read String constant [" + string + "]."));
}
after = Definition.STRING_TYPE;
@ -61,6 +62,6 @@ public final class LString extends ALink {
@Override
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;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.Variables.Variable;
@ -33,8 +34,8 @@ public final class LVariable extends ALink {
int slot;
public LVariable(int line, int offset, String location, String name) {
super(line, offset, location, 0);
public LVariable(Location location, String name) {
super(location, 0);
this.name = name;
}
@ -42,13 +43,13 @@ public final class LVariable extends ALink {
@Override
ALink analyze(Variables variables) {
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);
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;

View File

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

View File

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

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.Variables.Variable;
@ -42,8 +43,8 @@ public final class SCatch extends AStatement {
Label end;
Label exception;
public SCatch(int line, int offset, String location, String type, String name, SBlock block) {
super(line, offset, location);
public SCatch(Location location, String type, String name, SBlock block) {
super(location);
this.type = type;
this.name = name;
@ -57,11 +58,11 @@ public final class SCatch extends AStatement {
try {
type = Definition.getType(this.type);
} 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)) {
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);
@ -84,7 +85,7 @@ public final class SCatch extends AStatement {
@Override
void write(MethodWriter writer) {
writer.writeStatementOffset(offset);
writer.writeStatementOffset(location);
Label jump = new Label();
writer.mark(jump);

View File

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

View File

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

View File

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

View File

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

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.MethodWriter;
@ -31,8 +32,8 @@ public final class SExpression extends AStatement {
AExpression expression;
public SExpression(int line, int offset, String location, AExpression expression) {
super(line, offset, location);
public SExpression(Location location, AExpression expression) {
super(location);
this.expression = expression;
}
@ -43,7 +44,7 @@ public final class SExpression extends AStatement {
expression.analyze(variables);
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;
@ -60,7 +61,7 @@ public final class SExpression extends AStatement {
@Override
void write(MethodWriter writer) {
writer.writeStatementOffset(offset);
writer.writeStatementOffset(location);
expression.write(writer);
if (methodEscape) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -20,6 +20,7 @@
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Variables;
import org.objectweb.asm.Label;
import org.elasticsearch.painless.MethodWriter;
@ -33,8 +34,8 @@ public final class SWhile extends AStatement {
AExpression condition;
final SBlock block;
public SWhile(int line, int offset, String location, int maxLoopCounter, AExpression condition, SBlock block) {
super(line, offset, location);
public SWhile(Location location, int maxLoopCounter, AExpression condition, SBlock block) {
super(location);
this.maxLoopCounter = maxLoopCounter;
this.condition = condition;
@ -55,11 +56,11 @@ public final class SWhile extends AStatement {
continuous = (boolean)condition.constant;
if (!continuous) {
throw new IllegalArgumentException(error("Extraneous while loop."));
throw createError(new IllegalArgumentException("Extraneous while loop."));
}
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);
if (block.loopEscape && !block.anyContinue) {
throw new IllegalArgumentException(error("Extraneous while loop."));
throw createError(new IllegalArgumentException("Extraneous while loop."));
}
if (continuous && !block.anyBreak) {
@ -92,7 +93,7 @@ public final class SWhile extends AStatement {
@Override
void write(MethodWriter writer) {
writer.writeStatementOffset(offset);
writer.writeStatementOffset(location);
Label begin = new Label();
Label end = new Label();
@ -102,13 +103,13 @@ public final class SWhile extends AStatement {
condition.write(writer);
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.brake = end;
block.write(writer);
} else {
writer.writeLoopCounter(loopCounterSlot, 1, offset);
writer.writeLoopCounter(loopCounterSlot, 1, location);
}
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.
* 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.
* E* (expression) - These are nodess 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.
* E* (expression) - These are nodes that represent an expression in Painless. These are the middle level nodes.
* L* (link) - These are nodes that represent a piece of a variable/method chain. The are the lowest level nodes.
* <p>
* The following is a brief description of each node:
* {@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.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.EConditional} - Respresents a conditional expression.
* {@link org.elasticsearch.painless.node.EConstant} - Respresents a constant. (Internal only.)
* {@link org.elasticsearch.painless.node.EDecimal} - Respresents a decimal constant.
* {@link org.elasticsearch.painless.node.EConditional} - Represents a conditional expression.
* {@link org.elasticsearch.painless.node.EConstant} - Represents a constant. (Internal only.)
* {@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.EFunctionRef} - Represents a function reference.
* {@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.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.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.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.)
@ -58,7 +58,7 @@
* {@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.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.LStatic} - Represents a static type target.
* {@link org.elasticsearch.painless.node.LString} - Represents a string constant.

View File

@ -70,24 +70,20 @@ public class ConditionalTests extends ScriptTestCase {
}
public void testIncompatibleAssignment() {
try {
expectScriptThrows(ClassCastException.class, () -> {
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;");
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;");
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;");
fail("expected class cast exception");
} catch (ClassCastException expected) {}
});
}
}

View File

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

View File

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

View File

@ -25,7 +25,7 @@ public class OverloadTests extends ScriptTestCase {
public void testMethod() {
assertEquals(2, exec("return 'abc123abc'.indexOf('c');"));
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');");
});
assertTrue(expected.getMessage().contains("[indexOf] with [3] arguments"));

View File

@ -124,18 +124,12 @@ public class RemainderTests extends ScriptTestCase {
}
public void testDivideByZeroConst() throws Exception {
try {
expectScriptThrows(ArithmeticException.class, () -> {
exec("return 1%0;");
fail("should have hit exception");
} catch (ArithmeticException expected) {
// divide by zero
}
});
try {
expectScriptThrows(ArithmeticException.class, () -> {
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! */
public void testScoreVar() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("int _score = 5; return _score;");
});
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! */
public void testScoreStore() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("_score = 5; return _score;");
});
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! */
public void testDocVar() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("int doc = 5; return doc;");
});
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! */
public void testDocStore() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("doc = 5; return doc;");
});
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! */
public void testCtxVar() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("int ctx = 5; return ctx;");
});
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! */
public void testCtxStore() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("ctx = 5; return ctx;");
});
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! */
public void testAggregationValueVar() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("int _value = 5; return _value;");
});
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! */
public void testAggregationValueStore() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("_value = 5; return _value;");
});
assertTrue(expected.getMessage().contains("Variable [_value] is read-only"));

View File

@ -71,11 +71,11 @@ public class WhenThingsGoWrongTests extends ScriptTestCase {
}
public void testInvalidShift() {
expectThrows(ClassCastException.class, () -> {
expectScriptThrows(ClassCastException.class, () -> {
exec("float x = 15F; x <<= 2; return x;");
});
expectThrows(ClassCastException.class, () -> {
expectScriptThrows(ClassCastException.class, () -> {
exec("double x = 15F; x <<= 2; return x;");
});
}
@ -134,7 +134,7 @@ public class WhenThingsGoWrongTests extends ScriptTestCase {
assertTrue(expected.getMessage().contains(
"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) {}");
fail("should have hit ParseException");
});
@ -156,7 +156,7 @@ public class WhenThingsGoWrongTests extends ScriptTestCase {
final char[] tooManyChars = new char[Compiler.MAXIMUM_SOURCE_LENGTH + 1];
Arrays.fill(tooManyChars, '0');
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec(new String(tooManyChars));
});
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) {
ANTLRInputStream stream = new ANTLRInputStream(source);
PainlessLexer lexer = new ErrorHandlingLexer(stream);
PainlessLexer lexer = new ErrorHandlingLexer(stream, "testing");
PainlessParser parser = new PainlessParser(new CommonTokenStream(lexer));
ParserErrorStrategy strategy = new ParserErrorStrategy();
ParserErrorStrategy strategy = new ParserErrorStrategy("testing");
lexer.removeErrorListeners();
parser.removeErrorListeners();

View File

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