Spicy
struct.h
1 // Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <string>
6 #include <vector>
7 
8 #include <hilti/ast/expressions/member.h>
9 #include <hilti/ast/operators/common.h>
10 #include <hilti/ast/types/any.h>
11 #include <hilti/ast/types/struct.h>
12 #include <hilti/ast/types/unknown.h>
13 
14 namespace hilti::operator_ {
15 
16 namespace struct_::detail {
17 
18 // Returns an operand as a member expression.
19 static expression::Member memberExpression(const Expression& op) {
20  if ( auto c = op.tryAs<expression::Coerced>() )
21  return c->expression().as<expression::Member>();
22 
23  return op.as<expression::Member>();
24 }
25 
26 // Checks if an operand refers to a valid field inside a struct.
27 static inline void checkName(const Expression& op0, const Expression& op1, Node& node, bool check_optional = false) {
28  auto id = memberExpression(op1).id().local();
29  auto f = op0.type().as<type::Struct>().field(id);
30 
31  if ( ! f ) {
32  node.addError(util::fmt("type does not have field '%s'", id));
33  return;
34  }
35 
36  if ( check_optional && ! f->isOptional() )
37  node.addError(util::fmt("field '%s' is not &optional", id));
38 }
39 
40 // Returns the type of a struct field referenced by an operand.
41 static inline Type itemType(const Expression& op0, const Expression& op1) {
42  if ( auto st = op0.type().tryAs<type::Struct>() ) {
43  if ( auto f = st->field(memberExpression(op1).id().local()) )
44  return f->type();
45  }
46 
47  return type::unknown;
48 }
49 
50 } // namespace struct_::detail
51 
52 BEGIN_OPERATOR_CUSTOM(struct_, Unset)
53  Type result(const hilti::node::Range<Expression>& ops) const { return type::void_; }
54 
55  bool isLhs() const { return true; }
56  auto priority() const { return hilti::operator_::Priority::Normal; }
57 
58  const std::vector<Operand>& operands() const {
59  static std::vector<Operand> _operands = {{{}, type::Struct(type::Wildcard()), false, {}, "struct"},
60  {{}, type::Member(type::Wildcard()), false, {}, "<field>"}};
61  return _operands;
62  }
63 
64  void validate(const expression::ResolvedOperator& i, operator_::position_t p) const {
65  detail::checkName(i.op0(), i.op1(), p.node, true);
66  }
67 
68  std::string doc() const {
69  return R"(
70 Clears an optional field.
71 )";
72  }
73 END_OPERATOR_CUSTOM_x
74 
75 BEGIN_OPERATOR_CUSTOM_x(struct_, MemberNonConst, Member)
76  Type result(const hilti::node::Range<Expression>& ops) const {
77  if ( ops.empty() )
78  return type::DocOnly("<field type>");
79 
80  return type::nonConstant(detail::itemType(ops[0], ops[1]), true);
81  }
82 
83  bool isLhs() const { return true; }
84  auto priority() const { return hilti::operator_::Priority::Normal; }
85 
86  const std::vector<Operand>& operands() const {
87  static std::vector<Operand> _operands = {{{}, type::Struct(type::Wildcard()), false, {}, "struct"},
88  {{}, type::Member(type::Wildcard()), false, {}, "<field>"}};
89  return _operands;
90  }
91 
92  void validate(const expression::ResolvedOperator& i, operator_::position_t p) const {
93  detail::checkName(i.op0(), i.op1(), p.node);
94  }
95 
96  std::string doc() const {
97  return R"(
98 Retrieves the value of a struct's field. If the field does not have a value assigned,
99 it returns its ``&default`` expression if that has been defined; otherwise it
100 triggers an exception.
101 )";
102  }
103 END_OPERATOR_CUSTOM_x
104 
105 BEGIN_OPERATOR_CUSTOM_x(struct_, MemberConst, Member)
106  Type result(const hilti::node::Range<Expression>& ops) const {
107  if ( ops.empty() )
108  return type::DocOnly("<field type>");
109 
110  return type::constant(detail::itemType(ops[0], ops[1]));
111  }
112 
113  bool isLhs() const { return false; }
114  auto priority() const { return hilti::operator_::Priority::Normal; }
115 
116  const std::vector<Operand>& operands() const {
117  static std::vector<Operand> _operands =
118  {{{}, type::constant(type::Struct(type::Wildcard())), false, {}, "struct"},
119  {{}, type::Member(type::Wildcard()), false, {}, "<field>"}};
120  return _operands;
121  }
122 
123  void validate(const expression::ResolvedOperator& i, operator_::position_t p) const {
124  detail::checkName(i.op0(), i.op1(), p.node);
125  }
126 
127  std::string doc() const {
128  return R"(
129 Retrieves the value of a struct's field. If the field does not have a value assigned,
130 it returns its ``&default`` expression if that has been defined; otherwise it
131 triggers an exception.
132 )";
133  }
134 END_OPERATOR_CUSTOM_x
135 
136 BEGIN_OPERATOR_CUSTOM(struct_, TryMember)
137  Type result(const hilti::node::Range<Expression>& ops) const {
138  if ( ops.empty() )
139  return type::DocOnly("<field type>");
140 
141  return detail::itemType(ops[0], ops[1]);
142  }
143 
144  bool isLhs() const { return false; }
145  auto priority() const { return hilti::operator_::Priority::Normal; }
146 
147  const std::vector<Operand>& operands() const {
148  static std::vector<Operand> _operands = {{{}, type::Struct(type::Wildcard()), false, {}, "struct"},
149  {{}, type::Member(type::Wildcard()), false, {}, "<field>"}};
150  return _operands;
151  }
152 
153  void validate(const expression::ResolvedOperator& i, operator_::position_t p) const {
154  detail::checkName(i.op0(), i.op1(), p.node);
155  }
156 
157  std::string doc() const {
158  return R"(
159 Retrieves the value of a struct's field. If the field does not have a value
160 assigned, it returns its ``&default`` expression if that has been defined;
161 otherwise it signals a special non-error exception to the host application
162 (which will normally still lead to aborting execution, similar to the standard
163 dereference operator, unless the host application specifically handles this
164 exception differently).
165 )";
166  }
167 END_OPERATOR_CUSTOM
168 
169 BEGIN_OPERATOR_CUSTOM(struct_, HasMember)
170  Type result(const hilti::node::Range<Expression>& /* ops */) const { return type::Bool(); }
171 
172  bool isLhs() const { return false; }
173  auto priority() const { return hilti::operator_::Priority::Normal; }
174 
175  const std::vector<Operand>& operands() const {
176  static std::vector<Operand> _operands =
177  {{{}, type::constant(type::Struct(type::Wildcard())), false, {}, "struct"},
178  {{}, type::Member(type::Wildcard()), false, {}, "<field>"}};
179  return _operands;
180  }
181 
182  void validate(const expression::ResolvedOperator& i, operator_::position_t p) const {
183  detail::checkName(i.op0(), i.op1(), p.node);
184  }
185 
186  std::string doc() const {
187  return "Returns true if the struct's field has a value assigned (not counting any ``&default``).";
188  }
189 END_OPERATOR_CUSTOM
190 
191 OPERATOR_DECLARE_ONLY(struct_, MemberCall)
192 
193 namespace struct_ {
194 
195 class MemberCall : public hilti::expression::ResolvedOperatorBase {
196 public:
197  using hilti::expression::ResolvedOperatorBase::ResolvedOperatorBase;
198 
199  struct Operator : public hilti::trait::isOperator {
200  Operator(const type::Struct& stype, const declaration::Field& f) {
201  auto ftype = f.type().as<type::Function>();
202  auto op0 = operator_::Operand{{}, stype};
203  auto op1 = operator_::Operand{{}, type::Member(f.id())};
204  auto op2 = operator_::Operand{{}, type::OperandList::fromParameters(ftype.parameters())};
205  _field = f;
206  _operands = {op0, op1, op2};
207  _result = ftype.result().type();
208  };
209 
210  static operator_::Kind kind() { return operator_::Kind::MemberCall; }
211  const std::vector<operator_::Operand>& operands() const { return _operands; }
212  Type result(const hilti::node::Range<Expression>& /* ops */) const { return _result; }
213  bool isLhs() const { return false; }
214  auto priority() const { return hilti::operator_::Priority::Normal; }
215  void validate(const expression::ResolvedOperator& /* i */, operator_::position_t p) const {}
216  std::string doc() const { return "<dynamic - no doc>"; }
217  std::string docNamespace() const { return "<dynamic - no ns>"; }
218 
219  Expression instantiate(const std::vector<Expression>& operands, const Meta& meta) const {
220  auto ops =
221  std::vector<Expression>{operands[0], expression::Member(_field.id(), _field.type(), _field.meta()),
222  operands[2]};
223 
224  auto ro = expression::ResolvedOperator(MemberCall(*this, ops, meta));
225  ro.setMeta(meta);
226  return ro;
227  }
228 
229  private:
230  declaration::Field _field;
231  std::vector<operator_::Operand> _operands;
232  Type _result;
233  };
234 };
235 
236 } // namespace struct_
237 
238 } // namespace hilti::operator_
Definition: node.h:37
Definition: operator-registry.h:15
Definition: operator.h:35
Definition: resolved-operator.h:37