Esempio n. 1
0
Expression::Ptr InstanceOf::compress(const StaticContext::Ptr &context)
{
    const Expression::Ptr me(SingleContainer::compress(context));

    if(me.data() != this || m_operand->has(DisableTypingDeduction))
        return me;

    const SequenceType::Ptr opType(m_operand->staticType());
    const ItemType::Ptr itType(m_targetType->itemType());
    const ItemType::Ptr ioType(opType->itemType());

    if(m_targetType->cardinality().isMatch(opType->cardinality()))
    {
        if(itType->xdtTypeMatches(ioType))
            return wrapLiteral(CommonValues::BooleanTrue, context, this);
        else if(!ioType->xdtTypeMatches(itType))
        {
            return wrapLiteral(CommonValues::BooleanFalse, context, this);
        }
    }
    /* The cardinality is not guaranteed to match; it will need testing. */
    else if(!ioType->xdtTypeMatches(itType))
    {
        /* There's no way it's gonna match. The cardinality is not only
         * wrong, but the item type as well. */
        return wrapLiteral(CommonValues::BooleanFalse, context, this);
    }

    return me;
}
Esempio n. 2
0
bool XSLTNodeTest::xdtTypeMatches(const ItemType::Ptr &other) const
{
    if(!other->isNodeType())
        return false;

    return *static_cast<const XSLTNodeTest *>(other.data()) == *this
           ? true
           : xdtTypeMatches(other->xdtSuperType());
}
Esempio n. 3
0
bool BuiltinNodeType<kind>::xdtTypeMatches(const ItemType::Ptr &other) const
{
    if(!other->isNodeType())
        return false;

    return *static_cast<const BuiltinNodeType *>(other.data()) == *this
            ? true
            : xdtTypeMatches(other->xdtSuperType());
}
Esempio n. 4
0
AtomicComparator::Ptr ComparisonPlatform<TSubClass, issueError, comparisonType, errorCode>::
fetchComparator(const ItemType::Ptr &t1,
                const ItemType::Ptr &t2,
                const ReportContext::Ptr &context) const
{
    Q_ASSERT(t1);
    Q_ASSERT(t2);

    if(*BuiltinTypes::xsAnyAtomicType == *t1    ||
       *BuiltinTypes::xsAnyAtomicType == *t2    ||
       *BuiltinTypes::item == *t1               ||
       *BuiltinTypes::item == *t2               ||
       *BuiltinTypes::numeric == *t1            ||
       *BuiltinTypes::numeric == *t2            ||
       *CommonSequenceTypes::Empty == *t1       ||
       *CommonSequenceTypes::Empty == *t2)
    {
        /* The static type of(at least) one of the operands could not
         * be narrowed further, so we do the operator
         * lookup at runtime.
         */
        return AtomicComparator::Ptr();
    }

    const AtomicComparatorLocator::Ptr locator
        (static_cast<const AtomicType *>(t1.data())->comparatorLocator());

    if(!locator)
    {
        if(issueError)
        {
            context->error(QtXmlPatterns::tr("No comparisons can be done involving the type %1.")
                                            .arg(formatType(context->namePool(), t1)),
                                       errorCode, static_cast<const TSubClass *>(this)->actualReflection());
        }
        return AtomicComparator::Ptr();
    }

    const AtomicComparator::Ptr comp(static_cast<const AtomicType *>(t2.data())->accept(locator, operatorID(),
                                                                                       static_cast<const TSubClass *>(this)->actualReflection()));

    if(comp)
        return comp;
    else if(issueError)
    {
        context->error(QtXmlPatterns::tr("Operator %1 is not available between atomic values of type %2 and %3.")
                                        .arg(formatKeyword(AtomicComparator::displayName(operatorID(),
                                                                                         comparisonType)),
                                             formatType(context->namePool(), t1),
                                             formatType(context->namePool(), t2)),
                                   errorCode, static_cast<const TSubClass *>(this)->actualReflection());
    }

    return AtomicComparator::Ptr();
}
Esempio n. 5
0
bool AtomicType::xdtTypeMatches(const ItemType::Ptr &other) const
{
    if(other->isAtomicType())
    {
        if(*other == *this)
            return true;
        else
            return xdtTypeMatches(other->xdtSuperType());
    }
    else
        return false;
}
Esempio n. 6
0
bool AbstractNodeTest::xdtTypeMatches(const ItemType::Ptr &other) const
{
    Q_ASSERT(other);

    if(other->isNodeType())
    {
        if(*other == *this)
            return true;
        else
            return xdtTypeMatches(other->xdtSuperType());
    }
    else
        return false;
}
Esempio n. 7
0
AtomicCaster::Ptr CastingPlatform<TSubClass, issueError>::locateCaster(const ItemType::Ptr &sourceType,
                                                                       const ReportContext::Ptr &context,
                                                                       bool &castImpossible,
                                                                       const SourceLocationReflection *const location,
                                                                       const ItemType::Ptr &targetType)
{
    Q_ASSERT(sourceType);
    Q_ASSERT(targetType);

    const AtomicCasterLocator::Ptr locator(static_cast<AtomicType *>(
            targetType.data())->casterLocator());
    if(!locator)
    {
        if(issueError)
        {
            context->error(QtXmlPatterns::tr("No casting is possible with %1 as the target type.")
                                        .arg(formatType(context->namePool(), targetType)),
                                       ReportContext::XPTY0004, location);
        }
        else
            castImpossible = true;

        return AtomicCaster::Ptr();
    }

    const AtomicCaster::Ptr caster(static_cast<const AtomicType *>(sourceType.data())->accept(locator, location));
    if(!caster)
    {
        if(issueError)
        {
            context->error(QtXmlPatterns::tr("It is not possible to cast from %1 to %2.")
                                            .arg(formatType(context->namePool(), sourceType))
                                            .arg(formatType(context->namePool(), targetType)),
                                       ReportContext::XPTY0004, location);
        }
        else
            castImpossible = true;

        return AtomicCaster::Ptr();
    }

    return caster;
}
Esempio n. 8
0
Expression::Ptr InstanceOf::compress(const StaticContext::Ptr &context)
{
    const Expression::Ptr me(SingleContainer::compress(context));

    if(me != this || m_operand->has(DisableTypingDeduction))
        return me;

    const SequenceType::Ptr opType(m_operand->staticType());
    const ItemType::Ptr targetType(m_targetType->itemType());
    const ItemType::Ptr operandType(opType->itemType());

    if(m_targetType->cardinality().isMatch(opType->cardinality()))
    {
        if(*operandType == *CommonSequenceTypes::Empty || targetType->xdtTypeMatches(operandType))
            return wrapLiteral(CommonValues::BooleanTrue, context, this);
        else if(!operandType->xdtTypeMatches(targetType))
            return wrapLiteral(CommonValues::BooleanFalse, context, this);
    }
    /* Optimization: rule out the case where instance of will always fail. */

    return me;
}
Esempio n. 9
0
Expression::Ptr TypeChecker::verifyType(const Expression::Ptr &operand,
                                        const SequenceType::Ptr &reqSeqType,
                                        const StaticContext::Ptr &context,
                                        const ReportContext::ErrorCode code,
                                        const Options options)
{
    const ItemType::Ptr reqType(reqSeqType->itemType());
    const Expression::Properties props(operand->properties());

    /* If operand requires a focus, do the necessary type checking for that. */
    if(props.testFlag(Expression::RequiresFocus) && options.testFlag(CheckFocus))
    {
        const ItemType::Ptr contextType(context->contextItemType());
        if(contextType)
        {
            if(props.testFlag(Expression::RequiresContextItem))
            {
                Q_ASSERT_X(operand->expectedContextItemType(), Q_FUNC_INFO,
                           "When the Expression sets the RequiresContextItem property, it must "
                           "return a type in expectedContextItemType()");
                const ItemType::Ptr expectedContextType(operand->expectedContextItemType());

                /* Allow the empty sequence. We don't want to trigger XPTY0020 on ()/... . */
                if(!expectedContextType->xdtTypeMatches(contextType) && contextType != CommonSequenceTypes::Empty)
                {
                    context->error(wrongType(context->namePool(), operand->expectedContextItemType(), contextType),
                                   ReportContext::XPTY0020, operand.data());
                    return operand;
                }
            }
        }
        else
        {
            context->error(QtXmlPatterns::tr("The focus is undefined."), ReportContext::XPDY0002, operand.data());
            return operand;
        }
    }

    SequenceType::Ptr operandSeqType(operand->staticType());
    ItemType::Ptr operandType(operandSeqType->itemType());

    /* This returns the operand if the types are identical or if operandType
     * is a subtype of reqType. */
    if(reqType->xdtTypeMatches(operandType) || *operandType == *CommonSequenceTypes::Empty)
        return operand;

    /* Since we haven't exited yet, it means that the operandType is a super type
     * of reqType, and that there hence is a path down to it through the
     * type hierachy -- but that doesn't necessarily mean that a up-cast(down the
     * hierarchy) would succeed. */

    Expression::Ptr result(operand);

    if(reqType->isAtomicType())
    {
        const Expression::ID opID = operand->id();
        if((opID == Expression::IDArgumentReference ||
                (opID == Expression::IDCardinalityVerifier && operand->operands().first()->is(Expression::IDArgumentReference)))
                && *BuiltinTypes::item == *operandType)
            return Expression::Ptr(new ArgumentConverter(result, reqType));

        if(!operandType->isAtomicType())
        {
            result = Expression::Ptr(new Atomizer(result));
            /* The atomizer might know more about the type. */
            operandType = result->staticType()->itemType();
        }

        if(reqType->xdtTypeMatches(operandType))
        {
            /* Atomization was sufficient. Either the expected type is xs:anyAtomicType
             * or the type the Atomizer knows it returns, matches the required type. */
            return result;
        }

        const bool compatModeEnabled = context->compatModeEnabled();

        if((options.testFlag(AutomaticallyConvert) && BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(operandType)) ||
                (compatModeEnabled && BuiltinTypes::xsString->xdtTypeMatches(reqType)))
        {
            if(*reqType == *BuiltinTypes::numeric)
            {
                result = typeCheck(new UntypedAtomicConverter(result, BuiltinTypes::xsDouble, code),
                                   context, reqSeqType);
            }
            else
                result = typeCheck(new UntypedAtomicConverter(result, reqType, code), context, reqSeqType);

            /* The UntypedAtomicConverter might know more about the type, so reload. */
            operandType = result->staticType()->itemType();
        }
        else if(compatModeEnabled && *reqType == *BuiltinTypes::xsDouble)
        {
            const FunctionFactory::Ptr functions(context->functionSignatures());
            Expression::List numberArgs;
            numberArgs.append(operand);

            result = functions->createFunctionCall(QXmlName(StandardNamespaces::fn, StandardLocalNames::number),
                                                   numberArgs,
                                                   context,
                                                   operand.data())->typeCheck(context, reqSeqType);
            operandType = result->staticType()->itemType();
            context->wrapExpressionWith(operand.data(), result);
        }

        if(reqType->xdtTypeMatches(operandType))
            return result;

        /* Test if promotion will solve it; the xdtTypeMatches didn't
         * do that. */
        if(options.testFlag(AutomaticallyConvert) && promotionPossible(operandType, reqType, context))
        {
            if(options.testFlag(GeneratePromotion))
                return Expression::Ptr(new UntypedAtomicConverter(result, reqType));
            else
                return result;
        }

        if(operandType->xdtTypeMatches(reqType))
        {
            /* For example, operandType is numeric, and reqType is xs:integer. */
            return Expression::Ptr(new ItemVerifier(result, reqType, code));
        }
        else
        {
            context->error(wrongType(context->namePool(), reqType, operandType), code, operand.data());
            return result;
        }
    }
    else if(reqType->isNodeType())
    {

        ReportContext::ErrorCode myCode;

        if(*reqType == *CommonSequenceTypes::EBV->itemType())
            myCode = ReportContext::FORG0006;
        else
            myCode = code;

        /* empty-sequence() is considered valid because it's ok to do
         * for example nilled( () ). That is, to pass an empty sequence to a
         * function requiring for example node()?. */
        if(*operandType == *CommonSequenceTypes::Empty)
            return result;
        else if(!operandType->xdtTypeMatches(reqType))
        {
            context->error(wrongType(context->namePool(), reqType, operandType), myCode, operand.data());
            return result;
        }

        /* Operand must be an item. Thus, the sequence can contain both
         * nodes and atomic values: we have to verify. */
        return Expression::Ptr(new ItemVerifier(result, reqType, myCode));
    }
    else
    {
        Q_ASSERT(*reqType == *CommonSequenceTypes::Empty);

        /* element() doesn't match empty-sequence(), but element()* does. */
        if(!reqType->xdtTypeMatches(operandType) &&
                !operandSeqType->cardinality().allowsEmpty())
        {
            context->error(wrongType(context->namePool(), reqType, operandType),
                           code, operand.data());
            return result;
        }
    }

    /* This line should be reached if required type is
     * EBVType, and the operand is compatible. */
    return result;
}
bool AnyNodeType::xdtTypeMatches(const ItemType::Ptr &other) const
{
    return other->isNodeType();
}