Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
81146 views
1
// Generated by CoffeeScript 1.6.3
2
(function() {
3
var BOM, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HEREDOC, HEREDOC_ILLEGAL, HEREDOC_INDENT, HEREGEX, HEREGEX_OMIT, IDENTIFIER, INDEXABLE, INVERSES, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LINE_BREAK, LINE_CONTINUER, LOGIC, Lexer, MATH, MULTILINER, MULTI_DENT, NOT_REGEX, NOT_SPACED_REGEX, NUMBER, OPERATOR, REGEX, RELATION, RESERVED, Rewriter, SHIFT, SIMPLESTR, STRICT_PROSCRIBED, TRAILING_SPACES, UNARY, WHITESPACE, compact, count, invertLiterate, key, last, locationDataToString, repeat, starts, throwSyntaxError, _ref, _ref1,
4
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
5
6
_ref = require('./rewriter'), Rewriter = _ref.Rewriter, INVERSES = _ref.INVERSES;
7
8
_ref1 = require('./helpers'), count = _ref1.count, starts = _ref1.starts, compact = _ref1.compact, last = _ref1.last, repeat = _ref1.repeat, invertLiterate = _ref1.invertLiterate, locationDataToString = _ref1.locationDataToString, throwSyntaxError = _ref1.throwSyntaxError;
9
10
exports.Lexer = Lexer = (function() {
11
function Lexer() {}
12
13
Lexer.prototype.tokenize = function(code, opts) {
14
var consumed, i, tag, _ref2;
15
if (opts == null) {
16
opts = {};
17
}
18
this.literate = opts.literate;
19
this.indent = 0;
20
this.indebt = 0;
21
this.outdebt = 0;
22
this.indents = [];
23
this.ends = [];
24
this.tokens = [];
25
this.chunkLine = opts.line || 0;
26
this.chunkColumn = opts.column || 0;
27
code = this.clean(code);
28
i = 0;
29
while (this.chunk = code.slice(i)) {
30
consumed = this.identifierToken() || this.commentToken() || this.whitespaceToken() || this.lineToken() || this.heredocToken() || this.stringToken() || this.numberToken() || this.regexToken() || this.jsToken() || this.literalToken();
31
_ref2 = this.getLineAndColumnFromChunk(consumed), this.chunkLine = _ref2[0], this.chunkColumn = _ref2[1];
32
i += consumed;
33
}
34
this.closeIndentation();
35
if (tag = this.ends.pop()) {
36
this.error("missing " + tag);
37
}
38
if (opts.rewrite === false) {
39
return this.tokens;
40
}
41
return (new Rewriter).rewrite(this.tokens);
42
};
43
44
Lexer.prototype.clean = function(code) {
45
if (code.charCodeAt(0) === BOM) {
46
code = code.slice(1);
47
}
48
code = code.replace(/\r/g, '').replace(TRAILING_SPACES, '');
49
if (WHITESPACE.test(code)) {
50
code = "\n" + code;
51
this.chunkLine--;
52
}
53
if (this.literate) {
54
code = invertLiterate(code);
55
}
56
return code;
57
};
58
59
Lexer.prototype.identifierToken = function() {
60
var colon, colonOffset, forcedIdentifier, id, idLength, input, match, poppedToken, prev, tag, tagToken, _ref2, _ref3, _ref4;
61
if (!(match = IDENTIFIER.exec(this.chunk))) {
62
return 0;
63
}
64
input = match[0], id = match[1], colon = match[2];
65
idLength = id.length;
66
poppedToken = void 0;
67
if (id === 'own' && this.tag() === 'FOR') {
68
this.token('OWN', id);
69
return id.length;
70
}
71
forcedIdentifier = colon || (prev = last(this.tokens)) && (((_ref2 = prev[0]) === '.' || _ref2 === '?.' || _ref2 === '::' || _ref2 === '?::') || !prev.spaced && prev[0] === '@');
72
tag = 'IDENTIFIER';
73
if (!forcedIdentifier && (__indexOf.call(JS_KEYWORDS, id) >= 0 || __indexOf.call(COFFEE_KEYWORDS, id) >= 0)) {
74
tag = id.toUpperCase();
75
if (tag === 'WHEN' && (_ref3 = this.tag(), __indexOf.call(LINE_BREAK, _ref3) >= 0)) {
76
tag = 'LEADING_WHEN';
77
} else if (tag === 'FOR') {
78
this.seenFor = true;
79
} else if (tag === 'UNLESS') {
80
tag = 'IF';
81
} else if (__indexOf.call(UNARY, tag) >= 0) {
82
tag = 'UNARY';
83
} else if (__indexOf.call(RELATION, tag) >= 0) {
84
if (tag !== 'INSTANCEOF' && this.seenFor) {
85
tag = 'FOR' + tag;
86
this.seenFor = false;
87
} else {
88
tag = 'RELATION';
89
if (this.value() === '!') {
90
poppedToken = this.tokens.pop();
91
id = '!' + id;
92
}
93
}
94
}
95
}
96
if (__indexOf.call(JS_FORBIDDEN, id) >= 0) {
97
if (forcedIdentifier) {
98
tag = 'IDENTIFIER';
99
id = new String(id);
100
id.reserved = true;
101
} else if (__indexOf.call(RESERVED, id) >= 0) {
102
this.error("reserved word \"" + id + "\"");
103
}
104
}
105
if (!forcedIdentifier) {
106
if (__indexOf.call(COFFEE_ALIASES, id) >= 0) {
107
id = COFFEE_ALIAS_MAP[id];
108
}
109
tag = (function() {
110
switch (id) {
111
case '!':
112
return 'UNARY';
113
case '==':
114
case '!=':
115
return 'COMPARE';
116
case '&&':
117
case '||':
118
return 'LOGIC';
119
case 'true':
120
case 'false':
121
return 'BOOL';
122
case 'break':
123
case 'continue':
124
return 'STATEMENT';
125
default:
126
return tag;
127
}
128
})();
129
}
130
tagToken = this.token(tag, id, 0, idLength);
131
if (poppedToken) {
132
_ref4 = [poppedToken[2].first_line, poppedToken[2].first_column], tagToken[2].first_line = _ref4[0], tagToken[2].first_column = _ref4[1];
133
}
134
if (colon) {
135
colonOffset = input.lastIndexOf(':');
136
this.token(':', ':', colonOffset, colon.length);
137
}
138
return input.length;
139
};
140
141
Lexer.prototype.numberToken = function() {
142
var binaryLiteral, lexedLength, match, number, octalLiteral;
143
if (!(match = NUMBER.exec(this.chunk))) {
144
return 0;
145
}
146
number = match[0];
147
if (/^0[BOX]/.test(number)) {
148
this.error("radix prefix '" + number + "' must be lowercase");
149
} else if (/E/.test(number) && !/^0x/.test(number)) {
150
this.error("exponential notation '" + number + "' must be indicated with a lowercase 'e'");
151
} else if (/^0\d*[89]/.test(number)) {
152
this.error("decimal literal '" + number + "' must not be prefixed with '0'");
153
} else if (/^0\d+/.test(number)) {
154
this.error("octal literal '" + number + "' must be prefixed with '0o'");
155
}
156
lexedLength = number.length;
157
if (octalLiteral = /^0o([0-7]+)/.exec(number)) {
158
number = '0x' + parseInt(octalLiteral[1], 8).toString(16);
159
}
160
if (binaryLiteral = /^0b([01]+)/.exec(number)) {
161
number = '0x' + parseInt(binaryLiteral[1], 2).toString(16);
162
}
163
this.token('NUMBER', number, 0, lexedLength);
164
return lexedLength;
165
};
166
167
Lexer.prototype.stringToken = function() {
168
var match, octalEsc, string;
169
switch (this.chunk.charAt(0)) {
170
case "'":
171
if (!(match = SIMPLESTR.exec(this.chunk))) {
172
return 0;
173
}
174
string = match[0];
175
this.token('STRING', string.replace(MULTILINER, '\\\n'), 0, string.length);
176
break;
177
case '"':
178
if (!(string = this.balancedString(this.chunk, '"'))) {
179
return 0;
180
}
181
if (0 < string.indexOf('#{', 1)) {
182
this.interpolateString(string.slice(1, -1), {
183
strOffset: 1,
184
lexedLength: string.length
185
});
186
} else {
187
this.token('STRING', this.escapeLines(string, 0, string.length));
188
}
189
break;
190
default:
191
return 0;
192
}
193
if (octalEsc = /^(?:\\.|[^\\])*\\(?:0[0-7]|[1-7])/.test(string)) {
194
this.error("octal escape sequences " + string + " are not allowed");
195
}
196
return string.length;
197
};
198
199
Lexer.prototype.heredocToken = function() {
200
var doc, heredoc, match, quote;
201
if (!(match = HEREDOC.exec(this.chunk))) {
202
return 0;
203
}
204
heredoc = match[0];
205
quote = heredoc.charAt(0);
206
doc = this.sanitizeHeredoc(match[2], {
207
quote: quote,
208
indent: null
209
});
210
if (quote === '"' && 0 <= doc.indexOf('#{')) {
211
this.interpolateString(doc, {
212
heredoc: true,
213
strOffset: 3,
214
lexedLength: heredoc.length
215
});
216
} else {
217
this.token('STRING', this.makeString(doc, quote, true), 0, heredoc.length);
218
}
219
return heredoc.length;
220
};
221
222
Lexer.prototype.commentToken = function() {
223
var comment, here, match;
224
if (!(match = this.chunk.match(COMMENT))) {
225
return 0;
226
}
227
comment = match[0], here = match[1];
228
if (here) {
229
this.token('HERECOMMENT', this.sanitizeHeredoc(here, {
230
herecomment: true,
231
indent: repeat(' ', this.indent)
232
}), 0, comment.length);
233
}
234
return comment.length;
235
};
236
237
Lexer.prototype.jsToken = function() {
238
var match, script;
239
if (!(this.chunk.charAt(0) === '`' && (match = JSTOKEN.exec(this.chunk)))) {
240
return 0;
241
}
242
this.token('JS', (script = match[0]).slice(1, -1), 0, script.length);
243
return script.length;
244
};
245
246
Lexer.prototype.regexToken = function() {
247
var flags, length, match, prev, regex, _ref2, _ref3;
248
if (this.chunk.charAt(0) !== '/') {
249
return 0;
250
}
251
if (match = HEREGEX.exec(this.chunk)) {
252
length = this.heregexToken(match);
253
return length;
254
}
255
prev = last(this.tokens);
256
if (prev && (_ref2 = prev[0], __indexOf.call((prev.spaced ? NOT_REGEX : NOT_SPACED_REGEX), _ref2) >= 0)) {
257
return 0;
258
}
259
if (!(match = REGEX.exec(this.chunk))) {
260
return 0;
261
}
262
_ref3 = match, match = _ref3[0], regex = _ref3[1], flags = _ref3[2];
263
if (regex.slice(0, 2) === '/*') {
264
this.error('regular expressions cannot begin with `*`');
265
}
266
if (regex === '//') {
267
regex = '/(?:)/';
268
}
269
this.token('REGEX', "" + regex + flags, 0, match.length);
270
return match.length;
271
};
272
273
Lexer.prototype.heregexToken = function(match) {
274
var body, flags, flagsOffset, heregex, plusToken, prev, re, tag, token, tokens, value, _i, _len, _ref2, _ref3, _ref4;
275
heregex = match[0], body = match[1], flags = match[2];
276
if (0 > body.indexOf('#{')) {
277
re = body.replace(HEREGEX_OMIT, '').replace(/\//g, '\\/');
278
if (re.match(/^\*/)) {
279
this.error('regular expressions cannot begin with `*`');
280
}
281
this.token('REGEX', "/" + (re || '(?:)') + "/" + flags, 0, heregex.length);
282
return heregex.length;
283
}
284
this.token('IDENTIFIER', 'RegExp', 0, 0);
285
this.token('CALL_START', '(', 0, 0);
286
tokens = [];
287
_ref2 = this.interpolateString(body, {
288
regex: true
289
});
290
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
291
token = _ref2[_i];
292
tag = token[0], value = token[1];
293
if (tag === 'TOKENS') {
294
tokens.push.apply(tokens, value);
295
} else if (tag === 'NEOSTRING') {
296
if (!(value = value.replace(HEREGEX_OMIT, ''))) {
297
continue;
298
}
299
value = value.replace(/\\/g, '\\\\');
300
token[0] = 'STRING';
301
token[1] = this.makeString(value, '"', true);
302
tokens.push(token);
303
} else {
304
this.error("Unexpected " + tag);
305
}
306
prev = last(this.tokens);
307
plusToken = ['+', '+'];
308
plusToken[2] = prev[2];
309
tokens.push(plusToken);
310
}
311
tokens.pop();
312
if (((_ref3 = tokens[0]) != null ? _ref3[0] : void 0) !== 'STRING') {
313
this.token('STRING', '""', 0, 0);
314
this.token('+', '+', 0, 0);
315
}
316
(_ref4 = this.tokens).push.apply(_ref4, tokens);
317
if (flags) {
318
flagsOffset = heregex.lastIndexOf(flags);
319
this.token(',', ',', flagsOffset, 0);
320
this.token('STRING', '"' + flags + '"', flagsOffset, flags.length);
321
}
322
this.token(')', ')', heregex.length - 1, 0);
323
return heregex.length;
324
};
325
326
Lexer.prototype.lineToken = function() {
327
var diff, indent, match, noNewlines, size;
328
if (!(match = MULTI_DENT.exec(this.chunk))) {
329
return 0;
330
}
331
indent = match[0];
332
this.seenFor = false;
333
size = indent.length - 1 - indent.lastIndexOf('\n');
334
noNewlines = this.unfinished();
335
if (size - this.indebt === this.indent) {
336
if (noNewlines) {
337
this.suppressNewlines();
338
} else {
339
this.newlineToken(0);
340
}
341
return indent.length;
342
}
343
if (size > this.indent) {
344
if (noNewlines) {
345
this.indebt = size - this.indent;
346
this.suppressNewlines();
347
return indent.length;
348
}
349
diff = size - this.indent + this.outdebt;
350
this.token('INDENT', diff, indent.length - size, size);
351
this.indents.push(diff);
352
this.ends.push('OUTDENT');
353
this.outdebt = this.indebt = 0;
354
} else {
355
this.indebt = 0;
356
this.outdentToken(this.indent - size, noNewlines, indent.length);
357
}
358
this.indent = size;
359
return indent.length;
360
};
361
362
Lexer.prototype.outdentToken = function(moveOut, noNewlines, outdentLength) {
363
var dent, len;
364
while (moveOut > 0) {
365
len = this.indents.length - 1;
366
if (this.indents[len] === void 0) {
367
moveOut = 0;
368
} else if (this.indents[len] === this.outdebt) {
369
moveOut -= this.outdebt;
370
this.outdebt = 0;
371
} else if (this.indents[len] < this.outdebt) {
372
this.outdebt -= this.indents[len];
373
moveOut -= this.indents[len];
374
} else {
375
dent = this.indents.pop() + this.outdebt;
376
moveOut -= dent;
377
this.outdebt = 0;
378
this.pair('OUTDENT');
379
this.token('OUTDENT', dent, 0, outdentLength);
380
}
381
}
382
if (dent) {
383
this.outdebt -= moveOut;
384
}
385
while (this.value() === ';') {
386
this.tokens.pop();
387
}
388
if (!(this.tag() === 'TERMINATOR' || noNewlines)) {
389
this.token('TERMINATOR', '\n', outdentLength, 0);
390
}
391
return this;
392
};
393
394
Lexer.prototype.whitespaceToken = function() {
395
var match, nline, prev;
396
if (!((match = WHITESPACE.exec(this.chunk)) || (nline = this.chunk.charAt(0) === '\n'))) {
397
return 0;
398
}
399
prev = last(this.tokens);
400
if (prev) {
401
prev[match ? 'spaced' : 'newLine'] = true;
402
}
403
if (match) {
404
return match[0].length;
405
} else {
406
return 0;
407
}
408
};
409
410
Lexer.prototype.newlineToken = function(offset) {
411
while (this.value() === ';') {
412
this.tokens.pop();
413
}
414
if (this.tag() !== 'TERMINATOR') {
415
this.token('TERMINATOR', '\n', offset, 0);
416
}
417
return this;
418
};
419
420
Lexer.prototype.suppressNewlines = function() {
421
if (this.value() === '\\') {
422
this.tokens.pop();
423
}
424
return this;
425
};
426
427
Lexer.prototype.literalToken = function() {
428
var match, prev, tag, value, _ref2, _ref3, _ref4, _ref5;
429
if (match = OPERATOR.exec(this.chunk)) {
430
value = match[0];
431
if (CODE.test(value)) {
432
this.tagParameters();
433
}
434
} else {
435
value = this.chunk.charAt(0);
436
}
437
tag = value;
438
prev = last(this.tokens);
439
if (value === '=' && prev) {
440
if (!prev[1].reserved && (_ref2 = prev[1], __indexOf.call(JS_FORBIDDEN, _ref2) >= 0)) {
441
this.error("reserved word \"" + (this.value()) + "\" can't be assigned");
442
}
443
if ((_ref3 = prev[1]) === '||' || _ref3 === '&&') {
444
prev[0] = 'COMPOUND_ASSIGN';
445
prev[1] += '=';
446
return value.length;
447
}
448
}
449
if (value === ';') {
450
this.seenFor = false;
451
tag = 'TERMINATOR';
452
} else if (__indexOf.call(MATH, value) >= 0) {
453
tag = 'MATH';
454
} else if (__indexOf.call(COMPARE, value) >= 0) {
455
tag = 'COMPARE';
456
} else if (__indexOf.call(COMPOUND_ASSIGN, value) >= 0) {
457
tag = 'COMPOUND_ASSIGN';
458
} else if (__indexOf.call(UNARY, value) >= 0) {
459
tag = 'UNARY';
460
} else if (__indexOf.call(SHIFT, value) >= 0) {
461
tag = 'SHIFT';
462
} else if (__indexOf.call(LOGIC, value) >= 0 || value === '?' && (prev != null ? prev.spaced : void 0)) {
463
tag = 'LOGIC';
464
} else if (prev && !prev.spaced) {
465
if (value === '(' && (_ref4 = prev[0], __indexOf.call(CALLABLE, _ref4) >= 0)) {
466
if (prev[0] === '?') {
467
prev[0] = 'FUNC_EXIST';
468
}
469
tag = 'CALL_START';
470
} else if (value === '[' && (_ref5 = prev[0], __indexOf.call(INDEXABLE, _ref5) >= 0)) {
471
tag = 'INDEX_START';
472
switch (prev[0]) {
473
case '?':
474
prev[0] = 'INDEX_SOAK';
475
}
476
}
477
}
478
switch (value) {
479
case '(':
480
case '{':
481
case '[':
482
this.ends.push(INVERSES[value]);
483
break;
484
case ')':
485
case '}':
486
case ']':
487
this.pair(value);
488
}
489
this.token(tag, value);
490
return value.length;
491
};
492
493
Lexer.prototype.sanitizeHeredoc = function(doc, options) {
494
var attempt, herecomment, indent, match, _ref2;
495
indent = options.indent, herecomment = options.herecomment;
496
if (herecomment) {
497
if (HEREDOC_ILLEGAL.test(doc)) {
498
this.error("block comment cannot contain \"*/\", starting");
499
}
500
if (doc.indexOf('\n') < 0) {
501
return doc;
502
}
503
} else {
504
while (match = HEREDOC_INDENT.exec(doc)) {
505
attempt = match[1];
506
if (indent === null || (0 < (_ref2 = attempt.length) && _ref2 < indent.length)) {
507
indent = attempt;
508
}
509
}
510
}
511
if (indent) {
512
doc = doc.replace(RegExp("\\n" + indent, "g"), '\n');
513
}
514
if (!herecomment) {
515
doc = doc.replace(/^\n/, '');
516
}
517
return doc;
518
};
519
520
Lexer.prototype.tagParameters = function() {
521
var i, stack, tok, tokens;
522
if (this.tag() !== ')') {
523
return this;
524
}
525
stack = [];
526
tokens = this.tokens;
527
i = tokens.length;
528
tokens[--i][0] = 'PARAM_END';
529
while (tok = tokens[--i]) {
530
switch (tok[0]) {
531
case ')':
532
stack.push(tok);
533
break;
534
case '(':
535
case 'CALL_START':
536
if (stack.length) {
537
stack.pop();
538
} else if (tok[0] === '(') {
539
tok[0] = 'PARAM_START';
540
return this;
541
} else {
542
return this;
543
}
544
}
545
}
546
return this;
547
};
548
549
Lexer.prototype.closeIndentation = function() {
550
return this.outdentToken(this.indent);
551
};
552
553
Lexer.prototype.balancedString = function(str, end) {
554
var continueCount, i, letter, match, prev, stack, _i, _ref2;
555
continueCount = 0;
556
stack = [end];
557
for (i = _i = 1, _ref2 = str.length; 1 <= _ref2 ? _i < _ref2 : _i > _ref2; i = 1 <= _ref2 ? ++_i : --_i) {
558
if (continueCount) {
559
--continueCount;
560
continue;
561
}
562
switch (letter = str.charAt(i)) {
563
case '\\':
564
++continueCount;
565
continue;
566
case end:
567
stack.pop();
568
if (!stack.length) {
569
return str.slice(0, +i + 1 || 9e9);
570
}
571
end = stack[stack.length - 1];
572
continue;
573
}
574
if (end === '}' && (letter === '"' || letter === "'")) {
575
stack.push(end = letter);
576
} else if (end === '}' && letter === '/' && (match = HEREGEX.exec(str.slice(i)) || REGEX.exec(str.slice(i)))) {
577
continueCount += match[0].length - 1;
578
} else if (end === '}' && letter === '{') {
579
stack.push(end = '}');
580
} else if (end === '"' && prev === '#' && letter === '{') {
581
stack.push(end = '}');
582
}
583
prev = letter;
584
}
585
return this.error("missing " + (stack.pop()) + ", starting");
586
};
587
588
Lexer.prototype.interpolateString = function(str, options) {
589
var column, expr, heredoc, i, inner, interpolated, len, letter, lexedLength, line, locationToken, nested, offsetInChunk, pi, plusToken, popped, regex, rparen, strOffset, tag, token, tokens, value, _i, _len, _ref2, _ref3, _ref4;
590
if (options == null) {
591
options = {};
592
}
593
heredoc = options.heredoc, regex = options.regex, offsetInChunk = options.offsetInChunk, strOffset = options.strOffset, lexedLength = options.lexedLength;
594
offsetInChunk = offsetInChunk || 0;
595
strOffset = strOffset || 0;
596
lexedLength = lexedLength || str.length;
597
if (heredoc && str.length > 0 && str[0] === '\n') {
598
str = str.slice(1);
599
strOffset++;
600
}
601
tokens = [];
602
pi = 0;
603
i = -1;
604
while (letter = str.charAt(i += 1)) {
605
if (letter === '\\') {
606
i += 1;
607
continue;
608
}
609
if (!(letter === '#' && str.charAt(i + 1) === '{' && (expr = this.balancedString(str.slice(i + 1), '}')))) {
610
continue;
611
}
612
if (pi < i) {
613
tokens.push(this.makeToken('NEOSTRING', str.slice(pi, i), strOffset + pi));
614
}
615
inner = expr.slice(1, -1);
616
if (inner.length) {
617
_ref2 = this.getLineAndColumnFromChunk(strOffset + i + 1), line = _ref2[0], column = _ref2[1];
618
nested = new Lexer().tokenize(inner, {
619
line: line,
620
column: column,
621
rewrite: false
622
});
623
popped = nested.pop();
624
if (((_ref3 = nested[0]) != null ? _ref3[0] : void 0) === 'TERMINATOR') {
625
popped = nested.shift();
626
}
627
if (len = nested.length) {
628
if (len > 1) {
629
nested.unshift(this.makeToken('(', '(', strOffset + i + 1, 0));
630
nested.push(this.makeToken(')', ')', strOffset + i + 1 + inner.length, 0));
631
}
632
tokens.push(['TOKENS', nested]);
633
}
634
}
635
i += expr.length;
636
pi = i + 1;
637
}
638
if ((i > pi && pi < str.length)) {
639
tokens.push(this.makeToken('NEOSTRING', str.slice(pi), strOffset + pi));
640
}
641
if (regex) {
642
return tokens;
643
}
644
if (!tokens.length) {
645
return this.token('STRING', '""', offsetInChunk, lexedLength);
646
}
647
if (tokens[0][0] !== 'NEOSTRING') {
648
tokens.unshift(this.makeToken('NEOSTRING', '', offsetInChunk));
649
}
650
if (interpolated = tokens.length > 1) {
651
this.token('(', '(', offsetInChunk, 0);
652
}
653
for (i = _i = 0, _len = tokens.length; _i < _len; i = ++_i) {
654
token = tokens[i];
655
tag = token[0], value = token[1];
656
if (i) {
657
if (i) {
658
plusToken = this.token('+', '+');
659
}
660
locationToken = tag === 'TOKENS' ? value[0] : token;
661
plusToken[2] = {
662
first_line: locationToken[2].first_line,
663
first_column: locationToken[2].first_column,
664
last_line: locationToken[2].first_line,
665
last_column: locationToken[2].first_column
666
};
667
}
668
if (tag === 'TOKENS') {
669
(_ref4 = this.tokens).push.apply(_ref4, value);
670
} else if (tag === 'NEOSTRING') {
671
token[0] = 'STRING';
672
token[1] = this.makeString(value, '"', heredoc);
673
this.tokens.push(token);
674
} else {
675
this.error("Unexpected " + tag);
676
}
677
}
678
if (interpolated) {
679
rparen = this.makeToken(')', ')', offsetInChunk + lexedLength, 0);
680
rparen.stringEnd = true;
681
this.tokens.push(rparen);
682
}
683
return tokens;
684
};
685
686
Lexer.prototype.pair = function(tag) {
687
var size, wanted;
688
if (tag !== (wanted = last(this.ends))) {
689
if ('OUTDENT' !== wanted) {
690
this.error("unmatched " + tag);
691
}
692
this.indent -= size = last(this.indents);
693
this.outdentToken(size, true);
694
return this.pair(tag);
695
}
696
return this.ends.pop();
697
};
698
699
Lexer.prototype.getLineAndColumnFromChunk = function(offset) {
700
var column, lineCount, lines, string;
701
if (offset === 0) {
702
return [this.chunkLine, this.chunkColumn];
703
}
704
if (offset >= this.chunk.length) {
705
string = this.chunk;
706
} else {
707
string = this.chunk.slice(0, +(offset - 1) + 1 || 9e9);
708
}
709
lineCount = count(string, '\n');
710
column = this.chunkColumn;
711
if (lineCount > 0) {
712
lines = string.split('\n');
713
column = last(lines).length;
714
} else {
715
column += string.length;
716
}
717
return [this.chunkLine + lineCount, column];
718
};
719
720
Lexer.prototype.makeToken = function(tag, value, offsetInChunk, length) {
721
var lastCharacter, locationData, token, _ref2, _ref3;
722
if (offsetInChunk == null) {
723
offsetInChunk = 0;
724
}
725
if (length == null) {
726
length = value.length;
727
}
728
locationData = {};
729
_ref2 = this.getLineAndColumnFromChunk(offsetInChunk), locationData.first_line = _ref2[0], locationData.first_column = _ref2[1];
730
lastCharacter = Math.max(0, length - 1);
731
_ref3 = this.getLineAndColumnFromChunk(offsetInChunk + lastCharacter), locationData.last_line = _ref3[0], locationData.last_column = _ref3[1];
732
token = [tag, value, locationData];
733
return token;
734
};
735
736
Lexer.prototype.token = function(tag, value, offsetInChunk, length) {
737
var token;
738
token = this.makeToken(tag, value, offsetInChunk, length);
739
this.tokens.push(token);
740
return token;
741
};
742
743
Lexer.prototype.tag = function(index, tag) {
744
var tok;
745
return (tok = last(this.tokens, index)) && (tag ? tok[0] = tag : tok[0]);
746
};
747
748
Lexer.prototype.value = function(index, val) {
749
var tok;
750
return (tok = last(this.tokens, index)) && (val ? tok[1] = val : tok[1]);
751
};
752
753
Lexer.prototype.unfinished = function() {
754
var _ref2;
755
return LINE_CONTINUER.test(this.chunk) || ((_ref2 = this.tag()) === '\\' || _ref2 === '.' || _ref2 === '?.' || _ref2 === '?::' || _ref2 === 'UNARY' || _ref2 === 'MATH' || _ref2 === '+' || _ref2 === '-' || _ref2 === 'SHIFT' || _ref2 === 'RELATION' || _ref2 === 'COMPARE' || _ref2 === 'LOGIC' || _ref2 === 'THROW' || _ref2 === 'EXTENDS');
756
};
757
758
Lexer.prototype.escapeLines = function(str, heredoc) {
759
return str.replace(MULTILINER, heredoc ? '\\n' : '');
760
};
761
762
Lexer.prototype.makeString = function(body, quote, heredoc) {
763
if (!body) {
764
return quote + quote;
765
}
766
body = body.replace(/\\([\s\S])/g, function(match, contents) {
767
if (contents === '\n' || contents === quote) {
768
return contents;
769
} else {
770
return match;
771
}
772
});
773
body = body.replace(RegExp("" + quote, "g"), '\\$&');
774
return quote + this.escapeLines(body, heredoc) + quote;
775
};
776
777
Lexer.prototype.error = function(message) {
778
return throwSyntaxError(message, {
779
first_line: this.chunkLine,
780
first_column: this.chunkColumn
781
});
782
};
783
784
return Lexer;
785
786
})();
787
788
JS_KEYWORDS = ['true', 'false', 'null', 'this', 'new', 'delete', 'typeof', 'in', 'instanceof', 'return', 'throw', 'break', 'continue', 'debugger', 'if', 'else', 'switch', 'for', 'while', 'do', 'try', 'catch', 'finally', 'class', 'extends', 'super'];
789
790
COFFEE_KEYWORDS = ['undefined', 'then', 'unless', 'until', 'loop', 'of', 'by', 'when'];
791
792
COFFEE_ALIAS_MAP = {
793
and: '&&',
794
or: '||',
795
is: '==',
796
isnt: '!=',
797
not: '!',
798
yes: 'true',
799
no: 'false',
800
on: 'true',
801
off: 'false'
802
};
803
804
COFFEE_ALIASES = (function() {
805
var _results;
806
_results = [];
807
for (key in COFFEE_ALIAS_MAP) {
808
_results.push(key);
809
}
810
return _results;
811
})();
812
813
COFFEE_KEYWORDS = COFFEE_KEYWORDS.concat(COFFEE_ALIASES);
814
815
RESERVED = ['case', 'default', 'function', 'var', 'void', 'with', 'const', 'let', 'enum', 'export', 'import', 'native', '__hasProp', '__extends', '__slice', '__bind', '__indexOf', 'implements', 'interface', 'package', 'private', 'protected', 'public', 'static', 'yield'];
816
817
STRICT_PROSCRIBED = ['arguments', 'eval'];
818
819
JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED).concat(STRICT_PROSCRIBED);
820
821
exports.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS).concat(STRICT_PROSCRIBED);
822
823
exports.STRICT_PROSCRIBED = STRICT_PROSCRIBED;
824
825
BOM = 65279;
826
827
IDENTIFIER = /^([$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*)([^\n\S]*:(?!:))?/;
828
829
NUMBER = /^0b[01]+|^0o[0-7]+|^0x[\da-f]+|^\d*\.?\d+(?:e[+-]?\d+)?/i;
830
831
HEREDOC = /^("""|''')([\s\S]*?)(?:\n[^\n\S]*)?\1/;
832
833
OPERATOR = /^(?:[-=]>|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?(\.|::)|\.{2,3})/;
834
835
WHITESPACE = /^[^\n\S]+/;
836
837
COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)$)|^(?:\s*#(?!##[^#]).*)+/;
838
839
CODE = /^[-=]>/;
840
841
MULTI_DENT = /^(?:\n[^\n\S]*)+/;
842
843
SIMPLESTR = /^'[^\\']*(?:\\.[^\\']*)*'/;
844
845
JSTOKEN = /^`[^\\`]*(?:\\.[^\\`]*)*`/;
846
847
REGEX = /^(\/(?![\s=])[^[\/\n\\]*(?:(?:\\[\s\S]|\[[^\]\n\\]*(?:\\[\s\S][^\]\n\\]*)*])[^[\/\n\\]*)*\/)([imgy]{0,4})(?!\w)/;
848
849
HEREGEX = /^\/{3}([\s\S]+?)\/{3}([imgy]{0,4})(?!\w)/;
850
851
HEREGEX_OMIT = /\s+(?:#.*)?/g;
852
853
MULTILINER = /\n/g;
854
855
HEREDOC_INDENT = /\n+([^\n\S]*)/g;
856
857
HEREDOC_ILLEGAL = /\*\//;
858
859
LINE_CONTINUER = /^\s*(?:,|\??\.(?![.\d])|::)/;
860
861
TRAILING_SPACES = /\s+$/;
862
863
COMPOUND_ASSIGN = ['-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=', '<<=', '>>=', '>>>=', '&=', '^=', '|='];
864
865
UNARY = ['!', '~', 'NEW', 'TYPEOF', 'DELETE', 'DO'];
866
867
LOGIC = ['&&', '||', '&', '|', '^'];
868
869
SHIFT = ['<<', '>>', '>>>'];
870
871
COMPARE = ['==', '!=', '<', '>', '<=', '>='];
872
873
MATH = ['*', '/', '%'];
874
875
RELATION = ['IN', 'OF', 'INSTANCEOF'];
876
877
BOOL = ['TRUE', 'FALSE'];
878
879
NOT_REGEX = ['NUMBER', 'REGEX', 'BOOL', 'NULL', 'UNDEFINED', '++', '--'];
880
881
NOT_SPACED_REGEX = NOT_REGEX.concat(')', '}', 'THIS', 'IDENTIFIER', 'STRING', ']');
882
883
CALLABLE = ['IDENTIFIER', 'STRING', 'REGEX', ')', ']', '}', '?', '::', '@', 'THIS', 'SUPER'];
884
885
INDEXABLE = CALLABLE.concat('NUMBER', 'BOOL', 'NULL', 'UNDEFINED');
886
887
LINE_BREAK = ['INDENT', 'OUTDENT', 'TERMINATOR'];
888
889
}).call(this);
890
891