Mostly just some cleaning up - especially in regexp.

Merged server specific GC changes from NES branch.
Bunch o' ECMA version 3 fixes to jsregexp.
This commit is contained in:
rogerl%netscape.com 1999-09-07 20:34:47 +00:00
parent 549e69a421
commit c79698a838
7 changed files with 464 additions and 372 deletions

View File

@ -764,13 +764,19 @@ JS_NewContext(JSRuntime *rt, size_t stacksize)
JS_PUBLIC_API(void)
JS_DestroyContext(JSContext *cx)
{
js_DestroyContext(cx, JS_TRUE);
js_DestroyContext(cx, JS_FORCE_GC);
}
JS_PUBLIC_API(void)
JS_DestroyContextNoGC(JSContext *cx)
{
js_DestroyContext(cx, JS_FALSE);
js_DestroyContext(cx, JS_NO_GC);
}
JS_PUBLIC_API(void)
JS_DestroyContextMaybeGC(JSContext *cx)
{
js_DestroyContext(cx, JS_MAYBE_GC);
}
JS_PUBLIC_API(void*)
@ -1082,7 +1088,20 @@ JS_MaybeGC(JSContext *cx)
rt = cx->runtime;
bytes = rt->gcBytes;
lastBytes = rt->gcLastBytes;
if (bytes > 8192 && bytes > lastBytes + lastBytes / 2)
if ((bytes > 8192 && bytes > lastBytes + lastBytes / 2)
#ifdef NES40
/*
This is the other side of the fix in jsgc.c, allocGCThing where we stopped
doing a gc when the allocation fails. It turned out that the server branch-
callback wasn't providing for enough gc to prevent certain string concatenations
from exhausting the heap - with large strings the number of JSObjects remains
small but the amount of malloc'd space can be huge. We re-instate a test of the
malloc'd space here to help trigger a gc. (The server changed the frequency of
issuing calls to MaybeGC as well).
*/
|| (rt->gcMallocBytes > rt->gcMaxBytes)
#endif /* NES40 */
)
JS_GC(cx);
}

View File

@ -351,6 +351,9 @@ JS_DestroyContext(JSContext *cx);
extern JS_PUBLIC_API(void)
JS_DestroyContextNoGC(JSContext *cx);
extern JS_PUBLIC_API(void)
JS_DestroyContextMaybeGC(JSContext *cx);
JS_EXTERN_API(void*)
JS_GetContextPrivate(JSContext *cx);

View File

