Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qqmldompath.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3#include "qqmldomitem_p.h"
5#include <QtCore/QDebug>
6#include <QtCore/QTextStream>
7#include <QtCore/QChar>
8
9#include <cstdint>
10
12namespace QQmlJS {
13namespace Dom {
14class ErrorMessage;
15
16namespace PathEls {
17
77void Base::dump(const Sink &sink, const QString &name, bool hasSquareBrackets) const {
79 sink(u"[");
80 sink(name);
82 sink(u"]");
83}
84
85Filter::Filter(const function<bool(const DomItem &)> &f, QStringView filterDescription)
86 : filterFunction(f), filterDescription(filterDescription) {}
87
89 return QLatin1String("?(%1)").arg(filterDescription); }
90
92{
93 return s.startsWith(u"?(")
94 && s.mid(2, s.size()-3) == filterDescription
95 && s.endsWith(u")");
96}
97
98enum class ParserState{
99 Start,
101 End
102};
103
105{
106 int k1 = static_cast<int>(p1.kind());
107 int k2 = static_cast<int>(p2.kind());
108 if (k1 < k2)
109 return -1;
110 if (k1 > k2)
111 return 1;
112 switch (p1.kind()) {
113 case Kind::Empty:
114 return 0;
115 case Kind::Field:
116 return std::get<Field>(p1.m_data).fieldName.compare(std::get<Field>(p2.m_data).fieldName);
117 case Kind::Index:
118 if (std::get<Index>(p1.m_data).indexValue < std::get<Index>(p2.m_data).indexValue)
119 return -1;
120 if (std::get<Index>(p1.m_data).indexValue > std::get<Index>(p2.m_data).indexValue)
121 return 1;
122 return 0;
123 case Kind::Key:
124 return std::get<Key>(p1.m_data).keyValue.compare(std::get<Key>(p2.m_data).keyValue);
125 case Kind::Root:
126 {
127 PathRoot k1 = std::get<Root>(p1.m_data).contextKind;
128 PathRoot k2 = std::get<Root>(p2.m_data).contextKind;
131 if (k2 == PathRoot::Env || k2 == PathRoot::Universe)
132 k2 = PathRoot::Top;
133 int c = int(k1) - int(k2);
134 if (c != 0)
135 return c;
136 return std::get<Root>(p1.m_data).contextName.compare(std::get<Root>(p2.m_data).contextName);
137 }
138 case Kind::Current:
139 {
140 int c = int(std::get<Current>(p1.m_data).contextKind)
141 - int(std::get<Current>(p2.m_data).contextKind);
142 if (c != 0)
143 return c;
144 return std::get<Current>(p1.m_data).contextName
145 .compare(std::get<Current>(p2.m_data).contextName);
146 }
147 case Kind::Any:
148 return 0;
149 case Kind::Filter:
150 {
151 int c = std::get<Filter>(p1.m_data).filterDescription
152 .compare(std::get<Filter>(p2.m_data).filterDescription);
153 if (c != 0)
154 return c;
155 if (std::get<Filter>(p1.m_data).filterDescription.startsWith(u"<")) {
156 // assuming non comparable native code (target comparison is not portable)
157 auto pp1 = &p1;
158 auto pp2 = &p2;
159 if (pp1 < pp2)
160 return -1;
161 if (pp1 > pp2)
162 return 1;
163 }
164 return 0;
165 }
166 }
167 Q_ASSERT(false && "unexpected PathComponent in PathComponent::cmp");
168 return 0;
169}
170
171} // namespace PathEls
172
173const PathEls::PathComponent &Path::component(int i) const
174{
175 static Component emptyComponent;
176 if (i < 0)
177 i += m_length;
178 if (i >= m_length || i < 0) {
179 Q_ASSERT(false && "index out of bounds");
180 return emptyComponent;
181 }
182 i = i - m_length - m_endOffset;
183 auto data = m_data.get();
184 while (data) {
185 i += data->components.size();
186 if (i >= 0)
187 return std::as_const(data)->components[i];
188 data = data->parent.get();
189 }
190 Q_ASSERT(false && "Invalid data reached while resolving a seemengly valid index in Path (inconsisten Path object)");
191 return emptyComponent;
192}
193
195{
196 return mid(i,1);
197}
198
199QQmlJS::Dom::Path::operator bool() const
200{
201 return length() != 0;
202}
203
205{
206 return PathIterator{*this};
207}
208
210{
211 return PathIterator();
212}
213
215{
216 auto &comp = component(0);
217 if (PathEls::Root const * r = comp.asRoot())
218 return r->contextKind;
219 return PathRoot::Other;
220}
221
223{
224 auto comp = component(0);
225 if (PathEls::Current const * c = comp.asCurrent())
226 return c->contextKind;
227 return PathCurrent::Other;
228}
229
231{
232 if (m_length == 0)
233 return Path::Kind::Empty;
234 return component(0).kind();
235}
236
238{
239 return component(0).name();
240}
241
243{
244 return component(0).checkName(name);
245}
246
248{
249 return component(0).index(defaultValue);
250}
251
252function<bool(const DomItem &)> Path::headFilter() const
253{
254 auto &comp = component(0);
255 if (PathEls::Filter const * f = comp.asFilter()) {
256 return f->filterFunction;
257 }
258 return {};
259}
260
262{
263 return mid(0,1);
264}
265
267{
268 return mid(m_length-1, 1);
269}
270
272{
273 int i = length();
274 while (i>0) {
275 const PathEls::PathComponent &c=component(--i);
276 if (c.kind() == Kind::Field || c.kind() == Kind::Root || c.kind() == Kind::Current) {
277 return Source{mid(0, i), mid(i)};
278 }
279 }
280 return Source{Path(), *this};
281}
282
284{
285 if (quintptr(base.constData()) > quintptr(el.begin())
286 || quintptr(base.constData() + base.size()) < quintptr(el.begin()))
287 return false;
288 ptrdiff_t diff = base.constData() - el.begin();
289 return diff >= 0 && diff < base.size();
290}
291
292bool inQString(const QString &el, const QString &base)
293{
294 if (quintptr(base.constData()) > quintptr(el.constData())
295 || quintptr(base.constData() + base.size()) < quintptr(el.constData()))
296 return false;
297 ptrdiff_t diff = base.constData() - el.constData();
298 return diff >= 0 && diff < base.size() && diff + el.size() < base.size();
299}
300
302{
303 if (s.isEmpty())
304 return Path();
305 int len=1;
306 const QChar dot = QChar::fromLatin1('.');
307 const QChar lsBrace = QChar::fromLatin1('[');
308 const QChar rsBrace = QChar::fromLatin1(']');
309 const QChar dollar = QChar::fromLatin1('$');
310 const QChar at = QChar::fromLatin1('@');
311 const QChar quote = QChar::fromLatin1('"');
312 const QChar backslash = QChar::fromLatin1('\\');
313 const QChar underscore = QChar::fromLatin1('_');
314 const QChar tilda = QChar::fromLatin1('~');
315 for (int i=0; i < s.size(); ++i)
316 if (s.at(i) == lsBrace || s.at(i) == dot)
317 ++len;
318 QVector<Component> components;
319 components.reserve(len);
320 int i = 0;
321 int i0 = 0;
323 QStringList strVals;
324 while (i < s.size()) {
325 // skip space
326 while (i < s.size() && s.at(i).isSpace())
327 ++i;
328 if (i >= s.size())
329 break;
330 QChar c = s.at(i++);
331 switch (state) {
333 if (c == dollar) {
334 i0 = i;
335 while (i < s.size() && s.at(i).isLetterOrNumber()){
336 ++i;
337 }
338 components.append(Component(PathEls::Root(s.mid(i0,i-i0))));
340 } else if (c == at) {
341 i0 = i;
342 while (i < s.size() && s.at(i).isLetterOrNumber()){
343 ++i;
344 }
345 components.append(Component(PathEls::Current(s.mid(i0,i-i0))));
347 } else if (c.isLetter()) {
348 myErrors().warning(tr("Field expressions should start with a dot, even when at the start of the path %1.")
349 .arg(s)).handle(errorHandler);
350 return Path();
351 } else {
352 --i;
354 }
355 break;
357 if (c.isDigit()) {
358 i0 = i-1;
359 while (i < s.size() && s.at(i).isDigit())
360 ++i;
361 bool ok;
362 components.append(Component(static_cast<index_type>(s.mid(i0,i-i0).toString()
363 .toLongLong(&ok))));
364 if (!ok) {
365 myErrors().warning(tr("Error extracting integer from '%1' at char %2.")
366 .arg(s.mid(i0,i-i0))
367 .arg(QString::number(i0))).handle(errorHandler);
368 }
369 } else if (c.isLetter() || c == tilda || c == underscore) {
370 i0 = i-1;
371 while (i < s.size() && (s.at(i).isLetterOrNumber() || s.at(i) == underscore || s.at(i) == tilda))
372 ++i;
373 components.append(Component(PathEls::Key(s.mid(i0, i - i0).toString())));
374 } else if (c == quote) {
375 i0 = i;
376 QString strVal;
377 bool properEnd = false;
378 while (i < s.size()) {
379 c = s.at(i);
380 if (c == quote) {
381 properEnd = true;
382 break;
383 } else if (c == backslash) {
384 strVal.append(s.mid(i0, i - i0).toString());
385 c = s.at(++i);
386 i0 = i + 1;
387 if (c == QChar::fromLatin1('n'))
388 strVal.append(QChar::fromLatin1('\n'));
389 else if (c == QChar::fromLatin1('r'))
390 strVal.append(QChar::fromLatin1('\r'));
391 else if (c == QChar::fromLatin1('t'))
392 strVal.append(QChar::fromLatin1('\t'));
393 else
394 strVal.append(c);
395 }
396 ++i;
397 }
398 if (properEnd) {
399 strVal.append(s.mid(i0, i - i0).toString());
400 ++i;
401 } else {
402 myErrors().error(tr("Unclosed quoted string at char %1.")
403 .arg(QString::number(i - 1))).handle(errorHandler);
404 return Path();
405 }
406 components.append(PathEls::Key(strVal));
407 } else if (c == QChar::fromLatin1('*')) {
409 } else if (c == QChar::fromLatin1('?')) {
410 while (i < s.size() && s.at(i).isSpace())
411 ++i;
412 if (i >= s.size() || s.at(i) != QChar::fromLatin1('(')) {
413 myErrors().error(tr("Expected a brace in filter after the question mark (at char %1).")
414 .arg(QString::number(i))).handle(errorHandler);
415 return Path();
416 }
417 i0 = ++i;
418 while (i < s.size() && s.at(i) != QChar::fromLatin1(')')) ++i; // check matching braces when skipping??
419 if (i >= s.size() || s.at(i) != QChar::fromLatin1(')')) {
420 myErrors().error(tr("Expected a closing brace in filter after the question mark (at char %1).")
421 .arg(QString::number(i))).handle(errorHandler);
422 return Path();
423 }
424 //auto filterDesc = s.mid(i0,i-i0);
425 ++i;
426 myErrors().error(tr("Filter from string not yet implemented.")).handle(errorHandler);
427 return Path();
428 } else {
429 myErrors().error(tr("Unexpected character '%1' after square bracket at %2.")
430 .arg(c).arg(i-1)).handle(errorHandler);
431 return Path();
432 }
433 while (i < s.size() && s.at(i).isSpace()) ++i;
434 if (i >= s.size() || s.at(i) != rsBrace) {
435 myErrors().error(tr("square braces misses closing brace at char %1.")
436 .arg(QString::number(i))).handle(errorHandler);
437 return Path();
438 } else {
439 ++i;
440 }
442 break;
444 if (c == dot) {
445 while (i < s.size() && s.at(i).isSpace()) ++i;
446 if (i == s.size()) {
447 components.append(Component());
449 } else if (s.at(i).isLetter() || s.at(i) == underscore || s.at(i) == tilda) {
450 i0 = i;
451 while (i < s.size() && (s.at(i).isLetterOrNumber() || s.at(i) == underscore || s.at(i) == tilda)) {
452 ++i;
453 }
454 components.append(Component(PathEls::Field(s.mid(i0,i-i0))));
456 } else if (s.at(i).isDigit()) {
457 i0 = i;
458 while (i < s.size() && s.at(i).isDigit()){
459 ++i;
460 }
461 bool ok;
462 components.append(Component(static_cast<index_type>(s.mid(i0,i-i0).toString().toLongLong(&ok))));
463 if (!ok) {
464 myErrors().warning(tr("Error extracting integer from '%1' at char %2.")
465 .arg(s.mid(i0,i-i0))
466 .arg(QString::number(i0))).handle(errorHandler);
467 return Path();
468 } else {
469 myErrors().info(tr("Index should use square brackets and not a dot (at char %1).")
470 .arg(QString::number(i0))).handle(errorHandler);
471 }
473 } else if (s.at(i) == dot || s.at(i) == lsBrace) {
474 components.append(Component());
476 } else if (s.at(i) == at) {
477 i0 = ++i;
478 while (i < s.size() && s.at(i).isLetterOrNumber()){
479 ++i;
480 }
481 components.append(Component(PathEls::Current(s.mid(i0,i-i0))));
483 } else if (s.at(i) == dollar) {
484 i0 = ++i;
485 while (i < s.size() && s.at(i).isLetterOrNumber()){
486 ++i;
487 }
488 components.append(Component(PathEls::Root(s.mid(i0,i-i0))));
490 } else {
491 c=s.at(i);
492 myErrors().error(tr("Unexpected character '%1' after dot (at char %2).")
493 .arg(QStringView(&c,1))
494 .arg(QString::number(i-1))).handle(errorHandler);
495 return Path();
496 }
497 } else if (c == lsBrace) {
499 } else {
500 myErrors().error(tr("Unexpected character '%1' after end of component (char %2).")
501 .arg(QStringView(&c,1))
502 .arg(QString::number(i-1))).handle(errorHandler);
503 return Path();
504 }
505 break;
506 }
507 }
508 switch (state) {
510 return Path();
512 errorHandler(myErrors().error(tr("unclosed square brace at end.")));
513
514 return Path();
516 return Path(0, components.size(), std::make_shared<PathEls::PathData>(
517 strVals, components));
518 }
519 Q_ASSERT(false && "Unexpected state in Path::fromString");
520 return Path();
521}
522
524{
525 return Path(0,1,std::make_shared<PathEls::PathData>(
526 QStringList(), QVector<Component>(1,Component(PathEls::Root(s)))));
527}
528
530{
531 return Path(0,1,std::make_shared<PathEls::PathData>(
532 QStringList(s), QVector<Component>(1,Component(PathEls::Root(s)))));
533}
534
536{
537 return Path(0,1,std::make_shared<PathEls::PathData>(
538 QStringList(), QVector<Component>(1,Component(PathEls::Index(i)))));
539}
540
542{
543 return Path(0,1,std::make_shared<PathEls::PathData>(
544 QStringList(), QVector<Component>(1,Component(PathEls::Root(s)))));
545}
546
547
549{
550 return Path(0,1,std::make_shared<PathEls::PathData>(
551 QStringList(), QVector<Component>(1,Component(PathEls::Field(s)))));
552}
553
555{
556 return Path(0,1,std::make_shared<PathEls::PathData>(
557 QStringList(s), QVector<Component>(1,Component(PathEls::Field(s)))));
558}
559
561{
562 return Path(
563 0, 1,
564 std::make_shared<PathEls::PathData>(
565 QStringList(), QVector<Component>(1, Component(PathEls::Key(s.toString())))));
566}
567
569{
570 return Path(0, 1,
571 std::make_shared<PathEls::PathData>(
572 QStringList(), QVector<Component>(1, Component(PathEls::Key(s)))));
573}
574
576{
577 return Path(0,1,std::make_shared<PathEls::PathData>(
578 QStringList(), QVector<Component>(1,Component(PathEls::Current(s)))));
579}
580
582{
583 return Path(0,1,std::make_shared<PathEls::PathData>(
584 QStringList(s), QVector<Component>(1,Component(PathEls::Current(s)))));
585}
586
588{
589 return Path(0,1,std::make_shared<PathEls::PathData>(
590 QStringList(), QVector<Component>(1,Component(PathEls::Current(s)))));
591}
592
594{
595 return Path();
596}
597
599{
600 if (m_endOffset != 0)
601 return noEndOffset().empty();
602 return Path(0,m_length+1,std::make_shared<PathEls::PathData>(
603 QStringList(), QVector<Component>(1,Component()), m_data));
604}
605
607{
608 auto res = field(QStringView(name));
609 res.m_data->strData.append(name);
610 return res;
611}
612
614{
615 if (m_endOffset != 0)
616 return noEndOffset().field(name);
617 return Path(0,m_length+1,std::make_shared<PathEls::PathData>(
618 QStringList(), QVector<Component>(1,Component(PathEls::Field(name))), m_data));
619}
620
622{
623 if (m_endOffset != 0)
624 return noEndOffset().key(name);
625 return Path(0,m_length+1,std::make_shared<PathEls::PathData>(
626 QStringList(), QVector<Component>(1,Component(PathEls::Key(name))), m_data));
627}
628
630{
631 return key(name.toString());
632}
633
635{
636 if (m_endOffset != 0)
637 return noEndOffset().index(i);
638 return Path(0,m_length+1,std::make_shared<PathEls::PathData>(
639 QStringList(), QVector<Component>(1,Component(i)), m_data));
640}
641
643{
644 if (m_endOffset != 0)
645 return noEndOffset().any();
646 return Path(0,m_length+1,std::make_shared<PathEls::PathData>(
647 QStringList(), QVector<Component>(1,Component(PathEls::Any())), m_data));
648}
649
650Path Path::filter(const function<bool(const DomItem &)> &filterF, const QString &desc) const
651{
652 auto res = filter(filterF, QStringView(desc));
653 res.m_data->strData.append(desc);
654 return res;
655}
656
657Path Path::filter(const function<bool(const DomItem &)> &filter, QStringView desc) const
658{
659 if (m_endOffset != 0)
660 return noEndOffset().filter(filter, desc);
661 return Path(0,m_length+1,std::make_shared<PathEls::PathData>(
662 QStringList(), QVector<Component>(1,Component(PathEls::Filter(filter, desc))), m_data));
663}
664
666{
667 return Path(0,m_length+1,std::make_shared<PathEls::PathData>(
668 QStringList(), QVector<Component>(1,Component(PathEls::Current(s))), m_data));
669}
670
672{
673 auto res = current(QStringView(s));
674 res.m_data->strData.append(s);
675 return res;
676}
677
679{
680 if (m_endOffset != 0)
681 return noEndOffset().current(s);
682 return Path(0,m_length+1,std::make_shared<PathEls::PathData>(
683 QStringList(), QVector<Component>(1,Component(PathEls::Current(s))), m_data));
684}
685
686Path Path::path(const Path &toAdd, bool avoidToAddAsBase) const
687{
688 if (toAdd.length() == 0)
689 return *this;
690 int resLength = length() + toAdd.length();
691 if (m_endOffset != 0) {
692 Path thisExtended = this->expandBack();
693 if (thisExtended.length() > resLength)
694 thisExtended = thisExtended.mid(0, resLength);
695 Path added = thisExtended.mid(length(), thisExtended.length() - length());
696 if (added == toAdd.mid(0, toAdd.length())) {
697 if (resLength == thisExtended.length())
698 return thisExtended;
699 else
700 return thisExtended.path(toAdd.mid(added.length(), resLength - thisExtended.length()));
701 }
702 }
703 if (!avoidToAddAsBase) {
704 Path toAddExtended = toAdd.expandFront();
705 if (toAddExtended.length() >= resLength) {
706 toAddExtended = toAddExtended.mid(toAddExtended.length() - resLength, resLength);
707 if (toAddExtended.mid(0,length()) == *this)
708 return toAddExtended;
709 }
710 }
711 QVector<Component> components;
712 components.reserve(toAdd.length());
713 QStringList addedStrs;
714 bool addHasStr = false;
715 auto data = toAdd.m_data.get();
716 while (data) {
717 if (!data->strData.isEmpty()) {
718 addHasStr = true;
719 break;
720 }
721 data = data->parent.get();
722 }
723 if (addHasStr) {
724 QStringList myStrs;
725 data = m_data.get();
726 while (data) {
727 myStrs.append(data->strData);
728 data = data->parent.get();
729 }
730 data = toAdd.m_data.get();
731 while (data) {
732 for (int ij = 0; ij < data->strData.size(); ++ij) {
733 bool hasAlready = false;
734 for (int ii = 0; ii < myStrs.size() && !hasAlready; ++ii)
735 hasAlready = inQString(data->strData[ij], myStrs[ii]);
736 if (!hasAlready)
737 addedStrs.append(data->strData[ij]);
738 }
739 data = data->parent.get();
740 }
741 }
742 QStringList toAddStrs;
743 for (int i = 0; i < toAdd.length(); ++i) {
744 components.append(toAdd.component(i));
745 QStringView compStrView = toAdd.component(i).stringView();
746 if (!compStrView.isEmpty()) {
747 for (int j = 0; j < addedStrs.size(); ++j) {
748 if (inQString(compStrView, addedStrs[j])) {
749 toAddStrs.append(addedStrs[j]);
750 addedStrs.removeAt(j);
751 break;
752 }
753 }
754 }
755 }
756 return Path(0, m_length + toAdd.length(), std::make_shared<PathEls::PathData>(
757 toAddStrs, components, ((m_endOffset == 0) ? m_data : noEndOffset().m_data)));
758}
759
761{
762 int newLen = 0;
763 auto data = m_data.get();
764 while (data) {
765 newLen += data->components.size();
766 data = data->parent.get();
767 }
768 newLen -= m_endOffset;
769 return Path(m_endOffset, newLen, m_data);
770}
771
773{
774 if (m_endOffset > 0)
775 return Path(0, m_length + m_endOffset, m_data);
776 return *this;
777}
778
780{
781 if (m_length > 0)
782 m_length -= 1;
783 return *this;
784}
785
787{
788 Path res = *this;
789 if (m_length > 0)
790 m_length -= 1;
791 return res;
792}
793
794int Path::cmp(const Path &p1, const Path &p2)
795{
796 // lexicographic ordering
797 const int lMin = qMin(p1.m_length, p2.m_length);
798 if (p1.m_data.get() == p2.m_data.get() && p1.m_endOffset == p2.m_endOffset && p1.m_length == p2.m_length)
799 return 0;
800 for (int i = 0; i < lMin; ++i) {
801 int c = Component::cmp(p1.component(i), p2.component(i));
802 if (c != 0)
803 return c;
804 }
805 if (lMin < p2.m_length)
806 return -1;
807 if (p1.m_length > lMin)
808 return 1;
809 return 0;
810}
811
812Path::Path(quint16 endOffset, quint16 length, const std::shared_ptr<PathEls::PathData> &data)
813 :m_endOffset(endOffset), m_length(length), m_data(data)
814{
815}
816
817Path Path::noEndOffset() const
818{
819 if (m_length == 0)
820 return Path();
821 if (m_endOffset == 0)
822 return *this;
823 // peel back
824 qint16 endOffset = m_endOffset;
825 std::shared_ptr<PathEls::PathData> lastData = m_data;
826 while (lastData && endOffset >= lastData->components.size()) {
827 endOffset -= lastData->components.size();
828 lastData = lastData->parent;
829 }
830 if (endOffset > 0) {
831 Q_ASSERT(lastData && "Internal problem, reference to non existing PathData");
832 return Path(0, m_length, std::make_shared<PathEls::PathData>(
833 lastData->strData, lastData->components.mid(0, lastData->components.size() - endOffset), lastData->parent));
834 }
835 return Path(0, m_length, lastData);
836}
837
839{
840 if (m_endOffset != 0) {
841 Path newP = noEndOffset();
842 return newP.appendComponent(c);
843 }
844 if (m_data && m_data.use_count() != 1) {
845 // create a new path (otherwise paths linking to this will change)
846 Path newP(c);
847 newP.m_data->parent = m_data;
848 newP.m_length = static_cast<quint16>(m_length + 1);
849 return newP;
850 }
851 auto my_data =
852 (m_data ? m_data
853 : std::make_shared<PathEls::PathData>(QStringList(),
854 QVector<PathEls::PathComponent>()));
855 switch (c.kind()) {
859 // no string
861 // string assumed to stay valid (Fields::...)
862 my_data->components.append(c);
863 break;
865 if (c.asCurrent()->contextKind == PathCurrent::Other) {
866 my_data->strData.append(c.asCurrent()->contextName.toString());
867 my_data->components.append(PathEls::Current(my_data->strData.last()));
868 } else {
869 my_data->components.append(c);
870 }
871 break;
873 if (!c.asFilter()->filterDescription.isEmpty()) {
874 my_data->strData.append(c.asFilter()->filterDescription.toString());
875 my_data->components.append(
876 PathEls::Filter(c.asFilter()->filterFunction, my_data->strData.last()));
877 } else {
878 my_data->components.append(c);
879 }
880 break;
882 my_data->components.append(c);
883 break;
885 if (c.asRoot()->contextKind == PathRoot::Other) {
886 my_data->strData.append(c.asRoot()->contextName.toString());
887 my_data->components.append(PathEls::Root(my_data->strData.last()));
888 } else {
889 my_data->components.append(c);
890 }
891 break;
892 }
893 if (m_data)
894 m_endOffset = 1;
895 return Path { 0, static_cast<quint16>(m_length + 1), my_data };
896}
897
899{
900 static ErrorGroups res = {{NewErrorGroup("PathParsing")}};
901 return res;
902}
903
904void Path::dump(const Sink &sink) const
905{
906 bool first = true;
907 for (int i = 0; i < m_length; ++i) {
908 auto &c = component(i);
909 if (!c.hasSquareBrackets()) {
910 if (!first || (c.kind() != Kind::Root && c.kind() != Kind::Current))
911 sink(u".");
912 }
913 c.dump(sink);
914 first = false;
915 }
916}
917
919{
920 QString res;
922 dump([&stream](QStringView str){ stream << str; });
923 stream.flush();
924 return res;
925}
926
928{
929 if (m_length > n && n >= 0)
930 return Path(m_endOffset, m_length - n, m_data);
931 return Path();
932}
933
935{
936 if (m_length > n && n >= 0)
937 return Path(m_endOffset + n, m_length - n, m_data);
938 return Path();
939}
940
942{
943 length = qMin(m_length - offset, length);
944 if (offset < 0 || offset >= m_length || length <= 0 || length > m_length)
945 return Path();
946 int newEndOffset = m_endOffset + m_length - offset - length;
947 return Path(newEndOffset, length, m_data);
948}
949
951{
952 return mid(offset, m_length - offset);
953}
954
955Path Path::fromString(const QString &s, const ErrorHandler &errorHandler)
956{
957 Path res = fromString(QStringView(s), errorHandler);
958 if (res.m_data)
959 res.m_data->strData.append(s);
960 return res;
961}
962
963} // end namespace Dom
964} // end namespace QQmlJS
966
967#include "moc_qqmldompath_p.cpp"
NSData * m_data
\inmodule QtCore
QString arg(Args &&...args) const
Represents a set of tags grouping a set of related error messages.
void dump(const Sink &sink, const QString &name, bool hasSquareBrackets) const
bool checkName(QStringView s) const
bool checkName(QStringView s) const
static int cmp(const PathComponent &p1, const PathComponent &p2)
index_type index(index_type defaultValue=-1) const
PathCurrent headCurrent() const
Path dropTail(int n=1) const
index_type headIndex(index_type defaultValue=-1) const
static Path Key(QStringView s=u"")
static int cmp(const Path &p1, const Path &p2)
static Path Root(PathRoot r)
Path key(const QString &name) const
Path expandBack() const
Path field(const QString &name) const
QString headName() const
Path appendComponent(const PathEls::PathComponent &c)
Source split() const
PathIterator begin() const
Path current(PathCurrent s) const
Path filter(const std::function< bool(const DomItem &)> &, const QString &) const
static ErrorGroups myErrors()
bool checkHeadName(QStringView name) const
Path operator[](int i) const
static Path Index(index_type i)
Path path(const Path &toAdd, bool avoidToAddAsBase=false) const
Path empty() const
Path head() const
Path mid(int offset, int length) const
Path expandFront() const
void dump(const Sink &sink) const
Path last() const
Kind headKind() const
static Path Empty()
static Path fromString(const QString &s, const ErrorHandler &errorHandler=nullptr)
QString toString() const
static Path Field(QStringView s=u"")
PathIterator end() const
std::function< bool(const DomItem &) headFilter)() const
Path index(index_type i) const
Path dropFront(int n=1) const
static Path Current(PathCurrent c)
PathEls::PathComponent Component
PathRoot headRoot() const
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:78
constexpr qsizetype size() const noexcept
Returns the size of this string view, in UTF-16 code units (that is, surrogate pairs count as two for...
const_iterator begin() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first character in the st...
bool endsWith(QStringView s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
const_pointer constData() const noexcept
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition qstring.cpp:5455
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1226
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8084
\inmodule QtCore
QString str
[2]
QPixmap p2
QPixmap p1
[0]
else opt state
[0]
qint64 index_type
bool inQString(QStringView el, const QString &base)
std::function< void(const ErrorMessage &)> ErrorHandler
Combined button and popup list for selecting options.
QList< QString > QStringList
Constructs a string list that contains the given string, str.
DBusConnection const char DBusError * error
EGLStreamKHR stream
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
GLuint64 key
GLint GLenum GLint components
GLboolean r
[2]
GLenum GLuint GLenum GLsizei length
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat f
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
GLenum GLuint GLintptr offset
GLuint name
GLint first
GLfloat n
GLdouble s
[6]
Definition qopenglext.h:235
GLuint res
const GLubyte * c
GLsizei GLenum GLboolean sink
GLenum GLsizei len
static qreal dot(const QPointF &a, const QPointF &b)
#define NewErrorGroup(name)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int void * arg
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define k1
#define tr(X)
short qint16
Definition qtypes.h:47
unsigned short quint16
Definition qtypes.h:48
size_t quintptr
Definition qtypes.h:167
static const uint base
Definition qurlidna.cpp:20
static QString quote(const QString &str)
QAction * at
QStringView el