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);
43 node.addError(hilti::util::fmt(
"type does not have field '%s'",
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 const std::vector<Operand>& operands()
const {
65 static std::vector<Operand> _operands = {{{}, type::Unit(type::Wildcard()),
false, {},
"unit"},
66 {{}, type::Member(type::Wildcard()),
false, {},
"<field>"}};
71 detail::checkName(i.op0(), i.op1(), p.
node);
74 std::string doc()
const {
76 Clears an optional field. 81 BEGIN_OPERATOR_CUSTOM_x(unit, MemberNonConst, Member) 84 return type::DocOnly(
"<field type>");
86 return detail::itemType(ops[0], ops[1]);
89 bool isLhs()
const {
return true; }
90 auto priority()
const {
return hilti::operator_::Priority::Normal; }
92 const std::vector<Operand>& operands()
const {
93 static std::vector<Operand> _operands = {{{}, type::Unit(type::Wildcard()),
false, {},
"unit"},
94 {{}, type::Member(type::Wildcard()),
false, {},
"<field>"}};
99 detail::checkName(i.op0(), i.op1(), p.
node);
101 if ( i.op0().isConstant() )
102 p.
node.addError(
"cannot assign to field of constant unit instance");
105 std::string doc()
const {
107 Retrieves the value of a unit's field. If the field does not have a value assigned, 108 it returns its ``&default`` expression if that has been defined; otherwise it 109 triggers an exception. 112 END_OPERATOR_CUSTOM_x 114 BEGIN_OPERATOR_CUSTOM_x(unit, MemberConst, Member) 117 return type::DocOnly(
"<field type>");
119 return detail::itemType(ops[0], ops[1]);
122 bool isLhs()
const {
return false; }
123 auto priority()
const {
return hilti::operator_::Priority::Normal; }
125 const std::vector<Operand>& operands()
const {
126 static std::vector<Operand> _operands = {{{}, type::constant(type::Unit(type::Wildcard())),
false, {},
"unit"},
127 {{}, type::Member(type::Wildcard()),
false, {},
"<field>"}};
131 void validate(
const hilti::expression::ResolvedOperator& i, position_t p)
const {
132 detail::checkName(i.op0(), i.op1(), p.node);
135 std::string doc()
const {
137 Retrieves the value of a unit's field. If the field does not have a value assigned, 138 it returns its ``&default`` expression if that has been defined; otherwise it 139 triggers an exception. 142 END_OPERATOR_CUSTOM_x 144 BEGIN_OPERATOR_CUSTOM(unit, TryMember) 147 return type::DocOnly(
"<field type>");
149 return detail::itemType(ops[0], ops[1]);
152 bool isLhs()
const {
return false; }
153 auto priority()
const {
return hilti::operator_::Priority::Normal; }
155 const std::vector<Operand>& operands()
const {
156 static std::vector<Operand> _operands = {{{}, type::Unit(type::Wildcard()),
false, {},
"unit"},
157 {{}, type::Member(type::Wildcard()),
false, {},
"<field>"}};
161 void validate(
const hilti::expression::ResolvedOperator& i, position_t p)
const {
162 detail::checkName(i.op0(), i.op1(), p.node);
165 std::string doc()
const {
167 Retrieves the value of a unit's field. If the field does not have a value 168 assigned, it returns its ``&default`` expression if that has been defined; 169 otherwise it signals a special non-error exception to the host application 170 (which will normally still lead to aborting execution, similar to the standard 171 dereference operator, unless the host application specifically handles this 172 exception differently). 177 BEGIN_OPERATOR_CUSTOM(unit, HasMember) 180 bool isLhs()
const {
return false; }
181 auto priority()
const {
return hilti::operator_::Priority::Normal; }
183 const std::vector<Operand>& operands()
const {
184 static std::vector<Operand> _operands = {{{}, type::constant(type::Unit(type::Wildcard())),
false, {},
"unit"},
185 {{}, type::Member(type::Wildcard()),
false, {},
"<field>"}};
189 void validate(
const hilti::expression::ResolvedOperator& i, position_t p)
const {
190 detail::checkName(i.op0(), i.op1(), p.node);
193 std::string doc()
const {
194 return "Returns true if the unit's field has a value assigned (not counting any ``&default``).";
198 OPERATOR_DECLARE_ONLY(unit, MemberCall)
204 using hilti::expression::ResolvedOperatorBase::ResolvedOperatorBase;
207 Operator(
const type::Unit& stype,
const type::unit::item::Field& f) : _field(f) {
208 auto ftype = f.itemType().as<type::Function>();
209 auto op0 = Operand{{}, stype};
210 auto op1 = Operand{{}, type::Member(f.id())};
211 auto op2 = Operand{{}, type::OperandList::fromParameters(ftype.parameters())};
212 _operands = {op0, op1, op2};
213 _result = ftype.result().type();
216 static Kind kind() {
return Kind::MemberCall; }
217 const std::vector<Operand>& operands()
const {
return _operands; }
219 bool isLhs()
const {
return false; }
220 auto priority()
const {
return hilti::operator_::Priority::Normal; }
221 void validate(
const hilti::expression::ResolvedOperator& , position_t p)
const {}
222 std::string doc()
const {
return "<dynamic - no doc>"; }
223 std::string docNamespace()
const {
return "<dynamic - no ns>"; }
225 Expression instantiate(
const std::vector<Expression>& operands,
const Meta& meta)
const {
226 auto ops = std::vector<Expression>{operands[0],
230 auto ro = hilti::expression::ResolvedOperator(MemberCall(*
this, ops, meta));
236 type::unit::item::Field _field;
237 std::vector<Operand> _operands;
244 BEGIN_METHOD(unit, Offset)
245 const auto& signature()
const {
246 static auto _signature =
252 Returns the offset of the current location in the input stream relative to the 253 unit's start. If executed from inside a field hook, the offset will represent 254 the first byte that the field has been parsed from. If this method is called 255 before the unit's parsing has begun, it will throw a runtime exception. Once 256 parsing has started, the offset will remain available for the unit's entire 263 BEGIN_METHOD(unit, Position)
264 const auto& signature()
const {
265 static auto _signature =
271 Returns an iterator to the current position in the unit's input stream. If 272 executed from inside a field hook, the position will represent the first byte 273 that the field has been parsed from. If this method is called before the unit's 274 parsing has begun, it will throw a runtime exception. 281 BEGIN_METHOD(unit, Input)
282 const auto& signature()
const {
283 static auto _signature =
289 Returns an iterator referring to the input location where the current unit has 290 begun parsing. If this method is called before the units parsing has begun, it 291 will throw a runtime exception. Once available, the input position will remain 292 accessible for the unit's entire life time. 298 BEGIN_METHOD(unit, SetInput)
299 const auto& signature()
const {
300 static auto _signature =
302 .result = hilti::type::void_,
306 Moves the current parsing position to *i*. The iterator *i* must be into the 307 input of the current unit, or the method will throw a runtime exception. 313 BEGIN_METHOD(unit, Find)
314 const auto& signature()
const {
315 static auto _signature =
327 Searches a *needle* pattern inside the input region defined by where the unit 328 began parsing and its current parsing position. If executed from inside a field 329 hook, the current parasing position will represent the *first* byte that the 330 field has been parsed from. By default, the search will start at the beginning 331 of that region and scan forward. If the direction is 332 ``spicy::Direcction::Backward``, the search will start at the end of the region 333 and scan backward. In either case, a starting position can also be explicitly 334 given, but must lie inside the same region. 340 BEGIN_METHOD(unit, ConnectFilter)
341 const auto& signature()
const {
342 static auto _signature =
344 .result = hilti::type::void_,
345 .id =
"connect_filter",
349 Connects a separate filter unit to transform the unit's input transparently 350 before parsing. The filter unit will see the original input, and this unit will 351 receive everything the filter passes on through ``forward()``. 353 Filters can be connected only before a unit's parsing begins. The latest 354 possible point is from inside the target unit's ``%init`` hook. 360 BEGIN_METHOD(unit, Forward)
361 const auto& signature()
const {
362 static auto _signature =
364 .result = hilti::type::void_,
368 If the unit is connected as a filter to another one, this method forwards 369 transformed input over to that other one to parse. If the unit is not connected, 370 this method will silently discard the data. 376 BEGIN_METHOD(unit, ForwardEod)
377 const auto& signature()
const {
378 static auto _signature =
380 .result = hilti::type::void_,
384 If the unit is connected as a filter to another one, this method signals that 385 other one that end of its input has been reached. If the unit is not connected, 386 this method will not do anything. 392 BEGIN_METHOD(unit, Backtrack)
393 const auto& signature()
const {
394 static auto _signature =
396 .result = hilti::type::void_,
400 Aborts parsing at the current position and returns back to the most recent 401 ``&try`` attribute. Turns into a parse error if there's no ``&try`` in scope. 407 static inline auto contextResult(
bool is_const) {
410 if ( resolved_ops.empty() )
411 return type::DocOnly(
"<context>&");
413 const auto& ctype = resolved_ops[0].type().as<type::Unit>().contextType();
415 return Type(type::StrongReference(*ctype));
419 BEGIN_METHOD(unit, ContextConst)
420 const auto& signature()
const {
421 static auto _signature =
423 .result = contextResult(
true),
427 Returns a reference to the ``%context`` instance associated with the unit. 433 BEGIN_METHOD(unit, ContextNonConst)
434 const auto& signature()
const {
436 .result = contextResult(
false),
440 Returns a reference to the ``%context`` instance associated with the unit.
Definition: visitor-types.h:28
Definition: operator-registry.h:15
Definition: operator.h:35
E node
Definition: visitor-types.h:33
Definition: optional.h:13
Definition: reference.h:15
Type self
Definition: operator.h:255
Definition: resolved-operator.h:37
Definition: bitfield.h:17
Definition: operator.h:254