Spicy
field.h
1 // Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <optional>
6 #include <utility>
7 #include <vector>
8 
9 #include <hilti/ast/types/vector.h>
10 #include <hilti/base/uniquer.h>
11 
12 #include <spicy/ast/aliases.h>
13 #include <spicy/ast/engine.h>
14 #include <spicy/ast/types/unit-item.h>
15 
16 namespace spicy::type::unit::item {
17 
20 public:
21  Field(const std::optional<ID>& id, Type type, Engine e, const std::vector<Expression>& args,
22  std::optional<Expression> repeat, const std::vector<Expression>& sinks,
23  std::optional<AttributeSet> attrs = {}, std::optional<Expression> cond = {}, std::vector<Hook> hooks = {},
24  Meta m = Meta())
25  : NodeBase(nodes((id ? id : _uniquer.get("anon")), std::move(type), node::none, repeat, std::move(attrs),
26  std::move(cond), args, sinks, hooks),
27  std::move(m)),
28  _is_forwarding(false),
29  _is_transient(! id.has_value()),
30  _engine(e),
31  _args_start(6),
32  _args_end(_args_start + static_cast<int>(args.size())),
33  _sinks_start(_args_end),
34  _sinks_end(_sinks_start + static_cast<int>(sinks.size())),
35  _hooks_start(_sinks_end),
36  _hooks_end(_hooks_start + static_cast<int>(hooks.size())) {}
37 
38  Field(const std::optional<ID>& id, Ctor ctor, Engine e, const std::vector<Expression>& args,
39  std::optional<Expression> repeat, const std::vector<Expression>& sinks,
40  std::optional<AttributeSet> attrs = {}, std::optional<Expression> cond = {}, std::vector<Hook> hooks = {},
41  Meta m = Meta())
42  : NodeBase(nodes((id ? id : _uniquer.get("anon")), ctor.type(), ctor, repeat, std::move(attrs), std::move(cond),
43  args, sinks, hooks),
44  std::move(m)),
45  _is_forwarding(false),
46  _is_transient(! id.has_value()),
47  _engine(e),
48  _args_start(6),
49  _args_end(_args_start + static_cast<int>(args.size())),
50  _sinks_start(_args_end),
51  _sinks_end(_sinks_start + static_cast<int>(sinks.size())),
52  _hooks_start(_sinks_end),
53  _hooks_end(_hooks_start + static_cast<int>(hooks.size())) {}
54 
55  Field(const std::optional<ID>& id, Item item, Engine e, const std::vector<Expression>& args,
56  std::optional<Expression> repeat, const std::vector<Expression>& sinks,
57  std::optional<AttributeSet> attrs = {}, std::optional<Expression> cond = {}, std::vector<Hook> hooks = {},
58  const Meta& m = Meta())
59  : NodeBase(nodes((id ? id : _uniquer.get("anon")), item.itemType(), item, repeat, std::move(attrs),
60  std::move(cond), args, sinks, hooks),
61  m),
62  _is_forwarding(false),
63  _is_transient(! id.has_value()),
64  _engine(e),
65  _args_start(6),
66  _args_end(_args_start + static_cast<int>(args.size())),
67  _sinks_start(_args_end),
68  _sinks_end(_sinks_start + static_cast<int>(sinks.size())),
69  _hooks_start(_sinks_end),
70  _hooks_end(_hooks_start + static_cast<int>(hooks.size())) {}
71 
72  Field() = delete;
73  Field(const Field& other) = default;
74  Field(Field&& other) = default;
75  ~Field() = default;
76 
77  const auto& id() const { return childs()[0].as<ID>(); }
78  auto index() const { return _index; }
79  auto ctor() const { return childs()[2].tryReferenceAs<Ctor>(); }
80  auto item() const { return childs()[2].tryReferenceAs<Item>(); }
81 
82  auto repeatCount() const { return childs()[3].tryReferenceAs<Expression>(); }
83  auto attributes() const { return childs()[4].tryReferenceAs<AttributeSet>(); }
84  auto condition() const { return childs()[5].tryReferenceAs<Expression>(); }
85  auto arguments() const { return childs<Expression>(_args_start, _args_end); }
86  auto sinks() const { return childs<Expression>(_sinks_start, _sinks_end); }
87  auto hooks() const { return childs<Hook>(_hooks_start, _hooks_end); }
88  Engine engine() const { return _engine; }
89 
90  bool isContainer() const { return repeatCount().has_value(); }
91  bool isForwarding() const { return _is_forwarding; }
92  bool isTransient() const { return _is_transient; }
93  bool emitHook() const { return ! isTransient() || hooks().size(); }
94 
95  Type parseType() const;
96 
97  Type originalType() const { return childs()[1].as<Type>(); }
98 
99  Node& originalTypeNode() { return childs()[1]; }
100  Node& ctorNode() { return childs()[2]; }
101  Node& itemNode() { return childs()[2]; }
102  Node& attributesNode() { return childs()[4]; }
103 
104  // Get the `&convert` expression, if any.
105  //
106  // For unit-level converts, returns the unit type as well.
107  std::optional<std::pair<Expression, std::optional<Type>>> convertExpression() const;
108 
109  bool operator==(const Field& other) const {
110  return _engine == other._engine && id() == other.id() && originalType() == other.originalType() &&
111  attributes() == other.attributes() && arguments() == other.arguments() && sinks() == other.sinks() &&
112  condition() == other.condition() && hooks() == other.hooks(); // TODO
113  }
114 
115  Field& operator=(const Field& other) = default;
116  Field& operator=(Field&& other) = default;
117 
118  // Unit item interface
119  Type itemType() const;
120  auto isEqual(const Item& other) const { return node::isEqual(this, other); }
121 
122  // Node interface.
123  auto properties() const {
124  return node::Properties{{"engine", to_string(_engine)},
125  {"transient", _is_transient},
126  {"forwarding", _is_forwarding}};
127  }
128 
129  // Helper function for vector fields that returns the type of the
130  // vector's elements. The helper can be used in situations where the
131  // field type might not be fully resolved. It computes the type
132  // indirectly and dynamically: It looks up the struct that `self` is
133  // currently pointing to, and then extracts the auxiliary type from the
134  // struct's field named *id*. That type must be a vector, from which it
135  // then retrieves the element type.
136  //
137  // This is rather specialized of course, but necessary in some contexts.
138  // Note that it can only be used (1) at code locations where ``self``
139  // evaluates to the desired struct, and (2) the field's auxiliary type
140  // has been set to a vector type (as we do for structs corresponding to
141  // units, where the auxiliary type is the parse type of the field).
142  static Type vectorElementTypeThroughSelf(ID id);
143 
151  static Field setIndex(const Field& f, uint64_t index) {
152  auto x = Item(f)._clone().as<Field>();
153  x._index = index;
154  return x;
155  }
156 
157  static Field setForwarding(const Field& f, bool is_forwarding) {
158  auto x = Item(f)._clone().as<Field>();
159  x._is_forwarding = is_forwarding;
160  return x;
161  }
162 
163 private:
164  std::optional<uint64_t> _index;
165  bool _is_forwarding;
166  bool _is_transient;
167  Engine _engine;
168  int _args_start;
169  int _args_end;
170  int _sinks_start;
171  int _sinks_end;
172  int _hooks_start;
173  int _hooks_end;
174 
175  static inline hilti::util::Uniquer<ID> _uniquer;
176 };
177 
178 } // namespace spicy::type::unit::item
NodeBase(Meta meta)
Definition: node.h:325
auto & childs() const
Definition: node.h:445
Definition: field.h:19
Definition: meta.h:18
Definition: attribute.h:159
Definition: uniquer.h:15
Definition: node.h:97
Definition: unit-item.h:19
static Field setIndex(const Field &f, uint64_t index)
Definition: field.h:151
Definition: unit-item.h:39
Definition: id.h:18
Definition: node.h:318