mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-05-03 03:00:14 -04:00
The following is now allowed:
o =
a: 1
b: 2
"#{'c'}": 3
"#{'d'}": 4
e: 5
"#{'f'}": 6
g: 7
It compiles to:
o = (
obj = {
a: 1,
b: 2
},
obj["" + 'c'] = 3,
obj["" + 'd'] = 4,
obj.e = 5,
obj["" + 'f'] = 6,
obj.g = 7,
obj
);
- Closes #3039. Empty interpolations in object keys are now _supposed_ to be
allowed.
- Closes #1131. No need to improve error messages for attempted key
interpolation anymore.
- Implementing this required fixing the following bug: `("" + a): 1` used to
error out on the colon, saying "unexpected colon". But really, it is the
attempted object key that is unexpected. Now the error is on the opening
parenthesis instead.
- However, the above fix broke some error message tests for regexes. The easiest
way to fix this was to make a seemingly unrelated change: The error messages
for unexpected identifiers, numbers, strings and regexes now say for example
'unexpected string' instead of 'unexpected """some #{really long} string"""'.
In other words, the tag _name_ is used instead of the tag _value_.
This was way easier to implement, and is more helpful to the user. Using the
tag value is good for operators, reserved words and the like, but not for
tokens which can contain any text. For example, 'unexpected identifier' is
better than 'unexpected expected' (if a variable called 'expected' was used
erraneously).
- While writing tests for the above point I found a few minor bugs with string
locations which have been fixed.
500 lines
18 KiB
JavaScript
500 lines
18 KiB
JavaScript
// Generated by CoffeeScript 1.9.0
|
|
(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();
|
|
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;
|
|
if (startsLine == null) {
|
|
startsLine = true;
|
|
}
|
|
idx = j != null ? j : i;
|
|
stack.push([
|
|
'{', idx, {
|
|
sameLine: true,
|
|
startsLine: startsLine,
|
|
ours: true
|
|
}
|
|
]);
|
|
tokens.splice(idx, 0, generate('{', generate(new String('{')), 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', null, ':') > -1 && !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))) {
|
|
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.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', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@', 'THIS'];
|
|
|
|
IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'STRING_START', 'JS', 'REGEX', 'REGEX_START', 'NEW', 'PARAM_START', 'CLASS', 'IF', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'NULL', 'UNDEFINED', '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);
|