Bug 368152: jsregexp preprocessor-enabled "debugging" mode
authorcrowder@fiverocks.com
Thu, 22 Mar 2007 20:35:42 -0700
changeset 22 b1a52f0be0de986bee8928d18c7d223d82138155
parent 21 80a2d417f424407070f5057dd00eb9427077a451
child 23 3cc95ffbc74f780bd1305b29273f7222949cd25b
push idunknown
push userunknown
push dateunknown
bugs368152
milestone1.9a3pre
Bug 368152: jsregexp preprocessor-enabled "debugging" mode
js/src/jsregexp.c
js/src/jsreops.tbl
--- a/js/src/jsregexp.c
+++ b/js/src/jsregexp.c
@@ -39,16 +39,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 /*
  * JS regular expressions, after Perl.
  */
 #include "jsstddef.h"
 #include <stdlib.h>
 #include <string.h>
+#include <stdarg.h>
 #include "jstypes.h"
 #include "jsarena.h" /* Added by JSIFY */
 #include "jsutil.h" /* Added by JSIFY */
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsconfig.h"
@@ -58,75 +59,76 @@
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jsregexp.h"
 #include "jsscan.h"
 #include "jsstr.h"
 
-/* Note : contiguity of 'simple opcodes' is important for SimpleMatch() */
 typedef enum REOp {
-    REOP_EMPTY,         /* match rest of input against rest of r.e. */
-    REOP_BOL,           /* beginning of input (or line if multiline) */
-    REOP_EOL,           /* end of input (or line if multiline) */
-    REOP_WBDRY,         /* match "" at word boundary */
-    REOP_WNONBDRY,      /* match "" at word non-boundary */
-    REOP_DOT,           /* stands for any character */
-    REOP_DIGIT,         /* match a digit char: [0-9] */
-    REOP_NONDIGIT,      /* match a non-digit char: [^0-9] */
-    REOP_ALNUM,         /* match an alphanumeric char: [0-9a-z_A-Z] */
-    REOP_NONALNUM,      /* match a non-alphanumeric char: [^0-9a-z_A-Z] */
-    REOP_SPACE,         /* match a whitespace char */
-    REOP_NONSPACE,      /* match a non-whitespace char */
-    REOP_BACKREF,       /* back-reference (e.g., \1) to a parenthetical */
-    REOP_FLAT,          /* match a flat string */
-    REOP_FLAT1,         /* match a single char */
-    REOP_FLATi,         /* case-independent REOP_FLAT */
-    REOP_FLAT1i,        /* case-independent REOP_FLAT1 */
-    REOP_UCFLAT1,       /* single Unicode char */
-    REOP_UCFLAT1i,      /* case-independent REOP_UCFLAT1 */
-    REOP_UCFLAT,        /* flat Unicode string; len immediate counts chars */
-    REOP_UCFLATi,       /* case-independent REOP_UCFLAT */
-    REOP_CLASS,         /* character class with index */
-    REOP_NCLASS,        /* negated character class with index */
-
-    /* NCLASS is considered to be the last "simple" op-code */
-
-    REOP_ALT,           /* alternative subexpressions in kid and next */
-    REOP_QUANT,         /* quantified atom: atom{1,2} */
-    REOP_STAR,          /* zero or more occurrences of kid */
-    REOP_PLUS,          /* one or more occurrences of kid */
-    REOP_OPT,           /* optional subexpression in kid */
-    REOP_LPAREN,        /* left paren bytecode: kid is u.num'th sub-regexp */
-    REOP_RPAREN,        /* right paren bytecode */
-    REOP_JUMP,          /* for deoptimized closure loops */
-    REOP_DOTSTAR,       /* optimize .* to use a single opcode */
-    REOP_LPARENNON,     /* non-capturing version of REOP_LPAREN */
-    REOP_ASSERT,        /* zero width positive lookahead assertion */
-    REOP_ASSERT_NOT,    /* zero width negative lookahead assertion */
-    REOP_ASSERTTEST,    /* sentinel at end of assertion child */
-    REOP_ASSERTNOTTEST, /* sentinel at end of !assertion child */
-    REOP_MINIMALSTAR,   /* non-greedy version of * */
-    REOP_MINIMALPLUS,   /* non-greedy version of + */
-    REOP_MINIMALOPT,    /* non-greedy version of ? */
-    REOP_MINIMALQUANT,  /* non-greedy version of {} */
-    REOP_ENDCHILD,      /* sentinel at end of quantifier child */
-    REOP_REPEAT,        /* directs execution of greedy quantifier */
-    REOP_MINIMALREPEAT, /* directs execution of non-greedy quantifier */
-    REOP_ALTPREREQ,     /* prerequisite for ALT, either of two chars */
-    REOP_ALTPREREQ2,    /* prerequisite for ALT, a char or a class */
-    REOP_ENDALT,        /* end of final alternate */
-    REOP_CONCAT,        /* concatenation of terms (parse time only) */
-    REOP_END,           /* end of expression */
-    REOP_LIMIT          /* META: no operator >= to this */
+#define REOP_DEF(opcode, name) opcode,
+#include "jsreops.tbl"
+#undef REOP_DEF
 } REOp;
 
 #define REOP_IS_SIMPLE(op)  ((op) <= (unsigned)REOP_NCLASS)
 
