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/declarations/expression.h>
10 #include <hilti/ast/expressions/keyword.h>
11 #include <hilti/ast/types/vector.h>
12 #include <hilti/base/uniquer.h>
13 #include <hilti/base/util.h>
14 
15 #include <spicy/ast/aliases.h>
16 #include <spicy/ast/engine.h>
17 #include <spicy/ast/types/unit-item.h>
18 
19 namespace spicy::type::unit::item {
20 
23 public:
24  Field(const std::optional<ID>& id, Type type, Engine e, const std::vector<Expression>& args,
25  std::optional<Expression> repeat, const std::vector<Expression>& sinks,
26  std::optional<AttributeSet> attrs = {}, std::optional<Expression> cond = {},
27  const std::vector<Hook>& hooks = {}, Meta m = Meta())
28  : NodeBase(nodes((id ? id : _uniquer.get("anon")), hilti::type::pruneWalk(std::move(type)), hilti::type::auto_,
29  hilti::node::none, hilti::type::auto_, node::none, std::move(repeat), std::move(attrs),
30  std::move(cond), args, sinks, hooks),
31  std::move(m)),
32  _is_forwarding(false),
33  _is_transient(! id.has_value()),
34  _engine(e),
35  _args_start(9),
36  _args_end(_args_start + static_cast<int>(args.size())),
37  _sinks_start(_args_end),
38  _sinks_end(_sinks_start + static_cast<int>(sinks.size())),
39  _hooks_start(_sinks_end),
40  _hooks_end(_hooks_start + static_cast<int>(hooks.size())) {}
41 
42  Field(const std::optional<ID>& id, Ctor ctor, Engine e, const std::vector<Expression>& args,
43  std::optional<Expression> repeat, const std::vector<Expression>& sinks,
44  std::optional<AttributeSet> attrs = {}, std::optional<Expression> cond = {},
45  const std::vector<Hook>& hooks = {}, Meta m = Meta())
46  : NodeBase(nodes((id ? id : _uniquer.get("anon")), hilti::node::none, hilti::type::auto_, hilti::node::none,
47  hilti::type::auto_, std::move(ctor), std::move(repeat), std::move(attrs), std::move(cond),
48  args, sinks, hooks),
49  std::move(m)),
50  _is_forwarding(false),
51  _is_transient(! id.has_value()),
52  _engine(e),
53  _args_start(9),
54  _args_end(_args_start + static_cast<int>(args.size())),
55  _sinks_start(_args_end),
56  _sinks_end(_sinks_start + static_cast<int>(sinks.size())),
57  _hooks_start(_sinks_end),
58  _hooks_end(_hooks_start + static_cast<int>(hooks.size())) {}
59 
60  Field(const std::optional<ID>& id, Item item, Engine e, const std::vector<Expression>& args,
61  std::optional<Expression> repeat, const std::vector<Expression>& sinks,
62  std::optional<AttributeSet> attrs = {}, std::optional<Expression> cond = {},
63  const std::vector<Hook>& hooks = {}, const Meta& m = Meta())
64  : NodeBase(nodes((id ? id : _uniquer.get("anon")), hilti::node::none, hilti::type::auto_, hilti::node::none,
65  hilti::type::auto_, std::move(item), std::move(repeat), std::move(attrs), std::move(cond),
66  args, sinks, hooks),
67  m),
68  _is_forwarding(false),
69  _is_transient(! id.has_value()),
70  _engine(e),
71  _args_start(9),
72  _args_end(_args_start + static_cast<int>(args.size())),
73  _sinks_start(_args_end),
74  _sinks_end(_sinks_start + static_cast<int>(sinks.size())),
75  _hooks_start(_sinks_end),
76  _hooks_end(_hooks_start + static_cast<int>(hooks.size())) {}
77 
78  Field(const std::optional<ID>& id, NodeRef type, Engine e, const std::vector<Expression>& args,
79  std::optional<Expression> repeat, const std::vector<Expression>& sinks,
80  std::optional<AttributeSet> attrs = {}, std::optional<Expression> cond = {},
81  const std::vector<Hook>& hooks = {}, const Meta& m = Meta())
82  : NodeBase(nodes((id ? id : _uniquer.get("anon")), node::none, hilti::type::auto_, hilti::node::none,
83  hilti::type::auto_, node::none, std::move(repeat), std::move(attrs), std::move(cond), args,
84  sinks, hooks),
85  m),
86  _type(std::move(type)),
87  _is_forwarding(false),
88  _is_transient(! id.has_value()),
89  _engine(e),
90  _args_start(9),
91  _args_end(_args_start + static_cast<int>(args.size())),
92  _sinks_start(_args_end),
93  _sinks_end(_sinks_start + static_cast<int>(sinks.size())),
94  _hooks_start(_sinks_end),
95  _hooks_end(_hooks_start + static_cast<int>(hooks.size())) {
96  (*_type)->isA<hilti::declaration::Type>();
97  }
98 
99  Field() = delete;
100  Field(const Field& other) = default;
101  Field(Field&& other) = default;
102  ~Field() = default;
103 
104  const auto& id() const { return children()[0].as<ID>(); }
105  auto index() const { return _index; }
106  auto ctor() const { return children()[5].tryAs<Ctor>(); }
107  auto item() const { return children()[5].tryAs<Item>(); }
108 
109  auto repeatCount() const { return children()[6].tryAs<Expression>(); }
110  auto attributes() const { return children()[7].tryAs<AttributeSet>(); }
111  auto condition() const { return children()[8].tryAs<Expression>(); }
112  auto arguments() const { return children<Expression>(_args_start, _args_end); }
113  auto sinks() const { return children<Expression>(_sinks_start, _sinks_end); }
114  auto hooks() const { return children<Hook>(_hooks_start, _hooks_end); }
115  Engine engine() const { return _engine; }
116 
117  bool isContainer() const { return repeatCount().has_value(); }
118  bool isForwarding() const { return _is_forwarding; }
119  bool isTransient() const { return _is_transient; }
120  bool emitHook() const { return ! isTransient() || hooks().size(); }
121 
122  const Type& originalType() const {
123  if ( _type )
124  return (*_type)->as<hilti::declaration::Type>().type();
125 
126  if ( auto t = children()[1].tryAs<Type>() )
127  return *t;
128 
129  if ( auto c = ctor() )
130  return c->type();
131 
132  if ( auto i = item() )
133  return i->itemType();
134 
135  hilti::util::cannot_be_reached();
136  }
137 
138  const Type& parseType() const { return children()[2].as<Type>(); }
139  NodeRef parseTypeRef() const { return NodeRef(children()[2]); }
140  const Type& itemType() const { return children()[4].as<Type>(); }
141 
142  const Type& ddType() const {
143  if ( auto x = children()[3].tryAs<hilti::declaration::Expression>() )
144  return x->expression().type();
145  else
146  return hilti::type::auto_;
147  }
148 
149  NodeRef ddRef() const {
150  if ( children()[3].isA<Declaration>() )
151  return NodeRef(children()[3]);
152  else
153  return {};
154  }
155 
156  auto itemRef() { return NodeRef(children()[5]); }
157 
158  // Get the `&convert` expression, if any.
159  std::optional<std::pair<const Expression, std::optional<const Type>>> convertExpression() const;
160 
161  void setForwarding(bool is_forwarding) { _is_forwarding = is_forwarding; }
162  void setDDType(Type t) { children()[3] = hilti::expression::Keyword::createDollarDollarDeclaration(std::move(t)); }
163  void setIndex(uint64_t index) { _index = index; }
164  void setItemType(Type t) { children()[4] = hilti::type::pruneWalk(std::move(t)); }
165  void setParseType(Type t) { children()[2] = hilti::type::pruneWalk(std::move(t)); }
166 
167  bool operator==(const Field& other) const {
168  return _engine == other._engine && id() == other.id() && originalType() == other.originalType() &&
169  itemType() == other.itemType() && parseType() == other.parseType() &&
170  attributes() == other.attributes() && arguments() == other.arguments() && sinks() == other.sinks() &&
171  condition() == other.condition() && hooks() == other.hooks();
172  }
173 
174  Field& operator=(const Field& other) = default;
175  Field& operator=(Field&& other) = default;
176 
177  // Unit item interface
178  bool isResolved() const { return _type || item() || type::isResolved(itemType()); }
179  auto isEqual(const Item& other) const { return node::isEqual(this, other); }
180 
181  // Node interface.
182  auto properties() const {
183  return node::Properties{{"engine", to_string(_engine)},
184  {"transient", _is_transient},
185  {"forwarding", _is_forwarding}};
186  }
187 
188 private:
189  std::optional<NodeRef> _type;
190  std::optional<uint64_t> _index;
191  bool _is_forwarding;
192  bool _is_transient;
193  Engine _engine;
194  int _args_start;
195  int _args_end;
196  int _sinks_start;
197  int _sinks_end;
198  int _hooks_start;
199  int _hooks_end;
200 
201  static inline hilti::util::Uniquer<ID> _uniquer;
202 };
203 
204 } // namespace spicy::type::unit::item
NodeBase(Meta meta)
Definition: node.h:366
Definition: type.h:15
const Node none
Definition: node.cc:14
const auto & children() const
Definition: node.h:471
Definition: field.h:22
static Declaration createDollarDollarDeclaration(Type t)
Definition: keyword.h:63
Definition: meta.h:19
Definition: attribute.h:145
Definition: type.h:158
Definition: uniquer.h:15
Definition: node-ref.h:45
Definition: unit-item.h:19
Definition: hook.h:22
Definition: id.h:18
Definition: node.h:359