Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
164 commits
Select commit Hold shift + click to select a range
80cb760
implement URLPattern skeleton
anonrig Nov 30, 2024
fc4b193
use correct value for clang-format
anonrig Nov 30, 2024
cd9df5e
fix build errors
anonrig Nov 30, 2024
09c3f42
create url_pattern-inl.h
anonrig Nov 30, 2024
6656757
add canonicalize methods
anonrig Dec 4, 2024
686af7d
add ada::parse_url_pattern function
anonrig Dec 4, 2024
3c08805
add more comments
anonrig Dec 4, 2024
66da95c
implement getters
anonrig Dec 4, 2024
8377009
add has_regexp_groups()
anonrig Dec 4, 2024
61f4b67
start implementing tokenizer & tokenize
anonrig Dec 4, 2024
fe3af13
add initial parser_url_pattern method
anonrig Dec 4, 2024
1262f8c
add todos and remove redundant qualifiers
anonrig Dec 4, 2024
20691e3
implement escape pattern
anonrig Dec 4, 2024
eed6d80
add CompileComponentOptions
anonrig Dec 7, 2024
f153e00
minor fixes for add-url-pattern (#800)
lemire Dec 8, 2024
7dbf175
rename commits
anonrig Dec 8, 2024
5f36b46
add more parse_url_pattern
anonrig Dec 9, 2024
4619c9d
rename url_pattern class
anonrig Dec 9, 2024
5cdb6db
complete parse_url_pattern implementation
anonrig Dec 9, 2024
5f28a37
add `_component` suffix to components
anonrig Dec 9, 2024
20d7529
remove unnecessary void
anonrig Dec 9, 2024
16aace3
implement generate regular expression methods
anonrig Dec 10, 2024
14d217c
continue working on parser
anonrig Dec 10, 2024
4a31b3f
fix build error
anonrig Dec 12, 2024
f10d3b2
implement constructor string parser
anonrig Dec 12, 2024
4c20080
implement all of tokenizer's functions
anonrig Dec 12, 2024
74f72fd
fix build errors
anonrig Dec 12, 2024
969c87a
fix warnings
anonrig Dec 12, 2024
6276ce8
complete tokenizer
anonrig Dec 12, 2024
5f02b24
implement escape_regexp_string
anonrig Dec 12, 2024
f55e3f5
implement generate_pattern_string
anonrig Dec 12, 2024
cc73e97
fix compiler warnings
anonrig Dec 12, 2024
ca60161
semi-implement match
anonrig Dec 13, 2024
1a47532
complete one more todo
anonrig Dec 13, 2024
a67fe01
simplify create_component_match_result
anonrig Dec 13, 2024
37dc747
simplify
anonrig Dec 13, 2024
d4d843d
use correct inputs for match/exec/test
anonrig Dec 13, 2024
5c212d7
rename wpt_tests to wpt_url_tests
anonrig Dec 13, 2024
d33f228
add wpt_urlpattern_tests skeleton
anonrig Dec 13, 2024
530deb4
add first test
anonrig Dec 14, 2024
f1e04ce
Build fixes (#801)
lemire Dec 14, 2024
a10ba16
fix 2 bugs
anonrig Dec 14, 2024
b67580d
fix linter issues
anonrig Dec 14, 2024
42d6c32
fix 2 more bugs
anonrig Dec 14, 2024
8d8acb2
more progress on missing features
anonrig Dec 16, 2024
ac0817e
move url_pattern_helpers to separate file
anonrig Dec 16, 2024
8523594
fix build errors
anonrig Dec 16, 2024
096e159
use url_pattern_encoding_callback
anonrig Dec 17, 2024
f711faf
fix url pattern constructor error
anonrig Dec 17, 2024
fc5b020
fix more issues
anonrig Dec 17, 2024
690a14a
add initial version of wpt test runner
anonrig Dec 17, 2024
4f1dc9b
simplify json logic (#802)
lemire Dec 17, 2024
21109d1
add fuzzer
anonrig Dec 17, 2024
8929462
removing the reset
lemire Dec 17, 2024
6759d37
update ada idna
anonrig Dec 18, 2024
e8897d9
use ada idna method for valid name code point
anonrig Dec 18, 2024
4e96bbe
fix add part implementation
anonrig Dec 18, 2024
43c806d
fix invalid access errors
anonrig Dec 18, 2024
029e17f
implement tests correctly
anonrig Dec 18, 2024
c4c373b
improve test runner
anonrig Dec 18, 2024
4b3f34d
add url_pattern_init to_string() method
anonrig Dec 19, 2024
8d4994c
update WPT tests
anonrig Dec 19, 2024
5e6f934
fix last remaining todo
anonrig Dec 19, 2024
71468e2
simplify test runner
anonrig Dec 19, 2024
6a4c9a5
minor fixes
lemire Dec 19, 2024
fd6d1d4
some reworking
lemire Dec 19, 2024
7dca1de
make sure to skip invalid tests
anonrig Dec 19, 2024
6d38085
remove std::ranges::iota due to clang
anonrig Dec 20, 2024
abb2af0
add more fuzzing coverage
anonrig Dec 20, 2024
a0df533
try to fix windows issues
anonrig Dec 20, 2024
aeb4699
remove unnecessary copy
anonrig Dec 20, 2024
1eeab05
start testing the validity of the correct responses
anonrig Dec 20, 2024
208c2ff
fix couple of bugs
anonrig Dec 20, 2024
664ed1c
fix invalid ascii checks
anonrig Dec 20, 2024
60c4015
make pattern generation more verbose
anonrig Dec 20, 2024
5e989f0
fix regex error
anonrig Dec 20, 2024
5539349
remove semicolon due to -Werror,-Wextra-semi
anonrig Dec 20, 2024
04252cd
guarding regex call (#805)
lemire Dec 20, 2024
3eac233
add more logging
anonrig Dec 23, 2024
3f7536c
change ada_idna to char32_t
anonrig Dec 23, 2024
602a565
remove try/catch
anonrig Dec 23, 2024
fc3e76e
make canonicalize_ methods more flexible
anonrig Dec 23, 2024
9407a49
fix change_state
anonrig Dec 23, 2024
6d8e960
fix invalid substr call
anonrig Dec 23, 2024
67fb323
fix generate_pattern_string impl
anonrig Dec 23, 2024
dbd003d
fix more small issues
anonrig Dec 23, 2024
8619179
improve url_pattern_init::process
anonrig Dec 23, 2024
a4f0c42
correctly computing the next code point (#808)
lemire Dec 23, 2024
099fb43
adding checks
lemire Dec 23, 2024
049dd11
use std string view to avoid copy
anonrig Dec 23, 2024
6b29fed
use next_index instead of index
anonrig Dec 23, 2024
61f45be
highlight the error message
anonrig Dec 23, 2024
d2bcf67
better decoding
lemire Dec 23, 2024
e997a28
I think that the test is in error (#810)
lemire Dec 23, 2024
6e96857
remove invalid WPT test data
anonrig Dec 24, 2024
188e171
remove invalid assertion
anonrig Dec 24, 2024
5682bf1
fix ipv6 address canonicalize
anonrig Dec 24, 2024
67f9708
fix canonicalize_ipv6_hostname
anonrig Dec 24, 2024
681bf67
simplify test runner
anonrig Dec 24, 2024
3304dd0
fix test runner
anonrig Dec 24, 2024
40f85e3
add a todo
anonrig Dec 24, 2024
fdb044e
remove invalid test case
anonrig Dec 24, 2024
8ee26f4
add tests for expected object
anonrig Dec 24, 2024
7f4acf2
fix hostname tests
anonrig Dec 25, 2024
505f526
complete match implementation
anonrig Dec 25, 2024
6f284c4
fix empty component tests
anonrig Dec 26, 2024
d928625
revert some wpt changes
anonrig Dec 26, 2024
64c6968
add some optional result logging (#812)
lemire Dec 26, 2024
8090940
lint
lemire Dec 26, 2024
f204a8c
fixing logging
lemire Dec 26, 2024
d7b92eb
removing diagram printout
Dec 27, 2024
fc884cb
fix asan build errors
anonrig Dec 28, 2024
77f44d3
simpler version of the yagiz/add-url-pattern branch (#815)
lemire Dec 28, 2024
ab71fa0
simplify implementation
anonrig Dec 29, 2024
ca66004
improve url_pattern_part emplace_back calls
anonrig Dec 29, 2024
b2d9e70
fix url_pattern_component constructor
anonrig Dec 31, 2024
baeafc6
remove the usage of ada.h inside src
anonrig Dec 31, 2024
487582d
move all helper methods to url_pattern.cpp
anonrig Dec 31, 2024
ffee76c
fix urlpatterntestdata.json
anonrig Dec 31, 2024
0100006
fix build errors
anonrig Dec 31, 2024
757683b
add missing check
anonrig Dec 31, 2024
8dc937e
more tests (#817)
lemire Dec 31, 2024
53ba80f
fix assertion error
anonrig Dec 31, 2024
edbf6c0
don't move function calls
anonrig Dec 31, 2024
5f74dd3
fix token reference asan error
anonrig Dec 31, 2024
a5580c7
another test (#818)
lemire Dec 31, 2024
db7acf9
simplify parser and tests
anonrig Jan 1, 2025
c60c2dc
remove unnecessary duplicate_name method
anonrig Jan 1, 2025
385f554
convert Token to class
anonrig Jan 1, 2025
dab41f6
minor cleanups
anonrig Jan 1, 2025
cf69585
remove invalid std::move
anonrig Jan 1, 2025
bd9655d
simplify parser
anonrig Jan 1, 2025
393f515
remove invalid pathname WPT
anonrig Jan 1, 2025
64f66c6
leave some todos for WPT
anonrig Jan 1, 2025
1f563d4
complete inputs parsing
anonrig Jan 1, 2025
52c33b5
removed duplicated code
anonrig Jan 3, 2025
6ae710b
merge error enums
anonrig Jan 3, 2025
1b59155
fix a boolean operation
anonrig Jan 3, 2025
dd20066
update urlpatterntestdata.json
anonrig Jan 3, 2025
528027c
remove unnecessary assertions
anonrig Jan 3, 2025
65fe0b6
removing GLIBCXX debug
Jan 3, 2025
613d60d
updating macos ci
Jan 3, 2025
943f0aa
indent
Jan 3, 2025
9bb11ad
keeping only static
Jan 3, 2025
5b1de58
improve wpt runner
anonrig Jan 3, 2025
1ec8ea0
fix match
anonrig Jan 3, 2025
c858831
add assertions for object return
anonrig Jan 4, 2025
36a7b72
check __cpp_lib_format
lemire Jan 4, 2025
ff2bf00
adding version header (#824)
lemire Jan 4, 2025
0feb9a6
fix match related bugs
anonrig Jan 5, 2025
57accd5
fix port canonicalize
anonrig Jan 5, 2025
67f9988
fix port setting caused by url parser bug
anonrig Jan 5, 2025
9deaa41
add temporary check for special schemes
anonrig Jan 5, 2025
d47ca13
revert opaque host change
anonrig Jan 6, 2025
14e6c53
fix match when input needs to be parsed
anonrig Jan 6, 2025
6f2838f
fix match hash and search prefix
anonrig Jan 6, 2025
89c8bea
fix internal assertion
anonrig Jan 6, 2025
e3f4fe2
improve wpt test runner
anonrig Jan 6, 2025
8b8d5e6
improve regexp matching
anonrig Jan 7, 2025
a47d8c5
fix wpt testrunner
anonrig Jan 7, 2025
b620b09
fix test implementation
anonrig Jan 7, 2025
36a9097
add half-working match_result
anonrig Jan 7, 2025
87def0a
improve regex matching
anonrig Jan 8, 2025
61728b2
remove invalid WPT test
anonrig Jan 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
more progress on missing features
  • Loading branch information
anonrig committed Jan 8, 2025
commit 8d8acb2e1006183bae91ab243b56225d59350e28
264 changes: 245 additions & 19 deletions include/ada/url_pattern-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,25 +227,6 @@ inline bool constructor_string_parser::is_protocol_suffix() {
return is_non_special_pattern_char(token_index, ":");
}

inline void
constructor_string_parser::compute_protocol_matches_special_scheme_flag() {
// Let protocol string be the result of running make a component string given
// parser.
auto protocol_string = make_component_string();
// Let protocol component be the result of compiling a component given
// protocol string, canonicalize a protocol, and default options.
auto protocol_component = url_pattern_component::compile(
protocol_string, canonicalize_protocol,
url_pattern_compile_component_options::DEFAULT);
// If the result of running protocol component matches a special scheme given
// protocol component is true, then set parser’s protocol matches a special
// scheme flag to true.
if (protocol_component_matches_special_scheme(
protocol_component.get_pattern())) {
protocol_matches_a_special_scheme_flag = true;
}
}

inline void constructor_string_parser::change_state(State new_state,
size_t skip) {
// If parser’s state is not "init", not "authority", and not "done", then set
Expand Down Expand Up @@ -452,8 +433,253 @@ inline bool is_valid_name_code_point(char cp, bool first) {
return true;
}

template <url_pattern_encoding_callback F>
Token* url_pattern_parser<F>::try_consume_modifier_token() {
// Let token be the result of running try to consume a token given parser and
// "other-modifier".
auto token = try_consume_token(token_type::OTHER_MODIFIER);
// If token is not null, then return token.
if (token) return token;
// Set token to the result of running try to consume a token given parser and
// "asterisk".
token = try_consume_token(token_type::ASTERISK);
// Return token.
return token;
}

template <url_pattern_encoding_callback F>
Token* url_pattern_parser<F>::try_consume_regexp_or_wildcard_token(
Token* name_token) {
// Let token be the result of running try to consume a token given parser and
// "regexp".
auto token = try_consume_token(token_type::REGEXP);
// If name token is null and token is null, then set token to the result of
// running try to consume a token given parser and "asterisk".
if (!name_token && !token) {
token = try_consume_token(token_type::ASTERISK);
}
// Return token.
return token;
}

template <url_pattern_encoding_callback F>
Token* url_pattern_parser<F>::try_consume_token(token_type type) {
// Assert: parser’s index is less than parser’s token list size.
ADA_ASSERT_TRUE(index < tokens.size());
// Let next token be parser’s token list[parser’s index].
auto& next_token = tokens.at(index);
// If next token’s type is not type return null.
if (next_token.type != type) return nullptr;
// Increase parser’s index by 1.
index++;
// Return next token.
return &next_token;
}

template <url_pattern_encoding_callback F>
std::string url_pattern_parser<F>::consume_text() {
// Let result be the empty string.
std::string result{};
// While true:
while (true) {
// Let token be the result of running try to consume a token given parser
// and "char".
auto token = try_consume_token(token_type::CHAR);
// If token is null, then set token to the result of running try to consume
// a token given parser and "escaped-char".
if (!token) token = try_consume_token(token_type::ESCAPED_CHAR);
// If token is null, then break.
if (!token) break;
// Append token’s value to the end of result.
result.append(token->value);
}
// Return result.
return result;
}

template <url_pattern_encoding_callback F>
tl::expected<Token, url_pattern_errors>
url_pattern_parser<F>::consume_required_token(token_type type) {
// Let result be the result of running try to consume a token given parser and
// type.
auto result = try_consume_token(type);
// If result is null, then throw a TypeError.
if (!result) {
return tl::unexpected(url_pattern_errors::type_error);
}
return std::move(*result);
}

template <url_pattern_encoding_callback F>
std::optional<url_pattern_errors>
url_pattern_parser<F>::maybe_add_part_from_the_pending_fixed_value() {
// If parser’s pending fixed value is the empty string, then return.
if (pending_fixed_value.empty()) return std::nullopt;
// Let encoded value be the result of running parser’s encoding callback given
// parser’s pending fixed value.
tl::expected<std::string, url_pattern_errors> encoded_value =
encoding_callback(pending_fixed_value);
if (!encoded_value) {
return encoded_value.error();
}
// Set parser’s pending fixed value to the empty string.
pending_fixed_value.clear();
// Let part be a new part whose type is "fixed-text", value is encoded value,
// and modifier is "none".
url_pattern_part part{.type = url_pattern_part_type::FIXED_TEXT,
.value = std::move(encoded_value.value()),
.modifier = url_pattern_part_modifier::NONE};
// Append part to parser’s part list.
parts.push_back(std::move(part));
return std::nullopt;
}

template <url_pattern_encoding_callback F>
std::optional<url_pattern_errors> url_pattern_parser<F>::add_part(
std::string_view prefix, Token* name_token, Token* regexp_or_wildcard_token,
std::string_view suffix, Token* modifier_token) {
// Let modifier be "none".
auto modifier = url_pattern_part_modifier::NONE;
// If modifier token is not null:
if (modifier_token) {
// If modifier token’s value is "?" then set modifier to "optional".
if (modifier_token->value == "?") {
modifier = url_pattern_part_modifier::OPTIONAL;
} else if (modifier_token->value == "*") {
// Otherwise if modifier token’s value is "*" then set modifier to
// "zero-or-more".
modifier = url_pattern_part_modifier::ZERO_OR_MORE;
} else if (modifier_token->value == "+") {
// Otherwise if modifier token’s value is "+" then set modifier to
// "one-or-more".
modifier = url_pattern_part_modifier::ONE_OR_MORE;
}
// If name token is null and regexp or wildcard token is null and modifier
// is "none":
if (!name_token && !regexp_or_wildcard_token &&
modifier == url_pattern_part_modifier::NONE) {
// Append prefix to the end of parser’s pending fixed value.
pending_fixed_value.append(prefix);
return std::nullopt;
}
// Run maybe add a part from the pending fixed value given parser.
if (auto error = maybe_add_part_from_the_pending_fixed_value()) {
return *error;
}
// If name token is null and regexp or wildcard token is null:
if (!name_token && !regexp_or_wildcard_token) {
// Assert: suffix is the empty string.
ADA_ASSERT_TRUE(suffix.empty());
// If prefix is the empty string, then return.
if (prefix.empty()) return std::nullopt;
// Let encoded value be the result of running parser’s encoding callback
// given prefix.
auto encoded_value = encoding_callback(prefix);
if (!encoded_value) {
return encoded_value.error();
}
// Let part be a new part whose type is "fixed-text", value is encoded
// value, and modifier is modifier.
url_pattern_part part{.type = url_pattern_part_type::FIXED_TEXT,
.value = std::move(*encoded_value),
.modifier = modifier};
// Append part to parser’s part list.
parts.push_back(std::move(part));
return std::nullopt;
}
// Let regexp value be the empty string.
std::string regexp_value{};
// If regexp or wildcard token is null, then set regexp value to parser’s
// segment wildcard regexp.
if (!regexp_or_wildcard_token) {
regexp_value = segment_wildcard_regexp;
} else if (regexp_or_wildcard_token->type == token_type::ASTERISK) {
// Otherwise if regexp or wildcard token’s type is "asterisk", then set
// regexp value to the full wildcard regexp value.
regexp_value = ".*";
} else {
// Otherwise set regexp value to regexp or wildcard token’s value.
regexp_value = regexp_or_wildcard_token->value;
}
// Let type be "regexp".
auto type = url_pattern_part_type::REGEXP;
// If regexp value is parser’s segment wildcard regexp:
if (regexp_value == segment_wildcard_regexp) {
// Set type to "segment-wildcard".
type = url_pattern_part_type::SEGMENT_WILDCARD;
// Set regexp value to the empty string.
regexp_value.clear();
} else if (regexp_value == ".*") {
// Otherwise if regexp value is the full wildcard regexp value:
// Set type to "full-wildcard".
type = url_pattern_part_type::FULL_WILDCARD;
// Set regexp value to the empty string.
regexp_value.clear();
}
// Let name be the empty string.
std::string name{};
// If name token is not null, then set name to name token’s value.
if (name_token) {
name = name_token->value;
} else if (regexp_or_wildcard_token != nullptr) {
// Otherwise if regexp or wildcard token is not null:
// Set name to parser’s next numeric name, serialized.
// TODO: Implement this
// Increment parser’s next numeric name by 1.
next_numeric_name++;
}
// If the result of running is a duplicate name given parser and name is
// true, then throw a TypeError.
if (is_duplicate_name(name)) {
return url_pattern_errors::type_error;
}
// Let encoded prefix be the result of running parser’s encoding callback
// given prefix.
auto encoded_prefix = encoding_callback(prefix);
if (!encoded_prefix) return encoded_prefix.error();
// Let encoded suffix be the result of running parser’s encoding callback
// given suffix.
auto encoded_suffix = encoding_callback(suffix);
if (!encoded_suffix) return encoded_suffix.error();
// Let part be a new part whose type is type, value is regexp value,
// modifier is modifier, name is name, prefix is encoded prefix, and suffix
// is encoded suffix.
auto part = url_pattern_part{.type = type,
.value = std::move(regexp_value),
.modifier = modifier,
.prefix = std::move(*encoded_prefix),
.suffix = std::move(*encoded_suffix)};
// Append part to parser’s part list.
parts.emplace_back(std::move(part));
}
return std::nullopt;
}

template <url_pattern_encoding_callback F>
bool url_pattern_parser<F>::is_duplicate_name(std::string_view name) {
// For each part of parser’s part list:
// If part’s name is name, then return true.
return std::ranges::any_of(
parts, [&name](const auto& part) { return part.name == name; });
}

} // namespace url_pattern_helpers

inline std::string_view url_pattern_compile_component_options::get_delimiter()
const {
if (delimiter) {
return {&delimiter.value(), 1};
}
return {};
}

inline std::string_view url_pattern_compile_component_options::get_prefix()
const {
if (prefix) {
return {&prefix.value(), 1};
}
return {};
}
} // namespace ada

#endif
60 changes: 54 additions & 6 deletions include/ada/url_pattern.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,16 +152,21 @@ struct url_pattern_compile_component_options {
std::optional<char> new_prefix = std::nullopt)
: delimiter(new_delimiter), prefix(new_prefix){};

// @see https://urlpattern.spec.whatwg.org/#options-delimiter-code-point
std::optional<char> delimiter{};
// @see https://urlpattern.spec.whatwg.org/#options-prefix-code-point
std::optional<char> prefix{};
std::string_view get_delimiter() const ada_warn_unused;
std::string_view get_prefix() const ada_warn_unused;

// @see https://urlpattern.spec.whatwg.org/#options-ignore-case
bool ignore_case = false;

static url_pattern_compile_component_options DEFAULT;
static url_pattern_compile_component_options HOSTNAME;
static url_pattern_compile_component_options PATHNAME;

private:
// @see https://urlpattern.spec.whatwg.org/#options-delimiter-code-point
std::optional<char> delimiter{};
// @see https://urlpattern.spec.whatwg.org/#options-prefix-code-point
std::optional<char> prefix{};
};

// A struct providing the URLPattern matching results for a single
Expand Down Expand Up @@ -190,7 +195,7 @@ class url_pattern_component {

// @see https://urlpattern.spec.whatwg.org/#compile-a-component
template <url_pattern_encoding_callback F>
static url_pattern_component compile(
static tl::expected<url_pattern_component, url_pattern_errors> compile(
std::string_view input, F encoding_callback,
url_pattern_compile_component_options& options);

Expand Down Expand Up @@ -340,6 +345,48 @@ struct Token {
std::string value{};
};

// @see https://urlpattern.spec.whatwg.org/#pattern-parser
template <url_pattern_encoding_callback F>
class url_pattern_parser {
public:
url_pattern_parser(F encoding_callback_,
std::string_view segment_wildcard_regexp_)
: encoding_callback(encoding_callback_),
segment_wildcard_regexp(std::string(segment_wildcard_regexp_)) {}

// @see https://urlpattern.spec.whatwg.org/#try-to-consume-a-token
Token* try_consume_token(token_type type);
// @see https://urlpattern.spec.whatwg.org/#try-to-consume-a-modifier-token
Token* try_consume_modifier_token();
// @see
// https://urlpattern.spec.whatwg.org/#try-to-consume-a-regexp-or-wildcard-token
Token* try_consume_regexp_or_wildcard_token(Token* name_token);
// @see https://urlpattern.spec.whatwg.org/#consume-text
std::string consume_text();
// @see https://urlpattern.spec.whatwg.org/#consume-a-required-token
tl::expected<Token, url_pattern_errors> consume_required_token(
token_type type);
// @see
// https://urlpattern.spec.whatwg.org/#maybe-add-a-part-from-the-pending-fixed-value
std::optional<url_pattern_errors>
maybe_add_part_from_the_pending_fixed_value() ada_warn_unused;
// @see https://urlpattern.spec.whatwg.org/#add-a-part
std::optional<url_pattern_errors> add_part(
std::string_view prefix, Token* name_token,
Token* regexp_or_wildcard_token, std::string_view suyffix,
Token* modifier_token) ada_warn_unused;
// @see https://urlpattern.spec.whatwg.org/#is-a-duplicate-name
bool is_duplicate_name(std::string_view name);

std::vector<Token> tokens{};
F encoding_callback;
std::string segment_wildcard_regexp;
std::vector<url_pattern_part> parts{};
std::string pending_fixed_value{};
size_t index = 0;
size_t next_numeric_name = 0;
};

// @see https://urlpattern.spec.whatwg.org/#tokenizer
class Tokenizer {
public:
Expand Down Expand Up @@ -427,7 +474,8 @@ struct constructor_string_parser {

// @see
// https://urlpattern.spec.whatwg.org/#compute-protocol-matches-a-special-scheme-flag
void compute_protocol_matches_special_scheme_flag();
std::optional<url_pattern_errors>
compute_protocol_matches_special_scheme_flag();

// @see https://urlpattern.spec.whatwg.org/#next-is-authority-slashes
bool next_is_authority_slashes();
Expand Down
Loading