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 enum class Side { LHS, RHS };
64 
69 class Expression {
70 public:
71  Expression() = default;
72  Expression(std::string s, Side side = Side::RHS) : _s(std::move(s)), _side(side) {}
73  Expression(const char* s, Side side = Side::RHS) : _s(s), _side(side) {}
74 
75  bool isLhs() const { return _side == Side::LHS; }
76 
77  operator std::string() const { return _s; }
78  explicit operator bool() const { return ! _s.empty(); }
79  bool operator<(const Expression& s) const { return _s < s._s; }
80  bool operator==(const Expression& s) const { return _s == s._s; }
81  bool operator!=(const Expression& s) const { return _s != s._s; }
82 
83 private:
84  std::string _s;
85  Side _side = Side::LHS;
86 };
87 
88 extern std::string normalize_id(std::string id);
89 
91 class ID : public detail::IDBase<ID, normalize_id> {
92 public:
94  using Base::IDBase;
95  ID() = default;
96  explicit ID(const ::hilti::ID& id) : Base(std::string(id)) {}
97  ID& operator=(const ::hilti::ID& id) {
98  *this = ID(id);
99  return *this;
100  }
101 
103  static ID fromNormalized(std::string id) { return ID(std::move(id), Base::AlreadyNormalized()); }
104 };
105 
106 extern void to_json(nlohmann::json& j, const cxx::ID& id); // NOLINT
107 extern void from_json(const nlohmann::json& j, cxx::ID& id); // NOLINT
108 
109 namespace declaration {
110 
112 struct IncludeFile {
113  std::string file;
114  bool operator<(const IncludeFile& o) const { return file < o.file; }
115 };
116 
118 struct Local {
119  Local(Local&&) = default;
120  Local(const Local&) = default;
121  Local& operator=(Local&&) = default;
122  Local& operator=(const Local&) = default;
123  Local(cxx::ID _id = {}, cxx::Type _type = {}, std::vector<cxx::Expression> _args = {},
124  std::optional<cxx::Expression> _init = {}, Linkage _linkage = {})
125  : id(std::move(_id)),
126  type(std::move(_type)),
127  args(std::move(_args)),
128  init(std::move(_init)),
129  linkage(std::move(_linkage)) {}
130 
131  cxx::ID id;
132  cxx::Type type;
133  std::vector<cxx::Expression> args;
134  std::optional<cxx::Expression> init;
135  Linkage linkage;
136 
137  // Returns true if the ID starts with two underscores, which is the
138  // namespace reserved for internal IDs.
139  bool isInternal() const { return util::startsWith(id.local(), "__"); }
140 
141  std::string str() const;
142  operator std::string() const { return str(); }
143 };
144 
146 struct Global {
147  cxx::ID id;
148  cxx::Type type;
149  std::vector<cxx::Expression> args;
150  std::optional<cxx::Expression> init;
151  Linkage linkage;
152 
153  bool operator==(const Global& other) const {
154  return id == other.id && type == other.type && init == other.init && linkage == other.linkage;
155  }
156 
157  std::string str() const;
158  operator std::string() const { return str(); }
159 };
160 
162 struct Constant {
163  cxx::ID id;
164  cxx::Type type = Type();
165  std::optional<cxx::Expression> init;
166  Linkage linkage;
167  bool forward_decl = false;
168 
169  bool operator<(const Constant& s) const { return id < s.id; }
170  bool operator==(const Constant& other) const {
171  return id == other.id && type == other.type && init == other.init && linkage == other.linkage;
172  }
173 };
174 
175 extern void to_json(nlohmann::json& j, const Constant& c); // NOLINT
176 extern void from_json(const nlohmann::json& j, Constant& c); // NOLINT
177 
179 struct Type {
180  cxx::ID id;
181  cxx::Type type;
182  std::string inline_code;
183  bool forward_decl = false;
184  bool forward_decl_prio = false;
185  bool no_using = false; // turned on automatically for types starting with "struct"
186 
187  Type(cxx::ID _id = {}, cxx::Type _type = {}, std::string _inline_code = {}, bool _forward_decl = false,
188  bool _forward_decl_prio = false, bool _no_using = false)
189  : id(std::move(_id)),
190  type(std::move(_type)),
191  inline_code(std::move(_inline_code)),
192  forward_decl(_forward_decl),
193  forward_decl_prio(_forward_decl_prio),
194  no_using(_no_using) {}
195 
196  bool operator==(const Type& other) const {
197  return id == other.id && type == other.type && inline_code == other.inline_code &&
198  forward_decl == other.forward_decl && forward_decl_prio == other.forward_decl_prio &&
199  no_using == other.no_using;
200  }
201 };
202 
203 extern void to_json(nlohmann::json& j, const Type& t); // NOLINT
204 extern void from_json(const nlohmann::json& j, Type& t); // NOLINT
205 
207 struct Argument {
208  cxx::ID id;
209  cxx::Type type;
210  std::optional<cxx::Expression> default_;
211  cxx::Type internal_type = "";
212  operator std::string() const { return id ? util::fmt("%s %s", type, id) : std::string(type); }
213 
214  bool operator==(const Argument& other) const { return type == other.type && id == other.id; }
215 };
216 
217 extern void to_json(nlohmann::json& j, const Argument& a); // NOLINT
218 extern void from_json(const nlohmann::json& j, Argument& a); // NOLINT
219 
220 } // namespace declaration
221 
223 class Block {
224 public:
225  Block() {}
226  Block(std::vector<std::string> stmts);
227 
228  void addStatement(std::string stmt);
229  void addStatementAtFront(std::string stmt);
230  void addBlock(Block child);
231  void addComment(const std::string& stmt, bool sep_before = true, bool sep_after = false);
232  void addLocal(const declaration::Local& v);
233  void addTmp(const declaration::Local& v);
234  void addReturn(const Expression& expr = Expression());
235  void addIf(const Expression& cond, Block true_);
236  void addIf(const Expression& init, const Expression& cond, cxx::Block true_);
237  void addIf(const Expression& cond, Block true_, Block false_);
238  void addIf(const Expression& init, const Expression& cond, Block true_, Block false_);
239  void addElseIf(const Expression& cond, Block true_);
240  void addElse(Block true_);
241  void addFor(const Expression& init, const Expression& cond, const Expression& next, const cxx::Block& body);
242  void addForRange(bool const_, const ID& id, const Expression& seq, const cxx::Block& body);
243  // void addForRange(const Expression& init, bool const_, const ID& id, const Expression& seq, cxx::Block body); //
244  // C++20 ...
245  void addWhile(const Expression& cond, const Block& body);
246  void addLambda(const std::string& name, const std::string& signature, Block body);
247  void addSwitch(const Expression& cond, const std::vector<std::pair<Expression, Block>>& cases_,
248  std::optional<Block> default_ = {});
249  void appendFromBlock(Block b);
250  void addTry(Block body, std::vector<std::pair<declaration::Argument, Block>> catches);
251 
252  bool ensureBracesForBlock() const { return _ensure_braces_for_block; }
253  void setEnsureBracesforBlock() { _ensure_braces_for_block = true; }
254 
255  size_t size(bool ignore_comments = false) const;
256 
257  Block& operator+=(const Block& other);
258 
259  operator bool() const { return ! (_stmts.empty() && _tmps.empty()); }
260 
261  friend ::hilti::detail::cxx::Formatter& operator<<(Formatter& f, const Block& x);
262 
263  bool operator==(const Block& other) const { return _stmts == other._stmts; }
264 
265 private:
266  using Flags = unsigned int;
267  std::vector<std::tuple<std::string, Block, Flags>> _stmts;
268  std::vector<std::string> _tmps;
269  bool _ensure_braces_for_block = false;
270 };
271 
272 namespace declaration {
273 
275 struct Function {
276  cxx::Type result;
277  cxx::ID id;
278  std::vector<Argument> args;
279  bool const_ = false;
280  Linkage linkage = "static";
281  Attribute attribute = "";
282  std::optional<Block> inline_body; // TODO(robin): Not serialized to JSON yet.
283 
284  std::string prototype(bool qualify) const;
285  std::string parameters() const;
286 
287  bool operator==(const Function& other) const {
288  return result == other.result && id == other.id && args == other.args && linkage == other.linkage &&
289  attribute == other.attribute && inline_body == other.inline_body;
290  }
291 };
292 
293 extern void to_json(nlohmann::json& j, const Function& f); // NOLINT
294 extern void from_json(const nlohmann::json& j, Function& f); // NOLINT
295 
296 } // namespace declaration
297 
299 struct Function {
300  declaration::Function declaration;
301  Block body;
302  bool default_ = false;
303 
304  bool operator==(const Function& other) const { return declaration == other.declaration && body == other.body; }
305 };
306 
307 namespace type {
308 namespace struct_ {
309 
310 using Member = std::variant<declaration::Local, declaration::Function>;
311 
312 inline bool operator<(const Member& m1, const Member& m2) {
313  auto id = [](auto m) {
314  if ( auto x = std::get_if<declaration::Local>(&m) )
315  return x->id;
316  if ( auto x = std::get_if<declaration::Function>(&m) )
317  return x->id;
318 
319  throw std::bad_variant_access();
320  };
321 
322  return id(m1) < id(m2);
323 }
324 
325 } // namespace struct_
326 
328 struct Struct {
329  std::vector<declaration::Argument> args;
330  std::vector<struct_::Member> members;
331  cxx::ID type_name;
332  std::optional<cxx::Type> self;
333  bool add_ctors = false;
334  std::string str() const;
335  std::string inlineCode() const;
336 
337  operator std::string() const { return str(); }
338  operator cxx::Type() const { return str(); }
339 };
340 
341 namespace union_ {
342 using Member = struct_::Member;
343 } // namespace union_
344 
346 struct Union {
347  std::vector<union_::Member> members;
348  cxx::ID type_name;
349  std::string str() const;
350  operator std::string() const { return str(); }
351  operator cxx::Type() const { return str(); }
352 };
353 
354 namespace enum_ {
355 using Label = std::pair<cxx::ID, int>;
356 } // namespace enum_
357 
359 struct Enum {
360  std::vector<enum_::Label> labels;
361  cxx::ID type_name;
362  std::string str() const;
363  operator std::string() const { return str(); }
364  operator cxx::Type() const { return str(); }
365 };
366 
367 } // namespace type
368 
369 inline std::ostream& operator<<(std::ostream& o, const ID& i) { return o << std::string(i); }
370 inline std::ostream& operator<<(std::ostream& o, const Linkage& l) { return o << std::string(l); }
371 inline std::ostream& operator<<(std::ostream& o, const Type& t) { return o << std::string(t); }
372 inline std::ostream& operator<<(std::ostream& o, const Attribute& a) { return o << std::string(a); }
373 inline std::ostream& operator<<(std::ostream& o, const declaration::Argument& t) { return o << std::string(t); }
374 inline std::ostream& operator<<(std::ostream& o, const Expression& e) { return o << std::string(e); }
375 
376 extern Formatter& operator<<(Formatter& f, const Block& x);
377 extern Formatter& operator<<(Formatter& f, const Expression& x);
378 extern Formatter& operator<<(Formatter& f, const ID& x);
379 extern Formatter& operator<<(Formatter& f, const Function& x);
380 extern Formatter& operator<<(Formatter& f, const Type& x);
381 extern Formatter& operator<<(Formatter& f, const declaration::Type& x);
382 extern Formatter& operator<<(Formatter& f, const declaration::IncludeFile& x);
383 extern Formatter& operator<<(Formatter& f, const declaration::Local& x);
384 extern Formatter& operator<<(Formatter& f, const declaration::Global& x);
385 extern Formatter& operator<<(Formatter& f, const declaration::Function& x);
386 extern Formatter& operator<<(Formatter& f, const declaration::Constant& x);
387 
388 } // namespace hilti::detail::cxx
Definition: formatter.h:16
Definition: elements.h:223
Definition: elements.h:28
Definition: elements.h:118
Definition: elements.h:146
Definition: elements.h:359
Definition: elements.h:18
Definition: elements.h:328
Definition: elements.h:69
Definition: elements.h:91
Definition: elements.h:299
Definition: id-base.h:28
Definition: elements.h:179
static ID fromNormalized(std::string id)
Definition: elements.h:103
Definition: elements.h:346