Spicy
attribute.h
1 // Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <functional>
6 #include <iostream>
7 #include <optional>
8 #include <string>
9 #include <utility>
10 #include <vector>
11 
12 #include <hilti/ast/ctors/integer.h>
13 #include <hilti/ast/ctors/string.h>
14 #include <hilti/ast/expression.h>
15 #include <hilti/ast/expressions/ctor.h>
16 #include <hilti/ast/node.h>
17 #include <hilti/base/logger.h>
18 #include <hilti/base/result.h>
19 #include <hilti/base/util.h>
20 #include <hilti/compiler/coercion.h>
21 #include <hilti/global.h>
22 
23 namespace hilti {
24 
26 class Attribute : public NodeBase {
27 public:
28  Attribute() = default;
29 
36  Attribute(std::string tag, Meta m = Meta()) : NodeBase({node::none}, std::move(m)), _tag(std::move(tag)) {}
37 
46  Attribute(std::string tag, Node v, Meta m = Meta())
47  : NodeBase({std::move(v)}, std::move(m)), _tag(std::move(tag)) {}
48 
50  const auto& tag() const { return _tag; }
51 
53  bool hasValue() const { return ! childs()[0].isA<node::None>(); }
54 
60  const Node& value() const { return childs().at(0); }
61 
73  template<typename T>
74  Result<T> valueAs() const {
75  if constexpr ( std::is_same<T, Expression>::value ) {
76  if ( ! hasValue() )
77  return result::Error(hilti::util::fmt("attribute '%s' requires an expression", _tag));
78 
79  if ( auto e = value().tryAs<Expression>() )
80  return *e;
81 
82  return result::Error(hilti::util::fmt("value for attribute '%s' must be an expression", _tag));
83  }
84 
85  if constexpr ( std::is_same<T, std::string>::value ) {
86  if ( ! hasValue() )
87  return result::Error(hilti::util::fmt("attribute '%s' requires a string", _tag));
88 
89  if ( auto e = value().tryAs<expression::Ctor>() )
90  if ( auto s = e->ctor().tryAs<ctor::String>() )
91  return s->value();
92  return result::Error(hilti::util::fmt("value for attribute '%s' must be a string", _tag));
93  }
94 
95  if constexpr ( std::is_same<T, int64_t>::value ) {
96  if ( ! hasValue() )
97  return result::Error(hilti::util::fmt("attribute '%s' requires an integer", _tag));
98 
99  if ( auto e = value().tryAs<expression::Ctor>() ) {
100  if ( auto s = e->ctor().tryAs<ctor::SignedInteger>() )
101  return s->value();
102 
103  if ( auto s = e->ctor().tryAs<ctor::UnsignedInteger>() )
104  return static_cast<int64_t>(s->value());
105  }
106 
107  return result::Error(hilti::util::fmt("value for attribute '%s' must be an integer", _tag));
108  }
109 
110  logger().internalError(hilti::util::fmt("unsupported attribute value type requested (%s)", typeid(T).name()));
111  }
112 
114  auto properties() const { return node::Properties{{"tag", _tag}}; }
115 
116  bool operator==(const Attribute& other) const {
117  if ( _tag != other._tag )
118  return false;
119 
120  if ( auto x = valueAs<Expression>() ) {
121  auto y = other.valueAs<Expression>();
122  return y && *x == *y;
123  }
124 
125  if ( auto x = valueAs<std::string>() ) {
126  auto y = other.valueAs<std::string>();
127  return y && *x == *y;
128  }
129 
130  return false;
131  }
132 
139  static Attribute setValue(const Attribute& a, Node n) {
140  auto x = Attribute(a);
141  if ( a.childs().empty() )
142  x.childs().emplace_back(std::move(n));
143  else
144  x.childs()[0] = std::move(n);
145 
146  return x;
147  }
148 
149 private:
150  std::string _tag;
151 };
152 
156 inline Node to_node(Attribute i) { return Node(std::move(i)); }
157 
159 class AttributeSet : public NodeBase {
160 public:
167  explicit AttributeSet(std::vector<Attribute> a, Meta m = Meta()) : NodeBase(nodes(std::move(a)), std::move(m)) {}
168 
174  AttributeSet(Meta m = Meta()) : NodeBase({}, std::move(m)) {}
175 
177  const auto& attributes() const {
178  if ( _cache.attributes.empty() )
179  _cache.attributes = childs<Attribute>(0, -1);
180 
181  return _cache.attributes;
182  }
183 
190  std::optional<Attribute> find(std::string_view tag) const {
191  for ( auto& a : attributes() )
192  if ( a.tag() == tag )
193  return a;
194 
195  return {};
196  }
197 
203  std::vector<Attribute> findAll(std::string_view tag) const {
204  std::vector<Attribute> result;
205 
206  for ( auto& a : attributes() )
207  if ( a.tag() == tag )
208  result.push_back(a);
209 
210  return result;
211  }
212 
222  Result<bool> coerceValueTo(const std::string& tag, const Type& dst) {
223  for ( auto& n : childs() ) {
224  auto a = n.as<Attribute>();
225  if ( a.tag() != tag )
226  continue;
227 
228  if ( auto e = a.valueAs<Expression>() ) {
229  auto ne = coerceExpression(*e, dst);
230  if ( ! ne.coerced )
231  return result::Error("cannot coerce attribute value");
232 
233  if ( ne.nexpr ) {
234  n = Attribute(tag, std::move(*ne.nexpr));
235  return true;
236  }
237 
238  return false;
239  }
240  }
241 
242  return false;
243  }
244 
250  bool has(std::string_view tag) const { return find(tag).has_value(); }
251 
253  auto properties() const { return node::Properties{}; }
254 
255  bool operator==(const AttributeSet& other) const { return attributes() == other.attributes(); };
256 
258  operator bool() const { return ! childs().empty(); }
259 
268  s.addChild(std::move(a));
269  return s;
270  }
271 
279  static std::optional<AttributeSet> add(std::optional<AttributeSet> s, Attribute a) {
280  if ( ! s )
281  s = AttributeSet({}, a.meta());
282 
283  s->addChild(std::move(a));
284  return s;
285  }
286 
295  static std::optional<Attribute> find(const std::optional<AttributeSet>& attrs, std::string_view tag) {
296  if ( attrs )
297  return attrs->find(tag);
298  else
299  return {};
300  }
301 
309  static std::vector<Attribute> findAll(const std::optional<AttributeSet>& attrs, std::string_view tag) {
310  if ( attrs )
311  return attrs->findAll(tag);
312  else
313  return {};
314  }
315 
323  static bool has(const std::optional<AttributeSet>& attrs, std::string_view tag) {
324  if ( attrs )
325  return attrs->has(tag);
326  else
327  return false;
328  }
329 
330  void clearCache() { _cache.attributes.clear(); }
331 
332 private:
333  mutable struct { std::vector<Attribute> attributes; } _cache;
334 };
335 
339 inline Node to_node(AttributeSet i) { return Node(std::move(i)); }
340 inline Node to_node(std::optional<AttributeSet>&& i) { return i ? to_node(*i) : node::none; }
341 
342 } // namespace hilti
Attribute(std::string tag, Node v, Meta m=Meta())
Definition: attribute.h:46
bool hasValue() const
Definition: attribute.h:53
static Attribute setValue(const Attribute &a, Node n)
Definition: attribute.h:139
auto & childs() const
Definition: node.h:445
Definition: result.h:18
std::vector< T > childs(int begin, int end) const
Definition: node.h:373
Definition: string.h:15
static std::optional< Attribute > find(const std::optional< AttributeSet > &attrs, std::string_view tag)
Definition: attribute.h:295
const Node none
Definition: node.cc:12
std::vector< Attribute > findAll(std::string_view tag) const
Definition: attribute.h:203
Definition: optional.h:79
void addChild(Node n)
Definition: node.h:434
Definition: node.h:468
Definition: integer.h:45
AttributeSet(std::vector< Attribute > a, Meta m=Meta())
Definition: attribute.h:167
const auto & attributes() const
Definition: attribute.h:177
const Node & value() const
Definition: attribute.h:60
Definition: integer.h:59
Definition: meta.h:18
Definition: attribute.h:159
static std::vector< Attribute > findAll(const std::optional< AttributeSet > &attrs, std::string_view tag)
Definition: attribute.h:309
Result< T > valueAs() const
Definition: attribute.h:74
Attribute(std::string tag, Meta m=Meta())
Definition: attribute.h:36
std::string fmt(const char *fmt, const Args &... args)
Definition: util.h:80
Definition: attribute.h:26
auto properties() const
Definition: attribute.h:114
const auto & tag() const
Definition: attribute.h:50
static bool has(const std::optional< AttributeSet > &attrs, std::string_view tag)
Definition: attribute.h:323
std::map< std::string, node::detail::PropertyValue > Properties
Definition: node.h:83
AttributeSet(Meta m=Meta())
Definition: attribute.h:174
Result< bool > coerceValueTo(const std::string &tag, const Type &dst)
Definition: attribute.h:222
static std::optional< AttributeSet > add(std::optional< AttributeSet > s, Attribute a)
Definition: attribute.h:279
auto properties() const
Definition: attribute.h:253
std::optional< Attribute > find(std::string_view tag) const
Definition: attribute.h:190
Definition: node.h:97
static AttributeSet add(AttributeSet s, Attribute a)
Definition: attribute.h:267
auto & meta() const
Definition: node.h:449
bool has(std::string_view tag) const
Definition: attribute.h:250
Definition: result.h:67
Definition: node.h:318
void clearCache()
Definition: node.h:457