mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-11 04:15:43 +00:00
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:
parent
549e69a421
commit
c79698a838
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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. */
|
||||
|
@ -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);
|
||||
|
@ -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++);
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user