19 changed files with 1831 additions and 667 deletions
@ -0,0 +1,114 @@
@@ -0,0 +1,114 @@
|
||||
/* |
||||
* Copyright 2002-2012 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.expression.spel.ast; |
||||
|
||||
import org.springframework.expression.EvaluationException; |
||||
import org.springframework.expression.Operation; |
||||
import org.springframework.expression.TypedValue; |
||||
import org.springframework.expression.spel.ExpressionState; |
||||
import org.springframework.expression.spel.SpelEvaluationException; |
||||
import org.springframework.expression.spel.SpelMessage; |
||||
import org.springframework.util.Assert; |
||||
|
||||
/** |
||||
* Decrement operator. Can be used in a prefix or postfix form. This will throw |
||||
* appropriate exceptions if the operand in question does not support decrement. |
||||
* |
||||
* @author Andy Clement |
||||
* @since 3.2 |
||||
*/ |
||||
public class OpDec extends Operator { |
||||
|
||||
private boolean postfix; // false means prefix
|
||||
|
||||
public OpDec(int pos, boolean postfix, SpelNodeImpl... operands) { |
||||
super("--", pos, operands); |
||||
Assert.notEmpty(operands); |
||||
this.postfix = postfix; |
||||
} |
||||
|
||||
@Override |
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException { |
||||
SpelNodeImpl operand = getLeftOperand(); |
||||
|
||||
// The operand is going to be read and then assigned to, we don't want to evaluate it twice.
|
||||
|
||||
ValueRef lvalue = operand.getValueRef(state); |
||||
|
||||
final TypedValue operandTypedValue = lvalue.getValue();//operand.getValueInternal(state);
|
||||
final Object operandValue = operandTypedValue.getValue(); |
||||
TypedValue returnValue = operandTypedValue; |
||||
TypedValue newValue = null; |
||||
|
||||
if (operandValue instanceof Number) { |
||||
Number op1 = (Number) operandValue; |
||||
if (op1 instanceof Double) { |
||||
newValue = new TypedValue(op1.doubleValue() - 1.0d, operandTypedValue.getTypeDescriptor()); |
||||
} else if (op1 instanceof Float) { |
||||
newValue = new TypedValue(op1.floatValue() - 1.0f, operandTypedValue.getTypeDescriptor()); |
||||
} else if (op1 instanceof Long) { |
||||
newValue = new TypedValue(op1.longValue() - 1L, operandTypedValue.getTypeDescriptor()); |
||||
} else if (op1 instanceof Short) { |
||||
newValue = new TypedValue(op1.shortValue() - (short)1, operandTypedValue.getTypeDescriptor()); |
||||
} else { |
||||
newValue = new TypedValue(op1.intValue() - 1, operandTypedValue.getTypeDescriptor()); |
||||
} |
||||
} |
||||
if (newValue==null) { |
||||
try { |
||||
newValue = state.operate(Operation.SUBTRACT, returnValue.getValue(), 1); |
||||
} catch (SpelEvaluationException see) { |
||||
if (see.getMessageCode()==SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES) { |
||||
// This means the operand is not decrementable
|
||||
throw new SpelEvaluationException(operand.getStartPosition(),SpelMessage.OPERAND_NOT_DECREMENTABLE,operand.toStringAST()); |
||||
} else { |
||||
throw see; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// set the new value
|
||||
try { |
||||
lvalue.setValue(newValue.getValue()); |
||||
} catch (SpelEvaluationException see) { |
||||
// if unable to set the value the operand is not writable (e.g. 1-- )
|
||||
if (see.getMessageCode()==SpelMessage.SETVALUE_NOT_SUPPORTED) { |
||||
throw new SpelEvaluationException(operand.getStartPosition(),SpelMessage.OPERAND_NOT_DECREMENTABLE); |
||||
} else { |
||||
throw see; |
||||
} |
||||
} |
||||
|
||||
if (!postfix) { |
||||
// the return value is the new value, not the original value
|
||||
returnValue = newValue; |
||||
} |
||||
|
||||
return returnValue; |
||||
} |
||||
|
||||
@Override |
||||
public String toStringAST() { |
||||
return new StringBuilder().append(getLeftOperand().toStringAST()).append("--").toString(); |
||||
} |
||||
|
||||
@Override |
||||
public SpelNodeImpl getRightOperand() { |
||||
return null; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,112 @@
@@ -0,0 +1,112 @@
|
||||
/* |
||||
* Copyright 2002-2012 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.expression.spel.ast; |
||||
|
||||
import org.springframework.expression.EvaluationException; |
||||
import org.springframework.expression.Operation; |
||||
import org.springframework.expression.TypedValue; |
||||
import org.springframework.expression.spel.ExpressionState; |
||||
import org.springframework.expression.spel.SpelEvaluationException; |
||||
import org.springframework.expression.spel.SpelMessage; |
||||
import org.springframework.util.Assert; |
||||
|
||||
/** |
||||
* Increment operator. Can be used in a prefix or postfix form. This will throw |
||||
* appropriate exceptions if the operand in question does not support increment. |
||||
* |
||||
* @author Andy Clement |
||||
* @since 3.2 |
||||
*/ |
||||
public class OpInc extends Operator { |
||||
|
||||
private boolean postfix; // false means prefix
|
||||
|
||||
public OpInc(int pos, boolean postfix, SpelNodeImpl... operands) { |
||||
super("++", pos, operands); |
||||
Assert.notEmpty(operands); |
||||
this.postfix = postfix; |
||||
} |
||||
|
||||
@Override |
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException { |
||||
SpelNodeImpl operand = getLeftOperand(); |
||||
|
||||
ValueRef lvalue = operand.getValueRef(state); |
||||
|
||||
final TypedValue operandTypedValue = lvalue.getValue(); |
||||
final Object operandValue = operandTypedValue.getValue(); |
||||
TypedValue returnValue = operandTypedValue; |
||||
TypedValue newValue = null; |
||||
|
||||
if (operandValue instanceof Number) { |
||||
Number op1 = (Number) operandValue; |
||||
if (op1 instanceof Double) { |
||||
newValue = new TypedValue(op1.doubleValue() + 1.0d, operandTypedValue.getTypeDescriptor()); |
||||
} else if (op1 instanceof Float) { |
||||
newValue = new TypedValue(op1.floatValue() + 1.0f, operandTypedValue.getTypeDescriptor()); |
||||
} else if (op1 instanceof Long) { |
||||
newValue = new TypedValue(op1.longValue() + 1L, operandTypedValue.getTypeDescriptor()); |
||||
} else if (op1 instanceof Short) { |
||||
newValue = new TypedValue(op1.shortValue() + (short)1, operandTypedValue.getTypeDescriptor()); |
||||
} else { |
||||
newValue = new TypedValue(op1.intValue() + 1, operandTypedValue.getTypeDescriptor()); |
||||
} |
||||
} |
||||
if (newValue==null) { |
||||
try { |
||||
newValue = state.operate(Operation.ADD, returnValue.getValue(), 1); |
||||
} catch (SpelEvaluationException see) { |
||||
if (see.getMessageCode()==SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES) { |
||||
// This means the operand is not incrementable
|
||||
throw new SpelEvaluationException(operand.getStartPosition(),SpelMessage.OPERAND_NOT_INCREMENTABLE,operand.toStringAST()); |
||||
} else { |
||||
throw see; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// set the name value
|
||||
try { |
||||
lvalue.setValue(newValue.getValue()); |
||||
} catch (SpelEvaluationException see) { |
||||
// if unable to set the value the operand is not writable (e.g. 1++ )
|
||||
if (see.getMessageCode()==SpelMessage.SETVALUE_NOT_SUPPORTED) { |
||||
throw new SpelEvaluationException(operand.getStartPosition(),SpelMessage.OPERAND_NOT_INCREMENTABLE); |
||||
} else { |
||||
throw see; |
||||
} |
||||
} |
||||
|
||||
if (!postfix) { |
||||
// the return value is the new value, not the original value
|
||||
returnValue = newValue; |
||||
} |
||||
|
||||
return returnValue; |
||||
} |
||||
|
||||
@Override |
||||
public String toStringAST() { |
||||
return new StringBuilder().append(getLeftOperand().toStringAST()).append("++").toString(); |
||||
} |
||||
|
||||
@Override |
||||
public SpelNodeImpl getRightOperand() { |
||||
return null; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,107 @@
@@ -0,0 +1,107 @@
|
||||
/* |
||||
* Copyright 2002-2012 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.expression.spel.ast; |
||||
|
||||
import org.springframework.expression.TypedValue; |
||||
import org.springframework.expression.spel.SpelEvaluationException; |
||||
import org.springframework.expression.spel.SpelMessage; |
||||
|
||||
/** |
||||
* 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 |
||||
* incorrect duplication of operand evaluation. For example in 'list[index++]++' without 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 |
||||
* double increment index. |
||||
* |
||||
* @author Andy Clement |
||||
* @since 3.2 |
||||
*/ |
||||
public interface ValueRef { |
||||
|
||||
/** |
||||
* A ValueRef for the null value. |
||||
*/ |
||||
static class NullValueRef implements ValueRef { |
||||
|
||||
static NullValueRef instance = new NullValueRef(); |
||||
|
||||
public TypedValue getValue() { |
||||
return TypedValue.NULL; |
||||
} |
||||
|
||||
public void setValue(Object newValue) { |
||||
// The exception position '0' isn't right but the overhead of creating
|
||||
// instances of this per node (where the node is solely for error reporting)
|
||||
// would be unfortunate.
|
||||
throw new SpelEvaluationException(0,SpelMessage.NOT_ASSIGNABLE,"null"); |
||||
} |
||||
|
||||
public boolean isWritable() { |
||||
return false; |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* A ValueRef holder for a single value, which cannot be set. |
||||
*/ |
||||
static class TypedValueHolderValueRef implements ValueRef { |
||||
|
||||
private TypedValue typedValue; |
||||
private SpelNodeImpl node; // used only for error reporting
|
||||
|
||||
public TypedValueHolderValueRef(TypedValue typedValue,SpelNodeImpl node) { |
||||
this.typedValue = typedValue; |
||||
this.node = node; |
||||
} |
||||
|
||||
public TypedValue getValue() { |
||||
return typedValue; |
||||
} |
||||
|
||||
public void setValue(Object newValue) { |
||||
throw new SpelEvaluationException( |
||||
node.pos, SpelMessage.NOT_ASSIGNABLE, node.toStringAST()); |
||||
} |
||||
|
||||
public boolean isWritable() { |
||||
return false; |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Returns the value this ValueRef points to, it should not require expression |
||||
* component re-evaluation. |
||||
* @return the value |
||||
*/ |
||||
TypedValue getValue(); |
||||
|
||||
/** |
||||
* Sets the value this ValueRef points to, it should not require expression component |
||||
* re-evaluation. |
||||
* @param newValue the new value |
||||
*/ |
||||
void setValue(Object newValue); |
||||
|
||||
/** |
||||
* Indicates whether calling setValue(Object) is supported. |
||||
* @return true if setValue() is supported for this value reference. |
||||
*/ |
||||
boolean isWritable(); |
||||
} |
||||
Loading…
Reference in new issue