38 using AST::Visitor::endVisit;
39 using AST::Visitor::visit;
41 static constexpr const auto className =
"QmlDomAstCreator";
47 DomValue(
const T &
obj) : kind(T::kindValue),
value(
obj)
77 class ScriptStackElement
81 static ScriptStackElement from(
const T &
obj)
83 if constexpr (std::is_same_v<T, ScriptElements::ScriptList>) {
94 using Variant = std::variant<ScriptElementVariant, ScriptElements::ScriptList>;
99 Q_ASSERT_X(std::holds_alternative<ScriptElementVariant>(
value),
"takeVariant",
100 "Should be a variant, did the parser change?");
101 return std::get<ScriptElementVariant>(std::move(
value));
104 bool isList()
const {
return std::holds_alternative<ScriptElements::ScriptList>(
value); };
108 Q_ASSERT_X(std::holds_alternative<ScriptElements::ScriptList>(
value),
"takeList",
109 "Should be a List, did the parser change?");
110 return std::get<ScriptElements::ScriptList>(std::move(
value));
115 if (
auto x = std::get_if<ScriptElementVariant>(&
value)) {
116 x->base()->setSemanticScope(scope);
118 }
else if (
auto x = std::get_if<ScriptElements::ScriptList>(&
value)) {
119 x->setSemanticScope(scope);
133 std::shared_ptr<QmlFile> qmlFilePtr;
134 QVector<QmlStackElement> nodeStack;
135 QList<ScriptStackElement> scriptNodeStack;
136 QVector<int> arrayBindingLevels;
138 int m_nestedFunctionDepth = 0;
139 bool m_enableScriptExpressions =
false;
140 bool m_loadFileLazily =
false;
145 bool m_skipBindingIdentifiers =
false;
150 QmlStackElement ¤tEl(
int idx = 0)
152 Q_ASSERT_X(idx < nodeStack.size() && idx >= 0,
"currentQmlObjectOrComponentEl",
153 "Stack does not contain enough elements!");
154 int i = nodeStack.size() - idx;
156 DomType k = nodeStack.at(
i).item.kind;
157 if (k == T::kindValue)
160 Q_ASSERT_X(
false,
"currentEl",
"Stack does not contan object of type ");
161 return nodeStack.last();
165 ScriptStackElement ¤tScriptEl(
int idx = 0)
167 Q_ASSERT_X(m_enableScriptExpressions,
"currentScriptEl",
168 "Cannot access script elements when they are disabled!");
170 Q_ASSERT_X(idx < scriptNodeStack.size() && idx >= 0,
"currentQmlObjectOrComponentEl",
171 "Stack does not contain enough elements!");
172 int i = scriptNodeStack.size() - idx;
174 DomType k = scriptNodeStack.at(
i).kind;
175 if (k == T::element_type::kindValue)
176 return scriptNodeStack[
i];
178 Q_ASSERT_X(
false,
"currentEl",
"Stack does not contain object of type ");
179 return scriptNodeStack.last();
183 T ¤t(
int idx = 0)
185 return std::get<T>(currentEl<T>(idx).
item.value);
190 QmlStackElement ¤tQmlObjectOrComponentEl(
int idx = 0);
192 QmlStackElement ¤tNodeEl(
int i = 0);
193 ScriptStackElement ¤tScriptNodeEl(
int i = 0);
195 DomValue ¤tNode(
int i = 0);
197 void removeCurrentNode(std::optional<DomType> expectedType);
198 void removeCurrentScriptNode(std::optional<DomType> expectedType);
200 void pushEl(
const Path &
p,
const DomValue &
it, AST::Node *
n)
202 nodeStack.append({
p,
it, createMap(
it.kind,
p,
n) });
209 const ScriptElementVariant &
210 finalizeScriptExpression(
const ScriptElementVariant &element,
const Path &pathFromOwner,
213 void setScriptExpression (
const std::shared_ptr<ScriptExpression>&
value);
215 Path pathOfLastScriptNode()
const;
221 template<
typename AstNodeT>
222 static std::shared_ptr<ScriptElements::Literal> makeStringLiteral(
QStringView value,
225 auto myExp = std::make_shared<ScriptElements::Literal>(ast->firstSourceLocation(),
226 ast->lastSourceLocation());
227 myExp->setLiteralValue(
value.toString());
231 static std::shared_ptr<ScriptElements::Literal> makeStringLiteral(
QStringView value,
234 auto myExp = std::make_shared<ScriptElements::Literal>(loc);
235 myExp->setLiteralValue(
value.toString());
245 template<
typename ScriptElementT,
typename AstNodeT,
247 std::enable_if_t<!std::is_same_v<ScriptElementT, ScriptElements::ScriptList>>>
248 static decltype(
auto) makeScriptElement(AstNodeT *ast)
250 auto myExp = std::make_shared<ScriptElementT>(ast->firstSourceLocation(),
251 ast->lastSourceLocation());
260 template<
typename AstNodeT>
261 static std::shared_ptr<ScriptElements::GenericScriptElement>
262 makeGenericScriptElement(AstNodeT *ast, DomType kind)
264 auto myExp = std::make_shared<ScriptElements::GenericScriptElement>(
265 ast->firstSourceLocation(), ast->lastSourceLocation());
266 myExp->setKind(kind);
270 enum UnaryExpressionKind { Prefix, Postfix };
271 std::shared_ptr<ScriptElements::GenericScriptElement>
273 bool hasExpression, UnaryExpressionKind
type);
275 static std::shared_ptr<ScriptElements::GenericScriptElement>
276 makeGenericScriptElement(SourceLocation
location, DomType kind)
278 auto myExp = std::make_shared<ScriptElements::GenericScriptElement>(
location);
279 myExp->setKind(kind);
288 template<
typename AstNodeT>
289 static decltype(
auto) makeScriptList(AstNodeT *ast)
292 ScriptElements::ScriptList(ast->firstSourceLocation(), ast->lastSourceLocation());
296 template<
typename ScriptElementT>
297 void pushScriptElement(
const ScriptElementT &element)
299 Q_ASSERT_X(m_enableScriptExpressions,
"pushScriptElement",
300 "Cannot create script elements when they are disabled!");
301 scriptNodeStack.append(ScriptStackElement::from(element));
304 void disableScriptElements()
306 m_enableScriptExpressions =
false;
307 scriptNodeStack.clear();
310 ScriptElementVariant scriptElementForQualifiedId(AST::UiQualifiedId *expression);
316 void endVisit(AST::UiProgram *)
override;
318 bool visit(AST::UiPragma *
el)
override;
320 bool visit(AST::UiImport *
el)
override;
322 bool visit(AST::UiPublicMember *
el)
override;
323 void endVisit(AST::UiPublicMember *
el)
override;
326 ScriptElementVariant prepareBodyForFunction(AST::FunctionExpression *fExpression);
329 bool visit(AST::FunctionExpression *
el)
override;
330 void endVisit(AST::FunctionExpression *)
override;
332 bool visit(AST::FunctionDeclaration *
el)
override;
333 void endVisit(AST::FunctionDeclaration *)
override;
335 bool visit(AST::UiSourceElement *
el)
override;
336 void endVisit(AST::UiSourceElement *)
override;
387 const std::shared_ptr<ScriptElements::GenericScriptElement> &element);
543 return !scriptNodeStack.isEmpty() && !scriptNodeStack.last().isList();
547 return !scriptNodeStack.isEmpty() && scriptNodeStack.last().isList();
552 void endVisitForLists(T *
list,
const std::function<
int(T *)> &scriptElementsPerEntry = {});
565 bool visit(AST::name *) override; \
566 void endVisit(AST::name *) override;
578 m_enableScriptExpressions =
enable;
584 m_loadFileLazily =
enable;
591 void setScopeInDomAfterEndvisit();
592 void setScopeInDomBeforeEndvisit();
594 template<
typename U,
typename... V>
595 using IsInList = std::disjunction<std::is_same<U, V>...>;
597 using RequiresCustomIteration =
601 enum VisitorKind :
bool { DomCreator, ScopeCreator };
607 struct InactiveVisitorMarker
611 VisitorKind inactiveVisitorKind;
613 VisitorKind stillActiveVisitorKind()
const
615 return inactiveVisitorKind == DomCreator ? ScopeCreator : DomCreator;
620 void customListIteration(T *
t)
622 static_assert(RequiresCustomIteration<T>::value);
624 if constexpr (std::is_same_v<T, AST::PatternElementList>) {
627 }
else if constexpr (std::is_same_v<T, AST::PatternPropertyList>) {
629 }
else if constexpr (std::is_same_v<T, AST::FormalParameterList>) {
631 }
else if constexpr (std::is_same_v<T, AST::VariableDeclarationList>) {
633 }
else if constexpr (std::is_same_v<T, AST::ArgumentList>) {
635 }
else if constexpr (std::is_same_v<T, AST::PatternElementList>) {
644 static void initMarkerForActiveVisitor(std::optional<InactiveVisitorMarker> &inactiveVisitorMarker,
647 inactiveVisitorMarker.emplace();
648 inactiveVisitorMarker->inactiveVisitorKind = continueForDom ? ScopeCreator : DomCreator;
649 inactiveVisitorMarker->count = 1;
650 inactiveVisitorMarker->nodeKind = nodeKind;
654 bool performListIterationIfRequired(T *
t)
656 if constexpr (RequiresCustomIteration<T>::value) {
657 customListIteration(
t);
667 const auto handleVisitResult = [
this,
t](
const bool continueVisit) {
668 if (m_inactiveVisitorMarker && m_inactiveVisitorMarker->nodeKind ==
t->kind)
669 m_inactiveVisitorMarker->count += 1;
672 return performListIterationIfRequired(
t);
673 return continueVisit;
677 if (!m_inactiveVisitorMarker) {
678 bool continueForDom = m_domCreator.
visit(
t);
679 bool continueForScope = m_scopeCreator.
visit(
t);
680 if (!continueForDom && !continueForScope)
682 else if (continueForDom ^ continueForScope) {
683 initMarkerForActiveVisitor(m_inactiveVisitorMarker,
AST::Node::Kind(
t->kind),
685 return performListIterationIfRequired(
t);
687 Q_ASSERT(continueForDom && continueForScope);
688 return performListIterationIfRequired(
t);
694 switch (m_inactiveVisitorMarker->stillActiveVisitorKind()) {
696 return handleVisitResult(m_domCreator.
visit(
t));
698 return handleVisitResult(m_scopeCreator.
visit(
t));
706 if (m_inactiveVisitorMarker && m_inactiveVisitorMarker->nodeKind ==
t->kind) {
707 m_inactiveVisitorMarker->count -= 1;
708 if (m_inactiveVisitorMarker->count == 0)
709 m_inactiveVisitorMarker.reset();
711 if (m_inactiveVisitorMarker) {
712 switch (m_inactiveVisitorMarker->stillActiveVisitorKind()) {
723 setScopeInDomBeforeEndvisit();
725 setScopeInDomAfterEndvisit();
732 QString m_implicitImportDirectory;
734 QQmlDomAstCreator m_domCreator;
736 std::optional<InactiveVisitorMarker> m_inactiveVisitorMarker;
737 bool m_enableScriptExpressions =
false;
738 bool m_loadFileLazily =
false;