formatter.cpp 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include "toolchain/format/formatter.h"
  5. namespace Carbon::Format {
  6. auto Formatter::Run() -> bool {
  7. if (tokens_->has_errors()) {
  8. // TODO: Error recovery.
  9. return false;
  10. }
  11. auto comments = tokens_->comments();
  12. auto comment_it = comments.begin();
  13. // If there are no tokens or comments, format as empty.
  14. if (tokens_->size() == 0 && comment_it == comments.end()) {
  15. *out_ << "\n";
  16. return true;
  17. }
  18. for (auto token : tokens_->tokens()) {
  19. auto token_kind = tokens_->GetKind(token);
  20. while (comment_it != comments.end() &&
  21. tokens_->IsAfterComment(token, *comment_it)) {
  22. RequireEmptyLine();
  23. PrepareForSpacedContent();
  24. // TODO: We do need to adjust the indent of multi-line comments.
  25. *out_ << tokens_->GetCommentText(*comment_it);
  26. // Comment text includes a terminating newline, so just update the state.
  27. line_state_ = LineState::Empty;
  28. ++comment_it;
  29. }
  30. switch (token_kind) {
  31. case Lex::TokenKind::FileStart:
  32. break;
  33. case Lex::TokenKind::FileEnd:
  34. RequireEmptyLine();
  35. break;
  36. case Lex::TokenKind::OpenCurlyBrace:
  37. PrepareForSpacedContent();
  38. *out_ << "{";
  39. // Check for `{}`.
  40. if (NextToken(token) != tokens_->GetMatchedClosingToken(token)) {
  41. RequireEmptyLine();
  42. }
  43. indent_ += 2;
  44. break;
  45. case Lex::TokenKind::CloseCurlyBrace:
  46. indent_ -= 2;
  47. PrepareForPackedContent();
  48. *out_ << "}";
  49. RequireEmptyLine();
  50. break;
  51. case Lex::TokenKind::Semi:
  52. PrepareForPackedContent();
  53. *out_ << ";";
  54. RequireEmptyLine();
  55. break;
  56. default:
  57. if (token_kind.IsOneOf(
  58. {Lex::TokenKind::CloseParen, Lex::TokenKind::Colon,
  59. Lex::TokenKind::ColonExclaim, Lex::TokenKind::Comma})) {
  60. PrepareForPackedContent();
  61. } else {
  62. PrepareForSpacedContent();
  63. }
  64. *out_ << tokens_->GetTokenText(token);
  65. line_state_ = token_kind.is_opening_symbol()
  66. ? LineState::HasSeparator
  67. : LineState::NeedsSeparator;
  68. break;
  69. }
  70. }
  71. return true;
  72. }
  73. auto Formatter::PrepareForPackedContent() -> void {
  74. if (line_state_ == LineState::Empty) {
  75. out_->indent(indent_);
  76. line_state_ = LineState::HasSeparator;
  77. }
  78. }
  79. auto Formatter::RequireEmptyLine() -> void {
  80. if (line_state_ != LineState::Empty) {
  81. *out_ << "\n";
  82. line_state_ = LineState::Empty;
  83. }
  84. }
  85. auto Formatter::PrepareForSpacedContent() -> void {
  86. if (line_state_ == LineState::NeedsSeparator) {
  87. *out_ << " ";
  88. line_state_ = LineState::HasSeparator;
  89. } else {
  90. PrepareForPackedContent();
  91. }
  92. }
  93. } // namespace Carbon::Format