private boolean isPredicatePattern(Expression exp) { if (exp instanceof ItemChecker) { exp = ((ItemChecker)exp).getBaseExpression(); } return exp instanceof FilterExpression && (((FilterExpression)exp).getSelectExpression() instanceof ContextItemExpression); }
/** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new ItemChecker(getBaseExpression().copy(), requiredItemType, role); }
/** * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process(). * This method indicates which of these methods is provided. This implementation provides both iterate() and * process() methods natively. */ public int getImplementationMethod() { int m = ITERATE_METHOD | PROCESS_METHOD | ITEM_FEED_METHOD; if (!Cardinality.allowsMany(getCardinality())) { m |= EVALUATE_METHOD; } return m; }
/** * Simplify an expression * */ /*@NotNull*/ public Expression simplify() throws XPathException { Expression operand = getBaseExpression().simplify(); if (requiredItemType instanceof AnyItemType) { return operand; } setBaseExpression(operand); return this; }
/** * Iterate over the sequence of values */ /*@NotNull*/ public SequenceIterator<?> iterate(XPathContext context) throws XPathException { SequenceIterator<?> base = getBaseExpression().iterate(context); return new ItemMappingIterator<>(base, getMappingFunction(context), true); }
getOperand().typeCheck(visitor, contextInfo); Expression operand = getBaseExpression(); List<Expression> checkedOperands = new ArrayList<>(); for (Operand o : block.operands()) { ItemChecker checkedOp = new ItemChecker(o.getChildExpression(), requiredItemType, role); checkedOperands.add(checkedOp); final TypeHierarchy th = getConfiguration().getTypeHierarchy(); int card = operand.getCardinality(); if (card == StaticProperty.EMPTY) { visitor.getStaticContext().issueWarning( "The only value that can pass type-checking is an empty sequence. " + message, getLocation()); XPathException err = new XPathException(message); err.setErrorCode(role.getErrorCode()); err.setLocation(this.getLocation()); err.setIsTypeError(role.isTypeError()); throw err;
/** * Process the instruction, without returning any tail calls * * @param context The dynamic context, giving access to the current node, * the current variables, etc. */ public void process(XPathContext context) throws XPathException { Expression next = operand; ItemType type = Type.ITEM_TYPE; if (next instanceof ItemChecker) { type = ((ItemChecker)next).getRequiredType(); next = ((ItemChecker)next).getBaseExpression(); } if ((next.getImplementationMethod() & PROCESS_METHOD) != 0 && !(type instanceof DocumentNodeTest)) { SequenceReceiver out = context.getReceiver(); TypeCheckingFilter filter = new TypeCheckingFilter(); filter.setUnderlyingReceiver(out); filter.setPipelineConfiguration(out.getPipelineConfiguration()); filter.setRequiredType(type, requiredCardinality, role); context.setReceiver(filter); next.process(context); filter.close(); context.setReceiver(out); } else { super.process(context); } }
/** * Create an expression whose effect is to apply function coercion to coerce a function from this type to another type * * @param exp the expression that delivers the supplied sequence of function items (the ones in need of coercion) * @param role information for use in diagnostics * @return the sequence of coerced functions, each on a function that calls the corresponding original function * after checking the parameters */ public Expression makeFunctionSequenceCoercer(Expression exp, RoleDiagnostic role) throws XPathException { return new ItemChecker(exp, this, role); }
/** * Evaluate as an Item. */ public Item evaluateItem(XPathContext context) throws XPathException { final TypeHierarchy th = context.getConfiguration().getTypeHierarchy(); Item item = getBaseExpression().evaluateItem(context); if (item == null) { return null; } if (requiredItemType.matches(item, th)) { return item; } else if (requiredItemType.getUType().subsumes(UType.STRING) && BuiltInAtomicType.ANY_URI.matches(item, th)) { return item; } else { String message = role.composeErrorMessage(requiredItemType, item, th); String errorCode = role.getErrorCode(); if ("XPDY0050".equals(errorCode)) { // error in "treat as" assertion dynamicError(message, errorCode, context); } else { typeError(message, errorCode, context); } return null; } }
private void testConformance(Item item, XPathContext context) throws XPathException { if (!requiredItemType.matchesItem(item, true, (context == null ? null : context.getConfiguration()))) { String message; if (context == null) { // no name pool available message = "Supplied value of type " + Type.displayTypeName(item) + " does not match the required type of " + role.getMessage(); } else { final NamePool pool = context.getNamePool(); final TypeHierarchy th = context.getConfiguration().getTypeHierarchy(); message = role.composeErrorMessage(requiredItemType, Value.asValue(item).getItemType(th), pool); } String errorCode = role.getErrorCode(); if ("XPDY0050".equals(errorCode)) { // error in "treat as" assertion dynamicError(message, errorCode, context); } else { typeError(message, errorCode, context); } } }
Expression other = checker.getBaseExpression(); checker.setBaseExpression(this); checker.setParentExpression(null); return checker;
/** * Perform optimisation of an expression and its subexpressions. * <p>This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.</p> * * @param visitor an expression visitor * @param contextInfo the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ @Override public Expression optimize(ExpressionVisitor visitor, ContextItemStaticInfo contextInfo) throws XPathException { getOperand().optimize(visitor, contextInfo); TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); int rel = th.relationship(requiredItemType, getBaseExpression().getItemType()); if (rel == TypeHierarchy.SAME_TYPE || rel == TypeHierarchy.SUBSUMES) { return getBaseExpression(); } return this; }
/** * Determine the data type of the items returned by the expression */ /*@NotNull*/ public ItemType getItemType() { ItemType operandType = getBaseExpression().getItemType(); TypeHierarchy th = getConfiguration().getTypeHierarchy(); int relationship = th.relationship(requiredItemType, operandType); switch (relationship) { case TypeHierarchy.OVERLAPS: if (requiredItemType instanceof NodeTest && operandType instanceof NodeTest) { return new CombinedNodeTest((NodeTest) requiredItemType, Token.INTERSECT, (NodeTest) operandType); } else { // we don't know how to intersect atomic types, it doesn't actually happen return requiredItemType; } case TypeHierarchy.SUBSUMES: case TypeHierarchy.SAME_TYPE: // shouldn't happen, but it doesn't matter return operandType; case TypeHierarchy.SUBSUMED_BY: default: return requiredItemType; } }
/** * Process the instruction, without returning any tail calls * * @param context The dynamic context, giving access to the current node, * the current variables, etc. */ public void process(XPathContext context) throws XPathException { Expression next = getBaseExpression(); int card = StaticProperty.ALLOWS_ZERO_OR_MORE; if (next instanceof CardinalityChecker) { card = ((CardinalityChecker) next).getRequiredCardinality(); next = ((CardinalityChecker) next).getBaseExpression(); } if ((next.getImplementationMethod() & PROCESS_METHOD) != 0 && !(requiredItemType instanceof DocumentNodeTest)) { Receiver out = context.getReceiver(); TypeCheckingFilter filter = new TypeCheckingFilter(out); filter.setRequiredType(requiredItemType, card, role, getLocation()); context.setReceiver(filter); next.process(context); filter.close(); context.setReceiver(out); } else { // Force pull-mode evaluation super.process(context); } }
/** * Constructor * @param sequence the expression whose value we are checking * @param itemType the required type of the items in the sequence * @param role information used in constructing an error message */ public ItemChecker(Expression sequence, ItemType itemType, RoleLocator role) { super(sequence); requiredItemType = itemType; this.role = role; adoptChildExpression(sequence); }
/** * Evaluate as an Item. */ public Item evaluateItem(XPathContext context) throws XPathException { Item item = operand.evaluateItem(context); if (item==null) return null; testConformance(item, context); return item; }
getOperand().typeCheck(visitor, contextInfo); Expression operand = getBaseExpression(); List<Expression> checkedOperands = new ArrayList<>(); for (Operand o : block.operands()) { ItemChecker checkedOp = new ItemChecker(o.getChildExpression(), requiredItemType, role); checkedOperands.add(checkedOp); final TypeHierarchy th = getConfiguration().getTypeHierarchy(); int card = operand.getCardinality(); if (card == StaticProperty.EMPTY) { visitor.getStaticContext().issueWarning( "The only value that can pass type-checking is an empty sequence. " + message, getLocation()); XPathException err = new XPathException(message); err.setErrorCode(role.getErrorCode()); err.setLocation(this.getLocation()); err.setIsTypeError(role.isTypeError()); throw err;
/** * Process the instruction, without returning any tail calls * * @param context The dynamic context, giving access to the current node, * the current variables, etc. */ public void process(XPathContext context) throws XPathException { Expression next = operand; ItemType type = Type.ITEM_TYPE; if (next instanceof ItemChecker) { type = ((ItemChecker)next).getRequiredType(); next = ((ItemChecker)next).getBaseExpression(); } if ((next.getImplementationMethod() & PROCESS_METHOD) != 0 && !(type instanceof DocumentNodeTest)) { SequenceReceiver out = context.getReceiver(); TypeCheckingFilter filter = new TypeCheckingFilter(); filter.setUnderlyingReceiver(out); filter.setPipelineConfiguration(out.getPipelineConfiguration()); filter.setRequiredType(type, requiredCardinality, role); context.setReceiver(filter); next.process(context); filter.close(); context.setReceiver(out); } else { super.process(context); } }
/** * Create an expression whose effect is to apply function coercion to coerce a function from this type to another type * * @param exp the expression that delivers the supplied sequence of function items (the ones in need of coercion) * @param role information for use in diagnostics * @return the sequence of coerced functions, each on a function that calls the corresponding original function * after checking the parameters */ public Expression makeFunctionSequenceCoercer(Expression exp, RoleDiagnostic role) throws XPathException { return new ItemChecker(exp, this, role); }
/** * Evaluate as an Item. */ public Item evaluateItem(XPathContext context) throws XPathException { final TypeHierarchy th = context.getConfiguration().getTypeHierarchy(); Item item = getBaseExpression().evaluateItem(context); if (item == null) { return null; } if (requiredItemType.matches(item, th)) { return item; } else if (requiredItemType.getUType().subsumes(UType.STRING) && BuiltInAtomicType.ANY_URI.matches(item, th)) { return item; } else { String message = role.composeErrorMessage(requiredItemType, item, th); String errorCode = role.getErrorCode(); if ("XPDY0050".equals(errorCode)) { // error in "treat as" assertion dynamicError(message, errorCode, context); } else { typeError(message, errorCode, context); } return null; } }