Spicy
printer.h
1 // Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <cstddef>
6 #include <iostream>
7 #include <string>
8 #include <utility>
9 #include <vector>
10 
11 #include <hilti/base/util.h>
12 #include <hilti/compiler/detail/visitors.h>
13 
14 namespace hilti::printer {
15 
16 class Stream {
17 public:
18  Stream(std::ostream& s, bool _compact) : _stream(s), _compact(_compact), _nl(_compact ? ' ' : '\n') {}
19 
20  void beginLine() {
21  _flush_pending();
22  _stream << std::string(static_cast<size_t>(_indent) * 4, ' ');
23  }
24  void endLine() {
25  if ( _compact )
26  _pending = ' ';
27  else
28  _stream << '\n';
29  }
30 
31  void emptyLine() {
32  if ( _wrote_nl )
33  return;
34 
35  endLine();
36  _wrote_nl = true;
37  }
38 
39  char newline() const { return _nl; }
40 
41  const ID& currentScope() const { return _scopes.back(); }
42  void pushScope(ID id) { _scopes.push_back(std::move(id)); }
43  void popScope() { _scopes.pop_back(); }
44 
45  bool isCompact() { return _compact; }
46  bool setCompact(bool new_compact) {
47  auto old = _compact;
48  _compact = new_compact;
49  return old;
50  }
51 
52  bool isExpandSubsequentType() const { return _expand_subsequent_type; }
53  void setExpandSubsequentType(bool expand) { _expand_subsequent_type = expand; }
54 
55  bool isFirstInBlock() const { return _first_in_block; }
56  bool isLastInBlock() const { return _last_in_block; }
57  void setPositionInBlock(bool first, bool last) {
58  _first_in_block = first;
59  _last_in_block = last;
60  }
61 
62  auto indent() const { return _indent; }
63  void incrementIndent() { ++_indent; }
64  void decrementIndent() {
65  --_indent;
66  _first_in_block = _last_in_block = false;
67  }
68 
69  template<typename T, IF_DERIVED_FROM(T, trait::isNode)>
70  Stream& operator<<(const T& t) {
71  _flush_pending();
72  if constexpr ( std::is_base_of<trait::isType, T>::value ) {
73  if ( auto id = Type(t).typeID() )
74  _stream << *id;
75  }
76  else
77  hilti::detail::printAST(t, *this);
78 
79  return *this;
80  }
81 
82  template<typename T, IF_NOT_DERIVED_FROM(T, trait::isNode)>
83  Stream& operator<<(const T& t) {
84  _wrote_nl = false;
85  _flush_pending();
86  _stream << t;
87  _expand_subsequent_type = false;
88  return *this;
89  }
90 
91  // Output lists.
92  template<typename T>
93  Stream& operator<<(std::pair<T, const char*> p) {
94  bool first = true;
95  for ( auto& i : p.first ) {
96  _flush_pending();
97 
98  if ( ! first )
99  _stream << p.second;
100 
101  (*this) << i;
102  first = false;
103  }
104 
105  return *this;
106  }
107 
108 private:
109  void _flush_pending() {
110  _stream << _pending;
111  _pending.clear();
112  }
113 
114  std::ostream& _stream;
115  bool _compact;
116  char _nl;
117  std::string _pending;
118  int _indent = 0;
119  bool _wrote_nl = false;
120  bool _first_in_block = false;
121  bool _last_in_block = false;
122  bool _expand_subsequent_type = false;
123  std::vector<ID> _scopes = {""};
124 };
125 
126 } // namespace hilti::printer
Definition: visitors.h:24
Definition: printer.h:16
Definition: type.h:160
Definition: id.h:18