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