Spicy
generic.h
1 // Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <string>
6 #include <utility>
7 #include <vector>
8 
9 #include <hilti/ast/ctors/bool.h>
10 #include <hilti/ast/ctors/coerced.h>
11 #include <hilti/ast/expressions/type.h>
12 #include <hilti/ast/operators/common.h>
13 #include <hilti/ast/types/address.h>
14 #include <hilti/ast/types/bool.h>
15 #include <hilti/ast/types/bytes.h>
16 #include <hilti/ast/types/error.h>
17 #include <hilti/ast/types/integer.h>
18 #include <hilti/ast/types/real.h>
19 #include <hilti/ast/types/reference.h>
20 #include <hilti/ast/types/result.h>
21 #include <hilti/ast/types/stream.h>
22 #include <hilti/ast/types/tuple.h>
23 #include <hilti/ast/types/type.h>
24 
25 namespace hilti::operator_ {
26 
27 BEGIN_OPERATOR_CUSTOM(generic, Pack)
28  Type result(const hilti::node::Range<Expression>& ops) const {
29  if ( ops.empty() )
30  return type::DocOnly("<packable>");
31 
32  return type::Bytes();
33  }
34 
35  bool isLhs() const { return false; }
36  auto priority() const { return hilti::operator_::Priority::Normal; }
37 
38  const std::vector<Operand>& operands() const {
39  static std::vector<Operand> _operands = {Operand{{}, type::Tuple(type::Wildcard())}};
40  return _operands;
41  }
42 
43  void validate(const expression::ResolvedOperator& i, operator_::position_t p) const {
44  const auto args = i.op0().type().template as<type::Tuple>().elements();
45 
46  if ( args.empty() ) {
47  p.node.addError("not enough arguments for pack operator");
48  return;
49  }
50 
51  const auto& input_type = args[0].type();
52 
53  if ( input_type.isA<type::SignedInteger>() || input_type.isA<type::UnsignedInteger>() ) {
54  if ( args.size() == 2 ) {
55  auto arg1 = args[1].type().typeID();
56  if ( arg1 && arg1->local() == ID("ByteOrder") )
57  return;
58  }
59 
60  p.node.addError("invalid arguments for integer packing; want (<value>, <ByteOrder>)");
61  return;
62  }
63 
64  else if ( input_type.isA<type::Address>() ) {
65  if ( args.size() == 2 ) {
66  auto arg1 = args[1].type().typeID();
67  if ( arg1 && arg1->local() == ID("ByteOrder") )
68  return;
69  }
70 
71  p.node.addError("invalid arguments for address packing; want (<value>, <ByteOrder>)");
72  return;
73  }
74 
75  else if ( input_type.isA<type::Real>() ) {
76  if ( args.size() == 3 ) {
77  auto arg1 = args[1].type().typeID();
78  auto arg2 = args[2].type().typeID();
79  if ( arg1 && arg1->local() == ID("RealType") && arg2 && arg2->local() == ID("ByteOrder") )
80  return;
81  }
82 
83  p.node.addError("invalid arguments for real packing; want (<value>, <RealType>, <ByteOrder>)");
84  return;
85  }
86 
87  else
88  p.node.addError("type not packable");
89  }
90 
91  std::string doc() const { return "Packs a value into a binary representation."; }
92 END_OPERATOR_CUSTOM
93 
94 BEGIN_OPERATOR_CUSTOM(generic, Unpack)
95  Type result(const hilti::node::Range<Expression>& ops) const {
96  if ( ops.empty() )
97  return type::DocOnly("<unpackable>");
98 
99  const auto args = ops[1].type().template as<type::Tuple>().elements();
100  if ( args.empty() )
101  return type::Error();
102 
103  auto t = type::Tuple({ops[0].type().as<type::Type_>().typeValue(), args[0].type()}, ops[0].meta());
104 
105  auto throw_on_error = ops[2].as<expression::Ctor>().ctor().as<ctor::Bool>().value();
106  return throw_on_error ? Type(t) : Type(type::Result(t));
107  }
108 
109  bool isLhs() const { return false; }
110  auto priority() const { return hilti::operator_::Priority::Normal; }
111 
112  const std::vector<Operand>& operands() const {
113  static std::vector<Operand> _operands = {Operand{{}, type::Type_(type::Wildcard())},
114  Operand{{}, type::Tuple(type::Wildcard())}, Operand({}, type::Bool())};
115  return _operands;
116  }
117 
118  void validate(const expression::ResolvedOperator& i, operator_::position_t p) const {
119  const auto& data_type = i.op0().type().as<type::Type_>().typeValue();
120  const auto args = i.op1().type().template as<type::Tuple>().elements();
121 
122  if ( args.size() < 1 ) {
123  p.node.addError("not enough arguments for unpack operator");
124  return;
125  }
126 
127  const auto& input_type = args[0].type();
128 
129  if ( ! (input_type.isA<type::Bytes>() || input_type.isA<type::stream::View>()) ) {
130  p.node.addError("unpack() can be used only with bytes or a stream view as input");
131  return;
132  }
133 
134  if ( data_type.isA<type::SignedInteger>() || data_type.isA<type::UnsignedInteger>() ) {
135  if ( args.size() == 2 ) {
136  auto arg1 = args[1].type().typeID();
137  if ( arg1 && arg1->local() == ID("ByteOrder") )
138  return;
139  }
140 
141  p.node.addError("invalid arguments for integer unpacking; want (<data>, <ByteOrder>)");
142  return;
143  }
144 
145  else if ( data_type.isA<type::Address>() ) {
146  if ( args.size() == 3 ) {
147  auto arg1 = args[1].type().typeID();
148  auto arg2 = args[2].type().typeID();
149  if ( arg1 && arg1->local() == ID("AddressFamily") && arg2 && arg2->local() == ID("ByteOrder") )
150  return;
151  }
152 
153  p.node.addError("invalid arguments for address unpacking; want (<data>, <AddressFamily>, <ByteOrder>)");
154  return;
155  }
156 
157  else if ( data_type.isA<type::Real>() ) {
158  if ( args.size() == 3 ) {
159  auto arg1 = args[1].type().typeID();
160  auto arg2 = args[2].type().typeID();
161  if ( arg1 && arg1->local() == ID("RealType") && arg2 && arg2->local() == ID("ByteOrder") )
162  return;
163  }
164 
165  p.node.addError("invalid arguments for real unpacking; want (<data>, <RealType>, <ByteOrder>)");
166  return;
167  }
168 
169  else
170  p.node.addError("type not unpackable");
171  }
172 
173  std::string doc() const { return "Unpacks a value from a binary representation."; }
174 END_OPERATOR_CUSTOM
175 
176 BEGIN_OPERATOR_CUSTOM(generic, Begin)
177  Type result(const hilti::node::Range<Expression>& ops) const {
178  if ( ops.empty() )
179  return type::DocOnly("<iterator>");
180 
181  return type::isIterable(ops[0].type()) ? ops[0].type().iteratorType(ops[0].isConstant()) : type::unknown;
182  }
183 
184  bool isLhs() const { return false; }
185  auto priority() const { return hilti::operator_::Priority::Normal; }
186 
187  const std::vector<Operand>& operands() const {
188  static std::vector<Operand> _operands = {
189  Operand{{}, type::Any(), false, {}, "<container>"},
190  };
191  return _operands;
192  }
193 
194  void validate(const expression::ResolvedOperator& i, operator_::position_t p) const {
195  if ( ! type::isIterable(i.operands()[0].type()) )
196  p.node.addError("not an iterable type");
197  }
198 
199  std::string doc() const { return "Returns an iterator to the beginning of the container's content."; }
200 END_OPERATOR_CUSTOM
201 
202 BEGIN_OPERATOR_CUSTOM(generic, End)
203  Type result(const hilti::node::Range<Expression>& ops) const {
204  if ( ops.empty() )
205  return type::DocOnly("<iterator>");
206 
207  return type::isIterable(ops[0].type()) ? ops[0].type().iteratorType(ops[0].isConstant()) : type::unknown;
208  }
209 
210  bool isLhs() const { return false; }
211  auto priority() const { return hilti::operator_::Priority::Normal; }
212 
213  const std::vector<Operand>& operands() const {
214  static std::vector<Operand> _operands = {
215  {{}, type::Any(), false, {}, "<container>"},
216  };
217  return _operands;
218  }
219 
220  void validate(const expression::ResolvedOperator& i, operator_::position_t p) const {
221  if ( ! type::isIterable(i.operands()[0].type()) )
222  p.node.addError("not an iterable type");
223  }
224 
225  std::string doc() const { return "Returns an iterator to the end of the container's content."; }
226 END_OPERATOR_CUSTOM
227 
228 BEGIN_OPERATOR_CUSTOM(generic, New)
229  Type result(const hilti::node::Range<Expression>& ops) const {
230  if ( ops.empty() )
231  return type::DocOnly("strong_ref<T>");
232 
233  auto t = ops[0].type();
234 
235  if ( auto tv = ops[0].type().tryAs<type::Type_>() )
236  t = tv->typeValue();
237 
238  return type::StrongReference(t, t.meta());
239  }
240 
241  bool isLhs() const { return false; }
242  auto priority() const { return hilti::operator_::Priority::Normal; }
243 
244  const std::vector<Operand>& operands() const {
245  static std::vector<Operand> _operands = {
246  {"t", type::Any()},
247  {{}, type::Tuple(type::Wildcard())},
248  };
249  return _operands;
250  }
251 
252  void validate(const expression::ResolvedOperator& i, operator_::position_t p) const {
253  auto t = i.operands()[0].type();
254 
255  if ( auto tv = i.operands()[0].type().tryAs<type::Type_>() )
256  t = tv->typeValue();
257 
258  if ( ! type::isAllocable(t) )
259  p.node.addError("not an allocable type");
260  }
261 
262  std::string doc() const {
263  return R"(
264 Returns a reference to an instance of a type newly allocated on the heap.
265 If `x' is a type, a default instance of that type will be allocated.
266 If `x` is an expression, an instance of the expression's type will be allocated and initialized with the value of the expression.
267 )";
268  }
269 END_OPERATOR_CUSTOM
270 
276 OPERATOR_DECLARE_ONLY(generic, CastedCoercion)
277 
278 namespace generic {
279 
281 public:
282  using hilti::expression::ResolvedOperatorBase::ResolvedOperatorBase;
283 
285  Operator() = default;
286 
287  static operator_::Kind kind() { return operator_::Kind::Cast; }
288  const std::vector<operator_::Operand>& operands() const {
289  static std::vector<Operand> _operands = {}; // Won't participate in overload resolution
290  return _operands;
291  }
292  Type result(const hilti::node::Range<Expression>& ops) const {
293  return ops[1].as<expression::Type_>().typeValue();
294  }
295  bool isLhs() const { return false; }
296  auto priority() const { return hilti::operator_::Priority::Normal; }
297  void validate(const expression::ResolvedOperator& /* i */, operator_::position_t /* p */) const {}
298  std::string doc() const { return "<dynamic - no doc>"; }
299  std::string docNamespace() const { return "<dynamic - no ns>"; }
300 
301  Expression instantiate(const std::vector<Expression>& operands, const Meta& meta) const {
302  auto ro = expression::ResolvedOperator(CastedCoercion(*this, operands, meta));
303  ro.setMeta(meta);
304  return std::move(ro);
305  }
306  };
307 };
308 } // namespace generic
309 
310 } // namespace hilti::operator_
Definition: type.h:13
Definition: node.h:38
Definition: visitor-types.h:28
Definition: operator-registry.h:15
Definition: operator.h:35
Definition: meta.h:19
Definition: type.h:160
Definition: resolved-operator.h:37