10 #include <hilti/ast/builder/expression.h> 11 #include <hilti/ast/expressions/member.h> 12 #include <hilti/ast/operator.h> 13 #include <hilti/ast/operators/common.h> 14 #include <hilti/ast/types/any.h> 15 #include <hilti/ast/types/bytes.h> 16 #include <hilti/ast/types/integer.h> 17 #include <hilti/ast/types/reference.h> 18 #include <hilti/ast/types/stream.h> 19 #include <hilti/ast/types/unknown.h> 21 #include <spicy/ast/types/unit.h> 27 namespace unit::detail {
38 static inline void checkName(
const Expression& op0,
const Expression& op1, Node& node) {
39 auto id = memberExpression(op1).id().local();
40 auto i = op0.type().as<type::Unit>().itemByName(
id);
47 static inline Type itemType(
const Expression& op0,
const Expression& op1) {
48 if (
auto st = op0.type().tryAs<type::Unit>() ) {
49 if (
auto i = st->itemByName(memberExpression(op1).
id().local()) )
58 BEGIN_OPERATOR_CUSTOM(unit, Unset)
61 bool isLhs()
const {
return true; }
62 auto priority()
const {
return hilti::operator_::Priority::Normal; }
64 std::vector<Operand> operands()
const {
65 return {{.type = type::Unit(type::Wildcard()), .doc =
"unit"},
66 {.type = type::Member(type::Wildcard()), .doc =
"<field>"}};
70 detail::checkName(i.op0(), i.op1(), p.
node);
73 std::string doc()
const {
75 Clears an optional field. 80 BEGIN_OPERATOR_CUSTOM_x(unit, MemberNonConst, Member) 83 return type::DocOnly(
"<field type>");
85 return detail::itemType(ops[0], ops[1]);
88 bool isLhs()
const {
return true; }
89 auto priority()
const {
return hilti::operator_::Priority::Normal; }
91 std::vector<Operand> operands()
const {
92 return {{.type = type::Unit(type::Wildcard()), .doc =
"unit"},
93 {.type = type::Member(type::Wildcard()), .doc =
"<field>"}};
97 detail::checkName(i.op0(), i.op1(), p.
node);
99 if ( i.op0().isConstant() )
100 p.
node.addError(
"cannot assign to field of constant unit instance");
103 std::string doc()
const {
105 Retrieves the value of a unit's field. If the field does not have a value assigned, 106 it returns its ``&default`` expression if that has been defined; otherwise it 107 triggers an exception. 110 END_OPERATOR_CUSTOM_x 112 BEGIN_OPERATOR_CUSTOM_x(unit, MemberConst, Member) 115 return type::DocOnly(
"<field type>");
117 return detail::itemType(ops[0], ops[1]);
120 bool isLhs()
const {
return false; }
121 auto priority()
const {
return hilti::operator_::Priority::Normal; }
123 std::vector<Operand> operands()
const {
124 return {{.type = type::constant(type::Unit(type::Wildcard())), .doc =
"unit"},
125 {.type = type::Member(type::Wildcard()), .doc =
"<field>"}};
128 void validate(
const hilti::expression::ResolvedOperator& i, position_t p)
const {
129 detail::checkName(i.op0(), i.op1(), p.node);
132 std::string doc()
const {
134 Retrieves the value of a unit's field. If the field does not have a value assigned, 135 it returns its ``&default`` expression if that has been defined; otherwise it 136 triggers an exception. 139 END_OPERATOR_CUSTOM_x 141 BEGIN_OPERATOR_CUSTOM(unit, TryMember) 144 return type::DocOnly(
"<field type>");
146 return detail::itemType(ops[0], ops[1]);
149 bool isLhs()
const {
return false; }
150 auto priority()
const {
return hilti::operator_::Priority::Normal; }
152 std::vector<Operand> operands()
const {
153 return {{.type = type::Unit(type::Wildcard()), .doc =
"unit"},
154 {.type = type::Member(type::Wildcard()), .doc =
"<field>"}};
157 void validate(
const hilti::expression::ResolvedOperator& i, position_t p)
const {
158 detail::checkName(i.op0(), i.op1(), p.node);
161 std::string doc()
const {
163 Retrieves the value of a unit's field. If the field does not have a value 164 assigned, it returns its ``&default`` expression if that has been defined; 165 otherwise it signals a special non-error exception to the host application 166 (which will normally still lead to aborting execution, similar to the standard 167 dereference operator, unless the host application specifically handles this 168 exception differently). 173 BEGIN_OPERATOR_CUSTOM(unit, HasMember) 176 bool isLhs()
const {
return false; }
177 auto priority()
const {
return hilti::operator_::Priority::Normal; }
179 std::vector<Operand> operands()
const {
180 return {{.type = type::constant(type::Unit(type::Wildcard())), .doc =
"unit"},
181 {.type = type::Member(type::Wildcard()), .doc =
"<field>"}};
184 void validate(
const hilti::expression::ResolvedOperator& i, position_t p)
const {
185 detail::checkName(i.op0(), i.op1(), p.node);
188 std::string doc()
const {
189 return "Returns true if the unit's field has a value assigned (not counting any ``&default``).";
193 OPERATOR_DECLARE_ONLY(unit, MemberCall)
199 using hilti::expression::ResolvedOperatorBase::ResolvedOperatorBase;
202 Operator(
const type::Unit& stype,
const type::unit::item::Field& f) : _field(f) {
203 auto ftype = f.itemType().as<type::Function>();
204 auto op0 = Operand{.type = stype};
205 auto op1 = Operand{.type = type::Member(f.id())};
206 auto op2 = Operand{.type = type::OperandList::fromParameters(ftype.parameters())};
207 _operands = {op0, op1, op2};
208 _result = ftype.result().type();
211 static Kind kind() {
return Kind::MemberCall; }
212 std::vector<Operand> operands()
const {
return _operands; }
214 bool isLhs()
const {
return false; }
215 auto priority()
const {
return hilti::operator_::Priority::Normal; }
216 void validate(
const hilti::expression::ResolvedOperator& , position_t p)
const {}
217 std::string doc()
const {
return "<dynamic - no doc>"; }
218 std::string docNamespace()
const {
return "<dynamic - no ns>"; }
220 Expression instantiate(
const std::vector<Expression>& operands,
const Meta& meta)
const {
221 auto ops = std::vector<Expression>{operands[0],
225 auto ro = hilti::expression::ResolvedOperator(MemberCall(*
this, ops, meta));
231 type::unit::item::Field _field;
232 std::vector<Operand> _operands;
239 BEGIN_METHOD(unit, Offset)
240 auto signature()
const {
246 Returns the offset of the current location in the input stream relative to the 247 unit's start. If executed from inside a field hook, the offset will represent 248 the first byte that the field has been parsed from. If this method is called 249 before the unit's parsing has begun, it will throw a runtime exception. Once 250 parsing has started, the offset will remain available for the unit's entire 256 BEGIN_METHOD(unit, Position) 257 auto signature()
const {
263 Returns an iterator to the current position in the unit's input stream. If 264 executed from inside a field hook, the position will represent the first byte 265 that the field has been parsed from. If this method is called before the unit's 266 parsing has begun, it will throw a runtime exception. 272 BEGIN_METHOD(unit, Input) 273 auto signature()
const {
279 Returns an iterator referring to the input location where the current unit has 280 begun parsing. If this method is called before the units parsing has begun, it 281 will throw a runtime exception. Once available, the input position will remain 282 accessible for the unit's entire life time. 287 BEGIN_METHOD(unit, SetInput) 288 auto signature()
const {
290 .result = hilti::type::void_,
295 Moves the current parsing position to *i*. The iterator *i* must be into the 296 input of the current unit, or the method will throw a runtime exception. 301 BEGIN_METHOD(unit, Find) 302 auto signature()
const {
318 Searches a *needle* pattern inside the input region defined by where the unit 319 began parsing and its current parsing position. If executed from inside a field 320 hook, the current parasing position will represent the *first* byte that the 321 field has been parsed from. By default, the search will start at the beginning 322 of that region and scan forward. If the direction is 323 ``spicy::Direcction::Backward``, the search will start at the end of the region 324 and scan backward. In either case, a starting position can also be explicitly 325 given, but must lie inside the same region. 330 BEGIN_METHOD(unit, ConnectFilter) 331 auto signature()
const {
333 .result = hilti::type::void_,
334 .id =
"connect_filter",
335 .args = {{.id =
"filter",
339 Connects a separate filter unit to transform the unit's input transparently 340 before parsing. The filter unit will see the original input, and this unit will 341 receive everything the filter passes on through ``forward()``. 343 Filters can be connected only before a unit's parsing begins. The latest 344 possible point is from inside the target unit's ``%init`` hook. 349 BEGIN_METHOD(unit, Forward) 350 auto signature()
const {
352 .result = hilti::type::void_,
356 If the unit is connected as a filter to another one, this method forwards 357 transformed input over to that other one to parse. If the unit is not connected, 358 this method will silently discard the data. 363 BEGIN_METHOD(unit, ForwardEod) 364 auto signature()
const {
366 .result = hilti::type::void_,
370 If the unit is connected as a filter to another one, this method signals that 371 other one that end of its input has been reached. If the unit is not connected, 372 this method will not do anything. 377 BEGIN_METHOD(unit, Backtrack) 378 auto signature()
const {
380 .result = hilti::type::void_,
384 Aborts parsing at the current position and returns back to the most recent 385 ``&try`` attribute. Turns into a parse error if there's no ``&try`` in scope. 390 static inline auto contextResult(
bool is_const) {
393 if ( resolved_ops.empty() )
394 return type::DocOnly(
"<context>&");
396 const auto& ctype = resolved_ops[0].type().as<type::Unit>().contextType();
398 return Type(type::StrongReference(*ctype));
402 BEGIN_METHOD(unit, ContextConst)
403 auto signature()
const {
405 .result = contextResult(
true),
409 Returns a reference to the ``%context`` instance associated with the unit. 414 BEGIN_METHOD(unit, ContextNonConst) 415 auto signature()
const {
417 .result = contextResult(
false),
421 Returns a reference to the ``%context`` instance associated with the unit.
Definition: visitor-types.h:28
Definition: operator-registry.h:16
Definition: operator.h:38
E node
Definition: visitor-types.h:33
Definition: optional.h:14
Definition: reference.h:16
Type self
Definition: operator.h:244
std::string fmt(const char *fmt, const Args &... args)
Definition: util.h:80
Definition: resolved-operator.h:40
Definition: bitfield.h:18
Definition: operator.h:243