#pragma once
#include <optional>
#include <string>
#include <vector>
#include "fwd.hpp"
#include "Regex.hpp"
#include "RegexMatchResult.hpp"
NAMESPACE_SOUP
{
struct RegexMatcher
{
struct RollbackPoint
{
const RegexConstraint* c;
const char* it;
RegexMatchResult result{};
};
const RegexConstraint* c;
const char* it;
const char* const begin;
const char* const end;
std::vector<RollbackPoint> rollback_points{};
std::vector<const char*> checkpoints{};
RegexMatchResult result{};
RegexMatcher(const Regex& r, const char* begin, const char* end)
: c(r.group.initial), begin(begin), end(end)
{
}
void reset(const Regex& r) noexcept
{
c = r.group.initial;
rollback_points.clear();
checkpoints.clear();
result.groups.clear();
}
void saveRollback(const RegexConstraint* rollback_transition)
{
rollback_points.emplace_back(RollbackPoint{ rollback_transition, it, result });
}
void restoreRollback()
{
c = rollback_points.back().c;
it = rollback_points.back().it;
result = std::move(rollback_points.back().result);
rollback_points.pop_back();
}
bool shouldSaveCheckpoint() noexcept
{
if (reinterpret_cast<uintptr_t>(c) & 0b1)
{
c = reinterpret_cast<const RegexConstraint*>(reinterpret_cast<uintptr_t>(c) & ~0b1);
SOUP_ASSERT(c != nullptr);
return true;
}
return false;
}
bool shouldResetCapture() noexcept
{
if (reinterpret_cast<uintptr_t>(c) & 0b10)
{
c = reinterpret_cast<const RegexConstraint*>(reinterpret_cast<uintptr_t>(c) & ~0b10);
return true;
}
return false;
}
void saveCheckpoint()
{
checkpoints.emplace_back(it);
}
void restoreCheckpoint()
{
it = checkpoints.back();
checkpoints.pop_back();
}
void insertMissingCapturingGroups(const RegexGroup* g)
{
for (; g; g = g->parent)
{
if (g->lookahead_or_lookbehind)
{
break;
}
if (g->isNonCapturing())
{
continue;
}
while (g->index >= this->result.groups.size())
{
this->result.groups.emplace_back(std::nullopt);
}
if (!this->result.groups.at(g->index).has_value())
{
this->result.groups.at(g->index) = RegexMatchedGroup{ g->name, this->it, this->it };
}
}
}
};
}