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> 20 #include <hilti/ast/types/void.h> 22 #include <spicy/ast/types/unit.h> 28 namespace unit::detail {
39 static inline void checkName(
const Expression& op0,
const Expression& op1, Node& node) {
40 auto id = memberExpression(op1).id().local();
41 auto i = op0.type().as<type::Unit>().itemByName(
id);
44 node.addError(hilti::util::fmt(
"type does not have field '%s'",
id));
48 static inline Type itemType(
const Expression& op0,
const Expression& op1) {
49 if (
auto st = op0.type().tryAs<type::Unit>() ) {
50 if (
auto i = st->itemByName(memberExpression(op1).
id().local()) )
59 BEGIN_OPERATOR_CUSTOM(unit, Unset)
62 bool isLhs()
const {
return true; }
63 auto priority()
const {
return hilti::operator_::Priority::Normal; }
65 const std::vector<Operand>& operands()
const {
66 static std::vector<Operand> _operands = {{{}, type::Unit(type::Wildcard()),
false, {},
"unit"},
67 {{}, type::Member(type::Wildcard()),
false, {},
"<field>"}};
72 detail::checkName(i.op0(), i.op1(), p.
node);
75 std::string doc()
const {
77 Clears an optional field. 82 BEGIN_OPERATOR_CUSTOM_x(unit, MemberNonConst, Member) 85 return type::DocOnly(
"<field type>");
87 return detail::itemType(ops[0], ops[1]);
90 bool isLhs()
const {
return true; }
91 auto priority()
const {
return hilti::operator_::Priority::Normal; }
93 const std::vector<Operand>& operands()
const {
94 static std::vector<Operand> _operands = {{{}, type::Unit(type::Wildcard()),
false, {},
"unit"},
95 {{}, type::Member(type::Wildcard()),
false, {},
"<field>"}};
100 detail::checkName(i.op0(), i.op1(), p.
node);
102 if ( i.op0().isConstant() )
103 p.
node.addError(
"cannot assign to field of constant unit instance");
106 std::string doc()
const {
108 Retrieves the value of a unit's field. If the field does not have a value assigned, 109 it returns its ``&default`` expression if that has been defined; otherwise it 110 triggers an exception. 113 END_OPERATOR_CUSTOM_x 115 BEGIN_OPERATOR_CUSTOM_x(unit, MemberConst, Member) 118 return type::DocOnly(
"<field type>");
120 return detail::itemType(ops[0], ops[1]);
123 bool isLhs()
const {
return false; }
124 auto priority()
const {
return hilti::operator_::Priority::Normal; }
126 const std::vector<Operand>& operands()
const {
127 static std::vector<Operand> _operands = {{{}, type::constant(type::Unit(type::Wildcard())),
false, {},
"unit"},
128 {{}, type::Member(type::Wildcard()),
false, {},
"<field>"}};
132 void validate(
const hilti::expression::ResolvedOperator& i, position_t p)
const {
133 detail::checkName(i.op0(), i.op1(), p.node);
136 std::string doc()
const {
138 Retrieves the value of a unit's field. If the field does not have a value assigned, 139 it returns its ``&default`` expression if that has been defined; otherwise it 140 triggers an exception. 143 END_OPERATOR_CUSTOM_x 145 BEGIN_OPERATOR_CUSTOM(unit, TryMember) 148 return type::DocOnly(
"<field type>");
150 return detail::itemType(ops[0], ops[1]);
153 bool isLhs()
const {
return false; }
154 auto priority()
const {
return hilti::operator_::Priority::Normal; }
156 const std::vector<Operand>& operands()
const {
157 static std::vector<Operand> _operands = {{{}, type::Unit(type::Wildcard()),
false, {},
"unit"},
158 {{}, type::Member(type::Wildcard()),
false, {},
"<field>"}};
162 void validate(
const hilti::expression::ResolvedOperator& i, position_t p)
const {
163 detail::checkName(i.op0(), i.op1(), p.node);
166 std::string doc()
const {
168 Retrieves the value of a unit's field. If the field does not have a value 169 assigned, it returns its ``&default`` expression if that has been defined; 170 otherwise it signals a special non-error exception to the host application 171 (which will normally still lead to aborting execution, similar to the standard 172 dereference operator, unless the host application specifically handles this 173 exception differently). 178 BEGIN_OPERATOR_CUSTOM(unit, HasMember) 181 bool isLhs()
const {
return false; }
182 auto priority()
const {
return hilti::operator_::Priority::Normal; }
184 const std::vector<Operand>& operands()
const {
185 static std::vector<Operand> _operands = {{{}, type::constant(type::Unit(type::Wildcard())),
false, {},
"unit"},
186 {{}, type::Member(type::Wildcard()),
false, {},
"<field>"}};
190 void validate(
const hilti::expression::ResolvedOperator& i, position_t p)
const {
191 detail::checkName(i.op0(), i.op1(), p.node);
194 std::string doc()
const {
195 return "Returns true if the unit's field has a value assigned (not counting any ``&default``).";
199 OPERATOR_DECLARE_ONLY(unit, MemberCall)
205 using hilti::expression::ResolvedOperatorBase::ResolvedOperatorBase;
208 Operator(
const type::Unit& stype,
const type::unit::item::Field& f) : _field(f) {
209 auto ftype = f.itemType().as<type::Function>();
210 auto op0 = Operand{{}, stype};
211 auto op1 = Operand{{}, type::Member(f.id())};
212 auto op2 = Operand{{}, type::OperandList::fromParameters(ftype.parameters())};
213 _operands = {op0, op1, op2};
214 _result = ftype.result().type();
217 static Kind kind() {
return Kind::MemberCall; }
218 const std::vector<Operand>& operands()
const {
return _operands; }
220 bool isLhs()
const {
return false; }
221 auto priority()
const {
return hilti::operator_::Priority::Normal; }
222 void validate(
const hilti::expression::ResolvedOperator& , position_t p)
const {}
223 std::string doc()
const {
return "<dynamic - no doc>"; }
224 std::string docNamespace()
const {
return "<dynamic - no ns>"; }
226 Expression instantiate(
const std::vector<Expression>& operands,
const Meta& meta)
const {
227 auto ops = std::vector<Expression>{operands[0],
231 auto ro = hilti::expression::ResolvedOperator(MemberCall(*
this, ops, meta));
237 type::unit::item::Field _field;
238 std::vector<Operand> _operands;
245 BEGIN_METHOD(unit, Offset)
246 const auto& signature()
const {
247 static auto _signature =
253 Returns the offset of the current location in the input stream relative to the 254 unit's start. If executed from inside a field hook, the offset will represent 255 the first byte that the field has been parsed from. If this method is called 256 before the unit's parsing has begun, it will throw a runtime exception. Once 257 parsing has started, the offset will remain available for the unit's entire 264 BEGIN_METHOD(unit, Position)
265 const auto& signature()
const {
266 static auto _signature =
272 Returns an iterator to the current position in the unit's input stream. If 273 executed from inside a field hook, the position will represent the first byte 274 that the field has been parsed from. If this method is called before the unit's 275 parsing has begun, it will throw a runtime exception. 282 BEGIN_METHOD(unit, Input)
283 const auto& signature()
const {
284 static auto _signature =
290 Returns an iterator referring to the input location where the current unit has 291 begun parsing. If this method is called before the units parsing has begun, it 292 will throw a runtime exception. Once available, the input position will remain 293 accessible for the unit's entire life time. 299 BEGIN_METHOD(unit, SetInput)
300 const auto& signature()
const {
301 static auto _signature =
303 .result = hilti::type::void_,
307 Moves the current parsing position to *i*. The iterator *i* must be into the 308 input of the current unit, or the method will throw a runtime exception. 314 BEGIN_METHOD(unit, Find)
315 const auto& signature()
const {
316 static auto _signature =
328 Searches a *needle* pattern inside the input region defined by where the unit 329 began parsing and its current parsing position. If executed from inside a field 330 hook, the current parasing position will represent the *first* byte that the 331 field has been parsed from. By default, the search will start at the beginning 332 of that region and scan forward. If the direction is 333 ``spicy::Direcction::Backward``, the search will start at the end of the region 334 and scan backward. In either case, a starting position can also be explicitly 335 given, but must lie inside the same region. 341 BEGIN_METHOD(unit, ConnectFilter)
342 const auto& signature()
const {
343 static auto _signature =
345 .result = hilti::type::void_,
346 .id =
"connect_filter",
350 Connects a separate filter unit to transform the unit's input transparently 351 before parsing. The filter unit will see the original input, and this unit will 352 receive everything the filter passes on through ``forward()``. 354 Filters can be connected only before a unit's parsing begins. The latest 355 possible point is from inside the target unit's ``%init`` hook. 361 BEGIN_METHOD(unit, Forward)
362 const auto& signature()
const {
363 static auto _signature =
365 .result = hilti::type::void_,
369 If the unit is connected as a filter to another one, this method forwards 370 transformed input over to that other one to parse. If the unit is not connected, 371 this method will silently discard the data. 377 BEGIN_METHOD(unit, ForwardEod)
378 const auto& signature()
const {
379 static auto _signature =
381 .result = hilti::type::void_,
385 If the unit is connected as a filter to another one, this method signals that 386 other one that end of its input has been reached. If the unit is not connected, 387 this method will not do anything. 393 BEGIN_METHOD(unit, Backtrack)
394 const auto& signature()
const {
395 static auto _signature =
397 .result = hilti::type::void_,
401 Aborts parsing at the current position and returns back to the most recent 402 ``&try`` attribute. Turns into a parse error if there's no ``&try`` in scope. 408 static inline auto contextResult(
bool is_const) {
411 if ( resolved_ops.empty() )
412 return type::DocOnly(
"<context>&");
414 if (
const auto& ctype = resolved_ops[0].type().as<type::Unit>().contextType() )
415 return Type(type::StrongReference(*ctype));
423 BEGIN_METHOD(unit, ContextConst)
424 const auto& signature()
const {
425 static auto _signature =
427 .result = contextResult(
true),
431 Returns a reference to the ``%context`` instance associated with the unit. 437 BEGIN_METHOD(unit, ContextNonConst)
438 const auto& signature()
const {
440 .result = contextResult(
false),
444 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