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 ! children()[0].isA<node::None>(); }
55 
61  const Node& value() const { return children()[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 
119  auto x = valueAsExpression();
120  if ( ! x )
121  return x.error();
122 
123  if ( ! type::isResolved(dst) )
124  return false;
125 
126  auto ne = coerceExpression(*x, dst);
127  if ( ! ne.coerced )
128  return result::Error(util::fmt("cannot coerce attribute's expression from type '%s' to '%s' (%s)",
129  x->get().type(), dst, tag()));
130 
131  if ( ne.nexpr ) {
132  children()[0] = *ne.nexpr;
133  return true;
134  }
135 
136  return false;
137  }
138 
140  auto properties() const { return node::Properties{{"tag", _tag}}; }
141 
142  bool operator==(const Attribute& other) const {
143  if ( _tag != other._tag )
144  return false;
145 
146  if ( auto x = valueAsExpression() ) {
147  auto y = other.valueAsExpression();
148  return y && *x == *y;
149  }
150 
151  else if ( auto x = valueAsString() ) {
152  auto y = other.valueAsString();
153  return y && *x == *y;
154  }
155 
156  else if ( auto x = valueAsInteger() ) {
157  auto y = other.valueAsInteger();
158  return y && *x == *y;
159  }
160 
161  return false;
162  }
163 
164 private:
165  std::string _tag;
166 };
167 
171 inline Node to_node(Attribute i) { return Node(std::move(i)); }
172 
174 class AttributeSet : public NodeBase {
175 public:
182  explicit AttributeSet(std::vector<Attribute> a, Meta m = Meta()) : NodeBase(nodes(std::move(a)), std::move(m)) {}
183 
189  AttributeSet(Meta m = Meta()) : NodeBase({}, std::move(m)) {}
190 
192  auto attributes() const { return children<Attribute>(0, -1); }
193 
200  hilti::optional_ref<const Attribute> find(std::string_view tag) const {
201  for ( const auto& a : attributes() )
202  if ( a.tag() == tag )
203  return a;
204 
205  return {};
206  }
207 
213  auto findAll(std::string_view tag) const {
215 
216  for ( const auto& a : attributes() )
217  if ( a.tag() == tag )
218  result.insert(a);
219 
220  return result;
221  }
222 
232  Result<bool> coerceValueTo(const std::string& tag, const Type& dst) {
233  if ( ! type::isResolved(dst) )
234  return false;
235 
236  for ( auto& n : children() ) {
237  auto a = n.as<Attribute>();
238  if ( a.tag() != tag )
239  continue;
240 
241  if ( auto e = a.valueAsExpression() ) {
242  auto ne = coerceExpression(*e, dst);
243  if ( ! ne.coerced )
244  return result::Error("cannot coerce attribute value");
245 
246  if ( ne.nexpr ) {
247  n = Attribute(tag, std::move(*ne.nexpr));
248  return true;
249  }
250 
251  return false;
252  }
253  }
254 
255  return false;
256  }
257 
263  bool has(std::string_view tag) const { return find(tag).has_value(); }
264 
266  auto properties() const { return node::Properties{}; }
267 
268  bool operator==(const AttributeSet& other) const { return attributes() == other.attributes(); };
269 
271  operator bool() const { return ! children().empty(); }
272 
281  s.addChild(std::move(a));
282  return s;
283  }
284 
292  static AttributeSet add(std::optional<AttributeSet> s, Attribute a) {
293  if ( ! s )
294  s = AttributeSet({}, a.meta());
295 
296  s->addChild(std::move(a));
297  return *s;
298  }
299 
309  std::string_view tag) {
310  if ( attrs )
311  return attrs->find(tag);
312  else
313  return {};
314  }
315 
323  static hilti::node::Set<Attribute> findAll(const std::optional<const AttributeSet>& attrs, std::string_view tag) {
324  if ( attrs )
325  return attrs->findAll(tag);
326  else
327  return {};
328  }
329 
338  std::string_view tag) {
339  if ( attrs )
340  return attrs->findAll(tag);
341  else
342  return {};
343  }
344 
352  static bool has(const std::optional<AttributeSet>& attrs, std::string_view tag) {
353  if ( attrs )
354  return attrs->has(tag);
355  else
356  return false;
357  }
358 };
359 
363 inline Node to_node(AttributeSet i) { return Node(std::move(i)); }
364 inline Node to_node(std::optional<AttributeSet>&& i) { return i ? to_node(*i) : node::none; }
365 
366 } // 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:337
Definition: string.h:14
Result< bool > coerceValueTo(const Type &dst)
Definition: attribute.h:118
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:323
const auto & children() const
Definition: node.h:471
void addChild(Node n)
Definition: node.h:460
Definition: node.h:490
Definition: integer.h:44
AttributeSet(std::vector< Attribute > a, Meta m=Meta())
Definition: attribute.h:182
const Node & value() const
Definition: attribute.h:61
Definition: integer.h:55
static hilti::optional_ref< const Attribute > find(const hilti::optional_ref< const AttributeSet > &attrs, std::string_view tag)
Definition: attribute.h:308
Definition: meta.h:19
Definition: attribute.h:174
Definition: type.h:160
Definition: optional-ref.h:22
Definition: node.h:40
auto findAll(std::string_view tag) const
Definition: attribute.h:213
Attribute(std::string tag, Meta m=Meta())
Definition: attribute.h:37
hilti::optional_ref< const Attribute > find(std::string_view tag) const
Definition: attribute.h:200
Definition: attribute.h:27
auto properties() const
Definition: attribute.h:140
const auto & tag() const
Definition: attribute.h:51
static bool has(const std::optional< AttributeSet > &attrs, std::string_view tag)
Definition: attribute.h:352
std::map< std::string, node::detail::PropertyValue > Properties
Definition: node.h:97
AttributeSet(Meta m=Meta())
Definition: attribute.h:189
Result< bool > coerceValueTo(const std::string &tag, const Type &dst)
Definition: attribute.h:232
auto properties() const
Definition: attribute.h:266
Definition: node.h:111
Result< std::reference_wrapper< const Expression > > valueAsExpression() const
Definition: attribute.h:74
static AttributeSet add(std::optional< AttributeSet > s, Attribute a)
Definition: attribute.h:292
static AttributeSet add(AttributeSet s, Attribute a)
Definition: attribute.h:280
auto & meta() const
Definition: node.h:475
bool has(std::string_view tag) const
Definition: attribute.h:263
auto attributes() const
Definition: attribute.h:192
Definition: result.h:67
Definition: node.h:359