Projekt

Obecné

Profil

Stáhnout (10.2 KB) Statistiky
| Větev: | Revize:
1
/*!
2
 * RegJSGen
3
 * Copyright 2014 Benjamin Tan <https://d10.github.io/>
4
 * Available under MIT license <http://d10.mit-license.org/>
5
 */
6
;(function() {
7
  'use strict';
8

    
9
  /** Used to determine if values are of the language type `Object` */
10
  var objectTypes = {
11
    'function': true,
12
    'object': true
13
  };
14

    
15
  /** Used as a reference to the global object */
16
  var root = (objectTypes[typeof window] && window) || this;
17

    
18
  /** Backup possible global object */
19
  var oldRoot = root;
20

    
21
  /** Detect free variable `exports` */
22
  var freeExports = objectTypes[typeof exports] && exports;
23

    
24
  /** Detect free variable `module` */
25
  var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;
26

    
27
  /** Detect free variable `global` from Node.js or Browserified code and use it as `root` */
28
  var freeGlobal = freeExports && freeModule && typeof global == 'object' && global;
29
  if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal || freeGlobal.self === freeGlobal)) {
30
    root = freeGlobal;
31
  }
32

    
33
  /*--------------------------------------------------------------------------*/
34

    
35
  /*! Based on https://mths.be/fromcodepoint v0.2.0 by @mathias */
36

    
37
  var stringFromCharCode = String.fromCharCode;
38
  var floor = Math.floor;
39
  function fromCodePoint() {
40
    var MAX_SIZE = 0x4000;
41
    var codeUnits = [];
42
    var highSurrogate;
43
    var lowSurrogate;
44
    var index = -1;
45
    var length = arguments.length;
46
    if (!length) {
47
      return '';
48
    }
49
    var result = '';
50
    while (++index < length) {
51
      var codePoint = Number(arguments[index]);
52
      if (
53
        !isFinite(codePoint) || // `NaN`, `+Infinity`, or `-Infinity`
54
        codePoint < 0 || // not a valid Unicode code point
55
        codePoint > 0x10FFFF || // not a valid Unicode code point
56
        floor(codePoint) != codePoint // not an integer
57
      ) {
58
        throw RangeError('Invalid code point: ' + codePoint);
59
      }
60
      if (codePoint <= 0xFFFF) {
61
        // BMP code point
62
        codeUnits.push(codePoint);
63
      } else {
64
        // Astral code point; split in surrogate halves
65
        // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
66
        codePoint -= 0x10000;
67
        highSurrogate = (codePoint >> 10) + 0xD800;
68
        lowSurrogate = (codePoint % 0x400) + 0xDC00;
69
        codeUnits.push(highSurrogate, lowSurrogate);
70
      }
71
      if (index + 1 == length || codeUnits.length > MAX_SIZE) {
72
        result += stringFromCharCode.apply(null, codeUnits);
73
        codeUnits.length = 0;
74
      }
75
    }
76
    return result;
77
  }
78

    
79
  function assertType(type, expected) {
80
    if (expected.indexOf('|') == -1) {
81
      if (type == expected) {
82
        return;
83
      }
84

    
85
      throw Error('Invalid node type: ' + type);
86
    }
87

    
88
    expected = assertType.hasOwnProperty(expected)
89
      ? assertType[expected]
90
      : (assertType[expected] = RegExp('^(?:' + expected + ')$'));
91

    
92
    if (expected.test(type)) {
93
      return;
94
    }
95

    
96
    throw Error('Invalid node type: ' + type);
97
  }
98

    
99
  /*--------------------------------------------------------------------------*/
100

    
101
  function generate(node) {
102
    var type = node.type;
103

    
104
    if (generate.hasOwnProperty(type) && typeof generate[type] == 'function') {
105
      return generate[type](node);
106
    }
107

    
108
    throw Error('Invalid node type: ' + type);
109
  }
110

    
111
  /*--------------------------------------------------------------------------*/
