mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 10:48:11 +00:00
LibJS: Support LegacyOctalEscapeSequence in string literals
https://tc39.es/ecma262/#sec-additional-syntax-string-literals The syntax and semantics of 11.8.4 is extended as follows except that this extension is not allowed for strict mode code: Syntax EscapeSequence:: CharacterEscapeSequence LegacyOctalEscapeSequence NonOctalDecimalEscapeSequence HexEscapeSequence UnicodeEscapeSequence LegacyOctalEscapeSequence:: OctalDigit [lookahead ∉ OctalDigit] ZeroToThree OctalDigit [lookahead ∉ OctalDigit] FourToSeven OctalDigit ZeroToThree OctalDigit OctalDigit ZeroToThree :: one of 0 1 2 3 FourToSeven :: one of 4 5 6 7 NonOctalDecimalEscapeSequence :: one of 8 9 This definition of EscapeSequence is not used in strict mode or when parsing TemplateCharacter. Note It is possible for string literals to precede a Use Strict Directive that places the enclosing code in strict mode, and implementations must take care to not use this extended definition of EscapeSequence with such literals. For example, attempting to parse the following source text must fail: function invalid() { "\7"; "use strict"; }
This commit is contained in:
parent
9f036959e8
commit
4fb96afafc
5 changed files with 104 additions and 11 deletions
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Stephan Unverwerth <s.unverwerth@gmx.de>
|
||||
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -103,8 +104,19 @@ String Token::string_value(StringValueStatus& status) const
|
|||
{
|
||||
ASSERT(type() == TokenType::StringLiteral || type() == TokenType::TemplateLiteralString);
|
||||
auto is_template = type() == TokenType::TemplateLiteralString;
|
||||
auto offset = is_template ? 0 : 1;
|
||||
|
||||
auto offset = type() == TokenType::TemplateLiteralString ? 0 : 1;
|
||||
size_t i;
|
||||
|
||||
auto lookahead = [&]<typename T>(T fn, size_t distance = 1) -> bool {
|
||||
if (i + distance >= m_value.length() - offset)
|
||||
return false;
|
||||
return fn(m_value[i + distance]);
|
||||
};
|
||||
|
||||
auto is_octal_digit = [](char c) {
|
||||
return c >= '0' && c <= '7';
|
||||
};
|
||||
|
||||
auto encoding_failure = [&status](StringValueStatus parse_status) -> String {
|
||||
status = parse_status;
|
||||
|
@ -112,7 +124,7 @@ String Token::string_value(StringValueStatus& status) const
|
|||
};
|
||||
|
||||
StringBuilder builder;
|
||||
for (size_t i = offset; i < m_value.length() - offset; ++i) {
|
||||
for (i = offset; i < m_value.length() - offset; ++i) {
|
||||
if (m_value[i] == '\\' && i + 1 < m_value.length() - offset) {
|
||||
i++;
|
||||
switch (m_value[i]) {
|
||||
|
@ -134,9 +146,6 @@ String Token::string_value(StringValueStatus& status) const
|
|||
case 'v':
|
||||
builder.append('\v');
|
||||
break;
|
||||
case '0':
|
||||
builder.append((char)0);
|
||||
break;
|
||||
case '\'':
|
||||
builder.append('\'');
|
||||
break;
|
||||
|
@ -200,9 +209,43 @@ String Token::string_value(StringValueStatus& status) const
|
|||
builder.append(m_value[i]);
|
||||
break;
|
||||
}
|
||||
if (m_value[i] == '0' && !lookahead(isdigit)) {
|
||||
builder.append((char)0);
|
||||
break;
|
||||
}
|
||||
|
||||
// FIXME: Also parse octal. Should anything else generate a syntax error?
|
||||
builder.append(m_value[i]);
|
||||
// In non-strict mode LegacyOctalEscapeSequence is allowed in strings:
|
||||
// https://tc39.es/ecma262/#sec-additional-syntax-string-literals
|
||||
String octal_str;
|
||||
|
||||
// OctalDigit [lookahead ∉ OctalDigit]
|
||||
if (is_octal_digit(m_value[i]) && !lookahead(is_octal_digit)) {
|
||||
status = StringValueStatus::LegacyOctalEscapeSequence;
|
||||
octal_str = String(&m_value[i], 1);
|
||||
}
|
||||
// ZeroToThree OctalDigit [lookahead ∉ OctalDigit]
|
||||
else if (m_value[i] >= '0' && m_value[i] <= '3' && lookahead(is_octal_digit) && !lookahead(is_octal_digit, 2)) {
|
||||
status = StringValueStatus::LegacyOctalEscapeSequence;
|
||||
octal_str = String(m_value.substring_view(i, 2));
|
||||
i++;
|
||||
}
|
||||
// FourToSeven OctalDigit
|
||||
else if (m_value[i] >= '4' && m_value[i] <= '7' && lookahead(is_octal_digit)) {
|
||||
status = StringValueStatus::LegacyOctalEscapeSequence;
|
||||
octal_str = String(m_value.substring_view(i, 2));
|
||||
i++;
|
||||
}
|
||||
// ZeroToThree OctalDigit OctalDigit
|
||||
else if (m_value[i] >= '0' && m_value[i] <= '3' && lookahead(is_octal_digit) && lookahead(is_octal_digit, 2)) {
|
||||
status = StringValueStatus::LegacyOctalEscapeSequence;
|
||||
octal_str = String(m_value.substring_view(i, 3));
|
||||
i += 2;
|
||||
}
|
||||
|
||||
if (status == StringValueStatus::LegacyOctalEscapeSequence)
|
||||
builder.append_code_point(strtoul(octal_str.characters(), nullptr, 8));
|
||||
else
|
||||
builder.append(m_value[i]);
|
||||
}
|
||||
} else {
|
||||
builder.append(m_value[i]);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue