formatter.h 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  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. #ifndef CARBON_TOOLCHAIN_FORMAT_FORMATTER_H_
  5. #define CARBON_TOOLCHAIN_FORMAT_FORMATTER_H_
  6. #include <cstdint>
  7. #include "common/ostream.h"
  8. #include "toolchain/lex/tokenized_buffer.h"
  9. namespace Carbon::Format {
  10. // Implements Format(); see format.h. It's intended to be constructed and
  11. // `Run()` once, then destructed.
  12. //
  13. // TODO: This will probably need to work less linearly in the future, for
  14. // example to handle smart wrapping of arguments. This is a simple
  15. // implementation that only handles simple code. Before adding too much more
  16. // complexity, it should be rewritten.
  17. //
  18. // TODO: Add retention of blank lines between original code.
  19. //
  20. // TODO: Add support for formatting line ranges (will need flags too).
  21. class Formatter {
  22. public:
  23. explicit Formatter(const Lex::TokenizedBuffer* tokens, llvm::raw_ostream* out)
  24. : tokens_(tokens), out_(out) {}
  25. // See class comments.
  26. auto Run() -> bool;
  27. private:
  28. // Tracks the status of the current line of output.
  29. enum class LineState : uint8_t {
  30. // There is no output for the current line.
  31. Empty,
  32. // The current line has content (possibly just an indent), and does not need
  33. // a separator added.
  34. HasSeparator,
  35. // The current line has content, and will need a separator, typically a
  36. // single space or newline.
  37. NeedsSeparator,
  38. };
  39. // Ensure output is on an empty line, setting line_state_ to Empty. May output
  40. // a newline, dependent on line state. Does not indent, allowing blank lines.
  41. auto RequireEmptyLine() -> void;
  42. // Ensures there is a separator before adding new content. May do
  43. // `PrepareForPackedContent` or output a separator space, dependent on line
  44. // state. Always results in line_state_ being HasSeparator; the caller is
  45. // responsible for adjusting state if needed.
  46. auto PrepareForSpacedContent() -> void;
  47. // Requires that the current line is indented, but not necessarily a separator
  48. // space. May output spaces for `indent_`, dependent on line state. Only
  49. // guarantees the line_state_ is not Empty; the caller is responsible for
  50. // adjusting state if needed.
  51. auto PrepareForPackedContent() -> void;
  52. // Returns the next token index.
  53. static auto NextToken(Lex::TokenIndex token) -> Lex::TokenIndex {
  54. return *(Lex::TokenIterator(token) + 1);
  55. }
  56. // The tokens being formatted.
  57. const Lex::TokenizedBuffer* tokens_;
  58. // The output stream for formatted content.
  59. llvm::raw_ostream* out_;
  60. // The state of the line currently written to output.
  61. LineState line_state_ = LineState::Empty;
  62. // The current code indent level, to be added to new lines.
  63. int indent_ = 0;
  64. };
  65. } // namespace Carbon::Format
  66. #endif // CARBON_TOOLCHAIN_FORMAT_FORMATTER_H_