diff options
Diffstat (limited to 'src/qmldom/qqmldompath.cpp')
-rw-r--r-- | src/qmldom/qqmldompath.cpp | 485 |
1 files changed, 270 insertions, 215 deletions
diff --git a/src/qmldom/qqmldompath.cpp b/src/qmldom/qqmldompath.cpp index 60086ced10..d2b4582bc0 100644 --- a/src/qmldom/qqmldompath.cpp +++ b/src/qmldom/qqmldompath.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -**/ -#include "qqmldompath_p.h" +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qqmldomitem_p.h" #include "qqmldomerrormessage_p.h" #include <QtCore/QDebug> @@ -101,8 +65,6 @@ The current contexts are: \li \l{@module} The current module instantiation. \li \l{@ids} The ids in the current component. \li \l{@types} All the types in the current component (reachable through imports, respecting renames) -\li \l{@instantiation} The current instantiation, either component instantiation or module - instantiation \li \l{@lookupStrict} The strict lookup inside the current object: localJS, ids, properties, proto properties, component, its properties, global context, oterwise error \li \l{@lookupDynamic} The default lookup inside the current object: localJS, ids, properties, proto @@ -112,15 +74,16 @@ The current contexts are: \endlist */ -void Base::dump(Sink sink) const { - if (hasSquareBrackets()) +void Base::dump(const Sink &sink, const QString &name, bool hasSquareBrackets) const { + if (hasSquareBrackets) sink(u"["); - sink(name()); - if (hasSquareBrackets()) + sink(name); + if (hasSquareBrackets) sink(u"]"); } -Filter::Filter(function<bool(DomItem)> f, QStringView filterDescription): filterFunction(f), filterDescription(filterDescription) {} +Filter::Filter(const function<bool(const DomItem &)> &f, QStringView filterDescription) + : filterFunction(f), filterDescription(filterDescription) {} QString Filter::name() const { return QLatin1String("?(%1)").arg(filterDescription); } @@ -128,7 +91,7 @@ QString Filter::name() const { bool Filter::checkName(QStringView s) const { return s.startsWith(u"?(") - && s.mid(2, s.length()-3) == filterDescription + && s.mid(2, s.size()-3) == filterDescription && s.endsWith(u")"); } @@ -138,13 +101,6 @@ enum class ParserState{ End }; -} // namespace PathEls - -using namespace PathEls; - -PathComponent::~PathComponent(){ -} - int PathComponent::cmp(const PathComponent &p1, const PathComponent &p2) { int k1 = static_cast<int>(p1.kind()); @@ -157,37 +113,46 @@ int PathComponent::cmp(const PathComponent &p1, const PathComponent &p2) case Kind::Empty: return 0; case Kind::Field: - return p1.data.field.fieldName.compare(p2.data.field.fieldName); + return std::get<Field>(p1.m_data).fieldName.compare(std::get<Field>(p2.m_data).fieldName); case Kind::Index: - if (p1.data.index.indexValue < p2.data.index.indexValue) + if (std::get<Index>(p1.m_data).indexValue < std::get<Index>(p2.m_data).indexValue) return -1; - if (p1.data.index.indexValue > p2.data.index.indexValue) + if (std::get<Index>(p1.m_data).indexValue > std::get<Index>(p2.m_data).indexValue) return 1; return 0; case Kind::Key: - return p1.data.key.keyValue.compare(p2.data.key.keyValue); + return std::get<Key>(p1.m_data).keyValue.compare(std::get<Key>(p2.m_data).keyValue); case Kind::Root: { - int c = int(p1.data.root.contextKind) - int(p2.data.root.contextKind); + PathRoot k1 = std::get<Root>(p1.m_data).contextKind; + PathRoot k2 = std::get<Root>(p2.m_data).contextKind; + if (k1 == PathRoot::Env || k1 == PathRoot::Universe) + k1 = PathRoot::Top; + if (k2 == PathRoot::Env || k2 == PathRoot::Universe) + k2 = PathRoot::Top; + int c = int(k1) - int(k2); if (c != 0) return c; - return p1.data.root.contextName.compare(p2.data.root.contextName); + return std::get<Root>(p1.m_data).contextName.compare(std::get<Root>(p2.m_data).contextName); } case Kind::Current: { - int c = int(p1.data.current.contextKind) - int(p2.data.current.contextKind); + int c = int(std::get<Current>(p1.m_data).contextKind) + - int(std::get<Current>(p2.m_data).contextKind); if (c != 0) return c; - return p1.data.current.contextName.compare(p2.data.current.contextName); + return std::get<Current>(p1.m_data).contextName + .compare(std::get<Current>(p2.m_data).contextName); } case Kind::Any: return 0; case Kind::Filter: { - int c = p1.data.filter.filterDescription.compare(p2.data.filter.filterDescription); + int c = std::get<Filter>(p1.m_data).filterDescription + .compare(std::get<Filter>(p2.m_data).filterDescription); if (c != 0) return c; - if (p1.data.filter.filterDescription.startsWith(u"<")) { + if (std::get<Filter>(p1.m_data).filterDescription.startsWith(u"<")) { // assuming non comparable native code (target comparison is not portable) auto pp1 = &p1; auto pp2 = &p2; @@ -203,24 +168,27 @@ int PathComponent::cmp(const PathComponent &p1, const PathComponent &p2) return 0; } -PathComponent Path::component(int i) const +} // namespace PathEls + +const PathEls::PathComponent &Path::component(int i) const { + static Component emptyComponent; if (i < 0) i += m_length; if (i >= m_length || i < 0) { Q_ASSERT(false && "index out of bounds"); - return Component(); + return emptyComponent; } i = i - m_length - m_endOffset; auto data = m_data.get(); while (data) { - i += data->components.length(); + i += data->components.size(); if (i >= 0) - return data->components.at(i); + return std::as_const(data)->components[i]; data = data->parent.get(); } Q_ASSERT(false && "Invalid data reached while resolving a seemengly valid index in Path (inconsisten Path object)"); - return Component(); + return emptyComponent; } Path Path::operator[](int i) const @@ -233,10 +201,20 @@ QQmlJS::Dom::Path::operator bool() const return length() != 0; } +PathIterator Path::begin() const +{ + return PathIterator{*this}; +} + +PathIterator Path::end() const +{ + return PathIterator(); +} + PathRoot Path::headRoot() const { - auto comp = component(0); - if (Root const * r = comp.base()->asRoot()) + auto &comp = component(0); + if (PathEls::Root const * r = comp.asRoot()) return r->contextKind; return PathRoot::Other; } @@ -244,13 +222,15 @@ PathRoot Path::headRoot() const PathCurrent Path::headCurrent() const { auto comp = component(0); - if (Current const * c = comp.base()->asCurrent()) + if (PathEls::Current const * c = comp.asCurrent()) return c->contextKind; return PathCurrent::Other; } Path::Kind Path::headKind() const { + if (m_length == 0) + return Path::Kind::Empty; return component(0).kind(); } @@ -269,10 +249,10 @@ index_type Path::headIndex(index_type defaultValue) const return component(0).index(defaultValue); } -function<bool (DomItem)> Path::headFilter() const +function<bool(const DomItem &)> Path::headFilter() const { - auto comp = component(0); - if (Filter const * f = comp.base()->asFilter()) { + auto &comp = component(0); + if (PathEls::Filter const * f = comp.asFilter()) { return f->filterFunction; } return {}; @@ -300,7 +280,7 @@ Source Path::split() const return Source{Path(), *this}; } -bool inQString(QStringView el, QString base) +bool inQString(QStringView el, const QString &base) { if (quintptr(base.constData()) > quintptr(el.begin()) || quintptr(base.constData() + base.size()) < quintptr(el.begin())) @@ -309,7 +289,7 @@ bool inQString(QStringView el, QString base) return diff >= 0 && diff < base.size(); } -bool inQString(QString el, QString base) +bool inQString(const QString &el, const QString &base) { if (quintptr(base.constData()) > quintptr(el.constData()) || quintptr(base.constData() + base.size()) < quintptr(el.constData())) @@ -318,7 +298,7 @@ bool inQString(QString el, QString base) return diff >= 0 && diff < base.size() && diff + el.size() < base.size(); } -Path Path::fromString(QStringView s, ErrorHandler errorHandler) +Path Path::fromString(QStringView s, const ErrorHandler &errorHandler) { if (s.isEmpty()) return Path(); @@ -332,51 +312,51 @@ Path Path::fromString(QStringView s, ErrorHandler errorHandler) const QChar backslash = QChar::fromLatin1('\\'); const QChar underscore = QChar::fromLatin1('_'); const QChar tilda = QChar::fromLatin1('~'); - for (int i=0; i < s.length(); ++i) + for (int i=0; i < s.size(); ++i) if (s.at(i) == lsBrace || s.at(i) == dot) ++len; QVector<Component> components; components.reserve(len); int i = 0; int i0 = 0; - ParserState state = ParserState::Start; + PathEls::ParserState state = PathEls::ParserState::Start; QStringList strVals; - while (i < s.length()) { + while (i < s.size()) { // skip space - while (i < s.length() && s.at(i).isSpace()) + while (i < s.size() && s.at(i).isSpace()) ++i; - if (i >= s.length()) + if (i >= s.size()) break; QChar c = s.at(i++); switch (state) { - case ParserState::Start: + case PathEls::ParserState::Start: if (c == dollar) { i0 = i; - while (i < s.length() && s.at(i).isLetterOrNumber()){ + while (i < s.size() && s.at(i).isLetterOrNumber()){ ++i; } - components.append(Component(Root(s.mid(i0,i-i0)))); - state = ParserState::End; + components.append(Component(PathEls::Root(s.mid(i0,i-i0)))); + state = PathEls::ParserState::End; } else if (c == at) { i0 = i; - while (i < s.length() && s.at(i).isLetterOrNumber()){ + while (i < s.size() && s.at(i).isLetterOrNumber()){ ++i; } - components.append(Component(Current(s.mid(i0,i-i0)))); - state = ParserState::End; + components.append(Component(PathEls::Current(s.mid(i0,i-i0)))); + state = PathEls::ParserState::End; } else if (c.isLetter()) { myErrors().warning(tr("Field expressions should start with a dot, even when at the start of the path %1.") .arg(s)).handle(errorHandler); return Path(); } else { --i; - state = ParserState::End; + state = PathEls::ParserState::End; } break; - case ParserState::IndexOrKey: + case PathEls::ParserState::IndexOrKey: if (c.isDigit()) { i0 = i-1; - while (i < s.length() && s.at(i).isDigit()) + while (i < s.size() && s.at(i).isDigit()) ++i; bool ok; components.append(Component(static_cast<index_type>(s.mid(i0,i-i0).toString() @@ -388,22 +368,19 @@ Path Path::fromString(QStringView s, ErrorHandler errorHandler) } } else if (c.isLetter() || c == tilda || c == underscore) { i0 = i-1; - while (i < s.length() && (s.at(i).isLetterOrNumber() || s.at(i) == underscore || s.at(i) == tilda)) + while (i < s.size() && (s.at(i).isLetterOrNumber() || s.at(i) == underscore || s.at(i) == tilda)) ++i; - components.append(Component(Key(s.mid(i0, i-i0)))); + components.append(Component(PathEls::Key(s.mid(i0, i - i0).toString()))); } else if (c == quote) { i0 = i; QString strVal; - QStringView key; - bool needsConversion = false; bool properEnd = false; - while (i < s.length()) { + while (i < s.size()) { c = s.at(i); if (c == quote) { properEnd = true; break; } else if (c == backslash) { - needsConversion = true; strVal.append(s.mid(i0, i - i0).toString()); c = s.at(++i); i0 = i + 1; @@ -419,33 +396,27 @@ Path Path::fromString(QStringView s, ErrorHandler errorHandler) ++i; } if (properEnd) { - if (needsConversion) { - strVal.append(s.mid(i0, i - i0).toString()); - strVals.append(strVal); - key=strVal; - } else { - key = s.mid(i0, i - i0); - } + strVal.append(s.mid(i0, i - i0).toString()); ++i; } else { myErrors().error(tr("Unclosed quoted string at char %1.") .arg(QString::number(i - 1))).handle(errorHandler); return Path(); } - components.append(Key(key)); + components.append(PathEls::Key(strVal)); } else if (c == QChar::fromLatin1('*')) { - components.append(Component(Any())); + components.append(Component(PathEls::Any())); } else if (c == QChar::fromLatin1('?')) { - while (i < s.length() && s.at(i).isSpace()) + while (i < s.size() && s.at(i).isSpace()) ++i; - if (i >= s.length() || s.at(i) != QChar::fromLatin1('(')) { + if (i >= s.size() || s.at(i) != QChar::fromLatin1('(')) { myErrors().error(tr("Expected a brace in filter after the question mark (at char %1).") .arg(QString::number(i))).handle(errorHandler); return Path(); } i0 = ++i; - while (i < s.length() && s.at(i) != QChar::fromLatin1(')')) ++i; // check matching braces when skipping?? - if (i >= s.length() || s.at(i) != QChar::fromLatin1(')')) { + while (i < s.size() && s.at(i) != QChar::fromLatin1(')')) ++i; // check matching braces when skipping?? + if (i >= s.size() || s.at(i) != QChar::fromLatin1(')')) { myErrors().error(tr("Expected a closing brace in filter after the question mark (at char %1).") .arg(QString::number(i))).handle(errorHandler); return Path(); @@ -459,32 +430,32 @@ Path Path::fromString(QStringView s, ErrorHandler errorHandler) .arg(c).arg(i-1)).handle(errorHandler); return Path(); } - while (i < s.length() && s.at(i).isSpace()) ++i; - if (i >= s.length() || s.at(i) != rsBrace) { + while (i < s.size() && s.at(i).isSpace()) ++i; + if (i >= s.size() || s.at(i) != rsBrace) { myErrors().error(tr("square braces misses closing brace at char %1.") .arg(QString::number(i))).handle(errorHandler); return Path(); } else { ++i; } - state = ParserState::End; + state = PathEls::ParserState::End; break; - case ParserState::End: + case PathEls::ParserState::End: if (c == dot) { - while (i < s.length() && s.at(i).isSpace()) ++i; - if (i == s.length()) { + while (i < s.size() && s.at(i).isSpace()) ++i; + if (i == s.size()) { components.append(Component()); - state = ParserState::End; + state = PathEls::ParserState::End; } else if (s.at(i).isLetter() || s.at(i) == underscore || s.at(i) == tilda) { i0 = i; - while (i < s.length() && (s.at(i).isLetterOrNumber() || s.at(i) == underscore || s.at(i) == tilda)) { + while (i < s.size() && (s.at(i).isLetterOrNumber() || s.at(i) == underscore || s.at(i) == tilda)) { ++i; } - components.append(Component(Field(s.mid(i0,i-i0)))); - state = ParserState::End; + components.append(Component(PathEls::Field(s.mid(i0,i-i0)))); + state = PathEls::ParserState::End; } else if (s.at(i).isDigit()) { i0 = i; - while (i < s.length() && s.at(i).isDigit()){ + while (i < s.size() && s.at(i).isDigit()){ ++i; } bool ok; @@ -495,27 +466,27 @@ Path Path::fromString(QStringView s, ErrorHandler errorHandler) .arg(QString::number(i0))).handle(errorHandler); return Path(); } else { - myErrors().hint(tr("Index should use square brackets and not a dot (at char %1).") + myErrors().info(tr("Index should use square brackets and not a dot (at char %1).") .arg(QString::number(i0))).handle(errorHandler); } - state = ParserState::End; + state = PathEls::ParserState::End; } else if (s.at(i) == dot || s.at(i) == lsBrace) { components.append(Component()); - state = ParserState::End; + state = PathEls::ParserState::End; } else if (s.at(i) == at) { i0 = ++i; - while (i < s.length() && s.at(i).isLetterOrNumber()){ + while (i < s.size() && s.at(i).isLetterOrNumber()){ ++i; } - components.append(Component(Current(s.mid(i0,i-i0)))); - state = ParserState::End; + components.append(Component(PathEls::Current(s.mid(i0,i-i0)))); + state = PathEls::ParserState::End; } else if (s.at(i) == dollar) { i0 = ++i; - while (i < s.length() && s.at(i).isLetterOrNumber()){ + while (i < s.size() && s.at(i).isLetterOrNumber()){ ++i; } - components.append(Component(Root(s.mid(i0,i-i0)))); - state = ParserState::End; + components.append(Component(PathEls::Root(s.mid(i0,i-i0)))); + state = PathEls::ParserState::End; } else { c=s.at(i); myErrors().error(tr("Unexpected character '%1' after dot (at char %2).") @@ -524,7 +495,7 @@ Path Path::fromString(QStringView s, ErrorHandler errorHandler) return Path(); } } else if (c == lsBrace) { - state = ParserState::IndexOrKey; + state = PathEls::ParserState::IndexOrKey; } else { myErrors().error(tr("Unexpected character '%1' after end of component (char %2).") .arg(QStringView(&c,1)) @@ -535,163 +506,184 @@ Path Path::fromString(QStringView s, ErrorHandler errorHandler) } } switch (state) { - case ParserState::Start: + case PathEls::ParserState::Start: return Path(); - case ParserState::IndexOrKey: + case PathEls::ParserState::IndexOrKey: errorHandler(myErrors().error(tr("unclosed square brace at end."))); return Path(); - case ParserState::End: - return Path(0, components.length(), std::make_shared<PathData>(strVals, components)); + case PathEls::ParserState::End: + return Path(0, components.size(), std::make_shared<PathEls::PathData>( + strVals, components)); } Q_ASSERT(false && "Unexpected state in Path::fromString"); return Path(); } -Path Path::root(PathRoot s) +Path Path::Root(PathRoot s) { - return Path(0,1,std::make_shared<PathData>(QStringList(), QVector<Component>(1,Component(Root(s))))); + return Path(0,1,std::make_shared<PathEls::PathData>( + QStringList(), QVector<Component>(1,Component(PathEls::Root(s))))); } -Path Path::root(QString s) +Path Path::Root(const QString &s) { - return Path(0,1,std::make_shared<PathData>(QStringList(s), QVector<Component>(1,Component(Root(s))))); + return Path(0,1,std::make_shared<PathEls::PathData>( + QStringList(s), QVector<Component>(1,Component(PathEls::Root(s))))); } -Path Path::index(index_type i) +Path Path::Index(index_type i) { - return Path(0,1,std::make_shared<PathData>(QStringList(), QVector<Component>(1,Component(Index(i))))); + return Path(0,1,std::make_shared<PathEls::PathData>( + QStringList(), QVector<Component>(1,Component(PathEls::Index(i))))); } -Path Path::root(QStringView s) +Path Path::Root(QStringView s) { - return Path(0,1,std::make_shared<PathData>(QStringList(), QVector<Component>(1,Component(Root(s))))); + return Path(0,1,std::make_shared<PathEls::PathData>( + QStringList(), QVector<Component>(1,Component(PathEls::Root(s))))); } -Path Path::field(QStringView s) +Path Path::Field(QStringView s) { - return Path(0,1,std::make_shared<PathData>(QStringList(), QVector<Component>(1,Component(Field(s))))); + return Path(0,1,std::make_shared<PathEls::PathData>( + QStringList(), QVector<Component>(1,Component(PathEls::Field(s))))); } -Path Path::field(QString s) +Path Path::Field(const QString &s) { - return Path(0,1,std::make_shared<PathData>(QStringList(s), QVector<Component>(1,Component(Field(s))))); + return Path(0,1,std::make_shared<PathEls::PathData>( + QStringList(s), QVector<Component>(1,Component(PathEls::Field(s))))); } -Path Path::key(QStringView s) +Path Path::Key(QStringView s) { - return Path(0,1,std::make_shared<PathData>(QStringList(), QVector<Component>(1,Component(Key(s))))); + return Path( + 0, 1, + std::make_shared<PathEls::PathData>( + QStringList(), QVector<Component>(1, Component(PathEls::Key(s.toString()))))); } -Path Path::key(QString s) +Path Path::Key(const QString &s) { - return Path(0,1,std::make_shared<PathData>(QStringList(s), QVector<Component>(1,Component(Key(s))))); + return Path(0, 1, + std::make_shared<PathEls::PathData>( + QStringList(), QVector<Component>(1, Component(PathEls::Key(s))))); } -Path Path::current(PathCurrent s) +Path Path::Current(PathCurrent s) { - return Path(0,1,std::make_shared<PathData>(QStringList(), QVector<Component>(1,Component(Current(s))))); + return Path(0,1,std::make_shared<PathEls::PathData>( + QStringList(), QVector<Component>(1,Component(PathEls::Current(s))))); } -Path Path::current(QString s) +Path Path::Current(const QString &s) { - return Path(0,1,std::make_shared<PathData>(QStringList(s), QVector<Component>(1,Component(Current(s))))); + return Path(0,1,std::make_shared<PathEls::PathData>( + QStringList(s), QVector<Component>(1,Component(PathEls::Current(s))))); } -Path Path::current(QStringView s) +Path Path::Current(QStringView s) { - return Path(0,1,std::make_shared<PathData>(QStringList(), QVector<Component>(1,Component(Current(s))))); + return Path(0,1,std::make_shared<PathEls::PathData>( + QStringList(), QVector<Component>(1,Component(PathEls::Current(s))))); } -Path Path::empty() +Path Path::Empty() { return Path(); } -Path Path::subEmpty() const +Path Path::empty() const { if (m_endOffset != 0) - return noEndOffset().subEmpty(); - return Path(0,m_length+1,std::make_shared<PathData>(QStringList(), QVector<Component>(1,Component()), m_data)); + return noEndOffset().empty(); + return Path(0,m_length+1,std::make_shared<PathEls::PathData>( + QStringList(), QVector<Component>(1,Component()), m_data)); } -Path Path::subField(QString name) const +Path Path::field(const QString &name) const { - auto res = subField(QStringView(name)); + auto res = field(QStringView(name)); res.m_data->strData.append(name); return res; } -Path Path::subField(QStringView name) const +Path Path::field(QStringView name) const { if (m_endOffset != 0) - return noEndOffset().subField(name); - return Path(0,m_length+1,std::make_shared<PathData>(QStringList(), QVector<Component>(1,Component(Field(name))), m_data)); + return noEndOffset().field(name); + return Path(0,m_length+1,std::make_shared<PathEls::PathData>( + QStringList(), QVector<Component>(1,Component(PathEls::Field(name))), m_data)); } -Path Path::subKey(QString name) const +Path Path::key(const QString &name) const { - auto res = subKey(QStringView(name)); - res.m_data->strData.append(name); - return res; + if (m_endOffset != 0) + return noEndOffset().key(name); + return Path(0,m_length+1,std::make_shared<PathEls::PathData>( + QStringList(), QVector<Component>(1,Component(PathEls::Key(name))), m_data)); } -Path Path::subKey(QStringView name) const +Path Path::key(QStringView name) const { - if (m_endOffset != 0) - return noEndOffset().subKey(name); - return Path(0,m_length+1,std::make_shared<PathData>(QStringList(), QVector<Component>(1,Component(Key(name))), m_data)); + return key(name.toString()); } -Path Path::subIndex(index_type i) const +Path Path::index(index_type i) const { if (m_endOffset != 0) - return noEndOffset().subIndex(i); - return Path(0,m_length+1,std::make_shared<PathData>(QStringList(), QVector<Component>(1,Component(i)), m_data)); + return noEndOffset().index(i); + return Path(0,m_length+1,std::make_shared<PathEls::PathData>( + QStringList(), QVector<Component>(1,Component(i)), m_data)); } -Path Path::subAny() const +Path Path::any() const { if (m_endOffset != 0) - return noEndOffset().subAny(); - return Path(0,m_length+1,std::make_shared<PathData>(QStringList(), QVector<Component>(1,Component(Any())), m_data)); + return noEndOffset().any(); + return Path(0,m_length+1,std::make_shared<PathEls::PathData>( + QStringList(), QVector<Component>(1,Component(PathEls::Any())), m_data)); } -Path Path::subFilter(function<bool (DomItem)> filter, QString desc) const +Path Path::filter(const function<bool(const DomItem &)> &filterF, const QString &desc) const { - auto res = subFilter(filter, QStringView(desc)); + auto res = filter(filterF, QStringView(desc)); res.m_data->strData.append(desc); return res; } -Path Path::subFilter(function<bool (DomItem)> filter, QStringView desc) const +Path Path::filter(const function<bool(const DomItem &)> &filter, QStringView desc) const { if (m_endOffset != 0) - return noEndOffset().subFilter(filter, desc); - return Path(0,m_length+1,std::make_shared<PathData>(QStringList(), QVector<Component>(1,Component(Filter(filter, desc))), m_data)); + return noEndOffset().filter(filter, desc); + return Path(0,m_length+1,std::make_shared<PathEls::PathData>( + QStringList(), QVector<Component>(1,Component(PathEls::Filter(filter, desc))), m_data)); } -Path Path::subCurrent(PathCurrent s) const +Path Path::current(PathCurrent s) const { - return Path(0,m_length+1,std::make_shared<PathData>(QStringList(), QVector<Component>(1,Component(Current(s))), m_data)); + return Path(0,m_length+1,std::make_shared<PathEls::PathData>( + QStringList(), QVector<Component>(1,Component(PathEls::Current(s))), m_data)); } -Path Path::subCurrent(QString s) const +Path Path::current(const QString &s) const { - auto res = subCurrent(QStringView(s)); + auto res = current(QStringView(s)); res.m_data->strData.append(s); return res; } -Path Path::subCurrent(QStringView s) const +Path Path::current(QStringView s) const { if (m_endOffset != 0) - return noEndOffset().subCurrent(s); - return Path(0,m_length+1,std::make_shared<PathData>(QStringList(), QVector<Component>(1,Component(Current(s))), m_data)); + return noEndOffset().current(s); + return Path(0,m_length+1,std::make_shared<PathEls::PathData>( + QStringList(), QVector<Component>(1,Component(PathEls::Current(s))), m_data)); } -Path Path::subPath(Path toAdd, bool avoidToAddAsBase) const +Path Path::path(const Path &toAdd, bool avoidToAddAsBase) const { if (toAdd.length() == 0) return *this; @@ -705,7 +697,7 @@ Path Path::subPath(Path toAdd, bool avoidToAddAsBase) const if (resLength == thisExtended.length()) return thisExtended; else - return thisExtended.subPath(toAdd.mid(added.length(), resLength - thisExtended.length())); + return thisExtended.path(toAdd.mid(added.length(), resLength - thisExtended.length())); } } if (!avoidToAddAsBase) { @@ -737,9 +729,9 @@ Path Path::subPath(Path toAdd, bool avoidToAddAsBase) const } data = toAdd.m_data.get(); while (data) { - for (int ij = 0; ij < data->strData.length(); ++ij) { + for (int ij = 0; ij < data->strData.size(); ++ij) { bool hasAlready = false; - for (int ii = 0; ii < myStrs.length() && !hasAlready; ++ii) + for (int ii = 0; ii < myStrs.size() && !hasAlready; ++ii) hasAlready = inQString(data->strData[ij], myStrs[ii]); if (!hasAlready) addedStrs.append(data->strData[ij]); @@ -752,7 +744,7 @@ Path Path::subPath(Path toAdd, bool avoidToAddAsBase) const components.append(toAdd.component(i)); QStringView compStrView = toAdd.component(i).stringView(); if (!compStrView.isEmpty()) { - for (int j = 0; j < addedStrs.length(); ++j) { + for (int j = 0; j < addedStrs.size(); ++j) { if (inQString(compStrView, addedStrs[j])) { toAddStrs.append(addedStrs[j]); addedStrs.removeAt(j); @@ -761,8 +753,8 @@ Path Path::subPath(Path toAdd, bool avoidToAddAsBase) const } } } - return Path(0, m_length + toAdd.length(), - std::make_shared<PathData>(toAddStrs, components, ((m_endOffset == 0) ? m_data : noEndOffset().m_data))); + return Path(0, m_length + toAdd.length(), std::make_shared<PathEls::PathData>( + toAddStrs, components, ((m_endOffset == 0) ? m_data : noEndOffset().m_data))); } Path Path::expandFront() const @@ -770,7 +762,7 @@ Path Path::expandFront() const int newLen = 0; auto data = m_data.get(); while (data) { - newLen += data->components.length(); + newLen += data->components.size(); data = data->parent.get(); } newLen -= m_endOffset; @@ -817,7 +809,7 @@ int Path::cmp(const Path &p1, const Path &p2) return 0; } -Path::Path(quint16 endOffset, quint16 length, std::shared_ptr<PathData> data) +Path::Path(quint16 endOffset, quint16 length, const std::shared_ptr<PathEls::PathData> &data) :m_endOffset(endOffset), m_length(length), m_data(data) { } @@ -830,29 +822,90 @@ Path Path::noEndOffset() const return *this; // peel back qint16 endOffset = m_endOffset; - std::shared_ptr<PathData> lastData = m_data; - while (lastData && endOffset >= lastData->components.length()) { - endOffset -= lastData->components.length(); + std::shared_ptr<PathEls::PathData> lastData = m_data; + while (lastData && endOffset >= lastData->components.size()) { + endOffset -= lastData->components.size(); lastData = lastData->parent; } if (endOffset > 0) { Q_ASSERT(lastData && "Internal problem, reference to non existing PathData"); - return Path(0, m_length, std::make_shared<PathData>(lastData->strData, lastData->components.mid(0, lastData->components.length() - endOffset), lastData->parent)); + return Path(0, m_length, std::make_shared<PathEls::PathData>( + lastData->strData, lastData->components.mid(0, lastData->components.size() - endOffset), lastData->parent)); } return Path(0, m_length, lastData); } +Path Path::appendComponent(const PathEls::PathComponent &c) +{ + if (m_endOffset != 0) { + Path newP = noEndOffset(); + return newP.appendComponent(c); + } + if (m_data && m_data.use_count() != 1) { + // create a new path (otherwise paths linking to this will change) + Path newP(c); + newP.m_data->parent = m_data; + newP.m_length = static_cast<quint16>(m_length + 1); + return newP; + } + auto my_data = + (m_data ? m_data + : std::make_shared<PathEls::PathData>(QStringList(), + QVector<PathEls::PathComponent>())); + switch (c.kind()) { + case PathEls::Kind::Any: + case PathEls::Kind::Empty: + case PathEls::Kind::Index: + // no string + case PathEls::Kind::Field: + // string assumed to stay valid (Fields::...) + my_data->components.append(c); + break; + case PathEls::Kind::Current: + if (c.asCurrent()->contextKind == PathCurrent::Other) { + my_data->strData.append(c.asCurrent()->contextName.toString()); + my_data->components.append(PathEls::Current(my_data->strData.last())); + } else { + my_data->components.append(c); + } + break; + case PathEls::Kind::Filter: + if (!c.asFilter()->filterDescription.isEmpty()) { + my_data->strData.append(c.asFilter()->filterDescription.toString()); + my_data->components.append( + PathEls::Filter(c.asFilter()->filterFunction, my_data->strData.last())); + } else { + my_data->components.append(c); + } + break; + case PathEls::Kind::Key: + my_data->components.append(c); + break; + case PathEls::Kind::Root: + if (c.asRoot()->contextKind == PathRoot::Other) { + my_data->strData.append(c.asRoot()->contextName.toString()); + my_data->components.append(PathEls::Root(my_data->strData.last())); + } else { + my_data->components.append(c); + } + break; + } + if (m_data) + m_endOffset = 1; + return Path { 0, static_cast<quint16>(m_length + 1), my_data }; +} + ErrorGroups Path::myErrors() { static ErrorGroups res = {{NewErrorGroup("PathParsing")}}; return res; } -void Path::dump(Sink sink) const +void Path::dump(const Sink &sink) const { bool first = true; for (int i = 0; i < m_length; ++i) { - auto c = component(i); + auto &c = component(i); if (!c.hasSquareBrackets()) { if (!first || (c.kind() != Kind::Root && c.kind() != Kind::Current)) sink(u"."); @@ -871,17 +924,17 @@ QString Path::toString() const return res; } -Path Path::dropFront() const +Path Path::dropFront(int n) const { - if (m_length > 0) - return Path(m_endOffset, m_length - 1, m_data); + if (m_length > n && n >= 0) + return Path(m_endOffset, m_length - n, m_data); return Path(); } -Path Path::dropTail() const +Path Path::dropTail(int n) const { - if (m_length > 0) - return Path(m_endOffset + 1, m_length - 1, m_data); + if (m_length > n && n >= 0) + return Path(m_endOffset + n, m_length - n, m_data); return Path(); } @@ -899,7 +952,7 @@ Path Path::mid(int offset) const return mid(offset, m_length - offset); } -Path Path::fromString(QString s, ErrorHandler errorHandler) +Path Path::fromString(const QString &s, const ErrorHandler &errorHandler) { Path res = fromString(QStringView(s), errorHandler); if (res.m_data) @@ -910,3 +963,5 @@ Path Path::fromString(QString s, ErrorHandler errorHandler) } // end namespace Dom } // end namespace QQmlJS QT_END_NAMESPACE + +#include "moc_qqmldompath_p.cpp" |