2014-10-13 14:12:33 +02:00
|
|
|
#ifndef regex_hh_INCLUDED
|
|
|
|
#define regex_hh_INCLUDED
|
|
|
|
|
|
|
|
#include "string.hh"
|
2017-10-02 08:59:04 +02:00
|
|
|
#include "regex_impl.hh"
|
2014-10-13 14:12:33 +02:00
|
|
|
|
|
|
|
namespace Kakoune
|
|
|
|
{
|
|
|
|
|
2014-10-13 20:40:27 +02:00
|
|
|
// Regex that keeps track of its string representation
|
2017-10-09 08:04:14 +02:00
|
|
|
class Regex
|
2014-10-13 20:40:27 +02:00
|
|
|
{
|
2016-12-14 21:59:39 +01:00
|
|
|
public:
|
2014-10-13 20:40:27 +02:00
|
|
|
Regex() = default;
|
|
|
|
|
2017-12-01 12:57:02 +01:00
|
|
|
explicit Regex(StringView re, RegexCompileFlags flags = RegexCompileFlags::None);
|
2014-10-13 20:40:27 +02:00
|
|
|
bool empty() const { return m_str.empty(); }
|
2015-04-09 00:16:27 +02:00
|
|
|
bool operator==(const Regex& other) const { return m_str == other.m_str; }
|
|
|
|
bool operator!=(const Regex& other) const { return m_str != other.m_str; }
|
2014-10-13 20:40:27 +02:00
|
|
|
|
2015-03-10 20:33:46 +01:00
|
|
|
const String& str() const { return m_str; }
|
2014-10-13 20:40:27 +02:00
|
|
|
|
2017-10-09 08:04:14 +02:00
|
|
|
size_t mark_count() const { return m_impl->save_count / 2 - 1; }
|
2019-01-03 12:52:15 +01:00
|
|
|
int named_capture_index(StringView name) const;
|
2017-10-09 08:04:14 +02:00
|
|
|
|
2016-08-18 23:42:31 +02:00
|
|
|
static constexpr const char* option_type_name = "regex";
|
2016-08-06 10:05:50 +02:00
|
|
|
|
2017-10-06 07:40:27 +02:00
|
|
|
const CompiledRegex* impl() const { return m_impl.get(); }
|
2017-10-02 08:59:04 +02:00
|
|
|
|
2014-10-13 20:40:27 +02:00
|
|
|
private:
|
2017-10-06 07:40:27 +02:00
|
|
|
RefPtr<CompiledRegex> m_impl;
|
2017-10-09 08:04:14 +02:00
|
|
|
String m_str;
|
2014-10-13 20:40:27 +02:00
|
|
|
};
|
2015-03-10 20:33:46 +01:00
|
|
|
|
2014-10-13 14:12:33 +02:00
|
|
|
template<typename Iterator>
|
2017-10-09 08:04:14 +02:00
|
|
|
struct MatchResults
|
2016-05-10 10:12:30 +02:00
|
|
|
{
|
|
|
|
struct SubMatch : std::pair<Iterator, Iterator>
|
|
|
|
{
|
|
|
|
SubMatch() = default;
|
2017-10-09 08:04:14 +02:00
|
|
|
SubMatch(Iterator begin, Iterator end)
|
2022-11-20 06:59:08 +01:00
|
|
|
: std::pair<Iterator, Iterator>{begin, end}, matched{static_cast<bool>(begin)}
|
2016-05-10 10:12:30 +02:00
|
|
|
{}
|
|
|
|
|
|
|
|
bool matched = false;
|
|
|
|
};
|
|
|
|
|
2022-05-19 18:15:20 +02:00
|
|
|
struct iterator
|
2016-05-10 10:12:30 +02:00
|
|
|
{
|
2022-05-19 18:15:20 +02:00
|
|
|
using difference_type = size_t;
|
|
|
|
using value_type = SubMatch;
|
|
|
|
using pointer = SubMatch*;
|
|
|
|
using reference = SubMatch;
|
|
|
|
using iterator_category = std::bidirectional_iterator_tag;
|
2017-11-12 05:30:21 +01:00
|
|
|
using It = typename Vector<Iterator, MemoryDomain::Regex>::const_iterator;
|
2017-10-09 08:04:14 +02:00
|
|
|
|
|
|
|
iterator() = default;
|
|
|
|
iterator(It it) : m_it{std::move(it)} {}
|
|
|
|
|
|
|
|
iterator& operator--() { m_it += 2; return *this; }
|
|
|
|
iterator& operator++() { m_it += 2; return *this; }
|
|
|
|
SubMatch operator*() const { return {*m_it, *(m_it+1)}; }
|
|
|
|
|
|
|
|
friend bool operator==(const iterator& lhs, const iterator& rhs) { return lhs.m_it == rhs.m_it; }
|
|
|
|
friend bool operator!=(const iterator& lhs, const iterator& rhs) { return lhs.m_it != rhs.m_it; }
|
|
|
|
private:
|
2016-05-10 10:12:30 +02:00
|
|
|
|
2017-10-09 08:04:14 +02:00
|
|
|
It m_it;
|
2016-05-10 10:12:30 +02:00
|
|
|
};
|
|
|
|
|
2017-10-09 08:04:14 +02:00
|
|
|
MatchResults() = default;
|
2017-11-12 05:30:21 +01:00
|
|
|
MatchResults(Vector<Iterator, MemoryDomain::Regex> values) : m_values{std::move(values)} {}
|
2017-10-09 08:04:14 +02:00
|
|
|
|
|
|
|
iterator begin() const { return iterator{m_values.begin()}; }
|
|
|
|
iterator cbegin() const { return iterator{m_values.cbegin()}; }
|
|
|
|
iterator end() const { return iterator{m_values.end()}; }
|
|
|
|
iterator cend() const { return iterator{m_values.cend()}; }
|
|
|
|
|
|
|
|
size_t size() const { return m_values.size() / 2; }
|
|
|
|
bool empty() const { return m_values.empty(); }
|
|
|
|
|
|
|
|
SubMatch operator[](size_t i) const
|
|
|
|
{
|
|
|
|
return i * 2 < m_values.size() ?
|
|
|
|
SubMatch{m_values[i*2], m_values[i*2+1]} : SubMatch{};
|
|
|
|
}
|
|
|
|
|
|
|
|
friend bool operator==(const MatchResults& lhs, const MatchResults& rhs)
|
|
|
|
{
|
|
|
|
return lhs.m_values == rhs.m_values;
|
|
|
|
}
|
2016-05-10 10:12:30 +02:00
|
|
|
|
2017-10-09 08:04:14 +02:00
|
|
|
friend bool operator!=(const MatchResults& lhs, const MatchResults& rhs)
|
|
|
|
{
|
|
|
|
return not (lhs == rhs);
|
|
|
|
}
|
|
|
|
|
|
|
|
void swap(MatchResults& other)
|
|
|
|
{
|
|
|
|
m_values.swap(other.m_values);
|
|
|
|
}
|
|
|
|
|
2017-11-29 07:07:04 +01:00
|
|
|
Vector<Iterator, MemoryDomain::Regex>& values() { return m_values; }
|
|
|
|
|
2017-10-09 08:04:14 +02:00
|
|
|
private:
|
2017-11-12 05:30:21 +01:00
|
|
|
Vector<Iterator, MemoryDomain::Regex> m_values;
|
2016-05-10 10:12:30 +02:00
|
|
|
};
|
2014-10-13 14:12:33 +02:00
|
|
|
|
2018-03-04 19:48:10 +01:00
|
|
|
inline RegexExecFlags match_flags(bool bol, bool eol, bool bow, bool eow)
|
2015-12-23 22:43:07 +01:00
|
|
|
{
|
2017-10-09 08:04:14 +02:00
|
|
|
return (bol ? RegexExecFlags::None : RegexExecFlags::NotBeginOfLine) |
|
|
|
|
(eol ? RegexExecFlags::None : RegexExecFlags::NotEndOfLine) |
|
|
|
|
(bow ? RegexExecFlags::None : RegexExecFlags::NotBeginOfWord) |
|
2018-03-04 19:48:10 +01:00
|
|
|
(eow ? RegexExecFlags::None : RegexExecFlags::NotEndOfWord);
|
2015-12-23 22:43:07 +01:00
|
|
|
}
|
|
|
|
|
2016-05-10 10:12:30 +02:00
|
|
|
template<typename It>
|
|
|
|
bool regex_match(It begin, It end, const Regex& re)
|
|
|
|
{
|
2018-12-27 01:29:33 +01:00
|
|
|
ThreadedRegexVM<It, RegexMode::Forward | RegexMode::AnyMatch | RegexMode::NoSaves> vm{*re.impl()};
|
|
|
|
return vm.exec(begin, end, begin, end, RegexExecFlags::None);
|
2016-05-10 10:12:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename It>
|
|
|
|
bool regex_match(It begin, It end, MatchResults<It>& res, const Regex& re)
|
|
|
|
{
|
2017-11-29 07:07:04 +01:00
|
|
|
res.values().clear();
|
2018-12-27 01:29:33 +01:00
|
|
|
ThreadedRegexVM<It, RegexMode::Forward> vm{*re.impl()};
|
2018-03-04 19:48:10 +01:00
|
|
|
if (vm.exec(begin, end, begin, end, RegexExecFlags::None))
|
2018-03-04 17:10:47 +01:00
|
|
|
{
|
|
|
|
std::copy(vm.captures().begin(), vm.captures().end(), std::back_inserter(res.values()));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2016-05-10 10:12:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename It>
|
2018-03-04 19:48:10 +01:00
|
|
|
bool regex_search(It begin, It end, It subject_begin, It subject_end, const Regex& re,
|
2017-10-09 08:04:14 +02:00
|
|
|
RegexExecFlags flags = RegexExecFlags::None)
|
2016-05-10 10:12:30 +02:00
|
|
|
{
|
2018-12-27 01:29:33 +01:00
|
|
|
ThreadedRegexVM<It, RegexMode::Forward | RegexMode::Search | RegexMode::AnyMatch | RegexMode::NoSaves> vm{*re.impl()};
|
|
|
|
return vm.exec(begin, end, subject_begin, subject_end, flags);
|
2016-05-10 10:12:30 +02:00
|
|
|
}
|
|
|
|
|
2018-12-27 01:29:33 +01:00
|
|
|
template<typename It, RegexMode mode = RegexMode::Forward>
|
2018-03-04 19:48:10 +01:00
|
|
|
bool regex_search(It begin, It end, It subject_begin, It subject_end,
|
|
|
|
MatchResults<It>& res, const Regex& re,
|
2017-10-09 08:04:14 +02:00
|
|
|
RegexExecFlags flags = RegexExecFlags::None)
|
2016-05-10 10:12:30 +02:00
|
|
|
{
|
2017-11-29 07:07:04 +01:00
|
|
|
res.values().clear();
|
2018-12-27 01:29:33 +01:00
|
|
|
ThreadedRegexVM<It, mode | RegexMode::Search> vm{*re.impl()};
|
|
|
|
if (vm.exec(begin, end, subject_begin, subject_end, flags))
|
2018-03-04 17:10:47 +01:00
|
|
|
{
|
|
|
|
std::move(vm.captures().begin(), vm.captures().end(), std::back_inserter(res.values()));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2016-05-10 10:12:30 +02:00
|
|
|
}
|
|
|
|
|
2017-12-03 10:04:37 +01:00
|
|
|
template<typename It>
|
2018-03-04 19:48:10 +01:00
|
|
|
bool backward_regex_search(It begin, It end, It subject_begin, It subject_end,
|
|
|
|
MatchResults<It>& res, const Regex& re,
|
|
|
|
RegexExecFlags flags = RegexExecFlags::None)
|
2017-12-03 10:04:37 +01:00
|
|
|
{
|
2018-12-27 01:29:33 +01:00
|
|
|
return regex_search<It, RegexMode::Backward>(begin, end, subject_begin, subject_end, res, re, flags);
|
2017-12-03 10:04:37 +01:00
|
|
|
}
|
|
|
|
|
2014-10-13 14:12:33 +02:00
|
|
|
String option_to_string(const Regex& re);
|
2018-05-27 05:00:04 +02:00
|
|
|
Regex option_from_string(Meta::Type<Regex>, StringView str);
|
2014-10-13 14:12:33 +02:00
|
|
|
|
2018-12-27 01:29:33 +01:00
|
|
|
template<typename Iterator, RegexMode mode = RegexMode::Forward,
|
2018-12-20 13:07:50 +01:00
|
|
|
typename VmArg = const Regex>
|
2017-10-02 16:35:31 +02:00
|
|
|
struct RegexIterator
|
|
|
|
{
|
2018-12-27 01:29:33 +01:00
|
|
|
static_assert(has_direction(mode));
|
|
|
|
static constexpr bool forward = mode & RegexMode::Forward;
|
2017-10-02 16:35:31 +02:00
|
|
|
using ValueType = MatchResults<Iterator>;
|
2018-12-19 11:47:44 +01:00
|
|
|
struct Sentinel{};
|
|
|
|
struct It
|
|
|
|
{
|
|
|
|
It(RegexIterator& base) : m_base(base), m_valid{m_base.next()} {}
|
|
|
|
|
|
|
|
const ValueType& operator*() const { kak_assert(m_valid); return m_base.m_results; }
|
|
|
|
const ValueType* operator->() const { kak_assert(m_valid); return &m_base.m_results; }
|
|
|
|
|
|
|
|
It& operator++() { m_valid = m_base.next(); return *this; }
|
2018-12-20 13:07:50 +01:00
|
|
|
bool operator==(Sentinel) const { return not m_valid; }
|
|
|
|
bool operator!=(Sentinel) const { return m_valid; }
|
2018-12-19 11:47:44 +01:00
|
|
|
|
|
|
|
RegexIterator& m_base;
|
|
|
|
bool m_valid;
|
|
|
|
};
|
|
|
|
|
2018-03-04 19:48:10 +01:00
|
|
|
RegexIterator(Iterator begin, Iterator end,
|
|
|
|
Iterator subject_begin, Iterator subject_end,
|
2018-12-20 13:07:50 +01:00
|
|
|
VmArg& vm_arg, RegexExecFlags flags = RegexExecFlags::None)
|
2018-12-27 01:29:33 +01:00
|
|
|
: m_vm{make_vm(vm_arg)}, m_next_pos{forward ? begin : end},
|
2018-04-25 00:13:53 +02:00
|
|
|
m_begin{std::move(begin)}, m_end{std::move(end)},
|
|
|
|
m_subject_begin{std::move(subject_begin)}, m_subject_end{std::move(subject_end)},
|
2018-12-19 11:47:44 +01:00
|
|
|
m_flags{flags} {}
|
2017-10-02 16:35:31 +02:00
|
|
|
|
2018-12-20 13:07:50 +01:00
|
|
|
RegexIterator(const Iterator& begin, const Iterator& end,
|
|
|
|
VmArg& vm_arg, RegexExecFlags flags = RegexExecFlags::None)
|
|
|
|
: RegexIterator{begin, end, begin, end, vm_arg, flags} {}
|
2018-03-04 19:48:10 +01:00
|
|
|
|
2018-12-19 11:47:44 +01:00
|
|
|
It begin() { return {*this}; }
|
|
|
|
Sentinel end() const { return {}; }
|
2017-12-02 07:02:41 +01:00
|
|
|
|
2017-10-02 16:35:31 +02:00
|
|
|
private:
|
2018-12-19 11:47:44 +01:00
|
|
|
bool next()
|
2017-10-02 16:35:31 +02:00
|
|
|
{
|
2018-12-27 01:29:33 +01:00
|
|
|
auto additional_flags = RegexExecFlags::None;
|
2017-10-02 16:35:31 +02:00
|
|
|
if (m_results.size() and m_results[0].first == m_results[0].second)
|
2017-10-09 08:04:14 +02:00
|
|
|
additional_flags |= RegexExecFlags::NotInitialNull;
|
2017-10-02 16:35:31 +02:00
|
|
|
|
2018-12-19 11:47:44 +01:00
|
|
|
if (not m_vm.exec(forward ? m_next_pos : m_begin, forward ? m_end : m_next_pos,
|
|
|
|
m_subject_begin, m_subject_end, m_flags | additional_flags))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
m_results.values().clear();
|
|
|
|
std::move(m_vm.captures().begin(), m_vm.captures().end(), std::back_inserter(m_results.values()));
|
2018-12-27 01:29:33 +01:00
|
|
|
m_next_pos = forward ? m_results[0].second : m_results[0].first;
|
2023-01-23 07:38:02 +01:00
|
|
|
kak_assert(forward ? (m_next_pos <= m_end) : (m_next_pos >= m_begin));
|
2018-12-19 11:47:44 +01:00
|
|
|
return true;
|
2017-10-02 16:35:31 +02:00
|
|
|
}
|
|
|
|
|
2018-12-27 01:29:33 +01:00
|
|
|
using RegexVM = ThreadedRegexVM<Iterator, mode | RegexMode::Search>;
|
2018-12-20 13:07:50 +01:00
|
|
|
static RegexVM& make_vm(RegexVM& vm) { return vm; }
|
|
|
|
static RegexVM make_vm(const Regex& regex) { return {*regex.impl()}; }
|
|
|
|
|
|
|
|
decltype(make_vm(std::declval<VmArg&>())) m_vm;
|
2017-10-02 16:35:31 +02:00
|
|
|
MatchResults<Iterator> m_results;
|
2017-12-02 07:02:41 +01:00
|
|
|
Iterator m_next_pos{};
|
2017-10-02 16:35:31 +02:00
|
|
|
const Iterator m_begin{};
|
|
|
|
const Iterator m_end{};
|
2018-03-04 19:48:10 +01:00
|
|
|
const Iterator m_subject_begin{};
|
|
|
|
const Iterator m_subject_end{};
|
2017-10-09 08:04:14 +02:00
|
|
|
const RegexExecFlags m_flags = RegexExecFlags::None;
|
2017-10-02 16:35:31 +02:00
|
|
|
};
|
|
|
|
|
2014-10-13 14:12:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif // regex_hh_INCLUDED
|