LCOV - code coverage report
Current view: top level - 11/bits - regex_compiler.tcc (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 241 304 79.3 %
Date: 2025-08-24 09:11:10 Functions: 26 52 50.0 %

          Line data    Source code
       1             : // class template regex -*- C++ -*-
       2             : 
       3             : // Copyright (C) 2013-2021 Free Software Foundation, Inc.
       4             : //
       5             : // This file is part of the GNU ISO C++ Library.  This library is free
       6             : // software; you can redistribute it and/or modify it under the
       7             : // terms of the GNU General Public License as published by the
       8             : // Free Software Foundation; either version 3, or (at your option)
       9             : // any later version.
      10             : 
      11             : // This library is distributed in the hope that it will be useful,
      12             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             : // GNU General Public License for more details.
      15             : 
      16             : // Under Section 7 of GPL version 3, you are granted additional
      17             : // permissions described in the GCC Runtime Library Exception, version
      18             : // 3.1, as published by the Free Software Foundation.
      19             : 
      20             : // You should have received a copy of the GNU General Public License and
      21             : // a copy of the GCC Runtime Library Exception along with this program;
      22             : // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
      23             : // <http://www.gnu.org/licenses/>.
      24             : 
      25             : /**
      26             :  *  @file bits/regex_compiler.tcc
      27             :  *  This is an internal header file, included by other library headers.
      28             :  *  Do not attempt to use it directly. @headername{regex}
      29             :  */
      30             : 
      31             : // FIXME make comments doxygen format.
      32             : 
      33             : /*
      34             : // This compiler refers to "Regular Expression Matching Can Be Simple And Fast"
      35             : // (http://swtch.com/~rsc/regexp/regexp1.html),
      36             : // but doesn't strictly follow it.
      37             : //
      38             : // When compiling, states are *chained* instead of tree- or graph-constructed.
      39             : // It's more like structured programs: there's if statement and loop statement.
      40             : //
      41             : // For alternative structure (say "a|b"), aka "if statement", two branches
      42             : // should be constructed. However, these two shall merge to an "end_tag" at
      43             : // the end of this operator:
      44             : //
      45             : //                branch1
      46             : //              /        \
      47             : // => begin_tag            end_tag =>
      48             : //              \        /
      49             : //                branch2
      50             : //
      51             : // This is the difference between this implementation and that in Russ's
      52             : // article.
      53             : //
      54             : // That's why we introduced dummy node here ------ "end_tag" is a dummy node.
      55             : // All dummy nodes will be eliminated at the end of compilation.
      56             : */
      57             : 
      58             : namespace std _GLIBCXX_VISIBILITY(default)
      59             : {
      60             : _GLIBCXX_BEGIN_NAMESPACE_VERSION
      61             : 
      62             : namespace __detail
      63             : {
      64             :   template<typename _TraitsT>
      65         368 :     _Compiler<_TraitsT>::
      66             :     _Compiler(const _CharT* __b, const _CharT* __e,
      67             :               const typename _TraitsT::locale_type& __loc, _FlagT __flags)
      68         368 :     : _M_flags(_S_validate(__flags)),
      69         368 :       _M_scanner(__b, __e, _M_flags, __loc),
      70         368 :       _M_nfa(make_shared<_RegexT>(__loc, _M_flags)),
      71         368 :       _M_traits(_M_nfa->_M_traits),
      72         736 :       _M_ctype(std::use_facet<_CtypeT>(__loc))
      73             :     {
      74         368 :       _StateSeqT __r(*_M_nfa, _M_nfa->_M_start());
      75         368 :       __r._M_append(_M_nfa->_M_insert_subexpr_begin());
      76         368 :       this->_M_disjunction();
      77         368 :       if (!_M_match_token(_ScannerT::_S_token_eof))
      78           0 :         __throw_regex_error(regex_constants::error_paren);
      79         368 :       __r._M_append(_M_pop());
      80         368 :       __glibcxx_assert(_M_stack.empty());
      81         368 :       __r._M_append(_M_nfa->_M_insert_subexpr_end());
      82         368 :       __r._M_append(_M_nfa->_M_insert_accept());
      83         368 :       _M_nfa->_M_eliminate_dummy();
      84         368 :     }
      85             : 
      86             :   template<typename _TraitsT>
      87             :     void
      88        1196 :     _Compiler<_TraitsT>::
      89             :     _M_disjunction()
      90             :     {
      91        1196 :       this->_M_alternative();
      92        1524 :       while (_M_match_token(_ScannerT::_S_token_or))
      93             :         {
      94         328 :           _StateSeqT __alt1 = _M_pop();
      95         328 :           this->_M_alternative();
      96         328 :           _StateSeqT __alt2 = _M_pop();
      97         328 :           auto __end = _M_nfa->_M_insert_dummy();
      98         328 :           __alt1._M_append(__end);
      99         328 :           __alt2._M_append(__end);
     100             :           // __alt2 is state._M_next, __alt1 is state._M_alt. The executor
     101             :           // executes _M_alt before _M_next, as well as executing left
     102             :           // alternative before right one.
     103         328 :           _M_stack.push(_StateSeqT(*_M_nfa,
     104         328 :                                    _M_nfa->_M_insert_alt(
     105             :                                      __alt2._M_start, __alt1._M_start, false),
     106             :                                    __end));
     107             :         }
     108        1196 :     }
     109             : 
     110             :   template<typename _TraitsT>
     111             :     void
     112        7416 :     _Compiler<_TraitsT>::
     113             :     _M_alternative()
     114             :     {
     115        7416 :       if (this->_M_term())
     116             :         {
     117        5892 :           _StateSeqT __re = _M_pop();
     118        5892 :           this->_M_alternative();
     119        5892 :           __re._M_append(_M_pop());
     120        5892 :           _M_stack.push(__re);
     121             :         }
     122             :       else
     123        1524 :         _M_stack.push(_StateSeqT(*_M_nfa, _M_nfa->_M_insert_dummy()));
     124        7416 :     }
     125             : 
     126             :   template<typename _TraitsT>
     127             :     bool
     128        7416 :     _Compiler<_TraitsT>::
     129             :     _M_term()
     130             :     {
     131        7416 :       if (this->_M_assertion())
     132         181 :         return true;
     133        7235 :       if (this->_M_atom())
     134             :         {
     135        6794 :           while (this->_M_quantifier())
     136             :             ;
     137        5711 :           return true;
     138             :         }
     139        1524 :       return false;
     140             :     }
     141             : 
     142             :   template<typename _TraitsT>
     143             :     bool
     144        7416 :     _Compiler<_TraitsT>::
     145             :     _M_assertion()
     146             :     {
     147        7416 :       if (_M_match_token(_ScannerT::_S_token_line_begin))
     148          96 :         _M_stack.push(_StateSeqT(*_M_nfa, _M_nfa->_M_insert_line_begin()));
     149        7320 :       else if (_M_match_token(_ScannerT::_S_token_line_end))
     150          85 :         _M_stack.push(_StateSeqT(*_M_nfa, _M_nfa->_M_insert_line_end()));
     151        7235 :       else if (_M_match_token(_ScannerT::_S_token_word_bound))
     152             :         // _M_value[0] == 'n' means it's negative, say "not word boundary".
     153           0 :         _M_stack.push(_StateSeqT(*_M_nfa, _M_nfa->
     154           0 :               _M_insert_word_bound(_M_value[0] == 'n')));
     155        7235 :       else if (_M_match_token(_ScannerT::_S_token_subexpr_lookahead_begin))
     156             :         {
     157           0 :           auto __neg = _M_value[0] == 'n';
     158           0 :           this->_M_disjunction();
     159           0 :           if (!_M_match_token(_ScannerT::_S_token_subexpr_end))
     160           0 :             __throw_regex_error(regex_constants::error_paren,
     161             :                                 "Parenthesis is not closed.");
     162           0 :           auto __tmp = _M_pop();
     163           0 :           __tmp._M_append(_M_nfa->_M_insert_accept());
     164           0 :           _M_stack.push(
     165           0 :               _StateSeqT(
     166           0 :                 *_M_nfa,
     167           0 :                 _M_nfa->_M_insert_lookahead(__tmp._M_start, __neg)));
     168             :         }
     169             :       else
     170        7235 :         return false;
     171         181 :       return true;
     172             :     }
     173             : 
     174             :   template<typename _TraitsT>
     175             :     bool
     176        6794 :     _Compiler<_TraitsT>::
     177             :     _M_quantifier()
     178             :     {
     179        6794 :       bool __neg = (_M_flags & regex_constants::ECMAScript);
     180       10710 :       auto __init = [this, &__neg]()
     181             :         {
     182         979 :           if (_M_stack.empty())
     183           0 :             __throw_regex_error(regex_constants::error_badrepeat,
     184             :                                 "Nothing to repeat before a quantifier.");
     185         979 :           __neg = __neg && _M_match_token(_ScannerT::_S_token_opt);
     186             :         };
     187        6794 :       if (_M_match_token(_ScannerT::_S_token_closure0))
     188             :         {
     189         111 :           __init();
     190         111 :           auto __e = _M_pop();
     191         111 :           _StateSeqT __r(*_M_nfa,
     192         111 :                          _M_nfa->_M_insert_repeat(_S_invalid_state_id,
     193             :                                                   __e._M_start, __neg));
     194         111 :           __e._M_append(__r);
     195         111 :           _M_stack.push(__r);
     196             :         }
     197        6683 :       else if (_M_match_token(_ScannerT::_S_token_closure1))
     198             :         {
     199         548 :           __init();
     200         548 :           auto __e = _M_pop();
     201         548 :           __e._M_append(_M_nfa->_M_insert_repeat(_S_invalid_state_id,
     202             :                                                  __e._M_start, __neg));
     203         548 :           _M_stack.push(__e);
     204             :         }
     205        6135 :       else if (_M_match_token(_ScannerT::_S_token_opt))
     206             :         {
     207         320 :           __init();
     208         320 :           auto __e = _M_pop();
     209         320 :           auto __end = _M_nfa->_M_insert_dummy();
     210         320 :           _StateSeqT __r(*_M_nfa,
     211         320 :                          _M_nfa->_M_insert_repeat(_S_invalid_state_id,
     212             :                                                   __e._M_start, __neg));
     213         320 :           __e._M_append(__end);
     214         320 :           __r._M_append(__end);
     215         320 :           _M_stack.push(__r);
     216             :         }
     217        5815 :       else if (_M_match_token(_ScannerT::_S_token_interval_begin))
     218             :         {
     219         104 :           if (_M_stack.empty())
     220           0 :             __throw_regex_error(regex_constants::error_badrepeat,
     221             :                                 "Nothing to repeat before a quantifier.");
     222         104 :           if (!_M_match_token(_ScannerT::_S_token_dup_count))
     223           0 :             __throw_regex_error(regex_constants::error_badbrace,
     224             :                                 "Unexpected token in brace expression.");
     225         104 :           _StateSeqT __r(_M_pop());
     226         104 :           _StateSeqT __e(*_M_nfa, _M_nfa->_M_insert_dummy());
     227         104 :           long __min_rep = _M_cur_int_value(10);
     228         104 :           bool __infi = false;
     229         104 :           long __n = 0;
     230             : 
     231             :           // {3
     232         104 :           if (_M_match_token(_ScannerT::_S_token_comma))
     233             :             {
     234         104 :               if (_M_match_token(_ScannerT::_S_token_dup_count)) // {3,7}
     235         104 :                 __n = _M_cur_int_value(10) - __min_rep;
     236             :               else
     237           0 :                 __infi = true;
     238             :             }
     239         104 :           if (!_M_match_token(_ScannerT::_S_token_interval_end))
     240           0 :             __throw_regex_error(regex_constants::error_brace,
     241             :                                 "Unexpected end of brace expression.");
     242             : 
     243         104 :           __neg = __neg && _M_match_token(_ScannerT::_S_token_opt);
     244             : 
     245         208 :           for (long __i = 0; __i < __min_rep; ++__i)
     246         104 :             __e._M_append(__r._M_clone());
     247             : 
     248         104 :           if (__infi)
     249             :             {
     250           0 :               auto __tmp = __r._M_clone();
     251           0 :               _StateSeqT __s(*_M_nfa,
     252           0 :                              _M_nfa->_M_insert_repeat(_S_invalid_state_id,
     253             :                                                       __tmp._M_start, __neg));
     254           0 :               __tmp._M_append(__s);
     255           0 :               __e._M_append(__s);
     256             :             }
     257             :           else
     258             :             {
     259         104 :               if (__n < 0)
     260           0 :                 __throw_regex_error(regex_constants::error_badbrace,
     261             :                                     "Invalid range in brace expression.");
     262         104 :               auto __end = _M_nfa->_M_insert_dummy();
     263             :               // _M_alt is the "match more" branch, and _M_next is the
     264             :               // "match less" one. Switch _M_alt and _M_next of all created
     265             :               // nodes. This is a hack but IMO works well.
     266         104 :               std::stack<_StateIdT> __stack;
     267        5380 :               for (long __i = 0; __i < __n; ++__i)
     268             :                 {
     269        5276 :                   auto __tmp = __r._M_clone();
     270        5276 :                   auto __alt = _M_nfa->_M_insert_repeat(__tmp._M_start,
     271             :                                                         __end, __neg);
     272        5276 :                   __stack.push(__alt);
     273        5276 :                   __e._M_append(_StateSeqT(*_M_nfa, __alt, __tmp._M_end));
     274             :                 }
     275         104 :               __e._M_append(__end);
     276        5380 :               while (!__stack.empty())
     277             :                 {
     278        5276 :                   auto& __tmp = (*_M_nfa)[__stack.top()];
     279        5276 :                   __stack.pop();
     280        5276 :                   std::swap(__tmp._M_next, __tmp._M_alt);
     281             :                 }
     282         104 :             }
     283         104 :           _M_stack.push(__e);
     284             :         }
     285             :       else
     286        5711 :         return false;
     287        1083 :       return true;
     288             :     }
     289             : 
     290             : #define __INSERT_REGEX_MATCHER(__func, ...)\
     291             :         do {\
     292             :           if (!(_M_flags & regex_constants::icase))\
     293             :             if (!(_M_flags & regex_constants::collate))\
     294             :               __func<false, false>(__VA_ARGS__);\
     295             :             else\
     296             :               __func<false, true>(__VA_ARGS__);\
     297             :           else\
     298             :             if (!(_M_flags & regex_constants::collate))\
     299             :               __func<true, false>(__VA_ARGS__);\
     300             :             else\
     301             :               __func<true, true>(__VA_ARGS__);\
     302             :         } while (false)
     303             : 
     304             :   template<typename _TraitsT>
     305             :     bool
     306        7235 :     _Compiler<_TraitsT>::
     307             :     _M_atom()
     308             :     {
     309        7235 :       if (_M_match_token(_ScannerT::_S_token_anychar))
     310             :         {
     311         347 :           if (!(_M_flags & regex_constants::ECMAScript))
     312           0 :             __INSERT_REGEX_MATCHER(_M_insert_any_matcher_posix);
     313             :           else
     314         347 :             __INSERT_REGEX_MATCHER(_M_insert_any_matcher_ecma);
     315             :         }
     316        6888 :       else if (_M_try_char())
     317        4047 :         __INSERT_REGEX_MATCHER(_M_insert_char_matcher);
     318        2841 :       else if (_M_match_token(_ScannerT::_S_token_backref))
     319           0 :         _M_stack.push(_StateSeqT(*_M_nfa, _M_nfa->
     320           0 :                                  _M_insert_backref(_M_cur_int_value(10))));
     321        2841 :       else if (_M_match_token(_ScannerT::_S_token_quoted_class))
     322          89 :         __INSERT_REGEX_MATCHER(_M_insert_character_class_matcher);
     323        2752 :       else if (_M_match_token(_ScannerT::_S_token_subexpr_no_group_begin))
     324             :         {
     325         141 :           _StateSeqT __r(*_M_nfa, _M_nfa->_M_insert_dummy());
     326         141 :           this->_M_disjunction();
     327         141 :           if (!_M_match_token(_ScannerT::_S_token_subexpr_end))
     328           0 :             __throw_regex_error(regex_constants::error_paren,
     329             :                                 "Parenthesis is not closed.");
     330         141 :           __r._M_append(_M_pop());
     331         141 :           _M_stack.push(__r);
     332             :         }
     333        2611 :       else if (_M_match_token(_ScannerT::_S_token_subexpr_begin))
     334             :         {
     335         687 :           _StateSeqT __r(*_M_nfa, _M_nfa->_M_insert_subexpr_begin());
     336         687 :           this->_M_disjunction();
     337         687 :           if (!_M_match_token(_ScannerT::_S_token_subexpr_end))
     338           0 :             __throw_regex_error(regex_constants::error_paren,
     339             :                                 "Parenthesis is not closed.");
     340         687 :           __r._M_append(_M_pop());
     341         687 :           __r._M_append(_M_nfa->_M_insert_subexpr_end());
     342         687 :           _M_stack.push(__r);
     343             :         }
     344        1924 :       else if (!_M_bracket_expression())
     345        1524 :         return false;
     346        5711 :       return true;
     347             :     }
     348             : 
     349             :   template<typename _TraitsT>
     350             :     bool
     351        1924 :     _Compiler<_TraitsT>::
     352             :     _M_bracket_expression()
     353             :     {
     354             :       bool __neg =
     355        1924 :         _M_match_token(_ScannerT::_S_token_bracket_neg_begin);
     356        1924 :       if (!(__neg || _M_match_token(_ScannerT::_S_token_bracket_begin)))
     357        1524 :         return false;
     358         400 :       __INSERT_REGEX_MATCHER(_M_insert_bracket_matcher, __neg);
     359         400 :       return true;
     360             :     }
     361             : #undef __INSERT_REGEX_MATCHER
     362             : 
     363             :   template<typename _TraitsT>
     364             :   template<bool __icase, bool __collate>
     365             :     void
     366         347 :     _Compiler<_TraitsT>::
     367             :     _M_insert_any_matcher_ecma()
     368             :     {
     369         347 :       _M_stack.push(_StateSeqT(*_M_nfa,
     370         347 :         _M_nfa->_M_insert_matcher
     371         347 :           (_AnyMatcher<_TraitsT, true, __icase, __collate>
     372             :             (_M_traits))));
     373         347 :     }
     374             : 
     375             :   template<typename _TraitsT>
     376             :   template<bool __icase, bool __collate>
     377             :     void
     378           0 :     _Compiler<_TraitsT>::
     379             :     _M_insert_any_matcher_posix()
     380             :     {
     381           0 :       _M_stack.push(_StateSeqT(*_M_nfa,
     382           0 :         _M_nfa->_M_insert_matcher
     383           0 :           (_AnyMatcher<_TraitsT, false, __icase, __collate>
     384             :             (_M_traits))));
     385           0 :     }
     386             : 
     387             :   template<typename _TraitsT>
     388             :   template<bool __icase, bool __collate>
     389             :     void
     390        4047 :     _Compiler<_TraitsT>::
     391             :     _M_insert_char_matcher()
     392             :     {
     393        4047 :       _M_stack.push(_StateSeqT(*_M_nfa,
     394        4047 :         _M_nfa->_M_insert_matcher
     395       12141 :           (_CharMatcher<_TraitsT, __icase, __collate>
     396        4047 :             (_M_value[0], _M_traits))));
     397        4047 :     }
     398             : 
     399             :   template<typename _TraitsT>
     400             :   template<bool __icase, bool __collate>
     401             :     void
     402          89 :     _Compiler<_TraitsT>::
     403             :     _M_insert_character_class_matcher()
     404             :     {
     405          89 :       __glibcxx_assert(_M_value.size() == 1);
     406          89 :       _BracketMatcher<__icase, __collate> __matcher
     407          89 :         (_M_ctype.is(_CtypeT::upper, _M_value[0]), _M_traits);
     408          89 :       __matcher._M_add_character_class(_M_value, false);
     409          89 :       __matcher._M_ready();
     410          89 :       _M_stack.push(_StateSeqT(*_M_nfa,
     411          89 :         _M_nfa->_M_insert_matcher(std::move(__matcher))));
     412          89 :     }
     413             : 
     414             :   template<typename _TraitsT>
     415             :   template<bool __icase, bool __collate>
     416             :     void
     417         400 :     _Compiler<_TraitsT>::
     418             :     _M_insert_bracket_matcher(bool __neg)
     419             :     {
     420         400 :       _BracketMatcher<__icase, __collate> __matcher(__neg, _M_traits);
     421         400 :       _BracketState __last_char;
     422         400 :       if (_M_try_char())
     423         233 :         __last_char.set(_M_value[0]);
     424         167 :       else if (_M_match_token(_ScannerT::_S_token_bracket_dash))
     425             :         // Dash as first character is a normal character.
     426           2 :         __last_char.set('-');
     427        2081 :       while (_M_expression_term(__last_char, __matcher))
     428             :         ;
     429         400 :       if (__last_char._M_is_char())
     430         242 :         __matcher._M_add_char(__last_char.get());
     431         400 :       __matcher._M_ready();
     432         800 :       _M_stack.push(_StateSeqT(
     433         400 :                       *_M_nfa,
     434         400 :                       _M_nfa->_M_insert_matcher(std::move(__matcher))));
     435         400 :     }
     436             : 
     437             :   template<typename _TraitsT>
     438             :   template<bool __icase, bool __collate>
     439             :     bool
     440        2081 :     _Compiler<_TraitsT>::
     441             :     _M_expression_term(_BracketState& __last_char,
     442             :                        _BracketMatcher<__icase, __collate>& __matcher)
     443             :     {
     444        2081 :       if (_M_match_token(_ScannerT::_S_token_bracket_end))
     445         400 :         return false;
     446             : 
     447             :       // Add any previously cached char into the matcher and update cache.
     448        5839 :       const auto __push_char = [&](_CharT __ch)
     449             :       {
     450        1136 :         if (__last_char._M_is_char())
     451         750 :           __matcher._M_add_char(__last_char.get());
     452        1136 :         __last_char.set(__ch);
     453             :       };
     454             :       // Add any previously cached char into the matcher and update cache.
     455        2179 :       const auto __push_class = [&]
     456             :       {
     457         166 :         if (__last_char._M_is_char())
     458           0 :           __matcher._M_add_char(__last_char.get());
     459             :         // We don't cache anything here, just record that the last thing
     460             :         // processed was a character class (or similar).
     461         166 :         __last_char.reset(_BracketState::_Type::_Class);
     462             :       };
     463             : 
     464        1681 :       if (_M_match_token(_ScannerT::_S_token_collsymbol))
     465             :         {
     466           0 :           auto __symbol = __matcher._M_add_collate_element(_M_value);
     467           0 :           if (__symbol.size() == 1)
     468           0 :             __push_char(__symbol[0]);
     469             :           else
     470           0 :             __push_class();
     471           0 :         }
     472        1681 :       else if (_M_match_token(_ScannerT::_S_token_equiv_class_name))
     473             :         {
     474           0 :           __push_class();
     475           0 :           __matcher._M_add_equivalence_class(_M_value);
     476             :         }
     477        1681 :       else if (_M_match_token(_ScannerT::_S_token_char_class_name))
     478             :         {
     479           0 :           __push_class();
     480           0 :           __matcher._M_add_character_class(_M_value, false);
     481             :         }
     482        1681 :       else if (_M_try_char())
     483        1136 :         __push_char(_M_value[0]);
     484             :       // POSIX doesn't allow '-' as a start-range char (say [a-z--0]),
     485             :       // except when the '-' is the first or last character in the bracket
     486             :       // expression ([--0]). ECMAScript treats all '-' after a range as a
     487             :       // normal character. Also see above, where _M_expression_term gets called.
     488             :       //
     489             :       // As a result, POSIX rejects [-----], but ECMAScript doesn't.
     490             :       // Boost (1.57.0) always uses POSIX style even in its ECMAScript syntax.
     491             :       // Clang (3.5) always uses ECMAScript style even in its POSIX syntax.
     492             :       //
     493             :       // It turns out that no one reads BNFs ;)
     494         545 :       else if (_M_match_token(_ScannerT::_S_token_bracket_dash))
     495             :         {
     496         379 :           if (_M_match_token(_ScannerT::_S_token_bracket_end))
     497             :             {
     498             :               // For "-]" the dash is a literal character.
     499           0 :               __push_char('-');
     500           0 :               return false;
     501             :             }
     502         379 :           else if (__last_char._M_is_class())
     503             :             {
     504             :               // "\\w-" is invalid, start of range must be a single char.
     505           0 :               __throw_regex_error(regex_constants::error_range,
     506             :                     "Invalid start of range in bracket expression.");
     507             :             }
     508         379 :           else if (__last_char._M_is_char())
     509             :             {
     510         379 :               if (_M_try_char())
     511             :                 {
     512             :                   // "x-y"
     513         379 :                   __matcher._M_make_range(__last_char.get(), _M_value[0]);
     514         379 :                   __last_char.reset();
     515             :                 }
     516           0 :               else if (_M_match_token(_ScannerT::_S_token_bracket_dash))
     517             :                 {
     518             :                   // "x--"
     519           0 :                   __matcher._M_make_range(__last_char.get(), '-');
     520           0 :                   __last_char.reset();
     521             :                 }
     522             :               else
     523           0 :                 __throw_regex_error(regex_constants::error_range,
     524             :                       "Invalid end of range in bracket expression.");
     525             :             }
     526           0 :           else if (_M_flags & regex_constants::ECMAScript)
     527             :             {
     528             :               // A dash that is not part of an existing range. Might be the
     529             :               // start of a new range, or might just be a literal '-' char.
     530             :               // Only ECMAScript allows that in the middle of a bracket expr.
     531           0 :               __push_char('-');
     532             :             }
     533             :           else
     534           0 :             __throw_regex_error(regex_constants::error_range,
     535             :                                 "Invalid dash in bracket expression.");
     536             :         }
     537         166 :       else if (_M_match_token(_ScannerT::_S_token_quoted_class))
     538             :         {
     539         166 :           __push_class();
     540         166 :           __matcher._M_add_character_class(_M_value,
     541         332 :                                            _M_ctype.is(_CtypeT::upper,
     542         166 :                                                        _M_value[0]));
     543             :         }
     544             :       else
     545           0 :         __throw_regex_error(regex_constants::error_brack,
     546             :                             "Unexpected character in bracket expression.");
     547             : 
     548        1681 :       return true;
     549             :     }
     550             : 
     551             :   template<typename _TraitsT>
     552             :     bool
     553        9348 :     _Compiler<_TraitsT>::
     554             :     _M_try_char()
     555             :     {
     556        9348 :       bool __is_char = false;
     557        9348 :       if (_M_match_token(_ScannerT::_S_token_oct_num))
     558             :         {
     559           0 :           __is_char = true;
     560           0 :           _M_value.assign(1, _M_cur_int_value(8));
     561             :         }
     562        9348 :       else if (_M_match_token(_ScannerT::_S_token_hex_num))
     563             :         {
     564           0 :           __is_char = true;
     565           0 :           _M_value.assign(1, _M_cur_int_value(16));
     566             :         }
     567        9348 :       else if (_M_match_token(_ScannerT::_S_token_ord_char))
     568        5795 :         __is_char = true;
     569        9348 :       return __is_char;
     570             :     }
     571             : 
     572             :   template<typename _TraitsT>
     573             :     bool
     574      117294 :     _Compiler<_TraitsT>::
     575             :     _M_match_token(_TokenT __token)
     576             :     {
     577      117294 :       if (__token == _M_scanner._M_get_token())
     578             :         {
     579       11613 :           _M_value = _M_scanner._M_get_value();
     580       11613 :           _M_scanner._M_advance();
     581       11613 :           return true;
     582             :         }
     583      105681 :       return false;
     584             :     }
     585             : 
     586             :   template<typename _TraitsT>
     587             :     int
     588         208 :     _Compiler<_TraitsT>::
     589             :     _M_cur_int_value(int __radix)
     590             :     {
     591         208 :       int __v = 0;
     592         498 :       for (_CharT __c : _M_value)
     593         580 :         if (__builtin_mul_overflow(__v, __radix, &__v)
     594         290 :             || __builtin_add_overflow(__v, _M_traits.value(__c, __radix), &__v))
     595           0 :             std::__throw_regex_error(regex_constants::error_backref,
     596             :                                      "invalid back reference");
     597         208 :       return __v;
     598             :     }
     599             : 
     600             :   template<typename _TraitsT, bool __icase, bool __collate>
     601             :     bool
     602      125184 :     _BracketMatcher<_TraitsT, __icase, __collate>::
     603             :     _M_apply(_CharT __ch, false_type) const
     604             :     {
     605     1373537 :       return [this, __ch]
     606             :       {
     607      125184 :         if (std::binary_search(_M_char_set.begin(), _M_char_set.end(),
     608      250368 :                                _M_translator._M_translate(__ch)))
     609         992 :           return true;
     610      124192 :         auto __s = _M_translator._M_transform(__ch);
     611      206791 :         for (auto& __it : _M_range_set)
     612       90021 :           if (_M_translator._M_match_range(__it.first, __it.second, __s))
     613        7422 :             return true;
     614      116770 :         if (_M_traits.isctype(__ch, _M_class_set))
     615        8208 :           return true;
     616      217124 :         if (std::find(_M_equiv_set.begin(), _M_equiv_set.end(),
     617      108562 :                       _M_traits.transform_primary(&__ch, &__ch+1))
     618      325686 :             != _M_equiv_set.end())
     619           0 :           return true;
     620      108562 :         for (auto& __it : _M_neg_class_set)
     621           0 :           if (!_M_traits.isctype(__ch, __it))
     622           0 :             return true;
     623      108562 :         return false;
     624      125184 :       }() ^ _M_is_non_matching;
     625             :     }
     626             : } // namespace __detail
     627             : 
     628             : _GLIBCXX_END_NAMESPACE_VERSION
     629             : } // namespace

Generated by: LCOV version 1.14