Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

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 &gt; b,
697      *   negative if a &lt; 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