Spicy
stream.h
1 // Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <hilti/ast/expressions/id.h>
6 #include <hilti/ast/operators/common.h>
7 #include <hilti/ast/types/bool.h>
8 #include <hilti/ast/types/bytes.h>
9 #include <hilti/ast/types/integer.h>
10 #include <hilti/ast/types/stream.h>
11 
12 namespace hilti {
13 namespace operator_ {
14 
15 // stream::Iterator
16 
17 STANDARD_OPERATOR_1(stream::iterator, Deref, type::UnsignedInteger(64), type::constant(type::stream::Iterator()),
18  "Returns the character the iterator is pointing to.");
19 STANDARD_OPERATOR_1(stream::iterator, IncrPostfix, type::stream::Iterator(), type::stream::Iterator(),
20  "Advances the iterator by one byte, returning the previous position.");
21 STANDARD_OPERATOR_1(stream::iterator, IncrPrefix, type::stream::Iterator(), type::stream::Iterator(),
22  "Advances the iterator by one byte, returning the new position.");
23 
24 STANDARD_OPERATOR_2(
25  stream::iterator, Equal, type::Bool(), type::constant(type::stream::Iterator()),
26  type::constant(type::stream::Iterator()),
27  "Compares the two positions. The result is undefined if they are not referring to the same stream value.");
28 STANDARD_OPERATOR_2(
29  stream::iterator, Unequal, type::Bool(), type::constant(type::stream::Iterator()),
30  type::constant(type::stream::Iterator()),
31  "Compares the two positions. The result is undefined if they are not referring to the same stream value.");
32 STANDARD_OPERATOR_2(
33  stream::iterator, Lower, type::Bool(), type::constant(type::stream::Iterator()),
34  type::constant(type::stream::Iterator()),
35  "Compares the two positions. The result is undefined if they are not referring to the same stream value.");
36 STANDARD_OPERATOR_2(
37  stream::iterator, LowerEqual, type::Bool(), type::constant(type::stream::Iterator()),
38  type::constant(type::stream::Iterator()),
39  "Compares the two positions. The result is undefined if they are not referring to the same stream value.");
40 STANDARD_OPERATOR_2(
41  stream::iterator, Greater, type::Bool(), type::constant(type::stream::Iterator()),
42  type::constant(type::stream::Iterator()),
43  "Compares the two positions. The result is undefined if they are not referring to the same stream value.");
44 STANDARD_OPERATOR_2(
45  stream::iterator, GreaterEqual, type::Bool(), type::constant(type::stream::Iterator()),
46  type::constant(type::stream::Iterator()),
47  "Compares the two positions. The result is undefined if they are not referring to the same stream value.");
48 STANDARD_OPERATOR_2(
49  stream::iterator, Difference, type::SignedInteger(64), type::constant(type::stream::Iterator()),
50  type::constant(type::stream::Iterator()),
51  "Returns the number of stream between the two iterators. The result will be negative if the second iterator points "
52  "to a location before the first. The result is undefined if the iterators do not refer to the same stream "
53  "instance.");
54 STANDARD_OPERATOR_2(stream::iterator, Sum, type::stream::Iterator(), type::constant(type::stream::Iterator()),
55  type::UnsignedInteger(64), "Advances the iterator by the given number of stream.")
56 STANDARD_OPERATOR_2(stream::iterator, SumAssign, type::stream::Iterator(), type::stream::Iterator(),
57  type::UnsignedInteger(64), "Advances the iterator by the given number of stream.")
58 
59 BEGIN_METHOD(stream::iterator, Offset)
60  auto signature() const {
61  return Signature{.self = type::constant(type::stream::Iterator()),
62  .result = type::UnsignedInteger(64),
63  .id = "offset",
64  .args = {},
65  .doc = R"(
66 Returns the offset of the byte that the iterator refers to relative to the
67 beginning of the underlying stream value.
68 )"};
69  }
70 END_METHOD
71 
72 BEGIN_METHOD(stream::iterator, IsFrozen)
73  auto signature() const {
74  return Signature{.self = type::constant(type::stream::Iterator()),
75  .result = type::Bool(),
76  .id = "is_frozen",
77  .args = {},
78  .doc = R"(
79 Returns whether the stream value that the iterator refers to has been frozen.
80 )"};
81  }
82 END_METHOD
83 
84 // stream::View
85 
86 STANDARD_OPERATOR_1(stream::view, Size, type::UnsignedInteger(64), type::constant(type::stream::View()),
87  "Returns the number of stream the view contains.");
88 STANDARD_OPERATOR_2x(stream::view, InBytes, In, type::Bool(), type::constant(type::stream::View()),
89  type::constant(type::Bytes()),
90  "Returns true if the right-hand-side view contains the left-hand-side bytes as a subsequence.");
91 STANDARD_OPERATOR_2x(stream::view, InView, In, type::Bool(), type::constant(type::Bytes()),
92  type::constant(type::stream::View()),
93  "Returns true if the right-hand-side bytes contains the left-hand-side view as a subsequence.");
94 STANDARD_OPERATOR_2x(stream::view, EqualView, Equal, type::Bool(), type::constant(type::stream::View()),
95  type::constant(type::stream::View()), "Compares the views lexicographically.");
96 STANDARD_OPERATOR_2x(stream::view, EqualBytes, Equal, type::Bool(), type::constant(type::stream::View()),
97  type::constant(type::Bytes()), "Compares a stream view and a bytes intances lexicographically.");
98 STANDARD_OPERATOR_2x(stream::view, UnequalView, Unequal, type::Bool(), type::constant(type::stream::View()),
99  type::constant(type::stream::View()), "Compares two views lexicographically.");
100 STANDARD_OPERATOR_2x(stream::view, UnequalBytes, Unequal, type::Bool(), type::constant(type::stream::View()),
101  type::constant(type::Bytes()), "Compares a stream view and a bytes instance lexicographically.");
102 
103 BEGIN_METHOD(stream::view, Offset)
104  auto signature() const {
105  return Signature{.self = type::constant(type::stream::View()),
106  .result = type::UnsignedInteger(64),
107  .id = "offset",
108  .args = {},
109  .doc = R"(
110 Returns the offset of the view's starting position within the associated stream value.
111 )"};
112  }
113 END_METHOD
114 
115 BEGIN_METHOD(stream::view, AdvanceBy)
116  auto signature() const {
117  return Signature{.self = type::constant(type::stream::View()),
118  .result = type::stream::View(),
119  .id = "advance",
120  .args = {{.id = "i", .type = type::stream::Iterator()}},
121  .doc = R"(
122 Advances the view's starting position to a given iterator *i*, returning the new
123 view. The iterator must be referring to the same stream values as the view, and
124 it must be equal or ahead of the view's starting position.
125 )"};
126  }
127 END_METHOD
128 
129 BEGIN_METHOD(stream::view, Limit)
130  auto signature() const {
131  return Signature{.self = type::constant(type::stream::View()),
132  .result = type::stream::View(),
133  .id = "limit",
134  .args = {{.id = "i", .type = type::UnsignedInteger(64)}},
135  .doc = R"(
136 Returns a new view that keeps the current start but cuts off the end *i*
137 characters from that beginning. The returned view will not be able to expand any
138 further.
139 )"};
140  }
141 END_METHOD
142 
143 BEGIN_METHOD(stream::view, AdvanceTo)
144  auto signature() const {
145  return Signature{.self = type::constant(type::stream::View()),
146  .result = type::stream::View(),
147  .id = "advance",
148  .args = {{.id = "i", .type = type::UnsignedInteger(64)}},
149  .doc = R"(
150 Advances the view's starting position by *i* stream, returning the new view.
151 )"};
152  }
153 END_METHOD
154 
155 BEGIN_METHOD(stream::view, Find)
156  auto signature() const {
157  return Signature{.self = type::constant(type::stream::View()),
158  .result = type::Tuple({type::Bool(), type::stream::Iterator()}),
159  .id = "find",
160  .args = {{.id = "needle", .type = type::constant(type::Bytes())}},
161  .doc = R"(
162 Searches *needle* inside the view's content. Returns a tuple of a boolean and an
163 iterator. If *needle* was found, the boolean will be true and the iterator will point
164 to its first occurance. If *needle* was not found, the boolean will be false and
165 the iterator will point to the last position so that everything before that is
166 guaranteed to not contain even a partial match of *needle* (in other words: one can
167 trim until that position and then restart the search from there if more data
168 gets appended to the underlying stream value). Note that for a simple yes/no result,
169 you should use the ``in`` operator instead of this method, as it's more efficient.
170 )"};
171  }
172 END_METHOD
173 
174 BEGIN_METHOD(stream::view, At)
175  auto signature() const {
176  return Signature{.self = type::constant(type::stream::View()),
177  .result = type::stream::Iterator(),
178  .id = "at",
179  .args = {{.id = "i", .type = type::UnsignedInteger(64)}},
180  .doc = R"(
181 Returns an iterator representing the offset *i* inside the view.
182 )"};
183  }
184 END_METHOD
185 
186 BEGIN_METHOD(stream::view, StartsWith)
187  auto signature() const {
188  return Signature{.self = type::constant(type::stream::View()),
189  .result = type::Bool(),
190  .id = "starts_with",
191  .args = {{.id = "b", .type = type::constant(type::Bytes())}},
192  .doc = R"(
193 Returns true if the view starts with *b*.
194 )"};
195  }
196 END_METHOD
197 
198 BEGIN_METHOD(stream::view, SubIterators)
199  auto signature() const {
200  return Signature{.self = type::constant(type::stream::View()),
201  .result = type::stream::View(),
202  .id = "sub",
203  .args = {{.id = "begin", .type = type::stream::Iterator()},
204  {.id = "end", .type = type::stream::Iterator()}},
205  .doc = R"(
206 Returns a new view of the subsequence from *begin* up to (but not including)
207 *end*.
208 )"};
209  }
210 END_METHOD
211 
212 BEGIN_METHOD(stream::view, SubIterator)
213  auto signature() const {
214  return Signature{.self = type::constant(type::stream::View()),
215  .result = type::stream::View(),
216  .id = "sub",
217  .args = {{.id = "end", .type = type::stream::Iterator()}},
218  .doc = R"(
219 Returns a new view of the subsequence from the beginning of the stream up to
220 (but not including) *end*.
221 )"};
222  }
223 END_METHOD
224 
225 BEGIN_METHOD(stream::view, SubOffsets)
226  auto signature() const {
227  return Signature{.self = type::constant(type::stream::View()),
228  .result = type::stream::View(),
229  .id = "sub",
230  .args = {{.id = "begin", .type = type::UnsignedInteger(64)},
231  {.id = "end", .type = type::UnsignedInteger(64)}},
232  .doc = R"(
233 Returns a new view of the subsequence from offset *begin* to (but not including)
234 offset *end*. The offsets are relative to the beginning of the view.
235 )"};
236  }
237 END_METHOD
238 
239 // Stream
240 
241 STANDARD_OPERATOR_1(stream, Size, type::UnsignedInteger(64), type::constant(type::Stream()),
242  "Returns the number of stream the value contains.");
243 STANDARD_OPERATOR_2(stream, Unequal, type::Bool(), type::constant(type::Stream()), type::constant(type::Stream()),
244  "Compares two stream values lexicographically.");
245 STANDARD_OPERATOR_2x(stream, SumAssignView, SumAssign, type::Stream(), type::Stream(),
246  type::constant(type::stream::View()), "Concatenates another stream's view to the target stream.");
247 STANDARD_OPERATOR_2x(stream, SumAssignBytes, SumAssign, type::Stream(), type::Stream(), type::constant(type::Bytes()),
248  "Concatenates data to the stream.");
249 
250 BEGIN_METHOD(stream, Freeze)
251  auto signature() const {
252  return Signature{.self = type::Stream(), .result = type::void_, .id = "freeze", .args = {}, .doc = R"(
253 Freezes the stream value. Once frozen, one cannot append any more data to a
254 frozen stream value (unless it gets unfrozen first). If the value is
255 already frozen, the operation does not change anything.
256 )"};
257  }
258 END_METHOD
259 
260 BEGIN_METHOD(stream, Unfreeze)
261  auto signature() const {
262  return Signature{.self = type::Stream(), .result = type::void_, .id = "unfreeze", .args = {}, .doc = R"(
263 Unfreezes the stream value. A unfrozen stream value can be further modified. If
264 the value is already unfrozen (which is the default), the operation does not
265 change anything.
266 )"};
267  }
268 END_METHOD
269 
270 BEGIN_METHOD(stream, IsFrozen)
271  auto signature() const {
272  return Signature{.self = type::constant(type::Stream()),
273  .result = type::Bool(),
274  .id = "is_frozen",
275  .args = {},
276  .doc = R"(
277 Returns true if the stream value has been frozen.
278 )"};
279  }
280 END_METHOD
281 
282 BEGIN_METHOD(stream, At)
283  auto signature() const {
284  return Signature{.self = type::constant(type::Stream()),
285  .result = type::stream::Iterator(),
286  .id = "at",
287  .args = {{.id = "i", .type = type::UnsignedInteger(64)}},
288  .doc = R"(
289 Returns an iterator representing the offset *i* inside the stream value.
290 )"};
291  }
292 END_METHOD
293 
294 BEGIN_METHOD(stream, Trim)
295  auto signature() const {
296  return Signature{.self = type::Stream(),
297  .result = type::void_,
298  .id = "trim",
299  .args = {{.id = "i", .type = type::stream::Iterator()}},
300  .doc = R"(
301 Trims the stream value by removing all data from its beginning up to (but not
302 including) the position *i*. The iterator *i* will remain valid afterwards and
303 will still point to the same location, which will now be the beginning of the stream's
304 value. All existing iterators pointing to *i* or beyond will remain valid and keep
305 their offsets as well. The effect of this operation is undefined if *i* does not
306 actually refer to a location inside the stream value. Trimming is permitted
307 even on frozen values.
308 )"};
309  }
310 END_METHOD
311 
312 } // namespace operator_
313 } // namespace hilti