roseFlushLastByteHistory(t, scratch, offset);
}
-static rose_inline
-void roseCheckEodSuffixes(const struct RoseEngine *t, u64a offset,
- struct hs_scratch *scratch) {
- const u8 *aa = getActiveLeafArray(t, scratch->core_info.state);
- const u32 aaCount = t->activeArrayCount;
- UNUSED u32 qCount = t->queueCount;
-
- for (u32 qi = mmbit_iterate(aa, aaCount, MMB_INVALID); qi != MMB_INVALID;
- qi = mmbit_iterate(aa, aaCount, qi)) {
- const struct NfaInfo *info = getNfaInfoByQueue(t, qi);
- const struct NFA *nfa = getNfaByInfo(t, info);
-
- assert(nfaAcceptsEod(nfa));
-
- DEBUG_PRINTF("checking nfa %u\n", qi);
-
- assert(fatbit_isset(scratch->aqa, qCount, qi)); /* we have just been
- triggered */
-
- char *fstate = scratch->fullState + info->fullStateOffset;
- const char *sstate = scratch->core_info.state + info->stateOffset;
-
- struct mq *q = scratch->queues + qi;
-
- pushQueueNoMerge(q, MQE_END, scratch->core_info.len);
-
- q->context = NULL;
- /* rose exec is used as we don't want to / can't raise matches in the
- * history buffer. */
- char rv = nfaQueueExecRose(q->nfa, q, MO_INVALID_IDX);
- if (rv) { /* nfa is still alive */
- if (nfaCheckFinalState(nfa, fstate, sstate, offset,
- roseReportAdaptor, roseReportSomAdaptor,
- scratch) == MO_HALT_MATCHING) {
- DEBUG_PRINTF("user instructed us to stop\n");
- return;
- }
- }
- }
-}
-
static rose_inline
int roseRunEodProgram(const struct RoseEngine *t, u64a offset,
struct hs_scratch *scratch) {
if (roseEodRunIterator(t, offset, scratch) == MO_HALT_MATCHING) {
return;
}
-
- roseCheckEodSuffixes(t, offset, scratch);
}
}
return HWLM_CONTINUE_MATCHING;
}
+static rose_inline
+hwlmcb_rv_t roseSuffixesEod(const struct RoseEngine *rose,
+ struct hs_scratch *scratch, u64a offset) {
+ const u8 *aa = getActiveLeafArray(rose, scratch->core_info.state);
+ const u32 aaCount = rose->activeArrayCount;
+
+ for (u32 qi = mmbit_iterate(aa, aaCount, MMB_INVALID); qi != MMB_INVALID;
+ qi = mmbit_iterate(aa, aaCount, qi)) {
+ const struct NfaInfo *info = getNfaInfoByQueue(rose, qi);
+ const struct NFA *nfa = getNfaByInfo(rose, info);
+
+ assert(nfaAcceptsEod(nfa));
+
+ DEBUG_PRINTF("checking nfa %u\n", qi);
+
+ /* We have just been triggered. */
+ assert(fatbit_isset(scratch->aqa, rose->queueCount, qi));
+
+ char *fstate = scratch->fullState + info->fullStateOffset;
+ const char *sstate = scratch->core_info.state + info->stateOffset;
+
+ struct mq *q = scratch->queues + qi;
+
+ pushQueueNoMerge(q, MQE_END, scratch->core_info.len);
+
+ q->context = NULL;
+ /* rose exec is used as we don't want to / can't raise matches in the
+ * history buffer. */
+ if (!nfaQueueExecRose(q->nfa, q, MO_INVALID_IDX)) {
+ DEBUG_PRINTF("nfa is dead\n");
+ continue;
+ }
+ if (nfaCheckFinalState(nfa, fstate, sstate, offset, roseReportAdaptor,
+ roseReportSomAdaptor,
+ scratch) == MO_HALT_MATCHING) {
+ DEBUG_PRINTF("user instructed us to stop\n");
+ return HWLM_TERMINATE_MATCHING;
+ }
+ }
+ return HWLM_CONTINUE_MATCHING;
+}
+
static
void updateSeqPoint(struct RoseContext *tctxt, u64a offset,
const char from_mpv) {
}
PROGRAM_NEXT_INSTRUCTION
+ PROGRAM_CASE(SUFFIXES_EOD) {
+ if (roseSuffixesEod(t, scratch, end) ==
+ HWLM_TERMINATE_MATCHING) {
+ return HWLM_TERMINATE_MATCHING;
+ }
+ }
+ PROGRAM_NEXT_INSTRUCTION
+
PROGRAM_CASE(END) {
DEBUG_PRINTF("finished\n");
return HWLM_CONTINUE_MATCHING;
case ROSE_INSTR_SPARSE_ITER_BEGIN: return &u.sparseIterBegin;
case ROSE_INSTR_SPARSE_ITER_NEXT: return &u.sparseIterNext;
case ROSE_INSTR_ENGINES_EOD: return &u.enginesEod;
+ case ROSE_INSTR_SUFFIXES_EOD: return &u.suffixesEod;
case ROSE_INSTR_END: return &u.end;
}
assert(0);
case ROSE_INSTR_SPARSE_ITER_BEGIN: return sizeof(u.sparseIterBegin);
case ROSE_INSTR_SPARSE_ITER_NEXT: return sizeof(u.sparseIterNext);
case ROSE_INSTR_ENGINES_EOD: return sizeof(u.enginesEod);
+ case ROSE_INSTR_SUFFIXES_EOD: return sizeof(u.suffixesEod);
case ROSE_INSTR_END: return sizeof(u.end);
}
assert(0);
ROSE_STRUCT_SPARSE_ITER_BEGIN sparseIterBegin;
ROSE_STRUCT_SPARSE_ITER_NEXT sparseIterNext;
ROSE_STRUCT_ENGINES_EOD enginesEod;
+ ROSE_STRUCT_SUFFIXES_EOD suffixesEod;
ROSE_STRUCT_END end;
} u;
return program;
}
+static
+bool hasEodAnchoredSuffix(const RoseBuildImpl &build) {
+ const RoseGraph &g = build.g;
+ for (auto v : vertices_range(g)) {
+ if (g[v].suffix && build.isInETable(v)) {
+ DEBUG_PRINTF("vertex %zu is in eod table and has a suffix\n",
+ g[v].idx);
+ return true;
+ }
+ }
+ return false;
+}
+
/**
* Returns the pair (program offset, sparse iter offset).
*/
}
}
- if (predProgramLists.empty()) {
- DEBUG_PRINTF("no eod anchored roles\n");
+ vector<RoseInstruction> program;
+ if (!predProgramLists.empty()) {
+ addPredBlocks(bc, predProgramLists, program, false);
+ }
+
+ if (hasEodAnchoredSuffix(build)) {
+ if (!program.empty()) {
+ assert(program.back().code() == ROSE_INSTR_END);
+ program.pop_back();
+ }
+ program.emplace_back(ROSE_INSTR_SUFFIXES_EOD);
+ }
+
+ if (program.empty()) {
return 0;
}
- vector<RoseInstruction> program;
- addPredBlocks(bc, predProgramLists, program, false);
+ program = flattenProgram({program});
assert(program.size() > 1);
applyFinalSpecialisation(program);
}
PROGRAM_NEXT_INSTRUCTION
+ PROGRAM_CASE(SUFFIXES_EOD) {}
+ PROGRAM_NEXT_INSTRUCTION
+
PROGRAM_CASE(END) { return; }
PROGRAM_NEXT_INSTRUCTION
/** \brief Check outfixes and suffixes for EOD and fire reports if so. */
ROSE_INSTR_ENGINES_EOD,
+ /** \brief Catch up and check active suffixes for EOD and fire reports if
+ * so. */
+ ROSE_INSTR_SUFFIXES_EOD,
+
ROSE_INSTR_END //!< End of program.
};
u32 iter_offset; //!< Offset of mmbit_sparse_iter structure.
};
+struct ROSE_STRUCT_SUFFIXES_EOD {
+ u8 code; //!< From enum RoseInstructionCode.
+};
+
struct ROSE_STRUCT_END {
u8 code; //!< From enum RoseInstructionCode.
};