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::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; }
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; }
Expression::Ptr Expression::constantPropagate(const StaticContext::Ptr &context) const { Q_ASSERT(context); /* Optimization: We rewrite literals to literals here, which is pointless. * Maybe we should have a property which says "doesn't disable elimination * but don't eliminate me." */ if(staticType()->cardinality().allowsMany()) { Item::Iterator::Ptr it(evaluateSequence(context->dynamicContext())); Item::List result; Item item(it->next()); while(item) { result.append(item); item = it->next(); } switch(result.count()) { case 0: return EmptySequence::create(this, context); case 1: return rewrite(Expression::Ptr(new Literal(result.first())), context); default: return rewrite(Expression::Ptr(new LiteralSequence(result)), context); } } else { const Item item(evaluateSingleton(context->dynamicContext())); if(item) return rewrite(Expression::Ptr(new Literal(item)), context); else return EmptySequence::create(this, context); } }