Start work on string interpolation autocomplete fixes

This commit is contained in:
Kampfkarren 2022-11-15 11:17:52 -08:00
parent 816e41a8f2
commit c32cdd5c42
4 changed files with 668 additions and 586 deletions

File diff suppressed because it is too large Load diff

View file

@ -1219,6 +1219,29 @@ static std::optional<const ClassTypeVar*> getMethodContainingClass(const ModuleP
return std::nullopt;
}
static bool stringPartOfInterpString(const AstNode* node, Position position)
{
const AstExprInterpString* interpString = node->as<AstExprInterpString>();
if (!interpString)
{
return false;
}
printf("expressions.count: %ld\n", interpString->expressions.size);
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))
{
return false;
}
}
return true;
// return node->is<AstExprInterpString>();
}
static std::optional<AutocompleteEntryMap> autocompleteStringParams(const SourceModule& sourceModule, const ModulePtr& module,
const std::vector<AstNode*>& nodes, Position position, StringCompletionCallback callback)
{
@ -1227,7 +1250,7 @@ static std::optional<AutocompleteEntryMap> autocompleteStringParams(const Source
return std::nullopt;
}
if (!nodes.back()->is<AstExprConstantString>() && !nodes.back()->is<AstExprError>())
if (!nodes.back()->is<AstExprConstantString>() && !stringPartOfInterpString(nodes.back(), position) && !nodes.back()->is<AstExprError>())
{
return std::nullopt;
}
@ -1432,7 +1455,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
return autocompleteExpression(sourceModule, *module, singletonTypes, &typeArena, ancestry, position);
else if (AstStatRepeat* statRepeat = extractStat<AstStatRepeat>(ancestry); statRepeat)
return {autocompleteStatement(sourceModule, *module, ancestry, position), ancestry, AutocompleteContext::Statement};
else if (AstExprTable* exprTable = parent->as<AstExprTable>(); exprTable && (node->is<AstExprGlobal>() || node->is<AstExprConstantString>()))
else if (AstExprTable* exprTable = parent->as<AstExprTable>(); exprTable && (node->is<AstExprGlobal>() || node->is<AstExprConstantString>() || node->is<AstExprInterpString>()))
{
for (const auto& [kind, key, value] : exprTable->items)
{
@ -1471,7 +1494,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
{
return {*ret, ancestry, AutocompleteContext::String};
}
else if (node->is<AstExprConstantString>())
else if (node->is<AstExprConstantString>() || stringPartOfInterpString(node, position))
{
AutocompleteEntryMap result;

View file

@ -2677,6 +2677,7 @@ AstExpr* Parser::parseInterpString()
if (!Lexer::fixupQuotedString(scratchData))
{
nextLexeme();
printf("FIXUP QUOTED STRING FAIL\n");
return reportExprError(startLocation, {}, "Interpolated string literal contains malformed escape sequence");
}
@ -2694,9 +2695,30 @@ AstExpr* Parser::parseInterpString()
return allocator.alloc<AstExprInterpString>(startLocation, stringsArray, expressionsArray);
}
AstExpr* expression = parseExpr();
switch (lexer.current().type)
{
case Lexeme::InterpStringMid:
case Lexeme::InterpStringEnd:
{
nextLexeme();
expressions.push_back(reportExprError(location, {}, "Malformed interpolated string, expected expression inside '{}'"));
AstArray<AstArray<char>> stringsArray = copy(strings);
AstArray<AstExpr*> expressionsArray = copy(expressions);
expressions.push_back(expression);
return allocator.alloc<AstExprInterpString>(startLocation, stringsArray, expressionsArray);
}
case Lexeme::BrokenString:
{
nextLexeme();
expressions.push_back(reportExprError(location, {}, "Malformed interpolated string, did you forget to add a '`'?"));
AstArray<AstArray<char>> stringsArray = copy(strings);
AstArray<AstExpr*> expressionsArray = copy(expressions);
return allocator.alloc<AstExprInterpString>(startLocation, stringsArray, expressionsArray);
}
default:
expressions.push_back(parseExpr());
}
switch (lexer.current().type)
{
@ -2706,11 +2728,14 @@ AstExpr* Parser::parseInterpString()
break;
case Lexeme::BrokenInterpDoubleBrace:
nextLexeme();
printf("BROKEN INTERP DOUBLE BRACE\n");
return reportExprError(location, {}, ERROR_INVALID_INTERP_DOUBLE_BRACE);
case Lexeme::BrokenString:
nextLexeme();
printf("BROKEN STRING\n");
return reportExprError(location, {}, "Malformed interpolated string, did you forget to add a '}'?");
default:
printf("DEFAULT: %s\n", lexer.current().toString().c_str());
return reportExprError(location, {}, "Malformed interpolated string, got %s", lexer.current().toString().c_str());
}
} while (true);

View file

@ -7,6 +7,7 @@
#include "Luau/StringUtils.h"
#include "Fixture.h"
#include "ScopedFlags.h"
#include "doctest.h"
@ -2708,13 +2709,46 @@ a = if temp then even else abc@3
CHECK(ac.entryMap.count("abcdef"));
}
TEST_CASE_FIXTURE(ACFixture, "autocomplete_interpolated_string")
TEST_CASE_FIXTURE(ACFixture, "autocomplete_interpolated_string_constant")
{
ScopedFastFlag sff{"LuauInterpolatedStringBaseSupport", true};
printf("======= autocomplete_interpolated_string_constant =======\n");
// check(R"(f(`@1`))");
// auto ac = autocomplete('1');
// CHECK(ac.entryMap.empty());
// CHECK_EQ(ac.context, AutocompleteContext::String);
check(R"(f(`{"a"} @1`))");
auto ac = autocomplete('1');
CHECK(ac.entryMap.empty());
CHECK_EQ(ac.context, AutocompleteContext::String);
}
TEST_CASE_FIXTURE(ACFixture, "autocomplete_interpolated_string_expression")
{
ScopedFastFlag sff{"LuauInterpolatedStringBaseSupport", true};
check(R"(f(`expression = {@1}`))");
auto ac = autocomplete('1');
CHECK(ac.entryMap.count("table"));
CHECK_EQ(ac.context, AutocompleteContext::Expression);
}
TEST_CASE_FIXTURE(ACFixture, "autocomplete_interpolated_string_expression_with_comments")
{
ScopedFastFlag sff{"LuauInterpolatedStringBaseSupport", true};
check(R"(f(`expression = {--[[ bla bla bla ]]@1`))");
auto ac = autocomplete('1');
CHECK(ac.entryMap.count("table"));
CHECK_EQ(ac.context, AutocompleteContext::Expression);
check(R"(f(`expression = {@1--[[ bla bla bla ]]`))");
ac = autocomplete('1');
CHECK(ac.entryMap.count("table"));
CHECK_EQ(ac.context, AutocompleteContext::Expression);
}
TEST_CASE_FIXTURE(ACFixture, "autocomplete_explicit_type_pack")