mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-05-03 03:00:14 -04:00
This commit adds another post-processing step after normal lexing that sets the locationData on all OUTDENT tokens to be at the last character of the previous token. This does feel like a little bit of a hack. Ideally the location data would be set correctly in the first place and not in a post-processing step, but I tried that and some temporary intermediate tokens were causing problems, so I decided to set the location data once those intermediate tokens were removed. Also, having this as a separate processing step makes it more robust and isolated. This fixes the problem in https://github.com/decaffeinate/decaffeinate/issues/371 . In that issue, the CoffeeScript tokens had three OUTDENT tokens in a row, and the last two overlapped with the `]`. Since at least one of those OUTDENT tokens was considered part of the function body, the function expression had an ending position just after the end of the `]`. OUTDENT tokens are sort of a weird case in the lexer anyway, since they often don't correspond to an actual location in the source code. It seems like the code in `lexer.coffee` makes an attempt at finding a good place for them, but in some cases, it has a bad result. This seems hard to avoid in the general case. For example, in this code: ```coffee [-> a] ``` There must be an OUTDENT between the `a` and the `]`, but CoffeeScript tokens have an inclusive start and end, so they must always be at least one character wide (I think). In this case, the lexer was choosing the `]` as the location, and the parser ended up generating correct location data, I believe because it ignores the outermost INDENT and OUTDENT tokens. However, with multiple OUTDENT tokens in a row, the parser ends up producing location data that is wrong. It seems to me like there isn't a solid answer to "what location do OUTDENT tokens have", since it hasn't mattered much, but for this commit, I'm defining it: they always have the location of the last character of the previous token. This should hopefully be fairly safe because tokens are still in the same order relative to each other. Also, it's worth noting that this makes the start location for OUTDENT tokens awkward. However, OUTDENT tokens are always used to mark the end of something, so their `last_line` and `last_column` values are always what matter when determining AST node bounds, so it is most important for those to be correct.
523 lines
19 KiB
JavaScript
523 lines
19 KiB
JavaScript
// Generated by CoffeeScript 1.11.1
|
|
(function() {
|
|
var BALANCED_PAIRS, CALL_CLOSERS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, IMPLICIT_UNSPACED_CALL, INVERSES, LINEBREAKS, SINGLE_CLOSERS, SINGLE_LINERS, generate, k, left, len, ref, rite,
|
|
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; },
|
|
slice = [].slice;
|
|
|
|
generate = function(tag, value, origin) {
|
|
var tok;
|
|
tok = [tag, value];
|
|
tok.generated = true;
|
|
if (origin) {
|
|
tok.origin = origin;
|
|
}
|
|
return tok;
|
|
};
|
|
|
|
exports.Rewriter = (function() {
|
|
function Rewriter() {}
|
|
|
|
Rewriter.prototype.rewrite = function(tokens1) {
|
|
this.tokens = tokens1;
|
|
this.removeLeadingNewlines();
|
|
this.closeOpenCalls();
|
|
this.closeOpenIndexes();
|
|
this.normalizeLines();
|
|
this.tagPostfixConditionals();
|
|
this.addImplicitBracesAndParens();
|
|
this.addLocationDataToGeneratedTokens();
|
|
this.fixOutdentLocationData();
|
|
return this.tokens;
|
|
};
|
|
|
|
Rewriter.prototype.scanTokens = function(block) {
|
|
var i, token, tokens;
|
|
tokens = this.tokens;
|
|
i = 0;
|
|
while (token = tokens[i]) {
|
|
i += block.call(this, token, i, tokens);
|
|
}
|
|
return true;
|
|
};
|
|
|
|
Rewriter.prototype.detectEnd = function(i, condition, action) {
|
|
var levels, ref, ref1, token, tokens;
|
|
tokens = this.tokens;
|
|
levels = 0;
|
|
while (token = tokens[i]) {
|
|
if (levels === 0 && condition.call(this, token, i)) {
|
|
return action.call(this, token, i);
|
|
}
|
|
if (!token || levels < 0) {
|
|
return action.call(this, token, i - 1);
|
|
}
|
|
if (ref = token[0], indexOf.call(EXPRESSION_START, ref) >= 0) {
|
|
levels += 1;
|
|
} else if (ref1 = token[0], indexOf.call(EXPRESSION_END, ref1) >= 0) {
|
|
levels -= 1;
|
|
}
|
|
i += 1;
|
|
}
|
|
return i - 1;
|
|
};
|
|
|
|
Rewriter.prototype.removeLeadingNewlines = function() {
|
|
var i, k, len, ref, tag;
|
|
ref = this.tokens;
|
|
for (i = k = 0, len = ref.length; k < len; i = ++k) {
|
|
tag = ref[i][0];
|
|
if (tag !== 'TERMINATOR') {
|
|
break;
|
|
}
|
|
}
|
|
if (i) {
|
|
return this.tokens.splice(0, i);
|
|
}
|
|
};
|
|
|
|
Rewriter.prototype.closeOpenCalls = function() {
|
|
var action, condition;
|
|
condition = function(token, i) {
|
|
var ref;
|
|
return ((ref = token[0]) === ')' || ref === 'CALL_END') || token[0] === 'OUTDENT' && this.tag(i - 1) === ')';
|
|
};
|
|
action = function(token, i) {
|
|
return this.tokens[token[0] === 'OUTDENT' ? i - 1 : i][0] = 'CALL_END';
|
|
};
|
|
return this.scanTokens(function(token, i) {
|
|
if (token[0] === 'CALL_START') {
|
|
this.detectEnd(i + 1, condition, action);
|
|
}
|
|
return 1;
|
|
});
|
|
};
|
|
|
|
Rewriter.prototype.closeOpenIndexes = function() {
|
|
var action, condition;
|
|
condition = function(token, i) {
|
|
var ref;
|
|
return (ref = token[0]) === ']' || ref === 'INDEX_END';
|
|
};
|
|
action = function(token, i) {
|
|
return token[0] = 'INDEX_END';
|
|
};
|
|
return this.scanTokens(function(token, i) {
|
|
if (token[0] === 'INDEX_START') {
|
|
this.detectEnd(i + 1, condition, action);
|
|
}
|
|
return 1;
|
|
});
|
|
};
|
|
|
|
Rewriter.prototype.indexOfTag = function() {
|
|
var fuzz, i, j, k, pattern, ref, ref1;
|
|
i = arguments[0], pattern = 2 <= arguments.length ? slice.call(arguments, 1) : [];
|
|
fuzz = 0;
|
|
for (j = k = 0, ref = pattern.length; 0 <= ref ? k < ref : k > ref; j = 0 <= ref ? ++k : --k) {
|
|
while (this.tag(i + j + fuzz) === 'HERECOMMENT') {
|
|
fuzz += 2;
|
|
}
|
|
if (pattern[j] == null) {
|
|
continue;
|
|
}
|
|
if (typeof pattern[j] === 'string') {
|
|
pattern[j] = [pattern[j]];
|
|
}
|
|
if (ref1 = this.tag(i + j + fuzz), indexOf.call(pattern[j], ref1) < 0) {
|
|
return -1;
|
|
}
|
|
}
|
|
return i + j + fuzz - 1;
|
|
};
|
|
|
|
Rewriter.prototype.looksObjectish = function(j) {
|
|
var end, index;
|
|
if (this.indexOfTag(j, '@', null, ':') > -1 || this.indexOfTag(j, null, ':') > -1) {
|
|
return true;
|
|
}
|
|
index = this.indexOfTag(j, EXPRESSION_START);
|
|
if (index > -1) {
|
|
end = null;
|
|
this.detectEnd(index + 1, (function(token) {
|
|
var ref;
|
|
return ref = token[0], indexOf.call(EXPRESSION_END, ref) >= 0;
|
|
}), (function(token, i) {
|
|
return end = i;
|
|
}));
|
|
if (this.tag(end + 1) === ':') {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
Rewriter.prototype.findTagsBackwards = function(i, tags) {
|
|
var backStack, ref, ref1, ref2, ref3, ref4, ref5;
|
|
backStack = [];
|
|
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))) {
|
|
if (ref = this.tag(i), indexOf.call(EXPRESSION_END, ref) >= 0) {
|
|
backStack.push(this.tag(i));
|
|
}
|
|
if ((ref1 = this.tag(i), indexOf.call(EXPRESSION_START, ref1) >= 0) && backStack.length) {
|
|
backStack.pop();
|
|
}
|
|
i -= 1;
|
|
}
|
|
return ref5 = this.tag(i), indexOf.call(tags, ref5) >= 0;
|
|
};
|
|
|
|
Rewriter.prototype.addImplicitBracesAndParens = function() {
|
|
var stack, start;
|
|
stack = [];
|
|
start = null;
|
|
return this.scanTokens(function(token, i, tokens) {
|
|
var endImplicitCall, endImplicitObject, forward, inImplicit, inImplicitCall, inImplicitControl, inImplicitObject, newLine, nextTag, offset, prevTag, prevToken, ref, ref1, ref2, ref3, ref4, ref5, s, sameLine, stackIdx, stackTag, stackTop, startIdx, startImplicitCall, startImplicitObject, startsLine, tag;
|
|
tag = token[0];
|
|
prevTag = (prevToken = i > 0 ? tokens[i - 1] : [])[0];
|
|
nextTag = (i < tokens.length - 1 ? tokens[i + 1] : [])[0];
|
|
stackTop = function() {
|
|
return stack[stack.length - 1];
|
|
};
|
|
startIdx = i;
|
|
forward = function(n) {
|
|
return i - startIdx + n;
|
|
};
|
|
inImplicit = function() {
|
|
var ref, ref1;
|
|
return (ref = stackTop()) != null ? (ref1 = ref[2]) != null ? ref1.ours : void 0 : void 0;
|
|
};
|
|
inImplicitCall = function() {
|
|
var ref;
|
|
return inImplicit() && ((ref = stackTop()) != null ? ref[0] : void 0) === '(';
|
|
};
|
|
inImplicitObject = function() {
|
|
var ref;
|
|
return inImplicit() && ((ref = stackTop()) != null ? ref[0] : void 0) === '{';
|
|
};
|
|
inImplicitControl = function() {
|
|
var ref;
|
|
return inImplicit && ((ref = stackTop()) != null ? ref[0] : void 0) === 'CONTROL';
|
|
};
|
|
startImplicitCall = function(j) {
|
|
var idx;
|
|
idx = j != null ? j : i;
|
|
stack.push([
|
|
'(', idx, {
|
|
ours: true
|
|
}
|
|
]);
|
|
tokens.splice(idx, 0, generate('CALL_START', '('));
|
|
if (j == null) {
|
|
return i += 1;
|
|
}
|
|
};
|
|
endImplicitCall = function() {
|
|
stack.pop();
|
|
tokens.splice(i, 0, generate('CALL_END', ')', ['', 'end of input', token[2]]));
|
|
return i += 1;
|
|
};
|
|
startImplicitObject = function(j, startsLine) {
|
|
var idx, val;
|
|
if (startsLine == null) {
|
|
startsLine = true;
|
|
}
|
|
idx = j != null ? j : i;
|
|
stack.push([
|
|
'{', idx, {
|
|
sameLine: true,
|
|
startsLine: startsLine,
|
|
ours: true
|
|
}
|
|
]);
|
|
val = new String('{');
|
|
val.generated = true;
|
|
tokens.splice(idx, 0, generate('{', val, token));
|
|
if (j == null) {
|
|
return i += 1;
|
|
}
|
|
};
|
|
endImplicitObject = function(j) {
|
|
j = j != null ? j : i;
|
|
stack.pop();
|
|
tokens.splice(j, 0, generate('}', '}', token));
|
|
return i += 1;
|
|
};
|
|
if (inImplicitCall() && (tag === 'IF' || tag === 'TRY' || tag === 'FINALLY' || tag === 'CATCH' || tag === 'CLASS' || tag === 'SWITCH')) {
|
|
stack.push([
|
|
'CONTROL', i, {
|
|
ours: true
|
|
}
|
|
]);
|
|
return forward(1);
|
|
}
|
|
if (tag === 'INDENT' && inImplicit()) {
|
|
if (prevTag !== '=>' && prevTag !== '->' && prevTag !== '[' && prevTag !== '(' && prevTag !== ',' && prevTag !== '{' && prevTag !== 'TRY' && prevTag !== 'ELSE' && prevTag !== '=') {
|
|
while (inImplicitCall()) {
|
|
endImplicitCall();
|
|
}
|
|
}
|
|
if (inImplicitControl()) {
|
|
stack.pop();
|
|
}
|
|
stack.push([tag, i]);
|
|
return forward(1);
|
|
}
|
|
if (indexOf.call(EXPRESSION_START, tag) >= 0) {
|
|
stack.push([tag, i]);
|
|
return forward(1);
|
|
}
|
|
if (indexOf.call(EXPRESSION_END, tag) >= 0) {
|
|
while (inImplicit()) {
|
|
if (inImplicitCall()) {
|
|
endImplicitCall();
|
|
} else if (inImplicitObject()) {
|
|
endImplicitObject();
|
|
} else {
|
|
stack.pop();
|
|
}
|
|
}
|
|
start = stack.pop();
|
|
}
|
|
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))) {
|
|
if (tag === '?') {
|
|
tag = token[0] = 'FUNC_EXIST';
|
|
}
|
|
startImplicitCall(i + 1);
|
|
return forward(2);
|
|
}
|
|
if (indexOf.call(IMPLICIT_FUNC, tag) >= 0 && this.indexOfTag(i + 1, 'INDENT') > -1 && this.looksObjectish(i + 2) && !this.findTagsBackwards(i, ['CLASS', 'EXTENDS', 'IF', 'CATCH', 'SWITCH', 'LEADING_WHEN', 'FOR', 'WHILE', 'UNTIL'])) {
|
|
startImplicitCall(i + 1);
|
|
stack.push(['INDENT', i + 2]);
|
|
return forward(3);
|
|
}
|
|
if (tag === ':') {
|
|
s = (function() {
|
|
var ref2;
|
|
switch (false) {
|
|
case ref2 = this.tag(i - 1), indexOf.call(EXPRESSION_END, ref2) < 0:
|
|
return start[1];
|
|
case this.tag(i - 2) !== '@':
|
|
return i - 2;
|
|
default:
|
|
return i - 1;
|
|
}
|
|
}).call(this);
|
|
while (this.tag(s - 2) === 'HERECOMMENT') {
|
|
s -= 2;
|
|
}
|
|
this.insideForDeclaration = nextTag === 'FOR';
|
|
startsLine = s === 0 || (ref2 = this.tag(s - 1), indexOf.call(LINEBREAKS, ref2) >= 0) || tokens[s - 1].newLine;
|
|
if (stackTop()) {
|
|
ref3 = stackTop(), stackTag = ref3[0], stackIdx = ref3[1];
|
|
if ((stackTag === '{' || stackTag === 'INDENT' && this.tag(stackIdx - 1) === '{') && (startsLine || this.tag(s - 1) === ',' || this.tag(s - 1) === '{')) {
|
|
return forward(1);
|
|
}
|
|
}
|
|
startImplicitObject(s, !!startsLine);
|
|
return forward(2);
|
|
}
|
|
if (inImplicitObject() && indexOf.call(LINEBREAKS, tag) >= 0) {
|
|
stackTop()[2].sameLine = false;
|
|
}
|
|
newLine = prevTag === 'OUTDENT' || prevToken.newLine;
|
|
if (indexOf.call(IMPLICIT_END, tag) >= 0 || indexOf.call(CALL_CLOSERS, tag) >= 0 && newLine) {
|
|
while (inImplicit()) {
|
|
ref4 = stackTop(), stackTag = ref4[0], stackIdx = ref4[1], (ref5 = ref4[2], sameLine = ref5.sameLine, startsLine = ref5.startsLine);
|
|
if (inImplicitCall() && prevTag !== ',') {
|
|
endImplicitCall();
|
|
} else if (inImplicitObject() && !this.insideForDeclaration && sameLine && tag !== 'TERMINATOR' && prevTag !== ':') {
|
|
endImplicitObject();
|
|
} else if (inImplicitObject() && tag === 'TERMINATOR' && prevTag !== ',' && !(startsLine && this.looksObjectish(i + 1))) {
|
|
if (nextTag === 'HERECOMMENT') {
|
|
return forward(1);
|
|
}
|
|
endImplicitObject();
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (tag === ',' && !this.looksObjectish(i + 1) && inImplicitObject() && !this.insideForDeclaration && (nextTag !== 'TERMINATOR' || !this.looksObjectish(i + 2))) {
|
|
offset = nextTag === 'OUTDENT' ? 1 : 0;
|
|
while (inImplicitObject()) {
|
|
endImplicitObject(i + offset);
|
|
}
|
|
}
|
|
return forward(1);
|
|
});
|
|
};
|
|
|
|
Rewriter.prototype.addLocationDataToGeneratedTokens = function() {
|
|
return this.scanTokens(function(token, i, tokens) {
|
|
var column, line, nextLocation, prevLocation, ref, ref1;
|
|
if (token[2]) {
|
|
return 1;
|
|
}
|
|
if (!(token.generated || token.explicit)) {
|
|
return 1;
|
|
}
|
|
if (token[0] === '{' && (nextLocation = (ref = tokens[i + 1]) != null ? ref[2] : void 0)) {
|
|
line = nextLocation.first_line, column = nextLocation.first_column;
|
|
} else if (prevLocation = (ref1 = tokens[i - 1]) != null ? ref1[2] : void 0) {
|
|
line = prevLocation.last_line, column = prevLocation.last_column;
|
|
} else {
|
|
line = column = 0;
|
|
}
|
|
token[2] = {
|
|
first_line: line,
|
|
first_column: column,
|
|
last_line: line,
|
|
last_column: column
|
|
};
|
|
return 1;
|
|
});
|
|
};
|
|
|
|
Rewriter.prototype.fixOutdentLocationData = function() {
|
|
return this.scanTokens(function(token, i, tokens) {
|
|
var prevLocationData;
|
|
if (token[0] !== 'OUTDENT') {
|
|
return 1;
|
|
}
|
|
prevLocationData = tokens[i - 1][2];
|
|
token[2] = {
|
|
first_line: prevLocationData.last_line,
|
|
first_column: prevLocationData.last_column,
|
|
last_line: prevLocationData.last_line,
|
|
last_column: prevLocationData.last_column
|
|
};
|
|
return 1;
|
|
});
|
|
};
|
|
|
|
Rewriter.prototype.normalizeLines = function() {
|
|
var action, condition, indent, outdent, starter;
|
|
starter = indent = outdent = null;
|
|
condition = function(token, i) {
|
|
var ref, ref1, ref2, ref3;
|
|
return token[1] !== ';' && (ref = token[0], indexOf.call(SINGLE_CLOSERS, ref) >= 0) && !(token[0] === 'TERMINATOR' && (ref1 = this.tag(i + 1), indexOf.call(EXPRESSION_CLOSE, ref1) >= 0)) && !(token[0] === 'ELSE' && starter !== 'THEN') && !(((ref2 = token[0]) === 'CATCH' || ref2 === 'FINALLY') && (starter === '->' || starter === '=>')) || (ref3 = token[0], indexOf.call(CALL_CLOSERS, ref3) >= 0) && this.tokens[i - 1].newLine;
|
|
};
|
|
action = function(token, i) {
|
|
return this.tokens.splice((this.tag(i - 1) === ',' ? i - 1 : i), 0, outdent);
|
|
};
|
|
return this.scanTokens(function(token, i, tokens) {
|
|
var j, k, ref, ref1, ref2, tag;
|
|
tag = token[0];
|
|
if (tag === 'TERMINATOR') {
|
|
if (this.tag(i + 1) === 'ELSE' && this.tag(i - 1) !== 'OUTDENT') {
|
|
tokens.splice.apply(tokens, [i, 1].concat(slice.call(this.indentation())));
|
|
return 1;
|
|
}
|
|
if (ref = this.tag(i + 1), indexOf.call(EXPRESSION_CLOSE, ref) >= 0) {
|
|
tokens.splice(i, 1);
|
|
return 0;
|
|
}
|
|
}
|
|
if (tag === 'CATCH') {
|
|
for (j = k = 1; k <= 2; j = ++k) {
|
|
if (!((ref1 = this.tag(i + j)) === 'OUTDENT' || ref1 === 'TERMINATOR' || ref1 === 'FINALLY')) {
|
|
continue;
|
|
}
|
|
tokens.splice.apply(tokens, [i + j, 0].concat(slice.call(this.indentation())));
|
|
return 2 + j;
|
|
}
|
|
}
|
|
if (indexOf.call(SINGLE_LINERS, tag) >= 0 && this.tag(i + 1) !== 'INDENT' && !(tag === 'ELSE' && this.tag(i + 1) === 'IF')) {
|
|
starter = tag;
|
|
ref2 = this.indentation(tokens[i]), indent = ref2[0], outdent = ref2[1];
|
|
if (starter === 'THEN') {
|
|
indent.fromThen = true;
|
|
}
|
|
tokens.splice(i + 1, 0, indent);
|
|
this.detectEnd(i + 2, condition, action);
|
|
if (tag === 'THEN') {
|
|
tokens.splice(i, 1);
|
|
}
|
|
return 1;
|
|
}
|
|
return 1;
|
|
});
|
|
};
|
|
|
|
Rewriter.prototype.tagPostfixConditionals = function() {
|
|
var action, condition, original;
|
|
original = null;
|
|
condition = function(token, i) {
|
|
var prevTag, tag;
|
|
tag = token[0];
|
|
prevTag = this.tokens[i - 1][0];
|
|
return tag === 'TERMINATOR' || (tag === 'INDENT' && indexOf.call(SINGLE_LINERS, prevTag) < 0);
|
|
};
|
|
action = function(token, i) {
|
|
if (token[0] !== 'INDENT' || (token.generated && !token.fromThen)) {
|
|
return original[0] = 'POST_' + original[0];
|
|
}
|
|
};
|
|
return this.scanTokens(function(token, i) {
|
|
if (token[0] !== 'IF') {
|
|
return 1;
|
|
}
|
|
original = token;
|
|
this.detectEnd(i + 1, condition, action);
|
|
return 1;
|
|
});
|
|
};
|
|
|
|
Rewriter.prototype.indentation = function(origin) {
|
|
var indent, outdent;
|
|
indent = ['INDENT', 2];
|
|
outdent = ['OUTDENT', 2];
|
|
if (origin) {
|
|
indent.generated = outdent.generated = true;
|
|
indent.origin = outdent.origin = origin;
|
|
} else {
|
|
indent.explicit = outdent.explicit = true;
|
|
}
|
|
return [indent, outdent];
|
|
};
|
|
|
|
Rewriter.prototype.generate = generate;
|
|
|
|
Rewriter.prototype.tag = function(i) {
|
|
var ref;
|
|
return (ref = this.tokens[i]) != null ? ref[0] : void 0;
|
|
};
|
|
|
|
return Rewriter;
|
|
|
|
})();
|
|
|
|
BALANCED_PAIRS = [['(', ')'], ['[', ']'], ['{', '}'], ['INDENT', 'OUTDENT'], ['CALL_START', 'CALL_END'], ['PARAM_START', 'PARAM_END'], ['INDEX_START', 'INDEX_END'], ['STRING_START', 'STRING_END'], ['REGEX_START', 'REGEX_END']];
|
|
|
|
exports.INVERSES = INVERSES = {};
|
|
|
|
EXPRESSION_START = [];
|
|
|
|
EXPRESSION_END = [];
|
|
|
|
for (k = 0, len = BALANCED_PAIRS.length; k < len; k++) {
|
|
ref = BALANCED_PAIRS[k], left = ref[0], rite = ref[1];
|
|
EXPRESSION_START.push(INVERSES[rite] = left);
|
|
EXPRESSION_END.push(INVERSES[left] = rite);
|
|
}
|
|
|
|
EXPRESSION_CLOSE = ['CATCH', 'THEN', 'ELSE', 'FINALLY'].concat(EXPRESSION_END);
|
|
|
|
IMPLICIT_FUNC = ['IDENTIFIER', 'PROPERTY', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@', 'THIS'];
|
|
|
|
IMPLICIT_CALL = ['IDENTIFIER', 'PROPERTY', 'NUMBER', 'INFINITY', 'NAN', 'STRING', 'STRING_START', 'REGEX', 'REGEX_START', 'JS', 'NEW', 'PARAM_START', 'CLASS', 'IF', 'TRY', 'SWITCH', 'THIS', 'UNDEFINED', 'NULL', 'BOOL', 'UNARY', 'YIELD', 'UNARY_MATH', 'SUPER', 'THROW', '@', '->', '=>', '[', '(', '{', '--', '++'];
|
|
|
|
IMPLICIT_UNSPACED_CALL = ['+', '-'];
|
|
|
|
IMPLICIT_END = ['POST_IF', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR'];
|
|
|
|
SINGLE_LINERS = ['ELSE', '->', '=>', 'TRY', 'FINALLY', 'THEN'];
|
|
|
|
SINGLE_CLOSERS = ['TERMINATOR', 'CATCH', 'FINALLY', 'ELSE', 'OUTDENT', 'LEADING_WHEN'];
|
|
|
|
LINEBREAKS = ['TERMINATOR', 'INDENT', 'OUTDENT'];
|
|
|
|
CALL_CLOSERS = ['.', '?.', '::', '?::'];
|
|
|
|
}).call(this);
|