1 package net.sf.saxon.expr; 2 3 import net.sf.saxon.om.Item; 4 import net.sf.saxon.om.SequenceIterator; 5 import net.sf.saxon.sort.AtomicComparer; 6 import net.sf.saxon.sort.CodepointCollator; 7 import net.sf.saxon.trans.DynamicError; 8 import net.sf.saxon.trans.StaticError; 9 import net.sf.saxon.trans.XPathException; 10 import net.sf.saxon.type.AtomicType; 11 import net.sf.saxon.type.ItemType; 12 import net.sf.saxon.type.Type; 13 import net.sf.saxon.type.ValidationException; 14 import net.sf.saxon.value.*; 15 import net.sf.saxon.functions.Position; 16 17 import java.util.Comparator ; 18 19 20 25 26 public class GeneralComparison extends BinaryExpression { 27 28 protected int singletonOperator; 29 protected AtomicComparer comparer; 30 31 38 39 public GeneralComparison(Expression p0, int op, Expression p1) { 40 super(p0, op, p1); 41 singletonOperator = getSingletonOperator(op); 42 } 43 44 47 48 public int computeCardinality() { 49 return StaticProperty.EXACTLY_ONE; 50 } 51 52 57 58 public Expression typeCheck(StaticContext env, ItemType contextItemType) throws XPathException { 59 60 operand0 = operand0.typeCheck(env, contextItemType); 61 operand1 = operand1.typeCheck(env, contextItemType); 62 63 65 if (operand0 == EmptySequence.getInstance() || operand1 == EmptySequence.getInstance()) { 66 return BooleanValue.FALSE; 67 } 68 69 71 Optimizer opt = env.getConfiguration().getOptimizer(); 72 operand0 = ExpressionTool.unsorted(opt, operand0, false); 73 operand1 = ExpressionTool.unsorted(opt, operand1, false); 74 75 SequenceType atomicType = SequenceType.ATOMIC_SEQUENCE; 76 77 RoleLocator role0 = new RoleLocator(RoleLocator.BINARY_EXPR, Token.tokens[operator], 0, null); 78 role0.setSourceLocator(this); 79 operand0 = TypeChecker.staticTypeCheck(operand0, atomicType, false, role0, env); 80 81 RoleLocator role1 = new RoleLocator(RoleLocator.BINARY_EXPR, Token.tokens[operator], 1, null); 82 role1.setSourceLocator(this); 83 operand1 = TypeChecker.staticTypeCheck(operand1, atomicType, false, role1, env); 84 85 ItemType t0 = operand0.getItemType(); 86 ItemType t1 = operand1.getItemType(); 87 88 int c0 = operand0.getCardinality(); 89 int c1 = operand1.getCardinality(); 90 91 if (t0 == Type.ANY_ATOMIC_TYPE || t0 == Type.UNTYPED_ATOMIC_TYPE || 92 t1 == Type.ANY_ATOMIC_TYPE || t1 == Type.UNTYPED_ATOMIC_TYPE) { 93 } else { 95 int pt0 = t0.getPrimitiveType(); 96 int pt1 = t1.getPrimitiveType(); 97 if (!Type.isComparable(pt0, pt1)) { 98 StaticError err = new StaticError("Cannot compare " + t0.toString(env.getNamePool()) + 99 " to " + t1.toString(env.getNamePool())); 100 err.setErrorCode("XPTY0004"); 101 err.setIsTypeError(true); 102 throw err; 103 } 104 } 105 106 if (c0 == StaticProperty.EXACTLY_ONE && 107 c1 == StaticProperty.EXACTLY_ONE && 108 t0 != Type.ANY_ATOMIC_TYPE && 109 t1 != Type.ANY_ATOMIC_TYPE) { 110 111 114 Expression e0 = operand0; 115 Expression e1 = operand1; 116 117 if (t0 == Type.UNTYPED_ATOMIC_TYPE) { 118 if (t1 == Type.UNTYPED_ATOMIC_TYPE) { 119 e0 = new CastExpression(operand0, Type.STRING_TYPE, false); 120 adoptChildExpression(e0); 121 e1 = new CastExpression(operand1, Type.STRING_TYPE, false); 122 adoptChildExpression(e1); 123 } else if (Type.isSubType(t1, Type.NUMBER_TYPE)) { 124 e0 = new CastExpression(operand0, Type.DOUBLE_TYPE, false); 125 adoptChildExpression(e0); 126 } else { 127 e0 = new CastExpression(operand0, (AtomicType)t1, false); 128 adoptChildExpression(e0); 129 } 130 } else if (t1 == Type.UNTYPED_ATOMIC_TYPE) { 131 if (Type.isSubType(t0, Type.NUMBER_TYPE)) { 132 e1 = new CastExpression(operand1, Type.DOUBLE_TYPE, false); 133 adoptChildExpression(e1); 134 } else { 135 e1 = new CastExpression(operand1, (AtomicType)t0, false); 136 adoptChildExpression(e1); 137 } 138 } 139 140 ValueComparison vc = new ValueComparison(e0, singletonOperator, e1); 141 ExpressionTool.copyLocationInfo(this, vc); 142 vc.setParentExpression(getParentExpression()); 143 return vc.simplify(env).typeCheck(env, contextItemType); 144 } 145 146 Comparator comp = env.getCollation(env.getDefaultCollationName()); 147 if (comp == null) { 148 comp = CodepointCollator.getInstance(); 149 } 150 comparer = new AtomicComparer(comp, env.getConfiguration()); 151 152 154 if (!Cardinality.allowsMany(c0) && !Cardinality.allowsMany(c1)) { 155 156 158 SingletonComparison sc = new SingletonComparison(operand0, singletonOperator, operand1); 159 ExpressionTool.copyLocationInfo(this, sc); 160 sc.setParentExpression(getParentExpression()); 161 sc.setComparator(comparer, env.getConfiguration()); 162 return sc.typeCheck(env, contextItemType); 163 } 164 165 167 if (!Cardinality.allowsMany(c0)) { 168 169 GeneralComparison mc = getInverseComparison(); 172 ExpressionTool.copyLocationInfo(this, mc); 173 mc.setParentExpression(getParentExpression()); 174 mc.comparer = comparer; 175 return mc.typeCheck(env, contextItemType); 176 } 177 178 180 186 187 if (operator != Token.EQUALS && operator != Token.NE && 188 (Type.isSubType(t0, Type.NUMBER_TYPE) || Type.isSubType(t1, Type.NUMBER_TYPE))) { 189 190 Expression e0 = operand0; 191 if (!Type.isSubType(t0, Type.NUMBER_TYPE)) { 192 RoleLocator role = new RoleLocator(RoleLocator.BINARY_EXPR, Token.tokens[operator], 0, null); 193 role.setSourceLocator(this); 194 e0 = TypeChecker.staticTypeCheck(e0, SequenceType.NUMERIC_SEQUENCE, false, role, env); 195 } 196 Expression e1 = operand1; 197 if (!Type.isSubType(t1, Type.NUMBER_TYPE)) { 198 RoleLocator role = new RoleLocator(RoleLocator.BINARY_EXPR, Token.tokens[operator], 1, null); 199 role.setSourceLocator(this); 200 e1 = TypeChecker.staticTypeCheck(e1, SequenceType.NUMERIC_SEQUENCE, false, role, env); 201 } 202 MinimaxComparison mc = new MinimaxComparison(e0, operator, e1); 203 ExpressionTool.copyLocationInfo(this, mc); 204 mc.setParentExpression(getParentExpression()); 205 return mc.typeCheck(env, contextItemType); 206 207 } 208 209 210 212 if ((operand0 instanceof Value) && (operand1 instanceof Value)) { 213 return (AtomicValue)evaluateItem(null); 214 } 215 216 return this; 217 } 218 219 220 225 226 public Expression optimize(Optimizer opt, StaticContext env, ItemType contextItemType) throws XPathException { 227 228 operand0 = operand0.optimize(opt, env, contextItemType); 229 operand1 = operand1.optimize(opt, env, contextItemType); 230 231 233 if (operand0 == EmptySequence.getInstance() || operand1 == EmptySequence.getInstance()) { 234 return BooleanValue.FALSE; 235 } 236 237 239 operand0 = ExpressionTool.unsorted(opt, operand0, false); 240 operand1 = ExpressionTool.unsorted(opt, operand1, false); 241 242 ItemType t0 = operand0.getItemType(); 243 ItemType t1 = operand1.getItemType(); 244 245 int c0 = operand0.getCardinality(); 246 int c1 = operand1.getCardinality(); 247 248 if (c0 == StaticProperty.EXACTLY_ONE && 249 c1 == StaticProperty.EXACTLY_ONE && 250 t0 != Type.ANY_ATOMIC_TYPE && 251 t1 != Type.ANY_ATOMIC_TYPE) { 252 253 256 Expression e0 = operand0; 257 Expression e1 = operand1; 258 259 if (t0 == Type.UNTYPED_ATOMIC_TYPE) { 260 if (t1 == Type.UNTYPED_ATOMIC_TYPE) { 261 e0 = new CastExpression(operand0, Type.STRING_TYPE, false); 262 adoptChildExpression(e0); 263 e1 = new CastExpression(operand1, Type.STRING_TYPE, false); 264 adoptChildExpression(e1); 265 } else if (Type.isSubType(t1, Type.NUMBER_TYPE)) { 266 e0 = new CastExpression(operand0, Type.DOUBLE_TYPE, false); 267 adoptChildExpression(e0); 268 } else { 269 e0 = new CastExpression(operand0, (AtomicType)t1, false); 270 adoptChildExpression(e0); 271 } 272 } else if (t1 == Type.UNTYPED_ATOMIC_TYPE) { 273 if (Type.isSubType(t0, Type.NUMBER_TYPE)) { 274 e1 = new CastExpression(operand1, Type.DOUBLE_TYPE, false); 275 adoptChildExpression(e1); 276 } else { 277 e1 = new CastExpression(operand1, (AtomicType)t0, false); 278 adoptChildExpression(e1); 279 } 280 } 281 282 ValueComparison vc = new ValueComparison(e0, singletonOperator, e1); 283 ExpressionTool.copyLocationInfo(this, vc); 284 vc.setParentExpression(getParentExpression()); 285 return vc.simplify(env).typeCheck(env, contextItemType).optimize(opt, env, contextItemType); 286 } 287 288 Comparator comp = env.getCollation(env.getDefaultCollationName()); 289 if (comp == null) { 290 comp = CodepointCollator.getInstance(); 291 } 292 comparer = new AtomicComparer(comp, env.getConfiguration()); 293 294 296 if (!Cardinality.allowsMany(c0) && !Cardinality.allowsMany(c1)) { 297 298 300 SingletonComparison sc = new SingletonComparison(operand0, singletonOperator, operand1); 301 ExpressionTool.copyLocationInfo(this, sc); 302 sc.setParentExpression(getParentExpression()); 303 sc.setComparator(comparer, env.getConfiguration()); 304 return sc.typeCheck(env, contextItemType).optimize(opt, env, contextItemType); 305 } 306 307 309 if (!Cardinality.allowsMany(c0)) { 310 311 GeneralComparison mc = getInverseComparison(); 313 ExpressionTool.copyLocationInfo(this, mc); 314 mc.setParentExpression(getParentExpression()); 315 mc.comparer = comparer; 316 return mc.optimize(opt, env, contextItemType); 317 } 318 319 321 322 if (operand0 instanceof RangeExpression && 323 Type.isSubType(operand1.getItemType(), Type.INTEGER_TYPE) && 324 !Cardinality.allowsMany(operand1.getCardinality())) { 325 Expression min = ((RangeExpression)operand0).operand0; 326 Expression max = ((RangeExpression)operand0).operand1; 327 if (operand1 instanceof Position) { 328 PositionRange pr = new PositionRange(min, max); 329 ExpressionTool.copyLocationInfo(this, pr); 330 pr.setParentExpression(getParentExpression()); 331 return pr; 332 } else { 333 IntegerRangeTest ir = new IntegerRangeTest(operand1, min, max); 334 ExpressionTool.copyLocationInfo(this, ir); 335 ir.setParentExpression(getParentExpression()); 336 return ir; 337 } 338 } 339 340 if (operand0 instanceof IntegerRange && 341 Type.isSubType(operand1.getItemType(), Type.INTEGER_TYPE) && 342 !Cardinality.allowsMany(operand1.getCardinality())) { 343 long min = ((IntegerRange)operand0).getStart(); 344 long max = ((IntegerRange)operand0).getEnd(); 345 if (operand1 instanceof Position) { 346 PositionRange pr = new PositionRange(new IntegerValue(min), new IntegerValue(max)); 347 ExpressionTool.copyLocationInfo(this, pr); 348 pr.setParentExpression(getParentExpression()); 349 return pr; 350 } else { 351 IntegerRangeTest ir = new IntegerRangeTest(operand1, new IntegerValue(min), new IntegerValue(max)); 352 ExpressionTool.copyLocationInfo(this, ir); 353 ir.setParentExpression(getParentExpression()); 354 return ir; 355 } 356 } 357 358 360 if ((operand0 instanceof Value) && (operand1 instanceof Value)) { 361 return (AtomicValue)evaluateItem(null); 362 } 363 364 return this; 365 } 366 367 368 374 375 public Item evaluateItem(XPathContext context) throws XPathException { 376 return BooleanValue.get(effectiveBooleanValue(context)); 377 } 378 379 385 386 public boolean effectiveBooleanValue(XPathContext context) throws XPathException { 387 388 try { 389 SequenceIterator iter1 = operand0.iterate(context); 390 SequenceIterator iter2 = operand1.iterate(context); 391 392 Value seq2 = SequenceExtent.makeSequenceExtent(iter2); 393 int count2 = seq2.getLength(); 395 396 if (count2 == 0) { 397 return false; 398 } 399 400 if (count2 == 1) { 401 AtomicValue s2 = (AtomicValue)seq2.itemAt(0); 402 while (true) { 403 AtomicValue s1 = (AtomicValue)iter1.next(); 404 if (s1 == null) { 405 break; 406 } 407 if (compare(s1, singletonOperator, s2, comparer, context)) { 408 return true; 409 } 410 } 411 return false; 412 } 413 414 while (true) { 415 AtomicValue s1 = (AtomicValue)iter1.next(); 416 if (s1 == null) { 417 break; 418 } 419 SequenceIterator e2 = seq2.iterate(null); 420 while (true) { 421 AtomicValue s2 = (AtomicValue)e2.next(); 422 if (s2 == null) { 423 break; 424 } 425 if (compare(s1, singletonOperator, s2, comparer, context)) { 426 return true; 427 } 428 } 429 } 430 431 return false; 432 } catch (DynamicError e) { 433 if (e.getXPathContext() == null) { 435 e.setXPathContext(context); 436 } 437 if (e.getLocator() == null) { 438 e.setLocator(this); 439 } 440 throw e; 441 } catch (ValidationException e) { 442 DynamicError err = new DynamicError(e); 443 err.setXPathContext(context); 444 if (e.getLineNumber() == -1) { 445 err.setLocator(this); 446 } else { 447 err.setLocator(e); 448 } 449 err.setErrorCode(e.getErrorCodeLocalPart()); 450 throw err; 451 } 452 453 } 454 455 458 459 protected static boolean compare(AtomicValue a1, 460 int operator, 461 AtomicValue a2, 462 AtomicComparer comparer, 463 XPathContext context) throws XPathException { 464 465 AtomicValue v1 = a1; 466 AtomicValue v2 = a2; 467 if (a1 instanceof UntypedAtomicValue) { 468 if (a2 instanceof NumericValue) { 469 v1 = a1.convert(Type.DOUBLE, context); 470 } else if (a2 instanceof UntypedAtomicValue) { 471 } else { 473 v1 = a1.convert(a2.getItemType().getPrimitiveType(), context); 474 } 475 } 476 if (a2 instanceof UntypedAtomicValue) { 477 if (a1 instanceof NumericValue) { 478 v2 = a2.convert(Type.DOUBLE, context); 479 } else if (a1 instanceof UntypedAtomicValue) { 480 } else { 482 v2 = a2.convert(a1.getItemType().getPrimitiveType(), context); 483 } 484 } 485 return ValueComparison.compare(v1, operator, v2, comparer); 486 487 } 488 489 494 495 public ItemType getItemType() { 496 return Type.BOOLEAN_TYPE; 497 } 498 499 502 503 private static int getSingletonOperator(int op) { 504 switch (op) { 505 case Token.EQUALS: 506 return Token.FEQ; 507 case Token.GE: 508 return Token.FGE; 509 case Token.NE: 510 return Token.FNE; 511 case Token.LT: 512 return Token.FLT; 513 case Token.GT: 514 return Token.FGT; 515 case Token.LE: 516 return Token.FLE; 517 default: 518 return op; 519 } 520 } 521 522 protected GeneralComparison getInverseComparison() { 523 return new GeneralComparison(operand1, Token.inverse(operator), operand0); 524 } 525 526 protected String displayOperator() { 527 return "many-to-many " + super.displayOperator(); 528 } 529 530 } 531 532 | Popular Tags |