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