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/expressions/type.h>
10 #include <hilti/ast/operators/common.h>
11 #include <hilti/ast/types/bytes.h>
12 #include <hilti/ast/types/reference.h>
13 #include <hilti/ast/types/result.h>
14 #include <hilti/ast/types/stream.h>
15 #include <hilti/ast/types/tuple.h>
16 #include <hilti/ast/types/type.h>
17 
18 namespace hilti {
19 namespace operator_ {
20 
21 BEGIN_OPERATOR_CUSTOM(generic, Unpack)
22  Type result(const hilti::node::Range<Expression>& ops) const {
23  if ( ops.empty() )
24  return type::DocOnly("<unpackable>");
25 
26  const auto& data_type = ops[1].type().as<type::Tuple>().elements()[0].type();
27  return type::Result(type::Tuple({ops[0].type().as<type::Type_>().typeValue(), data_type}, ops[0].meta()));
28  }
29 
30  bool isLhs() const { return false; }
31 
32  std::vector<Operand> operands() const {
33  return {{.type = type::Type_(type::Wildcard())}, {.type = type::Tuple(type::Wildcard())}};
34  }
35 
36  void validate(const expression::ResolvedOperator& i, operator_::position_t p) const {
37  const auto& data_type = i.op1().type().template as<type::Tuple>().elements()[0].type();
38 
39  if ( ! (data_type.isA<type::Bytes>() || data_type.isA<type::stream::View>()) )
40  p.node.addError("unpack() can be used only with bytes or a stream view as input");
41  }
42 
43  std::string doc() const { return "Unpacks a value from a binary representation."; }
44 END_OPERATOR_CUSTOM
45 
46 BEGIN_OPERATOR_CUSTOM(generic, Begin)
47  Type result(const hilti::node::Range<Expression>& ops) const {
48  if ( ops.empty() )
49  return type::DocOnly("<iterator>");
50 
51  return type::isIterable(ops[0].type()) ? ops[0].type().iteratorType(ops[0].isConstant()) : type::unknown;
52  }
53 
54  bool isLhs() const { return false; }
55 
56  std::vector<Operand> operands() const {
57  return {
58  {.type = type::Any(), .doc = "<container>"},
59  };
60  }
61 
62  void validate(const expression::ResolvedOperator& i, operator_::position_t p) const {
63  if ( ! type::isIterable(i.operands()[0].type()) )
64  p.node.addError("not an iterable type");
65  }
66 
67  std::string doc() const { return "Returns an iterator to the beginning of the container's content."; }
68 END_OPERATOR_CUSTOM
69 
70 BEGIN_OPERATOR_CUSTOM(generic, End)
71  Type result(const hilti::node::Range<Expression>& ops) const {
72  if ( ops.empty() )
73  return type::DocOnly("<iterator>");
74 
75  return type::isIterable(ops[0].type()) ? ops[0].type().iteratorType(ops[0].isConstant()) : type::unknown;
76  }
77 
78  bool isLhs() const { return false; }
79 
80  std::vector<Operand> operands() const {
81  return {
82  {.type = type::Any(), .doc = "<container>"},
83  };
84  }
85 
86  void validate(const expression::ResolvedOperator& i, operator_::position_t p) const {
87  if ( ! type::isIterable(i.operands()[0].type()) )
88  p.node.addError("not an iterable type");
89  }
90 
91  std::string doc() const { return "Returns an iterator to the end of the container's content."; }
92 END_OPERATOR_CUSTOM
93 
94 BEGIN_OPERATOR_CUSTOM(generic, New)
95  Type result(const hilti::node::Range<Expression>& ops) const {
96  if ( ops.empty() )
97  return type::DocOnly("strong_ref<T>");
98 
99  auto t = ops[0].type();
100 
101  if ( auto tv = ops[0].type().tryAs<type::Type_>() )
102  t = tv->typeValue();
103 
104  return type::StrongReference(t, t.meta());
105  }
106 
107  bool isLhs() const { return false; }
108 
109  std::vector<Operand> operands() const {
110  return {
111  {.id = "t", .type = type::Any()},
112  {.type = type::Tuple(type::Wildcard())},
113  };
114  }
115 
116  void validate(const expression::ResolvedOperator& i, operator_::position_t p) const {
117  auto t = i.operands()[0].type();
118 
119  if ( auto tv = i.operands()[0].type().tryAs<type::Type_>() )
120  t = tv->typeValue();
121 
122  if ( ! type::isAllocable(t) )
123  p.node.addError("not an allocable type");
124  }
125 
126  std::string doc() const {
127  return R"(
128 Returns a reference to an instance of a type newly allocated on the heap.
129 If `x' is a type, a default instance of that type will be allocated.
130 If `x` is an expression, an instance of the expression's type will be allocated and initialized with the value of the expression.
131 )";
132  }
133 END_OPERATOR_CUSTOM
134 
140 OPERATOR_DECLARE_ONLY(generic, CastedCoercion)
141 
142 namespace generic {
143 
145 public:
146  using hilti::expression::ResolvedOperatorBase::ResolvedOperatorBase;
147 
149  Operator() = default;
150 
151  static operator_::Kind kind() { return operator_::Kind::Cast; }
152  std::vector<operator_::Operand> operands() const { return {}; } // Won't participate in overload resolution
153  Type result(const hilti::node::Range<Expression>& ops) const {
154  return ops[1].as<expression::Type_>().typeValue();
155  }
156  bool isLhs() const { return false; }
157  void validate(const expression::ResolvedOperator& /* i */, operator_::position_t /* p */) const {}
158  std::string doc() const { return "<dynamic - no doc>"; }
159  std::string docNamespace() const { return "<dynamic - no ns>"; }
160 
161  Expression instantiate(const std::vector<Expression>& operands, const Meta& meta) const {
162  auto ro = expression::ResolvedOperator(CastedCoercion(*this, operands, meta));
163  ro.setMeta(meta);
164  return std::move(ro);
165  }
166  };
167 };
168 } // namespace generic
169 
170 } // namespace operator_
171 } // namespace hilti
Definition: type.h:14
Definition: node.h:39
Definition: visitor-types.h:28
Definition: operator.h:38
Definition: meta.h:18
Definition: type.h:159
Definition: resolved-operator.h:40