mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
Fixed leading whitespace before interpolation in simple strings
This commit is contained in:
parent
b11d956d53
commit
a61b6ee925
3 changed files with 44 additions and 38 deletions
|
@ -166,30 +166,25 @@
|
|||
};
|
||||
|
||||
Lexer.prototype.stringToken = function() {
|
||||
var match, octalEsc, string;
|
||||
switch (this.chunk.charAt(0)) {
|
||||
var octalEsc, quote, string, trimmed;
|
||||
switch (quote = this.chunk.charAt(0)) {
|
||||
case "'":
|
||||
if (!(match = SIMPLESTR.exec(this.chunk))) {
|
||||
return 0;
|
||||
}
|
||||
string = match[0];
|
||||
this.token('STRING', this.escapeLines(string), 0, string.length);
|
||||
string = SIMPLESTR.exec(this.chunk)[0];
|
||||
break;
|
||||
case '"':
|
||||
if (!(string = this.balancedString(this.chunk, '"'))) {
|
||||
return 0;
|
||||
}
|
||||
if (0 < string.indexOf('#{', 1)) {
|
||||
this.interpolateString(string.slice(1, -1), {
|
||||
strOffset: 1,
|
||||
lexedLength: string.length
|
||||
});
|
||||
} else {
|
||||
this.token('STRING', this.escapeLines(string), 0, string.length);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
string = this.balancedString(this.chunk, '"');
|
||||
}
|
||||
if (!string) {
|
||||
return 0;
|
||||
}
|
||||
trimmed = this.removeNewlines(string.slice(1, -1));
|
||||
if (quote === '"' && 0 < string.indexOf('#{', 1)) {
|
||||
this.interpolateString(trimmed, {
|
||||
strOffset: 1,
|
||||
lexedLength: string.length
|
||||
});
|
||||
} else {
|
||||
this.token('STRING', quote + this.escapeLines(trimmed) + quote, 0, string.length);
|
||||
}
|
||||
if (octalEsc = /^(?:\\.|[^\\])*\\(?:0[0-7]|[1-7])/.test(string)) {
|
||||
this.error("octal escape sequences " + string + " are not allowed");
|
||||
|
@ -763,6 +758,10 @@
|
|||
return LINE_CONTINUER.test(this.chunk) || ((_ref2 = this.tag()) === '\\' || _ref2 === '.' || _ref2 === '?.' || _ref2 === '?::' || _ref2 === 'UNARY' || _ref2 === 'MATH' || _ref2 === '+' || _ref2 === '-' || _ref2 === 'SHIFT' || _ref2 === 'RELATION' || _ref2 === 'COMPARE' || _ref2 === 'LOGIC' || _ref2 === 'THROW' || _ref2 === 'EXTENDS');
|
||||
};
|
||||
|
||||
Lexer.prototype.removeNewlines = function(str) {
|
||||
return str.replace(/^\s*\n\s*/, '').replace(/([^\\]|\\\\)\s*\n\s*$/, '$1');
|
||||
};
|
||||
|
||||
Lexer.prototype.escapeLines = function(str, heredoc) {
|
||||
str = str.replace(/\\[^\S\n]*(\n|\\)\s*/g, function(escaped, character) {
|
||||
if (character === '\n') {
|
||||
|
@ -774,7 +773,7 @@
|
|||
if (heredoc) {
|
||||
return str.replace(MULTILINER, '\\n');
|
||||
} else {
|
||||
return str.replace(/^(.)\s*\n\s*/, '$1').replace(/\s*\n\s*(.)$/, '$1').replace(/\s*\n\s*/g, ' ');
|
||||
return str.replace(/\s*\n\s*/g, ' ');
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -186,19 +186,15 @@ exports.Lexer = class Lexer
|
|||
# Matches strings, including multi-line strings. Ensures that quotation marks
|
||||
# are balanced within the string's contents, and within nested interpolations.
|
||||
stringToken: ->
|
||||
switch @chunk.charAt 0
|
||||
when "'"
|
||||
return 0 unless match = SIMPLESTR.exec @chunk
|
||||
string = match[0]
|
||||
@token 'STRING', @escapeLines(string), 0, string.length
|
||||
when '"'
|
||||
return 0 unless string = @balancedString @chunk, '"'
|
||||
if 0 < string.indexOf '#{', 1
|
||||
@interpolateString string[1...-1], strOffset: 1, lexedLength: string.length
|
||||
else
|
||||
@token 'STRING', @escapeLines(string), 0, string.length
|
||||
else
|
||||
return 0
|
||||
switch quote = @chunk.charAt 0
|
||||
when "'" then [string] = SIMPLESTR.exec @chunk
|
||||
when '"' then string = @balancedString @chunk, '"'
|
||||
return 0 unless string
|
||||
trimmed = @removeNewlines string[1...-1]
|
||||
if quote is '"' and 0 < string.indexOf '#{', 1
|
||||
@interpolateString trimmed, strOffset: 1, lexedLength: string.length
|
||||
else
|
||||
@token 'STRING', quote + @escapeLines(trimmed) + quote, 0, string.length
|
||||
if octalEsc = /^(?:\\.|[^\\])*\\(?:0[0-7]|[1-7])/.test string
|
||||
@error "octal escape sequences #{string} are not allowed"
|
||||
string.length
|
||||
|
@ -686,6 +682,11 @@ exports.Lexer = class Lexer
|
|||
@tag() in ['\\', '.', '?.', '?::', 'UNARY', 'MATH', '+', '-', 'SHIFT', 'RELATION'
|
||||
'COMPARE', 'LOGIC', 'THROW', 'EXTENDS']
|
||||
|
||||
# Remove newlines from beginning and (non escaped) from end of string literals.
|
||||
removeNewlines: (str) ->
|
||||
str.replace(/^\s*\n\s*/, '')
|
||||
.replace(/([^\\]|\\\\)\s*\n\s*$/, '$1')
|
||||
|
||||
# Converts newlines for string literals.
|
||||
escapeLines: (str, heredoc) ->
|
||||
# Ignore escaped backslashes and remove escaped newlines
|
||||
|
@ -695,9 +696,7 @@ exports.Lexer = class Lexer
|
|||
str.replace MULTILINER, '\\n'
|
||||
else
|
||||
# Trim leading and trailing whitespace, string includes quotes
|
||||
str.replace(/^(.)\s*\n\s*/, '$1')
|
||||
.replace(/\s*\n\s*(.)$/, '$1')
|
||||
.replace(/\s*\n\s*/g, ' ')
|
||||
str.replace /\s*\n\s*/g, ' '
|
||||
|
||||
# Constructs a string token by escaping quotes and newlines.
|
||||
makeString: (body, quote, heredoc) ->
|
||||
|
|
|
@ -81,6 +81,9 @@ test "#3229, multiline strings", ->
|
|||
'string ' + "inside
|
||||
interpolation"
|
||||
}", "a string inside interpolation"
|
||||
eq "
|
||||
#{1}
|
||||
", '1'
|
||||
|
||||
# Handle escaped backslashes correctly.
|
||||
eq '\\', `'\\'`
|
||||
|
@ -155,6 +158,11 @@ test "#3249, escape newlines in heredocs with backslashes", ->
|
|||
too #{3}\
|
||||
!
|
||||
""", 'interpolation 1\n follows 2 too 3!'
|
||||
eq """
|
||||
|
||||
#{1} #{2}
|
||||
|
||||
""", '\n1 2\n'
|
||||
|
||||
# TODO: uncomment when #2388 is fixed
|
||||
# eq """a heredoc #{
|
||||
|
|
Loading…
Reference in a new issue