1// Copyright (C) 2023 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
4#ifndef QQMLDOMSCRIPTELEMENTS_P_H
5#define QQMLDOMSCRIPTELEMENTS_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include "qqmldomitem_p.h"
19#include "qqmldomelements_p.h"
20#include "qqmldomattachedinfo_p.h"
21#include "qqmldompath_p.h"
22#include <algorithm>
23#include <limits>
24#include <type_traits>
25#include <utility>
26#include <variant>
27
28QT_BEGIN_NAMESPACE
29
30namespace QQmlJS {
31namespace Dom {
32
33namespace ScriptElements {
34
35template<DomType type>
36class ScriptElementBase : public ScriptElement
37{
38public:
39 using BaseT = ScriptElementBase<type>;
40 static constexpr DomType kindValue = type;
41 static constexpr DomKind domKindValue = DomKind::ScriptElement;
42
43 ScriptElementBase(QQmlJS::SourceLocation combinedLocation = QQmlJS::SourceLocation{})
44 : ScriptElement(), m_locations({ { FileLocationRegion::MainRegion, combinedLocation } })
45 {
46 }
47 ScriptElementBase(QQmlJS::SourceLocation first, QQmlJS::SourceLocation last)
48 : ScriptElementBase(combine(l1: first, l2: last))
49 {
50 }
51 DomType kind() const override { return type; }
52 DomKind domKind() const override { return domKindValue; }
53
54 void createFileLocations(const FileLocations::Tree &base) override
55 {
56 FileLocations::Tree res =
57 FileLocations::ensure(base, basePath: pathFromOwner(), pType: AttachedInfo::PathType::Relative);
58 for (auto location: m_locations) {
59 FileLocations::addRegion(fLoc: res, region: location.first, loc: location.second);
60 }
61 }
62
63 /*
64 Pretty prints the current DomItem. Currently, for script elements, this is done entirely on
65 the parser representation (via the AST classes), but it could be moved here if needed.
66 */
67 // void writeOut(const DomItem &self, OutWriter &lw) const override;
68
69 /*!
70 All of the following overloads are only required for optimization purposes.
71 The base implementation will work fine, but might be slightly slower.
72 You can override dump(), fields(), field(), indexes(), index(), keys() or key() if the
73 performance of the base class becomes problematic.
74 */
75
76 // // needed for debug
77 // void dump(const DomItem &, const Sink &sink, int indent, FilterT filter) const override;
78
79 // // just required for optimization if iterateDirectSubpaths is slow
80 // QList<QString> fields(const DomItem &self) const override;
81 // DomItem field(const DomItem &self, QStringView name) const override;
82
83 // index_type indexes(const DomItem &self) const override;
84 // DomItem index(const DomItem &self, index_type index) const override;
85
86 // QSet<QString> const keys(const DomItem &self) const override;
87 // DomItem key(const DomItem &self, const QString &name) const override;
88
89 QQmlJS::SourceLocation mainRegionLocation() const
90 {
91 Q_ASSERT(m_locations.size() > 0);
92 Q_ASSERT(m_locations.front().first == FileLocationRegion::MainRegion);
93
94 auto current = m_locations.front();
95 return current.second;
96 }
97 void setMainRegionLocation(const QQmlJS::SourceLocation &location)
98 {
99 Q_ASSERT(m_locations.size() > 0);
100 Q_ASSERT(m_locations.front().first == FileLocationRegion::MainRegion);
101
102 m_locations.front().second = location;
103 }
104 void addLocation(FileLocationRegion region, QQmlJS::SourceLocation location)
105 {
106 Q_ASSERT_X(region != FileLocationRegion::MainRegion, "ScriptElementBase::addLocation",
107 "use the setCombinedLocation instead!");
108 m_locations.emplace_back(args&: region, args&: location);
109 }
110
111protected:
112 std::vector<std::pair<FileLocationRegion, QQmlJS::SourceLocation>> m_locations;
113};
114
115class ScriptList : public ScriptElementBase<DomType::List>
116{
117public:
118 using typename ScriptElementBase<DomType::List>::BaseT;
119
120 using BaseT::BaseT;
121
122 // minimal required overload for this to be wrapped as DomItem:
123 bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override
124 {
125 bool cont =
126 asList(path: self.pathFromOwner().key(name: QString())).iterateDirectSubpaths(self, visitor);
127 return cont;
128 }
129 void updatePathFromOwner(const Path &p) override
130 {
131 BaseT::updatePathFromOwner(newPath: p);
132 for (int i = 0; i < m_list.size(); ++i) {
133 Q_ASSERT(m_list[i].base());
134 m_list[i].base()->updatePathFromOwner(newPath: p.index(i));
135 }
136 }
137 void createFileLocations(const FileLocations::Tree &base) override
138 {
139 BaseT::createFileLocations(base);
140
141 for (int i = 0; i < m_list.size(); ++i) {
142 Q_ASSERT(m_list[i].base());
143 m_list[i].base()->createFileLocations(fileLocationOfOwner: base);
144 }
145 }
146
147 List asList(const Path &path) const
148 {
149 auto asList = List::fromQList<ScriptElementVariant>(
150 pathFromOwner: path, list: m_list,
151 elWrapper: [](const DomItem &list, const PathEls::PathComponent &, const ScriptElementVariant &wrapped)
152 -> DomItem { return list.subScriptElementWrapperItem(obj: wrapped); });
153
154 return asList;
155 }
156
157 void append(const ScriptElementVariant &statement) { m_list.push_back(t: statement); }
158 void append(const ScriptList &list) { m_list.append(l: list.m_list); }
159 void reverse() { std::reverse(first: m_list.begin(), last: m_list.end()); }
160 void replaceKindForGenericChildren(DomType oldType, DomType newType);
161 const QList<ScriptElementVariant> &qList() { return std::as_const(t&: m_list); };
162
163private:
164 QList<ScriptElementVariant> m_list;
165};
166
167class GenericScriptElement : public ScriptElementBase<DomType::ScriptGenericElement>
168{
169public:
170 using BaseT::BaseT;
171 using VariantT = std::variant<ScriptElementVariant, ScriptList>;
172
173 bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
174 void updatePathFromOwner(const Path &p) override;
175 void createFileLocations(const FileLocations::Tree &base) override;
176
177 DomType kind() const override { return m_kind; }
178 void setKind(DomType kind) { m_kind = kind; }
179
180 decltype(auto) insertChild(QStringView name, VariantT v)
181 {
182 return m_children.insert(x: std::make_pair(x&: name, y&: v));
183 }
184
185 ScriptElementVariant elementChild(const QQmlJS::Dom::FieldType &field)
186 {
187 auto it = m_children.find(x: field);
188 if (it == m_children.end())
189 return {};
190 if (!std::holds_alternative<ScriptElementVariant>(v: it->second))
191 return {};
192 return std::get<ScriptElementVariant>(v&: it->second);
193 }
194
195 void insertValue(QStringView name, const QCborValue &v)
196 {
197 m_values.insert(x: std::make_pair(x&: name, y: v));
198 }
199
200 QCborValue value() const override
201 {
202 auto it = m_values.find(x: Fields::value);
203 if (it == m_values.cend())
204 return {};
205
206 return it->second;
207 }
208
209private:
210 /*!
211 \internal
212 The DomItem interface will use iterateDirectSubpaths for all kinds of operations on the
213 GenericScriptElement. Therefore, to avoid bad surprises when using the DomItem interface, use
214 a sorted map to always iterate the children in the same order.
215 */
216 std::map<QQmlJS::Dom::FieldType, VariantT> m_children;
217 // value fields
218 std::map<QQmlJS::Dom::FieldType, QCborValue> m_values;
219 DomType m_kind = DomType::Empty;
220};
221
222class BlockStatement : public ScriptElementBase<DomType::ScriptBlockStatement>
223{
224public:
225 using BaseT::BaseT;
226
227 // minimal required overload for this to be wrapped as DomItem:
228 bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
229 void updatePathFromOwner(const Path &p) override;
230 void createFileLocations(const FileLocations::Tree &base) override;
231
232 ScriptList statements() const { return m_statements; }
233 void setStatements(const ScriptList &statements) { m_statements = statements; }
234
235private:
236 ScriptList m_statements;
237};
238
239class IdentifierExpression : public ScriptElementBase<DomType::ScriptIdentifierExpression>
240{
241public:
242 using BaseT::BaseT;
243 void setName(QStringView name) { m_name = name.toString(); }
244 QString name() { return m_name; }
245
246 // minimal required overload for this to be wrapped as DomItem:
247 bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
248
249 QCborValue value() const override { return QCborValue(m_name); }
250
251private:
252 QString m_name;
253};
254
255class Literal : public ScriptElementBase<DomType::ScriptLiteral>
256{
257public:
258 using BaseT::BaseT;
259
260 using VariantT = std::variant<QString, double, bool, std::nullptr_t>;
261
262 void setLiteralValue(VariantT value) { m_value = value; }
263 VariantT literalValue() const { return m_value; }
264
265 // minimal required overload for this to be wrapped as DomItem:
266 bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
267
268 QCborValue value() const override
269 {
270 return std::visit(visitor: [](auto &&e) -> QCborValue { return e; }, variants: m_value);
271 }
272
273private:
274 VariantT m_value;
275};
276
277// TODO: test this method + implement foreach etc
278class ForStatement : public ScriptElementBase<DomType::ScriptForStatement>
279{
280public:
281 using BaseT::BaseT;
282
283 // minimal required overload for this to be wrapped as DomItem:
284 bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
285 void updatePathFromOwner(const Path &p) override;
286 void createFileLocations(const FileLocations::Tree &base) override;
287
288 ScriptElementVariant initializer() const { return m_initializer; }
289 void setInitializer(const ScriptElementVariant &newInitializer)
290 {
291 m_initializer = newInitializer;
292 }
293
294 ScriptElementVariant declarations() const { return m_declarations; }
295 void setDeclarations(const ScriptElementVariant &newDeclaration)
296 {
297 m_declarations = newDeclaration;
298 }
299 ScriptElementVariant condition() const { return m_condition; }
300 void setCondition(const ScriptElementVariant &newCondition) { m_condition = newCondition; }
301 ScriptElementVariant expression() const { return m_expression; }
302 void setExpression(const ScriptElementVariant &newExpression) { m_expression = newExpression; }
303 ScriptElementVariant body() const { return m_body; }
304 void setBody(const ScriptElementVariant &newBody) { m_body = newBody; }
305
306private:
307 ScriptElementVariant m_initializer;
308 ScriptElementVariant m_declarations;
309 ScriptElementVariant m_condition;
310 ScriptElementVariant m_expression;
311 ScriptElementVariant m_body;
312};
313
314class IfStatement : public ScriptElementBase<DomType::ScriptIfStatement>
315{
316public:
317 using BaseT::BaseT;
318
319 // minimal required overload for this to be wrapped as DomItem:
320 bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
321 void updatePathFromOwner(const Path &p) override;
322 void createFileLocations(const FileLocations::Tree &base) override;
323
324 ScriptElementVariant condition() const { return m_condition; }
325 void setCondition(const ScriptElementVariant &condition) { m_condition = condition; }
326 ScriptElementVariant consequence() { return m_consequence; }
327 void setConsequence(const ScriptElementVariant &consequence) { m_consequence = consequence; }
328 ScriptElementVariant alternative() { return m_alternative; }
329 void setAlternative(const ScriptElementVariant &alternative) { m_alternative = alternative; }
330
331private:
332 ScriptElementVariant m_condition;
333 ScriptElementVariant m_consequence;
334 ScriptElementVariant m_alternative;
335};
336
337class ReturnStatement : public ScriptElementBase<DomType::ScriptReturnStatement>
338{
339public:
340 using BaseT::BaseT;
341
342 // minimal required overload for this to be wrapped as DomItem:
343 bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
344 void updatePathFromOwner(const Path &p) override;
345 void createFileLocations(const FileLocations::Tree &base) override;
346
347 ScriptElementVariant expression() const { return m_expression; }
348 void setExpression(ScriptElementVariant expression) { m_expression = expression; }
349
350private:
351 ScriptElementVariant m_expression;
352};
353
354class BinaryExpression : public ScriptElementBase<DomType::ScriptBinaryExpression>
355{
356public:
357 using BaseT::BaseT;
358
359 enum Operator : char {
360 FieldMemberAccess,
361 ArrayMemberAccess,
362 TO_BE_IMPLEMENTED = std::numeric_limits<char>::max(), // not required by qmlls
363 };
364
365 // minimal required overload for this to be wrapped as DomItem:
366 bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
367 void updatePathFromOwner(const Path &p) override;
368 void createFileLocations(const FileLocations::Tree &base) override;
369
370 ScriptElementVariant left() const { return m_left; }
371 void setLeft(const ScriptElementVariant &newLeft) { m_left = newLeft; }
372 ScriptElementVariant right() const { return m_right; }
373 void setRight(const ScriptElementVariant &newRight) { m_right = newRight; }
374 int op() const { return m_operator; }
375 void setOp(Operator op) { m_operator = op; }
376
377private:
378 ScriptElementVariant m_left;
379 ScriptElementVariant m_right;
380 Operator m_operator = TO_BE_IMPLEMENTED;
381};
382
383class VariableDeclarationEntry : public ScriptElementBase<DomType::ScriptVariableDeclarationEntry>
384{
385public:
386 using BaseT::BaseT;
387
388 enum ScopeType { Var, Let, Const };
389
390 ScopeType scopeType() const { return m_scopeType; }
391 void setScopeType(ScopeType scopeType) { m_scopeType = scopeType; }
392
393 ScriptElementVariant identifier() const { return m_identifier; }
394 void setIdentifier(const ScriptElementVariant &identifier) { m_identifier = identifier; }
395
396 ScriptElementVariant initializer() const { return m_initializer; }
397 void setInitializer(const ScriptElementVariant &initializer) { m_initializer = initializer; }
398
399 bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
400 void updatePathFromOwner(const Path &p) override;
401 void createFileLocations(const FileLocations::Tree &base) override;
402
403private:
404 ScopeType m_scopeType;
405 ScriptElementVariant m_identifier;
406 ScriptElementVariant m_initializer;
407};
408
409class VariableDeclaration : public ScriptElementBase<DomType::ScriptVariableDeclaration>
410{
411public:
412 using BaseT::BaseT;
413
414 // minimal required overload for this to be wrapped as DomItem:
415 bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
416 void updatePathFromOwner(const Path &p) override;
417 void createFileLocations(const FileLocations::Tree &base) override;
418
419 void setDeclarations(const ScriptList &list) { m_declarations = list; }
420 ScriptList declarations() { return m_declarations; }
421
422private:
423 ScriptList m_declarations;
424};
425
426} // namespace ScriptElements
427} // end namespace Dom
428} // end namespace QQmlJS
429
430QT_END_NAMESPACE
431
432#endif // QQMLDOMSCRIPTELEMENTS_P_H
433

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtdeclarative/src/qmldom/qqmldomscriptelements_p.h