Spicy
elements.h
1 // Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <optional>
6 #include <string>
7 #include <tuple>
8 #include <utility>
9 #include <variant>
10 #include <vector>
11 
12 #include <hilti/rt/json-fwd.h>
13 
14 #include <hilti/ast/id.h>
15 #include <hilti/base/id-base.h>
16 #include <hilti/base/util.h>
17 
18 namespace hilti::detail::cxx {
19 
20 class Formatter;
21 
22 namespace element {
23 enum class Type { Expression, Type, Linkage, Attribute };
24 } // namespace element
25 
27 template<element::Type T>
28 class Element {
29 public:
30  Element() = default;
31  Element(std::string s) : _s(std::move(s)) {}
32  Element(const char* s) : _s(s) {}
33 
34  Element& operator=(const std::string& s) {
35  _s = s;
36  return *this;
37  }
38  Element& operator=(std::string&& s) {
39  _s = std::move(s);
40  return *this;
41  }
42  Element& operator=(const char* s) {
43  _s = s;
44  return *this;
45  }
46 
47  bool isMultiLine() const { return _s.find('\n') != std::string::npos; }
48 
49  operator std::string() const { return _s; }
50  explicit operator bool() const { return ! _s.empty(); }
51  bool operator<(const Element& s) const { return _s < s._s; }
52  bool operator==(const Element& s) const { return _s == s._s; }
53 
54 private:
55  std::string _s;
56 };
57 
63 extern std::string normalize_id(std::string id);
64 
66 class ID : public detail::IDBase<ID, normalize_id> {
67 public:
69  using Base::IDBase;
70  ID() = default;
71  explicit ID(const ::hilti::ID& id) : Base(std::string(id)) {}
72  ID& operator=(const ::hilti::ID& id) {
73  *this = ID(id);
74  return *this;
75  }
76 
78  static ID fromNormalized(std::string id) { return ID(std::move(id), Base::AlreadyNormalized()); }
79 };
80 
81 extern void to_json(nlohmann::json& j, const cxx::ID& id); // NOLINT
82 extern void from_json(const nlohmann::json& j, cxx::ID& id); // NOLINT
83 
84 namespace declaration {
85 
87 struct IncludeFile {
88  std::string file;
89  bool operator<(const IncludeFile& o) const { return file < o.file; }
90 };
91 
93 struct Local {
94  cxx::ID id;
95  cxx::Type type;
96  std::vector<cxx::Expression> args;
97  std::optional<cxx::Expression> init;
98  Linkage linkage;
99 
100  // Returns true if the ID starts with two underscores, which is the
101  // namespace reserved for internal IDs.
102  bool isInternal() const { return util::startsWith(id.local(), "__"); }
103 
104  std::string str() const;
105  operator std::string() const { return str(); }
106 };
107 
109 struct Global {
110  cxx::ID id;
111  cxx::Type type;
112  std::vector<cxx::Expression> args;
113  std::optional<cxx::Expression> init;
114  Linkage linkage;
115 
116  bool operator==(const Global& other) const {
117  return id == other.id && type == other.type && init == other.init && linkage == other.linkage;
118  }
119 
120  std::string str() const;
121  operator std::string() const { return str(); }
122 };
123 
125 struct Constant {
126  cxx::ID id;
127  cxx::Type type = Type();
128  std::optional<cxx::Expression> init;
129  Linkage linkage;
130  bool forward_decl = false;
131 
132  bool operator<(const Constant& s) const { return id < s.id; }
133  bool operator==(const Constant& other) const {
134  return id == other.id && type == other.type && init == other.init && linkage == other.linkage;
135  }
136 };
137 
138 extern void to_json(nlohmann::json& j, const Constant& c); // NOLINT
139 extern void from_json(const nlohmann::json& j, Constant& c); // NOLINT
140 
142 struct Type {
143  cxx::ID id;
144  cxx::Type type;
145  std::string inline_code = "";
146  bool forward_decl = false;
147  bool forward_decl_prio = false;
148  bool no_using = false; // turned on automatically for types starting with "struct"
149 
150  bool operator==(const Type& other) const {
151  return id == other.id && type == other.type && inline_code == other.inline_code &&
152  forward_decl == other.forward_decl && forward_decl_prio == other.forward_decl_prio &&
153  no_using == other.no_using;
154  }
155 };
156 
157 extern void to_json(nlohmann::json& j, const Type& t); // NOLINT
158 extern void from_json(const nlohmann::json& j, Type& t); // NOLINT
159 
161 struct Argument {
162  cxx::ID id;
163  cxx::Type type;
164  std::optional<cxx::Expression> default_;
165  cxx::Type internal_type = "";
166  operator std::string() const { return id ? util::fmt("%s %s", type, id) : std::string(type); }
167 
168  bool operator==(const Argument& other) const { return type == other.type && id == other.id; }
169 };
170 
171 extern void to_json(nlohmann::json& j, const Argument& a); // NOLINT
172 extern void from_json(const nlohmann::json& j, Argument& a); // NOLINT
173 
174 } // namespace declaration
175 
177 class Block {
178 public:
179  Block() {}
180  Block(std::vector<std::string> stmts);
181 
182  void addStatement(std::string stmt);
183  void addStatementAtFront(std::string stmt);
184  void addBlock(Block child);
185  void addComment(const std::string& stmt, bool sep_before = true, bool sep_after = false);
186  void addLocal(const declaration::Local& v);
187  void addTmp(const declaration::Local& v);
188  void addReturn(const Expression& expr = Expression());
189  void addIf(const Expression& cond, Block true_);
190  void addIf(const Expression& init, const Expression& cond, cxx::Block true_);
191  void addIf(const Expression& cond, Block true_, Block false_);
192  void addIf(const Expression& init, const Expression& cond, Block true_, Block false_);
193  void addElseIf(const Expression& cond, Block true_);
194  void addElse(Block true_);
195  void addFor(const Expression& init, const Expression& cond, const Expression& next, const cxx::Block& body);
196  void addForRange(bool const_, const ID& id, const Expression& seq, const cxx::Block& body);
197  // void addForRange(const Expression& init, bool const_, const ID& id, const Expression& seq, cxx::Block body); //
198  // C++20 ...
199  void addWhile(const Expression& cond, const Block& body);
200  void addLambda(const std::string& name, const std::string& signature, Block body);
201  void addSwitch(const Expression& cond, const std::vector<std::pair<Expression, Block>>& cases_,
202  std::optional<Block> default_ = {});
203  void appendFromBlock(Block b);
204  void addTry(Block body, std::vector<std::pair<declaration::Argument, Block>> catches);
205 
206  bool ensureBracesForBlock() const { return _ensure_braces_for_block; }
207  void setEnsureBracesforBlock() { _ensure_braces_for_block = true; }
208 
209  size_t size(bool ignore_comments = false) const;
210 
211  Block& operator+=(const Block& other);
212 
213  operator bool() const { return ! (_stmts.empty() && _tmps.empty()); }
214 
215  friend ::hilti::detail::cxx::Formatter& operator<<(Formatter& f, const Block& x);
216 
217  bool operator==(const Block& other) const { return _stmts == other._stmts; }
218 
219 private:
220  using Flags = unsigned int;
221  std::vector<std::tuple<std::string, Block, Flags>> _stmts;
222  std::vector<std::string> _tmps;
223  bool _ensure_braces_for_block = false;
224 };
225 
226 namespace declaration {
227 
229 struct Function {
230  cxx::Type result;
231  cxx::ID id;
232  std::vector<Argument> args;
233  bool const_ = false;
234  Linkage linkage = "static";
235  Attribute attribute = "";
236  std::optional<Block> inline_body; // TODO(robin): Not serialized to JSON yet.
237 
238  std::string prototype(bool qualify) const;
239  std::string parameters() const;
240 
241  bool operator==(const Function& other) const {
242  return result == other.result && id == other.id && args == other.args && linkage == other.linkage &&
243  attribute == other.attribute && inline_body == other.inline_body;
244  }
245 };
246 
247 extern void to_json(nlohmann::json& j, const Function& f); // NOLINT
248 extern void from_json(const nlohmann::json& j, Function& f); // NOLINT
249 
250 } // namespace declaration
251 
253 struct Function {
254  declaration::Function declaration;
255  Block body;
256  bool default_ = false;
257 
258  bool operator==(const Function& other) const { return declaration == other.declaration && body == other.body; }
259 };
260 
261 namespace type {
262 namespace struct_ {
263 
264 using Member = std::variant<declaration::Local, declaration::Function>;
265 
266 inline bool operator<(const Member& m1, const Member& m2) {
267  auto id = [](auto m) {
268  if ( auto x = std::get_if<declaration::Local>(&m) )
269  return x->id;
270  if ( auto x = std::get_if<declaration::Function>(&m) )
271  return x->id;
272 
273  throw std::bad_variant_access();
274  };
275 
276  return id(m1) < id(m2);
277 }
278 
279 } // namespace struct_
280 
282 struct Struct {
283  std::vector<declaration::Argument> args;
284  std::vector<struct_::Member> members;
285  cxx::ID type_name;
286  std::optional<cxx::Type> self;
287  bool add_ctors = false;
288  std::string str() const;
289  std::string inlineCode() const;
290 
291  operator std::string() const { return str(); }
292  operator cxx::Type() const { return str(); }
293 };
294 
295 namespace union_ {
296 using Member = struct_::Member;
297 } // namespace union_
298 
300 struct Union {
301  std::vector<union_::Member> members;
302  cxx::ID type_name;
303  std::string str() const;
304  operator std::string() const { return str(); }
305  operator cxx::Type() const { return str(); }
306 };
307 
308 namespace enum_ {
309 using Label = std::pair<cxx::ID, int>;
310 } // namespace enum_
311 
313 struct Enum {
314  std::vector<enum_::Label> labels;
315  cxx::ID type_name;
316  std::string str() const;
317  operator std::string() const { return str(); }
318  operator cxx::Type() const { return str(); }
319 };
320 
321 } // namespace type
322 
323 inline std::ostream& operator<<(std::ostream& o, const ID& i) { return o << std::string(i); }
324 inline std::ostream& operator<<(std::ostream& o, const Linkage& l) { return o << std::string(l); }
325 inline std::ostream& operator<<(std::ostream& o, const Type& t) { return o << std::string(t); }
326 inline std::ostream& operator<<(std::ostream& o, const Attribute& a) { return o << std::string(a); }
327 inline std::ostream& operator<<(std::ostream& o, const declaration::Argument& t) { return o << std::string(t); }
328 inline std::ostream& operator<<(std::ostream& o, const Expression& e) { return o << std::string(e); }
329 
330 extern Formatter& operator<<(Formatter& f, const Block& x);
331 extern Formatter& operator<<(Formatter& f, const Expression& x);
332 extern Formatter& operator<<(Formatter& f, const ID& x);
333 extern Formatter& operator<<(Formatter& f, const Function& x);
334 extern Formatter& operator<<(Formatter& f, const Type& x);
335 extern Formatter& operator<<(Formatter& f, const declaration::Type& x);
336 extern Formatter& operator<<(Formatter& f, const declaration::IncludeFile& x);
337 extern Formatter& operator<<(Formatter& f, const declaration::Local& x);
338 extern Formatter& operator<<(Formatter& f, const declaration::Global& x);
339 extern Formatter& operator<<(Formatter& f, const declaration::Function& x);
340 extern Formatter& operator<<(Formatter& f, const declaration::Constant& x);
341 
342 } // namespace hilti::detail::cxx
Definition: formatter.h:16
Definition: elements.h:177
Definition: elements.h:28
Definition: elements.h:109
Definition: elements.h:313
Definition: elements.h:18
std::string fmt(const char *fmt, const Args &... args)
Definition: util.h:80
bool startsWith(const std::string &s, const std::string &prefix)
Definition: util.h:285
Definition: elements.h:282
Definition: elements.h:66
Definition: elements.h:253
Definition: id-base.h:28
Definition: elements.h:142
static ID fromNormalized(std::string id)
Definition: elements.h:78
Definition: elements.h:300