|
@@ -786,6 +786,8 @@ GDScriptTokenizer::Token GDScriptTokenizer::string() {
|
|
}
|
|
}
|
|
|
|
|
|
String result;
|
|
String result;
|
|
|
|
+ char32_t prev = 0;
|
|
|
|
+ int prev_pos = 0;
|
|
|
|
|
|
for (;;) {
|
|
for (;;) {
|
|
// Consume actual string.
|
|
// Consume actual string.
|
|
@@ -852,9 +854,11 @@ GDScriptTokenizer::Token GDScriptTokenizer::string() {
|
|
case '\\':
|
|
case '\\':
|
|
escaped = '\\';
|
|
escaped = '\\';
|
|
break;
|
|
break;
|
|
- case 'u':
|
|
|
|
|
|
+ case 'U':
|
|
|
|
+ case 'u': {
|
|
// Hexadecimal sequence.
|
|
// Hexadecimal sequence.
|
|
- for (int i = 0; i < 4; i++) {
|
|
|
|
|
|
+ int hex_len = (code == 'U') ? 6 : 4;
|
|
|
|
+ for (int j = 0; j < hex_len; j++) {
|
|
if (_is_at_end()) {
|
|
if (_is_at_end()) {
|
|
return make_error("Unterminated string.");
|
|
return make_error("Unterminated string.");
|
|
}
|
|
}
|
|
@@ -886,7 +890,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::string() {
|
|
|
|
|
|
_advance();
|
|
_advance();
|
|
}
|
|
}
|
|
- break;
|
|
|
|
|
|
+ } break;
|
|
case '\r':
|
|
case '\r':
|
|
if (_peek() != '\n') {
|
|
if (_peek() != '\n') {
|
|
// Carriage return without newline in string. (???)
|
|
// Carriage return without newline in string. (???)
|
|
@@ -909,11 +913,53 @@ GDScriptTokenizer::Token GDScriptTokenizer::string() {
|
|
valid_escape = false;
|
|
valid_escape = false;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
+ // Parse UTF-16 pair.
|
|
|
|
+ if (valid_escape) {
|
|
|
|
+ if ((escaped & 0xfffffc00) == 0xd800) {
|
|
|
|
+ if (prev == 0) {
|
|
|
|
+ prev = escaped;
|
|
|
|
+ prev_pos = column - 2;
|
|
|
|
+ continue;
|
|
|
|
+ } else {
|
|
|
|
+ Token error = make_error("Invalid UTF-16 sequence in string, unpaired lead surrogate");
|
|
|
|
+ error.start_column = column - 2;
|
|
|
|
+ error.leftmost_column = error.start_column;
|
|
|
|
+ push_error(error);
|
|
|
|
+ valid_escape = false;
|
|
|
|
+ prev = 0;
|
|
|
|
+ }
|
|
|
|
+ } else if ((escaped & 0xfffffc00) == 0xdc00) {
|
|
|
|
+ if (prev == 0) {
|
|
|
|
+ Token error = make_error("Invalid UTF-16 sequence in string, unpaired trail surrogate");
|
|
|
|
+ error.start_column = column - 2;
|
|
|
|
+ error.leftmost_column = error.start_column;
|
|
|
|
+ push_error(error);
|
|
|
|
+ valid_escape = false;
|
|
|
|
+ } else {
|
|
|
|
+ escaped = (prev << 10UL) + escaped - ((0xd800 << 10UL) + 0xdc00 - 0x10000);
|
|
|
|
+ prev = 0;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (prev != 0) {
|
|
|
|
+ Token error = make_error("Invalid UTF-16 sequence in string, unpaired lead surrogate");
|
|
|
|
+ error.start_column = prev_pos;
|
|
|
|
+ error.leftmost_column = error.start_column;
|
|
|
|
+ push_error(error);
|
|
|
|
+ prev = 0;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
if (valid_escape) {
|
|
if (valid_escape) {
|
|
result += escaped;
|
|
result += escaped;
|
|
}
|
|
}
|
|
} else if (ch == quote_char) {
|
|
} else if (ch == quote_char) {
|
|
|
|
+ if (prev != 0) {
|
|
|
|
+ Token error = make_error("Invalid UTF-16 sequence in string, unpaired lead surrogate");
|
|
|
|
+ error.start_column = prev_pos;
|
|
|
|
+ error.leftmost_column = error.start_column;
|
|
|
|
+ push_error(error);
|
|
|
|
+ prev = 0;
|
|
|
|
+ }
|
|
_advance();
|
|
_advance();
|
|
if (is_multiline) {
|
|
if (is_multiline) {
|
|
if (_peek() == quote_char && _peek(1) == quote_char) {
|
|
if (_peek() == quote_char && _peek(1) == quote_char) {
|
|
@@ -930,6 +976,13 @@ GDScriptTokenizer::Token GDScriptTokenizer::string() {
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
|
|
+ if (prev != 0) {
|
|
|
|
+ Token error = make_error("Invalid UTF-16 sequence in string, unpaired lead surrogate");
|
|
|
|
+ error.start_column = prev_pos;
|
|
|
|
+ error.leftmost_column = error.start_column;
|
|
|
|
+ push_error(error);
|
|
|
|
+ prev = 0;
|
|
|
|
+ }
|
|
result += ch;
|
|
result += ch;
|
|
_advance();
|
|
_advance();
|
|
if (ch == '\n') {
|
|
if (ch == '\n') {
|
|
@@ -937,6 +990,13 @@ GDScriptTokenizer::Token GDScriptTokenizer::string() {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ if (prev != 0) {
|
|
|
|
+ Token error = make_error("Invalid UTF-16 sequence in string, unpaired lead surrogate");
|
|
|
|
+ error.start_column = prev_pos;
|
|
|
|
+ error.leftmost_column = error.start_column;
|
|
|
|
+ push_error(error);
|
|
|
|
+ prev = 0;
|
|
|
|
+ }
|
|
|
|
|
|
// Make the literal.
|
|
// Make the literal.
|
|
Variant string;
|
|
Variant string;
|