@@ -80,6 +80,244 @@ inline bool url_pattern_part::is_regexp() const noexcept {
80
80
return type == url_pattern_part_type::REGEXP;
81
81
}
82
82
83
+ namespace url_pattern_helpers {
84
+ inline void constructor_string_parser::rewind () {
85
+ // Set parser’s token index to parser’s component start.
86
+ token_index = component_start;
87
+ // Set parser’s token increment to 0.
88
+ token_increment = 0 ;
89
+ }
90
+
91
+ inline bool constructor_string_parser::is_hash_prefix () {
92
+ // Return the result of running is a non-special pattern char given parser,
93
+ // parser’s token index and "#".
94
+ return is_non_special_pattern_char (token_index, " #" );
95
+ }
96
+
97
+ inline bool constructor_string_parser::is_search_prefix () {
98
+ // If result of running is a non-special pattern char given parser, parser’s
99
+ // token index and "?" is true, then return true.
100
+ if (is_non_special_pattern_char (token_index, " ?" )) {
101
+ return true ;
102
+ }
103
+
104
+ // If parser’s token list[parser’s token index]'s value is not "?", then
105
+ // return false.
106
+ if (token_list[token_index].value != " ?" ) {
107
+ return false ;
108
+ }
109
+
110
+ // If previous index is less than 0, then return true.
111
+ if (token_index == 0 ) return true ;
112
+ // Let previous index be parser’s token index − 1.
113
+ auto previous_index = token_index - 1 ;
114
+ // Let previous token be the result of running get a safe token given parser
115
+ // and previous index.
116
+ auto previous_token = get_safe_token (previous_index);
117
+ // If any of the following are true, then return false:
118
+ // - previous token’s type is "name".
119
+ // - previous token’s type is "regexp".
120
+ // - previous token’s type is "close".
121
+ // - previous token’s type is "asterisk".
122
+ return !(previous_token.type == token_type::NAME ||
123
+ previous_token.type == token_type::REGEXP ||
124
+ previous_token.type == token_type::CLOSE ||
125
+ previous_token.type == token_type::ASTERISK);
126
+ }
127
+
128
+ inline bool constructor_string_parser::is_non_special_pattern_char (
129
+ size_t index, std::string_view value) {
130
+ // Let token be the result of running get a safe token given parser and index.
131
+ auto token = get_safe_token (index );
132
+
133
+ // If token’s value is not value, then return false.
134
+ if (token.value != value) {
135
+ return false ;
136
+ }
137
+
138
+ // If any of the following are true:
139
+ // - token’s type is "char";
140
+ // - token’s type is "escaped-char"; or
141
+ // - token’s type is "invalid-char",
142
+ // - then return true.
143
+ return token.type == token_type::CHAR ||
144
+ token.type == token_type::ESCAPED_CHAR ||
145
+ token.type == token_type::INVALID_CHAR ||
146
+ token.type == token_type::INVALID_CHAR;
147
+ }
148
+
149
+ inline const Token& constructor_string_parser::get_safe_token (size_t index) {
150
+ // If index is less than parser’s token list's size, then return parser’s
151
+ // token list[index].
152
+ if (index < token_list.size ()) [[likely]] {
153
+ return token_list[index ];
154
+ }
155
+
156
+ // Assert: parser’s token list's size is greater than or equal to 1.
157
+ ADA_ASSERT_TRUE (token_list.size () >= 1 );
158
+
159
+ // Let token be parser’s token list[last index].
160
+ // Assert: token’s type is "end".
161
+ ADA_ASSERT_TRUE (token_list.end ()->type == token_type::END);
162
+
163
+ // Return token.
164
+ return *token_list.end ();
165
+ }
166
+
167
+ inline bool constructor_string_parser::is_group_open () const {
168
+ // If parser’s token list[parser’s token index]'s type is "open", then return
169
+ // true.
170
+ return token_list[token_index].type == token_type::OPEN;
171
+ }
172
+
173
+ inline bool constructor_string_parser::is_group_close () const {
174
+ // If parser’s token list[parser’s token index]'s type is "close", then return
175
+ // true.
176
+ return token_list[token_index].type == token_type::CLOSE;
177
+ }
178
+
179
+ inline bool constructor_string_parser::next_is_authority_slashes () {
180
+ // If the result of running is a non-special pattern char given parser,
181
+ // parser’s token index + 1, and "/" is false, then return false.
182
+ if (!is_non_special_pattern_char (token_index + 1 , " /" )) {
183
+ return false ;
184
+ }
185
+ // If the result of running is a non-special pattern char given parser,
186
+ // parser’s token index + 2, and "/" is false, then return false.
187
+ if (!is_non_special_pattern_char (token_index + 2 , " /" )) {
188
+ return false ;
189
+ }
190
+ return true ;
191
+ }
192
+
193
+ inline bool constructor_string_parser::is_protocol_suffix () {
194
+ // Return the result of running is a non-special pattern char given parser,
195
+ // parser’s token index, and ":".
196
+ return is_non_special_pattern_char (token_index, " :" );
197
+ }
198
+
199
+ inline void
200
+ constructor_string_parser::compute_protocol_matches_special_scheme_flag () {
201
+ // Let protocol string be the result of running make a component string given
202
+ // parser.
203
+ auto protocol_string = make_component_string ();
204
+ // Let protocol component be the result of compiling a component given
205
+ // protocol string, canonicalize a protocol, and default options.
206
+ auto protocol_component = url_pattern_component::compile (
207
+ protocol_string, canonicalize_protocol,
208
+ url_pattern_compile_component_options::DEFAULT);
209
+ // If the result of running protocol component matches a special scheme given
210
+ // protocol component is true, then set parser’s protocol matches a special
211
+ // scheme flag to true.
212
+ if (protocol_component_matches_special_scheme (
213
+ protocol_component.get_pattern ())) {
214
+ protocol_matches_a_special_scheme_flag = true ;
215
+ }
216
+ }
217
+
218
+ inline void constructor_string_parser::change_state (State new_state,
219
+ size_t skip) {
220
+ // If parser’s state is not "init", not "authority", and not "done", then set
221
+ // parser’s result[parser’s state] to the result of running make a component
222
+ // string given parser.
223
+ if (state != State::INIT && state != State::AUTHORITY &&
224
+ state != State::DONE) {
225
+ auto value = make_component_string ();
226
+ // TODO: Simplify this.
227
+ switch (state) {
228
+ case State::PROTOCOL: {
229
+ result.protocol = value;
230
+ break ;
231
+ }
232
+ case State::USERNAME: {
233
+ result.username = value;
234
+ break ;
235
+ }
236
+ case State::PASSWORD: {
237
+ result.password = value;
238
+ break ;
239
+ }
240
+ case State::HOSTNAME: {
241
+ result.hostname = value;
242
+ break ;
243
+ }
244
+ case State::PORT: {
245
+ result.port = value;
246
+ break ;
247
+ }
248
+ case State::PATHNAME: {
249
+ result.pathname = value;
250
+ break ;
251
+ }
252
+ case State::SEARCH: {
253
+ result.search = value;
254
+ break ;
255
+ }
256
+ case State::HASH: {
257
+ result.hash = value;
258
+ break ;
259
+ }
260
+ default :
261
+ unreachable ();
262
+ }
263
+ } else if ((state == State::PROTOCOL || state == State::AUTHORITY ||
264
+ state == State::USERNAME || state == State::PASSWORD ||
265
+ state == State::HOSTNAME || state == State::PORT) &&
266
+ (new_state == State::SEARCH || new_state == State::HASH) &&
267
+ !result.pathname .has_value ()) {
268
+ // If parser’s state is "protocol", "authority", "username", "password",
269
+ // "hostname", or "port"; new state is "search" or "hash"; and parser’s
270
+ // result["pathname"] does not exist, then:
271
+ // If parser’s protocol matches a special scheme flag is true, then set
272
+ // parser’s result["pathname"] to "/".
273
+ if (protocol_matches_a_special_scheme_flag) {
274
+ result.pathname = " /" ;
275
+ } else {
276
+ // Otherwise, set parser’s result["pathname"] to the empty string.
277
+ result.pathname = " " ;
278
+ }
279
+ } else if ((state == State::PROTOCOL || state == State::AUTHORITY ||
280
+ state == State::USERNAME || state == State::PASSWORD ||
281
+ state == State::HOSTNAME || state == State::PORT ||
282
+ state == State::PATHNAME) &&
283
+ new_state == State::HASH && !result.search .has_value ()) {
284
+ // If parser’s state is "protocol", "authority", "username", "password",
285
+ // "hostname", "port", or "pathname"; new state is "hash"; and parser’s
286
+ // result["search"] does not exist, then set parser’s result["search"] to
287
+ // the empty string.
288
+ result.search = " " ;
289
+ }
290
+
291
+ // If parser’s state is not "init" and new state is not "done", then:
292
+
293
+ // Set parser’s state to new state.
294
+ state = new_state;
295
+ // Increment parser’s token index by skip.
296
+ token_index += skip;
297
+ // Set parser’s token increment to 0.
298
+ token_increment = 0 ;
299
+ }
300
+
301
+ inline std::string_view constructor_string_parser::make_component_string () {
302
+ // Assert: parser’s token index is less than parser’s token list's size.
303
+ ADA_ASSERT_TRUE (token_index < token_list.size ());
304
+
305
+ // Let token be parser’s token list[parser’s token index].
306
+ const auto token = token_list[token_index];
307
+ // Let component start token be the result of running get a safe token given
308
+ // parser and parser’s component start.
309
+ const auto component_start_token = get_safe_token (component_start);
310
+ // Let component start input index be component start token’s index.
311
+ const auto component_start_input_index = component_start_token.index ;
312
+ // Let end index be token’s index.
313
+ const auto end_index = token.index ;
314
+ // Return the code point substring from component start input index to end
315
+ // index within parser’s input.
316
+ return input.substr (component_start_input_index, end_index);
317
+ }
318
+
319
+ } // namespace url_pattern_helpers
320
+
83
321
} // namespace ada
84
322
85
323
#endif
0 commit comments