fix escape of $ in template strings

https://github.com/dart-lang/dev_compiler/issues/379

R=vsm@google.com

Review URL: https://codereview.chromium.org/1426243002 .
This commit is contained in:
John Messerly 2015-11-02 10:32:49 -08:00
parent edd9cbe7ea
commit 749d820ce6
6 changed files with 26 additions and 15 deletions

View file

@ -2375,10 +2375,10 @@ dart_library.library('dart/_internal', null, /* Imports */[
let POWERS_OF_TEN = dart.const([1.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0, 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0, 100000000000000.0, 1000000000000000.0, 10000000000000000.0, 100000000000000000.0, 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0, 1e+21, 1e+22]); let POWERS_OF_TEN = dart.const([1.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0, 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0, 100000000000000.0, 1000000000000000.0, 10000000000000000.0, 100000000000000000.0, 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0, 1e+21, 1e+22]);
dart.defineLazyProperties(Symbol, { dart.defineLazyProperties(Symbol, {
get publicSymbolPattern() { get publicSymbolPattern() {
return core.RegExp.new(`^(?:${Symbol.operatorRE}$|${Symbol.publicIdentifierRE}(?:=?$|[.](?!$)))+?$`); return core.RegExp.new(`^(?:${Symbol.operatorRE}\$|${Symbol.publicIdentifierRE}(?:=?\$|[.](?!\$)))+?\$`);
}, },
get symbolPattern() { get symbolPattern() {
return core.RegExp.new(`^(?:${Symbol.operatorRE}$|${Symbol.identifierRE}(?:=?$|[.](?!$)))+?$`); return core.RegExp.new(`^(?:${Symbol.operatorRE}\$|${Symbol.identifierRE}(?:=?\$|[.](?!\$)))+?\$`);
} }
}); });
// Exports: // Exports:

View file

@ -1184,7 +1184,7 @@ dart_library.library('dart/core', null, /* Imports */[
[_getKey]() { [_getKey]() {
let key = dart.as(_js_helper.Primitives.getProperty(this, Expando$()._KEY_PROPERTY_NAME), String); let key = dart.as(_js_helper.Primitives.getProperty(this, Expando$()._KEY_PROPERTY_NAME), String);
if (key == null) { if (key == null) {
key = `expando$key$${(() => { key = `expando\$key\$${(() => {
let x = Expando$()._keyCount; let x = Expando$()._keyCount;
Expando$()._keyCount = dart.notNull(x) + 1; Expando$()._keyCount = dart.notNull(x) + 1;
return x; return x;

View file

@ -299,28 +299,35 @@ class JsBuilder {
// Start by escaping the backslashes. // Start by escaping the backslashes.
String escaped = value.replaceAll('\\', '\\\\'); String escaped = value.replaceAll('\\', '\\\\');
// Replace $ in template strings:
// http://www.ecma-international.org/ecma-262/6.0/#sec-template-literal-lexical-components
var quoteReplace = quote == '`' ? r'`$' : quote;
// http://www.ecma-international.org/ecma-262/6.0/#sec-literals-string-literals // http://www.ecma-international.org/ecma-262/6.0/#sec-literals-string-literals
// > All code points may appear literally in a string literal except for the // > All code points may appear literally in a string literal except for the
// > closing quote code points, U+005C (REVERSE SOLIDUS), // > closing quote code points, U+005C (REVERSE SOLIDUS),
// > U+000D (CARRIAGE RETURN), U+2028 (LINE SEPARATOR), // > U+000D (CARRIAGE RETURN), U+2028 (LINE SEPARATOR),
// > U+2029 (PARAGRAPH SEPARATOR), and U+000A (LINE FEED). // > U+2029 (PARAGRAPH SEPARATOR), and U+000A (LINE FEED).
var re = new RegExp('\n|\r|$quote|\b|\f|\t|\v|\u2028|\u2029'); var re = new RegExp('[\n\r$quoteReplace\b\f\t\v\u2028\u2029]');
escaped = escaped.replaceAllMapped(re, (m) { escaped = escaped.replaceAllMapped(re, (m) {
switch (m.group(0)) { switch (m.group(0)) {
case "\n" : return r"\n"; case "\n" : return r"\n";
case "\r" : return r"\r"; case "\r" : return r"\r";
case "\u2028": return r"\u2028"; case "\u2028": return r"\u2028";
case "\u2029": return r"\u2029"; case "\u2029": return r"\u2029";
// Quotes are only replaced if they conflict with the containing quote // Quotes and $ are only replaced if they conflict with the containing
case '"': return r'\"'; // quote, see regex above.
case "'": return r"\'"; case '"': return r'\"';
case "`": return r"\`"; case "'": return r"\'";
case "`": return r"\`";
case r"$": return r"\$";
// TODO(jmesserly): these don't need to be escaped for correctness, // TODO(jmesserly): these don't need to be escaped for correctness,
// but they are conventionally escaped. // but they are conventionally escaped.
case "\b" : return r"\b"; case "\b": return r"\b";
case "\t" : return r"\t"; case "\t": return r"\t";
case "\f" : return r"\f"; case "\f": return r"\f";
case "\v" : return r"\v"; case "\v": return r"\v";
} }
}); });
LiteralString result = new LiteralString('$quote$escaped$quote'); LiteralString result = new LiteralString('$quote$escaped$quote');

View file

@ -9,12 +9,12 @@ author: Dart Dev Compiler team <dev-compiler@dartlang.org>
homepage: https://github.com/dart-lang/dev_compiler homepage: https://github.com/dart-lang/dev_compiler
dependencies: dependencies:
analyzer: ^0.26.1+10 analyzer: ^0.26.1+17
args: ^0.13.0 args: ^0.13.0
cli_util: ^0.0.1 cli_util: ^0.0.1
crypto: ^0.9.0 crypto: ^0.9.0
html: ^0.12.0 html: ^0.12.0
js: ^0.6.0-beta.6 js: ^0.6.0-beta.7
logging: ">=0.9.2 <0.12.0" logging: ">=0.9.2 <0.12.0"
path: ^1.3.0 path: ^1.3.0
pub_semver: ^1.1.0 pub_semver: ^1.1.0

View file

@ -43,7 +43,8 @@ dart_library.library('misc', null, /* Imports */[
return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'; return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
} }
dart.fn(_isWhitespace, core.bool, [core.String]); dart.fn(_isWhitespace, core.bool, [core.String]);
let _escapeMap = dart.const(dart.map({'\n': '\\n', '\r': '\\r', '\f': '\\f', '\b': '\\b', '\t': '\\t', '\v': '\\v', '': '\\x7F'})); let expr = 'foo';
let _escapeMap = dart.const(dart.map({'\n': '\\n', '\r': '\\r', '\f': '\\f', '\b': '\\b', '\t': '\\t', '\v': '\\v', '': '\\x7F', [`\${${expr}}`]: ''}));
function main() { function main() {
core.print(dart.toString(1)); core.print(dart.toString(1));
core.print(dart.toString(1.0)); core.print(dart.toString(1.0));
@ -61,5 +62,6 @@ dart_library.library('misc', null, /* Imports */[
exports.Generic = Generic; exports.Generic = Generic;
exports.Base = Base; exports.Base = Base;
exports.Derived = Derived; exports.Derived = Derived;
exports.expr = expr;
exports.main = main; exports.main = main;
}); });

View file

@ -31,6 +31,7 @@ class Derived {
bool _isWhitespace(String ch) => bool _isWhitespace(String ch) =>
ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'; ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
const expr = 'foo';
const _escapeMap = const { const _escapeMap = const {
'\n': r'\n', '\n': r'\n',
'\r': r'\r', '\r': r'\r',
@ -39,6 +40,7 @@ const _escapeMap = const {
'\t': r'\t', '\t': r'\t',
'\v': r'\v', '\v': r'\v',
'\x7F': r'\x7F', // delete '\x7F': r'\x7F', // delete
'\${${expr}}': ''
}; };