function XRegExp(pattern, flags) {
    if (XRegExp.isRegExp(pattern)) {
        if (flags !== undefined) {
            throw new TypeError('Cannot supply flags when copying a RegExp');
        }
        return copyRegex(pattern);
    }

    // Copy the argument behavior of `RegExp`
    pattern = pattern === undefined ? '' : String(pattern);
    flags = flags === undefined ? '' : String(flags);

    if (XRegExp.isInstalled('astral') && flags.indexOf('A') === -1) {
        // This causes an error to be thrown if the Unicode Base addon is not available
        flags += 'A';
    }

    if (!patternCache[pattern]) {
        patternCache[pattern] = {};
    }

    if (!patternCache[pattern][flags]) {
        var context = {
            hasNamedCapture: false,
            captureNames: []
        };
        var scope = defaultScope;
        var output = '';
        var pos = 0;
        var result;

        // Check for flag-related errors, and strip/apply flags in a leading mode modifier
        var applied = prepareFlags(pattern, flags);
        var appliedPattern = applied.pattern;
        var appliedFlags = applied.flags;

        // Use XRegExp's tokens to translate the pattern to a native regex pattern.
        // `appliedPattern.length` may change on each iteration if tokens use `reparse`
        while (pos < appliedPattern.length) {
            do {
                // Check for custom tokens at the current position
                result = runTokens(appliedPattern, appliedFlags, pos, scope, context);
                // If the matched token used the `reparse` option, splice its output into the
                // pattern before running tokens again at the same position
                if (result && result.reparse) {
                    appliedPattern = appliedPattern.slice(0, pos) +
                        result.output +
                        appliedPattern.slice(pos + result.matchLength);
                }
            } while (result && result.reparse);

            if (result) {
                output += result.output;
                pos += (result.matchLength || 1);
            } else {
                // Get the native token at the current position
                var token = XRegExp.exec(appliedPattern, nativeTokens[scope], pos, 'sticky')[0];
                output += token;
                pos += token.length;
                if (token === '[' && scope === defaultScope) {
                    scope = classScope;
                } else if (token === ']' && scope === classScope) {
                    scope = defaultScope;
                }
            }
        }

        patternCache[pattern][flags] = {
            // Use basic cleanup to collapse repeated empty groups like `(?:)(?:)` to `(?:)`. Empty
            // groups are sometimes inserted during regex transpilation in order to keep tokens
            // separated. However, more than one empty group in a row is never needed.
            pattern: nativ.replace.call(output, /(?:\(\?:\))+/g, '(?:)'),
            // Strip all but native flags
            flags: nativ.replace.call(appliedFlags, /[^gimuy]+/g, ''),
            // `context.captureNames` has an item for each capturing group, even if unnamed
            captures: context.hasNamedCapture ? context.captureNames : null
        };
    }

    var generated = patternCache[pattern][flags];
    return augment(
        new RegExp(generated.pattern, generated.flags),
        generated.captures,
        pattern,
        flags
    );
}
Creates an extended regular expression object for matching text with a pattern. Differs from a
native regular expression in that additional syntax and flags are supported. The returned object
is in fact a native `RegExp` and works with all native methods.

@class XRegExp
@constructor
@param {String|RegExp} pattern Regex pattern string, or an existing regex object to copy.
@param {String} [flags] Any combination of flags.
  Native flags:
    - `g` - global
    - `i` - ignore case
    - `m` - multiline anchors
    - `u` - unicode (ES6)
    - `y` - sticky (Firefox 3+, ES6)
  Additional XRegExp flags:
    - `n` - explicit capture
    - `s` - dot matches all (aka singleline)
    - `x` - free-spacing and line comments (aka extended)
    - `A` - astral (requires the Unicode Base addon)
  Flags cannot be provided when constructing one `RegExp` from another.
@returns {RegExp} Extended regular expression object.
@example

// With named capture and flag x
XRegExp('(?<year>  [0-9]{4} ) -?  # year  \n\
         (?<month> [0-9]{2} ) -?  # month \n\
         (?<day>   [0-9]{2} )     # day   ', 'x');

// Providing a regex object copies it. Native regexes are recompiled using native (not XRegExp)
// syntax. Copies maintain extended data, are augmented with `XRegExp.prototype` properties, and
// have fresh `lastIndex` properties (set to zero).
XRegExp(/regex/);