/*
 *  Backreferences in the pattern part are covered, rather confusingly:
 *
 *    - E5 Section 15.10.2.9: AtomEscape production, which first
 *      evaluates the DecimalEscape production and looks at the result.
 *
 *    - E5 Section 15.10.2.11: DecimalEscape production; returns either
 *      a NUL character or a non-zero number.
 *
 *  This is rather confusing in that since DecimalEscape cannot evaluate
 *  to a zero number (\0 generates NUL character matcher), the check for
 *  zero in E5 Section 15.10.2.9 step 4 seems unnecessary.  Also note
 *  that (quoted from E5 Section 15.10.2.11).
 *
 *    "NOTE: If \ is followed by a decimal number n whose first digit
 *     is not 0, then the escape sequence is considered to be a
 *     backreference. It is an error if n is greater than the total
 *     number of left capturing parentheses in the entire regular
 *     expression. \0 represents the <NUL> character and cannot be
 *     followed by a decimal digit."
 *
 *  The evaluation algorithm in E5 Section 15.10.2.9 contains the actual
 *  behavior; more specifically step 4 throws a SyntaxError if "n=0 or
 *  n>NCapturingParens".
 *
 *  This means that:
 *
 *    - '\0' is a character match for U+0000
 *    - '\00' is apparently a SyntaxError
 *    - '\1' is a backreference, and a SyntaxError if there are no captures
 *
 *  If \n is in [1,NCapturingParens], but has not captured anything (perhaps
 *  it was an alternative in a disjunction that was not matched, or the capture
 *  only happens in the future), then the backreference should always SUCCEED!
 *  See E5 Section 15.10.2.9, step 5.3.
 */

var t;

/*===
null
102 111 111 0 4
SyntaxError
SyntaxError
SyntaxError
foo foo
fooquux undefined
===*/

/* Note: double quote backslashes carefully below. */

/*
 *  FIXME: neither Rhino nor V8 will throw SyntaxError from these cases
 *  (they'll just return a null match).  So perhaps this interpretation is wrong?
 */

try {
    /* no match -> null */
    eval("t = /foo\\0/.exec('foobar'); print(t);");
} catch (e) {
    print(e.name);
}

try {
    /* matches U+0000 -> t[0] = 'foo\u0000', avoid printing it directly */
    eval("t = /foo\\0/.exec('foo\\u0000'); print(t[0].charCodeAt(0), t[0].charCodeAt(1), t[0].charCodeAt(2), t[0].charCodeAt(3), t[0].length);");
} catch (e) {
    print(e.name);
}

try {
    /* '\0' must not be followed by decimal digits -> SyntaxError */
    eval("t = /foo\\00/.exec('foobar'); print(t);");
} catch (e) {
    print(e.name);
}

try {
    /* same as above */
    eval("t = /foo\\01/.exec('foobar'); print(t);");
} catch (e) {
    print(e.name);
}

try {
    /* not allowed, > NCapturingParen (=0) -> SyntaxError
     *
     * Note: Rhino will throw an *uncatchable* NullPointerException here!
     */

    eval("t = /foo\\1/.exec('foobar'); print(t);");
} catch (e) {
    print(e.name);
}

try {
    /* allowed, backreference is ignored, only 'foo' is matched */
    eval("t = /\\1(foo)/.exec('foobar'); print(t[0], t[1]);");
} catch (e) {
    print(e.name);
}

try {
    /* (?:foo|(bar)) will match 'foo', and capture \1 will be undefined.
     * The \1 will then succeed without matching any input.
     * Finally, 'quux' is matched.
     */
    eval("t = /(?:foo|(bar))\\1quux/.exec('fooquux'); print(t[0], t[1]);");
} catch (e) {
    print(e.name);
}

