1
0
Fork 0
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:
Marc Häfner 2013-06-14 00:21:47 +02:00
parent ba7cb3ab69
commit 4fd5e9a3ab
7 changed files with 342 additions and 220 deletions

View file

@ -32,7 +32,7 @@
Root: [
o('', function() {
return new Block;
}), o('Body'), o('Block TERMINATOR')
}), o('Body')
],
Body: [
o('Line', function() {

View file

@ -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

View file

@ -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.

View file

@ -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
# ---------

View file

@ -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

View file

@ -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