SequenceType::Ptr FirstItemPredicate::staticType() const
{
    const SequenceType::Ptr t(m_operand->staticType());
    return makeGenericSequenceType(t->itemType(), t->cardinality().toWithoutMany());
}
SequenceType::Ptr GenericPredicate::staticType() const
{
    const SequenceType::Ptr type(m_operand1->staticType());
    return makeGenericSequenceType(type->itemType(),
                                   type->cardinality() | Cardinality::zeroOrOne());
}
Exemple #3
0
Expression::Ptr TypeChecker::applyFunctionConversion(const Expression::Ptr &operand,
                                                     const SequenceType::Ptr &reqType,
                                                     const StaticContext::Ptr &context,
                                                     const ReportContext::ErrorCode code,
                                                     const Options options)
{
    Q_ASSERT_X(!ReportContext::codeToString(code).isEmpty(), Q_FUNC_INFO,
               "This test ensures 'code' exists, otherwise codeToString() would assert.");
    Q_ASSERT(operand);
    Q_ASSERT(reqType);
    Q_ASSERT(context);

    /* Do it in two steps: verify type, and then cardinality. */
    const Expression::Ptr cardVerified(CardinalityVerifier::verifyCardinality(operand, reqType->cardinality(), context, code));
    return verifyType(cardVerified, reqType, context, code, options);
}
Exemple #4
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;
}
Exemple #5
0
bool SequenceType::is(const SequenceType::Ptr &other) const
{
    return matches(other) && other->matches(Ptr(this));
}
SequenceType::Ptr ArithmeticExpression::staticType() const
{
    Cardinality card;

    /* These variables are important because they ensure staticType() only
     * gets called once from this function. Before, this lead to strange
     * semi-infinite recursion involving many arithmetic expressions. */
    const SequenceType::Ptr st1(m_operand1->staticType());
    const SequenceType::Ptr st2(m_operand2->staticType());

    if(st1->cardinality().allowsEmpty() ||
       st2->cardinality().allowsEmpty())
    {
        card = Cardinality::zeroOrOne();
    }
    else
        card = Cardinality::exactlyOne();

    if(m_op == AtomicMathematician::IDiv)
        return makeGenericSequenceType(BuiltinTypes::xsInteger, card);

    const ItemType::Ptr t1(st1->itemType());
    const ItemType::Ptr t2(st2->itemType());
    ItemType::Ptr returnType;

    /* Please, make this beautiful? */
    if(BuiltinTypes::xsTime->xdtTypeMatches(t1) ||
       BuiltinTypes::xsDate->xdtTypeMatches(t1) ||
       BuiltinTypes::xsDateTime->xdtTypeMatches(t1))
    {
        if(BuiltinTypes::xsDuration->xdtTypeMatches(t2))
            returnType = t1;
        else
            returnType = BuiltinTypes::xsDayTimeDuration;
    }
    else if(BuiltinTypes::xsYearMonthDuration->xdtTypeMatches(t1))
    {
        if(m_op == AtomicMathematician::Div &&
           BuiltinTypes::xsYearMonthDuration->xdtTypeMatches(t2))
        {
            returnType = BuiltinTypes::xsDecimal;
        }
        else if(BuiltinTypes::numeric->xdtTypeMatches(t2))
            returnType = BuiltinTypes::xsYearMonthDuration;
        else
            returnType = t2;
    }
    else if(BuiltinTypes::xsYearMonthDuration->xdtTypeMatches(t2))
    {
        returnType = BuiltinTypes::xsYearMonthDuration;
    }
    else if(BuiltinTypes::xsDayTimeDuration->xdtTypeMatches(t1))
    {
        if(m_op == AtomicMathematician::Div &&
           BuiltinTypes::xsDayTimeDuration->xdtTypeMatches(t2))
        {
            returnType = BuiltinTypes::xsDecimal;
        }
        else if(BuiltinTypes::numeric->xdtTypeMatches(t2))
            returnType = BuiltinTypes::xsDayTimeDuration;
        else
            returnType = t2;
    }
    else if(BuiltinTypes::xsDayTimeDuration->xdtTypeMatches(t2))
    {
        returnType = BuiltinTypes::xsDayTimeDuration;
    }
    else if(BuiltinTypes::xsDouble->xdtTypeMatches(t1) ||
            BuiltinTypes::xsDouble->xdtTypeMatches(t2))
    {
        returnType = BuiltinTypes::xsDouble;
    }
    else if(BuiltinTypes::xsFloat->xdtTypeMatches(t1) ||
            BuiltinTypes::xsFloat->xdtTypeMatches(t2))
    {
        if(m_isCompat)
            returnType = BuiltinTypes::xsFloat;
        else
            returnType = BuiltinTypes::xsDouble;
    }
    else if(BuiltinTypes::xsInteger->xdtTypeMatches(t1) &&
            BuiltinTypes::xsInteger->xdtTypeMatches(t2))
    {
        if(m_isCompat)
            returnType = BuiltinTypes::xsDouble;
        else
        {
            /* "A div B  numeric  numeric  op:numeric-divide(A, B)
             * numeric; but xs:decimal if both operands are xs:integer" */
            if(m_op == AtomicMathematician::Div)
                returnType = BuiltinTypes::xsDecimal;
            else
                returnType = BuiltinTypes::xsInteger;
        }
    }
    else if(m_isCompat && (BuiltinTypes::xsInteger->xdtTypeMatches(t1) &&
                           BuiltinTypes::xsInteger->xdtTypeMatches(t2)))
    {
        returnType = BuiltinTypes::xsDouble;
    }
    else
    {
        /* If typeCheck() has been called, our operands conform to expectedOperandTypes(), and
         * the types are hence either xs:decimals, or xs:anyAtomicType(meaning the static type could
         * not be inferred), or empty-sequence(). So we use the union of the two types. The combinations
         * could also be wrong.*/
        returnType = t1 | t2;

        /* However, if we're called before typeCheck(), we could potentially have nodes, so we need to make
         * sure that the type is at least atomic. */
        if(!BuiltinTypes::xsAnyAtomicType->xdtTypeMatches(returnType))
            returnType = BuiltinTypes::xsAnyAtomicType;
    }

    return makeGenericSequenceType(returnType, card);
}
SequenceType::Ptr Atomizer::staticType() const
{
    const SequenceType::Ptr opt(m_operand->staticType());
    return makeGenericSequenceType(opt->itemType()->atomizedType(),
                                   opt->cardinality());
}