@@ -1609,25 +1609,80 @@ namespace boost { namespace parser {
16091609 V base_;
16101610 };
16111611
1612+ enum class symbol_table_op { insert, erase, clear };
1613+
1614+ template <typename T>
1615+ struct symbol_table_operation
1616+ {
1617+ std::string key_;
1618+ std::optional<T> value_;
1619+ symbol_table_op kind_;
1620+ };
1621+
1622+ template <typename T>
1623+ void apply_symbol_table_operations (
1624+ std::vector<std::pair<std::string, T>> & initial_elements,
1625+ std::vector<symbol_table_operation<T>> & pending_operations)
1626+ {
1627+ auto lower_bound = [&initial_elements](std::string const & str) {
1628+ return std::lower_bound (
1629+ initial_elements.begin (),
1630+ initial_elements.end (),
1631+ str,
1632+ [&str](auto const & a, auto b) {
1633+ return a.first < b;
1634+ });
1635+ };
1636+
1637+ for (auto & op : pending_operations) {
1638+ if (op.kind_ == symbol_table_op::insert) {
1639+ auto it = lower_bound (op.key_ );
1640+ if (it == initial_elements.end () ||
1641+ it->first != op.key_ ) {
1642+ initial_elements.insert (
1643+ it,
1644+ std::pair<std::string, T>(
1645+ std::move (op.key_ ), std::move (*op.value_ )));
1646+ } else {
1647+ it->second = std::move (*op.value_ );
1648+ }
1649+ } else if (op.kind_ == symbol_table_op::erase) {
1650+ auto it = lower_bound (op.key_ );
1651+ if (it != initial_elements.end () && it->first == op.key_ )
1652+ initial_elements.erase (it);
1653+ } else {
1654+ initial_elements.clear ();
1655+ }
1656+ }
1657+
1658+ pending_operations.clear ();
1659+ }
1660+
16121661 template <typename Context, typename T>
16131662 auto get_trie (
1614- Context const & context, symbol_parser<T> const & symbol_parser )
1663+ Context const & context, symbol_parser<T> const & sym_parser )
16151664 {
16161665 using trie_t = text::trie_map<std::vector<char32_t >, T>;
16171666 using result_type = std::pair<trie_t &, bool >;
16181667 symbol_table_tries_t & symbol_table_tries =
16191668 *context.symbol_table_tries_ ;
16201669
1621- auto & [any, has_case_folded] =
1622- symbol_table_tries[(void *)&symbol_parser ];
1670+ auto & [any, has_case_folded, pending_ops ] =
1671+ symbol_table_tries[(void *)&sym_parser. ref () ];
16231672
16241673 bool const needs_case_folded = context.no_case_depth_ ;
16251674
16261675 if (!any.has_value ()) {
16271676 any = trie_t {};
16281677 has_case_folded = false ;
16291678 trie_t & trie = *std::any_cast<trie_t >(&any);
1630- for (auto const & e : symbol_parser.initial_elements ()) {
1679+ if (pending_ops) {
1680+ detail::apply_symbol_table_operations (
1681+ sym_parser.initial_elements (),
1682+ sym_parser.pending_operations ());
1683+ pending_ops = false ;
1684+ }
1685+ for (auto const & e : sym_parser.initial_elements ()) {
16311686 trie.insert (e.first | text::as_utf32, e.second );
16321687 if (needs_case_folded) {
16331688 trie.insert (
@@ -2153,6 +2208,67 @@ namespace boost { namespace parser {
21532208 Iter & it_;
21542209 };
21552210
2211+ template <typename Parser>
2212+ using has_parser_data_member_expr =
2213+ decltype (std::declval<Parser>().parser_);
2214+ template <typename Parser>
2215+ constexpr bool has_parser_data_member_v =
2216+ is_detected_v<has_parser_data_member_expr, Parser>;
2217+
2218+ template <typename Parser>
2219+ using has_parsers_data_member_expr =
2220+ decltype (std::declval<Parser>().parsers_);
2221+ template <typename Parser>
2222+ constexpr bool has_parsers_data_member_v =
2223+ is_detected_v<has_parsers_data_member_expr, Parser>;
2224+
2225+ template <typename Context, typename Parser>
2226+ void visit_symbol_table_parsers_impl (
2227+ Context & context, Parser const & p);
2228+
2229+ template <typename Context, typename Parser>
2230+ void visit_symbol_table_parser (Context & context, Parser const & p)
2231+ {
2232+ if constexpr (has_parser_data_member_v<Parser>) {
2233+ detail::visit_symbol_table_parsers_impl (context, p.parser_ );
2234+ }
2235+ }
2236+ template <typename Context, typename T>
2237+ void visit_symbol_table_parser (
2238+ Context & context, symbol_parser<T> const & p)
2239+ {
2240+ auto & [_, has_case_folded, pending_ops] =
2241+ (*context.symbol_table_tries_ )[(void *)&p.ref ()];
2242+ has_case_folded = false ;
2243+ pending_ops = !p.pending_operations ().empty ();
2244+ }
2245+
2246+ template <typename Context, typename Parser>
2247+ void visit_symbol_table_parsers_impl (
2248+ Context & context, Parser const & p)
2249+ {
2250+ if constexpr (has_parsers_data_member_v<Parser>) {
2251+ auto visit = [&context](auto & parser) {
2252+ detail::visit_symbol_table_parsers_impl (context, parser);
2253+ };
2254+ detail::hl::for_each (p.parsers_ , visit);
2255+ } else {
2256+ detail::visit_symbol_table_parser (context, p);
2257+ }
2258+ }
2259+
2260+ template <
2261+ typename Context,
2262+ typename Parser,
2263+ typename GlobalState,
2264+ typename ErrorHandler>
2265+ void visit_symbol_table_parsers (
2266+ Context & context,
2267+ parser_interface<Parser, GlobalState, ErrorHandler> const & p)
2268+ {
2269+ detail::visit_symbol_table_parsers_impl (context, p.parser_ );
2270+ }
2271+
21562272 template <
21572273 bool Debug,
21582274 typename Iter,
@@ -2179,6 +2295,7 @@ namespace boost { namespace parser {
21792295 error_handler,
21802296 parser.globals_ ,
21812297 symbol_table_tries);
2298+ detail::visit_symbol_table_parsers (context, parser);
21822299 auto const flags =
21832300 Debug ? detail::enable_trace (detail::flags::gen_attrs)
21842301 : detail::flags::gen_attrs;
@@ -2227,6 +2344,7 @@ namespace boost { namespace parser {
22272344 error_handler,
22282345 parser.globals_ ,
22292346 symbol_table_tries);
2347+ detail::visit_symbol_table_parsers (context, parser);
22302348 auto const flags =
22312349 Debug ? detail::enable_trace (detail::flags::gen_attrs)
22322350 : detail::flags::gen_attrs;
@@ -2281,6 +2399,7 @@ namespace boost { namespace parser {
22812399 callbacks,
22822400 parser.globals_ ,
22832401 symbol_table_tries);
2402+ detail::visit_symbol_table_parsers (context, parser);
22842403 auto const flags =
22852404 Debug ? detail::enable_trace (detail::flags::gen_attrs)
22862405 : detail::flags::gen_attrs;
@@ -2332,6 +2451,7 @@ namespace boost { namespace parser {
23322451 error_handler,
23332452 parser.globals_ ,
23342453 symbol_table_tries);
2454+ detail::visit_symbol_table_parsers (context, parser);
23352455 auto const flags =
23362456 Debug ? detail::enable_trace (detail::default_flags ())
23372457 : detail::default_flags ();
@@ -2377,6 +2497,7 @@ namespace boost { namespace parser {
23772497 error_handler,
23782498 parser.globals_ ,
23792499 symbol_table_tries);
2500+ detail::visit_symbol_table_parsers (context, parser);
23802501 auto const flags =
23812502 Debug ? detail::enable_trace (detail::default_flags ())
23822503 : detail::default_flags ();
@@ -2430,6 +2551,7 @@ namespace boost { namespace parser {
24302551 callbacks,
24312552 parser.globals_ ,
24322553 symbol_table_tries);
2554+ detail::visit_symbol_table_parsers (context, parser);
24332555 auto const flags =
24342556 Debug ? detail::enable_trace (detail::default_flags ())
24352557 : detail::default_flags ();
@@ -4976,6 +5098,15 @@ namespace boost { namespace parser {
49765098 }
49775099 }
49785100
5101+ /* * Erases the entry whose UTF-8 match string is `str` from the copy
5102+ of the symbol table inside the parse context `context`. */
5103+ template <typename Context>
5104+ void clear (Context const & context) const
5105+ {
5106+ auto [trie, _] = detail::get_trie (context, ref ());
5107+ trie.clear ();
5108+ }
5109+
49795110 template <
49805111 typename Iter,
49815112 typename Sentinel,
@@ -5025,7 +5156,9 @@ namespace boost { namespace parser {
50255156 }
50265157 }
50275158
5028- std::vector<std::pair<std::string_view, T>> initial_elements_;
5159+ mutable std::vector<std::pair<std::string, T>> initial_elements_;
5160+ mutable std::vector<detail::symbol_table_operation<T>>
5161+ pending_operations_;
50295162 symbol_parser const * copied_from_;
50305163
50315164 symbol_parser const & ref () const noexcept
@@ -5034,11 +5167,16 @@ namespace boost { namespace parser {
50345167 return *copied_from_;
50355168 return *this ;
50365169 }
5037- std::vector<std::pair<std::string_view , T>> const &
5170+ std::vector<std::pair<std::string , T>> &
50385171 initial_elements () const noexcept
50395172 {
50405173 return ref ().initial_elements_ ;
50415174 }
5175+ std::vector<detail::symbol_table_operation<T>> &
5176+ pending_operations () const noexcept
5177+ {
5178+ return ref ().pending_operations_ ;
5179+ }
50425180
50435181 std::string_view diagnostic_text_;
50445182 };
@@ -5598,30 +5736,59 @@ namespace boost { namespace parser {
55985736 {}
55995737 symbols (std::initializer_list<std::pair<std::string_view, T>> il)
56005738 {
5601- this ->parser_ .initial_elements_ = il;
5739+ this ->parser_ .initial_elements_ .resize (il.size ());
5740+ std::copy (il.begin (), il.end (),
5741+ this ->parser_ .initial_elements_ .begin ());
56025742 }
56035743 symbols (
56045744 char const * diagnostic_text,
56055745 std::initializer_list<std::pair<std::string_view, T>> il) :
56065746 parser_interface<symbol_parser<T>>(
56075747 symbol_parser<T>(diagnostic_text))
56085748 {
5609- this ->parser_ .initial_elements_ = il;
5749+ this ->parser_ .initial_elements_ .resize (il.size ());
5750+ std::copy (il.begin (), il.end (),
5751+ this ->parser_ .initial_elements_ .begin ());
56105752 }
56115753
56125754 using parser_interface<symbol_parser<T>>::operator ();
56135755
5614- /* * Adds an entry consisting of a UTF-8 string `str` to match, and an
5615- associated attribute `x`, to `*this`. The entry is added for use
5616- in all subsequent top-level parses. Subsequent lookups during the
5617- current top-level parse will not match `str`. */
5756+ /* * Inserts an entry consisting of a UTF-8 string `str` to match, and
5757+ an associated attribute `x`, to `*this`. The entry is added for
5758+ use in all subsequent top-level parses. Subsequent lookups during
5759+ the current top-level parse will not necessarily match `str`. */
56185760 symbols & insert_for_next_parse (std::string_view str, T x)
56195761 {
5620- this ->parser_ .initial_elements_ .push_back (
5621- std::pair<std::string_view, T>(str, std::move (x)));
5762+ this ->parser_ .pending_operations ().push_back (
5763+ detail::symbol_table_operation<T>{
5764+ std::string (str),
5765+ std::move (x),
5766+ detail::symbol_table_op::insert});
56225767 return *this ;
56235768 }
56245769
5770+ /* * Erases the entry whose UTF-8 match string is `str`, from `*this`.
5771+ The entry will no longer be available for use in all subsequent
5772+ top-level parses. `str` will not be removed from the symbols
5773+ matched in the current top-level parse. */
5774+ void erase_for_next_parse (std::string_view str)
5775+ {
5776+ this ->parser_ .pending_operations ().push_back (
5777+ detail::symbol_table_operation<T>{
5778+ std::string (str),
5779+ std::nullopt ,
5780+ detail::symbol_table_op::erase});
5781+ }
5782+
5783+ /* * Erases all the entries from the copy of the symbol table inside
5784+ the parse context `context`. */
5785+ void clear_for_next_parse ()
5786+ {
5787+ this ->parser_ .pending_operations ().push_back (
5788+ detail::symbol_table_operation<T>{
5789+ {}, std::nullopt , detail::symbol_table_op::clear});
5790+ }
5791+
56255792 /* * Equivalent to `insert_for_next_parse(str, std::move(x))`. */
56265793 symbols & operator ()(std::string_view str, T x)
56275794 {
@@ -5655,7 +5822,15 @@ namespace boost { namespace parser {
56555822 {
56565823 this ->parser_ .erase (context, str);
56575824 }
5658- };
5825+
5826+ /* * Erases all the entries from the copy of the symbol table inside
5827+ the parse context `context`. */
5828+ template <typename Context>
5829+ void clear (Context const & context) const
5830+ {
5831+ this ->parser_ .clear (context);
5832+ }
5833+ };
56595834
56605835#ifndef BOOST_PARSER_DOXYGEN
56615836
0 commit comments