1 | // Copyright (C) 2021 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 "qqmldomreformatter_p.h" |
5 | #include "qqmldomcomments_p.h" |
6 | |
7 | #include <QtQml/private/qqmljsast_p.h> |
8 | #include <QtQml/private/qqmljsastvisitor_p.h> |
9 | #include <QtQml/private/qqmljsengine_p.h> |
10 | #include <QtQml/private/qqmljslexer_p.h> |
11 | |
12 | #include <QString> |
13 | |
14 | #include <limits> |
15 | |
16 | QT_BEGIN_NAMESPACE |
17 | namespace QQmlJS { |
18 | namespace Dom { |
19 | |
20 | using namespace AST; |
21 | |
22 | class Rewriter : protected BaseVisitor |
23 | { |
24 | OutWriter &lw; |
25 | std::shared_ptr<AstComments> ; |
26 | std::function<QStringView(SourceLocation)> loc2Str; |
27 | QHash<Node *, QList<std::function<void()>>> postOps; |
28 | int expressionDepth = 0; |
29 | |
30 | bool addSemicolons() const { return expressionDepth > 0; } |
31 | |
32 | public: |
33 | (OutWriter &lw, std::shared_ptr<AstComments> , |
34 | std::function<QStringView(SourceLocation)> loc2Str, Node *node) |
35 | : lw(lw), comments(comments), loc2Str(loc2Str) |
36 | { |
37 | accept(node); |
38 | } |
39 | |
40 | protected: |
41 | bool preVisit(Node *n) override |
42 | { |
43 | if (CommentedElement *c = comments->commentForNode(n)) { |
44 | c->writePre(lw); |
45 | postOps[n].append(t: [c, this]() { c->writePost(lw); }); |
46 | } |
47 | return true; |
48 | } |
49 | void postVisit(Node *n) override |
50 | { |
51 | for (auto &op : postOps[n]) { |
52 | op(); |
53 | } |
54 | postOps.remove(key: n); |
55 | } |
56 | |
57 | void accept(Node *node) { Node::accept(node, visitor: this); } |
58 | |
59 | void lnAcceptIndented(Node *node) |
60 | { |
61 | int indent = lw.increaseIndent(level: 1); |
62 | lw.ensureNewline(); |
63 | accept(node); |
64 | lw.decreaseIndent(level: 1, expectedIndent: indent); |
65 | } |
66 | |
67 | void out(const char *str) { lw.write(v: QString::fromLatin1(ba: str)); } |
68 | |
69 | void out(QStringView str) { lw.write(v: str); } |
70 | |
71 | void out(const SourceLocation &loc) |
72 | { |
73 | if (loc.length != 0) |
74 | out(str: loc2Str(loc)); |
75 | } |
76 | |
77 | void newLine() { lw.ensureNewline(); } |
78 | |
79 | bool acceptBlockOrIndented(Node *ast, bool finishWithSpaceOrNewline = false) |
80 | { |
81 | if (cast<Block *>(ast)) { |
82 | out(str: " " ); |
83 | accept(node: ast); |
84 | if (finishWithSpaceOrNewline) |
85 | out(str: " " ); |
86 | return true; |
87 | } else { |
88 | if (finishWithSpaceOrNewline) |
89 | postOps[ast].append(t: [this]() { this->newLine(); }); |
90 | lnAcceptIndented(node: ast); |
91 | return false; |
92 | } |
93 | } |
94 | |
95 | #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0) |
96 | // we are not supposed to handle the ui |
97 | bool visit(UiPragmaValueList *) override |
98 | { |
99 | Q_ASSERT(false); |
100 | return false; |
101 | } |
102 | #endif |
103 | bool visit(UiPragma *) override |
104 | { |
105 | Q_ASSERT(false); |
106 | return false; |
107 | } |
108 | bool visit(UiEnumDeclaration *) override |
109 | { |
110 | Q_ASSERT(false); |
111 | return false; |
112 | } |
113 | bool visit(UiEnumMemberList *) override |
114 | { |
115 | Q_ASSERT(false); |
116 | return false; |
117 | } |
118 | bool visit(UiImport *) override |
119 | { |
120 | Q_ASSERT(false); |
121 | return false; |
122 | } |
123 | bool visit(UiObjectDefinition *) override |
124 | { |
125 | Q_ASSERT(false); |
126 | return false; |
127 | } |
128 | bool visit(UiObjectInitializer *) override |
129 | { |
130 | Q_ASSERT(false); |
131 | return false; |
132 | } |
133 | bool visit(UiParameterList *) override |
134 | { |
135 | Q_ASSERT(false); |
136 | return false; |
137 | } |
138 | bool visit(UiPublicMember *) override |
139 | { |
140 | Q_ASSERT(false); |
141 | return false; |
142 | } |
143 | bool visit(UiObjectBinding *) override |
144 | { |
145 | Q_ASSERT(false); |
146 | return false; |
147 | } |
148 | bool visit(UiScriptBinding *) override |
149 | { |
150 | Q_ASSERT(false); |
151 | return false; |
152 | } |
153 | bool visit(UiArrayBinding *) override |
154 | { |
155 | Q_ASSERT(false); |
156 | return false; |
157 | } |
158 | bool (UiHeaderItemList *) override |
159 | { |
160 | Q_ASSERT(false); |
161 | return false; |
162 | } |
163 | bool visit(UiObjectMemberList *) override |
164 | { |
165 | Q_ASSERT(false); |
166 | return false; |
167 | } |
168 | bool visit(UiArrayMemberList *) override |
169 | { |
170 | Q_ASSERT(false); |
171 | return false; |
172 | } |
173 | bool visit(UiQualifiedId *) override |
174 | { |
175 | Q_ASSERT(false); |
176 | return false; |
177 | } |
178 | bool visit(UiProgram *) override |
179 | { |
180 | Q_ASSERT(false); |
181 | return false; |
182 | } |
183 | bool visit(UiSourceElement *) override |
184 | { |
185 | Q_ASSERT(false); |
186 | return false; |
187 | } |
188 | bool visit(UiVersionSpecifier *) override |
189 | { |
190 | Q_ASSERT(false); |
191 | return false; |
192 | } |
193 | bool visit(UiInlineComponent *) override |
194 | { |
195 | Q_ASSERT(false); |
196 | return false; |
197 | } |
198 | bool visit(UiAnnotation *) override |
199 | { |
200 | Q_ASSERT(false); |
201 | return false; |
202 | } |
203 | bool visit(UiAnnotationList *) override |
204 | { |
205 | Q_ASSERT(false); |
206 | return false; |
207 | } |
208 | bool visit(UiRequired *) override |
209 | { |
210 | Q_ASSERT(false); |
211 | return false; |
212 | } |
213 | |
214 | bool visit(ThisExpression *ast) override |
215 | { |
216 | out(loc: ast->thisToken); |
217 | return true; |
218 | } |
219 | bool visit(NullExpression *ast) override |
220 | { |
221 | out(loc: ast->nullToken); |
222 | return true; |
223 | } |
224 | bool visit(TrueLiteral *ast) override |
225 | { |
226 | out(loc: ast->trueToken); |
227 | return true; |
228 | } |
229 | bool visit(FalseLiteral *ast) override |
230 | { |
231 | out(loc: ast->falseToken); |
232 | return true; |
233 | } |
234 | bool visit(IdentifierExpression *ast) override |
235 | { |
236 | out(loc: ast->identifierToken); |
237 | return true; |
238 | } |
239 | bool visit(StringLiteral *ast) override |
240 | { |
241 | // correctly handle multiline literals |
242 | if (ast->literalToken.length == 0) |
243 | return true; |
244 | QStringView str = loc2Str(ast->literalToken); |
245 | if (lw.indentNextlines && str.contains(c: QLatin1Char('\n'))) { |
246 | out(str: str.mid(pos: 0, n: 1)); |
247 | lw.indentNextlines = false; |
248 | out(str: str.mid(pos: 1)); |
249 | lw.indentNextlines = true; |
250 | } else { |
251 | out(str); |
252 | } |
253 | return true; |
254 | } |
255 | bool visit(NumericLiteral *ast) override |
256 | { |
257 | out(loc: ast->literalToken); |
258 | return true; |
259 | } |
260 | bool visit(RegExpLiteral *ast) override |
261 | { |
262 | out(loc: ast->literalToken); |
263 | return true; |
264 | } |
265 | |
266 | bool visit(ArrayPattern *ast) override |
267 | { |
268 | out(loc: ast->lbracketToken); |
269 | int baseIndent = lw.increaseIndent(level: 1); |
270 | if (ast->elements) |
271 | accept(node: ast->elements); |
272 | out(loc: ast->commaToken); |
273 | lw.decreaseIndent(level: 1, expectedIndent: baseIndent); |
274 | out(loc: ast->rbracketToken); |
275 | return false; |
276 | } |
277 | |
278 | bool visit(ObjectPattern *ast) override |
279 | { |
280 | out(loc: ast->lbraceToken); |
281 | ++expressionDepth; |
282 | if (ast->properties) { |
283 | lnAcceptIndented(node: ast->properties); |
284 | newLine(); |
285 | } |
286 | --expressionDepth; |
287 | out(loc: ast->rbraceToken); |
288 | return false; |
289 | } |
290 | |
291 | bool visit(PatternElementList *ast) override |
292 | { |
293 | for (PatternElementList *it = ast; it; it = it->next) { |
294 | if (it->elision) |
295 | accept(node: it->elision); |
296 | if (it->elision && it->element) |
297 | out(str: ", " ); |
298 | if (it->element) |
299 | accept(node: it->element); |
300 | if (it->next) |
301 | out(str: ", " ); |
302 | } |
303 | return false; |
304 | } |
305 | |
306 | bool visit(PatternPropertyList *ast) override |
307 | { |
308 | for (PatternPropertyList *it = ast; it; it = it->next) { |
309 | PatternProperty *assignment = AST::cast<PatternProperty *>(ast: it->property); |
310 | if (assignment) { |
311 | preVisit(n: assignment); |
312 | const bool isStringLike = [this](const SourceLocation &loc) { |
313 | const auto name = loc2Str(loc); |
314 | if (name.first() == name.last()) { |
315 | if (name.first() == QStringLiteral("\'" ) |
316 | || name.first() == QStringLiteral("\"" )) |
317 | return true; |
318 | } |
319 | return false; |
320 | }(assignment->name->propertyNameToken); |
321 | |
322 | if (isStringLike) |
323 | out(str: "\"" ); |
324 | |
325 | accept(node: assignment->name); |
326 | if (isStringLike) |
327 | out(str: "\"" ); |
328 | |
329 | bool useInitializer = false; |
330 | const bool bindingIdentifierExist = !assignment->bindingIdentifier.isEmpty(); |
331 | if (assignment->colonToken.length > 0) { |
332 | out(str: ": " ); |
333 | useInitializer = true; |
334 | if (bindingIdentifierExist) |
335 | out(str: assignment->bindingIdentifier); |
336 | } |
337 | |
338 | if (assignment->initializer) { |
339 | if (bindingIdentifierExist) { |
340 | out(str: " = " ); |
341 | useInitializer = true; |
342 | } |
343 | if (useInitializer) |
344 | accept(node: assignment->initializer); |
345 | } |
346 | |
347 | if (it->next) { |
348 | out(str: "," ); |
349 | newLine(); |
350 | } |
351 | postVisit(n: assignment); |
352 | continue; |
353 | } |
354 | |
355 | PatternPropertyList *getterSetter = AST::cast<PatternPropertyList *>(ast: it->next); |
356 | if (getterSetter && getterSetter->property) { |
357 | switch (getterSetter->property->type) { |
358 | case PatternElement::Getter: |
359 | out(str: "get" ); |
360 | break; |
361 | case PatternElement::Setter: |
362 | out(str: "set" ); |
363 | break; |
364 | default: |
365 | break; |
366 | } |
367 | |
368 | accept(node: getterSetter->property->name); |
369 | out(str: "(" ); |
370 | // accept(getterSetter->formals); // TODO |
371 | out(str: ")" ); |
372 | out(str: " {" ); |
373 | // accept(getterSetter->functionBody); // TODO |
374 | out(str: " }" ); |
375 | } |
376 | } |
377 | return false; |
378 | } |
379 | |
380 | bool visit(NestedExpression *ast) override |
381 | { |
382 | out(loc: ast->lparenToken); |
383 | int baseIndent = lw.increaseIndent(level: 1); |
384 | accept(node: ast->expression); |
385 | lw.decreaseIndent(level: 1, expectedIndent: baseIndent); |
386 | out(loc: ast->rparenToken); |
387 | return false; |
388 | } |
389 | |
390 | bool visit(IdentifierPropertyName *ast) override |
391 | { |
392 | out(str: ast->id.toString()); |
393 | return true; |
394 | } |
395 | bool visit(StringLiteralPropertyName *ast) override |
396 | { |
397 | out(str: ast->id.toString()); |
398 | return true; |
399 | } |
400 | bool visit(NumericLiteralPropertyName *ast) override |
401 | { |
402 | out(str: QString::number(ast->id)); |
403 | return true; |
404 | } |
405 | |
406 | bool visit(TemplateLiteral *ast) override |
407 | { |
408 | // correctly handle multiline literals |
409 | if (ast->literalToken.length != 0) { |
410 | QStringView str = loc2Str(ast->literalToken); |
411 | if (lw.indentNextlines && str.contains(c: QLatin1Char('\n'))) { |
412 | out(str: str.mid(pos: 0, n: 1)); |
413 | lw.indentNextlines = false; |
414 | out(str: str.mid(pos: 1)); |
415 | lw.indentNextlines = true; |
416 | } else { |
417 | out(str); |
418 | } |
419 | } |
420 | accept(node: ast->expression); |
421 | return true; |
422 | } |
423 | |
424 | bool visit(ArrayMemberExpression *ast) override |
425 | { |
426 | accept(node: ast->base); |
427 | out(loc: ast->lbracketToken); |
428 | int indent = lw.increaseIndent(level: 1); |
429 | accept(node: ast->expression); |
430 | lw.decreaseIndent(level: 1, expectedIndent: indent); |
431 | out(loc: ast->rbracketToken); |
432 | return false; |
433 | } |
434 | |
435 | bool visit(FieldMemberExpression *ast) override |
436 | { |
437 | accept(node: ast->base); |
438 | out(loc: ast->dotToken); |
439 | out(loc: ast->identifierToken); |
440 | return false; |
441 | } |
442 | |
443 | bool visit(NewMemberExpression *ast) override |
444 | { |
445 | out(str: "new " ); // ast->newToken |
446 | accept(node: ast->base); |
447 | out(loc: ast->lparenToken); |
448 | accept(node: ast->arguments); |
449 | out(loc: ast->rparenToken); |
450 | return false; |
451 | } |
452 | |
453 | bool visit(NewExpression *ast) override |
454 | { |
455 | out(str: "new " ); // ast->newToken |
456 | accept(node: ast->expression); |
457 | return false; |
458 | } |
459 | |
460 | bool visit(CallExpression *ast) override |
461 | { |
462 | accept(node: ast->base); |
463 | out(loc: ast->lparenToken); |
464 | int baseIndent = lw.increaseIndent(level: 1); |
465 | accept(node: ast->arguments); |
466 | lw.decreaseIndent(level: 1, expectedIndent: baseIndent); |
467 | out(loc: ast->rparenToken); |
468 | return false; |
469 | } |
470 | |
471 | bool visit(PostIncrementExpression *ast) override |
472 | { |
473 | accept(node: ast->base); |
474 | out(loc: ast->incrementToken); |
475 | return false; |
476 | } |
477 | |
478 | bool visit(PostDecrementExpression *ast) override |
479 | { |
480 | accept(node: ast->base); |
481 | out(loc: ast->decrementToken); |
482 | return false; |
483 | } |
484 | |
485 | bool visit(PreIncrementExpression *ast) override |
486 | { |
487 | out(loc: ast->incrementToken); |
488 | accept(node: ast->expression); |
489 | return false; |
490 | } |
491 | |
492 | bool visit(PreDecrementExpression *ast) override |
493 | { |
494 | out(loc: ast->decrementToken); |
495 | accept(node: ast->expression); |
496 | return false; |
497 | } |
498 | |
499 | bool visit(DeleteExpression *ast) override |
500 | { |
501 | out(str: "delete " ); // ast->deleteToken |
502 | accept(node: ast->expression); |
503 | return false; |
504 | } |
505 | |
506 | bool visit(VoidExpression *ast) override |
507 | { |
508 | out(str: "void " ); // ast->voidToken |
509 | accept(node: ast->expression); |
510 | return false; |
511 | } |
512 | |
513 | bool visit(TypeOfExpression *ast) override |
514 | { |
515 | out(str: "typeof " ); // ast->typeofToken |
516 | accept(node: ast->expression); |
517 | return false; |
518 | } |
519 | |
520 | bool visit(UnaryPlusExpression *ast) override |
521 | { |
522 | out(loc: ast->plusToken); |
523 | accept(node: ast->expression); |
524 | return false; |
525 | } |
526 | |
527 | bool visit(UnaryMinusExpression *ast) override |
528 | { |
529 | out(loc: ast->minusToken); |
530 | accept(node: ast->expression); |
531 | return false; |
532 | } |
533 | |
534 | bool visit(TildeExpression *ast) override |
535 | { |
536 | out(loc: ast->tildeToken); |
537 | accept(node: ast->expression); |
538 | return false; |
539 | } |
540 | |
541 | bool visit(NotExpression *ast) override |
542 | { |
543 | out(loc: ast->notToken); |
544 | accept(node: ast->expression); |
545 | return false; |
546 | } |
547 | |
548 | bool visit(BinaryExpression *ast) override |
549 | { |
550 | accept(node: ast->left); |
551 | out(str: " " ); |
552 | out(loc: ast->operatorToken); |
553 | out(str: " " ); |
554 | accept(node: ast->right); |
555 | return false; |
556 | } |
557 | |
558 | bool visit(ConditionalExpression *ast) override |
559 | { |
560 | accept(node: ast->expression); |
561 | out(str: " ? " ); // ast->questionToken |
562 | accept(node: ast->ok); |
563 | out(str: " : " ); // ast->colonToken |
564 | accept(node: ast->ko); |
565 | return false; |
566 | } |
567 | |
568 | bool visit(Block *ast) override |
569 | { |
570 | out(loc: ast->lbraceToken); |
571 | ++expressionDepth; |
572 | lnAcceptIndented(node: ast->statements); |
573 | newLine(); |
574 | --expressionDepth; |
575 | out(loc: ast->rbraceToken); |
576 | return false; |
577 | } |
578 | |
579 | bool visit(VariableStatement *ast) override |
580 | { |
581 | out(loc: ast->declarationKindToken); |
582 | out(str: " " ); |
583 | accept(node: ast->declarations); |
584 | if (addSemicolons()) |
585 | out(str: ";" ); |
586 | return false; |
587 | } |
588 | |
589 | |
590 | void outputScope(VariableScope scope) { |
591 | switch (scope) { |
592 | case VariableScope::Const: |
593 | out(str: "const " ); |
594 | break; |
595 | case VariableScope::Let: |
596 | out(str: "let " ); |
597 | break; |
598 | case VariableScope::Var: |
599 | out(str: "var " ); |
600 | break; |
601 | default: |
602 | break; |
603 | } |
604 | } |
605 | |
606 | bool visit(PatternElement *ast) override |
607 | { |
608 | if (ast->isForDeclaration) { |
609 | outputScope(scope: ast->scope); |
610 | } |
611 | switch (ast->type) { |
612 | case PatternElement::Literal: |
613 | case PatternElement::Method: |
614 | case PatternElement::Binding: |
615 | break; |
616 | case PatternElement::Getter: |
617 | out(str: "get " ); |
618 | break; |
619 | case PatternElement::Setter: |
620 | out(str: "set " ); |
621 | break; |
622 | case PatternElement::SpreadElement: |
623 | out(str: "..." ); |
624 | break; |
625 | } |
626 | |
627 | accept(node: ast->bindingTarget); |
628 | if (!ast->destructuringPattern()) |
629 | out(loc: ast->identifierToken); |
630 | if (ast->initializer) { |
631 | if (ast->isVariableDeclaration() || ast->type == AST::PatternElement::Binding) |
632 | out(str: " = " ); |
633 | accept(node: ast->initializer); |
634 | } |
635 | return false; |
636 | } |
637 | |
638 | bool visit(EmptyStatement *ast) override |
639 | { |
640 | out(loc: ast->semicolonToken); |
641 | return false; |
642 | } |
643 | |
644 | bool visit(IfStatement *ast) override |
645 | { |
646 | out(loc: ast->ifToken); |
647 | out(str: " " ); |
648 | out(loc: ast->lparenToken); |
649 | preVisit(n: ast->expression); |
650 | ast->expression->accept0(visitor: this); |
651 | out(loc: ast->rparenToken); |
652 | postVisit(n: ast->expression); |
653 | acceptBlockOrIndented(ast: ast->ok, finishWithSpaceOrNewline: ast->ko); |
654 | if (ast->ko) { |
655 | out(loc: ast->elseToken); |
656 | if (cast<Block *>(ast: ast->ko) || cast<IfStatement *>(ast: ast->ko)) { |
657 | out(str: " " ); |
658 | accept(node: ast->ko); |
659 | } else { |
660 | lnAcceptIndented(node: ast->ko); |
661 | } |
662 | } |
663 | return false; |
664 | } |
665 | |
666 | bool visit(DoWhileStatement *ast) override |
667 | { |
668 | out(loc: ast->doToken); |
669 | acceptBlockOrIndented(ast: ast->statement, finishWithSpaceOrNewline: true); |
670 | out(loc: ast->whileToken); |
671 | out(str: " " ); |
672 | out(loc: ast->lparenToken); |
673 | accept(node: ast->expression); |
674 | out(loc: ast->rparenToken); |
675 | return false; |
676 | } |
677 | |
678 | bool visit(WhileStatement *ast) override |
679 | { |
680 | out(loc: ast->whileToken); |
681 | out(str: " " ); |
682 | out(loc: ast->lparenToken); |
683 | accept(node: ast->expression); |
684 | out(loc: ast->rparenToken); |
685 | acceptBlockOrIndented(ast: ast->statement); |
686 | return false; |
687 | } |
688 | |
689 | bool visit(ForStatement *ast) override |
690 | { |
691 | out(loc: ast->forToken); |
692 | out(str: " " ); |
693 | out(loc: ast->lparenToken); |
694 | if (ast->initialiser) { |
695 | accept(node: ast->initialiser); |
696 | } else if (ast->declarations) { |
697 | outputScope(scope: ast->declarations->declaration->scope); |
698 | accept(node: ast->declarations); |
699 | } |
700 | out(str: "; " ); // ast->firstSemicolonToken |
701 | accept(node: ast->condition); |
702 | out(str: "; " ); // ast->secondSemicolonToken |
703 | accept(node: ast->expression); |
704 | out(loc: ast->rparenToken); |
705 | acceptBlockOrIndented(ast: ast->statement); |
706 | return false; |
707 | } |
708 | |
709 | bool visit(ForEachStatement *ast) override |
710 | { |
711 | out(loc: ast->forToken); |
712 | out(str: " " ); |
713 | out(loc: ast->lparenToken); |
714 | accept(node: ast->lhs); |
715 | out(str: " " ); |
716 | out(loc: ast->inOfToken); |
717 | out(str: " " ); |
718 | accept(node: ast->expression); |
719 | out(loc: ast->rparenToken); |
720 | acceptBlockOrIndented(ast: ast->statement); |
721 | return false; |
722 | } |
723 | |
724 | bool visit(ContinueStatement *ast) override |
725 | { |
726 | out(loc: ast->continueToken); |
727 | if (!ast->label.isNull()) { |
728 | out(str: " " ); |
729 | out(loc: ast->identifierToken); |
730 | } |
731 | if (addSemicolons()) |
732 | out(str: ";" ); |
733 | return false; |
734 | } |
735 | |
736 | bool visit(BreakStatement *ast) override |
737 | { |
738 | out(loc: ast->breakToken); |
739 | if (!ast->label.isNull()) { |
740 | out(str: " " ); |
741 | out(loc: ast->identifierToken); |
742 | } |
743 | if (addSemicolons()) |
744 | out(str: ";" ); |
745 | return false; |
746 | } |
747 | |
748 | bool visit(ReturnStatement *ast) override |
749 | { |
750 | out(loc: ast->returnToken); |
751 | if (ast->expression) { |
752 | if (ast->returnToken.length != 0) |
753 | out(str: " " ); |
754 | accept(node: ast->expression); |
755 | } |
756 | if (ast->returnToken.length > 0 && addSemicolons()) |
757 | out(str: ";" ); |
758 | return false; |
759 | } |
760 | |
761 | bool visit(ThrowStatement *ast) override |
762 | { |
763 | out(loc: ast->throwToken); |
764 | if (ast->expression) { |
765 | out(str: " " ); |
766 | accept(node: ast->expression); |
767 | } |
768 | if (addSemicolons()) |
769 | out(str: ";" ); |
770 | return false; |
771 | } |
772 | |
773 | bool visit(WithStatement *ast) override |
774 | { |
775 | out(loc: ast->withToken); |
776 | out(str: " " ); |
777 | out(loc: ast->lparenToken); |
778 | accept(node: ast->expression); |
779 | out(loc: ast->rparenToken); |
780 | acceptBlockOrIndented(ast: ast->statement); |
781 | return false; |
782 | } |
783 | |
784 | bool visit(SwitchStatement *ast) override |
785 | { |
786 | out(loc: ast->switchToken); |
787 | out(str: " " ); |
788 | out(loc: ast->lparenToken); |
789 | accept(node: ast->expression); |
790 | out(loc: ast->rparenToken); |
791 | out(str: " " ); |
792 | accept(node: ast->block); |
793 | return false; |
794 | } |
795 | |
796 | bool visit(CaseBlock *ast) override |
797 | { |
798 | out(loc: ast->lbraceToken); |
799 | ++expressionDepth; |
800 | newLine(); |
801 | accept(node: ast->clauses); |
802 | if (ast->clauses && ast->defaultClause) |
803 | newLine(); |
804 | accept(node: ast->defaultClause); |
805 | if (ast->moreClauses) |
806 | newLine(); |
807 | accept(node: ast->moreClauses); |
808 | newLine(); |
809 | --expressionDepth; |
810 | out(loc: ast->rbraceToken); |
811 | return false; |
812 | } |
813 | |
814 | bool visit(CaseClause *ast) override |
815 | { |
816 | out(str: "case " ); // ast->caseToken |
817 | accept(node: ast->expression); |
818 | out(loc: ast->colonToken); |
819 | if (ast->statements) |
820 | lnAcceptIndented(node: ast->statements); |
821 | return false; |
822 | } |
823 | |
824 | bool visit(DefaultClause *ast) override |
825 | { |
826 | out(loc: ast->defaultToken); |
827 | out(loc: ast->colonToken); |
828 | lnAcceptIndented(node: ast->statements); |
829 | return false; |
830 | } |
831 | |
832 | bool visit(LabelledStatement *ast) override |
833 | { |
834 | out(loc: ast->identifierToken); |
835 | out(str: ": " ); // ast->colonToken |
836 | accept(node: ast->statement); |
837 | return false; |
838 | } |
839 | |
840 | bool visit(TryStatement *ast) override |
841 | { |
842 | out(str: "try " ); // ast->tryToken |
843 | accept(node: ast->statement); |
844 | if (ast->catchExpression) { |
845 | out(str: " " ); |
846 | accept(node: ast->catchExpression); |
847 | } |
848 | if (ast->finallyExpression) { |
849 | out(str: " " ); |
850 | accept(node: ast->finallyExpression); |
851 | } |
852 | return false; |
853 | } |
854 | |
855 | bool visit(Catch *ast) override |
856 | { |
857 | out(loc: ast->catchToken); |
858 | out(str: " " ); |
859 | out(loc: ast->lparenToken); |
860 | out(loc: ast->identifierToken); |
861 | out(str: ") " ); // ast->rparenToken |
862 | accept(node: ast->statement); |
863 | return false; |
864 | } |
865 | |
866 | bool visit(Finally *ast) override |
867 | { |
868 | out(str: "finally " ); // ast->finallyToken |
869 | accept(node: ast->statement); |
870 | return false; |
871 | } |
872 | |
873 | bool visit(FunctionDeclaration *ast) override |
874 | { |
875 | return visit(ast: static_cast<FunctionExpression *>(ast)); |
876 | } |
877 | |
878 | bool visit(FunctionExpression *ast) override |
879 | { |
880 | if (!ast->isArrowFunction) { |
881 | out(str: "function " ); // ast->functionToken |
882 | if (!ast->name.isNull()) |
883 | out(loc: ast->identifierToken); |
884 | } |
885 | out(loc: ast->lparenToken); |
886 | const bool needParentheses = ast->formals && |
887 | (ast->formals->next || |
888 | (ast->formals->element && ast->formals->element->bindingTarget)); |
889 | if (ast->isArrowFunction && needParentheses) |
890 | out(str: "(" ); |
891 | int baseIndent = lw.increaseIndent(level: 1); |
892 | accept(node: ast->formals); |
893 | lw.decreaseIndent(level: 1, expectedIndent: baseIndent); |
894 | if (ast->isArrowFunction && needParentheses) |
895 | out(str: ")" ); |
896 | out(loc: ast->rparenToken); |
897 | if (ast->isArrowFunction && !ast->formals) |
898 | out(str: "()" ); |
899 | out(str: " " ); |
900 | if (ast->isArrowFunction) |
901 | out(str: "=> " ); |
902 | out(loc: ast->lbraceToken); |
903 | if (ast->lbraceToken.length != 0) |
904 | ++expressionDepth; |
905 | if (ast->body) { |
906 | if (ast->body->next || ast->lbraceToken.length != 0) { |
907 | lnAcceptIndented(node: ast->body); |
908 | newLine(); |
909 | } else { |
910 | // print a single statement in one line. E.g. x => x * 2 |
911 | baseIndent = lw.increaseIndent(level: 1); |
912 | accept(node: ast->body); |
913 | lw.decreaseIndent(level: 1, expectedIndent: baseIndent); |
914 | } |
915 | } |
916 | if (ast->lbraceToken.length != 0) |
917 | --expressionDepth; |
918 | out(loc: ast->rbraceToken); |
919 | return false; |
920 | } |
921 | |
922 | bool visit(Elision *ast) override |
923 | { |
924 | for (Elision *it = ast; it; it = it->next) { |
925 | if (it->next) |
926 | out(str: ", " ); // ast->commaToken |
927 | } |
928 | return false; |
929 | } |
930 | |
931 | bool visit(ArgumentList *ast) override |
932 | { |
933 | for (ArgumentList *it = ast; it; it = it->next) { |
934 | if (it->isSpreadElement) |
935 | out(str: "..." ); |
936 | accept(node: it->expression); |
937 | if (it->next) { |
938 | out(str: ", " ); // it->commaToken |
939 | } |
940 | } |
941 | return false; |
942 | } |
943 | |
944 | bool visit(StatementList *ast) override |
945 | { |
946 | ++expressionDepth; |
947 | for (StatementList *it = ast; it; it = it->next) { |
948 | // ### work around parser bug: skip empty statements with wrong tokens |
949 | if (EmptyStatement *emptyStatement = cast<EmptyStatement *>(ast: it->statement)) { |
950 | if (loc2Str(emptyStatement->semicolonToken) != QLatin1String(";" )) |
951 | continue; |
952 | } |
953 | |
954 | accept(node: it->statement); |
955 | if (it->next) |
956 | newLine(); |
957 | } |
958 | --expressionDepth; |
959 | return false; |
960 | } |
961 | |
962 | bool visit(VariableDeclarationList *ast) override |
963 | { |
964 | for (VariableDeclarationList *it = ast; it; it = it->next) { |
965 | accept(node: it->declaration); |
966 | if (it->next) |
967 | out(str: ", " ); // it->commaToken |
968 | } |
969 | return false; |
970 | } |
971 | |
972 | bool visit(CaseClauses *ast) override |
973 | { |
974 | for (CaseClauses *it = ast; it; it = it->next) { |
975 | accept(node: it->clause); |
976 | if (it->next) |
977 | newLine(); |
978 | } |
979 | return false; |
980 | } |
981 | |
982 | bool visit(FormalParameterList *ast) override |
983 | { |
984 | for (FormalParameterList *it = ast; it; it = it->next) { |
985 | // compare FormalParameterList::finish |
986 | if (auto id = it->element->bindingIdentifier.toString(); !id.isEmpty()) |
987 | out(str: id); |
988 | if (it->element->bindingTarget) |
989 | accept(node: it->element->bindingTarget); |
990 | if (it->next) |
991 | out(str: ", " ); |
992 | } |
993 | return false; |
994 | } |
995 | |
996 | // to check |
997 | bool visit(TypeExpression *) override { return true; } |
998 | bool visit(SuperLiteral *) override |
999 | { |
1000 | out(str: "super" ); |
1001 | return true; |
1002 | } |
1003 | bool visit(PatternProperty *) override { return true; } |
1004 | bool visit(ComputedPropertyName *) override |
1005 | { |
1006 | out(str: "[" ); |
1007 | return true; |
1008 | } |
1009 | bool visit(TaggedTemplate *) override { return true; } |
1010 | bool visit(Expression *el) override |
1011 | { |
1012 | accept(node: el->left); |
1013 | out(str: ", " ); |
1014 | accept(node: el->right); |
1015 | return false; |
1016 | } |
1017 | bool visit(ExpressionStatement *el) override |
1018 | { |
1019 | if (addSemicolons()) |
1020 | postOps[el->expression].append(t: [this]() { out(str: ";" ); }); |
1021 | return true; |
1022 | } |
1023 | bool visit(YieldExpression *) override { return true; } |
1024 | bool visit(ClassExpression *) override { return true; } |
1025 | |
1026 | // Return false because we want to omit default function calls in accept0 implementation. |
1027 | bool visit(ClassDeclaration *ast) override |
1028 | { |
1029 | preVisit(n: ast); |
1030 | out(loc: ast->classToken); |
1031 | out(str: " " ); |
1032 | out(str: ast->name); |
1033 | if (ast->heritage) { |
1034 | out(str: " extends " ); |
1035 | accept(node: ast->heritage); |
1036 | } |
1037 | out(str: " {" ); |
1038 | int baseIndent = lw.increaseIndent(); |
1039 | for (ClassElementList *it = ast->elements; it; it = it->next) { |
1040 | PatternProperty *property = it->property; |
1041 | lw.newline(); |
1042 | preVisit(n: property); |
1043 | if (it->isStatic) |
1044 | out(str: "static " ); |
1045 | if (property->type == PatternProperty::Getter) |
1046 | out(str: "get " ); |
1047 | else if (property->type == PatternProperty::Setter) |
1048 | out(str: "set " ); |
1049 | FunctionExpression *f = AST::cast<FunctionExpression *>(ast: property->initializer); |
1050 | const bool scoped = f->lbraceToken.length != 0; |
1051 | out(loc: f->functionToken); |
1052 | out(loc: f->lparenToken); |
1053 | accept(node: f->formals); |
1054 | out(loc: f->rparenToken); |
1055 | out(loc: f->lbraceToken); |
1056 | if (scoped) |
1057 | ++expressionDepth; |
1058 | if (f->body) { |
1059 | if (f->body->next || scoped) { |
1060 | lnAcceptIndented(node: f->body); |
1061 | lw.newline(); |
1062 | } else { |
1063 | baseIndent = lw.increaseIndent(level: 1); |
1064 | accept(node: f->body); |
1065 | lw.decreaseIndent(level: 1, expectedIndent: baseIndent); |
1066 | } |
1067 | } |
1068 | if (scoped) |
1069 | --expressionDepth; |
1070 | out(loc: f->rbraceToken); |
1071 | lw.newline(); |
1072 | postVisit(n: property); |
1073 | } |
1074 | lw.decreaseIndent(level: 1, expectedIndent: baseIndent); |
1075 | out(str: "}" ); |
1076 | postVisit(n: ast); |
1077 | return false; |
1078 | } |
1079 | |
1080 | bool visit(ClassElementList *) override { return true; } |
1081 | bool visit(Program *) override { return true; } |
1082 | bool visit(NameSpaceImport *) override { return true; } |
1083 | bool visit(ImportSpecifier *) override { return true; } |
1084 | bool visit(ImportsList *) override { return true; } |
1085 | bool visit(NamedImports *) override { return true; } |
1086 | bool visit(FromClause *) override { return true; } |
1087 | bool visit(ImportClause *) override { return true; } |
1088 | bool visit(ImportDeclaration *) override { return true; } |
1089 | bool visit(ExportSpecifier *) override { return true; } |
1090 | bool visit(ExportsList *) override { return true; } |
1091 | bool visit(ExportClause *) override { return true; } |
1092 | bool visit(ExportDeclaration *) override { return true; } |
1093 | bool visit(ESModule *) override { return true; } |
1094 | bool visit(DebuggerStatement *) override { return true; } |
1095 | bool visit(Type *) override { return true; } |
1096 | bool visit(TypeAnnotation *) override { return true; } |
1097 | |
1098 | // overridden to use BasicVisitor (and ensure warnings about new added AST) |
1099 | void endVisit(UiProgram *) override { } |
1100 | void endVisit(UiImport *) override { } |
1101 | void (UiHeaderItemList *) override { } |
1102 | #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0) |
1103 | void endVisit(UiPragmaValueList *) override { } |
1104 | #endif |
1105 | void endVisit(UiPragma *) override { } |
1106 | void endVisit(UiPublicMember *) override { } |
1107 | void endVisit(UiSourceElement *) override { } |
1108 | void endVisit(UiObjectDefinition *) override { } |
1109 | void endVisit(UiObjectInitializer *) override { } |
1110 | void endVisit(UiObjectBinding *) override { } |
1111 | void endVisit(UiScriptBinding *) override { } |
1112 | void endVisit(UiArrayBinding *) override { } |
1113 | void endVisit(UiParameterList *) override { } |
1114 | void endVisit(UiObjectMemberList *) override { } |
1115 | void endVisit(UiArrayMemberList *) override { } |
1116 | void endVisit(UiQualifiedId *) override { } |
1117 | void endVisit(UiEnumDeclaration *) override { } |
1118 | void endVisit(UiEnumMemberList *) override { } |
1119 | void endVisit(UiVersionSpecifier *) override { } |
1120 | void endVisit(UiInlineComponent *) override { } |
1121 | void endVisit(UiAnnotation *) override { } |
1122 | void endVisit(UiAnnotationList *) override { } |
1123 | void endVisit(UiRequired *) override { } |
1124 | void endVisit(TypeExpression *) override { } |
1125 | void endVisit(ThisExpression *) override { } |
1126 | void endVisit(IdentifierExpression *) override { } |
1127 | void endVisit(NullExpression *) override { } |
1128 | void endVisit(TrueLiteral *) override { } |
1129 | void endVisit(FalseLiteral *) override { } |
1130 | void endVisit(SuperLiteral *) override { } |
1131 | void endVisit(StringLiteral *) override { } |
1132 | void endVisit(TemplateLiteral *) override { } |
1133 | void endVisit(NumericLiteral *) override { } |
1134 | void endVisit(RegExpLiteral *) override { } |
1135 | void endVisit(ArrayPattern *) override { } |
1136 | void endVisit(ObjectPattern *) override { } |
1137 | void endVisit(PatternElementList *) override { } |
1138 | void endVisit(PatternPropertyList *) override { } |
1139 | void endVisit(PatternElement *) override { } |
1140 | void endVisit(PatternProperty *) override { } |
1141 | void endVisit(Elision *) override { } |
1142 | void endVisit(NestedExpression *) override { } |
1143 | void endVisit(IdentifierPropertyName *) override { } |
1144 | void endVisit(StringLiteralPropertyName *) override { } |
1145 | void endVisit(NumericLiteralPropertyName *) override { } |
1146 | void endVisit(ComputedPropertyName *) override { out(str: "]" ); } |
1147 | void endVisit(ArrayMemberExpression *) override { } |
1148 | void endVisit(FieldMemberExpression *) override { } |
1149 | void endVisit(TaggedTemplate *) override { } |
1150 | void endVisit(NewMemberExpression *) override { } |
1151 | void endVisit(NewExpression *) override { } |
1152 | void endVisit(CallExpression *) override { } |
1153 | void endVisit(ArgumentList *) override { } |
1154 | void endVisit(PostIncrementExpression *) override { } |
1155 | void endVisit(PostDecrementExpression *) override { } |
1156 | void endVisit(DeleteExpression *) override { } |
1157 | void endVisit(VoidExpression *) override { } |
1158 | void endVisit(TypeOfExpression *) override { } |
1159 | void endVisit(PreIncrementExpression *) override { } |
1160 | void endVisit(PreDecrementExpression *) override { } |
1161 | void endVisit(UnaryPlusExpression *) override { } |
1162 | void endVisit(UnaryMinusExpression *) override { } |
1163 | void endVisit(TildeExpression *) override { } |
1164 | void endVisit(NotExpression *) override { } |
1165 | void endVisit(BinaryExpression *) override { } |
1166 | void endVisit(ConditionalExpression *) override { } |
1167 | void endVisit(Expression *) override { } |
1168 | void endVisit(Block *) override { } |
1169 | void endVisit(StatementList *) override { } |
1170 | void endVisit(VariableStatement *) override { } |
1171 | void endVisit(VariableDeclarationList *) override { } |
1172 | void endVisit(EmptyStatement *) override { } |
1173 | void endVisit(ExpressionStatement *) override { } |
1174 | void endVisit(IfStatement *) override { } |
1175 | void endVisit(DoWhileStatement *) override { } |
1176 | void endVisit(WhileStatement *) override { } |
1177 | void endVisit(ForStatement *) override { } |
1178 | void endVisit(ForEachStatement *) override { } |
1179 | void endVisit(ContinueStatement *) override { } |
1180 | void endVisit(BreakStatement *) override { } |
1181 | void endVisit(ReturnStatement *) override { } |
1182 | void endVisit(YieldExpression *) override { } |
1183 | void endVisit(WithStatement *) override { } |
1184 | void endVisit(SwitchStatement *) override { } |
1185 | void endVisit(CaseBlock *) override { } |
1186 | void endVisit(CaseClauses *) override { } |
1187 | void endVisit(CaseClause *) override { } |
1188 | void endVisit(DefaultClause *) override { } |
1189 | void endVisit(LabelledStatement *) override { } |
1190 | void endVisit(ThrowStatement *) override { } |
1191 | void endVisit(TryStatement *) override { } |
1192 | void endVisit(Catch *) override { } |
1193 | void endVisit(Finally *) override { } |
1194 | void endVisit(FunctionDeclaration *) override { } |
1195 | void endVisit(FunctionExpression *) override { } |
1196 | void endVisit(FormalParameterList *) override { } |
1197 | void endVisit(ClassExpression *) override { } |
1198 | void endVisit(ClassDeclaration *) override { } |
1199 | void endVisit(ClassElementList *) override { } |
1200 | void endVisit(Program *) override { } |
1201 | void endVisit(NameSpaceImport *) override { } |
1202 | void endVisit(ImportSpecifier *) override { } |
1203 | void endVisit(ImportsList *) override { } |
1204 | void endVisit(NamedImports *) override { } |
1205 | void endVisit(FromClause *) override { } |
1206 | void endVisit(ImportClause *) override { } |
1207 | void endVisit(ImportDeclaration *) override { } |
1208 | void endVisit(ExportSpecifier *) override { } |
1209 | void endVisit(ExportsList *) override { } |
1210 | void endVisit(ExportClause *) override { } |
1211 | void endVisit(ExportDeclaration *) override { } |
1212 | void endVisit(ESModule *) override { } |
1213 | void endVisit(DebuggerStatement *) override { } |
1214 | void endVisit(Type *) override { } |
1215 | void endVisit(TypeAnnotation *) override { } |
1216 | |
1217 | void throwRecursionDepthError() override |
1218 | { |
1219 | out(str: "/* ERROR: Hit recursion limit visiting AST, rewrite failed */" ); |
1220 | } |
1221 | }; |
1222 | |
1223 | void (OutWriter &lw, std::shared_ptr<AstComments> , |
1224 | const std::function<QStringView(SourceLocation)> loc2Str, AST::Node *n) |
1225 | { |
1226 | if (n) { |
1227 | Rewriter rewriter(lw, comments, loc2Str, n); |
1228 | } |
1229 | } |
1230 | |
1231 | } // namespace Dom |
1232 | } // namespace QQmlJS |
1233 | QT_END_NAMESPACE |
1234 | |