', start: 8, end: 13},
- * // {name: 'match', value: '
an
', start: 13, end: 27},
- * // {name: 'right', value: '
', start: 27, end: 33},
- * // {name: 'between', value: ' example', start: 33, end: 41}
- * // ]
- *
- * // Omitting unneeded parts with null valueNames, and using escapeChar
- * str = '...{1}\\{{function(x,y){return y+x;}}';
- * XRegExp.matchRecursive(str, '{', '}', 'g', {
- * valueNames: ['literal', null, 'value', null],
- * escapeChar: '\\'
- * });
- * // -> [
- * // {name: 'literal', value: '...', start: 0, end: 3},
- * // {name: 'value', value: '1', start: 4, end: 5},
- * // {name: 'literal', value: '\\{', start: 6, end: 8},
- * // {name: 'value', value: 'function(x,y){return y+x;}', start: 9, end: 35}
- * // ]
- *
- * // Sticky mode via flag y
- * str = '<1><<<2>>><3>4<5>';
- * XRegExp.matchRecursive(str, '<', '>', 'gy');
- * // -> ['1', '<<2>>', '3']
- */
- XRegExp.matchRecursive = function (str, left, right, flags, options) {
- flags = flags || "";
- options = options || {};
- var global = flags.indexOf("g") > -1,
- sticky = flags.indexOf("y") > -1,
- basicFlags = flags.replace(/y/g, ""), // Flag y controlled internally
- escapeChar = options.escapeChar,
- vN = options.valueNames,
- output = [],
- openTokens = 0,
- delimStart = 0,
- delimEnd = 0,
- lastOuterEnd = 0,
- outerStart,
- innerStart,
- leftMatch,
- rightMatch,
- esc;
- left = XRegExp(left, basicFlags);
- right = XRegExp(right, basicFlags);
-
- if (escapeChar) {
- if (escapeChar.length > 1) {
- throw new SyntaxError("can't use more than one escape character");
- }
- escapeChar = XRegExp.escape(escapeChar);
- // Using XRegExp.union safely rewrites backreferences in `left` and `right`
- esc = new RegExp(
- "(?:" + escapeChar + "[\\S\\s]|(?:(?!" + XRegExp.union([left, right]).source + ")[^" + escapeChar + "])+)+",
- flags.replace(/[^im]+/g, "") // Flags gy not needed here; flags nsx handled by XRegExp
- );
- }
-
- while (true) {
- // If using an escape character, advance to the delimiter's next starting position,
- // skipping any escaped characters in between
- if (escapeChar) {
- delimEnd += (XRegExp.exec(str, esc, delimEnd, "sticky") || [""])[0].length;
- }
- leftMatch = XRegExp.exec(str, left, delimEnd);
- rightMatch = XRegExp.exec(str, right, delimEnd);
- // Keep the leftmost match only
- if (leftMatch && rightMatch) {
- if (leftMatch.index <= rightMatch.index) {
- rightMatch = null;
- } else {
- leftMatch = null;
- }
- }
- /* Paths (LM:leftMatch, RM:rightMatch, OT:openTokens):
- LM | RM | OT | Result
- 1 | 0 | 1 | loop
- 1 | 0 | 0 | loop
- 0 | 1 | 1 | loop
- 0 | 1 | 0 | throw
- 0 | 0 | 1 | throw
- 0 | 0 | 0 | break
- * Doesn't include the sticky mode special case
- * Loop ends after the first completed match if `!global` */
- if (leftMatch || rightMatch) {
- delimStart = (leftMatch || rightMatch).index;
- delimEnd = delimStart + (leftMatch || rightMatch)[0].length;
- } else if (!openTokens) {
- break;
- }
- if (sticky && !openTokens && delimStart > lastOuterEnd) {
- break;
- }
- if (leftMatch) {
- if (!openTokens) {
- outerStart = delimStart;
- innerStart = delimEnd;
- }
- ++openTokens;
- } else if (rightMatch && openTokens) {
- if (!--openTokens) {
- if (vN) {
- if (vN[0] && outerStart > lastOuterEnd) {
- output.push(row(vN[0], str.slice(lastOuterEnd, outerStart), lastOuterEnd, outerStart));
- }
- if (vN[1]) {
- output.push(row(vN[1], str.slice(outerStart, innerStart), outerStart, innerStart));
- }
- if (vN[2]) {
- output.push(row(vN[2], str.slice(innerStart, delimStart), innerStart, delimStart));
- }
- if (vN[3]) {
- output.push(row(vN[3], str.slice(delimStart, delimEnd), delimStart, delimEnd));
- }
- } else {
- output.push(str.slice(innerStart, delimStart));
- }
- lastOuterEnd = delimEnd;
- if (!global) {
- break;
- }
- }
- } else {
- throw new Error("string contains unbalanced delimiters");
- }
- // If the delimiter matched an empty string, avoid an infinite loop
- if (delimStart === delimEnd) {
- ++delimEnd;
- }
- }
-
- if (global && !sticky && vN && vN[0] && str.length > lastOuterEnd) {
- output.push(row(vN[0], str.slice(lastOuterEnd), lastOuterEnd, str.length));
- }
-
- return output;
- };
-
-}(XRegExp));
-
-
-/***** build.js *****/
-
-/*!
- * XRegExp.build v0.1.0
- * (c) 2012 Steven Levithan