mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
Better handling of initial indent at file start.
* Detect initial indentation before the first token and enforce it. * Don't add `INDENT` token (or the matching `OUTDENT, TERMINATOR`).
This commit is contained in:
parent
ba7cb3ab69
commit
4fd5e9a3ab
7 changed files with 342 additions and 220 deletions
|
@ -32,7 +32,7 @@
|
|||
Root: [
|
||||
o('', function() {
|
||||
return new Block;
|
||||
}), o('Body'), o('Block TERMINATOR')
|
||||
}), o('Body')
|
||||
],
|
||||
Body: [
|
||||
o('Line', function() {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
}
|
||||
this.literate = opts.literate;
|
||||
this.indent = 0;
|
||||
this.baseIndent = 0;
|
||||
this.indebt = 0;
|
||||
this.outdebt = 0;
|
||||
this.indents = [];
|
||||
|
@ -346,11 +347,17 @@
|
|||
this.suppressNewlines();
|
||||
return indent.length;
|
||||
}
|
||||
if (!this.tokens.length) {
|
||||
this.baseIndent = this.indent = size;
|
||||
return indent.length;
|
||||
}
|
||||
diff = size - this.indent + this.outdebt;
|
||||
this.token('INDENT', diff, indent.length - size, size);
|
||||
this.indents.push(diff);
|
||||
this.ends.push('OUTDENT');
|
||||
this.outdebt = this.indebt = 0;
|
||||
} else if (size < this.baseIndent) {
|
||||
this.error('missing indentation', indent.length);
|
||||
} else {
|
||||
this.indebt = 0;
|
||||
this.outdentToken(this.indent - size, noNewlines, indent.length);
|
||||
|
@ -774,10 +781,15 @@
|
|||
return quote + this.escapeLines(body, heredoc) + quote;
|
||||
};
|
||||
|
||||
Lexer.prototype.error = function(message) {
|
||||
Lexer.prototype.error = function(message, offset) {
|
||||
var first_column, first_line, _ref2;
|
||||
if (offset == null) {
|
||||
offset = 0;
|
||||
}
|
||||
_ref2 = this.getLineAndColumnFromChunk(offset), first_line = _ref2[0], first_column = _ref2[1];
|
||||
return throwSyntaxError(message, {
|
||||
first_line: this.chunkLine,
|
||||
first_column: this.chunkColumn
|
||||
first_line: first_line,
|
||||
first_column: first_column
|
||||
});
|
||||
};
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -74,7 +74,6 @@ grammar =
|
|||
Root: [
|
||||
o '', -> new Block
|
||||
o 'Body'
|
||||
o 'Block TERMINATOR'
|
||||
]
|
||||
|
||||
# Any list of statements and expressions, separated by line breaks or semicolons.
|
||||
|
|
|
@ -35,13 +35,14 @@ exports.Lexer = class Lexer
|
|||
# Before returning the token stream, run it through the [Rewriter](rewriter.html)
|
||||
# unless explicitly asked not to.
|
||||
tokenize: (code, opts = {}) ->
|
||||
@literate = opts.literate # Are we lexing literate CoffeeScript?
|
||||
@indent = 0 # The current indentation level.
|
||||
@indebt = 0 # The over-indentation at the current level.
|
||||
@outdebt = 0 # The under-outdentation at the current level.
|
||||
@indents = [] # The stack of all current indentation levels.
|
||||
@ends = [] # The stack for pairing up tokens.
|
||||
@tokens = [] # Stream of parsed tokens in the form `['TYPE', value, location data]`.
|
||||
@literate = opts.literate # Are we lexing literate CoffeeScript?
|
||||
@indent = 0 # The current indentation level.
|
||||
@baseIndent = 0 # The overall minimum indentation level
|
||||
@indebt = 0 # The over-indentation at the current level.
|
||||
@outdebt = 0 # The under-outdentation at the current level.
|
||||
@indents = [] # The stack of all current indentation levels.
|
||||
@ends = [] # The stack for pairing up tokens.
|
||||
@tokens = [] # Stream of parsed tokens in the form `['TYPE', value, location data]`.
|
||||
|
||||
@chunkLine =
|
||||
opts.line or 0 # The start line for the current @chunk.
|
||||
|
@ -322,11 +323,16 @@ exports.Lexer = class Lexer
|
|||
@indebt = size - @indent
|
||||
@suppressNewlines()
|
||||
return indent.length
|
||||
unless @tokens.length
|
||||
@baseIndent = @indent = size
|
||||
return indent.length
|
||||
diff = size - @indent + @outdebt
|
||||
@token 'INDENT', diff, indent.length - size, size
|
||||
@indents.push diff
|
||||
@ends.push 'OUTDENT'
|
||||
@outdebt = @indebt = 0
|
||||
else if size < @baseIndent
|
||||
@error 'missing indentation', indent.length
|
||||
else
|
||||
@indebt = 0
|
||||
@outdentToken @indent - size, noNewlines, indent.length
|
||||
|
@ -691,10 +697,11 @@ exports.Lexer = class Lexer
|
|||
quote + @escapeLines(body, heredoc) + quote
|
||||
|
||||
# Throws a compiler error on the current position.
|
||||
error: (message) ->
|
||||
error: (message, offset = 0) ->
|
||||
# TODO: Are there some cases we could improve the error line number by
|
||||
# passing the offset in the chunk where the error happened?
|
||||
throwSyntaxError message, first_line: @chunkLine, first_column: @chunkColumn
|
||||
[first_line, first_column] = @getLineAndColumnFromChunk offset
|
||||
throwSyntaxError message, {first_line, first_column}
|
||||
|
||||
# Constants
|
||||
# ---------
|
||||
|
|
|
@ -144,3 +144,10 @@ test "#1299: Disallow token misnesting", ->
|
|||
ok no
|
||||
catch e
|
||||
eq 'unmatched ]', e.message
|
||||
|
||||
test "#2981: Enforce initial indentation", ->
|
||||
try
|
||||
CoffeeScript.compile ' a\nb'
|
||||
ok no
|
||||
catch e
|
||||
eq 'missing indentation', e.message
|
||||
|
|
|
@ -41,8 +41,8 @@ test "Verify location of generated tokens", ->
|
|||
test "Verify location of generated tokens (with indented first line)", ->
|
||||
tokens = CoffeeScript.tokens " a = 83"
|
||||
|
||||
eq tokens.length, 6
|
||||
[IndentToken, aToken, equalsToken, numberToken] = tokens
|
||||
eq tokens.length, 4
|
||||
[aToken, equalsToken, numberToken] = tokens
|
||||
|
||||
eq aToken[2].first_line, 0
|
||||
eq aToken[2].first_column, 2
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue