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