5#include <QtCore/QDebug>
6#include <QtCore/QTextStream>
19
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
179void Base::
dump(
const Sink &sink,
const QString &name,
bool hasSquareBrackets)
const {
180 if (hasSquareBrackets)
183 if (hasSquareBrackets)
187Filter::
Filter(
const function<
bool(
const DomItem &)> &f, QStringView filterDescription)
191 return QLatin1String(
"?(%1)").arg(filterDescription); }
195 return s.startsWith(u"?(")
196 && s.mid(2, s.size()-3) == filterDescription
208 int k1 =
static_cast<
int>(p1
.kind());
209 int k2 =
static_cast<
int>(p2
.kind());
218 return std::get<Field>(p1.m_data).fieldName.compare(
std::get<Field>(p2.m_data).fieldName);
220 if (
std::get<Index>(p1.m_data).indexValue <
std::get<Index>(p2.m_data).indexValue)
222 if (
std::get<Index>(p1.m_data).indexValue >
std::get<Index>(p2.m_data).indexValue)
226 return std::get<Key>(p1.m_data).keyValue.compare(
std::get<Key>(p2.m_data).keyValue);
229 PathRoot k1 =
std::get<Root>(p1.m_data).contextKind;
230 PathRoot k2 =
std::get<Root>(p2.m_data).contextKind;
235 int c =
int(k1) -
int(k2);
238 return std::get<Root>(p1.m_data).contextName.compare(
std::get<Root>(p2.m_data).contextName);
242 int c =
int(
std::get<Current>(p1.m_data).contextKind)
243 -
int(
std::get<Current>(p2.m_data).contextKind);
246 return std::get<Current>(p1.m_data).contextName
247 .compare(
std::get<Current>(p2.m_data).contextName);
253 int c =
std::get<Filter>(p1.m_data).filterDescription
254 .compare(
std::get<Filter>(p2.m_data).filterDescription);
257 if (
std::get<Filter>(p1.m_data).filterDescription.startsWith(u"<")) {
269 Q_ASSERT(
false &&
"unexpected PathComponent in PathComponent::cmp");
276
277
278
279
280
281
282
283
284
290 if (i >= m_length || i < 0) {
291 Q_ASSERT(
false &&
"index out of bounds");
292 return emptyComponent;
294 i = i - m_length - m_endOffset;
295 auto data = m_data.get();
297 i += data->components.size();
299 return std::as_const(data)->components[i];
300 data = data->parent.get();
302 Q_ASSERT(
false &&
"Invalid data reached while resolving a seemengly valid index in Path (inconsisten Path object)");
303 return emptyComponent;
318 return PathIterator{*
this};
328 auto &comp = component(0);
336 auto comp = component(0);
351 return component(0).name();
356 return component(0).checkName(name);
361 return component(0).index(defaultValue);
366 auto &comp = component(0);
368 return f->filterFunction;
380 return mid(m_length-1, 1);
384
385
386
396 return Source{
Path(), *
this};
404 const QChar dot = QChar::fromLatin1(
'.');
405 const QChar lsBrace = QChar::fromLatin1(
'[');
406 const QChar rsBrace = QChar::fromLatin1(
']');
407 const QChar dollar = QChar::fromLatin1(
'$');
408 const QChar at = QChar::fromLatin1(
'@');
409 const QChar quote = QChar::fromLatin1(
'"');
410 const QChar backslash = QChar::fromLatin1(
'\\');
411 const QChar underscore = QChar::fromLatin1(
'_');
412 const QChar tilda = QChar::fromLatin1(
'~');
413 for (
int i=0; i < s.size(); ++i)
414 if (s.at(i) == lsBrace || s.at(i) == dot)
416 QVector<Component> components;
417 components.reserve(len);
421 while (i < s.size()) {
423 while (i < s.size() && s.at(i).isSpace())
432 while (i < s.size() && s.at(i).isLetterOrNumber()){
437 }
else if (c == at) {
439 while (i < s.size() && s.at(i).isLetterOrNumber()){
444 }
else if (c.isLetter()) {
445 myErrors().warning(tr(
"Field expressions should start with a dot, even when at the start of the path %1.")
446 .arg(s)
).handle(errorHandler);
456 while (i < s.size() && s.at(i).isDigit())
459 components.append(
Component(
static_cast<index_type>(s.mid(i0,i-i0).toString()
462 myErrors().warning(tr(
"Error extracting integer from '%1' at char %2.")
464 .arg(QString::number(i0))).handle(errorHandler);
466 }
else if (c.isLetter() || c == tilda || c == underscore) {
468 while (i < s.size() && (s.at(i).isLetterOrNumber() || s.at(i) == underscore || s.at(i) == tilda))
471 }
else if (c == quote) {
474 bool properEnd =
false;
475 while (i < s.size()) {
480 }
else if (c == backslash) {
481 strVal.append(s.mid(i0, i - i0).toString());
484 if (c == QChar::fromLatin1(
'n'))
485 strVal.append(QChar::fromLatin1(
'\n'));
486 else if (c == QChar::fromLatin1(
'r'))
487 strVal.append(QChar::fromLatin1(
'\r'));
488 else if (c == QChar::fromLatin1(
't'))
489 strVal.append(QChar::fromLatin1(
'\t'));
496 strVal.append(s.mid(i0, i - i0).toString());
499 myErrors().error(tr(
"Unclosed quoted string at char %1.")
500 .arg(QString::number(i - 1))).handle(errorHandler);
503 components.append(
PathEls::Key(strVal));
504 }
else if (c == QChar::fromLatin1(
'*')) {
506 }
else if (c == QChar::fromLatin1(
'?')) {
507 while (i < s.size() && s.at(i).isSpace())
509 if (i >= s.size() || s.at(i) != QChar::fromLatin1(
'(')) {
510 myErrors().error(tr(
"Expected a brace in filter after the question mark (at char %1).")
511 .arg(QString::number(i))).handle(errorHandler);
515 while (i < s.size() && s.at(i) != QChar::fromLatin1(
')')) ++i;
516 if (i >= s.size() || s.at(i) != QChar::fromLatin1(
')')) {
517 myErrors().error(tr(
"Expected a closing brace in filter after the question mark (at char %1).")
518 .arg(QString::number(i))).handle(errorHandler);
527 .arg(c).arg(i-1)
).handle(errorHandler);
530 while (i < s.size() && s.at(i).isSpace()) ++i;
531 if (i >= s.size() || s.at(i) != rsBrace) {
532 myErrors().error(tr(
"square braces misses closing brace at char %1.")
533 .arg(QString::number(i))).handle(errorHandler);
542 while (i < s.size() && s.at(i).isSpace()) ++i;
546 }
else if (s.at(i).isLetter() || s.at(i) == underscore || s.at(i) == tilda) {
548 while (i < s.size() && (s.at(i).isLetterOrNumber() || s.at(i) == underscore || s.at(i) == tilda)) {
553 }
else if (s.at(i).isDigit()) {
555 while (i < s.size() && s.at(i).isDigit()){
559 components.append(
Component(
static_cast<index_type>(s.mid(i0,i-i0).toString().toLongLong(&ok))));
561 myErrors().warning(tr(
"Error extracting integer from '%1' at char %2.")
563 .arg(QString::number(i0))).handle(errorHandler);
566 myErrors().info(tr(
"Index should use square brackets and not a dot (at char %1).")
567 .arg(QString::number(i0))).handle(errorHandler);
570 }
else if (s.at(i) == dot || s.at(i) == lsBrace) {
573 }
else if (s.at(i) == at) {
575 while (i < s.size() && s.at(i).isLetterOrNumber()){
580 }
else if (s.at(i) == dollar) {
582 while (i < s.size() && s.at(i).isLetterOrNumber()){
589 myErrors().error(tr(
"Unexpected character '%1' after dot (at char %2).")
590 .arg(QStringView(&c,1))
591 .arg(QString::number(i-1))).handle(errorHandler);
594 }
else if (c == lsBrace) {
597 myErrors().error(tr(
"Unexpected character '%1' after end of component (char %2).")
598 .arg(QStringView(&c,1))
599 .arg(QString::number(i-1))).handle(errorHandler);
614 QStringList(), components));
616 Q_ASSERT(
false &&
"Unexpected state in Path::fromString");
692 if (m_endOffset != 0)
694 return Path(0,m_length+1,std::make_shared<PathEls::PathData>(
695 QStringList(), QVector<Component>(1,Component()), m_data));
700 auto res = withField(QStringView(name));
701 res.m_data->strData.append(name);
707 if (m_endOffset != 0)
708 return noEndOffset().withField(name);
709 return Path(0,m_length+1,std::make_shared<PathEls::PathData>(
710 QStringList(), QVector<Component>(1,Component(PathEls::Field(name))), m_data));
715 if (m_endOffset != 0)
716 return noEndOffset().withKey(name);
717 return Path(0,m_length+1,std::make_shared<PathEls::PathData>(
718 QStringList(), QVector<Component>(1,Component(PathEls::Key(name))), m_data));
723 return withKey(name.toString());
728 if (m_endOffset != 0)
729 return noEndOffset().withIndex(i);
730 return Path(0,m_length+1,std::make_shared<PathEls::PathData>(
731 QStringList(), QVector<Component>(1,Component(i)), m_data));
736 if (m_endOffset != 0)
738 return Path(0,m_length+1,std::make_shared<PathEls::PathData>(
739 QStringList(), QVector<Component>(1,Component(PathEls::Any())), m_data));
744 auto res = withFilter(filterF, QStringView(desc));
745 res.m_data->strData.append(desc);
751 if (m_endOffset != 0)
752 return noEndOffset().withFilter(filter, desc);
753 return Path(0,m_length+1,std::make_shared<PathEls::PathData>(
754 QStringList(), QVector<Component>(1,Component(PathEls::Filter(filter, desc))), m_data));
759 return Path(0,m_length+1,std::make_shared<PathEls::PathData>(
760 QStringList(), QVector<Component>(1,Component(PathEls::Current(s))), m_data));
766 res.m_data->strData.append(s);
772 if (m_endOffset != 0)
774 return Path(0,m_length+1,std::make_shared<PathEls::PathData>(
775 QStringList(), QVector<Component>(1,Component(PathEls::Current(s))), m_data));
783 QVector<Component> components;
784 components.reserve(size);
785 for (
auto it = list.crbegin(), end = list.crend(); it != end; ++it) {
786 for (
auto it2 = (**it).cbegin(), end2 = (**it).cend(); it2 != end2; ++it2) {
787 components.append(*it2);
788 if (components.size() >= size)
799 std::vector<QVector<Component> *> componentList;
800 qsizetype foundComponents = 0;
801 QStringList addedStrs;
802 for (
auto data = pathStart; data; data = data->parent.get()) {
803 addedStrs.append(data->strData);
804 componentList.push_back(&data->components);
805 foundComponents += data->components.size();
807 if (foundComponents >= size)
808 return std::make_pair(componentList, addedStrs);
810 return std::make_pair(componentList, addedStrs);
814
815
816
817
818
824 if (m_endOffset != 0) {
827 thisExtended = thisExtended
.mid(0
, resLength
);
836 if (!avoidToAddAsBase) {
838 if (toAddExtended
.length() >= resLength) {
839 toAddExtended = toAddExtended
.mid(toAddExtended
.length() - resLength
, resLength
);
841 return toAddExtended;
845 const Path toAddNoEndOffset = toAdd.noEndOffset();
846 auto [componentListList, addedStrs] =
847 collectBackwards(toAddNoEndOffset.m_data.get(), toAdd.length());
849 QVector<Component> componentList = reverseAndConcat(componentListList, toAdd.length());
858
859
860
861
862
863
864
865
866
867
868
869
870
871
875 auto data = m_data.get();
877 newLen += data->components.size();
878 data = data->parent.get();
880 newLen -= m_endOffset;
881 return Path(m_endOffset, newLen, m_data);
885
886
887
888
889
890
891
892
893
894
895
896
897
898
902 return Path(0, m_length + m_endOffset, m_data);
924 const int lMin = qMin(p1.m_length, p2.m_length);
925 if (p1.m_data.get() == p2.m_data.get() && p1.m_endOffset == p2.m_endOffset && p1.m_length == p2.m_length)
927 for (
int i = 0; i < lMin; ++i) {
932 if (lMin < p2.m_length)
934 if (p1.m_length > lMin)
940 :m_endOffset(endOffset), m_length(length), m_data(data)
948 if (m_endOffset == 0)
951 qint16 endOffset = m_endOffset;
953 while (lastData && endOffset >= lastData->components.size()) {
954 endOffset -= lastData->components.size();
955 lastData = lastData->parent;
958 Q_ASSERT(lastData &&
"Internal problem, reference to non existing PathData");
959 return Path(0, m_length, std::make_shared<PathEls::PathData>(
960 lastData->strData, lastData->components.mid(0, lastData->components.size() - endOffset), lastData->parent));
962 return Path(0, m_length, lastData);
967 if (m_endOffset != 0) {
968 Path newP = noEndOffset();
971 if (m_data && m_data.use_count() != 1) {
974 newP.m_data->parent = m_data;
975 newP.m_length =
static_cast<quint16>(m_length + 1);
980 : std::make_shared<PathEls::PathData>(QStringList(),
981 QVector<PathEls::PathComponent>()));
989 my_data->components.append(c);
993 my_data->strData.append(c
.asCurrent()->contextName.toString());
994 my_data->components.append(
PathEls::Current(my_data->strData.last()));
996 my_data->components.append(c);
1001 my_data->strData.append(c
.asFilter()->filterDescription.toString());
1002 my_data->components.append(
1005 my_data->components.append(c);
1009 my_data->components.append(c);
1013 my_data->strData.append(c
.asRoot()->contextName.toString());
1014 my_data->components.append(
PathEls::Root(my_data->strData.last()));
1016 my_data->components.append(c);
1022 return Path { 0,
static_cast<quint16>(m_length + 1), my_data };
1034 for (
int i = 0; i < m_length; ++i) {
1035 auto &c = component(i);
1048 QTextStream stream(&res);
1049 dump([&stream](QStringView str){ stream << str; });
1056 if (m_length > n && n >= 0)
1057 return Path(m_endOffset, m_length - n, m_data);
1063 if (m_length > n && n >= 0)
1064 return Path(m_endOffset + n, m_length - n, m_data);
1070 length = qMin(m_length - offset, length);
1071 if (offset < 0 || offset >= m_length || length <= 0 || length > m_length)
1073 int newEndOffset = m_endOffset + m_length - offset - length;
1074 return Path(newEndOffset, length, m_data);
1079 return mid(offset, m_length - offset);
1084 Path res = fromString(QStringView(s), errorHandler);
1086 res.m_data->strData.append(s);
1094#include "moc_qqmldompath_p.cpp"
A value type that references any element of the Dom.
Represents a set of tags grouping a set of related error messages.
ErrorMessage warning(const Dumper &message) const
ErrorMessage error(const Dumper &message) const
Represents an error message connected to the dom.
void dump(const Sink &sink, const QString &name, bool hasSquareBrackets) const
bool checkName(QStringView s) const
Filter(const std::function< bool(const DomItem &)> &f, QStringView filterDescription=u"<native code filter>")
const Filter * asFilter() const
static int cmp(const PathComponent &p1, const PathComponent &p2)
const Current * asCurrent() const
PathComponent(Current &&o)
const Root * asRoot() const
bool hasSquareBrackets() const
Path withCurrent(const QString &s) const
PathCurrent headCurrent() const
Path dropTail(int n=1) const
index_type headIndex(index_type defaultValue=-1) const
Path withIndex(index_type i) const
static int cmp(const Path &p1, const Path &p2)
Path expandBack() const
Expand a path suffix hidden by slicing.
Path withKey(QStringView name) const
Path withPath(const Path &toAdd, bool avoidToAddAsBase=false) const
Returns a copy of this with toAdd appended to it.
Source split() const
Splits the path at the last field, root or current Component.
PathIterator begin() const
static Path fromRoot(PathRoot r)
Path withComponent(const PathEls::PathComponent &c)
static ErrorGroups myErrors()
bool checkHeadName(QStringView name) const
Path operator[](int i) const
Path withKey(const QString &name) const
Path withCurrent(QStringView s=u"") const
Path mid(int offset, int length) const
Path expandFront() const
Expand a path prefix hidden by slicing.
Path withFilter(const std::function< bool(const DomItem &)> &, QStringView desc=u"<native code filter>") const
Path withCurrent(PathCurrent s) const
void dump(const Sink &sink) const
Path withFilter(const std::function< bool(const DomItem &)> &, const QString &) const
Path mid(int offset) const
Path withField(QStringView name) const
std::function< bool(const DomItem &)> headFilter() const
Path dropFront(int n=1) const
Path withField(const QString &name) const
PathEls::PathComponent Component
static Path fromCurrent(PathCurrent c)
PathRoot headRoot() const
Path(const PathEls::PathComponent &c)
static QVector< Path::Component > reverseAndConcat(const std::vector< QVector< Path::Component > * > &list, qsizetype size)
std::function< void(const ErrorMessage &)> ErrorHandler
bool operator==(const Path &lhs, const Path &rhs)
static std::pair< std::vector< QVector< Path::Component > * >, QStringList > collectBackwards(PathEls::PathData *pathStart, qsizetype size)
#define NewErrorGroup(name)