Projekt

Obecné

Profil

Stáhnout (29.9 KB) Statistiky
| Větev: | Revize:
1
// regjsparser
2
//
3
// ==================================================================
4
//
5
// See ECMA-262 Standard: 15.10.1
6
//
7
// NOTE: The ECMA-262 standard uses the term "Assertion" for /^/. Here the
8
//   term "Anchor" is used.
9
//
10
// Pattern ::
11
//      Disjunction
12
//
13
// Disjunction ::
14
//      Alternative
15
//      Alternative | Disjunction
16
//
17
// Alternative ::
18
//      [empty]
19
//      Alternative Term
20
//
21
// Term ::
22
//      Anchor
23
//      Atom
24
//      Atom Quantifier
25
//
26
// Anchor ::
27
//      ^
28
//      $
29
//      \ b
30
//      \ B
31
//      ( ? = Disjunction )
32
//      ( ? ! Disjunction )
33
//
34
// Quantifier ::
35
//      QuantifierPrefix
36
//      QuantifierPrefix ?
37
//
38
// QuantifierPrefix ::
39
//      *
40
//      +
41
//      ?
42
//      { DecimalDigits }
43
//      { DecimalDigits , }
44
//      { DecimalDigits , DecimalDigits }
45
//
46
// Atom ::
47
//      PatternCharacter
48
//      .
49
//      \ AtomEscape
50
//      CharacterClass
51
//      ( Disjunction )
52
//      ( ? : Disjunction )
53
//
54
// PatternCharacter ::
55
//      SourceCharacter but not any of: ^ $ \ . * + ? ( ) [ ] { } |
56
//
57
// AtomEscape ::
58
//      DecimalEscape
59
//      CharacterEscape
60
//      CharacterClassEscape
61
//
62
// CharacterEscape[U] ::
63
//      ControlEscape
64
//      c ControlLetter
65
//      HexEscapeSequence
66
//      RegExpUnicodeEscapeSequence[?U] (ES6)
67
//      IdentityEscape[?U]
68
//
69
// ControlEscape ::
70
//      one of f n r t v
71
// ControlLetter ::
72
//      one of
73
//          a b c d e f g h i j k l m n o p q r s t u v w x y z
74
//          A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
75
//
76
// IdentityEscape ::
77
//      SourceCharacter but not IdentifierPart
78
//      <ZWJ>
79
//      <ZWNJ>
80
//
81
// DecimalEscape ::
82
//      DecimalIntegerLiteral [lookahead ∉ DecimalDigit]
83
//
84
// CharacterClassEscape ::
85
//      one of d D s S w W
86
//
87
// CharacterClass ::
88
//      [ [lookahead ∉ {^}] ClassRanges ]
89
//      [ ^ ClassRanges ]
90
//
91
// ClassRanges ::
92
//      [empty]
93
//      NonemptyClassRanges
94
//
95
// NonemptyClassRanges ::
96
//      ClassAtom
97
//      ClassAtom NonemptyClassRangesNoDash
98
//      ClassAtom - ClassAtom ClassRanges
99
//
100
// NonemptyClassRangesNoDash ::
101
//      ClassAtom
102
//      ClassAtomNoDash NonemptyClassRangesNoDash
103
//      ClassAtomNoDash - ClassAtom ClassRanges
104
//
105
// ClassAtom ::
106
//      -
107
//      ClassAtomNoDash
108
//
109
// ClassAtomNoDash ::
110
//      SourceCharacter but not one of \ or ] or -
111
//      \ ClassEscape
112
//
113
// ClassEscape ::
114
//      DecimalEscape
115
//      b
116
//      CharacterEscape
117
//      CharacterClassEscape
118

    
119
(function() {
120

    
121
  function parse(str, flags) {
122
    function addRaw(node) {
123
      node.raw = str.substring(node.range[0], node.range[1]);
124
      return node;
125
    }
126

    
127
    function updateRawStart(node, start) {
128
      node.range[0] = start;
129
      return addRaw(node);
130
    }
131

    
132
    function createAnchor(kind, rawLength) {
133
      return addRaw({
134
        type: 'anchor',
135
        kind: kind,
136
        range: [
137
          pos - rawLength,
138
          pos
139
        ]
140
      });
141
    }
142

    
143
    function createValue(kind, codePoint, from, to) {
144
      return addRaw({
145
        type: 'value',
146
        kind: kind,
147
        codePoint: codePoint,
148
        range: [from, to]
149
      });
150
    }
151

    
152
    function createEscaped(kind, codePoint, value, fromOffset) {
153
      fromOffset = fromOffset || 0;
154
      return createValue(kind, codePoint, pos - (value.length + fromOffset), pos);
155
    }
156

    
157
    function createCharacter(matches) {
158
      var _char = matches[0];
159
      var first = _char.charCodeAt(0);
160
      if (hasUnicodeFlag) {
161
        var second;
162
        if (_char.length === 1 && first >= 0xD800 && first <= 0xDBFF) {
163
          second = lookahead().charCodeAt(0);
164
          if (second >= 0xDC00 && second <= 0xDFFF) {
165
            // Unicode surrogate pair
166
            pos++;
167
            return createValue(
168
                'symbol',
169
                (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000,
170
                pos - 2, pos);
171
          }
172
        }
173
      }
174
      return createValue('symbol', first, pos - 1, pos);
175
    }
176

    
177
    function createDisjunction(alternatives, from, to) {
178
      return addRaw({
179
        type: 'disjunction',
180
        body: alternatives,
181
        range: [
182
          from,
183
          to
184
        ]
185
      });
186
    }
187

    
188
    function createDot() {
189
      return addRaw({
190
        type: 'dot',
191
        range: [
192
          pos - 1,
193
          pos
194
        ]
195
      });
196
    }
197

    
198
    function createCharacterClassEscape(value) {
199
      return addRaw({
200
        type: 'characterClassEscape',
201
        value: value,
202
        range: [
203
          pos - 2,
204
          pos
205
        ]
206
      });
207
    }
208

    
209
    function createReference(matchIndex) {
210
      return addRaw({
211
        type: 'reference',
212
        matchIndex: parseInt(matchIndex, 10),
213
        range: [
214
          pos - 1 - matchIndex.length,
215
          pos
216
        ]
217
      });
218
    }
219

    
220
    function createGroup(behavior, disjunction, from, to) {
221
      return addRaw({
222
        type: 'group',
223
        behavior: behavior,
224
        body: disjunction,
225
        range: [
226
          from,
227
          to
228
        ]
229
      });
230
    }
231

    
232
    function createQuantifier(min, max, from, to) {
233
      if (to == null) {
234
        from = pos - 1;
235
        to = pos;
236
      }
237

    
238
      return addRaw({
239
        type: 'quantifier',
240
        min: min,
241
        max: max,
242
        greedy: true,
243
        body: null, // set later on
244
        range: [
245
          from,
246
          to
247
        ]
248
      });
249
    }
250

    
251
    function createAlternative(terms, from, to) {
252
      return addRaw({
253
        type: 'alternative',
254
        body: terms,
255
        range: [
256
          from,
257
          to
258
        ]
259
      });
260
    }
261

    
262
    function createCharacterClass(classRanges, negative, from, to) {
263
      return addRaw({
264
        type: 'characterClass',
265
        body: classRanges,
266
        negative: negative,
267
        range: [
268
          from,
269
          to
270
        ]
271
      });
272
    }
273

    
274
    function createClassRange(min, max, from, to) {
275
      // See 15.10.2.15:
276
      if (min.codePoint > max.codePoint) {
277
        bail('invalid range in character class', min.raw + '-' + max.raw, from, to);
278
      }
279

    
280
      return addRaw({
281
        type: 'characterClassRange',
282
        min: min,
283
        max: max,
284
        range: [
285
          from,
286
          to
287
        ]
288
      });
289
    }
290

    
291
    function flattenBody(body) {
292
      if (body.type === 'alternative') {
293
        return body.body;
294
      } else {
295
        return [body];
296
      }
297
    }
298

    
299
    function isEmpty(obj) {
300
      return obj.type === 'empty';
301
    }
302

    
303
    function incr(amount) {
304
      amount = (amount || 1);
305
      var res = str.substring(pos, pos + amount);
306
      pos += (amount || 1);
307
      return res;
308
    }
309

    
310
    function skip(value) {
311
      if (!match(value)) {
312
        bail('character', value);
313
      }
314
    }
315

    
316
    function match(value) {
317
      if (str.indexOf(value, pos) === pos) {
318
        return incr(value.length);
319
      }
320
    }
321

    
322
    function lookahead() {
323
      return str[pos];
324
    }
325

    
326
    function current(value) {
327
      return str.indexOf(value, pos) === pos;
328
    }
329

    
330
    function next(value) {
331
      return str[pos + 1] === value;
332
    }
333

    
334
    function matchReg(regExp) {
335
      var subStr = str.substring(pos);
336
      var res = subStr.match(regExp);
337
      if (res) {
338
        res.range = [];
339
        res.range[0] = pos;
340
        incr(res[0].length);
341
        res.range[1] = pos;
342
      }
343
      return res;
344
    }
345

    
346
    function parseDisjunction() {
347
      // Disjunction ::
348
      //      Alternative
349
      //      Alternative | Disjunction
350
      var res = [], from = pos;
351
      res.push(parseAlternative());
352

    
353
      while (match('|')) {
354
        res.push(parseAlternative());
355
      }
356

    
357
      if (res.length === 1) {
358
        return res[0];
359
      }
360

    
361
      return createDisjunction(res, from, pos);
362
    }
363

    
364
    function parseAlternative() {
365
      var res = [], from = pos;
366
      var term;
367

    
368
      // Alternative ::
369
      //      [empty]
370
      //      Alternative Term
371
      while (term = parseTerm()) {
372
        res.push(term);
373
      }
374

    
375
      if (res.length === 1) {
376
        return res[0];
377
      }
378

    
379
      return createAlternative(res, from, pos);
380
    }
381

    
382
    function parseTerm() {
383
      // Term ::
384
      //      Anchor
385
      //      Atom
386
      //      Atom Quantifier
387

    
388
      if (pos >= str.length || current('|') || current(')')) {
389
        return null; /* Means: The term is empty */
390
      }
391

    
392
      var anchor = parseAnchor();
393

    
394
      if (anchor) {
395
        return anchor;
396
      }
397

    
398
      var atom = parseAtom();
399
      if (!atom) {
400
        bail('Expected atom');
401
      }
402
      var quantifier = parseQuantifier() || false;
403
      if (quantifier) {
404
        quantifier.body = flattenBody(atom);
405
        // The quantifier contains the atom. Therefore, the beginning of the
406
        // quantifier range is given by the beginning of the atom.
407
        updateRawStart(quantifier, atom.range[0]);
408
        return quantifier;
409
      }
410
      return atom;
411
    }
412

    
413
    function parseGroup(matchA, typeA, matchB, typeB) {
414
      var type = null, from = pos;
415

    
416
      if (match(matchA)) {
417
        type = typeA;
418
      } else if (match(matchB)) {
419
        type = typeB;
420
      } else {
421
        return false;
422
      }
423

    
424
      var body = parseDisjunction();
425
      if (!body) {
426
        bail('Expected disjunction');
427
      }
428
      skip(')');
429
      var group = createGroup(type, flattenBody(body), from, pos);
430

    
431
      if (type == 'normal') {
432
        // Keep track of the number of closed groups. This is required for
433
        // parseDecimalEscape(). In case the string is parsed a second time the
434
        // value already holds the total count and no incrementation is required.
435
        if (firstIteration) {
436
          closedCaptureCounter++;
437
        }
438
      }
439
      return group;
440
    }
441

    
442
    function parseAnchor() {
443
      // Anchor ::
444
      //      ^
445
      //      $
446
      //      \ b
447
      //      \ B
448
      //      ( ? = Disjunction )
449
      //      ( ? ! Disjunction )
450
      var res, from = pos;
451

    
452
      if (match('^')) {
453
        return createAnchor('start', 1 /* rawLength */);
454
      } else if (match('$')) {
455
        return createAnchor('end', 1 /* rawLength */);
456
      } else if (match('\\b')) {
457
        return createAnchor('boundary', 2 /* rawLength */);
458
      } else if (match('\\B')) {
459
        return createAnchor('not-boundary', 2 /* rawLength */);
460
      } else {
461
        return parseGroup('(?=', 'lookahead', '(?!', 'negativeLookahead');
462
      }
463
    }
464

    
465
    function parseQuantifier() {
466
      // Quantifier ::
467
      //      QuantifierPrefix
468
      //      QuantifierPrefix ?
469
      //
470
      // QuantifierPrefix ::
471
      //      *
472
      //      +
473
      //      ?
474
      //      { DecimalDigits }
475
      //      { DecimalDigits , }
476
      //      { DecimalDigits , DecimalDigits }
477

    
478
      var res, from = pos;
479
      var quantifier;
480
      var min, max;
481

    
482
      if (match('*')) {
483
        quantifier = createQuantifier(0);
484
      }
485
      else if (match('+')) {
486
        quantifier = createQuantifier(1);
487
      }
488
      else if (match('?')) {
489
        quantifier = createQuantifier(0, 1);
490
      }
491
      else if (res = matchReg(/^\{([0-9]+)\}/)) {
492
        min = parseInt(res[1], 10);
493
        quantifier = createQuantifier(min, min, res.range[0], res.range[1]);
494
      }
495
      else if (res = matchReg(/^\{([0-9]+),\}/)) {
496
        min = parseInt(res[1], 10);
497
        quantifier = createQuantifier(min, undefined, res.range[0], res.range[1]);
498
      }
499
      else if (res = matchReg(/^\{([0-9]+),([0-9]+)\}/)) {
500
        min = parseInt(res[1], 10);
501
        max = parseInt(res[2], 10);
502
        if (min > max) {
503
          bail('numbers out of order in {} quantifier', '', from, pos);
504
        }
505
        quantifier = createQuantifier(min, max, res.range[0], res.range[1]);
506
      }
507

    
508
      if (quantifier) {
509
        if (match('?')) {
510
          quantifier.greedy = false;
511
          quantifier.range[1] += 1;
512
        }
513
      }
514

    
515
      return quantifier;
516
    }
517

    
518
    function parseAtom() {
519
      // Atom ::
520
      //      PatternCharacter
521
      //      .
522
      //      \ AtomEscape
523
      //      CharacterClass
524
      //      ( Disjunction )
525
      //      ( ? : Disjunction )
526

    
527
      var res;
528

    
529
      // jviereck: allow ']', '}' here as well to be compatible with browser's
530
      //   implementations: ']'.match(/]/);
531
      // if (res = matchReg(/^[^^$\\.*+?()[\]{}|]/)) {
532
      if (res = matchReg(/^[^^$\\.*+?(){[|]/)) {
533
        //      PatternCharacter
534
        return createCharacter(res);
535
      }
536
      else if (match('.')) {
537
        //      .
538
        return createDot();
539
      }
540
      else if (match('\\')) {
541
        //      \ AtomEscape
542
        res = parseAtomEscape();
543
        if (!res) {
544
          bail('atomEscape');
545
        }
546
        return res;
547
      }
548
      else if (res = parseCharacterClass()) {
549
        return res;
550
      }
551
      else {
552
        //      ( Disjunction )
553
        //      ( ? : Disjunction )
554
        return parseGroup('(?:', 'ignore', '(', 'normal');
555
      }
556
    }
557

    
558
    function parseUnicodeSurrogatePairEscape(firstEscape) {
559
      if (hasUnicodeFlag) {
560
        var first, second;
561
        if (firstEscape.kind == 'unicodeEscape' &&
562
          (first = firstEscape.codePoint) >= 0xD800 && first <= 0xDBFF &&
563
          current('\\') && next('u') ) {
564
          var prevPos = pos;
565
          pos++;
566
          var secondEscape = parseClassEscape();
567
          if (secondEscape.kind == 'unicodeEscape' &&
568
            (second = secondEscape.codePoint) >= 0xDC00 && second <= 0xDFFF) {
569
            // Unicode surrogate pair
570
            firstEscape.range[1] = secondEscape.range[1];
571
            firstEscape.codePoint = (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000;
572
            firstEscape.type = 'value';
573
            firstEscape.kind = 'unicodeCodePointEscape';
574
            addRaw(firstEscape);
575
          }
576
          else {
577
            pos = prevPos;
578
          }
579
        }
580
      }
581
      return firstEscape;
582
    }
583

    
584
    function parseClassEscape() {
585
      return parseAtomEscape(true);
586
    }
587

    
588
    function parseAtomEscape(insideCharacterClass) {
589
      // AtomEscape ::
590
      //      DecimalEscape
591
      //      CharacterEscape
592
      //      CharacterClassEscape
593

    
594
      var res, from = pos;
595

    
596
      res = parseDecimalEscape();
597
      if (res) {
598
        return res;
599
      }
600

    
601
      // For ClassEscape
602
      if (insideCharacterClass) {
603
        if (match('b')) {
604
          // 15.10.2.19
605
          // The production ClassEscape :: b evaluates by returning the
606
          // CharSet containing the one character <BS> (Unicode value 0008).
607
          return createEscaped('singleEscape', 0x0008, '\\b');
608
        } else if (match('B')) {
609
          bail('\\B not possible inside of CharacterClass', '', from);
610
        }
611
      }
612

    
613
      res = parseCharacterEscape();
614

    
615
      return res;
616
    }
617

    
618

    
619
    function parseDecimalEscape() {
620
      // DecimalEscape ::
621
      //      DecimalIntegerLiteral [lookahead ∉ DecimalDigit]
622
      //      CharacterClassEscape :: one of d D s S w W
623

    
624
      var res, match;
625

    
626
      if (res = matchReg(/^(?!0)\d+/)) {
627
        match = res[0];
628
        var refIdx = parseInt(res[0], 10);
629
        if (refIdx <= closedCaptureCounter) {
630
          // If the number is smaller than the normal-groups found so
631
          // far, then it is a reference...
632
          return createReference(res[0]);
633
        } else {
634
          // ... otherwise it needs to be interpreted as a octal (if the
635
          // number is in an octal format). If it is NOT octal format,
636
          // then the slash is ignored and the number is matched later
637
          // as normal characters.
638

    
639
          // Recall the negative decision to decide if the input must be parsed
640
          // a second time with the total normal-groups.
641
          backrefDenied.push(refIdx);
642

    
643
          // Reset the position again, as maybe only parts of the previous
644
          // matched numbers are actual octal numbers. E.g. in '019' only
645
          // the '01' should be matched.
646
          incr(-res[0].length);
647
          if (res = matchReg(/^[0-7]{1,3}/)) {
648
            return createEscaped('octal', parseInt(res[0], 8), res[0], 1);
649
          } else {
650
            // If we end up here, we have a case like /\91/. Then the
651
            // first slash is to be ignored and the 9 & 1 to be treated
652
            // like ordinary characters. Create a character for the
653
            // first number only here - other number-characters
654
            // (if available) will be matched later.
655
            res = createCharacter(matchReg(/^[89]/));
656
            return updateRawStart(res, res.range[0] - 1);
657
          }
658
        }
659
      }
660
      // Only allow octal numbers in the following. All matched numbers start
661
      // with a zero (if the do not, the previous if-branch is executed).
662
      // If the number is not octal format and starts with zero (e.g. `091`)
663
      // then only the zeros `0` is treated here and the `91` are ordinary
664
      // characters.
665
      // Example:
666
      //   /\091/.exec('\091')[0].length === 3
667
      else if (res = matchReg(/^[0-7]{1,3}/)) {
668
        match = res[0];
669
        if (/^0{1,3}$/.test(match)) {
670
          // If they are all zeros, then only take the first one.
671
          return createEscaped('null', 0x0000, '0', match.length + 1);
672
        } else {
673
          return createEscaped('octal', parseInt(match, 8), match, 1);
674
        }
675
      } else if (res = matchReg(/^[dDsSwW]/)) {
676
        return createCharacterClassEscape(res[0]);
677
      }
678
      return false;
679
    }
680

    
681
    function parseCharacterEscape() {
682
      // CharacterEscape ::
683
      //      ControlEscape
684
      //      c ControlLetter
685
      //      HexEscapeSequence
686
      //      UnicodeEscapeSequence
687
      //      IdentityEscape
688

    
689
      var res;
690
      if (res = matchReg(/^[fnrtv]/)) {
691
        // ControlEscape
692
        var codePoint = 0;
693
        switch (res[0]) {
694
          case 't': codePoint = 0x009; break;
695
          case 'n': codePoint = 0x00A; break;
696
          case 'v': codePoint = 0x00B; break;
697
          case 'f': codePoint = 0x00C; break;
698
          case 'r': codePoint = 0x00D; break;
699
        }
700
        return createEscaped('singleEscape', codePoint, '\\' + res[0]);
701
      } else if (res = matchReg(/^c([a-zA-Z])/)) {
702
        // c ControlLetter
703
        return createEscaped('controlLetter', res[1].charCodeAt(0) % 32, res[1], 2);
704
      } else if (res = matchReg(/^x([0-9a-fA-F]{2})/)) {
705
        // HexEscapeSequence
706
        return createEscaped('hexadecimalEscape', parseInt(res[1], 16), res[1], 2);
707
      } else if (res = matchReg(/^u([0-9a-fA-F]{4})/)) {
708
        // UnicodeEscapeSequence
709
        return parseUnicodeSurrogatePairEscape(
710
          createEscaped('unicodeEscape', parseInt(res[1], 16), res[1], 2)
711
        );
712
      } else if (hasUnicodeFlag && (res = matchReg(/^u\{([0-9a-fA-F]+)\}/))) {
713
        // RegExpUnicodeEscapeSequence (ES6 Unicode code point escape)
714
        return createEscaped('unicodeCodePointEscape', parseInt(res[1], 16), res[1], 4);
715
      } else {
716
        // IdentityEscape
717
        return parseIdentityEscape();
718
      }
719
    }
720

    
721
    // Taken from the Esprima parser.
722
    function isIdentifierPart(ch) {
723
      // Generated by `tools/generate-identifier-regex.js`.
724
      var NonAsciiIdentifierPart = new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0-\u08B2\u08E4-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D01-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D60-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA69D\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2D\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]');
725

    
726
      return (ch === 36) || (ch === 95) ||  // $ (dollar) and _ (underscore)
727
        (ch >= 65 && ch <= 90) ||         // A..Z
728
        (ch >= 97 && ch <= 122) ||        // a..z
729
        (ch >= 48 && ch <= 57) ||         // 0..9
730
        (ch === 92) ||                    // \ (backslash)
731
        ((ch >= 0x80) && NonAsciiIdentifierPart.test(String.fromCharCode(ch)));
732
    }
733

    
734
    function parseIdentityEscape() {
735
      // IdentityEscape ::
736
      //      SourceCharacter but not IdentifierPart
737
      //      <ZWJ>
738
      //      <ZWNJ>
739

    
740
      var ZWJ = '\u200C';
741
      var ZWNJ = '\u200D';
742

    
743
      var tmp;
744

    
745
      if (!isIdentifierPart(lookahead())) {
746
        tmp = incr();
747
        return createEscaped('identifier', tmp.charCodeAt(0), tmp, 1);
748
      }
749

    
750
      if (match(ZWJ)) {
751
        // <ZWJ>
752
        return createEscaped('identifier', 0x200C, ZWJ);
753
      } else if (match(ZWNJ)) {
754
        // <ZWNJ>
755
        return createEscaped('identifier', 0x200D, ZWNJ);
756
      }
757

    
758
      return null;
759
    }
760

    
761
    function parseCharacterClass() {
762
      // CharacterClass ::
763
      //      [ [lookahead ∉ {^}] ClassRanges ]
764
      //      [ ^ ClassRanges ]
765

    
766
      var res, from = pos;
767
      if (res = matchReg(/^\[\^/)) {
768
        res = parseClassRanges();
769
        skip(']');
770
        return createCharacterClass(res, true, from, pos);
771
      } else if (match('[')) {
772
        res = parseClassRanges();
773
        skip(']');
774
        return createCharacterClass(res, false, from, pos);
775
      }
776

    
777
      return null;
778
    }
779

    
780
    function parseClassRanges() {
781
      // ClassRanges ::
782
      //      [empty]
783
      //      NonemptyClassRanges
784

    
785
      var res;
786
      if (current(']')) {
787
        // Empty array means nothing insinde of the ClassRange.
788
        return [];
789
      } else {
790
        res = parseNonemptyClassRanges();
791
        if (!res) {
792
          bail('nonEmptyClassRanges');
793
        }
794
        return res;
795
      }
796
    }
797

    
798
    function parseHelperClassRanges(atom) {
799
      var from, to, res;
800
      if (current('-') && !next(']')) {
801
        // ClassAtom - ClassAtom ClassRanges
802
        skip('-');
803

    
804
        res = parseClassAtom();
805
        if (!res) {
806
          bail('classAtom');
807
        }
808
        to = pos;
809
        var classRanges = parseClassRanges();
810
        if (!classRanges) {
811
          bail('classRanges');
812
        }
813
        from = atom.range[0];
814
        if (classRanges.type === 'empty') {
815
          return [createClassRange(atom, res, from, to)];
816
        }
817
        return [createClassRange(atom, res, from, to)].concat(classRanges);
818
      }
819

    
820
      res = parseNonemptyClassRangesNoDash();
821
      if (!res) {
822
        bail('nonEmptyClassRangesNoDash');
823
      }
824

    
825
      return [atom].concat(res);
826
    }
827

    
828
    function parseNonemptyClassRanges() {
829
      // NonemptyClassRanges ::
830
      //      ClassAtom
831
      //      ClassAtom NonemptyClassRangesNoDash
832
      //      ClassAtom - ClassAtom ClassRanges
833

    
834
      var atom = parseClassAtom();
835
      if (!atom) {
836
        bail('classAtom');
837
      }
838

    
839
      if (current(']')) {
840
        // ClassAtom
841
        return [atom];
842
      }
843

    
844
      // ClassAtom NonemptyClassRangesNoDash
845
      // ClassAtom - ClassAtom ClassRanges
846
      return parseHelperClassRanges(atom);
847
    }
848

    
849
    function parseNonemptyClassRangesNoDash() {
850
      // NonemptyClassRangesNoDash ::
851
      //      ClassAtom
852
      //      ClassAtomNoDash NonemptyClassRangesNoDash
853
      //      ClassAtomNoDash - ClassAtom ClassRanges
854

    
855
      var res = parseClassAtom();
856
      if (!res) {
857
        bail('classAtom');
858
      }
859
      if (current(']')) {
860
        //      ClassAtom
861
        return res;
862
      }
863

    
864
      // ClassAtomNoDash NonemptyClassRangesNoDash
865
      // ClassAtomNoDash - ClassAtom ClassRanges
866
      return parseHelperClassRanges(res);
867
    }
868

    
869
    function parseClassAtom() {
870
      // ClassAtom ::
871
      //      -
872
      //      ClassAtomNoDash
873
      if (match('-')) {
874
        return createCharacter('-');
875
      } else {
876
        return parseClassAtomNoDash();
877
      }
878
    }
879

    
880
    function parseClassAtomNoDash() {
881
      // ClassAtomNoDash ::
882
      //      SourceCharacter but not one of \ or ] or -
883
      //      \ ClassEscape
884

    
885
      var res;
886
      if (res = matchReg(/^[^\\\]-]/)) {
887
        return createCharacter(res[0]);
888
      } else if (match('\\')) {
889
        res = parseClassEscape();
890
        if (!res) {
891
          bail('classEscape');
892
        }
893

    
894
        return parseUnicodeSurrogatePairEscape(res);
895
      }
896
    }
897

    
898
    function bail(message, details, from, to) {
899
      from = from == null ? pos : from;
900
      to = to == null ? from : to;
901

    
902
      var contextStart = Math.max(0, from - 10);
903
      var contextEnd = Math.min(to + 10, str.length);
904

    
905
      // Output a bit of context and a line pointing to where our error is.
906
      //
907
      // We are assuming that there are no actual newlines in the content as this is a regular expression.
908
      var context = '    ' + str.substring(contextStart, contextEnd);
909
      var pointer = '    ' + new Array(from - contextStart + 1).join(' ') + '^';
910

    
911
      throw SyntaxError(message + ' at position ' + from + (details ? ': ' + details : '') + '\n' + context + '\n' + pointer);
912
    }
913

    
914
    var backrefDenied = [];
915
    var closedCaptureCounter = 0;
916
    var firstIteration = true;
917
    var hasUnicodeFlag = (flags || "").indexOf("u") !== -1;
918
    var pos = 0;
919

    
920
    // Convert the input to a string and treat the empty string special.
921
    str = String(str);
922
    if (str === '') {
923
      str = '(?:)';
924
    }
925

    
926
    var result = parseDisjunction();
927

    
928
    if (result.range[1] !== str.length) {
929
      bail('Could not parse entire input - got stuck', '', result.range[1]);
930
    }
931

    
932
    // The spec requires to interpret the `\2` in `/\2()()/` as backreference.
933
    // As the parser collects the number of capture groups as the string is
934
    // parsed it is impossible to make these decisions at the point when the
935
    // `\2` is handled. In case the local decision turns out to be wrong after
936
    // the parsing has finished, the input string is parsed a second time with
937
    // the total number of capture groups set.
938
    //
939
    // SEE: https://github.com/jviereck/regjsparser/issues/70
940
    for (var i = 0; i < backrefDenied.length; i++) {
941
      if (backrefDenied[i] <= closedCaptureCounter) {
942
        // Parse the input a second time.
943
        pos = 0;
944
        firstIteration = false;
945
        return parseDisjunction();
946
      }
947
    }
948

    
949
    return result;
950
  }
951

    
952
  var regjsparser = {
953
    parse: parse
954
  };
955

    
956
  if (typeof module !== 'undefined' && module.exports) {
957
    module.exports = regjsparser;
958
  } else {
959
    window.regjsparser = regjsparser;
960
  }
961

    
962
}());
(5-5/5)