Spicy
printer.h
1 // Copyright (c) 2020-now by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <cstddef>
6 #include <iostream>
7 #include <memory>
8 #include <string>
9 #include <utility>
10 #include <vector>
11 
12 #include <hilti/ast/forward.h>
13 #include <hilti/ast/id.h>
14 #include <hilti/base/util.h>
15 
16 namespace hilti {
17 
18 struct Plugin;
19 
20 namespace printer {
21 
32 void print(std::ostream& out, Node* root, bool compact, bool user_visible);
33 
34 namespace detail {
35 
37 struct State {
38  const Plugin* current_plugin = nullptr;
39 
40  std::vector<ID> scopes = {{""}};
41  std::string pending;
42  int indent = 0;
43  bool wrote_nl = false;
44  bool first_in_block = false;
45  bool last_in_block = false;
46  bool expand_subsequent_type = false;
47  bool compact = false;
48  bool user_visible = true;
49 
50  inline static std::unique_ptr<State> current;
51  inline static uint64_t depth = 0;
52 };
53 } // namespace detail
54 
56 class Stream {
57 public:
58  Stream(std::ostream& s) : _stream(s) {}
59 
60  auto& state() const {
61  assert(detail::State::current);
62  return *detail::State::current;
63  }
64 
65  void beginLine() {
66  _flush_pending();
67  _stream << std::string(static_cast<size_t>(state().indent) * 4, ' ');
68  }
69 
70  void endLine() { _stream << '\n'; }
71 
72  void emptyLine() {
73  if ( state().wrote_nl )
74  return;
75 
76  endLine();
77  state().wrote_nl = true;
78  }
79 
80  char newline() const { return '\n'; }
81 
82  bool isExpandSubsequentType() const { return state().expand_subsequent_type; }
83  void setExpandSubsequentType(bool expand) { state().expand_subsequent_type = expand; }
84 
85  bool isCompact() const { return state().compact; }
86  void setCompact(bool compact) { state().compact = compact; }
87 
88 
89  bool isFirstInBlock() const { return state().first_in_block; }
90  bool isLastInBlock() const { return state().last_in_block; }
91  void setPositionInBlock(bool first, bool last) {
92  state().first_in_block = first;
93  state().last_in_block = last;
94  }
95 
96  auto indent() const { return state().indent; }
97  void incrementIndent() { ++state().indent; }
98  void decrementIndent() {
99  --state().indent;
100  state().first_in_block = state().last_in_block = false;
101  }
102 
103  const ID& currentScope() { return state().scopes.back(); }
104  void pushScope(ID id) { state().scopes.push_back(std::move(id)); }
105  void popScope() { state().scopes.pop_back(); }
106 
107  template<typename T, IF_DERIVED_FROM(T, Node)>
108  Stream& operator<<(T* t) {
109  _flush_pending();
110  _print(t);
111  return *this;
112  }
113 
114  Stream& operator<<(const ID& id);
115 
116  template<typename T, IF_NOT_DERIVED_FROM(T, Node)>
117  Stream& operator<<(const T& t) {
118  state().wrote_nl = false;
119  _flush_pending();
120  _stream << t;
121  return *this;
122  }
123 
124  // Output lists.
125  template<typename T>
126  Stream& operator<<(const std::pair<T, const char*>& p) {
127  bool first = true;
128  for ( const auto& i : p.first ) {
129  _flush_pending();
130 
131  if ( ! first )
132  _stream << p.second;
133 
134  (*this) << i;
135  first = false;
136  }
137 
138  return *this;
139  }
140 
141  template<typename T>
142  Stream& operator<<(std::pair<T*, const char*> p) {
143  bool first = true;
144  for ( auto& i : p.first ) {
145  _flush_pending();
146 
147  if ( ! first )
148  _stream << p.second;
149 
150  (*this) << *i;
151  first = false;
152  }
153 
154  return *this;
155  }
156 
157 private:
158  friend void printer::print(std::ostream& out, Node* root, bool compact, bool user_visible);
159 
160  void _print(Node* root);
161 
162  void _flush_pending() {
163  _stream << state().pending;
164  state().pending.clear();
165  }
166 
167  std::ostream& _stream;
168 };
169 
170 } // namespace printer
171 } // namespace hilti
Definition: id.h:15
Definition: node.h:239
Definition: printer.h:56
void print(const T &t, const hilti::rt::TypeInfo *, bool newline=true)
Definition: hilti.h:23
Definition: plugin.h:52
Definition: printer.h:37