mirror of
https://github.com/luau-lang/luau.git
synced 2025-05-04 10:33:46 +01:00
Fix string interpolation autocomplete
This commit is contained in:
parent
c32cdd5c42
commit
eb53fa5bec
5 changed files with 36 additions and 37 deletions
|
@ -1,6 +1,7 @@
|
||||||
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||||
#include "Luau/AstQuery.h"
|
#include "Luau/AstQuery.h"
|
||||||
|
|
||||||
|
#include "Luau/Ast.h"
|
||||||
#include "Luau/Module.h"
|
#include "Luau/Module.h"
|
||||||
#include "Luau/Scope.h"
|
#include "Luau/Scope.h"
|
||||||
#include "Luau/TypeInfer.h"
|
#include "Luau/TypeInfer.h"
|
||||||
|
|
|
@ -1227,11 +1227,8 @@ static bool stringPartOfInterpString(const AstNode* node, Position position)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("expressions.count: %ld\n", interpString->expressions.size);
|
|
||||||
|
|
||||||
for (const AstExpr* expression : interpString->expressions)
|
for (const AstExpr* expression : interpString->expressions)
|
||||||
{
|
{
|
||||||
printf("%s <= %s <= %s -- expression = %d\n", toString(expression->location.begin).c_str(), toString(position).c_str(), toString(expression->location.end).c_str(), expression->classIndex);
|
|
||||||
if (expression->location.containsClosed(position))
|
if (expression->location.containsClosed(position))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -1239,7 +1236,6 @@ static bool stringPartOfInterpString(const AstNode* node, Position position)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
// return node->is<AstExprInterpString>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::optional<AutocompleteEntryMap> autocompleteStringParams(const SourceModule& sourceModule, const ModulePtr& module,
|
static std::optional<AutocompleteEntryMap> autocompleteStringParams(const SourceModule& sourceModule, const ModulePtr& module,
|
||||||
|
|
|
@ -22,7 +22,7 @@ bool lua_telemetry_parsed_named_non_function_type = false;
|
||||||
LUAU_FASTFLAGVARIABLE(LuauErrorDoubleHexPrefix, false)
|
LUAU_FASTFLAGVARIABLE(LuauErrorDoubleHexPrefix, false)
|
||||||
LUAU_DYNAMIC_FASTFLAGVARIABLE(LuaReportParseIntegerIssues, false)
|
LUAU_DYNAMIC_FASTFLAGVARIABLE(LuaReportParseIntegerIssues, false)
|
||||||
|
|
||||||
LUAU_FASTFLAGVARIABLE(LuauInterpolatedStringBaseSupport, false)
|
LUAU_FASTFLAGVARIABLE(LuauInterpolatedStringBaseSupport, true)
|
||||||
|
|
||||||
LUAU_FASTFLAGVARIABLE(LuauCommaParenWarnings, false)
|
LUAU_FASTFLAGVARIABLE(LuauCommaParenWarnings, false)
|
||||||
LUAU_FASTFLAGVARIABLE(LuauTableConstructorRecovery, false)
|
LUAU_FASTFLAGVARIABLE(LuauTableConstructorRecovery, false)
|
||||||
|
@ -2661,6 +2661,7 @@ AstExpr* Parser::parseInterpString()
|
||||||
TempVector<AstExpr*> expressions(scratchExpr);
|
TempVector<AstExpr*> expressions(scratchExpr);
|
||||||
|
|
||||||
Location startLocation = lexer.current().location;
|
Location startLocation = lexer.current().location;
|
||||||
|
Location endLocation;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
@ -2668,17 +2669,16 @@ AstExpr* Parser::parseInterpString()
|
||||||
LUAU_ASSERT(currentLexeme.type == Lexeme::InterpStringBegin || currentLexeme.type == Lexeme::InterpStringMid ||
|
LUAU_ASSERT(currentLexeme.type == Lexeme::InterpStringBegin || currentLexeme.type == Lexeme::InterpStringMid ||
|
||||||
currentLexeme.type == Lexeme::InterpStringEnd || currentLexeme.type == Lexeme::InterpStringSimple);
|
currentLexeme.type == Lexeme::InterpStringEnd || currentLexeme.type == Lexeme::InterpStringSimple);
|
||||||
|
|
||||||
Location location = currentLexeme.location;
|
endLocation = currentLexeme.location;
|
||||||
|
|
||||||
Location startOfBrace = Location(location.end, 1);
|
Location startOfBrace = Location(endLocation.end, 1);
|
||||||
|
|
||||||
scratchData.assign(currentLexeme.data, currentLexeme.length);
|
scratchData.assign(currentLexeme.data, currentLexeme.length);
|
||||||
|
|
||||||
if (!Lexer::fixupQuotedString(scratchData))
|
if (!Lexer::fixupQuotedString(scratchData))
|
||||||
{
|
{
|
||||||
nextLexeme();
|
nextLexeme();
|
||||||
printf("FIXUP QUOTED STRING FAIL\n");
|
return reportExprError(Location{startLocation, endLocation}, {}, "Interpolated string literal contains malformed escape sequence");
|
||||||
return reportExprError(startLocation, {}, "Interpolated string literal contains malformed escape sequence");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AstArray<char> chars = copy(scratchData);
|
AstArray<char> chars = copy(scratchData);
|
||||||
|
@ -2689,10 +2689,7 @@ AstExpr* Parser::parseInterpString()
|
||||||
|
|
||||||
if (currentLexeme.type == Lexeme::InterpStringEnd || currentLexeme.type == Lexeme::InterpStringSimple)
|
if (currentLexeme.type == Lexeme::InterpStringEnd || currentLexeme.type == Lexeme::InterpStringSimple)
|
||||||
{
|
{
|
||||||
AstArray<AstArray<char>> stringsArray = copy(strings);
|
break;
|
||||||
AstArray<AstExpr*> expressionsArray = copy(expressions);
|
|
||||||
|
|
||||||
return allocator.alloc<AstExprInterpString>(startLocation, stringsArray, expressionsArray);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (lexer.current().type)
|
switch (lexer.current().type)
|
||||||
|
@ -2701,20 +2698,14 @@ AstExpr* Parser::parseInterpString()
|
||||||
case Lexeme::InterpStringEnd:
|
case Lexeme::InterpStringEnd:
|
||||||
{
|
{
|
||||||
nextLexeme();
|
nextLexeme();
|
||||||
expressions.push_back(reportExprError(location, {}, "Malformed interpolated string, expected expression inside '{}'"));
|
expressions.push_back(reportExprError(endLocation, {}, "Malformed interpolated string, expected expression inside '{}'"));
|
||||||
AstArray<AstArray<char>> stringsArray = copy(strings);
|
break;
|
||||||
AstArray<AstExpr*> expressionsArray = copy(expressions);
|
|
||||||
|
|
||||||
return allocator.alloc<AstExprInterpString>(startLocation, stringsArray, expressionsArray);
|
|
||||||
}
|
}
|
||||||
case Lexeme::BrokenString:
|
case Lexeme::BrokenString:
|
||||||
{
|
{
|
||||||
nextLexeme();
|
nextLexeme();
|
||||||
expressions.push_back(reportExprError(location, {}, "Malformed interpolated string, did you forget to add a '`'?"));
|
expressions.push_back(reportExprError(endLocation, {}, "Malformed interpolated string, did you forget to add a '`'?"));
|
||||||
AstArray<AstArray<char>> stringsArray = copy(strings);
|
break;
|
||||||
AstArray<AstExpr*> expressionsArray = copy(expressions);
|
|
||||||
|
|
||||||
return allocator.alloc<AstExprInterpString>(startLocation, stringsArray, expressionsArray);
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
expressions.push_back(parseExpr());
|
expressions.push_back(parseExpr());
|
||||||
|
@ -2728,17 +2719,18 @@ AstExpr* Parser::parseInterpString()
|
||||||
break;
|
break;
|
||||||
case Lexeme::BrokenInterpDoubleBrace:
|
case Lexeme::BrokenInterpDoubleBrace:
|
||||||
nextLexeme();
|
nextLexeme();
|
||||||
printf("BROKEN INTERP DOUBLE BRACE\n");
|
return reportExprError(endLocation, {}, ERROR_INVALID_INTERP_DOUBLE_BRACE);
|
||||||
return reportExprError(location, {}, ERROR_INVALID_INTERP_DOUBLE_BRACE);
|
|
||||||
case Lexeme::BrokenString:
|
case Lexeme::BrokenString:
|
||||||
nextLexeme();
|
nextLexeme();
|
||||||
printf("BROKEN STRING\n");
|
return reportExprError(endLocation, {}, "Malformed interpolated string, did you forget to add a '}'?");
|
||||||
return reportExprError(location, {}, "Malformed interpolated string, did you forget to add a '}'?");
|
|
||||||
default:
|
default:
|
||||||
printf("DEFAULT: %s\n", lexer.current().toString().c_str());
|
return reportExprError(endLocation, {}, "Malformed interpolated string, got %s", lexer.current().toString().c_str());
|
||||||
return reportExprError(location, {}, "Malformed interpolated string, got %s", lexer.current().toString().c_str());
|
|
||||||
}
|
}
|
||||||
} while (true);
|
} while (true);
|
||||||
|
|
||||||
|
AstArray<AstArray<char>> stringsArray = copy(strings);
|
||||||
|
AstArray<AstExpr*> expressionsArray = copy(expressions);
|
||||||
|
return allocator.alloc<AstExprInterpString>(Location{startLocation, endLocation}, stringsArray, expressionsArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
AstExpr* Parser::parseNumber()
|
AstExpr* Parser::parseNumber()
|
||||||
|
|
|
@ -183,7 +183,7 @@ TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstExprInterpString")
|
||||||
AstStat* statement = expectParseStatement("local a = `var = {x}`");
|
AstStat* statement = expectParseStatement("local a = `var = {x}`");
|
||||||
|
|
||||||
std::string_view expected =
|
std::string_view expected =
|
||||||
R"({"type":"AstStatLocal","location":"0,0 - 0,18","vars":[{"luauType":null,"name":"a","type":"AstLocal","location":"0,6 - 0,7"}],"values":[{"type":"AstExprInterpString","location":"0,10 - 0,18","strings":["var = ",""],"expressions":[{"type":"AstExprGlobal","location":"0,18 - 0,19","global":"x"}]}]})";
|
R"({"type":"AstStatLocal","location":"0,0 - 0,21","vars":[{"luauType":null,"name":"a","type":"AstLocal","location":"0,6 - 0,7"}],"values":[{"type":"AstExprInterpString","location":"0,10 - 0,21","strings":["var = ",""],"expressions":[{"type":"AstExprGlobal","location":"0,18 - 0,19","global":"x"}]}]})";
|
||||||
|
|
||||||
CHECK(toJson(statement) == expected);
|
CHECK(toJson(statement) == expected);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2712,15 +2712,24 @@ a = if temp then even else abc@3
|
||||||
TEST_CASE_FIXTURE(ACFixture, "autocomplete_interpolated_string_constant")
|
TEST_CASE_FIXTURE(ACFixture, "autocomplete_interpolated_string_constant")
|
||||||
{
|
{
|
||||||
ScopedFastFlag sff{"LuauInterpolatedStringBaseSupport", true};
|
ScopedFastFlag sff{"LuauInterpolatedStringBaseSupport", true};
|
||||||
printf("======= autocomplete_interpolated_string_constant =======\n");
|
|
||||||
|
|
||||||
// check(R"(f(`@1`))");
|
check(R"(f(`@1`))");
|
||||||
// auto ac = autocomplete('1');
|
auto ac = autocomplete('1');
|
||||||
// CHECK(ac.entryMap.empty());
|
CHECK(ac.entryMap.empty());
|
||||||
// CHECK_EQ(ac.context, AutocompleteContext::String);
|
CHECK_EQ(ac.context, AutocompleteContext::String);
|
||||||
|
|
||||||
|
check(R"(f(`@1 {"a"}`))");
|
||||||
|
ac = autocomplete('1');
|
||||||
|
CHECK(ac.entryMap.empty());
|
||||||
|
CHECK_EQ(ac.context, AutocompleteContext::String);
|
||||||
|
|
||||||
check(R"(f(`{"a"} @1`))");
|
check(R"(f(`{"a"} @1`))");
|
||||||
auto ac = autocomplete('1');
|
ac = autocomplete('1');
|
||||||
|
CHECK(ac.entryMap.empty());
|
||||||
|
CHECK_EQ(ac.context, AutocompleteContext::String);
|
||||||
|
|
||||||
|
check(R"(f(`{"a"} @1 {"b"}`))");
|
||||||
|
ac = autocomplete('1');
|
||||||
CHECK(ac.entryMap.empty());
|
CHECK(ac.entryMap.empty());
|
||||||
CHECK_EQ(ac.context, AutocompleteContext::String);
|
CHECK_EQ(ac.context, AutocompleteContext::String);
|
||||||
}
|
}
|
||||||
|
@ -2745,8 +2754,9 @@ TEST_CASE_FIXTURE(ACFixture, "autocomplete_interpolated_string_expression_with_c
|
||||||
CHECK(ac.entryMap.count("table"));
|
CHECK(ac.entryMap.count("table"));
|
||||||
CHECK_EQ(ac.context, AutocompleteContext::Expression);
|
CHECK_EQ(ac.context, AutocompleteContext::Expression);
|
||||||
|
|
||||||
check(R"(f(`expression = {@1--[[ bla bla bla ]]`))");
|
check(R"(f(`expression = {@1 --[[ bla bla bla ]]`))");
|
||||||
ac = autocomplete('1');
|
ac = autocomplete('1');
|
||||||
|
CHECK(!ac.entryMap.empty());
|
||||||
CHECK(ac.entryMap.count("table"));
|
CHECK(ac.entryMap.count("table"));
|
||||||
CHECK_EQ(ac.context, AutocompleteContext::Expression);
|
CHECK_EQ(ac.context, AutocompleteContext::Expression);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue