-
//
// file: regexcmp.cpp
//
-// Copyright (C) 2002-2008 International Business Machines Corporation and others.
+// Copyright (C) 2002-2010 International Business Machines Corporation and others.
// All Rights Reserved.
//
// This file contains the ICU regular expression compiler, which is responsible
#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+#include "unicode/ustring.h"
#include "unicode/unistr.h"
#include "unicode/uniset.h"
#include "unicode/uchar.h"
#include "unicode/parseerr.h"
#include "unicode/regex.h"
#include "util.h"
+#include "putilimp.h"
#include "cmemory.h"
#include "cstring.h"
#include "uvectr32.h"
+#include "uvectr64.h"
#include "uassert.h"
#include "ucln_in.h"
#include "uinvchar.h"
// generated by a Perl script.
#include "regexcmp.h"
#include "regexst.h"
+#include "regextxt.h"
RegexCompile::RegexCompile(RegexPattern *rxp, UErrorCode &status) :
fParenStack(status), fSetStack(status), fSetOpStack(status)
{
+ // Lazy init of all shared global sets (needed for init()'s empty text)
+ RegexStaticSets::initGlobals(&status);
+
fStatus = &status;
fRXPat = rxp;
fScanIndex = 0;
- fNextIndex = 0;
+ fLastChar = -1;
fPeekChar = -1;
fLineNum = 1;
fCharNum = 0;
const UnicodeString &pat, // Source pat to be compiled.
UParseError &pp, // Error position info
UErrorCode &e) // Error Code
+{
+ fRXPat->fPatternString = new UnicodeString(pat);
+ UText patternText = UTEXT_INITIALIZER;
+ utext_openConstUnicodeString(&patternText, fRXPat->fPatternString, &e);
+
+ if (U_SUCCESS(e)) {
+ compile(&patternText, pp, e);
+ utext_close(&patternText);
+ }
+}
+
+//
+// compile, UText mode
+// All the work is actually done here.
+//
+void RegexCompile::compile(
+ UText *pat, // Source pat to be compiled.
+ UParseError &pp, // Error position info
+ UErrorCode &e) // Error Code
{
fStatus = &e;
fParseErr = &pp;
}
// There should be no pattern stuff in the RegexPattern object. They can not be reused.
- U_ASSERT(fRXPat->fPattern.length() == 0);
+ U_ASSERT(fRXPat->fPattern == NULL || utext_nativeLength(fRXPat->fPattern) == 0);
// Prepare the RegexPattern object to receive the compiled pattern.
- fRXPat->fPattern = pat;
+ fRXPat->fPattern = utext_clone(fRXPat->fPattern, pat, FALSE, TRUE, fStatus);
fRXPat->fStaticSets = RegexStaticSets::gStaticSets->fPropSets;
fRXPat->fStaticSets8 = RegexStaticSets::gStaticSets->fPropSets8;
// Initialize the pattern scanning state machine
- fPatternLength = pat.length();
+ fPatternLength = utext_nativeLength(pat);
uint16_t state = 1;
const RegexTableEl *tableEl;
nextChar(fC); // Fetch the first char from the pattern string.
// The pattern has now been read and processed, and the compiled code generated.
//
- // Back-reference fixup
- //
- int32_t loc;
- for (loc=0; loc<fRXPat->fCompiledPat->size(); loc++) {
- int32_t op = fRXPat->fCompiledPat->elementAti(loc);
- int32_t opType = URX_TYPE(op);
- if (opType == URX_BACKREF || opType == URX_BACKREF_I) {
- int32_t where = URX_VAL(op);
- if (where > fRXPat->fGroupMap->size()) {
- error(U_REGEX_INVALID_BACK_REF);
- break;
- }
- where = fRXPat->fGroupMap->elementAti(where-1);
- op = URX_BUILD(opType, where);
- fRXPat->fCompiledPat->setElementAt(op, loc);
- }
- }
-
-
//
// Compute the number of digits requried for the largest capture group number.
//
fRXPat->fMaxCaptureDigits = 1;
int32_t n = 10;
- for (;;) {
- if (n > fRXPat->fGroupMap->size()) {
- break;
- }
+ int32_t groupCount = fRXPat->fGroupMap->size();
+ while (n <= groupCount) {
fRXPat->fMaxCaptureDigits++;
n *= 10;
}
// The pattern's fFrameSize so far has accumulated the requirements for
// storage for capture parentheses, counters, etc. that are encountered
// in the pattern. Add space for the two variables that are always
- // present in the saved state: the input string position and the
- // position in the compiled pattern.
+ // present in the saved state: the input string position (int64_t) and
+ // the position in the compiled pattern.
+ //
+ fRXPat->fFrameSize+=RESTACKFRAME_HDRCOUNT;
+
//
- fRXPat->fFrameSize+=2;
+ // Optimization pass 1: NOPs, back-references, and case-folding
+ //
+ stripNOPs();
//
// Get bounds for the minimum and maximum length of a string that this
fRXPat->fMinMatchLen = minMatchLength(3, fRXPat->fCompiledPat->size()-1);
//
- // Optimization passes
+ // Optimization pass 2: match start type
//
matchStartType();
- stripNOPs();
//
// Set up fast latin-1 range sets
// side fails to match and backtracks. Locate the position for the
// save from the location on the top of the parentheses stack.
int32_t savePosition = fParenStack.popi();
- int32_t op = fRXPat->fCompiledPat->elementAti(savePosition);
+ int32_t op = (int32_t)fRXPat->fCompiledPat->elementAti(savePosition);
U_ASSERT(URX_TYPE(op) == URX_NOP); // original contents of reserved location
op = URX_BUILD(URX_STATE_SAVE, fRXPat->fCompiledPat->size()+1);
fRXPat->fCompiledPat->setElementAt(op, savePosition);
// is an '|' alternation within the parens.
//
// Each capture group gets three slots in the save stack frame:
- // 0: Capture Group start position (in input string being matched.)
- // 1: Capture Group end positino.
- // 2: Start of Match-in-progress.
+ // 0: Capture Group start position (in input string being matched.)
+ // 1: Capture Group end position.
+ // 2: Start of Match-in-progress.
// The first two locations are for a completed capture group, and are
// referred to by back references and the like.
// The third location stores the capture start position when an START_CAPTURE is
// encountered. This will be promoted to a completed capture when (and if) the corresponding
- // END_CAPure is encountered.
+ // END_CAPTURE is encountered.
{
fRXPat->fCompiledPat->addElement(URX_BUILD(URX_NOP, 0), *fStatus);
int32_t varsLoc = fRXPat->fFrameSize; // Reserve three slots in match stack frame.
fParenStack.push(fRXPat->fCompiledPat->size()-2, *fStatus); // The STATE_SAVE location
fParenStack.push(fRXPat->fCompiledPat->size()-1, *fStatus); // The second NOP location
- // Instructions #5 and #6 will be added when the ')' is encountered.
+ // Instructions #5 - #7 will be added when the ')' is encountered.
}
break;
// Check for simple constructs, which may get special optimized code.
if (topLoc == fRXPat->fCompiledPat->size() - 1) {
- int32_t repeatedOp = fRXPat->fCompiledPat->elementAti(topLoc);
+ int32_t repeatedOp = (int32_t)fRXPat->fCompiledPat->elementAti(topLoc);
if (URX_TYPE(repeatedOp) == URX_SETREF) {
// Emit optimized code for [char set]+
// Check for simple *, where the construct being repeated
// compiled to single opcode, and might be optimizable.
if (topLoc == fRXPat->fCompiledPat->size() - 1) {
- int32_t repeatedOp = fRXPat->fCompiledPat->elementAti(topLoc);
+ int32_t repeatedOp = (int32_t)fRXPat->fCompiledPat->elementAti(topLoc);
if (URX_TYPE(repeatedOp) == URX_SETREF) {
// Emit optimized code for a [char set]*
int32_t op = URX_BUILD(URX_STO_SP, varLoc);
fRXPat->fCompiledPat->setElementAt(op, topLoc);
- int32_t loopOp = fRXPat->fCompiledPat->popi();
+ int32_t loopOp = (int32_t)fRXPat->fCompiledPat->popi();
U_ASSERT(URX_TYPE(loopOp) == URX_CTR_LOOP && URX_VAL(loopOp) == topLoc);
loopOp++; // point LoopOp after the just-inserted STO_SP
fRXPat->fCompiledPat->push(loopOp, *fStatus);
// Have encountered the ']' that closes a set.
// Force the evaluation of any pending operations within this set,
// leave the completed set on the top of the set stack.
- {
setEval(setEnd);
- int32_t setOp = fSetOpStack.popi();
- U_ASSERT(setOp==setStart);
+ U_ASSERT(fSetOpStack.peeki()==setStart);
+ fSetOpStack.popi();
break;
- }
case doSetFinish:
{
}
- case doSetNegate:
+ case doSetNegate:
// Scanned a '^' at the start of a set.
// Push the negation operator onto the set op stack.
// A twist for case-insensitive matching:
// If the last thing compiled into the pattern was not a literal char,
// force this new literal char to begin a new string, and not append to the previous.
- op = fRXPat->fCompiledPat->lastElementi();
+ op = (int32_t)fRXPat->fCompiledPat->lastElementi();
opType = URX_TYPE(op);
if (!(opType == URX_STRING_LEN || opType == URX_ONECHAR || opType == URX_ONECHAR_I)) {
fixLiterals();
// First char of a string in the pattern.
// Emit a OneChar op into the compiled pattern.
emitONE_CHAR(c);
-
- // Also add it to the string pool, in case we get a second adjacent literal
- // and want to change form ONE_CHAR to STRING
+
+ // Mark that we might actually be starting a string here
fStringOpStart = fRXPat->fLiteralText.length();
- fRXPat->fLiteralText.append(c);
return;
}
- // We are adding onto an existing string
- fRXPat->fLiteralText.append(c);
-
- op = fRXPat->fCompiledPat->lastElementi();
+ op = (int32_t)fRXPat->fCompiledPat->lastElementi();
opType = URX_TYPE(op);
U_ASSERT(opType == URX_ONECHAR || opType == URX_ONECHAR_I || opType == URX_STRING_LEN);
fRXPat->fCompiledPat->setElementAt(op, patternLoc);
return;
}
-
+
// The most recently emitted op is a ONECHAR.
// We've now received another adjacent char. Change the ONECHAR op
// to a string op.
+ fRXPat->fLiteralText.append(URX_VAL(op));
+
if (fModeFlags & UREGEX_CASE_INSENSITIVE) {
op = URX_BUILD(URX_STRING_I, fStringOpStart);
} else {
op = URX_BUILD(URX_STRING_LEN, 0);
fRXPat->fCompiledPat->addElement(op, *fStatus);
}
-
+
+ // We are adding onto an existing string
+ fRXPat->fLiteralText.append(c);
+
// The pattern contains a URX_SRING / URX_STRING_LEN. Update the
// string length to reflect the new char we just added to the string.
stringLen = fRXPat->fLiteralText.length() - fStringOpStart;
if ((fModeFlags & UREGEX_CASE_INSENSITIVE) &&
u_hasBinaryProperty(c, UCHAR_CASE_SENSITIVE)) {
// We have a cased character, and are in case insensitive matching mode.
- c = u_foldCase(c, U_FOLD_CASE_DEFAULT);
+ //c = u_foldCase(c, U_FOLD_CASE_DEFAULT); // !!!: handled in stripNOPs() now
op = URX_BUILD(URX_ONECHAR_I, c);
} else {
// Uncased char, or case sensitive match mode.
// If the last operation from the compiled pattern is not a string,
// nothing needs to be done
- op = fRXPat->fCompiledPat->lastElementi();
+ op = (int32_t)fRXPat->fCompiledPat->lastElementi();
opType = URX_TYPE(op);
if (opType != URX_STRING_LEN) {
return;
//
//------------------------------------------------------------------------------
void RegexCompile::insertOp(int32_t where) {
- UVector32 *code = fRXPat->fCompiledPat;
+ UVector64 *code = fRXPat->fCompiledPat;
U_ASSERT(where>0 && where < code->size());
int32_t nop = URX_BUILD(URX_NOP, 0);
// were moved down by the insert. Fix them.
int32_t loc;
for (loc=0; loc<code->size(); loc++) {
- int32_t op = code->elementAti(loc);
+ int32_t op = (int32_t)code->elementAti(loc);
int32_t opType = URX_TYPE(op);
int32_t opValue = URX_VAL(op);
if ((opType == URX_JMP ||
break;
}
U_ASSERT(patIdx>0 && patIdx <= fRXPat->fCompiledPat->size());
- patOp = fRXPat->fCompiledPat->elementAti(patIdx);
+ patOp = (int32_t)fRXPat->fCompiledPat->elementAti(patIdx);
U_ASSERT(URX_VAL(patOp) == 0); // Branch target for JMP should not be set.
patOp |= fRXPat->fCompiledPat->size(); // Set it now.
fRXPat->fCompiledPat->setElementAt(patOp, patIdx);
// The frame offset of the variables for this cg is obtained from the
// start capture op and put it into the end-capture op.
{
- int32_t captureOp = fRXPat->fCompiledPat->elementAti(fMatchOpenParen+1);
+ int32_t captureOp = (int32_t)fRXPat->fCompiledPat->elementAti(fMatchOpenParen+1);
U_ASSERT(URX_TYPE(captureOp) == URX_START_CAPTURE);
int32_t frameVarLocation = URX_VAL(captureOp);
// Insert a LD_SP operation to restore the state stack to the position
// it was when the atomic parens were entered.
{
- int32_t stoOp = fRXPat->fCompiledPat->elementAti(fMatchOpenParen+1);
+ int32_t stoOp = (int32_t)fRXPat->fCompiledPat->elementAti(fMatchOpenParen+1);
U_ASSERT(URX_TYPE(stoOp) == URX_STO_SP);
int32_t stoLoc = URX_VAL(stoOp);
int32_t ldOp = URX_BUILD(URX_LD_SP, stoLoc);
case lookAhead:
{
- int32_t startOp = fRXPat->fCompiledPat->elementAti(fMatchOpenParen-5);
+ int32_t startOp = (int32_t)fRXPat->fCompiledPat->elementAti(fMatchOpenParen-5);
U_ASSERT(URX_TYPE(startOp) == URX_LA_START);
int32_t dataLoc = URX_VAL(startOp);
int32_t op = URX_BUILD(URX_LA_END, dataLoc);
case negLookAhead:
{
// See comment at doOpenLookAheadNeg
- int32_t startOp = fRXPat->fCompiledPat->elementAti(fMatchOpenParen-1);
+ int32_t startOp = (int32_t)fRXPat->fCompiledPat->elementAti(fMatchOpenParen-1);
U_ASSERT(URX_TYPE(startOp) == URX_LA_START);
int32_t dataLoc = URX_VAL(startOp);
int32_t op = URX_BUILD(URX_LA_END, dataLoc);
fRXPat->fCompiledPat->addElement(op, *fStatus);
op = URX_BUILD(URX_BACKTRACK, 0);
fRXPat->fCompiledPat->addElement(op, *fStatus);
- op = URX_BUILD(URX_LA_END, 0);
+ op = URX_BUILD(URX_LA_END, dataLoc);
fRXPat->fCompiledPat->addElement(op, *fStatus);
// Patch the URX_SAVE near the top of the block.
// The destination of the SAVE is the final LA_END that was just added.
- int32_t saveOp = fRXPat->fCompiledPat->elementAti(fMatchOpenParen);
+ int32_t saveOp = (int32_t)fRXPat->fCompiledPat->elementAti(fMatchOpenParen);
U_ASSERT(URX_TYPE(saveOp) == URX_STATE_SAVE);
int32_t dest = fRXPat->fCompiledPat->size()-1;
saveOp = URX_BUILD(URX_STATE_SAVE, dest);
// See comment at doOpenLookBehind.
// Append the URX_LB_END and URX_LA_END to the compiled pattern.
- int32_t startOp = fRXPat->fCompiledPat->elementAti(fMatchOpenParen-4);
+ int32_t startOp = (int32_t)fRXPat->fCompiledPat->elementAti(fMatchOpenParen-4);
U_ASSERT(URX_TYPE(startOp) == URX_LB_START);
int32_t dataLoc = URX_VAL(startOp);
int32_t op = URX_BUILD(URX_LB_END, dataLoc);
// See comment at doOpenLookBehindNeg.
// Append the URX_LBN_END to the compiled pattern.
- int32_t startOp = fRXPat->fCompiledPat->elementAti(fMatchOpenParen-5);
+ int32_t startOp = (int32_t)fRXPat->fCompiledPat->elementAti(fMatchOpenParen-5);
U_ASSERT(URX_TYPE(startOp) == URX_LB_START);
int32_t dataLoc = URX_VAL(startOp);
int32_t op = URX_BUILD(URX_LBN_END, dataLoc);
// ignored strings, that would be better.)
theSet->removeAllStrings();
int32_t setSize = theSet->size();
- UChar32 firstSetChar = theSet->charAt(0);
switch (setSize) {
case 0:
// The set contains only a single code point. Put it into
// the compiled pattern as a single char operation rather
// than a set, and discard the set itself.
- literalChar(firstSetChar);
+ literalChar(theSet->charAt(0));
delete theSet;
}
break;
fRXPat->fCompiledPat->addElement(op, *fStatus);
if ((fIntervalLow & 0xff000000) != 0 ||
- fIntervalUpper > 0 && (fIntervalUpper & 0xff000000) != 0) {
+ (fIntervalUpper > 0 && (fIntervalUpper & 0xff000000) != 0)) {
error(U_REGEX_NUMBER_TOO_BIG);
}
// Pick up the opcode that is to be repeated
//
- int32_t op = fRXPat->fCompiledPat->elementAti(topOfBlock);
+ int32_t op = (int32_t)fRXPat->fCompiledPat->elementAti(topOfBlock);
// Compute the pattern location where the inline sequence
// will end, and set up the state save op that will be needed.
}
for (loc = 3; loc<end; loc++) {
- op = fRXPat->fCompiledPat->elementAti(loc);
+ op = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
opType = URX_TYPE(op);
// The loop is advancing linearly through the pattern.
case URX_STO_INP_LOC:
case URX_BACKREF: // BackRef. Must assume that it might be a zero length match
case URX_BACKREF_I:
-
+
case URX_STO_SP: // Setup for atomic or possessive blocks. Doesn't change what can match.
case URX_LD_SP:
break;
case URX_STRING:
{
loc++;
- int32_t stringLenOp = fRXPat->fCompiledPat->elementAti(loc);
+ int32_t stringLenOp = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
int32_t stringLen = URX_VAL(stringLenOp);
U_ASSERT(URX_TYPE(stringLenOp) == URX_STRING_LEN);
U_ASSERT(stringLenOp >= 2);
// attempt a string search for possible match positions. But we
// do update the set of possible starting characters.
loc++;
- int32_t stringLenOp = fRXPat->fCompiledPat->elementAti(loc);
+ int32_t stringLenOp = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
int32_t stringLen = URX_VAL(stringLenOp);
U_ASSERT(URX_TYPE(stringLenOp) == URX_STRING_LEN);
U_ASSERT(stringLenOp >= 2);
// move loc forwards to the end of the loop, skipping over the body.
// If the min count is > 0,
// continue normal processing of the body of the loop.
- int32_t loopEndLoc = fRXPat->fCompiledPat->elementAti(loc+1);
+ int32_t loopEndLoc = (int32_t)fRXPat->fCompiledPat->elementAti(loc+1);
loopEndLoc = URX_VAL(loopEndLoc);
- int32_t minLoopCount = fRXPat->fCompiledPat->elementAti(loc+2);
+ int32_t minLoopCount = (int32_t)fRXPat->fCompiledPat->elementAti(loc+2);
if (minLoopCount == 0) {
// Min Loop Count of 0, treat like a forward branch and
// move the current minimum length up to the target
int32_t depth = (opType == URX_LA_START? 2: 1);
for (;;) {
loc++;
- op = fRXPat->fCompiledPat->elementAti(loc);
+ op = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
if (URX_TYPE(op) == URX_LA_START) {
depth+=2;
}
}
for (loc = start; loc<=end; loc++) {
- op = fRXPat->fCompiledPat->elementAti(loc);
+ op = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
opType = URX_TYPE(op);
// The loop is advancing linearly through the pattern.
case URX_STRING_I:
{
loc++;
- int32_t stringLenOp = fRXPat->fCompiledPat->elementAti(loc);
+ int32_t stringLenOp = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
currentLen += URX_VAL(stringLenOp);
}
break;
// move loc forwards to the end of the loop, skipping over the body.
// If the min count is > 0,
// continue normal processing of the body of the loop.
- int32_t loopEndLoc = fRXPat->fCompiledPat->elementAti(loc+1);
+ int32_t loopEndLoc = (int32_t)fRXPat->fCompiledPat->elementAti(loc+1);
loopEndLoc = URX_VAL(loopEndLoc);
- int32_t minLoopCount = fRXPat->fCompiledPat->elementAti(loc+2);
+ int32_t minLoopCount = (int32_t)fRXPat->fCompiledPat->elementAti(loc+2);
if (minLoopCount == 0) {
loc = loopEndLoc;
} else {
int32_t depth = (opType == URX_LA_START? 2: 1);;
for (;;) {
loc++;
- op = fRXPat->fCompiledPat->elementAti(loc);
+ op = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
if (URX_TYPE(op) == URX_LA_START) {
// The boilerplate for look-ahead includes two LA_END insturctions,
// Depth will be decremented by each one when it is seen.
}
for (loc = start; loc<=end; loc++) {
- op = fRXPat->fCompiledPat->elementAti(loc);
+ op = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
opType = URX_TYPE(op);
// The loop is advancing linearly through the pattern.
case URX_STRING_I:
{
loc++;
- int32_t stringLenOp = fRXPat->fCompiledPat->elementAti(loc);
+ int32_t stringLenOp = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
currentLen += URX_VAL(stringLenOp);
}
break;
int32_t depth = 0;
for (;;) {
loc++;
- op = fRXPat->fCompiledPat->elementAti(loc);
+ op = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
if (URX_TYPE(op) == URX_LA_START || URX_TYPE(op) == URX_LB_START) {
depth++;
}
// code generation to provide locations that may be patched later.
// Many end up unneeded, and are removed by this function.
//
+// In order to minimize the number of passes through the pattern,
+// back-reference fixup is also performed here (adjusting
+// back-reference operands to point to the correct frame offsets).
+//
+// In addition, case-insensitive character and string literals are
+// now case-folded here, rather than when first parsed or at match
+// time.
+//
//------------------------------------------------------------------------------
void RegexCompile::stripNOPs() {
int32_t d = 0;
for (loc=0; loc<end; loc++) {
deltas.addElement(d, *fStatus);
- int32_t op = fRXPat->fCompiledPat->elementAti(loc);
+ int32_t op = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
if (URX_TYPE(op) == URX_NOP) {
d++;
}
}
+
+ UnicodeString caseStringBuffer;
+ int32_t stringDelta = 0;
// Make a second pass over the code, removing the NOPs by moving following
// code up, and patching operands that refer to code locations that
int32_t src;
int32_t dst = 0;
for (src=0; src<end; src++) {
- int32_t op = fRXPat->fCompiledPat->elementAti(src);
+ int32_t op = (int32_t)fRXPat->fCompiledPat->elementAti(src);
int32_t opType = URX_TYPE(op);
switch (opType) {
case URX_NOP:
break;
}
+ case URX_ONECHAR_I:
+ {
+ UChar32 c = URX_VAL(op);
+ if (u_hasBinaryProperty(c, UCHAR_CASE_SENSITIVE)) {
+ // We have a cased character to fold
+ c = u_foldCase(c, U_FOLD_CASE_DEFAULT);
+ op = URX_BUILD(URX_ONECHAR_I, c);
+ }
+
+ fRXPat->fCompiledPat->setElementAt(op, dst);
+ dst++;
+ break;
+ }
+ case URX_STRING_I:
+ {
+ op = URX_BUILD(URX_STRING_I, URX_VAL(op)+stringDelta);
+
+ src++;
+ int32_t lengthOp = (int32_t)fRXPat->fCompiledPat->elementAti(src);
+
+ caseStringBuffer.setTo(fRXPat->fLiteralText, URX_VAL(op), URX_VAL(lengthOp));
+ caseStringBuffer.foldCase(U_FOLD_CASE_DEFAULT);
+
+ int32_t newLen = caseStringBuffer.length();
+ if (newLen <= URX_VAL(lengthOp)) {
+ // don't shift if we don't have to, take the tiny memory hit of a smaller string
+ fRXPat->fLiteralText.replace(URX_VAL(op), newLen, caseStringBuffer);
+ } else {
+ // shift other strings over...at least UnicodeString handles this for us!
+ fRXPat->fLiteralText.replace(URX_VAL(op), URX_VAL(lengthOp), caseStringBuffer);
+ stringDelta += newLen - URX_VAL(lengthOp);
+ }
+ lengthOp = URX_BUILD(URX_STRING_LEN, newLen);
+
+ fRXPat->fCompiledPat->setElementAt(op, dst);
+ fRXPat->fCompiledPat->setElementAt(lengthOp, dst+1);
+ dst += 2;
+ break;
+ }
+ case URX_BACKREF:
+ case URX_BACKREF_I:
+ {
+ int32_t where = URX_VAL(op);
+ if (where > fRXPat->fGroupMap->size()) {
+ error(U_REGEX_INVALID_BACK_REF);
+ break;
+ }
+ where = fRXPat->fGroupMap->elementAti(where-1);
+ op = URX_BUILD(opType, where);
+ fRXPat->fCompiledPat->setElementAt(op, dst);
+ dst++;
+
+ fRXPat->fNeedsAltInput = TRUE;
+ break;
+ }
+ case URX_STRING:
+ op = URX_BUILD(URX_STRING, URX_VAL(op)+stringDelta);
+ // continue
case URX_RESERVED_OP:
case URX_RESERVED_OP_N:
case URX_BACKTRACK:
case URX_END:
case URX_ONECHAR:
- case URX_STRING:
case URX_STRING_LEN:
case URX_START_CAPTURE:
case URX_END_CAPTURE:
case URX_DOTANY_UNIX:
case URX_STO_SP:
case URX_LD_SP:
- case URX_BACKREF:
case URX_STO_INP_LOC:
case URX_LA_START:
case URX_LA_END:
- case URX_ONECHAR_I:
- case URX_STRING_I:
- case URX_BACKREF_I:
case URX_DOLLAR_M:
case URX_CARET_M:
case URX_CARET_M_UNIX:
void RegexCompile::error(UErrorCode e) {
if (U_SUCCESS(*fStatus)) {
*fStatus = e;
- fParseErr->line = fLineNum;
- fParseErr->offset = fCharNum;
+ // Hmm. fParseErr (UParseError) line & offset fields are int32_t in public
+ // API (see common/unicode/parseerr.h), while fLineNum and fCharNum are
+ // int64_t. If the values of the latter are out of range for the former,
+ // set them to the appropriate "field not supported" values.
+ if (fLineNum > 0x7FFFFFFF) {
+ fParseErr->line = 0;
+ fParseErr->offset = -1;
+ } else if (fCharNum > 0x7FFFFFFF) {
+ fParseErr->line = (int32_t)fLineNum;
+ fParseErr->offset = -1;
+ } else {
+ fParseErr->line = (int32_t)fLineNum;
+ fParseErr->offset = (int32_t)fCharNum;
+ }
+
+ UErrorCode status = U_ZERO_ERROR; // throwaway status for extracting context
// Fill in the context.
// Note: extractBetween() pins supplied indicies to the string bounds.
uprv_memset(fParseErr->preContext, 0, sizeof(fParseErr->preContext));
uprv_memset(fParseErr->postContext, 0, sizeof(fParseErr->postContext));
- fRXPat->fPattern.extractBetween(fScanIndex-U_PARSE_CONTEXT_LEN+1, fScanIndex,
- fParseErr->preContext, 0);
- fRXPat->fPattern.extractBetween(fScanIndex, fScanIndex+U_PARSE_CONTEXT_LEN-1,
- fParseErr->postContext, 0);
+ utext_extract(fRXPat->fPattern, fScanIndex-U_PARSE_CONTEXT_LEN+1, fScanIndex, fParseErr->preContext, U_PARSE_CONTEXT_LEN, &status);
+ utext_extract(fRXPat->fPattern, fScanIndex, fScanIndex+U_PARSE_CONTEXT_LEN-1, fParseErr->postContext, U_PARSE_CONTEXT_LEN, &status);
}
}
//------------------------------------------------------------------------------
UChar32 RegexCompile::nextCharLL() {
UChar32 ch;
- UnicodeString &pattern = fRXPat->fPattern;
if (fPeekChar != -1) {
ch = fPeekChar;
fPeekChar = -1;
return ch;
}
- if (fPatternLength==0 || fNextIndex >= fPatternLength) {
- return (UChar32)-1;
+
+ // assume we're already in the right place
+ ch = UTEXT_NEXT32(fRXPat->fPattern);
+ if (ch == U_SENTINEL) {
+ return ch;
}
- ch = pattern.char32At(fNextIndex);
- fNextIndex = pattern.moveIndex32(fNextIndex, 1);
if (ch == chCR ||
ch == chNEL ||
ch == chLS ||
- ch == chLF && fLastChar != chCR) {
+ (ch == chLF && fLastChar != chCR)) {
// Character is starting a new line. Bump up the line number, and
// reset the column to 0.
fLineNum++;
//------------------------------------------------------------------------------
void RegexCompile::nextChar(RegexPatternChar &c) {
- fScanIndex = fNextIndex;
+ fScanIndex = UTEXT_GETNATIVEINDEX(fRXPat->fPattern);
c.fChar = nextCharLL();
c.fQuoted = FALSE;
// check for backslash escaped characters.
//
if (c.fChar == chBackSlash) {
- int32_t startX = fNextIndex; // start and end positions of the
- int32_t endX = fNextIndex; // sequence following the '\'
+ int64_t pos = UTEXT_GETNATIVEINDEX(fRXPat->fPattern);
if (RegexStaticSets::gStaticSets->fUnescapeCharSet.contains(peekCharLL())) {
//
// A '\' sequence that is handled by ICU's standard unescapeAt function.
//
nextCharLL(); // get & discard the peeked char.
c.fQuoted = TRUE;
- c.fChar = fRXPat->fPattern.unescapeAt(endX);
- if (startX == endX) {
- error(U_REGEX_BAD_ESCAPE_SEQUENCE);
+
+ if (UTEXT_FULL_TEXT_IN_CHUNK(fRXPat->fPattern, fPatternLength)) {
+ int32_t endIndex = (int32_t)pos;
+ c.fChar = u_unescapeAt(uregex_ucstr_unescape_charAt, &endIndex, (int32_t)fPatternLength, (void *)fRXPat->fPattern->chunkContents);
+
+ if (endIndex == pos) {
+ error(U_REGEX_BAD_ESCAPE_SEQUENCE);
+ }
+ fCharNum += endIndex - pos;
+ UTEXT_SETNATIVEINDEX(fRXPat->fPattern, endIndex);
+ } else {
+ int32_t offset = 0;
+ struct URegexUTextUnescapeCharContext context = U_REGEX_UTEXT_UNESCAPE_CONTEXT(fRXPat->fPattern);
+
+ UTEXT_SETNATIVEINDEX(fRXPat->fPattern, pos);
+ c.fChar = u_unescapeAt(uregex_utext_unescape_charAt, &offset, INT32_MAX, &context);
+
+ if (offset == 0) {
+ error(U_REGEX_BAD_ESCAPE_SEQUENCE);
+ } else if (context.lastOffset == offset) {
+ UTEXT_PREVIOUS32(fRXPat->fPattern);
+ } else if (context.lastOffset != offset-1) {
+ utext_moveIndex32(fRXPat->fPattern, offset - context.lastOffset - 1);
+ }
+ fCharNum += offset;
}
- fCharNum += endX - startX;
- fNextIndex = endX;
}
else if (peekCharLL() == chDigit0) {
// Octal Escape, using Java Regexp Conventions
// which are \0 followed by 1-3 octal digits.
// Different from ICU Unescape handling of Octal, which does not
// require the leading 0.
- // Java also has the convention of only consuning 2 octal digits if
+ // Java also has the convention of only consuming 2 octal digits if
// the three digit number would be > 0xff
//
c.fChar = 0;
// Save the scanner state.
// TODO: move this into the scanner, with the state encapsulated in some way. Ticket 6062
- int32_t savedScanIndex = fScanIndex;
- int32_t savedNextIndex = fNextIndex;
+ int64_t savedScanIndex = fScanIndex;
+ int64_t savedNextIndex = UTEXT_GETNATIVEINDEX(fRXPat->fPattern);
UBool savedQuoteMode = fQuoteMode;
UBool savedInBackslashQuote = fInBackslashQuote;
UBool savedEOLComments = fEOLComments;
- int32_t savedLineNum = fLineNum;
- int32_t savedCharNum = fCharNum;
+ int64_t savedLineNum = fLineNum;
+ int64_t savedCharNum = fCharNum;
UChar32 savedLastChar = fLastChar;
UChar32 savedPeekChar = fPeekChar;
RegexPatternChar savedfC = fC;
// The main scanner will retry the input as a normal set expression,
// not a [:Property:] expression.
fScanIndex = savedScanIndex;
- fNextIndex = savedNextIndex;
fQuoteMode = savedQuoteMode;
fInBackslashQuote = savedInBackslashQuote;
fEOLComments = savedEOLComments;
fLastChar = savedLastChar;
fPeekChar = savedPeekChar;
fC = savedfC;
+ UTEXT_SETNATIVEINDEX(fRXPat->fPattern, savedNextIndex);
}
return uset;
}
//
// The property as it was didn't work.
- // Do emergency fixes -
+
+ // Do [:word:]. It is not recognized as a property by UnicodeSet. "word" not standard POSIX
+ // or standard Java, but many other regular expression packages do recognize it.
+
+ if (propName.caseCompare(UNICODE_STRING_SIMPLE("word"), 0) == 0) {
+ *fStatus = U_ZERO_ERROR;
+ set = new UnicodeSet(*(fRXPat->fStaticSets[URX_ISWORD_SET]));
+ if (set == NULL) {
+ *fStatus = U_MEMORY_ALLOCATION_ERROR;
+ return set;
+ }
+ if (negated) {
+ set->complement();
+ }
+ return set;
+ }
+
+
+ // Do Java fixes -
// InGreek -> InGreek or Coptic, that being the official Unicode name for that block.
// InCombiningMarksforSymbols -> InCombiningDiacriticalMarksforSymbols.
//