mirror of
https://github.com/luau-lang/luau.git
synced 2025-05-04 10:33:46 +01:00
Start work on string interpolation autocomplete fixes
This commit is contained in:
parent
816e41a8f2
commit
c32cdd5c42
4 changed files with 668 additions and 586 deletions
File diff suppressed because it is too large
Load diff
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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")
|
||||
|
|
Loading…
Add table
Reference in a new issue