Index: libcxx/include/regex =================================================================== --- libcxx/include/regex +++ libcxx/include/regex @@ -32,7 +32,8 @@ extended = unspecified, awk = unspecified, grep = unspecified, - egrep = unspecified + egrep = unspecified, + multiline = unspecified // C++17 }; constexpr syntax_option_type operator~(syntax_option_type f); @@ -142,6 +143,7 @@ static constexpr regex_constants::syntax_option_type awk = regex_constants::awk; static constexpr regex_constants::syntax_option_type grep = regex_constants::grep; static constexpr regex_constants::syntax_option_type egrep = regex_constants::egrep; + static constexpr regex_constants::syntax_option_type multiline = regex_constants::multiline; // C++17 // construct/copy/destroy: basic_regex(); @@ -803,6 +805,10 @@ awk = 1 << 6, grep = 1 << 7, egrep = 1 << 8 +#if _LIBCPP_STD_VER > 14 + , + multiline = 1 << 10 +#endif }; inline _LIBCPP_CONSTEXPR @@ -1976,6 +1982,15 @@ // __l_anchor +#if _LIBCPP_STD_VER > 14 +template +inline _LIBCPP_CONSTEXPR +bool __is_eol(_CharT c) +{ + return c == '\r' || c == '\n'; +} +#endif + template class __l_anchor : public __owns_one_state<_CharT> @@ -1985,9 +2000,11 @@ public: typedef _VSTD::__state<_CharT> __state; + bool __multiline; + _LIBCPP_INLINE_VISIBILITY - __l_anchor(__node<_CharT>* __s) - : base(__s) {} + __l_anchor(bool __multiline, __node<_CharT>* __s) + : base(__s), __multiline(__multiline) {} virtual void __exec(__state&) const; }; @@ -2002,6 +2019,15 @@ __s.__do_ = __state::__accept_but_not_consume; __s.__node_ = this->first(); } +#if _LIBCPP_STD_VER > 14 + else if (__multiline && + !__s.__at_first_ && + __is_eol(*_VSTD::prev(__s.__current_))) + { + __s.__do_ = __state::__accept_but_not_consume; + __s.__node_ = this->first(); + } +#endif else { __s.__do_ = __state::__reject; @@ -2020,9 +2046,11 @@ public: typedef _VSTD::__state<_CharT> __state; + bool __multiline; + _LIBCPP_INLINE_VISIBILITY - __r_anchor(__node<_CharT>* __s) - : base(__s) {} + __r_anchor(bool __multiline, __node<_CharT>* __s) + : base(__s), __multiline(__multiline) {} virtual void __exec(__state&) const; }; @@ -2037,6 +2065,13 @@ __s.__do_ = __state::__accept_but_not_consume; __s.__node_ = this->first(); } +#if _LIBCPP_STD_VER > 14 + else if (__multiline && __is_eol(*__s.__current_)) + { + __s.__do_ = __state::__accept_but_not_consume; + __s.__node_ = this->first(); + } +#endif else { __s.__do_ = __state::__reject; @@ -2536,6 +2571,9 @@ static const regex_constants::syntax_option_type awk = regex_constants::awk; static const regex_constants::syntax_option_type grep = regex_constants::grep; static const regex_constants::syntax_option_type egrep = regex_constants::egrep; +#if _LIBCPP_STD_VER > 14 + static const regex_constants::syntax_option_type multiline = regex_constants::multiline; +#endif // construct/copy/destroy: _LIBCPP_INLINE_VISIBILITY @@ -2707,6 +2745,14 @@ _LIBCPP_INLINE_VISIBILITY unsigned __loop_count() const {return __loop_count_;} + _LIBCPP_INLINE_VISIBILITY + bool __use_multiline() const +#if _LIBCPP_STD_VER > 14 + {return __get_grammar(__flags_) == ECMAScript && (__flags_ & multiline);} +#else + {return false;} +#endif + template _ForwardIterator __parse(_ForwardIterator __first, _ForwardIterator __last); @@ -4722,7 +4768,7 @@ void basic_regex<_CharT, _Traits>::__push_l_anchor() { - __end_->first() = new __l_anchor<_CharT>(__end_->first()); + __end_->first() = new __l_anchor<_CharT>(__use_multiline(), __end_->first()); __end_ = static_cast<__owns_one_state<_CharT>*>(__end_->first()); } @@ -4730,7 +4776,7 @@ void basic_regex<_CharT, _Traits>::__push_r_anchor() { - __end_->first() = new __r_anchor<_CharT>(__end_->first()); + __end_->first() = new __r_anchor<_CharT>(__use_multiline(), __end_->first()); __end_ = static_cast<__owns_one_state<_CharT>*>(__end_->first()); } Index: libcxx/test/std/re/re.const/re.matchflag/match_multiline.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/re/re.const/re.matchflag/match_multiline.pass.cpp @@ -0,0 +1,272 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// multiline: +// Specifies that ^ shall match the beginning of a line and $ shall match +// the end of a line, if the ECMAScript engine is selected. + +#include +#include +#include "test_macros.h" + +static void search(const char* pat, std::regex_constants::syntax_option_type f, + const char* target, bool expected) +{ + std::regex re(pat, f); + std::cmatch m; + assert(std::regex_search(target, m, re) == expected); + + if(expected) { + assert(m.size() == 1); + assert(m.length(0) == 3); + assert(m.str(0) == "foo"); + } + else + { + assert(m.size() == 0); + } +} + +int main(int, char**) +{ + using std::regex_constants::ECMAScript; + using std::regex_constants::basic; + using std::regex_constants::extended; + using std::regex_constants::awk; + using std::regex_constants::grep; + using std::regex_constants::egrep; + using std::regex_constants::multiline; + + { + const char* pat = "^foo"; + const char* target = "foo"; + + search(pat, ECMAScript, target, true); + search(pat, basic, target, true); + search(pat, extended, target, true); + search(pat, awk, target, true); + search(pat, grep, target, true); + search(pat, egrep, target, true); + + search(pat, ECMAScript | multiline, target, true); + search(pat, basic | multiline, target, true); + search(pat, extended | multiline, target, true); + search(pat, awk | multiline, target, true); + search(pat, grep | multiline, target, true); + search(pat, egrep | multiline, target, true); + } + { + const char* pat = "^foo"; + const char* target = "\nfoo"; + + search(pat, ECMAScript, target, false); + search(pat, basic, target, false); + search(pat, extended, target, false); + search(pat, awk, target, false); + search(pat, grep, target, false); + search(pat, egrep, target, false); + + search(pat, ECMAScript | multiline, target, true); + search(pat, basic | multiline, target, false); + search(pat, extended | multiline, target, false); + search(pat, awk | multiline, target, false); + search(pat, grep | multiline, target, false); + search(pat, egrep | multiline, target, false); + } + { + const char* pat = "^foo"; + const char* target = "bar\nfoo"; + + search(pat, ECMAScript, target, false); + search(pat, basic, target, false); + search(pat, extended, target, false); + search(pat, awk, target, false); + search(pat, grep, target, false); + search(pat, egrep, target, false); + + search(pat, ECMAScript | multiline, target, true); + search(pat, basic | multiline, target, false); + search(pat, extended | multiline, target, false); + search(pat, awk | multiline, target, false); + search(pat, grep | multiline, target, false); + search(pat, egrep | multiline, target, false); + } + + { + const char* pat = "foo$"; + const char* target = "foo"; + + search(pat, ECMAScript, target, true); + search(pat, basic, target, true); + search(pat, extended, target, true); + search(pat, awk, target, true); + search(pat, grep, target, true); + search(pat, egrep, target, true); + + search(pat, ECMAScript | multiline, target, true); + search(pat, basic | multiline, target, true); + search(pat, extended | multiline, target, true); + search(pat, awk | multiline, target, true); + search(pat, grep | multiline, target, true); + search(pat, egrep | multiline, target, true); + } + { + const char* pat = "foo$"; + const char* target = "foo\n"; + + search(pat, ECMAScript, target, false); + search(pat, basic, target, false); + search(pat, extended, target, false); + search(pat, awk, target, false); + search(pat, grep, target, false); + search(pat, egrep, target, false); + + search(pat, ECMAScript | multiline, target, true); + search(pat, basic | multiline, target, false); + search(pat, extended | multiline, target, false); + search(pat, awk | multiline, target, false); + search(pat, grep | multiline, target, false); + search(pat, egrep | multiline, target, false); + } + { + const char* pat = "foo$"; + const char* target = "foo\nbar"; + + search(pat, ECMAScript, target, false); + search(pat, basic, target, false); + search(pat, extended, target, false); + search(pat, awk, target, false); + search(pat, grep, target, false); + search(pat, egrep, target, false); + + search(pat, ECMAScript | multiline, target, true); + search(pat, basic | multiline, target, false); + search(pat, extended | multiline, target, false); + search(pat, awk | multiline, target, false); + search(pat, grep | multiline, target, false); + search(pat, egrep | multiline, target, false); + } + + + { + const char* pat = "^foo"; + const char* target = "foo"; + + search(pat, ECMAScript, target, true); + search(pat, basic, target, true); + search(pat, extended, target, true); + search(pat, awk, target, true); + search(pat, grep, target, true); + search(pat, egrep, target, true); + + search(pat, ECMAScript | multiline, target, true); + search(pat, basic | multiline, target, true); + search(pat, extended | multiline, target, true); + search(pat, awk | multiline, target, true); + search(pat, grep | multiline, target, true); + search(pat, egrep | multiline, target, true); + } + { + const char* pat = "^foo"; + const char* target = "\rfoo"; + + search(pat, ECMAScript, target, false); + search(pat, basic, target, false); + search(pat, extended, target, false); + search(pat, awk, target, false); + search(pat, grep, target, false); + search(pat, egrep, target, false); + + search(pat, ECMAScript | multiline, target, true); + search(pat, basic | multiline, target, false); + search(pat, extended | multiline, target, false); + search(pat, awk | multiline, target, false); + search(pat, grep | multiline, target, false); + search(pat, egrep | multiline, target, false); + } + { + const char* pat = "^foo"; + const char* target = "bar\rfoo"; + + search(pat, ECMAScript, target, false); + search(pat, basic, target, false); + search(pat, extended, target, false); + search(pat, awk, target, false); + search(pat, grep, target, false); + search(pat, egrep, target, false); + + search(pat, ECMAScript | multiline, target, true); + search(pat, basic | multiline, target, false); + search(pat, extended | multiline, target, false); + search(pat, awk | multiline, target, false); + search(pat, grep | multiline, target, false); + search(pat, egrep | multiline, target, false); + } + + { + const char* pat = "foo$"; + const char* target = "foo"; + + search(pat, ECMAScript, target, true); + search(pat, basic, target, true); + search(pat, extended, target, true); + search(pat, awk, target, true); + search(pat, grep, target, true); + search(pat, egrep, target, true); + + search(pat, ECMAScript | multiline, target, true); + search(pat, basic | multiline, target, true); + search(pat, extended | multiline, target, true); + search(pat, awk | multiline, target, true); + search(pat, grep | multiline, target, true); + search(pat, egrep | multiline, target, true); + } + { + const char* pat = "foo$"; + const char* target = "foo\r"; + + search(pat, ECMAScript, target, false); + search(pat, basic, target, false); + search(pat, extended, target, false); + search(pat, awk, target, false); + search(pat, grep, target, false); + search(pat, egrep, target, false); + + search(pat, ECMAScript | multiline, target, true); + search(pat, basic | multiline, target, false); + search(pat, extended | multiline, target, false); + search(pat, awk | multiline, target, false); + search(pat, grep | multiline, target, false); + search(pat, egrep | multiline, target, false); + } + { + const char* pat = "foo$"; + const char* target = "foo\rbar"; + + search(pat, ECMAScript, target, false); + search(pat, basic, target, false); + search(pat, extended, target, false); + search(pat, awk, target, false); + search(pat, grep, target, false); + search(pat, egrep, target, false); + + search(pat, ECMAScript | multiline, target, true); + search(pat, basic | multiline, target, false); + search(pat, extended | multiline, target, false); + search(pat, awk | multiline, target, false); + search(pat, grep | multiline, target, false); + search(pat, egrep | multiline, target, false); + } + + return 0; +} Index: libcxx/test/std/re/re.const/re.synopt/syntax_option_type.pass.cpp =================================================================== --- libcxx/test/std/re/re.const/re.synopt/syntax_option_type.pass.cpp +++ libcxx/test/std/re/re.const/re.synopt/syntax_option_type.pass.cpp @@ -23,7 +23,8 @@ // extended = unspecified, // awk = unspecified, // grep = unspecified, -// egrep = unspecified +// egrep = unspecified, +// multiline = unspecified // }; // // } @@ -48,6 +49,9 @@ assert(std::regex_constants::awk != 0); assert(std::regex_constants::grep != 0); assert(std::regex_constants::egrep != 0); +#if _LIBCPP_STD_VER > 14 + assert(std::regex_constants::multiline != 0); +#endif assert((std::regex_constants::icase & std::regex_constants::nosubs) == 0); assert((std::regex_constants::icase & std::regex_constants::optimize) == 0); @@ -58,6 +62,9 @@ assert((std::regex_constants::icase & std::regex_constants::awk) == 0); assert((std::regex_constants::icase & std::regex_constants::grep) == 0); assert((std::regex_constants::icase & std::regex_constants::egrep) == 0); +#if _LIBCPP_STD_VER > 14 + assert((std::regex_constants::icase & std::regex_constants::multiline) == 0); +#endif assert((std::regex_constants::nosubs & std::regex_constants::optimize) == 0); assert((std::regex_constants::nosubs & std::regex_constants::collate) == 0); @@ -67,6 +74,9 @@ assert((std::regex_constants::nosubs & std::regex_constants::awk) == 0); assert((std::regex_constants::nosubs & std::regex_constants::grep) == 0); assert((std::regex_constants::nosubs & std::regex_constants::egrep) == 0); +#if _LIBCPP_STD_VER > 14 + assert((std::regex_constants::nosubs & std::regex_constants::multiline) == 0); +#endif assert((std::regex_constants::optimize & std::regex_constants::collate) == 0); assert((std::regex_constants::optimize & std::regex_constants::ECMAScript) == 0); @@ -75,6 +85,9 @@ assert((std::regex_constants::optimize & std::regex_constants::awk) == 0); assert((std::regex_constants::optimize & std::regex_constants::grep) == 0); assert((std::regex_constants::optimize & std::regex_constants::egrep) == 0); +#if _LIBCPP_STD_VER > 14 + assert((std::regex_constants::optimize & std::regex_constants::multiline) == 0); +#endif assert((std::regex_constants::collate & std::regex_constants::ECMAScript) == 0); assert((std::regex_constants::collate & std::regex_constants::basic) == 0); @@ -82,26 +95,46 @@ assert((std::regex_constants::collate & std::regex_constants::awk) == 0); assert((std::regex_constants::collate & std::regex_constants::grep) == 0); assert((std::regex_constants::collate & std::regex_constants::egrep) == 0); +#if _LIBCPP_STD_VER > 14 + assert((std::regex_constants::collate & std::regex_constants::multiline) == 0); +#endif assert((std::regex_constants::ECMAScript & std::regex_constants::basic) == 0); assert((std::regex_constants::ECMAScript & std::regex_constants::extended) == 0); assert((std::regex_constants::ECMAScript & std::regex_constants::awk) == 0); assert((std::regex_constants::ECMAScript & std::regex_constants::grep) == 0); assert((std::regex_constants::ECMAScript & std::regex_constants::egrep) == 0); +#if _LIBCPP_STD_VER > 14 + assert((std::regex_constants::ECMAScript & std::regex_constants::multiline) == 0); +#endif assert((std::regex_constants::basic & std::regex_constants::extended) == 0); assert((std::regex_constants::basic & std::regex_constants::awk) == 0); assert((std::regex_constants::basic & std::regex_constants::grep) == 0); assert((std::regex_constants::basic & std::regex_constants::egrep) == 0); +#if _LIBCPP_STD_VER > 14 + assert((std::regex_constants::basic & std::regex_constants::multiline) == 0); +#endif assert((std::regex_constants::extended & std::regex_constants::awk) == 0); assert((std::regex_constants::extended & std::regex_constants::grep) == 0); assert((std::regex_constants::extended & std::regex_constants::egrep) == 0); +#if _LIBCPP_STD_VER > 14 + assert((std::regex_constants::extended & std::regex_constants::multiline) == 0); +#endif assert((std::regex_constants::awk & std::regex_constants::grep) == 0); assert((std::regex_constants::awk & std::regex_constants::egrep) == 0); +#if _LIBCPP_STD_VER > 14 + assert((std::regex_constants::awk & std::regex_constants::multiline) == 0); +#endif assert((std::regex_constants::grep & std::regex_constants::egrep) == 0); +#if _LIBCPP_STD_VER > 14 + assert((std::regex_constants::grep & std::regex_constants::multiline) == 0); + + assert((std::regex_constants::egrep & std::regex_constants::multiline) == 0); +#endif assert((std::regex_constants::icase | std::regex_constants::nosubs) != 0); assert((std::regex_constants::icase ^ std::regex_constants::nosubs) != 0); Index: libcxx/www/cxx1z_status.html =================================================================== --- libcxx/www/cxx1z_status.html +++ libcxx/www/cxx1z_status.html @@ -371,7 +371,7 @@ 2460LWG issue 2408 and value categoriesIssaquahComplete 2468Self-move-assignment of library typesIssaquah 2475Allow overwriting of std::basic_string terminator with charT() to allow cleaner interoperation with legacy APIsIssaquahComplete - 2503multiline option should be added to syntax_option_typeIssaquah + 2503multiline option should be added to syntax_option_typeIssaquahComplete 2510Tag types should not be DefaultConstructibleIssaquah 2514Type traits must not be finalIssaquahComplete 2518[fund.ts.v2] Non-member swap for propagate_const should call member swapIssaquahComplete @@ -503,7 +503,7 @@ -

Last Updated: 26-Feb-2018

+

Last Updated: 9-Jun-2019