This source file includes following definitions.
- flags
- rune_max
- ncap_
- FinishRegexp
- PushRegexp
- LookupCaseFold
- ApplyFold
- CycleFoldRune
- AddFoldedRange
- PushLiteral
- PushCarat
- PushWordBoundary
- PushDollar
- PushDot
- PushSimpleOp
- PushRepeatOp
- PushRepetition
- IsMarker
- DoLeftParen
- DoLeftParenNoCapture
- AddLiteral
- DoVerticalBar
- DoRightParen
- DoFinish
- LeadingRegexp
- RemoveLeadingRegexp
- LeadingString
- RemoveLeadingString
- FactorAlternation
- FactorAlternationRecursive
- DoCollapse
- DoConcatenation
- DoAlternation
- MaybeConcatString
- ParseInteger
- MaybeParseRepetition
- StringPieceToRune
- IsValidUTF8
- IsHex
- UnHex
- ParseEscape
- AddRangeFlags
- LookupGroup
- LookupPosixGroup
- LookupPerlGroup
- LookupUnicodeGroup
- AddUGroup
- MaybeParsePerlCCEscape
- ParseUnicodeGroup
- ParseCCName
- ParseCCCharacter
- ParseCCRange
- ParseCharClass
- IsValidCaptureName
- ParsePerlFlags
- ConvertLatin1ToUTF8
- Parse
#include "util/util.h"
#include "re2/regexp.h"
#include "re2/stringpiece.h"
#include "re2/unicode_casefold.h"
#include "re2/unicode_groups.h"
namespace re2 {
class Regexp::ParseState {
public:
ParseState(ParseFlags flags, const StringPiece& whole_regexp,
RegexpStatus* status);
~ParseState();
ParseFlags flags() { return flags_; }
int rune_max() { return rune_max_; }
bool PushRegexp(Regexp* re);
bool PushLiteral(Rune r);
bool PushSimpleOp(RegexpOp op);
bool PushCarat();
bool PushWordBoundary(bool word);
bool PushDollar();
bool PushDot();
bool PushRepeatOp(RegexpOp op, const StringPiece& s, bool nongreedy);
bool PushRepetition(int min, int max, const StringPiece& s, bool nongreedy);
bool IsMarker(RegexpOp op);
bool DoLeftParen(const StringPiece& name);
bool DoLeftParenNoCapture();
bool DoVerticalBar();
bool DoRightParen();
Regexp* DoFinish();
Regexp* FinishRegexp(Regexp*);
bool ParseCharClass(StringPiece* s, Regexp** out_re,
RegexpStatus* status);
bool ParseCCCharacter(StringPiece* s, Rune *rp,
const StringPiece& whole_class,
RegexpStatus* status);
bool ParseCCRange(StringPiece* s, RuneRange* rr,
const StringPiece& whole_class,
RegexpStatus* status);
bool ParsePerlFlags(StringPiece* s);
void DoConcatenation();
void DoAlternation();
void DoCollapse(RegexpOp op);
bool MaybeConcatString(int r, ParseFlags flags);
private:
ParseFlags flags_;
StringPiece whole_regexp_;
RegexpStatus* status_;
Regexp* stacktop_;
int ncap_;
int rune_max_;
DISALLOW_EVIL_CONSTRUCTORS(ParseState);
};
const RegexpOp kLeftParen = static_cast<RegexpOp>(kMaxRegexpOp+1);
const RegexpOp kVerticalBar = static_cast<RegexpOp>(kMaxRegexpOp+2);
Regexp::ParseState::ParseState(ParseFlags flags,
const StringPiece& whole_regexp,
RegexpStatus* status)
: flags_(flags), whole_regexp_(whole_regexp),
status_(status), stacktop_(NULL), ncap_(0) {
if (flags_ & Latin1)
rune_max_ = 0xFF;
else
rune_max_ = Runemax;
}
Regexp::ParseState::~ParseState() {
Regexp* next;
for (Regexp* re = stacktop_; re != NULL; re = next) {
next = re->down_;
re->down_ = NULL;
if (re->op() == kLeftParen)
delete re->name_;
re->Decref();
}
}
Regexp* Regexp::ParseState::FinishRegexp(Regexp* re) {
if (re == NULL)
return NULL;
re->down_ = NULL;
if (re->op_ == kRegexpCharClass && re->ccb_ != NULL) {
CharClassBuilder* ccb = re->ccb_;
re->ccb_ = NULL;
re->cc_ = ccb->GetCharClass();
delete ccb;
}
return re;
}
bool Regexp::ParseState::PushRegexp(Regexp* re) {
MaybeConcatString(-1, NoParseFlags);
if (re->op_ == kRegexpCharClass) {
if (re->ccb_->size() == 1) {
Rune r = re->ccb_->begin()->lo;
re->Decref();
re = new Regexp(kRegexpLiteral, flags_);
re->rune_ = r;
} else if (re->ccb_->size() == 2) {
Rune r = re->ccb_->begin()->lo;
if ('A' <= r && r <= 'Z' && re->ccb_->Contains(r + 'a' - 'A')) {
re->Decref();
re = new Regexp(kRegexpLiteral, flags_ | FoldCase);
re->rune_ = r + 'a' - 'A';
}
}
}
if (!IsMarker(re->op()))
re->simple_ = re->ComputeSimple();
re->down_ = stacktop_;
stacktop_ = re;
return true;
}
CaseFold* LookupCaseFold(CaseFold *f, int n, Rune r) {
CaseFold* ef = f + n;
while (n > 0) {
int m = n/2;
if (f[m].lo <= r && r <= f[m].hi)
return &f[m];
if (r < f[m].lo) {
n = m;
} else {
f += m+1;
n -= m+1;
}
}
if (f < ef)
return f;
return NULL;
}
Rune ApplyFold(CaseFold *f, Rune r) {
switch (f->delta) {
default:
return r + f->delta;
case EvenOddSkip:
if ((r - f->lo) % 2)
return r;
case EvenOdd:
if (r%2 == 0)
return r + 1;
return r - 1;
case OddEvenSkip:
if ((r - f->lo) % 2)
return r;
case OddEven:
if (r%2 == 1)
return r + 1;
return r - 1;
}
}
Rune CycleFoldRune(Rune r) {
CaseFold* f = LookupCaseFold(unicode_casefold, num_unicode_casefold, r);
if (f == NULL || r < f->lo)
return r;
return ApplyFold(f, r);
}
static void AddFoldedRange(CharClassBuilder* cc, Rune lo, Rune hi, int depth) {
if (depth > 10) {
LOG(DFATAL) << "AddFoldedRange recurses too much.";
return;
}
if (!cc->AddRange(lo, hi))
return;
while (lo <= hi) {
CaseFold* f = LookupCaseFold(unicode_casefold, num_unicode_casefold, lo);
if (f == NULL)
break;
if (lo < f->lo) {
lo = f->lo;
continue;
}
Rune lo1 = lo;
Rune hi1 = min<Rune>(hi, f->hi);
switch (f->delta) {
default:
lo1 += f->delta;
hi1 += f->delta;
break;
case EvenOdd:
if (lo1%2 == 1)
lo1--;
if (hi1%2 == 0)
hi1++;
break;
case OddEven:
if (lo1%2 == 0)
lo1--;
if (hi1%2 == 1)
hi1++;
break;
}
AddFoldedRange(cc, lo1, hi1, depth+1);
lo = f->hi + 1;
}
}
bool Regexp::ParseState::PushLiteral(Rune r) {
if ((flags_ & FoldCase) && CycleFoldRune(r) != r) {
Regexp* re = new Regexp(kRegexpCharClass, flags_ & ~FoldCase);
re->ccb_ = new CharClassBuilder;
Rune r1 = r;
do {
if (!(flags_ & NeverNL) || r != '\n') {
re->ccb_->AddRange(r, r);
}
r = CycleFoldRune(r);
} while (r != r1);
re->ccb_->RemoveAbove(rune_max_);
return PushRegexp(re);
}
if ((flags_ & NeverNL) && r == '\n')
return PushRegexp(new Regexp(kRegexpNoMatch, flags_));
if (MaybeConcatString(r, flags_))
return true;
Regexp* re = new Regexp(kRegexpLiteral, flags_);
re->rune_ = r;
return PushRegexp(re);
}
bool Regexp::ParseState::PushCarat() {
if (flags_ & OneLine) {
return PushSimpleOp(kRegexpBeginText);
}
return PushSimpleOp(kRegexpBeginLine);
}
bool Regexp::ParseState::PushWordBoundary(bool word) {
if (word)
return PushSimpleOp(kRegexpWordBoundary);
return PushSimpleOp(kRegexpNoWordBoundary);
}
bool Regexp::ParseState::PushDollar() {
if (flags_ & OneLine) {
Regexp::ParseFlags oflags = flags_;
flags_ = flags_ | WasDollar;
bool ret = PushSimpleOp(kRegexpEndText);
flags_ = oflags;
return ret;
}
return PushSimpleOp(kRegexpEndLine);
}
bool Regexp::ParseState::PushDot() {
if ((flags_ & DotNL) && !(flags_ & NeverNL))
return PushSimpleOp(kRegexpAnyChar);
Regexp* re = new Regexp(kRegexpCharClass, flags_ & ~FoldCase);
re->ccb_ = new CharClassBuilder;
re->ccb_->AddRange(0, '\n' - 1);
re->ccb_->AddRange('\n' + 1, rune_max_);
return PushRegexp(re);
}
bool Regexp::ParseState::PushSimpleOp(RegexpOp op) {
Regexp* re = new Regexp(op, flags_);
return PushRegexp(re);
}
bool Regexp::ParseState::PushRepeatOp(RegexpOp op, const StringPiece& s,
bool nongreedy) {
if (stacktop_ == NULL || IsMarker(stacktop_->op())) {
status_->set_code(kRegexpRepeatArgument);
status_->set_error_arg(s);
return false;
}
Regexp::ParseFlags fl = flags_;
if (nongreedy)
fl = fl ^ NonGreedy;
Regexp* re = new Regexp(op, fl);
re->AllocSub(1);
re->down_ = stacktop_->down_;
re->sub()[0] = FinishRegexp(stacktop_);
re->simple_ = re->ComputeSimple();
stacktop_ = re;
return true;
}
bool Regexp::ParseState::PushRepetition(int min, int max,
const StringPiece& s,
bool nongreedy) {
if ((max != -1 && max < min) || min > 1000 || max > 1000) {
status_->set_code(kRegexpRepeatSize);
status_->set_error_arg(s);
return false;
}
if (stacktop_ == NULL || IsMarker(stacktop_->op())) {
status_->set_code(kRegexpRepeatArgument);
status_->set_error_arg(s);
return false;
}
Regexp::ParseFlags fl = flags_;
if (nongreedy)
fl = fl ^ NonGreedy;
Regexp* re = new Regexp(kRegexpRepeat, fl);
re->min_ = min;
re->max_ = max;
re->AllocSub(1);
re->down_ = stacktop_->down_;
re->sub()[0] = FinishRegexp(stacktop_);
re->simple_ = re->ComputeSimple();
stacktop_ = re;
return true;
}
bool Regexp::ParseState::IsMarker(RegexpOp op) {
return op >= kLeftParen;
}
bool Regexp::ParseState::DoLeftParen(const StringPiece& name) {
Regexp* re = new Regexp(kLeftParen, flags_);
re->cap_ = ++ncap_;
if (name.data() != NULL)
re->name_ = new string(name.as_string());
return PushRegexp(re);
}
bool Regexp::ParseState::DoLeftParenNoCapture() {
Regexp* re = new Regexp(kLeftParen, flags_);
re->cap_ = -1;
return PushRegexp(re);
}
static void AddLiteral(CharClassBuilder* cc, Rune r, bool foldascii) {
cc->AddRange(r, r);
if (foldascii && 'a' <= r && r <= 'z')
cc->AddRange(r + 'A' - 'a', r + 'A' - 'a');
}
bool Regexp::ParseState::DoVerticalBar() {
MaybeConcatString(-1, NoParseFlags);
DoConcatenation();
Regexp* r1;
Regexp* r2;
if ((r1 = stacktop_) != NULL &&
(r2 = stacktop_->down_) != NULL &&
r2->op() == kVerticalBar) {
Regexp* r3;
if ((r1->op() == kRegexpLiteral ||
r1->op() == kRegexpCharClass ||
r1->op() == kRegexpAnyChar) &&
(r3 = r2->down_) != NULL) {
Rune rune;
switch (r3->op()) {
case kRegexpLiteral:
rune = r3->rune_;
r3->op_ = kRegexpCharClass;
r3->cc_ = NULL;
r3->ccb_ = new CharClassBuilder;
AddLiteral(r3->ccb_, rune, r3->parse_flags_ & Regexp::FoldCase);
case kRegexpCharClass:
if (r1->op() == kRegexpLiteral)
AddLiteral(r3->ccb_, r1->rune_,
r1->parse_flags_ & Regexp::FoldCase);
else if (r1->op() == kRegexpCharClass)
r3->ccb_->AddCharClass(r1->ccb_);
if (r1->op() == kRegexpAnyChar || r3->ccb_->full()) {
delete r3->ccb_;
r3->ccb_ = NULL;
r3->op_ = kRegexpAnyChar;
}
case kRegexpAnyChar:
stacktop_ = r2;
r1->Decref();
return true;
default:
break;
}
}
r1->down_ = r2->down_;
r2->down_ = r1;
stacktop_ = r2;
return true;
}
return PushSimpleOp(kVerticalBar);
}
bool Regexp::ParseState::DoRightParen() {
DoAlternation();
Regexp* r1;
Regexp* r2;
if ((r1 = stacktop_) == NULL ||
(r2 = r1->down_) == NULL ||
r2->op() != kLeftParen) {
status_->set_code(kRegexpMissingParen);
status_->set_error_arg(whole_regexp_);
return false;
}
stacktop_ = r2->down_;
Regexp* re = r2;
flags_ = re->parse_flags();
if (re->cap_ > 0) {
re->op_ = kRegexpCapture;
re->AllocSub(1);
re->sub()[0] = FinishRegexp(r1);
re->simple_ = re->ComputeSimple();
} else {
re->Decref();
re = r1;
}
return PushRegexp(re);
}
Regexp* Regexp::ParseState::DoFinish() {
DoAlternation();
Regexp* re = stacktop_;
if (re != NULL && re->down_ != NULL) {
status_->set_code(kRegexpMissingParen);
status_->set_error_arg(whole_regexp_);
return NULL;
}
stacktop_ = NULL;
return FinishRegexp(re);
}
Regexp* Regexp::LeadingRegexp(Regexp* re) {
if (re->op() == kRegexpEmptyMatch)
return NULL;
if (re->op() == kRegexpConcat && re->nsub() >= 2) {
Regexp** sub = re->sub();
if (sub[0]->op() == kRegexpEmptyMatch)
return NULL;
return sub[0];
}
return re;
}
Regexp* Regexp::RemoveLeadingRegexp(Regexp* re) {
if (re->op() == kRegexpEmptyMatch)
return re;
if (re->op() == kRegexpConcat && re->nsub() >= 2) {
Regexp** sub = re->sub();
if (sub[0]->op() == kRegexpEmptyMatch)
return re;
sub[0]->Decref();
sub[0] = NULL;
if (re->nsub() == 2) {
Regexp* nre = sub[1];
sub[1] = NULL;
re->Decref();
return nre;
}
re->nsub_--;
memmove(sub, sub + 1, re->nsub_ * sizeof sub[0]);
return re;
}
Regexp::ParseFlags pf = re->parse_flags();
re->Decref();
return new Regexp(kRegexpEmptyMatch, pf);
}
Rune* Regexp::LeadingString(Regexp* re, int *nrune,
Regexp::ParseFlags *flags) {
while (re->op() == kRegexpConcat && re->nsub() > 0)
re = re->sub()[0];
*flags = static_cast<Regexp::ParseFlags>(re->parse_flags_ & Regexp::FoldCase);
if (re->op() == kRegexpLiteral) {
*nrune = 1;
return &re->rune_;
}
if (re->op() == kRegexpLiteralString) {
*nrune = re->nrunes_;
return re->runes_;
}
*nrune = 0;
return NULL;
}
void Regexp::RemoveLeadingString(Regexp* re, int n) {
Regexp* stk[4];
int d = 0;
while (re->op() == kRegexpConcat) {
if (d < arraysize(stk))
stk[d++] = re;
re = re->sub()[0];
}
if (re->op() == kRegexpLiteral) {
re->rune_ = 0;
re->op_ = kRegexpEmptyMatch;
} else if (re->op() == kRegexpLiteralString) {
if (n >= re->nrunes_) {
delete[] re->runes_;
re->runes_ = NULL;
re->nrunes_ = 0;
re->op_ = kRegexpEmptyMatch;
} else if (n == re->nrunes_ - 1) {
Rune rune = re->runes_[re->nrunes_ - 1];
delete[] re->runes_;
re->runes_ = NULL;
re->nrunes_ = 0;
re->rune_ = rune;
re->op_ = kRegexpLiteral;
} else {
re->nrunes_ -= n;
memmove(re->runes_, re->runes_ + n, re->nrunes_ * sizeof re->runes_[0]);
}
}
while (d-- > 0) {
re = stk[d];
Regexp** sub = re->sub();
if (sub[0]->op() == kRegexpEmptyMatch) {
sub[0]->Decref();
sub[0] = NULL;
switch (re->nsub()) {
case 0:
case 1:
LOG(DFATAL) << "Concat of " << re->nsub();
re->submany_ = NULL;
re->op_ = kRegexpEmptyMatch;
break;
case 2: {
Regexp* old = sub[1];
sub[1] = NULL;
re->Swap(old);
old->Decref();
break;
}
default:
re->nsub_--;
memmove(sub, sub + 1, re->nsub_ * sizeof sub[0]);
break;
}
}
}
}
const int kFactorAlternationMaxDepth = 8;
int Regexp::FactorAlternation(
Regexp** sub, int n,
Regexp::ParseFlags altflags) {
return FactorAlternationRecursive(sub, n, altflags,
kFactorAlternationMaxDepth);
}
int Regexp::FactorAlternationRecursive(
Regexp** sub, int n,
Regexp::ParseFlags altflags,
int maxdepth) {
if (maxdepth <= 0)
return n;
Rune *rune = NULL;
int nrune = 0;
Regexp::ParseFlags runeflags = Regexp::NoParseFlags;
int start = 0;
int out = 0;
for (int i = 0; i <= n; i++) {
Rune* rune_i = NULL;
int nrune_i = 0;
Regexp::ParseFlags runeflags_i = Regexp::NoParseFlags;
if (i < n) {
rune_i = LeadingString(sub[i], &nrune_i, &runeflags_i);
if (runeflags_i == runeflags) {
int same = 0;
while (same < nrune && same < nrune_i && rune[same] == rune_i[same])
same++;
if (same > 0) {
nrune = same;
continue;
}
}
}
if (i == start) {
} else if (i == start+1) {
sub[out++] = sub[start];
} else {
Regexp* x[2];
x[0] = LiteralString(rune, nrune, runeflags);
for (int j = start; j < i; j++)
RemoveLeadingString(sub[j], nrune);
int nn = FactorAlternationRecursive(sub + start, i - start, altflags,
maxdepth - 1);
x[1] = AlternateNoFactor(sub + start, nn, altflags);
sub[out++] = Concat(x, 2, altflags);
}
if (i < n) {
start = i;
rune = rune_i;
nrune = nrune_i;
runeflags = runeflags_i;
}
}
n = out;
start = 0;
out = 0;
Regexp* first = NULL;
for (int i = 0; i <= n; i++) {
Regexp* first_i = NULL;
if (i < n) {
first_i = LeadingRegexp(sub[i]);
if (first != NULL && Regexp::Equal(first, first_i)) {
continue;
}
}
if (i == start) {
} else if (i == start+1) {
sub[out++] = sub[start];
} else {
Regexp* x[2];
x[0] = first->Incref();
for (int j = start; j < i; j++)
sub[j] = RemoveLeadingRegexp(sub[j]);
int nn = FactorAlternationRecursive(sub + start, i - start, altflags,
maxdepth - 1);
x[1] = AlternateNoFactor(sub + start, nn, altflags);
sub[out++] = Concat(x, 2, altflags);
}
if (i < n) {
start = i;
first = first_i;
}
}
n = out;
start = 0;
out = 0;
for (int i = 0; i <= n; i++) {
if (i < n &&
(sub[i]->op() == kRegexpLiteral ||
sub[i]->op() == kRegexpCharClass))
continue;
if (i == start) {
} else if (i == start+1) {
sub[out++] = sub[start];
} else {
CharClassBuilder ccb;
for (int j = start; j < i; j++) {
Regexp* re = sub[j];
if (re->op() == kRegexpCharClass) {
CharClass* cc = re->cc();
for (CharClass::iterator it = cc->begin(); it != cc->end(); ++it)
ccb.AddRange(it->lo, it->hi);
} else if (re->op() == kRegexpLiteral) {
ccb.AddRangeFlags(re->rune(), re->rune(), re->parse_flags());
} else {
LOG(DFATAL) << "RE2: unexpected op: " << re->op() << " "
<< re->ToString();
}
re->Decref();
}
sub[out++] = NewCharClass(ccb.GetCharClass(), altflags);
}
if (i < n)
sub[out++] = sub[i];
start = i+1;
}
n = out;
start = 0;
out = 0;
for (int i = 0; i < n; i++) {
if (i + 1 < n &&
sub[i]->op() == kRegexpEmptyMatch &&
sub[i+1]->op() == kRegexpEmptyMatch) {
sub[i]->Decref();
continue;
}
sub[out++] = sub[i];
}
n = out;
return n;
}
void Regexp::ParseState::DoCollapse(RegexpOp op) {
int n = 0;
Regexp* next = NULL;
Regexp* sub;
for (sub = stacktop_; sub != NULL && !IsMarker(sub->op()); sub = next) {
next = sub->down_;
if (sub->op_ == op)
n += sub->nsub_;
else
n++;
}
if (stacktop_ != NULL && stacktop_->down_ == next)
return;
Regexp** subs = new Regexp*[n];
next = NULL;
int i = n;
for (sub = stacktop_; sub != NULL && !IsMarker(sub->op()); sub = next) {
next = sub->down_;
if (sub->op_ == op) {
Regexp** sub_subs = sub->sub();
for (int k = sub->nsub_ - 1; k >= 0; k--)
subs[--i] = sub_subs[k]->Incref();
sub->Decref();
} else {
subs[--i] = FinishRegexp(sub);
}
}
Regexp* re = ConcatOrAlternate(op, subs, n, flags_, true);
delete[] subs;
re->simple_ = re->ComputeSimple();
re->down_ = next;
stacktop_ = re;
}
void Regexp::ParseState::DoConcatenation() {
Regexp* r1 = stacktop_;
if (r1 == NULL || IsMarker(r1->op())) {
Regexp* re = new Regexp(kRegexpEmptyMatch, flags_);
PushRegexp(re);
}
DoCollapse(kRegexpConcat);
}
void Regexp::ParseState::DoAlternation() {
DoVerticalBar();
Regexp* r1 = stacktop_;
stacktop_ = r1->down_;
r1->Decref();
DoCollapse(kRegexpAlternate);
}
bool Regexp::ParseState::MaybeConcatString(int r, ParseFlags flags) {
Regexp* re1;
Regexp* re2;
if ((re1 = stacktop_) == NULL || (re2 = re1->down_) == NULL)
return false;
if (re1->op_ != kRegexpLiteral && re1->op_ != kRegexpLiteralString)
return false;
if (re2->op_ != kRegexpLiteral && re2->op_ != kRegexpLiteralString)
return false;
if ((re1->parse_flags_ & FoldCase) != (re2->parse_flags_ & FoldCase))
return false;
if (re2->op_ == kRegexpLiteral) {
Rune rune = re2->rune_;
re2->op_ = kRegexpLiteralString;
re2->nrunes_ = 0;
re2->runes_ = NULL;
re2->AddRuneToString(rune);
}
if (re1->op_ == kRegexpLiteral) {
re2->AddRuneToString(re1->rune_);
} else {
for (int i = 0; i < re1->nrunes_; i++)
re2->AddRuneToString(re1->runes_[i]);
re1->nrunes_ = 0;
delete[] re1->runes_;
re1->runes_ = NULL;
}
if (r >= 0) {
re1->op_ = kRegexpLiteral;
re1->rune_ = r;
re1->parse_flags_ = flags;
return true;
}
stacktop_ = re2;
re1->Decref();
return false;
}
static bool ParseInteger(StringPiece* s, int* np) {
if (s->size() == 0 || !isdigit((*s)[0] & 0xFF))
return false;
if (s->size() >= 2 && (*s)[0] == '0' && isdigit((*s)[1] & 0xFF))
return false;
int n = 0;
int c;
while (s->size() > 0 && isdigit(c = (*s)[0] & 0xFF)) {
if (n >= 100000000)
return false;
n = n*10 + c - '0';
s->remove_prefix(1);
}
*np = n;
return true;
}
static bool MaybeParseRepetition(StringPiece* sp, int* lo, int* hi) {
StringPiece s = *sp;
if (s.size() == 0 || s[0] != '{')
return false;
s.remove_prefix(1);
if (!ParseInteger(&s, lo))
return false;
if (s.size() == 0)
return false;
if (s[0] == ',') {
s.remove_prefix(1);
if (s.size() == 0)
return false;
if (s[0] == '}') {
*hi = -1;
} else {
if (!ParseInteger(&s, hi))
return false;
}
} else {
*hi = *lo;
}
if (s.size() == 0 || s[0] != '}')
return false;
s.remove_prefix(1);
*sp = s;
return true;
}
static int StringPieceToRune(Rune *r, StringPiece *sp, RegexpStatus* status) {
int n;
if (fullrune(sp->data(), sp->size())) {
n = chartorune(r, sp->data());
if (!(n == 1 && *r == Runeerror)) {
sp->remove_prefix(n);
return n;
}
}
status->set_code(kRegexpBadUTF8);
status->set_error_arg(NULL);
return -1;
}
static bool IsValidUTF8(const StringPiece& s, RegexpStatus* status) {
StringPiece t = s;
Rune r;
while (t.size() > 0) {
if (StringPieceToRune(&r, &t, status) < 0)
return false;
}
return true;
}
static int IsHex(int c) {
return ('0' <= c && c <= '9') ||
('A' <= c && c <= 'F') ||
('a' <= c && c <= 'f');
}
static int UnHex(int c) {
if ('0' <= c && c <= '9')
return c - '0';
if ('A' <= c && c <= 'F')
return c - 'A' + 10;
if ('a' <= c && c <= 'f')
return c - 'a' + 10;
LOG(DFATAL) << "Bad hex digit " << c;
return 0;
}
static bool ParseEscape(StringPiece* s, Rune* rp,
RegexpStatus* status, int rune_max) {
const char* begin = s->begin();
if (s->size() < 1 || (*s)[0] != '\\') {
status->set_code(kRegexpInternalError);
status->set_error_arg(NULL);
return false;
}
if (s->size() < 2) {
status->set_code(kRegexpTrailingBackslash);
status->set_error_arg(NULL);
return false;
}
Rune c, c1;
s->remove_prefix(1);
if (StringPieceToRune(&c, s, status) < 0)
return false;
int code;
switch (c) {
default:
if (c < Runeself && !isalpha(c) && !isdigit(c)) {
*rp = c;
return true;
}
goto BadEscape;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
if (s->size() == 0 || (*s)[0] < '0' || (*s)[0] > '7')
goto BadEscape;
case '0':
code = c - '0';
if (s->size() > 0 && '0' <= (c = (*s)[0]) && c <= '7') {
code = code * 8 + c - '0';
s->remove_prefix(1);
if (s->size() > 0) {
c = (*s)[0];
if ('0' <= c && c <= '7') {
code = code * 8 + c - '0';
s->remove_prefix(1);
}
}
}
*rp = code;
return true;
case 'x':
if (s->size() == 0)
goto BadEscape;
if (StringPieceToRune(&c, s, status) < 0)
return false;
if (c == '{') {
if (StringPieceToRune(&c, s, status) < 0)
return false;
int nhex = 0;
code = 0;
while (IsHex(c)) {
nhex++;
code = code * 16 + UnHex(c);
if (code > rune_max)
goto BadEscape;
if (s->size() == 0)
goto BadEscape;
if (StringPieceToRune(&c, s, status) < 0)
return false;
}
if (c != '}' || nhex == 0)
goto BadEscape;
*rp = code;
return true;
}
if (s->size() == 0)
goto BadEscape;
if (StringPieceToRune(&c1, s, status) < 0)
return false;
if (!IsHex(c) || !IsHex(c1))
goto BadEscape;
*rp = UnHex(c) * 16 + UnHex(c1);
return true;
case 'n':
*rp = '\n';
return true;
case 'r':
*rp = '\r';
return true;
case 't':
*rp = '\t';
return true;
case 'a':
*rp = '\a';
return true;
case 'f':
*rp = '\f';
return true;
case 'v':
*rp = '\v';
return true;
}
LOG(DFATAL) << "Not reached in ParseEscape.";
BadEscape:
status->set_code(kRegexpBadEscape);
status->set_error_arg(StringPiece(begin, s->data() - begin));
return false;
}
void CharClassBuilder::AddRangeFlags(
Rune lo, Rune hi, Regexp::ParseFlags parse_flags) {
bool cutnl = !(parse_flags & Regexp::ClassNL) ||
(parse_flags & Regexp::NeverNL);
if (cutnl && lo <= '\n' && '\n' <= hi) {
if (lo < '\n')
AddRangeFlags(lo, '\n' - 1, parse_flags);
if (hi > '\n')
AddRangeFlags('\n' + 1, hi, parse_flags);
return;
}
if (parse_flags & Regexp::FoldCase)
AddFoldedRange(this, lo, hi, 0);
else
AddRange(lo, hi);
}
static UGroup* LookupGroup(const StringPiece& name,
UGroup *groups, int ngroups) {
for (int i = 0; i < ngroups; i++)
if (StringPiece(groups[i].name) == name)
return &groups[i];
return NULL;
}
static URange16 any16[] = { { 0, 65535 } };
static URange32 any32[] = { { 65536, Runemax } };
static UGroup anygroup = { "Any", +1, any16, 1, any32, 1 };
static UGroup* LookupPosixGroup(const StringPiece& name) {
return LookupGroup(name, posix_groups, num_posix_groups);
}
static UGroup* LookupPerlGroup(const StringPiece& name) {
return LookupGroup(name, perl_groups, num_perl_groups);
}
static UGroup* LookupUnicodeGroup(const StringPiece& name) {
if (name == StringPiece("Any"))
return &anygroup;
return LookupGroup(name, unicode_groups, num_unicode_groups);
}
static void AddUGroup(CharClassBuilder *cc, UGroup *g, int sign,
Regexp::ParseFlags parse_flags) {
if (sign == +1) {
for (int i = 0; i < g->nr16; i++) {
cc->AddRangeFlags(g->r16[i].lo, g->r16[i].hi, parse_flags);
}
for (int i = 0; i < g->nr32; i++) {
cc->AddRangeFlags(g->r32[i].lo, g->r32[i].hi, parse_flags);
}
} else {
if (parse_flags & Regexp::FoldCase) {
CharClassBuilder ccb1;
AddUGroup(&ccb1, g, +1, parse_flags);
bool cutnl = !(parse_flags & Regexp::ClassNL) ||
(parse_flags & Regexp::NeverNL);
if (cutnl) {
ccb1.AddRange('\n', '\n');
}
ccb1.Negate();
cc->AddCharClass(&ccb1);
return;
}
int next = 0;
for (int i = 0; i < g->nr16; i++) {
if (next < g->r16[i].lo)
cc->AddRangeFlags(next, g->r16[i].lo - 1, parse_flags);
next = g->r16[i].hi + 1;
}
for (int i = 0; i < g->nr32; i++) {
if (next < g->r32[i].lo)
cc->AddRangeFlags(next, g->r32[i].lo - 1, parse_flags);
next = g->r32[i].hi + 1;
}
if (next <= Runemax)
cc->AddRangeFlags(next, Runemax, parse_flags);
}
}
UGroup* MaybeParsePerlCCEscape(StringPiece* s, Regexp::ParseFlags parse_flags) {
if (!(parse_flags & Regexp::PerlClasses))
return NULL;
if (s->size() < 2 || (*s)[0] != '\\')
return NULL;
StringPiece name(s->begin(), 2);
UGroup *g = LookupPerlGroup(name);
if (g == NULL)
return NULL;
s->remove_prefix(name.size());
return g;
}
enum ParseStatus {
kParseOk,
kParseError,
kParseNothing,
};
ParseStatus ParseUnicodeGroup(StringPiece* s, Regexp::ParseFlags parse_flags,
CharClassBuilder *cc,
RegexpStatus* status) {
if (!(parse_flags & Regexp::UnicodeGroups))
return kParseNothing;
if (s->size() < 2 || (*s)[0] != '\\')
return kParseNothing;
Rune c = (*s)[1];
if (c != 'p' && c != 'P')
return kParseNothing;
int sign = +1;
if (c == 'P')
sign = -1;
StringPiece seq = *s;
StringPiece name;
s->remove_prefix(2);
if (!StringPieceToRune(&c, s, status))
return kParseError;
if (c != '{') {
const char* p = seq.begin() + 2;
name = StringPiece(p, s->begin() - p);
} else {
int end = s->find('}', 0);
if (end == s->npos) {
if (!IsValidUTF8(seq, status))
return kParseError;
status->set_code(kRegexpBadCharRange);
status->set_error_arg(seq);
return kParseError;
}
name = StringPiece(s->begin(), end);
s->remove_prefix(end + 1);
if (!IsValidUTF8(name, status))
return kParseError;
}
seq = StringPiece(seq.begin(), s->begin() - seq.begin());
if (name.size() > 0 && name[0] == '^') {
sign = -sign;
name.remove_prefix(1);
}
UGroup *g = LookupUnicodeGroup(name);
if (g == NULL) {
status->set_code(kRegexpBadCharRange);
status->set_error_arg(seq);
return kParseError;
}
AddUGroup(cc, g, sign, parse_flags);
return kParseOk;
}
static ParseStatus ParseCCName(StringPiece* s, Regexp::ParseFlags parse_flags,
CharClassBuilder *cc,
RegexpStatus* status) {
const char* p = s->data();
const char* ep = s->data() + s->size();
if (ep - p < 2 || p[0] != '[' || p[1] != ':')
return kParseNothing;
const char* q;
for (q = p+2; q <= ep-2 && (*q != ':' || *(q+1) != ']'); q++)
;
if (q > ep-2)
return kParseNothing;
q += 2;
StringPiece name(p, q-p);
UGroup *g = LookupPosixGroup(name);
if (g == NULL) {
status->set_code(kRegexpBadCharRange);
status->set_error_arg(name);
return kParseError;
}
s->remove_prefix(name.size());
AddUGroup(cc, g, g->sign, parse_flags);
return kParseOk;
}
bool Regexp::ParseState::ParseCCCharacter(StringPiece* s, Rune *rp,
const StringPiece& whole_class,
RegexpStatus* status) {
if (s->size() == 0) {
status->set_code(kRegexpMissingBracket);
status->set_error_arg(whole_class);
return false;
}
if (s->size() >= 1 && (*s)[0] == '\\')
return ParseEscape(s, rp, status, rune_max_);
return StringPieceToRune(rp, s, status) >= 0;
}
bool Regexp::ParseState::ParseCCRange(StringPiece* s, RuneRange* rr,
const StringPiece& whole_class,
RegexpStatus* status) {
StringPiece os = *s;
if (!ParseCCCharacter(s, &rr->lo, whole_class, status))
return false;
if (s->size() >= 2 && (*s)[0] == '-' && (*s)[1] != ']') {
s->remove_prefix(1);
if (!ParseCCCharacter(s, &rr->hi, whole_class, status))
return false;
if (rr->hi < rr->lo) {
status->set_code(kRegexpBadCharRange);
status->set_error_arg(StringPiece(os.data(), s->data() - os.data()));
return false;
}
} else {
rr->hi = rr->lo;
}
return true;
}
bool Regexp::ParseState::ParseCharClass(StringPiece* s,
Regexp** out_re,
RegexpStatus* status) {
StringPiece whole_class = *s;
if (s->size() == 0 || (*s)[0] != '[') {
status->set_code(kRegexpInternalError);
status->set_error_arg(NULL);
return false;
}
bool negated = false;
Regexp* re = new Regexp(kRegexpCharClass, flags_ & ~FoldCase);
re->ccb_ = new CharClassBuilder;
s->remove_prefix(1);
if (s->size() > 0 && (*s)[0] == '^') {
s->remove_prefix(1);
negated = true;
if (!(flags_ & ClassNL) || (flags_ & NeverNL)) {
re->ccb_->AddRange('\n', '\n');
}
}
bool first = true;
while (s->size() > 0 && ((*s)[0] != ']' || first)) {
if ((*s)[0] == '-' && !first && !(flags_&PerlX) &&
(s->size() == 1 || (*s)[1] != ']')) {
StringPiece t = *s;
t.remove_prefix(1);
Rune r;
int n = StringPieceToRune(&r, &t, status);
if (n < 0) {
re->Decref();
return false;
}
status->set_code(kRegexpBadCharRange);
status->set_error_arg(StringPiece(s->data(), 1+n));
re->Decref();
return false;
}
first = false;
if (s->size() > 2 && (*s)[0] == '[' && (*s)[1] == ':') {
switch (ParseCCName(s, flags_, re->ccb_, status)) {
case kParseOk:
continue;
case kParseError:
re->Decref();
return false;
case kParseNothing:
break;
}
}
if (s->size() > 2 &&
(*s)[0] == '\\' &&
((*s)[1] == 'p' || (*s)[1] == 'P')) {
switch (ParseUnicodeGroup(s, flags_, re->ccb_, status)) {
case kParseOk:
continue;
case kParseError:
re->Decref();
return false;
case kParseNothing:
break;
}
}
UGroup *g = MaybeParsePerlCCEscape(s, flags_);
if (g != NULL) {
AddUGroup(re->ccb_, g, g->sign, flags_);
continue;
}
RuneRange rr;
if (!ParseCCRange(s, &rr, whole_class, status)) {
re->Decref();
return false;
}
re->ccb_->AddRangeFlags(rr.lo, rr.hi, flags_ | Regexp::ClassNL);
}
if (s->size() == 0) {
status->set_code(kRegexpMissingBracket);
status->set_error_arg(whole_class);
re->Decref();
return false;
}
s->remove_prefix(1);
if (negated)
re->ccb_->Negate();
re->ccb_->RemoveAbove(rune_max_);
*out_re = re;
return true;
}
static bool IsValidCaptureName(const StringPiece& name) {
if (name.size() == 0)
return false;
for (int i = 0; i < name.size(); i++) {
int c = name[i];
if (('0' <= c && c <= '9') ||
('a' <= c && c <= 'z') ||
('A' <= c && c <= 'Z') ||
c == '_')
continue;
return false;
}
return true;
}
bool Regexp::ParseState::ParsePerlFlags(StringPiece* s) {
StringPiece t = *s;
if (!(flags_ & PerlX) || t.size() < 2 || t[0] != '(' || t[1] != '?') {
LOG(DFATAL) << "Bad call to ParseState::ParsePerlFlags";
status_->set_code(kRegexpInternalError);
return false;
}
t.remove_prefix(2);
if (t.size() > 2 && t[0] == 'P' && t[1] == '<') {
int end = t.find('>', 2);
if (end == t.npos) {
if (!IsValidUTF8(*s, status_))
return false;
status_->set_code(kRegexpBadNamedCapture);
status_->set_error_arg(*s);
return false;
}
StringPiece capture(t.begin()-2, end+3);
StringPiece name(t.begin()+2, end-2);
if (!IsValidUTF8(name, status_))
return false;
if (!IsValidCaptureName(name)) {
status_->set_code(kRegexpBadNamedCapture);
status_->set_error_arg(capture);
return false;
}
if (!DoLeftParen(name)) {
return false;
}
s->remove_prefix(capture.end() - s->begin());
return true;
}
bool negated = false;
bool sawflags = false;
int nflags = flags_;
Rune c;
for (bool done = false; !done; ) {
if (t.size() == 0)
goto BadPerlOp;
if (StringPieceToRune(&c, &t, status_) < 0)
return false;
switch (c) {
default:
goto BadPerlOp;
case 'i':
sawflags = true;
if (negated)
nflags &= ~FoldCase;
else
nflags |= FoldCase;
break;
case 'm':
sawflags = true;
if (negated)
nflags |= OneLine;
else
nflags &= ~OneLine;
break;
case 's':
sawflags = true;
if (negated)
nflags &= ~DotNL;
else
nflags |= DotNL;
break;
case 'U':
sawflags = true;
if (negated)
nflags &= ~NonGreedy;
else
nflags |= NonGreedy;
break;
case '-':
if (negated)
goto BadPerlOp;
negated = true;
sawflags = false;
break;
case ':':
if (!DoLeftParenNoCapture()) {
return false;
}
done = true;
break;
case ')':
done = true;
break;
}
}
if (negated && !sawflags)
goto BadPerlOp;
flags_ = static_cast<Regexp::ParseFlags>(nflags);
*s = t;
return true;
BadPerlOp:
status_->set_code(kRegexpBadPerlOp);
status_->set_error_arg(StringPiece(s->begin(), t.begin() - s->begin()));
return false;
}
void ConvertLatin1ToUTF8(const StringPiece& latin1, string* utf) {
char buf[UTFmax];
utf->clear();
for (int i = 0; i < latin1.size(); i++) {
Rune r = latin1[i] & 0xFF;
int n = runetochar(buf, &r);
utf->append(buf, n);
}
}
Regexp* Regexp::Parse(const StringPiece& s, ParseFlags global_flags,
RegexpStatus* status) {
RegexpStatus xstatus;
if (status == NULL)
status = &xstatus;
ParseState ps(global_flags, s, status);
StringPiece t = s;
if (global_flags & Latin1) {
string* tmp = new string;
ConvertLatin1ToUTF8(t, tmp);
status->set_tmp(tmp);
t = *tmp;
}
if (global_flags & Literal) {
while (t.size() > 0) {
Rune r;
if (StringPieceToRune(&r, &t, status) < 0)
return NULL;
if (!ps.PushLiteral(r))
return NULL;
}
return ps.DoFinish();
}
StringPiece lastunary = NULL;
while (t.size() > 0) {
StringPiece isunary = NULL;
switch (t[0]) {
default: {
Rune r;
if (StringPieceToRune(&r, &t, status) < 0)
return NULL;
if (!ps.PushLiteral(r))
return NULL;
break;
}
case '(':
if ((ps.flags() & PerlX) && (t.size() >= 2 && t[1] == '?')) {
if (!ps.ParsePerlFlags(&t))
return NULL;
break;
}
if (ps.flags() & NeverCapture) {
if (!ps.DoLeftParenNoCapture())
return NULL;
} else {
if (!ps.DoLeftParen(NULL))
return NULL;
}
t.remove_prefix(1);
break;
case '|':
if (!ps.DoVerticalBar())
return NULL;
t.remove_prefix(1);
break;
case ')':
if (!ps.DoRightParen())
return NULL;
t.remove_prefix(1);
break;
case '^':
if (!ps.PushCarat())
return NULL;
t.remove_prefix(1);
break;
case '$':
if (!ps.PushDollar())
return NULL;
t.remove_prefix(1);
break;
case '.':
if (!ps.PushDot())
return NULL;
t.remove_prefix(1);
break;
case '[': {
Regexp* re;
if (!ps.ParseCharClass(&t, &re, status))
return NULL;
if (!ps.PushRegexp(re))
return NULL;
break;
}
case '*': {
RegexpOp op;
op = kRegexpStar;
goto Rep;
case '+':
op = kRegexpPlus;
goto Rep;
case '?':
op = kRegexpQuest;
goto Rep;
Rep:
StringPiece opstr = t;
bool nongreedy = false;
t.remove_prefix(1);
if (ps.flags() & PerlX) {
if (t.size() > 0 && t[0] == '?') {
nongreedy = true;
t.remove_prefix(1);
}
if (lastunary.size() > 0) {
status->set_code(kRegexpRepeatOp);
status->set_error_arg(StringPiece(lastunary.begin(),
t.begin() - lastunary.begin()));
return NULL;
}
}
opstr.set(opstr.data(), t.data() - opstr.data());
if (!ps.PushRepeatOp(op, opstr, nongreedy))
return NULL;
isunary = opstr;
break;
}
case '{': {
int lo, hi;
StringPiece opstr = t;
if (!MaybeParseRepetition(&t, &lo, &hi)) {
if (!ps.PushLiteral('{'))
return NULL;
t.remove_prefix(1);
break;
}
bool nongreedy = false;
if (ps.flags() & PerlX) {
if (t.size() > 0 && t[0] == '?') {
nongreedy = true;
t.remove_prefix(1);
}
if (lastunary.size() > 0) {
status->set_code(kRegexpRepeatOp);
status->set_error_arg(StringPiece(lastunary.begin(),
t.begin() - lastunary.begin()));
return NULL;
}
}
opstr.set(opstr.data(), t.data() - opstr.data());
if (!ps.PushRepetition(lo, hi, opstr, nongreedy))
return NULL;
isunary = opstr;
break;
}
case '\\': {
if ((ps.flags() & Regexp::PerlB) &&
t.size() >= 2 && (t[1] == 'b' || t[1] == 'B')) {
if (!ps.PushWordBoundary(t[1] == 'b'))
return NULL;
t.remove_prefix(2);
break;
}
if ((ps.flags() & Regexp::PerlX) && t.size() >= 2) {
if (t[1] == 'A') {
if (!ps.PushSimpleOp(kRegexpBeginText))
return NULL;
t.remove_prefix(2);
break;
}
if (t[1] == 'z') {
if (!ps.PushSimpleOp(kRegexpEndText))
return NULL;
t.remove_prefix(2);
break;
}
if (t[1] == 'C') {
if (!ps.PushSimpleOp(kRegexpAnyByte))
return NULL;
t.remove_prefix(2);
break;
}
if (t[1] == 'Q') {
t.remove_prefix(2);
while (t.size() > 0) {
if (t.size() >= 2 && t[0] == '\\' && t[1] == 'E') {
t.remove_prefix(2);
break;
}
Rune r;
if (StringPieceToRune(&r, &t, status) < 0)
return NULL;
if (!ps.PushLiteral(r))
return NULL;
}
break;
}
}
if (t.size() >= 2 && (t[1] == 'p' || t[1] == 'P')) {
Regexp* re = new Regexp(kRegexpCharClass, ps.flags() & ~FoldCase);
re->ccb_ = new CharClassBuilder;
switch (ParseUnicodeGroup(&t, ps.flags(), re->ccb_, status)) {
case kParseOk:
if (!ps.PushRegexp(re))
return NULL;
goto Break2;
case kParseError:
re->Decref();
return NULL;
case kParseNothing:
re->Decref();
break;
}
}
UGroup *g = MaybeParsePerlCCEscape(&t, ps.flags());
if (g != NULL) {
Regexp* re = new Regexp(kRegexpCharClass, ps.flags() & ~FoldCase);
re->ccb_ = new CharClassBuilder;
AddUGroup(re->ccb_, g, g->sign, ps.flags());
if (!ps.PushRegexp(re))
return NULL;
break;
}
Rune r;
if (!ParseEscape(&t, &r, status, ps.rune_max()))
return NULL;
if (!ps.PushLiteral(r))
return NULL;
break;
}
}
Break2:
lastunary = isunary;
}
return ps.DoFinish();
}
}