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 <set>
9 #include <string>
10 #include <utility>
11 #include <vector>
12 
13 #include <hilti/ast/ctors/integer.h>
14 #include <hilti/ast/ctors/string.h>
15 #include <hilti/ast/expression.h>
16 #include <hilti/ast/expressions/ctor.h>
17 #include <hilti/ast/node.h>
18 #include <hilti/base/logger.h>
19 #include <hilti/base/result.h>
20 #include <hilti/base/util.h>
21 #include <hilti/compiler/coercion.h>
22 #include <hilti/global.h>
23 
24 namespace hilti {
25 
27 class Attribute : public NodeBase {
28 public:
29  Attribute() = default;
30 
37  Attribute(std::string tag, Meta m = Meta()) : NodeBase({node::none}, std::move(m)), _tag(std::move(tag)) {}
38 
47  Attribute(std::string tag, Node v, Meta m = Meta())
48  : NodeBase({std::move(v)}, std::move(m)), _tag(std::move(tag)) {}
49 
51  const auto& tag() const { return _tag; }
52 
54  bool hasValue() const { return ! childs()[0].isA<node::None>(); }
55 
61  const Node& value() const { return childs()[0]; }
62 
75  if ( ! hasValue() )
76  return result::Error(hilti::util::fmt("attribute '%s' requires an expression", _tag));
77 
78  if ( ! value().isA<Expression>() )
79  return result::Error(hilti::util::fmt("value for attribute '%s' must be an expression", _tag));
80 
81  return {value().as<Expression>()};
82  }
83 
84  Result<std::string> valueAsString() const {
85  if ( ! hasValue() )
86  return result::Error(hilti::util::fmt("attribute '%s' requires a string", _tag));
87 
88  if ( auto e = value().tryAs<expression::Ctor>() )
89  if ( auto s = e->ctor().tryAs<ctor::String>() )
90  return s->value();
91 
92  return result::Error(hilti::util::fmt("value for attribute '%s' must be a string", _tag));
93  }
94 
95  Result<int64_t> valueAsInteger() const {
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 
111  auto properties() const { return node::Properties{{"tag", _tag}}; }
112 
113  bool operator==(const Attribute& other) const {
114  if ( _tag != other._tag )
115  return false;
116 
117  if ( auto x = valueAsExpression() ) {
118  auto y = other.valueAsExpression();
119  return y && *x == *y;
120  }
121 
122  else if ( auto x = valueAsString() ) {
123  auto y = other.valueAsString();
124  return y && *x == *y;
125  }
126 
127  else if ( auto x = valueAsInteger() ) {
128  auto y = other.valueAsInteger();
129  return y && *x == *y;
130  }
131 
132  return false;
133  }
134 
135 private:
136  std::string _tag;
137 };
138 
142 inline Node to_node(Attribute i) { return Node(std::move(i)); }
143 
145 class AttributeSet : public NodeBase {
146 public:
153  explicit AttributeSet(std::vector<Attribute> a, Meta m = Meta()) : NodeBase(nodes(std::move(a)), std::move(m)) {}
154 
160  AttributeSet(Meta m = Meta()) : NodeBase({}, std::move(m)) {}
161 
163  auto attributes() const { return childs<Attribute>(0, -1); }
164 
171  hilti::optional_ref<const Attribute> find(std::string_view tag) const {
172  for ( const auto& a : attributes() )
173  if ( a.tag() == tag )
174  return a;
175 
176  return {};
177  }
178 
184  auto findAll(std::string_view tag) const {
186 
187  for ( const auto& a : attributes() )
188  if ( a.tag() == tag )
189  result.insert(a);
190 
191  return result;
192  }
193 
203  Result<bool> coerceValueTo(const std::string& tag, const Type& dst) {
204  if ( ! type::isResolved(dst) )
205  return false;
206 
207  for ( auto& n : childs() ) {
208  auto a = n.as<Attribute>();
209  if ( a.tag() != tag )
210  continue;
211 
212  if ( auto e = a.valueAsExpression() ) {
213  auto ne = coerceExpression(*e, dst);
214  if ( ! ne.coerced )
215  return result::Error("cannot coerce attribute value");
216 
217  if ( ne.nexpr ) {
218  n = Attribute(tag, std::move(*ne.nexpr));
219  return true;
220  }
221 
222  return false;
223  }
224  }
225 
226  return false;
227  }
228 
234  bool has(std::string_view tag) const { return find(tag).has_value(); }
235 
237  auto properties() const { return node::Properties{}; }
238 
239  bool operator==(const AttributeSet& other) const { return attributes() == other.attributes(); };
240 
242  operator bool() const { return ! childs().empty(); }
243 
252  s.addChild(std::move(a));
253  return s;
254  }
255 
263  static AttributeSet add(std::optional<AttributeSet> s, Attribute a) {
264  if ( ! s )
265  s = AttributeSet({}, a.meta());
266 
267  s->addChild(std::move(a));
268  return *s;
269  }
270 
280  std::string_view tag) {
281  if ( attrs )
282  return attrs->find(tag);
283  else
284  return {};
285  }
286 
294  static hilti::node::Set<Attribute> findAll(const std::optional<const AttributeSet>& attrs, std::string_view tag) {
295  if ( attrs )
296  return attrs->findAll(tag);
297  else
298  return {};
299  }
300 
309  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 
334 inline Node to_node(AttributeSet i) { return Node(std::move(i)); }
335 inline Node to_node(std::optional<AttributeSet>&& i) { return i ? to_node(*i) : node::none; }
336 
337 } // namespace hilti
Attribute(std::string tag, Node v, Meta m=Meta())
Definition: attribute.h:47
bool hasValue() const
Definition: attribute.h:54
Definition: result.h:18
static hilti::node::Set< Attribute > findAll(const hilti::optional_ref< const AttributeSet > &attrs, std::string_view tag)
Definition: attribute.h:308
Definition: string.h:15
const Node none
Definition: node.cc:14
Definition: optional.h:79
static hilti::node::Set< Attribute > findAll(const std::optional< const AttributeSet > &attrs, std::string_view tag)
Definition: attribute.h:294
void addChild(Node n)
Definition: node.h:459
Definition: node.h:489
Definition: integer.h:45
AttributeSet(std::vector< Attribute > a, Meta m=Meta())
Definition: attribute.h:153
const Node & value() const
Definition: attribute.h:61
Definition: integer.h:59
static hilti::optional_ref< const Attribute > find(const hilti::optional_ref< const AttributeSet > &attrs, std::string_view tag)
Definition: attribute.h:279
Definition: meta.h:18
Definition: attribute.h:145
Definition: type.h:159
Definition: optional-ref.h:22
Definition: node.h:42
auto findAll(std::string_view tag) const
Definition: attribute.h:184
Attribute(std::string tag, Meta m=Meta())
Definition: attribute.h:37
std::string fmt(const char *fmt, const Args &... args)
Definition: util.h:80
hilti::optional_ref< const Attribute > find(std::string_view tag) const
Definition: attribute.h:171
Definition: attribute.h:27
auto properties() const
Definition: attribute.h:111
const auto & tag() const
Definition: attribute.h:51
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:99
AttributeSet(Meta m=Meta())
Definition: attribute.h:160
Result< bool > coerceValueTo(const std::string &tag, const Type &dst)
Definition: attribute.h:203
auto properties() const
Definition: attribute.h:237
Definition: node.h:113
Result< std::reference_wrapper< const Expression > > valueAsExpression() const
Definition: attribute.h:74
static AttributeSet add(std::optional< AttributeSet > s, Attribute a)
Definition: attribute.h:263
const auto & childs() const
Definition: node.h:470
static AttributeSet add(AttributeSet s, Attribute a)
Definition: attribute.h:251
auto & meta() const
Definition: node.h:474
bool has(std::string_view tag) const
Definition: attribute.h:234
auto attributes() const
Definition: attribute.h:163
Definition: result.h:67
Definition: node.h:358