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

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