static class AddOverload extends Add {
private static final long serialVersionUID = 1L;
@Override
public Object add(Object param1, Object param2)
throws EvaluationException {
if(param1 instanceof String && param2 instanceof Number ) {
String res = ((String) param1) + ((Number) param2).intValue();
return res;
}
if(param1 instanceof Number && param2 instanceof String ) {
// uses a method of superclass which ensures the number is
// actually represents an integer throwing a parse exception if it is not.
int l = super.asStrictInt(0, param1);
String res = "" + l + ((String) param2);
return res;
}
return super.add(param1, param2);
}
}
Jep jep = new Jep();
jep.getOperatorTable().getAdd().setPFMC(new AddOverload());
// Testing
Node n1 = jep.parse("\"foo\" + 9");
Object res1 = jep.evaluate(n1);
assertEquals("foo9",res1);
Node n2 = jep.parse("8 + \"foo\"");
Object res2 = jep.evaluate(n2);
assertEquals("8foo",res2);
class AddOverload extends Add {
private static final long serialVersionUID = 1L;
@Override
public Object add(Object param1, Object param2)
throws EvaluationException {
if(param1 instanceof Number && param2 instanceof String ) {
// uses a method of superclass which ensures the number is
// actually represents an integer throwing a parse exception if it is not.
int l = super.asStrictInt(0, param1);
String res = "" + l + ((String) param2);
return res;
}
return super.add(param1, param2);
}
}
@Test
public void testAddOverload() throws JepException {
Jep jep = new Jep();
jep.getOperatorTable().getAdd().setPFMC(new AddOverload());
Node n1 = jep.parse("\"foo\" + 9");
try {
Object res1 = jep.evaluate(n1);
fail("Exception should be thrown");
}
catch(JepException e) {
}
Node n2 = jep.parse("8 + \"foo\"");
Object res2 = jep.evaluate(n2);
assertEquals("8foo",res2);
Node n3 = jep.parse("5*2-3+ \" Foo\"");
Object res3 = jep.evaluate(n3);
assertEquals("7 Foo",res3);
Node n4 = jep.parse("1+2+3+ \" Foo\"");
Object res4 = jep.evaluate(n4);
assertEquals("6 Foo",res4);
}
/**
* Class to perform the rearrangements
* (s + a) + b -> s + (a + b)
* (s + a) - b -> s + (a - b)
* where s is a string and a and b are any other nodes
*/
static class AddReAssociate extends DeepCopyVisitor {
private static final long serialVersionUID = 1L;
Operator add,sub;
public AddReAssociate(Jep j) {
super(j);
add = this.ot.getAdd();
sub = this.ot.getSubtract();
}
@Override
public Object visit(ASTOpNode node, Object data) throws JepException {
// process all the children of this node
Node[] children=visitChildren(node,data);
// this.jep.print(node); // print statements commented out, uncomment to see actions taken
// System.out.print('\t');
Operator baseop = node.getOperator();
if(baseop == add) { // test if we have an addition operator
Node lhs = children[0];
if(lhs instanceof ASTOpNode && lhs.getOperator() == add) { // Have + on lhs node
// check left of lhs
Node lhs_lhs = lhs.jjtGetChild(0);
if(lhs_lhs instanceof ASTConstant && lhs_lhs.getValue() instanceof String) { // is it a string
// now build (a+b)
Node new_rhs = nf.buildOperatorNode(add, lhs.jjtGetChild(1), children[1]);
// build s + (a+b)
Node new_node = nf.buildOperatorNode(add, lhs_lhs, new_rhs);
// jep.println(new_node);
return new_node;
}
}
}
if(baseop == sub) {
// Have + on lhs node
Node lhs = children[0];
if(lhs instanceof ASTOpNode && lhs.getOperator() == add) {
// check left of lhs
Node lhs_lhs = lhs.jjtGetChild(0);
if(lhs_lhs instanceof ASTConstant && lhs_lhs.getValue() instanceof String) {
// now build (a+b)
Node new_rhs = nf.buildOperatorNode(sub, lhs.jjtGetChild(1), children[1]);
Node new_node = nf.buildOperatorNode(add, lhs_lhs, new_rhs);
// jep.println(new_node);
return new_node;
}
}
}
// System.out.println();
// default action if the above not matched. Rebuild the node.
return nf.buildOperatorNode(baseop,children);
}
}
static class AddOverload extends Add {
private static final long serialVersionUID = 1L;
@Override public Object add(Object param1, Object param2) throws EvaluationException {
if(param1 instanceof Number && param2 instanceof String ) { // uses a method of superclass which ensures the number is // actually represents an integer throwing a parse exception if it is not. int l = super.asStrictInt(0, param1); String res = "" + l + ((String) param2); return res; }
if(param1 instanceof String && param2 instanceof Number ) {
// uses a method of superclass which ensures the number is // actually represents an integer throwing a parse exception if it is not.
int r = super.asStrictInt(1, param2); String res = ((String) param1) + r;
return res; } return super.add(param1, param2); } }
@Test public void testAddOverload() throws JepException {
Jep jep = new Jep();
jep.getOperatorTable().getAdd().setPFMC(new AddOverload()); AddReAssociate ara = new AddReAssociate(jep); jep.getPrintVisitor().setMode(PrintVisitor.FULL_BRACKET, true);
Node n1 = jep.parse("\"foo\" + 9");
Object res1 = jep.evaluate(n1); assertEquals("foo9",res1);
Node n2 = jep.parse("8 + \"foo\""); Object res2 = jep.evaluate(n2); assertEquals("8foo",res2);
Node n3 = jep.parse("5*2-3+ \" Foo\""); Object res3 = jep.evaluate(n3); assertEquals("7 Foo",res3);
Node n4 = jep.parse("1+2+3+ \" Foo\""); Object res4 = jep.evaluate(n4); assertEquals("6 Foo",res4);
Node n5 = jep.parse("\"Foo \"+1+2+3"); Node n5a = ara.visit(n5); Object res5 = jep.evaluate(n5a); assertEquals("Foo 6",res5); { Node n6 = jep.parse("\"Foo \"+1-2+3"); Node n6a = ara.visit(n6); Object res6 = jep.evaluate(n6a); assertEquals("Foo 2",res6); } { Node n6 = jep.parse("\"Foo \"+9-2-3"); Node n6a = ara.visit(n6); Object res6 = jep.evaluate(n6a); assertEquals("Foo 4",res6); } }
Node n6 = jep.parse("\"Foo \"+9-2-3"); Node n6a = ara.visit(n6); Object res6 = jep.evaluate(n6a);
Below is what I came up with to solve our specific concerns of mixing Integers, Double and Strings - it's you first example with a helper method/icing. There may be a cleaner way, but it's handling values in a way that met our acceptance criteria.
static class AddOverload extends Add {
private static final long serialVersionUID = 1L;
@Override
public Object add(Object param1, Object param2)
throws EvaluationException {
if(param1 instanceof String && param2 instanceof Number ) {
return ((String) param1) + getProperNumberFormat((Double)param2);
}
if(param1 instanceof Number && param2 instanceof String ) {
// uses a method of superclass which ensures the number is
// actually represents an integer throwing a parse exception if it is not.
return "" + getProperNumberFormat((Double)param1) + ((String) param2);
}
return super.add(param1, param2);
}
}
public static String getProperNumberFormat(Double rawNumber) {
if (rawNumber == Math.ceil(rawNumber)) {
return new Integer(rawNumber.intValue()).toString();
} else {
return rawNumber.toString();
}
}