#include "ng_builder.h"
#include "grey.h"
#include "ng.h"
#include "ng_util.h"
#include "ue2common.h"
#include "compiler/compiler.h"
#include "util/compile_error.h"
#include "util/make_unique.h"
#include <cassert>
using namespace std;
namespace ue2 {
namespace {
class NFABuilderImpl : public NFABuilder {
public:
NFABuilderImpl(ReportManager &rm, const Grey &grey,
const ParsedExpression &expr);
~NFABuilderImpl() override;
Position makePositions(size_t nPositions) override;
Position getStart() const override;
Position getStartDotStar() const override;
Position getAccept() const override;
Position getAcceptEOD() const override;
bool isSpecialState(Position p) const override;
void setNodeReportID(Position position, int offsetAdjust) override;
void addCharReach(Position position, const CharReach &cr) override;
void setAssertFlag(Position position, u32 flag) override;
u32 getAssertFlag(Position position) override;
void addVertex(Position p) override;
void addEdge(Position start, Position end) override;
bool hasEdge(Position start, Position end) const override;
u32 numVertices() const override { return vertIdx; }
void cloneRegion(Position first, Position last,
unsigned posOffset) override;
BuiltExpression getGraph() override;
private:
NFAVertex getVertex(Position pos) const;
pair<NFAEdge, bool> addEdge(NFAVertex u, NFAVertex v);
ReportManager &rm;
const Grey &grey;
unique_ptr<NGHolder> graph;
ExpressionInfo expr;
vector<NFAVertex> id2vertex;
u32 vertIdx;
};
}
NFABuilderImpl::NFABuilderImpl(ReportManager &rm_in, const Grey &grey_in,
const ParsedExpression &parsed)
: rm(rm_in), grey(grey_in), graph(ue2::make_unique<NGHolder>()),
expr(parsed.expr), vertIdx(N_SPECIALS) {
id2vertex.reserve(64);
id2vertex.resize(N_SPECIALS);
id2vertex[NODE_START] = graph->start;
id2vertex[NODE_START_DOTSTAR] = graph->startDs;
id2vertex[NODE_ACCEPT] = graph->accept;
id2vertex[NODE_ACCEPT_EOD] = graph->acceptEod;
}
NFABuilderImpl::~NFABuilderImpl() {
}
NFAVertex NFABuilderImpl::getVertex(Position pos) const {
assert(id2vertex.size() >= pos);
const NFAVertex v = id2vertex[pos];
assert(v != NGHolder::null_vertex());
assert((*graph)[v].index == pos);
return v;
}
void NFABuilderImpl::addVertex(Position pos) {
if (pos > grey.limitGraphVertices) {
throw CompileError("Pattern too large.");
}
NFAVertex v = add_vertex(*graph);
if (id2vertex.size() <= pos) {
id2vertex.resize(pos + 1);
}
id2vertex[pos] = v;
(*graph)[v].index = pos;
}
BuiltExpression NFABuilderImpl::getGraph() {
DEBUG_PRINTF("built graph has %zu vertices and %zu edges\n",
num_vertices(*graph), num_edges(*graph));
if (num_edges(*graph) > grey.limitGraphEdges) {
throw CompileError("Pattern too large.");
}
if (num_vertices(*graph) > grey.limitGraphVertices) {
throw CompileError("Pattern too large.");
}
return { expr, move(graph) };
}
void NFABuilderImpl::setNodeReportID(Position pos, int offsetAdjust) {
Report ir = rm.getBasicInternalReport(expr, offsetAdjust);
DEBUG_PRINTF("setting report id on %u = (%u, %d, %u)\n",
pos, expr.report, offsetAdjust, ir.ekey);
NFAVertex v = getVertex(pos);
auto &reports = (*graph)[v].reports;
reports.clear();
reports.insert(rm.getInternalId(ir));
}
void NFABuilderImpl::addCharReach(Position pos, const CharReach &cr) {
NFAVertex v = getVertex(pos);
(*graph)[v].char_reach |= cr;
}
void NFABuilderImpl::setAssertFlag(Position pos, u32 flag) {
NFAVertex v = getVertex(pos);
(*graph)[v].assert_flags |= flag;
}
u32 NFABuilderImpl::getAssertFlag(Position pos) {
NFAVertex v = getVertex(pos);
return (*graph)[v].assert_flags;
}
pair<NFAEdge, bool> NFABuilderImpl::addEdge(NFAVertex u, NFAVertex v) {
assert(edge(u, v, *graph).second == false);
return add_edge(u, v, *graph);
}
void NFABuilderImpl::addEdge(Position startPos, Position endPos) {
DEBUG_PRINTF("%u -> %u\n", startPos, endPos);
assert(startPos < vertIdx);
assert(endPos < vertIdx);
NFAVertex u = getVertex(startPos);
NFAVertex v = getVertex(endPos);
if ((u == graph->start || u == graph->startDs) && v == graph->startDs) {
assert(edge(u, v, *graph).second == true);
return;
}
assert(edge(u, v, *graph).second == false);
addEdge(u, v);
}
bool NFABuilderImpl::hasEdge(Position startPos, Position endPos) const {
return edge(getVertex(startPos), getVertex(endPos), *graph).second;
}
Position NFABuilderImpl::getStart() const {
return NODE_START;
}
Position NFABuilderImpl::getStartDotStar() const {
return NODE_START_DOTSTAR;
}
Position NFABuilderImpl::getAccept() const {
return NODE_ACCEPT;
}
Position NFABuilderImpl::getAcceptEOD() const {
return NODE_ACCEPT_EOD;
}
bool NFABuilderImpl::isSpecialState(Position p) const {
return (p == NODE_START || p == NODE_START_DOTSTAR ||
p == NODE_ACCEPT || p == NODE_ACCEPT_EOD);
}
Position NFABuilderImpl::makePositions(size_t nPositions) {
Position base = vertIdx;
for (size_t i = 0; i < nPositions; i++) {
addVertex(vertIdx++);
}
DEBUG_PRINTF("built %zu positions from base %u\n", nPositions, base);
return base;
}
void NFABuilderImpl::cloneRegion(Position first, Position last, unsigned posOffset) {
NGHolder &g = *graph;
assert(posOffset > 0);
DEBUG_PRINTF("cloning nodes in [%u, %u], offset %u\n", first, last,
posOffset);
for (Position i = first; i <= last; ++i) {
NFAVertex orig = getVertex(i);
Position destIdx = i + posOffset;
assert(destIdx < vertIdx);
NFAVertex dest = getVertex(destIdx);
g[dest] = g[orig]; g[dest].index = destIdx;
}
}
unique_ptr<NFABuilder> makeNFABuilder(ReportManager &rm, const CompileContext &cc,
const ParsedExpression &expr) {
return ue2::make_unique<NFABuilderImpl>(rm, cc.grey, expr);
}
NFABuilder::~NFABuilder() { }
}