@ -74,7 +74,7 @@ js_NewContext(JSRuntime *rt, size_t stacksize)
#if JS_HAS_REGEXPS
if (!js_InitRegExpStatics(cx, &cx->regExpStatics)) {
js_DestroyContext(cx, JS_TRUE);
js_DestroyContext(cx, JS_FORCE_GC);
return NULL;
}
#endif
@ -86,7 +86,7 @@ js_NewContext(JSRuntime *rt, size_t stacksize)
}
void
js_DestroyContext(JSContext *cx, JSBool force_gc)
js_DestroyContext(JSContext *cx, JS_GC_Flag gcFlag)
{
JSRuntime *rt;
JSBool rtempty;
@ -128,11 +128,14 @@ js_DestroyContext(JSContext *cx, JSBool force_gc)
js_FreeRegExpStatics(cx, &cx->regExpStatics);
#endif
if (force_gc)
if (gcFlag == JS_FORCE_GC)
js_ForceGC(cx);
else
if (gcFlag == JS_MAYBE_GC)
JS_MaybeGC(cx);
if (rtempty) {
if (!force_gc)
if (gcFlag == JS_NO_GC)
js_ForceGC(cx);
/* Free atom state now that we've run the GC. */

View File

@ -35,6 +35,8 @@
JS_BEGIN_EXTERN_C
typedef enum JS_GC_Flag { JS_FORCE_GC, JS_NO_GC, JS_MAYBE_GC } JS_GC_Flag;
struct JSRuntime {
/* Garbage collector state, used by jsgc.c. */
JSArenaPool gcArenaPool;
@ -199,7 +201,7 @@ extern JSContext *
js_NewContext(JSRuntime *rt, size_t stacksize);
extern void
js_DestroyContext(JSContext *cx, JSBool force_gc);
js_DestroyContext(JSContext *cx, JS_GC_Flag gcFlag);
extern JSContext *
js_ContextIterator(JSRuntime *rt, JSContext **iterp);

View File

@ -175,6 +175,18 @@ js_AllocGCThing(JSContext *cx, uintN flags)
JSBool tried_gc = JS_FALSE;
#endif
#ifdef NES40
/* Fix for GC bug - previous allocation of a new atom has
not yet found a home, so a subsequent call to GC here will
flush that atom. This 'hack' prevents that from happening
by requiring that the heap grow rather than running a GC.
The concern is that enough GC's will not occur then, since
we're counting on back-branches and force_GC's from the
server.
*/
tried_gc = JS_TRUE;
#endif /* NES40 */
rt = cx->runtime;
JS_LOCK_GC(rt);
METER(rt->gcStats.alloc++);

View File

@ -203,7 +203,7 @@ PrintChar(jschar c)
#endif
}
static gOffset = 0;
static int gOffset = 0;
static JSBool
DumpRegExp(JSContext *cx, RENode *ren)
@ -778,7 +778,7 @@ static RENode *
ParseAtom(CompilerState *state)
{
const jschar *cp, *ocp;
uintN num, tmp, len;
uintN tmp, num, len;
RENode *ren, *ren2;
jschar c;
REOp op;
@ -854,26 +854,18 @@ ParseAtom(CompilerState *state)
break;
case '[':
/* A char class must have at least one char in it. */
if ((c = *++cp) == 0)
goto bad_cclass;
ren = NewRENode(state, REOP_CCLASS, (void *)cp);
++cp;
ren = NewRENode(state, REOP_CCLASS, (void *)cp);
if (!ren)
return NULL;
/* A negated class must have at least one char in it after the ^. */
if (c == '^' && *++cp == 0)
goto bad_cclass;
while ((c = *++cp) != ']') {
if (c == 0) {
bad_cclass:
while ((c = *++cp) != ']') {
if (cp == state->cpend) {
JS_ReportErrorNumber(state->context, js_GetErrorMessage, NULL,
JSMSG_UNTERM_CLASS, ocp);
return NULL;
}
if (c == '\\' && cp[1] != 0)
if (c == '\\' && (cp+1 != state->cpend))
cp++;
}
ren->u.kid2 = (void *)cp++;
@ -886,12 +878,12 @@ ParseAtom(CompilerState *state)
case '\\':
c = *++cp;
switch (c) {
case 0:
if (cp == state->cpend) {
JS_ReportErrorNumber(state->context, js_GetErrorMessage, NULL,
JSMSG_TRAILING_SLASH);
return NULL;
}
switch (c) {
case 'f':
case 'n':
case 'r':
@ -919,21 +911,7 @@ ParseAtom(CompilerState *state)
case 'S':
ren = NewRENode(state, REOP_NONSPACE, NULL);
break;
case '0':
do_octal:
num = 0;
while ('0' <= (c = *++cp) && c <= '7') {
tmp = 8 * num + (uintN)JS7_UNDEC(c);
if (tmp > 0377)
break;
num = tmp;
}
cp--;
ren = NewRENode(state, REOP_FLAT1, NULL);
c = (jschar)num;
break;
case '1':
case '2':
case '3':
@ -943,31 +921,114 @@ ParseAtom(CompilerState *state)
case '7':
case '8':
case '9':
num = (uintN)JS7_UNDEC(c);
tmp = 1;
for (c = *++cp; JS7_ISDEC(c); c = *++cp, tmp++)
num = 10 * num - (uintN)JS7_UNDEC(c);
/* n in [8-9] and > count of parenetheses, then revert to
'8' or '9', ignoring the '\' */
if (((num == 8) || (num == 9)) && (num > state->parenCount)) {
ocp = --cp; /* skip beyond the '\' */
goto do_flat;
}
/* more than 1 digit, or a number greater than
the count of parentheses => it's an octal */
if ((tmp > 1) || (num > state->parenCount)) {
cp = ocp;
goto do_octal;
}
cp--;
ren = NewRENode(state, REOP_BACKREF, NULL);
if (!ren)
return NULL;
ren->u.num = num - 1; /* \1 is numbered 0, etc. */
/*
Yuk. Keeping the old style \n interpretation for 1.2
compatibility.
*/
if (state->context->version <= JSVERSION_1_4) {
switch (c) {
case '0':
do_octal:
num = 0;
while ('0' <= (c = *++cp) && c <= '7') {
tmp = 8 * num + (uintN)JS7_UNDEC(c);
if (tmp > 0377)
break;
num = tmp;
}
cp--;
ren = NewRENode(state, REOP_FLAT1, NULL);
c = (jschar)num;
break;
/* Avoid common chr- and flags-setting code after switch. */
ren->flags = RENODE_NONEMPTY;
goto bump_cp;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
num = (uintN)JS7_UNDEC(c);
tmp = 1;
for (c = *++cp; JS7_ISDEC(c); c = *++cp, tmp++)
num = 10 * num + (uintN)JS7_UNDEC(c);
/* n in [8-9] and > count of parenetheses, then revert to
'8' or '9', ignoring the '\' */
if (((num == 8) || (num == 9)) && (num > state->parenCount)) {
ocp = --cp; /* skip beyond the '\' */
goto do_flat;
}
/* more than 1 digit, or a number greater than
the count of parentheses => it's an octal */
if ((tmp > 1) || (num > state->parenCount)) {
cp = ocp;
goto do_octal;
}
cp--;
ren = NewRENode(state, REOP_BACKREF, NULL);
if (!ren)
return NULL;
ren->u.num = num - 1; /* \1 is numbered 0, etc. */
/* Avoid common chr- and flags-setting code after switch. */
ren->flags = RENODE_NONEMPTY;
goto bump_cp;
}
}
else {
if (cp < (state->cpend - 1) && cp[1] >= '0' && cp[1] <= '9') {
if (c >= '0' && c <= '3') {
if (c <= '7') { /* ZeroToThree OctalDigit */
if (cp < (state->cpend - 2)
&& cp[2] >= '0' && cp[2] <= '9') {
ren = NewRENode(state, REOP_FLAT1, NULL);
c = 64 * (uintN)JS7_UNDEC(c)
+ 8 * (uintN)JS7_UNDEC(*++cp)
+ (uintN)JS7_UNDEC(*++cp);
}
else /*ZeroToThree OctalDigit lookahead != OctalDigit */
goto twodigitescape;
}
else /* ZeroToThree EightOrNine */
goto twodigitescape;
}
else { /* FourToNine DecimalDigit */
twodigitescape:
num = 10 * (uintN)JS7_UNDEC(c) + (uintN)JS7_UNDEC(cp[1]);
if (num >= 10 && num <= state->parenCount) {
cp++;
goto backref;
}
if (c > '7' || cp[1] > '7') {
JS_ReportErrorNumber(state->context, js_GetErrorMessage, NULL,
JSMSG_INVALID_BACKREF);
return NULL;
}
ren = NewRENode(state, REOP_FLAT1, NULL);
c = 8 * (uintN)JS7_UNDEC(c) + (uintN)JS7_UNDEC(*++cp);
}
}
else { /* DecimalDigit lookahead != DecimalDigit */
if (c == '0') {
ren = NewRENode(state, REOP_FLAT1, NULL);
c = 0;
}
else {
num = (uintN)JS7_UNDEC(c);
backref:
ren = NewRENode(state, REOP_BACKREF, NULL);
if (!ren)
return NULL;
ren->u.num = num - 1; /* \1 is numbered 0, etc. */
/* Avoid common chr- and flags-setting code after switch. */
ren->flags = RENODE_NONEMPTY;
goto bump_cp;
}
}
}
break;
case 'x':
ocp = cp;
@ -979,9 +1040,13 @@ ParseAtom(CompilerState *state)
num <<= 4;
num += JS7_UNHEX(c);
} else {
cp--; /* back up so cp points to last hex char */
if (state->context->version <= JSVERSION_1_4)
cp--; /* back up so cp points to last hex char */
else
goto nothex; /* ECMA 2 insists on pairs */
}
} else {
nothex:
cp = ocp; /* \xZZ is xZZ (Perl does \0ZZ!) */
num = 'x';
}
@ -1033,10 +1098,10 @@ ParseAtom(CompilerState *state)
default:
do_flat:
while ((c = *++cp) != 0 && !js_strchr(metachars, c))
while ((c = *++cp) && (cp != state->cpend) && !js_strchr(metachars, c))
;
len = (uintN)(cp - ocp);
if (c != 0 && len > 1 && js_strchr(closurechars, c)) {
if ((cp != state->cpend) && len > 1 && js_strchr(closurechars, c)) {
cp--;
len--;
}
@ -1099,7 +1164,6 @@ js_NewRegExp(JSContext *cx, JSString *str, uintN flags)
if (!re)
goto out;
re->source = str;
re->length = state.progLength;
re->lastIndex = 0;
re->parenCount = state.parenCount;
re->flags = flags;
@ -1517,307 +1581,296 @@ static JSBool buildBitmap(MatchState *state, RENode *ren)
static const jschar *matchRENodes(MatchState *state, RENode *ren, RENode *stop,
const jschar *cp)
{
const jschar *cp2, *kidMatch, *cpend = state->cpend;
const jschar *cp2, *kidMatch, *lastKid, *source, *cpend = state->cpend;
jschar c;
JSSubString *parsub;
uintN i, b, bit;
uintN num;
uintN i, b, bit, num, length;
while ((ren != stop) && (ren != NULL))
{
switch (ren->op) {
case REOP_EMPTY:
break;
case REOP_ALT: {
if (ren->next->op != REOP_ALT) {
ren = (RENode *)ren->kid;
continue;
}
else {
const jschar *kidMatch = matchRENodes(state, (RENode *)ren->kid,
stop, cp);
if (kidMatch != NULL) return kidMatch;
}
}
break;
case REOP_QUANT: {
const jschar *lastKid = NULL;
for (num = 0; num < ren->u.range.min; num++) {
kidMatch = matchRENodes(state, (RENode *)ren->kid,
ren->next, cp);
if (kidMatch == NULL)
return NULL;
else {
lastKid = cp;
cp = kidMatch;
}
}
if ((ren->flags & RENODE_MINIMAL) == 0)
cp = matchGreedyKid(state, ren, num,
ren->u.range.max, cp, lastKid);
else
cp = matchNonGreedyKid(state, ren, num,
ren->u.range.max, cp);
if (cp == NULL) return NULL;
break;
}
case REOP_PLUS:
kidMatch = matchRENodes(state, (RENode *)ren->kid,
ren->next, cp);
if (kidMatch == NULL)
return NULL;
if ((ren->flags & RENODE_MINIMAL) == 0) {
cp = matchGreedyKid(state, ren, 1, 0, cp, NULL);
if (cp == NULL) return NULL;
}
else {
cp = matchNonGreedyKid(state, ren, 1, 0, kidMatch);
if (cp == NULL) return NULL;
}
break;
case REOP_STAR:
if ((ren->flags & RENODE_MINIMAL) == 0) {
cp = matchGreedyKid(state, ren, 0, 0, cp, NULL);
if (cp == NULL) return NULL;
}
else {
cp = matchNonGreedyKid(state, ren, 0, 0, cp);
if (cp == NULL) return NULL;
}
break;
case REOP_OPT: {
num = state->parenCount;
if (ren->flags & RENODE_MINIMAL) {
const jschar *restMatch = matchRENodes(state, ren->next,
stop, cp);
if (restMatch != NULL) return restMatch;
}
kidMatch = matchRENodes(state, (RENode *)ren->kid,
ren->next, cp);
if (kidMatch == NULL)
break;
else {
const jschar *restMatch = matchRENodes(state, ren->next,
stop, kidMatch);
if (restMatch == NULL) {
/* need to undo the result of running the kid */
state->parenCount = num;
break;
}
else
return restMatch;
}
}
case REOP_LPARENNON:
ren = (RENode *)ren->kid;
continue;
case REOP_RPARENNON:
break;
case REOP_LPAREN: {
num = ren->u.num;
ren = (RENode *)ren->kid;
parsub = &state->parens[num];
parsub->chars = cp;
parsub->length = 0;
if (num >= state->parenCount)
state->parenCount = num + 1;
continue;
}
case REOP_RPAREN: {
num = ren->u.num;
parsub = &state->parens[num];
parsub->length = cp - parsub->chars;
break;
}
case REOP_ASSERT: {
kidMatch = matchRENodes(state, (RENode *)ren->kid,
ren->next, cp);
if (kidMatch == NULL) return NULL;
break;
}
case REOP_ASSERT_NOT: {
kidMatch = matchRENodes(state, (RENode *)ren->kid,
ren->next, cp);
if (kidMatch != NULL) return NULL;
break;
}
case REOP_BACKREF: {
num = ren->u.num;
parsub = &state->parens[num];
if ((cp + parsub->length) > cpend)
return NULL;
else {
cp2 = parsub->chars;
for (i = 0; i < parsub->length; i++) {
if (!matchChar(state->flags, *cp++, *cp2++))
return NULL;
}
}
}
break;
case REOP_CCLASS:
if (cp != cpend) {
if (ren->u.ucclass.bitmap == NULL) {
if (!buildBitmap(state, ren))
return NULL;
}
c = *cp;
b = (c >> 3);
if (b >= ren->u.ucclass.bmsize) {
cp2 = ren->kid;
if (*cp2 == '^')
cp++;
else
return NULL;
} else {
bit = c & 7;
bit = 1 << bit;
if ((ren->u.ucclass.bitmap[b] & bit) != 0)
cp++;
else
return NULL;
}
}
else
return NULL;
break;
case REOP_DOT:
if ((cp != cpend) && (*cp != '\n'))
cp++;
else
return NULL;
break;
case REOP_DOTSTARMIN: {
for (cp2 = cp; cp2 < cpend; cp2++) {
const jschar *cp3 = matchRENodes(state, ren->next,
stop, cp2);
if (cp3 != NULL) return cp3;
if (*cp2 == '\n')
return NULL;
}
return NULL;
}
case REOP_DOTSTAR: {
for (cp2 = cp; cp2 < cpend; cp2++)
if (*cp2 == '\n')
break;
while (cp2 >= cp) {
const jschar *cp3 = matchRENodes(state, ren->next,
stop, cp2);
if (cp3 != NULL)
return cp3;
cp2--;
}
return NULL;
}
case REOP_WBDRY:
if (((cp == state->cpbegin) || !JS_ISWORD(cp[-1]))
^ ((cp >= cpend) || !JS_ISWORD(*cp)))
; /* leave cp */
else
return NULL;
break;
case REOP_WNONBDRY:
if (((cp == state->cpbegin) || !JS_ISWORD(cp[-1]))
^ ((cp < cpend) && JS_ISWORD(*cp)))
; /* leave cp */
else
return NULL;
break;
case REOP_EOLONLY:
case REOP_EOL: {
if (cp == cpend)
; /* leave cp */
else {
if (state->context->regExpStatics.multiline
|| ((state->flags & JSREG_MULTILINE) != 0))
if (*cp == '\n')
;/* leave cp */
else
return NULL;
else
return NULL;
}
}
break;
case REOP_BOL: {
if (cp != state->cpbegin) {
if ((cp < cpend)
&& (state->context->regExpStatics.multiline
|| ((state->flags & JSREG_MULTILINE) != 0))) {
if (cp[-1] == '\n') {
break;
}
}
return NULL;
}
/* leave cp */
}
break;
case REOP_DIGIT:
if ((cp != cpend) && JS_ISDIGIT(*cp))
cp++;
else
return NULL;
break;
case REOP_NONDIGIT:
if ((cp != cpend) && !JS_ISDIGIT(*cp))
cp++;
else
return NULL;
break;
case REOP_ALNUM:
if ((cp != cpend) && JS_ISWORD(*cp))
cp++;
else
return NULL;
break;
case REOP_NONALNUM:
if ((cp != cpend) && !JS_ISWORD(*cp))
cp++;
else
return NULL;
break;
case REOP_SPACE:
if ((cp != cpend) && JS_ISSPACE(*cp))
cp++;
else
return NULL;
break;
case REOP_NONSPACE:
if ((cp != cpend) && !JS_ISSPACE(*cp))
cp++;
else
return NULL;
break;
case REOP_FLAT1:
if ((cp != cpend)
&& matchChar(state->flags, ren->u.chr, *cp))
cp++;
else
return NULL;
break;
case REOP_FLAT: {
jschar *source = ren->kid;
uintN length = (jschar *)ren->u.kid2 - source;
if ((cp + length) > cpend)
return NULL;
else {
for (i = 0; i < length; i++) {
if (!matchChar(state->flags, *cp++, *source++))
return NULL;
}
}
}
break;
case REOP_JUMP:
break;
case REOP_END:
break;
default :
JS_ASSERT(JS_FALSE);
break;
switch (ren->op) {
case REOP_EMPTY:
break;
case REOP_ALT:
if (ren->next->op != REOP_ALT) {
ren = (RENode *)ren->kid;
continue;
}
kidMatch = matchRENodes(state, (RENode *)ren->kid, stop, cp);
if (kidMatch != NULL) return kidMatch;
break;
case REOP_QUANT:
lastKid = NULL;
for (num = 0; num < ren->u.range.min; num++) {
kidMatch = matchRENodes(state, (RENode *)ren->kid,
ren->next, cp);
if (kidMatch == NULL)
return NULL;
lastKid = cp;
cp = kidMatch;
}
if (num == ren->u.range.max) break;
if ((ren->flags & RENODE_MINIMAL) == 0)
cp = matchGreedyKid(state, ren, num,
ren->u.range.max, cp, lastKid);
else
cp = matchNonGreedyKid(state, ren, num,
ren->u.range.max, cp);
if (cp == NULL) return NULL;
break;
case REOP_PLUS:
kidMatch = matchRENodes(state, (RENode *)ren->kid,
ren->next, cp);
if (kidMatch == NULL)
return NULL;
if ((ren->flags & RENODE_MINIMAL) == 0) {
cp = matchGreedyKid(state, ren, 1, 0, cp, NULL);
if (cp == NULL) return NULL;
}
else {
cp = matchNonGreedyKid(state, ren, 1, 0, kidMatch);
if (cp == NULL) return NULL;
}
break;
case REOP_STAR:
if ((ren->flags & RENODE_MINIMAL) == 0) {
cp = matchGreedyKid(state, ren, 0, 0, cp, NULL);
if (cp == NULL) return NULL;
}
else {
cp = matchNonGreedyKid(state, ren, 0, 0, cp);
if (cp == NULL) return NULL;
}
break;
case REOP_OPT:
num = state->parenCount;
if (ren->flags & RENODE_MINIMAL) {
const jschar *restMatch = matchRENodes(state, ren->next,
stop, cp);
if (restMatch != NULL) return restMatch;
}
kidMatch = matchRENodes(state, (RENode *)ren->kid,
ren->next, cp);
if (kidMatch == NULL) {
state->parenCount = num;
break;
}
else {
const jschar *restMatch = matchRENodes(state, ren->next,
stop, kidMatch);
if (restMatch == NULL) {
/* need to undo the result of running the kid */
state->parenCount = num;
break;
}
else
return restMatch;
}
case REOP_LPARENNON:
ren = (RENode *)ren->kid;
continue;
case REOP_RPARENNON:
break;
case REOP_LPAREN:
num = ren->u.num;
ren = (RENode *)ren->kid;
parsub = &state->parens[num];
parsub->chars = cp;
parsub->length = 0;
if (num >= state->parenCount)
state->parenCount = num + 1;
continue;
case REOP_RPAREN:
num = ren->u.num;
parsub = &state->parens[num];
parsub->length = cp - parsub->chars;
break;
case REOP_ASSERT:
kidMatch = matchRENodes(state, (RENode *)ren->kid,
ren->next, cp);
if (kidMatch == NULL) return NULL;
break;
case REOP_ASSERT_NOT:
kidMatch = matchRENodes(state, (RENode *)ren->kid,
ren->next, cp);
if (kidMatch != NULL) return NULL;
break;
case REOP_BACKREF:
num = ren->u.num;
if (num >= state->parenCount) {
JS_ReportErrorNumber(state->context, js_GetErrorMessage, NULL,
JSMSG_BAD_BACKREF);
return NULL;
}
parsub = &state->parens[num];
if ((cp + parsub->length) > cpend)
return NULL;
else {
cp2 = parsub->chars;
for (i = 0; i < parsub->length; i++) {
if (!matchChar(state->flags, *cp++, *cp2++))
return NULL;
}
}
break;
case REOP_CCLASS:
if (cp != cpend) {
if (ren->u.ucclass.bitmap == NULL) {
if (!buildBitmap(state, ren))
return NULL;
}
c = *cp;
b = (c >> 3);
if (b >= ren->u.ucclass.bmsize) {
cp2 = ren->kid;
if (*cp2 == '^')
cp++;
else
return NULL;
}
else {
bit = c & 7;
bit = 1 << bit;
if ((ren->u.ucclass.bitmap[b] & bit) != 0)
cp++;
else
return NULL;
}
}
else
return NULL;
break;
case REOP_DOT:
if ((cp != cpend) && (*cp != '\n'))
cp++;
else
return NULL;
break;
case REOP_DOTSTARMIN:
for (cp2 = cp; cp2 < cpend; cp2++) {
const jschar *cp3 = matchRENodes(state, ren->next,
stop, cp2);
if (cp3 != NULL) return cp3;
if (*cp2 == '\n')
return NULL;
}
return NULL;
case REOP_DOTSTAR:
for (cp2 = cp; cp2 < cpend; cp2++)
if (*cp2 == '\n')
break;
while (cp2 >= cp) {
const jschar *cp3 = matchRENodes(state, ren->next,
stop, cp2);
if (cp3 != NULL)
return cp3;
cp2--;
}
return NULL;
case REOP_WBDRY:
if (((cp == state->cpbegin) || !JS_ISWORD(cp[-1]))
^ ((cp >= cpend) || !JS_ISWORD(*cp)))
; /* leave cp */
else
return NULL;
break;
case REOP_WNONBDRY:
if (((cp == state->cpbegin) || !JS_ISWORD(cp[-1]))
^ ((cp < cpend) && JS_ISWORD(*cp)))
; /* leave cp */
else
return NULL;
break;
case REOP_EOLONLY:
case REOP_EOL:
if (cp == cpend)
; /* leave cp */
else {
if (state->context->regExpStatics.multiline
|| ((state->flags & JSREG_MULTILINE) != 0))
if (*cp == '\n')
;/* leave cp */
else
return NULL;
else
return NULL;
}
break;
case REOP_BOL:
if (cp != state->cpbegin) {
if ((cp < cpend)
&& (state->context->regExpStatics.multiline
|| ((state->flags & JSREG_MULTILINE) != 0))) {
if (cp[-1] == '\n') {
break;
}
}
return NULL;
}
/* leave cp */
break;
case REOP_DIGIT:
if ((cp != cpend) && JS_ISDIGIT(*cp))
cp++;
else
return NULL;
break;
case REOP_NONDIGIT:
if ((cp != cpend) && !JS_ISDIGIT(*cp))
cp++;
else
return NULL;
break;
case REOP_ALNUM:
if ((cp != cpend) && JS_ISWORD(*cp))
cp++;
else
return NULL;
break;
case REOP_NONALNUM:
if ((cp != cpend) && !JS_ISWORD(*cp))
cp++;
else
return NULL;
break;
case REOP_SPACE:
if ((cp != cpend) && JS_ISSPACE(*cp))
cp++;
else
return NULL;
break;
case REOP_NONSPACE:
if ((cp != cpend) && !JS_ISSPACE(*cp))
cp++;
else
return NULL;
break;
case REOP_FLAT1:
if ((cp != cpend)
&& matchChar(state->flags, ren->u.chr, *cp))
cp++;
else
return NULL;
break;
case REOP_FLAT:
source = ren->kid;
length = (const jschar *)ren->u.kid2 - source;
if ((cp + length) > cpend)
return NULL;
else {
for (i = 0; i < length; i++) {
if (!matchChar(state->flags, *cp++, *source++))
return NULL;
}
}
break;
case REOP_JUMP:
break;
case REOP_END:
break;
default :
JS_ASSERT(JS_FALSE);
break;
}
ren = ren->next;
}
@ -2092,7 +2145,8 @@ regexp_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
*vp = BOOLEAN_TO_JSVAL((re->flags & JSREG_FOLD) != 0);
break;
case REGEXP_LAST_INDEX:
*vp = INT_TO_JSVAL((jsint)re->lastIndex);
if (!js_NewNumberValue(cx, (jsdouble)re->lastIndex, vp))
return JS_FALSE;
break;
case REGEXP_MULTILINE:
*vp = BOOLEAN_TO_JSVAL((re->flags & JSREG_MULTILINE) != 0);
@ -2118,7 +2172,7 @@ regexp_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
if (re && slot == REGEXP_LAST_INDEX) {
if (!js_ValueToNumber(cx, *vp, &d))
return JS_FALSE;
re->lastIndex = (size_t)d;
re->lastIndex = (uintN)d;
}
JS_UNLOCK_OBJ(cx, obj);
return JS_TRUE;
@ -2483,11 +2537,11 @@ regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
argv[0] = STRING_TO_JSVAL(str);
}
if (re->flags & JSREG_GLOB) {
JS_LOCK_OBJ(cx, obj);
locked = JS_TRUE;
i = re->lastIndex;
JS_LOCK_OBJ(cx, obj);
locked = JS_TRUE;
i = re->lastIndex;
} else {
i = 0;
i = 0;
}
ok = js_ExecuteRegExp(cx, re, str, &i, test, rval);
if (re->flags & JSREG_GLOB)

View File

@ -51,8 +51,7 @@ struct JSRegExpStatics {
struct JSRegExp {
JSString *source; /* locked source string, sans // */
size_t length; /* program length in bytes */
size_t lastIndex; /* index after last match, for //g iterator */
uintN lastIndex; /* index after last match, for //g iterator */
uintN parenCount; /* number of parenthesized submatches */
uint8 flags; /* flags, see jsapi.h */
struct RENode *ren; /* regular expression tree root */