From ffa25aae77b7e4526b96eb3c5a197fbe4b2e74c3 Mon Sep 17 00:00:00 2001 From: Simon Lydell Date: Tue, 3 Feb 2015 20:42:50 +0100 Subject: [PATCH] Improve error messages for unexpected regexes --- lib/coffee-script/lexer.js | 7 ++++--- src/lexer.coffee | 5 +++-- test/error_messages.coffee | 16 ++++++++++++++++ test/location.coffee | 2 +- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/lib/coffee-script/lexer.js b/lib/coffee-script/lexer.js index 99d76328..e39bcd13 100644 --- a/lib/coffee-script/lexer.js +++ b/lib/coffee-script/lexer.js @@ -279,7 +279,7 @@ }; Lexer.prototype.regexToken = function() { - var closed, end, flags, index, match, prev, re, ref2, ref3, regex, rparen, tokens; + var closed, end, errorToken, flags, index, match, prev, re, ref2, ref3, regex, rparen, tokens; switch (false) { case !(match = REGEX_ILLEGAL.exec(this.chunk)): this.error("regular expressions cannot begin with " + match[2], match.index + match[1].length); @@ -309,6 +309,7 @@ } flags = REGEX_FLAGS.exec(this.chunk.slice(index))[0]; end = index + flags.length; + errorToken = this.makeToken('REGEX', this.chunk.slice(0, end), 0, end); switch (false) { case !!VALID_FLAGS.test(flags): this.error("invalid regular expression flags " + flags, index); @@ -318,11 +319,11 @@ break; case tokens.length !== 1: re = this.formatHeregex(tokens[0][1]).replace(/\//g, '\\/'); - this.token('REGEX', "/" + (re || '(?:)') + "/" + flags); + this.token('REGEX', "/" + (re || '(?:)') + "/" + flags, 0, end, errorToken); break; default: this.token('IDENTIFIER', 'RegExp', 0, 0); - this.token('CALL_START', '(', 0, 0); + this.token('CALL_START', '(', 0, 0, errorToken); this.mergeInterpolationTokens(tokens, '"', (function(_this) { return function(value) { return _this.formatHeregex(value).replace(/\\/g, '\\\\'); diff --git a/src/lexer.coffee b/src/lexer.coffee index 9a8cc88f..8cbc9b5d 100644 --- a/src/lexer.coffee +++ b/src/lexer.coffee @@ -272,6 +272,7 @@ exports.Lexer = class Lexer [flags] = REGEX_FLAGS.exec @chunk[index..] end = index + flags.length + errorToken = @makeToken 'REGEX', @chunk[...end], 0, end switch when not VALID_FLAGS.test flags @error "invalid regular expression flags #{flags}", index @@ -279,10 +280,10 @@ exports.Lexer = class Lexer @token 'REGEX', "#{regex}#{flags}" when tokens.length is 1 re = @formatHeregex(tokens[0][1]).replace(/\//g, '\\/') - @token 'REGEX', "/#{ re or '(?:)' }/#{flags}" + @token 'REGEX', "/#{ re or '(?:)' }/#{flags}", 0, end, errorToken else @token 'IDENTIFIER', 'RegExp', 0, 0 - @token 'CALL_START', '(', 0, 0 + @token 'CALL_START', '(', 0, 0, errorToken @mergeInterpolationTokens tokens, '"', (value) => @formatHeregex(value).replace(/\\/g, '\\\\') if flags diff --git a/test/error_messages.coffee b/test/error_messages.coffee index 19b3a8d3..9e351e2c 100644 --- a/test/error_messages.coffee +++ b/test/error_messages.coffee @@ -125,6 +125,22 @@ test "#1096: unexpected generated tokens", -> for i in [1]: ^ ''' + # Unexpected regex + assertErrorFormat '{/a/i: val}', ''' + [stdin]:1:2: error: unexpected /a/i + {/a/i: val} + ^^^^ + ''' + assertErrorFormat '{///a///i: val}', ''' + [stdin]:1:2: error: unexpected ///a///i + {///a///i: val} + ^^^^^^^^ + ''' + assertErrorFormat '{///#{a}///i: val}', ''' + [stdin]:1:2: error: unexpected ///#{a}///i + {///#{a}///i: val} + ^^^^^^^^^^^ + ''' test "#1316: unexpected end of interpolation", -> assertErrorFormat ''' diff --git a/test/location.coffee b/test/location.coffee index 3369fe59..fa7f68c5 100644 --- a/test/location.coffee +++ b/test/location.coffee @@ -446,7 +446,7 @@ test "#3621: Multiline regex and manual `Regex` call with interpolation should tokenB = tokensB[i] eq tokenA[0], tokenB[0] eq tokenA[1], tokenB[1] - eq tokenA.origin?[1], tokenB.origin?[1] + eq tokenA.origin?[1], tokenB.origin?[1] unless tokenA[0] is 'CALL_START' eq tokenA.stringEnd, tokenB.stringEnd test "Verify all tokens get a location", ->