1 package net.sf.saxon.expr; 2 3 import net.sf.saxon.functions.NumberFn; 4 import net.sf.saxon.functions.StringFn; 5 import net.sf.saxon.functions.SystemFunction; 6 import net.sf.saxon.style.StandardNames; 7 import net.sf.saxon.trans.StaticError; 8 import net.sf.saxon.trans.XPathException; 9 import net.sf.saxon.trans.DynamicError; 10 import net.sf.saxon.type.AnyItemType; 11 import net.sf.saxon.type.AtomicType; 12 import net.sf.saxon.type.ItemType; 13 import net.sf.saxon.type.Type; 14 import net.sf.saxon.value.*; 15 import net.sf.saxon.pattern.NoNodeTest; 16 17 import javax.xml.transform.SourceLocator ; 18 19 24 25 public final class TypeChecker { 26 27 private TypeChecker() {} 29 30 67 68 public static Expression staticTypeCheck(Expression supplied, 69 SequenceType req, 70 boolean backwardsCompatible, 71 RoleLocator role, 72 StaticContext env) 73 throws StaticError { 74 75 77 Expression exp = supplied; 78 79 ItemType reqItemType = req.getPrimaryType(); 80 int reqCard = req.getCardinality(); 81 boolean allowsMany = Cardinality.allowsMany(reqCard); 82 83 ItemType suppliedItemType = null; 84 int suppliedCard = -1; 86 88 boolean cardOK = (reqCard == StaticProperty.ALLOWS_ZERO_OR_MORE); 89 if (!cardOK) { 92 suppliedCard = exp.getCardinality(); 93 cardOK = Cardinality.subsumes(reqCard, suppliedCard); 94 } 96 97 boolean itemTypeOK = reqItemType instanceof AnyItemType; 98 if (!itemTypeOK) { 102 suppliedItemType = exp.getItemType(); 103 if (suppliedItemType instanceof NoNodeTest) { 104 itemTypeOK = true; 106 } else { 107 int relation = Type.relationship(reqItemType, suppliedItemType); 108 itemTypeOK = relation == Type.SAME_TYPE || relation == Type.SUBSUMES; 109 } 110 } 111 112 113 if (backwardsCompatible && !allowsMany) { 115 if (Cardinality.allowsMany(suppliedCard)) { 117 ComputedExpression cexp = new FirstItemExpression(exp); 118 cexp.adoptChildExpression(exp); 119 exp = cexp; 120 suppliedCard = StaticProperty.ALLOWS_ZERO_OR_ONE; 121 cardOK = Cardinality.subsumes(reqCard, suppliedCard); 122 } 123 if (!itemTypeOK) { 124 if (reqItemType == Type.STRING_TYPE) { 126 StringFn fn = (StringFn)SystemFunction.makeSystemFunction("string", 1, env.getNamePool()); 127 fn.setParentExpression(exp.getParentExpression()); 128 Expression[] args = {exp}; 129 fn.setArguments(args); 130 try { 131 exp = fn.simplify(env).typeCheck(env, AnyItemType.getInstance()); 132 } catch (XPathException err) { 133 throw err.makeStatic(); 134 } 135 suppliedItemType = Type.STRING_TYPE; 136 suppliedCard = StaticProperty.EXACTLY_ONE; 137 cardOK = Cardinality.subsumes(reqCard, suppliedCard); 138 itemTypeOK = true; 139 } 140 if (reqItemType == Type.NUMBER_TYPE || reqItemType == Type.DOUBLE_TYPE) { 142 NumberFn fn = (NumberFn)SystemFunction.makeSystemFunction("number", 1, env.getNamePool()); 143 Expression[] args = {exp}; 144 fn.setArguments(args); 145 try { 146 exp = fn.simplify(env).typeCheck(env, AnyItemType.getInstance()); 147 } catch (XPathException err) { 148 throw err.makeStatic(); 149 } 150 suppliedItemType = Type.DOUBLE_TYPE; 151 suppliedCard = StaticProperty.EXACTLY_ONE; 152 cardOK = Cardinality.subsumes(reqCard, suppliedCard); 153 itemTypeOK = true; 154 } 155 } 156 } 157 158 if (!itemTypeOK) { 159 161 if (reqItemType instanceof AtomicType) { 162 163 if (!(suppliedItemType instanceof AtomicType) && 165 !(suppliedCard == StaticProperty.EMPTY)) { 166 ComputedExpression cexp = new Atomizer(exp, env.getConfiguration()); 167 exp = cexp; 168 suppliedItemType = exp.getItemType(); 169 suppliedCard = exp.getCardinality(); 170 cardOK = Cardinality.subsumes(reqCard, suppliedCard); 171 } 172 173 175 177 if ((suppliedItemType == Type.UNTYPED_ATOMIC_TYPE) 178 && !(reqItemType == Type.UNTYPED_ATOMIC_TYPE || reqItemType == Type.ANY_ATOMIC_TYPE)) { 179 180 ComputedExpression cexp = new UntypedAtomicConverter(exp, (AtomicType)reqItemType, true); 181 try { 182 if (exp instanceof Value) { 183 exp = new SequenceExtent(cexp.iterate(null)).simplify(); 184 } else { 185 exp = cexp; 186 } 187 } catch (XPathException err) { 188 throw err.makeStatic(); 189 } 190 itemTypeOK = true; 191 suppliedItemType = reqItemType; 192 } 193 194 197 if ((suppliedItemType == Type.ANY_ATOMIC_TYPE) 198 && !(reqItemType == Type.UNTYPED_ATOMIC_TYPE || reqItemType == Type.ANY_ATOMIC_TYPE)) { 199 200 ComputedExpression cexp = new UntypedAtomicConverter(exp, (AtomicType)reqItemType, false); 201 try { 202 if (exp instanceof Value) { 203 exp = new SequenceExtent(cexp.iterate(null)).simplify(); 204 } else { 205 exp = cexp; 206 } 207 } catch (XPathException err) { 208 throw err.makeStatic(); 209 } 210 } 211 212 214 int rt = ((AtomicType)reqItemType).getFingerprint(); 215 if (rt == StandardNames.XS_DOUBLE || rt == StandardNames.XS_FLOAT) { 216 if (Type.relationship(suppliedItemType, Type.NUMBER_TYPE) != Type.DISJOINT) { 217 exp = new NumericPromoter(exp, rt); 218 try { 219 exp = exp.simplify(env).typeCheck(env, AnyItemType.getInstance()); 220 } catch (XPathException err) { 221 throw err.makeStatic(); 222 } 223 suppliedItemType = (rt == StandardNames.XS_DOUBLE ? Type.DOUBLE_TYPE : Type.FLOAT_TYPE); 224 suppliedCard = -1; 225 } 226 } 227 228 230 if (rt == Type.STRING && 231 Type.isSubType(suppliedItemType, Type.ANY_URI_TYPE)) { 232 suppliedItemType = Type.STRING_TYPE; 233 itemTypeOK = true; 234 } 238 239 } 240 } 241 242 if (itemTypeOK && cardOK) { 244 return exp; 245 } 246 247 if (suppliedCard == -1) { 249 suppliedCard = exp.getCardinality(); 250 if (!cardOK) { 251 cardOK = Cardinality.subsumes(reqCard, suppliedCard); 252 } 253 } 254 255 if (cardOK && suppliedCard==StaticProperty.EMPTY) { 258 return exp; 259 } 260 261 if (suppliedCard==StaticProperty.EMPTY && ((reqCard & StaticProperty.ALLOWS_ZERO) == 0) ) { 263 StaticError err = new StaticError( 264 "An empty sequence is not allowed as the " + role.getMessage(), 265 getLocator(supplied, role)); 266 err.setErrorCode(role.getErrorCode()); 267 err.setIsTypeError(true); 268 throw err; 269 } 270 271 273 int relation = Type.relationship(suppliedItemType, reqItemType); 274 if (relation == Type.DISJOINT) { 275 if (Cardinality.allowsZero(suppliedCard) && 278 Cardinality.allowsZero(reqCard)) { 279 if (suppliedCard != StaticProperty.EMPTY) { 280 String msg = "Required item type of " + role.getMessage() + 281 " is " + reqItemType.toString(env.getNamePool()) + 282 "; supplied value has item type " + 283 suppliedItemType.toString(env.getNamePool()) + 284 ". The expression can succeed only if the supplied value is an empty sequence."; 285 env.issueWarning(msg, getLocator(supplied, role)); 286 } 287 } else { 288 StaticError err = new StaticError( 289 "Required item type of " + role.getMessage() + 290 " is " + reqItemType.toString(env.getNamePool()) + 291 "; supplied value has item type " + 292 suppliedItemType.toString(env.getNamePool()), 293 getLocator(supplied, role)); 294 err.setErrorCode(role.getErrorCode()); 295 err.setIsTypeError(true); 296 throw err; 297 } 298 } 299 300 304 if (!(relation == Type.SAME_TYPE || relation == Type.SUBSUMED_BY)) { 305 if (exp instanceof Value) { 306 StaticError err = new StaticError( 307 "Required item type of " + role.getMessage() + 308 " is " + reqItemType.toString(env.getNamePool()) + 309 "; supplied value has item type " + 310 suppliedItemType.toString(env.getNamePool()), 311 getLocator(supplied, role)); 312 err.setErrorCode(role.getErrorCode()); 313 err.setIsTypeError(true); 314 throw err; 315 } 316 ComputedExpression cexp = new ItemChecker(exp, reqItemType, role); 317 cexp.adoptChildExpression(exp); 318 exp = cexp; 319 } 320 321 if (!cardOK) { 322 if (exp instanceof Value) { 323 StaticError err = new StaticError ( 324 "Required cardinality of " + role.getMessage() + 325 " is " + Cardinality.toString(reqCard) + 326 "; supplied value has cardinality " + 327 Cardinality.toString(suppliedCard), 328 getLocator(supplied, role)); 329 err.setIsTypeError(true); 330 err.setErrorCode(role.getErrorCode()); 331 throw err; 332 } else { 333 ComputedExpression cexp = CardinalityChecker.makeCardinalityChecker(exp, reqCard, role); 334 cexp.adoptChildExpression(exp); 335 exp = cexp; 336 } 337 } 338 339 return exp; 340 } 341 342 359 360 public static Expression strictTypeCheck(Expression supplied, 361 SequenceType req, 362 RoleLocator role, 363 StaticContext env) 364 throws StaticError { 365 366 368 Expression exp = supplied; 369 370 ItemType reqItemType = req.getPrimaryType(); 371 int reqCard = req.getCardinality(); 372 373 ItemType suppliedItemType = null; 374 int suppliedCard = -1; 376 378 boolean cardOK = (reqCard == StaticProperty.ALLOWS_ZERO_OR_MORE); 379 if (!cardOK) { 382 suppliedCard = exp.getCardinality(); 383 cardOK = Cardinality.subsumes(reqCard, suppliedCard); 384 } 385 386 boolean itemTypeOK = req.getPrimaryType() instanceof AnyItemType; 387 if (!itemTypeOK) { 391 suppliedItemType = exp.getItemType(); 392 int relation = Type.relationship(reqItemType, suppliedItemType); 393 itemTypeOK = relation == Type.SAME_TYPE || relation == Type.SUBSUMES; 394 } 395 396 if (itemTypeOK && cardOK) { 398 return exp; 399 } 400 401 if (suppliedCard == -1) { 403 if (suppliedItemType instanceof NoNodeTest) { 404 suppliedCard = StaticProperty.EMPTY; 405 } else { 406 suppliedCard = exp.getCardinality(); 407 } 408 if (!cardOK) { 409 cardOK = Cardinality.subsumes(reqCard, suppliedCard); 410 } 411 } 412 413 if (cardOK && suppliedCard==StaticProperty.EMPTY) { 416 return exp; 417 } 418 419 if (suppliedItemType == null) { 421 suppliedItemType = exp.getItemType(); 422 } 423 424 if (suppliedCard==StaticProperty.EMPTY && ((reqCard & StaticProperty.ALLOWS_ZERO) == 0) ) { 425 StaticError err = new StaticError( 426 "An empty sequence is not allowed as the " + role.getMessage(), 427 getLocator(supplied, role)); 428 err.setErrorCode(role.getErrorCode()); 429 err.setIsTypeError(true); 430 throw err; 431 } 432 433 435 int relation = Type.relationship(suppliedItemType, reqItemType); 436 if (relation == Type.DISJOINT) { 437 if (Cardinality.allowsZero(suppliedCard) && 440 Cardinality.allowsZero(reqCard)) { 441 if (suppliedCard != StaticProperty.EMPTY) { 442 String msg = "Required item type of " + role.getMessage() + 443 " is " + reqItemType.toString(env.getNamePool()) + 444 "; supplied value has item type " + 445 suppliedItemType.toString(env.getNamePool()) + 446 ". The expression can succeed only if the supplied value is an empty sequence."; 447 env.issueWarning(msg, getLocator(supplied, role)); 448 } 449 } else { 450 StaticError err = new StaticError( 451 "Required item type of " + role.getMessage() + 452 " is " + reqItemType.toString(env.getNamePool()) + 453 "; supplied value has item type " + 454 suppliedItemType.toString(env.getNamePool()), 455 getLocator(supplied, role)); 456 err.setErrorCode(role.getErrorCode()); 457 err.setIsTypeError(true); 458 throw err; 459 } 460 } 461 462 466 if (!(relation == Type.SAME_TYPE || relation == Type.SUBSUMED_BY)) { 467 ComputedExpression cexp = new ItemChecker(exp, reqItemType, role); 468 cexp.adoptChildExpression(exp); 469 exp = cexp; 470 } 471 472 if (!cardOK) { 473 if (exp instanceof Value) { 474 StaticError err = new StaticError ( 475 "Required cardinality of " + role.getMessage() + 476 " is " + Cardinality.toString(reqCard) + 477 "; supplied value has cardinality " + 478 Cardinality.toString(suppliedCard), 479 getLocator(supplied, role)); 480 err.setIsTypeError(true); 481 err.setErrorCode(role.getErrorCode()); 482 throw err; 483 } else { 484 ComputedExpression cexp = CardinalityChecker.makeCardinalityChecker(exp, reqCard, role); 485 cexp.adoptChildExpression(exp); 486 exp = cexp; 487 } 488 } 489 490 return exp; 491 } 492 493 496 497 private static SourceLocator getLocator(Expression supplied, RoleLocator role) { 498 SourceLocator loc = ExpressionTool.getLocator(supplied); 499 if (loc == null) { 500 loc = role.getSourceLocator(); 501 } 502 return loc; 503 } 504 505 512 513 public static DynamicError testConformance(Value val, SequenceType requiredType) { 514 ItemType reqItemType = requiredType.getPrimaryType(); 515 if (!Type.isSubType(val.getItemType(), reqItemType)) { 516 DynamicError err = new DynamicError ( 517 "Global parameter requires type " + reqItemType + 518 "; supplied value has type " + val.getItemType()); 519 err.setIsTypeError(true); 520 return err; 521 } 522 int reqCardinality = requiredType.getCardinality(); 523 if (!Cardinality.subsumes(reqCardinality, val.getCardinality())) { 524 DynamicError err = new DynamicError ( 525 "Supplied value of external parameter does not match the required cardinality"); 526 err.setIsTypeError(true); 527 return err; 528 } 529 return null; 530 } 531 } 532 533 | Popular Tags |