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); }
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); }
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; }
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(); }
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; }; }
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; } } }
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(); }
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); }
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(); } }
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; }
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(); }
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. */ }
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(); } }
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); }
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(); }
bool Boolean::evaluateEBV(const Item::Iterator::Ptr &it, const QExplicitlySharedDataPointer<DynamicContext> &context) { return evaluateEBV(it->next(), it, context); }
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); } }