Source code: com/tripi/asp/ArithmeticNode.java
1 /**
2 * ArrowHead ASP Server
3 * This is a source file for the ArrowHead ASP Server - an 100% Java
4 * VBScript interpreter and ASP server.
5 *
6 * For more information, see http://www.tripi.com/arrowhead
7 *
8 * Copyright (C) 2002 Terence Haddock
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 */
25 package com.tripi.asp;
26
27 import java.util.Calendar;
28 import java.util.Date;
29 import java.util.Vector;
30
31 import org.apache.log4j.Category;
32
33 /**
34 * ArithmenticNode handles arithmetic operations.
35 * Status of implementation:
36 * <ul>
37 * <li><b>+</b> Addition - Fully implemented.
38 * <li><b>and</b> - Fully implemented.
39 * <li><b>&</b> Concat - Fully implemented.
40 * <li><b>/</b> Division - Fully implemented.
41 * <li><b>eqv</b> - Fully implemented.
42 * <li><b>^</b> Exponent - Fully implemented.
43 * <li><b>imp</b> Logical implication - Fully implemented.
44 * <li><b>\</b> Integer division - Fully implemented.
45 * <li><b>is</b> object comparison - <B>TODO</b> Not implemented.
46 * <li><b>mod</b> modulus - Fully implemented.
47 * <li><b>*</b> multiply - Fully implemented.
48 * <li><b>-</b> negation - Fully implemented.
49 * <li><b>not</b> logical negation - Fully implemented.
50 * <li><b>or</b> logical or - Fully implemented.
51 *
52 * </ul>
53 *
54 * @author Terence Haddock
55 * @version 0.9
56 */
57 public class ArithmeticNode implements Node
58 {
59 /** Debugging class */
60 private Category DBG = Category.getInstance(ArithmeticNode.class.getName());
61
62 /** The plus operator. */
63 public static final int PLUS = 1;
64
65 /** The minus operator. */
66 public static final int MINUS = 2;
67
68 /** The multiplicative operator. */
69 public static final int MULT = 3;
70
71 /** The division operator. */
72 public static final int DIV = 4;
73
74 /** The integer division operator. */
75 public static final int INTDIV = 5;
76
77 /** The string concatenation operator. */
78 public static final int CONCAT = 6;
79
80 /** The equal operator. */
81 public static final int EQ = 7;
82
83 /** The greater than operator. */
84 public static final int GT = 8;
85
86 /** Less than operator */
87 public static final int LT = 9;
88
89 /** Not equal operator */
90 public static final int NE = 10;
91
92 /** Logical not operator */
93 public static final int NOT = 11;
94
95 /** Logical or operator */
96 public static final int OR = 12;
97
98 /** Logical and operator */
99 public static final int AND = 13;
100
101 /** Exponent (power) operator */
102 public static final int EXP = 14;
103
104 /** Logical equivalence operator */
105 public static final int EQV = 15;
106
107 /** Logical implication operator */
108 public static final int IMP = 16;
109
110 /** Modulus operator */
111 public static final int MOD = 17;
112
113 /** Logical exclusive or operator */
114 public static final int XOR = 18;
115
116 /** Greater than or equal operator */
117 public static final int GE = 19;
118
119 /** Less than or equal operator */
120 public static final int LE = 20;
121
122 /** Object equivilence */
123 public static final int IS = 21;
124
125 /** Left side of expression */
126 Object left;
127
128 /** Right side of expression */
129 Object right;
130
131 /** Type of expression */
132 int type;
133
134 /**
135 * Constructor for creating a new arithmetic node.
136 * @param left Left side of expression.
137 * @param right Right side of expression
138 * @param type type of expression
139 */
140 public ArithmeticNode(Object left, Object right, int type)
141 {
142 this.left = left;
143 this.right = right;
144 this.type = type;
145 }
146
147 /**
148 * Gets this operation type.
149 */
150 public int getType()
151 {
152 return type;
153 }
154
155 /**
156 * Gets the left hand side.
157 * @return left hand side
158 */
159 public Object getLeft()
160 {
161 return left;
162 }
163
164 /**
165 * Gets the right hand side.
166 * @return right hand side.
167 */
168 public Object getRight()
169 {
170 return right;
171 }
172
173 /**
174 * Dumps this node to standard out.
175 * @throws AspException if an error occurs.
176 * @see Node#dump()
177 */
178 public void dump() throws AspException
179 {
180 System.out.print("(");
181 if (left instanceof Node) {
182 ((Node)left).dump();
183 } else {
184 System.out.print(left);
185 }
186 switch(type)
187 {
188 case PLUS:System.out.print(" + ");break;
189 case MINUS:System.out.print(" - ");break;
190 case MULT:System.out.print(" * ");break;
191 case DIV:System.out.print(" / ");break;
192 case INTDIV:System.out.print(" \\ ");break;
193 case CONCAT:System.out.print(" & ");break;
194 case EQ:System.out.print(" = ");break;
195 case GT:System.out.print(" > ");break;
196 case LT:System.out.print(" < ");break;
197 case NE:System.out.print(" <> ");break;
198 case NOT:System.out.print(" NOT ");break;
199 case OR:System.out.print(" OR ");break;
200 case AND:System.out.print(" AND ");break;
201 case EXP:System.out.print(" ^ ");break;
202 case EQV:System.out.print(" EQV ");break;
203 case IMP:System.out.print(" IMP ");break;
204 case MOD:System.out.print(" MOD ");break;
205 case XOR:System.out.print(" XOR ");break;
206 case GE:System.out.print(" >= ");break;
207 case LE:System.out.print(" <= ");break;
208 }
209 if (right instanceof Node) {
210 ((Node)right).dump();
211 } else {
212 System.out.print(right);
213 }
214 System.out.print(")");
215 }
216
217 /**
218 * Prepares this node for execution.
219 *
220 * @param context Global context
221 * @throws AspException if an error occurs.
222 * @see Node#prepare(AspContext)
223 */
224 public void prepare(AspContext context) throws AspException
225 {
226 /* Nothing to do, the arguments to expressions should
227 * in general not need prepared.
228 */
229 }
230
231 /**
232 * Dumps this node to standard out.
233 * @param context AspContext of expression
234 * @return evaluated value of this expression
235 * @throws AspException if an error occurs.
236 * @see Node#execute(AspContext)
237 */
238 public Object execute(AspContext context) throws AspException
239 {
240 Object avalObj=null, bvalObj=null;
241 if (left != null) {
242 avalObj = ((Node)left).execute(context);
243 avalObj = Types.dereference(avalObj);
244 }
245 if (right != null) {
246 bvalObj = ((Node)right).execute(context);
247 bvalObj = Types.dereference(bvalObj);
248 }
249 switch(type)
250 {
251 case PLUS: {
252 if (Constants.nullNode.equals(avalObj) ||
253 Constants.nullNode.equals(bvalObj)) {
254 return Constants.nullNode;
255 } else if (Types.isDate(avalObj) && Types.isDate(bvalObj))
256 {
257 AspDate aVal = Types.coerceToDate(avalObj);
258 AspDate bVal = Types.coerceToDate(bvalObj);
259
260 return doDateAdd(aVal, bVal);
261 } else if (Types.isDate(avalObj)) {
262 final IdentNode dateAddIdent = new IdentNode("dateadd");
263
264 AspDate aval = Types.coerceToDate(avalObj);
265 Integer bval = Types.coerceToInteger(bvalObj);
266
267 AbstractFunctionNode func = (AbstractFunctionNode)
268 context.getValue(dateAddIdent);
269 Vector values = new Vector();
270 values.add("y");
271 values.add(bval);
272 values.add(aval);
273 return func.execute(values, context);
274 } else if (Types.isDate(bvalObj)) {
275 final IdentNode dateAddIdent = new IdentNode("dateadd");
276
277 Integer aval = Types.coerceToInteger(avalObj);
278 AspDate bval = Types.coerceToDate(bvalObj);
279
280 AbstractFunctionNode func = (AbstractFunctionNode)
281 context.getValue(dateAddIdent);
282 Vector values = new Vector();
283 values.add("y");
284 values.add(aval);
285 values.add(bval);
286 return func.execute(values, context);
287 } else if (avalObj instanceof String &&
288 bvalObj instanceof String) {
289 String aval = Types.coerceToString(avalObj);
290 String bval = Types.coerceToString(bvalObj);
291 return aval + bval;
292 } else if (avalObj instanceof Double ||
293 bvalObj instanceof Double) {
294 Double aval = Types.coerceToDouble(avalObj);
295 Double bval = Types.coerceToDouble(bvalObj);
296 return new Double(aval.doubleValue() + bval.doubleValue());
297 } else {
298 Integer aval = Types.coerceToInteger(avalObj);
299 Integer bval = Types.coerceToInteger(bvalObj);
300 return new Integer(aval.intValue() + bval.intValue());
301 }
302 }
303 case MINUS: {
304 if (avalObj instanceof NullNode || bvalObj instanceof NullNode)
305 {
306 return Constants.nullNode;
307 } else if (Types.isDate(avalObj) && Types.isDate(bvalObj)) {
308 final IdentNode dateDiffIdent = new IdentNode("datediff");
309
310 AspDate aval = Types.coerceToDate(avalObj);
311 AspDate bval = Types.coerceToDate(bvalObj);
312
313 AbstractFunctionNode func = (AbstractFunctionNode)
314 context.getValue(dateDiffIdent);
315 Vector values = new Vector();
316 values.add("y");
317 values.add(bval);
318 values.add(aval);
319 return func.execute(values, context);
320 } else if (Types.isDate(avalObj)) {
321 final IdentNode dateAddIdent = new IdentNode("dateadd");
322
323 AspDate aval = Types.coerceToDate(avalObj);
324 Integer bval = new Integer(-Types.coerceToInteger(bvalObj)
325 .intValue());
326
327 AbstractFunctionNode func = (AbstractFunctionNode)
328 context.getValue(dateAddIdent);
329 Vector values = new Vector();
330 values.add("y");
331 values.add(bval);
332 values.add(aval);
333 return func.execute(values, context);
334 } else if (avalObj instanceof Double || bvalObj instanceof Double) {
335 final Double zero = new Double(0);
336 Double aval;
337 if (avalObj == null) {
338 aval = zero;
339 } else {
340 aval = Types.coerceToDouble(avalObj);
341 }
342 Double bval = Types.coerceToDouble(bvalObj);
343 return new Double(aval.doubleValue() - bval.doubleValue());
344 } else {
345 final Integer zero = new Integer(0);
346 Integer aval;
347 if (avalObj == null) {
348 aval = zero;
349 } else {
350 aval = Types.coerceToInteger(avalObj);
351 }
352 Integer bval = Types.coerceToInteger(bvalObj);
353 return new Integer(aval.intValue() - bval.intValue());
354 }
355 }
356 case MULT: {
357 if (Constants.nullNode.equals(avalObj) ||
358 Constants.nullNode.equals(bvalObj))
359 {
360 return Constants.nullNode;
361 } else if (avalObj instanceof Double ||
362 bvalObj instanceof Double) {
363 Double aval = Types.coerceToDouble(avalObj);
364 Double bval = Types.coerceToDouble(bvalObj);
365 return new Double(aval.doubleValue() * bval.doubleValue());
366 } else {
367 Integer aval = Types.coerceToInteger(avalObj);
368 Integer bval = Types.coerceToInteger(bvalObj);
369 return new Integer(aval.intValue() * bval.intValue());
370 }
371 }
372 case DIV: {
373 if (Constants.nullNode.equals(avalObj) ||
374 Constants.nullNode.equals(bvalObj))
375 return Constants.nullNode;
376 Double aval = Types.coerceToDouble(avalObj);
377 Double bval = Types.coerceToDouble(bvalObj);
378 return new Double(aval.doubleValue() / bval.doubleValue());
379 }
380 case INTDIV: {
381 if (Constants.nullNode.equals(avalObj) ||
382 Constants.nullNode.equals(bvalObj))
383 return Constants.nullNode;
384 Integer aval = Types.coerceToInteger(avalObj);
385 Integer bval = Types.coerceToInteger(bvalObj);
386 return new Integer(aval.intValue() / bval.intValue());
387 }
388 case IS: {
389 if (avalObj instanceof NothingNode)
390 {
391 if (bvalObj instanceof NothingNode)
392 return new Boolean(true);
393 if (!(bvalObj instanceof JavaObjectNode))
394 {
395 throw new AspException("Object expected");
396 }
397 return new Boolean(false);
398 }
399 if (bvalObj instanceof NothingNode)
400 {
401 if (!(avalObj instanceof JavaObjectNode))
402 {
403 throw new AspException("Object expected");
404 }
405 return new Boolean(false);
406 }
407 if (!(avalObj instanceof JavaObjectNode) ||
408 !(bvalObj instanceof JavaObjectNode))
409 {
410 throw new AspException("Object expected");
411 }
412 Object avalSubObj = ((JavaObjectNode)avalObj).getSubObject();
413 Object bvalSubObj = ((JavaObjectNode)bvalObj).getSubObject();
414 return new Boolean(avalSubObj == bvalSubObj);
415 }
416 case MOD: {
417 if (Constants.nullNode.equals(avalObj) ||
418 Constants.nullNode.equals(bvalObj)) {
419 return Constants.nullNode;
420 } else if (avalObj instanceof Integer &&
421 bvalObj instanceof Integer) {
422 Integer aval = Types.coerceToInteger(avalObj);
423 Integer bval = Types.coerceToInteger(bvalObj);
424 return new Integer(aval.intValue() % bval.intValue());
425 } else {
426 double aval = Types.coerceToDouble(avalObj).doubleValue();
427 double bval = Types.coerceToDouble(bvalObj).doubleValue();
428 return new Integer((int)(Math.round(aval) %
429 Math.round(bval)));
430 }
431 }
432 case CONCAT: {
433 if (Constants.nullNode.equals(avalObj) &&
434 Constants.nullNode.equals(bvalObj))
435 return Constants.nullNode;
436 String aval = Types.coerceToString(avalObj);
437 String bval = Types.coerceToString(bvalObj);
438 return aval + bval;
439 }
440 case EQ:
441 if (Constants.nullNode.equals(avalObj) ||
442 Constants.nullNode.equals(bvalObj))
443 return Constants.nullNode;
444 return new Boolean(compare(avalObj, bvalObj) == 0);
445 case GT:
446 if (Constants.nullNode.equals(avalObj) ||
447 Constants.nullNode.equals(bvalObj))
448 return Constants.nullNode;
449 return new Boolean(compare(avalObj, bvalObj) > 0);
450 case GE:
451 if (Constants.nullNode.equals(avalObj) ||
452 Constants.nullNode.equals(bvalObj))
453 return Constants.nullNode;
454 return new Boolean(compare(avalObj, bvalObj) >= 0);
455 case LT:
456 if (Constants.nullNode.equals(avalObj) ||
457 Constants.nullNode.equals(bvalObj))
458 return Constants.nullNode;
459 return new Boolean(compare(avalObj, bvalObj) < 0);
460 case LE:
461 if (Constants.nullNode.equals(avalObj) ||
462 Constants.nullNode.equals(bvalObj))
463 return Constants.nullNode;
464 return new Boolean(compare(avalObj, bvalObj) <= 0);
465 case NE:
466 if (Constants.nullNode.equals(avalObj) ||
467 Constants.nullNode.equals(bvalObj))
468 return Constants.nullNode;
469 return new Boolean(compare(avalObj, bvalObj) != 0);
470 case NOT: {
471 if (Constants.nullNode.equals(avalObj))
472 return Constants.nullNode;
473 if (Types.isNumber(avalObj))
474 {
475 int bval = Types.coerceToInteger(avalObj).intValue();
476 return new Integer((-bval)-1);
477 } else {
478 Boolean bval = Types.coerceToBoolean(avalObj);
479 return new Boolean(!bval.booleanValue());
480 }
481 }
482 case OR: {
483 if (Constants.nullNode.equals(avalObj) &&
484 Constants.nullNode.equals(bvalObj))
485 return Constants.nullNode;
486 if (Types.isNumber(avalObj) || Types.isNumber(bvalObj))
487 return doNumericOr(avalObj, bvalObj);
488 else
489 return doLogicalOr(avalObj, bvalObj);
490 }
491 case AND: {
492 if (Constants.nullNode.equals(avalObj) &&
493 Constants.nullNode.equals(bvalObj))
494 return Constants.nullNode;
495 if (Types.isNumber(avalObj) || Types.isNumber(bvalObj))
496 return doNumericAnd(avalObj, bvalObj);
497 else
498 return doLogicalAnd(avalObj, bvalObj);
499 }
500 case XOR: {
501 if (Constants.nullNode.equals(avalObj) ||
502 Constants.nullNode.equals(bvalObj))
503 return Constants.nullNode;
504 if (Types.isNumber(avalObj) || Types.isNumber(bvalObj))
505 return doNumericXor(avalObj, bvalObj);
506 else
507 return doLogicalXor(avalObj, bvalObj);
508 }
509 case EQV: {
510 if (Constants.nullNode.equals(avalObj) ||
511 Constants.nullNode.equals(bvalObj))
512 return Constants.nullNode;
513 Boolean aval = Types.coerceToBoolean(avalObj);
514 Boolean bval = Types.coerceToBoolean(bvalObj);
515 return new Boolean(aval.booleanValue()==bval.booleanValue());
516 }
517 case IMP: {
518 boolean aval, bval;
519
520 if (Constants.nullNode.equals(avalObj)) {
521 if (Constants.nullNode.equals(bvalObj))
522 return Constants.nullNode;
523 bval = Types.coerceToBoolean(bvalObj).booleanValue();
524 if (bval) return new Boolean(true);
525 return Constants.nullNode;
526 } else if (Constants.nullNode.equals(bvalObj)) {
527 aval = Types.coerceToBoolean(avalObj).booleanValue();
528 if (!aval) return new Boolean(true);
529 return Constants.nullNode;
530 }
531
532 aval = Types.coerceToBoolean(avalObj).booleanValue();
533 bval = Types.coerceToBoolean(bvalObj).booleanValue();
534 if (!aval || aval && bval) {
535 return new Boolean(true);
536 } else {
537 return new Boolean(false);
538 }
539 }
540 case EXP: {
541 if (Constants.nullNode.equals(avalObj) ||
542 Constants.nullNode.equals(bvalObj))
543 return Constants.nullNode;
544 Double aval = Types.coerceToDouble(avalObj);
545 Double bval = Types.coerceToDouble(bvalObj);
546 return new Double(Math.pow(aval.doubleValue(), bval.doubleValue()));
547 }
548 }
549 throw new AspException("Unknown operator type: " + type);
550 }
551
552 /**
553 * Internal function to perform a logical AND operation.
554 * @param avalObj left hand side, expected to be of type boolean or NULL
555 * @param bvalObj right hand side, expected to be of type boolean or NULL
556 * @return result of logical and
557 */
558 private Object doLogicalAnd(Object avalObj, Object bvalObj)
559 throws AspException
560 {
561 boolean aval;
562 boolean bval;
563 if (Constants.nullNode.equals(bvalObj))
564 {
565 bvalObj = avalObj;
566 avalObj = Constants.nullNode;
567 }
568 if (Constants.nullNode.equals(avalObj))
569 {
570 bval = Types.coerceToBoolean(bvalObj).booleanValue();
571 if (!bval) return new Boolean(false);
572 return Constants.nullNode;
573 }
574 aval = Types.coerceToBoolean(avalObj).booleanValue();
575 bval = Types.coerceToBoolean(bvalObj).booleanValue();
576 return new Boolean(aval&&bval);
577 }
578
579 /**
580 * Internal function to perform a numeric AND operation.
581 * @param avalObj left hand side, expected to be of type boolean or NULL
582 * @param bvalObj right hand side, expected to be of type boolean or NULL
583 * @return result of logical and
584 */
585 private Object doNumericAnd(Object avalObj, Object bvalObj)
586 throws AspException
587 {
588 int aval;
589 int bval;
590 if (Constants.nullNode.equals(bvalObj))
591 {
592 bvalObj = avalObj;
593 avalObj = Constants.nullNode;
594 }
595 if (Constants.nullNode.equals(avalObj))
596 {
597 bval = Types.coerceToInteger(bvalObj).intValue();
598 if (bval == 0) return new Integer(0);
599 return Constants.nullNode;
600 }
601 aval = Types.coerceToInteger(avalObj).intValue();
602 bval = Types.coerceToInteger(bvalObj).intValue();
603 return new Integer(aval&bval);
604 }
605
606 /**
607 * Internal function to perform a logical OR operation.
608 * @param avalObj left hand side, expected to be of type boolean or NULL
609 * @param bvalObj right hand side, expected to be of type boolean or NULL
610 * @return result of logical and
611 */
612 private Object doLogicalOr(Object avalObj, Object bvalObj)
613 throws AspException
614 {
615 boolean aval;
616 boolean bval;
617 if (Constants.nullNode.equals(bvalObj))
618 {
619 bvalObj = avalObj;
620 avalObj = Constants.nullNode;
621 }
622 if (Constants.nullNode.equals(avalObj))
623 {
624 bval = Types.coerceToBoolean(bvalObj).booleanValue();
625 if (bval) return new Boolean(true);
626 return Constants.nullNode;
627 }
628 aval = Types.coerceToBoolean(avalObj).booleanValue();
629 bval = Types.coerceToBoolean(bvalObj).booleanValue();
630 return new Boolean(aval||bval);
631 }
632
633 /**
634 * Internal function to perform a numeric OR operation.
635 * @param avalObj left hand side, expected to be of type boolean or NULL
636 * @param bvalObj right hand side, expected to be of type boolean or NULL
637 * @return result of logical and
638 */
639 private Object doNumericOr(Object avalObj, Object bvalObj)
640 throws AspException
641 {
642 int aval;
643 int bval;
644 if (Constants.nullNode.equals(bvalObj))
645 {
646 bvalObj = avalObj;
647 avalObj = Constants.nullNode;
648 }
649 if (Constants.nullNode.equals(avalObj))
650 {
651 bval = Types.coerceToInteger(bvalObj).intValue();
652 if (bval != 0) return bvalObj;
653 return Constants.nullNode;
654 }
655 aval = Types.coerceToInteger(avalObj).intValue();
656 bval = Types.coerceToInteger(bvalObj).intValue();
657 return new Integer(aval|bval);
658 }
659
660 /**
661 * Internal function to perform a logical XOR operation.
662 * @param avalObj left hand side, expected to be of type boolean or NULL
663 * @param bvalObj right hand side, expected to be of type boolean or NULL
664 * @return result of logical and
665 */
666 private Object doLogicalXor(Object avalObj, Object bvalObj)
667 throws AspException
668 {
669 boolean aval;
670 boolean bval;
671 aval = Types.coerceToBoolean(avalObj).booleanValue();
672 bval = Types.coerceToBoolean(bvalObj).booleanValue();
673 return new Boolean(aval^bval);
674 }
675
676 /**
677 * Internal function to perform a numeric XOR operation.
678 * @param avalObj left hand side, expected to be of type boolean or NULL
679 * @param bvalObj right hand side, expected to be of type boolean or NULL
680 * @return result of logical and
681 */
682 private Object doNumericXor(Object avalObj, Object bvalObj)
683 throws AspException
684 {
685 int aval;
686 int bval;
687 aval = Types.coerceToInteger(avalObj).intValue();
688 bval = Types.coerceToInteger(bvalObj).intValue();
689 return new Integer(aval^bval);
690 }
691
692 /**
693 * Internal procedure used to compare any two expressions.
694 * @param aObj object A
695 * @param bObj object B
696 * @return comparison of this expression, positive if a > b,
697 * negative if a < b, zero if a = b.
698 * @throws AspException if an error occurs.
699 * @see Node#execute(AspContext)
700 */
701 protected int compare(Object aObj, Object bObj) throws AspException
702 {
703 if (DBG.isDebugEnabled()) {
704 DBG.debug("Compare aObj: " + aObj);
705 if (aObj != null) DBG.debug("aObj type: " + aObj.getClass());
706 DBG.debug("Compare bObj: " + bObj);
707 if (bObj != null) DBG.debug("bObj type: " + bObj.getClass());
708 }
709 if (aObj instanceof UndefinedValueNode)
710 {
711 if (bObj instanceof UndefinedValueNode) return 0;
712 if (bObj instanceof Integer)
713 {
714 int bInt = Types.coerceToInteger(bObj).intValue();
715 return -bInt;
716 } else {
717 String bStr = Types.coerceToString(bObj);
718 if (bStr.equals("0")) return 0;
719 return -bStr.compareTo("");
720 }
721 }
722 if (bObj instanceof UndefinedValueNode)
723 {
724 if (aObj instanceof Integer)
725 {
726 int aInt = Types.coerceToInteger(aObj).intValue();
727 return aInt;
728 } else {
729 String aStr = Types.coerceToString(aObj);
730 if (aStr.equals("0")) return 0;
731 return aStr.compareTo("");
732 }
733 }
734 if (Types.isDate(aObj) && Types.isDate(bObj))
735 {
736 Date aDate = ((AspDate)aObj).toDate();
737 Date bDate = ((AspDate)bObj).toDate();
738 return aDate.compareTo(bDate);
739 }
740 if (aObj instanceof Integer && bObj instanceof Integer)
741 {
742 int aInt = Types.coerceToInteger(aObj).intValue();
743 int bInt = Types.coerceToInteger(bObj).intValue();
744 if (aInt > bInt) return 1;
745 if (aInt < bInt) return -1;
746 return 0;
747 }
748 if ((aObj instanceof Double || aObj instanceof Integer) &&
749 (bObj instanceof Double || bObj instanceof Integer))
750 {
751 double aDoub = Types.coerceToDouble(aObj).doubleValue();
752 double bDoub = Types.coerceToDouble(bObj).doubleValue();
753 if (aDoub > bDoub) return 1;
754 if (aDoub < bDoub) return -1;
755 return 0;
756 }
757 String aStr = Types.coerceToString(aObj);
758 String bStr = Types.coerceToString(bObj);
759 if (DBG.isDebugEnabled()) {
760 DBG.debug("\"" + aStr + "\"<=>\"" + bStr + "\"");
761 }
762 return aStr.compareTo(bStr);
763 }
764
765 /**
766 * This function performs an add function with two dates.
767 * @param aDate left hand value
768 * @param bDate right hand value
769 * @return new date value
770 */
771 private static AspDate doDateAdd(AspDate aDate, AspDate bDate)
772 throws AspException
773 {
774 if (aDate.hasTime() && bDate.hasDate()) {
775 AspDate tmp = aDate;
776 aDate = bDate;
777 bDate = tmp;
778 }
779 if (bDate.hasDate())
780 throw new AspNotImplementedException("Date + Date");
781 if (!bDate.hasTime())
782 throw new AspNotImplementedException("Date + Date");
783 Calendar cal = aDate.toCalendar();
784 cal.add(Calendar.HOUR, bDate.getHour());
785 cal.add(Calendar.MINUTE, bDate.getMinute());
786 cal.add(Calendar.SECOND, bDate.getSecond());
787 return new AspDate(cal, true, true);
788 }
789 };
790