making the lexer more sophisticated about incorrect outdents ... a little safer for everyone.

This commit is contained in:
Jeremy Ashkenas 2010-06-01 23:32:46 -04:00
parent 1fbb6e8734
commit 61d9bd7e5e
3 changed files with 33 additions and 9 deletions

View File

@ -54,6 +54,8 @@
// The current line.
this.indent = 0;
// The current indentation level.
this.outdebt = 0;
// The under-outdentation of the last outdent.
this.indents = [];
// The stack of all current indentation levels.
this.tokens = [];
@ -321,10 +323,17 @@
// inwards past several recorded indents.
Lexer.prototype.outdent_token = function(move_out, no_newlines) {
var last_indent;
while (move_out > 0 && this.indents.length) {
last_indent = this.indents.pop();
this.token('OUTDENT', last_indent);
move_out -= last_indent;
if (move_out > -this.outdebt) {
while (move_out > 0 && this.indents.length) {
last_indent = this.indents.pop();
this.token('OUTDENT', last_indent);
move_out -= last_indent;
}
} else {
this.outdebt += move_out;
}
if (!(no_newlines)) {
this.outdebt = move_out;
}
if (!(this.tag() === 'TERMINATOR' || no_newlines)) {
this.token('TERMINATOR', "\n");

View File

@ -46,6 +46,7 @@ exports.Lexer: class Lexer
@i : 0 # Current character position we're parsing.
@line : o.line or 0 # The current line.
@indent : 0 # The current indentation level.
@outdebt : 0 # The under-outdentation of the last outdent.
@indents : [] # The stack of all current indentation levels.
@tokens : [] # Stream of parsed tokens in the form ['TYPE', value, line]
while @i < @code.length
@ -218,10 +219,14 @@ exports.Lexer: class Lexer
# Record an outdent token or multiple tokens, if we happen to be moving back
# inwards past several recorded indents.
outdent_token: (move_out, no_newlines) ->
while move_out > 0 and @indents.length
last_indent: @indents.pop()
@token 'OUTDENT', last_indent
move_out: - last_indent
if move_out > -@outdebt
while move_out > 0 and @indents.length
last_indent: @indents.pop()
@token 'OUTDENT', last_indent
move_out: - last_indent
else
@outdebt: + move_out
@outdebt: move_out unless no_newlines
@token 'TERMINATOR', "\n" unless @tag() is 'TERMINATOR' or no_newlines
true

View File

@ -22,4 +22,14 @@ counter
.tick ->
1
ok results.join(' ') is '3 2 1'
ok results.join(' ') is '3 2 1'
# Make incorrect indentation safe.
func: ->
obj: {
key: 10
}
obj.key - 5
ok func() is 5