Item CodepointsToStringFN::evaluateSingleton(const DynamicContext::Ptr &context) const
{
    const Item::Iterator::Ptr it(m_operands.first()->evaluateSequence(context));

    if(!it)
        return CommonValues::EmptyString;

    QString retval;
    Item item(it->next());
    while(item)
    {
        const qint32 cp = static_cast<qint32>(item.as<Numeric>()->toInteger());

        if(!isValidXML10Char(cp))
        {
            context->error(QtXmlPatterns::tr("%1 is not a valid XML 1.0 character.")
                                            .arg(formatData(QLatin1String("0x") +
                                                          QString::number(cp, 16))),
                                       ReportContext::FOCH0001, this);

            return CommonValues::EmptyString;
        }
        retval.append(QChar(cp));
        item = it->next();
    }

    return AtomicString::fromValue(retval);
}
Beispiel #2
0
Item AvgFN::evaluateSingleton(const DynamicContext::Ptr &context) const
{
    const Item::Iterator::Ptr it(m_operands.first()->evaluateSequence(context));
    Item sum(it->next());

    xsInteger count = 0;
    while(sum)
    {
        ++count;
        const Item next(it->next());
        if(!next)
            break;

        sum = ArithmeticExpression::flexiblyCalculate(sum, AtomicMathematician::Add,
                                                      next, m_adder, context,
                                                      this,
                                                      ReportContext::FORG0006);
    };

    if(!sum)
        return Item();

    /* Note that we use the same m_mather which was used for adding,
     * can be worth to think about. */
    return ArithmeticExpression::flexiblyCalculate(sum, AtomicMathematician::Div,
                                                   Integer::fromValue(count),
                                                   m_divider, context,
                                                   this,
                                                   ReportContext::FORG0006);
}
Beispiel #3
0
Item SumFN::evaluateSingleton(const DynamicContext::Ptr &context) const
{
    const Item::Iterator::Ptr it(m_operands.first()->evaluateSequence(context));
    Item sum(it->next());

    while(sum)
    {
        const Item next(it->next());
        if(!next)
            break;

        sum = ArithmeticExpression::flexiblyCalculate(sum, AtomicMathematician::Add,
                                                      next, m_mather, context, this,
                                                      ReportContext::FORG0006);
    };

    if(!sum)
    {
        if(m_operands.count() == 1)
            return CommonValues::IntegerZero;
        else
            return m_operands.last()->evaluateSingleton(context);
    }

    return sum;
}
Beispiel #4
0
Item GenericPredicate::mapToItem(const Item &item,
                                 const DynamicContext::Ptr &context) const
{
    const Item::Iterator::Ptr it(m_operand2->evaluateSequence(context));
    const Item pcateItem(it->next());

    if(!pcateItem)
        return Item(); /* The predicate evaluated to the empty sequence */
    else if(pcateItem.isNode())
        return item;
    /* Ok, now it must be an AtomicValue */
    else if(BuiltinTypes::numeric->xdtTypeMatches(pcateItem.type()))
    { /* It's a positional predicate. */
        if(it->next())
        {
            context->error(QtXmlPatterns::tr("A positional predicate must "
                                             "evaluate to a single numeric "
                                             "value."),
                              ReportContext::FORG0006, this);
            return Item();
        }

        if(Double::isEqual(static_cast<xsDouble>(context->contextPosition()),
                           pcateItem.as<Numeric>()->toDouble()))
        {
            return item;
        }
        else
            return Item();
    }
    else if(Boolean::evaluateEBV(pcateItem, it, context)) /* It's a truth predicate. */
        return item;
    else
        return Item();
}
Beispiel #5
0
bool QuantifiedExpression::evaluateEBV(const DynamicContext::Ptr &context) const
{
    const Item::Iterator::Ptr it(makeItemMappingIterator<Item>(ConstPtr(this),
                                                               m_operand1->evaluateSequence(context),
                                                               context));

    Item item(it->next());

    if(m_quantifier == Some)
    {
        while(item)
        {
            if(m_operand2->evaluateEBV(context))
                return true;
            else
                item = it->next();
        };

        return false;
    }
    else
    {
        Q_ASSERT(m_quantifier == Every);

        while(item)
        {
            if(m_operand2->evaluateEBV(context))
                item = it->next();
            else
                return false;
        }

        return true;
    }
}
bool DeepEqualFN::evaluateEBV(const DynamicContext::Ptr &context) const
{
    const Item::Iterator::Ptr it1(m_operands.first()->evaluateSequence(context));
    const Item::Iterator::Ptr it2(m_operands.at(1)->evaluateSequence(context));

    while(true)
    {
        const Item item1(it1->next());
        const Item item2(it2->next());

        if(!item1)
        {
            if(item2)
                return false;
            else
                return true;
        }
        else if(!item2)
        {
            if(item1)
                return false;
            else
                return true;
        }
        else if(item1.isNode())
        {
            if(item2.isNode())
            {
                if(item1.asNode().isDeepEqual(item2.asNode()))
                    continue;
                else
                    return false;
            }
            else
                return false;
        }
        else if(item2.isNode())
        {
            /* We know that item1 is not a node due to the check above. */
            return false;
        }
        else if(flexibleCompare(item1, item2, context))
            continue;
        else if(BuiltinTypes::numeric->itemMatches(item1) &&
                item1.as<Numeric>()->isNaN() &&
                item2.as<Numeric>()->isNaN())
        {
            // TODO
            /* Handle the specific NaN circumstances. item2 isn't checked whether it's of
             * type numeric, since the AtomicComparator lookup would have failed if both weren't
             * numeric. */
            continue;
        }
        else
            return false;
    };
}
Beispiel #7
0
Item::Iterator::Ptr Path::evaluateSequence(const DynamicContext::Ptr &context) const
{
    /* Note, we use the old context for m_operand1. */
    const Item::Iterator::Ptr source(m_operand1->evaluateSequence(context));

    const DynamicContext::Ptr focus(context->createFocus());
    focus->setFocusIterator(source);

    const Item::Iterator::Ptr result(makeSequenceMappingIterator<Item>(ConstPtr(this), source, focus));

    if(m_checkXPTY0018)
    {
        /* This is an expensive code path, but it should happen very rarely. */

        enum FoundItem
        {
            FoundNone,
            FoundNode,
            FoundAtomicValue
        } hasFound = FoundNone;

        Item::List whenChecked;

        Item next(result->next());

        while(next)
        {
            const FoundItem found = next.isAtomicValue() ? FoundAtomicValue : FoundNode;

            if(hasFound != FoundNone && hasFound != found)
            {
                /* It's an atomic value and we've already found a node. Mixed content. */
                context->error(QtXmlPatterns::tr("The last step in a path must contain either nodes "
                                                 "or atomic values. It cannot be a mixture between the two."),
                               ReportContext::XPTY0018, this);
            }
            else
                hasFound = found;

            whenChecked.append(next);
            next = result->next();
        }

        return makeListIterator(whenChecked);
    }
    else
        return result;
}
Item::Iterator::Ptr CardinalityVerifier::evaluateSequence(const DynamicContext::Ptr &context) const
{
    const Item::Iterator::Ptr it(m_operand->evaluateSequence(context));
    const Item next(it->next());

    if(next)
    {
        const Item next2(it->next());

        if(next2)
        {
            if(m_reqCard.allowsMany())
            {
                Item::List start;
                start.append(next);
                start.append(next2);

                return Item::Iterator::Ptr(new InsertionIterator(it, 1, makeListIterator(start)));
            }
            else
            {
                context->error(wrongCardinality(m_reqCard, Cardinality::twoOrMore()), m_errorCode, this);
                return CommonValues::emptyIterator;
            }
        }
        else
        {
            /* We might be instantiated for the empty sequence. */
            if(m_reqCard.isEmpty())
            {
                context->error(wrongCardinality(m_reqCard, Cardinality::twoOrMore()), m_errorCode, this);
                return CommonValues::emptyIterator;
            }
            else
                return makeSingletonIterator(next);
        }
    }
    else
    {
        if(m_reqCard.allowsEmpty())
            return CommonValues::emptyIterator;
        else
        {
            context->error(wrongCardinality(m_reqCard, Cardinality::twoOrMore()), m_errorCode, this);
            return CommonValues::emptyIterator;
        }
    }
}
Beispiel #9
0
Item GenericPredicate::evaluateSingleton(const DynamicContext::Ptr &context) const
{
    const Item::Iterator::Ptr focus(m_operand1->evaluateSequence(context));
    const DynamicContext::Ptr newContext(context->createFocus());
    newContext->setFocusIterator(focus);
    return mapToItem(focus->next(), newContext);
}
QString StringSplitter::loadNext()
{
    const Item sourceNext(m_source->next());

    if(sourceNext.isNull())
    {
        m_sourceAtEnd = true;
        /* We might have strings in m_buffer, let's empty it. */
        return next();
    }

    const QStringList candidates(sourceNext.stringValue().simplified().split(QLatin1Char(' ')));
    const int count = candidates.length();

    for(int i = 0; i < count; ++i)
    {
        const QString &at = candidates.at(i);

        if(QXmlUtils::isNCName(at))
            m_buffer.push(at);
    }

    /* So, now we have populated m_buffer, let's start from the beginning. */
    return next();
}
Beispiel #11
0
bool Boolean::evaluateEBV(const Item &first,
                          const Item::Iterator::Ptr &it,
                          const QExplicitlySharedDataPointer<DynamicContext> &context)
{
    Q_ASSERT(it);
    Q_ASSERT(context);

    if(!first)
        return false;
    else if(first.isNode())
        return true;

    const Item second(it->next());

    if(second)
    {
        Q_ASSERT(context);
        context->error(QtXmlPatterns::tr("Effective Boolean Value cannot be calculated for a sequence "
                                         "containing two or more atomic values."),
                          ReportContext::FORG0006,
                          QSourceLocation());
        return false;
    }
    else
        return first.as<AtomicValue>()->evaluateEBV(context);
}
Beispiel #12
0
void ForClause::evaluateToSequenceReceiver(const DynamicContext::Ptr &context) const
{
    Item::Iterator::Ptr it;
    const Item::Iterator::Ptr source(m_operand1->evaluateSequence(context));

    riggPositionalVariable(context, source);

    Item next(source->next());

    while(next)
    {
        context->setRangeVariable(m_varSlot, next);
        m_operand2->evaluateToSequenceReceiver(context);
        next = source->next();
    }
}
Item XSLTSimpleContentConstructor::evaluateSingleton(const DynamicContext::Ptr &context) const
{
    const Item::Iterator::Ptr it(m_operand->evaluateSequence(context));

    Item next(it->next());
    QString result;

    bool previousIsText = false;
    bool discard = false;

    if(next)
    {
        const QString unit(processItem(next, discard, previousIsText));

        if(!discard)
            result = unit;

        next = it->next();
    }
    else
        return Item();

    while(next)
    {
        bool currentIsText = false;
        const QString unit(processItem(next, discard, currentIsText));

        if(!discard)
        {
            /* "Adjacent text nodes in the sequence are merged into a single text
             * node." */
            if(previousIsText && currentIsText)
                ;
            else
                result += QLatin1Char(' ');

            result += unit;
        }

        next = it->next();
        previousIsText = currentIsText;
    }

    return AtomicString::fromValue(result);
}
void CopyOf::evaluateToSequenceReceiver(const DynamicContext::Ptr &context) const
{
    const Item::Iterator::Ptr it(m_operand->evaluateSequence(context));
    QAbstractXmlReceiver *const receiver = context->outputReceiver();
    Item next(it->next());

    while(next)
    {
        if(next.isNode())
        {
            const QXmlNodeModelIndex &asNode = next.asNode();
            asNode.model()->copyNodeTo(asNode, receiver, m_settings);
        }
        else
            receiver->item(next);

        next = it->next();
    }
}
Beispiel #15
0
bool GeneralComparison::evaluateEBV(const DynamicContext::Ptr &context) const
{
    const Item::Iterator::Ptr it1(m_operand1->evaluateSequence(context));
    Item item1(it1->next());

    if(!item1)
        return false;

    const Item::Iterator::Ptr it2(m_operand2->evaluateSequence(context));
    Item::List cache;
    Item item2;

    while(true)
    {
        item2 = it2->next();
        if(!item2)
            break;

        if(generalCompare(item1, item2, context))
            return true;

        cache.append(item2);
    }

    while(true)
    {
        item1 = it1->next();

        if(!item1)
            return false;

        const Item::List::const_iterator end(cache.constEnd());
        Item::List::const_iterator it(cache.constBegin());

        for(; it != end; ++it)
            if(generalCompare(item1, *it, context))
                return true;
    }

    Q_ASSERT(false);
    return false;
}
Beispiel #16
0
bool CastableAs::evaluateEBV(const DynamicContext::Ptr &context) const
{
    Item item;

    if(m_operand->staticType()->cardinality().allowsMany())
    {
        const Item::Iterator::Ptr it(m_operand->evaluateSequence(context));
        item = it->next();

        if(it->next())
            return false;
    }
    else
        item = m_operand->evaluateSingleton(context);

    if(item)
        return !cast(item, context).as<AtomicValue>()->hasError();
    else
        return m_targetType->cardinality().allowsEmpty();
}
Beispiel #17
0
void Path::evaluateToSequenceReceiver(const DynamicContext::Ptr &context) const
{
    /* Note, we use the old context for m_operand1. */
    const Item::Iterator::Ptr source(m_operand1->evaluateSequence(context));

    const DynamicContext::Ptr focus(context->createFocus());
    focus->setFocusIterator(source);

    while(source->next())
        m_operand2->evaluateToSequenceReceiver(focus);
}
Item CardinalityVerifier::evaluateSingleton(const DynamicContext::Ptr &context) const
{
    if(m_allowsMany)
    {
        const Item::Iterator::Ptr it(m_operand->evaluateSequence(context));
        const Item item(it->next());

        if(item)
        {
            if(it->next())
            {
                context->error(wrongCardinality(m_reqCard, Cardinality::twoOrMore()),
                               m_errorCode, this);
                return Item();
            }
            else
                return item;
        }
        else if(m_reqCard.allowsEmpty())
            return Item();
        else
        {
            context->error(wrongCardinality(m_reqCard), m_errorCode, this);
            return Item();
        }
    }
    else
    {
        const Item item(m_operand->evaluateSingleton(context));

        if(item)
            return item;
        else if(m_reqCard.allowsEmpty())
            return Item();
        else
        {
            context->error(wrongCardinality(m_reqCard), m_errorCode, this);
            return Item();
        }
    }
}
Item::Iterator::Ptr IdrefFN::evaluateSequence(const DynamicContext::Ptr &context) const
{
    const Item::Iterator::Ptr ids(m_operands.first()->evaluateSequence(context));

    Item mId(ids->next());
    if(!mId)
        return CommonValues::emptyIterator;

    const Item node(m_operands.last()->evaluateSingleton(context));
    checkTargetNode(node.asNode(), context, ReportContext::FODC0001);

    return CommonValues::emptyIterator; /* TODO Haven't implemented further. */
}
Beispiel #20
0
void CopyOf::evaluateToSequenceReceiver(const DynamicContext::Ptr &context) const
{
    /* Optimization: this completely breaks streaming. We get a call to
     * evaluateToSequenceReceiver() but we require heap allocations by calling
     * evaluateSequence(). */

    const Item::Iterator::Ptr it(m_operand->evaluateSequence(context));
    QAbstractXmlReceiver *const receiver = context->outputReceiver();
    Item next(it->next());

    while(next)
    {
        if(next.isNode())
        {
            const QXmlNodeModelIndex &asNode = next.asNode();
            asNode.model()->copyNodeTo(asNode, receiver, m_settings);
        }
        else
            receiver->item(next);

        next = it->next();
    }
}
Beispiel #21
0
bool InstanceOf::evaluateEBV(const DynamicContext::Ptr &context) const
{
    const Item::Iterator::Ptr it(m_operand->evaluateSequence(context));
    Item item(it->next());
    unsigned int count = 1;

    if(!item)
        return m_targetType->cardinality().allowsEmpty();

    do
    {
        if(!m_targetType->itemType()->itemMatches(item))
            return false;

        if(count == 2 && !m_targetType->cardinality().allowsMany())
            return false;

        item = it->next();
        ++count;
    } while(item);

    return true;
}
Item SimpleContentConstructor::evaluateSingleton(const DynamicContext::Ptr &context) const
{
    const Item::Iterator::Ptr it(m_operand->evaluateSequence(context));
    Item next(it->next());
    QString result;

    if(next)
    {
        result = next.stringValue();
        next = it->next();
    }
    else
        return Item();

    while(next)
    {
        result += QLatin1Char(' ');
        result += next.stringValue();
        next = it->next();
    }

    return AtomicString::fromValue(result);
}
Beispiel #23
0
Item Path::evaluateSingleton(const DynamicContext::Ptr &context) const
{
    /* This function is called if both operands' cardinality is exactly-one. Therefore
     * we manually go forward in the focus by calling next().
     *
     * We don't check for XPTY0018, only in evaluateSequence(), since if we're guaranteed
     * to evaluate to one item, we can only evaluate to one node or one atomic value.
     */

    /* Note, we use the old context for m_operand1. */
    const Item::Iterator::Ptr source(m_operand1->evaluateSequence(context));

    const DynamicContext::Ptr focus(context->createFocus());
    focus->setFocusIterator(source);

    /* This test is needed because if the focus is empty, we don't want to(nor can't) evaluate
     * the next step. */
    // TODO Why are we at all invoked then?
    if(source->next())
        return m_operand2->evaluateSingleton(focus);
    else
        return Item();
}
Beispiel #24
0
bool Boolean::evaluateEBV(const Item::Iterator::Ptr &it,
                          const QExplicitlySharedDataPointer<DynamicContext> &context)
{
    return evaluateEBV(it->next(), it, context);
}
Beispiel #25
0
Item
ComparingAggregator<oper, result>::evaluateSingleton(const DynamicContext::Ptr &context) const
{
    const Item::Iterator::Ptr it(m_operands.first()->evaluateSequence(context));
    Item largest;

    while(true)
    {
        Item next(it->next());

        if(!next)
        {
            return largest;
        }

        AtomicComparator::Ptr comp(comparator());

        if(!comp)
        {
            ItemType::Ptr t1(next.type());
            Q_ASSERT(t1);

            if(BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(t1))
            {
                next = cast(next, context);
                t1 = BuiltinTypes::xsDouble;
            }

            if(!largest)
            {
                largest = next;
                continue;
            }

            Q_ASSERT(largest);
            comp = fetchComparator(largest.type(), t1, context);
            Q_ASSERT(comp);
        }
        else if(!largest)
        {
            largest = next;
            continue;
        }

        if(comp->compare(next, operatorID(), largest) == result)
        {
            largest = applyNumericPromotion(largest, next, next);
            continue;
        }

        const ItemType::Ptr t(next.type());

        if(BuiltinTypes::xsDouble->xdtTypeMatches(t) &&
           next.as<Numeric>()->isNaN())
        {
            return CommonValues::DoubleNaN;
        }
        else if(BuiltinTypes::xsFloat->xdtTypeMatches(t) &&
                next.as<Numeric>()->isNaN())
        {
            if(BuiltinTypes::xsDouble->xdtTypeMatches(largest.type()))
                return CommonValues::DoubleNaN;

            /* If we have a xs:double somewhere, we must promote the NaN value to xs:double,
             * and we really should raise error on invalid value. */
            largest = it->next();

            while(largest)
            {
                const ItemType::Ptr tf(largest.type());
                if(BuiltinTypes::xsDouble->xdtTypeMatches(tf))
                    return CommonValues::DoubleNaN;
                else if(BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(tf))
                {
                    /* Attempt a convert, which will raise an error if it doesn't work out. */
                    cast(largest, context);
                    return CommonValues::DoubleNaN;
                }
                else if(!BuiltinTypes::numeric->xdtTypeMatches(tf))
                {
                    fetchComparator(BuiltinTypes::xsFloat, tf, context);
                }
                else
                    largest = it->next();
            };

            return CommonValues::FloatNaN;
        }
        else
            largest = applyNumericPromotion(largest, next, largest);
    }
}