SpelNodeImpl manages start/end position in separate integer values

Fixes gh-22157
This commit is contained in:
Juergen Hoeller 2019-01-28 22:50:56 +01:00
parent 5aed117b68
commit 7a77e83e10
51 changed files with 280 additions and 298 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -31,8 +31,8 @@ import org.springframework.expression.spel.ExpressionState;
*/ */
public class Assign extends SpelNodeImpl { public class Assign extends SpelNodeImpl {
public Assign(int pos, SpelNodeImpl... operands) { public Assign(int startPos, int endPos, SpelNodeImpl... operands) {
super(pos, operands); super(startPos, endPos, operands);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -37,8 +37,8 @@ public class BeanReference extends SpelNodeImpl {
private final String beanName; private final String beanName;
public BeanReference(int pos, String beanName) { public BeanReference(int startPos, int endPos, String beanName) {
super(pos); super(startPos, endPos);
this.beanName = beanName; this.beanName = beanName;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -31,8 +31,8 @@ public class BooleanLiteral extends Literal {
private final BooleanTypedValue value; private final BooleanTypedValue value;
public BooleanLiteral(String payload, int pos, boolean value) { public BooleanLiteral(String payload, int startPos, int endPos, boolean value) {
super(payload, pos); super(payload, startPos, endPos);
this.value = BooleanTypedValue.forValue(value); this.value = BooleanTypedValue.forValue(value);
this.exitTypeDescriptor = "Z"; this.exitTypeDescriptor = "Z";
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -33,8 +33,8 @@ import org.springframework.lang.Nullable;
*/ */
public class CompoundExpression extends SpelNodeImpl { public class CompoundExpression extends SpelNodeImpl {
public CompoundExpression(int pos, SpelNodeImpl... expressionComponents) { public CompoundExpression(int startPos, int endPos, SpelNodeImpl... expressionComponents) {
super(pos, expressionComponents); super(startPos, endPos, expressionComponents);
if (expressionComponents.length < 2) { if (expressionComponents.length < 2) {
throw new IllegalStateException("Do not build compound expressions with less than two entries: " + throw new IllegalStateException("Do not build compound expressions with less than two entries: " +
expressionComponents.length); expressionComponents.length);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -72,8 +72,8 @@ public class ConstructorReference extends SpelNodeImpl {
* Create a constructor reference. The first argument is the type, the rest are the parameters to the constructor * Create a constructor reference. The first argument is the type, the rest are the parameters to the constructor
* call * call
*/ */
public ConstructorReference(int pos, SpelNodeImpl... arguments) { public ConstructorReference(int startPos, int endPos, SpelNodeImpl... arguments) {
super(pos, arguments); super(startPos, endPos, arguments);
this.isArrayConstructor = false; this.isArrayConstructor = false;
} }
@ -81,8 +81,8 @@ public class ConstructorReference extends SpelNodeImpl {
* Create a constructor reference. The first argument is the type, the rest are the parameters to the constructor * Create a constructor reference. The first argument is the type, the rest are the parameters to the constructor
* call * call
*/ */
public ConstructorReference(int pos, SpelNodeImpl[] dimensions, SpelNodeImpl... arguments) { public ConstructorReference(int startPos, int endPos, SpelNodeImpl[] dimensions, SpelNodeImpl... arguments) {
super(pos, arguments); super(startPos, endPos, arguments);
this.isArrayConstructor = true; this.isArrayConstructor = true;
this.dimensions = dimensions; this.dimensions = dimensions;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -36,8 +36,8 @@ import org.springframework.util.StringUtils;
*/ */
public class Elvis extends SpelNodeImpl { public class Elvis extends SpelNodeImpl {
public Elvis(int pos, SpelNodeImpl... args) { public Elvis(int startPos, int endPos, SpelNodeImpl... args) {
super(pos, args); super(startPos, endPos, args);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -32,8 +32,8 @@ public class FloatLiteral extends Literal {
private final TypedValue value; private final TypedValue value;
public FloatLiteral(String payload, int pos, float value) { public FloatLiteral(String payload, int startPos, int endPos, float value) {
super(payload, pos); super(payload, startPos, endPos);
this.value = new TypedValue(value); this.value = new TypedValue(value);
this.exitTypeDescriptor = "F"; this.exitTypeDescriptor = "F";
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -57,8 +57,8 @@ public class FunctionReference extends SpelNodeImpl {
private volatile Method method; private volatile Method method;
public FunctionReference(String functionName, int pos, SpelNodeImpl... arguments) { public FunctionReference(String functionName, int startPos, int endPos, SpelNodeImpl... arguments) {
super(pos, arguments); super(startPos, endPos, arguments);
this.name = functionName; this.name = functionName;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -31,8 +31,8 @@ public class Identifier extends SpelNodeImpl {
private final TypedValue id; private final TypedValue id;
public Identifier(String payload, int pos) { public Identifier(String payload, int startPos, int endPos) {
super(pos); super(startPos, endPos);
this.id = new TypedValue(payload); this.id = new TypedValue(payload);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -90,8 +90,8 @@ public class Indexer extends SpelNodeImpl {
private IndexedType indexedType; private IndexedType indexedType;
public Indexer(int pos, SpelNodeImpl expr) { public Indexer(int startPos, int endPos, SpelNodeImpl expr) {
super(pos, expr); super(startPos, endPos, expr);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -42,8 +42,8 @@ public class InlineList extends SpelNodeImpl {
private TypedValue constant; // TODO must be immutable list private TypedValue constant; // TODO must be immutable list
public InlineList(int pos, SpelNodeImpl... args) { public InlineList(int startPos, int endPos, SpelNodeImpl... args) {
super(pos, args); super(startPos, endPos, args);
checkIfConstant(); checkIfConstant();
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -40,14 +40,14 @@ public class InlineMap extends SpelNodeImpl {
private TypedValue constant; private TypedValue constant;
public InlineMap(int pos, SpelNodeImpl... args) { public InlineMap(int startPos, int endPos, SpelNodeImpl... args) {
super(pos, args); super(startPos, endPos, args);
checkIfConstant(); checkIfConstant();
} }
/** /**
* If all the components of the list are constants, or lists/maps that themselves * If all the components of the map are constants, or lists/maps that themselves
* contain constants, then a constant list can be built to represent this node. * contain constants, then a constant list can be built to represent this node.
* This will speed up later getValue calls and reduce the amount of garbage created. * This will speed up later getValue calls and reduce the amount of garbage created.
*/ */
@ -70,14 +70,14 @@ public class InlineMap extends SpelNodeImpl {
break; break;
} }
} }
else if (!((c%2)==0 && (child instanceof PropertyOrFieldReference))) { else if (!(c % 2 == 0 && child instanceof PropertyOrFieldReference)) {
isConstant = false; isConstant = false;
break; break;
} }
} }
} }
if (isConstant) { if (isConstant) {
Map<Object,Object> constantMap = new LinkedHashMap<>(); Map<Object, Object> constantMap = new LinkedHashMap<>();
int childCount = getChildCount(); int childCount = getChildCount();
for (int c = 0; c < childCount; c++) { for (int c = 0; c < childCount; c++) {
SpelNode keyChild = getChild(c++); SpelNode keyChild = getChild(c++);
@ -159,9 +159,9 @@ public class InlineMap extends SpelNodeImpl {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Nullable @Nullable
public Map<Object,Object> getConstantValue() { public Map<Object, Object> getConstantValue() {
Assert.state(this.constant != null, "No constant"); Assert.state(this.constant != null, "No constant");
return (Map<Object,Object>) this.constant.getValue(); return (Map<Object, Object>) this.constant.getValue();
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -32,8 +32,8 @@ public class IntLiteral extends Literal {
private final TypedValue value; private final TypedValue value;
public IntLiteral(String payload, int pos, int value) { public IntLiteral(String payload, int startPos, int endPos, int value) {
super(payload, pos); super(payload, startPos, endPos);
this.value = new TypedValue(value); this.value = new TypedValue(value);
this.exitTypeDescriptor = "I"; this.exitTypeDescriptor = "I";
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -36,8 +36,8 @@ public abstract class Literal extends SpelNodeImpl {
private final String originalValue; private final String originalValue;
public Literal(@Nullable String originalValue, int pos) { public Literal(@Nullable String originalValue, int startPos, int endPos) {
super(pos); super(startPos, endPos);
this.originalValue = originalValue; this.originalValue = originalValue;
} }
@ -74,39 +74,39 @@ public abstract class Literal extends SpelNodeImpl {
* @param radix the base of number * @param radix the base of number
* @return a subtype of Literal that can represent it * @return a subtype of Literal that can represent it
*/ */
public static Literal getIntLiteral(String numberToken, int pos, int radix) { public static Literal getIntLiteral(String numberToken, int startPos, int endPos, int radix) {
try { try {
int value = Integer.parseInt(numberToken, radix); int value = Integer.parseInt(numberToken, radix);
return new IntLiteral(numberToken, pos, value); return new IntLiteral(numberToken, startPos, endPos, value);
} }
catch (NumberFormatException ex) { catch (NumberFormatException ex) {
throw new InternalParseException(new SpelParseException(pos>>16, ex, SpelMessage.NOT_AN_INTEGER, numberToken)); throw new InternalParseException(new SpelParseException(startPos, ex, SpelMessage.NOT_AN_INTEGER, numberToken));
} }
} }
public static Literal getLongLiteral(String numberToken, int pos, int radix) { public static Literal getLongLiteral(String numberToken, int startPos, int endPos, int radix) {
try { try {
long value = Long.parseLong(numberToken, radix); long value = Long.parseLong(numberToken, radix);
return new LongLiteral(numberToken, pos, value); return new LongLiteral(numberToken, startPos, endPos, value);
} }
catch (NumberFormatException ex) { catch (NumberFormatException ex) {
throw new InternalParseException(new SpelParseException(pos>>16, ex, SpelMessage.NOT_A_LONG, numberToken)); throw new InternalParseException(new SpelParseException(startPos, ex, SpelMessage.NOT_A_LONG, numberToken));
} }
} }
public static Literal getRealLiteral(String numberToken, int pos, boolean isFloat) { public static Literal getRealLiteral(String numberToken, int startPos, int endPos, boolean isFloat) {
try { try {
if (isFloat) { if (isFloat) {
float value = Float.parseFloat(numberToken); float value = Float.parseFloat(numberToken);
return new FloatLiteral(numberToken, pos, value); return new FloatLiteral(numberToken, startPos, endPos, value);
} }
else { else {
double value = Double.parseDouble(numberToken); double value = Double.parseDouble(numberToken);
return new RealLiteral(numberToken, pos, value); return new RealLiteral(numberToken, startPos, endPos, value);
} }
} }
catch (NumberFormatException ex) { catch (NumberFormatException ex) {
throw new InternalParseException(new SpelParseException(pos>>16, ex, SpelMessage.NOT_A_REAL, numberToken)); throw new InternalParseException(new SpelParseException(startPos, ex, SpelMessage.NOT_A_REAL, numberToken));
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -31,8 +31,8 @@ public class LongLiteral extends Literal {
private final TypedValue value; private final TypedValue value;
public LongLiteral(String payload, int pos, long value) { public LongLiteral(String payload, int startPos, int endPos, long value) {
super(payload, pos); super(payload, startPos, endPos);
this.value = new TypedValue(value); this.value = new TypedValue(value);
this.exitTypeDescriptor = "J"; this.exitTypeDescriptor = "J";
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -64,8 +64,8 @@ public class MethodReference extends SpelNodeImpl {
private volatile CachedMethodExecutor cachedExecutor; private volatile CachedMethodExecutor cachedExecutor;
public MethodReference(boolean nullSafe, String methodName, int pos, SpelNodeImpl... arguments) { public MethodReference(boolean nullSafe, String methodName, int startPos, int endPos, SpelNodeImpl... arguments) {
super(pos, arguments); super(startPos, endPos, arguments);
this.name = methodName; this.name = methodName;
this.nullSafe = nullSafe; this.nullSafe = nullSafe;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -28,8 +28,8 @@ import org.springframework.expression.spel.CodeFlow;
*/ */
public class NullLiteral extends Literal { public class NullLiteral extends Literal {
public NullLiteral(int pos) { public NullLiteral(int startPos, int endPos) {
super(null, pos); super(null, startPos, endPos);
this.exitTypeDescriptor = "Ljava/lang/Object"; this.exitTypeDescriptor = "Ljava/lang/Object";
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -37,8 +37,8 @@ import org.springframework.lang.Nullable;
*/ */
public class OpAnd extends Operator { public class OpAnd extends Operator {
public OpAnd(int pos, SpelNodeImpl... operands) { public OpAnd(int startPos, int endPos, SpelNodeImpl... operands) {
super("and", pos, operands); super("and", startPos, endPos, operands);
this.exitTypeDescriptor = "Z"; this.exitTypeDescriptor = "Z";
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -41,8 +41,8 @@ public class OpDec extends Operator {
private final boolean postfix; // false means prefix private final boolean postfix; // false means prefix
public OpDec(int pos, boolean postfix, SpelNodeImpl... operands) { public OpDec(int startPos, int endPos, boolean postfix, SpelNodeImpl... operands) {
super("--", pos, operands); super("--", startPos, endPos, operands);
this.postfix = postfix; this.postfix = postfix;
Assert.notEmpty(operands, "Operands must not be empty"); Assert.notEmpty(operands, "Operands must not be empty");
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -39,8 +39,8 @@ import org.springframework.util.NumberUtils;
*/ */
public class OpDivide extends Operator { public class OpDivide extends Operator {
public OpDivide(int pos, SpelNodeImpl... operands) { public OpDivide(int startPos, int endPos, SpelNodeImpl... operands) {
super("/", pos, operands); super("/", startPos, endPos, operands);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -31,8 +31,8 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
*/ */
public class OpEQ extends Operator { public class OpEQ extends Operator {
public OpEQ(int pos, SpelNodeImpl... operands) { public OpEQ(int startPos, int endPos, SpelNodeImpl... operands) {
super("==", pos, operands); super("==", startPos, endPos, operands);
this.exitTypeDescriptor = "Z"; this.exitTypeDescriptor = "Z";
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -36,8 +36,8 @@ import org.springframework.util.NumberUtils;
*/ */
public class OpGE extends Operator { public class OpGE extends Operator {
public OpGE(int pos, SpelNodeImpl... operands) { public OpGE(int startPos, int endPos, SpelNodeImpl... operands) {
super(">=", pos, operands); super(">=", startPos, endPos, operands);
this.exitTypeDescriptor = "Z"; this.exitTypeDescriptor = "Z";
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -36,8 +36,8 @@ import org.springframework.util.NumberUtils;
*/ */
public class OpGT extends Operator { public class OpGT extends Operator {
public OpGT(int pos, SpelNodeImpl... operands) { public OpGT(int startPos, int endPos, SpelNodeImpl... operands) {
super(">", pos, operands); super(">", startPos, endPos, operands);
this.exitTypeDescriptor = "Z"; this.exitTypeDescriptor = "Z";
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -41,8 +41,8 @@ public class OpInc extends Operator {
private final boolean postfix; // false means prefix private final boolean postfix; // false means prefix
public OpInc(int pos, boolean postfix, SpelNodeImpl... operands) { public OpInc(int startPos, int endPos, boolean postfix, SpelNodeImpl... operands) {
super("++", pos, operands); super("++", startPos, endPos, operands);
this.postfix = postfix; this.postfix = postfix;
Assert.notEmpty(operands, "Operands must not be empty"); Assert.notEmpty(operands, "Operands must not be empty");
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -36,8 +36,8 @@ import org.springframework.util.NumberUtils;
*/ */
public class OpLE extends Operator { public class OpLE extends Operator {
public OpLE(int pos, SpelNodeImpl... operands) { public OpLE(int startPos, int endPos, SpelNodeImpl... operands) {
super("<=", pos, operands); super("<=", startPos, endPos, operands);
this.exitTypeDescriptor = "Z"; this.exitTypeDescriptor = "Z";
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -36,8 +36,8 @@ import org.springframework.util.NumberUtils;
*/ */
public class OpLT extends Operator { public class OpLT extends Operator {
public OpLT(int pos, SpelNodeImpl... operands) { public OpLT(int startPos, int endPos, SpelNodeImpl... operands) {
super("<", pos, operands); super("<", startPos, endPos, operands);
this.exitTypeDescriptor = "Z"; this.exitTypeDescriptor = "Z";
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -47,8 +47,8 @@ import org.springframework.util.NumberUtils;
*/ */
public class OpMinus extends Operator { public class OpMinus extends Operator {
public OpMinus(int pos, SpelNodeImpl... operands) { public OpMinus(int startPos, int endPos, SpelNodeImpl... operands) {
super("-", pos, operands); super("-", startPos, endPos, operands);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -38,8 +38,8 @@ import org.springframework.util.NumberUtils;
*/ */
public class OpModulus extends Operator { public class OpModulus extends Operator {
public OpModulus(int pos, SpelNodeImpl... operands) { public OpModulus(int startPos, int endPos, SpelNodeImpl... operands) {
super("%", pos, operands); super("%", startPos, endPos, operands);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -52,8 +52,8 @@ import org.springframework.util.NumberUtils;
*/ */
public class OpMultiply extends Operator { public class OpMultiply extends Operator {
public OpMultiply(int pos, SpelNodeImpl... operands) { public OpMultiply(int startPos, int endPos, SpelNodeImpl... operands) {
super("*", pos, operands); super("*", startPos, endPos, operands);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -32,8 +32,8 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
*/ */
public class OpNE extends Operator { public class OpNE extends Operator {
public OpNE(int pos, SpelNodeImpl... operands) { public OpNE(int startPos, int endPos, SpelNodeImpl... operands) {
super("!=", pos, operands); super("!=", startPos, endPos, operands);
this.exitTypeDescriptor = "Z"; this.exitTypeDescriptor = "Z";
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -36,8 +36,8 @@ import org.springframework.lang.Nullable;
*/ */
public class OpOr extends Operator { public class OpOr extends Operator {
public OpOr(int pos, SpelNodeImpl... operands) { public OpOr(int startPos, int endPos, SpelNodeImpl... operands) {
super("or", pos, operands); super("or", startPos, endPos, operands);
this.exitTypeDescriptor = "Z"; this.exitTypeDescriptor = "Z";
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -50,8 +50,8 @@ import org.springframework.util.NumberUtils;
*/ */
public class OpPlus extends Operator { public class OpPlus extends Operator {
public OpPlus(int pos, SpelNodeImpl... operands) { public OpPlus(int startPos, int endPos, SpelNodeImpl... operands) {
super("+", pos, operands); super("+", startPos, endPos, operands);
Assert.notEmpty(operands, "Operands must not be empty"); Assert.notEmpty(operands, "Operands must not be empty");
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -54,8 +54,8 @@ public abstract class Operator extends SpelNodeImpl {
protected String rightActualDescriptor; protected String rightActualDescriptor;
public Operator(String payload, int pos, SpelNodeImpl... operands) { public Operator(String payload, int startPos, int endPos, SpelNodeImpl... operands) {
super(pos, operands); super(startPos, endPos, operands);
this.operatorName = payload; this.operatorName = payload;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2014 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -36,8 +36,8 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
*/ */
public class OperatorBetween extends Operator { public class OperatorBetween extends Operator {
public OperatorBetween(int pos, SpelNodeImpl... operands) { public OperatorBetween(int startPos, int endPos, SpelNodeImpl... operands) {
super("between", pos, operands); super("between", startPos, endPos, operands);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -41,8 +41,8 @@ public class OperatorInstanceof extends Operator {
private Class<?> type; private Class<?> type;
public OperatorInstanceof(int pos, SpelNodeImpl... operands) { public OperatorInstanceof(int startPos, int endPos, SpelNodeImpl... operands) {
super("instanceof", pos, operands); super("instanceof", startPos, endPos, operands);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -45,8 +45,8 @@ public class OperatorMatches extends Operator {
private final ConcurrentMap<String, Pattern> patternCache = new ConcurrentHashMap<>(); private final ConcurrentMap<String, Pattern> patternCache = new ConcurrentHashMap<>();
public OperatorMatches(int pos, SpelNodeImpl... operands) { public OperatorMatches(int startPos, int endPos, SpelNodeImpl... operands) {
super("matches", pos, operands); super("matches", startPos, endPos, operands);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -35,8 +35,8 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
*/ */
public class OperatorNot extends SpelNodeImpl { // Not is a unary operator so does not extend BinaryOperator public class OperatorNot extends SpelNodeImpl { // Not is a unary operator so does not extend BinaryOperator
public OperatorNot(int pos, SpelNodeImpl operand) { public OperatorNot(int startPos, int endPos, SpelNodeImpl operand) {
super(pos, operand); super(startPos, endPos, operand);
this.exitTypeDescriptor = "Z"; this.exitTypeDescriptor = "Z";
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2014 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -34,8 +34,8 @@ import org.springframework.util.NumberUtils;
*/ */
public class OperatorPower extends Operator { public class OperatorPower extends Operator {
public OperatorPower(int pos, SpelNodeImpl... operands) { public OperatorPower(int startPos, int endPos, SpelNodeImpl... operands) {
super("^", pos, operands); super("^", startPos, endPos, operands);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -46,8 +46,8 @@ public class Projection extends SpelNodeImpl {
private final boolean nullSafe; private final boolean nullSafe;
public Projection(boolean nullSafe, int pos, SpelNodeImpl expression) { public Projection(boolean nullSafe, int startPos, int endPos, SpelNodeImpl expression) {
super(pos, expression); super(startPos, endPos, expression);
this.nullSafe = nullSafe; this.nullSafe = nullSafe;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -64,8 +64,8 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
private volatile PropertyAccessor cachedWriteAccessor; private volatile PropertyAccessor cachedWriteAccessor;
public PropertyOrFieldReference(boolean nullSafe, String propertyOrFieldName, int pos) { public PropertyOrFieldReference(boolean nullSafe, String propertyOrFieldName, int startPos, int endPos) {
super(pos); super(startPos, endPos);
this.nullSafe = nullSafe; this.nullSafe = nullSafe;
this.name = propertyOrFieldName; this.name = propertyOrFieldName;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -36,8 +36,8 @@ public class QualifiedIdentifier extends SpelNodeImpl {
private TypedValue value; private TypedValue value;
public QualifiedIdentifier(int pos, SpelNodeImpl... operands) { public QualifiedIdentifier(int startPos, int endPos, SpelNodeImpl... operands) {
super(pos, operands); super(startPos, endPos, operands);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -31,8 +31,8 @@ public class RealLiteral extends Literal {
private final TypedValue value; private final TypedValue value;
public RealLiteral(String payload, int pos, double value) { public RealLiteral(String payload, int startPos, int endPos, double value) {
super(payload, pos); super(payload, startPos, endPos);
this.value = new TypedValue(value); this.value = new TypedValue(value);
this.exitTypeDescriptor = "D"; this.exitTypeDescriptor = "D";
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -69,8 +69,8 @@ public class Selection extends SpelNodeImpl {
private final boolean nullSafe; private final boolean nullSafe;
public Selection(boolean nullSafe, int variant, int pos, SpelNodeImpl expression) { public Selection(boolean nullSafe, int variant, int startPos, int endPos, SpelNodeImpl expression) {
super(pos, expression); super(startPos, endPos, expression);
this.nullSafe = nullSafe; this.nullSafe = nullSafe;
this.variant = variant; this.variant = variant;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -47,7 +47,9 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes {
private static final SpelNodeImpl[] NO_CHILDREN = new SpelNodeImpl[0]; private static final SpelNodeImpl[] NO_CHILDREN = new SpelNodeImpl[0];
protected final int pos; // start = top 16bits, end = bottom 16bits private final int startPos;
private final int endPos;
protected SpelNodeImpl[] children = SpelNodeImpl.NO_CHILDREN; protected SpelNodeImpl[] children = SpelNodeImpl.NO_CHILDREN;
@ -67,8 +69,9 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes {
protected volatile String exitTypeDescriptor; protected volatile String exitTypeDescriptor;
public SpelNodeImpl(int pos, SpelNodeImpl... operands) { public SpelNodeImpl(int startPos, int endPos, SpelNodeImpl... operands) {
this.pos = pos; this.startPos = startPos;
this.endPos = endPos;
if (!ObjectUtils.isEmpty(operands)) { if (!ObjectUtils.isEmpty(operands)) {
this.children = operands; this.children = operands;
for (SpelNodeImpl operand : operands) { for (SpelNodeImpl operand : operands) {
@ -146,12 +149,12 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes {
@Override @Override
public int getStartPosition() { public int getStartPosition() {
return (this.pos >> 16); return this.startPos;
} }
@Override @Override
public int getEndPosition() { public int getEndPosition() {
return (this.pos & 0xffff); return this.endPos;
} }
/** /**

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -33,8 +33,8 @@ public class StringLiteral extends Literal {
private final TypedValue value; private final TypedValue value;
public StringLiteral(String payload, int pos, String value) { public StringLiteral(String payload, int startPos, int endPos, String value) {
super(payload, pos); super(payload, startPos, endPos);
String valueWithinQuotes = value.substring(1, value.length() - 1); String valueWithinQuotes = value.substring(1, value.length() - 1);
valueWithinQuotes = StringUtils.replace(valueWithinQuotes, "''", "'"); valueWithinQuotes = StringUtils.replace(valueWithinQuotes, "''", "'");

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -36,8 +36,8 @@ import org.springframework.util.ObjectUtils;
*/ */
public class Ternary extends SpelNodeImpl { public class Ternary extends SpelNodeImpl {
public Ternary(int pos, SpelNodeImpl... args) { public Ternary(int startPos, int endPos, SpelNodeImpl... args) {
super(pos, args); super(startPos, endPos, args);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -41,12 +41,12 @@ public class TypeReference extends SpelNodeImpl {
private transient Class<?> type; private transient Class<?> type;
public TypeReference(int pos, SpelNodeImpl qualifiedId) { public TypeReference(int startPos, int endPos, SpelNodeImpl qualifiedId) {
this(pos, qualifiedId, 0); this(startPos, endPos, qualifiedId, 0);
} }
public TypeReference(int pos, SpelNodeImpl qualifiedId, int dims) { public TypeReference(int startPos, int endPos, SpelNodeImpl qualifiedId, int dims) {
super(pos, qualifiedId); super(startPos, endPos, qualifiedId);
this.dimensions = dims; this.dimensions = dims;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -24,8 +24,8 @@ import org.springframework.lang.Nullable;
/** /**
* Represents a reference to a value. With a reference it is possible to get or set the * Represents a reference to a value. With a reference it is possible to get or set the
* value. Passing around value references rather than the values themselves can avoid * value. Passing around value references rather than the values themselves can avoid
* incorrect duplication of operand evaluation. For example in 'list[index++]++' without a * incorrect duplication of operand evaluation. For example in 'list[index++]++' without
* value reference for 'list[index++]' it would be necessary to evaluate list[index++] * a value reference for 'list[index++]' it would be necessary to evaluate list[index++]
* twice (once to get the value, once to determine where the value goes) and that would * twice (once to get the value, once to determine where the value goes) and that would
* double increment index. * double increment index.
* *
@ -103,7 +103,8 @@ public interface ValueRef {
@Override @Override
public void setValue(@Nullable Object newValue) { public void setValue(@Nullable Object newValue) {
throw new SpelEvaluationException(this.node.pos, SpelMessage.NOT_ASSIGNABLE, this.node.toStringAST()); throw new SpelEvaluationException(
this.node.getStartPosition(), SpelMessage.NOT_ASSIGNABLE, this.node.toStringAST());
} }
@Override @Override

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -44,8 +44,8 @@ public class VariableReference extends SpelNodeImpl {
private final String name; private final String name;
public VariableReference(String variableName, int pos) { public VariableReference(String variableName, int startPos, int endPos) {
super(pos); super(startPos, endPos);
this.name = variableName; this.name = variableName;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -155,32 +155,32 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
if (t != null) { if (t != null) {
if (t.kind == TokenKind.ASSIGN) { // a=b if (t.kind == TokenKind.ASSIGN) { // a=b
if (expr == null) { if (expr == null) {
expr = new NullLiteral(toPos(t.startPos - 1, t.endPos - 1)); expr = new NullLiteral(t.startPos - 1, t.endPos - 1);
} }
nextToken(); nextToken();
SpelNodeImpl assignedValue = eatLogicalOrExpression(); SpelNodeImpl assignedValue = eatLogicalOrExpression();
return new Assign(toPos(t), expr, assignedValue); return new Assign(t.startPos, t.endPos, expr, assignedValue);
} }
if (t.kind == TokenKind.ELVIS) { // a?:b (a if it isn't null, otherwise b) if (t.kind == TokenKind.ELVIS) { // a?:b (a if it isn't null, otherwise b)
if (expr == null) { if (expr == null) {
expr = new NullLiteral(toPos(t.startPos - 1, t.endPos - 2)); expr = new NullLiteral(t.startPos - 1, t.endPos - 2);
} }
nextToken(); // elvis has left the building nextToken(); // elvis has left the building
SpelNodeImpl valueIfNull = eatExpression(); SpelNodeImpl valueIfNull = eatExpression();
if (valueIfNull == null) { if (valueIfNull == null) {
valueIfNull = new NullLiteral(toPos(t.startPos + 1, t.endPos + 1)); valueIfNull = new NullLiteral(t.startPos + 1, t.endPos + 1);
} }
return new Elvis(toPos(t), expr, valueIfNull); return new Elvis(t.startPos, t.endPos, expr, valueIfNull);
} }
if (t.kind == TokenKind.QMARK) { // a?b:c if (t.kind == TokenKind.QMARK) { // a?b:c
if (expr == null) { if (expr == null) {
expr = new NullLiteral(toPos(t.startPos - 1, t.endPos - 1)); expr = new NullLiteral(t.startPos - 1, t.endPos - 1);
} }
nextToken(); nextToken();
SpelNodeImpl ifTrueExprValue = eatExpression(); SpelNodeImpl ifTrueExprValue = eatExpression();
eatToken(TokenKind.COLON); eatToken(TokenKind.COLON);
SpelNodeImpl ifFalseExprValue = eatExpression(); SpelNodeImpl ifFalseExprValue = eatExpression();
return new Ternary(toPos(t), expr, ifTrueExprValue, ifFalseExprValue); return new Ternary(t.startPos, t.endPos, expr, ifTrueExprValue, ifFalseExprValue);
} }
} }
return expr; return expr;
@ -194,7 +194,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
Token t = takeToken(); //consume OR Token t = takeToken(); //consume OR
SpelNodeImpl rhExpr = eatLogicalAndExpression(); SpelNodeImpl rhExpr = eatLogicalAndExpression();
checkOperands(t, expr, rhExpr); checkOperands(t, expr, rhExpr);
expr = new OpOr(toPos(t), expr, rhExpr); expr = new OpOr(t.startPos, t.endPos, expr, rhExpr);
} }
return expr; return expr;
} }
@ -207,7 +207,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
Token t = takeToken(); // consume 'AND' Token t = takeToken(); // consume 'AND'
SpelNodeImpl rhExpr = eatRelationalExpression(); SpelNodeImpl rhExpr = eatRelationalExpression();
checkOperands(t, expr, rhExpr); checkOperands(t, expr, rhExpr);
expr = new OpAnd(toPos(t), expr, rhExpr); expr = new OpAnd(t.startPos, t.endPos, expr, rhExpr);
} }
return expr; return expr;
} }
@ -224,36 +224,35 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
TokenKind tk = relationalOperatorToken.kind; TokenKind tk = relationalOperatorToken.kind;
if (relationalOperatorToken.isNumericRelationalOperator()) { if (relationalOperatorToken.isNumericRelationalOperator()) {
int pos = toPos(t);
if (tk == TokenKind.GT) { if (tk == TokenKind.GT) {
return new OpGT(pos, expr, rhExpr); return new OpGT(t.startPos, t.endPos, expr, rhExpr);
} }
if (tk == TokenKind.LT) { if (tk == TokenKind.LT) {
return new OpLT(pos, expr, rhExpr); return new OpLT(t.startPos, t.endPos, expr, rhExpr);
} }
if (tk == TokenKind.LE) { if (tk == TokenKind.LE) {
return new OpLE(pos, expr, rhExpr); return new OpLE(t.startPos, t.endPos, expr, rhExpr);
} }
if (tk == TokenKind.GE) { if (tk == TokenKind.GE) {
return new OpGE(pos, expr, rhExpr); return new OpGE(t.startPos, t.endPos, expr, rhExpr);
} }
if (tk == TokenKind.EQ) { if (tk == TokenKind.EQ) {
return new OpEQ(pos, expr, rhExpr); return new OpEQ(t.startPos, t.endPos, expr, rhExpr);
} }
Assert.isTrue(tk == TokenKind.NE, "Not-equals token expected"); Assert.isTrue(tk == TokenKind.NE, "Not-equals token expected");
return new OpNE(pos, expr, rhExpr); return new OpNE(t.startPos, t.endPos, expr, rhExpr);
} }
if (tk == TokenKind.INSTANCEOF) { if (tk == TokenKind.INSTANCEOF) {
return new OperatorInstanceof(toPos(t), expr, rhExpr); return new OperatorInstanceof(t.startPos, t.endPos, expr, rhExpr);
} }
if (tk == TokenKind.MATCHES) { if (tk == TokenKind.MATCHES) {
return new OperatorMatches(toPos(t), expr, rhExpr); return new OperatorMatches(t.startPos, t.endPos, expr, rhExpr);
} }
Assert.isTrue(tk == TokenKind.BETWEEN, "Between token expected"); Assert.isTrue(tk == TokenKind.BETWEEN, "Between token expected");
return new OperatorBetween(toPos(t), expr, rhExpr); return new OperatorBetween(t.startPos, t.endPos, expr, rhExpr);
} }
return expr; return expr;
} }
@ -267,10 +266,10 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
SpelNodeImpl rhExpr = eatProductExpression(); SpelNodeImpl rhExpr = eatProductExpression();
checkRightOperand(t, rhExpr); checkRightOperand(t, rhExpr);
if (t.kind == TokenKind.PLUS) { if (t.kind == TokenKind.PLUS) {
expr = new OpPlus(toPos(t), expr, rhExpr); expr = new OpPlus(t.startPos, t.endPos, expr, rhExpr);
} }
else if (t.kind == TokenKind.MINUS) { else if (t.kind == TokenKind.MINUS) {
expr = new OpMinus(toPos(t), expr, rhExpr); expr = new OpMinus(t.startPos, t.endPos, expr, rhExpr);
} }
} }
return expr; return expr;
@ -285,14 +284,14 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
SpelNodeImpl rhExpr = eatPowerIncDecExpression(); SpelNodeImpl rhExpr = eatPowerIncDecExpression();
checkOperands(t, expr, rhExpr); checkOperands(t, expr, rhExpr);
if (t.kind == TokenKind.STAR) { if (t.kind == TokenKind.STAR) {
expr = new OpMultiply(toPos(t), expr, rhExpr); expr = new OpMultiply(t.startPos, t.endPos, expr, rhExpr);
} }
else if (t.kind == TokenKind.DIV) { else if (t.kind == TokenKind.DIV) {
expr = new OpDivide(toPos(t), expr, rhExpr); expr = new OpDivide(t.startPos, t.endPos, expr, rhExpr);
} }
else { else {
Assert.isTrue(t.kind == TokenKind.MOD, "Mod token expected"); Assert.isTrue(t.kind == TokenKind.MOD, "Mod token expected");
expr = new OpModulus(toPos(t), expr, rhExpr); expr = new OpModulus(t.startPos, t.endPos, expr, rhExpr);
} }
} }
return expr; return expr;
@ -306,14 +305,14 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
Token t = takeToken(); //consume POWER Token t = takeToken(); //consume POWER
SpelNodeImpl rhExpr = eatUnaryExpression(); SpelNodeImpl rhExpr = eatUnaryExpression();
checkRightOperand(t, rhExpr); checkRightOperand(t, rhExpr);
return new OperatorPower(toPos(t), expr, rhExpr); return new OperatorPower(t.startPos, t.endPos, expr, rhExpr);
} }
if (expr != null && peekToken(TokenKind.INC, TokenKind.DEC)) { if (expr != null && peekToken(TokenKind.INC, TokenKind.DEC)) {
Token t = takeToken(); //consume INC/DEC Token t = takeToken(); //consume INC/DEC
if (t.getKind() == TokenKind.INC) { if (t.getKind() == TokenKind.INC) {
return new OpInc(toPos(t), true, expr); return new OpInc(t.startPos, t.endPos, true, expr);
} }
return new OpDec(toPos(t), true, expr); return new OpDec(t.startPos, t.endPos, true, expr);
} }
return expr; return expr;
} }
@ -326,21 +325,21 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
SpelNodeImpl expr = eatUnaryExpression(); SpelNodeImpl expr = eatUnaryExpression();
Assert.state(expr != null, "No node"); Assert.state(expr != null, "No node");
if (t.kind == TokenKind.NOT) { if (t.kind == TokenKind.NOT) {
return new OperatorNot(toPos(t), expr); return new OperatorNot(t.startPos, t.endPos, expr);
} }
if (t.kind == TokenKind.PLUS) { if (t.kind == TokenKind.PLUS) {
return new OpPlus(toPos(t), expr); return new OpPlus(t.startPos, t.endPos, expr);
} }
Assert.isTrue(t.kind == TokenKind.MINUS, "Minus token expected"); Assert.isTrue(t.kind == TokenKind.MINUS, "Minus token expected");
return new OpMinus(toPos(t), expr); return new OpMinus(t.startPos, t.endPos, expr);
} }
if (peekToken(TokenKind.INC, TokenKind.DEC)) { if (peekToken(TokenKind.INC, TokenKind.DEC)) {
Token t = takeToken(); Token t = takeToken();
SpelNodeImpl expr = eatUnaryExpression(); SpelNodeImpl expr = eatUnaryExpression();
if (t.getKind() == TokenKind.INC) { if (t.getKind() == TokenKind.INC) {
return new OpInc(toPos(t), false, expr); return new OpInc(t.startPos, t.endPos, false, expr);
} }
return new OpDec(toPos(t), false, expr); return new OpDec(t.startPos, t.endPos, false, expr);
} }
return eatPrimaryExpression(); return eatPrimaryExpression();
} }
@ -362,8 +361,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
if (start == null || nodes == null) { if (start == null || nodes == null) {
return start; return start;
} }
return new CompoundExpression(toPos(start.getStartPosition(), return new CompoundExpression(start.getStartPosition(), nodes.get(nodes.size() - 1).getEndPosition(),
nodes.get(nodes.size() - 1).getEndPosition()),
nodes.toArray(new SpelNodeImpl[0])); nodes.toArray(new SpelNodeImpl[0]));
} }
@ -424,12 +422,12 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
SpelNodeImpl[] args = maybeEatMethodArgs(); SpelNodeImpl[] args = maybeEatMethodArgs();
if (args == null) { if (args == null) {
push(new VariableReference(functionOrVariableName.stringValue(), push(new VariableReference(functionOrVariableName.stringValue(),
toPos(t.startPos, functionOrVariableName.endPos))); t.startPos, functionOrVariableName.endPos));
return true; return true;
} }
push(new FunctionReference(functionOrVariableName.stringValue(), push(new FunctionReference(functionOrVariableName.stringValue(),
toPos(t.startPos, functionOrVariableName.endPos), args)); t.startPos, functionOrVariableName.endPos, args));
return true; return true;
} }
@ -548,11 +546,10 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
BeanReference beanReference; BeanReference beanReference;
if (beanRefToken.getKind() == TokenKind.FACTORY_BEAN_REF) { if (beanRefToken.getKind() == TokenKind.FACTORY_BEAN_REF) {
String beanNameString = String.valueOf(TokenKind.FACTORY_BEAN_REF.tokenChars) + beanName; String beanNameString = String.valueOf(TokenKind.FACTORY_BEAN_REF.tokenChars) + beanName;
beanReference = new BeanReference( beanReference = new BeanReference(beanRefToken.startPos, beanNameToken.endPos, beanNameString);
toPos(beanRefToken.startPos, beanNameToken.endPos), beanNameString);
} }
else { else {
beanReference = new BeanReference(toPos(beanNameToken), beanName); beanReference = new BeanReference(beanNameToken.startPos, beanNameToken.endPos, beanName);
} }
this.constructedNodes.push(beanReference); this.constructedNodes.push(beanReference);
return true; return true;
@ -571,7 +568,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
Token t = takeToken(); Token t = takeToken();
if (peekToken(TokenKind.RSQUARE)) { if (peekToken(TokenKind.RSQUARE)) {
// looks like 'T]' (T is map key) // looks like 'T]' (T is map key)
push(new PropertyOrFieldReference(false, t.stringValue(), toPos(t))); push(new PropertyOrFieldReference(false, t.stringValue(), t.startPos, t.endPos));
return true; return true;
} }
eatToken(TokenKind.LPAREN); eatToken(TokenKind.LPAREN);
@ -584,7 +581,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
dims++; dims++;
} }
eatToken(TokenKind.RPAREN); eatToken(TokenKind.RPAREN);
this.constructedNodes.push(new TypeReference(toPos(typeName), node, dims)); this.constructedNodes.push(new TypeReference(typeName.startPos, typeName.endPos, node, dims));
return true; return true;
} }
return false; return false;
@ -598,7 +595,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
return false; return false;
} }
nextToken(); nextToken();
this.constructedNodes.push(new NullLiteral(toPos(nullToken))); this.constructedNodes.push(new NullLiteral(nullToken.startPos, nullToken.endPos));
return true; return true;
} }
return false; return false;
@ -614,7 +611,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
SpelNodeImpl expr = eatExpression(); SpelNodeImpl expr = eatExpression();
Assert.state(expr != null, "No node"); Assert.state(expr != null, "No node");
eatToken(TokenKind.RSQUARE); eatToken(TokenKind.RSQUARE);
this.constructedNodes.push(new Projection(nullSafeNavigation, toPos(t), expr)); this.constructedNodes.push(new Projection(nullSafeNavigation, t.startPos, t.endPos, expr));
return true; return true;
} }
@ -631,12 +628,12 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
if (peekToken(TokenKind.RCURLY, true)) { if (peekToken(TokenKind.RCURLY, true)) {
// empty list '{}' // empty list '{}'
Assert.state(closingCurly != null, "No token"); Assert.state(closingCurly != null, "No token");
expr = new InlineList(toPos(t.startPos, closingCurly.endPos)); expr = new InlineList(t.startPos, closingCurly.endPos);
} }
else if (peekToken(TokenKind.COLON, true)) { else if (peekToken(TokenKind.COLON, true)) {
closingCurly = eatToken(TokenKind.RCURLY); closingCurly = eatToken(TokenKind.RCURLY);
// empty map '{:}' // empty map '{:}'
expr = new InlineMap(toPos(t.startPos, closingCurly.endPos)); expr = new InlineMap(t.startPos, closingCurly.endPos);
} }
else { else {
SpelNodeImpl firstExpression = eatExpression(); SpelNodeImpl firstExpression = eatExpression();
@ -648,7 +645,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
List<SpelNodeImpl> elements = new ArrayList<>(); List<SpelNodeImpl> elements = new ArrayList<>();
elements.add(firstExpression); elements.add(firstExpression);
closingCurly = eatToken(TokenKind.RCURLY); closingCurly = eatToken(TokenKind.RCURLY);
expr = new InlineList(toPos(t.startPos, closingCurly.endPos), elements.toArray(new SpelNodeImpl[0])); expr = new InlineList(t.startPos, closingCurly.endPos, elements.toArray(new SpelNodeImpl[0]));
} }
else if (peekToken(TokenKind.COMMA, true)) { // multi-item list else if (peekToken(TokenKind.COMMA, true)) { // multi-item list
List<SpelNodeImpl> elements = new ArrayList<>(); List<SpelNodeImpl> elements = new ArrayList<>();
@ -658,7 +655,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
} }
while (peekToken(TokenKind.COMMA, true)); while (peekToken(TokenKind.COMMA, true));
closingCurly = eatToken(TokenKind.RCURLY); closingCurly = eatToken(TokenKind.RCURLY);
expr = new InlineList(toPos(t.startPos, closingCurly.endPos), elements.toArray(new SpelNodeImpl[0])); expr = new InlineList(t.startPos, closingCurly.endPos, elements.toArray(new SpelNodeImpl[0]));
} }
else if (peekToken(TokenKind.COLON, true)) { // map! else if (peekToken(TokenKind.COLON, true)) { // map!
@ -671,7 +668,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
elements.add(eatExpression()); elements.add(eatExpression());
} }
closingCurly = eatToken(TokenKind.RCURLY); closingCurly = eatToken(TokenKind.RCURLY);
expr = new InlineMap(toPos(t.startPos, closingCurly.endPos), elements.toArray(new SpelNodeImpl[0])); expr = new InlineMap(t.startPos, closingCurly.endPos, elements.toArray(new SpelNodeImpl[0]));
} }
else { else {
throw internalException(t.startPos, SpelMessage.OOD); throw internalException(t.startPos, SpelMessage.OOD);
@ -690,7 +687,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
SpelNodeImpl expr = eatExpression(); SpelNodeImpl expr = eatExpression();
Assert.state(expr != null, "No node"); Assert.state(expr != null, "No node");
eatToken(TokenKind.RSQUARE); eatToken(TokenKind.RSQUARE);
this.constructedNodes.push(new Indexer(toPos(t), expr)); this.constructedNodes.push(new Indexer(t.startPos, t.endPos, expr));
return true; return true;
} }
@ -703,17 +700,17 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
nextToken(); nextToken();
SpelNodeImpl expr = eatExpression(); SpelNodeImpl expr = eatExpression();
if (expr == null) { if (expr == null) {
throw internalException(toPos(t), SpelMessage.MISSING_SELECTION_EXPRESSION); throw internalException(t.startPos, SpelMessage.MISSING_SELECTION_EXPRESSION);
} }
eatToken(TokenKind.RSQUARE); eatToken(TokenKind.RSQUARE);
if (t.kind == TokenKind.SELECT_FIRST) { if (t.kind == TokenKind.SELECT_FIRST) {
this.constructedNodes.push(new Selection(nullSafeNavigation, Selection.FIRST, toPos(t), expr)); this.constructedNodes.push(new Selection(nullSafeNavigation, Selection.FIRST, t.startPos, t.endPos, expr));
} }
else if (t.kind == TokenKind.SELECT_LAST) { else if (t.kind == TokenKind.SELECT_LAST) {
this.constructedNodes.push(new Selection(nullSafeNavigation, Selection.LAST, toPos(t), expr)); this.constructedNodes.push(new Selection(nullSafeNavigation, Selection.LAST, t.startPos, t.endPos, expr));
} }
else { else {
this.constructedNodes.push(new Selection(nullSafeNavigation, Selection.ALL, toPos(t), expr)); this.constructedNodes.push(new Selection(nullSafeNavigation, Selection.ALL, t.startPos, t.endPos, expr));
} }
return true; return true;
} }
@ -728,7 +725,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
while (isValidQualifiedId(node)) { while (isValidQualifiedId(node)) {
nextToken(); nextToken();
if (node.kind != TokenKind.DOT) { if (node.kind != TokenKind.DOT) {
qualifiedIdPieces.add(new Identifier(node.stringValue(), toPos(node))); qualifiedIdPieces.add(new Identifier(node.stringValue(), node.startPos, node.endPos));
} }
node = peekToken(); node = peekToken();
} }
@ -739,8 +736,8 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
throw internalException(node.startPos, SpelMessage.NOT_EXPECTED_TOKEN, throw internalException(node.startPos, SpelMessage.NOT_EXPECTED_TOKEN,
"qualified ID", node.getKind().toString().toLowerCase()); "qualified ID", node.getKind().toString().toLowerCase());
} }
int pos = toPos(qualifiedIdPieces.getFirst().getStartPosition(), qualifiedIdPieces.getLast().getEndPosition()); return new QualifiedIdentifier(qualifiedIdPieces.getFirst().getStartPosition(),
return new QualifiedIdentifier(pos, qualifiedIdPieces.toArray(new SpelNodeImpl[0])); qualifiedIdPieces.getLast().getEndPosition(), qualifiedIdPieces.toArray(new SpelNodeImpl[0]));
} }
private boolean isValidQualifiedId(@Nullable Token node) { private boolean isValidQualifiedId(@Nullable Token node) {
@ -764,12 +761,12 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
if (args == null) { if (args == null) {
// property // property
push(new PropertyOrFieldReference(nullSafeNavigation, methodOrPropertyName.stringValue(), push(new PropertyOrFieldReference(nullSafeNavigation, methodOrPropertyName.stringValue(),
toPos(methodOrPropertyName))); methodOrPropertyName.startPos, methodOrPropertyName.endPos));
return true; return true;
} }
// method reference // method reference
push(new MethodReference(nullSafeNavigation, methodOrPropertyName.stringValue(), push(new MethodReference(nullSafeNavigation, methodOrPropertyName.stringValue(),
toPos(methodOrPropertyName), args)); methodOrPropertyName.startPos, methodOrPropertyName.endPos, args));
// TODO what is the end position for a method reference? the name or the last arg? // TODO what is the end position for a method reference? the name or the last arg?
return true; return true;
} }
@ -784,7 +781,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
// It looks like a constructor reference but is NEW being used as a map key? // It looks like a constructor reference but is NEW being used as a map key?
if (peekToken(TokenKind.RSQUARE)) { if (peekToken(TokenKind.RSQUARE)) {
// looks like 'NEW]' (so NEW used as map key) // looks like 'NEW]' (so NEW used as map key)
push(new PropertyOrFieldReference(false, newToken.stringValue(), toPos(newToken))); push(new PropertyOrFieldReference(false, newToken.stringValue(), newToken.startPos, newToken.endPos));
return true; return true;
} }
SpelNodeImpl possiblyQualifiedConstructorName = eatPossiblyQualifiedId(); SpelNodeImpl possiblyQualifiedConstructorName = eatPossiblyQualifiedId();
@ -805,14 +802,14 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
if (maybeEatInlineListOrMap()) { if (maybeEatInlineListOrMap()) {
nodes.add(pop()); nodes.add(pop());
} }
push(new ConstructorReference(toPos(newToken), push(new ConstructorReference(newToken.startPos, newToken.endPos,
dimensions.toArray(new SpelNodeImpl[0]), nodes.toArray(new SpelNodeImpl[0]))); dimensions.toArray(new SpelNodeImpl[0]), nodes.toArray(new SpelNodeImpl[0])));
} }
else { else {
// regular constructor invocation // regular constructor invocation
eatConstructorArgs(nodes); eatConstructorArgs(nodes);
// TODO correct end position? // TODO correct end position?
push(new ConstructorReference(toPos(newToken), nodes.toArray(new SpelNodeImpl[0]))); push(new ConstructorReference(newToken.startPos, newToken.endPos, nodes.toArray(new SpelNodeImpl[0])));
} }
return true; return true;
} }
@ -841,31 +838,31 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
return false; return false;
} }
if (t.kind == TokenKind.LITERAL_INT) { if (t.kind == TokenKind.LITERAL_INT) {
push(Literal.getIntLiteral(t.stringValue(), toPos(t), 10)); push(Literal.getIntLiteral(t.stringValue(), t.startPos, t.endPos, 10));
} }
else if (t.kind == TokenKind.LITERAL_LONG) { else if (t.kind == TokenKind.LITERAL_LONG) {
push(Literal.getLongLiteral(t.stringValue(), toPos(t), 10)); push(Literal.getLongLiteral(t.stringValue(), t.startPos, t.endPos, 10));
} }
else if (t.kind == TokenKind.LITERAL_HEXINT) { else if (t.kind == TokenKind.LITERAL_HEXINT) {
push(Literal.getIntLiteral(t.stringValue(), toPos(t), 16)); push(Literal.getIntLiteral(t.stringValue(), t.startPos, t.endPos, 16));
} }
else if (t.kind == TokenKind.LITERAL_HEXLONG) { else if (t.kind == TokenKind.LITERAL_HEXLONG) {
push(Literal.getLongLiteral(t.stringValue(), toPos(t), 16)); push(Literal.getLongLiteral(t.stringValue(), t.startPos, t.endPos, 16));
} }
else if (t.kind == TokenKind.LITERAL_REAL) { else if (t.kind == TokenKind.LITERAL_REAL) {
push(Literal.getRealLiteral(t.stringValue(), toPos(t), false)); push(Literal.getRealLiteral(t.stringValue(), t.startPos, t.endPos, false));
} }
else if (t.kind == TokenKind.LITERAL_REAL_FLOAT) { else if (t.kind == TokenKind.LITERAL_REAL_FLOAT) {
push(Literal.getRealLiteral(t.stringValue(), toPos(t), true)); push(Literal.getRealLiteral(t.stringValue(), t.startPos, t.endPos, true));
} }
else if (peekIdentifierToken("true")) { else if (peekIdentifierToken("true")) {
push(new BooleanLiteral(t.stringValue(), toPos(t), true)); push(new BooleanLiteral(t.stringValue(), t.startPos, t.endPos, true));
} }
else if (peekIdentifierToken("false")) { else if (peekIdentifierToken("false")) {
push(new BooleanLiteral(t.stringValue(), toPos(t), false)); push(new BooleanLiteral(t.stringValue(), t.startPos, t.endPos, false));
} }
else if (t.kind == TokenKind.LITERAL_STRING) { else if (t.kind == TokenKind.LITERAL_STRING) {
push(new StringLiteral(t.stringValue(), toPos(t), t.stringValue())); push(new StringLiteral(t.stringValue(), t.startPos, t.endPos, t.stringValue()));
} }
else { else {
return false; return false;
@ -1040,17 +1037,8 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
} }
} }
private InternalParseException internalException(int pos, SpelMessage message, Object... inserts) { private InternalParseException internalException(int startPos, SpelMessage message, Object... inserts) {
return new InternalParseException(new SpelParseException(this.expressionString, pos, message, inserts)); return new InternalParseException(new SpelParseException(this.expressionString, startPos, message, inserts));
}
private int toPos(Token t) {
// Compress the start and end of a token into a single int
return (t.startPos << 16) + t.endPos;
}
private int toPos(int start, int end) {
return (start << 16) + end;
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -23,7 +23,6 @@ import java.util.Locale;
import org.junit.Test; import org.junit.Test;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.support.GenericConversionService; import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
@ -45,16 +44,16 @@ public class OpPlusTests {
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void test_emptyOperands() { public void test_emptyOperands() {
new OpPlus(-1); new OpPlus(-1, -1);
} }
@Test(expected = SpelEvaluationException.class) @Test(expected = SpelEvaluationException.class)
public void test_unaryPlusWithStringLiteral() { public void test_unaryPlusWithStringLiteral() {
ExpressionState expressionState = new ExpressionState(new StandardEvaluationContext()); ExpressionState expressionState = new ExpressionState(new StandardEvaluationContext());
StringLiteral str = new StringLiteral("word", -1, "word"); StringLiteral str = new StringLiteral("word", -1, -1, "word");
OpPlus o = new OpPlus(-1, str); OpPlus o = new OpPlus(-1, -1, str);
o.getValueInternal(expressionState); o.getValueInternal(expressionState);
} }
@ -63,8 +62,8 @@ public class OpPlusTests {
ExpressionState expressionState = new ExpressionState(new StandardEvaluationContext()); ExpressionState expressionState = new ExpressionState(new StandardEvaluationContext());
{ {
RealLiteral realLiteral = new RealLiteral("123.00", -1, 123.0); RealLiteral realLiteral = new RealLiteral("123.00", -1, -1, 123.0);
OpPlus o = new OpPlus(-1, realLiteral); OpPlus o = new OpPlus(-1, -1, realLiteral);
TypedValue value = o.getValueInternal(expressionState); TypedValue value = o.getValueInternal(expressionState);
assertEquals(Double.class, value.getTypeDescriptor().getObjectType()); assertEquals(Double.class, value.getTypeDescriptor().getObjectType());
@ -73,8 +72,8 @@ public class OpPlusTests {
} }
{ {
IntLiteral intLiteral = new IntLiteral("123", -1, 123); IntLiteral intLiteral = new IntLiteral("123", -1, -1, 123);
OpPlus o = new OpPlus(-1, intLiteral); OpPlus o = new OpPlus(-1, -1, intLiteral);
TypedValue value = o.getValueInternal(expressionState); TypedValue value = o.getValueInternal(expressionState);
assertEquals(Integer.class, value.getTypeDescriptor().getObjectType()); assertEquals(Integer.class, value.getTypeDescriptor().getObjectType());
@ -83,8 +82,8 @@ public class OpPlusTests {
} }
{ {
LongLiteral longLiteral = new LongLiteral("123", -1, 123L); LongLiteral longLiteral = new LongLiteral("123", -1, -1, 123L);
OpPlus o = new OpPlus(-1, longLiteral); OpPlus o = new OpPlus(-1, -1, longLiteral);
TypedValue value = o.getValueInternal(expressionState); TypedValue value = o.getValueInternal(expressionState);
assertEquals(Long.class, value.getTypeDescriptor().getObjectType()); assertEquals(Long.class, value.getTypeDescriptor().getObjectType());
@ -98,9 +97,9 @@ public class OpPlusTests {
ExpressionState expressionState = new ExpressionState(new StandardEvaluationContext()); ExpressionState expressionState = new ExpressionState(new StandardEvaluationContext());
{ {
RealLiteral n1 = new RealLiteral("123.00", -1, 123.0); RealLiteral n1 = new RealLiteral("123.00", -1, -1, 123.0);
RealLiteral n2 = new RealLiteral("456.00", -1, 456.0); RealLiteral n2 = new RealLiteral("456.00", -1, -1, 456.0);
OpPlus o = new OpPlus(-1, n1, n2); OpPlus o = new OpPlus(-1, -1, n1, n2);
TypedValue value = o.getValueInternal(expressionState); TypedValue value = o.getValueInternal(expressionState);
assertEquals(Double.class, value.getTypeDescriptor().getObjectType()); assertEquals(Double.class, value.getTypeDescriptor().getObjectType());
@ -109,9 +108,9 @@ public class OpPlusTests {
} }
{ {
LongLiteral n1 = new LongLiteral("123", -1, 123L); LongLiteral n1 = new LongLiteral("123", -1, -1, 123L);
LongLiteral n2 = new LongLiteral("456", -1, 456L); LongLiteral n2 = new LongLiteral("456", -1, -1, 456L);
OpPlus o = new OpPlus(-1, n1, n2); OpPlus o = new OpPlus(-1, -1, n1, n2);
TypedValue value = o.getValueInternal(expressionState); TypedValue value = o.getValueInternal(expressionState);
assertEquals(Long.class, value.getTypeDescriptor().getObjectType()); assertEquals(Long.class, value.getTypeDescriptor().getObjectType());
@ -120,9 +119,9 @@ public class OpPlusTests {
} }
{ {
IntLiteral n1 = new IntLiteral("123", -1, 123); IntLiteral n1 = new IntLiteral("123", -1, -1, 123);
IntLiteral n2 = new IntLiteral("456", -1, 456); IntLiteral n2 = new IntLiteral("456", -1, -1, 456);
OpPlus o = new OpPlus(-1, n1, n2); OpPlus o = new OpPlus(-1, -1, n1, n2);
TypedValue value = o.getValueInternal(expressionState); TypedValue value = o.getValueInternal(expressionState);
assertEquals(Integer.class, value.getTypeDescriptor().getObjectType()); assertEquals(Integer.class, value.getTypeDescriptor().getObjectType());
@ -135,9 +134,9 @@ public class OpPlusTests {
public void test_binaryPlusWithStringOperands() { public void test_binaryPlusWithStringOperands() {
ExpressionState expressionState = new ExpressionState(new StandardEvaluationContext()); ExpressionState expressionState = new ExpressionState(new StandardEvaluationContext());
StringLiteral n1 = new StringLiteral("\"foo\"", -1, "\"foo\""); StringLiteral n1 = new StringLiteral("\"foo\"", -1, -1, "\"foo\"");
StringLiteral n2 = new StringLiteral("\"bar\"", -1, "\"bar\""); StringLiteral n2 = new StringLiteral("\"bar\"", -1, -1, "\"bar\"");
OpPlus o = new OpPlus(-1, n1, n2); OpPlus o = new OpPlus(-1, -1, n1, n2);
TypedValue value = o.getValueInternal(expressionState); TypedValue value = o.getValueInternal(expressionState);
assertEquals(String.class, value.getTypeDescriptor().getObjectType()); assertEquals(String.class, value.getTypeDescriptor().getObjectType());
@ -149,9 +148,9 @@ public class OpPlusTests {
public void test_binaryPlusWithLeftStringOperand() { public void test_binaryPlusWithLeftStringOperand() {
ExpressionState expressionState = new ExpressionState(new StandardEvaluationContext()); ExpressionState expressionState = new ExpressionState(new StandardEvaluationContext());
StringLiteral n1 = new StringLiteral("\"number is \"", -1, "\"number is \""); StringLiteral n1 = new StringLiteral("\"number is \"", -1, -1, "\"number is \"");
LongLiteral n2 = new LongLiteral("123", -1, 123); LongLiteral n2 = new LongLiteral("123", -1, -1, 123);
OpPlus o = new OpPlus(-1, n1, n2); OpPlus o = new OpPlus(-1, -1, n1, n2);
TypedValue value = o.getValueInternal(expressionState); TypedValue value = o.getValueInternal(expressionState);
assertEquals(String.class, value.getTypeDescriptor().getObjectType()); assertEquals(String.class, value.getTypeDescriptor().getObjectType());
@ -163,9 +162,9 @@ public class OpPlusTests {
public void test_binaryPlusWithRightStringOperand() { public void test_binaryPlusWithRightStringOperand() {
ExpressionState expressionState = new ExpressionState(new StandardEvaluationContext()); ExpressionState expressionState = new ExpressionState(new StandardEvaluationContext());
LongLiteral n1 = new LongLiteral("123", -1, 123); LongLiteral n1 = new LongLiteral("123", -1, -1, 123);
StringLiteral n2 = new StringLiteral("\" is a number\"", -1, "\" is a number\""); StringLiteral n2 = new StringLiteral("\" is a number\"", -1, -1, "\" is a number\"");
OpPlus o = new OpPlus(-1, n1, n2); OpPlus o = new OpPlus(-1, -1, n1, n2);
TypedValue value = o.getValueInternal(expressionState); TypedValue value = o.getValueInternal(expressionState);
assertEquals(String.class, value.getTypeDescriptor().getObjectType()); assertEquals(String.class, value.getTypeDescriptor().getObjectType());
@ -175,16 +174,14 @@ public class OpPlusTests {
@Test @Test
public void test_binaryPlusWithTime_ToString() { public void test_binaryPlusWithTime_ToString() {
ExpressionState expressionState = new ExpressionState(new StandardEvaluationContext()); ExpressionState expressionState = new ExpressionState(new StandardEvaluationContext());
Time time = new Time(new Date().getTime()); Time time = new Time(new Date().getTime());
VariableReference var = new VariableReference("timeVar", -1); VariableReference var = new VariableReference("timeVar", -1, -1);
var.setValue(expressionState, time); var.setValue(expressionState, time);
StringLiteral n2 = new StringLiteral("\" is now\"", -1, "\" is now\""); StringLiteral n2 = new StringLiteral("\" is now\"", -1, -1, "\" is now\"");
OpPlus o = new OpPlus(-1, var, n2); OpPlus o = new OpPlus(-1, -1, var, n2);
TypedValue value = o.getValueInternal(expressionState); TypedValue value = o.getValueInternal(expressionState);
assertEquals(String.class, value.getTypeDescriptor().getObjectType()); assertEquals(String.class, value.getTypeDescriptor().getObjectType());
@ -194,29 +191,22 @@ public class OpPlusTests {
@Test @Test
public void test_binaryPlusWithTimeConverted() { public void test_binaryPlusWithTimeConverted() {
SimpleDateFormat format = new SimpleDateFormat("hh :--: mm :--: ss", Locale.ENGLISH);
final SimpleDateFormat format = new SimpleDateFormat("hh :--: mm :--: ss", Locale.ENGLISH);
GenericConversionService conversionService = new GenericConversionService(); GenericConversionService conversionService = new GenericConversionService();
conversionService.addConverter(new Converter<Time, String>() { conversionService.addConverter(Time.class, String.class, format::format);
@Override
public String convert(Time source) {
return format.format(source);
}
});
StandardEvaluationContext evaluationContextConverter = new StandardEvaluationContext(); StandardEvaluationContext evaluationContextConverter = new StandardEvaluationContext();
evaluationContextConverter.setTypeConverter(new StandardTypeConverter(conversionService)); evaluationContextConverter.setTypeConverter(new StandardTypeConverter(conversionService));
ExpressionState expressionState = new ExpressionState(evaluationContextConverter); ExpressionState expressionState = new ExpressionState(evaluationContextConverter);
Time time = new Time(new Date().getTime()); Time time = new Time(new Date().getTime());
VariableReference var = new VariableReference("timeVar", -1); VariableReference var = new VariableReference("timeVar", -1, -1);
var.setValue(expressionState, time); var.setValue(expressionState, time);
StringLiteral n2 = new StringLiteral("\" is now\"", -1, "\" is now\""); StringLiteral n2 = new StringLiteral("\" is now\"", -1, -1, "\" is now\"");
OpPlus o = new OpPlus(-1, var, n2); OpPlus o = new OpPlus(-1, -1, var, n2);
TypedValue value = o.getValueInternal(expressionState); TypedValue value = o.getValueInternal(expressionState);
assertEquals(String.class, value.getTypeDescriptor().getObjectType()); assertEquals(String.class, value.getTypeDescriptor().getObjectType());