Skip to content

Commit 55ee19b

Browse files
authored
fix: properly set location data in OUTDENT nodes (jashkenas#2)
Backport of jashkenas#4291 . In f609036, a line was changed from `if length > 0 then (length - 1) else 0` to `Math.max 0, length - 1`. However, in some cases, the `length` variable can be `undefined`. The previous code would correctly compute `lastCharacter` as 0, but the new code would compute it as `NaN`. This would cause trouble later on: the end location would just be the end of the current chunk, which would be incorrect. Here's a specific case where the parser was behaving incorrectly: ``` a { b: -> return c d, if e f } g ``` The OUTDENT tokens after the `f` had an undefined length, so the `NaN` made it so the end location was at the end of the file. That meant that various nodes in the AST, like the `return` node, would incorrectly have an end location at the end of the file. To fix, I just reverted the change to that particular line. Also add a test that tokens have locations that are in order
1 parent c558757 commit 55ee19b

File tree

3 files changed

+21
-2
lines changed

3 files changed

+21
-2
lines changed

lib/coffee-script/lexer.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/lexer.coffee

+1-1
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,7 @@ exports.Lexer = class Lexer
649649

650650
# Use length - 1 for the final offset - we're supplying the last_line and the last_column,
651651
# so if last_column == first_column, then we're looking at a character of length 1.
652-
lastCharacter = Math.max 0, length - 1
652+
lastCharacter = if length > 0 then (length - 1) else 0
653653
[locationData.last_line, locationData.last_column] =
654654
@getLineAndColumnFromChunk offsetInChunk + lastCharacter
655655

test/location.coffee

+19
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,25 @@ test "#3621: Multiline regex and manual `Regex` call with interpolation should
450450
eq tokenA.origin?[1], tokenB.origin?[1]
451451
eq tokenA.stringEnd, tokenB.stringEnd
452452

453+
test "Verify tokens have locations that are in order", ->
454+
source = '''
455+
a {
456+
b: ->
457+
return c d,
458+
if e
459+
f
460+
}
461+
g
462+
'''
463+
tokens = CoffeeScript.tokens source
464+
lastToken = null
465+
for token in tokens
466+
if lastToken
467+
ok token[2].first_line >= lastToken[2].last_line
468+
if token[2].first_line == lastToken[2].last_line
469+
ok token[2].first_column >= lastToken[2].last_column
470+
lastToken = token
471+
453472
test "Verify all tokens get a location", ->
454473
doesNotThrow ->
455474
tokens = CoffeeScript.tokens testScript

0 commit comments

Comments
 (0)