MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
regex2nfa.cpp
Go to the documentation of this file.
2
3#include <automaton/nfa.h>
4#include <fe/bitset.h>
5
6#include <mim/lam.h>
7#include <mim/world.h>
8
10
11using namespace mim;
12
13namespace mim::plug::regex {
14
15namespace {
16
17/// Every byte a transition can carry.
18const auto All_Chars = fe::Bitset(256, true);
19
20/// The bytes @p regex matches.
21fe::Bitset gather_chars(const Def* regex) {
22 auto res = fe::Bitset();
23 for (auto arg : detail::flatten_in_arg<regex::disj>(regex)) {
24 if (auto not_ = Axm::isa<regex::not_>(arg)) {
25 res |= All_Chars - gather_chars(not_->arg());
26 } else if (Axm::isa<regex::any>(arg)) {
27 res |= All_Chars;
28 } else {
29 auto rng_match = Axm::isa<regex::range, false>(arg);
30 assert(rng_match
31 && "as per normalizer, if we're in a 'not' argument, we must only have disjs, nots and ranges!");
32
33 auto lb = Lit::as<std::uint8_t>(rng_match->arg(2, 0));
34 auto ub = Lit::as<std::uint8_t>(rng_match->arg(2, 1));
35 for (std::uint16_t c = lb; c <= ub; ++c)
36 res.set(c);
37 }
38 }
39 return res;
40}
41
42struct Regex2NfaConverter {
43 Regex2NfaConverter()
44 : nfa_(std::make_unique<automaton::NFA>()) {}
45
46 void add_range_transitions(automaton::NFANode* from, automaton::NFANode* to, std::uint16_t lb, std::uint16_t ub) {
47 for (auto i = lb; i <= ub; ++i)
48 from->add_transition(to, i);
49 }
50
51 void add_range_transitions(automaton::NFANode* from, automaton::NFANode* to, const Def* lit0, const Def* lit1) {
52 auto lb = lit0->as<Lit>()->get();
53 auto ub = lit1->as<Lit>()->get();
54 add_range_transitions(from, to, lb, ub);
55 }
56
57 void
58 convert(const Def* regex, automaton::NFANode* start, automaton::NFANode* end, automaton::NFANode* error = nullptr) {
59 if (auto conj = Axm::isa<regex::conj>(regex)) {
60 auto middle = nfa_->add_state();
61 convert(conj->arg(2, 0), start, middle, error);
62 convert(conj->arg(2, 1), middle, end, error);
63 } else if (auto any = Axm::isa<regex::any>(regex)) {
64 add_range_transitions(start, end, 0_u16, 255);
65 } else if (auto range = Axm::isa<regex::range>(regex)) {
66 add_range_transitions(start, end, range->arg(2, 0), range->arg(2, 1));
67 if (error) add_range_transitions(start, error, 0, 255);
68 } else if (auto not_ = Axm::isa<regex::not_>(regex)) {
69 auto first = nfa_->add_state();
70
72
73 for (auto c : All_Chars - gather_chars(not_->arg()))
74 first->add_transition(end, std::uint16_t(c));
75 } else if (auto neg = Axm::isa<regex::neg_lookahead>(regex)) {
76 auto first = nfa_->add_state();
77 auto error = nfa_->add_state();
78 error->set_erroring(true);
79
81
82 convert(neg->arg(), first, error, end);
84 } else if (auto disj = Axm::isa<regex::disj>(regex)) {
85 convert(disj->arg(2, 0), start, end, error);
86 convert(disj->arg(2, 1), start, end, error);
87 } else if (auto opt = Axm::isa(quant::optional, regex)) {
89 convert(opt->arg(), start, end);
90 } else if (auto star = Axm::isa(quant::star, regex)) {
91 auto m1 = nfa_->add_state();
92 auto m2 = nfa_->add_state();
95 m2->add_transition(m1, automaton::NFA::SpecialTransitons::EPSILON);
96 m2->add_transition(end, automaton::NFA::SpecialTransitons::EPSILON);
97 convert(star->arg(), m1, m2);
98 } else if (auto plus = Axm::isa(quant::plus, regex)) {
99 auto m0 = nfa_->add_state();
100 auto m1 = nfa_->add_state();
101 auto m2 = nfa_->add_state();
102 convert(plus->arg(), start, m0, error);
103 m0->add_transition(m1, automaton::NFA::SpecialTransitons::EPSILON);
104 m2->add_transition(m1, automaton::NFA::SpecialTransitons::EPSILON);
105 m2->add_transition(end, automaton::NFA::SpecialTransitons::EPSILON);
106 m0->add_transition(end, automaton::NFA::SpecialTransitons::EPSILON);
107 convert(plus->arg(), m1, m2);
108 } else if (auto empty = Axm::isa<regex::empty>(regex)) {
110 }
111 }
112
113 void convert(const Def* regex) {
114 auto start = nfa_->add_state();
115 nfa_->set_start(start);
116 auto end = nfa_->add_state();
117 end->set_accepting(true);
118 convert(regex, start, end);
119 }
120
121 std::unique_ptr<automaton::NFA> nfa() { return std::move(nfa_); }
122
123private:
124 std::unique_ptr<automaton::NFA> nfa_;
125};
126
127} // namespace
128
129std::unique_ptr<automaton::NFA> regex2nfa(const Def* regex) {
130 Regex2NfaConverter converter;
131 converter.convert(regex);
132 return converter.nfa();
133}
134
135} // namespace mim::plug::regex
136
137extern "C" automaton::NFA* regex2nfa(const Def* regex) { return mim::plug::regex::regex2nfa(regex).release(); }
void set_accepting(bool accepting)
Definition nfa.h:42
void add_transition(const NFANode *to, std::uint16_t c)
Definition nfa.cpp:9
static auto isa(const Def *def)
Definition axm.h:112
Base class for all Defs.
Definition def.h:289
static T as(const Def *def)
Definition def.h:982
The regex Plugin
Definition lower_regex.h:5
std::unique_ptr< automaton::NFA > regex2nfa(const Def *regex)
Definition ast.h:16
@ Lit
Definition def.h:125
automaton::NFA * regex2nfa(const mim::Def *regex)
You can fe::dl::get this function.