+#ifdef DEBUG
+const char *reop_names[] = {
+#define REOP_DEF(opcode, name) name,
+#include "jsreops.tbl"
+#undef REOP_DEF
+    NULL
+};
+#endif
+
+#ifdef __GNUC__
+static int
+re_debug(const char *fmt, ...) __attribute__ ((format(printf, 1, 2)));
+#endif
+
+#ifdef REGEXP_DEBUG
+static int
+re_debug(const char *fmt, ...)
+{
+    va_list ap;
+    int retval;
+
+    va_start(ap, fmt);
+    retval = vprintf(fmt, ap);
+    va_end(ap);
+    return retval;
+}
+
+static void
+re_debug_chars(const jschar *chrs, size_t length)
+{
+    int i = 0;
+
+    printf(" \"");
+    while (*chrs && i++ < length) {
+        putchar((char)*chrs++);
+    }
+    printf("\"");
+}
+#else  /* !REGEXP_DEBUG */
+/* This should be optimized to a no-op by our tier-1 compilers. */
+static int
+re_debug(const char *fmt, ...)
+{
+    return 0;
+}
+
+static void
+re_debug_chars(const jschar *chrs, size_t length)
+{
+}
+#endif /* !REGEXP_DEBUG */
+
 struct RENode {
     REOp            op;         /* r.e. op bytecode */
     RENode          *next;      /* next in concatenation order */
     void            *kid;       /* first operand */
     union {
         void        *kid2;      /* second operand */
         jsint       num;        /* could be a number */
         size_t      parenIndex; /* or a parenthesis index */
@@ -2065,16 +2067,21 @@ PushBackTrackState(REGlobalData *gData, 
     size_t sz = sizeof(REBackTrackData) +
                 gData->stateStackTop * sizeof(REProgState) +
                 parenCount * sizeof(RECapture);
 
     ptrdiff_t btsize = gData->backTrackStackSize;
     ptrdiff_t btincr = ((char *)result + sz) -
                        ((char *)gData->backTrackStack + btsize);
 
+    re_debug("\tBT_Push[%d]: %d,%d",
+             ((char *)result - (char *)gData->backTrackStack) /
+              sizeof(REBackTrackData),
+             parenIndex, parenCount);
+
     JS_COUNT_OPERATION(gData->cx, JSOW_JUMP * (1 + parenCount));
     if (btincr > 0) {
         ptrdiff_t offset = (char *)result - (char *)gData->backTrackStack;
 
         JS_COUNT_OPERATION(gData->cx, JSOW_ALLOCATION);
         btincr = JS_ROUNDUP(btincr, btsize);
         JS_ARENA_GROW_CAST(gData->backTrackStack, REBackTrackData *,
                            &gData->pool, btsize, btincr);
@@ -2089,24 +2096,24 @@ PushBackTrackState(REGlobalData *gData, 
     gData->backTrackSP = result;
     result->sz = gData->cursz;
     gData->cursz = sz;
 
     result->backtrack_op = op;
     result->backtrack_pc = target;
     result->cp = cp;
     result->parenCount = parenCount;
+    result->parenIndex = parenIndex;
 
     result->saveStateStackTop = gData->stateStackTop;
     JS_ASSERT(gData->stateStackTop);
     memcpy(result + 1, gData->stateStack,
            sizeof(REProgState) * result->saveStateStackTop);
 
     if (parenCount != 0) {
-        result->parenIndex = parenIndex;
         memcpy((char *)(result + 1) +
                sizeof(REProgState) * result->saveStateStackTop,
                &x->parens[parenIndex],
                sizeof(RECapture) * parenCount);
         for (i = 0; i != parenCount; i++)
             x->parens[parenIndex + i].index = -1;
     }
 
@@ -2497,16 +2504,21 @@ SimpleMatch(REGlobalData *gData, REMatch
     size_t parenIndex;
     size_t offset, length, index;
     jsbytecode *pc = *startpc;  /* pc has already been incremented past op */
     jschar *source;
     const jschar *startcp = x->cp;
     jschar ch;
     RECharSet *charSet;
 
+#ifdef REGEXP_DEBUG
+    const char *opname = reop_names[op];
+    re_debug("\n%06d: %*s%s", pc - gData->regexp->program,
+             gData->stateStackTop * 2, "", opname);
+#endif
     switch (op) {
       case REOP_EMPTY:
         result = x;
         break;
       case REOP_BOL:
         if (x->cp != gData->cpbegin) {
             if (!gData->cx->regExpStatics.multiline &&
                 !(gData->regexp->flags & JSREG_MULTILINE)) {
@@ -2590,26 +2602,28 @@ SimpleMatch(REGlobalData *gData, REMatch
       case REOP_FLAT:
         pc = ReadCompactIndex(pc, &offset);
         JS_ASSERT(offset < JSSTRING_LENGTH(gData->regexp->source));
         pc = ReadCompactIndex(pc, &length);
         JS_ASSERT(1 <= length);
         JS_ASSERT(length <= JSSTRING_LENGTH(gData->regexp->source) - offset);
         if (length <= (size_t)(gData->cpend - x->cp)) {
             source = JSSTRING_CHARS(gData->regexp->source) + offset;
+            re_debug_chars(source, length);
             for (index = 0; index != length; index++) {
                 if (source[index] != x->cp[index])
                     return NULL;
             }
             x->cp += length;
             result = x;
         }
         break;
       case REOP_FLAT1:
         matchCh = *pc++;
+        re_debug(" '%c' == '%c'", (char)matchCh, (char)*x->cp);
         if (x->cp != gData->cpend && *x->cp == matchCh) {
             result = x;
             result->cp++;
         }
         break;
       case REOP_FLATi:
         pc = ReadCompactIndex(pc, &offset);
         JS_ASSERT(offset < JSSTRING_LENGTH(gData->regexp->source));
@@ -2623,16 +2637,17 @@ SimpleMatch(REGlobalData *gData, REMatch
         matchCh = *pc++;
         if (x->cp != gData->cpend && upcase(*x->cp) == upcase(matchCh)) {
             result = x;
             result->cp++;
         }
         break;
       case REOP_UCFLAT1:
         matchCh = GET_ARG(pc);
+        re_debug(" '%c' == '%c'", (char)matchCh, (char)*x->cp);
         pc += ARG_LEN;
         if (x->cp != gData->cpend && *x->cp == matchCh) {
             result = x;
             result->cp++;
         }
         break;
       case REOP_UCFLAT1i:
         matchCh = GET_ARG(pc);
@@ -2677,16 +2692,17 @@ SimpleMatch(REGlobalData *gData, REMatch
 
       default:
         JS_ASSERT(JS_FALSE);
     }
     if (result) {
         if (!updatecp)
             x->cp = startcp;
         *startpc = pc;
+        re_debug(" * ");
         return result;
     }
     x->cp = startcp;
     return NULL;
 }
 
 static REMatchState *
 ExecuteREBytecode(REGlobalData *gData, REMatchState *x)
@@ -2724,44 +2740,47 @@ ExecuteREBytecode(REGlobalData *gData, R
                 op = (REOp) *pc++;
                 JS_ASSERT(op < REOP_LIMIT);
                 break;
             }
             gData->skipped++;
             x->cp++;
         }
         if (!anchor)
-            return NULL;
+            goto bad;
     }
 
     for (;;) {
+#ifdef REGEXP_DEBUG
+        const char *opname = reop_names[op];
+        re_debug("\n%06d: %*s%s", pc - gData->regexp->program,
+                 gData->stateStackTop * 2, "", opname);
+#endif
         if (REOP_IS_SIMPLE(op)) {
             result = SimpleMatch(gData, x, op, &pc, JS_TRUE);
         } else {
             curState = &gData->stateStack[gData->stateStackTop];
             switch (op) {
               case REOP_END:
-                if (x)
-                    return x;
-                break;
+                goto good;
               case REOP_ALTPREREQ2:
                 nextpc = pc + GET_OFFSET(pc);   /* start of next op */
                 pc += ARG_LEN;
                 matchCh2 = GET_ARG(pc);
                 pc += ARG_LEN;
                 k = GET_ARG(pc);
                 pc += ARG_LEN;
 
                 if (x->cp != gData->cpend) {
                     if (*x->cp == matchCh2)
                         goto doAlt;
 
                     charSet = &gData->regexp->classList[k];
                     if (!charSet->converted && !ProcessCharSet(gData, charSet))
-                        return NULL;
+                        goto bad;
                     matchCh1 = *x->cp;
                     k = matchCh1 >> 3;
                     if ((charSet->length == 0 ||
                          matchCh1 > charSet->length ||
                          !(charSet->u.bits[k] & (1 << (matchCh1 & 0x7)))) ^
                         charSet->sense) {
                         goto doAlt;
                     }
@@ -2797,17 +2816,17 @@ ExecuteREBytecode(REGlobalData *gData, R
                         pc = nextpc;
                         continue;
                     }
                     result = x;
                     op = (REOp) *pc++;
                 }
                 nextop = (REOp) *nextpc++;
                 if (!PushBackTrackState(gData, nextop, nextpc, x, startcp, 0, 0))
-                    return NULL;
+                    goto bad;
                 continue;
 
               /*
                * Occurs at (successful) end of REOP_ALT,
                */
               case REOP_JUMP:
                 /*
                  * If we have not gotten a result here, it is because of an
@@ -2833,16 +2852,17 @@ ExecuteREBytecode(REGlobalData *gData, R
                     result = x;
 
                 --gData->stateStackTop;
                 op = (REOp) *pc++;
                 continue;
 
               case REOP_LPAREN:
                 pc = ReadCompactIndex(pc, &parenIndex);
+                re_debug("[ %d ]", parenIndex);
                 JS_ASSERT(parenIndex < gData->regexp->parenCount);
                 if (parenIndex + 1 > parenSoFar)
                     parenSoFar = parenIndex + 1;
                 x->parens[parenIndex].index = x->cp - gData->cpbegin;
                 x->parens[parenIndex].length = 0;
                 op = (REOp) *pc++;
                 continue;
 
@@ -2867,17 +2887,17 @@ ExecuteREBytecode(REGlobalData *gData, R
                 curState->u.assertion.top =
                     (char *)gData->backTrackSP - (char *)gData->backTrackStack;
                 curState->u.assertion.sz = gData->cursz;
                 curState->index = x->cp - gData->cpbegin;
                 curState->parenSoFar = parenSoFar;
                 PUSH_STATE_STACK(gData);
                 if (!PushBackTrackState(gData, REOP_ASSERTTEST,
                                         nextpc, x, x->cp, 0, 0)) {
-                    return NULL;
+                    goto bad;
                 }
                 continue;
 
               case REOP_ASSERT_NOT:
                 nextpc = pc + GET_OFFSET(pc);
                 pc += ARG_LEN;
                 op = (REOp) *pc++;
                 testpc = pc;
@@ -2891,17 +2911,17 @@ ExecuteREBytecode(REGlobalData *gData, R
                     = (char *)gData->backTrackSP -
                       (char *)gData->backTrackStack;
                 curState->u.assertion.sz = gData->cursz;
                 curState->index = x->cp - gData->cpbegin;
                 curState->parenSoFar = parenSoFar;
                 PUSH_STATE_STACK(gData);
                 if (!PushBackTrackState(gData, REOP_ASSERTNOTTEST,
                                         nextpc, x, x->cp, 0, 0)) {
-                    return NULL;
+                    goto bad;
                 }
                 continue;
 
               case REOP_ASSERTTEST:
                 --gData->stateStackTop;
                 --curState;
                 x->cp = gData->cpbegin + curState->index;
                 gData->backTrackSP =
@@ -2968,17 +2988,17 @@ ExecuteREBytecode(REGlobalData *gData, R
                 curState->index = startcp - gData->cpbegin;
                 curState->continue_op = REOP_REPEAT;
                 curState->continue_pc = pc;
                 curState->parenSoFar = parenSoFar;
                 PUSH_STATE_STACK(gData);
                 if (curState->u.quantifier.min == 0 &&
                     !PushBackTrackState(gData, REOP_REPEAT, pc, x, startcp,
                                         0, 0)) {
-                    return NULL;
+                    goto bad;
                 }
                 pc = nextpc;
                 continue;
 
               case REOP_ENDCHILD: /* marks the end of a quantifier child */
                 pc = curState[-1].continue_pc;
                 op = curState[-1].continue_op;
                 continue;
@@ -3021,17 +3041,17 @@ ExecuteREBytecode(REGlobalData *gData, R
                     curState->index = startcp - gData->cpbegin;
                     PUSH_STATE_STACK(gData);
                     if (curState->u.quantifier.min == 0 &&
                         !PushBackTrackState(gData, REOP_REPEAT,
                                             pc, x, startcp,
                                             curState->parenSoFar,
                                             parenSoFar -
                                             curState->parenSoFar)) {
-                        return NULL;
+                        goto bad;
                     }
                 } while (*nextpc == REOP_ENDCHILD);
                 pc = nextpc;
                 op = (REOp) *pc++;
                 parenSoFar = curState->parenSoFar;
                 continue;
 
               repeatDone:
@@ -3067,77 +3087,78 @@ ExecuteREBytecode(REGlobalData *gData, R
                     curState->continue_op = REOP_MINIMALREPEAT;
                     curState->continue_pc = pc;
                     /* step over <next> */
                     pc += OFFSET_LEN;
                     op = (REOp) *pc++;
                 } else {
                     if (!PushBackTrackState(gData, REOP_MINIMALREPEAT,
                                             pc, x, x->cp, 0, 0)) {
-                        return NULL;
+                        goto bad;
                     }
                     --gData->stateStackTop;
                     pc = pc + GET_OFFSET(pc);
                     op = (REOp) *pc++;
                 }
                 continue;
 
               case REOP_MINIMALREPEAT:
                 --gData->stateStackTop;
                 --curState;
 
+                re_debug("{%d,%d}", curState->u.quantifier.min,
+                         curState->u.quantifier.max);
+#define PREPARE_REPEAT()                                                      \
+    JS_BEGIN_MACRO                                                            \
+        curState->index = x->cp - gData->cpbegin;                             \
+        curState->continue_op = REOP_MINIMALREPEAT;                           \
+        curState->continue_pc = pc;                                           \
+        pc += ARG_LEN;                                                        \
+        for (k = curState->parenSoFar; k < parenSoFar; k++)                   \
+            x->parens[k].index = -1;                                          \
+        PUSH_STATE_STACK(gData);                                              \
+        op = (REOp) *pc++;                                                    \
+        JS_ASSERT(op < REOP_LIMIT);                                           \
+    JS_END_MACRO
+
                 if (!result) {
+                    re_debug(" - ");
                     /*
                      * Non-greedy failure - try to consume another child.
                      */
                     if (curState->u.quantifier.max == (uintN) -1 ||
                         curState->u.quantifier.max > 0) {
-                        curState->index = x->cp - gData->cpbegin;
-                        curState->continue_op = REOP_MINIMALREPEAT;
-                        curState->continue_pc = pc;
-                        pc += ARG_LEN;
-                        for (k = curState->parenSoFar; k < parenSoFar; k++)
-                            x->parens[k].index = -1;
-                        PUSH_STATE_STACK(gData);
-                        op = (REOp) *pc++;
+                        PREPARE_REPEAT();
                         continue;
                     }
                     /* Don't need to adjust pc since we're going to pop. */
                     break;
                 }
                 if (curState->u.quantifier.min == 0 &&
                     x->cp == gData->cpbegin + curState->index) {
                     /* Matched an empty string, that'll get us nowhere. */
                     result = NULL;
                     break;
                 }
                 if (curState->u.quantifier.min != 0)
                     curState->u.quantifier.min--;
                 if (curState->u.quantifier.max != (uintN) -1)
                     curState->u.quantifier.max--;
                 if (curState->u.quantifier.min != 0) {
-                    curState->continue_op = REOP_MINIMALREPEAT;
-                    curState->continue_pc = pc;
-                    pc += ARG_LEN;
-                    for (k = curState->parenSoFar; k < parenSoFar; k++)
-                        x->parens[k].index = -1;
-                    curState->index = x->cp - gData->cpbegin;
-                    PUSH_STATE_STACK(gData);
-                    op = (REOp) *pc++;
-                    JS_ASSERT(op < REOP_LIMIT);
+                    PREPARE_REPEAT();
                     continue;
                 }
                 curState->index = x->cp - gData->cpbegin;
                 curState->parenSoFar = parenSoFar;
                 PUSH_STATE_STACK(gData);
                 if (!PushBackTrackState(gData, REOP_MINIMALREPEAT,
                                         pc, x, x->cp,
                                         curState->parenSoFar,
                                         parenSoFar - curState->parenSoFar)) {
-                    return NULL;
+                    goto bad;
                 }
                 --gData->stateStackTop;
                 pc = pc + GET_OFFSET(pc);
                 op = (REOp) *pc++;
                 JS_ASSERT(op < REOP_LIMIT);
                 continue;
               default:
                 JS_ASSERT(JS_FALSE);
@@ -3189,27 +3210,40 @@ ExecuteREBytecode(REGlobalData *gData, R
                        sizeof(REProgState) * backTrackData->saveStateStackTop,
                        sizeof(RECapture) * backTrackData->parenCount);
                 parenSoFar = backTrackData->parenIndex + backTrackData->parenCount;
             } else {
                 for (k = curState->parenSoFar; k < parenSoFar; k++)
                     x->parens[k].index = -1;
                 parenSoFar = curState->parenSoFar;
             }
+
+            re_debug("\tBT_Pop[%d]: %d,%d",
+                     ((char *)backTrackData - (char *)gData->backTrackStack) /
+                      sizeof(REBackTrackData),
+                     backTrackData->parenIndex, backTrackData->parenCount);
+
             continue;
         }
         x = result;
 
         /*
          *  Continue with the expression.
          */
         op = (REOp)*pc++;
         JS_ASSERT(op < REOP_LIMIT);
     }
+
+bad:            
+    re_debug("\n");
     return NULL;
+              
+good:           
+    re_debug("\n");
+    return x;   
 }
 
 static REMatchState *
 MatchRegExp(REGlobalData *gData, REMatchState *x)
 {
     REMatchState *result;
     const jschar *cp = x->cp;
     const jschar *cp2;
@@ -4239,8 +4273,9 @@ js_GetLastIndex(JSContext *cx, JSObject 
 JSBool
 js_SetLastIndex(JSContext *cx, JSObject *obj, jsdouble lastIndex)
 {
     jsval v;
 
     return js_NewNumberValue(cx, lastIndex, &v) &&
            JS_SetReservedSlot(cx, obj, 0, v);
 }
+
new file mode 100644
--- /dev/null
+++ b/js/src/jsreops.tbl
@@ -0,0 +1,147 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=0 ft=C:
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "license"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "as is" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contentsof this file are subject to the Mozilla Public License Version
+ * 1.1 (the "license"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of thter (the "lgpl"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+
+/* Note : contiguity of 'simple opcodes' is important for SimpleMatch() */
+
+/* match rest of input against rest of r.e. */
+REOP_DEF(REOP_EMPTY,         "empty")
+/* beginning of input (or line if multiline) */
+REOP_DEF(REOP_BOL,           "bol")
+/* end of input (or line if multiline) */
+REOP_DEF(REOP_EOL,           "eol")
+/* match "" at word boundary */
+REOP_DEF(REOP_WBDRY,         "wbdry")
+/* match "" at word non-boundary */
+REOP_DEF(REOP_WNONBDRY,      "wnonbdry")
+/* stands for any character */
+REOP_DEF(REOP_DOT,           "dot")
+/* match a digit char: [0-9] */
+REOP_DEF(REOP_DIGIT,         "digit")
+/* match a non-digit char: [^0-9] */
+REOP_DEF(REOP_NONDIGIT,      "nondigit")
+/* match an alphanumeric char: [0-9a-z_A-Z] */
+REOP_DEF(REOP_ALNUM,         "alnum")
+/* match a non-alphanumeric char: [^0-9a-z_A-Z] */
+REOP_DEF(REOP_NONALNUM,      "nonalnum")
+/* match a whitespace char */
+REOP_DEF(REOP_SPACE,         "space")
+/* match a non-whitespace char */
+REOP_DEF(REOP_NONSPACE,      "nonspace")
+/* back-reference (e.g., \1) to a parenthetical */
+REOP_DEF(REOP_BACKREF,       "backref")
+/* match a flat string */
+REOP_DEF(REOP_FLAT,          "flat")
+/* match a single char */
+REOP_DEF(REOP_FLAT1,         "flat1")
+/* case-independent REOP_FLAT */
+REOP_DEF(REOP_FLATi,         "flati")
+/* case-independent REOP_FLAT1 */
+REOP_DEF(REOP_FLAT1i,        "flat1i")
+/* single Unicode char */
+REOP_DEF(REOP_UCFLAT1,       "ucflat1")
+/* case-independent REOP_UCFLAT1 */
+REOP_DEF(REOP_UCFLAT1i,      "ucflat1i")
+/* flat Unicode string; len immediate counts chars */
+REOP_DEF(REOP_UCFLAT,        "ucflat")
+/* case-independent REOP_UCFLAT */
+REOP_DEF(REOP_UCFLATi,       "ucflati")
+/* character class with index */
+REOP_DEF(REOP_CLASS,         "class")
+/* negated character class with index */
+REOP_DEF(REOP_NCLASS,        "nclass")
+
+/* NCLASS is considered to be the last "simple" op-code */
+    
+
+/* alternative subexpressions in kid and next */
+REOP_DEF(REOP_ALT,           "alt")
+/* quantified atom: atom{1,2} */
+REOP_DEF(REOP_QUANT,         "quant")
+/* zero or more occurrences of kid */
+REOP_DEF(REOP_STAR,          "star")
+/* one or more occurrences of kid */
+REOP_DEF(REOP_PLUS,          "plus")
+/* optional subexpression in kid */
+REOP_DEF(REOP_OPT,           "opt")
+/* left paren bytecode: kid is u.num'th sub-regexp */
+REOP_DEF(REOP_LPAREN,        "lparen")
+/* right paren bytecode */
+REOP_DEF(REOP_RPAREN,        "rparen")
+/* for deoptimized closure loops */
+REOP_DEF(REOP_JUMP,          "jump")
+/* optimize .* to use a single opcode */
+REOP_DEF(REOP_DOTSTAR,       "dotstar")
+/* non-capturing version of REOP_LPAREN */
+REOP_DEF(REOP_LPARENNON,     "lparennon")
+/* zero width positive lookahead assertion */
+REOP_DEF(REOP_ASSERT,        "assert")
+/* zero width negative lookahead assertion */
+REOP_DEF(REOP_ASSERT_NOT,    "assert_not")
+/* sentinel at end of assertion child */
+REOP_DEF(REOP_ASSERTTEST,    "asserttest")
+/* sentinel at end of !assertion child */
+REOP_DEF(REOP_ASSERTNOTTEST, "assertnottest")
+/* non-greedy version of * */
+REOP_DEF(REOP_MINIMALSTAR,   "minimalstar")
+/* non-greedy version of + */
+REOP_DEF(REOP_MINIMALPLUS,   "minimalplus")
+/* non-greedy version of ? */
+REOP_DEF(REOP_MINIMALOPT,    "minimalopt")
+/* non-greedy version of {} */
+REOP_DEF(REOP_MINIMALQUANT,  "minimalquant")
+/* sentinel at end of quantifier child */
+REOP_DEF(REOP_ENDCHILD,      "endchild")
+/* directs execution of greedy quantifier */
+REOP_DEF(REOP_REPEAT,        "repeat")
+/* directs execution of non-greedy quantifier */
+REOP_DEF(REOP_MINIMALREPEAT, "minimalrepeat")
+/* prerequisite for ALT, either of two chars */
+REOP_DEF(REOP_ALTPREREQ,     "altprereq")
+/* prerequisite for ALT, a char or a class */
+REOP_DEF(REOP_ALTPREREQ2,    "altprereq2")
+/* end of final alternate */
+REOP_DEF(REOP_ENDALT,        "endalt")
+/* concatenation of terms (parse time only) */
+REOP_DEF(REOP_CONCAT,        "concat")
+/* end of expression */
+REOP_DEF(REOP_END,           "end")
+/* META: no operator >= to this */
+REOP_DEF(REOP_LIMIT,"limit")