1
0
Fork 0
mirror of https://github.com/jashkenas/coffeescript.git synced 2022-11-09 12:23:24 -05:00

[CS2] Comments (#4572)

* Make `addLocationDataFn` more DRY

* Style fixes

* Provide access to full parser inside our custom function running in parser.js; rename the function to lay the groundwork for adding data aside from location data

* Fix style.

* Fix style.

* Label test comments

* Update grammar to remove comment tokens; update DSL to call new helper function that preserves comments through parsing

* New implementation of compiling block comments: the lexer pulls them out of the token stream, attaching them as a property to a token; the rewriter moves the attachment around so it lives on a token that is destined to make it through to compilation (and in a good placement); and the nodes render the block comment. All tests but one pass (commented out).

* If a comment follows a class declaration, move the comment inside the class body

* Style

* Improve indentation of multiline comments

* Fix indentation for block comments, at least in the cases covered by the one failing test

* Don’t reverse the order of unshifted comments

* Simplify rewriter’s handling of comments, generalizing the special case

* Expand the list of tokens we need to avoid for passing comments through the parser; get some literal tokens to have nodes created for them so that the comments pass through

* Improve comments; fix multiline flag

* Prepare HereComments for processing line comments

* Line comments, first draft: the tests pass, but the line comments aren’t indented and sometimes trail previous lines when they shouldn’t; updated compiler output in following commit

* Updated compiler, now with line comments

* `process` doesn’t exist in the browser, so we should check for its existence first

* Update parser output

* Test that proves #4290 is fixed

* Indent line comments, first pass

* Compiled output with indented line comments

* Comments that start a new line shouldn’t trail; don’t skip comments attached to generated tokens; stop looking for indentation once we hit a newline

* Revised output

* Cleanup

* Split “multiline” line comment tokens, shifting them forward or back as appropriate

* Fix comments in module specifiers

* Abstract attaching comments to a node

* Line comments in interpolated strings

* Line comments can’t be multiline anymore

* Improve handling of blank lines and indentation of following comments that start a new line (i.e. don’t trail)

* Make comments compilation more object-oriented

* Remove lots of dead code that we don’t need anymore because a comment is never a node, only a fragment

* Improve eqJS helper

* Fix #4290 definitively, with improved output for arrays with interspersed block comments

* Add support for line comments output interspersed within arrays

* Fix mistake, don’t lose the variable we’re working on

* Remove redundant replacements

* Check for indentation only from the start of the string

* Indentations in generated JS are always multiples of two spaces (never tabs) so just look for 2+ spaces

* Update package versions; run Babel twice, once for each preset, temporarily until a Babili bug is fixed that prevents it from running with the env preset

* Don’t rely on `fragment.type`, which can break when the compiler is minified

* Updated generated docs and browser compiler

* Output block comments after function arguments

* Comments appear above scope `var` declarations; better tracking of generated `JS` tokens created only to shepherd comments through to the output

* Create new FuncGlyph node, to hold comments we want to output near the function parameters

* Block comments between `)` and `->`/`=>` get output between `)` and `{`.

* Fix indentation of comments that are the first line inside a bare mode block

* Updated output

* Full Flow example

* Updated browser compiler

* Abstract and organize comment fragment generation code; store more properties on the comment fragment objects; make `throw` behave like `return`

* Abstract token insertion code

* Add missing locationData to STRING_START token, giving it the locationData of the overall StringWithInterpolations token so that comments attached to STRING_START end up on the StringWithInterpolations node

* Allow `SUPER` tokens to carry comments

* Rescue comments from `Existence` nodes and `If` nodes’ conditions

* Rescue comments after `\` line continuation tokens

* Updated compiled output

* Updated browser compiler

* Output block comments in the same `compileFragments` method as line comments, except for inline block comments

* Comments before splice

* Updated browser compiler

* Track compiledComments as a property of Base, to ensure that it’s not a global variable

* Docs: split up the Usage section

* Docs for type annotations via Flow; updated docs output

* Update regular comments documentation

* Updated browser compiler

* Comments before soak

* Comments before static methods, and probably before `@variable =` (this) assignments generally

* Comments before ‘if exists?’, refactor comment before ‘if this.var’ to be more precise, improve helper methods

* Comments before a method that contains ‘super()’ should output above the method property, not above the ‘super.method()’ call

* Fix missing comments before `if not` (i.e. before a UNARY token)

* Fix comments before ‘for’; add test for comment before assignment if (fixed in earlier commit)

* Comments within heregexes

* Updated browser compiler

* Update description to reflect what’s now happening in compileCommentFragments

* Preserve blank lines between line comments; output “whitespace-only” line comments as blank lines, rather than `//` following by whitespace

* Better future-proof comments tests

* Comments before object destructuring; abstract method for setting comments aside before compilation

* Handle more cases of comments before or after `for` loop declaration lines

* Fix indentation of comments preceding `for` loops

* Fix comment before splat function parameter

* Catch another RegexWithInterpolations comment edge case

* Updated browser compiler

* Change heregex example to one that’s more readable; update output

* Remove a few last references to the defunct HERECOMMENT token

* Abstract location hash creation into a function

* Improved clarity per code review notes

* Updated browser compiler
This commit is contained in:
Geoffrey Booth 2017-08-02 19:34:34 -07:00 committed by GitHub
parent 6c9cf37811
commit 6d21dc5495
46 changed files with 10394 additions and 1437 deletions

View file

@ -1,19 +1,27 @@
// Generated by CoffeeScript 2.0.0-beta3
(function() {
var buildLocationData, extend, flatten, ref, repeat, syntaxErrorToString;
// This file contains the common helper functions that we'd like to share among
// the **Lexer**, **Rewriter**, and the **Nodes**. Merge objects, flatten
// arrays, count characters, that sort of thing.
// Peek at the beginning of a given string to see if it matches a sequence.
var attachCommentsToNode, buildLocationData, buildLocationHash, extend, flatten, ref, repeat, syntaxErrorToString;
exports.starts = function(string, literal, start) {
return literal === string.substr(start, literal.length);
};
// Peek at the end of a given string to see if it matches a sequence.
exports.ends = function(string, literal, back) {
var len;
len = literal.length;
return literal === string.substr(string.length - len - (back || 0), len);
};
// Repeat a string `n` times.
exports.repeat = repeat = function(str, n) {
var res;
// Use clever algorithm to have O(log(n)) string concatenation operations.
res = '';
while (n > 0) {
if (n & 1) {
@ -25,6 +33,7 @@
return res;
};
// Trim out all falsy values from an array.
exports.compact = function(array) {
var i, item, len1, results;
results = [];
@ -37,6 +46,7 @@
return results;
};
// Count the number of occurrences of a string in a string.
exports.count = function(string, substr) {
var num, pos;
num = pos = 0;
@ -49,10 +59,14 @@
return num;
};
// Merge objects, returning a fresh copy with attributes from both sides.
// Used every time `Base#compile` is called, to allow properties in the
// options hash to propagate down the tree without polluting other branches.
exports.merge = function(options, overrides) {
return extend(extend({}, options), overrides);
};
// Extend a source object with the properties of another object (shallow copy).
extend = exports.extend = function(object, properties) {
var key, val;
for (key in properties) {
@ -62,6 +76,8 @@
return object;
};
// Return a flattened version of an array.
// Handy for getting a list of `children` from the nodes.
exports.flatten = flatten = function(array) {
var element, flattened, i, len1;
flattened = [];
@ -76,6 +92,8 @@
return flattened;
};
// Delete a key from an object, returning the value. Useful when a node is
// looking for a particular method in an options hash.
exports.del = function(obj, key) {
var val;
val = obj[key];
@ -83,6 +101,7 @@
return val;
};
// Typical Array::some
exports.some = (ref = Array.prototype.some) != null ? ref : function(fn) {
var e, i, len1, ref1;
ref1 = this;
@ -95,12 +114,18 @@
return false;
};
// Helper 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.”
exports.invertLiterate = function(code) {
var blankLine, i, indented, insideComment, len1, line, listItemStart, out, ref1;
out = [];
blankLine = /^\s*$/;
indented = /^[\t ]/;
listItemStart = /^(?:\t?| {0,3})(?:[\*\-\+]|[0-9]{1,9}\.)[ \t]/;
listItemStart = /^(?:\t?| {0,3})(?:[\*\-\+]|[0-9]{1,9}\.)[ \t]/; // Up to one tab, or up to three spaces, or neither;
// followed by `*`, `-` or `+`;
// or by an integer up to 9 digits long, followed by a period;
// followed by a space or a tab.
insideComment = false;
ref1 = code.split('\n');
for (i = 0, len1 = ref1.length; i < len1; i++) {
@ -121,6 +146,8 @@
return out.join('\n');
};
// Merge two jison-style location data objects together.
// If `last` is not provided, this will simply return `first`.
buildLocationData = function(first, last) {
if (!last) {
return first;
@ -134,15 +161,59 @@
}
};
exports.addLocationDataFn = function(first, last) {
buildLocationHash = function(loc) {
return `${loc.first_line}x${loc.first_column}-${loc.last_line}x${loc.last_column}`;
};
// This returns a function which takes an object as a parameter, and if that
// object is an AST node, updates that object's locationData.
// The object is returned either way.
exports.addDataToNode = function(parserState, first, last) {
return function(obj) {
if (((typeof obj) === 'object') && (!!obj['updateLocationDataIfMissing'])) {
var i, len1, objHash, ref1, token, tokenHash;
// Add location data
if (((obj != null ? obj.updateLocationDataIfMissing : void 0) != null) && (first != null)) {
obj.updateLocationDataIfMissing(buildLocationData(first, last));
}
// Add comments data
if (!parserState.tokenComments) {
parserState.tokenComments = {};
ref1 = parserState.parser.tokens;
for (i = 0, len1 = ref1.length; i < len1; i++) {
token = ref1[i];
if (!token.comments) {
continue;
}
tokenHash = buildLocationHash(token[2]);
if (parserState.tokenComments[tokenHash] == null) {
parserState.tokenComments[tokenHash] = token.comments;
} else {
parserState.tokenComments[tokenHash].push(...token.comments);
}
}
}
if (obj.locationData != null) {
objHash = buildLocationHash(obj.locationData);
if (parserState.tokenComments[objHash] != null) {
attachCommentsToNode(parserState.tokenComments[objHash], obj);
}
}
return obj;
};
};
exports.attachCommentsToNode = attachCommentsToNode = function(comments, node) {
if ((comments == null) || comments.length === 0) {
return;
}
if (node.comments == null) {
node.comments = [];
}
return node.comments.push(...comments);
};
// Convert jison location data to a string.
// `obj` can be a token, or a locationData.
exports.locationDataToString = function(obj) {
var locationData;
if (("2" in obj) && ("first_line" in obj[2])) {
@ -157,6 +228,7 @@
}
};
// A `.coffee.md` compatible version of `basename`, that returns the file sans-extension.
exports.baseFileName = function(file, stripExt = false, useWinPathSep = false) {
var parts, pathSep;
pathSep = useWinPathSep ? /\\|\// : /\//;
@ -173,24 +245,36 @@
return parts.join('.');
};
// Determine if a filename represents a CoffeeScript file.
exports.isCoffee = function(file) {
return /\.((lit)?coffee|coffee\.md)$/.test(file);
};
// Determine if a filename represents a Literate CoffeeScript file.
exports.isLiterate = function(file) {
return /\.(litcoffee|coffee\.md)$/.test(file);
};
// Throws a SyntaxError from a given location.
// The error's `toString` will return an error message following the "standard"
// format `<filename>:<line>:<col>: <message>` plus the line with the error and a
// marker showing where the error is.
exports.throwSyntaxError = function(message, location) {
var error;
error = new SyntaxError(message);
error.location = location;
error.toString = syntaxErrorToString;
// Instead of showing the compiler's stacktrace, show our custom error message
// (this is useful when the error bubbles up in Node.js applications that
// compile CoffeeScript for example).
error.stack = error.toString();
throw error;
};
// Update a compiler SyntaxError with source code information if it didn't have
// it already.
exports.updateSyntaxError = function(error, code, filename) {
// Avoid screwing up the `stack` property of other errors (i.e. possible bugs).
if (error.toString === syntaxErrorToString) {
error.code || (error.code = code);
error.filename || (error.filename = filename);
@ -214,8 +298,10 @@
filename = this.filename || '[stdin]';
codeLine = this.code.split('\n')[first_line];
start = first_column;
// Show only the first line on multi-line errors.
end = first_line === last_line ? last_column + 1 : codeLine.length;
marker = codeLine.slice(0, start).replace(/[^\s]/g, ' ') + repeat('^', end - start);
// Check to see if we're running on a color-enabled TTY.
if (typeof process !== "undefined" && process !== null) {
colorsEnabled = ((ref1 = process.stdout) != null ? ref1.isTTY : void 0) && !((ref2 = process.env) != null ? ref2.NODE_DISABLE_COLORS : void 0);
}