diff --git a/Ast/src/Lexer.cpp b/Ast/src/Lexer.cpp index 70612ca1..870e11c2 100644 --- a/Ast/src/Lexer.cpp +++ b/Ast/src/Lexer.cpp @@ -624,6 +624,15 @@ Lexeme Lexer::readInterpolatedStringSection(Position start, Lexeme::Type formatT return Lexeme(Location(start, position()), Lexeme::BrokenString); case '\\': + // Allow for \u{}, which would otherwise be consumed by looking for { + if (peekch(1) == 'u' && peekch(2) == '{') + { + consume(); // backslash + consume(); // u + consume(); // { + break; + } + readBackslashInString(); break; diff --git a/Compiler/src/Compiler.cpp b/Compiler/src/Compiler.cpp index 17256e15..666cca54 100644 --- a/Compiler/src/Compiler.cpp +++ b/Compiler/src/Compiler.cpp @@ -1639,7 +1639,7 @@ struct Compiler RegScope rs(this); - uint8_t baseReg = allocReg(expr, 2 + expr->expressions.size); + uint8_t baseReg = allocReg(expr, uint8_t(2 + expr->expressions.size)); emitLoadK(baseReg, formatStringIndex); diff --git a/tests/Lexer.test.cpp b/tests/Lexer.test.cpp index 7330aba6..9ff06bc9 100644 --- a/tests/Lexer.test.cpp +++ b/tests/Lexer.test.cpp @@ -175,4 +175,17 @@ TEST_CASE("string_interpolation_unmatched_brace") CHECK_EQ(lexer.next().type, '}'); } +TEST_CASE("string_interpolation_with_unicode_escape") +{ + ScopedFastFlag sff{"LuauInterpolatedStringBaseSupport", true}; + + const std::string testInput = R"(`\u{1F41B}`)"; + Luau::Allocator alloc; + AstNameTable table(alloc); + Lexer lexer(testInput.c_str(), testInput.size(), table); + + CHECK_EQ(lexer.next().type, Lexeme::InterpStringSimple); + CHECK_EQ(lexer.next().type, Lexeme::Eof); +} + TEST_SUITE_END(); diff --git a/tests/conformance/stringinterp.lua b/tests/conformance/stringinterp.lua index 9bb29a7e..539505f4 100644 --- a/tests/conformance/stringinterp.lua +++ b/tests/conformance/stringinterp.lua @@ -61,4 +61,6 @@ end assertEq(identity`text`, "text") assertEq(identity`foo{"bar"}`, "foobar") +assertEq(`\u{0041}\t`, "A\t") + return "OK"