Spicy
attribute.h
1 // Copyright (c) 2020-now by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <algorithm>
6 #include <optional>
7 #include <string>
8 #include <string_view>
9 #include <utility>
10 
11 #include <hilti/ast/expression.h>
12 #include <hilti/ast/forward.h>
13 #include <hilti/ast/node.h>
14 #include <hilti/base/util.h>
15 
16 namespace hilti {
17 
18 namespace attribute {
19 
30 class Kind {
31 public:
32  explicit Kind(std::string name) : _name(std::move(name)) { _register(); }
33 
34  Kind() = delete;
35  Kind(const Kind& other) = default;
36  Kind(Kind&& other) = default;
37 
38  ~Kind() = default; // not unregistering here, so that attribute remains known
39 
40  operator std::string() const { return _name; }
41 
42  Kind& operator=(const Kind& other) = default;
43  Kind& operator=(Kind&& other) = default;
44 
45  bool operator==(const Kind& other) const { return _name == other._name; }
46  bool operator!=(const Kind& other) const { return ! operator==(other); }
47 
48  // Returns a corresponding attribute kind iff the string matches to one of
49  // the known attributes created so far. Otherwise throws an `out_of_range`
50  // exception.
51  static Kind fromString(const std::string_view& s) {
52  if ( _known_attributes && _known_attributes->count(std::string(s)) > 0 )
53  return Kind(std::string(s));
54  else
55  throw std::out_of_range("unknown attribute kind: " + std::string(s));
56  }
57 
58 private:
59  void _register();
60 
61  std::string _name = "<unset attribute>";
62  static std::set<std::string>* _known_attributes;
63 };
64 
66 inline bool isOneOf(const Kind& kind, std::initializer_list<Kind> kinds) {
67  return std::find(kinds.begin(), kinds.end(), kind) != kinds.end();
68 }
69 
70 inline auto to_string(const Kind& kind) { return std::string(kind); }
71 
72 inline std::ostream& operator<<(std::ostream& out, const Kind& x) {
73  out << to_string(x);
74  return out;
75 }
76 
77 namespace kind {
78 inline auto from_string(const std::string_view& s) { return Kind::fromString(s); }
79 
80 // In the following, we predefine all attributes that are part of the HILTI language.
81 
82 const Kind AlwaysEmit("&always-emit");
83 const Kind Anchor("&anchor");
84 const Kind Anonymous("&anonymous");
85 const Kind Convert("&convert");
86 const Kind Cxxname("&cxxname");
87 const Kind Debug("&debug");
88 const Kind Default("&default");
89 const Kind HavePrototype("&have_prototype");
90 const Kind Internal("&internal");
91 const Kind NeededByFeature("&needed-by-feature");
92 const Kind NoEmit("&no-emit");
93 const Kind Nosub("&nosub");
94 const Kind OnHeap("&on-heap");
95 const Kind Optional("&optional");
96 const Kind Priority("&priority");
97 const Kind RequiresTypeFeature("&requires-type-feature");
98 const Kind Static("&static");
99 
100 } // namespace kind
101 } // namespace attribute
102 
104 class Attribute : public Node {
105 public:
107  const auto& kind() const { return _kind; }
108 
110  auto hasValue() const { return child(0) != nullptr; }
111 
117  Node* value() const { return child(0); }
118 
126 
135 
146 
157 
158  node::Properties properties() const final {
159  auto p = node::Properties{{"tag", to_string(kind())}};
160  return Node::properties() + std::move(p);
161  }
162 
171  static auto create(ASTContext* ctx, const attribute::Kind& kind, Expression* v, const Meta& m = Meta()) {
172  return ctx->make<Attribute>(ctx, {v}, kind, m);
173  }
174 
181  static auto create(ASTContext* ctx, const attribute::Kind& kind, const Meta& m = Meta()) {
182  return create(ctx, kind, nullptr, m);
183  }
184 
185 protected:
187  : Node(ctx, NodeTags, std::move(children), std::move(m)), _kind(std::move(kind)) {}
188 
189  std::string _dump() const override;
190 
191  HILTI_NODE_0(Attribute, final);
192 
193 private:
194  attribute::Kind _kind;
195 };
196 
198 class AttributeSet : public Node {
199 public:
201  auto attributes() const { return children<Attribute>(0, {}); }
202 
209  Attribute* find(const attribute::Kind& kind) const;
210 
216  hilti::node::Set<Attribute> findAll(const attribute::Kind& kind) const;
217 
223  bool has(const attribute::Kind& kind) const { return find(kind) != nullptr; }
224 
226  void add(ASTContext* ctx, Attribute* a) {
227  addChild(ctx, a);
228  // Combine this location with the attribute's location so this spans the range
229  setMeta(meta().mergeLocation(a->location()));
230  }
231 
233  void remove(const attribute::Kind& kind);
234 
236  operator bool() const { return ! attributes().empty(); }
237 
238  static auto create(ASTContext* ctx, const Attributes& attrs = {}, Meta m = Meta()) {
239  return ctx->make<AttributeSet>(ctx, attrs, std::move(m));
240  }
241 
242 protected:
250  : Node(ctx, NodeTags, std::move(children), std::move(m)) {}
251 
257  AttributeSet(ASTContext* ctx, Meta m = Meta()) : Node(ctx, {node::tag::AttributeSet}, {}, std::move(m)) {}
258 
259  std::string _dump() const override;
260 
261  HILTI_NODE_0(AttributeSet, final);
262 };
263 
264 } // namespace hilti
265 
266 namespace std {
267 template<>
268 struct hash<hilti::attribute::Kind> {
269  size_t operator()(const hilti::attribute::Kind& x) const { return std::hash<std::string>()(x); }
270 };
271 } // namespace std
Definition: ast-context.h:121
T * make(Args &&... args)
Definition: ast-context.h:366
Definition: attribute.h:104
static auto create(ASTContext *ctx, const attribute::Kind &kind, Expression *v, const Meta &m=Meta())
Definition: attribute.h:171
std::string _dump() const override
Definition: attribute.cc:80
Result< Expression * > valueAsExpression() const
Definition: attribute.cc:24
Node * value() const
Definition: attribute.h:117
Result< int64_t > valueAsInteger() const
Definition: attribute.cc:45
Result< bool > coerceValueTo(Builder *builder, QualifiedType *dst)
Definition: attribute.cc:60
static auto create(ASTContext *ctx, const attribute::Kind &kind, const Meta &m=Meta())
Definition: attribute.h:181
const auto & kind() const
Definition: attribute.h:107
node::Properties properties() const final
Definition: attribute.h:158
Result< std::string > valueAsString() const
Definition: attribute.cc:34
auto hasValue() const
Definition: attribute.h:110
Definition: attribute.h:198
std::string _dump() const override
Definition: attribute.cc:82
hilti::node::Set< Attribute > findAll(const attribute::Kind &kind) const
Definition: attribute.cc:92
void add(ASTContext *ctx, Attribute *a)
Definition: attribute.h:226
bool has(const attribute::Kind &kind) const
Definition: attribute.h:223
auto attributes() const
Definition: attribute.h:201
void remove(const attribute::Kind &kind)
Definition: attribute.cc:102
Attribute * find(const attribute::Kind &kind) const
Definition: attribute.cc:84
AttributeSet(ASTContext *ctx, Meta m=Meta())
Definition: attribute.h:257
AttributeSet(ASTContext *ctx, Nodes children, Meta m=Meta())
Definition: attribute.h:249
Definition: builder.h:36
Definition: expression.h:15
Definition: meta.h:30
Definition: node.h:239
void setMeta(Meta m)
Definition: node.h:311
void addChild(ASTContext *ctx, Node *n)
Definition: node.h:497
const auto & location() const
Definition: node.h:308
const auto & children() const
Definition: node.h:363
const auto & meta() const
Definition: node.h:305
T * child(unsigned int i) const
Definition: node.h:373
virtual node::Properties properties() const
Definition: node.h:866
Definition: forward.h:758
Definition: type.h:356
Definition: attribute.h:30
Definition: result.h:71