From 6d34c9380ccc04ad3fee372cdaf5d71b7b9456aa Mon Sep 17 00:00:00 2001 From: ElevenDuan Date: Wed, 7 Feb 2024 17:29:58 +0800 Subject: [PATCH] The unicode escape in tagged template with es2021 Signed-off-by: ElevenDuan Change-Id: I767ab1b9e011ba98973d717c4f3e4c94018d74e6 --- es2panda/compiler/base/literals.cpp | 8 +++- es2panda/ir/base/templateElement.h | 11 ++++++ es2panda/lexer/lexer.cpp | 35 ++++++++++++++++- es2panda/lexer/lexer.h | 10 ++++- es2panda/lexer/token/token.h | 12 ++++++ es2panda/parser/expressionParser.cpp | 12 ++++-- es2panda/parser/parserImpl.h | 2 +- ...-template-string-escape-error-expected.txt | 9 +++++ .../test-tag-template-string-escape-error.js | 38 ++++++++++++++++++ ...-template-string-escape-error-expected.txt | 9 +++++ ...eneric-tag-template-string-escape-error.ts | 39 +++++++++++++++++++ .../js/test_template_string-expected.txt | 1 + .../test/parser/js/test_template_string.js | 16 ++++++++ .../js/test_template_string1-expected.txt | 1 + .../test/parser/js/test_template_string1.js | 16 ++++++++ .../js/test_template_string2-expected.txt | 1 + .../test/parser/js/test_template_string2.js | 16 ++++++++ .../js/test_template_string3-expected.txt | 1 + .../test/parser/js/test_template_string3.js | 16 ++++++++ .../js/test_template_string4-expected.txt | 1 + .../test/parser/js/test_template_string4.js | 16 ++++++++ .../js/test_template_string5-expected.txt | 1 + .../test/parser/js/test_template_string5.js | 16 ++++++++ 23 files changed, 277 insertions(+), 10 deletions(-) create mode 100644 es2panda/test/compiler/js/test-tag-template-string-escape-error-expected.txt create mode 100644 es2panda/test/compiler/js/test-tag-template-string-escape-error.js create mode 100644 es2panda/test/compiler/ts/cases/compiler/test-ts-generic-tag-template-string-escape-error-expected.txt create mode 100644 es2panda/test/compiler/ts/cases/compiler/test-ts-generic-tag-template-string-escape-error.ts create mode 100644 es2panda/test/parser/js/test_template_string-expected.txt create mode 100644 es2panda/test/parser/js/test_template_string.js create mode 100644 es2panda/test/parser/js/test_template_string1-expected.txt create mode 100644 es2panda/test/parser/js/test_template_string1.js create mode 100644 es2panda/test/parser/js/test_template_string2-expected.txt create mode 100644 es2panda/test/parser/js/test_template_string2.js create mode 100644 es2panda/test/parser/js/test_template_string3-expected.txt create mode 100644 es2panda/test/parser/js/test_template_string3.js create mode 100644 es2panda/test/parser/js/test_template_string4-expected.txt create mode 100644 es2panda/test/parser/js/test_template_string4.js create mode 100644 es2panda/test/parser/js/test_template_string5-expected.txt create mode 100644 es2panda/test/parser/js/test_template_string5.js diff --git a/es2panda/compiler/base/literals.cpp b/es2panda/compiler/base/literals.cpp index 0690bb6602..9775c55e5e 100644 --- a/es2panda/compiler/base/literals.cpp +++ b/es2panda/compiler/base/literals.cpp @@ -48,8 +48,12 @@ void Literals::GetTemplateObject(PandaGen *pg, const ir::TaggedTemplateExpressio pg->LoadAccumulatorString(element, element->Raw()); pg->StoreObjByValue(element, rawArr, indexReg); - - pg->LoadAccumulatorString(element, element->Cooked()); + // Generate ldundefined when element is escape error + if (element->EscapeError()) { + pg->LoadConst(element, compiler::Constant::JS_UNDEFINED); + } else { + pg->LoadAccumulatorString(element, element->Cooked()); + } pg->StoreObjByValue(element, cookedArr, indexReg); elemIndex++; diff --git a/es2panda/ir/base/templateElement.h b/es2panda/ir/base/templateElement.h index f717c4f4e4..1e52a65b8e 100644 --- a/es2panda/ir/base/templateElement.h +++ b/es2panda/ir/base/templateElement.h @@ -49,6 +49,16 @@ public: return cooked_; } + bool EscapeError() const + { + return escapeError_; + } + + void SetEscapeError(bool escapeError) + { + escapeError_ = escapeError; + } + void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; @@ -58,6 +68,7 @@ public: protected: util::StringView raw_ {}; util::StringView cooked_ {}; + bool escapeError_ {false}; }; } // namespace panda::es2panda::ir diff --git a/es2panda/lexer/lexer.cpp b/es2panda/lexer/lexer.cpp index 224b5c9bc8..cb86683430 100644 --- a/es2panda/lexer/lexer.cpp +++ b/es2panda/lexer/lexer.cpp @@ -66,12 +66,20 @@ char32_t Lexer::ScanUnicodeCodePointEscape() constexpr auto multiplier = 16; code = code * multiplier + HexValue(cp); if (code > UNICODE_CODE_POINT_MAX) { + if (CheckTokenIsTaggedTemplate()) { + AssignTokenEscapeError(); + break; + } ThrowError("Invalid unicode escape sequence"); } } - if (cp != LEX_CHAR_RIGHT_BRACE) { - ThrowError("Invalid unicode escape sequence"); + if (CheckTokenIsTaggedTemplate()) { + AssignTokenEscapeError(); + return static_cast(code); + } else { + ThrowError("Invalid unicode escape sequence"); + } } Iterator().Forward(1); @@ -602,6 +610,10 @@ void Lexer::ScanStringUnicodePart(util::UString *str) } if (isOctal) { + if (CheckTokenIsTaggedTemplate()) { + AssignTokenEscapeError(); + break; + } ThrowError("Octal escape sequences are not allowed in strict mode"); } @@ -609,6 +621,10 @@ void Lexer::ScanStringUnicodePart(util::UString *str) } default: { if (IsDecimalDigit(Iterator().Peek())) { + if (CheckTokenIsTaggedTemplate()) { + AssignTokenEscapeError(); + break; + } ThrowError("Invalid character escape sequence in strict mode"); } @@ -1661,4 +1677,19 @@ void Lexer::NextToken(LexerNextTokenFlags flags) SkipWhiteSpaces(); } +void Lexer::AssignTokenEscapeError() +{ + GetToken().flags_ |= TokenFlags::ESCAPE_ERROR; +} + +void Lexer::AssignTokenTaggedTemplate() +{ + GetToken().flags_ |= TokenFlags::TAGGED_TEMPLATE; +} + +bool Lexer::CheckTokenIsTaggedTemplate() const +{ + return GetToken().IsTaggedTemplate(); +} + } // namespace panda::es2panda::lexer diff --git a/es2panda/lexer/lexer.h b/es2panda/lexer/lexer.h index 7ce0e506dc..f8d531f931 100644 --- a/es2panda/lexer/lexer.h +++ b/es2panda/lexer/lexer.h @@ -91,6 +91,7 @@ public: LexerTemplateString ScanTemplateString(); void ScanTemplateStringEnd(); void PushTemplateContext(TemplateLiteralParserContext *ctx); + void AssignTokenTaggedTemplate(); private: ArenaAllocator *Allocator(); @@ -102,6 +103,7 @@ private: void SetTokenStart(); void SetTokenEnd(); + bool CheckTokenIsTaggedTemplate() const; inline util::StringView::Iterator &Iterator() { @@ -161,6 +163,7 @@ private: void ScanDecimalLiteral(); void ScanDecimalDigits(bool allowNumericSeparator); void CheckNumberLiteralEnd(); + void AssignTokenEscapeError(); inline static uint32_t HexValue(char32_t ch); inline static bool IsDecimalDigit(uint32_t cp); @@ -312,7 +315,12 @@ char32_t Lexer::ScanHexEscape() Iterator().Forward(1); if (!IsHexDigit(cp)) { - ThrowError("Invalid unicode escape sequence"); + // Should not throw error in tagged template in ES2021 + if (CheckTokenIsTaggedTemplate()) { + AssignTokenEscapeError(); + } else { + ThrowError("Invalid unicode escape sequence"); + } } constexpr auto MULTIPLIER = 16; diff --git a/es2panda/lexer/token/token.h b/es2panda/lexer/token/token.h index c31c3efe81..7f7876414e 100644 --- a/es2panda/lexer/token/token.h +++ b/es2panda/lexer/token/token.h @@ -30,6 +30,8 @@ enum class TokenFlags { HAS_ESCAPE = (1 << 2), NUMBER_BIGINT = (1 << 3), NUMBER_HAS_UNDERSCORE = (1 << 4), + ESCAPE_ERROR = (1 << 5), + TAGGED_TEMPLATE = (1 << 6), }; DEFINE_BITOPS(TokenFlags) @@ -106,6 +108,16 @@ public: return flags_ & TokenFlags::NEW_LINE; } + bool EscapeError() const + { + return flags_ & TokenFlags::ESCAPE_ERROR; + } + + bool IsTaggedTemplate() const + { + return flags_ & TokenFlags::TAGGED_TEMPLATE; + } + bool IsAccessability() const; bool IsAsyncModifier() const; bool IsStaticModifier() const; diff --git a/es2panda/parser/expressionParser.cpp b/es2panda/parser/expressionParser.cpp index 3c34c1b3f9..b400ddfb1d 100644 --- a/es2panda/parser/expressionParser.cpp +++ b/es2panda/parser/expressionParser.cpp @@ -863,7 +863,7 @@ ir::Expression *ParserImpl::ParseAssignmentExpression(ir::Expression *lhsExpress return lhsExpression; } -ir::TemplateLiteral *ParserImpl::ParseTemplateLiteral() +ir::TemplateLiteral *ParserImpl::ParseTemplateLiteral(bool isTaggedTemplate) { lexer::SourcePosition startLoc = lexer_->GetToken().Start(); @@ -873,14 +873,18 @@ ir::TemplateLiteral *ParserImpl::ParseTemplateLiteral() while (true) { lexer_->ResetTokenEnd(); const auto startPos = lexer_->Save(); - + if (isTaggedTemplate) { + lexer_->AssignTokenTaggedTemplate(); + } lexer_->ScanString(); util::StringView cooked = lexer_->GetToken().String(); + bool escapeError = lexer_->GetToken().EscapeError(); lexer_->Rewind(startPos); auto [raw, end, scanExpression] = lexer_->ScanTemplateString(); auto *element = AllocNode(raw.View(), cooked); + element->SetEscapeError(escapeError); element->SetRange({lexer::SourcePosition {startPos.iterator.Index(), startPos.line}, lexer::SourcePosition {end, lexer_->Line()}}); quasis.push_back(element); @@ -1620,7 +1624,7 @@ bool ParserImpl::ParsePotentialTsGenericFunctionCall(ir::Expression **returnExpr } if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_BACK_TICK) { - ir::TemplateLiteral *propertyNode = ParseTemplateLiteral(); + ir::TemplateLiteral *propertyNode = ParseTemplateLiteral(true); lexer::SourcePosition endLoc = propertyNode->End(); *returnExpression = AllocNode(*returnExpression, propertyNode, typeParams); @@ -1718,7 +1722,7 @@ ir::Expression *ParserImpl::ParsePostPrimaryExpression(ir::Expression *primaryEx continue; } case lexer::TokenType::PUNCTUATOR_BACK_TICK: { - ir::TemplateLiteral *propertyNode = ParseTemplateLiteral(); + ir::TemplateLiteral *propertyNode = ParseTemplateLiteral(true); lexer::SourcePosition endLoc = propertyNode->End(); returnExpression = AllocNode(returnExpression, propertyNode, nullptr); diff --git a/es2panda/parser/parserImpl.h b/es2panda/parser/parserImpl.h index 2889a846b0..e5394f967d 100644 --- a/es2panda/parser/parserImpl.h +++ b/es2panda/parser/parserImpl.h @@ -431,7 +431,7 @@ private: bool isDeclare = false); ir::Expression *ParsePatternElement(ExpressionParseFlags flags = ExpressionParseFlags::NO_OPTS, bool allowDefault = true, bool isDeclare = false); - ir::TemplateLiteral *ParseTemplateLiteral(); + ir::TemplateLiteral *ParseTemplateLiteral(bool isTaggedTemplate = false); ir::Expression *ParseImportExpression(); ir::ObjectExpression *ParseImportAssertionForDynamicImport(); void ValidateImportAssertionForDynamicImport(ir::ObjectExpression *importAssertion); diff --git a/es2panda/test/compiler/js/test-tag-template-string-escape-error-expected.txt b/es2panda/test/compiler/js/test-tag-template-string-escape-error-expected.txt new file mode 100644 index 0000000000..b784bb76e3 --- /dev/null +++ b/es2panda/test/compiler/js/test-tag-template-string-escape-error-expected.txt @@ -0,0 +1,9 @@ +ES2021undefined +ES2021undefined +ES2021undefined +ES2021undefined +ES2021 ჿ +ES2021undefined +ES2021 ዝ +ES2021undefined +ES2021 ª diff --git a/es2panda/test/compiler/js/test-tag-template-string-escape-error.js b/es2panda/test/compiler/js/test-tag-template-string-escape-error.js new file mode 100644 index 0000000000..e8d10e2a7f --- /dev/null +++ b/es2panda/test/compiler/js/test-tag-template-string-escape-error.js @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function fn(str, substitute) { + return substitute + str[1]; +} +const str = 'ES2021'; +const result = fn`${str} \ubuntu`; +const result1 = fn`${str} \123`; +const result2 = fn`${str} \0123`; +const result3 = fn`${str} \u{11ffff}`; +const result31 = fn`${str} \u{10ff}`; +const result4 = fn`${str} \u{12dd`; +const result41 = fn`${str} \u12dd`; +const result5 = fn`${str} \xgg`; +const result6 = fn`${str} \xaa`; + +print(result); +print(result1); +print(result2); +print(result3); +print(result31); +print(result4); +print(result41); +print(result5); +print(result6); diff --git a/es2panda/test/compiler/ts/cases/compiler/test-ts-generic-tag-template-string-escape-error-expected.txt b/es2panda/test/compiler/ts/cases/compiler/test-ts-generic-tag-template-string-escape-error-expected.txt new file mode 100644 index 0000000000..b784bb76e3 --- /dev/null +++ b/es2panda/test/compiler/ts/cases/compiler/test-ts-generic-tag-template-string-escape-error-expected.txt @@ -0,0 +1,9 @@ +ES2021undefined +ES2021undefined +ES2021undefined +ES2021undefined +ES2021 ჿ +ES2021undefined +ES2021 ዝ +ES2021undefined +ES2021 ª diff --git a/es2panda/test/compiler/ts/cases/compiler/test-ts-generic-tag-template-string-escape-error.ts b/es2panda/test/compiler/ts/cases/compiler/test-ts-generic-tag-template-string-escape-error.ts new file mode 100644 index 0000000000..ed07b2e64a --- /dev/null +++ b/es2panda/test/compiler/ts/cases/compiler/test-ts-generic-tag-template-string-escape-error.ts @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function fn(strs: TemplateStringsArray, ...args: T[]) : T { + return args[0] + args[1] + strs[2]; +} +const str = 'ES'; +const num = 2021; +const result = fn`${str}${num} \ubuntu`; +const result1 = fn`${str}${num} \123`; +const result2 = fn`${str}${num} \0123`; +const result3 = fn`${str}${num} \u{11ffff}`; +const result31 = fn`${str}${num} \u{10ff}`; +const result4 = fn`${str}${num} \u{12dd`; +const result41 = fn`${str}${num} \u12dd`; +const result5 = fn`${str}${num} \xgg`; +const result6 = fn`${str}${num} \xaa`; + +print(result); +print(result1); +print(result2); +print(result3); +print(result31); +print(result4); +print(result41); +print(result5); +print(result6); diff --git a/es2panda/test/parser/js/test_template_string-expected.txt b/es2panda/test/parser/js/test_template_string-expected.txt new file mode 100644 index 0000000000..5df45b6c5d --- /dev/null +++ b/es2panda/test/parser/js/test_template_string-expected.txt @@ -0,0 +1 @@ +SyntaxError: Invalid unicode escape sequence [test_template_string.js:16:18] diff --git a/es2panda/test/parser/js/test_template_string.js b/es2panda/test/parser/js/test_template_string.js new file mode 100644 index 0000000000..2dba6954e6 --- /dev/null +++ b/es2panda/test/parser/js/test_template_string.js @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const str = `\ubuntu`; diff --git a/es2panda/test/parser/js/test_template_string1-expected.txt b/es2panda/test/parser/js/test_template_string1-expected.txt new file mode 100644 index 0000000000..c4eb2bdceb --- /dev/null +++ b/es2panda/test/parser/js/test_template_string1-expected.txt @@ -0,0 +1 @@ +SyntaxError: Invalid character escape sequence in strict mode [test_template_string1.js:16:15] diff --git a/es2panda/test/parser/js/test_template_string1.js b/es2panda/test/parser/js/test_template_string1.js new file mode 100644 index 0000000000..a07b0d0d2f --- /dev/null +++ b/es2panda/test/parser/js/test_template_string1.js @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const str = `\123`; diff --git a/es2panda/test/parser/js/test_template_string2-expected.txt b/es2panda/test/parser/js/test_template_string2-expected.txt new file mode 100644 index 0000000000..129400dd1f --- /dev/null +++ b/es2panda/test/parser/js/test_template_string2-expected.txt @@ -0,0 +1 @@ +SyntaxError: Octal escape sequences are not allowed in strict mode [test_template_string2.js:16:15] diff --git a/es2panda/test/parser/js/test_template_string2.js b/es2panda/test/parser/js/test_template_string2.js new file mode 100644 index 0000000000..152f94504b --- /dev/null +++ b/es2panda/test/parser/js/test_template_string2.js @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const str = `\0123`; diff --git a/es2panda/test/parser/js/test_template_string3-expected.txt b/es2panda/test/parser/js/test_template_string3-expected.txt new file mode 100644 index 0000000000..1f57dcecef --- /dev/null +++ b/es2panda/test/parser/js/test_template_string3-expected.txt @@ -0,0 +1 @@ +SyntaxError: Invalid unicode escape sequence [test_template_string3.js:16:23] diff --git a/es2panda/test/parser/js/test_template_string3.js b/es2panda/test/parser/js/test_template_string3.js new file mode 100644 index 0000000000..4f42f1443c --- /dev/null +++ b/es2panda/test/parser/js/test_template_string3.js @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const str = `\u{11ffff}`; diff --git a/es2panda/test/parser/js/test_template_string4-expected.txt b/es2panda/test/parser/js/test_template_string4-expected.txt new file mode 100644 index 0000000000..7db38dd569 --- /dev/null +++ b/es2panda/test/parser/js/test_template_string4-expected.txt @@ -0,0 +1 @@ +SyntaxError: Invalid unicode escape sequence [test_template_string4.js:16:21] diff --git a/es2panda/test/parser/js/test_template_string4.js b/es2panda/test/parser/js/test_template_string4.js new file mode 100644 index 0000000000..9d640c3d56 --- /dev/null +++ b/es2panda/test/parser/js/test_template_string4.js @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const str = `\u{12dd`; diff --git a/es2panda/test/parser/js/test_template_string5-expected.txt b/es2panda/test/parser/js/test_template_string5-expected.txt new file mode 100644 index 0000000000..53c9ba7442 --- /dev/null +++ b/es2panda/test/parser/js/test_template_string5-expected.txt @@ -0,0 +1 @@ +SyntaxError: Invalid unicode escape sequence [test_template_string5.js:16:17] diff --git a/es2panda/test/parser/js/test_template_string5.js b/es2panda/test/parser/js/test_template_string5.js new file mode 100644 index 0000000000..899c9809a0 --- /dev/null +++ b/es2panda/test/parser/js/test_template_string5.js @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const str = `\xgg`; -- Gitee