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