mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-05-03 03:00:14 -04:00
Merge pull request #4313 from eelco/no-whitespace-mixing-strict
Don’t allow mixing spaces and tabs for indentation
This commit is contained in:
@@ -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.
|
||||
@@ -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
|
||||
@@ -362,6 +373,7 @@ 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
|
||||
@@ -369,6 +381,7 @@ exports.Lexer = class Lexer
|
||||
@ends.push {tag: 'OUTDENT'}
|
||||
@outdebt = @indebt = 0
|
||||
@indent = size
|
||||
@indentLiteral = newIndentLiteral
|
||||
else if size < @baseIndent
|
||||
@error 'missing indentation', offset: indent.length
|
||||
else
|
||||
@@ -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
|
||||
|
||||
@@ -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 + 1, 2
|
||||
eq 1 + 1, 2
|
||||
|
||||
test "don't accidentally stringify keywords", ->
|
||||
ok (-> this == 'this')() is false
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user