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 | #include "qqmldom_utils_p.h" |
5 | #include "qqmldomitem_p.h" |
6 | #include "qqmldompath_p.h" |
7 | #include "qqmldomscriptelements_p.h" |
8 | #include <memory> |
9 | #include <utility> |
10 | #include <variant> |
11 | |
12 | using namespace QQmlJS::Dom::ScriptElements; |
13 | using QQmlJS::Dom::DomType; |
14 | using QQmlJS::Dom::ScriptElement; |
15 | using QQmlJS::Dom::ScriptElementVariant; |
16 | |
17 | /*! |
18 | \internal |
19 | \class ScriptElementBase |
20 | |
21 | The base class for all script elements. |
22 | |
23 | Derived classes should implement createFileLocations, DomElement::updatePathFromOwner and |
24 | DomBase::iterateDirectSubpaths. Furthermore, they need their own DomType enum. |
25 | |
26 | updatePathFromOwner and createFileLocations should be called on the script element root node |
27 | after it was constructed for the DomItem-wrapping to work correctly. Without it, methods like |
28 | iterateDirectSubpaths and all the stuff in DomItem will not work. |
29 | |
30 | createFileLocations does not work without having the pathFromOwner set |
31 | first via updatePathFromOwner. |
32 | |
33 | In derived classes, the updatePathFromOwner-implementation should call the base implementation |
34 | and also call recursively updatePathFromOwner on the derived class's children. |
35 | |
36 | See \l ScriptElementBase::createFileLocations for the createFileLocations implementation in |
37 | derived classes. |
38 | |
39 | Derived classes need to implement iterateDirectSubpaths to comply with the DomItem interface. |
40 | */ |
41 | |
42 | /*! |
43 | \internal |
44 | \fn ScriptElementBase::createFileLocations |
45 | |
46 | Usually, all the visits/recursive calls to DOM elements can be done using the DomItem interface, |
47 | once all the DOM has been constructed. |
48 | |
49 | During construction, createFileLocations can be used to annotate the DOM representation with the |
50 | corresponding source locations, which are needed, e.g., to find the corresponding DOM element |
51 | from a certain text position. When called, createFileLocations sets an entry for itself in the |
52 | FileLocationsTree. |
53 | |
54 | Derived classes should call the base implemenatation and recursively call createFileLocations on |
55 | all their children. |
56 | |
57 | Usually, only the root of the script DOM element requires one createFileLocations call after |
58 | construction \b{and} after a pathFromOwner was set using updatePathFromOwner. |
59 | |
60 | */ |
61 | |
62 | /*! |
63 | \internal |
64 | \class ScriptList |
65 | |
66 | A Helper class for writing script elements that contain lists, helps for implementing the |
67 | recursive calls of iterateDirectSubpaths, updatePathFromOwner and createFileLocations. |
68 | */ |
69 | |
70 | /*! |
71 | \internal |
72 | Helper for fields with elements in iterateDirectSubpaths. |
73 | */ |
74 | static bool wrap(const QQmlJS::Dom::DomItem &self, QQmlJS::Dom::DirectVisitor visitor, QStringView field, |
75 | const ScriptElementVariant &value) |
76 | { |
77 | if (!value) |
78 | return true; |
79 | |
80 | const bool b = |
81 | self.dvItemField(visitor, f: field, it: [&self, field, &value]() -> QQmlJS::Dom::DomItem { |
82 | const QQmlJS::Dom::Path pathFromOwner{ self.pathFromOwner().field(name: field) }; |
83 | return self.subScriptElementWrapperItem(obj: value); |
84 | }); |
85 | return b; |
86 | } |
87 | |
88 | /*! |
89 | \internal |
90 | Helper for fields with lists in iterateDirectSubpaths. |
91 | */ |
92 | static bool wrap(const QQmlJS::Dom::DomItem &self, QQmlJS::Dom::DirectVisitor visitor, QStringView field, |
93 | const ScriptList &value) |
94 | { |
95 | const bool b = |
96 | self.dvItemField(visitor, f: field, it: [&self, field, &value]() -> QQmlJS::Dom::DomItem { |
97 | const QQmlJS::Dom::Path pathFromOwner{ self.pathFromOwner().field(name: field) }; |
98 | return self.subListItem(list: value.asList(path: pathFromOwner)); |
99 | }); |
100 | return b; |
101 | } |
102 | |
103 | bool GenericScriptElement::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const |
104 | { |
105 | bool cont = true; |
106 | for (auto it = m_children.begin(); it != m_children.end(); ++it) { |
107 | cont &= std::visit( |
108 | visitor: [&self, &visitor, &it](auto &&e) { return wrap(self, visitor, it->first, e); }, |
109 | variants: it->second); |
110 | } |
111 | for (auto it = m_values.begin(); it != m_values.end(); ++it) { |
112 | cont &= self.dvValueField(visitor, f: it->first, value: it->second); |
113 | } |
114 | return cont; |
115 | } |
116 | |
117 | void GenericScriptElement::updatePathFromOwner(const Path &p) |
118 | { |
119 | BaseT::updatePathFromOwner(newPath: p); |
120 | for (auto it = m_children.begin(); it != m_children.end(); ++it) { |
121 | std::visit(visitor: qOverloadedVisitor{ [&p, &it](ScriptElementVariant &e) { |
122 | e.base()->updatePathFromOwner(newPath: p.field(name: it->first)); |
123 | }, |
124 | [&p, &it](ScriptList &list) { |
125 | list.updatePathFromOwner(p: p.field(name: it->first)); |
126 | } }, |
127 | variants&: it->second); |
128 | } |
129 | } |
130 | |
131 | void GenericScriptElement::createFileLocations(const FileLocations::Tree &base) |
132 | { |
133 | BaseT::createFileLocations(base); |
134 | for (auto it = m_children.begin(); it != m_children.end(); ++it) { |
135 | std::visit( |
136 | visitor: qOverloadedVisitor{ |
137 | [&base](ScriptElementVariant &e) { e.base()->createFileLocations(fileLocationOfOwner: base); }, |
138 | [&base](ScriptList &list) { list.createFileLocations(base); } }, |
139 | variants&: it->second); |
140 | } |
141 | } |
142 | |
143 | bool BlockStatement::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const |
144 | { |
145 | // TODO: test me |
146 | bool cont = true; |
147 | cont &= wrap(self, visitor, field: Fields::statements, value: m_statements); |
148 | return cont; |
149 | } |
150 | |
151 | void BlockStatement::updatePathFromOwner(const Path &p) |
152 | { |
153 | BaseT::updatePathFromOwner(newPath: p); |
154 | m_statements.updatePathFromOwner(p: p.field(name: Fields::statements)); |
155 | } |
156 | |
157 | void BlockStatement::createFileLocations(const FileLocations::Tree &base) |
158 | { |
159 | BaseT::createFileLocations(base); |
160 | m_statements.createFileLocations(base); |
161 | } |
162 | |
163 | bool IdentifierExpression::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const |
164 | { |
165 | bool cont = true; |
166 | cont &= self.dvValueField(visitor, f: Fields::identifier, value: m_name); |
167 | return cont; |
168 | } |
169 | |
170 | bool Literal::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const |
171 | { |
172 | bool cont = true; |
173 | std::visit(visitor: [&cont, &visitor, |
174 | &self](auto &&e) { cont &= self.dvValueField(visitor, Fields::value, e); }, |
175 | variants: m_value); |
176 | return cont; |
177 | } |
178 | |
179 | bool IfStatement::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const |
180 | { |
181 | // TODO: test me |
182 | bool cont = true; |
183 | cont &= wrap(self, visitor, field: Fields::condition, value: m_condition); |
184 | cont &= wrap(self, visitor, field: Fields::consequence, value: m_consequence); |
185 | cont &= wrap(self, visitor, field: Fields::alternative, value: m_alternative); |
186 | return cont; |
187 | } |
188 | |
189 | void IfStatement::updatePathFromOwner(const Path &p) |
190 | { |
191 | BaseT::updatePathFromOwner(newPath: p); |
192 | if (auto ptr = m_condition.base()) |
193 | ptr->updatePathFromOwner(newPath: p.field(name: Fields::condition)); |
194 | if (auto ptr = m_consequence.base()) |
195 | ptr->updatePathFromOwner(newPath: p.field(name: Fields::consequence)); |
196 | if (auto ptr = m_alternative.base()) |
197 | ptr->updatePathFromOwner(newPath: p.field(name: Fields::alternative)); |
198 | } |
199 | |
200 | void IfStatement::createFileLocations(const FileLocations::Tree &base) |
201 | { |
202 | BaseT::createFileLocations(base); |
203 | if (auto ptr = m_condition.base()) |
204 | ptr->createFileLocations(fileLocationOfOwner: base); |
205 | if (auto ptr = m_consequence.base()) |
206 | ptr->createFileLocations(fileLocationOfOwner: base); |
207 | if (auto ptr = m_alternative.base()) |
208 | ptr->createFileLocations(fileLocationOfOwner: base); |
209 | } |
210 | |
211 | bool ForStatement::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const |
212 | { |
213 | bool cont = true; |
214 | cont &= wrap(self, visitor, field: Fields::initializer, value: m_initializer); |
215 | cont &= wrap(self, visitor, field: Fields::declarations, value: m_declarations); |
216 | cont &= wrap(self, visitor, field: Fields::condition, value: m_condition); |
217 | cont &= wrap(self, visitor, field: Fields::expression, value: m_expression); |
218 | cont &= wrap(self, visitor, field: Fields::body, value: m_body); |
219 | return cont; |
220 | } |
221 | |
222 | void ForStatement::updatePathFromOwner(const Path &p) |
223 | { |
224 | BaseT::updatePathFromOwner(newPath: p); |
225 | if (auto ptr = m_initializer.base()) |
226 | ptr->updatePathFromOwner(newPath: p.field(name: Fields::initializer)); |
227 | if (auto ptr = m_declarations.base()) |
228 | ptr->updatePathFromOwner(newPath: p.field(name: Fields::declarations)); |
229 | if (auto ptr = m_condition.base()) |
230 | ptr->updatePathFromOwner(newPath: p.field(name: Fields::condition)); |
231 | if (auto ptr = m_expression.base()) |
232 | ptr->updatePathFromOwner(newPath: p.field(name: Fields::expression)); |
233 | if (auto ptr = m_body.base()) |
234 | ptr->updatePathFromOwner(newPath: p.field(name: Fields::body)); |
235 | } |
236 | |
237 | void ForStatement::createFileLocations(const FileLocations::Tree &base) |
238 | { |
239 | BaseT::createFileLocations(base); |
240 | if (auto ptr = m_initializer.base()) |
241 | ptr->createFileLocations(fileLocationOfOwner: base); |
242 | if (auto ptr = m_declarations.base()) |
243 | ptr->createFileLocations(fileLocationOfOwner: base); |
244 | if (auto ptr = m_condition.base()) |
245 | ptr->createFileLocations(fileLocationOfOwner: base); |
246 | if (auto ptr = m_expression.base()) |
247 | ptr->createFileLocations(fileLocationOfOwner: base); |
248 | if (auto ptr = m_body.base()) |
249 | ptr->createFileLocations(fileLocationOfOwner: base); |
250 | } |
251 | |
252 | bool BinaryExpression::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const |
253 | { |
254 | bool cont = true; |
255 | cont &= wrap(self, visitor, field: Fields::left, value: m_left); |
256 | cont &= self.dvValueField(visitor, f: Fields::operation, value: m_operator); |
257 | cont &= wrap(self, visitor, field: Fields::right, value: m_right); |
258 | return cont; |
259 | } |
260 | |
261 | void BinaryExpression::updatePathFromOwner(const Path &p) |
262 | { |
263 | BaseT::updatePathFromOwner(newPath: p); |
264 | if (auto ptr = m_left.base()) |
265 | ptr->updatePathFromOwner(newPath: p.field(name: Fields::left)); |
266 | if (auto ptr = m_right.base()) |
267 | ptr->updatePathFromOwner(newPath: p.field(name: Fields::right)); |
268 | } |
269 | |
270 | void BinaryExpression::createFileLocations(const FileLocations::Tree &base) |
271 | { |
272 | BaseT::createFileLocations(base); |
273 | if (auto ptr = m_left.base()) |
274 | ptr->createFileLocations(fileLocationOfOwner: base); |
275 | if (auto ptr = m_right.base()) |
276 | ptr->createFileLocations(fileLocationOfOwner: base); |
277 | } |
278 | |
279 | bool VariableDeclarationEntry::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const |
280 | { |
281 | bool cont = true; |
282 | cont &= self.dvValueField(visitor, f: Fields::scopeType, value: m_scopeType); |
283 | cont &= wrap(self, visitor, field: Fields::identifier, value: m_identifier); |
284 | cont &= wrap(self, visitor, field: Fields::initializer, value: m_initializer); |
285 | return cont; |
286 | } |
287 | |
288 | void VariableDeclarationEntry::updatePathFromOwner(const Path &p) |
289 | { |
290 | BaseT::updatePathFromOwner(newPath: p); |
291 | if (auto ptr = m_identifier.base()) |
292 | ptr->updatePathFromOwner(newPath: p.field(name: Fields::identifier)); |
293 | if (auto ptr = m_initializer.base()) |
294 | ptr->updatePathFromOwner(newPath: p.field(name: Fields::initializer)); |
295 | } |
296 | |
297 | void VariableDeclarationEntry::createFileLocations(const FileLocations::Tree &base) |
298 | { |
299 | BaseT::createFileLocations(base); |
300 | if (auto ptr = m_identifier.base()) |
301 | ptr->createFileLocations(fileLocationOfOwner: base); |
302 | if (auto ptr = m_initializer.base()) |
303 | ptr->createFileLocations(fileLocationOfOwner: base); |
304 | } |
305 | |
306 | bool VariableDeclaration::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const |
307 | { |
308 | bool cont = true; |
309 | cont &= wrap(self, visitor, field: Fields::declarations, value: m_declarations); |
310 | return cont; |
311 | } |
312 | |
313 | void VariableDeclaration::updatePathFromOwner(const Path &p) |
314 | { |
315 | BaseT::updatePathFromOwner(newPath: p); |
316 | m_declarations.updatePathFromOwner(p: p.field(name: Fields::declarations)); |
317 | } |
318 | |
319 | void VariableDeclaration::createFileLocations(const FileLocations::Tree &base) |
320 | { |
321 | BaseT::createFileLocations(base); |
322 | m_declarations.createFileLocations(base); |
323 | } |
324 | |
325 | bool ReturnStatement::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const |
326 | { |
327 | bool cont = true; |
328 | cont &= wrap(self, visitor, field: Fields::expression, value: m_expression); |
329 | return cont; |
330 | } |
331 | |
332 | void ReturnStatement::updatePathFromOwner(const Path &p) |
333 | { |
334 | BaseT::updatePathFromOwner(newPath: p); |
335 | if (auto ptr = m_expression.base()) |
336 | ptr->updatePathFromOwner(newPath: p.field(name: Fields::expression)); |
337 | } |
338 | |
339 | void ReturnStatement::createFileLocations(const FileLocations::Tree &base) |
340 | { |
341 | BaseT::createFileLocations(base); |
342 | if (auto ptr = m_expression.base()) |
343 | ptr->createFileLocations(fileLocationOfOwner: base); |
344 | } |
345 | |
346 | void ScriptList::replaceKindForGenericChildren(DomType oldType, DomType newType) |
347 | { |
348 | for (auto &it : m_list) { |
349 | if (auto current = it.data()) { |
350 | if (auto genericElement = |
351 | std::get_if<std::shared_ptr<ScriptElements::GenericScriptElement>>( |
352 | ptr: &*current)) { |
353 | if ((*genericElement)->kind() == oldType) |
354 | (*genericElement)->setKind(newType); |
355 | } |
356 | } |
357 | } |
358 | } |
359 |
Definitions
- wrap
- wrap
- iterateDirectSubpaths
- updatePathFromOwner
- createFileLocations
- iterateDirectSubpaths
- updatePathFromOwner
- createFileLocations
- iterateDirectSubpaths
- iterateDirectSubpaths
- iterateDirectSubpaths
- updatePathFromOwner
- createFileLocations
- iterateDirectSubpaths
- updatePathFromOwner
- createFileLocations
- iterateDirectSubpaths
- updatePathFromOwner
- createFileLocations
- iterateDirectSubpaths
- updatePathFromOwner
- createFileLocations
- iterateDirectSubpaths
- updatePathFromOwner
- createFileLocations
- iterateDirectSubpaths
- updatePathFromOwner
- createFileLocations
Start learning QML with our Intro Training
Find out more