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 
58  std::vector<Operand> operands() const {
59  return {{.type = type::Struct(type::Wildcard()), .doc = "struct"},
60  {.type = type::Member(type::Wildcard()), .doc = "<field>"}};
61  }
62 
63  void validate(const expression::ResolvedOperator& i, operator_::position_t p) const {
64  detail::checkName(i.op0(), i.op1(), p.node, true);
65  }
66 
67  std::string doc() const {
68  return R"(
69 Clears an optional field.
70 )";
71  }
72 END_OPERATOR_CUSTOM_x
73 
74 BEGIN_OPERATOR_CUSTOM_x(struct_, MemberNonConst, Member)
75  Type result(const hilti::node::Range<Expression>& ops) const {
76  if ( ops.empty() )
77  return type::DocOnly("<field type>");
78 
79  return type::nonConstant(detail::itemType(ops[0], ops[1]), true);
80  }
81 
82  bool isLhs() const { return true; }
83 
84  std::vector<Operand> operands() const {
85  return {{.type = type::Struct(type::Wildcard()), .doc = "struct"},
86  {.type = type::Member(type::Wildcard()), .doc = "<field>"}};
87  }
88 
89  void validate(const expression::ResolvedOperator& i, operator_::position_t p) const {
90  detail::checkName(i.op0(), i.op1(), p.node);
91  }
92 
93  std::string doc() const {
94  return R"(
95 Retrieves the value of a struct's field. If the field does not have a value assigned,
96 it returns its ``&default`` expression if that has been defined; otherwise it
97 triggers an exception.
98 )";
99  }
100 END_OPERATOR_CUSTOM_x
101 
102 BEGIN_OPERATOR_CUSTOM_x(struct_, MemberConst, Member)
103  Type result(const hilti::node::Range<Expression>& ops) const {
104  if ( ops.empty() )
105  return type::DocOnly("<field type>");
106 
107  return type::constant(detail::itemType(ops[0], ops[1]));
108  }
109 
110  bool isLhs() const { return false; }
111 
112  std::vector<Operand> operands() const {
113  return {{.type = type::constant(type::Struct(type::Wildcard())), .doc = "struct"},
114  {.type = type::Member(type::Wildcard()), .doc = "<field>"}};
115  }
116 
117  void validate(const expression::ResolvedOperator& i, operator_::position_t p) const {
118  detail::checkName(i.op0(), i.op1(), p.node);
119  }
120 
121  std::string doc() const {
122  return R"(
123 Retrieves the value of a struct's field. If the field does not have a value assigned,
124 it returns its ``&default`` expression if that has been defined; otherwise it
125 triggers an exception.
126 )";
127  }
128 END_OPERATOR_CUSTOM_x
129 
130 BEGIN_OPERATOR_CUSTOM(struct_, TryMember)
131  Type result(const hilti::node::Range<Expression>& ops) const {
132  if ( ops.empty() )
133  return type::DocOnly("<field type>");
134 
135  return detail::itemType(ops[0], ops[1]);
136  }
137 
138  bool isLhs() const { return false; }
139 
140  std::vector<Operand> operands() const {
141  return {{.type = type::Struct(type::Wildcard()), .doc = "struct"},
142  {.type = type::Member(type::Wildcard()), .doc = "<field>"}};
143  }
144 
145  void validate(const expression::ResolvedOperator& i, operator_::position_t p) const {
146  detail::checkName(i.op0(), i.op1(), p.node);
147  }
148 
149  std::string doc() const {
150  return R"(
151 Retrieves the value of a struct's field. If the field does not have a value
152 assigned, it returns its ``&default`` expression if that has been defined;
153 otherwise it signals a special non-error exception to the host application
154 (which will normally still lead to aborting execution, similar to the standard
155 dereference operator, unless the host application specifically handles this
156 exception differently).
157 )";
158  }
159 END_OPERATOR_CUSTOM
160 
161 BEGIN_OPERATOR_CUSTOM(struct_, HasMember)
162  Type result(const hilti::node::Range<Expression>& /* ops */) const { return type::Bool(); }
163 
164  bool isLhs() const { return false; }
165 
166  std::vector<Operand> operands() const {
167  return {{.type = type::constant(type::Struct(type::Wildcard())), .doc = "struct"},
168  {.type = type::Member(type::Wildcard()), .doc = "<field>"}};
169  }
170 
171  void validate(const expression::ResolvedOperator& i, operator_::position_t p) const {
172  detail::checkName(i.op0(), i.op1(), p.node);
173  }
174 
175  std::string doc() const {
176  return "Returns true if the struct's field has a value assigned (not counting any ``&default``).";
177  }
178 END_OPERATOR_CUSTOM
179 
180 OPERATOR_DECLARE_ONLY(struct_, MemberCall)
181 
182 namespace struct_ {
183 
184 class MemberCall : public hilti::expression::ResolvedOperatorBase {
185 public:
186  using hilti::expression::ResolvedOperatorBase::ResolvedOperatorBase;
187 
188  struct Operator : public hilti::trait::isOperator {
189  Operator(const type::Struct& stype, const declaration::Field& f) {
190  auto ftype = f.type().as<type::Function>();
191  auto op0 = operator_::Operand{.type = stype};
192  auto op1 = operator_::Operand{.type = type::Member(f.id())};
193  auto op2 = operator_::Operand{.type = type::OperandList::fromParameters(ftype.parameters())};
194  _field = f;
195  _operands = {op0, op1, op2};
196  _result = ftype.result().type();
197  };
198 
199  static operator_::Kind kind() { return operator_::Kind::MemberCall; }
200  std::vector<operator_::Operand> operands() const { return _operands; }
201  Type result(const hilti::node::Range<Expression>& /* ops */) const { return _result; }
202  bool isLhs() const { return false; }
203  void validate(const expression::ResolvedOperator& /* i */, operator_::position_t p) const {}
204  std::string doc() const { return "<dynamic - no doc>"; }
205  std::string docNamespace() const { return "<dynamic - no ns>"; }
206 
207  Expression instantiate(const std::vector<Expression>& operands, const Meta& meta) const {
208  auto ops =
209  std::vector<Expression>{operands[0], expression::Member(_field.id(), _field.type(), _field.meta()),
210  operands[2]};
211 
212  auto ro = expression::ResolvedOperator(MemberCall(*this, ops, meta));
213  ro.setMeta(meta);
214  return ro;
215  }
216 
217  private:
218  declaration::Field _field;
219  std::vector<operator_::Operand> _operands;
220  Type _result;
221  };
222 };
223 
224 } // namespace struct_
225 
226 } // namespace operator_
227 } // 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