Skip to content

Commit

Permalink
Merge pull request #4313 from eelco/no-whitespace-mixing-strict
Browse files Browse the repository at this point in the history
Don’t allow mixing spaces and tabs for indentation
  • Loading branch information
jashkenas authored Sep 27, 2016
2 parents f8b0c80 + bb40b11 commit c5c4d7c
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 26 deletions.
14 changes: 14 additions & 0 deletions src/lexer.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ exports.Lexer = class Lexer
@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.
@indentLiteral = '' # The indentation
@ends = [] # The stack for pairing up tokens.
@tokens = [] # Stream of parsed tokens in the form `['TYPE', value, location data]`.
@seenFor = no # Used to recognize FORIN and FOROF tokens.
Expand Down Expand Up @@ -351,6 +352,16 @@ exports.Lexer = class Lexer
size = indent.length - 1 - indent.lastIndexOf '\n'
noNewlines = @unfinished()

newIndentLiteral = if size > 0 then indent[-size..] else ''
unless /^(.?)\1*$/.exec newIndentLiteral
@error 'mixed indentation', offset: indent.length
return indent.length

minLiteralLength = Math.min newIndentLiteral.length, @indentLiteral.length
if newIndentLiteral[...minLiteralLength] isnt @indentLiteral[...minLiteralLength]
@error 'indentation mismatch', offset: indent.length
return indent.length

if size - @indebt is @indent
if noNewlines then @suppressNewlines() else @newlineToken 0
return indent.length
Expand All @@ -362,13 +373,15 @@ exports.Lexer = class Lexer
return indent.length
unless @tokens.length
@baseIndent = @indent = size
@indentLiteral = newIndentLiteral
return indent.length
diff = size - @indent + @outdebt
@token 'INDENT', diff, indent.length - size, size
@indents.push diff
@ends.push {tag: 'OUTDENT'}
@outdebt = @indebt = 0
@indent = size
@indentLiteral = newIndentLiteral
else if size < @baseIndent
@error 'missing indentation', offset: indent.length
else
Expand Down Expand Up @@ -405,6 +418,7 @@ exports.Lexer = class Lexer

@token 'TERMINATOR', '\n', outdentLength, 0 unless @tag() is 'TERMINATOR' or noNewlines
@indent = decreasedIndent
@indentLiteral = @indentLiteral[...decreasedIndent]
this

# Matches and consumes non-meaningful whitespace. Tag the previous token
Expand Down
2 changes: 1 addition & 1 deletion test/compilation.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ test "#2516: Unicode spaces should not be part of identifiers", ->
eq 5, {c: 5}[ 'c' ]

# A line where every space in non-breaking
  eq 1 + 12  
eq 1 + 12  

test "don't accidentally stringify keywords", ->
ok (-> this == 'this')() is false
Expand Down
12 changes: 0 additions & 12 deletions test/error_messages.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,6 @@ test "compiler error formatting", ->
^^^^
'''

test "compiler error formatting with mixed tab and space", ->
assertErrorFormat """
\t if a
\t test
""",
'''
[stdin]:1:4: error: unexpected if
\t if a
\t ^^
'''


if require?
fs = require 'fs'
path = require 'path'
Expand Down
33 changes: 33 additions & 0 deletions test/formatting.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -254,3 +254,36 @@ test "#1275: allow indentation before closing brackets", ->
a = 1
)
eq 1, a

test "don’t allow mixing of spaces and tabs for indentation", ->
try
CoffeeScript.compile '''
new Layer
x: 0
y: 1
'''
ok no
catch e
eq 'indentation mismatch', e.message

test "each code block that starts at indentation 0 can use a different style", ->
doesNotThrow ->
CoffeeScript.compile '''
new Layer
x: 0
y: 1
new Layer
x: 0
y: 1
'''

test "tabs and spaces cannot be mixed for indentation", ->
try
CoffeeScript.compile '''
new Layer
x: 0
y: 1
'''
ok no
catch e
eq 'mixed indentation', e.message
26 changes: 13 additions & 13 deletions test/scope.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -59,21 +59,21 @@ test "#1183: super + fat arrows", ->
dolater = (cb) -> cb()

class A
constructor: ->
@_i = 0
foo : (cb) ->
dolater =>
@_i += 1
cb()
constructor: ->
@_i = 0
foo : (cb) ->
dolater =>
@_i += 1
cb()

class B extends A
constructor : ->
super
foo : (cb) ->
dolater =>
dolater =>
@_i += 2
super cb
constructor : ->
super
foo : (cb) ->
dolater =>
dolater =>
@_i += 2
super cb

b = new B
b.foo => eq b._i, 3
Expand Down

0 comments on commit c5c4d7c

Please sign in to comment.