112

    
113
  function generateAlternative(node) {
114
    assertType(node.type, 'alternative');
115

    
116
    var terms = node.body,
117
        length = terms ? terms.length : 0;
118

    
119
    if (length == 1) {
120
      return generateTerm(terms[0]);
121
    } else {
122
      var i = -1,
123
          result = '';
124

    
125
      while (++i < length) {
126
        result += generateTerm(terms[i]);
127
      }
128

    
129
      return result;
130
    }
131
  }
132

    
133
  function generateAnchor(node) {
134
    assertType(node.type, 'anchor');
135

    
136
    switch (node.kind) {
137
      case 'start':
138
        return '^';
139
      case 'end':
140
        return '$';
141
      case 'boundary':
142
        return '\\b';
143
      case 'not-boundary':
144
        return '\\B';
145
      default:
146
        throw Error('Invalid assertion');
147
    }
148
  }
149

    
150
  function generateAtom(node) {
151
    assertType(node.type, 'anchor|characterClass|characterClassEscape|dot|group|reference|value');
152

    
153
    return generate(node);
154
  }
155

    
156
  function generateCharacterClass(node) {
157
    assertType(node.type, 'characterClass');
158

    
159
    var classRanges = node.body,
160
        length = classRanges ? classRanges.length : 0;
161

    
162
    var i = -1,
163
        result = '[';
164

    
165
    if (node.negative) {
166
      result += '^';
167
    }
168

    
169
    while (++i < length) {
170
      result += generateClassAtom(classRanges[i]);
171
    }
172

    
173
    result += ']';
174

    
175
    return result;
176
  }
177

    
178
  function generateCharacterClassEscape(node) {
179
    assertType(node.type, 'characterClassEscape');
180

    
181
    return '\\' + node.value;
182
  }
183

    
184
  function generateCharacterClassRange(node) {
185
    assertType(node.type, 'characterClassRange');
186

    
187
    var min = node.min,
188
        max = node.max;
189

    
190
    if (min.type == 'characterClassRange' || max.type == 'characterClassRange') {
191
      throw Error('Invalid character class range');
192
    }
193

    
194
    return generateClassAtom(min) + '-' + generateClassAtom(max);
195
  }
196

    
197
  function generateClassAtom(node) {
198
    assertType(node.type, 'anchor|characterClassEscape|characterClassRange|dot|value');
199

    
200
    return generate(node);
201
  }
202

    
203
  function generateDisjunction(node) {
204
    assertType(node.type, 'disjunction');
205

    
206
    var body = node.body,
207
        length = body ? body.length : 0;
208

    
209
    if (length == 0) {
210
      throw Error('No body');
211
    } else if (length == 1) {
212
      return generate(body[0]);
213
    } else {
214
      var i = -1,
215
          result = '';
216

    
217
      while (++i < length) {
218
        if (i != 0) {
219
          result += '|';
220
        }
221
        result += generate(body[i]);
222
      }
223

    
224
      return result;
225
    }
226
  }
227

    
228
  function generateDot(node) {
229
    assertType(node.type, 'dot');
230

    
231
    return '.';
232
  }
233

    
234
  function generateGroup(node) {
235
    assertType(node.type, 'group');
236

    
237
    var result = '(';
238

    
239
    switch (node.behavior) {
240
      case 'normal':
241
        break;
242
      case 'ignore':
243
        result += '?:';
244
        break;
245
      case 'lookahead':
246
        result += '?=';
247
        break;
248
      case 'negativeLookahead':
249
        result += '?!';
250
        break;
251
      default:
252
        throw Error('Invalid behaviour: ' + node.behaviour);
253
    }
254

    
255
    var body = node.body,
256
        length = body ? body.length : 0;
257

    
258
    if (length == 1) {
259
      result += generate(body[0]);
260
    } else {
261
      var i = -1;
262

    
263
      while (++i < length) {
264
        result += generate(body[i]);
265
      }
266
    }
267

    
268
    result += ')';
269

    
270
    return result;
271
  }
