Permalink
Browse files

Fix edge case where whitespace, line-comments, and inline-comments fo…

…llow each other and are followed by a quantifier.
  • Loading branch information...
1 parent 6b1da53 commit 86b39763643bc38e256872eeeb6600d51baaf0fe @slevithan committed Aug 22, 2012
Showing with 48 additions and 14 deletions.
  1. +23 −7 src/xregexp.js
  2. +2 −0 tests/spec/s-xregexp.js
  3. +23 −7 xregexp-all.js
View
30 src/xregexp.js
@@ -67,9 +67,6 @@ var XRegExp = (function(undefined) {
// Any backreference or dollar-prefixed character in replacement strings
replacementToken = /\$(?:{([\w$]+)}|(\d\d?|[\s\S]))/g,
-// Any greedy or lazy quantifier
- quantifier = /^(?:[?*+]|{\d+(?:,\d*)?})\??/,
-
// Check for correct `exec` handling of nonparticipating capturing groups
correctExecNpcg = nativ.exec.call(/()??/, '')[1] === undefined,
@@ -226,6 +223,25 @@ var XRegExp = (function(undefined) {
}
/**
+ * Checks whether the next nonignorable token after the specified position is a quantifier.
+ * @private
+ * @param {String} pattern Pattern to search within.
+ * @param {Number} pos Index in `pattern` to search at.
+ * @param {String} flags Flags used by the pattern.
+ * @returns {Boolean} Whether the next token is a quantifier.
+ */
+ function isQuantifierNext(pattern, pos, flags) {
+ return nativ.test.call(
+ flags.indexOf('x') > -1 ?
+ // Ignore any leading whitespace, line-comments, and inline-comments
+ /^(?:\s+|#.*|\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/ :
+ // Ignore any leading inline-comments
+ /^(?:\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/,
+ pattern.slice(pos)
+ );
+ }
+
+/**
* Prepares an options object from the given value.
* @private
* @param {String|Object} value Value to convert to an options object.
@@ -1512,9 +1528,9 @@ var XRegExp = (function(undefined) {
*/
add(
/\(\?#[^)]*\)/,
- function(match) {
+ function(match, scope, flags) {
// Keep tokens separated unless the following token is a quantifier
- return nativ.test.call(quantifier, match.input.slice(match.index + match[0].length)) ?
+ return isQuantifierNext(match.input, match.index + match[0].length, flags) ?
'' : '(?:)';
}
);
@@ -1523,9 +1539,9 @@ var XRegExp = (function(undefined) {
*/
add(
/\s+|#.*/,
- function(match) {
+ function(match, scope, flags) {
// Keep tokens separated unless the following token is a quantifier
- return nativ.test.call(quantifier, match.input.slice(match.index + match[0].length)) ?
+ return isQuantifierNext(match.input, match.index + match[0].length, flags) ?
'' : '(?:)';
},
{flag: 'x'}
View
2 tests/spec/s-xregexp.js
@@ -277,6 +277,7 @@ describe('XRegExp()', function() {
it('should apply a following quantifier to the preceding atom', function() {
expect(XRegExp('^a(?#)+$').test('aaa')).toBe(true);
+ expect(XRegExp('^a(?#)(?#)+$').test('aaa')).toBe(true);
});
it('should separate atoms', function() {
@@ -631,6 +632,7 @@ describe('XRegExp()', function() {
expect(XRegExp('^a +$', 'x').test('aaa')).toBe(true);
expect(XRegExp('^a#comment\n+$', 'x').test('aaa')).toBe(true);
expect(XRegExp('^a #comment\n +$', 'x').test('aaa')).toBe(true);
+ expect(XRegExp('^a (?#comment) #comment\n +$', 'x').test('aaa')).toBe(true);
});
it('should separate atoms', function() {
View
30 xregexp-all.js
@@ -94,9 +94,6 @@ var XRegExp = (function(undefined) {
// Any backreference or dollar-prefixed character in replacement strings
replacementToken = /\$(?:{([\w$]+)}|(\d\d?|[\s\S]))/g,
-// Any greedy or lazy quantifier
- quantifier = /^(?:[?*+]|{\d+(?:,\d*)?})\??/,
-
// Check for correct `exec` handling of nonparticipating capturing groups
correctExecNpcg = nativ.exec.call(/()??/, '')[1] === undefined,
@@ -253,6 +250,25 @@ var XRegExp = (function(undefined) {
}
/**
+ * Checks whether the next nonignorable token after the specified position is a quantifier.
+ * @private
+ * @param {String} pattern Pattern to search within.
+ * @param {Number} pos Index in `pattern` to search at.
+ * @param {String} flags Flags used by the pattern.
+ * @returns {Boolean} Whether the next token is a quantifier.
+ */
+ function isQuantifierNext(pattern, pos, flags) {
+ return nativ.test.call(
+ flags.indexOf('x') > -1 ?
+ // Ignore any leading whitespace, line-comments, and inline-comments
+ /^(?:\s+|#.*|\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/ :
+ // Ignore any leading inline-comments
+ /^(?:\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/,
+ pattern.slice(pos)
+ );
+ }
+
+/**
* Prepares an options object from the given value.
* @private
* @param {String|Object} value Value to convert to an options object.
@@ -1539,9 +1555,9 @@ var XRegExp = (function(undefined) {
*/
add(
/\(\?#[^)]*\)/,
- function(match) {
+ function(match, scope, flags) {
// Keep tokens separated unless the following token is a quantifier
- return nativ.test.call(quantifier, match.input.slice(match.index + match[0].length)) ?
+ return isQuantifierNext(match.input, match.index + match[0].length, flags) ?
'' : '(?:)';
}
);
@@ -1550,9 +1566,9 @@ var XRegExp = (function(undefined) {
*/
add(
/\s+|#.*/,
- function(match) {
+ function(match, scope, flags) {
// Keep tokens separated unless the following token is a quantifier
- return nativ.test.call(quantifier, match.input.slice(match.index + match[0].length)) ?
+ return isQuantifierNext(match.input, match.index + match[0].length, flags) ?
'' : '(?:)';
},
{flag: 'x'}

0 comments on commit 86b3976

Please sign in to comment.