Merge branch '2' into get-set-warning

# Conflicts:
#	lib/coffeescript/lexer.js
This commit is contained in:
Geoffrey Booth
2017-04-06 10:12:46 -07:00
21 changed files with 1178 additions and 737 deletions

View File

@@ -24,15 +24,10 @@
helpers.extend(global, {
task: function(name, description, action) {
var ref;
if (!action) {
ref = [description, action], action = ref[0], description = ref[1];
[action, description] = [description, action];
}
return tasks[name] = {
name: name,
description: description,
action: action
};
return tasks[name] = {name, description, action};
},
option: function(letter, flag, description) {
return switches.push([letter, flag, description]);

View File

@@ -9,9 +9,9 @@
path = require('path');
Lexer = require('./lexer').Lexer;
({Lexer} = require('./lexer'));
parser = require('./parser').parser;
({parser} = require('./parser'));
helpers = require('./helpers');
@@ -59,7 +59,7 @@
exports.compile = compile = withPrettyErrors(function(code, options) {
var currentColumn, currentLine, encoded, extend, filename, fragment, fragments, generateSourceMap, header, i, j, js, len, len1, map, merge, newLines, ref, ref1, sourceMapDataURI, sourceURL, token, tokens, v3SourceMap;
merge = helpers.merge, extend = helpers.extend;
({merge, extend} = helpers);
options = extend({}, options);
generateSourceMap = options.sourceMap || options.inlineMap || (options.filename == null);
filename = options.filename || '<anonymous>';
@@ -132,7 +132,7 @@
}
if (options.sourceMap) {
return {
js: js,
js,
sourceMap: map,
v3SourceMap: JSON.stringify(v3SourceMap, null, 2)
};
@@ -254,9 +254,9 @@
stripped = raw.charCodeAt(0) === 0xFEFF ? raw.substring(1) : raw;
try {
answer = compile(stripped, {
filename: filename,
sourceMap: sourceMap,
inlineMap: inlineMap,
filename,
sourceMap,
inlineMap,
sourceFiles: [filename],
literate: helpers.isLiterate(filename)
});
@@ -274,7 +274,7 @@
var tag, token;
token = parser.tokens[this.pos++];
if (token) {
tag = token[0], this.yytext = token[1], this.yylloc = token[2];
[tag, this.yytext, this.yylloc] = token;
parser.errorToken = token.origin || token;
this.yylineno = this.yylloc.first_line;
} else {
@@ -293,11 +293,10 @@
parser.yy = require('./nodes');
parser.yy.parseError = function(message, arg) {
var errorLoc, errorTag, errorText, errorToken, token, tokens;
token = arg.token;
errorToken = parser.errorToken, tokens = parser.tokens;
errorTag = errorToken[0], errorText = errorToken[1], errorLoc = errorToken[2];
parser.yy.parseError = function(message, {token}) {
var errorLoc, errorTag, errorText, errorToken, tokens;
({errorToken, tokens} = parser);
[errorTag, errorText, errorLoc] = errorToken;
errorText = (function() {
switch (false) {
case errorToken !== tokens[tokens.length - 1]:

View File

@@ -1,6 +1,6 @@
// Generated by CoffeeScript 2.0.0-alpha1
(function() {
var BANNER, CoffeeScript, EventEmitter, SWITCHES, compileJoin, compileOptions, compilePath, compileScript, compileStdio, exec, findDirectoryIndex, forkNode, fs, helpers, hidden, joinTimeout, makePrelude, mkdirp, notSources, optionParser, optparse, opts, outputPath, parseOptions, path, printLine, printTokens, printWarn, ref, removeSource, removeSourceDir, silentUnlink, sourceCode, sources, spawn, timeLog, usage, useWinPathSep, version, wait, watch, watchDir, watchedDirs, writeJs,
var BANNER, CoffeeScript, EventEmitter, SWITCHES, compileJoin, compileOptions, compilePath, compileScript, compileStdio, exec, findDirectoryIndex, forkNode, fs, helpers, hidden, joinTimeout, makePrelude, mkdirp, notSources, optionParser, optparse, opts, outputPath, parseOptions, path, printLine, printTokens, printWarn, removeSource, removeSourceDir, silentUnlink, sourceCode, sources, spawn, timeLog, usage, useWinPathSep, version, wait, watch, watchDir, watchedDirs, writeJs,
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; };
fs = require('fs');
@@ -13,9 +13,9 @@
CoffeeScript = require('./coffeescript');
ref = require('child_process'), spawn = ref.spawn, exec = ref.exec;
({spawn, exec} = require('child_process'));
EventEmitter = require('events').EventEmitter;
({EventEmitter} = require('events'));
useWinPathSep = path.sep === '\\';
@@ -50,7 +50,7 @@
optionParser = null;
exports.run = function() {
var i, len, literals, ref1, replCliOpts, results, source;
var i, len, literals, ref, replCliOpts, results, source;
parseOptions();
replCliOpts = {
useGlobal: true
@@ -90,10 +90,10 @@
opts.join = path.resolve(opts.join);
console.error('\nThe --join option is deprecated and will be removed in a future version.\n\nIf for some reason it\'s necessary to share local variables between files,\nreplace...\n\n $ coffee --compile --join bundle.js -- a.coffee b.coffee c.coffee\n\nwith...\n\n $ cat a.coffee b.coffee c.coffee | coffee --compile --stdio > bundle.js\n');
}
ref1 = opts["arguments"];
ref = opts["arguments"];
results = [];
for (i = 0, len = ref1.length; i < len; i++) {
source = ref1[i];
for (i = 0, len = ref.length; i < len; i++) {
source = ref[i];
source = path.resolve(source);
results.push(compilePath(source, true, source));
}
@@ -104,7 +104,7 @@
return requires.map(function(module) {
var _, match, name;
if (match = module.match(/^(.*)=(.*)$/)) {
_ = match[0], name = match[1], module = match[2];
[_, name, module] = match;
}
name || (name = helpers.baseFileName(module, true, useWinPathSep));
return `${name} = require('${module}')`;
@@ -178,10 +178,10 @@
};
findDirectoryIndex = function(source) {
var err, ext, i, index, len, ref1;
ref1 = CoffeeScript.FILE_EXTENSIONS;
for (i = 0, len = ref1.length; i < len; i++) {
ext = ref1[i];
var err, ext, i, index, len, ref;
ref = CoffeeScript.FILE_EXTENSIONS;
for (i = 0, len = ref.length; i < len; i++) {
ext = ref[i];
index = path.join(source, `index${ext}`);
try {
if ((fs.statSync(index)).isFile()) {
@@ -203,11 +203,7 @@
o = opts;
options = compileOptions(file, base);
try {
t = task = {
file: file,
input: input,
options: options
};
t = task = {file, input, options};
CoffeeScript.emit('compile', task);
if (o.tokens) {
return printTokens(CoffeeScript.tokens(t.input, t.options));
@@ -425,12 +421,12 @@
};
silentUnlink = function(path) {
var err, ref1;
var err, ref;
try {
return fs.unlinkSync(path);
} catch (error) {
err = error;
if ((ref1 = err.code) !== 'ENOENT' && ref1 !== 'EPERM') {
if ((ref = err.code) !== 'ENOENT' && ref !== 'EPERM') {
throw err;
}
}
@@ -546,7 +542,7 @@
compileOptions = function(filename, base) {
var answer, cwd, jsDir, jsPath;
answer = {
filename: filename,
filename,
literate: opts.literate || helpers.isLiterate(filename),
bare: opts.bare,
header: opts.compile && !opts['no-header'],
@@ -559,7 +555,7 @@
jsPath = outputPath(filename, base);
jsDir = path.dirname(jsPath);
answer = helpers.merge(answer, {
jsPath: jsPath,
jsPath,
sourceRoot: path.relative(jsDir, cwd),
sourceFiles: [path.relative(cwd, filename)],
generatedFile: helpers.baseFileName(jsPath, false, useWinPathSep)

View File

@@ -2,7 +2,7 @@
(function() {
var Parser, alt, alternatives, grammar, name, o, operators, token, tokens, unwrap;
Parser = require('jison').Parser;
({Parser} = require('jison'));
unwrap = /^function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/;

View File

@@ -1,8 +1,8 @@
// Generated by CoffeeScript 2.0.0-alpha1
(function() {
var buildLocationData, extend, flatten, marked, ref, repeat, syntaxErrorToString;
var buildLocationData, extend, flatten, md, ref, repeat, syntaxErrorToString;
marked = require('marked');
md = require('markdown-it')();
exports.starts = function(string, literal, start) {
return literal === string.substr(start, literal.length);
@@ -28,10 +28,10 @@
};
exports.compact = function(array) {
var i, item, len1, results;
var item, j, len1, results;
results = [];
for (i = 0, len1 = array.length; i < len1; i++) {
item = array[i];
for (j = 0, len1 = array.length; j < len1; j++) {
item = array[j];
if (item) {
results.push(item);
}
@@ -65,10 +65,10 @@
};
exports.flatten = flatten = function(array) {
var element, flattened, i, len1;
var element, flattened, j, len1;
flattened = [];
for (i = 0, len1 = array.length; i < len1; i++) {
element = array[i];
for (j = 0, len1 = array.length; j < len1; j++) {
element = array[j];
if ('[object Array]' === Object.prototype.toString.call(element)) {
flattened = flattened.concat(flatten(element));
} else {
@@ -86,10 +86,10 @@
};
exports.some = (ref = Array.prototype.some) != null ? ref : function(fn) {
var e, i, len1, ref1;
var e, j, len1, ref1;
ref1 = this;
for (i = 0, len1 = ref1.length; i < len1; i++) {
e = ref1[i];
for (j = 0, len1 = ref1.length; j < len1; j++) {
e = ref1[j];
if (fn(e)) {
return true;
}
@@ -98,24 +98,23 @@
};
exports.invertLiterate = function(code) {
var generateRandomToken, i, item, len1, out, ref1, token;
generateRandomToken = function() {
return `${Math.random() * Date.now()}`;
};
while (token === void 0 || code.indexOf(token) !== -1) {
token = generateRandomToken();
}
code = code.replace("\t", token);
out = "";
ref1 = marked.lexer(code, {});
for (i = 0, len1 = ref1.length; i < len1; i++) {
item = ref1[i];
if (item.type === 'code') {
out += `${item.text}\n`;
var out;
out = [];
md.renderer.rules = {
code_block: function(tokens, idx) {
var i, j, len1, line, lines, results, startLine;
startLine = tokens[idx].map[0];
lines = tokens[idx].content.split('\n');
results = [];
for (i = j = 0, len1 = lines.length; j < len1; i = ++j) {
line = lines[i];
results.push(out[startLine + i] = line);
}
return results;
}
}
out.replace(token, "\t");
return out;
};
md.render(code);
return out.join('\n');
};
buildLocationData = function(first, last) {
@@ -197,11 +196,11 @@
};
syntaxErrorToString = function() {
var codeLine, colorize, colorsEnabled, end, filename, first_column, first_line, last_column, last_line, marker, ref1, ref2, ref3, ref4, start;
var codeLine, colorize, colorsEnabled, end, filename, first_column, first_line, last_column, last_line, marker, ref1, ref2, ref3, start;
if (!(this.code && this.location)) {
return Error.prototype.toString.call(this);
}
ref1 = this.location, first_line = ref1.first_line, first_column = ref1.first_column, last_line = ref1.last_line, last_column = ref1.last_column;
({first_line, first_column, last_line, last_column} = this.location);
if (last_line == null) {
last_line = first_line;
}
@@ -214,9 +213,9 @@
end = first_line === last_line ? last_column + 1 : codeLine.length;
marker = codeLine.slice(0, start).replace(/[^\s]/g, ' ') + repeat('^', end - start);
if (typeof process !== "undefined" && process !== null) {
colorsEnabled = ((ref2 = process.stdout) != null ? ref2.isTTY : void 0) && !((ref3 = process.env) != null ? ref3.NODE_DISABLE_COLORS : void 0);
colorsEnabled = ((ref1 = process.stdout) != null ? ref1.isTTY : void 0) && !((ref2 = process.env) != null ? ref2.NODE_DISABLE_COLORS : void 0);
}
if ((ref4 = this.colorful) != null ? ref4 : colorsEnabled) {
if ((ref3 = this.colorful) != null ? ref3 : colorsEnabled) {
colorize = function(str) {
return `\x1B[1;31m${str}\x1B[0m`;
};

View File

@@ -1,15 +1,15 @@
// Generated by CoffeeScript 2.0.0-alpha1
(function() {
var BOM, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HERECOMMENT_ILLEGAL, HEREDOC_DOUBLE, HEREDOC_INDENT, HEREDOC_SINGLE, HEREGEX, HEREGEX_OMIT, HERE_JSTOKEN, IDENTIFIER, INDENTABLE_CLOSERS, INDEXABLE, INVALID_ESCAPE, INVERSES, JSTOKEN, JS_KEYWORDS, LEADING_BLANK_LINE, LINE_BREAK, LINE_CONTINUER, Lexer, MATH, MULTI_DENT, NOT_REGEX, NUMBER, OPERATOR, POSSIBLY_DIVISION, REGEX, REGEX_FLAGS, REGEX_ILLEGAL, RELATION, RESERVED, Rewriter, SHIFT, SIMPLE_STRING_OMIT, STRICT_PROSCRIBED, STRING_DOUBLE, STRING_OMIT, STRING_SINGLE, STRING_START, TRAILING_BLANK_LINE, TRAILING_SPACES, UNARY, UNARY_MATH, VALID_FLAGS, WHITESPACE, compact, count, invertLiterate, isForFrom, isUnassignable, key, locationDataToString, ref, ref1, repeat, starts, throwSyntaxError,
var BOM, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HERECOMMENT_ILLEGAL, HEREDOC_DOUBLE, HEREDOC_INDENT, HEREDOC_SINGLE, HEREGEX, HEREGEX_OMIT, HERE_JSTOKEN, IDENTIFIER, INDENTABLE_CLOSERS, INDEXABLE, INVALID_ESCAPE, INVERSES, JSTOKEN, JS_KEYWORDS, LEADING_BLANK_LINE, LINE_BREAK, LINE_CONTINUER, Lexer, MATH, MULTI_DENT, NOT_REGEX, NUMBER, OPERATOR, POSSIBLY_DIVISION, REGEX, REGEX_FLAGS, REGEX_ILLEGAL, RELATION, RESERVED, Rewriter, SHIFT, SIMPLE_STRING_OMIT, STRICT_PROSCRIBED, STRING_DOUBLE, STRING_OMIT, STRING_SINGLE, STRING_START, TRAILING_BLANK_LINE, TRAILING_SPACES, UNARY, UNARY_MATH, VALID_FLAGS, WHITESPACE, compact, count, invertLiterate, isForFrom, isUnassignable, key, locationDataToString, repeat, starts, throwSyntaxError,
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; };
ref = require('./rewriter'), Rewriter = ref.Rewriter, INVERSES = ref.INVERSES;
({Rewriter, INVERSES} = require('./rewriter'));
ref1 = require('./helpers'), count = ref1.count, starts = ref1.starts, compact = ref1.compact, repeat = ref1.repeat, invertLiterate = ref1.invertLiterate, locationDataToString = ref1.locationDataToString, throwSyntaxError = ref1.throwSyntaxError;
({count, starts, compact, repeat, invertLiterate, locationDataToString, throwSyntaxError} = require('./helpers'));
exports.Lexer = Lexer = class Lexer {
tokenize(code, opts = {}) {
var consumed, end, i, ref2;
var consumed, end, i;
this.literate = opts.literate;
this.indent = 0;
this.baseIndent = 0;
@@ -29,7 +29,7 @@
i = 0;
while (this.chunk = code.slice(i)) {
consumed = this.identifierToken() || this.commentToken() || this.whitespaceToken() || this.lineToken() || this.stringToken() || this.numberToken() || this.regexToken() || this.jsToken() || this.literalToken();
ref2 = this.getLineAndColumnFromChunk(consumed), this.chunkLine = ref2[0], this.chunkColumn = ref2[1];
[this.chunkLine, this.chunkColumn] = this.getLineAndColumnFromChunk(consumed);
i += consumed;
if (opts.untilBalanced && this.ends.length === 0) {
return {
@@ -64,11 +64,11 @@
}
identifierToken() {
var alias, colon, colonOffset, id, idLength, input, match, poppedToken, prev, prevprev, ref10, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9, tag, tagToken;
var alias, colon, colonOffset, id, idLength, input, match, poppedToken, prev, prevprev, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, tag, tagToken;
if (!(match = IDENTIFIER.exec(this.chunk))) {
return 0;
}
input = match[0], id = match[1], colon = match[2];
[input, id, colon] = match;
idLength = id.length;
poppedToken = void 0;
if (id === 'own' && this.tag() === 'FOR') {
@@ -82,27 +82,27 @@
if (id === 'as' && this.seenImport) {
if (this.value() === '*') {
this.tokens[this.tokens.length - 1][0] = 'IMPORT_ALL';
} else if (ref2 = this.value(), indexOf.call(COFFEE_KEYWORDS, ref2) >= 0) {
} else if (ref = this.value(), indexOf.call(COFFEE_KEYWORDS, ref) >= 0) {
this.tokens[this.tokens.length - 1][0] = 'IDENTIFIER';
}
if ((ref3 = this.tag()) === 'DEFAULT' || ref3 === 'IMPORT_ALL' || ref3 === 'IDENTIFIER') {
if ((ref1 = this.tag()) === 'DEFAULT' || ref1 === 'IMPORT_ALL' || ref1 === 'IDENTIFIER') {
this.token('AS', id);
return id.length;
}
}
if (id === 'as' && this.seenExport && ((ref4 = this.tag()) === 'IDENTIFIER' || ref4 === 'DEFAULT')) {
if (id === 'as' && this.seenExport && ((ref2 = this.tag()) === 'IDENTIFIER' || ref2 === 'DEFAULT')) {
this.token('AS', id);
return id.length;
}
if (id === 'default' && this.seenExport && ((ref5 = this.tag()) === 'EXPORT' || ref5 === 'AS')) {
if (id === 'default' && this.seenExport && ((ref3 = this.tag()) === 'EXPORT' || ref3 === 'AS')) {
this.token('DEFAULT', id);
return id.length;
}
prev = this.prev();
tag = colon || (prev != null) && (((ref6 = prev[0]) === '.' || ref6 === '?.' || ref6 === '::' || ref6 === '?::') || !prev.spaced && prev[0] === '@') ? 'PROPERTY' : 'IDENTIFIER';
tag = colon || (prev != null) && (((ref4 = prev[0]) === '.' || ref4 === '?.' || ref4 === '::' || ref4 === '?::') || !prev.spaced && prev[0] === '@') ? 'PROPERTY' : 'IDENTIFIER';
if (tag === 'IDENTIFIER' && (indexOf.call(JS_KEYWORDS, id) >= 0 || indexOf.call(COFFEE_KEYWORDS, id) >= 0) && !(this.exportSpecifierList && indexOf.call(COFFEE_KEYWORDS, id) >= 0)) {
tag = id.toUpperCase();
if (tag === 'WHEN' && (ref7 = this.tag(), indexOf.call(LINE_BREAK, ref7) >= 0)) {
if (tag === 'WHEN' && (ref5 = this.tag(), indexOf.call(LINE_BREAK, ref5) >= 0)) {
tag = 'LEADING_WHEN';
} else if (tag === 'FOR') {
this.seenFor = true;
@@ -130,11 +130,11 @@
tag = 'FORFROM';
this.seenFor = false;
} else if (tag === 'PROPERTY' && prev) {
if (prev.spaced && (ref8 = prev[0], indexOf.call(CALLABLE, ref8) >= 0) && /^[gs]et$/.test(prev[1])) {
if (prev.spaced && (ref6 = prev[0], indexOf.call(CALLABLE, ref6) >= 0) && /^[gs]et$/.test(prev[1])) {
this.error(`'${prev[1]}' cannot be used as a keyword, or as a function call without parentheses`, prev[2]);
} else {
prevprev = this.tokens[this.tokens.length - 2];
if (((ref9 = prev[0]) === '@' || ref9 === 'THIS') && prevprev && prevprev.spaced && /^[gs]et$/.test(prevprev[1])) {
if (((ref7 = prev[0]) === '@' || ref7 === 'THIS') && prevprev && prevprev.spaced && /^[gs]et$/.test(prevprev[1])) {
this.error(`'${prevprev[1]}' cannot be used as a keyword, or as a function call without parentheses`, prevprev[2]);
}
}
@@ -176,7 +176,7 @@
tagToken.origin = [tag, alias, tagToken[2]];
}
if (poppedToken) {
ref10 = [poppedToken[2].first_line, poppedToken[2].first_column], tagToken[2].first_line = ref10[0], tagToken[2].first_column = ref10[1];
[tagToken[2].first_line, tagToken[2].first_column] = [poppedToken[2].first_line, poppedToken[2].first_column];
}
if (colon) {
colonOffset = input.lastIndexOf(':');
@@ -232,8 +232,8 @@
}
stringToken() {
var $, attempt, delimiter, doc, end, heredoc, i, indent, indentRegex, match, prev, quote, ref2, ref3, ref4, regex, token, tokens;
quote = (STRING_START.exec(this.chunk) || [])[0];
var $, attempt, delimiter, doc, end, heredoc, i, indent, indentRegex, match, prev, quote, ref, ref1, regex, token, tokens;
[quote] = STRING_START.exec(this.chunk) || [];
if (!quote) {
return 0;
}
@@ -241,7 +241,7 @@
if (prev && this.value() === 'from' && (this.seenImport || this.seenExport)) {
prev[0] = 'FROM';
}
if (prev && prev.spaced && (ref2 = prev[0], indexOf.call(CALLABLE, ref2) >= 0) && /^[gs]et$/.test(prev[1])) {
if (prev && prev.spaced && (ref = prev[0], indexOf.call(CALLABLE, ref) >= 0) && /^[gs]et$/.test(prev[1])) {
this.error(`'${prev[1]}' cannot be used as a keyword, or as a function call without parentheses`, prev[2]);
}
regex = (function() {
@@ -257,7 +257,10 @@
}
})();
heredoc = quote.length === 3;
ref3 = this.matchWithInterpolations(regex, quote), tokens = ref3.tokens, end = ref3.index;
({
tokens,
index: end
} = this.matchWithInterpolations(regex, quote));
$ = tokens.length - 1;
delimiter = quote.charAt(0);
if (heredoc) {
@@ -275,16 +278,14 @@
})()).join('#{}');
while (match = HEREDOC_INDENT.exec(doc)) {
attempt = match[1];
if (indent === null || (0 < (ref4 = attempt.length) && ref4 < indent.length)) {
if (indent === null || (0 < (ref1 = attempt.length) && ref1 < indent.length)) {
indent = attempt;
}
}
if (indent) {
indentRegex = RegExp(`\\n${indent}`, "g");
}
this.mergeInterpolationTokens(tokens, {
delimiter: delimiter
}, (value, i) => {
this.mergeInterpolationTokens(tokens, {delimiter}, (value, i) => {
value = this.formatString(value);
if (indentRegex) {
value = value.replace(indentRegex, '\n');
@@ -298,9 +299,7 @@
return value;
});
} else {
this.mergeInterpolationTokens(tokens, {
delimiter: delimiter
}, (value, i) => {
this.mergeInterpolationTokens(tokens, {delimiter}, (value, i) => {
value = this.formatString(value);
value = value.replace(SIMPLE_STRING_OMIT, function(match, offset) {
if ((i === 0 && offset === 0) || (i === $ && offset + match.length === value.length)) {
@@ -320,7 +319,7 @@
if (!(match = this.chunk.match(COMMENT))) {
return 0;
}
comment = match[0], here = match[1];
[comment, here] = match;
if (here) {
if (match = HERECOMMENT_ILLEGAL.exec(comment)) {
this.error(`block comments cannot contain ${match[0]}`, {
@@ -349,7 +348,7 @@
}
regexToken() {
var body, closed, end, flags, index, match, origin, prev, ref2, ref3, regex, tokens;
var body, closed, end, flags, index, match, origin, prev, ref, ref1, regex, tokens;
switch (false) {
case !(match = REGEX_ILLEGAL.exec(this.chunk)):
this.error(`regular expressions cannot begin with ${match[2]}`, {
@@ -357,10 +356,10 @@
});
break;
case !(match = this.matchWithInterpolations(HEREGEX, '///')):
tokens = match.tokens, index = match.index;
({tokens, index} = match);
break;
case !(match = REGEX.exec(this.chunk)):
regex = match[0], body = match[1], closed = match[2];
[regex, body, closed] = match;
this.validateEscapes(body, {
isRegex: true,
offsetInChunk: 1
@@ -368,11 +367,11 @@
index = regex.length;
prev = this.prev();
if (prev) {
if (prev.spaced && (ref2 = prev[0], indexOf.call(CALLABLE, ref2) >= 0)) {
if (prev.spaced && (ref = prev[0], indexOf.call(CALLABLE, ref) >= 0)) {
if (!closed || POSSIBLY_DIVISION.test(regex)) {
return 0;
}
} else if (ref3 = prev[0], indexOf.call(NOT_REGEX, ref3) >= 0) {
} else if (ref1 = prev[0], indexOf.call(NOT_REGEX, ref1) >= 0) {
return 0;
}
}
@@ -383,7 +382,7 @@
default:
return 0;
}
flags = REGEX_FLAGS.exec(this.chunk.slice(index))[0];
[flags] = REGEX_FLAGS.exec(this.chunk.slice(index));
end = index + flags.length;
origin = this.makeToken('REGEX', null, 0, end);
switch (false) {
@@ -482,7 +481,7 @@
}
outdentToken(moveOut, noNewlines, outdentLength) {
var decreasedIndent, dent, lastIndent, ref2;
var decreasedIndent, dent, lastIndent, ref;
decreasedIndent = this.indent - moveOut;
while (moveOut > 0) {
lastIndent = this.indents[this.indents.length - 1];
@@ -496,7 +495,7 @@
moveOut -= lastIndent;
} else {
dent = this.indents.pop() + this.outdebt;
if (outdentLength && (ref2 = this.chunk[outdentLength], indexOf.call(INDENTABLE_CLOSERS, ref2) >= 0)) {
if (outdentLength && (ref = this.chunk[outdentLength], indexOf.call(INDENTABLE_CLOSERS, ref) >= 0)) {
decreasedIndent -= dent - moveOut;
moveOut = dent;
}
@@ -554,9 +553,9 @@
}
literalToken() {
var match, message, origin, prev, ref2, ref3, ref4, ref5, skipToken, tag, token, value;
var match, message, origin, prev, ref, ref1, ref2, ref3, skipToken, tag, token, value;
if (match = OPERATOR.exec(this.chunk)) {
value = match[0];
[value] = match;
if (CODE.test(value)) {
this.tagParameters();
}
@@ -567,14 +566,14 @@
prev = this.prev();
if (prev && indexOf.call(['=', ...COMPOUND_ASSIGN], value) >= 0) {
skipToken = false;
if (value === '=' && ((ref2 = prev[1]) === '||' || ref2 === '&&') && !prev.spaced) {
if (value === '=' && ((ref = prev[1]) === '||' || ref === '&&') && !prev.spaced) {
prev[0] = 'COMPOUND_ASSIGN';
prev[1] += '=';
prev = this.tokens[this.tokens.length - 2];
skipToken = true;
}
if (prev && prev[0] !== 'PROPERTY') {
origin = (ref3 = prev.origin) != null ? ref3 : prev;
origin = (ref1 = prev.origin) != null ? ref1 : prev;
message = isUnassignable(prev[1], origin[1]);
if (message) {
this.error(message, origin[2]);
@@ -609,12 +608,12 @@
} else if (value === '?' && (prev != null ? prev.spaced : void 0)) {
tag = 'BIN?';
} else if (prev && !prev.spaced) {
if (value === '(' && (ref4 = prev[0], indexOf.call(CALLABLE, ref4) >= 0)) {
if (value === '(' && (ref2 = prev[0], indexOf.call(CALLABLE, ref2) >= 0)) {
if (prev[0] === '?') {
prev[0] = 'FUNC_EXIST';
}
tag = 'CALL_START';
} else if (value === '[' && (ref5 = prev[0], indexOf.call(INDEXABLE, ref5) >= 0)) {
} else if (value === '[' && (ref3 = prev[0], indexOf.call(INDEXABLE, ref3) >= 0)) {
tag = 'INDEX_START';
switch (prev[0]) {
case '?':
@@ -647,7 +646,7 @@
return this;
}
stack = [];
tokens = this.tokens;
({tokens} = this);
i = tokens.length;
tokens[--i][0] = 'PARAM_END';
while (tok = tokens[--i]) {
@@ -675,7 +674,7 @@
}
matchWithInterpolations(regex, delimiter) {
var close, column, firstToken, index, lastToken, line, nested, offsetInChunk, open, ref2, ref3, ref4, str, strPart, tokens;
var close, column, firstToken, index, lastToken, line, nested, offsetInChunk, open, ref, str, strPart, tokens;
tokens = [];
offsetInChunk = delimiter.length;
if (this.chunk.slice(0, offsetInChunk) !== delimiter) {
@@ -683,10 +682,10 @@
}
str = this.chunk.slice(offsetInChunk);
while (true) {
strPart = regex.exec(str)[0];
[strPart] = regex.exec(str);
this.validateEscapes(strPart, {
isRegex: delimiter.charAt(0) === '/',
offsetInChunk: offsetInChunk
offsetInChunk
});
tokens.push(this.makeToken('NEOSTRING', strPart, offsetInChunk));
str = str.slice(strPart.length);
@@ -694,18 +693,21 @@
if (str.slice(0, 2) !== '#{') {
break;
}
ref2 = this.getLineAndColumnFromChunk(offsetInChunk + 1), line = ref2[0], column = ref2[1];
ref3 = new Lexer().tokenize(str.slice(1), {
[line, column] = this.getLineAndColumnFromChunk(offsetInChunk + 1);
({
tokens: nested,
index
} = new Lexer().tokenize(str.slice(1), {
line: line,
column: column,
untilBalanced: true
}), nested = ref3.tokens, index = ref3.index;
}));
index += 1;
open = nested[0], close = nested[nested.length - 1];
open[0] = open[1] = '(';
close[0] = close[1] = ')';
close.origin = ['', 'end of interpolation', close[2]];
if (((ref4 = nested[1]) != null ? ref4[0] : void 0) === 'TERMINATOR') {
if (((ref = nested[1]) != null ? ref[0] : void 0) === 'TERMINATOR') {
nested.splice(1, 1);
}
tokens.push(['TOKENS', nested]);
@@ -729,7 +731,7 @@
lastToken[2].last_column -= 1;
}
return {
tokens: tokens,
tokens,
index: offsetInChunk + delimiter.length
};
}
@@ -742,7 +744,7 @@
firstIndex = this.tokens.length;
for (i = j = 0, len = tokens.length; j < len; i = ++j) {
token = tokens[i];
tag = token[0], value = token[1];
[tag, value] = token;
switch (tag) {
case 'TOKENS':
if (value.length === 2) {
@@ -800,13 +802,13 @@
}
pair(tag) {
var lastIndent, prev, ref2, ref3, wanted;
ref2 = this.ends, prev = ref2[ref2.length - 1];
var lastIndent, prev, ref, ref1, wanted;
ref = this.ends, prev = ref[ref.length - 1];
if (tag !== (wanted = prev != null ? prev.tag : void 0)) {
if ('OUTDENT' !== wanted) {
this.error(`unmatched ${tag}`);
}
ref3 = this.indents, lastIndent = ref3[ref3.length - 1];
ref1 = this.indents, lastIndent = ref1[ref1.length - 1];
this.outdentToken(lastIndent, true);
return this.pair(tag);
}
@@ -814,7 +816,7 @@
}
getLineAndColumnFromChunk(offset) {
var column, lastLine, lineCount, ref2, string;
var column, lastLine, lineCount, ref, string;
if (offset === 0) {
return [this.chunkLine, this.chunkColumn];
}
@@ -826,7 +828,7 @@
lineCount = count(string, '\n');
column = this.chunkColumn;
if (lineCount > 0) {
ref2 = string.split('\n'), lastLine = ref2[ref2.length - 1];
ref = string.split('\n'), lastLine = ref[ref.length - 1];
column = lastLine.length;
} else {
column += string.length;
@@ -835,11 +837,11 @@
}
makeToken(tag, value, offsetInChunk = 0, length = value.length) {
var lastCharacter, locationData, ref2, ref3, token;
var lastCharacter, locationData, token;
locationData = {};
ref2 = this.getLineAndColumnFromChunk(offsetInChunk), locationData.first_line = ref2[0], locationData.first_column = ref2[1];
[locationData.first_line, locationData.first_column] = this.getLineAndColumnFromChunk(offsetInChunk);
lastCharacter = length > 0 ? length - 1 : 0;
ref3 = this.getLineAndColumnFromChunk(offsetInChunk + lastCharacter), locationData.last_line = ref3[0], locationData.last_column = ref3[1];
[locationData.last_line, locationData.last_column] = this.getLineAndColumnFromChunk(offsetInChunk + lastCharacter);
token = [tag, value, locationData];
return token;
}
@@ -855,14 +857,14 @@
}
tag() {
var ref2, token;
ref2 = this.tokens, token = ref2[ref2.length - 1];
var ref, token;
ref = this.tokens, token = ref[ref.length - 1];
return token != null ? token[0] : void 0;
}
value() {
var ref2, token;
ref2 = this.tokens, token = ref2[ref2.length - 1];
var ref, token;
ref = this.tokens, token = ref[ref.length - 1];
return token != null ? token[1] : void 0;
}
@@ -871,8 +873,8 @@
}
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');
var ref;
return LINE_CONTINUER.test(this.chunk) || ((ref = this.tag()) === '\\' || ref === '.' || ref === '?.' || ref === '?::' || ref === 'UNARY' || ref === 'MATH' || ref === 'UNARY_MATH' || ref === '+' || ref === '-' || ref === '**' || ref === 'SHIFT' || ref === 'RELATION' || ref === 'COMPARE' || ref === '&' || ref === '^' || ref === '|' || ref === '&&' || ref === '||' || ref === 'BIN?' || ref === 'THROW' || ref === 'EXTENDS');
}
formatString(str) {
@@ -884,7 +886,7 @@
}
validateEscapes(str, options = {}) {
var before, hex, invalidEscape, match, message, octal, ref2, unicode;
var before, hex, invalidEscape, match, message, octal, ref, unicode;
match = INVALID_ESCAPE.exec(str);
if (!match) {
return;
@@ -896,7 +898,7 @@
message = octal ? "octal escape sequences are not allowed" : "invalid escape sequence";
invalidEscape = `\\${octal || hex || unicode}`;
return this.error(`${message} ${invalidEscape}`, {
offset: ((ref2 = options.offsetInChunk) != null ? ref2 : 0) + match.index + before.length,
offset: ((ref = options.offsetInChunk) != null ? ref : 0) + match.index + before.length,
length: invalidEscape.length
});
}
@@ -939,11 +941,11 @@
}
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,
first_column: first_column,
last_column: first_column + ((ref4 = options.length) != null ? ref4 : 1) - 1
var first_column, first_line, location, ref, ref1;
location = 'first_line' in options ? options : ([first_line, first_column] = this.getLineAndColumnFromChunk((ref = options.offset) != null ? ref : 0), {
first_line,
first_column,
last_column: first_column + ((ref1 = options.length) != null ? ref1 : 1) - 1
});
return throwSyntaxError(message, location);
}
@@ -966,7 +968,7 @@
exports.isUnassignable = isUnassignable;
isForFrom = function(prev) {
var ref2;
var ref;
if (prev[0] === 'IDENTIFIER') {
if (prev[1] === 'from') {
prev[1][0] = 'IDENTIFIER';
@@ -975,7 +977,7 @@
return true;
} else if (prev[0] === 'FOR') {
return false;
} else if ((ref2 = prev[1]) === '{' || ref2 === '[' || ref2 === ',' || ref2 === ':') {
} else if ((ref = prev[1]) === '{' || ref === '[' || ref === ',' || ref === ':') {
return false;
} else {
return true;

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
(function() {
var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments, repeat;
repeat = require('./helpers').repeat;
({repeat} = require('./helpers'));
exports.OptionParser = OptionParser = class OptionParser {
constructor(rules, banner) {

View File

@@ -48,7 +48,7 @@
}
if (child_process) {
fork = child_process.fork;
({fork} = child_process);
binary = require.resolve('../../bin/coffee');
child_process.fork = function(path, args, options) {
if (helpers.isCoffee(path)) {

View File

@@ -1,6 +1,6 @@
// Generated by CoffeeScript 2.0.0-alpha1
(function() {
var CoffeeScript, addHistory, addMultilineHandler, fs, getCommandId, merge, nodeREPL, path, ref, replDefaults, runInContext, updateSyntaxError, vm;
var CoffeeScript, addHistory, addMultilineHandler, fs, getCommandId, merge, nodeREPL, path, replDefaults, runInContext, updateSyntaxError, vm;
fs = require('fs');
@@ -12,18 +12,18 @@
CoffeeScript = require('./coffeescript');
ref = require('./helpers'), merge = ref.merge, updateSyntaxError = ref.updateSyntaxError;
({merge, updateSyntaxError} = require('./helpers'));
replDefaults = {
prompt: 'coffee> ',
historyFile: process.env.HOME ? path.join(process.env.HOME, '.coffee_history') : void 0,
historyMaxInputSize: 10240,
"eval": function(input, context, filename, cb) {
var Assign, Block, Literal, Value, ast, err, js, ref1, referencedVars, token, tokens;
var Assign, Block, Literal, Value, ast, err, js, referencedVars, token, tokens;
input = input.replace(/\uFF00/g, '\n');
input = input.replace(/^\(([\s\S]*)\n\)$/m, '$1');
input = input.replace(/^\s*try\s*{([\s\S]*)}\s*catch.*$/m, '$1');
ref1 = require('./nodes'), Block = ref1.Block, Assign = ref1.Assign, Value = ref1.Value, Literal = ref1.Literal;
({Block, Assign, Value, Literal} = require('./nodes'));
try {
tokens = CoffeeScript.tokens(input);
referencedVars = (function() {
@@ -42,7 +42,7 @@
js = ast.compile({
bare: true,
locals: Object.keys(context),
referencedVars: referencedVars
referencedVars
});
return cb(null, runInContext(js, context, filename));
} catch (error) {
@@ -62,9 +62,9 @@
};
addMultilineHandler = function(repl) {
var inputStream, multiline, nodeLineListener, origPrompt, outputStream, ref1, rli;
rli = repl.rli, inputStream = repl.inputStream, outputStream = repl.outputStream;
origPrompt = (ref1 = repl._prompt) != null ? ref1 : repl.prompt;
var inputStream, multiline, nodeLineListener, origPrompt, outputStream, ref, rli;
({rli, inputStream, outputStream} = repl);
origPrompt = (ref = repl._prompt) != null ? ref : repl.prompt;
multiline = {
enabled: false,
initialPrompt: origPrompt.replace(/^[^> ]*/, function(x) {
@@ -168,10 +168,10 @@
module.exports = {
start: function(opts = {}) {
var build, major, minor, ref1, repl;
ref1 = process.versions.node.split('.').map(function(n) {
var build, major, minor, repl;
[major, minor, build] = process.versions.node.split('.').map(function(n) {
return parseInt(n);
}), major = ref1[0], minor = ref1[1], build = ref1[2];
});
if (major < 6) {
console.warn("Node 6+ required for CoffeeScript REPL");
process.exit(1);

View File

@@ -1,6 +1,6 @@
// Generated by CoffeeScript 2.0.0-alpha1
(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,
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, 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; };
generate = function(tag, value, origin) {
@@ -30,7 +30,7 @@
scanTokens(block) {
var i, token, tokens;
tokens = this.tokens;
({tokens} = this);
i = 0;
while (token = tokens[i]) {
i += block.call(this, token, i, tokens);
@@ -40,7 +40,7 @@
detectEnd(i, condition, action) {
var levels, ref, ref1, token, tokens;
tokens = this.tokens;
({tokens} = this);
levels = 0;
while (token = tokens[i]) {
if (levels === 0 && condition.call(this, token, i)) {
@@ -63,7 +63,7 @@
var i, k, len, ref, tag;
ref = this.tokens;
for (i = k = 0, len = ref.length; k < len; i = ++k) {
tag = ref[i][0];
[tag] = ref[i];
if (tag !== 'TERMINATOR') {
break;
}
@@ -168,10 +168,10 @@
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];
var endImplicitCall, endImplicitObject, forward, inImplicit, inImplicitCall, inImplicitControl, inImplicitObject, newLine, nextTag, offset, prevTag, prevToken, ref, ref1, ref2, s, sameLine, stackIdx, stackTag, stackTop, startIdx, startImplicitCall, startImplicitObject, startsLine, tag;
[tag] = token;
[prevTag] = prevToken = i > 0 ? tokens[i - 1] : [];
[nextTag] = i < tokens.length - 1 ? tokens[i + 1] : [];
stackTop = function() {
return stack[stack.length - 1];
};
@@ -302,7 +302,7 @@
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];
[stackTag, stackIdx] = stackTop();
if ((stackTag === '{' || stackTag === 'INDENT' && this.tag(stackIdx - 1) === '{') && (startsLine || this.tag(s - 1) === ',' || this.tag(s - 1) === '{')) {
return forward(1);
}
@@ -316,7 +316,7 @@
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);
[stackTag, stackIdx, {sameLine, startsLine}] = stackTop();
if (inImplicitCall() && prevTag !== ',') {
endImplicitCall();
} else if (inImplicitObject() && !this.insideForDeclaration && sameLine && tag !== 'TERMINATOR' && prevTag !== ':') {
@@ -351,9 +351,15 @@
return 1;
}
if (token[0] === '{' && (nextLocation = (ref = tokens[i + 1]) != null ? ref[2] : void 0)) {
line = nextLocation.first_line, column = nextLocation.first_column;
({
first_line: line,
first_column: column
} = nextLocation);
} else if (prevLocation = (ref1 = tokens[i - 1]) != null ? ref1[2] : void 0) {
line = prevLocation.last_line, column = prevLocation.last_column;
({
last_line: line,
last_column: column
} = prevLocation);
} else {
line = column = 0;
}
@@ -395,8 +401,8 @@
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];
var j, k, ref, ref1, tag;
[tag] = token;
if (tag === 'TERMINATOR') {
if (this.tag(i + 1) === 'ELSE' && this.tag(i - 1) !== 'OUTDENT') {
tokens.splice(i, 1, ...this.indentation());
@@ -418,7 +424,7 @@
}
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];
[indent, outdent] = this.indentation(tokens[i]);
if (starter === 'THEN') {
indent.fromThen = true;
}
@@ -438,8 +444,8 @@
original = null;
condition = function(token, i) {
var prevTag, tag;
tag = token[0];
prevTag = this.tokens[i - 1][0];
[tag] = token;
[prevTag] = this.tokens[i - 1];
return tag === 'TERMINATOR' || (tag === 'INDENT' && indexOf.call(SINGLE_LINERS, prevTag) < 0);
};
action = function(token, i) {
@@ -492,7 +498,7 @@
EXPRESSION_END = [];
for (k = 0, len = BALANCED_PAIRS.length; k < len; k++) {
ref = BALANCED_PAIRS[k], left = ref[0], rite = ref[1];
[left, rite] = BALANCED_PAIRS[k];
EXPRESSION_START.push(INVERSES[rite] = left);
EXPRESSION_END.push(INVERSES[left] = rite);
}

View File

@@ -30,10 +30,7 @@
if (Object.prototype.hasOwnProperty.call(this.positions, name)) {
return this.variables[this.positions[name]].type = type;
} else {
return this.positions[name] = this.variables.push({
name: name,
type: type
}) - 1;
return this.positions[name] = this.variables.push({name, type}) - 1;
}
}
@@ -110,7 +107,7 @@
assign(name, value) {
this.add(name, {
value: value,
value,
assigned: true
}, true);
return this.hasAssignments = true;

View File

@@ -8,20 +8,15 @@
this.columns = [];
}
add(column, arg, options) {
var sourceColumn, sourceLine;
sourceLine = arg[0], sourceColumn = arg[1];
if (options === void 0) {
options = {};
}
add(column, [sourceLine, sourceColumn], options = {}) {
if (this.columns[column] && options.noReplace) {
return;
}
return this.columns[column] = {
line: this.line,
column: column,
sourceLine: sourceLine,
sourceColumn: sourceColumn
column,
sourceLine,
sourceColumn
};
}
@@ -45,14 +40,13 @@
add(sourceLocation, generatedLocation, options = {}) {
var base, column, line, lineMap;
line = generatedLocation[0], column = generatedLocation[1];
[line, column] = generatedLocation;
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];
sourceLocation([line, column]) {
var lineMap;
while (!((lineMap = this.lines[line]) || (line <= 0))) {
line--;
}

View File

@@ -47,6 +47,6 @@
"underscore": "~1.8.3"
},
"dependencies": {
"marked": "~0.3.6"
"markdown-it": "^8.3.1"
}
}

View File

@@ -2,16 +2,7 @@
# the **Lexer**, **Rewriter**, and the **Nodes**. Merge objects, flatten
# arrays, count characters, that sort of thing.
marked = require 'marked'
# marked.setOptions
# renderer: new marked.Renderer()
# gfm: true
# tables: true
# breaks: false
# pedantic: false
# sanitize: true
# smartLists: true
# smartypants: false
md = require('markdown-it')()
# Peek at the beginning of a given string to see if it matches a sequence.
exports.starts = (string, literal, start) ->
@@ -80,23 +71,18 @@ exports.some = Array::some ? (fn) ->
# Simple function for extracting code from Literate CoffeeScript by stripping
# out all non-code blocks, producing a string of CoffeeScript code that can
# be compiled “normally.”
# be compiled “normally.” Uses [MarkdownIt](https://markdown-it.github.io/)
# to tell the difference between Markdown and code blocks.
exports.invertLiterate = (code) ->
# Create a placeholder for tabs, that isnt used anywhere in `code`, and then
# re-insert the tabs after code extraction.
generateRandomToken = ->
"#{Math.random() * Date.now()}"
while token is undefined or code.indexOf(token) isnt -1
token = generateRandomToken()
code = code.replace "\t", token
# Parse as markdown, discard everything except code blocks.
out = ""
for item in marked.lexer code, {}
out += "#{item.text}\n" if item.type is 'code'
# Put the tabs back in.
out.replace token, "\t"
out
out = []
md.renderer.rules =
code_block: (tokens, idx) ->
startLine = tokens[idx].map[0]
lines = tokens[idx].content.split '\n'
for line, i in lines
out[startLine + i] = line
md.render code
out.join '\n'
# Merge two jison-style location data objects together.
# If `last` is not provided, this will simply return `first`.

View File

@@ -279,7 +279,7 @@ exports.Base = class Base
makeCode: (code) ->
new CodeFragment this, code
wrapInBraces: (fragments) ->
wrapInParentheses: (fragments) ->
[].concat @makeCode('('), fragments, @makeCode(')')
# `fragmentsList` is an array of arrays of fragments. Each array in fragmentsList will be
@@ -432,7 +432,7 @@ exports.Block = class Block extends Base
answer = @joinFragmentArrays(compiledNodes, ', ')
else
answer = [@makeCode "void 0"]
if compiledNodes.length > 1 and o.level >= LEVEL_LIST then @wrapInBraces answer else answer
if compiledNodes.length > 1 and o.level >= LEVEL_LIST then @wrapInParentheses answer else answer
# If we happen to be the top-level **Block**, wrap everything in
# a safety closure, unless requested not to.
@@ -532,7 +532,7 @@ exports.NaNLiteral = class NaNLiteral extends NumberLiteral
compileNode: (o) ->
code = [@makeCode '0/0']
if o.level >= LEVEL_OP then @wrapInBraces code else code
if o.level >= LEVEL_OP then @wrapInParentheses code else code
exports.StringLiteral = class StringLiteral extends Literal
@@ -543,6 +543,9 @@ exports.PassthroughLiteral = class PassthroughLiteral extends Literal
exports.IdentifierLiteral = class IdentifierLiteral extends Literal
isAssignable: YES
eachName: (iterator) ->
iterator @
exports.PropertyName = class PropertyName extends Literal
isAssignable: YES
@@ -581,8 +584,7 @@ exports.BooleanLiteral = class BooleanLiteral extends Literal
#### Return
# A `return` is a *pureStatement* -- wrapping it in a closure wouldn't
# make sense.
# A `return` is a *pureStatement*wrapping it in a closure wouldnt make sense.
exports.Return = class Return extends Base
constructor: (@expression) ->
super()
@@ -627,14 +629,15 @@ exports.AwaitReturn = class AwaitReturn extends Return
# A value, variable or literal or parenthesized, indexed or dotted into,
# or vanilla.
exports.Value = class Value extends Base
constructor: (base, props, tag) ->
constructor: (base, props, tag, isDefaultValue = no) ->
return base if not props and base instanceof Value
super()
@base = base
@properties = props or []
@[tag] = true if tag
@base = base
@properties = props or []
@[tag] = yes if tag
@isDefaultValue = isDefaultValue
return this
children: ['base', 'properties']
@@ -740,6 +743,14 @@ exports.Value = class Value extends Base
return new If new Existence(fst), snd, soak: on
no
eachName: (iterator) ->
if @hasProperties()
iterator @
else if @base.isAssignable()
@base.eachName iterator
else
@error 'tried to assign to unassignable value'
#### Comment
# CoffeeScript passes through block comments as JavaScript block comments
@@ -1097,13 +1108,26 @@ exports.Slice = class Slice extends Base
# An object literal, nothing fancy.
exports.Obj = class Obj extends Base
constructor: (props, @generated = false) ->
constructor: (props, @generated = no, @lhs = no) ->
super()
@objects = @properties = props or []
children: ['properties']
isAssignable: ->
for prop in @properties
# Check for reserved words.
message = isUnassignable prop.unwrapAll().value
prop.error message if message
prop = prop.value if prop instanceof Assign and prop.context is 'object'
return no unless prop.isAssignable()
yes
shouldCache: ->
not @isAssignable()
compileNode: (o) ->
props = @properties
if @generated
@@ -1111,56 +1135,95 @@ exports.Obj = class Obj extends Base
node.error 'cannot have an implicit value in an implicit object'
idt = o.indent += TAB
lastNoncom = @lastNonComment @properties
isCompact = yes
for prop in @properties
if prop instanceof Comment or (prop instanceof Assign and prop.context is 'object')
isCompact = no
answer = []
answer.push @makeCode "{#{if props.length is 0 then '}' else '\n'}"
answer.push @makeCode "{#{if isCompact then '' else '\n'}"
for prop, i in props
join = if i is props.length - 1
''
else if isCompact
', '
else if prop is lastNoncom or prop instanceof Comment
'\n'
else
',\n'
indent = if prop instanceof Comment then '' else idt
if prop instanceof Assign
if prop.context isnt 'object'
prop.operatorToken.error "unexpected #{prop.operatorToken.value}"
if prop.variable instanceof Value and prop.variable.hasProperties()
prop.variable.error 'invalid object key'
if prop instanceof Value and prop.this
prop = new Assign prop.properties[0].name, prop, 'object'
if prop not instanceof Comment and prop not instanceof Assign
indent = if isCompact or prop instanceof Comment then '' else idt
key = if prop instanceof Assign and prop.context is 'object'
prop.variable
else if prop instanceof Assign
prop.operatorToken.error "unexpected #{prop.operatorToken.value}" unless @lhs
prop.variable
else if prop not instanceof Comment
prop
if key instanceof Value and key.hasProperties()
key.error 'invalid object key' if prop.context is 'object' or not key.this
key = key.properties[0].name
prop = new Assign key, prop, 'object'
if key is prop
if prop.shouldCache()
[key, value] = prop.base.cache o
key = new PropertyName key.value if key instanceof IdentifierLiteral
prop = new Assign key, value, 'object'
else
else if not prop.bareLiteral?(IdentifierLiteral)
prop = new Assign prop, prop, 'object'
if indent then answer.push @makeCode indent
answer.push prop.compileToFragments(o, LEVEL_TOP)...
if join then answer.push @makeCode join
answer.push @makeCode "\n#{@tab}}" unless props.length is 0
if @front then @wrapInBraces answer else answer
answer.push @makeCode "#{if isCompact then '' else "\n#{@tab}"}}"
if @front then @wrapInParentheses answer else answer
assigns: (name) ->
for prop in @properties when prop.assigns name then return yes
no
eachName: (iterator) ->
for prop in @properties
prop = prop.value if prop instanceof Assign and prop.context is 'object'
prop = prop.unwrapAll()
prop.eachName iterator if prop.eachName?
#### Arr
# An array literal.
exports.Arr = class Arr extends Base
constructor: (objs) ->
constructor: (objs, @lhs = no) ->
super()
@objects = objs or []
children: ['objects']
isAssignable: ->
return no unless @objects.length
for obj, i in @objects
return no if obj instanceof Splat and i + 1 isnt @objects.length
return no unless obj.isAssignable() and (not obj.isAtomic or obj.isAtomic())
yes
shouldCache: ->
not @isAssignable()
compileNode: (o) ->
return [@makeCode '[]'] unless @objects.length
o.indent += TAB
answer = []
# If this array is the left-hand side of an assignment, all its children
# are too.
if @lhs
for obj in @objects
unwrappedObj = obj.unwrapAll()
unwrappedObj.lhs = yes if unwrappedObj instanceof Arr or unwrappedObj instanceof Obj
compiledObjs = (obj.compileToFragments o, LEVEL_LIST for obj in @objects)
for fragments, index in compiledObjs
if index
@@ -1178,6 +1241,11 @@ exports.Arr = class Arr extends Base
for obj in @objects when obj.assigns name then return yes
no
eachName: (iterator) ->
for obj in @objects
obj = obj.unwrapAll()
obj.eachName iterator
#### Class
# The CoffeeScript class definition.
@@ -1195,7 +1263,7 @@ exports.Class = class Class extends Base
# Special handling to allow `class expr.A extends A` declarations
parentName = @parent.base.value if @parent instanceof Value and not @parent.hasProperties()
@hasNameClash = @name? and @name == parentName
@hasNameClash = @name? and @name is parentName
if executableBody or @hasNameClash
@compileNode = @compileClassDeclaration
@@ -1205,7 +1273,7 @@ exports.Class = class Class extends Base
result = @compileClassDeclaration o
# Anonymous classes are only valid in expressions
result = @wrapInBraces result if not @name? and o.level is LEVEL_TOP
result = @wrapInParentheses result if not @name? and o.level is LEVEL_TOP
if @variable
assign = new Assign @variable, new Literal(''), null, { @moduleDeclaration }
@@ -1304,7 +1372,7 @@ exports.Class = class Class extends Base
@boundMethods.push method.name
method.bound = false
if initializer.length != expressions.length
if initializer.length isnt expressions.length
@body.expressions = (expression.hoist() for expression in initializer)
new Block expressions
@@ -1405,7 +1473,7 @@ exports.ExecutableClassBody = class ExecutableClassBody extends Base
@class.externalCtor = externalCtor
@externalCtor.variable.base = externalCtor
if @name != @class.name
if @name isnt @class.name
@body.expressions.unshift new Assign (new IdentifierLiteral @name), @class
else
@body.expressions.unshift @class
@@ -1640,6 +1708,8 @@ exports.Assign = class Assign extends Base
children: ['variable', 'value']
isAssignable: YES
isStatement: (o) ->
o?.level is LEVEL_TOP and @context? and (@moduleDeclaration or "?" in @context)
@@ -1654,39 +1724,57 @@ exports.Assign = class Assign extends Base
unfoldSoak: (o) ->
unfoldSoak o, this, 'variable'
# Compile an assignment, delegating to `compilePatternMatch` or
# Compile an assignment, delegating to `compileDestructuring` or
# `compileSplice` if appropriate. Keep track of the name of the base object
# we've been assigned to, for correct internal references. If the variable
# has not been seen yet within the current scope, declare it.
compileNode: (o) ->
if isValue = @variable instanceof Value
return @compilePatternMatch o if @variable.isArray() or @variable.isObject()
isValue = @variable instanceof Value
if isValue
# When compiling `@variable`, remember if it is part of a function parameter.
@variable.param = @param
# If `@variable` is an array or an object, were destructuring;
# if its also `isAssignable()`, the destructuring syntax is supported
# in ES and we can output it as is; otherwise we `@compileDestructuring`
# and convert this ES-unsupported destructuring into acceptable output.
if @variable.isArray() or @variable.isObject()
# This is the left-hand side of an assignment; let `Arr` and `Obj`
# know that, so that those nodes know that theyre assignable as
# destructured variables.
@variable.base.lhs = yes
return @compileDestructuring o unless @variable.isAssignable()
return @compileSplice o if @variable.isSplice()
return @compileConditional o if @context in ['||=', '&&=', '?=']
return @compileSpecialMath o if @context in ['**=', '//=', '%%=']
unless @context
varBase = @variable.unwrapAll()
unless varBase.isAssignable()
@variable.error "'#{@variable.compile o}' can't be assigned"
varBase.eachName (name) =>
return if name.hasProperties?()
message = isUnassignable name.value
name.error message if message
# `moduleDeclaration` can be `'import'` or `'export'`
@checkAssignability o, name
if @moduleDeclaration
o.scope.add name.value, @moduleDeclaration
else
o.scope.find name.value
if @value instanceof Code
if @value.isStatic
@value.name = @variable.properties[0]
else if @variable.properties?.length >= 2
[properties..., prototype, name] = @variable.properties
@value.name = name if prototype.name?.value is 'prototype'
unless @context
varBase = @variable.unwrapAll()
unless varBase.isAssignable()
@variable.error "'#{@variable.compile o}' can't be assigned"
unless varBase.hasProperties?()
# `moduleDeclaration` can be `'import'` or `'export'`
if @moduleDeclaration
@checkAssignability o, varBase
o.scope.add varBase.value, @moduleDeclaration
else if @param
o.scope.add varBase.value, 'var'
else
@checkAssignability o, varBase
o.scope.find varBase.value
val = @value.compileToFragments o, LEVEL_LIST
@variable.front = true if isValue and @variable.base instanceof Obj
compiledName = @variable.compileToFragments o, LEVEL_LIST
if @context is 'object'
@@ -1699,25 +1787,40 @@ exports.Assign = class Assign extends Base
return compiledName.concat @makeCode(": "), val
answer = compiledName.concat @makeCode(" #{ @context or '=' } "), val
if o.level <= LEVEL_LIST then answer else @wrapInBraces answer
# Per https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Assignment_without_declaration,
# if were destructuring without declaring, the destructuring assignment must be wrapped in parentheses.
if o.level > LEVEL_LIST or (isValue and @variable.base instanceof Obj and not @param)
@wrapInParentheses answer
else
answer
# Brief implementation of recursive pattern matching, when assigning array or
# object literals to a value. Peeks at their properties to assign inner names.
compilePatternMatch: (o) ->
compileDestructuring: (o) ->
top = o.level is LEVEL_TOP
{value} = this
{objects} = @variable.base
unless olen = objects.length
olen = objects.length
# Special-case for `{} = a` and `[] = a` (empty patterns).
# Compile to simply `a`.
if olen is 0
code = value.compileToFragments o
return if o.level >= LEVEL_OP then @wrapInBraces code else code
return if o.level >= LEVEL_OP then @wrapInParentheses code else code
[obj] = objects
# Disallow `[...] = a` for some reason. (Could be equivalent to `[] = a`?)
if olen is 1 and obj instanceof Expansion
obj.error 'Destructuring assignment has no target'
isObject = @variable.isObject()
# Special case for when there's only one thing destructured off of
# something. `{a} = b`, `[a] = b`, `{a: b} = c`
if top and olen is 1 and obj not instanceof Splat
# Pick the property straight off the value when theres just one to pick
# (no need to cache the value into a variable).
defaultValue = null
defaultValue = undefined
if obj instanceof Assign and obj.context is 'object'
# A regular object pattern-match.
{variable: {base: idx}, value: obj} = obj
@@ -1742,24 +1845,43 @@ exports.Assign = class Assign extends Base
value.properties.push new (if acc then Access else Index) idx
message = isUnassignable obj.unwrap().value
obj.error message if message
value = new Op '?', value, defaultValue if defaultValue
if defaultValue
defaultValue.isDefaultValue = yes
value = new Op '?', value, defaultValue
return new Assign(obj, value, null, param: @param).compileToFragments o, LEVEL_TOP
vvar = value.compileToFragments o, LEVEL_LIST
vvarText = fragmentsToText vvar
assigns = []
expandedIdx = false
# Make vvar into a simple variable if it isn't already.
# At this point, there are several things to destructure. So the `fn()` in
# `{a, b} = fn()` must be cached, for example. Make vvar into a simple
# variable if it isn't already.
if value.unwrap() not instanceof IdentifierLiteral or @variable.assigns(vvarText)
assigns.push [@makeCode("#{ ref = o.scope.freeVariable 'ref' } = "), vvar...]
ref = o.scope.freeVariable 'ref'
assigns.push [@makeCode(ref + ' = '), vvar...]
vvar = [@makeCode ref]
vvarText = ref
# And here comes the big loop that handles all of these cases:
# `[a, b] = c`
# `[a..., b] = c`
# `[..., a, b] = c`
# `[@a, b] = c`
# `[a = 1, b] = c`
# `{a, b} = c`
# `{@a, b} = c`
# `{a = 1, b} = c`
# etc.
for obj, i in objects
idx = i
if not expandedIdx and obj instanceof Splat
name = obj.name.unwrap().value
obj = obj.unwrap()
val = "#{olen} <= #{vvarText}.length ? #{ utility 'slice', o }.call(#{vvarText}, #{i}"
if rest = olen - i - 1
rest = olen - i - 1
if rest isnt 0
ivar = o.scope.freeVariable 'i', single: true
val += ", #{ivar} = #{vvarText}.length - #{rest}) : (#{ivar} = #{i}, [])"
else
@@ -1767,7 +1889,8 @@ exports.Assign = class Assign extends Base
val = new Literal val
expandedIdx = "#{ivar}++"
else if not expandedIdx and obj instanceof Expansion
if rest = olen - i - 1
rest = olen - i - 1
if rest isnt 0
if rest is 1
expandedIdx = "#{vvarText}.length - 1"
else
@@ -1779,7 +1902,7 @@ exports.Assign = class Assign extends Base
else
if obj instanceof Splat or obj instanceof Expansion
obj.error "multiple splats/expansions are disallowed in an assignment"
defaultValue = null
defaultValue = undefined
if obj instanceof Assign and obj.context is 'object'
# A regular object pattern-match.
{variable: {base: idx}, value: obj} = obj
@@ -1802,14 +1925,17 @@ exports.Assign = class Assign extends Base
name = obj.unwrap().value
acc = idx.unwrap() instanceof PropertyName
val = new Value new Literal(vvarText), [new (if acc then Access else Index) idx]
val = new Op '?', val, defaultValue if defaultValue
if defaultValue
defaultValue.isDefaultValue = yes
val = new Op '?', val, defaultValue
if name?
message = isUnassignable name
obj.error message if message
assigns.push new Assign(obj, val, null, param: @param, subpattern: yes).compileToFragments o, LEVEL_LIST
assigns.push vvar unless top or @subpattern
fragments = @joinFragmentArrays assigns, ', '
if o.level < LEVEL_LIST then fragments else @wrapInBraces fragments
if o.level < LEVEL_LIST then fragments else @wrapInParentheses fragments
# When compiling a conditional assignment, take care to ensure that the
# operands are only evaluated once, even though we have to reference them
@@ -1825,7 +1951,7 @@ exports.Assign = class Assign extends Base
new If(new Existence(left), right, type: 'if').addElse(new Assign(right, @value, '=')).compileToFragments o
else
fragments = new Op(@context[...-1], left, new Assign(right, @value, '=')).compileToFragments o
if o.level <= LEVEL_LIST then fragments else @wrapInBraces fragments
if o.level <= LEVEL_LIST then fragments else @wrapInParentheses fragments
# Convert special math assignment operators like `a **= b` to the equivalent
# extended form `a = a ** b` and then compiles that.
@@ -1853,7 +1979,10 @@ exports.Assign = class Assign extends Base
to = "9e9"
[valDef, valRef] = @value.cache o, LEVEL_LIST
answer = [].concat @makeCode("[].splice.apply(#{name}, [#{fromDecl}, #{to}].concat("), valDef, @makeCode(")), "), valRef
if o.level > LEVEL_TOP then @wrapInBraces answer else answer
if o.level > LEVEL_TOP then @wrapInParentheses answer else answer
eachName: (iterator) ->
@variable.unwrapAll().eachName iterator
#### Code
@@ -1947,13 +2076,18 @@ exports.Code = class Code extends Base
haveSplatParam = yes
if param.splat
params.push ref = param.asReference o
splatParamName = fragmentsToText ref.compileNode o
if param.name instanceof Arr
# Splat arrays are treated oddly by ES; deal with them the legacy
# way in the function body. TODO: Should this be handled in the
# function parameter list, and if so, how?
splatParamName = o.scope.freeVariable 'arg'
params.push ref = new Value new IdentifierLiteral splatParamName
exprs.push new Assign new Value(param.name), ref, null, param: yes
else
params.push ref = param.asReference o
splatParamName = fragmentsToText ref.compileNode o
if param.shouldCache()
exprs.push new Assign new Value(param.name), ref, '=', param: yes
# TODO: output destructured parameters as is, and fix destructuring
# of objects with default values to work in this context (see
# Obj.compileNode `if prop.context isnt 'object'`).
exprs.push new Assign new Value(param.name), ref, null, param: yes
else # `param` is an Expansion
splatParamName = o.scope.freeVariable 'args'
params.push new Value new IdentifierLiteral splatParamName
@@ -1972,11 +2106,11 @@ exports.Code = class Code extends Base
# to the function body assigning it, e.g.
# `(arg) => { var a = arg.a; }`, with a default value if it has one.
if param.value?
condition = new Op '==', param, new UndefinedLiteral
ifTrue = new Assign new Value(param.name), param.value, '=', param: yes
condition = new Op '===', param, new UndefinedLiteral
ifTrue = new Assign new Value(param.name), param.value, null, param: yes
exprs.push new If condition, ifTrue
else
exprs.push new Assign new Value(param.name), param.asReference(o), '=', param: yes
exprs.push new Assign new Value(param.name), param.asReference(o), null, param: yes
# If this parameter comes before the splat or expansion, it will go
# in the function definition parameter list.
@@ -1989,11 +2123,17 @@ exports.Code = class Code extends Base
ref = param.asReference o
else
if param.value? and not param.assignedInBody
ref = new Assign new Value(param.name), param.value, '='
ref = new Assign new Value(param.name), param.value, null, param: yes
else
ref = param
# Add this parameters reference to the function scope
o.scope.parameter fragmentsToText (if param.value? then param else ref).compileToFragments o
# Add this parameters reference(s) to the function scope.
if param.name instanceof Arr or param.name instanceof Obj
# This parameter is destructured.
param.name.lhs = yes
param.name.eachName (prop) ->
o.scope.parameter prop.value
else
o.scope.parameter fragmentsToText (if param.value? then param else ref).compileToFragments o
params.push ref
else
paramsAfterSplat.push param
@@ -2001,8 +2141,8 @@ exports.Code = class Code extends Base
# function parameter list we need to assign its default value
# (if necessary) as an expression in the body.
if param.value? and not param.shouldCache()
condition = new Op '==', param, new UndefinedLiteral
ifTrue = new Assign new Value(param.name), param.value, '='
condition = new Op '===', param, new UndefinedLiteral
ifTrue = new Assign new Value(param.name), param.value
exprs.push new If condition, ifTrue
# Add this parameter to the scope, since it wouldnt have been added yet since it was skipped earlier.
o.scope.add param.name.value, 'var', yes if param.name?.value?
@@ -2056,7 +2196,7 @@ exports.Code = class Code extends Base
answer.push @makeCode '}'
return [@makeCode(@tab), answer...] if @isMethod
if @front or (o.level >= LEVEL_ACCESS) then @wrapInBraces answer else answer
if @front or (o.level >= LEVEL_ACCESS) then @wrapInParentheses answer else answer
eachParamName: (iterator) ->
param.eachName iterator for param in @params
@@ -2084,7 +2224,7 @@ exports.Code = class Code extends Base
superCall.error "'super' is only allowed in derived class constructors" if @ctor is 'base'
superCall.expressions = thisAssignments
haveThisParam = thisAssignments.length and thisAssignments.length != @thisAssignments?.length
haveThisParam = thisAssignments.length and thisAssignments.length isnt @thisAssignments?.length
if @ctor is 'derived' and not seenSuper and haveThisParam
param = thisAssignments[0].variable
param.error "Can't use @params in derived class constructors without calling super"
@@ -2205,7 +2345,8 @@ exports.Splat = class Splat extends Base
children: ['name']
isAssignable: YES
isAssignable: ->
@name.isAssignable() and (not @name.isAtomic or @name.isAtomic())
constructor: (name) ->
super()
@@ -2299,7 +2440,7 @@ exports.While = class While extends Base
# Simple Arithmetic and logical operations. Performs some conversion from
# CoffeeScript operations into their JavaScript equivalents.
exports.Op = class Op extends Base
constructor: (op, first, second, flip ) ->
constructor: (op, first, second, flip) ->
return new In first, second if op is 'in'
if op is 'do'
return Op::generateDo first
@@ -2410,7 +2551,7 @@ exports.Op = class Op extends Base
return @compileUnary o if @isUnary()
return @compileChain o if isChain
switch @operator
when '?' then @compileExistence o
when '?' then @compileExistence o, @second.isDefaultValue
when '**' then @compilePower o
when '//' then @compileFloorDivision o
when '%%' then @compileModulo o
@@ -2418,7 +2559,7 @@ exports.Op = class Op extends Base
lhs = @first.compileToFragments o, LEVEL_OP
rhs = @second.compileToFragments o, LEVEL_OP
answer = [].concat lhs, @makeCode(" #{@operator} "), rhs
if o.level <= LEVEL_OP then answer else @wrapInBraces answer
if o.level <= LEVEL_OP then answer else @wrapInParentheses answer
# Mimic Python's chained comparisons when multiple comparison operators are
# used sequentially. For example:
@@ -2430,17 +2571,17 @@ exports.Op = class Op extends Base
fst = @first.compileToFragments o, LEVEL_OP
fragments = fst.concat @makeCode(" #{if @invert then '&&' else '||'} "),
(shared.compileToFragments o), @makeCode(" #{@operator} "), (@second.compileToFragments o, LEVEL_OP)
@wrapInBraces fragments
@wrapInParentheses fragments
# Keep reference to the left expression, unless this an existential assignment
compileExistence: (o) ->
compileExistence: (o, checkOnlyUndefined) ->
if @first.shouldCache()
ref = new IdentifierLiteral o.scope.freeVariable 'ref'
fst = new Parens new Assign ref, @first
else
fst = @first
ref = fst
new If(new Existence(fst), ref, type: 'if').addElse(@second).compileToFragments o
new If(new Existence(fst, checkOnlyUndefined), ref, type: 'if').addElse(@second).compileToFragments o
# Compile a unary **Op**.
compileUnary: (o) ->
@@ -2521,7 +2662,7 @@ exports.In = class In extends Base
for item, i in @array.base.objects
if i then tests.push @makeCode cnj
tests = tests.concat (if i then ref else sub), @makeCode(cmp), item.compileToFragments(o, LEVEL_ACCESS)
if o.level < LEVEL_OP then tests else @wrapInBraces tests
if o.level < LEVEL_OP then tests else @wrapInParentheses tests
compileLoopTest: (o) ->
[sub, ref] = @object.cache o, LEVEL_LIST
@@ -2529,7 +2670,7 @@ exports.In = class In extends Base
@makeCode(", "), ref, @makeCode(") " + if @negated then '< 0' else '>= 0')
return fragments if fragmentsToText(sub) is fragmentsToText(ref)
fragments = sub.concat @makeCode(', '), fragments
if o.level < LEVEL_LIST then fragments else @wrapInBraces fragments
if o.level < LEVEL_LIST then fragments else @wrapInParentheses fragments
toString: (idt) ->
super idt, @constructor.name + if @negated then '!' else ''
@@ -2600,12 +2741,13 @@ exports.Throw = class Throw extends Base
#### Existence
# Checks a variable for existence -- not *null* and not *undefined*. This is
# Checks a variable for existence -- not `null` and not `undefined`. This is
# similar to `.nil?` in Ruby, and avoids having to consult a JavaScript truth
# table.
# table. Optionally only check if a variable is not `undefined`.
exports.Existence = class Existence extends Base
constructor: (@expression) ->
constructor: (@expression, onlyNotUndefined = no) ->
super()
@comparisonTarget = if onlyNotUndefined then 'undefined' else 'null'
children: ['expression']
@@ -2616,10 +2758,19 @@ exports.Existence = class Existence extends Base
code = @expression.compile o, LEVEL_OP
if @expression.unwrap() instanceof IdentifierLiteral and not o.scope.check code
[cmp, cnj] = if @negated then ['===', '||'] else ['!==', '&&']
code = "typeof #{code} #{cmp} \"undefined\" #{cnj} #{code} #{cmp} null"
code = "typeof #{code} #{cmp} \"undefined\"" + if @comparisonTarget isnt 'undefined' then " #{cnj} #{code} #{cmp} #{@comparisonTarget}" else ''
else
# do not use strict equality here; it will break existing code
code = "#{code} #{if @negated then '==' else '!='} null"
# We explicity want to use loose equality (`==`) when comparing against `null`,
# so that an existence check roughly corresponds to a check for truthiness.
# Do *not* change this to `===` for `null`, as this will break mountains of
# existing code. When comparing only against `undefined`, however, we want to
# use `===` because this use case is for parity with ES2015+ default values,
# which only get assigned when the variable is `undefined` (but not `null`).
cmp = if @comparisonTarget is 'null'
if @negated then '==' else '!='
else # `undefined`
if @negated then '===' else '!=='
code = "#{code} #{cmp} #{@comparisonTarget}"
[@makeCode(if o.level <= LEVEL_COND then code else "(#{code})")]
#### Parens
@@ -2647,7 +2798,7 @@ exports.Parens = class Parens extends Base
fragments = expr.compileToFragments o, LEVEL_PAREN
bare = o.level < LEVEL_OP and (expr instanceof Op or expr instanceof Call or
(expr instanceof For and expr.returns))
if bare then fragments else @wrapInBraces fragments
if bare then fragments else @wrapInParentheses fragments
#### StringWithInterpolations
@@ -2719,7 +2870,7 @@ exports.For = class For extends While
@index.error 'cannot use index with for-from' if @from and @index
source.ownTag.error "cannot use own with for-#{if @from then 'from' else 'in'}" if @own and not @object
[@name, @index] = [@index, @name] if @object
@index.error 'index cannot be a pattern matching expression' if @index instanceof Value and not @index.isAssignable()
@index.error 'index cannot be a pattern matching expression' if @index?.isArray?() or @index?.isObject?()
@range = @source instanceof Value and @source.base instanceof Range and not @source.properties.length and not @from
@pattern = @name instanceof Value
@index.error 'indexes do not apply to range loops' if @range and @index
@@ -2954,7 +3105,7 @@ exports.If = class If extends Base
body = @bodyNode().compileToFragments o, LEVEL_LIST
alt = if @elseBodyNode() then @elseBodyNode().compileToFragments(o, LEVEL_LIST) else [@makeCode('void 0')]
fragments = cond.concat @makeCode(" ? "), body, @makeCode(" : "), alt
if o.level >= LEVEL_COND then @wrapInBraces fragments else fragments
if o.level >= LEVEL_COND then @wrapInParentheses fragments else fragments
unfoldSoak: ->
@soak and this

View File

@@ -142,7 +142,8 @@ test "#1192: assignment starting with object literals", ->
# Destructuring Assignment
test "empty destructuring assignment", ->
{} = [] = undefined
{} = {}
[] = []
test "chained destructuring assignments", ->
[a] = {0: b} = {'0': c} = [nonce={}]
@@ -305,7 +306,7 @@ test "simple array destructuring defaults", ->
[a = 2] = [undefined]
eq 2, a
[a = 3] = [null]
eq 3, a
eq null, a # Breaking change in CS2: per ES2015, default values are applied for `undefined` but not for `null`.
[a = 4] = [0]
eq 0, a
arr = [a = 5]
@@ -318,7 +319,7 @@ test "simple object destructuring defaults", ->
{b = 2} = {b: undefined}
eq b, 2
{b = 3} = {b: null}
eq b, 3
eq b, null # Breaking change in CS2: per ES2015, default values are applied for `undefined` but not for `null`.
{b = 4} = {b: 0}
eq b, 0
@@ -327,17 +328,17 @@ test "simple object destructuring defaults", ->
{b: c = 2} = {b: undefined}
eq c, 2
{b: c = 3} = {b: null}
eq c, 3
eq c, null # Breaking change in CS2: per ES2015, default values are applied for `undefined` but not for `null`.
{b: c = 4} = {b: 0}
eq c, 0
test "multiple array destructuring defaults", ->
[a = 1, b = 2, c] = [null, 12, 13]
[a = 1, b = 2, c] = [undefined, 12, 13]
eq a, 1
eq b, 12
eq c, 13
[a, b = 2, c = 3] = [null, 12, 13]
eq a, null
[a, b = 2, c = 3] = [undefined, 12, 13]
eq a, undefined
eq b, 12
eq c, 13
[a = 1, b, c = 3] = [11, 12]
@@ -368,7 +369,7 @@ test "destructuring assignment with context (@) properties and defaults", ->
a={}; b={}; c={}; d={}; e={}
obj =
fn: () ->
local = [a, {b, c: null}, d]
local = [a, {b, c: undefined}, d]
[@a, {b: @b = b, @c = c}, @d, @e = e] = local
eq undefined, obj[key] for key in ['a','b','c','d','e']
obj.fn()
@@ -387,7 +388,7 @@ test "destructuring assignment with defaults single evaluation", ->
[a = fn()] = [10]
eq 10, a
eq 1, callCount
{a = fn(), b: c = fn()} = {a: 20, b: null}
{a = fn(), b: c = fn()} = {a: 20, b: undefined}
eq 20, a
eq c, 1
eq callCount, 2

View File

@@ -179,7 +179,7 @@ test "destructuring in function definition", ->
{url, async, beforeSend, cache, method, data}
fn = ->
deepEqual ajax('/home', beforeSend: fn, cache: null, method: 'post'), {
deepEqual ajax('/home', beforeSend: fn, method: 'post'), {
url: '/home', async: true, beforeSend: fn, cache: true, method: 'post', data: {}
}
@@ -352,3 +352,13 @@ test "#4406 Destructured parameter default evaluation order with generator funct
next = -> ++current
foo = ({ a = next() }, b = next()) -> [ a, b ]
arrayEq foo({}), [1, 2]
test "Destructured parameter with default value, that itself has a default value", ->
# Adapted from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
draw = ({size = 'big', coords = {x: 0, y: 0}, radius = 25} = {}) -> "#{size}-#{coords.x}-#{coords.y}-#{radius}"
output = draw
coords:
x: 18
y: 30
radius: 30
eq output, 'big-18-30-30'

View File

@@ -1,19 +1,18 @@
Literate CoffeeScript Test
--------------------------
# Literate CoffeeScript Test
comment comment
test "basic literate CoffeeScript parsing", ->
ok yes
now with a...
test "broken up indentation", ->
... broken up ...
do ->
... nested block.
ok yes
@@ -25,36 +24,36 @@ Code must be separated from text by a blank line.
The next line is part of the text and will not be executed.
fail()
ok yes
ok yes
Code in `backticks is not parsed` and...
test "comments in indented blocks work", ->
do ->
do ->
# Regular comment.
###
Block comment.
###
ok yes
Regular [Markdown](http://example.com/markdown) features, like links
Regular [Markdown](http://example.com/markdown) features, like links
and unordered lists, are fine:
* I
* I
* Am
* A
* List
Tabs work too:
test "tabbed code", ->
ok yes
test "tabbed code", ->
ok yes
---
@@ -63,11 +62,12 @@ Tabs work too:
<p>
executed = true # should not execute, this is just HTML para, not code!
if true
executed = true # should not execute, this is just HTML para, not code!
</p>
test "should ignore indented sections inside HTML", ->
test "should ignore code blocks inside HTML", ->
eq executed, false
---
@@ -119,24 +119,8 @@ Tabs work too:
---
This next one probably passes because a string is inoffensive in compiled js, also, can't get `marked` to parse it correctly, and not sure if empty line is permitted between title and reference
This is [an example][id] reference-style link.
[id]: http://example.com/
"Optional Title Here"
---
executed = no
1986. What a great season.
executed = yes
and test...
test "should recognise indented code blocks in lists", ->
ok executed
[id]: http://example.com/ "Optional Title Here"
---
@@ -148,7 +132,7 @@ and test...
and test...
test "should recognise indented code blocks in lists with empty line as separator", ->
test "should recognize indented code blocks in lists with empty line as separator", ->
ok executed
---
@@ -163,3 +147,11 @@ and test...
test "should ignore indented code in escaped list like number", ->
eq executed, no
one last test!
test "block quotes should render correctly", ->
quote = '''
foo
and bar!
'''
eq quote, 'foo\n and bar!'

View File

@@ -0,0 +1,157 @@
# Tabbed Literate CoffeeScript Test
comment comment
test "basic literate CoffeeScript parsing", ->
ok yes
now with a...
test "broken up indentation", ->
... broken up ...
do ->
... nested block.
ok yes
Code must be separated from text by a blank line.
test "code blocks must be preceded by a blank line", ->
The next line is part of the text and will not be executed.
fail()
ok yes
Code in `backticks is not parsed` and...
test "comments in indented blocks work", ->
do ->
do ->
# Regular comment.
###
Block comment.
###
ok yes
Regular [Markdown](http://example.com/markdown) features, like links
and unordered lists, are fine:
* I
* Am
* A
* List
Spaces work too:
test "spaced code", ->
ok yes
---
# keep track of whether code blocks are executed or not
executed = false
<p>
if true
executed = true # should not execute, this is just HTML para, not code!
</p>
test "should ignore code blocks inside HTML", ->
eq executed, false
---
* A list item with a code block:
test "basic literate CoffeeScript parsing", ->
ok yes
---
* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
viverra nec, fringilla in, laoreet vitae, risus.
* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
Suspendisse id sem consectetuer libero luctus adipiscing.
---
1. This is a list item with two paragraphs. Lorem ipsum dolor
sit amet, consectetuer adipiscing elit. Aliquam hendrerit
mi posuere lectus.
Vestibulum enim wisi, viverra nec, fringilla in, laoreet
vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
sit amet velit.
2. Suspendisse id sem consectetuer libero luctus adipiscing.
---
1. This is a list item with two paragraphs. Lorem ipsum dolor
sit amet, consectetuer adipiscing elit. Aliquam hendrerit
mi posuere lectus.
Vestibulum enim wisi, viverra nec, fringilla in, laoreet
vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
sit amet velit.
2. Suspendisse id sem consectetuer libero luctus adipiscing.
---
* A list item with a blockquote:
> This is a blockquote
> inside a list item.
---
This is [an example][id] reference-style link.
[id]: http://example.com/ "Optional Title Here"
---
executed = no
1986. What a great season.
executed = yes
and test...
test "should recognize indented code blocks in lists with empty line as separator", ->
ok executed
---
executed = no
1986\. What a great season.
executed = yes
and test...
test "should ignore indented code in escaped list like number", ->
eq executed, no
one last test!
test "block quotes should render correctly", ->
quote = '''
foo
and bar!
'''
eq quote, 'foo\n\t\tand bar!'

View File

@@ -1,7 +1,7 @@
# Strict Early Errors
# -------------------
# The following are prohibited under ES5's `strict` mode
# The following are prohibited under ES5s `strict` mode
# * `Octal Integer Literals`
# * `Octal Escape Sequences`
# * duplicate property definitions in `Object Literal`s