272

    
273
  function generateQuantifier(node) {
274
    assertType(node.type, 'quantifier');
275

    
276
    var quantifier = '',
277
        min = node.min,
278
        max = node.max;
279

    
280
    switch (max) {
281
      case undefined:
282
      case null:
283
        switch (min) {
284
          case 0:
285
            quantifier = '*'
286
            break;
287
          case 1:
288
            quantifier = '+';
289
            break;
290
          default:
291
            quantifier = '{' + min + ',}';
292
            break;
293
        }
294
        break;
295
      default:
296
        if (min == max) {
297
          quantifier = '{' + min + '}';
298
        }
299
        else if (min == 0 && max == 1) {
300
          quantifier = '?';
301
        } else {
302
          quantifier = '{' + min + ',' + max + '}';
303
        }
304
        break;
305
    }
306

    
307
    if (!node.greedy) {
308
      quantifier += '?';
309
    }
310

    
311
    return generateAtom(node.body[0]) + quantifier;
312
  }
313

    
314
  function generateReference(node) {
315
    assertType(node.type, 'reference');
316

    
317
    return '\\' + node.matchIndex;
318
  }
319

    
320
  function generateTerm(node) {
321
    assertType(node.type, 'anchor|characterClass|characterClassEscape|empty|group|quantifier|reference|value');
322

    
323
    return generate(node);
324
  }
325

    
326
  function generateValue(node) {
327
    assertType(node.type, 'value');
328

    
329
    var kind = node.kind,
330
        codePoint = node.codePoint;
331

    
332
    switch (kind) {
333
      case 'controlLetter':
334
        return '\\c' + fromCodePoint(codePoint + 64);
335
      case 'hexadecimalEscape':
336
        return '\\x' + ('00' + codePoint.toString(16).toUpperCase()).slice(-2);
337
      case 'identifier':
338
        return '\\' + fromCodePoint(codePoint);
339
      case 'null':
340
        return '\\' + codePoint;
341
      case 'octal':
342
        return '\\' + codePoint.toString(8);
343
      case 'singleEscape':
344
        switch (codePoint) {
345
          case 0x0008:
346
            return '\\b';
347
          case 0x009:
348
            return '\\t';
349
          case 0x00A:
350
            return '\\n';
351
          case 0x00B:
352
            return '\\v';
353
          case 0x00C:
354
            return '\\f';
355
          case 0x00D:
356
            return '\\r';
357
          default:
358
            throw Error('Invalid codepoint: ' + codePoint);
359
        }
360
      case 'symbol':
361
        return fromCodePoint(codePoint);
362
      case 'unicodeEscape':
363
        return '\\u' + ('0000' + codePoint.toString(16).toUpperCase()).slice(-4);
364
      case 'unicodeCodePointEscape':
365
        return '\\u{' + codePoint.toString(16).toUpperCase() + '}';
366
      default:
367
        throw Error('Unsupported node kind: ' + kind);
368
    }
369
  }
370

    
371
  /*--------------------------------------------------------------------------*/
372

    
373
  generate.alternative = generateAlternative;
374
  generate.anchor = generateAnchor;
375
  generate.characterClass = generateCharacterClass;
376
  generate.characterClassEscape = generateCharacterClassEscape;
377
  generate.characterClassRange = generateCharacterClassRange;
378
  generate.disjunction = generateDisjunction;
379
  generate.dot = generateDot;
380
  generate.group = generateGroup;
381
  generate.quantifier = generateQuantifier;
382
  generate.reference = generateReference;
383
  generate.value = generateValue;
384

    
385
  /*--------------------------------------------------------------------------*/
386

    
387
  // export regjsgen
388
  // some AMD build optimizers, like r.js, check for condition patterns like the following:
389
  if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
390
    // define as an anonymous module so, through path mapping, it can be aliased
391
    define(function() {
392
      return {
393
        'generate': generate
394
      };
395
    });
396
  }
397
  // check for `exports` after `define` in case a build optimizer adds an `exports` object
398
  else if (freeExports && freeModule) {
399
    // in Narwhal, Node.js, Rhino -require, or RingoJS
400
    freeExports.generate = generate;
401
  }
402
  // in a browser or Rhino
403
  else {
404
    root.regjsgen = {
405
      'generate': generate
406
    };
407
  }
408
}.call(this));
(3-3/3)