fix(es): Consume surrogate pairs (#4115)

This commit is contained in:
Alexander Akait 2022-03-28 15:18:06 +03:00 committed by GitHub
parent 13e7b4f92a
commit fcf67c4570
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
87 changed files with 1150 additions and 155 deletions

View File

@ -0,0 +1,6 @@
// @target: es5
// ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp)
// 2. Let cu1 be floor((cp 65536) / 1024) + 0xD800.
// Although we should just get back a single code point value of 0xD800,
// this is a useful edge-case test.
var x = "\u{D800}";

View File

@ -0,0 +1,6 @@
// @target: es5
// ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp)
// 2. Let cu1 be floor((cp 65536) / 1024) + 0xD800.
// Although we should just get back a single code point value of 0xD800,
// this is a useful edge-case test.
var x = "\u{D800}";

View File

@ -0,0 +1,6 @@
// @target: es6
// ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp)
// 2. Let cu1 be floor((cp 65536) / 1024) + 0xD800.
// Although we should just get back a single code point value of 0xD800,
// this is a useful edge-case test.
var x = "\u{D800}";

View File

@ -0,0 +1,6 @@
// @target: es6
// ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp)
// 2. Let cu1 be floor((cp 65536) / 1024) + 0xD800.
// Although we should just get back a single code point value of 0xD800,
// this is a useful edge-case test.
var x = "\u{D800}";

View File

@ -0,0 +1,6 @@
// @target: es5
// ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp)
// 2. Let cu2 be ((cp 65536) modulo 1024) + 0xDC00.
// Although we should just get back a single code point value of 0xDC00,
// this is a useful edge-case test.
var x = "\u{DC00}";

View File

@ -0,0 +1,6 @@
// @target: es5
// ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp)
// 2. Let cu2 be ((cp 65536) modulo 1024) + 0xDC00.
// Although we should just get back a single code point value of 0xDC00,
// this is a useful edge-case test.
var x = "\u{DC00}";

View File

@ -0,0 +1,6 @@
// @target: es6
// ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp)
// 2. Let cu2 be ((cp 65536) modulo 1024) + 0xDC00.
// Although we should just get back a single code point value of 0xDC00,
// this is a useful edge-case test.
var x = "\u{DC00}";

View File

@ -0,0 +1,6 @@
// @target: es6
// ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp)
// 2. Let cu2 be ((cp 65536) modulo 1024) + 0xDC00.
// Although we should just get back a single code point value of 0xDC00,
// this is a useful edge-case test.
var x = "\u{DC00}";

View File

@ -0,0 +1,6 @@
// @target: es5
// ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp)
// 2. Let cu1 be floor((cp 65536) / 1024) + 0xD800.
// Although we should just get back a single code point value of 0xD800,
// this is a useful edge-case test.
var x = `\u{D800}`;

View File

@ -0,0 +1,6 @@
// @target: es5
// ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp)
// 2. Let cu1 be floor((cp 65536) / 1024) + 0xD800.
// Although we should just get back a single code point value of 0xD800,
// this is a useful edge-case test.
var x = "\u{D800}";

View File

@ -0,0 +1,6 @@
// @target: es6
// ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp)
// 2. Let cu1 be floor((cp 65536) / 1024) + 0xD800.
// Although we should just get back a single code point value of 0xD800,
// this is a useful edge-case test.
var x = `\u{D800}`;

View File

@ -0,0 +1,6 @@
// @target: es6
// ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp)
// 2. Let cu1 be floor((cp 65536) / 1024) + 0xD800.
// Although we should just get back a single code point value of 0xD800,
// this is a useful edge-case test.
var x = "\u{D800}";

View File

@ -0,0 +1,6 @@
// @target: es5
// ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp)
// 2. Let cu2 be ((cp 65536) modulo 1024) + 0xDC00.
// Although we should just get back a single code point value of 0xDC00,
// this is a useful edge-case test.
var x = `\u{DC00}`;

View File

@ -0,0 +1,6 @@
// @target: es5
// ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp)
// 2. Let cu2 be ((cp 65536) modulo 1024) + 0xDC00.
// Although we should just get back a single code point value of 0xDC00,
// this is a useful edge-case test.
var x = "\u{DC00}";

View File

@ -0,0 +1,6 @@
// @target: es6
// ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp)
// 2. Let cu2 be ((cp 65536) modulo 1024) + 0xDC00.
// Although we should just get back a single code point value of 0xDC00,
// this is a useful edge-case test.
var x = `\u{DC00}`;

View File

@ -0,0 +1,6 @@
// @target: es6
// ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp)
// 2. Let cu2 be ((cp 65536) modulo 1024) + 0xDC00.
// Although we should just get back a single code point value of 0xDC00,
// this is a useful edge-case test.
var x = "\u{DC00}";

View File

@ -3324,23 +3324,38 @@ fn get_quoted_utf16(v: &str, target: EsVersion) -> String {
match next {
// TODO fix me - workaround for surrogate pairs
Some('\x00') => {
Some('u') => {
let mut inner_iter = iter.clone();
inner_iter.next();
let next = inner_iter.peek();
let mut is_curly = false;
let mut next = inner_iter.peek();
if next == Some(&'{') {
is_curly = true;
if let Some('u') = next {
inner_iter.next();
next = inner_iter.peek();
}
let mut is_valid = true;
if let Some(c @ 'D' | c @ 'd') = next {
let mut inner_buf = String::new();
inner_buf.push('\\');
inner_buf.push('u');
for _ in 0..4 {
if is_curly {
inner_buf.push('{');
}
inner_buf.push(*c);
inner_iter.next();
let mut is_valid = true;
for _ in 0..3 {
let c = inner_iter.next();
match c {
@ -3355,13 +3370,21 @@ fn get_quoted_utf16(v: &str, target: EsVersion) -> String {
}
}
if is_curly {
inner_buf.push('}');
}
if is_valid {
buf.push_str(&inner_buf);
for _ in 0..6 {
let end = if is_curly { 7 } else { 5 };
for _ in 0..end {
iter.next();
}
}
} else {
buf.push_str("\\\\");
}
}
_ => {

View File

@ -98,15 +98,29 @@ const string90 = new RegExp(" ").test(" ");
const string91 = new RegExp("\x1b").test("[" + "\x1b" + "]");
const string92 = new RegExp("\\x1b").test("\x1b");
const string93 = new RegExp("").test("");
const string94 = '퟿';
const string95 = 'ퟻ';
const string94 = "퟿";
const string95 = "ퟻ";
const string96 = sql`'#ERROR'`;
const string97 = '\u{a0}';
const string97 = "\u{a0}";
const string98 = "\ud83d\ude00";
const string99 = "\ud83d@\ude00";
const string100 = "\a";
const string101 = "";
// const string97 = '\u{D800}';
// const string97 = '\u{DBFF}';
// const string98 = '\u{DC00}';
// const string99 = '\u{DFFF}';
const string102 = "\uD800";
const string103 = "\u{D800}";
const string104 = "\uDBFF";
const string105 = "\u{DBFF}";
const string106 = "\uDC00";
const string107 = "\u{DC00}";
const string108 = "\uDFFF";
const string109 = "\u{DFFF}";
const string110 = "\uFFFF";
const string111 = "\u{FFFF}";
const string112 = "\ud800";
const string113 = "\uD800";
React.createElement("div", null, "this should not parse as unicode: \\u00a0");
const a = "\u0591-\u06ef\u06fa-\u08ff\u200f\ud802-\ud803\ud83a-\ud83b\ufb1d-\ufdff\ufe70-\ufefc";
const b = "A-Za-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02b8\u0300-\u0590\u0900-\u1fff\u200e\u2c00-\ud801\ud804-\ud839\ud83c-\udbff\uf900-\ufb1c\ufe00-\ufe6f\ufefd-\uffff";
var x = "\u{D800}";
var x2 = "\u{D800}";
var x3 = "\u{D800}\u{D800}";

View File

@ -98,11 +98,29 @@ const string90 = new RegExp(" ").test(" ");
const string91 = new RegExp("\x1b").test("[" + "\x1b" + "]");
const string92 = new RegExp("\\x1b").test("\x1b");
const string93 = new RegExp("").test("");
const string94 = '퟿';
const string95 = 'ퟻ';
const string94 = "퟿";
const string95 = "ퟻ";
const string96 = sql`'#ERROR'`;
const string97 = '\u{a0}';
const string97 = "\u{a0}";
const string98 = "\ud83d\ude00";
const string99 = "\ud83d@\ude00";
const string100 = "\a";
const string101 = "";
const string102 = "\uD800";
const string103 = "\u{D800}";
const string104 = "\uDBFF";
const string105 = "\u{DBFF}";
const string106 = "\uDC00";
const string107 = "\u{DC00}";
const string108 = "\uDFFF";
const string109 = "\u{DFFF}";
const string110 = "\uFFFF";
const string111 = "\u{FFFF}";
const string112 = "\ud800";
const string113 = "\uD800";
React.createElement("div", null, "this should not parse as unicode: \\u00a0");
const a = "\u0591-\u06ef\u06fa-\u08ff\u200f\ud802-\ud803\ud83a-\ud83b\ufb1d-\ufdff\ufe70-\ufefc";
const b = "A-Za-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02b8\u0300-\u0590\u0900-\u1fff\u200e\u2c00-\ud801\ud804-\ud839\ud83c-\udbff\uf900-\ufb1c\ufe00-\ufe6f\ufefd-\uffff";
var x = "\u{D800}";
var x2 = "\u{D800}";
var x3 = "\u{D800}\u{D800}";

View File

@ -1,3 +1,3 @@
const string1="test";const string2="test";const string3='te"st';const string4="te'st";const string5="test\ntest\ntest";const string6=`Yet another string primitive`;const string7="This is a very long string which needs to wrap across multiple lines because otherwise my code is unreadable.";const string8="\u4E2D\u6587 espa\xf1ol English \u0939\u093F\u0928\u094D\u0926\u0940 \u0627\u0644\u0639\u0631\u0628\u064A\u0629 portugu\xeas \u09AC\u09BE\u0982\u09B2\u09BE \u0440\u0443\u0441\u0441\u043A\u0438\u0439 \u65E5\u672C\u8A9E \u0A2A\u0A70\u0A1C\u0A3E\u0A2C\u0A40 \uD55C\uAD6D\uC5B4 \u0BA4\u0BAE\u0BBF\u0BB4\u0BCD";const string9=``;const string10=`xx\`x`;const string11=`${foo+2}`;const string12=` foo ${bar+`baz ${qux}`}`;const string13=String.raw`foo`;const string14=foo`bar`;const string15=`foo
bar
ↂωↂ`;const string16=`\``;const string17=`${4+4} equals 4 + 4`;const string18=`This is ${undefined}`;const string19=`This is ${NaN}`;const string20=`This is ${null}`;const string21=`This is ${Infinity}`;const string22="This is ${1/0}";const string23="This is ${1/0}";const string24="This is ${NaN}";const string25="This is ${null}";const string26=`This is ${1/0}`;const string27=`This is ${0/0}`;const string28="This is ${0/0}";const string29="This is ${0/0}";const string30=`${4**11}`;const string31=`${4**12}`;const string32=`${4**14}`;const string33="";const string34="\b";const string35="\f";const string36=" ";const string37="\v";const string38="\n";const string39="\\n";const string40="\\";const string41='\\"';const string42="'\"";const string43="\\\\";const string44="\0";const string45="\0!";const string46="\x001";const string47="\\0";const string48="\\0!";const string49="\x07";const string50="\x07!";const string51="\x071";const string52="\x07";const string53="\\7";const string54="\\7!";const string55="\\01";const string56="\x10";const string57="\\x10";const string58="\x1b";const string59="\\x1B";const string60="\uABCD";const string61="\uABCD";const string62="U000123AB";const string63="\u{123AB}";const string64="\ud808\udfab";const string65="\ud808";const string66="\ud808X";const string67="\udfab";const string68="\udfabX";const string69="\x80";const string70="\xff";const string71="\xf0\x9f\x8d\x95";const string72="\ud801\udc02\udc03\ud804";const string73="\u03C0";const ="\u{1F408}";const 貓abc="\u{1F408}";const abc貓="\u{1F408}";const string74="\u2028";const string75="\u2029";const string76="\uFEFF";const string77="\x10";const string78=" ";const string79=" ";const string80="2";const string81="\x16";const string82="\x06";const string83="\0a";const string84='"test"test"test';const string85="\"test'test'test";const string86='"test"test"test';const string87="'test'test'test";const string88="\u{1F604}";const string89=new RegExp("\r").test("\r");const string90=new RegExp(" ").test(" ");const string91=new RegExp("\x1b").test("["+"\x1b"+"]");const string92=new RegExp("\\x1b").test("\x1b");const string93=new RegExp("\x1b").test("\x1b");const string94="\uD7FF";const string95="\uD7FB";const string96=sql`'#ERROR'`;const string97="\xa0";const string98="\ud83d\ude00";const string99="\ud83d@\ude00";const string100="a";const string101="\u2028"
ↂωↂ`;const string16=`\``;const string17=`${4+4} equals 4 + 4`;const string18=`This is ${undefined}`;const string19=`This is ${NaN}`;const string20=`This is ${null}`;const string21=`This is ${Infinity}`;const string22="This is ${1/0}";const string23="This is ${1/0}";const string24="This is ${NaN}";const string25="This is ${null}";const string26=`This is ${1/0}`;const string27=`This is ${0/0}`;const string28="This is ${0/0}";const string29="This is ${0/0}";const string30=`${4**11}`;const string31=`${4**12}`;const string32=`${4**14}`;const string33="";const string34="\b";const string35="\f";const string36=" ";const string37="\v";const string38="\n";const string39="\\n";const string40="\\";const string41='\\"';const string42="'\"";const string43="\\\\";const string44="\0";const string45="\0!";const string46="\x001";const string47="\\0";const string48="\\0!";const string49="\x07";const string50="\x07!";const string51="\x071";const string52="\x07";const string53="\\7";const string54="\\7!";const string55="\\01";const string56="\x10";const string57="\\x10";const string58="\x1b";const string59="\\x1B";const string60="\uABCD";const string61="\uABCD";const string62="U000123AB";const string63="\u{123AB}";const string64="\uD808\uDFAB";const string65="\uD808";const string66="\uD808X";const string67="\uDFAB";const string68="\uDFABX";const string69="\x80";const string70="\xff";const string71="\xf0\x9f\x8d\x95";const string72="\uD801\uDC02\uDC03\uD804";const string73="\u03C0";const ="\u{1F408}";const 貓abc="\u{1F408}";const abc貓="\u{1F408}";const string74="\u2028";const string75="\u2029";const string76="\uFEFF";const string77="\x10";const string78=" ";const string79=" ";const string80="2";const string81="\x16";const string82="\x06";const string83="\0a";const string84='"test"test"test';const string85="\"test'test'test";const string86='"test"test"test';const string87="'test'test'test";const string88="\u{1F604}";const string89=new RegExp("\r").test("\r");const string90=new RegExp(" ").test(" ");const string91=new RegExp("\x1b").test("["+"\x1b"+"]");const string92=new RegExp("\\x1b").test("\x1b");const string93=new RegExp("\x1b").test("\x1b");const string94="\uD7FF";const string95="\uD7FB";const string96=sql`'#ERROR'`;const string97="\xa0";const string98="\ud83d\ude00";const string99="\ud83d@\ude00";const string100="a";const string101="\u2028";const string102="\uD800";const string103="\u{D800}";const string104="\uDBFF";const string105="\u{DBFF}";const string106="\uDC00";const string107="\u{DC00}";const string108="\uDFFF";const string109="\u{DFFF}";const string110="\uFFFF";const string111="\uFFFF";const string112="\ud800";const string113="\uD800";React.createElement("div",null,"this should not parse as unicode: \\u00a0");const a="\u0591-\u06EF\u06FA-\u08FF\u200F\ud802-\ud803\ud83a-\ud83b\uFB1D-\uFDFF\uFE70-\uFEFC";const b="A-Za-z\xc0-\xd6\xd8-\xf6\xf8-\u02B8\u0300-\u0590\u0900-\u1FFF\u200E\u2C00-\ud801\ud804-\ud839\ud83c-\udbff\uF900-\uFB1C\uFE00-\uFE6F\uFEFD-\uFFFF";var x="\u{D800}";var x2="\u{D800}";var x3="\u{D800}\u{D800}"

View File

@ -12,4 +12,4 @@ test\u2028
test\u2029
test\xa7
test
`;const template_literal103=`\0z`;const template_literal104=`\0`;const template_literal105=`x``x`;const template_literal106=`😀`;const template_literal107=`\u1111`;const template_literal108=`\u{1111}`;const template_literal109=`\x10`;const template_literal110=`\\x10`;const template_literal111=`\\\\`;const template_literal112=``;const template_literal113=``;const template_literal113=`\x7f`;console.log(`\0`);console.log(`\x001`);console.log(`\0a`)
`;const template_literal103=`\0z`;const template_literal104=`\0`;const template_literal105=`x``x`;const template_literal106=`😀`;const template_literal107=`\u1111`;const template_literal108=`\u{1111}`;const template_literal109=`\x10`;const template_literal110=`\\x10`;const template_literal111=`\\\\`;const template_literal112=``;const template_literal113=``;const template_literal114=`\x7f`;console.log(`\0`);console.log(`\x001`);console.log(`\0a`);const template_literal115=`\uD800`;const template_literal116=`\u{D800}`;const template_literal117=`\uDBFF`;const template_literal118=`\u{DBFF}`;const template_literal119=`\uDC00`;const template_literal120=`\u{DC00}`;const template_literal121=`\uDFFF`;const template_literal122=`\u{DFFF}`;const template_literal123=`\uFFFF`;const template_literal124=`\u{FFFF}`

View File

@ -77,12 +77,9 @@ pub enum SyntaxError {
c: char,
},
InvalidStrEscape,
InvalidUnicodeCodePoint,
InvalidUnicodeEscape,
InvalidCodePoint,
ExpectedHexChars {
/// Number of expected characters.
count: u8,
BadCharacterEscapeSequence {
expected: &'static str,
},
NumLitTerminatedWithExp,
LegacyCommentInModule,
@ -294,11 +291,9 @@ impl SyntaxError {
SyntaxError::IdentAfterNum => "Identifier cannot follow number".into(),
SyntaxError::UnexpectedChar { c } => format!("Unexpected character {:?}", c).into(),
SyntaxError::InvalidStrEscape => "Invalid string escape".into(),
SyntaxError::InvalidUnicodeCodePoint => "Undefined Unicode code-point".into(),
SyntaxError::InvalidUnicodeEscape => "Invalid unicode escape".into(),
SyntaxError::InvalidCodePoint => "Invalid unicode code point".into(),
SyntaxError::ExpectedHexChars { count } => {
format!("Expected {} hex characters", count).into()
SyntaxError::BadCharacterEscapeSequence { expected } => {
format!("Bad character escape sequence, expected {}", expected).into()
}
SyntaxError::LegacyCommentInModule => {
"Legacy comments cannot be used in module code".into()

View File

@ -480,7 +480,11 @@ impl<'a, I: Input> Lexer<'a, I> {
/// Read an escaped character for string literal.
///
/// In template literal, we should preserve raw string.
fn read_escaped_char(&mut self, raw: &mut Raw, in_template: bool) -> LexResult<Option<Char>> {
fn read_escaped_char(
&mut self,
raw: &mut Raw,
in_template: bool,
) -> LexResult<Option<Vec<Char>>> {
debug_assert_eq!(self.cur(), Some('\\'));
let start = self.cur_pos();
@ -509,11 +513,13 @@ impl<'a, I: Input> Lexer<'a, I> {
'f' => push_c_and_ret!('\u{000c}'),
'\r' => {
raw.push_str("\r");
self.bump(); // remove '\r'
if self.eat(b'\n') {
raw.push_str("\n");
}
return Ok(None);
}
'\n' | '\u{2028}' | '\u{2029}' => {
@ -524,20 +530,33 @@ impl<'a, I: Input> Lexer<'a, I> {
_ => unreachable!(),
}
self.bump();
return Ok(None);
}
// read hexadecimal escape sequences
'x' => {
raw.push_str("x");
self.bump(); // 'x'
return self.read_hex_char(start, 2, raw).map(Some);
match self.read_int_u32::<16>(2, raw)? {
Some(val) => return Ok(Some(vec![Char::from(val)])),
None => self.error(
start,
SyntaxError::BadCharacterEscapeSequence {
expected: "2 hex characters",
},
)?,
}
}
// read unicode escape sequences
'u' => {
return self.read_unicode_escape(start, raw).map(Some);
}
'u' => match self.read_unicode_escape(raw) {
Ok(chars) => return Ok(Some(chars)),
Err(err) => self.error(start, err.error.1)?,
},
// octal escape sequences
'0'..='7' => {
raw.push(c);
@ -548,7 +567,7 @@ impl<'a, I: Input> Lexer<'a, I> {
match self.cur() {
Some(next) if next.is_digit(8) => c,
// \0 is not an octal literal nor decimal literal.
_ => return Ok(Some('\u{0000}'.into())),
_ => return Ok(Some(vec!['\u{0000}'.into()])),
}
} else {
c
@ -575,31 +594,34 @@ impl<'a, I: Input> Lexer<'a, I> {
.and_then(|value| value.checked_add(v as u8));
match new_val {
Some(val) => val,
None => return Ok(Some(value as char).map(From::from)),
None => return Ok(Some(vec![Char::from(value as char)])),
}
} else {
value * 8 + v as u8
};
self.bump();
raw.push(cur.unwrap());
}
_ => return Ok(Some(value as u32).map(From::from)),
_ => return Ok(Some(vec![Char::from(value as u32)])),
}
}};
}
one!(false);
one!(true);
return Ok(Some(value as char).map(From::from));
return Ok(Some(vec![Char::from(value as char)]));
}
_ => {
raw.push(c);
c
}
};
self.input.bump();
Ok(Some(c.into()))
Ok(Some(vec![c.into()]))
}
}
@ -774,23 +796,31 @@ impl<'a, I: Input> Lexer<'a, I> {
// unicode escape
'\\' => {
l.bump();
if !l.is(b'u') {
l.error_span(pos_span(start), SyntaxError::ExpectedUnicodeEscape)?
}
has_escape = true;
let c = l.read_unicode_escape(start, &mut Raw(None))?;
let valid = if first {
c.is_ident_start()
} else {
c.is_ident_part()
};
if !valid {
l.emit_error(start, SyntaxError::InvalidIdentChar);
let chars = l.read_unicode_escape(&mut Raw(None))?;
if let Some(c) = chars.get(0) {
let valid = if first {
c.is_ident_start()
} else {
c.is_ident_part()
};
if !valid {
l.emit_error(start, SyntaxError::InvalidIdentChar);
}
}
buf.extend(c);
}
for c in chars {
buf.extend(c);
}
}
_ => {
break;
}
@ -803,53 +833,107 @@ impl<'a, I: Input> Lexer<'a, I> {
})
}
fn read_unicode_escape(&mut self, start: BytePos, raw: &mut Raw) -> LexResult<Char> {
fn read_unicode_escape(&mut self, raw: &mut Raw) -> LexResult<Vec<Char>> {
debug_assert_eq!(self.cur(), Some('u'));
self.bump();
let mut chars = vec![];
let mut is_curly = false;
self.bump(); // 'u'
raw.push_str("u");
if self.eat(b'{') {
is_curly = true;
raw.push('{');
// let cp_start = self.cur_pos();
let c = self.read_code_point(raw)?;
}
if !self.eat(b'}') {
self.error(start, SyntaxError::InvalidUnicodeEscape)?
let state = self.input.cur_pos();
let c = match self.read_int_u32::<16>(if is_curly { 0 } else { 4 }, raw) {
Ok(Some(val)) => {
if 0x0010_ffff >= val {
char::from_u32(val)
} else {
let start = self.cur_pos();
self.error(
start,
SyntaxError::BadCharacterEscapeSequence {
expected: if is_curly {
"1-6 hex characters in the range 0 to 10FFFF."
} else {
"4 hex characters"
},
},
)?
}
}
_ => {
let start = self.cur_pos();
self.error(
start,
SyntaxError::BadCharacterEscapeSequence {
expected: if is_curly {
"1-6 hex characters"
} else {
"4 hex characters"
},
},
)?
}
};
match c {
Some(c) => {
chars.push(c.into());
}
_ => {
self.input.reset_to(state);
chars.push(Char::from('\\'));
chars.push(Char::from('u'));
if is_curly {
chars.push(Char::from('{'));
for _ in 0..6 {
if let Some(c) = self.input.cur() {
if c == '}' {
break;
}
self.bump();
chars.push(Char::from(c));
} else {
break;
}
}
chars.push(Char::from('}'));
} else {
for _ in 0..4 {
if let Some(c) = self.input.cur() {
self.bump();
chars.push(Char::from(c));
}
}
}
}
}
if is_curly {
if !self.eat(b'}') {
self.error(state, SyntaxError::InvalidUnicodeEscape)?
}
raw.push('}');
Ok(c)
} else {
self.read_hex_char(start, 4, raw)
}
}
///
///
/// This method returns [Char] as non-utf8 character is valid in JavaScript.
/// See https://github.com/swc-project/swc/issues/261
fn read_hex_char(&mut self, start: BytePos, count: u8, raw: &mut Raw) -> LexResult<Char> {
debug_assert!(count == 2 || count == 4);
// let pos = self.cur_pos();
match self.read_int_u32::<16>(count, raw)? {
Some(val) => Ok(val.into()),
None => self.error(start, SyntaxError::ExpectedHexChars { count })?,
}
}
/// Read `CodePoint`.
fn read_code_point(&mut self, raw: &mut Raw) -> LexResult<Char> {
let start = self.cur_pos();
let val = self.read_int_u32::<16>(0, raw)?;
match val {
Some(val) if 0x0010_ffff >= val => match char::from_u32(val) {
Some(c) => Ok(c.into()),
None => self.error(start, SyntaxError::InvalidCodePoint)?,
},
_ => self.error(start, SyntaxError::InvalidCodePoint)?,
}
Ok(chars)
}
/// See https://tc39.github.io/ecma262/#sec-literals-string-literals
@ -862,6 +946,7 @@ impl<'a, I: Input> Lexer<'a, I> {
raw.push(quote);
self.bump(); // '"'
self.with_buf(|l, out| {
while let Some(c) = {
// Optimization
@ -890,8 +975,10 @@ impl<'a, I: Input> Lexer<'a, I> {
let mut wrapped = Raw(Some(String::new()));
if let Some(s) = l.read_escaped_char(&mut wrapped, false)? {
out.extend(s);
if let Some(chars) = l.read_escaped_char(&mut wrapped, false)? {
for c in chars {
out.extend(c);
}
}
raw.push_str(&wrapped.0.unwrap());
@ -1019,9 +1106,11 @@ impl<'a, I: Input> Lexer<'a, I> {
let mut wrapped = Raw(Some(raw));
match self.read_escaped_char(&mut wrapped, true) {
Ok(Some(s)) => {
Ok(Some(chars)) => {
if let Ok(ref mut cooked) = cooked {
cooked.extend(s);
for c in chars {
cooked.extend(c);
}
}
}
Ok(None) => {}

View File

@ -268,9 +268,11 @@ fn tpl_invalid_unicode_escape() {
Span {
lo: BytePos(1),
hi: BytePos(3),
ctxt: SyntaxContext::empty()
ctxt: SyntaxContext::empty(),
},
SyntaxError::ExpectedHexChars { count: 4 }
SyntaxError::BadCharacterEscapeSequence {
expected: "4 hex characters"
}
))
}),
raw: "\\unicode".into(),
@ -286,11 +288,13 @@ fn tpl_invalid_unicode_escape() {
cooked: Err(Error {
error: Box::new((
Span {
lo: BytePos(4),
lo: BytePos(1),
hi: BytePos(4),
ctxt: SyntaxContext::empty()
ctxt: SyntaxContext::empty(),
},
SyntaxError::InvalidCodePoint
SyntaxError::BadCharacterEscapeSequence {
expected: "1-6 hex characters"
}
))
}),
raw: "\\u{".into(),
@ -308,9 +312,11 @@ fn tpl_invalid_unicode_escape() {
Span {
lo: BytePos(1),
hi: BytePos(3),
ctxt: SyntaxContext::empty()
ctxt: SyntaxContext::empty(),
},
SyntaxError::ExpectedHexChars { count: 2 }
SyntaxError::BadCharacterEscapeSequence {
expected: "2 hex characters"
}
))
}),
raw: "\\xhex".into(),

View File

@ -0,0 +1 @@
<div>this should not parse as unicode: \u00a0</div>;

View File

@ -0,0 +1,78 @@
{
"type": "Module",
"span": {
"start": 0,
"end": 52,
"ctxt": 0
},
"body": [
{
"type": "ExpressionStatement",
"span": {
"start": 0,
"end": 52,
"ctxt": 0
},
"expression": {
"type": "JSXElement",
"span": {
"start": 0,
"end": 51,
"ctxt": 0
},
"opening": {
"type": "JSXOpeningElement",
"name": {
"type": "Identifier",
"span": {
"start": 1,
"end": 4,
"ctxt": 0
},
"value": "div",
"optional": false
},
"span": {
"start": 0,
"end": 5,
"ctxt": 0
},
"attributes": [],
"selfClosing": false,
"typeArguments": null
},
"children": [
{
"type": "JSXText",
"span": {
"start": 5,
"end": 45,
"ctxt": 0
},
"value": "this should not parse as unicode: \\u00a0",
"raw": "this should not parse as unicode: \\u00a0"
}
],
"closing": {
"type": "JSXClosingElement",
"span": {
"start": 45,
"end": 51,
"ctxt": 0
},
"name": {
"type": "Identifier",
"span": {
"start": 47,
"end": 50,
"ctxt": 0
},
"value": "div",
"optional": false
}
}
}
}
],
"interpreter": null
}

View File

@ -0,0 +1,3 @@
const x = <div onclick={{ s: "\uD800" }}></div>;
const x = <div onclick={{ s: "\u{D800}" }}></div>;

View File

@ -0,0 +1,291 @@
{
"type": "Module",
"span": {
"start": 0,
"end": 99,
"ctxt": 0
},
"body": [
{
"type": "VariableDeclaration",
"span": {
"start": 0,
"end": 48,
"ctxt": 0
},
"kind": "const",
"declare": false,
"declarations": [
{
"type": "VariableDeclarator",
"span": {
"start": 6,
"end": 47,
"ctxt": 0
},
"id": {
"type": "Identifier",
"span": {
"start": 6,
"end": 7,
"ctxt": 0
},
"value": "x",
"optional": false,
"typeAnnotation": null
},
"init": {
"type": "JSXElement",
"span": {
"start": 10,
"end": 47,
"ctxt": 0
},
"opening": {
"type": "JSXOpeningElement",
"name": {
"type": "Identifier",
"span": {
"start": 11,
"end": 14,
"ctxt": 0
},
"value": "div",
"optional": false
},
"span": {
"start": 10,
"end": 41,
"ctxt": 0
},
"attributes": [
{
"type": "JSXAttribute",
"span": {
"start": 15,
"end": 40,
"ctxt": 0
},
"name": {
"type": "Identifier",
"span": {
"start": 15,
"end": 22,
"ctxt": 0
},
"value": "onclick",
"optional": false
},
"value": {
"type": "JSXExpressionContainer",
"span": {
"start": 23,
"end": 40,
"ctxt": 0
},
"expression": {
"type": "ObjectExpression",
"span": {
"start": 24,
"end": 39,
"ctxt": 0
},
"properties": [
{
"type": "KeyValueProperty",
"key": {
"type": "Identifier",
"span": {
"start": 26,
"end": 27,
"ctxt": 0
},
"value": "s",
"optional": false
},
"value": {
"type": "StringLiteral",
"span": {
"start": 29,
"end": 37,
"ctxt": 0
},
"value": "\\uD800",
"raw": "\"\\uD800\""
}
}
]
}
}
}
],
"selfClosing": false,
"typeArguments": null
},
"children": [],
"closing": {
"type": "JSXClosingElement",
"span": {
"start": 41,
"end": 47,
"ctxt": 0
},
"name": {
"type": "Identifier",
"span": {
"start": 43,
"end": 46,
"ctxt": 0
},
"value": "div",
"optional": false
}
}
},
"definite": false
}
]
},
{
"type": "VariableDeclaration",
"span": {
"start": 49,
"end": 99,
"ctxt": 0
},
"kind": "const",
"declare": false,
"declarations": [
{
"type": "VariableDeclarator",
"span": {
"start": 55,
"end": 98,
"ctxt": 0
},
"id": {
"type": "Identifier",
"span": {
"start": 55,
"end": 56,
"ctxt": 0
},
"value": "x",
"optional": false,
"typeAnnotation": null
},
"init": {
"type": "JSXElement",
"span": {
"start": 59,
"end": 98,
"ctxt": 0
},
"opening": {
"type": "JSXOpeningElement",
"name": {
"type": "Identifier",
"span": {
"start": 60,
"end": 63,
"ctxt": 0
},
"value": "div",
"optional": false
},
"span": {
"start": 59,
"end": 92,
"ctxt": 0
},
"attributes": [
{
"type": "JSXAttribute",
"span": {
"start": 64,
"end": 91,
"ctxt": 0
},
"name": {
"type": "Identifier",
"span": {
"start": 64,
"end": 71,
"ctxt": 0
},
"value": "onclick",
"optional": false
},
"value": {
"type": "JSXExpressionContainer",
"span": {
"start": 72,
"end": 91,
"ctxt": 0
},
"expression": {
"type": "ObjectExpression",
"span": {
"start": 73,
"end": 90,
"ctxt": 0
},
"properties": [
{
"type": "KeyValueProperty",
"key": {
"type": "Identifier",
"span": {
"start": 75,
"end": 76,
"ctxt": 0
},
"value": "s",
"optional": false
},
"value": {
"type": "StringLiteral",
"span": {
"start": 78,
"end": 88,
"ctxt": 0
},
"value": "\\u{D800}",
"raw": "\"\\u{D800}\""
}
}
]
}
}
}
],
"selfClosing": false,
"typeArguments": null
},
"children": [],
"closing": {
"type": "JSXClosingElement",
"span": {
"start": 92,
"end": 98,
"ctxt": 0
},
"name": {
"type": "Identifier",
"span": {
"start": 94,
"end": 97,
"ctxt": 0
},
"value": "div",
"optional": false
}
}
},
"definite": false
}
]
}
],
"interpreter": null
}

View File

@ -0,0 +1,3 @@
const x = <div onclick={{ t: `\uD800` }}></div>;
const x = <div onclick={{ t: `\u{D800}` }}></div>;

View File

@ -0,0 +1,315 @@
{
"type": "Module",
"span": {
"start": 0,
"end": 99,
"ctxt": 0
},
"body": [
{
"type": "VariableDeclaration",
"span": {
"start": 0,
"end": 48,
"ctxt": 0
},
"kind": "const",
"declare": false,
"declarations": [
{
"type": "VariableDeclarator",
"span": {
"start": 6,
"end": 47,
"ctxt": 0
},
"id": {
"type": "Identifier",
"span": {
"start": 6,
"end": 7,
"ctxt": 0
},
"value": "x",
"optional": false,
"typeAnnotation": null
},
"init": {
"type": "JSXElement",
"span": {
"start": 10,
"end": 47,
"ctxt": 0
},
"opening": {
"type": "JSXOpeningElement",
"name": {
"type": "Identifier",
"span": {
"start": 11,
"end": 14,
"ctxt": 0
},
"value": "div",
"optional": false
},
"span": {
"start": 10,
"end": 41,
"ctxt": 0
},
"attributes": [
{
"type": "JSXAttribute",
"span": {
"start": 15,
"end": 40,
"ctxt": 0
},
"name": {
"type": "Identifier",
"span": {
"start": 15,
"end": 22,
"ctxt": 0
},
"value": "onclick",
"optional": false
},
"value": {
"type": "JSXExpressionContainer",
"span": {
"start": 23,
"end": 40,
"ctxt": 0
},
"expression": {
"type": "ObjectExpression",
"span": {
"start": 24,
"end": 39,
"ctxt": 0
},
"properties": [
{
"type": "KeyValueProperty",
"key": {
"type": "Identifier",
"span": {
"start": 26,
"end": 27,
"ctxt": 0
},
"value": "t",
"optional": false
},
"value": {
"type": "TemplateLiteral",
"span": {
"start": 29,
"end": 37,
"ctxt": 0
},
"expressions": [],
"quasis": [
{
"type": "TemplateElement",
"span": {
"start": 30,
"end": 36,
"ctxt": 0
},
"tail": true,
"cooked": "\\uD800",
"raw": "\\uD800"
}
]
}
}
]
}
}
}
],
"selfClosing": false,
"typeArguments": null
},
"children": [],
"closing": {
"type": "JSXClosingElement",
"span": {
"start": 41,
"end": 47,
"ctxt": 0
},
"name": {
"type": "Identifier",
"span": {
"start": 43,
"end": 46,
"ctxt": 0
},
"value": "div",
"optional": false
}
}
},
"definite": false
}
]
},
{
"type": "VariableDeclaration",
"span": {
"start": 49,
"end": 99,
"ctxt": 0
},
"kind": "const",
"declare": false,
"declarations": [
{
"type": "VariableDeclarator",
"span": {
"start": 55,
"end": 98,
"ctxt": 0
},
"id": {
"type": "Identifier",
"span": {
"start": 55,
"end": 56,
"ctxt": 0
},
"value": "x",
"optional": false,
"typeAnnotation": null
},
"init": {
"type": "JSXElement",
"span": {
"start": 59,
"end": 98,
"ctxt": 0
},
"opening": {
"type": "JSXOpeningElement",
"name": {
"type": "Identifier",
"span": {
"start": 60,
"end": 63,
"ctxt": 0
},
"value": "div",
"optional": false
},
"span": {
"start": 59,
"end": 92,
"ctxt": 0
},
"attributes": [
{
"type": "JSXAttribute",
"span": {
"start": 64,
"end": 91,
"ctxt": 0
},
"name": {
"type": "Identifier",
"span": {
"start": 64,
"end": 71,
"ctxt": 0
},
"value": "onclick",
"optional": false
},
"value": {
"type": "JSXExpressionContainer",
"span": {
"start": 72,
"end": 91,
"ctxt": 0
},
"expression": {
"type": "ObjectExpression",
"span": {
"start": 73,
"end": 90,
"ctxt": 0
},
"properties": [
{
"type": "KeyValueProperty",
"key": {
"type": "Identifier",
"span": {
"start": 75,
"end": 76,
"ctxt": 0
},
"value": "t",
"optional": false
},
"value": {
"type": "TemplateLiteral",
"span": {
"start": 78,
"end": 88,
"ctxt": 0
},
"expressions": [],
"quasis": [
{
"type": "TemplateElement",
"span": {
"start": 79,
"end": 87,
"ctxt": 0
},
"tail": true,
"cooked": "\\u{D800}",
"raw": "\\u{D800}"
}
]
}
}
]
}
}
}
],
"selfClosing": false,
"typeArguments": null
},
"children": [],
"closing": {
"type": "JSXClosingElement",
"span": {
"start": 92,
"end": 98,
"ctxt": 0
},
"name": {
"type": "Identifier",
"span": {
"start": 94,
"end": 97,
"ctxt": 0
},
"value": "div",
"optional": false
}
}
},
"definite": false
}
]
}
],
"interpreter": null
}

View File

@ -0,0 +1 @@
const string = "\xZZ";

View File

@ -0,0 +1,6 @@
x Bad character escape sequence, expected 2 hex characters
,-[$DIR/tests/pat/errors/bad_character_escape_sequence/input.js:1:1]
1 | const string = "\xZZ";
: ^^
`----

View File

@ -0,0 +1 @@
const string = "\x";

View File

@ -0,0 +1,6 @@
x Bad character escape sequence, expected 2 hex characters
,-[$DIR/tests/pat/errors/bad_character_escape_sequence_1/input.js:1:1]
1 | const string = "\x";
: ^^
`----

View File

@ -0,0 +1 @@
const string = "\uZZZZ";

View File

@ -0,0 +1,6 @@
x Bad character escape sequence, expected 4 hex characters
,-[$DIR/tests/pat/errors/bad_character_escape_sequence_2/input.js:1:1]
1 | const string = "\uZZZZ";
: ^^
`----

View File

@ -0,0 +1 @@
const string = "\u{FFFFFF}";

View File

@ -0,0 +1,6 @@
x Bad character escape sequence, expected 1-6 hex characters in the range 0 to 10FFFF.
,-[$DIR/tests/pat/errors/bad_character_escape_sequence_3/input.js:1:1]
1 | const string = "\u{FFFFFF}";
: ^^^^^^^^^
`----

View File

@ -0,0 +1 @@
const string = "\xFZ";

View File

@ -0,0 +1,6 @@
x Bad character escape sequence, expected 2 hex characters
,-[$DIR/tests/pat/errors/bad_character_escape_sequence_4/input.js:1:1]
1 | const string = "\xFZ";
: ^^^
`----

View File

@ -0,0 +1 @@
const string = "\u{ZZZZ}";

View File

@ -0,0 +1,6 @@
x Bad character escape sequence, expected 1-6 hex characters
,-[$DIR/tests/pat/errors/bad_character_escape_sequence_5/input.js:1:1]
1 | const string = "\u{ZZZZ}";
: ^^^
`----

View File

@ -0,0 +1 @@
const string = "\u{FFFFFF}";

View File

@ -0,0 +1,6 @@
x Bad character escape sequence, expected 1-6 hex characters in the range 0 to 10FFFF.
,-[$DIR/tests/pat/errors/bad_character_escape_sequence_6/input.js:1:1]
1 | const string = "\u{FFFFFF}";
: ^^^^^^^^^
`----

View File

@ -0,0 +1 @@
const string = "\

View File

@ -0,0 +1,6 @@
x Invalid string escape
,-[$DIR/tests/pat/errors/unterminated_string_constant/input.js:1:1]
1 | const string = "\
: ^
`----

View File

@ -0,0 +1 @@
const string = "\"

View File

@ -0,0 +1,6 @@
x Unterminated string constant
,-[$DIR/tests/pat/errors/unterminated_string_constant_1/input.js:1:1]
1 | const string = "\"
: ^^^
`----

View File

@ -1,6 +1,6 @@
x Expected 4 hex characters
x Bad character escape sequence, expected 4 hex characters
,-[$DIR/tests/test262-parser/fail/0c7d4912f3869297.js:1:1]
1 | \u12
: ^^^^
: ^
`----

View File

@ -1,5 +1,5 @@
x Expected 2 hex characters
x Bad character escape sequence, expected 2 hex characters
,-[$DIR/tests/test262-parser/fail/0f2794d0bcec2dd7.js:1:1]
1 | '\x1
: ^^^

View File

@ -1,6 +1,6 @@
x Invalid unicode code point
x Bad character escape sequence, expected 1-6 hex characters in the range 0 to 10FFFF.
,-[$DIR/tests/test262-parser/fail/14eaa7e71c682461.js:1:1]
1 | ("\u{FFFFFFF}")
: ^^^^^^^
: ^^^^^^^^^^
`----

View File

@ -1,6 +1,6 @@
x Expected 4 hex characters
x Bad character escape sequence, expected 4 hex characters
,-[$DIR/tests/test262-parser/fail/26031afc9eaef976.js:1:1]
1 | a\u11z
: ^^^^
: ^
`----

View File

@ -1,6 +1,6 @@
x Invalid unicode code point
x Bad character escape sequence, expected 1-6 hex characters
,-[$DIR/tests/test262-parser/fail/2687d6d9043bd5cb.js:1:1]
1 | "\u{}"
: ^
: ^^^
`----

View File

@ -1,6 +1,6 @@
x Expected 4 hex characters
x Bad character escape sequence, expected 4 hex characters
,-[$DIR/tests/test262-parser/fail/28151222a45ac800.js:1:1]
1 | \ua
: ^^^
: ^
`----

View File

@ -1,5 +1,5 @@
x Expected 2 hex characters
x Bad character escape sequence, expected 2 hex characters
,-[$DIR/tests/test262-parser/fail/3b473034dde14c98.js:1:1]
1 | "\xx";
: ^^

View File

@ -1,5 +1,5 @@
x Expected 4 hex characters
x Bad character escape sequence, expected 4 hex characters
,-[$DIR/tests/test262-parser/fail/55b9f51ad21c7f25.js:1:1]
1 | "\u";
: ^^

View File

@ -1,5 +1,5 @@
x Expected 4 hex characters
x Bad character escape sequence, expected 4 hex characters
,-[$DIR/tests/test262-parser/fail/575367951ac8635d.js:1:1]
1 | ('\u')
: ^^

View File

@ -1,5 +1,5 @@
x Expected 4 hex characters
x Bad character escape sequence, expected 4 hex characters
,-[$DIR/tests/test262-parser/fail/5a627d08e9b33ad1.js:1:1]
1 | "\u00";
: ^^^^

View File

@ -1,6 +1,6 @@
x Expected 4 hex characters
x Bad character escape sequence, expected 4 hex characters
,-[$DIR/tests/test262-parser/fail/610fe4450d41c81e.js:1:1]
1 | \u
: ^^
: ^
`----

View File

@ -1,6 +1,6 @@
x Expected 4 hex characters
x Bad character escape sequence, expected 4 hex characters
,-[$DIR/tests/test262-parser/fail/61b72f954b679c22.js:1:1]
1 | \u1
: ^^^
: ^
`----

View File

@ -1,5 +1,5 @@
x Expected 2 hex characters
x Bad character escape sequence, expected 2 hex characters
,-[$DIR/tests/test262-parser/fail/66dd7a60a05be9f8.js:1:1]
1 | '\x1
: ^^^

View File

@ -1,6 +1,6 @@
x Expected 4 hex characters
x Bad character escape sequence, expected 4 hex characters
,-[$DIR/tests/test262-parser/fail/6a96389a0cce57e9.js:1:1]
1 | var x = /[a-z]/\ux
: ^^
: ^
`----

View File

@ -1,6 +1,6 @@
x Expected 4 hex characters
x Bad character escape sequence, expected 4 hex characters
,-[$DIR/tests/test262-parser/fail/6c3a76d368c398cc.js:1:1]
1 | a\u1z
: ^^^
: ^
`----

View File

@ -1,6 +1,6 @@
x Expected 4 hex characters
x Bad character escape sequence, expected 4 hex characters
,-[$DIR/tests/test262-parser/fail/6cb3fc8ff354bd89.js:1:1]
1 | a\uz
: ^^
: ^
`----

View File

@ -1,6 +1,6 @@
x Expected 4 hex characters
x Bad character escape sequence, expected 4 hex characters
,-[$DIR/tests/test262-parser/fail/73b0a0c9a26e1950.js:1:1]
1 | a\u113
: ^^^^^
: ^
`----

View File

@ -1,5 +1,5 @@
x Expected 4 hex characters
x Bad character escape sequence, expected 4 hex characters
,-[$DIR/tests/test262-parser/fail/73c84046ac613107.js:1:1]
1 | "\ux";
: ^^

View File

@ -1,5 +1,5 @@
x Expected 4 hex characters
x Bad character escape sequence, expected 4 hex characters
,-[$DIR/tests/test262-parser/fail/783f01472f94a412.js:1:1]
1 | "\u000";
: ^^^^^

View File

@ -1,6 +1,6 @@
x Expected 4 hex characters
x Bad character escape sequence, expected 4 hex characters
,-[$DIR/tests/test262-parser/fail/92dfbd6c58d2c61f.js:1:1]
1 | a\u
: ^^
: ^
`----

View File

@ -1,5 +1,5 @@
x Expected 2 hex characters
x Bad character escape sequence, expected 2 hex characters
,-[$DIR/tests/test262-parser/fail/92ed8c5d2d151ff9.js:1:1]
1 | '\x
: ^^

View File

@ -1,6 +1,6 @@
x Expected 4 hex characters
x Bad character escape sequence, expected 4 hex characters
,-[$DIR/tests/test262-parser/fail/94535dc25ef762ee.js:1:1]
1 | var x = /[a-z]/\\ux
: ^^
: ^
`----

View File

@ -1,6 +1,6 @@
x Invalid unicode code point
x Bad character escape sequence, expected 1-6 hex characters in the range 0 to 10FFFF.
,-[$DIR/tests/test262-parser/fail/aca911e336954a5b.js:1:1]
1 | ("\u{110000}")
: ^^^^^^
: ^^^^^^^^^
`----

View File

@ -1,5 +1,5 @@
x Expected 2 hex characters
x Bad character escape sequence, expected 2 hex characters
,-[$DIR/tests/test262-parser/fail/b3fc8ced7ce28c35.js:1:1]
1 | ('\x')
: ^^

View File

@ -1,5 +1,5 @@
x Expected 2 hex characters
x Bad character escape sequence, expected 2 hex characters
,-[$DIR/tests/test262-parser/fail/b61406dafcaab4b7.js:1:1]
1 | ('\x0')
: ^^^

View File

@ -1,6 +1,6 @@
x Expected 4 hex characters
x Bad character escape sequence, expected 4 hex characters
,-[$DIR/tests/test262-parser/fail/bdb40451ba403567.js:1:1]
1 | a\u1
: ^^^
: ^
`----

View File

@ -1,8 +1,8 @@
x Expected 4 hex characters
x Bad character escape sequence, expected 4 hex characters
,-[$DIR/tests/test262-parser/fail/c3afed3cb0fb92ab.js:1:1]
1 | \uD800\u
: ^^
: ^
`----
x Invalid character in identifier

View File

@ -1,5 +1,5 @@
x Expected 2 hex characters
x Bad character escape sequence, expected 2 hex characters
,-[$DIR/tests/test262-parser/fail/c79647e7baf81f8f.js:1:1]
1 | "\x0";
: ^^^

View File

@ -1,5 +1,5 @@
x Expected 4 hex characters
x Bad character escape sequence, expected 4 hex characters
,-[$DIR/tests/test262-parser/fail/c86a72939cce6f53.js:1:1]
1 | "\u
: ^^

View File

@ -1,6 +1,6 @@
x Expected 4 hex characters
x Bad character escape sequence, expected 4 hex characters
,-[$DIR/tests/test262-parser/fail/f03be7c48423eaed.js:1:1]
1 | \u113
: ^^^^^
: ^
`----

View File

@ -1,6 +1,6 @@
x Expected 4 hex characters
x Bad character escape sequence, expected 4 hex characters
,-[$DIR/tests/test262-parser/fail/f6dc8a19882274b5.js:1:1]
1 | a\u12
: ^^^^
: ^
`----

View File

@ -1,6 +1,6 @@
x Invalid unicode code point
x Bad character escape sequence, expected 1-6 hex characters in the range 0 to 10FFFF.
,-[$DIR/tests/test262-parser/fail/f8b20220d8c85d71.js:1:1]
1 | "\u{110000}"
: ^^^^^^
: ^^^^^^^^^
`----

View File

@ -1,5 +1,5 @@
x Expected 4 hex characters
x Bad character escape sequence, expected 4 hex characters
,-[$DIR/tests/test262-parser/fail/fc8bfabd18ec26dc.js:1:1]
1 | "\u0";
: ^^^

View File

@ -1,6 +1,6 @@
x Expected 4 hex characters
x Bad character escape sequence, expected 4 hex characters
,-[$DIR/tests/test262-parser/fail/fefae4f97aa879de.js:1:1]
1 | a\u111z
: ^^^^^
: ^
`----

View File

@ -1,5 +1,5 @@
x Expected 2 hex characters
x Bad character escape sequence, expected 2 hex characters
,-[$DIR/tests/test262-parser/fail/ffcb5a1d89aed63f.js:1:1]
1 | "\x";
: ^^

View File

@ -1438,21 +1438,21 @@ where
}
fn nth_char(s: &str, mut idx: usize) -> Cow<str> {
if !s.contains("\\\0") {
if !s.contains("\\ud") && !s.contains("\\uD") {
return Cow::Owned(s.chars().nth(idx).unwrap().to_string());
}
let mut iter = s.chars().peekable();
while let Some(c) = iter.next() {
if c == '\\' && iter.peek().copied() == Some('\0') {
if c == '\\' && iter.peek().copied() == Some('u') {
if idx == 0 {
let mut buf = String::new();
buf.push('\\');
buf.extend(iter.take(6));
buf.extend(iter.take(5));
return Cow::Owned(buf);
} else {
for _ in 0..6 {
for _ in 0..5 {
iter.next();
}
}

View File

@ -972,8 +972,8 @@ fn test_fold_get_elem2_1() {
fold("x = 'string'[5]", "x = \"g\"");
fold("x = 'string'[0]", "x = \"s\"");
fold("x = 's'[0]", "x = \"s\"");
fold("x = '\\uD83D\\uDCA9'[0]", "x = \"\\ud83d\"");
fold("x = '\\uD83D\\uDCA9'[1]", "x = \"\\udca9\"");
fold("x = '\\uD83D\\uDCA9'[0]", "x = \"\\uD83D\"");
fold("x = '\\uD83D\\uDCA9'[1]", "x = \"\\uDCA9\"");
}
#[test]