mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-05-03 03:00:14 -04:00
[CS2] Throw an error for ambiguous get or set keywords or function calls (#4484)
* Throw an error for ambiguous `get` or `set` function calls or ES5 getter/setter keywords, to warn the user to use parentheses if they intend a function call (or to inform them that `get` or `set` cannot be used as a keyword)
* Code golf
* Catch get or set keyword before static method
* DRY up getting the previous token
* Throw an error if get or set are used as keywords before what looks like a function or method with an interpolated/dynamic name
* Allow `get` or `set` parentheses-less function calls when first argument is a string without a colon (so a plain string, not a property accessor)
* Revert "Allow `get` or `set` parentheses-less function calls when first argument is a string without a colon (so a plain string, not a property accessor)"
This reverts commit 2d1addf5a4.
* Optimization
* No longer throw an error on `get` or `set` function calls to objects with dynamic property names (introduces a way to circumvent our check for trying to avoid the `get` or `set` keywords, but not worth the complications for this tiny edge case)
This commit is contained in:
@@ -132,7 +132,7 @@ exports.Lexer = class Lexer
|
||||
@token 'DEFAULT', id
|
||||
return id.length
|
||||
|
||||
[..., prev] = @tokens
|
||||
prev = @prev()
|
||||
|
||||
tag =
|
||||
if colon or prev? and
|
||||
@@ -170,6 +170,16 @@ exports.Lexer = class Lexer
|
||||
isForFrom(prev)
|
||||
tag = 'FORFROM'
|
||||
@seenFor = no
|
||||
# Throw an error on attempts to use `get` or `set` as keywords, or
|
||||
# what CoffeeScript would normally interpret as calls to functions named
|
||||
# `get` or `set`, i.e. `get({foo: function () {}})`
|
||||
else if tag is 'PROPERTY' and prev
|
||||
if prev.spaced and prev[0] in CALLABLE and /^[gs]et$/.test(prev[1])
|
||||
@error "'#{prev[1]}' cannot be used as a keyword, or as a function call without parentheses", prev[2]
|
||||
else
|
||||
prevprev = @tokens[@tokens.length - 2]
|
||||
if prev[0] in ['@', 'THIS'] and prevprev and prevprev.spaced and /^[gs]et$/.test(prevprev[1])
|
||||
@error "'#{prevprev[1]}' cannot be used as a keyword, or as a function call without parentheses", prevprev[2]
|
||||
|
||||
if tag is 'IDENTIFIER' and id in RESERVED
|
||||
@error "reserved word '#{id}'", length: id.length
|
||||
@@ -237,8 +247,9 @@ exports.Lexer = class Lexer
|
||||
|
||||
# If the preceding token is `from` and this is an import or export statement,
|
||||
# properly tag the `from`.
|
||||
if @tokens.length and @value() is 'from' and (@seenImport or @seenExport)
|
||||
@tokens[@tokens.length - 1][0] = 'FROM'
|
||||
prev = @prev()
|
||||
if prev and @value() is 'from' and (@seenImport or @seenExport)
|
||||
prev[0] = 'FROM'
|
||||
|
||||
regex = switch quote
|
||||
when "'" then STRING_SINGLE
|
||||
@@ -318,7 +329,7 @@ exports.Lexer = class Lexer
|
||||
[regex, body, closed] = match
|
||||
@validateEscapes body, isRegex: yes, offsetInChunk: 1
|
||||
index = regex.length
|
||||
[..., prev] = @tokens
|
||||
prev = @prev()
|
||||
if prev
|
||||
if prev.spaced and prev[0] in CALLABLE
|
||||
return 0 if not closed or POSSIBLY_DIVISION.test regex
|
||||
@@ -440,7 +451,7 @@ exports.Lexer = class Lexer
|
||||
whitespaceToken: ->
|
||||
return 0 unless (match = WHITESPACE.exec @chunk) or
|
||||
(nline = @chunk.charAt(0) is '\n')
|
||||
[..., prev] = @tokens
|
||||
prev = @prev()
|
||||
prev[if match then 'spaced' else 'newLine'] = true if prev
|
||||
if match then match[0].length else 0
|
||||
|
||||
@@ -468,7 +479,7 @@ exports.Lexer = class Lexer
|
||||
else
|
||||
value = @chunk.charAt 0
|
||||
tag = value
|
||||
[..., prev] = @tokens
|
||||
prev = @prev()
|
||||
|
||||
if prev and value in ['=', COMPOUND_ASSIGN...]
|
||||
skipToken = false
|
||||
@@ -758,6 +769,10 @@ exports.Lexer = class Lexer
|
||||
[..., token] = @tokens
|
||||
token?[1]
|
||||
|
||||
# Get the previous token in the token stream.
|
||||
prev: ->
|
||||
@tokens[@tokens.length - 1]
|
||||
|
||||
# Are we in the midst of an unfinished expression?
|
||||
unfinished: ->
|
||||
LINE_CONTINUER.test(@chunk) or
|
||||
|
||||
@@ -775,7 +775,7 @@ exports.Call = class Call extends Base
|
||||
constructor: (@variable, @args = [], @soak) ->
|
||||
super()
|
||||
|
||||
@isNew = false
|
||||
@isNew = no
|
||||
if @variable instanceof Value and @variable.isNotCallable()
|
||||
@variable.error "literal is not a function"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user