1 4 package gnu.xquery.util; 5 import gnu.mapping.*; 6 import gnu.kawa.functions.NumberCompare; 7 import gnu.math.*; 8 import gnu.expr.*; 9 import gnu.kawa.xml.*; 10 import gnu.bytecode.ClassType; 11 12 13 14 public class Compare extends Procedure2 implements CanInline 15 { 16 static final int RESULT_GRT = 1; 17 static final int RESULT_EQU = 0; 18 static final int RESULT_LSS = -1; 19 static final int RESULT_NAN = -2; 20 static final int RESULT_NEQ = -3; 21 22 static final int TRUE_IF_GRT = 1 << (RESULT_GRT + 3); 24 static final int TRUE_IF_EQU = 1 << (RESULT_EQU + 3); 25 static final int TRUE_IF_LSS = 1 << (RESULT_LSS + 3); 26 static final int TRUE_IF_NAN = 1 << (RESULT_NAN + 3); 27 static final int TRUE_IF_NEQ = 1 << (RESULT_NEQ + 3); 28 static final int VALUE_COMPARISON = 1 << 5; 29 static final int LENIENT_COMPARISON = 1 << 6; 30 static final int LENIENT_EQ = (TRUE_IF_EQU|LENIENT_COMPARISON); 31 32 int flags; 33 34 public static Compare make(String name, int flags) 35 { 36 Compare proc = new Compare(); 37 proc.setName(name); 38 proc.flags = flags; 39 return proc; 40 } 41 42 58 59 public static boolean apply(int flags, Object arg1, Object arg2, 60 NamedCollator collator) 61 { 62 if (arg1 instanceof Values) 63 { 64 Values values1 = (Values) arg1; 65 int index = 0; 66 for (;;) 67 { 68 int next = values1.nextDataIndex(index); 69 if (next < 0) 70 return false; 71 if (apply(flags, values1.getPosNext(index << 1), arg2, collator)) 72 return true; 73 index = next; 74 } 75 } 76 if (arg2 instanceof Values) 77 { 78 Values values2 = (Values) arg2; 79 int index = 0; 80 for (;;) 81 { 82 int next = values2.nextDataIndex(index); 83 if (next < 0) 84 return false; 85 if (apply(flags, arg1, values2.getPosNext(index << 1), collator)) 86 return true; 87 index = next; 88 } 89 } 90 return atomicCompare(flags, 91 KNode.atomicValue(arg1), 92 KNode.atomicValue(arg2), 93 collator); 94 } 95 96 public static boolean equalityComparison (int flags) 97 { 98 return ((flags & TRUE_IF_GRT) != 0) == ((flags & TRUE_IF_LSS) != 0); 99 } 100 101 public static boolean atomicCompare(int flags, Object arg1, Object arg2, 102 NamedCollator collator) 103 { 104 if (arg1 instanceof UntypedAtomic) 105 { 106 String str = arg1.toString(); 107 if ((flags & VALUE_COMPARISON) != 0) 108 arg1 = str; 109 else if (arg2 instanceof DateTime) 110 arg1 = XTimeType.parseDateTime(str, ((DateTime) arg2).components()); 111 else if (arg2 instanceof Duration) 112 arg1 = Duration.parse(str, ((Duration) arg2).unit()); 113 else if (arg2 instanceof Number ) 114 arg1 = new DFloNum(str); 115 else if (arg2 instanceof Boolean ) 116 arg1 = XDataType.booleanType.valueOf(str); 117 else 118 arg1 = str; 119 } 120 if (arg2 instanceof UntypedAtomic) 121 { 122 String str = arg2.toString(); 123 if ((flags & VALUE_COMPARISON) != 0) 124 arg2 = str; 125 else if (arg1 instanceof DateTime) 126 arg2 = XTimeType.parseDateTime(str, ((DateTime) arg1).components()); 127 else if (arg1 instanceof Duration) 128 arg2 = Duration.parse(str, ((Duration) arg1).unit()); 129 else if (arg1 instanceof Number ) 130 arg2 = new DFloNum(str); 131 else if (arg1 instanceof Boolean ) 132 arg2 = XDataType.booleanType.valueOf(str); 133 else 134 arg2 = str; 135 } 136 int comp; 137 if (arg1 instanceof Number || arg2 instanceof Number ) 138 { 139 if (arg1 instanceof Duration) 140 { 141 if (! (arg2 instanceof Duration)) 142 comp = -3; 143 else 144 { 145 Duration d1 = (Duration) arg1; 146 Duration d2 = (Duration) arg2; 147 if ((d1.unit != d2.unit || d1.unit == Unit.duration) 148 && ! equalityComparison(flags)) 149 comp = -3; 150 else 151 comp = Duration.compare(d1, d2); 152 } 153 } 154 else if (arg1 instanceof DateTime) 155 { 156 if (! (arg2 instanceof DateTime)) 157 comp = -3; 158 else 159 { 160 DateTime d1 = (DateTime) arg1; 161 DateTime d2 = (DateTime) arg2; 162 int m1 = d1.components(); 163 int m2 = d2.components(); 164 if (m1 != m2) 165 comp = -3; 166 else if (! equalityComparison(flags) 167 && m1 != DateTime.TIME_MASK 168 && m1 != DateTime.DATE_MASK 169 && m1 != (DateTime.DATE_MASK|DateTime.TIME_MASK)) 170 comp = -3; 171 else 172 comp = DateTime.compare(d1, d2); 173 } 174 } 175 else if (arg2 instanceof Duration || arg2 instanceof DateTime) 176 comp = -3; 177 else 178 comp = NumberCompare.compare(arg1, arg2, false); 179 if (comp == -3 && (flags & LENIENT_COMPARISON) == 0) 180 throw new IllegalArgumentException ("values cannot be compared"); 181 return NumberCompare.checkCompareCode(comp, flags); 182 } 183 if (arg1 instanceof Symbol) 184 { 185 if (arg2 instanceof Symbol && equalityComparison(flags)) 186 comp = arg1.equals(arg2) ? 0 : -2; 187 else 188 comp = -3; 189 } 190 else if (arg1 instanceof Boolean ) 191 { 192 if (arg2 instanceof Boolean ) 193 { 194 boolean b1 = ((Boolean ) arg1).booleanValue(); 195 boolean b2 = ((Boolean ) arg2).booleanValue(); 196 comp = b1 == b2 ? 0 : b2 ? -1 : 1; 197 } 198 else 199 comp = -3; 200 } 201 else if (arg2 instanceof Boolean || arg2 instanceof Symbol) 202 comp = -3; 203 else 204 { 205 String str1 = arg1.toString(); 206 String str2 = arg2.toString(); 207 208 if (collator != null) 209 comp = collator.compare(str1, str2); 210 else 211 212 comp = str1.compareTo(str2); 213 comp = comp < 0 ? -1 : comp > 0 ? 1 : 0; 214 } 215 if (comp == -3 && (flags & LENIENT_COMPARISON) == 0) 216 throw new IllegalArgumentException ("values cannot be compared"); 217 return NumberCompare.checkCompareCode(comp, flags); 218 } 219 220 public Object apply2 (Object arg1, Object arg2) 221 { 222 if ((flags & VALUE_COMPARISON) != 0) 223 { 224 if (arg1 == null || arg1 == Values.empty) return arg1; 225 if (arg2 == null || arg2 == Values.empty) return arg2; 226 return atomicCompare(flags, 227 KNode.atomicValue(arg1), 228 KNode.atomicValue(arg2), 229 null) ? Boolean.TRUE: Boolean.FALSE; 230 } 231 return apply(flags, arg1, arg2, null) ? Boolean.TRUE : Boolean.FALSE; 232 } 233 234 public static final Compare $Eq = make("=",TRUE_IF_EQU); 235 public static final Compare $Ex$Eq 236 = make("!=",TRUE_IF_GRT|TRUE_IF_LSS|TRUE_IF_NAN|TRUE_IF_NEQ); 237 public static final Compare $Gr = make(">",TRUE_IF_GRT); 238 public static final Compare $Gr$Eq= make(">=",TRUE_IF_GRT|TRUE_IF_EQU); 239 public static final Compare $Ls = make("<",TRUE_IF_LSS); 240 public static final Compare $Ls$Eq= make("<=",TRUE_IF_LSS|TRUE_IF_EQU); 241 242 public static final Compare valEq = 243 make("eq",TRUE_IF_EQU|VALUE_COMPARISON); 244 public static final Compare valNe = 245 make("ne",TRUE_IF_GRT|TRUE_IF_LSS|TRUE_IF_NAN|TRUE_IF_NEQ|VALUE_COMPARISON); 246 public static final Compare valGt = 247 make("gt",TRUE_IF_GRT|VALUE_COMPARISON); 248 public static final Compare valGe = 249 make("ge",TRUE_IF_GRT|TRUE_IF_EQU|VALUE_COMPARISON); 250 public static final Compare valLt = 251 make("lt",TRUE_IF_LSS|VALUE_COMPARISON); 252 public static final Compare valLe = 253 make("le",TRUE_IF_LSS|TRUE_IF_EQU|VALUE_COMPARISON); 254 255 public Expression inline (ApplyExp exp, ExpWalker walker) 256 { 257 Expression folded = exp.inlineIfConstant(this, walker); 258 if (folded != exp) 259 return folded; 260 if ((flags & VALUE_COMPARISON) != 0) 261 { 262 } 263 else 264 { 265 exp = new ApplyExp(ClassType.make("gnu.xquery.util.Compare") 266 .getDeclaredMethod("apply", 4), 267 new Expression[] { new QuoteExp(IntNum.make(flags)), 268 exp.getArg(0), 269 exp.getArg(1), 270 QuoteExp.nullExp }); 271 } 272 if (exp.getTypeRaw() == null) 273 exp.setType(XDataType.booleanType); 274 return exp; 275 } 276 } 277 | Popular Tags |