UNPKG

17.3 kBJavaScriptView Raw
1// Generated by CoffeeScript 1.6.0
2(function() {
3 var BALANCED_PAIRS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_BLOCK, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, IMPLICIT_UNSPACED_CALL, INVERSES, LINEBREAKS, SINGLE_CLOSERS, SINGLE_LINERS, generate, left, rite, _i, _len, _ref,
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 __slice = [].slice;
6
7 generate = function(tag, value) {
8 var tok;
9 tok = [tag, value];
10 tok.generated = true;
11 return tok;
12 };
13
14 exports.Rewriter = (function() {
15
16 function Rewriter() {}
17
18 Rewriter.prototype.rewrite = function(tokens) {
19 this.tokens = tokens;
20 this.removeLeadingNewlines();
21 this.removeMidExpressionNewlines();
22 this.closeOpenCalls();
23 this.closeOpenIndexes();
24 this.addImplicitIndentation();
25 this.tagPostfixConditionals();
26 this.addImplicitBracesAndParens();
27 this.addLocationDataToGeneratedTokens();
28 return this.tokens;
29 };
30
31 Rewriter.prototype.scanTokens = function(block) {
32 var i, token, tokens;
33 tokens = this.tokens;
34 i = 0;
35 while (token = tokens[i]) {
36 i += block.call(this, token, i, tokens);
37 }
38 return true;
39 };
40
41 Rewriter.prototype.detectEnd = function(i, condition, action) {
42 var levels, token, tokens, _ref, _ref1;
43 tokens = this.tokens;
44 levels = 0;
45 while (token = tokens[i]) {
46 if (levels === 0 && condition.call(this, token, i)) {
47 return action.call(this, token, i);
48 }
49 if (!token || levels < 0) {
50 return action.call(this, token, i - 1);
51 }
52 if (_ref = token[0], __indexOf.call(EXPRESSION_START, _ref) >= 0) {
53 levels += 1;
54 } else if (_ref1 = token[0], __indexOf.call(EXPRESSION_END, _ref1) >= 0) {
55 levels -= 1;
56 }
57 i += 1;
58 }
59 return i - 1;
60 };
61
62 Rewriter.prototype.removeLeadingNewlines = function() {
63 var i, tag, _i, _len, _ref;
64 _ref = this.tokens;
65 for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
66 tag = _ref[i][0];
67 if (tag !== 'TERMINATOR') {
68 break;
69 }
70 }
71 if (i) {
72 return this.tokens.splice(0, i);
73 }
74 };
75
76 Rewriter.prototype.removeMidExpressionNewlines = function() {
77 return this.scanTokens(function(token, i, tokens) {
78 var _ref;
79 if (!(token[0] === 'TERMINATOR' && (_ref = this.tag(i + 1), __indexOf.call(EXPRESSION_CLOSE, _ref) >= 0))) {
80 return 1;
81 }
82 tokens.splice(i, 1);
83 return 0;
84 });
85 };
86
87 Rewriter.prototype.closeOpenCalls = function() {
88 var action, condition;
89 condition = function(token, i) {
90 var _ref;
91 return ((_ref = token[0]) === ')' || _ref === 'CALL_END') || token[0] === 'OUTDENT' && this.tag(i - 1) === ')';
92 };
93 action = function(token, i) {
94 return this.tokens[token[0] === 'OUTDENT' ? i - 1 : i][0] = 'CALL_END';
95 };
96 return this.scanTokens(function(token, i) {
97 if (token[0] === 'CALL_START') {
98 this.detectEnd(i + 1, condition, action);
99 }
100 return 1;
101 });
102 };
103
104 Rewriter.prototype.closeOpenIndexes = function() {
105 var action, condition;
106 condition = function(token, i) {
107 var _ref;
108 return (_ref = token[0]) === ']' || _ref === 'INDEX_END';
109 };
110 action = function(token, i) {
111 return token[0] = 'INDEX_END';
112 };
113 return this.scanTokens(function(token, i) {
114 if (token[0] === 'INDEX_START') {
115 this.detectEnd(i + 1, condition, action);
116 }
117 return 1;
118 });
119 };
120
121 Rewriter.prototype.matchTags = function() {
122 var fuzz, i, j, pattern, _i, _ref, _ref1;
123 i = arguments[0], pattern = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
124 fuzz = 0;
125 for (j = _i = 0, _ref = pattern.length; 0 <= _ref ? _i < _ref : _i > _ref; j = 0 <= _ref ? ++_i : --_i) {
126 while (this.tag(i + j + fuzz) === 'HERECOMMENT') {
127 fuzz += 2;
128 }
129 if (pattern[j] == null) {
130 continue;
131 }
132 if (typeof pattern[j] === 'string') {
133 pattern[j] = [pattern[j]];
134 }
135 if (_ref1 = this.tag(i + j + fuzz), __indexOf.call(pattern[j], _ref1) < 0) {
136 return false;
137 }
138 }
139 return true;
140 };
141
142 Rewriter.prototype.looksObjectish = function(j) {
143 return this.matchTags(j, '@', null, ':') || this.matchTags(j, null, ':');
144 };
145
146 Rewriter.prototype.findTagsBackwards = function(i, tags) {
147 var backStack, _ref, _ref1, _ref2, _ref3, _ref4, _ref5;
148 backStack = [];
149 while (i >= 0 && (backStack.length || (_ref2 = this.tag(i), __indexOf.call(tags, _ref2) < 0) && ((_ref3 = this.tag(i), __indexOf.call(EXPRESSION_START, _ref3) < 0) || this.tokens[i].generated) && (_ref4 = this.tag(i), __indexOf.call(LINEBREAKS, _ref4) < 0))) {
150 if (_ref = this.tag(i), __indexOf.call(EXPRESSION_END, _ref) >= 0) {
151 backStack.push(this.tag(i));
152 }
153 if ((_ref1 = this.tag(i), __indexOf.call(EXPRESSION_START, _ref1) >= 0) && backStack.length) {
154 backStack.pop();
155 }
156 i -= 1;
157 }
158 return _ref5 = this.tag(i), __indexOf.call(tags, _ref5) >= 0;
159 };
160
161 Rewriter.prototype.addImplicitBracesAndParens = function() {
162 var stack;
163 stack = [];
164 return this.scanTokens(function(token, i, tokens) {
165 var endImplicitCall, endImplicitObject, forward, inImplicit, inImplicitCall, inImplicitControl, inImplicitObject, nextTag, offset, prevTag, s, sameLine, stackIdx, stackTag, stackTop, startIdx, startImplicitCall, startImplicitObject, startsLine, tag, _ref, _ref1, _ref2, _ref3, _ref4, _ref5;
166 tag = token[0];
167 prevTag = (i > 0 ? tokens[i - 1] : [])[0];
168 nextTag = (i < tokens.length - 1 ? tokens[i + 1] : [])[0];
169 stackTop = function() {
170 return stack[stack.length - 1];
171 };
172 startIdx = i;
173 forward = function(n) {
174 return i - startIdx + n;
175 };
176 inImplicit = function() {
177 var _ref, _ref1;
178 return (_ref = stackTop()) != null ? (_ref1 = _ref[2]) != null ? _ref1.ours : void 0 : void 0;
179 };
180 inImplicitCall = function() {
181 var _ref;
182 return inImplicit() && ((_ref = stackTop()) != null ? _ref[0] : void 0) === '(';
183 };
184 inImplicitObject = function() {
185 var _ref;
186 return inImplicit() && ((_ref = stackTop()) != null ? _ref[0] : void 0) === '{';
187 };
188 inImplicitControl = function() {
189 var _ref;
190 return inImplicit && ((_ref = stackTop()) != null ? _ref[0] : void 0) === 'CONTROL';
191 };
192 startImplicitCall = function(j) {
193 var idx;
194 idx = j != null ? j : i;
195 stack.push([
196 '(', idx, {
197 ours: true
198 }
199 ]);
200 tokens.splice(idx, 0, generate('CALL_START', '('));
201 if (j == null) {
202 return i += 1;
203 }
204 };
205 endImplicitCall = function() {
206 stack.pop();
207 tokens.splice(i, 0, generate('CALL_END', ')'));
208 return i += 1;
209 };
210 startImplicitObject = function(j, startsLine) {
211 var idx;
212 if (startsLine == null) {
213 startsLine = true;
214 }
215 idx = j != null ? j : i;
216 stack.push([
217 '{', idx, {
218 sameLine: true,
219 startsLine: startsLine,
220 ours: true
221 }
222 ]);
223 tokens.splice(idx, 0, generate('{', generate(new String('{'))));
224 if (j == null) {
225 return i += 1;
226 }
227 };
228 endImplicitObject = function(j) {
229 j = j != null ? j : i;
230 stack.pop();
231 tokens.splice(j, 0, generate('}', '}'));
232 return i += 1;
233 };
234 if (inImplicitCall() && (tag === 'IF' || tag === 'TRY' || tag === 'FINALLY' || tag === 'CATCH' || tag === 'CLASS' || tag === 'SWITCH')) {
235 stack.push([
236 'CONTROL', i, {
237 ours: true
238 }
239 ]);
240 return forward(1);
241 }
242 if (tag === 'INDENT' && inImplicit()) {
243 if (prevTag !== '=>' && prevTag !== '->' && prevTag !== '[' && prevTag !== '(' && prevTag !== ',' && prevTag !== '{' && prevTag !== 'TRY' && prevTag !== 'ELSE' && prevTag !== '=') {
244 while (inImplicitCall()) {
245 endImplicitCall();
246 }
247 }
248 if (inImplicitControl()) {
249 stack.pop();
250 }
251 stack.push([tag, i]);
252 return forward(1);
253 }
254 if (__indexOf.call(EXPRESSION_START, tag) >= 0) {
255 stack.push([tag, i]);
256 return forward(1);
257 }
258 if (__indexOf.call(EXPRESSION_END, tag) >= 0) {
259 while (inImplicit()) {
260 if (inImplicitCall()) {
261 endImplicitCall();
262 } else if (inImplicitObject()) {
263 endImplicitObject();
264 } else {
265 stack.pop();
266 }
267 }
268 stack.pop();
269 }
270 if ((__indexOf.call(IMPLICIT_FUNC, tag) >= 0 && token.spaced || tag === '?' && i > 0 && !tokens[i - 1].spaced) && (__indexOf.call(IMPLICIT_CALL, nextTag) >= 0 || __indexOf.call(IMPLICIT_UNSPACED_CALL, nextTag) >= 0 && !((_ref = tokens[i + 1]) != null ? _ref.spaced : void 0) && !((_ref1 = tokens[i + 1]) != null ? _ref1.newLine : void 0))) {
271 if (tag === '?') {
272 tag = token[0] = 'FUNC_EXIST';
273 }
274 startImplicitCall(i + 1);
275 return forward(2);
276 }
277 if (this.matchTags(i, IMPLICIT_FUNC, 'INDENT', null, ':') && !this.findTagsBackwards(i, ['CLASS', 'EXTENDS', 'IF', 'CATCH', 'SWITCH', 'LEADING_WHEN', 'FOR', 'WHILE', 'UNTIL'])) {
278 startImplicitCall(i + 1);
279 stack.push(['INDENT', i + 2]);
280 return forward(3);
281 }
282 if (tag === ':') {
283 if (this.tag(i - 2) === '@') {
284 s = i - 2;
285 } else {
286 s = i - 1;
287 }
288 while (this.tag(s - 2) === 'HERECOMMENT') {
289 s -= 2;
290 }
291 startsLine = s === 0 || (_ref2 = this.tag(s - 1), __indexOf.call(LINEBREAKS, _ref2) >= 0) || tokens[s - 1].newLine;
292 if (stackTop()) {
293 _ref3 = stackTop(), stackTag = _ref3[0], stackIdx = _ref3[1];
294 if ((stackTag === '{' || stackTag === 'INDENT' && this.tag(stackIdx - 1) === '{') && (startsLine || this.tag(s - 1) === ',' || this.tag(s - 1) === '{')) {
295 return forward(1);
296 }
297 }
298 startImplicitObject(s, !!startsLine);
299 return forward(2);
300 }
301 if (prevTag === 'OUTDENT' && inImplicitCall() && (tag === '.' || tag === '?.' || tag === '::' || tag === '?::')) {
302 endImplicitCall();
303 return forward(1);
304 }
305 if (inImplicitObject() && __indexOf.call(LINEBREAKS, tag) >= 0) {
306 stackTop()[2].sameLine = false;
307 }
308 if (__indexOf.call(IMPLICIT_END, tag) >= 0) {
309 while (inImplicit()) {
310 _ref4 = stackTop(), stackTag = _ref4[0], stackIdx = _ref4[1], (_ref5 = _ref4[2], sameLine = _ref5.sameLine, startsLine = _ref5.startsLine);
311 if (inImplicitCall() && prevTag !== ',') {
312 endImplicitCall();
313 } else if (inImplicitObject() && sameLine && !startsLine) {
314 endImplicitObject();
315 } else if (inImplicitObject() && tag === 'TERMINATOR' && prevTag !== ',' && !(startsLine && this.looksObjectish(i + 1))) {
316 endImplicitObject();
317 } else {
318 break;
319 }
320 }
321 }
322 if (tag === ',' && !this.looksObjectish(i + 1) && inImplicitObject() && (nextTag !== 'TERMINATOR' || !this.looksObjectish(i + 2))) {
323 offset = nextTag === 'OUTDENT' ? 1 : 0;
324 while (inImplicitObject()) {
325 endImplicitObject(i + offset);
326 }
327 }
328 return forward(1);
329 });
330 };
331
332 Rewriter.prototype.addLocationDataToGeneratedTokens = function() {
333 return this.scanTokens(function(token, i, tokens) {
334 var last_column, last_line, _ref, _ref1, _ref2;
335 if (token[2]) {
336 return 1;
337 }
338 if (!(token.generated || token.explicit)) {
339 return 1;
340 }
341 _ref2 = (_ref = (_ref1 = tokens[i - 1]) != null ? _ref1[2] : void 0) != null ? _ref : {
342 last_line: 0,
343 last_column: 0
344 }, last_line = _ref2.last_line, last_column = _ref2.last_column;
345 token[2] = {
346 first_line: last_line,
347 first_column: last_column,
348 last_line: last_line,
349 last_column: last_column
350 };
351 return 1;
352 });
353 };
354
355 Rewriter.prototype.addImplicitIndentation = function() {
356 var action, condition, indent, outdent, starter;
357 starter = indent = outdent = null;
358 condition = function(token, i) {
359 var _ref;
360 return token[1] !== ';' && (_ref = token[0], __indexOf.call(SINGLE_CLOSERS, _ref) >= 0) && !(token[0] === 'ELSE' && (starter !== 'IF' && starter !== 'THEN'));
361 };
362 action = function(token, i) {
363 return this.tokens.splice((this.tag(i - 1) === ',' ? i - 1 : i), 0, outdent);
364 };
365 return this.scanTokens(function(token, i, tokens) {
366 var tag, _ref, _ref1;
367 tag = token[0];
368 if (tag === 'TERMINATOR' && this.tag(i + 1) === 'THEN') {
369 tokens.splice(i, 1);
370 return 0;
371 }
372 if (tag === 'ELSE' && this.tag(i - 1) !== 'OUTDENT') {
373 tokens.splice.apply(tokens, [i, 0].concat(__slice.call(this.indentation(token))));
374 return 2;
375 }
376 if (tag === 'CATCH' && ((_ref = this.tag(i + 2)) === 'OUTDENT' || _ref === 'TERMINATOR' || _ref === 'FINALLY')) {
377 tokens.splice.apply(tokens, [i + 2, 0].concat(__slice.call(this.indentation(token))));
378 return 4;
379 }
380 if (__indexOf.call(SINGLE_LINERS, tag) >= 0 && this.tag(i + 1) !== 'INDENT' && !(tag === 'ELSE' && this.tag(i + 1) === 'IF')) {
381 starter = tag;
382 _ref1 = this.indentation(token, true), indent = _ref1[0], outdent = _ref1[1];
383 if (starter === 'THEN') {
384 indent.fromThen = true;
385 }
386 tokens.splice(i + 1, 0, indent);
387 this.detectEnd(i + 2, condition, action);
388 if (tag === 'THEN') {
389 tokens.splice(i, 1);
390 }
391 return 1;
392 }
393 return 1;
394 });
395 };
396
397 Rewriter.prototype.tagPostfixConditionals = function() {
398 var action, condition, original;
399 original = null;
400 condition = function(token, i) {
401 var _ref;
402 return (_ref = token[0]) === 'TERMINATOR' || _ref === 'INDENT';
403 };
404 action = function(token, i) {
405 if (token[0] !== 'INDENT' || (token.generated && !token.fromThen)) {
406 return original[0] = 'POST_' + original[0];
407 }
408 };
409 return this.scanTokens(function(token, i) {
410 if (token[0] !== 'IF') {
411 return 1;
412 }
413 original = token;
414 this.detectEnd(i + 1, condition, action);
415 return 1;
416 });
417 };
418
419 Rewriter.prototype.indentation = function(token, implicit) {
420 var indent, outdent;
421 if (implicit == null) {
422 implicit = false;
423 }
424 indent = ['INDENT', 2];
425 outdent = ['OUTDENT', 2];
426 if (implicit) {
427 indent.generated = outdent.generated = true;
428 }
429 if (!implicit) {
430 indent.explicit = outdent.explicit = true;
431 }
432 return [indent, outdent];
433 };
434
435 Rewriter.prototype.generate = generate;
436
437 Rewriter.prototype.tag = function(i) {
438 var _ref;
439 return (_ref = this.tokens[i]) != null ? _ref[0] : void 0;
440 };
441
442 return Rewriter;
443
444 })();
445
446 BALANCED_PAIRS = [['(', ')'], ['[', ']'], ['{', '}'], ['INDENT', 'OUTDENT'], ['CALL_START', 'CALL_END'], ['PARAM_START', 'PARAM_END'], ['INDEX_START', 'INDEX_END']];
447
448 exports.INVERSES = INVERSES = {};
449
450 EXPRESSION_START = [];
451
452 EXPRESSION_END = [];
453
454 for (_i = 0, _len = BALANCED_PAIRS.length; _i < _len; _i++) {
455 _ref = BALANCED_PAIRS[_i], left = _ref[0], rite = _ref[1];
456 EXPRESSION_START.push(INVERSES[rite] = left);
457 EXPRESSION_END.push(INVERSES[left] = rite);
458 }
459
460 EXPRESSION_CLOSE = ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat(EXPRESSION_END);
461
462 IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@', 'THIS'];
463
464 IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS', 'IF', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'NULL', 'UNDEFINED', 'UNARY', 'SUPER', '@', '->', '=>', '[', '(', '{', '--', '++'];
465
466 IMPLICIT_UNSPACED_CALL = ['+', '-'];
467
468 IMPLICIT_BLOCK = ['->', '=>', '{', '[', ','];
469
470 IMPLICIT_END = ['POST_IF', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR'];
471
472 SINGLE_LINERS = ['ELSE', '->', '=>', 'TRY', 'FINALLY', 'THEN'];
473
474 SINGLE_CLOSERS = ['TERMINATOR', 'CATCH', 'FINALLY', 'ELSE', 'OUTDENT', 'LEADING_WHEN'];
475
476 LINEBREAKS = ['TERMINATOR', 'INDENT', 'OUTDENT'];
477
478}).call(this);