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; }
63 std::vector<Operand> operands()
const {
64 return {{.type = type::Unit(type::Wildcard()), .doc =
"unit"},
65 {.type = type::Member(type::Wildcard()), .doc =
"<field>"}};
69 detail::checkName(i.op0(), i.op1(), p.
node);
72 std::string doc()
const {
74 Clears an optional field. 79 BEGIN_OPERATOR_CUSTOM_x(unit, MemberNonConst, Member) 82 return type::DocOnly(
"<field type>");
84 return detail::itemType(ops[0], ops[1]);
87 bool isLhs()
const {
return true; }
89 std::vector<Operand> operands()
const {
90 return {{.type = type::Unit(type::Wildcard()), .doc =
"unit"},
91 {.type = type::Member(type::Wildcard()), .doc =
"<field>"}};
95 detail::checkName(i.op0(), i.op1(), p.
node);
97 if ( i.op0().isConstant() )
98 p.
node.addError(
"cannot assign to field of constant unit instance");
101 std::string doc()
const {
103 Retrieves the value of a unit's field. If the field does not have a value assigned, 104 it returns its ``&default`` expression if that has been defined; otherwise it 105 triggers an exception. 108 END_OPERATOR_CUSTOM_x 110 BEGIN_OPERATOR_CUSTOM_x(unit, MemberConst, Member) 113 return type::DocOnly(
"<field type>");
115 return detail::itemType(ops[0], ops[1]);
118 bool isLhs()
const {
return false; }
120 std::vector<Operand> operands()
const {
121 return {{.type = type::constant(type::Unit(type::Wildcard())), .doc =
"unit"},
122 {.type = type::Member(type::Wildcard()), .doc =
"<field>"}};
125 void validate(
const hilti::expression::ResolvedOperator& i, position_t p)
const {
126 detail::checkName(i.op0(), i.op1(), p.node);
129 std::string doc()
const {
131 Retrieves the value of a unit's field. If the field does not have a value assigned, 132 it returns its ``&default`` expression if that has been defined; otherwise it 133 triggers an exception. 136 END_OPERATOR_CUSTOM_x 138 BEGIN_OPERATOR_CUSTOM(unit, TryMember) 141 return type::DocOnly(
"<field type>");
143 return detail::itemType(ops[0], ops[1]);
146 bool isLhs()
const {
return false; }
148 std::vector<Operand> operands()
const {
149 return {{.type = type::Unit(type::Wildcard()), .doc =
"unit"},
150 {.type = type::Member(type::Wildcard()), .doc =
"<field>"}};
153 void validate(
const hilti::expression::ResolvedOperator& i, position_t p)
const {
154 detail::checkName(i.op0(), i.op1(), p.node);
157 std::string doc()
const {
159 Retrieves the value of a unit's field. If the field does not have a value 160 assigned, it returns its ``&default`` expression if that has been defined; 161 otherwise it signals a special non-error exception to the host application 162 (which will normally still lead to aborting execution, similar to the standard 163 dereference operator, unless the host application specifically handles this 164 exception differently). 169 BEGIN_OPERATOR_CUSTOM(unit, HasMember) 172 bool isLhs()
const {
return false; }
174 std::vector<Operand> operands()
const {
175 return {{.type = type::constant(type::Unit(type::Wildcard())), .doc =
"unit"},
176 {.type = type::Member(type::Wildcard()), .doc =
"<field>"}};
179 void validate(
const hilti::expression::ResolvedOperator& i, position_t p)
const {
180 detail::checkName(i.op0(), i.op1(), p.node);
183 std::string doc()
const {
184 return "Returns true if the unit's field has a value assigned (not counting any ``&default``).";
188 OPERATOR_DECLARE_ONLY(unit, MemberCall)
194 using hilti::expression::ResolvedOperatorBase::ResolvedOperatorBase;
197 Operator(
const type::Unit& stype,
const type::unit::item::Field& f) : _field(f) {
198 auto ftype = f.itemType().as<type::Function>();
199 auto op0 = Operand{.type = stype};
200 auto op1 = Operand{.type = type::Member(f.id())};
201 auto op2 = Operand{.type = type::OperandList::fromParameters(ftype.parameters())};
202 _operands = {op0, op1, op2};
203 _result = ftype.result().type();
206 static Kind kind() {
return Kind::MemberCall; }
207 std::vector<Operand> operands()
const {
return _operands; }
209 bool isLhs()
const {
return false; }
210 void validate(
const hilti::expression::ResolvedOperator& , position_t p)
const {}
211 std::string doc()
const {
return "<dynamic - no doc>"; }
212 std::string docNamespace()
const {
return "<dynamic - no ns>"; }
214 Expression instantiate(
const std::vector<Expression>& operands,
const Meta& meta)
const {
215 auto ops = std::vector<Expression>{operands[0],
219 auto ro = hilti::expression::ResolvedOperator(MemberCall(*
this, ops, meta));
225 type::unit::item::Field _field;
226 std::vector<Operand> _operands;
233 BEGIN_METHOD(unit, Offset)
234 auto signature()
const {
240 Returns the offset of the current location in the input stream relative to the 241 unit's start. If executed from inside a field hook, the offset will represent 242 the first byte that the field has been parsed from. If this method is called 243 before the unit's parsing has begun, it will throw a runtime exception. Once 244 parsing has started, the offset will remain available for the unit's entire 247 Usage of this method requires the unit to be declared with the ``%random-access`` 253 BEGIN_METHOD(unit, Position) 254 auto signature()
const {
260 Returns an iterator to the current position in the unit's input stream. If 261 executed from inside a field hook, the position will represent the first byte 262 that the field has been parsed from. If this method is called before the unit's 263 parsing has begun, it will throw a runtime exception. 265 Usage of this method requires the unit to be declared with the ``%random-access`` 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. 284 Usage of this method requires the unit to be declared with the ``%random-access`` 290 BEGIN_METHOD(unit, SetInput) 291 auto signature()
const {
293 .result = hilti::type::void_,
298 Moves the current parsing position to *i*. The iterator *i* must be into the 299 input of the current unit, or the method will throw a runtime execption. 301 Usage of this method requires the unit to be declared with the ``%random-access`` 307 BEGIN_METHOD(unit, Find) 308 auto signature()
const {
324 Searches a *needle* pattern inside the input region defined by where the unit 325 began parsing and its current parsing position. If executed from inside a field 326 hook, the current parasing position will represent the *first* byte that the 327 field has been parsed from. By default, the search will start at the beginning 328 of that region and scan forward. If the direction is 329 ``spicy::Direcction::Backward``, the search will start at the end of the region 330 and scan backward. In either case, a starting position can also be explicitly 331 given, but must lie inside the same region. 333 Usage of this method requires the unit to be declared with the ``%random-access`` 339 BEGIN_METHOD(unit, ConnectFilter) 340 auto signature()
const {
342 .result = hilti::type::void_,
343 .id =
"connect_filter",
344 .args = {{.id =
"filter",
348 Connects a separate filter unit to transform the unit's input transparently 349 before parsing. The filter unit will see the original input, and this unit will 350 receive everything the filter passes on through ``forward()``. 352 Filters can be connected only before a unit's parsing begins. The latest 353 possible point is from inside the target unit's ``%init`` hook. 358 BEGIN_METHOD(unit, Forward) 359 auto signature()
const {
361 .result = hilti::type::void_,
365 If the unit is connected as a filter to another one, this method forwards 366 transformed input over to that other one to parse. If the unit is not connected, 367 this method will silently discard the data. 372 BEGIN_METHOD(unit, ForwardEod) 373 auto signature()
const {
375 .result = hilti::type::void_,
379 If the unit is connected as a filter to another one, this method signals that 380 other one that end of its input has been reached. If the unit is not connected, 381 this method will not do anything. 386 BEGIN_METHOD(unit, Backtrack) 387 auto signature()
const {
389 .result = hilti::type::void_,
393 Aborts parsing at the current position and returns back to the most recent 394 ``&try`` attribute. Turns into a parse error if there's no ``&try`` in scope. 399 static inline auto contextResult(
bool is_const) {
402 if ( resolved_ops.empty() )
403 return type::DocOnly(
"<context>&");
405 const auto& ctype = resolved_ops[0].type().as<type::Unit>().contextType();
407 return Type(type::StrongReference(*ctype));
411 BEGIN_METHOD(unit, ContextConst)
412 auto signature()
const {
414 .result = contextResult(
true),
418 Returns a reference to the ``%context`` instance associated with the unit. 423 BEGIN_METHOD(unit, ContextNonConst) 424 auto signature()
const {
426 .result = contextResult(
false),
430 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:241
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:240