source: icGREP/icgrep-devel/icgrep/re/grapheme_clusters.cpp @ 5772

Last change on this file since 5772 was 5772, checked in by cameron, 10 months ago

resolveGraphemeMode

File size: 5.5 KB
Line 
1#include "grapheme_clusters.h"
2#include <re/re_cc.h>
3#include <re/re_name.h>
4#include <re/re_alt.h>             // for Alt, makeAlt
5#include <re/re_any.h>             // for makeAny, Any
6#include <re/re_assertion.h>       // for Assertion, Assertion::Sense, Asser...
7#include <re/re_diff.h>            // for Diff, makeDiff
8#include <re/re_group.h>
9#include <re/re_intersect.h>       // for Intersect
10#include <re/re_name.h>            // for Name
11#include <re/re_rep.h>             // for Rep, makeRep
12#include <re/re_seq.h>             // for Seq, makeSeq
13#include <re/re_start.h>
14#include <re/re_end.h>
15#include <re/printer_re.h>
16#include <vector>                  // for vector, allocator
17#include <llvm/Support/Casting.h>  // for dyn_cast, isa
18#include <llvm/Support/ErrorHandling.h>
19#include <llvm/Support/raw_ostream.h>
20
21/*
22 Unicode Technical Standard #18 defines grapheme cluster mode, signified by the (?g) switch.
23 The mode is defined in terms of the assertion of grapheme cluster boundary assertions \b{g}
24 after every atomic literal.
25 
26 resolveGraphemeMode transforms a regular expression to perform the required insertion of
27 grapheme cluster boundaries, and the elimination of grapheme cluster mode groups.
28
29*/
30
31using namespace llvm;
32
33namespace re {
34bool hasGraphemeClusterBoundary(const RE * re) {
35    if (isa<CC>(re)) {
36        return false;
37    } else if (const Name * n = dyn_cast<Name>(re)) {
38        if (n->getType() == Name::Type::ZeroWidth) {
39            const std::string nameString = n->getName();
40            return (nameString == "GCB") || (nameString == "nonGCB");
41        }
42        return hasGraphemeClusterBoundary(n->getDefinition());
43    } else if (const Alt * alt = dyn_cast<Alt>(re)) {
44        for (const RE * re : *alt) {
45            if (hasGraphemeClusterBoundary(re)) return true;
46        }
47        return false;
48    } else if (const Seq * seq = dyn_cast<Seq>(re)) {
49        for (const RE * re : *seq) {
50            if (hasGraphemeClusterBoundary(re)) return true;
51        }
52        return false;
53    } else if (const Rep * rep = dyn_cast<Rep>(re)) {
54        return hasGraphemeClusterBoundary(rep->getRE());
55    } else if (const Diff * diff = dyn_cast<Diff>(re)) {
56        return hasGraphemeClusterBoundary(diff->getLH()) || hasGraphemeClusterBoundary(diff->getRH());
57    } else if (const Intersect * e = dyn_cast<Intersect>(re)) {
58        return hasGraphemeClusterBoundary(e->getLH()) || hasGraphemeClusterBoundary(e->getRH());
59    } else if (isa<Start>(re) || isa<End>(re)) {
60        return false;
61    } else if (const Assertion * a = dyn_cast<Assertion>(re)) {
62        return hasGraphemeClusterBoundary(a->getAsserted());
63    } else if (const Group * g = dyn_cast<Group>(re)) {
64        if ((g->getMode() == Group::Mode::GraphemeMode) && (g->getSense() == Group::Sense::On)) return true;
65        else return hasGraphemeClusterBoundary(g->getRE());
66    }
67    else llvm_unreachable("Unknown RE type");
68}
69   
70RE * resolveGraphemeMode(RE * re, bool inGraphemeMode) {
71    if (isa<Name>(re)) {
72        if (inGraphemeMode && (cast<Name>(re)->getName() == "."))
73            return makeSeq({makeAny(), makeRep(makeSeq({makeZeroWidth("NonGCB"), makeAny()}), 0, Rep::UNBOUNDED_REP), makeZeroWidth("GCB")});
74        else return re;
75    }
76    else if (isa<CC>(re)) {
77        if (inGraphemeMode) return makeSeq({re, makeZeroWidth("GCB")});
78        else return re;
79    }
80    else if (Seq * seq = dyn_cast<Seq>(re)) {
81        std::vector<RE*> list;
82        bool afterSingleChar = false;
83        for (auto i = seq->begin(); i != seq->end(); ++i) {
84            bool atSingleChar = isa<CC>(re) && (cast<CC>(re)->count() == 1);
85            if (afterSingleChar && inGraphemeMode && !atSingleChar)
86                list.push_back(makeZeroWidth("GCB"));
87            if (isa<CC>(re)) list.push_back(*i);
88            else {
89                list.push_back(resolveGraphemeMode(*i, inGraphemeMode));
90            }
91            afterSingleChar = atSingleChar;
92        }
93        if (afterSingleChar && inGraphemeMode) list.push_back(makeZeroWidth("GCB"));
94        return makeSeq(list.begin(), list.end());
95    } else if (Group * g = dyn_cast<Group>(re)) {
96        if (g->getMode() == Group::Mode::GraphemeMode) {
97            return resolveGraphemeMode(g->getRE(), g->getSense() == Group::Sense::On);
98        }
99        else {
100            return makeGroup(g->getMode(), resolveGraphemeMode(g->getRE(), inGraphemeMode), g->getSense());
101        }
102    } else if (Alt * alt = dyn_cast<Alt>(re)) {
103        std::vector<RE*> list;
104        for (auto i = alt->begin(); i != alt->end(); ++i) {
105            list.push_back(resolveGraphemeMode(*i, inGraphemeMode));
106        }
107        return makeAlt(list.begin(), list.end());
108    } else if (Rep * rep = dyn_cast<Rep>(re)) {
109        return makeRep(resolveGraphemeMode(rep->getRE(), inGraphemeMode), rep->getLB(), rep->getUB());
110    } else if (const Diff * diff = dyn_cast<const Diff>(re)) {
111        return makeDiff(resolveGraphemeMode(diff->getLH(), inGraphemeMode),
112                        resolveGraphemeMode(diff->getRH(), inGraphemeMode));
113    } else if (const Intersect * e = dyn_cast<const Intersect>(re)) {
114        return makeIntersect(resolveGraphemeMode(e->getLH(), inGraphemeMode),
115                             resolveGraphemeMode(e->getRH(), inGraphemeMode));
116    } else if (const Assertion * a = dyn_cast<Assertion>(re)) {
117        return makeAssertion(resolveGraphemeMode(a->getAsserted(), inGraphemeMode), a->getKind(), a->getSense());
118    } else if (isa<Start>(re) || isa<End>(re)) {
119        return re;
120    } else llvm_unreachable("Unknown RE type");
121}
122
123}
Note: See TracBrowser for help on using the repository browser.