mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-05-03 03:00:14 -04:00
Merge branch '2' into 2-docs
This commit is contained in:
@@ -7,10 +7,8 @@
|
||||
|
||||
ref1 = require('./helpers'), count = ref1.count, starts = ref1.starts, compact = ref1.compact, repeat = ref1.repeat, invertLiterate = ref1.invertLiterate, locationDataToString = ref1.locationDataToString, throwSyntaxError = ref1.throwSyntaxError;
|
||||
|
||||
exports.Lexer = Lexer = (function() {
|
||||
function Lexer() {}
|
||||
|
||||
Lexer.prototype.tokenize = function(code, opts = {}) {
|
||||
exports.Lexer = Lexer = class Lexer {
|
||||
tokenize(code, opts = {}) {
|
||||
var consumed, end, i, ref2;
|
||||
this.literate = opts.literate;
|
||||
this.indent = 0;
|
||||
@@ -48,9 +46,9 @@
|
||||
return this.tokens;
|
||||
}
|
||||
return (new Rewriter).rewrite(this.tokens);
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.clean = function(code) {
|
||||
clean(code) {
|
||||
if (code.charCodeAt(0) === BOM) {
|
||||
code = code.slice(1);
|
||||
}
|
||||
@@ -63,9 +61,9 @@
|
||||
code = invertLiterate(code);
|
||||
}
|
||||
return code;
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.identifierToken = function() {
|
||||
identifierToken() {
|
||||
var alias, colon, colonOffset, id, idLength, input, match, poppedToken, prev, ref2, ref3, ref4, ref5, ref6, ref7, tag, tagToken;
|
||||
if (!(match = IDENTIFIER.exec(this.chunk))) {
|
||||
return 0;
|
||||
@@ -176,9 +174,9 @@
|
||||
this.token(':', ':', colonOffset, colon.length);
|
||||
}
|
||||
return input.length;
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.numberToken = function() {
|
||||
numberToken() {
|
||||
var base, lexedLength, match, number, numberValue, tag;
|
||||
if (!(match = NUMBER.exec(this.chunk))) {
|
||||
return 0;
|
||||
@@ -222,9 +220,9 @@
|
||||
tag = numberValue === 2e308 ? 'INFINITY' : 'NUMBER';
|
||||
this.token(tag, number, 0, lexedLength);
|
||||
return lexedLength;
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.stringToken = function() {
|
||||
stringToken() {
|
||||
var $, attempt, delimiter, doc, end, heredoc, i, indent, indentRegex, match, quote, ref2, ref3, regex, token, tokens;
|
||||
quote = (STRING_START.exec(this.chunk) || [])[0];
|
||||
if (!quote) {
|
||||
@@ -302,9 +300,9 @@
|
||||
});
|
||||
}
|
||||
return end;
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.commentToken = function() {
|
||||
commentToken() {
|
||||
var comment, here, match;
|
||||
if (!(match = this.chunk.match(COMMENT))) {
|
||||
return 0;
|
||||
@@ -323,9 +321,9 @@
|
||||
this.token('HERECOMMENT', here, 0, comment.length);
|
||||
}
|
||||
return comment.length;
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.jsToken = function() {
|
||||
jsToken() {
|
||||
var match, script;
|
||||
if (!(this.chunk.charAt(0) === '`' && (match = HERE_JSTOKEN.exec(this.chunk) || JSTOKEN.exec(this.chunk)))) {
|
||||
return 0;
|
||||
@@ -335,9 +333,9 @@
|
||||
});
|
||||
this.token('JS', script, 0, match[0].length);
|
||||
return match[0].length;
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.regexToken = function() {
|
||||
regexToken() {
|
||||
var body, closed, end, flags, index, match, origin, prev, ref2, ref3, ref4, regex, tokens;
|
||||
switch (false) {
|
||||
case !(match = REGEX_ILLEGAL.exec(this.chunk)):
|
||||
@@ -406,9 +404,9 @@
|
||||
this.token('REGEX_END', ')', end, 0);
|
||||
}
|
||||
return end;
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.lineToken = function() {
|
||||
lineToken() {
|
||||
var diff, indent, match, minLiteralLength, newIndentLiteral, noNewlines, size;
|
||||
if (!(match = MULTI_DENT.exec(this.chunk))) {
|
||||
return 0;
|
||||
@@ -468,9 +466,9 @@
|
||||
this.outdentToken(this.indent - size, noNewlines, indent.length);
|
||||
}
|
||||
return indent.length;
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.outdentToken = function(moveOut, noNewlines, outdentLength) {
|
||||
outdentToken(moveOut, noNewlines, outdentLength) {
|
||||
var decreasedIndent, dent, lastIndent, ref2;
|
||||
decreasedIndent = this.indent - moveOut;
|
||||
while (moveOut > 0) {
|
||||
@@ -507,9 +505,9 @@
|
||||
this.indent = decreasedIndent;
|
||||
this.indentLiteral = this.indentLiteral.slice(0, decreasedIndent);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.whitespaceToken = function() {
|
||||
whitespaceToken() {
|
||||
var match, nline, prev, ref2;
|
||||
if (!((match = WHITESPACE.exec(this.chunk)) || (nline = this.chunk.charAt(0) === '\n'))) {
|
||||
return 0;
|
||||
@@ -523,9 +521,9 @@
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.newlineToken = function(offset) {
|
||||
newlineToken(offset) {
|
||||
while (this.value() === ';') {
|
||||
this.tokens.pop();
|
||||
}
|
||||
@@ -533,16 +531,16 @@
|
||||
this.token('TERMINATOR', '\n', offset, 0);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.suppressNewlines = function() {
|
||||
suppressNewlines() {
|
||||
if (this.value() === '\\') {
|
||||
this.tokens.pop();
|
||||
}
|
||||
return this;
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.literalToken = function() {
|
||||
literalToken() {
|
||||
var match, message, origin, prev, ref2, ref3, ref4, ref5, ref6, skipToken, tag, token, value;
|
||||
if (match = OPERATOR.exec(this.chunk)) {
|
||||
value = match[0];
|
||||
@@ -628,9 +626,9 @@
|
||||
}
|
||||
this.tokens.push(token);
|
||||
return value.length;
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.tagParameters = function() {
|
||||
tagParameters() {
|
||||
var i, stack, tok, tokens;
|
||||
if (this.tag() !== ')') {
|
||||
return this;
|
||||
@@ -657,13 +655,13 @@
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.closeIndentation = function() {
|
||||
closeIndentation() {
|
||||
return this.outdentToken(this.indent);
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.matchWithInterpolations = function(regex, delimiter) {
|
||||
matchWithInterpolations(regex, delimiter) {
|
||||
var close, column, firstToken, index, lastToken, line, nested, offsetInChunk, open, ref2, ref3, ref4, str, strPart, tokens;
|
||||
tokens = [];
|
||||
offsetInChunk = delimiter.length;
|
||||
@@ -721,9 +719,9 @@
|
||||
tokens: tokens,
|
||||
index: offsetInChunk + delimiter.length
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.mergeInterpolationTokens = function(tokens, options, fn) {
|
||||
mergeInterpolationTokens(tokens, options, fn) {
|
||||
var converted, firstEmptyStringIndex, firstIndex, i, j, lastToken, len, locationToken, lparen, plusToken, rparen, tag, token, tokensToPush, value;
|
||||
if (tokens.length > 1) {
|
||||
lparen = this.token('STRING_START', '(', 0, 0);
|
||||
@@ -786,9 +784,9 @@
|
||||
last_column: lastToken[2].last_column
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.pair = function(tag) {
|
||||
pair(tag) {
|
||||
var lastIndent, prev, ref2, ref3, wanted;
|
||||
ref2 = this.ends, prev = ref2[ref2.length - 1];
|
||||
if (tag !== (wanted = prev != null ? prev.tag : void 0)) {
|
||||
@@ -800,9 +798,9 @@
|
||||
return this.pair(tag);
|
||||
}
|
||||
return this.ends.pop();
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.getLineAndColumnFromChunk = function(offset) {
|
||||
getLineAndColumnFromChunk(offset) {
|
||||
var column, lastLine, lineCount, ref2, string;
|
||||
if (offset === 0) {
|
||||
return [this.chunkLine, this.chunkColumn];
|
||||
@@ -821,9 +819,9 @@
|
||||
column += string.length;
|
||||
}
|
||||
return [this.chunkLine + lineCount, column];
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.makeToken = function(tag, value, offsetInChunk = 0, length = value.length) {
|
||||
makeToken(tag, value, offsetInChunk = 0, length = value.length) {
|
||||
var lastCharacter, locationData, ref2, ref3, token;
|
||||
locationData = {};
|
||||
ref2 = this.getLineAndColumnFromChunk(offsetInChunk), locationData.first_line = ref2[0], locationData.first_column = ref2[1];
|
||||
@@ -831,9 +829,9 @@
|
||||
ref3 = this.getLineAndColumnFromChunk(offsetInChunk + lastCharacter), locationData.last_line = ref3[0], locationData.last_column = ref3[1];
|
||||
token = [tag, value, locationData];
|
||||
return token;
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.token = function(tag, value, offsetInChunk, length, origin) {
|
||||
token(tag, value, offsetInChunk, length, origin) {
|
||||
var token;
|
||||
token = this.makeToken(tag, value, offsetInChunk, length);
|
||||
if (origin) {
|
||||
@@ -841,34 +839,34 @@
|
||||
}
|
||||
this.tokens.push(token);
|
||||
return token;
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.tag = function() {
|
||||
tag() {
|
||||
var ref2, token;
|
||||
ref2 = this.tokens, token = ref2[ref2.length - 1];
|
||||
return token != null ? token[0] : void 0;
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.value = function() {
|
||||
value() {
|
||||
var ref2, token;
|
||||
ref2 = this.tokens, token = ref2[ref2.length - 1];
|
||||
return token != null ? token[1] : void 0;
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.unfinished = function() {
|
||||
unfinished() {
|
||||
var ref2;
|
||||
return LINE_CONTINUER.test(this.chunk) || ((ref2 = this.tag()) === '\\' || ref2 === '.' || ref2 === '?.' || ref2 === '?::' || ref2 === 'UNARY' || ref2 === 'MATH' || ref2 === 'UNARY_MATH' || ref2 === '+' || ref2 === '-' || ref2 === '**' || ref2 === 'SHIFT' || ref2 === 'RELATION' || ref2 === 'COMPARE' || ref2 === '&' || ref2 === '^' || ref2 === '|' || ref2 === '&&' || ref2 === '||' || ref2 === 'BIN?' || ref2 === 'THROW' || ref2 === 'EXTENDS');
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.formatString = function(str) {
|
||||
formatString(str) {
|
||||
return str.replace(STRING_OMIT, '$1');
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.formatHeregex = function(str) {
|
||||
formatHeregex(str) {
|
||||
return str.replace(HEREGEX_OMIT, '$1$2');
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.validateEscapes = function(str, options = {}) {
|
||||
validateEscapes(str, options = {}) {
|
||||
var before, hex, invalidEscape, match, message, octal, ref2, unicode;
|
||||
match = INVALID_ESCAPE.exec(str);
|
||||
if (!match) {
|
||||
@@ -884,9 +882,9 @@
|
||||
offset: ((ref2 = options.offsetInChunk) != null ? ref2 : 0) + match.index + before.length,
|
||||
length: invalidEscape.length
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.makeDelimitedLiteral = function(body, options = {}) {
|
||||
makeDelimitedLiteral(body, options = {}) {
|
||||
var regex;
|
||||
if (body === '' && options.delimiter === '/') {
|
||||
body = '(?:)';
|
||||
@@ -921,9 +919,9 @@
|
||||
}
|
||||
});
|
||||
return `${options.delimiter}${body}${options.delimiter}`;
|
||||
};
|
||||
}
|
||||
|
||||
Lexer.prototype.error = function(message, options = {}) {
|
||||
error(message, options = {}) {
|
||||
var first_column, first_line, location, ref2, ref3, ref4;
|
||||
location = 'first_line' in options ? options : ((ref3 = this.getLineAndColumnFromChunk((ref2 = options.offset) != null ? ref2 : 0), first_line = ref3[0], first_column = ref3[1], ref3), {
|
||||
first_line: first_line,
|
||||
@@ -931,11 +929,9 @@
|
||||
last_column: first_column + ((ref4 = options.length) != null ? ref4 : 1) - 1
|
||||
});
|
||||
return throwSyntaxError(message, location);
|
||||
};
|
||||
}
|
||||
|
||||
return Lexer;
|
||||
|
||||
})();
|
||||
};
|
||||
|
||||
isUnassignable = function(name, displayName = name) {
|
||||
switch (false) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,13 +4,13 @@
|
||||
|
||||
repeat = require('./helpers').repeat;
|
||||
|
||||
exports.OptionParser = OptionParser = (function() {
|
||||
function OptionParser(rules, banner) {
|
||||
exports.OptionParser = OptionParser = class OptionParser {
|
||||
constructor(rules, banner) {
|
||||
this.banner = banner;
|
||||
this.rules = buildRules(rules);
|
||||
}
|
||||
|
||||
OptionParser.prototype.parse = function(args) {
|
||||
parse(args) {
|
||||
var arg, i, isOption, j, k, len, len1, matchedRule, options, originalArgs, pos, ref, rule, seenNonOptionArg, skippingArgument, value;
|
||||
options = {
|
||||
"arguments": []
|
||||
@@ -56,9 +56,9 @@
|
||||
}
|
||||
}
|
||||
return options;
|
||||
};
|
||||
}
|
||||
|
||||
OptionParser.prototype.help = function() {
|
||||
help() {
|
||||
var j, len, letPart, lines, ref, rule, spaces;
|
||||
lines = [];
|
||||
if (this.banner) {
|
||||
@@ -73,11 +73,9 @@
|
||||
lines.push(' ' + letPart + rule.longFlag + spaces + rule.description);
|
||||
}
|
||||
return `\n${lines.join('\n')}\n`;
|
||||
};
|
||||
}
|
||||
|
||||
return OptionParser;
|
||||
|
||||
})();
|
||||
};
|
||||
|
||||
LONG_FLAG = /^(--\w[\w\-]*)/;
|
||||
|
||||
|
||||
@@ -14,470 +14,471 @@
|
||||
};
|
||||
|
||||
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);
|
||||
class Rewriter {
|
||||
rewrite(tokens1) {
|
||||
this.tokens = tokens1;
|
||||
this.removeLeadingNewlines();
|
||||
this.closeOpenCalls();
|
||||
this.closeOpenIndexes();
|
||||
this.normalizeLines();
|
||||
this.tagPostfixConditionals();
|
||||
this.addImplicitBracesAndParens();
|
||||
this.addLocationDataToGeneratedTokens();
|
||||
this.fixOutdentLocationData();
|
||||
return this.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);
|
||||
scanTokens(block) {
|
||||
var i, token, tokens;
|
||||
tokens = this.tokens;
|
||||
i = 0;
|
||||
while (token = tokens[i]) {
|
||||
i += block.call(this, token, i, tokens);
|
||||
}
|
||||
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(i, ...pattern) {
|
||||
var fuzz, j, k, ref, ref1;
|
||||
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) {
|
||||
|
||||
detectEnd(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;
|
||||
}
|
||||
|
||||
removeLeadingNewlines() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
closeOpenCalls() {
|
||||
var action, condition;
|
||||
condition = function(token, i) {
|
||||
var ref;
|
||||
return ref = token[0], indexOf.call(EXPRESSION_END, ref) >= 0;
|
||||
}), (function(token, i) {
|
||||
return end = i;
|
||||
}));
|
||||
if (this.tag(end + 1) === ':') {
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
closeOpenIndexes() {
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
indexOfTag(i, ...pattern) {
|
||||
var fuzz, j, k, ref, ref1;
|
||||
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;
|
||||
}
|
||||
|
||||
looksObjectish(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;
|
||||
}
|
||||
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));
|
||||
findTagsBackwards(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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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
|
||||
addImplicitBracesAndParens() {
|
||||
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;
|
||||
}
|
||||
]);
|
||||
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 = true) {
|
||||
var idx, val;
|
||||
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()) {
|
||||
};
|
||||
endImplicitCall = function() {
|
||||
stack.pop();
|
||||
tokens.splice(i, 0, generate('CALL_END', ')', ['', 'end of input', token[2]]));
|
||||
return i += 1;
|
||||
};
|
||||
startImplicitObject = function(j, startsLine = true) {
|
||||
var idx, val;
|
||||
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);
|
||||
}
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
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';
|
||||
if (indexOf.call(EXPRESSION_START, tag) >= 0) {
|
||||
stack.push([tag, i]);
|
||||
return forward(1);
|
||||
}
|
||||
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;
|
||||
if (indexOf.call(EXPRESSION_END, tag) >= 0) {
|
||||
while (inImplicit()) {
|
||||
if (inImplicitCall()) {
|
||||
endImplicitCall();
|
||||
} else if (inImplicitObject()) {
|
||||
endImplicitObject();
|
||||
} else {
|
||||
stack.pop();
|
||||
}
|
||||
}
|
||||
}).call(this);
|
||||
while (this.tag(s - 2) === 'HERECOMMENT') {
|
||||
s -= 2;
|
||||
start = stack.pop();
|
||||
}
|
||||
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);
|
||||
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);
|
||||
}
|
||||
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') {
|
||||
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);
|
||||
}
|
||||
endImplicitObject();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
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);
|
||||
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);
|
||||
});
|
||||
};
|
||||
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' || (token.generated && token[0] === 'CALL_END') || (token.generated && token[0] === '}'))) {
|
||||
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(i, 1, ...this.indentation());
|
||||
addLocationDataToGeneratedTokens() {
|
||||
return this.scanTokens(function(token, i, tokens) {
|
||||
var column, line, nextLocation, prevLocation, ref, ref1;
|
||||
if (token[2]) {
|
||||
return 1;
|
||||
}
|
||||
if (ref = this.tag(i + 1), indexOf.call(EXPRESSION_CLOSE, ref) >= 0) {
|
||||
tokens.splice(i, 1);
|
||||
return 0;
|
||||
if (!(token.generated || token.explicit)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
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(i + j, 0, ...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);
|
||||
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;
|
||||
}
|
||||
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];
|
||||
|
||||
fixOutdentLocationData() {
|
||||
return this.scanTokens(function(token, i, tokens) {
|
||||
var prevLocationData;
|
||||
if (!(token[0] === 'OUTDENT' || (token.generated && token[0] === 'CALL_END') || (token.generated && token[0] === '}'))) {
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
normalizeLines() {
|
||||
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(i, 1, ...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(i + j, 0, ...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;
|
||||
});
|
||||
}
|
||||
|
||||
tagPostfixConditionals() {
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
indentation(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];
|
||||
}
|
||||
|
||||
tag(i) {
|
||||
var ref;
|
||||
return (ref = this.tokens[i]) != null ? ref[0] : void 0;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Rewriter.prototype.generate = generate;
|
||||
|
||||
Rewriter.prototype.tag = function(i) {
|
||||
var ref;
|
||||
return (ref = this.tokens[i]) != null ? ref[0] : void 0;
|
||||
};
|
||||
|
||||
return Rewriter;
|
||||
|
||||
})();
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
var Scope,
|
||||
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; };
|
||||
|
||||
exports.Scope = Scope = (function() {
|
||||
function Scope(parent, expressions, method, referencedVars) {
|
||||
exports.Scope = Scope = class Scope {
|
||||
constructor(parent, expressions, method, referencedVars) {
|
||||
var ref, ref1;
|
||||
this.parent = parent;
|
||||
this.expressions = expressions;
|
||||
@@ -23,7 +23,7 @@
|
||||
this.root = (ref = (ref1 = this.parent) != null ? ref1.root : void 0) != null ? ref : this;
|
||||
}
|
||||
|
||||
Scope.prototype.add = function(name, type, immediate) {
|
||||
add(name, type, immediate) {
|
||||
if (this.shared && !immediate) {
|
||||
return this.parent.add(name, type, immediate);
|
||||
}
|
||||
@@ -35,37 +35,37 @@
|
||||
type: type
|
||||
}) - 1;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Scope.prototype.namedMethod = function() {
|
||||
namedMethod() {
|
||||
var ref;
|
||||
if (((ref = this.method) != null ? ref.name : void 0) || !this.parent) {
|
||||
return this.method;
|
||||
}
|
||||
return this.parent.namedMethod();
|
||||
};
|
||||
}
|
||||
|
||||
Scope.prototype.find = function(name) {
|
||||
find(name) {
|
||||
if (this.check(name)) {
|
||||
return true;
|
||||
}
|
||||
this.add(name, 'var');
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
Scope.prototype.parameter = function(name) {
|
||||
parameter(name) {
|
||||
if (this.shared && this.parent.check(name, true)) {
|
||||
return;
|
||||
}
|
||||
return this.add(name, 'param');
|
||||
};
|
||||
}
|
||||
|
||||
Scope.prototype.check = function(name) {
|
||||
check(name) {
|
||||
var ref;
|
||||
return !!(this.type(name) || ((ref = this.parent) != null ? ref.check(name) : void 0));
|
||||
};
|
||||
}
|
||||
|
||||
Scope.prototype.temporary = function(name, index, single = false) {
|
||||
temporary(name, index, single = false) {
|
||||
var diff, endCode, letter, newCode, num, startCode;
|
||||
if (single) {
|
||||
startCode = name.charCodeAt(0);
|
||||
@@ -78,9 +78,9 @@
|
||||
} else {
|
||||
return `${name}${index || ''}`;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Scope.prototype.type = function(name) {
|
||||
type(name) {
|
||||
var i, len, ref, v;
|
||||
ref = this.variables;
|
||||
for (i = 0, len = ref.length; i < len; i++) {
|
||||
@@ -90,9 +90,9 @@
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
Scope.prototype.freeVariable = function(name, options = {}) {
|
||||
freeVariable(name, options = {}) {
|
||||
var index, ref, temp;
|
||||
index = 0;
|
||||
while (true) {
|
||||
@@ -106,21 +106,21 @@
|
||||
this.add(temp, 'var', true);
|
||||
}
|
||||
return temp;
|
||||
};
|
||||
}
|
||||
|
||||
Scope.prototype.assign = function(name, value) {
|
||||
assign(name, value) {
|
||||
this.add(name, {
|
||||
value: value,
|
||||
assigned: true
|
||||
}, true);
|
||||
return this.hasAssignments = true;
|
||||
};
|
||||
}
|
||||
|
||||
Scope.prototype.hasDeclarations = function() {
|
||||
hasDeclarations() {
|
||||
return !!this.declaredVariables().length;
|
||||
};
|
||||
}
|
||||
|
||||
Scope.prototype.declaredVariables = function() {
|
||||
declaredVariables() {
|
||||
var v;
|
||||
return ((function() {
|
||||
var i, len, ref, results;
|
||||
@@ -134,9 +134,9 @@
|
||||
}
|
||||
return results;
|
||||
}).call(this)).sort();
|
||||
};
|
||||
}
|
||||
|
||||
Scope.prototype.assignedVariables = function() {
|
||||
assignedVariables() {
|
||||
var i, len, ref, results, v;
|
||||
ref = this.variables;
|
||||
results = [];
|
||||
@@ -147,10 +147,8 @@
|
||||
}
|
||||
}
|
||||
return results;
|
||||
};
|
||||
}
|
||||
|
||||
return Scope;
|
||||
|
||||
})();
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
(function() {
|
||||
var LineMap, SourceMap;
|
||||
|
||||
LineMap = (function() {
|
||||
function LineMap(line1) {
|
||||
LineMap = class LineMap {
|
||||
constructor(line1) {
|
||||
this.line = line1;
|
||||
this.columns = [];
|
||||
}
|
||||
|
||||
LineMap.prototype.add = function(column, arg, options = {}) {
|
||||
add(column, arg, options = {}) {
|
||||
var sourceColumn, sourceLine;
|
||||
sourceLine = arg[0], sourceColumn = arg[1];
|
||||
if (this.columns[column] && options.noReplace) {
|
||||
@@ -20,94 +20,117 @@
|
||||
sourceLine: sourceLine,
|
||||
sourceColumn: sourceColumn
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
LineMap.prototype.sourceLocation = function(column) {
|
||||
sourceLocation(column) {
|
||||
var mapping;
|
||||
while (!((mapping = this.columns[column]) || (column <= 0))) {
|
||||
column--;
|
||||
}
|
||||
return mapping && [mapping.sourceLine, mapping.sourceColumn];
|
||||
};
|
||||
}
|
||||
|
||||
return LineMap;
|
||||
|
||||
})();
|
||||
};
|
||||
|
||||
SourceMap = (function() {
|
||||
var BASE64_CHARS, VLQ_CONTINUATION_BIT, VLQ_SHIFT, VLQ_VALUE_MASK;
|
||||
|
||||
function SourceMap() {
|
||||
this.lines = [];
|
||||
}
|
||||
|
||||
SourceMap.prototype.add = function(sourceLocation, generatedLocation, options = {}) {
|
||||
var base, column, line, lineMap;
|
||||
line = generatedLocation[0], column = generatedLocation[1];
|
||||
lineMap = ((base = this.lines)[line] || (base[line] = new LineMap(line)));
|
||||
return lineMap.add(column, sourceLocation, options);
|
||||
};
|
||||
|
||||
SourceMap.prototype.sourceLocation = function(arg) {
|
||||
var column, line, lineMap;
|
||||
line = arg[0], column = arg[1];
|
||||
while (!((lineMap = this.lines[line]) || (line <= 0))) {
|
||||
line--;
|
||||
class SourceMap {
|
||||
constructor() {
|
||||
this.lines = [];
|
||||
}
|
||||
return lineMap && lineMap.sourceLocation(column);
|
||||
};
|
||||
|
||||
SourceMap.prototype.generate = function(options = {}, code = null) {
|
||||
var buffer, i, j, lastColumn, lastSourceColumn, lastSourceLine, len, len1, lineMap, lineNumber, mapping, needComma, ref, ref1, v3, writingline;
|
||||
writingline = 0;
|
||||
lastColumn = 0;
|
||||
lastSourceLine = 0;
|
||||
lastSourceColumn = 0;
|
||||
needComma = false;
|
||||
buffer = "";
|
||||
ref = this.lines;
|
||||
for (lineNumber = i = 0, len = ref.length; i < len; lineNumber = ++i) {
|
||||
lineMap = ref[lineNumber];
|
||||
if (lineMap) {
|
||||
ref1 = lineMap.columns;
|
||||
for (j = 0, len1 = ref1.length; j < len1; j++) {
|
||||
mapping = ref1[j];
|
||||
if (!(mapping)) {
|
||||
continue;
|
||||
add(sourceLocation, generatedLocation, options = {}) {
|
||||
var base, column, line, lineMap;
|
||||
line = generatedLocation[0], column = generatedLocation[1];
|
||||
lineMap = ((base = this.lines)[line] || (base[line] = new LineMap(line)));
|
||||
return lineMap.add(column, sourceLocation, options);
|
||||
}
|
||||
|
||||
sourceLocation(arg) {
|
||||
var column, line, lineMap;
|
||||
line = arg[0], column = arg[1];
|
||||
while (!((lineMap = this.lines[line]) || (line <= 0))) {
|
||||
line--;
|
||||
}
|
||||
return lineMap && lineMap.sourceLocation(column);
|
||||
}
|
||||
|
||||
generate(options = {}, code = null) {
|
||||
var buffer, i, j, lastColumn, lastSourceColumn, lastSourceLine, len, len1, lineMap, lineNumber, mapping, needComma, ref, ref1, v3, writingline;
|
||||
writingline = 0;
|
||||
lastColumn = 0;
|
||||
lastSourceLine = 0;
|
||||
lastSourceColumn = 0;
|
||||
needComma = false;
|
||||
buffer = "";
|
||||
ref = this.lines;
|
||||
for (lineNumber = i = 0, len = ref.length; i < len; lineNumber = ++i) {
|
||||
lineMap = ref[lineNumber];
|
||||
if (lineMap) {
|
||||
ref1 = lineMap.columns;
|
||||
for (j = 0, len1 = ref1.length; j < len1; j++) {
|
||||
mapping = ref1[j];
|
||||
if (!(mapping)) {
|
||||
continue;
|
||||
}
|
||||
while (writingline < mapping.line) {
|
||||
lastColumn = 0;
|
||||
needComma = false;
|
||||
buffer += ";";
|
||||
writingline++;
|
||||
}
|
||||
if (needComma) {
|
||||
buffer += ",";
|
||||
needComma = false;
|
||||
}
|
||||
buffer += this.encodeVlq(mapping.column - lastColumn);
|
||||
lastColumn = mapping.column;
|
||||
buffer += this.encodeVlq(0);
|
||||
buffer += this.encodeVlq(mapping.sourceLine - lastSourceLine);
|
||||
lastSourceLine = mapping.sourceLine;
|
||||
buffer += this.encodeVlq(mapping.sourceColumn - lastSourceColumn);
|
||||
lastSourceColumn = mapping.sourceColumn;
|
||||
needComma = true;
|
||||
}
|
||||
while (writingline < mapping.line) {
|
||||
lastColumn = 0;
|
||||
needComma = false;
|
||||
buffer += ";";
|
||||
writingline++;
|
||||
}
|
||||
if (needComma) {
|
||||
buffer += ",";
|
||||
needComma = false;
|
||||
}
|
||||
buffer += this.encodeVlq(mapping.column - lastColumn);
|
||||
lastColumn = mapping.column;
|
||||
buffer += this.encodeVlq(0);
|
||||
buffer += this.encodeVlq(mapping.sourceLine - lastSourceLine);
|
||||
lastSourceLine = mapping.sourceLine;
|
||||
buffer += this.encodeVlq(mapping.sourceColumn - lastSourceColumn);
|
||||
lastSourceColumn = mapping.sourceColumn;
|
||||
needComma = true;
|
||||
}
|
||||
}
|
||||
v3 = {
|
||||
version: 3,
|
||||
file: options.generatedFile || '',
|
||||
sourceRoot: options.sourceRoot || '',
|
||||
sources: options.sourceFiles || [''],
|
||||
names: [],
|
||||
mappings: buffer
|
||||
};
|
||||
if (options.inlineMap) {
|
||||
v3.sourcesContent = [code];
|
||||
}
|
||||
return v3;
|
||||
}
|
||||
v3 = {
|
||||
version: 3,
|
||||
file: options.generatedFile || '',
|
||||
sourceRoot: options.sourceRoot || '',
|
||||
sources: options.sourceFiles || [''],
|
||||
names: [],
|
||||
mappings: buffer
|
||||
};
|
||||
if (options.inlineMap) {
|
||||
v3.sourcesContent = [code];
|
||||
|
||||
encodeVlq(value) {
|
||||
var answer, nextChunk, signBit, valueToEncode;
|
||||
answer = '';
|
||||
signBit = value < 0 ? 1 : 0;
|
||||
valueToEncode = (Math.abs(value) << 1) + signBit;
|
||||
while (valueToEncode || !answer) {
|
||||
nextChunk = valueToEncode & VLQ_VALUE_MASK;
|
||||
valueToEncode = valueToEncode >> VLQ_SHIFT;
|
||||
if (valueToEncode) {
|
||||
nextChunk |= VLQ_CONTINUATION_BIT;
|
||||
}
|
||||
answer += this.encodeBase64(nextChunk);
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
return v3;
|
||||
|
||||
encodeBase64(value) {
|
||||
return BASE64_CHARS[value] || (function() {
|
||||
throw new Error(`Cannot Base64 encode value: ${value}`);
|
||||
})();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
VLQ_SHIFT = 5;
|
||||
@@ -116,30 +139,8 @@
|
||||
|
||||
VLQ_VALUE_MASK = VLQ_CONTINUATION_BIT - 1;
|
||||
|
||||
SourceMap.prototype.encodeVlq = function(value) {
|
||||
var answer, nextChunk, signBit, valueToEncode;
|
||||
answer = '';
|
||||
signBit = value < 0 ? 1 : 0;
|
||||
valueToEncode = (Math.abs(value) << 1) + signBit;
|
||||
while (valueToEncode || !answer) {
|
||||
nextChunk = valueToEncode & VLQ_VALUE_MASK;
|
||||
valueToEncode = valueToEncode >> VLQ_SHIFT;
|
||||
if (valueToEncode) {
|
||||
nextChunk |= VLQ_CONTINUATION_BIT;
|
||||
}
|
||||
answer += this.encodeBase64(nextChunk);
|
||||
}
|
||||
return answer;
|
||||
};
|
||||
|
||||
BASE64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||||
|
||||
SourceMap.prototype.encodeBase64 = function(value) {
|
||||
return BASE64_CHARS[value] || (function() {
|
||||
throw new Error(`Cannot Base64 encode value: ${value}`);
|
||||
})();
|
||||
};
|
||||
|
||||
return SourceMap;
|
||||
|
||||
})();
|
||||
|
||||
712
src/nodes.coffee
712
src/nodes.coffee
File diff suppressed because it is too large
Load Diff
@@ -449,7 +449,7 @@ test "#1591, #1101: splatted expressions in destructuring assignment must be ass
|
||||
|
||||
test "#1643: splatted accesses in destructuring assignments should not be declared as variables", ->
|
||||
nonce = {}
|
||||
accesses = ['o.a', 'o["a"]', '(o.a)', '(o.a).a', '@o.a', 'C::a', 'C::', 'f().a', 'o?.a', 'o?.a.b', 'f?().a']
|
||||
accesses = ['o.a', 'o["a"]', '(o.a)', '(o.a).a', '@o.a', 'C::a', 'f().a', 'o?.a', 'o?.a.b', 'f?().a']
|
||||
for access in accesses
|
||||
for i,j in [1,2,3] #position can matter
|
||||
code =
|
||||
|
||||
@@ -191,3 +191,20 @@ test "implicit call with `await`", ->
|
||||
|
||||
a = addOne await 3
|
||||
eq a, 4
|
||||
|
||||
test "async methods in classes", ->
|
||||
class Base
|
||||
@static: ->
|
||||
await 1
|
||||
method: ->
|
||||
await 2
|
||||
|
||||
eq await Base.static(), 1
|
||||
eq await new Base().method(), 2
|
||||
|
||||
class Child extends Base
|
||||
@static: -> super
|
||||
method: -> super
|
||||
|
||||
eq await Child.static(), 1
|
||||
eq await new Child().method(), 2
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
# * Class Definition
|
||||
# * Class Instantiation
|
||||
# * Inheritance and Super
|
||||
# * ES2015+ Class Interoperability
|
||||
|
||||
test "classes with a four-level inheritance chain", ->
|
||||
|
||||
@@ -26,7 +27,9 @@ test "classes with a four-level inheritance chain", ->
|
||||
@array = [1, 2, 3]
|
||||
|
||||
class ThirdChild extends SecondChild
|
||||
constructor: -> thirdCtor.call this
|
||||
constructor: ->
|
||||
super()
|
||||
thirdCtor.call this
|
||||
|
||||
# Gratuitous comment for testing.
|
||||
func: (string) ->
|
||||
@@ -66,25 +69,6 @@ test "constructors with inheritance and super", ->
|
||||
ok (new SubClass).prop is 'top-super-sub'
|
||||
|
||||
|
||||
test "Overriding the static property new doesn't clobber Function::new", ->
|
||||
|
||||
class OneClass
|
||||
@new: 'new'
|
||||
function: 'function'
|
||||
constructor: (name) -> @name = name
|
||||
|
||||
class TwoClass extends OneClass
|
||||
delete TwoClass.new
|
||||
|
||||
Function.prototype.new = -> new this arguments...
|
||||
|
||||
ok (TwoClass.new('three')).name is 'three'
|
||||
ok (new OneClass).function is 'function'
|
||||
ok OneClass.new is 'new'
|
||||
|
||||
delete Function.prototype.new
|
||||
|
||||
|
||||
test "basic classes, again, but in the manual prototype style", ->
|
||||
|
||||
Base = ->
|
||||
@@ -464,7 +448,7 @@ test "ensure that constructors invoked with splats return a new object", ->
|
||||
# Ensure that constructors invoked with splats cache the function.
|
||||
called = 0
|
||||
get = -> if called++ then false else class Type
|
||||
new get() args...
|
||||
new (get()) args...
|
||||
|
||||
test "`new` shouldn't add extra parens", ->
|
||||
|
||||
@@ -480,6 +464,7 @@ test "`new` works against bare function", ->
|
||||
test "#1182: a subclass should be able to set its constructor to an external function", ->
|
||||
ctor = ->
|
||||
@val = 1
|
||||
return
|
||||
class A
|
||||
class B extends A
|
||||
constructor: ctor
|
||||
@@ -498,7 +483,7 @@ test "#1313: misplaced __extends", ->
|
||||
class A
|
||||
class B extends A
|
||||
prop: nonce
|
||||
constructor: ->
|
||||
constructor: -> super
|
||||
eq nonce, B::prop
|
||||
|
||||
test "#1182: execution order needs to be considered as well", ->
|
||||
@@ -738,21 +723,21 @@ test "#2599: other typed constructors should be inherited", ->
|
||||
ok (new Derived) not instanceof Base
|
||||
ok (new Base) not instanceof Base
|
||||
|
||||
test "#2359: extending native objects that use other typed constructors requires defining a constructor", ->
|
||||
class BrokenArray extends Array
|
||||
method: -> 'no one will call me'
|
||||
test "extending native objects works with and without defining a constructor", ->
|
||||
class MyArray extends Array
|
||||
method: -> 'yes!'
|
||||
|
||||
brokenArray = new BrokenArray
|
||||
ok brokenArray not instanceof BrokenArray
|
||||
ok typeof brokenArray.method is 'undefined'
|
||||
myArray = new MyArray
|
||||
ok myArray instanceof MyArray
|
||||
ok 'yes!', myArray.method()
|
||||
|
||||
class WorkingArray extends Array
|
||||
class OverrideArray extends Array
|
||||
constructor: -> super
|
||||
method: -> 'yes!'
|
||||
|
||||
workingArray = new WorkingArray
|
||||
ok workingArray instanceof WorkingArray
|
||||
eq 'yes!', workingArray.method()
|
||||
overrideArray = new OverrideArray
|
||||
ok overrideArray instanceof OverrideArray
|
||||
eq 'yes!', overrideArray.method()
|
||||
|
||||
|
||||
test "#2782: non-alphanumeric-named bound functions", ->
|
||||
@@ -855,7 +840,7 @@ test "#1392 calling `super` in methods defined on namespaced classes", ->
|
||||
eq 1, count
|
||||
|
||||
class C
|
||||
@a: ->
|
||||
@a: (->)
|
||||
@a extends Base
|
||||
@a::m = -> super
|
||||
eq 5, (new C.a).m()
|
||||
@@ -898,3 +883,811 @@ test "dynamic method names and super", ->
|
||||
class C extends B
|
||||
m: -> super
|
||||
eq 5, (new C).m()
|
||||
|
||||
# ES2015+ class interoperability
|
||||
# Based on https://github.com/balupton/es6-javascript-class-interop
|
||||
# Helper functions to generate true ES classes to extend:
|
||||
getBasicClass = ->
|
||||
```
|
||||
class BasicClass {
|
||||
constructor (greeting) {
|
||||
this.greeting = greeting || 'hi'
|
||||
}
|
||||
}
|
||||
```
|
||||
BasicClass
|
||||
|
||||
getExtendedClass = (BaseClass) ->
|
||||
```
|
||||
class ExtendedClass extends BaseClass {
|
||||
constructor (greeting, name) {
|
||||
super(greeting || 'hello')
|
||||
this.name = name
|
||||
}
|
||||
}
|
||||
```
|
||||
ExtendedClass
|
||||
|
||||
test "can instantiate a basic ES class", ->
|
||||
BasicClass = getBasicClass()
|
||||
i = new BasicClass 'howdy!'
|
||||
eq i.greeting, 'howdy!'
|
||||
|
||||
test "can instantiate an extended ES class", ->
|
||||
BasicClass = getBasicClass()
|
||||
ExtendedClass = getExtendedClass BasicClass
|
||||
i = new ExtendedClass 'yo', 'buddy'
|
||||
eq i.greeting, 'yo'
|
||||
eq i.name, 'buddy'
|
||||
|
||||
test "can extend a basic ES class", ->
|
||||
BasicClass = getBasicClass()
|
||||
class ExtendedClass extends BasicClass
|
||||
constructor: (@name) ->
|
||||
super()
|
||||
i = new ExtendedClass 'dude'
|
||||
eq i.name, 'dude'
|
||||
|
||||
test "can extend an extended ES class", ->
|
||||
BasicClass = getBasicClass()
|
||||
ExtendedClass = getExtendedClass BasicClass
|
||||
|
||||
class ExtendedExtendedClass extends ExtendedClass
|
||||
constructor: (@value) ->
|
||||
super()
|
||||
getDoubledValue: ->
|
||||
@value * 2
|
||||
|
||||
i = new ExtendedExtendedClass 7
|
||||
eq i.getDoubledValue(), 14
|
||||
|
||||
test "CoffeeScript class can be extended in ES", ->
|
||||
class CoffeeClass
|
||||
constructor: (@favoriteDrink = 'latte', @size = 'grande') ->
|
||||
getDrinkOrder: ->
|
||||
"#{@size} #{@favoriteDrink}"
|
||||
|
||||
```
|
||||
class ECMAScriptClass extends CoffeeClass {
|
||||
constructor (favoriteDrink) {
|
||||
super(favoriteDrink);
|
||||
this.favoriteDrink = this.favoriteDrink + ' with a dash of semicolons';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
e = new ECMAScriptClass 'coffee'
|
||||
eq e.getDrinkOrder(), 'grande coffee with a dash of semicolons'
|
||||
|
||||
test "extended CoffeeScript class can be extended in ES", ->
|
||||
class CoffeeClass
|
||||
constructor: (@favoriteDrink = 'latte') ->
|
||||
|
||||
class CoffeeClassWithDrinkOrder extends CoffeeClass
|
||||
constructor: (@favoriteDrink, @size = 'grande') ->
|
||||
super()
|
||||
getDrinkOrder: ->
|
||||
"#{@size} #{@favoriteDrink}"
|
||||
|
||||
```
|
||||
class ECMAScriptClass extends CoffeeClassWithDrinkOrder {
|
||||
constructor (favoriteDrink) {
|
||||
super(favoriteDrink);
|
||||
this.favoriteDrink = this.favoriteDrink + ' with a dash of semicolons';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
e = new ECMAScriptClass 'coffee'
|
||||
eq e.getDrinkOrder(), 'grande coffee with a dash of semicolons'
|
||||
|
||||
test "`this` access after `super` in extended classes", ->
|
||||
class Base
|
||||
|
||||
class Test extends Base
|
||||
constructor: (param, @param) ->
|
||||
eq param, nonce
|
||||
|
||||
result = { super: super(), @param, @method }
|
||||
eq result.super, this
|
||||
eq result.param, @param
|
||||
eq result.method, @method
|
||||
ok result.method isnt Test::method
|
||||
|
||||
method: =>
|
||||
|
||||
nonce = {}
|
||||
new Test nonce, {}
|
||||
|
||||
test "`@`-params and bound methods with multiple `super` paths (blocks)", ->
|
||||
nonce = {}
|
||||
|
||||
class Base
|
||||
constructor: (@name) ->
|
||||
|
||||
class Test extends Base
|
||||
constructor: (param, @param) ->
|
||||
if param
|
||||
super 'param'
|
||||
eq @name, 'param'
|
||||
else
|
||||
super 'not param'
|
||||
eq @name, 'not param'
|
||||
eq @param, nonce
|
||||
ok @method isnt Test::method
|
||||
method: =>
|
||||
new Test true, nonce
|
||||
new Test false, nonce
|
||||
|
||||
|
||||
test "`@`-params and bound methods with multiple `super` paths (expressions)", ->
|
||||
nonce = {}
|
||||
|
||||
class Base
|
||||
constructor: (@name) ->
|
||||
|
||||
class Test extends Base
|
||||
constructor: (param, @param) ->
|
||||
# Contrived example: force each path into an expression with inline assertions
|
||||
if param
|
||||
result = (
|
||||
eq (super 'param'), @;
|
||||
eq @name, 'param';
|
||||
eq @param, nonce;
|
||||
ok @method isnt Test::method
|
||||
)
|
||||
else
|
||||
result = (
|
||||
eq (super 'not param'), @;
|
||||
eq @name, 'not param';
|
||||
eq @param, nonce;
|
||||
ok @method isnt Test::method
|
||||
)
|
||||
method: =>
|
||||
new Test true, nonce
|
||||
new Test false, nonce
|
||||
|
||||
test "constructor super in arrow functions", ->
|
||||
class Test extends (class)
|
||||
constructor: (@param) ->
|
||||
do => super
|
||||
eq @param, nonce
|
||||
|
||||
new Test nonce = {}
|
||||
|
||||
# Ensure that we always throw if we experience more than one super()
|
||||
# call in a constructor. This ends up being a runtime error.
|
||||
# Should be caught at compile time.
|
||||
test "multiple super calls", ->
|
||||
throwsA = """
|
||||
class A
|
||||
constructor: (@drink) ->
|
||||
make: -> "Making a #{@drink}"
|
||||
|
||||
class MultiSuper extends A
|
||||
constructor: (drink) ->
|
||||
super(drink)
|
||||
super(drink)
|
||||
@newDrink = drink
|
||||
new MultiSuper('Late').make()
|
||||
"""
|
||||
throws -> CoffeeScript.run throwsA, bare: yes
|
||||
|
||||
# Basic test to ensure we can pass @params in a constuctor and
|
||||
# inheritance works correctly
|
||||
test "@ params", ->
|
||||
class A
|
||||
constructor: (@drink, @shots, @flavor) ->
|
||||
make: -> "Making a #{@flavor} #{@drink} with #{@shots} shot(s)"
|
||||
|
||||
a = new A('Machiato', 2, 'chocolate')
|
||||
eq a.make(), "Making a chocolate Machiato with 2 shot(s)"
|
||||
|
||||
class B extends A
|
||||
b = new B('Machiato', 2, 'chocolate')
|
||||
eq b.make(), "Making a chocolate Machiato with 2 shot(s)"
|
||||
|
||||
# Ensure we can accept @params with default parameters in a constructor
|
||||
test "@ params with defaults in a constructor", ->
|
||||
class A
|
||||
# Multiple @ params with defaults
|
||||
constructor: (@drink = 'Americano', @shots = '1', @flavor = 'caramel') ->
|
||||
make: -> "Making a #{@flavor} #{@drink} with #{@shots} shot(s)"
|
||||
|
||||
a = new A()
|
||||
eq a.make(), "Making a caramel Americano with 1 shot(s)"
|
||||
|
||||
# Ensure we can handle default constructors with class params
|
||||
test "@ params with class params", ->
|
||||
class Beverage
|
||||
drink: 'Americano'
|
||||
shots: '1'
|
||||
flavor: 'caramel'
|
||||
|
||||
class A
|
||||
# Class creation as a default param with `this`
|
||||
constructor: (@drink = new Beverage()) ->
|
||||
a = new A()
|
||||
eq a.drink.drink, 'Americano'
|
||||
|
||||
beverage = new Beverage
|
||||
class B
|
||||
# class costruction with a default external param
|
||||
constructor: (@drink = beverage) ->
|
||||
|
||||
b = new B()
|
||||
eq b.drink.drink, 'Americano'
|
||||
|
||||
class C
|
||||
# Default constructor with anonymous empty class
|
||||
constructor: (@meta = class) ->
|
||||
c = new C()
|
||||
ok c.meta instanceof Function
|
||||
|
||||
test "@ params without super, including errors", ->
|
||||
classA = """
|
||||
class A
|
||||
constructor: (@drink) ->
|
||||
make: -> "Making a #{@drink}"
|
||||
a = new A('Machiato')
|
||||
"""
|
||||
|
||||
throwsB = """
|
||||
class B extends A
|
||||
#implied super
|
||||
constructor: (@drink) ->
|
||||
b = new B('Machiato')
|
||||
"""
|
||||
throws -> CoffeeScript.compile classA + throwsB, bare: yes
|
||||
|
||||
test "@ params super race condition", ->
|
||||
classA = """
|
||||
class A
|
||||
constructor: (@drink) ->
|
||||
make: -> "Making a #{@drink}"
|
||||
"""
|
||||
|
||||
throwsB = """
|
||||
class B extends A
|
||||
constructor: (@params) ->
|
||||
|
||||
b = new B('Machiato')
|
||||
"""
|
||||
throws -> CoffeeScript.compile classA + throwsB, bare: yes
|
||||
|
||||
# Race condition with @ and super
|
||||
throwsC = """
|
||||
class C extends A
|
||||
constructor: (@params) ->
|
||||
super(@params)
|
||||
|
||||
c = new C('Machiato')
|
||||
"""
|
||||
throws -> CoffeeScript.compile classA + throwsC, bare: yes
|
||||
|
||||
|
||||
test "@ with super call", ->
|
||||
class D
|
||||
make: -> "Making a #{@drink}"
|
||||
|
||||
class E extends D
|
||||
constructor: (@drink) ->
|
||||
super()
|
||||
|
||||
e = new E('Machiato')
|
||||
eq e.make(), "Making a Machiato"
|
||||
|
||||
test "@ with splats and super call", ->
|
||||
class A
|
||||
make: -> "Making a #{@drink}"
|
||||
|
||||
class B extends A
|
||||
constructor: (@drink...) ->
|
||||
super()
|
||||
|
||||
B = new B('Machiato')
|
||||
eq B.make(), "Making a Machiato"
|
||||
|
||||
|
||||
test "super and external constructors", ->
|
||||
# external constructor with @ param is allowed
|
||||
ctorA = (@drink) ->
|
||||
class A
|
||||
constructor: ctorA
|
||||
make: -> "Making a #{@drink}"
|
||||
a = new A('Machiato')
|
||||
eq a.make(), "Making a Machiato"
|
||||
|
||||
# External constructor with super
|
||||
throwsC = """
|
||||
class B
|
||||
constructor: (@drink) ->
|
||||
make: -> "Making a #{@drink}"
|
||||
|
||||
ctorC = (drink) ->
|
||||
super(drink)
|
||||
|
||||
class C extends B
|
||||
constructor: ctorC
|
||||
c = new C('Machiato')
|
||||
"""
|
||||
throws -> CoffeeScript.compile throwsC, bare: yes
|
||||
|
||||
|
||||
test "super in external prototype", ->
|
||||
class A
|
||||
constructor: (@drink) ->
|
||||
make: -> "Making a #{@drink}"
|
||||
|
||||
class B extends A
|
||||
B::make = (@flavor) -> super() + " with #{@flavor}"
|
||||
b = new B('Machiato')
|
||||
eq b.make('caramel'), "Making a Machiato with caramel"
|
||||
|
||||
# Fails, bound
|
||||
# TODO: Could this throw a compile error?
|
||||
class C extends A
|
||||
C::make = (@flavor) => super() + " with #{@flavor}"
|
||||
c = new C('Machiato')
|
||||
ok c.make('caramel') isnt "Making a Machiato with caramel"
|
||||
|
||||
|
||||
test "bound functions without super", ->
|
||||
# Bound function with @
|
||||
# Throw on compile, since bound
|
||||
# constructors are illegal
|
||||
throwsA = """
|
||||
class A
|
||||
constructor: (drink) =>
|
||||
@drink = drink
|
||||
|
||||
"""
|
||||
throws -> CoffeeScript.compile throwsA, bare: yes
|
||||
|
||||
test "super in a bound function in a constructor", ->
|
||||
throwsB = """
|
||||
class A
|
||||
class B extends A
|
||||
constructor: do => super
|
||||
"""
|
||||
throws -> CoffeeScript.compile throwsB, bare: yes
|
||||
|
||||
test "super in a bound function", ->
|
||||
class A
|
||||
constructor: (@drink) ->
|
||||
make: -> "Making a #{@drink}"
|
||||
|
||||
class B extends A
|
||||
make: (@flavor) =>
|
||||
super + " with #{@flavor}"
|
||||
|
||||
b = new B('Machiato')
|
||||
eq b.make('vanilla'), "Making a Machiato with vanilla"
|
||||
|
||||
# super in a bound function in a bound function
|
||||
class C extends A
|
||||
make: (@flavor) =>
|
||||
func = () =>
|
||||
super + " with #{@flavor}"
|
||||
func()
|
||||
|
||||
c = new C('Machiato')
|
||||
eq c.make('vanilla'), "Making a Machiato with vanilla"
|
||||
|
||||
# bound function in a constructor
|
||||
class D extends A
|
||||
constructor: (drink) ->
|
||||
super(drink)
|
||||
x = =>
|
||||
eq @drink, "Machiato"
|
||||
x()
|
||||
d = new D('Machiato')
|
||||
eq d.make(), "Making a Machiato"
|
||||
|
||||
# duplicate
|
||||
test "super in a try/catch", ->
|
||||
classA = """
|
||||
class A
|
||||
constructor: (param) ->
|
||||
throw "" unless param
|
||||
"""
|
||||
|
||||
throwsB = """
|
||||
class B extends A
|
||||
constructor: ->
|
||||
try
|
||||
super
|
||||
"""
|
||||
|
||||
throwsC = """
|
||||
ctor = ->
|
||||
try
|
||||
super
|
||||
|
||||
class C extends A
|
||||
constructor: ctor
|
||||
"""
|
||||
throws -> CoffeeScript.run classA + throwsB, bare: yes
|
||||
throws -> CoffeeScript.run classA + throwsC, bare: yes
|
||||
|
||||
test "mixed ES6 and CS6 classes with a four-level inheritance chain", ->
|
||||
# Extended test
|
||||
# ES2015+ class interoperability
|
||||
|
||||
```
|
||||
class Base {
|
||||
constructor (greeting) {
|
||||
this.greeting = greeting || 'hi';
|
||||
}
|
||||
func (string) {
|
||||
return 'zero/' + string;
|
||||
}
|
||||
static staticFunc (string) {
|
||||
return 'static/' + string;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
class FirstChild extends Base
|
||||
func: (string) ->
|
||||
super('one/') + string
|
||||
|
||||
|
||||
```
|
||||
class SecondChild extends FirstChild {
|
||||
func (string) {
|
||||
return super.func('two/' + string);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
thirdCtor = ->
|
||||
@array = [1, 2, 3]
|
||||
|
||||
class ThirdChild extends SecondChild
|
||||
constructor: ->
|
||||
super()
|
||||
thirdCtor.call this
|
||||
func: (string) ->
|
||||
super('three/') + string
|
||||
|
||||
result = (new ThirdChild).func 'four'
|
||||
ok result is 'zero/one/two/three/four'
|
||||
ok Base.staticFunc('word') is 'static/word'
|
||||
|
||||
# exercise extends in a nested class
|
||||
test "nested classes with super", ->
|
||||
class Outer
|
||||
constructor: ->
|
||||
@label = 'outer'
|
||||
|
||||
class @Inner
|
||||
constructor: ->
|
||||
@label = 'inner'
|
||||
|
||||
class @ExtendedInner extends @Inner
|
||||
constructor: ->
|
||||
tmp = super()
|
||||
@label = tmp.label + ' extended'
|
||||
|
||||
@extender: () =>
|
||||
class ExtendedSelf extends @
|
||||
constructor: ->
|
||||
tmp = super()
|
||||
@label = tmp.label + ' from this'
|
||||
new ExtendedSelf
|
||||
|
||||
eq (new Outer).label, 'outer'
|
||||
eq (new Outer.Inner).label, 'inner'
|
||||
eq (new Outer.ExtendedInner).label, 'inner extended'
|
||||
eq (Outer.extender()).label, 'outer from this'
|
||||
|
||||
test "Static methods generate 'static' keywords", ->
|
||||
compile = """
|
||||
class CheckStatic
|
||||
constructor: (@drink) ->
|
||||
@className: -> 'CheckStatic'
|
||||
|
||||
c = new CheckStatic('Machiato')
|
||||
"""
|
||||
result = CoffeeScript.compile compile, bare: yes
|
||||
ok result.match(' static ')
|
||||
|
||||
test "Static methods in nested classes", ->
|
||||
class Outer
|
||||
@name: -> 'Outer'
|
||||
|
||||
class @Inner
|
||||
@name: -> 'Inner'
|
||||
|
||||
eq Outer.name(), 'Outer'
|
||||
eq Outer.Inner.name(), 'Inner'
|
||||
|
||||
|
||||
test "mixed constructors with inheritance and ES6 super", ->
|
||||
identity = (f) -> f
|
||||
|
||||
class TopClass
|
||||
constructor: (arg) ->
|
||||
@prop = 'top-' + arg
|
||||
|
||||
```
|
||||
class SuperClass extends TopClass {
|
||||
constructor (arg) {
|
||||
identity(super('super-' + arg));
|
||||
}
|
||||
}
|
||||
```
|
||||
class SubClass extends SuperClass
|
||||
constructor: ->
|
||||
identity super 'sub'
|
||||
|
||||
ok (new SubClass).prop is 'top-super-sub'
|
||||
|
||||
test "ES6 static class methods can be overriden", ->
|
||||
class A
|
||||
@name: -> 'A'
|
||||
|
||||
class B extends A
|
||||
@name: -> 'B'
|
||||
|
||||
eq A.name(), 'A'
|
||||
eq B.name(), 'B'
|
||||
|
||||
# If creating static by direct assignment rather than ES6 static keyword
|
||||
test "ES6 Static methods should set `this` to undefined // ES6 ", ->
|
||||
class A
|
||||
@test: ->
|
||||
eq this, undefined
|
||||
|
||||
# Ensure that our object prototypes work with ES6
|
||||
test "ES6 prototypes can be overriden", ->
|
||||
class A
|
||||
className: 'classA'
|
||||
|
||||
```
|
||||
class B {
|
||||
test () {return "B";};
|
||||
}
|
||||
```
|
||||
b = new B
|
||||
a = new A
|
||||
eq a.className, 'classA'
|
||||
eq b.test(), 'B'
|
||||
Object.setPrototypeOf(b, a)
|
||||
eq b.className, 'classA'
|
||||
# This shouldn't throw,
|
||||
# as we only change inheritance not object construction
|
||||
# This may be an issue with ES, rather than CS construction?
|
||||
#eq b.test(), 'B'
|
||||
|
||||
class D extends B
|
||||
B::test = () -> 'D'
|
||||
eq (new D).test(), 'D'
|
||||
|
||||
# TODO: implement this error check
|
||||
# test "ES6 conformance to extending non-classes", ->
|
||||
# A = (@title) ->
|
||||
# 'Title: ' + @
|
||||
|
||||
# class B extends A
|
||||
# b = new B('caffeinated')
|
||||
# eq b.title, 'caffeinated'
|
||||
|
||||
# # Check inheritance chain
|
||||
# A::getTitle = () -> @title
|
||||
# eq b.getTitle(), 'caffeinated'
|
||||
|
||||
# throwsC = """
|
||||
# C = {title: 'invalid'}
|
||||
# class D extends {}
|
||||
# """
|
||||
# # This should catch on compile and message should be "class can only extend classes and functions."
|
||||
# throws -> CoffeeScript.run throwsC, bare: yes
|
||||
|
||||
# TODO: Evaluate future compliance with "strict mode";
|
||||
# test "Class function environment should be in `strict mode`, ie as if 'use strict' was in use", ->
|
||||
# class A
|
||||
# # this might be a meaningless test, since these are likely to be runtime errors and different
|
||||
# # for every browser. Thoughts?
|
||||
# constructor: () ->
|
||||
# # Ivalid: prop reassignment
|
||||
# @state = {prop: [1], prop: {a: 'a'}}
|
||||
# # eval reassignment
|
||||
# @badEval = eval;
|
||||
|
||||
# # Should throw, but doesn't
|
||||
# a = new A
|
||||
|
||||
# TODO: new.target needs support Separate issue
|
||||
# test "ES6 support for new.target (functions and constructors)", ->
|
||||
# throwsA = """
|
||||
# class A
|
||||
# constructor: () ->
|
||||
# a = new.target.name
|
||||
# """
|
||||
# throws -> CoffeeScript.compile throwsA, bare: yes
|
||||
|
||||
test "only one method named constructor allowed", ->
|
||||
throwsA = """
|
||||
class A
|
||||
constructor: (@first) ->
|
||||
constructor: (@last) ->
|
||||
"""
|
||||
throws -> CoffeeScript.compile throwsA, bare: yes
|
||||
|
||||
test "If the constructor of a child class does not call super,it should return an object.", ->
|
||||
nonce = {}
|
||||
|
||||
class A
|
||||
class B extends A
|
||||
constructor: ->
|
||||
return nonce
|
||||
|
||||
eq nonce, new B
|
||||
|
||||
|
||||
test "super can only exist in extended classes", ->
|
||||
throwsA = """
|
||||
class A
|
||||
constructor: (@name) ->
|
||||
super()
|
||||
"""
|
||||
throws -> CoffeeScript.compile throwsA, bare: yes
|
||||
|
||||
# --- CS1 classes compatability breaks ---
|
||||
test "CS6 Class extends a CS1 compiled class", ->
|
||||
```
|
||||
// Generated by CoffeeScript 1.11.1
|
||||
var BaseCS1, ExtendedCS1,
|
||||
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||
hasProp = {}.hasOwnProperty;
|
||||
|
||||
BaseCS1 = (function() {
|
||||
function BaseCS1(drink) {
|
||||
this.drink = drink;
|
||||
}
|
||||
|
||||
BaseCS1.prototype.make = function() {
|
||||
return "making a " + this.drink;
|
||||
};
|
||||
|
||||
BaseCS1.className = function() {
|
||||
return 'BaseCS1';
|
||||
};
|
||||
|
||||
return BaseCS1;
|
||||
|
||||
})();
|
||||
|
||||
ExtendedCS1 = (function(superClass) {
|
||||
extend(ExtendedCS1, superClass);
|
||||
|
||||
function ExtendedCS1(flavor) {
|
||||
this.flavor = flavor;
|
||||
ExtendedCS1.__super__.constructor.call(this, 'cafe ole');
|
||||
}
|
||||
|
||||
ExtendedCS1.prototype.make = function() {
|
||||
return "making a " + this.drink + " with " + this.flavor;
|
||||
};
|
||||
|
||||
ExtendedCS1.className = function() {
|
||||
return 'ExtendedCS1';
|
||||
};
|
||||
|
||||
return ExtendedCS1;
|
||||
|
||||
})(BaseCS1);
|
||||
|
||||
```
|
||||
class B extends BaseCS1
|
||||
eq B.className(), 'BaseCS1'
|
||||
b = new B('machiato')
|
||||
eq b.make(), "making a machiato"
|
||||
|
||||
|
||||
test "CS6 Class extends an extended CS1 compiled class", ->
|
||||
```
|
||||
// Generated by CoffeeScript 1.11.1
|
||||
var BaseCS1, ExtendedCS1,
|
||||
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||
hasProp = {}.hasOwnProperty;
|
||||
|
||||
BaseCS1 = (function() {
|
||||
function BaseCS1(drink) {
|
||||
this.drink = drink;
|
||||
}
|
||||
|
||||
BaseCS1.prototype.make = function() {
|
||||
return "making a " + this.drink;
|
||||
};
|
||||
|
||||
BaseCS1.className = function() {
|
||||
return 'BaseCS1';
|
||||
};
|
||||
|
||||
return BaseCS1;
|
||||
|
||||
})();
|
||||
|
||||
ExtendedCS1 = (function(superClass) {
|
||||
extend(ExtendedCS1, superClass);
|
||||
|
||||
function ExtendedCS1(flavor) {
|
||||
this.flavor = flavor;
|
||||
ExtendedCS1.__super__.constructor.call(this, 'cafe ole');
|
||||
}
|
||||
|
||||
ExtendedCS1.prototype.make = function() {
|
||||
return "making a " + this.drink + " with " + this.flavor;
|
||||
};
|
||||
|
||||
ExtendedCS1.className = function() {
|
||||
return 'ExtendedCS1';
|
||||
};
|
||||
|
||||
return ExtendedCS1;
|
||||
|
||||
})(BaseCS1);
|
||||
|
||||
```
|
||||
class B extends ExtendedCS1
|
||||
eq B.className(), 'ExtendedCS1'
|
||||
b = new B('vanilla')
|
||||
eq b.make(), "making a cafe ole with vanilla"
|
||||
|
||||
test "CS6 Class extends a CS1 compiled class with super()", ->
|
||||
```
|
||||
// Generated by CoffeeScript 1.11.1
|
||||
var BaseCS1, ExtendedCS1,
|
||||
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||
hasProp = {}.hasOwnProperty;
|
||||
|
||||
BaseCS1 = (function() {
|
||||
function BaseCS1(drink) {
|
||||
this.drink = drink;
|
||||
}
|
||||
|
||||
BaseCS1.prototype.make = function() {
|
||||
return "making a " + this.drink;
|
||||
};
|
||||
|
||||
BaseCS1.className = function() {
|
||||
return 'BaseCS1';
|
||||
};
|
||||
|
||||
return BaseCS1;
|
||||
|
||||
})();
|
||||
|
||||
ExtendedCS1 = (function(superClass) {
|
||||
extend(ExtendedCS1, superClass);
|
||||
|
||||
function ExtendedCS1(flavor) {
|
||||
this.flavor = flavor;
|
||||
ExtendedCS1.__super__.constructor.call(this, 'cafe ole');
|
||||
}
|
||||
|
||||
ExtendedCS1.prototype.make = function() {
|
||||
return "making a " + this.drink + " with " + this.flavor;
|
||||
};
|
||||
|
||||
ExtendedCS1.className = function() {
|
||||
return 'ExtendedCS1';
|
||||
};
|
||||
|
||||
return ExtendedCS1;
|
||||
|
||||
})(BaseCS1);
|
||||
|
||||
```
|
||||
class B extends ExtendedCS1
|
||||
constructor: (@shots) ->
|
||||
super('caramel')
|
||||
make: () ->
|
||||
super + " and #{@shots} shots of espresso"
|
||||
|
||||
eq B.className(), 'ExtendedCS1'
|
||||
b = new B('three')
|
||||
eq b.make(), "making a cafe ole with caramel and three shots of espresso"
|
||||
|
||||
@@ -378,11 +378,15 @@ test "#3132: Place block-comments nicely", ->
|
||||
var DummyClass;
|
||||
|
||||
DummyClass = (function() {
|
||||
class DummyClass {
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
function DummyClass() {}
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
|
||||
constructor() {}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -416,7 +416,7 @@ test "#3795: invalid escapes", ->
|
||||
assertErrorFormat '''
|
||||
///a \\u002 0 space///
|
||||
''', '''
|
||||
[stdin]:1:6: error: invalid escape sequence \\u002
|
||||
[stdin]:1:6: error: invalid escape sequence \\u002 \n\
|
||||
///a \\u002 0 space///
|
||||
^\^^^^^
|
||||
'''
|
||||
@@ -1205,3 +1205,45 @@ test "tagged template literals must be called by an identifier", ->
|
||||
1"""#{b}"""
|
||||
^
|
||||
'''
|
||||
|
||||
test "constructor functions can't be async", ->
|
||||
assertErrorFormat 'class then constructor: -> await x', '''
|
||||
[stdin]:1:12: error: Class constructor may not be async
|
||||
class then constructor: -> await x
|
||||
^^^^^^^^^^^
|
||||
'''
|
||||
|
||||
test "constructor functions can't be generators", ->
|
||||
assertErrorFormat 'class then constructor: -> yield', '''
|
||||
[stdin]:1:12: error: Class constructor may not be a generator
|
||||
class then constructor: -> yield
|
||||
^^^^^^^^^^^
|
||||
'''
|
||||
|
||||
test "non-derived constructors can't call super", ->
|
||||
assertErrorFormat 'class then constructor: -> super', '''
|
||||
[stdin]:1:28: error: 'super' is only allowed in derived class constructors
|
||||
class then constructor: -> super
|
||||
^^^^^
|
||||
'''
|
||||
|
||||
test "derived constructors can't reference `this` before calling super", ->
|
||||
assertErrorFormat 'class extends A then constructor: -> @', '''
|
||||
[stdin]:1:38: error: Can't reference 'this' before calling super in derived class constructors
|
||||
class extends A then constructor: -> @
|
||||
^
|
||||
'''
|
||||
|
||||
test "derived constructors can't use @params without calling super", ->
|
||||
assertErrorFormat 'class extends A then constructor: (@a) ->', '''
|
||||
[stdin]:1:36: error: Can't use @params in derived class constructors without calling super
|
||||
class extends A then constructor: (@a) ->
|
||||
^^
|
||||
'''
|
||||
|
||||
test "'super' is not allowed in constructor parameter defaults", ->
|
||||
assertErrorFormat 'class extends A then constructor: (a = super) ->', '''
|
||||
[stdin]:1:40: error: 'super' is not allowed in constructor parameter defaults
|
||||
class extends A then constructor: (a = super) ->
|
||||
^^^^^
|
||||
'''
|
||||
|
||||
@@ -325,3 +325,20 @@ test "from as a destructured array variable name in a for loop declaration", ->
|
||||
for [from, to] from a
|
||||
b.push from
|
||||
arrayEq b, [1, 3]
|
||||
|
||||
test "generator methods in classes", ->
|
||||
class Base
|
||||
@static: ->
|
||||
yield 1
|
||||
method: ->
|
||||
yield 2
|
||||
|
||||
arrayEq [1], Array.from Base.static()
|
||||
arrayEq [2], Array.from new Base().method()
|
||||
|
||||
class Child extends Base
|
||||
@static: -> super
|
||||
method: -> super
|
||||
|
||||
arrayEq [1], Array.from Child.static()
|
||||
arrayEq [2], Array.from new Child().method()
|
||||
|
||||
@@ -457,7 +457,7 @@ test "export class", ->
|
||||
baz: ->
|
||||
console.log 'hello, world!'"""
|
||||
output = toJS input
|
||||
ok /^export (class foo|var foo = \(function)/.test toJS input
|
||||
ok /^export (var foo = class foo|var foo = \(function)/.test toJS input
|
||||
|
||||
test "export class that extends", ->
|
||||
input = """
|
||||
|
||||
@@ -330,7 +330,7 @@ test "floor division operator", ->
|
||||
|
||||
test "floor division operator compound assignment", ->
|
||||
a = 7
|
||||
a //= 2
|
||||
a //= 1 + 1
|
||||
eq 3, a
|
||||
|
||||
test "modulo operator", ->
|
||||
@@ -436,3 +436,27 @@ test "#3598: Unary + and - coerce the operand once when it is an identifier", ->
|
||||
ok ~a in [0, -2]
|
||||
assertOneCoercion (a) ->
|
||||
ok a / 2 in [0, 0.5]
|
||||
|
||||
test "'new' target", ->
|
||||
nonce = {}
|
||||
ctor = -> nonce
|
||||
|
||||
eq (new ctor), nonce
|
||||
eq (new ctor()), nonce
|
||||
|
||||
ok new class
|
||||
|
||||
ctor = class
|
||||
ok (new ctor) instanceof ctor
|
||||
ok (new ctor()) instanceof ctor
|
||||
|
||||
# Force an executable class body
|
||||
ctor = class then a = 1
|
||||
ok (new ctor) instanceof ctor
|
||||
|
||||
get = -> ctor
|
||||
ok (new get()) not instanceof ctor
|
||||
ok (new (get())()) instanceof ctor
|
||||
|
||||
# classes must be called with `new`. In this case `new` applies to `get` only
|
||||
throws -> new get()()
|
||||
|
||||
@@ -8,6 +8,7 @@ Stream = require 'stream'
|
||||
|
||||
class MockInputStream extends Stream
|
||||
constructor: ->
|
||||
super()
|
||||
@readable = true
|
||||
|
||||
resume: ->
|
||||
@@ -17,6 +18,7 @@ class MockInputStream extends Stream
|
||||
|
||||
class MockOutputStream extends Stream
|
||||
constructor: ->
|
||||
super()
|
||||
@writable = true
|
||||
@written = []
|
||||
|
||||
|
||||
Reference in New Issue
Block a user