Formatter.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915
  1. /*
  2. * Copyright (c) 2020, the SerenityOS developers.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "Formatter.h"
  7. #include "AST.h"
  8. #include "Parser.h"
  9. #include "PosixParser.h"
  10. #include <AK/Hex.h>
  11. #include <AK/ScopedValueRollback.h>
  12. #include <AK/TemporaryChange.h>
  13. namespace Shell {
  14. DeprecatedString Formatter::format()
  15. {
  16. auto node = m_root_node ?: (m_parse_as_posix ? Posix::Parser(m_source).parse() : Parser(m_source).parse());
  17. if (m_cursor >= 0)
  18. m_output_cursor = m_cursor;
  19. if (!node)
  20. return DeprecatedString();
  21. if (node->is_syntax_error())
  22. return m_source;
  23. if (m_cursor >= 0) {
  24. auto hit_test = node->hit_test_position(m_cursor);
  25. if (hit_test.matching_node)
  26. m_hit_node = hit_test.matching_node.ptr();
  27. else
  28. m_hit_node = nullptr;
  29. }
  30. m_parent_node = nullptr;
  31. node->visit(*this);
  32. VERIFY(m_builders.size() == 1);
  33. auto string = current_builder().string_view();
  34. if (!string.ends_with(' '))
  35. current_builder().append(m_trivia);
  36. return current_builder().to_deprecated_string();
  37. }
  38. void Formatter::with_added_indent(int indent, Function<void()> callback)
  39. {
  40. TemporaryChange indent_change { m_current_indent, m_current_indent + indent };
  41. callback();
  42. }
  43. void Formatter::in_new_block(Function<void()> callback)
  44. {
  45. current_builder().append('{');
  46. with_added_indent(1, [&] {
  47. insert_separator();
  48. callback();
  49. });
  50. insert_separator();
  51. current_builder().append('}');
  52. }
  53. DeprecatedString Formatter::in_new_builder(Function<void()> callback, StringBuilder new_builder)
  54. {
  55. m_builders.append(move(new_builder));
  56. callback();
  57. return m_builders.take_last().to_deprecated_string();
  58. }
  59. void Formatter::test_and_update_output_cursor(const AST::Node* node)
  60. {
  61. if (!node)
  62. return;
  63. if (node != m_hit_node)
  64. return;
  65. m_output_cursor = current_builder().length() + m_cursor - node->position().start_offset;
  66. }
  67. void Formatter::visited(const AST::Node* node)
  68. {
  69. m_last_visited_node = node;
  70. }
  71. void Formatter::will_visit(const AST::Node* node)
  72. {
  73. if (!m_last_visited_node)
  74. return;
  75. if (!node)
  76. return;
  77. auto direct_sequence_child = !m_parent_node || m_parent_node->kind() == AST::Node::Kind::Sequence;
  78. if (direct_sequence_child && node->kind() != AST::Node::Kind::Sequence && node->kind() != AST::Node::Kind::Execute) {
  79. // Collapse more than one empty line to a single one.
  80. if (node->position().start_line.line_number - m_last_visited_node->position().end_line.line_number > 1)
  81. insert_separator();
  82. }
  83. }
  84. void Formatter::insert_separator(bool escaped)
  85. {
  86. if (escaped)
  87. current_builder().append('\\');
  88. current_builder().append('\n');
  89. if (!escaped && !m_heredocs_to_append_after_sequence.is_empty()) {
  90. for (auto& entry : m_heredocs_to_append_after_sequence) {
  91. current_builder().append(entry);
  92. }
  93. m_heredocs_to_append_after_sequence.clear();
  94. }
  95. insert_indent();
  96. }
  97. void Formatter::insert_indent()
  98. {
  99. for (size_t i = 0; i < m_current_indent; ++i)
  100. current_builder().append(" "sv);
  101. }
  102. void Formatter::visit(const AST::PathRedirectionNode* node)
  103. {
  104. will_visit(node);
  105. test_and_update_output_cursor(node);
  106. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  107. NodeVisitor::visit(node);
  108. visited(node);
  109. }
  110. void Formatter::visit(const AST::And* node)
  111. {
  112. will_visit(node);
  113. test_and_update_output_cursor(node);
  114. auto should_indent = m_parent_node && m_parent_node->kind() != AST::Node::Kind::And;
  115. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  116. with_added_indent(should_indent ? 1 : 0, [&] {
  117. node->left()->visit(*this);
  118. current_builder().append(' ');
  119. insert_separator(true);
  120. current_builder().append("&& "sv);
  121. node->right()->visit(*this);
  122. });
  123. visited(node);
  124. }
  125. void Formatter::visit(const AST::ListConcatenate* node)
  126. {
  127. will_visit(node);
  128. test_and_update_output_cursor(node);
  129. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  130. auto first = true;
  131. for (auto& subnode : node->list()) {
  132. if (!first)
  133. current_builder().append(' ');
  134. first = false;
  135. subnode->visit(*this);
  136. }
  137. visited(node);
  138. }
  139. void Formatter::visit(const AST::Background* node)
  140. {
  141. will_visit(node);
  142. test_and_update_output_cursor(node);
  143. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  144. NodeVisitor::visit(node);
  145. current_builder().append(" &"sv);
  146. visited(node);
  147. }
  148. void Formatter::visit(const AST::BarewordLiteral* node)
  149. {
  150. will_visit(node);
  151. test_and_update_output_cursor(node);
  152. current_builder().append(node->text());
  153. visited(node);
  154. }
  155. void Formatter::visit(const AST::BraceExpansion* node)
  156. {
  157. will_visit(node);
  158. test_and_update_output_cursor(node);
  159. if (!m_parent_node || m_parent_node->kind() != AST::Node::Kind::Slice)
  160. current_builder().append('{');
  161. {
  162. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  163. bool first = true;
  164. for (auto& entry : node->entries()) {
  165. if (!first)
  166. current_builder().append(',');
  167. first = false;
  168. entry.visit(*this);
  169. }
  170. }
  171. if (!m_parent_node || m_parent_node->kind() != AST::Node::Kind::Slice)
  172. current_builder().append('}');
  173. visited(node);
  174. }
  175. void Formatter::visit(const AST::CastToCommand* node)
  176. {
  177. will_visit(node);
  178. test_and_update_output_cursor(node);
  179. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  180. NodeVisitor::visit(node);
  181. visited(node);
  182. }
  183. void Formatter::visit(const AST::CastToList* node)
  184. {
  185. will_visit(node);
  186. test_and_update_output_cursor(node);
  187. current_builder().append('(');
  188. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  189. NodeVisitor::visit(node);
  190. current_builder().append(')');
  191. visited(node);
  192. }
  193. void Formatter::visit(const AST::CloseFdRedirection* node)
  194. {
  195. will_visit(node);
  196. test_and_update_output_cursor(node);
  197. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  198. current_builder().appendff("{}>&-", node->fd());
  199. visited(node);
  200. }
  201. void Formatter::visit(const AST::CommandLiteral*)
  202. {
  203. VERIFY_NOT_REACHED();
  204. }
  205. void Formatter::visit(const AST::Comment* node)
  206. {
  207. will_visit(node);
  208. test_and_update_output_cursor(node);
  209. current_builder().append("#"sv);
  210. current_builder().append(node->text());
  211. visited(node);
  212. }
  213. void Formatter::visit(const AST::ContinuationControl* node)
  214. {
  215. will_visit(node);
  216. test_and_update_output_cursor(node);
  217. if (node->continuation_kind() == AST::ContinuationControl::Break)
  218. current_builder().append("break"sv);
  219. else if (node->continuation_kind() == AST::ContinuationControl::Continue)
  220. current_builder().append("continue"sv);
  221. else
  222. VERIFY_NOT_REACHED();
  223. visited(node);
  224. }
  225. void Formatter::visit(const AST::DynamicEvaluate* node)
  226. {
  227. will_visit(node);
  228. test_and_update_output_cursor(node);
  229. current_builder().append('$');
  230. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  231. NodeVisitor::visit(node);
  232. visited(node);
  233. }
  234. void Formatter::visit(const AST::DoubleQuotedString* node)
  235. {
  236. will_visit(node);
  237. test_and_update_output_cursor(node);
  238. auto not_in_heredoc = m_parent_node->kind() != AST::Node::Kind::Heredoc;
  239. if (not_in_heredoc)
  240. current_builder().append("\""sv);
  241. TemporaryChange quotes { m_options.in_double_quotes, true };
  242. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  243. NodeVisitor::visit(node);
  244. if (not_in_heredoc)
  245. current_builder().append("\""sv);
  246. visited(node);
  247. }
  248. void Formatter::visit(const AST::Fd2FdRedirection* node)
  249. {
  250. will_visit(node);
  251. test_and_update_output_cursor(node);
  252. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  253. current_builder().appendff("{}>&{}", node->source_fd(), node->dest_fd());
  254. if (m_hit_node == node)
  255. ++m_output_cursor;
  256. visited(node);
  257. }
  258. void Formatter::visit(const AST::FunctionDeclaration* node)
  259. {
  260. will_visit(node);
  261. test_and_update_output_cursor(node);
  262. current_builder().append(node->name().name);
  263. current_builder().append('(');
  264. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  265. auto first = true;
  266. for (auto& arg : node->arguments()) {
  267. if (!first)
  268. current_builder().append(' ');
  269. first = false;
  270. current_builder().append(arg.name);
  271. }
  272. current_builder().append(") "sv);
  273. in_new_block([&] {
  274. if (node->block())
  275. node->block()->visit(*this);
  276. });
  277. visited(node);
  278. }
  279. void Formatter::visit(const AST::ForLoop* node)
  280. {
  281. will_visit(node);
  282. test_and_update_output_cursor(node);
  283. auto is_loop = node->iterated_expression().is_null();
  284. current_builder().append(is_loop ? "loop"sv : "for "sv);
  285. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  286. if (!is_loop) {
  287. if (node->index_variable().has_value()) {
  288. current_builder().append("index "sv);
  289. current_builder().append(node->index_variable()->name);
  290. current_builder().append(" "sv);
  291. }
  292. if (node->variable().has_value() && node->variable()->name != "it") {
  293. current_builder().append(node->variable()->name);
  294. current_builder().append(" in "sv);
  295. }
  296. node->iterated_expression()->visit(*this);
  297. }
  298. current_builder().append(' ');
  299. in_new_block([&] {
  300. if (node->block())
  301. node->block()->visit(*this);
  302. });
  303. visited(node);
  304. }
  305. void Formatter::visit(const AST::Glob* node)
  306. {
  307. will_visit(node);
  308. test_and_update_output_cursor(node);
  309. current_builder().append(node->text());
  310. visited(node);
  311. }
  312. void Formatter::visit(const AST::Heredoc* node)
  313. {
  314. will_visit(node);
  315. test_and_update_output_cursor(node);
  316. current_builder().append("<<"sv);
  317. if (node->deindent())
  318. current_builder().append('~');
  319. else
  320. current_builder().append('-');
  321. if (node->allow_interpolation())
  322. current_builder().appendff("{}", node->end());
  323. else
  324. current_builder().appendff("'{}'", node->end());
  325. auto content = in_new_builder([&] {
  326. if (!node->contents())
  327. return;
  328. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  329. TemporaryChange heredoc { m_options.in_heredoc, true };
  330. auto& contents = *node->contents();
  331. contents.visit(*this);
  332. current_builder().appendff("\n{}\n", node->end());
  333. });
  334. m_heredocs_to_append_after_sequence.append(move(content));
  335. visited(node);
  336. }
  337. void Formatter::visit(const AST::HistoryEvent* node)
  338. {
  339. will_visit(node);
  340. test_and_update_output_cursor(node);
  341. current_builder().append('!');
  342. switch (node->selector().event.kind) {
  343. case AST::HistorySelector::EventKind::ContainingStringLookup:
  344. current_builder().append('?');
  345. current_builder().append(node->selector().event.text);
  346. break;
  347. case AST::HistorySelector::EventKind::StartingStringLookup:
  348. current_builder().append(node->selector().event.text);
  349. break;
  350. case AST::HistorySelector::EventKind::IndexFromStart:
  351. current_builder().append(node->selector().event.text);
  352. break;
  353. case AST::HistorySelector::EventKind::IndexFromEnd:
  354. if (node->selector().event.index == 0)
  355. current_builder().append('!');
  356. else
  357. current_builder().append(node->selector().event.text);
  358. break;
  359. }
  360. auto& range = node->selector().word_selector_range;
  361. if (!range.end.has_value()
  362. || range.end.value().kind != AST::HistorySelector::WordSelectorKind::Last
  363. || range.start.kind != AST::HistorySelector::WordSelectorKind::Index || range.start.selector != 0) {
  364. auto append_word = [this](auto& selector) {
  365. switch (selector.kind) {
  366. case AST::HistorySelector::WordSelectorKind::Index:
  367. if (selector.selector == 0)
  368. current_builder().append('^');
  369. else
  370. current_builder().appendff("{}", selector.selector);
  371. break;
  372. case AST::HistorySelector::WordSelectorKind::Last:
  373. current_builder().append('$');
  374. break;
  375. }
  376. };
  377. current_builder().append(':');
  378. append_word(range.start);
  379. if (range.end.has_value()) {
  380. current_builder().append('-');
  381. append_word(range.end.value());
  382. }
  383. }
  384. visited(node);
  385. }
  386. void Formatter::visit(const AST::Execute* node)
  387. {
  388. will_visit(node);
  389. test_and_update_output_cursor(node);
  390. auto& builder = current_builder();
  391. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  392. ScopedValueRollback options_rollback { m_options };
  393. if (node->does_capture_stdout())
  394. builder.append("$("sv);
  395. NodeVisitor::visit(node);
  396. if (node->does_capture_stdout())
  397. builder.append(")"sv);
  398. visited(node);
  399. }
  400. void Formatter::visit(const AST::IfCond* node)
  401. {
  402. will_visit(node);
  403. test_and_update_output_cursor(node);
  404. current_builder().append("if "sv);
  405. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  406. node->condition()->visit(*this);
  407. current_builder().append(' ');
  408. in_new_block([&] {
  409. if (node->true_branch())
  410. node->true_branch()->visit(*this);
  411. });
  412. if (node->false_branch()) {
  413. current_builder().append(" else "sv);
  414. if (node->false_branch()->kind() != AST::Node::Kind::IfCond) {
  415. in_new_block([&] {
  416. node->false_branch()->visit(*this);
  417. });
  418. } else {
  419. node->false_branch()->visit(*this);
  420. }
  421. } else if (node->else_position().has_value()) {
  422. current_builder().append(" else "sv);
  423. }
  424. visited(node);
  425. }
  426. void Formatter::visit(const AST::ImmediateExpression* node)
  427. {
  428. will_visit(node);
  429. test_and_update_output_cursor(node);
  430. current_builder().append("${"sv);
  431. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  432. current_builder().append(node->function_name());
  433. for (auto& node : node->arguments()) {
  434. current_builder().append(' ');
  435. node.visit(*this);
  436. }
  437. if (node->has_closing_brace())
  438. current_builder().append('}');
  439. visited(node);
  440. }
  441. void Formatter::visit(const AST::Join* node)
  442. {
  443. will_visit(node);
  444. test_and_update_output_cursor(node);
  445. auto should_parenthesise = m_options.explicit_parentheses;
  446. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  447. TemporaryChange parens { m_options.explicit_parentheses, false };
  448. if (should_parenthesise)
  449. current_builder().append('(');
  450. node->left()->visit(*this);
  451. current_builder().append(' ');
  452. node->right()->visit(*this);
  453. if (should_parenthesise)
  454. current_builder().append(')');
  455. visited(node);
  456. }
  457. void Formatter::visit(const AST::MatchExpr* node)
  458. {
  459. will_visit(node);
  460. test_and_update_output_cursor(node);
  461. current_builder().append("match "sv);
  462. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  463. node->matched_expr()->visit(*this);
  464. if (!node->expr_name().is_empty()) {
  465. current_builder().append(" as "sv);
  466. current_builder().append(node->expr_name());
  467. }
  468. current_builder().append(' ');
  469. in_new_block([&] {
  470. auto first_entry = true;
  471. for (auto& entry : node->entries()) {
  472. if (!first_entry)
  473. insert_separator();
  474. first_entry = false;
  475. auto first = true;
  476. entry.options.visit(
  477. [&](NonnullRefPtrVector<AST::Node> const& patterns) {
  478. for (auto& option : patterns) {
  479. if (!first)
  480. current_builder().append(" | "sv);
  481. first = false;
  482. option.visit(*this);
  483. }
  484. },
  485. [&](Vector<Regex<ECMA262>> const& patterns) {
  486. for (auto& option : patterns) {
  487. if (!first)
  488. current_builder().append(" | "sv);
  489. first = false;
  490. auto node = make_ref_counted<AST::BarewordLiteral>(AST::Position {}, option.pattern_value);
  491. node->visit(*this);
  492. }
  493. });
  494. current_builder().append(' ');
  495. if (entry.match_names.has_value() && !entry.match_names.value().is_empty()) {
  496. current_builder().append("as ("sv);
  497. auto first = true;
  498. for (auto& name : entry.match_names.value()) {
  499. if (!first)
  500. current_builder().append(' ');
  501. first = false;
  502. current_builder().append(name);
  503. }
  504. current_builder().append(") "sv);
  505. }
  506. in_new_block([&] {
  507. if (entry.body)
  508. entry.body->visit(*this);
  509. });
  510. }
  511. });
  512. visited(node);
  513. }
  514. void Formatter::visit(const AST::Or* node)
  515. {
  516. will_visit(node);
  517. test_and_update_output_cursor(node);
  518. auto should_indent = m_parent_node && m_parent_node->kind() != AST::Node::Kind::Or;
  519. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  520. with_added_indent(should_indent ? 1 : 0, [&] {
  521. node->left()->visit(*this);
  522. current_builder().append(" "sv);
  523. insert_separator(true);
  524. current_builder().append("|| "sv);
  525. node->right()->visit(*this);
  526. });
  527. visited(node);
  528. }
  529. void Formatter::visit(const AST::Pipe* node)
  530. {
  531. will_visit(node);
  532. test_and_update_output_cursor(node);
  533. auto should_indent = m_parent_node && m_parent_node->kind() != AST::Node::Kind::Pipe;
  534. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  535. node->left()->visit(*this);
  536. current_builder().append(" "sv);
  537. with_added_indent(should_indent ? 1 : 0, [&] {
  538. insert_separator(true);
  539. current_builder().append("| "sv);
  540. node->right()->visit(*this);
  541. });
  542. visited(node);
  543. }
  544. void Formatter::visit(const AST::Range* node)
  545. {
  546. will_visit(node);
  547. test_and_update_output_cursor(node);
  548. if (!m_parent_node || m_parent_node->kind() != AST::Node::Kind::Slice)
  549. current_builder().append('{');
  550. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  551. node->start()->visit(*this);
  552. current_builder().append(".."sv);
  553. node->end()->visit(*this);
  554. if (!m_parent_node || m_parent_node->kind() != AST::Node::Kind::Slice)
  555. current_builder().append('}');
  556. visited(node);
  557. }
  558. void Formatter::visit(const AST::ReadRedirection* node)
  559. {
  560. will_visit(node);
  561. test_and_update_output_cursor(node);
  562. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  563. if (node->fd() != 0)
  564. current_builder().appendff(" {}<", node->fd());
  565. else
  566. current_builder().append(" <"sv);
  567. NodeVisitor::visit(node);
  568. visited(node);
  569. }
  570. void Formatter::visit(const AST::ReadWriteRedirection* node)
  571. {
  572. will_visit(node);
  573. test_and_update_output_cursor(node);
  574. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  575. if (node->fd() != 0)
  576. current_builder().appendff(" {}<>", node->fd());
  577. else
  578. current_builder().append(" <>"sv);
  579. NodeVisitor::visit(node);
  580. visited(node);
  581. }
  582. void Formatter::visit(const AST::Sequence* node)
  583. {
  584. will_visit(node);
  585. test_and_update_output_cursor(node);
  586. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  587. bool first = true;
  588. for (auto& entry : node->entries()) {
  589. if (first)
  590. first = false;
  591. else
  592. insert_separator();
  593. entry.visit(*this);
  594. }
  595. visited(node);
  596. }
  597. void Formatter::visit(const AST::Subshell* node)
  598. {
  599. will_visit(node);
  600. test_and_update_output_cursor(node);
  601. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  602. in_new_block([&] {
  603. NodeVisitor::visit(node);
  604. });
  605. visited(node);
  606. }
  607. void Formatter::visit(const AST::Slice* node)
  608. {
  609. will_visit(node);
  610. test_and_update_output_cursor(node);
  611. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  612. current_builder().append('[');
  613. node->selector()->visit(*this);
  614. current_builder().append(']');
  615. visited(node);
  616. }
  617. void Formatter::visit(const AST::SimpleVariable* node)
  618. {
  619. will_visit(node);
  620. test_and_update_output_cursor(node);
  621. current_builder().append('$');
  622. current_builder().append(node->name());
  623. if (const AST::Node* slice = node->slice())
  624. slice->visit(*this);
  625. visited(node);
  626. }
  627. void Formatter::visit(const AST::SpecialVariable* node)
  628. {
  629. will_visit(node);
  630. test_and_update_output_cursor(node);
  631. current_builder().append('$');
  632. current_builder().append(node->name());
  633. if (const AST::Node* slice = node->slice())
  634. slice->visit(*this);
  635. visited(node);
  636. }
  637. void Formatter::visit(const AST::Juxtaposition* node)
  638. {
  639. will_visit(node);
  640. test_and_update_output_cursor(node);
  641. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  642. NodeVisitor::visit(node);
  643. visited(node);
  644. }
  645. void Formatter::visit(const AST::StringLiteral* node)
  646. {
  647. will_visit(node);
  648. test_and_update_output_cursor(node);
  649. if (!m_options.in_double_quotes && !m_options.in_heredoc)
  650. current_builder().append("'"sv);
  651. if (m_options.in_double_quotes && !m_options.in_heredoc) {
  652. for (auto ch : node->text()) {
  653. switch (ch) {
  654. case '"':
  655. case '\\':
  656. case '$':
  657. current_builder().append('\\');
  658. break;
  659. case '\n':
  660. current_builder().append("\\n"sv);
  661. continue;
  662. case '\r':
  663. current_builder().append("\\r"sv);
  664. continue;
  665. case '\t':
  666. current_builder().append("\\t"sv);
  667. continue;
  668. case '\v':
  669. current_builder().append("\\v"sv);
  670. continue;
  671. case '\f':
  672. current_builder().append("\\f"sv);
  673. continue;
  674. case '\a':
  675. current_builder().append("\\a"sv);
  676. continue;
  677. case '\e':
  678. current_builder().append("\\e"sv);
  679. continue;
  680. default:
  681. break;
  682. }
  683. current_builder().append(ch);
  684. }
  685. } else {
  686. current_builder().append(node->text());
  687. }
  688. if (!m_options.in_double_quotes && !m_options.in_heredoc)
  689. current_builder().append("'"sv);
  690. visited(node);
  691. }
  692. void Formatter::visit(const AST::StringPartCompose* node)
  693. {
  694. will_visit(node);
  695. test_and_update_output_cursor(node);
  696. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  697. NodeVisitor::visit(node);
  698. visited(node);
  699. }
  700. void Formatter::visit(const AST::SyntaxError* node)
  701. {
  702. will_visit(node);
  703. test_and_update_output_cursor(node);
  704. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  705. NodeVisitor::visit(node);
  706. visited(node);
  707. }
  708. void Formatter::visit(const AST::Tilde* node)
  709. {
  710. will_visit(node);
  711. test_and_update_output_cursor(node);
  712. current_builder().append(node->text());
  713. visited(node);
  714. }
  715. void Formatter::visit(const AST::VariableDeclarations* node)
  716. {
  717. will_visit(node);
  718. test_and_update_output_cursor(node);
  719. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  720. auto first = true;
  721. for (auto& entry : node->variables()) {
  722. if (!first)
  723. current_builder().append(' ');
  724. first = false;
  725. entry.name->visit(*this);
  726. current_builder().append('=');
  727. if (entry.value->is_command())
  728. current_builder().append('(');
  729. entry.value->visit(*this);
  730. if (entry.value->is_command())
  731. current_builder().append(')');
  732. }
  733. visited(node);
  734. }
  735. void Formatter::visit(const AST::WriteAppendRedirection* node)
  736. {
  737. will_visit(node);
  738. test_and_update_output_cursor(node);
  739. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  740. if (node->fd() != 1)
  741. current_builder().appendff(" {}>>", node->fd());
  742. else
  743. current_builder().append(" >>"sv);
  744. NodeVisitor::visit(node);
  745. visited(node);
  746. }
  747. void Formatter::visit(const AST::WriteRedirection* node)
  748. {
  749. will_visit(node);
  750. test_and_update_output_cursor(node);
  751. TemporaryChange<const AST::Node*> parent { m_parent_node, node };
  752. if (node->fd() != 1)
  753. current_builder().appendff(" {}>", node->fd());
  754. else
  755. current_builder().append(" >"sv);
  756. NodeVisitor::visit(node);
  757. visited(node);
  758. }
  759. }