mirror of
https://github.com/boostorg/parser.git
synced 2026-01-19 16:32:13 +00:00
Compare commits
40 Commits
boost-1.89
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c54307b95c | ||
|
|
5b3f122aa7 | ||
|
|
6db68bc7f7 | ||
|
|
00fe33d2f3 | ||
|
|
bb183cf5ee | ||
|
|
885595f7bd | ||
|
|
6826f957a1 | ||
|
|
647cec6683 | ||
|
|
c2ddd6e116 | ||
|
|
f7246de9db | ||
|
|
703a8afafe | ||
|
|
0eacce6080 | ||
|
|
5e61ba4e9e | ||
|
|
dc6144eeb4 | ||
|
|
d873d7ea80 | ||
|
|
1f5303c756 | ||
|
|
41e891dc95 | ||
|
|
159472ac6e | ||
|
|
bfa3e33372 | ||
|
|
8d7a64f7fe | ||
|
|
8c23054e07 | ||
|
|
11a5d9a872 | ||
|
|
d241bd7853 | ||
|
|
086241cbd9 | ||
|
|
e3a3cc8bf2 | ||
|
|
f789199743 | ||
|
|
f20c4cfb02 | ||
|
|
fcbc53ddce | ||
|
|
fed0a883ad | ||
|
|
bfc61fa963 | ||
|
|
68c306bf66 | ||
|
|
d5d080b9f2 | ||
|
|
03341ba32d | ||
|
|
7e69b27d7c | ||
|
|
17d76bc158 | ||
|
|
050b9ba800 | ||
|
|
125f12407b | ||
|
|
e4ba7c7a17 | ||
|
|
9a138a20f6 | ||
|
|
c32d594d64 |
@@ -1,4 +1,4 @@
|
||||
name: macos-13 - Clang 14
|
||||
name: macos-15 - Clang
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -14,9 +14,9 @@ jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
cxx_std: [17]
|
||||
cxx_std: [17, 20]
|
||||
|
||||
runs-on: macos-13
|
||||
runs-on: macos-15
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
4
.github/workflows/ubuntu.yml
vendored
4
.github/workflows/ubuntu.yml
vendored
@@ -18,10 +18,6 @@ jobs:
|
||||
compiler_version: [g++-10, g++-11]
|
||||
cxx_std: [17, 20]
|
||||
os: [ubuntu-22.04]
|
||||
include:
|
||||
- compiler_version: g++-9
|
||||
cxx_std: 17
|
||||
os: ubuntu-20.04
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
|
||||
@@ -562,7 +562,7 @@
|
||||
<constructor><parameter name="p"><paramtype>parser_type</paramtype></parameter><parameter name="gs"><paramtype>global_state_type</paramtype></parameter><parameter name="eh"><paramtype>error_handler_type</paramtype></parameter></constructor>
|
||||
</struct><struct name="perm_parser"><template>
|
||||
<template-type-parameter name="ParserTuple"/>
|
||||
</template><description><para>Applies each parsers in <computeroutput>ParserTuple</computeroutput>, an any order, stopping after all of them have matched the input. The parse succeeds iff all the parsers match, regardless of the order in which they do. The attribute produced is a <computeroutput>parser::tuple</computeroutput> containing the attributes of the subparsers, in their order of the parsers' appearance in <computeroutput>ParserTuple</computeroutput>, not the order of the parsers' matches. It is an error to specialize <computeroutput><classname alt="boost::parser::perm_parser">perm_parser</classname></computeroutput> with a <computeroutput>ParserTuple</computeroutput> template parameter that includes an <computeroutput><classname alt="boost::parser::eps_parser">eps_parser</classname></computeroutput>. </para></description><data-member name="parsers_"><type><classname>ParserTuple</classname></type></data-member>
|
||||
</template><description><para>Applies each parsers in <computeroutput>ParserTuple</computeroutput>, in any order, stopping after all of them have matched the input. The parse succeeds iff all the parsers match, regardless of the order in which they do. The attribute produced is a <computeroutput>parser::tuple</computeroutput> containing the attributes of the subparsers, in their order of the parsers' appearance in <computeroutput>ParserTuple</computeroutput>, not the order of the parsers' matches. It is an error to specialize <computeroutput><classname alt="boost::parser::perm_parser">perm_parser</classname></computeroutput> with a <computeroutput>ParserTuple</computeroutput> template parameter that includes an <computeroutput><classname alt="boost::parser::eps_parser">eps_parser</classname></computeroutput>. </para></description><data-member name="parsers_"><type><classname>ParserTuple</classname></type></data-member>
|
||||
<method-group name="public member functions">
|
||||
<method name="call" cv="const"><type><classname>auto</classname></type><template>
|
||||
<template-type-parameter name="Iter"/>
|
||||
@@ -597,7 +597,7 @@
|
||||
<method name="parser_interface"><type><classname>constexpr</classname> <classname>quoted_string_parser</classname>() <classname>return</classname></type><parameter name=""><paramtype><classname>quoted_string_parser</classname>(std::move(<classname>x</classname>))</paramtype></parameter></method>
|
||||
<method name="operator()" cv="const noexcept"><type><classname>constexpr</classname> <classname>auto</classname></type><template>
|
||||
<template-nontype-parameter name="R"><type><classname>parsable_range_like</classname></type></template-nontype-parameter>
|
||||
</template><parameter name="r"><paramtype><classname>R</classname> &&</paramtype></parameter><description><para>Returns a <computeroutput><classname alt="boost::parser::parser_interface">parser_interface</classname></computeroutput> containing a <computeroutput><classname alt="boost::parser::quoted_string_parser">quoted_string_parser</classname></computeroutput> that accepts any of the values in <computeroutput>r</computeroutput> as its quotation marks. If the input being matched during the parse is a a sequence of <computeroutput>char32_t</computeroutput>, the elements of <computeroutput>r</computeroutput> are transcoded from their presumed encoding to UTF-32 during the comparison. Otherwise, the character begin matched is directly compared to the elements of <computeroutput>r</computeroutput>. </para></description></method>
|
||||
</template><parameter name="r"><paramtype><classname>R</classname> &&</paramtype></parameter><description><para>Returns a <computeroutput><classname alt="boost::parser::parser_interface">parser_interface</classname></computeroutput> containing a <computeroutput><classname alt="boost::parser::quoted_string_parser">quoted_string_parser</classname></computeroutput> that accepts any of the values in <computeroutput>r</computeroutput> as its quotation marks. If the input being matched during the parse is a sequence of <computeroutput>char32_t</computeroutput>, the elements of <computeroutput>r</computeroutput> are transcoded from their presumed encoding to UTF-32 during the comparison. Otherwise, the character begin matched is directly compared to the elements of <computeroutput>r</computeroutput>. </para></description></method>
|
||||
<method name="operator()" cv="const noexcept"><type><classname>auto</classname></type><template>
|
||||
<template-type-parameter name="T"/>
|
||||
<template-type-parameter name="U"/>
|
||||
@@ -605,7 +605,7 @@
|
||||
<method name="operator()" cv="const noexcept"><type><classname>auto</classname></type><template>
|
||||
<template-nontype-parameter name="R"><type><classname>parsable_range_like</classname></type></template-nontype-parameter>
|
||||
<template-type-parameter name="T"/>
|
||||
</template><parameter name="r"><paramtype><classname>R</classname> &&</paramtype></parameter><parameter name="escapes"><paramtype><classname>symbols</classname>< <classname>T</classname> > <classname>const</classname> &</paramtype></parameter><description><para>Returns a <computeroutput><classname alt="boost::parser::parser_interface">parser_interface</classname></computeroutput> containing a <computeroutput><classname alt="boost::parser::quoted_string_parser">quoted_string_parser</classname></computeroutput> that accepts any of the values in <computeroutput>r</computeroutput> as its quotation marks. If the input being matched during the parse is a a sequence of <computeroutput>char32_t</computeroutput>, the elements of <computeroutput>r</computeroutput> are transcoded from their presumed encoding to UTF-32 during the comparison. Otherwise, the character begin matched is directly compared to the elements of <computeroutput>r</computeroutput>. <computeroutput>symbols</computeroutput> provides a list of strings that may appear after a backslash to form an escape sequence, and what character(s) each escape sequence represents. Note that <computeroutput>"\\"</tt> and <tt>"\ch"</computeroutput> are always valid escape sequences. </para></description></method>
|
||||
</template><parameter name="r"><paramtype><classname>R</classname> &&</paramtype></parameter><parameter name="escapes"><paramtype><classname>symbols</classname>< <classname>T</classname> > <classname>const</classname> &</paramtype></parameter><description><para>Returns a <computeroutput><classname alt="boost::parser::parser_interface">parser_interface</classname></computeroutput> containing a <computeroutput><classname alt="boost::parser::quoted_string_parser">quoted_string_parser</classname></computeroutput> that accepts any of the values in <computeroutput>r</computeroutput> as its quotation marks. If the input being matched during the parse is a sequence of <computeroutput>char32_t</computeroutput>, the elements of <computeroutput>r</computeroutput> are transcoded from their presumed encoding to UTF-32 during the comparison. Otherwise, the character begin matched is directly compared to the elements of <computeroutput>r</computeroutput>. <computeroutput>symbols</computeroutput> provides a list of strings that may appear after a backslash to form an escape sequence, and what character(s) each escape sequence represents. Note that <computeroutput>"\\"</tt> and <tt>"\ch"</computeroutput> are always valid escape sequences. </para></description></method>
|
||||
</method-group>
|
||||
</struct><struct name="repeat_directive"><template>
|
||||
<template-type-parameter name="MinType"/>
|
||||
@@ -1016,7 +1016,7 @@
|
||||
<template-type-parameter name="DelimiterParser"><default><classname alt="boost::parser::detail::nope">detail::nope</classname></default></template-type-parameter>
|
||||
<template-type-parameter name="MinType"><default><classname alt="boost::parser::parse_error">int64_t</classname></default></template-type-parameter>
|
||||
<template-type-parameter name="MaxType"><default><classname alt="boost::parser::parse_error">int64_t</classname></default></template-type-parameter>
|
||||
</template><description><para>Repeats the application of another parser <computeroutput>p</computeroutput> of type <computeroutput>Parser</computeroutput>, optionally applying another parser <computeroutput>d</computeroutput> of type <computeroutput>DelimiterParser</computeroutput> in between each pair of applications of <computeroutput>p</computeroutput>. The parse succeeds if <computeroutput>p</computeroutput> succeeds at least the minumum number of times, and <computeroutput>d</computeroutput> succeeds each time it is applied. The attribute produced is a sequence of the type of attribute produced by <computeroutput>Parser</computeroutput>. </para></description></struct><struct name="rule"><template>
|
||||
</template><description><para>Repeats the application of another parser <computeroutput>p</computeroutput> of type <computeroutput>Parser</computeroutput>, optionally applying another parser <computeroutput>d</computeroutput> of type <computeroutput>DelimiterParser</computeroutput> in between each pair of applications of <computeroutput>p</computeroutput>. The parse succeeds if <computeroutput>p</computeroutput> succeeds at least the minimum number of times, and <computeroutput>d</computeroutput> succeeds each time it is applied. The attribute produced is a sequence of the type of attribute produced by <computeroutput>Parser</computeroutput>. </para></description></struct><struct name="rule"><template>
|
||||
<template-type-parameter name="TagType"/>
|
||||
<template-type-parameter name="Attribute"><default>no_attribute</default></template-type-parameter>
|
||||
<template-type-parameter name="LocalState"><default>no_local_state</default></template-type-parameter>
|
||||
@@ -1049,7 +1049,7 @@
|
||||
</para></description></struct><struct name="transform_parser"><template>
|
||||
<template-type-parameter name="Parser"/>
|
||||
<template-type-parameter name="F"/>
|
||||
</template><description><para>Applies the given parser <computeroutput>p</computeroutput> of type <computeroutput>Parser</computeroutput>. The attribute produced by <computeroutput>p</computeroutput> is passed to the fiven invocable <computeroutput>f</computeroutput> of type <computeroutput>F</computeroutput>. <computeroutput>f</computeroutput> will only be invoked if <computeroutput>p</computeroutput> succeeds and sttributes are currently being generated. The parse succeeds iff <computeroutput>p</computeroutput> succeeds. The attribute produced is the the result of the call to <computeroutput>f</computeroutput>. </para></description></struct><struct name="uint_parser"><template>
|
||||
</template><description><para>Applies the given parser <computeroutput>p</computeroutput> of type <computeroutput>Parser</computeroutput>. The attribute produced by <computeroutput>p</computeroutput> is passed to the given invocable <computeroutput>f</computeroutput> of type <computeroutput>F</computeroutput>. <computeroutput>f</computeroutput> will only be invoked if <computeroutput>p</computeroutput> succeeds and attributes are currently being generated. The parse succeeds iff <computeroutput>p</computeroutput> succeeds. The attribute produced is the result of the call to <computeroutput>f</computeroutput>. </para></description></struct><struct name="uint_parser"><template>
|
||||
<template-type-parameter name="T"/>
|
||||
<template-nontype-parameter name="Radix"><type><classname>int</classname></type><default>10</default></template-nontype-parameter>
|
||||
<template-nontype-parameter name="MinDigits"><type><classname>int</classname></type><default>1</default></template-nontype-parameter>
|
||||
@@ -1112,7 +1112,7 @@
|
||||
</template><parameter name="context"><paramtype><classname>Context</classname> <classname>const</classname> &</paramtype></parameter><description><para>Returns a reference to one or more local values that the bottommost rule is declared to have; multiple values will be stored within a <computeroutput>parser::tuple</computeroutput>. Returns <computeroutput>none</computeroutput> if there is no bottommost rule, or if that rule has no locals. </para></description></function>
|
||||
<function name="_params"><type><classname>decltype</classname>(<classname>auto</classname>)</type><template>
|
||||
<template-type-parameter name="Context"/>
|
||||
</template><parameter name="context"><paramtype><classname>Context</classname> <classname>const</classname> &</paramtype></parameter><description><para>Returns a reference to one or more parameters passed to the bottommost rule <computeroutput>r</computeroutput>, by using <computeroutput>r</computeroutput> as <computeroutput>r.with(param0, param1, ... paramN)</computeroutput>; multiple values will be stored within a <computeroutput>parser::tuple</computeroutput>. Returns <computeroutput>none</computeroutput> if there is no bottommost rule, or if that rule was not given any parameters. </para></description></function>
|
||||
</template><parameter name="context"><paramtype><classname>Context</classname> <classname>const</classname> &</paramtype></parameter><description><para>Returns a reference to one or more parameters passed to the bottommost rule <computeroutput>r</computeroutput>, by using <computeroutput>r</computeroutput> as <computeroutput>r.with(param0, param1, ..., paramN)</computeroutput>; multiple values will be stored within a <computeroutput>parser::tuple</computeroutput>. Returns <computeroutput>none</computeroutput> if there is no bottommost rule, or if that rule was not given any parameters. </para></description></function>
|
||||
<function name="_globals"><type><classname>decltype</classname>(<classname>auto</classname>)</type><template>
|
||||
<template-type-parameter name="Context"/>
|
||||
</template><parameter name="context"><paramtype><classname>Context</classname> <classname>const</classname> &</paramtype></parameter><description><para>Returns a reference to the globals object associated with the top-level parser. Returns <computeroutput>none</computeroutput> if there is no associated globals object. </para></description></function>
|
||||
@@ -1512,7 +1512,7 @@ P, Q)</computeroutput>, and <computeroutput>search_all_view(E, P, Q, R)</compute
|
||||
<template-type-parameter name="GlobalState"/>
|
||||
<template-type-parameter name="ErrorHandler"/>
|
||||
<template-type-parameter name="SkipParser"/>
|
||||
</template><description><para>Produces a sequence of subranges of the underlying sequence of type <computeroutput>V</computeroutput>. the underlying sequence is split into subranges delimited by matches of the given parser, possibly using a given skip-parser. </para></description><struct name="iterator"><template>
|
||||
</template><description><para>Produces a sequence of subranges of the underlying sequence of type <computeroutput>V</computeroutput>. The underlying sequence is split into subranges delimited by matches of the given parser, possibly using a given skip-parser. </para></description><struct name="iterator"><template>
|
||||
<template-nontype-parameter name="Const"><type><classname>bool</classname></type></template-nontype-parameter>
|
||||
</template><typedef name="I"><type><emphasis>unspecified</emphasis></type></typedef>
|
||||
<typedef name="S"><type><emphasis>unspecified</emphasis></type></typedef>
|
||||
@@ -1767,21 +1767,21 @@ P, Q)</computeroutput>, and <computeroutput>split_view(E, P, Q, R)</computeroutp
|
||||
<namespace name="parser">
|
||||
<class name="utf16_view"><template>
|
||||
<template-nontype-parameter name="V"><type><emphasis>unspecified</emphasis></type><purpose><para>Constrained by <computeroutput>std::ranges::view<V></computeroutput>. Additionally, the value type of <computeroutput>V</computeroutput> must be <computeroutput>char</computeroutput>, <computeroutput>wchar_t</computeroutput>, <computeroutput>char8_t</computeroutput>, <computeroutput>char16_t</computeroutput>, or <computeroutput>char32_t</computeroutput>. </para></purpose></template-nontype-parameter>
|
||||
</template><description><para>A view that produces UTF-16 from an given sequence of UTF.</para><para>
|
||||
</template><description><para>A view that produces UTF-16 from a given sequence of UTF.</para><para>
|
||||
</para></description><method-group name="public member functions">
|
||||
</method-group>
|
||||
<constructor cv="= default"/>
|
||||
<constructor><parameter name="base"><paramtype>V</paramtype></parameter></constructor>
|
||||
</class><class name="utf32_view"><template>
|
||||
<template-nontype-parameter name="V"><type><emphasis>unspecified</emphasis></type><purpose><para>Constrained by <computeroutput>std::ranges::view<V></computeroutput>. Additionally, the value type of <computeroutput>V</computeroutput> must be <computeroutput>char</computeroutput>, <computeroutput>wchar_t</computeroutput>, <computeroutput>char8_t</computeroutput>, <computeroutput>char16_t</computeroutput>, or <computeroutput>char32_t</computeroutput>. </para></purpose></template-nontype-parameter>
|
||||
</template><description><para>A view that produces UTF-32 from an given sequence of UTF.</para><para>
|
||||
</template><description><para>A view that produces UTF-32 from a given sequence of UTF.</para><para>
|
||||
</para></description><method-group name="public member functions">
|
||||
</method-group>
|
||||
<constructor cv="= default"/>
|
||||
<constructor><parameter name="base"><paramtype>V</paramtype></parameter></constructor>
|
||||
</class><class name="utf8_view"><template>
|
||||
<template-nontype-parameter name="V"><type><emphasis>unspecified</emphasis></type><purpose><para>Constrained by <computeroutput>std::ranges::view<V></computeroutput>. Additionally, the value type of <computeroutput>V</computeroutput> must be <computeroutput>char</computeroutput>, <computeroutput>wchar_t</computeroutput>, <computeroutput>char8_t</computeroutput>, <computeroutput>char16_t</computeroutput>, or <computeroutput>char32_t</computeroutput>. </para></purpose></template-nontype-parameter>
|
||||
</template><description><para>A view that produces UTF-8 from an given sequence of UTF.</para><para>
|
||||
</template><description><para>A view that produces UTF-8 from a given sequence of UTF.</para><para>
|
||||
</para></description><method-group name="public member functions">
|
||||
</method-group>
|
||||
<constructor cv="= default"/>
|
||||
@@ -2142,4 +2142,4 @@ P, Q, R, S)</computeroutput>, respectively. </para></description></data-member>
|
||||
</namespace>
|
||||
</namespace>
|
||||
</header>
|
||||
</library-reference>
|
||||
</library-reference>
|
||||
|
||||
@@ -202,7 +202,7 @@ It has a different API, and other code that operates on text expects a string
|
||||
instead of some other container. Arrays of characters are already considered
|
||||
special by the standard library and common practice in C++.
|
||||
|
||||
Second, When you write a parser that parses multiple characters in a row, you
|
||||
Second, when you write a parser that parses multiple characters in a row, you
|
||||
are typically trying to produce a string attribute, rather than a few
|
||||
individual character values. When you use multiple non-character parsers in a
|
||||
row, you are typically trying to produce multiple values. For instance:
|
||||
@@ -217,7 +217,7 @@ I've rarely written a parser like `parser_2` and wanted a
|
||||
`std::vector<std::string>`.
|
||||
|
||||
_Parser_ therefore makes the common case the default behavior, and provides
|
||||
you with the _merge_ and _sep_ directives to let you opt-in to generating the
|
||||
you with the _merge_ and _sep_ directives to let you opt in to generating the
|
||||
less-common attributes.
|
||||
|
||||
[heading Attribute compatibility rules are more strict than in Spirit]
|
||||
@@ -261,13 +261,12 @@ Also, Spirit-style looseness is more complicated than `parser` above
|
||||
indicates. Remember, `int_ | eps` and `-int_` are supposed to be semantically
|
||||
equivalent. To do otherwise this would be a profound violation of the
|
||||
principle of least surprise. So, if they're equivalent, we would need to
|
||||
apply the same rule to `int_ | eps`. Also, we would probably need to apply it
|
||||
to `if_(cond)[int_]`, which is also a `std::optional<int>`. This is a lot to
|
||||
remember, and this is complicated to implement and maintain.
|
||||
apply the same rule to `int_ | eps`. This is a lot to remember, and this is
|
||||
complicated to implement and maintain.
|
||||
|
||||
I've been using Spirit 1 and later Spirit 2 since they were released. I did
|
||||
not know about the particular looseness discussed here; a user pointed it out
|
||||
on Github. In many years of using these libraries, I never fully learned all
|
||||
on GitHub. In many years of using these libraries, I never fully learned all
|
||||
the attribute-compatibility rules, and was often surprised by them.
|
||||
|
||||
Having a small set of rules that the user can internalize is vital; if the
|
||||
@@ -299,7 +298,7 @@ that it succeeds (if it had failed, it would have cleared its attribute). It
|
||||
does not know that there is nothing after it that could continue the parse,
|
||||
nor that it is being used in to do a full parse. So, the over-all parse
|
||||
fails, but the part of the parse that fills in the out-param attribute does
|
||||
not know do clear its attribute.
|
||||
not know to clear its attribute.
|
||||
|
||||
This is why the explicit clearing behavior happens at the end of _p_. This is
|
||||
not without its downsides, though. Consider this.
|
||||
@@ -315,7 +314,7 @@ not without its downsides, though. Consider this.
|
||||
Here, the explicit clearing replaces the previous value of `3`, even though
|
||||
the parser never touched the value! Destroying users' variables' state
|
||||
without need may seem like a bad idea, but consider the alternative _emdash_
|
||||
In the previous example, we had spurious values left in the out-param
|
||||
in the previous example, we had spurious values left in the out-param
|
||||
attribute. Here, without clearing, we would have had a value left in the
|
||||
out-param attribute, not because it was a partial result of the parse, but
|
||||
because the parse never touched it. This is certain to be confusing, or at
|
||||
@@ -338,7 +337,7 @@ They do not even work correctly for ASCII values. This is because they use
|
||||
the C standard library's locale mechanism, which can be set to anything the
|
||||
current platform supports, and can be set by any code anywhere in your
|
||||
program; the locale is mutable global state. So, even if you use the default
|
||||
"C locale in your program, if you link against a library that sets the locale
|
||||
C locale in your program, if you link against a library that sets the locale
|
||||
to something that breaks ASCII character recognition (an EBCDIC locale, for
|
||||
instance), your program is now incorrect, regardless of the code you wrote.
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ the input they match unless otherwise stated in the table below.]
|
||||
[[ _attr_np_`(arg0)` ]
|
||||
[ Always matches, and consumes no input. Generates the attribute `_RES_np_(arg0)`. ]
|
||||
[ `decltype(_RES_np_(arg0))`. ]
|
||||
[ An important use case for `_attr_` is to provide a default attribute value as a trailing alternative. For instance, an *optional* comma-delmited list is: `int_ % ',' | attr(std::vector<int>)`. Without the "`| attr(...)`", at least one `int_` match would be required. ]]
|
||||
[ An important use case for `_attr_` is to provide a default attribute value as a trailing alternative. For instance, an *optional* comma-delimited list is: `int_ % ',' | attr(std::vector<int>)`. Without the "`| attr(...)`", at least one `int_` match would be required. ]]
|
||||
|
||||
[[ _ch_ ]
|
||||
[ Matches any single code point. ]
|
||||
@@ -138,7 +138,7 @@ the input they match unless otherwise stated in the table below.]
|
||||
[]]
|
||||
|
||||
[[ `_hex_digit_` ]
|
||||
[ Matches a single hexidecimal digit code point. ]
|
||||
[ Matches a single hexadecimal digit code point. ]
|
||||
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See the entry for _ch_. ]
|
||||
[]]
|
||||
|
||||
@@ -319,7 +319,7 @@ the input they match unless otherwise stated in the table below.]
|
||||
|
||||
[[ `_if_np_(pred)[p]` ]
|
||||
[ Equivalent to `_e_(pred) >> p`. ]
|
||||
[ `std::optional<_ATTR_np_(p)>` ]
|
||||
[ `_ATTR_np_(p)` ]
|
||||
[ It is an error to write `_if_np_(pred)`. That is, it is an error to omit the conditionally matched parser `p`. ]]
|
||||
|
||||
[[ `_sw_np_(arg0)(arg1, p1)(arg2, p2) ...` ]
|
||||
@@ -328,9 +328,9 @@ the input they match unless otherwise stated in the table below.]
|
||||
[ It is an error to write `_sw_np_(arg0)`. That is, it is an error to omit the conditionally matched parsers `p1`, `p2`, .... ]]
|
||||
|
||||
[[ _symbols_t_ ]
|
||||
[ _symbols_ is an associative container of key, value pairs. Each key is a _std_str_ and each value has type `T`. In the Unicode parsing path, the strings are considered to be UTF-8 encoded; in the non-Unicode path, no encoding is assumed. _symbols_ Matches the longest prefix `pre` of the input that is equal to one of the keys `k`. If the length `len` of `pre` is zero, and there is no zero-length key, it does not match the input. If `len` is positive, the generated attribute is the value associated with `k`.]
|
||||
[ _symbols_ is an associative container of key, value pairs. Each key is a _std_str_ and each value has type `T`. In the Unicode parsing path, the strings are considered to be UTF-8 encoded; in the non-Unicode path, no encoding is assumed. _symbols_ matches the longest prefix `pre` of the input that is equal to one of the keys `k`. If the length `len` of `pre` is zero, and there is no zero-length key, it does not match the input. If `len` is positive, the generated attribute is the value associated with `k`.]
|
||||
[ `T` ]
|
||||
[ Unlike the other entries in this table, _symbols_ is a type, not an object. ]]
|
||||
[ Unlike the other entries in this table, _symbols_ is a type, not an object. Inside of skippers, all _symbols_ will appear empty. ]]
|
||||
|
||||
[[ _quot_str_ ]
|
||||
[ Matches `'"'`, followed by zero or more characters, followed by `'"'`. ]
|
||||
@@ -368,7 +368,7 @@ character type (or use _attr_ to do so).]
|
||||
]
|
||||
|
||||
[template table_combining_operations
|
||||
Here are all the operator overloaded for parsers. In the tables below:
|
||||
Here are all the operators overloaded for parsers. In the tables below:
|
||||
|
||||
* `c` is a character of type `char` or `char32_t`;
|
||||
|
||||
@@ -399,7 +399,7 @@ consume the input they match unless otherwise stated in the table below.]
|
||||
[[`p1 | p2`] [ Matches iff either `p1` matches or `p2` matches. ] [`std::variant<_ATTR_np_(p1), _ATTR_np_(p2)>` (See note.)] [ `|` is associative; `p1 | p2 | p3`, `(p1 | p2) | p3`, and `p1 | (p2 | p3)` are all equivalent. This attribute type only applies to the case where `p1` and `p2` both generate attributes, and where the attribute types are different; see _attr_gen_ for the full rules. ]]
|
||||
[[`p | c`] [ Equivalent to `p | lit(c)`. ] [`_ATTR_np_(p)`] []]
|
||||
[[`p | r`] [ Equivalent to `p | lit(r)`. ] [`_ATTR_np_(p)`] []]
|
||||
[[`p1 || p2`] [ Matches iff `p1` matches and `p2` matches, regardless of the order they match in. ] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2)>`] [ `||` is associative; `p1 || p2 || p3`, `(p1 || p2) || p3`, and `p1 || (p2 || p3)` are all equivalent. It is an error to include a _e_ (conditional or non-conditional) in an `operator||` expression. Though the parsers are matched in any order, the attribute elements are always in the order written in the `operator||` expression. ]]
|
||||
[[`p1 || p2`] [ Matches iff `p1` matches and `p2` matches, regardless of the order they match in. ] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2)>`] [ `||` is associative; `p1 || p2 || p3`, `(p1 || p2) || p3`, and `p1 || (p2 || p3)` are all equivalent. It is an error to include an _e_ (conditional or non-conditional) in an `operator||` expression. Though the parsers are matched in any order, the attribute elements are always in the order written in the `operator||` expression. ]]
|
||||
[[`p1 - p2`] [ Equivalent to `!p2 >> p1`. ] [`_ATTR_np_(p1)`] []]
|
||||
[[`p - c`] [ Equivalent to `p - lit(c)`. ] [`_ATTR_np_(p)`] []]
|
||||
[[`p - r`] [ Equivalent to `p - lit(r)`. ] [`_ATTR_np_(p)`] []]
|
||||
@@ -557,7 +557,7 @@ tables below:
|
||||
|
||||
[[`_rpt_np_(arg0)[p]`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`]]
|
||||
[[`_rpt_np_(arg0, arg1)[p]`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`]]
|
||||
[[`_if_np_(pred)[p]`] [`std::optional<_ATTR_np_(p)>`]]
|
||||
[[`_if_np_(pred)[p]`] [`_ATTR_np_(p)`]]
|
||||
[[`_sw_np_(arg0)(arg1, p1)(arg2, p2)...`]
|
||||
[`std::variant<_ATTR_np_(p1), _ATTR_np_(p2), ...>`]]
|
||||
]
|
||||
|
||||
@@ -13,7 +13,7 @@ A /semantic action/ is an arbitrary bit of logic associated with a parser,
|
||||
that is only executed when the parser matches.
|
||||
|
||||
Simpler parsers can be combined to form more complex parsers. Given some
|
||||
combining operation `C`, and parsers `P0`, `P1`, ... `PN`, `C(P0, P1, ... PN)`
|
||||
combining operation `C`, and parsers `P0`, `P1`, ..., `PN`, `C(P0, P1, ..., PN)`
|
||||
creates a new parser `Q`. This creates a /parse tree/. `Q` is the parent of
|
||||
`P1`, `P2` is the child of `Q`, etc. The parsers are applied in the top-down
|
||||
fashion implied by this topology. When you use `Q` to parse a string, it
|
||||
@@ -113,7 +113,7 @@ Also, just ignore for now the fact that _Parser_ somehow figured out that the
|
||||
result type of the `*bp::char_` parser is a _std_str_. There are clear rules
|
||||
for this that we'll cover later.
|
||||
|
||||
The effects of this call to _p_ is not very interesting _emdash_ since the
|
||||
The effects of this call to _p_ are not very interesting _emdash_ since the
|
||||
parser we gave it cannot ever fail, and because we're placing the output in
|
||||
the same type as the input, it just copies the contents of `input` to
|
||||
`result`.
|
||||
@@ -403,7 +403,7 @@ Copying the entire context when mutating the context is therefore fast. The
|
||||
context does no memory allocation.
|
||||
|
||||
[tip All these functions that take the parse context as their first parameter
|
||||
will find by found by Argument-Dependent Lookup. You will probably never need
|
||||
will be found by Argument-Dependent Lookup. You will probably never need
|
||||
to qualify them with `boost::parser::`.]
|
||||
|
||||
[heading Accessors for data that are always available]
|
||||
@@ -414,7 +414,7 @@ underscore.
|
||||
|
||||
[heading _pass_]
|
||||
|
||||
_pass_ returns a reference to a `bool` indicating the success of failure of
|
||||
_pass_ returns a reference to a `bool` indicating the success or failure of
|
||||
the current parse. This can be used to force the current parse to pass or
|
||||
fail:
|
||||
|
||||
@@ -632,7 +632,7 @@ All this is intended to introduce the notion of _rs_. It still may be a bit
|
||||
unclear why you would want to use _rs_. The use cases for, and lots of detail
|
||||
about, _rs_ is in a later section, _more_about_rules_.
|
||||
|
||||
[note The existence of _rs_ means that will probably never have to write a
|
||||
[note The existence of _rs_ means that you will probably never have to write a
|
||||
low-level parser. You can just put existing parsers together into _rs_
|
||||
instead.]
|
||||
|
||||
@@ -901,7 +901,7 @@ all parser in its sequence. It then produces its attribute, a
|
||||
`bp::parse()`.
|
||||
|
||||
Something to take note of between Steps #3 and #4: at the beginning of #4, the
|
||||
input position had returned to where is was at the beginning of #3. This kind
|
||||
input position had returned to where it was at the beginning of #3. This kind
|
||||
of backtracking happens in alternative parsers when an alternative fails. The
|
||||
next page has more details on the semantics of backtracking.
|
||||
|
||||
@@ -1257,7 +1257,7 @@ were unsigned, you would use `uint_`. If it were signed, you would use
|
||||
constexpr auto hex_int = bp::uint_.base<16>();
|
||||
|
||||
You simply chain together the constraints you want to use, like
|
||||
`.base<16>().digits<2>()` or .digits<4>().base<8>()`.
|
||||
`.base<16>().digits<2>()` or `.digits<4>().base<8>()`.
|
||||
|
||||
So, if you wanted to parse exactly eight hexadecimal digits in a row in order
|
||||
to recognize Unicode character literals like C++ has (e.g. `\Udeadbeef`), you
|
||||
@@ -1296,7 +1296,7 @@ instance, `lexeme[a >> b] >> c` is a _seq_p_ containing two parsers, `lexeme[a
|
||||
in a _lex_p_. This in turn turns off the sequence parser combining logic,
|
||||
since both sides of the second `operator>>` in `lexeme[a >> b] >> c` are not
|
||||
_seq_ps_. Sequence parsers have several rules that govern what the overall
|
||||
attribute type of the parser is, based on the positions and attributes of it
|
||||
attribute type of the parser is, based on the positions and attributes of its
|
||||
subparsers (see _attr_gen_). Therefore, it's important to know which
|
||||
directives create a new parser (and what kind), and which ones do not; this is
|
||||
indicated for each directive below.
|
||||
@@ -1328,7 +1328,7 @@ Creates an _omt_p_.
|
||||
|
||||
[heading _raw_]
|
||||
|
||||
`_raw_np_[p]` changes the attribute from `_ATTR_np_(p)` to to a view that
|
||||
`_raw_np_[p]` changes the attribute from `_ATTR_np_(p)` to a view that
|
||||
delimits the subrange of the input that was matched by `p`. The type of the
|
||||
view is `_v_<I>`, where `I` is the type of the iterator used within the parse.
|
||||
Note that this may not be the same as the iterator type passed to _p_. For
|
||||
@@ -1394,7 +1394,7 @@ need to support the multi-expanding code points, use the other overload, like:
|
||||
and if you do it to two bits of text `A` and `B`, then you can compare them
|
||||
bitwise to see if they are the same, except of case. Case folding may
|
||||
sometimes expand a code point into multiple code points (e.g. case folding
|
||||
`"ẞ"` yields `"ss"`. When such a multi-code point expansion occurs, the
|
||||
`"ẞ"` yields `"ss"`). When such a multi-code point expansion occurs, the
|
||||
expanded code points are in the NFKC normalization form.]
|
||||
|
||||
Creates a _noc_p_.
|
||||
@@ -1510,7 +1510,7 @@ pretty useless. You should never see this type in practice. Within semantic
|
||||
actions, asking for the attribute of a non-attribute-producing parser (using
|
||||
`_attr(ctx)`) will yield a value of the special type `boost::parser::none`.
|
||||
When calling _p_ in a form that returns the attribute parsed, when there is no
|
||||
attribute, simply returns `bool`; this indicates the success of failure of the
|
||||
attribute, simply returns `bool`; this indicates the success or failure of the
|
||||
parse.]
|
||||
|
||||
[warning _Parser_ assumes that all attributes are semi-regular (see
|
||||
@@ -1686,7 +1686,7 @@ eligible for combining via `OP`.
|
||||
|
||||
[heading Alternative parser attribute rules]
|
||||
|
||||
The rules for alternative parsers are much simpler. For an alternative parer
|
||||
The rules for alternative parsers are much simpler. For an alternative parser
|
||||
`p`, let the list of attribute types for the subparsers of `p` be `a0, a1, a2,
|
||||
..., an`. The attribute of `p` is `std::variant<a0, a1, a2, ..., an>`, with
|
||||
the following steps applied:
|
||||
@@ -1694,7 +1694,7 @@ the following steps applied:
|
||||
* all the `none` attributes are left out, and if any are, the attribute is
|
||||
wrapped in a `std::optional`, like `std::optional<std::variant</*...*/>>`;
|
||||
|
||||
* duplicates in the `std::variant` template parameters `<T1, T2, ... Tn>` are
|
||||
* duplicates in the `std::variant` template parameters `<T1, T2, ..., Tn>` are
|
||||
removed; every type that appears does so exactly once;
|
||||
|
||||
* if the attribute is `std::variant<T>` or `std::optional<std::variant<T>>`,
|
||||
@@ -1790,7 +1790,7 @@ subparsers in the sequence parser to use the same variable for their
|
||||
attribute.
|
||||
|
||||
Another directive, _sep_, also applies only to sequence parsers, but does the
|
||||
opposite of _merge_. If forces all the attributes produced by the subparsers
|
||||
opposite of _merge_. It forces all the attributes produced by the subparsers
|
||||
of the sequence parser to stay separate, even if they would have combined.
|
||||
For instance, consider this parser.
|
||||
|
||||
@@ -1844,7 +1844,7 @@ and _sep_ do not. Since they operate only on sequence parsers, all they do is
|
||||
create a copy of the sequence parser they are given. The _seq_p_ template has
|
||||
a template parameter `CombiningGroups`, and all _merge_ and _sep_ do is take a
|
||||
given _seq_p_ and create a copy of it with a different `CombiningGroups`
|
||||
template parameter. This means that _merge_ and _sep_ are can be ignored in
|
||||
template parameter. This means that _merge_ and _sep_ can be ignored in
|
||||
`operator>>` expressions much like parentheses are. Consider an example.
|
||||
|
||||
namespace bp = boost::parser;
|
||||
@@ -1867,7 +1867,7 @@ given function `f`. For example:
|
||||
|
||||
Here, we have a function `str_sum` that we use for `f`. It assumes each
|
||||
character in the given _std_str_ `s` is a digit, and returns the sum of all
|
||||
the digits in `s`. Out parser `parser` would normally return a _std_str_.
|
||||
the digits in `s`. Our parser `parser` would normally return a _std_str_.
|
||||
However, since `str_sum` returns a different type _emdash_ `int` _emdash_ that
|
||||
is the attribute type of the full parser,
|
||||
`bp::transform(by_value_str_sum)[parser]`, as you can see from the
|
||||
@@ -1900,7 +1900,7 @@ common:
|
||||
* They each return a value contextually convertible to `bool`.
|
||||
|
||||
* They each take at least a range to parse and a parser. The "range to parse"
|
||||
may be an iterator/sentinel pair or an single range object.
|
||||
may be an iterator/sentinel pair or a single range object.
|
||||
|
||||
* They each require forward iterability of the range to parse.
|
||||
|
||||
@@ -2241,7 +2241,7 @@ encoding. Here is how it deduces which case the call falls under:
|
||||
|
||||
* Otherwise, the input is in a UTF encoding.
|
||||
|
||||
[tip if you want to want to parse in ASCII-only mode, or in some other
|
||||
[tip If you want to parse in ASCII-only mode, or in some other
|
||||
non-Unicode encoding, use only sequences of `char`, like _std_str_ or `char
|
||||
const *`.]
|
||||
|
||||
@@ -2265,7 +2265,7 @@ _eh_debugging_ section of the tutorial for details.
|
||||
[heading Globals and error handlers]
|
||||
|
||||
Each call to _p_ can optionally have a globals object associated with it. To
|
||||
use a particular globals object with you parser, you call _w_glb_ to create a
|
||||
use a particular globals object with your parser, you call _w_glb_ to create a
|
||||
new parser with the globals object in it:
|
||||
|
||||
struct globals_t
|
||||
@@ -2469,11 +2469,12 @@ defined somewhere.
|
||||
BOOST_PARSER_DEFINE_RULES(value);
|
||||
|
||||
Notice the two expectation points. One before `(value % ',')`, one before the
|
||||
final `'}'`. Later, you call parse in some input:
|
||||
final `'}'`. Later, you parse in some input:
|
||||
|
||||
bp::parse("{ 4, 5 a", value, bp::ws);
|
||||
|
||||
This runs should of the second expectation point, and produces output like this:
|
||||
This runs afoul of the second expectation point, and produces output like
|
||||
this:
|
||||
|
||||
[pre
|
||||
1:7: error: Expected '}' here:
|
||||
@@ -2493,7 +2494,7 @@ the earlier expectation:
|
||||
]
|
||||
|
||||
Not nearly as nice. The problem is that the expectation is on `(value %
|
||||
',')`. So, even thought we gave `value` reasonable diagnostic text, we put the
|
||||
',')`. So, even though we gave `value` reasonable diagnostic text, we put the
|
||||
text on the wrong thing. We can introduce a new rule to put the diagnostic
|
||||
text in the right place.
|
||||
|
||||
@@ -2520,7 +2521,7 @@ message:
|
||||
]
|
||||
|
||||
The _r_ `value` might be useful elsewhere in our code, perhaps in another
|
||||
parser. It's diagnostic text is appropriate for those other potential uses.
|
||||
parser. Its diagnostic text is appropriate for those other potential uses.
|
||||
|
||||
[heading Recursive rules]
|
||||
|
||||
@@ -2571,7 +2572,7 @@ of a recursive _r_. This is because each instance of the rule needs a place
|
||||
to put the attribute it generates from its parse. However, we only want a
|
||||
single return value for the uppermost rule; if each instance had a separate
|
||||
value in `_val(ctx)`, then it would be impossible to build up the result of a
|
||||
recursive rule step by step during in the evaluation of the recursive
|
||||
recursive rule step by step during the evaluation of the recursive
|
||||
instantiations.
|
||||
|
||||
Also, consider this rule:
|
||||
@@ -2623,7 +2624,7 @@ use each other without introducing cycles:
|
||||
|
||||
BOOST_PARSER_DEFINE_RULES(string, object_element, object, array, value);
|
||||
|
||||
Here we have a parser for a Javascript-value-like type `value_type`.
|
||||
Here we have a parser for a JavaScript-value-like type `value_type`.
|
||||
`value_type` may be an array, which itself may contain other arrays, objects,
|
||||
strings, etc. Since we need to be able to parse objects within arrays and
|
||||
vice versa, we need each of those two parsers to be able to refer to each
|
||||
@@ -2661,7 +2662,7 @@ semantics, is a lot easier to read, and is a lot less code.]
|
||||
[heading Locals]
|
||||
|
||||
The _r_ template takes another template parameter we have not discussed yet.
|
||||
You can pass a third parameter `LocalState` to _r_, which will be defaulted
|
||||
You can pass a third parameter `LocalState` to _r_, which will be default
|
||||
constructed by the _r_, and made available within semantic actions used in the
|
||||
rule as `_locals_np_(ctx)`. This gives your rule some local state, if it
|
||||
needs it. The type of `LocalState` can be anything regular. It could be a
|
||||
@@ -2773,7 +2774,7 @@ rewritten as:
|
||||
|
||||
auto const foo_def = bp::repeat(bp::_p<0>)[' '_l];
|
||||
|
||||
Using __p_ can prevent you from having to write a bunch of lambdas that get
|
||||
Using __p_ can prevent you from having to write a bunch of lambdas that
|
||||
each get an argument out of the parse context using `_params_np_(ctx)[0_c]` or
|
||||
similar.
|
||||
|
||||
@@ -3160,7 +3161,7 @@ worrying if the input is Unicode or not because, under the covers, what takes
|
||||
place is a simple comparison of two integral values.
|
||||
|
||||
[note _Parser_ actually promotes any two values to a common type using
|
||||
`std::common_type` before comparing them. This is almost always works because
|
||||
`std::common_type` before comparing them. This almost always works because
|
||||
the input and any parameter passed to _ch_ must be character types. ]
|
||||
|
||||
Since matches are always done at a code point level (remember, a "code point"
|
||||
@@ -3441,7 +3442,7 @@ is not very useful. Consider this.
|
||||
auto c_b = bp::char_('c') >> bp::char_('b');
|
||||
auto result = bp::parse("acb", a_b | c_b);
|
||||
|
||||
If we reported the farthest-reaching parser and it's position, it would be the
|
||||
If we reported the farthest-reaching parser and its position, it would be the
|
||||
`a_b` parser, at position `"bc"` in the input. Is this really enlightening?
|
||||
Was the error in the input putting the `'a'` at the beginning or putting the
|
||||
`'c'` in the middle? If you point the user at `a_b` as the parser that
|
||||
@@ -3610,7 +3611,7 @@ If we trace a substantial parser, we will see a *lot* of output. Each code
|
||||
point of the input must be considered, one at a time, to see if a certain rule
|
||||
matches. As an example, let's trace a parse using the JSON parser from
|
||||
_ex_json_. The input is `"null"`. `null` is one of the types that a
|
||||
Javascript value can have; the top-level parser in the JSON parser example is:
|
||||
JavaScript value can have; the top-level parser in the JSON parser example is:
|
||||
|
||||
auto const value_p_def =
|
||||
number | bp::bool_ | null | string | array_p | object_p;
|
||||
@@ -3798,7 +3799,7 @@ _Parser_ seldom allocates memory. The exceptions to this are:
|
||||
useful for such replacements.
|
||||
|
||||
With the exception of allocating the name of the parser that was expected in a
|
||||
failed expectation situation, _Parser_ does not does not allocate unless you
|
||||
failed expectation situation, _Parser_ does not allocate unless you
|
||||
tell it to, by using _symbols_, using a particular error_handler, turning on
|
||||
trace, or parsing into attributes that allocate.
|
||||
|
||||
@@ -3806,7 +3807,7 @@ trace, or parsing into attributes that allocate.
|
||||
|
||||
[section Best Practices]
|
||||
|
||||
[heading Parse unicode from the start]
|
||||
[heading Parse Unicode from the start]
|
||||
|
||||
If you want to parse ASCII, using the Unicode parsing API will not actually
|
||||
cost you anything. Your input will be parsed, `char` by `char`, and compared
|
||||
@@ -3953,7 +3954,7 @@ First, let's look at the template and function parameters.
|
||||
`true` if the parse succeeds, and `false` otherwise.
|
||||
|
||||
Now the body of the function. Notice that it just dispatches to the other
|
||||
`call()` overload. This is really common, since both overloads need to to the
|
||||
`call()` overload. This is really common, since both overloads need to do the
|
||||
same parsing; only the attribute may differ. The first line of the body
|
||||
defines `attr_t`, the default attribute type of our wrapped parser `parser_`.
|
||||
It does this by getting the `decltype()` of a use of `parser_.call()`. (This
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//[ extended_json_example
|
||||
// This header includes a type called json::value that acts as a
|
||||
// Javascript-like polymorphic value type.
|
||||
// JavaScript-like polymorphic value type.
|
||||
#include "json.hpp"
|
||||
|
||||
#include <boost/parser/parser.hpp>
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace boost { namespace parser {
|
||||
std::declval<bool &>(),
|
||||
std::declval<int &>(),
|
||||
std::declval<ErrorHandler const &>(),
|
||||
std::declval<detail::nope &>(),
|
||||
std::declval<detail::nope const &>(),
|
||||
std::declval<detail::symbol_table_tries_t &>(),
|
||||
std::declval<detail::pending_symbol_table_operations_t &>()));
|
||||
|
||||
|
||||
@@ -16,19 +16,19 @@
|
||||
|
||||
/** Boost.Parser uses assertions (`BOOST_ASSERT()`) in several places to
|
||||
indicate that your use of the library has an error in it. All of those
|
||||
places could heve instead been ill-formed code, caught at compile time.
|
||||
places could have instead been ill-formed code, caught at compile time.
|
||||
It is far quicker and easier to determine exactly where in your code such
|
||||
an error is located if this is a runtime failure; you can just look at the
|
||||
stack in your favorite debugger. However, if you want to make thes kinds
|
||||
stack in your favorite debugger. However, if you want to make these kinds
|
||||
of errors always ill-formed code, define this macro. */
|
||||
# define BOOST_PARSER_NO_RUNTIME_ASSERTIONS
|
||||
|
||||
/** Asserts that the given condition is true. If
|
||||
`BOOST_PARSER_NO_RUNTIME_ASSERTIONS` macro is defined by the user,
|
||||
`BOOST_PARSER_ASSERT` expends to a compile-time `static_assert()`.
|
||||
`BOOST_PARSER_ASSERT` expands to a compile-time `static_assert()`.
|
||||
Otherwise, it expands to a run-time `BOOST_ASSERT()`. Note that defining
|
||||
`BOOST_DISABLE_ASSERTS` disables the use of C `assert`, even when
|
||||
`BOOST_ASSERT` is unavailble. */
|
||||
`BOOST_ASSERT` is unavailable. */
|
||||
# define BOOST_PARSER_ASSERT(condition)
|
||||
|
||||
/** Boost.Parser will automatically use concepts to constrain templates when
|
||||
|
||||
@@ -47,7 +47,10 @@ namespace boost::parser::detail {
|
||||
// One-byte fast path.
|
||||
if (cp < 0x100) {
|
||||
// ASCII letter fast path.
|
||||
if (0x41 <= cp && cp < 0x5a) {
|
||||
if (0x61 <= cp && cp <= 0x7a) {
|
||||
*out++ = cp;
|
||||
return out;
|
||||
} else if (0x41 <= cp && cp <= 0x5a) {
|
||||
*out++ = cp + 0x20;
|
||||
return out;
|
||||
} else if (cp == 0x00DF) {
|
||||
|
||||
@@ -24,7 +24,10 @@
|
||||
#define BOOST_PARSER_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE 0
|
||||
#endif
|
||||
|
||||
#if !BOOST_PARSER_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE && \
|
||||
#if !BOOST_STL_INTERFACES_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE && \
|
||||
BOOST_STL_INTERFACES_USE_CONCEPTS && defined(BOOST_GCC) && 14 <= __GNUC__
|
||||
#define BOOST_PARSER_USE_LIBSTDCPP_GCC14_RANGE_ADAPTOR_CLOSURE 1
|
||||
#elif !BOOST_PARSER_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE && \
|
||||
BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS && \
|
||||
defined(BOOST_PARSER_GCC) && 12 <= __GNUC__
|
||||
#define BOOST_PARSER_USE_LIBSTDCPP_GCC12_RANGE_ADAPTOR_CLOSURE 1
|
||||
@@ -198,6 +201,11 @@ namespace boost::parser::detail { namespace stl_interfaces {
|
||||
template<typename D>
|
||||
using range_adaptor_closure = std::ranges::range_adaptor_closure<D>;
|
||||
|
||||
#elif BOOST_PARSER_USE_LIBSTDCPP_GCC14_RANGE_ADAPTOR_CLOSURE
|
||||
|
||||
template<typename D>
|
||||
using range_adaptor_closure = std::views::__adaptor::_RangeAdaptorClosure<D>;
|
||||
|
||||
#elif BOOST_PARSER_USE_LIBSTDCPP_GCC12_RANGE_ADAPTOR_CLOSURE
|
||||
|
||||
template<typename D>
|
||||
@@ -259,7 +267,7 @@ namespace boost::parser::detail { namespace stl_interfaces {
|
||||
template<typename F>
|
||||
struct closure : range_adaptor_closure<closure<F>>
|
||||
{
|
||||
constexpr closure(F f) : f_(f) {}
|
||||
constexpr closure(F f) : f_(std::move(f)) {}
|
||||
|
||||
#if BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
|
||||
template<typename T>
|
||||
@@ -327,7 +335,7 @@ namespace boost::parser::detail { namespace stl_interfaces {
|
||||
template<typename F>
|
||||
struct adaptor
|
||||
{
|
||||
constexpr adaptor(F f) : f_(f) {}
|
||||
constexpr adaptor(F f) : f_(std::move(f)) {}
|
||||
|
||||
template<typename... Args>
|
||||
constexpr auto operator()(Args &&... args) const
|
||||
|
||||
@@ -126,7 +126,7 @@ namespace boost::parser::detail::text::detail {
|
||||
else if constexpr (can_ref_view<R>)
|
||||
return ref_view(r);
|
||||
else
|
||||
return owning_view<T>(std::move(r));
|
||||
return owning_view<T>((R &&)r);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -90,6 +90,9 @@ namespace boost { namespace parser {
|
||||
os << ":\n";
|
||||
|
||||
std::string underlining(std::distance(position.line_start, it), ' ');
|
||||
std::transform(position.line_start, it,
|
||||
underlining.begin(),
|
||||
[](auto c) { return c == '\t' ? '\t' : ' ';});
|
||||
detail::trace_input(os, position.line_start, it, false, 1u << 31);
|
||||
if (it == last) {
|
||||
os << '\n' << underlining << "^\n";
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace boost { namespace parser {
|
||||
|
||||
/** The error handler used when the user does not specify a custom one.
|
||||
This error handler prints warnings and errors to `std::cerr`, and does
|
||||
not have an associcated filename. */
|
||||
not have an associated filename. */
|
||||
struct default_error_handler
|
||||
{
|
||||
constexpr default_error_handler() = default;
|
||||
|
||||
@@ -374,7 +374,10 @@ namespace boost { namespace parser {
|
||||
template<typename T>
|
||||
using print_type = typename print_t<T>::type;
|
||||
|
||||
template<typename R, typename Parser>
|
||||
struct null_parser
|
||||
{};
|
||||
|
||||
template<typename R, typename Parser, typename SkipParser = null_parser>
|
||||
struct attribute_impl;
|
||||
|
||||
// Utility types.
|
||||
@@ -412,7 +415,7 @@ namespace boost { namespace parser {
|
||||
}
|
||||
};
|
||||
|
||||
inline nope global_nope;
|
||||
inline nope const global_nope;
|
||||
|
||||
template<typename T>
|
||||
using parser_interface_tag_expr =
|
||||
@@ -433,7 +436,7 @@ namespace boost { namespace parser {
|
||||
typename I,
|
||||
typename S,
|
||||
typename ErrorHandler,
|
||||
typename GlobalState = nope,
|
||||
typename GlobalState = nope const,
|
||||
typename Callbacks = nope,
|
||||
typename Attr = nope,
|
||||
typename Val = nope,
|
||||
@@ -469,6 +472,37 @@ namespace boost { namespace parser {
|
||||
nope_or_pointer_t<Where, true> where_{};
|
||||
int no_case_depth_ = 0;
|
||||
|
||||
// These exist in order to provide an address, if requested, for
|
||||
// either kind of symbol table struct. The nonstatic member
|
||||
// pointers for these will be null if this context was created
|
||||
// inside of detail::skip(), but nothing prevents the user from
|
||||
// trying to use a symbol_parser anyway. So, we have these.
|
||||
static std::optional<symbol_table_tries_t>
|
||||
empty_symbol_table_tries_;
|
||||
static std::optional<pending_symbol_table_operations_t>
|
||||
empty_pending_symbol_table_operations_;
|
||||
|
||||
symbol_table_tries_t & get_symbol_table_tries() const
|
||||
{
|
||||
if (symbol_table_tries_)
|
||||
return *symbol_table_tries_;
|
||||
if (!empty_symbol_table_tries_)
|
||||
empty_symbol_table_tries_ = symbol_table_tries_t();
|
||||
return *empty_symbol_table_tries_;
|
||||
}
|
||||
|
||||
pending_symbol_table_operations_t &
|
||||
get_pending_symbol_table_operations() const
|
||||
{
|
||||
if (pending_symbol_table_operations_)
|
||||
return *pending_symbol_table_operations_;
|
||||
if (!empty_pending_symbol_table_operations_) {
|
||||
empty_pending_symbol_table_operations_ =
|
||||
pending_symbol_table_operations_t();
|
||||
}
|
||||
return *empty_pending_symbol_table_operations_;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static auto nope_or_address(T & x)
|
||||
{
|
||||
@@ -510,6 +544,23 @@ namespace boost { namespace parser {
|
||||
globals_(nope_or_address(globals))
|
||||
{}
|
||||
|
||||
parse_context(
|
||||
std::bool_constant<DoTrace>,
|
||||
std::bool_constant<UseCallbacks>,
|
||||
I & first,
|
||||
S last,
|
||||
bool & success,
|
||||
int & indent,
|
||||
ErrorHandler const & error_handler,
|
||||
GlobalState & globals) :
|
||||
first_(first),
|
||||
last_(last),
|
||||
pass_(std::addressof(success)),
|
||||
trace_indent_(std::addressof(indent)),
|
||||
error_handler_(std::addressof(error_handler)),
|
||||
globals_(nope_or_address(globals))
|
||||
{}
|
||||
|
||||
// With callbacks.
|
||||
parse_context(
|
||||
std::bool_constant<DoTrace>,
|
||||
@@ -628,6 +679,64 @@ namespace boost { namespace parser {
|
||||
{}
|
||||
};
|
||||
|
||||
template<
|
||||
bool DoTrace,
|
||||
bool UseCallbacks,
|
||||
typename I,
|
||||
typename S,
|
||||
typename ErrorHandler,
|
||||
typename GlobalState,
|
||||
typename Callbacks,
|
||||
typename Attr,
|
||||
typename Val,
|
||||
typename RuleTag,
|
||||
typename RuleLocals,
|
||||
typename RuleParams,
|
||||
typename Where>
|
||||
std::optional<symbol_table_tries_t> parse_context<
|
||||
DoTrace,
|
||||
UseCallbacks,
|
||||
I,
|
||||
S,
|
||||
ErrorHandler,
|
||||
GlobalState,
|
||||
Callbacks,
|
||||
Attr,
|
||||
Val,
|
||||
RuleTag,
|
||||
RuleLocals,
|
||||
RuleParams,
|
||||
Where>::empty_symbol_table_tries_;
|
||||
|
||||
template<
|
||||
bool DoTrace,
|
||||
bool UseCallbacks,
|
||||
typename I,
|
||||
typename S,
|
||||
typename ErrorHandler,
|
||||
typename GlobalState,
|
||||
typename Callbacks,
|
||||
typename Attr,
|
||||
typename Val,
|
||||
typename RuleTag,
|
||||
typename RuleLocals,
|
||||
typename RuleParams,
|
||||
typename Where>
|
||||
std::optional<pending_symbol_table_operations_t> parse_context<
|
||||
DoTrace,
|
||||
UseCallbacks,
|
||||
I,
|
||||
S,
|
||||
ErrorHandler,
|
||||
GlobalState,
|
||||
Callbacks,
|
||||
Attr,
|
||||
Val,
|
||||
RuleTag,
|
||||
RuleLocals,
|
||||
RuleParams,
|
||||
Where>::empty_pending_symbol_table_operations_;
|
||||
|
||||
template<
|
||||
bool DoTrace,
|
||||
bool UseCallbacks,
|
||||
@@ -747,7 +856,7 @@ namespace boost { namespace parser {
|
||||
bool & success,
|
||||
int & indent,
|
||||
ErrorHandler const & error_handler,
|
||||
nope & n,
|
||||
nope const & n,
|
||||
symbol_table_tries_t & symbol_table_tries,
|
||||
pending_symbol_table_operations_t &
|
||||
pending_symbol_table_operations) noexcept
|
||||
@@ -765,6 +874,33 @@ namespace boost { namespace parser {
|
||||
pending_symbol_table_operations);
|
||||
}
|
||||
|
||||
template<
|
||||
bool DoTrace,
|
||||
bool UseCallbacks,
|
||||
typename Iter,
|
||||
typename Sentinel,
|
||||
typename ErrorHandler>
|
||||
auto make_context(
|
||||
Iter first,
|
||||
Sentinel last,
|
||||
bool & success,
|
||||
int & indent,
|
||||
ErrorHandler const & error_handler,
|
||||
nope const & n,
|
||||
nope const &,
|
||||
nope const &) noexcept
|
||||
{
|
||||
return parse_context(
|
||||
std::bool_constant<DoTrace>{},
|
||||
std::bool_constant<UseCallbacks>{},
|
||||
first,
|
||||
last,
|
||||
success,
|
||||
indent,
|
||||
error_handler,
|
||||
n);
|
||||
}
|
||||
|
||||
template<
|
||||
bool DoTrace,
|
||||
bool UseCallbacks,
|
||||
@@ -1359,7 +1495,7 @@ namespace boost { namespace parser {
|
||||
auto const r = cps | text::as_utf8;
|
||||
c.insert(c.end(), r.begin(), r.end());
|
||||
} else {
|
||||
detail::insert(c, std::move(x));
|
||||
detail::insert(c, (T &&)x);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1466,9 +1602,6 @@ namespace boost { namespace parser {
|
||||
uint32_t(flags::in_apply_parser);
|
||||
}
|
||||
|
||||
struct null_parser
|
||||
{};
|
||||
|
||||
struct skip_skipper
|
||||
{
|
||||
template<
|
||||
@@ -1518,18 +1651,9 @@ namespace boost { namespace parser {
|
||||
bool success = true;
|
||||
int indent = 0;
|
||||
rethrow_error_handler eh;
|
||||
nope n;
|
||||
symbol_table_tries_t symbol_table_tries;
|
||||
pending_symbol_table_operations_t pending_symbol_table_operations;
|
||||
nope const n;
|
||||
auto const context = detail::make_context<false, false>(
|
||||
first,
|
||||
last,
|
||||
success,
|
||||
indent,
|
||||
eh,
|
||||
n,
|
||||
symbol_table_tries,
|
||||
pending_symbol_table_operations);
|
||||
first, last, success, indent, eh, n, n, n);
|
||||
while (success) {
|
||||
skip_(
|
||||
first,
|
||||
@@ -1699,7 +1823,7 @@ namespace boost { namespace parser {
|
||||
using trie_t = text::trie_map<std::vector<char32_t>, T>;
|
||||
using result_type = std::pair<trie_t &, bool>;
|
||||
symbol_table_tries_t & symbol_table_tries =
|
||||
*context.symbol_table_tries_;
|
||||
context.get_symbol_table_tries();
|
||||
|
||||
auto & [any, has_case_folded] =
|
||||
symbol_table_tries[(void *)&sym_parser.ref()];
|
||||
@@ -1738,7 +1862,7 @@ namespace boost { namespace parser {
|
||||
Context const & context, symbol_parser<T> const & sym_parser)
|
||||
{
|
||||
void const * ptr = static_cast<void const *>(&sym_parser);
|
||||
auto & entry = (*context.pending_symbol_table_operations_)[ptr];
|
||||
auto & entry = (context.get_pending_symbol_table_operations())[ptr];
|
||||
std::vector<detail::symbol_table_operation<T>> * retval = nullptr;
|
||||
if (entry.visit_) {
|
||||
retval = std::any_cast<
|
||||
@@ -1951,9 +2075,9 @@ namespace boost { namespace parser {
|
||||
template<typename T, typename Tuple, int... Is>
|
||||
auto
|
||||
make_from_tuple_impl(Tuple && tup, std::integer_sequence<int, Is...>)
|
||||
-> decltype(T(parser::get(std::move(tup), llong<Is>{})...))
|
||||
-> decltype(T(parser::get((Tuple &&)tup, llong<Is>{})...))
|
||||
{
|
||||
return T(parser::get(std::move(tup), llong<Is>{})...);
|
||||
return T(parser::get((Tuple &&)tup, llong<Is>{})...);
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
@@ -1987,7 +2111,7 @@ namespace boost { namespace parser {
|
||||
auto const r = cps | text::as_utf8;
|
||||
c.insert(c.end(), r.begin(), r.end());
|
||||
} else if constexpr (std::is_convertible_v<just_u &&, just_t>) {
|
||||
detail::insert(c, std::move(x));
|
||||
detail::insert(c, (U &&)x);
|
||||
} else if constexpr (
|
||||
!is_tuple<just_t>::value && is_tuple<just_u>::value &&
|
||||
std::is_aggregate_v<just_t> &&
|
||||
@@ -1996,8 +2120,7 @@ namespace boost { namespace parser {
|
||||
auto int_seq =
|
||||
std::make_integer_sequence<int, tuple_size_<just_u>>();
|
||||
detail::insert(
|
||||
c,
|
||||
detail::tuple_to_aggregate<just_t>(std::move(x), int_seq));
|
||||
c, detail::tuple_to_aggregate<just_t>((U &&)x, int_seq));
|
||||
} else if constexpr (
|
||||
is_tuple<just_t>::value && !is_tuple<just_u>::value &&
|
||||
std::is_aggregate_v<just_u> &&
|
||||
@@ -2013,8 +2136,7 @@ namespace boost { namespace parser {
|
||||
} else if constexpr (is_constructible_from_tuple_v<
|
||||
just_t,
|
||||
just_u>) {
|
||||
detail::insert(
|
||||
c, detail::make_from_tuple<just_t>(std::move(x)));
|
||||
detail::insert(c, detail::make_from_tuple<just_t>((U &&)x));
|
||||
} else {
|
||||
static_assert(
|
||||
sizeof(U) && false,
|
||||
@@ -2029,7 +2151,7 @@ namespace boost { namespace parser {
|
||||
{
|
||||
if (!gen_attrs)
|
||||
return;
|
||||
detail::move_back_impl(c, std::move(x));
|
||||
detail::move_back_impl(c, (T &&)x);
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
@@ -2098,7 +2220,7 @@ namespace boost { namespace parser {
|
||||
"is almost certainly not what you meant to write, so "
|
||||
"Boost.Parser disallows it. If you want to do this, write "
|
||||
"a semantic action and do it explicitly.");
|
||||
t = std::move(u);
|
||||
t = (U &&)u;
|
||||
} else if constexpr (
|
||||
!is_tuple<just_t>::value && is_tuple<just_u>::value &&
|
||||
std::is_aggregate_v<just_t> &&
|
||||
@@ -2106,7 +2228,7 @@ namespace boost { namespace parser {
|
||||
is_struct_assignable_v<just_t, just_u>) {
|
||||
auto int_seq =
|
||||
std::make_integer_sequence<int, tuple_size_<just_u>>();
|
||||
t = detail::tuple_to_aggregate<just_t>(std::move(u), int_seq);
|
||||
t = detail::tuple_to_aggregate<just_t>((U &&)u, int_seq);
|
||||
} else if constexpr (
|
||||
is_tuple<just_t>::value && !is_tuple<just_u>::value &&
|
||||
std::is_aggregate_v<just_u> &&
|
||||
@@ -2120,7 +2242,7 @@ namespace boost { namespace parser {
|
||||
} else if constexpr (is_constructible_from_tuple_v<
|
||||
just_t,
|
||||
just_u>) {
|
||||
t = detail::make_from_tuple<just_t>(std::move(u));
|
||||
t = detail::make_from_tuple<just_t>((U &&)u);
|
||||
} else {
|
||||
static_assert(
|
||||
sizeof(T) && false,
|
||||
@@ -2541,7 +2663,7 @@ namespace boost { namespace parser {
|
||||
detail::skip(first, last, skip, flags);
|
||||
using attr_t = typename detail::attribute_impl<
|
||||
BOOST_PARSER_SUBRANGE<std::remove_const_t<Iter>, Sentinel>,
|
||||
Parser>::type;
|
||||
Parser, SkipParser>::type;
|
||||
try {
|
||||
attr_t attr_ =
|
||||
parser(first, last, context, skip, flags, success);
|
||||
@@ -3237,6 +3359,8 @@ namespace boost { namespace parser {
|
||||
|
||||
//[ opt_parser_gen_attr_path
|
||||
parser_.call(first, last, context, skip, flags, success, retval);
|
||||
if (!success)
|
||||
retval = Attribute();
|
||||
success = true;
|
||||
//]
|
||||
}
|
||||
@@ -3389,7 +3513,7 @@ namespace boost { namespace parser {
|
||||
|
||||
bool done = false;
|
||||
auto try_parser = [prev_first = first,
|
||||
use_parser,
|
||||
&use_parser,
|
||||
&success,
|
||||
flags,
|
||||
&retval,
|
||||
@@ -3405,7 +3529,9 @@ namespace boost { namespace parser {
|
||||
else
|
||||
use_parser.first_ = prev_first;
|
||||
};
|
||||
detail::hl::for_each(parsers_, try_parser); // TODO: -> fold-expr
|
||||
std::apply([&try_parser](auto&&... args) {
|
||||
((try_parser(args)), ...);
|
||||
}, parsers_);
|
||||
|
||||
if (!done)
|
||||
success = false;
|
||||
@@ -3556,9 +3682,7 @@ namespace boost { namespace parser {
|
||||
call(first, last, context, skip, flags, success, attr);
|
||||
if (success)
|
||||
detail::assign(retval, std::move(attr));
|
||||
} else if constexpr (
|
||||
detail::is_tuple<Attribute>{} ||
|
||||
detail::is_struct_compatible_v<Attribute, result_t>) {
|
||||
} else if constexpr (detail::is_tuple<Attribute>{}) {
|
||||
call_impl(
|
||||
first,
|
||||
last,
|
||||
@@ -3571,9 +3695,9 @@ namespace boost { namespace parser {
|
||||
|
||||
if (!success)
|
||||
detail::assign(retval, Attribute());
|
||||
} else if constexpr (detail::is_constructible_from_tuple_v<
|
||||
Attribute,
|
||||
result_t>) {
|
||||
} else if constexpr (
|
||||
detail::is_struct_compatible_v<Attribute, result_t> ||
|
||||
detail::is_constructible_from_tuple_v<Attribute, result_t>) {
|
||||
result_t temp_retval{};
|
||||
call_impl(
|
||||
first,
|
||||
@@ -3586,10 +3710,16 @@ namespace boost { namespace parser {
|
||||
indices);
|
||||
|
||||
if (success && detail::gen_attrs(flags)) {
|
||||
detail::assign(
|
||||
retval,
|
||||
detail::make_from_tuple<Attribute>(
|
||||
std::move(temp_retval)));
|
||||
if constexpr (detail::is_struct_compatible_v<
|
||||
Attribute,
|
||||
result_t>) {
|
||||
detail::assign(retval, temp_retval);
|
||||
} else {
|
||||
detail::assign(
|
||||
retval,
|
||||
detail::make_from_tuple<Attribute>(
|
||||
std::move(temp_retval)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#if 0 // TODO Seems incompatible with this parser.
|
||||
@@ -4352,11 +4482,11 @@ namespace boost { namespace parser {
|
||||
&success,
|
||||
&retval](auto const &
|
||||
parser_index_merged_and_backtrack) {
|
||||
if (!success) // Someone earlier already failed...
|
||||
return;
|
||||
auto flags = flags_;
|
||||
using namespace literals;
|
||||
detail::skip(first, last, skip, flags);
|
||||
if (!success) // Someone earlier already failed...
|
||||
return;
|
||||
|
||||
auto const & parser =
|
||||
parser::get(parser_index_merged_and_backtrack, 0_c);
|
||||
@@ -4405,7 +4535,8 @@ namespace boost { namespace parser {
|
||||
|
||||
if constexpr (
|
||||
(out_container == attr_container &&
|
||||
!was_merged_into_adjacent_container) ||
|
||||
!was_merged_into_adjacent_container &&
|
||||
!detail::is_nope_v<attr_t>) ||
|
||||
is_in_a_group) {
|
||||
parser.call(
|
||||
first, last, context, skip, flags, success, out);
|
||||
@@ -4431,7 +4562,9 @@ namespace boost { namespace parser {
|
||||
}
|
||||
using just_x = attr_t;
|
||||
using just_out = detail::remove_cv_ref_t<decltype(out)>;
|
||||
if constexpr (
|
||||
if constexpr (detail::is_nope_v<attr_t>) {
|
||||
// nothing to do
|
||||
} else if constexpr (
|
||||
(!out_container ||
|
||||
!std::is_same_v<just_x, just_out>) &&
|
||||
std::is_assignable_v<just_out &, just_x &&> &&
|
||||
@@ -4447,7 +4580,9 @@ namespace boost { namespace parser {
|
||||
|
||||
auto const parsers_and_indices =
|
||||
detail::hl::zip(parsers_, indices, merged, backtracking{});
|
||||
detail::hl::for_each(parsers_and_indices, use_parser);
|
||||
std::apply([&use_parser](auto&&... args) {
|
||||
((use_parser(args)), ...);
|
||||
}, parsers_and_indices);
|
||||
}
|
||||
|
||||
template<bool AllowBacktracking, typename Parser>
|
||||
@@ -4604,7 +4739,7 @@ namespace boost { namespace parser {
|
||||
} else {
|
||||
// If you see an error here, it's because you are using an
|
||||
// invocable for a semantic action that returns a non-void
|
||||
// type Ret, but values fo type Ret is not assignable to
|
||||
// type Ret, but values of type Ret is not assignable to
|
||||
// _val(ctx). To fix this, only use this invocable within
|
||||
// a rule whose attribute type is assignable from Ret, or
|
||||
// remove the non-void return statement(s) from your
|
||||
@@ -5888,7 +6023,7 @@ namespace boost { namespace parser {
|
||||
};
|
||||
|
||||
/** Returns a `parser_interface` with the same parser and error handler,
|
||||
with `globals` added. The resut of passing any non-top-level parser
|
||||
with `globals` added. The result of passing any non-top-level parser
|
||||
for the `parser` argument is undefined. */
|
||||
template<typename Parser, typename GlobalState, typename ErrorHandler>
|
||||
auto with_globals(
|
||||
@@ -5900,7 +6035,7 @@ namespace boost { namespace parser {
|
||||
}
|
||||
|
||||
/** Returns a `parser_interface` with the same parser and globals, with
|
||||
`error_handler` added. The resut of passing any non-top-level parser
|
||||
`error_handler` added. The result of passing any non-top-level parser
|
||||
for the `parser` argument is undefined. */
|
||||
template<typename Parser, typename GlobalState, typename ErrorHandler>
|
||||
auto with_error_handler(
|
||||
@@ -5915,7 +6050,7 @@ namespace boost { namespace parser {
|
||||
|
||||
/** A `symbols<T>` represents the initial state of a symbol table parser
|
||||
that produces attributes of type `T`. The entries in the symbol table
|
||||
can be changed during parsing, but those mutations to not affect the
|
||||
can be changed during parsing, but those mutations do not affect the
|
||||
`symbols<T>` object itself; all mutations happen to a copy of the
|
||||
symbol table in the parse context. For table entries that should be
|
||||
used during every parse, add entries via `add()` or `operator()`. For
|
||||
@@ -6013,7 +6148,7 @@ namespace boost { namespace parser {
|
||||
}
|
||||
|
||||
/** Inserts an entry consisting of a UTF-8 string to match `str`, and
|
||||
an associtated attribute `x`, to the copy of the symbol table
|
||||
an associated attribute `x`, to the copy of the symbol table
|
||||
inside the parse context `context`. */
|
||||
template<typename Context>
|
||||
void insert(Context const & context, std::string_view str, T x) const
|
||||
@@ -6352,7 +6487,7 @@ namespace boost { namespace parser {
|
||||
|
||||
// Directives.
|
||||
|
||||
/** Represents a unparameterized higher-order parser (e.g. `omit_parser`)
|
||||
/** Represents an unparameterized higher-order parser (e.g. `omit_parser`)
|
||||
as a directive (e.g. `omit[other_parser]`). */
|
||||
template<template<class> class Parser>
|
||||
struct directive
|
||||
@@ -6430,7 +6565,7 @@ namespace boost { namespace parser {
|
||||
}
|
||||
|
||||
/** A directive that represents a `perm_parser`, where the items parsed
|
||||
are delimited by `DelimiterParser`,
|
||||
are delimited by `DelimiterParser`
|
||||
(e.g. `delimiter(delimter_parser)[some_perm_parser]`). This directive
|
||||
only applies to `perm_parser`s. */
|
||||
template<typename DelimiterParser>
|
||||
@@ -6569,7 +6704,7 @@ namespace boost { namespace parser {
|
||||
/** Returns a `transform_directive` that uses invocable `F` to do its
|
||||
work. */
|
||||
template<typename F>
|
||||
auto transform(F f)
|
||||
constexpr auto transform(F f)
|
||||
{
|
||||
return transform_directive<F>{std::move(f)};
|
||||
}
|
||||
@@ -7233,7 +7368,7 @@ namespace boost { namespace parser {
|
||||
|
||||
/** The single-character parser. The produced attribute is the type of
|
||||
the matched code point (`char` or `char32_t`). Used as-is, `char_`
|
||||
matches any code point. `char_` can also can be used to create code
|
||||
matches any code point. `char_` can also be used to create code
|
||||
point parsers that match one or more specific code point values, by
|
||||
calling it with: a single value comparable to a code point; a closed
|
||||
range of code point values `[lo, hi]`, or a set of code point values
|
||||
@@ -7244,7 +7379,7 @@ namespace boost { namespace parser {
|
||||
inline constexpr parser_interface<char_parser<detail::nope>> char_;
|
||||
|
||||
/** The code point parser. It produces a `char32_t` attribute. Used
|
||||
as-is, `cp` matches any code point. `cp` can also can be used to
|
||||
as-is, `cp` matches any code point. `cp` can also be used to
|
||||
create code point parsers that match one or more specific code point
|
||||
values, by calling it with: a single value comparable to a code point;
|
||||
a closed range of code point values `[lo, hi]`, or a set of code point
|
||||
@@ -7504,9 +7639,10 @@ namespace boost { namespace parser {
|
||||
|
||||
auto const prev_first = first;
|
||||
|
||||
auto append = [&retval,
|
||||
std::string temp;
|
||||
auto append = [&temp,
|
||||
gen_attrs = detail::gen_attrs(flags)](auto & ctx) {
|
||||
detail::move_back(retval, _attr(ctx), gen_attrs);
|
||||
detail::move_back(temp, _attr(ctx), gen_attrs);
|
||||
};
|
||||
|
||||
auto quote_ch = [&]() {
|
||||
@@ -7564,7 +7700,10 @@ namespace boost { namespace parser {
|
||||
detail::disable_skip(flags),
|
||||
success);
|
||||
|
||||
if (!success) {
|
||||
if (success) {
|
||||
if (detail::gen_attrs(flags))
|
||||
detail::assign(retval, std::move(temp));
|
||||
} else {
|
||||
retval = Attribute();
|
||||
first = prev_first;
|
||||
}
|
||||
@@ -7903,8 +8042,8 @@ namespace boost { namespace parser {
|
||||
few of which are Latin. */
|
||||
inline constexpr parser_interface<digit_parser> digit;
|
||||
|
||||
/** The hexidecimal digit parser. Matches the full set of Unicode
|
||||
hexidecimal digits (upper or lower case); in other words, all Unicode
|
||||
/** The hexadecimal digit parser. Matches the full set of Unicode
|
||||
hexadecimal digits (upper or lower case); in other words, all Unicode
|
||||
code points with the "Hex_Digit" character property. */
|
||||
inline constexpr parser_interface<
|
||||
char_subrange_parser<detail::hex_digit_subranges>>
|
||||
@@ -8390,9 +8529,9 @@ namespace boost { namespace parser {
|
||||
template<typename SwitchValue, typename OrParser>
|
||||
struct switch_parser
|
||||
{
|
||||
switch_parser() {}
|
||||
switch_parser(SwitchValue switch_value) : switch_value_(switch_value) {}
|
||||
switch_parser(SwitchValue switch_value, OrParser or_parser) :
|
||||
constexpr switch_parser() {}
|
||||
constexpr switch_parser(SwitchValue switch_value) : switch_value_(switch_value) {}
|
||||
constexpr switch_parser(SwitchValue switch_value, OrParser or_parser) :
|
||||
switch_value_(switch_value), or_parser_(or_parser)
|
||||
{}
|
||||
|
||||
@@ -9671,7 +9810,7 @@ namespace boost { namespace parser {
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template<typename R, typename Parser>
|
||||
template<typename R, typename Parser, typename SkipParser>
|
||||
struct attribute_impl
|
||||
{
|
||||
using parser_type = typename Parser::parser_type;
|
||||
@@ -9694,7 +9833,7 @@ namespace boost { namespace parser {
|
||||
std::declval<iterator &>(),
|
||||
std::declval<sentinel>(),
|
||||
std::declval<context>(),
|
||||
detail::null_parser{},
|
||||
SkipParser{},
|
||||
detail::flags::gen_attrs,
|
||||
std::declval<bool &>()));
|
||||
};
|
||||
|
||||
@@ -115,7 +115,7 @@ namespace boost { namespace parser {
|
||||
bool & success,
|
||||
int & indent,
|
||||
ErrorHandler const & error_handler,
|
||||
nope &,
|
||||
nope const &,
|
||||
symbol_table_tries_t & symbol_table_tries,
|
||||
pending_symbol_table_operations_t &
|
||||
pending_symbol_table_operations) noexcept;
|
||||
|
||||
@@ -344,6 +344,219 @@ void github_issue_248()
|
||||
}
|
||||
}
|
||||
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
namespace github_issue_268_ {
|
||||
namespace bp = boost::parser;
|
||||
constexpr bp::rule<struct name, std::string_view> name = "name";
|
||||
auto name_def = bp::string_view[bp::lexeme[+(
|
||||
bp::lower | bp::upper | bp::digit | bp::char_("_"))]];
|
||||
BOOST_PARSER_DEFINE_RULES(name)
|
||||
constexpr bp::rule<struct qd_vec, std::vector<double>> qd_vec = "qd_vec";
|
||||
auto qd_vec_def = bp::lit("\"") >>
|
||||
bp::double_ %
|
||||
(bp::lit(",") |
|
||||
(bp::lit("\"") >> bp::lit(",") >> bp::lit("\""))) >>
|
||||
bp::lit('\"');
|
||||
BOOST_PARSER_DEFINE_RULES(qd_vec)
|
||||
struct lu_table_template_1
|
||||
{
|
||||
std::vector<double> index_1;
|
||||
std::string_view variable_1;
|
||||
};
|
||||
constexpr boost::parser::
|
||||
rule<struct lu_table_template_1_tag, lu_table_template_1>
|
||||
lu_table_template_1_rule = "lu_table_template_1";
|
||||
auto lu_table_template_1_rule_def = (bp::lit("index_1") >> '(' >> qd_vec >>
|
||||
')' >> ';') >>
|
||||
(bp::lit("variable_1") >> ':' >> name >>
|
||||
';');
|
||||
BOOST_PARSER_DEFINE_RULES(lu_table_template_1_rule)
|
||||
|
||||
constexpr boost::parser::
|
||||
rule<struct lu_table_template_1_permut_tag, lu_table_template_1>
|
||||
lu_table_template_1_permut_rule = "lu_table_template_1";
|
||||
auto lu_table_template_1_permut_rule_def =
|
||||
(bp::lit("index_1") >> '(' >> qd_vec >> ')' >> ';') ||
|
||||
(bp::lit("variable_1") >> ':' >> name >> ';');
|
||||
BOOST_PARSER_DEFINE_RULES(lu_table_template_1_permut_rule)
|
||||
}
|
||||
#endif
|
||||
|
||||
void github_issue_268()
|
||||
{
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
namespace bp = boost::parser;
|
||||
using namespace github_issue_268_;
|
||||
std::string inputstring = "index_1 ( \"1\" ) ; variable_1 : bier;";
|
||||
|
||||
auto const def_result = bp::parse(
|
||||
inputstring, lu_table_template_1_rule_def, bp::blank, bp::trace::off);
|
||||
std::cout << "seq_parser generates this type:\n"
|
||||
<< typeid(def_result.value()).name() << std::endl;
|
||||
BOOST_TEST(def_result);
|
||||
|
||||
auto const permut_def_result = bp::parse(
|
||||
inputstring,
|
||||
lu_table_template_1_permut_rule_def,
|
||||
bp::blank,
|
||||
bp::trace::off);
|
||||
std::cout << "permut_parser generates this type:\n"
|
||||
<< typeid(permut_def_result.value()).name() << std::endl;
|
||||
BOOST_TEST(permut_def_result);
|
||||
|
||||
auto const result = bp::parse(
|
||||
inputstring, lu_table_template_1_rule, bp::blank, bp::trace::off);
|
||||
std::cout << "seq_parser in rule generates this type:\n"
|
||||
<< typeid(result.value()).name() << std::endl;
|
||||
BOOST_TEST(result);
|
||||
|
||||
auto const permut_result = bp::parse(
|
||||
inputstring,
|
||||
lu_table_template_1_permut_rule,
|
||||
bp::blank,
|
||||
bp::trace::off);
|
||||
std::cout << "permut_parser generates this type:\n"
|
||||
<< typeid(permut_result.value()).name() << std::endl;
|
||||
BOOST_TEST(permut_result);
|
||||
#endif
|
||||
}
|
||||
|
||||
void github_issue_279()
|
||||
{
|
||||
namespace bp = boost::parser;
|
||||
|
||||
{
|
||||
constexpr auto condition_clause =
|
||||
bp::lit(U"while") > bp::lit(U"someexpression") >> bp::attr(true);
|
||||
|
||||
constexpr auto do_statement =
|
||||
bp::lexeme[bp::lit(U"do") >> &bp::ws] > -condition_clause > bp::eol;
|
||||
|
||||
auto const result =
|
||||
bp::parse(U"do\n", do_statement, bp::blank, bp::trace::off);
|
||||
BOOST_TEST(result);
|
||||
std::optional<bool> const & condition = result.value();
|
||||
BOOST_TEST(!condition.has_value());
|
||||
}
|
||||
|
||||
{
|
||||
constexpr auto condition_clause =
|
||||
bp::lit(U"while") > bp::lit(U"someexpression") >> bp::attr(true);
|
||||
|
||||
constexpr auto do_statement_reverse =
|
||||
-condition_clause > bp::lexeme[bp::lit(U"do") >> &bp::ws] > bp::eol;
|
||||
|
||||
auto const result =
|
||||
bp::parse(U"do\n", do_statement_reverse, bp::blank, bp::trace::off);
|
||||
BOOST_TEST(result);
|
||||
std::optional<bool> const & condition = result.value();
|
||||
BOOST_TEST(!condition.has_value());
|
||||
}
|
||||
}
|
||||
|
||||
namespace github_issue_285_ {
|
||||
namespace bp = boost::parser;
|
||||
|
||||
struct Content
|
||||
{
|
||||
~Content()
|
||||
{
|
||||
int setbreakpointhere = 0;
|
||||
(void)setbreakpointhere;
|
||||
}
|
||||
};
|
||||
constexpr bp::rule<struct content_tag, std::shared_ptr<Content>> content =
|
||||
"content";
|
||||
constexpr auto content_action = [](auto & ctx) {
|
||||
std::shared_ptr<Content> & result = _val(ctx);
|
||||
result = std::make_shared<Content>();
|
||||
};
|
||||
constexpr auto content_def =
|
||||
(bp::lit(U"content") >> bp::eol)[content_action];
|
||||
BOOST_PARSER_DEFINE_RULES(content);
|
||||
}
|
||||
|
||||
void github_issue_285()
|
||||
{
|
||||
using namespace github_issue_285_;
|
||||
namespace bp = boost::parser;
|
||||
|
||||
constexpr auto prolog = bp::lit(U"prolog") >> bp::eol;
|
||||
|
||||
constexpr auto epilog =
|
||||
bp::no_case[bp::lexeme[bp::lit(U"epi") >> bp::lit(U"log")]] >> bp::eol;
|
||||
|
||||
constexpr auto full_parser = prolog >> content >> epilog;
|
||||
|
||||
std::string teststring =
|
||||
"prolog\n"
|
||||
"content\n"
|
||||
"epilog\n";
|
||||
|
||||
// "content" produces a shared_ptr with the result.
|
||||
// The "epilog" parser must not delete the result.
|
||||
|
||||
auto const result = bp::parse(teststring, full_parser, bp::blank);
|
||||
BOOST_TEST(result);
|
||||
BOOST_TEST(result.value().get() != nullptr);
|
||||
}
|
||||
|
||||
void github_pr_290()
|
||||
{
|
||||
namespace bp = boost::parser;
|
||||
|
||||
auto const pTest = bp::lit("TEST:") > -bp::quoted_string;
|
||||
|
||||
auto result = bp::parse("TEST: \"foo\"", pTest, bp::blank);
|
||||
BOOST_TEST(result);
|
||||
BOOST_TEST(*result == "foo");
|
||||
}
|
||||
|
||||
namespace github_pr_297_ {
|
||||
namespace bp = boost::parser;
|
||||
constexpr auto bar_required_f = [](auto& ctx) -> bool {
|
||||
const bool& argument = bp::_p<0>(ctx);
|
||||
return argument;
|
||||
};
|
||||
constexpr bp::rule<struct foobar_parser_tag> foobar_parser = "foobar_parser";
|
||||
constexpr auto foobar_parser_def =
|
||||
bp::lit("foo")
|
||||
>> bp::switch_(bar_required_f)
|
||||
(true, bp::lit("bar"))
|
||||
(false, -bp::lit("bar"));
|
||||
BOOST_PARSER_DEFINE_RULES(foobar_parser);
|
||||
}
|
||||
|
||||
void github_pr_297()
|
||||
{
|
||||
namespace bp = boost::parser;
|
||||
using namespace github_pr_297_;
|
||||
|
||||
{
|
||||
const bool bar_required = true;
|
||||
const bool result =
|
||||
bp::parse("foo bar", foobar_parser.with(bar_required), bp::blank);
|
||||
BOOST_TEST(result);
|
||||
}
|
||||
{
|
||||
const bool bar_required = true;
|
||||
const bool result =
|
||||
bp::parse("foo", foobar_parser.with(bar_required), bp::blank);
|
||||
BOOST_TEST(!result);
|
||||
}
|
||||
{
|
||||
const bool bar_required = false;
|
||||
const bool result =
|
||||
bp::parse("foo bar", foobar_parser.with(bar_required), bp::blank);
|
||||
BOOST_TEST(result);
|
||||
}
|
||||
{
|
||||
const bool bar_required = false;
|
||||
const bool result =
|
||||
bp::parse("foo", foobar_parser.with(bar_required), bp::blank);
|
||||
BOOST_TEST(result);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
@@ -356,5 +569,10 @@ int main()
|
||||
github_issue_209();
|
||||
github_issue_223();
|
||||
github_issue_248();
|
||||
github_issue_268();
|
||||
github_issue_279();
|
||||
github_issue_285();
|
||||
github_pr_290();
|
||||
github_pr_297();
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user