//
// Copyright (c) 2023 Alan de Freitas (alandefreitas@gmail.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/url
//

= Compound Rules

The rules shown so far have defined
https://en.wikipedia.org/wiki/Terminal_and_nonterminal_symbols[__terminal symbols__,window=blank_], representing indivisible units of grammar.
To parse more complex things, a
https://en.wikipedia.org/wiki/Parser_combinator[__parser combinator__,window=blank_]
(or __compound rule__) is a rule which accepts as parameters one or more rules and combines them to form a higher order algorithm.
In this section we introduce the compound rules provided by the library, and how they may be used to express more complex grammars.

== Tuple Rule

Consider the following grammar:

[source,cpp]
----
version = "v" dec-octet "." dec-octet
----

We can express this using cpp:tuple_rule[], which matches one or more specified rules in sequence.
The folllowing defines a sequence using some character literals and two decimal octets, which is a fancy way of saying a number between 0 and 255:

[source,cpp]
----
include::example$unit/doc_grammar.cpp[tag=code_grammar_3_1,indent=0]
----

This rule has a value type of cpp:std::tuple[], whose types correspond to the value type of each rule specified upon construction.
The decimal octets are represented by the cpp:grammar::dec_octet_rule[dec_octet_rule] which stores its result in an cpp:unsigned char[]:

[source,cpp]
----
include::example$unit/doc_grammar.cpp[tag=code_grammar_3_2,indent=0]
----

To extract elements from cpp:std::tuple[] the function cpp:std::get[]
must be used.
In this case, we don't care to know the value for the matching character literals.
The cpp:tuple_rule[] discards match results whose value type is cpp:void[].
We can use the cpp:grammar::squelch[squelch]
compound rule to convert a matching value type to cpp:void[], and reformulate our rule:

[source,cpp]
----
include::example$unit/doc_grammar.cpp[tag=code_grammar_3_3,indent=0]
----

When all but one of the value types is cpp:void[], the cpp:std::tuple[] is elided and the remaining value type is promoted to the result of the match:

[source,cpp]
----
include::example$unit/doc_grammar.cpp[tag=code_grammar_3_4,indent=0]
----

== Optional Rule

BNF elements in brackets denote optional components.
These are expressed using cpp:grammar::optional_rule[optional_rule], whose value type is an
cpp:optional[].
For example, we can adapt the port rule from above to be an optional component:

[source,cpp]
----
include::example$unit/doc_grammar.cpp[tag=code_grammar_3_5,indent=0]
----

In this example we build up a rule to represent an endpoint as an IPv4 address with an optional port:

[source,cpp]
----
include::example$unit/doc_grammar.cpp[tag=code_grammar_3_6,indent=0]
----

This can be simplified; the library provides cpp:ipv4_address_rule[]
whose result type is cpp:ipv4_address[], offering more utility than representing the address simply as a collection of four numbers:

[source,cpp]
----
include::example$unit/doc_grammar.cpp[tag=code_grammar_3_7,indent=0]
----

== Variant Rule

BNF elements separated by unquoted slashes represent a set of alternatives from which one element may match.
We represent them using cpp:variant_rule[], whose value type is a variant.
Consider the following HTTP production rule which comes from
https://datatracker.ietf.org/doc/html/rfc7230#section-5.3"[rfc7230,window=blank_]:

[source,cpp]
----
request-target = origin-form
                / absolute-form
                / authority-form
                / asterisk-form
----

The __request-target__ can be exactly one of these things.
Here we define the rule, using cpp:origin_form_rule[], cpp:absolute_uri_rule[], and cpp:authority_rule[] which come with the library, and obtain a result from parsing a string:

[source,cpp]
----
include::example$unit/doc_grammar.cpp[tag=code_grammar_3_8,indent=0]
----

In the next section we discuss facilities to parse a repeating number of elements.




