UNPKG

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