Regex: Fix handling of ^ and $ in backward matching mode

This commit is contained in:
Maxime Coste 2017-10-11 19:24:01 +08:00
parent 3c999aba37
commit 2b97e4e124
3 changed files with 19 additions and 8 deletions

View File

@ -1192,6 +1192,12 @@ auto test_regex = UnitTest{[]{
kak_assert(StringView{vm.captures()[0], vm.captures()[1]} == "boz"); kak_assert(StringView{vm.captures()[0], vm.captures()[1]} == "boz");
} }
{
TestVM<MatchDirection::Backward> vm{R"($)"};
kak_assert(vm.exec("foo\nbar\nbaz\nqux", RegexExecFlags::Search | RegexExecFlags::NotEndOfLine));
kak_assert(StringView{vm.captures()[0]} == "\nqux");
}
{ {
TestVM<> vm{R"(()*)"}; TestVM<> vm{R"(()*)"};
kak_assert(not vm.exec(" ")); kak_assert(not vm.exec(" "));

View File

@ -130,23 +130,28 @@ public:
bool exec(Iterator begin, Iterator end, RegexExecFlags flags) bool exec(Iterator begin, Iterator end, RegexExecFlags flags)
{ {
const bool forward = direction == MatchDirection::Forward; if (flags & RegexExecFlags::NotInitialNull and begin == end)
return false;
constexpr bool forward = direction == MatchDirection::Forward;
const bool prev_avail = flags & RegexExecFlags::PrevAvailable; const bool prev_avail = flags & RegexExecFlags::PrevAvailable;
m_begin = Utf8It{utf8::iterator<Iterator>{forward ? begin : end, m_begin = Utf8It{utf8::iterator<Iterator>{forward ? begin : end,
prev_avail ? begin-1 : begin, end}}; prev_avail ? begin-1 : begin, end}};
m_end = Utf8It{utf8::iterator<Iterator>{forward ? end : begin, m_end = Utf8It{utf8::iterator<Iterator>{forward ? end : begin,
prev_avail ? begin-1 : begin, end}}; prev_avail ? begin-1 : begin, end}};
m_flags = flags; if (forward)
m_flags = flags;
if (flags & RegexExecFlags::NotInitialNull and m_begin == m_end) else // Flip line begin/end flags as we flipped the instructions on compilation.
return false; m_flags = (RegexExecFlags)(flags & ~(RegexExecFlags::NotEndOfLine | RegexExecFlags::NotBeginOfLine)) |
((flags & RegexExecFlags::NotEndOfLine) ? RegexExecFlags::NotBeginOfLine : RegexExecFlags::None) |
((flags & RegexExecFlags::NotBeginOfLine) ? RegexExecFlags::NotEndOfLine : RegexExecFlags::None);
const bool no_saves = (m_flags & RegexExecFlags::NoSaves); const bool no_saves = (flags & RegexExecFlags::NoSaves);
Utf8It start{m_begin}; Utf8It start{m_begin};
const bool* start_chars = m_program.start_chars ? m_program.start_chars->map : nullptr; const bool* start_chars = m_program.start_chars ? m_program.start_chars->map : nullptr;
if (flags & RegexExecFlags::Search) if (flags & RegexExecFlags::Search)
to_next_start(start, m_end, start_chars); to_next_start(start, m_end, start_chars);

View File

@ -881,7 +881,7 @@ Selection find_next_match(const Context& context, const Selection& sel, const Re
wrapped = false; wrapped = false;
const bool found = (direction == MatchDirection::Forward) ? const bool found = (direction == MatchDirection::Forward) ?
find_next(buffer, utf8::next(pos, buffer.end()), matches, regex, wrapped) find_next(buffer, utf8::next(pos, buffer.end()), matches, regex, wrapped)
: find_prev(buffer, pos, matches, regex, wrapped); : find_prev(buffer, utf8::previous(pos, buffer.begin()), matches, regex, wrapped);
if (not found or matches[0].first == buffer.end()) if (not found or matches[0].first == buffer.end())
throw runtime_error(format("'{}': no matches found", regex.str())); throw runtime_error(format("'{}': no matches found", regex.str()));